[net-next PATCH v5 07/10] net: axienet: Convert to use PCS subsystem
From: Sean Anderson <sean.anderson@linux.dev>
Date: 2025-05-23 20:34:46
Also in:
lkml, netdev
Subsystem:
networking drivers, the rest, xilinx axi ethernet driver · Maintainers:
Andrew Lunn, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds, Radhey Shyam Pandey
Convert the AXI Ethernet driver to use the PCS subsystem, including the new Xilinx PCA/PMA driver. Unfortunately, we must use a helper to work with bare MDIO nodes without a compatible. Signed-off-by: Sean Anderson <sean.anderson@linux.dev> Reviewed-by: Suraj Gupta <redacted> Tested-by: Suraj Gupta <redacted> --- Changes in v5: - Use MDIO_BUS instead of MDIO_DEVICE Changes in v4: - Convert to dev-less pcs_put Changes in v3: - Select PCS_XILINX unconditionally drivers/net/ethernet/xilinx/Kconfig | 7 ++ drivers/net/ethernet/xilinx/xilinx_axienet.h | 4 +- .../net/ethernet/xilinx/xilinx_axienet_main.c | 104 ++++-------------- 3 files changed, 28 insertions(+), 87 deletions(-)
diff --git a/drivers/net/ethernet/xilinx/Kconfig b/drivers/net/ethernet/xilinx/Kconfig
index 7502214cc7d5..5381c3915e95 100644
--- a/drivers/net/ethernet/xilinx/Kconfig
+++ b/drivers/net/ethernet/xilinx/Kconfig@@ -25,8 +25,15 @@ config XILINX_EMACLITE config XILINX_AXI_EMAC tristate "Xilinx 10/100/1000 AXI Ethernet support" + depends on COMMON_CLK + depends on GPIOLIB depends on HAS_IOMEM + depends on OF + depends on PCS depends on XILINX_DMA + select MDIO_BUS + select OF_DYNAMIC + select PCS_XILINX select PHYLINK select DIMLIB help
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet.h b/drivers/net/ethernet/xilinx/xilinx_axienet.h
index 5ff742103beb..f46e862245eb 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet.h
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet.h@@ -473,7 +473,6 @@ struct skbuf_dma_descriptor { * @dev: Pointer to device structure * @phylink: Pointer to phylink instance * @phylink_config: phylink configuration settings - * @pcs_phy: Reference to PCS/PMA PHY if used * @pcs: phylink pcs structure for PCS PHY * @switch_x_sgmii: Whether switchable 1000BaseX/SGMII mode is enabled in the core * @axi_clk: AXI4-Lite bus clock
@@ -553,8 +552,7 @@ struct axienet_local { struct phylink *phylink; struct phylink_config phylink_config; - struct mdio_device *pcs_phy; - struct phylink_pcs pcs; + struct phylink_pcs *pcs; bool switch_x_sgmii;
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
index 1b7a653c1f4e..588032ff5b6f 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c@@ -35,6 +35,8 @@ #include <linux/platform_device.h> #include <linux/skbuff.h> #include <linux/math64.h> +#include <linux/pcs.h> +#include <linux/pcs-xilinx.h> #include <linux/phy.h> #include <linux/mii.h> #include <linux/ethtool.h>
@@ -2519,63 +2521,6 @@ static const struct ethtool_ops axienet_ethtool_ops = { .get_rmon_stats = axienet_ethtool_get_rmon_stats, }; -static struct axienet_local *pcs_to_axienet_local(struct phylink_pcs *pcs) -{ - return container_of(pcs, struct axienet_local, pcs); -} - -static void axienet_pcs_get_state(struct phylink_pcs *pcs, - unsigned int neg_mode, - struct phylink_link_state *state) -{ - struct mdio_device *pcs_phy = pcs_to_axienet_local(pcs)->pcs_phy; - - phylink_mii_c22_pcs_get_state(pcs_phy, neg_mode, state); -} - -static void axienet_pcs_an_restart(struct phylink_pcs *pcs) -{ - struct mdio_device *pcs_phy = pcs_to_axienet_local(pcs)->pcs_phy; - - phylink_mii_c22_pcs_an_restart(pcs_phy); -} - -static int axienet_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode, - phy_interface_t interface, - const unsigned long *advertising, - bool permit_pause_to_mac) -{ - struct mdio_device *pcs_phy = pcs_to_axienet_local(pcs)->pcs_phy; - struct net_device *ndev = pcs_to_axienet_local(pcs)->ndev; - struct axienet_local *lp = netdev_priv(ndev); - int ret; - - if (lp->switch_x_sgmii) { - ret = mdiodev_write(pcs_phy, XLNX_MII_STD_SELECT_REG, - interface == PHY_INTERFACE_MODE_SGMII ? - XLNX_MII_STD_SELECT_SGMII : 0); - if (ret < 0) { - netdev_warn(ndev, - "Failed to switch PHY interface: %d\n", - ret); - return ret; - } - } - - ret = phylink_mii_c22_pcs_config(pcs_phy, interface, advertising, - neg_mode); - if (ret < 0) - netdev_warn(ndev, "Failed to configure PCS: %d\n", ret); - - return ret; -} - -static const struct phylink_pcs_ops axienet_pcs_ops = { - .pcs_get_state = axienet_pcs_get_state, - .pcs_config = axienet_pcs_config, - .pcs_an_restart = axienet_pcs_an_restart, -}; - static struct phylink_pcs *axienet_mac_select_pcs(struct phylink_config *config, phy_interface_t interface) {
@@ -2583,8 +2528,8 @@ static struct phylink_pcs *axienet_mac_select_pcs(struct phylink_config *config, struct axienet_local *lp = netdev_priv(ndev); if (interface == PHY_INTERFACE_MODE_1000BASEX || - interface == PHY_INTERFACE_MODE_SGMII) - return &lp->pcs; + interface == PHY_INTERFACE_MODE_SGMII) + return lp->pcs; return NULL; }
@@ -3056,28 +3001,23 @@ static int axienet_probe(struct platform_device *pdev) if (lp->phy_mode == PHY_INTERFACE_MODE_SGMII || lp->phy_mode == PHY_INTERFACE_MODE_1000BASEX) { - np = of_parse_phandle(pdev->dev.of_node, "pcs-handle", 0); - if (!np) { - /* Deprecated: Always use "pcs-handle" for pcs_phy. - * Falling back to "phy-handle" here is only for - * backward compatibility with old device trees. - */ - np = of_parse_phandle(pdev->dev.of_node, "phy-handle", 0); - } - if (!np) { - dev_err(&pdev->dev, "pcs-handle (preferred) or phy-handle required for 1000BaseX/SGMII\n"); - ret = -EINVAL; - goto cleanup_mdio; - } - lp->pcs_phy = of_mdio_find_device(np); - if (!lp->pcs_phy) { - ret = -EPROBE_DEFER; - of_node_put(np); + DECLARE_PHY_INTERFACE_MASK(interfaces); + + phy_interface_zero(interfaces); + if (lp->switch_x_sgmii || + lp->phy_mode == PHY_INTERFACE_MODE_SGMII) + __set_bit(PHY_INTERFACE_MODE_SGMII, interfaces); + if (lp->switch_x_sgmii || + lp->phy_mode == PHY_INTERFACE_MODE_1000BASEX) + __set_bit(PHY_INTERFACE_MODE_1000BASEX, interfaces); + + lp->pcs = axienet_xilinx_pcs_get(&pdev->dev, interfaces); + if (IS_ERR(lp->pcs)) { + ret = PTR_ERR(lp->pcs); + dev_err_probe(&pdev->dev, ret, + "could not get PCS for 1000BASE-X/SGMII\n"); goto cleanup_mdio; } - of_node_put(np); - lp->pcs.ops = &axienet_pcs_ops; - lp->pcs.poll = true; } lp->phylink_config.dev = &ndev->dev;
@@ -3115,8 +3055,6 @@ static int axienet_probe(struct platform_device *pdev) phylink_destroy(lp->phylink); cleanup_mdio: - if (lp->pcs_phy) - put_device(&lp->pcs_phy->dev); if (lp->mii_bus) axienet_mdio_teardown(lp); cleanup_clk:
@@ -3139,9 +3077,7 @@ static void axienet_remove(struct platform_device *pdev) if (lp->phylink) phylink_destroy(lp->phylink); - if (lp->pcs_phy) - put_device(&lp->pcs_phy->dev); - + pcs_put(lp->pcs); axienet_mdio_teardown(lp); clk_bulk_disable_unprepare(XAE_NUM_MISC_CLOCKS, lp->misc_clks);
--
2.35.1.1320.gc452695387.dirty