Commit 1f12177b authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'cpsw-switchdev'

Grygorii Strashko says:

====================
net: ethernet: ti: introduce new cpsw switchdev based driver

Thank you All for review of v6.

There are no significant changes in this version, just fixed comments to v6.

--- v6
The major change in this version is DT bindings conversation to json-schema, and
fixed other comments to v5. Also added patch to clean up ALE on init and netif
restart.

--- v5
The major part of work done in this iteration is rebasing on top of net-next
with XDP series from Ivan Khoronzhuk [3], and enable XDP support in the new
CPSW switchdev driver (it was little bit painful ;(). There are mostly no
functional changes in new CPSW driver, just few fixes, sync with old driver
and cleanups/optimizations. So, I've kept rest of cover letter unchanged.

---
This series originally based on work [1][2] done by
Ilias Apalodimas <ilias.apalodimas@linaro.org>.

This the RFC v5 which introduces new CPSW switchdev based driver which is
operating in dual-emac mode by default, thus working as 2 individual
network interfaces. The Switch mode can be enabled by configuring devlink driver
parameter "switch_mode" to 1/true:
	devlink dev param set platform/48484000.switch \
	name switch_mode value 1 cmode runtime
This can be done regardless of the state of Port's netdev devices - UP/DOWN, but
Port's netdev devices have to be in UP before joining the bridge to avoid
overwriting of bridge configuration as CPSW switch driver completely reloads its
configuration when first Port changes its state to UP.
When the both interfaces joined the bridge - CPSW switch driver will start
marking packets with offload_fwd_mark flag unless "ale_bypass=0".
All configuration is implemented via switchdev API.

The previous solution of tracking both Ports joined the bridge
(from netdevice_notifier) proved to be not correct as changing CPSW switch
driver mode required cleanup of ALE table and CPSW settings which happens
while second Port is joined bridge and as result configuration loaded
by bridge for the first Port became corrupted.

The introduction of the new CPSW switchdev based driver (cpsw_new.c) is split
on two parts: Part 1 - basic dual-emac driver; Part 2 switchdev support.
Such approach has simplified code development and testing alot. And, I hope,
it will help with better review.

patches #1 - 5: preparation patches which also moves common code to cpsw_priv.c
patches #6 - 9: Introduce TI CPSW switch driver based on switchdev and new
 DT bindings
patch #10: new CPSW switchdev driver documentation
patch #11: adds DT nodes for new CPSW switchdev driver added for DRA7 SoC
patch #12: adds DT nodes for new cpsw switchdev driver for am571x-idk board
patch #13: enables build of TI CPSW driver

Most of the contents of the previous cover-letter have been added in
new driver documentation, so please refer to that for configuration,
testing and future work.

These patches can be found at (branch contains some additional patches required
for testing on top of net-next):
 https://github.com/grygoriyS/linux.git
 branch: lkml-5.4-switch-tbd-v7

changes in v7:
 - patch 2: added check for devm_kmalloc_array() return value
 - patch 6: fixed comments

changes in v6: https://lkml.org/lkml/2019/11/9/108
 - DT bindings converted to json-schema
 - netdev initialization is split on creation and registration.
   The netdevs registration happens now at the end of the pobe.
 - reworked cpsw_set_pauseparam() to use PHYlib APIs.
 - other comments for v5 fixed

v5: https://patchwork.kernel.org/cover/11208785/
 - rebase on top of net-next with XDP series from Ivan Khoronzhuk [3],
   and enable XDP support in the new CPSW switchdev driver
   cpsw driver (tested XDP_DROP only)
 - sync with old cpsw driver
 - implement comments from  Ivan Khoronzhuk and Rob Herring
 - fixed "NETDEV WATCHDOG: .." warning after interface after interface UP/DOWN,
   missed TX wake in cpsw_adjust_link()

v4: https://patchwork.kernel.org/cover/11010523/
 - finished split of common CPSW code
 - added devlink support
 - changed CPSW mode configuration approach: from netdevice_notifier to devlink
   parameter
 - refactor and clean up ALE changes which allows to modify VLANs/MDBs entries
 - added missed support for port QDISC_CBS and QDISC_MQPRIO
 - the CPSW is split on two parts: basic dual_mac driver and switchdev support
 - added missed callback .ndo_get_port_parent_id()
 - reworked ingress frames marking in switch mode (offload_fwd_mark)
 - applied comments from Andrew Lunn

v3: https://lwn.net/Articles/786677/
Changes in v3:
- alot of work done to split properly common code between legacy and switchdev
  CPSW drivers and clean up code
- CPSW switchdev interface updated to the current LKML switchdev interface
- actually new CPSW switchdev based driver introduced
- optimized dual_mac mode in new driver. Main change is that in promiscuous
mode P0_UNI_FLOOD (both ports) is enabled in addition to ALLMULTI (current
port) instead of ALE_BYPASS.  So, port in non promiscuous mode will keep
possibility of mcast and vlan filtering.
- changed bridge join sequnce: now switch mode will be enabled only when
both ports joined the bridge. CPSW will be switched to dual_mac mode if any
port leave bridge. ALE table is completly cleared and then refiled while
switching to switch mode - this simplidies code a lot, but introduces some
limitation to bridge setup sequence:
 ip link add name br0 type bridge
 ip link set dev br0 type bridge ageing_time 1000
 ip link set dev br0 type bridge vlan_filtering 0 <- disable
 echo 0 > /sys/class/net/br0/bridge/default_vlan

 ip link set dev sw0p1 up <- add ports
 ip link set dev sw0p2 up
 ip link set dev sw0p1 master br0
 ip link set dev sw0p2 master br0

 echo 1 > /sys/class/net/br0/bridge/default_vlan <- enable
 ip link set dev br0 type bridge vlan_filtering 1
 bridge vlan add dev br0 vid 1 pvid untagged self
- STP tested with vlan_filtering 1/0. To make STP work I've had to set
  NO_SA_UPDATE for all slave ports (see comment in code). It also required to
  statically register STP mcast address {0x01, 0x80, 0xc2, 0x0, 0x0, 0x0};
- allowed build both TI_CPSW and TI_CPSW_SWITCHDEV drivers
- PTP can be enabled on both ports in dual_mac mode

[1] https://patchwork.ozlabs.org/cover/929367/
[2] https://patches.linaro.org/cover/136709/
[3] https://patchwork.kernel.org/cover/11035813/


====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents b9242da6 3727d259
Loading
Loading
Loading
Loading
+240 −0
Original line number Diff line number Diff line
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
$id: http://devicetree.org/schemas/net/ti,cpsw-switch.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#

title: TI SoC Ethernet Switch Controller (CPSW) Device Tree Bindings

maintainers:
  - Grygorii Strashko <grygorii.strashko@ti.com>
  - Sekhar Nori <nsekhar@ti.com>

description:
  The 3-port switch gigabit ethernet subsystem provides ethernet packet
  communication and can be configured as an ethernet switch. It provides the
  gigabit media independent interface (GMII),reduced gigabit media
  independent interface (RGMII), reduced media independent interface (RMII),
  the management data input output (MDIO) for physical layer device (PHY)
  management.

properties:
  compatible:
    oneOf:
      - const: ti,cpsw-switch
      - items:
         - const: ti,am335x-cpsw-switch
         - const: ti,cpsw-switch
      - items:
        - const: ti,am4372-cpsw-switch
        - const: ti,cpsw-switch
      - items:
        - const: ti,dra7-cpsw-switch
        - const: ti,cpsw-switch

  reg:
    maxItems: 1
    description:
       The physical base address and size of full the CPSW module IO range

  ranges: true

  clocks:
    maxItems: 1
    description: CPSW functional clock

  clock-names:
    maxItems: 1
    items:
      - const: fck

  interrupts:
    items:
      - description: RX_THRESH interrupt
      - description: RX interrupt
      - description: TX interrupt
      - description: MISC interrupt

  interrupt-names:
    items:
      - const: "rx_thresh"
      - const: "rx"
      - const: "tx"
      - const: "misc"

  pinctrl-names: true

  syscon:
    $ref: /schemas/types.yaml#definitions/phandle
    description:
      Phandle to the system control device node which provides access to
      efuse IO range with MAC addresses


  ethernet-ports:
    type: object
    properties:
      '#address-cells':
        const: 1
      '#size-cells':
        const: 0

    patternProperties:
      "^port@[0-9]+$":
          type: object
          minItems: 1
          maxItems: 2
          description: CPSW external ports

          allOf:
            - $ref: ethernet-controller.yaml#

          properties:
            reg:
              maxItems: 1
              enum: [1, 2]
              description: CPSW port number

            phys:
              $ref: /schemas/types.yaml#definitions/phandle-array
              maxItems: 1
              description:  phandle on phy-gmii-sel PHY

            label:
              $ref: /schemas/types.yaml#/definitions/string-array
              maxItems: 1
              description: label associated with this port

            ti,dual-emac-pvid:
              $ref: /schemas/types.yaml#/definitions/uint32
              maxItems: 1
              minimum: 1
              maximum: 1024
              description:
                Specifies default PORT VID to be used to segregate
                ports. Default value - CPSW port number.

          required:
            - reg
            - phys

  mdio:
    type: object
    allOf:
      - $ref: "ti,davinci-mdio.yaml#"
    description:
      CPSW MDIO bus.

  cpts:
    type: object
    description:
      The Common Platform Time Sync (CPTS) module

    properties:
      clocks:
        maxItems: 1
        description: CPTS reference clock

      clock-names:
        maxItems: 1
        items:
          - const: cpts

      cpts_clock_mult:
        $ref: /schemas/types.yaml#/definitions/uint32
        description:
          Numerator to convert input clock ticks into ns

      cpts_clock_shift:
        $ref: /schemas/types.yaml#/definitions/uint32
        description:
          Denominator to convert input clock ticks into ns.
          Mult and shift will be calculated basing on CPTS rftclk frequency if
          both cpts_clock_shift and cpts_clock_mult properties are not provided.

    required:
      - clocks
      - clock-names

required:
  - compatible
  - reg
  - ranges
  - clocks
  - clock-names
  - interrupts
  - interrupt-names
  - '#address-cells'
  - '#size-cells'

examples:
  - |
    #include <dt-bindings/interrupt-controller/irq.h>
    #include <dt-bindings/interrupt-controller/arm-gic.h>
    #include <dt-bindings/clock/dra7.h>

    mac_sw: switch@0 {
        compatible = "ti,dra7-cpsw-switch","ti,cpsw-switch";
        reg = <0x0 0x4000>;
        ranges = <0 0 0x4000>;
        clocks = <&gmac_main_clk>;
        clock-names = "fck";
        #address-cells = <1>;
        #size-cells = <1>;
        syscon = <&scm_conf>;
        inctrl-names = "default", "sleep";

        interrupts = <GIC_SPI 334 IRQ_TYPE_LEVEL_HIGH>,
                     <GIC_SPI 335 IRQ_TYPE_LEVEL_HIGH>,
                     <GIC_SPI 336 IRQ_TYPE_LEVEL_HIGH>,
                     <GIC_SPI 337 IRQ_TYPE_LEVEL_HIGH>;
        interrupt-names = "rx_thresh", "rx", "tx", "misc";

        ethernet-ports {
                #address-cells = <1>;
                #size-cells = <0>;

                cpsw_port1: port@1 {
                        reg = <1>;
                        label = "port1";
                        mac-address = [ 00 00 00 00 00 00 ];
                        phys = <&phy_gmii_sel 1>;
                        phy-handle = <&ethphy0_sw>;
                        phy-mode = "rgmii";
                        ti,dual_emac_pvid = <1>;
                };

                cpsw_port2: port@2 {
                        reg = <2>;
                        label = "wan";
                        mac-address = [ 00 00 00 00 00 00 ];
                        phys = <&phy_gmii_sel 2>;
                        phy-handle = <&ethphy1_sw>;
                        phy-mode = "rgmii";
                        ti,dual_emac_pvid = <2>;
                };
        };

        davinci_mdio_sw: mdio@1000 {
                compatible = "ti,cpsw-mdio","ti,davinci_mdio";
                reg = <0x1000 0x100>;
                clocks = <&gmac_clkctrl DRA7_GMAC_GMAC_CLKCTRL 0>;
                clock-names = "fck";
                #address-cells = <1>;
                #size-cells = <0>;
                bus_freq = <1000000>;

                ethphy0_sw: ethernet-phy@0 {
                        reg = <0>;
                };

                ethphy1_sw: ethernet-phy@1 {
                        reg = <1>;
                };
        };

        cpts {
                clocks = <&gmac_clkctrl DRA7_GMAC_GMAC_CLKCTRL 25>;
                clock-names = "cpts";
        };
    };
+209 −0
Original line number Diff line number Diff line
* Texas Instruments CPSW switchdev based ethernet driver 2.0

- Port renaming
On older udev versions renaming of ethX to swXpY will not be automatically
supported
In order to rename via udev:
ip -d link show dev sw0p1 | grep switchid

SUBSYSTEM=="net", ACTION=="add", ATTR{phys_switch_id}==<switchid>, \
        ATTR{phys_port_name}!="", NAME="sw0$attr{phys_port_name}"


====================
# Dual mac mode
====================
- The new (cpsw_new.c) driver is operating in dual-emac mode by default, thus
working as 2 individual network interfaces. Main differences from legacy CPSW
driver are:
 - optimized promiscuous mode: The P0_UNI_FLOOD (both ports) is enabled in
addition to ALLMULTI (current port) instead of ALE_BYPASS.
So, Ports in promiscuous mode will keep possibility of mcast and vlan filtering,
which is provides significant benefits when ports are joined to the same bridge,
but without enabling "switch" mode, or to different bridges.
 - learning disabled on ports as it make not too much sense for
   segregated ports - no forwarding in HW.
 - enabled basic support for devlink.

	devlink dev show
		platform/48484000.switch

	devlink dev param show
	platform/48484000.switch:
	name switch_mode type driver-specific
	values:
		cmode runtime value false
	name ale_bypass type driver-specific
	values:
		cmode runtime value false

Devlink configuration parameters
====================
See Documentation/networking/devlink-params-ti-cpsw-switch.txt

====================
# Bridging in dual mac mode
====================
The dual_mac mode requires two vids to be reserved for internal purposes,
which, by default, equal CPSW Port numbers. As result, bridge has to be
configured in vlan unaware mode or default_pvid has to be adjusted.

	ip link add name br0 type bridge
	ip link set dev br0 type bridge vlan_filtering 0
	echo 0 > /sys/class/net/br0/bridge/default_pvid
	ip link set dev sw0p1 master br0
	ip link set dev sw0p2 master br0
 - or -
	ip link add name br0 type bridge
	ip link set dev br0 type bridge vlan_filtering 0
	echo 100 > /sys/class/net/br0/bridge/default_pvid
	ip link set dev br0 type bridge vlan_filtering 1
	ip link set dev sw0p1 master br0
	ip link set dev sw0p2 master br0

====================
# Enabling "switch"
====================
The Switch mode can be enabled by configuring devlink driver parameter
"switch_mode" to 1/true:
	devlink dev param set platform/48484000.switch \
	name switch_mode value 1 cmode runtime

This can be done regardless of the state of Port's netdev devices - UP/DOWN, but
Port's netdev devices have to be in UP before joining to the bridge to avoid
overwriting of bridge configuration as CPSW switch driver copletly reloads its
configuration when first Port changes its state to UP.

When the both interfaces joined the bridge - CPSW switch driver will enable
marking packets with offload_fwd_mark flag unless "ale_bypass=0"

All configuration is implemented via switchdev API.

====================
# Bridge setup
====================
	devlink dev param set platform/48484000.switch \
	name switch_mode value 1 cmode runtime

	ip link add name br0 type bridge
	ip link set dev br0 type bridge ageing_time 1000
	ip link set dev sw0p1 up
	ip link set dev sw0p2 up
	ip link set dev sw0p1 master br0
	ip link set dev sw0p2 master br0
	[*] bridge vlan add dev br0 vid 1 pvid untagged self

[*] if vlan_filtering=1. where default_pvid=1

=================
# On/off STP
=================
ip link set dev BRDEV type bridge stp_state 1/0

Note. Steps [*] are mandatory.

====================
# VLAN configuration
====================
bridge vlan add dev br0 vid 1 pvid untagged self <---- add cpu port to VLAN 1

Note. This step is mandatory for bridge/default_pvid.

=================
# Add extra VLANs
=================
 1. untagged:
    bridge vlan add dev sw0p1 vid 100 pvid untagged master
    bridge vlan add dev sw0p2 vid 100 pvid untagged master
    bridge vlan add dev br0 vid 100 pvid untagged self <---- Add cpu port to VLAN100

 2. tagged:
    bridge vlan add dev sw0p1 vid 100 master
    bridge vlan add dev sw0p2 vid 100 master
    bridge vlan add dev br0 vid 100 pvid tagged self <---- Add cpu port to VLAN100

====
FDBs
====
FDBs are automatically added on the appropriate switch port upon detection

Manually adding FDBs:
bridge fdb add aa:bb:cc:dd:ee:ff dev sw0p1 master vlan 100
bridge fdb add aa:bb:cc:dd:ee:fe dev sw0p2 master <---- Add on all VLANs

====
MDBs
====
MDBs are automatically added on the appropriate switch port upon detection

Manually adding MDBs:
bridge mdb add dev br0 port sw0p1 grp 239.1.1.1 permanent vid 100
bridge mdb add dev br0 port sw0p1 grp 239.1.1.1 permanent <---- Add on all VLANs

==================
Multicast flooding
==================
CPU port mcast_flooding is always on

Turning flooding on/off on swithch ports:
bridge link set dev sw0p1 mcast_flood on/off

==================
Access and Trunk port
==================
 bridge vlan add dev sw0p1 vid 100 pvid untagged master
 bridge vlan add dev sw0p2 vid 100 master


 bridge vlan add dev br0 vid 100 self
 ip link add link br0 name br0.100 type vlan id 100

 Note. Setting PVID on Bridge device itself working only for
 default VLAN (default_pvid).

=====================
 NFS
=====================
The only way for NFS to work is by chrooting to a minimal environment when
switch configuration that will affect connectivity is needed.
Assuming you are booting NFS with eth1 interface(the script is hacky and
it's just there to prove NFS is doable).

setup.sh:
#!/bin/sh
mkdir proc
mount -t proc none /proc
ifconfig br0  > /dev/null
if [ $? -ne 0 ]; then
        echo "Setting up bridge"
        ip link add name br0 type bridge
        ip link set dev br0 type bridge ageing_time 1000
        ip link set dev br0 type bridge vlan_filtering 1

        ip link set eth1 down
        ip link set eth1 name sw0p1
        ip link set dev sw0p1 up
        ip link set dev sw0p2 up
        ip link set dev sw0p2 master br0
        ip link set dev sw0p1 master br0
        bridge vlan add dev br0 vid 1 pvid untagged self
        ifconfig sw0p1 0.0.0.0
        udhchc -i br0
fi
umount /proc

run_nfs.sh:
#!/bin/sh
mkdir /tmp/root/bin -p
mkdir /tmp/root/lib -p

cp -r /lib/ /tmp/root/
cp -r /bin/ /tmp/root/
cp /sbin/ip /tmp/root/bin
cp /sbin/bridge /tmp/root/bin
cp /sbin/ifconfig /tmp/root/bin
cp /sbin/udhcpc /tmp/root/bin
cp /path/to/setup.sh /tmp/root/bin
chroot /tmp/root/ busybox sh /bin/setup.sh

run ./run_nfs.sh
+10 −0
Original line number Diff line number Diff line
ale_bypass	[DEVICE, DRIVER-SPECIFIC]
		Allows to enable ALE_CONTROL(4).BYPASS mode for debug purposes.
		All packets will be sent to the Host port only if enabled.
		Type: bool
		Configuration mode: runtime

switch_mode	[DEVICE, DRIVER-SPECIFIC]
		Enable switch mode
		Type: bool
		Configuration mode: runtime
+27 −0
Original line number Diff line number Diff line
@@ -186,3 +186,30 @@
	pinctrl-1 = <&mmc2_pins_hs>;
	pinctrl-2 = <&mmc2_pins_ddr_rev20 &mmc2_iodelay_ddr_conf>;
};

&mac_sw {
	pinctrl-names = "default", "sleep";
	status = "okay";
};

&cpsw_port1 {
	phy-handle = <&ethphy0_sw>;
	phy-mode = "rgmii";
	ti,dual-emac-pvid = <1>;
};

&cpsw_port2 {
	phy-handle = <&ethphy1_sw>;
	phy-mode = "rgmii";
	ti,dual-emac-pvid = <2>;
};

&davinci_mdio_sw {
	ethphy0_sw: ethernet-phy@0 {
		reg = <0>;
	};

	ethphy1_sw: ethernet-phy@1 {
		reg = <1>;
	};
};
+5 −0
Original line number Diff line number Diff line
@@ -27,3 +27,8 @@
	pinctrl-1 = <&mmc2_pins_hs>;
	pinctrl-2 = <&mmc2_pins_ddr_rev20>;
};

&mac {
	status = "okay";
	dual_emac;
};
Loading