[ofa-general] [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 general
mailing list