]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/net/stmmac/stmmac_main.c
Merge tag 'v2.6.38' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[mv-sheeva.git] / drivers / net / stmmac / stmmac_main.c
index 2114837809e76707e69f41cde38b0a0856ee745a..0e5f03135b50abd053712ca6ddaf1e14df76a241 100644 (file)
@@ -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
@@ -1552,8 +1560,10 @@ static int stmmac_mac_device_setup(struct net_device *dev)
 
        priv->hw = device;
 
-       if (device_can_wakeup(priv->device))
+       if (device_can_wakeup(priv->device)) {
                priv->wolopts = WAKE_MAGIC; /* Magic Frame as default */
+               enable_irq_wake(dev->irq);
+       }
 
        return 0;
 }
@@ -1598,7 +1608,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 +1644,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 +1658,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 +1682,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 +1706,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 +1729,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 +1784,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 +1800,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 +1856,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 +1867,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,
+       },
 };
 
 /**