From: Sean Anderson <sean.anderson@linux.dev>
To: netdev@vger.kernel.org, Andrew Lunn <andrew+netdev@lunn.ch>,
"David S . Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@google.com>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
Russell King <linux@armlinux.org.uk>
Cc: Vineeth Karumanchi <vineeth.karumanchi@amd.com>,
Heiner Kallweit <hkallweit1@gmail.com>,
linux-kernel@vger.kernel.org,
Kory Maincent <kory.maincent@bootlin.com>,
Daniel Golle <daniel@makrotopia.org>,
Simon Horman <horms@kernel.org>,
Christian Marangi <ansuelsmth@gmail.com>,
Lei Wei <quic_leiwei@quicinc.com>,
Sean Anderson <sean.anderson@linux.dev>,
Michal Simek <michal.simek@amd.com>,
Radhey Shyam Pandey <radhey.shyam.pandey@amd.com>,
Robert Hancock <robert.hancock@calian.com>,
linux-arm-kernel@lists.infradead.org
Subject: [net-next PATCH v6 07/10] net: axienet: Convert to use PCS subsystem
Date: Tue, 10 Jun 2025 19:31:31 -0400 [thread overview]
Message-ID: <20250610233134.3588011-8-sean.anderson@linux.dev> (raw)
In-Reply-To: <20250610233134.3588011-1-sean.anderson@linux.dev>
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. This functionality is gated
behind a config to allow it to be disabled by vendors who have fixed all
of their devicetrees.
Signed-off-by: Sean Anderson <sean.anderson@linux.dev>
---
Changes in v6:
- Introduce config for compatibility helpers
- Move axienet_pcs_fixup to this commit
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 | 13 ++
drivers/net/ethernet/xilinx/xilinx_axienet.h | 4 +-
.../net/ethernet/xilinx/xilinx_axienet_main.c | 160 +++++++++---------
3 files changed, 90 insertions(+), 87 deletions(-)
diff --git a/drivers/net/ethernet/xilinx/Kconfig b/drivers/net/ethernet/xilinx/Kconfig
index 7502214cc7d5..d9c7a151bbaa 100644
--- a/drivers/net/ethernet/xilinx/Kconfig
+++ b/drivers/net/ethernet/xilinx/Kconfig
@@ -27,12 +27,25 @@ config XILINX_AXI_EMAC
tristate "Xilinx 10/100/1000 AXI Ethernet support"
depends on HAS_IOMEM
depends on XILINX_DMA
+ select MDIO_BUS
+ select OF_DYNAMIC
select PHYLINK
select DIMLIB
help
This driver supports the 10/100/1000 Ethernet from Xilinx for the
AXI bus interface used in Xilinx Virtex FPGAs and Soc's.
+config XILINX_AXI_EMAC_PCS_COMPAT
+ bool "Xilinx AXI Ethernet PCS compatibility shim"
+ default PCS_XILINX
+ depends on XILINX_AXI_EMAC
+ select OF_DYNAMIC
+ help
+ Enable support for older devicetrees which do not have compatibles
+ for the Xilinx PCS/PMA. If you enable this option, you should
+ probably enable PCS_XILINX too. If you do not use 1G speeds, or you
+ do not have a (Xilinx) PCS, say n. If unsure, say y.
+
config XILINX_LL_TEMAC
tristate "Xilinx LL TEMAC (LocalLink Tri-mode Ethernet MAC) driver"
depends on HAS_IOMEM
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 6011d7eae0c7..09852960713b 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
@@ -35,6 +35,7 @@
#include <linux/platform_device.h>
#include <linux/skbuff.h>
#include <linux/math64.h>
+#include <linux/pcs.h>
#include <linux/phy.h>
#include <linux/mii.h>
#include <linux/ethtool.h>
@@ -2519,63 +2520,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 +2527,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;
}
@@ -2744,6 +2688,59 @@ static void axienet_dma_err_handler(struct work_struct *work)
axienet_setoptions(ndev, lp->options);
}
+#ifdef CONFIG_XILINX_AXI_EMAC_PCS_COMPAT
+static int axienet_pcs_fixup(struct of_changeset *ocs, struct device_node *np,
+ void *data)
+{
+ unsigned int interface, mode_count, mode = 0;
+ const unsigned long *interfaces = data;
+ const char **modes;
+ int ret;
+
+ mode_count = bitmap_weight(interfaces, PHY_INTERFACE_MODE_MAX);
+ WARN_ON_ONCE(!mode_count);
+ modes = kcalloc(mode_count, sizeof(*modes), GFP_KERNEL);
+ if (!modes)
+ return -ENOMEM;
+
+ for_each_set_bit(interface, interfaces, PHY_INTERFACE_MODE_MAX)
+ modes[mode++] = phy_modes(interface);
+ ret = of_changeset_add_prop_string_array(ocs, np, "xlnx,pcs-modes",
+ modes, mode_count);
+ kfree(modes);
+ if (ret)
+ return ret;
+
+ return of_changeset_add_prop_string(ocs, np, "compatible", "xlnx,pcs");
+}
+
+/**
+ * axienet_pcs_get() - PCS Compatibility function for old device trees
+ * @dev: The MAC device
+ * @interfaces: The interfaces to use as a fallback
+ *
+ * This is a helper function to ensure backwards compatibility with device
+ * trees which do not include compatible strings for the PCS/PMA.
+ *
+ * Return: a PCS, or an error pointer
+ */
+static struct phylink_pcs *axienet_pcs_get(struct device *dev,
+ const unsigned long *interfaces)
+{
+ struct fwnode_handle *fwnode;
+ struct phylink_pcs *pcs;
+
+ fwnode = pcs_find_fwnode(dev_fwnode(dev), NULL, "phy-handle", false);
+ if (IS_ERR(fwnode))
+ return ERR_CAST(fwnode);
+
+ pcs = pcs_get_by_fwnode_compat(dev, fwnode, axienet_pcs_fixup,
+ (void *)interfaces);
+ fwnode_handle_put(fwnode);
+ return pcs;
+}
+#endif
+
/**
* axienet_probe - Axi Ethernet probe function.
* @pdev: Pointer to platform device structure.
@@ -3056,28 +3053,27 @@ 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);
+#ifdef CONFIG_XILINX_AXI_EMAC_PCS_COMPAT
+ 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_pcs_get(&pdev->dev, interfaces);
+#else
+ lp->pcs = pcs_get(&pdev->dev, NULL);
+#endif
+ 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 +3111,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 +3133,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
next prev parent reply other threads:[~2025-06-10 23:32 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-06-10 23:31 [net-next PATCH v6 00/10] Add PCS core support Sean Anderson
2025-06-10 23:31 ` [net-next PATCH v6 01/10] dt-bindings: net: Add Xilinx PCS Sean Anderson
2025-06-10 23:31 ` [net-next PATCH v6 02/10] net: phylink: Support setting PCS link change callbacks Sean Anderson
2025-06-10 23:31 ` [net-next PATCH v6 03/10] net: pcs: Add subsystem Sean Anderson
2025-06-11 0:24 ` Randy Dunlap
2025-06-12 15:38 ` Sean Anderson
2025-06-10 23:31 ` [net-next PATCH v6 04/10] net: dsa: ocelot: suppress PHY device scanning on the internal MDIO bus Sean Anderson
2025-06-10 23:31 ` [net-next PATCH v6 05/10] net: pcs: lynx: Convert to an MDIO driver Sean Anderson
2025-06-13 11:27 ` kernel test robot
2025-06-10 23:31 ` [net-next PATCH v6 06/10] net: pcs: Add Xilinx PCS driver Sean Anderson
2025-06-11 5:11 ` Maxime Chevallier
2025-06-12 15:34 ` Sean Anderson
2025-06-12 0:14 ` kernel test robot
2025-06-10 23:31 ` Sean Anderson [this message]
2025-06-11 20:56 ` [net-next PATCH v6 07/10] net: axienet: Convert to use PCS subsystem kernel test robot
2025-06-11 22:19 ` kernel test robot
2025-06-10 23:31 ` [net-next PATCH v6 08/10] net: macb: Move most of mac_config to mac_prepare Sean Anderson
2025-06-10 23:35 ` Sean Anderson
2025-06-10 23:36 ` [net-next PATCH v6 09/10] net: macb: Support external PCSs Sean Anderson
2025-06-13 14:50 ` kernel test robot
2025-06-10 23:37 ` [net-next PATCH v6 10/10] of: property: Add device link support for PCS Sean Anderson
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250610233134.3588011-8-sean.anderson@linux.dev \
--to=sean.anderson@linux.dev \
--cc=andrew+netdev@lunn.ch \
--cc=ansuelsmth@gmail.com \
--cc=daniel@makrotopia.org \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=hkallweit1@gmail.com \
--cc=horms@kernel.org \
--cc=kory.maincent@bootlin.com \
--cc=kuba@kernel.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux@armlinux.org.uk \
--cc=michal.simek@amd.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=quic_leiwei@quicinc.com \
--cc=radhey.shyam.pandey@amd.com \
--cc=robert.hancock@calian.com \
--cc=vineeth.karumanchi@amd.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).