diff options
Diffstat (limited to 'drivers/net/ethernet/ibm/ibmvnic.c')
| -rw-r--r-- | drivers/net/ethernet/ibm/ibmvnic.c | 45 | 
1 files changed, 36 insertions, 9 deletions
| diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 9198e6bd5160..b23d6545f835 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -404,7 +404,7 @@ static int ibmvnic_open(struct net_device *netdev)  	send_map_query(adapter);  	for (i = 0; i < rxadd_subcrqs; i++) {  		init_rx_pool(adapter, &adapter->rx_pool[i], -			     IBMVNIC_BUFFS_PER_POOL, i, +			     adapter->req_rx_add_entries_per_subcrq, i,  			     be64_to_cpu(size_array[i]), 1);  		if (alloc_rx_pool(adapter, &adapter->rx_pool[i])) {  			dev_err(dev, "Couldn't alloc rx pool\n"); @@ -419,23 +419,23 @@ static int ibmvnic_open(struct net_device *netdev)  	for (i = 0; i < tx_subcrqs; i++) {  		tx_pool = &adapter->tx_pool[i];  		tx_pool->tx_buff = -		    kcalloc(adapter->max_tx_entries_per_subcrq, +		    kcalloc(adapter->req_tx_entries_per_subcrq,  			    sizeof(struct ibmvnic_tx_buff), GFP_KERNEL);  		if (!tx_pool->tx_buff)  			goto tx_pool_alloc_failed;  		if (alloc_long_term_buff(adapter, &tx_pool->long_term_buff, -					 adapter->max_tx_entries_per_subcrq * +					 adapter->req_tx_entries_per_subcrq *  					 adapter->req_mtu))  			goto tx_ltb_alloc_failed;  		tx_pool->free_map = -		    kcalloc(adapter->max_tx_entries_per_subcrq, +		    kcalloc(adapter->req_tx_entries_per_subcrq,  			    sizeof(int), GFP_KERNEL);  		if (!tx_pool->free_map)  			goto tx_fm_alloc_failed; -		for (j = 0; j < adapter->max_tx_entries_per_subcrq; j++) +		for (j = 0; j < adapter->req_tx_entries_per_subcrq; j++)  			tx_pool->free_map[j] = j;  		tx_pool->consumer_index = 0; @@ -705,6 +705,7 @@ static int ibmvnic_xmit(struct sk_buff *skb, struct net_device *netdev)  	u8 *hdrs = (u8 *)&adapter->tx_rx_desc_req;  	struct device *dev = &adapter->vdev->dev;  	struct ibmvnic_tx_buff *tx_buff = NULL; +	struct ibmvnic_sub_crq_queue *tx_scrq;  	struct ibmvnic_tx_pool *tx_pool;  	unsigned int tx_send_failed = 0;  	unsigned int tx_map_failed = 0; @@ -724,6 +725,7 @@ static int ibmvnic_xmit(struct sk_buff *skb, struct net_device *netdev)  	int ret = 0;  	tx_pool = &adapter->tx_pool[queue_num]; +	tx_scrq = adapter->tx_scrq[queue_num];  	txq = netdev_get_tx_queue(netdev, skb_get_queue_mapping(skb));  	handle_array = (u64 *)((u8 *)(adapter->login_rsp_buf) +  				   be32_to_cpu(adapter->login_rsp_buf-> @@ -744,7 +746,7 @@ static int ibmvnic_xmit(struct sk_buff *skb, struct net_device *netdev)  	tx_pool->consumer_index =  	    (tx_pool->consumer_index + 1) % -		adapter->max_tx_entries_per_subcrq; +		adapter->req_tx_entries_per_subcrq;  	tx_buff = &tx_pool->tx_buff[index];  	tx_buff->skb = skb; @@ -817,7 +819,7 @@ static int ibmvnic_xmit(struct sk_buff *skb, struct net_device *netdev)  		if (tx_pool->consumer_index == 0)  			tx_pool->consumer_index = -				adapter->max_tx_entries_per_subcrq - 1; +				adapter->req_tx_entries_per_subcrq - 1;  		else  			tx_pool->consumer_index--; @@ -826,6 +828,14 @@ static int ibmvnic_xmit(struct sk_buff *skb, struct net_device *netdev)  		ret = NETDEV_TX_BUSY;  		goto out;  	} + +	atomic_inc(&tx_scrq->used); + +	if (atomic_read(&tx_scrq->used) >= adapter->req_tx_entries_per_subcrq) { +		netdev_info(netdev, "Stopping queue %d\n", queue_num); +		netif_stop_subqueue(netdev, queue_num); +	} +  	tx_packets++;  	tx_bytes += skb->len;  	txq->trans_start = jiffies; @@ -1213,6 +1223,7 @@ static struct ibmvnic_sub_crq_queue *init_sub_crq_queue(struct ibmvnic_adapter  	scrq->adapter = adapter;  	scrq->size = 4 * PAGE_SIZE / sizeof(*scrq->msgs);  	scrq->cur = 0; +	atomic_set(&scrq->used, 0);  	scrq->rx_skb_top = NULL;  	spin_lock_init(&scrq->lock); @@ -1246,6 +1257,7 @@ static void release_sub_crqs(struct ibmvnic_adapter *adapter)  				release_sub_crq_queue(adapter,  						      adapter->tx_scrq[i]);  			} +		kfree(adapter->tx_scrq);  		adapter->tx_scrq = NULL;  	} @@ -1258,6 +1270,7 @@ static void release_sub_crqs(struct ibmvnic_adapter *adapter)  				release_sub_crq_queue(adapter,  						      adapter->rx_scrq[i]);  			} +		kfree(adapter->rx_scrq);  		adapter->rx_scrq = NULL;  	}  } @@ -1355,14 +1368,28 @@ restart_loop:  						 DMA_TO_DEVICE);  			} -			if (txbuff->last_frag) +			if (txbuff->last_frag) { +				atomic_dec(&scrq->used); + +				if (atomic_read(&scrq->used) <= +				    (adapter->req_tx_entries_per_subcrq / 2) && +				    netif_subqueue_stopped(adapter->netdev, +							   txbuff->skb)) { +					netif_wake_subqueue(adapter->netdev, +							    scrq->pool_index); +					netdev_dbg(adapter->netdev, +						   "Started queue %d\n", +						   scrq->pool_index); +				} +  				dev_kfree_skb_any(txbuff->skb); +			}  			adapter->tx_pool[pool].free_map[adapter->tx_pool[pool].  						     producer_index] = index;  			adapter->tx_pool[pool].producer_index =  			    (adapter->tx_pool[pool].producer_index + 1) % -			    adapter->max_tx_entries_per_subcrq; +			    adapter->req_tx_entries_per_subcrq;  		}  		/* remove tx_comp scrq*/  		next->tx_comp.first = 0; |