netdev: remove HAVE_ leftovers
[safe/jmp/linux-2.6] / drivers / net / fec.c
index f8396fb..16a1d58 100644 (file)
@@ -86,8 +86,7 @@ static unsigned char  fec_mac_default[] = {
 #endif
 #endif /* CONFIG_M5272 */
 
-/* Forward declarations of some structures to support different PHYs
-*/
+/* Forward declarations of some structures to support different PHYs */
 
 typedef struct {
        uint mii_data;
@@ -123,8 +122,7 @@ typedef struct {
 #error "FEC: descriptor ring size constants too large"
 #endif
 
-/* Interrupt events/masks.
-*/
+/* Interrupt events/masks. */
 #define FEC_ENET_HBERR ((uint)0x80000000)      /* Heartbeat error */
 #define FEC_ENET_BABR  ((uint)0x40000000)      /* Babbling receiver */
 #define FEC_ENET_BABT  ((uint)0x20000000)      /* Babbling transmitter */
@@ -174,18 +172,18 @@ struct fec_enet_private {
        /* The saved address of a sent-in-place packet/buffer, for skfree(). */
        unsigned char *tx_bounce[TX_RING_SIZE];
        struct  sk_buff* tx_skbuff[TX_RING_SIZE];
+       struct  sk_buff* rx_skbuff[RX_RING_SIZE];
        ushort  skb_cur;
        ushort  skb_dirty;
 
-       /* CPM dual port RAM relative addresses.
-       */
+       /* CPM dual port RAM relative addresses */
        dma_addr_t      bd_dma;
-       /* Address of Rx and Tx buffers. */
+       /* Address of Rx and Tx buffers */
        struct bufdesc  *rx_bd_base;
        struct bufdesc  *tx_bd_base;
        /* The next free ring entry */
        struct bufdesc  *cur_rx, *cur_tx; 
-       /* The ring entries to be free()ed. */
+       /* The ring entries to be free()ed */
        struct bufdesc  *dirty_tx;
 
        uint    tx_full;
@@ -213,17 +211,13 @@ struct fec_enet_private {
        int     full_duplex;
 };
 
-static int fec_enet_open(struct net_device *dev);
-static int fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev);
 static void fec_enet_mii(struct net_device *dev);
 static irqreturn_t fec_enet_interrupt(int irq, void * dev_id);
 static void fec_enet_tx(struct net_device *dev);
 static void fec_enet_rx(struct net_device *dev);
 static int fec_enet_close(struct net_device *dev);
-static void set_multicast_list(struct net_device *dev);
 static void fec_restart(struct net_device *dev, int duplex);
 static void fec_stop(struct net_device *dev);
-static void fec_set_mac_address(struct net_device *dev);
 
 
 /* MII processing.  We keep this as simple as possible.  Requests are
@@ -245,19 +239,16 @@ static mii_list_t *mii_tail;
 static int     mii_queue(struct net_device *dev, int request,
                                void (*func)(uint, struct net_device *));
 
-/* Make MII read/write commands for the FEC.
-*/
+/* Make MII read/write commands for the FEC */
 #define mk_mii_read(REG)       (0x60020000 | ((REG & 0x1f) << 18))
 #define mk_mii_write(REG, VAL) (0x50020000 | ((REG & 0x1f) << 18) | \
                                                (VAL & 0xffff))
 #define mk_mii_end     0
 
-/* Transmitter timeout.
-*/
-#define TX_TIMEOUT (2*HZ)
+/* Transmitter timeout */
+#define TX_TIMEOUT (2 * HZ)
 
-/* Register definitions for the PHY.
-*/
+/* Register definitions for the PHY */
 
 #define MII_REG_CR          0  /* Control Register                         */
 #define MII_REG_SR          1  /* Status Register                          */
@@ -294,12 +285,13 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct fec_enet_private *fep = netdev_priv(dev);
        struct bufdesc *bdp;
+       void *bufaddr;
        unsigned short  status;
        unsigned long flags;
 
        if (!fep->link) {
                /* Link is down or autonegotiation is in progress. */
-               return 1;
+               return NETDEV_TX_BUSY;
        }
 
        spin_lock_irqsave(&fep->hw_lock, flags);
@@ -307,40 +299,36 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
        bdp = fep->cur_tx;
 
        status = bdp->cbd_sc;
-#ifndef final_version
+
        if (status & BD_ENET_TX_READY) {
                /* Ooops.  All transmit buffers are full.  Bail out.
                 * This should not happen, since dev->tbusy should be set.
                 */
                printk("%s: tx queue full!.\n", dev->name);
                spin_unlock_irqrestore(&fep->hw_lock, flags);
-               return 1;
+               return NETDEV_TX_BUSY;
        }
-#endif
 
-       /* Clear all of the status flags.
-        */
+       /* Clear all of the status flags */
        status &= ~BD_ENET_TX_STATS;
 
-       /* Set buffer length and buffer pointer.
-       */
-       bdp->cbd_bufaddr = __pa(skb->data);
+       /* Set buffer length and buffer pointer */
+       bufaddr = skb->data;
        bdp->cbd_datlen = skb->len;
 
        /*
-        *      On some FEC implementations data must be aligned on
-        *      4-byte boundaries. Use bounce buffers to copy data
-        *      and get it aligned. Ugh.
+        * On some FEC implementations data must be aligned on
+        * 4-byte boundaries. Use bounce buffers to copy data
+        * and get it aligned. Ugh.
         */
-       if (bdp->cbd_bufaddr & FEC_ALIGNMENT) {
+       if (((unsigned long) bufaddr) & FEC_ALIGNMENT) {
                unsigned int index;
                index = bdp - fep->tx_bd_base;
                memcpy(fep->tx_bounce[index], (void *)skb->data, skb->len);
-               bdp->cbd_bufaddr = __pa(fep->tx_bounce[index]);
+               bufaddr = fep->tx_bounce[index];
        }
 
-       /* Save skb pointer.
-       */
+       /* Save skb pointer */
        fep->tx_skbuff[fep->skb_cur] = skb;
 
        dev->stats.tx_bytes += skb->len;
@@ -349,13 +337,12 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
        /* Push the data cache so the CPM does not get stale memory
         * data.
         */
-       dma_sync_single(NULL, bdp->cbd_bufaddr,
-                       bdp->cbd_datlen, DMA_TO_DEVICE);
+       bdp->cbd_bufaddr = dma_map_single(&dev->dev, bufaddr,
+                       FEC_ENET_TX_FRSIZE, DMA_TO_DEVICE);
 
        /* Send it on its way.  Tell FEC it's ready, interrupt when done,
         * it's the last BD of the frame, and to put the CRC on the end.
         */
-
        status |= (BD_ENET_TX_READY | BD_ENET_TX_INTR
                        | BD_ENET_TX_LAST | BD_ENET_TX_TC);
        bdp->cbd_sc = status;
@@ -365,13 +352,11 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
        /* Trigger transmission start */
        writel(0, fep->hwp + FEC_X_DES_ACTIVE);
 
-       /* If this was the last BD in the ring, start at the beginning again.
-       */
-       if (status & BD_ENET_TX_WRAP) {
+       /* If this was the last BD in the ring, start at the beginning again. */
+       if (status & BD_ENET_TX_WRAP)
                bdp = fep->tx_bd_base;
-       } else {
+       else
                bdp++;
-       }
 
        if (bdp == fep->dirty_tx) {
                fep->tx_full = 1;
@@ -382,7 +367,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        spin_unlock_irqrestore(&fep->hw_lock, flags);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static void
@@ -390,48 +375,12 @@ fec_timeout(struct net_device *dev)
 {
        struct fec_enet_private *fep = netdev_priv(dev);
 
-       printk("%s: transmit timed out.\n", dev->name);
        dev->stats.tx_errors++;
-#ifndef final_version
-       {
-       int     i;
-       struct bufdesc *bdp;
 
-       printk("Ring data dump: cur_tx %lx%s, dirty_tx %lx cur_rx: %lx\n",
-              (unsigned long)fep->cur_tx, fep->tx_full ? " (full)" : "",
-              (unsigned long)fep->dirty_tx,
-              (unsigned long)fep->cur_rx);
-
-       bdp = fep->tx_bd_base;
-       printk(" tx: %u buffers\n",  TX_RING_SIZE);
-       for (i = 0 ; i < TX_RING_SIZE; i++) {
-               printk("  %08x: %04x %04x %08x\n",
-                      (uint) bdp,
-                      bdp->cbd_sc,
-                      bdp->cbd_datlen,
-                      (int) bdp->cbd_bufaddr);
-               bdp++;
-       }
-
-       bdp = fep->rx_bd_base;
-       printk(" rx: %lu buffers\n",  (unsigned long) RX_RING_SIZE);
-       for (i = 0 ; i < RX_RING_SIZE; i++) {
-               printk("  %08x: %04x %04x %08x\n",
-                      (uint) bdp,
-                      bdp->cbd_sc,
-                      bdp->cbd_datlen,
-                      (int) bdp->cbd_bufaddr);
-               bdp++;
-       }
-       }
-#endif
        fec_restart(dev, fep->full_duplex);
        netif_wake_queue(dev);
 }
 
-/* The interrupt handler.
- * This is called from the MPC core interrupt.
- */
 static irqreturn_t
 fec_enet_interrupt(int irq, void * dev_id)
 {
@@ -440,12 +389,10 @@ fec_enet_interrupt(int irq, void * dev_id)
        uint    int_events;
        irqreturn_t ret = IRQ_NONE;
 
-       /* Get the interrupt events that caused us to be here. */
        do {
                int_events = readl(fep->hwp + FEC_IEVENT);
                writel(int_events, fep->hwp + FEC_IEVENT);
 
-               /* Handle receive event in its own function. */
                if (int_events & FEC_ENET_RXF) {
                        ret = IRQ_HANDLED;
                        fec_enet_rx(dev);
@@ -480,11 +427,15 @@ fec_enet_tx(struct net_device *dev)
        struct  sk_buff *skb;
 
        fep = netdev_priv(dev);
-       spin_lock_irq(&fep->hw_lock);
+       spin_lock(&fep->hw_lock);
        bdp = fep->dirty_tx;
 
        while (((status = bdp->cbd_sc) & BD_ENET_TX_READY) == 0) {
-               if (bdp == fep->cur_tx && fep->tx_full == 0) break;
+               if (bdp == fep->cur_tx && fep->tx_full == 0)
+                       break;
+
+               dma_unmap_single(&dev->dev, bdp->cbd_bufaddr, FEC_ENET_TX_FRSIZE, DMA_TO_DEVICE);
+               bdp->cbd_bufaddr = 0;
 
                skb = fep->tx_skbuff[fep->skb_dirty];
                /* Check for errors. */
@@ -506,31 +457,27 @@ fec_enet_tx(struct net_device *dev)
                        dev->stats.tx_packets++;
                }
 
-#ifndef final_version
                if (status & BD_ENET_TX_READY)
                        printk("HEY! Enet xmit interrupt and TX_READY.\n");
-#endif
+
                /* Deferred means some collisions occurred during transmit,
                 * but we eventually sent the packet OK.
                 */
                if (status & BD_ENET_TX_DEF)
                        dev->stats.collisions++;
 
-               /* Free the sk buffer associated with this last transmit.
-                */
+               /* Free the sk buffer associated with this last transmit */
                dev_kfree_skb_any(skb);
                fep->tx_skbuff[fep->skb_dirty] = NULL;
                fep->skb_dirty = (fep->skb_dirty + 1) & TX_RING_MOD_MASK;
 
-               /* Update pointer to next buffer descriptor to be transmitted.
-                */
+               /* Update pointer to next buffer descriptor to be transmitted */
                if (status & BD_ENET_TX_WRAP)
                        bdp = fep->tx_bd_base;
                else
                        bdp++;
 
-               /* Since we have freed up a buffer, the ring is no longer
-                * full.
+               /* Since we have freed up a buffer, the ring is no longer full
                 */
                if (fep->tx_full) {
                        fep->tx_full = 0;
@@ -539,7 +486,7 @@ fec_enet_tx(struct net_device *dev)
                }
        }
        fep->dirty_tx = bdp;
-       spin_unlock_irq(&fep->hw_lock);
+       spin_unlock(&fep->hw_lock);
 }
 
 
@@ -562,121 +509,104 @@ fec_enet_rx(struct net_device *dev)
        flush_cache_all();
 #endif
 
-       spin_lock_irq(&fep->hw_lock);
+       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.
         */
        bdp = fep->cur_rx;
 
-while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) {
+       while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) {
 
-#ifndef final_version
-       /* Since we have allocated space to hold a complete frame,
-        * the last indicator should be set.
-        */
-       if ((status & BD_ENET_RX_LAST) == 0)
-               printk("FEC ENET: rcv is not +last\n");
-#endif
+               /* Since we have allocated space to hold a complete frame,
+                * the last indicator should be set.
+                */
+               if ((status & BD_ENET_RX_LAST) == 0)
+                       printk("FEC ENET: rcv is not +last\n");
 
-       if (!fep->opened)
-               goto rx_processing_done;
+               if (!fep->opened)
+                       goto rx_processing_done;
 
-       /* Check for errors. */
-       if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO |
+               /* Check for errors. */
+               if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO |
                           BD_ENET_RX_CR | BD_ENET_RX_OV)) {
-               dev->stats.rx_errors++;
-               if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH)) {
-               /* Frame too long or too short. */
-                       dev->stats.rx_length_errors++;
+                       dev->stats.rx_errors++;
+                       if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH)) {
+                               /* Frame too long or too short. */
+                               dev->stats.rx_length_errors++;
+                       }
+                       if (status & BD_ENET_RX_NO)     /* Frame alignment */
+                               dev->stats.rx_frame_errors++;
+                       if (status & BD_ENET_RX_CR)     /* CRC Error */
+                               dev->stats.rx_crc_errors++;
+                       if (status & BD_ENET_RX_OV)     /* FIFO overrun */
+                               dev->stats.rx_fifo_errors++;
                }
-               if (status & BD_ENET_RX_NO)     /* Frame alignment */
+
+               /* Report late collisions as a frame error.
+                * On this error, the BD is closed, but we don't know what we
+                * have in the buffer.  So, just drop this frame on the floor.
+                */
+               if (status & BD_ENET_RX_CL) {
+                       dev->stats.rx_errors++;
                        dev->stats.rx_frame_errors++;
-               if (status & BD_ENET_RX_CR)     /* CRC Error */
-                       dev->stats.rx_crc_errors++;
-               if (status & BD_ENET_RX_OV)     /* FIFO overrun */
-                       dev->stats.rx_fifo_errors++;
-       }
+                       goto rx_processing_done;
+               }
 
-       /* Report late collisions as a frame error.
-        * On this error, the BD is closed, but we don't know what we
-        * have in the buffer.  So, just drop this frame on the floor.
-        */
-       if (status & BD_ENET_RX_CL) {
-               dev->stats.rx_errors++;
-               dev->stats.rx_frame_errors++;
-               goto rx_processing_done;
-       }
+               /* Process the incoming frame. */
+               dev->stats.rx_packets++;
+               pkt_len = bdp->cbd_datlen;
+               dev->stats.rx_bytes += pkt_len;
+               data = (__u8*)__va(bdp->cbd_bufaddr);
 
-       /* Process the incoming frame.
-        */
-       dev->stats.rx_packets++;
-       pkt_len = bdp->cbd_datlen;
-       dev->stats.rx_bytes += pkt_len;
-       data = (__u8*)__va(bdp->cbd_bufaddr);
-
-       dma_sync_single(NULL, (unsigned long)__pa(data),
-                       pkt_len - 4, DMA_FROM_DEVICE);
-
-       /* This does 16 byte alignment, exactly what we need.
-        * The packet length includes FCS, but we don't want to
-        * include that when passing upstream as it messes up
-        * bridging applications.
-        */
-       skb = dev_alloc_skb(pkt_len-4);
+               dma_unmap_single(NULL, bdp->cbd_bufaddr, bdp->cbd_datlen,
+                               DMA_FROM_DEVICE);
 
-       if (skb == NULL) {
-               printk("%s: Memory squeeze, dropping packet.\n", dev->name);
-               dev->stats.rx_dropped++;
-       } else {
-               skb_put(skb,pkt_len-4); /* Make room */
-               skb_copy_to_linear_data(skb, data, pkt_len-4);
-               skb->protocol=eth_type_trans(skb,dev);
-               netif_rx(skb);
-       }
-  rx_processing_done:
+               /* This does 16 byte alignment, exactly what we need.
+                * The packet length includes FCS, but we don't want to
+                * include that when passing upstream as it messes up
+                * bridging applications.
+                */
+               skb = dev_alloc_skb(pkt_len - 4 + NET_IP_ALIGN);
 
-       /* Clear the status flags for this buffer.
-       */
-       status &= ~BD_ENET_RX_STATS;
+               if (unlikely(!skb)) {
+                       printk("%s: Memory squeeze, dropping packet.\n",
+                                       dev->name);
+                       dev->stats.rx_dropped++;
+               } else {
+                       skb_reserve(skb, NET_IP_ALIGN);
+                       skb_put(skb, pkt_len - 4);      /* Make room */
+                       skb_copy_to_linear_data(skb, data, pkt_len - 4);
+                       skb->protocol = eth_type_trans(skb, dev);
+                       netif_rx(skb);
+               }
 
-       /* Mark the buffer empty.
-       */
-       status |= BD_ENET_RX_EMPTY;
-       bdp->cbd_sc = status;
+               bdp->cbd_bufaddr = dma_map_single(NULL, data, bdp->cbd_datlen,
+                       DMA_FROM_DEVICE);
+rx_processing_done:
+               /* Clear the status flags for this buffer */
+               status &= ~BD_ENET_RX_STATS;
 
-       /* Update BD pointer to next entry.
-       */
-       if (status & BD_ENET_RX_WRAP)
-               bdp = fep->rx_bd_base;
-       else
-               bdp++;
+               /* Mark the buffer empty */
+               status |= BD_ENET_RX_EMPTY;
+               bdp->cbd_sc = status;
 
-#if 1
-       /* Doing this here will keep the FEC running while we process
-        * incoming frames.  On a heavily loaded network, we should be
-        * able to keep up at the expense of system resources.
-        */
-       writel(0, fep->hwp + FEC_R_DES_ACTIVE);
-#endif
-   } /* while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) */
+               /* Update BD pointer to next entry */
+               if (status & BD_ENET_RX_WRAP)
+                       bdp = fep->rx_bd_base;
+               else
+                       bdp++;
+               /* Doing this here will keep the FEC running while we process
+                * incoming frames.  On a heavily loaded network, we should be
+                * able to keep up at the expense of system resources.
+                */
+               writel(0, fep->hwp + FEC_R_DES_ACTIVE);
+       }
        fep->cur_rx = bdp;
 
-#if 0
-       /* Doing this here will allow us to process all frames in the
-        * ring before the FEC is allowed to put more there.  On a heavily
-        * loaded network, some frames may be lost.  Unfortunately, this
-        * increases the interrupt overhead since we can potentially work
-        * our way back to the interrupt return only to come right back
-        * here.
-        */
-       fecp->fec_r_des_active = 0;
-#endif
-
-       spin_unlock_irq(&fep->hw_lock);
+       spin_unlock(&fep->hw_lock);
 }
 
-
 /* called from interrupt context */
 static void
 fec_enet_mii(struct net_device *dev)
@@ -685,7 +615,7 @@ fec_enet_mii(struct net_device *dev)
        mii_list_t      *mip;
 
        fep = netdev_priv(dev);
-       spin_lock_irq(&fep->mii_lock);
+       spin_lock(&fep->mii_lock);
 
        if ((mip = mii_head) == NULL) {
                printk("MII and no head!\n");
@@ -703,21 +633,19 @@ fec_enet_mii(struct net_device *dev)
                writel(mip->mii_regval, fep->hwp + FEC_MII_DATA);
 
 unlock:
-       spin_unlock_irq(&fep->mii_lock);
+       spin_unlock(&fep->mii_lock);
 }
 
 static int
-mii_queue(struct net_device *dev, int regval, void (*func)(uint, struct net_device *))
+mii_queue_unlocked(struct net_device *dev, int regval,
+               void (*func)(uint, struct net_device *))
 {
        struct fec_enet_private *fep;
-       unsigned long   flags;
        mii_list_t      *mip;
        int             retval;
 
-       /* Add PHY address to register command.
-       */
+       /* Add PHY address to register command */
        fep = netdev_priv(dev);
-       spin_lock_irqsave(&fep->mii_lock, flags);
 
        regval |= fep->phy_addr << 23;
        retval = 0;
@@ -738,6 +666,19 @@ mii_queue(struct net_device *dev, int regval, void (*func)(uint, struct net_devi
                retval = 1;
        }
 
+       return retval;
+}
+
+static int
+mii_queue(struct net_device *dev, int regval,
+               void (*func)(uint, struct net_device *))
+{
+       struct fec_enet_private *fep;
+       unsigned long   flags;
+       int             retval;
+       fep = netdev_priv(dev);
+       spin_lock_irqsave(&fep->mii_lock, flags);
+       retval = mii_queue_unlocked(dev, regval, func);
        spin_unlock_irqrestore(&fep->mii_lock, flags);
        return retval;
 }
@@ -1213,20 +1154,11 @@ static void __inline__ fec_request_mii_intr(struct net_device *dev)
                printk("FEC: Could not allocate fec(MII) IRQ(66)!\n");
 }
 
-static void __inline__ fec_disable_phy_intr(void)
+static void __inline__ fec_disable_phy_intr(struct net_device *dev)
 {
-       volatile unsigned long *icrp;
-       icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR1);
-       *icrp = 0x08000000;
-}
-
-static void __inline__ fec_phy_ack_intr(void)
-{
-       volatile unsigned long *icrp;
-       /* Acknowledge the interrupt */
-       icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR1);
-       *icrp = 0x0d000000;
+       free_irq(66, dev);
 }
+#endif
 
 #ifdef CONFIG_M5272
 static void __inline__ fec_get_mac(struct net_device *dev)
@@ -1358,11 +1290,6 @@ static void mii_relink(struct work_struct *work)
                fec_restart(dev, duplex);
        } else
                fec_stop(dev);
-
-#if 0
-       enable_irq(fep->mii_irq);
-#endif
-
 }
 
 /* mii_queue_relink is called in interrupt context from mii_link_interrupt */
@@ -1371,12 +1298,12 @@ static void mii_queue_relink(uint mii_reg, struct net_device *dev)
        struct fec_enet_private *fep = netdev_priv(dev);
 
        /*
-       ** We cannot queue phy_task twice in the workqueue.  It
-       ** would cause an endless loop in the workqueue.
-       ** Fortunately, if the last mii_relink entry has not yet been
-       ** executed now, it will do the job for the current interrupt,
-       ** which is just what we want.
-       */
+        * We cannot queue phy_task twice in the workqueue.  It
+        * would cause an endless loop in the workqueue.
+        * Fortunately, if the last mii_relink entry has not yet been
+        * executed now, it will do the job for the current interrupt,
+        * which is just what we want.
+        */
        if (fep->mii_phy_task_queued)
                return;
 
@@ -1407,8 +1334,7 @@ phy_cmd_t const phy_cmd_config[] = {
        { mk_mii_end, }
        };
 
-/* Read remainder of PHY ID.
-*/
+/* Read remainder of PHY ID. */
 static void
 mii_discover_phy3(uint mii_reg, struct net_device *dev)
 {
@@ -1447,14 +1373,13 @@ mii_discover_phy(uint mii_reg, struct net_device *dev)
        if (fep->phy_addr < 32) {
                if ((phytype = (mii_reg & 0xffff)) != 0xffff && phytype != 0) {
 
-                       /* Got first part of ID, now get remainder.
-                       */
+                       /* Got first part of ID, now get remainder */
                        fep->phy_id = phytype << 16;
-                       mii_queue(dev, mk_mii_read(MII_REG_PHYIR2),
+                       mii_queue_unlocked(dev, mk_mii_read(MII_REG_PHYIR2),
                                                        mii_discover_phy3);
                } else {
                        fep->phy_addr++;
-                       mii_queue(dev, mk_mii_read(MII_REG_PHYIR1),
+                       mii_queue_unlocked(dev, mk_mii_read(MII_REG_PHYIR1),
                                                        mii_discover_phy);
                }
        } else {
@@ -1463,13 +1388,12 @@ mii_discover_phy(uint mii_reg, struct net_device *dev)
                writel(0, fep->hwp + FEC_MII_SPEED);
                fep->phy_speed = 0;
 #ifdef HAVE_mii_link_interrupt
-               fec_disable_phy_intr();
+               fec_disable_phy_intr(dev);
 #endif
        }
 }
 
-/* This interrupt occurs when the PHY detects a link change.
-*/
+/* This interrupt occurs when the PHY detects a link change */
 #ifdef HAVE_mii_link_interrupt
 static irqreturn_t
 mii_link_interrupt(int irq, void * dev_id)
@@ -1477,12 +1401,6 @@ mii_link_interrupt(int irq, void * dev_id)
        struct  net_device *dev = dev_id;
        struct fec_enet_private *fep = netdev_priv(dev);
 
-       fec_phy_ack_intr();
-
-#if 0
-       disable_irq(fep->mii_irq);  /* disable now, enable later */
-#endif
-
        mii_do_cmd(dev, fep->phy->ack_int);
        mii_do_cmd(dev, phy_cmd_relink);  /* restart and display status */
 
@@ -1490,19 +1408,91 @@ mii_link_interrupt(int irq, void * dev_id)
 }
 #endif
 
+static void fec_enet_free_buffers(struct net_device *dev)
+{
+       struct fec_enet_private *fep = netdev_priv(dev);
+       int i;
+       struct sk_buff *skb;
+       struct bufdesc  *bdp;
+
+       bdp = fep->rx_bd_base;
+       for (i = 0; i < RX_RING_SIZE; i++) {
+               skb = fep->rx_skbuff[i];
+
+               if (bdp->cbd_bufaddr)
+                       dma_unmap_single(&dev->dev, bdp->cbd_bufaddr,
+                                       FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE);
+               if (skb)
+                       dev_kfree_skb(skb);
+               bdp++;
+       }
+
+       bdp = fep->tx_bd_base;
+       for (i = 0; i < TX_RING_SIZE; i++)
+               kfree(fep->tx_bounce[i]);
+}
+
+static int fec_enet_alloc_buffers(struct net_device *dev)
+{
+       struct fec_enet_private *fep = netdev_priv(dev);
+       int i;
+       struct sk_buff *skb;
+       struct bufdesc  *bdp;
+
+       bdp = fep->rx_bd_base;
+       for (i = 0; i < RX_RING_SIZE; i++) {
+               skb = dev_alloc_skb(FEC_ENET_RX_FRSIZE);
+               if (!skb) {
+                       fec_enet_free_buffers(dev);
+                       return -ENOMEM;
+               }
+               fep->rx_skbuff[i] = skb;
+
+               bdp->cbd_bufaddr = dma_map_single(&dev->dev, skb->data,
+                               FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE);
+               bdp->cbd_sc = BD_ENET_RX_EMPTY;
+               bdp++;
+       }
+
+       /* Set the last buffer to wrap. */
+       bdp--;
+       bdp->cbd_sc |= BD_SC_WRAP;
+
+       bdp = fep->tx_bd_base;
+       for (i = 0; i < TX_RING_SIZE; i++) {
+               fep->tx_bounce[i] = kmalloc(FEC_ENET_TX_FRSIZE, GFP_KERNEL);
+
+               bdp->cbd_sc = 0;
+               bdp->cbd_bufaddr = 0;
+               bdp++;
+       }
+
+       /* Set the last buffer to wrap. */
+       bdp--;
+       bdp->cbd_sc |= BD_SC_WRAP;
+
+       return 0;
+}
+
 static int
 fec_enet_open(struct net_device *dev)
 {
        struct fec_enet_private *fep = netdev_priv(dev);
+       int ret;
 
        /* I should reset the ring buffers here, but I don't yet know
         * a simple way to do that.
         */
-       fec_set_mac_address(dev);
+
+       ret = fec_enet_alloc_buffers(dev);
+       if (ret)
+               return ret;
 
        fep->sequence_done = 0;
        fep->link = 0;
 
+       fec_restart(dev, 1);
+
        if (fep->phy) {
                mii_do_cmd(dev, fep->phy->ack_int);
                mii_do_cmd(dev, fep->phy->config);
@@ -1519,21 +1509,17 @@ fec_enet_open(struct net_device *dev)
                        schedule();
 
                mii_do_cmd(dev, fep->phy->startup);
-
-               /* Set the initial link state to true. A lot of hardware
-                * based on this device does not implement a PHY interrupt,
-                * so we are never notified of link change.
-                */
-               fep->link = 1;
-       } else {
-               fep->link = 1; /* lets just try it and see */
-               /* no phy,  go full duplex,  it's most likely a hub chip */
-               fec_restart(dev, 1);
        }
 
+       /* Set the initial link state to true. A lot of hardware
+        * based on this device does not implement a PHY interrupt,
+        * so we are never notified of link change.
+        */
+       fep->link = 1;
+
        netif_start_queue(dev);
        fep->opened = 1;
-       return 0;               /* Success */
+       return 0;
 }
 
 static int
@@ -1541,12 +1527,13 @@ fec_enet_close(struct net_device *dev)
 {
        struct fec_enet_private *fep = netdev_priv(dev);
 
-       /* Don't know what to do yet.
-       */
+       /* Don't know what to do yet. */
        fep->opened = 0;
        netif_stop_queue(dev);
        fec_stop(dev);
 
+        fec_enet_free_buffers(dev);
+
        return 0;
 }
 
@@ -1570,101 +1557,113 @@ static void set_multicast_list(struct net_device *dev)
        unsigned int i, j, bit, data, crc, tmp;
        unsigned char hash;
 
-       if (dev->flags&IFF_PROMISC) {
+       if (dev->flags & IFF_PROMISC) {
                tmp = readl(fep->hwp + FEC_R_CNTRL);
                tmp |= 0x8;
                writel(tmp, fep->hwp + FEC_R_CNTRL);
-       } else {
-               tmp = readl(fep->hwp + FEC_R_CNTRL);
-               tmp &= ~0x8;
-               writel(tmp, fep->hwp + FEC_R_CNTRL);
+               return;
+       }
 
-               if (dev->flags & IFF_ALLMULTI) {
-                       /* Catch all multicast addresses, so set the
-                        * filter to all 1's.
-                        */
-                       writel(0xffffffff, fep->hwp + FEC_GRP_HASH_TABLE_HIGH);
-                       writel(0xffffffff, fep->hwp + FEC_GRP_HASH_TABLE_LOW);
-               } else {
-                       /* Clear filter and add the addresses in hash register.
-                       */
-                       writel(0, fep->hwp + FEC_GRP_HASH_TABLE_HIGH);
-                       writel(0, fep->hwp + FEC_GRP_HASH_TABLE_LOW);
-
-                       dmi = dev->mc_list;
-
-                       for (j = 0; j < dev->mc_count; j++, dmi = dmi->next)
-                       {
-                               /* Only support group multicast for now.
-                               */
-                               if (!(dmi->dmi_addr[0] & 1))
-                                       continue;
-
-                               /* calculate crc32 value of mac address
-                               */
-                               crc = 0xffffffff;
-
-                               for (i = 0; i < dmi->dmi_addrlen; i++)
-                               {
-                                       data = dmi->dmi_addr[i];
-                                       for (bit = 0; bit < 8; bit++, data >>= 1)
-                                       {
-                                               crc = (crc >> 1) ^
-                                               (((crc ^ data) & 1) ? CRC32_POLY : 0);
-                                       }
-                               }
-
-                               /* only upper 6 bits (HASH_BITS) are used
-                                  which point to specific bit in he hash registers
-                               */
-                               hash = (crc >> (32 - HASH_BITS)) & 0x3f;
-
-                               if (hash > 31) {
-                                       tmp = readl(fep->hwp + FEC_GRP_HASH_TABLE_HIGH);
-                                       tmp |= 1 << (hash - 32);
-                                       writel(tmp, fep->hwp + FEC_GRP_HASH_TABLE_HIGH);
-                               } else {
-                                       tmp = readl(fep->hwp + FEC_GRP_HASH_TABLE_LOW);
-                                       tmp |= 1 << hash;
-                                       writel(tmp, fep->hwp + FEC_GRP_HASH_TABLE_LOW);
-                               }
+       tmp = readl(fep->hwp + FEC_R_CNTRL);
+       tmp &= ~0x8;
+       writel(tmp, fep->hwp + FEC_R_CNTRL);
+
+       if (dev->flags & IFF_ALLMULTI) {
+               /* Catch all multicast addresses, so set the
+                * filter to all 1's
+                */
+               writel(0xffffffff, fep->hwp + FEC_GRP_HASH_TABLE_HIGH);
+               writel(0xffffffff, fep->hwp + FEC_GRP_HASH_TABLE_LOW);
+
+               return;
+       }
+
+       /* Clear filter and add the addresses in hash register
+        */
+       writel(0, fep->hwp + FEC_GRP_HASH_TABLE_HIGH);
+       writel(0, fep->hwp + FEC_GRP_HASH_TABLE_LOW);
+
+       dmi = dev->mc_list;
+
+       for (j = 0; j < dev->mc_count; j++, dmi = dmi->next) {
+               /* Only support group multicast for now */
+               if (!(dmi->dmi_addr[0] & 1))
+                       continue;
+
+               /* calculate crc32 value of mac address */
+               crc = 0xffffffff;
+
+               for (i = 0; i < dmi->dmi_addrlen; i++) {
+                       data = dmi->dmi_addr[i];
+                       for (bit = 0; bit < 8; bit++, data >>= 1) {
+                               crc = (crc >> 1) ^
+                               (((crc ^ data) & 1) ? CRC32_POLY : 0);
                        }
                }
+
+               /* only upper 6 bits (HASH_BITS) are used
+                * which point to specific bit in he hash registers
+                */
+               hash = (crc >> (32 - HASH_BITS)) & 0x3f;
+
+               if (hash > 31) {
+                       tmp = readl(fep->hwp + FEC_GRP_HASH_TABLE_HIGH);
+                       tmp |= 1 << (hash - 32);
+                       writel(tmp, fep->hwp + FEC_GRP_HASH_TABLE_HIGH);
+               } else {
+                       tmp = readl(fep->hwp + FEC_GRP_HASH_TABLE_LOW);
+                       tmp |= 1 << hash;
+                       writel(tmp, fep->hwp + FEC_GRP_HASH_TABLE_LOW);
+               }
        }
 }
 
-/* Set a MAC change in hardware.
- */
-static void
-fec_set_mac_address(struct net_device *dev)
+/* Set a MAC change in hardware. */
+static int
+fec_set_mac_address(struct net_device *dev, void *p)
 {
        struct fec_enet_private *fep = netdev_priv(dev);
+       struct sockaddr *addr = p;
+
+       if (!is_valid_ether_addr(addr->sa_data))
+               return -EADDRNOTAVAIL;
+
+       memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
 
-       /* Set station address. */
        writel(dev->dev_addr[3] | (dev->dev_addr[2] << 8) |
                (dev->dev_addr[1] << 16) | (dev->dev_addr[0] << 24),
                fep->hwp + FEC_ADDR_LOW);
        writel((dev->dev_addr[5] << 16) | (dev->dev_addr[4] << 24),
                fep + FEC_ADDR_HIGH);
+       return 0;
 }
 
+static const struct net_device_ops fec_netdev_ops = {
+       .ndo_open               = fec_enet_open,
+       .ndo_stop               = fec_enet_close,
+       .ndo_start_xmit         = fec_enet_start_xmit,
+       .ndo_set_multicast_list = set_multicast_list,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_validate_addr      = eth_validate_addr,
+       .ndo_tx_timeout         = fec_timeout,
+       .ndo_set_mac_address    = fec_set_mac_address,
+};
+
  /*
   * XXX:  We need to clean up on failure exits here.
   *
   * index is only used in legacy code
   */
-int __init fec_enet_init(struct net_device *dev, int index)
+static int fec_enet_init(struct net_device *dev, int index)
 {
        struct fec_enet_private *fep = netdev_priv(dev);
-       unsigned long   mem_addr;
-       struct bufdesc *bdp, *cbd_base;
-       int             i, j;
+       struct bufdesc *cbd_base;
+       int i;
 
-       /* Allocate memory for buffer descriptors.
-       */
-       mem_addr = (unsigned long)dma_alloc_coherent(NULL, PAGE_SIZE,
-                       &fep->bd_dma, GFP_KERNEL);
-       if (mem_addr == 0) {
+       /* Allocate memory for buffer descriptors. */
+       cbd_base = dma_alloc_coherent(NULL, PAGE_SIZE, &fep->bd_dma,
+                       GFP_KERNEL);
+       if (!cbd_base) {
                printk("FEC: allocate descriptor memory failed?\n");
                return -ENOMEM;
        }
@@ -1676,11 +1675,6 @@ int __init fec_enet_init(struct net_device *dev, int index)
        fep->hwp = (void __iomem *)dev->base_addr;
        fep->netdev = dev;
 
-       /* Whack a reset.  We should wait for this.
-       */
-       writel(1, fep->hwp + FEC_ECNTRL);
-       udelay(10);
-
        /* Set the Ethernet address */
 #ifdef CONFIG_M5272
        fec_get_mac(dev);
@@ -1698,117 +1692,26 @@ int __init fec_enet_init(struct net_device *dev, int index)
        }
 #endif
 
-       cbd_base = (struct bufdesc *)mem_addr;
-
-       /* Set receive and transmit descriptor base.
-       */
+       /* Set receive and transmit descriptor base. */
        fep->rx_bd_base = cbd_base;
        fep->tx_bd_base = cbd_base + RX_RING_SIZE;
 
-       fep->dirty_tx = fep->cur_tx = fep->tx_bd_base;
-       fep->cur_rx = fep->rx_bd_base;
-
-       fep->skb_cur = fep->skb_dirty = 0;
-
-       /* Initialize the receive buffer descriptors.
-       */
-       bdp = fep->rx_bd_base;
-       for (i=0; i<FEC_ENET_RX_PAGES; i++) {
-
-               /* Allocate a page.
-               */
-               mem_addr = __get_free_page(GFP_KERNEL);
-               /* XXX: missing check for allocation failure */
-
-               /* Initialize the BD for every fragment in the page.
-               */
-               for (j=0; j<FEC_ENET_RX_FRPPG; j++) {
-                       bdp->cbd_sc = BD_ENET_RX_EMPTY;
-                       bdp->cbd_bufaddr = __pa(mem_addr);
-                       mem_addr += FEC_ENET_RX_FRSIZE;
-                       bdp++;
-               }
-       }
-
-       /* Set the last buffer to wrap.
-       */
-       bdp--;
-       bdp->cbd_sc |= BD_SC_WRAP;
-
-       /* ...and the same for transmmit.
-       */
-       bdp = fep->tx_bd_base;
-       for (i=0, j=FEC_ENET_TX_FRPPG; i<TX_RING_SIZE; i++) {
-               if (j >= FEC_ENET_TX_FRPPG) {
-                       mem_addr = __get_free_page(GFP_KERNEL);
-                       j = 1;
-               } else {
-                       mem_addr += FEC_ENET_TX_FRSIZE;
-                       j++;
-               }
-               fep->tx_bounce[i] = (unsigned char *) mem_addr;
-
-               /* Initialize the BD for every fragment in the page.
-               */
-               bdp->cbd_sc = 0;
-               bdp->cbd_bufaddr = 0;
-               bdp++;
-       }
-
-       /* Set the last buffer to wrap.
-       */
-       bdp--;
-       bdp->cbd_sc |= BD_SC_WRAP;
-
-       /* Set receive and transmit descriptor base.
-       */
-       writel(fep->bd_dma, fep->hwp + FEC_R_DES_START);
-       writel((unsigned long)fep->bd_dma + sizeof(struct bufdesc) * RX_RING_SIZE,
-                       fep->hwp + FEC_X_DES_START);
-
 #ifdef HAVE_mii_link_interrupt
        fec_request_mii_intr(dev);
 #endif
-
-       writel(0, fep->hwp + FEC_GRP_HASH_TABLE_HIGH);
-       writel(0, fep->hwp + FEC_GRP_HASH_TABLE_LOW);
-       writel(PKT_MAXBLR_SIZE, fep->hwp + FEC_R_BUFF_SIZE);
-       writel(2, fep->hwp + FEC_ECNTRL);
-       writel(0, fep->hwp + FEC_R_DES_ACTIVE);
-#ifndef CONFIG_M5272
-       writel(0, fep->hwp + FEC_HASH_TABLE_HIGH);
-       writel(0, fep->hwp + FEC_HASH_TABLE_LOW);
-#endif
-
-       /* The FEC Ethernet specific entries in the device structure. */
-       dev->open = fec_enet_open;
-       dev->hard_start_xmit = fec_enet_start_xmit;
-       dev->tx_timeout = fec_timeout;
+       /* The FEC Ethernet specific entries in the device structure */
        dev->watchdog_timeo = TX_TIMEOUT;
-       dev->stop = fec_enet_close;
-       dev->set_multicast_list = set_multicast_list;
+       dev->netdev_ops = &fec_netdev_ops;
 
        for (i=0; i<NMII-1; i++)
                mii_cmds[i].mii_next = &mii_cmds[i+1];
        mii_free = mii_cmds;
 
-       /* setup MII interface */
-       writel(OPT_FRAME_SIZE | 0x04, fep->hwp + FEC_R_CNTRL);
-       writel(0, fep->hwp + FEC_X_CNTRL);
-
-       /*
-        * Set MII speed to 2.5 MHz
-        */
+       /* Set MII speed to 2.5 MHz */
        fep->phy_speed = ((((clk_get_rate(fep->clk) / 2 + 4999999)
                                        / 2500000) / 2) & 0x3F) << 1;
-       writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
        fec_restart(dev, 0);
 
-       /* Clear and enable interrupts */
-       writel(0xffc00000, fep->hwp + FEC_IEVENT);
-       writel(FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII,
-                       fep->hwp + FEC_IMASK);
-
        /* Queue up command to detect the PHY and initialize the
         * remainder of the interface.
         */
@@ -1837,12 +1740,13 @@ fec_restart(struct net_device *dev, int duplex)
        /* Clear any outstanding interrupt. */
        writel(0xffc00000, fep->hwp + FEC_IEVENT);
 
-       /* Set station address. */
-       fec_set_mac_address(dev);
-
        /* Reset all multicast. */
        writel(0, fep->hwp + FEC_GRP_HASH_TABLE_HIGH);
        writel(0, fep->hwp + FEC_GRP_HASH_TABLE_LOW);
+#ifndef CONFIG_M5272
+       writel(0, fep->hwp + FEC_HASH_TABLE_HIGH);
+       writel(0, fep->hwp + FEC_HASH_TABLE_LOW);
+#endif
 
        /* Set maximum receive buffer size. */
        writel(PKT_MAXBLR_SIZE, fep->hwp + FEC_R_BUFF_SIZE);
@@ -1857,8 +1761,8 @@ fec_restart(struct net_device *dev, int duplex)
 
        /* Reset SKB transmit buffers. */
        fep->skb_cur = fep->skb_dirty = 0;
-       for (i=0; i<=TX_RING_MOD_MASK; i++) {
-               if (fep->tx_skbuff[i] != NULL) {
+       for (i = 0; i <= TX_RING_MOD_MASK; i++) {
+               if (fep->tx_skbuff[i]) {
                        dev_kfree_skb_any(fep->tx_skbuff[i]);
                        fep->tx_skbuff[i] = NULL;
                }
@@ -1866,20 +1770,20 @@ fec_restart(struct net_device *dev, int duplex)
 
        /* Initialize the receive buffer descriptors. */
        bdp = fep->rx_bd_base;
-       for (i=0; i<RX_RING_SIZE; i++) {
+       for (i = 0; i < RX_RING_SIZE; i++) {
 
                /* Initialize the BD for every fragment in the page. */
                bdp->cbd_sc = BD_ENET_RX_EMPTY;
                bdp++;
        }
 
-       /* Set the last buffer to wrap. */
+       /* Set the last buffer to wrap */
        bdp--;
        bdp->cbd_sc |= BD_SC_WRAP;
 
-       /* ...and the same for transmmit. */
+       /* ...and the same for transmit */
        bdp = fep->tx_bd_base;
-       for (i=0; i<TX_RING_SIZE; i++) {
+       for (i = 0; i < TX_RING_SIZE; i++) {
 
                /* Initialize the BD for every fragment in the page. */
                bdp->cbd_sc = 0;
@@ -1887,11 +1791,11 @@ fec_restart(struct net_device *dev, int duplex)
                bdp++;
        }
 
-       /* Set the last buffer to wrap. */
+       /* Set the last buffer to wrap */
        bdp--;
        bdp->cbd_sc |= BD_SC_WRAP;
 
-       /* Enable MII mode. */
+       /* Enable MII mode */
        if (duplex) {
                /* MII enable / FD enable */
                writel(OPT_FRAME_SIZE | 0x04, fep->hwp + FEC_R_CNTRL);
@@ -1903,14 +1807,14 @@ fec_restart(struct net_device *dev, int duplex)
        }
        fep->full_duplex = duplex;
 
-       /* Set MII speed. */
+       /* Set MII speed */
        writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
 
-       /* And last, enable the transmit and receive processing. */
+       /* And last, enable the transmit and receive processing */
        writel(2, fep->hwp + FEC_ECNTRL);
        writel(0, fep->hwp + FEC_R_DES_ACTIVE);
 
-       /* Enable interrupts we wish to service. */
+       /* Enable interrupts we wish to service */
        writel(FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII,
                        fep->hwp + FEC_IMASK);
 }
@@ -1920,9 +1824,7 @@ fec_stop(struct net_device *dev)
 {
        struct fec_enet_private *fep = netdev_priv(dev);
 
-       /*
-       ** We cannot expect a graceful transmit stop without link !!!
-       */
+       /* We cannot expect a graceful transmit stop without link !!! */
        if (fep->link) {
                writel(1, fep->hwp + FEC_X_CNTRL); /* Graceful transmit stop */
                udelay(10);