Merge branch 'ibmvnic-Updated-reset-handler-andcode-fixes'

Nathan Fontenot says:

====================
ibmvnic: Updated reset handler and code fixes

This set of patches multiple code fixes and a new rest handler
for the ibmvnic driver. In order to implement the new reset handler
for the ibmvnic driver resource initialization needed to be moved to
its own routine, a state variable is introduced to replace the
various is_* flags in the driver, and a new routine to handle the
assorted reasons the driver can be reset.

v4 updates:

Patch 3/11: Corrected trailing whitespace
Patch 7/11: Corrected trailing whitespace

v3 updates:

Patch 10/11: Correct patch subject line to be a description of the patch.

v2 updates:

Patch 11/11: Use __netif_subqueue_stopped() instead of
netif_subqueue_stopped() to avoid possible use of an un-initialized
skb variable.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2017-05-03 11:33:06 -04:00
commit f411af6822
2 changed files with 394 additions and 210 deletions

View File

@ -194,7 +194,8 @@ static void free_long_term_buff(struct ibmvnic_adapter *adapter,
if (!ltb->buff) if (!ltb->buff)
return; return;
if (!adapter->failover) if (adapter->reset_reason != VNIC_RESET_FAILOVER &&
adapter->reset_reason != VNIC_RESET_MOBILITY)
send_request_unmap(adapter, ltb->map_id); send_request_unmap(adapter, ltb->map_id);
dma_free_coherent(dev, ltb->size, ltb->buff, ltb->addr); dma_free_coherent(dev, ltb->size, ltb->buff, ltb->addr);
} }
@ -292,9 +293,6 @@ static void replenish_pools(struct ibmvnic_adapter *adapter)
{ {
int i; int i;
if (adapter->migrated)
return;
adapter->replenish_task_cycles++; adapter->replenish_task_cycles++;
for (i = 0; i < be32_to_cpu(adapter->login_rsp_buf->num_rxadd_subcrqs); for (i = 0; i < be32_to_cpu(adapter->login_rsp_buf->num_rxadd_subcrqs);
i++) { i++) {
@ -350,7 +348,7 @@ static void release_rx_pools(struct ibmvnic_adapter *adapter)
free_long_term_buff(adapter, &rx_pool->long_term_buff); free_long_term_buff(adapter, &rx_pool->long_term_buff);
if (!rx_pool->rx_buff) if (!rx_pool->rx_buff)
continue; continue;
for (j = 0; j < rx_pool->size; j++) { for (j = 0; j < rx_pool->size; j++) {
if (rx_pool->rx_buff[j].skb) { if (rx_pool->rx_buff[j].skb) {
@ -554,11 +552,20 @@ static int ibmvnic_login(struct net_device *netdev)
static void release_resources(struct ibmvnic_adapter *adapter) static void release_resources(struct ibmvnic_adapter *adapter)
{ {
int i;
release_tx_pools(adapter); release_tx_pools(adapter);
release_rx_pools(adapter); release_rx_pools(adapter);
release_stats_token(adapter); release_stats_token(adapter);
release_error_buffers(adapter); release_error_buffers(adapter);
if (adapter->napi) {
for (i = 0; i < adapter->req_rx_queues; i++) {
if (&adapter->napi[i])
netif_napi_del(&adapter->napi[i]);
}
}
} }
static int set_link_state(struct ibmvnic_adapter *adapter, u8 link_state) static int set_link_state(struct ibmvnic_adapter *adapter, u8 link_state)
@ -569,11 +576,6 @@ static int set_link_state(struct ibmvnic_adapter *adapter, u8 link_state)
bool resend; bool resend;
int rc; int rc;
if (adapter->logical_link_state == link_state) {
netdev_dbg(netdev, "Link state already %d\n", link_state);
return 0;
}
netdev_err(netdev, "setting link state %d\n", link_state); netdev_err(netdev, "setting link state %d\n", link_state);
memset(&crq, 0, sizeof(crq)); memset(&crq, 0, sizeof(crq));
crq.logical_link_state.first = IBMVNIC_CRQ_CMD; crq.logical_link_state.first = IBMVNIC_CRQ_CMD;
@ -624,22 +626,10 @@ static int set_real_num_queues(struct net_device *netdev)
return rc; return rc;
} }
static int ibmvnic_open(struct net_device *netdev) static int init_resources(struct ibmvnic_adapter *adapter)
{ {
struct ibmvnic_adapter *adapter = netdev_priv(netdev); struct net_device *netdev = adapter->netdev;
struct device *dev = &adapter->vdev->dev; int i, rc;
int rc = 0;
int i;
if (adapter->is_closed) {
rc = ibmvnic_init(adapter);
if (rc)
return rc;
}
rc = ibmvnic_login(netdev);
if (rc)
return rc;
rc = set_real_num_queues(netdev); rc = set_real_num_queues(netdev);
if (rc) if (rc)
@ -647,7 +637,7 @@ static int ibmvnic_open(struct net_device *netdev)
rc = init_sub_crq_irqs(adapter); rc = init_sub_crq_irqs(adapter);
if (rc) { if (rc) {
dev_err(dev, "failed to initialize sub crq irqs\n"); netdev_err(netdev, "failed to initialize sub crq irqs\n");
return -1; return -1;
} }
@ -659,90 +649,184 @@ static int ibmvnic_open(struct net_device *netdev)
adapter->napi = kcalloc(adapter->req_rx_queues, adapter->napi = kcalloc(adapter->req_rx_queues,
sizeof(struct napi_struct), GFP_KERNEL); sizeof(struct napi_struct), GFP_KERNEL);
if (!adapter->napi) if (!adapter->napi)
goto ibmvnic_open_fail; return -ENOMEM;
for (i = 0; i < adapter->req_rx_queues; i++) { for (i = 0; i < adapter->req_rx_queues; i++) {
netif_napi_add(netdev, &adapter->napi[i], ibmvnic_poll, netif_napi_add(netdev, &adapter->napi[i], ibmvnic_poll,
NAPI_POLL_WEIGHT); NAPI_POLL_WEIGHT);
napi_enable(&adapter->napi[i]);
} }
send_map_query(adapter); send_map_query(adapter);
rc = init_rx_pools(netdev); rc = init_rx_pools(netdev);
if (rc) if (rc)
goto ibmvnic_open_fail; return rc;
rc = init_tx_pools(netdev); rc = init_tx_pools(netdev);
if (rc) return rc;
goto ibmvnic_open_fail; }
static int __ibmvnic_open(struct net_device *netdev)
{
struct ibmvnic_adapter *adapter = netdev_priv(netdev);
enum vnic_state prev_state = adapter->state;
int i, rc;
adapter->state = VNIC_OPENING;
replenish_pools(adapter); replenish_pools(adapter);
for (i = 0; i < adapter->req_rx_queues; i++)
napi_enable(&adapter->napi[i]);
/* We're ready to receive frames, enable the sub-crq interrupts and /* We're ready to receive frames, enable the sub-crq interrupts and
* set the logical link state to up * set the logical link state to up
*/ */
for (i = 0; i < adapter->req_rx_queues; i++) for (i = 0; i < adapter->req_rx_queues; i++) {
enable_scrq_irq(adapter, adapter->rx_scrq[i]); if (prev_state == VNIC_CLOSED)
enable_irq(adapter->rx_scrq[i]->irq);
else
enable_scrq_irq(adapter, adapter->rx_scrq[i]);
}
for (i = 0; i < adapter->req_tx_queues; i++) for (i = 0; i < adapter->req_tx_queues; i++) {
enable_scrq_irq(adapter, adapter->tx_scrq[i]); if (prev_state == VNIC_CLOSED)
enable_irq(adapter->tx_scrq[i]->irq);
else
enable_scrq_irq(adapter, adapter->tx_scrq[i]);
}
rc = set_link_state(adapter, IBMVNIC_LOGICAL_LNK_UP); rc = set_link_state(adapter, IBMVNIC_LOGICAL_LNK_UP);
if (rc) if (rc) {
goto ibmvnic_open_fail; for (i = 0; i < adapter->req_rx_queues; i++)
napi_disable(&adapter->napi[i]);
release_resources(adapter);
return rc;
}
netif_tx_start_all_queues(netdev); netif_tx_start_all_queues(netdev);
adapter->is_closed = false;
return 0; if (prev_state == VNIC_CLOSED) {
ibmvnic_open_fail:
for (i = 0; i < adapter->req_rx_queues; i++)
napi_disable(&adapter->napi[i]);
release_resources(adapter);
return -ENOMEM;
}
static void disable_sub_crqs(struct ibmvnic_adapter *adapter)
{
int i;
if (adapter->tx_scrq) {
for (i = 0; i < adapter->req_tx_queues; i++)
if (adapter->tx_scrq[i])
disable_irq(adapter->tx_scrq[i]->irq);
}
if (adapter->rx_scrq) {
for (i = 0; i < adapter->req_rx_queues; i++) for (i = 0; i < adapter->req_rx_queues; i++)
if (adapter->rx_scrq[i]) napi_schedule(&adapter->napi[i]);
disable_irq(adapter->rx_scrq[i]->irq); }
adapter->state = VNIC_OPEN;
return rc;
}
static int ibmvnic_open(struct net_device *netdev)
{
struct ibmvnic_adapter *adapter = netdev_priv(netdev);
int rc;
mutex_lock(&adapter->reset_lock);
if (adapter->state != VNIC_CLOSED) {
rc = ibmvnic_login(netdev);
if (rc) {
mutex_unlock(&adapter->reset_lock);
return rc;
}
rc = init_resources(adapter);
if (rc) {
netdev_err(netdev, "failed to initialize resources\n");
release_resources(adapter);
mutex_unlock(&adapter->reset_lock);
return rc;
}
}
rc = __ibmvnic_open(netdev);
mutex_unlock(&adapter->reset_lock);
return rc;
}
static void clean_tx_pools(struct ibmvnic_adapter *adapter)
{
struct ibmvnic_tx_pool *tx_pool;
u64 tx_entries;
int tx_scrqs;
int i, j;
if (!adapter->tx_pool)
return;
tx_scrqs = be32_to_cpu(adapter->login_rsp_buf->num_txsubm_subcrqs);
tx_entries = adapter->req_tx_entries_per_subcrq;
/* Free any remaining skbs in the tx buffer pools */
for (i = 0; i < tx_scrqs; i++) {
tx_pool = &adapter->tx_pool[i];
if (!tx_pool)
continue;
for (j = 0; j < tx_entries; j++) {
if (tx_pool->tx_buff[j].skb) {
dev_kfree_skb_any(tx_pool->tx_buff[j].skb);
tx_pool->tx_buff[j].skb = NULL;
}
}
} }
} }
static int ibmvnic_close(struct net_device *netdev) static int __ibmvnic_close(struct net_device *netdev)
{ {
struct ibmvnic_adapter *adapter = netdev_priv(netdev); struct ibmvnic_adapter *adapter = netdev_priv(netdev);
int rc = 0; int rc = 0;
int i; int i;
adapter->closing = true; adapter->state = VNIC_CLOSING;
disable_sub_crqs(adapter); netif_tx_stop_all_queues(netdev);
if (adapter->napi) { if (adapter->napi) {
for (i = 0; i < adapter->req_rx_queues; i++) for (i = 0; i < adapter->req_rx_queues; i++)
napi_disable(&adapter->napi[i]); napi_disable(&adapter->napi[i]);
} }
if (!adapter->failover) clean_tx_pools(adapter);
netif_tx_stop_all_queues(netdev);
if (adapter->tx_scrq) {
for (i = 0; i < adapter->req_tx_queues; i++)
if (adapter->tx_scrq[i]->irq)
disable_irq(adapter->tx_scrq[i]->irq);
}
rc = set_link_state(adapter, IBMVNIC_LOGICAL_LNK_DN); rc = set_link_state(adapter, IBMVNIC_LOGICAL_LNK_DN);
if (rc)
return rc;
release_resources(adapter); if (adapter->rx_scrq) {
for (i = 0; i < adapter->req_rx_queues; i++) {
int retries = 10;
while (pending_scrq(adapter, adapter->rx_scrq[i])) {
retries--;
mdelay(100);
if (retries == 0)
break;
}
if (adapter->rx_scrq[i]->irq)
disable_irq(adapter->rx_scrq[i]->irq);
}
}
adapter->state = VNIC_CLOSED;
return rc;
}
static int ibmvnic_close(struct net_device *netdev)
{
struct ibmvnic_adapter *adapter = netdev_priv(netdev);
int rc;
mutex_lock(&adapter->reset_lock);
rc = __ibmvnic_close(netdev);
mutex_unlock(&adapter->reset_lock);
adapter->is_closed = true;
adapter->closing = false;
return rc; return rc;
} }
@ -901,13 +985,7 @@ static int ibmvnic_xmit(struct sk_buff *skb, struct net_device *netdev)
int index = 0; int index = 0;
int ret = 0; int ret = 0;
tx_pool = &adapter->tx_pool[queue_num]; if (adapter->resetting) {
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->
off_txsubm_subcrqs));
if (adapter->migrated) {
if (!netif_subqueue_stopped(netdev, skb)) if (!netif_subqueue_stopped(netdev, skb))
netif_stop_subqueue(netdev, queue_num); netif_stop_subqueue(netdev, queue_num);
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
@ -918,6 +996,12 @@ static int ibmvnic_xmit(struct sk_buff *skb, struct net_device *netdev)
goto out; goto out;
} }
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->off_txsubm_subcrqs));
index = tx_pool->free_map[tx_pool->consumer_index]; index = tx_pool->free_map[tx_pool->consumer_index];
offset = index * adapter->req_mtu; offset = index * adapter->req_mtu;
dst = tx_pool->long_term_buff.buff + offset; dst = tx_pool->long_term_buff.buff + offset;
@ -1099,18 +1183,185 @@ static int ibmvnic_set_mac(struct net_device *netdev, void *p)
return 0; return 0;
} }
/**
* do_reset returns zero if we are able to keep processing reset events, or
* non-zero if we hit a fatal error and must halt.
*/
static int do_reset(struct ibmvnic_adapter *adapter,
struct ibmvnic_rwi *rwi, u32 reset_state)
{
struct net_device *netdev = adapter->netdev;
int i, rc;
netif_carrier_off(netdev);
adapter->reset_reason = rwi->reset_reason;
if (rwi->reset_reason == VNIC_RESET_MOBILITY) {
rc = ibmvnic_reenable_crq_queue(adapter);
if (rc)
return 0;
}
rc = __ibmvnic_close(netdev);
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) {
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;
rc = __ibmvnic_open(netdev);
if (rc) {
if (list_empty(&adapter->rwi_list))
adapter->state = VNIC_CLOSED;
else
adapter->state = reset_state;
return 0;
}
netif_carrier_on(netdev);
/* kick napi */
for (i = 0; i < adapter->req_rx_queues; i++)
napi_schedule(&adapter->napi[i]);
return 0;
}
static struct ibmvnic_rwi *get_next_rwi(struct ibmvnic_adapter *adapter)
{
struct ibmvnic_rwi *rwi;
mutex_lock(&adapter->rwi_lock);
if (!list_empty(&adapter->rwi_list)) {
rwi = list_first_entry(&adapter->rwi_list, struct ibmvnic_rwi,
list);
list_del(&rwi->list);
} else {
rwi = NULL;
}
mutex_unlock(&adapter->rwi_lock);
return rwi;
}
static void free_all_rwi(struct ibmvnic_adapter *adapter)
{
struct ibmvnic_rwi *rwi;
rwi = get_next_rwi(adapter);
while (rwi) {
kfree(rwi);
rwi = get_next_rwi(adapter);
}
}
static void __ibmvnic_reset(struct work_struct *work)
{
struct ibmvnic_rwi *rwi;
struct ibmvnic_adapter *adapter;
struct net_device *netdev;
u32 reset_state;
int rc;
adapter = container_of(work, struct ibmvnic_adapter, ibmvnic_reset);
netdev = adapter->netdev;
mutex_lock(&adapter->reset_lock);
adapter->resetting = true;
reset_state = adapter->state;
rwi = get_next_rwi(adapter);
while (rwi) {
rc = do_reset(adapter, rwi, reset_state);
kfree(rwi);
if (rc)
break;
rwi = get_next_rwi(adapter);
}
if (rc) {
free_all_rwi(adapter);
return;
}
adapter->resetting = false;
mutex_unlock(&adapter->reset_lock);
}
static void ibmvnic_reset(struct ibmvnic_adapter *adapter,
enum ibmvnic_reset_reason reason)
{
struct ibmvnic_rwi *rwi, *tmp;
struct net_device *netdev = adapter->netdev;
struct list_head *entry;
if (adapter->state == VNIC_REMOVING ||
adapter->state == VNIC_REMOVED) {
netdev_dbg(netdev, "Adapter removing, skipping reset\n");
return;
}
mutex_lock(&adapter->rwi_lock);
list_for_each(entry, &adapter->rwi_list) {
tmp = list_entry(entry, struct ibmvnic_rwi, list);
if (tmp->reset_reason == reason) {
netdev_err(netdev, "Matching reset found, skipping\n");
mutex_unlock(&adapter->rwi_lock);
return;
}
}
rwi = kzalloc(sizeof(*rwi), GFP_KERNEL);
if (!rwi) {
mutex_unlock(&adapter->rwi_lock);
ibmvnic_close(netdev);
return;
}
rwi->reset_reason = reason;
list_add_tail(&rwi->list, &adapter->rwi_list);
mutex_unlock(&adapter->rwi_lock);
schedule_work(&adapter->ibmvnic_reset);
}
static void ibmvnic_tx_timeout(struct net_device *dev) static void ibmvnic_tx_timeout(struct net_device *dev)
{ {
struct ibmvnic_adapter *adapter = netdev_priv(dev); struct ibmvnic_adapter *adapter = netdev_priv(dev);
int rc;
/* Adapter timed out, resetting it */ ibmvnic_reset(adapter, VNIC_RESET_TIMEOUT);
release_sub_crqs(adapter);
rc = ibmvnic_reset_crq(adapter);
if (rc)
dev_err(&adapter->vdev->dev, "Adapter timeout, reset failed\n");
else
ibmvnic_send_crq_init(adapter);
} }
static void remove_buff_from_pool(struct ibmvnic_adapter *adapter, static void remove_buff_from_pool(struct ibmvnic_adapter *adapter,
@ -1153,7 +1404,7 @@ static int ibmvnic_poll(struct napi_struct *napi, int budget)
/* free the entry */ /* free the entry */
next->rx_comp.first = 0; next->rx_comp.first = 0;
remove_buff_from_pool(adapter, rx_buff); remove_buff_from_pool(adapter, rx_buff);
break; continue;
} }
length = be32_to_cpu(next->rx_comp.len); length = be32_to_cpu(next->rx_comp.len);
@ -1177,6 +1428,7 @@ static int ibmvnic_poll(struct napi_struct *napi, int budget)
skb_put(skb, length); skb_put(skb, length);
skb->protocol = eth_type_trans(skb, netdev); skb->protocol = eth_type_trans(skb, netdev);
skb_record_rx_queue(skb, scrq_num);
if (flags & IBMVNIC_IP_CHKSUM_GOOD && if (flags & IBMVNIC_IP_CHKSUM_GOOD &&
flags & IBMVNIC_TCP_UDP_CHKSUM_GOOD) { flags & IBMVNIC_TCP_UDP_CHKSUM_GOOD) {
@ -1557,19 +1809,8 @@ static int ibmvnic_complete_tx(struct ibmvnic_adapter *adapter,
} }
if (txbuff->last_frag) { if (txbuff->last_frag) {
if (atomic_sub_return(next->tx_comp.num_comps,
&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); dev_kfree_skb_any(txbuff->skb);
txbuff->skb = NULL;
} }
adapter->tx_pool[pool].free_map[adapter->tx_pool[pool]. adapter->tx_pool[pool].free_map[adapter->tx_pool[pool].
@ -1580,6 +1821,15 @@ static int ibmvnic_complete_tx(struct ibmvnic_adapter *adapter,
} }
/* remove tx_comp scrq*/ /* remove tx_comp scrq*/
next->tx_comp.first = 0; next->tx_comp.first = 0;
if (atomic_sub_return(next->tx_comp.num_comps, &scrq->used) <=
(adapter->req_tx_entries_per_subcrq / 2) &&
__netif_subqueue_stopped(adapter->netdev,
scrq->pool_index)) {
netif_wake_subqueue(adapter->netdev, scrq->pool_index);
netdev_info(adapter->netdev, "Started queue %d\n",
scrq->pool_index);
}
} }
enable_scrq_irq(adapter, scrq); enable_scrq_irq(adapter, scrq);
@ -1853,7 +2103,8 @@ static int pending_scrq(struct ibmvnic_adapter *adapter,
{ {
union sub_crq *entry = &scrq->msgs[scrq->cur]; union sub_crq *entry = &scrq->msgs[scrq->cur];
if (entry->generic.first & IBMVNIC_CRQ_CMD_RSP || adapter->closing) if (entry->generic.first & IBMVNIC_CRQ_CMD_RSP ||
adapter->state == VNIC_CLOSING)
return 1; return 1;
else else
return 0; return 0;
@ -1991,18 +2242,6 @@ static int ibmvnic_send_crq_init(struct ibmvnic_adapter *adapter)
return ibmvnic_send_crq(adapter, &crq); return ibmvnic_send_crq(adapter, &crq);
} }
static int ibmvnic_send_crq_init_complete(struct ibmvnic_adapter *adapter)
{
union ibmvnic_crq crq;
memset(&crq, 0, sizeof(crq));
crq.generic.first = IBMVNIC_CRQ_INIT_CMD;
crq.generic.cmd = IBMVNIC_CRQ_INIT_COMPLETE;
netdev_dbg(adapter->netdev, "Sending CRQ init complete\n");
return ibmvnic_send_crq(adapter, &crq);
}
static int send_version_xchg(struct ibmvnic_adapter *adapter) static int send_version_xchg(struct ibmvnic_adapter *adapter)
{ {
union ibmvnic_crq crq; union ibmvnic_crq crq;
@ -2500,6 +2739,9 @@ static void handle_error_indication(union ibmvnic_crq *crq,
if (be32_to_cpu(crq->error_indication.error_id)) if (be32_to_cpu(crq->error_indication.error_id))
request_error_information(adapter, crq); request_error_information(adapter, crq);
if (crq->error_indication.flags & IBMVNIC_FATAL_ERROR)
ibmvnic_reset(adapter, VNIC_RESET_FATAL);
} }
static void handle_change_mac_rsp(union ibmvnic_crq *crq, static void handle_change_mac_rsp(union ibmvnic_crq *crq,
@ -2888,26 +3130,6 @@ static void handle_query_cap_rsp(union ibmvnic_crq *crq,
} }
} }
static void ibmvnic_xport_event(struct work_struct *work)
{
struct ibmvnic_adapter *adapter = container_of(work,
struct ibmvnic_adapter,
ibmvnic_xport);
struct device *dev = &adapter->vdev->dev;
long rc;
release_sub_crqs(adapter);
if (adapter->migrated) {
rc = ibmvnic_reenable_crq_queue(adapter);
if (rc)
dev_err(dev, "Error after enable rc=%ld\n", rc);
adapter->migrated = false;
rc = ibmvnic_send_crq_init(adapter);
if (rc)
dev_err(dev, "Error sending init rc=%ld\n", rc);
}
}
static void ibmvnic_handle_crq(union ibmvnic_crq *crq, static void ibmvnic_handle_crq(union ibmvnic_crq *crq,
struct ibmvnic_adapter *adapter) struct ibmvnic_adapter *adapter)
{ {
@ -2925,12 +3147,6 @@ static void ibmvnic_handle_crq(union ibmvnic_crq *crq,
switch (gen_crq->cmd) { switch (gen_crq->cmd) {
case IBMVNIC_CRQ_INIT: case IBMVNIC_CRQ_INIT:
dev_info(dev, "Partner initialized\n"); dev_info(dev, "Partner initialized\n");
/* Send back a response */
rc = ibmvnic_send_crq_init_complete(adapter);
if (!rc)
schedule_work(&adapter->vnic_crq_init);
else
dev_err(dev, "Can't send initrsp rc=%ld\n", rc);
break; break;
case IBMVNIC_CRQ_INIT_COMPLETE: case IBMVNIC_CRQ_INIT_COMPLETE:
dev_info(dev, "Partner initialization complete\n"); dev_info(dev, "Partner initialization complete\n");
@ -2941,19 +3157,18 @@ static void ibmvnic_handle_crq(union ibmvnic_crq *crq,
} }
return; return;
case IBMVNIC_CRQ_XPORT_EVENT: case IBMVNIC_CRQ_XPORT_EVENT:
netif_carrier_off(netdev);
if (gen_crq->cmd == IBMVNIC_PARTITION_MIGRATED) { if (gen_crq->cmd == IBMVNIC_PARTITION_MIGRATED) {
dev_info(dev, "Re-enabling adapter\n"); dev_info(dev, "Migrated, re-enabling adapter\n");
adapter->migrated = true; ibmvnic_reset(adapter, VNIC_RESET_MOBILITY);
schedule_work(&adapter->ibmvnic_xport);
} else if (gen_crq->cmd == IBMVNIC_DEVICE_FAILOVER) { } else if (gen_crq->cmd == IBMVNIC_DEVICE_FAILOVER) {
dev_info(dev, "Backing device failover detected\n"); dev_info(dev, "Backing device failover detected\n");
netif_carrier_off(netdev); ibmvnic_reset(adapter, VNIC_RESET_FAILOVER);
adapter->failover = true;
} else { } else {
/* The adapter lost the connection */ /* The adapter lost the connection */
dev_err(dev, "Virtual Adapter failed (rc=%d)\n", dev_err(dev, "Virtual Adapter failed (rc=%d)\n",
gen_crq->cmd); gen_crq->cmd);
schedule_work(&adapter->ibmvnic_xport); ibmvnic_reset(adapter, VNIC_RESET_FATAL);
} }
return; return;
case IBMVNIC_CRQ_CMD_RSP: case IBMVNIC_CRQ_CMD_RSP:
@ -3234,64 +3449,6 @@ static int init_crq_queue(struct ibmvnic_adapter *adapter)
return retrc; return retrc;
} }
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);
bool restart = false;
int rc;
if (adapter->failover) {
release_sub_crqs(adapter);
if (netif_running(netdev)) {
netif_tx_disable(netdev);
ibmvnic_close(netdev);
restart = true;
}
}
reinit_completion(&adapter->init_done);
send_version_xchg(adapter);
if (!wait_for_completion_timeout(&adapter->init_done, timeout)) {
dev_err(dev, "Passive init timeout\n");
goto task_failed;
}
netdev->mtu = adapter->req_mtu - ETH_HLEN;
if (adapter->failover) {
adapter->failover = false;
if (restart) {
rc = ibmvnic_open(netdev);
if (rc)
goto restart_failed;
}
netif_carrier_on(netdev);
return;
}
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;
restart_failed:
dev_err(dev, "Failed to restart ibmvnic, rc=%d\n", rc);
register_failed:
release_sub_crqs(adapter);
task_failed:
dev_err(dev, "Passive initialization was not successful\n");
}
static int ibmvnic_init(struct ibmvnic_adapter *adapter) static int ibmvnic_init(struct ibmvnic_adapter *adapter)
{ {
struct device *dev = &adapter->vdev->dev; struct device *dev = &adapter->vdev->dev;
@ -3346,10 +3503,10 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
return -ENOMEM; return -ENOMEM;
adapter = netdev_priv(netdev); adapter = netdev_priv(netdev);
adapter->state = VNIC_PROBING;
dev_set_drvdata(&dev->dev, netdev); dev_set_drvdata(&dev->dev, netdev);
adapter->vdev = dev; adapter->vdev = dev;
adapter->netdev = netdev; adapter->netdev = netdev;
adapter->failover = false;
ether_addr_copy(adapter->mac_addr, mac_addr_p); ether_addr_copy(adapter->mac_addr, mac_addr_p);
ether_addr_copy(netdev->dev_addr, adapter->mac_addr); ether_addr_copy(netdev->dev_addr, adapter->mac_addr);
@ -3358,14 +3515,17 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
netdev->ethtool_ops = &ibmvnic_ethtool_ops; netdev->ethtool_ops = &ibmvnic_ethtool_ops;
SET_NETDEV_DEV(netdev, &dev->dev); SET_NETDEV_DEV(netdev, &dev->dev);
INIT_WORK(&adapter->vnic_crq_init, handle_crq_init_rsp);
INIT_WORK(&adapter->ibmvnic_xport, ibmvnic_xport_event);
spin_lock_init(&adapter->stats_lock); spin_lock_init(&adapter->stats_lock);
INIT_LIST_HEAD(&adapter->errors); INIT_LIST_HEAD(&adapter->errors);
spin_lock_init(&adapter->error_list_lock); spin_lock_init(&adapter->error_list_lock);
INIT_WORK(&adapter->ibmvnic_reset, __ibmvnic_reset);
INIT_LIST_HEAD(&adapter->rwi_list);
mutex_init(&adapter->reset_lock);
mutex_init(&adapter->rwi_lock);
adapter->resetting = false;
rc = ibmvnic_init(adapter); rc = ibmvnic_init(adapter);
if (rc) { if (rc) {
free_netdev(netdev); free_netdev(netdev);
@ -3373,7 +3533,6 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
} }
netdev->mtu = adapter->req_mtu - ETH_HLEN; netdev->mtu = adapter->req_mtu - ETH_HLEN;
adapter->is_closed = false;
rc = register_netdev(netdev); rc = register_netdev(netdev);
if (rc) { if (rc) {
@ -3383,6 +3542,7 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
} }
dev_info(&dev->dev, "ibmvnic registered\n"); dev_info(&dev->dev, "ibmvnic registered\n");
adapter->state = VNIC_PROBED;
return 0; return 0;
} }
@ -3391,12 +3551,17 @@ static int ibmvnic_remove(struct vio_dev *dev)
struct net_device *netdev = dev_get_drvdata(&dev->dev); struct net_device *netdev = dev_get_drvdata(&dev->dev);
struct ibmvnic_adapter *adapter = netdev_priv(netdev); struct ibmvnic_adapter *adapter = netdev_priv(netdev);
adapter->state = VNIC_REMOVING;
unregister_netdev(netdev); unregister_netdev(netdev);
mutex_lock(&adapter->reset_lock);
release_resources(adapter); release_resources(adapter);
release_sub_crqs(adapter); release_sub_crqs(adapter);
release_crq_queue(adapter); release_crq_queue(adapter);
adapter->state = VNIC_REMOVED;
mutex_unlock(&adapter->reset_lock);
free_netdev(netdev); free_netdev(netdev);
dev_set_drvdata(&dev->dev, NULL); dev_set_drvdata(&dev->dev, NULL);

View File

@ -913,6 +913,25 @@ struct ibmvnic_error_buff {
__be32 error_id; __be32 error_id;
}; };
enum vnic_state {VNIC_PROBING = 1,
VNIC_PROBED,
VNIC_OPENING,
VNIC_OPEN,
VNIC_CLOSING,
VNIC_CLOSED,
VNIC_REMOVING,
VNIC_REMOVED};
enum ibmvnic_reset_reason {VNIC_RESET_FAILOVER = 1,
VNIC_RESET_MOBILITY,
VNIC_RESET_FATAL,
VNIC_RESET_TIMEOUT};
struct ibmvnic_rwi {
enum ibmvnic_reset_reason reset_reason;
struct list_head list;
};
struct ibmvnic_adapter { struct ibmvnic_adapter {
struct vio_dev *vdev; struct vio_dev *vdev;
struct net_device *netdev; struct net_device *netdev;
@ -922,7 +941,6 @@ struct ibmvnic_adapter {
dma_addr_t ip_offload_tok; dma_addr_t ip_offload_tok;
struct ibmvnic_control_ip_offload_buffer ip_offload_ctrl; struct ibmvnic_control_ip_offload_buffer ip_offload_ctrl;
dma_addr_t ip_offload_ctrl_tok; dma_addr_t ip_offload_ctrl_tok;
bool migrated;
u32 msg_enable; u32 msg_enable;
/* Statistics */ /* Statistics */
@ -962,7 +980,6 @@ struct ibmvnic_adapter {
u64 promisc; u64 promisc;
struct ibmvnic_tx_pool *tx_pool; struct ibmvnic_tx_pool *tx_pool;
bool closing;
struct completion init_done; struct completion init_done;
int init_done_rc; int init_done_rc;
@ -1007,9 +1024,11 @@ struct ibmvnic_adapter {
__be64 tx_rx_desc_req; __be64 tx_rx_desc_req;
u8 map_id; u8 map_id;
struct work_struct vnic_crq_init;
struct work_struct ibmvnic_xport;
struct tasklet_struct tasklet; struct tasklet_struct tasklet;
bool failover; enum vnic_state state;
bool is_closed; enum ibmvnic_reset_reason reset_reason;
struct mutex reset_lock, rwi_lock;
struct list_head rwi_list;
struct work_struct ibmvnic_reset;
bool resetting;
}; };