Commit 6548755c authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge branch 'ibmvnic-assorted-bug-fixes'

Dany Madden says:

====================
ibmvnic: assorted bug fixes

Assorted fixes for ibmvnic originated from "[PATCH net 00/15] ibmvnic:
assorted bug fixes" sent by Lijun Pan.
====================

Link: https://lore.kernel.org/r/20201126000432.29897-1-drt@linux.ibm.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents bd2d5c54 98c41f04
Loading
Loading
Loading
Loading
+103 −65
Original line number Diff line number Diff line
@@ -834,7 +834,7 @@ static void release_napi(struct ibmvnic_adapter *adapter)
static int ibmvnic_login(struct net_device *netdev)
{
	struct ibmvnic_adapter *adapter = netdev_priv(netdev);
	unsigned long timeout = msecs_to_jiffies(30000);
	unsigned long timeout = msecs_to_jiffies(20000);
	int retry_count = 0;
	int retries = 10;
	bool retry;
@@ -850,10 +850,8 @@ static int ibmvnic_login(struct net_device *netdev)
		adapter->init_done_rc = 0;
		reinit_completion(&adapter->init_done);
		rc = send_login(adapter);
		if (rc) {
			netdev_warn(netdev, "Unable to login\n");
		if (rc)
			return rc;
		}

		if (!wait_for_completion_timeout(&adapter->init_done,
						 timeout)) {
@@ -940,7 +938,7 @@ static void release_resources(struct ibmvnic_adapter *adapter)
static int set_link_state(struct ibmvnic_adapter *adapter, u8 link_state)
{
	struct net_device *netdev = adapter->netdev;
	unsigned long timeout = msecs_to_jiffies(30000);
	unsigned long timeout = msecs_to_jiffies(20000);
	union ibmvnic_crq crq;
	bool resend;
	int rc;
@@ -1857,7 +1855,7 @@ static int do_change_param_reset(struct ibmvnic_adapter *adapter,
	if (reset_state == VNIC_OPEN) {
		rc = __ibmvnic_close(netdev);
		if (rc)
			return rc;
			goto out;
	}

	release_resources(adapter);
@@ -1875,24 +1873,25 @@ static int do_change_param_reset(struct ibmvnic_adapter *adapter,
	}

	rc = ibmvnic_reset_init(adapter, true);
	if (rc)
		return IBMVNIC_INIT_FAILED;
	if (rc) {
		rc = IBMVNIC_INIT_FAILED;
		goto out;
	}

	/* If the adapter was in PROBE state prior to the reset,
	 * exit here.
	 */
	if (reset_state == VNIC_PROBED)
		return 0;
		goto out;

	rc = ibmvnic_login(netdev);
	if (rc) {
		adapter->state = reset_state;
		return rc;
		goto out;
	}

	rc = init_resources(adapter);
	if (rc)
		return rc;
		goto out;

	ibmvnic_disable_irqs(adapter);

@@ -1902,8 +1901,10 @@ static int do_change_param_reset(struct ibmvnic_adapter *adapter,
		return 0;

	rc = __ibmvnic_open(netdev);
	if (rc)
		return IBMVNIC_OPEN_FAILED;
	if (rc) {
		rc = IBMVNIC_OPEN_FAILED;
		goto out;
	}

	/* refresh device's multicast list */
	ibmvnic_set_multi(netdev);
@@ -1912,7 +1913,10 @@ static int do_change_param_reset(struct ibmvnic_adapter *adapter,
	for (i = 0; i < adapter->req_rx_queues; i++)
		napi_schedule(&adapter->napi[i]);

	return 0;
out:
	if (rc)
		adapter->state = reset_state;
	return rc;
}

/**
@@ -2015,7 +2019,6 @@ static int do_reset(struct ibmvnic_adapter *adapter,

		rc = ibmvnic_login(netdev);
		if (rc) {
			adapter->state = reset_state;
			goto out;
		}

@@ -2083,6 +2086,9 @@ static int do_reset(struct ibmvnic_adapter *adapter,
	rc = 0;

out:
	/* restore the adapter state if reset failed */
	if (rc)
		adapter->state = reset_state;
	rtnl_unlock();

	return rc;
@@ -2115,43 +2121,46 @@ static int do_hard_reset(struct ibmvnic_adapter *adapter,
	if (rc) {
		netdev_err(adapter->netdev,
			   "Couldn't initialize crq. rc=%d\n", rc);
		return rc;
		goto out;
	}

	rc = ibmvnic_reset_init(adapter, false);
	if (rc)
		return rc;
		goto out;

	/* If the adapter was in PROBE state prior to the reset,
	 * exit here.
	 */
	if (reset_state == VNIC_PROBED)
		return 0;
		goto out;

	rc = ibmvnic_login(netdev);
	if (rc) {
		adapter->state = VNIC_PROBED;
		return 0;
	}
	if (rc)
		goto out;

	rc = init_resources(adapter);
	if (rc)
		return rc;
		goto out;

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

	if (reset_state == VNIC_CLOSED)
		return 0;
		goto out;

	rc = __ibmvnic_open(netdev);
	if (rc)
		return IBMVNIC_OPEN_FAILED;
	if (rc) {
		rc = IBMVNIC_OPEN_FAILED;
		goto out;
	}

	call_netdevice_notifiers(NETDEV_NOTIFY_PEERS, netdev);
	call_netdevice_notifiers(NETDEV_RESEND_IGMP, netdev);

	return 0;
out:
	/* restore adapter state if reset failed */
	if (rc)
		adapter->state = reset_state;
	return rc;
}

static struct ibmvnic_rwi *get_next_rwi(struct ibmvnic_adapter *adapter)
@@ -2173,17 +2182,6 @@ static struct ibmvnic_rwi *get_next_rwi(struct ibmvnic_adapter *adapter)
	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;
@@ -2241,20 +2239,23 @@ static void __ibmvnic_reset(struct work_struct *work)
				rc = do_hard_reset(adapter, rwi, reset_state);
				rtnl_unlock();
			}
			if (rc) {
				/* give backing device time to settle down */
				netdev_dbg(adapter->netdev,
					   "[S:%d] Hard reset failed, waiting 60 secs\n",
					   adapter->state);
				set_current_state(TASK_UNINTERRUPTIBLE);
				schedule_timeout(60 * HZ);
			}
		} else if (!(rwi->reset_reason == VNIC_RESET_FATAL &&
				adapter->from_passive_init)) {
			rc = do_reset(adapter, rwi, reset_state);
		}
		kfree(rwi);
		if (rc == IBMVNIC_OPEN_FAILED) {
			if (list_empty(&adapter->rwi_list))
				adapter->state = VNIC_CLOSED;
			else
				adapter->state = reset_state;
			rc = 0;
		} else if (rc && rc != IBMVNIC_INIT_FAILED &&
		    !adapter->force_reset_recovery)
			break;
		adapter->last_reset_time = jiffies;

		if (rc)
			netdev_dbg(adapter->netdev, "Reset failed, rc=%d\n", rc);

		rwi = get_next_rwi(adapter);

@@ -2268,11 +2269,6 @@ static void __ibmvnic_reset(struct work_struct *work)
		complete(&adapter->reset_done);
	}

	if (rc) {
		netdev_dbg(adapter->netdev, "Reset failed\n");
		free_all_rwi(adapter);
	}

	clear_bit_unlock(0, &adapter->resetting);
}

@@ -2360,7 +2356,13 @@ static void ibmvnic_tx_timeout(struct net_device *dev, unsigned int txqueue)
			   "Adapter is resetting, skip timeout reset\n");
		return;
	}

	/* No queuing up reset until at least 5 seconds (default watchdog val)
	 * after last reset
	 */
	if (time_before(jiffies, (adapter->last_reset_time + dev->watchdog_timeo))) {
		netdev_dbg(dev, "Not yet time to tx timeout.\n");
		return;
	}
	ibmvnic_reset(adapter, VNIC_RESET_TIMEOUT);
}

@@ -2860,15 +2862,26 @@ static int reset_one_sub_crq_queue(struct ibmvnic_adapter *adapter,
{
	int rc;

	if (!scrq) {
		netdev_dbg(adapter->netdev,
			   "Invalid scrq reset. irq (%d) or msgs (%p).\n",
			   scrq->irq, scrq->msgs);
		return -EINVAL;
	}

	if (scrq->irq) {
		free_irq(scrq->irq, scrq);
		irq_dispose_mapping(scrq->irq);
		scrq->irq = 0;
	}

	if (scrq->msgs) {
		memset(scrq->msgs, 0, 4 * PAGE_SIZE);
		atomic_set(&scrq->used, 0);
		scrq->cur = 0;
	} else {
		netdev_dbg(adapter->netdev, "Invalid scrq reset\n");
		return -EINVAL;
	}

	rc = h_reg_sub_crq(adapter->vdev->unit_address, scrq->msg_token,
			   4 * PAGE_SIZE, &scrq->crq_num, &scrq->hw_irq);
@@ -3721,15 +3734,16 @@ static int send_login(struct ibmvnic_adapter *adapter)
	struct ibmvnic_login_rsp_buffer *login_rsp_buffer;
	struct ibmvnic_login_buffer *login_buffer;
	struct device *dev = &adapter->vdev->dev;
	struct vnic_login_client_data *vlcd;
	dma_addr_t rsp_buffer_token;
	dma_addr_t buffer_token;
	size_t rsp_buffer_size;
	union ibmvnic_crq crq;
	int client_data_len;
	size_t buffer_size;
	__be64 *tx_list_p;
	__be64 *rx_list_p;
	int client_data_len;
	struct vnic_login_client_data *vlcd;
	int rc;
	int i;

	if (!adapter->tx_scrq || !adapter->rx_scrq) {
@@ -3833,16 +3847,25 @@ static int send_login(struct ibmvnic_adapter *adapter)
	crq.login.cmd = LOGIN;
	crq.login.ioba = cpu_to_be32(buffer_token);
	crq.login.len = cpu_to_be32(buffer_size);
	ibmvnic_send_crq(adapter, &crq);

	adapter->login_pending = true;
	rc = ibmvnic_send_crq(adapter, &crq);
	if (rc) {
		adapter->login_pending = false;
		netdev_err(adapter->netdev, "Failed to send login, rc=%d\n", rc);
		goto buf_rsp_map_failed;
	}

	return 0;

buf_rsp_map_failed:
	kfree(login_rsp_buffer);
	adapter->login_rsp_buf = NULL;
buf_rsp_alloc_failed:
	dma_unmap_single(dev, buffer_token, buffer_size, DMA_TO_DEVICE);
buf_map_failed:
	kfree(login_buffer);
	adapter->login_buf = NULL;
buf_alloc_failed:
	return -1;
}
@@ -4385,6 +4408,15 @@ static int handle_login_rsp(union ibmvnic_crq *login_rsp_crq,
	u64 *size_array;
	int i;

	/* CHECK: Test/set of login_pending does not need to be atomic
	 * because only ibmvnic_tasklet tests/clears this.
	 */
	if (!adapter->login_pending) {
		netdev_warn(netdev, "Ignoring unexpected login response\n");
		return 0;
	}
	adapter->login_pending = false;

	dma_unmap_single(dev, adapter->login_buf_token, adapter->login_buf_sz,
			 DMA_TO_DEVICE);
	dma_unmap_single(dev, adapter->login_rsp_buf_token,
@@ -4414,7 +4446,7 @@ static int handle_login_rsp(union ibmvnic_crq *login_rsp_crq,
	     adapter->req_rx_add_queues !=
	     be32_to_cpu(login_rsp->num_rxadd_subcrqs))) {
		dev_err(dev, "FATAL: Inconsistent login and login rsp\n");
		ibmvnic_remove(adapter->vdev);
		ibmvnic_reset(adapter, VNIC_RESET_FATAL);
		return -EIO;
	}
	size_array = (u64 *)((u8 *)(adapter->login_rsp_buf) +
@@ -4756,6 +4788,11 @@ static void ibmvnic_handle_crq(union ibmvnic_crq *crq,
		case IBMVNIC_CRQ_INIT:
			dev_info(dev, "Partner initialized\n");
			adapter->from_passive_init = true;
			/* Discard any stale login responses from prev reset.
			 * CHECK: should we clear even on INIT_COMPLETE?
			 */
			adapter->login_pending = false;

			if (!completion_done(&adapter->init_done)) {
				complete(&adapter->init_done);
				adapter->init_done_rc = -EIO;
@@ -5093,7 +5130,7 @@ static int init_crq_queue(struct ibmvnic_adapter *adapter)
static int ibmvnic_reset_init(struct ibmvnic_adapter *adapter, bool reset)
{
	struct device *dev = &adapter->vdev->dev;
	unsigned long timeout = msecs_to_jiffies(30000);
	unsigned long timeout = msecs_to_jiffies(20000);
	u64 old_num_rx_queues, old_num_tx_queues;
	int rc;

@@ -5188,6 +5225,7 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
	dev_set_drvdata(&dev->dev, netdev);
	adapter->vdev = dev;
	adapter->netdev = netdev;
	adapter->login_pending = false;

	ether_addr_copy(adapter->mac_addr, mac_addr_p);
	ether_addr_copy(netdev->dev_addr, adapter->mac_addr);
@@ -5251,7 +5289,7 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
	adapter->state = VNIC_PROBED;

	adapter->wait_for_reset = false;

	adapter->last_reset_time = jiffies;
	return 0;

ibmvnic_register_fail:
+3 −0
Original line number Diff line number Diff line
@@ -1086,6 +1086,9 @@ struct ibmvnic_adapter {
	struct delayed_work ibmvnic_delayed_reset;
	unsigned long resetting;
	bool napi_enabled, from_passive_init;
	bool login_pending;
	/* last device reset time */
	unsigned long last_reset_time;

	bool failover_pending;
	bool force_reset_recovery;