Re: [RFC v8 net-next 00/16] add support for VSC7512 control over SPI

Colin Foster
2022-05-09T18:43:54Z

On Mon, May 09, 2022 at 05:13:05PM +0000, Vladimir Oltean wrote:
> Hi Colin,
>
> On Sun, May 08, 2022 at 11:52:57AM -0700, Colin Foster wrote:
> > The patch set in general is to add support for the VSC7512, and
> > eventually the VSC7511, VSC7513 and VSC7514 devices controlled over
> > SPI. The driver is believed to be fully functional for the internal
> > phy ports (0-3) on the VSC7512. It is not yet functional for SGMII,
> > QSGMII, and SerDes ports.
> >
> > I have mentioned previously:
> > The hardware setup I'm using for development is a beaglebone black, with
> > jumpers from SPI0 to the microchip VSC7512 dev board. The microchip dev
> > board has been modified to not boot from flash, but wait for SPI. An
> > ethernet cable is connected from the beaglebone ethernet to port 0 of
> > the dev board.
> >
> > The relevant sections of the device tree I'm using for the VSC7512 is
> > below. Notably the SGPIO LEDs follow link status and speed from network
> > triggers.
> >
> > In order to make this work, I have modified the cpsw driver, and now the
> > cpsw_new driver, to allow for frames over 1500 bytes. Otherwise the
> > tagging protocol will not work between the beaglebone and the VSC7512. I
> > plan to eventually try to get those changes in mainline, but I don't
> > want to get distracted from my initial goal. I also had to change
> > bonecommon.dtsi to avoid using VLAN 0.
>
> This ti,dual-emac-pvid thing is a really odd thing to put in the device
> tree. But what's the problem with VLAN 0 anyway?

Ahh, I see that was an exchange between me and Grygorii Strashko that
wasn't public. Looking now, it might be VLAN 1...

I'd see "failed to initialize vlan filtering" when I ran "ip link set
dev swp1 master br0" because the default bridge vlan conflicted with
slave_data->dual_emac_res_vlan = port_id;
(drivers/net/ethernet/ti/cpsw_new.c, around line 1325)

My initial attempt was to just change cpsw_port1
ti,dual-emac-pvid=<12>; but that didn't change the behavior. Maybe if I
went back to it again, seeing as I'm much older and wiser than I was
before, I could find the correct device tree solution... Ideally I think
I should have the ability to not enable cpsw_port1 and be good.

But I think the magic was really just to set
slave_data->dual_emac_res_vlan = 10 + port_id; to avoid conflicts.

This became an issue at 5.15, when cpsw_new was rolled in to the .dtsis
I've been using.

>
> >
> > I believe much of the MFD sections are very near feature-complete,
> > whereas the switch section will require ongoing work to enable
> > additional ports / features. This could lead to a couple potential
> > scenarios:
> >
> > The first being patches 1-8 being split into a separate patch set, while
> > patches 9-16 remain in the RFC state. This would offer the pinctrl /
> > sgpio / mdio controller functionality, but no switch control until it is
> > ready.
> >
> > The second would assume the current state of the switch driver is
> > acceptable (or at least very near so) and the current patch set gets an
> > official PATCH set (with minor changes as necessary - e.g. squashing
> > patch 16 into 14). That might be ambitious.
> >
> > The third would be to keep this patch set in RFC until switch
> > functionality is more complete. I'd understand if this was the desired
> > path... but it would mean me having to bug more reviewers.
>
> Considering that the merge window is approaching, I'd say get the
> non-DSA stuff accepted until then, then repost the DSA stuff in ~3 weeks
> from now as non-RFC, once v5.18 is cut and the development for v5.20
> (or whatever the number will be) begins.

That's the approach I'd prefer as well.

>
> > / {
> > vscleds {
> > compatible = "gpio-leds";
> > vscled@0 {
> > label = "port0led";
> > gpios = <&sgpio_out1 0 0 GPIO_ACTIVE_LOW>;
> > default-state = "off";
> > linux,default-trigger = "ocelot-miim0.2.auto-mii:00:link";
> > };
> > vscled@1 {
> > label = "port0led1";
> > gpios = <&sgpio_out1 0 1 GPIO_ACTIVE_LOW>;
> > default-state = "off";
> > linux,default-trigger = "ocelot-miim0.2.auto-mii:00:1Gbps";
> > };
> > [ ... ]
> > };
> > };
> >
> > &spi0 {
> > #address-cells = <1>;
> > #size-cells = <0>;
> > status = "okay";
> >
> > ocelot-chip@0 {
> > compatible = "mscc,vsc7512_mfd_spi";
>
> Can you use hyphens instead of underscores in this compatible string?
>
> > spi-max-frequency = <2500000>;
> > reg = <0>;
> >
> > ethernet-switch@0 {
>
> I don't think the switch node should have any address?
>
> > compatible = "mscc,vsc7512-ext-switch";
> > ports {
> > #address-cells = <1>;
> > #size-cells = <0>;
> >
> > port@0 {
> > reg = <0>;
> > label = "cpu";
> > status = "okay";
> > ethernet = <&mac_sw>;
> > phy-handle = <&sw_phy0>;
> > phy-mode = "internal";
> > };
> >
> > port@1 {
> > reg = <1>;
> > label = "swp1";
> > status = "okay";
> > phy-handle = <&sw_phy1>;
> > phy-mode = "internal";
> > };
> > };
> > };
> >
> > mdio0: mdio0@0 {
>
> This is going to be interesting. Some drivers with multiple MDIO buses
> create an "mdios" container with #address-cells = <1> and put the MDIO
> bus nodes under that. Others create an "mdio" node and an "mdio0" node
> (and no address for either of them).
>
> The problem with the latter approach is that
> Documentation/devicetree/bindings/net/mdio.yaml does not accept the
> "mdio0"/"mdio1" node name for an MDIO bus.

Hmm... That'll be interesting indeed. The 7514
(arch/mips/boot/dts/mscc/ocelot.dtsi) is where I undoubtedly started.
Is there an issue with the 7514, or is it just an issue with my
implementation, which should be:

mdio0: mdio@0 {

instead of mdio0@0?

>
> > compatible = "mscc,ocelot-miim";
> > #address-cells = <1>;
> > #size-cells = <0>;
> >
> > sw_phy0: ethernet-phy@0 {
> > reg = <0x0>;
> > };
> >
> > sw_phy1: ethernet-phy@1 {
> > reg = <0x1>;
> > };
> >
> > sw_phy2: ethernet-phy@2 {
> > reg = <0x2>;
> > };
> >
> > sw_phy3: ethernet-phy@3 {
> > reg = <0x3>;
> > };
> > };
> >
> > mdio1: mdio1@1 {
> > compatible = "mscc,ocelot-miim";
> > pinctrl-names = "default";
> > pinctrl-0 = <&miim1>;
> > #address-cells = <1>;
> > #size-cells = <0>;
> >
> > sw_phy4: ethernet-phy@4 {
> > reg = <0x4>;
> > };
> >
> > sw_phy5: ethernet-phy@5 {
> > reg = <0x5>;
> > };
> >
> > sw_phy6: ethernet-phy@6 {
> > reg = <0x6>;
> > };
> >
> > sw_phy7: ethernet-phy@7 {
> > reg = <0x7>;
> > };
> > };
> >
> > gpio: pinctrl@0 {
>
> Similar thing with the address. All these @0 addresses actually conflict
> with each other.
>
> > compatible = "mscc,ocelot-pinctrl";
> > gpio-controller;
> > #gpio_cells = <2>;
> > gpio-ranges = <&gpio 0 0 22>;
> >
> > led_shift_reg_pins: led-shift-reg-pins {
> > pins = "GPIO_0", "GPIO_1", "GPIO_2", "GPIO_3";
> > function = "sg0";
> > };
> >
> > miim1: miim1 {
> > pins = "GPIO_14", "GPIO_15";
> > function = "miim";
> > };
> > };
> >
> > sgpio: sgpio {
>
> And mixing nodes with addresses with nodes without addresses is broken too.
>
> > compatible = "mscc,ocelot-sgpio";
> > #address-cells = <1>;
> > #size-cells = <0>;
> > bus-frequency=<12500000>;
> > clocks = <&ocelot_clock>;
> > microchip,sgpio-port-ranges = <0 15>;
> > pinctrl-names = "default";
> > pinctrl-0 = <&led_shift_reg_pins>;
> >
> > sgpio_in0: sgpio@0 {
> > compatible = "microchip,sparx5-sgpio-bank";
> > reg = <0>;
> > gpio-controller;
> > #gpio-cells = <3>;
> > ngpios = <64>;
> > };
> >
> > sgpio_out1: sgpio@1 {
> > compatible = "microchip,sparx5-sgpio-bank";
> > reg = <1>;
> > gpio-controller;
> > #gpio-cells = <3>;
> > ngpios = <64>;
> > };
> > };
> > };
> > };
> >
> > And I'll include the relevant dmesg prints - I don't love the "invalid
> > resource" prints, as they seem to be misleading. They're a byproduct of
> > looking for IO resources before falling back to REG.
> >
> > [ 0.000000] Booting Linux on physical CPU 0x0
> > [ 0.000000] Linux version 5.18.0-rc5-01295-g47053e327c52 (X@X) (arm-linux-gnueabi-gcc (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0, GNU ld (GNU Binutils for Ubuntu) 2.34) #630 SMP PREEMPT Sun May 8 10:56:51 PDT 2022
> > ...
> > [ 2.829319] pinctrl-ocelot ocelot-pinctrl.0.auto: DMA mask not set
>
> Why does this get printed, if you put a dump_stack() in of_dma_configure_id()?

I'll run that tonight.

>
> > [ 2.835718] pinctrl-ocelot ocelot-pinctrl.0.auto: invalid resource
> > [ 2.842717] gpiochip_find_base: found new base at 2026
> > [ 2.842774] gpio gpiochip4: (ocelot-gpio): created GPIO range 0->21 ==> ocelot-pinctrl.0.auto PIN 0->21
> > [ 2.845693] gpio gpiochip4: (ocelot-gpio): added GPIO chardev (254:4)
> > [ 2.845828] gpio gpiochip4: registered GPIOs 2026 to 2047 on ocelot-gpio
> > [ 2.845855] pinctrl-ocelot ocelot-pinctrl.0.auto: driver registered
> > [ 2.855925] pinctrl-microchip-sgpio ocelot-sgpio.1.auto: DMA mask not set
> > [ 2.863089] pinctrl-microchip-sgpio ocelot-sgpio.1.auto: invalid resource
> > [ 2.870801] gpiochip_find_base: found new base at 1962
> > [ 2.871528] gpio_stub_drv gpiochip5: (ocelot-sgpio.1.auto-input): added GPIO chardev (254:5)
> > [ 2.871666] gpio_stub_drv gpiochip5: registered GPIOs 1962 to 2025 on ocelot-sgpio.1.auto-input
> > [ 2.872364] gpiochip_find_base: found new base at 1898
> > [ 2.873244] gpio_stub_drv gpiochip6: (ocelot-sgpio.1.auto-output): added GPIO chardev (254:6)
> > [ 2.873354] gpio_stub_drv gpiochip6: registered GPIOs 1898 to 1961 on ocelot-sgpio.1.auto-output
> > [ 2.881148] mscc-miim ocelot-miim0.2.auto: DMA mask not set
> > [ 2.886929] mscc-miim ocelot-miim0.2.auto: invalid resource
> > [ 2.893738] mdio_bus ocelot-miim0.2.auto-mii: GPIO lookup for consumer reset
> > [ 2.893769] mdio_bus ocelot-miim0.2.auto-mii: using device tree for GPIO lookup
> > [ 2.893802] of_get_named_gpiod_flags: can't parse 'reset-gpios' property of node '/ocp/interconnect@48000000/segment@0/target-module@30000/spi@0/ocelot-chip@0/mdio0[0]'
> > [ 2.893898] of_get_named_gpiod_flags: can't parse 'reset-gpio' property of node '/ocp/interconnect@48000000/segment@0/target-module@30000/spi@0/ocelot-chip@0/mdio0[0]'
> > [ 2.893996] mdio_bus ocelot-miim0.2.auto-mii: using lookup tables for GPIO lookup
> > [ 2.894012] mdio_bus ocelot-miim0.2.auto-mii: No GPIO consumer reset found
> > [ 3.395738] mdio_bus ocelot-miim0.2.auto-mii:00: GPIO lookup for consumer reset
> > [ 3.395777] mdio_bus ocelot-miim0.2.auto-mii:00: using device tree for GPIO lookup
> > [ 3.395840] of_get_named_gpiod_flags: can't parse 'reset-gpios' property of node '/ocp/interconnect@48000000/segment@0/target-module@30000/spi@0/ocelot-chip@0/mdio0/ethernet-phy@0[0]'
> > [ 3.395959] of_get_named_gpiod_flags: can't parse 'reset-gpio' property of node '/ocp/interconnect@48000000/segment@0/target-module@30000/spi@0/ocelot-chip@0/mdio0/ethernet-phy@0[0]'
> > [ 3.396069] mdio_bus ocelot-miim0.2.auto-mii:00: using lookup tables for GPIO lookup
> > [ 3.396086] mdio_bus ocelot-miim0.2.auto-mii:00: No GPIO consumer reset found
> > ...
> > [ 3.449187] ocelot-ext-switch ocelot-ext-switch.4.auto: DMA mask not set
> > [ 5.336880] ocelot-ext-switch ocelot-ext-switch.4.auto: PHY [ocelot-miim0.2.auto-mii:00] driver [Generic PHY] (irq=POLL)
> > [ 5.349087] ocelot-ext-switch ocelot-ext-switch.4.auto: configuring for phy/internal link mode
> > [ 5.363619] ocelot-ext-switch ocelot-ext-switch.4.auto swp1 (uninitialized): PHY [ocelot-miim0.2.auto-mii:01] driver [Generic PHY] (irq=POLL)
> > [ 5.381396] ocelot-ext-switch ocelot-ext-switch.4.auto swp2 (uninitialized): PHY [ocelot-miim0.2.auto-mii:02] driver [Generic PHY] (irq=POLL)
> > [ 5.398525] ocelot-ext-switch ocelot-ext-switch.4.auto swp3 (uninitialized): PHY [ocelot-miim0.2.auto-mii:03] driver [Generic PHY] (irq=POLL)
>
> Do the PHYs not have a specific driver?

When I have the other four ports defined, those correctly find the
vsc85xx driver, perform serdes calibration, etc. (assuming I have that
phy support compiled in) The internal phys I believe have always just
been using a generic driver.

>
> > [ 5.422048] device eth0 entered promiscuous mode
> > [ 5.426785] DSA: tree 0 setup
> > ...
> > [ 7.450067] ocelot-ext-switch ocelot-ext-switch.4.auto: Link is Up - 100Mbps/Full - flow control off
> > [ 21.556395] cpsw-switch 4a100000.switch: starting ndev. mode: dual_mac
> > [ 21.648564] SMSC LAN8710/LAN8720 4a101000.mdio:00: attached PHY driver (mii_bus:phy_addr=4a101000.mdio:00, irq=POLL)
> > [ 21.667970] 8021q: adding VLAN 0 to HW filter on device eth0
> > [ 21.705360] ocelot-ext-switch ocelot-ext-switch.4.auto swp1: configuring for phy/internal link mode
> > [ 22.018230] ocelot-ext-switch ocelot-ext-switch.4.auto: Link is Down
> > [ 23.771740] cpsw-switch 4a100000.switch eth0: Link is Up - 100Mbps/Full - flow control off
> > [ 24.090929] ocelot-ext-switch ocelot-ext-switch.4.auto: Link is Up - 100Mbps/Full - flow control off
> > [ 25.853021] ocelot-ext-switch ocelot-ext-switch.4.auto swp1: Link is Up - 1Gbps/Full - flow control rx/tx
> >
> >
> > RFC history:
> > v1 (accidentally named vN)
> > * Initial architecture. Not functional
> > * General concepts laid out
> >
> > v2
> > * Near functional. No CPU port communication, but control over all
> > external ports
> > * Cleaned up regmap implementation from v1
> >
> > v3
> > * Functional
> > * Shared MDIO transactions routed through mdio-mscc-miim
> > * CPU / NPI port enabled by way of vsc7512_enable_npi_port /
> > felix->info->enable_npi_port
> > * NPI port tagging functional - Requires a CPU port driver that supports
> > frames of 1520 bytes. Verified with a patch to the cpsw driver
> >
> > v4
> > * Functional
> > * Device tree fixes
> > * Add hooks for pinctrl-ocelot - some functionality by way of sysfs
> > * Add hooks for pinctrl-microsemi-sgpio - not yet fully functional
> > * Remove lynx_pcs interface for a generic phylink_pcs. The goal here
> > is to have an ocelot_pcs that will work for each configuration of
> > every port.
> >
> > v5
> > * Restructured to MFD
> > * Several commits were split out, submitted, and accepted
> > * pinctrl-ocelot believed to be fully functional (requires commits
> > from the linux-pinctrl tree)
> > * External MDIO bus believed to be fully functional
> >
> > v6
> > * Applied several suggestions from the last RFC from Lee Jones. I
> > hope I didn't miss anything.
> > * Clean up MFD core - SPI interaction. They no longer use callbacks.
> > * regmaps get registered to the child device, and don't attempt to
> > get shared. It seems if a regmap is to be shared, that should be
> > solved with syscon, not dev or mfd.
> >
> > v7
> > * Applied as much as I could from Lee and Vladimir's suggestions. As
> > always, the feedback is greatly appreciated!
> > * Remove "ocelot_spi" container complication
> > * Move internal MDIO bus from ocelot_ext to MFD, with a devicetree
> > change to match
> > * Add initial HSIO support
> > * Switch to IORESOURCE_REG for resource definitions
> >
> > v8
> > * Applied another round of suggestions from Lee and Vladimir
> > * Utilize regmap bus reads, which speeds bulk transfers up by an
>
> bus -> bulk?

Either is probably valid. Here I'm referencing struct regmap_bus,
so _regmap_bus_read allows the utilization of bulk transfers for stats.

>
> > order of magnitude
> > * Add two additional patches to utilize phylink_generic_validate
> > * Changed GPL V2 to GPL in licenses where applicable (checkpatch)
> > * Remove initial hsio/serdes changes from the RFC
> >
> >
> > Colin Foster (16):
> > pinctrl: ocelot: allow pinctrl-ocelot to be loaded as a module
> > pinctrl: microchip-sgpio: allow sgpio driver to be used as a module
> > net: ocelot: add interface to get regmaps when exernally controlled
> > net: mdio: mscc-miim: add ability to be used in a non-mmio
> > configuration
> > pinctrl: ocelot: add ability to be used in a non-mmio configuration
> > pinctrl: microchip-sgpio: add ability to be used in a non-mmio
> > configuration
> > resource: add define macro for register address resources
> > mfd: ocelot: add support for the vsc7512 chip via spi
> > net: mscc: ocelot: expose ocelot wm functions
> > net: dsa: felix: add configurable device quirks
> > net: mscc: ocelot: expose regfield definition to be used by other
> > drivers
> > net: mscc: ocelot: expose stats layout definition to be used by other
> > drivers
> > net: mscc: ocelot: expose vcap_props structure
> > net: dsa: ocelot: add external ocelot switch control
> > net: dsa: felix: add phylink_get_caps capability
> > net: dsa: ocelot: utilize phylink_generic_validate
> >
> > drivers/mfd/Kconfig | 18 +
> > drivers/mfd/Makefile | 2 +
> > drivers/mfd/ocelot-core.c | 138 ++++++++
> > drivers/mfd/ocelot-spi.c | 311 +++++++++++++++++
> > drivers/mfd/ocelot.h | 34 ++
> > drivers/net/dsa/ocelot/Kconfig | 14 +
> > drivers/net/dsa/ocelot/Makefile | 5 +
> > drivers/net/dsa/ocelot/felix.c | 29 +-
> > drivers/net/dsa/ocelot/felix.h | 3 +
> > drivers/net/dsa/ocelot/felix_vsc9959.c | 1 +
> > drivers/net/dsa/ocelot/ocelot_ext.c | 366 +++++++++++++++++++++
> > drivers/net/dsa/ocelot/seville_vsc9953.c | 1 +
> > drivers/net/ethernet/mscc/ocelot_devlink.c | 31 ++
> > drivers/net/ethernet/mscc/ocelot_vsc7514.c | 230 +------------
> > drivers/net/ethernet/mscc/vsc7514_regs.c | 200 +++++++++++
> > drivers/net/mdio/mdio-mscc-miim.c | 31 +-
> > drivers/pinctrl/Kconfig | 4 +-
> > drivers/pinctrl/pinctrl-microchip-sgpio.c | 26 +-
> > drivers/pinctrl/pinctrl-ocelot.c | 35 +-
> > include/linux/ioport.h | 5 +
> > include/soc/mscc/ocelot.h | 19 ++
> > include/soc/mscc/vsc7514_regs.h | 6 +
> > 22 files changed, 1251 insertions(+), 258 deletions(-)
> > create mode 100644 drivers/mfd/ocelot-core.c
> > create mode 100644 drivers/mfd/ocelot-spi.c
> > create mode 100644 drivers/mfd/ocelot.h
> > create mode 100644 drivers/net/dsa/ocelot/ocelot_ext.c
> >
> > --
> > 2.25.1
> >