[ewg] [PATCH 3/10] nes: nic queue start/stop and carrier fix

Glenn Grundstrom NetEffect glenn at lists.openfabrics.org
Thu Dec 20 12:26:22 PST 2007


If a full send queue occurs, netif_stop_queue() is called
but netif_start_queue() was not being called.

Signed-off-by: Glenn Grundstrom <ggrundstrom at neteffect.com>

---

diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c
index 810a9ae..2ff4c41 100644
--- a/drivers/infiniband/hw/nes/nes_nic.c
+++ b/drivers/infiniband/hw/nes/nes_nic.c
@@ -203,6 +203,7 @@ static int nes_netdev_open(struct net_device *netdev)
 		return ret;
 	}
 
+	netif_carrier_off(netdev);
 	netif_stop_queue(netdev);
 
 	if ((!nesvnic->of_device_registered) && (nesvnic->rdma_enabled)) {
@@ -502,6 +503,13 @@ static int nes_netdev_start_xmit(struct sk_buff *skb, struct net_device *netdev)
 			netdev->name, skb->len, skb_headlen(skb),
 			skb_shinfo(skb)->nr_frags, skb_is_gso(skb));
 	*/
+
+	if (!netif_carrier_ok(netdev))
+		return NETDEV_TX_OK;
+
+	if (netif_queue_stopped(netdev))
+		return NETDEV_TX_BUSY;
+
 	local_irq_save(flags);
 	if (!spin_trylock(&nesnic->sq_lock)) {
 		local_irq_restore(flags);
@@ -511,12 +519,20 @@ static int nes_netdev_start_xmit(struct sk_buff *skb, struct net_device *netdev)
 
 	/* Check if SQ is full */
 	if ((((nesnic->sq_tail+(nesnic->sq_size*2))-nesnic->sq_head) & (nesnic->sq_size - 1)) == 1) {
-		netif_stop_queue(netdev);
-		spin_unlock_irqrestore(&nesnic->sq_lock, flags);
+		if (!netif_queue_stopped(netdev)) {
+			netif_stop_queue(netdev);
+			barrier();
+			if ((((((volatile u16)nesnic->sq_tail)+(nesnic->sq_size*2))-nesnic->sq_head) & (nesnic->sq_size - 1)) != 1) {
+				netif_start_queue(netdev);
+				goto sq_no_longer_full;
+			}
+		}
 		nesvnic->sq_full++;
+		spin_unlock_irqrestore(&nesnic->sq_lock, flags);
 		return NETDEV_TX_BUSY;
 	}
 
+sq_no_longer_full:
 	nr_frags = skb_shinfo(skb)->nr_frags;
 	if (skb_headlen(skb) > NES_FIRST_FRAG_SIZE) {
 		nr_frags++;
@@ -534,13 +550,23 @@ static int nes_netdev_start_xmit(struct sk_buff *skb, struct net_device *netdev)
 					(nesnic->sq_size - 1);
 
 			if (unlikely(wqes_needed > wqes_available)) {
-				netif_stop_queue(netdev);
+				if (!netif_queue_stopped(netdev)) {
+					netif_stop_queue(netdev);
+					barrier();
+					wqes_available = (((((volatile u16)nesnic->sq_tail)+nesnic->sq_size)-nesnic->sq_head) - 1) &
+						(nesnic->sq_size - 1);
+					if (wqes_needed <= wqes_available) {
+						netif_start_queue(netdev);
+						goto tso_sq_no_longer_full;
+					}
+				}
+				nesvnic->sq_full++;
 				spin_unlock_irqrestore(&nesnic->sq_lock, flags);
 				nes_debug(NES_DBG_NIC_TX, "%s: HNIC SQ full- TSO request has too many frags!\n",
 						netdev->name);
-				nesvnic->sq_full++;
 				return NETDEV_TX_BUSY;
 			}
+tso_sq_no_longer_full:
 			/* Map all the buffers */
 			for (tso_frag_count=0; tso_frag_count < skb_shinfo(skb)->nr_frags;
 					tso_frag_count++) {



More information about the ewg mailing list