]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
net: dsa: tag_brcm: add support for legacy FCS tags
authorÁlvaro Fernández Rojas <noltari@gmail.com>
Sat, 14 Jun 2025 07:59:48 +0000 (09:59 +0200)
committerJakub Kicinski <kuba@kernel.org>
Wed, 18 Jun 2025 00:52:01 +0000 (17:52 -0700)
Add support for legacy Broadcom FCS tags, which are similar to
DSA_TAG_PROTO_BRCM_LEGACY.
BCM5325 and BCM5365 switches require including the original FCS value and
length, as opposed to BCM63xx switches.
Adding the original FCS value and length to DSA_TAG_PROTO_BRCM_LEGACY would
impact performance of BCM63xx switches, so it's better to create a new tag.

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
Reviewed-by: Florian Fainelli <florian.fainelli@broadcom.com>
Link: https://patch.msgid.link/20250614080000.1884236-3-noltari@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
include/net/dsa.h
net/dsa/Kconfig
net/dsa/tag_brcm.c

index 55e2d97f247eb0305baaf5719782269433918f18..d73ea08800660ebf562481551a3790a65f84de90 100644 (file)
@@ -54,11 +54,13 @@ struct tc_action;
 #define DSA_TAG_PROTO_RZN1_A5PSW_VALUE         26
 #define DSA_TAG_PROTO_LAN937X_VALUE            27
 #define DSA_TAG_PROTO_VSC73XX_8021Q_VALUE      28
+#define DSA_TAG_PROTO_BRCM_LEGACY_FCS_VALUE    29
 
 enum dsa_tag_protocol {
        DSA_TAG_PROTO_NONE              = DSA_TAG_PROTO_NONE_VALUE,
        DSA_TAG_PROTO_BRCM              = DSA_TAG_PROTO_BRCM_VALUE,
        DSA_TAG_PROTO_BRCM_LEGACY       = DSA_TAG_PROTO_BRCM_LEGACY_VALUE,
+       DSA_TAG_PROTO_BRCM_LEGACY_FCS   = DSA_TAG_PROTO_BRCM_LEGACY_FCS_VALUE,
        DSA_TAG_PROTO_BRCM_PREPEND      = DSA_TAG_PROTO_BRCM_PREPEND_VALUE,
        DSA_TAG_PROTO_DSA               = DSA_TAG_PROTO_DSA_VALUE,
        DSA_TAG_PROTO_EDSA              = DSA_TAG_PROTO_EDSA_VALUE,
index 2dfe9063613feb3251f3ec9f96adc87d2e0cd47a..869cbe57162f9d78569ff7f042df49cf27c5629b 100644 (file)
@@ -42,12 +42,24 @@ config NET_DSA_TAG_BRCM
          Broadcom switches which place the tag after the MAC source address.
 
 config NET_DSA_TAG_BRCM_LEGACY
-       tristate "Tag driver for Broadcom legacy switches using in-frame headers"
+       tristate "Tag driver for BCM63xx legacy switches using in-frame headers"
        select NET_DSA_TAG_BRCM_COMMON
        help
          Say Y if you want to enable support for tagging frames for the
-         Broadcom legacy switches which place the tag after the MAC source
+         BCM63xx legacy switches which place the tag after the MAC source
          address.
+         This tag is used in BCM63xx legacy switches which work without the
+         original FCS and length before the tag insertion.
+
+config NET_DSA_TAG_BRCM_LEGACY_FCS
+       tristate "Tag driver for BCM53xx legacy switches using in-frame headers"
+       select NET_DSA_TAG_BRCM_COMMON
+       help
+         Say Y if you want to enable support for tagging frames for the
+         BCM53xx legacy switches which place the tag after the MAC source
+         address.
+         This tag is used in BCM53xx legacy switches which expect original
+         FCS and length before the tag insertion to be present.
 
 config NET_DSA_TAG_BRCM_PREPEND
        tristate "Tag driver for Broadcom switches using prepended headers"
index 9f4b0bcd95cde9c6704627a31809c8bf88f9e87c..26bb657ceac36f32c23ba3791b8efc72280e1b5c 100644 (file)
@@ -15,6 +15,7 @@
 
 #define BRCM_NAME              "brcm"
 #define BRCM_LEGACY_NAME       "brcm-legacy"
+#define BRCM_LEGACY_FCS_NAME   "brcm-legacy-fcs"
 #define BRCM_PREPEND_NAME      "brcm-prepend"
 
 /* Legacy Broadcom tag (6 bytes) */
 #define BRCM_LEG_MULTICAST     (1 << 5)
 #define BRCM_LEG_EGRESS                (2 << 5)
 #define BRCM_LEG_INGRESS       (3 << 5)
+#define BRCM_LEG_LEN_HI(x)     (((x) >> 8) & 0x7)
+
+/* 4th byte in the tag */
+#define BRCM_LEG_LEN_LO(x)     ((x) & 0xff)
 
 /* 6th byte in the tag */
 #define BRCM_LEG_PORT_ID       (0xf)
@@ -212,7 +217,8 @@ DSA_TAG_DRIVER(brcm_netdev_ops);
 MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_BRCM, BRCM_NAME);
 #endif
 
-#if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_LEGACY)
+#if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_LEGACY) || \
+       IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_LEGACY_FCS)
 static struct sk_buff *brcm_leg_tag_rcv(struct sk_buff *skb,
                                        struct net_device *dev)
 {
@@ -244,7 +250,9 @@ static struct sk_buff *brcm_leg_tag_rcv(struct sk_buff *skb,
 
        return skb;
 }
+#endif /* CONFIG_NET_DSA_TAG_BRCM_LEGACY || CONFIG_NET_DSA_TAG_BRCM_LEGACY_FCS */
 
+#if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_LEGACY)
 static struct sk_buff *brcm_leg_tag_xmit(struct sk_buff *skb,
                                         struct net_device *dev)
 {
@@ -294,6 +302,66 @@ DSA_TAG_DRIVER(brcm_legacy_netdev_ops);
 MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_BRCM_LEGACY, BRCM_LEGACY_NAME);
 #endif /* CONFIG_NET_DSA_TAG_BRCM_LEGACY */
 
+#if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_LEGACY_FCS)
+static struct sk_buff *brcm_leg_fcs_tag_xmit(struct sk_buff *skb,
+                                            struct net_device *dev)
+{
+       struct dsa_port *dp = dsa_user_to_port(dev);
+       unsigned int fcs_len;
+       __le32 fcs_val;
+       u8 *brcm_tag;
+
+       /* The Ethernet switch we are interfaced with needs packets to be at
+        * least 64 bytes (including FCS) otherwise they will be discarded when
+        * they enter the switch port logic. When Broadcom tags are enabled, we
+        * need to make sure that packets are at least 70 bytes (including FCS
+        * and tag) because the length verification is done after the Broadcom
+        * tag is stripped off the ingress packet.
+        *
+        * Let dsa_user_xmit() free the SKB.
+        */
+       if (__skb_put_padto(skb, ETH_ZLEN + BRCM_LEG_TAG_LEN, false))
+               return NULL;
+
+       fcs_len = skb->len;
+       fcs_val = cpu_to_le32(crc32_le(~0, skb->data, fcs_len) ^ ~0);
+
+       skb_push(skb, BRCM_LEG_TAG_LEN);
+
+       dsa_alloc_etype_header(skb, BRCM_LEG_TAG_LEN);
+
+       brcm_tag = skb->data + 2 * ETH_ALEN;
+
+       /* Broadcom tag type */
+       brcm_tag[0] = BRCM_LEG_TYPE_HI;
+       brcm_tag[1] = BRCM_LEG_TYPE_LO;
+
+       /* Broadcom tag value */
+       brcm_tag[2] = BRCM_LEG_EGRESS | BRCM_LEG_LEN_HI(fcs_len);
+       brcm_tag[3] = BRCM_LEG_LEN_LO(fcs_len);
+       brcm_tag[4] = 0;
+       brcm_tag[5] = dp->index & BRCM_LEG_PORT_ID;
+
+       /* Original FCS value */
+       if (__skb_pad(skb, ETH_FCS_LEN, false))
+               return NULL;
+       skb_put_data(skb, &fcs_val, ETH_FCS_LEN);
+
+       return skb;
+}
+
+static const struct dsa_device_ops brcm_legacy_fcs_netdev_ops = {
+       .name = BRCM_LEGACY_FCS_NAME,
+       .proto = DSA_TAG_PROTO_BRCM_LEGACY_FCS,
+       .xmit = brcm_leg_fcs_tag_xmit,
+       .rcv = brcm_leg_tag_rcv,
+       .needed_headroom = BRCM_LEG_TAG_LEN,
+};
+
+DSA_TAG_DRIVER(brcm_legacy_fcs_netdev_ops);
+MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_BRCM_LEGACY_FCS, BRCM_LEGACY_FCS_NAME);
+#endif /* CONFIG_NET_DSA_TAG_BRCM_LEGACY_FCS */
+
 #if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_PREPEND)
 static struct sk_buff *brcm_tag_xmit_prepend(struct sk_buff *skb,
                                             struct net_device *dev)
@@ -328,6 +396,9 @@ static struct dsa_tag_driver *dsa_tag_driver_array[] =      {
 #if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_LEGACY)
        &DSA_TAG_DRIVER_NAME(brcm_legacy_netdev_ops),
 #endif
+#if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_LEGACY_FCS)
+       &DSA_TAG_DRIVER_NAME(brcm_legacy_fcs_netdev_ops),
+#endif
 #if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_PREPEND)
        &DSA_TAG_DRIVER_NAME(brcm_prepend_netdev_ops),
 #endif