Merge branch 'for-2.6.25' of master.kernel.org:/pub/scm/linux/kernel/git/galak/powerp...
[safe/jmp/linux-2.6] / drivers / net / gianfar.c
index 0e8e3fc..0431e9e 100644 (file)
@@ -9,7 +9,8 @@
  * Author: Andy Fleming
  * Maintainer: Kumar Gala
  *
- * Copyright (c) 2002-2004 Freescale Semiconductor, Inc.
+ * Copyright (c) 2002-2006 Freescale Semiconductor, Inc.
+ * Copyright (c) 2007 MontaVista Software, Inc.
  *
  * This program is free software; you can redistribute  it and/or modify it
  * under  the terms of  the GNU General  Public License as published by the
@@ -64,9 +65,7 @@
  *  The driver then cleans up the buffer.
  */
 
-#include <linux/config.h>
 #include <linux/kernel.h>
-#include <linux/sched.h>
 #include <linux/string.h>
 #include <linux/errno.h>
 #include <linux/unistd.h>
@@ -117,12 +116,11 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev);
 static void gfar_timeout(struct net_device *dev);
 static int gfar_close(struct net_device *dev);
 struct sk_buff *gfar_new_skb(struct net_device *dev, struct rxbd8 *bdp);
-static struct net_device_stats *gfar_get_stats(struct net_device *dev);
 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, struct pt_regs *regs);
-static irqreturn_t gfar_transmit(int irq, void *dev_id, struct pt_regs *regs);
-static irqreturn_t gfar_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t gfar_error(int irq, void *dev_id);
+static irqreturn_t gfar_transmit(int irq, void *dev_id);
+static irqreturn_t gfar_interrupt(int irq, void *dev_id);
 static void adjust_link(struct net_device *dev);
 static void init_registers(struct net_device *dev);
 static int init_phy(struct net_device *dev);
@@ -131,20 +129,25 @@ static int gfar_remove(struct platform_device *pdev);
 static void free_skb_resources(struct gfar_private *priv);
 static void gfar_set_multi(struct net_device *dev);
 static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr);
+static void gfar_configure_serdes(struct net_device *dev);
+extern int gfar_local_mdio_write(struct gfar_mii *regs, int mii_id, int regnum, u16 value);
+extern int gfar_local_mdio_read(struct gfar_mii *regs, int mii_id, int regnum);
 #ifdef CONFIG_GFAR_NAPI
-static int gfar_poll(struct net_device *dev, int *budget);
+static int gfar_poll(struct napi_struct *napi, int budget);
+#endif
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void gfar_netpoll(struct net_device *dev);
 #endif
 int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit);
 static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, int length);
 static void gfar_vlan_rx_register(struct net_device *netdev,
                                struct vlan_group *grp);
-static void gfar_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid);
 void gfar_halt(struct net_device *dev);
 void gfar_start(struct net_device *dev);
 static void gfar_clear_exact_match(struct net_device *dev);
 static void gfar_set_mac_for_addr(struct net_device *dev, int num, u8 *addr);
 
-extern struct ethtool_ops gfar_ethtool_ops;
+extern const struct ethtool_ops gfar_ethtool_ops;
 
 MODULE_AUTHOR("Freescale Semiconductor, Inc");
 MODULE_DESCRIPTION("Gianfar Ethernet Driver");
@@ -165,8 +168,8 @@ static int gfar_probe(struct platform_device *pdev)
        struct gfar_private *priv = NULL;
        struct gianfar_platform_data *einfo;
        struct resource *r;
-       int idx;
        int err = 0;
+       DECLARE_MAC_BUF(mac);
 
        einfo = (struct gianfar_platform_data *) pdev->dev.platform_data;
 
@@ -184,6 +187,7 @@ static int gfar_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        priv = netdev_priv(dev);
+       priv->dev = dev;
 
        /* Set the info in the priv to the current info */
        priv->einfo = einfo;
@@ -193,8 +197,12 @@ static int gfar_probe(struct platform_device *pdev)
                priv->interruptTransmit = platform_get_irq_byname(pdev, "tx");
                priv->interruptReceive = platform_get_irq_byname(pdev, "rx");
                priv->interruptError = platform_get_irq_byname(pdev, "error");
+               if (priv->interruptTransmit < 0 || priv->interruptReceive < 0 || priv->interruptError < 0)
+                       goto regs_fail;
        } else {
                priv->interruptTransmit = platform_get_irq(pdev, 0);
+               if (priv->interruptTransmit < 0)
+                       goto regs_fail;
        }
 
        /* get a pointer to the register memory */
@@ -206,7 +214,8 @@ static int gfar_probe(struct platform_device *pdev)
                goto regs_fail;
        }
 
-       spin_lock_init(&priv->lock);
+       spin_lock_init(&priv->txlock);
+       spin_lock_init(&priv->rxlock);
 
        platform_set_drvdata(pdev, dev);
 
@@ -244,7 +253,6 @@ static int gfar_probe(struct platform_device *pdev)
        /* Set the dev->base_addr to the gfar reg region */
        dev->base_addr = (unsigned long) (priv->regs);
 
-       SET_MODULE_OWNER(dev);
        SET_NETDEV_DEV(dev, &pdev->dev);
 
        /* Fill in the dev structure */
@@ -253,11 +261,12 @@ static int gfar_probe(struct platform_device *pdev)
        dev->tx_timeout = gfar_timeout;
        dev->watchdog_timeo = TX_TIMEOUT;
 #ifdef CONFIG_GFAR_NAPI
-       dev->poll = gfar_poll;
-       dev->weight = GFAR_DEV_WEIGHT;
+       netif_napi_add(dev, &priv->napi, gfar_poll, GFAR_DEV_WEIGHT);
+#endif
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       dev->poll_controller = gfar_netpoll;
 #endif
        dev->stop = gfar_close;
-       dev->get_stats = gfar_get_stats;
        dev->change_mtu = gfar_change_mtu;
        dev->mtu = 1500;
        dev->set_multicast_list = gfar_set_multi;
@@ -274,7 +283,6 @@ static int gfar_probe(struct platform_device *pdev)
 
        if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_VLAN) {
                dev->vlan_rx_register = gfar_vlan_rx_register;
-               dev->vlan_rx_kill_vid = gfar_vlan_rx_kill_vid;
 
                dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
 
@@ -350,10 +358,8 @@ static int gfar_probe(struct platform_device *pdev)
        gfar_init_sysfs(dev);
 
        /* Print out the device info */
-       printk(KERN_INFO DEVICE_NAME, dev->name);
-       for (idx = 0; idx < 6; idx++)
-               printk("%2.2x%c", dev->dev_addr[idx], idx == 5 ? ' ' : ':');
-       printk("\n");
+       printk(KERN_INFO DEVICE_NAME "%s\n",
+              dev->name, print_mac(mac, dev->dev_addr));
 
        /* Even more device info helps when determining which kernel */
        /* provided which set of benchmarks. */
@@ -388,6 +394,48 @@ static int gfar_remove(struct platform_device *pdev)
 }
 
 
+/* Reads the controller's registers to determine what interface
+ * connects it to the PHY.
+ */
+static phy_interface_t gfar_get_interface(struct net_device *dev)
+{
+       struct gfar_private *priv = netdev_priv(dev);
+       u32 ecntrl = gfar_read(&priv->regs->ecntrl);
+
+       if (ecntrl & ECNTRL_SGMII_MODE)
+               return PHY_INTERFACE_MODE_SGMII;
+
+       if (ecntrl & ECNTRL_TBI_MODE) {
+               if (ecntrl & ECNTRL_REDUCED_MODE)
+                       return PHY_INTERFACE_MODE_RTBI;
+               else
+                       return PHY_INTERFACE_MODE_TBI;
+       }
+
+       if (ecntrl & ECNTRL_REDUCED_MODE) {
+               if (ecntrl & ECNTRL_REDUCED_MII_MODE)
+                       return PHY_INTERFACE_MODE_RMII;
+               else {
+                       phy_interface_t interface = priv->einfo->interface;
+
+                       /*
+                        * This isn't autodetected right now, so it must
+                        * be set by the device tree or platform code.
+                        */
+                       if (interface == PHY_INTERFACE_MODE_RGMII_ID)
+                               return PHY_INTERFACE_MODE_RGMII_ID;
+
+                       return PHY_INTERFACE_MODE_RGMII;
+               }
+       }
+
+       if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_GIGABIT)
+               return PHY_INTERFACE_MODE_GMII;
+
+       return PHY_INTERFACE_MODE_MII;
+}
+
+
 /* Initializes driver's PHY state, and attaches to the PHY.
  * Returns 0 on success.
  */
@@ -399,6 +447,7 @@ static int init_phy(struct net_device *dev)
                SUPPORTED_1000baseT_Full : 0;
        struct phy_device *phydev;
        char phy_id[BUS_ID_SIZE];
+       phy_interface_t interface;
 
        priv->oldlink = 0;
        priv->oldspeed = 0;
@@ -406,7 +455,12 @@ static int init_phy(struct net_device *dev)
 
        snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT, priv->einfo->bus_id, priv->einfo->phy_id);
 
-       phydev = phy_connect(dev, phy_id, &adjust_link, 0);
+       interface = gfar_get_interface(dev);
+
+       phydev = phy_connect(dev, phy_id, &adjust_link, 0, interface);
+
+       if (interface == PHY_INTERFACE_MODE_SGMII)
+               gfar_configure_serdes(dev);
 
        if (IS_ERR(phydev)) {
                printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
@@ -422,6 +476,27 @@ static int init_phy(struct net_device *dev)
        return 0;
 }
 
+static void gfar_configure_serdes(struct net_device *dev)
+{
+       struct gfar_private *priv = netdev_priv(dev);
+       struct gfar_mii __iomem *regs =
+                       (void __iomem *)&priv->regs->gfar_mii_regs;
+
+       /* Initialise TBI i/f to communicate with serdes (lynx phy) */
+
+       /* Single clk mode, mii mode off(for aerdes communication) */
+       gfar_local_mdio_write(regs, TBIPA_VALUE, MII_TBICON, TBICON_CLK_SELECT);
+
+       /* Supported pause and full-duplex, no half-duplex */
+       gfar_local_mdio_write(regs, TBIPA_VALUE, MII_ADVERTISE,
+                       ADVERTISE_1000XFULL | ADVERTISE_1000XPAUSE |
+                       ADVERTISE_1000XPSE_ASYM);
+
+       /* ANEG enable, restart ANEG, full duplex mode, speed[1] set */
+       gfar_local_mdio_write(regs, TBIPA_VALUE, MII_BMCR, BMCR_ANENABLE |
+                       BMCR_ANRESTART | BMCR_FULLDPLX | BMCR_SPEED1000);
+}
+
 static void init_registers(struct net_device *dev)
 {
        struct gfar_private *priv = netdev_priv(dev);
@@ -511,11 +586,13 @@ void stop_gfar(struct net_device *dev)
        phy_stop(priv->phydev);
 
        /* Lock it down */
-       spin_lock_irqsave(&priv->lock, flags);
+       spin_lock_irqsave(&priv->txlock, flags);
+       spin_lock(&priv->rxlock);
 
        gfar_halt(dev);
 
-       spin_unlock_irqrestore(&priv->lock, flags);
+       spin_unlock(&priv->rxlock);
+       spin_unlock_irqrestore(&priv->txlock, flags);
 
        /* Free the IRQs */
        if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) {
@@ -601,14 +678,15 @@ void gfar_start(struct net_device *dev)
        tempval |= DMACTRL_INIT_SETTINGS;
        gfar_write(&priv->regs->dmactrl, tempval);
 
-       /* Clear THLT, so that the DMA starts polling now */
-       gfar_write(&regs->tstat, TSTAT_CLEAR_THALT);
-
        /* Make sure we aren't stopped */
        tempval = gfar_read(&priv->regs->dmactrl);
        tempval &= ~(DMACTRL_GRS | DMACTRL_GTS);
        gfar_write(&priv->regs->dmactrl, tempval);
 
+       /* Clear THLT/RHLT, so that the DMA starts polling now */
+       gfar_write(&regs->tstat, TSTAT_CLEAR_THALT);
+       gfar_write(&regs->rstat, RSTAT_CLEAR_RHALT);
+
        /* Unmask the interrupts we look for */
        gfar_write(&regs->imask, IMASK_DEFAULT);
 }
@@ -618,7 +696,7 @@ int startup_gfar(struct net_device *dev)
 {
        struct txbd8 *txbdp;
        struct rxbd8 *rxbdp;
-       dma_addr_t addr;
+       dma_addr_t addr = 0;
        unsigned long vaddr;
        int i;
        struct gfar_private *priv = netdev_priv(dev);
@@ -854,8 +932,15 @@ tx_skb_fail:
 /* Returns 0 for success. */
 static int gfar_enet_open(struct net_device *dev)
 {
+#ifdef CONFIG_GFAR_NAPI
+       struct gfar_private *priv = netdev_priv(dev);
+#endif
        int err;
 
+#ifdef CONFIG_GFAR_NAPI
+       napi_enable(&priv->napi);
+#endif
+
        /* Initialize a bunch of registers */
        init_registers(dev);
 
@@ -863,10 +948,20 @@ static int gfar_enet_open(struct net_device *dev)
 
        err = init_phy(dev);
 
-       if(err)
+       if(err) {
+#ifdef CONFIG_GFAR_NAPI
+               napi_disable(&priv->napi);
+#endif
                return err;
+       }
 
        err = startup_gfar(dev);
+       if (err) {
+#ifdef CONFIG_GFAR_NAPI
+               napi_disable(&priv->napi);
+#endif
+               return err;
+       }
 
        netif_start_queue(dev);
 
@@ -894,18 +989,18 @@ static inline void gfar_tx_checksum(struct sk_buff *skb, struct txfcb *fcb)
 
        /* Tell the controller what the protocol is */
        /* And provide the already calculated phcs */
-       if (skb->nh.iph->protocol == IPPROTO_UDP) {
+       if (ip_hdr(skb)->protocol == IPPROTO_UDP) {
                flags |= TXFCB_UDP;
-               fcb->phcs = skb->h.uh->check;
+               fcb->phcs = udp_hdr(skb)->check;
        } else
-               fcb->phcs = skb->h.th->check;
+               fcb->phcs = tcp_hdr(skb)->check;
 
        /* l3os is the distance between the start of the
         * frame (skb->data) and the start of the IP hdr.
         * l4os is the distance between the start of the
         * l3 hdr and the l4 hdr */
-       fcb->l3os = (u16)(skb->nh.raw - skb->data - GMAC_FCB_LEN);
-       fcb->l4os = (u16)(skb->h.raw - skb->nh.raw);
+       fcb->l3os = (u16)(skb_network_offset(skb) - GMAC_FCB_LEN);
+       fcb->l4os = skb_network_header_len(skb);
 
        fcb->flags = flags;
 }
@@ -924,12 +1019,13 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
        struct txfcb *fcb = NULL;
        struct txbd8 *txbdp;
        u16 status;
+       unsigned long flags;
 
        /* Update transmit stats */
-       priv->stats.tx_bytes += skb->len;
+       dev->stats.tx_bytes += skb->len;
 
        /* Lock priv now */
-       spin_lock_irq(&priv->lock);
+       spin_lock_irqsave(&priv->txlock, flags);
 
        /* Point at the first free tx descriptor */
        txbdp = priv->cur_tx;
@@ -939,7 +1035,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        /* Set up checksumming */
        if (likely((dev->features & NETIF_F_IP_CSUM)
-                       && (CHECKSUM_HW == skb->ip_summed))) {
+                       && (CHECKSUM_PARTIAL == skb->ip_summed))) {
                fcb = gfar_add_fcb(skb, txbdp);
                status |= TXBD_TOE;
                gfar_tx_checksum(skb, fcb);
@@ -976,6 +1072,15 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        dev->trans_start = jiffies;
 
+       /* The powerpc-specific eieio() is used, as wmb() has too strong
+        * semantics (it requires synchronization between cacheable and
+        * uncacheable mappings, which eieio doesn't provide and which we
+        * don't need), thus requiring a more expensive sync instruction.  At
+        * some point, the set of architecture-independent barrier functions
+        * should be expanded to include weaker barriers.
+        */
+
+       eieio();
        txbdp->status = status;
 
        /* If this was the last BD in the ring, the next one */
@@ -990,7 +1095,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
        if (txbdp == priv->dirty_tx) {
                netif_stop_queue(dev);
 
-               priv->stats.tx_fifo_errors++;
+               dev->stats.tx_fifo_errors++;
        }
 
        /* Update the current txbd to the next one */
@@ -1000,7 +1105,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
        gfar_write(&priv->regs->tstat, TSTAT_CLEAR_THALT);
 
        /* Unlock priv */
-       spin_unlock_irq(&priv->lock);
+       spin_unlock_irqrestore(&priv->txlock, flags);
 
        return 0;
 }
@@ -1009,6 +1114,11 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
 static int gfar_close(struct net_device *dev)
 {
        struct gfar_private *priv = netdev_priv(dev);
+
+#ifdef CONFIG_GFAR_NAPI
+       napi_disable(&priv->napi);
+#endif
+
        stop_gfar(dev);
 
        /* Disconnect from the PHY */
@@ -1020,14 +1130,6 @@ static int gfar_close(struct net_device *dev)
        return 0;
 }
 
-/* returns a net_device_stats structure pointer */
-static struct net_device_stats * gfar_get_stats(struct net_device *dev)
-{
-       struct gfar_private *priv = netdev_priv(dev);
-
-       return &(priv->stats);
-}
-
 /* Changes the mac address if the controller is not running. */
 int gfar_set_mac_address(struct net_device *dev)
 {
@@ -1045,7 +1147,7 @@ static void gfar_vlan_rx_register(struct net_device *dev,
        unsigned long flags;
        u32 tempval;
 
-       spin_lock_irqsave(&priv->lock, flags);
+       spin_lock_irqsave(&priv->rxlock, flags);
 
        priv->vlgrp = grp;
 
@@ -1055,7 +1157,7 @@ static void gfar_vlan_rx_register(struct net_device *dev,
                tempval |= TCTRL_VLINS;
 
                gfar_write(&priv->regs->tctrl, tempval);
-               
+
                /* Enable VLAN tag extraction */
                tempval = gfar_read(&priv->regs->rctrl);
                tempval |= RCTRL_VLEX;
@@ -1072,24 +1174,9 @@ static void gfar_vlan_rx_register(struct net_device *dev,
                gfar_write(&priv->regs->rctrl, tempval);
        }
 
-       spin_unlock_irqrestore(&priv->lock, flags);
+       spin_unlock_irqrestore(&priv->rxlock, flags);
 }
 
-
-static void gfar_vlan_rx_kill_vid(struct net_device *dev, uint16_t vid)
-{
-       struct gfar_private *priv = netdev_priv(dev);
-       unsigned long flags;
-
-       spin_lock_irqsave(&priv->lock, flags);
-
-       if (priv->vlgrp)
-               priv->vlgrp->vlan_devices[vid] = NULL;
-
-       spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-
 static int gfar_change_mtu(struct net_device *dev, int new_mtu)
 {
        int tempsize, tempval;
@@ -1152,9 +1239,7 @@ static int gfar_change_mtu(struct net_device *dev, int new_mtu)
  * starting over will fix the problem. */
 static void gfar_timeout(struct net_device *dev)
 {
-       struct gfar_private *priv = netdev_priv(dev);
-
-       priv->stats.tx_errors++;
+       dev->stats.tx_errors++;
 
        if (dev->flags & IFF_UP) {
                stop_gfar(dev);
@@ -1165,7 +1250,7 @@ static void gfar_timeout(struct net_device *dev)
 }
 
 /* Interrupt Handler for Transmit complete */
-static irqreturn_t gfar_transmit(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t gfar_transmit(int irq, void *dev_id)
 {
        struct net_device *dev = (struct net_device *) dev_id;
        struct gfar_private *priv = netdev_priv(dev);
@@ -1175,7 +1260,7 @@ static irqreturn_t gfar_transmit(int irq, void *dev_id, struct pt_regs *regs)
        gfar_write(&priv->regs->ievent, IEVENT_TX_MASK);
 
        /* Lock priv */
-       spin_lock(&priv->lock);
+       spin_lock(&priv->txlock);
        bdp = priv->dirty_tx;
        while ((bdp->status & TXBD_READY) == 0) {
                /* If dirty_tx and cur_tx are the same, then either the */
@@ -1184,12 +1269,12 @@ static irqreturn_t gfar_transmit(int irq, void *dev_id, struct pt_regs *regs)
                if ((bdp == priv->cur_tx) && (netif_queue_stopped(dev) == 0))
                        break;
 
-               priv->stats.tx_packets++;
+               dev->stats.tx_packets++;
 
                /* Deferred means some collisions occurred during transmit, */
                /* but we eventually sent the packet. */
                if (bdp->status & TXBD_DEF)
-                       priv->stats.collisions++;
+                       dev->stats.collisions++;
 
                /* Free the sk buffer associated with this TxBD */
                dev_kfree_skb_irq(priv->tx_skbuff[priv->skb_dirtytx]);
@@ -1220,7 +1305,7 @@ static irqreturn_t gfar_transmit(int irq, void *dev_id, struct pt_regs *regs)
        else
                gfar_write(&priv->regs->txic, 0);
 
-       spin_unlock(&priv->lock);
+       spin_unlock(&priv->txlock);
 
        return IRQ_HANDLED;
 }
@@ -1240,29 +1325,29 @@ struct sk_buff * gfar_new_skb(struct net_device *dev, struct rxbd8 *bdp)
                return NULL;
 
        alignamount = RXBUF_ALIGNMENT -
-               (((unsigned) skb->data) & (RXBUF_ALIGNMENT - 1));
+               (((unsigned long) skb->data) & (RXBUF_ALIGNMENT - 1));
 
        /* 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, alignamount);
 
-       skb->dev = dev;
-
        bdp->bufPtr = dma_map_single(NULL, skb->data,
                        priv->rx_buffer_size, DMA_FROM_DEVICE);
 
        bdp->length = 0;
 
        /* Mark the buffer empty */
+       eieio();
        bdp->status |= (RXBD_EMPTY | RXBD_INTERRUPT);
 
        return skb;
 }
 
-static inline void count_errors(unsigned short status, struct gfar_private *priv)
+static inline void count_errors(unsigned short status, struct net_device *dev)
 {
-       struct net_device_stats *stats = &priv->stats;
+       struct gfar_private *priv = netdev_priv(dev);
+       struct net_device_stats *stats = &dev->stats;
        struct gfar_extra_stats *estats = &priv->extra_stats;
 
        /* If the packet was truncated, none of the other errors
@@ -1297,13 +1382,14 @@ static inline void count_errors(unsigned short status, struct gfar_private *priv
        }
 }
 
-irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t gfar_receive(int irq, void *dev_id)
 {
        struct net_device *dev = (struct net_device *) dev_id;
        struct gfar_private *priv = netdev_priv(dev);
-
 #ifdef CONFIG_GFAR_NAPI
        u32 tempval;
+#else
+       unsigned long flags;
 #endif
 
        /* Clear IEVENT, so rx interrupt isn't called again
@@ -1312,12 +1398,12 @@ irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs)
 
        /* support NAPI */
 #ifdef CONFIG_GFAR_NAPI
-       if (netif_rx_schedule_prep(dev)) {
+       if (netif_rx_schedule_prep(dev, &priv->napi)) {
                tempval = gfar_read(&priv->regs->imask);
                tempval &= IMASK_RX_DISABLED;
                gfar_write(&priv->regs->imask, tempval);
 
-               __netif_rx_schedule(dev);
+               __netif_rx_schedule(dev, &priv->napi);
        } else {
                if (netif_msg_rx_err(priv))
                        printk(KERN_DEBUG "%s: receive called twice (%x)[%x]\n",
@@ -1326,7 +1412,7 @@ irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs)
        }
 #else
 
-       spin_lock(&priv->lock);
+       spin_lock_irqsave(&priv->rxlock, flags);
        gfar_clean_rx_ring(dev, priv->rx_ring_size);
 
        /* If we are coalescing interrupts, update the timer */
@@ -1337,7 +1423,7 @@ irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs)
        else
                gfar_write(&priv->regs->rxic, 0);
 
-       spin_unlock(&priv->lock);
+       spin_unlock_irqrestore(&priv->rxlock, flags);
 #endif
 
        return IRQ_HANDLED;
@@ -1386,7 +1472,7 @@ static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
        if (NULL == skb) {
                if (netif_msg_rx_err(priv))
                        printk(KERN_WARNING "%s: Missing skb!!.\n", dev->name);
-               priv->stats.rx_dropped++;
+               dev->stats.rx_dropped++;
                priv->extra_stats.rx_skbmissing++;
        } else {
                int ret;
@@ -1437,13 +1523,14 @@ int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit)
        bdp = priv->cur_rx;
 
        while (!((bdp->status & RXBD_EMPTY) || (--rx_work_limit < 0))) {
+               rmb();
                skb = priv->rx_skbuff[priv->skb_currx];
 
                if (!(bdp->status &
                      (RXBD_LARGE | RXBD_SHORT | RXBD_NONOCTET
                       | RXBD_CRCERR | RXBD_OVERRUN | RXBD_TRUNCATED))) {
                        /* Increment the number of packets */
-                       priv->stats.rx_packets++;
+                       dev->stats.rx_packets++;
                        howmany++;
 
                        /* Remove the FCS from the packet length */
@@ -1451,9 +1538,9 @@ int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit)
 
                        gfar_process_frame(dev, skb, pkt_len);
 
-                       priv->stats.rx_bytes += pkt_len;
+                       dev->stats.rx_bytes += pkt_len;
                } else {
-                       count_errors(bdp->status, priv);
+                       count_errors(bdp->status, dev);
 
                        if (skb)
                                dev_kfree_skb_any(skb);
@@ -1486,34 +1573,20 @@ int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit)
        /* Update the current rxbd pointer to be the next one */
        priv->cur_rx = bdp;
 
-       /* If no packets have arrived since the
-        * last one we processed, clear the IEVENT RX and
-        * BSY bits so that another interrupt won't be
-        * generated when we set IMASK */
-       if (bdp->status & RXBD_EMPTY)
-               gfar_write(&priv->regs->ievent, IEVENT_RX_MASK);
-
        return howmany;
 }
 
 #ifdef CONFIG_GFAR_NAPI
-static int gfar_poll(struct net_device *dev, int *budget)
+static int gfar_poll(struct napi_struct *napi, int budget)
 {
+       struct gfar_private *priv = container_of(napi, struct gfar_private, napi);
+       struct net_device *dev = priv->dev;
        int howmany;
-       struct gfar_private *priv = netdev_priv(dev);
-       int rx_work_limit = *budget;
-
-       if (rx_work_limit > dev->quota)
-               rx_work_limit = dev->quota;
-
-       howmany = gfar_clean_rx_ring(dev, rx_work_limit);
 
-       dev->quota -= howmany;
-       rx_work_limit -= howmany;
-       *budget -= howmany;
+       howmany = gfar_clean_rx_ring(dev, budget);
 
-       if (rx_work_limit >= 0) {
-               netif_rx_complete(dev);
+       if (howmany < budget) {
+               netif_rx_complete(dev, napi);
 
                /* Clear the halt bit in RSTAT */
                gfar_write(&priv->regs->rstat, RSTAT_CLEAR_RHALT);
@@ -1529,12 +1602,39 @@ static int gfar_poll(struct net_device *dev, int *budget)
                        gfar_write(&priv->regs->rxic, 0);
        }
 
-       return (rx_work_limit < 0) ? 1 : 0;
+       return howmany;
+}
+#endif
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/*
+ * Polling 'interrupt' - used by things like netconsole to send skbs
+ * without having to re-enable interrupts. It's not called while
+ * the interrupt routine is executing.
+ */
+static void gfar_netpoll(struct net_device *dev)
+{
+       struct gfar_private *priv = netdev_priv(dev);
+
+       /* If the device has multiple interrupts, run tx/rx */
+       if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) {
+               disable_irq(priv->interruptTransmit);
+               disable_irq(priv->interruptReceive);
+               disable_irq(priv->interruptError);
+               gfar_interrupt(priv->interruptTransmit, dev);
+               enable_irq(priv->interruptError);
+               enable_irq(priv->interruptReceive);
+               enable_irq(priv->interruptTransmit);
+       } else {
+               disable_irq(priv->interruptTransmit);
+               gfar_interrupt(priv->interruptTransmit, dev);
+               enable_irq(priv->interruptTransmit);
+       }
 }
 #endif
 
 /* The interrupt handler for devices with one interrupt */
-static irqreturn_t gfar_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t gfar_interrupt(int irq, void *dev_id)
 {
        struct net_device *dev = dev_id;
        struct gfar_private *priv = netdev_priv(dev);
@@ -1542,71 +1642,17 @@ static irqreturn_t gfar_interrupt(int irq, void *dev_id, struct pt_regs *regs)
        /* Save ievent for future reference */
        u32 events = gfar_read(&priv->regs->ievent);
 
-       /* Clear IEVENT */
-       gfar_write(&priv->regs->ievent, events);
-
        /* Check for reception */
-       if ((events & IEVENT_RXF0) || (events & IEVENT_RXB0))
-               gfar_receive(irq, dev_id, regs);
+       if (events & IEVENT_RX_MASK)
+               gfar_receive(irq, dev_id);
 
        /* Check for transmit completion */
-       if ((events & IEVENT_TXF) || (events & IEVENT_TXB))
-               gfar_transmit(irq, dev_id, regs);
-
-       /* Update error statistics */
-       if (events & IEVENT_TXE) {
-               priv->stats.tx_errors++;
-
-               if (events & IEVENT_LC)
-                       priv->stats.tx_window_errors++;
-               if (events & IEVENT_CRL)
-                       priv->stats.tx_aborted_errors++;
-               if (events & IEVENT_XFUN) {
-                       if (netif_msg_tx_err(priv))
-                               printk(KERN_WARNING "%s: tx underrun. dropped packet\n", dev->name);
-                       priv->stats.tx_dropped++;
-                       priv->extra_stats.tx_underrun++;
-
-                       /* Reactivate the Tx Queues */
-                       gfar_write(&priv->regs->tstat, TSTAT_CLEAR_THALT);
-               }
-       }
-       if (events & IEVENT_BSY) {
-               priv->stats.rx_errors++;
-               priv->extra_stats.rx_bsy++;
-
-               gfar_receive(irq, dev_id, regs);
-
-#ifndef CONFIG_GFAR_NAPI
-               /* Clear the halt bit in RSTAT */
-               gfar_write(&priv->regs->rstat, RSTAT_CLEAR_RHALT);
-#endif
-
-               if (netif_msg_rx_err(priv))
-                       printk(KERN_DEBUG "%s: busy error (rhalt: %x)\n",
-                                       dev->name,
-                                       gfar_read(&priv->regs->rstat));
-       }
-       if (events & IEVENT_BABR) {
-               priv->stats.rx_errors++;
-               priv->extra_stats.rx_babr++;
+       if (events & IEVENT_TX_MASK)
+               gfar_transmit(irq, dev_id);
 
-               if (netif_msg_rx_err(priv))
-                       printk(KERN_DEBUG "%s: babbling error\n", dev->name);
-       }
-       if (events & IEVENT_EBERR) {
-               priv->extra_stats.eberr++;
-               if (netif_msg_rx_err(priv))
-                       printk(KERN_DEBUG "%s: EBERR\n", dev->name);
-       }
-       if ((events & IEVENT_RXC) && (netif_msg_rx_err(priv)))
-                       printk(KERN_DEBUG "%s: control frame\n", dev->name);
-
-       if (events & IEVENT_BABT) {
-               priv->extra_stats.tx_babt++;
-               if (netif_msg_rx_err(priv))
-                       printk(KERN_DEBUG "%s: babt error\n", dev->name);
-       }
+       /* Check for errors */
+       if (events & IEVENT_ERR_MASK)
+               gfar_error(irq, dev_id);
 
        return IRQ_HANDLED;
 }
@@ -1625,7 +1671,7 @@ static void adjust_link(struct net_device *dev)
        struct phy_device *phydev = priv->phydev;
        int new_state = 0;
 
-       spin_lock_irqsave(&priv->lock, flags);
+       spin_lock_irqsave(&priv->txlock, flags);
        if (phydev->link) {
                u32 tempval = gfar_read(&regs->maccfg2);
                u32 ecntrl = gfar_read(&regs->ecntrl);
@@ -1690,7 +1736,7 @@ static void adjust_link(struct net_device *dev)
        if (new_state && netif_msg_link(priv))
                phy_print_status(phydev);
 
-       spin_unlock_irqrestore(&priv->lock, flags);
+       spin_unlock_irqrestore(&priv->txlock, flags);
 }
 
 /* Update the hash table based on the current list of multicast
@@ -1705,9 +1751,6 @@ static void gfar_set_multi(struct net_device *dev)
        u32 tempval;
 
        if(dev->flags & IFF_PROMISC) {
-               if (netif_msg_drv(priv))
-                       printk(KERN_INFO "%s: Entering promiscuous mode.\n",
-                                       dev->name);
                /* Set RCTRL to PROM */
                tempval = gfar_read(&regs->rctrl);
                tempval |= RCTRL_PROM;
@@ -1718,7 +1761,7 @@ static void gfar_set_multi(struct net_device *dev)
                tempval &= ~(RCTRL_PROM);
                gfar_write(&regs->rctrl, tempval);
        }
-       
+
        if(dev->flags & IFF_ALLMULTI) {
                /* Set the hash to rx all multicast frames */
                gfar_write(&regs->igaddr0, 0xffffffff);
@@ -1857,7 +1900,7 @@ static void gfar_set_mac_for_addr(struct net_device *dev, int num, u8 *addr)
 }
 
 /* GFAR error interrupt handler */
-static irqreturn_t gfar_error(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t gfar_error(int irq, void *dev_id)
 {
        struct net_device *dev = dev_id;
        struct gfar_private *priv = netdev_priv(dev);
@@ -1871,21 +1914,21 @@ static irqreturn_t gfar_error(int irq, void *dev_id, struct pt_regs *regs)
        /* Hmm... */
        if (netif_msg_rx_err(priv) || netif_msg_tx_err(priv))
                printk(KERN_DEBUG "%s: error interrupt (ievent=0x%08x imask=0x%08x)\n",
-                               dev->name, events, gfar_read(&priv->regs->imask));
+                      dev->name, events, gfar_read(&priv->regs->imask));
 
        /* Update the error counters */
        if (events & IEVENT_TXE) {
-               priv->stats.tx_errors++;
+               dev->stats.tx_errors++;
 
                if (events & IEVENT_LC)
-                       priv->stats.tx_window_errors++;
+                       dev->stats.tx_window_errors++;
                if (events & IEVENT_CRL)
-                       priv->stats.tx_aborted_errors++;
+                       dev->stats.tx_aborted_errors++;
                if (events & IEVENT_XFUN) {
                        if (netif_msg_tx_err(priv))
-                               printk(KERN_DEBUG "%s: underrun.  packet dropped.\n",
-                                               dev->name);
-                       priv->stats.tx_dropped++;
+                               printk(KERN_DEBUG "%s: TX FIFO underrun, "
+                                      "packet dropped.\n", dev->name);
+                       dev->stats.tx_dropped++;
                        priv->extra_stats.tx_underrun++;
 
                        /* Reactivate the Tx Queues */
@@ -1895,10 +1938,10 @@ static irqreturn_t gfar_error(int irq, void *dev_id, struct pt_regs *regs)
                        printk(KERN_DEBUG "%s: Transmit Error\n", dev->name);
        }
        if (events & IEVENT_BSY) {
-               priv->stats.rx_errors++;
+               dev->stats.rx_errors++;
                priv->extra_stats.rx_bsy++;
 
-               gfar_receive(irq, dev_id, regs);
+               gfar_receive(irq, dev_id);
 
 #ifndef CONFIG_GFAR_NAPI
                /* Clear the halt bit in RSTAT */
@@ -1906,30 +1949,28 @@ static irqreturn_t gfar_error(int irq, void *dev_id, struct pt_regs *regs)
 #endif
 
                if (netif_msg_rx_err(priv))
-                       printk(KERN_DEBUG "%s: busy error (rhalt: %x)\n",
-                                       dev->name,
-                                       gfar_read(&priv->regs->rstat));
+                       printk(KERN_DEBUG "%s: busy error (rstat: %x)\n",
+                              dev->name, gfar_read(&priv->regs->rstat));
        }
        if (events & IEVENT_BABR) {
-               priv->stats.rx_errors++;
+               dev->stats.rx_errors++;
                priv->extra_stats.rx_babr++;
 
                if (netif_msg_rx_err(priv))
-                       printk(KERN_DEBUG "%s: babbling error\n", dev->name);
+                       printk(KERN_DEBUG "%s: babbling RX error\n", dev->name);
        }
        if (events & IEVENT_EBERR) {
                priv->extra_stats.eberr++;
                if (netif_msg_rx_err(priv))
-                       printk(KERN_DEBUG "%s: EBERR\n", dev->name);
+                       printk(KERN_DEBUG "%s: bus error\n", dev->name);
        }
        if ((events & IEVENT_RXC) && netif_msg_rx_status(priv))
-               if (netif_msg_rx_status(priv))
-                       printk(KERN_DEBUG "%s: control frame\n", dev->name);
+               printk(KERN_DEBUG "%s: control frame\n", dev->name);
 
        if (events & IEVENT_BABT) {
                priv->extra_stats.tx_babt++;
                if (netif_msg_tx_err(priv))
-                       printk(KERN_DEBUG "%s: babt error\n", dev->name);
+                       printk(KERN_DEBUG "%s: babbling TX error\n", dev->name);
        }
        return IRQ_HANDLED;
 }
@@ -1954,7 +1995,7 @@ static int __init gfar_init(void)
 
        if (err)
                gfar_mdio_exit();
-       
+
        return err;
 }