[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20250728221823.11968-7-sean.anderson@linux.dev>
Date: Mon, 28 Jul 2025 18:18:22 -0400
From: Sean Anderson <sean.anderson@...ux.dev>
To: Radhey Shyam Pandey <radhey.shyam.pandey@....com>,
Andrew Lunn <andrew+netdev@...n.ch>,
"David S . Miller" <davem@...emloft.net>,
Eric Dumazet <edumazet@...gle.com>,
Jakub Kicinski <kuba@...nel.org>,
Paolo Abeni <pabeni@...hat.com>,
netdev@...r.kernel.org
Cc: linux-kernel@...r.kernel.org,
Greg Kroah-Hartman <gregkh@...uxfoundation.org>,
Michal Simek <michal.simek@....com>,
linux-arm-kernel@...ts.infradead.org,
Leon Romanovsky <leon@...nel.org>,
Sean Anderson <sean.anderson@...ux.dev>
Subject: [PATCH net-next v3 6/7] net: axienet: Rearrange lifetime functions
Rearrange the lifetime functions (probe, remove, etc.) in preparation
for the next commit. No functional change intended.
Signed-off-by: Sean Anderson <sean.anderson@...ux.dev>
---
Changes in v3:
- Rework to use a separate axienet_common structure
drivers/net/ethernet/xilinx/xilinx_axienet.h | 41 ++++--
.../net/ethernet/xilinx/xilinx_axienet_main.c | 135 ++++++++++--------
.../net/ethernet/xilinx/xilinx_axienet_mdio.c | 45 +++---
3 files changed, 127 insertions(+), 94 deletions(-)
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet.h b/drivers/net/ethernet/xilinx/xilinx_axienet.h
index 5ff742103beb..d7215dd92ce9 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet.h
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet.h
@@ -467,6 +467,29 @@ struct skbuf_dma_descriptor {
int sg_len;
};
+/**
+ * struct axienet_common - axienet private common data
+ * @pdev: Pointer to common platform device structure
+ * @axi_clk: AXI4-Lite bus clock
+ * @reset_lock: Lock held while resetting the device to prevent register access
+ * @mii_bus: Pointer to MII bus structure
+ * @mii_clk_div: MII bus clock divider value
+ * @regs_start: Resource start for axienet device addresses
+ * @regs: Base address for the axienet_local device address space
+ */
+struct axienet_common {
+ struct platform_device *pdev;
+
+ struct clk *axi_clk;
+
+ struct mutex reset_lock;
+ struct mii_bus *mii_bus;
+ u8 mii_clk_div;
+
+ void __iomem *regs;
+ resource_size_t regs_start;
+};
+
/**
* struct axienet_local - axienet private per device data
* @ndev: Pointer for net_device to which it will be attached.
@@ -549,6 +572,7 @@ struct skbuf_dma_descriptor {
struct axienet_local {
struct net_device *ndev;
struct device *dev;
+ struct axienet_common *cp;
struct phylink *phylink;
struct phylink_config phylink_config;
@@ -558,13 +582,11 @@ struct axienet_local {
bool switch_x_sgmii;
- struct clk *axi_clk;
struct clk_bulk_data misc_clks[XAE_NUM_MISC_CLOCKS];
struct mii_bus *mii_bus;
u8 mii_clk_div;
- resource_size_t regs_start;
void __iomem *regs;
void __iomem *dma_regs;
@@ -654,21 +676,14 @@ static inline u32 axienet_ior(struct axienet_local *lp, off_t offset)
return ioread32(lp->regs + offset);
}
-static inline u32 axinet_ior_read_mcr(struct axienet_local *lp)
-{
- return axienet_ior(lp, XAE_MDIO_MCR_OFFSET);
-}
-
static inline void axienet_lock_mii(struct axienet_local *lp)
{
- if (lp->mii_bus)
- mutex_lock(&lp->mii_bus->mdio_lock);
+ mutex_lock(&lp->cp->reset_lock);
}
static inline void axienet_unlock_mii(struct axienet_local *lp)
{
- if (lp->mii_bus)
- mutex_unlock(&lp->mii_bus->mdio_lock);
+ mutex_unlock(&lp->cp->reset_lock);
}
/**
@@ -738,7 +753,7 @@ static inline void axienet_dma_out_addr(struct axienet_local *lp, off_t reg,
#endif /* CONFIG_64BIT */
/* Function prototypes visible in xilinx_axienet_mdio.c for other files */
-int axienet_mdio_setup(struct axienet_local *lp);
-void axienet_mdio_teardown(struct axienet_local *lp);
+int axienet_mdio_setup(struct axienet_common *lp);
+void axienet_mdio_teardown(struct axienet_common *lp);
#endif /* XILINX_AXI_ENET_H */
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
index 28927c7c6c41..f235ef15187c 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
@@ -225,8 +225,8 @@ static void axienet_dma_bd_release(struct net_device *ndev)
static u64 axienet_dma_rate(struct axienet_local *lp)
{
- if (lp->axi_clk)
- return clk_get_rate(lp->axi_clk);
+ if (lp->cp->axi_clk)
+ return clk_get_rate(lp->cp->axi_clk);
return 125000000; /* arbitrary guess if no clock rate set */
}
@@ -2749,29 +2749,17 @@ static void axienet_disable_misc(void *clocks)
clk_bulk_disable_unprepare(XAE_NUM_MISC_CLOCKS, clocks);
}
-/**
- * axienet_probe - Axi Ethernet probe function.
- * @pdev: Pointer to platform device structure.
- *
- * Return: 0, on success
- * Non-zero error value on failure.
- *
- * This is the probe routine for Axi Ethernet driver. This is called before
- * any other driver routines are invoked. It allocates and sets up the Ethernet
- * device. Parses through device tree and populates fields of
- * axienet_local. It registers the Ethernet device.
- */
-static int axienet_probe(struct platform_device *pdev)
+static int axienet_mac_probe(struct axienet_common *cp)
{
- int ret;
+ struct platform_device *pdev = cp->pdev;
struct device *dev = &pdev->dev;
- struct device_node *np;
struct axienet_local *lp;
struct net_device *ndev;
- struct resource *ethres;
+ struct device_node *np;
u8 mac_addr[ETH_ALEN];
int addr_width = 32;
u32 value;
+ int ret;
ndev = devm_alloc_etherdev(dev, sizeof(*lp));
if (!ndev)
@@ -2790,6 +2778,8 @@ static int axienet_probe(struct platform_device *pdev)
lp = netdev_priv(ndev);
lp->ndev = ndev;
lp->dev = dev;
+ lp->cp = cp;
+ lp->regs = cp->regs;
lp->options = XAE_OPTION_DEFAULTS;
lp->rx_bd_num = RX_BD_NUM_DEFAULT;
lp->tx_bd_num = TX_BD_NUM_DEFAULT;
@@ -2801,17 +2791,6 @@ static int axienet_probe(struct platform_device *pdev)
seqcount_mutex_init(&lp->hw_stats_seqcount, &lp->stats_lock);
INIT_DEFERRABLE_WORK(&lp->stats_work, axienet_refresh_stats);
- lp->axi_clk = devm_clk_get_optional_enabled(dev, "s_axi_lite_clk");
- if (!lp->axi_clk) {
- /* For backward compatibility, if named AXI clock is not present,
- * treat the first clock specified as the AXI clock.
- */
- lp->axi_clk = devm_clk_get_optional_enabled(dev, NULL);
- }
- if (IS_ERR(lp->axi_clk))
- return dev_err_probe(dev, PTR_ERR(lp->axi_clk),
- "could not get AXI clock\n");
-
lp->misc_clks[0].id = "axis_clk";
lp->misc_clks[1].id = "ref_clk";
lp->misc_clks[2].id = "mgt_clk";
@@ -2831,12 +2810,6 @@ static int axienet_probe(struct platform_device *pdev)
if (ret)
return ret;
- /* Map device registers */
- lp->regs = devm_platform_get_and_ioremap_resource(pdev, 0, ðres);
- if (IS_ERR(lp->regs))
- return PTR_ERR(lp->regs);
- lp->regs_start = ethres->start;
-
/* Setup checksum offload, but default to off if not specified */
lp->features = 0;
@@ -3045,11 +3018,6 @@ static int axienet_probe(struct platform_device *pdev)
lp->tx_dma_cr = axienet_calc_cr(lp, XAXIDMA_DFT_TX_THRESHOLD,
XAXIDMA_DFT_TX_USEC);
- ret = axienet_mdio_setup(lp);
- if (ret)
- dev_warn(dev,
- "error registering MDIO bus: %d\n", ret);
-
if (lp->phy_mode == PHY_INTERFACE_MODE_SGMII ||
lp->phy_mode == PHY_INTERFACE_MODE_1000BASEX) {
np = of_parse_phandle(dev->of_node, "pcs-handle", 0);
@@ -3061,17 +3029,14 @@ static int axienet_probe(struct platform_device *pdev)
np = of_parse_phandle(dev->of_node, "phy-handle", 0);
}
if (!np) {
- dev_err(dev, "pcs-handle (preferred) or phy-handle required for 1000BaseX/SGMII\n");
- ret = -EINVAL;
- goto cleanup_mdio;
+ dev_err(dev,
+ "pcs-handle (preferred) or phy-handle required for 1000BaseX/SGMII\n");
+ return -EINVAL;
}
lp->pcs_phy = of_mdio_find_device(np);
- if (!lp->pcs_phy) {
- ret = -EPROBE_DEFER;
- of_node_put(np);
- goto cleanup_mdio;
- }
of_node_put(np);
+ if (!lp->pcs_phy)
+ return -EPROBE_DEFER;
lp->pcs.ops = &axienet_pcs_ops;
lp->pcs.poll = true;
}
@@ -3096,7 +3061,7 @@ static int axienet_probe(struct platform_device *pdev)
if (IS_ERR(lp->phylink)) {
ret = PTR_ERR(lp->phylink);
dev_err(dev, "phylink_create error (%i)\n", ret);
- goto cleanup_mdio;
+ goto cleanup_pcs;
}
ret = register_netdev(lp->ndev);
@@ -3109,32 +3074,24 @@ static int axienet_probe(struct platform_device *pdev)
cleanup_phylink:
phylink_destroy(lp->phylink);
-
-cleanup_mdio:
+cleanup_pcs:
if (lp->pcs_phy)
put_device(&lp->pcs_phy->dev);
- if (lp->mii_bus)
- axienet_mdio_teardown(lp);
return ret;
}
-static void axienet_remove(struct platform_device *pdev)
+static void axienet_mac_remove(struct platform_device *pdev)
{
struct net_device *ndev = platform_get_drvdata(pdev);
struct axienet_local *lp = netdev_priv(ndev);
unregister_netdev(ndev);
-
- if (lp->phylink)
- phylink_destroy(lp->phylink);
-
+ phylink_destroy(lp->phylink);
if (lp->pcs_phy)
put_device(&lp->pcs_phy->dev);
-
- axienet_mdio_teardown(lp);
}
-static void axienet_shutdown(struct platform_device *pdev)
+static void axienet_mac_shutdown(struct platform_device *pdev)
{
struct net_device *ndev = platform_get_drvdata(pdev);
@@ -3182,10 +3139,64 @@ static int axienet_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(axienet_pm_ops,
axienet_suspend, axienet_resume);
+static int axienet_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct axienet_common *cp;
+ struct resource *ethres;
+ int ret;
+
+ cp = devm_kzalloc(dev, sizeof(*cp), GFP_KERNEL);
+ if (!cp)
+ return -ENOMEM;
+
+ cp->pdev = pdev;
+ mutex_init(&cp->reset_lock);
+
+ cp->axi_clk = devm_clk_get_optional_enabled(dev, "s_axi_lite_clk");
+ if (!cp->axi_clk) {
+ /* For backward compatibility, if named AXI clock is not present,
+ * treat the first clock specified as the AXI clock.
+ */
+ cp->axi_clk = devm_clk_get_optional_enabled(dev, NULL);
+ }
+ if (IS_ERR(cp->axi_clk))
+ return dev_err_probe(dev, PTR_ERR(cp->axi_clk),
+ "could not get AXI clock\n");
+
+ /* Map device registers */
+ cp->regs = devm_platform_get_and_ioremap_resource(pdev, 0, ðres);
+ if (IS_ERR(cp->regs))
+ return PTR_ERR(cp->regs);
+ cp->regs_start = ethres->start;
+
+ ret = axienet_mdio_setup(cp);
+ if (ret)
+ dev_warn(dev, "error registering MDIO bus: %d\n", ret);
+
+ ret = axienet_mac_probe(cp);
+ if (!ret)
+ return 0;
+
+ if (cp->mii_bus)
+ axienet_mdio_teardown(cp);
+ return ret;
+}
+
+static void axienet_remove(struct platform_device *pdev)
+{
+ struct net_device *ndev = platform_get_drvdata(pdev);
+ struct axienet_local *lp = netdev_priv(ndev);
+
+ axienet_mac_remove(pdev);
+ if (lp->mii_bus)
+ axienet_mdio_teardown(lp->cp);
+}
+
static struct platform_driver axienet_driver = {
.probe = axienet_probe,
.remove = axienet_remove,
- .shutdown = axienet_shutdown,
+ .shutdown = axienet_mac_shutdown,
.driver = {
.name = "xilinx_axienet",
.pm = &axienet_pm_ops,
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c b/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c
index 2799d168ed9d..d428ce6da639 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c
@@ -12,6 +12,7 @@
#include <linux/clk.h>
#include <linux/of_address.h>
#include <linux/of_mdio.h>
+#include <linux/platform_device.h>
#include <linux/jiffies.h>
#include <linux/iopoll.h>
@@ -22,13 +23,13 @@
/**
* axienet_mdio_wait_until_ready - MDIO wait function
- * @lp: Pointer to axienet local data structure.
+ * @lp: Pointer to axienet common data structure.
*
* Return : 0 on success, Negative value on errors
*
* Wait till MDIO interface is ready to accept a new transaction.
*/
-static int axienet_mdio_wait_until_ready(struct axienet_local *lp)
+static int axienet_mdio_wait_until_ready(struct axienet_common *lp)
{
u32 val;
@@ -39,11 +40,11 @@ static int axienet_mdio_wait_until_ready(struct axienet_local *lp)
/**
* axienet_mdio_mdc_enable - MDIO MDC enable function
- * @lp: Pointer to axienet local data structure.
+ * @lp: Pointer to axienet common data structure.
*
* Enable the MDIO MDC. Called prior to a read/write operation
*/
-static void axienet_mdio_mdc_enable(struct axienet_local *lp)
+static void axienet_mdio_mdc_enable(struct axienet_common *lp)
{
iowrite32((u32)lp->mii_clk_div | XAE_MDIO_MC_MDIOEN_MASK,
lp->regs + XAE_MDIO_MC_OFFSET);
@@ -51,11 +52,11 @@ static void axienet_mdio_mdc_enable(struct axienet_local *lp)
/**
* axienet_mdio_mdc_disable - MDIO MDC disable function
- * @lp: Pointer to axienet local data structure.
+ * @lp: Pointer to axienet common data structure.
*
* Disable the MDIO MDC. Called after a read/write operation
*/
-static void axienet_mdio_mdc_disable(struct axienet_local *lp)
+static void axienet_mdio_mdc_disable(struct axienet_common *lp)
{
u32 mc_reg;
@@ -80,8 +81,9 @@ static int axienet_mdio_read(struct mii_bus *bus, int phy_id, int reg)
{
u32 rc;
int ret;
- struct axienet_local *lp = bus->priv;
+ struct axienet_common *lp = bus->priv;
+ guard(mutex)(&lp->reset_lock);
axienet_mdio_mdc_enable(lp);
ret = axienet_mdio_wait_until_ready(lp);
@@ -127,13 +129,14 @@ static int axienet_mdio_read(struct mii_bus *bus, int phy_id, int reg)
static int axienet_mdio_write(struct mii_bus *bus, int phy_id, int reg,
u16 val)
{
- struct axienet_local *lp = bus->priv;
+ struct axienet_common *lp = bus->priv;
int ret;
u32 mcr;
dev_dbg(&bus->dev, "%s(phy_id=%i, reg=%x, val=%x)\n", __func__,
phy_id, reg, val);
+ guard(mutex)(&lp->reset_lock);
axienet_mdio_mdc_enable(lp);
ret = axienet_mdio_wait_until_ready(lp);
@@ -160,7 +163,7 @@ static int axienet_mdio_write(struct mii_bus *bus, int phy_id, int reg,
/**
* axienet_mdio_enable - MDIO hardware setup function
- * @lp: Pointer to axienet local data structure.
+ * @lp: Pointer to axienet common data structure.
* @np: Pointer to mdio device tree node.
*
* Return: 0 on success, -ETIMEDOUT on a timeout, -EOVERFLOW on a clock
@@ -171,7 +174,7 @@ static int axienet_mdio_write(struct mii_bus *bus, int phy_id, int reg,
**/
static int axienet_mdio_enable(struct mii_bus *bus, struct device_node *np)
{
- struct axienet_local *lp = bus->priv;
+ struct axienet_common *lp = bus->priv;
u32 mdio_freq = DEFAULT_MDIO_FREQ;
u32 host_clock;
u32 clk_div;
@@ -187,7 +190,7 @@ static int axienet_mdio_enable(struct mii_bus *bus, struct device_node *np)
/* Legacy fallback: detect CPU clock frequency and use as AXI
* bus clock frequency. This only works on certain platforms.
*/
- np1 = of_find_node_by_name(NULL, "lpu");
+ np1 = of_find_node_by_name(NULL, "cpu");
if (!np1) {
dev_warn(&bus->dev,
"Could not find CPU device node.\n");
@@ -258,6 +261,7 @@ static int axienet_mdio_enable(struct mii_bus *bus, struct device_node *np)
"Setting MDIO clock divisor to %u/%u Hz host clock.\n",
lp->mii_clk_div, host_clock);
+ guard(mutex)(&lp->reset_lock);
axienet_mdio_mdc_enable(lp);
ret = axienet_mdio_wait_until_ready(lp);
@@ -269,7 +273,7 @@ static int axienet_mdio_enable(struct mii_bus *bus, struct device_node *np)
/**
* axienet_mdio_setup - MDIO setup function
- * @lp: Pointer to axienet local data structure.
+ * @lp: Pointer to axienet common data structure.
*
* Return: 0 on success, -ETIMEDOUT on a timeout, -EOVERFLOW on a clock
* divisor overflow, -ENOMEM when mdiobus_alloc (to allocate
@@ -278,7 +282,7 @@ static int axienet_mdio_enable(struct mii_bus *bus, struct device_node *np)
* Sets up the MDIO interface by initializing the MDIO clock.
* Register the MDIO interface.
**/
-int axienet_mdio_setup(struct axienet_local *lp)
+int axienet_mdio_setup(struct axienet_common *lp)
{
struct device_node *mdio_node;
struct mii_bus *bus;
@@ -295,18 +299,21 @@ int axienet_mdio_setup(struct axienet_local *lp)
bus->name = "Xilinx Axi Ethernet MDIO";
bus->read = axienet_mdio_read;
bus->write = axienet_mdio_write;
- bus->parent = lp->dev;
+ bus->parent = &lp->pdev->dev;
lp->mii_bus = bus;
- mdio_node = of_get_child_by_name(lp->dev->of_node, "mdio");
- ret = axienet_mdio_enable(bus, mdio_node);
+ mdio_node = of_get_child_by_name(lp->pdev->dev.of_node, "mdio");
+ scoped_guard(mutex, &lp->reset_lock)
+ ret = axienet_mdio_enable(bus, mdio_node);
if (ret < 0)
goto unregister;
ret = of_mdiobus_register(bus, mdio_node);
of_node_put(mdio_node);
- axienet_mdio_mdc_disable(lp);
+ scoped_guard(mutex, &lp->reset_lock)
+ axienet_mdio_mdc_disable(lp);
if (ret) {
+unregister:
mdiobus_free(bus);
lp->mii_bus = NULL;
}
@@ -315,11 +322,11 @@ int axienet_mdio_setup(struct axienet_local *lp)
/**
* axienet_mdio_teardown - MDIO remove function
- * @lp: Pointer to axienet local data structure.
+ * @lp: Pointer to axienet common data structure.
*
* Unregisters the MDIO and frees any associate memory for mii bus.
*/
-void axienet_mdio_teardown(struct axienet_local *lp)
+void axienet_mdio_teardown(struct axienet_common *lp)
{
mdiobus_unregister(lp->mii_bus);
mdiobus_free(lp->mii_bus);
--
2.35.1.1320.gc452695387.dirty
Powered by blists - more mailing lists