Re: [PATCH RFC 19/28] net: dsa: bcm_sf2: make it a real platform driver
Hi Andrew, Le 23/12/2015 04:56, Andrew Lunn a écrit : > diff --git a/Documentation/devicetree/bindings/net/dsa/broadcom.txt > b/Documentation/devicetree/bindings/net/dsa/broadcom.txt > new file mode 100644 > index ..bd92be0ef2c8 > --- /dev/null > +++ b/Documentation/devicetree/bindings/net/dsa/broadcom.txt > @@ -0,0 +1,48 @@ > +* Broadcom Starfighter 2 integrated switch device > + > +Required properties: > + > +- compatible: should be "brcm,brcm-sf2" > +- 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 > + > +Optional properties: > + > +- reg-names: litteral names for the device base register addresses, > + when present must be: "core", "reg", "intrl2_0", "intrl2_1", "fcb", > + "acb" These are in fact mandatory properties. > + > +- interrupt-names: litternal names for the device interrupt lines, > + when present must be: "switch_0" and "switch_1" Likewise > + > +- brcm,num-gphy: specify the maximum number of integrated gigabit PHYs > + in the switch Likewise > + > +- 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 All of these above are indeed optional. Having to introduce a new binding for this driver to be converted is a major deal breaker, the platforms I use have a frozen, yet wrongly specified Device Tree binding, but still, we need to keep backward compatibility with it. My initial attempt, if you remove the part where I tried to convert every switch driver into a PHY device handled that: https://github.com/ffainelli/linux/commit/287fc1b33cdd6155c507a95531fd820a5c6dbaf4 Since we have dsa_of_probe(), that alone should be enough to allow us to maintain a dsa_platform_data structure along with the old binding. This is not a whole lot different from your patch 13. Thanks! -- Florian -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH RFC 21/28] net: dsa: Add some debug prints for error cases
Le 23/12/2015 04:56, Andrew Lunn a écrit : > Due to the complexity it can be hard to know why DSA fails to probe. > Add some debug prints for the common error cases. > > Signed-off-by: Andrew Lunn <and...@lunn.ch> Acked-by: Florian Fainelli <f.faine...@gmail.com> I had something similar here since, thanks! -- Florian -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH RFC 12/28] net: dsa: Make dsa,mii-bus optional
Le 23/12/2015 04:56, Andrew Lunn a écrit : > When all the switches are devices and register to the DSA framework, > having a dsa,mii-bus property is not required. > > Signed-off-by: Andrew Lunn <and...@lunn.ch> Acked-by: Florian Fainelli <f.faine...@gmail.com> -- Florian -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH RFC 06/28] net: dsa: Have the switch driver allocate there own private memory
Le 23/12/2015 04:56, Andrew Lunn a écrit : > Now the switch devices have a dev pointer, make use if it for allocating > the drivers private data structures using a devm_kzalloc(). > > Signed-off-by: Andrew Lunn <and...@lunn.ch> > --- > drivers/net/dsa/bcm_sf2.c | 7 +-- > drivers/net/dsa/mv88e6123.c | 6 +++--- > drivers/net/dsa/mv88e6131.c | 6 +++--- > drivers/net/dsa/mv88e6171.c | 6 +++--- > drivers/net/dsa/mv88e6352.c | 6 +++--- > drivers/net/dsa/mv88e6xxx.c | 13 ++--- > drivers/net/dsa/mv88e6xxx.h | 5 - > include/net/dsa.h | 8 +++- > 8 files changed, 38 insertions(+), 19 deletions(-) > > diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c > index 6925b3c13895..23326c2a01b8 100644 > --- a/drivers/net/dsa/bcm_sf2.c > +++ b/drivers/net/dsa/bcm_sf2.c > @@ -929,7 +929,7 @@ static void bcm_sf2_identify_ports(struct bcm_sf2_priv > *priv, > static int bcm_sf2_sw_setup(struct dsa_switch *ds, struct device *dev) > { > const char *reg_names[BCM_SF2_REGS_NUM] = BCM_SF2_REGS_NAME; > - struct bcm_sf2_priv *priv = ds_to_priv(ds); > + struct bcm_sf2_priv *priv; > struct device_node *dn; > void __iomem **base; > unsigned int port; > @@ -937,6 +937,10 @@ static int bcm_sf2_sw_setup(struct dsa_switch *ds, > struct device *dev) > u32 reg, rev; > int ret; > > + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); > + if (!priv) > + return -ENOMEM; This looks fine overall, except that part, there is an earlier priv = ds_to_priv() in the function so we might be missing a ds->priv = priv here once the allocation is successful. With that fixed: Acked-by: Florian Fainelli <f.faine...@gmail.com> -- Florian -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH RFC 07/28] net: dsa: Remove allocation of driver private memory
Le 23/12/2015 04:56, Andrew Lunn a écrit : > The drivers now allocate their own memory for private usage. Remove > the allocation from the core code. > > Signed-off-by: Andrew Lunn <and...@lunn.ch> Acked-by: Florian Fainelli <f.faine...@gmail.com> -- Florian -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH RFC 08/28] net: dsa: Keep the mii bus and address in the private structure
Le 23/12/2015 04:56, Andrew Lunn a écrit : > Rather than looking up the mii bus and address every time, do it once > and setup, and keep it in the private structure. > > Signed-off-by: Andrew Lunn <and...@lunn.ch> Acked-by: Florian Fainelli <f.faine...@gmail.com> -- Florian -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH RFC 25/28] Documentation: DSA: Describe how probe of DSA and switches work.
Le 23/12/2015 04:56, Andrew Lunn a écrit : > With the introduction of switches as linux devices and the use of the > component framework, probing has become more complex. Add some > documentation. > > Signed-off-by: Andrew Lunn> --- > Documentation/networking/dsa/dsa.txt | 48 > > 1 file changed, 48 insertions(+) > > diff --git a/Documentation/networking/dsa/dsa.txt > b/Documentation/networking/dsa/dsa.txt > index aa9c1f9313cd..376afa135a81 100644 > --- a/Documentation/networking/dsa/dsa.txt > +++ b/Documentation/networking/dsa/dsa.txt > @@ -398,6 +398,54 @@ Switch configuration >on the management interface and "hardcode"/"force" this MAC address for the >CPU/management interface as an optimization > > +Call flow > +- > + > +With the ability for switch devices to be true linux devices, the call > +flow is somewhat complex. The component framework is used to link the > +dsa framework as the master, with switch devices, as slaves. > + > +A switch device should add itself as a component in its probe > +function. > + > +The DSA framework can either be configured using a platform_data > +structure or from the device tree. If device tree is being used, the > +dsa framework probe function will allocate a platform_data structure, > +and populate it using the device tree, via the dsa_of_probe() > +function. Within the DSA device tree, switch devices are represented > +by a phandle to the switch device. These phandles are saved into the > +platform data so that when switch slaves register themselves, they can > +be correctly positioned in the DSA cluster. Humm, I guess I am still not clear on that, in a DT-only system, do I still need to get the DSA platform device to be probed via DT, along with references to the switches I want? If that is the case, that seems a little awkward, could not we probe the individual switches, and see if they need DSA instead? Or is that how the component framework works, just being a bit confused here. Thanks! -- Florian -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH RFC 24/28] net: dsa: If a switch fails to probe, defer probing
Le 23/12/2015 04:56, Andrew Lunn a écrit : > Switches are either listed in device tree of platform_data. They > should exist. If the probe fails, defer the probe, which is the likely > cause of failure, not broken device tree or platform data. > > Signed-off-by: Andrew Lunn <and...@lunn.ch> Acked-by: Florian Fainelli <f.faine...@gmail.com> -- Florian -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH net-next] net: phy: bcm7xxx: Add entry for Broadcom BCM7435
Add a PHY entry for the Broadcom BCM7435 chips, this is a 40nm generation Ethernet PHY which is analogous to its 7425 and 7429 counter parts. Signed-off-by: Florian Fainelli <f.faine...@gmail.com> --- drivers/net/phy/bcm7xxx.c | 14 ++ include/linux/brcmphy.h | 1 + 2 files changed, 15 insertions(+) diff --git a/drivers/net/phy/bcm7xxx.c b/drivers/net/phy/bcm7xxx.c index 03d4809a9126..d4083c381cd1 100644 --- a/drivers/net/phy/bcm7xxx.c +++ b/drivers/net/phy/bcm7xxx.c @@ -361,6 +361,19 @@ static struct phy_driver bcm7xxx_driver[] = { .resume = bcm7xxx_config_init, .driver = { .owner = THIS_MODULE }, }, { + .phy_id = PHY_ID_BCM7435, + .phy_id_mask= 0xfff0, + .name = "Broadcom BCM7435", + .features = PHY_GBIT_FEATURES | + SUPPORTED_Pause | SUPPORTED_Asym_Pause, + .flags = PHY_IS_INTERNAL, + .config_init= bcm7xxx_config_init, + .config_aneg= genphy_config_aneg, + .read_status= genphy_read_status, + .suspend= bcm7xxx_suspend, + .resume = bcm7xxx_config_init, + .driver = { .owner = THIS_MODULE }, +}, { .phy_id = PHY_BCM_OUI_4, .phy_id_mask= 0x, .name = "Broadcom BCM7XXX 40nm", @@ -395,6 +408,7 @@ static struct mdio_device_id __maybe_unused bcm7xxx_tbl[] = { { PHY_ID_BCM7425, 0xfff0, }, { PHY_ID_BCM7429, 0xfff0, }, { PHY_ID_BCM7439, 0xfff0, }, + { PHY_ID_BCM7435, 0xfff0, }, { PHY_ID_BCM7445, 0xfff0, }, { PHY_BCM_OUI_4, 0x }, { PHY_BCM_OUI_5, 0xff00 }, diff --git a/include/linux/brcmphy.h b/include/linux/brcmphy.h index 59f4a7304419..f0ba9c2ec639 100644 --- a/include/linux/brcmphy.h +++ b/include/linux/brcmphy.h @@ -26,6 +26,7 @@ #define PHY_ID_BCM7366 0x600d8490 #define PHY_ID_BCM7425 0x600d86b0 #define PHY_ID_BCM7429 0x600d8730 +#define PHY_ID_BCM7435 0x600d8750 #define PHY_ID_BCM7439 0x600d8480 #define PHY_ID_BCM7439_2 0xae025080 #define PHY_ID_BCM7445 0x600d8510 -- 2.1.0 -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH net-next] MAINTAINERS: PHY: Change maintainer to reviewer
Now that there is a reviewer role, add myself as reviewer since the PHY library code is maintained via the networking tree. Signed-off-by: Florian Fainelli <f.faine...@gmail.com> --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index ea1751283b49..950c321eef73 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4195,7 +4195,7 @@ F:include/linux/netfilter_bridge/ F: net/bridge/ ETHERNET PHY LIBRARY -M: Florian Fainelli <f.faine...@gmail.com> +R: Florian Fainelli <f.faine...@gmail.com> L: netdev@vger.kernel.org S: Maintained F: include/linux/phy.h -- 2.1.0 -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: bridge-utils: wrong sysfs path odds
On 25/11/15 01:21, Richard Weinberger wrote: > Am 25.11.2015 um 01:37 schrieb Stephen Hemminger: >> On Wed, 25 Nov 2015 01:24:47 +0100 >> Richard Weinbergerwrote: >> >>> Am 25.11.2015 um 01:15 schrieb Richard Weinberger: Hi! Today I was hunting down an issue where "brctl stp br0 off" always failed on mips64be with n32 userland. It turned out that the ioctl(fd, SIOCDEVPRIVATE, ) with BRCTL_SET_BRIDGE_STP_STATE returned -EOPNOTSUPP. First I thought that this is a plain ABI issue on mips as in old_dev_ioctl() the ioctl() argument was 0x1 instead of the expected BRCTL_SET_BRIDGE_STP_STATE (0x14) >>> >>> Should be 0xe and not 0x14. It is 14 in decimal. :) >>> >>> Thanks, >>> //richard >> >> Ask Debian maintainer to send his patches, I don't go patch hunting. >> > > While looking what other distros do I came across this patch: > https://pkgs.fedoraproject.org/cgit/bridge-utils.git/tree/bridge-utils-1.5-check-error-returns-from-write-to-sysfs.patch > > Beside of checking return errors is fixes also the sysfs path in br_set(). > Can you please merge it upstream? > > Distros seems to carry more patches for that package, if it helps I can do > the patch hunting for you. > It would be nice to have a recent bridge-utils release. The last one is from > 2011. Most of what bridge-utils does can be done by iproute2's bridge sub-command FWIW. -- Florian -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH net-next] MAINTAINERS: PHY: Change maintainer to reviewer
On 25/11/15 08:36, David Miller wrote: > From: Joe Perches <j...@perches.com> > Date: Tue, 24 Nov 2015 17:04:11 -0800 > >> On Tue, 2015-11-24 at 15:29 -0800, Florian Fainelli wrote: >>> Now that there is a reviewer role, add myself as reviewer since the PHY >>> library code is maintained via the networking tree. >> >> [] >> >>> diff --git a/MAINTAINERS b/MAINTAINERS >> [] >>> @@ -4195,7 +4195,7 @@ F:include/linux/netfilter_bridge/ >>> F:>> net/bridge/ >>> >>> ETHERNET PHY LIBRARY >>> -M: Florian Fainelli <f.faine...@gmail.com> >>> +R: Florian Fainelli <f.faine...@gmail.com> >>> L: netdev@vger.kernel.org >>> S: Maintained >>> F: include/linux/phy.h >> >> Just because the upstream path is not a tree you >> manage doesn't mean you aren't a maintainer. >> >> I think the status should be something other than >> "Maintained" if you are not the maintainer. > > Yeah, I kinda agree, Florian you are pretty much the de-facto > maintainer and I usually wait for you to review any PHY library > changes before applying them unless they are _really_ obvious. Sounds good, let's drop this patch then, thanks! -- Florian -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 00/13] mvneta Buffer Management and enhancements
On 21/11/15 23:53, Marcin Wojtas wrote: > > 4. Buffer manager (BM) support with two preparatory commits. As it is a > separate block, common for all network ports, a new driver is introduced, > which configures it and exposes API to the main network driver. It is > throughly described in binding documentation and commit log. Please note, > that enabling per-port BM usage is done using phandle and the data passed > in mvneta_bm_probe. It is designed for usage of on-demand device probe > and dev_set/get_drvdata, however it's awaiting merge to linux-next. > Therefore, deferring probe is not used - if something goes wrong (same > in case of errors during changing MTU or suspend/resume cycle) mvneta > driver falls back to software buffer management and works in a regular way. Looking at your patches, it was not entirely clear to me how the buffer manager on these Marvell SoCs work, but other networking products have something similar, like Broadcom's Cable Modem SoCs (BCM33xx) FPM, and maybe Freescale's FMAN/DPAA seems to do something similar. Does the buffer manager allocation work by giving you a reference/token to a buffer as opposed to its address? If that is the case, it would be good to design support for such hardware in a way that it can be used by more drivers. Eric Dumazet suggested a while ago to me that you could get abstract such allocation using hardware-assisted buffer allocation by either introducing a new mm zone (instead of ZONE_NORMAL/DMA/HIGHMEM etc.), or using a different NUMA node id, such that SKB allocation and freeing helpers could deal with the specifics, and your networking stack and driver would be mostly unaware of the buffer manager underlying implementation. The purpose would be to get a 'struct page' reference to your buffer pool allocation object, so it becomes mostly transparent to other areas of the kernel, and you could further specialize everything that needs to be based on this node id or zone. Finally, these hardware-assisted allocation schemes typically work very well when there is a forwarding/routing workload involved, because you can easily steal packets and SKBs from the network stack, but that does not necessarily play nicely with host-terminated/initiated traffic which wants to have good feedback on what's happening at the NIC level (queueing, buffering, etc.). > > Known issues: > - problems with obtaining all mapped buffers from internal SRAM, when > destroying the buffer pointer pool > - problems with unmapping chunk of SRAM during driver removal > Above do not have an impact on the operation, as they are called during > driver removal or in error path. Humm, what is the reason for using the on-chip SRAM here, is it because that's the only storage location the Buffer Manager can allocate from, or is it because it is presumably faster or with constant access times than DRAM? Would be nice to explain a bit more in details how the buffer manager works and its interfacing with the network controllers. Can I use the buffer manager with other peripherals as well? Like if I wanted to do zero-copy or hardware-assisted memcpy DMA, would that be a suitable scheme? Thanks! -- Florian -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [RFC 2/8] net-next: phy: dont auto handle carrier state when multiple phys are attached
On 22/11/15 00:40, John Crispin wrote: > A network core might have more than one phy attached to its cpu port via a > switch. The current code will set the carrier state to on/off when ever a > cable is plugged into any of these ports. Not really, no. The current PHY library implementation does not allow more than one net_device instance to be bound to multiple PHY devices. Since this is an integrated switch, you should really expose per-port network devices, that is the paradigm we settled down on using for Ethernet switches now (irrespective of using DSA or switchdev, or both). > > The patch adds a new bool that allows the driver to tell the phy_device to not > set the carrier state. Instead the driver can manually handle the carrier > state. I am missing the bigger picture of how this is used, also, if link down is a problem, would not link up be for the same reasons? > > Signed-off-by: John Crispin <blo...@openwrt.org> > Signed-off-by: Felix Fietkau <n...@openwrt.org> > Signed-off-by: Michael Lee <igv...@gmail.com> > Cc: Florian Fainelli <f.faine...@gmail.com> > --- > drivers/net/phy/phy.c |9 ++--- > include/linux/phy.h |1 + > 2 files changed, 7 insertions(+), 3 deletions(-) > > diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c > index 48ce6ef..bd2df40 100644 > --- a/drivers/net/phy/phy.c > +++ b/drivers/net/phy/phy.c > @@ -843,7 +843,8 @@ void phy_state_machine(struct work_struct *work) > /* If the link is down, give up on negotiation for now */ > if (!phydev->link) { > phydev->state = PHY_NOLINK; > - netif_carrier_off(phydev->attached_dev); > + if (!phydev->no_auto_carrier_off) > + netif_carrier_off(phydev->attached_dev); > phydev->adjust_link(phydev->attached_dev); > break; > } > @@ -926,7 +927,8 @@ void phy_state_machine(struct work_struct *work) > netif_carrier_on(phydev->attached_dev); > } else { > phydev->state = PHY_NOLINK; > - netif_carrier_off(phydev->attached_dev); > + if (!phydev->no_auto_carrier_off) > + netif_carrier_off(phydev->attached_dev); > } > > phydev->adjust_link(phydev->attached_dev); > @@ -938,7 +940,8 @@ void phy_state_machine(struct work_struct *work) > case PHY_HALTED: > if (phydev->link) { > phydev->link = 0; > - netif_carrier_off(phydev->attached_dev); > + if (!phydev->no_auto_carrier_off) > + netif_carrier_off(phydev->attached_dev); > phydev->adjust_link(phydev->attached_dev); > do_suspend = true; > } > diff --git a/include/linux/phy.h b/include/linux/phy.h > index 05fde31..276ab8a 100644 > --- a/include/linux/phy.h > +++ b/include/linux/phy.h > @@ -377,6 +377,7 @@ struct phy_device { > bool is_pseudo_fixed_link; > bool has_fixups; > bool suspended; > + bool no_auto_carrier_off; > > enum phy_state state; > > -- Florian -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH net-next 2/2] dsa: mv88e6xxx.c: Hardware reset the chip if available
On 18/11/15 15:29, Andrew Lunn wrote: > The device tree binding now allows a gpio to be specified which is > attached to the switch chips reset line. If it is defined, perform > a hardware reset on the switch during setup. > > Signed-off-by: Andrew Lunn> --- > drivers/net/dsa/mv88e6xxx.c | 14 ++ > 1 file changed, 14 insertions(+) > > diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c > index b06dba05594a..c0bbbe7713c5 100644 > --- a/drivers/net/dsa/mv88e6xxx.c > +++ b/drivers/net/dsa/mv88e6xxx.c > @@ -19,6 +19,7 @@ > #include > #include > #include > +#include > #include > #include > #include > @@ -2323,7 +2324,10 @@ int mv88e6xxx_switch_reset(struct dsa_switch *ds, bool > ppu_active) > { > struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); > u16 is_reset = (ppu_active ? 0x8800 : 0xc800); > + int gpio = ds->pd->reset; > + int flags = ds->pd->reset_flags; > unsigned long timeout; > + int on = 1; > int ret; > int i; > > @@ -2336,6 +2340,16 @@ int mv88e6xxx_switch_reset(struct dsa_switch *ds, bool > ppu_active) > /* Wait for transmit queues to drain. */ > usleep_range(2000, 4000); > > + /* If there is a gpio connected to the reset pin, toggle it */ > + if (gpio_is_valid(gpio)) { > + if (flags && OF_GPIO_ACTIVE_LOW) > + on = !on; > + gpio_set_value_cansleep(gpio, on); > + usleep_range(1, 2); > + gpio_set_value_cansleep(gpio, !on); > + usleep_range(1, 2); > + } We are embedding reset logic here about the delays and polarity, while there is now a proper abstraction for this within the reset controller subsystem under drivers/reset/core.c. Could we utilize that facility instead which would make us more robust wrt. non-GPIO reset lines (for instance some SF2 switches on DSL gateways could definitively benefit from this). There does not seem to be a reset controller GPIO binding and generic driver, but this seems like an appropriate candidate? -- Florian -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] net: tulip: turn compile-time warning into dev_warn()
On 19/11/15 04:26, Will Deacon wrote: > On Thu, Nov 19, 2015 at 11:42:26AM +0100, Arnd Bergmann wrote: >> The tulip driver causes annoying build-time warnings for allmodconfig >> builds for all recent architectures: >> >> dec/tulip/winbond-840.c:910:2: warning: #warning Processor architecture >> undefined >> dec/tulip/tulip_core.c:101:2: warning: #warning Processor architecture >> undefined! >> >> This is the last remaining warning for arm64, and I'd like to get rid of >> it. We don't really know the cache line size, architecturally it would >> be at least 16 bytes, but all implementations I found have 64 or 128 >> bytes. Configuring tulip for 32-byte lines as we do on ARM32 seems to >> be the safe but slow default, and nobody who cares about performance these >> days would use a tulip chip anyway, so we can just use that. >> >> To save the next person the job of trying to find out what this is for >> and picking a default for their architecture just to kill off the warning, >> I'm now removing the preprocessor #warning and turning it into a pr_warn >> or dev_warn that prints the equivalent information when the driver gets >> loaded. >> >> Signed-off-by: Arnd Bergmann>> >> diff --git a/drivers/net/ethernet/dec/tulip/tulip_core.c >> b/drivers/net/ethernet/dec/tulip/tulip_core.c >> index ed41559bae77..b553409e04ad 100644 >> --- a/drivers/net/ethernet/dec/tulip/tulip_core.c >> +++ b/drivers/net/ethernet/dec/tulip/tulip_core.c >> @@ -98,8 +98,7 @@ static int csr0 = 0x01A0 | 0x4800; >> #elif defined(__mips__) >> static int csr0 = 0x0020 | 0x4000; >> #else >> -#warning Processor architecture undefined! >> -static int csr0 = 0x00A0 | 0x4800; >> +static int csr0; >> #endif >> >> /* Operational parameters that usually are not changed. */ >> @@ -1982,6 +1981,12 @@ static int __init tulip_init (void) >> pr_info("%s", version); >> #endif >> >> +if (!csr0) { >> +pr_warn("tulip: unknown CPU architecture, using default >> csr0\n"); >> +/* default to 8 longword cache line alignment */ >> +csr0 = 0x00A0 | 0x4800; > > Maybe print "defaulting to 8 longword cache line alignment" instead of > "default csr0"? > >> diff --git a/drivers/net/ethernet/dec/tulip/winbond-840.c >> b/drivers/net/ethernet/dec/tulip/winbond-840.c >> index 9beb3d34d4ba..3c0e4d5c5fef 100644 >> --- a/drivers/net/ethernet/dec/tulip/winbond-840.c >> +++ b/drivers/net/ethernet/dec/tulip/winbond-840.c >> @@ -907,7 +907,7 @@ static void init_registers(struct net_device *dev) >> #elif defined(CONFIG_SPARC) || defined (CONFIG_PARISC) || >> defined(CONFIG_ARM) >> i |= 0x4800; >> #else >> -#warning Processor architecture undefined >> +dev_warn(>dev, "unknown CPU architecture, using default csr0 >> setting\n"); >> i |= 0x4800; > > Then we could print the default csr0 value here. > > But, to be honest, this patch fixes a #warning on arm64 for a driver that > I never expect to be used. So whatever you do to silence it: > > Acked-by: Will Deacon > > /me waits for on-soc tulip integration. FWIW, this already happened, the ADMtek/Infineon ADM8668 actually integrated a Tulip chip. I have not submitted these patches below from the OpenWrt tree because the chip is barely used nowadays, and it was only mostly popular with the Linksys WRTU54G. The patches could be made less intrusive if we did convert the pci_dma* calls into regular DMA-API calls, which they are nowadays, oh well! https://dev.openwrt.org/browser/trunk/target/linux/adm8668/patches-3.18/004-tulip_pci_split.patch https://dev.openwrt.org/browser/trunk/target/linux/adm8668/patches-3.18/005-tulip_platform.patch -- Florian -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] net: tulip: update MAINTAINER status to Orphan
On 19/11/15 17:56, Grant Grundler wrote: > From: Grant Grundler> > I haven't had any PCI tulip HW for the past ~5 years. I have > been reviewing tulip patches and can continue doing that. > > Signed-off-by: Grant Grundler > --- > I'm also proposing to add linux-parisc to the list since AFAIK, all > parisc systems but the C8000 workstations (PA8800/PA8900 CPU) > use tulip for onboard LAN. > > Specific mips and alpha systems also care about tulip driver too. > But I don't know either well enough to suggest respective mailing > lists should see every tulip patch. For MIPS, is not Cobalt the primary (and sole) user? You could add linux-m...@linux-mips.org if that helps. My Cobalt stayed behind me when I moved to the US, so outside of Yoichi, I am not sure who else cares these days... > > MAINTAINERS | 4 ++-- > 1 file changed, 2 insertions(+), 2 deletions(-) > > diff --git a/MAINTAINERS b/MAINTAINERS > index ea17512..ec07061 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -10888,9 +10888,9 @@ S:Maintained > F: drivers/media/tuners/tua9001* > > TULIP NETWORK DRIVERS > -M: Grant Grundler > L: netdev@vger.kernel.org > -S: Maintained > +L: linux-par...@vger.kernel.org > +S: Orphan > F: drivers/net/ethernet/dec/tulip/ > > TUN/TAP driver > -- Florian -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH net-next 01/17] net: dsa: slave: chip data is optional, don't dereference NULL
On 06/03/2016 09:44 AM, Andrew Lunn wrote: > The new binding does not make use of dsa_chip_data, a.k.a cd. When > retrieving the size of the EEPROM attached to a switch, don't assume > there is a cd attached to the switch structure. > > Signed-off-by: Andrew Lunn <and...@lunn.ch> Reviewed-by: Florian Fainelli <f.faine...@gmail.com> -- Florian
Re: [PATCH net-next 03/17] net: dsa: slave: Remove MDIO address from switch MDIO bus name
On 06/03/2016 09:44 AM, Andrew Lunn wrote: > The DSA layer should no longer assume the switch is connected to an > MDIO bus. As a result, we cannot use the address on the MDIO bus when > forming the name of the switches internal MDIO bus for its builtin and > possibly external PHYs. The switch index is sufficient to make the > name unique, so drop the MDIO address. > > Signed-off-by: Andrew Lunn <and...@lunn.ch> Reviewed-by: Florian Fainelli <f.faine...@gmail.com> -- Florian
[PATCH net-next 2/2] bgmac: Add support for ethtool statistics
Read the statistics from the BGMAC's builtin MAC and return them to user-space using the standard ethtool helpers. Signed-off-by: Florian Fainelli <f.faine...@gmail.com> --- drivers/net/ethernet/broadcom/bgmac.c | 125 ++ drivers/net/ethernet/broadcom/bgmac.h | 4 +- 2 files changed, 127 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bgmac.c b/drivers/net/ethernet/broadcom/bgmac.c index 156fa6323745..d5877365d81a 100644 --- a/drivers/net/ethernet/broadcom/bgmac.c +++ b/drivers/net/ethernet/broadcom/bgmac.c @@ -1382,6 +1382,128 @@ static const struct net_device_ops bgmac_netdev_ops = { * ethtool_ops **/ +struct bgmac_stat { + u8 size; + u32 offset; + const char *name; +}; + +static struct bgmac_stat bgmac_get_strings_stats[] = { + { 8, BGMAC_TX_GOOD_OCTETS, "tx_good_octets" }, + { 4, BGMAC_TX_GOOD_PKTS, "tx_good" }, + { 8, BGMAC_TX_OCTETS, "tx_octets" }, + { 4, BGMAC_TX_PKTS, "tx_pkts" }, + { 4, BGMAC_TX_BROADCAST_PKTS, "tx_broadcast" }, + { 4, BGMAC_TX_MULTICAST_PKTS, "tx_multicast" }, + { 4, BGMAC_TX_LEN_64, "tx_64" }, + { 4, BGMAC_TX_LEN_65_TO_127, "tx_65_127" }, + { 4, BGMAC_TX_LEN_128_TO_255, "tx_128_255" }, + { 4, BGMAC_TX_LEN_256_TO_511, "tx_256_511" }, + { 4, BGMAC_TX_LEN_512_TO_1023, "tx_512_1023" }, + { 4, BGMAC_TX_LEN_1024_TO_1522, "tx_1024_1522" }, + { 4, BGMAC_TX_LEN_1523_TO_2047, "tx_1523_2047" }, + { 4, BGMAC_TX_LEN_2048_TO_4095, "tx_2048_4095" }, + { 4, BGMAC_TX_LEN_4096_TO_8191, "tx_4096_8191" }, + { 4, BGMAC_TX_LEN_8192_TO_MAX, "tx_8192_max" }, + { 4, BGMAC_TX_JABBER_PKTS, "tx_jabber" }, + { 4, BGMAC_TX_OVERSIZE_PKTS, "tx_oversize" }, + { 4, BGMAC_TX_FRAGMENT_PKTS, "tx_fragment" }, + { 4, BGMAC_TX_UNDERRUNS, "tx_underruns" }, + { 4, BGMAC_TX_TOTAL_COLS, "tx_total_cols" }, + { 4, BGMAC_TX_SINGLE_COLS, "tx_single_cols" }, + { 4, BGMAC_TX_MULTIPLE_COLS, "tx_multiple_cols" }, + { 4, BGMAC_TX_EXCESSIVE_COLS, "tx_excessive_cols" }, + { 4, BGMAC_TX_LATE_COLS, "tx_late_cols" }, + { 4, BGMAC_TX_DEFERED, "tx_defered" }, + { 4, BGMAC_TX_CARRIER_LOST, "tx_carrier_lost" }, + { 4, BGMAC_TX_PAUSE_PKTS, "tx_pause" }, + { 4, BGMAC_TX_UNI_PKTS, "tx_unicast" }, + { 4, BGMAC_TX_Q0_PKTS, "tx_q0" }, + { 8, BGMAC_TX_Q0_OCTETS, "tx_q0_octets" }, + { 4, BGMAC_TX_Q1_PKTS, "tx_q1" }, + { 8, BGMAC_TX_Q1_OCTETS, "tx_q1_octets" }, + { 4, BGMAC_TX_Q2_PKTS, "tx_q2" }, + { 8, BGMAC_TX_Q2_OCTETS, "tx_q2_octets" }, + { 4, BGMAC_TX_Q3_PKTS, "tx_q3" }, + { 8, BGMAC_TX_Q3_OCTETS, "tx_q3_octets" }, + { 8, BGMAC_RX_GOOD_OCTETS, "rx_good_octets" }, + { 4, BGMAC_RX_GOOD_PKTS, "rx_good" }, + { 8, BGMAC_RX_OCTETS, "rx_octets" }, + { 4, BGMAC_RX_PKTS, "rx_pkts" }, + { 4, BGMAC_RX_BROADCAST_PKTS, "rx_broadcast" }, + { 4, BGMAC_RX_MULTICAST_PKTS, "rx_multicast" }, + { 4, BGMAC_RX_LEN_64, "rx_64" }, + { 4, BGMAC_RX_LEN_65_TO_127, "rx_65_127" }, + { 4, BGMAC_RX_LEN_128_TO_255, "rx_128_255" }, + { 4, BGMAC_RX_LEN_256_TO_511, "rx_256_511" }, + { 4, BGMAC_RX_LEN_512_TO_1023, "rx_512_1023" }, + { 4, BGMAC_RX_LEN_1024_TO_1522, "rx_1024_1522" }, + { 4, BGMAC_RX_LEN_1523_TO_2047, "rx_1523_2047" }, + { 4, BGMAC_RX_LEN_2048_TO_4095, "rx_2048_4095" }, + { 4, BGMAC_RX_LEN_4096_TO_8191, "rx_4096_8191" }, + { 4, BGMAC_RX_LEN_8192_TO_MAX, "rx_8192_max" }, + { 4, BGMAC_RX_JABBER_PKTS, "rx_jabber" }, + { 4, BGMAC_RX_OVERSIZE_PKTS, "rx_oversize" }, + { 4, BGMAC_RX_FRAGMENT_PKTS, "rx_fragment" }, + { 4, BGMAC_RX_MISSED_PKTS, "rx_missed" }, + { 4, BGMAC_RX_CRC_ALIGN_ERRS, "rx_crc_align" }, + { 4, BGMAC_RX_UNDERSIZE, "rx_undersize" }, + { 4, BGMAC_RX_CRC_ERRS, "rx_crc" }, + { 4, BGMAC_RX_ALIGN_ERRS, "rx_align" }, + { 4, BGMAC_RX_SYMBOL_ERRS, "rx_symbol" }, + { 4, BGMAC_RX_PAUSE_PKTS, "rx_pause" }, + { 4, BGMAC_RX_NONPAUSE_PKTS, "rx_nonpause" }, + { 4, BGMAC_RX_SACHANGES, "rx_sa_changes" }, + { 4, BGMAC_RX_UNI_PKTS, "rx_unicast" }, +}; + +#define BGMAC_STATS_LEN
[PATCH net-next 1/2] bgmac: Bind net_device with backing device structure
In preparation for allowing different helpers to be utilized against network devices created by the bgmac driver, make sure that we bind the net_device with core->dev. Signed-off-by: Florian Fainelli <f.faine...@gmail.com> --- drivers/net/ethernet/broadcom/bgmac.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/broadcom/bgmac.c b/drivers/net/ethernet/broadcom/bgmac.c index ee5f431ab32a..156fa6323745 100644 --- a/drivers/net/ethernet/broadcom/bgmac.c +++ b/drivers/net/ethernet/broadcom/bgmac.c @@ -1588,6 +1588,7 @@ static int bgmac_probe(struct bcma_device *core) bgmac->net_dev = net_dev; bgmac->core = core; bcma_set_drvdata(core, bgmac); + SET_NETDEV_DEV(net_dev, >dev); /* Defaults */ memcpy(bgmac->net_dev->dev_addr, mac, ETH_ALEN); -- 2.7.4
[PATCH net-next 0/2] net: bgmac: Misc improvements
Hi David, Rafal, Hauke, Felix, This patch series add minor changes to the bgmac driver: - properly bind net_device with its backing device structure such that we can locate the device using common helper functions - add support for ethtool statistics reading the HW MIB counters which is useful for debugging Thanks Florian Fainelli (2): bgmac: Bind net_device with backing device structure bgmac: Add support for ethtool statistics drivers/net/ethernet/broadcom/bgmac.c | 126 ++ drivers/net/ethernet/broadcom/bgmac.h | 4 +- 2 files changed, 128 insertions(+), 2 deletions(-) -- 2.7.4
Re: [PATCH net-next 2/2] bgmac: Add support for ethtool statistics
On 06/03/2016 10:57 AM, Ben Hutchings wrote: > On Fri, 2016-06-03 at 10:07 -0700, Florian Fainelli wrote: > [...] >> +static void bgmac_get_strings(struct net_device *dev, u32 stringset, >> + u8 *data) >> +{ >> +int i; >> + >> +if (stringset != ETH_SS_STATS) >> +return; >> + >> +for (i = 0; i < BGMAC_STATS_LEN; i++) >> +memcpy(data + i * ETH_GSTRING_LEN, >> + bgmac_get_strings_stats[i].name, >> + ETH_GSTRING_LEN); > > These strings are null-terminated, not padded to ETH_GSTRING_LEN. So > here you should be using strlcpy() instead of memcpy(). > >> +} >> + >> +static void bgmac_get_ethtool_stats(struct net_device *dev, >> +struct ethtool_stats *ss, uint64_t *data) >> +{ >> +struct bgmac *bgmac = netdev_priv(dev); >> +const struct bgmac_stat *s; >> +unsigned int i; >> +u64 val; >> + >> +if (!netif_running(dev)) >> +return; >> + >> +for (i = 0; i < BGMAC_STATS_LEN; i++) { >> +s = _get_strings_stats[i]; >> +val = 0; >> +if (s->size == 8) >> +val = (u64)bgmac_read(bgmac, s->offset + 4); > > Isn't this missing a << 32? It is, guess I should have made sure there was 4GB+ worth of traffic to make sure this seemed reasonable. > > Does reading the high 32 bits latch the value of the low 32 bits? If > not, you need to read the high bits again after the low bits and retry > if they changed. Yes these registers are latched. > >> +val |= bgmac_read(bgmac, s->offset); >> +data[i] = (u64)val; > > Redundant cast. Indeed, thanks. -- Florian
Re: [PATCH net-next 04/17] net: dsa: tag_{e}dsa.c: Remove dependency on platform data
On 06/03/2016 09:44 AM, Andrew Lunn wrote: > The platform data nr_chips is used when validating a received packet, > to ensure it comes from a know switch chip. The number of possible > switches is limited to DSA_MAX_SWITCHES, so use this as the first > validation step. The new binding allows holes in the dst->ds[] array, > so also ensure ensure there is a valid dsa_switch for this packet. > > Signed-off-by: Andrew Lunn <and...@lunn.ch> Reviewed-by: Florian Fainelli <f.faine...@gmail.com> -- Florian
Re: [PATCH net-next 11/17] net: dsa: Refactor selection of tag ops into a function
On 06/03/2016 09:44 AM, Andrew Lunn wrote: > Replace the two switch statements with an array lookup, and store the > result in the dsa tree structure. The drivers no longer need to know > the selected tag protocol, so remove it from the dsa switch structure. > > Signed-off-by: Andrew Lunn <and...@lunn.ch> Reviewed-by: Florian Fainelli <f.faine...@gmail.com> -- Florian
Re: [PATCH net-next 00/17] New DSA bind, switches as devices
On 06/03/2016 09:43 AM, Andrew Lunn wrote: > The interesting patches here are the last three. They implement a new > binding for DSA, which removes a few limitations of the current DSA > binding. In particular, it allows switches to be true Linux devices. > These devices can be on any type of bus, unlike the old DSA binding > which assumes MDIO. See the commit log for more details. The second to > last patch modifies an existing boards device tree to use the new > binding, giving a good example of how switches can be true MDIO > devices. The last patch documents the new binding. > > I know both John Crispin and Bryan Whitehead are interesting in > implementing DSA drivers, hence i have CC: you. Comments welcome. > > Thanks go to Florian and Vivien for reviewing, testing and bug fixing > these patches. Will keep reviewing patches by one, but a quick smoke test here on a BCM7445 with bcm_sf2 gives me all thumbs up. Tested-by: Florian Fainelli <f.faine...@gmail.com> Thanks! > > Since RFC: > > * Split the mv88e6xxx MDIO refactor into a rename patch and a refactor > patch. > * Extend commit message with comment about wrong of_node_put() > * Fix destroy of cpu and dsa ports. > * Rename _DSA_TAG_LAST to DSA_TAG_LAST and add a comment. > > Andrew Lunn (16): > net: dsa: slave: chip data is optional, don't dereference NULL > net: dsa: slave: Remove MDIO address from switch MDIO bus name > net: dsa: tag_{e}dsa.c: Remove dependency on platform data > net: dsa: Add a ports structure and use it in the switch structure > net: dsa: Move port device node into port structure > net: dsa: Remove dynamic allocate of routing table > net: dsa: Copy the routing table into the switch structure > net: dsa: Split up creating/destroying of DSA and CPU ports > net: dsa: mv88e6xxx: Only support EDSA tagging > net: dsa: Refactor selection of tag ops into a function > net: dsa: Make mdio bus optional > net: dsa: mv88e6xxx: Rename _phy_ to _mdio_ > net: dsa: mv88e6xxx: Refactor MDIO so driver registers mdio bus > net: dsa: Add new binding implementation > arm: dt: vf610-zii-devel-b: Make use of new DSA binding > net: dsa: Document new binding > > Vivien Didelot (1): > net: dsa: mv88e6xxx: fix circular lock in PPU work > > Documentation/devicetree/bindings/net/dsa/dsa.txt | 278 - > arch/arm/boot/dts/vf610-zii-dev-rev-b.dts | 328 +-- > drivers/net/dsa/bcm_sf2.c | 4 +- > drivers/net/dsa/mv88e6xxx.c | 267 ++--- > drivers/net/dsa/mv88e6xxx.h | 6 + > include/net/dsa.h | 56 +- > net/dsa/Makefile | 2 +- > net/dsa/dsa.c | 210 --- > net/dsa/dsa2.c| 653 > ++ > net/dsa/dsa_priv.h| 6 +- > net/dsa/slave.c | 57 +- > net/dsa/tag_brcm.c| 4 +- > net/dsa/tag_dsa.c | 10 +- > net/dsa/tag_edsa.c| 10 +- > net/dsa/tag_trailer.c | 4 +- > 15 files changed, 1485 insertions(+), 410 deletions(-) > create mode 100644 net/dsa/dsa2.c > -- Florian
Re: [PATCH net-next 05/17] net: dsa: Add a ports structure and use it in the switch structure
On 06/03/2016 09:44 AM, Andrew Lunn wrote: > There are going to be more per-port members added to the switch > structure. So add a port structure and move the netdev into it. > > Signed-off-by: Andrew Lunn <and...@lunn.ch> Reviewed-by: Florian Fainelli <f.faine...@gmail.com> -- Florian
Re: [PATCH net-next 06/17] net: dsa: Move port device node into port structure
On 06/03/2016 09:44 AM, Andrew Lunn wrote: > Move the port device node structure into the port structure, from the > chip data. This information is needed in the next step of implementing > the new binding. > > The chip data structure is used while parsing the whole old binding, > before the individual switch structures exist. With the new bindings, > this is reversed, the switches exist first, and the interconnections > between the switches is derived from the individual switch > bindings. Thus this chip data structure becomes unneeded. > > Signed-off-by: Andrew Lunn <and...@lunn.ch> Reviewed-by: Florian Fainelli <f.faine...@gmail.com> -- Florian
Re: [PATCH net-next 09/17] net: dsa: Split up creating/destroying of DSA and CPU ports
On 06/03/2016 09:44 AM, Andrew Lunn wrote: > Refactor the code to setup a single DSA/CPU port into a function of > its own, and export it, so it can be used by the new binding. > > Similarly, refactor the destroy code into a function. When destroying > the ports, don't put the of node. They should be released at the end > along with the normal ports. > > Signed-off-by: Andrew Lunn <and...@lunn.ch> Reviewed-by: Florian Fainelli <f.faine...@gmail.com> -- Florian
Re: [PATCH net-next 08/17] net: dsa: Copy the routing table into the switch structure
On 06/03/2016 09:44 AM, Andrew Lunn wrote: > The new binding will not have a chip data structure, it will place the > routing directly into the switch structure. To enable backwards > compatibility, copy the routing from the chip data into the switch > structure. > > Signed-off-by: Andrew Lunn <and...@lunn.ch> Reviewed-by: Florian Fainelli <f.faine...@gmail.com> -- Florian
Re: [PATCH net-next 10/17] net: dsa: mv88e6xxx: Only support EDSA tagging
On 06/03/2016 09:44 AM, Andrew Lunn wrote: > The merged driver no longer offers the option to use DSA tagging. So > remove the code to setup the switch to do DSA tagging and hard code > the use of EDSA. > > Signed-off-by: Andrew Lunn <and...@lunn.ch> Reviewed-by: Florian Fainelli <f.faine...@gmail.com> -- Florian
Re: [PATCH net-next 02/17] net: dsa: mv88e6xxx: fix circular lock in PPU work
ce: > [4.679674] [<8010d354>] (dump_backtrace) from [<8010d5a0>] > (show_stack+0x20/0x24) > [4.687252] r6:80fb3c88 r5:80fb3c88 r4:80fb4728 r3:0002 > [4.693003] [<8010d580>] (show_stack) from [<803b45e8>] > (dump_stack+0x24/0x28) > [4.700246] [<803b45c4>] (dump_stack) from [<80157398>] > (print_circular_bug+0x208/0x32c) > [4.708361] [<80157190>] (print_circular_bug) from [<8015a630>] > (__lock_acquire+0x185c/0x1b80) > [4.716982] r10:9ec22a00 r9:0060 r8:8164b6bc r7:0040 > r6:0003 r5:8163a5b4 > [4.724905] r4:0003 r3:9ec22de8 > [4.728537] [<80158dd4>] (__lock_acquire) from [<8015ad5c>] > (lock_acquire+0xb4/0x1dc) > [4.736378] r10:6013 r9: r8: r7: > r6:9e5e9c50 r5:80e618e0 > [4.744301] r4: > [4.746879] [<8015aca8>] (lock_acquire) from [<806d86bc>] > (mutex_lock_nested+0x54/0x360) > [4.754976] r10:9e5e9c1c r9:80e616c4 r8:9f685ea0 r7:001b > r6:9ec22a00 r5:8163a5b4 > [4.762899] r4:9e5e9c1c > [4.765477] [<806d8668>] (mutex_lock_nested) from [<8049c758>] > (mv88e6xxx_reg_read+0x30/0x54) > [4.774008] r10:80e60c5b r9:80e616c4 r8:9f685ea0 r7:001b > r6:0004 r5:9e5e9c10 > [4.781930] r4:9e5e9c1c > [4.784507] [<8049c728>] (mv88e6xxx_reg_read) from [<8049cad8>] > (mv88e6xxx_ppu_reenable_work+0x40/0xd4) > [4.793907] r7:9ffd5400 r6:9e5e9c68 r5:9e5e9cb0 r4:9e5e9c10 > [4.799659] [<8049ca98>] (mv88e6xxx_ppu_reenable_work) from > [<8013a794>] (process_one_work+0x1a8/0x604) > [4.809059] r9:80e616c4 r8:9f685ea0 r7:9ffd5400 r6:80e0a1c8 > r5:9f5f2e80 r4:9e5e9cb0 > [4.816910] [<8013a5ec>] (process_one_work) from [<8013ac54>] > (worker_thread+0x64/0x528) > [4.825010] r10:9f5f2e80 r9:0008 r8:80e0dc80 r7:80e0a1fc > r6:80e0a1c8 r5:9f5f2e98 > [4.832933] r4:80e0a1c8 > [4.835510] [<8013abf0>] (worker_thread) from [<801409e8>] > (kthread+0xec/0x100) > [4.842827] r10: r9: r8: r7:8013abf0 > r6:9f5f2e80 r5:9ec15740 > [4.850749] r4: > [4.853327] [<801408fc>] (kthread) from [<80108f30>] > (ret_from_fork+0x14/0x24) > [4.860557] r7: r6: r5:801408fc r4:9ec15740 > > Signed-off-by: Vivien Didelot <vivien.dide...@savoirfairelinux.com> Reviewed-by: Florian Fainelli <f.faine...@gmail.com> -- Florian
Re: [PATCH net-next 07/17] net: dsa: Remove dynamic allocate of routing table
On 06/03/2016 09:44 AM, Andrew Lunn wrote: > With a maximum of four switches, the size of the routing table is the > same as the pointer to it. Removing it makes the code simpler. > > Signed-off-by: Andrew Lunn <and...@lunn.ch> Reviewed-by: Florian Fainelli <f.faine...@gmail.com> -- Florian
Re: [PATCH net-next 15/17] net: dsa: Add new binding implementation
On 06/03/2016 09:44 AM, Andrew Lunn wrote: > The existing DSA binding has a number of limitations and problems. The > main problem is that it cannot represent a switch as a linux device, > hanging off some bus. It is limited to one CPU port. The DSA platform > device is artificial, and does not really represent hardware. > > Implement a new binding which can be embedded into any type of node on > a bus to represent one switch device, and its links to other switches. > > Signed-off-by: Andrew Lunn <and...@lunn.ch> > Signed-off-by: Florian Fainelli <f.faine...@gmail.com> Just a few nits that I had not seen before... > diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c > index 6c314f300424..d8cb2acd4f0a 100644 > --- a/net/dsa/dsa.c > +++ b/net/dsa/dsa.c > @@ -294,6 +294,7 @@ static int dsa_switch_setup_one(struct dsa_switch *ds, > struct device *parent) > } > dst->cpu_switch = index; > dst->cpu_port = i; > + ds->cpu_port_mask |= 1 << i; > } else if (!strcmp(name, "dsa")) { > ds->dsa_port_mask |= 1 << i; > } else { We might want to undo setting the cpu_port_mask bit in dsa_cpu_dsa_destroy()? [snip] > +static int dsa_ds_complete(struct dsa_switch_tree *dst, struct dsa_switch > *ds) > +{ > + struct device_node *port; > + u32 index; > + int err; > + > + for (index = 0; index < DSA_MAX_PORTS; index++) { > + port = ds->ports[index].dn; > + if (!port) > + continue; > + > + if (!dsa_port_is_dsa(port)) > + continue; > + > + ds->dsa_port_mask |= 1 << index; > + > + err = dsa_port_complete(dst, ds, port, index); > + if (err != 0) Should we move ds->dsa_port_mask |= 1 << index into dsa_port_complete, for a) symetry with code undoing this, and b) avoid letting this bit be set in case dsa_port_complete() returns an error? -- Florian
[PATCH net-next v4 0/6] net: dsa: misc improvements
Hi all, This patch series builds on top of Andrew's "New DSA bind, switches as devices" patch set and does the following: - add a few helper functions/goodies for net/dsa/dsa2.c to be as close as possible from net/dsa/dsa.c in terms of what drivers can expect, in particular the slave MDIO bus and the enabled_port_mask and phy_mii_mask - fix the CPU port ethtools ops to work in a multiple tree setup since we can no longer assume a single tree is supported - make the bcm_sf2 driver register its own MDIO bus, yet assign it to ds->slave_mii_bus for everything to work in net/dsa/slave.c wrt. PHY probing, this is a tad cleaner than what we have now Changes in v2: Most of the previous patches have been dropped to just keep the relevant ones now. Changes in v3: - split the addition of the slave MII bus as a separate patch - properly unwind all operations at the right place and right time (ethtool ops, slave MDIO bus - fixed a few typos here and there Changes in v4: - removed superfluous dst agrument to dsa_cpu_port_ethtool_{setup,restore} Florian Fainelli (6): net: dsa: Provide unique DSA slave MII bus names net: dsa: Initialize ds->enabled_port_mask and ds->phys_mii_mask net: dsa: Provide a slave MII bus if needed net: dsa: Add initialization helper for CPU port ethtool_ops net: dsa: Initialize CPU port ethtool ops per tree net: dsa: bcm_sf2: Register our slave MDIO bus drivers/net/dsa/bcm_sf2.c | 215 +- drivers/net/dsa/bcm_sf2.h | 6 ++ include/net/dsa.h | 1 + net/dsa/dsa.c | 41 + net/dsa/dsa2.c| 36 net/dsa/dsa_priv.h| 5 ++ net/dsa/slave.c | 25 ++ 7 files changed, 232 insertions(+), 97 deletions(-) -- 2.7.4
[PATCH net-next v4 4/6] net: dsa: Add initialization helper for CPU port ethtool_ops
Add a helper function: dsa_cpu_port_ethtool_init() which initializes a custom ethtool_ops structure with custom DSA ethtool operations for CPU ports. This is a preliminary change to move the initialization outside of net/dsa/slave.c. Reviewed-by: Vivien Didelot <vivien.dide...@savoirfairelinux.com> Signed-off-by: Florian Fainelli <f.faine...@gmail.com> --- net/dsa/dsa_priv.h | 1 + net/dsa/slave.c| 14 -- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h index b42f1a5f95f3..106a9f067f94 100644 --- a/net/dsa/dsa_priv.h +++ b/net/dsa/dsa_priv.h @@ -58,6 +58,7 @@ const struct dsa_device_ops *dsa_resolve_tag_protocol(int tag_protocol); /* slave.c */ extern const struct dsa_device_ops notag_netdev_ops; void dsa_slave_mii_bus_init(struct dsa_switch *ds); +void dsa_cpu_port_ethtool_init(struct ethtool_ops *ops); int dsa_slave_create(struct dsa_switch *ds, struct device *parent, int port, const char *name); void dsa_slave_destroy(struct net_device *slave_dev); diff --git a/net/dsa/slave.c b/net/dsa/slave.c index a51dfedf0014..8d159932e082 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -865,6 +865,13 @@ static void dsa_slave_poll_controller(struct net_device *dev) } #endif +void dsa_cpu_port_ethtool_init(struct ethtool_ops *ops) +{ + ops->get_sset_count = dsa_cpu_port_get_sset_count; + ops->get_ethtool_stats = dsa_cpu_port_get_ethtool_stats; + ops->get_strings = dsa_cpu_port_get_strings; +} + static const struct ethtool_ops dsa_slave_ethtool_ops = { .get_settings = dsa_slave_get_settings, .set_settings = dsa_slave_set_settings, @@ -1124,12 +1131,7 @@ int dsa_slave_create(struct dsa_switch *ds, struct device *parent, sizeof(struct ethtool_ops)); memcpy(_cpu_port_ethtool_ops, >master_ethtool_ops, sizeof(struct ethtool_ops)); - dsa_cpu_port_ethtool_ops.get_sset_count = - dsa_cpu_port_get_sset_count; - dsa_cpu_port_ethtool_ops.get_ethtool_stats = - dsa_cpu_port_get_ethtool_stats; - dsa_cpu_port_ethtool_ops.get_strings = - dsa_cpu_port_get_strings; + dsa_cpu_port_ethtool_init(_cpu_port_ethtool_ops); master->ethtool_ops = _cpu_port_ethtool_ops; } eth_hw_addr_inherit(slave_dev, master); -- 2.7.4
[PATCH net-next v4 3/6] net: dsa: Provide a slave MII bus if needed
Mimic what net/dsa/dsa.c does and provide a slave MII bus by default which will be created if the driver implements a phy_read method. Reviewed-by: Andrew Lunn <and...@lunn.ch> Reviewed-by: Vivien Didelot <vivien.dide...@savoirfairelinux.com> Signed-off-by: Florian Fainelli <f.faine...@gmail.com> --- net/dsa/dsa2.c | 15 +++ 1 file changed, 15 insertions(+) diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c index 921a36fd139d..4e0f3c268103 100644 --- a/net/dsa/dsa2.c +++ b/net/dsa/dsa2.c @@ -312,6 +312,18 @@ static int dsa_ds_apply(struct dsa_switch_tree *dst, struct dsa_switch *ds) if (err < 0) return err; + if (!ds->slave_mii_bus && ds->drv->phy_read) { + ds->slave_mii_bus = devm_mdiobus_alloc(ds->dev); + if (!ds->slave_mii_bus) + return -ENOMEM; + + dsa_slave_mii_bus_init(ds); + + err = mdiobus_register(ds->slave_mii_bus); + if (err < 0) + return err; + } + for (index = 0; index < DSA_MAX_PORTS; index++) { port = ds->ports[index].dn; if (!port) @@ -361,6 +373,9 @@ static void dsa_ds_unapply(struct dsa_switch_tree *dst, struct dsa_switch *ds) dsa_user_port_unapply(port, index, ds); } + + if (ds->slave_mii_bus && ds->drv->phy_read) + mdiobus_unregister(ds->slave_mii_bus); } static int dsa_dst_apply(struct dsa_switch_tree *dst) -- 2.7.4
[PATCH net-next v4 2/6] net: dsa: Initialize ds->enabled_port_mask and ds->phys_mii_mask
Some drivers rely on these two bitmasks to contain the correct values for them to successfully probe and initialize at drv->setup() time, calculate correct values to put in both masks as early as possible in dsa_get_ports_dn(). Reviewed-by: Andrew Lunn <and...@lunn.ch> Signed-off-by: Florian Fainelli <f.faine...@gmail.com> --- net/dsa/dsa2.c | 15 +++ 1 file changed, 15 insertions(+) diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c index 80dfe08db825..921a36fd139d 100644 --- a/net/dsa/dsa2.c +++ b/net/dsa/dsa2.c @@ -283,6 +283,7 @@ static void dsa_user_port_unapply(struct device_node *port, u32 index, if (ds->ports[index].netdev) { dsa_slave_destroy(ds->ports[index].netdev); ds->ports[index].netdev = NULL; + ds->enabled_port_mask &= ~(1 << index); } } @@ -292,6 +293,13 @@ static int dsa_ds_apply(struct dsa_switch_tree *dst, struct dsa_switch *ds) u32 index; int err; + /* Initialize ds->phys_mii_mask before registering the slave MDIO bus +* driver and before drv->setup() has run, since the switch drivers and +* the slave MDIO bus driver rely on these values for probing PHY +* devices or not +*/ + ds->phys_mii_mask = ds->enabled_port_mask; + err = ds->drv->setup(ds); if (err < 0) return err; @@ -511,6 +519,13 @@ static int dsa_parse_ports_dn(struct device_node *ports, struct dsa_switch *ds) return -EINVAL; ds->ports[reg].dn = port; + + /* Initialize enabled_port_mask now for drv->setup() +* to have access to a correct value, just like what +* net/dsa/dsa.c::dsa_switch_setup_one does. +*/ + if (!dsa_port_is_cpu(port)) + ds->enabled_port_mask |= 1 << reg; } return 0; -- 2.7.4
[PATCH net-next v4 1/6] net: dsa: Provide unique DSA slave MII bus names
In case we have multiples trees and switches with the same index, we need to add another discriminating id: the switch tree. Reviewed-by: Andrew Lunn <and...@lunn.ch> Reviewed-by: Vivien Didelot <vivien.dide...@savoirfairelinux.com> Signed-off-by: Florian Fainelli <f.faine...@gmail.com> --- net/dsa/slave.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 15a492261895..a51dfedf0014 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -49,7 +49,8 @@ void dsa_slave_mii_bus_init(struct dsa_switch *ds) ds->slave_mii_bus->name = "dsa slave smi"; ds->slave_mii_bus->read = dsa_slave_phy_read; ds->slave_mii_bus->write = dsa_slave_phy_write; - snprintf(ds->slave_mii_bus->id, MII_BUS_ID_SIZE, "dsa-%d", ds->index); + snprintf(ds->slave_mii_bus->id, MII_BUS_ID_SIZE, "dsa-%d.%d", +ds->dst->tree, ds->index); ds->slave_mii_bus->parent = ds->dev; ds->slave_mii_bus->phy_mask = ~ds->phys_mii_mask; } -- 2.7.4
[PATCH net-next v4 6/6] net: dsa: bcm_sf2: Register our slave MDIO bus
Register a slave MDIO bus which allows us to divert problematic read/writes towards conflicting pseudo-PHY address (30). Do no longer rely on DSA's slave_mii_bus, but instead provide our own implementation which offers more flexibility as to what to do, and when to register it. We need to register it by the time we are able to get access to our memory mapped registers, which is not until drv->setup() time. In order to avoid forward declarations, we need to re-order the function bodies a bit. Reviewed-by: Andrew Lunn <and...@lunn.ch> Reviewed-by: Vivien Didelot <vivien.dide...@savoirfairelinux.com> Signed-off-by: Florian Fainelli <f.faine...@gmail.com> --- drivers/net/dsa/bcm_sf2.c | 215 +- drivers/net/dsa/bcm_sf2.h | 6 ++ 2 files changed, 140 insertions(+), 81 deletions(-) diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index 73df91bb0466..d6625783703f 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -836,6 +837,66 @@ static int bcm_sf2_sw_fdb_dump(struct dsa_switch *ds, int port, return 0; } +static int bcm_sf2_sw_indir_rw(struct bcm_sf2_priv *priv, int op, int addr, + int regnum, u16 val) +{ + 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 & 0x; +} + +static int bcm_sf2_sw_mdio_read(struct mii_bus *bus, int addr, int regnum) +{ + struct bcm_sf2_priv *priv = bus->priv; + + /* Intercept reads from Broadcom pseudo-PHY address, else, send +* them to our master MDIO bus controller +*/ + if (addr == BRCM_PSEUDO_PHY_ADDR && priv->indir_phy_mask & BIT(addr)) + return bcm_sf2_sw_indir_rw(priv, 1, addr, regnum, 0); + else + return mdiobus_read(priv->master_mii_bus, addr, regnum); +} + +static int bcm_sf2_sw_mdio_write(struct mii_bus *bus, int addr, int regnum, +u16 val) +{ + struct bcm_sf2_priv *priv = bus->priv; + + /* Intercept writes to the Broadcom pseudo-PHY address, else, +* send them to our master MDIO bus controller +*/ + if (addr == BRCM_PSEUDO_PHY_ADDR && priv->indir_phy_mask & BIT(addr)) + bcm_sf2_sw_indir_rw(priv, 0, addr, regnum, val); + else + mdiobus_write(priv->master_mii_bus, addr, regnum, val); + + return 0; +} + static irqreturn_t bcm_sf2_switch_0_isr(int irq, void *dev_id) { struct bcm_sf2_priv *priv = dev_id; @@ -932,6 +993,72 @@ static void bcm_sf2_identify_ports(struct bcm_sf2_priv *priv, } } +static int bcm_sf2_mdio_register(struct dsa_switch *ds) +{ + struct bcm_sf2_priv *priv = ds_to_priv(ds); + struct device_node *dn; + static int index; + int err; + + /* Find our integrated MDIO bus node */ + dn = of_find_compatible_node(NULL, NULL, "brcm,unimac-mdio"); + priv->master_mii_bus = of_mdio_find_bus(dn); + if (!priv->master_mii_bus) + return -EPROBE_DEFER; + + get_device(>master_mii_bus->dev); + priv->master_mii_dn = dn; + + priv->slave_mii_bus = devm_mdiobus_alloc(ds->dev); + if (!priv->slave_mii_bus) + return -ENOMEM; + + priv->slave_mii_bus->priv = priv; + priv->slave_mii_bus->name = "sf2 slave mii"; + priv->slave_mii_bus->read = bcm_sf2_sw_mdio_read; + priv->slave_mii_bus->write = bcm_sf2_sw_mdio_write; + snprintf(priv->slave_mii_bus->id, MII_BUS_ID_SIZE, "sf2-%d", +index++); + priv->slave_mii_bus->dev.of_node = dn; + + /* Include the pseudo-PHY address to divert reads towards our +* workaround. This is only required for 7445D0, since 7445E0 +* disconnects the internal switch pseudo-PHY such that we can use the +* regular SWITCH_MDIO master controller instead. +* +* Here we flag the pseudo PHY as needing special treatment and would +* otherwise make all other PHY read/writes go to the master MDIO bus +* controller that comes with this switch backed by the "
[PATCH net-next v4 5/6] net: dsa: Initialize CPU port ethtool ops per tree
Now that we can properly support multiple distinct trees in the system, using a global variable: dsa_cpu_port_ethtool_ops is getting clobbered as soon as the second switch tree gets probed, and we don't want that. We need to move this to be dynamically allocated, and since we can't really be comparing addresses anymore to determine first time initialization versus any other times, just move this to dsa.c and dsa2.c where the remainder of the dst/ds initialization happens. The operations teardown restores the master netdev's ethtool_ops to its original ethtool_ops pointer (typically within the Ethernet driver) Signed-off-by: Florian Fainelli <f.faine...@gmail.com> --- include/net/dsa.h | 1 + net/dsa/dsa.c | 41 + net/dsa/dsa2.c | 6 ++ net/dsa/dsa_priv.h | 2 ++ net/dsa/slave.c| 10 -- 5 files changed, 50 insertions(+), 10 deletions(-) diff --git a/include/net/dsa.h b/include/net/dsa.h index cca7ef230742..20b3087ad193 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -116,6 +116,7 @@ struct dsa_switch_tree { * Original copy of the master netdev ethtool_ops */ struct ethtool_ops master_ethtool_ops; + const struct ethtool_ops *master_orig_ethtool_ops; /* * The switch and port to which the CPU is attached. diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c index ce3b942dce76..766d2a525ada 100644 --- a/net/dsa/dsa.c +++ b/net/dsa/dsa.c @@ -266,6 +266,41 @@ const struct dsa_device_ops *dsa_resolve_tag_protocol(int tag_protocol) return ops; } +int dsa_cpu_port_ethtool_setup(struct dsa_switch *ds) +{ + struct net_device *master; + struct ethtool_ops *cpu_ops; + + master = ds->dst->master_netdev; + if (ds->master_netdev) + master = ds->master_netdev; + + cpu_ops = devm_kzalloc(ds->dev, sizeof(*cpu_ops), GFP_KERNEL); + if (!cpu_ops) + return -ENOMEM; + + memcpy(>dst->master_ethtool_ops, master->ethtool_ops, + sizeof(struct ethtool_ops)); + ds->dst->master_orig_ethtool_ops = master->ethtool_ops; + memcpy(cpu_ops, >dst->master_ethtool_ops, + sizeof(struct ethtool_ops)); + dsa_cpu_port_ethtool_init(cpu_ops); + master->ethtool_ops = cpu_ops; + + return 0; +} + +void dsa_cpu_port_ethtool_restore(struct dsa_switch *ds) +{ + struct net_device *master; + + master = ds->dst->master_netdev; + if (ds->master_netdev) + master = ds->master_netdev; + + master->ethtool_ops = ds->dst->master_orig_ethtool_ops; +} + static int dsa_switch_setup_one(struct dsa_switch *ds, struct device *parent) { struct dsa_switch_driver *drv = ds->drv; @@ -379,6 +414,10 @@ static int dsa_switch_setup_one(struct dsa_switch *ds, struct device *parent) ret = 0; } + ret = dsa_cpu_port_ethtool_setup(ds); + if (ret) + return ret; + #ifdef CONFIG_NET_DSA_HWMON /* If the switch provides a temperature sensor, * register with hardware monitoring subsystem. @@ -963,6 +1002,8 @@ static void dsa_remove_dst(struct dsa_switch_tree *dst) dsa_switch_destroy(ds); } + dsa_cpu_port_ethtool_restore(dst->ds[0]); + dev_put(dst->master_netdev); } diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c index 4e0f3c268103..83b95fc4cede 100644 --- a/net/dsa/dsa2.c +++ b/net/dsa/dsa2.c @@ -394,6 +394,10 @@ static int dsa_dst_apply(struct dsa_switch_tree *dst) return err; } + err = dsa_cpu_port_ethtool_setup(dst->ds[0]); + if (err) + return err; + /* If we use a tagging format that doesn't have an ethertype * field, make sure that all packets from this point on get * sent to the tag format's receive function. @@ -429,6 +433,8 @@ static void dsa_dst_unapply(struct dsa_switch_tree *dst) dsa_ds_unapply(dst, ds); } + dsa_cpu_port_ethtool_restore(dst->ds[0]); + pr_info("DSA: tree %d unapplied\n", dst->tree); dst->applied = false; } diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h index 106a9f067f94..00077a9c97f4 100644 --- a/net/dsa/dsa_priv.h +++ b/net/dsa/dsa_priv.h @@ -54,6 +54,8 @@ int dsa_cpu_dsa_setup(struct dsa_switch *ds, struct device *dev, struct device_node *port_dn, int port); void dsa_cpu_dsa_destroy(struct device_node *port_dn); const struct dsa_device_ops *dsa_resolve_tag_protocol(int tag_protocol); +int dsa_cpu_port_ethtool_setup(struct dsa_switch *ds); +void dsa_cpu_port_ethtool_restore(struct dsa_switch *ds); /* slave.c */ extern const struct dsa_device_ops notag_netdev_ops; diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 8d159932e082..7236eb26dc97 100644 --- a/net/dsa/sla
Re: [PATCH net-next v2 5/5] net: dsa: bcm_sf2: Register our slave MDIO bus
On 06/07/2016 12:11 PM, Vivien Didelot wrote: > Hi Andrew, > > Andrew Lunnwrites: > With the legacy interface it is tricky. When would you call such a remove/tairdown function when using the old binding? >>> >>> That'd go in dsa_switch_destroy I guess, but it just covers the case >>> where the whole DSA code is unloaded... >> >> I don't think that helps you. It should not be possible to unload the >> DSA core while there is an active driver. The drivers needs to unload >> first > > Well, dsa_switch_destroy() is where ds->slave_mii_bus gets unregistered > (if registered by the framework), so it seems fair to do something like: > > if (ds->drv->shutdown) > ds->drv->shutdown(ds); > > But I'm still not sure if it is worth it to add a new legacy specific > function to DSA drivers, unless there is a use case for such optional > teardown callback for the new bindings too. The new binding requires the use of dsa_unregister_switch() so this is where all the teardown and resource freeing should occur. I do not really think it is worth trying to fix the old binding and support code now, unless we want to migrate it somehow to using the code from net/dsa/dsa2.c. -- Florian
[PATCH net-next v3 6/6] net: dsa: bcm_sf2: Register our slave MDIO bus
Register a slave MDIO bus which allows us to divert problematic read/writes towards conflicting pseudo-PHY address (30). Do no longer rely on DSA's slave_mii_bus, but instead provide our own implementation which offers more flexibility as to what to do, and when to register it. We need to register it by the time we are able to get access to our memory mapped registers, which is not until drv->setup() time. In order to avoid forward declarations, we need to re-order the function bodies a bit. Reviewed-by: Andrew Lunn <and...@lunn.ch> Reviewed-by: Vivien Didelot <vivien.dide...@savoirfairelinux.com> Signed-off-by: Florian Fainelli <f.faine...@gmail.com> --- drivers/net/dsa/bcm_sf2.c | 215 +- drivers/net/dsa/bcm_sf2.h | 6 ++ 2 files changed, 140 insertions(+), 81 deletions(-) diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index 73df91bb0466..d6625783703f 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -836,6 +837,66 @@ static int bcm_sf2_sw_fdb_dump(struct dsa_switch *ds, int port, return 0; } +static int bcm_sf2_sw_indir_rw(struct bcm_sf2_priv *priv, int op, int addr, + int regnum, u16 val) +{ + 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 & 0x; +} + +static int bcm_sf2_sw_mdio_read(struct mii_bus *bus, int addr, int regnum) +{ + struct bcm_sf2_priv *priv = bus->priv; + + /* Intercept reads from Broadcom pseudo-PHY address, else, send +* them to our master MDIO bus controller +*/ + if (addr == BRCM_PSEUDO_PHY_ADDR && priv->indir_phy_mask & BIT(addr)) + return bcm_sf2_sw_indir_rw(priv, 1, addr, regnum, 0); + else + return mdiobus_read(priv->master_mii_bus, addr, regnum); +} + +static int bcm_sf2_sw_mdio_write(struct mii_bus *bus, int addr, int regnum, +u16 val) +{ + struct bcm_sf2_priv *priv = bus->priv; + + /* Intercept writes to the Broadcom pseudo-PHY address, else, +* send them to our master MDIO bus controller +*/ + if (addr == BRCM_PSEUDO_PHY_ADDR && priv->indir_phy_mask & BIT(addr)) + bcm_sf2_sw_indir_rw(priv, 0, addr, regnum, val); + else + mdiobus_write(priv->master_mii_bus, addr, regnum, val); + + return 0; +} + static irqreturn_t bcm_sf2_switch_0_isr(int irq, void *dev_id) { struct bcm_sf2_priv *priv = dev_id; @@ -932,6 +993,72 @@ static void bcm_sf2_identify_ports(struct bcm_sf2_priv *priv, } } +static int bcm_sf2_mdio_register(struct dsa_switch *ds) +{ + struct bcm_sf2_priv *priv = ds_to_priv(ds); + struct device_node *dn; + static int index; + int err; + + /* Find our integrated MDIO bus node */ + dn = of_find_compatible_node(NULL, NULL, "brcm,unimac-mdio"); + priv->master_mii_bus = of_mdio_find_bus(dn); + if (!priv->master_mii_bus) + return -EPROBE_DEFER; + + get_device(>master_mii_bus->dev); + priv->master_mii_dn = dn; + + priv->slave_mii_bus = devm_mdiobus_alloc(ds->dev); + if (!priv->slave_mii_bus) + return -ENOMEM; + + priv->slave_mii_bus->priv = priv; + priv->slave_mii_bus->name = "sf2 slave mii"; + priv->slave_mii_bus->read = bcm_sf2_sw_mdio_read; + priv->slave_mii_bus->write = bcm_sf2_sw_mdio_write; + snprintf(priv->slave_mii_bus->id, MII_BUS_ID_SIZE, "sf2-%d", +index++); + priv->slave_mii_bus->dev.of_node = dn; + + /* Include the pseudo-PHY address to divert reads towards our +* workaround. This is only required for 7445D0, since 7445E0 +* disconnects the internal switch pseudo-PHY such that we can use the +* regular SWITCH_MDIO master controller instead. +* +* Here we flag the pseudo PHY as needing special treatment and would +* otherwise make all other PHY read/writes go to the master MDIO bus +* controller that comes with this switch backed by the "
[PATCH net-next v3 5/6] net: dsa: Initialize CPU port ethtool ops per tree
Now that we can properly support multiple distinct trees in the system, using a global variable: dsa_cpu_port_ethtool_ops is getting clobbered as soon as the second switch tree gets probed, and we don't want that. We need to move this to be dynamically allocated, and since we can't really be comparing addresses anymore to determine first time initialization versus any other times, just move this to dsa.c and dsa2.c where the remainder of the dst/ds initialization happens. The operations teardown restores the master netdev's ethtool_ops to its original ethtool_ops pointer (typically within the Ethernet driver) Signed-off-by: Florian Fainelli <f.faine...@gmail.com> --- include/net/dsa.h | 1 + net/dsa/dsa.c | 43 +++ net/dsa/dsa2.c | 6 ++ net/dsa/dsa_priv.h | 4 net/dsa/slave.c| 10 -- 5 files changed, 54 insertions(+), 10 deletions(-) diff --git a/include/net/dsa.h b/include/net/dsa.h index cca7ef230742..20b3087ad193 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -116,6 +116,7 @@ struct dsa_switch_tree { * Original copy of the master netdev ethtool_ops */ struct ethtool_ops master_ethtool_ops; + const struct ethtool_ops *master_orig_ethtool_ops; /* * The switch and port to which the CPU is attached. diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c index ce3b942dce76..80f930d38df1 100644 --- a/net/dsa/dsa.c +++ b/net/dsa/dsa.c @@ -266,6 +266,43 @@ const struct dsa_device_ops *dsa_resolve_tag_protocol(int tag_protocol) return ops; } +int dsa_cpu_port_ethtool_setup(struct dsa_switch_tree *dst, + struct dsa_switch *ds) +{ + struct net_device *master; + struct ethtool_ops *cpu_ops; + + master = ds->dst->master_netdev; + if (ds->master_netdev) + master = ds->master_netdev; + + cpu_ops = devm_kzalloc(ds->dev, sizeof(*cpu_ops), GFP_KERNEL); + if (!cpu_ops) + return -ENOMEM; + + memcpy(>master_ethtool_ops, master->ethtool_ops, + sizeof(struct ethtool_ops)); + dst->master_orig_ethtool_ops = master->ethtool_ops; + memcpy(cpu_ops, >master_ethtool_ops, + sizeof(struct ethtool_ops)); + dsa_cpu_port_ethtool_init(cpu_ops); + master->ethtool_ops = cpu_ops; + + return 0; +} + +void dsa_cpu_port_ethtool_restore(struct dsa_switch_tree *dst, + struct dsa_switch *ds) +{ + struct net_device *master; + + master = ds->dst->master_netdev; + if (ds->master_netdev) + master = ds->master_netdev; + + master->ethtool_ops = dst->master_orig_ethtool_ops; +} + static int dsa_switch_setup_one(struct dsa_switch *ds, struct device *parent) { struct dsa_switch_driver *drv = ds->drv; @@ -379,6 +416,10 @@ static int dsa_switch_setup_one(struct dsa_switch *ds, struct device *parent) ret = 0; } + ret = dsa_cpu_port_ethtool_setup(dst, ds); + if (ret) + return ret; + #ifdef CONFIG_NET_DSA_HWMON /* If the switch provides a temperature sensor, * register with hardware monitoring subsystem. @@ -963,6 +1004,8 @@ static void dsa_remove_dst(struct dsa_switch_tree *dst) dsa_switch_destroy(ds); } + dsa_cpu_port_ethtool_restore(dst, dst->ds[0]); + dev_put(dst->master_netdev); } diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c index 4e0f3c268103..7ffee268a526 100644 --- a/net/dsa/dsa2.c +++ b/net/dsa/dsa2.c @@ -394,6 +394,10 @@ static int dsa_dst_apply(struct dsa_switch_tree *dst) return err; } + err = dsa_cpu_port_ethtool_setup(dst, dst->ds[0]); + if (err) + return err; + /* If we use a tagging format that doesn't have an ethertype * field, make sure that all packets from this point on get * sent to the tag format's receive function. @@ -429,6 +433,8 @@ static void dsa_dst_unapply(struct dsa_switch_tree *dst) dsa_ds_unapply(dst, ds); } + dsa_cpu_port_ethtool_restore(dst, dst->ds[0]); + pr_info("DSA: tree %d unapplied\n", dst->tree); dst->applied = false; } diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h index 106a9f067f94..9c920c27f22c 100644 --- a/net/dsa/dsa_priv.h +++ b/net/dsa/dsa_priv.h @@ -54,6 +54,10 @@ int dsa_cpu_dsa_setup(struct dsa_switch *ds, struct device *dev, struct device_node *port_dn, int port); void dsa_cpu_dsa_destroy(struct device_node *port_dn); const struct dsa_device_ops *dsa_resolve_tag_protocol(int tag_protocol); +int dsa_cpu_port_ethtool_setup(struct dsa_switch_tree *dst, + struct dsa_switch *ds); +void dsa_cpu_port_ethtool_restore(struct dsa_switch_tree
[PATCH net-next v3 0/6] net: dsa: misc improvements
Hi all, This patch series builds on top of Andrew's "New DSA bind, switches as devices" patch set and does the following: - add a few helper functions/goodies for net/dsa/dsa2.c to be as close as possible from net/dsa/dsa.c in terms of what drivers can expect, in particular the slave MDIO bus and the enabled_port_mask and phy_mii_mask - fix the CPU port ethtools ops to work in a multiple tree setup since we can no longer assume a single tree is supported - make the bcm_sf2 driver register its own MDIO bus, yet assign it to ds->slave_mii_bus for everything to work in net/dsa/slave.c wrt. PHY probing, this is a tad cleaner than what we have now Changes in v2: Most of the previous patches have been dropped to just keep the relevant ones now. Changes in v3: - split the addition of the slave MII bus as a separate patch - properly unwind all operations at the right place and right time (ethtool ops, slave MDIO bus - fixed a few typos here and there Florian Fainelli (6): net: dsa: Provide unique DSA slave MII bus names net: dsa: Initialize ds->enabled_port_mask and ds->phys_mii_mask net: dsa: Provide a slave MII bus if needed net: dsa: Add initialization helper for CPU port ethtool_ops net: dsa: Initialize CPU port ethtool ops per tree net: dsa: bcm_sf2: Register our slave MDIO bus drivers/net/dsa/bcm_sf2.c | 215 +- drivers/net/dsa/bcm_sf2.h | 6 ++ include/net/dsa.h | 1 + net/dsa/dsa.c | 41 + net/dsa/dsa2.c| 36 net/dsa/dsa_priv.h| 5 ++ net/dsa/slave.c | 25 ++ 7 files changed, 232 insertions(+), 97 deletions(-) -- 2.7.4
[PATCH net-next v3 2/6] net: dsa: Initialize ds->enabled_port_mask and ds->phys_mii_mask
Some drivers rely on these two bitmasks to contain the correct values for them to successfully probe and initialize at drv->setup() time, calculate correct values to put in both masks as early as possible in dsa_get_ports_dn(). Signed-off-by: Florian Fainelli <f.faine...@gmail.com> --- net/dsa/dsa2.c | 15 +++ 1 file changed, 15 insertions(+) diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c index 80dfe08db825..921a36fd139d 100644 --- a/net/dsa/dsa2.c +++ b/net/dsa/dsa2.c @@ -283,6 +283,7 @@ static void dsa_user_port_unapply(struct device_node *port, u32 index, if (ds->ports[index].netdev) { dsa_slave_destroy(ds->ports[index].netdev); ds->ports[index].netdev = NULL; + ds->enabled_port_mask &= ~(1 << index); } } @@ -292,6 +293,13 @@ static int dsa_ds_apply(struct dsa_switch_tree *dst, struct dsa_switch *ds) u32 index; int err; + /* Initialize ds->phys_mii_mask before registering the slave MDIO bus +* driver and before drv->setup() has run, since the switch drivers and +* the slave MDIO bus driver rely on these values for probing PHY +* devices or not +*/ + ds->phys_mii_mask = ds->enabled_port_mask; + err = ds->drv->setup(ds); if (err < 0) return err; @@ -511,6 +519,13 @@ static int dsa_parse_ports_dn(struct device_node *ports, struct dsa_switch *ds) return -EINVAL; ds->ports[reg].dn = port; + + /* Initialize enabled_port_mask now for drv->setup() +* to have access to a correct value, just like what +* net/dsa/dsa.c::dsa_switch_setup_one does. +*/ + if (!dsa_port_is_cpu(port)) + ds->enabled_port_mask |= 1 << reg; } return 0; -- 2.7.4
[PATCH net-next v3 1/6] net: dsa: Provide unique DSA slave MII bus names
In case we have multiples trees and switches with the same index, we need to add another discriminating id: the switch tree. Reviewed-by: Andrew Lunn <and...@lunn.ch> Reviewed-by: Vivien Didelot <vivien.dide...@savoirfairelinux.com> Signed-off-by: Florian Fainelli <f.faine...@gmail.com> --- net/dsa/slave.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 15a492261895..a51dfedf0014 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -49,7 +49,8 @@ void dsa_slave_mii_bus_init(struct dsa_switch *ds) ds->slave_mii_bus->name = "dsa slave smi"; ds->slave_mii_bus->read = dsa_slave_phy_read; ds->slave_mii_bus->write = dsa_slave_phy_write; - snprintf(ds->slave_mii_bus->id, MII_BUS_ID_SIZE, "dsa-%d", ds->index); + snprintf(ds->slave_mii_bus->id, MII_BUS_ID_SIZE, "dsa-%d.%d", +ds->dst->tree, ds->index); ds->slave_mii_bus->parent = ds->dev; ds->slave_mii_bus->phy_mask = ~ds->phys_mii_mask; } -- 2.7.4
[PATCH net-next v3 3/6] net: dsa: Provide a slave MII bus if needed
Mimic what net/dsa/dsa.c does and provide a slave MII bus by default which will be created if the driver implements a phy_read method. Signed-off-by: Florian Fainelli <f.faine...@gmail.com> --- net/dsa/dsa2.c | 15 +++ 1 file changed, 15 insertions(+) diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c index 921a36fd139d..4e0f3c268103 100644 --- a/net/dsa/dsa2.c +++ b/net/dsa/dsa2.c @@ -312,6 +312,18 @@ static int dsa_ds_apply(struct dsa_switch_tree *dst, struct dsa_switch *ds) if (err < 0) return err; + if (!ds->slave_mii_bus && ds->drv->phy_read) { + ds->slave_mii_bus = devm_mdiobus_alloc(ds->dev); + if (!ds->slave_mii_bus) + return -ENOMEM; + + dsa_slave_mii_bus_init(ds); + + err = mdiobus_register(ds->slave_mii_bus); + if (err < 0) + return err; + } + for (index = 0; index < DSA_MAX_PORTS; index++) { port = ds->ports[index].dn; if (!port) @@ -361,6 +373,9 @@ static void dsa_ds_unapply(struct dsa_switch_tree *dst, struct dsa_switch *ds) dsa_user_port_unapply(port, index, ds); } + + if (ds->slave_mii_bus && ds->drv->phy_read) + mdiobus_unregister(ds->slave_mii_bus); } static int dsa_dst_apply(struct dsa_switch_tree *dst) -- 2.7.4
[PATCH net-next v3 4/6] net: dsa: Add initialization helper for CPU port ethtool_ops
Add a helper function: dsa_cpu_port_ethtool_init() which initializes a custom ethtool_ops structure with custom DSA ethtool operations for CPU ports. This is a preliminary change to move the initialization outside of net/dsa/slave.c. Signed-off-by: Florian Fainelli <f.faine...@gmail.com> --- net/dsa/dsa_priv.h | 1 + net/dsa/slave.c| 14 -- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h index b42f1a5f95f3..106a9f067f94 100644 --- a/net/dsa/dsa_priv.h +++ b/net/dsa/dsa_priv.h @@ -58,6 +58,7 @@ const struct dsa_device_ops *dsa_resolve_tag_protocol(int tag_protocol); /* slave.c */ extern const struct dsa_device_ops notag_netdev_ops; void dsa_slave_mii_bus_init(struct dsa_switch *ds); +void dsa_cpu_port_ethtool_init(struct ethtool_ops *ops); int dsa_slave_create(struct dsa_switch *ds, struct device *parent, int port, const char *name); void dsa_slave_destroy(struct net_device *slave_dev); diff --git a/net/dsa/slave.c b/net/dsa/slave.c index a51dfedf0014..8d159932e082 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -865,6 +865,13 @@ static void dsa_slave_poll_controller(struct net_device *dev) } #endif +void dsa_cpu_port_ethtool_init(struct ethtool_ops *ops) +{ + ops->get_sset_count = dsa_cpu_port_get_sset_count; + ops->get_ethtool_stats = dsa_cpu_port_get_ethtool_stats; + ops->get_strings = dsa_cpu_port_get_strings; +} + static const struct ethtool_ops dsa_slave_ethtool_ops = { .get_settings = dsa_slave_get_settings, .set_settings = dsa_slave_set_settings, @@ -1124,12 +1131,7 @@ int dsa_slave_create(struct dsa_switch *ds, struct device *parent, sizeof(struct ethtool_ops)); memcpy(_cpu_port_ethtool_ops, >master_ethtool_ops, sizeof(struct ethtool_ops)); - dsa_cpu_port_ethtool_ops.get_sset_count = - dsa_cpu_port_get_sset_count; - dsa_cpu_port_ethtool_ops.get_ethtool_stats = - dsa_cpu_port_get_ethtool_stats; - dsa_cpu_port_ethtool_ops.get_strings = - dsa_cpu_port_get_strings; + dsa_cpu_port_ethtool_init(_cpu_port_ethtool_ops); master->ethtool_ops = _cpu_port_ethtool_ops; } eth_hw_addr_inherit(slave_dev, master); -- 2.7.4
[PATCH net-next v2 1/3] bgmac: Bind net_device with backing device structure
In preparation for allowing different helpers to be utilized against network devices created by the bgmac driver, make sure that we bind the net_device with core->dev. Signed-off-by: Florian Fainelli <f.faine...@gmail.com> --- drivers/net/ethernet/broadcom/bgmac.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/broadcom/bgmac.c b/drivers/net/ethernet/broadcom/bgmac.c index ee5f431ab32a..156fa6323745 100644 --- a/drivers/net/ethernet/broadcom/bgmac.c +++ b/drivers/net/ethernet/broadcom/bgmac.c @@ -1588,6 +1588,7 @@ static int bgmac_probe(struct bcma_device *core) bgmac->net_dev = net_dev; bgmac->core = core; bcma_set_drvdata(core, bgmac); + SET_NETDEV_DEV(net_dev, >dev); /* Defaults */ memcpy(bgmac->net_dev->dev_addr, mac, ETH_ALEN); -- 2.7.4
[PATCH net-next v2 2/3] bgmac: Add support for ethtool statistics
Read the statistics from the BGMAC's builtin MAC and return them to user-space using the standard ethtool helpers. Signed-off-by: Florian Fainelli <f.faine...@gmail.com> --- Changes in v2: - use strlcpy() - properly fix the latching of the hi/lo reads - remove redundant cast drivers/net/ethernet/broadcom/bgmac.c | 124 ++ drivers/net/ethernet/broadcom/bgmac.h | 4 +- 2 files changed, 126 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bgmac.c b/drivers/net/ethernet/broadcom/bgmac.c index 156fa6323745..133bf64c7a8b 100644 --- a/drivers/net/ethernet/broadcom/bgmac.c +++ b/drivers/net/ethernet/broadcom/bgmac.c @@ -1382,6 +1382,127 @@ static const struct net_device_ops bgmac_netdev_ops = { * ethtool_ops **/ +struct bgmac_stat { + u8 size; + u32 offset; + const char *name; +}; + +static struct bgmac_stat bgmac_get_strings_stats[] = { + { 8, BGMAC_TX_GOOD_OCTETS, "tx_good_octets" }, + { 4, BGMAC_TX_GOOD_PKTS, "tx_good" }, + { 8, BGMAC_TX_OCTETS, "tx_octets" }, + { 4, BGMAC_TX_PKTS, "tx_pkts" }, + { 4, BGMAC_TX_BROADCAST_PKTS, "tx_broadcast" }, + { 4, BGMAC_TX_MULTICAST_PKTS, "tx_multicast" }, + { 4, BGMAC_TX_LEN_64, "tx_64" }, + { 4, BGMAC_TX_LEN_65_TO_127, "tx_65_127" }, + { 4, BGMAC_TX_LEN_128_TO_255, "tx_128_255" }, + { 4, BGMAC_TX_LEN_256_TO_511, "tx_256_511" }, + { 4, BGMAC_TX_LEN_512_TO_1023, "tx_512_1023" }, + { 4, BGMAC_TX_LEN_1024_TO_1522, "tx_1024_1522" }, + { 4, BGMAC_TX_LEN_1523_TO_2047, "tx_1523_2047" }, + { 4, BGMAC_TX_LEN_2048_TO_4095, "tx_2048_4095" }, + { 4, BGMAC_TX_LEN_4096_TO_8191, "tx_4096_8191" }, + { 4, BGMAC_TX_LEN_8192_TO_MAX, "tx_8192_max" }, + { 4, BGMAC_TX_JABBER_PKTS, "tx_jabber" }, + { 4, BGMAC_TX_OVERSIZE_PKTS, "tx_oversize" }, + { 4, BGMAC_TX_FRAGMENT_PKTS, "tx_fragment" }, + { 4, BGMAC_TX_UNDERRUNS, "tx_underruns" }, + { 4, BGMAC_TX_TOTAL_COLS, "tx_total_cols" }, + { 4, BGMAC_TX_SINGLE_COLS, "tx_single_cols" }, + { 4, BGMAC_TX_MULTIPLE_COLS, "tx_multiple_cols" }, + { 4, BGMAC_TX_EXCESSIVE_COLS, "tx_excessive_cols" }, + { 4, BGMAC_TX_LATE_COLS, "tx_late_cols" }, + { 4, BGMAC_TX_DEFERED, "tx_defered" }, + { 4, BGMAC_TX_CARRIER_LOST, "tx_carrier_lost" }, + { 4, BGMAC_TX_PAUSE_PKTS, "tx_pause" }, + { 4, BGMAC_TX_UNI_PKTS, "tx_unicast" }, + { 4, BGMAC_TX_Q0_PKTS, "tx_q0" }, + { 8, BGMAC_TX_Q0_OCTETS, "tx_q0_octets" }, + { 4, BGMAC_TX_Q1_PKTS, "tx_q1" }, + { 8, BGMAC_TX_Q1_OCTETS, "tx_q1_octets" }, + { 4, BGMAC_TX_Q2_PKTS, "tx_q2" }, + { 8, BGMAC_TX_Q2_OCTETS, "tx_q2_octets" }, + { 4, BGMAC_TX_Q3_PKTS, "tx_q3" }, + { 8, BGMAC_TX_Q3_OCTETS, "tx_q3_octets" }, + { 8, BGMAC_RX_GOOD_OCTETS, "rx_good_octets" }, + { 4, BGMAC_RX_GOOD_PKTS, "rx_good" }, + { 8, BGMAC_RX_OCTETS, "rx_octets" }, + { 4, BGMAC_RX_PKTS, "rx_pkts" }, + { 4, BGMAC_RX_BROADCAST_PKTS, "rx_broadcast" }, + { 4, BGMAC_RX_MULTICAST_PKTS, "rx_multicast" }, + { 4, BGMAC_RX_LEN_64, "rx_64" }, + { 4, BGMAC_RX_LEN_65_TO_127, "rx_65_127" }, + { 4, BGMAC_RX_LEN_128_TO_255, "rx_128_255" }, + { 4, BGMAC_RX_LEN_256_TO_511, "rx_256_511" }, + { 4, BGMAC_RX_LEN_512_TO_1023, "rx_512_1023" }, + { 4, BGMAC_RX_LEN_1024_TO_1522, "rx_1024_1522" }, + { 4, BGMAC_RX_LEN_1523_TO_2047, "rx_1523_2047" }, + { 4, BGMAC_RX_LEN_2048_TO_4095, "rx_2048_4095" }, + { 4, BGMAC_RX_LEN_4096_TO_8191, "rx_4096_8191" }, + { 4, BGMAC_RX_LEN_8192_TO_MAX, "rx_8192_max" }, + { 4, BGMAC_RX_JABBER_PKTS, "rx_jabber" }, + { 4, BGMAC_RX_OVERSIZE_PKTS, "rx_oversize" }, + { 4, BGMAC_RX_FRAGMENT_PKTS, "rx_fragment" }, + { 4, BGMAC_RX_MISSED_PKTS, "rx_missed" }, + { 4, BGMAC_RX_CRC_ALIGN_ERRS, "rx_crc_align" }, + { 4, BGMAC_RX_UNDERSIZE, "rx_undersize" }, + { 4, BGMAC_RX_CRC_ERRS, "rx_crc" }, + { 4, BGMAC_RX_ALIGN_ERRS, "rx_align" }, + { 4, BGMAC_RX_SYMBOL_ERRS, "rx_symbol" }, + { 4, BGMAC_RX_PAUSE_PKTS, "rx_pause" }, + { 4, BGMAC_RX_NONPAUSE_PKTS, "rx_nonpause" }, + { 4, BGMAC_RX_SACHANGES, "
[PATCH net-next v2 0/3] net: bgmac: Misc improvements
Hi David, Rafal, Hauke, Felix, This patch series add minor changes to the bgmac driver: - properly bind net_device with its backing device structure such that we can locate the device using common helper functions - add support for ethtool statistics reading the HW MIB counters which is useful for debugging - add netdev statistics throughout the TX/RX path to know what is going on Thanks Florian Fainelli (3): bgmac: Bind net_device with backing device structure bgmac: Add support for ethtool statistics bgmac: Maintain some netdev statistics drivers/net/ethernet/broadcom/bgmac.c | 135 ++ drivers/net/ethernet/broadcom/bgmac.h | 4 +- 2 files changed, 137 insertions(+), 2 deletions(-) -- 2.7.4
[PATCH net-next v2 3/3] bgmac: Maintain some netdev statistics
Add a few netdev statistics to report transmitted and received bytes and packets and a few obvious errors. Signed-off-by: Florian Fainelli <f.faine...@gmail.com> --- drivers/net/ethernet/broadcom/bgmac.c | 10 ++ 1 file changed, 10 insertions(+) diff --git a/drivers/net/ethernet/broadcom/bgmac.c b/drivers/net/ethernet/broadcom/bgmac.c index 133bf64c7a8b..0ee34cc96bc9 100644 --- a/drivers/net/ethernet/broadcom/bgmac.c +++ b/drivers/net/ethernet/broadcom/bgmac.c @@ -246,6 +246,8 @@ err_dma_head: err_drop: dev_kfree_skb(skb); + net_dev->stats.tx_dropped++; + net_dev->stats.tx_errors++; return NETDEV_TX_OK; } @@ -284,6 +286,8 @@ static void bgmac_dma_tx_free(struct bgmac *bgmac, struct bgmac_dma_ring *ring) DMA_TO_DEVICE); if (slot->skb) { + bgmac->net_dev->stats.tx_bytes += slot->skb->len; + bgmac->net_dev->stats.tx_packets++; bytes_compl += slot->skb->len; pkts_compl++; @@ -464,6 +468,7 @@ static int bgmac_dma_rx_read(struct bgmac *bgmac, struct bgmac_dma_ring *ring, bgmac_err(bgmac, "Found poisoned packet at slot %d, DMA issue!\n", ring->start); put_page(virt_to_head_page(buf)); + bgmac->net_dev->stats.rx_errors++; break; } @@ -471,6 +476,8 @@ static int bgmac_dma_rx_read(struct bgmac *bgmac, struct bgmac_dma_ring *ring, bgmac_err(bgmac, "Found oversized packet at slot %d, DMA issue!\n", ring->start); put_page(virt_to_head_page(buf)); + bgmac->net_dev->stats.rx_length_errors++; + bgmac->net_dev->stats.rx_errors++; break; } @@ -481,6 +488,7 @@ static int bgmac_dma_rx_read(struct bgmac *bgmac, struct bgmac_dma_ring *ring, if (unlikely(!skb)) { bgmac_err(bgmac, "build_skb failed\n"); put_page(virt_to_head_page(buf)); + bgmac->net_dev->stats.rx_errors++; break; } skb_put(skb, BGMAC_RX_FRAME_OFFSET + @@ -490,6 +498,8 @@ static int bgmac_dma_rx_read(struct bgmac *bgmac, struct bgmac_dma_ring *ring, skb_checksum_none_assert(skb); skb->protocol = eth_type_trans(skb, bgmac->net_dev); + bgmac->net_dev->stats.rx_bytes += len; + bgmac->net_dev->stats.rx_packets++; napi_gro_receive(>napi, skb); handled++; } while (0); -- 2.7.4
Re: [PATCH net-next v3 5/6] net: dsa: Initialize CPU port ethtool ops per tree
On 06/07/2016 02:51 PM, Andrew Lunn wrote: >> +int dsa_cpu_port_ethtool_setup(struct dsa_switch_tree *dst, >> + struct dsa_switch *ds) >> +{ >> +struct net_device *master; >> +struct ethtool_ops *cpu_ops; >> + >> +master = ds->dst->master_netdev; > > You pass in dst as a parameter, and then don't use it! I do use it here: memcpy(>master_ethtool_ops, master->ethtool_ops, sizeof(struct ethtool_ops)); > >> +void dsa_cpu_port_ethtool_restore(struct dsa_switch_tree *dst, >> + struct dsa_switch *ds) >> +{ >> +struct net_device *master; >> + >> +master = ds->dst->master_netdev; > > Same here. and here: master->ethtool_ops = dst->master_orig_ethtool_ops; I sure could simplify that and use ds->dst instead if you find it more elegant, works for me. -- Florian
Re: [PATCH v4 7/7] phy: Add Northstar2 PCI Phy support
On 06/06/2016 05:41 AM, Pramod Kumar wrote: > Add PCI Phy support for Broadcom Northstar2 SoCs. This driver uses the > interface from the iproc mdio mux driver to enable the devices > respective phys. > > Reviewed-by: Andrew Lunn> Signed-off-by: Jon Mason > Signed-off-by: Pramod Kumar > --- > drivers/phy/Kconfig| 8 +++ > drivers/phy/Makefile | 2 +- > drivers/phy/phy-bcm-ns2-pcie.c | 115 > + > 3 files changed, 124 insertions(+), 1 deletion(-) > create mode 100644 drivers/phy/phy-bcm-ns2-pcie.c > > diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig > index b869b98..01fb93b 100644 > --- a/drivers/phy/Kconfig > +++ b/drivers/phy/Kconfig > @@ -434,4 +434,12 @@ config PHY_CYGNUS_PCIE > > source "drivers/phy/tegra/Kconfig" > > +config PHY_NS2_PCIE > + tristate "Broadcom Northstar2 PCIe PHY driver" > + depends on OF && MDIO_BUS_MUX_BCM_IPROC > + select GENERIC_PHY > + default ARCH_BCM_IPROC Are not you missing a dependency on PHYLIB too to provide mdio_module_register() etc. (at least make it build)? -- Florian
Re: [PATCH v4 3/7] binding: mdio-mux: Add DT binding doc for Broadcom MDIO bus multiplexer
On 06/06/2016 05:41 AM, Pramod Kumar wrote: > Add DT binding doc for Broadcom MDIO bus multiplexer driver. > > Reviewed-by: Andrew Lunn <and...@lunn.ch> > Signed-off-by: Pramod Kumar <pramod.ku...@broadcom.com> Reviewed-by: Florian Fainelli <f.faine...@gmail.com> > +for example: > + mdio_mux_iproc: mdio-mux@6602023c { I think Rob wanted you to drop the underscores here in favor of dashes, there are more below, not critical imho. > + compatible = "brcm,mdio-mux-iproc"; > + reg = <0x6602023c 0x14>; > + #address-cells = <1>; > + #size-cells = <0>; > + > + mdio@0 { > + reg = <0x0>; > + #address-cells = <1>; > + #size-cells = <0>; > + > + pci_phy0: pci-phy@0 { -- Florian
Re: [PATCH v4 4/7] dt: mdio-mux: Add mdio multiplexer driver node
On 06/06/2016 05:41 AM, Pramod Kumar wrote: > Add integrated MDIO multiplexer driver node which contains > two mux PCIe bus and one ethernet bus along with phys > lying on these bus. > > Signed-off-by: Pramod Kumar> --- > + mdio_mux_iproc: mdio-mux@6602023c { > + compatible = "brcm,mdio-mux-iproc"; > + reg = <0x6602023c 0x14>; > + #address-cells = <1>; > + #size-cells = <0>; > + > + mdio@0 { > + reg = <0x0>; > + #address-cells = <1>; > + #size-cells = <0>; > + > + pci_phy0: pci-phy@0 { > + compatible = "brcm,ns2-pcie-phy"; > + reg = <0x0>; > + #phy-cells = <0>; > + }; > + }; > + > + mdio@7 { > + reg = <0x7>; > + #address-cells = <1>; > + #size-cells = <0>; > + > + pci_phy1: pci-phy@0 { > + compatible = "brcm,ns2-pcie-phy"; > + reg = <0x0>; > + #phy-cells = <0>; > + }; Are these two PHYs always available in the NS2 SoC, or does that depend on interfaces exposed at the board level? Should not they be flagged with a disabled status property by default and enabled in their respective board files? -- Florian
Re: [PATCH v4 1/7] mdio: mux: Enhanced MDIO mux framework for integrated multiplexers
On 06/06/2016 05:41 AM, Pramod Kumar wrote: > An integrated multiplexer uses same address space for > "muxed bus selection" and "generation of mdio transaction" > hence its good to register parent bus from mux driver. > > Hence added a mechanism where mux driver could register a > parent bus and pass it down to framework via mdio_mux_init api. > > Signed-off-by: Pramod Kumar <pramod.ku...@broadcom.com> Reviewed-by: Florian Fainelli <f.faine...@gmail.com> > diff --git a/include/linux/mdio-mux.h b/include/linux/mdio-mux.h > index a243dbb..61f5b21 100644 > --- a/include/linux/mdio-mux.h > +++ b/include/linux/mdio-mux.h > @@ -10,11 +10,13 @@ > #ifndef __LINUX_MDIO_MUX_H > #define __LINUX_MDIO_MUX_H > #include > +#include You could have added just a forward declaration, this is a pointer to the structure so you don't need the compiler to have full knowledge of the storage type. Not a biggie. -- Florian
Re: [PATCH 1/5] ethernet: add sun8i-emac driver
On 06/03/2016 02:56 AM, LABBE Corentin wrote: > This patch add support for sun8i-emac ethernet MAC hardware. > It could be found in Allwinner H3/A83T/A64 SoCs. > > It supports 10/100/1000 Mbit/s speed with half/full duplex. > It can use an internal PHY (MII 10/100) or an external PHY > via RGMII/RMII. > > Signed-off-by: LABBE Corentin> --- [snip] > + > +struct ethtool_str { > + char name[ETH_GSTRING_LEN]; You might as well drop the encapsulating structure and just use an array of strings? > +}; > + [snip] > + > +/* The datasheet said that each descriptor can transfers up to 4096bytes > + * But latter, a register documentation reduce that value to 2048 > + * Anyway using 2048 cause strange behaviours and even BSP driver use 2047 > + */ > +#define DESC_BUF_MAX 2044 > +#if (DESC_BUF_MAX < (ETH_FRAME_LEN + 4)) > +#error "DESC_BUF_MAX must be set at minimum to ETH_FRAME_LEN + 4" > +#endif You can probably drop that, it would not make much sense to enable fragments and a buffer size smaller than ETH_FRAME_LEN + ETH_FCS_LEN anyway. > + > +/* MAGIC value for knowing if a descriptor is available or not */ > +#define DCLEAN (BIT(16) | BIT(14) | BIT(12) | BIT(10) | BIT(9)) > + > +/* Structure of DMA descriptor used by the hardware */ > +struct dma_desc { > + u32 status; /* status of the descriptor */ > + u32 st; /* Information on the frame */ > + u32 buf_addr; /* physical address of the frame data */ > + u32 next; /* physical address of next dma_desc */ > +} __packed __aligned(4); This has been noticed in other emails, no need for the __packed here, they are all naturally aligned. > + > +/* Benched on OPIPC with 100M, setting more than 256 does not give any > + * perf boost > + */ > +static int nbdesc_tx = 256; > +module_param(nbdesc_tx, int, S_IRUGO | S_IWUSR); > +MODULE_PARM_DESC(nbdesc_tx, "Number of descriptors in the TX list"); > +static int nbdesc_rx = 128; > +module_param(nbdesc_rx, int, S_IRUGO | S_IWUSR); > +MODULE_PARM_DESC(nbdesc_rx, "Number of descriptors in the RX list"); This needs to be statically defined to begin driver operation with, and then implement the ethtool operations to re-size the rings would you want that. [snip] > +/* Return the number of contiguous free descriptors > + * starting from tx_slot > + */ > +static int rb_tx_numfreedesc(struct net_device *ndev) > +{ > + struct sun8i_emac_priv *priv = netdev_priv(ndev); > + > + if (priv->tx_slot < priv->tx_dirty) > + return priv->tx_dirty - priv->tx_slot; Does this work with if tx_dirty wraps around? > + > + return (nbdesc_tx - priv->tx_slot) + priv->tx_dirty; > +} > + > +/* Allocate a skb in a DMA descriptor > + * > + * @i index of slot to fill > +*/ > +static int sun8i_emac_rx_sk(struct net_device *ndev, int i) > +{ > + struct sun8i_emac_priv *priv = netdev_priv(ndev); > + struct dma_desc *ddesc; > + struct sk_buff *sk; The networking stack typically refers to "sk" as socket and skb as socket buffers. > + > + ddesc = priv->dd_rx + i; > + > + ddesc->st = 0; > + > + sk = netdev_alloc_skb_ip_align(ndev, DESC_BUF_MAX); > + if (!sk) > + return -ENOMEM; > + > + /* should not happen */ > + if (unlikely(priv->rx_sk[i])) > + dev_warn(priv->dev, "BUG: Leaking a skbuff\n"); > + > + priv->rx_sk[i] = sk; > + > + ddesc->buf_addr = dma_map_single(priv->dev, sk->data, > + DESC_BUF_MAX, DMA_FROM_DEVICE); > + if (dma_mapping_error(priv->dev, ddesc->buf_addr)) { > + dev_err(priv->dev, "ERROR: Cannot dma_map RX buffer\n"); > + dev_kfree_skb(sk); > + return -EFAULT; > + } > + ddesc->st |= DESC_BUF_MAX; > + ddesc->status = BIT(31); You are missing a lightweight barrier here to ensure there is no re-ordering done by the compiler in how you write to the descriptors in DRAM, even though they are allocated from dma_alloc_coherent(). [snip] > +static void sun8i_emac_set_link_mode(struct sun8i_emac_priv *priv) > +{ > + u32 v; > + > + v = readl(priv->base + SUN8I_EMAC_BASIC_CTL0); > + > + if (priv->duplex) > + v |= BIT(0); > + else > + v &= ~BIT(0); > + > + v &= ~0x0C; > + switch (priv->speed) { > + case 1000: > + break; > + case 100: > + v |= BIT(2); > + v |= BIT(3); > + break; > + case 10: > + v |= BIT(3); > + break; > + } Proper defines for all of these bits and masks? > + > + writel(v, priv->base + SUN8I_EMAC_BASIC_CTL0); > +} > + > +static void sun8i_emac_flow_ctrl(struct sun8i_emac_priv *priv, int duplex, > + int fc, int pause) > +{ > + u32 flow = 0; pause is unused (outside of printing it) here > + > + netif_dbg(priv, link, priv->ndev, "%s %d %d %d\n", __func__, > + duplex, fc, pause); > + > + flow = readl(priv->base +
Re: [PATCH v4 5/7] net: mdio-mux: Add MDIO mux driver for iProc SoCs
On 06/06/2016 05:41 AM, Pramod Kumar wrote: > iProc based SoCs supports the integrated mdio multiplexer which > has the bus selection as well as mdio transaction generation logic > inside. > > This multiplexer has child buses for PCIe, SATA, USB and ETH. These > buses could be internal or external to SOC where PHYs are attached. > These buses could use C-45 or C-22 mdio transaction. > > Signed-off-by: Pramod Kumar <pramod.ku...@broadcom.com> Reviewed-by: Florian Fainelli <f.faine...@gmail.com> -- Florian
Re: [PATCH net-next 2/9] net: dsa: Add support for parsing the old binding
On 06/05/2016 08:19 PM, Andrew Lunn wrote: >> How much support do we want to have for the old binding for in tree >> platforms? Is the plan to migrate them all to the new binding? > > I think there are three cases to consider. > > 1) There are some old boards using setup.c files which have a platform >device, platform data, etc. I've never used DSA in this way, and it >could be all the recent additions have broken this. We might want >to test this, and if it is in fact broken, and has been for a >while, it indicates nobody uses those boards any more. We might >suggest removing them. Even if they do work, i doubt anybody is >interested in converting them to device tree. So we might have to >keep the platform data support around. We had a report a while ago of breakage, which got addressed and fixed upstream, so if it breaks again, it will get fixed again. > > 2) In tree devices using the DT binding. We can update them all to the >new binding. The kirkwood boards don't have a u-boot which is DT >capable. Some of the armada boards do have a DT capable uboot, but >all these boards have been added by the community, so i suspect >they are not flashed never to be changed again. > > 3) Out of tree devices using the DT binding. As far as i can see, >there is no in three board actually using the Broadcom SF2 driver >and its odd binding. However from talking to you, i know there are >devices out in the wild using this binding, and their DT blob is >fixed, never to be changed again. The concept of an "in-tree" board does not make much sense once the bootloader provides a blob to the kernel, and synchronizing the Device Tree sources with what a bootloader provides is just a pain with no reward as long as the binding remains standard and works. > > It actually seems odd to me that we have a nice new binding and an > implement which is reasonably clean, and we want to add code to > support a legacy binding for an out of tree board. > > I need to think on this for a while. However, i don't see the old code > and binding going away anytime soon. It will take a few cycles to > determine if the old platform device/platform data still works, and to > remove the old boards if not. We can update the in tree devices to the > new binding, but we should keep the old binding a while to aid the > transition. I do not see the need for platform data going away actually, there are tons of devices out there that are not supported using Device Tree, yet feature Ethernet switches that could easily be supported would we want to add support for that, and clearly an answer along the lines of let's add Device Tree support for these platforms is not going to fly. > > I'm tempted to say you should keep using the old code to support your > out of tree devices. You should define a new binding for SF2 which > conforms to the device tree binding document which just got accepted, > and add it to SF 2 alongside the legacy binding. And it would be great > if you could go the last step and actually add a boards device tree > file using it. I suppose I could do that. > > I'm hesitant to add legacy binding support for SF2 to the new DSA2 > code. We should try to keep it free of cruft, and set a good example > for others to follow when they bring along there new drivers. What if this code was moved to the bcm_sf2.c where it matters and there is just the bottom part of dsa_register_switch() exposed instead? -- Florian
Re: [PATCH 1/5] ethernet: add sun8i-emac driver
Le 09/06/2016 02:44, LABBE Corentin a écrit : > Hello > > I agree to all your comments, but for some I have additionnal questions > > On Mon, Jun 06, 2016 at 11:25:15AM -0700, Florian Fainelli wrote: >> On 06/03/2016 02:56 AM, LABBE Corentin wrote: >> >> [snip] >> >>> + >>> +/* The datasheet said that each descriptor can transfers up to 4096bytes >>> + * But latter, a register documentation reduce that value to 2048 >>> + * Anyway using 2048 cause strange behaviours and even BSP driver use 2047 >>> + */ >>> +#define DESC_BUF_MAX 2044 >>> +#if (DESC_BUF_MAX < (ETH_FRAME_LEN + 4)) >>> +#error "DESC_BUF_MAX must be set at minimum to ETH_FRAME_LEN + 4" >>> +#endif >> >> You can probably drop that, it would not make much sense to enable >> fragments and a buffer size smaller than ETH_FRAME_LEN + ETH_FCS_LEN anyway. >> > > I has added this test for preventing someone who want to "optimize" > DESC_BUF_MAX to doing mistake. > But I agree that it is of low use. It's actually dangerous, and if you don't make sure that the value is properly rounded to whatever the DMA controller's alignment should be, performance could be terribel too. > >>> +/* Return the number of contiguous free descriptors >>> + * starting from tx_slot >>> + */ >>> +static int rb_tx_numfreedesc(struct net_device *ndev) >>> +{ >>> + struct sun8i_emac_priv *priv = netdev_priv(ndev); >>> + >>> + if (priv->tx_slot < priv->tx_dirty) >>> + return priv->tx_dirty - priv->tx_slot; >> >> Does this work with if tx_dirty wraps around? >> > > The tx_dirty cannot wrap since I always keep an empty slot. (tx_slot cannot > go equal or after tx_dirty) OK, fair enough. > >>> +/* Grab a frame into a skb from descriptor number i */ >>> +static int sun8i_emac_rx_from_ddesc(struct net_device *ndev, int i) >>> +{ >>> + struct sk_buff *skb; >>> + struct sun8i_emac_priv *priv = netdev_priv(ndev); >>> + struct dma_desc *ddesc = priv->dd_rx + i; >>> + int frame_len; >>> + int crc_checked = 0; >>> + >>> + if (ndev->features & NETIF_F_RXCSUM) >>> + crc_checked = 1; >> >> Assuming CRC here refers to the Ethernet frame's FCS, then this is >> absolutely not how NETIF_F_RXCSUM works. NETIF_F_RXCSUM is about your >> Ethernet adapter supporting L3/L4 checksum offloads, while the Ethernet >> FCS is pretty much mandatory for the frame to be properly received in >> the first place. Can you clarify which way it is? >> > > No CRC here is RXCSUM. I understand the misnaming. > I will rename the variable to rxcsum_done. Thanks > >>> + >>> + priv->ndev->stats.rx_packets++; >>> + priv->ndev->stats.rx_bytes += frame_len; >>> + priv->rx_sk[i] = NULL; >>> + >>> + /* this frame is not the last */ >>> + if ((ddesc->status & BIT(8)) == 0) { >>> + dev_warn(priv->dev, "Multi frame not implemented currlen=%d\n", >>> +frame_len); >>> + } >>> + >>> + sun8i_emac_rx_sk(ndev, i); >>> + >>> + netif_rx(skb); >> >> netif_receive_skb() at the very least, or if you implement NAPI, like >> you shoud napi_gro_receive(). >> > > netif_receive_skb documentation say > "This function may only be called from softirq context and interrupts should > be enabled." > but the calling functions is in hardirq context. Well, yes, because you are not implementing NAPI, while you should, you execute in hard interrupt context. Once you move to NAPI, you can and should use netif_receive_skb(). > >>> + return 0; >>> +} >>> + >>> +/* Cycle over RX DMA descriptors for finding frame to receive >>> + */ >>> +static int sun8i_emac_receive_all(struct net_device *ndev) >>> +{ >>> + struct sun8i_emac_priv *priv = netdev_priv(ndev); >>> + struct dma_desc *ddesc; >>> + >>> + ddesc = priv->dd_rx + priv->rx_dirty; >>> + while (!(ddesc->status & BIT(31))) { >>> + sun8i_emac_rx_from_ddesc(ndev, priv->rx_dirty); >>> + rb_inc(>rx_dirty, nbdesc_rx); >>> + ddesc = priv->dd_rx + priv->rx_dirty; >>> + }; >> >> So, what if we ping flood your device here, is not there a remote chance >> that we keep the RX interrupt so busy we can't break out of this loop
Re: [PATCH net-next 4/4] net: dsa: bcm_sf2: Add VLAN support
On 06/10/2016 05:00 AM, Andrew Lunn wrote: >> @@ -148,6 +155,9 @@ struct bcm_sf2_priv { >> struct device_node *master_mii_dn; >> struct mii_bus *slave_mii_bus; >> struct mii_bus *master_mii_bus; >> + >> +/* Cache of programmed VLANs */ >> +struct bcm_sf2_vlan vlans[VLAN_N_VID]; > > Hi Florian > > This is a 16Kbyte array. So i assume the whole priv structure needs 5 > pages. Have you had any trouble allocating this much memory, > particularly once it has been used for a while and fragmented? Well, since this is using the old binding, we can't unload the driver, it's built into the kernel, so initializes early enough we have got plenty of memory. > > I just wondered if it might be better to use vmalloc() for the > vlans. That's a very good point, I can't really see a drawback to doing this, will submit a patch moving this to a dynamic allocation. Another possible approach would have been to allocate the vlan structure upong port_vlan_prepare() though that would typically result in more fragmentation over time once se start using more VLANs. -- Florian
Re: [PATCH net-next 1/5] net: dsa: b53: Add support for Broadcom RoboSwitch
On 06/10/2016 05:11 AM, Andrew Lunn wrote: >> +static void b53_switch_reset_gpio(struct b53_device *dev) >> +{ >> +int gpio = dev->reset_gpio; >> + >> +if (gpio < 0) >> +return; >> + >> +/* Reset sequence: RESET low(50ms)->high(20ms) >> + */ >> +gpio_set_value(gpio, 0); >> +mdelay(50); >> + >> +gpio_set_value(gpio, 1); >> +mdelay(20); >> + >> +dev->current_page = 0xff; >> +} > > Hi Florian > > It would be better to use the gpiod API here, so the active hi/active > low flag is respected. OK. > >> +dev->reset_gpio = b53_switch_get_reset_gpio(dev); >> +if (dev->reset_gpio >= 0) { >> +ret = devm_gpio_request_one(dev->dev, dev->reset_gpio, >> +GPIOF_OUT_INIT_HIGH, "robo_reset"); >> +if (ret) >> +return ret; >> +} >> + >> +return 0; >> +} > >> +static inline int b53_switch_get_reset_gpio(struct b53_device *dev) >> +{ >> +enum bcm47xx_board board = bcm47xx_board_get(); >> + >> +switch (board) { >> +case BCM47XX_BOARD_LINKSYS_WRT300NV11: >> +case BCM47XX_BOARD_LINKSYS_WRT310NV1: >> +return 8; > > Rather than hard coding it, could we get it from device tree? Difficult for now, this is for in-tree MIPS-based platforms under arch/mips/bcm47xx, which are using SSB/platform data. -- Florian
[PATCH net-next 3/4] net: dsa: bcm_sf2: Add VLAN registers definitions
Add the definitions for the VLAN registers that we are going to manipulate in subsequent patches. Signed-off-by: Florian Fainelli <f.faine...@gmail.com> --- drivers/net/dsa/bcm_sf2_regs.h | 70 ++ 1 file changed, 70 insertions(+) diff --git a/drivers/net/dsa/bcm_sf2_regs.h b/drivers/net/dsa/bcm_sf2_regs.h index 97780d43b5c0..9f2a9cb42074 100644 --- a/drivers/net/dsa/bcm_sf2_regs.h +++ b/drivers/net/dsa/bcm_sf2_regs.h @@ -274,6 +274,23 @@ #define CORE_ARLA_SRCH_RSLT_MACVID(x) (CORE_ARLA_SRCH_RSLT_0_MACVID + ((x) * 0x40)) #define CORE_ARLA_SRCH_RSLT(x) (CORE_ARLA_SRCH_RSLT_0 + ((x) * 0x40)) +#define CORE_ARLA_VTBL_RWCTRL 0x1600 +#define ARLA_VTBL_CMD_WRITE 0 +#define ARLA_VTBL_CMD_READ1 +#define ARLA_VTBL_CMD_CLEAR 2 +#define ARLA_VTBL_STDN(1 << 7) + +#define CORE_ARLA_VTBL_ADDR0x1604 +#define VTBL_ADDR_INDEX_MASK 0xfff + +#define CORE_ARLA_VTBL_ENTRY 0x160c +#define FWD_MAP_MASK 0x1ff +#define UNTAG_MAP_MASK0x1ff +#define UNTAG_MAP_SHIFT 9 +#define MSTP_INDEX_MASK 0x7 +#define MSTP_INDEX_SHIFT 18 +#define FWD_MODE (1 << 21) + #define CORE_MEM_PSM_VDD_CTRL 0x2380 #define P_TXQ_PSM_VDD_SHIFT 2 #define P_TXQ_PSM_VDD_MASK0x3 @@ -287,6 +304,59 @@ #define CORE_PORT_VLAN_CTL_PORT(x) (0xc400 + ((x) * 0x8)) #define PORT_VLAN_CTRL_MASK 0x1ff +#define CORE_VLAN_CTRL00xd000 +#define CHANGE_1P_VID_INNER (1 << 0) +#define CHANGE_1P_VID_OUTER (1 << 1) +#define CHANGE_1Q_VID (1 << 3) +#define VLAN_LEARN_MODE_SVL (0 << 5) +#define VLAN_LEARN_MODE_IVL (3 << 5) +#define VLAN_EN (1 << 7) + +#define CORE_VLAN_CTRL10xd004 +#define EN_RSV_MCAST_FWDMAP (1 << 2) +#define EN_RSV_MCAST_UNTAG(1 << 3) +#define EN_IPMC_BYPASS_FWDMAP (1 << 5) +#define EN_IPMC_BYPASS_UNTAG (1 << 6) + +#define CORE_VLAN_CTRL20xd008 +#define EN_MIIM_BYPASS_V_FWDMAP (1 << 2) +#define EN_GMRP_GVRP_V_FWDMAP (1 << 5) +#define EN_GMRP_GVRP_UNTAG_MAP(1 << 6) + +#define CORE_VLAN_CTRL30xd00c +#define EN_DROP_NON1Q_MASK0x1ff + +#define CORE_VLAN_CTRL40xd014 +#define RESV_MCAST_FLOOD (1 << 1) +#define EN_DOUBLE_TAG_MASK0x3 +#define EN_DOUBLE_TAG_SHIFT 2 +#define EN_MGE_REV_GMRP (1 << 4) +#define EN_MGE_REV_GVRP (1 << 5) +#define INGR_VID_CHK_SHIFT6 +#define INGR_VID_CHK_MASK 0x3 +#define INGR_VID_CHK_FWD (0 << INGR_VID_CHK_SHIFT) +#define INGR_VID_CHK_DROP (1 << INGR_VID_CHK_SHIFT) +#define INGR_VID_CHK_NO_CHK (2 << INGR_VID_CHK_SHIFT) +#define INGR_VID_CHK_VID_VIOL_IMP (3 << INGR_VID_CHK_SHIFT) + +#define CORE_VLAN_CTRL50xd018 +#define EN_CPU_RX_BYP_INNER_CRCCHCK (1 << 0) +#define EN_VID_FFF_FWD(1 << 2) +#define DROP_VTABLE_MISS (1 << 3) +#define EGRESS_DIR_FRM_BYP_TRUNK_EN (1 << 4) +#define PRESV_NON1Q (1 << 6) + +#define CORE_VLAN_CTRL60xd01c +#define STRICT_SFD_DETECT (1 << 0) +#define DIS_ARL_BUST_LMIT (1 << 4) + +#define CORE_DEFAULT_1Q_TAG_P(x) (0xd040 + ((x) * 8)) +#define CFI_SHIFT 12 +#define PRI_SHIFT 13 +#define PRI_MASK 0x7 + +#define CORE_JOIN_ALL_VLAN_EN 0xd140 + #define CORE_EEE_EN_CTRL 0x24800 #define CORE_EEE_LPI_INDICATE 0x24810 -- 2.7.4
[PATCH net-next 1/4] net: dsa: bcm_sf2: Split fast age into a helper function
Add a helper function to fast age something that is controlled by the caller: port, VLAN. We will use this to implement a VLAN fast age operation. Signed-off-by: Florian Fainelli <f.faine...@gmail.com> --- drivers/net/dsa/bcm_sf2.c | 20 +--- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index d6625783703f..ad22caba51e5 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c @@ -461,17 +461,11 @@ static int bcm_sf2_sw_set_eee(struct dsa_switch *ds, int port, return 0; } -/* Fast-ageing of ARL entries for a given port, equivalent to an ARL - * flush for that port. - */ -static int bcm_sf2_sw_fast_age_port(struct dsa_switch *ds, int port) +static int bcm_sf2_fast_age_op(struct bcm_sf2_priv *priv) { - struct bcm_sf2_priv *priv = ds_to_priv(ds); unsigned int timeout = 1000; u32 reg; - core_writel(priv, port, CORE_FAST_AGE_PORT); - reg = core_readl(priv, CORE_FAST_AGE_CTRL); reg |= EN_AGE_PORT | EN_AGE_DYNAMIC | FAST_AGE_STR_DONE; core_writel(priv, reg, CORE_FAST_AGE_CTRL); @@ -492,6 +486,18 @@ static int bcm_sf2_sw_fast_age_port(struct dsa_switch *ds, int port) return 0; } +/* Fast-ageing of ARL entries for a given port, equivalent to an ARL + * flush for that port. + */ +static int bcm_sf2_sw_fast_age_port(struct dsa_switch *ds, int port) +{ + struct bcm_sf2_priv *priv = ds_to_priv(ds); + + core_writel(priv, port, CORE_FAST_AGE_PORT); + + return bcm_sf2_fast_age_op(priv); +} + static int bcm_sf2_sw_br_join(struct dsa_switch *ds, int port, struct net_device *bridge) { -- 2.7.4
[PATCH net-next 5/5] net: dsa: b53: Plug in VLAN support
Add support for configuration VLANs on B53 devices by implementing the port VLAN add/del/dump functions. We currently default to a behavior which is equivalent to having VLAN filtering turned on, where all VLANs not programmed into the VLAN port-based vector will be discarded on ingress. Signed-off-by: Florian Fainelli <f.faine...@gmail.com> --- drivers/net/dsa/b53/b53_common.c | 256 +++ drivers/net/dsa/b53/b53_priv.h | 13 +- 2 files changed, 243 insertions(+), 26 deletions(-) diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index ad1d68272016..5321083379c7 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -186,15 +186,15 @@ static int b53_do_vlan_op(struct b53_device *dev, u8 op) return -EIO; } -static void b53_set_vlan_entry(struct b53_device *dev, u16 vid, u16 members, - u16 untag) +static void b53_set_vlan_entry(struct b53_device *dev, u16 vid, + struct b53_vlan *vlan) { if (is5325(dev)) { u32 entry = 0; - if (members) { - entry = ((untag & VA_UNTAG_MASK_25) << VA_UNTAG_S_25) | - members; + if (vlan->members) { + entry = ((vlan->untag & VA_UNTAG_MASK_25) << +VA_UNTAG_S_25) | vlan->members; if (dev->core_rev >= 3) entry |= VA_VALID_25_R4 | vid << VA_VID_HIGH_S; else @@ -207,9 +207,9 @@ static void b53_set_vlan_entry(struct b53_device *dev, u16 vid, u16 members, } else if (is5365(dev)) { u16 entry = 0; - if (members) - entry = ((untag & VA_UNTAG_MASK_65) << VA_UNTAG_S_65) | - members | VA_VALID_65; + if (vlan->members) + entry = ((vlan->untag & VA_UNTAG_MASK_65) << +VA_UNTAG_S_65) | vlan->members | VA_VALID_65; b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_WRITE_65, entry); b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_TABLE_ACCESS_65, vid | @@ -217,13 +217,55 @@ static void b53_set_vlan_entry(struct b53_device *dev, u16 vid, u16 members, } else { b53_write16(dev, B53_ARLIO_PAGE, dev->vta_regs[1], vid); b53_write32(dev, B53_ARLIO_PAGE, dev->vta_regs[2], - (untag << VTE_UNTAG_S) | members); + (vlan->untag << VTE_UNTAG_S) | vlan->members); b53_do_vlan_op(dev, VTA_CMD_WRITE); } + + dev_dbg(dev->ds->dev, "VID: %d, members: 0x%04x, untag: 0x%04x\n", + vid, vlan->members, vlan->untag); +} + +static void b53_get_vlan_entry(struct b53_device *dev, u16 vid, + struct b53_vlan *vlan) +{ + if (is5325(dev)) { + u32 entry = 0; + + b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_TABLE_ACCESS_25, vid | + VTA_RW_STATE_RD | VTA_RW_OP_EN); + b53_read32(dev, B53_VLAN_PAGE, B53_VLAN_WRITE_25, ); + + if (dev->core_rev >= 3) + vlan->valid = !!(entry & VA_VALID_25_R4); + else + vlan->valid = !!(entry & VA_VALID_25); + vlan->members = entry & VA_MEMBER_MASK; + vlan->untag = (entry >> VA_UNTAG_S_25) & VA_UNTAG_MASK_25; + + } else if (is5365(dev)) { + u16 entry = 0; + + b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_TABLE_ACCESS_65, vid | + VTA_RW_STATE_WR | VTA_RW_OP_EN); + b53_read16(dev, B53_VLAN_PAGE, B53_VLAN_WRITE_65, ); + + vlan->valid = !!(entry & VA_VALID_65); + vlan->members = entry & VA_MEMBER_MASK; + vlan->untag = (entry >> VA_UNTAG_S_65) & VA_UNTAG_MASK_65; + } else { + u32 entry = 0; + + b53_write16(dev, B53_ARLIO_PAGE, dev->vta_regs[1], vid); + b53_do_vlan_op(dev, VTA_CMD_READ); + b53_read32(dev, B53_ARLIO_PAGE, dev->vta_regs[2], ); + vlan->members = entry & VTE_MEMBERS; + vlan->untag = (entry >> VTE_UNTAG_S) & VTE_MEMBERS; + vlan->valid = true; + } } -void b53_set_forwarding(struct b53_device *dev, int enable) +static void b53_set_forwarding(struct b53_device *dev, int enable) { u8 mgmt; @@ -237,7 +279,7 @@ void b53_set_forwarding(struct b53_device *dev, int enable) b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, mgmt); } -static
[PATCH net-next 0/5] net: dsa: Broadcom BCM53xx switches support
Hi all, This patch series adds support for the Broadcom BCM53xx series aka RoboSwitches. This driver is largely based on Jonas Gorski's b53 driver for OpenWrt which can be found here: https://dev.openwrt.org/browser/trunk/target/linux/generic/files/drivers/net/phy/b53 a few bug fixes and DSA-ifycation later, here is what we got. This has been successfully tested in the following configurations: - Broadcom BCM53011 using the SRAB bus layer with 4 ports LAN, 1 port WAN - A Broadcom BCM7445 device with an internal Starfighter 2 switch (bcm_sf2.c) and a Broadcom BCM53125 hanging off one of its ports connected via MDIO, creating two trees hanging off each other, and this works! - A Broadcom BCM53125 MDIO connected to a Lamobo/Bananapi R1 board using the STMMAC MDIO driver For now, we do not enable Broadcom tags, because there are different generations of switches being supported which have different tag formats, but the plan is to enable them later on. Support for different HW features will be added later: EEE, Compact Field Processor (TCAM) once this initial cut gets accepted. Testing and bug reports welcome! Florian Fainelli (5): net: dsa: b53: Add support for Broadcom RoboSwitch net: dsa: b53: Add BCM7445 quirk net: dsa: b53: Implement ARL add/del/dump operations net: dsa: b53: Add bridge support net: dsa: b53: Plug in VLAN support Documentation/devicetree/bindings/net/dsa/b53.txt | 90 ++ MAINTAINERS |8 + drivers/net/dsa/Kconfig |2 + drivers/net/dsa/Makefile |2 + drivers/net/dsa/b53/Kconfig | 33 + drivers/net/dsa/b53/Makefile |6 + drivers/net/dsa/b53/b53_common.c | 1787 + drivers/net/dsa/b53/b53_mdio.c| 392 + drivers/net/dsa/b53/b53_mmap.c| 260 +++ drivers/net/dsa/b53/b53_priv.h| 387 + drivers/net/dsa/b53/b53_regs.h| 434 + drivers/net/dsa/b53/b53_spi.c | 331 drivers/net/dsa/b53/b53_srab.c| 415 + include/linux/platform_data/b53.h | 33 + 14 files changed, 4180 insertions(+) create mode 100644 Documentation/devicetree/bindings/net/dsa/b53.txt create mode 100644 drivers/net/dsa/b53/Kconfig create mode 100644 drivers/net/dsa/b53/Makefile create mode 100644 drivers/net/dsa/b53/b53_common.c create mode 100644 drivers/net/dsa/b53/b53_mdio.c create mode 100644 drivers/net/dsa/b53/b53_mmap.c create mode 100644 drivers/net/dsa/b53/b53_priv.h create mode 100644 drivers/net/dsa/b53/b53_regs.h create mode 100644 drivers/net/dsa/b53/b53_spi.c create mode 100644 drivers/net/dsa/b53/b53_srab.c create mode 100644 include/linux/platform_data/b53.h -- 2.7.4
[PATCH net-next 4/5] net: dsa: b53: Add bridge support
Add support for HW bridging by tying the ports together in the same port VLAN mask when they belong to the same bridge, and isolating them to be alone with the CPU port when they are not. Propagate STP states from the bridge layer to the switch's HW mapping when requested. Signed-off-by: Florian Fainelli <f.faine...@gmail.com> --- drivers/net/dsa/b53/b53_common.c | 162 ++- drivers/net/dsa/b53/b53_priv.h | 3 + drivers/net/dsa/b53/b53_regs.h | 12 +++ 3 files changed, 174 insertions(+), 3 deletions(-) diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index a9f1de407f57..ad1d68272016 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -339,12 +340,12 @@ static int b53_set_jumbo(struct b53_device *dev, bool enable, bool allow_10_100) return b53_write16(dev, B53_JUMBO_PAGE, dev->jumbo_size_reg, max_size); } -static int b53_flush_arl(struct b53_device *dev) +static int b53_flush_arl(struct b53_device *dev, u8 mask) { unsigned int i; b53_write8(dev, B53_CTRL_PAGE, B53_FAST_AGE_CTRL, - FAST_AGE_DONE | FAST_AGE_DYNAMIC | FAST_AGE_STATIC); + FAST_AGE_DONE | FAST_AGE_DYNAMIC | mask); for (i = 0; i < 10; i++) { u8 fast_age_ctrl; @@ -365,14 +366,52 @@ out: return 0; } +static int b53_fast_age_port(struct b53_device *dev, int port) +{ + b53_write8(dev, B53_CTRL_PAGE, B53_FAST_AGE_PORT_CTRL, port); + + return b53_flush_arl(dev, FAST_AGE_PORT); +} + +static void b53_imp_vlan_setup(struct dsa_switch *ds, int cpu_port) +{ + struct b53_device *dev = ds_to_priv(ds); + unsigned int i; + u16 pvlan; + + /* 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. +*/ + b53_for_each_port(dev, i) { + b53_read16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(i), ); + pvlan |= BIT(cpu_port); + b53_write16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(i), pvlan); + } +} + static int b53_enable_port(struct dsa_switch *ds, int port, struct phy_device *phy) { struct b53_device *dev = ds_to_priv(ds); + unsigned int cpu_port = dev->cpu_port; + u16 pvlan; /* Clear the Rx and Tx disable bits and set to no spanning tree */ b53_write8(dev, B53_CTRL_PAGE, B53_PORT_CTRL(port), 0); + /* Set this port, and only this one to be in the default VLAN, +* if member of a bridge, restore its membership prior to +* bringing down this port. +*/ + b53_read16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(port), ); + pvlan &= ~0x1ff; + pvlan |= BIT(port); + pvlan |= dev->ports[port].vlan_ctl_mask; + b53_write16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(port), pvlan); + + b53_imp_vlan_setup(ds, cpu_port); + return 0; } @@ -482,7 +521,7 @@ static int b53_switch_reset(struct b53_device *dev) b53_enable_mib(dev); - return b53_flush_arl(dev); + return b53_flush_arl(dev, FAST_AGE_STATIC); } static int b53_phy_read16(struct dsa_switch *ds, int addr, int reg) @@ -1019,6 +1058,120 @@ static int b53_fdb_dump(struct dsa_switch *ds, int port, return 0; } +static int b53_br_join(struct dsa_switch *ds, int port, + struct net_device *bridge) +{ + struct b53_device *dev = ds_to_priv(ds); + u16 pvlan, reg; + unsigned int i; + + dev->ports[port].bridge_dev = bridge; + b53_read16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(port), ); + + b53_for_each_port(dev, i) { + if (dev->ports[i].bridge_dev != bridge) + continue; + + /* Add this local port to the remote port VLAN control +* membership and update the remote port bitmask +*/ + b53_read16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(i), ); + reg |= BIT(port); + b53_write16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(i), reg); + dev->ports[i].vlan_ctl_mask = reg; + + pvlan |= BIT(i); + } + + /* Configure the local port VLAN control membership to include +* remote ports and update the local port bitmask +*/ + b53_write16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(port), pvlan); + dev->ports[port].vlan_ctl_mask = pvlan; + + return 0; +} + +static void b53_br_leave(struct dsa_switch *ds, int port) +{ + struct b53_device *dev = ds_to_priv(ds); + struct net_device *bridge = dev->ports[port].bridge_dev; + unsigned int i; + u16 pvlan, reg; + + b53_read16(dev, B53
[PATCH net-next 4/4] net: dsa: bcm_sf2: Add VLAN support
Add support for configuring VLANs on the Broadcom Starfigther2 switch. This is all done through the bridge vlan facility just like other DSA drivers. Signed-off-by: Florian Fainelli <f.faine...@gmail.com> --- drivers/net/dsa/bcm_sf2.c | 266 +- drivers/net/dsa/bcm_sf2.h | 10 ++ 2 files changed, 275 insertions(+), 1 deletion(-) diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index d726f5906ef9..cd1d630ae3a9 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c @@ -467,7 +467,7 @@ static int bcm_sf2_fast_age_op(struct bcm_sf2_priv *priv) u32 reg; reg = core_readl(priv, CORE_FAST_AGE_CTRL); - reg |= EN_AGE_PORT | EN_AGE_DYNAMIC | FAST_AGE_STR_DONE; + reg |= EN_AGE_PORT | EN_AGE_VLAN | EN_AGE_DYNAMIC | FAST_AGE_STR_DONE; core_writel(priv, reg, CORE_FAST_AGE_CTRL); do { @@ -498,13 +498,86 @@ static int bcm_sf2_sw_fast_age_port(struct dsa_switch *ds, int port) return bcm_sf2_fast_age_op(priv); } +static int bcm_sf2_sw_fast_age_vlan(struct bcm_sf2_priv *priv, u16 vid) +{ + core_writel(priv, vid, CORE_FAST_AGE_VID); + + return bcm_sf2_fast_age_op(priv); +} + +static int bcm_sf2_vlan_op_wait(struct bcm_sf2_priv *priv) +{ + unsigned int timeout = 10; + u32 reg; + + do { + reg = core_readl(priv, CORE_ARLA_VTBL_RWCTRL); + if (!(reg & ARLA_VTBL_STDN)) + return 0; + + usleep_range(1000, 2000); + } while (timeout--); + + return -ETIMEDOUT; +} + +static int bcm_sf2_vlan_op(struct bcm_sf2_priv *priv, u8 op) +{ + core_writel(priv, ARLA_VTBL_STDN | op, CORE_ARLA_VTBL_RWCTRL); + + return bcm_sf2_vlan_op_wait(priv); +} + +static void bcm_sf2_set_vlan_entry(struct bcm_sf2_priv *priv, u16 vid, + struct bcm_sf2_vlan *vlan) +{ + int ret; + + core_writel(priv, vid & VTBL_ADDR_INDEX_MASK, CORE_ARLA_VTBL_ADDR); + core_writel(priv, vlan->untag << UNTAG_MAP_SHIFT | vlan->members, + CORE_ARLA_VTBL_ENTRY); + + ret = bcm_sf2_vlan_op(priv, ARLA_VTBL_CMD_WRITE); + if (ret) + pr_err("failed to write VLAN entry\n"); +} + +static int bcm_sf2_get_vlan_entry(struct bcm_sf2_priv *priv, u16 vid, + struct bcm_sf2_vlan *vlan) +{ + u32 entry; + int ret; + + core_writel(priv, vid & VTBL_ADDR_INDEX_MASK, CORE_ARLA_VTBL_ADDR); + + ret = bcm_sf2_vlan_op(priv, ARLA_VTBL_CMD_READ); + if (ret) + return ret; + + entry = core_readl(priv, CORE_ARLA_VTBL_ENTRY); + vlan->members = entry & FWD_MAP_MASK; + vlan->untag = (entry >> UNTAG_MAP_SHIFT) & UNTAG_MAP_MASK; + + return 0; +} + static int bcm_sf2_sw_br_join(struct dsa_switch *ds, int port, struct net_device *bridge) { struct bcm_sf2_priv *priv = ds_to_priv(ds); + s8 cpu_port = ds->dst->cpu_port; unsigned int i; u32 reg, p_ctl; + /* Make this port leave the all VLANs join since we will have proper +* VLAN entries from now on +*/ + reg = core_readl(priv, CORE_JOIN_ALL_VLAN_EN); + reg &= ~BIT(port); + if ((reg & BIT(cpu_port)) == BIT(cpu_port)) + reg &= ~BIT(cpu_port); + core_writel(priv, reg, CORE_JOIN_ALL_VLAN_EN); + priv->port_sts[port].bridge_dev = bridge; p_ctl = core_readl(priv, CORE_PORT_VLAN_CTL_PORT(port)); @@ -536,6 +609,7 @@ static void bcm_sf2_sw_br_leave(struct dsa_switch *ds, int port) { struct bcm_sf2_priv *priv = ds_to_priv(ds); struct net_device *bridge = priv->port_sts[port].bridge_dev; + s8 cpu_port = ds->dst->cpu_port; unsigned int i; u32 reg, p_ctl; @@ -559,6 +633,13 @@ static void bcm_sf2_sw_br_leave(struct dsa_switch *ds, int port) core_writel(priv, p_ctl, CORE_PORT_VLAN_CTL_PORT(port)); priv->port_sts[port].vlan_ctl_mask = p_ctl; priv->port_sts[port].bridge_dev = NULL; + + /* Make this port join all VLANs without VLAN entries */ + reg = core_readl(priv, CORE_JOIN_ALL_VLAN_EN); + reg |= BIT(port); + if (!(reg & BIT(cpu_port))) + reg |= BIT(cpu_port); + core_writel(priv, reg, CORE_JOIN_ALL_VLAN_EN); } static void bcm_sf2_sw_br_set_stp_state(struct dsa_switch *ds, int port, @@ -1312,6 +1393,182 @@ static int bcm_sf2_sw_set_wol(struct dsa_switch *ds, int port, return p->ethtool_ops->set_wol(p, wol); } +static void bcm_sf2_enable_vlan(struct bcm_sf2_priv *priv, bool enable) +{ + u32 mgmt, vc0, vc1, vc4, vc5; + + mgmt = core_readl(priv, CORE_SWMODE); + vc0 = core_readl(priv, CORE_VLAN_CTRL0); + vc1 = core_readl(priv, CORE_VLAN_CTRL1); +
[PATCH net-next 2/4] net: dsa: bcm_sf2: Move setup function at the far end
Re-order the bcm_sf2_sw_setup() function so that it is at the far end of the driver to avoid any kind of forward declarations. Signed-off-by: Florian Fainelli <f.faine...@gmail.com> --- drivers/net/dsa/bcm_sf2.c | 238 +++--- 1 file changed, 119 insertions(+), 119 deletions(-) diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index ad22caba51e5..d726f5906ef9 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c @@ -1065,125 +1065,6 @@ static void bcm_sf2_mdio_unregister(struct bcm_sf2_priv *priv) of_node_put(priv->master_mii_dn); } -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(>indir_lock); - mutex_init(>stats_mutex); - - /* All the interesting properties are at the parent device_node -* level -*/ - dn = ds->cd->of_node->parent; - bcm_sf2_identify_ports(priv, ds->cd->of_node); - - priv->irq0 = irq_of_parse_and_map(dn, 0); - priv->irq1 = irq_of_parse_and_map(dn, 1); - - base = >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]); - ret = -ENOMEM; - goto out_unmap; - } - base++; - } - - ret = bcm_sf2_sw_rst(priv); - if (ret) { - pr_err("unable to software reset switch: %d\n", ret); - goto out_unmap; - } - - ret = bcm_sf2_mdio_register(ds); - if (ret) { - pr_err("failed to register MDIO bus\n"); - goto out_unmap; - } - - /* Disable all interrupts and request them */ - bcm_sf2_intr_disable(priv); - - 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", ->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->enabled_port_mask) - bcm_sf2_port_setup(ds, port, NULL); - else if (dsa_is_cpu_port(ds, port)) - bcm_sf2_imp_setup(ds, port); - else - bcm_sf2_port_disable(ds, port, NULL); - } - - 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); - - rev = reg_readl(priv, REG_PHY_REVISION); - priv->hw_params.gphy_rev = rev & PHY_REVISION_MASK; - - pr_info("Starfighter 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 = >core; - for (i = 0; i < BCM_SF2_REGS_NUM; i++) { - if (*base) - iounmap(*base); - base++; - } -
[PATCH net-next 0/4] net: dsa: bcm_sf2: add VLAN support
Hi all, This is long overdue, finally add support for VLANs in the Broadcom Starfigther 2 switch driver. There are a few things that make us differ from e.g; mv88e6xxx.c: - we keep a software cache of which VLANs are enabled and which are not to dramatically speed up the VLAN dump operation, we do not have any HW operation which would only return the list of valid VLAN entries, they would have to be all queried one by one, with 4K vlans, this takes a while - the default behavior is equivalent to setting VLAN filtering to 1, still working on implementing a proper port_vlan_filtering callback, but I figured the most conservative behavior is probably okay anyway - without enabling VLANs, the default behavior is to receive any 802.1q frames (per the DSA documentation), however, once we start enabling VLAN support, if an interface leaves the bridge, we still want it to receive all 802.1q frames so we utiliez the "Join all VLAN" feature of the switch to perform that Thanks! Florian Fainelli (4): net: dsa: bcm_sf2: Split fast age into a helper function net: dsa: bcm_sf2: Move setup function at the far end net: dsa: bcm_sf2: Add VLAN registers definitions net: dsa: bcm_sf2: Add VLAN support drivers/net/dsa/bcm_sf2.c | 524 +++-- drivers/net/dsa/bcm_sf2.h | 10 + drivers/net/dsa/bcm_sf2_regs.h | 70 ++ 3 files changed, 477 insertions(+), 127 deletions(-) -- 2.7.4
[PATCH net-next 1/5] net: dsa: b53: Add support for Broadcom RoboSwitch
This patch adds support for Broadcom's BCM53xx switch family, also known as RoboSwitch. Some of these switches are ubiquituous, found in home routers, Wi-Fi routers, DSL and cable modem gateways and other networking related products. This drivers adds the library driver (b53_common.c) as well as a few bus glue drivers for MDIO, SPI, Switch Register Access Block (SRAB) and memory-mapped I/O into a SoC's address space (Broadcom BCM63xx/33xx). Basic operations are supported to bring the Layer 1/2 up and running, but not much more at this point, subsequent patches add the remaining features. Signed-off-by: Florian Fainelli <f.faine...@gmail.com> --- Documentation/devicetree/bindings/net/dsa/b53.txt | 90 ++ MAINTAINERS |8 + drivers/net/dsa/Kconfig |2 + drivers/net/dsa/Makefile |2 + drivers/net/dsa/b53/Kconfig | 33 + drivers/net/dsa/b53/Makefile |6 + drivers/net/dsa/b53/b53_common.c | 1158 + drivers/net/dsa/b53/b53_mdio.c| 381 +++ drivers/net/dsa/b53/b53_mmap.c| 260 + drivers/net/dsa/b53/b53_priv.h| 322 ++ drivers/net/dsa/b53/b53_regs.h| 358 +++ drivers/net/dsa/b53/b53_spi.c | 331 ++ drivers/net/dsa/b53/b53_srab.c| 415 include/linux/platform_data/b53.h | 33 + 14 files changed, 3399 insertions(+) create mode 100644 Documentation/devicetree/bindings/net/dsa/b53.txt create mode 100644 drivers/net/dsa/b53/Kconfig create mode 100644 drivers/net/dsa/b53/Makefile create mode 100644 drivers/net/dsa/b53/b53_common.c create mode 100644 drivers/net/dsa/b53/b53_mdio.c create mode 100644 drivers/net/dsa/b53/b53_mmap.c create mode 100644 drivers/net/dsa/b53/b53_priv.h create mode 100644 drivers/net/dsa/b53/b53_regs.h create mode 100644 drivers/net/dsa/b53/b53_spi.c create mode 100644 drivers/net/dsa/b53/b53_srab.c create mode 100644 include/linux/platform_data/b53.h diff --git a/Documentation/devicetree/bindings/net/dsa/b53.txt b/Documentation/devicetree/bindings/net/dsa/b53.txt new file mode 100644 index ..4a5349a09655 --- /dev/null +++ b/Documentation/devicetree/bindings/net/dsa/b53.txt @@ -0,0 +1,90 @@ +Broadcom BCM53xx Ethernet switches +== + +Required properties: + +- compatible: For external switch chips, compatible string must be exactly one + of: "brcm,bcm5325" + "brcm,bcm53115" + "brcm,bcm53125" + "brcm,bcm53128" + "brcm,bcm5365" + "brcm,bcm5395" + "brcm,bcm5397" + "brcm,bcm5398" + + For the BCM5310x SoCs with an integrated switch, must be one of: + "brcm,bcm53010-srab" + "brcm,bcm53011-srab" + "brcm,bcm53012-srab" + "brcm,bcm53018-srab" + "brcm,bcm53019-srab" and the mandatory "brcm,bcm5301x-srab" string + + For the BCM63xx/33xx SoCs with an integrated switch, must be one of: + "brcm,bcm3384-switch" + "brcm,bcm6328-switch" + "brcm,bcm6368-switch" and the mandatory "brcm,bcm63xx-switch" + +See Documentation/devicetree/bindings/dsa/dsa.txt for a list of additional +required and optional properties. + +Examples: + +Ethernet switch connected via MDIO to the host, CPU port wired to eth0: + + eth0: ethernet@10001000 { + compatible = "brcm,unimac"; + reg = <0x10001000 0x1000>; + + fixed-link { + speed = <1000>; + duplex-full; + }; + }; + + mdio0: mdio@1000 { + compatible = "brcm,unimac-mdio"; + #address-cells = <1>; + #size-cells = <0>; + + switch0: ethernet-switch@30 { + compatible = "brcm,bcm53125"; + #address-cells = <1>; + #size-cells = <0>; + + ports { + port0@0 { + reg = <0>; + label = "lan1"; + }; + + port1@1 { + reg = <1>; + label = "lan2"; + }; + + port5@5 { + reg = <5>; + label = "cable-modem"; + fixed-link { +
[PATCH net-next 2/5] net: dsa: b53: Add BCM7445 quirk
The Broadcom BCM7445 STB chip has an issued in its revision D0 which was previously worked around in drivers/net/dsa/bcm_sf2.c where we may end-up double programming the integrated BCM7445 switch (bcm_sf2) and an external Broadcom switch such as BCM53125, since these are mostly register compatible. Add a small quirk which just defers probing until we are sitting on the slave DSA MDIO bus, which will allow us to intercept reads/writes and funnel them through the SF2 internal MDIO master (which happens to disconnect its pseudo PHY). Signed-off-by: Florian Fainelli <f.faine...@gmail.com> --- drivers/net/dsa/b53/b53_mdio.c | 11 +++ 1 file changed, 11 insertions(+) diff --git a/drivers/net/dsa/b53/b53_mdio.c b/drivers/net/dsa/b53/b53_mdio.c index c6cf7cf57cc3..aa87c3fffdac 100644 --- a/drivers/net/dsa/b53/b53_mdio.c +++ b/drivers/net/dsa/b53/b53_mdio.c @@ -316,6 +316,17 @@ static int b53_mdio_probe(struct mdio_device *mdiodev) return -ENODEV; } + /* First probe will come from SWITCH_MDIO controller on the 7445D0 +* switch, which will conflict with the 7445 integrated switch +* pseudo-phy (we end-up programming both). In that case, we return +* -EPROBE_DEFER for the first time we get here, and wait until we come +* back with the slave MDIO bus which has the correct indirection +* layer setup +*/ + if (of_machine_is_compatible("brcm,bcm7445d0") && + strcmp(mdiodev->bus->name, "sf2 slave mii")) + return -EPROBE_DEFER; + dev = b53_switch_alloc(>dev, _mdio_ops, mdiodev->bus); if (!dev) return -ENOMEM; -- 2.7.4
[PATCH net-next 3/5] net: dsa: b53: Implement ARL add/del/dump operations
Adds support for FDB add/delete/dump using the ARL read/write logic and the ARL search logic for faster dumps. The code is made flexible enough it could support devices with a different register layout like BCM5325 and BCM5365 which have fewer number of entries or pack values into a single 64 bits register. Signed-off-by: Florian Fainelli <f.faine...@gmail.com> --- drivers/net/dsa/b53/b53_common.c | 261 +++ drivers/net/dsa/b53/b53_priv.h | 57 + drivers/net/dsa/b53/b53_regs.h | 64 ++ 3 files changed, 382 insertions(+) diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index 6f0337d6dfa4..a9f1de407f57 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -26,7 +26,9 @@ #include #include #include +#include #include +#include #include "b53_regs.h" #include "b53_priv.h" @@ -777,6 +779,246 @@ static void b53_adjust_link(struct dsa_switch *ds, int port, } } +/* Address Resolution Logic routines */ +static int b53_arl_op_wait(struct b53_device *dev) +{ + unsigned int timeout = 10; + u8 reg; + + do { + b53_read8(dev, B53_ARLIO_PAGE, B53_ARLTBL_RW_CTRL, ); + if (!(reg & ARLTBL_START_DONE)) + return 0; + + usleep_range(1000, 2000); + } while (timeout--); + + dev_warn(dev->dev, "timeout waiting for ARL to finish: 0x%02x\n", reg); + + return -ETIMEDOUT; +} + +static int b53_arl_rw_op(struct b53_device *dev, unsigned int op) +{ + u8 reg; + + if (op > ARLTBL_RW) + return -EINVAL; + + b53_read8(dev, B53_ARLIO_PAGE, B53_ARLTBL_RW_CTRL, ); + reg |= ARLTBL_START_DONE; + if (op) + reg |= ARLTBL_RW; + else + reg &= ~ARLTBL_RW; + b53_write8(dev, B53_ARLIO_PAGE, B53_ARLTBL_RW_CTRL, reg); + + return b53_arl_op_wait(dev); +} + +static int b53_arl_read(struct b53_device *dev, u64 mac, + u16 vid, struct b53_arl_entry *ent, u8 *idx, + bool is_valid) +{ + unsigned int i; + int ret; + + ret = b53_arl_op_wait(dev); + if (ret) + return ret; + + /* Read the bins */ + for (i = 0; i < dev->num_arl_entries; i++) { + u64 mac_vid; + u32 fwd_entry; + + b53_read64(dev, B53_ARLIO_PAGE, + B53_ARLTBL_MAC_VID_ENTRY(i), _vid); + b53_read32(dev, B53_ARLIO_PAGE, + B53_ARLTBL_DATA_ENTRY(i), _entry); + b53_arl_to_entry(ent, mac_vid, fwd_entry); + + if (!(fwd_entry & ARLTBL_VALID)) + continue; + if ((mac_vid & ARLTBL_MAC_MASK) != mac) + continue; + *idx = i; + } + + return -ENOENT; +} + +static int b53_arl_op(struct b53_device *dev, int op, int port, + const unsigned char *addr, u16 vid, bool is_valid) +{ + struct b53_arl_entry ent; + u32 fwd_entry; + u64 mac, mac_vid = 0; + u8 idx = 0; + int ret; + + /* Convert the array into a 64-bit MAC */ + mac = b53_mac_to_u64(addr); + + /* Perform a read for the given MAC and VID */ + b53_write48(dev, B53_ARLIO_PAGE, B53_MAC_ADDR_IDX, mac); + b53_write16(dev, B53_ARLIO_PAGE, B53_VLAN_ID_IDX, vid); + + /* Issue a read operation for this MAC */ + ret = b53_arl_rw_op(dev, 1); + if (ret) + return ret; + + ret = b53_arl_read(dev, mac, vid, , , is_valid); + /* If this is a read, just finish now */ + if (op) + return ret; + + /* We could not find a matching MAC, so reset to a new entry */ + if (ret) { + fwd_entry = 0; + idx = 1; + } + + memset(, 0, sizeof(ent)); + ent.port = port; + ent.is_valid = is_valid; + ent.vid = vid; + ent.is_static = true; + memcpy(ent.mac, addr, ETH_ALEN); + b53_arl_from_entry(_vid, _entry, ); + + b53_write64(dev, B53_ARLIO_PAGE, + B53_ARLTBL_MAC_VID_ENTRY(idx), mac_vid); + b53_write32(dev, B53_ARLIO_PAGE, + B53_ARLTBL_DATA_ENTRY(idx), fwd_entry); + + return b53_arl_rw_op(dev, 0); +} + +static int b53_fdb_prepare(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_fdb *fdb, + struct switchdev_trans *trans) +{ + struct b53_device *priv = ds_to_priv(ds); + + /* 5325 and 5365 require some more massaging, but could +* be supported eventually +*/ + if (is5325(priv) || is5365(priv)) + return -EOPNOTSUPP; + + return 0; +} + +static void b53_fdb_add(struct dsa_switch *ds, int port,
[PATCH net-next] net: dsa: Provide CPU port statistics to master netdev
This patch overloads the DSA master netdev, aka CPU Ethernet MAC to also include switch-side statistics, which is useful for debugging purposes, when the switch is not properly connected to the Ethernet MAC (duplex mismatch, (RG)MII electrical issues etc.). We accomplish this by retaining the original copy of the master netdev's ethtool_ops, and just overload the 3 operations we care about: get_sset_count, get_strings and get_ethtool_stats so as to intercept these calls and call into the original master_netdev ethtool_ops, plus our own. We take this approach as opposed to providing a set of DSA helper functions that would retrive the CPU port's statistics, because the entire purpose of DSA is to allow unmodified Ethernet MAC drivers to be used as CPU conduit interfaces, therefore, statistics overlay in such drivers would simply not scale. The new ethtool -S output would therefore look like this now: statistics p<2 digits cpu port number>_ Signed-off-by: Florian Fainelli <f.faine...@gmail.com> --- Changes from RFC: - prepend the CPU port as a prefix to make it clear what the stats are about, master netdev interface stats are unchanged include/net/dsa.h | 5 net/dsa/slave.c | 88 +++ 2 files changed, 93 insertions(+) diff --git a/include/net/dsa.h b/include/net/dsa.h index 2d280aba97e2..8e86af87c84f 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -111,6 +111,11 @@ struct dsa_switch_tree { enum dsa_tag_protocol tag_protocol; /* +* Original copy of the master netdev ethtool_ops +*/ + struct ethtool_ops master_ethtool_ops; + + /* * The switch and port to which the CPU is attached. */ s8 cpu_switch; diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 3b6750f5e68b..5ea8a40c8d33 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -666,6 +666,78 @@ static void dsa_slave_get_strings(struct net_device *dev, } } +static void dsa_cpu_port_get_ethtool_stats(struct net_device *dev, + struct ethtool_stats *stats, + uint64_t *data) +{ + struct dsa_switch_tree *dst = dev->dsa_ptr; + struct dsa_switch *ds = dst->ds[0]; + s8 cpu_port = dst->cpu_port; + int count = 0; + + if (dst->master_ethtool_ops.get_sset_count) { + count = dst->master_ethtool_ops.get_sset_count(dev, + ETH_SS_STATS); + dst->master_ethtool_ops.get_ethtool_stats(dev, stats, data); + } + + if (ds->drv->get_ethtool_stats) + ds->drv->get_ethtool_stats(ds, cpu_port, data + count); +} + +static int dsa_cpu_port_get_sset_count(struct net_device *dev, int sset) +{ + struct dsa_switch_tree *dst = dev->dsa_ptr; + struct dsa_switch *ds = dst->ds[0]; + int count = 0; + + if (dst->master_ethtool_ops.get_sset_count) + count += dst->master_ethtool_ops.get_sset_count(dev, sset); + + if (sset == ETH_SS_STATS && ds->drv->get_sset_count) + count += ds->drv->get_sset_count(ds); + + return count; +} + +static void dsa_cpu_port_get_strings(struct net_device *dev, +uint32_t stringset, uint8_t *data) +{ + struct dsa_switch_tree *dst = dev->dsa_ptr; + struct dsa_switch *ds = dst->ds[0]; + s8 cpu_port = dst->cpu_port; + int len = ETH_GSTRING_LEN; + int mcount = 0, count; + unsigned int i; + uint8_t pfx[4]; + uint8_t *ndata; + + snprintf(pfx, sizeof(pfx), "p%.2d", cpu_port); + /* We do not want to be NULL-terminated, since this is a prefix */ + pfx[sizeof(pfx) - 1] = '_'; + + if (dst->master_ethtool_ops.get_sset_count) { + mcount = dst->master_ethtool_ops.get_sset_count(dev, + ETH_SS_STATS); + dst->master_ethtool_ops.get_strings(dev, stringset, data); + } + + if (stringset == ETH_SS_STATS && ds->drv->get_strings) { + ndata = data + mcount * len; + /* This function copies ETH_GSTRINGS_LEN bytes, we will mangle +* the output after to prepend our CPU port prefix we +* constructed earlier +*/ + ds->drv->get_strings(ds, cpu_port, ndata); + count = ds->drv->get_sset_count(ds); + for (i = 0; i < count; i++) { + memmove(ndata + (i * len + sizeof(pfx)), + ndata + i * len, len - sizeof(pfx)); + memcpy(ndata + i * len, pfx, sizeof(pfx)); + } + } +} +
[PATCH net-next 1/9] net: dsa: Prepare to support legacy DT binding
In preparation for supporting the legacy DT binding, call dsa_get_ports() early on to allow two different parsing code paths to be called. Signed-off-by: Florian Fainelli <f.faine...@gmail.com> --- net/dsa/dsa2.c | 12 +++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c index 4e5051bed643..b5640d8ffbae 100644 --- a/net/dsa/dsa2.c +++ b/net/dsa/dsa2.c @@ -552,7 +552,7 @@ static struct device_node *dsa_get_ports(struct dsa_switch *ds, return ports; } -static int _dsa_register_switch(struct dsa_switch *ds, struct device_node *np) +static int __dsa_register_switch(struct dsa_switch *ds, struct device_node *np) { struct device_node *ports = dsa_get_ports(ds, np); struct dsa_switch_tree *dst; @@ -622,6 +622,16 @@ out: return err; } +static int _dsa_register_switch(struct dsa_switch *ds, struct device_node *np) +{ + struct device_node *ports = dsa_get_ports(ds, np); + + if (IS_ERR(ports)) + return PTR_ERR(ports); + + return __dsa_register_switch(ds, np); +} + int dsa_register_switch(struct dsa_switch *ds, struct device_node *np) { int err; -- 2.7.4
[PATCH net-next 0/9] net: dsa: misc improvements
Hi all, This patch series builds on top of Andrew's "New DSA bind, switches as devices" patch set and does the following: - add support for the old DSA binding with the new dsa_register_switch() API which is needed by some platforms where the Device Tree is pretty much frozen - add a few helper functions/goodies for net/dsa/dsa2.c to be as close as possible from net/dsa/dsa.c in terms of what drivers can expect, in particular the slave MDIO bus and the enabled_port_mask and phy_mii_mask - fix the CPU port ethtools ops to work in a multiple tree setup since we can no longer assume a single tree is supported - finally conver the bcm_sf2 driver to be a true platform device driver and slightly rework its internal vs. external MDIO bus indirect read/writes to be cleaner Florian Fainelli (9): net: dsa: Prepare to support legacy DT binding net: dsa: Add support for parsing the old binding net: dsa: Provide unique DSA slave MII bus names net: dsa: Initialize ds->enabled_port_mask and ds->phys_mii_mask net: dsa: Export suspend/resume functions net: dsa: Add initialization helper for CPU port ethtool_ops net: dsa: Initialize CPU port ethtool ops per tree net: dsa: bcm_sf2: Make it a real platform device driver net: dsa: bcm_sf2: Register our slave MDIO bus drivers/net/dsa/bcm_sf2.c | 390 +- drivers/net/dsa/bcm_sf2.h | 6 + include/net/dsa.h | 14 ++ net/dsa/dsa.c | 35 - net/dsa/dsa2.c| 199 --- net/dsa/dsa_priv.h| 3 + net/dsa/slave.c | 25 ++- 7 files changed, 491 insertions(+), 181 deletions(-) -- 2.7.4
[PATCH net-next 7/7] net: dsa: bcm_sf2: Register our slave MDIO bus
Register a slave MDIO bus which allows us to divert problematic read/writes towards conflicting pseudo-PHY address (30). Do no longer rely on DSA's slave_mii_bus, but instead provide our own implementation which offers more flexibility as to what to do, and when to register it. Signed-off-by: Florian Fainelli <f.faine...@gmail.com> --- drivers/net/dsa/bcm_sf2.c | 141 -- drivers/net/dsa/bcm_sf2.h | 6 ++ 2 files changed, 106 insertions(+), 41 deletions(-) diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index 8dac74a6b5df..502ca65435bf 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -948,23 +949,6 @@ static int bcm_sf2_sw_setup(struct dsa_switch *ds) bcm_sf2_port_disable(ds, port, NULL); } - /* Include the pseudo-PHY address and the broadcast PHY address to -* divert reads towards our workaround. This is only required for -* 7445D0, since 7445E0 disconnects the internal switch pseudo-PHY such -* that we can use the regular SWITCH_MDIO master controller instead. -* -* By default, DSA initializes ds->phys_mii_mask to -* ds->enabled_port_mask to have a 1:1 mapping between Port address -* and PHY address in order to utilize the slave_mii_bus instance to -* read from Port PHYs. This is not what we want here, so we -* initialize phys_mii_mask 0 to always utilize the "master" MDIO -* bus backed by the "mdio-unimac" driver. -*/ - if (of_machine_is_compatible("brcm,bcm7445d0")) - ds->phys_mii_mask |= ((1 << BRCM_PSEUDO_PHY_ADDR) | (1 << 0)); - else - ds->phys_mii_mask = 0; - return 0; } @@ -985,10 +969,9 @@ static u32 bcm_sf2_sw_get_phy_flags(struct dsa_switch *ds, int port) return priv->hw_params.gphy_rev; } -static int bcm_sf2_sw_indir_rw(struct dsa_switch *ds, int op, int addr, +static int bcm_sf2_sw_indir_rw(struct bcm_sf2_priv *priv, int op, int addr, int regnum, u16 val) { - struct bcm_sf2_priv *priv = ds_to_priv(ds); int ret = 0; u32 reg; @@ -1017,32 +1000,31 @@ static int bcm_sf2_sw_indir_rw(struct dsa_switch *ds, int op, int addr, return ret & 0x; } -static int bcm_sf2_sw_phy_read(struct dsa_switch *ds, int addr, int regnum) +static int bcm_sf2_sw_phy_read(struct mii_bus *bus, int addr, int regnum) { - /* Intercept reads from the MDIO broadcast address or Broadcom -* pseudo-PHY address + struct bcm_sf2_priv *priv = bus->priv; + + /* Intercept reads from Broadcom pseudo-PHY address, else, send +* them to our master MDIO bus controller */ - switch (addr) { - case 0: - case BRCM_PSEUDO_PHY_ADDR: - return bcm_sf2_sw_indir_rw(ds, 1, addr, regnum, 0); - default: - return 0x; - } + if (addr == BRCM_PSEUDO_PHY_ADDR && priv->indir_phy_mask & BIT(addr)) + return bcm_sf2_sw_indir_rw(priv, 1, addr, regnum, 0); + else + return mdiobus_read(priv->master_mii_bus, addr, regnum); } -static int bcm_sf2_sw_phy_write(struct dsa_switch *ds, int addr, int regnum, +static int bcm_sf2_sw_phy_write(struct mii_bus *bus, int addr, int regnum, u16 val) { - /* Intercept writes to the MDIO broadcast address or Broadcom -* pseudo-PHY address + struct bcm_sf2_priv *priv = bus->priv; + + /* Intercept writes to the Broadcom pseudo-PHY address, else, +* send them to our master MDIO bus controller */ - switch (addr) { - case 0: - case BRCM_PSEUDO_PHY_ADDR: - bcm_sf2_sw_indir_rw(ds, 0, addr, regnum, val); - break; - } + if (addr == BRCM_PSEUDO_PHY_ADDR && priv->indir_phy_mask & BIT(addr)) + bcm_sf2_sw_indir_rw(priv, 0, addr, regnum, val); + else + mdiobus_write(priv->master_mii_bus, addr, regnum, val); return 0; } @@ -1283,8 +1265,6 @@ static struct dsa_switch_driver bcm_sf2_switch_ops = { .setup = bcm_sf2_sw_setup, .set_addr = bcm_sf2_sw_set_addr, .get_phy_flags = bcm_sf2_sw_get_phy_flags, - .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, @@ -1307,6 +1287,75 @@ static struct dsa_switch_driver bcm_sf2_switch_ops = { .port_fdb_dump = bcm_sf2_sw_
[PATCH net-next 5/9] net: dsa: Export suspend/resume functions
In preparation for allowing switch drivers to implement system-wide suspend/resume functions, export dsa_switch_suspend and dsa_switch_resume() such that these are callable from the appropriate driver specific suspend/resume functions. Signed-off-by: Florian Fainelli <f.faine...@gmail.com> --- include/net/dsa.h | 14 ++ net/dsa/dsa.c | 6 -- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/include/net/dsa.h b/include/net/dsa.h index d6ed5dee73e5..c5abaeda84f3 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -382,4 +382,18 @@ static inline bool dsa_uses_tagged_protocol(struct dsa_switch_tree *dst) void dsa_unregister_switch(struct dsa_switch *ds); int dsa_register_switch(struct dsa_switch *ds, struct device_node *np); +#ifdef CONFIG_PM_SLEEP +int dsa_switch_suspend(struct dsa_switch *ds); +int dsa_switch_resume(struct dsa_switch *ds); +#else +static inline int dsa_switch_suspend(struct dsa_switch *ds) +{ + return 0; +} +static inline int dsa_switch_resume(struct dsa_switch *ds) +{ + return 0; +} +#endif /* CONFIG_PM_SLEEP */ + #endif diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c index d8cb2acd4f0a..ebc29a1bee08 100644 --- a/net/dsa/dsa.c +++ b/net/dsa/dsa.c @@ -500,7 +500,7 @@ static void dsa_switch_destroy(struct dsa_switch *ds) } #ifdef CONFIG_PM_SLEEP -static int dsa_switch_suspend(struct dsa_switch *ds) +int dsa_switch_suspend(struct dsa_switch *ds) { int i, ret = 0; @@ -519,8 +519,9 @@ static int dsa_switch_suspend(struct dsa_switch *ds) return ret; } +EXPORT_SYMBOL_GPL(dsa_switch_suspend); -static int dsa_switch_resume(struct dsa_switch *ds) +int dsa_switch_resume(struct dsa_switch *ds) { int i, ret = 0; @@ -542,6 +543,7 @@ static int dsa_switch_resume(struct dsa_switch *ds) return 0; } +EXPORT_SYMBOL_GPL(dsa_switch_resume); #endif /* platform driver init and cleanup */ -- 2.7.4
[PATCH net-next 4/9] net: dsa: Initialize ds->enabled_port_mask and ds->phys_mii_mask
Some drivers heavily rely on these two bitmasks to contain the correct values for them to successfully probe and initialize at drv->setup() time, calculate correct values to put in both masks. To avoid multiple ports lookup, we also try to set dst->cpu_port during dsa_parse_ports_dn(), which is mostly useful for the case where we probe using the legacy binding which has properties/nodes in different places and does not use dsa_dst_parse(). Signed-off-by: Florian Fainelli <f.faine...@gmail.com> --- net/dsa/dsa2.c | 59 ++ 1 file changed, 47 insertions(+), 12 deletions(-) diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c index 23273fd984a8..e8386157de30 100644 --- a/net/dsa/dsa2.c +++ b/net/dsa/dsa2.c @@ -281,6 +281,7 @@ static void dsa_user_port_unapply(struct device_node *port, u32 index, if (ds->ports[index].netdev) { dsa_slave_destroy(ds->ports[index].netdev); ds->ports[index].netdev = NULL; + ds->enabled_port_mask &= ~(1 << index); } } @@ -290,6 +291,13 @@ static int dsa_ds_apply(struct dsa_switch_tree *dst, struct dsa_switch *ds) u32 index; int err; + /* Initialize ds->phys_mii_mask before registering the slave MDIO bus +* driver and before drv->setup() has run, since the switch drivers and +* the slave MDIO bus driver rely on these values for probing PHY +* devices or not +*/ + ds->phys_mii_mask = ds->enabled_port_mask; + err = ds->drv->setup(ds); if (err < 0) return err; @@ -302,6 +310,18 @@ static int dsa_ds_apply(struct dsa_switch_tree *dst, struct dsa_switch *ds) if (err < 0) return err; + if (!ds->slave_mii_bus && ds->drv->phy_read) { + ds->slave_mii_bus = devm_mdiobus_alloc(ds->dev); + if (!ds->slave_mii_bus) + return err; + + dsa_slave_mii_bus_init(ds); + + err = mdiobus_register(ds->slave_mii_bus); + if (err < 0) + return err; + } + for (index = 0; index < DSA_MAX_PORTS; index++) { port = ds->ports[index].dn; if (!port) @@ -421,7 +441,11 @@ static int _dsa_cpu_parse(struct dsa_switch_tree *dst, if (dst->cpu_switch == -1) { dst->cpu_switch = ds->index; - dst->cpu_port = index; + /* Only assign dst->cpu_port if not done already by +* dsa_parse_ports_dn +*/ + if (!dst->cpu_port) + dst->cpu_port = index; } dst->tag_ops = dsa_resolve_tag_protocol(ds->drv->tag_protocol); @@ -517,6 +541,15 @@ static int dsa_parse_ports_dn(struct device_node *ports, struct dsa_switch *ds) return -EINVAL; ds->ports[reg].dn = port; + + if (dsa_port_is_cpu(port)) + ds->dst->cpu_port = reg; + else + /* Initialize enabled_port_mask now for drv->setup() +* to have access to a correct value, just like what +* net/dsa/dsa.c::dsa_switch_setup_one does. +*/ + ds->enabled_port_mask |= 1 << reg; } return 0; @@ -585,10 +618,6 @@ static int _dsa_register_switch_legacy(struct dsa_switch *ds, struct device_node if (index >= DSA_MAX_SWITCHES) return -EINVAL; - err = dsa_parse_ports_dn(np->child, ds); - if (err) - return err; - dst = dsa_get_dst(tree); if (!dst) { dst = dsa_add_dst(tree); @@ -596,12 +625,17 @@ static int _dsa_register_switch_legacy(struct dsa_switch *ds, struct device_node return -ENOMEM; } + ds->dst = dst; + + err = dsa_parse_ports_dn(np->child, ds); + if (err) + return err; + if (dst->ds[index]) { err = -EBUSY; goto out; } - ds->dst = dst; ds->index = index; dsa_dst_add_ds(dst, ds, index); @@ -633,7 +667,7 @@ static int _dsa_register_switch_legacy(struct dsa_switch *ds, struct device_node goto out_del_dst; } - err = _dsa_cpu_parse(dst, ds, ethernet_dev, index); + err = _dsa_cpu_parse(dst, ds, ethernet_dev, dst->cpu_port); if (err) goto out_del_dst; @@ -676,10 +710,6 @@ static int __dsa_register_switch(struct dsa_switch *ds, struct device_node *np) if (IS_ERR(ports)) return PTR_ERR(ports); - err = dsa_parse_ports_dn(ports, ds); - if (err) - return er
Re: [PATCH net-next] net: dsa: bcm_sf2: Implement FDB operations
On 06/03/2016 05:05 PM, Florian Fainelli wrote: > Add support for the FDB add, delete, and dump operations. The add and > delete operations are implemented using directed ARL operations using > the specified MAC address and consist in a read operation, write and > readback operation. > > The dump operation consists in using the ARL search and software > filtering entries which are not for the desired port. And this one too should be discarded. -- Florian
Re: [PATCH net-next 0/9] net: dsa: misc improvements
On 06/03/2016 05:05 PM, Florian Fainelli wrote: > Hi all, > > This patch series builds on top of Andrew's "New DSA bind, switches as > devices" > patch set and does the following: > > - add support for the old DSA binding with the new dsa_register_switch() API > which is needed by some platforms where the Device Tree is pretty much > frozen > > - add a few helper functions/goodies for net/dsa/dsa2.c to be as close as > possible > from net/dsa/dsa.c in terms of what drivers can expect, in particular the > slave > MDIO bus and the enabled_port_mask and phy_mii_mask > > - fix the CPU port ethtools ops to work in a multiple tree setup since we can > no longer assume a single tree is supported > > - finally conver the bcm_sf2 driver to be a true platform device driver and > slightly rework its internal vs. external MDIO bus indirect read/writes to > be cleaner David, I cleaned up my mess in patchwork to leave just the relevant patches for you to review and apply, sorry about that, it's Friday. -- Florian
[PATCH net-next] net: dsa: bcm_sf2: Implement FDB operations
Add support for the FDB add, delete, and dump operations. The add and delete operations are implemented using directed ARL operations using the specified MAC address and consist in a read operation, write and readback operation. The dump operation consists in using the ARL search and software filtering entries which are not for the desired port. Signed-off-by: Florian Fainelli <f.faine...@gmail.com> --- drivers/net/dsa/bcm_sf2.c | 236 + drivers/net/dsa/bcm_sf2.h | 56 ++ drivers/net/dsa/bcm_sf2_regs.h | 43 3 files changed, 335 insertions(+) diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index 9d56515f4c4d..4f32b8a530bf 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c @@ -25,6 +25,8 @@ #include #include #include +#include +#include #include "bcm_sf2.h" #include "bcm_sf2_regs.h" @@ -555,6 +557,236 @@ static int bcm_sf2_sw_br_set_stp_state(struct dsa_switch *ds, int port, return 0; } +/* Address Resolution Logic routines */ +static int bcm_sf2_arl_op_wait(struct bcm_sf2_priv *priv) +{ + unsigned int timeout = 10; + u32 reg; + + do { + reg = core_readl(priv, CORE_ARLA_RWCTL); + if (!(reg & ARL_STRTDN)) + return 0; + + usleep_range(1000, 2000); + } while (timeout--); + + return -ETIMEDOUT; +} + +static int bcm_sf2_arl_rw_op(struct bcm_sf2_priv *priv, unsigned int op) +{ + u32 cmd; + + if (op > ARL_RW) + return -EINVAL; + + cmd = core_readl(priv, CORE_ARLA_RWCTL); + cmd &= ~IVL_SVL_SELECT; + cmd |= ARL_STRTDN; + if (op) + cmd |= ARL_RW; + else + cmd &= ~ARL_RW; + core_writel(priv, cmd, CORE_ARLA_RWCTL); + + return bcm_sf2_arl_op_wait(priv); +} + +static int bcm_sf2_arl_read(struct bcm_sf2_priv *priv, u64 mac, + u16 vid, struct bcm_sf2_arl_entry *ent, u8 *idx, + bool is_valid) +{ + unsigned int i; + int ret; + + ret = bcm_sf2_arl_op_wait(priv); + if (ret) + return ret; + + /* Read the 4 bins */ + for (i = 0; i < 4; i++) { + u64 mac_vid; + u32 fwd_entry; + + mac_vid = core_readq(priv, CORE_ARLA_MACVID_ENTRY(i)); + fwd_entry = core_readl(priv, CORE_ARLA_FWD_ENTRY(i)); + bcm_sf2_arl_to_entry(ent, mac_vid, fwd_entry); + + if (ent->is_valid && is_valid) { + *idx = i; + return 0; + } + + /* This is the MAC we just deleted */ + if (!is_valid && (mac_vid & mac)) + return 0; + } + + return -ENOENT; +} + +static int bcm_sf2_arl_op(struct bcm_sf2_priv *priv, int op, int port, + const unsigned char *addr, u16 vid, bool is_valid) +{ + struct bcm_sf2_arl_entry ent; + u32 fwd_entry; + u64 mac, mac_vid = 0; + u8 idx = 0; + int ret; + + /* Convert the array into a 64-bit MAC */ + mac = bcm_sf2_mac_to_u64(addr); + + /* Perform a read for the given MAC and VID */ + core_writeq(priv, mac, CORE_ARLA_MAC); + core_writel(priv, vid, CORE_ARLA_VID); + + /* Issue a read operation for this MAC */ + ret = bcm_sf2_arl_rw_op(priv, 1); + if (ret) + return ret; + + ret = bcm_sf2_arl_read(priv, mac, vid, , , is_valid); + /* If this is a read, just finish now */ + if (op) + return ret; + + /* We could not find a matching MAC, so reset to a new entry */ + if (ret) { + fwd_entry = 0; + idx = 0; + } + + memset(, 0, sizeof(ent)); + ent.port = port; + ent.is_valid = is_valid; + ent.vid = vid; + ent.is_static = true; + memcpy(ent.mac, addr, ETH_ALEN); + bcm_sf2_arl_from_entry(_vid, _entry, ); + + core_writeq(priv, mac_vid, CORE_ARLA_MACVID_ENTRY(idx)); + core_writel(priv, fwd_entry, CORE_ARLA_FWD_ENTRY(idx)); + + ret = bcm_sf2_arl_rw_op(priv, 0); + if (ret) + return ret; + + /* Re-read the entry to check */ + return bcm_sf2_arl_read(priv, mac, vid, , , is_valid); +} + +static int bcm_sf2_sw_fdb_prepare(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_fdb *fdb, + struct switchdev_trans *trans) +{ + /* We do not need to do anything specific here yet */ + return 0; +} + +static int bcm_sf2_sw_fdb_add(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_fdb *fdb, + struct switchdev_trans *trans) +{ + struct bcm_sf2_p
[PATCH net-next 6/9] net: dsa: Add initialization helper for CPU port ethtool_ops
Add a helper function: dsa_cpu_port_ethtool_init() which initializes a custom ethtool_ops structure with custom DSA ethtool operations for CPU ports. This is a preliminary change to move the initialization outside of net/dsa/slave.c. Signed-off-by: Florian Fainelli <f.faine...@gmail.com> --- net/dsa/dsa_priv.h | 1 + net/dsa/slave.c| 14 -- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h index b42f1a5f95f3..106a9f067f94 100644 --- a/net/dsa/dsa_priv.h +++ b/net/dsa/dsa_priv.h @@ -58,6 +58,7 @@ const struct dsa_device_ops *dsa_resolve_tag_protocol(int tag_protocol); /* slave.c */ extern const struct dsa_device_ops notag_netdev_ops; void dsa_slave_mii_bus_init(struct dsa_switch *ds); +void dsa_cpu_port_ethtool_init(struct ethtool_ops *ops); int dsa_slave_create(struct dsa_switch *ds, struct device *parent, int port, const char *name); void dsa_slave_destroy(struct net_device *slave_dev); diff --git a/net/dsa/slave.c b/net/dsa/slave.c index a51dfedf0014..8d159932e082 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -865,6 +865,13 @@ static void dsa_slave_poll_controller(struct net_device *dev) } #endif +void dsa_cpu_port_ethtool_init(struct ethtool_ops *ops) +{ + ops->get_sset_count = dsa_cpu_port_get_sset_count; + ops->get_ethtool_stats = dsa_cpu_port_get_ethtool_stats; + ops->get_strings = dsa_cpu_port_get_strings; +} + static const struct ethtool_ops dsa_slave_ethtool_ops = { .get_settings = dsa_slave_get_settings, .set_settings = dsa_slave_set_settings, @@ -1124,12 +1131,7 @@ int dsa_slave_create(struct dsa_switch *ds, struct device *parent, sizeof(struct ethtool_ops)); memcpy(_cpu_port_ethtool_ops, >master_ethtool_ops, sizeof(struct ethtool_ops)); - dsa_cpu_port_ethtool_ops.get_sset_count = - dsa_cpu_port_get_sset_count; - dsa_cpu_port_ethtool_ops.get_ethtool_stats = - dsa_cpu_port_get_ethtool_stats; - dsa_cpu_port_ethtool_ops.get_strings = - dsa_cpu_port_get_strings; + dsa_cpu_port_ethtool_init(_cpu_port_ethtool_ops); master->ethtool_ops = _cpu_port_ethtool_ops; } eth_hw_addr_inherit(slave_dev, master); -- 2.7.4
[PATCH net-next 7/9] net: dsa: Initialize CPU port ethtool ops per tree
Now that we can properly support multiple distinct trees in the system, using a global variable: dsa_cpu_port_ethtool_ops is getting clobbered as soon as the second switch tree gets probed, and we don't want that. We need to move this to be dynamically allocated, and since we can't really be comparing addresses anymore to determine first time initialization versus any other times, just move this to dsa.c and dsa2.c where the remainder of the dst/ds initialization happens. Signed-off-by: Florian Fainelli <f.faine...@gmail.com> --- net/dsa/dsa.c | 28 net/dsa/dsa2.c | 2 +- net/dsa/dsa_priv.h | 2 ++ net/dsa/slave.c| 10 -- 4 files changed, 31 insertions(+), 11 deletions(-) diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c index ebc29a1bee08..8fb8de6fb82d 100644 --- a/net/dsa/dsa.c +++ b/net/dsa/dsa.c @@ -266,6 +266,30 @@ const struct dsa_device_ops *dsa_resolve_tag_protocol(int tag_protocol) return ops; } +int dsa_cpu_port_ethtool_setup(struct dsa_switch_tree *dst, + struct dsa_switch *ds) +{ + struct net_device *master; + struct ethtool_ops *cpu_ops; + + master = ds->dst->master_netdev; + if (ds->master_netdev) + master = ds->master_netdev; + + cpu_ops = devm_kzalloc(ds->dev, sizeof(*cpu_ops), GFP_KERNEL); + if (!cpu_ops) + return -ENOMEM; + + memcpy(>master_ethtool_ops, master->ethtool_ops, + sizeof(struct ethtool_ops)); + memcpy(cpu_ops, >master_ethtool_ops, + sizeof(struct ethtool_ops)); + dsa_cpu_port_ethtool_init(cpu_ops); + master->ethtool_ops = cpu_ops; + + return 0; +} + static int dsa_switch_setup_one(struct dsa_switch *ds, struct device *parent) { struct dsa_switch_driver *drv = ds->drv; @@ -379,6 +403,10 @@ static int dsa_switch_setup_one(struct dsa_switch *ds, struct device *parent) ret = 0; } + ret = dsa_cpu_port_ethtool_setup(dst, ds); + if (ret) + return ret; + #ifdef CONFIG_NET_DSA_HWMON /* If the switch provides a temperature sensor, * register with hardware monitoring subsystem. diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c index e8386157de30..938262010524 100644 --- a/net/dsa/dsa2.c +++ b/net/dsa/dsa2.c @@ -346,7 +346,7 @@ static int dsa_ds_apply(struct dsa_switch_tree *dst, struct dsa_switch *ds) continue; } - return 0; + return dsa_cpu_port_ethtool_setup(dst, ds); } static void dsa_ds_unapply(struct dsa_switch_tree *dst, struct dsa_switch *ds) diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h index 106a9f067f94..3bb88b2fb580 100644 --- a/net/dsa/dsa_priv.h +++ b/net/dsa/dsa_priv.h @@ -54,6 +54,8 @@ int dsa_cpu_dsa_setup(struct dsa_switch *ds, struct device *dev, struct device_node *port_dn, int port); void dsa_cpu_dsa_destroy(struct device_node *port_dn); const struct dsa_device_ops *dsa_resolve_tag_protocol(int tag_protocol); +int dsa_cpu_port_ethtool_setup(struct dsa_switch_tree *dst, + struct dsa_switch *ds); /* slave.c */ extern const struct dsa_device_ops notag_netdev_ops; diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 8d159932e082..7236eb26dc97 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -892,8 +892,6 @@ static const struct ethtool_ops dsa_slave_ethtool_ops = { .get_eee= dsa_slave_get_eee, }; -static struct ethtool_ops dsa_cpu_port_ethtool_ops; - static const struct net_device_ops dsa_slave_netdev_ops = { .ndo_open = dsa_slave_open, .ndo_stop = dsa_slave_close, @@ -1126,14 +1124,6 @@ int dsa_slave_create(struct dsa_switch *ds, struct device *parent, slave_dev->features = master->vlan_features; slave_dev->ethtool_ops = _slave_ethtool_ops; - if (master->ethtool_ops != _cpu_port_ethtool_ops) { - memcpy(>master_ethtool_ops, master->ethtool_ops, - sizeof(struct ethtool_ops)); - memcpy(_cpu_port_ethtool_ops, >master_ethtool_ops, - sizeof(struct ethtool_ops)); - dsa_cpu_port_ethtool_init(_cpu_port_ethtool_ops); - master->ethtool_ops = _cpu_port_ethtool_ops; - } eth_hw_addr_inherit(slave_dev, master); slave_dev->priv_flags |= IFF_NO_QUEUE; slave_dev->netdev_ops = _slave_netdev_ops; -- 2.7.4
[PATCH net-next 2/9] net: dsa: Add support for parsing the old binding
Extend dsa2.c to support parsing for the old binding, which mostly means looking for more or less the same properties in different places. Signed-off-by: Florian Fainelli <f.faine...@gmail.com> --- net/dsa/dsa2.c | 142 ++--- 1 file changed, 126 insertions(+), 16 deletions(-) diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c index b5640d8ffbae..23273fd984a8 100644 --- a/net/dsa/dsa2.c +++ b/net/dsa/dsa2.c @@ -408,21 +408,11 @@ static void dsa_dst_unapply(struct dsa_switch_tree *dst) dst->applied = false; } -static int dsa_cpu_parse(struct device_node *port, u32 index, -struct dsa_switch_tree *dst, -struct dsa_switch *ds) +static int _dsa_cpu_parse(struct dsa_switch_tree *dst, + struct dsa_switch *ds, + struct net_device *ethernet_dev, + u32 index) { - struct net_device *ethernet_dev; - struct device_node *ethernet; - - ethernet = of_parse_phandle(port, "ethernet", 0); - if (!ethernet) - return -EINVAL; - - ethernet_dev = of_find_net_device_by_node(ethernet); - if (!ethernet_dev) - return -EPROBE_DEFER; - if (!ds->master_netdev) ds->master_netdev = ethernet_dev; @@ -445,6 +435,24 @@ static int dsa_cpu_parse(struct device_node *port, u32 index, return 0; } +static int dsa_cpu_parse(struct device_node *port, u32 index, +struct dsa_switch_tree *dst, +struct dsa_switch *ds) +{ + struct net_device *ethernet_dev; + struct device_node *ethernet; + + ethernet = of_parse_phandle(port, "ethernet", 0); + if (!ethernet) + return -EINVAL; + + ethernet_dev = of_find_net_device_by_node(ethernet); + if (!ethernet_dev) + return -EPROBE_DEFER; + + return _dsa_cpu_parse(dst, ds, ethernet_dev, index); +} + static int dsa_ds_parse(struct dsa_switch_tree *dst, struct dsa_switch *ds) { struct device_node *port; @@ -552,6 +560,108 @@ static struct device_node *dsa_get_ports(struct dsa_switch *ds, return ports; } +static int _dsa_register_switch_legacy(struct dsa_switch *ds, struct device_node *np) +{ + const char *compat = of_get_property(np, "compatible", NULL); + struct device_node *dn, *ethernet; + struct net_device *ethernet_dev; + struct dsa_switch_tree *dst; + u32 tree = 0, index; + int err; + + /* Tree is implied by how many devices are present in the DT with the +* supported compatible strings from net/dsa/dsa.c +*/ + for_each_compatible_node(dn, NULL, compat) { + if (dn != np) + tree++; + } + + /* index is present in the "reg" property, second cell */ + err = of_property_read_u32_index(np->child, "reg", 1, ); + if (err) + return err; + + if (index >= DSA_MAX_SWITCHES) + return -EINVAL; + + err = dsa_parse_ports_dn(np->child, ds); + if (err) + return err; + + dst = dsa_get_dst(tree); + if (!dst) { + dst = dsa_add_dst(tree); + if (!dst) + return -ENOMEM; + } + + if (dst->ds[index]) { + err = -EBUSY; + goto out; + } + + ds->dst = dst; + ds->index = index; + dsa_dst_add_ds(dst, ds, index); + + err = dsa_dst_complete(dst); + if (err < 0) + goto out; + + if (err == 1) { + /* Not all switches registered yet */ + err = 0; + goto out; + } + + if (dst->applied) { + pr_info("DSA: Disjoint trees?\n"); + err = -EINVAL; + goto out_del_dst; + } + + ethernet = of_parse_phandle(np, "dsa,ethernet", 0); + if (!ethernet) { + err = -EINVAL; + goto out_del_dst; + } + + ethernet_dev = of_find_net_device_by_node(ethernet); + if (!ethernet_dev) { + err = -EPROBE_DEFER; + goto out_del_dst; + } + + err = _dsa_cpu_parse(dst, ds, ethernet_dev, index); + if (err) + goto out_del_dst; + + if (!dst->master_netdev) { + pr_warn("Tree has no master device\n"); + goto out_del_dst; + } + + pr_info("DSA: tree %d parsed\n", dst->tree); + + err = dsa_dst_apply(dst); + if (err) { + dsa_dst_unapply(dst); + goto out_del_dst; + } + + dsa_put_dst(dst); + + return 0; + +out_del_dst: + dsa_dst_del_ds(dst, ds, ds->index); +out: + dsa_put_dst(dst);
[PATCH net-next 9/9] net: dsa: bcm_sf2: Register our slave MDIO bus
Register a slave MDIO bus which allows us to divert problematic read/writes towards conflicting pseudo-PHY address (30). Do no longer rely on DSA's slave_mii_bus, but instead provide our own implementation which offers more flexibility as to what to do, and when to register it. Signed-off-by: Florian Fainelli <f.faine...@gmail.com> --- drivers/net/dsa/bcm_sf2.c | 141 -- drivers/net/dsa/bcm_sf2.h | 6 ++ 2 files changed, 106 insertions(+), 41 deletions(-) diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index 8dac74a6b5df..502ca65435bf 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -948,23 +949,6 @@ static int bcm_sf2_sw_setup(struct dsa_switch *ds) bcm_sf2_port_disable(ds, port, NULL); } - /* Include the pseudo-PHY address and the broadcast PHY address to -* divert reads towards our workaround. This is only required for -* 7445D0, since 7445E0 disconnects the internal switch pseudo-PHY such -* that we can use the regular SWITCH_MDIO master controller instead. -* -* By default, DSA initializes ds->phys_mii_mask to -* ds->enabled_port_mask to have a 1:1 mapping between Port address -* and PHY address in order to utilize the slave_mii_bus instance to -* read from Port PHYs. This is not what we want here, so we -* initialize phys_mii_mask 0 to always utilize the "master" MDIO -* bus backed by the "mdio-unimac" driver. -*/ - if (of_machine_is_compatible("brcm,bcm7445d0")) - ds->phys_mii_mask |= ((1 << BRCM_PSEUDO_PHY_ADDR) | (1 << 0)); - else - ds->phys_mii_mask = 0; - return 0; } @@ -985,10 +969,9 @@ static u32 bcm_sf2_sw_get_phy_flags(struct dsa_switch *ds, int port) return priv->hw_params.gphy_rev; } -static int bcm_sf2_sw_indir_rw(struct dsa_switch *ds, int op, int addr, +static int bcm_sf2_sw_indir_rw(struct bcm_sf2_priv *priv, int op, int addr, int regnum, u16 val) { - struct bcm_sf2_priv *priv = ds_to_priv(ds); int ret = 0; u32 reg; @@ -1017,32 +1000,31 @@ static int bcm_sf2_sw_indir_rw(struct dsa_switch *ds, int op, int addr, return ret & 0x; } -static int bcm_sf2_sw_phy_read(struct dsa_switch *ds, int addr, int regnum) +static int bcm_sf2_sw_phy_read(struct mii_bus *bus, int addr, int regnum) { - /* Intercept reads from the MDIO broadcast address or Broadcom -* pseudo-PHY address + struct bcm_sf2_priv *priv = bus->priv; + + /* Intercept reads from Broadcom pseudo-PHY address, else, send +* them to our master MDIO bus controller */ - switch (addr) { - case 0: - case BRCM_PSEUDO_PHY_ADDR: - return bcm_sf2_sw_indir_rw(ds, 1, addr, regnum, 0); - default: - return 0x; - } + if (addr == BRCM_PSEUDO_PHY_ADDR && priv->indir_phy_mask & BIT(addr)) + return bcm_sf2_sw_indir_rw(priv, 1, addr, regnum, 0); + else + return mdiobus_read(priv->master_mii_bus, addr, regnum); } -static int bcm_sf2_sw_phy_write(struct dsa_switch *ds, int addr, int regnum, +static int bcm_sf2_sw_phy_write(struct mii_bus *bus, int addr, int regnum, u16 val) { - /* Intercept writes to the MDIO broadcast address or Broadcom -* pseudo-PHY address + struct bcm_sf2_priv *priv = bus->priv; + + /* Intercept writes to the Broadcom pseudo-PHY address, else, +* send them to our master MDIO bus controller */ - switch (addr) { - case 0: - case BRCM_PSEUDO_PHY_ADDR: - bcm_sf2_sw_indir_rw(ds, 0, addr, regnum, val); - break; - } + if (addr == BRCM_PSEUDO_PHY_ADDR && priv->indir_phy_mask & BIT(addr)) + bcm_sf2_sw_indir_rw(priv, 0, addr, regnum, val); + else + mdiobus_write(priv->master_mii_bus, addr, regnum, val); return 0; } @@ -1283,8 +1265,6 @@ static struct dsa_switch_driver bcm_sf2_switch_ops = { .setup = bcm_sf2_sw_setup, .set_addr = bcm_sf2_sw_set_addr, .get_phy_flags = bcm_sf2_sw_get_phy_flags, - .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, @@ -1307,6 +1287,75 @@ static struct dsa_switch_driver bcm_sf2_switch_ops = { .port_fdb_dump = bcm_sf2_sw_
Re: [PATCH net-next] net: dsa: Provide CPU port statistics to master netdev
On 06/03/2016 05:05 PM, Florian Fainelli wrote: > This patch overloads the DSA master netdev, aka CPU Ethernet MAC to also > include switch-side statistics, which is useful for debugging purposes, > when the switch is not properly connected to the Ethernet MAC (duplex > mismatch, (RG)MII electrical issues etc.). > > We accomplish this by retaining the original copy of the master netdev's > ethtool_ops, and just overload the 3 operations we care about: > get_sset_count, get_strings and get_ethtool_stats so as to intercept > these calls and call into the original master_netdev ethtool_ops, plus > our own. > > We take this approach as opposed to providing a set of DSA helper > functions that would retrive the CPU port's statistics, because the > entire purpose of DSA is to allow unmodified Ethernet MAC drivers to be > used as CPU conduit interfaces, therefore, statistics overlay in such > drivers would simply not scale. Disregard this patch, it was left in the patches folder... -- Florian
[PATCH net-next 3/9] net: dsa: Provide unique DSA slave MII bus names
In case we have multiples trees and switches with the same index, we need to add another discriminating id: the switch tree. Signed-off-by: Florian Fainelli <f.faine...@gmail.com> --- net/dsa/slave.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 15a492261895..a51dfedf0014 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -49,7 +49,8 @@ void dsa_slave_mii_bus_init(struct dsa_switch *ds) ds->slave_mii_bus->name = "dsa slave smi"; ds->slave_mii_bus->read = dsa_slave_phy_read; ds->slave_mii_bus->write = dsa_slave_phy_write; - snprintf(ds->slave_mii_bus->id, MII_BUS_ID_SIZE, "dsa-%d", ds->index); + snprintf(ds->slave_mii_bus->id, MII_BUS_ID_SIZE, "dsa-%d.%d", +ds->dst->tree, ds->index); ds->slave_mii_bus->parent = ds->dev; ds->slave_mii_bus->phy_mask = ~ds->phys_mii_mask; } -- 2.7.4
[PATCH net-next 6/7] net: dsa: bcm_sf2: Make it a real platform device driver
The Broadcom Starfighter 2 switch driver should be a proper platform driver, now that the DSA code has been updated to allow that, register a switch device, feed it with the proper configuration data coming from Device Tree and register our switch device with DSA. The bulk of the changes consist in moving what bcm_sf2_sw_setup() did into the platform driver probe function. Signed-off-by: Florian Fainelli <f.faine...@gmail.com> --- drivers/net/dsa/bcm_sf2.c | 251 -- net/dsa/dsa.c | 1 - 2 files changed, 151 insertions(+), 101 deletions(-) diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index 73df91bb0466..8dac74a6b5df 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c @@ -934,77 +934,8 @@ static void bcm_sf2_identify_ports(struct bcm_sf2_priv *priv, 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(>indir_lock); - mutex_init(>stats_mutex); - - /* All the interesting properties are at the parent device_node -* level -*/ - dn = ds->cd->of_node->parent; - bcm_sf2_identify_ports(priv, ds->cd->of_node); - - priv->irq0 = irq_of_parse_and_map(dn, 0); - priv->irq1 = irq_of_parse_and_map(dn, 1); - - base = >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]); - ret = -ENOMEM; - goto out_unmap; - } - base++; - } - - ret = bcm_sf2_sw_rst(priv); - if (ret) { - pr_err("unable to software reset switch: %d\n", ret); - goto out_unmap; - } - - /* Disable all interrupts and request them */ - bcm_sf2_intr_disable(priv); - - 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", ->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++) { @@ -1034,31 +965,7 @@ static int bcm_sf2_sw_setup(struct dsa_switch *ds) else ds->phys_mii_mask = 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); - - rev = reg_readl(priv, REG_PHY_REVISION); - priv->hw_params.gphy_rev = rev & PHY_REVISION_MASK; - - pr_info("Starfighter 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 = >core; - for (i = 0; i < BCM_SF2_REGS_NUM; i++) { - if (*base) - iounmap(*base); - base++; - } - return ret; } static int bcm_sf2_sw_set_addr(struct dsa_switch *ds, u8 *addr) @@ -1370,7 +1277,7 @@ static int bcm_sf2_sw_set_wol(struct dsa_switch *ds, int port, return p->ethtool_ops->
[PATCH net-next 8/9] net: dsa: bcm_sf2: Make it a real platform device driver
The Broadcom Starfighter 2 switch driver should be a proper platform driver, now that the DSA code has been updated to allow that, register a switch device, feed it with the proper configuration data coming from Device Tree and register our switch device with DSA. The bulk of the changes consist in moving what bcm_sf2_sw_setup() did into the platform driver probe function. Signed-off-by: Florian Fainelli <f.faine...@gmail.com> --- drivers/net/dsa/bcm_sf2.c | 251 -- net/dsa/dsa.c | 1 - 2 files changed, 151 insertions(+), 101 deletions(-) diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index 73df91bb0466..8dac74a6b5df 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c @@ -934,77 +934,8 @@ static void bcm_sf2_identify_ports(struct bcm_sf2_priv *priv, 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(>indir_lock); - mutex_init(>stats_mutex); - - /* All the interesting properties are at the parent device_node -* level -*/ - dn = ds->cd->of_node->parent; - bcm_sf2_identify_ports(priv, ds->cd->of_node); - - priv->irq0 = irq_of_parse_and_map(dn, 0); - priv->irq1 = irq_of_parse_and_map(dn, 1); - - base = >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]); - ret = -ENOMEM; - goto out_unmap; - } - base++; - } - - ret = bcm_sf2_sw_rst(priv); - if (ret) { - pr_err("unable to software reset switch: %d\n", ret); - goto out_unmap; - } - - /* Disable all interrupts and request them */ - bcm_sf2_intr_disable(priv); - - 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", ->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++) { @@ -1034,31 +965,7 @@ static int bcm_sf2_sw_setup(struct dsa_switch *ds) else ds->phys_mii_mask = 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); - - rev = reg_readl(priv, REG_PHY_REVISION); - priv->hw_params.gphy_rev = rev & PHY_REVISION_MASK; - - pr_info("Starfighter 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 = >core; - for (i = 0; i < BCM_SF2_REGS_NUM; i++) { - if (*base) - iounmap(*base); - base++; - } - return ret; } static int bcm_sf2_sw_set_addr(struct dsa_switch *ds, u8 *addr) @@ -1370,7 +1277,7 @@ static int bcm_sf2_sw_set_wol(struct dsa_switch *ds, int port, return p->ethtool_ops->
Re: [PATCH net-next 12/17] net: dsa: Make mdio bus optional
On 06/03/2016 09:44 AM, Andrew Lunn wrote: > The switch may want to instantiate its own MDIO bus. Only do it > centrally if the switch has not already created one, and the read op > is implemented. > > Signed-off-by: Andrew Lunn <and...@lunn.ch> Reviewed-by: Florian Fainelli <f.faine...@gmail.com> -- Florian
[PATCH net v2 0/3] Documentation: dsa: misc fixes
Hi David, Here are some miscelaneous documentation fixes for DSA, I targeted "net" because these are not functional code changes, but still documentation fixes per-se. Changes in v2: - reword what the port_vlan_filtering is about based on feedback from Vivien and Ido Florian Fainelli (3): Documentation: networking: dsa: Remove poll_link description Documentation: networking: dsa: Remove priv_size description Documentation: networking: dsa: Describe port_vlan_filtering Documentation/networking/dsa/dsa.txt | 17 ++--- 1 file changed, 10 insertions(+), 7 deletions(-) -- 2.7.4
[PATCH net v2 1/3] Documentation: networking: dsa: Remove poll_link description
This function has been removed in 4baee937b8d5 ("net: dsa: remove DSA link polling") in favor of using the PHYLIB polling mechanism. Reviewed-by: Vivien Didelot <vivien.dide...@savoirfairelinux.com> Signed-off-by: Florian Fainelli <f.faine...@gmail.com> --- Documentation/networking/dsa/dsa.txt | 5 - 1 file changed, 5 deletions(-) diff --git a/Documentation/networking/dsa/dsa.txt b/Documentation/networking/dsa/dsa.txt index 631b0f7ae16f..8303eb8ced79 100644 --- a/Documentation/networking/dsa/dsa.txt +++ b/Documentation/networking/dsa/dsa.txt @@ -416,11 +416,6 @@ PHY devices and link management to the switch port MDIO registers. If unavailable return a negative error code. -- poll_link: Function invoked by DSA to query the link state of the switch - builtin Ethernet PHYs, per port. This function is responsible for calling - netif_carrier_{on,off} when appropriate, and can be used to poll all ports in a - single call. Executes from workqueue context. - - adjust_link: Function invoked by the PHY library when a slave network device is attached to a PHY device. This function is responsible for appropriately configuring the switch port link parameters: speed, duplex, pause based on -- 2.7.4
[PATCH net v2 2/3] Documentation: networking: dsa: Remove priv_size description
We no longer have a priv_size structure member since 5feebd0a8a79 ("net: dsa: Remove allocation of driver private memory") Reviewed-by: Vivien Didelot <vivien.dide...@savoirfairelinux.com> Signed-off-by: Florian Fainelli <f.faine...@gmail.com> --- Documentation/networking/dsa/dsa.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/Documentation/networking/dsa/dsa.txt b/Documentation/networking/dsa/dsa.txt index 8303eb8ced79..411b57fd73aa 100644 --- a/Documentation/networking/dsa/dsa.txt +++ b/Documentation/networking/dsa/dsa.txt @@ -369,8 +369,6 @@ does not allocate any driver private context space. Switch configuration -- priv_size: additional size needed by the switch driver for its private context - - tag_protocol: this is to indicate what kind of tagging protocol is supported, should be a valid value from the dsa_tag_protocol enum -- 2.7.4
[PATCH net v2 3/3] Documentation: networking: dsa: Describe port_vlan_filtering
Described what the port_vlan_filtering function is supposed to accomplish. Fixes: fb2dabad69f0 ("net: dsa: support VLAN filtering switchdev attr") Signed-off-by: Florian Fainelli <f.faine...@gmail.com> --- Documentation/networking/dsa/dsa.txt | 10 ++ 1 file changed, 10 insertions(+) diff --git a/Documentation/networking/dsa/dsa.txt b/Documentation/networking/dsa/dsa.txt index 411b57fd73aa..9d05ed7f7da5 100644 --- a/Documentation/networking/dsa/dsa.txt +++ b/Documentation/networking/dsa/dsa.txt @@ -535,6 +535,16 @@ Bridge layer Bridge VLAN filtering - +- port_vlan_filtering: bridge layer function invoked when the bridge gets + configured for turning on or off VLAN filtering. If nothing specific needs to + be done at the hardware level, this callback does not need to be implemented. + When VLAN filtering is turned on, the hardware must be programmed with + rejecting 802.1Q frames which have VLAN IDs outside of the programmed allowed + VLAN ID map/rules. If there is no PVID programmed into the switch port, + untagged frames must be rejected as well. When turned off the switch must + accept any 802.1Q frames irrespective of their VLAN ID, and untagged frames are + allowed. + - port_vlan_prepare: bridge layer function invoked when the bridge prepares the configuration of a VLAN on the given port. If the operation is not supported by the hardware, this function should return -EOPNOTSUPP to inform the bridge -- 2.7.4
Re: [PATCH net-next v4 0/7] vmxnet3: upgrade to version 3
On 06/14/2016 11:52 AM, Shrikrishna Khare wrote: > This patchset upgrades vmxnet3 to version 3. > > Changes in v2: > - Following patch is updated. See that patch for details: >vmxnet3: add support for get_coalesce, set_coalesce ethtool > > Changes in v3: > - fix subject line to use vmxnet3: instead of Driver:Vmxnet3 > - resubmit when net-next is open > > Changes in v4: > - Following patch is updated. See that patch for details: >vmxnet3: add support for get_coalesce, set_coalesce ethtool You really need to improve your commit messages, because right now they are inexistent or too obvious to be of any value. A reviewer must be introduced to what code changes he/she is going to review next by looking at the diff and whether this will match or not the description that was provided in the commit message. -- Florian
Re: [PATCH 04/15] drivers: net: cpsw: ethtool: fix accessing to suspended device
On 06/15/2016 04:55 AM, Grygorii Strashko wrote: > The CPSW might be suspended by RPM if all ethX interfaces are down, > but it still could be accesible through ethtool interfce. In this case > ethtool operations, requiring registers access, will cause L3 errors and > CPSW crash. > > Hence, fix it by adding RPM get/put calls in ethtool callbcaks which > can access CPSW registers: .set_coalesce(), .get_ethtool_stats(), > .set_pauseparam(), .get_regs() Provided that you implement an ethtool_ops::begin, it will be called before each ethtool operation runs, so that could allow you to eliminate some of the duplication here. Conversely ethtool_ops::end terminates each operation and can be used for that purpose. > > Signed-off-by: Grygorii Strashko> --- > drivers/net/ethernet/ti/cpsw.c | 36 +++- > 1 file changed, 35 insertions(+), 1 deletion(-) > > diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c > index ba81d4e..1ba0c09 100644 > --- a/drivers/net/ethernet/ti/cpsw.c > +++ b/drivers/net/ethernet/ti/cpsw.c > @@ -931,6 +931,13 @@ static int cpsw_set_coalesce(struct net_device *ndev, > u32 prescale = 0; > u32 addnl_dvdr = 1; > u32 coal_intvl = 0; > + int ret; > + > + ret = pm_runtime_get_sync(>pdev->dev); > + if (ret < 0) { > + pm_runtime_put_noidle(>pdev->dev); > + return ret; > + } > > coal_intvl = coal->rx_coalesce_usecs; > > @@ -985,6 +992,8 @@ update_return: > priv->coal_intvl = coal_intvl; > } > > + pm_runtime_put(>pdev->dev); > + > return 0; > } > > @@ -1022,7 +1031,13 @@ static void cpsw_get_ethtool_stats(struct net_device > *ndev, > struct cpdma_chan_stats tx_stats; > u32 val; > u8 *p; > - int i; > + int i, ret; > + > + ret = pm_runtime_get_sync(>pdev->dev); > + if (ret < 0) { > + pm_runtime_put_noidle(>pdev->dev); > + return; > + } > > /* Collect Davinci CPDMA stats for Rx and Tx Channel */ > cpdma_chan_get_stats(priv->rxch, _stats); > @@ -1049,6 +1064,8 @@ static void cpsw_get_ethtool_stats(struct net_device > *ndev, > break; > } > } > + > + pm_runtime_put(>pdev->dev); > } > > static int cpsw_common_res_usage_state(struct cpsw_priv *priv) > @@ -1780,11 +1797,20 @@ static void cpsw_get_regs(struct net_device *ndev, > { > struct cpsw_priv *priv = netdev_priv(ndev); > u32 *reg = p; > + int ret; > + > + ret = pm_runtime_get_sync(>pdev->dev); > + if (ret < 0) { > + pm_runtime_put_noidle(>pdev->dev); > + return; > + } > > /* update CPSW IP version */ > regs->version = priv->version; > > cpsw_ale_dump(priv->ale, reg); > + > + pm_runtime_put(>pdev->dev); > } > > static void cpsw_get_drvinfo(struct net_device *ndev, > @@ -1902,12 +1928,20 @@ static int cpsw_set_pauseparam(struct net_device > *ndev, > { > struct cpsw_priv *priv = netdev_priv(ndev); > bool link; > + int ret; > + > + ret = pm_runtime_get_sync(>pdev->dev); > + if (ret < 0) { > + pm_runtime_put_noidle(>pdev->dev); > + return ret; > + } > > priv->rx_pause = pause->rx_pause ? true : false; > priv->tx_pause = pause->tx_pause ? true : false; > > for_each_slave(priv, _cpsw_adjust_link, priv, ); > > + pm_runtime_put(>pdev->dev); > return 0; > } > > -- Florian
[PATCH net-next v2 5/5] net: dsa: bcm_sf2: Register our slave MDIO bus
Register a slave MDIO bus which allows us to divert problematic read/writes towards conflicting pseudo-PHY address (30). Do no longer rely on DSA's slave_mii_bus, but instead provide our own implementation which offers more flexibility as to what to do, and when to register it. We need to register it by the time we are able to get access to our memory mapped registers, which is not until drv->setup() time. In order to avoid forward declarations, we need to re-order the function bodies a bit. Signed-off-by: Florian Fainelli <f.faine...@gmail.com> --- drivers/net/dsa/bcm_sf2.c | 215 +- drivers/net/dsa/bcm_sf2.h | 6 ++ 2 files changed, 140 insertions(+), 81 deletions(-) diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index 73df91bb0466..8026fc21c4fb 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -836,6 +837,66 @@ static int bcm_sf2_sw_fdb_dump(struct dsa_switch *ds, int port, return 0; } +static int bcm_sf2_sw_indir_rw(struct bcm_sf2_priv *priv, int op, int addr, + int regnum, u16 val) +{ + 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 & 0x; +} + +static int bcm_sf2_sw_mdio_read(struct mii_bus *bus, int addr, int regnum) +{ + struct bcm_sf2_priv *priv = bus->priv; + + /* Intercept reads from Broadcom pseudo-PHY address, else, send +* them to our master MDIO bus controller +*/ + if (addr == BRCM_PSEUDO_PHY_ADDR && priv->indir_phy_mask & BIT(addr)) + return bcm_sf2_sw_indir_rw(priv, 1, addr, regnum, 0); + else + return mdiobus_read(priv->master_mii_bus, addr, regnum); +} + +static int bcm_sf2_sw_mdio_write(struct mii_bus *bus, int addr, int regnum, +u16 val) +{ + struct bcm_sf2_priv *priv = bus->priv; + + /* Intercept writes to the Broadcom pseudo-PHY address, else, +* send them to our master MDIO bus controller +*/ + if (addr == BRCM_PSEUDO_PHY_ADDR && priv->indir_phy_mask & BIT(addr)) + bcm_sf2_sw_indir_rw(priv, 0, addr, regnum, val); + else + mdiobus_write(priv->master_mii_bus, addr, regnum, val); + + return 0; +} + static irqreturn_t bcm_sf2_switch_0_isr(int irq, void *dev_id) { struct bcm_sf2_priv *priv = dev_id; @@ -932,6 +993,72 @@ static void bcm_sf2_identify_ports(struct bcm_sf2_priv *priv, } } +static int bcm_sf2_mdio_register(struct dsa_switch *ds) +{ + struct bcm_sf2_priv *priv = ds_to_priv(ds); + struct device_node *dn; + static int index; + int err; + + /* Find our integratd MDIO bus node */ + dn = of_find_compatible_node(NULL, NULL, "brcm,unimac-mdio"); + priv->master_mii_bus = of_mdio_find_bus(dn); + if (!priv->master_mii_bus) + return -EPROBE_DEFER; + + get_device(>master_mii_bus->dev); + priv->master_mii_dn = dn; + + priv->slave_mii_bus = devm_mdiobus_alloc(ds->dev); + if (!priv->slave_mii_bus) + return -ENOMEM; + + priv->slave_mii_bus->priv = priv; + priv->slave_mii_bus->name = "sf2 slave mii"; + priv->slave_mii_bus->read = bcm_sf2_sw_mdio_read; + priv->slave_mii_bus->write = bcm_sf2_sw_mdio_write; + snprintf(priv->slave_mii_bus->id, MII_BUS_ID_SIZE, "sf2-%d", +index++); + priv->slave_mii_bus->dev.of_node = dn; + + /* Include the pseudo-PHY address to divert reads towards our +* workaround. This is only required for 7445D0, since 7445E0 +* disconnects the internal switch pseudo-PHY such that we can use the +* regular SWITCH_MDIO master controller instead. +* +* Here we flag the pseudo PHY as needing special treatment and would +* otherwise make all other PHY read/writes go to the master MDIO bus +* controller that comes with this switch backed by the "mdio-unimac" +* driver. +*/ + if (of_machine_is_compatible("brcm,bcm7445d0")) +