Merge branch 'for_paulus' of master.kernel.org:/pub/scm/linux/kernel/git/galak/powerpc
[pandora-kernel.git] / drivers / net / mv643xx_eth.c
index 6b4fff8..ea62a3e 100644 (file)
@@ -10,7 +10,7 @@
  *
  * Copyright (C) 2003 Ralf Baechle <ralf@linux-mips.org>
  *
- * Copyright (C) 2004-2005 MontaVista Software, Inc.
+ * Copyright (C) 2004-2006 MontaVista Software, Inc.
  *                        Dale Farnsworth <dale@farnsworth.org>
  *
  * Copyright (C) 2004 Steven J. Hill <sjhill1@rockwellcollins.com>
@@ -37,8 +37,6 @@
 #include <linux/tcp.h>
 #include <linux/udp.h>
 #include <linux/etherdevice.h>
-#include <linux/in.h>
-#include <linux/ip.h>
 
 #include <linux/bitops.h>
 #include <linux/delay.h>
 #include <asm/delay.h>
 #include "mv643xx_eth.h"
 
-/*
- * The first part is the high level driver of the gigE ethernet ports.
- */
-
-/* Constants */
-#define VLAN_HLEN              4
-#define FCS_LEN                        4
-#define DMA_ALIGN              8       /* hw requires 8-byte alignment */
-#define HW_IP_ALIGN            2       /* hw aligns IP header */
-#define WRAP                   HW_IP_ALIGN + ETH_HLEN + VLAN_HLEN + FCS_LEN
-#define RX_SKB_SIZE            ((dev->mtu + WRAP + 7) & ~0x7)
-
-#define INT_UNMASK_ALL                 0x0007ffff
-#define INT_UNMASK_ALL_EXT             0x0011ffff
-#define INT_MASK_ALL                   0x00000000
-#define INT_MASK_ALL_EXT               0x00000000
-#define INT_CAUSE_CHECK_BITS           INT_CAUSE_UNMASK_ALL
-#define INT_CAUSE_CHECK_BITS_EXT       INT_CAUSE_UNMASK_ALL_EXT
-
-#ifdef MV643XX_CHECKSUM_OFFLOAD_TX
-#define MAX_DESCS_PER_SKB      (MAX_SKB_FRAGS + 1)
-#else
-#define MAX_DESCS_PER_SKB      1
-#endif
-
-#define PHY_WAIT_ITERATIONS    1000    /* 1000 iterations * 10uS = 10mS max */
-#define PHY_WAIT_MICRO_SECONDS 10
-
 /* Static function declarations */
 static void eth_port_uc_addr_get(struct net_device *dev,
                                                unsigned char *MacAddr);
 static void eth_port_set_multicast_list(struct net_device *);
 static void mv643xx_eth_port_enable_tx(unsigned int port_num,
-                                               unsigned int channels);
+                                               unsigned int queues);
 static void mv643xx_eth_port_enable_rx(unsigned int port_num,
-                                               unsigned int channels);
+                                               unsigned int queues);
 static unsigned int mv643xx_eth_port_disable_tx(unsigned int port_num);
 static unsigned int mv643xx_eth_port_disable_rx(unsigned int port_num);
 static int mv643xx_eth_open(struct net_device *);
@@ -162,67 +132,53 @@ static int mv643xx_eth_change_mtu(struct net_device *dev, int new_mtu)
 }
 
 /*
- * mv643xx_eth_rx_task
+ * mv643xx_eth_rx_refill_descs
  *
  * Fills / refills RX queue on a certain gigabit ethernet port
  *
  * Input :     pointer to ethernet interface network device structure
  * Output :    N/A
  */
-static void mv643xx_eth_rx_task(void *data)
+static void mv643xx_eth_rx_refill_descs(struct net_device *dev)
 {
-       struct net_device *dev = (struct net_device *)data;
        struct mv643xx_private *mp = netdev_priv(dev);
        struct pkt_info pkt_info;
        struct sk_buff *skb;
        int unaligned;
 
-       if (test_and_set_bit(0, &mp->rx_task_busy))
-               panic("%s: Error in test_set_bit / clear_bit", dev->name);
-
-       while (mp->rx_desc_count < (mp->rx_ring_size - 5)) {
-               skb = dev_alloc_skb(RX_SKB_SIZE + DMA_ALIGN);
+       while (mp->rx_desc_count < mp->rx_ring_size) {
+               skb = dev_alloc_skb(ETH_RX_SKB_SIZE + ETH_DMA_ALIGN);
                if (!skb)
                        break;
                mp->rx_desc_count++;
-               unaligned = (u32)skb->data & (DMA_ALIGN - 1);
+               unaligned = (u32)skb->data & (ETH_DMA_ALIGN - 1);
                if (unaligned)
-                       skb_reserve(skb, DMA_ALIGN - unaligned);
+                       skb_reserve(skb, ETH_DMA_ALIGN - unaligned);
                pkt_info.cmd_sts = ETH_RX_ENABLE_INTERRUPT;
-               pkt_info.byte_cnt = RX_SKB_SIZE;
-               pkt_info.buf_ptr = dma_map_single(NULL, skb->data, RX_SKB_SIZE,
-                                                       DMA_FROM_DEVICE);
+               pkt_info.byte_cnt = ETH_RX_SKB_SIZE;
+               pkt_info.buf_ptr = dma_map_single(NULL, skb->data,
+                                       ETH_RX_SKB_SIZE, DMA_FROM_DEVICE);
                pkt_info.return_info = skb;
                if (eth_rx_return_buff(mp, &pkt_info) != ETH_OK) {
                        printk(KERN_ERR
                                "%s: Error allocating RX Ring\n", dev->name);
                        break;
                }
-               skb_reserve(skb, HW_IP_ALIGN);
+               skb_reserve(skb, ETH_HW_IP_ALIGN);
        }
-       clear_bit(0, &mp->rx_task_busy);
        /*
         * If RX ring is empty of SKB, set a timer to try allocating
-        * again in a later time .
+        * again at a later time.
         */
-       if ((mp->rx_desc_count == 0) && (mp->rx_timer_flag == 0)) {
+       if (mp->rx_desc_count == 0) {
                printk(KERN_INFO "%s: Rx ring is empty\n", dev->name);
-               /* After 100mSec */
-               mp->timeout.expires = jiffies + (HZ / 10);
+               mp->timeout.expires = jiffies + (HZ / 10);      /* 100 mSec */
                add_timer(&mp->timeout);
-               mp->rx_timer_flag = 1;
-       }
-#ifdef MV643XX_RX_QUEUE_FILL_ON_TASK
-       else {
-               /* Return interrupts */
-               mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(mp->port_num),
-                                                       INT_UNMASK_ALL);
        }
-#endif
 }
 
 /*
- * mv643xx_eth_rx_task_timer_wrapper
+ * mv643xx_eth_rx_refill_descs_timer_wrapper
  *
  * Timer routine to wake up RX queue filling task. This function is
  * used only in case the RX queue is empty, and all alloc_skb has
@@ -231,13 +187,9 @@ static void mv643xx_eth_rx_task(void *data)
  * Input :     pointer to ethernet interface network device structure
  * Output :    N/A
  */
-static void mv643xx_eth_rx_task_timer_wrapper(unsigned long data)
+static inline void mv643xx_eth_rx_refill_descs_timer_wrapper(unsigned long data)
 {
-       struct net_device *dev = (struct net_device *)data;
-       struct mv643xx_private *mp = netdev_priv(dev);
-
-       mp->rx_timer_flag = 0;
-       mv643xx_eth_rx_task((void *)data);
+       mv643xx_eth_rx_refill_descs((struct net_device *)data);
 }
 
 /*
@@ -329,55 +281,90 @@ static void mv643xx_eth_tx_timeout_task(struct net_device *dev)
 {
        struct mv643xx_private *mp = netdev_priv(dev);
 
-       netif_device_detach(dev);
+       if (!netif_running(dev))
+               return;
+
+       netif_stop_queue(dev);
+
        eth_port_reset(mp->port_num);
        eth_port_start(dev);
-       netif_device_attach(dev);
+
+       if (mp->tx_ring_size - mp->tx_desc_count >= MAX_DESCS_PER_SKB)
+               netif_wake_queue(dev);
 }
 
-/*
- * mv643xx_eth_free_tx_queue
+/**
+ * mv643xx_eth_free_tx_descs - Free the tx desc data for completed descriptors
  *
- * Input :     dev - a pointer to the required interface
- *
- * Output :    0 if was able to release skb , nonzero otherwise
+ * If force is non-zero, frees uncompleted descriptors as well
  */
-static int mv643xx_eth_free_tx_queue(struct net_device *dev,
-                                       unsigned int eth_int_cause_ext)
+int mv643xx_eth_free_tx_descs(struct net_device *dev, int force)
 {
        struct mv643xx_private *mp = netdev_priv(dev);
-       struct net_device_stats *stats = &mp->stats;
-       struct pkt_info pkt_info;
-       int released = 1;
+       struct eth_tx_desc *desc;
+       u32 cmd_sts;
+       struct sk_buff *skb;
+       unsigned long flags;
+       int tx_index;
+       dma_addr_t addr;
+       int count;
+       int released = 0;
+
+       while (mp->tx_desc_count > 0) {
+               spin_lock_irqsave(&mp->lock, flags);
+               tx_index = mp->tx_used_desc_q;
+               desc = &mp->p_tx_desc_area[tx_index];
+               cmd_sts = desc->cmd_sts;
+
+               if (!force && (cmd_sts & ETH_BUFFER_OWNED_BY_DMA)) {
+                       spin_unlock_irqrestore(&mp->lock, flags);
+                       return released;
+               }
+
+               mp->tx_used_desc_q = (tx_index + 1) % mp->tx_ring_size;
+               mp->tx_desc_count--;
 
-       if (!(eth_int_cause_ext & (BIT0 | BIT8)))
-               return released;
+               addr = desc->buf_ptr;
+               count = desc->byte_cnt;
+               skb = mp->tx_skb[tx_index];
+               if (skb)
+                       mp->tx_skb[tx_index] = NULL;
+
+               spin_unlock_irqrestore(&mp->lock, flags);
 
-       /* Check only queue 0 */
-       while (eth_tx_return_desc(mp, &pkt_info) == ETH_OK) {
-               if (pkt_info.cmd_sts & BIT0) {
+               if (cmd_sts & ETH_ERROR_SUMMARY) {
                        printk("%s: Error in TX\n", dev->name);
-                       stats->tx_errors++;
+                       mp->stats.tx_errors++;
                }
 
-               if (pkt_info.cmd_sts & ETH_TX_FIRST_DESC)
-                       dma_unmap_single(NULL, pkt_info.buf_ptr,
-                                       pkt_info.byte_cnt,
-                                       DMA_TO_DEVICE);
+               if (cmd_sts & ETH_TX_FIRST_DESC)
+                       dma_unmap_single(NULL, addr, count, DMA_TO_DEVICE);
                else
-                       dma_unmap_page(NULL, pkt_info.buf_ptr,
-                                       pkt_info.byte_cnt,
-                                       DMA_TO_DEVICE);
+                       dma_unmap_page(NULL, addr, count, DMA_TO_DEVICE);
 
-               if (pkt_info.return_info) {
-                       dev_kfree_skb_irq(pkt_info.return_info);
-                       released = 0;
-               }
+               if (skb)
+                       dev_kfree_skb_irq(skb);
+
+               released = 1;
        }
 
        return released;
 }
 
+static void mv643xx_eth_free_completed_tx_descs(struct net_device *dev)
+{
+       struct mv643xx_private *mp = netdev_priv(dev);
+
+       if (mv643xx_eth_free_tx_descs(dev, 0) &&
+           mp->tx_ring_size - mp->tx_desc_count >= MAX_DESCS_PER_SKB)
+               netif_wake_queue(dev);
+}
+
+static void mv643xx_eth_free_all_tx_descs(struct net_device *dev)
+{
+       mv643xx_eth_free_tx_descs(dev, 1);
+}
+
 /*
  * mv643xx_eth_receive
  *
@@ -389,11 +376,7 @@ static int mv643xx_eth_free_tx_queue(struct net_device *dev,
  *
  * Output :    number of served packets
  */
-#ifdef MV643XX_NAPI
 static int mv643xx_eth_receive_queue(struct net_device *dev, int budget)
-#else
-static int mv643xx_eth_receive_queue(struct net_device *dev)
-#endif
 {
        struct mv643xx_private *mp = netdev_priv(dev);
        struct net_device_stats *stats = &mp->stats;
@@ -401,15 +384,14 @@ static int mv643xx_eth_receive_queue(struct net_device *dev)
        struct sk_buff *skb;
        struct pkt_info pkt_info;
 
-#ifdef MV643XX_NAPI
        while (budget-- > 0 && eth_port_receive(mp, &pkt_info) == ETH_OK) {
-#else
-       while (eth_port_receive(mp, &pkt_info) == ETH_OK) {
-#endif
                mp->rx_desc_count--;
                received_packets++;
 
-               /* Update statistics. Note byte count includes 4 byte CRC count */
+               /*
+                * Update statistics.
+                * Note byte count includes 4 byte CRC count
+                */
                stats->rx_packets++;
                stats->rx_bytes += pkt_info.byte_cnt;
                skb = pkt_info.return_info;
@@ -457,6 +439,7 @@ static int mv643xx_eth_receive_queue(struct net_device *dev)
                }
                dev->last_rx = jiffies;
        }
+       mv643xx_eth_rx_refill_descs(dev);       /* Fill RX ring with skb's */
 
        return received_packets;
 }
@@ -468,7 +451,7 @@ static void mv643xx_eth_update_pscr(struct net_device *dev,
        struct mv643xx_private *mp = netdev_priv(dev);
        int port_num = mp->port_num;
        u32 o_pscr, n_pscr;
-       unsigned int channels;
+       unsigned int queues;
 
        o_pscr = mv_read(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num));
        n_pscr = o_pscr;
@@ -496,7 +479,7 @@ static void mv643xx_eth_update_pscr(struct net_device *dev,
                        mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num),
                                                                n_pscr);
                else {
-                       channels = mv643xx_eth_port_disable_tx(port_num);
+                       queues = mv643xx_eth_port_disable_tx(port_num);
 
                        o_pscr &= ~MV643XX_ETH_SERIAL_PORT_ENABLE;
                        mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num),
@@ -505,8 +488,8 @@ static void mv643xx_eth_update_pscr(struct net_device *dev,
                                                                n_pscr);
                        mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num),
                                                                n_pscr);
-                       if (channels)
-                               mv643xx_eth_port_enable_tx(port_num, channels);
+                       if (queues)
+                               mv643xx_eth_port_enable_tx(port_num, queues);
                }
        }
 }
@@ -532,80 +515,29 @@ static irqreturn_t mv643xx_eth_int_handler(int irq, void *dev_id,
 
        /* Read interrupt cause registers */
        eth_int_cause = mv_read(MV643XX_ETH_INTERRUPT_CAUSE_REG(port_num)) &
-                                               INT_UNMASK_ALL;
-
-       if (eth_int_cause & BIT1)
+                                               ETH_INT_UNMASK_ALL;
+       if (eth_int_cause & ETH_INT_CAUSE_EXT) {
                eth_int_cause_ext = mv_read(
                        MV643XX_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num)) &
-                                               INT_UNMASK_ALL_EXT;
-
-#ifdef MV643XX_NAPI
-       if (!(eth_int_cause & 0x0007fffd)) {
-               /* Dont ack the Rx interrupt */
-#endif
-               /*
-                * Clear specific ethernet port intrerrupt registers by
-                * acknowleding relevant bits.
-                */
-               mv_write(MV643XX_ETH_INTERRUPT_CAUSE_REG(port_num),
-                                                       ~eth_int_cause);
-               if (eth_int_cause_ext != 0x0)
-                       mv_write(MV643XX_ETH_INTERRUPT_CAUSE_EXTEND_REG
-                                       (port_num), ~eth_int_cause_ext);
-
-               /* UDP change : We may need this */
-               if ((eth_int_cause_ext & 0x0000ffff) &&
-                   (mv643xx_eth_free_tx_queue(dev, eth_int_cause_ext) == 0) &&
-                   (mp->tx_ring_size > mp->tx_desc_count + MAX_DESCS_PER_SKB))
-                       netif_wake_queue(dev);
-#ifdef MV643XX_NAPI
-       } else {
-               if (netif_rx_schedule_prep(dev)) {
-                       /* Mask all the interrupts */
-                       mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num),
-                                                               INT_MASK_ALL);
-                       /* wait for previous write to complete */
-                       mv_read(MV643XX_ETH_INTERRUPT_MASK_REG(port_num));
-                       __netif_rx_schedule(dev);
-               }
-#else
-               if (eth_int_cause & (BIT2 | BIT11))
-                       mv643xx_eth_receive_queue(dev, 0);
-
-               /*
-                * After forwarded received packets to upper layer, add a task
-                * in an interrupts enabled context that refills the RX ring
-                * with skb's.
-                */
-#ifdef MV643XX_RX_QUEUE_FILL_ON_TASK
-               /* Mask all interrupts on ethernet port */
-               mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num),
-                                                       INT_MASK_ALL);
-               /* wait for previous write to take effect */
-               mv_read(MV643XX_ETH_INTERRUPT_MASK_REG(port_num));
-
-               queue_task(&mp->rx_task, &tq_immediate);
-               mark_bh(IMMEDIATE_BH);
-#else
-               mp->rx_task.func(dev);
-#endif
-#endif
+                                               ETH_INT_UNMASK_ALL_EXT;
+               mv_write(MV643XX_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num),
+                                                       ~eth_int_cause_ext);
        }
+
        /* PHY status changed */
-       if (eth_int_cause_ext & (BIT16 | BIT20)) {
+       if (eth_int_cause_ext & ETH_INT_CAUSE_PHY) {
                struct ethtool_cmd cmd;
 
                if (mii_link_ok(&mp->mii)) {
                        mii_ethtool_gset(&mp->mii, &cmd);
                        mv643xx_eth_update_pscr(dev, &cmd);
+                       mv643xx_eth_port_enable_tx(port_num,
+                                                  ETH_TX_QUEUES_ENABLED);
                        if (!netif_carrier_ok(dev)) {
                                netif_carrier_on(dev);
-                               if (mp->tx_ring_size > mp->tx_desc_count +
-                                                       MAX_DESCS_PER_SKB) {
+                               if (mp->tx_ring_size - mp->tx_desc_count >=
+                                                       MAX_DESCS_PER_SKB)
                                        netif_wake_queue(dev);
-                                       /* Start TX queue */
-                                       mv643xx_eth_port_enable_tx(port_num, mp->port_tx_queue_command);
-                               }
                        }
                } else if (netif_carrier_ok(dev)) {
                        netif_stop_queue(dev);
@@ -613,6 +545,23 @@ static irqreturn_t mv643xx_eth_int_handler(int irq, void *dev_id,
                }
        }
 
+#ifdef MV643XX_NAPI
+       if (eth_int_cause & ETH_INT_CAUSE_RX) {
+               /* schedule the NAPI poll routine to maintain port */
+               mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num),
+                                                       ETH_INT_MASK_ALL);
+               /* wait for previous write to complete */
+               mv_read(MV643XX_ETH_INTERRUPT_MASK_REG(port_num));
+
+               netif_rx_schedule(dev);
+       }
+#else
+       if (eth_int_cause & ETH_INT_CAUSE_RX)
+               mv643xx_eth_receive_queue(dev, INT_MAX);
+#endif
+       if (eth_int_cause_ext & ETH_INT_CAUSE_TX)
+               mv643xx_eth_free_completed_tx_descs(dev);
+
        /*
         * If no real interrupt occured, exit.
         * This can happen when using gigE interrupt coalescing mechanism.
@@ -737,9 +686,6 @@ static void ether_init_rx_desc_ring(struct mv643xx_private *mp)
        mp->rx_used_desc_q = 0;
 
        mp->rx_desc_area_size = rx_desc_num * sizeof(struct eth_rx_desc);
-
-       /* Enable queue 0 for this port */
-       mp->port_rx_queue_command = 1;
 }
 
 /*
@@ -779,14 +725,8 @@ static void ether_init_tx_desc_ring(struct mv643xx_private *mp)
 
        mp->tx_curr_desc_q = 0;
        mp->tx_used_desc_q = 0;
-#ifdef MV643XX_CHECKSUM_OFFLOAD_TX
-       mp->tx_first_desc_q = 0;
-#endif
 
        mp->tx_desc_area_size = tx_desc_num * sizeof(struct eth_tx_desc);
-
-       /* Enable queue 0 for this port */
-       mp->port_tx_queue_command = 1;
 }
 
 static int mv643xx_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
@@ -847,15 +787,10 @@ static int mv643xx_eth_open(struct net_device *dev)
 
        eth_port_init(mp);
 
-       INIT_WORK(&mp->rx_task, (void (*)(void *))mv643xx_eth_rx_task, dev);
-
        memset(&mp->timeout, 0, sizeof(struct timer_list));
-       mp->timeout.function = mv643xx_eth_rx_task_timer_wrapper;
+       mp->timeout.function = mv643xx_eth_rx_refill_descs_timer_wrapper;
        mp->timeout.data = (unsigned long)dev;
 
-       mp->rx_task_busy = 0;
-       mp->rx_timer_flag = 0;
-
        /* Allocate RX and TX skb rings */
        mp->rx_skb = kmalloc(sizeof(*mp->rx_skb) * mp->rx_ring_size,
                                                                GFP_KERNEL);
@@ -928,7 +863,7 @@ static int mv643xx_eth_open(struct net_device *dev)
 
        ether_init_rx_desc_ring(mp);
 
-       mv643xx_eth_rx_task(dev);       /* Fill RX ring with skb's */
+       mv643xx_eth_rx_refill_descs(dev);       /* Fill RX ring with skb's */
 
        /* Clear any pending ethernet port interrupts */
        mv_write(MV643XX_ETH_INTERRUPT_CAUSE_REG(port_num), 0);
@@ -948,10 +883,10 @@ static int mv643xx_eth_open(struct net_device *dev)
 
        /* Unmask phy and link status changes interrupts */
        mv_write(MV643XX_ETH_INTERRUPT_EXTEND_MASK_REG(port_num),
-                                               INT_UNMASK_ALL_EXT);
+                                               ETH_INT_UNMASK_ALL_EXT);
 
        /* Unmask RX buffer and TX end interrupt */
-       mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), INT_UNMASK_ALL);
+       mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), ETH_INT_UNMASK_ALL);
 
        return 0;
 
@@ -968,25 +903,14 @@ out_free_irq:
 static void mv643xx_eth_free_tx_rings(struct net_device *dev)
 {
        struct mv643xx_private *mp = netdev_priv(dev);
-       unsigned int port_num = mp->port_num;
-       unsigned int curr;
-       struct sk_buff *skb;
 
        /* Stop Tx Queues */
-       mv643xx_eth_port_disable_tx(port_num);
+       mv643xx_eth_port_disable_tx(mp->port_num);
 
-       /* Free outstanding skb's on TX rings */
-       for (curr = 0; mp->tx_desc_count && curr < mp->tx_ring_size; curr++) {
-               skb = mp->tx_skb[curr];
-               if (skb) {
-                       mp->tx_desc_count -= skb_shinfo(skb)->nr_frags;
-                       dev_kfree_skb(skb);
-                       mp->tx_desc_count--;
-               }
-       }
-       if (mp->tx_desc_count)
-               printk("%s: Error on Tx descriptor free - could not free %d"
-                               " descriptors\n", dev->name, mp->tx_desc_count);
+       /* Free outstanding skb's on TX ring */
+       mv643xx_eth_free_all_tx_descs(dev);
+
+       BUG_ON(mp->tx_used_desc_q != mp->tx_curr_desc_q);
 
        /* Free TX ring */
        if (mp->tx_sram_size)
@@ -1042,7 +966,7 @@ static int mv643xx_eth_stop(struct net_device *dev)
        unsigned int port_num = mp->port_num;
 
        /* Mask all interrupts on ethernet port */
-       mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), INT_MASK_ALL);
+       mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), ETH_INT_MASK_ALL);
        /* wait for previous write to complete */
        mv_read(MV643XX_ETH_INTERRUPT_MASK_REG(port_num));
 
@@ -1067,31 +991,6 @@ static int mv643xx_eth_stop(struct net_device *dev)
 }
 
 #ifdef MV643XX_NAPI
-static void mv643xx_tx(struct net_device *dev)
-{
-       struct mv643xx_private *mp = netdev_priv(dev);
-       struct pkt_info pkt_info;
-
-       while (eth_tx_return_desc(mp, &pkt_info) == ETH_OK) {
-               if (pkt_info.cmd_sts & ETH_TX_FIRST_DESC)
-                       dma_unmap_single(NULL, pkt_info.buf_ptr,
-                                       pkt_info.byte_cnt,
-                                       DMA_TO_DEVICE);
-               else
-                       dma_unmap_page(NULL, pkt_info.buf_ptr,
-                                       pkt_info.byte_cnt,
-                                       DMA_TO_DEVICE);
-
-               if (pkt_info.return_info)
-                       dev_kfree_skb_irq(pkt_info.return_info);
-       }
-
-       if (netif_queue_stopped(dev) &&
-                       mp->tx_ring_size >
-                                       mp->tx_desc_count + MAX_DESCS_PER_SKB)
-               netif_wake_queue(dev);
-}
-
 /*
  * mv643xx_poll
  *
@@ -1105,7 +1004,7 @@ static int mv643xx_poll(struct net_device *dev, int *budget)
 
 #ifdef MV643XX_TX_FAST_REFILL
        if (++mp->tx_clean_threshold > 5) {
-               mv643xx_tx(dev);
+               mv643xx_eth_free_completed_tx_descs(dev);
                mp->tx_clean_threshold = 0;
        }
 #endif
@@ -1116,7 +1015,6 @@ static int mv643xx_poll(struct net_device *dev, int *budget)
                if (orig_budget > dev->quota)
                        orig_budget = dev->quota;
                work_done = mv643xx_eth_receive_queue(dev, orig_budget);
-               mp->rx_task.func(dev);
                *budget -= work_done;
                dev->quota -= work_done;
                if (work_done >= orig_budget)
@@ -1128,14 +1026,17 @@ static int mv643xx_poll(struct net_device *dev, int *budget)
                mv_write(MV643XX_ETH_INTERRUPT_CAUSE_REG(port_num), 0);
                mv_write(MV643XX_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num), 0);
                mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num),
-                                               INT_UNMASK_ALL);
+                                               ETH_INT_UNMASK_ALL);
        }
 
        return done ? 0 : 1;
 }
 #endif
 
-/* Hardware can't handle unaligned fragments smaller than 9 bytes.
+/**
+ * has_tiny_unaligned_frags - check if skb has any small, unaligned fragments
+ *
+ * Hardware can't handle unaligned fragments smaller than 9 bytes.
  * This helper function detects that case.
  */
 
@@ -1152,51 +1053,152 @@ static inline unsigned int has_tiny_unaligned_frags(struct sk_buff *skb)
        return 0;
 }
 
+/**
+ * eth_alloc_tx_desc_index - return the index of the next available tx desc
+ */
+static int eth_alloc_tx_desc_index(struct mv643xx_private *mp)
+{
+       int tx_desc_curr;
 
-/*
- * mv643xx_eth_start_xmit
+       BUG_ON(mp->tx_desc_count >= mp->tx_ring_size);
+
+       tx_desc_curr = mp->tx_curr_desc_q;
+       mp->tx_curr_desc_q = (tx_desc_curr + 1) % mp->tx_ring_size;
+
+       BUG_ON(mp->tx_curr_desc_q == mp->tx_used_desc_q);
+
+       return tx_desc_curr;
+}
+
+/**
+ * eth_tx_fill_frag_descs - fill tx hw descriptors for an skb's fragments.
  *
- * This function is queues a packet in the Tx descriptor for
- * required port.
+ * Ensure the data for each fragment to be transmitted is mapped properly,
+ * then fill in descriptors in the tx hw queue.
+ */
+static void eth_tx_fill_frag_descs(struct mv643xx_private *mp,
+                                  struct sk_buff *skb)
+{
+       int frag;
+       int tx_index;
+       struct eth_tx_desc *desc;
+
+       for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) {
+               skb_frag_t *this_frag = &skb_shinfo(skb)->frags[frag];
+
+               tx_index = eth_alloc_tx_desc_index(mp);
+               desc = &mp->p_tx_desc_area[tx_index];
+
+               desc->cmd_sts = ETH_BUFFER_OWNED_BY_DMA;
+               /* Last Frag enables interrupt and frees the skb */
+               if (frag == (skb_shinfo(skb)->nr_frags - 1)) {
+                       desc->cmd_sts |= ETH_ZERO_PADDING |
+                                        ETH_TX_LAST_DESC |
+                                        ETH_TX_ENABLE_INTERRUPT;
+                       mp->tx_skb[tx_index] = skb;
+               } else
+                       mp->tx_skb[tx_index] = 0;
+
+               desc = &mp->p_tx_desc_area[tx_index];
+               desc->l4i_chk = 0;
+               desc->byte_cnt = this_frag->size;
+               desc->buf_ptr = dma_map_page(NULL, this_frag->page,
+                                               this_frag->page_offset,
+                                               this_frag->size,
+                                               DMA_TO_DEVICE);
+       }
+}
+
+/**
+ * eth_tx_submit_descs_for_skb - submit data from an skb to the tx hw
  *
- * Input :     skb - a pointer to socket buffer
- *             dev - a pointer to the required port
+ * Ensure the data for an skb to be transmitted is mapped properly,
+ * then fill in descriptors in the tx hw queue and start the hardware.
+ */
+static void eth_tx_submit_descs_for_skb(struct mv643xx_private *mp,
+                                       struct sk_buff *skb)
+{
+       int tx_index;
+       struct eth_tx_desc *desc;
+       u32 cmd_sts;
+       int length;
+       int nr_frags = skb_shinfo(skb)->nr_frags;
+
+       cmd_sts = ETH_TX_FIRST_DESC | ETH_GEN_CRC | ETH_BUFFER_OWNED_BY_DMA;
+
+       tx_index = eth_alloc_tx_desc_index(mp);
+       desc = &mp->p_tx_desc_area[tx_index];
+
+       if (nr_frags) {
+               eth_tx_fill_frag_descs(mp, skb);
+
+               length = skb_headlen(skb);
+               mp->tx_skb[tx_index] = 0;
+       } else {
+               cmd_sts |= ETH_ZERO_PADDING |
+                          ETH_TX_LAST_DESC |
+                          ETH_TX_ENABLE_INTERRUPT;
+               length = skb->len;
+               mp->tx_skb[tx_index] = skb;
+       }
+
+       desc->byte_cnt = length;
+       desc->buf_ptr = dma_map_single(NULL, skb->data, length, DMA_TO_DEVICE);
+
+       if (skb->ip_summed == CHECKSUM_HW) {
+               BUG_ON(skb->protocol != ETH_P_IP);
+
+               cmd_sts |= ETH_GEN_TCP_UDP_CHECKSUM |
+                          ETH_GEN_IP_V_4_CHECKSUM  |
+                          skb->nh.iph->ihl << ETH_TX_IHL_SHIFT;
+
+               switch (skb->nh.iph->protocol) {
+               case IPPROTO_UDP:
+                       cmd_sts |= ETH_UDP_FRAME;
+                       desc->l4i_chk = skb->h.uh->check;
+                       break;
+               case IPPROTO_TCP:
+                       desc->l4i_chk = skb->h.th->check;
+                       break;
+               default:
+                       BUG();
+               }
+       } else {
+               /* Errata BTS #50, IHL must be 5 if no HW checksum */
+               cmd_sts |= 5 << ETH_TX_IHL_SHIFT;
+               desc->l4i_chk = 0;
+       }
+
+       /* ensure all other descriptors are written before first cmd_sts */
+       wmb();
+       desc->cmd_sts = cmd_sts;
+
+       /* ensure all descriptors are written before poking hardware */
+       wmb();
+       mv643xx_eth_port_enable_tx(mp->port_num, ETH_TX_QUEUES_ENABLED);
+
+       mp->tx_desc_count += nr_frags + 1;
+}
+
+/**
+ * mv643xx_eth_start_xmit - queue an skb to the hardware for transmission
  *
- * Output :    zero upon success
  */
 static int mv643xx_eth_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct mv643xx_private *mp = netdev_priv(dev);
        struct net_device_stats *stats = &mp->stats;
-       ETH_FUNC_RET_STATUS status;
        unsigned long flags;
-       struct pkt_info pkt_info;
 
-       if (netif_queue_stopped(dev)) {
-               printk(KERN_ERR
-                       "%s: Tried sending packet when interface is stopped\n",
-                       dev->name);
-               return 1;
-       }
+       BUG_ON(netif_queue_stopped(dev));
+       BUG_ON(skb == NULL);
 
-       /* This is a hard error, log it. */
-       if ((mp->tx_ring_size - mp->tx_desc_count) <=
-                                       (skb_shinfo(skb)->nr_frags + 1)) {
+       if (mp->tx_ring_size - mp->tx_desc_count < MAX_DESCS_PER_SKB) {
+               printk(KERN_ERR "%s: transmit with queue full\n", dev->name);
                netif_stop_queue(dev);
-               printk(KERN_ERR
-                       "%s: Bug in mv643xx_eth - Trying to transmit when"
-                       " queue full !\n", dev->name);
                return 1;
        }
 
-       /* Paranoid check - this shouldn't happen */
-       if (skb == NULL) {
-               stats->tx_dropped++;
-               printk(KERN_ERR "mv64320_eth paranoid check failed\n");
-               return 1;
-       }
-
-#ifdef MV643XX_CHECKSUM_OFFLOAD_TX
        if (has_tiny_unaligned_frags(skb)) {
                if ((skb_linearize(skb, GFP_ATOMIC) != 0)) {
                        stats->tx_dropped++;
@@ -1208,167 +1210,14 @@ static int mv643xx_eth_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        spin_lock_irqsave(&mp->lock, flags);
 
-       if (!skb_shinfo(skb)->nr_frags) {
-               if (skb->ip_summed != CHECKSUM_HW) {
-                       /* Errata BTS #50, IHL must be 5 if no HW checksum */
-                       pkt_info.cmd_sts = ETH_TX_ENABLE_INTERRUPT |
-                                          ETH_TX_FIRST_DESC |
-                                          ETH_TX_LAST_DESC |
-                                          5 << ETH_TX_IHL_SHIFT;
-                       pkt_info.l4i_chk = 0;
-               } else {
-                       pkt_info.cmd_sts = ETH_TX_ENABLE_INTERRUPT |
-                                          ETH_TX_FIRST_DESC |
-                                          ETH_TX_LAST_DESC |
-                                          ETH_GEN_TCP_UDP_CHECKSUM |
-                                          ETH_GEN_IP_V_4_CHECKSUM |
-                                          skb->nh.iph->ihl << ETH_TX_IHL_SHIFT;
-                       /* CPU already calculated pseudo header checksum. */
-                       if ((skb->protocol == ETH_P_IP) &&
-                           (skb->nh.iph->protocol == IPPROTO_UDP) ) {
-                               pkt_info.cmd_sts |= ETH_UDP_FRAME;
-                               pkt_info.l4i_chk = skb->h.uh->check;
-                       } else if ((skb->protocol == ETH_P_IP) &&
-                                  (skb->nh.iph->protocol == IPPROTO_TCP))
-                               pkt_info.l4i_chk = skb->h.th->check;
-                       else {
-                               printk(KERN_ERR
-                                       "%s: chksum proto != IPv4 TCP or UDP\n",
-                                       dev->name);
-                               spin_unlock_irqrestore(&mp->lock, flags);
-                               return 1;
-                       }
-               }
-               pkt_info.byte_cnt = skb->len;
-               pkt_info.buf_ptr = dma_map_single(NULL, skb->data, skb->len,
-                                                       DMA_TO_DEVICE);
-               pkt_info.return_info = skb;
-               status = eth_port_send(mp, &pkt_info);
-               if ((status == ETH_ERROR) || (status == ETH_QUEUE_FULL))
-                       printk(KERN_ERR "%s: Error on transmitting packet\n",
-                                                               dev->name);
-               stats->tx_bytes += pkt_info.byte_cnt;
-       } else {
-               unsigned int frag;
-
-               /* first frag which is skb header */
-               pkt_info.byte_cnt = skb_headlen(skb);
-               pkt_info.buf_ptr = dma_map_single(NULL, skb->data,
-                                                       skb_headlen(skb),
-                                                       DMA_TO_DEVICE);
-               pkt_info.l4i_chk = 0;
-               pkt_info.return_info = 0;
-
-               if (skb->ip_summed != CHECKSUM_HW)
-                       /* Errata BTS #50, IHL must be 5 if no HW checksum */
-                       pkt_info.cmd_sts = ETH_TX_FIRST_DESC |
-                                          5 << ETH_TX_IHL_SHIFT;
-               else {
-                       pkt_info.cmd_sts = ETH_TX_FIRST_DESC |
-                                          ETH_GEN_TCP_UDP_CHECKSUM |
-                                          ETH_GEN_IP_V_4_CHECKSUM |
-                                          skb->nh.iph->ihl << ETH_TX_IHL_SHIFT;
-                       /* CPU already calculated pseudo header checksum. */
-                       if ((skb->protocol == ETH_P_IP) &&
-                           (skb->nh.iph->protocol == IPPROTO_UDP)) {
-                               pkt_info.cmd_sts |= ETH_UDP_FRAME;
-                               pkt_info.l4i_chk = skb->h.uh->check;
-                       } else if ((skb->protocol == ETH_P_IP) &&
-                                  (skb->nh.iph->protocol == IPPROTO_TCP))
-                               pkt_info.l4i_chk = skb->h.th->check;
-                       else {
-                               printk(KERN_ERR
-                                       "%s: chksum proto != IPv4 TCP or UDP\n",
-                                       dev->name);
-                               spin_unlock_irqrestore(&mp->lock, flags);
-                               return 1;
-                       }
-               }
-
-               status = eth_port_send(mp, &pkt_info);
-               if (status != ETH_OK) {
-                       if ((status == ETH_ERROR))
-                               printk(KERN_ERR
-                                       "%s: Error on transmitting packet\n",
-                                       dev->name);
-                       if (status == ETH_QUEUE_FULL)
-                               printk("Error on Queue Full \n");
-                       if (status == ETH_QUEUE_LAST_RESOURCE)
-                               printk("Tx resource error \n");
-               }
-               stats->tx_bytes += pkt_info.byte_cnt;
-
-               /* Check for the remaining frags */
-               for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) {
-                       skb_frag_t *this_frag = &skb_shinfo(skb)->frags[frag];
-                       pkt_info.l4i_chk = 0x0000;
-                       pkt_info.cmd_sts = 0x00000000;
-
-                       /* Last Frag enables interrupt and frees the skb */
-                       if (frag == (skb_shinfo(skb)->nr_frags - 1)) {
-                               pkt_info.cmd_sts |= ETH_TX_ENABLE_INTERRUPT |
-                                                       ETH_TX_LAST_DESC;
-                               pkt_info.return_info = skb;
-                       } else {
-                               pkt_info.return_info = 0;
-                       }
-                       pkt_info.l4i_chk = 0;
-                       pkt_info.byte_cnt = this_frag->size;
-
-                       pkt_info.buf_ptr = dma_map_page(NULL, this_frag->page,
-                                                       this_frag->page_offset,
-                                                       this_frag->size,
-                                                       DMA_TO_DEVICE);
-
-                       status = eth_port_send(mp, &pkt_info);
-
-                       if (status != ETH_OK) {
-                               if ((status == ETH_ERROR))
-                                       printk(KERN_ERR "%s: Error on "
-                                                       "transmitting packet\n",
-                                                       dev->name);
-
-                               if (status == ETH_QUEUE_LAST_RESOURCE)
-                                       printk("Tx resource error \n");
-
-                               if (status == ETH_QUEUE_FULL)
-                                       printk("Queue is full \n");
-                       }
-                       stats->tx_bytes += pkt_info.byte_cnt;
-               }
-       }
-#else
-       spin_lock_irqsave(&mp->lock, flags);
-
-       pkt_info.cmd_sts = ETH_TX_ENABLE_INTERRUPT | ETH_TX_FIRST_DESC |
-                                                       ETH_TX_LAST_DESC;
-       pkt_info.l4i_chk = 0;
-       pkt_info.byte_cnt = skb->len;
-       pkt_info.buf_ptr = dma_map_single(NULL, skb->data, skb->len,
-                                                               DMA_TO_DEVICE);
-       pkt_info.return_info = skb;
-       status = eth_port_send(mp, &pkt_info);
-       if ((status == ETH_ERROR) || (status == ETH_QUEUE_FULL))
-               printk(KERN_ERR "%s: Error on transmitting packet\n",
-                                                               dev->name);
-       stats->tx_bytes += pkt_info.byte_cnt;
-#endif
-
-       /* Check if TX queue can handle another skb. If not, then
-        * signal higher layers to stop requesting TX
-        */
-       if (mp->tx_ring_size <= (mp->tx_desc_count + MAX_DESCS_PER_SKB))
-               /*
-                * Stop getting skb's from upper layers.
-                * Getting skb's from upper layers will be enabled again after
-                * packets are released.
-                */
-               netif_stop_queue(dev);
-
-       /* Update statistics and start of transmittion time */
+       eth_tx_submit_descs_for_skb(mp, skb);
+       stats->tx_bytes = skb->len;
        stats->tx_packets++;
        dev->trans_start = jiffies;
 
+       if (mp->tx_ring_size - mp->tx_desc_count < MAX_DESCS_PER_SKB)
+               netif_stop_queue(dev);
+
        spin_unlock_irqrestore(&mp->lock, flags);
 
        return 0;               /* success */
@@ -1397,13 +1246,13 @@ static void mv643xx_netpoll(struct net_device *netdev)
        struct mv643xx_private *mp = netdev_priv(netdev);
        int port_num = mp->port_num;
 
-       mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), INT_MASK_ALL);
+       mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), ETH_INT_MASK_ALL);
        /* wait for previous write to complete */
        mv_read(MV643XX_ETH_INTERRUPT_MASK_REG(port_num));
 
        mv643xx_eth_int_handler(netdev->irq, netdev, NULL);
 
-       mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), INT_UNMASK_ALL);
+       mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), ETH_INT_UNMASK_ALL);
 }
 #endif
 
@@ -1814,22 +1663,6 @@ MODULE_DESCRIPTION("Ethernet driver for Marvell MV643XX");
  *             to the Rx descriptor ring to enable the reuse of this source.
  *             Return Rx resource is done using the eth_rx_return_buff API.
  *
- *             Transmit operation:
- *             The eth_port_send API supports Scatter-Gather which enables to
- *             send a packet spanned over multiple buffers. This means that
- *             for each packet info structure given by the user and put into
- *             the Tx descriptors ring, will be transmitted only if the 'LAST'
- *             bit will be set in the packet info command status field. This
- *             API also consider restriction regarding buffer alignments and
- *             sizes.
- *             The user must return a Tx resource after ensuring the buffer
- *             has been transmitted to enable the Tx ring indexes to update.
- *
- *             BOARD LAYOUT
- *             This device is on-board.  No jumper diagram is necessary.
- *
- *             EXTERNAL INTERFACE
- *
  *     Prior to calling the initialization routine eth_port_init() the user
  *     must set the following fields under mv643xx_private struct:
  *     port_num                User Ethernet port number.
@@ -1883,7 +1716,6 @@ static void eth_port_set_filter_table_entry(int table, unsigned char entry);
 static void eth_port_init(struct mv643xx_private *mp)
 {
        mp->rx_resource_err = 0;
-       mp->tx_resource_err = 0;
 
        eth_port_reset(mp->port_num);
 
@@ -1966,7 +1798,7 @@ static void eth_port_start(struct net_device *dev)
                          MV643XX_ETH_PORT_SDMA_CONFIG_DEFAULT_VALUE);
 
        /* Enable port Rx. */
-       mv643xx_eth_port_enable_rx(port_num, mp->port_rx_queue_command);
+       mv643xx_eth_port_enable_rx(port_num, ETH_RX_QUEUES_ENABLED);
 
        /* Disable port bandwidth limits by clearing MTU register */
        mv_write(MV643XX_ETH_MAXIMUM_TRANSMIT_UNIT(port_num), 0);
@@ -2455,28 +2287,28 @@ static void ethernet_phy_reset(unsigned int eth_port_num)
 }
 
 static void mv643xx_eth_port_enable_tx(unsigned int port_num,
-                                       unsigned int channels)
+                                       unsigned int queues)
 {
-       mv_write(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(port_num), channels);
+       mv_write(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(port_num), queues);
 }
 
 static void mv643xx_eth_port_enable_rx(unsigned int port_num,
-                                       unsigned int channels)
+                                       unsigned int queues)
 {
-       mv_write(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num), channels);
+       mv_write(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num), queues);
 }
 
 static unsigned int mv643xx_eth_port_disable_tx(unsigned int port_num)
 {
-       u32 channels;
+       u32 queues;
 
        /* Stop Tx port activity. Check port Tx activity. */
-       channels = mv_read(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(port_num))
+       queues = mv_read(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(port_num))
                                                        & 0xFF;
-       if (channels) {
-               /* Issue stop command for active channels only */
+       if (queues) {
+               /* Issue stop command for active queues only */
                mv_write(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(port_num),
-                                                       (channels << 8));
+                                                       (queues << 8));
 
                /* Wait for all Tx activity to terminate. */
                /* Check port cause register that all Tx queues are stopped */
@@ -2490,20 +2322,20 @@ static unsigned int mv643xx_eth_port_disable_tx(unsigned int port_num)
                        udelay(PHY_WAIT_MICRO_SECONDS);
        }
 
-       return channels;
+       return queues;
 }
 
 static unsigned int mv643xx_eth_port_disable_rx(unsigned int port_num)
 {
-       u32 channels;
+       u32 queues;
 
        /* Stop Rx port activity. Check port Rx activity. */
-       channels = mv_read(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num)
-                                                       & 0xFF);
-       if (channels) {
-               /* Issue stop command for active channels only */
+       queues = mv_read(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num))
+                                                       & 0xFF;
+       if (queues) {
+               /* Issue stop command for active queues only */
                mv_write(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num),
-                                                       (channels << 8));
+                                                       (queues << 8));
 
                /* Wait for all Rx activity to terminate. */
                /* Check port cause register that all Rx queues are stopped */
@@ -2512,7 +2344,7 @@ static unsigned int mv643xx_eth_port_disable_rx(unsigned int port_num)
                        udelay(PHY_WAIT_MICRO_SECONDS);
        }
 
-       return channels;
+       return queues;
 }
 
 /*
@@ -2674,253 +2506,6 @@ static void mv643xx_mdio_write(struct net_device *dev, int phy_id, int location,
        eth_port_write_smi_reg(mp->port_num, location, val);
 }
 
-/*
- * eth_port_send - Send an Ethernet packet
- *
- * DESCRIPTION:
- *     This routine send a given packet described by p_pktinfo parameter. It
- *     supports transmitting of a packet spaned over multiple buffers. The
- *     routine updates 'curr' and 'first' indexes according to the packet
- *     segment passed to the routine. In case the packet segment is first,
- *     the 'first' index is update. In any case, the 'curr' index is updated.
- *     If the routine get into Tx resource error it assigns 'curr' index as
- *     'first'. This way the function can abort Tx process of multiple
- *     descriptors per packet.
- *
- * INPUT:
- *     struct mv643xx_private  *mp             Ethernet Port Control srtuct.
- *     struct pkt_info         *p_pkt_info     User packet buffer.
- *
- * OUTPUT:
- *     Tx ring 'curr' and 'first' indexes are updated.
- *
- * RETURN:
- *     ETH_QUEUE_FULL in case of Tx resource error.
- *     ETH_ERROR in case the routine can not access Tx desc ring.
- *     ETH_QUEUE_LAST_RESOURCE if the routine uses the last Tx resource.
- *     ETH_OK otherwise.
- *
- */
-#ifdef MV643XX_CHECKSUM_OFFLOAD_TX
-/*
- * Modified to include the first descriptor pointer in case of SG
- */
-static ETH_FUNC_RET_STATUS eth_port_send(struct mv643xx_private *mp,
-                                        struct pkt_info *p_pkt_info)
-{
-       int tx_desc_curr, tx_desc_used, tx_first_desc, tx_next_desc;
-       struct eth_tx_desc *current_descriptor;
-       struct eth_tx_desc *first_descriptor;
-       u32 command;
-
-       /* Do not process Tx ring in case of Tx ring resource error */
-       if (mp->tx_resource_err)
-               return ETH_QUEUE_FULL;
-
-       /*
-        * The hardware requires that each buffer that is <= 8 bytes
-        * in length must be aligned on an 8 byte boundary.
-        */
-       if (p_pkt_info->byte_cnt <= 8 && p_pkt_info->buf_ptr & 0x7) {
-               printk(KERN_ERR
-                       "mv643xx_eth port %d: packet size <= 8 problem\n",
-                       mp->port_num);
-               return ETH_ERROR;
-       }
-
-       mp->tx_desc_count++;
-       BUG_ON(mp->tx_desc_count > mp->tx_ring_size);
-
-       /* Get the Tx Desc ring indexes */
-       tx_desc_curr = mp->tx_curr_desc_q;
-       tx_desc_used = mp->tx_used_desc_q;
-
-       current_descriptor = &mp->p_tx_desc_area[tx_desc_curr];
-
-       tx_next_desc = (tx_desc_curr + 1) % mp->tx_ring_size;
-
-       current_descriptor->buf_ptr = p_pkt_info->buf_ptr;
-       current_descriptor->byte_cnt = p_pkt_info->byte_cnt;
-       current_descriptor->l4i_chk = p_pkt_info->l4i_chk;
-       mp->tx_skb[tx_desc_curr] = p_pkt_info->return_info;
-
-       command = p_pkt_info->cmd_sts | ETH_ZERO_PADDING | ETH_GEN_CRC |
-                                                       ETH_BUFFER_OWNED_BY_DMA;
-       if (command & ETH_TX_FIRST_DESC) {
-               tx_first_desc = tx_desc_curr;
-               mp->tx_first_desc_q = tx_first_desc;
-               first_descriptor = current_descriptor;
-               mp->tx_first_command = command;
-       } else {
-               tx_first_desc = mp->tx_first_desc_q;
-               first_descriptor = &mp->p_tx_desc_area[tx_first_desc];
-               BUG_ON(first_descriptor == NULL);
-               current_descriptor->cmd_sts = command;
-       }
-
-       if (command & ETH_TX_LAST_DESC) {
-               wmb();
-               first_descriptor->cmd_sts = mp->tx_first_command;
-
-               wmb();
-               mv643xx_eth_port_enable_tx(mp->port_num, mp->port_tx_queue_command);
-
-               /*
-                * Finish Tx packet. Update first desc in case of Tx resource
-                * error */
-               tx_first_desc = tx_next_desc;
-               mp->tx_first_desc_q = tx_first_desc;
-       }
-
-       /* Check for ring index overlap in the Tx desc ring */
-       if (tx_next_desc == tx_desc_used) {
-               mp->tx_resource_err = 1;
-               mp->tx_curr_desc_q = tx_first_desc;
-
-               return ETH_QUEUE_LAST_RESOURCE;
-       }
-
-       mp->tx_curr_desc_q = tx_next_desc;
-
-       return ETH_OK;
-}
-#else
-static ETH_FUNC_RET_STATUS eth_port_send(struct mv643xx_private *mp,
-                                        struct pkt_info *p_pkt_info)
-{
-       int tx_desc_curr;
-       int tx_desc_used;
-       struct eth_tx_desc *current_descriptor;
-       unsigned int command_status;
-
-       /* Do not process Tx ring in case of Tx ring resource error */
-       if (mp->tx_resource_err)
-               return ETH_QUEUE_FULL;
-
-       mp->tx_desc_count++;
-       BUG_ON(mp->tx_desc_count > mp->tx_ring_size);
-
-       /* Get the Tx Desc ring indexes */
-       tx_desc_curr = mp->tx_curr_desc_q;
-       tx_desc_used = mp->tx_used_desc_q;
-       current_descriptor = &mp->p_tx_desc_area[tx_desc_curr];
-
-       command_status = p_pkt_info->cmd_sts | ETH_ZERO_PADDING | ETH_GEN_CRC;
-       current_descriptor->buf_ptr = p_pkt_info->buf_ptr;
-       current_descriptor->byte_cnt = p_pkt_info->byte_cnt;
-       mp->tx_skb[tx_desc_curr] = p_pkt_info->return_info;
-
-       /* Set last desc with DMA ownership and interrupt enable. */
-       wmb();
-       current_descriptor->cmd_sts = command_status |
-                       ETH_BUFFER_OWNED_BY_DMA | ETH_TX_ENABLE_INTERRUPT;
-
-       wmb();
-       mv643xx_eth_port_enable_tx(mp->port_num, mp->port_tx_queue_command);
-
-       /* Finish Tx packet. Update first desc in case of Tx resource error */
-       tx_desc_curr = (tx_desc_curr + 1) % mp->tx_ring_size;
-
-       /* Update the current descriptor */
-       mp->tx_curr_desc_q = tx_desc_curr;
-
-       /* Check for ring index overlap in the Tx desc ring */
-       if (tx_desc_curr == tx_desc_used) {
-               mp->tx_resource_err = 1;
-               return ETH_QUEUE_LAST_RESOURCE;
-       }
-
-       return ETH_OK;
-}
-#endif
-
-/*
- * eth_tx_return_desc - Free all used Tx descriptors
- *
- * DESCRIPTION:
- *     This routine returns the transmitted packet information to the caller.
- *     It uses the 'first' index to support Tx desc return in case a transmit
- *     of a packet spanned over multiple buffer still in process.
- *     In case the Tx queue was in "resource error" condition, where there are
- *     no available Tx resources, the function resets the resource error flag.
- *
- * INPUT:
- *     struct mv643xx_private  *mp             Ethernet Port Control srtuct.
- *     struct pkt_info         *p_pkt_info     User packet buffer.
- *
- * OUTPUT:
- *     Tx ring 'first' and 'used' indexes are updated.
- *
- * RETURN:
- *     ETH_OK on success
- *     ETH_ERROR otherwise.
- *
- */
-static ETH_FUNC_RET_STATUS eth_tx_return_desc(struct mv643xx_private *mp,
-                                               struct pkt_info *p_pkt_info)
-{
-       int tx_desc_used;
-       int tx_busy_desc;
-       struct eth_tx_desc *p_tx_desc_used;
-       unsigned int command_status;
-       unsigned long flags;
-       int err = ETH_OK;
-
-       spin_lock_irqsave(&mp->lock, flags);
-
-#ifdef MV643XX_CHECKSUM_OFFLOAD_TX
-       tx_busy_desc = mp->tx_first_desc_q;
-#else
-       tx_busy_desc = mp->tx_curr_desc_q;
-#endif
-
-       /* Get the Tx Desc ring indexes */
-       tx_desc_used = mp->tx_used_desc_q;
-
-       p_tx_desc_used = &mp->p_tx_desc_area[tx_desc_used];
-
-       /* Sanity check */
-       if (p_tx_desc_used == NULL) {
-               err = ETH_ERROR;
-               goto out;
-       }
-
-       /* Stop release. About to overlap the current available Tx descriptor */
-       if (tx_desc_used == tx_busy_desc && !mp->tx_resource_err) {
-               err = ETH_ERROR;
-               goto out;
-       }
-
-       command_status = p_tx_desc_used->cmd_sts;
-
-       /* Still transmitting... */
-       if (command_status & (ETH_BUFFER_OWNED_BY_DMA)) {
-               err = ETH_ERROR;
-               goto out;
-       }
-
-       /* Pass the packet information to the caller */
-       p_pkt_info->cmd_sts = command_status;
-       p_pkt_info->return_info = mp->tx_skb[tx_desc_used];
-       p_pkt_info->buf_ptr = p_tx_desc_used->buf_ptr;
-       p_pkt_info->byte_cnt = p_tx_desc_used->byte_cnt;
-       mp->tx_skb[tx_desc_used] = NULL;
-
-       /* Update the next descriptor to release. */
-       mp->tx_used_desc_q = (tx_desc_used + 1) % mp->tx_ring_size;
-
-       /* Any Tx return cancels the Tx resource error status */
-       mp->tx_resource_err = 0;
-
-       BUG_ON(mp->tx_desc_count == 0);
-       mp->tx_desc_count--;
-
-out:
-       spin_unlock_irqrestore(&mp->lock, flags);
-
-       return err;
-}
-
 /*
  * eth_port_receive - Get received information from Rx ring.
  *