mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH net-next 0/2] net: dsa: mv88e6xxx: add support for DCB DSCP config
@ 2026-07-03  6:46 Luke Howard
  2026-07-03  6:46 ` [PATCH net-next 1/2] net: dsa: mv88e6xxx: add support for DCB DSCP app Luke Howard
  2026-07-03  6:46 ` [PATCH net-next 2/2] net: dsa: mv88e6xxx: add support for DCB apptrust app Luke Howard
  0 siblings, 2 replies; 3+ messages in thread
From: Luke Howard @ 2026-07-03  6:46 UTC (permalink / raw)
  To: Vladimir Oltean, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Vivien Didelot, Gregory CLEMENT, Andrew Lunn
  Cc: Cedric Jehasse, Kieran Tyrrell, Max Holtmann, Max Hunter,
	Christoph Mellauner, Simon Gapp, netdev, linux-kernel,
	Luke Howard

Add the DCB DSCP and apptrust applications for configuring DSCP to
queue mappings.

Signed-off-by: Luke Howard <lukeh@padl.com>
---
Luke Howard (2):
      net: dsa: mv88e6xxx: add support for DCB DSCP app
      net: dsa: mv88e6xxx: add support for DCB apptrust app

 drivers/net/dsa/mv88e6xxx/chip.c    |   8 +
 drivers/net/dsa/mv88e6xxx/chip.h    |  20 ++
 drivers/net/dsa/mv88e6xxx/dcb.c     | 406 ++++++++++++++++++++++++++++++++++++
 drivers/net/dsa/mv88e6xxx/dcb.h     |  11 +
 drivers/net/dsa/mv88e6xxx/global1.h |   8 +
 drivers/net/dsa/mv88e6xxx/port.h    |  10 +
 6 files changed, 463 insertions(+)
---
base-commit: 3abbe30231441f1fbb3305e9854c56a34650af53
change-id: 20260607-mv88e6xxx-dscp-prio-map-2fe4d8b0a19c
prerequisite-change-id: 20260430-net-next-mv88e6xxx-cbs-2121169caa68:v7
prerequisite-patch-id: 8ad59c43368d4639e0cabcc59a7f6e487560d3f7
prerequisite-patch-id: 22f1cda311b1826bd4151fc7d4cdf3d87ca519ed
prerequisite-change-id: 20260603-net-next-mv88e6xxx-pcp-prio-5752caa7926b:v1
prerequisite-patch-id: f324a0334ef91256d6f09562d978e9d6c32b7f3c
prerequisite-patch-id: 79c2b056ae68846b5e2950b9738cb83e73d2710e

Best regards,
--  
Luke Howard <lukeh@padl.com>


^ permalink raw reply	[flat|nested] 3+ messages in thread

* [PATCH net-next 1/2] net: dsa: mv88e6xxx: add support for DCB DSCP app
  2026-07-03  6:46 [PATCH net-next 0/2] net: dsa: mv88e6xxx: add support for DCB DSCP config Luke Howard
@ 2026-07-03  6:46 ` Luke Howard
  2026-07-03  6:46 ` [PATCH net-next 2/2] net: dsa: mv88e6xxx: add support for DCB apptrust app Luke Howard
  1 sibling, 0 replies; 3+ messages in thread
From: Luke Howard @ 2026-07-03  6:46 UTC (permalink / raw)
  To: Vladimir Oltean, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Vivien Didelot, Gregory CLEMENT, Andrew Lunn
  Cc: Cedric Jehasse, Kieran Tyrrell, Max Holtmann, Max Hunter,
	Christoph Mellauner, Simon Gapp, netdev, linux-kernel,
	Luke Howard

Implement {get,add,del}_dscp_prio for Marvell switches that support it.
On switches that do not support setting the QPri independently of FPri,
FPri is set to the default for the DSCP value.

On 6352-class switches the DSCP-to-QPri mapping is a global table with no
per-entry "unmapped" state: every DSCP is always mapped, so the DCB app
table comes up fully populated and deleting an entry restores its
reset-default QPri rather than removing it.

Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Luke Howard <lukeh@padl.com>
---
 drivers/net/dsa/mv88e6xxx/chip.c    |   6 +
 drivers/net/dsa/mv88e6xxx/chip.h    |  14 ++
 drivers/net/dsa/mv88e6xxx/dcb.c     | 294 ++++++++++++++++++++++++++++++++++++
 drivers/net/dsa/mv88e6xxx/dcb.h     |   6 +
 drivers/net/dsa/mv88e6xxx/global1.h |   8 +
 drivers/net/dsa/mv88e6xxx/port.h    |  10 ++
 6 files changed, 338 insertions(+)

diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index cefe6be2f0ce9..3bdf8c7b36612 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -7434,6 +7434,9 @@ static const struct dsa_switch_ops mv88e6xxx_switch_ops = {
 	.port_get_pcp_prio	= mv88e6xxx_port_get_pcp_prio,
 	.port_add_pcp_prio	= mv88e6xxx_port_add_pcp_prio,
 	.port_del_pcp_prio	= mv88e6xxx_port_del_pcp_prio,
+	.port_get_dscp_prio	= mv88e6xxx_port_get_dscp_prio,
+	.port_add_dscp_prio	= mv88e6xxx_port_add_dscp_prio,
+	.port_del_dscp_prio	= mv88e6xxx_port_del_dscp_prio,
 	.port_setup_tc		= mv88e6xxx_port_setup_tc,
 	.cls_flower_add		= mv88e6xxx_cls_flower_add,
 	.cls_flower_del         = mv88e6xxx_cls_flower_del,
@@ -7471,6 +7474,9 @@ static int mv88e6xxx_register_switch(struct mv88e6xxx_chip *chip)
 	ds->pcp_prio_mapping_is_global = dcb_ops &&
 					 dcb_ops->global_get_pcp_prio;
 
+	ds->dscp_prio_mapping_is_global = dcb_ops &&
+					  dcb_ops->global_get_dscp_prio;
+
 	/* Some chips support up to 32, but that requires enabling the
 	 * 5-bit port mode, which we do not support. 640k^W16 ought to
 	 * be enough for anyone.
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index 8c4e8b4890907..d6265e925574f 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -794,6 +794,20 @@ struct mv88e6xxx_dcb_ops {
 				 u8 pcp);
 	int (*port_set_pcp_prio)(struct mv88e6xxx_chip *chip, int port,
 				 u8 pcp, u8 prio);
+
+	/* Get/set the chip's global DSCP to queue priority (QPri) mapping */
+	int (*global_get_dscp_prio)(struct mv88e6xxx_chip *chip, u8 dscp);
+	int (*global_set_dscp_prio)(struct mv88e6xxx_chip *chip, u8 dscp,
+				    u8 prio);
+	int (*global_del_dscp_prio)(struct mv88e6xxx_chip *chip, u8 dscp);
+
+	/* Get/set a port's DSCP to queue priority (QPri) mapping */
+	int (*port_get_dscp_prio)(struct mv88e6xxx_chip *chip, int port,
+				  u8 dscp);
+	int (*port_set_dscp_prio)(struct mv88e6xxx_chip *chip, int port,
+				  u8 dscp, u8 prio);
+	int (*port_del_dscp_prio)(struct mv88e6xxx_chip *chip, int port,
+				  u8 dscp);
 };
 
 struct mv88e6xxx_ptp_ops {
diff --git a/drivers/net/dsa/mv88e6xxx/dcb.c b/drivers/net/dsa/mv88e6xxx/dcb.c
index 0a3099cdf3882..c26f43b27f09e 100644
--- a/drivers/net/dsa/mv88e6xxx/dcb.c
+++ b/drivers/net/dsa/mv88e6xxx/dcb.c
@@ -1,6 +1,10 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 // Copyright (c) 2026 Luminex Network Intelligence
 
+#include <linux/bitfield.h>
+
+#include <net/dscp.h>
+
 #include "chip.h"
 #include "dcb.h"
 #include "global1.h"
@@ -134,19 +138,201 @@ static int mv88e6393x_port_set_pcp_prio(struct mv88e6xxx_chip *chip, int port,
 	return mv88e639x_port_set_pcp_prio(chip, port, pcp, prio, true);
 }
 
+/* The DCB priority maps the DSCP to an egress queue priority (QPri); the frame
+ * priority (FPri) is left untouched.  These chips always map every DSCP, so
+ * there is no per-entry "unmapped" state on the global (6352) table: deleting
+ * an entry restores its reset-default QPri rather than removing it.
+ */
+
+/* G1 offset 0x19 is the IP Mapping Table only on these families; elsewhere it is
+ * the Core Tag Type register, so report DSCP mapping as unsupported there.
+ */
+static bool mv88e6352_has_ip_pri_map(struct mv88e6xxx_chip *chip)
+{
+	switch (chip->info->family) {
+	case MV88E6XXX_FAMILY_6320:
+	case MV88E6XXX_FAMILY_6341:
+	case MV88E6XXX_FAMILY_6352:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static int mv88e6352_get_dscp_prio(struct mv88e6xxx_chip *chip, u8 dscp)
+{
+	u16 val;
+	int err;
+
+	if (!mv88e6352_has_ip_pri_map(chip))
+		return -EOPNOTSUPP;
+
+	if (dscp >= DSCP_MAX)
+		return -EINVAL;
+
+	/* load the table pointer (Update clear), then read the entry back */
+	err = mv88e6xxx_g1_write(chip, MV88E6352_G1_IP_PRI_MAP,
+				 FIELD_PREP(MV88E6352_G1_IP_PRI_MAP_PTR_MASK,
+					    dscp));
+	if (err)
+		return err;
+
+	err = mv88e6xxx_g1_read(chip, MV88E6352_G1_IP_PRI_MAP, &val);
+	if (err)
+		return err;
+
+	return FIELD_GET(MV88E6352_G1_IP_PRI_MAP_QPRI_MASK, val);
+}
+
+/* Update only the QPri of a DSCP entry, preserving the global UseIpFPri bit and
+ * the per-entry FPri so the frame priority handling is left untouched.
+ */
+static int mv88e6352_write_dscp_qpri(struct mv88e6xxx_chip *chip, u8 dscp,
+				     u8 prio)
+{
+	u16 val;
+	int err;
+
+	/* load the table pointer (Update clear), then read the entry back */
+	err = mv88e6xxx_g1_write(chip, MV88E6352_G1_IP_PRI_MAP,
+				 FIELD_PREP(MV88E6352_G1_IP_PRI_MAP_PTR_MASK,
+					    dscp));
+	if (err)
+		return err;
+
+	err = mv88e6xxx_g1_read(chip, MV88E6352_G1_IP_PRI_MAP, &val);
+	if (err)
+		return err;
+
+	val &= ~(MV88E6352_G1_IP_PRI_MAP_PTR_MASK |
+		 MV88E6352_G1_IP_PRI_MAP_QPRI_MASK);
+	val |= MV88E6352_G1_IP_PRI_MAP_UPDATE |
+	       FIELD_PREP(MV88E6352_G1_IP_PRI_MAP_PTR_MASK, dscp) |
+	       FIELD_PREP(MV88E6352_G1_IP_PRI_MAP_QPRI_MASK, prio);
+
+	return mv88e6xxx_g1_write(chip, MV88E6352_G1_IP_PRI_MAP, val);
+}
+
+static int mv88e6352_set_dscp_prio(struct mv88e6xxx_chip *chip, u8 dscp,
+				   u8 prio)
+{
+	if (!mv88e6352_has_ip_pri_map(chip))
+		return -EOPNOTSUPP;
+
+	if (dscp >= DSCP_MAX)
+		return -EINVAL;
+
+	/* QPri range as for the PCP-to-priority mapping */
+	if (prio >= 4)
+		return -EINVAL;
+
+	return mv88e6352_write_dscp_qpri(chip, dscp, prio);
+}
+
+static int mv88e6352_del_dscp_prio(struct mv88e6xxx_chip *chip, u8 dscp)
+{
+	if (!mv88e6352_has_ip_pri_map(chip))
+		return -EOPNOTSUPP;
+
+	if (dscp >= DSCP_MAX)
+		return -EINVAL;
+
+	/* No per-entry disable exists, so restore the reset-default QPri, which
+	 * is the top two DSCP bits (DSCP >> 4: 0x00-0x0f->0, 0x10-0x1f->1,
+	 * 0x20-0x2f->2, 0x30-0x3f->3).
+	 */
+	return mv88e6352_write_dscp_qpri(chip, dscp, dscp >> 4);
+}
+
+static int mv88e6390_port_get_dscp_prio(struct mv88e6xxx_chip *chip, int port,
+					u8 dscp)
+{
+	u16 val;
+	int err;
+
+	if (dscp >= DSCP_MAX)
+		return -EINVAL;
+
+	/* load the table pointer (Update clear), then read the entry back */
+	err = mv88e6xxx_port_write(chip, port, MV88E6390_PORT_IP_PRI_MAP,
+				   FIELD_PREP(MV88E6390_PORT_IP_PRI_MAP_PTR_MASK,
+					      dscp));
+	if (err)
+		return err;
+
+	err = mv88e6xxx_port_read(chip, port, MV88E6390_PORT_IP_PRI_MAP, &val);
+	if (err)
+		return err;
+
+	if (val & MV88E6390_PORT_IP_PRI_MAP_DIS_IP_QPRI)
+		return -EOPNOTSUPP;
+
+	return FIELD_GET(MV88E6390_PORT_IP_PRI_MAP_QPRI_MASK, val);
+}
+
+static int mv88e6390_port_set_dscp_prio(struct mv88e6xxx_chip *chip, int port,
+					u8 dscp, u8 prio)
+{
+	if (dscp >= DSCP_MAX)
+		return -EINVAL;
+
+	/* QPri range as for the PCP-to-priority mapping */
+	if (prio >= 8)
+		return -EINVAL;
+
+	/* This write defines the whole entry: enable and set the QPri, disable
+	 * the FPri override so frame priority is left unchanged, and leave
+	 * IP_YELLOW clear.  The entry is owned solely by this API, so a blind
+	 * write is sufficient and no read-modify-write is needed.
+	 */
+	return mv88e6xxx_port_write(chip, port, MV88E6390_PORT_IP_PRI_MAP,
+				   MV88E6390_PORT_IP_PRI_MAP_UPDATE |
+				   MV88E6390_PORT_IP_PRI_MAP_DIS_IP_FPRI |
+				   FIELD_PREP(MV88E6390_PORT_IP_PRI_MAP_PTR_MASK,
+					      dscp) |
+				   FIELD_PREP(MV88E6390_PORT_IP_PRI_MAP_QPRI_MASK,
+					      prio));
+}
+
+static int mv88e6390_port_del_dscp_prio(struct mv88e6xxx_chip *chip, int port,
+					u8 dscp)
+{
+	if (dscp >= DSCP_MAX)
+		return -EINVAL;
+
+	/* Disable both the QPri and FPri overrides so the DSCP falls back to the
+	 * port default; get_dscp_prio then reports the entry as removed.
+	 */
+	return mv88e6xxx_port_write(chip, port, MV88E6390_PORT_IP_PRI_MAP,
+				   MV88E6390_PORT_IP_PRI_MAP_UPDATE |
+				   MV88E6390_PORT_IP_PRI_MAP_DIS_IP_QPRI |
+				   MV88E6390_PORT_IP_PRI_MAP_DIS_IP_FPRI |
+				   FIELD_PREP(MV88E6390_PORT_IP_PRI_MAP_PTR_MASK,
+					      dscp));
+}
+
 const struct mv88e6xxx_dcb_ops mv88e6352_dcb_ops = {
 	.global_get_pcp_prio = mv88e6352_get_pcp_prio,
 	.global_set_pcp_prio = mv88e6352_set_pcp_prio,
+	.global_get_dscp_prio = mv88e6352_get_dscp_prio,
+	.global_set_dscp_prio = mv88e6352_set_dscp_prio,
+	.global_del_dscp_prio = mv88e6352_del_dscp_prio,
 };
 
 const struct mv88e6xxx_dcb_ops mv88e6390_dcb_ops = {
 	.port_get_pcp_prio = mv88e6390_port_get_pcp_prio,
 	.port_set_pcp_prio = mv88e6390_port_set_pcp_prio,
+	.port_get_dscp_prio = mv88e6390_port_get_dscp_prio,
+	.port_set_dscp_prio = mv88e6390_port_set_dscp_prio,
+	.port_del_dscp_prio = mv88e6390_port_del_dscp_prio,
 };
 
 const struct mv88e6xxx_dcb_ops mv88e6393x_dcb_ops = {
 	.port_get_pcp_prio = mv88e6393x_port_get_pcp_prio,
 	.port_set_pcp_prio = mv88e6393x_port_set_pcp_prio,
+	.port_get_dscp_prio = mv88e6390_port_get_dscp_prio,
+	.port_set_dscp_prio = mv88e6390_port_set_dscp_prio,
+	.port_del_dscp_prio = mv88e6390_port_del_dscp_prio,
 };
 
 static int mv88e6xxx_dcb_get_pcp_prio(struct mv88e6xxx_chip *chip, int port,
@@ -227,3 +413,111 @@ int mv88e6xxx_port_del_pcp_prio(struct dsa_switch *ds, int port, u8 pcp,
 	mv88e6xxx_reg_unlock(chip);
 	return err;
 }
+
+static int mv88e6xxx_dcb_get_dscp_prio(struct mv88e6xxx_chip *chip, int port,
+				       u8 dscp)
+{
+	const struct mv88e6xxx_dcb_ops *dcb_ops = chip->info->ops->dcb_ops;
+
+	if (!dcb_ops)
+		return -EOPNOTSUPP;
+
+	if (dcb_ops->port_get_dscp_prio)
+		return dcb_ops->port_get_dscp_prio(chip, port, dscp);
+
+	if (dcb_ops->global_get_dscp_prio)
+		return dcb_ops->global_get_dscp_prio(chip, dscp);
+
+	return -EOPNOTSUPP;
+}
+
+static int mv88e6xxx_dcb_set_dscp_prio(struct mv88e6xxx_chip *chip, int port,
+				       u8 dscp, u8 prio)
+{
+	const struct mv88e6xxx_dcb_ops *dcb_ops = chip->info->ops->dcb_ops;
+
+	if (!dcb_ops)
+		return -EOPNOTSUPP;
+
+	if (dcb_ops->port_set_dscp_prio)
+		return dcb_ops->port_set_dscp_prio(chip, port, dscp, prio);
+
+	if (dcb_ops->global_set_dscp_prio)
+		return dcb_ops->global_set_dscp_prio(chip, dscp, prio);
+
+	return -EOPNOTSUPP;
+}
+
+static int mv88e6xxx_dcb_del_dscp_prio(struct mv88e6xxx_chip *chip, int port,
+				       u8 dscp)
+{
+	const struct mv88e6xxx_dcb_ops *dcb_ops = chip->info->ops->dcb_ops;
+
+	if (!dcb_ops)
+		return -EOPNOTSUPP;
+
+	if (dcb_ops->port_del_dscp_prio)
+		return dcb_ops->port_del_dscp_prio(chip, port, dscp);
+
+	if (dcb_ops->global_del_dscp_prio)
+		return dcb_ops->global_del_dscp_prio(chip, dscp);
+
+	return -EOPNOTSUPP;
+}
+
+int mv88e6xxx_port_get_dscp_prio(struct dsa_switch *ds, int port, u8 dscp)
+{
+	struct mv88e6xxx_chip *chip = ds->priv;
+	int err;
+
+	mv88e6xxx_reg_lock(chip);
+	err = mv88e6xxx_dcb_get_dscp_prio(chip, port, dscp);
+	mv88e6xxx_reg_unlock(chip);
+
+	return err;
+}
+
+int mv88e6xxx_port_add_dscp_prio(struct dsa_switch *ds, int port, u8 dscp,
+				 u8 prio)
+{
+	struct mv88e6xxx_chip *chip = ds->priv;
+	int err;
+
+	if (prio >= IEEE_8021Q_MAX_PRIORITIES)
+		return -EINVAL;
+
+	mv88e6xxx_reg_lock(chip);
+	err = mv88e6xxx_dcb_set_dscp_prio(chip, port, dscp, prio);
+	mv88e6xxx_reg_unlock(chip);
+
+	return err;
+}
+
+int mv88e6xxx_port_del_dscp_prio(struct dsa_switch *ds, int port, u8 dscp,
+				 u8 prio)
+{
+	struct mv88e6xxx_chip *chip = ds->priv;
+	int err;
+
+	mv88e6xxx_reg_lock(chip);
+
+	err = mv88e6xxx_dcb_get_dscp_prio(chip, port, dscp);
+	if (err == -EOPNOTSUPP) {
+		/* No explicit mapping for this DSCP, so nothing to remove */
+		err = 0;
+		goto unlock;
+	}
+	if (err < 0)
+		goto unlock;
+	if (err != prio) {
+		/* Mapping was changed in the meantime; leave it alone */
+		err = 0;
+		goto unlock;
+	}
+
+	err = mv88e6xxx_dcb_del_dscp_prio(chip, port, dscp);
+
+unlock:
+	mv88e6xxx_reg_unlock(chip);
+	return err;
+}
diff --git a/drivers/net/dsa/mv88e6xxx/dcb.h b/drivers/net/dsa/mv88e6xxx/dcb.h
index 7a2124ec23ba9..e1cf92bbd8729 100644
--- a/drivers/net/dsa/mv88e6xxx/dcb.h
+++ b/drivers/net/dsa/mv88e6xxx/dcb.h
@@ -18,4 +18,10 @@ int mv88e6xxx_port_add_pcp_prio(struct dsa_switch *ds, int port, u8 pcp,
 int mv88e6xxx_port_del_pcp_prio(struct dsa_switch *ds, int port, u8 pcp,
 				u8 prio);
 
+int mv88e6xxx_port_get_dscp_prio(struct dsa_switch *ds, int port, u8 dscp);
+int mv88e6xxx_port_add_dscp_prio(struct dsa_switch *ds, int port, u8 dscp,
+				 u8 prio);
+int mv88e6xxx_port_del_dscp_prio(struct dsa_switch *ds, int port, u8 dscp,
+				 u8 prio);
+
 #endif /* _MV88E6XXX_DCB_H_ */
diff --git a/drivers/net/dsa/mv88e6xxx/global1.h b/drivers/net/dsa/mv88e6xxx/global1.h
index 3dbb7a1b8fe11..fdc9795fa5c6d 100644
--- a/drivers/net/dsa/mv88e6xxx/global1.h
+++ b/drivers/net/dsa/mv88e6xxx/global1.h
@@ -195,6 +195,14 @@
 /* Offset 0x19: Core Tag Type */
 #define MV88E6185_G1_CORE_TAG_TYPE	0x19
 
+/* Offset 0x19: IP Mapping Table (6172/6176/6240/6320/6341/6352) */
+#define MV88E6352_G1_IP_PRI_MAP			0x19
+#define MV88E6352_G1_IP_PRI_MAP_UPDATE		0x8000
+#define MV88E6352_G1_IP_PRI_MAP_USE_IP_FPRI	0x4000
+#define MV88E6352_G1_IP_PRI_MAP_PTR_MASK	0x3f00
+#define MV88E6352_G1_IP_PRI_MAP_FPRI_MASK	0x0070
+#define MV88E6352_G1_IP_PRI_MAP_QPRI_MASK	0x0003
+
 /* Offset 0x1A: Monitor Control */
 #define MV88E6185_G1_MONITOR_CTL			0x1a
 #define MV88E6185_G1_MONITOR_CTL_INGRESS_DEST_MASK	0xf000
diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h
index 56143fa534c16..230a99f404606 100644
--- a/drivers/net/dsa/mv88e6xxx/port.h
+++ b/drivers/net/dsa/mv88e6xxx/port.h
@@ -448,6 +448,16 @@
 /* Control for Special LED (Index 0x7 of LED Control on Port 2) */
 #define MV88E6XXX_PORT_LED_CONTROL_0x07_P2_PTP_ACT		0 /* bits 6:0 PTP Activity */
 
+/* Offset 0x17: IP Priority Mapping Table */
+#define MV88E6390_PORT_IP_PRI_MAP			0x17
+#define MV88E6390_PORT_IP_PRI_MAP_UPDATE		BIT(15)
+#define MV88E6390_PORT_IP_PRI_MAP_PTR_MASK		GENMASK(14, 9)
+#define MV88E6390_PORT_IP_PRI_MAP_IP_YELLOW		BIT(8)
+#define MV88E6390_PORT_IP_PRI_MAP_DIS_IP_QPRI		BIT(7)
+#define MV88E6390_PORT_IP_PRI_MAP_QPRI_MASK		GENMASK(6, 4)
+#define MV88E6390_PORT_IP_PRI_MAP_DIS_IP_FPRI		BIT(3)
+#define MV88E6390_PORT_IP_PRI_MAP_FPRI_MASK		GENMASK(2, 0)
+
 /* Offset 0x18: IEEE Priority Mapping Table */
 #define MV88E6390_PORT_IEEE_PRIO_MAP_TABLE			0x18
 #define MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_UPDATE		0x8000

-- 
2.43.0


^ permalink raw reply	[flat|nested] 3+ messages in thread

* [PATCH net-next 2/2] net: dsa: mv88e6xxx: add support for DCB apptrust app
  2026-07-03  6:46 [PATCH net-next 0/2] net: dsa: mv88e6xxx: add support for DCB DSCP config Luke Howard
  2026-07-03  6:46 ` [PATCH net-next 1/2] net: dsa: mv88e6xxx: add support for DCB DSCP app Luke Howard
@ 2026-07-03  6:46 ` Luke Howard
  1 sibling, 0 replies; 3+ messages in thread
From: Luke Howard @ 2026-07-03  6:46 UTC (permalink / raw)
  To: Vladimir Oltean, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Vivien Didelot, Gregory CLEMENT, Andrew Lunn
  Cc: Cedric Jehasse, Kieran Tyrrell, Max Holtmann, Max Hunter,
	Christoph Mellauner, Simon Gapp, netdev, linux-kernel,
	Luke Howard

Implement port_{get,set}_apptrust for Marvell switches that support it.

This maps to the per-port USE_TAG / USE_IP / TAG_IF_BOTH bits in Port
Control 0, which the driver already initialises for every port (trust
both, IP taking precedence), so apptrust is available across the shared
mv88e6352_dcb_ops families, not only the 6352/6390/6393x.

Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Luke Howard <lukeh@padl.com>
---
 drivers/net/dsa/mv88e6xxx/chip.c |   2 +
 drivers/net/dsa/mv88e6xxx/chip.h |   6 +++
 drivers/net/dsa/mv88e6xxx/dcb.c  | 112 +++++++++++++++++++++++++++++++++++++++
 drivers/net/dsa/mv88e6xxx/dcb.h  |   5 ++
 4 files changed, 125 insertions(+)

diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 3bdf8c7b36612..6b85b2d0a982f 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -7437,6 +7437,8 @@ static const struct dsa_switch_ops mv88e6xxx_switch_ops = {
 	.port_get_dscp_prio	= mv88e6xxx_port_get_dscp_prio,
 	.port_add_dscp_prio	= mv88e6xxx_port_add_dscp_prio,
 	.port_del_dscp_prio	= mv88e6xxx_port_del_dscp_prio,
+	.port_get_apptrust	= mv88e6xxx_port_get_apptrust,
+	.port_set_apptrust	= mv88e6xxx_port_set_apptrust,
 	.port_setup_tc		= mv88e6xxx_port_setup_tc,
 	.cls_flower_add		= mv88e6xxx_cls_flower_add,
 	.cls_flower_del         = mv88e6xxx_cls_flower_del,
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index d6265e925574f..e95be110dfa7b 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -808,6 +808,12 @@ struct mv88e6xxx_dcb_ops {
 				  u8 dscp, u8 prio);
 	int (*port_del_dscp_prio)(struct mv88e6xxx_chip *chip, int port,
 				  u8 dscp);
+
+	/* Get/set a port's trusted application priority sources */
+	int (*port_get_apptrust)(struct mv88e6xxx_chip *chip, int port,
+				 u8 *sel, int *nsel);
+	int (*port_set_apptrust)(struct mv88e6xxx_chip *chip, int port,
+				 const u8 *sel, int nsel);
 };
 
 struct mv88e6xxx_ptp_ops {
diff --git a/drivers/net/dsa/mv88e6xxx/dcb.c b/drivers/net/dsa/mv88e6xxx/dcb.c
index c26f43b27f09e..08a08acb9bfad 100644
--- a/drivers/net/dsa/mv88e6xxx/dcb.c
+++ b/drivers/net/dsa/mv88e6xxx/dcb.c
@@ -311,12 +311,86 @@ static int mv88e6390_port_del_dscp_prio(struct mv88e6xxx_chip *chip, int port,
 					      dscp));
 }
 
+/* Application trust (apptrust).
+ *
+ * InitialPri (the UseTag/UseIP bits) selects which ingress values a port
+ * trusts for priority assignment; TagIfBoth breaks the tie when a frame
+ * matches both.  DCB lists selectors in increasing precedence, so the
+ * last-named selector is the most trusted.
+ */
+
+static int mv88e6xxx_set_apptrust(struct mv88e6xxx_chip *chip, int port,
+				  const u8 *sel, int nsel)
+{
+	bool use_tag = false, use_ip = false, tag_wins = false;
+	u16 reg;
+	int i, err;
+
+	for (i = 0; i < nsel; i++) {
+		switch (sel[i]) {
+		case DCB_APP_SEL_PCP:
+			use_tag = true;
+			tag_wins = true;
+			break;
+		case IEEE_8021QAZ_APP_SEL_DSCP:
+			use_ip = true;
+			tag_wins = false;
+			break;
+		default:
+			return -EOPNOTSUPP;
+		}
+	}
+
+	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, &reg);
+	if (err)
+		return err;
+
+	reg &= ~(MV88E6185_PORT_CTL0_USE_TAG | MV88E6185_PORT_CTL0_USE_IP |
+		 MV88E6XXX_PORT_CTL0_TAG_IF_BOTH);
+	if (use_tag)
+		reg |= MV88E6185_PORT_CTL0_USE_TAG;
+	if (use_ip)
+		reg |= MV88E6185_PORT_CTL0_USE_IP;
+	if (use_tag && use_ip && tag_wins)
+		reg |= MV88E6XXX_PORT_CTL0_TAG_IF_BOTH;
+
+	return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);
+}
+
+static int mv88e6xxx_get_apptrust(struct mv88e6xxx_chip *chip, int port,
+				  u8 *sel, int *nsel)
+{
+	bool tag_wins;
+	u16 reg;
+	int err, n = 0;
+
+	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, &reg);
+	if (err)
+		return err;
+
+	/* Report in increasing precedence: the winner of TagIfBoth comes last */
+	tag_wins = reg & MV88E6XXX_PORT_CTL0_TAG_IF_BOTH;
+
+	if (!tag_wins && (reg & MV88E6185_PORT_CTL0_USE_TAG))
+		sel[n++] = DCB_APP_SEL_PCP;
+	if (reg & MV88E6185_PORT_CTL0_USE_IP)
+		sel[n++] = IEEE_8021QAZ_APP_SEL_DSCP;
+	if (tag_wins && (reg & MV88E6185_PORT_CTL0_USE_TAG))
+		sel[n++] = DCB_APP_SEL_PCP;
+
+	*nsel = n;
+
+	return 0;
+}
+
 const struct mv88e6xxx_dcb_ops mv88e6352_dcb_ops = {
 	.global_get_pcp_prio = mv88e6352_get_pcp_prio,
 	.global_set_pcp_prio = mv88e6352_set_pcp_prio,
 	.global_get_dscp_prio = mv88e6352_get_dscp_prio,
 	.global_set_dscp_prio = mv88e6352_set_dscp_prio,
 	.global_del_dscp_prio = mv88e6352_del_dscp_prio,
+	.port_get_apptrust = mv88e6xxx_get_apptrust,
+	.port_set_apptrust = mv88e6xxx_set_apptrust,
 };
 
 const struct mv88e6xxx_dcb_ops mv88e6390_dcb_ops = {
@@ -325,6 +399,8 @@ const struct mv88e6xxx_dcb_ops mv88e6390_dcb_ops = {
 	.port_get_dscp_prio = mv88e6390_port_get_dscp_prio,
 	.port_set_dscp_prio = mv88e6390_port_set_dscp_prio,
 	.port_del_dscp_prio = mv88e6390_port_del_dscp_prio,
+	.port_get_apptrust = mv88e6xxx_get_apptrust,
+	.port_set_apptrust = mv88e6xxx_set_apptrust,
 };
 
 const struct mv88e6xxx_dcb_ops mv88e6393x_dcb_ops = {
@@ -333,6 +409,8 @@ const struct mv88e6xxx_dcb_ops mv88e6393x_dcb_ops = {
 	.port_get_dscp_prio = mv88e6390_port_get_dscp_prio,
 	.port_set_dscp_prio = mv88e6390_port_set_dscp_prio,
 	.port_del_dscp_prio = mv88e6390_port_del_dscp_prio,
+	.port_get_apptrust = mv88e6xxx_get_apptrust,
+	.port_set_apptrust = mv88e6xxx_set_apptrust,
 };
 
 static int mv88e6xxx_dcb_get_pcp_prio(struct mv88e6xxx_chip *chip, int port,
@@ -521,3 +599,37 @@ int mv88e6xxx_port_del_dscp_prio(struct dsa_switch *ds, int port, u8 dscp,
 	mv88e6xxx_reg_unlock(chip);
 	return err;
 }
+
+int mv88e6xxx_port_get_apptrust(struct dsa_switch *ds, int port, u8 *sel,
+				int *nsel)
+{
+	struct mv88e6xxx_chip *chip = ds->priv;
+	const struct mv88e6xxx_dcb_ops *dcb_ops = chip->info->ops->dcb_ops;
+	int err;
+
+	if (!dcb_ops || !dcb_ops->port_get_apptrust)
+		return -EOPNOTSUPP;
+
+	mv88e6xxx_reg_lock(chip);
+	err = dcb_ops->port_get_apptrust(chip, port, sel, nsel);
+	mv88e6xxx_reg_unlock(chip);
+
+	return err;
+}
+
+int mv88e6xxx_port_set_apptrust(struct dsa_switch *ds, int port, const u8 *sel,
+				int nsel)
+{
+	struct mv88e6xxx_chip *chip = ds->priv;
+	const struct mv88e6xxx_dcb_ops *dcb_ops = chip->info->ops->dcb_ops;
+	int err;
+
+	if (!dcb_ops || !dcb_ops->port_set_apptrust)
+		return -EOPNOTSUPP;
+
+	mv88e6xxx_reg_lock(chip);
+	err = dcb_ops->port_set_apptrust(chip, port, sel, nsel);
+	mv88e6xxx_reg_unlock(chip);
+
+	return err;
+}
diff --git a/drivers/net/dsa/mv88e6xxx/dcb.h b/drivers/net/dsa/mv88e6xxx/dcb.h
index e1cf92bbd8729..256d25d650014 100644
--- a/drivers/net/dsa/mv88e6xxx/dcb.h
+++ b/drivers/net/dsa/mv88e6xxx/dcb.h
@@ -24,4 +24,9 @@ int mv88e6xxx_port_add_dscp_prio(struct dsa_switch *ds, int port, u8 dscp,
 int mv88e6xxx_port_del_dscp_prio(struct dsa_switch *ds, int port, u8 dscp,
 				 u8 prio);
 
+int mv88e6xxx_port_get_apptrust(struct dsa_switch *ds, int port, u8 *sel,
+				int *nsel);
+int mv88e6xxx_port_set_apptrust(struct dsa_switch *ds, int port, const u8 *sel,
+				int nsel);
+
 #endif /* _MV88E6XXX_DCB_H_ */

-- 
2.43.0


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-07-03  6:46 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-07-03  6:46 [PATCH net-next 0/2] net: dsa: mv88e6xxx: add support for DCB DSCP config Luke Howard
2026-07-03  6:46 ` [PATCH net-next 1/2] net: dsa: mv88e6xxx: add support for DCB DSCP app Luke Howard
2026-07-03  6:46 ` [PATCH net-next 2/2] net: dsa: mv88e6xxx: add support for DCB apptrust app Luke Howard

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox