[PATCH net-next v2 08/10] net: dsa: realtek: rtl8365mb: program the PCP of untagged frames
From: Oleksij Rempel
Date: Thu Nov 12 2026 - 04:07:14 EST
Program the PCP that the switch gives to untagged frames whenever the
port default priority is set.
With PCP trust, the switch classifies an untagged frame by this value.
The value is 0 after reset, so untagged frames would be Best Effort
whatever the port default priority is. PCP trust is added by "net: dsa:
realtek: rtl8365mb: offload DCB apptrust".
The switch also puts this value into the tag it adds on egress. So far,
an untagged frame that left a VLAN-tagged port carried PCP 0. With a
default priority set, it now carries that priority as its PCP. The
standards require this:
IEEE 802.1AC-2016, 13.1: "The priority parameter of the
M_UNITDATA.indication shall take the value of the Default Priority
parameter for the SAP on which the MA_DATA.indication was received."
IEEE 802.1Q-2022, 6.9.4: "For untagged frames, the priority parameter
signaled in the corresponding M_UNITDATA.indication is taken to be the
received priority."
IEEE 802.1Q-2022, 6.9.3: "The priority and drop_eligible parameters
are encoded in the PCP field of the VLAN tag using the Priority Code
Point Encoding Table for the Port". With the default priority
regeneration (Table 6-4) and the 8P0D encoding (Table 6-2), the PCP
equals the Default Priority.
Signed-off-by: Oleksij Rempel <o.rempel@xxxxxxxxxxxxxx>
---
Changes in v2:
- New in v2. PCP trust needs it, or untagged frames would be Best
Effort.
---
drivers/net/dsa/realtek/realtek.h | 6 +++++-
drivers/net/dsa/realtek/rtl8365mb_qos.c | 18 +++++++++++++++++-
drivers/net/dsa/realtek/rtl8365mb_qos.h | 3 ++-
drivers/net/dsa/realtek/rtl83xx-qos.c | 14 ++++++++++----
4 files changed, 34 insertions(+), 7 deletions(-)
diff --git a/drivers/net/dsa/realtek/realtek.h b/drivers/net/dsa/realtek/realtek.h
index 9a7906331cbdeef03c59cb4859c32c6fef2020d9..a9bdadbea3cbe19eeef0f33762318f022881e75f 100644
--- a/drivers/net/dsa/realtek/realtek.h
+++ b/drivers/net/dsa/realtek/realtek.h
@@ -165,8 +165,12 @@ struct realtek_ops {
* priority. A *_prio getter returns an iprio or a negative errno.
*/
int (*qos_get_port_prio)(struct realtek_priv *priv, int port);
+ /* Set the priority of @port to @iprio, and make @untag_pcp the PCP
+ * given to untagged frames on @port. @untag_pcp is an 802.1p
+ * priority, not an iprio.
+ */
int (*qos_set_port_prio)(struct realtek_priv *priv, int port,
- u8 iprio);
+ u8 iprio, u8 untag_pcp);
int (*qos_set_pcp_prio)(struct realtek_priv *priv, u8 pcp, u8 iprio);
int (*qos_set_dscp_prio)(struct realtek_priv *priv, u8 dscp,
u8 iprio);
diff --git a/drivers/net/dsa/realtek/rtl8365mb_qos.c b/drivers/net/dsa/realtek/rtl8365mb_qos.c
index 378cd6ed7fe6447cc7508fef90dec4c5332cf3e1..2a849d0e4898a712d8f4babd5cdd03fe8e207814 100644
--- a/drivers/net/dsa/realtek/rtl8365mb_qos.c
+++ b/drivers/net/dsa/realtek/rtl8365mb_qos.c
@@ -64,6 +64,14 @@ static_assert(RTL8365MB_QOS_QMAP_DEFAULT < RTL8365MB_QOS_NUM_QMAPS);
#define RTL8365MB_QOS_1Q_REMAP_REG(_pcp) \
(0x0865 + (_pcp) / RTL8365MB_QOS_SELS_PER_REG)
+/* PCP given to untagged frames, one 3-bit field per port */
+#define RTL8365MB_QOS_PORT_UNTAG_PCP_REG(_p) \
+ (0x0851 + (_p) / RTL8365MB_QOS_SELS_PER_REG)
+
+/* Ports 0..7 fit in 0x0851..0x0852 */
+static_assert(RTL8365MB_QOS_PORT_UNTAG_PCP_REG(RTL8365MB_QOS_MAX_PORTS - 1) <=
+ 0x0852);
+
/* Port-based (default) priority, one select per port */
#define RTL8365MB_QOS_PORT_PRI_REG(_p) \
(0x0877 + (_p) / RTL8365MB_QOS_SELS_PER_REG)
@@ -184,7 +192,8 @@ int rtl8365mb_qos_get_port_prio(struct realtek_priv *priv, int port)
rtl8365mb_qos_sel_mask(port));
}
-int rtl8365mb_qos_set_port_prio(struct realtek_priv *priv, int port, u8 iprio)
+int rtl8365mb_qos_set_port_prio(struct realtek_priv *priv, int port, u8 iprio,
+ u8 untag_pcp)
{
int ret;
@@ -192,6 +201,13 @@ int rtl8365mb_qos_set_port_prio(struct realtek_priv *priv, int port, u8 iprio)
if (ret)
return ret;
+ ret = rtl8365mb_qos_regmap_update_field(priv,
+ RTL8365MB_QOS_PORT_UNTAG_PCP_REG(port),
+ rtl8365mb_qos_sel_mask(port),
+ untag_pcp);
+ if (ret)
+ return ret;
+
return rtl8365mb_qos_regmap_update_field(priv,
RTL8365MB_QOS_PORT_PRI_REG(port),
rtl8365mb_qos_sel_mask(port),
diff --git a/drivers/net/dsa/realtek/rtl8365mb_qos.h b/drivers/net/dsa/realtek/rtl8365mb_qos.h
index a3568d47f6c6ee9566074af0ec493ff4bbdbf44b..71949ece4af8fae5c49cf105ddaa3db9bc622cf2 100644
--- a/drivers/net/dsa/realtek/rtl8365mb_qos.h
+++ b/drivers/net/dsa/realtek/rtl8365mb_qos.h
@@ -20,7 +20,8 @@ struct realtek_priv;
int rtl8365mb_qos_pridec_init(struct realtek_priv *priv);
int rtl8365mb_qos_qmap_init(struct realtek_priv *priv);
int rtl8365mb_qos_get_port_prio(struct realtek_priv *priv, int port);
-int rtl8365mb_qos_set_port_prio(struct realtek_priv *priv, int port, u8 iprio);
+int rtl8365mb_qos_set_port_prio(struct realtek_priv *priv, int port, u8 iprio,
+ u8 untag_pcp);
int rtl8365mb_qos_set_pcp_prio(struct realtek_priv *priv, u8 pcp, u8 iprio);
int rtl8365mb_qos_set_dscp_prio(struct realtek_priv *priv, u8 dscp, u8 iprio);
diff --git a/drivers/net/dsa/realtek/rtl83xx-qos.c b/drivers/net/dsa/realtek/rtl83xx-qos.c
index 0a02e6c4538a919e30e3c35594c7e7e7cdc3cf81..08091586901291e45ad1a2c64730cdcc30298b7a 100644
--- a/drivers/net/dsa/realtek/rtl83xx-qos.c
+++ b/drivers/net/dsa/realtek/rtl83xx-qos.c
@@ -5,7 +5,7 @@
* is an 802.1Q traffic type. dcbnl uses 802.1p priorities. An 802.1p priority
* equals the PCP value in the default PCP decoding (IEEE 802.1Q-2022 6.9.3).
* This layer converts at its edges: every priority it hands a backend is an
- * internal priority.
+ * internal priority, except the 802.1p PCP given to untagged frames.
*
* The backend maps internal priorities to its egress queues itself.
*/
@@ -60,6 +60,7 @@ EXPORT_SYMBOL_NS_GPL(rtl83xx_qos_init, "REALTEK_DSA");
int rtl83xx_qos_init_port(struct dsa_switch *ds, int port)
{
struct realtek_priv *priv = ds->priv;
+ int untag_pcp;
if (!priv->ops->qos_set_port_prio)
return -EOPNOTSUPP;
@@ -68,8 +69,13 @@ int rtl83xx_qos_init_port(struct dsa_switch *ds, int port)
if (dsa_is_unused_port(ds, port))
return 0;
- /* Best Effort, not internal priority 0, which is Background */
- return priv->ops->qos_set_port_prio(priv, port, IEEE8021Q_TT_BE);
+ untag_pcp = ieee8021q_tt_to_pcp(IEEE8021Q_TT_BE);
+ if (untag_pcp < 0)
+ return untag_pcp;
+
+ /* iprio is Best Effort, not 0, which is Background */
+ return priv->ops->qos_set_port_prio(priv, port, IEEE8021Q_TT_BE,
+ untag_pcp);
}
EXPORT_SYMBOL_NS_GPL(rtl83xx_qos_init_port, "REALTEK_DSA");
@@ -104,6 +110,6 @@ int rtl83xx_port_set_default_prio(struct dsa_switch *ds, int port, u8 prio)
if (tt < 0)
return tt;
- return priv->ops->qos_set_port_prio(priv, port, tt);
+ return priv->ops->qos_set_port_prio(priv, port, tt, prio);
}
EXPORT_SYMBOL_NS_GPL(rtl83xx_port_set_default_prio, "REALTEK_DSA");
--
2.47.3