These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / net / ethernet / freescale / gianfar.c
index e616b71..3e233d9 100644 (file)
 
 #include "gianfar.h"
 
-#define TX_TIMEOUT      (1*HZ)
+#define TX_TIMEOUT      (5*HZ)
 
-const char gfar_driver_version[] = "1.3";
+const char gfar_driver_version[] = "2.0";
 
 static int gfar_enet_open(struct net_device *dev);
 static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev);
 static void gfar_reset_task(struct work_struct *work);
 static void gfar_timeout(struct net_device *dev);
 static int gfar_close(struct net_device *dev);
-static struct sk_buff *gfar_new_skb(struct net_device *dev,
-                                   dma_addr_t *bufaddr);
+static void gfar_alloc_rx_buffs(struct gfar_priv_rx_q *rx_queue,
+                               int alloc_cnt);
 static int gfar_set_mac_address(struct net_device *dev);
 static int gfar_change_mtu(struct net_device *dev, int new_mtu);
 static irqreturn_t gfar_error(int irq, void *dev_id);
@@ -141,8 +141,7 @@ static void gfar_netpoll(struct net_device *dev);
 #endif
 int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit);
 static void gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue);
-static void gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
-                              int amount_pull, struct napi_struct *napi);
+static void gfar_process_frame(struct net_device *ndev, struct sk_buff *skb);
 static void gfar_halt_nodisable(struct gfar_private *priv);
 static void gfar_clear_exact_match(struct net_device *dev);
 static void gfar_set_mac_for_addr(struct net_device *dev, int num,
@@ -169,17 +168,15 @@ static void gfar_init_rxbdp(struct gfar_priv_rx_q *rx_queue, struct rxbd8 *bdp,
        bdp->lstatus = cpu_to_be32(lstatus);
 }
 
-static int gfar_init_bds(struct net_device *ndev)
+static void gfar_init_bds(struct net_device *ndev)
 {
        struct gfar_private *priv = netdev_priv(ndev);
        struct gfar __iomem *regs = priv->gfargrp[0].regs;
        struct gfar_priv_tx_q *tx_queue = NULL;
        struct gfar_priv_rx_q *rx_queue = NULL;
        struct txbd8 *txbdp;
-       struct rxbd8 *rxbdp;
        u32 __iomem *rfbptr;
        int i, j;
-       dma_addr_t bufaddr;
 
        for (i = 0; i < priv->num_tx_queues; i++) {
                tx_queue = priv->tx_queue[i];
@@ -207,40 +204,26 @@ static int gfar_init_bds(struct net_device *ndev)
        rfbptr = &regs->rfbptr0;
        for (i = 0; i < priv->num_rx_queues; i++) {
                rx_queue = priv->rx_queue[i];
-               rx_queue->cur_rx = rx_queue->rx_bd_base;
-               rx_queue->skb_currx = 0;
-               rxbdp = rx_queue->rx_bd_base;
 
-               for (j = 0; j < rx_queue->rx_ring_size; j++) {
-                       struct sk_buff *skb = rx_queue->rx_skbuff[j];
+               rx_queue->next_to_clean = 0;
+               rx_queue->next_to_use = 0;
+               rx_queue->next_to_alloc = 0;
 
-                       if (skb) {
-                               bufaddr = be32_to_cpu(rxbdp->bufPtr);
-                       } else {
-                               skb = gfar_new_skb(ndev, &bufaddr);
-                               if (!skb) {
-                                       netdev_err(ndev, "Can't allocate RX buffers\n");
-                                       return -ENOMEM;
-                               }
-                               rx_queue->rx_skbuff[j] = skb;
-                       }
-
-                       gfar_init_rxbdp(rx_queue, rxbdp, bufaddr);
-                       rxbdp++;
-               }
+               /* make sure next_to_clean != next_to_use after this
+                * by leaving at least 1 unused descriptor
+                */
+               gfar_alloc_rx_buffs(rx_queue, gfar_rxbd_unused(rx_queue));
 
                rx_queue->rfbptr = rfbptr;
                rfbptr += 2;
        }
-
-       return 0;
 }
 
 static int gfar_alloc_skb_resources(struct net_device *ndev)
 {
        void *vaddr;
        dma_addr_t addr;
-       int i, j, k;
+       int i, j;
        struct gfar_private *priv = netdev_priv(ndev);
        struct device *dev = priv->dev;
        struct gfar_priv_tx_q *tx_queue = NULL;
@@ -279,7 +262,8 @@ static int gfar_alloc_skb_resources(struct net_device *ndev)
                rx_queue = priv->rx_queue[i];
                rx_queue->rx_bd_base = vaddr;
                rx_queue->rx_bd_dma_base = addr;
-               rx_queue->dev = ndev;
+               rx_queue->ndev = ndev;
+               rx_queue->dev = dev;
                addr  += sizeof(struct rxbd8) * rx_queue->rx_ring_size;
                vaddr += sizeof(struct rxbd8) * rx_queue->rx_ring_size;
        }
@@ -294,25 +278,20 @@ static int gfar_alloc_skb_resources(struct net_device *ndev)
                if (!tx_queue->tx_skbuff)
                        goto cleanup;
 
-               for (k = 0; k < tx_queue->tx_ring_size; k++)
-                       tx_queue->tx_skbuff[k] = NULL;
+               for (j = 0; j < tx_queue->tx_ring_size; j++)
+                       tx_queue->tx_skbuff[j] = NULL;
        }
 
        for (i = 0; i < priv->num_rx_queues; i++) {
                rx_queue = priv->rx_queue[i];
-               rx_queue->rx_skbuff =
-                       kmalloc_array(rx_queue->rx_ring_size,
-                                     sizeof(*rx_queue->rx_skbuff),
-                                     GFP_KERNEL);
-               if (!rx_queue->rx_skbuff)
+               rx_queue->rx_buff = kcalloc(rx_queue->rx_ring_size,
+                                           sizeof(*rx_queue->rx_buff),
+                                           GFP_KERNEL);
+               if (!rx_queue->rx_buff)
                        goto cleanup;
-
-               for (j = 0; j < rx_queue->rx_ring_size; j++)
-                       rx_queue->rx_skbuff[j] = NULL;
        }
 
-       if (gfar_init_bds(ndev))
-               goto cleanup;
+       gfar_init_bds(ndev);
 
        return 0;
 
@@ -354,28 +333,16 @@ static void gfar_init_rqprm(struct gfar_private *priv)
        }
 }
 
-static void gfar_rx_buff_size_config(struct gfar_private *priv)
+static void gfar_rx_offload_en(struct gfar_private *priv)
 {
-       int frame_size = priv->ndev->mtu + ETH_HLEN + ETH_FCS_LEN;
-
        /* set this when rx hw offload (TOE) functions are being used */
        priv->uses_rxfcb = 0;
 
        if (priv->ndev->features & (NETIF_F_RXCSUM | NETIF_F_HW_VLAN_CTAG_RX))
                priv->uses_rxfcb = 1;
 
-       if (priv->hwts_rx_en)
+       if (priv->hwts_rx_en || priv->rx_filer_enable)
                priv->uses_rxfcb = 1;
-
-       if (priv->uses_rxfcb)
-               frame_size += GMAC_FCB_LEN;
-
-       frame_size += priv->padding;
-
-       frame_size = (frame_size & ~(INCREMENTAL_BUFFER_SIZE - 1)) +
-                    INCREMENTAL_BUFFER_SIZE;
-
-       priv->rx_buffer_size = frame_size;
 }
 
 static void gfar_mac_rx_config(struct gfar_private *priv)
@@ -384,7 +351,7 @@ static void gfar_mac_rx_config(struct gfar_private *priv)
        u32 rctrl = 0;
 
        if (priv->rx_filer_enable) {
-               rctrl |= RCTRL_FILREN;
+               rctrl |= RCTRL_FILREN | RCTRL_PRSDEP_INIT;
                /* Program the RIR0 reg with the required distribution */
                if (priv->poll_mode == GFAR_SQ_POLLING)
                        gfar_write(&regs->rir0, DEFAULT_2RXQ_RIR0);
@@ -516,6 +483,15 @@ static struct net_device_stats *gfar_get_stats(struct net_device *dev)
        return &dev->stats;
 }
 
+static int gfar_set_mac_addr(struct net_device *dev, void *p)
+{
+       eth_mac_addr(dev, p);
+
+       gfar_set_mac_for_addr(dev, 0, dev->dev_addr);
+
+       return 0;
+}
+
 static const struct net_device_ops gfar_netdev_ops = {
        .ndo_open = gfar_enet_open,
        .ndo_start_xmit = gfar_start_xmit,
@@ -526,7 +502,7 @@ static const struct net_device_ops gfar_netdev_ops = {
        .ndo_tx_timeout = gfar_timeout,
        .ndo_do_ioctl = gfar_ioctl,
        .ndo_get_stats = gfar_get_stats,
-       .ndo_set_mac_address = eth_mac_addr,
+       .ndo_set_mac_address = gfar_set_mac_addr,
        .ndo_validate_addr = eth_validate_addr,
 #ifdef CONFIG_NET_POLL_CONTROLLER
        .ndo_poll_controller = gfar_netpoll,
@@ -556,22 +532,6 @@ static void gfar_ints_enable(struct gfar_private *priv)
        }
 }
 
-static void lock_tx_qs(struct gfar_private *priv)
-{
-       int i;
-
-       for (i = 0; i < priv->num_tx_queues; i++)
-               spin_lock(&priv->tx_queue[i]->txlock);
-}
-
-static void unlock_tx_qs(struct gfar_private *priv)
-{
-       int i;
-
-       for (i = 0; i < priv->num_tx_queues; i++)
-               spin_unlock(&priv->tx_queue[i]->txlock);
-}
-
 static int gfar_alloc_tx_queues(struct gfar_private *priv)
 {
        int i;
@@ -600,9 +560,8 @@ static int gfar_alloc_rx_queues(struct gfar_private *priv)
                if (!priv->rx_queue[i])
                        return -ENOMEM;
 
-               priv->rx_queue[i]->rx_skbuff = NULL;
                priv->rx_queue[i]->qindex = i;
-               priv->rx_queue[i]->dev = priv->ndev;
+               priv->rx_queue[i]->ndev = priv->ndev;
        }
        return 0;
 }
@@ -688,9 +647,9 @@ static int gfar_parse_group(struct device_node *np,
        if (model && strcasecmp(model, "FEC")) {
                gfar_irq(grp, RX)->irq = irq_of_parse_and_map(np, 1);
                gfar_irq(grp, ER)->irq = irq_of_parse_and_map(np, 2);
-               if (gfar_irq(grp, TX)->irq == NO_IRQ ||
-                   gfar_irq(grp, RX)->irq == NO_IRQ ||
-                   gfar_irq(grp, ER)->irq == NO_IRQ)
+               if (!gfar_irq(grp, TX)->irq ||
+                   !gfar_irq(grp, RX)->irq ||
+                   !gfar_irq(grp, ER)->irq)
                        return -EINVAL;
        }
 
@@ -935,7 +894,8 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev)
                                     FSL_GIANFAR_DEV_HAS_VLAN |
                                     FSL_GIANFAR_DEV_HAS_MAGIC_PACKET |
                                     FSL_GIANFAR_DEV_HAS_EXTENDED_HASH |
-                                    FSL_GIANFAR_DEV_HAS_TIMER;
+                                    FSL_GIANFAR_DEV_HAS_TIMER |
+                                    FSL_GIANFAR_DEV_HAS_RX_FILER;
 
        err = of_property_read_string(np, "phy-connection-type", &ctype);
 
@@ -948,6 +908,9 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev)
        if (of_find_property(np, "fsl,magic-packet", NULL))
                priv->device_flags |= FSL_GIANFAR_DEV_HAS_MAGIC_PACKET;
 
+       if (of_get_property(np, "fsl,wake-on-filer", NULL))
+               priv->device_flags |= FSL_GIANFAR_DEV_HAS_WAKE_ON_FILER;
+
        priv->phy_node = of_parse_phandle(np, "phy-handle", 0);
 
        /* In the case of a fixed PHY, the DT node associated
@@ -1194,12 +1157,11 @@ void gfar_mac_reset(struct gfar_private *priv)
 
        udelay(3);
 
-       /* Compute rx_buff_size based on config flags */
-       gfar_rx_buff_size_config(priv);
+       gfar_rx_offload_en(priv);
 
        /* Initialize the max receive frame/buffer lengths */
-       gfar_write(&regs->maxfrm, priv->rx_buffer_size);
-       gfar_write(&regs->mrblr, priv->rx_buffer_size);
+       gfar_write(&regs->maxfrm, GFAR_JUMBO_FRAME_SIZE);
+       gfar_write(&regs->mrblr, GFAR_RXB_SIZE);
 
        /* Initialize the Minimum Frame Length Register */
        gfar_write(&regs->minflr, MINFLR_INIT_SETTINGS);
@@ -1207,12 +1169,11 @@ void gfar_mac_reset(struct gfar_private *priv)
        /* Initialize MACCFG2. */
        tempval = MACCFG2_INIT_SETTINGS;
 
-       /* If the mtu is larger than the max size for standard
-        * ethernet frames (ie, a jumbo frame), then set maccfg2
-        * to allow huge frames, and to check the length
+       /* eTSEC74 erratum: Rx frames of length MAXFRM or MAXFRM-1
+        * are marked as truncated.  Avoid this by MACCFG2[Huge Frame]=1,
+        * and by checking RxBD[LG] and discarding larger than MAXFRM.
         */
-       if (priv->rx_buffer_size > DEFAULT_RX_BUFFER_SIZE ||
-           gfar_has_errata(priv, GFAR_ERRATA_74))
+       if (gfar_has_errata(priv, GFAR_ERRATA_74))
                tempval |= MACCFG2_HUGEFRAME | MACCFG2_LENGTHCHECK;
 
        gfar_write(&regs->maccfg2, tempval);
@@ -1367,7 +1328,6 @@ static int gfar_probe(struct platform_device *ofdev)
        priv->dev = &ofdev->dev;
        SET_NETDEV_DEV(dev, &ofdev->dev);
 
-       spin_lock_init(&priv->bflock);
        INIT_WORK(&priv->reset_task, gfar_reset_task);
 
        platform_set_drvdata(ofdev, priv);
@@ -1411,6 +1371,8 @@ static int gfar_probe(struct platform_device *ofdev)
                dev->features |= NETIF_F_HW_VLAN_CTAG_RX;
        }
 
+       dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
+
        gfar_init_addr_hash_table(priv);
 
        /* Insert receive time stamps into padding alignment bytes */
@@ -1421,8 +1383,6 @@ static int gfar_probe(struct platform_device *ofdev)
            priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER)
                dev->needed_headroom = GMAC_FCB_LEN;
 
-       priv->rx_buffer_size = DEFAULT_RX_BUFFER_SIZE;
-
        /* Initializing some of the rx/tx queue level parameters */
        for (i = 0; i < priv->num_tx_queues; i++) {
                priv->tx_queue[i]->tx_ring_size = DEFAULT_TX_RING_SIZE;
@@ -1437,8 +1397,9 @@ static int gfar_probe(struct platform_device *ofdev)
                priv->rx_queue[i]->rxic = DEFAULT_RXIC;
        }
 
-       /* always enable rx filer */
-       priv->rx_filer_enable = 1;
+       /* Always enable rx filer if available */
+       priv->rx_filer_enable =
+           (priv->device_flags & FSL_GIANFAR_DEV_HAS_RX_FILER) ? 1 : 0;
        /* Enable most messages by default */
        priv->msg_enable = (NETIF_MSG_IFUP << 1 ) - 1;
        /* use pritority h/w tx queue scheduling for single queue devices */
@@ -1459,9 +1420,14 @@ static int gfar_probe(struct platform_device *ofdev)
                goto register_fail;
        }
 
-       device_init_wakeup(&dev->dev,
-                          priv->device_flags &
-                          FSL_GIANFAR_DEV_HAS_MAGIC_PACKET);
+       if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET)
+               priv->wol_supported |= GFAR_WOL_MAGIC;
+
+       if ((priv->device_flags & FSL_GIANFAR_DEV_HAS_WAKE_ON_FILER) &&
+           priv->rx_filer_enable)
+               priv->wol_supported |= GFAR_WOL_FILER_UCAST;
+
+       device_set_wakeup_capable(&ofdev->dev, priv->wol_supported);
 
        /* fill out IRQ number and name fields */
        for (i = 0; i < priv->num_grps; i++) {
@@ -1524,53 +1490,153 @@ static int gfar_remove(struct platform_device *ofdev)
 
 #ifdef CONFIG_PM
 
+static void __gfar_filer_disable(struct gfar_private *priv)
+{
+       struct gfar __iomem *regs = priv->gfargrp[0].regs;
+       u32 temp;
+
+       temp = gfar_read(&regs->rctrl);
+       temp &= ~(RCTRL_FILREN | RCTRL_PRSDEP_INIT);
+       gfar_write(&regs->rctrl, temp);
+}
+
+static void __gfar_filer_enable(struct gfar_private *priv)
+{
+       struct gfar __iomem *regs = priv->gfargrp[0].regs;
+       u32 temp;
+
+       temp = gfar_read(&regs->rctrl);
+       temp |= RCTRL_FILREN | RCTRL_PRSDEP_INIT;
+       gfar_write(&regs->rctrl, temp);
+}
+
+/* Filer rules implementing wol capabilities */
+static void gfar_filer_config_wol(struct gfar_private *priv)
+{
+       unsigned int i;
+       u32 rqfcr;
+
+       __gfar_filer_disable(priv);
+
+       /* clear the filer table, reject any packet by default */
+       rqfcr = RQFCR_RJE | RQFCR_CMP_MATCH;
+       for (i = 0; i <= MAX_FILER_IDX; i++)
+               gfar_write_filer(priv, i, rqfcr, 0);
+
+       i = 0;
+       if (priv->wol_opts & GFAR_WOL_FILER_UCAST) {
+               /* unicast packet, accept it */
+               struct net_device *ndev = priv->ndev;
+               /* get the default rx queue index */
+               u8 qindex = (u8)priv->gfargrp[0].rx_queue->qindex;
+               u32 dest_mac_addr = (ndev->dev_addr[0] << 16) |
+                                   (ndev->dev_addr[1] << 8) |
+                                    ndev->dev_addr[2];
+
+               rqfcr = (qindex << 10) | RQFCR_AND |
+                       RQFCR_CMP_EXACT | RQFCR_PID_DAH;
+
+               gfar_write_filer(priv, i++, rqfcr, dest_mac_addr);
+
+               dest_mac_addr = (ndev->dev_addr[3] << 16) |
+                               (ndev->dev_addr[4] << 8) |
+                                ndev->dev_addr[5];
+               rqfcr = (qindex << 10) | RQFCR_GPI |
+                       RQFCR_CMP_EXACT | RQFCR_PID_DAL;
+               gfar_write_filer(priv, i++, rqfcr, dest_mac_addr);
+       }
+
+       __gfar_filer_enable(priv);
+}
+
+static void gfar_filer_restore_table(struct gfar_private *priv)
+{
+       u32 rqfcr, rqfpr;
+       unsigned int i;
+
+       __gfar_filer_disable(priv);
+
+       for (i = 0; i <= MAX_FILER_IDX; i++) {
+               rqfcr = priv->ftp_rqfcr[i];
+               rqfpr = priv->ftp_rqfpr[i];
+               gfar_write_filer(priv, i, rqfcr, rqfpr);
+       }
+
+       __gfar_filer_enable(priv);
+}
+
+/* gfar_start() for Rx only and with the FGPI filer interrupt enabled */
+static void gfar_start_wol_filer(struct gfar_private *priv)
+{
+       struct gfar __iomem *regs = priv->gfargrp[0].regs;
+       u32 tempval;
+       int i = 0;
+
+       /* Enable Rx hw queues */
+       gfar_write(&regs->rqueue, priv->rqueue);
+
+       /* Initialize DMACTRL to have WWR and WOP */
+       tempval = gfar_read(&regs->dmactrl);
+       tempval |= DMACTRL_INIT_SETTINGS;
+       gfar_write(&regs->dmactrl, tempval);
+
+       /* Make sure we aren't stopped */
+       tempval = gfar_read(&regs->dmactrl);
+       tempval &= ~DMACTRL_GRS;
+       gfar_write(&regs->dmactrl, tempval);
+
+       for (i = 0; i < priv->num_grps; i++) {
+               regs = priv->gfargrp[i].regs;
+               /* Clear RHLT, so that the DMA starts polling now */
+               gfar_write(&regs->rstat, priv->gfargrp[i].rstat);
+               /* enable the Filer General Purpose Interrupt */
+               gfar_write(&regs->imask, IMASK_FGPI);
+       }
+
+       /* Enable Rx DMA */
+       tempval = gfar_read(&regs->maccfg1);
+       tempval |= MACCFG1_RX_EN;
+       gfar_write(&regs->maccfg1, tempval);
+}
+
 static int gfar_suspend(struct device *dev)
 {
        struct gfar_private *priv = dev_get_drvdata(dev);
        struct net_device *ndev = priv->ndev;
        struct gfar __iomem *regs = priv->gfargrp[0].regs;
-       unsigned long flags;
        u32 tempval;
+       u16 wol = priv->wol_opts;
 
-       int magic_packet = priv->wol_en &&
-                          (priv->device_flags &
-                           FSL_GIANFAR_DEV_HAS_MAGIC_PACKET);
+       if (!netif_running(ndev))
+               return 0;
 
+       disable_napi(priv);
+       netif_tx_lock(ndev);
        netif_device_detach(ndev);
+       netif_tx_unlock(ndev);
 
-       if (netif_running(ndev)) {
+       gfar_halt(priv);
 
-               local_irq_save_nort(flags);
-               lock_tx_qs(priv);
+       if (wol & GFAR_WOL_MAGIC) {
+               /* Enable interrupt on Magic Packet */
+               gfar_write(&regs->imask, IMASK_MAG);
 
-               gfar_halt_nodisable(priv);
+               /* Enable Magic Packet mode */
+               tempval = gfar_read(&regs->maccfg2);
+               tempval |= MACCFG2_MPEN;
+               gfar_write(&regs->maccfg2, tempval);
 
-               /* Disable Tx, and Rx if wake-on-LAN is disabled. */
+               /* re-enable the Rx block */
                tempval = gfar_read(&regs->maccfg1);
-
-               tempval &= ~MACCFG1_TX_EN;
-
-               if (!magic_packet)
-                       tempval &= ~MACCFG1_RX_EN;
-
+               tempval |= MACCFG1_RX_EN;
                gfar_write(&regs->maccfg1, tempval);
 
-               unlock_tx_qs(priv);
-               local_irq_restore_nort(flags);
-
-               disable_napi(priv);
-
-               if (magic_packet) {
-                       /* Enable interrupt on Magic Packet */
-                       gfar_write(&regs->imask, IMASK_MAG);
+       } else if (wol & GFAR_WOL_FILER_UCAST) {
+               gfar_filer_config_wol(priv);
+               gfar_start_wol_filer(priv);
 
-                       /* Enable Magic Packet mode */
-                       tempval = gfar_read(&regs->maccfg2);
-                       tempval |= MACCFG2_MPEN;
-                       gfar_write(&regs->maccfg2, tempval);
-               } else {
-                       phy_stop(priv->phydev);
-               }
+       } else {
+               phy_stop(priv->phydev);
        }
 
        return 0;
@@ -1581,37 +1647,30 @@ static int gfar_resume(struct device *dev)
        struct gfar_private *priv = dev_get_drvdata(dev);
        struct net_device *ndev = priv->ndev;
        struct gfar __iomem *regs = priv->gfargrp[0].regs;
-       unsigned long flags;
        u32 tempval;
-       int magic_packet = priv->wol_en &&
-                          (priv->device_flags &
-                           FSL_GIANFAR_DEV_HAS_MAGIC_PACKET);
+       u16 wol = priv->wol_opts;
 
-       if (!netif_running(ndev)) {
-               netif_device_attach(ndev);
+       if (!netif_running(ndev))
                return 0;
-       }
 
-       if (!magic_packet && priv->phydev)
-               phy_start(priv->phydev);
+       if (wol & GFAR_WOL_MAGIC) {
+               /* Disable Magic Packet mode */
+               tempval = gfar_read(&regs->maccfg2);
+               tempval &= ~MACCFG2_MPEN;
+               gfar_write(&regs->maccfg2, tempval);
 
-       /* Disable Magic Packet mode, in case something
-        * else woke us up.
-        */
-       local_irq_save_nort(flags);
-       lock_tx_qs(priv);
+       } else if (wol & GFAR_WOL_FILER_UCAST) {
+               /* need to stop rx only, tx is already down */
+               gfar_halt(priv);
+               gfar_filer_restore_table(priv);
 
-       tempval = gfar_read(&regs->maccfg2);
-       tempval &= ~MACCFG2_MPEN;
-       gfar_write(&regs->maccfg2, tempval);
+       } else {
+               phy_start(priv->phydev);
+       }
 
        gfar_start(priv);
 
-       unlock_tx_qs(priv);
-       local_irq_restore_nort(flags);
-
        netif_device_attach(ndev);
-
        enable_napi(priv);
 
        return 0;
@@ -1628,10 +1687,7 @@ static int gfar_restore(struct device *dev)
                return 0;
        }
 
-       if (gfar_init_bds(ndev)) {
-               free_skb_resources(priv);
-               return -ENOMEM;
-       }
+       gfar_init_bds(ndev);
 
        gfar_mac_reset(priv);
 
@@ -1780,8 +1836,10 @@ static void gfar_configure_serdes(struct net_device *dev)
         * everything for us?  Resetting it takes the link down and requires
         * several seconds for it to come back.
         */
-       if (phy_read(tbiphy, MII_BMSR) & BMSR_LSTATUS)
+       if (phy_read(tbiphy, MII_BMSR) & BMSR_LSTATUS) {
+               put_device(&tbiphy->dev);
                return;
+       }
 
        /* Single clk mode, mii mode off(for serdes communication) */
        phy_write(tbiphy, MII_TBICON, TBICON_CLK_SELECT);
@@ -1793,6 +1851,8 @@ static void gfar_configure_serdes(struct net_device *dev)
        phy_write(tbiphy, MII_BMCR,
                  BMCR_ANENABLE | BMCR_ANRESTART | BMCR_FULLDPLX |
                  BMCR_SPEED1000);
+
+       put_device(&tbiphy->dev);
 }
 
 static int __gfar_is_rx_idle(struct gfar_private *priv)
@@ -1922,26 +1982,32 @@ static void free_skb_tx_queue(struct gfar_priv_tx_q *tx_queue)
 
 static void free_skb_rx_queue(struct gfar_priv_rx_q *rx_queue)
 {
-       struct rxbd8 *rxbdp;
-       struct gfar_private *priv = netdev_priv(rx_queue->dev);
        int i;
 
-       rxbdp = rx_queue->rx_bd_base;
+       struct rxbd8 *rxbdp = rx_queue->rx_bd_base;
+
+       if (rx_queue->skb)
+               dev_kfree_skb(rx_queue->skb);
 
        for (i = 0; i < rx_queue->rx_ring_size; i++) {
-               if (rx_queue->rx_skbuff[i]) {
-                       dma_unmap_single(priv->dev, be32_to_cpu(rxbdp->bufPtr),
-                                        priv->rx_buffer_size,
-                                        DMA_FROM_DEVICE);
-                       dev_kfree_skb_any(rx_queue->rx_skbuff[i]);
-                       rx_queue->rx_skbuff[i] = NULL;
-               }
+               struct  gfar_rx_buff *rxb = &rx_queue->rx_buff[i];
+
                rxbdp->lstatus = 0;
                rxbdp->bufPtr = 0;
                rxbdp++;
+
+               if (!rxb->page)
+                       continue;
+
+               dma_unmap_single(rx_queue->dev, rxb->dma,
+                                PAGE_SIZE, DMA_FROM_DEVICE);
+               __free_page(rxb->page);
+
+               rxb->page = NULL;
        }
-       kfree(rx_queue->rx_skbuff);
-       rx_queue->rx_skbuff = NULL;
+
+       kfree(rx_queue->rx_buff);
+       rx_queue->rx_buff = NULL;
 }
 
 /* If there are any tx skbs or rx skbs still around, free them.
@@ -1966,7 +2032,7 @@ static void free_skb_resources(struct gfar_private *priv)
 
        for (i = 0; i < priv->num_rx_queues; i++) {
                rx_queue = priv->rx_queue[i];
-               if (rx_queue->rx_skbuff)
+               if (rx_queue->rx_buff)
                        free_skb_rx_queue(rx_queue);
        }
 
@@ -2042,6 +2108,8 @@ static int register_grp_irqs(struct gfar_priv_grp *grp)
 
                        goto err_irq_fail;
                }
+               enable_irq_wake(gfar_irq(grp, ER)->irq);
+
                err = request_irq(gfar_irq(grp, TX)->irq, gfar_transmit, 0,
                                  gfar_irq(grp, TX)->name, grp);
                if (err < 0) {
@@ -2056,6 +2124,8 @@ static int register_grp_irqs(struct gfar_priv_grp *grp)
                                  gfar_irq(grp, RX)->irq);
                        goto rx_irq_fail;
                }
+               enable_irq_wake(gfar_irq(grp, RX)->irq);
+
        } else {
                err = request_irq(gfar_irq(grp, TX)->irq, gfar_interrupt, 0,
                                  gfar_irq(grp, TX)->name, grp);
@@ -2064,6 +2134,7 @@ static int register_grp_irqs(struct gfar_priv_grp *grp)
                                  gfar_irq(grp, TX)->irq);
                        goto err_irq_fail;
                }
+               enable_irq_wake(gfar_irq(grp, TX)->irq);
        }
 
        return 0;
@@ -2129,6 +2200,11 @@ int startup_gfar(struct net_device *ndev)
        /* Start Rx/Tx DMA and enable the interrupts */
        gfar_start(priv);
 
+       /* force link state update after mac reset */
+       priv->oldlink = 0;
+       priv->oldspeed = 0;
+       priv->oldduplex = -1;
+
        phy_start(priv->phydev);
 
        enable_napi(priv);
@@ -2158,8 +2234,6 @@ static int gfar_enet_open(struct net_device *dev)
        if (err)
                return err;
 
-       device_set_wakeup_enable(&dev->dev, priv->wol_en);
-
        return err;
 }
 
@@ -2254,7 +2328,6 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
        int i, rq = 0;
        int do_tstamp, do_csum, do_vlan;
        u32 bufaddr;
-       unsigned long flags;
        unsigned int nr_frags, nr_txbds, bytes_sent, fcb_len = 0;
 
        rq = skb->queue_mapping;
@@ -2434,19 +2507,6 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        netdev_tx_sent_queue(txq, bytes_sent);
 
-       /* We can work in parallel with gfar_clean_tx_ring(), except
-        * when modifying num_txbdfree. Note that we didn't grab the lock
-        * when we were reading the num_txbdfree and checking for available
-        * space, that's because outside of this function it can only grow,
-        * and once we've got needed space, it cannot suddenly disappear.
-        *
-        * The lock also protects us from gfar_error(), which can modify
-        * regs->tstat and thus retrigger the transfers, which is why we
-        * also must grab the lock before setting ready bit for the first
-        * to be transmitted BD.
-        */
-       spin_lock_irqsave(&tx_queue->txlock, flags);
-
        gfar_wmb();
 
        txbdp_start->lstatus = cpu_to_be32(lstatus);
@@ -2463,8 +2523,15 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        tx_queue->cur_tx = next_txbd(txbdp, base, tx_queue->tx_ring_size);
 
+       /* We can work in parallel with gfar_clean_tx_ring(), except
+        * when modifying num_txbdfree. Note that we didn't grab the lock
+        * when we were reading the num_txbdfree and checking for available
+        * space, that's because outside of this function it can only grow.
+        */
+       spin_lock_bh(&tx_queue->txlock);
        /* reduce TxBD free count */
        tx_queue->num_txbdfree -= (nr_txbds);
+       spin_unlock_bh(&tx_queue->txlock);
 
        /* If the next BD still needs to be cleaned up, then the bds
         * are full.  We need to tell the kernel to stop sending us stuff.
@@ -2478,9 +2545,6 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
        /* Tell the DMA to go go go */
        gfar_write(&regs->tstat, TSTAT_CLEAR_THALT >> tx_queue->qindex);
 
-       /* Unlock priv */
-       spin_unlock_irqrestore(&tx_queue->txlock, flags);
-
        return NETDEV_TX_OK;
 
 dma_map_err:
@@ -2534,7 +2598,7 @@ static int gfar_change_mtu(struct net_device *dev, int new_mtu)
        struct gfar_private *priv = netdev_priv(dev);
        int frame_size = new_mtu + ETH_HLEN;
 
-       if ((frame_size < 64) || (frame_size > JUMBO_FRAME_SIZE)) {
+       if ((frame_size < 64) || (frame_size > GFAR_JUMBO_FRAME_SIZE)) {
                netif_err(priv, drv, dev, "Invalid MTU setting\n");
                return -EINVAL;
        }
@@ -2588,15 +2652,6 @@ static void gfar_timeout(struct net_device *dev)
        schedule_work(&priv->reset_task);
 }
 
-static void gfar_align_skb(struct sk_buff *skb)
-{
-       /* We need the data buffer to be aligned properly.  We will reserve
-        * as many bytes as needed to align the data properly
-        */
-       skb_reserve(skb, RXBUF_ALIGNMENT -
-                   (((unsigned long) skb->data) & (RXBUF_ALIGNMENT - 1)));
-}
-
 /* Interrupt Handler for Transmit complete */
 static void gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
 {
@@ -2622,7 +2677,6 @@ static void gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
        skb_dirtytx = tx_queue->skb_dirtytx;
 
        while ((skb = tx_queue->tx_skbuff[skb_dirtytx])) {
-               unsigned long flags;
 
                frags = skb_shinfo(skb)->nr_frags;
 
@@ -2655,7 +2709,8 @@ static void gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
 
                if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)) {
                        struct skb_shared_hwtstamps shhwtstamps;
-                       u64 *ns = (u64*) (((u32)skb->data + 0x10) & ~0x7);
+                       u64 *ns = (u64 *)(((uintptr_t)skb->data + 0x10) &
+                                         ~0x7UL);
 
                        memset(&shhwtstamps, 0, sizeof(shhwtstamps));
                        shhwtstamps.hwtstamp = ns_to_ktime(*ns);
@@ -2686,9 +2741,9 @@ static void gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
                              TX_RING_MOD_MASK(tx_ring_size);
 
                howmany++;
-               spin_lock_irqsave(&tx_queue->txlock, flags);
+               spin_lock(&tx_queue->txlock);
                tx_queue->num_txbdfree += nr_txbds;
-               spin_unlock_irqrestore(&tx_queue->txlock, flags);
+               spin_unlock(&tx_queue->txlock);
        }
 
        /* If we freed a buffer, we can restart transmission, if necessary */
@@ -2704,49 +2759,85 @@ static void gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
        netdev_tx_completed_queue(txq, howmany, bytes_sent);
 }
 
-static struct sk_buff *gfar_alloc_skb(struct net_device *dev)
+static bool gfar_new_page(struct gfar_priv_rx_q *rxq, struct gfar_rx_buff *rxb)
 {
-       struct gfar_private *priv = netdev_priv(dev);
-       struct sk_buff *skb;
+       struct page *page;
+       dma_addr_t addr;
 
-       skb = netdev_alloc_skb(dev, priv->rx_buffer_size + RXBUF_ALIGNMENT);
-       if (!skb)
-               return NULL;
+       page = dev_alloc_page();
+       if (unlikely(!page))
+               return false;
 
-       gfar_align_skb(skb);
+       addr = dma_map_page(rxq->dev, page, 0, PAGE_SIZE, DMA_FROM_DEVICE);
+       if (unlikely(dma_mapping_error(rxq->dev, addr))) {
+               __free_page(page);
 
-       return skb;
+               return false;
+       }
+
+       rxb->dma = addr;
+       rxb->page = page;
+       rxb->page_offset = 0;
+
+       return true;
 }
 
-static struct sk_buff *gfar_new_skb(struct net_device *dev, dma_addr_t *bufaddr)
+static void gfar_rx_alloc_err(struct gfar_priv_rx_q *rx_queue)
 {
-       struct gfar_private *priv = netdev_priv(dev);
-       struct sk_buff *skb;
-       dma_addr_t addr;
+       struct gfar_private *priv = netdev_priv(rx_queue->ndev);
+       struct gfar_extra_stats *estats = &priv->extra_stats;
 
-       skb = gfar_alloc_skb(dev);
-       if (!skb)
-               return NULL;
+       netdev_err(rx_queue->ndev, "Can't alloc RX buffers\n");
+       atomic64_inc(&estats->rx_alloc_err);
+}
 
-       addr = dma_map_single(priv->dev, skb->data,
-                             priv->rx_buffer_size, DMA_FROM_DEVICE);
-       if (unlikely(dma_mapping_error(priv->dev, addr))) {
-               dev_kfree_skb_any(skb);
-               return NULL;
+static void gfar_alloc_rx_buffs(struct gfar_priv_rx_q *rx_queue,
+                               int alloc_cnt)
+{
+       struct rxbd8 *bdp;
+       struct gfar_rx_buff *rxb;
+       int i;
+
+       i = rx_queue->next_to_use;
+       bdp = &rx_queue->rx_bd_base[i];
+       rxb = &rx_queue->rx_buff[i];
+
+       while (alloc_cnt--) {
+               /* try reuse page */
+               if (unlikely(!rxb->page)) {
+                       if (unlikely(!gfar_new_page(rx_queue, rxb))) {
+                               gfar_rx_alloc_err(rx_queue);
+                               break;
+                       }
+               }
+
+               /* Setup the new RxBD */
+               gfar_init_rxbdp(rx_queue, bdp,
+                               rxb->dma + rxb->page_offset + RXBUF_ALIGNMENT);
+
+               /* Update to the next pointer */
+               bdp++;
+               rxb++;
+
+               if (unlikely(++i == rx_queue->rx_ring_size)) {
+                       i = 0;
+                       bdp = rx_queue->rx_bd_base;
+                       rxb = rx_queue->rx_buff;
+               }
        }
 
-       *bufaddr = addr;
-       return skb;
+       rx_queue->next_to_use = i;
+       rx_queue->next_to_alloc = i;
 }
 
-static inline void count_errors(unsigned short status, struct net_device *dev)
+static void count_errors(u32 lstatus, struct net_device *ndev)
 {
-       struct gfar_private *priv = netdev_priv(dev);
-       struct net_device_stats *stats = &dev->stats;
+       struct gfar_private *priv = netdev_priv(ndev);
+       struct net_device_stats *stats = &ndev->stats;
        struct gfar_extra_stats *estats = &priv->extra_stats;
 
        /* If the packet was truncated, none of the other errors matter */
-       if (status & RXBD_TRUNCATED) {
+       if (lstatus & BD_LFLAG(RXBD_TRUNCATED)) {
                stats->rx_length_errors++;
 
                atomic64_inc(&estats->rx_trunc);
@@ -2754,25 +2845,25 @@ static inline void count_errors(unsigned short status, struct net_device *dev)
                return;
        }
        /* Count the errors, if there were any */
-       if (status & (RXBD_LARGE | RXBD_SHORT)) {
+       if (lstatus & BD_LFLAG(RXBD_LARGE | RXBD_SHORT)) {
                stats->rx_length_errors++;
 
-               if (status & RXBD_LARGE)
+               if (lstatus & BD_LFLAG(RXBD_LARGE))
                        atomic64_inc(&estats->rx_large);
                else
                        atomic64_inc(&estats->rx_short);
        }
-       if (status & RXBD_NONOCTET) {
+       if (lstatus & BD_LFLAG(RXBD_NONOCTET)) {
                stats->rx_frame_errors++;
                atomic64_inc(&estats->rx_nonoctet);
        }
-       if (status & RXBD_CRCERR) {
+       if (lstatus & BD_LFLAG(RXBD_CRCERR)) {
                atomic64_inc(&estats->rx_crcerr);
                stats->rx_crc_errors++;
        }
-       if (status & RXBD_OVERRUN) {
+       if (lstatus & BD_LFLAG(RXBD_OVERRUN)) {
                atomic64_inc(&estats->rx_overrun);
-               stats->rx_crc_errors++;
+               stats->rx_over_errors++;
        }
 }
 
@@ -2780,7 +2871,14 @@ irqreturn_t gfar_receive(int irq, void *grp_id)
 {
        struct gfar_priv_grp *grp = (struct gfar_priv_grp *)grp_id;
        unsigned long flags;
-       u32 imask;
+       u32 imask, ievent;
+
+       ievent = gfar_read(&grp->regs->ievent);
+
+       if (unlikely(ievent & IEVENT_FGPI)) {
+               gfar_write(&grp->regs->ievent, IEVENT_FGPI);
+               return IRQ_HANDLED;
+       }
 
        if (likely(napi_schedule_prep(&grp->napi_rx))) {
                spin_lock_irqsave(&grp->grplock, flags);
@@ -2823,6 +2921,93 @@ static irqreturn_t gfar_transmit(int irq, void *grp_id)
        return IRQ_HANDLED;
 }
 
+static bool gfar_add_rx_frag(struct gfar_rx_buff *rxb, u32 lstatus,
+                            struct sk_buff *skb, bool first)
+{
+       unsigned int size = lstatus & BD_LENGTH_MASK;
+       struct page *page = rxb->page;
+
+       /* Remove the FCS from the packet length */
+       if (likely(lstatus & BD_LFLAG(RXBD_LAST)))
+               size -= ETH_FCS_LEN;
+
+       if (likely(first))
+               skb_put(skb, size);
+       else
+               skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page,
+                               rxb->page_offset + RXBUF_ALIGNMENT,
+                               size, GFAR_RXB_TRUESIZE);
+
+       /* try reuse page */
+       if (unlikely(page_count(page) != 1))
+               return false;
+
+       /* change offset to the other half */
+       rxb->page_offset ^= GFAR_RXB_TRUESIZE;
+
+       atomic_inc(&page->_count);
+
+       return true;
+}
+
+static void gfar_reuse_rx_page(struct gfar_priv_rx_q *rxq,
+                              struct gfar_rx_buff *old_rxb)
+{
+       struct gfar_rx_buff *new_rxb;
+       u16 nta = rxq->next_to_alloc;
+
+       new_rxb = &rxq->rx_buff[nta];
+
+       /* find next buf that can reuse a page */
+       nta++;
+       rxq->next_to_alloc = (nta < rxq->rx_ring_size) ? nta : 0;
+
+       /* copy page reference */
+       *new_rxb = *old_rxb;
+
+       /* sync for use by the device */
+       dma_sync_single_range_for_device(rxq->dev, old_rxb->dma,
+                                        old_rxb->page_offset,
+                                        GFAR_RXB_TRUESIZE, DMA_FROM_DEVICE);
+}
+
+static struct sk_buff *gfar_get_next_rxbuff(struct gfar_priv_rx_q *rx_queue,
+                                           u32 lstatus, struct sk_buff *skb)
+{
+       struct gfar_rx_buff *rxb = &rx_queue->rx_buff[rx_queue->next_to_clean];
+       struct page *page = rxb->page;
+       bool first = false;
+
+       if (likely(!skb)) {
+               void *buff_addr = page_address(page) + rxb->page_offset;
+
+               skb = build_skb(buff_addr, GFAR_SKBFRAG_SIZE);
+               if (unlikely(!skb)) {
+                       gfar_rx_alloc_err(rx_queue);
+                       return NULL;
+               }
+               skb_reserve(skb, RXBUF_ALIGNMENT);
+               first = true;
+       }
+
+       dma_sync_single_range_for_cpu(rx_queue->dev, rxb->dma, rxb->page_offset,
+                                     GFAR_RXB_TRUESIZE, DMA_FROM_DEVICE);
+
+       if (gfar_add_rx_frag(rxb, lstatus, skb, first)) {
+               /* reuse the free half of the page */
+               gfar_reuse_rx_page(rx_queue, rxb);
+       } else {
+               /* page cannot be reused, unmap it */
+               dma_unmap_page(rx_queue->dev, rxb->dma,
+                              PAGE_SIZE, DMA_FROM_DEVICE);
+       }
+
+       /* clear rxb content */
+       rxb->page = NULL;
+
+       return skb;
+}
+
 static inline void gfar_rx_checksum(struct sk_buff *skb, struct rxfcb *fcb)
 {
        /* If valid headers were found, and valid sums
@@ -2837,10 +3022,9 @@ static inline void gfar_rx_checksum(struct sk_buff *skb, struct rxfcb *fcb)
 }
 
 /* gfar_process_frame() -- handle one incoming packet if skb isn't NULL. */
-static void gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
-                              int amount_pull, struct napi_struct *napi)
+static void gfar_process_frame(struct net_device *ndev, struct sk_buff *skb)
 {
-       struct gfar_private *priv = netdev_priv(dev);
+       struct gfar_private *priv = netdev_priv(ndev);
        struct rxfcb *fcb = NULL;
 
        /* fcb is at the beginning if exists */
@@ -2849,10 +3033,8 @@ static void gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
        /* Remove the FCB from the skb
         * Remove the padded bytes, if there are any
         */
-       if (amount_pull) {
-               skb_record_rx_queue(skb, fcb->rq);
-               skb_pull(skb, amount_pull);
-       }
+       if (priv->uses_rxfcb)
+               skb_pull(skb, GMAC_FCB_LEN);
 
        /* Get receive timestamp from the skb */
        if (priv->hwts_rx_en) {
@@ -2866,24 +3048,20 @@ static void gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
        if (priv->padding)
                skb_pull(skb, priv->padding);
 
-       if (dev->features & NETIF_F_RXCSUM)
+       if (ndev->features & NETIF_F_RXCSUM)
                gfar_rx_checksum(skb, fcb);
 
        /* Tell the skb what kind of packet this is */
-       skb->protocol = eth_type_trans(skb, dev);
+       skb->protocol = eth_type_trans(skb, ndev);
 
        /* There's need to check for NETIF_F_HW_VLAN_CTAG_RX here.
         * Even if vlan rx accel is disabled, on some chips
         * RXFCB_VLN is pseudo randomly set.
         */
-       if (dev->features & NETIF_F_HW_VLAN_CTAG_RX &&
+       if (ndev->features & NETIF_F_HW_VLAN_CTAG_RX &&
            be16_to_cpu(fcb->flags) & RXFCB_VLN)
                __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
                                       be16_to_cpu(fcb->vlctl));
-
-       /* Send the packet up the stack */
-       napi_gro_receive(napi, skb);
-
 }
 
 /* gfar_clean_rx_ring() -- Processes each frame in the rx ring
@@ -2892,91 +3070,89 @@ static void gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
  */
 int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit)
 {
-       struct net_device *dev = rx_queue->dev;
-       struct rxbd8 *bdp, *base;
-       struct sk_buff *skb;
-       int pkt_len;
-       int amount_pull;
-       int howmany = 0;
-       struct gfar_private *priv = netdev_priv(dev);
+       struct net_device *ndev = rx_queue->ndev;
+       struct gfar_private *priv = netdev_priv(ndev);
+       struct rxbd8 *bdp;
+       int i, howmany = 0;
+       struct sk_buff *skb = rx_queue->skb;
+       int cleaned_cnt = gfar_rxbd_unused(rx_queue);
+       unsigned int total_bytes = 0, total_pkts = 0;
 
        /* Get the first full descriptor */
-       bdp = rx_queue->cur_rx;
-       base = rx_queue->rx_bd_base;
+       i = rx_queue->next_to_clean;
+
+       while (rx_work_limit--) {
+               u32 lstatus;
 
-       amount_pull = priv->uses_rxfcb ? GMAC_FCB_LEN : 0;
+               if (cleaned_cnt >= GFAR_RX_BUFF_ALLOC) {
+                       gfar_alloc_rx_buffs(rx_queue, cleaned_cnt);
+                       cleaned_cnt = 0;
+               }
 
-       while (!(be16_to_cpu(bdp->status) & RXBD_EMPTY) && rx_work_limit--) {
-               struct sk_buff *newskb;
-               dma_addr_t bufaddr;
+               bdp = &rx_queue->rx_bd_base[i];
+               lstatus = be32_to_cpu(bdp->lstatus);
+               if (lstatus & BD_LFLAG(RXBD_EMPTY))
+                       break;
 
+               /* order rx buffer descriptor reads */
                rmb();
 
-               /* Add another skb for the future */
-               newskb = gfar_new_skb(dev, &bufaddr);
+               /* fetch next to clean buffer from the ring */
+               skb = gfar_get_next_rxbuff(rx_queue, lstatus, skb);
+               if (unlikely(!skb))
+                       break;
 
-               skb = rx_queue->rx_skbuff[rx_queue->skb_currx];
+               cleaned_cnt++;
+               howmany++;
 
-               dma_unmap_single(priv->dev, be32_to_cpu(bdp->bufPtr),
-                                priv->rx_buffer_size, DMA_FROM_DEVICE);
-
-               if (unlikely(!(be16_to_cpu(bdp->status) & RXBD_ERR) &&
-                            be16_to_cpu(bdp->length) > priv->rx_buffer_size))
-                       bdp->status = cpu_to_be16(RXBD_LARGE);
-
-               /* We drop the frame if we failed to allocate a new buffer */
-               if (unlikely(!newskb ||
-                            !(be16_to_cpu(bdp->status) & RXBD_LAST) ||
-                            be16_to_cpu(bdp->status) & RXBD_ERR)) {
-                       count_errors(be16_to_cpu(bdp->status), dev);
-
-                       if (unlikely(!newskb)) {
-                               newskb = skb;
-                               bufaddr = be32_to_cpu(bdp->bufPtr);
-                       } else if (skb)
-                               dev_kfree_skb(skb);
-               } else {
-                       /* Increment the number of packets */
-                       rx_queue->stats.rx_packets++;
-                       howmany++;
-
-                       if (likely(skb)) {
-                               pkt_len = be16_to_cpu(bdp->length) -
-                                         ETH_FCS_LEN;
-                               /* Remove the FCS from the packet length */
-                               skb_put(skb, pkt_len);
-                               rx_queue->stats.rx_bytes += pkt_len;
-                               skb_record_rx_queue(skb, rx_queue->qindex);
-                               gfar_process_frame(dev, skb, amount_pull,
-                                                  &rx_queue->grp->napi_rx);
+               if (unlikely(++i == rx_queue->rx_ring_size))
+                       i = 0;
 
-                       } else {
-                               netif_warn(priv, rx_err, dev, "Missing skb!\n");
-                               rx_queue->stats.rx_dropped++;
-                               atomic64_inc(&priv->extra_stats.rx_skbmissing);
-                       }
+               rx_queue->next_to_clean = i;
+
+               /* fetch next buffer if not the last in frame */
+               if (!(lstatus & BD_LFLAG(RXBD_LAST)))
+                       continue;
 
+               if (unlikely(lstatus & BD_LFLAG(RXBD_ERR))) {
+                       count_errors(lstatus, ndev);
+
+                       /* discard faulty buffer */
+                       dev_kfree_skb(skb);
+                       skb = NULL;
+                       rx_queue->stats.rx_dropped++;
+                       continue;
                }
 
-               rx_queue->rx_skbuff[rx_queue->skb_currx] = newskb;
+               /* Increment the number of packets */
+               total_pkts++;
+               total_bytes += skb->len;
 
-               /* Setup the new bdp */
-               gfar_init_rxbdp(rx_queue, bdp, bufaddr);
+               skb_record_rx_queue(skb, rx_queue->qindex);
 
-               /* Update Last Free RxBD pointer for LFC */
-               if (unlikely(rx_queue->rfbptr && priv->tx_actual_en))
-                       gfar_write(rx_queue->rfbptr, (u32)bdp);
+               gfar_process_frame(ndev, skb);
 
-               /* Update to the next pointer */
-               bdp = next_bd(bdp, base, rx_queue->rx_ring_size);
+               /* Send the packet up the stack */
+               napi_gro_receive(&rx_queue->grp->napi_rx, skb);
 
-               /* update to point at the next skb */
-               rx_queue->skb_currx = (rx_queue->skb_currx + 1) &
-                                     RX_RING_MOD_MASK(rx_queue->rx_ring_size);
+               skb = NULL;
        }
 
-       /* Update the current rxbd pointer to be the next one */
-       rx_queue->cur_rx = bdp;
+       /* Store incomplete frames for completion */
+       rx_queue->skb = skb;
+
+       rx_queue->stats.rx_packets += total_pkts;
+       rx_queue->stats.rx_bytes += total_bytes;
+
+       if (cleaned_cnt)
+               gfar_alloc_rx_buffs(rx_queue, cleaned_cnt);
+
+       /* Update Last Free RxBD pointer for LFC */
+       if (unlikely(priv->tx_actual_en)) {
+               u32 bdp_dma = gfar_rxbd_dma_lastfree(rx_queue);
+
+               gfar_write(rx_queue->rfbptr, bdp_dma);
+       }
 
        return howmany;
 }
@@ -3411,30 +3587,19 @@ static irqreturn_t gfar_error(int irq, void *grp_id)
                if (events & IEVENT_CRL)
                        dev->stats.tx_aborted_errors++;
                if (events & IEVENT_XFUN) {
-                       unsigned long flags;
-
                        netif_dbg(priv, tx_err, dev,
                                  "TX FIFO underrun, packet dropped\n");
                        dev->stats.tx_dropped++;
                        atomic64_inc(&priv->extra_stats.tx_underrun);
 
-                       local_irq_save_nort(flags);
-                       lock_tx_qs(priv);
-
-                       /* Reactivate the Tx Queues */
-                       gfar_write(&regs->tstat, gfargrp->tstat);
-
-                       unlock_tx_qs(priv);
-                       local_irq_restore_nort(flags);
+                       schedule_work(&priv->reset_task);
                }
                netif_dbg(priv, tx_err, dev, "Transmit Error\n");
        }
        if (events & IEVENT_BSY) {
-               dev->stats.rx_errors++;
+               dev->stats.rx_over_errors++;
                atomic64_inc(&priv->extra_stats.rx_bsy);
 
-               gfar_receive(irq, grp_id);
-
                netif_dbg(priv, rx_err, dev, "busy error (rstat: %x)\n",
                          gfar_read(&regs->rstat));
        }
@@ -3503,7 +3668,6 @@ static noinline void gfar_update_link_state(struct gfar_private *priv)
        struct phy_device *phydev = priv->phydev;
        struct gfar_priv_rx_q *rx_queue = NULL;
        int i;
-       struct rxbd8 *bdp;
 
        if (unlikely(test_bit(GFAR_RESETTING, &priv->state)))
                return;
@@ -3560,15 +3724,11 @@ static noinline void gfar_update_link_state(struct gfar_private *priv)
                /* Turn last free buffer recording on */
                if ((tempval1 & MACCFG1_TX_FLOW) && !tx_flow_oldval) {
                        for (i = 0; i < priv->num_rx_queues; i++) {
+                               u32 bdp_dma;
+
                                rx_queue = priv->rx_queue[i];
-                               bdp = rx_queue->cur_rx;
-                               /* skip to previous bd */
-                               bdp = skip_bd(bdp, rx_queue->rx_ring_size - 1,
-                                             rx_queue->rx_bd_base,
-                                             rx_queue->rx_ring_size);
-
-                               if (rx_queue->rfbptr)
-                                       gfar_write(rx_queue->rfbptr, (u32)bdp);
+                               bdp_dma = gfar_rxbd_dma_lastfree(rx_queue);
+                               gfar_write(rx_queue->rfbptr, bdp_dma);
                        }
 
                        priv->tx_actual_en = 1;