diff options
Diffstat (limited to 'drivers/net/ethernet/atheros/ag71xx.c')
-rw-r--r-- | drivers/net/ethernet/atheros/ag71xx.c | 179 |
1 files changed, 68 insertions, 111 deletions
diff --git a/drivers/net/ethernet/atheros/ag71xx.c b/drivers/net/ethernet/atheros/ag71xx.c index a38be924cdaa..9586b6894f7e 100644 --- a/drivers/net/ethernet/atheros/ag71xx.c +++ b/drivers/net/ethernet/atheros/ag71xx.c @@ -149,11 +149,11 @@ #define FIFO_CFG4_MC BIT(8) /* Multicast Packet */ #define FIFO_CFG4_BC BIT(9) /* Broadcast Packet */ #define FIFO_CFG4_DR BIT(10) /* Dribble */ -#define FIFO_CFG4_LE BIT(11) /* Long Event */ -#define FIFO_CFG4_CF BIT(12) /* Control Frame */ -#define FIFO_CFG4_PF BIT(13) /* Pause Frame */ -#define FIFO_CFG4_UO BIT(14) /* Unsupported Opcode */ -#define FIFO_CFG4_VT BIT(15) /* VLAN tag detected */ +#define FIFO_CFG4_CF BIT(11) /* Control Frame */ +#define FIFO_CFG4_PF BIT(12) /* Pause Frame */ +#define FIFO_CFG4_UO BIT(13) /* Unsupported Opcode */ +#define FIFO_CFG4_VT BIT(14) /* VLAN tag detected */ +#define FIFO_CFG4_LE BIT(15) /* Long Event */ #define FIFO_CFG4_FT BIT(16) /* Frame Truncated */ #define FIFO_CFG4_UC BIT(17) /* Unicast Packet */ #define FIFO_CFG4_INIT (FIFO_CFG4_DE | FIFO_CFG4_DV | FIFO_CFG4_FC | \ @@ -168,28 +168,28 @@ #define FIFO_CFG5_DV BIT(1) /* RX_DV Event */ #define FIFO_CFG5_FC BIT(2) /* False Carrier */ #define FIFO_CFG5_CE BIT(3) /* Code Error */ -#define FIFO_CFG5_LM BIT(4) /* Length Mismatch */ -#define FIFO_CFG5_LO BIT(5) /* Length Out of Range */ -#define FIFO_CFG5_OK BIT(6) /* Packet is OK */ -#define FIFO_CFG5_MC BIT(7) /* Multicast Packet */ -#define FIFO_CFG5_BC BIT(8) /* Broadcast Packet */ -#define FIFO_CFG5_DR BIT(9) /* Dribble */ -#define FIFO_CFG5_CF BIT(10) /* Control Frame */ -#define FIFO_CFG5_PF BIT(11) /* Pause Frame */ -#define FIFO_CFG5_UO BIT(12) /* Unsupported Opcode */ -#define FIFO_CFG5_VT BIT(13) /* VLAN tag detected */ -#define FIFO_CFG5_LE BIT(14) /* Long Event */ -#define FIFO_CFG5_FT BIT(15) /* Frame Truncated */ -#define FIFO_CFG5_16 BIT(16) /* unknown */ -#define FIFO_CFG5_17 BIT(17) /* unknown */ +#define FIFO_CFG5_CR BIT(4) /* CRC error */ +#define FIFO_CFG5_LM BIT(5) /* Length Mismatch */ +#define FIFO_CFG5_LO BIT(6) /* Length Out of Range */ +#define FIFO_CFG5_OK BIT(7) /* Packet is OK */ +#define FIFO_CFG5_MC BIT(8) /* Multicast Packet */ +#define FIFO_CFG5_BC BIT(9) /* Broadcast Packet */ +#define FIFO_CFG5_DR BIT(10) /* Dribble */ +#define FIFO_CFG5_CF BIT(11) /* Control Frame */ +#define FIFO_CFG5_PF BIT(12) /* Pause Frame */ +#define FIFO_CFG5_UO BIT(13) /* Unsupported Opcode */ +#define FIFO_CFG5_VT BIT(14) /* VLAN tag detected */ +#define FIFO_CFG5_LE BIT(15) /* Long Event */ +#define FIFO_CFG5_FT BIT(16) /* Frame Truncated */ +#define FIFO_CFG5_UC BIT(17) /* Unicast Packet */ #define FIFO_CFG5_SF BIT(18) /* Short Frame */ #define FIFO_CFG5_BM BIT(19) /* Byte Mode */ #define FIFO_CFG5_INIT (FIFO_CFG5_DE | FIFO_CFG5_DV | FIFO_CFG5_FC | \ - FIFO_CFG5_CE | FIFO_CFG5_LO | FIFO_CFG5_OK | \ - FIFO_CFG5_MC | FIFO_CFG5_BC | FIFO_CFG5_DR | \ - FIFO_CFG5_CF | FIFO_CFG5_PF | FIFO_CFG5_VT | \ - FIFO_CFG5_LE | FIFO_CFG5_FT | FIFO_CFG5_16 | \ - FIFO_CFG5_17 | FIFO_CFG5_SF) + FIFO_CFG5_CE | FIFO_CFG5_LM | FIFO_CFG5_LO | \ + FIFO_CFG5_OK | FIFO_CFG5_MC | FIFO_CFG5_BC | \ + FIFO_CFG5_DR | FIFO_CFG5_CF | FIFO_CFG5_UO | \ + FIFO_CFG5_VT | FIFO_CFG5_LE | FIFO_CFG5_FT | \ + FIFO_CFG5_UC | FIFO_CFG5_SF) #define AG71XX_REG_TX_CTRL 0x0180 #define TX_CTRL_TXE BIT(0) /* Tx Enable */ @@ -379,10 +379,7 @@ struct ag71xx { u32 fifodata[3]; int mac_idx; - struct reset_control *mdio_reset; - struct mii_bus *mii_bus; struct clk *clk_mdio; - struct clk *clk_eth; }; static int ag71xx_desc_empty(struct ag71xx_desc *desc) @@ -447,6 +444,13 @@ static void ag71xx_int_disable(struct ag71xx *ag, u32 ints) ag71xx_cb(ag, AG71XX_REG_INT_ENABLE, ints); } +static int ag71xx_do_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd) +{ + struct ag71xx *ag = netdev_priv(ndev); + + return phylink_mii_ioctl(ag->phylink, ifr, cmd); +} + static void ag71xx_get_drvinfo(struct net_device *ndev, struct ethtool_drvinfo *info) { @@ -504,8 +508,7 @@ static void ag71xx_ethtool_get_strings(struct net_device *netdev, u32 sset, switch (sset) { case ETH_SS_STATS: for (i = 0; i < ARRAY_SIZE(ag71xx_statistics); i++) - memcpy(data + i * ETH_GSTRING_LEN, - ag71xx_statistics[i].name, ETH_GSTRING_LEN); + ethtool_puts(&data, ag71xx_statistics[i].name); break; case ETH_SS_TEST: net_selftest_get_strings(data); @@ -685,36 +688,27 @@ static int ag71xx_mdio_probe(struct ag71xx *ag) { struct device *dev = &ag->pdev->dev; struct net_device *ndev = ag->ndev; + struct reset_control *mdio_reset; static struct mii_bus *mii_bus; struct device_node *np, *mnp; int err; np = dev->of_node; - ag->mii_bus = NULL; - ag->clk_mdio = devm_clk_get(dev, "mdio"); + ag->clk_mdio = devm_clk_get_enabled(dev, "mdio"); if (IS_ERR(ag->clk_mdio)) { netif_err(ag, probe, ndev, "Failed to get mdio clk.\n"); return PTR_ERR(ag->clk_mdio); } - err = clk_prepare_enable(ag->clk_mdio); - if (err) { - netif_err(ag, probe, ndev, "Failed to enable mdio clk.\n"); - return err; - } - mii_bus = devm_mdiobus_alloc(dev); - if (!mii_bus) { - err = -ENOMEM; - goto mdio_err_put_clk; - } + if (!mii_bus) + return -ENOMEM; - ag->mdio_reset = of_reset_control_get_exclusive(np, "mdio"); - if (IS_ERR(ag->mdio_reset)) { + mdio_reset = devm_reset_control_get_exclusive(dev, "mdio"); + if (IS_ERR(mdio_reset)) { netif_err(ag, probe, ndev, "Failed to get reset mdio.\n"); - err = PTR_ERR(ag->mdio_reset); - goto mdio_err_put_clk; + return PTR_ERR(mdio_reset); } mii_bus->name = "ag71xx_mdio"; @@ -725,33 +719,18 @@ static int ag71xx_mdio_probe(struct ag71xx *ag) mii_bus->parent = dev; snprintf(mii_bus->id, MII_BUS_ID_SIZE, "%s.%d", np->name, ag->mac_idx); - if (!IS_ERR(ag->mdio_reset)) { - reset_control_assert(ag->mdio_reset); - msleep(100); - reset_control_deassert(ag->mdio_reset); - msleep(200); - } + reset_control_assert(mdio_reset); + msleep(100); + reset_control_deassert(mdio_reset); + msleep(200); mnp = of_get_child_by_name(np, "mdio"); - err = of_mdiobus_register(mii_bus, mnp); + err = devm_of_mdiobus_register(dev, mii_bus, mnp); of_node_put(mnp); if (err) - goto mdio_err_put_clk; - - ag->mii_bus = mii_bus; + return err; return 0; - -mdio_err_put_clk: - clk_disable_unprepare(ag->clk_mdio); - return err; -} - -static void ag71xx_mdio_remove(struct ag71xx *ag) -{ - if (ag->mii_bus) - mdiobus_unregister(ag->mii_bus); - clk_disable_unprepare(ag->clk_mdio); } static void ag71xx_hw_stop(struct ag71xx *ag) @@ -1637,7 +1616,6 @@ static int ag71xx_rx_packets(struct ag71xx *ag, int limit) unsigned int i = ring->curr & ring_mask; struct ag71xx_desc *desc = ag71xx_ring_desc(ring, i); int pktlen; - int err = 0; if (ag71xx_desc_empty(desc)) break; @@ -1660,6 +1638,7 @@ static int ag71xx_rx_packets(struct ag71xx *ag, int limit) skb = napi_build_skb(ring->buf[i].rx.rx_buf, ag71xx_buffer_size(ag)); if (!skb) { + ndev->stats.rx_errors++; skb_free_frag(ring->buf[i].rx.rx_buf); goto next; } @@ -1667,14 +1646,9 @@ static int ag71xx_rx_packets(struct ag71xx *ag, int limit) skb_reserve(skb, offset); skb_put(skb, pktlen); - if (err) { - ndev->stats.rx_dropped++; - kfree_skb(skb); - } else { - skb->dev = ndev; - skb->ip_summed = CHECKSUM_NONE; - list_add_tail(&skb->list, &rx_list); - } + skb->dev = ndev; + skb->ip_summed = CHECKSUM_NONE; + list_add_tail(&skb->list, &rx_list); next: ring->buf[i].rx.rx_buf = NULL; @@ -1799,7 +1773,7 @@ static const struct net_device_ops ag71xx_netdev_ops = { .ndo_open = ag71xx_open, .ndo_stop = ag71xx_stop, .ndo_start_xmit = ag71xx_hard_start_xmit, - .ndo_eth_ioctl = phy_do_ioctl, + .ndo_eth_ioctl = ag71xx_do_ioctl, .ndo_tx_timeout = ag71xx_tx_timeout, .ndo_change_mtu = ag71xx_change_mtu, .ndo_set_mac_address = eth_mac_addr, @@ -1816,6 +1790,7 @@ static int ag71xx_probe(struct platform_device *pdev) const struct ag71xx_dcfg *dcfg; struct net_device *ndev; struct resource *res; + struct clk *clk_eth; int tx_size, err, i; struct ag71xx *ag; @@ -1846,10 +1821,10 @@ static int ag71xx_probe(struct platform_device *pdev) return -EINVAL; } - ag->clk_eth = devm_clk_get(&pdev->dev, "eth"); - if (IS_ERR(ag->clk_eth)) { + clk_eth = devm_clk_get_enabled(&pdev->dev, "eth"); + if (IS_ERR(clk_eth)) { netif_err(ag, probe, ndev, "Failed to get eth clk.\n"); - return PTR_ERR(ag->clk_eth); + return PTR_ERR(clk_eth); } SET_NETDEV_DEV(ndev, &pdev->dev); @@ -1870,6 +1845,12 @@ static int ag71xx_probe(struct platform_device *pdev) if (!ag->mac_base) return -ENOMEM; + /* ensure that HW is in manual polling mode before interrupts are + * activated. Otherwise ag71xx_interrupt might call napi_schedule + * before it is initialized by netif_napi_add. + */ + ag71xx_int_disable(ag, AG71XX_INT_POLL); + ndev->irq = platform_get_irq(pdev, 0); err = devm_request_irq(&pdev->dev, ndev->irq, ag71xx_interrupt, 0x0, dev_name(&pdev->dev), ndev); @@ -1912,6 +1893,8 @@ static int ag71xx_probe(struct platform_device *pdev) ag->stop_desc->next = (u32)ag->stop_desc_dma; err = of_get_ethdev_address(np, ndev); + if (err == -EPROBE_DEFER) + return err; if (err) { netif_err(ag, probe, ndev, "invalid MAC address, using random address\n"); eth_hw_addr_random(ndev); @@ -1926,33 +1909,27 @@ static int ag71xx_probe(struct platform_device *pdev) netif_napi_add_weight(ndev, &ag->napi, ag71xx_poll, AG71XX_NAPI_WEIGHT); - err = clk_prepare_enable(ag->clk_eth); - if (err) { - netif_err(ag, probe, ndev, "Failed to enable eth clk.\n"); - return err; - } - ag71xx_wr(ag, AG71XX_REG_MAC_CFG1, 0); ag71xx_hw_init(ag); err = ag71xx_mdio_probe(ag); if (err) - goto err_put_clk; + return err; platform_set_drvdata(pdev, ndev); err = ag71xx_phylink_setup(ag); if (err) { netif_err(ag, probe, ndev, "failed to setup phylink (%d)\n", err); - goto err_mdio_remove; + return err; } - err = register_netdev(ndev); + err = devm_register_netdev(&pdev->dev, ndev); if (err) { netif_err(ag, probe, ndev, "unable to register net device\n"); platform_set_drvdata(pdev, NULL); - goto err_mdio_remove; + return err; } netif_info(ag, probe, ndev, "Atheros AG71xx at 0x%08lx, irq %d, mode:%s\n", @@ -1960,27 +1937,6 @@ static int ag71xx_probe(struct platform_device *pdev) phy_modes(ag->phy_if_mode)); return 0; - -err_mdio_remove: - ag71xx_mdio_remove(ag); -err_put_clk: - clk_disable_unprepare(ag->clk_eth); - return err; -} - -static void ag71xx_remove(struct platform_device *pdev) -{ - struct net_device *ndev = platform_get_drvdata(pdev); - struct ag71xx *ag; - - if (!ndev) - return; - - ag = netdev_priv(ndev); - unregister_netdev(ndev); - ag71xx_mdio_remove(ag); - clk_disable_unprepare(ag->clk_eth); - platform_set_drvdata(pdev, NULL); } static const u32 ar71xx_fifo_ar7100[] = { @@ -2064,10 +2020,10 @@ static const struct of_device_id ag71xx_match[] = { { .compatible = "qca,qca9560-eth", .data = &ag71xx_dcfg_qca9550 }, {} }; +MODULE_DEVICE_TABLE(of, ag71xx_match); static struct platform_driver ag71xx_driver = { .probe = ag71xx_probe, - .remove_new = ag71xx_remove, .driver = { .name = "ag71xx", .of_match_table = ag71xx_match, @@ -2075,4 +2031,5 @@ static struct platform_driver ag71xx_driver = { }; module_platform_driver(ag71xx_driver); +MODULE_DESCRIPTION("Atheros AR71xx built-in ethernet mac driver"); MODULE_LICENSE("GPL v2"); |