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

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


Jeff Kirsher says:

====================
40GbE Intel Wired LAN Driver Updates 2016-02-17

This series contains updates to i40e/i40evf once again.

Mitch updates the use of a define instead of a magic number.  Adds support
for packet split receive on VFs, which is disabled by default.  Expands on
a code comment which was not verbose or really helpful.  Fixes an issue
where if a reset fails to complete and was not properly setting the
adapter state, which would cause a panic on rmmod, so set the adpater
state to DOWN to avoid a panic.

Jesse cleans up a "dump" in debugfs that never panned out to be useful.

Anjali adds a workaround for cases where we might have interrupts that get
lost but wright-back (WB) happened.  Fixes an issue by falling back to
enabling unicast, multicast and broadcast promiscuous mode when the driver
must disable it's use of "default port" (defport mode) due to internal
incompatibility with Multiple Function per Port (MFP).  Fixes an issue
where queues should never be enabled/disabled in the interrupt handler.

Kiran cleans up th code which used hard coded base VEB SEID since it was
removed from the specification.

Shannon adds a few bits for better debug messages.  Fixes an obscure corner
case, where it was possible to clear the NVM update wait flag when no
update_done message was actually received.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents fbbef866 8888fd88
Loading
Loading
Loading
Loading
+1 −3
Original line number Diff line number Diff line
@@ -64,9 +64,6 @@
#include "i40e_dcb.h"

/* Useful i40e defaults */
#define I40E_BASE_PF_SEID     16
#define I40E_BASE_VSI_SEID    512
#define I40E_BASE_VEB_SEID    288
#define I40E_MAX_VEB          16

#define I40E_MAX_NUM_DESCRIPTORS      4096
@@ -512,6 +509,7 @@ struct i40e_vsi {
	u32 tx_busy;
	u64 tx_linearize;
	u64 tx_force_wb;
	u64 tx_lost_interrupt;
	u32 rx_buf_failed;
	u32 rx_page_failed;

+11 −9
Original line number Diff line number Diff line
/*******************************************************************************
 *
 * Intel Ethernet Controller XL710 Family Linux Driver
 * Copyright(c) 2013 - 2014 Intel Corporation.
 * Copyright(c) 2013 - 2016 Intel Corporation.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU General Public License,
@@ -953,6 +953,9 @@ i40e_status i40e_clean_arq_element(struct i40e_hw *hw,
	u16 flags;
	u16 ntu;

	/* pre-clean the event info */
	memset(&e->desc, 0, sizeof(e->desc));

	/* take the lock before we start messing with the ring */
	mutex_lock(&hw->aq.arq_mutex);

@@ -1020,14 +1023,6 @@ i40e_status i40e_clean_arq_element(struct i40e_hw *hw,
	hw->aq.arq.next_to_clean = ntc;
	hw->aq.arq.next_to_use = ntu;

clean_arq_element_out:
	/* Set pending if needed, unlock and return */
	if (pending != NULL)
		*pending = (ntc > ntu ? hw->aq.arq.count : 0) + (ntu - ntc);

clean_arq_element_err:
	mutex_unlock(&hw->aq.arq_mutex);

	if (i40e_is_nvm_update_op(&e->desc)) {
		if (hw->aq.nvm_release_on_done) {
			i40e_release_nvm(hw);
@@ -1048,6 +1043,13 @@ i40e_status i40e_clean_arq_element(struct i40e_hw *hw,
		}
	}

clean_arq_element_out:
	/* Set pending if needed, unlock and return */
	if (pending)
		*pending = (ntc > ntu ? hw->aq.arq.count : 0) + (ntu - ntc);
clean_arq_element_err:
	mutex_unlock(&hw->aq.arq_mutex);

	return ret_code;
}

+2 −1
Original line number Diff line number Diff line
/*******************************************************************************
 *
 * Intel Ethernet Controller XL710 Family Linux Driver
 * Copyright(c) 2013 - 2014 Intel Corporation.
 * Copyright(c) 2013 - 2016 Intel Corporation.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU General Public License,
@@ -1087,6 +1087,7 @@ struct i40e_aqc_set_vsi_promiscuous_modes {
#define I40E_AQC_SET_VSI_PROMISC_BROADCAST	0x04
#define I40E_AQC_SET_VSI_DEFAULT		0x08
#define I40E_AQC_SET_VSI_PROMISC_VLAN		0x10
#define I40E_AQC_SET_VSI_PROMISC_TX		0x8000
	__le16	seid;
#define I40E_AQC_VSI_PROM_CMD_SEID_MASK		0x3FF
	__le16	vlan_tag;
+8 −1
Original line number Diff line number Diff line
@@ -1952,12 +1952,19 @@ i40e_status i40e_aq_set_vsi_unicast_promiscuous(struct i40e_hw *hw,
	i40e_fill_default_direct_cmd_desc(&desc,
					i40e_aqc_opc_set_vsi_promiscuous_modes);

	if (set)
	if (set) {
		flags |= I40E_AQC_SET_VSI_PROMISC_UNICAST;
		if (((hw->aq.api_maj_ver == 1) && (hw->aq.api_min_ver >= 5)) ||
		    (hw->aq.api_maj_ver > 1))
			flags |= I40E_AQC_SET_VSI_PROMISC_TX;
	}

	cmd->promiscuous_flags = cpu_to_le16(flags);

	cmd->valid_flags = cpu_to_le16(I40E_AQC_SET_VSI_PROMISC_UNICAST);
	if (((hw->aq.api_maj_ver >= 1) && (hw->aq.api_min_ver >= 5)) ||
	    (hw->aq.api_maj_ver > 1))
		cmd->valid_flags |= cpu_to_le16(I40E_AQC_SET_VSI_PROMISC_TX);

	cmd->seid = cpu_to_le16(seid);
	status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details);
+3 −263
Original line number Diff line number Diff line
@@ -61,258 +61,12 @@ static struct i40e_veb *i40e_dbg_find_veb(struct i40e_pf *pf, int seid)
{
	int i;

	if ((seid < I40E_BASE_VEB_SEID) ||
	    (seid > (I40E_BASE_VEB_SEID + I40E_MAX_VEB)))
		dev_info(&pf->pdev->dev, "%d: bad seid\n", seid);
	else
	for (i = 0; i < I40E_MAX_VEB; i++)
		if (pf->veb[i] && pf->veb[i]->seid == seid)
			return pf->veb[i];
	return NULL;
}

/**************************************************************
 * dump
 * The dump entry in debugfs is for getting a data snapshow of
 * the driver's current configuration and runtime details.
 * When the filesystem entry is written, a snapshot is taken.
 * When the entry is read, the most recent snapshot data is dumped.
 **************************************************************/
static char *i40e_dbg_dump_buf;
static ssize_t i40e_dbg_dump_data_len;
static ssize_t i40e_dbg_dump_buffer_len;

/**
 * i40e_dbg_dump_read - read the dump data
 * @filp: the opened file
 * @buffer: where to write the data for the user to read
 * @count: the size of the user's buffer
 * @ppos: file position offset
 **/
static ssize_t i40e_dbg_dump_read(struct file *filp, char __user *buffer,
				  size_t count, loff_t *ppos)
{
	int bytes_not_copied;
	int len;

	/* is *ppos bigger than the available data? */
	if (*ppos >= i40e_dbg_dump_data_len || !i40e_dbg_dump_buf)
		return 0;

	/* be sure to not read beyond the end of available data */
	len = min_t(int, count, (i40e_dbg_dump_data_len - *ppos));

	bytes_not_copied = copy_to_user(buffer, &i40e_dbg_dump_buf[*ppos], len);
	if (bytes_not_copied)
		return -EFAULT;

	*ppos += len;
	return len;
}

/**
 * i40e_dbg_prep_dump_buf
 * @pf: the PF we're working with
 * @buflen: the desired buffer length
 *
 * Return positive if success, 0 if failed
 **/
static int i40e_dbg_prep_dump_buf(struct i40e_pf *pf, int buflen)
{
	/* if not already big enough, prep for re alloc */
	if (i40e_dbg_dump_buffer_len && i40e_dbg_dump_buffer_len < buflen) {
		kfree(i40e_dbg_dump_buf);
		i40e_dbg_dump_buffer_len = 0;
		i40e_dbg_dump_buf = NULL;
	}

	/* get a new buffer if needed */
	if (!i40e_dbg_dump_buf) {
		i40e_dbg_dump_buf = kzalloc(buflen, GFP_KERNEL);
		if (i40e_dbg_dump_buf != NULL)
			i40e_dbg_dump_buffer_len = buflen;
	}

	return i40e_dbg_dump_buffer_len;
}

/**
 * i40e_dbg_dump_write - trigger a datadump snapshot
 * @filp: the opened file
 * @buffer: where to find the user's data
 * @count: the length of the user's data
 * @ppos: file position offset
 *
 * Any write clears the stats
 **/
static ssize_t i40e_dbg_dump_write(struct file *filp,
				   const char __user *buffer,
				   size_t count, loff_t *ppos)
{
	struct i40e_pf *pf = filp->private_data;
	bool seid_found = false;
	long seid = -1;
	int buflen = 0;
	int i, ret;
	int len;
	u8 *p;

	/* don't allow partial writes */
	if (*ppos != 0)
		return 0;

	/* decode the SEID given to be dumped */
	ret = kstrtol_from_user(buffer, count, 0, &seid);

	if (ret) {
		dev_info(&pf->pdev->dev, "bad seid value\n");
	} else if (seid == 0) {
		seid_found = true;

		kfree(i40e_dbg_dump_buf);
		i40e_dbg_dump_buffer_len = 0;
		i40e_dbg_dump_data_len = 0;
		i40e_dbg_dump_buf = NULL;
		dev_info(&pf->pdev->dev, "debug buffer freed\n");

	} else if (seid == pf->pf_seid || seid == 1) {
		seid_found = true;

		buflen = sizeof(struct i40e_pf);
		buflen += (sizeof(struct i40e_aq_desc)
		     * (pf->hw.aq.num_arq_entries + pf->hw.aq.num_asq_entries));

		if (i40e_dbg_prep_dump_buf(pf, buflen)) {
			p = i40e_dbg_dump_buf;

			/* avoid use of memcpy here due to sparse warning
			 * about copy size.
			 */
			*((struct i40e_pf *)p) = *pf;
			p += sizeof(struct i40e_pf);

			len = (sizeof(struct i40e_aq_desc)
					* pf->hw.aq.num_asq_entries);
			memcpy(p, pf->hw.aq.asq.desc_buf.va, len);
			p += len;

			len = (sizeof(struct i40e_aq_desc)
					* pf->hw.aq.num_arq_entries);
			memcpy(p, pf->hw.aq.arq.desc_buf.va, len);
			p += len;

			i40e_dbg_dump_data_len = buflen;
			dev_info(&pf->pdev->dev,
				 "PF seid %ld dumped %d bytes\n",
				 seid, (int)i40e_dbg_dump_data_len);
		}
	} else if (seid >= I40E_BASE_VSI_SEID) {
		struct i40e_vsi *vsi = NULL;
		struct i40e_mac_filter *f;
		int filter_count = 0;

		mutex_lock(&pf->switch_mutex);
		vsi = i40e_dbg_find_vsi(pf, seid);
		if (!vsi) {
			mutex_unlock(&pf->switch_mutex);
			goto write_exit;
		}

		buflen = sizeof(struct i40e_vsi);
		buflen += sizeof(struct i40e_q_vector) * vsi->num_q_vectors;
		buflen += sizeof(struct i40e_ring) * 2 * vsi->num_queue_pairs;
		buflen += sizeof(struct i40e_tx_buffer) * vsi->num_queue_pairs;
		buflen += sizeof(struct i40e_rx_buffer) * vsi->num_queue_pairs;
		list_for_each_entry(f, &vsi->mac_filter_list, list)
			filter_count++;
		buflen += sizeof(struct i40e_mac_filter) * filter_count;

		if (i40e_dbg_prep_dump_buf(pf, buflen)) {
			p = i40e_dbg_dump_buf;
			seid_found = true;

			len = sizeof(struct i40e_vsi);
			memcpy(p, vsi, len);
			p += len;

			if (vsi->num_q_vectors) {
				len = (sizeof(struct i40e_q_vector)
					* vsi->num_q_vectors);
				memcpy(p, vsi->q_vectors, len);
				p += len;
			}

			if (vsi->num_queue_pairs) {
				len = (sizeof(struct i40e_ring) *
				      vsi->num_queue_pairs);
				memcpy(p, vsi->tx_rings, len);
				p += len;
				memcpy(p, vsi->rx_rings, len);
				p += len;
			}

			if (vsi->tx_rings[0]) {
				len = sizeof(struct i40e_tx_buffer);
				for (i = 0; i < vsi->num_queue_pairs; i++) {
					memcpy(p, vsi->tx_rings[i]->tx_bi, len);
					p += len;
				}
				len = sizeof(struct i40e_rx_buffer);
				for (i = 0; i < vsi->num_queue_pairs; i++) {
					memcpy(p, vsi->rx_rings[i]->rx_bi, len);
					p += len;
				}
			}

			/* macvlan filter list */
			len = sizeof(struct i40e_mac_filter);
			list_for_each_entry(f, &vsi->mac_filter_list, list) {
				memcpy(p, f, len);
				p += len;
			}

			i40e_dbg_dump_data_len = buflen;
			dev_info(&pf->pdev->dev,
				 "VSI seid %ld dumped %d bytes\n",
				 seid, (int)i40e_dbg_dump_data_len);
		}
		mutex_unlock(&pf->switch_mutex);
	} else if (seid >= I40E_BASE_VEB_SEID) {
		struct i40e_veb *veb = NULL;

		mutex_lock(&pf->switch_mutex);
		veb = i40e_dbg_find_veb(pf, seid);
		if (!veb) {
			mutex_unlock(&pf->switch_mutex);
			goto write_exit;
		}

		buflen = sizeof(struct i40e_veb);
		if (i40e_dbg_prep_dump_buf(pf, buflen)) {
			seid_found = true;
			memcpy(i40e_dbg_dump_buf, veb, buflen);
			i40e_dbg_dump_data_len = buflen;
			dev_info(&pf->pdev->dev,
				 "VEB seid %ld dumped %d bytes\n",
				 seid, (int)i40e_dbg_dump_data_len);
		}
		mutex_unlock(&pf->switch_mutex);
	}

write_exit:
	if (!seid_found)
		dev_info(&pf->pdev->dev, "unknown seid %ld\n", seid);

	return count;
}

static const struct file_operations i40e_dbg_dump_fops = {
	.owner = THIS_MODULE,
	.open =  simple_open,
	.read =  i40e_dbg_dump_read,
	.write = i40e_dbg_dump_write,
};

/**************************************************************
 * command
 * The command entry in debugfs is for giving the driver commands
@@ -933,12 +687,6 @@ static void i40e_dbg_dump_veb_seid(struct i40e_pf *pf, int seid)
{
	struct i40e_veb *veb;

	if ((seid < I40E_BASE_VEB_SEID) ||
	    (seid >= (I40E_MAX_VEB + I40E_BASE_VEB_SEID))) {
		dev_info(&pf->pdev->dev, "%d: bad seid\n", seid);
		return;
	}

	veb = i40e_dbg_find_veb(pf, seid);
	if (!veb) {
		dev_info(&pf->pdev->dev, "can't find veb %d\n", seid);
@@ -2217,11 +1965,6 @@ void i40e_dbg_pf_init(struct i40e_pf *pf)
	if (!pfile)
		goto create_failed;

	pfile = debugfs_create_file("dump", 0600, pf->i40e_dbg_pf, pf,
				    &i40e_dbg_dump_fops);
	if (!pfile)
		goto create_failed;

	pfile = debugfs_create_file("netdev_ops", 0600, pf->i40e_dbg_pf, pf,
				    &i40e_dbg_netdev_ops_fops);
	if (!pfile)
@@ -2242,9 +1985,6 @@ void i40e_dbg_pf_exit(struct i40e_pf *pf)
{
	debugfs_remove_recursive(pf->i40e_dbg_pf);
	pf->i40e_dbg_pf = NULL;

	kfree(i40e_dbg_dump_buf);
	i40e_dbg_dump_buf = NULL;
}

/**
Loading