[PATCH] mv643xx_eth: Refactor tx command queuing code
Dale Farnsworth [Fri, 3 Mar 2006 17:02:05 +0000 (10:02 -0700)]
Simplify and remove redundant code for filling transmit descriptors.
No changes in features; it's just a code reorganization/cleanup.

Signed-off-by: Dale Farnsworth <dale@farnsworth.org>
Signed-off-by: Jeff Garzik <jeff@garzik.org>

drivers/net/mv643xx_eth.c
drivers/net/mv643xx_eth.h

index 098f3a2..260be80 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>
@@ -554,7 +554,7 @@ static irqreturn_t mv643xx_eth_int_handler(int irq, void *dev_id,
                /* 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))
+                   (mp->tx_ring_size - mp->tx_desc_count > MAX_DESCS_PER_SKB))
                        netif_wake_queue(dev);
 #ifdef MV643XX_NAPI
        } else {
@@ -598,7 +598,7 @@ static irqreturn_t mv643xx_eth_int_handler(int irq, void *dev_id,
                        mv643xx_eth_update_pscr(dev, &cmd);
                        if (!netif_carrier_ok(dev)) {
                                netif_carrier_on(dev);
-                               if (mp->tx_ring_size > mp->tx_desc_count +
+                               if (mp->tx_ring_size - mp->tx_desc_count >
                                                        MAX_DESCS_PER_SKB) {
                                        netif_wake_queue(dev);
                                        /* Start TX queue */
@@ -777,9 +777,6 @@ 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);
 
@@ -1085,8 +1082,7 @@ static void mv643xx_tx(struct net_device *dev)
        }
 
        if (netif_queue_stopped(dev) &&
-                       mp->tx_ring_size >
-                                       mp->tx_desc_count + MAX_DESCS_PER_SKB)
+           mp->tx_ring_size - mp->tx_desc_count > MAX_DESCS_PER_SKB)
                netif_wake_queue(dev);
 }
 
@@ -1133,7 +1129,10 @@ static int mv643xx_poll(struct net_device *dev, int *budget)
 }
 #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.
  */
 
@@ -1150,223 +1149,170 @@ 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;
+
+       tx_desc_curr = mp->tx_curr_desc_q;
 
-/*
- * mv643xx_eth_start_xmit
- *
- * This function is queues a packet in the Tx descriptor for
- * required port.
- *
- * Input :     skb - a pointer to socket buffer
- *             dev - a pointer to the required port
+       BUG_ON(mp->tx_desc_count >= mp->tx_ring_size);
+       mp->tx_desc_count++;
+
+       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.
  *
- * Output :    zero upon success
+ * Ensure the data for each fragment to be transmitted is mapped properly,
+ * then fill in descriptors in the tx hw queue.
  */
-static int mv643xx_eth_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static void eth_tx_fill_frag_descs(struct mv643xx_private *mp,
+                                  struct sk_buff *skb)
 {
-       struct mv643xx_private *mp = netdev_priv(dev);
+       int frag;
+       int tx_index;
+       struct eth_tx_desc *desc;
        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;
+       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);
+               stats->tx_bytes += this_frag->size;
        }
+}
 
-       /* This is a hard error, log it. */
-       if ((mp->tx_ring_size - mp->tx_desc_count) <=
-                                       (skb_shinfo(skb)->nr_frags + 1)) {
-               netif_stop_queue(dev);
-               printk(KERN_ERR
-                       "%s: Bug in mv643xx_eth - Trying to transmit when"
-                       " queue full !\n", dev->name);
-               return 1;
-       }
+/**
+ * eth_tx_submit_descs_for_skb - submit data from an skb to the tx hw
+ *
+ * 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 int 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 tx_bytes = 0;
 
-       /* Paranoid check - this shouldn't happen */
-       if (skb == NULL) {
-               stats->tx_dropped++;
-               printk(KERN_ERR "mv64320_eth paranoid check failed\n");
-               return 1;
-       }
+       cmd_sts = ETH_TX_FIRST_DESC | ETH_GEN_CRC | ETH_BUFFER_OWNED_BY_DMA;
 
-#ifdef MV643XX_CHECKSUM_OFFLOAD_TX
-       if (has_tiny_unaligned_frags(skb)) {
-               if ((skb_linearize(skb, GFP_ATOMIC) != 0)) {
-                       stats->tx_dropped++;
-                       printk(KERN_DEBUG "%s: failed to linearize tiny "
-                                       "unaligned fragment\n", dev->name);
-                       return 1;
-               }
+       tx_index = eth_alloc_tx_desc_index(mp);
+       desc = &mp->p_tx_desc_area[tx_index];
+
+       if (skb_shinfo(skb)->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;
        }
 
-       spin_lock_irqsave(&mp->lock, flags);
+       desc->byte_cnt = length;
+       desc->buf_ptr = dma_map_single(NULL, skb->data, length, DMA_TO_DEVICE);
+       tx_bytes += length;
 
-       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;
-                       }
+       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();
                }
-               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;
-                       }
-               }
+               /* Errata BTS #50, IHL must be 5 if no HW checksum */
+               cmd_sts |= 5 << ETH_TX_IHL_SHIFT;
+               desc->l4i_chk = 0;
+       }
 
-               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;
+       /* ensure all other descriptors are written before first cmd_sts */
+       wmb();
+       desc->cmd_sts = cmd_sts;
 
-                       pkt_info.buf_ptr = dma_map_page(NULL, this_frag->page,
-                                                       this_frag->page_offset,
-                                                       this_frag->size,
-                                                       DMA_TO_DEVICE);
+       /* ensure all descriptors are written before poking hardware */
+       wmb();
+       mv643xx_eth_port_enable_tx(mp->port_num, mp->port_tx_queue_command);
 
-                       status = eth_port_send(mp, &pkt_info);
+       return tx_bytes;
+}
 
-                       if (status != ETH_OK) {
-                               if ((status == ETH_ERROR))
-                                       printk(KERN_ERR "%s: Error on "
-                                                       "transmitting packet\n",
-                                                       dev->name);
+/**
+ * mv643xx_eth_start_xmit - queue an skb to the hardware for transmission
+ *
+ */
+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;
+       unsigned long flags;
 
-                               if (status == ETH_QUEUE_LAST_RESOURCE)
-                                       printk("Tx resource error \n");
+       BUG_ON(netif_queue_stopped(dev));
+       BUG_ON(skb == NULL);
+       BUG_ON(mp->tx_ring_size - mp->tx_desc_count < MAX_DESCS_PER_SKB);
 
-                               if (status == ETH_QUEUE_FULL)
-                                       printk("Queue is full \n");
-                       }
-                       stats->tx_bytes += pkt_info.byte_cnt;
+       if (has_tiny_unaligned_frags(skb)) {
+               if ((skb_linearize(skb, GFP_ATOMIC) != 0)) {
+                       stats->tx_dropped++;
+                       printk(KERN_DEBUG "%s: failed to linearize tiny "
+                                       "unaligned fragment\n", dev->name);
+                       return 1;
                }
        }
-#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);
+       spin_lock_irqsave(&mp->lock, flags);
 
-       /* Update statistics and start of transmittion time */
+       stats->tx_bytes = eth_tx_submit_descs_for_skb(mp, skb);
        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 */
@@ -1812,22 +1758,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.
@@ -1881,7 +1811,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);
 
@@ -2673,166 +2602,6 @@ static void mv643xx_mdio_write(struct net_device *dev, int phy_id, int location,
 }
 
 /*
- * 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:
@@ -2858,7 +2627,6 @@ 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;
@@ -2866,33 +2634,23 @@ static ETH_FUNC_RET_STATUS eth_tx_return_desc(struct mv643xx_private *mp,
 
        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
+       BUG_ON(mp->tx_desc_count < 0);
+       if (mp->tx_desc_count == 0) {
+               /* no more tx descs in use */
+               err = ETH_ERROR;
+               goto out;
+       }
 
        /* 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;
-       }
+       BUG_ON(p_tx_desc_used == NULL);
 
        command_status = p_tx_desc_used->cmd_sts;
-
-       /* Still transmitting... */
        if (command_status & (ETH_BUFFER_OWNED_BY_DMA)) {
+               /* Still transmitting... */
                err = ETH_ERROR;
                goto out;
        }
@@ -2907,9 +2665,6 @@ static ETH_FUNC_RET_STATUS eth_tx_return_desc(struct mv643xx_private *mp,
        /* 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--;
 
index a553054..8768e1b 100644 (file)
@@ -330,7 +330,6 @@ struct mv643xx_private {
        u32 tx_sram_size;               /* Size of tx sram area         */
 
        int rx_resource_err;            /* Rx ring resource error flag */
-       int tx_resource_err;            /* Tx ring resource error flag */
 
        /* Tx/Rx rings managment indexes fields. For driver use */
 
@@ -339,10 +338,6 @@ struct mv643xx_private {
 
        /* Next available and first returning Tx resource */
        int tx_curr_desc_q, tx_used_desc_q;
-#ifdef MV643XX_CHECKSUM_OFFLOAD_TX
-       int tx_first_desc_q;
-       u32 tx_first_command;
-#endif
 
 #ifdef MV643XX_TX_FAST_REFILL
        u32 tx_clean_threshold;
@@ -350,12 +345,12 @@ struct mv643xx_private {
 
        struct eth_rx_desc *p_rx_desc_area;
        dma_addr_t rx_desc_dma;
-       unsigned int rx_desc_area_size;
+       int rx_desc_area_size;
        struct sk_buff **rx_skb;
 
        struct eth_tx_desc *p_tx_desc_area;
        dma_addr_t tx_desc_dma;
-       unsigned int tx_desc_area_size;
+       int tx_desc_area_size;
        struct sk_buff **tx_skb;
 
        struct work_struct tx_timeout_task;
@@ -367,13 +362,13 @@ struct mv643xx_private {
        struct mv643xx_mib_counters mib_counters;
        spinlock_t lock;
        /* Size of Tx Ring per queue */
-       unsigned int tx_ring_size;
+       int tx_ring_size;
        /* Number of tx descriptors in use */
-       unsigned int tx_desc_count;
+       int tx_desc_count;
        /* Size of Rx Ring per queue */
-       unsigned int rx_ring_size;
+       int rx_ring_size;
        /* Number of rx descriptors in use */
-       unsigned int rx_desc_count;
+       int rx_desc_count;
 
        /*
         * rx_task used to fill RX ring out of bottom half context
@@ -416,8 +411,6 @@ static void eth_port_read_smi_reg(unsigned int eth_port_num,
 static void eth_clear_mib_counters(unsigned int eth_port_num);
 
 /* Port data flow control routines */
-static ETH_FUNC_RET_STATUS eth_port_send(struct mv643xx_private *mp,
-                                        struct pkt_info *p_pkt_info);
 static ETH_FUNC_RET_STATUS eth_tx_return_desc(struct mv643xx_private *mp,
                                              struct pkt_info *p_pkt_info);
 static ETH_FUNC_RET_STATUS eth_port_receive(struct mv643xx_private *mp,