netxen: fix tx ring accounting
This forces every update of tx ring producer to check for availability of space for next full TSO command. Earlier firmware control commands didn't care to pause tx queue. Stop the tx queue if there's not enough space to transmit one full LSO command left on the tx ring after current transmit. This avoids returning NETDEV_TX_BUSY after checking distance between producer and consumer on every cpu. Restart the tx queue only if we have cleaned up enough tx descriptors. Signed-off-by: Dhananjay Phadke <dhananjay@netxen.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
d173346040
commit
cb2107be43
@@ -107,9 +107,14 @@ static uint32_t crb_cmd_producer[4] = {
|
||||
|
||||
void
|
||||
netxen_nic_update_cmd_producer(struct netxen_adapter *adapter,
|
||||
struct nx_host_tx_ring *tx_ring, u32 producer)
|
||||
struct nx_host_tx_ring *tx_ring)
|
||||
{
|
||||
NXWR32(adapter, tx_ring->crb_cmd_producer, producer);
|
||||
NXWR32(adapter, tx_ring->crb_cmd_producer, tx_ring->producer);
|
||||
|
||||
if (netxen_tx_avail(tx_ring) <= TX_STOP_THRESH) {
|
||||
netif_stop_queue(adapter->netdev);
|
||||
smp_mb();
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t crb_cmd_consumer[4] = {
|
||||
@@ -119,9 +124,9 @@ static uint32_t crb_cmd_consumer[4] = {
|
||||
|
||||
static inline void
|
||||
netxen_nic_update_cmd_consumer(struct netxen_adapter *adapter,
|
||||
struct nx_host_tx_ring *tx_ring, u32 consumer)
|
||||
struct nx_host_tx_ring *tx_ring)
|
||||
{
|
||||
NXWR32(adapter, tx_ring->crb_cmd_consumer, consumer);
|
||||
NXWR32(adapter, tx_ring->crb_cmd_consumer, tx_ring->sw_consumer);
|
||||
}
|
||||
|
||||
static uint32_t msi_tgt_status[8] = {
|
||||
@@ -900,8 +905,11 @@ netxen_nic_attach(struct netxen_adapter *adapter)
|
||||
tx_ring->crb_cmd_producer = crb_cmd_producer[adapter->portnum];
|
||||
tx_ring->crb_cmd_consumer = crb_cmd_consumer[adapter->portnum];
|
||||
|
||||
netxen_nic_update_cmd_producer(adapter, tx_ring, 0);
|
||||
netxen_nic_update_cmd_consumer(adapter, tx_ring, 0);
|
||||
tx_ring->producer = 0;
|
||||
tx_ring->sw_consumer = 0;
|
||||
|
||||
netxen_nic_update_cmd_producer(adapter, tx_ring);
|
||||
netxen_nic_update_cmd_consumer(adapter, tx_ring);
|
||||
}
|
||||
|
||||
for (ring = 0; ring < adapter->max_rds_rings; ring++) {
|
||||
@@ -1362,7 +1370,7 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
|
||||
dma_addr_t temp_dma;
|
||||
int i, k;
|
||||
|
||||
u32 producer, consumer;
|
||||
u32 producer;
|
||||
int frag_count, no_of_desc;
|
||||
u32 num_txd = tx_ring->num_desc;
|
||||
bool is_tso = false;
|
||||
@@ -1372,15 +1380,13 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
|
||||
/* 4 fragments per cmd des */
|
||||
no_of_desc = (frag_count + 3) >> 2;
|
||||
|
||||
producer = tx_ring->producer;
|
||||
smp_mb();
|
||||
consumer = tx_ring->sw_consumer;
|
||||
if ((no_of_desc+2) >= find_diff_among(producer, consumer, num_txd)) {
|
||||
if (unlikely(no_of_desc + 2) > netxen_tx_avail(tx_ring)) {
|
||||
netif_stop_queue(netdev);
|
||||
smp_mb();
|
||||
return NETDEV_TX_BUSY;
|
||||
}
|
||||
|
||||
producer = tx_ring->producer;
|
||||
|
||||
hwdesc = &tx_ring->desc_head[producer];
|
||||
netxen_clear_cmddesc((u64 *)hwdesc);
|
||||
pbuf = &tx_ring->cmd_buf_arr[producer];
|
||||
@@ -1493,7 +1499,7 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
|
||||
tx_ring->producer = producer;
|
||||
adapter->stats.txbytes += skb->len;
|
||||
|
||||
netxen_nic_update_cmd_producer(adapter, tx_ring, producer);
|
||||
netxen_nic_update_cmd_producer(adapter, tx_ring);
|
||||
|
||||
adapter->stats.xmitcalled++;
|
||||
|
||||
|
Reference in New Issue
Block a user