mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH net-next v4 0/8] net: dsa: Add support for SoC-e Ethernet switch IP cores
@ 2026-11-05 14:16 Vasilij Strassheim
  2026-11-05 14:16 ` [PATCH net-next v4 1/8] dt-bindings: vendor-prefixes: Add soce Vasilij Strassheim
                   ` (7 more replies)
  0 siblings, 8 replies; 13+ messages in thread
From: Vasilij Strassheim @ 2026-11-05 14:16 UTC (permalink / raw)
  To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Andrew Lunn,
	Vladimir Oltean, David S. Miller, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Russell King, Andrew Lunn, Heiner Kallweit,
	Eric Dumazet, Lee Jones, Eric Dumazet
  Cc: Vasilij Strassheim, devicetree, linux-kernel, netdev, mfd,
	Martin Kaistra, Benedikt Spranger, Krzysztof Kozlowski

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

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

The drivers use a memory-mapped control interface. The MFD parent
validates the core version and instantiates the child devices. The
switch driver reads the licensed and implemented port counts and
detects optional hardware features. Implemented port counts from 3
through 31 are supported.

The driver configures the hardware DSA feature to isolate user ports
from each other and restrict them to exchanging frames with the CPU
port. Bridge forwarding is handled in software by the Linux bridge.
Hardware STP offload is not implemented. The driver disables the
hardware STP feature when present, leaving STP state handling to the
Linux bridge.

Supported port interfaces are MII, GMII, RMII, and RGMII. On cores
synthesized with Port VLAN support, the driver programs VLAN membership
tables. Bridge VLAN filtering is not offloaded.

On cores synthesized without Port VLAN support, VLAN information is
lost when frames enter the switch through the CPU port and is not
preserved in the SDSA header. The driver therefore rejects direct VLAN
uppers on such cores. VLAN-aware software bridging is also unsupported
on these cores.

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

The drivers were tested with a SoC-e MRS 25.01 IP core on a Xilinx
ZynqMP platform. The tested core was synthesized with three ports, DSA,
IEEE 802.1w RSTP, hybrid SVL/IVL MAC tables, port-based VLAN support,
QoS priorities, and statistics counters.

VLAN TX testing exercised in-band C-tags. TX VLAN offload is disabled
and cannot be enabled on this platform, so the accelerated SDSA-TCI TX
path was not tested.

Signed-off-by: Vasilij Strassheim <v.strassheim@linutronix.de>
---
Changes in v4:
- Rebase onto net-next/main.
- Introduce an MFD parent for core version validation and DT-based
  child-device creation. Keep feature detection and switch register
  mapping in the DSA driver. (Andrew)
- Split the combined switch binding into MFD-parent and switch-function
  bindings. Use soce,swip for the parent and
  soce,swip-switch-00-04-0c-10 for the switch function.
- Reference dsa.yaml#/$defs/ethernet-ports and remove the redundant
  local DSA port schema reference and property closure. (Rob)
- Update description for swip-switch-00-04-0c-10 compatible. (Rob,
  Andrew)
- Rename the MDIO compatible to soce,swip-mdio and update the examples.
- Move the switch driver directly into drivers/net/dsa/, rename it
  to soce-swip.c, and remove its subdirectory Kconfig and Makefile.
- Rename the DSA and MDIO Kconfig symbols to NET_DSA_SOCE_SWIP and
  MDIO_SOCE_SWIP. Make the MFD and MDIO options internal and select
  them from NET_DSA_SOCE_SWIP.
- Reserve and map switch register blocks separately instead of
  claiming the entire IP-core window, and validate their ranges
  against the parent resource.
- Restrict the MDIO control resource to its lower 16-bit halfword.
  Use readw_poll_timeout() and writew() instead of 32-bit
  read-modify-write accesses, leaving the mux selector untouched.
  (Andrew, sashiko-bot)
- Replace the MDIO mapping helper with named platform resource mappings
  and propagate mapping errors through IS_ERR()/PTR_ERR().
- Report feature-detection failures with dev_err_probe() and use
  explicit masks and FIELD_GET() for version extraction. (Andrew)
- Advertise half-duplex capabilities for RMII and RGMII in phylink.
- Disable all user ports during setup before configuring VLANs,
  disabling hardware STP, and enabling tagging. (sashiko-bot)
- Remove the unreachable bridge VLAN-filtering callback and associated
  PVID and untagged-mask tracking. Keep hardware ports VLAN-unaware
  with ingress filtering disabled. (sashiko-bot)
- Program standalone VLAN 1 membership explicitly and preserve it
  when explicit VLAN membership is removed. Explicit membership takes
  precedence over default untagging. (sashiko-bot)
- Wait for both VLAN WRITE bits to clear before changing the shared
  VID selector or data registers. On programming failure, restore
  the software shadow, attempt hardware rollback, log rollback
  failures, and return the original error. (sashiko-bot)
- Clear the VLAN membership shadow after a successful setup reset.
- Handle VID 0 before checking hardware VLAN support in both callbacks.
  Return -EINVAL for unsupported non-zero VID additions. (sashiko-bot)
- Set needs_standalone_vlan_filtering only when Port VLAN is present.
  Reject direct VLAN uppers otherwise through port_prechangeupper,
  while retaining software-bridge support.
- Rename vlan_lock to feature_lock, initialize it independently of
  VLAN support, and remove unnecessary setup locking. (Andrew)
- Push accelerated non-802.1Q VLAN tags in-band before inserting
  SDSA, and handle allocation failure. (sashiko-bot)
- Include linux/bitfield.h explicitly in the SDSA tagger and document
  the duplicated VLAN TCI in received frames.
- Replace SKB_DROP_REASON_HDR_TRUNC with the reason returned by
  pskb_may_pull_reason(), following API change in net-next.

- Link to v3: https://patch.msgid.link/20260923-devel-vstrassheim-soce-dsa-ml-v3-0-ddebafcb9ba7@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>
To: Eric Dumazet <edumazet@kernel.org>
To: Lee Jones <lee@kernel.org>
Cc: devicetree@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Cc: netdev@vger.kernel.org
Cc: mfd@lists.linux.dev
Cc: Martin Kaistra <martin.kaistra@linutronix.de>
Cc: Benedikt Spranger <b.spranger@linutronix.de>

---
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 function
      dt-bindings: mfd: Add SoC-e SWIP parent
      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 membership table support

 .../devicetree/bindings/mfd/soce,swip.yaml         | 137 ++++
 .../bindings/net/dsa/soce,swip-switch.yaml         |  96 +++
 .../devicetree/bindings/net/soce,swip-mdio.yaml    |  47 ++
 .../devicetree/bindings/vendor-prefixes.yaml       |   2 +
 drivers/mfd/Kconfig                                |   9 +
 drivers/mfd/Makefile                               |   2 +
 drivers/mfd/soce-swip-core.c                       |  76 +++
 drivers/net/dsa/Kconfig                            |  15 +
 drivers/net/dsa/Makefile                           |   1 +
 drivers/net/dsa/soce-swip.c                        | 717 +++++++++++++++++++++
 drivers/net/dsa/soce-swip.h                        |  39 ++
 drivers/net/mdio/Kconfig                           |  10 +
 drivers/net/mdio/Makefile                          |   1 +
 drivers/net/mdio/mdio-soce.c                       | 213 ++++++
 include/net/dsa.h                                  |   2 +
 net/dsa/Kconfig                                    |   6 +
 net/dsa/Makefile                                   |   1 +
 net/dsa/tag_sdsa.c                                 | 168 +++++
 18 files changed, 1542 insertions(+)
---
base-commit: 7b6ab4dbc156e2f96419715130b3d5738a306c93
change-id: 20260729-devel-vstrassheim-soce-dsa-ml-20d6a5adb838

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


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

* [PATCH net-next v4 1/8] dt-bindings: vendor-prefixes: Add soce
  2026-11-05 14:16 [PATCH net-next v4 0/8] net: dsa: Add support for SoC-e Ethernet switch IP cores Vasilij Strassheim
@ 2026-11-05 14:16 ` Vasilij Strassheim
  2026-11-05 14:16 ` [PATCH net-next v4 2/8] dt-bindings: net: Add SoC-e SWIP MDIO controller Vasilij Strassheim
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 13+ messages in thread
From: Vasilij Strassheim @ 2026-11-05 14:16 UTC (permalink / raw)
  To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Andrew Lunn,
	Vladimir Oltean, David S. Miller, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Russell King, Andrew Lunn, Heiner Kallweit,
	Eric Dumazet, Lee Jones, Eric Dumazet
  Cc: Vasilij Strassheim, devicetree, linux-kernel, netdev, mfd,
	Martin Kaistra, Benedikt Spranger, 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 5471a06f93f1..20a850a6e86f 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -1599,6 +1599,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] 13+ messages in thread

* [PATCH net-next v4 2/8] dt-bindings: net: Add SoC-e SWIP MDIO controller
  2026-11-05 14:16 [PATCH net-next v4 0/8] net: dsa: Add support for SoC-e Ethernet switch IP cores Vasilij Strassheim
  2026-11-05 14:16 ` [PATCH net-next v4 1/8] dt-bindings: vendor-prefixes: Add soce Vasilij Strassheim
@ 2026-11-05 14:16 ` Vasilij Strassheim
  2026-11-05 14:16 ` [PATCH net-next v4 3/8] dt-bindings: net: dsa: Add SoC-e SWIP switch function Vasilij Strassheim
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 13+ messages in thread
From: Vasilij Strassheim @ 2026-11-05 14:16 UTC (permalink / raw)
  To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Andrew Lunn,
	Vladimir Oltean, David S. Miller, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Russell King, Andrew Lunn, Heiner Kallweit,
	Eric Dumazet, Lee Jones, Eric Dumazet
  Cc: Vasilij Strassheim, devicetree, linux-kernel, netdev, mfd,
	Martin Kaistra, Benedikt Spranger

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

The binding describes the transaction data registers and the lower
16-bit half of the control register shared with the external MDIO bus
selector. A sibling generic MMIO MDIO mux uses the upper half to select
the external bus.

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..7a0b8bd3ab71
--- /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 SWIP FPGA MDIO controller
+
+maintainers:
+  - Vasilij Strassheim <v.strassheim@linutronix.de>
+
+description:
+  MDIO controller integrated into the SoC-e Switch IP (SWIP) FPGA core.
+  External MDIO buses are selected through a sibling MMIO MDIO mux.
+
+$ref: mdio.yaml#
+
+properties:
+  compatible:
+    const: soce,swip-mdio
+
+  reg:
+    items:
+      - description: MDIO parameter, write data, and read data registers
+      - description: Lower 16-bit half of the MDIO transaction control register
+
+  reg-names:
+    items:
+      - const: data
+      - const: control
+
+required:
+  - compatible
+  - reg
+  - reg-names
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    mdio@204 {
+        compatible = "soce,swip-mdio";
+        reg = <0x204 0xc>, <0x200 0x2>;
+        reg-names = "data", "control";
+        #address-cells = <1>;
+        #size-cells = <0>;
+    };

-- 
2.39.5


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

* [PATCH net-next v4 3/8] dt-bindings: net: dsa: Add SoC-e SWIP switch function
  2026-11-05 14:16 [PATCH net-next v4 0/8] net: dsa: Add support for SoC-e Ethernet switch IP cores Vasilij Strassheim
  2026-11-05 14:16 ` [PATCH net-next v4 1/8] dt-bindings: vendor-prefixes: Add soce Vasilij Strassheim
  2026-11-05 14:16 ` [PATCH net-next v4 2/8] dt-bindings: net: Add SoC-e SWIP MDIO controller Vasilij Strassheim
@ 2026-11-05 14:16 ` Vasilij Strassheim
  2026-11-05 14:16 ` [PATCH net-next v4 4/8] dt-bindings: mfd: Add SoC-e SWIP parent Vasilij Strassheim
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 13+ messages in thread
From: Vasilij Strassheim @ 2026-11-05 14:16 UTC (permalink / raw)
  To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Andrew Lunn,
	Vladimir Oltean, David S. Miller, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Russell King, Andrew Lunn, Heiner Kallweit,
	Eric Dumazet, Lee Jones, Eric Dumazet
  Cc: Vasilij Strassheim, devicetree, linux-kernel, netdev, mfd,
	Martin Kaistra, Benedikt Spranger

Add a binding for the Ethernet switch function integrated into SoC-e
SWIP cores.

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

diff --git a/Documentation/devicetree/bindings/net/dsa/soce,swip-switch.yaml b/Documentation/devicetree/bindings/net/dsa/soce,swip-switch.yaml
new file mode 100644
index 000000000000..daac779c466d
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/dsa/soce,swip-switch.yaml
@@ -0,0 +1,96 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/net/dsa/soce,swip-switch.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: SoC-e SWIP FPGA Ethernet switch function
+
+maintainers:
+  - Vasilij Strassheim <v.strassheim@linutronix.de>
+
+description:
+  Ethernet switch function of the SoC-e Switch IP (SWIP) FPGA core. The port
+  count and presence of VLAN and STP register blocks depend on the FPGA
+  synthesis configuration.
+
+$ref: dsa.yaml#/$defs/ethernet-ports
+
+properties:
+  compatible:
+    const: soce,swip-switch-00-04-0c-10
+    description:
+      This compatible identifies the register layout; its suffix gives
+      the offsets of the core version and feature identification
+      registers (0x00, 0x04, 0x0c, and 0x10). Port counts and optional
+      features depend on the FPGA synthesis configuration and are
+      detected at runtime using this register layout.
+
+  reg: false
+
+  reg-names: false
+
+  ethernet-ports:
+    type: object
+    patternProperties:
+      '^ethernet-port@[0-9a-f]+$':
+        type: object
+
+        properties:
+          reg:
+            maximum: 30
+            description: Switch port index, from 0 through 30.
+
+          phy-mode:
+            enum:
+              - mii
+              - gmii
+              - rmii
+              - rgmii
+              - rgmii-id
+              - rgmii-rxid
+              - rgmii-txid
+
+        required:
+          - reg
+          - phy-mode
+
+required:
+  - compatible
+  - ethernet-ports
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    ethernet-switch {
+        compatible = "soce,swip-switch-00-04-0c-10";
+
+        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] 13+ messages in thread

* [PATCH net-next v4 4/8] dt-bindings: mfd: Add SoC-e SWIP parent
  2026-11-05 14:16 [PATCH net-next v4 0/8] net: dsa: Add support for SoC-e Ethernet switch IP cores Vasilij Strassheim
                   ` (2 preceding siblings ...)
  2026-11-05 14:16 ` [PATCH net-next v4 3/8] dt-bindings: net: dsa: Add SoC-e SWIP switch function Vasilij Strassheim
@ 2026-11-05 14:16 ` Vasilij Strassheim
  2026-11-06 11:13   ` Krzysztof Kozlowski
  2026-11-05 14:16 ` [PATCH net-next v4 5/8] net: dsa: Add tag handling for SoC-e switches Vasilij Strassheim
                   ` (3 subsequent siblings)
  7 siblings, 1 reply; 13+ messages in thread
From: Vasilij Strassheim @ 2026-11-05 14:16 UTC (permalink / raw)
  To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Andrew Lunn,
	Vladimir Oltean, David S. Miller, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Russell King, Andrew Lunn, Heiner Kallweit,
	Eric Dumazet, Lee Jones, Eric Dumazet
  Cc: Vasilij Strassheim, devicetree, linux-kernel, netdev, mfd,
	Martin Kaistra, Benedikt Spranger

Add a binding for the SoC-e SWIP multifunction FPGA IP core.

Describe the shared MMIO address space and address translation for
the required Ethernet switch child and the optional integrated MDIO
controller and MMIO-controlled MDIO multiplexer.

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

diff --git a/Documentation/devicetree/bindings/mfd/soce,swip.yaml b/Documentation/devicetree/bindings/mfd/soce,swip.yaml
new file mode 100644
index 000000000000..625be299e262
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/soce,swip.yaml
@@ -0,0 +1,137 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mfd/soce,swip.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: SoC-e SWIP multifunction Ethernet switch FPGA IP core
+
+maintainers:
+  - Vasilij Strassheim <v.strassheim@linutronix.de>
+
+description:
+  SoC-e Switch IP (SWIP) cores integrate Ethernet switching logic, an
+  MDIO controller, and an MDIO bus multiplexer in one memory-mapped device.
+  The MDIO bus multiplexer is wired to the integrated MDIO controller.
+
+properties:
+  compatible:
+    const: soce,swip
+
+  reg:
+    maxItems: 1
+
+  '#address-cells':
+    const: 1
+
+  '#size-cells':
+    const: 1
+
+  ranges: true
+
+  mdio@204:
+    $ref: /schemas/net/soce,swip-mdio.yaml#
+    unevaluatedProperties: false
+
+  mdio-mux@202:
+    $ref: /schemas/net/mdio-mux-mmioreg.yaml#
+    unevaluatedProperties: false
+
+  ethernet-switch:
+    $ref: /schemas/net/dsa/soce,swip-switch.yaml#
+    unevaluatedProperties: false
+
+required:
+  - compatible
+  - reg
+  - '#address-cells'
+  - '#size-cells'
+  - ranges
+  - ethernet-switch
+
+dependentRequired:
+  mdio-mux@202:
+    - mdio@204
+
+additionalProperties: false
+
+examples:
+  - |
+    ethernet-switch@80020000 {
+        compatible = "soce,swip";
+        reg = <0x80020000 0x10000>;
+        #address-cells = <1>;
+        #size-cells = <1>;
+        ranges = <0x0 0x80020000 0x10000>;
+
+        mdio_parent: mdio@204 {
+            compatible = "soce,swip-mdio";
+            reg = <0x204 0xc>, <0x200 0x2>;
+            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-switch {
+            compatible = "soce,swip-switch-00-04-0c-10";
+
+            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] 13+ messages in thread

* [PATCH net-next v4 5/8] net: dsa: Add tag handling for SoC-e switches
  2026-11-05 14:16 [PATCH net-next v4 0/8] net: dsa: Add support for SoC-e Ethernet switch IP cores Vasilij Strassheim
                   ` (3 preceding siblings ...)
  2026-11-05 14:16 ` [PATCH net-next v4 4/8] dt-bindings: mfd: Add SoC-e SWIP parent Vasilij Strassheim
@ 2026-11-05 14:16 ` Vasilij Strassheim
  2026-11-05 14:16 ` [PATCH net-next v4 6/8] net: mdio: Add SoC-e SWIP MDIO controller driver Vasilij Strassheim
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 13+ messages in thread
From: Vasilij Strassheim @ 2026-11-05 14:16 UTC (permalink / raw)
  To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Andrew Lunn,
	Vladimir Oltean, David S. Miller, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Russell King, Andrew Lunn, Heiner Kallweit,
	Eric Dumazet, Lee Jones, Eric Dumazet
  Cc: Vasilij Strassheim, devicetree, linux-kernel, netdev, mfd,
	Martin Kaistra, Benedikt Spranger

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
hardware-accelerated 802.1Q VLAN metadata into this field on transmit
and clear the skb VLAN metadata to prevent subsequent VLAN insertion by
the conduit.

Leave existing in-band VLAN headers in the encapsulated frame, after the
SDSA header. Whether an 802.1Q tag reaches the tagger as accelerated
metadata or an in-band header depends on the VLAN TX features inherited
from the conduit.

Since SDSA carries no TPID, move accelerated tags with other VLAN
protocols into the frame before inserting the SDSA header. On receive,
the switch keeps an ingress 802.1Q header in the frame and duplicates
its TCI in the SDSA header. Drop the in-band copy and restore the TCI as
accelerated 802.1Q metadata.

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 | 168 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 177 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..dcfa5de0ac6b
--- /dev/null
+++ b/net/dsa/tag_sdsa.c
@@ -0,0 +1,168 @@
+// 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/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;
+	bool encode_vlan;
+	bool tag_present;
+	u16 vlan_tci;
+
+	BUILD_BUG_ON(sizeof(*tag) != SDSA_HLEN);
+
+	/* SDSA carries no TPID, so only encode 802.1Q C-tags. */
+	tag_present = skb_vlan_tag_present(skb);
+	encode_vlan = tag_present && skb->vlan_proto == htons(ETH_P_8021Q);
+	/* Prevent the conduit from inserting a VLAN header ahead of SDSA. */
+	if (tag_present && !encode_vlan) {
+		skb = __vlan_hwaccel_push_inside(skb);
+		if (!skb)
+			return NULL;
+	}
+
+	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);
+	if (encode_vlan) {
+		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;
+
+	reason = pskb_may_pull_reason(skb, SDSA_HLEN);
+	if (unlikely(reason != SKB_NOT_DROPPED_YET))
+		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) {
+		/* The in-band tag duplicates the TCI carried in SDSA. */
+		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] 13+ messages in thread

* [PATCH net-next v4 6/8] net: mdio: Add SoC-e SWIP MDIO controller driver
  2026-11-05 14:16 [PATCH net-next v4 0/8] net: dsa: Add support for SoC-e Ethernet switch IP cores Vasilij Strassheim
                   ` (4 preceding siblings ...)
  2026-11-05 14:16 ` [PATCH net-next v4 5/8] net: dsa: Add tag handling for SoC-e switches Vasilij Strassheim
@ 2026-11-05 14:16 ` Vasilij Strassheim
  2026-11-05 14:16 ` [PATCH net-next v4 7/8] net: dsa: soce: Add basic support for SoC-e switch IP cores Vasilij Strassheim
  2026-11-05 14:16 ` [PATCH net-next v4 8/8] net: dsa: soce: Add VLAN membership table support Vasilij Strassheim
  7 siblings, 0 replies; 13+ messages in thread
From: Vasilij Strassheim @ 2026-11-05 14:16 UTC (permalink / raw)
  To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Andrew Lunn,
	Vladimir Oltean, David S. Miller, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Russell King, Andrew Lunn, Heiner Kallweit,
	Eric Dumazet, Lee Jones, Eric Dumazet
  Cc: Vasilij Strassheim, devicetree, linux-kernel, netdev, mfd,
	Martin Kaistra, Benedikt Spranger

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. Access transaction
control through the lower halfword to preserve the selector bits.

Check that the controller is idle before programming transaction
registers and poll for completion after each transaction cycle. Return
-ETIMEDOUT if the controller remains busy. No abort or reset recovery is
implemented.

The idle check does not cover selector writes: the generic mux changes
the selector before invoking the controller callback. After a timeout, a
subsequent access to a different child bus may therefore change the
selector while the previous transaction is still active. Whether the
hardware latches the selector at transaction start is not documented, so
such a bus change is not guaranteed to be safe. This limitation is
accepted when using the generic MMIO MDIO mux.

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

diff --git a/drivers/net/mdio/Kconfig b/drivers/net/mdio/Kconfig
index d44278f26fab..b9bb9016b925 100644
--- a/drivers/net/mdio/Kconfig
+++ b/drivers/net/mdio/Kconfig
@@ -189,6 +189,16 @@ config MDIO_REGMAP
 	  regmap. Users willing to use this driver must explicitly select
 	  REGMAP.
 
+config MDIO_SOCE_SWIP
+	tristate
+	depends on OF_MDIO && HAS_IOMEM
+	depends on MFD_SOCE_SWIP
+	help
+	  This driver provides support for the MDIO controller
+	  integrated into SoC-e SWIP Ethernet switch IP cores.  This option
+	  will be selected if the configuration for the main switch
+	  functionality of the FPGA IP core is selected.
+
 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..d69f918313d3 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_SWIP)		+= 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..5350feb92d55
--- /dev/null
+++ b/drivers/net/mdio/mdio-soce.c
@@ -0,0 +1,213 @@
+// 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_mdio.h>
+#include <linux/platform_device.h>
+
+#define SWIP_MDIO_TIMEOUT_US		1000
+
+#define SWIP_MDIO_PARAMS_OFFSET		0x0000
+#define SWIP_MDIO_WRITE_OFFSET		0x0004
+#define SWIP_MDIO_READ_OFFSET		0x0008
+
+#define SWIP_MDIO_CTRL_TRANSTYPE_MASK	GENMASK(4, 3)
+#define SWIP_MDIO_CTRL_TRANSTYPE_WRITE	0x1
+#define SWIP_MDIO_CTRL_TRANSTYPE_READ	0x3
+#define SWIP_MDIO_CTRL_CLAUSE		BIT(1)
+#define SWIP_MDIO_CTRL_OPSTATUS		BIT(0)
+#define SWIP_MDIO_PARAMS_REGDEV_MASK	GENMASK(12, 8)
+#define SWIP_MDIO_PARAMS_PHYADDR_MASK	GENMASK(4, 0)
+#define SWIP_MDIO_READ_DATA_MASK	GENMASK(15, 0)
+
+struct swip_mdio {
+	void __iomem *ctrl;
+	void __iomem *data;
+};
+
+static int swip_mdio_wait_for_idle(struct swip_mdio *priv)
+{
+	void __iomem *ctrl = priv->ctrl;
+	u16 val;
+
+	return readw_poll_timeout(ctrl, val, !(val & SWIP_MDIO_CTRL_OPSTATUS),
+				  10, SWIP_MDIO_TIMEOUT_US);
+}
+
+static int swip_mdio_read(struct mii_bus *bus, int phy_addr, int regnum)
+{
+	struct swip_mdio *priv = bus->priv;
+	void __iomem *data = priv->data;
+	u32 command;
+	int ret;
+
+	ret = swip_mdio_wait_for_idle(priv);
+	if (ret)
+		return ret;
+
+	writel(FIELD_PREP(SWIP_MDIO_PARAMS_REGDEV_MASK, regnum) |
+	       FIELD_PREP(SWIP_MDIO_PARAMS_PHYADDR_MASK, phy_addr),
+	       data + SWIP_MDIO_PARAMS_OFFSET);
+
+	command = FIELD_PREP(SWIP_MDIO_CTRL_TRANSTYPE_MASK,
+			     SWIP_MDIO_CTRL_TRANSTYPE_READ) |
+		  SWIP_MDIO_CTRL_OPSTATUS;
+	writew(command, priv->ctrl);
+
+	ret = swip_mdio_wait_for_idle(priv);
+	if (ret)
+		return ret;
+
+	return readl(data + SWIP_MDIO_READ_OFFSET) & SWIP_MDIO_READ_DATA_MASK;
+}
+
+static int swip_mdio_read_c45(struct mii_bus *bus, int phy_addr, int devad,
+			      int regnum)
+{
+	struct swip_mdio *priv = bus->priv;
+	void __iomem *data = priv->data;
+	u32 command;
+	int ret;
+
+	ret = swip_mdio_wait_for_idle(priv);
+	if (ret)
+		return ret;
+
+	writel(FIELD_PREP(SWIP_MDIO_PARAMS_REGDEV_MASK, devad) |
+	       FIELD_PREP(SWIP_MDIO_PARAMS_PHYADDR_MASK, phy_addr),
+	       data + SWIP_MDIO_PARAMS_OFFSET);
+	writel(regnum, data + SWIP_MDIO_WRITE_OFFSET);
+
+	command = SWIP_MDIO_CTRL_CLAUSE | SWIP_MDIO_CTRL_OPSTATUS;
+	writew(command, priv->ctrl);
+
+	ret = swip_mdio_wait_for_idle(priv);
+	if (ret)
+		return ret;
+
+	command = FIELD_PREP(SWIP_MDIO_CTRL_TRANSTYPE_MASK,
+			     SWIP_MDIO_CTRL_TRANSTYPE_READ) |
+		  SWIP_MDIO_CTRL_CLAUSE | SWIP_MDIO_CTRL_OPSTATUS;
+	writew(command, priv->ctrl);
+
+	ret = swip_mdio_wait_for_idle(priv);
+	if (ret)
+		return ret;
+
+	return readl(data + SWIP_MDIO_READ_OFFSET) & SWIP_MDIO_READ_DATA_MASK;
+}
+
+static int swip_mdio_write(struct mii_bus *bus, int phy_addr, int regnum,
+			   u16 val)
+{
+	struct swip_mdio *priv = bus->priv;
+	void __iomem *data = priv->data;
+	u32 command;
+	int ret;
+
+	ret = swip_mdio_wait_for_idle(priv);
+	if (ret)
+		return ret;
+
+	writel(FIELD_PREP(SWIP_MDIO_PARAMS_REGDEV_MASK, regnum) |
+	       FIELD_PREP(SWIP_MDIO_PARAMS_PHYADDR_MASK, phy_addr),
+	       data + SWIP_MDIO_PARAMS_OFFSET);
+	writel(val, data + SWIP_MDIO_WRITE_OFFSET);
+
+	command = FIELD_PREP(SWIP_MDIO_CTRL_TRANSTYPE_MASK,
+			     SWIP_MDIO_CTRL_TRANSTYPE_WRITE) |
+		  SWIP_MDIO_CTRL_OPSTATUS;
+	writew(command, priv->ctrl);
+
+	return swip_mdio_wait_for_idle(priv);
+}
+
+static int swip_mdio_write_c45(struct mii_bus *bus, int phy_addr, int devad,
+			       int regnum, u16 val)
+{
+	struct swip_mdio *priv = bus->priv;
+	void __iomem *data = priv->data;
+	u32 command;
+	int ret;
+
+	ret = swip_mdio_wait_for_idle(priv);
+	if (ret)
+		return ret;
+
+	writel(FIELD_PREP(SWIP_MDIO_PARAMS_REGDEV_MASK, devad) |
+	       FIELD_PREP(SWIP_MDIO_PARAMS_PHYADDR_MASK, phy_addr),
+	       data + SWIP_MDIO_PARAMS_OFFSET);
+	writel(regnum, data + SWIP_MDIO_WRITE_OFFSET);
+
+	command = SWIP_MDIO_CTRL_CLAUSE | SWIP_MDIO_CTRL_OPSTATUS;
+	writew(command, priv->ctrl);
+
+	ret = swip_mdio_wait_for_idle(priv);
+	if (ret)
+		return ret;
+
+	writel(val, data + SWIP_MDIO_WRITE_OFFSET);
+
+	command = FIELD_PREP(SWIP_MDIO_CTRL_TRANSTYPE_MASK,
+			     SWIP_MDIO_CTRL_TRANSTYPE_WRITE) |
+		  SWIP_MDIO_CTRL_CLAUSE | SWIP_MDIO_CTRL_OPSTATUS;
+	writew(command, priv->ctrl);
+
+	return swip_mdio_wait_for_idle(priv);
+}
+
+static int swip_mdio_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct swip_mdio *priv;
+	struct mii_bus *bus;
+
+	bus = devm_mdiobus_alloc_size(dev, sizeof(*priv));
+	if (!bus)
+		return -ENOMEM;
+
+	priv = bus->priv;
+	priv->data = devm_platform_ioremap_resource_byname(pdev, "data");
+	if (IS_ERR(priv->data))
+		return PTR_ERR(priv->data);
+
+	priv->ctrl = devm_platform_ioremap_resource_byname(pdev, "control");
+	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 = swip_mdio_read;
+	bus->write = swip_mdio_write;
+	bus->read_c45 = swip_mdio_read_c45;
+	bus->write_c45 = swip_mdio_write_c45;
+
+	return devm_of_mdiobus_register(dev, bus, dev->of_node);
+}
+
+static const struct of_device_id swip_mdio_of_match[] = {
+	{ .compatible = "soce,swip-mdio" },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, swip_mdio_of_match);
+
+static struct platform_driver swip_mdio_driver = {
+	.probe = swip_mdio_probe,
+	.driver = {
+		.name = "soce-mdio",
+		.of_match_table = swip_mdio_of_match,
+	},
+};
+module_platform_driver(swip_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] 13+ messages in thread

* [PATCH net-next v4 7/8] net: dsa: soce: Add basic support for SoC-e switch IP cores
  2026-11-05 14:16 [PATCH net-next v4 0/8] net: dsa: Add support for SoC-e Ethernet switch IP cores Vasilij Strassheim
                   ` (5 preceding siblings ...)
  2026-11-05 14:16 ` [PATCH net-next v4 6/8] net: mdio: Add SoC-e SWIP MDIO controller driver Vasilij Strassheim
@ 2026-11-05 14:16 ` Vasilij Strassheim
  2026-11-05 14:16 ` [PATCH net-next v4 8/8] net: dsa: soce: Add VLAN membership table support Vasilij Strassheim
  7 siblings, 0 replies; 13+ messages in thread
From: Vasilij Strassheim @ 2026-11-05 14:16 UTC (permalink / raw)
  To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Andrew Lunn,
	Vladimir Oltean, David S. Miller, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Russell King, Andrew Lunn, Heiner Kallweit,
	Eric Dumazet, Lee Jones, Eric Dumazet
  Cc: Vasilij Strassheim, devicetree, linux-kernel, netdev, mfd,
	Martin Kaistra, Benedikt Spranger

Add a DSA driver and an MFD parent for SoC-e FPGA-based Ethernet
switch IP cores.

The MFD parent validates the core version and populates the Device Tree
child devices, including the switch function, integrated MDIO controller,
and MDIO mux.

The DSA driver reads the licensed and implemented port counts and
synthesis-time feature registers. 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.

Reserve and map individual switch register blocks within the parent's
MMIO resource rather than claiming the entire IP-core address space.

Enable "All Frames" tagging and the hardware DSA custom rules during
setup. This isolates user ports and directs their ingress traffic to
the CPU port, leaving bridge forwarding to the Linux bridge.

Disable all user ports during setup and control port ingress and
egress through the DSA port enable and disable callbacks. Disable
tagging again during teardown.

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

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/mfd/Kconfig          |   9 ++
 drivers/mfd/Makefile         |   2 +
 drivers/mfd/soce-swip-core.c |  76 +++++++++
 drivers/net/dsa/Kconfig      |  15 ++
 drivers/net/dsa/Makefile     |   1 +
 drivers/net/dsa/soce-swip.c  | 369 +++++++++++++++++++++++++++++++++++++++++++
 drivers/net/dsa/soce-swip.h  |  35 ++++
 7 files changed, 507 insertions(+)

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 87ed55c155f0..ff3378e928fd 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -1291,6 +1291,15 @@ config MFD_QCOM_RPM
 	  Say M here if you want to include support for the Qualcomm RPM as a
 	  module. This will build a module called "qcom_rpm".
 
+config MFD_SOCE_SWIP
+	tristate
+	depends on OF
+	help
+	  Support for memory-mapped SoC-e Ethernet switch IP cores implemented
+	  in FPGAs. These devices integrate an Ethernet
+	  switch, an MDIO controller, and an MDIO bus selector.
+	  This is selected if Ethernet switch functionality is configured.
+
 config MFD_SPACEMIT_P1
 	tristate "SpacemiT P1 PMIC"
 	depends on ARCH_SPACEMIT || COMPILE_TEST
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index f8101d2a9ce9..9f4d2ccc3a24 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -302,6 +302,8 @@ obj-$(CONFIG_MFD_QNAP_MCU)	+= qnap-mcu.o
 obj-$(CONFIG_MFD_RSMU_I2C)	+= rsmu_i2c.o rsmu_core.o
 obj-$(CONFIG_MFD_RSMU_SPI)	+= rsmu_spi.o rsmu_core.o
 
+obj-$(CONFIG_MFD_SOCE_SWIP)	+= soce-swip-core.o
+
 obj-$(CONFIG_MFD_UPBOARD_FPGA)	+= upboard-fpga.o
 
 obj-$(CONFIG_MFD_LOONGSON_SE)	+= loongson-se.o
diff --git a/drivers/mfd/soce-swip-core.c b/drivers/mfd/soce-swip-core.c
new file mode 100644
index 000000000000..2f7d966eeab2
--- /dev/null
+++ b/drivers/mfd/soce-swip-core.c
@@ -0,0 +1,76 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/bitfield.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+
+#define SWIP_CORE_VERSION_OFFSET		0x0000
+#define SWIP_CORE_VERSION_VERSION_MASK		GENMASK(31, 24)
+#define SWIP_CORE_VERSION_SUBVERSION_MASK	GENMASK(23, 16)
+#define SWIP_CORE_VERSION_REVISION_MASK		GENMASK(15, 0)
+#define SWIP_MIN_CORE_VERSION			0x24
+#define SWIP_MIN_CORE_SUBVERSION		0x01
+
+static int swip_check_version(struct device *dev, void __iomem *base)
+{
+	u8 subversion;
+	u16 revision;
+	u8 version;
+	u32 regval;
+
+	regval = readl(base + SWIP_CORE_VERSION_OFFSET);
+	version = FIELD_GET(SWIP_CORE_VERSION_VERSION_MASK, regval);
+	subversion = FIELD_GET(SWIP_CORE_VERSION_SUBVERSION_MASK, regval);
+	revision = FIELD_GET(SWIP_CORE_VERSION_REVISION_MASK, regval);
+	if (version < SWIP_MIN_CORE_VERSION ||
+	    (version == SWIP_MIN_CORE_VERSION &&
+	     subversion < SWIP_MIN_CORE_SUBVERSION))
+		return dev_err_probe(dev, -ENODEV,
+				     "unsupported core version %02x.%02x.%04x\n",
+				     version, subversion, revision);
+
+	dev_info(dev, "SoC-e IP core version %02x.%02x.%04x detected\n",
+		 version, subversion, revision);
+
+	return 0;
+}
+
+static int swip_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct resource *res;
+	void __iomem *base;
+	int ret;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res || resource_size(res) < sizeof(u32))
+		return -EINVAL;
+	base = devm_ioremap(dev, res->start, sizeof(u32));
+	if (!base)
+		return -ENOMEM;
+	ret = swip_check_version(dev, base);
+	if (ret)
+		return ret;
+
+	return devm_of_platform_populate(dev);
+}
+
+static const struct of_device_id swip_of_match[] = {
+	{ .compatible = "soce,swip" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, swip_of_match);
+
+static struct platform_driver swip_driver = {
+	.probe = swip_probe,
+	.driver = {
+		.name = "soce-swip",
+		.of_match_table = swip_of_match,
+	},
+};
+module_platform_driver(swip_driver);
+
+MODULE_DESCRIPTION("SoC-e multifunction switch IP device driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig
index fe8cd5338fda..ed45e03e0de7 100644
--- a/drivers/net/dsa/Kconfig
+++ b/drivers/net/dsa/Kconfig
@@ -147,6 +147,21 @@ config NET_DSA_SMSC_LAN9303_MDIO
 	  Enable access functions if the Microchip LAN9303/LAN9354 is configured
 	  for MDIO managed mode.
 
+config NET_DSA_SOCE_SWIP
+	tristate "SoC-e SWIP switches"
+	depends on NET_DSA
+	depends on OF
+	depends on HAS_IOMEM
+	select MFD_SOCE_SWIP
+	select MDIO_SOCE_SWIP
+	select MDIO_BUS_MUX_MMIOREG
+	select NET_DSA_TAG_SDSA
+	help
+	  This enables support for switches based on SoC-e SWIP 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.
+
 config NET_DSA_VITESSE_VSC73XX
 	tristate
 	select NET_DSA_TAG_VSC73XX_8021Q
diff --git a/drivers/net/dsa/Makefile b/drivers/net/dsa/Makefile
index 7e637d56b35c..cb00d83ed29a 100644
--- a/drivers/net/dsa/Makefile
+++ b/drivers/net/dsa/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_NET_DSA_RZN1_A5PSW) += rzn1_a5psw.o
 obj-$(CONFIG_NET_DSA_SMSC_LAN9303) += lan9303-core.o
 obj-$(CONFIG_NET_DSA_SMSC_LAN9303_I2C) += lan9303_i2c.o
 obj-$(CONFIG_NET_DSA_SMSC_LAN9303_MDIO) += lan9303_mdio.o
+obj-$(CONFIG_NET_DSA_SOCE_SWIP) += soce-swip.o
 obj-$(CONFIG_NET_DSA_VITESSE_VSC73XX) += vitesse-vsc73xx-core.o
 obj-$(CONFIG_NET_DSA_VITESSE_VSC73XX_PLATFORM) += vitesse-vsc73xx-platform.o
 obj-$(CONFIG_NET_DSA_VITESSE_VSC73XX_SPI) += vitesse-vsc73xx-spi.o
diff --git a/drivers/net/dsa/soce-swip.c b/drivers/net/dsa/soce-swip.c
new file mode 100644
index 000000000000..70fc2da91dd2
--- /dev/null
+++ b/drivers/net/dsa/soce-swip.c
@@ -0,0 +1,369 @@
+// 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/if_vlan.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/of.h>
+#include <linux/of_net.h>
+#include <linux/phy.h>
+#include <linux/phylink.h>
+#include <linux/platform_device.h>
+#include <linux/string.h>
+
+#include <net/dsa.h>
+
+#include "soce-swip.h"
+
+#define SWIP_IDENT_BASE_OFFSET			0x0000
+#define SWIP_IDENT_SIZE				0x0050
+#define SWIP_LIC_FEATURES_OFFSET		0x0004
+#define SWIP_LIC_FEATURES_NUM_PORTS_MASK	GENMASK(31, 27)
+#define SWIP_IMPL_FEATURES0_OFFSET		0x000c
+#define SWIP_IMPL_FEATURES0_NUM_PORTS_MASK	GENMASK(31, 27)
+#define SWIP_IMPL_FEATURES0_STP			BIT(20)
+#define SWIP_IMPL_FEATURES0_DSA			BIT(23)
+#define SWIP_MIN_NUM_PORTS			3
+
+#define SWIP_DSA_BASE_OFFSET			0x1200
+#define SWIP_DSA_SIZE				0x0044
+#define SWIP_TAG_ALL_FRAMES_CTRL_OFFSET		0x001c
+#define SWIP_TAG_ALL_FRAMES_CTRL_ENABLE		BIT(0)
+#define SWIP_CUSTOM_RULES_TAGGING_OFFSET	0x0020
+#define SWIP_CUSTOM_RULES_TAGGING_ENABLE	BIT(0)
+
+#define SWIP_PORTS_BASE_OFFSET			0x3000
+#define SWIP_PORTS_SIZE				0x0014
+#define SWIP_PORTS_SELECTOR_OFFSET		0x0000
+#define SWIP_PORTS_SELECTOR_PORT_MASK		GENMASK(7, 0)
+#define SWIP_PORTS_CTRL_OFFSET			0x0004
+#define SWIP_PORTS_CTRL_INGR_EN			BIT(0)
+#define SWIP_PORTS_CTRL_EGR_EN			BIT(1)
+
+#define SWIP_STP_BASE_OFFSET			0x0f00
+#define SWIP_STP_SIZE				0x0040
+#define SWIP_STP_CTRL_OFFSET			0x0000
+#define SWIP_STP_CTRL_ENABLE			BIT(0)
+
+static void __iomem *swip_ioremap(struct device *dev,
+				  const struct resource *parent,
+				  resource_size_t offset, resource_size_t size,
+				  const char *name)
+{
+	struct resource res = {
+		.name = name,
+		.flags = IORESOURCE_MEM,
+	};
+
+	if (!size || offset >= resource_size(parent) ||
+	    size > resource_size(parent) - offset) {
+		dev_err(dev, "%s registers exceed parent resource\n", name);
+		return ERR_PTR(-EINVAL);
+	}
+
+	res.start = parent->start + offset;
+	res.end = res.start + size - 1;
+
+	return devm_ioremap_resource(dev, &res);
+}
+
+static int swip_identify(struct device *dev, void __iomem *base,
+			 struct swip_priv *priv)
+{
+	u32 implemented_ports;
+	u32 licensed_ports;
+	u32 regval;
+
+	regval = readl(base + SWIP_LIC_FEATURES_OFFSET);
+	licensed_ports = FIELD_GET(SWIP_LIC_FEATURES_NUM_PORTS_MASK, regval);
+	regval = readl(base + SWIP_IMPL_FEATURES0_OFFSET);
+	if (!(regval & SWIP_IMPL_FEATURES0_DSA))
+		return dev_err_probe(dev, -ENODEV,
+				     "core does not implement DSA\n");
+
+	implemented_ports =
+		FIELD_GET(SWIP_IMPL_FEATURES0_NUM_PORTS_MASK, regval);
+	if (!licensed_ports || licensed_ports > SWIP_MAX_NUM_PORTS ||
+	    implemented_ports < SWIP_MIN_NUM_PORTS ||
+	    implemented_ports > licensed_ports)
+		return dev_err_probe(dev, -EINVAL,
+				     "invalid port counts\n");
+
+	priv->features.num_ports = implemented_ports;
+	priv->features.stp = regval & SWIP_IMPL_FEATURES0_STP;
+
+	return 0;
+}
+
+static void swip_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_10 | MAC_100;
+		break;
+	default:
+		if (phy_interface_mode_is_rgmii(mode))
+			config->mac_capabilities |= MAC_10 | MAC_100 | MAC_1000;
+		break;
+	}
+}
+
+static void swip_enable_tagging(struct swip_dsa_local *local)
+{
+	void __iomem *base = local->dsa;
+	u32 regval;
+
+	/* Enabling "All Frames" tagging isolates user ports by forwarding
+	 * their complete ingress traffic only to the CPU port.
+	 */
+	regval = readl(base + SWIP_TAG_ALL_FRAMES_CTRL_OFFSET);
+	regval |= SWIP_TAG_ALL_FRAMES_CTRL_ENABLE;
+	writel(regval, base + SWIP_TAG_ALL_FRAMES_CTRL_OFFSET);
+
+	/* "All Frames" tagging needs the active custom tagging mechanism. */
+	regval = readl(base + SWIP_CUSTOM_RULES_TAGGING_OFFSET);
+	regval |= SWIP_CUSTOM_RULES_TAGGING_ENABLE;
+	writel(regval, base + SWIP_CUSTOM_RULES_TAGGING_OFFSET);
+}
+
+static void swip_disable_tagging(struct swip_dsa_local *local)
+{
+	void __iomem *base = local->dsa;
+	u32 regval;
+
+	regval = readl(base + SWIP_TAG_ALL_FRAMES_CTRL_OFFSET);
+	regval &= ~SWIP_TAG_ALL_FRAMES_CTRL_ENABLE;
+	writel(regval, base + SWIP_TAG_ALL_FRAMES_CTRL_OFFSET);
+
+	regval = readl(base + SWIP_CUSTOM_RULES_TAGGING_OFFSET);
+	regval &= ~SWIP_CUSTOM_RULES_TAGGING_ENABLE;
+	writel(regval, base + SWIP_CUSTOM_RULES_TAGGING_OFFSET);
+}
+
+static void swip_stp_disable(struct swip_dsa_local *local)
+{
+	void __iomem *base = local->stp;
+	u32 regval;
+
+	regval = readl(base + SWIP_STP_CTRL_OFFSET);
+	regval &= ~SWIP_STP_CTRL_ENABLE;
+	writel(regval, base + SWIP_STP_CTRL_OFFSET);
+}
+
+static void swip_port_select(struct swip_dsa_local *local, int port)
+{
+	writel(FIELD_PREP(SWIP_PORTS_SELECTOR_PORT_MASK, port),
+	       local->ports + SWIP_PORTS_SELECTOR_OFFSET);
+}
+
+static void swip_port_set_enabled(struct swip_dsa_local *local, int port,
+				  bool enabled)
+{
+	void __iomem *base = local->ports;
+	u32 regval;
+
+	swip_port_select(local, port);
+
+	regval = readl(base + SWIP_PORTS_CTRL_OFFSET);
+	if (enabled)
+		regval |= SWIP_PORTS_CTRL_INGR_EN | SWIP_PORTS_CTRL_EGR_EN;
+	else
+		regval &= ~(SWIP_PORTS_CTRL_INGR_EN | SWIP_PORTS_CTRL_EGR_EN);
+	writel(regval, base + SWIP_PORTS_CTRL_OFFSET);
+}
+
+static int swip_port_enable(struct dsa_switch *ds, int port,
+			    struct phy_device *phy)
+{
+	struct swip_priv *priv = ds->priv;
+
+	swip_port_set_enabled(&priv->local, port, true);
+
+	return 0;
+}
+
+static void swip_port_disable(struct dsa_switch *ds, int port)
+{
+	struct swip_priv *priv = ds->priv;
+
+	swip_port_set_enabled(&priv->local, port, false);
+}
+
+static int swip_setup(struct dsa_switch *ds)
+{
+	struct swip_priv *priv = ds->priv;
+	struct dsa_port *dp;
+
+	dsa_switch_for_each_user_port(dp, ds)
+		swip_port_set_enabled(&priv->local, dp->index, false);
+
+	/* Unconfigured hardware STP blocks frame forwarding. */
+	if (priv->features.stp)
+		swip_stp_disable(&priv->local);
+
+	swip_enable_tagging(&priv->local);
+
+	return 0;
+}
+
+static void swip_teardown(struct dsa_switch *ds)
+{
+	struct swip_priv *priv = ds->priv;
+	struct swip_dsa_local *local;
+
+	local = &priv->local;
+
+	swip_disable_tagging(local);
+}
+
+static enum dsa_tag_protocol swip_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 swip_switch_ops = {
+	.get_tag_protocol	= swip_get_tag_protocol,
+	.setup			= swip_setup,
+	.teardown		= swip_teardown,
+	.phylink_get_caps	= swip_phylink_get_caps,
+	.port_enable		= swip_port_enable,
+	.port_disable		= swip_port_disable,
+};
+
+static int swip_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct platform_device *parent;
+	struct swip_dsa_local *local;
+	struct swip_priv *priv;
+	struct dsa_switch *ds;
+	struct resource *res;
+	void __iomem *base;
+	int ret;
+
+	parent = to_platform_device(dev->parent);
+	res = platform_get_resource(parent, IORESOURCE_MEM, 0);
+	if (!res)
+		return -EINVAL;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	ds = &priv->ds;
+	ds->dev = dev;
+	ds->priv = priv;
+
+	base = swip_ioremap(dev, res, SWIP_IDENT_BASE_OFFSET,
+			    SWIP_IDENT_SIZE, "ident");
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+	ret = swip_identify(dev, base, priv);
+	if (ret)
+		return ret;
+
+	local = &priv->local;
+	local->dsa = swip_ioremap(dev, res, SWIP_DSA_BASE_OFFSET,
+				  SWIP_DSA_SIZE, "dsa");
+	if (IS_ERR(local->dsa))
+		return PTR_ERR(local->dsa);
+	local->ports = swip_ioremap(dev, res, SWIP_PORTS_BASE_OFFSET,
+				    SWIP_PORTS_SIZE, "ports");
+	if (IS_ERR(local->ports))
+		return PTR_ERR(local->ports);
+	if (priv->features.stp) {
+		local->stp = swip_ioremap(dev, res, SWIP_STP_BASE_OFFSET,
+					  SWIP_STP_SIZE, "stp");
+		if (IS_ERR(local->stp))
+			return PTR_ERR(local->stp);
+	}
+
+	ds->ops = &swip_switch_ops;
+	ds->num_ports = priv->features.num_ports;
+
+	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 SoC-e switch with %u ports\n",
+		 priv->features.num_ports);
+
+	return 0;
+}
+
+static void swip_remove(struct platform_device *pdev)
+{
+	struct swip_priv *priv = platform_get_drvdata(pdev);
+
+	if (!priv)
+		return;
+
+	dsa_unregister_switch(&priv->ds);
+	platform_set_drvdata(pdev, NULL);
+}
+
+static void swip_shutdown(struct platform_device *pdev)
+{
+	struct swip_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 swip_of_match[] = {
+	{ .compatible = "soce,swip-switch-00-04-0c-10" },
+	{ /* sentinel */ }
+};
+
+static struct platform_driver swip_driver = {
+	.probe = swip_probe,
+	.remove = swip_remove,
+	.shutdown = swip_shutdown,
+	.driver = {
+		.name = "soce-switch",
+		.of_match_table = swip_of_match,
+	},
+};
+
+module_platform_driver(swip_driver);
+MODULE_DEVICE_TABLE(of, swip_of_match);
+MODULE_AUTHOR("Vasilij Strassheim <v.strassheim@linutronix.de>");
+MODULE_DESCRIPTION("SoC-e SWIP DSA switch driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/dsa/soce-swip.h b/drivers/net/dsa/soce-swip.h
new file mode 100644
index 000000000000..d3a523ad6694
--- /dev/null
+++ b/drivers/net/dsa/soce-swip.h
@@ -0,0 +1,35 @@
+/* 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_SWIP_H
+#define SOCE_SWIP_H
+
+#include <linux/mutex.h>
+#include <linux/types.h>
+
+#include <net/dsa.h>
+
+#define SWIP_MAX_NUM_PORTS 31
+
+struct swip_features {
+	u32 num_ports;
+	bool stp;
+};
+
+struct swip_dsa_local {
+	void __iomem *dsa;
+	void __iomem *ports;
+	void __iomem *stp;
+};
+
+struct swip_priv {
+	struct swip_dsa_local local;
+	struct swip_features features;
+	struct dsa_switch ds;
+};
+
+#endif /* SOCE_SWIP_H */

-- 
2.39.5


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

* [PATCH net-next v4 8/8] net: dsa: soce: Add VLAN membership table support
  2026-11-05 14:16 [PATCH net-next v4 0/8] net: dsa: Add support for SoC-e Ethernet switch IP cores Vasilij Strassheim
                   ` (6 preceding siblings ...)
  2026-11-05 14:16 ` [PATCH net-next v4 7/8] net: dsa: soce: Add basic support for SoC-e switch IP cores Vasilij Strassheim
@ 2026-11-05 14:16 ` Vasilij Strassheim
  7 siblings, 0 replies; 13+ messages in thread
From: Vasilij Strassheim @ 2026-11-05 14:16 UTC (permalink / raw)
  To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Andrew Lunn,
	Vladimir Oltean, David S. Miller, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Russell King, Andrew Lunn, Heiner Kallweit,
	Eric Dumazet, Lee Jones, Eric Dumazet
  Cc: Vasilij Strassheim, devicetree, linux-kernel, netdev, mfd,
	Martin Kaistra, Benedikt Spranger

Program VLAN membership tables on switch cores that implement the Port
VLAN synthesis option.

Initialize VLAN-capable cores in VLAN-unaware mode with PVID 1 and
standalone VLAN 1 membership. For VLAN add and delete operations, update
per-VID membership masks and include CPU ports in active entries.
Preserve standalone VLAN 1 membership when explicit membership is
removed, and let explicit membership override default untagging.

Keep ingress filtering disabled. Bridge VLAN filtering is not offloaded.

Without Port VLAN synthesis, VLAN information is lost when frames enter
the switch through the CPU port and is not preserved in the SDSA header.
Reject direct VLAN uppers on such cores and warn that VLAN-aware
bridging is unsupported. Plain software bridge port joins remain
allowed.

Serialize multi-register VLAN operations with a per-switch feature
mutex. Clear the membership shadow after a successful hardware reset
during setup. On programming failure, restore the software shadow and
attempt a best-effort restore of the previous hardware entry. Log
rollback failures and return the original error.

Signed-off-by: Vasilij Strassheim <v.strassheim@linutronix.de>
---
 drivers/net/dsa/soce-swip.c | 348 ++++++++++++++++++++++++++++++++++++++++++++
 drivers/net/dsa/soce-swip.h |   4 +
 2 files changed, 352 insertions(+)

diff --git a/drivers/net/dsa/soce-swip.c b/drivers/net/dsa/soce-swip.c
index 70fc2da91dd2..7cc3f4abc691 100644
--- a/drivers/net/dsa/soce-swip.c
+++ b/drivers/net/dsa/soce-swip.c
@@ -28,6 +28,7 @@
 #define SWIP_LIC_FEATURES_NUM_PORTS_MASK	GENMASK(31, 27)
 #define SWIP_IMPL_FEATURES0_OFFSET		0x000c
 #define SWIP_IMPL_FEATURES0_NUM_PORTS_MASK	GENMASK(31, 27)
+#define SWIP_IMPL_FEATURES0_PORT_VLAN		BIT(9)
 #define SWIP_IMPL_FEATURES0_STP			BIT(20)
 #define SWIP_IMPL_FEATURES0_DSA			BIT(23)
 #define SWIP_MIN_NUM_PORTS			3
@@ -52,6 +53,37 @@
 #define SWIP_STP_CTRL_OFFSET			0x0000
 #define SWIP_STP_CTRL_ENABLE			BIT(0)
 
+#define SWIP_VLAN_BASE_OFFSET			0x0d00
+#define SWIP_VLAN_SIZE				0x0044
+#define SWIP_VLAN_CTRL_OFFSET			0x0000
+#define SWIP_VLAN_CTRL_ENABLE			BIT(0)
+#define SWIP_VLAN_RESET_OFFSET			0x0004
+#define SWIP_VLAN_RESET_CMD			BIT(0)
+#define SWIP_VLAN_PORT_SEL_OFFSET		0x0010
+#define SWIP_VLAN_PORT_SEL_PORT_MASK		GENMASK(7, 0)
+#define SWIP_VLAN_PORT_MODE_OFFSET		0x0014
+#define SWIP_VLAN_PORT_MODE_HYBRID		0x2
+#define SWIP_VLAN_PORT_TYPE_OFFSET		0x0018
+#define SWIP_VLAN_PORT_TYPE_UNAWARE		0x0
+#define SWIP_VLAN_PORT_VLAN_OFFSET		0x001c
+#define SWIP_VLAN_PORT_VLAN_PVID_MASK		GENMASK(11, 0)
+#define SWIP_VLAN_PORT_INGR_FILTER_OFFSET	0x0020
+#define SWIP_VLAN_PORT_INGR_ACCEPT_OFFSET	0x0024
+#define SWIP_VLAN_PORT_INGR_ACCEPT_ALL		0x0
+#define SWIP_VLAN_PORT_EGR_TAG_OFFSET		0x0028
+#define SWIP_VLAN_PORT_EGR_TAG_MASK		GENMASK(1, 0)
+#define SWIP_VLAN_PORT_EGR_TAG_UNTAG_PORT	0x0
+#define SWIP_VLAN_VID_SEL_OFFSET		0x002c
+#define SWIP_VLAN_VID_SEL_VID_MASK		GENMASK(11, 0)
+#define SWIP_VLAN_MEMBER_CTRL_OFFSET		0x0030
+#define SWIP_VLAN_MEMBER_CTRL_WRITE		BIT(0)
+#define SWIP_VLAN_MEMBER_PORTS_OFFSET		0x0034
+#define SWIP_VLAN_UNTAG_CTRL_OFFSET		0x003c
+#define SWIP_VLAN_UNTAG_CTRL_WRITE		BIT(0)
+#define SWIP_VLAN_UNTAG_PORTS_OFFSET		0x0040
+#define SWIP_VLAN_CMD_TIMEOUT_US		1000
+#define SWIP_STANDALONE_PVID			1
+
 static void __iomem *swip_ioremap(struct device *dev,
 				  const struct resource *parent,
 				  resource_size_t offset, resource_size_t size,
@@ -97,6 +129,7 @@ static int swip_identify(struct device *dev, void __iomem *base,
 				     "invalid port counts\n");
 
 	priv->features.num_ports = implemented_ports;
+	priv->features.port_vlan = regval & SWIP_IMPL_FEATURES0_PORT_VLAN;
 	priv->features.stp = regval & SWIP_IMPL_FEATURES0_STP;
 
 	return 0;
@@ -179,6 +212,185 @@ static void swip_stp_disable(struct swip_dsa_local *local)
 	writel(regval, base + SWIP_STP_CTRL_OFFSET);
 }
 
+static void swip_vlan_set_enabled(struct swip_dsa_local *local, bool enabled)
+{
+	void __iomem *base = local->vlan;
+	u32 regval;
+
+	regval = readl(base + SWIP_VLAN_CTRL_OFFSET);
+	if (enabled)
+		regval |= SWIP_VLAN_CTRL_ENABLE;
+	else
+		regval &= ~SWIP_VLAN_CTRL_ENABLE;
+	writel(regval, base + SWIP_VLAN_CTRL_OFFSET);
+}
+
+static int swip_vlan_reset(struct swip_dsa_local *local)
+{
+	void __iomem *base = local->vlan;
+	u32 regval;
+
+	writel(SWIP_VLAN_RESET_CMD, base + SWIP_VLAN_RESET_OFFSET);
+
+	return readl_poll_timeout(base + SWIP_VLAN_RESET_OFFSET,
+				  regval, !(regval & SWIP_VLAN_RESET_CMD), 10,
+				  SWIP_VLAN_CMD_TIMEOUT_US);
+}
+
+static int swip_vlan_wait_for_write(struct swip_dsa_local *local, u32 offset,
+				    u32 mask)
+{
+	void __iomem *base = local->vlan;
+	u32 regval;
+
+	return readl_poll_timeout(base + offset, regval,
+				  !(regval & mask), 10,
+				  SWIP_VLAN_CMD_TIMEOUT_US);
+}
+
+static void swip_vlan_select_port(struct swip_dsa_local *local, int port)
+{
+	writel(FIELD_PREP(SWIP_VLAN_PORT_SEL_PORT_MASK, port),
+	       local->vlan + SWIP_VLAN_PORT_SEL_OFFSET);
+}
+
+static void swip_vlan_select_vid(struct swip_dsa_local *local, u16 vid)
+{
+	writel(FIELD_PREP(SWIP_VLAN_VID_SEL_VID_MASK, vid),
+	       local->vlan + SWIP_VLAN_VID_SEL_OFFSET);
+}
+
+static void swip_vlan_config_port(struct swip_priv *priv, int port)
+{
+	struct swip_dsa_local *local = &priv->local;
+	void __iomem *base = local->vlan;
+	u32 regval;
+
+	swip_vlan_select_port(local, port);
+	writel(SWIP_VLAN_PORT_MODE_HYBRID, base + SWIP_VLAN_PORT_MODE_OFFSET);
+	writel(SWIP_VLAN_PORT_TYPE_UNAWARE, base + SWIP_VLAN_PORT_TYPE_OFFSET);
+	writel(FIELD_PREP(SWIP_VLAN_PORT_VLAN_PVID_MASK,
+			  SWIP_STANDALONE_PVID),
+	       base + SWIP_VLAN_PORT_VLAN_OFFSET);
+	writel(0, base + SWIP_VLAN_PORT_INGR_FILTER_OFFSET);
+	writel(SWIP_VLAN_PORT_INGR_ACCEPT_ALL,
+	       base + SWIP_VLAN_PORT_INGR_ACCEPT_OFFSET);
+
+	regval = readl(base + SWIP_VLAN_PORT_EGR_TAG_OFFSET);
+	regval &= ~SWIP_VLAN_PORT_EGR_TAG_MASK;
+	regval |= FIELD_PREP(SWIP_VLAN_PORT_EGR_TAG_MASK,
+			     SWIP_VLAN_PORT_EGR_TAG_UNTAG_PORT);
+	writel(regval, base + SWIP_VLAN_PORT_EGR_TAG_OFFSET);
+}
+
+static int swip_vlan_write_entry(struct swip_priv *priv, u16 vid)
+{
+	struct swip_dsa_local *local = &priv->local;
+	void __iomem *base = local->vlan;
+	struct dsa_port *dp;
+	u32 standalone = 0;
+	u32 cpu_ports;
+	u32 untagged;
+	u32 members;
+	int ret;
+
+	cpu_ports = dsa_cpu_ports(&priv->ds);
+	/* Bridge VLAN deletion must not remove standalone membership. */
+	if (vid == SWIP_STANDALONE_PVID) {
+		dsa_switch_for_each_user_port(dp, &priv->ds) {
+			if (!dsa_port_bridge_dev_get(dp))
+				standalone |= BIT(dp->index);
+		}
+	}
+	members = priv->vlan_members[vid] | standalone;
+	/* CPU membership preserves VLAN delivery to the conduit. */
+	if (members)
+		members |= cpu_ports;
+	/* Explicit VLAN configuration takes precedence over default untagging. */
+	untagged = standalone & ~priv->vlan_members[vid] & ~cpu_ports;
+
+	/* A timed-out command may still be using the shared VID selector. */
+	ret = swip_vlan_wait_for_write(local, SWIP_VLAN_MEMBER_CTRL_OFFSET,
+				       SWIP_VLAN_MEMBER_CTRL_WRITE);
+	if (ret)
+		return ret;
+	ret = swip_vlan_wait_for_write(local, SWIP_VLAN_UNTAG_CTRL_OFFSET,
+				       SWIP_VLAN_UNTAG_CTRL_WRITE);
+	if (ret)
+		return ret;
+
+	swip_vlan_select_vid(local, vid);
+	writel(members, base + SWIP_VLAN_MEMBER_PORTS_OFFSET);
+	writel(SWIP_VLAN_MEMBER_CTRL_WRITE,
+	       base + SWIP_VLAN_MEMBER_CTRL_OFFSET);
+	ret = swip_vlan_wait_for_write(local, SWIP_VLAN_MEMBER_CTRL_OFFSET,
+				       SWIP_VLAN_MEMBER_CTRL_WRITE);
+	if (ret)
+		return ret;
+
+	writel(untagged, base + SWIP_VLAN_UNTAG_PORTS_OFFSET);
+	writel(SWIP_VLAN_UNTAG_CTRL_WRITE,
+	       base + SWIP_VLAN_UNTAG_CTRL_OFFSET);
+
+	return swip_vlan_wait_for_write(local, SWIP_VLAN_UNTAG_CTRL_OFFSET,
+					SWIP_VLAN_UNTAG_CTRL_WRITE);
+}
+
+static int swip_vlan_setup(struct dsa_switch *ds)
+{
+	struct swip_priv *priv = ds->priv;
+	struct swip_dsa_local *local;
+	struct dsa_port *dp;
+	int ret;
+
+	local = &priv->local;
+
+	if (!priv->features.port_vlan)
+		return 0;
+
+	ret = swip_vlan_reset(local);
+	if (ret) {
+		dev_err(ds->dev, "failed to reset VLAN configuration: %d\n",
+			ret);
+		return ret;
+	}
+
+	memset(priv->vlan_members, 0,
+	       sizeof(*priv->vlan_members) * VLAN_N_VID);
+
+	ret = swip_vlan_write_entry(priv, SWIP_STANDALONE_PVID);
+	if (ret) {
+		dev_err(ds->dev, "failed to set up standalone VLAN: %d\n",
+			ret);
+		return ret;
+	}
+
+	dsa_switch_for_each_available_port(dp, ds)
+		swip_vlan_config_port(priv, dp->index);
+
+	swip_vlan_set_enabled(local, true);
+
+	return 0;
+}
+
+static void swip_vlan_teardown(struct swip_priv *priv)
+{
+	struct swip_dsa_local *local = &priv->local;
+	int ret;
+
+	if (!priv->features.port_vlan)
+		return;
+
+	scoped_guard(mutex, &priv->feature_lock) {
+		ret = swip_vlan_reset(local);
+		if (ret)
+			dev_warn(priv->ds.dev,
+				 "failed to reset VLAN configuration during teardown: %d\n",
+				 ret);
+		swip_vlan_set_enabled(local, false);
+	}
+}
+
 static void swip_port_select(struct swip_dsa_local *local, int port)
 {
 	writel(FIELD_PREP(SWIP_PORTS_SELECTOR_PORT_MASK, port),
@@ -222,10 +434,15 @@ static int swip_setup(struct dsa_switch *ds)
 {
 	struct swip_priv *priv = ds->priv;
 	struct dsa_port *dp;
+	int ret;
 
 	dsa_switch_for_each_user_port(dp, ds)
 		swip_port_set_enabled(&priv->local, dp->index, false);
 
+	ret = swip_vlan_setup(ds);
+	if (ret)
+		return ret;
+
 	/* Unconfigured hardware STP blocks frame forwarding. */
 	if (priv->features.stp)
 		swip_stp_disable(&priv->local);
@@ -243,6 +460,7 @@ static void swip_teardown(struct dsa_switch *ds)
 	local = &priv->local;
 
 	swip_disable_tagging(local);
+	swip_vlan_teardown(priv);
 }
 
 static enum dsa_tag_protocol swip_get_tag_protocol(struct dsa_switch *ds,
@@ -252,6 +470,111 @@ static enum dsa_tag_protocol swip_get_tag_protocol(struct dsa_switch *ds,
 	return DSA_TAG_PROTO_SDSA;
 }
 
+static int swip_port_vlan_add(struct dsa_switch *ds, int port,
+			      const struct switchdev_obj_port_vlan *vlan,
+			      struct netlink_ext_ack *extack)
+{
+	struct swip_priv *priv = ds->priv;
+	u32 port_mask = BIT(port);
+	int rollback_ret;
+	u32 old_members;
+	u32 *members;
+	int ret;
+
+	members = priv->vlan_members;
+
+	if (!vlan->vid)
+		return 0;
+
+	if (!priv->features.port_vlan) {
+		NL_SET_ERR_MSG_MOD(extack,
+				   "Port VLAN support is not implemented in the switch core");
+		return -EINVAL;
+	}
+
+	scoped_guard(mutex, &priv->feature_lock) {
+		old_members = members[vlan->vid];
+
+		members[vlan->vid] |= port_mask;
+
+		ret = swip_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;
+			/* Best-effort: restore the previous hardware entry. */
+			rollback_ret = swip_vlan_write_entry(priv, vlan->vid);
+			if (rollback_ret)
+				dev_err(ds->dev,
+					"failed to restore VLAN %u on port %d: %d\n",
+					vlan->vid, port, rollback_ret);
+			return ret;
+		}
+	}
+
+	return ret;
+}
+
+static int swip_port_vlan_del(struct dsa_switch *ds, int port,
+			      const struct switchdev_obj_port_vlan *vlan)
+{
+	struct swip_priv *priv = ds->priv;
+	u32 port_mask = BIT(port);
+	int rollback_ret;
+	u32 old_members;
+	u32 *members;
+	int ret;
+
+	members = priv->vlan_members;
+
+	if (!vlan->vid)
+		return 0;
+
+	if (!priv->features.port_vlan)
+		return -EOPNOTSUPP;
+
+	scoped_guard(mutex, &priv->feature_lock) {
+		old_members = members[vlan->vid];
+		members[vlan->vid] &= ~port_mask;
+		ret = swip_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;
+			/* Best-effort: restore the previous hardware entry. */
+			rollback_ret = swip_vlan_write_entry(priv, vlan->vid);
+			if (rollback_ret)
+				dev_err(ds->dev,
+					"failed to restore VLAN %u on port %d: %d\n",
+					vlan->vid, port, rollback_ret);
+			return ret;
+		}
+	}
+
+	return ret;
+}
+
+static int
+swip_port_prechangeupper(struct dsa_switch *ds, int port,
+			 struct netdev_notifier_changeupper_info *info)
+{
+	struct swip_priv *priv = ds->priv;
+	struct netlink_ext_ack *extack;
+
+	if (!info->linking || !is_vlan_dev(info->upper_dev) ||
+	    priv->features.port_vlan)
+		return 0;
+
+	extack = netdev_notifier_info_to_extack(&info->info);
+	NL_SET_ERR_MSG_MOD(extack,
+			   "VLAN uppers require Port VLAN support in the switch core");
+	return -EOPNOTSUPP;
+}
+
 static const struct dsa_switch_ops swip_switch_ops = {
 	.get_tag_protocol	= swip_get_tag_protocol,
 	.setup			= swip_setup,
@@ -259,6 +582,9 @@ static const struct dsa_switch_ops swip_switch_ops = {
 	.phylink_get_caps	= swip_phylink_get_caps,
 	.port_enable		= swip_port_enable,
 	.port_disable		= swip_port_disable,
+	.port_vlan_add		= swip_port_vlan_add,
+	.port_vlan_del		= swip_port_vlan_del,
+	.port_prechangeupper	= swip_port_prechangeupper,
 };
 
 static int swip_probe(struct platform_device *pdev)
@@ -308,10 +634,32 @@ static int swip_probe(struct platform_device *pdev)
 		if (IS_ERR(local->stp))
 			return PTR_ERR(local->stp);
 	}
+	ret = devm_mutex_init(dev, &priv->feature_lock);
+	if (ret)
+		return ret;
+
+	if (priv->features.port_vlan) {
+		local->vlan = swip_ioremap(dev, res, SWIP_VLAN_BASE_OFFSET,
+					   SWIP_VLAN_SIZE, "vlan");
+		if (IS_ERR(local->vlan))
+			return PTR_ERR(local->vlan);
+
+		priv->vlan_members =
+			devm_kcalloc(dev, VLAN_N_VID,
+				     sizeof(*priv->vlan_members), GFP_KERNEL);
+		if (!priv->vlan_members)
+			return -ENOMEM;
+
+	} else {
+		dev_warn(dev,
+			 "No Port VLAN: tagged CPU ingress loses VLAN IDs. VLAN-aware bridge unsupported\n");
+	}
 
 	ds->ops = &swip_switch_ops;
 	ds->num_ports = priv->features.num_ports;
 
+	ds->needs_standalone_vlan_filtering = priv->features.port_vlan;
+
 	dev_set_drvdata(dev, priv);
 
 	ret = dsa_register_switch(ds);
diff --git a/drivers/net/dsa/soce-swip.h b/drivers/net/dsa/soce-swip.h
index d3a523ad6694..034a05ce8dc5 100644
--- a/drivers/net/dsa/soce-swip.h
+++ b/drivers/net/dsa/soce-swip.h
@@ -17,18 +17,22 @@
 
 struct swip_features {
 	u32 num_ports;
+	bool port_vlan;
 	bool stp;
 };
 
 struct swip_dsa_local {
 	void __iomem *dsa;
 	void __iomem *ports;
+	void __iomem *vlan;
 	void __iomem *stp;
 };
 
 struct swip_priv {
 	struct swip_dsa_local local;
 	struct swip_features features;
+	struct mutex feature_lock; /* Serializes multi-register feature updates */
+	u32 *vlan_members;
 	struct dsa_switch ds;
 };
 

-- 
2.39.5


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

* Re: [PATCH net-next v4 4/8] dt-bindings: mfd: Add SoC-e SWIP parent
  2026-11-05 14:16 ` [PATCH net-next v4 4/8] dt-bindings: mfd: Add SoC-e SWIP parent Vasilij Strassheim
@ 2026-11-06 11:13   ` Krzysztof Kozlowski
  2026-11-06 21:51     ` Vasilij Strassheim
  0 siblings, 1 reply; 13+ messages in thread
From: Krzysztof Kozlowski @ 2026-11-06 11:13 UTC (permalink / raw)
  To: Vasilij Strassheim
  Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Andrew Lunn,
	Vladimir Oltean, David S. Miller, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Russell King, Andrew Lunn, Heiner Kallweit,
	Eric Dumazet, Lee Jones, devicetree, linux-kernel, netdev, mfd,
	Martin Kaistra, Benedikt Spranger

On Thu, Nov 05, 2026 at 03:16:48PM +0100, Vasilij Strassheim wrote:
> Add a binding for the SoC-e SWIP multifunction FPGA IP core.
> 
> Describe the shared MMIO address space and address translation for
> the required Ethernet switch child and the optional integrated MDIO
> controller and MMIO-controlled MDIO multiplexer.
> 
> Signed-off-by: Vasilij Strassheim <v.strassheim@linutronix.de>
> ---
>  .../devicetree/bindings/mfd/soce,swip.yaml         | 137 +++++++++++++++++++++
>  1 file changed, 137 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/mfd/soce,swip.yaml b/Documentation/devicetree/bindings/mfd/soce,swip.yaml
> new file mode 100644
> index 000000000000..625be299e262
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mfd/soce,swip.yaml
> @@ -0,0 +1,137 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/mfd/soce,swip.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: SoC-e SWIP multifunction Ethernet switch FPGA IP core
> +
> +maintainers:
> +  - Vasilij Strassheim <v.strassheim@linutronix.de>
> +
> +description:
> +  SoC-e Switch IP (SWIP) cores integrate Ethernet switching logic, an
> +  MDIO controller, and an MDIO bus multiplexer in one memory-mapped device.
> +  The MDIO bus multiplexer is wired to the integrated MDIO controller.
> +
> +properties:
> +  compatible:
> +    const: soce,swip
> +
> +  reg:
> +    maxItems: 1
> +
> +  '#address-cells':
> +    const: 1
> +
> +  '#size-cells':
> +    const: 1
> +
> +  ranges: true
> +
> +  mdio@204:
> +    $ref: /schemas/net/soce,swip-mdio.yaml#
> +    unevaluatedProperties: false
> +
> +  mdio-mux@202:
> +    $ref: /schemas/net/mdio-mux-mmioreg.yaml#
> +    unevaluatedProperties: false
> +
> +  ethernet-switch:

Why are you mixing children with and without bus addresses? This is
discouraged and shows that device is not correctly represented, e.g. if
the ethernet-switch does not have resources, then THIS device is the
ethernet switch.

> +    $ref: /schemas/net/dsa/soce,swip-switch.yaml#
> +    unevaluatedProperties: false
> +
> +required:
> +  - compatible
> +  - reg
> +  - '#address-cells'
> +  - '#size-cells'
> +  - ranges
> +  - ethernet-switch
> +
> +dependentRequired:
> +  mdio-mux@202:
> +    - mdio@204
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    ethernet-switch@80020000 {
> +        compatible = "soce,swip";
> +        reg = <0x80020000 0x10000>;
> +        #address-cells = <1>;
> +        #size-cells = <1>;
> +        ranges = <0x0 0x80020000 0x10000>;
> +
> +        mdio_parent: mdio@204 {
> +            compatible = "soce,swip-mdio";
> +            reg = <0x204 0xc>, <0x200 0x2>;
> +            reg-names = "data", "control";
> +            #address-cells = <1>;
> +            #size-cells = <0>;
> +        };
> +
> +        mdio-mux@202 {

Nodes are ordered by unit address.

Best regards,
Krzysztof


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

* Re: [PATCH net-next v4 4/8] dt-bindings: mfd: Add SoC-e SWIP parent
  2026-11-06 11:13   ` Krzysztof Kozlowski
@ 2026-11-06 21:51     ` Vasilij Strassheim
  2026-11-10 16:10       ` Vasilij Strassheim
  0 siblings, 1 reply; 13+ messages in thread
From: Vasilij Strassheim @ 2026-11-06 21:51 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Andrew Lunn,
	Vladimir Oltean, David S. Miller, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Russell King, Andrew Lunn, Heiner Kallweit,
	Eric Dumazet, Lee Jones, devicetree, linux-kernel, netdev, mfd,
	Martin Kaistra, Benedikt Spranger

On Fri, 2026-11-06 at 12:13 +0100, Krzysztof Kozlowski wrote:
> On Thu, Nov 05, 2026 at 03:16:48PM +0100, Vasilij Strassheim wrote:
> > Add a binding for the SoC-e SWIP multifunction FPGA IP core.
> > 
> > Describe the shared MMIO address space and address translation for
> > the required Ethernet switch child and the optional integrated MDIO
> > controller and MMIO-controlled MDIO multiplexer.
> > 
> > Signed-off-by: Vasilij Strassheim <v.strassheim@linutronix.de>
> > ---
> >  .../devicetree/bindings/mfd/soce,swip.yaml         | 137 +++++++++++++++++++++
> >  1 file changed, 137 insertions(+)
> > 
> > diff --git a/Documentation/devicetree/bindings/mfd/soce,swip.yaml b/Documentation/devicetree/bindings/mfd/soce,swip.yaml
> > new file mode 100644
> > index 000000000000..625be299e262
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/mfd/soce,swip.yaml
> > @@ -0,0 +1,137 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > +%YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/mfd/soce,swip.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: SoC-e SWIP multifunction Ethernet switch FPGA IP core
> > +
> > +maintainers:
> > +  - Vasilij Strassheim <v.strassheim@linutronix.de>
> > +
> > +description:
> > +  SoC-e Switch IP (SWIP) cores integrate Ethernet switching logic, an
> > +  MDIO controller, and an MDIO bus multiplexer in one memory-mapped device.
> > +  The MDIO bus multiplexer is wired to the integrated MDIO controller.
> > +
> > +properties:
> > +  compatible:
> > +    const: soce,swip
> > +
> > +  reg:
> > +    maxItems: 1
> > +
> > +  '#address-cells':
> > +    const: 1
> > +
> > +  '#size-cells':
> > +    const: 1
> > +
> > +  ranges: true
> > +
> > +  mdio@204:
> > +    $ref: /schemas/net/soce,swip-mdio.yaml#
> > +    unevaluatedProperties: false
> > +
> > +  mdio-mux@202:
> > +    $ref: /schemas/net/mdio-mux-mmioreg.yaml#
> > +    unevaluatedProperties: false
> > +
> > +  ethernet-switch:
> 
> Why are you mixing children with and without bus addresses? This is
> discouraged and shows that device is not correctly represented, e.g. if
> the ethernet-switch does not have resources, then THIS device is the
> ethernet switch.
> 

There is no hardware reason for leaving the switch child unaddressed.
Just an error that occurred while converting the binding to the MFD
model.
I will describe the switch function as an ethernet-switch@0 child node
with a reg property for it's register resources, like the ocelot MFD
binding.

> > +    $ref: /schemas/net/dsa/soce,swip-switch.yaml#
> > +    unevaluatedProperties: false
> > +
> > +required:
> > +  - compatible
> > +  - reg
> > +  - '#address-cells'
> > +  - '#size-cells'
> > +  - ranges
> > +  - ethernet-switch
> > +
> > +dependentRequired:
> > +  mdio-mux@202:
> > +    - mdio@204
> > +
> > +additionalProperties: false
> > +
> > +examples:
> > +  - |
> > +    ethernet-switch@80020000 {
> > +        compatible = "soce,swip";
> > +        reg = <0x80020000 0x10000>;
> > +        #address-cells = <1>;
> > +        #size-cells = <1>;
> > +        ranges = <0x0 0x80020000 0x10000>;
> > +
> > +        mdio_parent: mdio@204 {
> > +            compatible = "soce,swip-mdio";
> > +            reg = <0x204 0xc>, <0x200 0x2>;
> > +            reg-names = "data", "control";
> > +            #address-cells = <1>;
> > +            #size-cells = <0>;
> > +        };
> > +
> > +        mdio-mux@202 {
> 
> Nodes are ordered by unit address.

I will fix that.
Sashiko mentioned scripts/dtc/dt-check-style to find this. I wasn't
aware of this before and will use it more often in the future
additionally to dt_binding_check.

> 
> Best regards,
> Krzysztof
> 

Thanks,
Vasilij


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

* Re: [PATCH net-next v4 4/8] dt-bindings: mfd: Add SoC-e SWIP parent
  2026-11-06 21:51     ` Vasilij Strassheim
@ 2026-11-10 16:10       ` Vasilij Strassheim
  2026-11-10 19:21         ` Rob Herring
  0 siblings, 1 reply; 13+ messages in thread
From: Vasilij Strassheim @ 2026-11-10 16:10 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Andrew Lunn,
	Vladimir Oltean, David S. Miller, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Russell King, Andrew Lunn, Heiner Kallweit,
	Eric Dumazet, Lee Jones, devicetree, linux-kernel, netdev, mfd,
	Martin Kaistra, Benedikt Spranger

On Fri, 2026-11-06 at 22:51 +0100, Vasilij Strassheim wrote:
> On Fri, 2026-11-06 at 12:13 +0100, Krzysztof Kozlowski wrote:
> > On Thu, Nov 05, 2026 at 03:16:48PM +0100, Vasilij Strassheim wrote:
> > > Add a binding for the SoC-e SWIP multifunction FPGA IP core.
> > > 
> > > Describe the shared MMIO address space and address translation for
> > > the required Ethernet switch child and the optional integrated MDIO
> > > controller and MMIO-controlled MDIO multiplexer.
> > > 
> > > Signed-off-by: Vasilij Strassheim <v.strassheim@linutronix.de>
> > > ---
> > >  .../devicetree/bindings/mfd/soce,swip.yaml         | 137 +++++++++++++++++++++
> > >  1 file changed, 137 insertions(+)
> > > 
> > > diff --git a/Documentation/devicetree/bindings/mfd/soce,swip.yaml b/Documentation/devicetree/bindings/mfd/soce,swip.yaml
> > > new file mode 100644
> > > index 000000000000..625be299e262
> > > --- /dev/null
> > > +++ b/Documentation/devicetree/bindings/mfd/soce,swip.yaml
> > > @@ -0,0 +1,137 @@
> > > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > > +%YAML 1.2
> > > +---
> > > +$id: http://devicetree.org/schemas/mfd/soce,swip.yaml#
> > > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > > +
> > > +title: SoC-e SWIP multifunction Ethernet switch FPGA IP core
> > > +
> > > +maintainers:
> > > +  - Vasilij Strassheim <v.strassheim@linutronix.de>
> > > +
> > > +description:
> > > +  SoC-e Switch IP (SWIP) cores integrate Ethernet switching logic, an
> > > +  MDIO controller, and an MDIO bus multiplexer in one memory-mapped device.
> > > +  The MDIO bus multiplexer is wired to the integrated MDIO controller.
> > > +
> > > +properties:
> > > +  compatible:
> > > +    const: soce,swip
> > > +
> > > +  reg:
> > > +    maxItems: 1
> > > +
> > > +  '#address-cells':
> > > +    const: 1
> > > +
> > > +  '#size-cells':
> > > +    const: 1
> > > +
> > > +  ranges: true
> > > +
> > > +  mdio@204:
> > > +    $ref: /schemas/net/soce,swip-mdio.yaml#
> > > +    unevaluatedProperties: false
> > > +
> > > +  mdio-mux@202:
> > > +    $ref: /schemas/net/mdio-mux-mmioreg.yaml#
> > > +    unevaluatedProperties: false
> > > +
> > > +  ethernet-switch:
> > 
> > Why are you mixing children with and without bus addresses? This is
> > discouraged and shows that device is not correctly represented, e.g. if
> > the ethernet-switch does not have resources, then THIS device is the
> > ethernet switch.
> > 
> 
> There is no hardware reason for leaving the switch child unaddressed.
> Just an error that occurred while converting the binding to the MFD
> model.
> I will describe the switch function as an ethernet-switch@0 child node
> with a reg property for it's register resources, like the ocelot MFD
> binding.

It looks like I need a different name for the MFD parent to avoid a
naming collision with the ethernet-switch@0 child. I checked other
bindings but could not find a suitable example.

I would appreciate any suggestions for a suitable name for the parent
node representing the FPGA IP core. It mainly acts as a container for
its child devices. I am considering "bus", "ip-core" or "shell".

> > > +    $ref: /schemas/net/dsa/soce,swip-switch.yaml#
> > > +    unevaluatedProperties: false
> > > +
> > > +required:
> > > +  - compatible
> > > +  - reg
> > > +  - '#address-cells'
> > > +  - '#size-cells'
> > > +  - ranges
> > > +  - ethernet-switch
> > > +
> > > +dependentRequired:
> > > +  mdio-mux@202:
> > > +    - mdio@204
> > > +
> > > +additionalProperties: false
> > > +
> > > +examples:
> > > +  - |
> > > +    ethernet-switch@80020000 {
> > > +        compatible = "soce,swip";
> > > +        reg = <0x80020000 0x10000>;
> > > +        #address-cells = <1>;
> > > +        #size-cells = <1>;
> > > +        ranges = <0x0 0x80020000 0x10000>;
> > > +
> > > +        mdio_parent: mdio@204 {
> > > +            compatible = "soce,swip-mdio";
> > > +            reg = <0x204 0xc>, <0x200 0x2>;
> > > +            reg-names = "data", "control";
> > > +            #address-cells = <1>;
> > > +            #size-cells = <0>;
> > > +        };
> > > +
> > > +        mdio-mux@202 {
> 


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

* Re: [PATCH net-next v4 4/8] dt-bindings: mfd: Add SoC-e SWIP parent
  2026-11-10 16:10       ` Vasilij Strassheim
@ 2026-11-10 19:21         ` Rob Herring
  0 siblings, 0 replies; 13+ messages in thread
From: Rob Herring @ 2026-11-10 19:21 UTC (permalink / raw)
  To: Vasilij Strassheim
  Cc: Krzysztof Kozlowski, Krzysztof Kozlowski, Conor Dooley,
	Andrew Lunn, Vladimir Oltean, David S. Miller, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Russell King, Andrew Lunn,
	Heiner Kallweit, Eric Dumazet, Lee Jones, devicetree,
	linux-kernel, netdev, mfd, Martin Kaistra, Benedikt Spranger

On Tue, Nov 10, 2026 at 05:10:15PM +0100, Vasilij Strassheim wrote:
> On Fri, 2026-11-06 at 22:51 +0100, Vasilij Strassheim wrote:
> > On Fri, 2026-11-06 at 12:13 +0100, Krzysztof Kozlowski wrote:
> > > On Thu, Nov 05, 2026 at 03:16:48PM +0100, Vasilij Strassheim wrote:
> > > > Add a binding for the SoC-e SWIP multifunction FPGA IP core.
> > > > 
> > > > Describe the shared MMIO address space and address translation for
> > > > the required Ethernet switch child and the optional integrated MDIO
> > > > controller and MMIO-controlled MDIO multiplexer.
> > > > 
> > > > Signed-off-by: Vasilij Strassheim <v.strassheim@linutronix.de>
> > > > ---
> > > >  .../devicetree/bindings/mfd/soce,swip.yaml         | 137 +++++++++++++++++++++
> > > >  1 file changed, 137 insertions(+)
> > > > 
> > > > diff --git a/Documentation/devicetree/bindings/mfd/soce,swip.yaml b/Documentation/devicetree/bindings/mfd/soce,swip.yaml
> > > > new file mode 100644
> > > > index 000000000000..625be299e262
> > > > --- /dev/null
> > > > +++ b/Documentation/devicetree/bindings/mfd/soce,swip.yaml
> > > > @@ -0,0 +1,137 @@
> > > > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > > > +%YAML 1.2
> > > > +---
> > > > +$id: http://devicetree.org/schemas/mfd/soce,swip.yaml#
> > > > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > > > +
> > > > +title: SoC-e SWIP multifunction Ethernet switch FPGA IP core
> > > > +
> > > > +maintainers:
> > > > +  - Vasilij Strassheim <v.strassheim@linutronix.de>
> > > > +
> > > > +description:
> > > > +  SoC-e Switch IP (SWIP) cores integrate Ethernet switching logic, an
> > > > +  MDIO controller, and an MDIO bus multiplexer in one memory-mapped device.
> > > > +  The MDIO bus multiplexer is wired to the integrated MDIO controller.
> > > > +
> > > > +properties:
> > > > +  compatible:
> > > > +    const: soce,swip
> > > > +
> > > > +  reg:
> > > > +    maxItems: 1
> > > > +
> > > > +  '#address-cells':
> > > > +    const: 1
> > > > +
> > > > +  '#size-cells':
> > > > +    const: 1
> > > > +
> > > > +  ranges: true
> > > > +
> > > > +  mdio@204:
> > > > +    $ref: /schemas/net/soce,swip-mdio.yaml#
> > > > +    unevaluatedProperties: false
> > > > +
> > > > +  mdio-mux@202:
> > > > +    $ref: /schemas/net/mdio-mux-mmioreg.yaml#
> > > > +    unevaluatedProperties: false

Given the MDIO bus and mux registers are adjacent, I don't know that 
putting the mux into its own node and driver really buys you anything. 
Can't your MDIO driver handle the muxing directly? mdio-mux-mmioreg was 
created for when you have mux registers in some completely unrelated 
block.

> > > > +
> > > > +  ethernet-switch:
> > > 
> > > Why are you mixing children with and without bus addresses? This is
> > > discouraged and shows that device is not correctly represented, e.g. if
> > > the ethernet-switch does not have resources, then THIS device is the
> > > ethernet switch.
> > > 
> > 
> > There is no hardware reason for leaving the switch child unaddressed.
> > Just an error that occurred while converting the binding to the MFD
> > model.
> > I will describe the switch function as an ethernet-switch@0 child node
> > with a reg property for it's register resources, like the ocelot MFD
> > binding.
> 
> It looks like I need a different name for the MFD parent to avoid a
> naming collision with the ethernet-switch@0 child. I checked other
> bindings but could not find a suitable example.
> 
> I would appreciate any suggestions for a suitable name for the parent
> node representing the FPGA IP core. It mainly acts as a container for
> its child devices. I am considering "bus", "ip-core" or "shell".

Krzysztof's point was combine the child and parent nodes into the 
parent. This is not really an MFD. Almost every ethernet MAC has an MDIO 
controller in it and none of those bindings are MFDs.

Rob

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

end of thread, other threads:[~2026-11-10 19:21 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-11-05 14:16 [PATCH net-next v4 0/8] net: dsa: Add support for SoC-e Ethernet switch IP cores Vasilij Strassheim
2026-11-05 14:16 ` [PATCH net-next v4 1/8] dt-bindings: vendor-prefixes: Add soce Vasilij Strassheim
2026-11-05 14:16 ` [PATCH net-next v4 2/8] dt-bindings: net: Add SoC-e SWIP MDIO controller Vasilij Strassheim
2026-11-05 14:16 ` [PATCH net-next v4 3/8] dt-bindings: net: dsa: Add SoC-e SWIP switch function Vasilij Strassheim
2026-11-05 14:16 ` [PATCH net-next v4 4/8] dt-bindings: mfd: Add SoC-e SWIP parent Vasilij Strassheim
2026-11-06 11:13   ` Krzysztof Kozlowski
2026-11-06 21:51     ` Vasilij Strassheim
2026-11-10 16:10       ` Vasilij Strassheim
2026-11-10 19:21         ` Rob Herring
2026-11-05 14:16 ` [PATCH net-next v4 5/8] net: dsa: Add tag handling for SoC-e switches Vasilij Strassheim
2026-11-05 14:16 ` [PATCH net-next v4 6/8] net: mdio: Add SoC-e SWIP MDIO controller driver Vasilij Strassheim
2026-11-05 14:16 ` [PATCH net-next v4 7/8] net: dsa: soce: Add basic support for SoC-e switch IP cores Vasilij Strassheim
2026-11-05 14:16 ` [PATCH net-next v4 8/8] net: dsa: soce: Add VLAN membership table support Vasilij Strassheim

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®