qlcnic: Fix bug in Tx completion path
o Driver is using common tx_clean_lock for all Tx queues. This patch adds per queue tx_clean_lock. o Driver is not updating sw_consumer while processing Tx completion when interface is going down. Fixed in this patch. Signed-off-by: Shahed Shaikh <shahed.shaikh@qlogic.com> Signed-off-by: Manish Chopra <manish.chopra@qlogic.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Родитель
0d68fc4f12
Коммит
a02bdd423d
|
@ -579,6 +579,8 @@ struct qlcnic_host_tx_ring {
|
|||
dma_addr_t phys_addr;
|
||||
dma_addr_t hw_cons_phys_addr;
|
||||
struct netdev_queue *txq;
|
||||
/* Lock to protect Tx descriptors cleanup */
|
||||
spinlock_t tx_clean_lock;
|
||||
} ____cacheline_internodealigned_in_smp;
|
||||
|
||||
/*
|
||||
|
@ -1095,7 +1097,6 @@ struct qlcnic_adapter {
|
|||
struct qlcnic_filter_hash rx_fhash;
|
||||
struct list_head vf_mc_list;
|
||||
|
||||
spinlock_t tx_clean_lock;
|
||||
spinlock_t mac_learn_lock;
|
||||
/* spinlock for catching rcv filters for eswitch traffic */
|
||||
spinlock_t rx_mac_learn_lock;
|
||||
|
|
|
@ -134,6 +134,8 @@ void qlcnic_release_tx_buffers(struct qlcnic_adapter *adapter,
|
|||
struct qlcnic_skb_frag *buffrag;
|
||||
int i, j;
|
||||
|
||||
spin_lock(&tx_ring->tx_clean_lock);
|
||||
|
||||
cmd_buf = tx_ring->cmd_buf_arr;
|
||||
for (i = 0; i < tx_ring->num_desc; i++) {
|
||||
buffrag = cmd_buf->frag_array;
|
||||
|
@ -157,6 +159,8 @@ void qlcnic_release_tx_buffers(struct qlcnic_adapter *adapter,
|
|||
}
|
||||
cmd_buf++;
|
||||
}
|
||||
|
||||
spin_unlock(&tx_ring->tx_clean_lock);
|
||||
}
|
||||
|
||||
void qlcnic_free_sw_resources(struct qlcnic_adapter *adapter)
|
||||
|
|
|
@ -782,7 +782,7 @@ static int qlcnic_process_cmd_ring(struct qlcnic_adapter *adapter,
|
|||
struct net_device *netdev = adapter->netdev;
|
||||
struct qlcnic_skb_frag *frag;
|
||||
|
||||
if (!spin_trylock(&adapter->tx_clean_lock))
|
||||
if (!spin_trylock(&tx_ring->tx_clean_lock))
|
||||
return 1;
|
||||
|
||||
sw_consumer = tx_ring->sw_consumer;
|
||||
|
@ -811,8 +811,9 @@ static int qlcnic_process_cmd_ring(struct qlcnic_adapter *adapter,
|
|||
break;
|
||||
}
|
||||
|
||||
tx_ring->sw_consumer = sw_consumer;
|
||||
|
||||
if (count && netif_running(netdev)) {
|
||||
tx_ring->sw_consumer = sw_consumer;
|
||||
smp_mb();
|
||||
if (netif_tx_queue_stopped(tx_ring->txq) &&
|
||||
netif_carrier_ok(netdev)) {
|
||||
|
@ -838,7 +839,8 @@ static int qlcnic_process_cmd_ring(struct qlcnic_adapter *adapter,
|
|||
*/
|
||||
hw_consumer = le32_to_cpu(*(tx_ring->hw_consumer));
|
||||
done = (sw_consumer == hw_consumer);
|
||||
spin_unlock(&adapter->tx_clean_lock);
|
||||
|
||||
spin_unlock(&tx_ring->tx_clean_lock);
|
||||
|
||||
return done;
|
||||
}
|
||||
|
|
|
@ -1756,7 +1756,6 @@ void __qlcnic_down(struct qlcnic_adapter *adapter, struct net_device *netdev)
|
|||
if (qlcnic_sriov_vf_check(adapter))
|
||||
qlcnic_sriov_cleanup_async_list(&adapter->ahw->sriov->bc);
|
||||
smp_mb();
|
||||
spin_lock(&adapter->tx_clean_lock);
|
||||
netif_carrier_off(netdev);
|
||||
adapter->ahw->linkup = 0;
|
||||
netif_tx_disable(netdev);
|
||||
|
@ -1777,7 +1776,6 @@ void __qlcnic_down(struct qlcnic_adapter *adapter, struct net_device *netdev)
|
|||
|
||||
for (ring = 0; ring < adapter->drv_tx_rings; ring++)
|
||||
qlcnic_release_tx_buffers(adapter, &adapter->tx_ring[ring]);
|
||||
spin_unlock(&adapter->tx_clean_lock);
|
||||
}
|
||||
|
||||
/* Usage: During suspend and firmware recovery module */
|
||||
|
@ -2172,6 +2170,7 @@ int qlcnic_alloc_tx_rings(struct qlcnic_adapter *adapter,
|
|||
}
|
||||
memset(cmd_buf_arr, 0, TX_BUFF_RINGSIZE(tx_ring));
|
||||
tx_ring->cmd_buf_arr = cmd_buf_arr;
|
||||
spin_lock_init(&tx_ring->tx_clean_lock);
|
||||
}
|
||||
|
||||
if (qlcnic_83xx_check(adapter) ||
|
||||
|
@ -2299,7 +2298,6 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
rwlock_init(&adapter->ahw->crb_lock);
|
||||
mutex_init(&adapter->ahw->mem_lock);
|
||||
|
||||
spin_lock_init(&adapter->tx_clean_lock);
|
||||
INIT_LIST_HEAD(&adapter->mac_list);
|
||||
|
||||
qlcnic_register_dcb(adapter);
|
||||
|
|
Загрузка…
Ссылка в новой задаче