From nobody Sat Sep 26 07:17:10 2026 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5C6474FECFA; Thu, 3 Sep 2026 18:11:46 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=193.142.43.55 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788459111; cv=none; b=K7ASAlgQOIdW44cg8u1lJlgH5NeQrDmpFRNlIYTV2EpY5SmR/pH9ez7YTdYpOXH4ajMWTsNrf6CtT68w9MklJYYYRX+BnFvwBDab5I2tGGBqjV0i15qZRUVvtRPju8p9gtMXP2QDgGFxGx6hQ5ML5NKSEafRH7DwNbk8ZjEvISM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788459111; c=relaxed/simple; bh=Wr2OqW69o8MZw2XFVDxk9ByxGMJbThPaMC67F1FtZ4g=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=g0NZj+75H5s1vIEu3OOx6IPvVbnewEdixHaO0gQfSDic2z5M8ZiLIH9qq1QPoVyEQOGg4S7bGNz2+2ZeJXQ/Hm/NYLuYlsUg9uvkXUFYl9RXZnc/jOqNPvFTmY4RsLO0z86tnbPkiuy1usYAA0q8SzXXvBbR7Ygrs3YqT7KFiao= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de; spf=pass smtp.mailfrom=linutronix.de; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=a2N/o9Sr; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=hzPCkzqK; arc=none smtp.client-ip=193.142.43.55 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linutronix.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="a2N/o9Sr"; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="hzPCkzqK" From: Vasilij Strassheim DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1788459104; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=ZU1ty+E3jZObtE5Zgsy3Zsxcterr06GphGCs3MuS+n4=; b=a2N/o9Sr/k9I9VQb5I9rPp/mdgoGoJmjJdheIyOQaYC68Z3+X+UaFEgrPJKqsAfHNdygqI WpcKObQG62tStYHiMiUxAIv34sDMBYAYXasIYn07SURmsXqXHzOdE3GV3by4EAWV/wKVv0 /dMDpG6GTBVOuFYm9/xRzizok72Ysnfmcwzp0wiLMs0XOvHTx+dleGEKxAF4kdRsyD1PnQ JjtoZP5YGyLv5CI64BS/0tpYMItceCFKp7OO9JrXGa6lAYzEHz87eAbwBo2+FETyY8fDbB AAqWpE22mENMrW/WKzyyDfWtflr5ROmClbsjP6UiOJkOFyJVxOISIsQEbSvpOQ== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1788459104; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=ZU1ty+E3jZObtE5Zgsy3Zsxcterr06GphGCs3MuS+n4=; b=hzPCkzqK7RA99gRWoPYcnAtTIHNKfcD0jaeYpZndhHjfFdQTQ8bUo39w4kMim11GZDHIvm uYLF1lVIynUC0FAA== Date: Thu, 03 Sep 2026 20:10:58 +0200 Subject: [PATCH net-next v2 1/4] dt-bindings: vendor-prefixes: Add soce Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260903-devel-vstrassheim-soce-dsa-ml-v2-1-fb0587cb466b@linutronix.de> References: <20260903-devel-vstrassheim-soce-dsa-ml-v2-0-fb0587cb466b@linutronix.de> In-Reply-To: <20260903-devel-vstrassheim-soce-dsa-ml-v2-0-fb0587cb466b@linutronix.de> To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Andrew Lunn , Vladimir Oltean , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Russell King Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, netdev@vger.kernel.org, Martin Kaistra , Benedikt Spranger , Vasilij Strassheim Document binding for System-On-Chip Engineering, S.L. Link: https://soc-e.com/ Signed-off-by: Vasilij Strassheim Acked-by: Krzysztof Kozlowski --- Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Docum= entation/devicetree/bindings/vendor-prefixes.yaml index ba2002969373..1c641e1f0ca6 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -1581,6 +1581,8 @@ patternProperties: description: Standard Microsystems Corporation "^snps,.*": description: Synopsys, Inc. + "^soce,.*": + description: System-On-Chip Engineering, S.L. "^sochip,.*": description: Shenzhen SoChip Technology Co., Ltd. "^socionext,.*": --=20 2.39.5 From nobody Sat Sep 26 07:17:10 2026 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id F38D54F30DB; Thu, 3 Sep 2026 18:11:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=193.142.43.55 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788459111; cv=none; b=TopqM38J10bxki/TsyY2anEObf38m8j7SmKGl7U9YMWLiMcr+S8EIk25SLijkgJXKlrt/7/+DR+dlaVe43WFWbiKFasyrT5KJ1k/1u6gr3y233TmdL7hnvlA6Wduh0SVxkmodDiPU824JqCvkZQEqrRb2pdkvNKMfK6zwHu2hAc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788459111; c=relaxed/simple; bh=7FNsE5hcmXuh8cncWSUzASxF4qar/Wb9kp6VEMi534M=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=mfZNriuyLkrmcilzDqXBLmfeonBv0TgeTBA+yUwsDqHptN9e/K8VhTpXO0w6BYNtT8GKswfs8Hg7dIjZF31C8RM/XiZXNpUuRYHucevv505xffwOlY2btOAJt3horcisfYSohZnfr/XD4pck2itxjFxvh9FiBNGN/DRf1JsjZNE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de; spf=pass smtp.mailfrom=linutronix.de; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=WE3at6xK; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=GhTKBeBS; arc=none smtp.client-ip=193.142.43.55 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linutronix.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="WE3at6xK"; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="GhTKBeBS" From: Vasilij Strassheim DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1788459104; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=FkHy7NSqEWamgXkltGyNSAtC+2Gpn9ky7tURJQV0C88=; b=WE3at6xKVji4YDbuhFWAsRtoBNE0tYHTev3gDQFQEeid6HREYCBaGIKDAhNanqRdxoiv+l UQxQoWlPz+jG5WIPlmAlNYr4FNq0DIiXIpT6+0UowHO7+Mxw7fVuKZRKYjSgHM1AiZg3n7 R8WwZDhvvoFpdbyG25mdvcjGPco2yrU1pGblFgkycI5cFOAMWcJejg/jEXTSNinPEvvTGD zi4SobX4+pEC+cbXWNDPe3n5b/kB9lQmSxSWs5ALTvZ17v3oe4FUxyy6nTuK4jI77GHhVP 9GjIOlp5ntPbIrbbuSAhVXfVOP8bLLEtTTnAVt0Yp9oIGZIEE5teQH+DOZcNGg== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1788459104; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=FkHy7NSqEWamgXkltGyNSAtC+2Gpn9ky7tURJQV0C88=; b=GhTKBeBSjgnEHdUGHveVvAM6p2ZuWHHxjCs+urTspvzkQg5BLwQFKPGEDZ/fRVXVohpepn EOgylgg1OxYT8bDQ== Date: Thu, 03 Sep 2026 20:10:59 +0200 Subject: [PATCH net-next v2 2/4] dt-bindings: net: dsa: Add SoC-e SWIP switch Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260903-devel-vstrassheim-soce-dsa-ml-v2-2-fb0587cb466b@linutronix.de> References: <20260903-devel-vstrassheim-soce-dsa-ml-v2-0-fb0587cb466b@linutronix.de> In-Reply-To: <20260903-devel-vstrassheim-soce-dsa-ml-v2-0-fb0587cb466b@linutronix.de> To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Andrew Lunn , Vladimir Oltean , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Russell King Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, netdev@vger.kernel.org, Martin Kaistra , Benedikt Spranger , Vasilij Strassheim Add a binding for SoC-e FPGA-based Ethernet switch IP cores. The compatible identifies a register layout characterized by the core and feature identification registers at the encoded offsets. The concrete synthesis-time configuration is then autodetected from these registers. Signed-off-by: Vasilij Strassheim --- .../devicetree/bindings/net/dsa/soce,swip.yaml | 161 +++++++++++++++++= ++++ 1 file changed, 161 insertions(+) diff --git a/Documentation/devicetree/bindings/net/dsa/soce,swip.yaml b/Doc= umentation/devicetree/bindings/net/dsa/soce,swip.yaml new file mode 100644 index 000000000000..508e444e10da --- /dev/null +++ b/Documentation/devicetree/bindings/net/dsa/soce,swip.yaml @@ -0,0 +1,161 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/dsa/soce,swip.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: SoC-e ethernet switch IP core for FPGAs + +maintainers: + - Vasilij Strassheim + +description: + SoC-e Ethernet switch IP cores are FPGA-based switches whose features + and number of ports are selected at synthesis time. Ports can connect + to CPUs, external PHYs, FPGA logic, or other switch cores. The + integrated MDIO controller provides multiple independently selectable + external outputs. + +$ref: dsa.yaml# + +properties: + compatible: + const: soce,swip-00-04-0c-10 + description: + Register layout with the core version register at offset 0x00 and + feature identification registers at offsets 0x04, 0x0c, and 0x10. + Switch instances using this register layout are autodetected from + these registers and use this compatible regardless of their + synthesis-time feature and port configuration. + + reg: + maxItems: 1 + + mdios: + type: object + additionalProperties: false + description: + External MDIO buses provided by the integrated MDIO controller. + Each child bus selects one controller output. + + properties: + '#address-cells': + const: 1 + '#size-cells': + const: 0 + + patternProperties: + '^mdio@[0-9a-f]+$': + $ref: /schemas/net/mdio.yaml# + unevaluatedProperties: false + + properties: + reg: + maximum: 30 + description: + MDIO controller output index, which must be lower than the + number of implemented switch ports. + + required: + - reg + + required: + - '#address-cells' + - '#size-cells' + +patternProperties: + '^(ethernet-)?ports$': + patternProperties: + '^(ethernet-)?port@[0-9a-f]+$': + $ref: dsa-port.yaml# + unevaluatedProperties: false + + properties: + reg: + maximum: 30 + description: + Switch port index. Supported switch configurations have + up to 31 ports, numbered from 0 through 30. + + phy-mode: + enum: + - mii + - gmii + - rmii + - rgmii + - rgmii-id + - rgmii-rxid + - rgmii-txid + + required: + - phy-mode + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + ethernet-switch@80020000 { + compatible =3D "soce,swip-00-04-0c-10"; + reg =3D <0x80020000 0x10000>; + + ports { + #address-cells =3D <1>; + #size-cells =3D <0>; + + port@0 { + reg =3D <0>; + label =3D "lan0"; + phy-handle =3D <&switchphy0>; + phy-mode =3D "rgmii-id"; + }; + + port@1 { + reg =3D <1>; + label =3D "lan1"; + phy-handle =3D <&switchphy1>; + phy-mode =3D "rgmii-id"; + }; + + port@2 { + reg =3D <2>; + ethernet =3D <ð0>; + phy-mode =3D "gmii"; + + fixed-link { + speed =3D <1000>; + full-duplex; + }; + }; + }; + + mdios { + #address-cells =3D <1>; + #size-cells =3D <0>; + + mdio@0 { + reg =3D <0>; + #address-cells =3D <1>; + #size-cells =3D <0>; + + switchphy0: ethernet-phy@1 { + compatible =3D "ethernet-phy-ieee802.3-c22"; + reg =3D <1>; + }; + }; + + mdio@1 { + reg =3D <1>; + #address-cells =3D <1>; + #size-cells =3D <0>; + + switchphy1: ethernet-phy@1 { + compatible =3D "ethernet-phy-ieee802.3-c22"; + reg =3D <1>; + }; + }; + }; + }; --=20 2.39.5 From nobody Sat Sep 26 07:17:10 2026 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2435D4FECFF; Thu, 3 Sep 2026 18:11:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=193.142.43.55 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788459112; cv=none; b=i38RKf7HO4vdmm69NpVMcaPEigJpmd2r14hFSEdTFiBIxNy/meIjsg4a0yNawAQ0Co7pBjb0f6AzKqUkXl0VJXyXiDmzdr2Tn+6Ny+cElVarGUyxTfuTralOFJ/34lHCCpCQcnmxXVLMqc0SSWF+ubUsUv8pB4PPwPuEcgf65so= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788459112; c=relaxed/simple; bh=IhzIkMhFVBRAvWKRGStAF0ZPR5nz6jobNLpWzll85h8=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=jHu9Tnpl9su1iOST8qIIfOj4iw5qs4BOYe/oYdojEluO/wqcsHEUeN5x3so8tMZAEy4nZK3sPvV51OokZGj6EcLQkLwAueh1VqjAMAhS8CKBGHnYXC5Oe5q3O/2g60U637yVxyKYuw3iTiwUf5cAJtqR+63fIerSJIUg8wEwSrM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de; spf=pass smtp.mailfrom=linutronix.de; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=y6mn/PB+; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=P3SM2lG/; arc=none smtp.client-ip=193.142.43.55 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linutronix.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="y6mn/PB+"; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="P3SM2lG/" From: Vasilij Strassheim DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1788459105; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=CoNMJWHFriw+0cV444Unh9ymreGAqfbDBHFavMleW2U=; b=y6mn/PB+K7lJfttjp2YBQTZD03Je0spiEtWMCoGkdGLAT2Uh9QlCZCx11L0pccFV9VSNpy 7Yo+WL1sbr6yuTHyfrdp1Noxk/S43GZzvFSZptnPb6NZdDn94ig25PIGHACsl0X4sYqpas s4gBKQnZSod6vDTfCiQjfzoGIfvgmcaMXqFO0yJ9unxn5KnsAMlDaz9vTrQ64AfRG45W8l 4h9LFOaCVapQ4L1Yozb6xm1pIu7rdxTglXcrV8LueqhZpD6ZJ5l5tTeSYPl/eu+bd0C26e yTBULQFvzjtpLrQn3iKUVIsNgPdPpmt1LSRyxZ9h3+V7kZ7Bumc4/iIzq+6jbg== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1788459105; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=CoNMJWHFriw+0cV444Unh9ymreGAqfbDBHFavMleW2U=; b=P3SM2lG/0OnArM0o3aWUI2xloHJi04zs384InTwK2NCDYO/mN8NJkb/rcOeDNYMgGqkgcr tEHQEx5UnjdV77Ag== Date: Thu, 03 Sep 2026 20:11:00 +0200 Subject: [PATCH net-next v2 3/4] net: dsa: Add tag handling for SoC-e switches Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260903-devel-vstrassheim-soce-dsa-ml-v2-3-fb0587cb466b@linutronix.de> References: <20260903-devel-vstrassheim-soce-dsa-ml-v2-0-fb0587cb466b@linutronix.de> In-Reply-To: <20260903-devel-vstrassheim-soce-dsa-ml-v2-0-fb0587cb466b@linutronix.de> To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Andrew Lunn , Vladimir Oltean , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Russell King Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, netdev@vger.kernel.org, Martin Kaistra , Benedikt Spranger , Vasilij Strassheim SoC-e switches exchange frames with the conduit using an 8-byte SDSA header inserted between the source MAC address and the original EtherType. The header identifies itself with EtherType 0xdcdc and carries the frame direction and a 10-bit source or destination port. Add support for both frame types FROM_CPU and TO_CPU. SDSA VLAN metadata generation could not be tested on the available switch configuration yet. Leave these fields clear on transmit and reject receive headers which mark the metadata as valid. Signed-off-by: Vasilij Strassheim --- include/net/dsa.h | 2 + net/dsa/Kconfig | 6 +++ net/dsa/Makefile | 1 + net/dsa/tag_sdsa.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++++= ++++ 4 files changed, 132 insertions(+) diff --git a/include/net/dsa.h b/include/net/dsa.h index 7507d632e7c6..cabe9f94788a 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -61,6 +61,7 @@ struct tc_action; #define DSA_TAG_PROTO_NETC_VALUE 33 #define DSA_TAG_PROTO_KSZ8463_VALUE 34 #define DSA_TAG_PROTO_MT7628_VALUE 35 +#define DSA_TAG_PROTO_SDSA_VALUE 36 =20 enum dsa_tag_protocol { DSA_TAG_PROTO_NONE =3D DSA_TAG_PROTO_NONE_VALUE, @@ -99,6 +100,7 @@ enum dsa_tag_protocol { DSA_TAG_PROTO_NETC =3D DSA_TAG_PROTO_NETC_VALUE, DSA_TAG_PROTO_KSZ8463 =3D DSA_TAG_PROTO_KSZ8463_VALUE, DSA_TAG_PROTO_MT7628 =3D DSA_TAG_PROTO_MT7628_VALUE, + DSA_TAG_PROTO_SDSA =3D DSA_TAG_PROTO_SDSA_VALUE, }; =20 struct dsa_switch; diff --git a/net/dsa/Kconfig b/net/dsa/Kconfig index 23b4b74004ed..0032ccd3badf 100644 --- a/net/dsa/Kconfig +++ b/net/dsa/Kconfig @@ -188,6 +188,12 @@ config NET_DSA_TAG_RZN1_A5PSW Renesas RZ/N1 embedded switch that uses an 8 byte tag located after destination MAC address. =20 +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 d15bcf5c68f0..2f31ed0e4626 100644 --- a/net/dsa/Makefile +++ b/net/dsa/Makefile @@ -39,6 +39,7 @@ obj-$(CONFIG_NET_DSA_TAG_QCA) +=3D tag_qca.o obj-$(CONFIG_NET_DSA_TAG_RTL4_A) +=3D tag_rtl4_a.o obj-$(CONFIG_NET_DSA_TAG_RTL8_4) +=3D tag_rtl8_4.o obj-$(CONFIG_NET_DSA_TAG_RZN1_A5PSW) +=3D tag_rzn1_a5psw.o +obj-$(CONFIG_NET_DSA_TAG_SDSA) +=3D tag_sdsa.o obj-$(CONFIG_NET_DSA_TAG_SJA1105) +=3D tag_sja1105.o obj-$(CONFIG_NET_DSA_TAG_TRAILER) +=3D tag_trailer.o obj-$(CONFIG_NET_DSA_TAG_VSC73XX_8021Q) +=3D tag_vsc73xx_8021q.o diff --git a/net/dsa/tag_sdsa.c b/net/dsa/tag_sdsa.c new file mode 100644 index 000000000000..83bccd65b1b1 --- /dev/null +++ b/net/dsa/tag_sdsa.c @@ -0,0 +1,123 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2020-2026 System on Chip engineering, S.L. + * Copyright (c) 2026 Linutronix GmbH + * Author: Vasilij Strassheim + */ + +#include +#include +#include + +#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] (bit= s 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 *d= ev) +{ + struct dsa_port *dp =3D dsa_user_to_port(dev); + struct sdsa_tag *tag; + + BUILD_BUG_ON(sizeof(*tag) !=3D SDSA_HLEN); + + skb_push(skb, SDSA_HLEN); + dsa_alloc_etype_header(skb, SDSA_HLEN); + + /* Construct the FROM_CPU DSA tag. */ + tag =3D dsa_etype_header_pos_tx(skb); + tag->ethertype =3D cpu_to_be16(ETH_P_SDSA); + tag->reserved =3D 0; + tag->frame_type_port_hi =3D + 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 =3D FIELD_PREP(SDSA_TAG_PORT_LO_MASK, dp->index); + tag->vlan =3D 0; + + return skb; +} + +static struct sk_buff *sdsa_rcv(struct sk_buff *skb, struct net_device *de= v) +{ + struct sdsa_tag *tag; + int source_port; + u8 frame_type; + + if (unlikely(!pskb_may_pull(skb, SDSA_HLEN))) + goto out_drop; + + tag =3D dsa_etype_header_pos_rx(skb); + if (unlikely(tag->ethertype !=3D cpu_to_be16(ETH_P_SDSA))) + goto out_drop; + + /* Check that the frame type is TO_CPU. */ + frame_type =3D FIELD_GET(SDSA_TAG_FRAME_TYPE_MASK, + tag->frame_type_port_hi); + if (frame_type !=3D SDSA_FRAME_TYPE_TO_CPU) + goto out_drop; + + /* SDSA VLAN information is not supported. */ + if (tag->frame_type_port_hi & SDSA_TAG_VLAN_BIT) + goto out_drop; + + /* Determine the source port from the two port fields. */ + source_port =3D FIELD_GET(SDSA_TAG_PORT_HI_MASK, + tag->frame_type_port_hi) << + SDSA_TAG_PORT_HI_SHIFT; + source_port |=3D FIELD_GET(SDSA_TAG_PORT_LO_MASK, tag->port_lo); + + skb->dev =3D dsa_conduit_find_user(dev, 0, source_port); + if (!skb->dev) + goto out_drop; + + skb_pull_rcsum(skb, SDSA_HLEN); + dsa_strip_etype_header(skb, SDSA_HLEN); + + dsa_default_offload_fwd_mark(skb); + return skb; + +out_drop: + kfree_skb(skb); + return NULL; +} + +static const struct dsa_device_ops sdsa_netdev_ops =3D { + .name =3D SDSA_NAME, + .proto =3D DSA_TAG_PROTO_SDSA, + .xmit =3D sdsa_xmit, + .rcv =3D sdsa_rcv, + .needed_headroom =3D 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); --=20 2.39.5 From nobody Sat Sep 26 07:17:10 2026 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6F9524FECEF; Thu, 3 Sep 2026 18:11:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=193.142.43.55 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788459113; cv=none; b=QuiR5rKdKvyHZS0OmJs8RTH7FqtggJvwIYi3sqiDDIaa8K9KyfFWONVagDJWRuNRYTh71HUN/AQAV4JkD6AW383aSso8U6MHVGGEoyndovhrLD1/+rvlajEE0YaCKRvX8eQb8RFOeRG3e30wXCj2gBCy1HUD/DW0434Jp3HCg5s= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788459113; c=relaxed/simple; bh=LhxHs9DqooqXpENPvL+fc0rTJiNzxeLqkNetZa9UpUw=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=p+YG1moinN/Z1fbeuZTfpa4TLEv+iKl0cEGpx0Hq0IsA4jeYYHTnTOaZuhAO1yP1x/VYm0+fx0Ya+2Tx2xHwY609VZm87XFj+L7ridEAN5vwAPNkhCuzvJMYl0Sta5GJbjNSN0T190fbeQlBmDcC0EZd0y9CTYoSjRzROf0seB0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de; spf=pass smtp.mailfrom=linutronix.de; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=wespURYI; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=ZqJKiW/k; arc=none smtp.client-ip=193.142.43.55 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linutronix.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="wespURYI"; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="ZqJKiW/k" From: Vasilij Strassheim DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1788459106; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=plFndZhQx/b/89NM0Q4ZzhYixbux0MsQFRYcLkRRl9s=; b=wespURYIvZXe1cNXKdFLrw4EKbXwtnROrEFpwpLJBpfFiRZ/rXrZQGHHs9c0lBGuUEsKed FO0hQBe/GnYVSAKDDI1/1BLleZUcQnvVeLoXnBGf51pZystLR6wB7qCS1802ZGM+mZJoyV id9WXg+jVktBiPpqZz7G4Iq8fCadAThJQNDftxz52wEPWRWPge5iv3WsU2rXE4khOVXCLY cLv0jS4pOQa1CmbzBvqrSWUtFAJ5KnNq+juekQy/P6fe3Or5S3pq1p2mbL1zi0e7jGsvCp 5hcnOXBTCt4b5dvPxwDphaqm5A4TMQMhQcTbaO6hHDb+X8nAg9yfPkbiwsq14A== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1788459106; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=plFndZhQx/b/89NM0Q4ZzhYixbux0MsQFRYcLkRRl9s=; b=ZqJKiW/kLyiBaBeIsHHRlGPeU0NrdILF28TEiGuscNkGeOetX7EP1JjuqQ7VWkApFXf83V azNMX2q6P/jaGrAQ== Date: Thu, 03 Sep 2026 20:11:01 +0200 Subject: [PATCH net-next v2 4/4] net: dsa: soce: Add basic support for SoC-e switch IP cores Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260903-devel-vstrassheim-soce-dsa-ml-v2-4-fb0587cb466b@linutronix.de> References: <20260903-devel-vstrassheim-soce-dsa-ml-v2-0-fb0587cb466b@linutronix.de> In-Reply-To: <20260903-devel-vstrassheim-soce-dsa-ml-v2-0-fb0587cb466b@linutronix.de> To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Andrew Lunn , Vladimir Oltean , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Russell King Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, netdev@vger.kernel.org, Martin Kaistra , Benedikt Spranger , Vasilij Strassheim Add an initial DSA driver for SoC-e FPGA-based Ethernet switch IP cores. The driver accesses the switch through a memory-mapped register interface. During probe, it detects the core version and the licensed and implemented port counts, and verifies that the synthesized core provides DSA support. Port counts from 1 through 31 are supported. Enable "DSA custom rules" feature for all frames and derive the phylink capabilities from each port's phy-mode. Enabling this tagging feature of the switch, places all user ports into CPU-directed operation: frames received on user ports are forwarded exclusively to the CPU port and tagged with their source port. Consequently, standalone ports remain isolated. This switch IP core also has an integrated MDIO controller (called MDIO Bridge). Expose each configured hardware MDIO output as a separate logical MDIO bus. The buses support Clause 22 and Clause 45 transactions and serialize access to the shared MDIO controller. Tested with a SoC-e MRS 25.01 IP core on a Xilinx ZynqMP platform. Signed-off-by: Vasilij Strassheim --- drivers/net/dsa/Kconfig | 2 + drivers/net/dsa/Makefile | 1 + drivers/net/dsa/soce/Kconfig | 12 + drivers/net/dsa/soce/Makefile | 4 + drivers/net/dsa/soce/soce_dsa.h | 44 ++++ drivers/net/dsa/soce/soce_dsa_core.c | 297 +++++++++++++++++++++++++ drivers/net/dsa/soce/soce_mdio.c | 411 +++++++++++++++++++++++++++++++= ++++ drivers/net/dsa/soce/soce_mdio.h | 38 ++++ 8 files changed, 809 insertions(+) diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig index 8d8edcf89f10..1422b9c5bf85 100644 --- a/drivers/net/dsa/Kconfig +++ b/drivers/net/dsa/Kconfig @@ -94,6 +94,8 @@ source "drivers/net/dsa/ocelot/Kconfig" =20 source "drivers/net/dsa/qca/Kconfig" =20 +source "drivers/net/dsa/soce/Kconfig" + source "drivers/net/dsa/sja1105/Kconfig" =20 source "drivers/net/dsa/xrs700x/Kconfig" diff --git a/drivers/net/dsa/Makefile b/drivers/net/dsa/Makefile index df849cd0e640..b1336d5b3989 100644 --- a/drivers/net/dsa/Makefile +++ b/drivers/net/dsa/Makefile @@ -27,4 +27,5 @@ obj-y +=3D ocelot/ obj-y +=3D qca/ obj-y +=3D realtek/ obj-y +=3D sja1105/ +obj-y +=3D soce/ obj-y +=3D xrs700x/ diff --git a/drivers/net/dsa/soce/Kconfig b/drivers/net/dsa/soce/Kconfig new file mode 100644 index 000000000000..321da9835402 --- /dev/null +++ b/drivers/net/dsa/soce/Kconfig @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0 +config NET_DSA_SOCE + tristate "SoC-e switches" + depends on NET_DSA + depends on OF + depends on HAS_IOMEM + select NET_DSA_TAG_SDSA + help + This enables support for switches based on SoC-e IP cores. + Frames are exchanged with the CPU port using the SDSA DSA tag protocol. + The driver supports switch variants whose features and number of ports + are selected at synthesis time and detected at runtime. diff --git a/drivers/net/dsa/soce/Makefile b/drivers/net/dsa/soce/Makefile new file mode 100644 index 000000000000..c2635fe19643 --- /dev/null +++ b/drivers/net/dsa/soce/Makefile @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_NET_DSA_SOCE) +=3D soce_dsa.o +soce_dsa-objs :=3D soce_dsa_core.o soce_mdio.o diff --git a/drivers/net/dsa/soce/soce_dsa.h b/drivers/net/dsa/soce/soce_ds= a.h new file mode 100644 index 000000000000..ef01304209e6 --- /dev/null +++ b/drivers/net/dsa/soce/soce_dsa.h @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2020-2026 System on Chip engineering, S.L. + * Copyright (c) 2026 Linutronix GmbH + * Author: Vasilij Strassheim + */ + +#ifndef __SOCE_DSA_H +#define __SOCE_DSA_H + +#include +#include + +#define SOCE_MAX_NUM_PORTS 31 +#define SOCE_MAX_MDIO_ADDR 32 +#define SOCE_MAX_MDIO_OUTPUTS SOCE_MAX_NUM_PORTS + +struct dsa_switch; + +struct soce_mdio_ops { + int (*phy_read)(struct dsa_switch *ds, int mdio_output, int phy_addr, + int regnum); + int (*phy_write)(struct dsa_switch *ds, int mdio_output, int phy_addr, + int regnum, u16 val); + int (*phy_read_c45)(struct dsa_switch *ds, int mdio_output, int phy_addr, + int devad, int regnum); + int (*phy_write_c45)(struct dsa_switch *ds, int mdio_output, int phy_addr, + int devad, int regnum, u16 val); +}; + +struct soce_dsa_local { + void __iomem *base_addr; + void __iomem *mdio_master_addr; + /* Serializes all logical buses sharing the MDIO master. */ + struct mutex mdio_lock; + const struct soce_mdio_ops *mdio_ops; +}; + +struct soce_priv { + struct soce_dsa_local local; + struct dsa_switch *ds; +}; + +#endif /* __SOCE_DSA_H */ diff --git a/drivers/net/dsa/soce/soce_dsa_core.c b/drivers/net/dsa/soce/so= ce_dsa_core.c new file mode 100644 index 000000000000..60f9f8c030e8 --- /dev/null +++ b/drivers/net/dsa/soce/soce_dsa_core.c @@ -0,0 +1,297 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2020-2026 System on Chip engineering, S.L. + * Copyright (c) 2026 Linutronix GmbH + * Author: Vasilij Strassheim + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "soce_dsa.h" +#include "soce_mdio.h" + +#define SOCE_CORE_VERSION_SHIFT 24 +#define SOCE_CORE_SUBVERSION_SHIFT 16 +#define SOCE_LICENSED_NUM_PORTS_MASK GENMASK(31, 27) +#define SOCE_IMPLEMENTED_NUM_PORTS_MASK GENMASK(31, 27) +#define SOCE_IMPLEMENTED_DSA BIT(23) +#define SOCE_DSA_REGS_BASE 0x1200 +#define SOCE_TAG_ALL_FRAMES_CTRL_OFFSET (SOCE_DSA_REGS_BASE + 0x001c) +#define SOCE_TAG_ALL_FRAMES_ENABLE BIT(0) +#define SOCE_CUSTOM_RULES_TAGGING_OFFSET (SOCE_DSA_REGS_BASE + 0x0020) +#define SOCE_CUSTOM_RULES_TAGGING_ENABLE BIT(0) +#define SOCE_MIN_CORE_VERSION 0x24 +#define SOCE_MIN_CORE_SUBVERSION 0x01 + +static void soce_phylink_get_caps(struct dsa_switch *ds, int port, + struct phylink_config *config) +{ + struct dsa_port *dp =3D dsa_to_port(ds, port); + phy_interface_t mode; + int ret; + + ret =3D 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 =3D MAC_SYM_PAUSE | MAC_ASYM_PAUSE; + + switch (mode) { + case PHY_INTERFACE_MODE_MII: + config->mac_capabilities |=3D MAC_10 | MAC_100; + break; + case PHY_INTERFACE_MODE_GMII: + config->mac_capabilities |=3D MAC_10 | MAC_100 | MAC_1000; + break; + case PHY_INTERFACE_MODE_RMII: + config->mac_capabilities |=3D MAC_10FD | MAC_100FD; + break; + default: + if (phy_interface_mode_is_rgmii(mode)) + config->mac_capabilities |=3D MAC_10FD | MAC_100FD | + MAC_1000FD; + break; + } +} + +static const struct soce_mdio_ops soce_mdio_ops_c22_c45 =3D { + .phy_read =3D soce_mdio_23_02_read, + .phy_write =3D soce_mdio_23_02_write, + .phy_read_c45 =3D soce_mdio_23_02_read_c45, + .phy_write_c45 =3D soce_mdio_23_02_write_c45, +}; + +struct soce_probe_desc { + u32 core_version_offset; + u32 licensed_features_offset; + u32 implemented_features0_offset; + u32 mdio_master_offset; +}; + +static const struct soce_probe_desc soce_probe_desc_swip_00_04_0c_10 =3D { + .core_version_offset =3D 0x0000, + .licensed_features_offset =3D 0x0004, + .implemented_features0_offset =3D 0x000c, + .mdio_master_offset =3D 0x0200, +}; + +static int soce_sw_validate_core_version(u8 version, u8 subversion) +{ + if (version < SOCE_MIN_CORE_VERSION || + (version =3D=3D SOCE_MIN_CORE_VERSION && + subversion < SOCE_MIN_CORE_SUBVERSION)) + return -ENODEV; + + return 0; +} + +static void soce_sw_read_core_version(struct soce_dsa_local *local, + const struct soce_probe_desc *probe_desc, + u8 *version, u8 *subversion, u16 *revision) +{ + u32 regval; + + regval =3D readl(local->base_addr + probe_desc->core_version_offset); + *version =3D (u8)(regval >> SOCE_CORE_VERSION_SHIFT); + *subversion =3D (u8)(regval >> SOCE_CORE_SUBVERSION_SHIFT); + *revision =3D (u16)regval; +} + +static int soce_sw_detect_features(struct soce_dsa_local *local, + const struct soce_probe_desc *probe_desc, + u32 *numports) +{ + u32 implemented_numports; + u32 licensed_numports; + u32 regval; + + regval =3D readl(local->base_addr + probe_desc->licensed_features_offset); + licensed_numports =3D FIELD_GET(SOCE_LICENSED_NUM_PORTS_MASK, regval); + if (!licensed_numports || licensed_numports > SOCE_MAX_NUM_PORTS) + return -EINVAL; + + regval =3D readl(local->base_addr + + probe_desc->implemented_features0_offset); + if (!(regval & SOCE_IMPLEMENTED_DSA)) + return -ENODEV; + + implemented_numports =3D FIELD_GET(SOCE_IMPLEMENTED_NUM_PORTS_MASK, + regval); + if (!implemented_numports || + implemented_numports > licensed_numports) + return -EINVAL; + + *numports =3D implemented_numports; + + return 0; +} + +static void soce_sw_enable_tagging(struct soce_dsa_local *local) +{ + u32 regval; + + regval =3D readl(local->base_addr + SOCE_TAG_ALL_FRAMES_CTRL_OFFSET); + regval |=3D SOCE_TAG_ALL_FRAMES_ENABLE; + writel(regval, local->base_addr + SOCE_TAG_ALL_FRAMES_CTRL_OFFSET); + + regval =3D readl(local->base_addr + SOCE_CUSTOM_RULES_TAGGING_OFFSET); + regval |=3D SOCE_CUSTOM_RULES_TAGGING_ENABLE; + writel(regval, local->base_addr + SOCE_CUSTOM_RULES_TAGGING_OFFSET); +} + +static int soce_setup(struct dsa_switch *ds) +{ + struct soce_priv *priv =3D ds->priv; + + soce_sw_enable_tagging(&priv->local); + + return 0; +} + +static enum dsa_tag_protocol soce_get_tag_protocol(struct dsa_switch *ds, + int port, + enum dsa_tag_protocol mprop) +{ + return DSA_TAG_PROTO_SDSA; +} + +static const struct dsa_switch_ops soce_switch_ops =3D { + .get_tag_protocol =3D soce_get_tag_protocol, + .setup =3D soce_setup, + .phylink_get_caps =3D soce_phylink_get_caps, +}; + +static int soce_sw_probe(struct platform_device *pdev) +{ + const struct soce_probe_desc *probe_desc; + struct device *dev =3D &pdev->dev; + struct soce_dsa_local *local; + struct soce_priv *priv; + u8 hw_subversion; + u16 hw_revision; + u32 hw_numports; + u8 hw_version; + int ret; + + priv =3D devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->ds =3D devm_kzalloc(dev, sizeof(*priv->ds), GFP_KERNEL); + if (!priv->ds) + return -ENOMEM; + + priv->ds->dev =3D dev; + priv->ds->priv =3D priv; + probe_desc =3D of_device_get_match_data(dev); + if (!probe_desc) + return -EINVAL; + + local =3D &priv->local; + mutex_init(&local->mdio_lock); + + local->base_addr =3D devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(local->base_addr)) + return PTR_ERR(local->base_addr); + + soce_sw_read_core_version(local, probe_desc, &hw_version, + &hw_subversion, &hw_revision); + + ret =3D soce_sw_detect_features(local, probe_desc, &hw_numports); + if (ret) { + if (ret =3D=3D -ENODEV) + dev_err(dev, "switch core does not implement DSA\n"); + else + dev_err(dev, + "invalid licensed or implemented features register\n"); + return ret; + } + + ret =3D soce_sw_validate_core_version(hw_version, hw_subversion); + if (ret) { + dev_err(dev, "unsupported switch core version %.2X.%.2X.%.4X\n", + hw_version, hw_subversion, hw_revision); + return ret; + } + + priv->ds->ops =3D &soce_switch_ops; + local->mdio_ops =3D &soce_mdio_ops_c22_c45; + local->mdio_master_addr =3D + local->base_addr + probe_desc->mdio_master_offset; + + priv->ds->num_ports =3D hw_numports; + ret =3D soce_sw_register_mdio_buses(priv, dev, hw_numports); + if (ret) + return ret; + + dev_set_drvdata(dev, priv); + + ret =3D dsa_register_switch(priv->ds); + if (ret) + return ret; + + dev_info(dev, + "probed soce switch core version %02x.%02x.%04x with %u ports\n", + hw_version, hw_subversion, hw_revision, hw_numports); + + return 0; +} + +static void soce_sw_remove(struct platform_device *pdev) +{ + struct soce_priv *priv =3D platform_get_drvdata(pdev); + + if (!priv) + return; + + dsa_unregister_switch(priv->ds); + platform_set_drvdata(pdev, NULL); +} + +static void soce_sw_shutdown(struct platform_device *pdev) +{ + struct soce_priv *priv =3D platform_get_drvdata(pdev); + + if (!priv) + return; + + dsa_switch_shutdown(priv->ds); + platform_set_drvdata(pdev, NULL); +} + +static const struct of_device_id soce_of_match[] =3D { + { .compatible =3D "soce,swip-00-04-0c-10", + .data =3D &soce_probe_desc_swip_00_04_0c_10 }, + { /* sentinel */ }, +}; + +static struct platform_driver soce_driver =3D { + .probe =3D soce_sw_probe, + .remove =3D soce_sw_remove, + .shutdown =3D soce_sw_shutdown, + .driver =3D { + .name =3D "soce-swip", + .of_match_table =3D soce_of_match, + }, +}; + +module_platform_driver(soce_driver); +MODULE_DEVICE_TABLE(of, soce_of_match); +MODULE_AUTHOR("Vasilij Strassheim "); +MODULE_DESCRIPTION("Driver for SoC-e ethernet switch family"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/dsa/soce/soce_mdio.c b/drivers/net/dsa/soce/soce_m= dio.c new file mode 100644 index 000000000000..692dcbe57d1a --- /dev/null +++ b/drivers/net/dsa/soce/soce_mdio.c @@ -0,0 +1,411 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2020-2026 System on Chip engineering, S.L. + * Copyright (c) 2026 Linutronix GmbH + * Author: Vasilij Strassheim + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "soce_dsa.h" +#include "soce_mdio.h" + +#define SOCE_MDIO_TIMEOUT 1000 +#define SOCE_MDIO_C22_REG_MAX 0x1f +#define SOCE_MDIO_C45_DEVAD_MAX 0x1f +#define SOCE_MDIO_C45_REG_MAX 0xffff + +static inline bool soce_mdio_output_valid(int mdio_output) +{ + return mdio_output >=3D 0 && mdio_output < SOCE_MAX_MDIO_OUTPUTS; +} + +static inline bool soce_mdio_addr_valid(int phy_addr) +{ + return phy_addr >=3D 0 && phy_addr < SOCE_MAX_MDIO_ADDR; +} + +static inline bool soce_mdio_c22_reg_valid(int regnum) +{ + return regnum >=3D 0 && regnum <=3D SOCE_MDIO_C22_REG_MAX; +} + +static inline bool soce_mdio_c45_params_valid(int devad, int regnum) +{ + return devad >=3D 0 && devad <=3D SOCE_MDIO_C45_DEVAD_MAX && + regnum >=3D 0 && regnum <=3D SOCE_MDIO_C45_REG_MAX; +} + +struct soce_mdio_bus { + struct dsa_switch *ds; + u32 mdio_output; +}; + +static int soce_mdio_read(struct mii_bus *bus, int addr, int reg) +{ + struct soce_mdio_bus *state =3D bus->priv; + struct soce_dsa_local *local; + struct soce_priv *priv; + int ret; + + priv =3D state->ds->priv; + local =3D &priv->local; + + if (!local->mdio_ops || !local->mdio_ops->phy_read) + return -EOPNOTSUPP; + + if (!soce_mdio_addr_valid(addr)) + return -EINVAL; + + mutex_lock(&local->mdio_lock); + ret =3D local->mdio_ops->phy_read(state->ds, state->mdio_output, addr, + reg); + mutex_unlock(&local->mdio_lock); + + return ret; +} + +static int soce_mdio_write(struct mii_bus *bus, int addr, int reg, u16 val) +{ + struct soce_mdio_bus *state =3D bus->priv; + struct soce_dsa_local *local; + struct soce_priv *priv; + int ret; + + priv =3D state->ds->priv; + local =3D &priv->local; + + if (!local->mdio_ops || !local->mdio_ops->phy_write) + return -EOPNOTSUPP; + + if (!soce_mdio_addr_valid(addr)) + return -EINVAL; + + mutex_lock(&local->mdio_lock); + ret =3D local->mdio_ops->phy_write(state->ds, state->mdio_output, addr, + reg, val); + mutex_unlock(&local->mdio_lock); + + return ret; +} + +static int soce_mdio_read_c45(struct mii_bus *bus, int addr, int devad, + int regnum) +{ + struct soce_mdio_bus *state =3D bus->priv; + struct soce_dsa_local *local; + struct soce_priv *priv; + int ret; + + priv =3D state->ds->priv; + local =3D &priv->local; + + if (!local->mdio_ops || !local->mdio_ops->phy_read_c45) + return -EOPNOTSUPP; + + if (!soce_mdio_addr_valid(addr)) + return -EINVAL; + + mutex_lock(&local->mdio_lock); + ret =3D local->mdio_ops->phy_read_c45(state->ds, state->mdio_output, + addr, devad, regnum); + mutex_unlock(&local->mdio_lock); + + return ret; +} + +static int soce_mdio_write_c45(struct mii_bus *bus, int addr, int devad, + int regnum, u16 val) +{ + struct soce_mdio_bus *state =3D bus->priv; + struct soce_dsa_local *local; + struct soce_priv *priv; + int ret; + + priv =3D state->ds->priv; + local =3D &priv->local; + + if (!local->mdio_ops || !local->mdio_ops->phy_write_c45) + return -EOPNOTSUPP; + + if (!soce_mdio_addr_valid(addr)) + return -EINVAL; + + mutex_lock(&local->mdio_lock); + ret =3D local->mdio_ops->phy_write_c45(state->ds, state->mdio_output, + addr, devad, regnum, val); + mutex_unlock(&local->mdio_lock); + + return ret; +} + +static int soce_register_mdio_bus(struct soce_priv *priv, struct device *d= ev, + struct device_node *mdio_np, + u32 mdio_output) +{ + struct soce_mdio_bus *state; + struct mii_bus *bus; + + bus =3D devm_mdiobus_alloc(dev); + if (!bus) + return -ENOMEM; + + state =3D devm_kzalloc(dev, sizeof(*state), GFP_KERNEL); + if (!state) + return -ENOMEM; + + state->ds =3D priv->ds; + state->mdio_output =3D mdio_output; + + bus->priv =3D state; + bus->name =3D "soce mdio"; + bus->read =3D soce_mdio_read; + bus->write =3D soce_mdio_write; + bus->read_c45 =3D soce_mdio_read_c45; + bus->write_c45 =3D soce_mdio_write_c45; + /* ds->dst can be NULL during probe, before dsa_register_switch() */ + snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mdio-%u", dev_name(dev), + mdio_output); + bus->parent =3D dev; + + return devm_of_mdiobus_register(dev, bus, mdio_np); +} + +int soce_sw_register_mdio_buses(struct soce_priv *priv, struct device *dev, + u32 numports) +{ + struct device_node *mdios_node; + u32 mdio_output; + int ret =3D 0; + + mdios_node =3D of_get_child_by_name(dev->of_node, "mdios"); + if (!mdios_node) + return 0; + + for_each_available_child_of_node_scoped(mdios_node, mdio_node) { + ret =3D of_property_read_u32(mdio_node, "reg", &mdio_output); + if (ret) { + dev_err(dev, "missing reg in %pOF\n", mdio_node); + goto out_put_mdio; + } + + if (mdio_output >=3D numports) { + dev_err(dev, + "MDIO output %u in %pOF exceeds hardware limit %u\n", + mdio_output, mdio_node, numports - 1); + ret =3D -EINVAL; + goto out_put_mdio; + } + + ret =3D soce_register_mdio_bus(priv, dev, mdio_node, mdio_output); + if (ret) + goto out_put_mdio; + } + +out_put_mdio: + of_node_put(mdios_node); + return ret; +} + +static int soce_mdio_23_02_wait_for_idle(struct dsa_switch *ds) +{ + struct soce_priv *priv =3D ds->priv; + struct soce_dsa_local *local; + void __iomem *ctrl; + u32 val; + + local =3D &priv->local; + ctrl =3D local->mdio_master_addr + SOCE_MDIO_CTRL_OFFSET; + + return readl_poll_timeout(ctrl, val, + !(val & (0x1 << SOCE_MDIO_23_02_CTRL_OPSTATUS_OFFSET)), 10, + SOCE_MDIO_TIMEOUT * 1000); +} + +static int soce_mdio_23_02_read_c22(struct dsa_switch *ds, int mdio_output, + int phy_addr, int regnum) +{ + void __iomem *ctrl, *params, *read_reg; + struct soce_priv *priv =3D ds->priv; + struct soce_dsa_local *local; + u32 regvalue; + int ret; + + local =3D &priv->local; + ctrl =3D local->mdio_master_addr + SOCE_MDIO_CTRL_OFFSET; + params =3D local->mdio_master_addr + SOCE_MDIO_23_02_PARAMS_OFFSET; + read_reg =3D local->mdio_master_addr + SOCE_MDIO_23_02_READ_OFFSET; + + regvalue =3D (regnum << SOCE_MDIO_23_02_CTRL_REGADDRDEVTYPE_OFFSET) + + (phy_addr << SOCE_MDIO_23_02_CTRL_PHYADDR_OFFSET); + writel(regvalue, params); + + regvalue =3D ((mdio_output << SOCE_MDIO_23_02_CTRL_BUS_OFFSET) + + (0x3 << SOCE_MDIO_23_02_CTRL_TRANSTYPE_OFFSET) + + (0x0 << SOCE_MDIO_23_02_CTRL_CLAUSE_OFFSET) + + (0x1 << SOCE_MDIO_23_02_CTRL_OPSTATUS_OFFSET)); + writel(regvalue, ctrl); + + ret =3D soce_mdio_23_02_wait_for_idle(ds); + if (ret) + return ret; + + return readl(read_reg) & 0xffff; +} + +int soce_mdio_23_02_read_c45(struct dsa_switch *ds, int mdio_output, + int phy_addr, int devad, int regnum) +{ + void __iomem *ctrl, *params, *read_reg, *write_reg; + struct soce_priv *priv =3D ds->priv; + struct soce_dsa_local *local; + u32 regvalue; + int ret; + + if (!soce_mdio_output_valid(mdio_output) || + !soce_mdio_addr_valid(phy_addr) || + !soce_mdio_c45_params_valid(devad, regnum)) + return -EINVAL; + + local =3D &priv->local; + ctrl =3D local->mdio_master_addr + SOCE_MDIO_CTRL_OFFSET; + params =3D local->mdio_master_addr + SOCE_MDIO_23_02_PARAMS_OFFSET; + write_reg =3D local->mdio_master_addr + SOCE_MDIO_23_02_WRITE_OFFSET; + read_reg =3D local->mdio_master_addr + SOCE_MDIO_23_02_READ_OFFSET; + + regvalue =3D (devad << SOCE_MDIO_23_02_CTRL_REGADDRDEVTYPE_OFFSET) + + (phy_addr << SOCE_MDIO_23_02_CTRL_PHYADDR_OFFSET); + writel(regvalue, params); + + writel(regnum, write_reg); + + /* address cycle */ + regvalue =3D ((mdio_output << SOCE_MDIO_23_02_CTRL_BUS_OFFSET) + + (0x0 << SOCE_MDIO_23_02_CTRL_TRANSTYPE_OFFSET) + + (0x1 << SOCE_MDIO_23_02_CTRL_CLAUSE_OFFSET) + + (0x1 << SOCE_MDIO_23_02_CTRL_OPSTATUS_OFFSET)); + writel(regvalue, ctrl); + + ret =3D soce_mdio_23_02_wait_for_idle(ds); + if (ret) + return ret; + + /* read cycle */ + regvalue =3D ((mdio_output << SOCE_MDIO_23_02_CTRL_BUS_OFFSET) + + (0x3 << SOCE_MDIO_23_02_CTRL_TRANSTYPE_OFFSET) + + (0x1 << SOCE_MDIO_23_02_CTRL_CLAUSE_OFFSET) + + (0x1 << SOCE_MDIO_23_02_CTRL_OPSTATUS_OFFSET)); + writel(regvalue, ctrl); + + ret =3D soce_mdio_23_02_wait_for_idle(ds); + if (ret) + return ret; + + return readl(read_reg) & 0xffff; +} + +int soce_mdio_23_02_read(struct dsa_switch *ds, int mdio_output, int phy_a= ddr, + int regnum) +{ + if (!soce_mdio_output_valid(mdio_output) || + !soce_mdio_addr_valid(phy_addr) || + !soce_mdio_c22_reg_valid(regnum)) + return -EINVAL; + + return soce_mdio_23_02_read_c22(ds, mdio_output, phy_addr, regnum); +} + +static int soce_mdio_23_02_write_c22(struct dsa_switch *ds, int mdio_outpu= t, + int phy_addr, int regnum, u16 val) +{ + void __iomem *ctrl, *params, *write_reg; + struct soce_priv *priv =3D ds->priv; + struct soce_dsa_local *local; + u32 regvalue; + + local =3D &priv->local; + params =3D local->mdio_master_addr + SOCE_MDIO_23_02_PARAMS_OFFSET; + ctrl =3D local->mdio_master_addr + SOCE_MDIO_CTRL_OFFSET; + write_reg =3D local->mdio_master_addr + SOCE_MDIO_23_02_WRITE_OFFSET; + + regvalue =3D (regnum << SOCE_MDIO_23_02_CTRL_REGADDRDEVTYPE_OFFSET) + + (phy_addr << SOCE_MDIO_23_02_CTRL_PHYADDR_OFFSET); + writel(regvalue, params); + + writel(val, write_reg); + + regvalue =3D ((mdio_output << SOCE_MDIO_23_02_CTRL_BUS_OFFSET) + + (0x1 << SOCE_MDIO_23_02_CTRL_TRANSTYPE_OFFSET) + + (0x0 << SOCE_MDIO_23_02_CTRL_CLAUSE_OFFSET) + + (0x1 << SOCE_MDIO_23_02_CTRL_OPSTATUS_OFFSET)); + writel(regvalue, ctrl); + + return soce_mdio_23_02_wait_for_idle(ds); +} + +int soce_mdio_23_02_write_c45(struct dsa_switch *ds, int mdio_output, + int phy_addr, int devad, int regnum, u16 val) +{ + void __iomem *ctrl, *params, *write_reg; + struct soce_priv *priv =3D ds->priv; + struct soce_dsa_local *local; + u32 regvalue; + int ret; + + if (!soce_mdio_output_valid(mdio_output) || + !soce_mdio_addr_valid(phy_addr) || + !soce_mdio_c45_params_valid(devad, regnum)) + return -EINVAL; + + local =3D &priv->local; + ctrl =3D local->mdio_master_addr + SOCE_MDIO_CTRL_OFFSET; + params =3D local->mdio_master_addr + SOCE_MDIO_23_02_PARAMS_OFFSET; + write_reg =3D local->mdio_master_addr + SOCE_MDIO_23_02_WRITE_OFFSET; + + regvalue =3D (devad << SOCE_MDIO_23_02_CTRL_REGADDRDEVTYPE_OFFSET) + + (phy_addr << SOCE_MDIO_23_02_CTRL_PHYADDR_OFFSET); + writel(regvalue, params); + + writel(regnum, write_reg); + + /* address cycle */ + regvalue =3D ((mdio_output << SOCE_MDIO_23_02_CTRL_BUS_OFFSET) + + (0x0 << SOCE_MDIO_23_02_CTRL_TRANSTYPE_OFFSET) + + (0x1 << SOCE_MDIO_23_02_CTRL_CLAUSE_OFFSET) + + (0x1 << SOCE_MDIO_23_02_CTRL_OPSTATUS_OFFSET)); + writel(regvalue, ctrl); + + ret =3D soce_mdio_23_02_wait_for_idle(ds); + if (ret) + return ret; + + writel(val, write_reg); + + /* write cycle */ + regvalue =3D ((mdio_output << SOCE_MDIO_23_02_CTRL_BUS_OFFSET) + + (0x1 << SOCE_MDIO_23_02_CTRL_TRANSTYPE_OFFSET) + + (0x1 << SOCE_MDIO_23_02_CTRL_CLAUSE_OFFSET) + + (0x1 << SOCE_MDIO_23_02_CTRL_OPSTATUS_OFFSET)); + writel(regvalue, ctrl); + + return soce_mdio_23_02_wait_for_idle(ds); +} + +int soce_mdio_23_02_write(struct dsa_switch *ds, int mdio_output, int phy_= addr, + int regnum, u16 val) +{ + if (!soce_mdio_output_valid(mdio_output) || + !soce_mdio_addr_valid(phy_addr) || + !soce_mdio_c22_reg_valid(regnum)) + return -EINVAL; + + return soce_mdio_23_02_write_c22(ds, mdio_output, phy_addr, regnum, val); +} diff --git a/drivers/net/dsa/soce/soce_mdio.h b/drivers/net/dsa/soce/soce_m= dio.h new file mode 100644 index 000000000000..f2b21fe50d79 --- /dev/null +++ b/drivers/net/dsa/soce/soce_mdio.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2020-2026 System on Chip engineering, S.L. + * Copyright (c) 2026 Linutronix GmbH + * Author: Vasilij Strassheim + */ + +#ifndef __SOCE_MDIO_H +#define __SOCE_MDIO_H + +#define SOCE_MDIO_CTRL_OFFSET 0x0000 + +/* for newer versions */ +#define SOCE_MDIO_23_02_PARAMS_OFFSET 0x0004 +#define SOCE_MDIO_23_02_WRITE_OFFSET 0x0008 +#define SOCE_MDIO_23_02_READ_OFFSET 0x000c +#define SOCE_MDIO_23_02_CTRL_BUS_OFFSET 16 +#define SOCE_MDIO_23_02_CTRL_TRANSTYPE_OFFSET 3 +#define SOCE_MDIO_23_02_CTRL_CLAUSE_OFFSET 1 +#define SOCE_MDIO_23_02_CTRL_OPSTATUS_OFFSET 0 + +#define SOCE_MDIO_23_02_CTRL_REGADDRDEVTYPE_OFFSET 8 +#define SOCE_MDIO_23_02_CTRL_PHYADDR_OFFSET 0 + +struct device; +struct soce_priv; + +int soce_mdio_23_02_read(struct dsa_switch *ds, int mdio_output, int phy_a= ddr, + int regnum); +int soce_mdio_23_02_write(struct dsa_switch *ds, int mdio_output, int phy_= addr, + int regnum, u16 val); +int soce_mdio_23_02_read_c45(struct dsa_switch *ds, int mdio_output, + int phy_addr, int devad, int regnum); +int soce_mdio_23_02_write_c45(struct dsa_switch *ds, int mdio_output, + int phy_addr, int devad, int regnum, u16 val); +int soce_sw_register_mdio_buses(struct soce_priv *priv, struct device *dev, + u32 numports); +#endif /* __SOCE_MDIO_H */ --=20 2.39.5