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

Commit 2770a798 authored by Thomas Falcon's avatar Thomas Falcon Committed by David S. Miller
Browse files

ibmvnic: Introduce hard reset recovery



Introduce a recovery hard reset to handle reset failure as a result of
change of device context following a transport event, such as a
backing device failover or partition migration. These operations reset
the device context to its initial state. If this occurs during a reset,
any initialization commands are likely to fail with an invalid state
error as backing device firmware requests reinitialization.

When this happens, make one more attempt by performing a hard reset,
which frees any resources currently allocated and performs device
initialization. If a transport event occurs during a device reset, a
flag is set which will trigger a new hard reset following the
completionof the current reset event.

Signed-off-by: default avatarThomas Falcon <tlfalcon@linux.vnet.ibm.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 06e43d7f
Loading
Loading
Loading
Loading
+97 −4
Original line number Diff line number Diff line
@@ -1878,6 +1878,85 @@ static int do_reset(struct ibmvnic_adapter *adapter,
	return 0;
}

static int do_hard_reset(struct ibmvnic_adapter *adapter,
			 struct ibmvnic_rwi *rwi, u32 reset_state)
{
	struct net_device *netdev = adapter->netdev;
	int rc;

	netdev_dbg(adapter->netdev, "Hard resetting driver (%d)\n",
		   rwi->reset_reason);

	netif_carrier_off(netdev);
	adapter->reset_reason = rwi->reset_reason;

	ibmvnic_cleanup(netdev);
	release_resources(adapter);
	release_sub_crqs(adapter, 0);
	release_crq_queue(adapter);

	/* remove the closed state so when we call open it appears
	 * we are coming from the probed state.
	 */
	adapter->state = VNIC_PROBED;

	rc = init_crq_queue(adapter);
	if (rc) {
		netdev_err(adapter->netdev,
			   "Couldn't initialize crq. rc=%d\n", rc);
		return rc;
	}

	rc = ibmvnic_init(adapter);
	if (rc)
		return rc;

	/* 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;
	}
	/* netif_set_real_num_xx_queues needs to take rtnl lock here
	 * unless wait_for_reset is set, in which case the rtnl lock
	 * has already been taken before initializing the reset
	 */
	if (!adapter->wait_for_reset) {
		rtnl_lock();
		rc = init_resources(adapter);
		rtnl_unlock();
	} else {
		rc = init_resources(adapter);
	}
	if (rc)
		return rc;

	ibmvnic_disable_irqs(adapter);
	adapter->state = VNIC_CLOSED;

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

	return 0;
}

static struct ibmvnic_rwi *get_next_rwi(struct ibmvnic_adapter *adapter)
{
	struct ibmvnic_rwi *rwi;
@@ -1923,9 +2002,15 @@ static void __ibmvnic_reset(struct work_struct *work)

	rwi = get_next_rwi(adapter);
	while (rwi) {
		if (adapter->force_reset_recovery) {
			adapter->force_reset_recovery = false;
			rc = do_hard_reset(adapter, rwi, reset_state);
		} else {
			rc = do_reset(adapter, rwi, reset_state);
		}
		kfree(rwi);
		if (rc && rc != IBMVNIC_INIT_FAILED)
		if (rc && rc != IBMVNIC_INIT_FAILED &&
		    !adapter->force_reset_recovery)
			break;

		rwi = get_next_rwi(adapter);
@@ -1951,9 +2036,9 @@ static void __ibmvnic_reset(struct work_struct *work)
static int ibmvnic_reset(struct ibmvnic_adapter *adapter,
			 enum ibmvnic_reset_reason reason)
{
	struct list_head *entry, *tmp_entry;
	struct ibmvnic_rwi *rwi, *tmp;
	struct net_device *netdev = adapter->netdev;
	struct list_head *entry;
	int ret;

	if (adapter->state == VNIC_REMOVING ||
@@ -1989,7 +2074,13 @@ static int ibmvnic_reset(struct ibmvnic_adapter *adapter,
		ret = ENOMEM;
		goto err;
	}

	/* if we just received a transport event,
	 * flush reset queue and process this reset
	 */
	if (adapter->force_reset_recovery && !list_empty(&adapter->rwi_list)) {
		list_for_each_safe(entry, tmp_entry, &adapter->rwi_list)
			list_del(entry);
	}
	rwi->reset_reason = reason;
	list_add_tail(&rwi->list, &adapter->rwi_list);
	mutex_unlock(&adapter->rwi_lock);
@@ -4271,6 +4362,8 @@ static void ibmvnic_handle_crq(union ibmvnic_crq *crq,
	case IBMVNIC_CRQ_XPORT_EVENT:
		netif_carrier_off(netdev);
		adapter->crq.active = false;
		if (adapter->resetting)
			adapter->force_reset_recovery = true;
		if (gen_crq->cmd == IBMVNIC_PARTITION_MIGRATED) {
			dev_info(dev, "Migrated, re-enabling adapter\n");
			ibmvnic_reset(adapter, VNIC_RESET_MOBILITY);
+1 −0
Original line number Diff line number Diff line
@@ -1109,6 +1109,7 @@ struct ibmvnic_adapter {

	bool mac_change_pending;
	bool failover_pending;
	bool force_reset_recovery;

	struct ibmvnic_tunables desired;
	struct ibmvnic_tunables fallback;