* [PATCH net-next v3 12/12] Documentation: devicetree: add Broadcom Starfighter 2 binding
From: Florian Fainelli @ 2014-08-24 18:44 UTC (permalink / raw)
To: netdev; +Cc: davem, jhs, linville, alexander.h.duyck, Florian Fainelli
In-Reply-To: <1408905869-10471-1-git-send-email-f.fainelli@gmail.com>
Add the binding documentation for the Broadcom Starfighter 2 integrated
switch hardware.
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
.../devicetree/bindings/net/broadcom-sf2.txt | 78 ++++++++++++++++++++++
1 file changed, 78 insertions(+)
create mode 100644 Documentation/devicetree/bindings/net/broadcom-sf2.txt
diff --git a/Documentation/devicetree/bindings/net/broadcom-sf2.txt b/Documentation/devicetree/bindings/net/broadcom-sf2.txt
new file mode 100644
index 000000000000..30d487597ecb
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/broadcom-sf2.txt
@@ -0,0 +1,78 @@
+* Broadcom Starfighter 2 integrated swich
+
+Required properties:
+
+- compatible: should be "brcm,bcm7445-switch-v4.0"
+- reg: addresses and length of the register sets for the device, must be 6
+ pairs of register addresses and lengths
+- interrupts: interrupts for the devices, must be two interrupts
+- dsa,mii-bus: phandle to the MDIO bus controller, see dsa/dsa.txt
+- dsa,ethernet: phandle to the CPU network interface controller, see dsa/dsa.txt
+- #size-cells: must be 0
+- #address-cells: must be 2, see dsa/dsa.txt
+
+Subnodes:
+
+The integrated switch subnode should be specified according to the binding
+described in dsa/dsa.txt.
+
+Optional properties:
+
+- reg-names: litteral names for the device base register addresses, when present
+ must be: "core", "reg", "intrl2_0", "intrl2_1", "fcb", "acb"
+
+- interrupt-names: litternal names for the device interrupt lines, when present
+ must be: "switch_0" and "switch_1"
+
+- brcm,num-gphy: specify the maximum number of integrated gigabit PHYs in the
+ switch
+
+- brcm,num-rgmii-ports: specify the maximum number of RGMII interfaces supported
+ by the switch
+
+- brcm,fcb-pause-override: boolean property, if present indicates that the switch
+ supports Failover Control Block pause override capability
+
+- brcm,acb-packets-inflight: boolean property, if present indicates that the switch
+ Admission Control Block supports reporting the number of packets in-flight in a
+ switch queue
+
+Example:
+
+switch_top@f0b00000 {
+ compatible = "simple-bus";
+ #size-cells = <1>;
+ #address-cells = <1>;
+ ranges = <0 0xf0b00000 0x40804>;
+
+ ethernet_switch@0 {
+ compatible = "brcm,bcm7445-switch-v4.0";
+ #size-cells = <0>;
+ #address-cells = <2>;
+ reg = <0x0 0x40000
+ 0x40000 0x110
+ 0x40340 0x30
+ 0x40380 0x30
+ 0x40400 0x34
+ 0x40600 0x208>;
+ interrupts = <0 0x18 0
+ 0 0x19 0>;
+ brcm,num-gphy = <1>;
+ brcm,num-rgmii-ports = <2>;
+ brcm,fcb-pause-override;
+ brcm,acb-packets-inflight;
+
+ ...
+ switch@0 {
+ reg = <0 0>;
+ #size-cells = <0>;
+ #address-cells <1>;
+
+ port@0 {
+ label = "gphy";
+ reg = <0>;
+ };
+ ...
+ };
+ };
+};
--
1.9.1
^ permalink raw reply related
* [PATCH net-next v3 10/12] net: dsa: add Broadcom SF2 switch driver
From: Florian Fainelli @ 2014-08-24 18:44 UTC (permalink / raw)
To: netdev; +Cc: davem, jhs, linville, alexander.h.duyck, Florian Fainelli
In-Reply-To: <1408905869-10471-1-git-send-email-f.fainelli@gmail.com>
Add support for the Broadcom Starfigther 2 switch chip using a DSA
driver. This switch driver supports the following features:
- configuration of the external switch port interface: MII, RevMII,
RGMII and RGMII_NO_ID are supported
- support for the per-port MIB counters
- support for link interrupts for special ports (e.g: MoCA)
- powering up/down of switch memories to conserve power when ports are
unused
Finally, update the compatible property for the DSA core code to match
our switch top-level compatible node.
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
No changes in v3
Changes in v2:
- add support for reading to special MDIO phys (0 and 30)
- added more power down optimization
- added VLAN separation
drivers/net/dsa/Kconfig | 11 +
drivers/net/dsa/Makefile | 1 +
drivers/net/dsa/bcm_sf2.c | 626 +++++++++++++++++++++++++++++++++++++++++
drivers/net/dsa/bcm_sf2.h | 139 +++++++++
drivers/net/dsa/bcm_sf2_regs.h | 228 +++++++++++++++
net/dsa/dsa.c | 1 +
6 files changed, 1006 insertions(+)
create mode 100644 drivers/net/dsa/bcm_sf2.c
create mode 100644 drivers/net/dsa/bcm_sf2.h
create mode 100644 drivers/net/dsa/bcm_sf2_regs.h
diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig
index b8fe808b7957..3472af31821f 100644
--- a/drivers/net/dsa/Kconfig
+++ b/drivers/net/dsa/Kconfig
@@ -36,4 +36,15 @@ config NET_DSA_MV88E6123_61_65
This enables support for the Marvell 88E6123/6161/6165
ethernet switch chips.
+config NET_DSA_BCM_SF2
+ tristate "Broadcom Starfighter 2 Ethernet switch support"
+ select NET_DSA
+ select NET_DSA_TAG_BRCM
+ select FIXED_PHY
+ select BCM7XXX_PHY
+ select MDIO_BCM_UNIMAC
+ ---help---
+ This enables support for the Broadcom Starfighter 2 Ethernet
+ switch chips.
+
endmenu
diff --git a/drivers/net/dsa/Makefile b/drivers/net/dsa/Makefile
index f3bda05536cc..dd3cd3b8157f 100644
--- a/drivers/net/dsa/Makefile
+++ b/drivers/net/dsa/Makefile
@@ -7,3 +7,4 @@ endif
ifdef CONFIG_NET_DSA_MV88E6131
mv88e6xxx_drv-y += mv88e6131.o
endif
+obj-$(CONFIG_NET_DSA_BCM_SF2) += bcm_sf2.o
diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c
new file mode 100644
index 000000000000..cb06d11bddb7
--- /dev/null
+++ b/drivers/net/dsa/bcm_sf2.c
@@ -0,0 +1,626 @@
+/*
+ * Broadcom Starfighter 2 DSA switch driver
+ *
+ * Copyright (C) 2014, Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/phy.h>
+#include <linux/phy_fixed.h>
+#include <linux/mii.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <net/dsa.h>
+
+#include "bcm_sf2.h"
+#include "bcm_sf2_regs.h"
+
+/* String, offset, and register size in bytes if different from 4 bytes */
+static const struct bcm_sf2_hw_stats bcm_sf2_mib[] = {
+ { "TxOctets", 0x000, 8 },
+ { "TxDropPkts", 0x020 },
+ { "TxQPKTQ0", 0x030 },
+ { "TxBroadcastPkts", 0x040 },
+ { "TxMulticastPkts", 0x050 },
+ { "TxUnicastPKts", 0x060 },
+ { "TxCollisions", 0x070 },
+ { "TxSingleCollision", 0x080 },
+ { "TxMultipleCollision", 0x090 },
+ { "TxDeferredCollision", 0x0a0 },
+ { "TxLateCollision", 0x0b0 },
+ { "TxExcessiveCollision", 0x0c0 },
+ { "TxFrameInDisc", 0x0d0 },
+ { "TxPausePkts", 0x0e0 },
+ { "TxQPKTQ1", 0x0f0 },
+ { "TxQPKTQ2", 0x100 },
+ { "TxQPKTQ3", 0x110 },
+ { "TxQPKTQ4", 0x120 },
+ { "TxQPKTQ5", 0x130 },
+ { "RxOctets", 0x140, 8 },
+ { "RxUndersizePkts", 0x160 },
+ { "RxPausePkts", 0x170 },
+ { "RxPkts64Octets", 0x180 },
+ { "RxPkts65to127Octets", 0x190 },
+ { "RxPkts128to255Octets", 0x1a0 },
+ { "RxPkts256to511Octets", 0x1b0 },
+ { "RxPkts512to1023Octets", 0x1c0 },
+ { "RxPkts1024toMaxPktsOctets", 0x1d0 },
+ { "RxOversizePkts", 0x1e0 },
+ { "RxJabbers", 0x1f0 },
+ { "RxAlignmentErrors", 0x200 },
+ { "RxFCSErrors", 0x210 },
+ { "RxGoodOctets", 0x220, 8 },
+ { "RxDropPkts", 0x240 },
+ { "RxUnicastPkts", 0x250 },
+ { "RxMulticastPkts", 0x260 },
+ { "RxBroadcastPkts", 0x270 },
+ { "RxSAChanges", 0x280 },
+ { "RxFragments", 0x290 },
+ { "RxJumboPkt", 0x2a0 },
+ { "RxSymblErr", 0x2b0 },
+ { "InRangeErrCount", 0x2c0 },
+ { "OutRangeErrCount", 0x2d0 },
+ { "EEELpiEvent", 0x2e0 },
+ { "EEELpiDuration", 0x2f0 },
+ { "RxDiscard", 0x300, 8 },
+ { "TxQPKTQ6", 0x320 },
+ { "TxQPKTQ7", 0x330 },
+ { "TxPkts64Octets", 0x340 },
+ { "TxPkts65to127Octets", 0x350 },
+ { "TxPkts128to255Octets", 0x360 },
+ { "TxPkts256to511Ocets", 0x370 },
+ { "TxPkts512to1023Ocets", 0x380 },
+ { "TxPkts1024toMaxPktOcets", 0x390 },
+};
+
+#define BCM_SF2_STATS_SIZE ARRAY_SIZE(bcm_sf2_mib)
+
+static void bcm_sf2_sw_get_strings(struct dsa_switch *ds,
+ int port, uint8_t *data)
+{
+ unsigned int i;
+
+ for (i = 0; i < BCM_SF2_STATS_SIZE; i++)
+ memcpy(data + i * ETH_GSTRING_LEN,
+ bcm_sf2_mib[i].string, ETH_GSTRING_LEN);
+}
+
+static void bcm_sf2_sw_get_ethtool_stats(struct dsa_switch *ds,
+ int port, uint64_t *data)
+{
+ struct bcm_sf2_priv *priv = ds_to_priv(ds);
+ const struct bcm_sf2_hw_stats *s;
+ unsigned int i;
+ u64 val = 0;
+ u32 offset;
+
+ mutex_lock(&priv->stats_mutex);
+
+ /* Now fetch the per-port counters */
+ for (i = 0; i < BCM_SF2_STATS_SIZE; i++) {
+ s = &bcm_sf2_mib[i];
+
+ /* Do a latched 64-bit read if needed */
+ offset = s->reg + CORE_P_MIB_OFFSET(port);
+ if (s->sizeof_stat == 8)
+ val = core_readq(priv, offset);
+ else
+ val = core_readl(priv, offset);
+
+ data[i] = (u64)val;
+ }
+
+ mutex_unlock(&priv->stats_mutex);
+}
+
+static int bcm_sf2_sw_get_sset_count(struct dsa_switch *ds)
+{
+ return BCM_SF2_STATS_SIZE;
+}
+
+static char *bcm_sf2_sw_probe(struct mii_bus *bus, int sw_addr)
+{
+ return "Broadcom Starfighter 2";
+}
+
+static void bcm_sf2_imp_setup(struct dsa_switch *ds, int port)
+{
+ struct bcm_sf2_priv *priv = ds_to_priv(ds);
+ unsigned int i;
+ u32 reg, val;
+
+ /* Enable the port memories */
+ reg = core_readl(priv, CORE_MEM_PSM_VDD_CTRL);
+ reg &= ~P_TXQ_PSM_VDD(port);
+ core_writel(priv, reg, CORE_MEM_PSM_VDD_CTRL);
+
+ /* Enable Broadcast, Multicast, Unicast forwarding to IMP port */
+ reg = core_readl(priv, CORE_IMP_CTL);
+ reg |= (RX_BCST_EN | RX_MCST_EN | RX_UCST_EN);
+ reg &= ~(RX_DIS | TX_DIS);
+ core_writel(priv, reg, CORE_IMP_CTL);
+
+ /* Enable forwarding */
+ core_writel(priv, SW_FWDG_EN, CORE_SWMODE);
+
+ /* Enable IMP port in dumb mode */
+ reg = core_readl(priv, CORE_SWITCH_CTRL);
+ reg |= MII_DUMB_FWDG_EN;
+ core_writel(priv, reg, CORE_SWITCH_CTRL);
+
+ /* Resolve which bit controls the Broadcom tag */
+ switch (port) {
+ case 8:
+ val = BRCM_HDR_EN_P8;
+ break;
+ case 7:
+ val = BRCM_HDR_EN_P7;
+ break;
+ case 5:
+ val = BRCM_HDR_EN_P5;
+ break;
+ default:
+ val = 0;
+ break;
+ }
+
+ /* Enable Broadcom tags for IMP port */
+ reg = core_readl(priv, CORE_BRCM_HDR_CTRL);
+ reg |= val;
+ core_writel(priv, reg, CORE_BRCM_HDR_CTRL);
+
+ /* Enable reception Broadcom tag for CPU TX (switch RX) to
+ * allow us to tag outgoing frames
+ */
+ reg = core_readl(priv, CORE_BRCM_HDR_RX_DIS);
+ reg &= ~(1 << port);
+ core_writel(priv, reg, CORE_BRCM_HDR_RX_DIS);
+
+ /* Enable transmission of Broadcom tags from the switch (CPU RX) to
+ * allow delivering frames to the per-port net_devices
+ */
+ reg = core_readl(priv, CORE_BRCM_HDR_TX_DIS);
+ reg &= ~(1 << port);
+ core_writel(priv, reg, CORE_BRCM_HDR_TX_DIS);
+
+ /* Force link status for IMP port */
+ reg = core_readl(priv, CORE_STS_OVERRIDE_IMP);
+ reg |= (MII_SW_OR | LINK_STS);
+ core_writel(priv, reg, CORE_STS_OVERRIDE_IMP);
+
+ /* Enable the IMP Port to be in the same VLAN as the other ports
+ * on a per-port basis such that we only have Port i and IMP in
+ * the same VLAN.
+ */
+ for (i = 0; i < priv->hw_params.num_ports; i++) {
+ if (!((1 << i) & ds->phys_port_mask))
+ continue;
+
+ reg = core_readl(priv, CORE_PORT_VLAN_CTL_PORT(i));
+ reg |= (1 << port);
+ core_writel(priv, reg, CORE_PORT_VLAN_CTL_PORT(i));
+ }
+}
+
+static void bcm_sf2_port_setup(struct dsa_switch *ds, int port)
+{
+ struct bcm_sf2_priv *priv = ds_to_priv(ds);
+ u32 reg;
+
+ /* Clear the memory power down */
+ reg = core_readl(priv, CORE_MEM_PSM_VDD_CTRL);
+ reg &= ~P_TXQ_PSM_VDD(port);
+ core_writel(priv, reg, CORE_MEM_PSM_VDD_CTRL);
+
+ /* Clear the Rx and Tx disable bits and set to no spanning tree */
+ core_writel(priv, 0, CORE_G_PCTL_PORT(port));
+
+ /* Enable port 7 interrupts to get notified */
+ if (port == 7)
+ intrl2_1_mask_clear(priv, P_IRQ_MASK(P7_IRQ_OFF));
+
+ /* Set this port, and only this one to be in the default VLAN */
+ reg = core_readl(priv, CORE_PORT_VLAN_CTL_PORT(port));
+ reg &= ~PORT_VLAN_CTRL_MASK;
+ reg |= (1 << port);
+ core_writel(priv, reg, CORE_PORT_VLAN_CTL_PORT(port));
+}
+
+static void bcm_sf2_port_disable(struct dsa_switch *ds, int port)
+{
+ struct bcm_sf2_priv *priv = ds_to_priv(ds);
+ u32 off, reg;
+
+ if (dsa_is_cpu_port(ds, port))
+ off = CORE_IMP_CTL;
+ else
+ off = CORE_G_PCTL_PORT(port);
+
+ reg = core_readl(priv, off);
+ reg |= RX_DIS | TX_DIS;
+ core_writel(priv, reg, off);
+
+ /* Power down the port memory */
+ reg = core_readl(priv, CORE_MEM_PSM_VDD_CTRL);
+ reg |= P_TXQ_PSM_VDD(port);
+ core_writel(priv, reg, CORE_MEM_PSM_VDD_CTRL);
+}
+
+static irqreturn_t bcm_sf2_switch_0_isr(int irq, void *dev_id)
+{
+ struct bcm_sf2_priv *priv = dev_id;
+
+ priv->irq0_stat = intrl2_0_readl(priv, INTRL2_CPU_STATUS) &
+ ~priv->irq0_mask;
+ intrl2_0_writel(priv, priv->irq0_stat, INTRL2_CPU_CLEAR);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t bcm_sf2_switch_1_isr(int irq, void *dev_id)
+{
+ struct bcm_sf2_priv *priv = dev_id;
+
+ priv->irq1_stat = intrl2_1_readl(priv, INTRL2_CPU_STATUS) &
+ ~priv->irq1_mask;
+ intrl2_1_writel(priv, priv->irq1_stat, INTRL2_CPU_CLEAR);
+
+ if (priv->irq1_stat & P_LINK_UP_IRQ(P7_IRQ_OFF))
+ priv->port_sts[7].link = 1;
+ if (priv->irq1_stat & P_LINK_DOWN_IRQ(P7_IRQ_OFF))
+ priv->port_sts[7].link = 0;
+
+ return IRQ_HANDLED;
+}
+
+static int bcm_sf2_sw_setup(struct dsa_switch *ds)
+{
+ const char *reg_names[BCM_SF2_REGS_NUM] = BCM_SF2_REGS_NAME;
+ struct bcm_sf2_priv *priv = ds_to_priv(ds);
+ struct device_node *dn;
+ void __iomem **base;
+ unsigned int port;
+ unsigned int i;
+ u32 reg, rev;
+ int ret;
+
+ spin_lock_init(&priv->indir_lock);
+ mutex_init(&priv->stats_mutex);
+
+ /* All the interesting properties are at the parent device_node
+ * level
+ */
+ dn = ds->pd->of_node->parent;
+
+ priv->irq0 = irq_of_parse_and_map(dn, 0);
+ priv->irq1 = irq_of_parse_and_map(dn, 1);
+
+ base = &priv->core;
+ for (i = 0; i < BCM_SF2_REGS_NUM; i++) {
+ *base = of_iomap(dn, i);
+ if (*base == NULL) {
+ pr_err("unable to find register: %s\n", reg_names[i]);
+ return -ENODEV;
+ }
+ base++;
+ }
+
+ /* Disable all interrupts and request them */
+ intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_MASK_SET);
+ intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR);
+ intrl2_0_writel(priv, 0, INTRL2_CPU_MASK_CLEAR);
+ intrl2_1_writel(priv, 0xffffffff, INTRL2_CPU_MASK_SET);
+ intrl2_1_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR);
+ intrl2_1_writel(priv, 0, INTRL2_CPU_MASK_CLEAR);
+
+ ret = request_irq(priv->irq0, bcm_sf2_switch_0_isr, 0,
+ "switch_0", priv);
+ if (ret < 0) {
+ pr_err("failed to request switch_0 IRQ\n");
+ goto out_unmap;
+ }
+
+ ret = request_irq(priv->irq1, bcm_sf2_switch_1_isr, 0,
+ "switch_1", priv);
+ if (ret < 0) {
+ pr_err("failed to request switch_1 IRQ\n");
+ goto out_free_irq0;
+ }
+
+ /* Reset the MIB counters */
+ reg = core_readl(priv, CORE_GMNCFGCFG);
+ reg |= RST_MIB_CNT;
+ core_writel(priv, reg, CORE_GMNCFGCFG);
+ reg &= ~RST_MIB_CNT;
+ core_writel(priv, reg, CORE_GMNCFGCFG);
+
+ /* Get the maximum number of ports for this switch */
+ priv->hw_params.num_ports = core_readl(priv, CORE_IMP0_PRT_ID) + 1;
+ if (priv->hw_params.num_ports > DSA_MAX_PORTS)
+ priv->hw_params.num_ports = DSA_MAX_PORTS;
+
+ /* Assume a single GPHY setup if we can't read that property */
+ if (of_property_read_u32(dn, "brcm,num-gphy",
+ &priv->hw_params.num_gphy))
+ priv->hw_params.num_gphy = 1;
+
+ /* Enable all valid ports and disable those unused */
+ for (port = 0; port < priv->hw_params.num_ports; port++) {
+ /* IMP port receives special treatment */
+ if ((1 << port) & ds->phys_port_mask)
+ bcm_sf2_port_setup(ds, port);
+ else if (dsa_is_cpu_port(ds, port))
+ bcm_sf2_imp_setup(ds, port);
+ else
+ bcm_sf2_port_disable(ds, port);
+ }
+
+ /* Include the pseudo-PHY address and the broadcast PHY address to
+ * divert reads towards our workaround
+ */
+ ds->phys_mii_mask |= ((1 << 30) | (1 << 0));
+
+ rev = reg_readl(priv, REG_SWITCH_REVISION);
+ priv->hw_params.top_rev = (rev >> SWITCH_TOP_REV_SHIFT) &
+ SWITCH_TOP_REV_MASK;
+ priv->hw_params.core_rev = (rev & SF2_REV_MASK);
+
+ pr_info("Starfigther 2 top: %x.%02x, core: %x.%02x base: 0x%p, IRQs: %d, %d\n",
+ priv->hw_params.top_rev >> 8, priv->hw_params.top_rev & 0xff,
+ priv->hw_params.core_rev >> 8, priv->hw_params.core_rev & 0xff,
+ priv->core, priv->irq0, priv->irq1);
+
+ return 0;
+
+out_free_irq0:
+ free_irq(priv->irq0, priv);
+out_unmap:
+ base = &priv->core;
+ for (i = 0; i < BCM_SF2_REGS_NUM; i++) {
+ iounmap(*base);
+ base++;
+ }
+ return ret;
+}
+
+static int bcm_sf2_sw_set_addr(struct dsa_switch *ds, u8 *addr)
+{
+ return 0;
+}
+
+static int bcm_sf2_sw_indir_rw(struct dsa_switch *ds, int op, int addr,
+ int regnum, u16 val)
+{
+ struct bcm_sf2_priv *priv = ds_to_priv(ds);
+ int ret = 0;
+ u32 reg;
+
+ reg = reg_readl(priv, REG_SWITCH_CNTRL);
+ reg |= MDIO_MASTER_SEL;
+ reg_writel(priv, reg, REG_SWITCH_CNTRL);
+
+ /* Page << 8 | offset */
+ reg = 0x70;
+ reg <<= 2;
+ core_writel(priv, addr, reg);
+
+ /* Page << 8 | offset */
+ reg = 0x80 << 8 | regnum << 1;
+ reg <<= 2;
+
+ if (op)
+ ret = core_readl(priv, reg);
+ else
+ core_writel(priv, val, reg);
+
+ reg = reg_readl(priv, REG_SWITCH_CNTRL);
+ reg &= ~MDIO_MASTER_SEL;
+ reg_writel(priv, reg, REG_SWITCH_CNTRL);
+
+ return ret & 0xffff;
+}
+
+static int bcm_sf2_sw_phy_read(struct dsa_switch *ds, int addr, int regnum)
+{
+ /* Intercept reads from the MDIO broadcast address or Broadcom
+ * pseudo-PHY address
+ */
+ switch (addr) {
+ case 0:
+ case 30:
+ return bcm_sf2_sw_indir_rw(ds, 1, addr, regnum, 0);
+ default:
+ return 0xffff;
+ }
+}
+
+static int bcm_sf2_sw_phy_write(struct dsa_switch *ds, int addr, int regnum,
+ u16 val)
+{
+ /* Intercept writes to the MDIO broadcast address or Broadcom
+ * pseudo-PHY address
+ */
+ switch (addr) {
+ case 0:
+ case 30:
+ bcm_sf2_sw_indir_rw(ds, 0, addr, regnum, val);
+ break;
+ }
+
+ return 0;
+}
+
+static void bcm_sf2_sw_adjust_link(struct dsa_switch *ds, int port,
+ struct phy_device *phydev)
+{
+ struct bcm_sf2_priv *priv = ds_to_priv(ds);
+ u32 id_mode_dis = 0, port_mode;
+ const char *str = NULL;
+ u32 reg;
+
+ switch (phydev->interface) {
+ case PHY_INTERFACE_MODE_RGMII:
+ str = "RGMII (no delay)";
+ id_mode_dis = 1;
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+ if (!str)
+ str = "RGMII (TX delay)";
+ port_mode = EXT_GPHY;
+ break;
+ case PHY_INTERFACE_MODE_MII:
+ str = "MII";
+ port_mode = EXT_EPHY;
+ break;
+ case PHY_INTERFACE_MODE_REVMII:
+ str = "Reverse MII";
+ port_mode = EXT_REVMII;
+ break;
+ default:
+ goto force_link;
+ }
+
+ /* Clear id_mode_dis bit, and the existing port mode, but
+ * make sure we enable the RGMII block for data to pass
+ */
+ reg = reg_readl(priv, REG_RGMII_CNTRL_P(port));
+ reg &= ~ID_MODE_DIS;
+ reg &= ~(PORT_MODE_MASK << PORT_MODE_SHIFT);
+ reg &= ~(RX_PAUSE_EN | TX_PAUSE_EN);
+
+ reg |= port_mode | RGMII_MODE_EN;
+ if (id_mode_dis)
+ reg |= ID_MODE_DIS;
+
+ if (phydev->pause) {
+ if (phydev->asym_pause)
+ reg |= TX_PAUSE_EN;
+ reg |= RX_PAUSE_EN;
+ }
+
+ reg_writel(priv, reg, REG_RGMII_CNTRL_P(port));
+
+ pr_info("Port %d configured for %s\n", port, str);
+
+force_link:
+ /* Force link settings detected from the PHY */
+ reg = SW_OVERRIDE;
+ switch (phydev->speed) {
+ case SPEED_1000:
+ reg |= SPDSTS_1000 << SPEED_SHIFT;
+ break;
+ case SPEED_100:
+ reg |= SPDSTS_100 << SPEED_SHIFT;
+ break;
+ }
+
+ if (phydev->link)
+ reg |= LINK_STS;
+ if (phydev->duplex == DUPLEX_FULL)
+ reg |= DUPLX_MODE;
+
+ core_writel(priv, reg, CORE_STS_OVERRIDE_GMIIP_PORT(port));
+}
+
+static void bcm_sf2_sw_fixed_link_update(struct dsa_switch *ds, int port,
+ struct fixed_phy_status *status)
+{
+ struct bcm_sf2_priv *priv = ds_to_priv(ds);
+ u32 link, duplex, pause, speed;
+ u32 reg;
+
+ link = core_readl(priv, CORE_LNKSTS);
+ duplex = core_readl(priv, CORE_DUPSTS);
+ pause = core_readl(priv, CORE_PAUSESTS);
+ speed = core_readl(priv, CORE_SPDSTS);
+
+ speed >>= (port * SPDSTS_SHIFT);
+ speed &= SPDSTS_MASK;
+
+ status->link = 0;
+
+ /* Port 7 is special as we do not get link status from CORE_LNKSTS,
+ * which means that we need to force the link at the port override
+ * level to get the data to flow. We do use what the interrupt handler
+ * did determine before.
+ */
+ if (port == 7) {
+ status->link = priv->port_sts[port].link;
+ reg = core_readl(priv, CORE_STS_OVERRIDE_GMIIP_PORT(7));
+ reg |= SW_OVERRIDE;
+ if (status->link)
+ reg |= LINK_STS;
+ else
+ reg &= ~LINK_STS;
+ core_writel(priv, reg, CORE_STS_OVERRIDE_GMIIP_PORT(7));
+ status->duplex = 1;
+ } else {
+ status->link = !!(link & (1 << port));
+ status->duplex = !!(duplex & (1 << port));
+ }
+
+ switch (speed) {
+ case SPDSTS_10:
+ status->speed = SPEED_10;
+ break;
+ case SPDSTS_100:
+ status->speed = SPEED_100;
+ break;
+ case SPDSTS_1000:
+ status->speed = SPEED_1000;
+ break;
+ }
+
+ if ((pause & (1 << port)) &&
+ (pause & (1 << (port + PAUSESTS_TX_PAUSE_SHIFT)))) {
+ status->asym_pause = 1;
+ status->pause = 1;
+ }
+
+ if (pause & (1 << port))
+ status->pause = 1;
+}
+
+static struct dsa_switch_driver bcm_sf2_switch_driver = {
+ .tag_protocol = htons(ETH_P_BRCMTAG),
+ .priv_size = sizeof(struct bcm_sf2_priv),
+ .probe = bcm_sf2_sw_probe,
+ .setup = bcm_sf2_sw_setup,
+ .set_addr = bcm_sf2_sw_set_addr,
+ .phy_read = bcm_sf2_sw_phy_read,
+ .phy_write = bcm_sf2_sw_phy_write,
+ .get_strings = bcm_sf2_sw_get_strings,
+ .get_ethtool_stats = bcm_sf2_sw_get_ethtool_stats,
+ .get_sset_count = bcm_sf2_sw_get_sset_count,
+ .adjust_link = bcm_sf2_sw_adjust_link,
+ .fixed_link_update = bcm_sf2_sw_fixed_link_update,
+};
+
+static int __init bcm_sf2_init(void)
+{
+ register_switch_driver(&bcm_sf2_switch_driver);
+
+ return 0;
+}
+module_init(bcm_sf2_init);
+
+static void __exit bcm_sf2_exit(void)
+{
+ unregister_switch_driver(&bcm_sf2_switch_driver);
+}
+module_exit(bcm_sf2_exit);
+
+MODULE_AUTHOR("Broadcom Corporation");
+MODULE_DESCRIPTION("Driver for Broadcom Starfighter 2 ethernet switch chip");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:brcm-sf2");
diff --git a/drivers/net/dsa/bcm_sf2.h b/drivers/net/dsa/bcm_sf2.h
new file mode 100644
index 000000000000..d374f23824f6
--- /dev/null
+++ b/drivers/net/dsa/bcm_sf2.h
@@ -0,0 +1,139 @@
+/*
+ * Broadcom Starfighter2 private context
+ *
+ * Copyright (C) 2014, Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __BCM_SF2_H
+#define __BCM_SF2_H
+
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <linux/mii.h>
+
+#include <net/dsa.h>
+
+#include "bcm_sf2_regs.h"
+
+struct bcm_sf2_hw_params {
+ u16 top_rev;
+ u16 core_rev;
+ u32 num_gphy;
+ u8 num_acb_queue;
+ u8 num_rgmii;
+ u8 num_ports;
+ u8 fcb_pause_override:1;
+ u8 acb_packets_inflight:1;
+};
+
+#define BCM_SF2_REGS_NAME {\
+ "core", "reg", "intrl2_0", "intrl2_1", "fcb", "acb" \
+}
+#define BCM_SF2_REGS_NUM 6
+
+struct bcm_sf2_port_status {
+ unsigned int link;
+};
+
+struct bcm_sf2_priv {
+ /* Base registers, keep those in order with BCM_SF2_REGS_NAME */
+ void __iomem *core;
+ void __iomem *reg;
+ void __iomem *intrl2_0;
+ void __iomem *intrl2_1;
+ void __iomem *fcb;
+ void __iomem *acb;
+
+ /* spinlock protecting access to the indirect registers */
+ spinlock_t indir_lock;
+
+ int irq0;
+ int irq1;
+ u32 irq0_stat;
+ u32 irq0_mask;
+ u32 irq1_stat;
+ u32 irq1_mask;
+
+ /* Mutex protecting access to the MIB counters */
+ struct mutex stats_mutex;
+
+ struct bcm_sf2_hw_params hw_params;
+
+ struct bcm_sf2_port_status port_sts[DSA_MAX_PORTS];
+};
+
+struct bcm_sf2_hw_stats {
+ const char *string;
+ u16 reg;
+ u8 sizeof_stat;
+};
+
+#define SF2_IO_MACRO(name) \
+static inline u32 name##_readl(struct bcm_sf2_priv *priv, u32 off) \
+{ \
+ return __raw_readl(priv->name + off); \
+} \
+static inline void name##_writel(struct bcm_sf2_priv *priv, \
+ u32 val, u32 off) \
+{ \
+ __raw_writel(val, priv->name + off); \
+} \
+
+/* Accesses to 64-bits register requires us to latch the hi/lo pairs
+ * using the REG_DIR_DATA_{READ,WRITE} ancillary registers. The 'indir_lock'
+ * spinlock is automatically grabbed and released to provide relative
+ * atomiticy with latched reads/writes.
+ */
+#define SF2_IO64_MACRO(name) \
+static inline u64 name##_readq(struct bcm_sf2_priv *priv, u32 off) \
+{ \
+ u32 indir, dir; \
+ spin_lock(&priv->indir_lock); \
+ indir = reg_readl(priv, REG_DIR_DATA_READ); \
+ dir = __raw_readl(priv->name + off); \
+ spin_unlock(&priv->indir_lock); \
+ return (u64)indir << 32 | dir; \
+} \
+static inline void name##_writeq(struct bcm_sf2_priv *priv, u32 off, \
+ u64 val) \
+{ \
+ spin_lock(&priv->indir_lock); \
+ reg_writel(priv, upper_32_bits(val), REG_DIR_DATA_WRITE); \
+ __raw_writel(lower_32_bits(val), priv->name + off); \
+ spin_unlock(&priv->indir_lock); \
+}
+
+#define SWITCH_INTR_L2(which) \
+static inline void intrl2_##which##_mask_clear(struct bcm_sf2_priv *priv, \
+ u32 mask) \
+{ \
+ intrl2_##which##_writel(priv, mask, INTRL2_CPU_MASK_CLEAR); \
+ priv->irq##which##_mask &= ~(mask); \
+} \
+static inline void intrl2_##which##_mask_set(struct bcm_sf2_priv *priv, \
+ u32 mask) \
+{ \
+ intrl2_## which##_writel(priv, mask, INTRL2_CPU_MASK_SET); \
+ priv->irq##which##_mask |= (mask); \
+} \
+
+SF2_IO_MACRO(core);
+SF2_IO_MACRO(reg);
+SF2_IO64_MACRO(core);
+SF2_IO_MACRO(intrl2_0);
+SF2_IO_MACRO(intrl2_1);
+SF2_IO_MACRO(fcb);
+SF2_IO_MACRO(acb);
+
+SWITCH_INTR_L2(0);
+SWITCH_INTR_L2(1);
+
+#endif /* __BCM_SF2_H */
diff --git a/drivers/net/dsa/bcm_sf2_regs.h b/drivers/net/dsa/bcm_sf2_regs.h
new file mode 100644
index 000000000000..9b92e1925992
--- /dev/null
+++ b/drivers/net/dsa/bcm_sf2_regs.h
@@ -0,0 +1,228 @@
+/*
+ * Broadcom Starfigther 2 switch register defines
+ *
+ * Copyright (C) 2014, Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#ifndef __BCM_SF2_REGS_H
+#define __BCM_SF2_REGS_H
+
+
+/* Register set relative to 'REG' */
+#define REG_SWITCH_CNTRL 0x00
+#define MDIO_MASTER_SEL (1 << 0)
+
+#define REG_SWITCH_STATUS 0x04
+#define REG_DIR_DATA_WRITE 0x08
+#define REG_DIR_DATA_READ 0x0C
+
+#define REG_SWITCH_REVISION 0x18
+#define SF2_REV_MASK 0xffff
+#define SWITCH_TOP_REV_SHIFT 16
+#define SWITCH_TOP_REV_MASK 0xffff
+
+#define REG_PHY_REVISION 0x1C
+
+#define REG_SPHY_CNTRL 0x2C
+#define IDDQ_BIAS (1 << 0)
+#define EXT_PWR_DOWN (1 << 1)
+#define FORCE_DLL_EN (1 << 2)
+#define IDDQ_GLOBAL_PWR (1 << 3)
+#define CK25_DIS (1 << 4)
+#define PHY_RESET (1 << 5)
+#define PHY_PHYAD_SHIFT 8
+#define PHY_PHYAD_MASK 0x1F
+
+#define REG_RGMII_0_BASE 0x34
+#define REG_RGMII_CNTRL 0x00
+#define REG_RGMII_IB_STATUS 0x04
+#define REG_RGMII_RX_CLOCK_DELAY_CNTRL 0x08
+#define REG_RGMII_CNTRL_SIZE 0x0C
+#define REG_RGMII_CNTRL_P(x) (REG_RGMII_0_BASE + \
+ ((x) * REG_RGMII_CNTRL_SIZE))
+/* Relative to REG_RGMII_CNTRL */
+#define RGMII_MODE_EN (1 << 0)
+#define ID_MODE_DIS (1 << 1)
+#define PORT_MODE_SHIFT 2
+#define INT_EPHY (0 << PORT_MODE_SHIFT)
+#define INT_GPHY (1 << PORT_MODE_SHIFT)
+#define EXT_EPHY (2 << PORT_MODE_SHIFT)
+#define EXT_GPHY (3 << PORT_MODE_SHIFT)
+#define EXT_REVMII (4 << PORT_MODE_SHIFT)
+#define PORT_MODE_MASK 0x7
+#define RVMII_REF_SEL (1 << 5)
+#define RX_PAUSE_EN (1 << 6)
+#define TX_PAUSE_EN (1 << 7)
+#define TX_CLK_STOP_EN (1 << 8)
+#define LPI_COUNT_SHIFT 9
+#define LPI_COUNT_MASK 0x3F
+
+/* Register set relative to 'INTRL2_0' and 'INTRL2_1' */
+#define INTRL2_CPU_STATUS 0x00
+#define INTRL2_CPU_SET 0x04
+#define INTRL2_CPU_CLEAR 0x08
+#define INTRL2_CPU_MASK_STATUS 0x0c
+#define INTRL2_CPU_MASK_SET 0x10
+#define INTRL2_CPU_MASK_CLEAR 0x14
+
+/* Shared INTRL2_0 and INTRL2_ interrupt sources macros */
+#define P_LINK_UP_IRQ(x) (1 << (0 + (x)))
+#define P_LINK_DOWN_IRQ(x) (1 << (1 + (x)))
+#define P_ENERGY_ON_IRQ(x) (1 << (2 + (x)))
+#define P_ENERGY_OFF_IRQ(x) (1 << (3 + (x)))
+#define P_GPHY_IRQ(x) (1 << (4 + (x)))
+#define P_NUM_IRQ 5
+#define P_IRQ_MASK(x) (P_LINK_UP_IRQ((x)) | \
+ P_LINK_DOWN_IRQ((x)) | \
+ P_ENERGY_ON_IRQ((x)) | \
+ P_ENERGY_OFF_IRQ((x)) | \
+ P_GPHY_IRQ((x)))
+
+/* INTRL2_0 interrupt sources */
+#define P0_IRQ_OFF 0
+#define MEM_DOUBLE_IRQ (1 << 5)
+#define EEE_LPI_IRQ (1 << 6)
+#define P5_CPU_WAKE_IRQ (1 << 7)
+#define P8_CPU_WAKE_IRQ (1 << 8)
+#define P7_CPU_WAKE_IRQ (1 << 9)
+#define IEEE1588_IRQ (1 << 10)
+#define MDIO_ERR_IRQ (1 << 11)
+#define MDIO_DONE_IRQ (1 << 12)
+#define GISB_ERR_IRQ (1 << 13)
+#define UBUS_ERR_IRQ (1 << 14)
+#define FAILOVER_ON_IRQ (1 << 15)
+#define FAILOVER_OFF_IRQ (1 << 16)
+#define TCAM_SOFT_ERR_IRQ (1 << 17)
+
+/* INTRL2_1 interrupt sources */
+#define P7_IRQ_OFF 0
+#define P_IRQ_OFF(x) ((6 - (x)) * P_NUM_IRQ)
+
+/* Register set relative to 'CORE' */
+#define CORE_G_PCTL_PORT0 0x00000
+#define CORE_G_PCTL_PORT(x) (CORE_G_PCTL_PORT0 + (x * 0x4))
+#define CORE_IMP_CTL 0x00020
+#define RX_DIS (1 << 0)
+#define TX_DIS (1 << 1)
+#define RX_BCST_EN (1 << 2)
+#define RX_MCST_EN (1 << 3)
+#define RX_UCST_EN (1 << 4)
+#define G_MISTP_STATE_SHIFT 5
+#define G_MISTP_NO_STP (0 << G_MISTP_STATE_SHIFT)
+#define G_MISTP_DIS_STATE (1 << G_MISTP_STATE_SHIFT)
+#define G_MISTP_BLOCK_STATE (2 << G_MISTP_STATE_SHIFT)
+#define G_MISTP_LISTEN_STATE (3 << G_MISTP_STATE_SHIFT)
+#define G_MISTP_LEARN_STATE (4 << G_MISTP_STATE_SHIFT)
+#define G_MISTP_FWD_STATE (5 << G_MISTP_STATE_SHIFT)
+#define G_MISTP_STATE_MASK 0x7
+
+#define CORE_SWMODE 0x0002c
+#define SW_FWDG_MODE (1 << 0)
+#define SW_FWDG_EN (1 << 1)
+#define RTRY_LMT_DIS (1 << 2)
+
+#define CORE_STS_OVERRIDE_IMP 0x00038
+#define GMII_SPEED_UP_2G (1 << 6)
+#define MII_SW_OR (1 << 7)
+
+#define CORE_NEW_CTRL 0x00084
+#define IP_MC (1 << 0)
+#define OUTRANGEERR_DISCARD (1 << 1)
+#define INRANGEERR_DISCARD (1 << 2)
+#define CABLE_DIAG_LEN (1 << 3)
+#define OVERRIDE_AUTO_PD_WAR (1 << 4)
+#define EN_AUTO_PD_WAR (1 << 5)
+#define UC_FWD_EN (1 << 6)
+#define MC_FWD_EN (1 << 7)
+
+#define CORE_SWITCH_CTRL 0x00088
+#define MII_DUMB_FWDG_EN (1 << 6)
+
+#define CORE_SFT_LRN_CTRL 0x000f8
+#define SW_LEARN_CNTL(x) (1 << (x))
+
+#define CORE_STS_OVERRIDE_GMIIP_PORT(x) (0x160 + (x) * 4)
+#define LINK_STS (1 << 0)
+#define DUPLX_MODE (1 << 1)
+#define SPEED_SHIFT 2
+#define SPEED_MASK 0x3
+#define RXFLOW_CNTL (1 << 4)
+#define TXFLOW_CNTL (1 << 5)
+#define SW_OVERRIDE (1 << 6)
+
+#define CORE_WATCHDOG_CTRL 0x001e4
+#define SOFTWARE_RESET (1 << 7)
+#define EN_CHIP_RST (1 << 6)
+#define EN_SW_RESET (1 << 4)
+
+#define CORE_LNKSTS 0x00400
+#define LNK_STS_MASK 0x1ff
+
+#define CORE_SPDSTS 0x00410
+#define SPDSTS_10 0
+#define SPDSTS_100 1
+#define SPDSTS_1000 2
+#define SPDSTS_SHIFT 2
+#define SPDSTS_MASK 0x3
+
+#define CORE_DUPSTS 0x00420
+#define CORE_DUPSTS_MASK 0x1ff
+
+#define CORE_PAUSESTS 0x00428
+#define PAUSESTS_TX_PAUSE_SHIFT 9
+
+#define CORE_GMNCFGCFG 0x0800
+#define RST_MIB_CNT (1 << 0)
+#define RXBPDU_EN (1 << 1)
+
+#define CORE_IMP0_PRT_ID 0x0804
+
+#define CORE_BRCM_HDR_CTRL 0x0080c
+#define BRCM_HDR_EN_P8 (1 << 0)
+#define BRCM_HDR_EN_P5 (1 << 1)
+#define BRCM_HDR_EN_P7 (1 << 2)
+
+#define CORE_BRCM_HDR_CTRL2 0x0828
+
+#define CORE_HL_PRTC_CTRL 0x0940
+#define ARP_EN (1 << 0)
+#define RARP_EN (1 << 1)
+#define DHCP_EN (1 << 2)
+#define ICMPV4_EN (1 << 3)
+#define ICMPV6_EN (1 << 4)
+#define ICMPV6_FWD_MODE (1 << 5)
+#define IGMP_DIP_EN (1 << 8)
+#define IGMP_RPTLVE_EN (1 << 9)
+#define IGMP_RTPLVE_FWD_MODE (1 << 10)
+#define IGMP_QRY_EN (1 << 11)
+#define IGMP_QRY_FWD_MODE (1 << 12)
+#define IGMP_UKN_EN (1 << 13)
+#define IGMP_UKN_FWD_MODE (1 << 14)
+#define MLD_RPTDONE_EN (1 << 15)
+#define MLD_RPTDONE_FWD_MODE (1 << 16)
+#define MLD_QRY_EN (1 << 17)
+#define MLD_QRY_FWD_MODE (1 << 18)
+
+#define CORE_RST_MIB_CNT_EN 0x0950
+
+#define CORE_BRCM_HDR_RX_DIS 0x0980
+#define CORE_BRCM_HDR_TX_DIS 0x0988
+
+#define CORE_MEM_PSM_VDD_CTRL 0x2380
+#define P_TXQ_PSM_VDD_SHIFT 2
+#define P_TXQ_PSM_VDD_MASK 0x3
+#define P_TXQ_PSM_VDD(x) (P_TXQ_PSM_VDD_MASK << \
+ ((x) * P_TXQ_PSM_VDD_SHIFT))
+
+#define CORE_P0_MIB_OFFSET 0x8000
+#define P_MIB_SIZE 0x400
+#define CORE_P_MIB_OFFSET(x) (CORE_P0_MIB_OFFSET + (x) * P_MIB_SIZE)
+
+#define CORE_PORT_VLAN_CTL_PORT(x) (0xc400 + ((x) * 0x8))
+#define PORT_VLAN_CTRL_MASK 0x1ff
+
+#endif /* __BCM_SF2_REGS_H */
diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c
index cd33ddf6ff4f..65c6068a9435 100644
--- a/net/dsa/dsa.c
+++ b/net/dsa/dsa.c
@@ -617,6 +617,7 @@ static void dsa_shutdown(struct platform_device *pdev)
}
static const struct of_device_id dsa_of_match_table[] = {
+ { .compatible = "brcm,bcm7445-switch-v4.0" },
{ .compatible = "marvell,dsa", },
{}
};
--
1.9.1
^ permalink raw reply related
* [PATCH net-next v3 11/12] Documentation: devicetree: update dsa binding with optional properties
From: Florian Fainelli @ 2014-08-24 18:44 UTC (permalink / raw)
To: netdev; +Cc: davem, jhs, linville, alexander.h.duyck, Florian Fainelli
In-Reply-To: <1408905869-10471-1-git-send-email-f.fainelli@gmail.com>
Add documentation for a bunch of new optional properties described in
ethernet.txt and fixed-link.txt, this includes: 'phy-handle', 'phy-mode'
and the 'fixed-link' subnode.
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
Documentation/devicetree/bindings/net/dsa/dsa.txt | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/Documentation/devicetree/bindings/net/dsa/dsa.txt b/Documentation/devicetree/bindings/net/dsa/dsa.txt
index 49f4f7ae3f51..6192f9a7aa89 100644
--- a/Documentation/devicetree/bindings/net/dsa/dsa.txt
+++ b/Documentation/devicetree/bindings/net/dsa/dsa.txt
@@ -39,6 +39,22 @@ Optionnal property:
This property is only used when switches are being
chained/cascaded together.
+- phy-handle : Phandle to a PHY on an external MDIO bus, not the
+ switch internal one. See
+ Documentation/devicetree/bindings/net/ethernet.txt
+ for details.
+
+- phy-mode : String representing the connection to the designeted
+ PHY node specified by the 'phy-handle' property. See
+ Documentation/devicetree/bindings/net/ethernet.txt
+ for details.
+
+Optionnal subnodes:
+- fixed-link : Fixed-link subnode describing a link to a non-MDIO
+ managed entity. See
+ Documentation/devicetree/bindings/net/fixed-link.txt
+ for details.
+
Example:
dsa@0 {
@@ -58,6 +74,7 @@ Example:
port@0 {
reg = <0>;
label = "lan1";
+ phy-handle = <&phy0>;
};
port@1 {
--
1.9.1
^ permalink raw reply related
* [PATCH net-next v3 09/12] net: dsa: add Broadcom tag RX/TX handler
From: Florian Fainelli @ 2014-08-24 18:44 UTC (permalink / raw)
To: netdev; +Cc: davem, jhs, linville, alexander.h.duyck, Florian Fainelli
In-Reply-To: <1408905869-10471-1-git-send-email-f.fainelli@gmail.com>
Add support for the 4-bytes Broadcom tag that built-in switches such as
the Starfighter 2 might insert when receiving packets, or that we need
to insert while targetting specific switch ports. We use a fake
EtherType field for this 4-bytes switch tag: ETH_P_BRCMTAG since we need
to use the skb->protocol override in the receive path.
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
Changes in v3:
- add ETH_P_BRCMTAG as part of this changeset and not in a previous patch
- fixed an early de-reference in the receive hook
include/uapi/linux/if_ether.h | 1 +
net/dsa/Kconfig | 3 +
net/dsa/Makefile | 1 +
net/dsa/dsa.c | 6 ++
net/dsa/dsa_priv.h | 4 +
net/dsa/slave.c | 17 +++++
net/dsa/tag_brcm.c | 173 ++++++++++++++++++++++++++++++++++++++++++
7 files changed, 205 insertions(+)
create mode 100644 net/dsa/tag_brcm.c
diff --git a/include/uapi/linux/if_ether.h b/include/uapi/linux/if_ether.h
index 0f8210b8e0bc..2e9f13768abd 100644
--- a/include/uapi/linux/if_ether.h
+++ b/include/uapi/linux/if_ether.h
@@ -128,6 +128,7 @@
#define ETH_P_PHONET 0x00F5 /* Nokia Phonet frames */
#define ETH_P_IEEE802154 0x00F6 /* IEEE802.15.4 frame */
#define ETH_P_CAIF 0x00F7 /* ST-Ericsson CAIF protocol */
+#define ETH_P_BRCMTAG 0x00F8 /* Broadcom tag (4 bytes *) */
/*
* This is an Ethernet frame header.
diff --git a/net/dsa/Kconfig b/net/dsa/Kconfig
index f5eede1d6cb8..a585fd6352eb 100644
--- a/net/dsa/Kconfig
+++ b/net/dsa/Kconfig
@@ -12,6 +12,9 @@ config NET_DSA
if NET_DSA
# tagging formats
+config NET_DSA_TAG_BRCM
+ bool
+
config NET_DSA_TAG_DSA
bool
diff --git a/net/dsa/Makefile b/net/dsa/Makefile
index 7b9fcbbeda5d..da06ed1df620 100644
--- a/net/dsa/Makefile
+++ b/net/dsa/Makefile
@@ -3,6 +3,7 @@ obj-$(CONFIG_NET_DSA) += dsa_core.o
dsa_core-y += dsa.o slave.o
# tagging formats
+dsa_core-$(CONFIG_NET_DSA_TAG_BRCM) += tag_brcm.o
dsa_core-$(CONFIG_NET_DSA_TAG_DSA) += tag_dsa.o
dsa_core-$(CONFIG_NET_DSA_TAG_EDSA) += tag_edsa.o
dsa_core-$(CONFIG_NET_DSA_TAG_TRAILER) += tag_trailer.o
diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c
index 62f2f4e67d7d..cd33ddf6ff4f 100644
--- a/net/dsa/dsa.c
+++ b/net/dsa/dsa.c
@@ -650,6 +650,9 @@ static int __init dsa_init_module(void)
#ifdef CONFIG_NET_DSA_TAG_TRAILER
dev_add_pack(&trailer_packet_type);
#endif
+#ifdef CONFIG_NET_DSA_TAG_BRCM
+ dev_add_pack(&brcm_tag_packet_type);
+#endif
return 0;
}
module_init(dsa_init_module);
@@ -665,6 +668,9 @@ static void __exit dsa_cleanup_module(void)
#ifdef CONFIG_NET_DSA_TAG_DSA
dev_remove_pack(&dsa_packet_type);
#endif
+#ifdef CONFIG_NET_DSA_TAG_BRCM
+ dev_remove_pack(&brcm_tag_packet_type);
+#endif
platform_driver_unregister(&dsa_driver);
}
module_exit(dsa_cleanup_module);
diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
index a7f6f0c5fa31..8fb71da70dd6 100644
--- a/net/dsa/dsa_priv.h
+++ b/net/dsa/dsa_priv.h
@@ -60,5 +60,9 @@ extern struct packet_type edsa_packet_type;
netdev_tx_t trailer_xmit(struct sk_buff *skb, struct net_device *dev);
extern struct packet_type trailer_packet_type;
+/* tag_brcm.c */
+netdev_tx_t brcm_tag_xmit(struct sk_buff *skb, struct net_device *dev);
+extern struct packet_type brcm_tag_packet_type;
+
#endif
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index ee019ec29dec..279728c53c91 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -295,6 +295,18 @@ static const struct ethtool_ops dsa_slave_ethtool_ops = {
.get_sset_count = dsa_slave_get_sset_count,
};
+#ifdef CONFIG_NET_DSA_TAG_BRCM
+static const struct net_device_ops brcm_netdev_ops = {
+ .ndo_init = dsa_slave_init,
+ .ndo_open = dsa_slave_open,
+ .ndo_stop = dsa_slave_close,
+ .ndo_start_xmit = brcm_tag_xmit,
+ .ndo_change_rx_flags = dsa_slave_change_rx_flags,
+ .ndo_set_rx_mode = dsa_slave_set_rx_mode,
+ .ndo_set_mac_address = dsa_slave_set_mac_address,
+ .ndo_do_ioctl = dsa_slave_ioctl,
+};
+#endif
#ifdef CONFIG_NET_DSA_TAG_DSA
static const struct net_device_ops dsa_netdev_ops = {
.ndo_init = dsa_slave_init,
@@ -474,6 +486,11 @@ dsa_slave_create(struct dsa_switch *ds, struct device *parent,
slave_dev->netdev_ops = &trailer_netdev_ops;
break;
#endif
+#ifdef CONFIG_NET_DSA_TAG_BRCM
+ case htons(ETH_P_BRCMTAG):
+ slave_dev->netdev_ops = &brcm_netdev_ops;
+ break;
+#endif
default:
slave_dev->netdev_ops = ¬ag_netdev_ops;
break;
diff --git a/net/dsa/tag_brcm.c b/net/dsa/tag_brcm.c
new file mode 100644
index 000000000000..4b1c2c1896a3
--- /dev/null
+++ b/net/dsa/tag_brcm.c
@@ -0,0 +1,173 @@
+/*
+ * Broadcom tag support
+ *
+ * Copyright (C) 2014 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/etherdevice.h>
+#include <linux/list.h>
+#include <linux/netdevice.h>
+#include <linux/slab.h>
+#include "dsa_priv.h"
+
+/* This tag length is 4 bytes, older ones were 6 bytes, we do not
+ * handle them
+ */
+#define BRCM_TAG_LEN 4
+
+/* Tag is constructed and desconstructed using byte by byte access
+ * because the tag is placed after the MAC Source Address, which does
+ * not make it 4-bytes aligned, so this might cause unaligned accesses
+ * on most systems where this is used.
+ */
+
+/* Ingress and egress opcodes */
+#define BRCM_OPCODE_SHIFT 5
+#define BRCM_OPCODE_MASK 0x7
+
+/* Ingress fields */
+/* 1st byte in the tag */
+#define BRCM_IG_TC_SHIFT 2
+#define BRCM_IG_TC_MASK 0x7
+/* 2nd byte in the tag */
+#define BRCM_IG_TE_MASK 0x3
+#define BRCM_IG_TS_SHIFT 7
+/* 3rd byte in the tag */
+#define BRCM_IG_DSTMAP2_MASK 1
+#define BRCM_IG_DSTMAP1_MASK 0xff
+
+/* Egress fields */
+
+/* 2nd byte in the tag */
+#define BRCM_EG_CID_MASK 0xff
+
+/* 3rd byte in the tag */
+#define BRCM_EG_RC_MASK 0xff
+#define BRCM_EG_RC_RSVD (3 << 6)
+#define BRCM_EG_RC_EXCEPTION (1 << 5)
+#define BRCM_EG_RC_PROT_SNOOP (1 << 4)
+#define BRCM_EG_RC_PROT_TERM (1 << 3)
+#define BRCM_EG_RC_SWITCH (1 << 2)
+#define BRCM_EG_RC_MAC_LEARN (1 << 1)
+#define BRCM_EG_RC_MIRROR (1 << 0)
+#define BRCM_EG_TC_SHIFT 5
+#define BRCM_EG_TC_MASK 0x7
+#define BRCM_EG_PID_MASK 0x1f
+
+netdev_tx_t brcm_tag_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct dsa_slave_priv *p = netdev_priv(dev);
+ u8 *brcm_tag;
+
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += skb->len;
+
+ if (skb_cow_head(skb, BRCM_TAG_LEN) < 0)
+ goto out_free;
+
+ skb_push(skb, BRCM_TAG_LEN);
+
+ memmove(skb->data, skb->data + BRCM_TAG_LEN, 2 * ETH_ALEN);
+
+ /* Build the tag after the MAC Source Address */
+ brcm_tag = skb->data + 2 * ETH_ALEN;
+
+ /* Set the ingress opcode, traffic class, tag enforcment is
+ * deprecated
+ */
+ brcm_tag[0] = (1 << BRCM_OPCODE_SHIFT) |
+ ((skb->priority << BRCM_IG_TC_SHIFT) & BRCM_IG_TC_MASK);
+ brcm_tag[1] = 0;
+ brcm_tag[2] = 0;
+ if (p->port == 8)
+ brcm_tag[2] = BRCM_IG_DSTMAP2_MASK;
+ brcm_tag[3] = (1 << p->port) & BRCM_IG_DSTMAP1_MASK;
+
+ /* Queue the SKB for transmission on the parent interface, but
+ * do not modify its EtherType
+ */
+ skb->protocol = htons(ETH_P_BRCMTAG);
+ skb->dev = p->parent->dst->master_netdev;
+ dev_queue_xmit(skb);
+
+ return NETDEV_TX_OK;
+
+out_free:
+ kfree_skb(skb);
+ return NETDEV_TX_OK;
+}
+
+static int brcm_tag_rcv(struct sk_buff *skb, struct net_device *dev,
+ struct packet_type *pt, struct net_device *orig_dev)
+{
+ struct dsa_switch_tree *dst = dev->dsa_ptr;
+ struct dsa_switch *ds;
+ int source_port;
+ u8 *brcm_tag;
+
+ if (unlikely(dst == NULL))
+ goto out_drop;
+
+ ds = dst->ds[0];
+
+ skb = skb_unshare(skb, GFP_ATOMIC);
+ if (skb == NULL)
+ goto out;
+
+ if (unlikely(!pskb_may_pull(skb, BRCM_TAG_LEN)))
+ goto out_drop;
+
+ /* skb->data points to the EtherType, the tag is right before it */
+ brcm_tag = skb->data - 2;
+
+ /* The opcode should never be different than 0b000 */
+ if (unlikely((brcm_tag[0] >> BRCM_OPCODE_SHIFT) & BRCM_OPCODE_MASK))
+ goto out_drop;
+
+ /* We should never see a reserved reason code without knowing how to
+ * handle it
+ */
+ WARN_ON(brcm_tag[2] & BRCM_EG_RC_RSVD);
+
+ /* Locate which port this is coming from */
+ source_port = brcm_tag[3] & BRCM_EG_PID_MASK;
+
+ /* Validate port against switch setup, either the port is totally */
+ if (source_port >= DSA_MAX_PORTS || ds->ports[source_port] == NULL)
+ goto out_drop;
+
+ /* Remove Broadcom tag and update checksum */
+ skb_pull_rcsum(skb, BRCM_TAG_LEN);
+
+ /* Move the Ethernet DA and SA */
+ memmove(skb->data - ETH_HLEN,
+ skb->data - ETH_HLEN - BRCM_TAG_LEN,
+ 2 * ETH_ALEN);
+
+ skb_push(skb, ETH_HLEN);
+ skb->pkt_type = PACKET_HOST;
+ skb->dev = ds->ports[source_port];
+ skb->protocol = eth_type_trans(skb, skb->dev);
+
+ skb->dev->stats.rx_packets++;
+ skb->dev->stats.rx_bytes += skb->len;
+
+ netif_receive_skb(skb);
+
+ return 0;
+
+out_drop:
+ kfree_skb(skb);
+out:
+ return 0;
+}
+
+struct packet_type brcm_tag_packet_type __read_mostly = {
+ .type = cpu_to_be16(ETH_P_BRCMTAG),
+ .func = brcm_tag_rcv,
+};
--
1.9.1
^ permalink raw reply related
* [PATCH net-next v3 05/12] net: dsa: allow for more complex PHY setups
From: Florian Fainelli @ 2014-08-24 18:44 UTC (permalink / raw)
To: netdev; +Cc: davem, jhs, linville, alexander.h.duyck, Florian Fainelli
In-Reply-To: <1408905869-10471-1-git-send-email-f.fainelli@gmail.com>
Modify the DSA slave interface to be bound to an arbitray PHY, not just
the ones that are available as child PHY devices of the switch MDIO bus.
This allows us for instance to have external PHYs connected to a
separate MDIO bus, but yet also connected to a given switch port.
Under certain configurations, the physical port mask might not be a 1:1
mapping to the MII PHYs mask. This is the case, if e.g: Port 1 of the
switch is used and connects to a PHY at a MDIO address different than 1.
Introduce a phys_mii_mask variable which allows driver to implement and
divert their own MDIO read/writes operations for a subset of the MDIO
PHY addresses.
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
Changes in v2:
- introduce phys_mii_mask to allow switch drivers to divert MDIO operations
for some PHY addresses
- use the latest fixed PHY API
- iron out non-OF setups
include/net/dsa.h | 1 +
net/dsa/dsa.c | 5 ++++
net/dsa/dsa_priv.h | 4 +++
net/dsa/slave.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++---
4 files changed, 83 insertions(+), 3 deletions(-)
diff --git a/include/net/dsa.h b/include/net/dsa.h
index 66bb036831fd..89b44e8d2dc3 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -127,6 +127,7 @@ struct dsa_switch {
*/
u32 dsa_port_mask;
u32 phys_port_mask;
+ u32 phys_mii_mask;
struct mii_bus *slave_mii_bus;
struct net_device *ports[DSA_MAX_PORTS];
};
diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c
index 788b2b2f39f2..62f2f4e67d7d 100644
--- a/net/dsa/dsa.c
+++ b/net/dsa/dsa.c
@@ -144,6 +144,11 @@ dsa_switch_setup(struct dsa_switch_tree *dst, int index,
goto out;
}
+ /* Make the built-in MII bus mask match the number of ports,
+ * switch drivers can override this later
+ */
+ ds->phys_mii_mask = ds->phys_port_mask;
+
/*
* If the CPU connects to this switch, set the switch tree
* tagging protocol to the preferred tagging format of this
diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
index d4cf5cc747e3..a7f6f0c5fa31 100644
--- a/net/dsa/dsa_priv.h
+++ b/net/dsa/dsa_priv.h
@@ -33,6 +33,10 @@ struct dsa_slave_priv {
* to this port.
*/
struct phy_device *phy;
+ phy_interface_t phy_interface;
+ int old_link;
+ int old_pause;
+ int old_duplex;
};
/* dsa.c */
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 9e4d3816c54e..b4b6d457bfd0 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -12,6 +12,8 @@
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/phy.h>
+#include <linux/of_net.h>
+#include <linux/of_mdio.h>
#include "dsa_priv.h"
/* slave mii_bus handling ***************************************************/
@@ -19,7 +21,7 @@ static int dsa_slave_phy_read(struct mii_bus *bus, int addr, int reg)
{
struct dsa_switch *ds = bus->priv;
- if (ds->phys_port_mask & (1 << addr))
+ if (ds->phys_mii_mask & (1 << addr))
return ds->drv->phy_read(ds, addr, reg);
return 0xffff;
@@ -29,7 +31,7 @@ static int dsa_slave_phy_write(struct mii_bus *bus, int addr, int reg, u16 val)
{
struct dsa_switch *ds = bus->priv;
- if (ds->phys_port_mask & (1 << addr))
+ if (ds->phys_mii_mask & (1 << addr))
return ds->drv->phy_write(ds, addr, reg, val);
return 0;
@@ -330,7 +332,70 @@ static const struct net_device_ops trailer_netdev_ops = {
};
#endif
+static void dsa_slave_adjust_link(struct net_device *dev)
+{
+ struct dsa_slave_priv *p = netdev_priv(dev);
+ unsigned int status_changed = 0;
+
+ if (p->old_link != p->phy->link) {
+ status_changed = 1;
+ p->old_link = p->phy->link;
+ }
+
+ if (p->old_duplex != p->phy->duplex) {
+ status_changed = 1;
+ p->old_duplex = p->phy->duplex;
+ }
+
+ if (p->old_pause != p->phy->pause) {
+ status_changed = 1;
+ p->old_pause = p->phy->pause;
+ }
+
+ if (status_changed)
+ phy_print_status(p->phy);
+}
+
/* slave device setup *******************************************************/
+static void dsa_slave_phy_setup(struct dsa_slave_priv *p,
+ struct net_device *slave_dev)
+{
+ struct dsa_switch *ds = p->parent;
+ struct dsa_chip_data *cd = ds->pd;
+ struct device_node *phy_dn, *port_dn;
+ int ret;
+
+ port_dn = cd->port_dn[p->port];
+ p->phy_interface = of_get_phy_mode(port_dn);
+
+ phy_dn = of_parse_phandle(port_dn, "phy-handle", 0);
+ if (of_phy_is_fixed_link(port_dn)) {
+ /* In the case of a fixed PHY, the DT node associated
+ * to the fixed PHY is the Port DT node
+ */
+ ret = of_phy_register_fixed_link(port_dn);
+ if (ret) {
+ pr_err("failed to register fixed PHY\n");
+ return;
+ }
+ phy_dn = port_dn;
+ }
+
+ if (phy_dn)
+ p->phy = of_phy_connect(slave_dev, phy_dn,
+ dsa_slave_adjust_link, 0,
+ p->phy_interface);
+
+ /* We could not connect to a designated PHY, so use the switch internal
+ * MDIO bus instead
+ */
+ if (!p->phy)
+ p->phy = ds->slave_mii_bus->phy_map[p->port];
+ else
+ pr_info("attached PHY at address %d [%s]\n",
+ p->phy->addr, p->phy->drv->name);
+}
+
struct net_device *
dsa_slave_create(struct dsa_switch *ds, struct device *parent,
int port, char *name)
@@ -378,7 +443,12 @@ dsa_slave_create(struct dsa_switch *ds, struct device *parent,
p->dev = slave_dev;
p->parent = ds;
p->port = port;
- p->phy = ds->slave_mii_bus->phy_map[port];
+
+ p->old_pause = -1;
+ p->old_link = -1;
+ p->old_duplex = -1;
+
+ dsa_slave_phy_setup(p, slave_dev);
ret = register_netdev(slave_dev);
if (ret) {
--
1.9.1
^ permalink raw reply related
* [PATCH net-next v3 07/12] net: dsa: allow drivers to do link adjustment
From: Florian Fainelli @ 2014-08-24 18:44 UTC (permalink / raw)
To: netdev; +Cc: davem, jhs, linville, alexander.h.duyck, Florian Fainelli
In-Reply-To: <1408905869-10471-1-git-send-email-f.fainelli@gmail.com>
Whenever libphy determines that the link status of a given PHY/port has
changed, allow to call into the switch driver link adjustment callback
so proper actions can be taken care of by the switch driver upon link
notification.
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
include/net/dsa.h | 7 +++++++
net/dsa/slave.c | 4 ++++
2 files changed, 11 insertions(+)
diff --git a/include/net/dsa.h b/include/net/dsa.h
index 6620d4722efa..4507c50d29a6 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -16,6 +16,7 @@
#include <linux/timer.h>
#include <linux/workqueue.h>
#include <linux/of.h>
+#include <linux/phy.h>
#define DSA_MAX_SWITCHES 4
#define DSA_MAX_PORTS 12
@@ -179,6 +180,12 @@ struct dsa_switch_driver {
void (*poll_link)(struct dsa_switch *ds);
/*
+ * Link state adjustment (called from libphy)
+ */
+ void (*adjust_link)(struct dsa_switch *ds, int port,
+ struct phy_device *phydev);
+
+ /*
* ethtool hardware statistics.
*/
void (*get_strings)(struct dsa_switch *ds, int port, uint8_t *data);
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 35cd8b7a56b8..893afe9e60aa 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -357,6 +357,7 @@ static const struct net_device_ops notag_netdev_ops = {
static void dsa_slave_adjust_link(struct net_device *dev)
{
struct dsa_slave_priv *p = netdev_priv(dev);
+ struct dsa_switch *ds = p->parent;
unsigned int status_changed = 0;
if (p->old_link != p->phy->link) {
@@ -374,6 +375,9 @@ static void dsa_slave_adjust_link(struct net_device *dev)
p->old_pause = p->phy->pause;
}
+ if (ds->drv->adjust_link && status_changed)
+ ds->drv->adjust_link(ds, p->port, p->phy);
+
if (status_changed)
phy_print_status(p->phy);
}
--
1.9.1
^ permalink raw reply related
* [PATCH net-next v3 08/12] net: dsa: allow updating fixed PHY link information
From: Florian Fainelli @ 2014-08-24 18:44 UTC (permalink / raw)
To: netdev; +Cc: davem, jhs, linville, alexander.h.duyck, Florian Fainelli
In-Reply-To: <1408905869-10471-1-git-send-email-f.fainelli@gmail.com>
Allow switch drivers to hook a PHY link update callback to perform
port-specific link work.
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
include/net/dsa.h | 3 +++
net/dsa/slave.c | 17 +++++++++++++++++
2 files changed, 20 insertions(+)
diff --git a/include/net/dsa.h b/include/net/dsa.h
index 4507c50d29a6..9c0fd1b5e530 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -17,6 +17,7 @@
#include <linux/workqueue.h>
#include <linux/of.h>
#include <linux/phy.h>
+#include <linux/phy_fixed.h>
#define DSA_MAX_SWITCHES 4
#define DSA_MAX_PORTS 12
@@ -184,6 +185,8 @@ struct dsa_switch_driver {
*/
void (*adjust_link)(struct dsa_switch *ds, int port,
struct phy_device *phydev);
+ void (*fixed_link_update)(struct dsa_switch *ds, int port,
+ struct fixed_phy_status *st);
/*
* ethtool hardware statistics.
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 893afe9e60aa..ee019ec29dec 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -382,6 +382,18 @@ static void dsa_slave_adjust_link(struct net_device *dev)
phy_print_status(p->phy);
}
+static int dsa_slave_fixed_link_update(struct net_device *dev,
+ struct fixed_phy_status *status)
+{
+ struct dsa_slave_priv *p = netdev_priv(dev);
+ struct dsa_switch *ds = p->parent;
+
+ if (ds->drv->fixed_link_update)
+ ds->drv->fixed_link_update(ds, p->port, status);
+
+ return 0;
+}
+
/* slave device setup *******************************************************/
static void dsa_slave_phy_setup(struct dsa_slave_priv *p,
struct net_device *slave_dev)
@@ -389,6 +401,7 @@ static void dsa_slave_phy_setup(struct dsa_slave_priv *p,
struct dsa_switch *ds = p->parent;
struct dsa_chip_data *cd = ds->pd;
struct device_node *phy_dn, *port_dn;
+ unsigned int phy_is_fixed = 0;
int ret;
port_dn = cd->port_dn[p->port];
@@ -404,6 +417,7 @@ static void dsa_slave_phy_setup(struct dsa_slave_priv *p,
pr_err("failed to register fixed PHY\n");
return;
}
+ phy_is_fixed = 1;
phy_dn = port_dn;
}
@@ -412,6 +426,9 @@ static void dsa_slave_phy_setup(struct dsa_slave_priv *p,
dsa_slave_adjust_link, 0,
p->phy_interface);
+ if (p->phy && phy_is_fixed)
+ fixed_phy_set_link_update(p->phy, dsa_slave_fixed_link_update);
+
/* We could not connect to a designated PHY, so use the switch internal
* MDIO bus instead
*/
--
1.9.1
^ permalink raw reply related
* [PATCH net-next v3 06/12] net: dsa: allow switches to work without tagging
From: Florian Fainelli @ 2014-08-24 18:44 UTC (permalink / raw)
To: netdev; +Cc: davem, jhs, linville, alexander.h.duyck, Florian Fainelli
In-Reply-To: <1408905869-10471-1-git-send-email-f.fainelli@gmail.com>
In case switch port tagging is disabled (voluntarily, or the switch just
does not support it), allow us to continue using the master net_device
operations instead of the tag-specific ones.
dsa_protocol_is_tagged() is updated to check that the switch driver
tag_protocol field is not 0 to avoid overriding skb->protocol in the
eth_type_trans().
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
Changes in v3:
- update logic with the helpers introduced in the firs patch set
- renamed dummy to notag
include/net/dsa.h | 2 +-
net/dsa/slave.c | 25 ++++++++++++++++++++++++-
2 files changed, 25 insertions(+), 2 deletions(-)
diff --git a/include/net/dsa.h b/include/net/dsa.h
index 89b44e8d2dc3..6620d4722efa 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -206,7 +206,7 @@ static inline void *ds_to_priv(struct dsa_switch *ds)
*/
static inline bool dsa_protocol_is_tagged(struct dsa_switch_tree *dst)
{
- return dst->tag_protocol != ETH_P_EDSA;
+ return (dst->tag_protocol != 0) && (dst->tag_protocol != ETH_P_EDSA);
}
static inline __be16 dsa_tag_protocol(struct dsa_switch_tree *dst)
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index b4b6d457bfd0..35cd8b7a56b8 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -332,6 +332,28 @@ static const struct net_device_ops trailer_netdev_ops = {
};
#endif
+static netdev_tx_t dsa_slave_xmit(struct sk_buff *skb,
+ struct net_device *dev)
+{
+ struct dsa_slave_priv *p = netdev_priv(dev);
+
+ skb->dev = p->parent->dst->master_netdev;
+ dev_queue_xmit(skb);
+
+ return NETDEV_TX_OK;
+}
+
+static const struct net_device_ops notag_netdev_ops = {
+ .ndo_init = dsa_slave_init,
+ .ndo_open = dsa_slave_open,
+ .ndo_stop = dsa_slave_close,
+ .ndo_start_xmit = dsa_slave_xmit,
+ .ndo_change_rx_flags = dsa_slave_change_rx_flags,
+ .ndo_set_rx_mode = dsa_slave_set_rx_mode,
+ .ndo_set_mac_address = dsa_slave_set_mac_address,
+ .ndo_do_ioctl = dsa_slave_ioctl,
+};
+
static void dsa_slave_adjust_link(struct net_device *dev)
{
struct dsa_slave_priv *p = netdev_priv(dev);
@@ -432,7 +454,8 @@ dsa_slave_create(struct dsa_switch *ds, struct device *parent,
break;
#endif
default:
- BUG();
+ slave_dev->netdev_ops = ¬ag_netdev_ops;
+ break;
}
SET_NETDEV_DEV(slave_dev, parent);
--
1.9.1
^ permalink raw reply related
* [PATCH net-next v3 04/12] net: dsa: retain a per-port device_node pointer
From: Florian Fainelli @ 2014-08-24 18:44 UTC (permalink / raw)
To: netdev; +Cc: davem, jhs, linville, alexander.h.duyck, Florian Fainelli
In-Reply-To: <1408905869-10471-1-git-send-email-f.fainelli@gmail.com>
We will later use the per-port device_node pointer to fetch a bunch of
port-specific properties.
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
include/net/dsa.h | 1 +
net/dsa/dsa.c | 2 ++
net/dsa/slave.c | 1 +
3 files changed, 4 insertions(+)
diff --git a/include/net/dsa.h b/include/net/dsa.h
index 91d5ba435ab6..66bb036831fd 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -41,6 +41,7 @@ struct dsa_chip_data {
* or any other string to indicate this is a physical port.
*/
char *port_names[DSA_MAX_PORTS];
+ struct device_node *port_dn[DSA_MAX_PORTS];
/*
* An array (with nr_chips elements) of which element [a]
diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c
index 069586547cf5..788b2b2f39f2 100644
--- a/net/dsa/dsa.c
+++ b/net/dsa/dsa.c
@@ -432,6 +432,8 @@ static int dsa_of_probe(struct platform_device *pdev)
if (!port_name)
continue;
+ cd->port_dn[port_index] = port;
+
cd->port_names[port_index] = kstrdup(port_name,
GFP_KERNEL);
if (!cd->port_names[port_index]) {
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 45a1e34c89e0..9e4d3816c54e 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -371,6 +371,7 @@ dsa_slave_create(struct dsa_switch *ds, struct device *parent,
}
SET_NETDEV_DEV(slave_dev, parent);
+ slave_dev->dev.of_node = ds->pd->port_dn[port];
slave_dev->vlan_features = master->vlan_features;
p = netdev_priv(slave_dev);
--
1.9.1
^ permalink raw reply related
* [PATCH net-next v3 03/12] net: dsa: provide a switch device device tree node pointer
From: Florian Fainelli @ 2014-08-24 18:44 UTC (permalink / raw)
To: netdev; +Cc: davem, jhs, linville, alexander.h.duyck, Florian Fainelli
In-Reply-To: <1408905869-10471-1-git-send-email-f.fainelli@gmail.com>
We might need to fetch additional resources from the device tree node
pointer, such as register ranges or other properties. Keep a device_node
pointer around for this.
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
include/net/dsa.h | 7 +++++++
net/dsa/dsa.c | 1 +
2 files changed, 8 insertions(+)
diff --git a/include/net/dsa.h b/include/net/dsa.h
index 36a397bfbd2e..91d5ba435ab6 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -15,6 +15,7 @@
#include <linux/list.h>
#include <linux/timer.h>
#include <linux/workqueue.h>
+#include <linux/of.h>
#define DSA_MAX_SWITCHES 4
#define DSA_MAX_PORTS 12
@@ -26,6 +27,12 @@ struct dsa_chip_data {
struct device *mii_bus;
int sw_addr;
+ /* Device tree node pointer for this specific switch chip
+ * used during switch setup in case additional properties
+ * and resources needs to be used
+ */
+ struct device_node *of_node;
+
/*
* The names of the switch's ports. Use "cpu" to
* designate the switch port that the cpu is connected to,
diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c
index 0a49632fac47..069586547cf5 100644
--- a/net/dsa/dsa.c
+++ b/net/dsa/dsa.c
@@ -410,6 +410,7 @@ static int dsa_of_probe(struct platform_device *pdev)
chip_index++;
cd = &pd->chip[chip_index];
+ cd->of_node = child;
cd->mii_bus = &mdio_bus->dev;
sw_addr = of_get_property(child, "reg", NULL);
--
1.9.1
^ permalink raw reply related
* [PATCH net-next v3 02/12] net: phy: add generic UniMAC MDIO bus driver
From: Florian Fainelli @ 2014-08-24 18:44 UTC (permalink / raw)
To: netdev; +Cc: davem, jhs, linville, alexander.h.duyck, Florian Fainelli
In-Reply-To: <1408905869-10471-1-git-send-email-f.fainelli@gmail.com>
Add a generic UniMAC MDIO bus driver and its Device Tree binding, which
can be used by the BCMGENET driver as-is, and the upcoming Starfighter 2
Ethernet switch MDIO bus controller.
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
Changes in v3:
- renamed from mdio-unimac to mdio-bcm-unimac
Changes in v2:
- improved binding documentation with respect to the HW setups available
influencing interrupts
.../bindings/net/broadcom-mdio-unimac.txt | 39 ++++
drivers/net/phy/Kconfig | 6 +
drivers/net/phy/Makefile | 1 +
drivers/net/phy/mdio-bcm-unimac.c | 212 +++++++++++++++++++++
4 files changed, 258 insertions(+)
create mode 100644 Documentation/devicetree/bindings/net/broadcom-mdio-unimac.txt
create mode 100644 drivers/net/phy/mdio-bcm-unimac.c
diff --git a/Documentation/devicetree/bindings/net/broadcom-mdio-unimac.txt b/Documentation/devicetree/bindings/net/broadcom-mdio-unimac.txt
new file mode 100644
index 000000000000..ab0bb4247d14
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/broadcom-mdio-unimac.txt
@@ -0,0 +1,39 @@
+* Broadcom UniMAC MDIO bus controller
+
+Required properties:
+- compatible: should one from "brcm,genet-mdio-v1", "brcm,genet-mdio-v2",
+ "brcm,genet-mdio-v3", "brcm,genet-mdio-v4" or "brcm,unimac-mdio"
+- reg: address and length of the regsiter set for the device, first one is the
+ base register, and the second one is optional and for indirect accesses to
+ larger than 16-bits MDIO transactions
+- reg-names: name(s) of the register must be "mdio" and optional "mdio_indir_rw"
+- #size-cells: must be 1
+- #address-cells: must be 0
+
+Optional properties:
+- interrupts: must be one if the interrupt is shared with the Ethernet MAC or
+ Ethernet switch this MDIO block is integrated from, or must be two, if there
+ are two separate interrupts, first one must be "mdio done" and second must be
+ for "mdio error"
+- interrupt-names: must be "mdio_done_error" when there is a share interrupt fed
+ to this hardware block, or must be "mdio_done" for the first interrupt and
+ "mdio_error" for the second when there are separate interrupts
+
+Child nodes of this MDIO bus controller node are standard Ethernet PHY device
+nodes as described in Documentation/devicetree/bindings/net/phy.txt
+
+Example:
+
+mdio@403c0 {
+ compatible = "brcm,unimac-mdio";
+ reg = <0x403c0 0x8 0x40300 0x18>;
+ reg-names = "mdio", "mdio_indir_rw";
+ #size-cells = <1>;
+ #address-cells = <0>;
+
+ ...
+ phy@0 {
+ compatible = "ethernet-phy-ieee802.3-c22";
+ reg = <0>;
+ };
+};
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 65de0cab8d07..3e00f3adc91c 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -205,6 +205,12 @@ config MDIO_BUS_MUX_MMIOREG
Currently, only 8-bit registers are supported.
+config MDIO_BCM_UNIMAC
+ tristate "Broadcom UniMAC MDIO bus controller"
+ help
+ This module provides a driver for the Broadcom UniMAC MDIO busses.
+ It is required by the Broadcom GENET Ethernet device drivers.
+
endif # PHYLIB
config MICREL_KS8995MA
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index 7dc3d5b304cf..eb3b18b5978b 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -34,3 +34,4 @@ obj-$(CONFIG_MDIO_BUS_MUX_MMIOREG) += mdio-mux-mmioreg.o
obj-$(CONFIG_MDIO_SUN4I) += mdio-sun4i.o
obj-$(CONFIG_MDIO_MOXART) += mdio-moxart.o
obj-$(CONFIG_AMD_XGBE_PHY) += amd-xgbe-phy.o
+obj-$(CONFIG_MDIO_BCM_UNIMAC) += mdio-bcm-unimac.o
diff --git a/drivers/net/phy/mdio-bcm-unimac.c b/drivers/net/phy/mdio-bcm-unimac.c
new file mode 100644
index 000000000000..e6b08ceb9c37
--- /dev/null
+++ b/drivers/net/phy/mdio-bcm-unimac.c
@@ -0,0 +1,212 @@
+/*
+ * Broadcom UniMAC MDIO bus controller driver
+ *
+ * Copyright (C) 2014, Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/of_mdio.h>
+
+#define MDIO_CMD 0x00
+#define MDIO_START_BUSY (1 << 29)
+#define MDIO_READ_FAIL (1 << 28)
+#define MDIO_RD (2 << 26)
+#define MDIO_WR (1 << 26)
+#define MDIO_PMD_SHIFT 21
+#define MDIO_PMD_MASK 0x1F
+#define MDIO_REG_SHIFT 16
+#define MDIO_REG_MASK 0x1F
+
+#define MDIO_CFG 0x04
+#define MDIO_C22 (1 << 0)
+#define MDIO_C45 0
+#define MDIO_CLK_DIV_SHIFT 4
+#define MDIO_CLK_DIV_MASK 0x3F
+#define MDIO_SUPP_PREAMBLE (1 << 12)
+
+struct unimac_mdio_priv {
+ struct mii_bus *mii_bus;
+ void __iomem *base;
+};
+
+static inline void unimac_mdio_start(struct unimac_mdio_priv *priv)
+{
+ u32 reg;
+
+ reg = __raw_readl(priv->base + MDIO_CMD);
+ reg |= MDIO_START_BUSY;
+ __raw_writel(reg, priv->base + MDIO_CMD);
+}
+
+static inline unsigned int unimac_mdio_busy(struct unimac_mdio_priv *priv)
+{
+ return __raw_readl(priv->base + MDIO_CMD) & MDIO_START_BUSY;
+}
+
+static int unimac_mdio_read(struct mii_bus *bus, int phy_id, int reg)
+{
+ struct unimac_mdio_priv *priv = bus->priv;
+ unsigned int timeout = 1000;
+ u32 cmd;
+
+ /* Prepare the read operation */
+ cmd = MDIO_RD | (phy_id << MDIO_PMD_SHIFT) | (reg << MDIO_REG_SHIFT);
+ __raw_writel(cmd, priv->base + MDIO_CMD);
+
+ /* Start MDIO transaction */
+ unimac_mdio_start(priv);
+
+ do {
+ if (!unimac_mdio_busy(priv))
+ break;
+
+ usleep_range(1000, 2000);
+ } while (timeout--);
+
+ if (!timeout)
+ return -ETIMEDOUT;
+
+ cmd = __raw_readl(priv->base + MDIO_CMD);
+ if (cmd & MDIO_READ_FAIL)
+ return -EIO;
+
+ return cmd & 0xffff;
+}
+
+static int unimac_mdio_write(struct mii_bus *bus, int phy_id,
+ int reg, u16 val)
+{
+ struct unimac_mdio_priv *priv = bus->priv;
+ unsigned int timeout = 1000;
+ u32 cmd;
+
+ /* Prepare the write operation */
+ cmd = MDIO_WR | (phy_id << MDIO_PMD_SHIFT) |
+ (reg << MDIO_REG_SHIFT) | (0xffff & val);
+ __raw_writel(cmd, priv->base + MDIO_CMD);
+
+ unimac_mdio_start(priv);
+
+ do {
+ if (!unimac_mdio_busy(priv))
+ break;
+
+ usleep_range(1000, 2000);
+ } while (timeout--);
+
+ if (!timeout)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static int unimac_mdio_probe(struct platform_device *pdev)
+{
+ struct unimac_mdio_priv *priv;
+ struct device_node *np;
+ struct mii_bus *bus;
+ struct resource *r;
+ int ret;
+
+ np = pdev->dev.of_node;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ /* Just ioremap, as this MDIO block is usually integrated into an
+ * Ethernet MAC controller register range
+ */
+ priv->base = devm_ioremap(&pdev->dev, r->start, resource_size(r));
+ if (!priv->base) {
+ dev_err(&pdev->dev, "failed to remap register\n");
+ return -ENOMEM;
+ }
+
+ priv->mii_bus = mdiobus_alloc();
+ if (!priv->mii_bus)
+ return -ENOMEM;
+
+ bus = priv->mii_bus;
+ bus->priv = priv;
+ bus->name = "unimac MII bus";
+ bus->parent = &pdev->dev;
+ bus->read = unimac_mdio_read;
+ bus->write = unimac_mdio_write;
+ snprintf(bus->id, MII_BUS_ID_SIZE, "%s", pdev->name);
+
+ bus->irq = kcalloc(PHY_MAX_ADDR, sizeof(int), GFP_KERNEL);
+ if (!bus->irq) {
+ ret = -ENOMEM;
+ goto out_mdio_free;
+ }
+
+ ret = of_mdiobus_register(bus, np);
+ if (ret) {
+ dev_err(&pdev->dev, "MDIO bus registration failed\n");
+ goto out_mdio_irq;
+ }
+
+ platform_set_drvdata(pdev, priv);
+
+ dev_info(&pdev->dev, "Broadcom UniMAC MDIO bus at 0x%p\n", priv->base);
+
+ return 0;
+
+out_mdio_irq:
+ kfree(bus->irq);
+out_mdio_free:
+ mdiobus_free(bus);
+ return ret;
+}
+
+static int unimac_mdio_remove(struct platform_device *pdev)
+{
+ struct unimac_mdio_priv *priv = platform_get_drvdata(pdev);
+
+ mdiobus_unregister(priv->mii_bus);
+ kfree(priv->mii_bus->irq);
+ mdiobus_free(priv->mii_bus);
+
+ return 0;
+}
+
+static struct of_device_id unimac_mdio_ids[] = {
+ { .compatible = "brcm,genet-mdio-v4", },
+ { .compatible = "brcm,genet-mdio-v3", },
+ { .compatible = "brcm,genet-mdio-v2", },
+ { .compatible = "brcm,genet-mdio-v1", },
+ { .compatible = "brcm,unimac-mdio", },
+};
+
+static struct platform_driver unimac_mdio_driver = {
+ .driver = {
+ .name = "unimac-mdio",
+ .owner = THIS_MODULE,
+ .of_match_table = unimac_mdio_ids,
+ },
+ .probe = unimac_mdio_probe,
+ .remove = unimac_mdio_remove,
+};
+module_platform_driver(unimac_mdio_driver);
+
+MODULE_AUTHOR("Broadcom Corporation");
+MODULE_DESCRIPTION("Broadcom UniMAC MDIO bus controller");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:unimac-mdio");
--
1.9.1
^ permalink raw reply related
* [PATCH net-next v3 00/12] dsa: support for Broadcom Starfighter 2
From: Florian Fainelli @ 2014-08-24 18:44 UTC (permalink / raw)
To: netdev; +Cc: davem, jhs, linville, alexander.h.duyck, Florian Fainelli
Hi all,
This patch series adds support for the Broadcom Starfighter 2 (Roboswitch
successor) using the existing DSA infrastructure. This integrated switch
is heavily used in Set Top Box, Cable gateways and DSL gateways products
from Broadcom, and to a larger extent the new ARM-based Wi-Fi routers although
slightly differently.
Notable changes in v3 is the preliminary patch that reworks the skb->protocol
override helpers for non-Ethertype switch tags, based on feedback from
Alexander Duyck.
The biggest changes from v1 of this patch series are:
- use the new fixed PHY helpers
- improved the switch driver with more complete features (interrupts,
(RG)MII configuration, memory arrays power down/up, port disabling/enable
VLAN separation
Future work will focus on bringing the upstream driver in feature parity with
the current downstream driver, including:
- adding Wake-on-LAN support to the switch
- adding suspend/resume callbacks for S2/S3 Power Management modes
- extending the switch register interface to cover BCM5310X SoCs
Florian Fainelli (12):
net: dsa: rework skb->protocol override helpers
net: phy: add generic UniMAC MDIO bus driver
net: dsa: provide a switch device device tree node pointer
net: dsa: retain a per-port device_node pointer
net: dsa: allow for more complex PHY setups
net: dsa: allow switches to work without tagging
net: dsa: allow drivers to do link adjustment
net: dsa: allow updating fixed PHY link information
net: dsa: add Broadcom tag RX/TX handler
net: dsa: add Broadcom SF2 switch driver
Documentation: devicetree: update dsa binding with optional properties
Documentation: devicetree: add Broadcom Starfighter 2 binding
.../bindings/net/broadcom-mdio-unimac.txt | 39 ++
.../devicetree/bindings/net/broadcom-sf2.txt | 78 +++
Documentation/devicetree/bindings/net/dsa/dsa.txt | 17 +
drivers/net/dsa/Kconfig | 11 +
drivers/net/dsa/Makefile | 1 +
drivers/net/dsa/bcm_sf2.c | 626 +++++++++++++++++++++
drivers/net/dsa/bcm_sf2.h | 139 +++++
drivers/net/dsa/bcm_sf2_regs.h | 228 ++++++++
drivers/net/phy/Kconfig | 6 +
drivers/net/phy/Makefile | 1 +
drivers/net/phy/mdio-bcm-unimac.c | 212 +++++++
include/linux/netdevice.h | 16 +-
include/net/dsa.h | 30 +-
include/uapi/linux/if_ether.h | 1 +
net/dsa/Kconfig | 3 +
net/dsa/Makefile | 1 +
net/dsa/dsa.c | 15 +
net/dsa/dsa_priv.h | 8 +
net/dsa/slave.c | 140 ++++-
net/dsa/tag_brcm.c | 173 ++++++
net/ethernet/eth.c | 7 +-
21 files changed, 1729 insertions(+), 23 deletions(-)
create mode 100644 Documentation/devicetree/bindings/net/broadcom-mdio-unimac.txt
create mode 100644 Documentation/devicetree/bindings/net/broadcom-sf2.txt
create mode 100644 drivers/net/dsa/bcm_sf2.c
create mode 100644 drivers/net/dsa/bcm_sf2.h
create mode 100644 drivers/net/dsa/bcm_sf2_regs.h
create mode 100644 drivers/net/phy/mdio-bcm-unimac.c
create mode 100644 net/dsa/tag_brcm.c
--
1.9.1
^ permalink raw reply
* [PATCH net-next v3 01/12] net: dsa: rework skb->protocol override helpers
From: Florian Fainelli @ 2014-08-24 18:44 UTC (permalink / raw)
To: netdev; +Cc: davem, jhs, linville, alexander.h.duyck, Florian Fainelli
In-Reply-To: <1408905869-10471-1-git-send-email-f.fainelli@gmail.com>
DSA currently maintains one helper function per tagging protocol that
does not insert a real ethertype in the Ethernet frame:
netdev_uses_dsa_tags() and netdev_uses_trailer_tags().
This patch reworks the logic to introduce two helper functions that
makes the DSA tagging protocol checking more scalable to the addition of
new tagging protocols.
The first helper function returns whether a DSA-enabled device is using
a non-ethertype protocol, while the second helper does return the actual
protocol value we should override skb->protocol with.
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
New patch in v3
include/linux/netdevice.h | 16 +++++++---------
include/net/dsa.h | 11 ++++++-----
net/ethernet/eth.c | 7 ++-----
3 files changed, 15 insertions(+), 19 deletions(-)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 7e2b0b8b5cd7..c0a033b0037c 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1781,23 +1781,21 @@ void dev_net_set(struct net_device *dev, struct net *net)
#endif
}
-static inline bool netdev_uses_dsa_tags(struct net_device *dev)
+static inline bool netdev_uses_dsa_tagging(struct net_device *dev)
{
-#ifdef CONFIG_NET_DSA_TAG_DSA
+#ifdef CONFIG_NET_DSA
if (dev->dsa_ptr != NULL)
- return dsa_uses_dsa_tags(dev->dsa_ptr);
+ return dsa_protocol_is_tagged(dev->dsa_ptr);
#endif
-
- return 0;
+ return false;
}
-static inline bool netdev_uses_trailer_tags(struct net_device *dev)
+static inline __be16 netdev_dsa_tag_protocol(struct net_device *dev)
{
-#ifdef CONFIG_NET_DSA_TAG_TRAILER
+#ifdef CONFIG_NET_DSA
if (dev->dsa_ptr != NULL)
- return dsa_uses_trailer_tags(dev->dsa_ptr);
+ return dsa_tag_protocol(dev->dsa_ptr);
#endif
-
return 0;
}
diff --git a/include/net/dsa.h b/include/net/dsa.h
index 6efce384451e..36a397bfbd2e 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -192,15 +192,16 @@ static inline void *ds_to_priv(struct dsa_switch *ds)
* networking receive path to make sure that received frames get
* the right ->protocol assigned to them when one of those tag
* formats is in use.
+ *
+ * ETH_P_EDSA is the only real ethertype currently supported
*/
-static inline bool dsa_uses_dsa_tags(struct dsa_switch_tree *dst)
+static inline bool dsa_protocol_is_tagged(struct dsa_switch_tree *dst)
{
- return !!(dst->tag_protocol == htons(ETH_P_DSA));
+ return dst->tag_protocol != ETH_P_EDSA;
}
-static inline bool dsa_uses_trailer_tags(struct dsa_switch_tree *dst)
+static inline __be16 dsa_tag_protocol(struct dsa_switch_tree *dst)
{
- return !!(dst->tag_protocol == htons(ETH_P_TRAILER));
+ return dst->tag_protocol;
}
-
#endif
diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c
index f405e0592407..4ca8e489bc3d 100644
--- a/net/ethernet/eth.c
+++ b/net/ethernet/eth.c
@@ -181,11 +181,8 @@ __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev)
* variants has been configured on the receiving interface,
* and if so, set skb->protocol without looking at the packet.
*/
- if (unlikely(netdev_uses_dsa_tags(dev)))
- return htons(ETH_P_DSA);
-
- if (unlikely(netdev_uses_trailer_tags(dev)))
- return htons(ETH_P_TRAILER);
+ if (unlikely(netdev_uses_dsa_tagging(dev)))
+ return netdev_dsa_tag_protocol(dev);
if (likely(ntohs(eth->h_proto) >= ETH_P_802_3_MIN))
return eth->h_proto;
--
1.9.1
^ permalink raw reply related
* [PATCH v2] net: ec_bhf: remove excessive debug messages
From: Dariusz Marcinkiewicz @ 2014-08-24 18:40 UTC (permalink / raw)
To: davem, netdev, linux-kernel
This cuts down the number of debug information spit out by
the driver.
Signed-off-by: Dariusz Marcinkiewicz <reksio@newterm.pl>
---
Changes since v1:
* as suggested by Dave Miller, I am simply ditching all
debugfs stuff
drivers/net/ethernet/ec_bhf.c | 101 ++++-------------------------------------
1 file changed, 10 insertions(+), 91 deletions(-)
diff --git a/drivers/net/ethernet/ec_bhf.c b/drivers/net/ethernet/ec_bhf.c
index 056b44b..d101750 100644
--- a/drivers/net/ethernet/ec_bhf.c
+++ b/drivers/net/ethernet/ec_bhf.c
@@ -1,5 +1,5 @@
/*
- * drivers/net/ethernet/beckhoff/ec_bhf.c
+ * drivers/net/ethernet/ec_bhf.c
*
* Copyright (C) 2014 Darek Marcinkiewicz <reksio@newterm.pl>
*
@@ -18,9 +18,6 @@
* Those can be found on Bechhoff CX50xx industrial PCs.
*/
-#if 0
-#define DEBUG
-#endif
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
@@ -74,6 +71,8 @@
#define DMA_WINDOW_SIZE_MASK 0xfffffffc
+#define ETHERCAT_MASTER_ID 0x14
+
static struct pci_device_id ids[] = {
{ PCI_DEVICE(0x15ec, 0x5000), },
{ 0, }
@@ -131,7 +130,6 @@ struct bhf_dma {
struct ec_bhf_priv {
struct net_device *net_dev;
-
struct pci_dev *dev;
void __iomem *io;
@@ -162,32 +160,6 @@ struct ec_bhf_priv {
#define PRIV_TO_DEV(priv) (&(priv)->dev->dev)
-#define ETHERCAT_MASTER_ID 0x14
-
-static void ec_bhf_print_status(struct ec_bhf_priv *priv)
-{
- struct device *dev = PRIV_TO_DEV(priv);
-
- dev_dbg(dev, "Frame error counter: %d\n",
- ioread8(priv->mac_io + MAC_FRAME_ERR_CNT));
- dev_dbg(dev, "RX error counter: %d\n",
- ioread8(priv->mac_io + MAC_RX_ERR_CNT));
- dev_dbg(dev, "CRC error counter: %d\n",
- ioread8(priv->mac_io + MAC_CRC_ERR_CNT));
- dev_dbg(dev, "TX frame counter: %d\n",
- ioread32(priv->mac_io + MAC_TX_FRAME_CNT));
- dev_dbg(dev, "RX frame counter: %d\n",
- ioread32(priv->mac_io + MAC_RX_FRAME_CNT));
- dev_dbg(dev, "TX fifo level: %d\n",
- ioread8(priv->mac_io + MAC_TX_FIFO_LVL));
- dev_dbg(dev, "Dropped frames: %d\n",
- ioread8(priv->mac_io + MAC_DROPPED_FRMS));
- dev_dbg(dev, "Connected with CCAT slot: %d\n",
- ioread8(priv->mac_io + MAC_CONNECTED_CCAT_FLAG));
- dev_dbg(dev, "Link status: %d\n",
- ioread8(priv->mii_io + MII_LINK_STATUS));
-}
-
static void ec_bhf_reset(struct ec_bhf_priv *priv)
{
iowrite8(0, priv->mac_io + MAC_FRAME_ERR_CNT);
@@ -210,8 +182,6 @@ static void ec_bhf_send_packet(struct ec_bhf_priv *priv, struct tx_desc *desc)
u32 addr = (u8 *)desc - priv->tx_buf.buf;
iowrite32((ALIGN(len, 8) << 24) | addr, priv->fifo_io + FIFO_TX_REG);
-
- dev_dbg(PRIV_TO_DEV(priv), "Done sending packet\n");
}
static int ec_bhf_desc_sent(struct tx_desc *desc)
@@ -244,7 +214,6 @@ static void ec_bhf_add_rx_desc(struct ec_bhf_priv *priv, struct rx_desc *desc)
static void ec_bhf_process_rx(struct ec_bhf_priv *priv)
{
struct rx_desc *desc = &priv->rx_descs[priv->rx_dnext];
- struct device *dev = PRIV_TO_DEV(priv);
while (ec_bhf_pkt_received(desc)) {
int pkt_size = (le16_to_cpu(desc->header.len) &
@@ -253,20 +222,16 @@ static void ec_bhf_process_rx(struct ec_bhf_priv *priv)
struct sk_buff *skb;
skb = netdev_alloc_skb_ip_align(priv->net_dev, pkt_size);
- dev_dbg(dev, "Received packet, size: %d\n", pkt_size);
-
if (skb) {
memcpy(skb_put(skb, pkt_size), data, pkt_size);
skb->protocol = eth_type_trans(skb, priv->net_dev);
- dev_dbg(dev, "Protocol type: %x\n", skb->protocol);
-
priv->stat_rx_bytes += pkt_size;
netif_rx(skb);
} else {
- dev_err_ratelimited(dev,
- "Couldn't allocate a skb_buff for a packet of size %u\n",
- pkt_size);
+ dev_err_ratelimited(PRIV_TO_DEV(priv),
+ "Couldn't allocate a skb_buff for a packet of size %u\n",
+ pkt_size);
}
desc->header.recv = 0;
@@ -276,7 +241,6 @@ static void ec_bhf_process_rx(struct ec_bhf_priv *priv)
priv->rx_dnext = (priv->rx_dnext + 1) % priv->rx_dcount;
desc = &priv->rx_descs[priv->rx_dnext];
}
-
}
static enum hrtimer_restart ec_bhf_timer_fun(struct hrtimer *timer)
@@ -299,14 +263,7 @@ static int ec_bhf_setup_offsets(struct ec_bhf_priv *priv)
unsigned block_count, i;
void __iomem *ec_info;
- dev_dbg(dev, "Info block:\n");
- dev_dbg(dev, "Type of function: %x\n", (unsigned)ioread16(priv->io));
- dev_dbg(dev, "Revision of function: %x\n",
- (unsigned)ioread16(priv->io + INFO_BLOCK_REV));
-
block_count = ioread8(priv->io + INFO_BLOCK_BLK_CNT);
- dev_dbg(dev, "Number of function blocks: %x\n", block_count);
-
for (i = 0; i < block_count; i++) {
u16 type = ioread16(priv->io + i * INFO_BLOCK_SIZE +
INFO_BLOCK_TYPE);
@@ -317,29 +274,17 @@ static int ec_bhf_setup_offsets(struct ec_bhf_priv *priv)
dev_err(dev, "EtherCAT master with DMA block not found\n");
return -ENODEV;
}
- dev_dbg(dev, "EtherCAT master with DMA block found at pos: %d\n", i);
ec_info = priv->io + i * INFO_BLOCK_SIZE;
- dev_dbg(dev, "EtherCAT master revision: %d\n",
- ioread16(ec_info + INFO_BLOCK_REV));
priv->tx_dma_chan = ioread8(ec_info + INFO_BLOCK_TX_CHAN);
- dev_dbg(dev, "EtherCAT master tx dma channel: %d\n",
- priv->tx_dma_chan);
-
priv->rx_dma_chan = ioread8(ec_info + INFO_BLOCK_RX_CHAN);
- dev_dbg(dev, "EtherCAT master rx dma channel: %d\n",
- priv->rx_dma_chan);
priv->ec_io = priv->io + ioread32(ec_info + INFO_BLOCK_OFFSET);
priv->mii_io = priv->ec_io + ioread32(priv->ec_io + EC_MII_OFFSET);
priv->fifo_io = priv->ec_io + ioread32(priv->ec_io + EC_FIFO_OFFSET);
priv->mac_io = priv->ec_io + ioread32(priv->ec_io + EC_MAC_OFFSET);
- dev_dbg(dev,
- "EtherCAT block addres: %p, fifo address: %p, mii address: %p, mac address: %p\n",
- priv->ec_io, priv->fifo_io, priv->mii_io, priv->mac_io);
-
return 0;
}
@@ -350,8 +295,6 @@ static netdev_tx_t ec_bhf_start_xmit(struct sk_buff *skb,
struct tx_desc *desc;
unsigned len;
- dev_dbg(PRIV_TO_DEV(priv), "Starting xmit\n");
-
desc = &priv->tx_descs[priv->tx_dnext];
skb_copy_and_csum_dev(skb, desc->data);
@@ -366,15 +309,12 @@ static netdev_tx_t ec_bhf_start_xmit(struct sk_buff *skb,
priv->tx_dnext = (priv->tx_dnext + 1) % priv->tx_dcount;
if (!ec_bhf_desc_sent(&priv->tx_descs[priv->tx_dnext])) {
- /* Make sure that update updates to tx_dnext are perceived
+ /* Make sure that updates to tx_dnext are perceived
* by timer routine.
*/
smp_wmb();
netif_stop_queue(net_dev);
-
- dev_dbg(PRIV_TO_DEV(priv), "Stopping netif queue\n");
- ec_bhf_print_status(priv);
}
priv->stat_tx_bytes += len;
@@ -397,7 +337,6 @@ static int ec_bhf_alloc_dma_mem(struct ec_bhf_priv *priv,
mask = ioread32(priv->dma_io + offset);
mask &= DMA_WINDOW_SIZE_MASK;
- dev_dbg(dev, "Read mask %x for channel %d\n", mask, channel);
/* We want to allocate a chunk of memory that is:
* - aligned to the mask we just read
@@ -408,12 +347,10 @@ static int ec_bhf_alloc_dma_mem(struct ec_bhf_priv *priv,
buf->len = min_t(int, ~mask + 1, size);
buf->alloc_len = 2 * buf->len;
- dev_dbg(dev, "Allocating %d bytes for channel %d",
- (int)buf->alloc_len, channel);
buf->alloc = dma_alloc_coherent(dev, buf->alloc_len, &buf->alloc_phys,
GFP_KERNEL);
if (buf->alloc == NULL) {
- dev_info(dev, "Failed to allocate buffer\n");
+ dev_err(dev, "Failed to allocate buffer\n");
return -ENOMEM;
}
@@ -422,8 +359,6 @@ static int ec_bhf_alloc_dma_mem(struct ec_bhf_priv *priv,
iowrite32(0, priv->dma_io + offset + 4);
iowrite32(buf->buf_phys, priv->dma_io + offset);
- dev_dbg(dev, "Buffer: %x and read from dev: %x",
- (unsigned)buf->buf_phys, ioread32(priv->dma_io + offset));
return 0;
}
@@ -433,7 +368,7 @@ static void ec_bhf_setup_tx_descs(struct ec_bhf_priv *priv)
int i = 0;
priv->tx_dcount = priv->tx_buf.len / sizeof(struct tx_desc);
- priv->tx_descs = (struct tx_desc *) priv->tx_buf.buf;
+ priv->tx_descs = (struct tx_desc *)priv->tx_buf.buf;
priv->tx_dnext = 0;
for (i = 0; i < priv->tx_dcount; i++)
@@ -445,7 +380,7 @@ static void ec_bhf_setup_rx_descs(struct ec_bhf_priv *priv)
int i;
priv->rx_dcount = priv->rx_buf.len / sizeof(struct rx_desc);
- priv->rx_descs = (struct rx_desc *) priv->rx_buf.buf;
+ priv->rx_descs = (struct rx_desc *)priv->rx_buf.buf;
priv->rx_dnext = 0;
for (i = 0; i < priv->rx_dcount; i++) {
@@ -469,8 +404,6 @@ static int ec_bhf_open(struct net_device *net_dev)
struct device *dev = PRIV_TO_DEV(priv);
int err = 0;
- dev_info(dev, "Opening device\n");
-
ec_bhf_reset(priv);
err = ec_bhf_alloc_dma_mem(priv, &priv->rx_buf, priv->rx_dma_chan,
@@ -481,20 +414,13 @@ static int ec_bhf_open(struct net_device *net_dev)
}
ec_bhf_setup_rx_descs(priv);
- dev_info(dev, "RX buffer allocated, address: %x\n",
- (unsigned)priv->rx_buf.buf_phys);
-
err = ec_bhf_alloc_dma_mem(priv, &priv->tx_buf, priv->tx_dma_chan,
FIFO_SIZE * sizeof(struct tx_desc));
if (err) {
dev_err(dev, "Failed to allocate tx buffer\n");
goto error_rx_free;
}
- dev_dbg(dev, "TX buffer allocated, addres: %x\n",
- (unsigned)priv->tx_buf.buf_phys);
-
iowrite8(0, priv->mii_io + MII_MAC_FILT_FLAG);
-
ec_bhf_setup_tx_descs(priv);
netif_start_queue(net_dev);
@@ -504,10 +430,6 @@ static int ec_bhf_open(struct net_device *net_dev)
hrtimer_start(&priv->hrtimer, ktime_set(0, polling_frequency),
HRTIMER_MODE_REL);
- dev_info(PRIV_TO_DEV(priv), "Device open\n");
-
- ec_bhf_print_status(priv);
-
return 0;
error_rx_free:
@@ -640,9 +562,6 @@ static int ec_bhf_probe(struct pci_dev *dev, const struct pci_device_id *id)
memcpy_fromio(net_dev->dev_addr, priv->mii_io + MII_MAC_ADDR, 6);
- dev_dbg(&dev->dev, "CX5020 Ethercat master address: %pM\n",
- net_dev->dev_addr);
-
err = register_netdev(net_dev);
if (err < 0)
goto err_free_net_dev;
--
1.7.10.4
^ permalink raw reply related
* Re: [PATCH 0/3] Basic deferred TX queue flushing infrastructure.
From: Eric Dumazet @ 2014-08-24 17:37 UTC (permalink / raw)
To: David Miller
Cc: netdev, therbert, jhs, hannes, edumazet, jeffrey.t.kirsher, rusty
In-Reply-To: <20140823.213839.1953243016141233125.davem@davemloft.net>
On Sat, 2014-08-23 at 21:38 -0700, David Miller wrote:
> Like Tom Herbert has mentioned we have all the infrastructure (sort
> of) already to handle a list of SKBs going down into
> dev_hard_start_xmit() via the GSO handling.
>
> But that code is funny, because it keeps the original GSO head SKB
> around as a placeholder to maintain the list of segmented SKBs.
This is because dev_hard_start_xmit() do not return an skb, but a rc
code.
int ret = dev_hard_start_xmit(skb, dev, txq);
That can be changed so that we do not have to keep the original skb as
the GSO head :
sch_direct_xmit() would 'requeue' the new skb (might be in the middle of
the skb segmented chain), not the original one.
This would get rid of DEV_GSO_CB() presumably.
^ permalink raw reply
* [PATCH] staging: r8188eu: Add new USB ID
From: Larry Finger @ 2014-08-24 16:30 UTC (permalink / raw)
To: gregkh; +Cc: netdev, devel, Larry Finger
The Elecom WDC-150SU2M uses this chip.
Reported-by: Hiroki Kondo <kompiro@gmail.com>
Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
---
drivers/staging/rtl8188eu/os_dep/usb_intf.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/staging/rtl8188eu/os_dep/usb_intf.c b/drivers/staging/rtl8188eu/os_dep/usb_intf.c
index 264e639..407a318 100644
--- a/drivers/staging/rtl8188eu/os_dep/usb_intf.c
+++ b/drivers/staging/rtl8188eu/os_dep/usb_intf.c
@@ -43,6 +43,7 @@ static struct usb_device_id rtw_usb_id_tbl[] = {
{USB_DEVICE(USB_VENDER_ID_REALTEK, 0x0179)}, /* 8188ETV */
/*=== Customer ID ===*/
/****** 8188EUS ********/
+ {USB_DEVICE(0x056e, 0x4008)}, /* Elecom WDC-150SU2M */
{USB_DEVICE(0x07b8, 0x8179)}, /* Abocom - Abocom */
{USB_DEVICE(0x2001, 0x330F)}, /* DLink DWA-125 REV D1 */
{USB_DEVICE(0x2001, 0x3310)}, /* Dlink DWA-123 REV D1 */
--
1.8.4.5
^ permalink raw reply related
* Re: [patch net-next RFC 10/12] openvswitch: add support for datapath hardware offload
From: Jamal Hadi Salim @ 2014-08-24 15:15 UTC (permalink / raw)
To: Thomas Graf
Cc: ryazanov.s.a-Re5JQEeQqe8AvxtiuMwx3w, ronye-VPRAkNaXOzVWk0Htik3J/w,
jasowang-H+wXaHxf7aLQT0dZR+AlfA,
john.r.fastabend-ral2JQCrhuEAvxtiuMwx3w,
Neil.Jerram-QnUH15yq9NYqDJ6do+/SaQ,
edumazet-hpIqsD4AKlfQT0dZR+AlfA, andy-QlMahl40kYEqcZcGjlUOXw,
dev-yBygre7rU0TnMu66kgdUjQ, nbd-p3rKhJxN3npAfugRpC6u6w,
f.fainelli-Re5JQEeQqe8AvxtiuMwx3w, John Fastabend,
jeffrey.t.kirsher-ral2JQCrhuEAvxtiuMwx3w,
ogerlitz-VPRAkNaXOzVWk0Htik3J/w, ben-/+tVBieCtBitmTQ+vhA3Yw,
buytenh-OLH4Qvv75CYX/NnBR394Jw, Jiri Pirko,
roopa-qUQiAmfTcIp+XZJcv9eMoEEOCMrvLtNR,
aviadr-VPRAkNaXOzVWk0Htik3J/w,
nicolas.dichtel-pdR9zngts4EAvxtiuMwx3w,
vyasevic-H+wXaHxf7aLQT0dZR+AlfA, nhorman-2XuSBdqkA4R54TAoqtyWWQ,
netdev-u79uwXL29TY76Z2rM5mHXA,
stephen-OTpzqLSitTUnbdJkjeBofR2eb7JE58TQ,
dborkman-H+wXaHxf7aLQT0dZR+AlfA, ebiederm-aS9lmoZGLiVWk0Htik3J/w,
davem-fT/PcQaiUtIeIZ0/mPfg9Q
In-Reply-To: <20140824111218.GA32741-FZi0V3Vbi30CUdFEqe4BF2D2FQJk+8+b@public.gmane.org>
On 08/24/14 07:12, Thomas Graf wrote:
> On 08/23/14 at 09:53pm, Jamal Hadi Salim wrote:
>
> I get what you are saying but I don't see that to be the case here. I
> don't see how this series proposes the OVS case as *the* interface.
The focus of the patches is on offloading flows (uses the
ovs or shall i say the broadcom OF-DPA API, which is one
vendor's view of the world).
Yes, people are going to deploy more hardware which knows how to do
a lot of flows (but today that is in the tiny tiny minority)
I would have liked to see more focus on L2/3 as a first step because
they are more predominantly deployed than anything with flows. And
they are well understood from a functional perspective.
Then that would bring to the front API issues since you have
a large sample space of deployments and we can refactor as needed.
i.e
The hard part is dealing with 10 different chips which have a slightly
different meaning of (example) how to do L3 in their implementation.
I dont see such a focus in these patches because they start with a
premise "the world is about flows".
> It proposes *a* interface which in this case is flow based with mask
> support to accomodate the typical ntuple filter API in HW. OVS happens
> to be one of the easiest to use examples as a consumer because it
> already provides a flat flow representation.
>
In other words, there is a direct 1-1 map between this approach and OVS.
That is a contentious point.
> I thought this is exactly what is happening here. The flow key/mask
> based API as proposed focuses on basic forwarding for L2-L4.
>
Not at all.
I gave an example earlier with u32, but lets pick the other extreme
of well understood functions, say L3 (I could pick L2 as well).
This openflow api tries to describe different header
fields in the packet. That is not the challenge for such an
API. The challenge is dealing with the quarks.
Some chips implement FIB and NH conjoined; others implement
them separately.
I dont see how this is even being remotely touched on.
>
> Exactly and I never saw Jiri claim that swdev_flow_insert() would be
> the only offload capability exposed by the API. I see no reason why
> it could not also provide swdev_offset_match_insert() or
> swdev_ebpf_insert() for the 2*next generation HW. I don't think it
> makes sense to focus entirely on finding a single common denominator
> and channel everything through a single function to represent all the
> different generic and less generic offload capabilities. I believe
> that doing so will raise the minimal HW requirements barrier HW too
> much. I think we should start somewhere, learn and evolve.
>
You are asking me to go and add a new ndo() every time i have a new
network function? That is not scalable. I have no problem with
the approach that was posted - I have a problem that it is it
focused on flows (and is lacking ability to specify different
classifiers). It should not be called xxx_flow_xxx
> So essentially what you are saying is that the tc interface
> (in particular cls and act) could be used as an API to achieve offloads.
I am pointing to it as an example of something that is *done right* in
terms of not picking a universal classifier. Something the current
OVS posted/used api lacks (and to be frank OF never cared about because
it had a niche use case; lets not make that niche use case the centre
of gravity).
> Yes! I thought this was very clear and a given. I don't think that it
> makes sense to force every offload API consumer through the tc interface
> though.
If you looked at all my presentations I have never laid such
claim but i have always said I want everything described in
iproute2 to work. I dont think anyone disagreed.
I dont expect tc to be used as *the interface*; but on the same
token i dont expect OVS to be used as *the interface*.
Lets start with hardware abstraction. Lets map to existing Linux APIs
and then see where some massaging maybe needed.
> This comes back to my statements in a previous email. I don't
> think we should require that all the offload decision complexity *has*
> to live in the kernel.
Agreed. Move policy decisions out of the kernel for one but also
any complex acrobatics as well that are use case specific.
> Quagga, nft, or OVS should be given an API to
> influence this more directly (with the hardware complexity properly
> abstracted). In-kernel users such as bridge, l3 (especially rules),
> and tc itself could be handled through a cls/act derived API internally.
>
This abstraction gives OVS 1-1 mapping which is something i object to.
You want to penalize me for the sake of getting the OVS api in place?
Beginning with flows and laying claim to that one would be able to
cover everything is non-starter.
>> Lets pick an example of the u32 classifier (or i could pick nftables).
>> Using your scheme i have to incur penalties to translating u32 to your
>> classifier and only achieve basic functionality; and now in addition
>> i cant do 90% of my u32 features. And u32 is very implementable
>> in hardware.
>
> I don't fully understand the last claim.
I will simplify:
You cant possibly do the u32 classifier completely using the posted
hard-coded 15 tuple classifier. It is an NP-complete problem.
There are *a lot* of use cases which can be specified by u32 that are
not possible to specify with the tuples the patches posted propose.
The reverse is not true. You can fully specify the OVS classifier
with u32.
So if you want to specify the closest to a universal grammar for
specifying a classifier - use u32 and create templates for your
classifier.
There are some cases where that approach doesnt make sense:
example if i wanted to specify a string classifier etc.
But if we are talking packet header classifier - it is flexible.
There are also good reasons to specify a universal 5 tuple classifier.
As there are good reasons to specify your latest OF classifier.
But that OF classifier being the starting point is not pragmatic.
Sorry -I cut the email a little because people with short attention span
are probably not following by this time.
I may be slower in responding since i will be offline.
cheers,
jamal
^ permalink raw reply
* Re: [PATCH 0/3] Basic deferred TX queue flushing infrastructure.
From: Jamal Hadi Salim @ 2014-08-24 14:57 UTC (permalink / raw)
To: David Miller, netdev; +Cc: therbert, hannes, edumazet, jeffrey.t.kirsher, rusty
In-Reply-To: <20140823.213839.1953243016141233125.davem@davemloft.net>
On 08/24/14 00:38, David Miller wrote:
> From: David Miller <davem@davemloft.net>
> Date: Sat, 23 Aug 2014 13:28:11 -0700 (PDT)
>
>> This just adds the infrastructure, it does not actually add any
>> instances of actually doing multiple ndo_start_xmit calls per
>> ndo_xmit_flush invocation.
>
> So today I was looking more into this aspect.
>
> Like Tom Herbert has mentioned we have all the infrastructure (sort
> of) already to handle a list of SKBs going down into
> dev_hard_start_xmit() via the GSO handling.
>
> But that code is funny, because it keeps the original GSO head SKB
> around as a placeholder to maintain the list of segmented SKBs.
>
> So the list walker basically walks starting at skb->next. That's
> awkward for what we want to do, which is pass in an arbitrary list of
> SKBs.
>
> All it really wants that head SKB for is essentially list management,
> which seems like overkill to me.
>
> Anyways, this got me thinking that we should have something that
> provides the segment list management and stop keeping that head GSO
> SKB around.
>
> Then we can make that "gso:" label list walker generic enough that we
> could pass down arbitrary lists of SKBs from the qdisc_restart() path.
>
> This list management seems to be the only reason why we keep the GSO
> head SKB around after dev_gso_segment(), we should be able to free it
> up early without any problems right?
>
> I'm also thinking about whether we should hang the generic SKB list
> management off of the txq or the qdisc. Right now the gso_skb thing
> is in the qdisc.
>
> Thoughts?
I think leave it where it is (it messes with accounting otherwise)
and eventually you kill it when you have the batch interface right.
Clearly, the best thing to do is avoid altogether the need to have such
a list. The only reason you need a list around is because you dont know
how much you can send to the driver. tx_win idea may not be the best
but it tried to address that issue.
cheers,
jamal
^ permalink raw reply
* [RFC PATCH net-next 3/3] packet: make use of deferred TX queue flushing
From: Daniel Borkmann @ 2014-08-24 13:42 UTC (permalink / raw)
To: davem; +Cc: netdev
In-Reply-To: <1408887738-7661-1-git-send-email-dborkman@redhat.com>
This adds a first use-case of deferred tail pointer flushing
for AF_PACKET's TX_RING in QDISC_BYPASS mode.
Signed-off-by: Daniel Borkmann <dborkman@redhat.com>
---
net/packet/af_packet.c | 49 +++++++++++++++++++++++++++++++++++++------------
1 file changed, 37 insertions(+), 12 deletions(-)
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 0dfa990..27457e8 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -216,7 +216,8 @@ static void prb_fill_vlan_info(struct tpacket_kbdq_core *,
static void packet_flush_mclist(struct sock *sk);
struct packet_skb_cb {
- unsigned int origlen;
+ u32 enforce_flush:1,
+ origlen:31;
union {
struct sockaddr_pkt pkt;
struct sockaddr_ll ll;
@@ -237,8 +238,11 @@ struct packet_skb_cb {
static void __fanout_unlink(struct sock *sk, struct packet_sock *po);
static void __fanout_link(struct sock *sk, struct packet_sock *po);
+#define PACKET_FLUSH_THRESH 8
+
static int packet_direct_xmit(struct sk_buff *skb)
{
+ bool flush = PACKET_SKB_CB(skb)->enforce_flush;
struct net_device *dev = skb->dev;
netdev_features_t features;
struct netdev_queue *txq;
@@ -261,9 +265,12 @@ static int packet_direct_xmit(struct sk_buff *skb)
HARD_TX_LOCK(dev, txq, smp_processor_id());
if (!netif_xmit_frozen_or_drv_stopped(txq)) {
- ret = netdev_start_xmit(skb, dev);
- if (ret == NETDEV_TX_OK)
+ ret = __netdev_xmit_only(skb, dev);
+ if (ret == NETDEV_TX_OK) {
+ if (flush)
+ __netdev_xmit_flush(dev, queue_map);
txq_trans_update(txq);
+ }
}
HARD_TX_UNLOCK(dev, txq);
@@ -313,7 +320,7 @@ static u16 __packet_pick_tx_queue(struct net_device *dev, struct sk_buff *skb)
return (u16) raw_smp_processor_id() % dev->real_num_tx_queues;
}
-static void packet_pick_tx_queue(struct net_device *dev, struct sk_buff *skb)
+static u16 packet_pick_tx_queue(struct net_device *dev, struct sk_buff *skb)
{
const struct net_device_ops *ops = dev->netdev_ops;
u16 queue_index;
@@ -327,6 +334,7 @@ static void packet_pick_tx_queue(struct net_device *dev, struct sk_buff *skb)
}
skb_set_queue_mapping(skb, queue_index);
+ return queue_index;
}
/* register_prot_hook must be invoked with the po->bind_lock held,
@@ -2237,7 +2245,8 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
unsigned char *addr;
int len_sum = 0;
int status = TP_STATUS_AVAILABLE;
- int hlen, tlen;
+ int hlen, tlen, pending = 0;
+ u16 last_queue = 0;
mutex_lock(&po->pg_vec_lock);
@@ -2276,18 +2285,22 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
ph = packet_current_frame(po, &po->tx_ring,
TP_STATUS_SEND_REQUEST);
if (unlikely(ph == NULL)) {
- if (need_wait && need_resched())
+ if (need_wait && need_resched()) {
+ if (packet_use_direct_xmit(po) && pending > 0) {
+ __netdev_xmit_flush(dev, last_queue);
+ pending = 0;
+ }
schedule();
+ }
continue;
}
status = TP_STATUS_SEND_REQUEST;
hlen = LL_RESERVED_SPACE(dev);
- tlen = dev->needed_tailroom;
- skb = sock_alloc_send_skb(&po->sk,
- hlen + tlen + sizeof(struct sockaddr_ll),
- 0, &err);
+ tlen = dev->needed_tailroom;
+ skb = sock_alloc_send_skb(&po->sk, hlen + tlen +
+ sizeof(struct sockaddr_ll), 0, &err);
if (unlikely(skb == NULL))
goto out_status;
@@ -2319,13 +2332,18 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
}
}
- packet_pick_tx_queue(dev, skb);
+ last_queue = packet_pick_tx_queue(dev, skb);
skb->destructor = tpacket_destruct_skb;
__packet_set_status(po, ph, TP_STATUS_SENDING);
packet_inc_pending(&po->tx_ring);
status = TP_STATUS_SEND_REQUEST;
+ if (pending >= PACKET_FLUSH_THRESH) {
+ PACKET_SKB_CB(skb)->enforce_flush = 1;
+ pending = -1;
+ }
+
err = po->xmit(skb);
if (unlikely(err > 0)) {
err = net_xmit_errno(err);
@@ -2340,7 +2358,11 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
* let's treat it like congestion or err < 0
*/
err = 0;
+ } else {
+ /* Sucessfully sent out. */
+ pending++;
}
+
packet_increment_head(&po->tx_ring);
len_sum += tp_len;
} while (likely((ph != NULL) ||
@@ -2354,11 +2376,12 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
err = len_sum;
goto out_put;
-
out_status:
__packet_set_status(po, ph, status);
kfree_skb(skb);
out_put:
+ if (packet_use_direct_xmit(po) && pending > 0)
+ __netdev_xmit_flush(dev, last_queue);
dev_put(dev);
out:
mutex_unlock(&po->pg_vec_lock);
@@ -2561,6 +2584,8 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
if (unlikely(extra_len == 4))
skb->no_fcs = 1;
+ PACKET_SKB_CB(skb)->enforce_flush = 1;
+
err = po->xmit(skb);
if (err > 0 && (err = net_xmit_errno(err)) != 0)
goto out_unlock;
--
1.7.11.7
^ permalink raw reply related
* [RFC PATCH net-next 2/3] net: add __netdev_xmit_{only,flush} helpers
From: Daniel Borkmann @ 2014-08-24 13:42 UTC (permalink / raw)
To: davem; +Cc: netdev
In-Reply-To: <1408887738-7661-1-git-send-email-dborkman@redhat.com>
This adds two helpers to use xmit and flushing separately from
each other as opposed to netdev_start_xmit().
Signed-off-by: Daniel Borkmann <dborkman@redhat.com>
---
include/linux/netdevice.h | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 1d05932..33faa33 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -3393,6 +3393,21 @@ static inline netdev_tx_t netdev_start_xmit(struct sk_buff *skb, struct net_devi
return __netdev_start_xmit(ops, skb, dev);
}
+static inline netdev_tx_t __netdev_xmit_only(struct sk_buff *skb, struct net_device *dev)
+{
+ const struct net_device_ops *ops = dev->netdev_ops;
+
+ return ops->ndo_start_xmit(skb, dev);
+}
+
+static inline void __netdev_xmit_flush(struct net_device *dev, u16 queue)
+{
+ const struct net_device_ops *ops = dev->netdev_ops;
+
+ if (ops->ndo_xmit_flush)
+ ops->ndo_xmit_flush(dev, queue);
+}
+
int netdev_class_create_file_ns(struct class_attribute *class_attr,
const void *ns);
void netdev_class_remove_file_ns(struct class_attribute *class_attr,
--
1.7.11.7
^ permalink raw reply related
* [RFC PATCH net-next 1/3] ixgbe: support netdev_ops->ndo_xmit_flush()
From: Daniel Borkmann @ 2014-08-24 13:42 UTC (permalink / raw)
To: davem; +Cc: netdev
In-Reply-To: <1408887738-7661-1-git-send-email-dborkman@redhat.com>
This implements the deferred tail pointer flush API for the ixgbe
driver. Similar version also proposed longer time ago by Alexander Duyck.
Signed-off-by: Daniel Borkmann <dborkman@redhat.com>
---
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 28 +++++++++++++++++++++++----
1 file changed, 24 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 87bd53f..4e073cf 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -6957,10 +6957,6 @@ static void ixgbe_tx_map(struct ixgbe_ring *tx_ring,
i = 0;
tx_ring->next_to_use = i;
-
- /* notify HW of packet */
- ixgbe_write_tail(tx_ring, i);
-
return;
dma_error:
dev_err(tx_ring->dev, "TX DMA map failed\n");
@@ -7301,6 +7297,29 @@ static netdev_tx_t ixgbe_xmit_frame(struct sk_buff *skb,
return __ixgbe_xmit_frame(skb, netdev, NULL);
}
+static inline struct ixgbe_ring *
+__ixgb_tx_queue_mapping(struct ixgbe_adapter *adapter, u16 queue)
+{
+ if (unlikely(queue >= adapter->num_tx_queues))
+ queue = queue % adapter->num_tx_queues;
+
+ return adapter->tx_ring[queue];
+}
+
+static void ixgbe_xmit_flush(struct net_device *netdev, u16 queue)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ struct ixgbe_ring *tx_ring;
+
+ tx_ring = __ixgb_tx_queue_mapping(adapter, queue);
+ ixgbe_write_tail(tx_ring, tx_ring->next_to_use);
+
+ /* we need this if more than one processor can write to our tail
+ * at a time, it synchronizes IO on IA64/Altix systems
+ */
+ mmiowb();
+}
+
/**
* ixgbe_set_mac - Change the Ethernet Address of the NIC
* @netdev: network interface device structure
@@ -7914,6 +7933,7 @@ static const struct net_device_ops ixgbe_netdev_ops = {
.ndo_open = ixgbe_open,
.ndo_stop = ixgbe_close,
.ndo_start_xmit = ixgbe_xmit_frame,
+ .ndo_xmit_flush = ixgbe_xmit_flush,
.ndo_select_queue = ixgbe_select_queue,
.ndo_set_rx_mode = ixgbe_set_rx_mode,
.ndo_validate_addr = eth_validate_addr,
--
1.7.11.7
^ permalink raw reply related
* [RFC PATCH net-next 0/3] Some deferred TX queue follow-ups
From: Daniel Borkmann @ 2014-08-24 13:42 UTC (permalink / raw)
To: davem; +Cc: netdev
On top of Dave's `[PATCH 0/3] Basic deferred TX queue flushing infrastructure`.
It adds an implementation for ixgbe and a use-case for AF_PACKET's QDISC_BYPASS.
Daniel Borkmann (3):
ixgbe: support netdev_ops->ndo_xmit_flush()
net: add __netdev_xmit_{only,flush} helpers
packet: make use of deferred TX queue flushing
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 28 ++++++++++++---
include/linux/netdevice.h | 15 ++++++++
net/packet/af_packet.c | 49 ++++++++++++++++++++-------
3 files changed, 76 insertions(+), 16 deletions(-)
--
1.7.11.7
^ permalink raw reply
* Re: [PATCH 0/3] Basic deferred TX queue flushing infrastructure.
From: Jesper Dangaard Brouer @ 2014-08-24 12:58 UTC (permalink / raw)
To: Alexander Duyck
Cc: brouer, David Miller, netdev, therbert, jhs, hannes, edumazet,
jeffrey.t.kirsher, rusty
In-Reply-To: <53F922D1.70409@gmail.com>
On Sat, 23 Aug 2014 16:25:05 -0700
Alexander Duyck <alexander.duyck@gmail.com> wrote:
> On 08/23/2014 01:28 PM, David Miller wrote:
> >
[...]
> > Typically a device queues up a packet in the TX queue and then has to
> > do something to have the device start processing that new entry.
> > Sometimes this is composed of doing an MMIO write to a "tail"
> > register, and in other cases it can involve something as expensive as
> > a hypervisor call.
>
> The MMIO call isn't an issue until you encounter a locked operation, at
> least on x86 architecture. So this often shows up in perf traces as a
> hit on the qdisc lock right after completing a transmit. I've seen it
> at around 20% of CPU utilization when I was doing routing work with ixgbe.
My experience is that perf cannot measure these MMIO writes correctly.
Perf will often blame the lock operations in the qdisc system, but
playing with removing these qdisc and TXQ locks, I found that perf
would start blaming some asm inst that did not make sense (adjusting
the code, would make perf blame another asm inst that didn't make sense).
--
Best regards,
Jesper Dangaard Brouer
MSc.CS, Sr. Network Kernel Developer at Red Hat
Author of http://www.iptv-analyzer.org
LinkedIn: http://www.linkedin.com/in/brouer
^ permalink raw reply
* RE: [PATCH] vhost: Add polling mode
From: Razya Ladelsky @ 2014-08-24 12:26 UTC (permalink / raw)
To: David Laight
Cc: Eran Raichstein, Alex Glikson, kvm@vger.kernel.org,
Michael S. Tsirkin, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org, abel.gordon@gmail.com,
Yossi Kuperman1, Joel Nider,
virtualization@lists.linux-foundation.org
In-Reply-To: <063D6719AE5E284EB5DD2968C1650D6D1747D7F3@AcuExch.aculab.com>
David Laight <David.Laight@ACULAB.COM> wrote on 21/08/2014 05:29:41 PM:
> From: David Laight <David.Laight@ACULAB.COM>
> To: Razya Ladelsky/Haifa/IBM@IBMIL, "Michael S. Tsirkin"
<mst@redhat.com>
> Cc: "abel.gordon@gmail.com" <abel.gordon@gmail.com>, Alex Glikson/
> Haifa/IBM@IBMIL, Eran Raichstein/Haifa/IBM@IBMIL, Joel Nider/Haifa/
> IBM@IBMIL, "kvm@vger.kernel.org" <kvm@vger.kernel.org>, "linux-
> kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
> "netdev@vger.kernel.org" <netdev@vger.kernel.org>,
> "virtualization@lists.linux-foundation.org"
> <virtualization@lists.linux-foundation.org>, Yossi
Kuperman1/Haifa/IBM@IBMIL
> Date: 21/08/2014 05:31 PM
> Subject: RE: [PATCH] vhost: Add polling mode
>
> From: Razya Ladelsky
> > "Michael S. Tsirkin" <mst@redhat.com> wrote on 20/08/2014 01:57:10 PM:
> >
> > > > Results:
> > > >
> > > > Netperf, 1 vm:
> > > > The polling patch improved throughput by ~33% (1516 MB/sec ->
> 2046 MB/sec).
> > > > Number of exits/sec decreased 6x.
> > > > The same improvement was shown when I tested with 3 vms running
netperf
> > > > (4086 MB/sec -> 5545 MB/sec).
> > > >
> > > > filebench, 1 vm:
> > > > ops/sec improved by 13% with the polling patch. Number of exits
> > > > was reduced by 31%.
> > > > The same experiment with 3 vms running filebench showed similar
numbers.
> > > >
> > > > Signed-off-by: Razya Ladelsky <razya@il.ibm.com>
> > >
> > > This really needs more thourough benchmarking report, including
> > > system data. One good example for a related patch:
> > > http://lwn.net/Articles/551179/
> > > though for virtualization, we need data about host as well, and if
you
> > > want to look at streaming benchmarks, you need to test different
message
> > > sizes and measure packet size.
> > >
> >
> > Hi Michael,
> > I have already tried running netperf with several message sizes:
> > 64,128,256,512,600,800...
> > But the results are inconsistent even in the baseline/unpatched
> > configuration.
> > For smaller msg sizes, I get consistent numbers. However, at some
point,
> > when I increase the msg size
> > I get unstable results. For example, for a 512B msg, I get two
scenarios:
> > vm utilization 100%, vhost utilization 75%, throughput ~6300
> > vm utilization 80%, vhost utilization 13%, throughput ~9400 (line
rate)
> >
> > I don't know why vhost is behaving that way for certain message sizes.
> > Do you have any insight to why this is happening?
>
> Have you tried looking at the actual ethernet packet sizes.
> It may well jump between using small packets (the size of the writes)
> and full sized ones.
I will check it,
Thanks,
Razya
>
> If you are trying to measure ethernet packet 'cost' you need to use UDP.
> However that probably uses different code paths.
>
> David
>
>
>
^ permalink raw reply
* Re: [PATCH] drivers: net: wireless: Add include guards
From: Kalle Valo @ 2014-08-24 12:01 UTC (permalink / raw)
To: Rasmus Villemoes; +Cc: John W. Linville, linux-wireless, netdev, linux-kernel
In-Reply-To: <1408710414-13810-1-git-send-email-linux@rasmusvillemoes.dk>
Rasmus Villemoes <linux@rasmusvillemoes.dk> writes:
> The files ray_cs.h and rayctl.h both contain two thirds of what
> appears to be an include guard using the macro name RAYLINK_H (both
> lack the #define). Since RAYLINK_H is not defined anywhere, the
> guards using different macro names.
>
> Signed-off-by: Rasmus Villemoes <linux@rasmusvillemoes.dk>
> ---
> drivers/net/wireless/ray_cs.h | 5 +++--
> drivers/net/wireless/rayctl.h | 5 +++--
As this a change to ray_cs driver, please use prefix "ray_cs:" and drop
that "drivers: net: wireless:".
--
Kalle Valo
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox