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

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

Merge branch 'ibmvnic-fixes'



Thomas Falcon says:

====================
ibmvnic driver bugfixes and improvements

Miscellaneous fixes and improvements on the ibmvnic driver.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 5b58d836 65dc6891
Loading
Loading
Loading
Loading
+167 −60
Original line number Diff line number Diff line
@@ -75,6 +75,7 @@
#include <linux/uaccess.h>
#include <asm/firmware.h>
#include <linux/seq_file.h>
#include <linux/workqueue.h>

#include "ibmvnic.h"

@@ -89,6 +90,7 @@ MODULE_VERSION(IBMVNIC_DRIVER_VERSION);
static int ibmvnic_version = IBMVNIC_INITIAL_VERSION;
static int ibmvnic_remove(struct vio_dev *);
static void release_sub_crqs(struct ibmvnic_adapter *);
static void release_sub_crqs_no_irqs(struct ibmvnic_adapter *);
static int ibmvnic_reset_crq(struct ibmvnic_adapter *);
static int ibmvnic_send_crq_init(struct ibmvnic_adapter *);
static int ibmvnic_reenable_crq_queue(struct ibmvnic_adapter *);
@@ -469,7 +471,8 @@ static int ibmvnic_open(struct net_device *netdev)
	crq.logical_link_state.link_state = IBMVNIC_LOGICAL_LNK_UP;
	ibmvnic_send_crq(adapter, &crq);

	netif_start_queue(netdev);
	netif_tx_start_all_queues(netdev);

	return 0;

bounce_map_failed:
@@ -519,7 +522,7 @@ static int ibmvnic_close(struct net_device *netdev)
	for (i = 0; i < adapter->req_rx_queues; i++)
		napi_disable(&adapter->napi[i]);

	netif_stop_queue(netdev);
	netif_tx_stop_all_queues(netdev);

	if (adapter->bounce_buffer) {
		if (!dma_mapping_error(dev, adapter->bounce_buffer_dma)) {
@@ -1212,12 +1215,6 @@ static struct ibmvnic_sub_crq_queue *init_sub_crq_queue(struct ibmvnic_adapter
		goto reg_failed;
	}

	scrq->irq = irq_create_mapping(NULL, scrq->hw_irq);
	if (scrq->irq == NO_IRQ) {
		dev_err(dev, "Error mapping irq\n");
		goto map_irq_failed;
	}

	scrq->adapter = adapter;
	scrq->size = 4 * PAGE_SIZE / sizeof(*scrq->msgs);
	scrq->cur = 0;
@@ -1230,12 +1227,6 @@ static struct ibmvnic_sub_crq_queue *init_sub_crq_queue(struct ibmvnic_adapter

	return scrq;

map_irq_failed:
	do {
		rc = plpar_hcall_norets(H_FREE_SUB_CRQ,
					adapter->vdev->unit_address,
					scrq->crq_num);
	} while (rc == H_BUSY || H_IS_LONG_BUSY(rc));
reg_failed:
	dma_unmap_single(dev, scrq->msg_token, 4 * PAGE_SIZE,
			 DMA_BIDIRECTIONAL);
@@ -1256,6 +1247,7 @@ static void release_sub_crqs(struct ibmvnic_adapter *adapter)
			if (adapter->tx_scrq[i]) {
				free_irq(adapter->tx_scrq[i]->irq,
					 adapter->tx_scrq[i]);
				irq_dispose_mapping(adapter->tx_scrq[i]->irq);
				release_sub_crq_queue(adapter,
						      adapter->tx_scrq[i]);
			}
@@ -1267,6 +1259,7 @@ static void release_sub_crqs(struct ibmvnic_adapter *adapter)
			if (adapter->rx_scrq[i]) {
				free_irq(adapter->rx_scrq[i]->irq,
					 adapter->rx_scrq[i]);
				irq_dispose_mapping(adapter->rx_scrq[i]->irq);
				release_sub_crq_queue(adapter,
						      adapter->rx_scrq[i]);
			}
@@ -1276,6 +1269,29 @@ static void release_sub_crqs(struct ibmvnic_adapter *adapter)
	adapter->requested_caps = 0;
}

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

	if (adapter->tx_scrq) {
		for (i = 0; i < adapter->req_tx_queues; i++)
			if (adapter->tx_scrq[i])
				release_sub_crq_queue(adapter,
						      adapter->tx_scrq[i]);
		adapter->tx_scrq = NULL;
	}

	if (adapter->rx_scrq) {
		for (i = 0; i < adapter->req_rx_queues; i++)
			if (adapter->rx_scrq[i])
				release_sub_crq_queue(adapter,
						      adapter->rx_scrq[i]);
		adapter->rx_scrq = NULL;
	}

	adapter->requested_caps = 0;
}

static int disable_scrq_irq(struct ibmvnic_adapter *adapter,
			    struct ibmvnic_sub_crq_queue *scrq)
{
@@ -1395,6 +1411,66 @@ static irqreturn_t ibmvnic_interrupt_rx(int irq, void *instance)
	return IRQ_HANDLED;
}

static int init_sub_crq_irqs(struct ibmvnic_adapter *adapter)
{
	struct device *dev = &adapter->vdev->dev;
	struct ibmvnic_sub_crq_queue *scrq;
	int i = 0, j = 0;
	int rc = 0;

	for (i = 0; i < adapter->req_tx_queues; i++) {
		scrq = adapter->tx_scrq[i];
		scrq->irq = irq_create_mapping(NULL, scrq->hw_irq);

		if (scrq->irq == NO_IRQ) {
			rc = -EINVAL;
			dev_err(dev, "Error mapping irq\n");
			goto req_tx_irq_failed;
		}

		rc = request_irq(scrq->irq, ibmvnic_interrupt_tx,
				 0, "ibmvnic_tx", scrq);

		if (rc) {
			dev_err(dev, "Couldn't register tx irq 0x%x. rc=%d\n",
				scrq->irq, rc);
			irq_dispose_mapping(scrq->irq);
			goto req_rx_irq_failed;
		}
	}

	for (i = 0; i < adapter->req_rx_queues; i++) {
		scrq = adapter->rx_scrq[i];
		scrq->irq = irq_create_mapping(NULL, scrq->hw_irq);
		if (scrq->irq == NO_IRQ) {
			rc = -EINVAL;
			dev_err(dev, "Error mapping irq\n");
			goto req_rx_irq_failed;
		}
		rc = request_irq(scrq->irq, ibmvnic_interrupt_rx,
				 0, "ibmvnic_rx", scrq);
		if (rc) {
			dev_err(dev, "Couldn't register rx irq 0x%x. rc=%d\n",
				scrq->irq, rc);
			irq_dispose_mapping(scrq->irq);
			goto req_rx_irq_failed;
		}
	}
	return rc;

req_rx_irq_failed:
	for (j = 0; j < i; j++)
		free_irq(adapter->rx_scrq[j]->irq, adapter->rx_scrq[j]);
		irq_dispose_mapping(adapter->rx_scrq[j]->irq);
	i = adapter->req_tx_queues;
req_tx_irq_failed:
	for (j = 0; j < i; j++)
		free_irq(adapter->tx_scrq[j]->irq, adapter->tx_scrq[j]);
		irq_dispose_mapping(adapter->rx_scrq[j]->irq);
	release_sub_crqs_no_irqs(adapter);
	return rc;
}

static void init_sub_crqs(struct ibmvnic_adapter *adapter, int retry)
{
	struct device *dev = &adapter->vdev->dev;
@@ -1403,8 +1479,7 @@ static void init_sub_crqs(struct ibmvnic_adapter *adapter, int retry)
	union ibmvnic_crq crq;
	int total_queues;
	int more = 0;
	int i, j;
	int rc;
	int i;

	if (!retry) {
		/* Sub-CRQ entries are 32 byte long */
@@ -1483,13 +1558,6 @@ static void init_sub_crqs(struct ibmvnic_adapter *adapter, int retry)
	for (i = 0; i < adapter->req_tx_queues; i++) {
		adapter->tx_scrq[i] = allqueues[i];
		adapter->tx_scrq[i]->pool_index = i;
		rc = request_irq(adapter->tx_scrq[i]->irq, ibmvnic_interrupt_tx,
				 0, "ibmvnic_tx", adapter->tx_scrq[i]);
		if (rc) {
			dev_err(dev, "Couldn't register tx irq 0x%x. rc=%d\n",
				adapter->tx_scrq[i]->irq, rc);
			goto req_tx_irq_failed;
		}
	}

	adapter->rx_scrq = kcalloc(adapter->req_rx_queues,
@@ -1500,13 +1568,6 @@ static void init_sub_crqs(struct ibmvnic_adapter *adapter, int retry)
	for (i = 0; i < adapter->req_rx_queues; i++) {
		adapter->rx_scrq[i] = allqueues[i + adapter->req_tx_queues];
		adapter->rx_scrq[i]->scrq_num = i;
		rc = request_irq(adapter->rx_scrq[i]->irq, ibmvnic_interrupt_rx,
				 0, "ibmvnic_rx", adapter->rx_scrq[i]);
		if (rc) {
			dev_err(dev, "Couldn't register rx irq 0x%x. rc=%d\n",
				adapter->rx_scrq[i]->irq, rc);
			goto req_rx_irq_failed;
		}
	}

	memset(&crq, 0, sizeof(crq));
@@ -1559,15 +1620,6 @@ static void init_sub_crqs(struct ibmvnic_adapter *adapter, int retry)

	return;

req_rx_irq_failed:
	for (j = 0; j < i; j++)
		free_irq(adapter->rx_scrq[j]->irq, adapter->rx_scrq[j]);
	i = adapter->req_tx_queues;
req_tx_irq_failed:
	for (j = 0; j < i; j++)
		free_irq(adapter->tx_scrq[j]->irq, adapter->tx_scrq[j]);
	kfree(adapter->rx_scrq);
	adapter->rx_scrq = NULL;
rx_failed:
	kfree(adapter->tx_scrq);
	adapter->tx_scrq = NULL;
@@ -2348,9 +2400,9 @@ static void handle_request_cap_rsp(union ibmvnic_crq *crq,
			 *req_value,
			 (long int)be32_to_cpu(crq->request_capability_rsp.
					       number), name);
		release_sub_crqs(adapter);
		release_sub_crqs_no_irqs(adapter);
		*req_value = be32_to_cpu(crq->request_capability_rsp.number);
		complete(&adapter->init_done);
		init_sub_crqs(adapter, 1);
		return;
	default:
		dev_err(dev, "Error %d in request cap rsp\n",
@@ -2659,7 +2711,7 @@ static void handle_query_cap_rsp(union ibmvnic_crq *crq,

out:
	if (atomic_read(&adapter->running_cap_queries) == 0)
		complete(&adapter->init_done);
		init_sub_crqs(adapter, 0);
		/* We're done querying the capabilities, initialize sub-crqs */
}

@@ -3202,8 +3254,8 @@ static void ibmvnic_handle_crq(union ibmvnic_crq *crq,
			dev_info(dev, "Partner initialized\n");
			/* Send back a response */
			rc = ibmvnic_send_crq_init_complete(adapter);
			if (rc == 0)
				send_version_xchg(adapter);
			if (!rc)
				schedule_work(&adapter->vnic_crq_init);
			else
				dev_err(dev, "Can't send initrsp rc=%ld\n", rc);
			break;
@@ -3555,8 +3607,63 @@ static const struct file_operations ibmvnic_dump_ops = {
	.release        = single_release,
};

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

	send_version_xchg(adapter);
	reinit_completion(&adapter->init_done);
	if (!wait_for_completion_timeout(&adapter->init_done, timeout)) {
		dev_err(dev, "Passive init timeout\n");
		goto task_failed;
	}

	do {
		if (adapter->renegotiate) {
			adapter->renegotiate = false;
			release_sub_crqs_no_irqs(adapter);
			send_cap_queries(adapter);

			reinit_completion(&adapter->init_done);
			if (!wait_for_completion_timeout(&adapter->init_done,
							 timeout)) {
				dev_err(dev, "Passive init timeout\n");
				goto task_failed;
			}
		}
	} while (adapter->renegotiate);
	rc = init_sub_crq_irqs(adapter);

	if (rc)
		goto task_failed;

	netdev->real_num_tx_queues = adapter->req_tx_queues;

	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;

register_failed:
	release_sub_crqs(adapter);
task_failed:
	dev_err(dev, "Passive initialization was not successful\n");
}

static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
{
	unsigned long timeout = msecs_to_jiffies(30000);
	struct ibmvnic_adapter *adapter;
	struct net_device *netdev;
	unsigned char *mac_addr_p;
@@ -3593,6 +3700,8 @@ 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);

	spin_lock_init(&adapter->stats_lock);

	rc = ibmvnic_init_crq_queue(adapter);
@@ -3635,30 +3744,26 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
	ibmvnic_send_crq_init(adapter);

	init_completion(&adapter->init_done);
	wait_for_completion(&adapter->init_done);
	if (!wait_for_completion_timeout(&adapter->init_done, timeout))
		return 0;

	do {
		adapter->renegotiate = false;

		init_sub_crqs(adapter, 0);
		reinit_completion(&adapter->init_done);
		wait_for_completion(&adapter->init_done);

		if (adapter->renegotiate) {
			release_sub_crqs(adapter);
			adapter->renegotiate = false;
			release_sub_crqs_no_irqs(adapter);
			send_cap_queries(adapter);

			reinit_completion(&adapter->init_done);
			wait_for_completion(&adapter->init_done);
			if (!wait_for_completion_timeout(&adapter->init_done,
							 timeout))
				return 0;
		}
	} while (adapter->renegotiate);

	/* if init_sub_crqs is partially successful, retry */
	while (!adapter->tx_scrq || !adapter->rx_scrq) {
		init_sub_crqs(adapter, 1);

		reinit_completion(&adapter->init_done);
		wait_for_completion(&adapter->init_done);
	rc = init_sub_crq_irqs(adapter);
	if (rc) {
		dev_err(&dev->dev, "failed to initialize sub crq irqs\n");
		goto free_debugfs;
	}

	netdev->real_num_tx_queues = adapter->req_tx_queues;
@@ -3666,12 +3771,14 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
	rc = register_netdev(netdev);
	if (rc) {
		dev_err(&dev->dev, "failed to register netdev rc=%d\n", rc);
		goto free_debugfs;
		goto free_sub_crqs;
	}
	dev_info(&dev->dev, "ibmvnic registered\n");

	return 0;

free_sub_crqs:
	release_sub_crqs(adapter);
free_debugfs:
	if (adapter->debugfs_dir && !IS_ERR(adapter->debugfs_dir))
		debugfs_remove_recursive(adapter->debugfs_dir);
+2 −0
Original line number Diff line number Diff line
@@ -1045,4 +1045,6 @@ struct ibmvnic_adapter {
	u64 opt_rxba_entries_per_subcrq;
	__be64 tx_rx_desc_req;
	u8 map_id;

	struct work_struct vnic_crq_init;
};