]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/net/ethernet/freescale/fec.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid
[karo-tx-linux.git] / drivers / net / ethernet / freescale / fec.c
index f52ba338d2c7c0bedca1d1d1e684c129acbd0ed5..29d82cf1528e237b874b0cbbb51a37d6ce0d254e 100644 (file)
@@ -67,6 +67,7 @@
 #endif
 
 #define DRIVER_NAME    "fec"
+#define FEC_NAPI_WEIGHT        64
 
 /* Pause frame feild and FIFO threshold */
 #define FEC_ENET_FCE   (1 << 5)
@@ -168,6 +169,7 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");
 #define FEC_ENET_EBERR ((uint)0x00400000)      /* SDMA bus error */
 
 #define FEC_DEFAULT_IMASK (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII)
+#define FEC_RX_DISABLED_IMASK (FEC_DEFAULT_IMASK & (~FEC_ENET_RXF))
 
 /* The FEC stores dest/src/type, data, and checksum for receive packets.
  */
@@ -656,8 +658,8 @@ fec_enet_tx(struct net_device *ndev)
  * not been given to the system, we just set the empty indicator,
  * effectively tossing the packet.
  */
-static void
-fec_enet_rx(struct net_device *ndev)
+static int
+fec_enet_rx(struct net_device *ndev, int budget)
 {
        struct fec_enet_private *fep = netdev_priv(ndev);
        const struct platform_device_id *id_entry =
@@ -667,13 +669,12 @@ fec_enet_rx(struct net_device *ndev)
        struct  sk_buff *skb;
        ushort  pkt_len;
        __u8 *data;
+       int     pkt_received = 0;
 
 #ifdef CONFIG_M532x
        flush_cache_all();
 #endif
 
-       spin_lock(&fep->hw_lock);
-
        /* First, grab all of the stats for the incoming packet.
         * These get messed up if we get called due to a busy condition.
         */
@@ -681,6 +682,10 @@ fec_enet_rx(struct net_device *ndev)
 
        while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) {
 
+               if (pkt_received >= budget)
+                       break;
+               pkt_received++;
+
                /* Since we have allocated space to hold a complete frame,
                 * the last indicator should be set.
                 */
@@ -762,7 +767,7 @@ fec_enet_rx(struct net_device *ndev)
                        }
 
                        if (!skb_defer_rx_timestamp(skb))
-                               netif_rx(skb);
+                               napi_gro_receive(&fep->napi, skb);
                }
 
                bdp->cbd_bufaddr = dma_map_single(&fep->pdev->dev, data,
@@ -796,7 +801,7 @@ rx_processing_done:
        }
        fep->cur_rx = bdp;
 
-       spin_unlock(&fep->hw_lock);
+       return pkt_received;
 }
 
 static irqreturn_t
@@ -813,7 +818,13 @@ fec_enet_interrupt(int irq, void *dev_id)
 
                if (int_events & FEC_ENET_RXF) {
                        ret = IRQ_HANDLED;
-                       fec_enet_rx(ndev);
+
+                       /* Disable the RX interrupt */
+                       if (napi_schedule_prep(&fep->napi)) {
+                               writel(FEC_RX_DISABLED_IMASK,
+                                       fep->hwp + FEC_IMASK);
+                               __napi_schedule(&fep->napi);
+                       }
                }
 
                /* Transmit OK, or non-fatal error. Update the buffer
@@ -834,7 +845,18 @@ fec_enet_interrupt(int irq, void *dev_id)
        return ret;
 }
 
+static int fec_enet_rx_napi(struct napi_struct *napi, int budget)
+{
+       struct net_device *ndev = napi->dev;
+       int pkts = fec_enet_rx(ndev, budget);
+       struct fec_enet_private *fep = netdev_priv(ndev);
 
+       if (pkts < budget) {
+               napi_complete(napi);
+               writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
+       }
+       return pkts;
+}
 
 /* ------------------------------------------------------------------------- */
 static void fec_get_mac(struct net_device *ndev)
@@ -1392,6 +1414,8 @@ fec_enet_open(struct net_device *ndev)
        struct fec_enet_private *fep = netdev_priv(ndev);
        int ret;
 
+       napi_enable(&fep->napi);
+
        /* I should reset the ring buffers here, but I don't yet know
         * a simple way to do that.
         */
@@ -1604,6 +1628,9 @@ static int fec_enet_init(struct net_device *ndev)
        ndev->netdev_ops = &fec_netdev_ops;
        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);
+
        /* Initialize the receive buffer descriptors. */
        bdp = fep->rx_bd_base;
        for (i = 0; i < RX_RING_SIZE; i++) {
@@ -1662,10 +1689,13 @@ static void fec_reset_phy(struct platform_device *pdev)
                msec = 1;
 
        phy_reset = of_get_named_gpio(np, "phy-reset-gpios", 0);
+       if (!gpio_is_valid(phy_reset))
+               return;
+
        err = devm_gpio_request_one(&pdev->dev, phy_reset,
                                    GPIOF_OUT_INIT_LOW, "phy-reset");
        if (err) {
-               pr_debug("FEC: failed to get gpio phy-reset: %d\n", err);
+               dev_err(&pdev->dev, "failed to get phy-reset-gpios: %d\n", err);
                return;
        }
        msleep(msec);
@@ -1813,6 +1843,9 @@ fec_probe(struct platform_device *pdev)
 
        fec_reset_phy(pdev);
 
+       if (fep->bufdesc_ex)
+               fec_ptp_init(ndev, pdev);
+
        ret = fec_enet_init(ndev);
        if (ret)
                goto failed_init;
@@ -1828,9 +1861,6 @@ fec_probe(struct platform_device *pdev)
        if (ret)
                goto failed_register;
 
-       if (fep->bufdesc_ex)
-               fec_ptp_init(ndev, pdev);
-
        return 0;
 
 failed_register: