From d944c3d60ac9ec6968d97ac5704155d0afac5216 Mon Sep 17 00:00:00 2001 From: John Allen Date: Fri, 26 May 2017 10:30:13 -0400 Subject: [PATCH 01/11] ibmvnic: Track state of adapter napis Track the state of ibmvnic napis. The driver can get into states where it can be reset when napis are already disabled and attempting to disable them again will cause the driver to hang. Signed-off-by: John Allen Signed-off-by: Nathan Fontenot Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 37 ++++++++++++++++++++++-------- drivers/net/ethernet/ibm/ibmvnic.h | 1 + 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 27f79339e9a8..4997de425b5c 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -518,6 +518,32 @@ static void release_error_buffers(struct ibmvnic_adapter *adapter) spin_unlock_irqrestore(&adapter->error_list_lock, flags); } +static void ibmvnic_napi_enable(struct ibmvnic_adapter *adapter) +{ + int i; + + if (adapter->napi_enabled) + return; + + for (i = 0; i < adapter->req_rx_queues; i++) + napi_enable(&adapter->napi[i]); + + adapter->napi_enabled = true; +} + +static void ibmvnic_napi_disable(struct ibmvnic_adapter *adapter) +{ + int i; + + if (!adapter->napi_enabled) + return; + + for (i = 0; i < adapter->req_rx_queues; i++) + napi_disable(&adapter->napi[i]); + + adapter->napi_enabled = false; +} + static int ibmvnic_login(struct net_device *netdev) { struct ibmvnic_adapter *adapter = netdev_priv(netdev); @@ -674,9 +700,7 @@ static int __ibmvnic_open(struct net_device *netdev) adapter->state = VNIC_OPENING; replenish_pools(adapter); - - for (i = 0; i < adapter->req_rx_queues; i++) - napi_enable(&adapter->napi[i]); + ibmvnic_napi_enable(adapter); /* We're ready to receive frames, enable the sub-crq interrupts and * set the logical link state to up @@ -779,12 +803,7 @@ static int __ibmvnic_close(struct net_device *netdev) adapter->state = VNIC_CLOSING; netif_tx_stop_all_queues(netdev); - - if (adapter->napi) { - for (i = 0; i < adapter->req_rx_queues; i++) - napi_disable(&adapter->napi[i]); - } - + ibmvnic_napi_disable(adapter); clean_tx_pools(adapter); if (adapter->tx_scrq) { diff --git a/drivers/net/ethernet/ibm/ibmvnic.h b/drivers/net/ethernet/ibm/ibmvnic.h index 4702b48cfa44..4816e0425025 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.h +++ b/drivers/net/ethernet/ibm/ibmvnic.h @@ -1031,4 +1031,5 @@ struct ibmvnic_adapter { struct list_head rwi_list; struct work_struct ibmvnic_reset; bool resetting; + bool napi_enabled; }; From 017892c1ec15d4efcb30edf9fb56a64c889540c3 Mon Sep 17 00:00:00 2001 From: John Allen Date: Fri, 26 May 2017 10:30:19 -0400 Subject: [PATCH 02/11] ibmvnic: Handle failover after failed init crq Handle case where phyp sends a failover after failing to send the init crq. Signed-off-by: John Allen Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 11 ++++++++++- drivers/net/ethernet/ibm/ibmvnic.h | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 4997de425b5c..1f7cf6fbe150 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -3167,6 +3167,8 @@ static void ibmvnic_handle_crq(union ibmvnic_crq *crq, switch (gen_crq->cmd) { case IBMVNIC_CRQ_INIT: dev_info(dev, "Partner initialized\n"); + adapter->from_passive_init = true; + complete(&adapter->init_done); break; case IBMVNIC_CRQ_INIT_COMPLETE: dev_info(dev, "Partner initialization complete\n"); @@ -3481,11 +3483,18 @@ static int ibmvnic_init(struct ibmvnic_adapter *adapter) return rc; } + adapter->from_passive_init = false; + init_completion(&adapter->init_done); ibmvnic_send_crq_init(adapter); if (!wait_for_completion_timeout(&adapter->init_done, timeout)) { dev_err(dev, "Initialization sequence timed out\n"); - release_crq_queue(adapter); + return -1; + } + + if (adapter->from_passive_init) { + adapter->state = VNIC_OPEN; + adapter->from_passive_init = false; return -1; } diff --git a/drivers/net/ethernet/ibm/ibmvnic.h b/drivers/net/ethernet/ibm/ibmvnic.h index 4816e0425025..fa6ac4e4a16e 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.h +++ b/drivers/net/ethernet/ibm/ibmvnic.h @@ -1031,5 +1031,5 @@ struct ibmvnic_adapter { struct list_head rwi_list; struct work_struct ibmvnic_reset; bool resetting; - bool napi_enabled; + bool napi_enabled, from_passive_init; }; From 2ce9e4efbf4289ce48144ec4986f58033890fb6d Mon Sep 17 00:00:00 2001 From: John Allen Date: Fri, 26 May 2017 10:30:25 -0400 Subject: [PATCH 03/11] ibmvnic: Send gratuitous arp on reset Send gratuitous arp after any reset. Signed-off-by: John Allen Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 1f7cf6fbe150..465a8fafd95b 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -1273,6 +1273,7 @@ static int do_reset(struct ibmvnic_adapter *adapter, for (i = 0; i < adapter->req_rx_queues; i++) napi_schedule(&adapter->napi[i]); + netdev_notify_peers(netdev); return 0; } From 10f7621588b86d181a167c1535d0754eb5a58ba8 Mon Sep 17 00:00:00 2001 From: Thomas Falcon Date: Fri, 26 May 2017 10:30:31 -0400 Subject: [PATCH 04/11] ibmvnic: Fix cleanup of SKB's on driver close A race condition occurs when closing the driver. Free'ing of skb's can race between the close routine and ibmvnic_tx_interrupt. To fix this we move the claenup of tx pools during close to after the sub-CRQ interrupts are disabled. Signed-off-by: Thomas Falcon Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 465a8fafd95b..0f705e68755f 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -804,7 +804,6 @@ static int __ibmvnic_close(struct net_device *netdev) adapter->state = VNIC_CLOSING; netif_tx_stop_all_queues(netdev); ibmvnic_napi_disable(adapter); - clean_tx_pools(adapter); if (adapter->tx_scrq) { for (i = 0; i < adapter->req_tx_queues; i++) @@ -833,6 +832,7 @@ static int __ibmvnic_close(struct net_device *netdev) } } + clean_tx_pools(adapter); adapter->state = VNIC_CLOSED; return rc; } From 8cb31cfc9448e2ce0bda899eb15f74bc0a875d90 Mon Sep 17 00:00:00 2001 From: John Allen Date: Fri, 26 May 2017 10:30:37 -0400 Subject: [PATCH 05/11] ibmvnic: Non-fatal error handling Handle non-fatal error conditions. The process to do this when resetting the driver is to just do __ibmvnic_close followed by __ibmvnic_open. Signed-off-by: John Allen Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 64 ++++++++++++++++-------------- drivers/net/ethernet/ibm/ibmvnic.h | 1 + 2 files changed, 36 insertions(+), 29 deletions(-) diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 0f705e68755f..def867aaa422 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -1225,38 +1225,42 @@ static int do_reset(struct ibmvnic_adapter *adapter, if (rc) return rc; - /* remove the closed state so when we call open it appears - * we are coming from the probed state. - */ - adapter->state = VNIC_PROBED; - - release_resources(adapter); - release_sub_crqs(adapter); - release_crq_queue(adapter); - - rc = ibmvnic_init(adapter); - if (rc) - return 0; - - /* If the adapter was in PROBE state prior to the reset, exit here. */ - if (reset_state == VNIC_PROBED) - return 0; - - rc = ibmvnic_login(netdev); - if (rc) { + if (adapter->reset_reason != VNIC_RESET_NON_FATAL) { + /* remove the closed state so when we call open it appears + * we are coming from the probed state. + */ adapter->state = VNIC_PROBED; - return 0; + + release_resources(adapter); + release_sub_crqs(adapter); + release_crq_queue(adapter); + + rc = ibmvnic_init(adapter); + if (rc) + return 0; + + /* If the adapter was in PROBE state prior to the reset, + * exit here. + */ + if (reset_state == VNIC_PROBED) + return 0; + + rc = ibmvnic_login(netdev); + if (rc) { + adapter->state = VNIC_PROBED; + return 0; + } + + rtnl_lock(); + rc = init_resources(adapter); + rtnl_unlock(); + if (rc) + return rc; + + if (reset_state == VNIC_CLOSED) + return 0; } - rtnl_lock(); - rc = init_resources(adapter); - rtnl_unlock(); - if (rc) - return rc; - - if (reset_state == VNIC_CLOSED) - return 0; - rc = __ibmvnic_open(netdev); if (rc) { if (list_empty(&adapter->rwi_list)) @@ -2763,6 +2767,8 @@ static void handle_error_indication(union ibmvnic_crq *crq, if (crq->error_indication.flags & IBMVNIC_FATAL_ERROR) ibmvnic_reset(adapter, VNIC_RESET_FATAL); + else + ibmvnic_reset(adapter, VNIC_RESET_NON_FATAL); } static void handle_change_mac_rsp(union ibmvnic_crq *crq, diff --git a/drivers/net/ethernet/ibm/ibmvnic.h b/drivers/net/ethernet/ibm/ibmvnic.h index fa6ac4e4a16e..7e2300e64a47 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.h +++ b/drivers/net/ethernet/ibm/ibmvnic.h @@ -925,6 +925,7 @@ enum vnic_state {VNIC_PROBING = 1, enum ibmvnic_reset_reason {VNIC_RESET_FAILOVER = 1, VNIC_RESET_MOBILITY, VNIC_RESET_FATAL, + VNIC_RESET_NON_FATAL, VNIC_RESET_TIMEOUT}; struct ibmvnic_rwi { From b8c80b8413eec7ae154cdad692a7fd1cb32d0370 Mon Sep 17 00:00:00 2001 From: Thomas Falcon Date: Fri, 26 May 2017 10:30:42 -0400 Subject: [PATCH 06/11] ibmvnic: Halt TX and report carrier off on H_CLOSED return code This patch disables transmissions and reports carrier off if xmit function returns that the hardware TX queue is closed. The driver can then await a signal from firmware to determine the correct reset method. Signed-off-by: Thomas Falcon Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index def867aaa422..1c3f1edea9db 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -1111,8 +1111,14 @@ static int ibmvnic_xmit(struct sk_buff *skb, struct net_device *netdev) dev_kfree_skb_any(skb); tx_buff->skb = NULL; - if (lpar_rc == H_CLOSED) - netif_stop_subqueue(netdev, queue_num); + if (lpar_rc == H_CLOSED) { + /* Disable TX and report carrier off if queue is closed. + * Firmware guarantees that a signal will be sent to the + * driver, triggering a reset or some other action. + */ + netif_tx_stop_all_queues(netdev); + netif_carrier_off(netdev); + } tx_send_failed++; tx_dropped++; From f185a49a77bd34309fd6af6c5c7695386d010534 Mon Sep 17 00:00:00 2001 From: Thomas Falcon Date: Fri, 26 May 2017 10:30:48 -0400 Subject: [PATCH 07/11] ibmvnic: Deactivate RX pool buffer replenishment on H_CLOSED If H_CLOSED is returned, halt RX buffer replenishment activity until firmware sends a notification that the driver can reset. Signed-off-by: Thomas Falcon Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 1c3f1edea9db..47421e4052c3 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -200,6 +200,15 @@ static void free_long_term_buff(struct ibmvnic_adapter *adapter, dma_free_coherent(dev, ltb->size, ltb->buff, ltb->addr); } +static void deactivate_rx_pools(struct ibmvnic_adapter *adapter) +{ + int i; + + for (i = 0; i < be32_to_cpu(adapter->login_rsp_buf->num_rxadd_subcrqs); + i++) + adapter->rx_pool[i].active = 0; +} + static void replenish_rx_pool(struct ibmvnic_adapter *adapter, struct ibmvnic_rx_pool *pool) { @@ -217,6 +226,9 @@ static void replenish_rx_pool(struct ibmvnic_adapter *adapter, int index; int i; + if (!pool->active) + return; + handle_array = (u64 *)((u8 *)(adapter->login_rsp_buf) + be32_to_cpu(adapter->login_rsp_buf-> off_rxadd_subcrqs)); @@ -287,6 +299,15 @@ failure: dev_kfree_skb_any(skb); adapter->replenish_add_buff_failure++; atomic_add(buffers_added, &pool->available); + + if (lpar_rc == H_CLOSED) { + /* Disable buffer pool replenishment and report carrier off if + * queue is closed. Firmware guarantees that a signal will + * be sent to the driver, triggering a reset. + */ + deactivate_rx_pools(adapter); + netif_carrier_off(adapter->netdev); + } } static void replenish_pools(struct ibmvnic_adapter *adapter) From 152ce47dc48280182ab58539a721dadb3d7a8575 Mon Sep 17 00:00:00 2001 From: Nathan Fontenot Date: Fri, 26 May 2017 10:30:54 -0400 Subject: [PATCH 08/11] ibmvnic: Check adapter state during ibmvnic_poll We do not want to process any receive frames if the ibmvnic_poll routine is invoked while a reset is in process. Also, before replenishing the rx pools in the ibmvnic_poll, we want to make sure the adapter is not in the process of closing. Signed-off-by: Nathan Fontenot Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 47421e4052c3..760352f7f98d 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -1435,6 +1435,10 @@ static int ibmvnic_poll(struct napi_struct *napi, int budget) struct ibmvnic_adapter *adapter = netdev_priv(netdev); int scrq_num = (int)(napi - adapter->napi); int frames_processed = 0; + + if (adapter->resetting) + return 0; + restart_poll: while (frames_processed < budget) { struct sk_buff *skb; @@ -1493,7 +1497,9 @@ restart_poll: netdev->stats.rx_bytes += length; frames_processed++; } - replenish_rx_pool(adapter, &adapter->rx_pool[scrq_num]); + + if (adapter->state != VNIC_CLOSING) + replenish_rx_pool(adapter, &adapter->rx_pool[scrq_num]); if (frames_processed < budget) { enable_scrq_irq(adapter, adapter->rx_scrq[scrq_num]); From 28cde751021abb16458b858da3403bd7c511c0d7 Mon Sep 17 00:00:00 2001 From: Nathan Fontenot Date: Fri, 26 May 2017 10:31:00 -0400 Subject: [PATCH 09/11] ibmvnic: Reset the CRQ queue during driver reset When a driver reset operation occurs there is not a need to release the CRQ resources and re-allocate them. Instead a reset of the CRQ will suffice. Signed-off-by: Nathan Fontenot Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 760352f7f98d..b9b0c693ce01 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -1260,7 +1260,6 @@ static int do_reset(struct ibmvnic_adapter *adapter, release_resources(adapter); release_sub_crqs(adapter); - release_crq_queue(adapter); rc = ibmvnic_init(adapter); if (rc) @@ -3517,7 +3516,14 @@ static int ibmvnic_init(struct ibmvnic_adapter *adapter) unsigned long timeout = msecs_to_jiffies(30000); int rc; - rc = init_crq_queue(adapter); + if (adapter->resetting) { + rc = ibmvnic_reset_crq(adapter); + if (!rc) + rc = vio_enable_interrupts(adapter->vdev); + } else { + rc = init_crq_queue(adapter); + } + if (rc) { dev_err(dev, "Couldn't initialize crq. rc=%d\n", rc); return rc; From 8c0543adca2bb17808e46a24eb6e6247181a10b1 Mon Sep 17 00:00:00 2001 From: Nathan Fontenot Date: Fri, 26 May 2017 10:31:06 -0400 Subject: [PATCH 10/11] ibmvnic: Reset tx/rx pools on driver reset When resetting the ibmvnic driver there is not a need to release and re-allocate the resources for the tx and rx pools. These resources can just be reset to avoid the re-allocations. Signed-off-by: Nathan Fontenot Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 71 ++++++++++++++++++++++++++++-- 1 file changed, 67 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index b9b0c693ce01..5661a043f5e5 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -163,6 +163,16 @@ static long h_reg_sub_crq(unsigned long unit_address, unsigned long token, return rc; } +static void reset_long_term_buff(struct ibmvnic_adapter *adapter, + struct ibmvnic_long_term_buff *ltb) +{ + memset(ltb->buff, 0, ltb->size); + + init_completion(&adapter->fw_done); + send_request_map(adapter, ltb->addr, ltb->size, ltb->map_id); + wait_for_completion(&adapter->fw_done); +} + static int alloc_long_term_buff(struct ibmvnic_adapter *adapter, struct ibmvnic_long_term_buff *ltb, int size) { @@ -352,6 +362,32 @@ static int init_stats_token(struct ibmvnic_adapter *adapter) return 0; } +static int reset_rx_pools(struct ibmvnic_adapter *adapter) +{ + struct ibmvnic_rx_pool *rx_pool; + int rx_scrqs; + int i, j; + + rx_scrqs = be32_to_cpu(adapter->login_rsp_buf->num_rxadd_subcrqs); + for (i = 0; i < rx_scrqs; i++) { + rx_pool = &adapter->rx_pool[i]; + + reset_long_term_buff(adapter, &rx_pool->long_term_buff); + + for (j = 0; j < rx_pool->size; j++) + rx_pool->free_map[j] = j; + + memset(rx_pool->rx_buff, 0, + rx_pool->size * sizeof(struct ibmvnic_rx_buff)); + + atomic_set(&rx_pool->available, 0); + rx_pool->next_alloc = 0; + rx_pool->next_free = 0; + } + + return 0; +} + static void release_rx_pools(struct ibmvnic_adapter *adapter) { struct ibmvnic_rx_pool *rx_pool; @@ -453,6 +489,32 @@ static int init_rx_pools(struct net_device *netdev) return 0; } +static int reset_tx_pools(struct ibmvnic_adapter *adapter) +{ + struct ibmvnic_tx_pool *tx_pool; + int tx_scrqs; + int i, j; + + tx_scrqs = be32_to_cpu(adapter->login_rsp_buf->num_txsubm_subcrqs); + for (i = 0; i < tx_scrqs; i++) { + tx_pool = &adapter->tx_pool[i]; + + reset_long_term_buff(adapter, &tx_pool->long_term_buff); + + memset(tx_pool->tx_buff, 0, + adapter->req_tx_entries_per_subcrq * + sizeof(struct ibmvnic_tx_buff)); + + for (j = 0; j < adapter->req_tx_entries_per_subcrq; j++) + tx_pool->free_map[j] = j; + + tx_pool->consumer_index = 0; + tx_pool->producer_index = 0; + } + + return 0; +} + static void release_tx_pools(struct ibmvnic_adapter *adapter) { struct ibmvnic_tx_pool *tx_pool; @@ -1258,7 +1320,6 @@ static int do_reset(struct ibmvnic_adapter *adapter, */ adapter->state = VNIC_PROBED; - release_resources(adapter); release_sub_crqs(adapter); rc = ibmvnic_init(adapter); @@ -1277,9 +1338,11 @@ static int do_reset(struct ibmvnic_adapter *adapter, return 0; } - rtnl_lock(); - rc = init_resources(adapter); - rtnl_unlock(); + rc = reset_tx_pools(adapter); + if (rc) + return rc; + + rc = reset_rx_pools(adapter); if (rc) return rc; From 57a49436f4e8a76a9125c44d084d12b2c6e6206c Mon Sep 17 00:00:00 2001 From: Nathan Fontenot Date: Fri, 26 May 2017 10:31:12 -0400 Subject: [PATCH 11/11] ibmvnic: Reset sub-crqs during driver reset When the ibmvnic driver is resetting, we can just reset the sub crqs instead of releasing all of their resources and re-allocting them. Signed-off-by: Nathan Fontenot Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 46 ++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 5661a043f5e5..8dcf58088178 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -1320,8 +1320,6 @@ static int do_reset(struct ibmvnic_adapter *adapter, */ adapter->state = VNIC_PROBED; - release_sub_crqs(adapter); - rc = ibmvnic_init(adapter); if (rc) return 0; @@ -1728,6 +1726,45 @@ static const struct ethtool_ops ibmvnic_ethtool_ops = { /* Routines for managing CRQs/sCRQs */ +static int reset_one_sub_crq_queue(struct ibmvnic_adapter *adapter, + struct ibmvnic_sub_crq_queue *scrq) +{ + int rc; + + if (scrq->irq) { + free_irq(scrq->irq, scrq); + irq_dispose_mapping(scrq->irq); + scrq->irq = 0; + } + + memset(scrq->msgs, 0, 2 * PAGE_SIZE); + scrq->cur = 0; + + rc = h_reg_sub_crq(adapter->vdev->unit_address, scrq->msg_token, + 4 * PAGE_SIZE, &scrq->crq_num, &scrq->hw_irq); + return rc; +} + +static int reset_sub_crq_queues(struct ibmvnic_adapter *adapter) +{ + int i, rc; + + for (i = 0; i < adapter->req_tx_queues; i++) { + rc = reset_one_sub_crq_queue(adapter, adapter->tx_scrq[i]); + if (rc) + return rc; + } + + for (i = 0; i < adapter->req_rx_queues; i++) { + rc = reset_one_sub_crq_queue(adapter, adapter->rx_scrq[i]); + if (rc) + return rc; + } + + rc = init_sub_crq_irqs(adapter); + return rc; +} + static void release_sub_crq_queue(struct ibmvnic_adapter *adapter, struct ibmvnic_sub_crq_queue *scrq) { @@ -3607,7 +3644,10 @@ static int ibmvnic_init(struct ibmvnic_adapter *adapter) return -1; } - rc = init_sub_crqs(adapter); + if (adapter->resetting) + rc = reset_sub_crq_queues(adapter); + else + rc = init_sub_crqs(adapter); if (rc) { dev_err(dev, "Initialization of sub crqs failed\n"); release_crq_queue(adapter);