All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] net: phy: b53: switchdev driver for Broadcom BCM53xx switches
@ 2015-02-24 17:42 Rafał Miłecki
  2015-02-24 17:47 ` Rafał Miłecki
                   ` (3 more replies)
  0 siblings, 4 replies; 42+ messages in thread
From: Rafał Miłecki @ 2015-02-24 17:42 UTC (permalink / raw)
  To: David S. Miller, netdev
  Cc: Jonas Gorski, Florian Fainelli, Hauke Mehrtens, Felix Fietkau,
	Jiri Pirko, Rafał Miłecki

BCM53xx is series of Broadcom Ethernet switches that can be found in
various (mostly home) routers.
They are quite simple switches with mainly just support for:
1) Tagging incoming packets (PVID)
2) Untagging outgoing packets
3) Forwarding all packets across a single VLAN

This driver is split into common code (module) and bus specific code.
Right now only PHY (MDIO) support is included, other could follow after
accepting this driver. It was successfully tested on BCM4706 SoC with
BCM53125.

You could notice it's yet another try of submitting b53 driver. This
time it was modified to use recently introduced switchdev API which
hopefully make it possible to accept it mainline.

Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
---
Example usage. My BCM4706 router has switch with 6 ports:
0: WAN port
1-4: LAN ports
8: CPU connected port (on-SoC Ethernet device)

I decided to use VLAN 1 for WAN and VLAN 2 for LAN. I was able to
successfully configure it using:

bridge vlan add vid 1 dev sw0p1 pvid untagged
bridge vlan add vid 1 dev sw0p2 pvid untagged
bridge vlan add vid 1 dev sw0p3 pvid untagged
bridge vlan add vid 1 dev sw0p4 pvid untagged
bridge vlan add vid 1 dev sw0p8

bridge vlan add vid 2 dev sw0p0 pvid untagged
bridge vlan add vid 2 dev sw0p8
---
 drivers/net/phy/Kconfig          |   2 +
 drivers/net/phy/Makefile         |   1 +
 drivers/net/phy/b53/Kconfig      |  12 +
 drivers/net/phy/b53/Makefile     |   2 +
 drivers/net/phy/b53/b53_common.c | 961 +++++++++++++++++++++++++++++++++++++++
 drivers/net/phy/b53/b53_mdio.c   | 418 +++++++++++++++++
 drivers/net/phy/b53/b53_priv.h   | 299 ++++++++++++
 drivers/net/phy/b53/b53_regs.h   | 313 +++++++++++++
 8 files changed, 2008 insertions(+)
 create mode 100644 drivers/net/phy/b53/Kconfig
 create mode 100644 drivers/net/phy/b53/Makefile
 create mode 100644 drivers/net/phy/b53/b53_common.c
 create mode 100644 drivers/net/phy/b53/b53_mdio.c
 create mode 100644 drivers/net/phy/b53/b53_priv.h
 create mode 100644 drivers/net/phy/b53/b53_regs.h

diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 16adbc4..fc8554a 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -212,6 +212,8 @@ config MDIO_BCM_UNIMAC
 	  controllers as well as some Broadcom Ethernet switches such as the
 	  Starfighter 2 switches.
 
+source "drivers/net/phy/b53/Kconfig"
+
 endif # PHYLIB
 
 config MICREL_KS8995MA
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index 501ea76..3e8b3b7 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_LXT_PHY)		+= lxt.o
 obj-$(CONFIG_QSEMI_PHY)		+= qsemi.o
 obj-$(CONFIG_SMSC_PHY)		+= smsc.o
 obj-$(CONFIG_VITESSE_PHY)	+= vitesse.o
+obj-$(CONFIG_B53)		+= b53/
 obj-$(CONFIG_BROADCOM_PHY)	+= broadcom.o
 obj-$(CONFIG_BCM63XX_PHY)	+= bcm63xx.o
 obj-$(CONFIG_BCM7XXX_PHY)	+= bcm7xxx.o
diff --git a/drivers/net/phy/b53/Kconfig b/drivers/net/phy/b53/Kconfig
new file mode 100644
index 0000000..21bf6e7
--- /dev/null
+++ b/drivers/net/phy/b53/Kconfig
@@ -0,0 +1,12 @@
+menuconfig B53
+	tristate "Broadcom bcm53xx managed switch support"
+	help
+	  This driver adds support for Broadcom managed switch chips. It supports
+	  BCM5325E, BCM5365, BCM539x, BCM53115 and BCM53125 as well as BCM63XX
+	  integrated switches.
+
+config B53_PHY_DRIVER
+	tristate "B53 MDIO connected switch driver"
+	depends on B53
+	help
+	  Select to enable support for registering switches configured through MDIO.
diff --git a/drivers/net/phy/b53/Makefile b/drivers/net/phy/b53/Makefile
new file mode 100644
index 0000000..33d995b
--- /dev/null
+++ b/drivers/net/phy/b53/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_B53)		+= b53_common.o
+obj-$(CONFIG_B53_PHY_DRIVER)	+= b53_mdio.o
diff --git a/drivers/net/phy/b53/b53_common.c b/drivers/net/phy/b53/b53_common.c
new file mode 100644
index 0000000..fce6b71
--- /dev/null
+++ b/drivers/net/phy/b53/b53_common.c
@@ -0,0 +1,961 @@
+/*
+ * B53 switch driver main logic
+ *
+ * Copyright (C) 2011-2013 Jonas Gorski <jogo@openwrt.org>
+ *
+ * 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.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/slab.h>
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/etherdevice.h>
+#include <linux/export.h>
+#include <linux/gpio.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <net/netlink.h>
+#include <uapi/linux/if_bridge.h>
+#include <uapi/linux/rtnetlink.h>
+
+#include "b53_regs.h"
+#include "b53_priv.h"
+
+struct b53_chip_data {
+	u32 chip_id;
+	const char *dev_name;
+	const char *alias;
+	u16 vlans;
+	u16 enabled_ports;
+	u8 cpu_port;
+	u8 vta_regs[3];
+	u8 duplex_reg;
+	u8 jumbo_pm_reg;
+	u8 jumbo_size_reg;
+};
+
+static int b53_do_vlan_op(struct b53_device *dev, u8 op)
+{
+	unsigned int i;
+
+	b53_write8(dev, B53_ARLIO_PAGE, dev->chip->vta_regs[0],
+		   VTA_START_CMD | op);
+
+	for (i = 0; i < 10; i++) {
+		u8 vta;
+
+		b53_read8(dev, B53_ARLIO_PAGE, dev->chip->vta_regs[0], &vta);
+		if (!(vta & VTA_START_CMD))
+			return 0;
+
+		usleep_range(100, 200);
+	}
+
+	return -EIO;
+}
+
+static void b53_set_vlan_entry(struct b53_device *dev, u16 vid, u16 members,
+			       u16 untag)
+{
+	if (is5325(dev)) {
+		u32 entry = 0;
+
+		if (members) {
+			entry = ((untag & VA_UNTAG_MASK_25) << VA_UNTAG_S_25) |
+				members;
+			if (dev->core_rev >= 3)
+				entry |= VA_VALID_25_R4 | vid << VA_VID_HIGH_S;
+			else
+				entry |= VA_VALID_25;
+		}
+
+		b53_write32(dev, B53_VLAN_PAGE, B53_VLAN_WRITE_25, entry);
+		b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_TABLE_ACCESS_25, vid |
+			    VTA_RW_STATE_WR | VTA_RW_OP_EN);
+	} else if (is5365(dev)) {
+		u16 entry = 0;
+
+		if (members)
+			entry = ((untag & VA_UNTAG_MASK_65) << VA_UNTAG_S_65) |
+				members | VA_VALID_65;
+
+		b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_WRITE_65, entry);
+		b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_TABLE_ACCESS_65, vid |
+			    VTA_RW_STATE_WR | VTA_RW_OP_EN);
+	} else {
+		b53_write16(dev, B53_ARLIO_PAGE, dev->chip->vta_regs[1], vid);
+		b53_write32(dev, B53_ARLIO_PAGE, dev->chip->vta_regs[2],
+			    (untag << VTE_UNTAG_S) | members);
+
+		b53_do_vlan_op(dev, VTA_CMD_WRITE);
+	}
+}
+
+void b53_set_forwarding(struct b53_device *dev, int enable)
+{
+	u8 mgmt;
+
+	b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt);
+
+	if (enable)
+		mgmt |= SM_SW_FWD_EN;
+	else
+		mgmt &= ~SM_SW_FWD_EN;
+
+	b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, mgmt);
+}
+
+static void b53_enable_vlan(struct b53_device *dev, int enable)
+{
+	u8 mgmt, vc0, vc1, vc4 = 0, vc5;
+
+	b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt);
+	b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL0, &vc0);
+	b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL1, &vc1);
+
+	if (is5325(dev) || is5365(dev)) {
+		b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_25, &vc4);
+		b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5_25, &vc5);
+	} else if (is63xx(dev)) {
+		b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_63XX, &vc4);
+		b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5_63XX, &vc5);
+	} else {
+		b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4, &vc4);
+		b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5, &vc5);
+	}
+
+	mgmt &= ~SM_SW_FWD_MODE;
+
+	if (enable) {
+		vc0 |= VC0_VLAN_EN | VC0_VID_CHK_EN | VC0_VID_HASH_VID;
+		vc1 |= VC1_RX_MCST_UNTAG_EN | VC1_RX_MCST_FWD_EN;
+		vc4 &= ~VC4_ING_VID_CHECK_MASK;
+		vc4 |= VC4_ING_VID_VIO_DROP << VC4_ING_VID_CHECK_S;
+		vc5 |= VC5_DROP_VTABLE_MISS;
+
+		if (is5325(dev))
+			vc0 &= ~VC0_RESERVED_1;
+
+		if (is5325(dev) || is5365(dev))
+			vc1 |= VC1_RX_MCST_TAG_EN;
+
+		if (!is5325(dev) && !is5365(dev)) {
+			if (dev->allow_vid_4095)
+				vc5 |= VC5_VID_FFF_EN;
+			else
+				vc5 &= ~VC5_VID_FFF_EN;
+		}
+	} else {
+		vc0 &= ~(VC0_VLAN_EN | VC0_VID_CHK_EN | VC0_VID_HASH_VID);
+		vc1 &= ~(VC1_RX_MCST_UNTAG_EN | VC1_RX_MCST_FWD_EN);
+		vc4 &= ~VC4_ING_VID_CHECK_MASK;
+		vc5 &= ~VC5_DROP_VTABLE_MISS;
+
+		if (is5325(dev) || is5365(dev))
+			vc4 |= VC4_ING_VID_VIO_FWD << VC4_ING_VID_CHECK_S;
+		else
+			vc4 |= VC4_ING_VID_VIO_TO_IMP << VC4_ING_VID_CHECK_S;
+
+		if (is5325(dev) || is5365(dev))
+			vc1 &= ~VC1_RX_MCST_TAG_EN;
+
+		if (!is5325(dev) && !is5365(dev))
+			vc5 &= ~VC5_VID_FFF_EN;
+	}
+
+	b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL0, vc0);
+	b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL1, vc1);
+
+	if (is5325(dev) || is5365(dev)) {
+		/* enable the high 8 bit vid check on 5325 */
+		if (is5325(dev) && enable)
+			b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL3,
+				   VC3_HIGH_8BIT_EN);
+		else
+			b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL3, 0);
+
+		b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_25, vc4);
+		b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5_25, vc5);
+	} else if (is63xx(dev)) {
+		b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_CTRL3_63XX, 0);
+		b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_63XX, vc4);
+		b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5_63XX, vc5);
+	} else {
+		b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_CTRL3, 0);
+		b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4, vc4);
+		b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5, vc5);
+	}
+
+	b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, mgmt);
+}
+
+static int b53_set_jumbo(struct b53_device *dev, int enable, int allow_10_100)
+{
+	u32 port_mask = 0;
+	u16 max_size = JMS_MIN_SIZE;
+
+	if (is5325(dev) || is5365(dev))
+		return -EINVAL;
+
+	if (enable) {
+		port_mask = dev->enabled_ports;
+		max_size = JMS_MAX_SIZE;
+		if (allow_10_100)
+			port_mask |= JPM_10_100_JUMBO_EN;
+	}
+
+	b53_write32(dev, B53_JUMBO_PAGE, dev->chip->jumbo_pm_reg, port_mask);
+	return b53_write16(dev, B53_JUMBO_PAGE, dev->chip->jumbo_size_reg,
+			   max_size);
+}
+
+static int b53_flush_arl(struct b53_device *dev)
+{
+	unsigned int i;
+
+	b53_write8(dev, B53_CTRL_PAGE, B53_FAST_AGE_CTRL,
+		   FAST_AGE_DONE | FAST_AGE_DYNAMIC | FAST_AGE_STATIC);
+
+	for (i = 0; i < 10; i++) {
+		u8 fast_age_ctrl;
+
+		b53_read8(dev, B53_CTRL_PAGE, B53_FAST_AGE_CTRL,
+			  &fast_age_ctrl);
+
+		if (!(fast_age_ctrl & FAST_AGE_DONE))
+			return 0;
+
+		mdelay(1);
+	}
+
+	pr_warn("time out while flushing ARL\n");
+
+	return -EINVAL;
+}
+
+static void b53_enable_ports(struct b53_device *dev)
+{
+	unsigned i;
+
+	b53_for_each_port(dev, i) {
+		u8 port_ctrl;
+		u16 pvlan_mask;
+
+		/* prevent leaking packets between wan and lan in unmanaged
+		 * mode through port vlans.
+		 */
+		if (dev->enable_vlan || is_cpu_port(dev, i))
+			pvlan_mask = 0x1ff;
+		else if (is531x5(dev) || is5301x(dev))
+			/* BCM53115 may use a different port as cpu port */
+			pvlan_mask = BIT(dev->cpu_port);
+		else
+			pvlan_mask = BIT(B53_CPU_PORT);
+
+		/* BCM5325 CPU port is at 8 */
+		if ((is5325(dev) || is5365(dev)) && i == B53_CPU_PORT_25)
+			i = B53_CPU_PORT;
+
+		if (dev->chip_id == BCM5398_DEVICE_ID && (i == 6 || i == 7))
+			/* disable unused ports 6 & 7 */
+			port_ctrl = PORT_CTRL_RX_DISABLE | PORT_CTRL_TX_DISABLE;
+		else if (i == B53_CPU_PORT)
+			port_ctrl = PORT_CTRL_RX_BCST_EN |
+				    PORT_CTRL_RX_MCST_EN |
+				    PORT_CTRL_RX_UCST_EN;
+		else
+			port_ctrl = 0;
+
+		b53_write16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(i),
+			    pvlan_mask);
+
+		/* port state is handled by bcm63xx_enet driver */
+		if (!is63xx(dev) && !(is5301x(dev) && i == 6))
+			b53_write8(dev, B53_CTRL_PAGE, B53_PORT_CTRL(i),
+				   port_ctrl);
+	}
+}
+
+static void b53_enable_mib(struct b53_device *dev)
+{
+	u8 gc;
+
+	b53_read8(dev, B53_CTRL_PAGE, B53_GLOBAL_CONFIG, &gc);
+
+	gc &= ~(GC_RESET_MIB | GC_MIB_AC_EN);
+
+	b53_write8(dev, B53_CTRL_PAGE, B53_GLOBAL_CONFIG, gc);
+}
+
+static int b53_apply(struct b53_device *dev)
+{
+	int i;
+
+	/* clear all vlan entries */
+	if (is5325(dev) || is5365(dev)) {
+		for (i = 1; i < dev->chip->vlans; i++)
+			b53_set_vlan_entry(dev, i, 0, 0);
+	} else {
+		b53_do_vlan_op(dev, VTA_CMD_CLEAR);
+	}
+
+	b53_enable_vlan(dev, dev->enable_vlan);
+
+	/* fill VLAN table */
+	if (dev->enable_vlan) {
+		for (i = 0; i < dev->chip->vlans; i++) {
+			struct b53_vlan *vlan = &dev->vlans[i];
+
+			if (!vlan->members)
+				continue;
+
+			b53_set_vlan_entry(dev, i, vlan->members, vlan->untag);
+		}
+
+		b53_for_each_port(dev, i)
+			b53_write16(dev, B53_VLAN_PAGE,
+				    B53_VLAN_PORT_DEF_TAG(i),
+				    dev->ports[i]->pvid);
+	} else {
+		b53_for_each_port(dev, i)
+			b53_write16(dev, B53_VLAN_PAGE,
+				    B53_VLAN_PORT_DEF_TAG(i), 1);
+	}
+
+	b53_enable_ports(dev);
+
+	if (!is5325(dev) && !is5365(dev))
+		b53_set_jumbo(dev, dev->enable_jumbo, 1);
+
+	return 0;
+}
+
+static void b53_switch_reset_gpio(struct b53_device *dev)
+{
+	int gpio = dev->reset_gpio;
+
+	if (gpio < 0)
+		return;
+
+	/* Reset sequence: RESET low(50ms)->high(20ms) */
+
+	gpio_set_value(gpio, 0);
+	mdelay(50);
+
+	gpio_set_value(gpio, 1);
+	mdelay(20);
+
+	dev->current_page = 0xff;
+}
+
+static int b53_switch_reset(struct b53_device *dev)
+{
+	u8 mgmt;
+
+	b53_switch_reset_gpio(dev);
+
+	if (is539x(dev)) {
+		b53_write8(dev, B53_CTRL_PAGE, B53_SOFTRESET, 0x83);
+		b53_write8(dev, B53_CTRL_PAGE, B53_SOFTRESET, 0x00);
+	}
+
+	b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt);
+
+	if (!(mgmt & SM_SW_FWD_EN)) {
+		mgmt &= ~SM_SW_FWD_MODE;
+		mgmt |= SM_SW_FWD_EN;
+
+		b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, mgmt);
+		b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt);
+
+		if (!(mgmt & SM_SW_FWD_EN)) {
+			pr_err("Failed to enable switch!\n");
+			return -EINVAL;
+		}
+	}
+
+	/* enable all ports */
+	b53_enable_ports(dev);
+
+	/* configure MII port if necessary */
+	if (is5325(dev)) {
+		u8 mii_port_override;
+
+		b53_read8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL,
+			  &mii_port_override);
+		/* reverse mii needs to be enabled */
+		if (!(mii_port_override & PORT_OVERRIDE_RV_MII_25)) {
+			b53_write8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL,
+				   mii_port_override | PORT_OVERRIDE_RV_MII_25);
+			b53_read8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL,
+				  &mii_port_override);
+
+			if (!(mii_port_override & PORT_OVERRIDE_RV_MII_25)) {
+				pr_err("Failed to enable reverse MII mode\n");
+				return -EINVAL;
+			}
+		}
+	} else if ((is531x5(dev) || is5301x(dev)) &&
+		   dev->cpu_port == B53_CPU_PORT) {
+		u8 mii_port_override;
+
+		b53_read8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL,
+			  &mii_port_override);
+		b53_write8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL,
+			   mii_port_override | PORT_OVERRIDE_EN |
+			   PORT_OVERRIDE_LINK);
+	}
+
+	b53_enable_mib(dev);
+
+	return b53_flush_arl(dev);
+}
+
+/*****************
+ * Net device ops
+ *****************/
+
+static netdev_tx_t b53_port_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	dev_kfree_skb(skb);
+	dev->stats.tx_dropped++;
+
+	return NETDEV_TX_OK;
+}
+
+static int b53_port_vlan_rx_add_vid(struct net_device *dev,
+				    __be16 proto, u16 vid)
+{
+	struct b53_port *b53_port = netdev_priv(dev);
+	struct b53_device *b53 = b53_port->b53;
+	struct b53_vlan *vlan;
+
+	if (vid >= b53->chip->vlans)
+		return -EINVAL;
+
+	/* only BCM5325 and BCM5365 supports VID 0 */
+	if (vid == 0 && !is5325(b53) && !is5365(b53))
+		return -EINVAL;
+
+	/* VLAN 4095 needs special handling */
+	if (vid == 4095)
+		return -EINVAL;
+
+	vlan = &b53->vlans[vid];
+
+	vlan->members |= BIT(b53_port->port_number);
+
+	/* ignore disabled ports */
+	vlan->members &= b53->enabled_ports;
+
+	b53_apply(b53);
+
+	return 0;
+}
+
+static int b53_port_vlan_rx_kill_vid(struct net_device *dev,
+				     __be16 proto, u16 vid)
+{
+	struct b53_port *b53_port = netdev_priv(dev);
+	struct b53_device *b53 = b53_port->b53;
+	struct b53_vlan *vlan;
+
+	if (vid >= b53->chip->vlans)
+		return -EINVAL;
+
+	vlan = &b53->vlans[vid];
+
+	vlan->members &= ~BIT(b53_port->port_number);
+
+	b53_apply(b53);
+
+	return 0;
+}
+
+static int b53_port_switch_parent_id_get(struct net_device *dev,
+					 struct netdev_phys_item_id *psid)
+{
+	struct b53_port *b53_port = netdev_priv(dev);
+
+	memcpy(psid->id, b53_port->b53->dev_addr, ETH_ALEN);
+	psid->id_len = ETH_ALEN;
+
+	return 0;
+}
+
+static int b53_port_bridge_setlink(struct net_device *dev,
+				   struct nlmsghdr *nlh, u16 flags)
+{
+	struct b53_port *b53_port = netdev_priv(dev);
+	struct b53_device *b53 = b53_port->b53;
+	struct b53_vlan *vlan;
+	struct nlattr *afspec;
+	struct nlattr *attr;
+	struct bridge_vlan_info *vinfo;
+	int rem;
+
+	afspec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC);
+	if (!afspec)
+		return -EINVAL;
+
+	nla_for_each_nested(attr, afspec, rem) {
+		if (nla_type(attr) != IFLA_BRIDGE_VLAN_INFO)
+			continue;
+		if (nla_len(attr) != sizeof(struct bridge_vlan_info))
+			return -EINVAL;
+		vinfo = nla_data(attr);
+	}
+	if (!vinfo)
+		return -EINVAL;
+
+	if (vinfo->flags & BRIDGE_VLAN_INFO_PVID)
+		b53_port->pvid = vinfo->vid;
+	else
+		b53_port->pvid = 0;
+
+	vlan = &b53->vlans[vinfo->vid];
+	if (vinfo->flags & BRIDGE_VLAN_INFO_UNTAGGED)
+		vlan->untag |= BIT(b53_port->port_number);
+	else
+		vlan->untag &= ~BIT(b53_port->port_number);
+
+	b53_apply(b53);
+
+	return 0;
+}
+
+static const struct net_device_ops b53_port_netdev_ops = {
+	.ndo_start_xmit			= b53_port_xmit,
+	.ndo_vlan_rx_add_vid		= b53_port_vlan_rx_add_vid,
+	.ndo_vlan_rx_kill_vid		= b53_port_vlan_rx_kill_vid,
+	.ndo_switch_parent_id_get	= b53_port_switch_parent_id_get,
+	.ndo_bridge_setlink		= b53_port_bridge_setlink,
+};
+
+/*****************
+ * Common
+ *****************/
+
+static void b53_remove_ports(struct b53_device *b53)
+{
+	struct b53_port *b53_port;
+	unsigned int i;
+
+	for (i = 0; i < b53->port_count; i++) {
+		b53_port = b53->ports[i];
+		unregister_netdev(b53_port->ndev);
+	}
+	kfree(b53->ports);
+}
+
+static int b53_probe_port(struct b53_device *b53, unsigned int port_number)
+{
+	struct b53_port *b53_port;
+	struct net_device *ndev;
+	int err;
+
+	ndev = alloc_etherdev(sizeof(struct b53_port));
+	if (!ndev)
+		return -ENOMEM;
+	b53_port = netdev_priv(ndev);
+	b53_port->ndev = ndev;
+	b53_port->b53 = b53;
+	b53_port->port_number = port_number;
+
+	ndev->netdev_ops = &b53_port_netdev_ops;
+	ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER |
+			  NETIF_F_HW_SWITCH_OFFLOAD;
+	netif_carrier_on(ndev);
+	memcpy(ndev->dev_addr, b53->dev_addr, ETH_ALEN);
+
+	err = register_netdev(ndev);
+	if (err) {
+		dev_err(b53->dev, "register_netdev failed\n");
+		goto err_free_netdev;
+	}
+	b53->ports[port_number] = b53_port;
+
+	return 0;
+
+err_free_netdev:
+	free_netdev(ndev);
+	return err;
+}
+
+#define B53_VTA_REGS	\
+	{ B53_VT_ACCESS, B53_VT_INDEX, B53_VT_ENTRY }
+#define B53_VTA_REGS_9798 \
+	{ B53_VT_ACCESS_9798, B53_VT_INDEX_9798, B53_VT_ENTRY_9798 }
+#define B53_VTA_REGS_63XX \
+	{ B53_VT_ACCESS_63XX, B53_VT_INDEX_63XX, B53_VT_ENTRY_63XX }
+
+static const struct b53_chip_data b53_switch_chips[] = {
+	{
+		.chip_id = BCM5325_DEVICE_ID,
+		.dev_name = "BCM5325",
+		.alias = "bcm5325",
+		.vlans = 16,
+		.enabled_ports = 0x1f,
+		.cpu_port = B53_CPU_PORT_25,
+		.duplex_reg = B53_DUPLEX_STAT_FE,
+	},
+	{
+		.chip_id = BCM5365_DEVICE_ID,
+		.dev_name = "BCM5365",
+		.alias = "bcm5365",
+		.vlans = 256,
+		.enabled_ports = 0x1f,
+		.cpu_port = B53_CPU_PORT_25,
+		.duplex_reg = B53_DUPLEX_STAT_FE,
+	},
+	{
+		.chip_id = BCM5395_DEVICE_ID,
+		.dev_name = "BCM5395",
+		.alias = "bcm5395",
+		.vlans = 4096,
+		.enabled_ports = 0x1f,
+		.cpu_port = B53_CPU_PORT,
+		.vta_regs = B53_VTA_REGS,
+		.duplex_reg = B53_DUPLEX_STAT_GE,
+		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
+		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
+	},
+	{
+		.chip_id = BCM5397_DEVICE_ID,
+		.dev_name = "BCM5397",
+		.alias = "bcm5397",
+		.vlans = 4096,
+		.enabled_ports = 0x1f,
+		.cpu_port = B53_CPU_PORT,
+		.vta_regs = B53_VTA_REGS_9798,
+		.duplex_reg = B53_DUPLEX_STAT_GE,
+		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
+		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
+	},
+	{
+		.chip_id = BCM5398_DEVICE_ID,
+		.dev_name = "BCM5398",
+		.alias = "bcm5398",
+		.vlans = 4096,
+		.enabled_ports = 0x7f,
+		.cpu_port = B53_CPU_PORT,
+		.vta_regs = B53_VTA_REGS_9798,
+		.duplex_reg = B53_DUPLEX_STAT_GE,
+		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
+		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
+	},
+	{
+		.chip_id = BCM53115_DEVICE_ID,
+		.dev_name = "BCM53115",
+		.alias = "bcm53115",
+		.vlans = 4096,
+		.enabled_ports = 0x1f,
+		.vta_regs = B53_VTA_REGS,
+		.cpu_port = B53_CPU_PORT,
+		.duplex_reg = B53_DUPLEX_STAT_GE,
+		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
+		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
+	},
+	{
+		.chip_id = BCM53125_DEVICE_ID,
+		.dev_name = "BCM53125",
+		.alias = "bcm53125",
+		.vlans = 4096,
+		.enabled_ports = 0x1f,
+		.cpu_port = B53_CPU_PORT,
+		.vta_regs = B53_VTA_REGS,
+		.duplex_reg = B53_DUPLEX_STAT_GE,
+		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
+		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
+	},
+	{
+		.chip_id = BCM53128_DEVICE_ID,
+		.dev_name = "BCM53128",
+		.alias = "bcm53128",
+		.vlans = 4096,
+		.enabled_ports = 0x1ff,
+		.cpu_port = B53_CPU_PORT,
+		.vta_regs = B53_VTA_REGS,
+		.duplex_reg = B53_DUPLEX_STAT_GE,
+		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
+		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
+	},
+	{
+		.chip_id = BCM53010_DEVICE_ID,
+		.dev_name = "BCM53010",
+		.alias = "bcm53011",
+		.vlans = 4096,
+		.enabled_ports = 0x1f,
+		.cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */
+		.vta_regs = B53_VTA_REGS,
+		.duplex_reg = B53_DUPLEX_STAT_GE,
+		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
+		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
+	},
+	{
+		.chip_id = BCM53011_DEVICE_ID,
+		.dev_name = "BCM53011",
+		.alias = "bcm53011",
+		.vlans = 4096,
+		.enabled_ports = 0x1f,
+		.cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */
+		.vta_regs = B53_VTA_REGS,
+		.duplex_reg = B53_DUPLEX_STAT_GE,
+		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
+		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
+	},
+	{
+		.chip_id = BCM53012_DEVICE_ID,
+		.dev_name = "BCM53012",
+		.alias = "bcm53011",
+		.vlans = 4096,
+		.enabled_ports = 0x1f,
+		.cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */
+		.vta_regs = B53_VTA_REGS,
+		.duplex_reg = B53_DUPLEX_STAT_GE,
+		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
+		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
+	},
+	{
+		.chip_id = BCM53018_DEVICE_ID,
+		.dev_name = "BCM53018",
+		.alias = "bcm53018",
+		.vlans = 4096,
+		.enabled_ports = 0x1f,
+		.cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */
+		.vta_regs = B53_VTA_REGS,
+		.duplex_reg = B53_DUPLEX_STAT_GE,
+		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
+		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
+	},
+	{
+		.chip_id = BCM53019_DEVICE_ID,
+		.dev_name = "BCM53019",
+		.alias = "bcm53019",
+		.vlans = 4096,
+		.enabled_ports = 0x1f,
+		.cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */
+		.vta_regs = B53_VTA_REGS,
+		.duplex_reg = B53_DUPLEX_STAT_GE,
+		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
+		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
+	},
+};
+
+static int b53_switch_init(struct b53_device *dev)
+{
+	unsigned int i;
+	int err;
+
+	eth_random_addr(dev->dev_addr);
+
+	dev->cpu_port = dev->chip->cpu_port;
+	dev->enabled_ports = dev->chip->enabled_ports;
+
+	/* check which BCM5325x version we have */
+	if (is5325(dev)) {
+		u8 vc4;
+
+		b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_25, &vc4);
+
+		/* check reserved bits */
+		switch (vc4 & 3) {
+		case 1:
+			/* BCM5325E */
+			break;
+		case 3:
+			/* BCM5325F - do not use port 4 */
+			dev->enabled_ports &= ~BIT(4);
+			break;
+		default:
+/* On the BCM47XX SoCs this is the supported internal switch.*/
+#ifndef CONFIG_BCM47XX
+			/* BCM5325M */
+			return -EINVAL;
+#else
+			break;
+#endif
+		}
+	} else if (dev->chip_id == BCM53115_DEVICE_ID) {
+		u64 strap_value;
+
+		b53_read48(dev, B53_STAT_PAGE, B53_STRAP_VALUE, &strap_value);
+		/* use second IMP port if GMII is enabled */
+		if (strap_value & SV_GMII_CTRL_115)
+			dev->cpu_port = 5;
+	}
+
+	/* cpu port is always last */
+	dev->port_count = dev->cpu_port + 1;
+	dev->enabled_ports |= BIT(dev->cpu_port);
+
+	dev->ports = devm_kzalloc(dev->dev,
+				  sizeof(struct b53_port *) * dev->port_count,
+				  GFP_KERNEL);
+	if (!dev->ports)
+		return -ENOMEM;
+
+	for (i = 0; i < dev->port_count; i++) {
+		err = b53_probe_port(dev, i);
+		if (err)
+			goto err_remove_ports;
+	}
+
+	dev->vlans = devm_kzalloc(dev->dev,
+				  sizeof(struct b53_vlan) * dev->chip->vlans,
+				  GFP_KERNEL);
+	if (!dev->vlans)
+		return -ENOMEM;
+
+	dev->reset_gpio = b53_switch_get_reset_gpio(dev);
+	if (dev->reset_gpio >= 0) {
+		err = devm_gpio_request_one(dev->dev, dev->reset_gpio,
+					    GPIOF_OUT_INIT_HIGH, "robo_reset");
+		if (err)
+			return err;
+	}
+
+	return b53_switch_reset(dev);
+
+err_remove_ports:
+	b53_remove_ports(dev);
+	return err;
+}
+
+struct b53_device *b53_switch_alloc(struct device *base, struct b53_io_ops *ops,
+				    void *priv)
+{
+	struct b53_device *dev;
+
+	dev = devm_kzalloc(base, sizeof(*dev), GFP_KERNEL);
+	if (!dev)
+		return NULL;
+
+	dev->dev = base;
+	dev->ops = ops;
+	dev->priv = priv;
+	mutex_init(&dev->reg_mutex);
+
+	return dev;
+}
+EXPORT_SYMBOL(b53_switch_alloc);
+
+int b53_switch_detect(struct b53_device *dev)
+{
+	u32 id32;
+	u16 tmp;
+	u8 id8;
+	unsigned i;
+	int ret;
+
+	ret = b53_read8(dev, B53_MGMT_PAGE, B53_DEVICE_ID, &id8);
+	if (ret)
+		return ret;
+
+	switch (id8) {
+	case 0:
+		/* BCM5325 and BCM5365 do not have this register so reads
+		 * return 0. But the read operation did succeed, so assume
+		 * this is one of them.
+		 *
+		 * Next check if we can write to the 5325's VTA register; for
+		 * 5365 it is read only.
+		 */
+
+		b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_TABLE_ACCESS_25, 0xf);
+		b53_read16(dev, B53_VLAN_PAGE, B53_VLAN_TABLE_ACCESS_25, &tmp);
+
+		if (tmp == 0xf)
+			dev->chip_id = BCM5325_DEVICE_ID;
+		else
+			dev->chip_id = BCM5365_DEVICE_ID;
+		break;
+	case BCM5395_DEVICE_ID:
+	case BCM5397_DEVICE_ID:
+	case BCM5398_DEVICE_ID:
+		dev->chip_id = id8;
+		break;
+	default:
+		ret = b53_read32(dev, B53_MGMT_PAGE, B53_DEVICE_ID, &id32);
+		if (ret)
+			return ret;
+
+		switch (id32) {
+		case BCM53115_DEVICE_ID:
+		case BCM53125_DEVICE_ID:
+		case BCM53128_DEVICE_ID:
+		case BCM53010_DEVICE_ID:
+		case BCM53011_DEVICE_ID:
+		case BCM53012_DEVICE_ID:
+		case BCM53018_DEVICE_ID:
+		case BCM53019_DEVICE_ID:
+			dev->chip_id = id32;
+			break;
+		default:
+			pr_err("unsupported switch detected (BCM53%02x/BCM%x)\n",
+			       id8, id32);
+			return -ENODEV;
+		}
+	}
+
+	if (dev->chip_id == BCM5325_DEVICE_ID)
+		ret = b53_read8(dev, B53_STAT_PAGE, B53_REV_ID_25,
+				&dev->core_rev);
+	else
+		ret = b53_read8(dev, B53_MGMT_PAGE, B53_REV_ID, &dev->core_rev);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < ARRAY_SIZE(b53_switch_chips); i++) {
+		const struct b53_chip_data *chip = &b53_switch_chips[i];
+
+		if (chip->chip_id == dev->chip_id) {
+			dev->chip = chip;
+			return 0;
+		}
+	}
+
+	return -ENOENT;
+}
+EXPORT_SYMBOL(b53_switch_detect);
+
+int b53_switch_register(struct b53_device *dev)
+{
+	int ret;
+
+	if (!dev->chip_id && b53_switch_detect(dev))
+		return -EINVAL;
+
+	ret = b53_switch_init(dev);
+	if (ret)
+		return ret;
+
+	dev_info(dev->dev, "found switch: %s, rev %i\n", dev->chip->dev_name,
+		 dev->core_rev);
+
+	return 0;
+}
+EXPORT_SYMBOL(b53_switch_register);
+
+void b53_switch_exit(struct b53_device *b53)
+{
+	b53_remove_ports(b53);
+}
+EXPORT_SYMBOL(b53_switch_exit);
+
+MODULE_AUTHOR("Jonas Gorski <jogo@openwrt.org>");
+MODULE_DESCRIPTION("B53 switch library");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/phy/b53/b53_mdio.c b/drivers/net/phy/b53/b53_mdio.c
new file mode 100644
index 0000000..747ef67
--- /dev/null
+++ b/drivers/net/phy/b53/b53_mdio.c
@@ -0,0 +1,418 @@
+/*
+ * B53 register access through MII registers
+ *
+ * Copyright (C) 2011-2013 Jonas Gorski <jogo@openwrt.org>
+ *
+ * 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/delay.h>
+#include <linux/kernel.h>
+#include <linux/phy.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+
+#include "b53_priv.h"
+
+#define B53_PSEUDO_PHY	0x1e /* Register Access Pseudo PHY */
+
+/* MII registers */
+#define REG_MII_PAGE		0x10    /* MII Page register */
+#define REG_MII_ADDR		0x11    /* MII Address register */
+#define REG_MII_DATA0		0x18    /* MII Data register 0 */
+#define REG_MII_DATA1		0x19    /* MII Data register 1 */
+#define REG_MII_DATA2		0x1a    /* MII Data register 2 */
+#define REG_MII_DATA3		0x1b    /* MII Data register 3 */
+
+#define REG_MII_PAGE_ENABLE	BIT(0)
+#define REG_MII_ADDR_WRITE	BIT(0)
+#define REG_MII_ADDR_READ	BIT(1)
+
+static int b53_mdio_op(struct b53_device *dev, u8 page, u8 reg, u16 op)
+{
+	int i;
+	u16 v;
+	int ret;
+	struct mii_bus *bus = dev->priv;
+
+	if (dev->current_page != page) {
+		/* set page number */
+		v = (page << 8) | REG_MII_PAGE_ENABLE;
+		ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_PAGE, v);
+		if (ret)
+			return ret;
+		dev->current_page = page;
+	}
+
+	/* set register address */
+	v = (reg << 8) | op;
+	ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_ADDR, v);
+	if (ret)
+		return ret;
+
+	/* check if operation completed */
+	for (i = 0; i < 5; ++i) {
+		v = mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_ADDR);
+		if (!(v & (REG_MII_ADDR_WRITE | REG_MII_ADDR_READ)))
+			break;
+		usleep_range(10, 100);
+	}
+
+	if (WARN_ON(i == 5))
+		return -EIO;
+
+	return 0;
+}
+
+static int b53_mdio_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val)
+{
+	struct mii_bus *bus = dev->priv;
+	int ret;
+
+	ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ);
+	if (ret)
+		return ret;
+
+	*val = mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA0) & 0xff;
+
+	return 0;
+}
+
+static int b53_mdio_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val)
+{
+	struct mii_bus *bus = dev->priv;
+	int ret;
+
+	ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ);
+	if (ret)
+		return ret;
+
+	*val = mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA0);
+
+	return 0;
+}
+
+static int b53_mdio_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val)
+{
+	struct mii_bus *bus = dev->priv;
+	int ret;
+
+	ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ);
+	if (ret)
+		return ret;
+
+	*val = mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA0);
+	*val |= mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA1) << 16;
+
+	return 0;
+}
+
+static int b53_mdio_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val)
+{
+	struct mii_bus *bus = dev->priv;
+	u64 temp = 0;
+	int i;
+	int ret;
+
+	ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ);
+	if (ret)
+		return ret;
+
+	for (i = 2; i >= 0; i--) {
+		temp <<= 16;
+		temp |= mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA0 + i);
+	}
+
+	*val = temp;
+
+	return 0;
+}
+
+static int b53_mdio_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val)
+{
+	struct mii_bus *bus = dev->priv;
+	u64 temp = 0;
+	int i;
+	int ret;
+
+	ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ);
+	if (ret)
+		return ret;
+
+	for (i = 3; i >= 0; i--) {
+		temp <<= 16;
+		temp |= mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA0 + i);
+	}
+
+	*val = temp;
+
+	return 0;
+}
+
+static int b53_mdio_write8(struct b53_device *dev, u8 page, u8 reg, u8 value)
+{
+	struct mii_bus *bus = dev->priv;
+	int ret;
+
+	ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_DATA0, value);
+	if (ret)
+		return ret;
+
+	return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE);
+}
+
+static int b53_mdio_write16(struct b53_device *dev, u8 page, u8 reg, u16 value)
+{
+	struct mii_bus *bus = dev->priv;
+	int ret;
+
+	ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_DATA0, value);
+	if (ret)
+		return ret;
+
+	return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE);
+}
+
+static int b53_mdio_write32(struct b53_device *dev, u8 page, u8 reg, u32 value)
+{
+	struct mii_bus *bus = dev->priv;
+	unsigned int i;
+	u32 temp = value;
+
+	for (i = 0; i < 2; i++) {
+		int ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_DATA0 + i,
+				    temp & 0xffff);
+		if (ret)
+			return ret;
+		temp >>= 16;
+	}
+
+	return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE);
+}
+
+static int b53_mdio_write48(struct b53_device *dev, u8 page, u8 reg, u64 value)
+{
+	struct mii_bus *bus = dev->priv;
+	unsigned i;
+	u64 temp = value;
+
+	for (i = 0; i < 3; i++) {
+		int ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_DATA0 + i,
+				    temp & 0xffff);
+		if (ret)
+			return ret;
+		temp >>= 16;
+	}
+
+	return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE);
+}
+
+static int b53_mdio_write64(struct b53_device *dev, u8 page, u8 reg, u64 value)
+{
+	struct mii_bus *bus = dev->priv;
+	unsigned i;
+	u64 temp = value;
+
+	for (i = 0; i < 4; i++) {
+		int ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_DATA0 + i,
+				    temp & 0xffff);
+		if (ret)
+			return ret;
+		temp >>= 16;
+	}
+
+	return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE);
+}
+
+static struct b53_io_ops b53_mdio_ops = {
+	.read8 = b53_mdio_read8,
+	.read16 = b53_mdio_read16,
+	.read32 = b53_mdio_read32,
+	.read48 = b53_mdio_read48,
+	.read64 = b53_mdio_read64,
+	.write8 = b53_mdio_write8,
+	.write16 = b53_mdio_write16,
+	.write32 = b53_mdio_write32,
+	.write48 = b53_mdio_write48,
+	.write64 = b53_mdio_write64,
+};
+
+static int b53_phy_probe(struct phy_device *phydev)
+{
+	struct b53_device dev;
+	int ret;
+
+	/* allow the generic phy driver to take over */
+	if (phydev->addr != B53_PSEUDO_PHY && phydev->addr != 0)
+		return -ENODEV;
+
+	dev.current_page = 0xff;
+	dev.priv = phydev->bus;
+	dev.ops = &b53_mdio_ops;
+	mutex_init(&dev.reg_mutex);
+
+	ret = b53_switch_detect(&dev);
+	if (ret)
+		return ret;
+
+	if (is5325(&dev) || is5365(&dev))
+		phydev->supported = SUPPORTED_100baseT_Full;
+	else
+		phydev->supported = SUPPORTED_1000baseT_Full;
+
+	phydev->advertising = phydev->supported;
+
+	return 0;
+}
+
+static int b53_phy_config_init(struct phy_device *phydev)
+{
+	struct b53_device *dev;
+	int ret;
+
+	dev = b53_switch_alloc(&phydev->dev, &b53_mdio_ops, phydev->bus);
+	if (!dev)
+		return -ENOMEM;
+
+	/* we don't use page 0xff, so force a page set */
+	dev->current_page = 0xff;
+
+	ret = b53_switch_register(dev);
+	if (ret) {
+		dev_err(dev->dev, "failed to register switch: %i\n", ret);
+		return ret;
+	}
+
+	phydev->priv = dev;
+
+	return 0;
+}
+
+static void b53_phy_remove(struct phy_device *phydev)
+{
+	struct b53_device *priv = phydev->priv;
+
+	if (!priv)
+		return;
+
+	b53_switch_exit(priv);
+
+	phydev->priv = NULL;
+}
+
+static int b53_phy_config_aneg(struct phy_device *phydev)
+{
+	return 0;
+}
+
+static int b53_phy_read_status(struct phy_device *phydev)
+{
+	struct b53_device *priv = phydev->priv;
+
+	if (is5325(priv) || is5365(priv))
+		phydev->speed = 100;
+	else
+		phydev->speed = 1000;
+
+	phydev->duplex = DUPLEX_FULL;
+	phydev->link = 1;
+	phydev->state = PHY_RUNNING;
+
+	netif_carrier_on(phydev->attached_dev);
+	phydev->adjust_link(phydev->attached_dev);
+
+	return 0;
+}
+
+/* BCM5325, BCM539x */
+static struct phy_driver b53_phy_driver_id1 = {
+	.phy_id		= 0x0143bc00,
+	.name		= "Broadcom B53 (1)",
+	.phy_id_mask	= 0x1ffffc00,
+	.features	= 0,
+	.probe		= b53_phy_probe,
+	.remove		= b53_phy_remove,
+	.config_aneg	= b53_phy_config_aneg,
+	.config_init	= b53_phy_config_init,
+	.read_status	= b53_phy_read_status,
+	.driver = {
+		.owner = THIS_MODULE,
+	},
+};
+
+/* BCM53125, BCM53128 */
+static struct phy_driver b53_phy_driver_id2 = {
+	.phy_id		= 0x03625c00,
+	.name		= "Broadcom B53 (2)",
+	.phy_id_mask	= 0x1ffffc00,
+	.features	= 0,
+	.probe		= b53_phy_probe,
+	.remove		= b53_phy_remove,
+	.config_aneg	= b53_phy_config_aneg,
+	.config_init	= b53_phy_config_init,
+	.read_status	= b53_phy_read_status,
+	.driver = {
+		.owner = THIS_MODULE,
+	},
+};
+
+/* BCM5365 */
+static struct phy_driver b53_phy_driver_id3 = {
+	.phy_id		= 0x00406000,
+	.name		= "Broadcom B53 (3)",
+	.phy_id_mask	= 0x1ffffc00,
+	.features	= 0,
+	.probe		= b53_phy_probe,
+	.remove		= b53_phy_remove,
+	.config_aneg	= b53_phy_config_aneg,
+	.config_init	= b53_phy_config_init,
+	.read_status	= b53_phy_read_status,
+	.driver = {
+		.owner = THIS_MODULE,
+	},
+};
+
+int __init b53_phy_driver_register(void)
+{
+	int ret;
+
+	ret = phy_driver_register(&b53_phy_driver_id1);
+	if (ret)
+		return ret;
+
+	ret = phy_driver_register(&b53_phy_driver_id2);
+	if (ret)
+		goto err1;
+
+	ret = phy_driver_register(&b53_phy_driver_id3);
+	if (!ret)
+		return 0;
+
+	phy_driver_unregister(&b53_phy_driver_id2);
+err1:
+	phy_driver_unregister(&b53_phy_driver_id1);
+	return ret;
+}
+
+void __exit b53_phy_driver_unregister(void)
+{
+	phy_driver_unregister(&b53_phy_driver_id3);
+	phy_driver_unregister(&b53_phy_driver_id2);
+	phy_driver_unregister(&b53_phy_driver_id1);
+}
+
+module_init(b53_phy_driver_register);
+module_exit(b53_phy_driver_unregister);
+
+MODULE_DESCRIPTION("B53 MDIO access driver");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/phy/b53/b53_priv.h b/drivers/net/phy/b53/b53_priv.h
new file mode 100644
index 0000000..03ebaf0
--- /dev/null
+++ b/drivers/net/phy/b53/b53_priv.h
@@ -0,0 +1,299 @@
+/*
+ * B53 common definitions
+ *
+ * Copyright (C) 2011-2013 Jonas Gorski <jogo@openwrt.org>
+ *
+ * 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.
+ */
+
+#ifndef __B53_PRIV_H
+#define __B53_PRIV_H
+
+#include <linux/kernel.h>
+#include <linux/mutex.h>
+
+struct b53_device;
+
+struct b53_io_ops {
+	int (*read8)(struct b53_device *dev, u8 page, u8 reg, u8 *value);
+	int (*read16)(struct b53_device *dev, u8 page, u8 reg, u16 *value);
+	int (*read32)(struct b53_device *dev, u8 page, u8 reg, u32 *value);
+	int (*read48)(struct b53_device *dev, u8 page, u8 reg, u64 *value);
+	int (*read64)(struct b53_device *dev, u8 page, u8 reg, u64 *value);
+	int (*write8)(struct b53_device *dev, u8 page, u8 reg, u8 value);
+	int (*write16)(struct b53_device *dev, u8 page, u8 reg, u16 value);
+	int (*write32)(struct b53_device *dev, u8 page, u8 reg, u32 value);
+	int (*write48)(struct b53_device *dev, u8 page, u8 reg, u64 value);
+	int (*write64)(struct b53_device *dev, u8 page, u8 reg, u64 value);
+};
+
+enum {
+	BCM5325_DEVICE_ID = 0x25,
+	BCM5365_DEVICE_ID = 0x65,
+	BCM5395_DEVICE_ID = 0x95,
+	BCM5397_DEVICE_ID = 0x97,
+	BCM5398_DEVICE_ID = 0x98,
+	BCM53115_DEVICE_ID = 0x53115,
+	BCM53125_DEVICE_ID = 0x53125,
+	BCM53128_DEVICE_ID = 0x53128,
+	BCM63XX_DEVICE_ID = 0x6300,
+	BCM53010_DEVICE_ID = 0x53010,
+	BCM53011_DEVICE_ID = 0x53011,
+	BCM53012_DEVICE_ID = 0x53012,
+	BCM53018_DEVICE_ID = 0x53018,
+	BCM53019_DEVICE_ID = 0x53019,
+};
+
+#define B53_N_PORTS	9
+#define B53_N_PORTS_25	6
+
+struct b53_vlan {
+	unsigned int	members:B53_N_PORTS;
+	unsigned int	untag:B53_N_PORTS;
+};
+
+struct b53_port {
+	struct b53_device *b53;
+	struct net_device *ndev;
+
+	unsigned int port_number;
+	unsigned int pvid:12;
+};
+
+struct b53_chip_data;
+
+struct b53_device {
+	/* registers access */
+	struct mutex reg_mutex;
+	const struct b53_io_ops *ops;
+
+	unsigned char dev_addr[ETH_ALEN];
+	int port_count;
+
+	/* chip specific data */
+	u32 chip_id;
+	u8 core_rev;
+	const struct b53_chip_data *chip;
+	u8 cpu_port;
+	u16 enabled_ports;
+	int reset_gpio;
+
+	/* connect specific data */
+	u8 current_page;
+	struct device *dev;
+	void *priv;
+
+	/* run time configuration */
+	unsigned enable_vlan:1;
+	unsigned enable_jumbo:1;
+	unsigned allow_vid_4095:1;
+
+	struct b53_port **ports;
+	struct b53_vlan *vlans;
+
+	char *buf;
+};
+
+#define b53_for_each_port(dev, i) \
+	for (i = 0; i < B53_N_PORTS; i++) \
+		if (dev->enabled_ports & BIT(i))
+
+static inline int is5325(struct b53_device *dev)
+{
+	return dev->chip_id == BCM5325_DEVICE_ID;
+}
+
+static inline int is5365(struct b53_device *dev)
+{
+#ifdef CONFIG_BCM47XX
+	return dev->chip_id == BCM5365_DEVICE_ID;
+#else
+	return 0;
+#endif
+}
+
+static inline int is5397_98(struct b53_device *dev)
+{
+	return dev->chip_id == BCM5397_DEVICE_ID ||
+	       dev->chip_id == BCM5398_DEVICE_ID;
+}
+
+static inline int is539x(struct b53_device *dev)
+{
+	return dev->chip_id == BCM5395_DEVICE_ID ||
+	       dev->chip_id == BCM5397_DEVICE_ID ||
+	       dev->chip_id == BCM5398_DEVICE_ID;
+}
+
+static inline int is531x5(struct b53_device *dev)
+{
+	return dev->chip_id == BCM53115_DEVICE_ID ||
+		dev->chip_id == BCM53125_DEVICE_ID ||
+		dev->chip_id == BCM53128_DEVICE_ID;
+}
+
+static inline int is63xx(struct b53_device *dev)
+{
+#ifdef CONFIG_BCM63XX
+	return dev->chip_id == BCM63XX_DEVICE_ID;
+#else
+	return 0;
+#endif
+}
+
+static inline int is5301x(struct b53_device *dev)
+{
+	return dev->chip_id == BCM53010_DEVICE_ID ||
+		dev->chip_id == BCM53011_DEVICE_ID ||
+		dev->chip_id == BCM53012_DEVICE_ID ||
+		dev->chip_id == BCM53018_DEVICE_ID ||
+		dev->chip_id == BCM53019_DEVICE_ID;
+}
+
+#define B53_CPU_PORT_25	5
+#define B53_CPU_PORT	8
+
+static inline int is_cpu_port(struct b53_device *dev, int port)
+{
+	return dev->cpu_port == port;
+}
+
+struct b53_device *b53_switch_alloc(struct device *base, struct b53_io_ops *ops,
+				    void *priv);
+
+int b53_switch_detect(struct b53_device *dev);
+
+int b53_switch_register(struct b53_device *dev);
+
+void b53_switch_exit(struct b53_device *b53);
+
+static inline int b53_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val)
+{
+	int ret;
+
+	mutex_lock(&dev->reg_mutex);
+	ret = dev->ops->read8(dev, page, reg, val);
+	mutex_unlock(&dev->reg_mutex);
+
+	return ret;
+}
+
+static inline int b53_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val)
+{
+	int ret;
+
+	mutex_lock(&dev->reg_mutex);
+	ret = dev->ops->read16(dev, page, reg, val);
+	mutex_unlock(&dev->reg_mutex);
+
+	return ret;
+}
+
+static inline int b53_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val)
+{
+	int ret;
+
+	mutex_lock(&dev->reg_mutex);
+	ret = dev->ops->read32(dev, page, reg, val);
+	mutex_unlock(&dev->reg_mutex);
+
+	return ret;
+}
+
+static inline int b53_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val)
+{
+	int ret;
+
+	mutex_lock(&dev->reg_mutex);
+	ret = dev->ops->read48(dev, page, reg, val);
+	mutex_unlock(&dev->reg_mutex);
+
+	return ret;
+}
+
+static inline int b53_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val)
+{
+	int ret;
+
+	mutex_lock(&dev->reg_mutex);
+	ret = dev->ops->read64(dev, page, reg, val);
+	mutex_unlock(&dev->reg_mutex);
+
+	return ret;
+}
+
+static inline int b53_write8(struct b53_device *dev, u8 page, u8 reg, u8 value)
+{
+	int ret;
+
+	mutex_lock(&dev->reg_mutex);
+	ret = dev->ops->write8(dev, page, reg, value);
+	mutex_unlock(&dev->reg_mutex);
+
+	return ret;
+}
+
+static inline int b53_write16(struct b53_device *dev, u8 page, u8 reg,
+			      u16 value)
+{
+	int ret;
+
+	mutex_lock(&dev->reg_mutex);
+	ret = dev->ops->write16(dev, page, reg, value);
+	mutex_unlock(&dev->reg_mutex);
+
+	return ret;
+}
+
+static inline int b53_write32(struct b53_device *dev, u8 page, u8 reg,
+			      u32 value)
+{
+	int ret;
+
+	mutex_lock(&dev->reg_mutex);
+	ret = dev->ops->write32(dev, page, reg, value);
+	mutex_unlock(&dev->reg_mutex);
+
+	return ret;
+}
+
+static inline int b53_write48(struct b53_device *dev, u8 page, u8 reg,
+			      u64 value)
+{
+	int ret;
+
+	mutex_lock(&dev->reg_mutex);
+	ret = dev->ops->write48(dev, page, reg, value);
+	mutex_unlock(&dev->reg_mutex);
+
+	return ret;
+}
+
+static inline int b53_write64(struct b53_device *dev, u8 page, u8 reg,
+			      u64 value)
+{
+	int ret;
+
+	mutex_lock(&dev->reg_mutex);
+	ret = dev->ops->write64(dev, page, reg, value);
+	mutex_unlock(&dev->reg_mutex);
+
+	return ret;
+}
+
+static inline int b53_switch_get_reset_gpio(struct b53_device *dev)
+{
+	return -ENOENT;
+}
+
+#endif
diff --git a/drivers/net/phy/b53/b53_regs.h b/drivers/net/phy/b53/b53_regs.h
new file mode 100644
index 0000000..ba50915
--- /dev/null
+++ b/drivers/net/phy/b53/b53_regs.h
@@ -0,0 +1,313 @@
+/*
+ * B53 register definitions
+ *
+ * Copyright (C) 2004 Broadcom Corporation
+ * Copyright (C) 2011-2013 Jonas Gorski <jogo@openwrt.org>
+ *
+ * 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.
+ */
+
+#ifndef __B53_REGS_H
+#define __B53_REGS_H
+
+/* Management Port (SMP) Page offsets */
+#define B53_CTRL_PAGE			0x00 /* Control */
+#define B53_STAT_PAGE			0x01 /* Status */
+#define B53_MGMT_PAGE			0x02 /* Management Mode */
+#define B53_MIB_AC_PAGE			0x03 /* MIB Autocast */
+#define B53_ARLCTRL_PAGE		0x04 /* ARL Control */
+#define B53_ARLIO_PAGE			0x05 /* ARL Access */
+#define B53_FRAMEBUF_PAGE		0x06 /* Management frame access */
+#define B53_MEM_ACCESS_PAGE		0x08 /* Memory access */
+
+/* PHY Registers */
+#define B53_PORT_MII_PAGE(i)		(0x10 + i) /* Port i MII Registers */
+#define B53_IM_PORT_PAGE		0x18 /* Inverse MII Port (to EMAC) */
+#define B53_ALL_PORT_PAGE		0x19 /* All ports MII (broadcast) */
+
+/* MIB registers */
+#define B53_MIB_PAGE(i)			(0x20 + i)
+
+/* Quality of Service (QoS) Registers */
+#define B53_QOS_PAGE			0x30
+
+/* Port VLAN Page */
+#define B53_PVLAN_PAGE			0x31
+
+/* VLAN Registers */
+#define B53_VLAN_PAGE			0x34
+
+/* Jumbo Frame Registers */
+#define B53_JUMBO_PAGE			0x40
+
+/*************************************************************************
+ * Control Page registers
+ *************************************************************************/
+
+/* Port Control Register (8 bit) */
+#define B53_PORT_CTRL(i)		(0x00 + i)
+#define   PORT_CTRL_RX_DISABLE		BIT(0)
+#define   PORT_CTRL_TX_DISABLE		BIT(1)
+#define   PORT_CTRL_RX_BCST_EN		BIT(2) /* Broadcast RX (P8 only) */
+#define   PORT_CTRL_RX_MCST_EN		BIT(3) /* Multicast RX (P8 only) */
+#define   PORT_CTRL_RX_UCST_EN		BIT(4) /* Unicast RX (P8 only) */
+#define	  PORT_CTRL_STP_STATE_S		5
+#define   PORT_CTRL_STP_STATE_MASK	(0x3 << PORT_CTRL_STP_STATE_S)
+
+/* SMP Control Register (8 bit) */
+#define B53_SMP_CTRL			0x0a
+
+/* Switch Mode Control Register (8 bit) */
+#define B53_SWITCH_MODE			0x0b
+#define   SM_SW_FWD_MODE		BIT(0)	/* 1 = Managed Mode */
+#define   SM_SW_FWD_EN			BIT(1)	/* Forwarding Enable */
+
+/* IMP Port state override register (8 bit) */
+#define B53_PORT_OVERRIDE_CTRL		0x0e
+#define   PORT_OVERRIDE_LINK		BIT(0)
+#define   PORT_OVERRIDE_HALF_DUPLEX	BIT(1) /* 0 = Full Duplex */
+#define   PORT_OVERRIDE_SPEED_S		2
+#define   PORT_OVERRIDE_SPEED_10M	(0 << PORT_OVERRIDE_SPEED_S)
+#define   PORT_OVERRIDE_SPEED_100M	(1 << PORT_OVERRIDE_SPEED_S)
+#define   PORT_OVERRIDE_SPEED_1000M	(2 << PORT_OVERRIDE_SPEED_S)
+#define   PORT_OVERRIDE_RV_MII_25	BIT(4) /* BCM5325 only */
+#define   PORT_OVERRIDE_RX_FLOW		BIT(4)
+#define   PORT_OVERRIDE_TX_FLOW		BIT(5)
+#define   PORT_OVERRIDE_EN		BIT(7) /* Use the register contents */
+
+/* Power-down mode control */
+#define B53_PD_MODE_CTRL_25		0x0f
+
+/* IP Multicast control (8 bit) */
+#define B53_IP_MULTICAST_CTRL		0x21
+#define  B53_IPMC_FWD_EN		BIT(1)
+#define  B53_UC_FWD_EN			BIT(6)
+#define  B53_MC_FWD_EN			BIT(7)
+
+/* (16 bit) */
+#define B53_UC_FLOOD_MASK		0x32
+#define B53_MC_FLOOD_MASK		0x34
+#define B53_IPMC_FLOOD_MASK		0x36
+
+/* Software reset register (8 bit) */
+#define B53_SOFTRESET			0x79
+
+/* Fast Aging Control register (8 bit) */
+#define B53_FAST_AGE_CTRL		0x88
+#define   FAST_AGE_STATIC		BIT(0)
+#define   FAST_AGE_DYNAMIC		BIT(1)
+#define   FAST_AGE_PORT			BIT(2)
+#define   FAST_AGE_VLAN			BIT(3)
+#define   FAST_AGE_STP			BIT(4)
+#define   FAST_AGE_MC			BIT(5)
+#define   FAST_AGE_DONE			BIT(7)
+
+/*************************************************************************
+ * Status Page registers
+ *************************************************************************/
+
+/* Link Status Summary Register (16bit) */
+#define B53_LINK_STAT			0x00
+
+/* Link Status Change Register (16 bit) */
+#define B53_LINK_STAT_CHANGE		0x02
+
+/* Port Speed Summary Register (16 bit for FE, 32 bit for GE) */
+#define B53_SPEED_STAT			0x04
+#define  SPEED_PORT_FE(reg, port)	(((reg) >> (port)) & 1)
+#define  SPEED_PORT_GE(reg, port)	(((reg) >> 2 * (port)) & 3)
+#define  SPEED_STAT_10M			0
+#define  SPEED_STAT_100M		1
+#define  SPEED_STAT_1000M		2
+
+/* Duplex Status Summary (16 bit) */
+#define B53_DUPLEX_STAT_FE		0x06
+#define B53_DUPLEX_STAT_GE		0x08
+#define B53_DUPLEX_STAT_63XX		0x0c
+
+/* Revision ID register for BCM5325 */
+#define B53_REV_ID_25			0x50
+
+/* Strap Value (48 bit) */
+#define B53_STRAP_VALUE			0x70
+#define   SV_GMII_CTRL_115		BIT(27)
+
+/*************************************************************************
+ * Management Mode Page Registers
+ *************************************************************************/
+
+/* Global Management Config Register (8 bit) */
+#define B53_GLOBAL_CONFIG		0x00
+#define   GC_RESET_MIB			0x01
+#define   GC_RX_BPDU_EN			0x02
+#define   GC_MIB_AC_HDR_EN		0x10
+#define   GC_MIB_AC_EN			0x20
+#define   GC_FRM_MGMT_PORT_M		0xC0
+#define   GC_FRM_MGMT_PORT_04		0x00
+#define   GC_FRM_MGMT_PORT_MII		0x80
+
+/* Device ID register (8 or 32 bit) */
+#define B53_DEVICE_ID			0x30
+
+/* Revision ID register (8 bit) */
+#define B53_REV_ID			0x40
+
+/*************************************************************************
+ * ARL Access Page Registers
+ *************************************************************************/
+
+/* VLAN Table Access Register (8 bit) */
+#define B53_VT_ACCESS			0x80
+#define B53_VT_ACCESS_9798		0x60 /* for BCM5397/BCM5398 */
+#define B53_VT_ACCESS_63XX		0x60 /* for BCM6328/62/68 */
+#define   VTA_CMD_WRITE			0
+#define   VTA_CMD_READ			1
+#define   VTA_CMD_CLEAR			2
+#define   VTA_START_CMD			BIT(7)
+
+/* VLAN Table Index Register (16 bit) */
+#define B53_VT_INDEX			0x81
+#define B53_VT_INDEX_9798		0x61
+#define B53_VT_INDEX_63XX		0x62
+
+/* VLAN Table Entry Register (32 bit) */
+#define B53_VT_ENTRY			0x83
+#define B53_VT_ENTRY_9798		0x63
+#define B53_VT_ENTRY_63XX		0x64
+#define   VTE_MEMBERS			0x1ff
+#define   VTE_UNTAG_S			9
+#define   VTE_UNTAG			(0x1ff << 9)
+
+/*************************************************************************
+ * Port VLAN Registers
+ *************************************************************************/
+
+/* Port VLAN mask (16 bit) IMP port is always 8, also on 5325 & co */
+#define B53_PVLAN_PORT_MASK(i)		((i) * 2)
+
+/*************************************************************************
+ * 802.1Q Page Registers
+ *************************************************************************/
+
+/* Global QoS Control (8 bit) */
+#define B53_QOS_GLOBAL_CTL		0x00
+
+/* Enable 802.1Q for individual Ports (16 bit) */
+#define B53_802_1P_EN			0x04
+
+/*************************************************************************
+ * VLAN Page Registers
+ *************************************************************************/
+
+/* VLAN Control 0 (8 bit) */
+#define B53_VLAN_CTRL0			0x00
+#define   VC0_8021PF_CTRL_MASK		0x3
+#define   VC0_8021PF_CTRL_NONE		0x0
+#define   VC0_8021PF_CTRL_CHANGE_PRI	0x1
+#define   VC0_8021PF_CTRL_CHANGE_VID	0x2
+#define   VC0_8021PF_CTRL_CHANGE_BOTH	0x3
+#define   VC0_8021QF_CTRL_MASK		0xc
+#define   VC0_8021QF_CTRL_CHANGE_PRI	0x1
+#define   VC0_8021QF_CTRL_CHANGE_VID	0x2
+#define   VC0_8021QF_CTRL_CHANGE_BOTH	0x3
+#define   VC0_RESERVED_1		BIT(1)
+#define   VC0_DROP_VID_MISS		BIT(4)
+#define   VC0_VID_HASH_VID		BIT(5)
+#define   VC0_VID_CHK_EN		BIT(6)	/* Use VID,DA or VID,SA */
+#define   VC0_VLAN_EN			BIT(7)	/* 802.1Q VLAN Enabled */
+
+/* VLAN Control 1 (8 bit) */
+#define B53_VLAN_CTRL1			0x01
+#define   VC1_RX_MCST_TAG_EN		BIT(1)
+#define   VC1_RX_MCST_FWD_EN		BIT(2)
+#define   VC1_RX_MCST_UNTAG_EN		BIT(3)
+
+/* VLAN Control 2 (8 bit) */
+#define B53_VLAN_CTRL2			0x02
+
+/* VLAN Control 3 (8 bit when BCM5325, 16 bit else) */
+#define B53_VLAN_CTRL3			0x03
+#define B53_VLAN_CTRL3_63XX		0x04
+#define   VC3_MAXSIZE_1532		BIT(6) /* 5325 only */
+#define   VC3_HIGH_8BIT_EN		BIT(7) /* 5325 only */
+
+/* VLAN Control 4 (8 bit) */
+#define B53_VLAN_CTRL4			0x05
+#define B53_VLAN_CTRL4_25		0x04
+#define B53_VLAN_CTRL4_63XX		0x06
+#define   VC4_ING_VID_CHECK_S		6
+#define   VC4_ING_VID_CHECK_MASK	(0x3 << VC4_ING_VID_CHECK_S)
+#define   VC4_ING_VID_VIO_FWD		0 /* forward, but do not learn */
+#define   VC4_ING_VID_VIO_DROP		1 /* drop VID violations */
+#define   VC4_NO_ING_VID_CHK		2 /* do not check */
+#define   VC4_ING_VID_VIO_TO_IMP	3 /* redirect to MII port */
+
+/* VLAN Control 5 (8 bit) */
+#define B53_VLAN_CTRL5			0x06
+#define B53_VLAN_CTRL5_25		0x05
+#define B53_VLAN_CTRL5_63XX		0x07
+#define   VC5_VID_FFF_EN		BIT(2)
+#define   VC5_DROP_VTABLE_MISS		BIT(3)
+
+/* VLAN Control 6 (8 bit) */
+#define B53_VLAN_CTRL6			0x07
+#define B53_VLAN_CTRL6_63XX		0x08
+
+/* VLAN Table Access Register (16 bit) */
+#define B53_VLAN_TABLE_ACCESS_25	0x06	/* BCM5325E/5350 */
+#define B53_VLAN_TABLE_ACCESS_65	0x08	/* BCM5365 */
+#define   VTA_VID_LOW_MASK_25		0xf
+#define   VTA_VID_LOW_MASK_65		0xff
+#define   VTA_VID_HIGH_S_25		4
+#define   VTA_VID_HIGH_S_65		8
+#define   VTA_VID_HIGH_MASK_25		(0xff << VTA_VID_HIGH_S_25E)
+#define   VTA_VID_HIGH_MASK_65		(0xf << VTA_VID_HIGH_S_65)
+#define   VTA_RW_STATE			BIT(12)
+#define   VTA_RW_STATE_RD		0
+#define   VTA_RW_STATE_WR		BIT(12)
+#define   VTA_RW_OP_EN			BIT(13)
+
+/* VLAN Read/Write Registers for (16/32 bit) */
+#define B53_VLAN_WRITE_25		0x08
+#define B53_VLAN_WRITE_65		0x0a
+#define B53_VLAN_READ			0x0c
+#define   VA_MEMBER_MASK		0x3f
+#define   VA_UNTAG_S_25			6
+#define   VA_UNTAG_MASK_25		0x3f
+#define   VA_UNTAG_S_65			7
+#define   VA_UNTAG_MASK_65		0x1f
+#define   VA_VID_HIGH_S			12
+#define   VA_VID_HIGH_MASK		(0xffff << VA_VID_HIGH_S)
+#define   VA_VALID_25			BIT(20)
+#define   VA_VALID_25_R4		BIT(24)
+#define   VA_VALID_65			BIT(14)
+
+/* VLAN Port Default Tag (16 bit) */
+#define B53_VLAN_PORT_DEF_TAG(i)	(0x10 + 2 * (i))
+
+/*************************************************************************
+ * Jumbo Frame Page Registers
+ *************************************************************************/
+
+/* Jumbo Enable Port Mask (bit i == port i enabled) (32 bit) */
+#define B53_JUMBO_PORT_MASK		0x01
+#define B53_JUMBO_PORT_MASK_63XX	0x04
+#define   JPM_10_100_JUMBO_EN		BIT(24) /* GigE always enabled */
+
+/* Good Frame Max Size without 802.1Q TAG (16 bit) */
+#define B53_JUMBO_MAX_SIZE		0x05
+#define B53_JUMBO_MAX_SIZE_63XX		0x08
+#define   JMS_MIN_SIZE			1518
+#define   JMS_MAX_SIZE			9724
+
+#endif /* !__B53_REGS_H */
-- 
1.8.4.5

^ permalink raw reply related	[flat|nested] 42+ messages in thread

* Re: [PATCH] net: phy: b53: switchdev driver for Broadcom BCM53xx switches
  2015-02-24 17:42 [PATCH] net: phy: b53: switchdev driver for Broadcom BCM53xx switches Rafał Miłecki
@ 2015-02-24 17:47 ` Rafał Miłecki
  2015-02-24 21:51 ` Andrew Lunn
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 42+ messages in thread
From: Rafał Miłecki @ 2015-02-24 17:47 UTC (permalink / raw)
  To: David S. Miller, Network Development
  Cc: Jonas Gorski, Florian Fainelli, Hauke Mehrtens, Felix Fietkau,
	Jiri Pirko, Rafał Miłecki

On 24 February 2015 at 18:42, Rafał Miłecki <zajec5@gmail.com> wrote:
> diff --git a/drivers/net/phy/b53/Kconfig b/drivers/net/phy/b53/Kconfig
> new file mode 100644
> index 0000000..21bf6e7
> --- /dev/null
> +++ b/drivers/net/phy/b53/Kconfig
> @@ -0,0 +1,12 @@
> +menuconfig B53
> +       tristate "Broadcom bcm53xx managed switch support"
> +       help
> +         This driver adds support for Broadcom managed switch chips. It supports
> +         BCM5325E, BCM5365, BCM539x, BCM53115 and BCM53125 as well as BCM63XX
> +         integrated switches.

- You forgot depends NET_SWITCHDEV
- I see, thanks, will do in V2

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH] net: phy: b53: switchdev driver for Broadcom BCM53xx switches
  2015-02-24 17:42 [PATCH] net: phy: b53: switchdev driver for Broadcom BCM53xx switches Rafał Miłecki
  2015-02-24 17:47 ` Rafał Miłecki
@ 2015-02-24 21:51 ` Andrew Lunn
  2015-02-24 22:29   ` Rafał Miłecki
  2015-02-24 22:30 ` Andy Gospodarek
  2015-02-24 22:48 ` Florian Fainelli
  3 siblings, 1 reply; 42+ messages in thread
From: Andrew Lunn @ 2015-02-24 21:51 UTC (permalink / raw)
  To: Rafa?? Mi??ecki
  Cc: David S. Miller, netdev, Jonas Gorski, Florian Fainelli,
	Hauke Mehrtens, Felix Fietkau, Jiri Pirko

On Tue, Feb 24, 2015 at 06:42:07PM +0100, Rafa?? Mi??ecki wrote:
> BCM53xx is series of Broadcom Ethernet switches that can be found in
> various (mostly home) routers.
> They are quite simple switches with mainly just support for:
> 1) Tagging incoming packets (PVID)
> 2) Untagging outgoing packets
> 3) Forwarding all packets across a single VLAN
> 
> This driver is split into common code (module) and bus specific code.
> Right now only PHY (MDIO) support is included, other could follow after
> accepting this driver. It was successfully tested on BCM4706 SoC with
> BCM53125.
> 
> You could notice it's yet another try of submitting b53 driver. This
> time it was modified to use recently introduced switchdev API which
> hopefully make it possible to accept it mainline.
> 
> Signed-off-by: Rafa?? Mi??ecki <zajec5@gmail.com>
> ---
> Example usage. My BCM4706 router has switch with 6 ports:
> 0: WAN port
> 1-4: LAN ports
> 8: CPU connected port (on-SoC Ethernet device)
> 
> I decided to use VLAN 1 for WAN and VLAN 2 for LAN. I was able to
> successfully configure it using:
> 
> bridge vlan add vid 1 dev sw0p1 pvid untagged
> bridge vlan add vid 1 dev sw0p2 pvid untagged
> bridge vlan add vid 1 dev sw0p3 pvid untagged
> bridge vlan add vid 1 dev sw0p4 pvid untagged
> bridge vlan add vid 1 dev sw0p8
> 
> bridge vlan add vid 2 dev sw0p0 pvid untagged
> bridge vlan add vid 2 dev sw0p8
> ---
>  drivers/net/phy/Kconfig          |   2 +
>  drivers/net/phy/Makefile         |   1 +
>  drivers/net/phy/b53/Kconfig      |  12 +
>  drivers/net/phy/b53/Makefile     |   2 +
>  drivers/net/phy/b53/b53_common.c | 961 +++++++++++++++++++++++++++++++++++++++
>  drivers/net/phy/b53/b53_mdio.c   | 418 +++++++++++++++++
>  drivers/net/phy/b53/b53_priv.h   | 299 ++++++++++++
>  drivers/net/phy/b53/b53_regs.h   | 313 +++++++++++++

Hi Rafa??

I have a question about the location. Why drivers/net/phy?

  Andrew

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH] net: phy: b53: switchdev driver for Broadcom BCM53xx switches
  2015-02-24 21:51 ` Andrew Lunn
@ 2015-02-24 22:29   ` Rafał Miłecki
  2015-02-25  0:51     ` Andrew Lunn
  0 siblings, 1 reply; 42+ messages in thread
From: Rafał Miłecki @ 2015-02-24 22:29 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: David S. Miller, Network Development, Jonas Gorski,
	Florian Fainelli, Hauke Mehrtens, Felix Fietkau, Jiri Pirko

On 24 February 2015 at 22:51, Andrew Lunn <andrew@lunn.ch> wrote:
> On Tue, Feb 24, 2015 at 06:42:07PM +0100, Rafa?? Mi??ecki wrote:
>> BCM53xx is series of Broadcom Ethernet switches that can be found in
>> various (mostly home) routers.
>> They are quite simple switches with mainly just support for:
>> 1) Tagging incoming packets (PVID)
>> 2) Untagging outgoing packets
>> 3) Forwarding all packets across a single VLAN
>>
>> This driver is split into common code (module) and bus specific code.
>> Right now only PHY (MDIO) support is included, other could follow after
>> accepting this driver. It was successfully tested on BCM4706 SoC with
>> BCM53125.
>>
>> You could notice it's yet another try of submitting b53 driver. This
>> time it was modified to use recently introduced switchdev API which
>> hopefully make it possible to accept it mainline.
>>
>> Signed-off-by: Rafa?? Mi??ecki <zajec5@gmail.com>
>> ---
>> Example usage. My BCM4706 router has switch with 6 ports:
>> 0: WAN port
>> 1-4: LAN ports
>> 8: CPU connected port (on-SoC Ethernet device)
>>
>> I decided to use VLAN 1 for WAN and VLAN 2 for LAN. I was able to
>> successfully configure it using:
>>
>> bridge vlan add vid 1 dev sw0p1 pvid untagged
>> bridge vlan add vid 1 dev sw0p2 pvid untagged
>> bridge vlan add vid 1 dev sw0p3 pvid untagged
>> bridge vlan add vid 1 dev sw0p4 pvid untagged
>> bridge vlan add vid 1 dev sw0p8
>>
>> bridge vlan add vid 2 dev sw0p0 pvid untagged
>> bridge vlan add vid 2 dev sw0p8
>> ---
>>  drivers/net/phy/Kconfig          |   2 +
>>  drivers/net/phy/Makefile         |   1 +
>>  drivers/net/phy/b53/Kconfig      |  12 +
>>  drivers/net/phy/b53/Makefile     |   2 +
>>  drivers/net/phy/b53/b53_common.c | 961 +++++++++++++++++++++++++++++++++++++++
>>  drivers/net/phy/b53/b53_mdio.c   | 418 +++++++++++++++++
>>  drivers/net/phy/b53/b53_priv.h   | 299 ++++++++++++
>>  drivers/net/phy/b53/b53_regs.h   | 313 +++++++++++++
>
> Hi Rafa??
>
> I have a question about the location. Why drivers/net/phy?

It wasn't really my idea, all out-of-tree switch drivers
developed/used in OpenWrt are placed in drivers/net/phy/. My guess is
that it's because many of them register themselves as PHY drivers
(phy_driver_register, or module_phy_driver helper). AFAIK all mainline
PHY drivers all located in this directory. It's the same about
b53_mdio.c - we call phy_driver_register [0] for 3 different phy_id-s.

Now, there may be some exceptions, indeed. For example some devices
with BCM53xx switches use memory mapped registers instead of
MII-accessible registers. This means that after adding support for
such devices we'll get also some platform driver in
drivers/net/phy/b53/ (most likely b53_mmap.c). I'm not sure how much
acceptable it is. It seems we already have some non-PHY drivers in
drivers/net/phy/ like spi_ks8995.c. So maybe it's also acceptable to
have there some platform drivers?

That said, I'm not aware of any better place for switchdev drivers.
Unless we create some new directory like drivers/net/switch/ or
similar. But won't that somehow duplicate drivers/net/phy/ then?

[0] Actually it seems we should simply use module_phy_driver in
b53_mdio.c, I'll do this in V2!

-- 
Rafał

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH] net: phy: b53: switchdev driver for Broadcom BCM53xx switches
  2015-02-24 17:42 [PATCH] net: phy: b53: switchdev driver for Broadcom BCM53xx switches Rafał Miłecki
  2015-02-24 17:47 ` Rafał Miłecki
  2015-02-24 21:51 ` Andrew Lunn
@ 2015-02-24 22:30 ` Andy Gospodarek
  2015-02-24 22:50   ` Rafał Miłecki
  2015-02-24 22:48 ` Florian Fainelli
  3 siblings, 1 reply; 42+ messages in thread
From: Andy Gospodarek @ 2015-02-24 22:30 UTC (permalink / raw)
  To: Rafał Miłecki
  Cc: David S. Miller, netdev, Jonas Gorski, Florian Fainelli,
	Hauke Mehrtens, Felix Fietkau, Jiri Pirko

On Tue, Feb 24, 2015 at 06:42:07PM +0100, Rafał Miłecki wrote:
> BCM53xx is series of Broadcom Ethernet switches that can be found in
> various (mostly home) routers.
> They are quite simple switches with mainly just support for:
> 1) Tagging incoming packets (PVID)
> 2) Untagging outgoing packets
> 3) Forwarding all packets across a single VLAN
> 
> This driver is split into common code (module) and bus specific code.
> Right now only PHY (MDIO) support is included, other could follow after
> accepting this driver. It was successfully tested on BCM4706 SoC with
> BCM53125.
> 
> You could notice it's yet another try of submitting b53 driver. This
> time it was modified to use recently introduced switchdev API which
> hopefully make it possible to accept it mainline.

I must confess I do not know the entire history of this driver, but I
have a few comments....

> 
> Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
> ---
> Example usage. My BCM4706 router has switch with 6 ports:
> 0: WAN port
> 1-4: LAN ports
> 8: CPU connected port (on-SoC Ethernet device)

[...]
> diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
> index 501ea76..3e8b3b7 100644
> --- a/drivers/net/phy/Makefile
> +++ b/drivers/net/phy/Makefile
> @@ -10,6 +10,7 @@ obj-$(CONFIG_LXT_PHY)		+= lxt.o
>  obj-$(CONFIG_QSEMI_PHY)		+= qsemi.o
>  obj-$(CONFIG_SMSC_PHY)		+= smsc.o
>  obj-$(CONFIG_VITESSE_PHY)	+= vitesse.o
> +obj-$(CONFIG_B53)		+= b53/
Should this be in a different spot than drivers/net/phy?

(Also pointed out by Andrew Lunn and just answered, so I'll read that
response.)

> diff --git a/drivers/net/phy/b53/b53_common.c b/drivers/net/phy/b53/b53_common.c
> new file mode 100644
> index 0000000..fce6b71
> --- /dev/null
> +++ b/drivers/net/phy/b53/b53_common.c
[...]
> +
> +/*****************
> + * Net device ops
> + *****************/
> +
> +static netdev_tx_t b53_port_xmit(struct sk_buff *skb, struct net_device *dev)
> +{
> +	dev_kfree_skb(skb);
> +	dev->stats.tx_dropped++;
> +
> +	return NETDEV_TX_OK;
> +}
> +
> +static int b53_port_vlan_rx_add_vid(struct net_device *dev,
> +				    __be16 proto, u16 vid)
> +{
> +	struct b53_port *b53_port = netdev_priv(dev);
> +	struct b53_device *b53 = b53_port->b53;
> +	struct b53_vlan *vlan;
> +
> +	if (vid >= b53->chip->vlans)
> +		return -EINVAL;
> +
> +	/* only BCM5325 and BCM5365 supports VID 0 */
> +	if (vid == 0 && !is5325(b53) && !is5365(b53))
> +		return -EINVAL;
> +
> +	/* VLAN 4095 needs special handling */
> +	if (vid == 4095)
> +		return -EINVAL;
> +
> +	vlan = &b53->vlans[vid];
> +
> +	vlan->members |= BIT(b53_port->port_number);
> +
> +	/* ignore disabled ports */
> +	vlan->members &= b53->enabled_ports;
> +
> +	b53_apply(b53);
> +
> +	return 0;
> +}
> +
> +static int b53_port_vlan_rx_kill_vid(struct net_device *dev,
> +				     __be16 proto, u16 vid)
> +{
> +	struct b53_port *b53_port = netdev_priv(dev);
> +	struct b53_device *b53 = b53_port->b53;
> +	struct b53_vlan *vlan;
> +
> +	if (vid >= b53->chip->vlans)
> +		return -EINVAL;
> +
> +	vlan = &b53->vlans[vid];
> +
> +	vlan->members &= ~BIT(b53_port->port_number);
> +
> +	b53_apply(b53);
> +
> +	return 0;
> +}
> +
> +static int b53_port_switch_parent_id_get(struct net_device *dev,
> +					 struct netdev_phys_item_id *psid)
> +{
> +	struct b53_port *b53_port = netdev_priv(dev);
> +
> +	memcpy(psid->id, b53_port->b53->dev_addr, ETH_ALEN);
> +	psid->id_len = ETH_ALEN;
> +
> +	return 0;
> +}
> +
> +static int b53_port_bridge_setlink(struct net_device *dev,
> +				   struct nlmsghdr *nlh, u16 flags)
> +{
> +	struct b53_port *b53_port = netdev_priv(dev);
> +	struct b53_device *b53 = b53_port->b53;
> +	struct b53_vlan *vlan;
> +	struct nlattr *afspec;
> +	struct nlattr *attr;
> +	struct bridge_vlan_info *vinfo;
> +	int rem;
> +
> +	afspec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC);
> +	if (!afspec)
> +		return -EINVAL;
> +
> +	nla_for_each_nested(attr, afspec, rem) {
> +		if (nla_type(attr) != IFLA_BRIDGE_VLAN_INFO)
> +			continue;
> +		if (nla_len(attr) != sizeof(struct bridge_vlan_info))
> +			return -EINVAL;
> +		vinfo = nla_data(attr);
> +	}
> +	if (!vinfo)
> +		return -EINVAL;
> +
> +	if (vinfo->flags & BRIDGE_VLAN_INFO_PVID)
> +		b53_port->pvid = vinfo->vid;
> +	else
> +		b53_port->pvid = 0;
> +
> +	vlan = &b53->vlans[vinfo->vid];
> +	if (vinfo->flags & BRIDGE_VLAN_INFO_UNTAGGED)
> +		vlan->untag |= BIT(b53_port->port_number);
> +	else
> +		vlan->untag &= ~BIT(b53_port->port_number);
> +
> +	b53_apply(b53);
> +
> +	return 0;
> +}
> +
> +static const struct net_device_ops b53_port_netdev_ops = {
> +	.ndo_start_xmit			= b53_port_xmit,
> +	.ndo_vlan_rx_add_vid		= b53_port_vlan_rx_add_vid,
> +	.ndo_vlan_rx_kill_vid		= b53_port_vlan_rx_kill_vid,
> +	.ndo_switch_parent_id_get	= b53_port_switch_parent_id_get,
> +	.ndo_bridge_setlink		= b53_port_bridge_setlink,
> +};

I see there is an xmit function, but no napi registration at all.

Is this simply because the SoC ethernet dev is doing all the frame rx?
Is is able to demux the frames correctly, so it is clear which swXpY
received the frame?  That will be necessary to ensure that standard
applications that want to open sockets directly on the needed interfaces
can still function properly.

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH] net: phy: b53: switchdev driver for Broadcom BCM53xx switches
  2015-02-24 17:42 [PATCH] net: phy: b53: switchdev driver for Broadcom BCM53xx switches Rafał Miłecki
                   ` (2 preceding siblings ...)
  2015-02-24 22:30 ` Andy Gospodarek
@ 2015-02-24 22:48 ` Florian Fainelli
  2015-02-24 22:56   ` Rafał Miłecki
  2015-02-25  2:10   ` David Miller
  3 siblings, 2 replies; 42+ messages in thread
From: Florian Fainelli @ 2015-02-24 22:48 UTC (permalink / raw)
  To: Rafał Miłecki, David S. Miller, netdev
  Cc: Jonas Gorski, Hauke Mehrtens, Felix Fietkau, Jiri Pirko

On 24/02/15 09:42, Rafał Miłecki wrote:
> BCM53xx is series of Broadcom Ethernet switches that can be found in
> various (mostly home) routers.
> They are quite simple switches with mainly just support for:
> 1) Tagging incoming packets (PVID)
> 2) Untagging outgoing packets
> 3) Forwarding all packets across a single VLAN
> 
> This driver is split into common code (module) and bus specific code.
> Right now only PHY (MDIO) support is included, other could follow after
> accepting this driver. It was successfully tested on BCM4706 SoC with
> BCM53125.
> 
> You could notice it's yet another try of submitting b53 driver. This
> time it was modified to use recently introduced switchdev API which
> hopefully make it possible to accept it mainline.

This is good as a very basic driver, there is still a bunch of things
missing that might not be too hard to add to this submission:

- fetching MIB counters through ethtool
- reporting link state/parameters
- changing MTU/Jumbo frame support
- HW bridging support

> 
> Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
> ---
> Example usage. My BCM4706 router has switch with 6 ports:
> 0: WAN port
> 1-4: LAN ports
> 8: CPU connected port (on-SoC Ethernet device)
> 
> I decided to use VLAN 1 for WAN and VLAN 2 for LAN. I was able to
> successfully configure it using:
> 
> bridge vlan add vid 1 dev sw0p1 pvid untagged
> bridge vlan add vid 1 dev sw0p2 pvid untagged
> bridge vlan add vid 1 dev sw0p3 pvid untagged
> bridge vlan add vid 1 dev sw0p4 pvid untagged
> bridge vlan add vid 1 dev sw0p8
> 
> bridge vlan add vid 2 dev sw0p0 pvid untagged
> bridge vlan add vid 2 dev sw0p8
> ---
>  drivers/net/phy/Kconfig          |   2 +
>  drivers/net/phy/Makefile         |   1 +
>  drivers/net/phy/b53/Kconfig      |  12 +
>  drivers/net/phy/b53/Makefile     |   2 +
>  drivers/net/phy/b53/b53_common.c | 961 +++++++++++++++++++++++++++++++++++++++
>  drivers/net/phy/b53/b53_mdio.c   | 418 +++++++++++++++++
>  drivers/net/phy/b53/b53_priv.h   | 299 ++++++++++++
>  drivers/net/phy/b53/b53_regs.h   | 313 +++++++++++++
>  8 files changed, 2008 insertions(+)
>  create mode 100644 drivers/net/phy/b53/Kconfig
>  create mode 100644 drivers/net/phy/b53/Makefile
>  create mode 100644 drivers/net/phy/b53/b53_common.c
>  create mode 100644 drivers/net/phy/b53/b53_mdio.c
>  create mode 100644 drivers/net/phy/b53/b53_priv.h
>  create mode 100644 drivers/net/phy/b53/b53_regs.h
> 
> diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
> index 16adbc4..fc8554a 100644
> --- a/drivers/net/phy/Kconfig
> +++ b/drivers/net/phy/Kconfig
> @@ -212,6 +212,8 @@ config MDIO_BCM_UNIMAC
>  	  controllers as well as some Broadcom Ethernet switches such as the
>  	  Starfighter 2 switches.
>  
> +source "drivers/net/phy/b53/Kconfig"
> +
>  endif # PHYLIB
>  
>  config MICREL_KS8995MA
> diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
> index 501ea76..3e8b3b7 100644
> --- a/drivers/net/phy/Makefile
> +++ b/drivers/net/phy/Makefile
> @@ -10,6 +10,7 @@ obj-$(CONFIG_LXT_PHY)		+= lxt.o
>  obj-$(CONFIG_QSEMI_PHY)		+= qsemi.o
>  obj-$(CONFIG_SMSC_PHY)		+= smsc.o
>  obj-$(CONFIG_VITESSE_PHY)	+= vitesse.o
> +obj-$(CONFIG_B53)		+= b53/
>  obj-$(CONFIG_BROADCOM_PHY)	+= broadcom.o
>  obj-$(CONFIG_BCM63XX_PHY)	+= bcm63xx.o
>  obj-$(CONFIG_BCM7XXX_PHY)	+= bcm7xxx.o
> diff --git a/drivers/net/phy/b53/Kconfig b/drivers/net/phy/b53/Kconfig
> new file mode 100644
> index 0000000..21bf6e7
> --- /dev/null
> +++ b/drivers/net/phy/b53/Kconfig
> @@ -0,0 +1,12 @@
> +menuconfig B53
> +	tristate "Broadcom bcm53xx managed switch support"
> +	help
> +	  This driver adds support for Broadcom managed switch chips. It supports
> +	  BCM5325E, BCM5365, BCM539x, BCM53115 and BCM53125 as well as BCM63XX
> +	  integrated switches.
> +
> +config B53_PHY_DRIVER
> +	tristate "B53 MDIO connected switch driver"
> +	depends on B53
> +	help
> +	  Select to enable support for registering switches configured through MDIO.
> diff --git a/drivers/net/phy/b53/Makefile b/drivers/net/phy/b53/Makefile
> new file mode 100644
> index 0000000..33d995b
> --- /dev/null
> +++ b/drivers/net/phy/b53/Makefile
> @@ -0,0 +1,2 @@
> +obj-$(CONFIG_B53)		+= b53_common.o
> +obj-$(CONFIG_B53_PHY_DRIVER)	+= b53_mdio.o
> diff --git a/drivers/net/phy/b53/b53_common.c b/drivers/net/phy/b53/b53_common.c
> new file mode 100644
> index 0000000..fce6b71
> --- /dev/null
> +++ b/drivers/net/phy/b53/b53_common.c
> @@ -0,0 +1,961 @@
> +/*
> + * B53 switch driver main logic
> + *
> + * Copyright (C) 2011-2013 Jonas Gorski <jogo@openwrt.org>
> + *
> + * 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.
> + */
> +
> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> +
> +#include <linux/slab.h>
> +
> +#include <linux/delay.h>
> +#include <linux/device.h>
> +#include <linux/etherdevice.h>
> +#include <linux/export.h>
> +#include <linux/gpio.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <net/netlink.h>
> +#include <uapi/linux/if_bridge.h>
> +#include <uapi/linux/rtnetlink.h>
> +
> +#include "b53_regs.h"
> +#include "b53_priv.h"
> +
> +struct b53_chip_data {
> +	u32 chip_id;
> +	const char *dev_name;
> +	const char *alias;
> +	u16 vlans;
> +	u16 enabled_ports;
> +	u8 cpu_port;
> +	u8 vta_regs[3];
> +	u8 duplex_reg;
> +	u8 jumbo_pm_reg;
> +	u8 jumbo_size_reg;
> +};
> +
> +static int b53_do_vlan_op(struct b53_device *dev, u8 op)
> +{
> +	unsigned int i;
> +
> +	b53_write8(dev, B53_ARLIO_PAGE, dev->chip->vta_regs[0],
> +		   VTA_START_CMD | op);
> +
> +	for (i = 0; i < 10; i++) {
> +		u8 vta;
> +
> +		b53_read8(dev, B53_ARLIO_PAGE, dev->chip->vta_regs[0], &vta);
> +		if (!(vta & VTA_START_CMD))
> +			return 0;
> +
> +		usleep_range(100, 200);
> +	}
> +
> +	return -EIO;
> +}
> +
> +static void b53_set_vlan_entry(struct b53_device *dev, u16 vid, u16 members,
> +			       u16 untag)
> +{
> +	if (is5325(dev)) {
> +		u32 entry = 0;
> +
> +		if (members) {
> +			entry = ((untag & VA_UNTAG_MASK_25) << VA_UNTAG_S_25) |
> +				members;
> +			if (dev->core_rev >= 3)
> +				entry |= VA_VALID_25_R4 | vid << VA_VID_HIGH_S;
> +			else
> +				entry |= VA_VALID_25;
> +		}
> +
> +		b53_write32(dev, B53_VLAN_PAGE, B53_VLAN_WRITE_25, entry);
> +		b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_TABLE_ACCESS_25, vid |
> +			    VTA_RW_STATE_WR | VTA_RW_OP_EN);
> +	} else if (is5365(dev)) {
> +		u16 entry = 0;
> +
> +		if (members)
> +			entry = ((untag & VA_UNTAG_MASK_65) << VA_UNTAG_S_65) |
> +				members | VA_VALID_65;
> +
> +		b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_WRITE_65, entry);
> +		b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_TABLE_ACCESS_65, vid |
> +			    VTA_RW_STATE_WR | VTA_RW_OP_EN);
> +	} else {
> +		b53_write16(dev, B53_ARLIO_PAGE, dev->chip->vta_regs[1], vid);
> +		b53_write32(dev, B53_ARLIO_PAGE, dev->chip->vta_regs[2],
> +			    (untag << VTE_UNTAG_S) | members);
> +
> +		b53_do_vlan_op(dev, VTA_CMD_WRITE);
> +	}
> +}
> +
> +void b53_set_forwarding(struct b53_device *dev, int enable)
> +{
> +	u8 mgmt;
> +
> +	b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt);
> +
> +	if (enable)
> +		mgmt |= SM_SW_FWD_EN;
> +	else
> +		mgmt &= ~SM_SW_FWD_EN;
> +
> +	b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, mgmt);
> +}
> +
> +static void b53_enable_vlan(struct b53_device *dev, int enable)
> +{
> +	u8 mgmt, vc0, vc1, vc4 = 0, vc5;
> +
> +	b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt);
> +	b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL0, &vc0);
> +	b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL1, &vc1);
> +
> +	if (is5325(dev) || is5365(dev)) {
> +		b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_25, &vc4);
> +		b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5_25, &vc5);
> +	} else if (is63xx(dev)) {
> +		b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_63XX, &vc4);
> +		b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5_63XX, &vc5);
> +	} else {
> +		b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4, &vc4);
> +		b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5, &vc5);
> +	}
> +
> +	mgmt &= ~SM_SW_FWD_MODE;
> +
> +	if (enable) {
> +		vc0 |= VC0_VLAN_EN | VC0_VID_CHK_EN | VC0_VID_HASH_VID;
> +		vc1 |= VC1_RX_MCST_UNTAG_EN | VC1_RX_MCST_FWD_EN;
> +		vc4 &= ~VC4_ING_VID_CHECK_MASK;
> +		vc4 |= VC4_ING_VID_VIO_DROP << VC4_ING_VID_CHECK_S;
> +		vc5 |= VC5_DROP_VTABLE_MISS;
> +
> +		if (is5325(dev))
> +			vc0 &= ~VC0_RESERVED_1;
> +
> +		if (is5325(dev) || is5365(dev))
> +			vc1 |= VC1_RX_MCST_TAG_EN;
> +
> +		if (!is5325(dev) && !is5365(dev)) {
> +			if (dev->allow_vid_4095)
> +				vc5 |= VC5_VID_FFF_EN;
> +			else
> +				vc5 &= ~VC5_VID_FFF_EN;
> +		}
> +	} else {
> +		vc0 &= ~(VC0_VLAN_EN | VC0_VID_CHK_EN | VC0_VID_HASH_VID);
> +		vc1 &= ~(VC1_RX_MCST_UNTAG_EN | VC1_RX_MCST_FWD_EN);
> +		vc4 &= ~VC4_ING_VID_CHECK_MASK;
> +		vc5 &= ~VC5_DROP_VTABLE_MISS;
> +
> +		if (is5325(dev) || is5365(dev))
> +			vc4 |= VC4_ING_VID_VIO_FWD << VC4_ING_VID_CHECK_S;
> +		else
> +			vc4 |= VC4_ING_VID_VIO_TO_IMP << VC4_ING_VID_CHECK_S;
> +
> +		if (is5325(dev) || is5365(dev))
> +			vc1 &= ~VC1_RX_MCST_TAG_EN;
> +
> +		if (!is5325(dev) && !is5365(dev))
> +			vc5 &= ~VC5_VID_FFF_EN;
> +	}
> +
> +	b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL0, vc0);
> +	b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL1, vc1);
> +
> +	if (is5325(dev) || is5365(dev)) {
> +		/* enable the high 8 bit vid check on 5325 */
> +		if (is5325(dev) && enable)
> +			b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL3,
> +				   VC3_HIGH_8BIT_EN);
> +		else
> +			b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL3, 0);
> +
> +		b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_25, vc4);
> +		b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5_25, vc5);
> +	} else if (is63xx(dev)) {
> +		b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_CTRL3_63XX, 0);
> +		b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_63XX, vc4);
> +		b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5_63XX, vc5);
> +	} else {
> +		b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_CTRL3, 0);
> +		b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4, vc4);
> +		b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5, vc5);
> +	}
> +
> +	b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, mgmt);
> +}
> +
> +static int b53_set_jumbo(struct b53_device *dev, int enable, int allow_10_100)
> +{
> +	u32 port_mask = 0;
> +	u16 max_size = JMS_MIN_SIZE;
> +
> +	if (is5325(dev) || is5365(dev))
> +		return -EINVAL;
> +
> +	if (enable) {
> +		port_mask = dev->enabled_ports;
> +		max_size = JMS_MAX_SIZE;
> +		if (allow_10_100)
> +			port_mask |= JPM_10_100_JUMBO_EN;
> +	}
> +
> +	b53_write32(dev, B53_JUMBO_PAGE, dev->chip->jumbo_pm_reg, port_mask);
> +	return b53_write16(dev, B53_JUMBO_PAGE, dev->chip->jumbo_size_reg,
> +			   max_size);
> +}
> +
> +static int b53_flush_arl(struct b53_device *dev)
> +{
> +	unsigned int i;
> +
> +	b53_write8(dev, B53_CTRL_PAGE, B53_FAST_AGE_CTRL,
> +		   FAST_AGE_DONE | FAST_AGE_DYNAMIC | FAST_AGE_STATIC);
> +
> +	for (i = 0; i < 10; i++) {
> +		u8 fast_age_ctrl;
> +
> +		b53_read8(dev, B53_CTRL_PAGE, B53_FAST_AGE_CTRL,
> +			  &fast_age_ctrl);
> +
> +		if (!(fast_age_ctrl & FAST_AGE_DONE))
> +			return 0;
> +
> +		mdelay(1);
> +	}
> +
> +	pr_warn("time out while flushing ARL\n");
> +
> +	return -EINVAL;
> +}
> +
> +static void b53_enable_ports(struct b53_device *dev)
> +{
> +	unsigned i;
> +
> +	b53_for_each_port(dev, i) {
> +		u8 port_ctrl;
> +		u16 pvlan_mask;
> +
> +		/* prevent leaking packets between wan and lan in unmanaged
> +		 * mode through port vlans.
> +		 */
> +		if (dev->enable_vlan || is_cpu_port(dev, i))
> +			pvlan_mask = 0x1ff;
> +		else if (is531x5(dev) || is5301x(dev))
> +			/* BCM53115 may use a different port as cpu port */
> +			pvlan_mask = BIT(dev->cpu_port);
> +		else
> +			pvlan_mask = BIT(B53_CPU_PORT);
> +
> +		/* BCM5325 CPU port is at 8 */
> +		if ((is5325(dev) || is5365(dev)) && i == B53_CPU_PORT_25)
> +			i = B53_CPU_PORT;
> +
> +		if (dev->chip_id == BCM5398_DEVICE_ID && (i == 6 || i == 7))
> +			/* disable unused ports 6 & 7 */
> +			port_ctrl = PORT_CTRL_RX_DISABLE | PORT_CTRL_TX_DISABLE;
> +		else if (i == B53_CPU_PORT)
> +			port_ctrl = PORT_CTRL_RX_BCST_EN |
> +				    PORT_CTRL_RX_MCST_EN |
> +				    PORT_CTRL_RX_UCST_EN;
> +		else
> +			port_ctrl = 0;
> +
> +		b53_write16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(i),
> +			    pvlan_mask);
> +
> +		/* port state is handled by bcm63xx_enet driver */
> +		if (!is63xx(dev) && !(is5301x(dev) && i == 6))
> +			b53_write8(dev, B53_CTRL_PAGE, B53_PORT_CTRL(i),
> +				   port_ctrl);
> +	}
> +}
> +
> +static void b53_enable_mib(struct b53_device *dev)
> +{
> +	u8 gc;
> +
> +	b53_read8(dev, B53_CTRL_PAGE, B53_GLOBAL_CONFIG, &gc);
> +
> +	gc &= ~(GC_RESET_MIB | GC_MIB_AC_EN);
> +
> +	b53_write8(dev, B53_CTRL_PAGE, B53_GLOBAL_CONFIG, gc);
> +}
> +
> +static int b53_apply(struct b53_device *dev)
> +{
> +	int i;
> +
> +	/* clear all vlan entries */
> +	if (is5325(dev) || is5365(dev)) {
> +		for (i = 1; i < dev->chip->vlans; i++)
> +			b53_set_vlan_entry(dev, i, 0, 0);
> +	} else {
> +		b53_do_vlan_op(dev, VTA_CMD_CLEAR);
> +	}
> +
> +	b53_enable_vlan(dev, dev->enable_vlan);
> +
> +	/* fill VLAN table */
> +	if (dev->enable_vlan) {
> +		for (i = 0; i < dev->chip->vlans; i++) {
> +			struct b53_vlan *vlan = &dev->vlans[i];
> +
> +			if (!vlan->members)
> +				continue;
> +
> +			b53_set_vlan_entry(dev, i, vlan->members, vlan->untag);
> +		}
> +
> +		b53_for_each_port(dev, i)
> +			b53_write16(dev, B53_VLAN_PAGE,
> +				    B53_VLAN_PORT_DEF_TAG(i),
> +				    dev->ports[i]->pvid);
> +	} else {
> +		b53_for_each_port(dev, i)
> +			b53_write16(dev, B53_VLAN_PAGE,
> +				    B53_VLAN_PORT_DEF_TAG(i), 1);
> +	}
> +
> +	b53_enable_ports(dev);
> +
> +	if (!is5325(dev) && !is5365(dev))
> +		b53_set_jumbo(dev, dev->enable_jumbo, 1);
> +
> +	return 0;
> +}
> +
> +static void b53_switch_reset_gpio(struct b53_device *dev)
> +{
> +	int gpio = dev->reset_gpio;
> +
> +	if (gpio < 0)
> +		return;
> +
> +	/* Reset sequence: RESET low(50ms)->high(20ms) */
> +
> +	gpio_set_value(gpio, 0);
> +	mdelay(50);
> +
> +	gpio_set_value(gpio, 1);
> +	mdelay(20);
> +
> +	dev->current_page = 0xff;
> +}
> +
> +static int b53_switch_reset(struct b53_device *dev)
> +{
> +	u8 mgmt;
> +
> +	b53_switch_reset_gpio(dev);
> +
> +	if (is539x(dev)) {
> +		b53_write8(dev, B53_CTRL_PAGE, B53_SOFTRESET, 0x83);
> +		b53_write8(dev, B53_CTRL_PAGE, B53_SOFTRESET, 0x00);
> +	}
> +
> +	b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt);
> +
> +	if (!(mgmt & SM_SW_FWD_EN)) {
> +		mgmt &= ~SM_SW_FWD_MODE;
> +		mgmt |= SM_SW_FWD_EN;
> +
> +		b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, mgmt);
> +		b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt);
> +
> +		if (!(mgmt & SM_SW_FWD_EN)) {
> +			pr_err("Failed to enable switch!\n");
> +			return -EINVAL;
> +		}
> +	}
> +
> +	/* enable all ports */
> +	b53_enable_ports(dev);
> +
> +	/* configure MII port if necessary */
> +	if (is5325(dev)) {
> +		u8 mii_port_override;
> +
> +		b53_read8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL,
> +			  &mii_port_override);
> +		/* reverse mii needs to be enabled */
> +		if (!(mii_port_override & PORT_OVERRIDE_RV_MII_25)) {
> +			b53_write8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL,
> +				   mii_port_override | PORT_OVERRIDE_RV_MII_25);
> +			b53_read8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL,
> +				  &mii_port_override);
> +
> +			if (!(mii_port_override & PORT_OVERRIDE_RV_MII_25)) {
> +				pr_err("Failed to enable reverse MII mode\n");
> +				return -EINVAL;
> +			}
> +		}
> +	} else if ((is531x5(dev) || is5301x(dev)) &&
> +		   dev->cpu_port == B53_CPU_PORT) {
> +		u8 mii_port_override;
> +
> +		b53_read8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL,
> +			  &mii_port_override);
> +		b53_write8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL,
> +			   mii_port_override | PORT_OVERRIDE_EN |
> +			   PORT_OVERRIDE_LINK);
> +	}
> +
> +	b53_enable_mib(dev);
> +
> +	return b53_flush_arl(dev);
> +}
> +
> +/*****************
> + * Net device ops
> + *****************/
> +
> +static netdev_tx_t b53_port_xmit(struct sk_buff *skb, struct net_device *dev)
> +{
> +	dev_kfree_skb(skb);
> +	dev->stats.tx_dropped++;
> +
> +	return NETDEV_TX_OK;
> +}
> +
> +static int b53_port_vlan_rx_add_vid(struct net_device *dev,
> +				    __be16 proto, u16 vid)
> +{
> +	struct b53_port *b53_port = netdev_priv(dev);
> +	struct b53_device *b53 = b53_port->b53;
> +	struct b53_vlan *vlan;
> +
> +	if (vid >= b53->chip->vlans)
> +		return -EINVAL;
> +
> +	/* only BCM5325 and BCM5365 supports VID 0 */
> +	if (vid == 0 && !is5325(b53) && !is5365(b53))
> +		return -EINVAL;
> +
> +	/* VLAN 4095 needs special handling */
> +	if (vid == 4095)
> +		return -EINVAL;
> +
> +	vlan = &b53->vlans[vid];
> +
> +	vlan->members |= BIT(b53_port->port_number);
> +
> +	/* ignore disabled ports */
> +	vlan->members &= b53->enabled_ports;
> +
> +	b53_apply(b53);
> +
> +	return 0;
> +}
> +
> +static int b53_port_vlan_rx_kill_vid(struct net_device *dev,
> +				     __be16 proto, u16 vid)
> +{
> +	struct b53_port *b53_port = netdev_priv(dev);
> +	struct b53_device *b53 = b53_port->b53;
> +	struct b53_vlan *vlan;
> +
> +	if (vid >= b53->chip->vlans)
> +		return -EINVAL;
> +
> +	vlan = &b53->vlans[vid];
> +
> +	vlan->members &= ~BIT(b53_port->port_number);
> +
> +	b53_apply(b53);
> +
> +	return 0;
> +}
> +
> +static int b53_port_switch_parent_id_get(struct net_device *dev,
> +					 struct netdev_phys_item_id *psid)
> +{
> +	struct b53_port *b53_port = netdev_priv(dev);
> +
> +	memcpy(psid->id, b53_port->b53->dev_addr, ETH_ALEN);
> +	psid->id_len = ETH_ALEN;
> +
> +	return 0;
> +}
> +
> +static int b53_port_bridge_setlink(struct net_device *dev,
> +				   struct nlmsghdr *nlh, u16 flags)
> +{
> +	struct b53_port *b53_port = netdev_priv(dev);
> +	struct b53_device *b53 = b53_port->b53;
> +	struct b53_vlan *vlan;
> +	struct nlattr *afspec;
> +	struct nlattr *attr;
> +	struct bridge_vlan_info *vinfo;
> +	int rem;
> +
> +	afspec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC);
> +	if (!afspec)
> +		return -EINVAL;
> +
> +	nla_for_each_nested(attr, afspec, rem) {
> +		if (nla_type(attr) != IFLA_BRIDGE_VLAN_INFO)
> +			continue;
> +		if (nla_len(attr) != sizeof(struct bridge_vlan_info))
> +			return -EINVAL;
> +		vinfo = nla_data(attr);
> +	}
> +	if (!vinfo)
> +		return -EINVAL;
> +
> +	if (vinfo->flags & BRIDGE_VLAN_INFO_PVID)
> +		b53_port->pvid = vinfo->vid;
> +	else
> +		b53_port->pvid = 0;
> +
> +	vlan = &b53->vlans[vinfo->vid];
> +	if (vinfo->flags & BRIDGE_VLAN_INFO_UNTAGGED)
> +		vlan->untag |= BIT(b53_port->port_number);
> +	else
> +		vlan->untag &= ~BIT(b53_port->port_number);
> +
> +	b53_apply(b53);
> +
> +	return 0;
> +}
> +
> +static const struct net_device_ops b53_port_netdev_ops = {
> +	.ndo_start_xmit			= b53_port_xmit,
> +	.ndo_vlan_rx_add_vid		= b53_port_vlan_rx_add_vid,
> +	.ndo_vlan_rx_kill_vid		= b53_port_vlan_rx_kill_vid,
> +	.ndo_switch_parent_id_get	= b53_port_switch_parent_id_get,
> +	.ndo_bridge_setlink		= b53_port_bridge_setlink,
> +};
> +
> +/*****************
> + * Common
> + *****************/
> +
> +static void b53_remove_ports(struct b53_device *b53)
> +{
> +	struct b53_port *b53_port;
> +	unsigned int i;
> +
> +	for (i = 0; i < b53->port_count; i++) {
> +		b53_port = b53->ports[i];
> +		unregister_netdev(b53_port->ndev);
> +	}
> +	kfree(b53->ports);
> +}
> +
> +static int b53_probe_port(struct b53_device *b53, unsigned int port_number)
> +{
> +	struct b53_port *b53_port;
> +	struct net_device *ndev;
> +	int err;
> +
> +	ndev = alloc_etherdev(sizeof(struct b53_port));
> +	if (!ndev)
> +		return -ENOMEM;
> +	b53_port = netdev_priv(ndev);
> +	b53_port->ndev = ndev;
> +	b53_port->b53 = b53;
> +	b53_port->port_number = port_number;
> +
> +	ndev->netdev_ops = &b53_port_netdev_ops;
> +	ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER |
> +			  NETIF_F_HW_SWITCH_OFFLOAD;
> +	netif_carrier_on(ndev);
> +	memcpy(ndev->dev_addr, b53->dev_addr, ETH_ALEN);
> +
> +	err = register_netdev(ndev);
> +	if (err) {
> +		dev_err(b53->dev, "register_netdev failed\n");
> +		goto err_free_netdev;
> +	}
> +	b53->ports[port_number] = b53_port;
> +
> +	return 0;
> +
> +err_free_netdev:
> +	free_netdev(ndev);
> +	return err;
> +}
> +
> +#define B53_VTA_REGS	\
> +	{ B53_VT_ACCESS, B53_VT_INDEX, B53_VT_ENTRY }
> +#define B53_VTA_REGS_9798 \
> +	{ B53_VT_ACCESS_9798, B53_VT_INDEX_9798, B53_VT_ENTRY_9798 }
> +#define B53_VTA_REGS_63XX \
> +	{ B53_VT_ACCESS_63XX, B53_VT_INDEX_63XX, B53_VT_ENTRY_63XX }
> +
> +static const struct b53_chip_data b53_switch_chips[] = {
> +	{
> +		.chip_id = BCM5325_DEVICE_ID,
> +		.dev_name = "BCM5325",
> +		.alias = "bcm5325",
> +		.vlans = 16,
> +		.enabled_ports = 0x1f,
> +		.cpu_port = B53_CPU_PORT_25,
> +		.duplex_reg = B53_DUPLEX_STAT_FE,
> +	},
> +	{
> +		.chip_id = BCM5365_DEVICE_ID,
> +		.dev_name = "BCM5365",
> +		.alias = "bcm5365",
> +		.vlans = 256,
> +		.enabled_ports = 0x1f,
> +		.cpu_port = B53_CPU_PORT_25,
> +		.duplex_reg = B53_DUPLEX_STAT_FE,
> +	},
> +	{
> +		.chip_id = BCM5395_DEVICE_ID,
> +		.dev_name = "BCM5395",
> +		.alias = "bcm5395",
> +		.vlans = 4096,
> +		.enabled_ports = 0x1f,
> +		.cpu_port = B53_CPU_PORT,
> +		.vta_regs = B53_VTA_REGS,
> +		.duplex_reg = B53_DUPLEX_STAT_GE,
> +		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
> +		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
> +	},
> +	{
> +		.chip_id = BCM5397_DEVICE_ID,
> +		.dev_name = "BCM5397",
> +		.alias = "bcm5397",
> +		.vlans = 4096,
> +		.enabled_ports = 0x1f,
> +		.cpu_port = B53_CPU_PORT,
> +		.vta_regs = B53_VTA_REGS_9798,
> +		.duplex_reg = B53_DUPLEX_STAT_GE,
> +		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
> +		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
> +	},
> +	{
> +		.chip_id = BCM5398_DEVICE_ID,
> +		.dev_name = "BCM5398",
> +		.alias = "bcm5398",
> +		.vlans = 4096,
> +		.enabled_ports = 0x7f,
> +		.cpu_port = B53_CPU_PORT,
> +		.vta_regs = B53_VTA_REGS_9798,
> +		.duplex_reg = B53_DUPLEX_STAT_GE,
> +		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
> +		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
> +	},
> +	{
> +		.chip_id = BCM53115_DEVICE_ID,
> +		.dev_name = "BCM53115",
> +		.alias = "bcm53115",
> +		.vlans = 4096,
> +		.enabled_ports = 0x1f,
> +		.vta_regs = B53_VTA_REGS,
> +		.cpu_port = B53_CPU_PORT,
> +		.duplex_reg = B53_DUPLEX_STAT_GE,
> +		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
> +		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
> +	},
> +	{
> +		.chip_id = BCM53125_DEVICE_ID,
> +		.dev_name = "BCM53125",
> +		.alias = "bcm53125",
> +		.vlans = 4096,
> +		.enabled_ports = 0x1f,
> +		.cpu_port = B53_CPU_PORT,
> +		.vta_regs = B53_VTA_REGS,
> +		.duplex_reg = B53_DUPLEX_STAT_GE,
> +		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
> +		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
> +	},
> +	{
> +		.chip_id = BCM53128_DEVICE_ID,
> +		.dev_name = "BCM53128",
> +		.alias = "bcm53128",
> +		.vlans = 4096,
> +		.enabled_ports = 0x1ff,
> +		.cpu_port = B53_CPU_PORT,
> +		.vta_regs = B53_VTA_REGS,
> +		.duplex_reg = B53_DUPLEX_STAT_GE,
> +		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
> +		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
> +	},
> +	{
> +		.chip_id = BCM53010_DEVICE_ID,
> +		.dev_name = "BCM53010",
> +		.alias = "bcm53011",
> +		.vlans = 4096,
> +		.enabled_ports = 0x1f,
> +		.cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */
> +		.vta_regs = B53_VTA_REGS,
> +		.duplex_reg = B53_DUPLEX_STAT_GE,
> +		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
> +		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
> +	},
> +	{
> +		.chip_id = BCM53011_DEVICE_ID,
> +		.dev_name = "BCM53011",
> +		.alias = "bcm53011",
> +		.vlans = 4096,
> +		.enabled_ports = 0x1f,
> +		.cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */
> +		.vta_regs = B53_VTA_REGS,
> +		.duplex_reg = B53_DUPLEX_STAT_GE,
> +		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
> +		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
> +	},
> +	{
> +		.chip_id = BCM53012_DEVICE_ID,
> +		.dev_name = "BCM53012",
> +		.alias = "bcm53011",
> +		.vlans = 4096,
> +		.enabled_ports = 0x1f,
> +		.cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */
> +		.vta_regs = B53_VTA_REGS,
> +		.duplex_reg = B53_DUPLEX_STAT_GE,
> +		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
> +		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
> +	},
> +	{
> +		.chip_id = BCM53018_DEVICE_ID,
> +		.dev_name = "BCM53018",
> +		.alias = "bcm53018",
> +		.vlans = 4096,
> +		.enabled_ports = 0x1f,
> +		.cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */
> +		.vta_regs = B53_VTA_REGS,
> +		.duplex_reg = B53_DUPLEX_STAT_GE,
> +		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
> +		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
> +	},
> +	{
> +		.chip_id = BCM53019_DEVICE_ID,
> +		.dev_name = "BCM53019",
> +		.alias = "bcm53019",
> +		.vlans = 4096,
> +		.enabled_ports = 0x1f,
> +		.cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */
> +		.vta_regs = B53_VTA_REGS,
> +		.duplex_reg = B53_DUPLEX_STAT_GE,
> +		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
> +		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
> +	},
> +};
> +
> +static int b53_switch_init(struct b53_device *dev)
> +{
> +	unsigned int i;
> +	int err;
> +
> +	eth_random_addr(dev->dev_addr);
> +
> +	dev->cpu_port = dev->chip->cpu_port;
> +	dev->enabled_ports = dev->chip->enabled_ports;
> +
> +	/* check which BCM5325x version we have */
> +	if (is5325(dev)) {
> +		u8 vc4;
> +
> +		b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_25, &vc4);
> +
> +		/* check reserved bits */
> +		switch (vc4 & 3) {
> +		case 1:
> +			/* BCM5325E */
> +			break;
> +		case 3:
> +			/* BCM5325F - do not use port 4 */
> +			dev->enabled_ports &= ~BIT(4);
> +			break;
> +		default:
> +/* On the BCM47XX SoCs this is the supported internal switch.*/
> +#ifndef CONFIG_BCM47XX
> +			/* BCM5325M */
> +			return -EINVAL;
> +#else
> +			break;
> +#endif
> +		}
> +	} else if (dev->chip_id == BCM53115_DEVICE_ID) {
> +		u64 strap_value;
> +
> +		b53_read48(dev, B53_STAT_PAGE, B53_STRAP_VALUE, &strap_value);
> +		/* use second IMP port if GMII is enabled */
> +		if (strap_value & SV_GMII_CTRL_115)
> +			dev->cpu_port = 5;
> +	}
> +
> +	/* cpu port is always last */
> +	dev->port_count = dev->cpu_port + 1;
> +	dev->enabled_ports |= BIT(dev->cpu_port);
> +
> +	dev->ports = devm_kzalloc(dev->dev,
> +				  sizeof(struct b53_port *) * dev->port_count,
> +				  GFP_KERNEL);
> +	if (!dev->ports)
> +		return -ENOMEM;
> +
> +	for (i = 0; i < dev->port_count; i++) {
> +		err = b53_probe_port(dev, i);
> +		if (err)
> +			goto err_remove_ports;
> +	}
> +
> +	dev->vlans = devm_kzalloc(dev->dev,
> +				  sizeof(struct b53_vlan) * dev->chip->vlans,
> +				  GFP_KERNEL);
> +	if (!dev->vlans)
> +		return -ENOMEM;
> +
> +	dev->reset_gpio = b53_switch_get_reset_gpio(dev);
> +	if (dev->reset_gpio >= 0) {
> +		err = devm_gpio_request_one(dev->dev, dev->reset_gpio,
> +					    GPIOF_OUT_INIT_HIGH, "robo_reset");
> +		if (err)
> +			return err;
> +	}
> +
> +	return b53_switch_reset(dev);
> +
> +err_remove_ports:
> +	b53_remove_ports(dev);
> +	return err;
> +}
> +
> +struct b53_device *b53_switch_alloc(struct device *base, struct b53_io_ops *ops,
> +				    void *priv)
> +{
> +	struct b53_device *dev;
> +
> +	dev = devm_kzalloc(base, sizeof(*dev), GFP_KERNEL);
> +	if (!dev)
> +		return NULL;
> +
> +	dev->dev = base;
> +	dev->ops = ops;
> +	dev->priv = priv;
> +	mutex_init(&dev->reg_mutex);
> +
> +	return dev;
> +}
> +EXPORT_SYMBOL(b53_switch_alloc);
> +
> +int b53_switch_detect(struct b53_device *dev)
> +{
> +	u32 id32;
> +	u16 tmp;
> +	u8 id8;
> +	unsigned i;
> +	int ret;
> +
> +	ret = b53_read8(dev, B53_MGMT_PAGE, B53_DEVICE_ID, &id8);
> +	if (ret)
> +		return ret;
> +
> +	switch (id8) {
> +	case 0:
> +		/* BCM5325 and BCM5365 do not have this register so reads
> +		 * return 0. But the read operation did succeed, so assume
> +		 * this is one of them.
> +		 *
> +		 * Next check if we can write to the 5325's VTA register; for
> +		 * 5365 it is read only.
> +		 */
> +
> +		b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_TABLE_ACCESS_25, 0xf);
> +		b53_read16(dev, B53_VLAN_PAGE, B53_VLAN_TABLE_ACCESS_25, &tmp);
> +
> +		if (tmp == 0xf)
> +			dev->chip_id = BCM5325_DEVICE_ID;
> +		else
> +			dev->chip_id = BCM5365_DEVICE_ID;
> +		break;
> +	case BCM5395_DEVICE_ID:
> +	case BCM5397_DEVICE_ID:
> +	case BCM5398_DEVICE_ID:
> +		dev->chip_id = id8;
> +		break;
> +	default:
> +		ret = b53_read32(dev, B53_MGMT_PAGE, B53_DEVICE_ID, &id32);
> +		if (ret)
> +			return ret;
> +
> +		switch (id32) {
> +		case BCM53115_DEVICE_ID:
> +		case BCM53125_DEVICE_ID:
> +		case BCM53128_DEVICE_ID:
> +		case BCM53010_DEVICE_ID:
> +		case BCM53011_DEVICE_ID:
> +		case BCM53012_DEVICE_ID:
> +		case BCM53018_DEVICE_ID:
> +		case BCM53019_DEVICE_ID:
> +			dev->chip_id = id32;
> +			break;
> +		default:
> +			pr_err("unsupported switch detected (BCM53%02x/BCM%x)\n",
> +			       id8, id32);
> +			return -ENODEV;
> +		}
> +	}
> +
> +	if (dev->chip_id == BCM5325_DEVICE_ID)
> +		ret = b53_read8(dev, B53_STAT_PAGE, B53_REV_ID_25,
> +				&dev->core_rev);
> +	else
> +		ret = b53_read8(dev, B53_MGMT_PAGE, B53_REV_ID, &dev->core_rev);
> +	if (ret)
> +		return ret;
> +
> +	for (i = 0; i < ARRAY_SIZE(b53_switch_chips); i++) {
> +		const struct b53_chip_data *chip = &b53_switch_chips[i];
> +
> +		if (chip->chip_id == dev->chip_id) {
> +			dev->chip = chip;
> +			return 0;
> +		}
> +	}
> +
> +	return -ENOENT;
> +}
> +EXPORT_SYMBOL(b53_switch_detect);
> +
> +int b53_switch_register(struct b53_device *dev)
> +{
> +	int ret;
> +
> +	if (!dev->chip_id && b53_switch_detect(dev))
> +		return -EINVAL;
> +
> +	ret = b53_switch_init(dev);
> +	if (ret)
> +		return ret;
> +
> +	dev_info(dev->dev, "found switch: %s, rev %i\n", dev->chip->dev_name,
> +		 dev->core_rev);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(b53_switch_register);
> +
> +void b53_switch_exit(struct b53_device *b53)
> +{
> +	b53_remove_ports(b53);
> +}
> +EXPORT_SYMBOL(b53_switch_exit);
> +
> +MODULE_AUTHOR("Jonas Gorski <jogo@openwrt.org>");
> +MODULE_DESCRIPTION("B53 switch library");
> +MODULE_LICENSE("Dual BSD/GPL");
> diff --git a/drivers/net/phy/b53/b53_mdio.c b/drivers/net/phy/b53/b53_mdio.c
> new file mode 100644
> index 0000000..747ef67
> --- /dev/null
> +++ b/drivers/net/phy/b53/b53_mdio.c
> @@ -0,0 +1,418 @@
> +/*
> + * B53 register access through MII registers
> + *
> + * Copyright (C) 2011-2013 Jonas Gorski <jogo@openwrt.org>
> + *
> + * 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/delay.h>
> +#include <linux/kernel.h>
> +#include <linux/phy.h>
> +#include <linux/module.h>
> +#include <linux/netdevice.h>
> +
> +#include "b53_priv.h"
> +
> +#define B53_PSEUDO_PHY	0x1e /* Register Access Pseudo PHY */
> +
> +/* MII registers */
> +#define REG_MII_PAGE		0x10    /* MII Page register */
> +#define REG_MII_ADDR		0x11    /* MII Address register */
> +#define REG_MII_DATA0		0x18    /* MII Data register 0 */
> +#define REG_MII_DATA1		0x19    /* MII Data register 1 */
> +#define REG_MII_DATA2		0x1a    /* MII Data register 2 */
> +#define REG_MII_DATA3		0x1b    /* MII Data register 3 */
> +
> +#define REG_MII_PAGE_ENABLE	BIT(0)
> +#define REG_MII_ADDR_WRITE	BIT(0)
> +#define REG_MII_ADDR_READ	BIT(1)
> +
> +static int b53_mdio_op(struct b53_device *dev, u8 page, u8 reg, u16 op)
> +{
> +	int i;
> +	u16 v;
> +	int ret;
> +	struct mii_bus *bus = dev->priv;
> +
> +	if (dev->current_page != page) {
> +		/* set page number */
> +		v = (page << 8) | REG_MII_PAGE_ENABLE;
> +		ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_PAGE, v);
> +		if (ret)
> +			return ret;
> +		dev->current_page = page;
> +	}
> +
> +	/* set register address */
> +	v = (reg << 8) | op;
> +	ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_ADDR, v);
> +	if (ret)
> +		return ret;
> +
> +	/* check if operation completed */
> +	for (i = 0; i < 5; ++i) {
> +		v = mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_ADDR);
> +		if (!(v & (REG_MII_ADDR_WRITE | REG_MII_ADDR_READ)))
> +			break;
> +		usleep_range(10, 100);
> +	}
> +
> +	if (WARN_ON(i == 5))
> +		return -EIO;
> +
> +	return 0;
> +}
> +
> +static int b53_mdio_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val)
> +{
> +	struct mii_bus *bus = dev->priv;
> +	int ret;
> +
> +	ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ);
> +	if (ret)
> +		return ret;
> +
> +	*val = mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA0) & 0xff;
> +
> +	return 0;
> +}
> +
> +static int b53_mdio_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val)
> +{
> +	struct mii_bus *bus = dev->priv;
> +	int ret;
> +
> +	ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ);
> +	if (ret)
> +		return ret;
> +
> +	*val = mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA0);
> +
> +	return 0;
> +}
> +
> +static int b53_mdio_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val)
> +{
> +	struct mii_bus *bus = dev->priv;
> +	int ret;
> +
> +	ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ);
> +	if (ret)
> +		return ret;
> +
> +	*val = mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA0);
> +	*val |= mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA1) << 16;
> +
> +	return 0;
> +}
> +
> +static int b53_mdio_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val)
> +{
> +	struct mii_bus *bus = dev->priv;
> +	u64 temp = 0;
> +	int i;
> +	int ret;
> +
> +	ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ);
> +	if (ret)
> +		return ret;
> +
> +	for (i = 2; i >= 0; i--) {
> +		temp <<= 16;
> +		temp |= mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA0 + i);
> +	}
> +
> +	*val = temp;
> +
> +	return 0;
> +}
> +
> +static int b53_mdio_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val)
> +{
> +	struct mii_bus *bus = dev->priv;
> +	u64 temp = 0;
> +	int i;
> +	int ret;
> +
> +	ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ);
> +	if (ret)
> +		return ret;
> +
> +	for (i = 3; i >= 0; i--) {
> +		temp <<= 16;
> +		temp |= mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA0 + i);
> +	}
> +
> +	*val = temp;
> +
> +	return 0;
> +}
> +
> +static int b53_mdio_write8(struct b53_device *dev, u8 page, u8 reg, u8 value)
> +{
> +	struct mii_bus *bus = dev->priv;
> +	int ret;
> +
> +	ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_DATA0, value);
> +	if (ret)
> +		return ret;
> +
> +	return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE);
> +}
> +
> +static int b53_mdio_write16(struct b53_device *dev, u8 page, u8 reg, u16 value)
> +{
> +	struct mii_bus *bus = dev->priv;
> +	int ret;
> +
> +	ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_DATA0, value);
> +	if (ret)
> +		return ret;
> +
> +	return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE);
> +}
> +
> +static int b53_mdio_write32(struct b53_device *dev, u8 page, u8 reg, u32 value)
> +{
> +	struct mii_bus *bus = dev->priv;
> +	unsigned int i;
> +	u32 temp = value;
> +
> +	for (i = 0; i < 2; i++) {
> +		int ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_DATA0 + i,
> +				    temp & 0xffff);
> +		if (ret)
> +			return ret;
> +		temp >>= 16;
> +	}
> +
> +	return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE);
> +}
> +
> +static int b53_mdio_write48(struct b53_device *dev, u8 page, u8 reg, u64 value)
> +{
> +	struct mii_bus *bus = dev->priv;
> +	unsigned i;
> +	u64 temp = value;
> +
> +	for (i = 0; i < 3; i++) {
> +		int ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_DATA0 + i,
> +				    temp & 0xffff);
> +		if (ret)
> +			return ret;
> +		temp >>= 16;
> +	}
> +
> +	return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE);
> +}
> +
> +static int b53_mdio_write64(struct b53_device *dev, u8 page, u8 reg, u64 value)
> +{
> +	struct mii_bus *bus = dev->priv;
> +	unsigned i;
> +	u64 temp = value;
> +
> +	for (i = 0; i < 4; i++) {
> +		int ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_DATA0 + i,
> +				    temp & 0xffff);
> +		if (ret)
> +			return ret;
> +		temp >>= 16;
> +	}
> +
> +	return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE);
> +}
> +
> +static struct b53_io_ops b53_mdio_ops = {
> +	.read8 = b53_mdio_read8,
> +	.read16 = b53_mdio_read16,
> +	.read32 = b53_mdio_read32,
> +	.read48 = b53_mdio_read48,
> +	.read64 = b53_mdio_read64,
> +	.write8 = b53_mdio_write8,
> +	.write16 = b53_mdio_write16,
> +	.write32 = b53_mdio_write32,
> +	.write48 = b53_mdio_write48,
> +	.write64 = b53_mdio_write64,
> +};
> +
> +static int b53_phy_probe(struct phy_device *phydev)
> +{
> +	struct b53_device dev;
> +	int ret;
> +
> +	/* allow the generic phy driver to take over */
> +	if (phydev->addr != B53_PSEUDO_PHY && phydev->addr != 0)
> +		return -ENODEV;
> +
> +	dev.current_page = 0xff;
> +	dev.priv = phydev->bus;
> +	dev.ops = &b53_mdio_ops;
> +	mutex_init(&dev.reg_mutex);
> +
> +	ret = b53_switch_detect(&dev);
> +	if (ret)
> +		return ret;
> +
> +	if (is5325(&dev) || is5365(&dev))
> +		phydev->supported = SUPPORTED_100baseT_Full;
> +	else
> +		phydev->supported = SUPPORTED_1000baseT_Full;
> +
> +	phydev->advertising = phydev->supported;
> +
> +	return 0;
> +}
> +
> +static int b53_phy_config_init(struct phy_device *phydev)
> +{
> +	struct b53_device *dev;
> +	int ret;
> +
> +	dev = b53_switch_alloc(&phydev->dev, &b53_mdio_ops, phydev->bus);
> +	if (!dev)
> +		return -ENOMEM;
> +
> +	/* we don't use page 0xff, so force a page set */
> +	dev->current_page = 0xff;
> +
> +	ret = b53_switch_register(dev);
> +	if (ret) {
> +		dev_err(dev->dev, "failed to register switch: %i\n", ret);
> +		return ret;
> +	}
> +
> +	phydev->priv = dev;
> +
> +	return 0;
> +}
> +
> +static void b53_phy_remove(struct phy_device *phydev)
> +{
> +	struct b53_device *priv = phydev->priv;
> +
> +	if (!priv)
> +		return;
> +
> +	b53_switch_exit(priv);
> +
> +	phydev->priv = NULL;
> +}
> +
> +static int b53_phy_config_aneg(struct phy_device *phydev)
> +{
> +	return 0;
> +}
> +
> +static int b53_phy_read_status(struct phy_device *phydev)
> +{
> +	struct b53_device *priv = phydev->priv;
> +
> +	if (is5325(priv) || is5365(priv))
> +		phydev->speed = 100;
> +	else
> +		phydev->speed = 1000;
> +
> +	phydev->duplex = DUPLEX_FULL;
> +	phydev->link = 1;
> +	phydev->state = PHY_RUNNING;
> +
> +	netif_carrier_on(phydev->attached_dev);
> +	phydev->adjust_link(phydev->attached_dev);
> +
> +	return 0;
> +}
> +
> +/* BCM5325, BCM539x */
> +static struct phy_driver b53_phy_driver_id1 = {
> +	.phy_id		= 0x0143bc00,
> +	.name		= "Broadcom B53 (1)",
> +	.phy_id_mask	= 0x1ffffc00,
> +	.features	= 0,
> +	.probe		= b53_phy_probe,
> +	.remove		= b53_phy_remove,
> +	.config_aneg	= b53_phy_config_aneg,
> +	.config_init	= b53_phy_config_init,
> +	.read_status	= b53_phy_read_status,
> +	.driver = {
> +		.owner = THIS_MODULE,
> +	},
> +};
> +
> +/* BCM53125, BCM53128 */
> +static struct phy_driver b53_phy_driver_id2 = {
> +	.phy_id		= 0x03625c00,
> +	.name		= "Broadcom B53 (2)",
> +	.phy_id_mask	= 0x1ffffc00,
> +	.features	= 0,
> +	.probe		= b53_phy_probe,
> +	.remove		= b53_phy_remove,
> +	.config_aneg	= b53_phy_config_aneg,
> +	.config_init	= b53_phy_config_init,
> +	.read_status	= b53_phy_read_status,
> +	.driver = {
> +		.owner = THIS_MODULE,
> +	},
> +};
> +
> +/* BCM5365 */
> +static struct phy_driver b53_phy_driver_id3 = {
> +	.phy_id		= 0x00406000,
> +	.name		= "Broadcom B53 (3)",
> +	.phy_id_mask	= 0x1ffffc00,
> +	.features	= 0,
> +	.probe		= b53_phy_probe,
> +	.remove		= b53_phy_remove,
> +	.config_aneg	= b53_phy_config_aneg,
> +	.config_init	= b53_phy_config_init,
> +	.read_status	= b53_phy_read_status,
> +	.driver = {
> +		.owner = THIS_MODULE,
> +	},
> +};
> +
> +int __init b53_phy_driver_register(void)
> +{
> +	int ret;
> +
> +	ret = phy_driver_register(&b53_phy_driver_id1);
> +	if (ret)
> +		return ret;
> +
> +	ret = phy_driver_register(&b53_phy_driver_id2);
> +	if (ret)
> +		goto err1;
> +
> +	ret = phy_driver_register(&b53_phy_driver_id3);
> +	if (!ret)
> +		return 0;
> +
> +	phy_driver_unregister(&b53_phy_driver_id2);
> +err1:
> +	phy_driver_unregister(&b53_phy_driver_id1);
> +	return ret;
> +}
> +
> +void __exit b53_phy_driver_unregister(void)
> +{
> +	phy_driver_unregister(&b53_phy_driver_id3);
> +	phy_driver_unregister(&b53_phy_driver_id2);
> +	phy_driver_unregister(&b53_phy_driver_id1);
> +}
> +
> +module_init(b53_phy_driver_register);
> +module_exit(b53_phy_driver_unregister);
> +
> +MODULE_DESCRIPTION("B53 MDIO access driver");
> +MODULE_LICENSE("Dual BSD/GPL");
> diff --git a/drivers/net/phy/b53/b53_priv.h b/drivers/net/phy/b53/b53_priv.h
> new file mode 100644
> index 0000000..03ebaf0
> --- /dev/null
> +++ b/drivers/net/phy/b53/b53_priv.h
> @@ -0,0 +1,299 @@
> +/*
> + * B53 common definitions
> + *
> + * Copyright (C) 2011-2013 Jonas Gorski <jogo@openwrt.org>
> + *
> + * 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.
> + */
> +
> +#ifndef __B53_PRIV_H
> +#define __B53_PRIV_H
> +
> +#include <linux/kernel.h>
> +#include <linux/mutex.h>
> +
> +struct b53_device;
> +
> +struct b53_io_ops {
> +	int (*read8)(struct b53_device *dev, u8 page, u8 reg, u8 *value);
> +	int (*read16)(struct b53_device *dev, u8 page, u8 reg, u16 *value);
> +	int (*read32)(struct b53_device *dev, u8 page, u8 reg, u32 *value);
> +	int (*read48)(struct b53_device *dev, u8 page, u8 reg, u64 *value);
> +	int (*read64)(struct b53_device *dev, u8 page, u8 reg, u64 *value);
> +	int (*write8)(struct b53_device *dev, u8 page, u8 reg, u8 value);
> +	int (*write16)(struct b53_device *dev, u8 page, u8 reg, u16 value);
> +	int (*write32)(struct b53_device *dev, u8 page, u8 reg, u32 value);
> +	int (*write48)(struct b53_device *dev, u8 page, u8 reg, u64 value);
> +	int (*write64)(struct b53_device *dev, u8 page, u8 reg, u64 value);
> +};
> +
> +enum {
> +	BCM5325_DEVICE_ID = 0x25,
> +	BCM5365_DEVICE_ID = 0x65,
> +	BCM5395_DEVICE_ID = 0x95,
> +	BCM5397_DEVICE_ID = 0x97,
> +	BCM5398_DEVICE_ID = 0x98,
> +	BCM53115_DEVICE_ID = 0x53115,
> +	BCM53125_DEVICE_ID = 0x53125,
> +	BCM53128_DEVICE_ID = 0x53128,
> +	BCM63XX_DEVICE_ID = 0x6300,
> +	BCM53010_DEVICE_ID = 0x53010,
> +	BCM53011_DEVICE_ID = 0x53011,
> +	BCM53012_DEVICE_ID = 0x53012,
> +	BCM53018_DEVICE_ID = 0x53018,
> +	BCM53019_DEVICE_ID = 0x53019,
> +};
> +
> +#define B53_N_PORTS	9
> +#define B53_N_PORTS_25	6
> +
> +struct b53_vlan {
> +	unsigned int	members:B53_N_PORTS;
> +	unsigned int	untag:B53_N_PORTS;
> +};
> +
> +struct b53_port {
> +	struct b53_device *b53;
> +	struct net_device *ndev;
> +
> +	unsigned int port_number;
> +	unsigned int pvid:12;
> +};
> +
> +struct b53_chip_data;
> +
> +struct b53_device {
> +	/* registers access */
> +	struct mutex reg_mutex;
> +	const struct b53_io_ops *ops;
> +
> +	unsigned char dev_addr[ETH_ALEN];
> +	int port_count;
> +
> +	/* chip specific data */
> +	u32 chip_id;
> +	u8 core_rev;
> +	const struct b53_chip_data *chip;
> +	u8 cpu_port;
> +	u16 enabled_ports;
> +	int reset_gpio;
> +
> +	/* connect specific data */
> +	u8 current_page;
> +	struct device *dev;
> +	void *priv;
> +
> +	/* run time configuration */
> +	unsigned enable_vlan:1;
> +	unsigned enable_jumbo:1;
> +	unsigned allow_vid_4095:1;
> +
> +	struct b53_port **ports;
> +	struct b53_vlan *vlans;
> +
> +	char *buf;
> +};
> +
> +#define b53_for_each_port(dev, i) \
> +	for (i = 0; i < B53_N_PORTS; i++) \
> +		if (dev->enabled_ports & BIT(i))
> +
> +static inline int is5325(struct b53_device *dev)
> +{
> +	return dev->chip_id == BCM5325_DEVICE_ID;
> +}
> +
> +static inline int is5365(struct b53_device *dev)
> +{
> +#ifdef CONFIG_BCM47XX
> +	return dev->chip_id == BCM5365_DEVICE_ID;
> +#else
> +	return 0;
> +#endif
> +}
> +
> +static inline int is5397_98(struct b53_device *dev)
> +{
> +	return dev->chip_id == BCM5397_DEVICE_ID ||
> +	       dev->chip_id == BCM5398_DEVICE_ID;
> +}
> +
> +static inline int is539x(struct b53_device *dev)
> +{
> +	return dev->chip_id == BCM5395_DEVICE_ID ||
> +	       dev->chip_id == BCM5397_DEVICE_ID ||
> +	       dev->chip_id == BCM5398_DEVICE_ID;
> +}
> +
> +static inline int is531x5(struct b53_device *dev)
> +{
> +	return dev->chip_id == BCM53115_DEVICE_ID ||
> +		dev->chip_id == BCM53125_DEVICE_ID ||
> +		dev->chip_id == BCM53128_DEVICE_ID;
> +}
> +
> +static inline int is63xx(struct b53_device *dev)
> +{
> +#ifdef CONFIG_BCM63XX
> +	return dev->chip_id == BCM63XX_DEVICE_ID;
> +#else
> +	return 0;
> +#endif
> +}
> +
> +static inline int is5301x(struct b53_device *dev)
> +{
> +	return dev->chip_id == BCM53010_DEVICE_ID ||
> +		dev->chip_id == BCM53011_DEVICE_ID ||
> +		dev->chip_id == BCM53012_DEVICE_ID ||
> +		dev->chip_id == BCM53018_DEVICE_ID ||
> +		dev->chip_id == BCM53019_DEVICE_ID;
> +}
> +
> +#define B53_CPU_PORT_25	5
> +#define B53_CPU_PORT	8
> +
> +static inline int is_cpu_port(struct b53_device *dev, int port)
> +{
> +	return dev->cpu_port == port;
> +}
> +
> +struct b53_device *b53_switch_alloc(struct device *base, struct b53_io_ops *ops,
> +				    void *priv);
> +
> +int b53_switch_detect(struct b53_device *dev);
> +
> +int b53_switch_register(struct b53_device *dev);
> +
> +void b53_switch_exit(struct b53_device *b53);
> +
> +static inline int b53_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val)
> +{
> +	int ret;
> +
> +	mutex_lock(&dev->reg_mutex);
> +	ret = dev->ops->read8(dev, page, reg, val);
> +	mutex_unlock(&dev->reg_mutex);
> +
> +	return ret;
> +}
> +
> +static inline int b53_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val)
> +{
> +	int ret;
> +
> +	mutex_lock(&dev->reg_mutex);
> +	ret = dev->ops->read16(dev, page, reg, val);
> +	mutex_unlock(&dev->reg_mutex);
> +
> +	return ret;
> +}
> +
> +static inline int b53_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val)
> +{
> +	int ret;
> +
> +	mutex_lock(&dev->reg_mutex);
> +	ret = dev->ops->read32(dev, page, reg, val);
> +	mutex_unlock(&dev->reg_mutex);
> +
> +	return ret;
> +}
> +
> +static inline int b53_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val)
> +{
> +	int ret;
> +
> +	mutex_lock(&dev->reg_mutex);
> +	ret = dev->ops->read48(dev, page, reg, val);
> +	mutex_unlock(&dev->reg_mutex);
> +
> +	return ret;
> +}
> +
> +static inline int b53_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val)
> +{
> +	int ret;
> +
> +	mutex_lock(&dev->reg_mutex);
> +	ret = dev->ops->read64(dev, page, reg, val);
> +	mutex_unlock(&dev->reg_mutex);
> +
> +	return ret;
> +}
> +
> +static inline int b53_write8(struct b53_device *dev, u8 page, u8 reg, u8 value)
> +{
> +	int ret;
> +
> +	mutex_lock(&dev->reg_mutex);
> +	ret = dev->ops->write8(dev, page, reg, value);
> +	mutex_unlock(&dev->reg_mutex);
> +
> +	return ret;
> +}
> +
> +static inline int b53_write16(struct b53_device *dev, u8 page, u8 reg,
> +			      u16 value)
> +{
> +	int ret;
> +
> +	mutex_lock(&dev->reg_mutex);
> +	ret = dev->ops->write16(dev, page, reg, value);
> +	mutex_unlock(&dev->reg_mutex);
> +
> +	return ret;
> +}
> +
> +static inline int b53_write32(struct b53_device *dev, u8 page, u8 reg,
> +			      u32 value)
> +{
> +	int ret;
> +
> +	mutex_lock(&dev->reg_mutex);
> +	ret = dev->ops->write32(dev, page, reg, value);
> +	mutex_unlock(&dev->reg_mutex);
> +
> +	return ret;
> +}
> +
> +static inline int b53_write48(struct b53_device *dev, u8 page, u8 reg,
> +			      u64 value)
> +{
> +	int ret;
> +
> +	mutex_lock(&dev->reg_mutex);
> +	ret = dev->ops->write48(dev, page, reg, value);
> +	mutex_unlock(&dev->reg_mutex);
> +
> +	return ret;
> +}
> +
> +static inline int b53_write64(struct b53_device *dev, u8 page, u8 reg,
> +			      u64 value)
> +{
> +	int ret;
> +
> +	mutex_lock(&dev->reg_mutex);
> +	ret = dev->ops->write64(dev, page, reg, value);
> +	mutex_unlock(&dev->reg_mutex);
> +
> +	return ret;
> +}
> +
> +static inline int b53_switch_get_reset_gpio(struct b53_device *dev)
> +{
> +	return -ENOENT;
> +}
> +
> +#endif
> diff --git a/drivers/net/phy/b53/b53_regs.h b/drivers/net/phy/b53/b53_regs.h
> new file mode 100644
> index 0000000..ba50915
> --- /dev/null
> +++ b/drivers/net/phy/b53/b53_regs.h
> @@ -0,0 +1,313 @@
> +/*
> + * B53 register definitions
> + *
> + * Copyright (C) 2004 Broadcom Corporation
> + * Copyright (C) 2011-2013 Jonas Gorski <jogo@openwrt.org>
> + *
> + * 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.
> + */
> +
> +#ifndef __B53_REGS_H
> +#define __B53_REGS_H
> +
> +/* Management Port (SMP) Page offsets */
> +#define B53_CTRL_PAGE			0x00 /* Control */
> +#define B53_STAT_PAGE			0x01 /* Status */
> +#define B53_MGMT_PAGE			0x02 /* Management Mode */
> +#define B53_MIB_AC_PAGE			0x03 /* MIB Autocast */
> +#define B53_ARLCTRL_PAGE		0x04 /* ARL Control */
> +#define B53_ARLIO_PAGE			0x05 /* ARL Access */
> +#define B53_FRAMEBUF_PAGE		0x06 /* Management frame access */
> +#define B53_MEM_ACCESS_PAGE		0x08 /* Memory access */
> +
> +/* PHY Registers */
> +#define B53_PORT_MII_PAGE(i)		(0x10 + i) /* Port i MII Registers */
> +#define B53_IM_PORT_PAGE		0x18 /* Inverse MII Port (to EMAC) */
> +#define B53_ALL_PORT_PAGE		0x19 /* All ports MII (broadcast) */
> +
> +/* MIB registers */
> +#define B53_MIB_PAGE(i)			(0x20 + i)
> +
> +/* Quality of Service (QoS) Registers */
> +#define B53_QOS_PAGE			0x30
> +
> +/* Port VLAN Page */
> +#define B53_PVLAN_PAGE			0x31
> +
> +/* VLAN Registers */
> +#define B53_VLAN_PAGE			0x34
> +
> +/* Jumbo Frame Registers */
> +#define B53_JUMBO_PAGE			0x40
> +
> +/*************************************************************************
> + * Control Page registers
> + *************************************************************************/
> +
> +/* Port Control Register (8 bit) */
> +#define B53_PORT_CTRL(i)		(0x00 + i)
> +#define   PORT_CTRL_RX_DISABLE		BIT(0)
> +#define   PORT_CTRL_TX_DISABLE		BIT(1)
> +#define   PORT_CTRL_RX_BCST_EN		BIT(2) /* Broadcast RX (P8 only) */
> +#define   PORT_CTRL_RX_MCST_EN		BIT(3) /* Multicast RX (P8 only) */
> +#define   PORT_CTRL_RX_UCST_EN		BIT(4) /* Unicast RX (P8 only) */
> +#define	  PORT_CTRL_STP_STATE_S		5
> +#define   PORT_CTRL_STP_STATE_MASK	(0x3 << PORT_CTRL_STP_STATE_S)
> +
> +/* SMP Control Register (8 bit) */
> +#define B53_SMP_CTRL			0x0a
> +
> +/* Switch Mode Control Register (8 bit) */
> +#define B53_SWITCH_MODE			0x0b
> +#define   SM_SW_FWD_MODE		BIT(0)	/* 1 = Managed Mode */
> +#define   SM_SW_FWD_EN			BIT(1)	/* Forwarding Enable */
> +
> +/* IMP Port state override register (8 bit) */
> +#define B53_PORT_OVERRIDE_CTRL		0x0e
> +#define   PORT_OVERRIDE_LINK		BIT(0)
> +#define   PORT_OVERRIDE_HALF_DUPLEX	BIT(1) /* 0 = Full Duplex */
> +#define   PORT_OVERRIDE_SPEED_S		2
> +#define   PORT_OVERRIDE_SPEED_10M	(0 << PORT_OVERRIDE_SPEED_S)
> +#define   PORT_OVERRIDE_SPEED_100M	(1 << PORT_OVERRIDE_SPEED_S)
> +#define   PORT_OVERRIDE_SPEED_1000M	(2 << PORT_OVERRIDE_SPEED_S)
> +#define   PORT_OVERRIDE_RV_MII_25	BIT(4) /* BCM5325 only */
> +#define   PORT_OVERRIDE_RX_FLOW		BIT(4)
> +#define   PORT_OVERRIDE_TX_FLOW		BIT(5)
> +#define   PORT_OVERRIDE_EN		BIT(7) /* Use the register contents */
> +
> +/* Power-down mode control */
> +#define B53_PD_MODE_CTRL_25		0x0f
> +
> +/* IP Multicast control (8 bit) */
> +#define B53_IP_MULTICAST_CTRL		0x21
> +#define  B53_IPMC_FWD_EN		BIT(1)
> +#define  B53_UC_FWD_EN			BIT(6)
> +#define  B53_MC_FWD_EN			BIT(7)
> +
> +/* (16 bit) */
> +#define B53_UC_FLOOD_MASK		0x32
> +#define B53_MC_FLOOD_MASK		0x34
> +#define B53_IPMC_FLOOD_MASK		0x36
> +
> +/* Software reset register (8 bit) */
> +#define B53_SOFTRESET			0x79
> +
> +/* Fast Aging Control register (8 bit) */
> +#define B53_FAST_AGE_CTRL		0x88
> +#define   FAST_AGE_STATIC		BIT(0)
> +#define   FAST_AGE_DYNAMIC		BIT(1)
> +#define   FAST_AGE_PORT			BIT(2)
> +#define   FAST_AGE_VLAN			BIT(3)
> +#define   FAST_AGE_STP			BIT(4)
> +#define   FAST_AGE_MC			BIT(5)
> +#define   FAST_AGE_DONE			BIT(7)
> +
> +/*************************************************************************
> + * Status Page registers
> + *************************************************************************/
> +
> +/* Link Status Summary Register (16bit) */
> +#define B53_LINK_STAT			0x00
> +
> +/* Link Status Change Register (16 bit) */
> +#define B53_LINK_STAT_CHANGE		0x02
> +
> +/* Port Speed Summary Register (16 bit for FE, 32 bit for GE) */
> +#define B53_SPEED_STAT			0x04
> +#define  SPEED_PORT_FE(reg, port)	(((reg) >> (port)) & 1)
> +#define  SPEED_PORT_GE(reg, port)	(((reg) >> 2 * (port)) & 3)
> +#define  SPEED_STAT_10M			0
> +#define  SPEED_STAT_100M		1
> +#define  SPEED_STAT_1000M		2
> +
> +/* Duplex Status Summary (16 bit) */
> +#define B53_DUPLEX_STAT_FE		0x06
> +#define B53_DUPLEX_STAT_GE		0x08
> +#define B53_DUPLEX_STAT_63XX		0x0c
> +
> +/* Revision ID register for BCM5325 */
> +#define B53_REV_ID_25			0x50
> +
> +/* Strap Value (48 bit) */
> +#define B53_STRAP_VALUE			0x70
> +#define   SV_GMII_CTRL_115		BIT(27)
> +
> +/*************************************************************************
> + * Management Mode Page Registers
> + *************************************************************************/
> +
> +/* Global Management Config Register (8 bit) */
> +#define B53_GLOBAL_CONFIG		0x00
> +#define   GC_RESET_MIB			0x01
> +#define   GC_RX_BPDU_EN			0x02
> +#define   GC_MIB_AC_HDR_EN		0x10
> +#define   GC_MIB_AC_EN			0x20
> +#define   GC_FRM_MGMT_PORT_M		0xC0
> +#define   GC_FRM_MGMT_PORT_04		0x00
> +#define   GC_FRM_MGMT_PORT_MII		0x80
> +
> +/* Device ID register (8 or 32 bit) */
> +#define B53_DEVICE_ID			0x30
> +
> +/* Revision ID register (8 bit) */
> +#define B53_REV_ID			0x40
> +
> +/*************************************************************************
> + * ARL Access Page Registers
> + *************************************************************************/
> +
> +/* VLAN Table Access Register (8 bit) */
> +#define B53_VT_ACCESS			0x80
> +#define B53_VT_ACCESS_9798		0x60 /* for BCM5397/BCM5398 */
> +#define B53_VT_ACCESS_63XX		0x60 /* for BCM6328/62/68 */
> +#define   VTA_CMD_WRITE			0
> +#define   VTA_CMD_READ			1
> +#define   VTA_CMD_CLEAR			2
> +#define   VTA_START_CMD			BIT(7)
> +
> +/* VLAN Table Index Register (16 bit) */
> +#define B53_VT_INDEX			0x81
> +#define B53_VT_INDEX_9798		0x61
> +#define B53_VT_INDEX_63XX		0x62
> +
> +/* VLAN Table Entry Register (32 bit) */
> +#define B53_VT_ENTRY			0x83
> +#define B53_VT_ENTRY_9798		0x63
> +#define B53_VT_ENTRY_63XX		0x64
> +#define   VTE_MEMBERS			0x1ff
> +#define   VTE_UNTAG_S			9
> +#define   VTE_UNTAG			(0x1ff << 9)
> +
> +/*************************************************************************
> + * Port VLAN Registers
> + *************************************************************************/
> +
> +/* Port VLAN mask (16 bit) IMP port is always 8, also on 5325 & co */
> +#define B53_PVLAN_PORT_MASK(i)		((i) * 2)
> +
> +/*************************************************************************
> + * 802.1Q Page Registers
> + *************************************************************************/
> +
> +/* Global QoS Control (8 bit) */
> +#define B53_QOS_GLOBAL_CTL		0x00
> +
> +/* Enable 802.1Q for individual Ports (16 bit) */
> +#define B53_802_1P_EN			0x04
> +
> +/*************************************************************************
> + * VLAN Page Registers
> + *************************************************************************/
> +
> +/* VLAN Control 0 (8 bit) */
> +#define B53_VLAN_CTRL0			0x00
> +#define   VC0_8021PF_CTRL_MASK		0x3
> +#define   VC0_8021PF_CTRL_NONE		0x0
> +#define   VC0_8021PF_CTRL_CHANGE_PRI	0x1
> +#define   VC0_8021PF_CTRL_CHANGE_VID	0x2
> +#define   VC0_8021PF_CTRL_CHANGE_BOTH	0x3
> +#define   VC0_8021QF_CTRL_MASK		0xc
> +#define   VC0_8021QF_CTRL_CHANGE_PRI	0x1
> +#define   VC0_8021QF_CTRL_CHANGE_VID	0x2
> +#define   VC0_8021QF_CTRL_CHANGE_BOTH	0x3
> +#define   VC0_RESERVED_1		BIT(1)
> +#define   VC0_DROP_VID_MISS		BIT(4)
> +#define   VC0_VID_HASH_VID		BIT(5)
> +#define   VC0_VID_CHK_EN		BIT(6)	/* Use VID,DA or VID,SA */
> +#define   VC0_VLAN_EN			BIT(7)	/* 802.1Q VLAN Enabled */
> +
> +/* VLAN Control 1 (8 bit) */
> +#define B53_VLAN_CTRL1			0x01
> +#define   VC1_RX_MCST_TAG_EN		BIT(1)
> +#define   VC1_RX_MCST_FWD_EN		BIT(2)
> +#define   VC1_RX_MCST_UNTAG_EN		BIT(3)
> +
> +/* VLAN Control 2 (8 bit) */
> +#define B53_VLAN_CTRL2			0x02
> +
> +/* VLAN Control 3 (8 bit when BCM5325, 16 bit else) */
> +#define B53_VLAN_CTRL3			0x03
> +#define B53_VLAN_CTRL3_63XX		0x04
> +#define   VC3_MAXSIZE_1532		BIT(6) /* 5325 only */
> +#define   VC3_HIGH_8BIT_EN		BIT(7) /* 5325 only */
> +
> +/* VLAN Control 4 (8 bit) */
> +#define B53_VLAN_CTRL4			0x05
> +#define B53_VLAN_CTRL4_25		0x04
> +#define B53_VLAN_CTRL4_63XX		0x06
> +#define   VC4_ING_VID_CHECK_S		6
> +#define   VC4_ING_VID_CHECK_MASK	(0x3 << VC4_ING_VID_CHECK_S)
> +#define   VC4_ING_VID_VIO_FWD		0 /* forward, but do not learn */
> +#define   VC4_ING_VID_VIO_DROP		1 /* drop VID violations */
> +#define   VC4_NO_ING_VID_CHK		2 /* do not check */
> +#define   VC4_ING_VID_VIO_TO_IMP	3 /* redirect to MII port */
> +
> +/* VLAN Control 5 (8 bit) */
> +#define B53_VLAN_CTRL5			0x06
> +#define B53_VLAN_CTRL5_25		0x05
> +#define B53_VLAN_CTRL5_63XX		0x07
> +#define   VC5_VID_FFF_EN		BIT(2)
> +#define   VC5_DROP_VTABLE_MISS		BIT(3)
> +
> +/* VLAN Control 6 (8 bit) */
> +#define B53_VLAN_CTRL6			0x07
> +#define B53_VLAN_CTRL6_63XX		0x08
> +
> +/* VLAN Table Access Register (16 bit) */
> +#define B53_VLAN_TABLE_ACCESS_25	0x06	/* BCM5325E/5350 */
> +#define B53_VLAN_TABLE_ACCESS_65	0x08	/* BCM5365 */
> +#define   VTA_VID_LOW_MASK_25		0xf
> +#define   VTA_VID_LOW_MASK_65		0xff
> +#define   VTA_VID_HIGH_S_25		4
> +#define   VTA_VID_HIGH_S_65		8
> +#define   VTA_VID_HIGH_MASK_25		(0xff << VTA_VID_HIGH_S_25E)
> +#define   VTA_VID_HIGH_MASK_65		(0xf << VTA_VID_HIGH_S_65)
> +#define   VTA_RW_STATE			BIT(12)
> +#define   VTA_RW_STATE_RD		0
> +#define   VTA_RW_STATE_WR		BIT(12)
> +#define   VTA_RW_OP_EN			BIT(13)
> +
> +/* VLAN Read/Write Registers for (16/32 bit) */
> +#define B53_VLAN_WRITE_25		0x08
> +#define B53_VLAN_WRITE_65		0x0a
> +#define B53_VLAN_READ			0x0c
> +#define   VA_MEMBER_MASK		0x3f
> +#define   VA_UNTAG_S_25			6
> +#define   VA_UNTAG_MASK_25		0x3f
> +#define   VA_UNTAG_S_65			7
> +#define   VA_UNTAG_MASK_65		0x1f
> +#define   VA_VID_HIGH_S			12
> +#define   VA_VID_HIGH_MASK		(0xffff << VA_VID_HIGH_S)
> +#define   VA_VALID_25			BIT(20)
> +#define   VA_VALID_25_R4		BIT(24)
> +#define   VA_VALID_65			BIT(14)
> +
> +/* VLAN Port Default Tag (16 bit) */
> +#define B53_VLAN_PORT_DEF_TAG(i)	(0x10 + 2 * (i))
> +
> +/*************************************************************************
> + * Jumbo Frame Page Registers
> + *************************************************************************/
> +
> +/* Jumbo Enable Port Mask (bit i == port i enabled) (32 bit) */
> +#define B53_JUMBO_PORT_MASK		0x01
> +#define B53_JUMBO_PORT_MASK_63XX	0x04
> +#define   JPM_10_100_JUMBO_EN		BIT(24) /* GigE always enabled */
> +
> +/* Good Frame Max Size without 802.1Q TAG (16 bit) */
> +#define B53_JUMBO_MAX_SIZE		0x05
> +#define B53_JUMBO_MAX_SIZE_63XX		0x08
> +#define   JMS_MIN_SIZE			1518
> +#define   JMS_MAX_SIZE			9724
> +
> +#endif /* !__B53_REGS_H */
> 


-- 
Florian

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH] net: phy: b53: switchdev driver for Broadcom BCM53xx switches
  2015-02-24 22:30 ` Andy Gospodarek
@ 2015-02-24 22:50   ` Rafał Miłecki
  2015-02-24 22:55     ` Florian Fainelli
  0 siblings, 1 reply; 42+ messages in thread
From: Rafał Miłecki @ 2015-02-24 22:50 UTC (permalink / raw)
  To: Andy Gospodarek
  Cc: David S. Miller, Network Development, Jonas Gorski,
	Florian Fainelli, Hauke Mehrtens, Felix Fietkau, Jiri Pirko

On 24 February 2015 at 23:30, Andy Gospodarek <gospo@cumulusnetworks.com> wrote:
> On Tue, Feb 24, 2015 at 06:42:07PM +0100, Rafał Miłecki wrote:
>> BCM53xx is series of Broadcom Ethernet switches that can be found in
>> various (mostly home) routers.
>> They are quite simple switches with mainly just support for:
>> 1) Tagging incoming packets (PVID)
>> 2) Untagging outgoing packets
>> 3) Forwarding all packets across a single VLAN
>>
>> This driver is split into common code (module) and bus specific code.
>> Right now only PHY (MDIO) support is included, other could follow after
>> accepting this driver. It was successfully tested on BCM4706 SoC with
>> BCM53125.
>>
>> You could notice it's yet another try of submitting b53 driver. This
>> time it was modified to use recently introduced switchdev API which
>> hopefully make it possible to accept it mainline.
>
> I must confess I do not know the entire history of this driver, but I
> have a few comments....

I guess previous discussions were mostly focusing on API (like
swconfig), so a good review of b53 is still highly wanted!


>> diff --git a/drivers/net/phy/b53/b53_common.c b/drivers/net/phy/b53/b53_common.c
>> new file mode 100644
>> index 0000000..fce6b71
>> --- /dev/null
>> +++ b/drivers/net/phy/b53/b53_common.c
> [...]
>> +
>> +/*****************
>> + * Net device ops
>> + *****************/
>> +
>> +static netdev_tx_t b53_port_xmit(struct sk_buff *skb, struct net_device *dev)
>> +{
>> +     dev_kfree_skb(skb);
>> +     dev->stats.tx_dropped++;
>> +
>> +     return NETDEV_TX_OK;
>> +}
>> +
>> (...)
>> +
>> +static const struct net_device_ops b53_port_netdev_ops = {
>> +     .ndo_start_xmit                 = b53_port_xmit,
>> +     .ndo_vlan_rx_add_vid            = b53_port_vlan_rx_add_vid,
>> +     .ndo_vlan_rx_kill_vid           = b53_port_vlan_rx_kill_vid,
>> +     .ndo_switch_parent_id_get       = b53_port_switch_parent_id_get,
>> +     .ndo_bridge_setlink             = b53_port_bridge_setlink,
>> +};
>
> I see there is an xmit function, but no napi registration at all.
>
> Is this simply because the SoC ethernet dev is doing all the frame rx?
> Is is able to demux the frames correctly, so it is clear which swXpY
> received the frame?  That will be necessary to ensure that standard
> applications that want to open sockets directly on the needed interfaces
> can still function properly.

If you take a look at b53_port_xmit you'll start understanding why
there is no NAPI ;)

As said in the commit message, these switches are really simple
devices. We can't actually send packets to the particular ports
(unless something has changed in the more recent hardware). We also
don't receive any packets from the switch itself! Really, switch
doesn't give as any IRQ when receiving frame, it doesn't put it in any
memory (DMA) we could access.
So we can't even consider knowing which port has received the frame.

So if we want to get any packets from switch port N we have to:
1) Assign some PVID to the port N
2) Put port N and "CPU port" in the same VLAN (matching PVID)
3) Starting with above switch will tag every packet received on port N
and forward it to the "CPU port"
4) Listen on the Ethernet device connected to the "CPU port" for
packets with a proper VLAN ID

Now with the above example there are 2 most common scenarios you may
want to consider:

1) Having full control over every port
It requires assigning unique VLAN for every single port. Any switching
(forwarding packets) has to be done in software then.

2) Having few groups of ports
This is the most common case for home routers. You usually want to
have group of "LAN" ports when you don't really care which port
provided a given packet. This also allows using switch for offloading
traffic between machines the same ports group.

So all this driver really does it allowing us to *configure* the
switch. It doesn't handle any RX/TX.

-- 
Rafał

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH] net: phy: b53: switchdev driver for Broadcom BCM53xx switches
  2015-02-24 22:50   ` Rafał Miłecki
@ 2015-02-24 22:55     ` Florian Fainelli
  2015-02-25  0:15       ` Andrew Lunn
  2015-02-25  6:44       ` Rafał Miłecki
  0 siblings, 2 replies; 42+ messages in thread
From: Florian Fainelli @ 2015-02-24 22:55 UTC (permalink / raw)
  To: Rafał Miłecki, Andy Gospodarek
  Cc: David S. Miller, Network Development, Jonas Gorski,
	Hauke Mehrtens, Felix Fietkau, Jiri Pirko

On 24/02/15 14:50, Rafał Miłecki wrote:
> On 24 February 2015 at 23:30, Andy Gospodarek <gospo@cumulusnetworks.com> wrote:
>> On Tue, Feb 24, 2015 at 06:42:07PM +0100, Rafał Miłecki wrote:
>>> BCM53xx is series of Broadcom Ethernet switches that can be found in
>>> various (mostly home) routers.
>>> They are quite simple switches with mainly just support for:
>>> 1) Tagging incoming packets (PVID)
>>> 2) Untagging outgoing packets
>>> 3) Forwarding all packets across a single VLAN
>>>
>>> This driver is split into common code (module) and bus specific code.
>>> Right now only PHY (MDIO) support is included, other could follow after
>>> accepting this driver. It was successfully tested on BCM4706 SoC with
>>> BCM53125.
>>>
>>> You could notice it's yet another try of submitting b53 driver. This
>>> time it was modified to use recently introduced switchdev API which
>>> hopefully make it possible to accept it mainline.
>>
>> I must confess I do not know the entire history of this driver, but I
>> have a few comments....
> 
> I guess previous discussions were mostly focusing on API (like
> swconfig), so a good review of b53 is still highly wanted!
> 
> 
>>> diff --git a/drivers/net/phy/b53/b53_common.c b/drivers/net/phy/b53/b53_common.c
>>> new file mode 100644
>>> index 0000000..fce6b71
>>> --- /dev/null
>>> +++ b/drivers/net/phy/b53/b53_common.c
>> [...]
>>> +
>>> +/*****************
>>> + * Net device ops
>>> + *****************/
>>> +
>>> +static netdev_tx_t b53_port_xmit(struct sk_buff *skb, struct net_device *dev)
>>> +{
>>> +     dev_kfree_skb(skb);
>>> +     dev->stats.tx_dropped++;
>>> +
>>> +     return NETDEV_TX_OK;
>>> +}
>>> +
>>> (...)
>>> +
>>> +static const struct net_device_ops b53_port_netdev_ops = {
>>> +     .ndo_start_xmit                 = b53_port_xmit,
>>> +     .ndo_vlan_rx_add_vid            = b53_port_vlan_rx_add_vid,
>>> +     .ndo_vlan_rx_kill_vid           = b53_port_vlan_rx_kill_vid,
>>> +     .ndo_switch_parent_id_get       = b53_port_switch_parent_id_get,
>>> +     .ndo_bridge_setlink             = b53_port_bridge_setlink,
>>> +};
>>
>> I see there is an xmit function, but no napi registration at all.
>>
>> Is this simply because the SoC ethernet dev is doing all the frame rx?
>> Is is able to demux the frames correctly, so it is clear which swXpY
>> received the frame?  That will be necessary to ensure that standard
>> applications that want to open sockets directly on the needed interfaces
>> can still function properly.
> 
> If you take a look at b53_port_xmit you'll start understanding why
> there is no NAPI ;)
> 
> As said in the commit message, these switches are really simple
> devices. We can't actually send packets to the particular ports
> (unless something has changed in the more recent hardware).

These switches all support Broadcom tags, so you could use your host CPU
Ethernet MAC to send/receive packets to/from specific ports of the
switch, and then this is just like DSA, but everything that you say
below is true.

> We also
> don't receive any packets from the switch itself! Really, switch
> doesn't give as any IRQ when receiving frame, it doesn't put it in any
> memory (DMA) we could access.
> So we can't even consider knowing which port has received the frame.

If you ever wanted to use Broadcom tags, your CPU Ethernet MAC would
receive packets and be able to deliver them to per-port net_devices, but
the physical packets are indeed received from your host CPU Ethernet MAC
and transfered by it into DRAM.

> 
> So if we want to get any packets from switch port N we have to:
> 1) Assign some PVID to the port N
> 2) Put port N and "CPU port" in the same VLAN (matching PVID)
> 3) Starting with above switch will tag every packet received on port N
> and forward it to the "CPU port"
> 4) Listen on the Ethernet device connected to the "CPU port" for
> packets with a proper VLAN ID
> 
> Now with the above example there are 2 most common scenarios you may
> want to consider:
> 
> 1) Having full control over every port
> It requires assigning unique VLAN for every single port. Any switching
> (forwarding packets) has to be done in software then.
> 
> 2) Having few groups of ports
> This is the most common case for home routers. You usually want to
> have group of "LAN" ports when you don't really care which port
> provided a given packet. This also allows using switch for offloading
> traffic between machines the same ports group.

With that use case in mind, yes, your driver is doing exactly that,
allowing you to define VLAN membership for particular ports within a
group, all of this gets sent to the host CPU, where the IP routing happens.

> 
> So all this driver really does it allowing us to *configure* the
> switch. It doesn't handle any RX/TX.
> 


-- 
Florian

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH] net: phy: b53: switchdev driver for Broadcom BCM53xx switches
  2015-02-24 22:48 ` Florian Fainelli
@ 2015-02-24 22:56   ` Rafał Miłecki
  2015-02-24 22:59     ` Florian Fainelli
  2015-02-25  2:10   ` David Miller
  1 sibling, 1 reply; 42+ messages in thread
From: Rafał Miłecki @ 2015-02-24 22:56 UTC (permalink / raw)
  To: Florian Fainelli
  Cc: David S. Miller, Network Development, Jonas Gorski,
	Hauke Mehrtens, Felix Fietkau, Jiri Pirko

On 24 February 2015 at 23:48, Florian Fainelli <f.fainelli@gmail.com> wrote:
> On 24/02/15 09:42, Rafał Miłecki wrote:
>> BCM53xx is series of Broadcom Ethernet switches that can be found in
>> various (mostly home) routers.
>> They are quite simple switches with mainly just support for:
>> 1) Tagging incoming packets (PVID)
>> 2) Untagging outgoing packets
>> 3) Forwarding all packets across a single VLAN
>>
>> This driver is split into common code (module) and bus specific code.
>> Right now only PHY (MDIO) support is included, other could follow after
>> accepting this driver. It was successfully tested on BCM4706 SoC with
>> BCM53125.
>>
>> You could notice it's yet another try of submitting b53 driver. This
>> time it was modified to use recently introduced switchdev API which
>> hopefully make it possible to accept it mainline.
>
> This is good as a very basic driver,

Thanks :) That was exactly my point: to get a minimal driver (but
implementing the basic functionality!) accepted and then continue
improving it.


> there is still a bunch of things
> missing that might not be too hard to add to this submission:
>
> - fetching MIB counters through ethtool
> - reporting link state/parameters
> - changing MTU/Jumbo frame support
> - HW bridging support

I agree about missing features. I was already thinking about MIB, it
should be easy to support it with ethtool_ops and get_sset_count +
get_strings. Probably the same for link status. Not sure about HW
bridging.

Would you agree to work on having this basic driver accepted first
(like discussing code location, API usage) and then work on additional
features in separated patches? I think it would simplify the process
and could result in better core review, as people could focus on small
bunch of changes.

-- 
Rafał

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH] net: phy: b53: switchdev driver for Broadcom BCM53xx switches
  2015-02-24 22:56   ` Rafał Miłecki
@ 2015-02-24 22:59     ` Florian Fainelli
  0 siblings, 0 replies; 42+ messages in thread
From: Florian Fainelli @ 2015-02-24 22:59 UTC (permalink / raw)
  To: Rafał Miłecki
  Cc: David S. Miller, Network Development, Jonas Gorski,
	Hauke Mehrtens, Felix Fietkau, Jiri Pirko

On 24/02/15 14:56, Rafał Miłecki wrote:
> On 24 February 2015 at 23:48, Florian Fainelli <f.fainelli@gmail.com> wrote:
>> On 24/02/15 09:42, Rafał Miłecki wrote:
>>> BCM53xx is series of Broadcom Ethernet switches that can be found in
>>> various (mostly home) routers.
>>> They are quite simple switches with mainly just support for:
>>> 1) Tagging incoming packets (PVID)
>>> 2) Untagging outgoing packets
>>> 3) Forwarding all packets across a single VLAN
>>>
>>> This driver is split into common code (module) and bus specific code.
>>> Right now only PHY (MDIO) support is included, other could follow after
>>> accepting this driver. It was successfully tested on BCM4706 SoC with
>>> BCM53125.
>>>
>>> You could notice it's yet another try of submitting b53 driver. This
>>> time it was modified to use recently introduced switchdev API which
>>> hopefully make it possible to accept it mainline.
>>
>> This is good as a very basic driver,
> 
> Thanks :) That was exactly my point: to get a minimal driver (but
> implementing the basic functionality!) accepted and then continue
> improving it.
> 
> 
>> there is still a bunch of things
>> missing that might not be too hard to add to this submission:
>>
>> - fetching MIB counters through ethtool
>> - reporting link state/parameters
>> - changing MTU/Jumbo frame support
>> - HW bridging support
> 
> I agree about missing features. I was already thinking about MIB, it
> should be easy to support it with ethtool_ops and get_sset_count +
> get_strings. Probably the same for link status. Not sure about HW
> bridging.
> 
> Would you agree to work on having this basic driver accepted first
> (like discussing code location, API usage) and then work on additional
> features in separated patches? I think it would simplify the process
> and could result in better core review, as people could focus on small
> bunch of changes.

I would prefer if you could give me the time to implement that:
http://www.spinics.net/lists/netdev/msg295942.html

such that you would get a lot of the network device creation, operations
etc.. for free, with your driver still being a phy_driver ultimately.
But I have no strong objections either.
-- 
Florian

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH] net: phy: b53: switchdev driver for Broadcom BCM53xx switches
  2015-02-24 22:55     ` Florian Fainelli
@ 2015-02-25  0:15       ` Andrew Lunn
  2015-02-25  0:39         ` Florian Fainelli
  2015-02-25  6:44       ` Rafał Miłecki
  1 sibling, 1 reply; 42+ messages in thread
From: Andrew Lunn @ 2015-02-25  0:15 UTC (permalink / raw)
  To: Florian Fainelli
  Cc: Rafa?? Mi??ecki, Andy Gospodarek, David S. Miller,
	Network Development, Jonas Gorski, Hauke Mehrtens, Felix Fietkau,
	Jiri Pirko

On Tue, Feb 24, 2015 at 02:55:58PM -0800, Florian Fainelli wrote:
> On 24/02/15 14:50, Rafa?? Mi??ecki wrote:
> > On 24 February 2015 at 23:30, Andy Gospodarek <gospo@cumulusnetworks.com> wrote:
> >> On Tue, Feb 24, 2015 at 06:42:07PM +0100, Rafa?? Mi??ecki wrote:
> >>> BCM53xx is series of Broadcom Ethernet switches that can be found in
> >>> various (mostly home) routers.
> >>> They are quite simple switches with mainly just support for:
> >>> 1) Tagging incoming packets (PVID)
> >>> 2) Untagging outgoing packets
> >>> 3) Forwarding all packets across a single VLAN
> >>>
> >>> This driver is split into common code (module) and bus specific code.
> >>> Right now only PHY (MDIO) support is included, other could follow after
> >>> accepting this driver. It was successfully tested on BCM4706 SoC with
> >>> BCM53125.
> >>>
> >>> You could notice it's yet another try of submitting b53 driver. This
> >>> time it was modified to use recently introduced switchdev API which
> >>> hopefully make it possible to accept it mainline.
> >>
> >> I must confess I do not know the entire history of this driver, but I
> >> have a few comments....
> > 
> > I guess previous discussions were mostly focusing on API (like
> > swconfig), so a good review of b53 is still highly wanted!
> > 
> > 
> >>> diff --git a/drivers/net/phy/b53/b53_common.c b/drivers/net/phy/b53/b53_common.c
> >>> new file mode 100644
> >>> index 0000000..fce6b71
> >>> --- /dev/null
> >>> +++ b/drivers/net/phy/b53/b53_common.c
> >> [...]
> >>> +
> >>> +/*****************
> >>> + * Net device ops
> >>> + *****************/
> >>> +
> >>> +static netdev_tx_t b53_port_xmit(struct sk_buff *skb, struct net_device *dev)
> >>> +{
> >>> +     dev_kfree_skb(skb);
> >>> +     dev->stats.tx_dropped++;
> >>> +
> >>> +     return NETDEV_TX_OK;
> >>> +}
> >>> +
> >>> (...)
> >>> +
> >>> +static const struct net_device_ops b53_port_netdev_ops = {
> >>> +     .ndo_start_xmit                 = b53_port_xmit,
> >>> +     .ndo_vlan_rx_add_vid            = b53_port_vlan_rx_add_vid,
> >>> +     .ndo_vlan_rx_kill_vid           = b53_port_vlan_rx_kill_vid,
> >>> +     .ndo_switch_parent_id_get       = b53_port_switch_parent_id_get,
> >>> +     .ndo_bridge_setlink             = b53_port_bridge_setlink,
> >>> +};
> >>
> >> I see there is an xmit function, but no napi registration at all.
> >>
> >> Is this simply because the SoC ethernet dev is doing all the frame rx?
> >> Is is able to demux the frames correctly, so it is clear which swXpY
> >> received the frame?  That will be necessary to ensure that standard
> >> applications that want to open sockets directly on the needed interfaces
> >> can still function properly.
> > 
> > If you take a look at b53_port_xmit you'll start understanding why
> > there is no NAPI ;)
> > 
> > As said in the commit message, these switches are really simple
> > devices. We can't actually send packets to the particular ports
> > (unless something has changed in the more recent hardware).
> 
> These switches all support Broadcom tags, so you could use your host CPU
> Ethernet MAC to send/receive packets to/from specific ports of the
> switch, and then this is just like DSA, but everything that you say
> below is true.

If this hardware does support the concept of tags compatible to the
existing Broadcom Starfighter 2, should we not do that? Is there a
good reason these chips should use a difference abstraction than
Starfighter 2 and the Marvell devices?

	    Andrew

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH] net: phy: b53: switchdev driver for Broadcom BCM53xx switches
  2015-02-25  0:15       ` Andrew Lunn
@ 2015-02-25  0:39         ` Florian Fainelli
  2015-02-25  7:03           ` Rafał Miłecki
  0 siblings, 1 reply; 42+ messages in thread
From: Florian Fainelli @ 2015-02-25  0:39 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Rafa?? Mi??ecki, Andy Gospodarek, David S. Miller,
	Network Development, Jonas Gorski, Hauke Mehrtens, Felix Fietkau,
	Jiri Pirko

On 24/02/15 16:15, Andrew Lunn wrote:
> On Tue, Feb 24, 2015 at 02:55:58PM -0800, Florian Fainelli wrote:
>> On 24/02/15 14:50, Rafa?? Mi??ecki wrote:
>>> On 24 February 2015 at 23:30, Andy Gospodarek <gospo@cumulusnetworks.com> wrote:
>>>> On Tue, Feb 24, 2015 at 06:42:07PM +0100, Rafa?? Mi??ecki wrote:
>>>>> BCM53xx is series of Broadcom Ethernet switches that can be found in
>>>>> various (mostly home) routers.
>>>>> They are quite simple switches with mainly just support for:
>>>>> 1) Tagging incoming packets (PVID)
>>>>> 2) Untagging outgoing packets
>>>>> 3) Forwarding all packets across a single VLAN
>>>>>
>>>>> This driver is split into common code (module) and bus specific code.
>>>>> Right now only PHY (MDIO) support is included, other could follow after
>>>>> accepting this driver. It was successfully tested on BCM4706 SoC with
>>>>> BCM53125.
>>>>>
>>>>> You could notice it's yet another try of submitting b53 driver. This
>>>>> time it was modified to use recently introduced switchdev API which
>>>>> hopefully make it possible to accept it mainline.
>>>>
>>>> I must confess I do not know the entire history of this driver, but I
>>>> have a few comments....
>>>
>>> I guess previous discussions were mostly focusing on API (like
>>> swconfig), so a good review of b53 is still highly wanted!
>>>
>>>
>>>>> diff --git a/drivers/net/phy/b53/b53_common.c b/drivers/net/phy/b53/b53_common.c
>>>>> new file mode 100644
>>>>> index 0000000..fce6b71
>>>>> --- /dev/null
>>>>> +++ b/drivers/net/phy/b53/b53_common.c
>>>> [...]
>>>>> +
>>>>> +/*****************
>>>>> + * Net device ops
>>>>> + *****************/
>>>>> +
>>>>> +static netdev_tx_t b53_port_xmit(struct sk_buff *skb, struct net_device *dev)
>>>>> +{
>>>>> +     dev_kfree_skb(skb);
>>>>> +     dev->stats.tx_dropped++;
>>>>> +
>>>>> +     return NETDEV_TX_OK;
>>>>> +}
>>>>> +
>>>>> (...)
>>>>> +
>>>>> +static const struct net_device_ops b53_port_netdev_ops = {
>>>>> +     .ndo_start_xmit                 = b53_port_xmit,
>>>>> +     .ndo_vlan_rx_add_vid            = b53_port_vlan_rx_add_vid,
>>>>> +     .ndo_vlan_rx_kill_vid           = b53_port_vlan_rx_kill_vid,
>>>>> +     .ndo_switch_parent_id_get       = b53_port_switch_parent_id_get,
>>>>> +     .ndo_bridge_setlink             = b53_port_bridge_setlink,
>>>>> +};
>>>>
>>>> I see there is an xmit function, but no napi registration at all.
>>>>
>>>> Is this simply because the SoC ethernet dev is doing all the frame rx?
>>>> Is is able to demux the frames correctly, so it is clear which swXpY
>>>> received the frame?  That will be necessary to ensure that standard
>>>> applications that want to open sockets directly on the needed interfaces
>>>> can still function properly.
>>>
>>> If you take a look at b53_port_xmit you'll start understanding why
>>> there is no NAPI ;)
>>>
>>> As said in the commit message, these switches are really simple
>>> devices. We can't actually send packets to the particular ports
>>> (unless something has changed in the more recent hardware).
>>
>> These switches all support Broadcom tags, so you could use your host CPU
>> Ethernet MAC to send/receive packets to/from specific ports of the
>> switch, and then this is just like DSA, but everything that you say
>> below is true.
> 
> If this hardware does support the concept of tags compatible to the
> existing Broadcom Starfighter 2, should we not do that? Is there a
> good reason these chips should use a difference abstraction than
> Starfighter 2 and the Marvell devices?

No, I think that would be a reasonable thing to do, I am still a little
unclear how the older BCM5325 and friends work with respect to broadcom
tags, but regardless, DSA now understands switches that do not support
tags, so we should be good with some sort of b53 library.
-- 
Florian

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH] net: phy: b53: switchdev driver for Broadcom BCM53xx switches
  2015-02-24 22:29   ` Rafał Miłecki
@ 2015-02-25  0:51     ` Andrew Lunn
  0 siblings, 0 replies; 42+ messages in thread
From: Andrew Lunn @ 2015-02-25  0:51 UTC (permalink / raw)
  To: Rafa?? Mi??ecki
  Cc: David S. Miller, Network Development, Jonas Gorski,
	Florian Fainelli, Hauke Mehrtens, Felix Fietkau, Jiri Pirko

> That said, I'm not aware of any better place for switchdev drivers.

Reading Florian's email, it seems like this should be placed into
drivers/net/dsa, and refactored to use the DSA API.

	 Andrew

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH] net: phy: b53: switchdev driver for Broadcom BCM53xx switches
  2015-02-24 22:48 ` Florian Fainelli
  2015-02-24 22:56   ` Rafał Miłecki
@ 2015-02-25  2:10   ` David Miller
  1 sibling, 0 replies; 42+ messages in thread
From: David Miller @ 2015-02-25  2:10 UTC (permalink / raw)
  To: f.fainelli; +Cc: zajec5, netdev, jogo, hauke, nbd, jiri


Florian, this is one of my pet peeves.

Do not quote an entire patch in an email reply when you just want to
make specific comments on specific portions of the change.

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH] net: phy: b53: switchdev driver for Broadcom BCM53xx switches
  2015-02-24 22:55     ` Florian Fainelli
  2015-02-25  0:15       ` Andrew Lunn
@ 2015-02-25  6:44       ` Rafał Miłecki
  1 sibling, 0 replies; 42+ messages in thread
From: Rafał Miłecki @ 2015-02-25  6:44 UTC (permalink / raw)
  To: Florian Fainelli
  Cc: Andy Gospodarek, David S. Miller, Network Development,
	Jonas Gorski, Hauke Mehrtens, Felix Fietkau, Jiri Pirko

On 24 February 2015 at 23:55, Florian Fainelli <f.fainelli@gmail.com> wrote:
> On 24/02/15 14:50, Rafał Miłecki wrote:
>> On 24 February 2015 at 23:30, Andy Gospodarek <gospo@cumulusnetworks.com> wrote:
>>> I see there is an xmit function, but no napi registration at all.
>>>
>>> Is this simply because the SoC ethernet dev is doing all the frame rx?
>>> Is is able to demux the frames correctly, so it is clear which swXpY
>>> received the frame?  That will be necessary to ensure that standard
>>> applications that want to open sockets directly on the needed interfaces
>>> can still function properly.
>>
>> If you take a look at b53_port_xmit you'll start understanding why
>> there is no NAPI ;)
>>
>> As said in the commit message, these switches are really simple
>> devices. We can't actually send packets to the particular ports
>> (unless something has changed in the more recent hardware).
>
> These switches all support Broadcom tags, so you could use your host CPU
> Ethernet MAC to send/receive packets to/from specific ports of the
> switch, and then this is just like DSA, but everything that you say
> below is true.

OK, I'll need to learn about Broadcom tags then. Right now this is a
bit unclear for me. Are Broadcom tags supposed to be used with VLANs
at the same time?

I can get idea of sending packets in such setup. We could send packets
using VLAN interface (with VLAN tag), packets would go to all ports
assigned to the VLAN. Or we should send packets using port interface
with adding Broadcom tag there. Such packets would target a single
port. Quite easy.

But how switch would handle receiving packets from ports? If we were
using Broadcom tags and VLANs at the same time, how switch would know
if the packets received on port N should get a VLAN tag (PVID) or
should get a Broadcom tag?


>> So if we want to get any packets from switch port N we have to:
>> 1) Assign some PVID to the port N
>> 2) Put port N and "CPU port" in the same VLAN (matching PVID)
>> 3) Starting with above switch will tag every packet received on port N
>> and forward it to the "CPU port"
>> 4) Listen on the Ethernet device connected to the "CPU port" for
>> packets with a proper VLAN ID
>>
>> Now with the above example there are 2 most common scenarios you may
>> want to consider:
>>
>> 1) Having full control over every port
>> It requires assigning unique VLAN for every single port. Any switching
>> (forwarding packets) has to be done in software then.
>>
>> 2) Having few groups of ports
>> This is the most common case for home routers. You usually want to
>> have group of "LAN" ports when you don't really care which port
>> provided a given packet. This also allows using switch for offloading
>> traffic between machines the same ports group.
>
> With that use case in mind, yes, your driver is doing exactly that,
> allowing you to define VLAN membership for particular ports within a
> group, all of this gets sent to the host CPU, where the IP routing happens.

Not really. Let's say I setup VLAN N with 3 members:
1) Port A with PVID N & UNTAGGED
2) Port B with PVID N & UNTAGGED
3) CPU port
If machine connected to port A will start sending traffic to machine
connected to port B, switch will do all the work. CPU won't be
involved.

Just for sure I've tested above and I got 650 Mb/s iperf traffic with
99% idle BCM4706 CPU.

-- 
Rafał

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH] net: phy: b53: switchdev driver for Broadcom BCM53xx switches
  2015-02-25  0:39         ` Florian Fainelli
@ 2015-02-25  7:03           ` Rafał Miłecki
  2015-02-25  8:07             ` Jiri Pirko
  2015-02-25 14:03             ` Andrew Lunn
  0 siblings, 2 replies; 42+ messages in thread
From: Rafał Miłecki @ 2015-02-25  7:03 UTC (permalink / raw)
  To: Florian Fainelli
  Cc: Andrew Lunn, Andy Gospodarek, David S. Miller,
	Network Development, Jonas Gorski, Hauke Mehrtens, Felix Fietkau,
	Jiri Pirko

On 25 February 2015 at 01:39, Florian Fainelli <f.fainelli@gmail.com> wrote:
> On 24/02/15 16:15, Andrew Lunn wrote:
>> On Tue, Feb 24, 2015 at 02:55:58PM -0800, Florian Fainelli wrote:
>>> On 24/02/15 14:50, Rafa?? Mi??ecki wrote:
>>>> As said in the commit message, these switches are really simple
>>>> devices. We can't actually send packets to the particular ports
>>>> (unless something has changed in the more recent hardware).
>>>
>>> These switches all support Broadcom tags, so you could use your host CPU
>>> Ethernet MAC to send/receive packets to/from specific ports of the
>>> switch, and then this is just like DSA, but everything that you say
>>> below is true.
>>
>> If this hardware does support the concept of tags compatible to the
>> existing Broadcom Starfighter 2, should we not do that? Is there a
>> good reason these chips should use a difference abstraction than
>> Starfighter 2 and the Marvell devices?
>
> No, I think that would be a reasonable thing to do, I am still a little
> unclear how the older BCM5325 and friends work with respect to broadcom
> tags, but regardless, DSA now understands switches that do not support
> tags, so we should be good with some sort of b53 library.

DSA doesn't allow me to use switch (hardware) VLANs. I would need to
handle all forwarding in CPU. The most powerful Broadcom MIPS SoC -
BCM4706 - can handle about 130 Mb/s. Less powerful - BCM4718A1 - only
about 50 Mb/s.
This is way too bad for performance when there is a 1 Gb/s switch and
too bad for CPU usage.

I guess the whole idea of switchdev was to allow what proposed version
of b53 does? To handle VLANs in hardware.

-- 
Rafał

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH] net: phy: b53: switchdev driver for Broadcom BCM53xx switches
  2015-02-25  7:03           ` Rafał Miłecki
@ 2015-02-25  8:07             ` Jiri Pirko
  2015-02-25 14:03             ` Andrew Lunn
  1 sibling, 0 replies; 42+ messages in thread
From: Jiri Pirko @ 2015-02-25  8:07 UTC (permalink / raw)
  To: Rafał Miłecki
  Cc: Florian Fainelli, Andrew Lunn, Andy Gospodarek, David S. Miller,
	Network Development, Jonas Gorski, Hauke Mehrtens, Felix Fietkau

Wed, Feb 25, 2015 at 08:03:48AM CET, zajec5@gmail.com wrote:
>On 25 February 2015 at 01:39, Florian Fainelli <f.fainelli@gmail.com> wrote:
>> On 24/02/15 16:15, Andrew Lunn wrote:
>>> On Tue, Feb 24, 2015 at 02:55:58PM -0800, Florian Fainelli wrote:
>>>> On 24/02/15 14:50, Rafa?? Mi??ecki wrote:
>>>>> As said in the commit message, these switches are really simple
>>>>> devices. We can't actually send packets to the particular ports
>>>>> (unless something has changed in the more recent hardware).
>>>>
>>>> These switches all support Broadcom tags, so you could use your host CPU
>>>> Ethernet MAC to send/receive packets to/from specific ports of the
>>>> switch, and then this is just like DSA, but everything that you say
>>>> below is true.
>>>
>>> If this hardware does support the concept of tags compatible to the
>>> existing Broadcom Starfighter 2, should we not do that? Is there a
>>> good reason these chips should use a difference abstraction than
>>> Starfighter 2 and the Marvell devices?
>>
>> No, I think that would be a reasonable thing to do, I am still a little
>> unclear how the older BCM5325 and friends work with respect to broadcom
>> tags, but regardless, DSA now understands switches that do not support
>> tags, so we should be good with some sort of b53 library.
>
>DSA doesn't allow me to use switch (hardware) VLANs. I would need to
>handle all forwarding in CPU. The most powerful Broadcom MIPS SoC -
>BCM4706 - can handle about 130 Mb/s. Less powerful - BCM4718A1 - only
>about 50 Mb/s.
>This is way too bad for performance when there is a 1 Gb/s switch and
>too bad for CPU usage.

Please correct me if I'm wrong Florian, but I believe that DSA does
allow setting up chips to do forwarding without packets going to CPU.

b53 looks like it fits nicely into DSA architecture. I believe that it
should be integrated there.

>
>I guess the whole idea of switchdev was to allow what proposed version
>of b53 does? To handle VLANs in hardware.
>
>-- 
>Rafał

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH] net: phy: b53: switchdev driver for Broadcom BCM53xx switches
  2015-02-25  7:03           ` Rafał Miłecki
  2015-02-25  8:07             ` Jiri Pirko
@ 2015-02-25 14:03             ` Andrew Lunn
  2015-02-25 14:17               ` Rafał Miłecki
  2015-02-25 15:46               ` Andy Gospodarek
  1 sibling, 2 replies; 42+ messages in thread
From: Andrew Lunn @ 2015-02-25 14:03 UTC (permalink / raw)
  To: Rafa?? Mi??ecki
  Cc: Florian Fainelli, Andy Gospodarek, David S. Miller,
	Network Development, Jonas Gorski, Hauke Mehrtens, Felix Fietkau,
	Jiri Pirko

> DSA doesn't allow me to use switch (hardware) VLANs. I would need to
> handle all forwarding in CPU. The most powerful Broadcom MIPS SoC -
> BCM4706 - can handle about 130 Mb/s. Less powerful - BCM4718A1 - only
> about 50 Mb/s.
> This is way too bad for performance when there is a 1 Gb/s switch and
> too bad for CPU usage.
 
Hi Rafa??

Take a step back. Don't assume VLANs is the only way to do this. Look
at what Florian is doing with Starfighter and Gunter is doing with
Marvell chips. Recent patches allow the hardware to do the switching
between ports with these devices. See if you can use a similar scheme
with your chip.

What we don't want is X chip families and Y different ways to
configure the features. Ideal we want X chip families, and one way to
configure them all.

	  Andrew

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH] net: phy: b53: switchdev driver for Broadcom BCM53xx switches
  2015-02-25 14:03             ` Andrew Lunn
@ 2015-02-25 14:17               ` Rafał Miłecki
  2015-02-25 14:19                 ` Andrew Lunn
  2015-02-25 15:46               ` Andy Gospodarek
  1 sibling, 1 reply; 42+ messages in thread
From: Rafał Miłecki @ 2015-02-25 14:17 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Florian Fainelli, Andy Gospodarek, David S. Miller,
	Network Development, Jonas Gorski, Hauke Mehrtens, Felix Fietkau,
	Jiri Pirko

On 25 February 2015 at 15:03, Andrew Lunn <andrew@lunn.ch> wrote:
>> DSA doesn't allow me to use switch (hardware) VLANs. I would need to
>> handle all forwarding in CPU. The most powerful Broadcom MIPS SoC -
>> BCM4706 - can handle about 130 Mb/s. Less powerful - BCM4718A1 - only
>> about 50 Mb/s.
>> This is way too bad for performance when there is a 1 Gb/s switch and
>> too bad for CPU usage.
>
> Hi Rafa??
>
> Take a step back. Don't assume VLANs is the only way to do this. Look
> at what Florian is doing with Starfighter and Gunter is doing with
> Marvell chips. Recent patches allow the hardware to do the switching
> between ports with these devices. See if you can use a similar scheme
> with your chip.
>
> What we don't want is X chip families and Y different ways to
> configure the features. Ideal we want X chip families, and one way to
> configure them all.

Now I know about Broadcom tag, I'm aware it's not the only way and you
can be sure I'm looking for the one, most common way of handling this.

What do you mean by these recent patches? Has DSA recently received a
support for bridging ports in the hardware? Like setting VLANs using
some "bridge" comment (nl API) or something? Because I'm not aware of
that.

-- 
Rafał

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH] net: phy: b53: switchdev driver for Broadcom BCM53xx switches
  2015-02-25 14:17               ` Rafał Miłecki
@ 2015-02-25 14:19                 ` Andrew Lunn
  2015-02-26 14:58                   ` Rafał Miłecki
  0 siblings, 1 reply; 42+ messages in thread
From: Andrew Lunn @ 2015-02-25 14:19 UTC (permalink / raw)
  To: Rafa?? Mi??ecki
  Cc: Florian Fainelli, Andy Gospodarek, David S. Miller,
	Network Development, Jonas Gorski, Hauke Mehrtens, Felix Fietkau,
	Jiri Pirko

> What do you mean by these recent patches? Has DSA recently received a
> support for bridging ports in the hardware? Like setting VLANs using
> some "bridge" comment (nl API) or something? Because I'm not aware of
> that.

Yes. Scan over netdev list for the last week. e.g:

http://comments.gmane.org/gmane.linux.network/350754

	Andrew

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH] net: phy: b53: switchdev driver for Broadcom BCM53xx switches
  2015-02-25 14:03             ` Andrew Lunn
  2015-02-25 14:17               ` Rafał Miłecki
@ 2015-02-25 15:46               ` Andy Gospodarek
  2015-02-25 17:23                 ` Rafał Miłecki
                                   ` (2 more replies)
  1 sibling, 3 replies; 42+ messages in thread
From: Andy Gospodarek @ 2015-02-25 15:46 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Rafa?? Mi??ecki, Florian Fainelli, David S. Miller,
	Network Development, Jonas Gorski, Hauke Mehrtens, Felix Fietkau,
	Jiri Pirko

On Wed, Feb 25, 2015 at 03:03:56PM +0100, Andrew Lunn wrote:
[...]
> 
> What we don't want is X chip families and Y different ways to
> configure the features. Ideal we want X chip families, and one way to
> configure them all.

This statement is really my primary concern.  There is lots of interest
around hardware offload at this point and it seems like there is a risk
that a lack of consistency can create problems.

I think these patches are great as they allow for the programming of the
offload hardware (and it has been pointed out that this drastically
increases performance), but one concern I have with this patch (related
to this) is that I'm not sure there is a major need to create netdevs
automatically if there is not the ability to rx/tx actual frames on
these interfaces.

Since the SoC's NIC is going to handle all packet rx/tx then it seems
like there should be a way to signal between the switching
hardware/driver and the NIC driver.  I'm not sure what the ideal
interface for this is, but maybe there is room in the switchdev infra
add some ops to find a way to make this signalling possible to create
netdevs and allow incoming traffic to be assigned to the appropriate
device.

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH] net: phy: b53: switchdev driver for Broadcom BCM53xx switches
  2015-02-25 15:46               ` Andy Gospodarek
@ 2015-02-25 17:23                 ` Rafał Miłecki
  2015-02-25 21:56                 ` Andrew Lunn
  2015-02-26  0:53                 ` Scott Feldman
  2 siblings, 0 replies; 42+ messages in thread
From: Rafał Miłecki @ 2015-02-25 17:23 UTC (permalink / raw)
  To: Andy Gospodarek
  Cc: Andrew Lunn, Florian Fainelli, David S. Miller,
	Network Development, Jonas Gorski, Hauke Mehrtens, Felix Fietkau,
	Jiri Pirko

On 25 February 2015 at 16:46, Andy Gospodarek <gospo@cumulusnetworks.com> wrote:
> On Wed, Feb 25, 2015 at 03:03:56PM +0100, Andrew Lunn wrote:
> [...]
>>
>> What we don't want is X chip families and Y different ways to
>> configure the features. Ideal we want X chip families, and one way to
>> configure them all.
>
> This statement is really my primary concern.  There is lots of interest
> around hardware offload at this point and it seems like there is a risk
> that a lack of consistency can create problems.
>
> I think these patches are great as they allow for the programming of the
> offload hardware (and it has been pointed out that this drastically
> increases performance), but one concern I have with this patch (related
> to this) is that I'm not sure there is a major need to create netdevs
> automatically if there is not the ability to rx/tx actual frames on
> these interfaces.
>
> Since the SoC's NIC is going to handle all packet rx/tx then it seems
> like there should be a way to signal between the switching
> hardware/driver and the NIC driver.  I'm not sure what the ideal
> interface for this is, but maybe there is room in the switchdev infra
> add some ops to find a way to make this signalling possible to create
> netdevs and allow incoming traffic to be assigned to the appropriate
> device.

This is what we have in OpenWrt currently and what Florian was trying
to upstream last time. Please try to see
[PATCH 0/4 net-next] net: phy: add Generic Netlink switch configuration API
http://thread.gmane.org/gmane.linux.network/288039
, but be aware it's not a short discussion.

One of the reason for rejecting this patchset was that architecture
wasn't using net devices. So exactly something opposite you tried
suggesting now ;)

-- 
Rafał

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH] net: phy: b53: switchdev driver for Broadcom BCM53xx switches
  2015-02-25 15:46               ` Andy Gospodarek
  2015-02-25 17:23                 ` Rafał Miłecki
@ 2015-02-25 21:56                 ` Andrew Lunn
  2015-02-26  0:53                 ` Scott Feldman
  2 siblings, 0 replies; 42+ messages in thread
From: Andrew Lunn @ 2015-02-25 21:56 UTC (permalink / raw)
  To: Andy Gospodarek
  Cc: Rafa?? Mi??ecki, Florian Fainelli, David S. Miller,
	Network Development, Jonas Gorski, Hauke Mehrtens, Felix Fietkau,
	Jiri Pirko

On Wed, Feb 25, 2015 at 10:46:07AM -0500, Andy Gospodarek wrote:
> On Wed, Feb 25, 2015 at 03:03:56PM +0100, Andrew Lunn wrote:
> [...]
> > 
> > What we don't want is X chip families and Y different ways to
> > configure the features. Ideal we want X chip families, and one way to
> > configure them all.
> 
> This statement is really my primary concern.  There is lots of interest
> around hardware offload at this point and it seems like there is a risk
> that a lack of consistency can create problems.
> 
> I think these patches are great as they allow for the programming of the
> offload hardware (and it has been pointed out that this drastically
> increases performance), but one concern I have with this patch (related
> to this) is that I'm not sure there is a major need to create netdevs
> automatically if there is not the ability to rx/tx actual frames on
> these interfaces.

Using the broadcom tags, it does seem possible to direct packets out
specific ports. So this chip family could use the DSA infrastructure.
It should also be possible to perform bridging in hardware. We should
push DSA for all chips which fit this model.

However, i suspect there are simpler chips which do not support
tagging. When somebody tries to submit a driver for such a device, we
then need to consider what to do for these devices.

     Andrew

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH] net: phy: b53: switchdev driver for Broadcom BCM53xx switches
  2015-02-25 15:46               ` Andy Gospodarek
  2015-02-25 17:23                 ` Rafał Miłecki
  2015-02-25 21:56                 ` Andrew Lunn
@ 2015-02-26  0:53                 ` Scott Feldman
  2015-02-26  4:21                   ` Andy Gospodarek
  2 siblings, 1 reply; 42+ messages in thread
From: Scott Feldman @ 2015-02-26  0:53 UTC (permalink / raw)
  To: Andy Gospodarek
  Cc: Andrew Lunn, Rafa?? Mi??ecki, Florian Fainelli, David S. Miller,
	Network Development, Jonas Gorski, Hauke Mehrtens, Felix Fietkau,
	Jiri Pirko

On Wed, Feb 25, 2015 at 7:46 AM, Andy Gospodarek
<gospo@cumulusnetworks.com> wrote:
> On Wed, Feb 25, 2015 at 03:03:56PM +0100, Andrew Lunn wrote:
> [...]
>>
>> What we don't want is X chip families and Y different ways to
>> configure the features. Ideal we want X chip families, and one way to
>> configure them all.
>
> This statement is really my primary concern.  There is lots of interest
> around hardware offload at this point and it seems like there is a risk
> that a lack of consistency can create problems.
>
> I think these patches are great as they allow for the programming of the
> offload hardware (and it has been pointed out that this drastically
> increases performance), but one concern I have with this patch (related
> to this) is that I'm not sure there is a major need to create netdevs
> automatically if there is not the ability to rx/tx actual frames on
> these interfaces.

Even when not used for rx/tx to CPU, it seems the netdevs are still
useful as an anchor to build higher-level constructs such as bridge or
bond, and to hang stuff like netdev stats or ethtool-ish things.

-scott

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH] net: phy: b53: switchdev driver for Broadcom BCM53xx switches
  2015-02-26  0:53                 ` Scott Feldman
@ 2015-02-26  4:21                   ` Andy Gospodarek
  2015-02-26  6:47                     ` Jiri Pirko
  0 siblings, 1 reply; 42+ messages in thread
From: Andy Gospodarek @ 2015-02-26  4:21 UTC (permalink / raw)
  To: Scott Feldman
  Cc: Andrew Lunn, Rafa?? Mi??ecki, Florian Fainelli, David S. Miller,
	Network Development, Jonas Gorski, Hauke Mehrtens, Felix Fietkau,
	Jiri Pirko

On Wed, Feb 25, 2015 at 04:53:24PM -0800, Scott Feldman wrote:
> On Wed, Feb 25, 2015 at 7:46 AM, Andy Gospodarek
> <gospo@cumulusnetworks.com> wrote:
> > On Wed, Feb 25, 2015 at 03:03:56PM +0100, Andrew Lunn wrote:
> > [...]
> >>
> >> What we don't want is X chip families and Y different ways to
> >> configure the features. Ideal we want X chip families, and one way to
> >> configure them all.
> >
> > This statement is really my primary concern.  There is lots of interest
> > around hardware offload at this point and it seems like there is a risk
> > that a lack of consistency can create problems.
> >
> > I think these patches are great as they allow for the programming of the
> > offload hardware (and it has been pointed out that this drastically
> > increases performance), but one concern I have with this patch (related
> > to this) is that I'm not sure there is a major need to create netdevs
> > automatically if there is not the ability to rx/tx actual frames on
> > these interfaces.
> 
> Even when not used for rx/tx to CPU, it seems the netdevs are still
> useful as an anchor to build higher-level constructs such as bridge or
> bond, and to hang stuff like netdev stats or ethtool-ish things.
> 

I agree that they are useful, but now we are really dealing with a
netdev that is slightly lower functionality than we expect from a netdev
right now.

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH] net: phy: b53: switchdev driver for Broadcom BCM53xx switches
  2015-02-26  4:21                   ` Andy Gospodarek
@ 2015-02-26  6:47                     ` Jiri Pirko
  2015-02-26  7:14                       ` B Viswanath
                                         ` (2 more replies)
  0 siblings, 3 replies; 42+ messages in thread
From: Jiri Pirko @ 2015-02-26  6:47 UTC (permalink / raw)
  To: Andy Gospodarek
  Cc: Scott Feldman, Andrew Lunn, Rafa?? Mi??ecki, Florian Fainelli,
	David S. Miller, Network Development, Jonas Gorski,
	Hauke Mehrtens, Felix Fietkau

Thu, Feb 26, 2015 at 05:21:58AM CET, gospo@cumulusnetworks.com wrote:
>On Wed, Feb 25, 2015 at 04:53:24PM -0800, Scott Feldman wrote:
>> On Wed, Feb 25, 2015 at 7:46 AM, Andy Gospodarek
>> <gospo@cumulusnetworks.com> wrote:
>> > On Wed, Feb 25, 2015 at 03:03:56PM +0100, Andrew Lunn wrote:
>> > [...]
>> >>
>> >> What we don't want is X chip families and Y different ways to
>> >> configure the features. Ideal we want X chip families, and one way to
>> >> configure them all.
>> >
>> > This statement is really my primary concern.  There is lots of interest
>> > around hardware offload at this point and it seems like there is a risk
>> > that a lack of consistency can create problems.
>> >
>> > I think these patches are great as they allow for the programming of the
>> > offload hardware (and it has been pointed out that this drastically
>> > increases performance), but one concern I have with this patch (related
>> > to this) is that I'm not sure there is a major need to create netdevs
>> > automatically if there is not the ability to rx/tx actual frames on
>> > these interfaces.
>> 
>> Even when not used for rx/tx to CPU, it seems the netdevs are still
>> useful as an anchor to build higher-level constructs such as bridge or
>> bond, and to hang stuff like netdev stats or ethtool-ish things.
>> 
>
>I agree that they are useful, but now we are really dealing with a
>netdev that is slightly lower functionality than we expect from a netdev
>right now.

Is that a real care for some device now?
I agree with Scott that we need to model is consistently. If there is
such port netdev witch cannot tx/rx, we can expose the fact using some
flag...

>

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH] net: phy: b53: switchdev driver for Broadcom BCM53xx switches
  2015-02-26  6:47                     ` Jiri Pirko
@ 2015-02-26  7:14                       ` B Viswanath
  2015-02-26 14:13                       ` Andy Gospodarek
  2015-02-26 17:51                       ` Florian Fainelli
  2 siblings, 0 replies; 42+ messages in thread
From: B Viswanath @ 2015-02-26  7:14 UTC (permalink / raw)
  To: Jiri Pirko
  Cc: Andy Gospodarek, Scott Feldman, Andrew Lunn, Rafa?? Mi??ecki,
	Florian Fainelli, David S. Miller, Network Development,
	Jonas Gorski, Hauke Mehrtens, Felix Fietkau

On 26 February 2015 at 12:17, Jiri Pirko <jiri@resnulli.us> wrote:
> Thu, Feb 26, 2015 at 05:21:58AM CET, gospo@cumulusnetworks.com wrote:
>>On Wed, Feb 25, 2015 at 04:53:24PM -0800, Scott Feldman wrote:
>>> On Wed, Feb 25, 2015 at 7:46 AM, Andy Gospodarek
>>> <gospo@cumulusnetworks.com> wrote:
>>> > On Wed, Feb 25, 2015 at 03:03:56PM +0100, Andrew Lunn wrote:
>>> > [...]
>>> >>
>>> >> What we don't want is X chip families and Y different ways to
>>> >> configure the features. Ideal we want X chip families, and one way to
>>> >> configure them all.
>>> >
>>> > This statement is really my primary concern.  There is lots of interest
>>> > around hardware offload at this point and it seems like there is a risk
>>> > that a lack of consistency can create problems.
>>> >
>>> > I think these patches are great as they allow for the programming of the
>>> > offload hardware (and it has been pointed out that this drastically
>>> > increases performance), but one concern I have with this patch (related
>>> > to this) is that I'm not sure there is a major need to create netdevs
>>> > automatically if there is not the ability to rx/tx actual frames on
>>> > these interfaces.
>>>
>>> Even when not used for rx/tx to CPU, it seems the netdevs are still
>>> useful as an anchor to build higher-level constructs such as bridge or
>>> bond, and to hang stuff like netdev stats or ethtool-ish things.
>>>
>>
>>I agree that they are useful, but now we are really dealing with a
>>netdev that is slightly lower functionality than we expect from a netdev
>>right now.
>
> Is that a real care for some device now?
> I agree with Scott that we need to model is consistently. If there is
> such port netdev witch cannot tx/rx, we can expose the fact using some
> flag...

I would like to add that the 'requirements' are changing significantly
in this market. Until a while ago, all of the switch-ports were
considered a single device (and generally called LAN). If the
underlying driver exposed them as individual ports, then, they were
put-into a bridge, and used as such. The real reason for this was that
nobody was interested in individual packets from individual ports. If
packet comes to CPU because it could not be switched inside the
silicon, it was routed by the CPU (LAN to WAN). For those devices that
have wlan, the wlan interface was also added to the 'bridge'. This
bridge device really represented the 'LAN' of the network.

Now, there are requirements propping up which need more intelligence
in the 'router product'. This router is becoming center to a connected
home, with set-top boxes and IPTV behind, and even with a user
configurable DMZ port. Protocols are being run on LAN (like spanning
tree, and GxRP). All this mean, the software on the router needs to
look inside the LAN bridge and can't be content with a top-level
interface.

I guess I am saying that keeping netdevs for individual ports is going
to be a need, if it is not already there today. We will also see
traffic flowing on these netdevs in addition to statistics and other
stuff.  Keeping netdevs also makes it, as others say, consistent with
the management model.

>>
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH] net: phy: b53: switchdev driver for Broadcom BCM53xx switches
  2015-02-26  6:47                     ` Jiri Pirko
  2015-02-26  7:14                       ` B Viswanath
@ 2015-02-26 14:13                       ` Andy Gospodarek
  2015-02-26 14:19                         ` Scott Feldman
  2015-02-26 17:51                       ` Florian Fainelli
  2 siblings, 1 reply; 42+ messages in thread
From: Andy Gospodarek @ 2015-02-26 14:13 UTC (permalink / raw)
  To: Jiri Pirko
  Cc: Scott Feldman, Andrew Lunn, Rafa?? Mi??ecki, Florian Fainelli,
	David S. Miller, Network Development, Jonas Gorski,
	Hauke Mehrtens, Felix Fietkau

On Thu, Feb 26, 2015 at 07:47:55AM +0100, Jiri Pirko wrote:
> Thu, Feb 26, 2015 at 05:21:58AM CET, gospo@cumulusnetworks.com wrote:
> >On Wed, Feb 25, 2015 at 04:53:24PM -0800, Scott Feldman wrote:
> >> On Wed, Feb 25, 2015 at 7:46 AM, Andy Gospodarek
> >> <gospo@cumulusnetworks.com> wrote:
> >> > On Wed, Feb 25, 2015 at 03:03:56PM +0100, Andrew Lunn wrote:
> >> > [...]
> >> >>
> >> >> What we don't want is X chip families and Y different ways to
> >> >> configure the features. Ideal we want X chip families, and one way to
> >> >> configure them all.
> >> >
> >> > This statement is really my primary concern.  There is lots of interest
> >> > around hardware offload at this point and it seems like there is a risk
> >> > that a lack of consistency can create problems.
> >> >
> >> > I think these patches are great as they allow for the programming of the
> >> > offload hardware (and it has been pointed out that this drastically
> >> > increases performance), but one concern I have with this patch (related
> >> > to this) is that I'm not sure there is a major need to create netdevs
> >> > automatically if there is not the ability to rx/tx actual frames on
> >> > these interfaces.
> >> 
> >> Even when not used for rx/tx to CPU, it seems the netdevs are still
> >> useful as an anchor to build higher-level constructs such as bridge or
> >> bond, and to hang stuff like netdev stats or ethtool-ish things.
> >> 
> >
> >I agree that they are useful, but now we are really dealing with a
> >netdev that is slightly lower functionality than we expect from a netdev
> >right now.
> 
> Is that a real care for some device now?
I guess that depends on how users expect to use it.  :)

> I agree with Scott that we need to model is consistently. If there is
> such port netdev witch cannot tx/rx, we can expose the fact using some
> flag...
Using a flag to expose/mark this was exactly my thought.

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH] net: phy: b53: switchdev driver for Broadcom BCM53xx switches
  2015-02-26 14:13                       ` Andy Gospodarek
@ 2015-02-26 14:19                         ` Scott Feldman
  2015-02-26 14:44                           ` Jiri Pirko
  2015-02-26 17:52                           ` Florian Fainelli
  0 siblings, 2 replies; 42+ messages in thread
From: Scott Feldman @ 2015-02-26 14:19 UTC (permalink / raw)
  To: Andy Gospodarek
  Cc: Jiri Pirko, Andrew Lunn, Rafa?? Mi??ecki, Florian Fainelli,
	David S. Miller, Network Development, Jonas Gorski,
	Hauke Mehrtens, Felix Fietkau

On Thu, Feb 26, 2015 at 6:13 AM, Andy Gospodarek
<gospo@cumulusnetworks.com> wrote:
> On Thu, Feb 26, 2015 at 07:47:55AM +0100, Jiri Pirko wrote:
>> Thu, Feb 26, 2015 at 05:21:58AM CET, gospo@cumulusnetworks.com wrote:
>> >On Wed, Feb 25, 2015 at 04:53:24PM -0800, Scott Feldman wrote:
>> >> On Wed, Feb 25, 2015 at 7:46 AM, Andy Gospodarek
>> >> <gospo@cumulusnetworks.com> wrote:
>> >> > On Wed, Feb 25, 2015 at 03:03:56PM +0100, Andrew Lunn wrote:
>> >> > [...]
>> >> >>
>> >> >> What we don't want is X chip families and Y different ways to
>> >> >> configure the features. Ideal we want X chip families, and one way to
>> >> >> configure them all.
>> >> >
>> >> > This statement is really my primary concern.  There is lots of interest
>> >> > around hardware offload at this point and it seems like there is a risk
>> >> > that a lack of consistency can create problems.
>> >> >
>> >> > I think these patches are great as they allow for the programming of the
>> >> > offload hardware (and it has been pointed out that this drastically
>> >> > increases performance), but one concern I have with this patch (related
>> >> > to this) is that I'm not sure there is a major need to create netdevs
>> >> > automatically if there is not the ability to rx/tx actual frames on
>> >> > these interfaces.
>> >>
>> >> Even when not used for rx/tx to CPU, it seems the netdevs are still
>> >> useful as an anchor to build higher-level constructs such as bridge or
>> >> bond, and to hang stuff like netdev stats or ethtool-ish things.
>> >>
>> >
>> >I agree that they are useful, but now we are really dealing with a
>> >netdev that is slightly lower functionality than we expect from a netdev
>> >right now.
>>
>> Is that a real care for some device now?
> I guess that depends on how users expect to use it.  :)
>
>> I agree with Scott that we need to model is consistently. If there is
>> such port netdev witch cannot tx/rx, we can expose the fact using some
>> flag...
> Using a flag to expose/mark this was exactly my thought.

Missing .ndo_start_xmit is the clue....do we need more?

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH] net: phy: b53: switchdev driver for Broadcom BCM53xx switches
  2015-02-26 14:19                         ` Scott Feldman
@ 2015-02-26 14:44                           ` Jiri Pirko
  2015-02-27 22:21                             ` David Miller
  2015-02-26 17:52                           ` Florian Fainelli
  1 sibling, 1 reply; 42+ messages in thread
From: Jiri Pirko @ 2015-02-26 14:44 UTC (permalink / raw)
  To: Scott Feldman
  Cc: Andy Gospodarek, Andrew Lunn, Rafa?? Mi??ecki, Florian Fainelli,
	David S. Miller, Network Development, Jonas Gorski,
	Hauke Mehrtens, Felix Fietkau

Thu, Feb 26, 2015 at 03:19:27PM CET, sfeldma@gmail.com wrote:
>On Thu, Feb 26, 2015 at 6:13 AM, Andy Gospodarek
><gospo@cumulusnetworks.com> wrote:
>> On Thu, Feb 26, 2015 at 07:47:55AM +0100, Jiri Pirko wrote:
>>> Thu, Feb 26, 2015 at 05:21:58AM CET, gospo@cumulusnetworks.com wrote:
>>> >On Wed, Feb 25, 2015 at 04:53:24PM -0800, Scott Feldman wrote:
>>> >> On Wed, Feb 25, 2015 at 7:46 AM, Andy Gospodarek
>>> >> <gospo@cumulusnetworks.com> wrote:
>>> >> > On Wed, Feb 25, 2015 at 03:03:56PM +0100, Andrew Lunn wrote:
>>> >> > [...]
>>> >> >>
>>> >> >> What we don't want is X chip families and Y different ways to
>>> >> >> configure the features. Ideal we want X chip families, and one way to
>>> >> >> configure them all.
>>> >> >
>>> >> > This statement is really my primary concern.  There is lots of interest
>>> >> > around hardware offload at this point and it seems like there is a risk
>>> >> > that a lack of consistency can create problems.
>>> >> >
>>> >> > I think these patches are great as they allow for the programming of the
>>> >> > offload hardware (and it has been pointed out that this drastically
>>> >> > increases performance), but one concern I have with this patch (related
>>> >> > to this) is that I'm not sure there is a major need to create netdevs
>>> >> > automatically if there is not the ability to rx/tx actual frames on
>>> >> > these interfaces.
>>> >>
>>> >> Even when not used for rx/tx to CPU, it seems the netdevs are still
>>> >> useful as an anchor to build higher-level constructs such as bridge or
>>> >> bond, and to hang stuff like netdev stats or ethtool-ish things.
>>> >>
>>> >
>>> >I agree that they are useful, but now we are really dealing with a
>>> >netdev that is slightly lower functionality than we expect from a netdev
>>> >right now.
>>>
>>> Is that a real care for some device now?
>> I guess that depends on how users expect to use it.  :)
>>
>>> I agree with Scott that we need to model is consistently. If there is
>>> such port netdev witch cannot tx/rx, we can expose the fact using some
>>> flag...
>> Using a flag to expose/mark this was exactly my thought.
>
>Missing .ndo_start_xmit is the clue....do we need more?

You do not want to add null check for ndo_start_xmit to xmit path :)
This should be some stub in case of no-tx.

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH] net: phy: b53: switchdev driver for Broadcom BCM53xx switches
  2015-02-25 14:19                 ` Andrew Lunn
@ 2015-02-26 14:58                   ` Rafał Miłecki
  2015-02-26 15:18                     ` Andrew Lunn
  0 siblings, 1 reply; 42+ messages in thread
From: Rafał Miłecki @ 2015-02-26 14:58 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Florian Fainelli, Andy Gospodarek, David S. Miller,
	Network Development, Jonas Gorski, Hauke Mehrtens, Felix Fietkau,
	Jiri Pirko

On 25 February 2015 at 15:19, Andrew Lunn <andrew@lunn.ch> wrote:
>> What do you mean by these recent patches? Has DSA recently received a
>> support for bridging ports in the hardware? Like setting VLANs using
>> some "bridge" comment (nl API) or something? Because I'm not aware of
>> that.
>
> Yes. Scan over netdev list for the last week. e.g:
>
> http://comments.gmane.org/gmane.linux.network/350754

Hm, I can see it was actually merged to the net-next already:
https://git.kernel.org/cgit/linux/kernel/git/davem/net-next.git/commit/?id=bb66be1c549a0760500cfad404b3d79a136d0e44

But this dsa implementation is still totally unclear to me. So I can
see we now have
1) port_join_bridge
2) port_leave_bridge

How does it allow me to bridge few ports with specifying PVID /
(UN)TAG for some of them?

-- 
Rafał

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH] net: phy: b53: switchdev driver for Broadcom BCM53xx switches
  2015-02-26 14:58                   ` Rafał Miłecki
@ 2015-02-26 15:18                     ` Andrew Lunn
  2015-02-26 15:30                       ` Rafał Miłecki
  0 siblings, 1 reply; 42+ messages in thread
From: Andrew Lunn @ 2015-02-26 15:18 UTC (permalink / raw)
  To: Rafa?? Mi??ecki
  Cc: Florian Fainelli, Andy Gospodarek, David S. Miller,
	Network Development, Jonas Gorski, Hauke Mehrtens, Felix Fietkau,
	Jiri Pirko

On Thu, Feb 26, 2015 at 03:58:40PM +0100, Rafa?? Mi??ecki wrote:
> On 25 February 2015 at 15:19, Andrew Lunn <andrew@lunn.ch> wrote:
> >> What do you mean by these recent patches? Has DSA recently received a
> >> support for bridging ports in the hardware? Like setting VLANs using
> >> some "bridge" comment (nl API) or something? Because I'm not aware of
> >> that.
> >
> > Yes. Scan over netdev list for the last week. e.g:
> >
> > http://comments.gmane.org/gmane.linux.network/350754
> 
> Hm, I can see it was actually merged to the net-next already:
> https://git.kernel.org/cgit/linux/kernel/git/davem/net-next.git/commit/?id=bb66be1c549a0760500cfad404b3d79a136d0e44
> 
> But this dsa implementation is still totally unclear to me. So I can
> see we now have
> 1) port_join_bridge
> 2) port_leave_bridge
> 
> How does it allow me to bridge few ports with specifying PVID /
> (UN)TAG for some of them?

How about going back to the beginning. Look at the Starfigher 2 DSA
driver. Do you have similar registers? Can you map the Starfigher code
onto the b53 registers? If so, just write a new driver following the
Starfigher as a reference.

     Andrew

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH] net: phy: b53: switchdev driver for Broadcom BCM53xx switches
  2015-02-26 15:18                     ` Andrew Lunn
@ 2015-02-26 15:30                       ` Rafał Miłecki
  2015-02-26 15:36                         ` Andrew Lunn
  0 siblings, 1 reply; 42+ messages in thread
From: Rafał Miłecki @ 2015-02-26 15:30 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Florian Fainelli, Andy Gospodarek, David S. Miller,
	Network Development, Jonas Gorski, Hauke Mehrtens, Felix Fietkau,
	Jiri Pirko

On 26 February 2015 at 16:18, Andrew Lunn <andrew@lunn.ch> wrote:
> On Thu, Feb 26, 2015 at 03:58:40PM +0100, Rafa?? Mi??ecki wrote:
>> On 25 February 2015 at 15:19, Andrew Lunn <andrew@lunn.ch> wrote:
>> >> What do you mean by these recent patches? Has DSA recently received a
>> >> support for bridging ports in the hardware? Like setting VLANs using
>> >> some "bridge" comment (nl API) or something? Because I'm not aware of
>> >> that.
>> >
>> > Yes. Scan over netdev list for the last week. e.g:
>> >
>> > http://comments.gmane.org/gmane.linux.network/350754
>>
>> Hm, I can see it was actually merged to the net-next already:
>> https://git.kernel.org/cgit/linux/kernel/git/davem/net-next.git/commit/?id=bb66be1c549a0760500cfad404b3d79a136d0e44
>>
>> But this dsa implementation is still totally unclear to me. So I can
>> see we now have
>> 1) port_join_bridge
>> 2) port_leave_bridge
>>
>> How does it allow me to bridge few ports with specifying PVID /
>> (UN)TAG for some of them?
>
> How about going back to the beginning. Look at the Starfigher 2 DSA
> driver. Do you have similar registers? Can you map the Starfigher code
> onto the b53 registers? If so, just write a new driver following the
> Starfigher as a reference.

It doesn't really answer my question as I don't see functionality I'm
looking for in bcm_sf2. I don't see it handling (un)tagging or PVID
anywhere. It makes me believe such features are not implemented (and
not configurable) using bridges/dsa at all. Can you any API related to
untagging / PVID?

-- 
Rafał

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH] net: phy: b53: switchdev driver for Broadcom BCM53xx switches
  2015-02-26 15:30                       ` Rafał Miłecki
@ 2015-02-26 15:36                         ` Andrew Lunn
  2015-02-26 15:49                           ` Rafał Miłecki
  2015-02-26 17:57                           ` Florian Fainelli
  0 siblings, 2 replies; 42+ messages in thread
From: Andrew Lunn @ 2015-02-26 15:36 UTC (permalink / raw)
  To: Rafa?? Mi??ecki
  Cc: Florian Fainelli, Andy Gospodarek, David S. Miller,
	Network Development, Jonas Gorski, Hauke Mehrtens, Felix Fietkau,
	Jiri Pirko

> It doesn't really answer my question as I don't see functionality I'm
> looking for in bcm_sf2. I don't see it handling (un)tagging or PVID
> anywhere. It makes me believe such features are not implemented (and
> not configurable) using bridges/dsa at all. Can you any API related to
> untagging / PVID?

The (un)tagging code is in net/dsa/tag_brcm.c This is generic code, so
you would not expect to find it in bcm_sf2. All you need to do is set

        .tag_protocol           = DSA_TAG_PROTO_BRCM,

in your dsa_switch_driver structure and the core DSA code will ensure
the packets gets the header applied/removed.

    Andrew

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH] net: phy: b53: switchdev driver for Broadcom BCM53xx switches
  2015-02-26 15:36                         ` Andrew Lunn
@ 2015-02-26 15:49                           ` Rafał Miłecki
  2015-02-26 16:21                             ` Andrew Lunn
  2015-02-26 17:58                             ` Florian Fainelli
  2015-02-26 17:57                           ` Florian Fainelli
  1 sibling, 2 replies; 42+ messages in thread
From: Rafał Miłecki @ 2015-02-26 15:49 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Florian Fainelli, Andy Gospodarek, David S. Miller,
	Network Development, Jonas Gorski, Hauke Mehrtens, Felix Fietkau,
	Jiri Pirko

On 26 February 2015 at 16:36, Andrew Lunn <andrew@lunn.ch> wrote:
>> It doesn't really answer my question as I don't see functionality I'm
>> looking for in bcm_sf2. I don't see it handling (un)tagging or PVID
>> anywhere. It makes me believe such features are not implemented (and
>> not configurable) using bridges/dsa at all. Can you any API related to
>> untagging / PVID?
>
> The (un)tagging code is in net/dsa/tag_brcm.c This is generic code, so
> you would not expect to find it in bcm_sf2. All you need to do is set
>
>         .tag_protocol           = DSA_TAG_PROTO_BRCM,
>
> in your dsa_switch_driver structure and the core DSA code will ensure
> the packets gets the header applied/removed.

Sorry, I wasn't clear enough. I don't mean Broadcom proto tagging, but
a 802.1Q VLAN header including e.g. VID.

I'd like to have control over VLAN ID ports are using. The hardware
allows me to define VLAN with a number and also if:
1) Packets incoming on port X should be modified (by hw) to include
802.11Q header
2) Packets leaving port Y should be stripped out of 802.11Q header or not

Above allows me to create some fun setups. For example I can configure
my Linux interface to send packets with VID N. Then I can tell
hardware to:
1) Send packets with VID N untagged to port 1
2) Send packets with VID N still tagged to port 2

I don't see any way to achieve that with dsa. On the other hand this
is what my proposed b53 driver allows. I could achieve above setup
using:
bridge vlan add vid N dev sw0p1 pvid untagged
bridge vlan add vid N dev sw0p2
bridge vlan add vid N dev sw0p8

-- 
Rafał

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH] net: phy: b53: switchdev driver for Broadcom BCM53xx switches
  2015-02-26 15:49                           ` Rafał Miłecki
@ 2015-02-26 16:21                             ` Andrew Lunn
  2015-02-26 17:58                             ` Florian Fainelli
  1 sibling, 0 replies; 42+ messages in thread
From: Andrew Lunn @ 2015-02-26 16:21 UTC (permalink / raw)
  To: Rafa?? Mi??ecki
  Cc: Florian Fainelli, Andy Gospodarek, David S. Miller,
	Network Development, Jonas Gorski, Hauke Mehrtens, Felix Fietkau,
	Jiri Pirko

On Thu, Feb 26, 2015 at 04:49:51PM +0100, Rafa?? Mi??ecki wrote:
> On 26 February 2015 at 16:36, Andrew Lunn <andrew@lunn.ch> wrote:
> >> It doesn't really answer my question as I don't see functionality I'm
> >> looking for in bcm_sf2. I don't see it handling (un)tagging or PVID
> >> anywhere. It makes me believe such features are not implemented (and
> >> not configurable) using bridges/dsa at all. Can you any API related to
> >> untagging / PVID?
> >
> > The (un)tagging code is in net/dsa/tag_brcm.c This is generic code, so
> > you would not expect to find it in bcm_sf2. All you need to do is set
> >
> >         .tag_protocol           = DSA_TAG_PROTO_BRCM,
> >
> > in your dsa_switch_driver structure and the core DSA code will ensure
> > the packets gets the header applied/removed.
> 
> Sorry, I wasn't clear enough. I don't mean Broadcom proto tagging, but
> a 802.1Q VLAN header including e.g. VID.
> 
> I'd like to have control over VLAN ID ports are using. The hardware
> allows me to define VLAN with a number and also if:
> 1) Packets incoming on port X should be modified (by hw) to include
> 802.11Q header
> 2) Packets leaving port Y should be stripped out of 802.11Q header or not
> 
> Above allows me to create some fun setups. For example I can configure
> my Linux interface to send packets with VID N. Then I can tell
> hardware to:
> 1) Send packets with VID N untagged to port 1
> 2) Send packets with VID N still tagged to port 2

Ah, O.K.

DSA does not allow that, at the moment. The Marvell switches do
however support this. So i expect at some point it will get added.
This is actually a layer or two up. First you need plain packets
without 802.11q supported. Then you can add 802.11q on top of that,
using standard linux concepts. Then we can add ingress/egress VLAN tag
stripping/adding. This last part is maybe a new concept with linux,
since it is something we want in general, and not just when using the
SW bridge.

So lets say you have DSA slave interfaces lan1 and lan2

You could then do

vconfig add lan1 42 --strip
vconfig add lan2 42 

You could then add these lan1:42 and lan2:42 interfaces to the bridge
to get what you want?

    Andrew

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH] net: phy: b53: switchdev driver for Broadcom BCM53xx switches
  2015-02-26  6:47                     ` Jiri Pirko
  2015-02-26  7:14                       ` B Viswanath
  2015-02-26 14:13                       ` Andy Gospodarek
@ 2015-02-26 17:51                       ` Florian Fainelli
  2 siblings, 0 replies; 42+ messages in thread
From: Florian Fainelli @ 2015-02-26 17:51 UTC (permalink / raw)
  To: Jiri Pirko, Andy Gospodarek
  Cc: Scott Feldman, Andrew Lunn, Rafa?? Mi??ecki, David S. Miller,
	Network Development, Jonas Gorski, Hauke Mehrtens, Felix Fietkau

On 25/02/15 22:47, Jiri Pirko wrote:
> Thu, Feb 26, 2015 at 05:21:58AM CET, gospo@cumulusnetworks.com wrote:
>> On Wed, Feb 25, 2015 at 04:53:24PM -0800, Scott Feldman wrote:
>>> On Wed, Feb 25, 2015 at 7:46 AM, Andy Gospodarek
>>> <gospo@cumulusnetworks.com> wrote:
>>>> On Wed, Feb 25, 2015 at 03:03:56PM +0100, Andrew Lunn wrote:
>>>> [...]
>>>>>
>>>>> What we don't want is X chip families and Y different ways to
>>>>> configure the features. Ideal we want X chip families, and one way to
>>>>> configure them all.
>>>>
>>>> This statement is really my primary concern.  There is lots of interest
>>>> around hardware offload at this point and it seems like there is a risk
>>>> that a lack of consistency can create problems.
>>>>
>>>> I think these patches are great as they allow for the programming of the
>>>> offload hardware (and it has been pointed out that this drastically
>>>> increases performance), but one concern I have with this patch (related
>>>> to this) is that I'm not sure there is a major need to create netdevs
>>>> automatically if there is not the ability to rx/tx actual frames on
>>>> these interfaces.
>>>
>>> Even when not used for rx/tx to CPU, it seems the netdevs are still
>>> useful as an anchor to build higher-level constructs such as bridge or
>>> bond, and to hang stuff like netdev stats or ethtool-ish things.
>>>
>>
>> I agree that they are useful, but now we are really dealing with a
>> netdev that is slightly lower functionality than we expect from a netdev
>> right now.
> 
> Is that a real care for some device now?
> I agree with Scott that we need to model is consistently. If there is
> such port netdev witch cannot tx/rx, we can expose the fact using some
> flag...

At some point we discussed the possibility of not assigning an
inet_device/inet6_device pointer to a net_device which would be a pure
L2 net_device with only ethtool/bridge offloads, last I tried it blew up
in many places, but we can try again if this is deemed useful?
-- 
Florian

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH] net: phy: b53: switchdev driver for Broadcom BCM53xx switches
  2015-02-26 14:19                         ` Scott Feldman
  2015-02-26 14:44                           ` Jiri Pirko
@ 2015-02-26 17:52                           ` Florian Fainelli
  1 sibling, 0 replies; 42+ messages in thread
From: Florian Fainelli @ 2015-02-26 17:52 UTC (permalink / raw)
  To: Scott Feldman, Andy Gospodarek
  Cc: Jiri Pirko, Andrew Lunn, Rafa?? Mi??ecki, David S. Miller,
	Network Development, Jonas Gorski, Hauke Mehrtens, Felix Fietkau

On 26/02/15 06:19, Scott Feldman wrote:
> On Thu, Feb 26, 2015 at 6:13 AM, Andy Gospodarek
> <gospo@cumulusnetworks.com> wrote:
>> On Thu, Feb 26, 2015 at 07:47:55AM +0100, Jiri Pirko wrote:
>>> Thu, Feb 26, 2015 at 05:21:58AM CET, gospo@cumulusnetworks.com wrote:
>>>> On Wed, Feb 25, 2015 at 04:53:24PM -0800, Scott Feldman wrote:
>>>>> On Wed, Feb 25, 2015 at 7:46 AM, Andy Gospodarek
>>>>> <gospo@cumulusnetworks.com> wrote:
>>>>>> On Wed, Feb 25, 2015 at 03:03:56PM +0100, Andrew Lunn wrote:
>>>>>> [...]
>>>>>>>
>>>>>>> What we don't want is X chip families and Y different ways to
>>>>>>> configure the features. Ideal we want X chip families, and one way to
>>>>>>> configure them all.
>>>>>>
>>>>>> This statement is really my primary concern.  There is lots of interest
>>>>>> around hardware offload at this point and it seems like there is a risk
>>>>>> that a lack of consistency can create problems.
>>>>>>
>>>>>> I think these patches are great as they allow for the programming of the
>>>>>> offload hardware (and it has been pointed out that this drastically
>>>>>> increases performance), but one concern I have with this patch (related
>>>>>> to this) is that I'm not sure there is a major need to create netdevs
>>>>>> automatically if there is not the ability to rx/tx actual frames on
>>>>>> these interfaces.
>>>>>
>>>>> Even when not used for rx/tx to CPU, it seems the netdevs are still
>>>>> useful as an anchor to build higher-level constructs such as bridge or
>>>>> bond, and to hang stuff like netdev stats or ethtool-ish things.
>>>>>
>>>>
>>>> I agree that they are useful, but now we are really dealing with a
>>>> netdev that is slightly lower functionality than we expect from a netdev
>>>> right now.
>>>
>>> Is that a real care for some device now?
>> I guess that depends on how users expect to use it.  :)
>>
>>> I agree with Scott that we need to model is consistently. If there is
>>> such port netdev witch cannot tx/rx, we can expose the fact using some
>>> flag...
>> Using a flag to expose/mark this was exactly my thought.
> 
> Missing .ndo_start_xmit is the clue....do we need more?

We probably want to prevent users from assigning IP addresses to these
interfaces as well, a while ago we talked about not assigning an
inet_device/inet6_device pointer, maybe that's the way to go?
-- 
Florian

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH] net: phy: b53: switchdev driver for Broadcom BCM53xx switches
  2015-02-26 15:36                         ` Andrew Lunn
  2015-02-26 15:49                           ` Rafał Miłecki
@ 2015-02-26 17:57                           ` Florian Fainelli
  1 sibling, 0 replies; 42+ messages in thread
From: Florian Fainelli @ 2015-02-26 17:57 UTC (permalink / raw)
  To: Andrew Lunn, Rafa?? Mi??ecki
  Cc: Andy Gospodarek, David S. Miller, Network Development,
	Jonas Gorski, Hauke Mehrtens, Felix Fietkau, Jiri Pirko

On 26/02/15 07:36, Andrew Lunn wrote:
>> It doesn't really answer my question as I don't see functionality I'm
>> looking for in bcm_sf2. I don't see it handling (un)tagging or PVID
>> anywhere. It makes me believe such features are not implemented (and
>> not configurable) using bridges/dsa at all. Can you any API related to
>> untagging / PVID?
> 
> The (un)tagging code is in net/dsa/tag_brcm.c This is generic code, so
> you would not expect to find it in bcm_sf2. All you need to do is set
> 
>         .tag_protocol           = DSA_TAG_PROTO_BRCM,
> 
> in your dsa_switch_driver structure and the core DSA code will ensure
> the packets gets the header applied/removed.

This is untagging for the Broadcom tags, while Rafal is looking into
support the ndo_rx_vlan_{add,kill}_vid, which is something different here.
-- 
Florian

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH] net: phy: b53: switchdev driver for Broadcom BCM53xx switches
  2015-02-26 15:49                           ` Rafał Miłecki
  2015-02-26 16:21                             ` Andrew Lunn
@ 2015-02-26 17:58                             ` Florian Fainelli
  2015-02-26 18:26                               ` Scott Feldman
  1 sibling, 1 reply; 42+ messages in thread
From: Florian Fainelli @ 2015-02-26 17:58 UTC (permalink / raw)
  To: Rafał Miłecki, Andrew Lunn
  Cc: Andy Gospodarek, David S. Miller, Network Development,
	Jonas Gorski, Hauke Mehrtens, Felix Fietkau, Jiri Pirko

On 26/02/15 07:49, Rafał Miłecki wrote:
> On 26 February 2015 at 16:36, Andrew Lunn <andrew@lunn.ch> wrote:
>>> It doesn't really answer my question as I don't see functionality I'm
>>> looking for in bcm_sf2. I don't see it handling (un)tagging or PVID
>>> anywhere. It makes me believe such features are not implemented (and
>>> not configurable) using bridges/dsa at all. Can you any API related to
>>> untagging / PVID?
>>
>> The (un)tagging code is in net/dsa/tag_brcm.c This is generic code, so
>> you would not expect to find it in bcm_sf2. All you need to do is set
>>
>>         .tag_protocol           = DSA_TAG_PROTO_BRCM,
>>
>> in your dsa_switch_driver structure and the core DSA code will ensure
>> the packets gets the header applied/removed.
> 
> Sorry, I wasn't clear enough. I don't mean Broadcom proto tagging, but
> a 802.1Q VLAN header including e.g. VID.
> 
> I'd like to have control over VLAN ID ports are using. The hardware
> allows me to define VLAN with a number and also if:
> 1) Packets incoming on port X should be modified (by hw) to include
> 802.11Q header
> 2) Packets leaving port Y should be stripped out of 802.11Q header or not
> 
> Above allows me to create some fun setups. For example I can configure
> my Linux interface to send packets with VID N. Then I can tell
> hardware to:
> 1) Send packets with VID N untagged to port 1
> 2) Send packets with VID N still tagged to port 2
> 
> I don't see any way to achieve that with dsa. On the other hand this
> is what my proposed b53 driver allows. I could achieve above setup
> using:
> bridge vlan add vid N dev sw0p1 pvid untagged
> bridge vlan add vid N dev sw0p2
> bridge vlan add vid N dev sw0p8
> 

What we are currently missing today in DSA, which is on my TODO list as
well, is to add support for precisely this, using the existing:

ndo_add_vlan_rx_add_vid, ndo_vlan_rx_kill_vid, ndo_bridge_getlink and
ndo_bridge_setlink. Essentialy the same thing same your driver does,
just one level above, at the DSA layer, so we can have all DSA drivers
advertise/report that feature.
-- 
Florian

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH] net: phy: b53: switchdev driver for Broadcom BCM53xx switches
  2015-02-26 17:58                             ` Florian Fainelli
@ 2015-02-26 18:26                               ` Scott Feldman
  0 siblings, 0 replies; 42+ messages in thread
From: Scott Feldman @ 2015-02-26 18:26 UTC (permalink / raw)
  To: Florian Fainelli
  Cc: Rafał Miłecki, Andrew Lunn, Andy Gospodarek,
	David S. Miller, Network Development, Jonas Gorski,
	Hauke Mehrtens, Felix Fietkau, Jiri Pirko

On Thu, Feb 26, 2015 at 9:58 AM, Florian Fainelli <f.fainelli@gmail.com> wrote:
> On 26/02/15 07:49, Rafał Miłecki wrote:
>> On 26 February 2015 at 16:36, Andrew Lunn <andrew@lunn.ch> wrote:
>>>> It doesn't really answer my question as I don't see functionality I'm
>>>> looking for in bcm_sf2. I don't see it handling (un)tagging or PVID
>>>> anywhere. It makes me believe such features are not implemented (and
>>>> not configurable) using bridges/dsa at all. Can you any API related to
>>>> untagging / PVID?
>>>
>>> The (un)tagging code is in net/dsa/tag_brcm.c This is generic code, so
>>> you would not expect to find it in bcm_sf2. All you need to do is set
>>>
>>>         .tag_protocol           = DSA_TAG_PROTO_BRCM,
>>>
>>> in your dsa_switch_driver structure and the core DSA code will ensure
>>> the packets gets the header applied/removed.
>>
>> Sorry, I wasn't clear enough. I don't mean Broadcom proto tagging, but
>> a 802.1Q VLAN header including e.g. VID.
>>
>> I'd like to have control over VLAN ID ports are using. The hardware
>> allows me to define VLAN with a number and also if:
>> 1) Packets incoming on port X should be modified (by hw) to include
>> 802.11Q header
>> 2) Packets leaving port Y should be stripped out of 802.11Q header or not
>>
>> Above allows me to create some fun setups. For example I can configure
>> my Linux interface to send packets with VID N. Then I can tell
>> hardware to:
>> 1) Send packets with VID N untagged to port 1
>> 2) Send packets with VID N still tagged to port 2
>>
>> I don't see any way to achieve that with dsa. On the other hand this
>> is what my proposed b53 driver allows. I could achieve above setup
>> using:
>> bridge vlan add vid N dev sw0p1 pvid untagged
>> bridge vlan add vid N dev sw0p2
>> bridge vlan add vid N dev sw0p8
>>
>
> What we are currently missing today in DSA, which is on my TODO list as
> well, is to add support for precisely this, using the existing:
>
> ndo_add_vlan_rx_add_vid, ndo_vlan_rx_kill_vid, ndo_bridge_getlink and
> ndo_bridge_setlink. Essentialy the same thing same your driver does,
> just one level above, at the DSA layer, so we can have all DSA drivers
> advertise/report that feature.

Yes, with rocker we also used ndo_add_vlan_rx_add_vid,
ndo_vlan_rx_kill_vid to figure out the VLAN assignments on a bridge
port, and it works great.  What we haven't got to yet (on our TODO
list) is get access to the PVID of the bridge and use that for the
internal VLAN ID of the chip rather than reserving a portion of the
VLAN space for internal VLAN IDs.  You can use ndo_bridge_getlink and
ndo_bridge_setlink to get same VLAN info, but I think
ndo_add_vlan_rx_add_vid, ndo_vlan_rx_kill_vid is a better choice
because those will also work for the non-bridged port that is assigned
a VLAN, using vconfig for example.

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH] net: phy: b53: switchdev driver for Broadcom BCM53xx switches
  2015-02-26 14:44                           ` Jiri Pirko
@ 2015-02-27 22:21                             ` David Miller
  0 siblings, 0 replies; 42+ messages in thread
From: David Miller @ 2015-02-27 22:21 UTC (permalink / raw)
  To: jiri; +Cc: sfeldma, gospo, andrew, zajec5, f.fainelli, netdev, jogo, hauke, nbd

From: Jiri Pirko <jiri@resnulli.us>
Date: Thu, 26 Feb 2015 15:44:33 +0100

> Thu, Feb 26, 2015 at 03:19:27PM CET, sfeldma@gmail.com wrote:
>>Missing .ndo_start_xmit is the clue....do we need more?
> 
> You do not want to add null check for ndo_start_xmit to xmit path :)
> This should be some stub in case of no-tx.

Cheapest would be to force the device to use the noop_qdisc which
simply throws all packets away.

No fast path tests whatsoever.

Or we can attach an ndo_start_xmit that drops packets too.

^ permalink raw reply	[flat|nested] 42+ messages in thread

end of thread, other threads:[~2015-02-27 22:21 UTC | newest]

Thread overview: 42+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-02-24 17:42 [PATCH] net: phy: b53: switchdev driver for Broadcom BCM53xx switches Rafał Miłecki
2015-02-24 17:47 ` Rafał Miłecki
2015-02-24 21:51 ` Andrew Lunn
2015-02-24 22:29   ` Rafał Miłecki
2015-02-25  0:51     ` Andrew Lunn
2015-02-24 22:30 ` Andy Gospodarek
2015-02-24 22:50   ` Rafał Miłecki
2015-02-24 22:55     ` Florian Fainelli
2015-02-25  0:15       ` Andrew Lunn
2015-02-25  0:39         ` Florian Fainelli
2015-02-25  7:03           ` Rafał Miłecki
2015-02-25  8:07             ` Jiri Pirko
2015-02-25 14:03             ` Andrew Lunn
2015-02-25 14:17               ` Rafał Miłecki
2015-02-25 14:19                 ` Andrew Lunn
2015-02-26 14:58                   ` Rafał Miłecki
2015-02-26 15:18                     ` Andrew Lunn
2015-02-26 15:30                       ` Rafał Miłecki
2015-02-26 15:36                         ` Andrew Lunn
2015-02-26 15:49                           ` Rafał Miłecki
2015-02-26 16:21                             ` Andrew Lunn
2015-02-26 17:58                             ` Florian Fainelli
2015-02-26 18:26                               ` Scott Feldman
2015-02-26 17:57                           ` Florian Fainelli
2015-02-25 15:46               ` Andy Gospodarek
2015-02-25 17:23                 ` Rafał Miłecki
2015-02-25 21:56                 ` Andrew Lunn
2015-02-26  0:53                 ` Scott Feldman
2015-02-26  4:21                   ` Andy Gospodarek
2015-02-26  6:47                     ` Jiri Pirko
2015-02-26  7:14                       ` B Viswanath
2015-02-26 14:13                       ` Andy Gospodarek
2015-02-26 14:19                         ` Scott Feldman
2015-02-26 14:44                           ` Jiri Pirko
2015-02-27 22:21                             ` David Miller
2015-02-26 17:52                           ` Florian Fainelli
2015-02-26 17:51                       ` Florian Fainelli
2015-02-25  6:44       ` Rafał Miłecki
2015-02-24 22:48 ` Florian Fainelli
2015-02-24 22:56   ` Rafał Miłecki
2015-02-24 22:59     ` Florian Fainelli
2015-02-25  2:10   ` David Miller

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.