]> Git Repo - J-linux.git/blob - drivers/net/ethernet/microchip/sparx5/sparx5_dcb.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / drivers / net / ethernet / microchip / sparx5 / sparx5_dcb.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /* Microchip Sparx5 Switch driver
3  *
4  * Copyright (c) 2022 Microchip Technology Inc. and its subsidiaries.
5  */
6
7 #include <net/dcbnl.h>
8
9 #include "sparx5_port.h"
10
11 enum sparx5_dcb_apptrust_values {
12         SPARX5_DCB_APPTRUST_EMPTY,
13         SPARX5_DCB_APPTRUST_DSCP,
14         SPARX5_DCB_APPTRUST_PCP,
15         SPARX5_DCB_APPTRUST_DSCP_PCP,
16         __SPARX5_DCB_APPTRUST_MAX
17 };
18
19 static const struct sparx5_dcb_apptrust {
20         u8 selectors[IEEE_8021QAZ_APP_SEL_MAX + 1];
21         int nselectors;
22 } *sparx5_port_apptrust[SPX5_PORTS];
23
24 static const char *sparx5_dcb_apptrust_names[__SPARX5_DCB_APPTRUST_MAX] = {
25         [SPARX5_DCB_APPTRUST_EMPTY]    = "empty",
26         [SPARX5_DCB_APPTRUST_DSCP]     = "dscp",
27         [SPARX5_DCB_APPTRUST_PCP]      = "pcp",
28         [SPARX5_DCB_APPTRUST_DSCP_PCP] = "dscp pcp"
29 };
30
31 /* Sparx5 supported apptrust policies */
32 static const struct sparx5_dcb_apptrust
33         sparx5_dcb_apptrust_policies[__SPARX5_DCB_APPTRUST_MAX] = {
34         /* Empty *must* be first */
35         [SPARX5_DCB_APPTRUST_EMPTY]    = { { 0 }, 0 },
36         [SPARX5_DCB_APPTRUST_DSCP]     = { { IEEE_8021QAZ_APP_SEL_DSCP }, 1 },
37         [SPARX5_DCB_APPTRUST_PCP]      = { { DCB_APP_SEL_PCP }, 1 },
38         [SPARX5_DCB_APPTRUST_DSCP_PCP] = { { IEEE_8021QAZ_APP_SEL_DSCP,
39                                              DCB_APP_SEL_PCP }, 2 },
40 };
41
42 /* Validate app entry.
43  *
44  * Check for valid selectors and valid protocol and priority ranges.
45  */
46 static int sparx5_dcb_app_validate(struct net_device *dev,
47                                    const struct dcb_app *app)
48 {
49         int err = 0;
50
51         switch (app->selector) {
52         /* Default priority checks */
53         case IEEE_8021QAZ_APP_SEL_ETHERTYPE:
54                 if (app->protocol != 0)
55                         err = -EINVAL;
56                 else if (app->priority >= SPX5_PRIOS)
57                         err = -ERANGE;
58                 break;
59         /* Dscp checks */
60         case IEEE_8021QAZ_APP_SEL_DSCP:
61                 if (app->protocol >= SPARX5_PORT_QOS_DSCP_COUNT)
62                         err = -EINVAL;
63                 else if (app->priority >= SPX5_PRIOS)
64                         err = -ERANGE;
65                 break;
66         /* Pcp checks */
67         case DCB_APP_SEL_PCP:
68                 if (app->protocol >= SPARX5_PORT_QOS_PCP_DEI_COUNT)
69                         err = -EINVAL;
70                 else if (app->priority >= SPX5_PRIOS)
71                         err = -ERANGE;
72                 break;
73         default:
74                 err = -EINVAL;
75                 break;
76         }
77
78         if (err)
79                 netdev_err(dev, "Invalid entry: %d:%d\n", app->protocol,
80                            app->priority);
81
82         return err;
83 }
84
85 /* Validate apptrust configuration.
86  *
87  * Return index of supported apptrust configuration if valid, otherwise return
88  * error.
89  */
90 static int sparx5_dcb_apptrust_validate(struct net_device *dev, u8 *selectors,
91                                         int nselectors, int *err)
92 {
93         bool match = false;
94         int i, ii;
95
96         for (i = 0; i < ARRAY_SIZE(sparx5_dcb_apptrust_policies); i++) {
97                 if (sparx5_dcb_apptrust_policies[i].nselectors != nselectors)
98                         continue;
99                 match = true;
100                 for (ii = 0; ii < nselectors; ii++) {
101                         if (sparx5_dcb_apptrust_policies[i].selectors[ii] !=
102                             *(selectors + ii)) {
103                                 match = false;
104                                 break;
105                         }
106                 }
107                 if (match)
108                         break;
109         }
110
111         /* Requested trust configuration is not supported */
112         if (!match) {
113                 netdev_err(dev, "Valid apptrust configurations are:\n");
114                 for (i = 0; i < ARRAY_SIZE(sparx5_dcb_apptrust_names); i++)
115                         pr_info("order: %s\n", sparx5_dcb_apptrust_names[i]);
116                 *err = -EOPNOTSUPP;
117         }
118
119         return i;
120 }
121
122 static bool sparx5_dcb_apptrust_contains(int portno, u8 selector)
123 {
124         const struct sparx5_dcb_apptrust *conf = sparx5_port_apptrust[portno];
125         int i;
126
127         for (i = 0; i < conf->nselectors; i++)
128                 if (conf->selectors[i] == selector)
129                         return true;
130
131         return false;
132 }
133
134 static int sparx5_dcb_app_update(struct net_device *dev)
135 {
136         struct dcb_ieee_app_prio_map dscp_rewr_map = {0};
137         struct dcb_rewr_prio_pcp_map pcp_rewr_map = {0};
138         struct sparx5_port *port = netdev_priv(dev);
139         struct sparx5_port_qos_dscp_map *dscp_map;
140         struct sparx5_port_qos_pcp_map *pcp_map;
141         struct sparx5_port_qos qos = {0};
142         struct dcb_app app_itr = {0};
143         int portno = port->portno;
144         bool dscp_rewr = false;
145         bool pcp_rewr = false;
146         u16 dscp;
147         int i;
148
149         dscp_map = &qos.dscp.map;
150         pcp_map = &qos.pcp.map;
151
152         /* Get default prio. */
153         qos.default_prio = dcb_ieee_getapp_default_prio_mask(dev);
154         if (qos.default_prio)
155                 qos.default_prio = fls(qos.default_prio) - 1;
156
157         /* Get dscp ingress mapping */
158         for (i = 0; i < ARRAY_SIZE(dscp_map->map); i++) {
159                 app_itr.selector = IEEE_8021QAZ_APP_SEL_DSCP;
160                 app_itr.protocol = i;
161                 dscp_map->map[i] = dcb_getapp(dev, &app_itr);
162         }
163
164         /* Get pcp ingress mapping */
165         for (i = 0; i < ARRAY_SIZE(pcp_map->map); i++) {
166                 app_itr.selector = DCB_APP_SEL_PCP;
167                 app_itr.protocol = i;
168                 pcp_map->map[i] = dcb_getapp(dev, &app_itr);
169         }
170
171         /* Get pcp rewrite mapping */
172         dcb_getrewr_prio_pcp_mask_map(dev, &pcp_rewr_map);
173         for (i = 0; i < ARRAY_SIZE(pcp_rewr_map.map); i++) {
174                 if (!pcp_rewr_map.map[i])
175                         continue;
176                 pcp_rewr = true;
177                 qos.pcp_rewr.map.map[i] = fls(pcp_rewr_map.map[i]) - 1;
178         }
179
180         /* Get dscp rewrite mapping */
181         dcb_getrewr_prio_dscp_mask_map(dev, &dscp_rewr_map);
182         for (i = 0; i < ARRAY_SIZE(dscp_rewr_map.map); i++) {
183                 if (!dscp_rewr_map.map[i])
184                         continue;
185
186                 /* The rewrite table of the switch has 32 entries; one for each
187                  * priority for each DP level. Currently, the rewrite map does
188                  * not indicate DP level, so we map classified QoS class to
189                  * classified DSCP, for each classified DP level. Rewrite of
190                  * DSCP is only enabled, if we have active mappings.
191                  */
192                 dscp_rewr = true;
193                 dscp = fls64(dscp_rewr_map.map[i]) - 1;
194                 qos.dscp_rewr.map.map[i] = dscp;      /* DP 0 */
195                 qos.dscp_rewr.map.map[i + 8] = dscp;  /* DP 1 */
196                 qos.dscp_rewr.map.map[i + 16] = dscp; /* DP 2 */
197                 qos.dscp_rewr.map.map[i + 24] = dscp; /* DP 3 */
198         }
199
200         /* Enable use of pcp for queue classification ? */
201         if (sparx5_dcb_apptrust_contains(portno, DCB_APP_SEL_PCP)) {
202                 qos.pcp.qos_enable = true;
203                 qos.pcp.dp_enable = qos.pcp.qos_enable;
204                 /* Enable rewrite of PCP and DEI if PCP is trusted *and* rewrite
205                  * table is not empty.
206                  */
207                 if (pcp_rewr)
208                         qos.pcp_rewr.enable = true;
209         }
210
211         /* Enable use of dscp for queue classification ? */
212         if (sparx5_dcb_apptrust_contains(portno, IEEE_8021QAZ_APP_SEL_DSCP)) {
213                 qos.dscp.qos_enable = true;
214                 qos.dscp.dp_enable = qos.dscp.qos_enable;
215                 if (dscp_rewr)
216                         /* Do not enable rewrite if no mappings are active, as
217                          * classified DSCP will then be zero for all classified
218                          * QoS class and DP combinations.
219                          */
220                         qos.dscp_rewr.enable = true;
221         }
222
223         return sparx5_port_qos_set(port, &qos);
224 }
225
226 /* Set or delete DSCP app entry.
227  *
228  * DSCP mapping is global for all ports, so set and delete app entries are
229  * replicated for each port.
230  */
231 static int sparx5_dcb_ieee_dscp_setdel(struct net_device *dev,
232                                        struct dcb_app *app,
233                                        int (*setdel)(struct net_device *,
234                                                      struct dcb_app *))
235 {
236         struct sparx5_port *port = netdev_priv(dev);
237         struct sparx5 *sparx5 = port->sparx5;
238         struct sparx5_port *port_itr;
239         int err, i;
240
241         for (i = 0; i < sparx5->data->consts->n_ports; i++) {
242                 port_itr = port->sparx5->ports[i];
243                 if (!port_itr)
244                         continue;
245                 err = setdel(port_itr->ndev, app);
246                 if (err)
247                         return err;
248         }
249
250         return 0;
251 }
252
253 static int sparx5_dcb_ieee_delapp(struct net_device *dev, struct dcb_app *app)
254 {
255         int err;
256
257         if (app->selector == IEEE_8021QAZ_APP_SEL_DSCP)
258                 err = sparx5_dcb_ieee_dscp_setdel(dev, app, dcb_ieee_delapp);
259         else
260                 err = dcb_ieee_delapp(dev, app);
261
262         if (err < 0)
263                 return err;
264
265         return sparx5_dcb_app_update(dev);
266 }
267
268 static int sparx5_dcb_ieee_setapp(struct net_device *dev, struct dcb_app *app)
269 {
270         struct dcb_app app_itr;
271         int err = 0;
272         u8 prio;
273
274         err = sparx5_dcb_app_validate(dev, app);
275         if (err)
276                 goto out;
277
278         /* Delete current mapping, if it exists */
279         prio = dcb_getapp(dev, app);
280         if (prio) {
281                 app_itr = *app;
282                 app_itr.priority = prio;
283                 sparx5_dcb_ieee_delapp(dev, &app_itr);
284         }
285
286         if (app->selector == IEEE_8021QAZ_APP_SEL_DSCP)
287                 err = sparx5_dcb_ieee_dscp_setdel(dev, app, dcb_ieee_setapp);
288         else
289                 err = dcb_ieee_setapp(dev, app);
290
291         if (err)
292                 goto out;
293
294         sparx5_dcb_app_update(dev);
295
296 out:
297         return err;
298 }
299
300 static int sparx5_dcb_setapptrust(struct net_device *dev, u8 *selectors,
301                                   int nselectors)
302 {
303         struct sparx5_port *port = netdev_priv(dev);
304         int err = 0, idx;
305
306         idx = sparx5_dcb_apptrust_validate(dev, selectors, nselectors, &err);
307         if (err < 0)
308                 return err;
309
310         sparx5_port_apptrust[port->portno] = &sparx5_dcb_apptrust_policies[idx];
311
312         return sparx5_dcb_app_update(dev);
313 }
314
315 static int sparx5_dcb_getapptrust(struct net_device *dev, u8 *selectors,
316                                   int *nselectors)
317 {
318         struct sparx5_port *port = netdev_priv(dev);
319         const struct sparx5_dcb_apptrust *trust;
320
321         trust = sparx5_port_apptrust[port->portno];
322
323         memcpy(selectors, trust->selectors, trust->nselectors);
324         *nselectors = trust->nselectors;
325
326         return 0;
327 }
328
329 static int sparx5_dcb_delrewr(struct net_device *dev, struct dcb_app *app)
330 {
331         int err;
332
333         if (app->selector == IEEE_8021QAZ_APP_SEL_DSCP)
334                 err = sparx5_dcb_ieee_dscp_setdel(dev, app, dcb_delrewr);
335         else
336                 err = dcb_delrewr(dev, app);
337
338         if (err < 0)
339                 return err;
340
341         return sparx5_dcb_app_update(dev);
342 }
343
344 static int sparx5_dcb_setrewr(struct net_device *dev, struct dcb_app *app)
345 {
346         struct dcb_app app_itr;
347         int err = 0;
348         u16 proto;
349
350         err = sparx5_dcb_app_validate(dev, app);
351         if (err)
352                 goto out;
353
354         /* Delete current mapping, if it exists. */
355         proto = dcb_getrewr(dev, app);
356         if (proto) {
357                 app_itr = *app;
358                 app_itr.protocol = proto;
359                 sparx5_dcb_delrewr(dev, &app_itr);
360         }
361
362         if (app->selector == IEEE_8021QAZ_APP_SEL_DSCP)
363                 err = sparx5_dcb_ieee_dscp_setdel(dev, app, dcb_setrewr);
364         else
365                 err = dcb_setrewr(dev, app);
366
367         if (err)
368                 goto out;
369
370         sparx5_dcb_app_update(dev);
371
372 out:
373         return err;
374 }
375
376 const struct dcbnl_rtnl_ops sparx5_dcbnl_ops = {
377         .ieee_setapp = sparx5_dcb_ieee_setapp,
378         .ieee_delapp = sparx5_dcb_ieee_delapp,
379         .dcbnl_setapptrust = sparx5_dcb_setapptrust,
380         .dcbnl_getapptrust = sparx5_dcb_getapptrust,
381         .dcbnl_setrewr = sparx5_dcb_setrewr,
382         .dcbnl_delrewr = sparx5_dcb_delrewr,
383 };
384
385 int sparx5_dcb_init(struct sparx5 *sparx5)
386 {
387         struct sparx5_port *port;
388         int i;
389
390         for (i = 0; i < sparx5->data->consts->n_ports; i++) {
391                 port = sparx5->ports[i];
392                 if (!port)
393                         continue;
394                 port->ndev->dcbnl_ops = &sparx5_dcbnl_ops;
395                 /* Initialize [dscp, pcp] default trust */
396                 sparx5_port_apptrust[port->portno] =
397                         &sparx5_dcb_apptrust_policies
398                                 [SPARX5_DCB_APPTRUST_DSCP_PCP];
399
400                 /* Enable DSCP classification based on classified QoS class and
401                  * DP, for all DSCP values, for all ports.
402                  */
403                 sparx5_port_qos_dscp_rewr_mode_set(port,
404                                                    SPARX5_PORT_REW_DSCP_ALL);
405         }
406
407         return 0;
408 }
This page took 0.053074 seconds and 4 git commands to generate.