mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH net-next v3 0/8] net: dsa: Add SoC-e DSA driver
@ 2026-09-23 10:39 Vasilij Strassheim
  2026-09-23 10:39 ` [PATCH net-next v3 1/8] dt-bindings: vendor-prefixes: Add soce Vasilij Strassheim
                   ` (7 more replies)
  0 siblings, 8 replies; 17+ messages in thread
From: Vasilij Strassheim @ 2026-09-23 10:39 UTC (permalink / raw)
  To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Andrew Lunn,
	Vladimir Oltean, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Russell King, Andrew Lunn,
	Heiner Kallweit
  Cc: devicetree, linux-kernel, netdev, Martin Kaistra,
	Benedikt Spranger, Vasilij Strassheim, Krzysztof Kozlowski

Add support for SoC-e Ethernet switch IP cores synthesized for and
implemented in FPGAs.

The series introduces the SoC-e vendor prefix and device tree bindings,
an EtherType-based SDSA tagger, an MDIO controller driver, and a DSA
switch driver.

The switch driver uses a memory-mapped control interface. During probe,
it detects the core version and the licensed and implemented port
counts, and verifies that the synthesized core provides DSA support.
Port counts from 3 through 31 are supported.

It supports Ethernet switching using MII, GMII, RMII, and RGMII port
interfaces. VLAN filtering and membership are also offloaded when the
corresponding hardware feature is synthesized. Unsupported hardware STP
offloading is disabled.

External MDIO outputs are exposed as separate logical MDIO buses sharing
the integrated MDIO controller. The controller supports Clause 22 and
Clause 45 transactions, while the generic MMIO MDIO mux selects the
external bus through the shared control register.

The drivers were tested with a SoC-e MRS 25.01 IP core on a Xilinx
ZynqMP platform with the following options enabled: 3 ports, DSA, IEEE
802.1w - RSTP, MAC Table Type with Hybrid SVL/IV, Port-based VLAN, QoS -
Priorities, Statistic Counters.

Signed-off-by: Vasilij Strassheim <v.strassheim@linutronix.de>
---
Changes in v3:
- Rebase onto net-next/main and update tag protocol number in dsa.h
- Drop the deprecated ports and port@ node names and keep only
  ethernet-ports and ethernet-port@ in the binding.
- Drop labels from the switch binding example.
- Rename the MDIO master to MDIO controller.
- New Patches 2 and 5: Move the integrated MDIO controller into a
  separate driver and add the corresponding binding, Kconfig entry, and
  build integration.
- Switch from internal MDIO multiplexing to the generic MMIO MDIO mux
  framework for selecting the synthesized external MDIO buses.
- Check that the MDIO controller is idle before programming a
  transaction and wait for completion afterward.
- Replace MDIO magic values and resource indices with named definitions.
- Reduce MDIO timeout from 1s to more reasonable 1ms.
- Remove inline declarations and unnecessary checks from the remaining
  MDIO code.
- Use mdio-mux-mmioreg for the 11-bit MDIO bus selector at bits 26:16
  and access it through the upper 16-bit half of the shared control
  register.
- Update the switch binding to describe the MDIO controller, generic
  MMIO mux, child buses, and PHY references.
- Remove struct soce_probe_desc, since only one register layout is
  supported.
- Reject configurations with fewer than three implemented ports.
- Add port enable and disable callbacks to prevent unmanaged forwarding
  after driver unbind or module removal.
- Disable tagging during teardown.
- Rename and regroup register field macros to identify their associated
  registers.
- Remove obsolete and irrelevant comments.
- Add new comments for proper documentation and clarity.
- Switch to dev_err_probe() to improve probe error reporting.
- Embed struct dsa_switch in struct soce_priv instead of allocating it
  separately.
- Remove the trailing comma after the sentinel entry in the match table.

Follow-up validation and feature work using a new IP core:
- New patch 7: Add basic VLAN hardware offload through
  port_vlan_filtering, port_vlan_add, and port_vlan_del.
- Warn when the Port VLAN feature is unavailable and reject VLAN
  configuration with netlink extended acknowledgements.
- Reset VLAN offloading configuration during teardown.
- New patch 8: Disable STP offloading, which is not supported by the
  initial driver.
- Improvements in SDSA tag handling:
  - Add specific skb drop reasons for malformed SDSA frames.
  - Restore VLAN metadata from the SDSA tag on receive and encode skb
    VLAN metadata into the SDSA tag on transmit.

- Link to v2: https://patch.msgid.link/20260903-devel-vstrassheim-soce-dsa-ml-v2-0-fb0587cb466b@linutronix.de

Changes in v2:
- Correctly use net-next prefix
- Rework the binding into a single MMIO-based switch node
- Model hardware MDIO outputs as separate logical MDIO buses
- Detect the switch version, features, and port count from hardware
- Drop incomplete STP, bridge, and FDB offloading
- Derive phylink capabilities from each port's phy-mode
- Harden MDIO access and SDSA receive validation
- Address binding, naming, and coding style review comments

Link to v1: https://patch.msgid.link/20260729-devel-vstrassheim-soce-dsa-ml-v1-0-be569dae1b20@linutronix.de

To: Rob Herring <robh@kernel.org>
To: Krzysztof Kozlowski <krzk+dt@kernel.org>
To: Conor Dooley <conor+dt@kernel.org>
To: Andrew Lunn <andrew@lunn.ch>
To: Vladimir Oltean <olteanv@gmail.com>
To: "David S. Miller" <davem@davemloft.net>
To: Eric Dumazet <edumazet@google.com>
To: Jakub Kicinski <kuba@kernel.org>
To: Paolo Abeni <pabeni@redhat.com>
To: Vasilij Strassheim <v.strassheim@linutronix.de>
To: Simon Horman <horms@kernel.org>
To: Russell King <linux@armlinux.org.uk>
To: Andrew Lunn <andrew+netdev@lunn.ch>
To: Heiner Kallweit <hkallweit1@gmail.com>
Cc: devicetree@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Cc: netdev@vger.kernel.org

---
Vasilij Strassheim (8):
      dt-bindings: vendor-prefixes: Add soce
      dt-bindings: net: Add SoC-e SWIP MDIO controller
      dt-bindings: net: dsa: Add SoC-e SWIP switch
      net: dsa: Add tag handling for SoC-e switches
      net: mdio: Add SoC-e SWIP MDIO controller driver
      net: dsa: soce: Add basic support for SoC-e switch IP cores
      net: dsa: soce: Add VLAN offload support
      net: dsa: soce: Disable unsupported hardware STP

 .../devicetree/bindings/net/dsa/soce,swip.yaml     | 162 +++++
 .../devicetree/bindings/net/soce,swip-mdio.yaml    |  47 ++
 .../devicetree/bindings/vendor-prefixes.yaml       |   2 +
 drivers/net/dsa/Kconfig                            |   2 +
 drivers/net/dsa/Makefile                           |   1 +
 drivers/net/dsa/soce/Kconfig                       |  14 +
 drivers/net/dsa/soce/Makefile                      |   4 +
 drivers/net/dsa/soce/soce_dsa.h                    |  38 ++
 drivers/net/dsa/soce/soce_dsa_core.c               | 737 +++++++++++++++++++++
 drivers/net/mdio/Kconfig                           |   7 +
 drivers/net/mdio/Makefile                          |   1 +
 drivers/net/mdio/mdio-soce.c                       | 239 +++++++
 include/net/dsa.h                                  |   2 +
 net/dsa/Kconfig                                    |   6 +
 net/dsa/Makefile                                   |   1 +
 net/dsa/tag_sdsa.c                                 | 158 +++++
 16 files changed, 1421 insertions(+)
---
base-commit: 944ae66642b726bd6b25ae71b1e9ff88a0e0bdb0
change-id: 20260729-devel-vstrassheim-soce-dsa-ml-20d6a5adb838

Best regards,
--  
Vasilij Strassheim <v.strassheim@linutronix.de>


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

* [PATCH net-next v3 1/8] dt-bindings: vendor-prefixes: Add soce
  2026-09-23 10:39 [PATCH net-next v3 0/8] net: dsa: Add SoC-e DSA driver Vasilij Strassheim
@ 2026-09-23 10:39 ` Vasilij Strassheim
  2026-09-23 10:39 ` [PATCH net-next v3 2/8] dt-bindings: net: Add SoC-e SWIP MDIO controller Vasilij Strassheim
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 17+ messages in thread
From: Vasilij Strassheim @ 2026-09-23 10:39 UTC (permalink / raw)
  To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Andrew Lunn,
	Vladimir Oltean, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Russell King, Andrew Lunn,
	Heiner Kallweit
  Cc: devicetree, linux-kernel, netdev, Martin Kaistra,
	Benedikt Spranger, Vasilij Strassheim, Krzysztof Kozlowski

Document binding for System-On-Chip Engineering, S.L.

Link: https://soc-e.com/
Signed-off-by: Vasilij Strassheim <v.strassheim@linutronix.de>
Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
---
 Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
index ba2002969373..1c641e1f0ca6 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -1581,6 +1581,8 @@ patternProperties:
     description: Standard Microsystems Corporation
   "^snps,.*":
     description: Synopsys, Inc.
+  "^soce,.*":
+    description: System-On-Chip Engineering, S.L.
   "^sochip,.*":
     description: Shenzhen SoChip Technology Co., Ltd.
   "^socionext,.*":

-- 
2.39.5


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

* [PATCH net-next v3 2/8] dt-bindings: net: Add SoC-e SWIP MDIO controller
  2026-09-23 10:39 [PATCH net-next v3 0/8] net: dsa: Add SoC-e DSA driver Vasilij Strassheim
  2026-09-23 10:39 ` [PATCH net-next v3 1/8] dt-bindings: vendor-prefixes: Add soce Vasilij Strassheim
@ 2026-09-23 10:39 ` Vasilij Strassheim
  2026-09-25 22:55   ` Andrew Lunn
  2026-09-23 10:39 ` [PATCH net-next v3 3/8] dt-bindings: net: dsa: Add SoC-e SWIP switch Vasilij Strassheim
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 17+ messages in thread
From: Vasilij Strassheim @ 2026-09-23 10:39 UTC (permalink / raw)
  To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Andrew Lunn,
	Vladimir Oltean, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Russell King, Andrew Lunn,
	Heiner Kallweit
  Cc: devicetree, linux-kernel, netdev, Martin Kaistra,
	Benedikt Spranger, Vasilij Strassheim

Add a binding for the MDIO controller integrated into SoC-e SWIP
Ethernet switch IP cores.

The controller exposes separate register regions for transaction data
and for the shared transaction control and external bus selector
register. It acts as the parent bus for an MDIO mux used to access the
external MDIO interfaces synthesized into the switch core.

Signed-off-by: Vasilij Strassheim <v.strassheim@linutronix.de>
---
 .../devicetree/bindings/net/soce,swip-mdio.yaml    | 47 ++++++++++++++++++++++
 1 file changed, 47 insertions(+)

diff --git a/Documentation/devicetree/bindings/net/soce,swip-mdio.yaml b/Documentation/devicetree/bindings/net/soce,swip-mdio.yaml
new file mode 100644
index 000000000000..3cf4bde0508a
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/soce,swip-mdio.yaml
@@ -0,0 +1,47 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/net/soce,swip-mdio.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: SoC-e switch IP MDIO controller
+
+maintainers:
+  - Vasilij Strassheim <v.strassheim@linutronix.de>
+
+description:
+  MDIO controller integrated into SoC-e Ethernet switch FPGA IP cores.
+  The controller accesses multiple external MDIO buses through a mux.
+
+$ref: mdio.yaml#
+
+properties:
+  compatible:
+    const: soce,swip-mdio-23-02
+
+  reg:
+    items:
+      - description: MDIO parameter, write data, and read data registers
+      - description: Shared MDIO transaction control and bus selection register
+
+  reg-names:
+    items:
+      - const: data
+      - const: control
+
+required:
+  - compatible
+  - reg
+  - reg-names
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    mdio@204 {
+        compatible = "soce,swip-mdio-23-02";
+        reg = <0x204 0xc>, <0x200 0x4>;
+        reg-names = "data", "control";
+        #address-cells = <1>;
+        #size-cells = <0>;
+    };

-- 
2.39.5


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

* [PATCH net-next v3 3/8] dt-bindings: net: dsa: Add SoC-e SWIP switch
  2026-09-23 10:39 [PATCH net-next v3 0/8] net: dsa: Add SoC-e DSA driver Vasilij Strassheim
  2026-09-23 10:39 ` [PATCH net-next v3 1/8] dt-bindings: vendor-prefixes: Add soce Vasilij Strassheim
  2026-09-23 10:39 ` [PATCH net-next v3 2/8] dt-bindings: net: Add SoC-e SWIP MDIO controller Vasilij Strassheim
@ 2026-09-23 10:39 ` Vasilij Strassheim
  2026-09-25 23:05   ` Andrew Lunn
  2026-09-23 10:39 ` [PATCH net-next v3 4/8] net: dsa: Add tag handling for SoC-e switches Vasilij Strassheim
                   ` (4 subsequent siblings)
  7 siblings, 1 reply; 17+ messages in thread
From: Vasilij Strassheim @ 2026-09-23 10:39 UTC (permalink / raw)
  To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Andrew Lunn,
	Vladimir Oltean, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Russell King, Andrew Lunn,
	Heiner Kallweit
  Cc: devicetree, linux-kernel, netdev, Martin Kaistra,
	Benedikt Spranger, Vasilij Strassheim

Add a binding for SoC-e FPGA-based Ethernet switch IP cores.

The compatible identifies a register layout characterized by the core
and feature identification registers at the encoded offsets. The
concrete synthesis-time configuration is then autodetected from these
registers.

Describe the Ethernet ports and the optional integrated MDIO controller
with its generic MMIO mux and child buses.

Signed-off-by: Vasilij Strassheim <v.strassheim@linutronix.de>
---
 .../devicetree/bindings/net/dsa/soce,swip.yaml     | 162 +++++++++++++++++++++
 1 file changed, 162 insertions(+)

diff --git a/Documentation/devicetree/bindings/net/dsa/soce,swip.yaml b/Documentation/devicetree/bindings/net/dsa/soce,swip.yaml
new file mode 100644
index 000000000000..d614fb2a29d3
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/dsa/soce,swip.yaml
@@ -0,0 +1,162 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/net/dsa/soce,swip.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: SoC-e ethernet switch IP core for FPGAs
+
+maintainers:
+  - Vasilij Strassheim <v.strassheim@linutronix.de>
+
+description:
+  SoC-e Ethernet switch IP cores are FPGA-based switches whose features
+  and number of ports are selected at synthesis time. Ports can connect
+  to CPUs, external PHYs, FPGA logic, or other switch cores. An integrated
+  MDIO controller accesses the per-port external buses through a mux.
+
+$ref: dsa.yaml#
+
+properties:
+  compatible:
+    const: soce,swip-00-04-0c-10
+    description:
+      Register layout with the core version register at offset 0x00 and
+      feature identification registers at offsets 0x04, 0x0c, and 0x10.
+      Switch instances using this register layout are autodetected from
+      these registers and use this compatible regardless of their
+      synthesis-time feature and port configuration.
+
+  reg:
+    maxItems: 1
+
+  '#address-cells':
+    const: 1
+
+  '#size-cells':
+    const: 1
+
+  ranges: true
+
+  mdio@204:
+    $ref: /schemas/net/soce,swip-mdio.yaml#
+    unevaluatedProperties: false
+    description:
+      Integrated MDIO controller bus on the master side of the mux.
+
+  mdio-mux@202:
+    $ref: /schemas/net/mdio-mux-mmioreg.yaml#
+    unevaluatedProperties: false
+
+  ethernet-ports:
+    type: object
+    patternProperties:
+      '^ethernet-port@[0-9a-f]+$':
+        type: object
+        $ref: dsa-port.yaml#
+        unevaluatedProperties: false
+
+        properties:
+          reg:
+            maximum: 30
+            description:
+              Switch port index. Supported switch configurations have
+              up to 31 ports, numbered from 0 through 30.
+
+          phy-mode:
+            enum:
+              - mii
+              - gmii
+              - rmii
+              - rgmii
+              - rgmii-id
+              - rgmii-rxid
+              - rgmii-txid
+
+        required:
+          - reg
+          - phy-mode
+
+required:
+  - compatible
+  - reg
+  - ethernet-ports
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    ethernet-switch@80020000 {
+        compatible = "soce,swip-00-04-0c-10";
+        reg = <0x80020000 0x10000>;
+        #address-cells = <1>;
+        #size-cells = <1>;
+        ranges = <0x0 0x80020000 0x10000>;
+
+        mdio_parent: mdio@204 {
+            compatible = "soce,swip-mdio-23-02";
+            reg = <0x204 0xc>, <0x200 0x4>;
+            reg-names = "data", "control";
+            #address-cells = <1>;
+            #size-cells = <0>;
+        };
+
+        mdio-mux@202 {
+            compatible = "mdio-mux-mmioreg", "mdio-mux";
+            reg = <0x202 0x2>;
+            mux-mask = <0x07ff>;
+            mdio-parent-bus = <&mdio_parent>;
+            #address-cells = <1>;
+            #size-cells = <0>;
+
+            mdio@0 {
+                reg = <0>;
+                #address-cells = <1>;
+                #size-cells = <0>;
+
+                switchphy0: ethernet-phy@1 {
+                    compatible = "ethernet-phy-ieee802.3-c22";
+                    reg = <1>;
+                };
+            };
+
+            mdio@1 {
+                reg = <1>;
+                #address-cells = <1>;
+                #size-cells = <0>;
+
+                switchphy1: ethernet-phy@1 {
+                    compatible = "ethernet-phy-ieee802.3-c22";
+                    reg = <1>;
+                };
+            };
+        };
+
+        ethernet-ports {
+            #address-cells = <1>;
+            #size-cells = <0>;
+
+            ethernet-port@0 {
+                reg = <0>;
+                phy-handle = <&switchphy0>;
+                phy-mode = "rgmii-id";
+            };
+
+            ethernet-port@1 {
+                reg = <1>;
+                phy-handle = <&switchphy1>;
+                phy-mode = "rgmii-id";
+            };
+
+            ethernet-port@2 {
+                reg = <2>;
+                ethernet = <&eth0>;
+                phy-mode = "gmii";
+
+                fixed-link {
+                    speed = <1000>;
+                    full-duplex;
+                };
+            };
+        };
+    };

-- 
2.39.5


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

* [PATCH net-next v3 4/8] net: dsa: Add tag handling for SoC-e switches
  2026-09-23 10:39 [PATCH net-next v3 0/8] net: dsa: Add SoC-e DSA driver Vasilij Strassheim
                   ` (2 preceding siblings ...)
  2026-09-23 10:39 ` [PATCH net-next v3 3/8] dt-bindings: net: dsa: Add SoC-e SWIP switch Vasilij Strassheim
@ 2026-09-23 10:39 ` Vasilij Strassheim
       [not found]   ` <20260924104003.A49F31F000FF@smtp.kernel.org>
  2026-09-23 10:39 ` [PATCH net-next v3 5/8] net: mdio: Add SoC-e SWIP MDIO controller driver Vasilij Strassheim
                   ` (3 subsequent siblings)
  7 siblings, 1 reply; 17+ messages in thread
From: Vasilij Strassheim @ 2026-09-23 10:39 UTC (permalink / raw)
  To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Andrew Lunn,
	Vladimir Oltean, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Russell King, Andrew Lunn,
	Heiner Kallweit
  Cc: devicetree, linux-kernel, netdev, Martin Kaistra,
	Benedikt Spranger, Vasilij Strassheim

SoC-e switches exchange frames with the conduit using an 8-byte SDSA
header inserted between the source MAC address and the original
EtherType. The header identifies itself with EtherType 0xdcdc and
carries the frame direction and a 10-bit source or destination port.

Add transmit support for FROM_CPU frames and receive support for TO_CPU
frames. Validate the EtherType, frame type, header length, and source
port before accepting received frames.

The SDSA header can also carry an 802.1Q TCI. Encode accelerated VLAN
metadata into the header on transmit and restore it as skb VLAN metadata
on receive.

Signed-off-by: Vasilij Strassheim <v.strassheim@linutronix.de>
---
 include/net/dsa.h  |   2 +
 net/dsa/Kconfig    |   6 ++
 net/dsa/Makefile   |   1 +
 net/dsa/tag_sdsa.c | 158 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 167 insertions(+)

diff --git a/include/net/dsa.h b/include/net/dsa.h
index 5d12191b6f6f..8287fba8b107 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -62,6 +62,7 @@ struct tc_action;
 #define DSA_TAG_PROTO_KSZ8463_VALUE		34
 #define DSA_TAG_PROTO_MT7628_VALUE		35
 #define DSA_TAG_PROTO_KS8995_VALUE		36
+#define DSA_TAG_PROTO_SDSA_VALUE		37
 
 enum dsa_tag_protocol {
 	DSA_TAG_PROTO_NONE		= DSA_TAG_PROTO_NONE_VALUE,
@@ -101,6 +102,7 @@ enum dsa_tag_protocol {
 	DSA_TAG_PROTO_KSZ8463		= DSA_TAG_PROTO_KSZ8463_VALUE,
 	DSA_TAG_PROTO_MT7628		= DSA_TAG_PROTO_MT7628_VALUE,
 	DSA_TAG_PROTO_KS8995		= DSA_TAG_PROTO_KS8995_VALUE,
+	DSA_TAG_PROTO_SDSA		= DSA_TAG_PROTO_SDSA_VALUE,
 };
 
 struct dsa_switch;
diff --git a/net/dsa/Kconfig b/net/dsa/Kconfig
index 4f44bf3ede23..9b299cada316 100644
--- a/net/dsa/Kconfig
+++ b/net/dsa/Kconfig
@@ -194,6 +194,12 @@ config NET_DSA_TAG_RZN1_A5PSW
 	  Renesas RZ/N1 embedded switch that uses an 8 byte tag located after
 	  destination MAC address.
 
+config NET_DSA_TAG_SDSA
+	tristate "Tag driver for SoC-e switches using EtherType SDSA headers"
+	help
+	  Say Y or M if you want to enable support for tagging frames for the
+	  SoC-e switches.
+
 config NET_DSA_TAG_LAN9303
 	tristate "Tag driver for SMSC/Microchip LAN9303 family of switches"
 	help
diff --git a/net/dsa/Makefile b/net/dsa/Makefile
index 1f9cc30e9988..a4c8d0e6bc0f 100644
--- a/net/dsa/Makefile
+++ b/net/dsa/Makefile
@@ -40,6 +40,7 @@ obj-$(CONFIG_NET_DSA_TAG_QCA) += tag_qca.o
 obj-$(CONFIG_NET_DSA_TAG_RTL4_A) += tag_rtl4_a.o
 obj-$(CONFIG_NET_DSA_TAG_RTL8_4) += tag_rtl8_4.o
 obj-$(CONFIG_NET_DSA_TAG_RZN1_A5PSW) += tag_rzn1_a5psw.o
+obj-$(CONFIG_NET_DSA_TAG_SDSA) += tag_sdsa.o
 obj-$(CONFIG_NET_DSA_TAG_SJA1105) += tag_sja1105.o
 obj-$(CONFIG_NET_DSA_TAG_TRAILER) += tag_trailer.o
 obj-$(CONFIG_NET_DSA_TAG_VSC73XX_8021Q) += tag_vsc73xx_8021q.o
diff --git a/net/dsa/tag_sdsa.c b/net/dsa/tag_sdsa.c
new file mode 100644
index 000000000000..8cc3fa357be4
--- /dev/null
+++ b/net/dsa/tag_sdsa.c
@@ -0,0 +1,158 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2020-2026 System on Chip engineering, S.L.
+ * Copyright (c) 2026 Linutronix GmbH
+ * Author: Vasilij Strassheim <v.strassheim@linutronix.de>
+ */
+
+#include <linux/bitops.h>
+#include <linux/byteorder/generic.h>
+#include <linux/etherdevice.h>
+#include <linux/if_vlan.h>
+#include <linux/unaligned.h>
+
+#include "tag.h"
+
+#define SDSA_HLEN	8
+
+#define SDSA_NAME	"sdsa"
+#define ETH_P_SDSA	0xDCDC
+
+/* SDSA tag byte layout (after the 12-byte MAC header):
+ * Bytes 0-1: SDSA EtherType (0xDCDC)
+ * Bytes 2-3: Reserved
+ * Byte 4:    Frame type (bits 7-6), VLAN-info bit (bit 5), port[9:5] (bits 4-0)
+ * Byte 5:    Port[4:0] (bits 7-3)
+ * Bytes 6-7: PCP (bits 7-5) / CFI (bit 4) / VID (bits 3-0 + byte 7), only
+ *            meaningful when the VLAN-info bit is set.
+ */
+#define SDSA_TAG_FRAME_TYPE_MASK	GENMASK(7, 6)
+#define SDSA_TAG_VLAN_BIT		BIT(5)
+#define SDSA_TAG_PORT_HI_MASK		GENMASK(4, 0)
+#define SDSA_TAG_PORT_LO_MASK		GENMASK(7, 3)
+#define SDSA_TAG_PORT_HI_SHIFT		5
+#define SDSA_FRAME_TYPE_TO_CPU		0
+#define SDSA_FRAME_TYPE_FROM_CPU	1
+
+struct sdsa_tag {
+	__be16 ethertype;
+	__be16 reserved;
+	u8 frame_type_port_hi;
+	u8 port_lo;
+	__be16 vlan;
+};
+
+static struct sk_buff *sdsa_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct dsa_port *dp = dsa_user_to_port(dev);
+	struct sdsa_tag *tag;
+	u16 vlan_tci;
+
+	BUILD_BUG_ON(sizeof(*tag) != SDSA_HLEN);
+
+	skb_push(skb, SDSA_HLEN);
+	dsa_alloc_etype_header(skb, SDSA_HLEN);
+
+	tag = dsa_etype_header_pos_tx(skb);
+	tag->ethertype = cpu_to_be16(ETH_P_SDSA);
+	tag->reserved = 0;
+	tag->frame_type_port_hi =
+		FIELD_PREP(SDSA_TAG_FRAME_TYPE_MASK, SDSA_FRAME_TYPE_FROM_CPU) |
+		FIELD_PREP(SDSA_TAG_PORT_HI_MASK,
+			   dp->index >> SDSA_TAG_PORT_HI_SHIFT);
+	tag->port_lo = FIELD_PREP(SDSA_TAG_PORT_LO_MASK, dp->index);
+	/* SDSA carries no TPID, so only encode 802.1Q C-tags. */
+	if (skb_vlan_tag_present(skb) &&
+	    skb->vlan_proto == htons(ETH_P_8021Q)) {
+		vlan_tci = skb_vlan_tag_get(skb);
+		__vlan_hwaccel_clear_tag(skb);
+		tag->frame_type_port_hi |= SDSA_TAG_VLAN_BIT;
+		tag->vlan = cpu_to_be16(vlan_tci);
+	} else {
+		tag->vlan = 0;
+	}
+
+	return skb;
+}
+
+static struct sk_buff *sdsa_rcv(struct sk_buff *skb, struct net_device *dev)
+{
+	enum skb_drop_reason reason;
+	struct sdsa_tag *tag;
+	u16 dummy_vlan_tci;
+	bool vlan_present;
+	int source_port;
+	u16 encap_proto;
+	u8 frame_type;
+	u16 vlan_tci;
+
+	if (unlikely(!pskb_may_pull(skb, SDSA_HLEN))) {
+		reason = SKB_DROP_REASON_HDR_TRUNC;
+		goto out_drop;
+	}
+
+	tag = dsa_etype_header_pos_rx(skb);
+	if (unlikely(be16_to_cpu(tag->ethertype) != ETH_P_SDSA)) {
+		reason = SKB_DROP_REASON_DEV_HDR;
+		goto out_drop;
+	}
+
+	frame_type = FIELD_GET(SDSA_TAG_FRAME_TYPE_MASK,
+			       tag->frame_type_port_hi);
+	if (frame_type != SDSA_FRAME_TYPE_TO_CPU) {
+		reason = SKB_DROP_REASON_DEV_HDR;
+		goto out_drop;
+	}
+
+	vlan_present = tag->frame_type_port_hi & SDSA_TAG_VLAN_BIT;
+	vlan_tci = be16_to_cpu(tag->vlan);
+	encap_proto = get_unaligned_be16((u8 *)tag + SDSA_HLEN);
+
+	source_port = FIELD_GET(SDSA_TAG_PORT_HI_MASK,
+				tag->frame_type_port_hi) <<
+		      SDSA_TAG_PORT_HI_SHIFT;
+	source_port |= FIELD_GET(SDSA_TAG_PORT_LO_MASK, tag->port_lo);
+
+	skb->dev = dsa_conduit_find_user(dev, 0, source_port);
+	if (!skb->dev) {
+		reason = SKB_DROP_REASON_DEV_HDR;
+		goto out_drop;
+	}
+
+	skb_pull_rcsum(skb, SDSA_HLEN);
+	dsa_strip_etype_header(skb, SDSA_HLEN);
+	if (vlan_present) {
+		if (encap_proto == ETH_P_8021Q) {
+			skb_push_rcsum(skb, ETH_HLEN);
+			skb_reset_mac_header(skb);
+			if (__skb_vlan_pop(skb, &dummy_vlan_tci)) {
+				reason = SKB_DROP_REASON_NOMEM;
+				goto out_drop;
+			}
+			skb_pull_rcsum(skb, ETH_HLEN);
+		}
+
+		__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan_tci);
+	}
+
+	dsa_default_offload_fwd_mark(skb);
+	return skb;
+
+out_drop:
+	kfree_skb_reason(skb, reason);
+	return NULL;
+}
+
+static const struct dsa_device_ops sdsa_netdev_ops = {
+	.name = SDSA_NAME,
+	.proto = DSA_TAG_PROTO_SDSA,
+	.xmit = sdsa_xmit,
+	.rcv = sdsa_rcv,
+	.needed_headroom = SDSA_HLEN,
+};
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("DSA tag driver for SoC-e SDSA protocol");
+MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_SDSA, SDSA_NAME);
+
+module_dsa_tag_driver(sdsa_netdev_ops);

-- 
2.39.5


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

* [PATCH net-next v3 5/8] net: mdio: Add SoC-e SWIP MDIO controller driver
  2026-09-23 10:39 [PATCH net-next v3 0/8] net: dsa: Add SoC-e DSA driver Vasilij Strassheim
                   ` (3 preceding siblings ...)
  2026-09-23 10:39 ` [PATCH net-next v3 4/8] net: dsa: Add tag handling for SoC-e switches Vasilij Strassheim
@ 2026-09-23 10:39 ` Vasilij Strassheim
  2026-09-25 23:10   ` Andrew Lunn
  2026-09-23 10:39 ` [PATCH net-next v3 6/8] net: dsa: soce: Add basic support for SoC-e switch IP cores Vasilij Strassheim
                   ` (2 subsequent siblings)
  7 siblings, 1 reply; 17+ messages in thread
From: Vasilij Strassheim @ 2026-09-23 10:39 UTC (permalink / raw)
  To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Andrew Lunn,
	Vladimir Oltean, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Russell King, Andrew Lunn,
	Heiner Kallweit
  Cc: devicetree, linux-kernel, netdev, Martin Kaistra,
	Benedikt Spranger, Vasilij Strassheim

Add a driver for the MDIO controller integrated into SoC-e Ethernet
switch IP cores. Support Clause 22 transactions and the separate address
and data cycles required for Clause 45 accesses.

The transaction control register is shared with the external MDIO bus
selector. The selector occupies bits 26:16 and is managed by a generic
MMIO MDIO mux through the upper 16-bit halfword. Preserve those bits
when starting a transaction.

Check that the controller is idle before programming transaction
registers and poll for completion after each transaction cycle. Return a
timeout instead of waiting indefinitely, and allow a later access to
retry if the hardware becomes idle again.

Signed-off-by: Vasilij Strassheim <v.strassheim@linutronix.de>
---
 drivers/net/mdio/Kconfig     |   7 ++
 drivers/net/mdio/Makefile    |   1 +
 drivers/net/mdio/mdio-soce.c | 239 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 247 insertions(+)

diff --git a/drivers/net/mdio/Kconfig b/drivers/net/mdio/Kconfig
index d44278f26fab..21f2b516880b 100644
--- a/drivers/net/mdio/Kconfig
+++ b/drivers/net/mdio/Kconfig
@@ -189,6 +189,13 @@ config MDIO_REGMAP
 	  regmap. Users willing to use this driver must explicitly select
 	  REGMAP.
 
+config MDIO_SOCE
+	tristate "SoC-e MDIO controller"
+	depends on OF_MDIO && HAS_IOMEM
+	help
+	  This module provides a driver for the MDIO controller integrated
+	  into SoC-e Ethernet switch IP cores.
+
 config MDIO_THUNDER
 	tristate "ThunderX SOCs MDIO buses"
 	depends on 64BIT
diff --git a/drivers/net/mdio/Makefile b/drivers/net/mdio/Makefile
index 048586746026..079b46dea25f 100644
--- a/drivers/net/mdio/Makefile
+++ b/drivers/net/mdio/Makefile
@@ -23,6 +23,7 @@ obj-$(CONFIG_MDIO_OCTEON)		+= mdio-octeon.o
 obj-$(CONFIG_MDIO_PIC64HPSC)		+= mdio-pic64hpsc.o
 obj-$(CONFIG_MDIO_REALTEK_RTL9300)	+= mdio-realtek-rtl9300.o
 obj-$(CONFIG_MDIO_REGMAP)		+= mdio-regmap.o
+obj-$(CONFIG_MDIO_SOCE)			+= mdio-soce.o
 obj-$(CONFIG_MDIO_SUN4I)		+= mdio-sun4i.o
 obj-$(CONFIG_MDIO_THUNDER)		+= mdio-thunder.o
 obj-$(CONFIG_MDIO_XGENE)		+= mdio-xgene.o
diff --git a/drivers/net/mdio/mdio-soce.c b/drivers/net/mdio/mdio-soce.c
new file mode 100644
index 000000000000..59c0b3da483e
--- /dev/null
+++ b/drivers/net/mdio/mdio-soce.c
@@ -0,0 +1,239 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2020-2026 System on Chip engineering, S.L.
+ * Copyright (c) 2026 Linutronix GmbH
+ * Author: Vasilij Strassheim <v.strassheim@linutronix.de>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_mdio.h>
+#include <linux/platform_device.h>
+
+#define SOCE_MDIO_TIMEOUT_US		1000
+
+#define SOCE_MDIO_PARAMS_OFFSET		0x0000
+#define SOCE_MDIO_WRITE_OFFSET		0x0004
+#define SOCE_MDIO_READ_OFFSET		0x0008
+#define SOCE_MDIO_DATA_IOMAP_IDX	0
+#define SOCE_MDIO_CTRL_IOMAP_IDX	1
+
+#define SOCE_MDIO_CTRL_BUS_MASK		GENMASK(26, 16)
+#define SOCE_MDIO_CTRL_TRANSTYPE_MASK	GENMASK(4, 3)
+#define SOCE_MDIO_CTRL_TRANSTYPE_WRITE	0x1
+#define SOCE_MDIO_CTRL_TRANSTYPE_READ	0x3
+#define SOCE_MDIO_CTRL_CLAUSE		BIT(1)
+#define SOCE_MDIO_CTRL_OPSTATUS		BIT(0)
+#define SOCE_MDIO_PARAMS_REGDEV_MASK	GENMASK(12, 8)
+#define SOCE_MDIO_PARAMS_PHYADDR_MASK	GENMASK(4, 0)
+#define SOCE_MDIO_READ_DATA_MASK	GENMASK(15, 0)
+
+struct soce_mdio {
+	void __iomem *ctrl;
+	void __iomem *data;
+};
+
+static void __iomem *soce_mdio_iomap(struct device *dev, int index)
+{
+	struct resource res;
+	int ret;
+
+	ret = of_address_to_resource(dev->of_node, index, &res);
+	if (ret)
+		return IOMEM_ERR_PTR(ret);
+
+	return devm_ioremap(dev, res.start, resource_size(&res));
+}
+
+static int soce_mdio_wait_for_idle(struct soce_mdio *priv)
+{
+	void __iomem *ctrl = priv->ctrl;
+	u32 val;
+
+	return readl_poll_timeout(ctrl, val,
+		!(val & SOCE_MDIO_CTRL_OPSTATUS), 10,
+		SOCE_MDIO_TIMEOUT_US);
+}
+
+static void soce_mdio_start(struct soce_mdio *priv, u32 command)
+{
+	void __iomem *ctrl = priv->ctrl;
+
+	/* Keep the currently selected MDIO bus while updating op bits. */
+	command |= readl(ctrl) & SOCE_MDIO_CTRL_BUS_MASK;
+	writel(command, ctrl);
+}
+
+static int soce_mdio_read(struct mii_bus *bus, int phy_addr, int regnum)
+{
+	struct soce_mdio *priv = bus->priv;
+	void __iomem *data = priv->data;
+	u32 command;
+	int ret;
+
+	ret = soce_mdio_wait_for_idle(priv);
+	if (ret)
+		return ret;
+
+	writel(FIELD_PREP(SOCE_MDIO_PARAMS_REGDEV_MASK, regnum) |
+	       FIELD_PREP(SOCE_MDIO_PARAMS_PHYADDR_MASK, phy_addr),
+	       data + SOCE_MDIO_PARAMS_OFFSET);
+
+	command = FIELD_PREP(SOCE_MDIO_CTRL_TRANSTYPE_MASK,
+			     SOCE_MDIO_CTRL_TRANSTYPE_READ) |
+		  SOCE_MDIO_CTRL_OPSTATUS;
+	soce_mdio_start(priv, command);
+
+	ret = soce_mdio_wait_for_idle(priv);
+	if (ret)
+		return ret;
+
+	return readl(data + SOCE_MDIO_READ_OFFSET) & SOCE_MDIO_READ_DATA_MASK;
+}
+
+static int soce_mdio_read_c45(struct mii_bus *bus, int phy_addr, int devad,
+			      int regnum)
+{
+	struct soce_mdio *priv = bus->priv;
+	void __iomem *data = priv->data;
+	u32 command;
+	int ret;
+
+	ret = soce_mdio_wait_for_idle(priv);
+	if (ret)
+		return ret;
+
+	writel(FIELD_PREP(SOCE_MDIO_PARAMS_REGDEV_MASK, devad) |
+	       FIELD_PREP(SOCE_MDIO_PARAMS_PHYADDR_MASK, phy_addr),
+	       data + SOCE_MDIO_PARAMS_OFFSET);
+	writel(regnum, data + SOCE_MDIO_WRITE_OFFSET);
+
+	command = SOCE_MDIO_CTRL_CLAUSE | SOCE_MDIO_CTRL_OPSTATUS;
+	soce_mdio_start(priv, command);
+
+	ret = soce_mdio_wait_for_idle(priv);
+	if (ret)
+		return ret;
+
+	command = FIELD_PREP(SOCE_MDIO_CTRL_TRANSTYPE_MASK,
+			     SOCE_MDIO_CTRL_TRANSTYPE_READ) |
+		  SOCE_MDIO_CTRL_CLAUSE | SOCE_MDIO_CTRL_OPSTATUS;
+	soce_mdio_start(priv, command);
+
+	ret = soce_mdio_wait_for_idle(priv);
+	if (ret)
+		return ret;
+
+	return readl(data + SOCE_MDIO_READ_OFFSET) & SOCE_MDIO_READ_DATA_MASK;
+}
+
+static int soce_mdio_write(struct mii_bus *bus, int phy_addr, int regnum,
+			   u16 val)
+{
+	struct soce_mdio *priv = bus->priv;
+	void __iomem *data = priv->data;
+	u32 command;
+	int ret;
+
+	ret = soce_mdio_wait_for_idle(priv);
+	if (ret)
+		return ret;
+
+	writel(FIELD_PREP(SOCE_MDIO_PARAMS_REGDEV_MASK, regnum) |
+	       FIELD_PREP(SOCE_MDIO_PARAMS_PHYADDR_MASK, phy_addr),
+	       data + SOCE_MDIO_PARAMS_OFFSET);
+	writel(val, data + SOCE_MDIO_WRITE_OFFSET);
+
+	command = FIELD_PREP(SOCE_MDIO_CTRL_TRANSTYPE_MASK,
+			     SOCE_MDIO_CTRL_TRANSTYPE_WRITE) |
+		  SOCE_MDIO_CTRL_OPSTATUS;
+	soce_mdio_start(priv, command);
+
+	return soce_mdio_wait_for_idle(priv);
+}
+
+static int soce_mdio_write_c45(struct mii_bus *bus, int phy_addr, int devad,
+			       int regnum, u16 val)
+{
+	struct soce_mdio *priv = bus->priv;
+	void __iomem *data = priv->data;
+	u32 command;
+	int ret;
+
+	ret = soce_mdio_wait_for_idle(priv);
+	if (ret)
+		return ret;
+
+	writel(FIELD_PREP(SOCE_MDIO_PARAMS_REGDEV_MASK, devad) |
+	       FIELD_PREP(SOCE_MDIO_PARAMS_PHYADDR_MASK, phy_addr),
+	       data + SOCE_MDIO_PARAMS_OFFSET);
+	writel(regnum, data + SOCE_MDIO_WRITE_OFFSET);
+
+	command = SOCE_MDIO_CTRL_CLAUSE | SOCE_MDIO_CTRL_OPSTATUS;
+	soce_mdio_start(priv, command);
+
+	ret = soce_mdio_wait_for_idle(priv);
+	if (ret)
+		return ret;
+
+	writel(val, data + SOCE_MDIO_WRITE_OFFSET);
+
+	command = FIELD_PREP(SOCE_MDIO_CTRL_TRANSTYPE_MASK,
+			     SOCE_MDIO_CTRL_TRANSTYPE_WRITE) |
+		  SOCE_MDIO_CTRL_CLAUSE | SOCE_MDIO_CTRL_OPSTATUS;
+	soce_mdio_start(priv, command);
+
+	return soce_mdio_wait_for_idle(priv);
+}
+
+static int soce_mdio_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct soce_mdio *priv;
+	struct mii_bus *bus;
+
+	bus = devm_mdiobus_alloc_size(dev, sizeof(*priv));
+	if (!bus)
+		return -ENOMEM;
+
+	priv = bus->priv;
+	priv->data = soce_mdio_iomap(dev, SOCE_MDIO_DATA_IOMAP_IDX);
+	if (IS_ERR(priv->data))
+		return PTR_ERR(priv->data);
+
+	priv->ctrl = soce_mdio_iomap(dev, SOCE_MDIO_CTRL_IOMAP_IDX);
+	if (IS_ERR(priv->ctrl))
+		return PTR_ERR(priv->ctrl);
+
+	bus->name = "soce mdio";
+	snprintf(bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev));
+	bus->parent = dev;
+	bus->read = soce_mdio_read;
+	bus->write = soce_mdio_write;
+	bus->read_c45 = soce_mdio_read_c45;
+	bus->write_c45 = soce_mdio_write_c45;
+
+	return devm_of_mdiobus_register(dev, bus, dev->of_node);
+}
+
+static const struct of_device_id soce_mdio_of_match[] = {
+	{ .compatible = "soce,swip-mdio-23-02" },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, soce_mdio_of_match);
+
+static struct platform_driver soce_mdio_driver = {
+	.probe = soce_mdio_probe,
+	.driver = {
+		.name = "soce-mdio",
+		.of_match_table = soce_mdio_of_match,
+	},
+};
+module_platform_driver(soce_mdio_driver);
+
+MODULE_AUTHOR("Vasilij Strassheim <v.strassheim@linutronix.de>");
+MODULE_DESCRIPTION("SoC-e MDIO controller driver");
+MODULE_LICENSE("GPL");

-- 
2.39.5


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

* [PATCH net-next v3 6/8] net: dsa: soce: Add basic support for SoC-e switch IP cores
  2026-09-23 10:39 [PATCH net-next v3 0/8] net: dsa: Add SoC-e DSA driver Vasilij Strassheim
                   ` (4 preceding siblings ...)
  2026-09-23 10:39 ` [PATCH net-next v3 5/8] net: mdio: Add SoC-e SWIP MDIO controller driver Vasilij Strassheim
@ 2026-09-23 10:39 ` Vasilij Strassheim
  2026-09-25 23:17   ` Andrew Lunn
  2026-09-25 23:20   ` Andrew Lunn
  2026-09-23 10:39 ` [PATCH net-next v3 7/8] net: dsa: soce: Add VLAN offload support Vasilij Strassheim
  2026-09-23 10:39 ` [PATCH net-next v3 8/8] net: dsa: soce: Disable unsupported hardware STP Vasilij Strassheim
  7 siblings, 2 replies; 17+ messages in thread
From: Vasilij Strassheim @ 2026-09-23 10:39 UTC (permalink / raw)
  To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Andrew Lunn,
	Vladimir Oltean, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Russell King, Andrew Lunn,
	Heiner Kallweit
  Cc: devicetree, linux-kernel, netdev, Martin Kaistra,
	Benedikt Spranger, Vasilij Strassheim

Add a DSA driver for SoC-e FPGA-based Ethernet switch IP cores.

Read the core version and synthesis-time feature registers during probe.
Require DSA support and between 3 and 31 implemented ports, without
exceeding the licensed port count. Derive each port's phylink
capabilities from its phy-mode.

Enable "DSA custom rules" tagging for all frames during setup. This
directs ingress traffic from user ports to the CPU port while standalone
ports remain isolated. Enable and disable port ingress and egress
through the DSA port callbacks, and disable tagging again during
teardown so that unbinding the driver does not leave its managed
configuration active.

Populate the integrated MDIO controller and mux child devices used for
external PHY access.

Tested with a SoC-e MRS 25.01 IP core on a Xilinx ZynqMP platform.

Signed-off-by: Vasilij Strassheim <v.strassheim@linutronix.de>
---
 drivers/net/dsa/Kconfig              |   2 +
 drivers/net/dsa/Makefile             |   1 +
 drivers/net/dsa/soce/Kconfig         |  14 ++
 drivers/net/dsa/soce/Makefile        |   4 +
 drivers/net/dsa/soce/soce_dsa.h      |  26 +++
 drivers/net/dsa/soce/soce_dsa_core.c | 343 +++++++++++++++++++++++++++++++++++
 6 files changed, 390 insertions(+)

diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig
index fe8cd5338fda..879fbede83f0 100644
--- a/drivers/net/dsa/Kconfig
+++ b/drivers/net/dsa/Kconfig
@@ -94,6 +94,8 @@ source "drivers/net/dsa/ocelot/Kconfig"
 
 source "drivers/net/dsa/qca/Kconfig"
 
+source "drivers/net/dsa/soce/Kconfig"
+
 source "drivers/net/dsa/sja1105/Kconfig"
 
 source "drivers/net/dsa/xrs700x/Kconfig"
diff --git a/drivers/net/dsa/Makefile b/drivers/net/dsa/Makefile
index 7e637d56b35c..97de3d181440 100644
--- a/drivers/net/dsa/Makefile
+++ b/drivers/net/dsa/Makefile
@@ -26,4 +26,5 @@ obj-y				+= ocelot/
 obj-y				+= qca/
 obj-y				+= realtek/
 obj-y				+= sja1105/
+obj-y				+= soce/
 obj-y				+= xrs700x/
diff --git a/drivers/net/dsa/soce/Kconfig b/drivers/net/dsa/soce/Kconfig
new file mode 100644
index 000000000000..c31b7c5af695
--- /dev/null
+++ b/drivers/net/dsa/soce/Kconfig
@@ -0,0 +1,14 @@
+# SPDX-License-Identifier: GPL-2.0
+config NET_DSA_SOCE
+	tristate "SoC-e switches"
+	depends on NET_DSA
+	depends on OF
+	depends on HAS_IOMEM
+	select MDIO_BUS_MUX_MMIOREG
+	select MDIO_SOCE
+	select NET_DSA_TAG_SDSA
+	help
+	  This enables support for switches based on SoC-e IP cores.
+	  Frames are exchanged with the CPU port using the SDSA DSA tag protocol.
+	  The driver supports switch variants whose features and number of ports
+	  are selected at synthesis time and detected at runtime.
diff --git a/drivers/net/dsa/soce/Makefile b/drivers/net/dsa/soce/Makefile
new file mode 100644
index 000000000000..2a6d95ef663f
--- /dev/null
+++ b/drivers/net/dsa/soce/Makefile
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_NET_DSA_SOCE) += soce_dsa.o
+soce_dsa-objs := soce_dsa_core.o
diff --git a/drivers/net/dsa/soce/soce_dsa.h b/drivers/net/dsa/soce/soce_dsa.h
new file mode 100644
index 000000000000..2acd4dbaf958
--- /dev/null
+++ b/drivers/net/dsa/soce/soce_dsa.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2020-2026 System on Chip engineering, S.L.
+ * Copyright (c) 2026 Linutronix GmbH
+ * Author: Vasilij Strassheim <v.strassheim@linutronix.de>
+ */
+
+#ifndef __SOCE_DSA_H
+#define __SOCE_DSA_H
+
+#include <linux/types.h>
+
+#include <net/dsa.h>
+
+#define SOCE_MAX_NUM_PORTS 31
+
+struct soce_dsa_local {
+	void __iomem *base_addr;
+};
+
+struct soce_priv {
+	struct soce_dsa_local local;
+	struct dsa_switch ds;
+};
+
+#endif /* __SOCE_DSA_H */
diff --git a/drivers/net/dsa/soce/soce_dsa_core.c b/drivers/net/dsa/soce/soce_dsa_core.c
new file mode 100644
index 000000000000..d391b11b94ad
--- /dev/null
+++ b/drivers/net/dsa/soce/soce_dsa_core.c
@@ -0,0 +1,343 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2020-2026 System on Chip engineering, S.L.
+ * Copyright (c) 2026 Linutronix GmbH
+ * Author: Vasilij Strassheim <v.strassheim@linutronix.de>
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/of.h>
+#include <linux/of_net.h>
+#include <linux/of_platform.h>
+#include <linux/phy.h>
+#include <linux/phylink.h>
+#include <linux/platform_device.h>
+
+#include <net/dsa.h>
+
+#include "soce_dsa.h"
+
+#define SOCE_MIN_NUM_PORTS			3
+
+#define SOCE_CORE_VERSION_OFFSET		0x0000
+#define SOCE_CORE_VERSION_VERSION_SHIFT		24
+#define SOCE_CORE_VERSION_SUBVERSION_SHIFT	16
+#define SOCE_MIN_CORE_VERSION			0x24
+#define SOCE_MIN_CORE_SUBVERSION		0x01
+
+#define SOCE_LIC_FEATURES_OFFSET		0x0004
+#define SOCE_LIC_FEATURES_NUM_PORTS_MASK	GENMASK(31, 27)
+
+#define SOCE_IMPL_FEATURES0_OFFSET		0x000c
+#define SOCE_IMPL_FEATURES0_NUM_PORTS_MASK	GENMASK(31, 27)
+#define SOCE_IMPL_FEATURES0_PORT_VLAN		BIT(9)
+#define SOCE_IMPL_FEATURES0_DSA			BIT(23)
+
+#define SOCE_DSA_REGS_BASE			0x1200
+#define SOCE_TAG_ALL_FRAMES_CTRL_OFFSET		(SOCE_DSA_REGS_BASE + 0x001c)
+#define SOCE_TAG_ALL_FRAMES_CTRL_ENABLE		BIT(0)
+#define SOCE_CUSTOM_RULES_TAGGING_OFFSET	(SOCE_DSA_REGS_BASE + 0x0020)
+#define SOCE_CUSTOM_RULES_TAGGING_ENABLE	BIT(0)
+
+#define SOCE_PORTS_REGS_BASE			0x3000
+#define SOCE_PORTS_SELECTOR_OFFSET		SOCE_PORTS_REGS_BASE
+#define SOCE_PORTS_SELECTOR_PORT_MASK		GENMASK(7, 0)
+#define SOCE_PORTS_CTRL_OFFSET			(SOCE_PORTS_REGS_BASE + 0x0004)
+#define SOCE_PORTS_CTRL_INGR_EN			BIT(0)
+#define SOCE_PORTS_CTRL_EGR_EN			BIT(1)
+
+static void soce_phylink_get_caps(struct dsa_switch *ds, int port,
+				  struct phylink_config *config)
+{
+	struct dsa_port *dp = dsa_to_port(ds, port);
+	phy_interface_t mode;
+	int ret;
+
+	ret = of_get_phy_mode(dp->dn, &mode);
+	if (ret)
+		return;
+
+	if (phy_interface_mode_is_rgmii(mode))
+		phy_interface_set_rgmii(config->supported_interfaces);
+	else
+		__set_bit(mode, config->supported_interfaces);
+
+	config->mac_capabilities = MAC_SYM_PAUSE | MAC_ASYM_PAUSE;
+
+	switch (mode) {
+	case PHY_INTERFACE_MODE_MII:
+		config->mac_capabilities |= MAC_10 | MAC_100;
+		break;
+	case PHY_INTERFACE_MODE_GMII:
+		config->mac_capabilities |= MAC_10 | MAC_100 | MAC_1000;
+		break;
+	case PHY_INTERFACE_MODE_RMII:
+		config->mac_capabilities |= MAC_10FD | MAC_100FD;
+		break;
+	default:
+		if (phy_interface_mode_is_rgmii(mode))
+			config->mac_capabilities |= MAC_10FD | MAC_100FD |
+						    MAC_1000FD;
+		break;
+	}
+}
+
+static int soce_sw_validate_core_version(u8 version, u8 subversion)
+{
+	if (version < SOCE_MIN_CORE_VERSION ||
+	    (version == SOCE_MIN_CORE_VERSION &&
+	     subversion < SOCE_MIN_CORE_SUBVERSION))
+		return -ENODEV;
+
+	return 0;
+}
+
+static void soce_sw_read_core_version(struct soce_dsa_local *local,
+				      u8 *version, u8 *subversion,
+				      u16 *revision)
+{
+	u32 regval;
+
+	regval = readl(local->base_addr + SOCE_CORE_VERSION_OFFSET);
+	*version = (u8)(regval >> SOCE_CORE_VERSION_VERSION_SHIFT);
+	*subversion = (u8)(regval >> SOCE_CORE_VERSION_SUBVERSION_SHIFT);
+	*revision = (u16)regval;
+}
+
+static int soce_sw_detect_features(struct soce_dsa_local *local,
+				   u32 *numports)
+{
+	void __iomem *base = local->base_addr;
+	u32 implemented_numports;
+	u32 licensed_numports;
+	u32 regval;
+
+	regval = readl(base + SOCE_LIC_FEATURES_OFFSET);
+	licensed_numports = FIELD_GET(SOCE_LIC_FEATURES_NUM_PORTS_MASK, regval);
+	if (!licensed_numports || licensed_numports > SOCE_MAX_NUM_PORTS)
+		return -EINVAL;
+
+	regval = readl(base + SOCE_IMPL_FEATURES0_OFFSET);
+	if (!(regval & SOCE_IMPL_FEATURES0_DSA))
+		return -ENODEV;
+
+	implemented_numports =
+		FIELD_GET(SOCE_IMPL_FEATURES0_NUM_PORTS_MASK, regval);
+	if (implemented_numports < SOCE_MIN_NUM_PORTS ||
+	    implemented_numports > licensed_numports)
+		return -EINVAL;
+
+	*numports = implemented_numports;
+
+	return 0;
+}
+
+static void soce_sw_enable_tagging(struct soce_dsa_local *local)
+{
+	void __iomem *base = local->base_addr;
+	u32 regval;
+
+	regval = readl(base + SOCE_TAG_ALL_FRAMES_CTRL_OFFSET);
+	regval |= SOCE_TAG_ALL_FRAMES_CTRL_ENABLE;
+	writel(regval, base + SOCE_TAG_ALL_FRAMES_CTRL_OFFSET);
+
+	regval = readl(base + SOCE_CUSTOM_RULES_TAGGING_OFFSET);
+	regval |= SOCE_CUSTOM_RULES_TAGGING_ENABLE;
+	writel(regval, base + SOCE_CUSTOM_RULES_TAGGING_OFFSET);
+}
+
+static void soce_sw_disable_tagging(struct soce_dsa_local *local)
+{
+	void __iomem *base = local->base_addr;
+	u32 regval;
+
+	regval = readl(base + SOCE_TAG_ALL_FRAMES_CTRL_OFFSET);
+	regval &= ~SOCE_TAG_ALL_FRAMES_CTRL_ENABLE;
+	writel(regval, base + SOCE_TAG_ALL_FRAMES_CTRL_OFFSET);
+
+	regval = readl(base + SOCE_CUSTOM_RULES_TAGGING_OFFSET);
+	regval &= ~SOCE_CUSTOM_RULES_TAGGING_ENABLE;
+	writel(regval, base + SOCE_CUSTOM_RULES_TAGGING_OFFSET);
+}
+
+static void soce_port_select(struct soce_dsa_local *local, int port)
+{
+	writel(FIELD_PREP(SOCE_PORTS_SELECTOR_PORT_MASK, port),
+	       local->base_addr + SOCE_PORTS_SELECTOR_OFFSET);
+}
+
+static void soce_port_set_enabled(struct soce_dsa_local *local, int port,
+				  bool enabled)
+{
+	void __iomem *base = local->base_addr;
+	u32 regval;
+
+	soce_port_select(local, port);
+
+	regval = readl(base + SOCE_PORTS_CTRL_OFFSET);
+	if (enabled)
+		regval |= SOCE_PORTS_CTRL_INGR_EN | SOCE_PORTS_CTRL_EGR_EN;
+	else
+		regval &= ~(SOCE_PORTS_CTRL_INGR_EN | SOCE_PORTS_CTRL_EGR_EN);
+	writel(regval, base + SOCE_PORTS_CTRL_OFFSET);
+}
+
+static int soce_port_enable(struct dsa_switch *ds, int port,
+			    struct phy_device *phy)
+{
+	struct soce_priv *priv = ds->priv;
+
+	soce_port_set_enabled(&priv->local, port, true);
+
+	return 0;
+}
+
+static void soce_port_disable(struct dsa_switch *ds, int port)
+{
+	struct soce_priv *priv = ds->priv;
+
+	soce_port_set_enabled(&priv->local, port, false);
+}
+
+static int soce_setup(struct dsa_switch *ds)
+{
+	struct soce_priv *priv = ds->priv;
+
+	soce_sw_enable_tagging(&priv->local);
+
+	return 0;
+}
+
+static void soce_teardown(struct dsa_switch *ds)
+{
+	struct soce_priv *priv = ds->priv;
+
+	soce_sw_disable_tagging(&priv->local);
+}
+
+static enum dsa_tag_protocol soce_get_tag_protocol(struct dsa_switch *ds,
+						   int port,
+						   enum dsa_tag_protocol mprop)
+{
+	return DSA_TAG_PROTO_SDSA;
+}
+
+static const struct dsa_switch_ops soce_switch_ops = {
+	.get_tag_protocol	= soce_get_tag_protocol,
+	.setup			= soce_setup,
+	.teardown		= soce_teardown,
+	.phylink_get_caps	= soce_phylink_get_caps,
+	.port_enable		= soce_port_enable,
+	.port_disable		= soce_port_disable,
+};
+
+static int soce_sw_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct soce_dsa_local *local;
+	struct soce_priv *priv;
+	struct dsa_switch *ds;
+	u8 hw_subversion;
+	u16 hw_revision;
+	u32 hw_numports;
+	u8 hw_version;
+	int ret;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	ds = &priv->ds;
+	ds->dev = dev;
+	ds->priv = priv;
+
+	local = &priv->local;
+	local->base_addr = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(local->base_addr))
+		return PTR_ERR(local->base_addr);
+
+	soce_sw_read_core_version(local, &hw_version, &hw_subversion,
+				  &hw_revision);
+
+	ret = soce_sw_detect_features(local, &hw_numports);
+	if (ret) {
+		if (ret == -ENODEV)
+			dev_err(dev, "switch core does not implement DSA\n");
+		else
+			dev_err(dev,
+				"invalid licensed or implemented features register\n");
+		return ret;
+	}
+
+	ret = soce_sw_validate_core_version(hw_version, hw_subversion);
+	if (ret) {
+		dev_err(dev, "unsupported switch core version %.2X.%.2X.%.4X\n",
+			hw_version, hw_subversion, hw_revision);
+		return ret;
+	}
+
+	ds->ops = &soce_switch_ops;
+	ds->num_ports = hw_numports;
+	ret = devm_of_platform_populate(dev);
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "failed to populate child devices\n");
+
+	dev_set_drvdata(dev, priv);
+
+	ret = dsa_register_switch(ds);
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "failed to register DSA switch\n");
+
+	dev_info(dev,
+		 "probed soce switch core version %02x.%02x.%04x with %u ports\n",
+		 hw_version, hw_subversion, hw_revision, hw_numports);
+	return 0;
+}
+
+static void soce_sw_remove(struct platform_device *pdev)
+{
+	struct soce_priv *priv = platform_get_drvdata(pdev);
+
+	if (!priv)
+		return;
+
+	dsa_unregister_switch(&priv->ds);
+	platform_set_drvdata(pdev, NULL);
+}
+
+static void soce_sw_shutdown(struct platform_device *pdev)
+{
+	struct soce_priv *priv = platform_get_drvdata(pdev);
+
+	if (!priv)
+		return;
+
+	dsa_switch_shutdown(&priv->ds);
+	platform_set_drvdata(pdev, NULL);
+}
+
+static const struct of_device_id soce_of_match[] = {
+	{ .compatible = "soce,swip-00-04-0c-10" },
+	{ /* sentinel */ }
+};
+
+static struct platform_driver soce_driver = {
+	.probe = soce_sw_probe,
+	.remove = soce_sw_remove,
+	.shutdown = soce_sw_shutdown,
+	.driver = {
+		.name = "soce-swip",
+		.of_match_table = soce_of_match,
+	},
+};
+
+module_platform_driver(soce_driver);
+MODULE_DEVICE_TABLE(of, soce_of_match);
+MODULE_AUTHOR("Vasilij Strassheim <v.strassheim@linutronix.de>");
+MODULE_DESCRIPTION("Driver for SoC-e ethernet switch family");
+MODULE_LICENSE("GPL");
+MODULE_SOFTDEP("pre: mdio-soce mdio-mux-mmioreg");

-- 
2.39.5


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

* [PATCH net-next v3 7/8] net: dsa: soce: Add VLAN offload support
  2026-09-23 10:39 [PATCH net-next v3 0/8] net: dsa: Add SoC-e DSA driver Vasilij Strassheim
                   ` (5 preceding siblings ...)
  2026-09-23 10:39 ` [PATCH net-next v3 6/8] net: dsa: soce: Add basic support for SoC-e switch IP cores Vasilij Strassheim
@ 2026-09-23 10:39 ` Vasilij Strassheim
  2026-09-25 23:32   ` Andrew Lunn
  2026-09-23 10:39 ` [PATCH net-next v3 8/8] net: dsa: soce: Disable unsupported hardware STP Vasilij Strassheim
  7 siblings, 1 reply; 17+ messages in thread
From: Vasilij Strassheim @ 2026-09-23 10:39 UTC (permalink / raw)
  To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Andrew Lunn,
	Vladimir Oltean, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Russell King, Andrew Lunn,
	Heiner Kallweit
  Cc: devicetree, linux-kernel, netdev, Martin Kaistra,
	Benedikt Spranger, Vasilij Strassheim

Add VLAN filtering and membership offload for switch configurations that
implement the Port VLAN synthesis option. Without this feature active,
the switch removes VLAN information on CPU ingress without including the
removed information in the DSA tag. To avoid silent drops and
misbehaviour in this case, reject VLAN operations with a netlink
extended acknowledgment.

If the feature is available, configure ports in Hybrid and C-Port modes
and manage their PVID, ingress filtering and acceptance mode, and custom
egress untagging. Program the per-VID member and untagged port masks
through the hardware selector interface.

The port and VID selectors are shared by all VLAN operations, so
serialize selector and data register sequences with a dedicated mutex.
Track member and untagged masks in software and restore the shadow state
if programming fails.

Signed-off-by: Vasilij Strassheim <v.strassheim@linutronix.de>
---
 drivers/net/dsa/soce/soce_dsa.h      |  11 +
 drivers/net/dsa/soce/soce_dsa_core.c | 388 ++++++++++++++++++++++++++++++++++-
 2 files changed, 392 insertions(+), 7 deletions(-)

diff --git a/drivers/net/dsa/soce/soce_dsa.h b/drivers/net/dsa/soce/soce_dsa.h
index 2acd4dbaf958..41533a89d680 100644
--- a/drivers/net/dsa/soce/soce_dsa.h
+++ b/drivers/net/dsa/soce/soce_dsa.h
@@ -9,6 +9,7 @@
 #define __SOCE_DSA_H
 
 #include <linux/types.h>
+#include <linux/mutex.h>
 
 #include <net/dsa.h>
 
@@ -18,8 +19,18 @@ struct soce_dsa_local {
 	void __iomem *base_addr;
 };
 
+struct soce_features {
+	u32 num_ports;
+	bool port_vlan;
+};
+
 struct soce_priv {
 	struct soce_dsa_local local;
+	struct soce_features features;
+	struct mutex vlan_lock; /* Serializes selector-based VLAN accesses */
+	u32 *vlan_members;
+	u32 *vlan_untagged;
+	u16 port_pvid[SOCE_MAX_NUM_PORTS];
 	struct dsa_switch ds;
 };
 
diff --git a/drivers/net/dsa/soce/soce_dsa_core.c b/drivers/net/dsa/soce/soce_dsa_core.c
index d391b11b94ad..f93ce9da8400 100644
--- a/drivers/net/dsa/soce/soce_dsa_core.c
+++ b/drivers/net/dsa/soce/soce_dsa_core.c
@@ -5,7 +5,10 @@
  * Author: Vasilij Strassheim <v.strassheim@linutronix.de>
  */
 
+#include <linux/if_bridge.h>
+#include <linux/if_vlan.h>
 #include <linux/io.h>
+#include <linux/iopoll.h>
 #include <linux/module.h>
 #include <linux/netdevice.h>
 #include <linux/of.h>
@@ -48,6 +51,39 @@
 #define SOCE_PORTS_CTRL_INGR_EN			BIT(0)
 #define SOCE_PORTS_CTRL_EGR_EN			BIT(1)
 
+#define SOCE_VLAN_REGS_BASE			0x0d00
+#define SOCE_VLAN_CTRL_OFFSET			SOCE_VLAN_REGS_BASE
+#define SOCE_VLAN_CTRL_ENABLE			BIT(0)
+#define SOCE_VLAN_RESET_OFFSET			(SOCE_VLAN_REGS_BASE + 0x0004)
+#define SOCE_VLAN_RESET_CMD			BIT(0)
+#define SOCE_VLAN_PORT_SEL_OFFSET		(SOCE_VLAN_REGS_BASE + 0x0010)
+#define SOCE_VLAN_PORT_SEL_PORT_MASK		GENMASK(7, 0)
+#define SOCE_VLAN_PORT_MODE_OFFSET		(SOCE_VLAN_REGS_BASE + 0x0014)
+#define SOCE_VLAN_PORT_MODE_HYBRID		0x2
+#define SOCE_VLAN_PORT_TYPE_OFFSET		(SOCE_VLAN_REGS_BASE + 0x0018)
+#define SOCE_VLAN_PORT_TYPE_UNAWARE		0x0
+#define SOCE_VLAN_PORT_TYPE_C_PORT		0x1
+#define SOCE_VLAN_PORT_VLAN_OFFSET		(SOCE_VLAN_REGS_BASE + 0x001c)
+#define SOCE_VLAN_PORT_VLAN_PVID_MASK		GENMASK(11, 0)
+#define SOCE_VLAN_PORT_INGR_FILTER_OFFSET	(SOCE_VLAN_REGS_BASE + 0x0020)
+#define SOCE_VLAN_PORT_INGR_FILTER_EN		BIT(0)
+#define SOCE_VLAN_PORT_INGR_ACCEPT_OFFSET	(SOCE_VLAN_REGS_BASE + 0x0024)
+#define SOCE_VLAN_PORT_INGR_ACCEPT_ALL		0x0
+#define SOCE_VLAN_PORT_INGR_ACCEPT_TAGGED_ONLY	0x1
+#define SOCE_VLAN_PORT_EGR_TAG_OFFSET		(SOCE_VLAN_REGS_BASE + 0x0028)
+#define SOCE_VLAN_PORT_EGR_TAG_MASK		GENMASK(1, 0)
+#define SOCE_VLAN_PORT_EGR_TAG_UNTAG_PORT	0x0
+#define SOCE_VLAN_PORT_EGR_TAG_CUSTOM_UNTAG	0x3
+#define SOCE_VLAN_VID_SEL_OFFSET		(SOCE_VLAN_REGS_BASE + 0x002c)
+#define SOCE_VLAN_VID_SEL_VID_MASK		GENMASK(11, 0)
+#define SOCE_VLAN_MEMBER_CTRL_OFFSET		(SOCE_VLAN_REGS_BASE + 0x0030)
+#define SOCE_VLAN_MEMBER_CTRL_WRITE		BIT(0)
+#define SOCE_VLAN_MEMBER_PORTS_OFFSET		(SOCE_VLAN_REGS_BASE + 0x0034)
+#define SOCE_VLAN_UNTAG_CTRL_OFFSET		(SOCE_VLAN_REGS_BASE + 0x003c)
+#define SOCE_VLAN_UNTAG_CTRL_WRITE		BIT(0)
+#define SOCE_VLAN_UNTAG_PORTS_OFFSET		(SOCE_VLAN_REGS_BASE + 0x0040)
+#define SOCE_VLAN_CMD_TIMEOUT_US		1000
+
 static void soce_phylink_get_caps(struct dsa_switch *ds, int port,
 				  struct phylink_config *config)
 {
@@ -107,7 +143,7 @@ static void soce_sw_read_core_version(struct soce_dsa_local *local,
 }
 
 static int soce_sw_detect_features(struct soce_dsa_local *local,
-				   u32 *numports)
+				   struct soce_features *features)
 {
 	void __iomem *base = local->base_addr;
 	u32 implemented_numports;
@@ -123,13 +159,15 @@ static int soce_sw_detect_features(struct soce_dsa_local *local,
 	if (!(regval & SOCE_IMPL_FEATURES0_DSA))
 		return -ENODEV;
 
+	features->port_vlan = regval & SOCE_IMPL_FEATURES0_PORT_VLAN;
+
 	implemented_numports =
 		FIELD_GET(SOCE_IMPL_FEATURES0_NUM_PORTS_MASK, regval);
 	if (implemented_numports < SOCE_MIN_NUM_PORTS ||
 	    implemented_numports > licensed_numports)
 		return -EINVAL;
 
-	*numports = implemented_numports;
+	features->num_ports = implemented_numports;
 
 	return 0;
 }
@@ -162,6 +200,178 @@ static void soce_sw_disable_tagging(struct soce_dsa_local *local)
 	writel(regval, base + SOCE_CUSTOM_RULES_TAGGING_OFFSET);
 }
 
+static void soce_vlan_set_enabled(struct soce_dsa_local *local, bool enabled)
+{
+	void __iomem *base = local->base_addr;
+	u32 regval;
+
+	regval = readl(base + SOCE_VLAN_CTRL_OFFSET);
+	if (enabled)
+		regval |= SOCE_VLAN_CTRL_ENABLE;
+	else
+		regval &= ~SOCE_VLAN_CTRL_ENABLE;
+	writel(regval, base + SOCE_VLAN_CTRL_OFFSET);
+}
+
+static int soce_vlan_reset(struct soce_dsa_local *local)
+{
+	void __iomem *base = local->base_addr;
+	u32 regval;
+
+	writel(SOCE_VLAN_RESET_CMD, base + SOCE_VLAN_RESET_OFFSET);
+
+	return readl_poll_timeout(base + SOCE_VLAN_RESET_OFFSET,
+				  regval, !(regval & SOCE_VLAN_RESET_CMD), 10,
+				  SOCE_VLAN_CMD_TIMEOUT_US);
+}
+
+static int soce_vlan_wait_for_write(struct soce_dsa_local *local, u32 offset,
+				    u32 mask)
+{
+	void __iomem *base = local->base_addr;
+	u32 regval;
+
+	return readl_poll_timeout(base + offset, regval,
+				  !(regval & mask), 10,
+				  SOCE_VLAN_CMD_TIMEOUT_US);
+}
+
+static void soce_vlan_select_port(struct soce_dsa_local *local, int port)
+{
+	writel(FIELD_PREP(SOCE_VLAN_PORT_SEL_PORT_MASK, port),
+	       local->base_addr + SOCE_VLAN_PORT_SEL_OFFSET);
+}
+
+static void soce_vlan_select_vid(struct soce_dsa_local *local, u16 vid)
+{
+	writel(FIELD_PREP(SOCE_VLAN_VID_SEL_VID_MASK, vid),
+	       local->base_addr + SOCE_VLAN_VID_SEL_OFFSET);
+}
+
+static void soce_vlan_config_port(struct soce_priv *priv, int port,
+				  bool vlan_filtering)
+{
+	struct soce_dsa_local *local = &priv->local;
+	void __iomem *base = local->base_addr;
+	u32 egress_tagging;
+	u32 port_type;
+	u32 regval;
+	u32 accept;
+
+	port_type = vlan_filtering ? SOCE_VLAN_PORT_TYPE_C_PORT :
+				     SOCE_VLAN_PORT_TYPE_UNAWARE;
+	egress_tagging = vlan_filtering ? SOCE_VLAN_PORT_EGR_TAG_CUSTOM_UNTAG :
+					   SOCE_VLAN_PORT_EGR_TAG_UNTAG_PORT;
+
+	soce_vlan_select_port(local, port);
+	writel(SOCE_VLAN_PORT_MODE_HYBRID, base + SOCE_VLAN_PORT_MODE_OFFSET);
+	writel(port_type, base + SOCE_VLAN_PORT_TYPE_OFFSET);
+	writel(FIELD_PREP(SOCE_VLAN_PORT_VLAN_PVID_MASK,
+			  priv->port_pvid[port]),
+	       base + SOCE_VLAN_PORT_VLAN_OFFSET);
+	writel(vlan_filtering ? SOCE_VLAN_PORT_INGR_FILTER_EN : 0,
+	       base + SOCE_VLAN_PORT_INGR_FILTER_OFFSET);
+
+	/* Without a PVID, untagged frames have no VLAN to be classified
+	 * into, so only accept tagged frames while filtering.
+	 */
+	accept = vlan_filtering && !priv->port_pvid[port] ?
+			 SOCE_VLAN_PORT_INGR_ACCEPT_TAGGED_ONLY :
+			 SOCE_VLAN_PORT_INGR_ACCEPT_ALL;
+	writel(accept, base + SOCE_VLAN_PORT_INGR_ACCEPT_OFFSET);
+
+	regval = readl(base + SOCE_VLAN_PORT_EGR_TAG_OFFSET);
+	regval &= ~SOCE_VLAN_PORT_EGR_TAG_MASK;
+	regval |= FIELD_PREP(SOCE_VLAN_PORT_EGR_TAG_MASK, egress_tagging);
+	writel(regval, base + SOCE_VLAN_PORT_EGR_TAG_OFFSET);
+}
+
+static int soce_vlan_write_entry(struct soce_priv *priv, u16 vid)
+{
+	struct soce_dsa_local *local = &priv->local;
+	void __iomem *base = local->base_addr;
+	u32 cpu_ports;
+	u32 untagged;
+	u32 members;
+	int ret;
+
+	/* The CPU port must be a tagged member of every active VLAN so
+	 * tagged frames can reach the conduit.
+	 */
+	cpu_ports = dsa_cpu_ports(&priv->ds);
+	members = priv->vlan_members[vid];
+	if (members)
+		members |= cpu_ports;
+	untagged = priv->vlan_untagged[vid] & ~cpu_ports;
+
+	soce_vlan_select_vid(local, vid);
+	writel(members, base + SOCE_VLAN_MEMBER_PORTS_OFFSET);
+	writel(SOCE_VLAN_MEMBER_CTRL_WRITE,
+	       base + SOCE_VLAN_MEMBER_CTRL_OFFSET);
+	ret = soce_vlan_wait_for_write(local, SOCE_VLAN_MEMBER_CTRL_OFFSET,
+				       SOCE_VLAN_MEMBER_CTRL_WRITE);
+	if (ret)
+		return ret;
+
+	writel(untagged, base + SOCE_VLAN_UNTAG_PORTS_OFFSET);
+	writel(SOCE_VLAN_UNTAG_CTRL_WRITE,
+	       base + SOCE_VLAN_UNTAG_CTRL_OFFSET);
+
+	return soce_vlan_wait_for_write(local, SOCE_VLAN_UNTAG_CTRL_OFFSET,
+					SOCE_VLAN_UNTAG_CTRL_WRITE);
+}
+
+static int soce_vlan_setup(struct dsa_switch *ds)
+{
+	struct soce_priv *priv = ds->priv;
+	struct soce_dsa_local *local;
+	struct dsa_port *dp;
+	int ret;
+
+	local = &priv->local;
+
+	if (!priv->features.port_vlan)
+		return 0;
+
+	ret = soce_vlan_reset(local);
+	if (ret) {
+		dev_err(ds->dev, "failed to reset VLAN configuration: %d\n",
+			ret);
+		return ret;
+	}
+
+	/* Default every port to PVID 1, unfiltered, so standalone
+	 * forwarding keeps working before any bridge VLAN is configured.
+	 */
+	scoped_guard(mutex, &priv->vlan_lock) {
+		dsa_switch_for_each_available_port(dp, ds) {
+			priv->port_pvid[dp->index] = 1;
+			soce_vlan_config_port(priv, dp->index, false);
+		}
+		soce_vlan_set_enabled(local, true);
+	}
+
+	return 0;
+}
+
+static void soce_vlan_teardown(struct soce_priv *priv)
+{
+	struct soce_dsa_local *local = &priv->local;
+	int ret;
+
+	if (!priv->features.port_vlan)
+		return;
+
+	scoped_guard(mutex, &priv->vlan_lock) {
+		ret = soce_vlan_reset(local);
+		if (ret)
+			dev_warn(priv->ds.dev,
+				 "failed to reset VLAN configuration during teardown: %d\n",
+				 ret);
+		soce_vlan_set_enabled(local, false);
+	}
+}
+
 static void soce_port_select(struct soce_dsa_local *local, int port)
 {
 	writel(FIELD_PREP(SOCE_PORTS_SELECTOR_PORT_MASK, port),
@@ -204,6 +414,11 @@ static void soce_port_disable(struct dsa_switch *ds, int port)
 static int soce_setup(struct dsa_switch *ds)
 {
 	struct soce_priv *priv = ds->priv;
+	int ret;
+
+	ret = soce_vlan_setup(ds);
+	if (ret)
+		return ret;
 
 	soce_sw_enable_tagging(&priv->local);
 
@@ -213,8 +428,12 @@ static int soce_setup(struct dsa_switch *ds)
 static void soce_teardown(struct dsa_switch *ds)
 {
 	struct soce_priv *priv = ds->priv;
+	struct soce_dsa_local *local;
+
+	local = &priv->local;
 
-	soce_sw_disable_tagging(&priv->local);
+	soce_sw_disable_tagging(local);
+	soce_vlan_teardown(priv);
 }
 
 static enum dsa_tag_protocol soce_get_tag_protocol(struct dsa_switch *ds,
@@ -224,6 +443,130 @@ static enum dsa_tag_protocol soce_get_tag_protocol(struct dsa_switch *ds,
 	return DSA_TAG_PROTO_SDSA;
 }
 
+static int soce_port_vlan_add(struct dsa_switch *ds, int port,
+			      const struct switchdev_obj_port_vlan *vlan,
+			      struct netlink_ext_ack *extack)
+{
+	struct dsa_port *dp = dsa_to_port(ds, port);
+	struct soce_priv *priv = ds->priv;
+	u32 port_mask = BIT(port);
+	u32 *untagged_ports;
+	u32 old_untagged;
+	u32 old_members;
+	bool untagged;
+	u32 *members;
+	int ret;
+
+	untagged_ports = priv->vlan_untagged;
+	members = priv->vlan_members;
+
+	if (!priv->features.port_vlan) {
+		NL_SET_ERR_MSG_MOD(extack,
+				   "Port VLAN support is not implemented in the switch core");
+		return -EOPNOTSUPP;
+	}
+
+	if (!vlan->vid)
+		return 0;
+
+	untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
+
+	scoped_guard(mutex, &priv->vlan_lock) {
+		old_members = members[vlan->vid];
+		old_untagged = untagged_ports[vlan->vid];
+
+		members[vlan->vid] |= port_mask;
+		if (untagged)
+			untagged_ports[vlan->vid] |= port_mask;
+		else
+			untagged_ports[vlan->vid] &= ~port_mask;
+
+		ret = soce_vlan_write_entry(priv, vlan->vid);
+		if (ret) {
+			NL_SET_ERR_MSG_MOD(extack,
+					   "failed to update VLAN hardware tables");
+			dev_err(ds->dev,
+				"failed to add VLAN %u on port %d: %d\n",
+				vlan->vid, port, ret);
+			members[vlan->vid] = old_members;
+			untagged_ports[vlan->vid] = old_untagged;
+			return ret;
+		}
+
+		if (vlan->flags & BRIDGE_VLAN_INFO_PVID) {
+			priv->port_pvid[port] = vlan->vid;
+			soce_vlan_config_port(priv, port,
+					      dsa_port_is_vlan_filtering(dp));
+		}
+	}
+
+	return ret;
+}
+
+static int soce_port_vlan_del(struct dsa_switch *ds, int port,
+			      const struct switchdev_obj_port_vlan *vlan)
+{
+	struct dsa_port *dp = dsa_to_port(ds, port);
+	struct soce_priv *priv = ds->priv;
+	u32 port_mask = BIT(port);
+	u32 *untagged_ports;
+	u32 old_untagged;
+	u32 old_members;
+	u32 *members;
+	int ret;
+
+	untagged_ports = priv->vlan_untagged;
+	members = priv->vlan_members;
+
+	if (!priv->features.port_vlan)
+		return -EOPNOTSUPP;
+
+	if (!vlan->vid)
+		return 0;
+
+	scoped_guard(mutex, &priv->vlan_lock) {
+		old_members = members[vlan->vid];
+		old_untagged = untagged_ports[vlan->vid];
+		members[vlan->vid] &= ~port_mask;
+		untagged_ports[vlan->vid] &= ~port_mask;
+		ret = soce_vlan_write_entry(priv, vlan->vid);
+		if (ret) {
+			dev_err(ds->dev,
+				"failed to delete VLAN %u from port %d: %d\n",
+				vlan->vid, port, ret);
+			members[vlan->vid] = old_members;
+			untagged_ports[vlan->vid] = old_untagged;
+			return ret;
+		}
+
+		if (priv->port_pvid[port] == vlan->vid) {
+			priv->port_pvid[port] = 0;
+			soce_vlan_config_port(priv, port,
+					      dsa_port_is_vlan_filtering(dp));
+		}
+	}
+
+	return ret;
+}
+
+static int soce_port_vlan_filtering(struct dsa_switch *ds, int port,
+				    bool vlan_filtering,
+				    struct netlink_ext_ack *extack)
+{
+	struct soce_priv *priv = ds->priv;
+
+	if (!priv->features.port_vlan) {
+		NL_SET_ERR_MSG_MOD(extack,
+				   "Port VLAN support is not implemented in the switch core");
+		return -EOPNOTSUPP;
+	}
+
+	scoped_guard(mutex, &priv->vlan_lock)
+		soce_vlan_config_port(priv, port, vlan_filtering);
+
+	return 0;
+}
+
 static const struct dsa_switch_ops soce_switch_ops = {
 	.get_tag_protocol	= soce_get_tag_protocol,
 	.setup			= soce_setup,
@@ -231,6 +574,9 @@ static const struct dsa_switch_ops soce_switch_ops = {
 	.phylink_get_caps	= soce_phylink_get_caps,
 	.port_enable		= soce_port_enable,
 	.port_disable		= soce_port_disable,
+	.port_vlan_filtering	= soce_port_vlan_filtering,
+	.port_vlan_add		= soce_port_vlan_add,
+	.port_vlan_del		= soce_port_vlan_del,
 };
 
 static int soce_sw_probe(struct platform_device *pdev)
@@ -241,7 +587,6 @@ static int soce_sw_probe(struct platform_device *pdev)
 	struct dsa_switch *ds;
 	u8 hw_subversion;
 	u16 hw_revision;
-	u32 hw_numports;
 	u8 hw_version;
 	int ret;
 
@@ -261,7 +606,7 @@ static int soce_sw_probe(struct platform_device *pdev)
 	soce_sw_read_core_version(local, &hw_version, &hw_subversion,
 				  &hw_revision);
 
-	ret = soce_sw_detect_features(local, &hw_numports);
+	ret = soce_sw_detect_features(local, &priv->features);
 	if (ret) {
 		if (ret == -ENODEV)
 			dev_err(dev, "switch core does not implement DSA\n");
@@ -278,8 +623,35 @@ static int soce_sw_probe(struct platform_device *pdev)
 		return ret;
 	}
 
+	if (priv->features.port_vlan) {
+		ret = devm_mutex_init(dev, &priv->vlan_lock);
+		if (ret)
+			return ret;
+
+		priv->vlan_members =
+			devm_kcalloc(dev, VLAN_N_VID,
+				     sizeof(*priv->vlan_members), GFP_KERNEL);
+		if (!priv->vlan_members)
+			return -ENOMEM;
+
+		priv->vlan_untagged =
+			devm_kcalloc(dev, VLAN_N_VID,
+				     sizeof(*priv->vlan_untagged), GFP_KERNEL);
+		if (!priv->vlan_untagged)
+			return -ENOMEM;
+	} else {
+		dev_warn(dev,
+			 "VLAN-tagged frames received on the CPU port are unsupported\n");
+	}
+
 	ds->ops = &soce_switch_ops;
-	ds->num_ports = hw_numports;
+	ds->num_ports = priv->features.num_ports;
+
+	/* Force VLAN uppers always through the callbacks, so cores without
+	 * Port VLAN feature can reject them instead of silently dropping
+	 * VLAN frames.
+	 */
+	ds->needs_standalone_vlan_filtering = true;
 	ret = devm_of_platform_populate(dev);
 	if (ret)
 		return dev_err_probe(dev, ret,
@@ -294,7 +666,9 @@ static int soce_sw_probe(struct platform_device *pdev)
 
 	dev_info(dev,
 		 "probed soce switch core version %02x.%02x.%04x with %u ports\n",
-		 hw_version, hw_subversion, hw_revision, hw_numports);
+		 hw_version, hw_subversion, hw_revision,
+		 priv->features.num_ports);
+
 	return 0;
 }
 

-- 
2.39.5


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

* [PATCH net-next v3 8/8] net: dsa: soce: Disable unsupported hardware STP
  2026-09-23 10:39 [PATCH net-next v3 0/8] net: dsa: Add SoC-e DSA driver Vasilij Strassheim
                   ` (6 preceding siblings ...)
  2026-09-23 10:39 ` [PATCH net-next v3 7/8] net: dsa: soce: Add VLAN offload support Vasilij Strassheim
@ 2026-09-23 10:39 ` Vasilij Strassheim
  2026-09-25 23:24   ` Andrew Lunn
  7 siblings, 1 reply; 17+ messages in thread
From: Vasilij Strassheim @ 2026-09-23 10:39 UTC (permalink / raw)
  To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Andrew Lunn,
	Vladimir Oltean, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Russell King, Andrew Lunn,
	Heiner Kallweit
  Cc: devicetree, linux-kernel, netdev, Martin Kaistra,
	Benedikt Spranger, Vasilij Strassheim

The driver does not implement hardware STP offloading yet. Switch cores
synthesized with the STP feature enabled may therefore retain their
reset configuration and block frame forwarding.

Detect the synthesized STP feature and disable it during switch setup,
leaving STP state handling to the Linux bridge.

Signed-off-by: Vasilij Strassheim <v.strassheim@linutronix.de>
---
 drivers/net/dsa/soce/soce_dsa.h      |  1 +
 drivers/net/dsa/soce/soce_dsa_core.c | 20 ++++++++++++++++++++
 2 files changed, 21 insertions(+)

diff --git a/drivers/net/dsa/soce/soce_dsa.h b/drivers/net/dsa/soce/soce_dsa.h
index 41533a89d680..bb9e65567ec6 100644
--- a/drivers/net/dsa/soce/soce_dsa.h
+++ b/drivers/net/dsa/soce/soce_dsa.h
@@ -22,6 +22,7 @@ struct soce_dsa_local {
 struct soce_features {
 	u32 num_ports;
 	bool port_vlan;
+	bool stp;
 };
 
 struct soce_priv {
diff --git a/drivers/net/dsa/soce/soce_dsa_core.c b/drivers/net/dsa/soce/soce_dsa_core.c
index f93ce9da8400..3b9fde7a547e 100644
--- a/drivers/net/dsa/soce/soce_dsa_core.c
+++ b/drivers/net/dsa/soce/soce_dsa_core.c
@@ -36,6 +36,7 @@
 #define SOCE_IMPL_FEATURES0_OFFSET		0x000c
 #define SOCE_IMPL_FEATURES0_NUM_PORTS_MASK	GENMASK(31, 27)
 #define SOCE_IMPL_FEATURES0_PORT_VLAN		BIT(9)
+#define SOCE_IMPL_FEATURES0_STP			BIT(20)
 #define SOCE_IMPL_FEATURES0_DSA			BIT(23)
 
 #define SOCE_DSA_REGS_BASE			0x1200
@@ -51,6 +52,10 @@
 #define SOCE_PORTS_CTRL_INGR_EN			BIT(0)
 #define SOCE_PORTS_CTRL_EGR_EN			BIT(1)
 
+#define SOCE_STP_REGS_BASE			0x0f00
+#define SOCE_STP_CTRL_OFFSET			SOCE_STP_REGS_BASE
+#define SOCE_STP_CTRL_ENABLE			BIT(0)
+
 #define SOCE_VLAN_REGS_BASE			0x0d00
 #define SOCE_VLAN_CTRL_OFFSET			SOCE_VLAN_REGS_BASE
 #define SOCE_VLAN_CTRL_ENABLE			BIT(0)
@@ -160,6 +165,7 @@ static int soce_sw_detect_features(struct soce_dsa_local *local,
 		return -ENODEV;
 
 	features->port_vlan = regval & SOCE_IMPL_FEATURES0_PORT_VLAN;
+	features->stp = regval & SOCE_IMPL_FEATURES0_STP;
 
 	implemented_numports =
 		FIELD_GET(SOCE_IMPL_FEATURES0_NUM_PORTS_MASK, regval);
@@ -200,6 +206,16 @@ static void soce_sw_disable_tagging(struct soce_dsa_local *local)
 	writel(regval, base + SOCE_CUSTOM_RULES_TAGGING_OFFSET);
 }
 
+static void soce_stp_disable(struct soce_dsa_local *local)
+{
+	void __iomem *base = local->base_addr;
+	u32 regval;
+
+	regval = readl(base + SOCE_STP_CTRL_OFFSET);
+	regval &= ~SOCE_STP_CTRL_ENABLE;
+	writel(regval, base + SOCE_STP_CTRL_OFFSET);
+}
+
 static void soce_vlan_set_enabled(struct soce_dsa_local *local, bool enabled)
 {
 	void __iomem *base = local->base_addr;
@@ -420,6 +436,10 @@ static int soce_setup(struct dsa_switch *ds)
 	if (ret)
 		return ret;
 
+	/* Unconfigured hardware STP blocks frame forwarding. */
+	if (priv->features.stp)
+		soce_stp_disable(&priv->local);
+
 	soce_sw_enable_tagging(&priv->local);
 
 	return 0;

-- 
2.39.5


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

* Re: [PATCH net-next v3 4/8] net: dsa: Add tag handling for SoC-e switches
       [not found]   ` <20260924104003.A49F31F000FF@smtp.kernel.org>
@ 2026-09-25 12:46     ` Vasilij Strassheim
  0 siblings, 0 replies; 17+ messages in thread
From: Vasilij Strassheim @ 2026-09-25 12:46 UTC (permalink / raw)
  To: sashiko-reviews
  Cc: robh, conor+dt, devicetree, Krzysztof Kozlowski, Andrew Lunn,
	Vladimir Oltean, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Russell King, Andrew Lunn,
	Heiner Kallweit, linux-kernel, netdev, Martin Kaistra,
	Benedikt Spranger

On Thu, 2026-09-24 at 10:40 +0000, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
> - [High] net: dsa: tag_sdsa: unsupported VLAN tags left in hwaccel metadata
> --
> 
> commit c9312ab6752036eeab3076e94713c79223982016
> Author: Vasilij Strassheim <v.strassheim@linutronix.de>
> 
> net: dsa: Add tag handling for SoC-e switches
> 
> This commit adds a DSA tag driver for SoC-e switches, which use an 8-byte
> SDSA header carrying frame direction, port, and VLAN metadata. The header
> is inserted between the source MAC address and the original EtherType on
> transmit and receive.
> 
> > diff --git a/net/dsa/tag_sdsa.c b/net/dsa/tag_sdsa.c
> > new file mode 100644
> > index 0000000000000..8cc3fa357be42
> > --- /dev/null
> > +++ b/net/dsa/tag_sdsa.c
> 
> [ ... ]
> 
> > +static struct sk_buff *sdsa_xmit(struct sk_buff *skb, struct net_device *dev)
> > +{
> > +	struct dsa_port *dp = dsa_user_to_port(dev);
> > +	struct sdsa_tag *tag;
> > +	u16 vlan_tci;
> 
> [ ... ]
> 
> > +	/* SDSA carries no TPID, so only encode 802.1Q C-tags. */
> > +	if (skb_vlan_tag_present(skb) &&
> > +	    skb->vlan_proto == htons(ETH_P_8021Q)) {
> > +		vlan_tci = skb_vlan_tag_get(skb);
> > +		__vlan_hwaccel_clear_tag(skb);
> > +		tag->frame_type_port_hi |= SDSA_TAG_VLAN_BIT;
> > +		tag->vlan = cpu_to_be16(vlan_tci);
> > +	} else {
> > +		tag->vlan = 0;
> > +	}
> 
> [Severity: High]
> Does this else branch leave unsupported VLAN tags (like 802.1ad) in the 
> skb's hardware accelerated metadata?
> 
> If a user configures an unsupported VLAN protocol on a DSA user port, the 
> skb will still have skb_vlan_tag_present(skb) set when reaching sdsa_xmit().
> Because this branch does not clear the tag via __vlan_hwaccel_clear_tag(skb),
> the conduit driver's MAC hardware might subsequently insert the remaining 
> VLAN tag at the MAC boundary.
> 
> Could this insertion displace the 8-byte SDSA header just pushed, causing 
> the switch hardware to receive unrecognized frames and drop them?
> 

That's right, I missed it. I will fix it in a similar way to tag_ks8995.

> > +
> > +	return skb;
> > +}
> 


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

* Re: [PATCH net-next v3 2/8] dt-bindings: net: Add SoC-e SWIP MDIO controller
  2026-09-23 10:39 ` [PATCH net-next v3 2/8] dt-bindings: net: Add SoC-e SWIP MDIO controller Vasilij Strassheim
@ 2026-09-25 22:55   ` Andrew Lunn
  0 siblings, 0 replies; 17+ messages in thread
From: Andrew Lunn @ 2026-09-25 22:55 UTC (permalink / raw)
  To: Vasilij Strassheim
  Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Vladimir Oltean,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Russell King, Andrew Lunn, Heiner Kallweit,
	devicetree, linux-kernel, netdev, Martin Kaistra,
	Benedikt Spranger

> The controller exposes separate register regions for transaction data
> and for the shared transaction control and external bus selector
> register.

> +examples:
> +  - |
> +    mdio@204 {
> +        compatible = "soce,swip-mdio-23-02";
> +        reg = <0x204 0xc>, <0x200 0x4>;

At least in the example, they are not separate?

   Andrew

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

* Re: [PATCH net-next v3 3/8] dt-bindings: net: dsa: Add SoC-e SWIP switch
  2026-09-23 10:39 ` [PATCH net-next v3 3/8] dt-bindings: net: dsa: Add SoC-e SWIP switch Vasilij Strassheim
@ 2026-09-25 23:05   ` Andrew Lunn
  0 siblings, 0 replies; 17+ messages in thread
From: Andrew Lunn @ 2026-09-25 23:05 UTC (permalink / raw)
  To: Vasilij Strassheim
  Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Vladimir Oltean,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Russell King, Andrew Lunn, Heiner Kallweit,
	devicetree, linux-kernel, netdev, Martin Kaistra,
	Benedikt Spranger

> +  mdio@204:
> +    $ref: /schemas/net/soce,swip-mdio.yaml#
> +    unevaluatedProperties: false
> +    description:
> +      Integrated MDIO controller bus on the master side of the mux.
> +
> +  mdio-mux@202:
> +    $ref: /schemas/net/mdio-mux-mmioreg.yaml#
> +    unevaluatedProperties: false

> +        mdio_parent: mdio@204 {
> +            compatible = "soce,swip-mdio-23-02";
> +            reg = <0x204 0xc>, <0x200 0x4>;
> +            reg-names = "data", "control";
> +            #address-cells = <1>;
> +            #size-cells = <0>;
> +        };
> +
> +        mdio-mux@202 {
> +            compatible = "mdio-mux-mmioreg", "mdio-mux";
> +            reg = <0x202 0x2>;

So these two overlap? That is pretty unusual, so might be worth a comment somewhere.

	Andrew

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

* Re: [PATCH net-next v3 5/8] net: mdio: Add SoC-e SWIP MDIO controller driver
  2026-09-23 10:39 ` [PATCH net-next v3 5/8] net: mdio: Add SoC-e SWIP MDIO controller driver Vasilij Strassheim
@ 2026-09-25 23:10   ` Andrew Lunn
  0 siblings, 0 replies; 17+ messages in thread
From: Andrew Lunn @ 2026-09-25 23:10 UTC (permalink / raw)
  To: Vasilij Strassheim
  Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Vladimir Oltean,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Russell King, Andrew Lunn, Heiner Kallweit,
	devicetree, linux-kernel, netdev, Martin Kaistra,
	Benedikt Spranger

> diff --git a/drivers/net/mdio/Makefile b/drivers/net/mdio/Makefile
> index 048586746026..079b46dea25f 100644
> --- a/drivers/net/mdio/Makefile
> +++ b/drivers/net/mdio/Makefile
> @@ -23,6 +23,7 @@ obj-$(CONFIG_MDIO_OCTEON)		+= mdio-octeon.o
>  obj-$(CONFIG_MDIO_PIC64HPSC)		+= mdio-pic64hpsc.o
>  obj-$(CONFIG_MDIO_REALTEK_RTL9300)	+= mdio-realtek-rtl9300.o
>  obj-$(CONFIG_MDIO_REGMAP)		+= mdio-regmap.o
> +obj-$(CONFIG_MDIO_SOCE)			+= mdio-soce.o
>  obj-$(CONFIG_MDIO_SUN4I)		+= mdio-sun4i.o

Maybe the indentation is wrong here?

Otherwise:

Reviewed-by: Andrew Lunn <andrew@lunn.ch>

    Andrew

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

* Re: [PATCH net-next v3 6/8] net: dsa: soce: Add basic support for SoC-e switch IP cores
  2026-09-23 10:39 ` [PATCH net-next v3 6/8] net: dsa: soce: Add basic support for SoC-e switch IP cores Vasilij Strassheim
@ 2026-09-25 23:17   ` Andrew Lunn
  2026-09-25 23:20   ` Andrew Lunn
  1 sibling, 0 replies; 17+ messages in thread
From: Andrew Lunn @ 2026-09-25 23:17 UTC (permalink / raw)
  To: Vasilij Strassheim
  Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Vladimir Oltean,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Russell King, Andrew Lunn, Heiner Kallweit,
	devicetree, linux-kernel, netdev, Martin Kaistra,
	Benedikt Spranger

> +static void soce_sw_read_core_version(struct soce_dsa_local *local,
> +				      u8 *version, u8 *subversion,
> +				      u16 *revision)
> +{
> +	u32 regval;
> +
> +	regval = readl(local->base_addr + SOCE_CORE_VERSION_OFFSET);
> +	*version = (u8)(regval >> SOCE_CORE_VERSION_VERSION_SHIFT);
> +	*subversion = (u8)(regval >> SOCE_CORE_VERSION_SUBVERSION_SHIFT);
> +	*revision = (u16)regval;

FIELD_GET() would make this more readable. 

> +static int soce_sw_detect_features(struct soce_dsa_local *local,
> +				   u32 *numports)
> +{
> +	void __iomem *base = local->base_addr;
> +	u32 implemented_numports;
> +	u32 licensed_numports;
> +	u32 regval;
> +
> +	regval = readl(base + SOCE_LIC_FEATURES_OFFSET);
> +	licensed_numports = FIELD_GET(SOCE_LIC_FEATURES_NUM_PORTS_MASK, regval);
> +	if (!licensed_numports || licensed_numports > SOCE_MAX_NUM_PORTS)
> +		return -EINVAL;
> +
> +	regval = readl(base + SOCE_IMPL_FEATURES0_OFFSET);
> +	if (!(regval & SOCE_IMPL_FEATURES0_DSA))
> +		return -ENODEV;
> +
> +	implemented_numports =
> +		FIELD_GET(SOCE_IMPL_FEATURES0_NUM_PORTS_MASK, regval);
> +	if (implemented_numports < SOCE_MIN_NUM_PORTS ||
> +	    implemented_numports > licensed_numports)
> +		return -EINVAL;

Maybe add dev_err() here for all these error cases. It will help
somebody debug why there switch fails to probe.

	 Andrew

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

* Re: [PATCH net-next v3 6/8] net: dsa: soce: Add basic support for SoC-e switch IP cores
  2026-09-23 10:39 ` [PATCH net-next v3 6/8] net: dsa: soce: Add basic support for SoC-e switch IP cores Vasilij Strassheim
  2026-09-25 23:17   ` Andrew Lunn
@ 2026-09-25 23:20   ` Andrew Lunn
  1 sibling, 0 replies; 17+ messages in thread
From: Andrew Lunn @ 2026-09-25 23:20 UTC (permalink / raw)
  To: Vasilij Strassheim
  Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Vladimir Oltean,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Russell King, Andrew Lunn, Heiner Kallweit,
	devicetree, linux-kernel, netdev, Martin Kaistra,
	Benedikt Spranger

On Wed, Sep 23, 2026 at 12:39:33PM +0200, Vasilij Strassheim wrote:
> Add a DSA driver for SoC-e FPGA-based Ethernet switch IP cores.
> 
> Read the core version and synthesis-time feature registers during probe.
> Require DSA support and between 3 and 31 implemented ports, without
> exceeding the licensed port count. Derive each port's phylink
> capabilities from its phy-mode.
> 
> Enable "DSA custom rules" tagging for all frames during setup. This
> directs ingress traffic from user ports to the CPU port while standalone
> ports remain isolated. Enable and disable port ingress and egress
> through the DSA port callbacks, and disable tagging again during
> teardown so that unbinding the driver does not leave its managed
> configuration active.
> 
> Populate the integrated MDIO controller and mux child devices used for
> external PHY access.
> 
> Tested with a SoC-e MRS 25.01 IP core on a Xilinx ZynqMP platform.
> 
> Signed-off-by: Vasilij Strassheim <v.strassheim@linutronix.de>
> ---
>  drivers/net/dsa/Kconfig              |   2 +
>  drivers/net/dsa/Makefile             |   1 +
>  drivers/net/dsa/soce/Kconfig         |  14 ++
>  drivers/net/dsa/soce/Makefile        |   4 +
>  drivers/net/dsa/soce/soce_dsa.h      |  26 +++
>  drivers/net/dsa/soce/soce_dsa_core.c | 343 +++++++++++++++++++++++++++++++++++
>  6 files changed, 390 insertions(+)
> 
> diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig
> index fe8cd5338fda..879fbede83f0 100644
> --- a/drivers/net/dsa/Kconfig
> +++ b/drivers/net/dsa/Kconfig
> @@ -94,6 +94,8 @@ source "drivers/net/dsa/ocelot/Kconfig"
>  
>  source "drivers/net/dsa/qca/Kconfig"
>  
> +source "drivers/net/dsa/soce/Kconfig"
> +
>  source "drivers/net/dsa/sja1105/Kconfig"
>  
>  source "drivers/net/dsa/xrs700x/Kconfig"
> diff --git a/drivers/net/dsa/Makefile b/drivers/net/dsa/Makefile
> index 7e637d56b35c..97de3d181440 100644
> --- a/drivers/net/dsa/Makefile
> +++ b/drivers/net/dsa/Makefile
> @@ -26,4 +26,5 @@ obj-y				+= ocelot/
>  obj-y				+= qca/
>  obj-y				+= realtek/
>  obj-y				+= sja1105/
> +obj-y				+= soce/
>  obj-y				+= xrs700x/
> diff --git a/drivers/net/dsa/soce/Kconfig b/drivers/net/dsa/soce/Kconfig
> new file mode 100644
> index 000000000000..c31b7c5af695
> --- /dev/null
> +++ b/drivers/net/dsa/soce/Kconfig
> @@ -0,0 +1,14 @@
> +# SPDX-License-Identifier: GPL-2.0
> +config NET_DSA_SOCE
> +	tristate "SoC-e switches"
> +	depends on NET_DSA
> +	depends on OF
> +	depends on HAS_IOMEM
> +	select MDIO_BUS_MUX_MMIOREG
> +	select MDIO_SOCE
> +	select NET_DSA_TAG_SDSA
> +	help
> +	  This enables support for switches based on SoC-e IP cores.
> +	  Frames are exchanged with the CPU port using the SDSA DSA tag protocol.
> +	  The driver supports switch variants whose features and number of ports
> +	  are selected at synthesis time and detected at runtime.
> diff --git a/drivers/net/dsa/soce/Makefile b/drivers/net/dsa/soce/Makefile
> new file mode 100644
> index 000000000000..2a6d95ef663f
> --- /dev/null
> +++ b/drivers/net/dsa/soce/Makefile
> @@ -0,0 +1,4 @@
> +# SPDX-License-Identifier: GPL-2.0
> +
> +obj-$(CONFIG_NET_DSA_SOCE) += soce_dsa.o
> +soce_dsa-objs := soce_dsa_core.o
> diff --git a/drivers/net/dsa/soce/soce_dsa.h b/drivers/net/dsa/soce/soce_dsa.h
> new file mode 100644
> index 000000000000..2acd4dbaf958
> --- /dev/null
> +++ b/drivers/net/dsa/soce/soce_dsa.h
> @@ -0,0 +1,26 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (c) 2020-2026 System on Chip engineering, S.L.
> + * Copyright (c) 2026 Linutronix GmbH
> + * Author: Vasilij Strassheim <v.strassheim@linutronix.de>
> + */
> +
> +#ifndef __SOCE_DSA_H
> +#define __SOCE_DSA_H
> +
> +#include <linux/types.h>
> +
> +#include <net/dsa.h>
> +
> +#define SOCE_MAX_NUM_PORTS 31
> +
> +struct soce_dsa_local {
> +	void __iomem *base_addr;
> +};
> +
> +struct soce_priv {
> +	struct soce_dsa_local local;
> +	struct dsa_switch ds;
> +};
> +
> +#endif /* __SOCE_DSA_H */
> diff --git a/drivers/net/dsa/soce/soce_dsa_core.c b/drivers/net/dsa/soce/soce_dsa_core.c
> new file mode 100644
> index 000000000000..d391b11b94ad
> --- /dev/null
> +++ b/drivers/net/dsa/soce/soce_dsa_core.c
> @@ -0,0 +1,343 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (c) 2020-2026 System on Chip engineering, S.L.
> + * Copyright (c) 2026 Linutronix GmbH
> + * Author: Vasilij Strassheim <v.strassheim@linutronix.de>
> + */
> +
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/netdevice.h>
> +#include <linux/of.h>
> +#include <linux/of_net.h>
> +#include <linux/of_platform.h>
> +#include <linux/phy.h>
> +#include <linux/phylink.h>
> +#include <linux/platform_device.h>
> +
> +#include <net/dsa.h>
> +
> +#include "soce_dsa.h"
> +
> +#define SOCE_MIN_NUM_PORTS			3
> +
> +#define SOCE_CORE_VERSION_OFFSET		0x0000
> +#define SOCE_CORE_VERSION_VERSION_SHIFT		24
> +#define SOCE_CORE_VERSION_SUBVERSION_SHIFT	16
> +#define SOCE_MIN_CORE_VERSION			0x24
> +#define SOCE_MIN_CORE_SUBVERSION		0x01
> +
> +#define SOCE_LIC_FEATURES_OFFSET		0x0004
> +#define SOCE_LIC_FEATURES_NUM_PORTS_MASK	GENMASK(31, 27)
> +
> +#define SOCE_IMPL_FEATURES0_OFFSET		0x000c
> +#define SOCE_IMPL_FEATURES0_NUM_PORTS_MASK	GENMASK(31, 27)
> +#define SOCE_IMPL_FEATURES0_PORT_VLAN		BIT(9)
> +#define SOCE_IMPL_FEATURES0_DSA			BIT(23)
> +
> +#define SOCE_DSA_REGS_BASE			0x1200
> +#define SOCE_TAG_ALL_FRAMES_CTRL_OFFSET		(SOCE_DSA_REGS_BASE + 0x001c)
> +#define SOCE_TAG_ALL_FRAMES_CTRL_ENABLE		BIT(0)
> +#define SOCE_CUSTOM_RULES_TAGGING_OFFSET	(SOCE_DSA_REGS_BASE + 0x0020)
> +#define SOCE_CUSTOM_RULES_TAGGING_ENABLE	BIT(0)
> +
> +#define SOCE_PORTS_REGS_BASE			0x3000
> +#define SOCE_PORTS_SELECTOR_OFFSET		SOCE_PORTS_REGS_BASE
> +#define SOCE_PORTS_SELECTOR_PORT_MASK		GENMASK(7, 0)
> +#define SOCE_PORTS_CTRL_OFFSET			(SOCE_PORTS_REGS_BASE + 0x0004)
> +#define SOCE_PORTS_CTRL_INGR_EN			BIT(0)
> +#define SOCE_PORTS_CTRL_EGR_EN			BIT(1)
> +
> +static void soce_phylink_get_caps(struct dsa_switch *ds, int port,
> +				  struct phylink_config *config)
> +{
> +	struct dsa_port *dp = dsa_to_port(ds, port);
> +	phy_interface_t mode;
> +	int ret;
> +
> +	ret = of_get_phy_mode(dp->dn, &mode);
> +	if (ret)
> +		return;
> +
> +	if (phy_interface_mode_is_rgmii(mode))
> +		phy_interface_set_rgmii(config->supported_interfaces);
> +	else
> +		__set_bit(mode, config->supported_interfaces);
> +
> +	config->mac_capabilities = MAC_SYM_PAUSE | MAC_ASYM_PAUSE;
> +
> +	switch (mode) {
> +	case PHY_INTERFACE_MODE_MII:
> +		config->mac_capabilities |= MAC_10 | MAC_100;
> +		break;
> +	case PHY_INTERFACE_MODE_GMII:
> +		config->mac_capabilities |= MAC_10 | MAC_100 | MAC_1000;
> +		break;
> +	case PHY_INTERFACE_MODE_RMII:
> +		config->mac_capabilities |= MAC_10FD | MAC_100FD;
> +		break;
> +	default:
> +		if (phy_interface_mode_is_rgmii(mode))
> +			config->mac_capabilities |= MAC_10FD | MAC_100FD |
> +						    MAC_1000FD;
> +		break;
> +	}
> +}
> +
> +static int soce_sw_validate_core_version(u8 version, u8 subversion)
> +{
> +	if (version < SOCE_MIN_CORE_VERSION ||
> +	    (version == SOCE_MIN_CORE_VERSION &&
> +	     subversion < SOCE_MIN_CORE_SUBVERSION))
> +		return -ENODEV;
> +
> +	return 0;
> +}
> +
> +static void soce_sw_read_core_version(struct soce_dsa_local *local,
> +				      u8 *version, u8 *subversion,
> +				      u16 *revision)
> +{
> +	u32 regval;
> +
> +	regval = readl(local->base_addr + SOCE_CORE_VERSION_OFFSET);
> +	*version = (u8)(regval >> SOCE_CORE_VERSION_VERSION_SHIFT);
> +	*subversion = (u8)(regval >> SOCE_CORE_VERSION_SUBVERSION_SHIFT);
> +	*revision = (u16)regval;
> +}
> +
> +static int soce_sw_detect_features(struct soce_dsa_local *local,
> +				   u32 *numports)
> +{
> +	void __iomem *base = local->base_addr;
> +	u32 implemented_numports;
> +	u32 licensed_numports;
> +	u32 regval;
> +
> +	regval = readl(base + SOCE_LIC_FEATURES_OFFSET);
> +	licensed_numports = FIELD_GET(SOCE_LIC_FEATURES_NUM_PORTS_MASK, regval);
> +	if (!licensed_numports || licensed_numports > SOCE_MAX_NUM_PORTS)
> +		return -EINVAL;
> +
> +	regval = readl(base + SOCE_IMPL_FEATURES0_OFFSET);
> +	if (!(regval & SOCE_IMPL_FEATURES0_DSA))
> +		return -ENODEV;
> +
> +	implemented_numports =
> +		FIELD_GET(SOCE_IMPL_FEATURES0_NUM_PORTS_MASK, regval);
> +	if (implemented_numports < SOCE_MIN_NUM_PORTS ||
> +	    implemented_numports > licensed_numports)
> +		return -EINVAL;
> +
> +	*numports = implemented_numports;
> +
> +	return 0;
> +}
> +
> +static void soce_sw_enable_tagging(struct soce_dsa_local *local)
> +{
> +	void __iomem *base = local->base_addr;
> +	u32 regval;
> +
> +	regval = readl(base + SOCE_TAG_ALL_FRAMES_CTRL_OFFSET);
> +	regval |= SOCE_TAG_ALL_FRAMES_CTRL_ENABLE;
> +	writel(regval, base + SOCE_TAG_ALL_FRAMES_CTRL_OFFSET);
> +
> +	regval = readl(base + SOCE_CUSTOM_RULES_TAGGING_OFFSET);
> +	regval |= SOCE_CUSTOM_RULES_TAGGING_ENABLE;
> +	writel(regval, base + SOCE_CUSTOM_RULES_TAGGING_OFFSET);
> +}
> +
> +static void soce_sw_disable_tagging(struct soce_dsa_local *local)
> +{
> +	void __iomem *base = local->base_addr;
> +	u32 regval;
> +
> +	regval = readl(base + SOCE_TAG_ALL_FRAMES_CTRL_OFFSET);
> +	regval &= ~SOCE_TAG_ALL_FRAMES_CTRL_ENABLE;
> +	writel(regval, base + SOCE_TAG_ALL_FRAMES_CTRL_OFFSET);
> +
> +	regval = readl(base + SOCE_CUSTOM_RULES_TAGGING_OFFSET);
> +	regval &= ~SOCE_CUSTOM_RULES_TAGGING_ENABLE;
> +	writel(regval, base + SOCE_CUSTOM_RULES_TAGGING_OFFSET);
> +}
> +
> +static void soce_port_select(struct soce_dsa_local *local, int port)
> +{
> +	writel(FIELD_PREP(SOCE_PORTS_SELECTOR_PORT_MASK, port),
> +	       local->base_addr + SOCE_PORTS_SELECTOR_OFFSET);
> +}
> +
> +static void soce_port_set_enabled(struct soce_dsa_local *local, int port,
> +				  bool enabled)
> +{
> +	void __iomem *base = local->base_addr;
> +	u32 regval;
> +
> +	soce_port_select(local, port);
> +
> +	regval = readl(base + SOCE_PORTS_CTRL_OFFSET);
> +	if (enabled)
> +		regval |= SOCE_PORTS_CTRL_INGR_EN | SOCE_PORTS_CTRL_EGR_EN;
> +	else
> +		regval &= ~(SOCE_PORTS_CTRL_INGR_EN | SOCE_PORTS_CTRL_EGR_EN);
> +	writel(regval, base + SOCE_PORTS_CTRL_OFFSET);
> +}
> +
> +static int soce_port_enable(struct dsa_switch *ds, int port,
> +			    struct phy_device *phy)
> +{
> +	struct soce_priv *priv = ds->priv;
> +
> +	soce_port_set_enabled(&priv->local, port, true);
> +
> +	return 0;
> +}
> +
> +static void soce_port_disable(struct dsa_switch *ds, int port)
> +{
> +	struct soce_priv *priv = ds->priv;
> +
> +	soce_port_set_enabled(&priv->local, port, false);
> +}
> +
> +static int soce_setup(struct dsa_switch *ds)
> +{
> +	struct soce_priv *priv = ds->priv;
> +
> +	soce_sw_enable_tagging(&priv->local);

Once all the setup is finished, what is the state of the switch?

What we want is that the user ports are isolated from each other, and
can only exchange frames with the CPU. That makes the hardware
basically a port expander, and you do bridging in software. Later
patches can then add offload of bridging, and whatever else the
hardware can do, which Linux can also do in software.

	Andrew

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

* Re: [PATCH net-next v3 8/8] net: dsa: soce: Disable unsupported hardware STP
  2026-09-23 10:39 ` [PATCH net-next v3 8/8] net: dsa: soce: Disable unsupported hardware STP Vasilij Strassheim
@ 2026-09-25 23:24   ` Andrew Lunn
  0 siblings, 0 replies; 17+ messages in thread
From: Andrew Lunn @ 2026-09-25 23:24 UTC (permalink / raw)
  To: Vasilij Strassheim
  Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Vladimir Oltean,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Russell King, Andrew Lunn, Heiner Kallweit,
	devicetree, linux-kernel, netdev, Martin Kaistra,
	Benedikt Spranger

On Wed, Sep 23, 2026 at 12:39:35PM +0200, Vasilij Strassheim wrote:
> The driver does not implement hardware STP offloading yet.

What exactly do you mean by STP offload? Can it do the actual
protocol? No DSA switch can do that, we always use the software
implementation. I'm not even sure it is possible to offload the actual
protocol.

	Andrew

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

* Re: [PATCH net-next v3 7/8] net: dsa: soce: Add VLAN offload support
  2026-09-23 10:39 ` [PATCH net-next v3 7/8] net: dsa: soce: Add VLAN offload support Vasilij Strassheim
@ 2026-09-25 23:32   ` Andrew Lunn
  0 siblings, 0 replies; 17+ messages in thread
From: Andrew Lunn @ 2026-09-25 23:32 UTC (permalink / raw)
  To: Vasilij Strassheim
  Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Vladimir Oltean,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Russell King, Andrew Lunn, Heiner Kallweit,
	devicetree, linux-kernel, netdev, Martin Kaistra,
	Benedikt Spranger

> The port and VID selectors are shared by all VLAN operations, so
> serialize selector and data register sequences with a dedicated mutex.
> Track member and untagged masks in software and restore the shadow state
> if programming fails.

Looking at other features of the switch, how many different mutex are
going to be needed? Is it better to have a single mutex which protects
everything?

	Andrew

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

end of thread, other threads:[~2026-09-25 23:32 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-23 10:39 [PATCH net-next v3 0/8] net: dsa: Add SoC-e DSA driver Vasilij Strassheim
2026-09-23 10:39 ` [PATCH net-next v3 1/8] dt-bindings: vendor-prefixes: Add soce Vasilij Strassheim
2026-09-23 10:39 ` [PATCH net-next v3 2/8] dt-bindings: net: Add SoC-e SWIP MDIO controller Vasilij Strassheim
2026-09-25 22:55   ` Andrew Lunn
2026-09-23 10:39 ` [PATCH net-next v3 3/8] dt-bindings: net: dsa: Add SoC-e SWIP switch Vasilij Strassheim
2026-09-25 23:05   ` Andrew Lunn
2026-09-23 10:39 ` [PATCH net-next v3 4/8] net: dsa: Add tag handling for SoC-e switches Vasilij Strassheim
     [not found]   ` <20260924104003.A49F31F000FF@smtp.kernel.org>
2026-09-25 12:46     ` Vasilij Strassheim
2026-09-23 10:39 ` [PATCH net-next v3 5/8] net: mdio: Add SoC-e SWIP MDIO controller driver Vasilij Strassheim
2026-09-25 23:10   ` Andrew Lunn
2026-09-23 10:39 ` [PATCH net-next v3 6/8] net: dsa: soce: Add basic support for SoC-e switch IP cores Vasilij Strassheim
2026-09-25 23:17   ` Andrew Lunn
2026-09-25 23:20   ` Andrew Lunn
2026-09-23 10:39 ` [PATCH net-next v3 7/8] net: dsa: soce: Add VLAN offload support Vasilij Strassheim
2026-09-25 23:32   ` Andrew Lunn
2026-09-23 10:39 ` [PATCH net-next v3 8/8] net: dsa: soce: Disable unsupported hardware STP Vasilij Strassheim
2026-09-25 23:24   ` Andrew Lunn

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®