Netdev List
 help / color / mirror / Atom feed
* [PATCH v4 0/5] net: lan743x: Add SFP support for PCI11x1x
@ 2026-05-14 10:50 Thangaraj Samynathan
  2026-05-14 10:50 ` [PATCH v4 1/5] net: lan743x: rename is_sgmii_en to is_pcs_en Thangaraj Samynathan
                   ` (4 more replies)
  0 siblings, 5 replies; 11+ messages in thread
From: Thangaraj Samynathan @ 2026-05-14 10:50 UTC (permalink / raw)
  To: netdev
  Cc: andrew+netdev, davem, edumazet, kuba, pabeni, bryan.whitehead,
	UNGLinuxDriver, linux, linux-kernel

This series adds SFP module support for the Microchip PCI11x1x Ethernet
controller family by integrating with the kernel's phylink/SFP subsystem.

The PCI11x1x device contains an embedded PCIe switch with downstream
ports for the Ethernet controller and a multi-function peripheral endpoint
(GPIO, I2C, UART, SPI controllers). SFP support relies on this peripheral
endpoint: the GPIO controller provides the SFP control/status signals and
the I2C controller provides access to the SFP module EEPROM. SFP capability
is hardware-strapped and detected at probe time.

Patch 1 renames the misleading is_sgmii_en flag to is_pcs_en to better
reflect that it tracks PCS interface enablement rather than a specific
SGMII mode. No functional change.

Patch 2 reads the SFP enable straps (STRAP_SFP_USE_EN_ and STRAP_SFP_EN_)
from the PCI11x1x strap registers and stores the result in a new
is_sfp_support_en flag. A validation check ensures PCS is also enabled
whenever SFP support is requested, since SFP operation requires the PCS
interface.

Patch 3 registers software nodes to describe the SFP hardware topology to
the kernel: the GPIO device (for TX-fault, TX-disable, LOS, mod-def0, and
rate-select0 signals), the I2C adapter (for SFP EEPROM access), the SFP
cage node, and a phylink node configured for in-band-status mode. The
driver navigates the PCI topology at probe time to locate the paired
peripheral controller functions. A new CONFIG_LAN743X_SFP Kconfig symbol
guards the feature and selects the required I2C, GPIO, SFP, and PCS_XPCS
dependencies.

Patch 4 registers an SFP platform device backed by the SFP software node
when SFP support is enabled, and associates the I2C adapter's firmware node
so the SFP subsystem can manage module detection and EEPROM reads.

Patch 5 adds a dedicated PCS MDIO bus and an XPCS instance for SFP link
management. C45 read/write callbacks are wired to the existing internal
SGMII access functions. The mac_select_pcs phylink callback returns the
XPCS instance when present. SGMII and 2.5GBASE-X interface modes are
enabled in phylink to support the range of SFP modules. The phylink
connect path is also updated to skip the fallback PHY scan when SFP
support is active.

Based on original work by Raju Lakkaraju:
https://lwn.net/ml/all/20240911161054.4494-1-Raju.Lakkaraju%40microchip.com/

Change Log:
===========
v3 -> v4:
  - Use device_find_child() + i2c_verify_adapter() to locate the I2C
    adapter and dev_is_auxiliary() + name match to locate the GPIO aux
    device; removes dependency on peripheral driver struct layouts
    [patch 3/5, 4/5]
  - Use pci_walk_bus() for PCI peripheral device traversal [patch 4/5]
  - Fix memory leak on error paths in lan743x_swnodes_register()
    [patch 3/5]
  - Fix missing NULL terminator in property_entry arrays [patch 3/5]
  - Use DL_FLAG_AUTOREMOVE_CONSUMER for device links to peripheral
    devices [patch 4/5]
  - Set phy_mask = ~0 on PCS MDIO bus to prevent unintended PHY scan
    [patch 5/5]
  - Style fixes [patch 3/5]

v2 -> v3:
  - Add patch 1/5 to rename is_sgmii_en -> is_pcs_en as a prerequisite
    cleanup before the SFP series [patch 1/5]
  - Update error message to reference strap names:
    "SFP_EN strap specified without SGMII_EN strap" [patch 2/5]
  - Use str_enable_disable() helper for debug logging instead of open-coded
    ternary [patch 2/5]
  - Add is_sfp_support_en initialisation to false in probe [patch 2/5]
  - Move <linux/i2c.h>, <linux/gpio/machine.h>, <linux/auxiliary_bus.h>
    includes, PCI1XXXX_*/PCI11X1X_* macros, NODE_PROP macro and helper
    structs from lan743x_main.c to lan743x_main.h [patch 3/5]
  - Add lan743x_swnodes_unregister() helper with kfree inside the if block
    [patch 3/5]
  - Move software node registration out of lan743x_hardware_init() into
    lan743x_phylink_create() with proper error unwind, so it is not called
    on PM resume path [patch 3/5]
  - Move software node unregistration from lan743x_full_cleanup() into
    lan743x_destroy_phylink() to be symmetric with registration and handle
    probe failure path correctly [patch 3/5]
  - Use kzalloc_obj() instead of kzalloc() for sw_nodes allocation
    [patch 3/5]
  - Fix typo: "SPIcontrollers" -> "SPI controllers" in comment [patch 3/5]
  - Add cleanup_sfp: label in probe error path; null sfp_dev and i2c_adap
    pointers after unregister in lan743x_full_cleanup() [patch 4/5]
  - Move <linux/platform_device.h> to lan743x_main.h where
    struct platform_device *sfp_dev is declared [patch 4/5]
  - Fix probe failure path: goto cleanup_hardware -> goto cleanup_phylink
    on lan743x_sfp_register() failure [patch 4/5]
  - Consolidate phylink PCS and 2500Base-X support into a single patch
    [patch 5/5]
  - Switch from struct dw_xpcs * to struct phylink_pcs * internally; use
    xpcs_create_pcs_mdiodev() instead of xpcs_create_mdiodev() +
    xpcs_to_phylink_pcs(), and xpcs_destroy_pcs() instead of
    xpcs_destroy() [patch 5/5]
  - Use devm_mdiobus_alloc() instead of mdiobus_alloc() for pcs_mdiobus
    [patch 5/5]
  - Move <linux/phylink.h> and <linux/pcs/pcs-xpcs.h> from
    lan743x_main.c to lan743x_main.h [patch 5/5]

v1 -> v2:
  - Split the patches to 'PHYLINK' and 'SFP' parts
  - Change variable name from 'chip_rev' to 'fpga_rev'
  - SFP GPIO definitions and other macros move from lan743x_main.c to
    lan743x_main.h file
  - Change from 'PCI11X1X_' to 'PCI11X1X_EVB_PCI11010_' strings for
    GPIO macros
  - Add platform_device_unregister() when sfp register fail
  - Add two new patches to this patch series

Thangaraj Samynathan (5):
  net: lan743x: rename is_sgmii_en to is_pcs_en
  net: lan743x: read SFP straps from PCI11x1x device
  net: lan743x: Add support to software-nodes for SFP
  net: lan743x: Register SFP platform device for PCI11x1x
  net: lan743x: Add PCS/XPCS support for SFP on PCI11x1x

 drivers/net/ethernet/microchip/Kconfig        |  15 +
 .../net/ethernet/microchip/lan743x_ethtool.c  |   4 +-
 drivers/net/ethernet/microchip/lan743x_main.c | 450 +++++++++++++++++-
 drivers/net/ethernet/microchip/lan743x_main.h |  69 ++-
 4 files changed, 520 insertions(+), 18 deletions(-)

-- 
2.34.1


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

* [PATCH v4 1/5] net: lan743x: rename is_sgmii_en to is_pcs_en
  2026-05-14 10:50 [PATCH v4 0/5] net: lan743x: Add SFP support for PCI11x1x Thangaraj Samynathan
@ 2026-05-14 10:50 ` Thangaraj Samynathan
  2026-05-14 12:38   ` Andrew Lunn
  2026-05-14 10:50 ` [PATCH v4 2/5] net: lan743x: read SFP straps from PCI11x1x device Thangaraj Samynathan
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 11+ messages in thread
From: Thangaraj Samynathan @ 2026-05-14 10:50 UTC (permalink / raw)
  To: netdev
  Cc: andrew+netdev, davem, edumazet, kuba, pabeni, bryan.whitehead,
	UNGLinuxDriver, linux, linux-kernel

The flag is_sgmii_en indicates whether the PCS interface is enabled.
However, the name implies that the interface is strictly SGMII, which is
misleading.

Rename the variable to is_pcs_en to better reflect that the flag
represents the PCS enable state rather than a specific interface mode.
Update all references and logs accordingly (but keep device registers
unchanged to match its documentation).

No functional change intended.

Signed-off-by: Thangaraj Samynathan <thangaraj.s@microchip.com>
---
 .../net/ethernet/microchip/lan743x_ethtool.c   |  4 ++--
 drivers/net/ethernet/microchip/lan743x_main.c  | 18 +++++++++---------
 drivers/net/ethernet/microchip/lan743x_main.h  |  2 +-
 3 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/drivers/net/ethernet/microchip/lan743x_ethtool.c b/drivers/net/ethernet/microchip/lan743x_ethtool.c
index 9195419ecee0..743acfd56554 100644
--- a/drivers/net/ethernet/microchip/lan743x_ethtool.c
+++ b/drivers/net/ethernet/microchip/lan743x_ethtool.c
@@ -1312,7 +1312,7 @@ static int lan743x_get_regs_len(struct net_device *dev)
 	struct lan743x_adapter *adapter = netdev_priv(dev);
 	u32 num_regs = MAX_LAN743X_ETH_COMMON_REGS;
 
-	if (adapter->is_sgmii_en)
+	if (adapter->is_pcs_en)
 		num_regs += MAX_LAN743X_ETH_SGMII_REGS;
 
 	return num_regs * sizeof(u32);
@@ -1333,7 +1333,7 @@ static void lan743x_get_regs(struct net_device *dev,
 	lan743x_common_regs(dev, p);
 	p = (u32 *)p + MAX_LAN743X_ETH_COMMON_REGS;
 
-	if (adapter->is_sgmii_en) {
+	if (adapter->is_pcs_en) {
 		lan743x_sgmii_regs(dev, p);
 		p = (u32 *)p + MAX_LAN743X_ETH_SGMII_REGS;
 	}
diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/ethernet/microchip/lan743x_main.c
index f3332417162e..fad4a246e06e 100644
--- a/drivers/net/ethernet/microchip/lan743x_main.c
+++ b/drivers/net/ethernet/microchip/lan743x_main.c
@@ -59,22 +59,22 @@ static void pci11x1x_strap_get_status(struct lan743x_adapter *adapter)
 	      hw_cfg & HW_CFG_RST_PROTECT_)) ||
 	    (strap & STRAP_READ_USE_SGMII_EN_)) {
 		if (strap & STRAP_READ_SGMII_EN_)
-			adapter->is_sgmii_en = true;
+			adapter->is_pcs_en = true;
 		else
-			adapter->is_sgmii_en = false;
+			adapter->is_pcs_en = false;
 	} else {
 		fpga_rev = lan743x_csr_read(adapter, FPGA_REV);
 		if (fpga_rev) {
 			if (fpga_rev & FPGA_SGMII_OP)
-				adapter->is_sgmii_en = true;
+				adapter->is_pcs_en = true;
 			else
-				adapter->is_sgmii_en = false;
+				adapter->is_pcs_en = false;
 		} else {
-			adapter->is_sgmii_en = false;
+			adapter->is_pcs_en = false;
 		}
 	}
 	netif_dbg(adapter, drv, adapter->netdev,
-		  "SGMII I/F %sable\n", adapter->is_sgmii_en ? "En" : "Dis");
+		  "PCS I/F %s\n", str_enable_disable(adapter->is_pcs_en));
 }
 
 static bool is_pci11x1x_chip(struct lan743x_adapter *adapter)
@@ -1361,7 +1361,7 @@ static void lan743x_phy_interface_select(struct lan743x_adapter *adapter)
 	data = lan743x_csr_read(adapter, MAC_CR);
 	id_rev = adapter->csr.id_rev & ID_REV_ID_MASK_;
 
-	if (adapter->is_pci11x1x && adapter->is_sgmii_en)
+	if (adapter->is_pci11x1x && adapter->is_pcs_en)
 		adapter->phy_interface = PHY_INTERFACE_MODE_SGMII;
 	else if (id_rev == ID_REV_ID_LAN7430_)
 		adapter->phy_interface = PHY_INTERFACE_MODE_GMII;
@@ -3515,7 +3515,7 @@ static int lan743x_hardware_init(struct lan743x_adapter *adapter,
 		mutex_init(&adapter->sgmii_rw_lock);
 		pci11x1x_set_rfe_rd_fifo_threshold(adapter);
 		sgmii_ctl = lan743x_csr_read(adapter, SGMII_CTL);
-		if (adapter->is_sgmii_en) {
+		if (adapter->is_pcs_en) {
 			sgmii_ctl |= SGMII_CTL_SGMII_ENABLE_;
 			sgmii_ctl &= ~SGMII_CTL_SGMII_POWER_DN_;
 		} else {
@@ -3580,7 +3580,7 @@ static int lan743x_mdiobus_init(struct lan743x_adapter *adapter)
 
 	adapter->mdiobus->priv = (void *)adapter;
 	if (adapter->is_pci11x1x) {
-		if (adapter->is_sgmii_en) {
+		if (adapter->is_pcs_en) {
 			netif_dbg(adapter, drv, adapter->netdev,
 				  "SGMII operation\n");
 			adapter->mdiobus->read = lan743x_mdiobus_read_c22;
diff --git a/drivers/net/ethernet/microchip/lan743x_main.h b/drivers/net/ethernet/microchip/lan743x_main.h
index 160d94a7cee6..f0fa0580b04e 100644
--- a/drivers/net/ethernet/microchip/lan743x_main.h
+++ b/drivers/net/ethernet/microchip/lan743x_main.h
@@ -1070,7 +1070,7 @@ struct lan743x_adapter {
 	struct lan743x_tx       tx[PCI11X1X_USED_TX_CHANNELS];
 	struct lan743x_rx       rx[LAN743X_USED_RX_CHANNELS];
 	bool			is_pci11x1x;
-	bool			is_sgmii_en;
+	bool			is_pcs_en;
 	/* protect ethernet syslock */
 	spinlock_t		eth_syslock_spinlock;
 	bool			eth_syslock_en;
-- 
2.34.1


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

* [PATCH v4 2/5] net: lan743x: read SFP straps from PCI11x1x device
  2026-05-14 10:50 [PATCH v4 0/5] net: lan743x: Add SFP support for PCI11x1x Thangaraj Samynathan
  2026-05-14 10:50 ` [PATCH v4 1/5] net: lan743x: rename is_sgmii_en to is_pcs_en Thangaraj Samynathan
@ 2026-05-14 10:50 ` Thangaraj Samynathan
  2026-05-14 12:47   ` Andrew Lunn
  2026-05-14 10:50 ` [PATCH v4 3/5] net: lan743x: Add support to software-nodes for SFP Thangaraj Samynathan
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 11+ messages in thread
From: Thangaraj Samynathan @ 2026-05-14 10:50 UTC (permalink / raw)
  To: netdev
  Cc: andrew+netdev, davem, edumazet, kuba, pabeni, bryan.whitehead,
	UNGLinuxDriver, linux, linux-kernel

Reads the SFP enable bits from the strap registers to determine
if the hardware is configured for SFP usage.

Introduce CONFIG_LAN743X_SFP to guard SFP-specific code and select
the required peripheral dependencies (I2C_PCI1XXXX, GP_PCI1XXXX, SFP,
PCS_XPCS) only when SFP hardware is present. HWMON is also selected to
support thermal monitoring of SFP modules via the sfp subsystem.

- Add STRAP_SFP_USE_EN_ and STRAP_SFP_EN_ definitions to read SFP
  straps.
- Store SFP status in the adapter's is_sfp_support_en flag.
- Add a validation check when SFP support is requested without SGMII_EN
  strap; log the invalid combination and force is_sfp_support_en to false
  so subsequent SFP/PCS paths are safely skipped.
- Add debug logging for is_sfp_support_en using str_enable_disable()
  helper, consistent with the existing PCS debug log.

Signed-off-by: Thangaraj Samynathan <thangaraj.s@microchip.com>
---
 drivers/net/ethernet/microchip/Kconfig        | 15 ++++++++++++
 drivers/net/ethernet/microchip/lan743x_main.c | 23 +++++++++++++++++++
 drivers/net/ethernet/microchip/lan743x_main.h |  3 +++
 3 files changed, 41 insertions(+)

diff --git a/drivers/net/ethernet/microchip/Kconfig b/drivers/net/ethernet/microchip/Kconfig
index ee046468652c..0cc55d00ab52 100644
--- a/drivers/net/ethernet/microchip/Kconfig
+++ b/drivers/net/ethernet/microchip/Kconfig
@@ -57,6 +57,21 @@ config LAN743X
 	  To compile this driver as a module, choose M here. The module will be
 	  called lan743x.
 
+config LAN743X_SFP
+	bool "SFP support for PCI11x1x"
+	depends on LAN743X
+	select HWMON if LAN743X=y
+	select I2C_PCI1XXXX
+	select GP_PCI1XXXX
+	select SFP
+	select PCS_XPCS
+	help
+	  Enable SFP module support for the Microchip PCI11x1x Ethernet
+	  controller. Requires the GPIO and I2C peripheral controllers on
+	  the PCI11x1x device to be present and probed.
+
+	  If unsure, say N.
+
 source "drivers/net/ethernet/microchip/lan865x/Kconfig"
 source "drivers/net/ethernet/microchip/lan966x/Kconfig"
 source "drivers/net/ethernet/microchip/sparx5/Kconfig"
diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/ethernet/microchip/lan743x_main.c
index fad4a246e06e..77a554a0432c 100644
--- a/drivers/net/ethernet/microchip/lan743x_main.c
+++ b/drivers/net/ethernet/microchip/lan743x_main.c
@@ -62,6 +62,14 @@ static void pci11x1x_strap_get_status(struct lan743x_adapter *adapter)
 			adapter->is_pcs_en = true;
 		else
 			adapter->is_pcs_en = false;
+
+#ifdef CONFIG_LAN743X_SFP
+		if ((strap & STRAP_SFP_USE_EN_) && (strap & STRAP_SFP_EN_))
+			adapter->is_sfp_support_en = true;
+		else
+			adapter->is_sfp_support_en = false;
+#endif
+
 	} else {
 		fpga_rev = lan743x_csr_read(adapter, FPGA_REV);
 		if (fpga_rev) {
@@ -73,8 +81,22 @@ static void pci11x1x_strap_get_status(struct lan743x_adapter *adapter)
 			adapter->is_pcs_en = false;
 		}
 	}
+
+#ifdef CONFIG_LAN743X_SFP
+	if (adapter->is_pci11x1x && !adapter->is_pcs_en &&
+	    adapter->is_sfp_support_en) {
+		netif_err(adapter, drv, adapter->netdev,
+			  "Invalid EEPROM configuration: SFP_EN strap specified without SGMII_EN strap\n");
+		adapter->is_sfp_support_en = false;
+	}
+#endif
+
 	netif_dbg(adapter, drv, adapter->netdev,
 		  "PCS I/F %s\n", str_enable_disable(adapter->is_pcs_en));
+#ifdef CONFIG_LAN743X_SFP
+	netif_dbg(adapter, drv, adapter->netdev,
+		  "SFP support %s\n", str_enable_disable(adapter->is_sfp_support_en));
+#endif
 }
 
 static bool is_pci11x1x_chip(struct lan743x_adapter *adapter)
@@ -3665,6 +3687,7 @@ static int lan743x_pcidev_probe(struct pci_dev *pdev,
 			      NETIF_MSG_LINK | NETIF_MSG_IFUP |
 			      NETIF_MSG_IFDOWN | NETIF_MSG_TX_QUEUED;
 	netdev->max_mtu = LAN743X_MAX_FRAME_SIZE;
+	adapter->is_sfp_support_en = false;
 
 	of_get_mac_address(pdev->dev.of_node, adapter->mac_address);
 
diff --git a/drivers/net/ethernet/microchip/lan743x_main.h b/drivers/net/ethernet/microchip/lan743x_main.h
index f0fa0580b04e..d9eb10ffac6c 100644
--- a/drivers/net/ethernet/microchip/lan743x_main.h
+++ b/drivers/net/ethernet/microchip/lan743x_main.h
@@ -37,6 +37,8 @@
 
 #define STRAP_READ			(0x0C)
 #define STRAP_READ_USE_SGMII_EN_	BIT(22)
+#define STRAP_SFP_USE_EN_		BIT(31)
+#define STRAP_SFP_EN_			BIT(15)
 #define STRAP_READ_SGMII_EN_		BIT(6)
 #define STRAP_READ_SGMII_REFCLK_	BIT(5)
 #define STRAP_READ_SGMII_2_5G_		BIT(4)
@@ -1081,6 +1083,7 @@ struct lan743x_adapter {
 	u8			max_tx_channels;
 	u8			used_tx_channels;
 	u8			max_vector_count;
+	bool			is_sfp_support_en;
 
 #define LAN743X_ADAPTER_FLAG_OTP		BIT(0)
 	u32			flags;
-- 
2.34.1


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

* [PATCH v4 3/5] net: lan743x: Add support to software-nodes for SFP
  2026-05-14 10:50 [PATCH v4 0/5] net: lan743x: Add SFP support for PCI11x1x Thangaraj Samynathan
  2026-05-14 10:50 ` [PATCH v4 1/5] net: lan743x: rename is_sgmii_en to is_pcs_en Thangaraj Samynathan
  2026-05-14 10:50 ` [PATCH v4 2/5] net: lan743x: read SFP straps from PCI11x1x device Thangaraj Samynathan
@ 2026-05-14 10:50 ` Thangaraj Samynathan
  2026-05-14 12:57   ` Andrew Lunn
  2026-05-14 10:50 ` [PATCH v4 4/5] net: lan743x: Register SFP platform device for PCI11x1x Thangaraj Samynathan
  2026-05-14 10:50 ` [PATCH v4 5/5] net: lan743x: Add PCS/XPCS support for SFP on PCI11x1x Thangaraj Samynathan
  4 siblings, 1 reply; 11+ messages in thread
From: Thangaraj Samynathan @ 2026-05-14 10:50 UTC (permalink / raw)
  To: netdev
  Cc: andrew+netdev, davem, edumazet, kuba, pabeni, bryan.whitehead,
	UNGLinuxDriver, linux, linux-kernel

Register software nodes to describe the SFP hardware topology: the GPIO
device (for TX-fault, TX-disable, LOS, mod-def0, and rate-select0
signals), the I2C adapter (for SFP EEPROM access), the SFP cage node,
and a phylink node configured for in-band-status mode.

Property entry arrays are sized with a trailing zero-initialised entry
as required by swnode.c iteration. Error paths in
lan743x_swnodes_register() free the nodes allocation via a common
return_error label to avoid memory leaks.

Signed-off-by: Thangaraj Samynathan <thangaraj.s@microchip.com>
---
 drivers/net/ethernet/microchip/lan743x_main.c | 261 +++++++++++++++++-
 drivers/net/ethernet/microchip/lan743x_main.h |  58 ++++
 2 files changed, 317 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/ethernet/microchip/lan743x_main.c
index 77a554a0432c..b7bdf361705e 100644
--- a/drivers/net/ethernet/microchip/lan743x_main.c
+++ b/drivers/net/ethernet/microchip/lan743x_main.c
@@ -16,6 +16,7 @@
 #include <linux/iopoll.h>
 #include <linux/crc16.h>
 #include <linux/phylink.h>
+
 #include "lan743x_main.h"
 #include "lan743x_ethtool.h"
 
@@ -119,6 +120,139 @@ static void lan743x_pci_cleanup(struct lan743x_adapter *adapter)
 	pci_disable_device(adapter->pdev);
 }
 
+#ifdef CONFIG_LAN743X_SFP
+/* Walk the PCI11x1x topology to find a peripheral controller function by its
+ * device ID. Returns the matching pci_dev with its reference count incremented
+ * (caller must call pci_dev_put()), or NULL if not found.
+ *
+ * PCI11x1x devices consist of a PCIe switch with downstream ports. One port
+ * carries the embedded ethernet controller handled by this driver; another
+ * carries a multifunction peripheral endpoint (I2C, GPIO, UART, SPI).
+ *
+ * pci_walk_bus() is used to traverse the bus safely, as it holds the
+ * appropriate PCI bus lock during the walk.
+ */
+struct pci1xxxx_perif_ctx {
+	u16 perif_id;
+	struct pci_dev *found;
+};
+
+static int pci1xxxx_perif_match(struct pci_dev *dev, void *data)
+{
+	struct pci1xxxx_perif_ctx *ctx = data;
+
+	if (dev->vendor == PCI1XXXX_VENDOR_ID &&
+	    (dev->device & ~PCI1XXXX_DEV_MASK) == ctx->perif_id) {
+		ctx->found = pci_dev_get(dev);
+		return 1;
+	}
+	return 0;
+}
+
+static struct pci_dev *pci1xxxx_perif_dev_find(struct lan743x_adapter *adapter,
+					       u16 perif_id)
+{
+	struct pci1xxxx_perif_ctx ctx = { .perif_id = perif_id };
+	struct pci_dev *br_dev;
+
+	br_dev = pci_upstream_bridge(adapter->pdev);
+	if (!br_dev) {
+		netif_err(adapter, drv, adapter->netdev,
+			  "upstream bridge not found\n");
+		return NULL;
+	}
+
+	pci_walk_bus(br_dev->bus, pci1xxxx_perif_match, &ctx);
+
+	if (!ctx.found)
+		netif_err(adapter, drv, adapter->netdev,
+			  "pci1xxxx peripheral (0x%X) device not found\n",
+			  perif_id);
+	return ctx.found;
+}
+
+static int pci1xxxx_i2c_dev_match(struct device *dev, const void *data)
+{
+	return i2c_verify_adapter(dev);
+}
+
+static int pci1xxxx_i2c_adapter_get(struct lan743x_adapter *adapter)
+{
+	struct pci_dev *perif_dev;
+	struct device *adap_dev;
+
+	perif_dev = pci1xxxx_perif_dev_find(adapter, PCI1XXXX_PERIF_I2C_ID);
+	if (!perif_dev)
+		return -EPROBE_DEFER;
+
+	adap_dev = device_find_child(&perif_dev->dev, NULL,
+				     pci1xxxx_i2c_dev_match);
+	if (!adap_dev) {
+		pci_dev_put(perif_dev);
+		return -EPROBE_DEFER;
+	}
+
+	if (!device_link_add(&perif_dev->dev, &adapter->pdev->dev,
+			     DL_FLAG_MANAGED | DL_FLAG_AUTOREMOVE_CONSUMER)) {
+		netif_err(adapter, drv, adapter->netdev,
+			  "failed to link I2C peripheral device\n");
+		put_device(adap_dev);
+		pci_dev_put(perif_dev);
+		return -EINVAL;
+	}
+
+	adapter->i2c_adap = i2c_verify_adapter(adap_dev);
+	strscpy(adapter->nodes->i2c_name, adapter->i2c_adap->name,
+		sizeof(adapter->nodes->i2c_name));
+	netif_dbg(adapter, drv, adapter->netdev, "Found %s\n",
+		  adapter->i2c_adap->name);
+	put_device(adap_dev);
+	pci_dev_put(perif_dev);
+	return 0;
+}
+
+static int pci1xxxx_gpio_aux_dev_match(struct device *dev, const void *data)
+{
+	if (!dev_is_auxiliary(dev))
+		return 0;
+	return strcmp(to_auxiliary_dev(dev)->name, "gp_gpio") == 0;
+}
+
+static int pci1xxxx_gpio_dev_get(struct lan743x_adapter *adapter)
+{
+	struct pci_dev *perif_dev;
+	struct device *gpio_dev;
+
+	perif_dev = pci1xxxx_perif_dev_find(adapter, PCI1XXXX_PERIF_GPIO_ID);
+	if (!perif_dev)
+		return -EPROBE_DEFER;
+
+	gpio_dev = device_find_child(&perif_dev->dev, NULL,
+				     pci1xxxx_gpio_aux_dev_match);
+	if (!gpio_dev) {
+		pci_dev_put(perif_dev);
+		return -EPROBE_DEFER;
+	}
+
+	if (!device_link_add(&perif_dev->dev, &adapter->pdev->dev,
+			     DL_FLAG_MANAGED | DL_FLAG_AUTOREMOVE_CONSUMER)) {
+		netif_err(adapter, drv, adapter->netdev,
+			  "failed to link GPIO peripheral device\n");
+		put_device(gpio_dev);
+		pci_dev_put(perif_dev);
+		return -EINVAL;
+	}
+
+	strscpy(adapter->nodes->gpio_name, dev_name(gpio_dev),
+		sizeof(adapter->nodes->gpio_name));
+	netif_dbg(adapter, drv, adapter->netdev, "Found %s\n",
+		  adapter->nodes->gpio_name);
+	put_device(gpio_dev);
+	pci_dev_put(perif_dev);
+	return 0;
+}
+#endif /* CONFIG_LAN743X_SFP */
+
 static int lan743x_pci_init(struct lan743x_adapter *adapter,
 			    struct pci_dev *pdev)
 {
@@ -2897,6 +3031,107 @@ static int lan743x_rx_open(struct lan743x_rx *rx)
 	return ret;
 }
 
+#ifdef CONFIG_LAN743X_SFP
+static void lan743x_swnodes_unregister(struct lan743x_adapter *adapter)
+{
+	if (adapter->nodes) {
+		software_node_unregister_node_group(adapter->nodes->group);
+		kfree(adapter->nodes);
+		adapter->nodes = NULL;
+	}
+}
+
+static int lan743x_swnodes_register(struct lan743x_adapter *adapter)
+{
+	struct pci_dev *pdev = adapter->pdev;
+	struct lan743x_sw_nodes *nodes;
+	struct software_node *swnodes;
+	int ret;
+	u32 id;
+
+	nodes = kzalloc_obj(*nodes);
+	if (!nodes)
+		return -ENOMEM;
+
+	adapter->nodes = nodes;
+
+	ret = pci1xxxx_gpio_dev_get(adapter);
+	if (ret < 0)
+		goto return_error;
+
+	ret = pci1xxxx_i2c_adapter_get(adapter);
+	if (ret < 0)
+		goto return_error;
+
+	id = (pdev->bus->number << 8) | pdev->devfn;
+	snprintf(nodes->sfp_name, sizeof(nodes->sfp_name), "sfp-%d", id);
+	snprintf(nodes->phylink_name, sizeof(nodes->phylink_name),
+		 "mchp-pci1xxxx-phylink-%d", id);
+
+	swnodes = nodes->swnodes;
+
+	nodes->gpio_props[0] = PROPERTY_ENTRY_STRING("pinctrl-names", "default");
+	swnodes[SWNODE_GPIO] = NODE_PROP(nodes->gpio_name, nodes->gpio_props);
+
+	nodes->tx_fault_ref[0] = SOFTWARE_NODE_REFERENCE(&swnodes[SWNODE_GPIO],
+							 PCI11X1X_TX_FAULT_GPIO,
+							 GPIO_ACTIVE_HIGH);
+	nodes->tx_disable_ref[0] = SOFTWARE_NODE_REFERENCE(&swnodes[SWNODE_GPIO],
+							   PCI11X1X_TX_DIS_GPIO,
+							   GPIO_ACTIVE_HIGH);
+	nodes->mod_def0_ref[0] = SOFTWARE_NODE_REFERENCE(&swnodes[SWNODE_GPIO],
+							 PCI11X1X_MOD_DEF0_GPIO,
+							 GPIO_ACTIVE_LOW);
+	nodes->los_ref[0] = SOFTWARE_NODE_REFERENCE(&swnodes[SWNODE_GPIO],
+						    PCI11X1X_LOS_GPIO,
+						    GPIO_ACTIVE_HIGH);
+	nodes->rate_sel0_ref[0] = SOFTWARE_NODE_REFERENCE(&swnodes[SWNODE_GPIO],
+							  PCI11X1X_RATE_SEL0_GPIO,
+							  GPIO_ACTIVE_HIGH);
+
+	nodes->i2c_props[0] = PROPERTY_ENTRY_STRING("pinctrl-names", "default");
+	swnodes[SWNODE_I2C] = NODE_PROP(nodes->i2c_name, nodes->i2c_props);
+	nodes->i2c_ref[0] = SOFTWARE_NODE_REFERENCE(&swnodes[SWNODE_I2C]);
+
+	nodes->sfp_props[0] = PROPERTY_ENTRY_STRING("compatible", "sff,sfp");
+	nodes->sfp_props[1] = PROPERTY_ENTRY_REF_ARRAY("i2c-bus", nodes->i2c_ref);
+	nodes->sfp_props[2] = PROPERTY_ENTRY_REF_ARRAY("tx-fault-gpios",
+						       nodes->tx_fault_ref);
+	nodes->sfp_props[3] = PROPERTY_ENTRY_REF_ARRAY("tx-disable-gpios",
+						       nodes->tx_disable_ref);
+	nodes->sfp_props[4] = PROPERTY_ENTRY_REF_ARRAY("mod-def0-gpios",
+						       nodes->mod_def0_ref);
+	nodes->sfp_props[5] = PROPERTY_ENTRY_REF_ARRAY("los-gpios",
+						       nodes->los_ref);
+	nodes->sfp_props[6] = PROPERTY_ENTRY_REF_ARRAY("rate-select0-gpios",
+						       nodes->rate_sel0_ref);
+	swnodes[SWNODE_SFP] = NODE_PROP(nodes->sfp_name, nodes->sfp_props);
+	nodes->sfp_ref[0] = SOFTWARE_NODE_REFERENCE(&swnodes[SWNODE_SFP]);
+	nodes->phylink_props[0] = PROPERTY_ENTRY_STRING("managed",
+							"in-band-status");
+	nodes->phylink_props[1] = PROPERTY_ENTRY_REF_ARRAY("sfp",
+							   nodes->sfp_ref);
+	swnodes[SWNODE_PHYLINK] = NODE_PROP(nodes->phylink_name,
+					    nodes->phylink_props);
+
+	nodes->group[SWNODE_GPIO] = &swnodes[SWNODE_GPIO];
+	nodes->group[SWNODE_I2C] = &swnodes[SWNODE_I2C];
+	nodes->group[SWNODE_SFP] = &swnodes[SWNODE_SFP];
+	nodes->group[SWNODE_PHYLINK] = &swnodes[SWNODE_PHYLINK];
+
+	ret = software_node_register_node_group(nodes->group);
+	if (ret)
+		goto return_error;
+
+	return 0;
+
+return_error:
+	kfree(nodes);
+	adapter->nodes = NULL;
+	return ret;
+}
+#endif /* CONFIG_LAN743X_SFP */
+
 static int lan743x_phylink_sgmii_config(struct lan743x_adapter *adapter)
 {
 	u32 sgmii_ctl;
@@ -3141,7 +3376,9 @@ static const struct phylink_mac_ops lan743x_phylink_mac_ops = {
 static int lan743x_phylink_create(struct lan743x_adapter *adapter)
 {
 	struct net_device *netdev = adapter->netdev;
+	struct fwnode_handle *fwnode = NULL;
 	struct phylink *pl;
+	int ret;
 
 	adapter->phylink_config.dev = &netdev->dev;
 	adapter->phylink_config.type = PHYLINK_NETDEV;
@@ -3181,11 +3418,28 @@ static int lan743x_phylink_create(struct lan743x_adapter *adapter)
 	       adapter->phylink_config.supported_interfaces,
 	       sizeof(adapter->phylink_config.lpi_interfaces));
 
-	pl = phylink_create(&adapter->phylink_config, NULL,
-			    adapter->phy_interface, &lan743x_phylink_mac_ops);
+#ifdef CONFIG_LAN743X_SFP
+	if (adapter->is_sfp_support_en) {
+		ret = lan743x_swnodes_register(adapter);
+		if (ret) {
+			netdev_err(netdev, "failed to register software nodes\n");
+			return ret;
+		}
+		fwnode = software_node_fwnode(adapter->nodes->group[SWNODE_PHYLINK]);
+		if (!fwnode) {
+			lan743x_swnodes_unregister(adapter);
+			return -ENODEV;
+		}
+	}
+#endif
 
+	pl = phylink_create(&adapter->phylink_config, fwnode,
+			    adapter->phy_interface, &lan743x_phylink_mac_ops);
 	if (IS_ERR(pl)) {
 		netdev_err(netdev, "Could not create phylink (%pe)\n", pl);
+#ifdef CONFIG_LAN743X_SFP
+		lan743x_swnodes_unregister(adapter);
+#endif
 		return PTR_ERR(pl);
 	}
 
@@ -3492,6 +3746,9 @@ static void lan743x_destroy_phylink(struct lan743x_adapter *adapter)
 {
 	phylink_destroy(adapter->phylink);
 	adapter->phylink = NULL;
+#ifdef CONFIG_LAN743X_SFP
+	lan743x_swnodes_unregister(adapter);
+#endif
 }
 
 static void lan743x_full_cleanup(struct lan743x_adapter *adapter)
diff --git a/drivers/net/ethernet/microchip/lan743x_main.h b/drivers/net/ethernet/microchip/lan743x_main.h
index d9eb10ffac6c..1bff59f43d50 100644
--- a/drivers/net/ethernet/microchip/lan743x_main.h
+++ b/drivers/net/ethernet/microchip/lan743x_main.h
@@ -4,14 +4,36 @@
 #ifndef _LAN743X_H
 #define _LAN743X_H
 
+#include <linux/auxiliary_bus.h>
+#include <dt-bindings/gpio/gpio.h>
+#include <linux/i2c.h>
 #include <linux/phy.h>
 #include <linux/phylink.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
 #include "lan743x_ptp.h"
 
 #define DRIVER_AUTHOR   "Bryan Whitehead <Bryan.Whitehead@microchip.com>"
 #define DRIVER_DESC "LAN743x PCIe Gigabit Ethernet Driver"
 #define DRIVER_NAME "lan743x"
 
+#define PCI1XXXX_VENDOR_ID		0x1055
+#define PCI1XXXX_BR_PERIF_ID		0xA00C
+#define PCI1XXXX_PERIF_I2C_ID		0xA003
+#define PCI1XXXX_PERIF_GPIO_ID		0xA005
+#define PCI1XXXX_DEV_MASK		GENMASK(7, 4)
+#define PCI11X1X_TX_FAULT_GPIO		46
+#define PCI11X1X_TX_DIS_GPIO		47
+#define PCI11X1X_RATE_SEL0_GPIO		48
+#define PCI11X1X_LOS_GPIO		49
+#define PCI11X1X_MOD_DEF0_GPIO		51
+
+#define NODE_PROP(_NAME, _PROP)		\
+	((const struct software_node) {	\
+		.name = _NAME,		\
+		.properties = _PROP,	\
+	 })
+
 /* Register Definitions */
 #define ID_REV				(0x00)
 #define ID_REV_ID_MASK_			(0xFFFF0000)
@@ -1049,6 +1071,40 @@ enum lan743x_sgmii_lsd {
 
 #define MAC_SUPPORTED_WAKES  (WAKE_BCAST | WAKE_UCAST | WAKE_MCAST | \
 			      WAKE_MAGIC | WAKE_ARP)
+
+enum lan743x_swnodes {
+	SWNODE_GPIO = 0,
+	SWNODE_I2C,
+	SWNODE_SFP,
+	SWNODE_PHYLINK,
+	SWNODE_MAX
+};
+
+#define I2C_DRV_NAME           48
+#define GPIO_DRV_NAME          32
+#define SFP_NODE_NAME          32
+#define PHYLINK_NODE_NAME      32
+
+struct lan743x_sw_nodes {
+	char gpio_name[GPIO_DRV_NAME];
+	char i2c_name[I2C_DRV_NAME];
+	char sfp_name[SFP_NODE_NAME];
+	char phylink_name[PHYLINK_NODE_NAME];
+	struct property_entry gpio_props[2];
+	struct property_entry i2c_props[2];
+	struct property_entry sfp_props[8];
+	struct property_entry phylink_props[3];
+	struct software_node_ref_args i2c_ref[1];
+	struct software_node_ref_args tx_fault_ref[1];
+	struct software_node_ref_args tx_disable_ref[1];
+	struct software_node_ref_args mod_def0_ref[1];
+	struct software_node_ref_args los_ref[1];
+	struct software_node_ref_args rate_sel0_ref[1];
+	struct software_node_ref_args sfp_ref[1];
+	struct software_node swnodes[SWNODE_MAX];
+	const struct software_node *group[SWNODE_MAX + 1];
+};
+
 struct lan743x_adapter {
 	struct net_device       *netdev;
 	struct mii_bus		*mdiobus;
@@ -1092,6 +1148,8 @@ struct lan743x_adapter {
 	struct phylink		*phylink;
 	struct phylink_config	phylink_config;
 	int			rx_tstamp_filter;
+	struct lan743x_sw_nodes *nodes;
+	struct i2c_adapter      *i2c_adap;
 };
 
 #define LAN743X_COMPONENT_FLAG_RX(channel)  BIT(20 + (channel))
-- 
2.34.1


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

* [PATCH v4 4/5] net: lan743x: Register SFP platform device for PCI11x1x
  2026-05-14 10:50 [PATCH v4 0/5] net: lan743x: Add SFP support for PCI11x1x Thangaraj Samynathan
                   ` (2 preceding siblings ...)
  2026-05-14 10:50 ` [PATCH v4 3/5] net: lan743x: Add support to software-nodes for SFP Thangaraj Samynathan
@ 2026-05-14 10:50 ` Thangaraj Samynathan
  2026-05-14 10:50 ` [PATCH v4 5/5] net: lan743x: Add PCS/XPCS support for SFP on PCI11x1x Thangaraj Samynathan
  4 siblings, 0 replies; 11+ messages in thread
From: Thangaraj Samynathan @ 2026-05-14 10:50 UTC (permalink / raw)
  To: netdev
  Cc: andrew+netdev, davem, edumazet, kuba, pabeni, bryan.whitehead,
	UNGLinuxDriver, linux, linux-kernel

Register an SFP platform device backed by the SFP software node when
SFP support is enabled, and associate the I2C adapter's firmware node
so the SFP subsystem can manage module detection and EEPROM reads.

Signed-off-by: Thangaraj Samynathan <thangaraj.s@microchip.com>
---
 drivers/net/ethernet/microchip/lan743x_main.c | 64 +++++++++++++++++--
 drivers/net/ethernet/microchip/lan743x_main.h |  1 +
 2 files changed, 60 insertions(+), 5 deletions(-)

diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/ethernet/microchip/lan743x_main.c
index b7bdf361705e..649065c36434 100644
--- a/drivers/net/ethernet/microchip/lan743x_main.c
+++ b/drivers/net/ethernet/microchip/lan743x_main.c
@@ -192,8 +192,8 @@ static int pci1xxxx_i2c_adapter_get(struct lan743x_adapter *adapter)
 		return -EPROBE_DEFER;
 	}
 
-	if (!device_link_add(&perif_dev->dev, &adapter->pdev->dev,
-			     DL_FLAG_MANAGED | DL_FLAG_AUTOREMOVE_CONSUMER)) {
+	if (!device_link_add(&adapter->pdev->dev, &perif_dev->dev,
+			     DL_FLAG_AUTOREMOVE_CONSUMER)) {
 		netif_err(adapter, drv, adapter->netdev,
 			  "failed to link I2C peripheral device\n");
 		put_device(adap_dev);
@@ -234,8 +234,8 @@ static int pci1xxxx_gpio_dev_get(struct lan743x_adapter *adapter)
 		return -EPROBE_DEFER;
 	}
 
-	if (!device_link_add(&perif_dev->dev, &adapter->pdev->dev,
-			     DL_FLAG_MANAGED | DL_FLAG_AUTOREMOVE_CONSUMER)) {
+	if (!device_link_add(&adapter->pdev->dev, &perif_dev->dev,
+			     DL_FLAG_AUTOREMOVE_CONSUMER)) {
 		netif_err(adapter, drv, adapter->netdev,
 			  "failed to link GPIO peripheral device\n");
 		put_device(gpio_dev);
@@ -3132,6 +3132,34 @@ static int lan743x_swnodes_register(struct lan743x_adapter *adapter)
 }
 #endif /* CONFIG_LAN743X_SFP */
 
+#ifdef CONFIG_LAN743X_SFP
+static int lan743x_sfp_register(struct lan743x_adapter *adapter)
+{
+	struct pci_dev *pdev = adapter->pdev;
+	struct platform_device_info sfp_info;
+	struct platform_device *sfp_dev;
+
+	memset(&sfp_info, 0, sizeof(sfp_info));
+	sfp_info.parent = &adapter->pdev->dev;
+	sfp_info.fwnode = software_node_fwnode(adapter->nodes->group[SWNODE_SFP]);
+	sfp_info.name = "sfp";
+	sfp_info.id = (pci_domain_nr(pdev->bus) << 16) |
+		      (pdev->bus->number << 8) | pdev->devfn;
+	sfp_dev = platform_device_register_full(&sfp_info);
+	if (IS_ERR(sfp_dev)) {
+		netif_err(adapter, drv, adapter->netdev,
+			  "Failed to register SFP device\n");
+		return PTR_ERR(sfp_dev);
+	}
+
+	adapter->sfp_dev = sfp_dev;
+	netif_dbg(adapter, drv, adapter->netdev,
+		  "SFP platform device registered\n");
+
+	return 0;
+}
+#endif /* CONFIG_LAN743X_SFP */
+
 static int lan743x_phylink_sgmii_config(struct lan743x_adapter *adapter)
 {
 	u32 sgmii_ctl;
@@ -3754,6 +3782,12 @@ static void lan743x_destroy_phylink(struct lan743x_adapter *adapter)
 static void lan743x_full_cleanup(struct lan743x_adapter *adapter)
 {
 	unregister_netdev(adapter->netdev);
+	if (adapter->sfp_dev) {
+		platform_device_unregister(adapter->sfp_dev);
+		adapter->sfp_dev = NULL;
+	}
+	if (adapter->i2c_adap)
+		adapter->i2c_adap = NULL;
 
 	lan743x_destroy_phylink(adapter);
 	lan743x_mdiobus_cleanup(adapter);
@@ -3981,11 +4015,31 @@ static int lan743x_pcidev_probe(struct pci_dev *pdev,
 		goto cleanup_mdiobus;
 	}
 
+#ifdef CONFIG_LAN743X_SFP
+	if (adapter->is_sfp_support_en) {
+		adapter->i2c_adap->dev.fwnode =
+			software_node_fwnode(adapter->nodes->group[SWNODE_I2C]);
+
+		ret = lan743x_sfp_register(adapter);
+		if (ret < 0) {
+			netif_err(adapter, probe, netdev,
+				  "failed to sfp register (%d)\n", ret);
+			goto cleanup_phylink;
+		}
+	}
+#endif
+
 	ret = register_netdev(adapter->netdev);
 	if (ret < 0)
-		goto cleanup_phylink;
+		goto cleanup_sfp;
 	return 0;
 
+cleanup_sfp:
+	if (adapter->sfp_dev) {
+		platform_device_unregister(adapter->sfp_dev);
+		adapter->sfp_dev = NULL;
+	}
+
 cleanup_phylink:
 	lan743x_destroy_phylink(adapter);
 
diff --git a/drivers/net/ethernet/microchip/lan743x_main.h b/drivers/net/ethernet/microchip/lan743x_main.h
index 1bff59f43d50..a25864bd8328 100644
--- a/drivers/net/ethernet/microchip/lan743x_main.h
+++ b/drivers/net/ethernet/microchip/lan743x_main.h
@@ -1150,6 +1150,7 @@ struct lan743x_adapter {
 	int			rx_tstamp_filter;
 	struct lan743x_sw_nodes *nodes;
 	struct i2c_adapter      *i2c_adap;
+	struct platform_device  *sfp_dev;
 };
 
 #define LAN743X_COMPONENT_FLAG_RX(channel)  BIT(20 + (channel))
-- 
2.34.1


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

* [PATCH v4 5/5] net: lan743x: Add PCS/XPCS support for SFP on PCI11x1x
  2026-05-14 10:50 [PATCH v4 0/5] net: lan743x: Add SFP support for PCI11x1x Thangaraj Samynathan
                   ` (3 preceding siblings ...)
  2026-05-14 10:50 ` [PATCH v4 4/5] net: lan743x: Register SFP platform device for PCI11x1x Thangaraj Samynathan
@ 2026-05-14 10:50 ` Thangaraj Samynathan
  2026-05-14 13:16   ` Andrew Lunn
  4 siblings, 1 reply; 11+ messages in thread
From: Thangaraj Samynathan @ 2026-05-14 10:50 UTC (permalink / raw)
  To: netdev
  Cc: andrew+netdev, davem, edumazet, kuba, pabeni, bryan.whitehead,
	UNGLinuxDriver, linux, linux-kernel

Add a PCS MII bus and XPCS instance to support SFP modules on PCI11x1x
platforms.

Register a dedicated mdiobus for PCS access when SFP support is enabled
and initialize it with C45 read/write callbacks wired to the internal
SGMII access functions. Set phy_mask to ~0 to prevent the MDIO bus scan
from probing internal SGMII registers as PHY addresses.

Integrate the XPCS instance with phylink by providing a mac_select_pcs
callback. Support SGMII and 2.5GBASE-X interfaces in phylink, allowing
proper link configuration for SFP modules.

Cleanup the PCS mdiobus and XPCS instance during driver removal. Update
adapter structure to hold PCS mdiobus and XPCS references.

Signed-off-by: Thangaraj Samynathan <thangaraj.s@microchip.com>
---
 drivers/net/ethernet/microchip/lan743x_main.c | 92 ++++++++++++++++++-
 drivers/net/ethernet/microchip/lan743x_main.h |  5 +
 2 files changed, 94 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/ethernet/microchip/lan743x_main.c
index 649065c36434..72f135fba8e2 100644
--- a/drivers/net/ethernet/microchip/lan743x_main.c
+++ b/drivers/net/ethernet/microchip/lan743x_main.c
@@ -15,7 +15,6 @@
 #include <linux/rtnetlink.h>
 #include <linux/iopoll.h>
 #include <linux/crc16.h>
-#include <linux/phylink.h>
 
 #include "lan743x_main.h"
 #include "lan743x_ethtool.h"
@@ -1192,6 +1191,28 @@ static int lan743x_get_lsd(int speed, int duplex, u8 mss)
 	return lsd;
 }
 
+static int pci11x1x_pcs_read(struct mii_bus *bus, int addr, int devnum,
+			     int regnum)
+{
+	struct lan743x_adapter *adapter = bus->priv;
+
+	if (addr)
+		return -EOPNOTSUPP;
+
+	return lan743x_sgmii_read(adapter, devnum, regnum);
+}
+
+static int pci11x1x_pcs_write(struct mii_bus *bus, int addr, int devnum,
+			      int regnum, u16 val)
+{
+	struct lan743x_adapter *adapter = bus->priv;
+
+	if (addr)
+		return -EOPNOTSUPP;
+
+	return lan743x_sgmii_write(adapter, devnum, regnum, val);
+}
+
 static int lan743x_sgmii_mpll_set(struct lan743x_adapter *adapter,
 				  u16 baud)
 {
@@ -3268,6 +3289,18 @@ static void lan743x_mac_eee_enable(struct lan743x_adapter *adapter, bool enable)
 	lan743x_csr_write(adapter, MAC_CR, mac_cr);
 }
 
+static struct phylink_pcs *lan743x_phylink_mac_select(struct phylink_config *config,
+						      phy_interface_t interface)
+{
+	struct net_device *netdev = to_net_dev(config->dev);
+	struct lan743x_adapter *adapter = netdev_priv(netdev);
+
+	if (adapter->xpcs)
+		return adapter->xpcs;
+
+	return NULL;
+}
+
 static void lan743x_phylink_mac_config(struct phylink_config *config,
 				       unsigned int link_an_mode,
 				       const struct phylink_link_state *state)
@@ -3399,6 +3432,7 @@ static const struct phylink_mac_ops lan743x_phylink_mac_ops = {
 	.mac_link_up = lan743x_phylink_mac_link_up,
 	.mac_disable_tx_lpi = lan743x_mac_disable_tx_lpi,
 	.mac_enable_tx_lpi = lan743x_mac_enable_tx_lpi,
+	.mac_select_pcs = lan743x_phylink_mac_select,
 };
 
 static int lan743x_phylink_create(struct lan743x_adapter *adapter)
@@ -3422,6 +3456,7 @@ static int lan743x_phylink_create(struct lan743x_adapter *adapter)
 
 	switch (adapter->phy_interface) {
 	case PHY_INTERFACE_MODE_SGMII:
+	case PHY_INTERFACE_MODE_2500BASEX:
 		__set_bit(PHY_INTERFACE_MODE_SGMII,
 			  adapter->phylink_config.supported_interfaces);
 		__set_bit(PHY_INTERFACE_MODE_1000BASEX,
@@ -3489,12 +3524,13 @@ static int lan743x_phylink_connect(struct lan743x_adapter *adapter)
 	struct device_node *dn = adapter->pdev->dev.of_node;
 	struct net_device *dev = adapter->netdev;
 	struct phy_device *phydev;
-	int ret;
+	int ret = 0;
 
 	if (dn)
 		ret = phylink_of_phy_connect(adapter->phylink, dn, 0);
 
-	if (!dn || (ret && !lan743x_phy_handle_exists(dn))) {
+	if (!adapter->is_sfp_support_en &&
+	    (!dn || (ret && !lan743x_phy_handle_exists(dn)))) {
 		phydev = phy_find_first(adapter->mdiobus);
 		if (phydev) {
 			/* attach the mac to the phy */
@@ -3767,6 +3803,11 @@ static void lan743x_hardware_cleanup(struct lan743x_adapter *adapter)
 
 static void lan743x_mdiobus_cleanup(struct lan743x_adapter *adapter)
 {
+#ifdef CONFIG_LAN743X_SFP
+	if (adapter->xpcs)
+		xpcs_destroy_pcs(adapter->xpcs);
+#endif
+
 	mdiobus_unregister(adapter->mdiobus);
 }
 
@@ -3881,6 +3922,44 @@ static int lan743x_hardware_init(struct lan743x_adapter *adapter,
 	return 0;
 }
 
+#ifdef CONFIG_LAN743X_SFP
+static int lan743x_pcs_mdiobus_init(struct lan743x_adapter *adapter)
+{
+	struct phylink_pcs *pcs;
+	int ret;
+
+	adapter->pcs_mdiobus = devm_mdiobus_alloc(&adapter->pdev->dev);
+	if (!adapter->pcs_mdiobus)
+		return -ENOMEM;
+
+	adapter->pcs_mdiobus->priv = (void *)adapter;
+	adapter->pcs_mdiobus->read_c45 = pci11x1x_pcs_read;
+	adapter->pcs_mdiobus->write_c45 = pci11x1x_pcs_write;
+	adapter->pcs_mdiobus->name = "lan743x-pcs-mdiobus-c45";
+	adapter->pcs_mdiobus->phy_mask = ~0;
+	netif_dbg(adapter, drv, adapter->netdev, "lan743x-pcs-mdiobus-c45\n");
+	snprintf(adapter->pcs_mdiobus->id, MII_BUS_ID_SIZE, "pci-pcs-%s", pci_name(adapter->pdev));
+
+	if (!adapter->phy_interface)
+		lan743x_phy_interface_select(adapter);
+
+	ret = devm_mdiobus_register(&adapter->pdev->dev, adapter->pcs_mdiobus);
+	if (ret) {
+		netdev_err(adapter->netdev, "failed to register pcs mdiobus\n");
+		return ret;
+	}
+
+	pcs = xpcs_create_pcs_mdiodev(adapter->pcs_mdiobus, 0);
+	if (IS_ERR(pcs)) {
+		netdev_err(adapter->netdev, "failed to create xpcs\n");
+		return PTR_ERR(pcs);
+	}
+
+	adapter->xpcs = pcs;
+	return 0;
+}
+#endif /* CONFIG_LAN743X_SFP */
+
 static int lan743x_mdiobus_init(struct lan743x_adapter *adapter)
 {
 	int ret;
@@ -4002,6 +4081,13 @@ static int lan743x_pcidev_probe(struct pci_dev *pdev,
 	if (ret)
 		goto cleanup_hardware;
 
+#ifdef CONFIG_LAN743X_SFP
+	if (adapter->is_sfp_support_en) {
+		ret = lan743x_pcs_mdiobus_init(adapter);
+		if (ret)
+			goto cleanup_mdiobus;
+	}
+#endif
 	adapter->netdev->netdev_ops = &lan743x_netdev_ops;
 	adapter->netdev->ethtool_ops = &lan743x_ethtool_ops;
 	adapter->netdev->features = NETIF_F_SG | NETIF_F_TSO |
diff --git a/drivers/net/ethernet/microchip/lan743x_main.h b/drivers/net/ethernet/microchip/lan743x_main.h
index a25864bd8328..a16fc69c4466 100644
--- a/drivers/net/ethernet/microchip/lan743x_main.h
+++ b/drivers/net/ethernet/microchip/lan743x_main.h
@@ -8,6 +8,9 @@
 #include <dt-bindings/gpio/gpio.h>
 #include <linux/i2c.h>
 #include <linux/phy.h>
+#ifdef CONFIG_LAN743X_SFP
+#include <linux/pcs/pcs-xpcs.h>
+#endif
 #include <linux/phylink.h>
 #include <linux/platform_device.h>
 #include <linux/property.h>
@@ -1108,6 +1111,7 @@ struct lan743x_sw_nodes {
 struct lan743x_adapter {
 	struct net_device       *netdev;
 	struct mii_bus		*mdiobus;
+	struct mii_bus		*pcs_mdiobus;
 	int                     msg_enable;
 #ifdef CONFIG_PM
 	u32			wolopts;
@@ -1145,6 +1149,7 @@ struct lan743x_adapter {
 	u32			flags;
 	u32			hw_cfg;
 	phy_interface_t		phy_interface;
+	struct phylink_pcs      *xpcs;
 	struct phylink		*phylink;
 	struct phylink_config	phylink_config;
 	int			rx_tstamp_filter;
-- 
2.34.1


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

* Re: [PATCH v4 1/5] net: lan743x: rename is_sgmii_en to is_pcs_en
  2026-05-14 10:50 ` [PATCH v4 1/5] net: lan743x: rename is_sgmii_en to is_pcs_en Thangaraj Samynathan
@ 2026-05-14 12:38   ` Andrew Lunn
  0 siblings, 0 replies; 11+ messages in thread
From: Andrew Lunn @ 2026-05-14 12:38 UTC (permalink / raw)
  To: Thangaraj Samynathan
  Cc: netdev, andrew+netdev, davem, edumazet, kuba, pabeni,
	bryan.whitehead, UNGLinuxDriver, linux, linux-kernel

On Thu, May 14, 2026 at 04:20:24PM +0530, Thangaraj Samynathan wrote:
> The flag is_sgmii_en indicates whether the PCS interface is enabled.
> However, the name implies that the interface is strictly SGMII, which is
> misleading.
> 
> Rename the variable to is_pcs_en to better reflect that the flag
> represents the PCS enable state rather than a specific interface mode.
> Update all references and logs accordingly (but keep device registers
> unchanged to match its documentation).

So the documentation is also broken?

Can you get the documentation fixes, and then replace all references
of SGMII to PCS?

> -	if (adapter->is_pci11x1x && adapter->is_sgmii_en)
> +	if (adapter->is_pci11x1x && adapter->is_pcs_en)
>  		adapter->phy_interface = PHY_INTERFACE_MODE_SGMII;

Maybe this is in a later patch in this series, but i assume
PHY_INTERFACE_MODE_1000BASEX is also a potential mode?

	Andrew

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

* Re: [PATCH v4 2/5] net: lan743x: read SFP straps from PCI11x1x device
  2026-05-14 10:50 ` [PATCH v4 2/5] net: lan743x: read SFP straps from PCI11x1x device Thangaraj Samynathan
@ 2026-05-14 12:47   ` Andrew Lunn
  0 siblings, 0 replies; 11+ messages in thread
From: Andrew Lunn @ 2026-05-14 12:47 UTC (permalink / raw)
  To: Thangaraj Samynathan
  Cc: netdev, andrew+netdev, davem, edumazet, kuba, pabeni,
	bryan.whitehead, UNGLinuxDriver, linux, linux-kernel

On Thu, May 14, 2026 at 04:20:25PM +0530, Thangaraj Samynathan wrote:
> Reads the SFP enable bits from the strap registers to determine
> if the hardware is configured for SFP usage.

What exactly does this strapping mean? Is there a definition in the
documentation?

> Introduce CONFIG_LAN743X_SFP to guard SFP-specific code

Why? Does this add a lot of code? Most MAC drivers don't have such a
Kconfig configuration, so i think this needs some justification.

> +#ifdef CONFIG_LAN743X_SFP
> +	if (adapter->is_pci11x1x && !adapter->is_pcs_en &&
> +	    adapter->is_sfp_support_en) {
> +		netif_err(adapter, drv, adapter->netdev,
> +			  "Invalid EEPROM configuration: SFP_EN strap specified without SGMII_EN strap\n");
> +		adapter->is_sfp_support_en = false;

Shouldn't that be fatal? You have no way to drive the hardware, so is
there any point going further?

What also seems to be missing here is the case where the strapping is
set to indicate SFP, but CONFIG_LAN743X_SFP is not enabled. That
should also be a fatal error.

	Andrew

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

* Re: [PATCH v4 3/5] net: lan743x: Add support to software-nodes for SFP
  2026-05-14 10:50 ` [PATCH v4 3/5] net: lan743x: Add support to software-nodes for SFP Thangaraj Samynathan
@ 2026-05-14 12:57   ` Andrew Lunn
  2026-05-14 13:02     ` Andrew Lunn
  0 siblings, 1 reply; 11+ messages in thread
From: Andrew Lunn @ 2026-05-14 12:57 UTC (permalink / raw)
  To: Thangaraj Samynathan
  Cc: netdev, andrew+netdev, davem, edumazet, kuba, pabeni,
	bryan.whitehead, UNGLinuxDriver, linux, linux-kernel

> +#define PCI11X1X_TX_FAULT_GPIO		46
> +#define PCI11X1X_TX_DIS_GPIO		47
> +#define PCI11X1X_RATE_SEL0_GPIO		48
> +#define PCI11X1X_LOS_GPIO		49
> +#define PCI11X1X_MOD_DEF0_GPIO		51

How do you know these values?

Can i buy this device, design my own board, and decide to use a
different mapping of GPIO pins to SFP cage pins? Or does the data
sheet say you MUST use this mapping?

Maybe consider drivers/misc/lan966x_pci.dtso.

      Andrew

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

* Re: [PATCH v4 3/5] net: lan743x: Add support to software-nodes for SFP
  2026-05-14 12:57   ` Andrew Lunn
@ 2026-05-14 13:02     ` Andrew Lunn
  0 siblings, 0 replies; 11+ messages in thread
From: Andrew Lunn @ 2026-05-14 13:02 UTC (permalink / raw)
  To: Thangaraj Samynathan
  Cc: netdev, andrew+netdev, davem, edumazet, kuba, pabeni,
	bryan.whitehead, UNGLinuxDriver, linux, linux-kernel

On Thu, May 14, 2026 at 02:57:31PM +0200, Andrew Lunn wrote:
> > +#define PCI11X1X_TX_FAULT_GPIO		46
> > +#define PCI11X1X_TX_DIS_GPIO		47
> > +#define PCI11X1X_RATE_SEL0_GPIO		48
> > +#define PCI11X1X_LOS_GPIO		49
> > +#define PCI11X1X_MOD_DEF0_GPIO		51
> 
> How do you know these values?

https://ww1.microchip.com/downloads/aemDocuments/documents/UNG/ApplicationNotes/ApplicationNotes/AN2948-LAN743x-Functional-Description-and-Configuration-Registers-DS00002948.pdf

  The GPIO controller is comprised of 4 (for the LAN7430) or 12 (for
  the LAN7431) programmable input/output pins.

So i could use the LAN7430 and don't connect TX_FAULT. phylink will be
happy with the subset.

	Andrew

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

* Re: [PATCH v4 5/5] net: lan743x: Add PCS/XPCS support for SFP on PCI11x1x
  2026-05-14 10:50 ` [PATCH v4 5/5] net: lan743x: Add PCS/XPCS support for SFP on PCI11x1x Thangaraj Samynathan
@ 2026-05-14 13:16   ` Andrew Lunn
  0 siblings, 0 replies; 11+ messages in thread
From: Andrew Lunn @ 2026-05-14 13:16 UTC (permalink / raw)
  To: Thangaraj Samynathan
  Cc: netdev, andrew+netdev, davem, edumazet, kuba, pabeni,
	bryan.whitehead, UNGLinuxDriver, linux, linux-kernel

> Integrate the XPCS instance with phylink by providing a mac_select_pcs
> callback. Support SGMII and 2.5GBASE-X interfaces in phylink

Not 1000BaseX?

>  
>  	switch (adapter->phy_interface) {
>  	case PHY_INTERFACE_MODE_SGMII:
> +	case PHY_INTERFACE_MODE_2500BASEX:
>  		__set_bit(PHY_INTERFACE_MODE_SGMII,
>  			  adapter->phylink_config.supported_interfaces);
>  		__set_bit(PHY_INTERFACE_MODE_1000BASEX,

So it looks like there is some sort of mixup with SGMII and
1000BaseX. They are different things. Can adapter->phy_interface be
set to PHY_INTERFACE_MODE_1000BASEX? Should there be a case: for it?

It could be the broken documentation, using SGMII to mean PCS, has
resulted in other problems with 1000BaseX not being implemented
correct? You might want to look at all the "SGMII" code and fixup all
the 1000BaseX issues.

	Andrew

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

end of thread, other threads:[~2026-05-14 13:16 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-14 10:50 [PATCH v4 0/5] net: lan743x: Add SFP support for PCI11x1x Thangaraj Samynathan
2026-05-14 10:50 ` [PATCH v4 1/5] net: lan743x: rename is_sgmii_en to is_pcs_en Thangaraj Samynathan
2026-05-14 12:38   ` Andrew Lunn
2026-05-14 10:50 ` [PATCH v4 2/5] net: lan743x: read SFP straps from PCI11x1x device Thangaraj Samynathan
2026-05-14 12:47   ` Andrew Lunn
2026-05-14 10:50 ` [PATCH v4 3/5] net: lan743x: Add support to software-nodes for SFP Thangaraj Samynathan
2026-05-14 12:57   ` Andrew Lunn
2026-05-14 13:02     ` Andrew Lunn
2026-05-14 10:50 ` [PATCH v4 4/5] net: lan743x: Register SFP platform device for PCI11x1x Thangaraj Samynathan
2026-05-14 10:50 ` [PATCH v4 5/5] net: lan743x: Add PCS/XPCS support for SFP on PCI11x1x Thangaraj Samynathan
2026-05-14 13:16   ` Andrew Lunn

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