1 // SPDX-License-Identifier: GPL-2.0+
2 /* Microchip Sparx5 Switch driver
3  *
4  * Copyright (c) 2021 Microchip Technology Inc. and its subsidiaries.
5  */
6 
7 #include "sparx5_main_regs.h"
8 #include "sparx5_main.h"
9 
sparx5_vlant_set_mask(struct sparx5 * sparx5,u16 vid)10 static int sparx5_vlant_set_mask(struct sparx5 *sparx5, u16 vid)
11 {
12 	u32 mask[3];
13 
14 	/* Divide up mask in 32 bit words */
15 	bitmap_to_arr32(mask, sparx5->vlan_mask[vid], SPX5_PORTS);
16 
17 	/* Output mask to respective registers */
18 	spx5_wr(mask[0], sparx5, ANA_L3_VLAN_MASK_CFG(vid));
19 	spx5_wr(mask[1], sparx5, ANA_L3_VLAN_MASK_CFG1(vid));
20 	spx5_wr(mask[2], sparx5, ANA_L3_VLAN_MASK_CFG2(vid));
21 
22 	return 0;
23 }
24 
sparx5_vlan_init(struct sparx5 * sparx5)25 void sparx5_vlan_init(struct sparx5 *sparx5)
26 {
27 	u16 vid;
28 
29 	spx5_rmw(ANA_L3_VLAN_CTRL_VLAN_ENA_SET(1),
30 		 ANA_L3_VLAN_CTRL_VLAN_ENA,
31 		 sparx5,
32 		 ANA_L3_VLAN_CTRL);
33 
34 	/* Map VLAN = FID */
35 	for (vid = NULL_VID; vid < VLAN_N_VID; vid++)
36 		spx5_rmw(ANA_L3_VLAN_CFG_VLAN_FID_SET(vid),
37 			 ANA_L3_VLAN_CFG_VLAN_FID,
38 			 sparx5,
39 			 ANA_L3_VLAN_CFG(vid));
40 }
41 
sparx5_vlan_port_setup(struct sparx5 * sparx5,int portno)42 void sparx5_vlan_port_setup(struct sparx5 *sparx5, int portno)
43 {
44 	struct sparx5_port *port = sparx5->ports[portno];
45 
46 	/* Configure PVID */
47 	spx5_rmw(ANA_CL_VLAN_CTRL_VLAN_AWARE_ENA_SET(0) |
48 		 ANA_CL_VLAN_CTRL_PORT_VID_SET(port->pvid),
49 		 ANA_CL_VLAN_CTRL_VLAN_AWARE_ENA |
50 		 ANA_CL_VLAN_CTRL_PORT_VID,
51 		 sparx5,
52 		 ANA_CL_VLAN_CTRL(port->portno));
53 }
54 
sparx5_vlan_vid_add(struct sparx5_port * port,u16 vid,bool pvid,bool untagged)55 int sparx5_vlan_vid_add(struct sparx5_port *port, u16 vid, bool pvid,
56 			bool untagged)
57 {
58 	struct sparx5 *sparx5 = port->sparx5;
59 	int ret;
60 
61 	/* Make the port a member of the VLAN */
62 	set_bit(port->portno, sparx5->vlan_mask[vid]);
63 	ret = sparx5_vlant_set_mask(sparx5, vid);
64 	if (ret)
65 		return ret;
66 
67 	/* Default ingress vlan classification */
68 	if (pvid)
69 		port->pvid = vid;
70 
71 	/* Untagged egress vlan classification */
72 	if (untagged && port->vid != vid) {
73 		if (port->vid) {
74 			netdev_err(port->ndev,
75 				   "Port already has a native VLAN: %d\n",
76 				   port->vid);
77 			return -EBUSY;
78 		}
79 		port->vid = vid;
80 	}
81 
82 	sparx5_vlan_port_apply(sparx5, port);
83 
84 	return 0;
85 }
86 
sparx5_vlan_vid_del(struct sparx5_port * port,u16 vid)87 int sparx5_vlan_vid_del(struct sparx5_port *port, u16 vid)
88 {
89 	struct sparx5 *sparx5 = port->sparx5;
90 	int ret;
91 
92 	/* 8021q removes VID 0 on module unload for all interfaces
93 	 * with VLAN filtering feature. We need to keep it to receive
94 	 * untagged traffic.
95 	 */
96 	if (vid == 0)
97 		return 0;
98 
99 	/* Stop the port from being a member of the vlan */
100 	clear_bit(port->portno, sparx5->vlan_mask[vid]);
101 	ret = sparx5_vlant_set_mask(sparx5, vid);
102 	if (ret)
103 		return ret;
104 
105 	/* Ingress */
106 	if (port->pvid == vid)
107 		port->pvid = 0;
108 
109 	/* Egress */
110 	if (port->vid == vid)
111 		port->vid = 0;
112 
113 	sparx5_vlan_port_apply(sparx5, port);
114 
115 	return 0;
116 }
117 
sparx5_pgid_update_mask(struct sparx5_port * port,int pgid,bool enable)118 void sparx5_pgid_update_mask(struct sparx5_port *port, int pgid, bool enable)
119 {
120 	struct sparx5 *sparx5 = port->sparx5;
121 	u32 val, mask;
122 
123 	/* mask is spread across 3 registers x 32 bit */
124 	if (port->portno < 32) {
125 		mask = BIT(port->portno);
126 		val = enable ? mask : 0;
127 		spx5_rmw(val, mask, sparx5, ANA_AC_PGID_CFG(pgid));
128 	} else if (port->portno < 64) {
129 		mask = BIT(port->portno - 32);
130 		val = enable ? mask : 0;
131 		spx5_rmw(val, mask, sparx5, ANA_AC_PGID_CFG1(pgid));
132 	} else if (port->portno < SPX5_PORTS) {
133 		mask = BIT(port->portno - 64);
134 		val = enable ? mask : 0;
135 		spx5_rmw(val, mask, sparx5, ANA_AC_PGID_CFG2(pgid));
136 	} else {
137 		netdev_err(port->ndev, "Invalid port no: %d\n", port->portno);
138 	}
139 }
140 
sparx5_update_fwd(struct sparx5 * sparx5)141 void sparx5_update_fwd(struct sparx5 *sparx5)
142 {
143 	DECLARE_BITMAP(workmask, SPX5_PORTS);
144 	u32 mask[3];
145 	int port;
146 
147 	/* Divide up fwd mask in 32 bit words */
148 	bitmap_to_arr32(mask, sparx5->bridge_fwd_mask, SPX5_PORTS);
149 
150 	/* Update flood masks */
151 	for (port = PGID_UC_FLOOD; port <= PGID_BCAST; port++) {
152 		spx5_wr(mask[0], sparx5, ANA_AC_PGID_CFG(port));
153 		spx5_wr(mask[1], sparx5, ANA_AC_PGID_CFG1(port));
154 		spx5_wr(mask[2], sparx5, ANA_AC_PGID_CFG2(port));
155 	}
156 
157 	/* Update SRC masks */
158 	for (port = 0; port < SPX5_PORTS; port++) {
159 		if (test_bit(port, sparx5->bridge_fwd_mask)) {
160 			/* Allow to send to all bridged but self */
161 			bitmap_copy(workmask, sparx5->bridge_fwd_mask, SPX5_PORTS);
162 			clear_bit(port, workmask);
163 			bitmap_to_arr32(mask, workmask, SPX5_PORTS);
164 			spx5_wr(mask[0], sparx5, ANA_AC_SRC_CFG(port));
165 			spx5_wr(mask[1], sparx5, ANA_AC_SRC_CFG1(port));
166 			spx5_wr(mask[2], sparx5, ANA_AC_SRC_CFG2(port));
167 		} else {
168 			spx5_wr(0, sparx5, ANA_AC_SRC_CFG(port));
169 			spx5_wr(0, sparx5, ANA_AC_SRC_CFG1(port));
170 			spx5_wr(0, sparx5, ANA_AC_SRC_CFG2(port));
171 		}
172 	}
173 
174 	/* Learning enabled only for bridged ports */
175 	bitmap_and(workmask, sparx5->bridge_fwd_mask,
176 		   sparx5->bridge_lrn_mask, SPX5_PORTS);
177 	bitmap_to_arr32(mask, workmask, SPX5_PORTS);
178 
179 	/* Apply learning mask */
180 	spx5_wr(mask[0], sparx5, ANA_L2_AUTO_LRN_CFG);
181 	spx5_wr(mask[1], sparx5, ANA_L2_AUTO_LRN_CFG1);
182 	spx5_wr(mask[2], sparx5, ANA_L2_AUTO_LRN_CFG2);
183 }
184 
sparx5_vlan_port_apply(struct sparx5 * sparx5,struct sparx5_port * port)185 void sparx5_vlan_port_apply(struct sparx5 *sparx5,
186 			    struct sparx5_port *port)
187 
188 {
189 	u32 val;
190 
191 	/* Configure PVID, vlan aware */
192 	val = ANA_CL_VLAN_CTRL_VLAN_AWARE_ENA_SET(port->vlan_aware) |
193 		ANA_CL_VLAN_CTRL_VLAN_POP_CNT_SET(port->vlan_aware) |
194 		ANA_CL_VLAN_CTRL_PORT_VID_SET(port->pvid);
195 	spx5_wr(val, sparx5, ANA_CL_VLAN_CTRL(port->portno));
196 
197 	val = 0;
198 	if (port->vlan_aware && !port->pvid)
199 		/* If port is vlan-aware and tagged, drop untagged and
200 		 * priority tagged frames.
201 		 */
202 		val = ANA_CL_VLAN_FILTER_CTRL_TAG_REQUIRED_ENA_SET(1) |
203 			ANA_CL_VLAN_FILTER_CTRL_PRIO_CTAG_DIS_SET(1) |
204 			ANA_CL_VLAN_FILTER_CTRL_PRIO_STAG_DIS_SET(1);
205 	spx5_wr(val, sparx5,
206 		ANA_CL_VLAN_FILTER_CTRL(port->portno, 0));
207 
208 	/* Egress configuration (REW_TAG_CFG): VLAN tag type to 8021Q */
209 	val = REW_TAG_CTRL_TAG_TPID_CFG_SET(0);
210 	if (port->vlan_aware) {
211 		if (port->vid)
212 			/* Tag all frames except when VID == DEFAULT_VLAN */
213 			val |= REW_TAG_CTRL_TAG_CFG_SET(1);
214 		else
215 			val |= REW_TAG_CTRL_TAG_CFG_SET(3);
216 	}
217 	spx5_wr(val, sparx5, REW_TAG_CTRL(port->portno));
218 
219 	/* Egress VID */
220 	spx5_rmw(REW_PORT_VLAN_CFG_PORT_VID_SET(port->vid),
221 		 REW_PORT_VLAN_CFG_PORT_VID,
222 		 sparx5,
223 		 REW_PORT_VLAN_CFG(port->portno));
224 }
225