From: Chad Dupuis <cdupuis@redhat.com> Date: Fri, 6 Aug 2010 14:22:27 -0400 Subject: [net] qlge: fix pktgen issue reported by Cisco Message-id: <20100806141914.2774.87405.sendpatchset@localhost.localdomain> Patchwork-id: 27444 O-Subject: [RHEL 5.6 PATCH 2/10] qlge: Fixed pktgen, issue reported by Cisco. Bugzilla: 567402 Bugzilla ======== 567402 Upstream Status =============== RHEL 5 specific Description =========== >From 6418d44cb9b04f03bc2039c6eac5d523d2449b0b Mon Sep 17 00:00:00 2001 From: Jitendra Kalsaria <jitendra.kalsaria@qlogic.com> Date: Wed, 4 Aug 2010 16:28:55 -0700 Subject: [PATCH 2/8] qlge: Fixed pktgen, issue reported by Cisco. Signed-off-by: Jitendra Kalsaria <jitendra.kalsaria@qlogic.com> diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h index d1221b0..bf215a7 100644 --- a/drivers/net/qlge/qlge.h +++ b/drivers/net/qlge/qlge.h @@ -1310,7 +1310,6 @@ struct tx_ring { struct tx_ring_desc *q; /* descriptor list for the queue */ spinlock_t lock; atomic_t tx_count; /* counts down for every outstanding IO */ - atomic_t queue_stopped; /* Turns queue off when full. */ struct work_struct tx_work; struct ql_adapter *qdev; struct timer_list txq_clean_timer; @@ -2030,6 +2029,8 @@ struct ql_adapter { uint32_t *config_space; /* Saving mac addr */ char current_mac_addr[6]; + spinlock_t tx_lock; + u32 queue_stopped; /* Bitfield of queues that are full. */ }; /* diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index f66f617..96483b0 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -1920,17 +1920,6 @@ static int ql_clean_outbound_rx_ring(struct rx_ring *rx_ring) return count; ql_write_cq_idx(rx_ring); - if (netif_queue_stopped(qdev->ndev) && net_rsp != NULL) { - struct tx_ring *tx_ring = &qdev->tx_ring[net_rsp->txq_idx]; - if (atomic_read(&tx_ring->queue_stopped) && - (atomic_read(&tx_ring->tx_count) > - (tx_ring->wq_len / 4))) - /* - * The queue got stopped because the tx_ring was full. - * Wake it up, because it's now at least 25% empty. - */ - netif_wake_queue(qdev->ndev); - } rx_ring->bytes += bytes; rx_ring->packets += (unsigned long) count; return count; @@ -1947,6 +1936,17 @@ static void ql_txq_clean_timer(unsigned long data) ql_clean_outbound_rx_ring(rx_ring); spin_unlock(&tx_ring->lock); + if (netif_queue_stopped(qdev->ndev)) { + spin_lock(&qdev->tx_lock); + if (qdev->queue_stopped & (1 << tx_ring->wq_id)) { + if (atomic_read(&tx_ring->tx_count) > 64) { + qdev->queue_stopped &= ~(1 << tx_ring->wq_id); + if (!qdev->queue_stopped) + netif_wake_queue(qdev->ndev); + } + } + spin_unlock(&qdev->tx_lock); + } exit: mod_timer(&tx_ring->txq_clean_timer, jiffies + TXQ_CLEAN_TIME); @@ -2279,11 +2279,16 @@ int qlge_send(struct sk_buff *skb, struct net_device *ndev) ql_clean_outbound_rx_ring(&qdev->rx_ring[tx_ring->cq_id]); if (unlikely(atomic_read(&tx_ring->tx_count) < 2)) { spin_unlock(&tx_ring->lock); + del_timer_sync(&tx_ring->txq_clean_timer); QPRINTK_DBG(qdev, TX_QUEUED, INFO, - "shutting down tx queue %d du to lack of resources.\n", + "shutting down tx queue %d due to lack of resources.\n", tx_ring_idx); - netif_stop_queue(ndev); - atomic_inc(&tx_ring->queue_stopped); + spin_lock(&qdev->tx_lock); + if (!qdev->queue_stopped) + netif_stop_queue(ndev); + qdev->queue_stopped |= (1 << tx_ring->wq_id); + spin_unlock(&qdev->tx_lock); + mod_timer(&tx_ring->txq_clean_timer, jiffies); return NETDEV_TX_BUSY; } tx_ring_desc = &tx_ring->q[tx_ring->prod_idx]; @@ -2410,7 +2415,6 @@ static void ql_init_tx_ring(struct ql_adapter *qdev, struct tx_ring *tx_ring) tx_ring_desc++; } atomic_set(&tx_ring->tx_count, tx_ring->wq_len); - atomic_set(&tx_ring->queue_stopped, 0); } static void ql_free_tx_resources(struct ql_adapter *qdev, @@ -3668,6 +3672,7 @@ static int ql_adapter_up(struct ql_adapter *qdev) set_bit(QL_ADAPTER_UP, &qdev->flags); ql_enable_napi(qdev); ql_alloc_rx_buffers(qdev); + qdev->queue_stopped = 0; ql_enable_all_completion_interrupts(qdev); /* trigger link work function*/ @@ -4306,6 +4311,7 @@ static int __devinit ql_init_device(struct pci_dev *pdev, qdev->msg_enable = netif_msg_init(debug, default_msg); spin_lock_init(&qdev->hw_lock); spin_lock_init(&qdev->stats_lock); + spin_lock_init(&qdev->tx_lock); qdev->mpi_coredump = vmalloc(sizeof(struct ql_mpi_coredump)); if ((qdev->mpi_coredump == NULL) && qlge_mpi_coredump) {