* [PATCH net-next v8 00/11] Support for onsemi's S2500 10Base-T1S MAC-PHY
@ 2026-09-28 22:25 Selvamani Rajagopal via B4 Relay
2026-09-28 22:25 ` [PATCH net-next v8 01/11] dt-bindings: net: add onsemi's S2500 Selvamani Rajagopal via B4 Relay
` (10 more replies)
0 siblings, 11 replies; 24+ messages in thread
From: Selvamani Rajagopal via B4 Relay @ 2026-09-28 22:25 UTC (permalink / raw)
To: Selva Rajagopal, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Piergiorgio Beruto, Parthiban Veerasooran,
Simon Horman, Jonathan Corbet, Shuah Khan, Randy Dunlap,
Richard Cochran, Andrew Lunn, Heiner Kallweit, Russell King
Cc: Selva Rajagopal, netdev, devicetree, linux-kernel, linux-doc,
Jerry Ray, Krzysztof Kozlowski
This patch series brings support for onsemi's S2500 that iss
IEEE 802.3cg compliant Ethernet transceiver with an integrated
Media Access Controller (MAC-PHY)
Driver implementation is compatible and works with OA TC6
framework that is already present. S2500 driver supports
hardware timestamping. Along with this driver, OA TC6
frame work is also changed to add hardware timestamping
support.
Driver has support for running selftest and loopback tests.
Through ethtool, it can provide traffic stats, rmon stats,
and timestamping related traffic stats.
As S2500 has an internal PHY, changes have been added
to onsemi's PHY driver to support this device.
To: Andrew Lunn <andrew@lunn.ch>
To: Piergiorgio Beruto <pier.beruto@onsemi.com>
To: Heiner Kallweit <hkallweit1@gmail.com>
To: Russell King <linux@armlinux.org.uk>
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: Andrew Lunn <andrew+netdev@lunn.ch>
To: Parthiban Veerasooran <parthiban.veerasooran@microchip.com>
To: Selva Rajagopal <selvamani.rajagopal@onsemi.com>
To: Richard Cochran <richardcochran@gmail.com>
To: Rob Herring <robh@kernel.org>
To: Krzysztof Kozlowski <krzk+dt@kernel.org>
To: Conor Dooley <conor+dt@kernel.org>
To: Simon Horman <horms@kernel.org>
To: Jonathan Corbet <corbet@lwn.net>
To: Shuah Khan <skhan@linuxfoundation.org>
To: Randy Dunlap <rdunlap@infradead.org>
Cc: netdev@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Cc: devicetree@vger.kernel.org
Cc: linux-doc@vger.kernel.org
Cc: Jerry Ray <jerry.ray@microchip.com>
Signed-off-by: Selvamani Rajagopal <Selvamani.Rajagopal@onsemi.com>
Changes in v8:
- Modified to use newer MMD based read/write APIs
- clean up by removing unused definitions/initializations
- Better handling of timestamp capture events by using
bit fields so that we don't lose any event
- timestamp skb queue is protected with spinlock
- added reset-gpio in YAML file as support is recently added
- removed ioctl from OA TC6 framework as it is not needed.
Changes in v7:
- Fixed compiler warning due to prototype mismatch
- Moved the order of patches to ensure dt-bindings comes first
before it is being used
- Added missing review tag
- Added missing MODULE_DEVICE_TABLE
- OA_TC6 framework enables 64 bit timestamping mode by default.
- Compiler related warnings fixed.
- Link to v6: https://lore.kernel.org/r/20260629-s2500-mac-phy-support-v6-0-18ce79500371@onsemi.com
Changes in v6:
- Changes to ensure onsemi code stay within 80 columns.
- Fixed the error of "not described in comments section"
in comments section.
- Fixed compiler warnings.
- Link to v5: https://patch.msgid.link/20260614-s2500-mac-phy-support-v5-0-89874b72f725@onsemi.com
Changes in v5:
- kernel doc related changes in oa_tc.c, onsemi driver files and
oa tc6 rst file
- Link to v4: https://lore.kernel.org/r/20260605-s2500-mac-phy-support-v4-0-de0fbc13c6d8@onsemi.com
Changes in v4:
- Added return value comment for genphy_read/write_phy_mmd functions
- Added genphy_loopback_fixed_speed helper function to be used in
set_loopback callbacks
- Updated networking documentation for OA TC6 framework to elaborate
on what is expected in the ptp_clock_info structure for registration.
- added spi-max-frequency in YAML file based on alert from sashiko-bot
- Removed model/version from the onsemi driver's private structure as
they were useful as "information-only" data.
- Replaced the non-standard selftest with Linux's standard selftest
and made it as a separate patch
- Changed bit manipulation, shift operations to use macros so that
it is clean and readable.
- added new read_register and write_register apis with _mms postfix
so that MMS (memory map selector) can be given as a parameter.
- Fixed the wrong condition check with NETIF_F_RXFCS to subtract
FCS size from the length of the frame.
- Link to v3: https://lore.kernel.org/r/CY8PR02MB92499C9080614FA3CEB8CD0483162@CY8PR02MB9249.namprd02.prod.outlook.com
Changes in v3:
- Moved OA TC6 framework to its own directory.
- Split changes to smaller patches based on feedback.
- Added PHY loopback support as a separate patch.
- New, read and write register APIs with extra parameter MMS
- Link to v2: https://lore.kernel.org/r/CY8PR02MB924920C8825C7AE5D22EFA4483382@CY8PR02MB9249.namprd02.prod.outlook.com
Changes in v2:
- API to add vendor specific MMS to mdio device map.
- Link to v1: https://lore.kernel.org/r/CY8PR02MB9249D083B637477C254F9B0583322@CY8PR02MB9249.namprd02.prod.outlook.com
---
Selvamani Rajagopal (11):
dt-bindings: net: add onsemi's S2500
Documentation: networking: Add timestamp related APIs to OA TC6 framework
net: ethernet: oa_tc6: Move oa_tc6.c to its own directory
net: ethernet: oa_tc6: Move constant definitions to header file
net: ethernet: oa_tc6: Support for hardware timestamp
net: ethernet: oa_tc6: Support for vendor specific MMS
net: phy: ncn26000: Support for onsemi's S2500 internal phy
net: phy: ncn26000: Enable enhanced noise immunity
net: phy: ncn26000: Support for loopback
onsemi: s2500: Add driver support for S2500 MAC-PHY
onsemi: s2500: Added selftest support to onsemi's S2500 driver
.../devicetree/bindings/net/onnn,s2500.yaml | 72 +++
Documentation/networking/oa-tc6-framework.rst | 59 +++
MAINTAINERS | 13 +-
drivers/net/ethernet/Kconfig | 13 +-
drivers/net/ethernet/Makefile | 3 +-
drivers/net/ethernet/adi/Kconfig | 1 +
drivers/net/ethernet/microchip/lan865x/Kconfig | 1 +
drivers/net/ethernet/oa_tc6/Kconfig | 17 +
drivers/net/ethernet/oa_tc6/Makefile | 7 +
drivers/net/ethernet/{ => oa_tc6}/oa_tc6.c | 433 ++++++++++++-----
drivers/net/ethernet/oa_tc6/oa_tc6_ptp.c | 65 +++
drivers/net/ethernet/oa_tc6/oa_tc6_std_def.h | 161 +++++++
drivers/net/ethernet/oa_tc6/oa_tc6_tstamp.c | 224 +++++++++
drivers/net/ethernet/onsemi/Kconfig | 22 +
drivers/net/ethernet/onsemi/Makefile | 7 +
drivers/net/ethernet/onsemi/s2500/Kconfig | 21 +
drivers/net/ethernet/onsemi/s2500/Makefile | 7 +
drivers/net/ethernet/onsemi/s2500/s2500_ethtool.c | 375 +++++++++++++++
drivers/net/ethernet/onsemi/s2500/s2500_hw_def.h | 160 +++++++
drivers/net/ethernet/onsemi/s2500/s2500_main.c | 523 +++++++++++++++++++++
drivers/net/ethernet/onsemi/s2500/s2500_ptp.c | 174 +++++++
drivers/net/phy/dp83867.c | 11 +-
drivers/net/phy/ncn26000.c | 63 ++-
drivers/net/phy/phy_device.c | 20 +
include/linux/oa_tc6.h | 25 +
include/linux/phy.h | 2 +
26 files changed, 2331 insertions(+), 148 deletions(-)
---
base-commit: 014d795c73837ea2339a4ea8e8f82c6e959b845d
change-id: 20260601-s2500-mac-phy-support-4f3ae920fb73
Best regards,
--
Selvamani Rajagopal <Selvamani.Rajagopal@onsemi.com>
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH net-next v8 01/11] dt-bindings: net: add onsemi's S2500
2026-09-28 22:25 [PATCH net-next v8 00/11] Support for onsemi's S2500 10Base-T1S MAC-PHY Selvamani Rajagopal via B4 Relay
@ 2026-09-28 22:25 ` Selvamani Rajagopal via B4 Relay
2026-09-28 22:46 ` Selvamani Rajagopal
2026-09-28 22:25 ` [PATCH net-next v8 02/11] Documentation: networking: Add timestamp related APIs to OA TC6 framework Selvamani Rajagopal via B4 Relay
` (9 subsequent siblings)
10 siblings, 1 reply; 24+ messages in thread
From: Selvamani Rajagopal via B4 Relay @ 2026-09-28 22:25 UTC (permalink / raw)
To: Selva Rajagopal, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Piergiorgio Beruto, Parthiban Veerasooran,
Simon Horman, Jonathan Corbet, Shuah Khan, Randy Dunlap,
Richard Cochran, Andrew Lunn, Heiner Kallweit, Russell King
Cc: Selva Rajagopal, netdev, devicetree, linux-kernel, linux-doc,
Jerry Ray, Krzysztof Kozlowski
From: Selvamani Rajagopal <Selvamani.Rajagopal@onsemi.com>
Add device tree binding for the onsemi S2500 IEEE 802.3cg
compliant Ethernet transceiver device.
S2500 has both Media Access Controller (MAC) and 10Base-T1S
Ethernet PHY. MAC implements 10 Mbps half duplex Ethernet
MAC. Communication between the host and MAC-PHY is defined in
OPEN Alliance 10BASE-T1x MACPHY Serial Interface document
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Signed-off-by: Selvamani Rajagopal <Selvamani.Rajagopal@onsemi.com>
---
changes in v8
- Changed the interrupt type to level triggered
- Added reset-gpio entry that was recently supported.
changes in v7
- Added the missing review tag
- Removed the word YAML from the commit message
changes in v6
- Moved the signed off information to the right place.
changes in v5
- no changes
changes in v4:
- added spi-max-frequency as suggested by AI review
- changed interrupt to IRQ_TYPE_EDGE_FALLING as it is
being taken care in net (stable) branch
changes in v3
- Removed URL link that failed verification
changes in v2
- removed spi-max-frequency entry
- changed the compatible string to s2500
changes in v1
- Added the first version of YAML file for onsemi MAC-PHY
---
.../devicetree/bindings/net/onnn,s2500.yaml | 72 ++++++++++++++++++++++
MAINTAINERS | 7 +++
2 files changed, 79 insertions(+)
diff --git a/Documentation/devicetree/bindings/net/onnn,s2500.yaml b/Documentation/devicetree/bindings/net/onnn,s2500.yaml
new file mode 100644
index 000000000000..97d1cda36683
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/onnn,s2500.yaml
@@ -0,0 +1,72 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/net/onnn,s2500.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: onsemi S2500 10BASE-T1S MACPHY Ethernet Controllers
+
+maintainers:
+ - Piergiorgio Beruto <pier.beruto@onsemi.com>
+ - Selva Rajagopal <Selvamani.Rajagopal@onsemi.com>
+
+description:
+ The S2500 combines a Media Access Controller (MAC) and an
+ Ethernet PHY to enable 10BASE‑T1S networks. The Ethernet Media Access
+ Controller (MAC) module implements a 10 Mbps half duplex Ethernet MAC,
+ compatible with the IEEE 802.3 standard and a 10BASE-T1S physical layer
+ transceiver integrated into the S2500. The communication between
+ the host and the MAC-PHY is specified in the OPEN Alliance 10BASE-T1x
+ MACPHY Serial Interface (TC6).
+
+allOf:
+ - $ref: /schemas/net/ethernet-controller.yaml#
+ - $ref: /schemas/spi/spi-peripheral-props.yaml#
+
+properties:
+ compatible:
+ const: onnn,s2500
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ description:
+ Interrupt from MAC-PHY asserted in the event of Receive Chunks
+ Available, Transmit Chunk Credits Available and Extended Status
+ Event.
+ maxItems: 1
+
+ reset-gpios:
+ description:
+ GPIO connected to the active-low RST_N pin of the MAC-PHY.
+ maxItems: 1
+
+ spi-max-frequency:
+ maximum: 25000000
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - spi-max-frequency
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/irq.h>
+ spi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ethernet@0 {
+ compatible = "onnn,s2500";
+ reg = <0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <ð0_pins>;
+ interrupt-parent = <&gpio>;
+ interrupts = <25 IRQ_TYPE_LEVEL_LOW>;
+ spi-max-frequency = <15000000>;
+ };
+ };
diff --git a/MAINTAINERS b/MAINTAINERS
index 6de1ff058db6..64da809e4602 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -20426,6 +20426,13 @@ S: Supported
W: http://www.onsemi.com
F: drivers/net/phy/ncn*
+ONSEMI S2500 10BASE-T1S MACPHY ETHERNET DRIVER
+M: Selva Rajagopal <selvamani.rajagopal@onsemi.com>
+L: netdev@vger.kernel.org
+S: Supported
+F: Documentation/devicetree/bindings/net/onnn,s2500.yaml
+F: drivers/net/ethernet/onsemi/s2500/s2500_*
+
OP-TEE DRIVER
M: Jens Wiklander <jenswi@kernel.org>
L: op-tee@lists.trustedfirmware.org (moderated for non-subscribers)
--
2.43.0
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH net-next v8 02/11] Documentation: networking: Add timestamp related APIs to OA TC6 framework
2026-09-28 22:25 [PATCH net-next v8 00/11] Support for onsemi's S2500 10Base-T1S MAC-PHY Selvamani Rajagopal via B4 Relay
2026-09-28 22:25 ` [PATCH net-next v8 01/11] dt-bindings: net: add onsemi's S2500 Selvamani Rajagopal via B4 Relay
@ 2026-09-28 22:25 ` Selvamani Rajagopal via B4 Relay
2026-10-06 12:15 ` Andrew Lunn
2026-09-28 22:25 ` [PATCH net-next v8 03/11] net: ethernet: oa_tc6: Move oa_tc6.c to its own directory Selvamani Rajagopal via B4 Relay
` (8 subsequent siblings)
10 siblings, 1 reply; 24+ messages in thread
From: Selvamani Rajagopal via B4 Relay @ 2026-09-28 22:25 UTC (permalink / raw)
To: Selva Rajagopal, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Piergiorgio Beruto, Parthiban Veerasooran,
Simon Horman, Jonathan Corbet, Shuah Khan, Randy Dunlap,
Richard Cochran, Andrew Lunn, Heiner Kallweit, Russell King
Cc: Selva Rajagopal, netdev, devicetree, linux-kernel, linux-doc, Jerry Ray
From: Selvamani Rajagopal <Selvamani.Rajagopal@onsemi.com>
Added new APIs to support hardware timestamp feature as defined in
OPEN Alliance 10BASE-T1x MAC-PHY serial interface specification.
Added the newer read/write APIs that takes MMS as one of its parameters
as these were not documented so far.
Signed-off-by: Selvamani Rajagopal <Selvamani.Rajagopal@onsemi.com>
---
changes in v8
- Updated the the order of the parameters in oa_tc6_read_register_mms
and oa_tc6_write_register_mms apis.
- Removed the reference to ioctl
changes in v7
- No change
changes in v6
- No change
changes in v5
- Fixed "no blank line" issues in four places
changes in v4
- Added information for new APIs in OA TC6 framework
changes in v3
- Added more information for documentation
changes in v2
- Removed the changes to the existing API
- Updated information about newly added APIs
changes in v1
- Added changes to an existing API
- Added documentation to new hardware timestamp related APIs
---
Documentation/networking/oa-tc6-framework.rst | 59 +++++++++++++++++++++++++++
1 file changed, 59 insertions(+)
diff --git a/Documentation/networking/oa-tc6-framework.rst b/Documentation/networking/oa-tc6-framework.rst
index 0feda2f9d840..5bcc194be7ea 100644
--- a/Documentation/networking/oa-tc6-framework.rst
+++ b/Documentation/networking/oa-tc6-framework.rst
@@ -153,6 +153,10 @@ OPEN Alliance TC6 Framework
- Forwards the received Ethernet frame from 10Base-T1x MAC-PHY to n/w
subsystem.
+- If supported by the hardware and enabled, updates hardware timestamp
+ in skb, when indicated by one of the three timestamp capture registers
+ through TSC fields of the header.
+
Data Transaction
~~~~~~~~~~~~~~~~
@@ -496,3 +500,58 @@ the MAC-PHY.
Zero align receive frame feature can be enabled to align all receive ethernet
frames data to start at the beginning of any receive data chunk payload with a
start word offset (SWO) of zero.
+
+.. c:function:: int oa_tc6_ptp_register(struct oa_tc6 *tc6, \
+ struct ptp_clock_info *info);
+
+Registers the PTP hardware clock related functions with the kernel.
+This API simply registers. Initialization of the fields in the
+ptp_clock_info structure are left to the vendor as programming hardware
+timer is expected to be vendor dependent. The fields max_adj, owner,
+and all the functions for the clock operations, like adjfine, gettimex64,
+settime64, adjtime are expected to be initialized in the structure before
+calling the registering the hardware clock.
+
+.. c:function:: void oa_tc6_ptp_unregister(struct oa_tc6 *tc6);
+
+Unregisters the PTP hardware clock related callbacks.
+
+.. c:function:: int oa_tc6_get_ts_info(struct oa_tc6 *tc6, \
+ struct kernel_ethtool_ts_info *info);
+
+Provides timestamp related settings that are supported to ethtool.
+
+.. c:function:: void oa_tc6_hwtstamp_get(struct oa_tc6 *tc6, \
+ struct kernel_hwtstamp_config *cfg);
+
+Returns hardware timestamp configuration. Part of net_device_ops callbacks.
+
+.. c:function:: void oa_tc6_get_ts_stats(struct oa_tc6 *tc6, \
+ struct ethtool_ts_stats *ts_stats);
+
+Provides hardware timestamp related traffic statistics for ethtool.
+
+.. c:function:: int oa_tc6_hwtstamp_set(struct oa_tc6 *tc6, \
+ struct kernel_hwtstamp_config *cfg);
+
+Helper to set hardware timestamp configuration. Part of net_device_ops
+callbacks.
+
+.. c:function:: void oa_tc6_set_vend1_mms(struct oa_tc6 *tc6, int mms);
+
+Helper to map MDIO_MMD_VEND1 command to vendor specific Memory Map Select
+(MMS) value. This function offers flexibility for vendors that may have
+used any MMS value between 10 and 15 as allowed by the specification.
+MDIO_MMD_VEND2 is already mapped to MMS4 in the OA TC6 frame work code.
+
+.. c:function:: int oa_tc6_write_register_mms(struct oa_tc6 *tc6, \
+ u8 mms, u16 address, \
+ u32 value);
+
+Write a single register addressed by @mms and @address in the MAC-PHY.
+
+.. c:function:: int oa_tc6_read_register_mms(struct oa_tc6 *tc6, \
+ u8 mms, u16 address, \
+ u32 *value);
+
+Read a single register addressed by @mms and @address in the MAC-PHY.
--
2.43.0
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH net-next v8 03/11] net: ethernet: oa_tc6: Move oa_tc6.c to its own directory
2026-09-28 22:25 [PATCH net-next v8 00/11] Support for onsemi's S2500 10Base-T1S MAC-PHY Selvamani Rajagopal via B4 Relay
2026-09-28 22:25 ` [PATCH net-next v8 01/11] dt-bindings: net: add onsemi's S2500 Selvamani Rajagopal via B4 Relay
2026-09-28 22:25 ` [PATCH net-next v8 02/11] Documentation: networking: Add timestamp related APIs to OA TC6 framework Selvamani Rajagopal via B4 Relay
@ 2026-09-28 22:25 ` Selvamani Rajagopal via B4 Relay
2026-10-06 12:22 ` Andrew Lunn
2026-09-28 22:25 ` [PATCH net-next v8 04/11] net: ethernet: oa_tc6: Move constant definitions to header file Selvamani Rajagopal via B4 Relay
` (7 subsequent siblings)
10 siblings, 1 reply; 24+ messages in thread
From: Selvamani Rajagopal via B4 Relay @ 2026-09-28 22:25 UTC (permalink / raw)
To: Selva Rajagopal, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Piergiorgio Beruto, Parthiban Veerasooran,
Simon Horman, Jonathan Corbet, Shuah Khan, Randy Dunlap,
Richard Cochran, Andrew Lunn, Heiner Kallweit, Russell King
Cc: Selva Rajagopal, netdev, devicetree, linux-kernel, linux-doc, Jerry Ray
From: Selvamani Rajagopal <Selvamani.Rajagopal@onsemi.com>
Moving oa_tc6.c to its own directory, drivers/net/ethernet/oa_tc6. This
will facilitate adding more files to support other features
defined by OPEN Alliance 10BASE-T1x Serial Interface specification
This patch series is adding two files, one for hardware
timestamp related functions and one for PTP related APIs.
Signed-off-by: Selvamani Rajagopal <Selvamani.Rajagopal@onsemi.com>
---
changes in v8
- No change
changes in v7
- No change
changes in v6
- No change
changes in v5
- No change
changes in v4
- Removed reference to onsemi in Kconfig files
changes in v3
- Moved oa_tc6.c to its own, oa_tc6 directory under ethernet.
- First patch
---
MAINTAINERS | 2 +-
drivers/net/ethernet/Kconfig | 12 +-----------
drivers/net/ethernet/Makefile | 2 +-
drivers/net/ethernet/oa_tc6/Kconfig | 16 ++++++++++++++++
drivers/net/ethernet/oa_tc6/Makefile | 7 +++++++
drivers/net/ethernet/{ => oa_tc6}/oa_tc6.c | 0
6 files changed, 26 insertions(+), 13 deletions(-)
diff --git a/MAINTAINERS b/MAINTAINERS
index 64da809e4602..541ed016144d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -20457,7 +20457,7 @@ M: Parthiban Veerasooran <parthiban.veerasooran@microchip.com>
L: netdev@vger.kernel.org
S: Maintained
F: Documentation/networking/oa-tc6-framework.rst
-F: drivers/net/ethernet/oa_tc6.c
+F: drivers/net/ethernet/oa_tc6/oa_tc6*
F: include/linux/oa_tc6.h
OPEN FIRMWARE AND FLATTENED DEVICE TREE
diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig
index c2b0161d0bec..5758e0fbbca5 100644
--- a/drivers/net/ethernet/Kconfig
+++ b/drivers/net/ethernet/Kconfig
@@ -135,6 +135,7 @@ source "drivers/net/ethernet/netronome/Kconfig"
source "drivers/net/ethernet/8390/Kconfig"
source "drivers/net/ethernet/nvidia/Kconfig"
source "drivers/net/ethernet/nxp/Kconfig"
+source "drivers/net/ethernet/oa_tc6/Kconfig"
source "drivers/net/ethernet/oki-semi/Kconfig"
config ETHOC
@@ -147,17 +148,6 @@ config ETHOC
help
Say Y here if you want to use the OpenCores 10/100 Mbps Ethernet MAC.
-config OA_TC6
- tristate "OPEN Alliance TC6 10BASE-T1x MAC-PHY support" if COMPILE_TEST
- depends on SPI
- select PHYLIB
- help
- This library implements OPEN Alliance TC6 10BASE-T1x MAC-PHY
- Serial Interface protocol for supporting 10BASE-T1x MAC-PHYs.
-
- To know the implementation details, refer documentation in
- <file:Documentation/networking/oa-tc6-framework.rst>.
-
source "drivers/net/ethernet/pasemi/Kconfig"
source "drivers/net/ethernet/pensando/Kconfig"
source "drivers/net/ethernet/qlogic/Kconfig"
diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile
index a306dae23bcb..e0e86c249e42 100644
--- a/drivers/net/ethernet/Makefile
+++ b/drivers/net/ethernet/Makefile
@@ -72,6 +72,7 @@ obj-$(CONFIG_NET_VENDOR_NETRONOME) += netronome/
obj-$(CONFIG_NET_VENDOR_NI) += ni/
obj-$(CONFIG_NET_VENDOR_NVIDIA) += nvidia/
obj-$(CONFIG_LPC_ENET) += nxp/
+obj-$(CONFIG_OA_TC6) += oa_tc6/
obj-$(CONFIG_NET_VENDOR_OKI) += oki-semi/
obj-$(CONFIG_ETHOC) += ethoc.o
obj-$(CONFIG_NET_VENDOR_PASEMI) += pasemi/
@@ -105,5 +106,4 @@ obj-$(CONFIG_NET_VENDOR_XILINX) += xilinx/
obj-$(CONFIG_NET_VENDOR_XIRCOM) += xircom/
obj-$(CONFIG_NET_VENDOR_SYNOPSYS) += synopsys/
obj-$(CONFIG_NET_VENDOR_PENSANDO) += pensando/
-obj-$(CONFIG_OA_TC6) += oa_tc6.o
obj-$(CONFIG_NET_VENDOR_ZTE) += zte/
diff --git a/drivers/net/ethernet/oa_tc6/Kconfig b/drivers/net/ethernet/oa_tc6/Kconfig
new file mode 100644
index 000000000000..97345f345fb9
--- /dev/null
+++ b/drivers/net/ethernet/oa_tc6/Kconfig
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# OA TC6 10BASE-T1x MAC-PHY configuration
+#
+
+config OA_TC6
+ tristate "OPEN Alliance TC6 10BASE-T1x MAC-PHY support"
+ depends on SPI
+ select PHYLIB
+ help
+ This library implements OPEN Alliance TC6 10BASE-T1x MAC-PHY
+ Serial Interface protocol for supporting 10BASE-T1x MAC-PHYs.
+
+ To know the implementation details, refer documentation in
+ <file:Documentation/networking/oa-tc6-framework.rst>.
+
diff --git a/drivers/net/ethernet/oa_tc6/Makefile b/drivers/net/ethernet/oa_tc6/Makefile
new file mode 100644
index 000000000000..f24aae852ef2
--- /dev/null
+++ b/drivers/net/ethernet/oa_tc6/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Makefile for OA TC6 10BASE-T1x MAC-PHY
+#
+
+obj-$(CONFIG_OA_TC6) := oa_tc6_mod.o
+oa_tc6_mod-objs := oa_tc6.o
diff --git a/drivers/net/ethernet/oa_tc6.c b/drivers/net/ethernet/oa_tc6/oa_tc6.c
similarity index 100%
rename from drivers/net/ethernet/oa_tc6.c
rename to drivers/net/ethernet/oa_tc6/oa_tc6.c
--
2.43.0
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH net-next v8 04/11] net: ethernet: oa_tc6: Move constant definitions to header file
2026-09-28 22:25 [PATCH net-next v8 00/11] Support for onsemi's S2500 10Base-T1S MAC-PHY Selvamani Rajagopal via B4 Relay
` (2 preceding siblings ...)
2026-09-28 22:25 ` [PATCH net-next v8 03/11] net: ethernet: oa_tc6: Move oa_tc6.c to its own directory Selvamani Rajagopal via B4 Relay
@ 2026-09-28 22:25 ` Selvamani Rajagopal via B4 Relay
2026-10-06 12:24 ` Andrew Lunn
2026-09-28 22:25 ` [PATCH net-next v8 05/11] net: ethernet: oa_tc6: Support for hardware timestamp Selvamani Rajagopal via B4 Relay
` (6 subsequent siblings)
10 siblings, 1 reply; 24+ messages in thread
From: Selvamani Rajagopal via B4 Relay @ 2026-09-28 22:25 UTC (permalink / raw)
To: Selva Rajagopal, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Piergiorgio Beruto, Parthiban Veerasooran,
Simon Horman, Jonathan Corbet, Shuah Khan, Randy Dunlap,
Richard Cochran, Andrew Lunn, Heiner Kallweit, Russell King
Cc: Selva Rajagopal, netdev, devicetree, linux-kernel, linux-doc, Jerry Ray
From: Selvamani Rajagopal <Selvamani.Rajagopal@onsemi.com>
To help other source files within the module share the
constant definitions, some of the definitions from oa_tc6.c
are moved to a header file. This header file is still
private to OA TC6 framework.
oa_tc6 structure is also moved to this header file as it is
needed for other source files that are part of OA TC6
framework.
Signed-off-by: Selvamani Rajagopal <Selvamani.Rajagopal@onsemi.com>
---
changes in v8:
- Merged with latest base version's changes
changes in v7
- No change
changes in v6
- No change
changes in v5
- No change
changes in v4
- Added MMS values 1 and 12, which are used now
changes in v3
- Moved constant definitions from the source to newly created
header file for other sources in the directory to share.
- Standard specific defines are moved to Linux common header file
- First patch
---
drivers/net/ethernet/oa_tc6/oa_tc6.c | 104 +---------------------
drivers/net/ethernet/oa_tc6/oa_tc6_std_def.h | 125 +++++++++++++++++++++++++++
2 files changed, 126 insertions(+), 103 deletions(-)
diff --git a/drivers/net/ethernet/oa_tc6/oa_tc6.c b/drivers/net/ethernet/oa_tc6/oa_tc6.c
index 364027c39fa4..f8e9309a72f1 100644
--- a/drivers/net/ethernet/oa_tc6/oa_tc6.c
+++ b/drivers/net/ethernet/oa_tc6/oa_tc6.c
@@ -14,109 +14,7 @@
#include <linux/phy.h>
#include <linux/oa_tc6.h>
-/* Control command header */
-#define OA_TC6_CTRL_HEADER_DATA_NOT_CTRL BIT(31)
-#define OA_TC6_CTRL_HEADER_WRITE_NOT_READ BIT(29)
-#define OA_TC6_CTRL_HEADER_MEM_MAP_SELECTOR GENMASK(27, 24)
-#define OA_TC6_CTRL_HEADER_ADDR GENMASK(23, 8)
-#define OA_TC6_CTRL_HEADER_LENGTH GENMASK(7, 1)
-#define OA_TC6_CTRL_HEADER_PARITY BIT(0)
-
-/* Data header */
-#define OA_TC6_DATA_HEADER_DATA_NOT_CTRL BIT(31)
-#define OA_TC6_DATA_HEADER_DATA_VALID BIT(21)
-#define OA_TC6_DATA_HEADER_START_VALID BIT(20)
-#define OA_TC6_DATA_HEADER_START_WORD_OFFSET GENMASK(19, 16)
-#define OA_TC6_DATA_HEADER_END_VALID BIT(14)
-#define OA_TC6_DATA_HEADER_END_BYTE_OFFSET GENMASK(13, 8)
-#define OA_TC6_DATA_HEADER_PARITY BIT(0)
-
-/* Data footer */
-#define OA_TC6_DATA_FOOTER_EXTENDED_STS BIT(31)
-#define OA_TC6_DATA_FOOTER_RXD_HEADER_BAD BIT(30)
-#define OA_TC6_DATA_FOOTER_CONFIG_SYNC BIT(29)
-#define OA_TC6_DATA_FOOTER_RX_CHUNKS GENMASK(28, 24)
-#define OA_TC6_DATA_FOOTER_DATA_VALID BIT(21)
-#define OA_TC6_DATA_FOOTER_START_VALID BIT(20)
-#define OA_TC6_DATA_FOOTER_START_WORD_OFFSET GENMASK(19, 16)
-#define OA_TC6_DATA_FOOTER_END_VALID BIT(14)
-#define OA_TC6_DATA_FOOTER_END_BYTE_OFFSET GENMASK(13, 8)
-#define OA_TC6_DATA_FOOTER_TX_CREDITS GENMASK(5, 1)
-
-#define OA_TC6_CTRL_PROT_REPLY_SIZE 4
-#define OA_TC6_CTRL_HEADER_SIZE 4
-#define OA_TC6_CTRL_REG_VALUE_SIZE 4
-#define OA_TC6_CTRL_IGNORED_SIZE 4
-#define OA_TC6_CTRL_MAX_REGISTERS 128
-#define OA_TC6_CTRL_SPI_BUF_SIZE (OA_TC6_CTRL_HEADER_SIZE +\
- (OA_TC6_CTRL_MAX_REGISTERS *\
- (OA_TC6_CTRL_REG_VALUE_SIZE +\
- OA_TC6_CTRL_PROT_REPLY_SIZE)) +\
- OA_TC6_CTRL_IGNORED_SIZE)
-
-#define OA_TC6_CHUNK_PAYLOAD_SIZE 64
-#define OA_TC6_DATA_HEADER_SIZE 4
-#define OA_TC6_CHUNK_SIZE (OA_TC6_DATA_HEADER_SIZE +\
- OA_TC6_CHUNK_PAYLOAD_SIZE)
-#define OA_TC6_MAX_TX_CHUNKS 48
-#define OA_TC6_SPI_DATA_BUF_SIZE (OA_TC6_MAX_TX_CHUNKS *\
- OA_TC6_CHUNK_SIZE)
-#define STATUS0_RESETC_POLL_DELAY 1000
-#define STATUS0_RESETC_POLL_TIMEOUT 1000000
-
-#define OA_TC6_REG_MMS_MASK GENMASK(19, 16)
-
-/* Internal structure for MAC-PHY drivers */
-struct oa_tc6 {
- struct net_device *netdev;
- struct phy_device *phydev;
- struct mii_bus *mdiobus;
- struct spi_device *spi;
- struct mutex spi_ctrl_lock; /* Protects spi control transfer */
- spinlock_t tx_skb_lock; /* Protects tx skb handling */
- void *spi_ctrl_tx_buf;
- void *spi_ctrl_rx_buf;
- void *spi_data_tx_buf;
- void *spi_data_rx_buf;
- struct sk_buff *ongoing_tx_skb;
- struct sk_buff *waiting_tx_skb;
- struct sk_buff *rx_skb;
- u16 tx_skb_offset;
- u16 spi_data_tx_buf_offset;
- u16 tx_credits;
- u8 rx_chunks_available;
- bool wait_until_start_valid;
- bool int_flag;
- bool disable_traffic;
- bool prot_ctrl;
- enum oa_tc6_quirk_flag quirk_flags;
- struct gpio_desc *reset_gpio;
-};
-
-enum oa_tc6_header_type {
- OA_TC6_CTRL_HEADER,
- OA_TC6_DATA_HEADER,
-};
-
-enum oa_tc6_register_op {
- OA_TC6_CTRL_REG_READ = 0,
- OA_TC6_CTRL_REG_WRITE = 1,
-};
-
-enum oa_tc6_data_valid_info {
- OA_TC6_DATA_INVALID,
- OA_TC6_DATA_VALID,
-};
-
-enum oa_tc6_data_start_valid_info {
- OA_TC6_DATA_START_INVALID,
- OA_TC6_DATA_START_VALID,
-};
-
-enum oa_tc6_data_end_valid_info {
- OA_TC6_DATA_END_INVALID,
- OA_TC6_DATA_END_VALID,
-};
+#include "oa_tc6_std_def.h"
static int oa_tc6_spi_transfer(struct oa_tc6 *tc6,
enum oa_tc6_header_type header_type, u16 length)
diff --git a/drivers/net/ethernet/oa_tc6/oa_tc6_std_def.h b/drivers/net/ethernet/oa_tc6/oa_tc6_std_def.h
new file mode 100644
index 000000000000..403a9c22b5f1
--- /dev/null
+++ b/drivers/net/ethernet/oa_tc6/oa_tc6_std_def.h
@@ -0,0 +1,125 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Register and driver related definitions to support
+ * OPEN Alliance 10BASE‑T1x MAC‑PHY Serial Interface framework.
+ *
+ * Author: Selva Rajagopal <selvamani.rajagopal@onsemi.com>
+ */
+
+#ifndef OA_TC6_STD_DEF_H
+#define OA_TC6_STD_DEF_H
+
+#include <linux/ptp_clock_kernel.h>
+#include <linux/net_tstamp.h>
+#include <linux/netdevice.h>
+#include <linux/spi/spi.h>
+#include <linux/skbuff.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/phy.h>
+
+/* Control command header */
+#define OA_TC6_CTRL_HEADER_DATA_NOT_CTRL BIT(31)
+#define OA_TC6_CTRL_HEADER_WRITE_NOT_READ BIT(29)
+#define OA_TC6_CTRL_HEADER_MEM_MAP_SELECTOR GENMASK(27, 24)
+#define OA_TC6_CTRL_HEADER_ADDR GENMASK(23, 8)
+#define OA_TC6_CTRL_HEADER_LENGTH GENMASK(7, 1)
+#define OA_TC6_CTRL_HEADER_PARITY BIT(0)
+
+/* Data header */
+#define OA_TC6_DATA_HEADER_DATA_NOT_CTRL BIT(31)
+#define OA_TC6_DATA_HEADER_DATA_VALID BIT(21)
+#define OA_TC6_DATA_HEADER_START_VALID BIT(20)
+#define OA_TC6_DATA_HEADER_START_WORD_OFFSET GENMASK(19, 16)
+#define OA_TC6_DATA_HEADER_END_VALID BIT(14)
+#define OA_TC6_DATA_HEADER_END_BYTE_OFFSET GENMASK(13, 8)
+#define OA_TC6_DATA_HEADER_PARITY BIT(0)
+
+/* Data footer */
+#define OA_TC6_DATA_FOOTER_EXTENDED_STS BIT(31)
+#define OA_TC6_DATA_FOOTER_RXD_HEADER_BAD BIT(30)
+#define OA_TC6_DATA_FOOTER_CONFIG_SYNC BIT(29)
+#define OA_TC6_DATA_FOOTER_RX_CHUNKS GENMASK(28, 24)
+#define OA_TC6_DATA_FOOTER_DATA_VALID BIT(21)
+#define OA_TC6_DATA_FOOTER_START_VALID BIT(20)
+#define OA_TC6_DATA_FOOTER_START_WORD_OFFSET GENMASK(19, 16)
+#define OA_TC6_DATA_FOOTER_END_VALID BIT(14)
+#define OA_TC6_DATA_FOOTER_END_BYTE_OFFSET GENMASK(13, 8)
+#define OA_TC6_DATA_FOOTER_TX_CREDITS GENMASK(5, 1)
+
+#define OA_TC6_CTRL_PROT_REPLY_SIZE 4
+#define OA_TC6_CTRL_HEADER_SIZE 4
+#define OA_TC6_CTRL_REG_VALUE_SIZE 4
+#define OA_TC6_CTRL_IGNORED_SIZE 4
+#define OA_TC6_CTRL_MAX_REGISTERS 128
+#define OA_TC6_CTRL_SPI_BUF_SIZE (OA_TC6_CTRL_HEADER_SIZE +\
+ (OA_TC6_CTRL_MAX_REGISTERS *\
+ (OA_TC6_CTRL_REG_VALUE_SIZE +\
+ OA_TC6_CTRL_PROT_REPLY_SIZE)) +\
+ OA_TC6_CTRL_IGNORED_SIZE)
+
+#define OA_TC6_CHUNK_PAYLOAD_SIZE 64
+#define OA_TC6_DATA_HEADER_SIZE 4
+#define OA_TC6_CHUNK_SIZE (OA_TC6_DATA_HEADER_SIZE +\
+ OA_TC6_CHUNK_PAYLOAD_SIZE)
+#define OA_TC6_MAX_TX_CHUNKS 48
+#define OA_TC6_SPI_DATA_BUF_SIZE (OA_TC6_MAX_TX_CHUNKS *\
+ OA_TC6_CHUNK_SIZE)
+#define STATUS0_RESETC_POLL_DELAY 1000
+#define STATUS0_RESETC_POLL_TIMEOUT 1000000
+
+#define OA_TC6_REG_MMS_MASK GENMASK(19, 16)
+
+/* Internal structure for MAC-PHY drivers */
+struct oa_tc6 {
+ struct net_device *netdev;
+ struct phy_device *phydev;
+ struct mii_bus *mdiobus;
+ struct spi_device *spi;
+ struct mutex spi_ctrl_lock; /* Protects spi control transfer */
+ spinlock_t tx_skb_lock; /* Protects tx skb handling */
+ void *spi_ctrl_tx_buf;
+ void *spi_ctrl_rx_buf;
+ void *spi_data_tx_buf;
+ void *spi_data_rx_buf;
+ struct sk_buff *ongoing_tx_skb;
+ struct sk_buff *waiting_tx_skb;
+ struct sk_buff *rx_skb;
+ u16 tx_skb_offset;
+ u16 spi_data_tx_buf_offset;
+ u16 tx_credits;
+ u8 rx_chunks_available;
+ bool wait_until_start_valid;
+ bool int_flag;
+ bool disable_traffic;
+ bool prot_ctrl;
+ enum oa_tc6_quirk_flag quirk_flags;
+ struct gpio_desc *reset_gpio;
+};
+
+enum oa_tc6_header_type {
+ OA_TC6_CTRL_HEADER,
+ OA_TC6_DATA_HEADER,
+};
+
+enum oa_tc6_register_op {
+ OA_TC6_CTRL_REG_READ = 0,
+ OA_TC6_CTRL_REG_WRITE = 1,
+};
+
+enum oa_tc6_data_valid_info {
+ OA_TC6_DATA_INVALID,
+ OA_TC6_DATA_VALID,
+};
+
+enum oa_tc6_data_start_valid_info {
+ OA_TC6_DATA_START_INVALID,
+ OA_TC6_DATA_START_VALID,
+};
+
+enum oa_tc6_data_end_valid_info {
+ OA_TC6_DATA_END_INVALID,
+ OA_TC6_DATA_END_VALID,
+};
+#endif /* OA_TC6_STD_DEF_H */
+
--
2.43.0
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH net-next v8 05/11] net: ethernet: oa_tc6: Support for hardware timestamp
2026-09-28 22:25 [PATCH net-next v8 00/11] Support for onsemi's S2500 10Base-T1S MAC-PHY Selvamani Rajagopal via B4 Relay
` (3 preceding siblings ...)
2026-09-28 22:25 ` [PATCH net-next v8 04/11] net: ethernet: oa_tc6: Move constant definitions to header file Selvamani Rajagopal via B4 Relay
@ 2026-09-28 22:25 ` Selvamani Rajagopal via B4 Relay
2026-10-06 1:08 ` Jakub Kicinski
2026-10-06 12:48 ` Andrew Lunn
2026-09-28 22:25 ` [PATCH net-next v8 06/11] net: ethernet: oa_tc6: Support for vendor specific MMS Selvamani Rajagopal via B4 Relay
` (5 subsequent siblings)
10 siblings, 2 replies; 24+ messages in thread
From: Selvamani Rajagopal via B4 Relay @ 2026-09-28 22:25 UTC (permalink / raw)
To: Selva Rajagopal, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Piergiorgio Beruto, Parthiban Veerasooran,
Simon Horman, Jonathan Corbet, Shuah Khan, Randy Dunlap,
Richard Cochran, Andrew Lunn, Heiner Kallweit, Russell King
Cc: Selva Rajagopal, netdev, devicetree, linux-kernel, linux-doc, Jerry Ray
From: Selvamani Rajagopal <Selvamani.Rajagopal@onsemi.com>
PTP register/unregister calls are implemented in oa_tc6_ptp.c.
The APIs that work with the hardware for timestamp is provided
by vendor code as it may be vendor dependent.
Interface for ndo_hwtstamp_set/get, control and status
callback for ethtool are provided to support hardware timestamp
feature. ioctl interface passes the request to PHY.
Hardware timestamp functions that handle the traffic are generally
placed in oa_tc6.c. Rest of the timestamp functionalities, mostly
helper functions are in oa_tc6_tstamp.c.
When all the three timestamp capture registers are busy and not
available, driver drops the incoming TX SKB, if it comes with the
request for hardware timestamping. Normal traffic without timestamp
request is not affected.
Practically, application using hardware timestamp is not expected to
hit this scenario as three timestamp capture registers are plenty
considering the amount of traffic expected in such applications.
Signed-off-by: Selvamani Rajagopal <Selvamani.Rajagopal@onsemi.com>
---
changes in v8
- Moved few timestamp defintions to header file from source file.
- Improved logic in handling timestamp capture register events.
- timestamp skb queue is protected inside spinlock
- Removed unnecessary ioctl callback
changes in v7
- Fixed the parameter name mismatch in function protoype and
definition
- CONFIG0 is set with 64 bit timestamp support by default.
- Added information about return value for API documentation.
changes in v6
- Fixed the issue of function parameter in oa_tc6_get_ts_stats
not described in comments section for documentation.
- Avoided typecasting __be32 as u32
changes in v5
- As subtracting skb len by FCS size is considered bug, changes
are removed. Will be fixed in stable branch (net repo)
changes in v4
- Fixed the condition check for subtracting the FCS size
from skb len.
changes in v3
- Replaced warning printk with ratelimited printk
- Checking the hardware register before enabling hardware
timestamp
changes in v1
- Added hardware timestamp support to the OA TC6 framework.
---
MAINTAINERS | 1 +
drivers/net/ethernet/adi/Kconfig | 1 +
drivers/net/ethernet/microchip/lan865x/Kconfig | 1 +
drivers/net/ethernet/oa_tc6/Kconfig | 1 +
drivers/net/ethernet/oa_tc6/Makefile | 2 +-
drivers/net/ethernet/oa_tc6/oa_tc6.c | 317 +++++++++++++++++++++++--
drivers/net/ethernet/oa_tc6/oa_tc6_ptp.c | 65 +++++
drivers/net/ethernet/oa_tc6/oa_tc6_std_def.h | 35 +++
drivers/net/ethernet/oa_tc6/oa_tc6_tstamp.c | 224 +++++++++++++++++
include/linux/oa_tc6.h | 23 ++
10 files changed, 653 insertions(+), 17 deletions(-)
diff --git a/MAINTAINERS b/MAINTAINERS
index 541ed016144d..5c7028c94f56 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -20454,6 +20454,7 @@ F: drivers/rtc/rtc-optee.c
OPEN ALLIANCE 10BASE-T1S MACPHY SERIAL INTERFACE FRAMEWORK
M: Parthiban Veerasooran <parthiban.veerasooran@microchip.com>
+M: Selva Rajagopal <selvamani.rajagopal@onsemi.com> (timestamp support)
L: netdev@vger.kernel.org
S: Maintained
F: Documentation/networking/oa-tc6-framework.rst
diff --git a/drivers/net/ethernet/adi/Kconfig b/drivers/net/ethernet/adi/Kconfig
index bdb8ff7d15da..120a52e6b283 100644
--- a/drivers/net/ethernet/adi/Kconfig
+++ b/drivers/net/ethernet/adi/Kconfig
@@ -29,6 +29,7 @@ config ADIN1110
config ADIN1140
tristate "Analog Devices ADIN1140 MAC-PHY"
depends on SPI
+ depends on PTP_1588_CLOCK_OPTIONAL
select ADIN1140_PHY
select OA_TC6
help
diff --git a/drivers/net/ethernet/microchip/lan865x/Kconfig b/drivers/net/ethernet/microchip/lan865x/Kconfig
index 7f2a4e7e1915..342172cb8837 100644
--- a/drivers/net/ethernet/microchip/lan865x/Kconfig
+++ b/drivers/net/ethernet/microchip/lan865x/Kconfig
@@ -8,6 +8,7 @@ if NET_VENDOR_MICROCHIP
config LAN865X
tristate "LAN865x support"
depends on SPI
+ depends on PTP_1588_CLOCK_OPTIONAL
select OA_TC6
help
Support for the Microchip LAN8650/1 Rev.B0/B1 MACPHY Ethernet chip. It
diff --git a/drivers/net/ethernet/oa_tc6/Kconfig b/drivers/net/ethernet/oa_tc6/Kconfig
index 97345f345fb9..b7886ca13952 100644
--- a/drivers/net/ethernet/oa_tc6/Kconfig
+++ b/drivers/net/ethernet/oa_tc6/Kconfig
@@ -6,6 +6,7 @@
config OA_TC6
tristate "OPEN Alliance TC6 10BASE-T1x MAC-PHY support"
depends on SPI
+ depends on PTP_1588_CLOCK_OPTIONAL
select PHYLIB
help
This library implements OPEN Alliance TC6 10BASE-T1x MAC-PHY
diff --git a/drivers/net/ethernet/oa_tc6/Makefile b/drivers/net/ethernet/oa_tc6/Makefile
index f24aae852ef2..964f668efc2d 100644
--- a/drivers/net/ethernet/oa_tc6/Makefile
+++ b/drivers/net/ethernet/oa_tc6/Makefile
@@ -4,4 +4,4 @@
#
obj-$(CONFIG_OA_TC6) := oa_tc6_mod.o
-oa_tc6_mod-objs := oa_tc6.o
+oa_tc6_mod-objs := oa_tc6.o oa_tc6_ptp.o oa_tc6_tstamp.o
diff --git a/drivers/net/ethernet/oa_tc6/oa_tc6.c b/drivers/net/ethernet/oa_tc6/oa_tc6.c
index f8e9309a72f1..5cbe049f76ef 100644
--- a/drivers/net/ethernet/oa_tc6/oa_tc6.c
+++ b/drivers/net/ethernet/oa_tc6/oa_tc6.c
@@ -8,6 +8,7 @@
#include <linux/bitfield.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
+#include <linux/bitops.h>
#include <linux/iopoll.h>
#include <linux/interrupt.h>
#include <linux/mdio.h>
@@ -16,6 +17,16 @@
#include "oa_tc6_std_def.h"
+struct oa_tc6_ts_info_rx {
+ bool rtsa;
+ bool rtsp;
+};
+
+struct oa_tc6_ts_info_tx {
+ ktime_t hwtstamp;
+ u8 tsc;
+};
+
static int oa_tc6_spi_transfer(struct oa_tc6 *tc6,
enum oa_tc6_header_type header_type, u16 length)
{
@@ -50,6 +61,195 @@ static int oa_tc6_get_parity(u32 p)
return !((p >> 28) & 1);
}
+static struct oa_tc6_ts_info_tx *oa_tc6_tsinfo_tx(struct sk_buff *skb)
+{
+ return (struct oa_tc6_ts_info_tx *)(skb->cb);
+}
+
+static struct oa_tc6_ts_info_rx *oa_tc6_tsinfo_rx(struct sk_buff *skb)
+{
+ return (struct oa_tc6_ts_info_rx *)(skb->cb);
+}
+
+static u8 oa_tc6_next_tsc(u8 tsc)
+{
+ return tsc < OA_TC6_TTSCC_REG_ID ? tsc + 1 : OA_TC6_TTSCA_REG_ID;
+}
+
+static bool oa_tc6_req_tx_hwtstamp(struct oa_tc6 *tc6, struct sk_buff *skb)
+{
+ bool drop = false;
+ u8 tsc;
+ u8 i;
+
+ lockdep_assert_held(&tc6->tx_skb_lock);
+
+ if (!skb || !(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP))
+ return drop;
+
+ if (!tc6->hw_tstamp_enabled)
+ goto out;
+ if (tc6->ts_config.tx_type != HWTSTAMP_TX_ON) {
+ tc6->tx_hwtstamp_lost++;
+ goto out;
+ }
+
+ tsc = tc6->ttsc_current_id;
+ for (i = 0; i < OA_TC6_TTSCC_REG_ID; i++) {
+ if (!(tc6->ts_ttsc_pending & BIT(tsc -
+ OA_TC6_TTSCA_REG_ID)))
+ goto slot_found;
+ tsc = oa_tc6_next_tsc(tsc);
+ }
+
+ /* All the three slots are waiting for its event. This skb
+ * can't request timestamp. Marking it to be dropped.
+ */
+ tc6->tx_hwtstamp_lost++;
+ drop = true;
+ goto out;
+
+slot_found:
+ tc6->ts_ttsc_pending |= BIT(tsc - OA_TC6_TTSCA_REG_ID);
+ tc6->ttsc_current_id = oa_tc6_next_tsc(tsc);
+ oa_tc6_tsinfo_tx(skb)->tsc = tsc;
+ skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+out:
+ return drop;
+}
+
+static void oa_tc6_events_handle(struct oa_tc6 *tc6, u32 val, const u32 *ts)
+{
+ struct skb_shared_hwtstamps tstamp;
+ struct oa_tc6_ts_info_tx *ski;
+ struct sk_buff *skb, *tmp;
+ LIST_HEAD(deliver);
+ LIST_HEAD(drop);
+ u8 tsc, bit_num;
+ u32 handled = 0;
+ u32 event;
+
+ spin_lock_bh(&tc6->tx_skb_lock);
+ list_for_each_entry_safe(skb, tmp, &tc6->tx_ts_skb_q, list) {
+ ski = oa_tc6_tsinfo_tx(skb);
+ tsc = ski->tsc;
+ bit_num = tsc - OA_TC6_TTSCA_REG_ID;
+ event = OA_TC6_STATUS0_TTSCAA << bit_num;
+ if (!(val & event))
+ continue;
+ if (handled & event) {
+ dev_warn_ratelimited(&tc6->spi->dev,
+ "Multiple skbs\n");
+ tc6->tx_hwtstamp_err++;
+ list_move_tail(&skb->list, &drop);
+ continue;
+ }
+
+ handled |= event;
+ tc6->ts_ttsc_pending &= ~BIT(bit_num);
+
+ ski->hwtstamp = ktime_set(ts[2 * bit_num],
+ ts[2 * bit_num + 1]);
+ tc6->tx_hwtstamp_pkts++;
+ list_move_tail(&skb->list, &deliver);
+ }
+ spin_unlock_bh(&tc6->tx_skb_lock);
+
+ /* skb_tstamp_tx() clones the skb and wakes the owning socket, so keep
+ * it out of the lock that oa_tc6_start_xmit() takes.
+ */
+ list_for_each_entry_safe(skb, tmp, &deliver, list) {
+ list_del(&skb->list);
+ memset(&tstamp, 0, sizeof(tstamp));
+ tstamp.hwtstamp = oa_tc6_tsinfo_tx(skb)->hwtstamp;
+ skb_tstamp_tx(skb, &tstamp);
+ dev_kfree_skb(skb);
+ }
+
+ list_for_each_entry_safe(skb, tmp, &drop, list) {
+ list_del(&skb->list);
+ dev_kfree_skb(skb);
+ }
+
+ if (val & ~handled) {
+ tc6->tx_hwtstamp_err += hweight32(val & ~handled);
+ dev_warn_ratelimited(&tc6->spi->dev,
+ "Unexpected event: 0x%x\n",
+ val & ~handled);
+ }
+}
+
+void oa_tc6_cleanup_tx_tstamp_skbs(struct oa_tc6 *tc6)
+{
+ struct sk_buff *skb, *tmp;
+
+ spin_lock_bh(&tc6->tx_skb_lock);
+ list_for_each_entry_safe(skb, tmp, &tc6->tx_ts_skb_q, list) {
+ list_del(&skb->list);
+ tc6->ts_ttsc_pending &= ~BIT(oa_tc6_tsinfo_tx(skb)->tsc -
+ OA_TC6_TTSCA_REG_ID);
+ dev_kfree_skb(skb);
+
+ /* The frame was transmitted, only its timestamp is lost. */
+ tc6->tx_hwtstamp_lost++;
+ }
+ spin_unlock_bh(&tc6->tx_skb_lock);
+}
+
+static int oa_tc6_update_ts_in_rx_skb(struct oa_tc6 *tc6)
+{
+ unsigned int expected_len = ETH_HLEN;
+ struct sk_buff *skb = tc6->rx_skb;
+ struct oa_tc6_ts_info_rx *ski;
+ __be32 ts_val[2];
+ u32 ts[2];
+
+ ski = oa_tc6_tsinfo_rx(skb);
+ if (ski->rtsa)
+ expected_len += OA_TC6_TSTAMP_SZ;
+
+ if (skb->len < expected_len) {
+ tc6->netdev->stats.rx_length_errors++;
+ return -EINVAL;
+ }
+
+ if (!ski->rtsa)
+ return 0;
+
+ memcpy(&ts_val[0], skb->data, 4);
+ memcpy(&ts_val[1], (u32 *)skb->data + 1, 4);
+
+ ts[0] = be32_to_cpu(ts_val[0]);
+ ts[1] = be32_to_cpu(ts_val[1]);
+
+ /* Check parity */
+ if ((oa_tc6_get_parity(ts[0]) ^ oa_tc6_get_parity(ts[1])) ==
+ !ski->rtsp) {
+ struct skb_shared_hwtstamps *hw_ts;
+
+ /* Report timestamp to the upper layers */
+ hw_ts = skb_hwtstamps(skb);
+ memset(hw_ts, 0, sizeof(*hw_ts));
+ hw_ts->hwtstamp = ktime_set(ts[0], ts[1]);
+ }
+ skb_pull(skb, sizeof(ts));
+
+ return 0;
+}
+
+static int oa_tc6_update_standard_capability(struct oa_tc6 *tc6)
+{
+ u32 regval = 0;
+ int ret;
+
+ ret = oa_tc6_read_register(tc6, OA_TC6_REG_STDCAP, ®val);
+ if (ret)
+ return ret;
+ if (regval & OA_TC6_STDCAP_TIMESTAMP_CAPABILITY)
+ tc6->hw_tstamp_supported = true;
+ return 0;
+}
+
static __be32 oa_tc6_prepare_ctrl_header(u32 addr, u8 length,
enum oa_tc6_register_op reg_op)
{
@@ -625,6 +825,17 @@ static void oa_tc6_cleanup_ongoing_rx_skb(struct oa_tc6 *tc6)
static void oa_tc6_cleanup_ongoing_tx_skb(struct oa_tc6 *tc6)
{
+ if (tc6->ongoing_tx_skb &&
+ (skb_shinfo(tc6->ongoing_tx_skb)->tx_flags &
+ SKBTX_IN_PROGRESS)) {
+ u8 tsc = oa_tc6_tsinfo_tx(tc6->ongoing_tx_skb)->tsc;
+
+ spin_lock_bh(&tc6->tx_skb_lock);
+ tc6->ts_ttsc_pending &= ~BIT(tsc - OA_TC6_TTSCA_REG_ID);
+ spin_unlock_bh(&tc6->tx_skb_lock);
+ }
+
+ tc6->tx_skb_offset = 0;
oa_tc6_drop_tx_skb(tc6, tc6->ongoing_tx_skb);
tc6->ongoing_tx_skb = NULL;
}
@@ -650,6 +861,7 @@ static void oa_tc6_free_pending_skbs(struct oa_tc6 *tc6)
{
oa_tc6_free_ongoing_skbs(tc6);
oa_tc6_cleanup_waiting_tx_skb(tc6);
+ oa_tc6_cleanup_tx_tstamp_skbs(tc6);
}
static void oa_tc6_look_for_new_frame(struct oa_tc6 *tc6)
@@ -678,6 +890,8 @@ static void oa_tc6_disable_traffic(struct oa_tc6 *tc6)
netif_tx_disable(tc6->netdev);
oa_tc6_drop_tx_skb(tc6, skb);
oa_tc6_free_ongoing_skbs(tc6);
+ oa_tc6_cleanup_tx_tstamp_skbs(tc6);
+
oa_tc6_write_register(tc6, OA_TC6_REG_INT_MASK0, regval);
oa_tc6_read_register(tc6, OA_TC6_REG_STATUS0, ®val);
oa_tc6_write_register(tc6, OA_TC6_REG_STATUS0, regval);
@@ -686,15 +900,28 @@ static void oa_tc6_disable_traffic(struct oa_tc6 *tc6)
static int oa_tc6_process_extended_status(struct oa_tc6 *tc6)
{
+ u32 regs[OA_TC6_STATUS0_TTSC_REG_COUNT];
+ bool ts_valid = !!tc6->ptp_clock;
u32 value;
int ret;
- ret = oa_tc6_read_register(tc6, OA_TC6_REG_STATUS0, &value);
+ /* When timestamp is disabled, there is no behavior change
+ * as it reads only STATUS0 register. When enabled,
+ * TTSCA_HIGH..TTSCC_LOW are fetched together with STATUS0
+ * to avoid having to make second SPI transaction. Reading few
+ * extra registers, even it may not be needed every time this
+ * function is called, it is more efficient than making second
+ * SPI transaction, when needed.
+ */
+ ret = oa_tc6_read_registers(tc6, OA_TC6_REG_STATUS0, regs,
+ ts_valid ?
+ OA_TC6_STATUS0_TTSC_REG_COUNT : 1);
if (ret) {
netdev_err(tc6->netdev, "STATUS0 register read failed: %d\n",
ret);
return ret;
}
+ value = regs[0];
/* This function is called for each chunk received in a given SPI
* transaction. In case, extended status bit is set in more than
@@ -703,6 +930,11 @@ static int oa_tc6_process_extended_status(struct oa_tc6 *tc6)
if (!value)
return 0;
+ if ((value & OA_TC6_STATUS0_TTSCA_MASK) != 0)
+ oa_tc6_events_handle(tc6, value &
+ OA_TC6_STATUS0_TTSCA_MASK,
+ ®s[OA_TC6_TTSC_REG_OFFSET]);
+
/* Clear the error interrupts status */
ret = oa_tc6_write_register(tc6, OA_TC6_REG_STATUS0, value);
if (ret) {
@@ -788,6 +1020,13 @@ static void oa_tc6_submit_rx_skb(struct oa_tc6 *tc6)
tc6->rx_skb->len > ETH_FCS_LEN)
skb_trim(tc6->rx_skb, tc6->rx_skb->len - ETH_FCS_LEN);
+ if (oa_tc6_update_ts_in_rx_skb(tc6)) {
+ tc6->netdev->stats.rx_dropped++;
+ dev_kfree_skb_any(tc6->rx_skb);
+ tc6->rx_skb = NULL;
+ return;
+ }
+
tc6->rx_skb->protocol = eth_type_trans(tc6->rx_skb, tc6->netdev);
tc6->netdev->stats.rx_packets++;
tc6->netdev->stats.rx_bytes += tc6->rx_skb->len;
@@ -823,25 +1062,32 @@ static int oa_tc6_update_rx_skb(struct oa_tc6 *tc6, u8 *payload, u8 length)
* buffer pointer. We should release, if a valid pointer is found before
* allocating a new one.
*/
-static int oa_tc6_allocate_rx_skb(struct oa_tc6 *tc6)
+static int oa_tc6_allocate_rx_skb(struct oa_tc6 *tc6, u32 footer)
{
+ struct oa_tc6_ts_info_rx *ski;
+
oa_tc6_cleanup_ongoing_rx_skb(tc6);
- tc6->rx_skb = netdev_alloc_skb_ip_align(tc6->netdev, tc6->netdev->mtu +
- ETH_HLEN + ETH_FCS_LEN);
+ tc6->rx_skb = netdev_alloc_skb_ip_align(tc6->netdev,
+ tc6->netdev->mtu +
+ ETH_HLEN + ETH_FCS_LEN +
+ OA_TC6_TSTAMP_SZ);
if (!tc6->rx_skb) {
tc6->netdev->stats.rx_dropped++;
return -ENOMEM;
}
+ ski = oa_tc6_tsinfo_rx(tc6->rx_skb);
+ ski->rtsa = FIELD_GET(OA_TC6_DATA_FOOTER_RTSA_VALID, footer);
+ ski->rtsp = FIELD_GET(OA_TC6_DATA_FOOTER_RTSP_VALID, footer);
return 0;
}
static int oa_tc6_prcs_complete_rx_frame(struct oa_tc6 *tc6, u8 *payload,
- u16 size)
+ u16 size, u32 footer)
{
int ret;
- ret = oa_tc6_allocate_rx_skb(tc6);
+ ret = oa_tc6_allocate_rx_skb(tc6, footer);
if (ret)
return ret;
@@ -854,11 +1100,11 @@ static int oa_tc6_prcs_complete_rx_frame(struct oa_tc6 *tc6, u8 *payload,
return 0;
}
-static int oa_tc6_prcs_rx_frame_start(struct oa_tc6 *tc6, u8 *payload, u16 size)
+static int oa_tc6_prcs_rx_frame_start(struct oa_tc6 *tc6, u8 *payload, u16 size, u32 footer)
{
int ret;
- ret = oa_tc6_allocate_rx_skb(tc6);
+ ret = oa_tc6_allocate_rx_skb(tc6, footer);
if (ret)
return ret;
@@ -905,7 +1151,7 @@ static int oa_tc6_prcs_rx_chunk_payload(struct oa_tc6 *tc6, u8 *data,
size = end_byte_offset + 1 - start_byte_offset;
return oa_tc6_prcs_complete_rx_frame(tc6,
&data[start_byte_offset],
- size);
+ size, footer);
}
/* Process the chunk with only rx frame start */
@@ -913,7 +1159,7 @@ static int oa_tc6_prcs_rx_chunk_payload(struct oa_tc6 *tc6, u8 *data,
size = OA_TC6_CHUNK_PAYLOAD_SIZE - start_byte_offset;
return oa_tc6_prcs_rx_frame_start(tc6,
&data[start_byte_offset],
- size);
+ size, footer);
}
/* Process the chunk with only rx frame end */
@@ -946,7 +1192,7 @@ static int oa_tc6_prcs_rx_chunk_payload(struct oa_tc6 *tc6, u8 *data,
size = OA_TC6_CHUNK_PAYLOAD_SIZE - start_byte_offset;
return oa_tc6_prcs_rx_frame_start(tc6,
&data[start_byte_offset],
- size);
+ size, footer);
}
/* Process the chunk with ongoing rx frame data */
@@ -1025,13 +1271,15 @@ static int oa_tc6_process_spi_data_rx_buf(struct oa_tc6 *tc6, u16 length)
}
static __be32 oa_tc6_prepare_data_header(bool data_valid, bool start_valid,
- bool end_valid, u8 end_byte_offset)
+ bool end_valid, u8 end_byte_offset,
+ u8 tsc)
{
u32 header = FIELD_PREP(OA_TC6_DATA_HEADER_DATA_NOT_CTRL,
OA_TC6_DATA_HEADER) |
FIELD_PREP(OA_TC6_DATA_HEADER_DATA_VALID, data_valid) |
FIELD_PREP(OA_TC6_DATA_HEADER_START_VALID, start_valid) |
FIELD_PREP(OA_TC6_DATA_HEADER_END_VALID, end_valid) |
+ FIELD_PREP(OA_TC6_DATA_HEADER_TSC_OFFSET, tsc) |
FIELD_PREP(OA_TC6_DATA_HEADER_END_BYTE_OFFSET,
end_byte_offset);
@@ -1050,6 +1298,7 @@ static void oa_tc6_add_tx_skb_to_spi_buf(struct oa_tc6 *tc6)
enum oa_tc6_data_start_valid_info start_valid;
u8 end_byte_offset = 0;
u16 length_to_copy;
+ u8 tsc = 0;
/* Initial value is assigned here to avoid more than 80 characters in
* the declaration place.
@@ -1059,8 +1308,10 @@ static void oa_tc6_add_tx_skb_to_spi_buf(struct oa_tc6 *tc6)
/* Set start valid if the current tx chunk contains the start of the tx
* ethernet frame.
*/
- if (!tc6->tx_skb_offset)
+ if (!tc6->tx_skb_offset) {
start_valid = OA_TC6_DATA_START_VALID;
+ tsc = oa_tc6_tsinfo_tx(tc6->ongoing_tx_skb)->tsc;
+ }
/* If the remaining tx skb length is more than the chunk payload size of
* 64 bytes then copy only 64 bytes and leave the ongoing tx skb for
@@ -1081,17 +1332,30 @@ static void oa_tc6_add_tx_skb_to_spi_buf(struct oa_tc6 *tc6)
tc6->tx_skb_offset = 0;
tc6->netdev->stats.tx_bytes += tc6->ongoing_tx_skb->len;
tc6->netdev->stats.tx_packets++;
- kfree_skb(tc6->ongoing_tx_skb);
+
+ /* Free the ones that are not saved for later processing,
+ * like timestamping.
+ */
+ if (!(skb_shinfo(tc6->ongoing_tx_skb)->tx_flags &
+ SKBTX_IN_PROGRESS)) {
+ kfree_skb(tc6->ongoing_tx_skb);
+ } else {
+ spin_lock_bh(&tc6->tx_skb_lock);
+ list_add_tail(&tc6->ongoing_tx_skb->list,
+ &tc6->tx_ts_skb_q);
+ spin_unlock_bh(&tc6->tx_skb_lock);
+ }
tc6->ongoing_tx_skb = NULL;
}
*tx_buf = oa_tc6_prepare_data_header(OA_TC6_DATA_VALID, start_valid,
- end_valid, end_byte_offset);
+ end_valid, end_byte_offset, tsc);
tc6->spi_data_tx_buf_offset += OA_TC6_CHUNK_SIZE;
}
static u16 oa_tc6_prepare_spi_tx_buf_for_tx_skbs(struct oa_tc6 *tc6)
{
+ struct sk_buff *drop_skb;
u16 used_tx_credits;
/* Get tx skbs and convert them into tx chunks based on the tx credits
@@ -1100,10 +1364,21 @@ static u16 oa_tc6_prepare_spi_tx_buf_for_tx_skbs(struct oa_tc6 *tc6)
for (used_tx_credits = 0; used_tx_credits < tc6->tx_credits;
used_tx_credits++) {
if (!tc6->ongoing_tx_skb) {
+ drop_skb = NULL;
spin_lock_bh(&tc6->tx_skb_lock);
tc6->ongoing_tx_skb = tc6->waiting_tx_skb;
tc6->waiting_tx_skb = NULL;
+ if (oa_tc6_req_tx_hwtstamp(tc6,
+ tc6->ongoing_tx_skb)) {
+ drop_skb = tc6->ongoing_tx_skb;
+ tc6->ongoing_tx_skb = NULL;
+ if (!tc6->disable_traffic &&
+ netif_running(tc6->netdev) &&
+ netif_queue_stopped(tc6->netdev))
+ netif_wake_queue(tc6->netdev);
+ }
spin_unlock_bh(&tc6->tx_skb_lock);
+ oa_tc6_drop_tx_skb(tc6, drop_skb);
}
if (!tc6->ongoing_tx_skb)
break;
@@ -1120,7 +1395,7 @@ static void oa_tc6_add_empty_chunks_to_spi_buf(struct oa_tc6 *tc6,
header = oa_tc6_prepare_data_header(OA_TC6_DATA_INVALID,
OA_TC6_DATA_START_INVALID,
- OA_TC6_DATA_END_INVALID, 0);
+ OA_TC6_DATA_END_INVALID, 0, 0);
while (needed_empty_chunks--) {
__be32 *tx_buf = tc6->spi_data_tx_buf +
@@ -1312,6 +1587,7 @@ netdev_tx_t oa_tc6_start_xmit(struct oa_tc6 *tc6, struct sk_buff *skb)
return NETDEV_TX_OK;
}
+ oa_tc6_tsinfo_tx(skb)->tsc = 0;
spin_lock_bh(&tc6->tx_skb_lock);
if (tc6->waiting_tx_skb) {
netif_stop_queue(tc6->netdev);
@@ -1371,6 +1647,9 @@ struct oa_tc6 *oa_tc6_init(struct spi_device *spi, struct net_device *netdev,
SET_NETDEV_DEV(netdev, &spi->dev);
mutex_init(&tc6->spi_ctrl_lock);
spin_lock_init(&tc6->tx_skb_lock);
+ tc6->vend1_mms = -EOPNOTSUPP;
+ tc6->ttsc_current_id = OA_TC6_TTSCA_REG_ID;
+ INIT_LIST_HEAD(&tc6->tx_ts_skb_q);
if (quirks)
tc6->quirk_flags = quirks->quirk_flags;
@@ -1464,6 +1743,12 @@ struct oa_tc6 *oa_tc6_init(struct spi_device *spi, struct net_device *netdev,
goto phy_exit;
}
+ ret = oa_tc6_update_standard_capability(tc6);
+ if (ret) {
+ dev_err(&tc6->spi->dev, "Failed to read capability\n");
+ goto phy_exit;
+ }
+
ret = devm_request_threaded_irq(&tc6->spi->dev, tc6->spi->irq,
oa_tc6_macphy_isr,
oa_tc6_macphy_threaded_irq,
diff --git a/drivers/net/ethernet/oa_tc6/oa_tc6_ptp.c b/drivers/net/ethernet/oa_tc6/oa_tc6_ptp.c
new file mode 100644
index 000000000000..056b6408f045
--- /dev/null
+++ b/drivers/net/ethernet/oa_tc6/oa_tc6_ptp.c
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Support for hardware timestamping feature for OPEN Alliance
+ * 10BASE‑T1x MAC‑PHY Serial Interface framework
+ *
+ * Author: Selva Rajagopal <selvamani.rajagopal@onsemi.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/ptp_clock_kernel.h>
+#include <linux/ethtool.h>
+#include <linux/phy.h>
+#include <linux/oa_tc6.h>
+
+#include "oa_tc6_std_def.h"
+
+/**
+ * oa_tc6_ptp_register - Registers clock related callbacks
+ * @tc6: oa_tc6 struct.
+ * @info: Describes a PTP hardware clock
+ *
+ * Description: Vendors are expected to set the hardware timestamp
+ * related callbacks before calling this function.
+ *
+ * Return: 0 on success otherwise failed.
+ *
+ */
+int oa_tc6_ptp_register(struct oa_tc6 *tc6, struct ptp_clock_info *info)
+{
+ int ret = 0;
+
+ /* Not supporting hardware timestamp isn't an error */
+ if (!tc6->hw_tstamp_supported)
+ return ret;
+
+ snprintf(info->name, sizeof(info->name), "%s",
+ "OA TC6 PTP clock");
+ tc6->ptp_clock = ptp_clock_register(info, &tc6->spi->dev);
+ if (IS_ERR(tc6->ptp_clock)) {
+ ret = PTR_ERR(tc6->ptp_clock);
+ tc6->ptp_clock = NULL;
+ dev_err(&tc6->spi->dev, "Registration of %s failed\n",
+ info->name);
+ }
+
+ if (tc6->ptp_clock)
+ dev_info(&tc6->spi->dev, "%s registered. index %d\n",
+ info->name, ptp_clock_index(tc6->ptp_clock));
+ return ret;
+}
+EXPORT_SYMBOL_GPL(oa_tc6_ptp_register);
+
+/**
+ * oa_tc6_ptp_unregister - Unregisters clock related callbacks
+ * @tc6: oa_tc6 struct.
+ */
+void oa_tc6_ptp_unregister(struct oa_tc6 *tc6)
+{
+ if (tc6->ptp_clock) {
+ ptp_clock_unregister(tc6->ptp_clock);
+ tc6->ptp_clock = NULL;
+ }
+}
+EXPORT_SYMBOL_GPL(oa_tc6_ptp_unregister);
diff --git a/drivers/net/ethernet/oa_tc6/oa_tc6_std_def.h b/drivers/net/ethernet/oa_tc6/oa_tc6_std_def.h
index 403a9c22b5f1..06fe88f1ed7c 100644
--- a/drivers/net/ethernet/oa_tc6/oa_tc6_std_def.h
+++ b/drivers/net/ethernet/oa_tc6/oa_tc6_std_def.h
@@ -18,6 +18,9 @@
#include <linux/wait.h>
#include <linux/phy.h>
+/* Tx timestamp capture register A (high) */
+#define OA_TC6_REG_TTSCA_HIGH (0x10)
+
/* Control command header */
#define OA_TC6_CTRL_HEADER_DATA_NOT_CTRL BIT(31)
#define OA_TC6_CTRL_HEADER_WRITE_NOT_READ BIT(29)
@@ -33,6 +36,7 @@
#define OA_TC6_DATA_HEADER_START_WORD_OFFSET GENMASK(19, 16)
#define OA_TC6_DATA_HEADER_END_VALID BIT(14)
#define OA_TC6_DATA_HEADER_END_BYTE_OFFSET GENMASK(13, 8)
+#define OA_TC6_DATA_HEADER_TSC_OFFSET GENMASK(7, 6)
#define OA_TC6_DATA_HEADER_PARITY BIT(0)
/* Data footer */
@@ -44,6 +48,8 @@
#define OA_TC6_DATA_FOOTER_START_VALID BIT(20)
#define OA_TC6_DATA_FOOTER_START_WORD_OFFSET GENMASK(19, 16)
#define OA_TC6_DATA_FOOTER_END_VALID BIT(14)
+#define OA_TC6_DATA_FOOTER_RTSA_VALID BIT(7)
+#define OA_TC6_DATA_FOOTER_RTSP_VALID BIT(6)
#define OA_TC6_DATA_FOOTER_END_BYTE_OFFSET GENMASK(13, 8)
#define OA_TC6_DATA_FOOTER_TX_CREDITS GENMASK(5, 1)
@@ -70,6 +76,22 @@
#define OA_TC6_REG_MMS_MASK GENMASK(19, 16)
+#define OA_TC6_TSTAMP_SZ 8
+
+#define OA_TC6_TTSCA_REG_ID 1
+#define OA_TC6_TTSCB_REG_ID 2
+#define OA_TC6_TTSCC_REG_ID 3
+
+/* STATUS0 and the TTSCA/B/C capture registers are contiguous in MMS 0, so
+ * they are fetched with a single control transaction while timestamping is
+ * available.
+ */
+#define OA_TC6_TTSC_REG_OFFSET (OA_TC6_REG_TTSCA_HIGH - \
+ OA_TC6_REG_STATUS0)
+#define OA_TC6_TTSC_REG_COUNT (2 * OA_TC6_TTSCC_REG_ID)
+#define OA_TC6_STATUS0_TTSC_REG_COUNT (OA_TC6_TTSC_REG_OFFSET + \
+ OA_TC6_TTSC_REG_COUNT)
+
/* Internal structure for MAC-PHY drivers */
struct oa_tc6 {
struct net_device *netdev;
@@ -95,6 +117,16 @@ struct oa_tc6 {
bool prot_ctrl;
enum oa_tc6_quirk_flag quirk_flags;
struct gpio_desc *reset_gpio;
+ struct hwtstamp_config ts_config;
+ struct list_head tx_ts_skb_q;
+ struct ptp_clock *ptp_clock;
+ bool hw_tstamp_supported;
+ bool hw_tstamp_enabled;
+ u64 tx_hwtstamp_pkts;
+ u64 tx_hwtstamp_lost;
+ u64 tx_hwtstamp_err;
+ u8 ts_ttsc_pending;
+ u8 ttsc_current_id;
};
enum oa_tc6_header_type {
@@ -121,5 +153,8 @@ enum oa_tc6_data_end_valid_info {
OA_TC6_DATA_END_INVALID,
OA_TC6_DATA_END_VALID,
};
+
+void oa_tc6_cleanup_tx_tstamp_skbs(struct oa_tc6 *tc6);
+
#endif /* OA_TC6_STD_DEF_H */
diff --git a/drivers/net/ethernet/oa_tc6/oa_tc6_tstamp.c b/drivers/net/ethernet/oa_tc6/oa_tc6_tstamp.c
new file mode 100644
index 000000000000..d83f6ad9373a
--- /dev/null
+++ b/drivers/net/ethernet/oa_tc6/oa_tc6_tstamp.c
@@ -0,0 +1,224 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * OPEN Alliance 10BASE‑T1x MAC‑PHY Serial Interface framework
+ *
+ * Author: Selva Rajagopal <selvamani.rajagopal@onsemi.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/iopoll.h>
+#include <linux/mdio.h>
+#include <linux/phy.h>
+#include <linux/oa_tc6.h>
+
+#include "oa_tc6_std_def.h"
+
+static int oa_tc6_set_hwtstamp_settings(struct oa_tc6 *tc6,
+ const struct hwtstamp_config *ts_cfg)
+{
+ u32 regs[OA_TC6_REG_INT_MASK0 - OA_TC6_REG_CONFIG0 + 1];
+ u32 cfg0, irqm, status0;
+ bool disabled;
+ int ret;
+
+ if (tc6->ts_config.flags == ts_cfg->flags &&
+ tc6->ts_config.tx_type == ts_cfg->tx_type &&
+ tc6->ts_config.rx_filter == ts_cfg->rx_filter)
+ return 0;
+
+ spin_lock_bh(&tc6->tx_skb_lock);
+ disabled = tc6->disable_traffic;
+ spin_unlock_bh(&tc6->tx_skb_lock);
+ if (disabled)
+ return -EIO;
+
+ /* CONFIG0, STATUS0 and INT_MASK0 span one register block, so a
+ * single control transaction covers all three.
+ */
+ ret = oa_tc6_read_registers(tc6, OA_TC6_REG_CONFIG0, regs,
+ ARRAY_SIZE(regs));
+ if (ret) {
+ dev_err(&tc6->spi->dev, "Failed to read CFG0 block\n");
+ goto out;
+ }
+
+ cfg0 = regs[0];
+ status0 = regs[OA_TC6_REG_STATUS0 - OA_TC6_REG_CONFIG0];
+ irqm = regs[OA_TC6_REG_INT_MASK0 - OA_TC6_REG_CONFIG0];
+
+ /* Hardware timestamp feature supports 64-bit timestamp only */
+ if (ts_cfg->tx_type == HWTSTAMP_TX_ON ||
+ ts_cfg->rx_filter == HWTSTAMP_FILTER_ALL)
+ cfg0 |= (OA_TC6_CONFIG0_FTSE_ENABLE |
+ OA_TC6_CONFIG0_FTSS_64BIT_TSTAMP);
+ else
+ cfg0 &= ~OA_TC6_CONFIG0_FTSE_ENABLE;
+
+ if (ts_cfg->tx_type == HWTSTAMP_TX_ON)
+ irqm &= ~OA_TC6_INT_MASK0_TTSCA_MASK;
+ else
+ irqm |= OA_TC6_INT_MASK0_TTSCA_MASK;
+
+ /* STATUS0 is write-one-to-clear, so this acknowledges a capture
+ * without delivering its timestamp. Skip it while TX timestamping
+ * stays enabled, where a capture may still be outstanding.
+ */
+ status0 &= OA_TC6_STATUS0_TTSCA_MASK;
+ if (status0 && (tc6->ts_config.tx_type != HWTSTAMP_TX_ON ||
+ ts_cfg->tx_type != HWTSTAMP_TX_ON)) {
+ ret = oa_tc6_write_register(tc6, OA_TC6_REG_STATUS0,
+ status0);
+ if (ret) {
+ dev_err(&tc6->spi->dev,
+ "failed to write STATUS0 register\n");
+ goto out;
+ }
+ }
+
+ ret = oa_tc6_write_register(tc6, OA_TC6_REG_INT_MASK0, irqm);
+ if (ret) {
+ dev_err(&tc6->spi->dev, "failed to write IRQM register\n");
+ goto out;
+ }
+
+ ret = oa_tc6_write_register(tc6, OA_TC6_REG_CONFIG0, cfg0);
+ if (ret) {
+ dev_err(&tc6->spi->dev, "failed to write CFG0 register\n");
+ goto out;
+ }
+ spin_lock_bh(&tc6->tx_skb_lock);
+ tc6->ts_config = *ts_cfg;
+ if (cfg0 & OA_TC6_CONFIG0_FTSE_ENABLE)
+ tc6->hw_tstamp_enabled = true;
+ else
+ tc6->hw_tstamp_enabled = false;
+ spin_unlock_bh(&tc6->tx_skb_lock);
+
+ /* The TX timestamp completion interrupt is masked now. Time
+ * to release the queued skbs.
+ */
+ if (ts_cfg->tx_type != HWTSTAMP_TX_ON)
+ oa_tc6_cleanup_tx_tstamp_skbs(tc6);
+out:
+ return ret;
+}
+
+/**
+ * oa_tc6_hwtstamp_get - gets hardware timestamp config
+ * @tc6: oa_tc6 struct.
+ * @cfg: kernel copy of hardware timestamp config
+ */
+void oa_tc6_hwtstamp_get(struct oa_tc6 *tc6,
+ struct kernel_hwtstamp_config *cfg)
+{
+ hwtstamp_config_to_kernel(cfg, &tc6->ts_config);
+}
+EXPORT_SYMBOL_GPL(oa_tc6_hwtstamp_get);
+
+/**
+ * oa_tc6_hwtstamp_set - sets hardware timestamp config
+ * @tc6: oa_tc6 struct.
+ * @cfg: kernel copy of hardware timestamp config
+ *
+ * Return: 0 on success otherwise failed.
+ */
+int oa_tc6_hwtstamp_set(struct oa_tc6 *tc6,
+ struct kernel_hwtstamp_config *cfg)
+{
+ struct hwtstamp_config ts_cfg;
+ int ret;
+
+ if (!netif_running(tc6->netdev))
+ return -EIO;
+
+ /* Set only when STDCAP advertised the capability and the PHC
+ * registered, which is what ethtool -T reports.
+ */
+ if (!tc6->ptp_clock)
+ return -EOPNOTSUPP;
+
+ switch (cfg->tx_type) {
+ case HWTSTAMP_TX_OFF:
+ case HWTSTAMP_TX_ON:
+ break;
+ default:
+ return -ERANGE;
+ }
+
+ switch (cfg->rx_filter) {
+ case HWTSTAMP_FILTER_NONE:
+ case HWTSTAMP_FILTER_ALL:
+ case HWTSTAMP_FILTER_SOME:
+ case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
+ case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
+ case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
+ case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
+ case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
+ case HWTSTAMP_FILTER_PTP_V2_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
+ case HWTSTAMP_FILTER_NTP_ALL:
+ break;
+ default:
+ return -ERANGE;
+ }
+
+ hwtstamp_config_from_kernel(&ts_cfg, cfg);
+
+ /* Supports timestamping all traffic */
+ if (cfg->rx_filter != HWTSTAMP_FILTER_NONE ||
+ cfg->tx_type == HWTSTAMP_TX_ON)
+ ts_cfg.rx_filter = HWTSTAMP_FILTER_ALL;
+
+ ret = oa_tc6_set_hwtstamp_settings(tc6, &ts_cfg);
+ if (ret)
+ return ret;
+
+ /* Report what was programmed, not asked. */
+ cfg->rx_filter = ts_cfg.rx_filter;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(oa_tc6_hwtstamp_set);
+
+/**
+ * oa_tc6_get_ts_stats - Provides timestamping stats
+ * @tc6: oa_tc6 struct.
+ * @stats: ethtool data structure to fill in
+ */
+void oa_tc6_get_ts_stats(struct oa_tc6 *tc6,
+ struct ethtool_ts_stats *stats)
+{
+ stats->pkts = tc6->tx_hwtstamp_pkts;
+ stats->err = tc6->tx_hwtstamp_err;
+ stats->lost = tc6->tx_hwtstamp_lost;
+}
+EXPORT_SYMBOL_GPL(oa_tc6_get_ts_stats);
+
+/**
+ * oa_tc6_get_ts_info - Provides timestamp info for ethtool
+ * @tc6: oa_tc6 struct.
+ * @info: ethtool timestamping info structure
+ *
+ * Return: 0 on success otherwise failed.
+ */
+int oa_tc6_get_ts_info(struct oa_tc6 *tc6,
+ struct kernel_ethtool_ts_info *info)
+{
+ if (!tc6->ptp_clock)
+ return ethtool_op_get_ts_info(tc6->netdev, info);
+
+ info->so_timestamping = SOF_TIMESTAMPING_RAW_HARDWARE |
+ SOF_TIMESTAMPING_TX_HARDWARE |
+ SOF_TIMESTAMPING_RX_HARDWARE;
+ info->phc_index = ptp_clock_index(tc6->ptp_clock);
+ info->tx_types = BIT(HWTSTAMP_TX_OFF) | BIT(HWTSTAMP_TX_ON);
+ info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) |
+ BIT(HWTSTAMP_FILTER_ALL);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(oa_tc6_get_ts_info);
diff --git a/include/linux/oa_tc6.h b/include/linux/oa_tc6.h
index 27f652d4920b..365abdbf60d3 100644
--- a/include/linux/oa_tc6.h
+++ b/include/linux/oa_tc6.h
@@ -7,13 +7,18 @@
* Author: Parthiban Veerasooran <parthiban.veerasooran@microchip.com>
*/
+#ifndef _LINUX_OA_TC6_H
+#define _LINUX_OA_TC6_H
+
#include <linux/etherdevice.h>
#include <linux/spi/spi.h>
+#include <linux/ptp_clock_kernel.h>
/* OPEN Alliance TC6 registers */
/* Standard Capabilities Register */
#define OA_TC6_REG_STDCAP 0x0002
#define OA_TC6_STDCAP_DIRECT_PHY_REG_ACCESS BIT(8)
+#define OA_TC6_STDCAP_TIMESTAMP_CAPABILITY BIT(6)
/* Reset Control and Status Register */
#define OA_TC6_REG_RESET 0x0003
@@ -23,6 +28,8 @@
#define OA_TC6_REG_CONFIG0 0x0004
#define OA_TC6_CONFIG0_SYNC BIT(15)
#define OA_TC6_CONFIG0_ZARFE_ENABLE BIT(12)
+#define OA_TC6_CONFIG0_FTSE_ENABLE BIT(7)
+#define OA_TC6_CONFIG0_FTSS_64BIT_TSTAMP BIT(6)
#define OA_TC6_CONFIG0_PROTE BIT(5)
/* Configuration Register #2 */
@@ -30,6 +37,10 @@
/* Status Register #0 */
#define OA_TC6_REG_STATUS0 0x0008
+#define OA_TC6_STATUS0_TTSCAC BIT(10)
+#define OA_TC6_STATUS0_TTSCAB BIT(9)
+#define OA_TC6_STATUS0_TTSCAA BIT(8)
+#define OA_TC6_STATUS0_TTSCA_MASK GENMASK(10, 8)
#define OA_TC6_STATUS0_RESETC BIT(6) /* Reset Complete */
#define OA_TC6_STATUS0_HEADER_ERROR BIT(5)
#define OA_TC6_STATUS0_LOSS_OF_FRAME_ERROR BIT(4)
@@ -43,6 +54,7 @@
/* Interrupt Mask Register #0 */
#define OA_TC6_REG_INT_MASK0 0x000C
+#define OA_TC6_INT_MASK0_TTSCA_MASK GENMASK(10, 8)
#define OA_TC6_INT_MASK0_HEADER_ERR_MASK BIT(5)
#define OA_TC6_INT_MASK0_LOSS_OF_FRAME_ERR_MASK BIT(4)
#define OA_TC6_INT_MASK0_RX_BUFFER_OVERFLOW_ERR_MASK BIT(3)
@@ -93,3 +105,14 @@ int oa_tc6_mdiobus_read_c45(struct mii_bus *bus, int addr, int devnum,
int regnum);
int oa_tc6_mdiobus_write_c45(struct mii_bus *bus, int addr, int devnum,
int regnum, u16 val);
+int oa_tc6_ptp_register(struct oa_tc6 *tc6, struct ptp_clock_info *info);
+int oa_tc6_get_ts_info(struct oa_tc6 *tc6,
+ struct kernel_ethtool_ts_info *info);
+void oa_tc6_hwtstamp_get(struct oa_tc6 *tc6,
+ struct kernel_hwtstamp_config *cfg);
+void oa_tc6_get_ts_stats(struct oa_tc6 *tc6,
+ struct ethtool_ts_stats *stats);
+int oa_tc6_hwtstamp_set(struct oa_tc6 *tc6,
+ struct kernel_hwtstamp_config *cfg);
+void oa_tc6_ptp_unregister(struct oa_tc6 *tc6);
+#endif /* _LINUX_OA_TC6_H */
--
2.43.0
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH net-next v8 06/11] net: ethernet: oa_tc6: Support for vendor specific MMS
2026-09-28 22:25 [PATCH net-next v8 00/11] Support for onsemi's S2500 10Base-T1S MAC-PHY Selvamani Rajagopal via B4 Relay
` (4 preceding siblings ...)
2026-09-28 22:25 ` [PATCH net-next v8 05/11] net: ethernet: oa_tc6: Support for hardware timestamp Selvamani Rajagopal via B4 Relay
@ 2026-09-28 22:25 ` Selvamani Rajagopal via B4 Relay
2026-09-28 22:25 ` [PATCH net-next v8 07/11] net: phy: ncn26000: Support for onsemi's S2500 internal phy Selvamani Rajagopal via B4 Relay
` (4 subsequent siblings)
10 siblings, 0 replies; 24+ messages in thread
From: Selvamani Rajagopal via B4 Relay @ 2026-09-28 22:25 UTC (permalink / raw)
To: Selva Rajagopal, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Piergiorgio Beruto, Parthiban Veerasooran,
Simon Horman, Jonathan Corbet, Shuah Khan, Randy Dunlap,
Richard Cochran, Andrew Lunn, Heiner Kallweit, Russell King
Cc: Selva Rajagopal, netdev, devicetree, linux-kernel, linux-doc, Jerry Ray
From: Selvamani Rajagopal <Selvamani.Rajagopal@onsemi.com>
OPEN Alliance 10BASE-T1x Serial Interface specification, table 6
allows vendors to use any memory map select (MMS) value between
10 and 15. This new API interface enables vendor to map one of
thes MMS values to MDIO_MMD_VEND1.
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Selvamani Rajagopal <Selvamani.Rajagopal@onsemi.com>
---
changes in v8
- No change
changes in v7
- No change
changes in v6
- No change
changes in v5
- no change
changes in v4
- no change
changes in v3
- no change
changes in v2
- Moved the handling of vendor specific MMS mapping to separate patch
- new patch
---
drivers/net/ethernet/oa_tc6/oa_tc6.c | 20 +++++++++++++++++---
drivers/net/ethernet/oa_tc6/oa_tc6_std_def.h | 1 +
include/linux/oa_tc6.h | 1 +
3 files changed, 19 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/oa_tc6/oa_tc6.c b/drivers/net/ethernet/oa_tc6/oa_tc6.c
index 5cbe049f76ef..c1774fe84ba4 100644
--- a/drivers/net/ethernet/oa_tc6/oa_tc6.c
+++ b/drivers/net/ethernet/oa_tc6/oa_tc6.c
@@ -250,6 +250,18 @@ static int oa_tc6_update_standard_capability(struct oa_tc6 *tc6)
return 0;
}
+/**
+ * oa_tc6_set_vend1_mms - Add vendor specific MDIO_MMD to OA TC6 MMS
+ * mapper value.
+ * @tc6: oa_tc6 struct.
+ * @mms: vendor defined MMS value for VEND1 mdio device.
+ */
+void oa_tc6_set_vend1_mms(struct oa_tc6 *tc6, int mms)
+{
+ tc6->vend1_mms = mms;
+}
+EXPORT_SYMBOL_GPL(oa_tc6_set_vend1_mms);
+
static __be32 oa_tc6_prepare_ctrl_header(u32 addr, u8 length,
enum oa_tc6_register_op reg_op)
{
@@ -577,7 +589,7 @@ static int oa_tc6_mdiobus_write(struct mii_bus *bus, int addr, int regnum,
val);
}
-static int oa_tc6_get_phy_c45_mms(int devnum)
+static int oa_tc6_get_phy_c45_mms(struct oa_tc6 *tc6, int devnum)
{
switch (devnum) {
case MDIO_MMD_PCS:
@@ -590,6 +602,8 @@ static int oa_tc6_get_phy_c45_mms(int devnum)
return OA_TC6_PHY_C45_AUTO_NEG_MMS5;
case MDIO_MMD_POWER_UNIT:
return OA_TC6_PHY_C45_POWER_UNIT_MMS6;
+ case MDIO_MMD_VEND1:
+ return tc6->vend1_mms;
default:
return -EOPNOTSUPP;
}
@@ -603,7 +617,7 @@ int oa_tc6_mdiobus_read_c45(struct mii_bus *bus, int addr, int devnum,
int mms;
int ret;
- mms = oa_tc6_get_phy_c45_mms(devnum);
+ mms = oa_tc6_get_phy_c45_mms(tc6, devnum);
if (mms < 0)
return mms;
@@ -621,7 +635,7 @@ int oa_tc6_mdiobus_write_c45(struct mii_bus *bus, int addr, int devnum,
struct oa_tc6 *tc6 = bus->priv;
int mms;
- mms = oa_tc6_get_phy_c45_mms(devnum);
+ mms = oa_tc6_get_phy_c45_mms(tc6, devnum);
if (mms < 0)
return mms;
diff --git a/drivers/net/ethernet/oa_tc6/oa_tc6_std_def.h b/drivers/net/ethernet/oa_tc6/oa_tc6_std_def.h
index 06fe88f1ed7c..192cc2eaa041 100644
--- a/drivers/net/ethernet/oa_tc6/oa_tc6_std_def.h
+++ b/drivers/net/ethernet/oa_tc6/oa_tc6_std_def.h
@@ -127,6 +127,7 @@ struct oa_tc6 {
u64 tx_hwtstamp_err;
u8 ts_ttsc_pending;
u8 ttsc_current_id;
+ int vend1_mms;
};
enum oa_tc6_header_type {
diff --git a/include/linux/oa_tc6.h b/include/linux/oa_tc6.h
index 365abdbf60d3..88e7d5491b20 100644
--- a/include/linux/oa_tc6.h
+++ b/include/linux/oa_tc6.h
@@ -114,5 +114,6 @@ void oa_tc6_get_ts_stats(struct oa_tc6 *tc6,
struct ethtool_ts_stats *stats);
int oa_tc6_hwtstamp_set(struct oa_tc6 *tc6,
struct kernel_hwtstamp_config *cfg);
+void oa_tc6_set_vend1_mms(struct oa_tc6 *tc6, int mms);
void oa_tc6_ptp_unregister(struct oa_tc6 *tc6);
#endif /* _LINUX_OA_TC6_H */
--
2.43.0
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH net-next v8 07/11] net: phy: ncn26000: Support for onsemi's S2500 internal phy
2026-09-28 22:25 [PATCH net-next v8 00/11] Support for onsemi's S2500 10Base-T1S MAC-PHY Selvamani Rajagopal via B4 Relay
` (5 preceding siblings ...)
2026-09-28 22:25 ` [PATCH net-next v8 06/11] net: ethernet: oa_tc6: Support for vendor specific MMS Selvamani Rajagopal via B4 Relay
@ 2026-09-28 22:25 ` Selvamani Rajagopal via B4 Relay
2026-09-28 22:50 ` Selvamani Rajagopal
2026-09-28 22:25 ` [PATCH net-next v8 08/11] net: phy: ncn26000: Enable enhanced noise immunity Selvamani Rajagopal via B4 Relay
` (3 subsequent siblings)
10 siblings, 1 reply; 24+ messages in thread
From: Selvamani Rajagopal via B4 Relay @ 2026-09-28 22:25 UTC (permalink / raw)
To: Selva Rajagopal, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Piergiorgio Beruto, Parthiban Veerasooran,
Simon Horman, Jonathan Corbet, Shuah Khan, Randy Dunlap,
Richard Cochran, Andrew Lunn, Heiner Kallweit, Russell King
Cc: Selva Rajagopal, netdev, devicetree, linux-kernel, linux-doc, Jerry Ray
From: Selvamani Rajagopal <Selvamani.Rajagopal@onsemi.com>
Adding support for internal PHY of the integrated
media access controller S2500. PLCA tx opportunity timer's
default value is correct in this device, compared to
the currently supported PHY NCN26000.
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Selvamani Rajagopal <Selvamani.Rajagopal@onsemi.com>
---
changes in v8
- changes to use newer API for read/write_mmd callback
changes in v7
- No change
changes in v6
- No change
changes in v5
- No change
changes in v4
- no change
changes in v3
added new PHY support separate patch
changed model comparison to use phy_id_compare_model
changes in v2
Removed bug fixes. Retained only S2500 specific changes
changes in v1
Added support for an internal PHY of onsemi's MAC-PHY S2500
---
MAINTAINERS | 3 ++-
drivers/net/phy/ncn26000.c | 38 +++++++++++++++++++++++++++++++++-----
2 files changed, 35 insertions(+), 6 deletions(-)
diff --git a/MAINTAINERS b/MAINTAINERS
index 5c7028c94f56..5934fdd78753 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -20420,7 +20420,8 @@ S: Maintained
F: arch/mips/boot/dts/ralink/omega2p.dts
ONSEMI ETHERNET PHY DRIVERS
-M: Piergiorgio Beruto <piergiorgio.beruto@gmail.com>
+M: Piergiorgio Beruto <pier.beruto@onsemi.com>
+M: Selva Rajagopal <selvamani.rajagopal@onsemi.com>
L: netdev@vger.kernel.org
S: Supported
W: http://www.onsemi.com
diff --git a/drivers/net/phy/ncn26000.c b/drivers/net/phy/ncn26000.c
index cabdd83c614f..374684e11fac 100644
--- a/drivers/net/phy/ncn26000.c
+++ b/drivers/net/phy/ncn26000.c
@@ -2,7 +2,7 @@
/*
* Driver for the onsemi 10BASE-T1S NCN26000 PHYs family.
*
- * Copyright 2022 onsemi
+ * Copyright 2026 onsemi
*/
#include <linux/kernel.h>
#include <linux/bitfield.h>
@@ -14,6 +14,7 @@
#include "mdio-open-alliance.h"
+#define PHY_ID_S2500 0x180FF411
#define PHY_ID_NCN26000 0x180FF5A1
#define NCN26000_REG_IRQ_CTL 16
@@ -37,13 +38,18 @@
static int ncn26000_config_init(struct phy_device *phydev)
{
+ int ret = 0;
+
/* HW bug workaround: the default value of the PLCA TO_TIMER should be
* 32, where the current version of NCN26000 reports 24. This will be
* fixed in future PHY versions. For the time being, we force the
* correct default here.
*/
- return phy_write_mmd(phydev, MDIO_MMD_VEND2, MDIO_OATC14_PLCA_TOTMR,
- TO_TMR_DEFAULT);
+ if (phy_id_compare_model(phydev->drv->phy_id, PHY_ID_NCN26000))
+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND2,
+ MDIO_OATC14_PLCA_TOTMR,
+ TO_TMR_DEFAULT);
+ return ret;
}
static int ncn26000_config_aneg(struct phy_device *phydev)
@@ -117,8 +123,8 @@ static irqreturn_t ncn26000_handle_interrupt(struct phy_device *phydev)
static int ncn26000_config_intr(struct phy_device *phydev)
{
- int ret;
u16 irqe;
+ int ret;
if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
// acknowledge IRQs
@@ -141,6 +147,26 @@ static int ncn26000_config_intr(struct phy_device *phydev)
}
static struct phy_driver ncn26000_driver[] = {
+ {
+ PHY_ID_MATCH_MODEL(PHY_ID_S2500),
+ .name = "S2500",
+ .features = PHY_BASIC_T1S_P2MP_FEATURES,
+ .config_init = ncn26000_config_init,
+ .config_intr = ncn26000_config_intr,
+ .config_aneg = ncn26000_config_aneg,
+ .read_status = ncn26000_read_status,
+ .handle_interrupt = ncn26000_handle_interrupt,
+ .set_plca_cfg = genphy_c45_plca_set_cfg,
+ .get_plca_cfg = genphy_c45_plca_get_cfg,
+ .get_plca_status = genphy_c45_plca_get_status,
+ .soft_reset = genphy_soft_reset,
+ .get_sqi = genphy_c45_oatc14_get_sqi,
+ .get_sqi_max = genphy_c45_oatc14_get_sqi_max,
+ .read_mmd = genphy_read_mmd_c45,
+ .write_mmd = genphy_write_mmd_c45,
+ .cable_test_get_status = genphy_c45_oatc14_cable_test_get_status,
+ .cable_test_start = genphy_c45_oatc14_cable_test_start,
+ },
{
PHY_ID_MATCH_MODEL(PHY_ID_NCN26000),
.name = "NCN26000",
@@ -161,11 +187,13 @@ module_phy_driver(ncn26000_driver);
static const struct mdio_device_id __maybe_unused ncn26000_tbl[] = {
{ PHY_ID_MATCH_MODEL(PHY_ID_NCN26000) },
+ { PHY_ID_MATCH_MODEL(PHY_ID_S2500) },
{ }
};
MODULE_DEVICE_TABLE(mdio, ncn26000_tbl);
-MODULE_AUTHOR("Piergiorgio Beruto");
+MODULE_AUTHOR("Piergiorgio Beruto <pier.beruto@onsemi.com>");
+MODULE_AUTHOR("Selva Rajagopal <selvamani.rajagopal@onsemi.com>");
MODULE_DESCRIPTION("onsemi 10BASE-T1S PHY driver");
MODULE_LICENSE("Dual BSD/GPL");
--
2.43.0
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH net-next v8 08/11] net: phy: ncn26000: Enable enhanced noise immunity
2026-09-28 22:25 [PATCH net-next v8 00/11] Support for onsemi's S2500 10Base-T1S MAC-PHY Selvamani Rajagopal via B4 Relay
` (6 preceding siblings ...)
2026-09-28 22:25 ` [PATCH net-next v8 07/11] net: phy: ncn26000: Support for onsemi's S2500 internal phy Selvamani Rajagopal via B4 Relay
@ 2026-09-28 22:25 ` Selvamani Rajagopal via B4 Relay
2026-09-28 22:25 ` [PATCH net-next v8 09/11] net: phy: ncn26000: Support for loopback Selvamani Rajagopal via B4 Relay
` (2 subsequent siblings)
10 siblings, 0 replies; 24+ messages in thread
From: Selvamani Rajagopal via B4 Relay @ 2026-09-28 22:25 UTC (permalink / raw)
To: Selva Rajagopal, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Piergiorgio Beruto, Parthiban Veerasooran,
Simon Horman, Jonathan Corbet, Shuah Khan, Randy Dunlap,
Richard Cochran, Andrew Lunn, Heiner Kallweit, Russell King
Cc: Selva Rajagopal, netdev, devicetree, linux-kernel, linux-doc, Jerry Ray
From: Selvamani Rajagopal <Selvamani.Rajagopal@onsemi.com>
By setting ENI bit, noise immunity is improved and it is
specifically meant for PLCA enabled nodes.
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Selvamani Rajagopal <Selvamani.Rajagopal@onsemi.com>
---
changes in v8
- No change
changes in v7
- No change
changes in v6
- No change
changes in v5
- No changes
changes in v4
- No changes
changes in v3
- Moved as a separate patch
---
drivers/net/phy/ncn26000.c | 26 ++++++++++++++++++++++++--
1 file changed, 24 insertions(+), 2 deletions(-)
diff --git a/drivers/net/phy/ncn26000.c b/drivers/net/phy/ncn26000.c
index 374684e11fac..b362e85c7911 100644
--- a/drivers/net/phy/ncn26000.c
+++ b/drivers/net/phy/ncn26000.c
@@ -36,6 +36,10 @@
#define TO_TMR_DEFAULT 32
+#define NCN26000_REG_PHYCFG1 0x8001
+#define NCN26000_PHYCFG1_ENI BIT(7)
+#define NCN26000_PHYCFG1_ENI_MASK BIT(7)
+
static int ncn26000_config_init(struct phy_device *phydev)
{
int ret = 0;
@@ -106,6 +110,24 @@ static int ncn26000_read_status(struct phy_device *phydev)
return 0;
}
+/* Intercept PLCA enable/disable request to
+ * set the proprietary, ENI mode accordingly
+ */
+static int ncn26000_c45_plca_set_cfg(struct phy_device *phydev,
+ const struct phy_plca_cfg *plca_cfg)
+{
+ int ret = genphy_c45_plca_set_cfg(phydev, plca_cfg);
+ u16 eni_cfg = 0;
+
+ if (ret || plca_cfg->enabled < 0)
+ return ret;
+
+ eni_cfg = (plca_cfg->enabled) ? NCN26000_PHYCFG1_ENI : 0;
+ return phy_modify_mmd(phydev, MDIO_MMD_VEND2,
+ NCN26000_REG_PHYCFG1,
+ NCN26000_PHYCFG1_ENI_MASK, eni_cfg);
+}
+
static irqreturn_t ncn26000_handle_interrupt(struct phy_device *phydev)
{
int ret;
@@ -156,7 +178,7 @@ static struct phy_driver ncn26000_driver[] = {
.config_aneg = ncn26000_config_aneg,
.read_status = ncn26000_read_status,
.handle_interrupt = ncn26000_handle_interrupt,
- .set_plca_cfg = genphy_c45_plca_set_cfg,
+ .set_plca_cfg = ncn26000_c45_plca_set_cfg,
.get_plca_cfg = genphy_c45_plca_get_cfg,
.get_plca_status = genphy_c45_plca_get_status,
.soft_reset = genphy_soft_reset,
@@ -177,7 +199,7 @@ static struct phy_driver ncn26000_driver[] = {
.read_status = ncn26000_read_status,
.handle_interrupt = ncn26000_handle_interrupt,
.get_plca_cfg = genphy_c45_plca_get_cfg,
- .set_plca_cfg = genphy_c45_plca_set_cfg,
+ .set_plca_cfg = ncn26000_c45_plca_set_cfg,
.get_plca_status = genphy_c45_plca_get_status,
.soft_reset = genphy_soft_reset,
},
--
2.43.0
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH net-next v8 09/11] net: phy: ncn26000: Support for loopback
2026-09-28 22:25 [PATCH net-next v8 00/11] Support for onsemi's S2500 10Base-T1S MAC-PHY Selvamani Rajagopal via B4 Relay
` (7 preceding siblings ...)
2026-09-28 22:25 ` [PATCH net-next v8 08/11] net: phy: ncn26000: Enable enhanced noise immunity Selvamani Rajagopal via B4 Relay
@ 2026-09-28 22:25 ` Selvamani Rajagopal via B4 Relay
2026-10-06 13:05 ` Andrew Lunn
2026-10-06 13:06 ` Andrew Lunn
2026-09-28 22:25 ` [PATCH net-next v8 10/11] onsemi: s2500: Add driver support for S2500 MAC-PHY Selvamani Rajagopal via B4 Relay
2026-09-28 22:25 ` [PATCH net-next v8 11/11] onsemi: s2500: Added selftest support to onsemi's S2500 driver Selvamani Rajagopal via B4 Relay
10 siblings, 2 replies; 24+ messages in thread
From: Selvamani Rajagopal via B4 Relay @ 2026-09-28 22:25 UTC (permalink / raw)
To: Selva Rajagopal, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Piergiorgio Beruto, Parthiban Veerasooran,
Simon Horman, Jonathan Corbet, Shuah Khan, Randy Dunlap,
Richard Cochran, Andrew Lunn, Heiner Kallweit, Russell King
Cc: Selva Rajagopal, netdev, devicetree, linux-kernel, linux-doc, Jerry Ray
From: Selvamani Rajagopal <Selvamani.Rajagopal@onsemi.com>
Adding loopback support for S2500 internal PHY to help running
loopback test through ethtool.
This instance requires only manipulating the loopback bit in
the PHY only. So, added a generic helper function to modify
loopback bit of the PHY without modifying any other bit. This
will help the PHYs that may have fixed speed, like 10Base-T1S
or PHYs that don't need any other settings to set them in
loopback mode.
Signed-off-by: Selvamani Rajagopal <Selvamani.Rajagopal@onsemi.com>
---
changes in v8
- No code change. Changes were in two different patches.
Merged into one.
changes in v7
- No change
changes in v6
- No change
changes in v5
- No change
changes in v4
- Moved the onsemi implementation to a new, genphy API to
make it vendor agnostic.
changes in v3
- Addd loopback functionality for onsemi's PHY driver
- First patch
---
drivers/net/phy/dp83867.c | 11 +----------
drivers/net/phy/ncn26000.c | 1 +
drivers/net/phy/phy_device.c | 20 ++++++++++++++++++++
include/linux/phy.h | 2 ++
4 files changed, 24 insertions(+), 10 deletions(-)
diff --git a/drivers/net/phy/dp83867.c b/drivers/net/phy/dp83867.c
index a3cd5cb11ea0..38c17a68cf26 100644
--- a/drivers/net/phy/dp83867.c
+++ b/drivers/net/phy/dp83867.c
@@ -1058,15 +1058,6 @@ static void dp83867_link_change_notify(struct phy_device *phydev)
}
}
-static int dp83867_loopback(struct phy_device *phydev, bool enable, int speed)
-{
- if (enable && speed)
- return -EOPNOTSUPP;
-
- return phy_modify(phydev, MII_BMCR, BMCR_LOOPBACK,
- enable ? BMCR_LOOPBACK : 0);
-}
-
static int
dp83867_led_brightness_set(struct phy_device *phydev,
u8 index, enum led_brightness brightness)
@@ -1292,7 +1283,7 @@ static struct phy_driver dp83867_driver[] = {
.resume = dp83867_resume,
.link_change_notify = dp83867_link_change_notify,
- .set_loopback = dp83867_loopback,
+ .set_loopback = genphy_loopback_fixed_speed,
.led_brightness_set = dp83867_led_brightness_set,
.led_hw_is_supported = dp83867_led_hw_is_supported,
diff --git a/drivers/net/phy/ncn26000.c b/drivers/net/phy/ncn26000.c
index b362e85c7911..933cba6d00b5 100644
--- a/drivers/net/phy/ncn26000.c
+++ b/drivers/net/phy/ncn26000.c
@@ -178,6 +178,7 @@ static struct phy_driver ncn26000_driver[] = {
.config_aneg = ncn26000_config_aneg,
.read_status = ncn26000_read_status,
.handle_interrupt = ncn26000_handle_interrupt,
+ .set_loopback = genphy_loopback_fixed_speed,
.set_plca_cfg = ncn26000_c45_plca_set_cfg,
.get_plca_cfg = genphy_c45_plca_get_cfg,
.get_plca_status = genphy_c45_plca_get_status,
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 5b13a74e2fa9..ca438d4e8fcb 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -2775,6 +2775,26 @@ int genphy_write_mmd_unsupported(struct phy_device *phdev, int devnum,
}
EXPORT_SYMBOL(genphy_write_mmd_unsupported);
+/**
+ * genphy_loopback_fixed_speed - Helper to modify the PHY loopback mode
+ * without affecting any other settings.
+ * @phydev: The phy_device struct
+ * @enable: Flag to enable or disable the PHY level loopback.
+ * @speed: Speed setting. Not expected to be set. Error if it is set.
+ *
+ * Returns: 0 if successful, negative error code on failure.
+ */
+int genphy_loopback_fixed_speed(struct phy_device *phydev, bool enable,
+ int speed)
+{
+ if (enable && speed)
+ return -EOPNOTSUPP;
+
+ return phy_modify(phydev, MII_BMCR, BMCR_LOOPBACK,
+ enable ? BMCR_LOOPBACK : 0);
+}
+EXPORT_SYMBOL(genphy_loopback_fixed_speed);
+
int genphy_suspend(struct phy_device *phydev)
{
return phy_set_bits(phydev, MII_BMCR, BMCR_PDOWN);
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 7c5098a0dd6c..c1b9bc305c82 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -2327,6 +2327,8 @@ int genphy_read_mmd_unsupported(struct phy_device *phdev, int devad,
u16 regnum);
int genphy_write_mmd_unsupported(struct phy_device *phdev, int devnum,
u16 regnum, u16 val);
+int genphy_loopback_fixed_speed(struct phy_device *phydev, bool enable,
+ int speed);
/* Clause 37 */
int genphy_c37_config_aneg(struct phy_device *phydev);
--
2.43.0
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH net-next v8 10/11] onsemi: s2500: Add driver support for S2500 MAC-PHY
2026-09-28 22:25 [PATCH net-next v8 00/11] Support for onsemi's S2500 10Base-T1S MAC-PHY Selvamani Rajagopal via B4 Relay
` (8 preceding siblings ...)
2026-09-28 22:25 ` [PATCH net-next v8 09/11] net: phy: ncn26000: Support for loopback Selvamani Rajagopal via B4 Relay
@ 2026-09-28 22:25 ` Selvamani Rajagopal via B4 Relay
2026-10-06 13:54 ` Andrew Lunn
2026-09-28 22:25 ` [PATCH net-next v8 11/11] onsemi: s2500: Added selftest support to onsemi's S2500 driver Selvamani Rajagopal via B4 Relay
10 siblings, 1 reply; 24+ messages in thread
From: Selvamani Rajagopal via B4 Relay @ 2026-09-28 22:25 UTC (permalink / raw)
To: Selva Rajagopal, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Piergiorgio Beruto, Parthiban Veerasooran,
Simon Horman, Jonathan Corbet, Shuah Khan, Randy Dunlap,
Richard Cochran, Andrew Lunn, Heiner Kallweit, Russell King
Cc: Selva Rajagopal, netdev, devicetree, linux-kernel, linux-doc, Jerry Ray
From: Selvamani Rajagopal <Selvamani.Rajagopal@onsemi.com>
Support for onsemi's S2500, 802.3 cg compliant Ethernet
transceiver with integrated MAC-PHY. Works with
Open Alliance TC6 framework.
Hardware timestamp support is present in the driver.
adjtime callback is implemented using settime callback.
Driver has ethtool support for printing some device
registers, MAC stats, rmon stats and timestamp related
traffic counters.
Driver supports maximum three multicast filters. If
system has more than 3 multicast addresses to support,
all multicast traffic is allowed.
Signed-off-by: Selvamani Rajagopal <Selvamani.Rajagopal@onsemi.com>
---
changes in v8
- changes to use the new MMS read/write API in oa tc6 framework
- Updated to improve adjtime/adjfine implementation
- cleanup to remove unncessary definitions/initializations
- Removed unnecessary ioctl callback
changes in v7
- Moved the update to MAINTAINERS to the patch that has DTS
as it comes first.
- Added space between {}. Added missing MODULE_DEVICE_TABLE
- Removed the duplicate vendor dependency check in Kconfig
changes in v6
- Changes to ensure line length stay within 80 columns
changes in v5
- integrated the onsemi's selftest support to onsemi's driver
as a single patch as number of patches exceeded the limit
- Fixed the formatting issue in Kconfig file
- Fixed commenting issue
changes in v4
- MAC/PHY Loopback implemented by onsemi replaced by Linux
standard net_selftest APIs
- onsemi defined MMS values are replaced by OA TC definitions.
- removed only model information as it has practical use
- replaced all read/write APIs that use non-zero MMS to
use the new APIs that takes mms as one of its parameters.
- some bit manipulations are changed to use FIELD_GET macro
changes in v3
- split rmon stats and interface states separately.
- moved get_ts_info to OA TC6 framework as this isn't vendor
specific
- removed few static inline code
- moved ptp register code OA TC6 framework
changes in v2
- Removed the support for onsemi's NCN26010 which is legacy
MAC-PHY to keep only onsemi's S2500 MAC-PHY
- Renamed all the functions to start with S2500
changes in v1
- Added onsemi MAC-PHYs NCN26010 and S2500 support
---
drivers/net/ethernet/Kconfig | 1 +
drivers/net/ethernet/Makefile | 1 +
drivers/net/ethernet/onsemi/Kconfig | 22 +
drivers/net/ethernet/onsemi/Makefile | 7 +
drivers/net/ethernet/onsemi/s2500/Kconfig | 21 +
drivers/net/ethernet/onsemi/s2500/Makefile | 7 +
drivers/net/ethernet/onsemi/s2500/s2500_ethtool.c | 369 +++++++++++++++
drivers/net/ethernet/onsemi/s2500/s2500_hw_def.h | 160 +++++++
drivers/net/ethernet/onsemi/s2500/s2500_main.c | 523 ++++++++++++++++++++++
drivers/net/ethernet/onsemi/s2500/s2500_ptp.c | 174 +++++++
include/linux/oa_tc6.h | 1 +
11 files changed, 1286 insertions(+)
diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig
index 5758e0fbbca5..c160bf991345 100644
--- a/drivers/net/ethernet/Kconfig
+++ b/drivers/net/ethernet/Kconfig
@@ -137,6 +137,7 @@ source "drivers/net/ethernet/nvidia/Kconfig"
source "drivers/net/ethernet/nxp/Kconfig"
source "drivers/net/ethernet/oa_tc6/Kconfig"
source "drivers/net/ethernet/oki-semi/Kconfig"
+source "drivers/net/ethernet/onsemi/Kconfig"
config ETHOC
tristate "OpenCores 10/100 Mbps Ethernet MAC support"
diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile
index e0e86c249e42..e4bad64bf95c 100644
--- a/drivers/net/ethernet/Makefile
+++ b/drivers/net/ethernet/Makefile
@@ -74,6 +74,7 @@ obj-$(CONFIG_NET_VENDOR_NVIDIA) += nvidia/
obj-$(CONFIG_LPC_ENET) += nxp/
obj-$(CONFIG_OA_TC6) += oa_tc6/
obj-$(CONFIG_NET_VENDOR_OKI) += oki-semi/
+obj-$(CONFIG_NET_VENDOR_ONSEMI) += onsemi/
obj-$(CONFIG_ETHOC) += ethoc.o
obj-$(CONFIG_NET_VENDOR_PASEMI) += pasemi/
obj-$(CONFIG_NET_VENDOR_QLOGIC) += qlogic/
diff --git a/drivers/net/ethernet/onsemi/Kconfig b/drivers/net/ethernet/onsemi/Kconfig
new file mode 100644
index 000000000000..484de609462a
--- /dev/null
+++ b/drivers/net/ethernet/onsemi/Kconfig
@@ -0,0 +1,22 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# onsemi network device configuration
+#
+
+config NET_VENDOR_ONSEMI
+ bool "onsemi network devices"
+ default y
+ help
+ If you have a network card belonging to this class, say Y.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about onsemi ethernet devices. If you say Y, you
+ will be asked for your specific card in the following questions.
+
+if NET_VENDOR_ONSEMI
+
+source "drivers/net/ethernet/onsemi/s2500/Kconfig"
+
+endif # NET_VENDOR_ONSEMI
+
diff --git a/drivers/net/ethernet/onsemi/Makefile b/drivers/net/ethernet/onsemi/Makefile
new file mode 100644
index 000000000000..f3d4eb154313
--- /dev/null
+++ b/drivers/net/ethernet/onsemi/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Makefile for the onsemi network device drivers.
+#
+
+obj-$(CONFIG_S2500_MACPHY) += s2500/
+
diff --git a/drivers/net/ethernet/onsemi/s2500/Kconfig b/drivers/net/ethernet/onsemi/s2500/Kconfig
new file mode 100644
index 000000000000..abd967448af0
--- /dev/null
+++ b/drivers/net/ethernet/onsemi/s2500/Kconfig
@@ -0,0 +1,21 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# onsemi S2500 Driver Support
+#
+
+config S2500_MACPHY
+ tristate "S2500 support"
+ depends on SPI
+ depends on PTP_1588_CLOCK_OPTIONAL
+ imply NET_SELFTESTS
+ select BITREVERSE
+ select NCN26000_PHY
+ select OA_TC6
+ help
+ Support for the onsemi S2500 MACPHY Ethernet chip.
+ It works under the framework that conform to OPEN Alliance
+ 10BASE-T1x Serial Interface specification.
+
+ To compile this driver as a module, choose M here. The module will be
+ called s2500.
+
diff --git a/drivers/net/ethernet/onsemi/s2500/Makefile b/drivers/net/ethernet/onsemi/s2500/Makefile
new file mode 100644
index 000000000000..61ec705cdf9f
--- /dev/null
+++ b/drivers/net/ethernet/onsemi/s2500/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Makefile for the onsemi network device drivers.
+#
+obj-$(CONFIG_S2500_MACPHY) := s2500.o
+s2500-objs := s2500_main.o s2500_ethtool.o s2500_ptp.o
+
diff --git a/drivers/net/ethernet/onsemi/s2500/s2500_ethtool.c b/drivers/net/ethernet/onsemi/s2500/s2500_ethtool.c
new file mode 100644
index 000000000000..65bbcc1c7dc8
--- /dev/null
+++ b/drivers/net/ethernet/onsemi/s2500/s2500_ethtool.c
@@ -0,0 +1,369 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright 2026 Semiconductor Components Industries, LLC ("onsemi").
+ * onsemi's S2500 10BASE-T1S MAC-PHY driver
+ */
+
+#include <linux/ethtool.h>
+#include <linux/phy.h>
+
+#include "s2500_hw_def.h"
+
+#define S2500_NUM_REGS 38
+#define S2500_REGDUMP_LEN (sizeof(u32) * (S2500_NUM_REGS * 2))
+
+#define S2500_NUM_MAC_STATS 1
+#define S2500_NUM_RMON_STATS 12
+
+struct s2500_reg_map {
+ u16 reg;
+ u8 mms;
+};
+
+static const struct s2500_reg_map s2500_reg_map[S2500_NUM_REGS] = {
+ { S2500_REG_VS_ONIPVER, OA_TC6_PHY_C45_VS_PLCA_MMS4 },
+ { S2500_REG_VS_TWEAKS1, OA_TC6_PHY_C45_VS_PLCA_MMS4 },
+ { S2500_REG_VS_PLCAEXT, OA_TC6_PHY_C45_VS_PLCA_MMS4 },
+ { S2500_REG_VS_PMATUNE0, OA_TC6_PHY_C45_VS_PLCA_MMS4 },
+ { S2500_REG_VS_PMATUNE1, OA_TC6_PHY_C45_VS_PLCA_MMS4 },
+ { S2500_REG_VS_T1SWUPTUNE, OA_TC6_PHY_C45_VS_PLCA_MMS4 },
+ { S2500_REG_VS_HDD, OA_TC6_PHY_C45_VS_PLCA_MMS4 },
+ { S2500_REG_VS_DCQ_TOID, OA_TC6_PHY_C45_VS_PLCA_MMS4 },
+ { S2500_REG_VS_DCQ_SQI, OA_TC6_PHY_C45_VS_PLCA_MMS4 },
+ { S2500_REG_VS_DCQ_SQI_PLUS, OA_TC6_PHY_C45_VS_PLCA_MMS4 },
+ { S2500_REG_VS_HDD_TUNE1, OA_TC6_PHY_C45_VS_PLCA_MMS4 },
+ { S2500_REG_VS_HDD_TUNE2, OA_TC6_PHY_C45_VS_PLCA_MMS4 },
+ { S2500_REG_VS_HDD_TUNE3, OA_TC6_PHY_C45_VS_PLCA_MMS4 },
+ { S2500_REG_VS_WS_STATUS_0, OA_TC6_PHY_C45_VS_PLCA_MMS4 },
+ { S2500_REG_VS_WS_CTRL_0, OA_TC6_PHY_C45_VS_PLCA_MMS4 },
+ { S2500_REG_VS_WS_STATUS_1, OA_TC6_PHY_C45_VS_PLCA_MMS4 },
+ { S2500_REG_VS_WS_CTRL_1, OA_TC6_PHY_C45_VS_PLCA_MMS4 },
+ { S2500_REG_VS_MIIMIRQE, OA_TC6_PHY_C45_VS_MMS12 },
+ { S2500_REG_VS_MIIMIRQS, OA_TC6_PHY_C45_VS_MMS12 },
+ { S2500_REG_VS_DIOCFG0, OA_TC6_PHY_C45_VS_MMS12 },
+ { S2500_REG_VS_CHIPID, OA_TC6_PHY_C45_VS_MMS12 },
+ { S2500_REG_VS_TWEAKS2, OA_TC6_PHY_C45_VS_MMS12 },
+ { S2500_REG_VS_MACID0, OA_TC6_PHY_C45_VS_MMS12 },
+ { S2500_REG_VS_MACID1, OA_TC6_PHY_C45_VS_MMS12 },
+ { S2500_REG_VS_NVM_HEALTH, OA_TC6_PHY_C45_VS_MMS12 },
+ { S2500_REG_VS_PTP_SEC, OA_TC6_PHY_C45_VS_MMS12 },
+ { S2500_REG_VS_PTPNSEC, OA_TC6_PHY_C45_VS_MMS12 },
+ { S2500_REG_VS_PTP_SETSEC, OA_TC6_PHY_C45_VS_MMS12 },
+ { S2500_REG_VS_SETNSEC, OA_TC6_PHY_C45_VS_MMS12 },
+ { S2500_REG_VS_PTP_ADJ, OA_TC6_PHY_C45_VS_MMS12 },
+ { S2500_REG_VS_CMPCTL, OA_TC6_PHY_C45_VS_MMS12 },
+ { S2500_REG_VS_CMPSEC, OA_TC6_PHY_C45_VS_MMS12 },
+ { S2500_REG_VS_CMPNSEC, OA_TC6_PHY_C45_VS_MMS12 },
+ { S2500_REG_VS_CMPPER, OA_TC6_PHY_C45_VS_MMS12 },
+ { S2500_REG_VS_CAPCTL, OA_TC6_PHY_C45_VS_MMS12 },
+ { S2500_REG_VS_CAPSEC, OA_TC6_PHY_C45_VS_MMS12 },
+ { S2500_REG_VS_CAPNSEC, OA_TC6_PHY_C45_VS_MMS12 },
+ { S2500_REG_VS_BCNCNT, OA_TC6_PHY_C45_VS_MMS12 },
+};
+
+enum s2500_stat_idx {
+ S2500_MSTOCTECTSTX_IDX = 0,
+ S2500_MSTFRAMESTXOK_IDX,
+ S2500_MSTBCASTTXOK_IDX,
+ S2500_MSTMCASTTXOK_IDX,
+ S2500_MSTFRAMESTX64_IDX,
+ S2500_MSTFRAMESTX65_IDX,
+ S2500_MSTFRAMESTX128_IDX,
+ S2500_MSTFRAMESTX256_IDX,
+ S2500_MSTFRAMESTX512_IDX,
+ S2500_MSTFRAMESTX1024_IDX,
+ S2500_MSTTXUNDEFLOW_IDX,
+ S2500_MSTSINGLECOL_IDX,
+ S2500_MSTMULTICOL_IDX,
+ S2500_MSTEXCESSCOL_IDX,
+ S2500_MSTDEFERREDTX_IDX,
+ S2500_MSTCRSERR_IDX,
+ S2500_MSTOCTECTSRX_IDX,
+ S2500_MSTFRAMESRXOK_IDX,
+ S2500_MSTBCASTRXOK_IDX,
+ S2500_MSTMCASTRXOK_IDX,
+ S2500_MSTFRAMESRX64_IDX,
+ S2500_MSTFRAMESRX65_IDX,
+ S2500_MSTFRAMESRX128_IDX,
+ S2500_MSTFRAMESRX256_IDX,
+ S2500_MSTFRAMESRX512_IDX,
+ S2500_MSTFRAMESRX1024_IDX,
+ S2500_MSTRUNTSERR_IDX,
+ S2500_MSTRXTOOLONG_IDX,
+ S2500_MSTFCSERRS_IDX,
+ S2500_MSTSYMBOLERRS_IDX,
+ S2500_MSTALIGNERRS_IDX,
+ S2500_MSTRXOVERFLOW_IDX,
+ S2500_MSTRXDROPPED_IDX,
+};
+
+static const char s2500_mac_stat_strings[][ETH_GSTRING_LEN] = {
+ "rx_mismatch_drops",
+};
+
+static const u8 s2500_mac_stat_map[S2500_NUM_MAC_STATS] = {
+ S2500_MSTRXDROPPED_IDX,
+};
+
+static const u8 s2500_rmon_stat_map[S2500_NUM_RMON_STATS] = {
+ S2500_MSTFRAMESTX64_IDX,
+ S2500_MSTFRAMESTX65_IDX,
+ S2500_MSTFRAMESTX128_IDX,
+ S2500_MSTFRAMESTX256_IDX,
+ S2500_MSTFRAMESTX512_IDX,
+ S2500_MSTFRAMESTX1024_IDX,
+ S2500_MSTFRAMESRX64_IDX,
+ S2500_MSTFRAMESRX65_IDX,
+ S2500_MSTFRAMESRX128_IDX,
+ S2500_MSTFRAMESRX256_IDX,
+ S2500_MSTFRAMESRX512_IDX,
+ S2500_MSTFRAMESRX1024_IDX,
+};
+
+static const struct ethtool_rmon_hist_range s2500_rmon_hist_ranges[] = {
+ { 64, 64 },
+ { 65, 127 },
+ { 128, 255 },
+ { 256, 511 },
+ { 512, 1023 },
+ { 1024, 2000 },
+ { },
+};
+
+#define S2500_MAC_STATS_LEN ARRAY_SIZE(s2500_mac_stat_strings)
+static_assert(S2500_MAC_STATS_LEN == S2500_NUM_MAC_STATS);
+static_assert(ARRAY_SIZE(s2500_mac_stat_map) == S2500_NUM_MAC_STATS);
+static_assert(ARRAY_SIZE(s2500_rmon_stat_map) == S2500_NUM_RMON_STATS);
+
+#define STAT_REG_OFFSET(x) ((S2500_REG_MAC_ST##x) - \
+ S2500_REG_MAC_FIRST_STAT)
+
+static void s2500_update_stats(struct s2500_info *priv)
+{
+ u64 *data = priv->stats_data;
+ u32 *regs, *rptr, addr;
+ int ret;
+
+ if (time_is_after_jiffies(priv->stats_read_at +
+ S2500_STATS_CACHE_PERIOD))
+ return;
+
+ regs = kmalloc_array(S2500_NUM_STAT_REGS, sizeof(u32), GFP_KERNEL);
+ if (!regs)
+ return;
+
+ addr = FIELD_PREP(S2500_REG_MMS_MASK, OA_TC6_MAC_MMS1) |
+ S2500_REG_MAC_STOCTECTSTXL;
+ ret = oa_tc6_read_registers(priv->tc6, addr, regs,
+ S2500_NUM_STAT_REGS);
+ if (ret)
+ goto out;
+
+ priv->stats_read_at = jiffies;
+ rptr = regs;
+
+ /* TX bytes is a 64-bit value that is stored in two regs */
+ *(data++) += ((u64)*rptr) | (((u64)*(rptr + 1)) << 32);
+
+ /* Rest are 32-bit values until RX bytes register. */
+ for (rptr += 2; (rptr - regs) < STAT_REG_OFFSET(OCTECTSRXL); ++rptr)
+ *(data++) += *rptr;
+
+ /* RX bytes is a 64-bit value that is stored in two regs */
+ *(data++) += ((u64)*rptr) | (((u64)*(rptr + 1)) << 32);
+
+ for (rptr += 2; (rptr - regs) < S2500_NUM_STAT_REGS; ++rptr)
+ *(data++) += *rptr;
+out:
+ kfree(regs);
+}
+
+static void s2500_get_drvinfo(struct net_device *ndev,
+ struct ethtool_drvinfo *info)
+{
+ struct s2500_info *priv = netdev_priv(ndev);
+
+ strscpy(info->driver, DRV_NAME, sizeof(info->driver));
+ strscpy(info->bus_info, dev_name(&priv->spi->dev),
+ sizeof(info->bus_info));
+}
+
+static int s2500_get_sset_count(struct net_device *ndev, int sset)
+{
+ switch (sset) {
+ case ETH_SS_STATS:
+ return S2500_MAC_STATS_LEN;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static void s2500_get_strings(struct net_device *ndev, u32 stringset,
+ u8 *buf)
+{
+ switch (stringset) {
+ case ETH_SS_STATS:
+ memcpy(buf, s2500_mac_stat_strings,
+ S2500_MAC_STATS_LEN * ETH_GSTRING_LEN);
+ break;
+ }
+}
+
+static void s2500_get_ethtool_stats(struct net_device *ndev,
+ struct ethtool_stats *stats, u64 *data)
+{
+ struct s2500_info *priv = netdev_priv(ndev);
+ int i;
+
+ s2500_update_stats(priv);
+ for (i = 0; i < S2500_NUM_MAC_STATS; i++)
+ data[i] = priv->stats_data[s2500_mac_stat_map[i]];
+}
+
+static void s2500_get_eth_mac_stats(struct net_device *ndev,
+ struct ethtool_eth_mac_stats *mac_stats)
+{
+ struct s2500_info *priv = netdev_priv(ndev);
+ const u64 *st;
+
+ if (mac_stats->src != ETHTOOL_MAC_STATS_SRC_AGGREGATE)
+ return;
+
+ s2500_update_stats(priv);
+ st = priv->stats_data;
+
+ mac_stats->OctetsTransmittedOK = st[S2500_MSTOCTECTSTX_IDX];
+ mac_stats->FramesTransmittedOK = st[S2500_MSTFRAMESTXOK_IDX];
+ mac_stats->BroadcastFramesXmittedOK = st[S2500_MSTBCASTTXOK_IDX];
+ mac_stats->MulticastFramesXmittedOK = st[S2500_MSTMCASTTXOK_IDX];
+ mac_stats->SingleCollisionFrames = st[S2500_MSTSINGLECOL_IDX];
+ mac_stats->MultipleCollisionFrames = st[S2500_MSTMULTICOL_IDX];
+ mac_stats->FramesAbortedDueToXSColls = st[S2500_MSTEXCESSCOL_IDX];
+ mac_stats->FramesWithDeferredXmissions = st[S2500_MSTDEFERREDTX_IDX];
+ mac_stats->CarrierSenseErrors = st[S2500_MSTCRSERR_IDX];
+ mac_stats->FramesLostDueToIntMACXmitError =
+ st[S2500_MSTTXUNDEFLOW_IDX];
+ mac_stats->OctetsReceivedOK = st[S2500_MSTOCTECTSRX_IDX];
+ mac_stats->FramesReceivedOK = st[S2500_MSTFRAMESRXOK_IDX];
+ mac_stats->BroadcastFramesReceivedOK = st[S2500_MSTBCASTRXOK_IDX];
+ mac_stats->MulticastFramesReceivedOK = st[S2500_MSTMCASTRXOK_IDX];
+ mac_stats->FrameTooLongErrors = st[S2500_MSTRXTOOLONG_IDX];
+ mac_stats->FrameCheckSequenceErrors = st[S2500_MSTFCSERRS_IDX];
+ mac_stats->AlignmentErrors = st[S2500_MSTALIGNERRS_IDX];
+ mac_stats->FramesLostDueToIntMACRcvError =
+ st[S2500_MSTRXOVERFLOW_IDX];
+}
+
+static void s2500_get_eth_phy_stats(struct net_device *ndev,
+ struct ethtool_eth_phy_stats *phy_stats)
+{
+ struct s2500_info *priv = netdev_priv(ndev);
+
+ if (phy_stats->src != ETHTOOL_MAC_STATS_SRC_AGGREGATE)
+ return;
+
+ s2500_update_stats(priv);
+ phy_stats->SymbolErrorDuringCarrier =
+ priv->stats_data[S2500_MSTSYMBOLERRS_IDX];
+}
+
+static void s2500_rmon_stats(struct net_device *ndev,
+ struct ethtool_rmon_stats *rmon_stats,
+ const struct ethtool_rmon_hist_range **ranges)
+{
+ struct s2500_info *priv = netdev_priv(ndev);
+ u8 offset;
+ int i;
+
+ if (rmon_stats->src != ETHTOOL_MAC_STATS_SRC_AGGREGATE)
+ return;
+
+ s2500_update_stats(priv);
+
+ rmon_stats->undersize_pkts = priv->stats_data[S2500_MSTRUNTSERR_IDX];
+ rmon_stats->oversize_pkts = priv->stats_data[S2500_MSTRXTOOLONG_IDX];
+
+ for (i = 0; i < 6; i++) {
+ offset = s2500_rmon_stat_map[i];
+ rmon_stats->hist_tx[i] = priv->stats_data[offset];
+ }
+
+ for (i = 0; i < 6; i++) {
+ offset = s2500_rmon_stat_map[i + 6];
+ rmon_stats->hist[i] = priv->stats_data[offset];
+ }
+
+ *ranges = s2500_rmon_hist_ranges;
+}
+
+static int s2500_get_ts_info(struct net_device *ndev,
+ struct kernel_ethtool_ts_info *ts_info)
+{
+ struct s2500_info *priv = netdev_priv(ndev);
+
+ return oa_tc6_get_ts_info(priv->tc6, ts_info);
+}
+
+static int s2500_get_regs_len(struct net_device *dev)
+{
+ return S2500_REGDUMP_LEN;
+}
+
+static void s2500_get_regs(struct net_device *ndev,
+ struct ethtool_regs *regs, void *p)
+{
+ struct s2500_info *priv = netdev_priv(ndev);
+ __be32 *pbuff = p;
+ int ret = 0;
+ u32 val;
+ u16 reg;
+ u8 mms;
+ int i;
+
+ regs->version = 0;
+ memset(p, 0, S2500_REGDUMP_LEN);
+
+ if (!netif_running(ndev))
+ return;
+
+ for (i = 0; i < S2500_NUM_REGS; i++) {
+ val = 0;
+ reg = s2500_reg_map[i].reg;
+ mms = s2500_reg_map[i].mms;
+ ret = oa_tc6_read_register_mms(priv->tc6, mms, reg,
+ &val);
+
+ /* Write a pattern to indicate failure */
+ if (ret)
+ val = 0xDEADC0DE;
+ *pbuff++ = cpu_to_be32(((u32)mms << 16) | reg);
+ *pbuff++ = cpu_to_be32(val);
+ }
+}
+
+static void s2500_get_ts_stats(struct net_device *ndev,
+ struct ethtool_ts_stats *ts_stats)
+{
+ struct s2500_info *priv = netdev_priv(ndev);
+
+ oa_tc6_get_ts_stats(priv->tc6, ts_stats);
+}
+
+const struct ethtool_ops s2500_ethtool_ops = {
+ .get_drvinfo = s2500_get_drvinfo,
+ .get_link = ethtool_op_get_link,
+ .get_link_ksettings = phy_ethtool_get_link_ksettings,
+ .set_link_ksettings = phy_ethtool_set_link_ksettings,
+ .get_ts_stats = s2500_get_ts_stats,
+ .get_sset_count = s2500_get_sset_count,
+ .get_strings = s2500_get_strings,
+ .get_ethtool_stats = s2500_get_ethtool_stats,
+ .get_eth_mac_stats = s2500_get_eth_mac_stats,
+ .get_eth_phy_stats = s2500_get_eth_phy_stats,
+ .get_rmon_stats = s2500_rmon_stats,
+ .get_ts_info = s2500_get_ts_info,
+ .get_regs_len = s2500_get_regs_len,
+ .get_regs = s2500_get_regs,
+ .self_test = net_selftest,
+};
+
diff --git a/drivers/net/ethernet/onsemi/s2500/s2500_hw_def.h b/drivers/net/ethernet/onsemi/s2500/s2500_hw_def.h
new file mode 100644
index 000000000000..0d0b335a397a
--- /dev/null
+++ b/drivers/net/ethernet/onsemi/s2500/s2500_hw_def.h
@@ -0,0 +1,160 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright 2026 Semiconductor Components Industries, LLC ("onsemi").
+ * onsemi's S2500 10BASE-T1S MAC-PHY driver
+ */
+
+#ifndef S2500_HW_DEF_H
+#define S2500_HW_DEF_H
+
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/spi/spi.h>
+#include <linux/phylink.h>
+#include <linux/net_tstamp.h>
+#include <linux/ptp_clock_kernel.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/ktime.h>
+#include <linux/errno.h>
+#include <linux/oa_tc6.h>
+
+#define DRV_NAME "s2500"
+
+#define S2500_N_MCAST_FILTERS 3
+
+#define S2500_REG_MMS_MASK GENMASK(19, 16)
+
+/* SPI OID and model register */
+#define S2500_REG_PHYID 0x1
+
+#define S2500_PHYID_OUI_SHIFT 10
+#define S2500_PHYID_OUI_MASK GENMASK(31, S2500_PHYID_OUI_SHIFT)
+#define S2500_PHYID_OUI_MASK0 GENMASK(21, 16)
+#define S2500_PHYID_OUI_MASK1 GENMASK(15, 8)
+#define S2500_PHYID_OUI_MASK2 GENMASK(7, 0)
+
+#define S2500_CONFIG0_TXCTHRESH_SHIFT 10
+#define S2500_CONFIG0_RXCTE BIT(8)
+#define S2500_CONFIG0_CPS_SHIFT 0
+#define S2500_CONFIG0_TXCTHRESH_8 0x2
+#define S2500_CONFIG0_CPS_64 0x6
+
+/* Read only bit in STATUS0 register */
+#define S2500_STATUS0_PHY_INT BIT(7)
+
+#define S2500_REG_MAC_CTRL 0x0
+
+#define S2500_MAC_CTRL_MCSF BIT(18)
+#define S2500_MAC_CTRL_ADRF BIT(16)
+#define S2500_MAC_CTRL_FCSA BIT(8)
+#define S2500_MAC_CTRL_TXEN BIT(1)
+#define S2500_MAC_CTRL_RXEN BIT(0)
+
+/* MAC address filter registers */
+#define S2500_REG_MAC_ADDRFILTL(n) (16 + 2 * (n))
+#define S2500_REG_MAC_ADDRFILTH(n) (17 + 2 * (n))
+#define S2500_REG_MAC_ADDRMASKL(n) (32 + 2 * (n))
+#define S2500_REG_MAC_ADDRMASKH(n) (33 + 2 * (n))
+
+#define S2500_MAC_ADDRFILT_ENABLE BIT(31)
+
+/* MAC statistic registers */
+#define S2500_REG_MAC_STOCTECTSTXL 48
+#define S2500_REG_MAC_STOCTECTSTXH 49
+#define S2500_REG_MAC_STOCTECTSRXL 65
+#define S2500_REG_MAC_STOCTECTSRXH 66
+#define S2500_REG_MAC_STRXDROPPED 82
+
+/* First/last statistic register for sequential access */
+#define S2500_REG_MAC_FIRST_STAT S2500_REG_MAC_STOCTECTSTXL
+#define S2500_REG_MAC_LAST_STAT S2500_REG_MAC_STRXDROPPED
+
+#define S2500_NUM_STAT_REGS \
+ (S2500_REG_MAC_LAST_STAT - S2500_REG_MAC_FIRST_STAT + 1)
+#define S2500_NUM_STAT_VARS (S2500_NUM_STAT_REGS - 2)
+#define S2500_STATS_CACHE_PERIOD msecs_to_jiffies(100)
+
+/* Vendor specific MMS4 registers */
+#define S2500_REG_VS_ONIPVER 0x8000
+#define S2500_REG_VS_TWEAKS1 0x8001
+#define S2500_REG_VS_PLCAEXT 0x8002
+#define S2500_REG_VS_PMATUNE0 0x8003
+#define S2500_REG_VS_PMATUNE1 0x8004
+#define S2500_REG_VS_T1SWUPTUNE 0x8007
+#define S2500_REG_VS_HDD 0xCC01
+#define S2500_REG_VS_DCQ_TOID 0xCC02
+#define S2500_REG_VS_DCQ_SQI 0xCC03
+#define S2500_REG_VS_DCQ_SQI_PLUS 0xCC04
+#define S2500_REG_VS_HDD_TUNE1 0xCD00
+#define S2500_REG_VS_HDD_TUNE2 0xCD01
+#define S2500_REG_VS_HDD_TUNE3 0xCD02
+#define S2500_REG_VS_WS_STATUS_0 0xD000
+#define S2500_REG_VS_WS_CTRL_0 0xD001
+#define S2500_REG_VS_WS_STATUS_1 0xD100
+#define S2500_REG_VS_WS_CTRL_1 0xD101
+
+/* Vendor specific MMS12 registers */
+#define S2500_REG_VS_MIIMIRQE 0x10
+
+/* MIIM IRQ status register */
+#define S2500_REG_VS_MIIMIRQS 0x11
+
+#define S2500_REG_VS_DIOCFG0 0x12
+
+#define S2500_REG_VS_CHIPID 0x1000
+#define S2500_REG_VS_TWEAKS2 0x1001
+
+/* Permanent MAC address register */
+#define S2500_REG_VS_MACID0 0x1002
+#define S2500_VS_MACID0_BYTE4_MASK GENMASK(15, 8)
+#define S2500_VS_MACID0_BYTE5_MASK GENMASK(7, 0)
+
+#define S2500_REG_VS_MACID1 0x1003
+#define S2500_VS_MACID1_BYTE3_MASK GENMASK(7, 0)
+#define S2500_REG_VS_NVM_HEALTH 0x1005
+
+/* PTP registers */
+#define S2500_REG_VS_PTP_SEC 0x1010
+#define S2500_REG_VS_PTP_SETSEC 0x1012
+#define S2500_REG_VS_PTP_ADJ 0x1014
+
+/* Frequency adjust magnitude, 1 LSB = 0.000125 ppm = 1/8 ppb */
+#define S2500_PTP_ADJ_MAX GENMASK(27, 0)
+#define S2500_PTP_MAX_ADJ_PPB (S2500_PTP_ADJ_MAX / 8)
+#define S2500_REG_VS_PTPNSEC 0x1011
+#define S2500_REG_VS_SETNSEC 0x1013
+#define S2500_REG_VS_CMPCTL 0x1015
+#define S2500_REG_VS_CMPSEC 0x1016
+#define S2500_REG_VS_CMPNSEC 0x1017
+#define S2500_REG_VS_CMPPER 0x1018
+#define S2500_REG_VS_CAPCTL 0x1019
+#define S2500_REG_VS_CAPSEC 0x101A
+#define S2500_REG_VS_CAPNSEC 0x101B
+#define S2500_REG_VS_BCNCNT 0x101C
+
+/* prototypes / forward declarations */
+extern const struct ethtool_ops s2500_ethtool_ops;
+
+struct s2500_info {
+ struct device *dev;
+ struct net_device *ndev;
+
+ /* To have atomic operation for PTP time registers */
+ struct mutex ptp_adj_lock;
+
+ struct spi_device *spi;
+
+ /* statistic counters variables */
+ u64 stats_data[S2500_NUM_STAT_VARS];
+ unsigned long stats_read_at;
+
+ /* PTP related variables */
+ struct ptp_clock_info ptp_clock_info;
+ struct oa_tc6 *tc6;
+};
+
+int s2500_ptp_register(struct s2500_info *priv);
+
+#endif /* S2500_HW_DEF_H */
+
diff --git a/drivers/net/ethernet/onsemi/s2500/s2500_main.c b/drivers/net/ethernet/onsemi/s2500/s2500_main.c
new file mode 100644
index 000000000000..b74519776f4d
--- /dev/null
+++ b/drivers/net/ethernet/onsemi/s2500/s2500_main.c
@@ -0,0 +1,523 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright 2026 Semiconductor Components Industries, LLC ("onsemi").
+ * onsemi's S2500 10BASE-T1S MAC-PHY driver
+ */
+
+#include <linux/etherdevice.h>
+#include <linux/if_ether.h>
+#include <linux/irqchip.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/bitrev.h>
+#include <linux/phy.h>
+
+#include "s2500_hw_def.h"
+
+/* Initializes the net device MAC address by reading the UID stored
+ * into the device internal non-volatile memory.
+ */
+static int s2500_read_mac_from_nvmem(struct s2500_info *priv)
+{
+ u8 mms = OA_TC6_PHY_C45_VS_MMS12;
+ u8 addr[ETH_ALEN];
+ u32 mac1 = 0;
+ u32 mac0 = 0;
+ u32 val;
+ int ret;
+
+ ret = oa_tc6_read_register_mms(priv->tc6, mms,
+ S2500_REG_VS_MACID1, &mac1);
+ if (ret)
+ return ret;
+
+ ret = oa_tc6_read_register_mms(priv->tc6, mms,
+ S2500_REG_VS_MACID0, &mac0);
+ if (ret)
+ return ret;
+
+ /* Pre-production parts may have 0 */
+ if (mac0 == 0 && mac1 == 0)
+ return -ENXIO;
+
+ ret = oa_tc6_read_register(priv->tc6, S2500_REG_PHYID, &val);
+ if (ret)
+ return ret;
+
+ val = (val & S2500_PHYID_OUI_MASK) >> S2500_PHYID_OUI_SHIFT;
+
+ /* Mapping for bits from PHY ID register to OUI as give below.
+ * - PHY-ID[10:17] provides OUI[16:23]
+ * - PHY-ID[18:25] provides OUI[8:15]
+ * - PHY-ID[26:31] provides OUI[2:7]
+ *
+ * Hardware presents OUI such a way that this requires not just
+ * byte level swap, bit level swap is needed as well.
+ */
+ addr[0] = bitrev8(FIELD_GET(S2500_PHYID_OUI_MASK0, val));
+ addr[1] = bitrev8(FIELD_GET(S2500_PHYID_OUI_MASK1, val));
+ addr[2] = bitrev8(FIELD_GET(S2500_PHYID_OUI_MASK2, val));
+
+ addr[3] = FIELD_GET(S2500_VS_MACID1_BYTE3_MASK, mac1);
+ addr[4] = FIELD_GET(S2500_VS_MACID0_BYTE4_MASK, mac0);
+ addr[5] = FIELD_GET(S2500_VS_MACID0_BYTE5_MASK, mac0);
+
+ __dev_addr_set(priv->ndev, addr, ETH_ALEN);
+ priv->ndev->addr_assign_type = NET_ADDR_PERM;
+ return ret;
+}
+
+/* Writes MAC address to macphy registers */
+static int s2500_set_mac_filter(struct net_device *ndev, const u8 *mac)
+{
+ struct s2500_info *priv = netdev_priv(ndev);
+ u8 mms = OA_TC6_MAC_MMS1;
+ u32 val;
+ int ret;
+
+ /* Set unicast address filter */
+ ret = oa_tc6_write_register_mms(priv->tc6, mms,
+ S2500_REG_MAC_ADDRMASKL(0),
+ 0xffffffff);
+ if (ret)
+ return ret;
+
+ ret = oa_tc6_write_register_mms(priv->tc6, mms,
+ S2500_REG_MAC_ADDRMASKH(0),
+ 0xffff);
+ if (ret)
+ return ret;
+
+ val = get_unaligned_be32(&mac[2]);
+
+ ret = oa_tc6_write_register_mms(priv->tc6, mms,
+ S2500_REG_MAC_ADDRFILTL(0),
+ val);
+ if (ret)
+ return ret;
+
+ val = S2500_MAC_ADDRFILT_ENABLE | get_unaligned_be16(mac);
+
+ return oa_tc6_write_register_mms(priv->tc6, mms,
+ S2500_REG_MAC_ADDRFILTH(0),
+ val);
+}
+
+static int s2500_mac_ctrl_modify_bits(struct s2500_info *priv,
+ u32 in_bits, bool clr)
+{
+ u32 reg = S2500_REG_MAC_CTRL;
+ u8 mms = OA_TC6_MAC_MMS1;
+ u32 rval = 0;
+ u32 wval = 0;
+ int ret;
+
+ ret = oa_tc6_read_register_mms(priv->tc6, mms, reg, &rval);
+ if (ret)
+ return ret;
+
+ if (clr)
+ wval = rval & ~in_bits;
+ else
+ wval = rval | in_bits;
+ if (rval != wval)
+ ret = oa_tc6_write_register_mms(priv->tc6, mms,
+ reg, wval);
+ return ret;
+}
+
+static int s2500_init(struct s2500_info *priv)
+{
+ u32 val;
+ int ret;
+
+ /* Configure MAC-PHY's behavior */
+ val = OA_TC6_CONFIG0_SYNC | S2500_CONFIG0_RXCTE |
+ (S2500_CONFIG0_TXCTHRESH_8 <<
+ S2500_CONFIG0_TXCTHRESH_SHIFT) |
+ (S2500_CONFIG0_CPS_64 << S2500_CONFIG0_CPS_SHIFT) |
+ OA_TC6_CONFIG0_FTSS_64BIT_TSTAMP;
+
+ ret = oa_tc6_write_register(priv->tc6, OA_TC6_REG_CONFIG0,
+ val);
+ if (ret)
+ return ret;
+
+ /* Program the source MAC address into the device */
+ ret = s2500_set_mac_filter(priv->ndev, priv->ndev->dev_addr);
+ if (ret)
+ return ret;
+
+ val = S2500_MAC_CTRL_ADRF | S2500_MAC_CTRL_FCSA;
+
+ return s2500_mac_ctrl_modify_bits(priv, val, false);
+}
+
+static void s2500_shutdown(struct s2500_info *priv)
+{
+ u32 val = S2500_MAC_CTRL_TXEN | S2500_MAC_CTRL_RXEN;
+ struct net_device *ndev = priv->ndev;
+
+ netif_stop_queue(ndev);
+ phy_stop(ndev->phydev);
+
+ s2500_mac_ctrl_modify_bits(priv, val, true);
+}
+
+static int s2500_set_promiscuous_mode(struct s2500_info *priv,
+ unsigned int rx_flags)
+{
+ u32 val = S2500_MAC_CTRL_ADRF;
+ bool clr = false;
+
+ if (rx_flags & IFF_PROMISC)
+ clr = true;
+ return s2500_mac_ctrl_modify_bits(priv, val, clr);
+}
+
+static int s2500_set_multicast_mode(struct s2500_info *priv,
+ unsigned int rx_flags,
+ struct netdev_hw_addr_list *mc)
+{
+ struct netdev_hw_addr *ha;
+ u8 mms = OA_TC6_MAC_MMS1;
+ int i, ret = 0;
+ int mc_count;
+ u16 addr;
+ u32 val;
+
+ mc_count = netdev_hw_addr_list_count(mc);
+
+ if ((rx_flags & IFF_ALLMULTI) ||
+ mc_count > S2500_N_MCAST_FILTERS) {
+ /* Disable multicast filter */
+ ret = s2500_mac_ctrl_modify_bits(priv,
+ S2500_MAC_CTRL_MCSF,
+ true);
+ if (ret)
+ return ret;
+
+ /* Accept all multicasts */
+ addr = S2500_REG_MAC_ADDRMASKL(1);
+ ret = oa_tc6_write_register_mms(priv->tc6, mms,
+ addr, 0);
+ if (ret)
+ return ret;
+
+ addr = S2500_REG_MAC_ADDRMASKH(1);
+ ret = oa_tc6_write_register_mms(priv->tc6, mms,
+ addr, 0x100);
+ if (ret)
+ return ret;
+
+ addr = S2500_REG_MAC_ADDRFILTL(1);
+ ret = oa_tc6_write_register_mms(priv->tc6, mms,
+ addr, 0);
+ if (ret)
+ return ret;
+
+ val = S2500_MAC_ADDRFILT_ENABLE | 0x00000100;
+ addr = S2500_REG_MAC_ADDRFILTH(1);
+ ret = oa_tc6_write_register_mms(priv->tc6, mms,
+ addr, val);
+ } else if (mc_count == 0) {
+ /* Enable multicast filter */
+ ret = s2500_mac_ctrl_modify_bits(priv,
+ S2500_MAC_CTRL_MCSF,
+ false);
+ if (ret)
+ return ret;
+
+ /* Disable filters */
+ for (i = 1; i <= S2500_N_MCAST_FILTERS; i++) {
+ addr = S2500_REG_MAC_ADDRFILTH(i);
+ ret = oa_tc6_write_register_mms(priv->tc6,
+ mms, addr, 0);
+ if (ret)
+ return ret;
+ }
+ } else {
+ u32 addrh, addrl;
+
+ /* Disable multicast filter */
+ ret = s2500_mac_ctrl_modify_bits(priv,
+ S2500_MAC_CTRL_MCSF,
+ true);
+ if (ret)
+ return ret;
+
+ /* Disable filters */
+ for (i = 1; i <= S2500_N_MCAST_FILTERS; i++) {
+ addr = S2500_REG_MAC_ADDRFILTH(i);
+ ret = oa_tc6_write_register_mms(priv->tc6,
+ mms, addr, 0);
+ if (ret)
+ return ret;
+ }
+
+ /* Slot 0 holds the unicast MAC, multicast starts at 1 */
+ i = 1;
+ netdev_hw_addr_list_for_each(ha, mc) {
+ const u8 *mac = ha->addr;
+ int slot = i++;
+
+ addrh = S2500_MAC_ADDRFILT_ENABLE |
+ get_unaligned_be16(mac);
+ addrl = get_unaligned_be32(&mac[2]);
+
+ addr = S2500_REG_MAC_ADDRFILTH(slot);
+ ret = oa_tc6_write_register_mms(priv->tc6,
+ mms, addr,
+ addrh);
+ if (ret)
+ return ret;
+
+ addr = S2500_REG_MAC_ADDRFILTL(slot);
+ ret = oa_tc6_write_register_mms(priv->tc6,
+ mms, addr,
+ addrl);
+ if (ret)
+ return ret;
+
+ addr = S2500_REG_MAC_ADDRMASKL(slot);
+ ret = oa_tc6_write_register_mms(priv->tc6,
+ mms, addr,
+ 0xffffffff);
+ if (ret)
+ return ret;
+
+ addr = S2500_REG_MAC_ADDRMASKH(slot);
+ ret = oa_tc6_write_register_mms(priv->tc6,
+ mms, addr,
+ 0xffff);
+ if (ret)
+ return ret;
+ }
+ }
+ return ret;
+}
+
+static int s2500_set_rx_mode(struct net_device *ndev,
+ struct netdev_hw_addr_list *uc,
+ struct netdev_hw_addr_list *mc)
+{
+ struct s2500_info *priv = netdev_priv(ndev);
+ int ret;
+
+ ret = s2500_set_promiscuous_mode(priv, ndev->flags);
+ if (ret)
+ return ret;
+
+ return s2500_set_multicast_mode(priv, ndev->flags, mc);
+}
+
+static int s2500_set_mac_address(struct net_device *ndev, void *p)
+{
+ struct sockaddr *addr = p;
+ int ret;
+
+ if (!is_valid_ether_addr(addr->sa_data))
+ return -EADDRNOTAVAIL;
+
+ ret = s2500_set_mac_filter(ndev, addr->sa_data);
+ if (ret)
+ return ret;
+
+ eth_hw_addr_set(ndev, addr->sa_data);
+ return ret;
+}
+
+static netdev_tx_t s2500_start_xmit(struct sk_buff *skb,
+ struct net_device *ndev)
+{
+ struct s2500_info *priv = netdev_priv(ndev);
+
+ return oa_tc6_start_xmit(priv->tc6, skb);
+}
+
+static int s2500_open(struct net_device *ndev)
+{
+ struct s2500_info *priv = netdev_priv(ndev);
+ u32 val;
+ int ret;
+
+ dev_dbg(&ndev->dev, "%s", "s2500_open\n");
+ phy_start(priv->ndev->phydev);
+
+ val = S2500_MAC_CTRL_TXEN | S2500_MAC_CTRL_RXEN;
+ ret = s2500_mac_ctrl_modify_bits(priv, val, false);
+ if (!ret)
+ netif_start_queue(priv->ndev);
+ else
+ phy_stop(priv->ndev->phydev);
+ return ret;
+}
+
+static int s2500_stop(struct net_device *ndev)
+{
+ struct s2500_info *priv = netdev_priv(ndev);
+
+ dev_dbg(&ndev->dev, "%s", "s2500_stop\n");
+
+ s2500_shutdown(priv);
+ return 0;
+}
+
+static int s2500_hwtstamp_get(struct net_device *ndev,
+ struct kernel_hwtstamp_config *k_cfg)
+{
+ struct s2500_info *priv = netdev_priv(ndev);
+
+ oa_tc6_hwtstamp_get(priv->tc6, k_cfg);
+ return 0;
+}
+
+static int s2500_hwtstamp_set(struct net_device *ndev,
+ struct kernel_hwtstamp_config *cfg,
+ struct netlink_ext_ack *extack)
+{
+ struct s2500_info *priv = netdev_priv(ndev);
+
+ return oa_tc6_hwtstamp_set(priv->tc6, cfg);
+}
+
+static const struct net_device_ops s2500_netdev_ops = {
+ .ndo_open = s2500_open,
+ .ndo_stop = s2500_stop,
+ .ndo_start_xmit = s2500_start_xmit,
+ .ndo_set_mac_address = s2500_set_mac_address,
+ .ndo_set_rx_mode_async = s2500_set_rx_mode,
+ .ndo_eth_ioctl = phy_do_ioctl_running,
+ .ndo_hwtstamp_get = s2500_hwtstamp_get,
+ .ndo_hwtstamp_set = s2500_hwtstamp_set,
+};
+
+static int s2500_probe(struct spi_device *spi)
+{
+ struct device *dev = &spi->dev;
+ struct net_device *ndev;
+ struct s2500_info *priv;
+ u32 val;
+ int ret;
+
+ if (spi->irq < 0)
+ return -ENODEV;
+
+ ndev = devm_alloc_etherdev(dev, sizeof(struct s2500_info));
+ if (!ndev)
+ return -ENOMEM;
+
+ priv = netdev_priv(ndev);
+ priv->ndev = ndev;
+ priv->spi = spi;
+ priv->dev = dev;
+
+ SET_NETDEV_DEV(ndev, dev);
+
+ mutex_init(&priv->ptp_adj_lock);
+ ndev->irq = spi->irq;
+
+ /* Ensures that the first read is not from the cache. */
+ priv->stats_read_at = jiffies - S2500_STATS_CACHE_PERIOD;
+
+ spi_set_drvdata(spi, priv);
+
+ ndev->netdev_ops = &s2500_netdev_ops;
+ ndev->ethtool_ops = &s2500_ethtool_ops;
+ ndev->if_port = IF_PORT_10BASET;
+
+ priv->tc6 = oa_tc6_init(spi, ndev, NULL);
+ if (IS_ERR(priv->tc6)) {
+ ret = PTR_ERR(priv->tc6);
+ dev_err(&spi->dev, "OA TC6 init failed\n");
+ return ret;
+ }
+ oa_tc6_set_vend1_mms(priv->tc6, OA_TC6_PHY_C45_VS_MMS12);
+
+ /* All read-only bits. Some are self clear. No need to write */
+ ret = oa_tc6_read_register_mms(priv->tc6, OA_TC6_PHY_C45_VS_MMS12,
+ S2500_REG_VS_MIIMIRQS, &val);
+ if (ret) {
+ dev_err(&spi->dev, "Failed to read MIIM IRQ status\n");
+ goto err_reg_read;
+ }
+
+ /* Acknowledge all IRQ status bits */
+ ret = oa_tc6_read_register(priv->tc6,
+ OA_TC6_REG_STATUS0, &val);
+ if (!ret) {
+ /* Clear read only bit */
+ val &= ~S2500_STATUS0_PHY_INT;
+ oa_tc6_write_register(priv->tc6,
+ OA_TC6_REG_STATUS0, val);
+ }
+
+ ret = device_get_ethdev_address(priv->dev, ndev);
+ if (ret)
+ ret = s2500_read_mac_from_nvmem(priv);
+
+ if (ret) {
+ eth_hw_addr_random(ndev);
+ dev_warn(&spi->dev, "Using random MAC address %pM\n",
+ ndev->dev_addr);
+ }
+
+ ret = s2500_init(priv);
+ if (ret) {
+ dev_err(&spi->dev, "Failure seen in s2500_init\n");
+ goto err_reg_read;
+ }
+
+ /* Configure PTP as S2500 supports it */
+ ret = s2500_ptp_register(priv);
+ if (ret)
+ goto err_reg_read;
+
+ ret = register_netdev(ndev);
+ if (!ret)
+ return ret;
+ dev_err(&spi->dev, "Failed to register netdev\n");
+ oa_tc6_ptp_unregister(priv->tc6);
+err_reg_read:
+ oa_tc6_exit(priv->tc6);
+ return ret;
+}
+
+static void s2500_remove(struct spi_device *spi)
+{
+ struct s2500_info *priv = spi_get_drvdata(spi);
+
+ dev_dbg(&priv->ndev->dev, "%s", "s2500_remove\n");
+
+ unregister_netdev(priv->ndev);
+ oa_tc6_ptp_unregister(priv->tc6);
+ oa_tc6_exit(priv->tc6);
+}
+
+static const struct of_device_id s2500_of_match[] = {
+ { .compatible = "onnn,s2500" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, s2500_of_match);
+
+static const struct spi_device_id s2500_ids[] = {
+ { "s2500" },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, s2500_ids);
+
+static struct spi_driver s2500_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .of_match_table = s2500_of_match,
+ },
+ .probe = s2500_probe,
+ .remove = s2500_remove,
+ .id_table = s2500_ids,
+};
+module_spi_driver(s2500_driver);
+
+MODULE_AUTHOR("Piergiorgio Beruto <pier.beruto@onsemi.com>");
+MODULE_AUTHOR("Selva Rajagopal <selvamani.rajagopal@onsemi.com>");
+MODULE_DESCRIPTION("onsemi MACPHY ethernet driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/onsemi/s2500/s2500_ptp.c b/drivers/net/ethernet/onsemi/s2500/s2500_ptp.c
new file mode 100644
index 000000000000..441f33a6cf9a
--- /dev/null
+++ b/drivers/net/ethernet/onsemi/s2500/s2500_ptp.c
@@ -0,0 +1,174 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright 2026 Semiconductor Components Industries, LLC ("onsemi").
+ * onsemi's S2500 10BASE-T1S MAC-PHY driver
+ */
+
+#include "s2500_hw_def.h"
+
+static int s2500_ptp_get_time64(struct ptp_clock_info *ptp,
+ struct timespec64 *ts,
+ struct ptp_system_timestamp *ptp_sts)
+{
+ struct s2500_info *priv = container_of(ptp, struct s2500_info,
+ ptp_clock_info);
+ u32 data[2];
+ u32 addr;
+ int ret;
+
+ ptp_read_system_prets(ptp_sts);
+ addr = FIELD_PREP(S2500_REG_MMS_MASK,
+ OA_TC6_PHY_C45_VS_MMS12) |
+ S2500_REG_VS_PTP_SEC;
+ ret = oa_tc6_read_registers(priv->tc6, addr, &data[0], 2);
+ ptp_read_system_postts(ptp_sts);
+
+ if (!ret) {
+ ts->tv_sec = data[0];
+ ts->tv_nsec = data[1];
+ }
+
+ return ret;
+}
+
+static int s2500_ptp_write_time(struct s2500_info *priv,
+ const struct timespec64 *ts)
+{
+ u32 addr;
+ u32 data[2];
+
+ lockdep_assert_held(&priv->ptp_adj_lock);
+
+ if (ts->tv_sec >= (1ULL << 32))
+ return -ERANGE;
+
+ data[0] = (u32)ts->tv_sec;
+ /* bit 31 = execute set command */
+ data[1] = ts->tv_nsec | BIT(31);
+ addr = FIELD_PREP(S2500_REG_MMS_MASK,
+ OA_TC6_PHY_C45_VS_MMS12) |
+ S2500_REG_VS_PTP_SETSEC;
+
+ return oa_tc6_write_registers(priv->tc6, addr, &data[0], 2);
+}
+
+static int s2500_ptp_set_time64(struct ptp_clock_info *ptp,
+ const struct timespec64 *ts)
+{
+ struct s2500_info *priv = container_of(ptp, struct s2500_info,
+ ptp_clock_info);
+ int ret;
+
+ mutex_lock(&priv->ptp_adj_lock);
+ ret = s2500_ptp_write_time(priv, ts);
+ mutex_unlock(&priv->ptp_adj_lock);
+
+ return ret;
+}
+
+static int s2500_ptp_set_freq(struct s2500_info *priv, long scaled_ppm)
+{
+ u32 sign_bit = 0;
+ long adj;
+ u32 val;
+ u64 ppm;
+
+ if (scaled_ppm < 0) {
+ /* split sign / mod */
+ sign_bit = 1U << 31;
+ scaled_ppm = ~scaled_ppm + 1;
+ }
+
+ /*
+ * Convert unsigned scaled_ppm to atto-seconds per clock cycles.
+ * The scaled_ppm format is Qx.16 --> 1 lsb = 1/65536 ppm.
+ * The clock period of the S2500 is 8ns (125 MHz), so 1 lsb of
+ * adj register LSB is 1 atto-sec / 8ns = 0.000125 ppm.
+ * Represented in Qx.16 format, this is 0.000125 * 2^16 = 8(.192)
+ * To convert scaled_ppm into a register value we need to divide
+ * it by the LSB value, hence adj = (scaled_ppm * 1000) / 8192 to
+ * minimize the precision loss due to the integer arithmetic.
+ * That further reduces to (scaled_ppm * 125) / 1024.
+ */
+ ppm = (u64)scaled_ppm * 125;
+ do_div(ppm, 1024);
+ adj = (long)ppm;
+
+ /* check overflow */
+ if (adj > S2500_PTP_ADJ_MAX)
+ return -ERANGE;
+
+ val = (u32)adj | sign_bit;
+ return oa_tc6_write_register_mms(priv->tc6, OA_TC6_PHY_C45_VS_MMS12,
+ S2500_REG_VS_PTP_ADJ, val);
+}
+
+static int s2500_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
+{
+ struct s2500_info *priv = container_of(ptp, struct s2500_info,
+ ptp_clock_info);
+
+ return s2500_ptp_set_freq(priv, scaled_ppm);
+}
+
+static int s2500_ptp_step_time(struct s2500_info *priv, s64 delta)
+{
+ struct timespec64 target, now, delta_ts;
+ struct ptp_system_timestamp sts;
+ int ret;
+
+ memset(&sts, 0, sizeof(sts));
+ ret = s2500_ptp_get_time64(&priv->ptp_clock_info, &now, &sts);
+ if (ret)
+ return ret;
+ if (delta >= 0) {
+ delta_ts = ns_to_timespec64(delta);
+ target = timespec64_add(now, delta_ts);
+ } else {
+ delta_ts = ns_to_timespec64(-delta);
+ target = timespec64_sub(now, delta_ts);
+ }
+ /* The subtraction above can take the target below the epoch */
+ if (target.tv_sec < 0)
+ return -ERANGE;
+ return s2500_ptp_write_time(priv, &target);
+}
+
+static int s2500_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
+{
+ struct s2500_info *priv = container_of(ptp, struct s2500_info,
+ ptp_clock_info);
+ int ret;
+
+ /* Nothing to do */
+ if (delta == 0)
+ return 0;
+
+ /* The device has no add-delta register, so the offset is applied as
+ * a read-modify-write of the time registers.
+ */
+ mutex_lock(&priv->ptp_adj_lock);
+ ret = s2500_ptp_step_time(priv, delta);
+ mutex_unlock(&priv->ptp_adj_lock);
+
+ return ret;
+}
+
+int s2500_ptp_register(struct s2500_info *priv)
+{
+ struct ptp_clock_info *info = &priv->ptp_clock_info;
+ int ret;
+
+ info->max_adj = S2500_PTP_MAX_ADJ_PPB;
+ info->owner = THIS_MODULE;
+ info->adjfine = s2500_ptp_adjfine;
+ info->gettimex64 = s2500_ptp_get_time64;
+ info->settime64 = s2500_ptp_set_time64;
+ info->adjtime = s2500_ptp_adjtime;
+
+ ret = oa_tc6_ptp_register(priv->tc6, info);
+ if (ret)
+ dev_err(&priv->spi->dev, "PTP registration failed\n");
+ return ret;
+}
+
diff --git a/include/linux/oa_tc6.h b/include/linux/oa_tc6.h
index 88e7d5491b20..86075ee113fe 100644
--- a/include/linux/oa_tc6.h
+++ b/include/linux/oa_tc6.h
@@ -75,6 +75,7 @@
#define OA_TC6_PHY_C45_VS_PLCA_MMS4 4 /* MMD 31 */
#define OA_TC6_PHY_C45_AUTO_NEG_MMS5 5 /* MMD 7 */
#define OA_TC6_PHY_C45_POWER_UNIT_MMS6 6 /* MMD 13 */
+#define OA_TC6_PHY_C45_VS_MMS12 12 /* for vendors */
struct oa_tc6;
--
2.43.0
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH net-next v8 11/11] onsemi: s2500: Added selftest support to onsemi's S2500 driver
2026-09-28 22:25 [PATCH net-next v8 00/11] Support for onsemi's S2500 10Base-T1S MAC-PHY Selvamani Rajagopal via B4 Relay
` (9 preceding siblings ...)
2026-09-28 22:25 ` [PATCH net-next v8 10/11] onsemi: s2500: Add driver support for S2500 MAC-PHY Selvamani Rajagopal via B4 Relay
@ 2026-09-28 22:25 ` Selvamani Rajagopal via B4 Relay
10 siblings, 0 replies; 24+ messages in thread
From: Selvamani Rajagopal via B4 Relay @ 2026-09-28 22:25 UTC (permalink / raw)
To: Selva Rajagopal, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Piergiorgio Beruto, Parthiban Veerasooran,
Simon Horman, Jonathan Corbet, Shuah Khan, Randy Dunlap,
Richard Cochran, Andrew Lunn, Heiner Kallweit, Russell King
Cc: Selva Rajagopal, netdev, devicetree, linux-kernel, linux-doc, Jerry Ray
From: Selvamani Rajagopal <Selvamani.Rajagopal@onsemi.com>
Adds selftest support for onsemi S2500 MAC-PHY. Added as a separate
patch for the ease of review.
Signed-off-by: Selvamani Rajagopal <Selvamani.Rajagopal@onsemi.com>
---
changes in v8
- No change
changes in v7
- No change
changes in v6
- Moved the signed off information to the correct place.
changes in v5
- No change
changes in v4:
- Added a selftest as a separate patch
- First patch
---
drivers/net/ethernet/onsemi/s2500/s2500_ethtool.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/net/ethernet/onsemi/s2500/s2500_ethtool.c b/drivers/net/ethernet/onsemi/s2500/s2500_ethtool.c
index 65bbcc1c7dc8..08e748d4b10c 100644
--- a/drivers/net/ethernet/onsemi/s2500/s2500_ethtool.c
+++ b/drivers/net/ethernet/onsemi/s2500/s2500_ethtool.c
@@ -5,6 +5,7 @@
*/
#include <linux/ethtool.h>
+#include <net/selftests.h>
#include <linux/phy.h>
#include "s2500_hw_def.h"
@@ -193,6 +194,8 @@ static int s2500_get_sset_count(struct net_device *ndev, int sset)
switch (sset) {
case ETH_SS_STATS:
return S2500_MAC_STATS_LEN;
+ case ETH_SS_TEST:
+ return net_selftest_get_count();
default:
return -EOPNOTSUPP;
}
@@ -206,6 +209,9 @@ static void s2500_get_strings(struct net_device *ndev, u32 stringset,
memcpy(buf, s2500_mac_stat_strings,
S2500_MAC_STATS_LEN * ETH_GSTRING_LEN);
break;
+ case ETH_SS_TEST:
+ net_selftest_get_strings(buf);
+ break;
}
}
--
2.43.0
^ permalink raw reply [flat|nested] 24+ messages in thread
* RE: [PATCH net-next v8 01/11] dt-bindings: net: add onsemi's S2500
2026-09-28 22:25 ` [PATCH net-next v8 01/11] dt-bindings: net: add onsemi's S2500 Selvamani Rajagopal via B4 Relay
@ 2026-09-28 22:46 ` Selvamani Rajagopal
0 siblings, 0 replies; 24+ messages in thread
From: Selvamani Rajagopal @ 2026-09-28 22:46 UTC (permalink / raw)
To: Selvamani Rajagopal, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Piergiorgio Beruto, Parthiban Veerasooran,
Simon Horman, Jonathan Corbet, Shuah Khan, Randy Dunlap,
Richard Cochran, Andrew Lunn, Heiner Kallweit, Russell King
Cc: netdev, devicetree, linux-kernel, linux-doc, Jerry Ray,
Krzysztof Kozlowski
Krzysztof,
Not sure what I did is right. I didn't remove the "Reviewed by" tag though there was a change in the YAML file
Because it was a minor change. Previously it had edge triggered interrupt type. Now it is changed level triggered.
If I have to remove it, let me know. I can do it and generate new version.
Sincerely
Selva
> -----Original Message-----
> From: Selvamani Rajagopal via B4 Relay
> Subject: [PATCH net-next v8 01/11] dt-bindings: net: add onsemi's S2500
>
>
> Add device tree binding for the onsemi S2500 IEEE 802.3cg
> compliant Ethernet transceiver device.
>
> S2500 has both Media Access Controller (MAC) and 10Base-T1S
> Ethernet PHY. MAC implements 10 Mbps half duplex Ethernet
> MAC. Communication between the host and MAC-PHY is defined in
> OPEN Alliance 10BASE-T1x MACPHY Serial Interface document
>
> Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
> Signed-off-by: Selvamani Rajagopal <Selvamani.Rajagopal@onsemi.com>
>
> ---
> changes in v8
> - Changed the interrupt type to level triggered
> - Added reset-gpio entry that was recently supported.
> changes in v7
> - Added the missing review tag
> diff --git a/Documentation/devicetree/bindings/net/onnn,s2500.yaml
> b/Documentation/devicetree/bindings/net/onnn,s2500.yaml
^ permalink raw reply [flat|nested] 24+ messages in thread
* RE: [PATCH net-next v8 07/11] net: phy: ncn26000: Support for onsemi's S2500 internal phy
2026-09-28 22:25 ` [PATCH net-next v8 07/11] net: phy: ncn26000: Support for onsemi's S2500 internal phy Selvamani Rajagopal via B4 Relay
@ 2026-09-28 22:50 ` Selvamani Rajagopal
2026-09-29 11:54 ` Andrew Lunn
0 siblings, 1 reply; 24+ messages in thread
From: Selvamani Rajagopal @ 2026-09-28 22:50 UTC (permalink / raw)
To: Selvamani Rajagopal, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Piergiorgio Beruto, Parthiban Veerasooran,
Simon Horman, Jonathan Corbet, Shuah Khan, Randy Dunlap,
Richard Cochran, Andrew Lunn, Heiner Kallweit, Russell King
Cc: netdev, devicetree, linux-kernel, linux-doc, Jerry Ray
Andrew,
Thinking that I don't need to remove "Reviewed by" tag for minor changes, I kept it.
.read_mmd, and write_mmd callback was changed to use newer callsbacks
recently introduced in the in the kernel.
Let me know if you want me to remove "Reviewed by: tag for this change.
Sincerely
Selva
> -----Original Message-----
> From: Selvamani Rajagopal via B4 Relay
> <devnull+Selvamani.Rajagopal.onsemi.com@kernel.org>
> Subject: [PATCH net-next v8 07/11] net: phy: ncn26000: Support for onsemi's S2500
> internal phy
>
>
> Adding support for internal PHY of the integrated
> media access controller S2500. PLCA tx opportunity timer's
> default value is correct in this device, compared to
> the currently supported PHY NCN26000.
>
> Reviewed-by: Andrew Lunn <andrew@lunn.ch>
> Signed-off-by: Selvamani Rajagopal <Selvamani.Rajagopal@onsemi.com>
>
> ---
> changes in v8
> - changes to use newer API for read/write_mmd callback
> changes in v7
> - No change
> changes in v6
> + .read_mmd = genphy_read_mmd_c45,
> + .write_mmd = genphy_write_mmd_c45,
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH net-next v8 07/11] net: phy: ncn26000: Support for onsemi's S2500 internal phy
2026-09-28 22:50 ` Selvamani Rajagopal
@ 2026-09-29 11:54 ` Andrew Lunn
0 siblings, 0 replies; 24+ messages in thread
From: Andrew Lunn @ 2026-09-29 11:54 UTC (permalink / raw)
To: Selvamani Rajagopal
Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Piergiorgio Beruto, Parthiban Veerasooran, Simon Horman,
Jonathan Corbet, Shuah Khan, Randy Dunlap, Richard Cochran,
Heiner Kallweit, Russell King, netdev, devicetree, linux-kernel,
linux-doc, Jerry Ray
On Mon, Sep 28, 2026 at 10:50:00PM +0000, Selvamani Rajagopal wrote:
> Andrew,
>
> Thinking that I don't need to remove "Reviewed by" tag for minor changes, I kept it.
> .read_mmd, and write_mmd callback was changed to use newer callsbacks
> recently introduced in the in the kernel.
>
> Let me know if you want me to remove "Reviewed by: tag for this change.
Minor changes like this are fine.
Andrew
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH net-next v8 05/11] net: ethernet: oa_tc6: Support for hardware timestamp
2026-09-28 22:25 ` [PATCH net-next v8 05/11] net: ethernet: oa_tc6: Support for hardware timestamp Selvamani Rajagopal via B4 Relay
@ 2026-10-06 1:08 ` Jakub Kicinski
2026-10-06 16:19 ` Selvamani Rajagopal
2026-10-06 12:48 ` Andrew Lunn
1 sibling, 1 reply; 24+ messages in thread
From: Jakub Kicinski @ 2026-10-06 1:08 UTC (permalink / raw)
To: Selvamani Rajagopal via B4 Relay
Cc: Selvamani.Rajagopal, Andrew Lunn, David S. Miller, Eric Dumazet,
Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Piergiorgio Beruto, Parthiban Veerasooran, Simon Horman,
Jonathan Corbet, Shuah Khan, Randy Dunlap, Richard Cochran,
Andrew Lunn, Heiner Kallweit, Russell King, netdev, devicetree,
linux-kernel, linux-doc, Jerry Ray
On Mon, 28 Sep 2026 15:25:12 -0700 Selvamani Rajagopal via B4 Relay
wrote:
> PTP register/unregister calls are implemented in oa_tc6_ptp.c.
> The APIs that work with the hardware for timestamp is provided
> by vendor code as it may be vendor dependent.
drivers/net/ethernet/oa_tc6/oa_tc6.c:1650:7: error: no member named 'vend1_mms' in 'struct oa_tc6'
1650 | tc6->vend1_mms = -EOPNOTSUPP;
| ~~~ ^
--
pw-bot: cr
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH net-next v8 02/11] Documentation: networking: Add timestamp related APIs to OA TC6 framework
2026-09-28 22:25 ` [PATCH net-next v8 02/11] Documentation: networking: Add timestamp related APIs to OA TC6 framework Selvamani Rajagopal via B4 Relay
@ 2026-10-06 12:15 ` Andrew Lunn
0 siblings, 0 replies; 24+ messages in thread
From: Andrew Lunn @ 2026-10-06 12:15 UTC (permalink / raw)
To: Selvamani.Rajagopal
Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Piergiorgio Beruto, Parthiban Veerasooran, Simon Horman,
Jonathan Corbet, Shuah Khan, Randy Dunlap, Richard Cochran,
Heiner Kallweit, Russell King, netdev, devicetree, linux-kernel,
linux-doc, Jerry Ray
On Mon, Sep 28, 2026 at 03:25:09PM -0700, Selvamani Rajagopal via B4 Relay wrote:
> From: Selvamani Rajagopal <Selvamani.Rajagopal@onsemi.com>
>
> Added new APIs to support hardware timestamp feature as defined in
> OPEN Alliance 10BASE-T1x MAC-PHY serial interface specification.
>
> Added the newer read/write APIs that takes MMS as one of its parameters
> as these were not documented so far.
>
> Signed-off-by: Selvamani Rajagopal <Selvamani.Rajagopal@onsemi.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Andrew
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH net-next v8 03/11] net: ethernet: oa_tc6: Move oa_tc6.c to its own directory
2026-09-28 22:25 ` [PATCH net-next v8 03/11] net: ethernet: oa_tc6: Move oa_tc6.c to its own directory Selvamani Rajagopal via B4 Relay
@ 2026-10-06 12:22 ` Andrew Lunn
0 siblings, 0 replies; 24+ messages in thread
From: Andrew Lunn @ 2026-10-06 12:22 UTC (permalink / raw)
To: Selvamani.Rajagopal
Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Piergiorgio Beruto, Parthiban Veerasooran, Simon Horman,
Jonathan Corbet, Shuah Khan, Randy Dunlap, Richard Cochran,
Heiner Kallweit, Russell King, netdev, devicetree, linux-kernel,
linux-doc, Jerry Ray
On Mon, Sep 28, 2026 at 03:25:10PM -0700, Selvamani Rajagopal via B4 Relay wrote:
> From: Selvamani Rajagopal <Selvamani.Rajagopal@onsemi.com>
>
> Moving oa_tc6.c to its own directory, drivers/net/ethernet/oa_tc6. This
> will facilitate adding more files to support other features
> defined by OPEN Alliance 10BASE-T1x Serial Interface specification
>
> This patch series is adding two files, one for hardware
> timestamp related functions and one for PTP related APIs.
>
> Signed-off-by: Selvamani Rajagopal <Selvamani.Rajagopal@onsemi.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Andrew
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH net-next v8 04/11] net: ethernet: oa_tc6: Move constant definitions to header file
2026-09-28 22:25 ` [PATCH net-next v8 04/11] net: ethernet: oa_tc6: Move constant definitions to header file Selvamani Rajagopal via B4 Relay
@ 2026-10-06 12:24 ` Andrew Lunn
0 siblings, 0 replies; 24+ messages in thread
From: Andrew Lunn @ 2026-10-06 12:24 UTC (permalink / raw)
To: Selvamani.Rajagopal
Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Piergiorgio Beruto, Parthiban Veerasooran, Simon Horman,
Jonathan Corbet, Shuah Khan, Randy Dunlap, Richard Cochran,
Heiner Kallweit, Russell King, netdev, devicetree, linux-kernel,
linux-doc, Jerry Ray
On Mon, Sep 28, 2026 at 03:25:11PM -0700, Selvamani Rajagopal via B4 Relay wrote:
> From: Selvamani Rajagopal <Selvamani.Rajagopal@onsemi.com>
>
> To help other source files within the module share the
> constant definitions, some of the definitions from oa_tc6.c
> are moved to a header file. This header file is still
> private to OA TC6 framework.
>
> oa_tc6 structure is also moved to this header file as it is
> needed for other source files that are part of OA TC6
> framework.
>
> Signed-off-by: Selvamani Rajagopal <Selvamani.Rajagopal@onsemi.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Andrew
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH net-next v8 05/11] net: ethernet: oa_tc6: Support for hardware timestamp
2026-09-28 22:25 ` [PATCH net-next v8 05/11] net: ethernet: oa_tc6: Support for hardware timestamp Selvamani Rajagopal via B4 Relay
2026-10-06 1:08 ` Jakub Kicinski
@ 2026-10-06 12:48 ` Andrew Lunn
1 sibling, 0 replies; 24+ messages in thread
From: Andrew Lunn @ 2026-10-06 12:48 UTC (permalink / raw)
To: Selvamani.Rajagopal
Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Piergiorgio Beruto, Parthiban Veerasooran, Simon Horman,
Jonathan Corbet, Shuah Khan, Randy Dunlap, Richard Cochran,
Heiner Kallweit, Russell King, netdev, devicetree, linux-kernel,
linux-doc, Jerry Ray
> +static bool oa_tc6_req_tx_hwtstamp(struct oa_tc6 *tc6, struct sk_buff *skb)
> +{
> + bool drop = false;
> + u8 tsc;
> + u8 i;
> +
> + lockdep_assert_held(&tc6->tx_skb_lock);
> +
> + if (!skb || !(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP))
> + return drop;
> +
> + if (!tc6->hw_tstamp_enabled)
> + goto out;
> + if (tc6->ts_config.tx_type != HWTSTAMP_TX_ON) {
> + tc6->tx_hwtstamp_lost++;
> + goto out;
> + }
> +
> + tsc = tc6->ttsc_current_id;
> + for (i = 0; i < OA_TC6_TTSCC_REG_ID; i++) {
> + if (!(tc6->ts_ttsc_pending & BIT(tsc -
> + OA_TC6_TTSCA_REG_ID)))
> + goto slot_found;
The indentation is a bit off. Generally the whole of BIT(...) would be
on the next line.
> + tsc = oa_tc6_next_tsc(tsc);
> + }
> +
> + /* All the three slots are waiting for its event. This skb
> + * can't request timestamp. Marking it to be dropped.
> + */
> + tc6->tx_hwtstamp_lost++;
> + drop = true;
> + goto out;
> +
> +slot_found:
> + tc6->ts_ttsc_pending |= BIT(tsc - OA_TC6_TTSCA_REG_ID);
> + tc6->ttsc_current_id = oa_tc6_next_tsc(tsc);
> + oa_tc6_tsinfo_tx(skb)->tsc = tsc;
> + skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
> +out:
> + return drop;
The goto's here are a bit spaghetti code like. Since all out: does is
return, maybe just use "return true" above.
> static int oa_tc6_process_extended_status(struct oa_tc6 *tc6)
> {
> + u32 regs[OA_TC6_STATUS0_TTSC_REG_COUNT];
> + bool ts_valid = !!tc6->ptp_clock;
> u32 value;
> int ret;
>
> - ret = oa_tc6_read_register(tc6, OA_TC6_REG_STATUS0, &value);
> + /* When timestamp is disabled, there is no behavior change
> + * as it reads only STATUS0 register. When enabled,
> + * TTSCA_HIGH..TTSCC_LOW are fetched together with STATUS0
> + * to avoid having to make second SPI transaction. Reading few
> + * extra registers, even it may not be needed every time this
> + * function is called, it is more efficient than making second
> + * SPI transaction, when needed.
> + */
> + ret = oa_tc6_read_registers(tc6, OA_TC6_REG_STATUS0, regs,
> + ts_valid ?
> + OA_TC6_STATUS0_TTSC_REG_COUNT : 1);
> if (ret) {
> netdev_err(tc6->netdev, "STATUS0 register read failed: %d\n",
> ret);
> return ret;
> }
> + value = regs[0];
I assume there is a #define for register 0? It would be more readable
to use the name.
> +int oa_tc6_ptp_register(struct oa_tc6 *tc6, struct ptp_clock_info *info)
> +{
> + int ret = 0;
> +
> + /* Not supporting hardware timestamp isn't an error */
> + if (!tc6->hw_tstamp_supported)
> + return ret;
> +
> + snprintf(info->name, sizeof(info->name), "%s",
> + "OA TC6 PTP clock");
Are names meant to be unique? Have you tested this on a board with
multiple devices?
> + tc6->ptp_clock = ptp_clock_register(info, &tc6->spi->dev);
> + if (IS_ERR(tc6->ptp_clock)) {
> + ret = PTR_ERR(tc6->ptp_clock);
> + tc6->ptp_clock = NULL;
> + dev_err(&tc6->spi->dev, "Registration of %s failed\n",
> + info->name);
> + }
> +
> + if (tc6->ptp_clock)
> + dev_info(&tc6->spi->dev, "%s registered. index %d\n",
> + info->name, ptp_clock_index(tc6->ptp_clock));
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(oa_tc6_ptp_register);
> +
> +/**
> + * oa_tc6_ptp_unregister - Unregisters clock related callbacks
> + * @tc6: oa_tc6 struct.
> + */
> +void oa_tc6_ptp_unregister(struct oa_tc6 *tc6)
> +{
> + if (tc6->ptp_clock) {
> + ptp_clock_unregister(tc6->ptp_clock);
> + tc6->ptp_clock = NULL;
> + }
> +}
> +EXPORT_SYMBOL_GPL(oa_tc6_ptp_unregister);
> diff --git a/drivers/net/ethernet/oa_tc6/oa_tc6_std_def.h b/drivers/net/ethernet/oa_tc6/oa_tc6_std_def.h
> index 403a9c22b5f1..06fe88f1ed7c 100644
> --- a/drivers/net/ethernet/oa_tc6/oa_tc6_std_def.h
> +++ b/drivers/net/ethernet/oa_tc6/oa_tc6_std_def.h
> @@ -18,6 +18,9 @@
> #include <linux/wait.h>
> #include <linux/phy.h>
>
> +/* Tx timestamp capture register A (high) */
> +#define OA_TC6_REG_TTSCA_HIGH (0x10)
> +
> /* Control command header */
> #define OA_TC6_CTRL_HEADER_DATA_NOT_CTRL BIT(31)
> #define OA_TC6_CTRL_HEADER_WRITE_NOT_READ BIT(29)
> @@ -33,6 +36,7 @@
> #define OA_TC6_DATA_HEADER_START_WORD_OFFSET GENMASK(19, 16)
> #define OA_TC6_DATA_HEADER_END_VALID BIT(14)
> #define OA_TC6_DATA_HEADER_END_BYTE_OFFSET GENMASK(13, 8)
> +#define OA_TC6_DATA_HEADER_TSC_OFFSET GENMASK(7, 6)
> #define OA_TC6_DATA_HEADER_PARITY BIT(0)
>
> /* Data footer */
> @@ -44,6 +48,8 @@
> #define OA_TC6_DATA_FOOTER_START_VALID BIT(20)
> #define OA_TC6_DATA_FOOTER_START_WORD_OFFSET GENMASK(19, 16)
> #define OA_TC6_DATA_FOOTER_END_VALID BIT(14)
> +#define OA_TC6_DATA_FOOTER_RTSA_VALID BIT(7)
> +#define OA_TC6_DATA_FOOTER_RTSP_VALID BIT(6)
> #define OA_TC6_DATA_FOOTER_END_BYTE_OFFSET GENMASK(13, 8)
> #define OA_TC6_DATA_FOOTER_TX_CREDITS GENMASK(5, 1)
>
> @@ -70,6 +76,22 @@
>
> #define OA_TC6_REG_MMS_MASK GENMASK(19, 16)
>
> +#define OA_TC6_TSTAMP_SZ 8
> +
> +#define OA_TC6_TTSCA_REG_ID 1
> +#define OA_TC6_TTSCB_REG_ID 2
> +#define OA_TC6_TTSCC_REG_ID 3
> +
> +/* STATUS0 and the TTSCA/B/C capture registers are contiguous in MMS 0, so
> + * they are fetched with a single control transaction while timestamping is
> + * available.
> + */
> +#define OA_TC6_TTSC_REG_OFFSET (OA_TC6_REG_TTSCA_HIGH - \
> + OA_TC6_REG_STATUS0)
> +#define OA_TC6_TTSC_REG_COUNT (2 * OA_TC6_TTSCC_REG_ID)
> +#define OA_TC6_STATUS0_TTSC_REG_COUNT (OA_TC6_TTSC_REG_OFFSET + \
> + OA_TC6_TTSC_REG_COUNT)
> +
> /* Internal structure for MAC-PHY drivers */
> struct oa_tc6 {
> struct net_device *netdev;
> @@ -95,6 +117,16 @@ struct oa_tc6 {
> bool prot_ctrl;
> enum oa_tc6_quirk_flag quirk_flags;
> struct gpio_desc *reset_gpio;
> + struct hwtstamp_config ts_config;
> + struct list_head tx_ts_skb_q;
> + struct ptp_clock *ptp_clock;
> + bool hw_tstamp_supported;
> + bool hw_tstamp_enabled;
> + u64 tx_hwtstamp_pkts;
> + u64 tx_hwtstamp_lost;
> + u64 tx_hwtstamp_err;
> + u8 ts_ttsc_pending;
> + u8 ttsc_current_id;
> };
>
> enum oa_tc6_header_type {
> @@ -121,5 +153,8 @@ enum oa_tc6_data_end_valid_info {
> OA_TC6_DATA_END_INVALID,
> OA_TC6_DATA_END_VALID,
> };
> +
> +void oa_tc6_cleanup_tx_tstamp_skbs(struct oa_tc6 *tc6);
> +
> #endif /* OA_TC6_STD_DEF_H */
>
> diff --git a/drivers/net/ethernet/oa_tc6/oa_tc6_tstamp.c b/drivers/net/ethernet/oa_tc6/oa_tc6_tstamp.c
> new file mode 100644
> index 000000000000..d83f6ad9373a
> --- /dev/null
> +++ b/drivers/net/ethernet/oa_tc6/oa_tc6_tstamp.c
> @@ -0,0 +1,224 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * OPEN Alliance 10BASE‑T1x MAC‑PHY Serial Interface framework
> + *
> + * Author: Selva Rajagopal <selvamani.rajagopal@onsemi.com>
> + */
> +
> +#include <linux/bitfield.h>
> +#include <linux/iopoll.h>
> +#include <linux/mdio.h>
> +#include <linux/phy.h>
> +#include <linux/oa_tc6.h>
> +
> +#include "oa_tc6_std_def.h"
> +
> +static int oa_tc6_set_hwtstamp_settings(struct oa_tc6 *tc6,
> + const struct hwtstamp_config *ts_cfg)
> +{
> + u32 regs[OA_TC6_REG_INT_MASK0 - OA_TC6_REG_CONFIG0 + 1];
> + u32 cfg0, irqm, status0;
> + bool disabled;
> + int ret;
> +
> + if (tc6->ts_config.flags == ts_cfg->flags &&
> + tc6->ts_config.tx_type == ts_cfg->tx_type &&
> + tc6->ts_config.rx_filter == ts_cfg->rx_filter)
> + return 0;
> +
> + spin_lock_bh(&tc6->tx_skb_lock);
> + disabled = tc6->disable_traffic;
> + spin_unlock_bh(&tc6->tx_skb_lock);
> + if (disabled)
> + return -EIO;
> +
> + /* CONFIG0, STATUS0 and INT_MASK0 span one register block, so a
> + * single control transaction covers all three.
> + */
> + ret = oa_tc6_read_registers(tc6, OA_TC6_REG_CONFIG0, regs,
> + ARRAY_SIZE(regs));
> + if (ret) {
> + dev_err(&tc6->spi->dev, "Failed to read CFG0 block\n");
> + goto out;
> + }
> +
> + cfg0 = regs[0];
OA_TC6_REG_CONFIG0 - OA_TC6_REG_CONFIG0?
> + status0 = regs[OA_TC6_REG_STATUS0 - OA_TC6_REG_CONFIG0];
> + irqm = regs[OA_TC6_REG_INT_MASK0 - OA_TC6_REG_CONFIG0];
It then follow the pattern?
Andrew
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH net-next v8 09/11] net: phy: ncn26000: Support for loopback
2026-09-28 22:25 ` [PATCH net-next v8 09/11] net: phy: ncn26000: Support for loopback Selvamani Rajagopal via B4 Relay
@ 2026-10-06 13:05 ` Andrew Lunn
2026-10-06 13:06 ` Andrew Lunn
1 sibling, 0 replies; 24+ messages in thread
From: Andrew Lunn @ 2026-10-06 13:05 UTC (permalink / raw)
To: Selvamani.Rajagopal
Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Piergiorgio Beruto, Parthiban Veerasooran, Simon Horman,
Jonathan Corbet, Shuah Khan, Randy Dunlap, Richard Cochran,
Heiner Kallweit, Russell King, netdev, devicetree, linux-kernel,
linux-doc, Jerry Ray
> +/**
> + * genphy_loopback_fixed_speed - Helper to modify the PHY loopback mode
> + * without affecting any other settings.
> + * @phydev: The phy_device struct
> + * @enable: Flag to enable or disable the PHY level loopback.
> + * @speed: Speed setting. Not expected to be set. Error if it is set.
Naming is hard, and i'm not too sure about this one.
fixed_speed could actually mean, fix the PHY to use the given speed.
It is in fact doing the opposite, the speed is not fixed at all, it is
left to whatever the device supports. In this case, it just supports a
single speed, but that is unusual for PHYs.
Maybe call it genphy_loopback_no_speed()?
This helper is also not what most devices actually want to use, since
it only works if the device does not support autoneg. The "without
affecting any other settings" is not the best way to describe why you
would want to use this, not genphy_loopback. Please expand the
documentation a bit to make it clearer why you would want to use this
and not genphy_loopback.
Andrew
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH net-next v8 09/11] net: phy: ncn26000: Support for loopback
2026-09-28 22:25 ` [PATCH net-next v8 09/11] net: phy: ncn26000: Support for loopback Selvamani Rajagopal via B4 Relay
2026-10-06 13:05 ` Andrew Lunn
@ 2026-10-06 13:06 ` Andrew Lunn
1 sibling, 0 replies; 24+ messages in thread
From: Andrew Lunn @ 2026-10-06 13:06 UTC (permalink / raw)
To: Selvamani.Rajagopal
Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Piergiorgio Beruto, Parthiban Veerasooran, Simon Horman,
Jonathan Corbet, Shuah Khan, Randy Dunlap, Richard Cochran,
Heiner Kallweit, Russell King, netdev, devicetree, linux-kernel,
linux-doc, Jerry Ray
> @@ -2775,6 +2775,26 @@ int genphy_write_mmd_unsupported(struct phy_device *phdev, int devnum,
> }
> EXPORT_SYMBOL(genphy_write_mmd_unsupported);
>
> +/**
> + * genphy_loopback_fixed_speed - Helper to modify the PHY loopback mode
> + * without affecting any other settings.
> + * @phydev: The phy_device struct
> + * @enable: Flag to enable or disable the PHY level loopback.
> + * @speed: Speed setting. Not expected to be set. Error if it is set.
> + *
> + * Returns: 0 if successful, negative error code on failure.
> + */
> +int genphy_loopback_fixed_speed(struct phy_device *phydev, bool enable,
> + int speed)
> +{
> + if (enable && speed)
> + return -EOPNOTSUPP;
> +
> + return phy_modify(phydev, MII_BMCR, BMCR_LOOPBACK,
> + enable ? BMCR_LOOPBACK : 0);
> +}
> +EXPORT_SYMBOL(genphy_loopback_fixed_speed);
Please could you place it next to genphy_loopback()
> +
> int genphy_suspend(struct phy_device *phydev)
> {
> return phy_set_bits(phydev, MII_BMCR, BMCR_PDOWN);
> diff --git a/include/linux/phy.h b/include/linux/phy.h
> index 7c5098a0dd6c..c1b9bc305c82 100644
> --- a/include/linux/phy.h
> +++ b/include/linux/phy.h
> @@ -2327,6 +2327,8 @@ int genphy_read_mmd_unsupported(struct phy_device *phdev, int devad,
> u16 regnum);
> int genphy_write_mmd_unsupported(struct phy_device *phdev, int devnum,
> u16 regnum, u16 val);
> +int genphy_loopback_fixed_speed(struct phy_device *phydev, bool enable,
> + int speed);
and this next to genphy_loopback().
Andrew
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH net-next v8 10/11] onsemi: s2500: Add driver support for S2500 MAC-PHY
2026-09-28 22:25 ` [PATCH net-next v8 10/11] onsemi: s2500: Add driver support for S2500 MAC-PHY Selvamani Rajagopal via B4 Relay
@ 2026-10-06 13:54 ` Andrew Lunn
0 siblings, 0 replies; 24+ messages in thread
From: Andrew Lunn @ 2026-10-06 13:54 UTC (permalink / raw)
To: Selvamani.Rajagopal
Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Piergiorgio Beruto, Parthiban Veerasooran, Simon Horman,
Jonathan Corbet, Shuah Khan, Randy Dunlap, Richard Cochran,
Heiner Kallweit, Russell King, netdev, devicetree, linux-kernel,
linux-doc, Jerry Ray
> +static void s2500_update_stats(struct s2500_info *priv)
> +{
> + /* TX bytes is a 64-bit value that is stored in two regs */
> + *(data++) += ((u64)*rptr) | (((u64)*(rptr + 1)) << 32);
> + /* RX bytes is a 64-bit value that is stored in two regs */
> + *(data++) += ((u64)*rptr) | (((u64)*(rptr + 1)) << 32);
Is it guaranteed by the hardware these two words are read atomically?
> +static int s2500_ptp_write_time(struct s2500_info *priv,
> + const struct timespec64 *ts)
> +{
> + u32 addr;
> + u32 data[2];
Reverse christmas tree.
Andrew
^ permalink raw reply [flat|nested] 24+ messages in thread
* RE: [PATCH net-next v8 05/11] net: ethernet: oa_tc6: Support for hardware timestamp
2026-10-06 1:08 ` Jakub Kicinski
@ 2026-10-06 16:19 ` Selvamani Rajagopal
0 siblings, 0 replies; 24+ messages in thread
From: Selvamani Rajagopal @ 2026-10-06 16:19 UTC (permalink / raw)
To: Jakub Kicinski, Selvamani Rajagopal via B4 Relay
Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Paolo Abeni,
Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Piergiorgio Beruto, Parthiban Veerasooran, Simon Horman,
Jonathan Corbet, Shuah Khan, Randy Dunlap, Richard Cochran,
Andrew Lunn, Heiner Kallweit, Russell King, netdev, devicetree,
linux-kernel, linux-doc, Jerry Ray
> -----Original Message-----
> From: Jakub Kicinski <kuba@kernel.org>
> Sent: Monday, October 5, 2026 6:09 PM
> Subject: Re: [PATCH net-next v8 05/11] net: ethernet: oa_tc6: Support for hardware
> timestamp
>
>
> drivers/net/ethernet/oa_tc6/oa_tc6.c:1650:7: error: no member named 'vend1_mms' in
> 'struct oa_tc6'
> 1650 | tc6->vend1_mms = -EOPNOTSUPP;
Thanks for your review. Sorry. This line should have been part of 6/11 patch. Will move it.
> | ~~~ ^
> --
> pw-bot: cr
^ permalink raw reply [flat|nested] 24+ messages in thread
end of thread, other threads:[~2026-10-06 16:19 UTC | newest]
Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-28 22:25 [PATCH net-next v8 00/11] Support for onsemi's S2500 10Base-T1S MAC-PHY Selvamani Rajagopal via B4 Relay
2026-09-28 22:25 ` [PATCH net-next v8 01/11] dt-bindings: net: add onsemi's S2500 Selvamani Rajagopal via B4 Relay
2026-09-28 22:46 ` Selvamani Rajagopal
2026-09-28 22:25 ` [PATCH net-next v8 02/11] Documentation: networking: Add timestamp related APIs to OA TC6 framework Selvamani Rajagopal via B4 Relay
2026-10-06 12:15 ` Andrew Lunn
2026-09-28 22:25 ` [PATCH net-next v8 03/11] net: ethernet: oa_tc6: Move oa_tc6.c to its own directory Selvamani Rajagopal via B4 Relay
2026-10-06 12:22 ` Andrew Lunn
2026-09-28 22:25 ` [PATCH net-next v8 04/11] net: ethernet: oa_tc6: Move constant definitions to header file Selvamani Rajagopal via B4 Relay
2026-10-06 12:24 ` Andrew Lunn
2026-09-28 22:25 ` [PATCH net-next v8 05/11] net: ethernet: oa_tc6: Support for hardware timestamp Selvamani Rajagopal via B4 Relay
2026-10-06 1:08 ` Jakub Kicinski
2026-10-06 16:19 ` Selvamani Rajagopal
2026-10-06 12:48 ` Andrew Lunn
2026-09-28 22:25 ` [PATCH net-next v8 06/11] net: ethernet: oa_tc6: Support for vendor specific MMS Selvamani Rajagopal via B4 Relay
2026-09-28 22:25 ` [PATCH net-next v8 07/11] net: phy: ncn26000: Support for onsemi's S2500 internal phy Selvamani Rajagopal via B4 Relay
2026-09-28 22:50 ` Selvamani Rajagopal
2026-09-29 11:54 ` Andrew Lunn
2026-09-28 22:25 ` [PATCH net-next v8 08/11] net: phy: ncn26000: Enable enhanced noise immunity Selvamani Rajagopal via B4 Relay
2026-09-28 22:25 ` [PATCH net-next v8 09/11] net: phy: ncn26000: Support for loopback Selvamani Rajagopal via B4 Relay
2026-10-06 13:05 ` Andrew Lunn
2026-10-06 13:06 ` Andrew Lunn
2026-09-28 22:25 ` [PATCH net-next v8 10/11] onsemi: s2500: Add driver support for S2500 MAC-PHY Selvamani Rajagopal via B4 Relay
2026-10-06 13:54 ` Andrew Lunn
2026-09-28 22:25 ` [PATCH net-next v8 11/11] onsemi: s2500: Added selftest support to onsemi's S2500 driver Selvamani Rajagopal via B4 Relay
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®