[net-next PATCH v3 08/11] net: axienet: Convert to use PCS subsystem

Gupta, Suraj Suraj.Gupta2 at amd.com
Fri Apr 18 02:04:34 PDT 2025


[AMD Official Use Only - AMD Internal Distribution Only]

> -----Original Message-----
> From: Sean Anderson <sean.anderson at linux.dev>
> Sent: Wednesday, April 16, 2025 1:03 AM
> To: netdev at vger.kernel.org; Andrew Lunn <andrew+netdev at lunn.ch>; David S .
> Miller <davem at davemloft.net>; Eric Dumazet <edumazet at google.com>; Jakub
> Kicinski <kuba at kernel.org>; Paolo Abeni <pabeni at redhat.com>; Russell King
> <linux at armlinux.org.uk>
> Cc: upstream at airoha.com; Christian Marangi <ansuelsmth at gmail.com>; linux-
> kernel at vger.kernel.org; Kory Maincent <kory.maincent at bootlin.com>; Heiner
> Kallweit <hkallweit1 at gmail.com>; Sean Anderson <sean.anderson at linux.dev>;
> Gupta, Suraj <Suraj.Gupta2 at amd.com>; Simek, Michal
> <michal.simek at amd.com>; Pandey, Radhey Shyam
> <radhey.shyam.pandey at amd.com>; Robert Hancock
> <robert.hancock at calian.com>; linux-arm-kernel at lists.infradead.org
> Subject: [net-next PATCH v3 08/11] net: axienet: Convert to use PCS subsystem
>
> Caution: This message originated from an External Source. Use proper caution
> when opening attachments, clicking links, or responding.
>
>
> 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 at linux.dev>
> Reviewed-by: Suraj Gupta <suraj.gupta2 at amd.com>
>

Tested with ZynqMP AXI 1G ethernet design. Ping works fine, and netperf numbers are as expected.

Tested-by: Suraj Gupta <suraj.gupta2 at amd.com>

> ---
>
> 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..9f130376e1eb 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_DEVICE
> +       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 054abf283ab3..07487c4b2141 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(&pdev->dev, lp->pcs);
>         axienet_mdio_teardown(lp);
>
>         clk_bulk_disable_unprepare(XAE_NUM_MISC_CLOCKS, lp->misc_clks);
> --
> 2.35.1.1320.gc452695387.dirty




More information about the linux-arm-kernel mailing list