Commit ea22d51a authored by Thomas Falcon's avatar Thomas Falcon Committed by David S. Miller

ibmvnic: simplify and improve driver probe function

This patch creates a function that handles sub-CRQ IRQ creation
separately from sub-CRQ initialization. Another function is then needed
to release sub-CRQ resources prior to sub-CRQ IRQ creation.

These additions allow the driver probe function to be simplified,
specifically during the VNIC Server login process. A timeout is also
included while waiting for completion of the login process in case
the VNIC Server is not available or some other error occurs.
Signed-off-by: default avatarThomas Falcon <tlfalcon@linux.vnet.ibm.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 88eb98a0
...@@ -89,6 +89,7 @@ MODULE_VERSION(IBMVNIC_DRIVER_VERSION); ...@@ -89,6 +89,7 @@ MODULE_VERSION(IBMVNIC_DRIVER_VERSION);
static int ibmvnic_version = IBMVNIC_INITIAL_VERSION; static int ibmvnic_version = IBMVNIC_INITIAL_VERSION;
static int ibmvnic_remove(struct vio_dev *); static int ibmvnic_remove(struct vio_dev *);
static void release_sub_crqs(struct ibmvnic_adapter *); 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_reset_crq(struct ibmvnic_adapter *);
static int ibmvnic_send_crq_init(struct ibmvnic_adapter *); static int ibmvnic_send_crq_init(struct ibmvnic_adapter *);
static int ibmvnic_reenable_crq_queue(struct ibmvnic_adapter *); static int ibmvnic_reenable_crq_queue(struct ibmvnic_adapter *);
...@@ -1213,12 +1214,6 @@ static struct ibmvnic_sub_crq_queue *init_sub_crq_queue(struct ibmvnic_adapter ...@@ -1213,12 +1214,6 @@ static struct ibmvnic_sub_crq_queue *init_sub_crq_queue(struct ibmvnic_adapter
goto reg_failed; 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->adapter = adapter;
scrq->size = 4 * PAGE_SIZE / sizeof(*scrq->msgs); scrq->size = 4 * PAGE_SIZE / sizeof(*scrq->msgs);
scrq->cur = 0; scrq->cur = 0;
...@@ -1231,12 +1226,6 @@ static struct ibmvnic_sub_crq_queue *init_sub_crq_queue(struct ibmvnic_adapter ...@@ -1231,12 +1226,6 @@ static struct ibmvnic_sub_crq_queue *init_sub_crq_queue(struct ibmvnic_adapter
return scrq; 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: reg_failed:
dma_unmap_single(dev, scrq->msg_token, 4 * PAGE_SIZE, dma_unmap_single(dev, scrq->msg_token, 4 * PAGE_SIZE,
DMA_BIDIRECTIONAL); DMA_BIDIRECTIONAL);
...@@ -1279,6 +1268,29 @@ static void release_sub_crqs(struct ibmvnic_adapter *adapter) ...@@ -1279,6 +1268,29 @@ static void release_sub_crqs(struct ibmvnic_adapter *adapter)
adapter->requested_caps = 0; 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, static int disable_scrq_irq(struct ibmvnic_adapter *adapter,
struct ibmvnic_sub_crq_queue *scrq) struct ibmvnic_sub_crq_queue *scrq)
{ {
...@@ -1398,6 +1410,66 @@ static irqreturn_t ibmvnic_interrupt_rx(int irq, void *instance) ...@@ -1398,6 +1410,66 @@ static irqreturn_t ibmvnic_interrupt_rx(int irq, void *instance)
return IRQ_HANDLED; 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) static void init_sub_crqs(struct ibmvnic_adapter *adapter, int retry)
{ {
struct device *dev = &adapter->vdev->dev; struct device *dev = &adapter->vdev->dev;
...@@ -1406,8 +1478,7 @@ static void init_sub_crqs(struct ibmvnic_adapter *adapter, int retry) ...@@ -1406,8 +1478,7 @@ static void init_sub_crqs(struct ibmvnic_adapter *adapter, int retry)
union ibmvnic_crq crq; union ibmvnic_crq crq;
int total_queues; int total_queues;
int more = 0; int more = 0;
int i, j; int i;
int rc;
if (!retry) { if (!retry) {
/* Sub-CRQ entries are 32 byte long */ /* Sub-CRQ entries are 32 byte long */
...@@ -1486,13 +1557,6 @@ static void init_sub_crqs(struct ibmvnic_adapter *adapter, int retry) ...@@ -1486,13 +1557,6 @@ static void init_sub_crqs(struct ibmvnic_adapter *adapter, int retry)
for (i = 0; i < adapter->req_tx_queues; i++) { for (i = 0; i < adapter->req_tx_queues; i++) {
adapter->tx_scrq[i] = allqueues[i]; adapter->tx_scrq[i] = allqueues[i];
adapter->tx_scrq[i]->pool_index = 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, adapter->rx_scrq = kcalloc(adapter->req_rx_queues,
...@@ -1503,13 +1567,6 @@ static void init_sub_crqs(struct ibmvnic_adapter *adapter, int retry) ...@@ -1503,13 +1567,6 @@ static void init_sub_crqs(struct ibmvnic_adapter *adapter, int retry)
for (i = 0; i < adapter->req_rx_queues; i++) { for (i = 0; i < adapter->req_rx_queues; i++) {
adapter->rx_scrq[i] = allqueues[i + adapter->req_tx_queues]; adapter->rx_scrq[i] = allqueues[i + adapter->req_tx_queues];
adapter->rx_scrq[i]->scrq_num = i; 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)); memset(&crq, 0, sizeof(crq));
...@@ -1562,15 +1619,6 @@ static void init_sub_crqs(struct ibmvnic_adapter *adapter, int retry) ...@@ -1562,15 +1619,6 @@ static void init_sub_crqs(struct ibmvnic_adapter *adapter, int retry)
return; 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: rx_failed:
kfree(adapter->tx_scrq); kfree(adapter->tx_scrq);
adapter->tx_scrq = NULL; adapter->tx_scrq = NULL;
...@@ -2351,9 +2399,9 @@ static void handle_request_cap_rsp(union ibmvnic_crq *crq, ...@@ -2351,9 +2399,9 @@ static void handle_request_cap_rsp(union ibmvnic_crq *crq,
*req_value, *req_value,
(long int)be32_to_cpu(crq->request_capability_rsp. (long int)be32_to_cpu(crq->request_capability_rsp.
number), name); number), name);
release_sub_crqs(adapter); release_sub_crqs_no_irqs(adapter);
*req_value = be32_to_cpu(crq->request_capability_rsp.number); *req_value = be32_to_cpu(crq->request_capability_rsp.number);
complete(&adapter->init_done); init_sub_crqs(adapter, 1);
return; return;
default: default:
dev_err(dev, "Error %d in request cap rsp\n", dev_err(dev, "Error %d in request cap rsp\n",
...@@ -2662,7 +2710,7 @@ static void handle_query_cap_rsp(union ibmvnic_crq *crq, ...@@ -2662,7 +2710,7 @@ static void handle_query_cap_rsp(union ibmvnic_crq *crq,
out: out:
if (atomic_read(&adapter->running_cap_queries) == 0) 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 */ /* We're done querying the capabilities, initialize sub-crqs */
} }
...@@ -3560,6 +3608,7 @@ static const struct file_operations ibmvnic_dump_ops = { ...@@ -3560,6 +3608,7 @@ static const struct file_operations ibmvnic_dump_ops = {
static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id) 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 ibmvnic_adapter *adapter;
struct net_device *netdev; struct net_device *netdev;
unsigned char *mac_addr_p; unsigned char *mac_addr_p;
...@@ -3638,30 +3687,26 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id) ...@@ -3638,30 +3687,26 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
ibmvnic_send_crq_init(adapter); ibmvnic_send_crq_init(adapter);
init_completion(&adapter->init_done); init_completion(&adapter->init_done);
wait_for_completion(&adapter->init_done); if (!wait_for_completion_timeout(&adapter->init_done, timeout))
return 0;
do { do {
adapter->renegotiate = false;
init_sub_crqs(adapter, 0);
reinit_completion(&adapter->init_done);
wait_for_completion(&adapter->init_done);
if (adapter->renegotiate) { if (adapter->renegotiate) {
release_sub_crqs(adapter); adapter->renegotiate = false;
release_sub_crqs_no_irqs(adapter);
send_cap_queries(adapter); send_cap_queries(adapter);
reinit_completion(&adapter->init_done); 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); } while (adapter->renegotiate);
/* if init_sub_crqs is partially successful, retry */ rc = init_sub_crq_irqs(adapter);
while (!adapter->tx_scrq || !adapter->rx_scrq) { if (rc) {
init_sub_crqs(adapter, 1); dev_err(&dev->dev, "failed to initialize sub crq irqs\n");
goto free_debugfs;
reinit_completion(&adapter->init_done);
wait_for_completion(&adapter->init_done);
} }
netdev->real_num_tx_queues = adapter->req_tx_queues; netdev->real_num_tx_queues = adapter->req_tx_queues;
...@@ -3669,12 +3714,14 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id) ...@@ -3669,12 +3714,14 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
rc = register_netdev(netdev); rc = register_netdev(netdev);
if (rc) { if (rc) {
dev_err(&dev->dev, "failed to register netdev rc=%d\n", 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"); dev_info(&dev->dev, "ibmvnic registered\n");
return 0; return 0;
free_sub_crqs:
release_sub_crqs(adapter);
free_debugfs: free_debugfs:
if (adapter->debugfs_dir && !IS_ERR(adapter->debugfs_dir)) if (adapter->debugfs_dir && !IS_ERR(adapter->debugfs_dir))
debugfs_remove_recursive(adapter->debugfs_dir); debugfs_remove_recursive(adapter->debugfs_dir);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment