From patchwork Wed Feb 25 15:24:23 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexandru Ardelean X-Patchwork-Id: 443440 X-Patchwork-Delegate: jogo@openwrt.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from arrakis.dune.hu (arrakis.dune.hu [78.24.191.176]) (using TLSv1.1 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4FD181400B6 for ; Thu, 26 Feb 2015 02:25:39 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=fail reason="verification failed; unprotected key" header.d=gmail.com header.i=@gmail.com header.b=NUcR9Ww7; dkim-adsp=none (unprotected policy); dkim-atps=neutral Received: from arrakis.dune.hu (localhost [127.0.0.1]) by arrakis.dune.hu (Postfix) with ESMTP id 8EF2328C1B3; Wed, 25 Feb 2015 16:24:39 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on arrakis.dune.hu X-Spam-Level: X-Spam-Status: No, score=-1.5 required=5.0 tests=BAYES_00,FREEMAIL_FROM, T_DKIM_INVALID autolearn=unavailable version=3.3.2 Received: from arrakis.dune.hu (localhost [127.0.0.1]) by arrakis.dune.hu (Postfix) with ESMTP id ED6C128C184 for ; Wed, 25 Feb 2015 16:24:25 +0100 (CET) X-policyd-weight: using cached result; rate: -8.5 Received: from mail-we0-f176.google.com (mail-we0-f176.google.com [74.125.82.176]) by arrakis.dune.hu (Postfix) with ESMTPS for ; Wed, 25 Feb 2015 16:24:24 +0100 (CET) Received: by wesx3 with SMTP id x3so4310086wes.6 for ; Wed, 25 Feb 2015 07:24:33 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=6TW+q5u49GQbsR1ogzcunSlA6m2xgUszXFlMxKB3pHE=; b=NUcR9Ww7xL0RbGp4P0NAgvLPnufcCssyozqioOx2YUDohT+jUsQ3Btz/Fr4Uuf2hd1 +PvCY6l6SwI1qBdqw1/PW0JQ17/eFWxFxA8IqoJQVKpDn/7fTHfzf6oXL/0OQdAPAUPy x6xYbBb3A2SD9CnrNshGQrLHeja42bHrmQC0jib+TFUtlxrwLA7ixxChBDhzIyJ0B8Nt OgWvmkQnUirL3VwPzXJwa82nFCK4p6jn0tPE0NKJLCpZIJvAgW7+/qSji6sQSR027ZN8 1gHwdeAfLhR+OA4fZXvQSqv+6RDbMDhcY/r1rlL4B3dYZcLXYjStvcmB9kuU+Cs8R85A 0L2A== X-Received: by 10.194.59.232 with SMTP id c8mr7501293wjr.76.1424877873240; Wed, 25 Feb 2015 07:24:33 -0800 (PST) Received: from orion.local ([194.105.29.179]) by mx.google.com with ESMTPSA id j9sm65270756wjy.18.2015.02.25.07.24.32 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 25 Feb 2015 07:24:32 -0800 (PST) From: Alexandru Ardelean To: openwrt-devel@lists.openwrt.org Date: Wed, 25 Feb 2015 17:24:23 +0200 Message-Id: <1424877864-30726-2-git-send-email-ardeleanalex@gmail.com> X-Mailer: git-send-email 2.1.2 In-Reply-To: <1424877864-30726-1-git-send-email-ardeleanalex@gmail.com> References: <1424877864-30726-1-git-send-email-ardeleanalex@gmail.com> Subject: [OpenWrt-Devel] [PATCH 2/3] b53: add logic to handle the broadcom header X-BeenThere: openwrt-devel@lists.openwrt.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: OpenWrt Development List List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: openwrt-devel-bounces@lists.openwrt.org Sender: "openwrt-devel" 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 --- .../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 + * + * 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 +#include + +#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 #include #include +#include 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