From a63daf73a5870d73929546a525fca3b3fc08fece Mon Sep 17 00:00:00 2001 From: David Yang Date: Sat, 31 Jan 2026 10:18:47 +0800 Subject: [PATCH 1/5] net: dsa: tag_yt921x: clarify priority and code fields Packet priority is part of the tag, and the priority and code fields are used by tx and rx. Make revisions to reflect the facts. Signed-off-by: David Yang Link: https://patch.msgid.link/20260131021854.3405036-2-mmyangfl@gmail.com Reviewed-by: Vladimir Oltean Signed-off-by: Paolo Abeni --- net/dsa/tag_yt921x.c | 83 ++++++++++++++++++++++++++++---------------- 1 file changed, 53 insertions(+), 30 deletions(-) diff --git a/net/dsa/tag_yt921x.c b/net/dsa/tag_yt921x.c index 6bbfd42dc5df..098863d491ff 100644 --- a/net/dsa/tag_yt921x.c +++ b/net/dsa/tag_yt921x.c @@ -14,11 +14,14 @@ * are conflicts somewhere and/or you want to change it for some reason. * Tag: * 2: VLAN Tag - * 2: Rx Port + * 2: * 15b: Rx Port Valid * 14b-11b: Rx Port - * 10b-0b: Cmd? - * 2: Tx Port(s) + * 10b-8b: Tx/Rx Priority + * 7b: Tx/Rx Code Valid + * 6b-1b: Tx/Rx Code + * 0b: ? (unset) + * 2: * 15b: Tx Port(s) Valid * 10b-0b: Tx Port(s) Mask */ @@ -33,18 +36,30 @@ #define YT921X_TAG_PORT_EN BIT(15) #define YT921X_TAG_RX_PORT_M GENMASK(14, 11) -#define YT921X_TAG_RX_CMD_M GENMASK(10, 0) -#define YT921X_TAG_RX_CMD(x) FIELD_PREP(YT921X_TAG_RX_CMD_M, (x)) -#define YT921X_TAG_RX_CMD_FORWARDED 0x80 -#define YT921X_TAG_RX_CMD_UNK_UCAST 0xb2 -#define YT921X_TAG_RX_CMD_UNK_MCAST 0xb4 -#define YT921X_TAG_TX_PORTS GENMASK(10, 0) +#define YT921X_TAG_PRIO_M GENMASK(10, 8) +#define YT921X_TAG_PRIO(x) FIELD_PREP(YT921X_TAG_PRIO_M, (x)) +#define YT921X_TAG_CODE_EN BIT(7) +#define YT921X_TAG_CODE_M GENMASK(6, 1) +#define YT921X_TAG_CODE(x) FIELD_PREP(YT921X_TAG_CODE_M, (x)) +#define YT921X_TAG_TX_PORTS_M GENMASK(10, 0) +#define YT921X_TAG_TX_PORTS(x) FIELD_PREP(YT921X_TAG_TX_PORTS_M, (x)) + +/* Incomplete. Some are configurable via RMA_CTRL_CPU_CODE, the meaning of + * others remains unknown. + */ +enum yt921x_tag_code { + YT921X_TAG_CODE_FORWARD = 0, + YT921X_TAG_CODE_UNK_UCAST = 0x19, + YT921X_TAG_CODE_UNK_MCAST = 0x1a, + YT921X_TAG_CODE_PORT_COPY = 0x1b, + YT921X_TAG_CODE_FDB_COPY = 0x1c, +}; static struct sk_buff * yt921x_tag_xmit(struct sk_buff *skb, struct net_device *netdev) { __be16 *tag; - u16 tx; + u16 ctrl; skb_push(skb, YT921X_TAG_LEN); dsa_alloc_etype_header(skb, YT921X_TAG_LEN); @@ -55,9 +70,9 @@ yt921x_tag_xmit(struct sk_buff *skb, struct net_device *netdev) /* VLAN tag unrelated when TX */ tag[1] = 0; tag[2] = 0; - tx = FIELD_PREP(YT921X_TAG_TX_PORTS, dsa_xmit_port_mask(skb, netdev)) | - YT921X_TAG_PORT_EN; - tag[3] = htons(tx); + ctrl = YT921X_TAG_TX_PORTS(dsa_xmit_port_mask(skb, netdev)) | + YT921X_TAG_PORT_EN; + tag[3] = htons(ctrl); return skb; } @@ -67,7 +82,6 @@ yt921x_tag_rcv(struct sk_buff *skb, struct net_device *netdev) { unsigned int port; __be16 *tag; - u16 cmd; u16 rx; if (unlikely(!pskb_may_pull(skb, YT921X_TAG_LEN))) @@ -98,23 +112,32 @@ yt921x_tag_rcv(struct sk_buff *skb, struct net_device *netdev) return NULL; } - cmd = FIELD_GET(YT921X_TAG_RX_CMD_M, rx); - switch (cmd) { - case YT921X_TAG_RX_CMD_FORWARDED: - /* Already forwarded by hardware */ - dsa_default_offload_fwd_mark(skb); - break; - case YT921X_TAG_RX_CMD_UNK_UCAST: - case YT921X_TAG_RX_CMD_UNK_MCAST: - /* NOTE: hardware doesn't distinguish between TRAP (copy to CPU - * only) and COPY (forward and copy to CPU). In order to perform - * a soft switch, NEVER use COPY action in the switch driver. - */ - break; - default: + if (!(rx & YT921X_TAG_CODE_EN)) { dev_warn_ratelimited(&netdev->dev, - "Unexpected rx cmd 0x%02x\n", cmd); - break; + "Tag code not enabled in rx packet\n"); + } else { + u16 code = FIELD_GET(YT921X_TAG_CODE_M, rx); + + switch (code) { + case YT921X_TAG_CODE_FORWARD: + case YT921X_TAG_CODE_PORT_COPY: + case YT921X_TAG_CODE_FDB_COPY: + /* Already forwarded by hardware */ + dsa_default_offload_fwd_mark(skb); + break; + case YT921X_TAG_CODE_UNK_UCAST: + case YT921X_TAG_CODE_UNK_MCAST: + /* NOTE: hardware doesn't distinguish between TRAP (copy + * to CPU only) and COPY (forward and copy to CPU). In + * order to perform a soft switch, NEVER use COPY action + * in the switch driver. + */ + break; + default: + dev_warn_ratelimited(&netdev->dev, + "Unknown code 0x%02x\n", code); + break; + } } /* Remove YT921x tag and update checksum */ From 8cdb2cc9a11b589b564bd0fc72e524e1be69e967 Mon Sep 17 00:00:00 2001 From: David Yang Date: Sat, 31 Jan 2026 10:18:48 +0800 Subject: [PATCH 2/5] net: dsa: tag_yt921x: add priority support Required by DCB/QoS support of the switch driver, since the rx packets will have non-zero priorities. Signed-off-by: David Yang Link: https://patch.msgid.link/20260131021854.3405036-3-mmyangfl@gmail.com Reviewed-by: Vladimir Oltean Signed-off-by: Paolo Abeni --- net/dsa/tag_yt921x.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/net/dsa/tag_yt921x.c b/net/dsa/tag_yt921x.c index 098863d491ff..aefef8c770e3 100644 --- a/net/dsa/tag_yt921x.c +++ b/net/dsa/tag_yt921x.c @@ -69,7 +69,9 @@ yt921x_tag_xmit(struct sk_buff *skb, struct net_device *netdev) tag[0] = htons(ETH_P_YT921X); /* VLAN tag unrelated when TX */ tag[1] = 0; - tag[2] = 0; + ctrl = YT921X_TAG_CODE(YT921X_TAG_CODE_FORWARD) | YT921X_TAG_CODE_EN | + YT921X_TAG_PRIO(skb->priority); + tag[2] = htons(ctrl); ctrl = YT921X_TAG_TX_PORTS(dsa_xmit_port_mask(skb, netdev)) | YT921X_TAG_PORT_EN; tag[3] = htons(ctrl); @@ -112,6 +114,8 @@ yt921x_tag_rcv(struct sk_buff *skb, struct net_device *netdev) return NULL; } + skb->priority = FIELD_GET(YT921X_TAG_PRIO_M, rx); + if (!(rx & YT921X_TAG_CODE_EN)) { dev_warn_ratelimited(&netdev->dev, "Tag code not enabled in rx packet\n"); From 75b85703fd48bc63fcc91bf9206f71c4a2c592ec Mon Sep 17 00:00:00 2001 From: David Yang Date: Sat, 31 Jan 2026 10:18:49 +0800 Subject: [PATCH 3/5] net: dsa: yt921x: Refactor VLAN awareness setting Create a helper function to centralize the logic for enabling and disabling VLAN awareness on a port. Signed-off-by: David Yang Link: https://patch.msgid.link/20260131021854.3405036-4-mmyangfl@gmail.com Reviewed-by: Vladimir Oltean Signed-off-by: Paolo Abeni --- drivers/net/dsa/yt921x.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/drivers/net/dsa/yt921x.c b/drivers/net/dsa/yt921x.c index 4e4a5f7b3774..10f341436b44 100644 --- a/drivers/net/dsa/yt921x.c +++ b/drivers/net/dsa/yt921x.c @@ -1769,6 +1769,18 @@ yt921x_dsa_port_mdb_add(struct dsa_switch *ds, int port, return res; } +static int +yt921x_vlan_aware_set(struct yt921x_priv *priv, int port, bool vlan_aware) +{ + u32 ctrl; + + if (!vlan_aware) + ctrl = 0; + else + ctrl = YT921X_PORT_IGR_TPIDn_CTAG(0); + return yt921x_reg_write(priv, YT921X_PORTn_IGR_TPID(port), ctrl); +} + static int yt921x_port_set_pvid(struct yt921x_priv *priv, int port, u16 vid) { @@ -1818,14 +1830,7 @@ yt921x_vlan_filtering(struct yt921x_priv *priv, int port, bool vlan_filtering) if (res) return res; - /* Turn on / off VLAN awareness */ - mask = YT921X_PORT_IGR_TPIDn_CTAG_M; - if (!vlan_filtering) - ctrl = 0; - else - ctrl = YT921X_PORT_IGR_TPIDn_CTAG(0); - res = yt921x_reg_update_bits(priv, YT921X_PORTn_IGR_TPID(port), - mask, ctrl); + res = yt921x_vlan_aware_set(priv, port, vlan_filtering); if (res) return res; @@ -2022,8 +2027,7 @@ static int yt921x_userport_standalone(struct yt921x_priv *priv, int port) return res; /* Turn off VLAN awareness */ - mask = YT921X_PORT_IGR_TPIDn_CTAG_M; - res = yt921x_reg_clear_bits(priv, YT921X_PORTn_IGR_TPID(port), mask); + res = yt921x_vlan_aware_set(priv, port, false); if (res) return res; From 95e6bcab3c08e8a717c253631a14cd1a5e46eb8a Mon Sep 17 00:00:00 2001 From: David Yang Date: Sat, 31 Jan 2026 10:18:50 +0800 Subject: [PATCH 4/5] net: dsa: yt921x: Refactor yt921x_chip_setup() yt921x_chip_setup() is already pretty long, and is going to become longer. Split it into parts. Signed-off-by: David Yang Link: https://patch.msgid.link/20260131021854.3405036-5-mmyangfl@gmail.com Reviewed-by: Vladimir Oltean Signed-off-by: Paolo Abeni --- drivers/net/dsa/yt921x.c | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/drivers/net/dsa/yt921x.c b/drivers/net/dsa/yt921x.c index 10f341436b44..e418176b7c64 100644 --- a/drivers/net/dsa/yt921x.c +++ b/drivers/net/dsa/yt921x.c @@ -2902,7 +2902,7 @@ static int yt921x_chip_reset(struct yt921x_priv *priv) return 0; } -static int yt921x_chip_setup(struct yt921x_priv *priv) +static int yt921x_chip_setup_dsa(struct yt921x_priv *priv) { struct dsa_switch *ds = &priv->ds; unsigned long cpu_ports_mask; @@ -2920,16 +2920,6 @@ static int yt921x_chip_setup(struct yt921x_priv *priv) if (res) return res; - /* Enable and clear MIB */ - res = yt921x_reg_set_bits(priv, YT921X_FUNC, YT921X_FUNC_MIB); - if (res) - return res; - - ctrl = YT921X_MIB_CTRL_CLEAN | YT921X_MIB_CTRL_ALL_PORT; - res = yt921x_reg_write(priv, YT921X_MIB_CTRL, ctrl); - if (res) - return res; - /* Setup software switch */ ctrl = YT921X_CPU_COPY_TO_EXT_CPU; res = yt921x_reg_write(priv, YT921X_CPU_COPY, ctrl); @@ -2982,6 +2972,29 @@ static int yt921x_chip_setup(struct yt921x_priv *priv) if (res) return res; + return 0; +} + +static int yt921x_chip_setup(struct yt921x_priv *priv) +{ + u32 ctrl; + int res; + + ctrl = YT921X_FUNC_MIB; + res = yt921x_reg_set_bits(priv, YT921X_FUNC, ctrl); + if (res) + return res; + + res = yt921x_chip_setup_dsa(priv); + if (res) + return res; + + /* Clear MIB */ + ctrl = YT921X_MIB_CTRL_CLEAN | YT921X_MIB_CTRL_ALL_PORT; + res = yt921x_reg_write(priv, YT921X_MIB_CTRL, ctrl); + if (res) + return res; + /* Miscellaneous */ res = yt921x_reg_set_bits(priv, YT921X_SENSOR, YT921X_SENSOR_TEMP); if (res) From d5f778353fd443efd55069b93f3cd0447cfb9276 Mon Sep 17 00:00:00 2001 From: David Yang Date: Sat, 31 Jan 2026 10:18:51 +0800 Subject: [PATCH 5/5] net: dsa: yt921x: Add DCB/QoS support Set up global DSCP/PCP priority mappings and add related DCB methods. Signed-off-by: David Yang Link: https://patch.msgid.link/20260131021854.3405036-6-mmyangfl@gmail.com Reviewed-by: Vladimir Oltean Signed-off-by: Paolo Abeni --- drivers/net/dsa/Kconfig | 1 + drivers/net/dsa/yt921x.c | 253 ++++++++++++++++++++++++++++++++++++++- drivers/net/dsa/yt921x.h | 55 +++++++-- 3 files changed, 298 insertions(+), 11 deletions(-) diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig index 7eb301fd987d..24c37cbf70d7 100644 --- a/drivers/net/dsa/Kconfig +++ b/drivers/net/dsa/Kconfig @@ -158,6 +158,7 @@ config NET_DSA_VITESSE_VSC73XX_PLATFORM config NET_DSA_YT921X tristate "Motorcomm YT9215 ethernet switch chip support" select NET_DSA_TAG_YT921X + select NET_IEEE8021Q_HELPERS if DCB help This enables support for the Motorcomm YT9215 ethernet switch chip. diff --git a/drivers/net/dsa/yt921x.c b/drivers/net/dsa/yt921x.c index e418176b7c64..904613f4694a 100644 --- a/drivers/net/dsa/yt921x.c +++ b/drivers/net/dsa/yt921x.c @@ -8,6 +8,7 @@ * Copyright (c) 2025 David Yang */ +#include #include #include #include @@ -18,8 +19,11 @@ #include #include #include +#include #include +#include +#include #include "yt921x.h" @@ -1774,8 +1778,11 @@ yt921x_vlan_aware_set(struct yt921x_priv *priv, int port, bool vlan_aware) { u32 ctrl; + /* Abuse SVLAN for PCP parsing without polluting the FDB - it just works + * despite YT921X_VLAN_CTRL_SVLAN_EN never being set + */ if (!vlan_aware) - ctrl = 0; + ctrl = YT921X_PORT_IGR_TPIDn_STAG(0); else ctrl = YT921X_PORT_IGR_TPIDn_CTAG(0); return yt921x_reg_write(priv, YT921X_PORTn_IGR_TPID(port), ctrl); @@ -2396,6 +2403,122 @@ yt921x_dsa_port_stp_state_set(struct dsa_switch *ds, int port, u8 state) port, res); } +static int __maybe_unused +yt921x_dsa_port_get_default_prio(struct dsa_switch *ds, int port) +{ + struct yt921x_priv *priv = to_yt921x_priv(ds); + u32 val; + int res; + + mutex_lock(&priv->reg_lock); + res = yt921x_reg_read(priv, YT921X_PORTn_QOS(port), &val); + mutex_unlock(&priv->reg_lock); + + if (res) + return res; + + return FIELD_GET(YT921X_PORT_QOS_PRIO_M, val); +} + +static int __maybe_unused +yt921x_dsa_port_set_default_prio(struct dsa_switch *ds, int port, u8 prio) +{ + struct yt921x_priv *priv = to_yt921x_priv(ds); + u32 mask; + u32 ctrl; + int res; + + if (prio >= YT921X_PRIO_NUM) + return -EINVAL; + + mutex_lock(&priv->reg_lock); + mask = YT921X_PORT_QOS_PRIO_M | YT921X_PORT_QOS_PRIO_EN; + ctrl = YT921X_PORT_QOS_PRIO(prio) | YT921X_PORT_QOS_PRIO_EN; + res = yt921x_reg_update_bits(priv, YT921X_PORTn_QOS(port), mask, ctrl); + mutex_unlock(&priv->reg_lock); + + return res; +} + +static int __maybe_unused appprios_cmp(const void *a, const void *b) +{ + return ((const u8 *)b)[1] - ((const u8 *)a)[1]; +} + +static int __maybe_unused +yt921x_dsa_port_get_apptrust(struct dsa_switch *ds, int port, u8 *sel, + int *nselp) +{ + struct yt921x_priv *priv = to_yt921x_priv(ds); + u8 appprios[2][2] = {}; + int nsel; + u32 val; + int res; + + mutex_lock(&priv->reg_lock); + res = yt921x_reg_read(priv, YT921X_PORTn_PRIO_ORD(port), &val); + mutex_unlock(&priv->reg_lock); + + if (res) + return res; + + appprios[0][0] = IEEE_8021QAZ_APP_SEL_DSCP; + appprios[0][1] = (val >> (3 * YT921X_APP_SEL_DSCP)) & 7; + appprios[1][0] = DCB_APP_SEL_PCP; + appprios[1][1] = (val >> (3 * YT921X_APP_SEL_CVLAN_PCP)) & 7; + sort(appprios, ARRAY_SIZE(appprios), sizeof(appprios[0]), appprios_cmp, + NULL); + + nsel = 0; + for (int i = 0; i < ARRAY_SIZE(appprios) && appprios[i][1]; i++) { + sel[nsel] = appprios[i][0]; + nsel++; + } + *nselp = nsel; + + return 0; +} + +static int __maybe_unused +yt921x_dsa_port_set_apptrust(struct dsa_switch *ds, int port, const u8 *sel, + int nsel) +{ + struct yt921x_priv *priv = to_yt921x_priv(ds); + struct device *dev = to_device(priv); + u32 ctrl; + int res; + + if (nsel > YT921X_APP_SEL_NUM) + return -EINVAL; + + ctrl = 0; + for (int i = 0; i < nsel; i++) { + switch (sel[i]) { + case IEEE_8021QAZ_APP_SEL_DSCP: + ctrl |= YT921X_PORT_PRIO_ORD_APPm(YT921X_APP_SEL_DSCP, + 7 - i); + break; + case DCB_APP_SEL_PCP: + ctrl |= YT921X_PORT_PRIO_ORD_APPm(YT921X_APP_SEL_CVLAN_PCP, + 7 - i); + ctrl |= YT921X_PORT_PRIO_ORD_APPm(YT921X_APP_SEL_SVLAN_PCP, + 7 - i); + break; + default: + dev_err(dev, + "Invalid apptrust selector (at %d-th). Supported: dscp, pcp\n", + i + 1); + return -EOPNOTSUPP; + } + } + + mutex_lock(&priv->reg_lock); + res = yt921x_reg_write(priv, YT921X_PORTn_PRIO_ORD(port), ctrl); + mutex_unlock(&priv->reg_lock); + + return res; +} + static int yt921x_port_down(struct yt921x_priv *priv, int port) { u32 mask; @@ -2720,6 +2843,13 @@ static int yt921x_port_setup(struct yt921x_priv *priv, int port) if (res) return res; + /* Clear prio order (even if DCB is not enabled) to avoid unsolicited + * priorities + */ + res = yt921x_reg_write(priv, YT921X_PORTn_PRIO_ORD(port), 0); + if (res) + return res; + if (dsa_is_cpu_port(ds, port)) { /* Egress of CPU port is supposed to be completely controlled * via tagging, so set to oneway isolated (drop all packets @@ -2763,6 +2893,66 @@ static int yt921x_dsa_port_setup(struct dsa_switch *ds, int port) return res; } +/* Not "port" - DSCP mapping is global */ +static int __maybe_unused +yt921x_dsa_port_get_dscp_prio(struct dsa_switch *ds, int port, u8 dscp) +{ + struct yt921x_priv *priv = to_yt921x_priv(ds); + u32 val; + int res; + + mutex_lock(&priv->reg_lock); + res = yt921x_reg_read(priv, YT921X_IPM_DSCPn(dscp), &val); + mutex_unlock(&priv->reg_lock); + + if (res) + return res; + + return FIELD_GET(YT921X_IPM_PRIO_M, val); +} + +static int __maybe_unused +yt921x_dsa_port_del_dscp_prio(struct dsa_switch *ds, int port, u8 dscp, u8 prio) +{ + struct yt921x_priv *priv = to_yt921x_priv(ds); + u32 val; + int res; + + mutex_lock(&priv->reg_lock); + /* During a "dcb app replace" command, the new app table entry will be + * added first, then the old one will be deleted. But the hardware only + * supports one QoS class per DSCP value (duh), so if we blindly delete + * the app table entry for this DSCP value, we end up deleting the + * entry with the new priority. Avoid that by checking whether user + * space wants to delete the priority which is currently configured, or + * something else which is no longer current. + */ + res = yt921x_reg_read(priv, YT921X_IPM_DSCPn(dscp), &val); + if (!res && FIELD_GET(YT921X_IPM_PRIO_M, val) == prio) + res = yt921x_reg_write(priv, YT921X_IPM_DSCPn(dscp), + YT921X_IPM_PRIO(IEEE8021Q_TT_BK)); + mutex_unlock(&priv->reg_lock); + + return res; +} + +static int __maybe_unused +yt921x_dsa_port_add_dscp_prio(struct dsa_switch *ds, int port, u8 dscp, u8 prio) +{ + struct yt921x_priv *priv = to_yt921x_priv(ds); + int res; + + if (prio >= YT921X_PRIO_NUM) + return -EINVAL; + + mutex_lock(&priv->reg_lock); + res = yt921x_reg_write(priv, YT921X_IPM_DSCPn(dscp), + YT921X_IPM_PRIO(prio)); + mutex_unlock(&priv->reg_lock); + + return res; +} + static int yt921x_edata_wait(struct yt921x_priv *priv, u32 *valp) { u32 val = YT921X_EDATA_DATA_IDLE; @@ -2975,6 +3165,47 @@ static int yt921x_chip_setup_dsa(struct yt921x_priv *priv) return 0; } +static int __maybe_unused yt921x_chip_setup_qos(struct yt921x_priv *priv) +{ + u32 ctrl; + int res; + + /* DSCP to internal priorities */ + for (u8 dscp = 0; dscp < DSCP_MAX; dscp++) { + int prio = ietf_dscp_to_ieee8021q_tt(dscp); + + if (prio < 0) + return prio; + + res = yt921x_reg_write(priv, YT921X_IPM_DSCPn(dscp), + YT921X_IPM_PRIO(prio)); + if (res) + return res; + } + + /* 802.1Q QoS to internal priorities */ + for (u8 pcp = 0; pcp < 8; pcp++) + for (u8 dei = 0; dei < 2; dei++) { + ctrl = YT921X_IPM_PRIO(pcp); + if (dei) + /* "Red" almost means drop, so it's not that + * useful. Note that tc police does not support + * Three-Color very well + */ + ctrl |= YT921X_IPM_COLOR_YELLOW; + + for (u8 svlan = 0; svlan < 2; svlan++) { + u32 reg = YT921X_IPM_PCPn(svlan, dei, pcp); + + res = yt921x_reg_write(priv, reg, ctrl); + if (res) + return res; + } + } + + return 0; +} + static int yt921x_chip_setup(struct yt921x_priv *priv) { u32 ctrl; @@ -2989,6 +3220,12 @@ static int yt921x_chip_setup(struct yt921x_priv *priv) if (res) return res; +#if IS_ENABLED(CONFIG_DCB) + res = yt921x_chip_setup_qos(priv); + if (res) + return res; +#endif + /* Clear MIB */ ctrl = YT921X_MIB_CTRL_CLEAN | YT921X_MIB_CTRL_ALL_PORT; res = yt921x_reg_write(priv, YT921X_MIB_CTRL, ctrl); @@ -3104,10 +3341,23 @@ static const struct dsa_switch_ops yt921x_dsa_switch_ops = { .port_mst_state_set = yt921x_dsa_port_mst_state_set, .vlan_msti_set = yt921x_dsa_vlan_msti_set, .port_stp_state_set = yt921x_dsa_port_stp_state_set, +#if IS_ENABLED(CONFIG_DCB) + /* dcb */ + .port_get_default_prio = yt921x_dsa_port_get_default_prio, + .port_set_default_prio = yt921x_dsa_port_set_default_prio, + .port_get_apptrust = yt921x_dsa_port_get_apptrust, + .port_set_apptrust = yt921x_dsa_port_set_apptrust, +#endif /* port */ .get_tag_protocol = yt921x_dsa_get_tag_protocol, .phylink_get_caps = yt921x_dsa_phylink_get_caps, .port_setup = yt921x_dsa_port_setup, +#if IS_ENABLED(CONFIG_DCB) + /* dscp */ + .port_get_dscp_prio = yt921x_dsa_port_get_dscp_prio, + .port_del_dscp_prio = yt921x_dsa_port_del_dscp_prio, + .port_add_dscp_prio = yt921x_dsa_port_add_dscp_prio, +#endif /* chip */ .setup = yt921x_dsa_setup, }; @@ -3174,6 +3424,7 @@ static int yt921x_mdio_probe(struct mdio_device *mdiodev) ds = &priv->ds; ds->dev = dev; ds->assisted_learning_on_cpu_port = true; + ds->dscp_prio_mapping_is_global = true; ds->priv = priv; ds->ops = &yt921x_dsa_switch_ops; ds->ageing_time_min = 1 * 5000; diff --git a/drivers/net/dsa/yt921x.h b/drivers/net/dsa/yt921x.h index bacd4ccaa8e5..3f129b8d403f 100644 --- a/drivers/net/dsa/yt921x.h +++ b/drivers/net/dsa/yt921x.h @@ -269,6 +269,38 @@ #define YT921X_TPID_EGRn(x) (0x100300 + 4 * (x)) /* [0, 3] */ #define YT921X_TPID_EGR_TPID_M GENMASK(15, 0) +#define YT921X_IPM_DSCPn(n) (0x180000 + 4 * (n)) /* Internal Priority Map */ +#define YT921X_IPM_PCPn(map, dei, pcp) (0x180100 + 4 * (16 * (map) + 8 * (dei) + (pcp))) +#define YT921X_IPM_PRIO_M GENMASK(4, 2) +#define YT921X_IPM_PRIO(x) FIELD_PREP(YT921X_IPM_PRIO_M, (x)) +#define YT921X_IPM_COLOR_M GENMASK(1, 0) +#define YT921X_IPM_COLOR(x) FIELD_PREP(YT921X_IPM_COLOR_M, (x)) +#define YT921X_IPM_COLOR_GREEN YT921X_IPM_COLOR(0) +#define YT921X_IPM_COLOR_YELLOW YT921X_IPM_COLOR(1) +#define YT921X_IPM_COLOR_RED YT921X_IPM_COLOR(2) +#define YT921X_PORTn_QOS(port) (0x180180 + 4 * (port)) +#define YT921X_PORT_QOS_CVLAN_PRIO_MAP_ID BIT(5) +#define YT921X_PORT_QOS_SVLAN_PRIO_MAP_ID BIT(4) +#define YT921X_PORT_QOS_PRIO_M GENMASK(3, 1) +#define YT921X_PORT_QOS_PRIO(x) FIELD_PREP(YT921X_PORT_QOS_PRIO_M, (x)) +#define YT921X_PORT_QOS_PRIO_EN BIT(0) +#define YT921X_PORTn_PRIO_ORD(port) (0x180200 + 4 * (port)) +#define YT921X_PORT_PRIO_ORD_APPm_M(m) GENMASK(3 * (m) + 2, 3 * (m)) +#define YT921X_PORT_PRIO_ORD_APPm(m, x) ((x) << (3 * (m))) /* 0: disabled, except PORT_QOS_PRIO */ + +enum yt921x_app_selector { + YT921X_APP_SEL_MAC_SA, + YT921X_APP_SEL_MAC_DA, + YT921X_APP_SEL_VID, + YT921X_APP_SEL_ACL, + YT921X_APP_SEL_DSCP, + YT921X_APP_SEL_CVLAN_PCP, + YT921X_APP_SEL_SVLAN_PCP, + /* The physical port, i.e. YT921X_PORT_QOS_PRIO */ + YT921X_APP_SEL_PORT, + YT921X_APP_SEL_NUM +}; + #define YT921X_VLAN_IGR_FILTER 0x180280 #define YT921X_VLAN_IGR_FILTER_PORTn_BYPASS_IGMP(port) BIT((port) + 11) #define YT921X_VLAN_IGR_FILTER_PORTn(port) BIT(port) @@ -337,7 +369,7 @@ #define YT921X_FDB_OUT0 0x1804b0 #define YT921X_FDB_IO0_ADDR_HI4_M GENMASK(31, 0) #define YT921X_FDB_OUT1 0x1804b4 -#define YT921X_FDB_IO1_EGR_INT_PRI_EN BIT(31) +#define YT921X_FDB_IO1_EGR_PRIO_EN BIT(31) #define YT921X_FDB_IO1_STATUS_M GENMASK(30, 28) #define YT921X_FDB_IO1_STATUS(x) FIELD_PREP(YT921X_FDB_IO1_STATUS_M, (x)) #define YT921X_FDB_IO1_STATUS_INVALID YT921X_FDB_IO1_STATUS(0) @@ -356,9 +388,9 @@ #define YT921X_FDB_IO2_EGR_PORTS(x) FIELD_PREP(YT921X_FDB_IO2_EGR_PORTS_M, (x)) #define YT921X_FDB_IO2_EGR_DROP BIT(17) #define YT921X_FDB_IO2_COPY_TO_CPU BIT(16) -#define YT921X_FDB_IO2_IGR_INT_PRI_EN BIT(15) -#define YT921X_FDB_IO2_INT_PRI_M GENMASK(14, 12) -#define YT921X_FDB_IO2_INT_PRI(x) FIELD_PREP(YT921X_FDB_IO2_INT_PRI_M, (x)) +#define YT921X_FDB_IO2_IGR_PRIO_EN BIT(15) +#define YT921X_FDB_IO2_PRIO_M GENMASK(14, 12) +#define YT921X_FDB_IO2_PRIO(x) FIELD_PREP(YT921X_FDB_IO2_PRIO_M, (x)) #define YT921X_FDB_IO2_NEW_VID_M GENMASK(11, 0) #define YT921X_FDB_IO2_NEW_VID(x) FIELD_PREP(YT921X_FDB_IO2_NEW_VID_M, (x)) #define YT921X_FILTER_UNK_UCAST 0x180508 @@ -406,8 +438,9 @@ #define YT921X_VLAN_CTRL_FID_M GENMASK_ULL(34, 23) #define YT921X_VLAN_CTRL_FID(x) FIELD_PREP(YT921X_VLAN_CTRL_FID_M, (x)) #define YT921X_VLAN_CTRL_LEARN_DIS BIT_ULL(22) -#define YT921X_VLAN_CTRL_INT_PRI_EN BIT_ULL(21) -#define YT921X_VLAN_CTRL_INT_PRI_M GENMASK_ULL(20, 18) +#define YT921X_VLAN_CTRL_PRIO_EN BIT_ULL(21) +#define YT921X_VLAN_CTRL_PRIO_M GENMASK_ULL(20, 18) +#define YT921X_VLAN_CTRL_PRIO(x) FIELD_PREP(YT921X_VLAN_CTRL_PRIO_M, (x)) #define YT921X_VLAN_CTRL_PORTS_M GENMASK_ULL(17, 7) #define YT921X_VLAN_CTRL_PORTS(x) FIELD_PREP(YT921X_VLAN_CTRL_PORTS_M, (x)) #define YT921X_VLAN_CTRL_PORTn(port) BIT_ULL((port) + 7) @@ -433,14 +466,14 @@ #define YT921X_LAG_HASH_SRC_PORT BIT(0) #define YT921X_PORTn_VLAN_CTRL(port) (0x230010 + 4 * (port)) -#define YT921X_PORT_VLAN_CTRL_SVLAN_PRI_EN BIT(31) -#define YT921X_PORT_VLAN_CTRL_CVLAN_PRI_EN BIT(30) +#define YT921X_PORT_VLAN_CTRL_SVLAN_PRIO_EN BIT(31) +#define YT921X_PORT_VLAN_CTRL_CVLAN_PRIO_EN BIT(30) #define YT921X_PORT_VLAN_CTRL_SVID_M GENMASK(29, 18) #define YT921X_PORT_VLAN_CTRL_SVID(x) FIELD_PREP(YT921X_PORT_VLAN_CTRL_SVID_M, (x)) #define YT921X_PORT_VLAN_CTRL_CVID_M GENMASK(17, 6) #define YT921X_PORT_VLAN_CTRL_CVID(x) FIELD_PREP(YT921X_PORT_VLAN_CTRL_CVID_M, (x)) -#define YT921X_PORT_VLAN_CTRL_SVLAN_PRI_M GENMASK(5, 3) -#define YT921X_PORT_VLAN_CTRL_CVLAN_PRI_M GENMASK(2, 0) +#define YT921X_PORT_VLAN_CTRL_SVLAN_PRIO_M GENMASK(5, 3) +#define YT921X_PORT_VLAN_CTRL_CVLAN_PRIO_M GENMASK(2, 0) #define YT921X_PORTn_VLAN_CTRL1(port) (0x230080 + 4 * (port)) #define YT921X_PORT_VLAN_CTRL1_VLAN_RANGE_EN BIT(8) #define YT921X_PORT_VLAN_CTRL1_VLAN_RANGE_PROFILE_ID_M GENMASK(7, 4) @@ -478,6 +511,8 @@ enum yt921x_fdb_entry_status { #define YT921X_LAG_NUM 2 #define YT921X_LAG_PORT_NUM 4 +#define YT921X_PRIO_NUM 8 + #define YT9215_MAJOR 0x9002 #define YT9218_MAJOR 0x9001