Feature implemented and tested on BCM53128.

This will enable the processing of the Broadcom Tag/Header,
which will insert 4 bytes between the MAC header and EtherType field.

Note that b53_enable_brcm_hdr(dev) is called before
b53_enable_management(dev), since it seems that the CPU port
may be disabled after b53_enable_brcm_hdr(dev).

Two important notes about this logic:
- Adding 4 bytes in place of the EtherType field may confuses some
  ethernet hardware chips, causing them to stop padding packets
  up to 64 bytes (min frame size).
  In that case, CONFIG_B53_HDR_TX_SW_PADDING may be enabled
- You should increase the MTU size of the same ethernet chip to
  MTU size + 4 bytes in '/etc/config/network'.
  This is such that packets from the switch chip do not get dropped
  by the ethernet chip.
  Try more than 4 bytes since the ethernet driver may do some of it's own
  MTU & frame size computation that needs some sizes to be 8 byte aligned
  when set into it's registers.

Signed-off-by: Alexandru Ardelean <[email protected]>
---
 .../generic/files/drivers/net/phy/b53/Kconfig      |  21 ++++
 .../generic/files/drivers/net/phy/b53/Makefile     |   1 +
 .../generic/files/drivers/net/phy/b53/b53_common.c |  22 +++-
 .../generic/files/drivers/net/phy/b53/b53_hdr.c    | 129 +++++++++++++++++++++
 .../generic/files/drivers/net/phy/b53/b53_mdio.c   |   7 ++
 .../generic/files/drivers/net/phy/b53/b53_priv.h   |  18 +++
 6 files changed, 193 insertions(+), 5 deletions(-)
 create mode 100644 target/linux/generic/files/drivers/net/phy/b53/b53_hdr.c

diff --git a/target/linux/generic/files/drivers/net/phy/b53/Kconfig 
b/target/linux/generic/files/drivers/net/phy/b53/Kconfig
index 545814a..ebf1b91 100644
--- a/target/linux/generic/files/drivers/net/phy/b53/Kconfig
+++ b/target/linux/generic/files/drivers/net/phy/b53/Kconfig
@@ -48,3 +48,24 @@ config B53_HW_DEBUG_FEATURES
          So far they've been tested on BCM53128, and should work on BCM53125
          since that's a 4 port variant.
 
+config B53_HDR
+       bool "B53 Broadcom Header support"
+       depends on B53
+       select ETHERNET_PACKET_MANGLE
+       default n
+       help
+         Select to enable the Broadcom tag/header, which will cause the 
+         switch chip to insert 4 bytes between the MAC fields and
+         ether-type field.
+
+config B53_HDR_TX_SW_PADDING
+       bool "Pad runt TX packets in software"
+       depends on B53_HDR
+       default n
+       help
+         Enable this if your MAC driver has issues with adding padding
+         after the Broadcom Header is added in the packet.
+         If the packets will be < 64 bytes, they'll be padded up to 64
+         so that the switch chip does not discard them.
+         This is only used if the Broadcom Header is enabled via swconfig.
+
diff --git a/target/linux/generic/files/drivers/net/phy/b53/Makefile 
b/target/linux/generic/files/drivers/net/phy/b53/Makefile
index 7cc39c7..6c809f9 100644
--- a/target/linux/generic/files/drivers/net/phy/b53/Makefile
+++ b/target/linux/generic/files/drivers/net/phy/b53/Makefile
@@ -1,4 +1,5 @@
 obj-$(CONFIG_B53)              += b53_common.o
+obj-$(CONFIG_B53_HDR)          += b53_hdr.o
 
 obj-$(CONFIG_B53_PHY_FIXUP)    += b53_phy_fixup.o
 
diff --git a/target/linux/generic/files/drivers/net/phy/b53/b53_common.c 
b/target/linux/generic/files/drivers/net/phy/b53/b53_common.c
index a7093ee..9459b22 100644
--- a/target/linux/generic/files/drivers/net/phy/b53/b53_common.c
+++ b/target/linux/generic/files/drivers/net/phy/b53/b53_common.c
@@ -320,7 +320,6 @@ static void b53_enable_vlan(struct b53_device *dev, int 
enable)
 static void b53_enable_management(struct b53_device *dev)
 {
        u8 mgmt, gc;
-       u8 brcm_hdr_ctrl;
 
        /* Management has been disabled by by clearing the SM_SW_FWD_MODE bit
         * in b53_enable_vlan() or b53_reset_switch() */
@@ -328,14 +327,12 @@ static void b53_enable_management(struct b53_device *dev)
                return;
        b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt);
        b53_read8(dev, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, &gc);
-       b53_read8(dev, B53_MGMT_PAGE, B53_BRCM_HDR_CTRL, &brcm_hdr_ctrl);
 
        mgmt |= SM_SW_FWD_MODE;
        gc |= GC_FRM_MGMT_PORT_MII;
-       /* Chip inserts tag in frame when managed mode is on; not needed yet */
-       brcm_hdr_ctrl &= ~B53_BRCM_HDR_EN;
+       /* Whether the Broadcom tag is (un)set is entirely
+        * up to the b53_enable_brcm_hdr() function now */
 
-       b53_write8(dev, B53_CTRL_PAGE, B53_BRCM_HDR_CTRL, brcm_hdr_ctrl);
        b53_write8(dev, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, gc);
        b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, mgmt);
 }
@@ -692,6 +689,7 @@ static int b53_apply(struct b53_device *dev)
 
        if (!is5325(dev) && !is5365(dev))
                b53_set_jumbo(dev, dev->enable_jumbo, 1);
+       b53_enable_brcm_hdr(dev);
        b53_enable_management(dev);
 
        return 0;
@@ -776,6 +774,8 @@ static int b53_switch_reset(struct b53_device *dev)
        }
 
        b53_enable_mib(dev);
+       /* This will clear up a few things when resetting */
+       b53_enable_brcm_hdr(dev);
 
        return b53_flush_arl(dev);
 }
@@ -1375,6 +1375,9 @@ static int b53_global_reset_switch(struct switch_dev *dev)
        priv->enable_jumbo = 0;
        priv->allow_vid_4095 = 0;
        priv->enable_management = 0;
+#ifdef CONFIG_B53_HDR
+       priv->enable_brcm_hdr = 0;
+#endif
 
        memset(priv->vlans, 0, sizeof(priv->vlans) * dev->vlans);
        memset(priv->ports, 0, sizeof(priv->ports) * dev->ports);
@@ -1550,6 +1553,15 @@ static struct switch_attr b53_global_ops[] = {
                .get = b53_global_get_management,
                .max = 1,
        },
+#ifdef CONFIG_B53_HDR
+       {
+               .type = SWITCH_TYPE_INT,
+               .name = "enable_brcm_hdr",
+               .description = "Enable Broadcom Header",
+               .set = b53_global_set_brcm_hdr,
+               .get = b53_global_get_brcm_hdr,
+       },
+#endif
 #ifdef CONFIG_B53_HW_DEBUG_FEATURES
        {
                .type = SWITCH_TYPE_STRING,
diff --git a/target/linux/generic/files/drivers/net/phy/b53/b53_hdr.c 
b/target/linux/generic/files/drivers/net/phy/b53/b53_hdr.c
new file mode 100644
index 0000000..2a562a9
--- /dev/null
+++ b/target/linux/generic/files/drivers/net/phy/b53/b53_hdr.c
@@ -0,0 +1,129 @@
+/*
+ * B53 switch driver logic for the Broadcom Header/Tag
+ *
+ * Copyright (C) 2015 Alexandru Ardelean <[email protected]>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/platform_data/b53.h>
+#include <linux/rtnetlink.h>
+
+#include "b53_regs.h"
+#include "b53_priv.h"
+
+/* This tag length is 4 bytes, older ones were 6 bytes, we do not
+ * handle them
+ */
+#define BRCM_HDR_LEN    4
+#define MIN_FRAME_LEN   64
+
+static struct sk_buff *b53_mangle_tx(struct net_device *dev, struct sk_buff 
*skb)
+{
+       if (unlikely(skb_headroom(skb) < BRCM_HDR_LEN)) {
+               if (pskb_expand_head(skb, BRCM_HDR_LEN, 0, GFP_ATOMIC) < 0)
+                       goto out_err;
+       }
+
+       skb_push(skb, BRCM_HDR_LEN);
+
+       memmove(skb->data, skb->data + BRCM_HDR_LEN, 2 * ETH_ALEN);
+
+       /* Build the tag after the MAC Source Address */
+       memset(skb->data + 2 * ETH_ALEN, 0, BRCM_HDR_LEN);
+#ifdef CONFIG_B53_HDR_TX_SW_PADDING
+       /* FIXME: we're doing some padding here for runt ( < 64 bytes) packets;
+        *        some drivers/hw refuse to add hw padding for us after we add
+        *        the Broadcom tag in there, possibly because it's a 
invalid/null
+        *        ethertype it sees;
+        */
+       if (unlikely(skb->len < MIN_FRAME_LEN)) {
+               u8 *data;
+               int diff = (MIN_FRAME_LEN - skb->len);
+               if (skb_tailroom(skb) < diff)
+                       pskb_expand_head(skb, 0, diff, GFP_ATOMIC);
+               data = skb_put(skb, diff);
+               memset(data, 0, diff);
+       }
+#endif
+
+       return skb;
+
+out_err:
+       dev_kfree_skb_any(skb);
+       return NULL;
+}
+
+static void b53_mangle_rx(struct net_device *dev, struct sk_buff *skb)
+{
+       skb_pull(skb, BRCM_HDR_LEN);
+       memmove(skb->data,
+               skb->data - BRCM_HDR_LEN,
+               2 * ETH_ALEN);
+}
+
+void b53_enable_brcm_hdr(struct b53_device *dev)
+{
+       u8 brcm_hdr_ctrl;
+
+       b53_read8(dev, B53_MGMT_PAGE, B53_BRCM_HDR_CTRL, &brcm_hdr_ctrl);
+       if (!dev->enable_brcm_hdr && dev->eth_dev) {
+               dev->eth_dev->phy_ptr = NULL;
+               dev->eth_dev->priv_flags &= ~IFF_NO_IP_ALIGN;
+               dev->eth_dev->eth_mangle_rx = NULL;
+               dev->eth_dev->eth_mangle_tx = NULL;
+               dev->eth_dev = NULL;
+       }
+       brcm_hdr_ctrl &= ~B53_BRCM_HDR_EN;
+       if (!dev->eth_dev) {
+               goto out;
+       }
+
+       /* Broadcom Header work in hw if managed mode is not enabled */
+       if (!dev->enable_management)
+               goto out;
+
+       dev->eth_dev->phy_ptr = dev;
+       dev->eth_dev->priv_flags |= IFF_NO_IP_ALIGN;
+       dev->eth_dev->eth_mangle_rx = b53_mangle_rx;
+       dev->eth_dev->eth_mangle_tx = b53_mangle_tx;
+       brcm_hdr_ctrl |= B53_BRCM_HDR_EN;
+       pr_info("%s: attached broadcom tag mangle code to %s\n",
+               dev->sw_dev.name, dev->eth_dev->name);
+out:
+
+       b53_write8(dev, B53_MGMT_PAGE, B53_BRCM_HDR_CTRL, brcm_hdr_ctrl);
+}
+
+int b53_global_get_brcm_hdr(struct switch_dev *dev,
+               const struct switch_attr *attr,
+               struct switch_val *val)
+{
+       struct b53_device *priv = sw_to_b53(dev);
+
+       val->value.i = priv->enable_brcm_hdr;
+
+       return 0;
+}
+
+int b53_global_set_brcm_hdr(struct switch_dev *dev,
+               const struct switch_attr *attr,
+               struct switch_val *val)
+{
+       struct b53_device *priv = sw_to_b53(dev);
+
+       priv->enable_brcm_hdr = !!(val->value.i && !priv->eth_dev);
+
+       return 0;
+}
+
diff --git a/target/linux/generic/files/drivers/net/phy/b53/b53_mdio.c 
b/target/linux/generic/files/drivers/net/phy/b53/b53_mdio.c
index 3c25f0e..a3e8052 100644
--- a/target/linux/generic/files/drivers/net/phy/b53/b53_mdio.c
+++ b/target/linux/generic/files/drivers/net/phy/b53/b53_mdio.c
@@ -293,6 +293,9 @@ static int b53_phy_config_init(struct phy_device *phydev)
        dev->current_page = 0xff;
        /* force the ethX as alias */
        dev->sw_dev.alias = phydev->attached_dev->name;
+#ifdef CONFIG_B53_HDR
+       dev->eth_dev = phydev->attached_dev;
+#endif
 
        ret = b53_switch_register(dev);
        if (ret) {
@@ -312,6 +315,10 @@ static void b53_phy_remove(struct phy_device *phydev)
        if (!priv)
                return;
 
+#ifdef CONFIG_B53_HDR
+       priv->eth_dev = NULL;
+#endif
+
        b53_switch_remove(priv);
 
        phydev->priv = NULL;
diff --git a/target/linux/generic/files/drivers/net/phy/b53/b53_priv.h 
b/target/linux/generic/files/drivers/net/phy/b53/b53_priv.h
index 15df201..f487bf2 100644
--- a/target/linux/generic/files/drivers/net/phy/b53/b53_priv.h
+++ b/target/linux/generic/files/drivers/net/phy/b53/b53_priv.h
@@ -23,6 +23,7 @@
 #include <linux/mutex.h>
 #include <linux/switch.h>
 #include <linux/if_ether.h>
+#include <linux/netdevice.h>
 
 struct b53_device;
 
@@ -142,6 +143,11 @@ struct b53_device {
        struct b53_arl_ops *arl_ops;
 #endif
 
+#ifdef CONFIG_B53_HDR
+       struct net_device *eth_dev;
+       unsigned enable_brcm_hdr:1;
+#endif
+
        struct b53_port *ports;
        struct b53_vlan *vlans;
 
@@ -345,6 +351,18 @@ static inline int b53_write64(struct b53_device *dev, u8 
page, u8 reg,
        return ret;
 }
 
+#ifdef CONFIG_B53_HDR
+void b53_enable_brcm_hdr(struct b53_device *dev);
+int b53_global_get_brcm_hdr(struct switch_dev *dev,
+               const struct switch_attr *attr,
+               struct switch_val *val);
+int b53_global_set_brcm_hdr(struct switch_dev *dev,
+               const struct switch_attr *attr,
+               struct switch_val *val);
+#else
+#define b53_enable_brcm_hdr(x)
+#endif
+
 #ifdef CONFIG_BCM47XX
 
 #include <bcm47xx_nvram.h>
-- 
2.1.2
_______________________________________________
openwrt-devel mailing list
[email protected]
https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel

Reply via email to