Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f411af68 authored by David S. Miller's avatar David S. Miller
Browse files

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: default avatarDavid S. Miller <davem@davemloft.net>
parents 4d89ac2d 7c3e7de3
Loading
Loading
Loading
Loading
+363 −198
Original line number Diff line number Diff line
@@ -194,7 +194,8 @@ static void free_long_term_buff(struct ibmvnic_adapter *adapter,
	if (!ltb->buff)
		return;

	if (!adapter->failover)
	if (adapter->reset_reason != VNIC_RESET_FAILOVER &&
	    adapter->reset_reason != VNIC_RESET_MOBILITY)
		send_request_unmap(adapter, ltb->map_id);
	dma_free_coherent(dev, ltb->size, ltb->buff, ltb->addr);
}
@@ -292,9 +293,6 @@ static void replenish_pools(struct ibmvnic_adapter *adapter)
{
	int i;

	if (adapter->migrated)
		return;

	adapter->replenish_task_cycles++;
	for (i = 0; i < be32_to_cpu(adapter->login_rsp_buf->num_rxadd_subcrqs);
	     i++) {
@@ -554,11 +552,20 @@ static int ibmvnic_login(struct net_device *netdev)

static void release_resources(struct ibmvnic_adapter *adapter)
{
	int i;

	release_tx_pools(adapter);
	release_rx_pools(adapter);

	release_stats_token(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)
@@ -569,11 +576,6 @@ static int set_link_state(struct ibmvnic_adapter *adapter, u8 link_state)
	bool resend;
	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);
	memset(&crq, 0, sizeof(crq));
	crq.logical_link_state.first = IBMVNIC_CRQ_CMD;
@@ -624,22 +626,10 @@ static int set_real_num_queues(struct net_device *netdev)
	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 device *dev = &adapter->vdev->dev;
	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;
	struct net_device *netdev = adapter->netdev;
	int i, rc;

	rc = set_real_num_queues(netdev);
	if (rc)
@@ -647,7 +637,7 @@ static int ibmvnic_open(struct net_device *netdev)

	rc = init_sub_crq_irqs(adapter);
	if (rc) {
		dev_err(dev, "failed to initialize sub crq irqs\n");
		netdev_err(netdev, "failed to initialize sub crq irqs\n");
		return -1;
	}

@@ -659,90 +649,184 @@ static int ibmvnic_open(struct net_device *netdev)
	adapter->napi = kcalloc(adapter->req_rx_queues,
				sizeof(struct napi_struct), GFP_KERNEL);
	if (!adapter->napi)
		goto ibmvnic_open_fail;
		return -ENOMEM;

	for (i = 0; i < adapter->req_rx_queues; i++) {
		netif_napi_add(netdev, &adapter->napi[i], ibmvnic_poll,
			       NAPI_POLL_WEIGHT);
		napi_enable(&adapter->napi[i]);
	}

	send_map_query(adapter);

	rc = init_rx_pools(netdev);
	if (rc)
		goto ibmvnic_open_fail;
		return rc;

	rc = init_tx_pools(netdev);
	if (rc)
		goto ibmvnic_open_fail;
	return rc;
}

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);

	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
	 * 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++) {
		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++) {
		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);
	if (rc)
		goto ibmvnic_open_fail;
	if (rc) {
		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);
	adapter->is_closed = false;

	return 0;

ibmvnic_open_fail:
	if (prev_state == VNIC_CLOSED) {
		for (i = 0; i < adapter->req_rx_queues; i++)
		napi_disable(&adapter->napi[i]);
	release_resources(adapter);
	return -ENOMEM;
			napi_schedule(&adapter->napi[i]);
	}

static void disable_sub_crqs(struct ibmvnic_adapter *adapter)
	adapter->state = VNIC_OPEN;
	return rc;
}

static int ibmvnic_open(struct net_device *netdev)
{
	int i;
	struct ibmvnic_adapter *adapter = netdev_priv(netdev);
	int rc;

	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);
	mutex_lock(&adapter->reset_lock);

	if (adapter->state != VNIC_CLOSED) {
		rc = ibmvnic_login(netdev);
		if (rc) {
			mutex_unlock(&adapter->reset_lock);
			return rc;
		}

	if (adapter->rx_scrq) {
		for (i = 0; i < adapter->req_rx_queues; i++)
			if (adapter->rx_scrq[i])
				disable_irq(adapter->rx_scrq[i]->irq);
		rc = init_resources(adapter);
		if (rc) {
			netdev_err(netdev, "failed to initialize resources\n");
			release_resources(adapter);
			mutex_unlock(&adapter->reset_lock);
			return rc;
		}
	}

static int ibmvnic_close(struct net_device *netdev)
	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)
{
	struct ibmvnic_adapter *adapter = netdev_priv(netdev);
	int rc = 0;
	int i;

	adapter->closing = true;
	disable_sub_crqs(adapter);
	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]);
	}

	if (!adapter->failover)
		netif_tx_stop_all_queues(netdev);
	clean_tx_pools(adapter);

	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);
	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;
}

@@ -901,13 +985,7 @@ static int ibmvnic_xmit(struct sk_buff *skb, struct net_device *netdev)
	int index = 0;
	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->
					       off_txsubm_subcrqs));
	if (adapter->migrated) {
	if (adapter->resetting) {
		if (!netif_subqueue_stopped(netdev, skb))
			netif_stop_subqueue(netdev, queue_num);
		dev_kfree_skb_any(skb);
@@ -918,6 +996,12 @@ static int ibmvnic_xmit(struct sk_buff *skb, struct net_device *netdev)
		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];
	offset = index * adapter->req_mtu;
	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;
}

static void ibmvnic_tx_timeout(struct net_device *dev)
/**
 * 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 ibmvnic_adapter *adapter = netdev_priv(dev);
	int rc;
	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;

	/* Adapter timed out, resetting it */
	/* 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);
	rc = ibmvnic_reset_crq(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)
		dev_err(&adapter->vdev->dev, "Adapter timeout, reset failed\n");
		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
		ibmvnic_send_crq_init(adapter);
			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)
{
	struct ibmvnic_adapter *adapter = netdev_priv(dev);

	ibmvnic_reset(adapter, VNIC_RESET_TIMEOUT);
}

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 */
			next->rx_comp.first = 0;
			remove_buff_from_pool(adapter, rx_buff);
			break;
			continue;
		}

		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->protocol = eth_type_trans(skb, netdev);
		skb_record_rx_queue(skb, scrq_num);

		if (flags & IBMVNIC_IP_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 (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);
				txbuff->skb = NULL;
			}

			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*/
		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);
@@ -1853,7 +2103,8 @@ static int pending_scrq(struct ibmvnic_adapter *adapter,
{
	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;
	else
		return 0;
@@ -1991,18 +2242,6 @@ static int ibmvnic_send_crq_init(struct ibmvnic_adapter *adapter)
	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)
{
	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))
		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,
@@ -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,
			       struct ibmvnic_adapter *adapter)
{
@@ -2925,12 +3147,6 @@ static void ibmvnic_handle_crq(union ibmvnic_crq *crq,
		switch (gen_crq->cmd) {
		case IBMVNIC_CRQ_INIT:
			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;
		case IBMVNIC_CRQ_INIT_COMPLETE:
			dev_info(dev, "Partner initialization complete\n");
@@ -2941,19 +3157,18 @@ static void ibmvnic_handle_crq(union ibmvnic_crq *crq,
		}
		return;
	case IBMVNIC_CRQ_XPORT_EVENT:
		netif_carrier_off(netdev);
		if (gen_crq->cmd == IBMVNIC_PARTITION_MIGRATED) {
			dev_info(dev, "Re-enabling adapter\n");
			adapter->migrated = true;
			schedule_work(&adapter->ibmvnic_xport);
			dev_info(dev, "Migrated, re-enabling adapter\n");
			ibmvnic_reset(adapter, VNIC_RESET_MOBILITY);
		} else if (gen_crq->cmd == IBMVNIC_DEVICE_FAILOVER) {
			dev_info(dev, "Backing device failover detected\n");
			netif_carrier_off(netdev);
			adapter->failover = true;
			ibmvnic_reset(adapter, VNIC_RESET_FAILOVER);
		} else {
			/* The adapter lost the connection */
			dev_err(dev, "Virtual Adapter failed (rc=%d)\n",
				gen_crq->cmd);
			schedule_work(&adapter->ibmvnic_xport);
			ibmvnic_reset(adapter, VNIC_RESET_FATAL);
		}
		return;
	case IBMVNIC_CRQ_CMD_RSP:
@@ -3234,64 +3449,6 @@ static int init_crq_queue(struct ibmvnic_adapter *adapter)
	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)
{
	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;

	adapter = netdev_priv(netdev);
	adapter->state = VNIC_PROBING;
	dev_set_drvdata(&dev->dev, netdev);
	adapter->vdev = dev;
	adapter->netdev = netdev;
	adapter->failover = false;

	ether_addr_copy(adapter->mac_addr, mac_addr_p);
	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;
	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);

	INIT_LIST_HEAD(&adapter->errors);
	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);
	if (rc) {
		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;
	adapter->is_closed = false;

	rc = register_netdev(netdev);
	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");

	adapter->state = VNIC_PROBED;
	return 0;
}

@@ -3391,12 +3551,17 @@ static int ibmvnic_remove(struct vio_dev *dev)
	struct net_device *netdev = dev_get_drvdata(&dev->dev);
	struct ibmvnic_adapter *adapter = netdev_priv(netdev);

	adapter->state = VNIC_REMOVING;
	unregister_netdev(netdev);
	mutex_lock(&adapter->reset_lock);

	release_resources(adapter);
	release_sub_crqs(adapter);
	release_crq_queue(adapter);

	adapter->state = VNIC_REMOVED;

	mutex_unlock(&adapter->reset_lock);
	free_netdev(netdev);
	dev_set_drvdata(&dev->dev, NULL);

+25 −6
Original line number Diff line number Diff line
@@ -913,6 +913,25 @@ struct ibmvnic_error_buff {
	__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 vio_dev *vdev;
	struct net_device *netdev;
@@ -922,7 +941,6 @@ struct ibmvnic_adapter {
	dma_addr_t ip_offload_tok;
	struct ibmvnic_control_ip_offload_buffer ip_offload_ctrl;
	dma_addr_t ip_offload_ctrl_tok;
	bool migrated;
	u32 msg_enable;

	/* Statistics */
@@ -962,7 +980,6 @@ struct ibmvnic_adapter {
	u64 promisc;

	struct ibmvnic_tx_pool *tx_pool;
	bool closing;
	struct completion init_done;
	int init_done_rc;

@@ -1007,9 +1024,11 @@ struct ibmvnic_adapter {
	__be64 tx_rx_desc_req;
	u8 map_id;

	struct work_struct vnic_crq_init;
	struct work_struct ibmvnic_xport;
	struct tasklet_struct tasklet;
	bool failover;
	bool is_closed;
	enum vnic_state state;
	enum ibmvnic_reset_reason reset_reason;
	struct mutex reset_lock, rwi_lock;
	struct list_head rwi_list;
	struct work_struct ibmvnic_reset;
	bool resetting;
};