diff options
Diffstat (limited to 'drivers/net/ethernet/arc/emac_main.c')
-rw-r--r-- | drivers/net/ethernet/arc/emac_main.c | 182 |
1 files changed, 85 insertions, 97 deletions
diff --git a/drivers/net/ethernet/arc/emac_main.c b/drivers/net/ethernet/arc/emac_main.c index fe5cfeace6e3..abe1eabc0171 100644 --- a/drivers/net/ethernet/arc/emac_main.c +++ b/drivers/net/ethernet/arc/emac_main.c @@ -26,8 +26,17 @@ #include "emac.h" -#define DRV_NAME "arc_emac" -#define DRV_VERSION "1.0" + +/** + * arc_emac_tx_avail - Return the number of available slots in the tx ring. + * @priv: Pointer to ARC EMAC private data structure. + * + * returns: the number of slots available for transmission in tx the ring. + */ +static inline int arc_emac_tx_avail(struct arc_emac_priv *priv) +{ + return (priv->txbd_dirty + TX_BD_NUM - priv->txbd_curr - 1) % TX_BD_NUM; +} /** * arc_emac_adjust_link - Adjust the PHY link duplex. @@ -50,6 +59,8 @@ static void arc_emac_adjust_link(struct net_device *ndev) if (priv->speed != phy_dev->speed) { priv->speed = phy_dev->speed; state_changed = 1; + if (priv->set_mac_speed) + priv->set_mac_speed(priv, priv->speed); } if (priv->duplex != phy_dev->duplex) { @@ -120,8 +131,10 @@ static int arc_emac_set_settings(struct net_device *ndev, static void arc_emac_get_drvinfo(struct net_device *ndev, struct ethtool_drvinfo *info) { - strlcpy(info->driver, DRV_NAME, sizeof(info->driver)); - strlcpy(info->version, DRV_VERSION, sizeof(info->version)); + struct arc_emac_priv *priv = netdev_priv(ndev); + + strlcpy(info->driver, priv->drv_name, sizeof(info->driver)); + strlcpy(info->version, priv->drv_version, sizeof(info->version)); } static const struct ethtool_ops arc_emac_ethtool_ops = { @@ -180,10 +193,15 @@ static void arc_emac_tx_clean(struct net_device *ndev) txbd->info = 0; *txbd_dirty = (*txbd_dirty + 1) % TX_BD_NUM; - - if (netif_queue_stopped(ndev)) - netif_wake_queue(ndev); } + + /* Ensure that txbd_dirty is visible to tx() before checking + * for queue stopped. + */ + smp_mb(); + + if (netif_queue_stopped(ndev) && arc_emac_tx_avail(priv)) + netif_wake_queue(ndev); } /** @@ -298,7 +316,7 @@ static int arc_emac_poll(struct napi_struct *napi, int budget) work_done = arc_emac_rx(ndev, budget); if (work_done < budget) { napi_complete(napi); - arc_reg_or(priv, R_ENABLE, RXINT_MASK); + arc_reg_or(priv, R_ENABLE, RXINT_MASK | TXINT_MASK); } return work_done; @@ -327,9 +345,9 @@ static irqreturn_t arc_emac_intr(int irq, void *dev_instance) /* Reset all flags except "MDIO complete" */ arc_reg_set(priv, R_STATUS, status); - if (status & RXINT_MASK) { + if (status & (RXINT_MASK | TXINT_MASK)) { if (likely(napi_schedule_prep(&priv->napi))) { - arc_reg_clr(priv, R_ENABLE, RXINT_MASK); + arc_reg_clr(priv, R_ENABLE, RXINT_MASK | TXINT_MASK); __napi_schedule(&priv->napi); } } @@ -440,7 +458,7 @@ static int arc_emac_open(struct net_device *ndev) arc_reg_set(priv, R_TX_RING, (unsigned int)priv->txbd_dma); /* Enable interrupts */ - arc_reg_set(priv, R_ENABLE, RXINT_MASK | ERR_MASK); + arc_reg_set(priv, R_ENABLE, RXINT_MASK | TXINT_MASK | ERR_MASK); /* Set CONTROL */ arc_reg_set(priv, R_CTRL, @@ -511,7 +529,7 @@ static int arc_emac_stop(struct net_device *ndev) netif_stop_queue(ndev); /* Disable interrupts */ - arc_reg_clr(priv, R_ENABLE, RXINT_MASK | ERR_MASK); + arc_reg_clr(priv, R_ENABLE, RXINT_MASK | TXINT_MASK | ERR_MASK); /* Disable EMAC */ arc_reg_clr(priv, R_CTRL, EN_MASK); @@ -574,11 +592,9 @@ static int arc_emac_tx(struct sk_buff *skb, struct net_device *ndev) len = max_t(unsigned int, ETH_ZLEN, skb->len); - /* EMAC still holds this buffer in its possession. - * CPU must not modify this buffer descriptor - */ - if (unlikely((le32_to_cpu(*info) & OWN_MASK) == FOR_EMAC)) { + if (unlikely(!arc_emac_tx_avail(priv))) { netif_stop_queue(ndev); + netdev_err(ndev, "BUG! Tx Ring full when queue awake!\n"); return NETDEV_TX_BUSY; } @@ -607,12 +623,19 @@ static int arc_emac_tx(struct sk_buff *skb, struct net_device *ndev) /* Increment index to point to the next BD */ *txbd_curr = (*txbd_curr + 1) % TX_BD_NUM; - /* Get "info" of the next BD */ - info = &priv->txbd[*txbd_curr].info; + /* Ensure that tx_clean() sees the new txbd_curr before + * checking the queue status. This prevents an unneeded wake + * of the queue in tx_clean(). + */ + smp_mb(); - /* Check if if Tx BD ring is full - next BD is still owned by EMAC */ - if (unlikely((le32_to_cpu(*info) & OWN_MASK) == FOR_EMAC)) + if (!arc_emac_tx_avail(priv)) { netif_stop_queue(ndev); + /* Refresh tx_dirty */ + smp_mb(); + if (arc_emac_tx_avail(priv)) + netif_start_queue(ndev); + } arc_reg_set(priv, R_STATUS, TXPL_MASK); @@ -671,46 +694,38 @@ static const struct net_device_ops arc_emac_netdev_ops = { #endif }; -static int arc_emac_probe(struct platform_device *pdev) +int arc_emac_probe(struct net_device *ndev, int interface) { + struct device *dev = ndev->dev.parent; struct resource res_regs; struct device_node *phy_node; struct arc_emac_priv *priv; - struct net_device *ndev; const char *mac_addr; unsigned int id, clock_frequency, irq; int err; - if (!pdev->dev.of_node) - return -ENODEV; /* Get PHY from device tree */ - phy_node = of_parse_phandle(pdev->dev.of_node, "phy", 0); + phy_node = of_parse_phandle(dev->of_node, "phy", 0); if (!phy_node) { - dev_err(&pdev->dev, "failed to retrieve phy description from device tree\n"); + dev_err(dev, "failed to retrieve phy description from device tree\n"); return -ENODEV; } /* Get EMAC registers base address from device tree */ - err = of_address_to_resource(pdev->dev.of_node, 0, &res_regs); + err = of_address_to_resource(dev->of_node, 0, &res_regs); if (err) { - dev_err(&pdev->dev, "failed to retrieve registers base from device tree\n"); + dev_err(dev, "failed to retrieve registers base from device tree\n"); return -ENODEV; } /* Get IRQ from device tree */ - irq = irq_of_parse_and_map(pdev->dev.of_node, 0); + irq = irq_of_parse_and_map(dev->of_node, 0); if (!irq) { - dev_err(&pdev->dev, "failed to retrieve <irq> value from device tree\n"); + dev_err(dev, "failed to retrieve <irq> value from device tree\n"); return -ENODEV; } - ndev = alloc_etherdev(sizeof(struct arc_emac_priv)); - if (!ndev) - return -ENOMEM; - - platform_set_drvdata(pdev, ndev); - SET_NETDEV_DEV(ndev, &pdev->dev); ndev->netdev_ops = &arc_emac_netdev_ops; ndev->ethtool_ops = &arc_emac_ethtool_ops; @@ -719,60 +734,57 @@ static int arc_emac_probe(struct platform_device *pdev) ndev->flags &= ~IFF_MULTICAST; priv = netdev_priv(ndev); - priv->dev = &pdev->dev; + priv->dev = dev; - priv->regs = devm_ioremap_resource(&pdev->dev, &res_regs); + priv->regs = devm_ioremap_resource(dev, &res_regs); if (IS_ERR(priv->regs)) { - err = PTR_ERR(priv->regs); - goto out_netdev; + return PTR_ERR(priv->regs); } - dev_dbg(&pdev->dev, "Registers base address is 0x%p\n", priv->regs); + dev_dbg(dev, "Registers base address is 0x%p\n", priv->regs); - priv->clk = of_clk_get(pdev->dev.of_node, 0); - if (IS_ERR(priv->clk)) { - /* Get CPU clock frequency from device tree */ - if (of_property_read_u32(pdev->dev.of_node, "clock-frequency", - &clock_frequency)) { - dev_err(&pdev->dev, "failed to retrieve <clock-frequency> from device tree\n"); - err = -EINVAL; - goto out_netdev; - } - } else { + if (priv->clk) { err = clk_prepare_enable(priv->clk); if (err) { - dev_err(&pdev->dev, "failed to enable clock\n"); - goto out_clkget; + dev_err(dev, "failed to enable clock\n"); + return err; } clock_frequency = clk_get_rate(priv->clk); + } else { + /* Get CPU clock frequency from device tree */ + if (of_property_read_u32(dev->of_node, "clock-frequency", + &clock_frequency)) { + dev_err(dev, "failed to retrieve <clock-frequency> from device tree\n"); + return -EINVAL; + } } id = arc_reg_get(priv, R_ID); /* Check for EMAC revision 5 or 7, magic number */ if (!(id == 0x0005fd02 || id == 0x0007fd02)) { - dev_err(&pdev->dev, "ARC EMAC not detected, id=0x%x\n", id); + dev_err(dev, "ARC EMAC not detected, id=0x%x\n", id); err = -ENODEV; goto out_clken; } - dev_info(&pdev->dev, "ARC EMAC detected with id: 0x%x\n", id); + dev_info(dev, "ARC EMAC detected with id: 0x%x\n", id); /* Set poll rate so that it polls every 1 ms */ arc_reg_set(priv, R_POLLRATE, clock_frequency / 1000000); ndev->irq = irq; - dev_info(&pdev->dev, "IRQ is %d\n", ndev->irq); + dev_info(dev, "IRQ is %d\n", ndev->irq); /* Register interrupt handler for device */ - err = devm_request_irq(&pdev->dev, ndev->irq, arc_emac_intr, 0, + err = devm_request_irq(dev, ndev->irq, arc_emac_intr, 0, ndev->name, ndev); if (err) { - dev_err(&pdev->dev, "could not allocate IRQ\n"); + dev_err(dev, "could not allocate IRQ\n"); goto out_clken; } /* Get MAC address from device tree */ - mac_addr = of_get_mac_address(pdev->dev.of_node); + mac_addr = of_get_mac_address(dev->of_node); if (mac_addr) memcpy(ndev->dev_addr, mac_addr, ETH_ALEN); @@ -780,14 +792,14 @@ static int arc_emac_probe(struct platform_device *pdev) eth_hw_addr_random(ndev); arc_emac_set_address_internal(ndev); - dev_info(&pdev->dev, "MAC address is now %pM\n", ndev->dev_addr); + dev_info(dev, "MAC address is now %pM\n", ndev->dev_addr); /* Do 1 allocation instead of 2 separate ones for Rx and Tx BD rings */ - priv->rxbd = dmam_alloc_coherent(&pdev->dev, RX_RING_SZ + TX_RING_SZ, + priv->rxbd = dmam_alloc_coherent(dev, RX_RING_SZ + TX_RING_SZ, &priv->rxbd_dma, GFP_KERNEL); if (!priv->rxbd) { - dev_err(&pdev->dev, "failed to allocate data buffers\n"); + dev_err(dev, "failed to allocate data buffers\n"); err = -ENOMEM; goto out_clken; } @@ -795,31 +807,31 @@ static int arc_emac_probe(struct platform_device *pdev) priv->txbd = priv->rxbd + RX_BD_NUM; priv->txbd_dma = priv->rxbd_dma + RX_RING_SZ; - dev_dbg(&pdev->dev, "EMAC Device addr: Rx Ring [0x%x], Tx Ring[%x]\n", + dev_dbg(dev, "EMAC Device addr: Rx Ring [0x%x], Tx Ring[%x]\n", (unsigned int)priv->rxbd_dma, (unsigned int)priv->txbd_dma); - err = arc_mdio_probe(pdev, priv); + err = arc_mdio_probe(priv); if (err) { - dev_err(&pdev->dev, "failed to probe MII bus\n"); + dev_err(dev, "failed to probe MII bus\n"); goto out_clken; } priv->phy_dev = of_phy_connect(ndev, phy_node, arc_emac_adjust_link, 0, - PHY_INTERFACE_MODE_MII); + interface); if (!priv->phy_dev) { - dev_err(&pdev->dev, "of_phy_connect() failed\n"); + dev_err(dev, "of_phy_connect() failed\n"); err = -ENODEV; goto out_mdio; } - dev_info(&pdev->dev, "connected to %s phy with id 0x%x\n", + dev_info(dev, "connected to %s phy with id 0x%x\n", priv->phy_dev->drv->name, priv->phy_dev->phy_id); netif_napi_add(ndev, &priv->napi, arc_emac_poll, ARC_EMAC_NAPI_WEIGHT); err = register_netdev(ndev); if (err) { - dev_err(&pdev->dev, "failed to register network device\n"); + dev_err(dev, "failed to register network device\n"); goto out_netif_api; } @@ -832,19 +844,14 @@ out_netif_api: out_mdio: arc_mdio_remove(priv); out_clken: - if (!IS_ERR(priv->clk)) + if (priv->clk) clk_disable_unprepare(priv->clk); -out_clkget: - if (!IS_ERR(priv->clk)) - clk_put(priv->clk); -out_netdev: - free_netdev(ndev); return err; } +EXPORT_SYMBOL_GPL(arc_emac_probe); -static int arc_emac_remove(struct platform_device *pdev) +int arc_emac_remove(struct net_device *ndev) { - struct net_device *ndev = platform_get_drvdata(pdev); struct arc_emac_priv *priv = netdev_priv(ndev); phy_disconnect(priv->phy_dev); @@ -855,31 +862,12 @@ static int arc_emac_remove(struct platform_device *pdev) if (!IS_ERR(priv->clk)) { clk_disable_unprepare(priv->clk); - clk_put(priv->clk); } - free_netdev(ndev); return 0; } - -static const struct of_device_id arc_emac_dt_ids[] = { - { .compatible = "snps,arc-emac" }, - { /* Sentinel */ } -}; -MODULE_DEVICE_TABLE(of, arc_emac_dt_ids); - -static struct platform_driver arc_emac_driver = { - .probe = arc_emac_probe, - .remove = arc_emac_remove, - .driver = { - .name = DRV_NAME, - .owner = THIS_MODULE, - .of_match_table = arc_emac_dt_ids, - }, -}; - -module_platform_driver(arc_emac_driver); +EXPORT_SYMBOL_GPL(arc_emac_remove); MODULE_AUTHOR("Alexey Brodkin <abrodkin@synopsys.com>"); MODULE_DESCRIPTION("ARC EMAC driver"); |