]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/net/ethernet/freescale/fec_main.c
net: fec: use dev_get_platdata()
[karo-tx-linux.git] / drivers / net / ethernet / freescale / fec_main.c
index d3ad5ea711d316e1455cbe7d8eab61ecad8cb3d4..46019ba6e23a9161e950b62d2079757087a963de 100644 (file)
@@ -69,7 +69,6 @@ static void set_multicast_list(struct net_device *ndev);
 #endif
 
 #define DRIVER_NAME    "fec"
-#define FEC_NAPI_WEIGHT        64
 
 /* Pause frame feild and FIFO threshold */
 #define FEC_ENET_FCE   (1 << 5)
@@ -93,6 +92,20 @@ static void set_multicast_list(struct net_device *ndev);
 #define FEC_QUIRK_HAS_CSUM             (1 << 5)
 /* Controller has hardware vlan support */
 #define FEC_QUIRK_HAS_VLAN             (1 << 6)
+/* ENET IP errata ERR006358
+ *
+ * If the ready bit in the transmit buffer descriptor (TxBD[R]) is previously
+ * detected as not set during a prior frame transmission, then the
+ * ENET_TDAR[TDAR] bit is cleared at a later time, even if additional TxBDs
+ * were added to the ring and the ENET_TDAR[TDAR] bit is set. This results in
+ * If the ready bit in the transmit buffer descriptor (TxBD[R]) is previously
+ * detected as not set during a prior frame transmission, then the
+ * ENET_TDAR[TDAR] bit is cleared at a later time, even if additional TxBDs
+ * were added to the ring and the ENET_TDAR[TDAR] bit is set. This results in
+ * frames not being transmitted until there is a 0-to-1 transition on
+ * ENET_TDAR[TDAR].
+ */
+#define FEC_QUIRK_ERR006358            (1 << 7)
 
 static struct platform_device_id fec_devtype[] = {
        {
@@ -112,7 +125,7 @@ static struct platform_device_id fec_devtype[] = {
                .name = "imx6q-fec",
                .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |
                                FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM |
-                               FEC_QUIRK_HAS_VLAN,
+                               FEC_QUIRK_HAS_VLAN | FEC_QUIRK_ERR006358,
        }, {
                .name = "mvf600-fec",
                .driver_data = FEC_QUIRK_ENET_MAC,
@@ -275,16 +288,11 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
        struct fec_enet_private *fep = netdev_priv(ndev);
        const struct platform_device_id *id_entry =
                                platform_get_device_id(fep->pdev);
-       struct bufdesc *bdp;
+       struct bufdesc *bdp, *bdp_pre;
        void *bufaddr;
        unsigned short  status;
        unsigned int index;
 
-       if (!fep->link) {
-               /* Link is down or auto-negotiation is in progress. */
-               return NETDEV_TX_BUSY;
-       }
-
        /* Fill in a Tx ring entry */
        bdp = fep->cur_tx;
 
@@ -370,6 +378,15 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
                                ebdp->cbd_esc |= BD_ENET_TX_PINS;
                }
        }
+
+       bdp_pre = fec_enet_get_prevdesc(bdp, fep->bufdesc_ex);
+       if ((id_entry->driver_data & FEC_QUIRK_ERR006358) &&
+           !(bdp_pre->cbd_sc & BD_ENET_TX_READY)) {
+               fep->delay_work.trig_tx = true;
+               schedule_delayed_work(&(fep->delay_work.delay_work),
+                                       msecs_to_jiffies(1));
+       }
+
        /* If this was the last BD in the ring, start at the beginning again. */
        if (status & BD_ENET_TX_WRAP)
                bdp = fep->tx_bd_base;
@@ -689,6 +706,11 @@ static void fec_enet_work(struct work_struct *work)
                fec_restart(fep->netdev, fep->full_duplex);
                netif_wake_queue(fep->netdev);
        }
+
+       if (fep->delay_work.trig_tx) {
+               fep->delay_work.trig_tx = false;
+               writel(0, fep->hwp + FEC_X_DES_ACTIVE);
+       }
 }
 
 static void
@@ -1037,7 +1059,7 @@ static int fec_enet_rx_napi(struct napi_struct *napi, int budget)
 static void fec_get_mac(struct net_device *ndev)
 {
        struct fec_enet_private *fep = netdev_priv(ndev);
-       struct fec_platform_data *pdata = fep->pdev->dev.platform_data;
+       struct fec_platform_data *pdata = dev_get_platdata(&fep->pdev->dev);
        unsigned char *iap, tmpaddr[ETH_ALEN];
 
        /*
@@ -1958,7 +1980,7 @@ static int fec_enet_init(struct net_device *ndev)
        ndev->ethtool_ops = &fec_enet_ethtool_ops;
 
        writel(FEC_RX_DISABLED_IMASK, fep->hwp + FEC_IMASK);
-       netif_napi_add(ndev, &fep->napi, fec_enet_rx_napi, FEC_NAPI_WEIGHT);
+       netif_napi_add(ndev, &fep->napi, fec_enet_rx_napi, NAPI_POLL_WEIGHT);
 
        if (id_entry->driver_data & FEC_QUIRK_HAS_VLAN) {
                /* enable hw VLAN support */
@@ -2033,10 +2055,6 @@ fec_probe(struct platform_device *pdev)
        if (of_id)
                pdev->id_entry = of_id->data;
 
-       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!r)
-               return -ENXIO;
-
        /* Init network device */
        ndev = alloc_etherdev(sizeof(struct fec_enet_private));
        if (!ndev)
@@ -2054,6 +2072,7 @@ fec_probe(struct platform_device *pdev)
                fep->pause_flag |= FEC_PAUSE_FLAG_AUTONEG;
 #endif
 
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        fep->hwp = devm_ioremap_resource(&pdev->dev, r);
        if (IS_ERR(fep->hwp)) {
                ret = PTR_ERR(fep->hwp);
@@ -2069,7 +2088,7 @@ fec_probe(struct platform_device *pdev)
 
        ret = of_get_phy_mode(pdev->dev.of_node);
        if (ret < 0) {
-               pdata = pdev->dev.platform_data;
+               pdata = dev_get_platdata(&pdev->dev);
                if (pdata)
                        fep->phy_interface = pdata->phy;
                else
@@ -2103,10 +2122,25 @@ fec_probe(struct platform_device *pdev)
                fep->bufdesc_ex = 0;
        }
 
-       clk_prepare_enable(fep->clk_ahb);
-       clk_prepare_enable(fep->clk_ipg);
-       clk_prepare_enable(fep->clk_enet_out);
-       clk_prepare_enable(fep->clk_ptp);
+       ret = clk_prepare_enable(fep->clk_ahb);
+       if (ret)
+               goto failed_clk;
+
+       ret = clk_prepare_enable(fep->clk_ipg);
+       if (ret)
+               goto failed_clk_ipg;
+
+       if (fep->clk_enet_out) {
+               ret = clk_prepare_enable(fep->clk_enet_out);
+               if (ret)
+                       goto failed_clk_enet_out;
+       }
+
+       if (fep->clk_ptp) {
+               ret = clk_prepare_enable(fep->clk_ptp);
+               if (ret)
+                       goto failed_clk_ptp;
+       }
 
        fep->reg_phy = devm_regulator_get(&pdev->dev, "phy");
        if (!IS_ERR(fep->reg_phy)) {
@@ -2137,14 +2171,10 @@ fec_probe(struct platform_device *pdev)
                        ret = irq;
                        goto failed_irq;
                }
-               ret = request_irq(irq, fec_enet_interrupt, IRQF_DISABLED, pdev->name, ndev);
-               if (ret) {
-                       while (--i >= 0) {
-                               irq = platform_get_irq(pdev, i);
-                               free_irq(irq, ndev);
-                       }
+               ret = devm_request_irq(&pdev->dev, irq, fec_enet_interrupt,
+                                      IRQF_DISABLED, pdev->name, ndev);
+               if (ret)
                        goto failed_irq;
-               }
        }
 
        ret = fec_enet_mii_init(pdev);
@@ -2168,19 +2198,19 @@ failed_register:
        fec_enet_mii_remove(fep);
 failed_mii_init:
 failed_irq:
-       for (i = 0; i < FEC_IRQ_NUM; i++) {
-               irq = platform_get_irq(pdev, i);
-               if (irq > 0)
-                       free_irq(irq, ndev);
-       }
 failed_init:
        if (fep->reg_phy)
                regulator_disable(fep->reg_phy);
 failed_regulator:
-       clk_disable_unprepare(fep->clk_ahb);
+       if (fep->clk_ptp)
+               clk_disable_unprepare(fep->clk_ptp);
+failed_clk_ptp:
+       if (fep->clk_enet_out)
+               clk_disable_unprepare(fep->clk_enet_out);
+failed_clk_enet_out:
        clk_disable_unprepare(fep->clk_ipg);
-       clk_disable_unprepare(fep->clk_enet_out);
-       clk_disable_unprepare(fep->clk_ptp);
+failed_clk_ipg:
+       clk_disable_unprepare(fep->clk_ahb);
 failed_clk:
 failed_ioremap:
        free_netdev(ndev);
@@ -2193,25 +2223,21 @@ fec_drv_remove(struct platform_device *pdev)
 {
        struct net_device *ndev = platform_get_drvdata(pdev);
        struct fec_enet_private *fep = netdev_priv(ndev);
-       int i;
 
        cancel_delayed_work_sync(&(fep->delay_work.delay_work));
        unregister_netdev(ndev);
        fec_enet_mii_remove(fep);
        del_timer_sync(&fep->time_keep);
-       for (i = 0; i < FEC_IRQ_NUM; i++) {
-               int irq = platform_get_irq(pdev, i);
-               if (irq > 0)
-                       free_irq(irq, ndev);
-       }
        if (fep->reg_phy)
                regulator_disable(fep->reg_phy);
-       clk_disable_unprepare(fep->clk_ptp);
+       if (fep->clk_ptp)
+               clk_disable_unprepare(fep->clk_ptp);
        if (fep->ptp_clock)
                ptp_clock_unregister(fep->ptp_clock);
-       clk_disable_unprepare(fep->clk_enet_out);
-       clk_disable_unprepare(fep->clk_ahb);
+       if (fep->clk_enet_out)
+               clk_disable_unprepare(fep->clk_enet_out);
        clk_disable_unprepare(fep->clk_ipg);
+       clk_disable_unprepare(fep->clk_ahb);
        free_netdev(ndev);
 
        return 0;
@@ -2228,9 +2254,12 @@ fec_suspend(struct device *dev)
                fec_stop(ndev);
                netif_device_detach(ndev);
        }
-       clk_disable_unprepare(fep->clk_enet_out);
-       clk_disable_unprepare(fep->clk_ahb);
+       if (fep->clk_ptp)
+               clk_disable_unprepare(fep->clk_ptp);
+       if (fep->clk_enet_out)
+               clk_disable_unprepare(fep->clk_enet_out);
        clk_disable_unprepare(fep->clk_ipg);
+       clk_disable_unprepare(fep->clk_ahb);
 
        if (fep->reg_phy)
                regulator_disable(fep->reg_phy);
@@ -2251,15 +2280,44 @@ fec_resume(struct device *dev)
                        return ret;
        }
 
-       clk_prepare_enable(fep->clk_enet_out);
-       clk_prepare_enable(fep->clk_ahb);
-       clk_prepare_enable(fep->clk_ipg);
+       ret = clk_prepare_enable(fep->clk_ahb);
+       if (ret)
+               goto failed_clk_ahb;
+
+       ret = clk_prepare_enable(fep->clk_ipg);
+       if (ret)
+               goto failed_clk_ipg;
+
+       if (fep->clk_enet_out) {
+               ret = clk_prepare_enable(fep->clk_enet_out);
+               if (ret)
+                       goto failed_clk_enet_out;
+       }
+
+       if (fep->clk_ptp) {
+               ret = clk_prepare_enable(fep->clk_ptp);
+               if (ret)
+                       goto failed_clk_ptp;
+       }
+
        if (netif_running(ndev)) {
                fec_restart(ndev, fep->full_duplex);
                netif_device_attach(ndev);
        }
 
        return 0;
+
+failed_clk_ptp:
+       if (fep->clk_enet_out)
+               clk_disable_unprepare(fep->clk_enet_out);
+failed_clk_enet_out:
+       clk_disable_unprepare(fep->clk_ipg);
+failed_clk_ipg:
+       clk_disable_unprepare(fep->clk_ahb);
+failed_clk_ahb:
+       if (fep->reg_phy)
+               regulator_disable(fep->reg_phy);
+       return ret;
 }
 #endif /* CONFIG_PM_SLEEP */
 
@@ -2279,4 +2337,5 @@ static struct platform_driver fec_driver = {
 
 module_platform_driver(fec_driver);
 
+MODULE_ALIAS("platform:"DRIVER_NAME);
 MODULE_LICENSE("GPL");