summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaolo Abeni <pabeni@redhat.com>2026-02-10 13:40:52 +0100
committerPaolo Abeni <pabeni@redhat.com>2026-02-10 13:40:53 +0100
commit86dbebfb9053cd8626ee7c0297e991ce4843bd3f (patch)
tree2cba85724ef4d02f932c7209a2e880341fb1bbf3
parent4f65ee7e0cbfd6ff4db88a60a08bb10f1fdc4ecc (diff)
parent7ac5dddef5168b13e490402802f7628d012f477d (diff)
Merge branch 'net-ftgmac100-various-probe-cleanups'
Jacky Chou says: ==================== net: ftgmac100: Various probe cleanups The probe function of the ftgmac100 is rather complex, due to the way it has evolved over time, dealing with poor DT descriptions, and new variants of the MAC. Make use of DT match data to identify the MAC variant, rather than looking at the compatible string all the time. Make use of devm_ calls to simplify cleanup. This indirectly fixes inconsistent goto label names. Always probe the MDIO bus, when it exists. This simplifies the logic a bit. Move code into helpers to simply probe. Signed-off-by: Andrew Lunn <andrew@lunn.ch> Signed-off-by: Jacky Chou <jacky_chou@aspeedtech.com> ==================== Link: https://patch.msgid.link/20260206-ftgmac-cleanup-v5-0-ad28a9067ea7@aspeedtech.com Signed-off-by: Paolo Abeni <pabeni@redhat.com>
-rw-r--r--drivers/net/ethernet/faraday/ftgmac100.c356
1 files changed, 194 insertions, 162 deletions
diff --git a/drivers/net/ethernet/faraday/ftgmac100.c b/drivers/net/ethernet/faraday/ftgmac100.c
index a863f7841210..1e91e79c8134 100644
--- a/drivers/net/ethernet/faraday/ftgmac100.c
+++ b/drivers/net/ethernet/faraday/ftgmac100.c
@@ -33,6 +33,17 @@
#define DRV_NAME "ftgmac100"
+enum ftgmac100_mac_id {
+ FTGMAC100_FARADAY = 1,
+ FTGMAC100_AST2400,
+ FTGMAC100_AST2500,
+ FTGMAC100_AST2600
+};
+
+struct ftgmac100_match_data {
+ enum ftgmac100_mac_id mac_id;
+};
+
/* Arbitrary values, I am not sure the HW has limits */
#define MAX_RX_QUEUE_ENTRIES 1024
#define MAX_TX_QUEUE_ENTRIES 1024
@@ -66,6 +77,8 @@ struct ftgmac100 {
struct resource *res;
void __iomem *base;
+ enum ftgmac100_mac_id mac_id;
+
/* Rx ring */
unsigned int rx_q_entries;
struct ftgmac100_rxdes *rxdes;
@@ -1470,6 +1483,11 @@ static int ftgmac100_mii_probe(struct net_device *netdev)
phy_interface_t phy_intf;
int err;
+ if (!priv->mii_bus) {
+ dev_err(priv->dev, "No MDIO bus available\n");
+ return -ENODEV;
+ }
+
/* Default to RGMII. It's a gigabit part after all */
err = of_get_phy_mode(np, &phy_intf);
if (err)
@@ -1699,16 +1717,16 @@ static int ftgmac100_setup_mdio(struct net_device *netdev)
struct platform_device *pdev = to_platform_device(priv->dev);
struct device_node *np = pdev->dev.of_node;
struct device_node *mdio_np;
- int i, err = 0;
+ int err = 0;
u32 reg;
/* initialize mdio bus */
- priv->mii_bus = mdiobus_alloc();
+ priv->mii_bus = devm_mdiobus_alloc(priv->dev);
if (!priv->mii_bus)
return -EIO;
- if (of_device_is_compatible(np, "aspeed,ast2400-mac") ||
- of_device_is_compatible(np, "aspeed,ast2500-mac")) {
+ if (priv->mac_id == FTGMAC100_AST2400 ||
+ priv->mac_id == FTGMAC100_AST2500) {
/* The AST2600 has a separate MDIO controller */
/* For the AST2400 and AST2500 this driver only supports the
@@ -1727,24 +1745,16 @@ static int ftgmac100_setup_mdio(struct net_device *netdev)
priv->mii_bus->read = ftgmac100_mdiobus_read;
priv->mii_bus->write = ftgmac100_mdiobus_write;
- for (i = 0; i < PHY_MAX_ADDR; i++)
- priv->mii_bus->irq[i] = PHY_POLL;
-
mdio_np = of_get_child_by_name(np, "mdio");
- err = of_mdiobus_register(priv->mii_bus, mdio_np);
+ err = devm_of_mdiobus_register(priv->dev, priv->mii_bus, mdio_np);
+ of_node_put(mdio_np);
if (err) {
dev_err(priv->dev, "Cannot register MDIO bus!\n");
- goto err_register_mdiobus;
+ return err;
}
- of_node_put(mdio_np);
-
return 0;
-
-err_register_mdiobus:
- mdiobus_free(priv->mii_bus);
- return err;
}
static void ftgmac100_phy_disconnect(struct net_device *netdev)
@@ -1763,17 +1773,6 @@ static void ftgmac100_phy_disconnect(struct net_device *netdev)
fixed_phy_unregister(phydev);
}
-static void ftgmac100_destroy_mdio(struct net_device *netdev)
-{
- struct ftgmac100 *priv = netdev_priv(netdev);
-
- if (!priv->mii_bus)
- return;
-
- mdiobus_unregister(priv->mii_bus);
- mdiobus_free(priv->mii_bus);
-}
-
static void ftgmac100_ncsi_handler(struct ncsi_dev *nd)
{
if (unlikely(nd->state != ncsi_dev_state_functional))
@@ -1788,13 +1787,10 @@ static int ftgmac100_setup_clk(struct ftgmac100 *priv)
struct clk *clk;
int rc;
- clk = devm_clk_get(priv->dev, NULL /* MACCLK */);
+ clk = devm_clk_get_enabled(priv->dev, NULL /* MACCLK */);
if (IS_ERR(clk))
return PTR_ERR(clk);
priv->clk = clk;
- rc = clk_prepare_enable(priv->clk);
- if (rc)
- return rc;
/* Aspeed specifies a 100MHz clock is required for up to
* 1000Mbit link speeds. As NCSI is limited to 100Mbit, 25MHz
@@ -1803,21 +1799,17 @@ static int ftgmac100_setup_clk(struct ftgmac100 *priv)
rc = clk_set_rate(priv->clk, priv->use_ncsi ? FTGMAC_25MHZ :
FTGMAC_100MHZ);
if (rc)
- goto cleanup_clk;
+ return rc;
/* RCLK is for RMII, typically used for NCSI. Optional because it's not
* necessary if it's the AST2400 MAC, or the MAC is configured for
* RGMII, or the controller is not an ASPEED-based controller.
*/
- priv->rclk = devm_clk_get_optional(priv->dev, "RCLK");
- rc = clk_prepare_enable(priv->rclk);
- if (!rc)
- return 0;
-
-cleanup_clk:
- clk_disable_unprepare(priv->clk);
+ priv->rclk = devm_clk_get_optional_enabled(priv->dev, "RCLK");
+ if (IS_ERR(priv->rclk))
+ return PTR_ERR(priv->rclk);
- return rc;
+ return 0;
}
static bool ftgmac100_has_child_node(struct device_node *np, const char *name)
@@ -1833,16 +1825,121 @@ static bool ftgmac100_has_child_node(struct device_node *np, const char *name)
return ret;
}
+static int ftgmac100_probe_ncsi(struct net_device *netdev,
+ struct ftgmac100 *priv,
+ struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct phy_device *phydev;
+ int err;
+
+ if (!IS_ENABLED(CONFIG_NET_NCSI)) {
+ dev_err(&pdev->dev, "NCSI stack not enabled\n");
+ return -EINVAL;
+ }
+
+ dev_info(&pdev->dev, "Using NCSI interface\n");
+ priv->use_ncsi = true;
+ priv->ndev = ncsi_register_dev(netdev, ftgmac100_ncsi_handler);
+ if (!priv->ndev)
+ return -EINVAL;
+
+ phydev = fixed_phy_register(&ncsi_phy_status, np);
+ if (IS_ERR(phydev)) {
+ dev_err(&pdev->dev, "failed to register fixed PHY device\n");
+ err = PTR_ERR(phydev);
+ goto err_register_ndev;
+ }
+ err = phy_connect_direct(netdev, phydev, ftgmac100_adjust_link,
+ PHY_INTERFACE_MODE_RMII);
+ if (err) {
+ dev_err(&pdev->dev, "Connecting PHY failed\n");
+ goto err_register_phy;
+ }
+
+ return 0;
+err_register_phy:
+ fixed_phy_unregister(phydev);
+err_register_ndev:
+ if (priv->ndev)
+ ncsi_unregister_dev(priv->ndev);
+ priv->ndev = NULL;
+ return err;
+}
+
+static int ftgmac100_probe_dt(struct net_device *netdev,
+ struct platform_device *pdev,
+ struct ftgmac100 *priv,
+ struct device_node *np)
+{
+ struct phy_device *phy;
+ int err;
+
+ if (of_get_property(np, "use-ncsi", NULL))
+ return ftgmac100_probe_ncsi(netdev, priv, pdev);
+
+ if (of_phy_is_fixed_link(np) ||
+ of_get_property(np, "phy-handle", NULL)) {
+ /* Support "mdio"/"phy" child nodes for ast2400/2500
+ * with an embedded MDIO controller. Automatically
+ * scan the DTS for available PHYs and register
+ * them. 2600 has an independent MDIO controller, not
+ * part of the MAC.
+ */
+ phy = of_phy_get_and_connect(priv->netdev, np,
+ &ftgmac100_adjust_link);
+ if (!phy) {
+ dev_err(&pdev->dev, "Failed to connect to phy\n");
+ return -EINVAL;
+ }
+
+ /* Indicate that we support PAUSE frames (see comment in
+ * Documentation/networking/phy.rst)
+ */
+ phy_support_asym_pause(phy);
+
+ /* Display what we found */
+ phy_attached_info(phy);
+ return 0;
+ }
+
+ if (!ftgmac100_has_child_node(np, "mdio")) {
+ /* Support legacy ASPEED devicetree descriptions that
+ * decribe a MAC with an embedded MDIO controller but
+ * have no "mdio" child node. Automatically scan the
+ * MDIO bus for available PHYs.
+ */
+ err = ftgmac100_mii_probe(netdev);
+ if (err) {
+ dev_err(priv->dev, "MII probe failed!\n");
+ return err;
+ }
+ }
+
+ return 0;
+}
+
static int ftgmac100_probe(struct platform_device *pdev)
{
+ const struct ftgmac100_match_data *match_data;
+ enum ftgmac100_mac_id mac_id;
struct resource *res;
int irq;
struct net_device *netdev;
- struct phy_device *phydev;
struct ftgmac100 *priv;
struct device_node *np;
int err = 0;
+ np = pdev->dev.of_node;
+ if (np) {
+ match_data = of_device_get_match_data(&pdev->dev);
+ if (!match_data)
+ return -EINVAL;
+ mac_id = match_data->mac_id;
+ } else {
+ mac_id = FTGMAC100_FARADAY;
+ }
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENXIO;
@@ -1852,11 +1949,9 @@ static int ftgmac100_probe(struct platform_device *pdev)
return irq;
/* setup net_device */
- netdev = alloc_etherdev(sizeof(*priv));
- if (!netdev) {
- err = -ENOMEM;
- goto err_alloc_etherdev;
- }
+ netdev = devm_alloc_etherdev(&pdev->dev, sizeof(*priv));
+ if (!netdev)
+ return -ENOMEM;
SET_NETDEV_DEV(netdev, &pdev->dev);
@@ -1870,22 +1965,22 @@ static int ftgmac100_probe(struct platform_device *pdev)
priv = netdev_priv(netdev);
priv->netdev = netdev;
priv->dev = &pdev->dev;
+ priv->mac_id = mac_id;
INIT_WORK(&priv->reset_task, ftgmac100_reset_task);
/* map io memory */
- priv->res = request_mem_region(res->start, resource_size(res),
- dev_name(&pdev->dev));
+ priv->res = devm_request_mem_region(&pdev->dev,
+ res->start, resource_size(res),
+ dev_name(&pdev->dev));
if (!priv->res) {
dev_err(&pdev->dev, "Could not reserve memory region\n");
- err = -ENOMEM;
- goto err_req_mem;
+ return -ENOMEM;
}
- priv->base = ioremap(res->start, resource_size(res));
+ priv->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
if (!priv->base) {
dev_err(&pdev->dev, "Failed to ioremap ethernet registers\n");
- err = -EIO;
- goto err_ioremap;
+ return -EIO;
}
netdev->irq = irq;
@@ -1898,12 +1993,11 @@ static int ftgmac100_probe(struct platform_device *pdev)
/* MAC address from chip or random one */
err = ftgmac100_initial_mac(priv);
if (err)
- goto err_phy_connect;
+ return err;
- np = pdev->dev.of_node;
- if (np && (of_device_is_compatible(np, "aspeed,ast2400-mac") ||
- of_device_is_compatible(np, "aspeed,ast2500-mac") ||
- of_device_is_compatible(np, "aspeed,ast2600-mac"))) {
+ if (priv->mac_id == FTGMAC100_AST2400 ||
+ priv->mac_id == FTGMAC100_AST2500 ||
+ priv->mac_id == FTGMAC100_AST2600) {
priv->rxdes0_edorr_mask = BIT(30);
priv->txdes0_edotr_mask = BIT(30);
priv->is_aspeed = true;
@@ -1912,100 +2006,37 @@ static int ftgmac100_probe(struct platform_device *pdev)
priv->txdes0_edotr_mask = BIT(15);
}
- if (np && of_get_property(np, "use-ncsi", NULL)) {
- if (!IS_ENABLED(CONFIG_NET_NCSI)) {
- dev_err(&pdev->dev, "NCSI stack not enabled\n");
- err = -EINVAL;
- goto err_phy_connect;
- }
-
- dev_info(&pdev->dev, "Using NCSI interface\n");
- priv->use_ncsi = true;
- priv->ndev = ncsi_register_dev(netdev, ftgmac100_ncsi_handler);
- if (!priv->ndev) {
- err = -EINVAL;
- goto err_phy_connect;
- }
-
- phydev = fixed_phy_register(&ncsi_phy_status, np);
- if (IS_ERR(phydev)) {
- dev_err(&pdev->dev, "failed to register fixed PHY device\n");
- err = PTR_ERR(phydev);
- goto err_phy_connect;
- }
- err = phy_connect_direct(netdev, phydev, ftgmac100_adjust_link,
- PHY_INTERFACE_MODE_RMII);
- if (err) {
- dev_err(&pdev->dev, "Connecting PHY failed\n");
- goto err_phy_connect;
- }
- } else if (np && (of_phy_is_fixed_link(np) ||
- of_get_property(np, "phy-handle", NULL))) {
- struct phy_device *phy;
-
- /* Support "mdio"/"phy" child nodes for ast2400/2500 with
- * an embedded MDIO controller. Automatically scan the DTS for
- * available PHYs and register them.
- */
- if (of_get_property(np, "phy-handle", NULL) &&
- (of_device_is_compatible(np, "aspeed,ast2400-mac") ||
- of_device_is_compatible(np, "aspeed,ast2500-mac"))) {
- err = ftgmac100_setup_mdio(netdev);
- if (err)
- goto err_setup_mdio;
- }
-
- phy = of_phy_get_and_connect(priv->netdev, np,
- &ftgmac100_adjust_link);
- if (!phy) {
- dev_err(&pdev->dev, "Failed to connect to phy\n");
- err = -EINVAL;
- goto err_phy_connect;
- }
-
- /* Indicate that we support PAUSE frames (see comment in
- * Documentation/networking/phy.rst)
- */
- phy_support_asym_pause(phy);
-
- /* Display what we found */
- phy_attached_info(phy);
- } else if (np && !ftgmac100_has_child_node(np, "mdio")) {
- /* Support legacy ASPEED devicetree descriptions that decribe a
- * MAC with an embedded MDIO controller but have no "mdio"
- * child node. Automatically scan the MDIO bus for available
- * PHYs.
- */
- priv->use_ncsi = false;
+ if (priv->mac_id == FTGMAC100_FARADAY ||
+ priv->mac_id == FTGMAC100_AST2400 ||
+ priv->mac_id == FTGMAC100_AST2500) {
err = ftgmac100_setup_mdio(netdev);
if (err)
- goto err_setup_mdio;
-
- err = ftgmac100_mii_probe(netdev);
- if (err) {
- dev_err(priv->dev, "MII probe failed!\n");
- goto err_ncsi_dev;
- }
+ return err;
+ }
+ if (np) {
+ err = ftgmac100_probe_dt(netdev, pdev, priv, np);
+ if (err)
+ goto err;
}
priv->rst = devm_reset_control_get_optional_exclusive(priv->dev, NULL);
if (IS_ERR(priv->rst)) {
err = PTR_ERR(priv->rst);
- goto err_phy_connect;
+ goto err;
}
if (priv->is_aspeed) {
err = ftgmac100_setup_clk(priv);
if (err)
- goto err_phy_connect;
-
- /* Disable ast2600 problematic HW arbitration */
- if (of_device_is_compatible(np, "aspeed,ast2600-mac"))
- iowrite32(FTGMAC100_TM_DEFAULT,
- priv->base + FTGMAC100_OFFSET_TM);
+ goto err;
}
+ /* Disable ast2600 problematic HW arbitration */
+ if (priv->mac_id == FTGMAC100_AST2600)
+ iowrite32(FTGMAC100_TM_DEFAULT,
+ priv->base + FTGMAC100_OFFSET_TM);
+
/* Default ring sizes */
priv->rx_q_entries = priv->new_rx_q_entries = DEF_RX_QUEUE_ENTRIES;
priv->tx_q_entries = priv->new_tx_q_entries = DEF_TX_QUEUE_ENTRIES;
@@ -2019,11 +2050,11 @@ static int ftgmac100_probe(struct platform_device *pdev)
netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER;
/* AST2400 doesn't have working HW checksum generation */
- if (np && (of_device_is_compatible(np, "aspeed,ast2400-mac")))
+ if (priv->mac_id == FTGMAC100_AST2400)
netdev->hw_features &= ~NETIF_F_HW_CSUM;
/* AST2600 tx checksum with NCSI is broken */
- if (priv->use_ncsi && of_device_is_compatible(np, "aspeed,ast2600-mac"))
+ if (priv->use_ncsi && priv->mac_id == FTGMAC100_AST2600)
netdev->hw_features &= ~NETIF_F_HW_CSUM;
if (np && of_get_property(np, "no-hw-checksum", NULL))
@@ -2034,29 +2065,17 @@ static int ftgmac100_probe(struct platform_device *pdev)
err = register_netdev(netdev);
if (err) {
dev_err(&pdev->dev, "Failed to register netdev\n");
- goto err_register_netdev;
+ goto err;
}
netdev_info(netdev, "irq %d, mapped at %p\n", netdev->irq, priv->base);
return 0;
-err_register_netdev:
- clk_disable_unprepare(priv->rclk);
- clk_disable_unprepare(priv->clk);
-err_phy_connect:
+err:
ftgmac100_phy_disconnect(netdev);
-err_ncsi_dev:
if (priv->ndev)
ncsi_unregister_dev(priv->ndev);
- ftgmac100_destroy_mdio(netdev);
-err_setup_mdio:
- iounmap(priv->base);
-err_ioremap:
- release_resource(priv->res);
-err_req_mem:
- free_netdev(netdev);
-err_alloc_etherdev:
return err;
}
@@ -2072,26 +2091,39 @@ static void ftgmac100_remove(struct platform_device *pdev)
ncsi_unregister_dev(priv->ndev);
unregister_netdev(netdev);
- clk_disable_unprepare(priv->rclk);
- clk_disable_unprepare(priv->clk);
-
/* There's a small chance the reset task will have been re-queued,
* during stop, make sure it's gone before we free the structure.
*/
cancel_work_sync(&priv->reset_task);
ftgmac100_phy_disconnect(netdev);
- ftgmac100_destroy_mdio(netdev);
+}
- iounmap(priv->base);
- release_resource(priv->res);
+static const struct ftgmac100_match_data ftgmac100_match_data_ast2400 = {
+ .mac_id = FTGMAC100_AST2400
+};
- netif_napi_del(&priv->napi);
- free_netdev(netdev);
-}
+static const struct ftgmac100_match_data ftgmac100_match_data_ast2500 = {
+ .mac_id = FTGMAC100_AST2500
+};
+
+static const struct ftgmac100_match_data ftgmac100_match_data_ast2600 = {
+ .mac_id = FTGMAC100_AST2600
+};
+
+static const struct ftgmac100_match_data ftgmac100_match_data_faraday = {
+ .mac_id = FTGMAC100_FARADAY
+};
static const struct of_device_id ftgmac100_of_match[] = {
- { .compatible = "faraday,ftgmac100" },
+ { .compatible = "aspeed,ast2400-mac",
+ .data = &ftgmac100_match_data_ast2400},
+ { .compatible = "aspeed,ast2500-mac",
+ .data = &ftgmac100_match_data_ast2500 },
+ { .compatible = "aspeed,ast2600-mac",
+ .data = &ftgmac100_match_data_ast2600 },
+ { .compatible = "faraday,ftgmac100",
+ .data = &ftgmac100_match_data_faraday },
{ }
};
MODULE_DEVICE_TABLE(of, ftgmac100_of_match);