diff options
Diffstat (limited to 'drivers/net/ethernet/atheros/ag71xx.c')
-rw-r--r-- | drivers/net/ethernet/atheros/ag71xx.c | 212 |
1 files changed, 80 insertions, 132 deletions
diff --git a/drivers/net/ethernet/atheros/ag71xx.c b/drivers/net/ethernet/atheros/ag71xx.c index 0f2f400b5bc4..3d4c3d8698e2 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) @@ -1619,8 +1598,8 @@ static int ag71xx_rx_packets(struct ag71xx *ag, int limit) int ring_mask, ring_size, done = 0; unsigned int pktlen_mask, offset; struct ag71xx_ring *ring; - struct list_head rx_list; struct sk_buff *skb; + LIST_HEAD(rx_list); ring = &ag->rx_ring; pktlen_mask = ag->dcfg->desc_pktlen_mask; @@ -1631,13 +1610,10 @@ static int ag71xx_rx_packets(struct ag71xx *ag, int limit) netif_dbg(ag, rx_status, ndev, "rx packets, limit=%d, curr=%u, dirty=%u\n", limit, ring->curr, ring->dirty); - INIT_LIST_HEAD(&rx_list); - while (done < 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 +1636,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 +1644,10 @@ 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; + skb->protocol = eth_type_trans(skb, ndev); + list_add_tail(&skb->list, &rx_list); next: ring->buf[i].rx.rx_buf = NULL; @@ -1685,8 +1658,6 @@ next: ag71xx_ring_rx_refill(ag); - list_for_each_entry(skb, &rx_list, list) - skb->protocol = eth_type_trans(skb, ndev); netif_receive_skb_list(&rx_list); netif_dbg(ag, rx_status, ndev, "rx finish, curr=%u, dirty=%u, done=%d\n", @@ -1788,7 +1759,7 @@ static int ag71xx_change_mtu(struct net_device *ndev, int new_mtu) { struct ag71xx *ag = netdev_priv(ndev); - ndev->mtu = new_mtu; + WRITE_ONCE(ndev->mtu, new_mtu); ag71xx_wr(ag, AG71XX_REG_MAC_MFL, ag71xx_max_frame_len(ndev->mtu)); @@ -1799,7 +1770,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 +1787,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,11 +1818,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)) { - netif_err(ag, probe, ndev, "Failed to get eth clk.\n"); - return PTR_ERR(ag->clk_eth); - } + clk_eth = devm_clk_get_enabled(&pdev->dev, "eth"); + if (IS_ERR(clk_eth)) + return dev_err_probe(&pdev->dev, PTR_ERR(clk_eth), + "Failed to get eth clk."); SET_NETDEV_DEV(ndev, &pdev->dev); @@ -1861,14 +1832,19 @@ static int ag71xx_probe(struct platform_device *pdev) memcpy(ag->fifodata, dcfg->fifodata, sizeof(ag->fifodata)); ag->mac_reset = devm_reset_control_get(&pdev->dev, "mac"); - if (IS_ERR(ag->mac_reset)) { - netif_err(ag, probe, ndev, "missing mac reset\n"); - return PTR_ERR(ag->mac_reset); - } + if (IS_ERR(ag->mac_reset)) + return dev_err_probe(&pdev->dev, PTR_ERR(ag->mac_reset), + "missing mac reset"); - ag->mac_base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); - if (!ag->mac_base) - return -ENOMEM; + ag->mac_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(ag->mac_base)) + return PTR_ERR(ag->mac_base); + + /* 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, @@ -1912,6 +1888,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 +1904,23 @@ 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; - - platform_set_drvdata(pdev, ndev); + return err; err = ag71xx_phylink_setup(ag); - if (err) { - netif_err(ag, probe, ndev, "failed to setup phylink (%d)\n", err); - goto err_mdio_remove; - } + if (err) + return dev_err_probe(&pdev->dev, err, + "failed to setup phylink"); - 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 +1928,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 +2011,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 +2022,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"); |