diff options
Diffstat (limited to 'drivers/net/stmmac/stmmac_main.c')
-rw-r--r-- | drivers/net/stmmac/stmmac_main.c | 267 |
1 files changed, 144 insertions, 123 deletions
diff --git a/drivers/net/stmmac/stmmac_main.c b/drivers/net/stmmac/stmmac_main.c index 2114837809e..34a0af3837f 100644 --- a/drivers/net/stmmac/stmmac_main.c +++ b/drivers/net/stmmac/stmmac_main.c @@ -186,6 +186,18 @@ static inline u32 stmmac_tx_avail(struct stmmac_priv *priv) return priv->dirty_tx + priv->dma_tx_size - priv->cur_tx - 1; } +/* On some ST platforms, some HW system configuraton registers have to be + * set according to the link speed negotiated. + */ +static inline void stmmac_hw_fix_mac_speed(struct stmmac_priv *priv) +{ + struct phy_device *phydev = priv->phydev; + + if (likely(priv->plat->fix_mac_speed)) + priv->plat->fix_mac_speed(priv->plat->bsp_priv, + phydev->speed); +} + /** * stmmac_adjust_link * @dev: net device structure @@ -228,15 +240,13 @@ static void stmmac_adjust_link(struct net_device *dev) new_state = 1; switch (phydev->speed) { case 1000: - if (likely(priv->is_gmac)) + if (likely(priv->plat->has_gmac)) ctrl &= ~priv->hw->link.port; - if (likely(priv->fix_mac_speed)) - priv->fix_mac_speed(priv->bsp_priv, - phydev->speed); + stmmac_hw_fix_mac_speed(priv); break; case 100: case 10: - if (priv->is_gmac) { + if (priv->plat->has_gmac) { ctrl |= priv->hw->link.port; if (phydev->speed == SPEED_100) { ctrl |= priv->hw->link.speed; @@ -246,9 +256,7 @@ static void stmmac_adjust_link(struct net_device *dev) } else { ctrl &= ~priv->hw->link.port; } - if (likely(priv->fix_mac_speed)) - priv->fix_mac_speed(priv->bsp_priv, - phydev->speed); + stmmac_hw_fix_mac_speed(priv); break; default: if (netif_msg_link(priv)) @@ -305,7 +313,7 @@ static int stmmac_init_phy(struct net_device *dev) return 0; } - snprintf(bus_id, MII_BUS_ID_SIZE, "%x", priv->bus_id); + snprintf(bus_id, MII_BUS_ID_SIZE, "%x", priv->plat->bus_id); snprintf(phy_id, MII_BUS_ID_SIZE + 3, PHY_ID_FMT, bus_id, priv->phy_addr); pr_debug("stmmac_init_phy: trying to attach to %s\n", phy_id); @@ -552,7 +560,7 @@ static void free_dma_desc_resources(struct stmmac_priv *priv) */ static void stmmac_dma_operation_mode(struct stmmac_priv *priv) { - if (likely((priv->tx_coe) && (!priv->no_csum_insertion))) { + if (likely((priv->plat->tx_coe) && (!priv->no_csum_insertion))) { /* In case of GMAC, SF mode has to be enabled * to perform the TX COE. This depends on: * 1) TX COE if actually supported @@ -814,7 +822,7 @@ static int stmmac_open(struct net_device *dev) init_dma_desc_rings(dev); /* DMA initialization and SW reset */ - if (unlikely(priv->hw->dma->init(priv->ioaddr, priv->pbl, + if (unlikely(priv->hw->dma->init(priv->ioaddr, priv->plat->pbl, priv->dma_tx_phy, priv->dma_rx_phy) < 0)) { @@ -825,19 +833,17 @@ static int stmmac_open(struct net_device *dev) /* Copy the MAC addr into the HW */ priv->hw->mac->set_umac_addr(priv->ioaddr, dev->dev_addr, 0); /* If required, perform hw setup of the bus. */ - if (priv->bus_setup) - priv->bus_setup(priv->ioaddr); + if (priv->plat->bus_setup) + priv->plat->bus_setup(priv->ioaddr); /* Initialize the MAC Core */ priv->hw->mac->core_init(priv->ioaddr); priv->rx_coe = priv->hw->mac->rx_coe(priv->ioaddr); if (priv->rx_coe) pr_info("stmmac: Rx Checksum Offload Engine supported\n"); - if (priv->tx_coe) + if (priv->plat->tx_coe) pr_info("\tTX Checksum insertion supported\n"); - priv->shutdown = 0; - /* Initialise the MMC (if present) to disable all interrupts. */ writel(0xffffffff, priv->ioaddr + MMC_HIGH_INTR_MASK); writel(0xffffffff, priv->ioaddr + MMC_LOW_INTR_MASK); @@ -943,7 +949,7 @@ static int stmmac_sw_tso(struct stmmac_priv *priv, struct sk_buff *skb) skb, skb->len); segs = skb_gso_segment(skb, priv->dev->features & ~NETIF_F_TSO); - if (unlikely(IS_ERR(segs))) + if (IS_ERR(segs)) goto sw_tso_end; do { @@ -1042,7 +1048,8 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) return stmmac_sw_tso(priv, skb); if (likely((skb->ip_summed == CHECKSUM_PARTIAL))) { - if (unlikely((!priv->tx_coe) || (priv->no_csum_insertion))) + if (unlikely((!priv->plat->tx_coe) || + (priv->no_csum_insertion))) skb_checksum_help(skb); else csum_insertion = 1; @@ -1146,7 +1153,7 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv) DMA_FROM_DEVICE); (p + entry)->des2 = priv->rx_skbuff_dma[entry]; - if (unlikely(priv->is_gmac)) { + if (unlikely(priv->plat->has_gmac)) { if (bfsize >= BUF_SIZE_8KiB) (p + entry)->des3 = (p + entry)->des2 + BUF_SIZE_8KiB; @@ -1356,7 +1363,7 @@ static int stmmac_change_mtu(struct net_device *dev, int new_mtu) return -EBUSY; } - if (priv->is_gmac) + if (priv->plat->has_gmac) max_mtu = JUMBO_LEN; else max_mtu = ETH_DATA_LEN; @@ -1370,7 +1377,7 @@ static int stmmac_change_mtu(struct net_device *dev, int new_mtu) * needs to have the Tx COE disabled for oversized frames * (due to limited buffer sizes). In this case we disable * the TX csum insertionin the TDES and not use SF. */ - if ((priv->bugged_jumbo) && (priv->dev->mtu > ETH_DATA_LEN)) + if ((priv->plat->bugged_jumbo) && (priv->dev->mtu > ETH_DATA_LEN)) priv->no_csum_insertion = 1; else priv->no_csum_insertion = 0; @@ -1390,7 +1397,7 @@ static irqreturn_t stmmac_interrupt(int irq, void *dev_id) return IRQ_NONE; } - if (priv->is_gmac) + if (priv->plat->has_gmac) /* To handle GMAC own interrupts */ priv->hw->mac->host_irq_status((void __iomem *) dev->base_addr); @@ -1487,7 +1494,8 @@ static int stmmac_probe(struct net_device *dev) dev->netdev_ops = &stmmac_netdev_ops; stmmac_set_ethtool_ops(dev); - dev->features |= (NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_HIGHDMA); + dev->features |= NETIF_F_SG | NETIF_F_HIGHDMA | + NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; dev->watchdog_timeo = msecs_to_jiffies(watchdog); #ifdef STMMAC_VLAN_TAG_USED /* Both mac100 and gmac support receive VLAN tag detection */ @@ -1520,7 +1528,7 @@ static int stmmac_probe(struct net_device *dev) DBG(probe, DEBUG, "%s: Scatter/Gather: %s - HW checksums: %s\n", dev->name, (dev->features & NETIF_F_SG) ? "on" : "off", - (dev->features & NETIF_F_HW_CSUM) ? "on" : "off"); + (dev->features & NETIF_F_IP_CSUM) ? "on" : "off"); return ret; } @@ -1536,7 +1544,7 @@ static int stmmac_mac_device_setup(struct net_device *dev) struct mac_device_info *device; - if (priv->is_gmac) + if (priv->plat->has_gmac) device = dwmac1000_setup(priv->ioaddr); else device = dwmac100_setup(priv->ioaddr); @@ -1544,7 +1552,7 @@ static int stmmac_mac_device_setup(struct net_device *dev) if (!device) return -ENOMEM; - if (priv->enh_desc) { + if (priv->plat->enh_desc) { device->desc = &enh_desc_ops; pr_info("\tEnhanced descriptor structure\n"); } else @@ -1598,7 +1606,7 @@ static int stmmac_associate_phy(struct device *dev, void *data) plat_dat->bus_id); /* Check that this phy is for the MAC being initialised */ - if (priv->bus_id != plat_dat->bus_id) + if (priv->plat->bus_id != plat_dat->bus_id) return 0; /* OK, this PHY is connected to the MAC. @@ -1634,15 +1642,13 @@ static int stmmac_dvr_probe(struct platform_device *pdev) struct resource *res; void __iomem *addr = NULL; struct net_device *ndev = NULL; - struct stmmac_priv *priv; + struct stmmac_priv *priv = NULL; struct plat_stmmacenet_data *plat_dat; pr_info("STMMAC driver:\n\tplatform registration... "); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - ret = -ENODEV; - goto out; - } + if (!res) + return -ENODEV; pr_info("\tdone!\n"); if (!request_mem_region(res->start, resource_size(res), @@ -1650,22 +1656,21 @@ static int stmmac_dvr_probe(struct platform_device *pdev) pr_err("%s: ERROR: memory allocation failed" "cannot get the I/O addr 0x%x\n", __func__, (unsigned int)res->start); - ret = -EBUSY; - goto out; + return -EBUSY; } addr = ioremap(res->start, resource_size(res)); if (!addr) { pr_err("%s: ERROR: memory mapping failed\n", __func__); ret = -ENOMEM; - goto out; + goto out_release_region; } ndev = alloc_etherdev(sizeof(struct stmmac_priv)); if (!ndev) { pr_err("%s: ERROR: allocating the device\n", __func__); ret = -ENOMEM; - goto out; + goto out_unmap; } SET_NETDEV_DEV(ndev, &pdev->dev); @@ -1675,21 +1680,17 @@ static int stmmac_dvr_probe(struct platform_device *pdev) if (ndev->irq == -ENXIO) { pr_err("%s: ERROR: MAC IRQ configuration " "information not found\n", __func__); - ret = -ENODEV; - goto out; + ret = -ENXIO; + goto out_free_ndev; } priv = netdev_priv(ndev); priv->device = &(pdev->dev); priv->dev = ndev; plat_dat = pdev->dev.platform_data; - priv->bus_id = plat_dat->bus_id; - priv->pbl = plat_dat->pbl; /* TLI */ - priv->mii_clk_csr = plat_dat->clk_csr; - priv->tx_coe = plat_dat->tx_coe; - priv->bugged_jumbo = plat_dat->bugged_jumbo; - priv->is_gmac = plat_dat->has_gmac; /* GMAC is on board */ - priv->enh_desc = plat_dat->enh_desc; + + priv->plat = plat_dat; + priv->ioaddr = addr; /* PMT module is not integrated in all the MAC devices. */ @@ -1703,20 +1704,22 @@ static int stmmac_dvr_probe(struct platform_device *pdev) /* Set the I/O base addr */ ndev->base_addr = (unsigned long)addr; - /* Verify embedded resource for the platform */ - ret = stmmac_claim_resource(pdev); - if (ret < 0) - goto out; + /* Custom initialisation */ + if (priv->plat->init) { + ret = priv->plat->init(pdev); + if (unlikely(ret)) + goto out_free_ndev; + } /* MAC HW revice detection */ ret = stmmac_mac_device_setup(ndev); if (ret < 0) - goto out; + goto out_plat_exit; /* Network Device Registration */ ret = stmmac_probe(ndev); if (ret < 0) - goto out; + goto out_plat_exit; /* associate a PHY - it is provided by another platform bus */ if (!driver_for_each_device @@ -1724,31 +1727,33 @@ static int stmmac_dvr_probe(struct platform_device *pdev) stmmac_associate_phy)) { pr_err("No PHY device is associated with this MAC!\n"); ret = -ENODEV; - goto out; + goto out_unregister; } - priv->fix_mac_speed = plat_dat->fix_mac_speed; - priv->bus_setup = plat_dat->bus_setup; - priv->bsp_priv = plat_dat->bsp_priv; - pr_info("\t%s - (dev. name: %s - id: %d, IRQ #%d\n" "\tIO base addr: 0x%p)\n", ndev->name, pdev->name, pdev->id, ndev->irq, addr); /* MDIO bus Registration */ - pr_debug("\tMDIO bus (id: %d)...", priv->bus_id); + pr_debug("\tMDIO bus (id: %d)...", priv->plat->bus_id); ret = stmmac_mdio_register(ndev); if (ret < 0) - goto out; + goto out_unregister; pr_debug("registered!\n"); + return 0; -out: - if (ret < 0) { - platform_set_drvdata(pdev, NULL); - release_mem_region(res->start, resource_size(res)); - if (addr != NULL) - iounmap(addr); - } +out_unregister: + unregister_netdev(ndev); +out_plat_exit: + if (priv->plat->exit) + priv->plat->exit(pdev); +out_free_ndev: + free_netdev(ndev); + platform_set_drvdata(pdev, NULL); +out_unmap: + iounmap(addr); +out_release_region: + release_mem_region(res->start, resource_size(res)); return ret; } @@ -1777,6 +1782,9 @@ static int stmmac_dvr_remove(struct platform_device *pdev) stmmac_mdio_unregister(ndev); + if (priv->plat->exit) + priv->plat->exit(pdev); + platform_set_drvdata(pdev, NULL); unregister_netdev(ndev); @@ -1790,69 +1798,54 @@ static int stmmac_dvr_remove(struct platform_device *pdev) } #ifdef CONFIG_PM -static int stmmac_suspend(struct platform_device *pdev, pm_message_t state) +static int stmmac_suspend(struct device *dev) { - struct net_device *dev = platform_get_drvdata(pdev); - struct stmmac_priv *priv = netdev_priv(dev); + struct net_device *ndev = dev_get_drvdata(dev); + struct stmmac_priv *priv = netdev_priv(ndev); int dis_ic = 0; - if (!dev || !netif_running(dev)) + if (!ndev || !netif_running(ndev)) return 0; spin_lock(&priv->lock); - if (state.event == PM_EVENT_SUSPEND) { - netif_device_detach(dev); - netif_stop_queue(dev); - if (priv->phydev) - phy_stop(priv->phydev); + netif_device_detach(ndev); + netif_stop_queue(ndev); + if (priv->phydev) + phy_stop(priv->phydev); #ifdef CONFIG_STMMAC_TIMER - priv->tm->timer_stop(); - if (likely(priv->tm->enable)) - dis_ic = 1; + priv->tm->timer_stop(); + if (likely(priv->tm->enable)) + dis_ic = 1; #endif - napi_disable(&priv->napi); - - /* Stop TX/RX DMA */ - priv->hw->dma->stop_tx(priv->ioaddr); - priv->hw->dma->stop_rx(priv->ioaddr); - /* Clear the Rx/Tx descriptors */ - priv->hw->desc->init_rx_desc(priv->dma_rx, priv->dma_rx_size, - dis_ic); - priv->hw->desc->init_tx_desc(priv->dma_tx, priv->dma_tx_size); - - /* Enable Power down mode by programming the PMT regs */ - if (device_can_wakeup(priv->device)) - priv->hw->mac->pmt(priv->ioaddr, priv->wolopts); - else - stmmac_disable_mac(priv->ioaddr); - } else { - priv->shutdown = 1; - /* Although this can appear slightly redundant it actually - * makes fast the standby operation and guarantees the driver - * working if hibernation is on media. */ - stmmac_release(dev); - } + napi_disable(&priv->napi); + + /* Stop TX/RX DMA */ + priv->hw->dma->stop_tx(priv->ioaddr); + priv->hw->dma->stop_rx(priv->ioaddr); + /* Clear the Rx/Tx descriptors */ + priv->hw->desc->init_rx_desc(priv->dma_rx, priv->dma_rx_size, + dis_ic); + priv->hw->desc->init_tx_desc(priv->dma_tx, priv->dma_tx_size); + + /* Enable Power down mode by programming the PMT regs */ + if (device_may_wakeup(priv->device)) + priv->hw->mac->pmt(priv->ioaddr, priv->wolopts); + else + stmmac_disable_mac(priv->ioaddr); spin_unlock(&priv->lock); return 0; } -static int stmmac_resume(struct platform_device *pdev) +static int stmmac_resume(struct device *dev) { - struct net_device *dev = platform_get_drvdata(pdev); - struct stmmac_priv *priv = netdev_priv(dev); - - if (!netif_running(dev)) - return 0; + struct net_device *ndev = dev_get_drvdata(dev); + struct stmmac_priv *priv = netdev_priv(ndev); - if (priv->shutdown) { - /* Re-open the interface and re-init the MAC/DMA - and the rings (i.e. on hibernation stage) */ - stmmac_open(dev); + if (!netif_running(ndev)) return 0; - } spin_lock(&priv->lock); @@ -1861,10 +1854,10 @@ static int stmmac_resume(struct platform_device *pdev) * is received. Anyway, it's better to manually clear * this bit because it can generate problems while resuming * from another devices (e.g. serial console). */ - if (device_can_wakeup(priv->device)) + if (device_may_wakeup(priv->device)) priv->hw->mac->pmt(priv->ioaddr, 0); - netif_device_attach(dev); + netif_device_attach(ndev); /* Enable the MAC and DMA */ stmmac_enable_mac(priv->ioaddr); @@ -1872,31 +1865,59 @@ static int stmmac_resume(struct platform_device *pdev) priv->hw->dma->start_rx(priv->ioaddr); #ifdef CONFIG_STMMAC_TIMER - priv->tm->timer_start(tmrate); + if (likely(priv->tm->enable)) + priv->tm->timer_start(tmrate); #endif napi_enable(&priv->napi); if (priv->phydev) phy_start(priv->phydev); - netif_start_queue(dev); + netif_start_queue(ndev); spin_unlock(&priv->lock); return 0; } -#endif -static struct platform_driver stmmac_driver = { - .driver = { - .name = STMMAC_RESOURCE_NAME, - }, - .probe = stmmac_dvr_probe, - .remove = stmmac_dvr_remove, -#ifdef CONFIG_PM +static int stmmac_freeze(struct device *dev) +{ + struct net_device *ndev = dev_get_drvdata(dev); + + if (!ndev || !netif_running(ndev)) + return 0; + + return stmmac_release(ndev); +} + +static int stmmac_restore(struct device *dev) +{ + struct net_device *ndev = dev_get_drvdata(dev); + + if (!ndev || !netif_running(ndev)) + return 0; + + return stmmac_open(ndev); +} + +static const struct dev_pm_ops stmmac_pm_ops = { .suspend = stmmac_suspend, .resume = stmmac_resume, -#endif + .freeze = stmmac_freeze, + .thaw = stmmac_restore, + .restore = stmmac_restore, +}; +#else +static const struct dev_pm_ops stmmac_pm_ops; +#endif /* CONFIG_PM */ +static struct platform_driver stmmac_driver = { + .probe = stmmac_dvr_probe, + .remove = stmmac_dvr_remove, + .driver = { + .name = STMMAC_RESOURCE_NAME, + .owner = THIS_MODULE, + .pm = &stmmac_pm_ops, + }, }; /** |