diff options
Diffstat (limited to 'drivers/net/ethernet/ibm/ibmvnic.c')
| -rw-r--r-- | drivers/net/ethernet/ibm/ibmvnic.c | 241 | 
1 files changed, 174 insertions, 67 deletions
diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 864cb21351a4..88f3c85fb04a 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -75,6 +75,7 @@  #include <linux/uaccess.h>  #include <asm/firmware.h>  #include <linux/seq_file.h> +#include <linux/workqueue.h>  #include "ibmvnic.h" @@ -89,6 +90,7 @@ MODULE_VERSION(IBMVNIC_DRIVER_VERSION);  static int ibmvnic_version = IBMVNIC_INITIAL_VERSION;  static int ibmvnic_remove(struct vio_dev *);  static void release_sub_crqs(struct ibmvnic_adapter *); +static void release_sub_crqs_no_irqs(struct ibmvnic_adapter *);  static int ibmvnic_reset_crq(struct ibmvnic_adapter *);  static int ibmvnic_send_crq_init(struct ibmvnic_adapter *);  static int ibmvnic_reenable_crq_queue(struct ibmvnic_adapter *); @@ -469,7 +471,8 @@ static int ibmvnic_open(struct net_device *netdev)  	crq.logical_link_state.link_state = IBMVNIC_LOGICAL_LNK_UP;  	ibmvnic_send_crq(adapter, &crq); -	netif_start_queue(netdev); +	netif_tx_start_all_queues(netdev); +  	return 0;  bounce_map_failed: @@ -519,7 +522,7 @@ static int ibmvnic_close(struct net_device *netdev)  	for (i = 0; i < adapter->req_rx_queues; i++)  		napi_disable(&adapter->napi[i]); -	netif_stop_queue(netdev); +	netif_tx_stop_all_queues(netdev);  	if (adapter->bounce_buffer) {  		if (!dma_mapping_error(dev, adapter->bounce_buffer_dma)) { @@ -1212,12 +1215,6 @@ static struct ibmvnic_sub_crq_queue *init_sub_crq_queue(struct ibmvnic_adapter  		goto reg_failed;  	} -	scrq->irq = irq_create_mapping(NULL, scrq->hw_irq); -	if (scrq->irq == NO_IRQ) { -		dev_err(dev, "Error mapping irq\n"); -		goto map_irq_failed; -	} -  	scrq->adapter = adapter;  	scrq->size = 4 * PAGE_SIZE / sizeof(*scrq->msgs);  	scrq->cur = 0; @@ -1230,12 +1227,6 @@ static struct ibmvnic_sub_crq_queue *init_sub_crq_queue(struct ibmvnic_adapter  	return scrq; -map_irq_failed: -	do { -		rc = plpar_hcall_norets(H_FREE_SUB_CRQ, -					adapter->vdev->unit_address, -					scrq->crq_num); -	} while (rc == H_BUSY || H_IS_LONG_BUSY(rc));  reg_failed:  	dma_unmap_single(dev, scrq->msg_token, 4 * PAGE_SIZE,  			 DMA_BIDIRECTIONAL); @@ -1256,6 +1247,7 @@ static void release_sub_crqs(struct ibmvnic_adapter *adapter)  			if (adapter->tx_scrq[i]) {  				free_irq(adapter->tx_scrq[i]->irq,  					 adapter->tx_scrq[i]); +				irq_dispose_mapping(adapter->tx_scrq[i]->irq);  				release_sub_crq_queue(adapter,  						      adapter->tx_scrq[i]);  			} @@ -1267,6 +1259,7 @@ static void release_sub_crqs(struct ibmvnic_adapter *adapter)  			if (adapter->rx_scrq[i]) {  				free_irq(adapter->rx_scrq[i]->irq,  					 adapter->rx_scrq[i]); +				irq_dispose_mapping(adapter->rx_scrq[i]->irq);  				release_sub_crq_queue(adapter,  						      adapter->rx_scrq[i]);  			} @@ -1276,6 +1269,29 @@ static void release_sub_crqs(struct ibmvnic_adapter *adapter)  	adapter->requested_caps = 0;  } +static void release_sub_crqs_no_irqs(struct ibmvnic_adapter *adapter) +{ +	int i; + +	if (adapter->tx_scrq) { +		for (i = 0; i < adapter->req_tx_queues; i++) +			if (adapter->tx_scrq[i]) +				release_sub_crq_queue(adapter, +						      adapter->tx_scrq[i]); +		adapter->tx_scrq = NULL; +	} + +	if (adapter->rx_scrq) { +		for (i = 0; i < adapter->req_rx_queues; i++) +			if (adapter->rx_scrq[i]) +				release_sub_crq_queue(adapter, +						      adapter->rx_scrq[i]); +		adapter->rx_scrq = NULL; +	} + +	adapter->requested_caps = 0; +} +  static int disable_scrq_irq(struct ibmvnic_adapter *adapter,  			    struct ibmvnic_sub_crq_queue *scrq)  { @@ -1395,6 +1411,66 @@ static irqreturn_t ibmvnic_interrupt_rx(int irq, void *instance)  	return IRQ_HANDLED;  } +static int init_sub_crq_irqs(struct ibmvnic_adapter *adapter) +{ +	struct device *dev = &adapter->vdev->dev; +	struct ibmvnic_sub_crq_queue *scrq; +	int i = 0, j = 0; +	int rc = 0; + +	for (i = 0; i < adapter->req_tx_queues; i++) { +		scrq = adapter->tx_scrq[i]; +		scrq->irq = irq_create_mapping(NULL, scrq->hw_irq); + +		if (scrq->irq == NO_IRQ) { +			rc = -EINVAL; +			dev_err(dev, "Error mapping irq\n"); +			goto req_tx_irq_failed; +		} + +		rc = request_irq(scrq->irq, ibmvnic_interrupt_tx, +				 0, "ibmvnic_tx", scrq); + +		if (rc) { +			dev_err(dev, "Couldn't register tx irq 0x%x. rc=%d\n", +				scrq->irq, rc); +			irq_dispose_mapping(scrq->irq); +			goto req_rx_irq_failed; +		} +	} + +	for (i = 0; i < adapter->req_rx_queues; i++) { +		scrq = adapter->rx_scrq[i]; +		scrq->irq = irq_create_mapping(NULL, scrq->hw_irq); +		if (scrq->irq == NO_IRQ) { +			rc = -EINVAL; +			dev_err(dev, "Error mapping irq\n"); +			goto req_rx_irq_failed; +		} +		rc = request_irq(scrq->irq, ibmvnic_interrupt_rx, +				 0, "ibmvnic_rx", scrq); +		if (rc) { +			dev_err(dev, "Couldn't register rx irq 0x%x. rc=%d\n", +				scrq->irq, rc); +			irq_dispose_mapping(scrq->irq); +			goto req_rx_irq_failed; +		} +	} +	return rc; + +req_rx_irq_failed: +	for (j = 0; j < i; j++) +		free_irq(adapter->rx_scrq[j]->irq, adapter->rx_scrq[j]); +		irq_dispose_mapping(adapter->rx_scrq[j]->irq); +	i = adapter->req_tx_queues; +req_tx_irq_failed: +	for (j = 0; j < i; j++) +		free_irq(adapter->tx_scrq[j]->irq, adapter->tx_scrq[j]); +		irq_dispose_mapping(adapter->rx_scrq[j]->irq); +	release_sub_crqs_no_irqs(adapter); +	return rc; +} +  static void init_sub_crqs(struct ibmvnic_adapter *adapter, int retry)  {  	struct device *dev = &adapter->vdev->dev; @@ -1403,8 +1479,7 @@ static void init_sub_crqs(struct ibmvnic_adapter *adapter, int retry)  	union ibmvnic_crq crq;  	int total_queues;  	int more = 0; -	int i, j; -	int rc; +	int i;  	if (!retry) {  		/* Sub-CRQ entries are 32 byte long */ @@ -1483,13 +1558,6 @@ static void init_sub_crqs(struct ibmvnic_adapter *adapter, int retry)  	for (i = 0; i < adapter->req_tx_queues; i++) {  		adapter->tx_scrq[i] = allqueues[i];  		adapter->tx_scrq[i]->pool_index = i; -		rc = request_irq(adapter->tx_scrq[i]->irq, ibmvnic_interrupt_tx, -				 0, "ibmvnic_tx", adapter->tx_scrq[i]); -		if (rc) { -			dev_err(dev, "Couldn't register tx irq 0x%x. rc=%d\n", -				adapter->tx_scrq[i]->irq, rc); -			goto req_tx_irq_failed; -		}  	}  	adapter->rx_scrq = kcalloc(adapter->req_rx_queues, @@ -1500,13 +1568,6 @@ static void init_sub_crqs(struct ibmvnic_adapter *adapter, int retry)  	for (i = 0; i < adapter->req_rx_queues; i++) {  		adapter->rx_scrq[i] = allqueues[i + adapter->req_tx_queues];  		adapter->rx_scrq[i]->scrq_num = i; -		rc = request_irq(adapter->rx_scrq[i]->irq, ibmvnic_interrupt_rx, -				 0, "ibmvnic_rx", adapter->rx_scrq[i]); -		if (rc) { -			dev_err(dev, "Couldn't register rx irq 0x%x. rc=%d\n", -				adapter->rx_scrq[i]->irq, rc); -			goto req_rx_irq_failed; -		}  	}  	memset(&crq, 0, sizeof(crq)); @@ -1559,15 +1620,6 @@ static void init_sub_crqs(struct ibmvnic_adapter *adapter, int retry)  	return; -req_rx_irq_failed: -	for (j = 0; j < i; j++) -		free_irq(adapter->rx_scrq[j]->irq, adapter->rx_scrq[j]); -	i = adapter->req_tx_queues; -req_tx_irq_failed: -	for (j = 0; j < i; j++) -		free_irq(adapter->tx_scrq[j]->irq, adapter->tx_scrq[j]); -	kfree(adapter->rx_scrq); -	adapter->rx_scrq = NULL;  rx_failed:  	kfree(adapter->tx_scrq);  	adapter->tx_scrq = NULL; @@ -2121,7 +2173,7 @@ static void handle_error_info_rsp(union ibmvnic_crq *crq,  				  struct ibmvnic_adapter *adapter)  {  	struct device *dev = &adapter->vdev->dev; -	struct ibmvnic_error_buff *error_buff; +	struct ibmvnic_error_buff *error_buff, *tmp;  	unsigned long flags;  	bool found = false;  	int i; @@ -2133,7 +2185,7 @@ static void handle_error_info_rsp(union ibmvnic_crq *crq,  	}  	spin_lock_irqsave(&adapter->error_list_lock, flags); -	list_for_each_entry(error_buff, &adapter->errors, list) +	list_for_each_entry_safe(error_buff, tmp, &adapter->errors, list)  		if (error_buff->error_id == crq->request_error_rsp.error_id) {  			found = true;  			list_del(&error_buff->list); @@ -2348,9 +2400,9 @@ static void handle_request_cap_rsp(union ibmvnic_crq *crq,  			 *req_value,  			 (long int)be32_to_cpu(crq->request_capability_rsp.  					       number), name); -		release_sub_crqs(adapter); +		release_sub_crqs_no_irqs(adapter);  		*req_value = be32_to_cpu(crq->request_capability_rsp.number); -		complete(&adapter->init_done); +		init_sub_crqs(adapter, 1);  		return;  	default:  		dev_err(dev, "Error %d in request cap rsp\n", @@ -2659,7 +2711,7 @@ static void handle_query_cap_rsp(union ibmvnic_crq *crq,  out:  	if (atomic_read(&adapter->running_cap_queries) == 0) -		complete(&adapter->init_done); +		init_sub_crqs(adapter, 0);  		/* We're done querying the capabilities, initialize sub-crqs */  } @@ -3141,14 +3193,14 @@ static void handle_request_ras_comp_num_rsp(union ibmvnic_crq *crq,  static void ibmvnic_free_inflight(struct ibmvnic_adapter *adapter)  { -	struct ibmvnic_inflight_cmd *inflight_cmd; +	struct ibmvnic_inflight_cmd *inflight_cmd, *tmp1;  	struct device *dev = &adapter->vdev->dev; -	struct ibmvnic_error_buff *error_buff; +	struct ibmvnic_error_buff *error_buff, *tmp2;  	unsigned long flags;  	unsigned long flags2;  	spin_lock_irqsave(&adapter->inflight_lock, flags); -	list_for_each_entry(inflight_cmd, &adapter->inflight, list) { +	list_for_each_entry_safe(inflight_cmd, tmp1, &adapter->inflight, list) {  		switch (inflight_cmd->crq.generic.cmd) {  		case LOGIN:  			dma_unmap_single(dev, adapter->login_buf_token, @@ -3165,8 +3217,8 @@ static void ibmvnic_free_inflight(struct ibmvnic_adapter *adapter)  			break;  		case REQUEST_ERROR_INFO:  			spin_lock_irqsave(&adapter->error_list_lock, flags2); -			list_for_each_entry(error_buff, &adapter->errors, -					    list) { +			list_for_each_entry_safe(error_buff, tmp2, +						 &adapter->errors, list) {  				dma_unmap_single(dev, error_buff->dma,  						 error_buff->len,  						 DMA_FROM_DEVICE); @@ -3202,8 +3254,8 @@ static void ibmvnic_handle_crq(union ibmvnic_crq *crq,  			dev_info(dev, "Partner initialized\n");  			/* Send back a response */  			rc = ibmvnic_send_crq_init_complete(adapter); -			if (rc == 0) -				send_version_xchg(adapter); +			if (!rc) +				schedule_work(&adapter->vnic_crq_init);  			else  				dev_err(dev, "Can't send initrsp rc=%ld\n", rc);  			break; @@ -3555,8 +3607,63 @@ static const struct file_operations ibmvnic_dump_ops = {  	.release        = single_release,  }; +static void handle_crq_init_rsp(struct work_struct *work) +{ +	struct ibmvnic_adapter *adapter = container_of(work, +						       struct ibmvnic_adapter, +						       vnic_crq_init); +	struct device *dev = &adapter->vdev->dev; +	struct net_device *netdev = adapter->netdev; +	unsigned long timeout = msecs_to_jiffies(30000); +	int rc; + +	send_version_xchg(adapter); +	reinit_completion(&adapter->init_done); +	if (!wait_for_completion_timeout(&adapter->init_done, timeout)) { +		dev_err(dev, "Passive init timeout\n"); +		goto task_failed; +	} + +	do { +		if (adapter->renegotiate) { +			adapter->renegotiate = false; +			release_sub_crqs_no_irqs(adapter); +			send_cap_queries(adapter); + +			reinit_completion(&adapter->init_done); +			if (!wait_for_completion_timeout(&adapter->init_done, +							 timeout)) { +				dev_err(dev, "Passive init timeout\n"); +				goto task_failed; +			} +		} +	} while (adapter->renegotiate); +	rc = init_sub_crq_irqs(adapter); + +	if (rc) +		goto task_failed; + +	netdev->real_num_tx_queues = adapter->req_tx_queues; + +	rc = register_netdev(netdev); +	if (rc) { +		dev_err(dev, +			"failed to register netdev rc=%d\n", rc); +		goto register_failed; +	} +	dev_info(dev, "ibmvnic registered\n"); + +	return; + +register_failed: +	release_sub_crqs(adapter); +task_failed: +	dev_err(dev, "Passive initialization was not successful\n"); +} +  static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)  { +	unsigned long timeout = msecs_to_jiffies(30000);  	struct ibmvnic_adapter *adapter;  	struct net_device *netdev;  	unsigned char *mac_addr_p; @@ -3593,6 +3700,8 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)  	netdev->ethtool_ops = &ibmvnic_ethtool_ops;  	SET_NETDEV_DEV(netdev, &dev->dev); +	INIT_WORK(&adapter->vnic_crq_init, handle_crq_init_rsp); +  	spin_lock_init(&adapter->stats_lock);  	rc = ibmvnic_init_crq_queue(adapter); @@ -3635,30 +3744,26 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)  	ibmvnic_send_crq_init(adapter);  	init_completion(&adapter->init_done); -	wait_for_completion(&adapter->init_done); +	if (!wait_for_completion_timeout(&adapter->init_done, timeout)) +		return 0;  	do { -		adapter->renegotiate = false; - -		init_sub_crqs(adapter, 0); -		reinit_completion(&adapter->init_done); -		wait_for_completion(&adapter->init_done); -  		if (adapter->renegotiate) { -			release_sub_crqs(adapter); +			adapter->renegotiate = false; +			release_sub_crqs_no_irqs(adapter);  			send_cap_queries(adapter);  			reinit_completion(&adapter->init_done); -			wait_for_completion(&adapter->init_done); +			if (!wait_for_completion_timeout(&adapter->init_done, +							 timeout)) +				return 0;  		}  	} while (adapter->renegotiate); -	/* if init_sub_crqs is partially successful, retry */ -	while (!adapter->tx_scrq || !adapter->rx_scrq) { -		init_sub_crqs(adapter, 1); - -		reinit_completion(&adapter->init_done); -		wait_for_completion(&adapter->init_done); +	rc = init_sub_crq_irqs(adapter); +	if (rc) { +		dev_err(&dev->dev, "failed to initialize sub crq irqs\n"); +		goto free_debugfs;  	}  	netdev->real_num_tx_queues = adapter->req_tx_queues; @@ -3666,12 +3771,14 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)  	rc = register_netdev(netdev);  	if (rc) {  		dev_err(&dev->dev, "failed to register netdev rc=%d\n", rc); -		goto free_debugfs; +		goto free_sub_crqs;  	}  	dev_info(&dev->dev, "ibmvnic registered\n");  	return 0; +free_sub_crqs: +	release_sub_crqs(adapter);  free_debugfs:  	if (adapter->debugfs_dir && !IS_ERR(adapter->debugfs_dir))  		debugfs_remove_recursive(adapter->debugfs_dir);  |