Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.4.
  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
 11enum 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
 19static const struct sparx5_dcb_apptrust {
 20	u8 selectors[IEEE_8021QAZ_APP_SEL_MAX + 1];
 21	int nselectors;
 22} *sparx5_port_apptrust[SPX5_PORTS];
 23
 24static 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 */
 32static 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 */
 46static 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 */
 90static 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
122static 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
134static int sparx5_dcb_app_update(struct net_device *dev)
135{
136	struct sparx5_port *port = netdev_priv(dev);
137	struct sparx5_port_qos_dscp_map *dscp_map;
138	struct sparx5_port_qos_pcp_map *pcp_map;
139	struct sparx5_port_qos qos = {0};
140	struct dcb_app app_itr = {0};
141	int portno = port->portno;
142	int i;
143
144	dscp_map = &qos.dscp.map;
145	pcp_map = &qos.pcp.map;
146
147	/* Get default prio. */
148	qos.default_prio = dcb_ieee_getapp_default_prio_mask(dev);
149	if (qos.default_prio)
150		qos.default_prio = fls(qos.default_prio) - 1;
151
152	/* Get dscp ingress mapping */
153	for (i = 0; i < ARRAY_SIZE(dscp_map->map); i++) {
154		app_itr.selector = IEEE_8021QAZ_APP_SEL_DSCP;
155		app_itr.protocol = i;
156		dscp_map->map[i] = dcb_getapp(dev, &app_itr);
157	}
158
159	/* Get pcp ingress mapping */
160	for (i = 0; i < ARRAY_SIZE(pcp_map->map); i++) {
161		app_itr.selector = DCB_APP_SEL_PCP;
162		app_itr.protocol = i;
163		pcp_map->map[i] = dcb_getapp(dev, &app_itr);
164	}
165
166	/* Enable use of pcp for queue classification ? */
167	if (sparx5_dcb_apptrust_contains(portno, DCB_APP_SEL_PCP)) {
168		qos.pcp.qos_enable = true;
169		qos.pcp.dp_enable = qos.pcp.qos_enable;
170	}
171
172	/* Enable use of dscp for queue classification ? */
173	if (sparx5_dcb_apptrust_contains(portno, IEEE_8021QAZ_APP_SEL_DSCP)) {
174		qos.dscp.qos_enable = true;
175		qos.dscp.dp_enable = qos.dscp.qos_enable;
176	}
177
178	return sparx5_port_qos_set(port, &qos);
179}
180
181/* Set or delete dscp app entry.
182 *
183 * Dscp mapping is global for all ports, so set and delete app entries are
184 * replicated for each port.
185 */
186static int sparx5_dcb_ieee_dscp_setdel_app(struct net_device *dev,
187					   struct dcb_app *app, bool del)
188{
189	struct sparx5_port *port = netdev_priv(dev);
190	struct dcb_app apps[SPX5_PORTS];
191	struct sparx5_port *port_itr;
192	int err, i;
193
194	for (i = 0; i < SPX5_PORTS; i++) {
195		port_itr = port->sparx5->ports[i];
196		if (!port_itr)
197			continue;
198		memcpy(&apps[i], app, sizeof(struct dcb_app));
199		if (del)
200			err = dcb_ieee_delapp(port_itr->ndev, &apps[i]);
201		else
202			err = dcb_ieee_setapp(port_itr->ndev, &apps[i]);
203		if (err)
204			return err;
205	}
206
207	return 0;
208}
209
210static int sparx5_dcb_ieee_setapp(struct net_device *dev, struct dcb_app *app)
211{
212	struct dcb_app app_itr;
213	int err = 0;
214	u8 prio;
215
216	err = sparx5_dcb_app_validate(dev, app);
217	if (err)
218		goto out;
219
220	/* Delete current mapping, if it exists */
221	prio = dcb_getapp(dev, app);
222	if (prio) {
223		app_itr = *app;
224		app_itr.priority = prio;
225		dcb_ieee_delapp(dev, &app_itr);
226	}
227
228	if (app->selector == IEEE_8021QAZ_APP_SEL_DSCP)
229		err = sparx5_dcb_ieee_dscp_setdel_app(dev, app, false);
230	else
231		err = dcb_ieee_setapp(dev, app);
232
233	if (err)
234		goto out;
235
236	sparx5_dcb_app_update(dev);
237
238out:
239	return err;
240}
241
242static int sparx5_dcb_ieee_delapp(struct net_device *dev, struct dcb_app *app)
243{
244	int err;
245
246	if (app->selector == IEEE_8021QAZ_APP_SEL_DSCP)
247		err = sparx5_dcb_ieee_dscp_setdel_app(dev, app, true);
248	else
249		err = dcb_ieee_delapp(dev, app);
250
251	if (err < 0)
252		return err;
253
254	return sparx5_dcb_app_update(dev);
255}
256
257static int sparx5_dcb_setapptrust(struct net_device *dev, u8 *selectors,
258				  int nselectors)
259{
260	struct sparx5_port *port = netdev_priv(dev);
261	int err = 0, idx;
262
263	idx = sparx5_dcb_apptrust_validate(dev, selectors, nselectors, &err);
264	if (err < 0)
265		return err;
266
267	sparx5_port_apptrust[port->portno] = &sparx5_dcb_apptrust_policies[idx];
268
269	return sparx5_dcb_app_update(dev);
270}
271
272static int sparx5_dcb_getapptrust(struct net_device *dev, u8 *selectors,
273				  int *nselectors)
274{
275	struct sparx5_port *port = netdev_priv(dev);
276	const struct sparx5_dcb_apptrust *trust;
277
278	trust = sparx5_port_apptrust[port->portno];
279
280	memcpy(selectors, trust->selectors, trust->nselectors);
281	*nselectors = trust->nselectors;
282
283	return 0;
284}
285
286const struct dcbnl_rtnl_ops sparx5_dcbnl_ops = {
287	.ieee_setapp = sparx5_dcb_ieee_setapp,
288	.ieee_delapp = sparx5_dcb_ieee_delapp,
289	.dcbnl_setapptrust = sparx5_dcb_setapptrust,
290	.dcbnl_getapptrust = sparx5_dcb_getapptrust,
291};
292
293int sparx5_dcb_init(struct sparx5 *sparx5)
294{
295	struct sparx5_port *port;
296	int i;
297
298	for (i = 0; i < SPX5_PORTS; i++) {
299		port = sparx5->ports[i];
300		if (!port)
301			continue;
302		port->ndev->dcbnl_ops = &sparx5_dcbnl_ops;
303		/* Initialize [dscp, pcp] default trust */
304		sparx5_port_apptrust[port->portno] =
305			&sparx5_dcb_apptrust_policies
306				[SPARX5_DCB_APPTRUST_DSCP_PCP];
307	}
308
309	return 0;
310}