df96c17582effabc006fc103f8c6ec740a7df570
[platform/kernel/linux-starfive.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 /* Validate app entry.
12  *
13  * Check for valid selectors and valid protocol and priority ranges.
14  */
15 static int sparx5_dcb_app_validate(struct net_device *dev,
16                                    const struct dcb_app *app)
17 {
18         int err = 0;
19
20         switch (app->selector) {
21         /* Pcp checks */
22         case DCB_APP_SEL_PCP:
23                 if (app->protocol >= SPARX5_PORT_QOS_PCP_DEI_COUNT)
24                         err = -EINVAL;
25                 else if (app->priority >= SPX5_PRIOS)
26                         err = -ERANGE;
27                 break;
28         default:
29                 err = -EINVAL;
30                 break;
31         }
32
33         if (err)
34                 netdev_err(dev, "Invalid entry: %d:%d\n", app->protocol,
35                            app->priority);
36
37         return err;
38 }
39
40 static int sparx5_dcb_app_update(struct net_device *dev)
41 {
42         struct dcb_app app_itr = { .selector = DCB_APP_SEL_PCP };
43         struct sparx5_port *port = netdev_priv(dev);
44         struct sparx5_port_qos_pcp_map *pcp_map;
45         struct sparx5_port_qos qos = {0};
46         int i;
47
48         pcp_map = &qos.pcp.map;
49
50         /* Get pcp ingress mapping */
51         for (i = 0; i < ARRAY_SIZE(pcp_map->map); i++) {
52                 app_itr.protocol = i;
53                 pcp_map->map[i] = dcb_getapp(dev, &app_itr);
54         }
55
56         return sparx5_port_qos_set(port, &qos);
57 }
58
59 static int sparx5_dcb_ieee_setapp(struct net_device *dev, struct dcb_app *app)
60 {
61         struct dcb_app app_itr;
62         int err = 0;
63         u8 prio;
64
65         err = sparx5_dcb_app_validate(dev, app);
66         if (err)
67                 goto out;
68
69         /* Delete current mapping, if it exists */
70         prio = dcb_getapp(dev, app);
71         if (prio) {
72                 app_itr = *app;
73                 app_itr.priority = prio;
74                 dcb_ieee_delapp(dev, &app_itr);
75         }
76
77         err = dcb_ieee_setapp(dev, app);
78         if (err)
79                 goto out;
80
81         sparx5_dcb_app_update(dev);
82
83 out:
84         return err;
85 }
86
87 static int sparx5_dcb_ieee_delapp(struct net_device *dev, struct dcb_app *app)
88 {
89         int err;
90
91         err = dcb_ieee_delapp(dev, app);
92         if (err < 0)
93                 return err;
94
95         return sparx5_dcb_app_update(dev);
96 }
97
98 const struct dcbnl_rtnl_ops sparx5_dcbnl_ops = {
99         .ieee_setapp = sparx5_dcb_ieee_setapp,
100         .ieee_delapp = sparx5_dcb_ieee_delapp,
101 };
102
103 int sparx5_dcb_init(struct sparx5 *sparx5)
104 {
105         struct sparx5_port *port;
106         int i;
107
108         for (i = 0; i < SPX5_PORTS; i++) {
109                 port = sparx5->ports[i];
110                 if (!port)
111                         continue;
112                 port->ndev->dcbnl_ops = &sparx5_dcbnl_ops;
113         }
114
115         return 0;
116 }