[OpenWrt-Devel] [PATCH 2/3] b53: add logic to handle the broadcom header
Alexandru Ardelean
ardeleanalex at gmail.com
Wed Feb 25 10:24:23 EST 2015
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 <ardeleanalex at gmail.com>
---
.../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 <ardeleanalex at gmail.com>
+ *
+ * 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
openwrt-devel at lists.openwrt.org
https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel
More information about the openwrt-devel
mailing list