File Index
Files and directories
Sign in
FILE

ksz_dcb.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/dsa/microchip/ksz_dcb.c C
  1// SPDX-License-Identifier: GPL-2.0
  2// Copyright (c) 2024 Pengutronix, Oleksij Rempel <kernel@pengutronix.de>
  3
  4#include <linux/dsa/ksz_common.h>
  5#include <net/dsa.h>
  6#include <net/dscp.h>
  7#include <net/ieee8021q.h>
  8
  9#include "ksz_common.h"
 10#include "ksz_dcb.h"
 11#include "ksz8.h"
 12
 13/* Port X Control 0 register.
 14 * The datasheet specifies: Port 1 - 0x10, Port 2 - 0x20, Port 3 - 0x30.
 15 * However, the driver uses get_port_addr(), which maps Port 1 to offset 0.
 16 * Therefore, we define the base offset as 0x00 here to align with that logic.
 17 */
 18#define KSZ8_REG_PORT_1_CTRL_0			0x00
 19#define KSZ8463_REG_PORT_1_CTRL_0		0x6C
 20#define KSZ8_PORT_DIFFSERV_ENABLE		BIT(6)
 21#define KSZ8_PORT_802_1P_ENABLE			BIT(5)
 22#define KSZ8_PORT_BASED_PRIO_M			GENMASK(4, 3)
 23
 24#define KSZ8463_REG_TOS_DSCP_CTRL		0x16
 25#define KSZ88X3_REG_TOS_DSCP_CTRL		0x60
 26#define KSZ8765_REG_TOS_DSCP_CTRL		0x90
 27
 28#define KSZ9477_REG_SW_MAC_TOS_CTRL		0x033e
 29#define KSZ9477_SW_TOS_DSCP_REMAP		BIT(0)
 30#define KSZ9477_SW_TOS_DSCP_DEFAULT_PRIO_M	GENMASK(5, 3)
 31
 32#define KSZ9477_REG_DIFFSERV_PRIO_MAP		0x0340
 33
 34#define KSZ9477_REG_PORT_MRI_PRIO_CTRL		0x0801
 35#define KSZ9477_PORT_HIGHEST_PRIO		BIT(7)
 36#define KSZ9477_PORT_OR_PRIO			BIT(6)
 37#define KSZ9477_PORT_MAC_PRIO_ENABLE		BIT(4)
 38#define KSZ9477_PORT_VLAN_PRIO_ENABLE		BIT(3)
 39#define KSZ9477_PORT_802_1P_PRIO_ENABLE		BIT(2)
 40#define KSZ9477_PORT_DIFFSERV_PRIO_ENABLE	BIT(1)
 41#define KSZ9477_PORT_ACL_PRIO_ENABLE		BIT(0)
 42
 43#define KSZ9477_REG_PORT_MRI_MAC_CTRL		0x0802
 44#define KSZ9477_PORT_BASED_PRIO_M		GENMASK(2, 0)
 45
 46struct ksz_apptrust_map {
 47	u8 apptrust;
 48	u8 bit;
 49};
 50
 51static const struct ksz_apptrust_map ksz8_apptrust_map_to_bit[] = {
 52	{ DCB_APP_SEL_PCP, KSZ8_PORT_802_1P_ENABLE },
 53	{ IEEE_8021QAZ_APP_SEL_DSCP, KSZ8_PORT_DIFFSERV_ENABLE },
 54};
 55
 56static const struct ksz_apptrust_map ksz9477_apptrust_map_to_bit[] = {
 57	{ DCB_APP_SEL_PCP, KSZ9477_PORT_802_1P_PRIO_ENABLE },
 58	{ IEEE_8021QAZ_APP_SEL_DSCP, KSZ9477_PORT_DIFFSERV_PRIO_ENABLE },
 59};
 60
 61/* ksz_supported_apptrust[] - Supported apptrust selectors and Priority Order
 62 *			      of Internal Priority Map (IPM) sources.
 63 *
 64 * This array defines the apptrust selectors supported by the hardware, where
 65 * the index within the array indicates the priority of the selector - lower
 66 * indices correspond to higher priority. This fixed priority scheme is due to
 67 * the hardware's design, which does not support configurable priority among
 68 * different priority sources.
 69 *
 70 * The priority sources, including Tail Tag, ACL, VLAN PCP and DSCP are ordered
 71 * by the hardware's fixed logic, as detailed below. The order reflects a
 72 * non-configurable precedence where certain types of priority information
 73 * override others:
 74 *
 75 * 1. Tail Tag - Highest priority, overrides ACL, VLAN PCP, and DSCP priorities.
 76 * 2. ACL - Overrides VLAN PCP and DSCP priorities.
 77 * 3. VLAN PCP - Overrides DSCP priority.
 78 * 4. DSCP - Lowest priority, does not override any other priority source.
 79 *
 80 * In this context, the array's lower index (higher priority) for
 81 * 'DCB_APP_SEL_PCP' suggests its relative priority over
 82 * 'IEEE_8021QAZ_APP_SEL_DSCP' within the system's fixed priority scheme.
 83 *
 84 * DCB_APP_SEL_PCP - Priority Code Point selector
 85 * IEEE_8021QAZ_APP_SEL_DSCP - Differentiated Services Code Point selector
 86 */
 87static const u8 ksz_supported_apptrust[] = {
 88	DCB_APP_SEL_PCP,
 89	IEEE_8021QAZ_APP_SEL_DSCP,
 90};
 91
 92static const char * const ksz_supported_apptrust_variants[] = {
 93	"empty", "dscp", "pcp", "dscp pcp"
 94};
 95
 96static void ksz_get_default_port_prio_reg(struct ksz_device *dev, int *reg,
 97					  u8 *mask, int *shift)
 98{
 99	if (is_ksz8(dev)) {
100		*reg = KSZ8_REG_PORT_1_CTRL_0;
101		*mask = KSZ8_PORT_BASED_PRIO_M;
102		*shift = __bf_shf(KSZ8_PORT_BASED_PRIO_M);
103		if (ksz_is_ksz8463(dev))
104			*reg = KSZ8463_REG_PORT_1_CTRL_0;
105	} else {
106		*reg = KSZ9477_REG_PORT_MRI_MAC_CTRL;
107		*mask = KSZ9477_PORT_BASED_PRIO_M;
108		*shift = __bf_shf(KSZ9477_PORT_BASED_PRIO_M);
109	}
110}
111
112/**
113 * ksz_get_dscp_prio_reg - Retrieves the DSCP-to-priority-mapping register
114 * @dev: Pointer to the KSZ switch device structure
115 * @reg: Pointer to the register address to be set
116 * @per_reg: Pointer to the number of DSCP values per register
117 * @mask: Pointer to the mask to be set
118 *
119 * This function retrieves the DSCP to priority mapping register, the number of
120 * DSCP values per register, and the mask to be set.
121 */
122static void ksz_get_dscp_prio_reg(struct ksz_device *dev, int *reg,
123				  int *per_reg, u8 *mask)
124{
125	if (ksz_is_ksz87xx(dev) || ksz_is_8895_family(dev)) {
126		*reg = KSZ8765_REG_TOS_DSCP_CTRL;
127		*per_reg = 4;
128		*mask = GENMASK(1, 0);
129	} else if (ksz_is_ksz88x3(dev) || ksz_is_ksz8463(dev)) {
130		*reg = KSZ88X3_REG_TOS_DSCP_CTRL;
131		*per_reg = 4;
132		*mask = GENMASK(1, 0);
133		if (ksz_is_ksz8463(dev))
134			*reg = KSZ8463_REG_TOS_DSCP_CTRL;
135	} else {
136		*reg = KSZ9477_REG_DIFFSERV_PRIO_MAP;
137		*per_reg = 2;
138		*mask = GENMASK(2, 0);
139	}
140}
141
142/**
143 * ksz_get_apptrust_map_and_reg - Retrieves the apptrust map and register
144 * @dev: Pointer to the KSZ switch device structure
145 * @map: Pointer to the apptrust map to be set
146 * @reg: Pointer to the register address to be set
147 * @mask: Pointer to the mask to be set
148 *
149 * This function retrieves the apptrust map and register address for the
150 * apptrust configuration.
151 */
152static void ksz_get_apptrust_map_and_reg(struct ksz_device *dev,
153					 const struct ksz_apptrust_map **map,
154					 int *reg, u8 *mask)
155{
156	if (is_ksz8(dev)) {
157		*map = ksz8_apptrust_map_to_bit;
158		*reg = KSZ8_REG_PORT_1_CTRL_0;
159		*mask = KSZ8_PORT_DIFFSERV_ENABLE | KSZ8_PORT_802_1P_ENABLE;
160		if (ksz_is_ksz8463(dev))
161			*reg = KSZ8463_REG_PORT_1_CTRL_0;
162	} else {
163		*map = ksz9477_apptrust_map_to_bit;
164		*reg = KSZ9477_REG_PORT_MRI_PRIO_CTRL;
165		*mask = KSZ9477_PORT_802_1P_PRIO_ENABLE |
166			KSZ9477_PORT_DIFFSERV_PRIO_ENABLE;
167	}
168}
169
170/**
171 * ksz_port_get_default_prio - Retrieves the default priority for a port on a
172 *			       KSZ switch
173 * @ds: Pointer to the DSA switch structure
174 * @port: Port number from which to get the default priority
175 *
176 * This function fetches the default priority for the specified port on a KSZ
177 * switch.
178 *
179 * Return: The default priority of the port on success, or a negative error
180 * code on failure.
181 */
182int ksz_port_get_default_prio(struct dsa_switch *ds, int port)
183{
184	struct ksz_device *dev = ds->priv;
185	int ret, reg, shift;
186	u8 data, mask;
187
188	ksz_get_default_port_prio_reg(dev, &reg, &mask, &shift);
189
190	ret = ksz_pread8(dev, port, reg, &data);
191	if (ret)
192		return ret;
193
194	return (data & mask) >> shift;
195}
196
197/**
198 * ksz_port_set_default_prio - Sets the default priority for a port on a KSZ
199 *			       switch
200 * @ds: Pointer to the DSA switch structure
201 * @port: Port number for which to set the default priority
202 * @prio: Priority value to set
203 *
204 * This function sets the default priority for the specified port on a KSZ
205 * switch.
206 *
207 * Return: 0 on success, or a negative error code on failure.
208 */
209int ksz_port_set_default_prio(struct dsa_switch *ds, int port, u8 prio)
210{
211	struct ksz_device *dev = ds->priv;
212	int reg, shift;
213	u8 mask;
214
215	if (prio >= dev->info->num_ipms)
216		return -EINVAL;
217
218	ksz_get_default_port_prio_reg(dev, &reg, &mask, &shift);
219
220	return ksz_prmw8(dev, port, reg, mask, (prio << shift) & mask);
221}
222
223/**
224 * ksz_port_get_dscp_prio - Retrieves the priority for a DSCP value on a KSZ
225 *			    switch
226 * @ds: Pointer to the DSA switch structure
227 * @port: Port number for which to get the priority
228 * @dscp: DSCP value for which to get the priority
229 *
230 * This function fetches the priority value from switch global DSCP-to-priorty
231 * mapping table for the specified DSCP value.
232 *
233 * Return: The priority value for the DSCP on success, or a negative error
234 * code on failure.
235 */
236int ksz_port_get_dscp_prio(struct dsa_switch *ds, int port, u8 dscp)
237{
238	struct ksz_device *dev = ds->priv;
239	int reg, per_reg, ret, shift;
240	u8 data, mask;
241
242	ksz_get_dscp_prio_reg(dev, &reg, &per_reg, &mask);
243
244	/* If DSCP remapping is disabled, DSCP bits 3-5 are used as Internal
245	 * Priority Map (IPM)
246	 */
247	if (!is_ksz8(dev)) {
248		ret = ksz_read8(dev, KSZ9477_REG_SW_MAC_TOS_CTRL, &data);
249		if (ret)
250			return ret;
251
252		/* If DSCP remapping is disabled, DSCP bits 3-5 are used as
253		 * Internal Priority Map (IPM)
254		 */
255		if (!(data & KSZ9477_SW_TOS_DSCP_REMAP))
256			return FIELD_GET(KSZ9477_SW_TOS_DSCP_DEFAULT_PRIO_M,
257					 dscp);
258	}
259
260	/* In case DSCP remapping is enabled, we need to write the DSCP to
261	 * priority mapping table.
262	 */
263	reg += dscp / per_reg;
264	ret = ksz_read8(dev, reg, &data);
265	if (ret)
266		return ret;
267
268	shift = (dscp % per_reg) * (8 / per_reg);
269
270	return (data >> shift) & mask;
271}
272
273/**
274 * ksz_set_global_dscp_entry - Sets the global DSCP-to-priority mapping entry
275 * @dev: Pointer to the KSZ switch device structure
276 * @dscp: DSCP value for which to set the priority
277 * @ipm: Priority value to set
278 *
279 * This function sets the global DSCP-to-priority mapping entry for the
280 * specified DSCP value.
281 *
282 * Return: 0 on success, or a negative error code on failure.
283 */
284static int ksz_set_global_dscp_entry(struct ksz_device *dev, u8 dscp, u8 ipm)
285{
286	int reg, per_reg, shift;
287	u8 mask;
288
289	ksz_get_dscp_prio_reg(dev, &reg, &per_reg, &mask);
290
291	shift = (dscp % per_reg) * (8 / per_reg);
292
293	return ksz_rmw8(dev, reg + (dscp / per_reg), mask << shift,
294			ipm << shift);
295}
296
297/**
298 * ksz_init_global_dscp_map - Initializes the global DSCP-to-priority mapping
299 * @dev: Pointer to the KSZ switch device structure
300 *
301 * This function initializes the global DSCP-to-priority mapping table for the
302 * switch.
303 *
304 * Return: 0 on success, or a negative error code on failure
305 */
306static int ksz_init_global_dscp_map(struct ksz_device *dev)
307{
308	int ret, dscp;
309
310	/* On KSZ9xxx variants, DSCP remapping is disabled by default.
311	 * Enable to have, predictable and reproducible behavior across
312	 * different devices.
313	 */
314	if (!is_ksz8(dev)) {
315		ret = ksz_rmw8(dev, KSZ9477_REG_SW_MAC_TOS_CTRL,
316			       KSZ9477_SW_TOS_DSCP_REMAP,
317			       KSZ9477_SW_TOS_DSCP_REMAP);
318		if (ret)
319			return ret;
320	}
321
322	for (dscp = 0; dscp < DSCP_MAX; dscp++) {
323		int ipm, tt;
324
325		/* Map DSCP to Traffic Type, which is corresponding to the
326		 * Internal Priority Map (IPM) in the switch.
327		 */
328		if (!is_ksz8(dev)) {
329			ipm = ietf_dscp_to_ieee8021q_tt(dscp);
330		} else {
331			/* On KSZ8xxx variants we do not have IPM to queue
332			 * remapping table. We need to convert DSCP to Traffic
333			 * Type and then to queue.
334			 */
335			tt = ietf_dscp_to_ieee8021q_tt(dscp);
336			if (tt < 0)
337				return tt;
338
339			ipm = ieee8021q_tt_to_tc(tt, dev->info->num_tx_queues);
340		}
341
342		if (ipm < 0)
343			return ipm;
344
345		ret = ksz_set_global_dscp_entry(dev, dscp, ipm);
346	}
347
348	return 0;
349}
350
351/**
352 * ksz_port_add_dscp_prio - Adds a DSCP-to-priority mapping entry for a port on
353 *			    a KSZ switch.
354 * @ds: Pointer to the DSA switch structure
355 * @port: Port number for which to add the DSCP-to-priority mapping entry
356 * @dscp: DSCP value for which to add the priority
357 * @prio: Priority value to set
358 *
359 * Return: 0 on success, or a negative error code on failure
360 */
361int ksz_port_add_dscp_prio(struct dsa_switch *ds, int port, u8 dscp, u8 prio)
362{
363	struct ksz_device *dev = ds->priv;
364
365	if (prio >= dev->info->num_ipms)
366		return -ERANGE;
367
368	return ksz_set_global_dscp_entry(dev, dscp, prio);
369}
370
371/**
372 * ksz_port_del_dscp_prio - Deletes a DSCP-to-priority mapping entry for a port
373 *			    on a KSZ switch.
374 * @ds: Pointer to the DSA switch structure
375 * @port: Port number for which to delete the DSCP-to-priority mapping entry
376 * @dscp: DSCP value for which to delete the priority
377 * @prio: Priority value to delete
378 *
379 * Return: 0 on success, or a negative error code on failure
380 */
381int ksz_port_del_dscp_prio(struct dsa_switch *ds, int port, u8 dscp, u8 prio)
382{
383	struct ksz_device *dev = ds->priv;
384	int ipm;
385
386	if (ksz_port_get_dscp_prio(ds, port, dscp) != prio)
387		return 0;
388
389	if (is_ksz8(dev)) {
390		ipm = ieee8021q_tt_to_tc(IEEE8021Q_TT_BE,
391					 dev->info->num_tx_queues);
392		if (ipm < 0)
393			return ipm;
394	} else {
395		ipm = IEEE8021Q_TT_BE;
396	}
397
398	return ksz_set_global_dscp_entry(dev, dscp, ipm);
399}
400
401/**
402 * ksz_apptrust_error - Prints an error message for an invalid apptrust selector
403 * @dev: Pointer to the KSZ switch device structure
404 *
405 * This function prints an error message when an invalid apptrust selector is
406 * provided.
407 */
408static void ksz_apptrust_error(struct ksz_device *dev)
409{
410	char supported_apptrust_variants[64];
411	int i;
412
413	supported_apptrust_variants[0] = '\0';
414	for (i = 0; i < ARRAY_SIZE(ksz_supported_apptrust_variants); i++) {
415		if (i > 0)
416			strlcat(supported_apptrust_variants, ", ",
417				sizeof(supported_apptrust_variants));
418		strlcat(supported_apptrust_variants,
419			ksz_supported_apptrust_variants[i],
420			sizeof(supported_apptrust_variants));
421	}
422
423	dev_err(dev->dev, "Invalid apptrust selector or priority order. Supported: %s\n",
424		supported_apptrust_variants);
425}
426
427/**
428 * ksz_port_set_apptrust_validate - Validates the apptrust selectors
429 * @dev: Pointer to the KSZ switch device structure
430 * @port: Port number for which to set the apptrust selectors
431 * @sel: Array of apptrust selectors to validate
432 * @nsel: Number of apptrust selectors in the array
433 *
434 * This function validates the apptrust selectors provided and ensures that
435 * they are in the correct order.
436 *
437 * This family of switches supports two apptrust selectors: DCB_APP_SEL_PCP and
438 * IEEE_8021QAZ_APP_SEL_DSCP. The priority order of the selectors is fixed and
439 * cannot be changed. The order is as follows:
440 * 1. DCB_APP_SEL_PCP - Priority Code Point selector (highest priority)
441 * 2. IEEE_8021QAZ_APP_SEL_DSCP - Differentiated Services Code Point selector
442 *   (lowest priority)
443 *
444 * Return: 0 on success, or a negative error code on failure
445 */
446static int ksz_port_set_apptrust_validate(struct ksz_device *dev, int port,
447					  const u8 *sel, int nsel)
448{
449	int i, j, found;
450	int j_prev = 0;
451
452	/* Iterate through the requested selectors */
453	for (i = 0; i < nsel; i++) {
454		found = 0;
455
456		/* Check if the current selector is supported by the hardware */
457		for (j = 0; j < sizeof(ksz_supported_apptrust); j++) {
458			if (sel[i] != ksz_supported_apptrust[j])
459				continue;
460
461			found = 1;
462
463			/* Ensure that no higher priority selector (lower index)
464			 * precedes a lower priority one
465			 */
466			if (i > 0 && j <= j_prev)
467				goto err_sel_not_vaild;
468
469			j_prev = j;
470			break;
471		}
472
473		if (!found)
474			goto err_sel_not_vaild;
475	}
476
477	return 0;
478
479err_sel_not_vaild:
480	ksz_apptrust_error(dev);
481
482	return -EINVAL;
483}
484
485/**
486 * ksz_port_set_apptrust - Sets the apptrust selectors for a port on a KSZ
487 *			   switch
488 * @ds: Pointer to the DSA switch structure
489 * @port: Port number for which to set the apptrust selectors
490 * @sel: Array of apptrust selectors to set
491 * @nsel: Number of apptrust selectors in the array
492 *
493 * This function sets the apptrust selectors for the specified port on a KSZ
494 * switch.
495 *
496 * Return: 0 on success, or a negative error code on failure
497 */
498int ksz_port_set_apptrust(struct dsa_switch *ds, int port,
499			  const u8 *sel, int nsel)
500{
501	const struct ksz_apptrust_map *map;
502	struct ksz_device *dev = ds->priv;
503	int reg, i, ret;
504	u8 data = 0;
505	u8 mask;
506
507	ret = ksz_port_set_apptrust_validate(dev, port, sel, nsel);
508	if (ret)
509		return ret;
510
511	ksz_get_apptrust_map_and_reg(dev, &map, &reg, &mask);
512
513	for (i = 0; i < nsel; i++) {
514		int j;
515
516		for (j = 0; j < ARRAY_SIZE(ksz_supported_apptrust); j++) {
517			if (sel[i] != ksz_supported_apptrust[j])
518				continue;
519
520			data |= map[j].bit;
521			break;
522		}
523	}
524
525	return ksz_prmw8(dev, port, reg, mask, data);
526}
527
528/**
529 * ksz_port_get_apptrust - Retrieves the apptrust selectors for a port on a KSZ
530 *			   switch
531 * @ds: Pointer to the DSA switch structure
532 * @port: Port number for which to get the apptrust selectors
533 * @sel: Array to store the apptrust selectors
534 * @nsel: Number of apptrust selectors in the array
535 *
536 * This function fetches the apptrust selectors for the specified port on a KSZ
537 * switch.
538 *
539 * Return: 0 on success, or a negative error code on failure
540 */
541int ksz_port_get_apptrust(struct dsa_switch *ds, int port, u8 *sel, int *nsel)
542{
543	const struct ksz_apptrust_map *map;
544	struct ksz_device *dev = ds->priv;
545	int reg, i, ret;
546	u8 data;
547	u8 mask;
548
549	ksz_get_apptrust_map_and_reg(dev, &map, &reg, &mask);
550
551	ret = ksz_pread8(dev, port, reg, &data);
552	if (ret)
553		return ret;
554
555	*nsel = 0;
556	for (i = 0; i < ARRAY_SIZE(ksz_supported_apptrust); i++) {
557		if (data & map[i].bit)
558			sel[(*nsel)++] = ksz_supported_apptrust[i];
559	}
560
561	return 0;
562}
563
564/**
565 * ksz_dcb_init_port - Initializes the DCB configuration for a port on a KSZ
566 * @dev: Pointer to the KSZ switch device structure
567 * @port: Port number for which to initialize the DCB configuration
568 *
569 * This function initializes the DCB configuration for the specified port on a
570 * KSZ switch. Particular DCB configuration is set for the port, including the
571 * default priority and apptrust selectors.
572 * The default priority is set to Best Effort, and the apptrust selectors are
573 * set to all supported selectors.
574 *
575 * Return: 0 on success, or a negative error code on failure
576 */
577int ksz_dcb_init_port(struct ksz_device *dev, int port)
578{
579	const u8 ksz_default_apptrust[] = { DCB_APP_SEL_PCP };
580	int ret, ipm;
581
582	if (is_ksz8(dev)) {
583		ipm = ieee8021q_tt_to_tc(IEEE8021Q_TT_BE,
584					 dev->info->num_tx_queues);
585		if (ipm < 0)
586			return ipm;
587	} else {
588		ipm = IEEE8021Q_TT_BE;
589	}
590
591	/* Set the default priority for the port to Best Effort */
592	ret = ksz_port_set_default_prio(dev->ds, port, ipm);
593	if (ret)
594		return ret;
595
596	return ksz_port_set_apptrust(dev->ds, port, ksz_default_apptrust,
597				     ARRAY_SIZE(ksz_default_apptrust));
598}
599
600/**
601 * ksz_dcb_init - Initializes the DCB configuration for a KSZ switch
602 * @dev: Pointer to the KSZ switch device structure
603 *
604 * This function initializes the DCB configuration for a KSZ switch. The global
605 * DSCP-to-priority mapping table is initialized.
606 *
607 * Return: 0 on success, or a negative error code on failure
608 */
609int ksz_dcb_init(struct ksz_device *dev)
610{
611	return ksz_init_global_dscp_map(dev);
612}
~/ Read-only file preview.