1 // SPDX-License-Identifier: GPL-2.0+
2 /* Microchip Sparx5 Switch driver
4 * Copyright (c) 2021 Microchip Technology Inc. and its subsidiaries.
7 #include "sparx5_main_regs.h"
8 #include "sparx5_main.h"
10 static int sparx5_vlant_set_mask(struct sparx5 *sparx5, u16 vid)
14 /* Divide up mask in 32 bit words */
15 bitmap_to_arr32(mask, sparx5->vlan_mask[vid], SPX5_PORTS);
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));
25 void sparx5_vlan_init(struct sparx5 *sparx5)
29 spx5_rmw(ANA_L3_VLAN_CTRL_VLAN_ENA_SET(1),
30 ANA_L3_VLAN_CTRL_VLAN_ENA,
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,
39 ANA_L3_VLAN_CFG(vid));
42 void sparx5_vlan_port_setup(struct sparx5 *sparx5, int portno)
44 struct sparx5_port *port = sparx5->ports[portno];
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,
52 ANA_CL_VLAN_CTRL(port->portno));
55 int sparx5_vlan_vid_add(struct sparx5_port *port, u16 vid, bool pvid,
58 struct sparx5 *sparx5 = port->sparx5;
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);
67 /* Default ingress vlan classification */
71 /* Untagged egress vlan classification */
72 if (untagged && port->vid != vid) {
74 netdev_err(port->ndev,
75 "Port already has a native VLAN: %d\n",
82 sparx5_vlan_port_apply(sparx5, port);
87 int sparx5_vlan_vid_del(struct sparx5_port *port, u16 vid)
89 struct sparx5 *sparx5 = port->sparx5;
92 /* 8021q removes VID 0 on module unload for all interfaces
93 * with VLAN filtering feature. We need to keep it to receive
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);
106 if (port->pvid == vid)
110 if (port->vid == vid)
113 sparx5_vlan_port_apply(sparx5, port);
118 void sparx5_pgid_update_mask(struct sparx5_port *port, int pgid, bool enable)
120 struct sparx5 *sparx5 = port->sparx5;
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));
137 netdev_err(port->ndev, "Invalid port no: %d\n", port->portno);
141 void sparx5_update_fwd(struct sparx5 *sparx5)
143 DECLARE_BITMAP(workmask, SPX5_PORTS);
147 /* Divide up fwd mask in 32 bit words */
148 bitmap_to_arr32(mask, sparx5->bridge_fwd_mask, SPX5_PORTS);
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));
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));
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));
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);
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);
185 void sparx5_vlan_port_apply(struct sparx5 *sparx5,
186 struct sparx5_port *port)
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));
198 if (port->vlan_aware && !port->pvid)
199 /* If port is vlan-aware and tagged, drop untagged and
200 * priority tagged frames.
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);
206 ANA_CL_VLAN_FILTER_CTRL(port->portno, 0));
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) {
212 /* Tag all frames except when VID == DEFAULT_VLAN */
213 val |= REW_TAG_CTRL_TAG_CFG_SET(1);
215 val |= REW_TAG_CTRL_TAG_CFG_SET(3);
217 spx5_wr(val, sparx5, REW_TAG_CTRL(port->portno));
220 spx5_rmw(REW_PORT_VLAN_CFG_PORT_VID_SET(port->vid),
221 REW_PORT_VLAN_CFG_PORT_VID,
223 REW_PORT_VLAN_CFG(port->portno));