From cd2d6d33e2c5be653d10cdc8fcd7dcf0be28de50 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Thu, 15 Jan 2015 14:45:09 -0800 Subject: [PATCH 1/6] net: davinci_emac: Fix hangs with interrupts On davinci_emac, we have pulse interrupts. This means that we need to clear the EOI bits when disabling interrupts as otherwise the interrupts keep happening. And we also need to not clear the EOI bits again when enabling the interrupts as otherwise we will get tons of: unexpected IRQ trap at vector 00 These errors almost certainly mean that the omap-intc.c is signaling a spurious interrupt with the reserved irq 127 as we've seen earlier on omap3. Let's fix the issue by clearing the EOI bits when disabling the interrupts. Let's also keep the comment for "Rx Threshold and Misc interrupts are not enabled" for both enable and disable so people are aware of this when potentially adding more support. Note that eventually we should handle the RX and TX interrupts separately like cpsw is now doing. However, so far I have not seen any issues with this based on my testing, so it seems to behave a little different compared to the cpsw that had a similar issue. Cc: Brian Hutchinson Reviewed-by: Felipe Balbi Signed-off-by: Tony Lindgren Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/davinci_emac.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/ti/davinci_emac.c b/drivers/net/ethernet/ti/davinci_emac.c index ea712512c7d1..383ed527dad9 100644 --- a/drivers/net/ethernet/ti/davinci_emac.c +++ b/drivers/net/ethernet/ti/davinci_emac.c @@ -922,6 +922,16 @@ static void emac_int_disable(struct emac_priv *priv) if (priv->int_disable) priv->int_disable(); + /* NOTE: Rx Threshold and Misc interrupts are not enabled */ + + /* ack rxen only then a new pulse will be generated */ + emac_write(EMAC_DM646X_MACEOIVECTOR, + EMAC_DM646X_MAC_EOI_C0_RXEN); + + /* ack txen- only then a new pulse will be generated */ + emac_write(EMAC_DM646X_MACEOIVECTOR, + EMAC_DM646X_MAC_EOI_C0_TXEN); + local_irq_restore(flags); } else { @@ -951,15 +961,6 @@ static void emac_int_enable(struct emac_priv *priv) * register */ /* NOTE: Rx Threshold and Misc interrupts are not enabled */ - - /* ack rxen only then a new pulse will be generated */ - emac_write(EMAC_DM646X_MACEOIVECTOR, - EMAC_DM646X_MAC_EOI_C0_RXEN); - - /* ack txen- only then a new pulse will be generated */ - emac_write(EMAC_DM646X_MACEOIVECTOR, - EMAC_DM646X_MAC_EOI_C0_TXEN); - } else { /* Set DM644x control registers for interrupt control */ emac_ctrl_write(EMAC_CTRL_EWCTL, 0x1); From b5133e7a988b2cf8e1cd2b23231f36aff35ceffc Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Thu, 15 Jan 2015 14:45:10 -0800 Subject: [PATCH 2/6] net: davinci_emac: Fix runtime pm calls for davinci_emac Commit 3ba97381343b ("net: ethernet: davinci_emac: add pm_runtime support") added support for runtime PM, but it causes issues on omap3 related devices that actually gate the clocks: Unhandled fault: external abort on non-linefetch (0x1008) ... [] (emac_dev_getnetstats) from [] (dev_get_stats+0x78/0xc8) [] (dev_get_stats) from [] (rtnl_fill_ifinfo+0x3b8/0x938) [] (rtnl_fill_ifinfo) from [] (rtmsg_ifinfo+0x68/0xd8) [] (rtmsg_ifinfo) from [] (register_netdevice+0x3a0/0x4ec) [] (register_netdevice) from [] (register_netdev+0x14/0x24) [] (register_netdev) from [] (davinci_emac_probe+0x408/0x5c8) [] (davinci_emac_probe) from [] (platform_drv_probe+0x48/0xa4) Let's fix it by moving the pm_runtime_get() call earlier, and also add it to the emac_dev_getnetstats(). Also note that we want to use pm_runtime_get_sync() as we don't want to have deferred_resume happen. And let's also check the return value for pm_runtime_get_sync() as noted by Felipe Balbi . Cc: Brian Hutchinson Acked-by: Mark A. Greer Reviewed-by: Felipe Balbi Signed-off-by: Tony Lindgren Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/davinci_emac.c | 33 ++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/ti/davinci_emac.c b/drivers/net/ethernet/ti/davinci_emac.c index 383ed527dad9..5df339e9f67c 100644 --- a/drivers/net/ethernet/ti/davinci_emac.c +++ b/drivers/net/ethernet/ti/davinci_emac.c @@ -1538,7 +1538,13 @@ static int emac_dev_open(struct net_device *ndev) int i = 0; struct emac_priv *priv = netdev_priv(ndev); - pm_runtime_get(&priv->pdev->dev); + ret = pm_runtime_get_sync(&priv->pdev->dev); + if (ret < 0) { + pm_runtime_put_noidle(&priv->pdev->dev); + dev_err(&priv->pdev->dev, "%s: failed to get_sync(%d)\n", + __func__, ret); + return ret; + } netif_carrier_off(ndev); for (cnt = 0; cnt < ETH_ALEN; cnt++) @@ -1725,6 +1731,15 @@ static struct net_device_stats *emac_dev_getnetstats(struct net_device *ndev) struct emac_priv *priv = netdev_priv(ndev); u32 mac_control; u32 stats_clear_mask; + int err; + + err = pm_runtime_get_sync(&priv->pdev->dev); + if (err < 0) { + pm_runtime_put_noidle(&priv->pdev->dev); + dev_err(&priv->pdev->dev, "%s: failed to get_sync(%d)\n", + __func__, err); + return &ndev->stats; + } /* update emac hardware stats and reset the registers*/ @@ -1767,6 +1782,8 @@ static struct net_device_stats *emac_dev_getnetstats(struct net_device *ndev) ndev->stats.tx_fifo_errors += emac_read(EMAC_TXUNDERRUN); emac_write(EMAC_TXUNDERRUN, stats_clear_mask); + pm_runtime_put(&priv->pdev->dev); + return &ndev->stats; } @@ -1981,12 +1998,22 @@ static int davinci_emac_probe(struct platform_device *pdev) ndev->ethtool_ops = ðtool_ops; netif_napi_add(ndev, &priv->napi, emac_poll, EMAC_POLL_WEIGHT); + pm_runtime_enable(&pdev->dev); + rc = pm_runtime_get_sync(&pdev->dev); + if (rc < 0) { + pm_runtime_put_noidle(&pdev->dev); + dev_err(&pdev->dev, "%s: failed to get_sync(%d)\n", + __func__, rc); + goto no_cpdma_chan; + } + /* register the network device */ SET_NETDEV_DEV(ndev, &pdev->dev); rc = register_netdev(ndev); if (rc) { dev_err(&pdev->dev, "error in register_netdev\n"); rc = -ENODEV; + pm_runtime_put(&pdev->dev); goto no_cpdma_chan; } @@ -1996,9 +2023,7 @@ static int davinci_emac_probe(struct platform_device *pdev) "(regs: %p, irq: %d)\n", (void *)priv->emac_base_phys, ndev->irq); } - - pm_runtime_enable(&pdev->dev); - pm_runtime_resume(&pdev->dev); + pm_runtime_put(&pdev->dev); return 0; From 0f5372731dc13655da9edd282437a290eaa7c258 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Thu, 15 Jan 2015 14:45:11 -0800 Subject: [PATCH 3/6] net: davinci_emac: Free clock after checking the frequency We only use clk_get() to get the frequency, the rest is done by the runtime PM calls. Let's free the clock too. Cc: Brian Hutchinson Cc: Felipe Balbi Signed-off-by: Tony Lindgren Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/davinci_emac.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/ti/davinci_emac.c b/drivers/net/ethernet/ti/davinci_emac.c index 5df339e9f67c..59fdcdd43ed1 100644 --- a/drivers/net/ethernet/ti/davinci_emac.c +++ b/drivers/net/ethernet/ti/davinci_emac.c @@ -1894,6 +1894,7 @@ static int davinci_emac_probe(struct platform_device *pdev) return -EBUSY; } emac_bus_frequency = clk_get_rate(emac_clk); + devm_clk_put(&pdev->dev, emac_clk); /* TODO: Probe PHY here if possible */ From 1d82ffa6ba0f645d449c1b0489bb698a9a7301ea Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Thu, 15 Jan 2015 14:45:12 -0800 Subject: [PATCH 4/6] net: davinci_emac: Fix incomplete code for getting the phy from device tree Looks like the phy_id is never set up beyond getting the phandle. Note that we can remove the ifdef for phy_node as there is a stub for of_phy_connec() if CONFIG_OF is not set. Cc: Brian Hutchinson Cc: Felipe Balbi Signed-off-by: Tony Lindgren Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/davinci_emac.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/ti/davinci_emac.c b/drivers/net/ethernet/ti/davinci_emac.c index 59fdcdd43ed1..e44c8d84a3c6 100644 --- a/drivers/net/ethernet/ti/davinci_emac.c +++ b/drivers/net/ethernet/ti/davinci_emac.c @@ -62,6 +62,7 @@ #include #include #include +#include #include #include @@ -343,9 +344,7 @@ struct emac_priv { u32 multicast_hash_cnt[EMAC_NUM_MULTICAST_BITS]; u32 rx_addr_type; const char *phy_id; -#ifdef CONFIG_OF struct device_node *phy_node; -#endif struct phy_device *phydev; spinlock_t lock; /*platform specific members*/ @@ -1603,8 +1602,20 @@ static int emac_dev_open(struct net_device *ndev) cpdma_ctlr_start(priv->dma); priv->phydev = NULL; + + if (priv->phy_node) { + priv->phydev = of_phy_connect(ndev, priv->phy_node, + &emac_adjust_link, 0, 0); + if (!priv->phydev) { + dev_err(emac_dev, "could not connect to phy %s\n", + priv->phy_node->full_name); + ret = -ENODEV; + goto err; + } + } + /* use the first phy on the bus if pdata did not give us a phy id */ - if (!priv->phy_id) { + if (!priv->phydev && !priv->phy_id) { struct device *phy; phy = bus_find_device(&mdio_bus_type, NULL, NULL, @@ -1613,7 +1624,7 @@ static int emac_dev_open(struct net_device *ndev) priv->phy_id = dev_name(phy); } - if (priv->phy_id && *priv->phy_id) { + if (!priv->phydev && priv->phy_id && *priv->phy_id) { priv->phydev = phy_connect(ndev, priv->phy_id, &emac_adjust_link, PHY_INTERFACE_MODE_MII); @@ -1634,7 +1645,9 @@ static int emac_dev_open(struct net_device *ndev) "(mii_bus:phy_addr=%s, id=%x)\n", priv->phydev->drv->name, dev_name(&priv->phydev->dev), priv->phydev->phy_id); - } else { + } + + if (!priv->phydev) { /* No PHY , fix the link, speed and duplex settings */ dev_notice(emac_dev, "no phy, defaulting to 100/full\n"); priv->link = 1; From a1594321a9bc55ad44e02b27773cb0ed05837531 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Thu, 15 Jan 2015 14:45:13 -0800 Subject: [PATCH 5/6] net: davinci_emac: Fix ioremap for devices with MDIO within the EMAC address space Some devices like dm816x have the MDIO registers within the first EMAC instance address space. Let's fix the issue by allowing to pass an optional second IO range for the EMAC control register area. Cc: Brian Hutchinson Cc: Felipe Balbi Signed-off-by: Tony Lindgren Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/davinci_emac.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/ti/davinci_emac.c b/drivers/net/ethernet/ti/davinci_emac.c index e44c8d84a3c6..1e5ea81504f0 100644 --- a/drivers/net/ethernet/ti/davinci_emac.c +++ b/drivers/net/ethernet/ti/davinci_emac.c @@ -1890,7 +1890,7 @@ davinci_emac_of_get_pdata(struct platform_device *pdev, struct emac_priv *priv) static int davinci_emac_probe(struct platform_device *pdev) { int rc = 0; - struct resource *res; + struct resource *res, *res_ctrl; struct net_device *ndev; struct emac_priv *priv; unsigned long hw_ram_addr; @@ -1949,11 +1949,20 @@ static int davinci_emac_probe(struct platform_device *pdev) rc = PTR_ERR(priv->remap_addr); goto no_pdata; } + + res_ctrl = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (res_ctrl) { + priv->ctrl_base = + devm_ioremap_resource(&pdev->dev, res_ctrl); + if (IS_ERR(priv->ctrl_base)) + goto no_pdata; + } else { + priv->ctrl_base = priv->remap_addr + pdata->ctrl_mod_reg_offset; + } + priv->emac_base = priv->remap_addr + pdata->ctrl_reg_offset; ndev->base_addr = (unsigned long)priv->remap_addr; - priv->ctrl_base = priv->remap_addr + pdata->ctrl_mod_reg_offset; - hw_ram_addr = pdata->hw_ram_addr; if (!hw_ram_addr) hw_ram_addr = (u32 __force)res->start + pdata->ctrl_ram_offset; From de3900833ee635d5658415fea9c8c4e13507d777 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Thu, 15 Jan 2015 14:45:14 -0800 Subject: [PATCH 6/6] net: davinci_emac: Add support for emac on dm816x On dm816x we have two emac controllers with separate memory areas. Cc: Brian Hutchinson Cc: Felipe Balbi Signed-off-by: Tony Lindgren Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/net/davinci_emac.txt | 3 ++- drivers/net/ethernet/ti/davinci_emac.c | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/net/davinci_emac.txt b/Documentation/devicetree/bindings/net/davinci_emac.txt index 032808843f90..24c5cdaba8d2 100644 --- a/Documentation/devicetree/bindings/net/davinci_emac.txt +++ b/Documentation/devicetree/bindings/net/davinci_emac.txt @@ -4,7 +4,8 @@ This file provides information, what the device node for the davinci_emac interface contains. Required properties: -- compatible: "ti,davinci-dm6467-emac" or "ti,am3517-emac" +- compatible: "ti,davinci-dm6467-emac", "ti,am3517-emac" or + "ti,dm816-emac" - reg: Offset and length of the register set for the device - ti,davinci-ctrl-reg-offset: offset to control register - ti,davinci-ctrl-mod-reg-offset: offset to control module register diff --git a/drivers/net/ethernet/ti/davinci_emac.c b/drivers/net/ethernet/ti/davinci_emac.c index 1e5ea81504f0..5fae4354722c 100644 --- a/drivers/net/ethernet/ti/davinci_emac.c +++ b/drivers/net/ethernet/ti/davinci_emac.c @@ -2120,9 +2120,14 @@ static const struct emac_platform_data am3517_emac_data = { .hw_ram_addr = 0x01e20000, }; +static const struct emac_platform_data dm816_emac_data = { + .version = EMAC_VERSION_2, +}; + static const struct of_device_id davinci_emac_of_match[] = { {.compatible = "ti,davinci-dm6467-emac", }, {.compatible = "ti,am3517-emac", .data = &am3517_emac_data, }, + {.compatible = "ti,dm816-emac", .data = &dm816_emac_data, }, {}, }; MODULE_DEVICE_TABLE(of, davinci_emac_of_match);