Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a02bdd42 authored by Shahed Shaikh's avatar Shahed Shaikh Committed by David S. Miller
Browse files

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: default avatarShahed Shaikh <shahed.shaikh@qlogic.com>
Signed-off-by: default avatarManish Chopra <manish.chopra@qlogic.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 0d68fc4f
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -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;
+4 −0
Original line number Diff line number Diff line
@@ -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)
+5 −3
Original line number Diff line number Diff line
@@ -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;
	}

	if (count && netif_running(netdev)) {
	tx_ring->sw_consumer = sw_consumer;

	if (count && netif_running(netdev)) {
		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;
}
+1 −3
Original line number Diff line number Diff line
@@ -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);