]> Git Repo - linux.git/blob - drivers/net/ethernet/microchip/sparx5/sparx5_vlan.c
crypto: akcipher - Drop sign/verify operations
[linux.git] / drivers / net / ethernet / microchip / sparx5 / sparx5_vlan.c
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
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
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
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
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         /* Untagged egress vlan classification */
62         if (untagged && port->vid != vid) {
63                 if (port->vid) {
64                         netdev_err(port->ndev,
65                                    "Port already has a native VLAN: %d\n",
66                                    port->vid);
67                         return -EBUSY;
68                 }
69                 port->vid = vid;
70         }
71
72         /* Make the port a member of the VLAN */
73         set_bit(port->portno, sparx5->vlan_mask[vid]);
74         ret = sparx5_vlant_set_mask(sparx5, vid);
75         if (ret)
76                 return ret;
77
78         /* Default ingress vlan classification */
79         if (pvid)
80                 port->pvid = vid;
81
82         sparx5_vlan_port_apply(sparx5, port);
83
84         return 0;
85 }
86
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
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
141 void sparx5_pgid_clear(struct sparx5 *spx5, int pgid)
142 {
143         spx5_wr(0, spx5, ANA_AC_PGID_CFG(pgid));
144         spx5_wr(0, spx5, ANA_AC_PGID_CFG1(pgid));
145         spx5_wr(0, spx5, ANA_AC_PGID_CFG2(pgid));
146 }
147
148 void sparx5_pgid_read_mask(struct sparx5 *spx5, int pgid, u32 portmask[3])
149 {
150         portmask[0] = spx5_rd(spx5, ANA_AC_PGID_CFG(pgid));
151         portmask[1] = spx5_rd(spx5, ANA_AC_PGID_CFG1(pgid));
152         portmask[2] = spx5_rd(spx5, ANA_AC_PGID_CFG2(pgid));
153 }
154
155 void sparx5_update_fwd(struct sparx5 *sparx5)
156 {
157         DECLARE_BITMAP(workmask, SPX5_PORTS);
158         u32 mask[3];
159         int port;
160
161         /* Divide up fwd mask in 32 bit words */
162         bitmap_to_arr32(mask, sparx5->bridge_fwd_mask, SPX5_PORTS);
163
164         /* Update flood masks */
165         for (port = PGID_UC_FLOOD; port <= PGID_BCAST; port++) {
166                 spx5_wr(mask[0], sparx5, ANA_AC_PGID_CFG(port));
167                 spx5_wr(mask[1], sparx5, ANA_AC_PGID_CFG1(port));
168                 spx5_wr(mask[2], sparx5, ANA_AC_PGID_CFG2(port));
169         }
170
171         /* Update SRC masks */
172         for (port = 0; port < SPX5_PORTS; port++) {
173                 if (test_bit(port, sparx5->bridge_fwd_mask)) {
174                         /* Allow to send to all bridged but self */
175                         bitmap_copy(workmask, sparx5->bridge_fwd_mask, SPX5_PORTS);
176                         clear_bit(port, workmask);
177                         bitmap_to_arr32(mask, workmask, SPX5_PORTS);
178                         spx5_wr(mask[0], sparx5, ANA_AC_SRC_CFG(port));
179                         spx5_wr(mask[1], sparx5, ANA_AC_SRC_CFG1(port));
180                         spx5_wr(mask[2], sparx5, ANA_AC_SRC_CFG2(port));
181                 } else {
182                         spx5_wr(0, sparx5, ANA_AC_SRC_CFG(port));
183                         spx5_wr(0, sparx5, ANA_AC_SRC_CFG1(port));
184                         spx5_wr(0, sparx5, ANA_AC_SRC_CFG2(port));
185                 }
186         }
187
188         /* Learning enabled only for bridged ports */
189         bitmap_and(workmask, sparx5->bridge_fwd_mask,
190                    sparx5->bridge_lrn_mask, SPX5_PORTS);
191         bitmap_to_arr32(mask, workmask, SPX5_PORTS);
192
193         /* Apply learning mask */
194         spx5_wr(mask[0], sparx5, ANA_L2_AUTO_LRN_CFG);
195         spx5_wr(mask[1], sparx5, ANA_L2_AUTO_LRN_CFG1);
196         spx5_wr(mask[2], sparx5, ANA_L2_AUTO_LRN_CFG2);
197 }
198
199 void sparx5_vlan_port_apply(struct sparx5 *sparx5,
200                             struct sparx5_port *port)
201
202 {
203         u32 val;
204
205         /* Configure PVID, vlan aware */
206         val = ANA_CL_VLAN_CTRL_VLAN_AWARE_ENA_SET(port->vlan_aware) |
207                 ANA_CL_VLAN_CTRL_VLAN_POP_CNT_SET(port->vlan_aware) |
208                 ANA_CL_VLAN_CTRL_PORT_VID_SET(port->pvid);
209         spx5_wr(val, sparx5, ANA_CL_VLAN_CTRL(port->portno));
210
211         val = 0;
212         if (port->vlan_aware && !port->pvid)
213                 /* If port is vlan-aware and tagged, drop untagged and
214                  * priority tagged frames.
215                  */
216                 val = ANA_CL_VLAN_FILTER_CTRL_TAG_REQUIRED_ENA_SET(1) |
217                         ANA_CL_VLAN_FILTER_CTRL_PRIO_CTAG_DIS_SET(1) |
218                         ANA_CL_VLAN_FILTER_CTRL_PRIO_STAG_DIS_SET(1);
219         spx5_wr(val, sparx5,
220                 ANA_CL_VLAN_FILTER_CTRL(port->portno, 0));
221
222         /* Egress configuration (REW_TAG_CFG): VLAN tag selected via IFH */
223         val = REW_TAG_CTRL_TAG_TPID_CFG_SET(5);
224         if (port->vlan_aware) {
225                 if (port->vid)
226                         /* Tag all frames except when VID == DEFAULT_VLAN */
227                         val |= REW_TAG_CTRL_TAG_CFG_SET(1);
228                 else
229                         val |= REW_TAG_CTRL_TAG_CFG_SET(3);
230         }
231         spx5_wr(val, sparx5, REW_TAG_CTRL(port->portno));
232
233         /* Egress VID */
234         spx5_rmw(REW_PORT_VLAN_CFG_PORT_VID_SET(port->vid),
235                  REW_PORT_VLAN_CFG_PORT_VID,
236                  sparx5,
237                  REW_PORT_VLAN_CFG(port->portno));
238 }
This page took 0.05338 seconds and 4 git commands to generate.