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

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


Jeff Kirsher says:

====================
Intel Wired LAN Driver Updates 2014-07-24

This series contains updates to igb, ixgbe, i40e and i40evf.

Mark fixes a possible attempt to dereference a NULL pointer in ixgbe_probe().
Also changes some uses of strncpy to strlcpy when clearing is not needed to
prevent information leakage.

Jacob fixes a bug in the misuse of the list_for_each macro to loop over
every entry in the bus_list.  Instead of attempting to loop over the list
from a random entry point, go up to the bus and use the real list_head
entry point.  This prevents the possible read or write of unallocated or
incorrectly addressed memory.  Then provides a patch to prevent the
display of the minimum link qualification check if we might be in a
virtual machine.  This check is incorrect and misleading in this case,
since we actually do not really know what the available bandwidth is.
To do so, we simply check whether each function on the bus matches our
device id.

Carolyn adds a check and prints the error cause register value when the
hardware detects a malformed packet to assist the user.

Toralf Förster fixes a format mismatch in i40e which was found using
cppcheck.

Shannon adds nvmupdate support by implementing a state machine intended
to support the userland tool for updating the device eeprom.

Jesse fixes the extension header checksum logic for IPv6 in i40e and
i40evf.

Mitch reduces a delay in the i40evf driver where we do not need to
delay an entire millisecond to get into our critical section.

Kamil fixes an issue where access to the NVM was being blocked until
a driver reset where a check for NVM related admin queue commands
would not recognize that such a command was received and would not clear
nvm_busy flag.

Catherine fixes a couple of firmware API version errors.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents f6e67532 e3effd73
Loading
Loading
Loading
Loading
+22 −19
Original line number Original line Diff line number Diff line
@@ -38,8 +38,8 @@ static void i40e_resume_aq(struct i40e_hw *hw);
 **/
 **/
static inline bool i40e_is_nvm_update_op(struct i40e_aq_desc *desc)
static inline bool i40e_is_nvm_update_op(struct i40e_aq_desc *desc)
{
{
	return (desc->opcode == i40e_aqc_opc_nvm_erase) ||
	return (desc->opcode == cpu_to_le16(i40e_aqc_opc_nvm_erase)) ||
	       (desc->opcode == i40e_aqc_opc_nvm_update);
		(desc->opcode == cpu_to_le16(i40e_aqc_opc_nvm_update));
}
}


/**
/**
@@ -889,14 +889,9 @@ i40e_status i40e_asq_send_command(struct i40e_hw *hw,
		hw->aq.asq_last_status = (enum i40e_admin_queue_err)retval;
		hw->aq.asq_last_status = (enum i40e_admin_queue_err)retval;
	}
	}


	if (i40e_is_nvm_update_op(desc))
		hw->aq.nvm_busy = true;

	if (le16_to_cpu(desc->datalen) == buff_size) {
	i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE,
	i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE,
		   "AQTX: desc and buffer writeback:\n");
		   "AQTX: desc and buffer writeback:\n");
	i40e_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc, buff);
	i40e_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc, buff);
	}


	/* update the error if time out occurred */
	/* update the error if time out occurred */
	if ((!cmd_completed) &&
	if ((!cmd_completed) &&
@@ -907,6 +902,9 @@ i40e_status i40e_asq_send_command(struct i40e_hw *hw,
		status = I40E_ERR_ADMIN_QUEUE_TIMEOUT;
		status = I40E_ERR_ADMIN_QUEUE_TIMEOUT;
	}
	}


	if (!status && i40e_is_nvm_update_op(desc))
		hw->aq.nvm_busy = true;

asq_send_command_error:
asq_send_command_error:
	mutex_unlock(&hw->aq.asq_mutex);
	mutex_unlock(&hw->aq.asq_mutex);
asq_send_command_exit:
asq_send_command_exit:
@@ -979,17 +977,14 @@ i40e_status i40e_clean_arq_element(struct i40e_hw *hw,
			   I40E_DEBUG_AQ_MESSAGE,
			   I40E_DEBUG_AQ_MESSAGE,
			   "AQRX: Event received with error 0x%X.\n",
			   "AQRX: Event received with error 0x%X.\n",
			   hw->aq.arq_last_status);
			   hw->aq.arq_last_status);
	} else {
	}

	e->desc = *desc;
	e->desc = *desc;
	datalen = le16_to_cpu(desc->datalen);
	datalen = le16_to_cpu(desc->datalen);
	e->msg_size = min(datalen, e->msg_size);
	e->msg_size = min(datalen, e->msg_size);
	if (e->msg_buf != NULL && (e->msg_size != 0))
	if (e->msg_buf != NULL && (e->msg_size != 0))
		memcpy(e->msg_buf, hw->aq.arq.r.arq_bi[desc_idx].va,
		memcpy(e->msg_buf, hw->aq.arq.r.arq_bi[desc_idx].va,
		       e->msg_size);
		       e->msg_size);
	}

	if (i40e_is_nvm_update_op(&e->desc))
		hw->aq.nvm_busy = false;


	i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQRX: desc and buffer:\n");
	i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQRX: desc and buffer:\n");
	i40e_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc, e->msg_buf);
	i40e_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc, e->msg_buf);
@@ -1023,6 +1018,14 @@ i40e_status i40e_clean_arq_element(struct i40e_hw *hw,
		*pending = (ntc > ntu ? hw->aq.arq.count : 0) + (ntu - ntc);
		*pending = (ntc > ntu ? hw->aq.arq.count : 0) + (ntu - ntc);
	mutex_unlock(&hw->aq.arq_mutex);
	mutex_unlock(&hw->aq.arq_mutex);


	if (i40e_is_nvm_update_op(&e->desc)) {
		hw->aq.nvm_busy = false;
		if (hw->aq.nvm_release_on_done) {
			i40e_release_nvm(hw);
			hw->aq.nvm_release_on_done = false;
		}
	}

	return ret_code;
	return ret_code;
}
}


+36 −0
Original line number Original line Diff line number Diff line
@@ -94,6 +94,7 @@ struct i40e_adminq_info {
	u16 api_maj_ver;                /* api major version */
	u16 api_maj_ver;                /* api major version */
	u16 api_min_ver;                /* api minor version */
	u16 api_min_ver;                /* api minor version */
	bool nvm_busy;
	bool nvm_busy;
	bool nvm_release_on_done;


	struct mutex asq_mutex; /* Send queue lock */
	struct mutex asq_mutex; /* Send queue lock */
	struct mutex arq_mutex; /* Receive queue lock */
	struct mutex arq_mutex; /* Receive queue lock */
@@ -103,6 +104,41 @@ struct i40e_adminq_info {
	enum i40e_admin_queue_err arq_last_status;
	enum i40e_admin_queue_err arq_last_status;
};
};


/**
 * i40e_aq_rc_to_posix - convert errors to user-land codes
 * aq_rc: AdminQ error code to convert
 **/
static inline int i40e_aq_rc_to_posix(u16 aq_rc)
{
	int aq_to_posix[] = {
		0,           /* I40E_AQ_RC_OK */
		-EPERM,      /* I40E_AQ_RC_EPERM */
		-ENOENT,     /* I40E_AQ_RC_ENOENT */
		-ESRCH,      /* I40E_AQ_RC_ESRCH */
		-EINTR,      /* I40E_AQ_RC_EINTR */
		-EIO,        /* I40E_AQ_RC_EIO */
		-ENXIO,      /* I40E_AQ_RC_ENXIO */
		-E2BIG,      /* I40E_AQ_RC_E2BIG */
		-EAGAIN,     /* I40E_AQ_RC_EAGAIN */
		-ENOMEM,     /* I40E_AQ_RC_ENOMEM */
		-EACCES,     /* I40E_AQ_RC_EACCES */
		-EFAULT,     /* I40E_AQ_RC_EFAULT */
		-EBUSY,      /* I40E_AQ_RC_EBUSY */
		-EEXIST,     /* I40E_AQ_RC_EEXIST */
		-EINVAL,     /* I40E_AQ_RC_EINVAL */
		-ENOTTY,     /* I40E_AQ_RC_ENOTTY */
		-ENOSPC,     /* I40E_AQ_RC_ENOSPC */
		-ENOSYS,     /* I40E_AQ_RC_ENOSYS */
		-ERANGE,     /* I40E_AQ_RC_ERANGE */
		-EPIPE,      /* I40E_AQ_RC_EFLUSHED */
		-ESPIPE,     /* I40E_AQ_RC_BAD_ADDR */
		-EROFS,      /* I40E_AQ_RC_EMODE */
		-EFBIG,      /* I40E_AQ_RC_EFBIG */
	};

	return aq_to_posix[aq_rc];
}

/* general information */
/* general information */
#define I40E_AQ_LARGE_BUF	512
#define I40E_AQ_LARGE_BUF	512
#define I40E_ASQ_CMD_TIMEOUT	100000  /* usecs */
#define I40E_ASQ_CMD_TIMEOUT	100000  /* usecs */
+88 −0
Original line number Original line Diff line number Diff line
@@ -2121,6 +2121,47 @@ i40e_status i40e_aq_read_nvm(struct i40e_hw *hw, u8 module_pointer,
	return status;
	return status;
}
}


/**
 * i40e_aq_erase_nvm
 * @hw: pointer to the hw struct
 * @module_pointer: module pointer location in words from the NVM beginning
 * @offset: offset in the module (expressed in 4 KB from module's beginning)
 * @length: length of the section to be erased (expressed in 4 KB)
 * @last_command: tells if this is the last command in a series
 * @cmd_details: pointer to command details structure or NULL
 *
 * Erase the NVM sector using the admin queue commands
 **/
i40e_status i40e_aq_erase_nvm(struct i40e_hw *hw, u8 module_pointer,
			      u32 offset, u16 length, bool last_command,
			      struct i40e_asq_cmd_details *cmd_details)
{
	struct i40e_aq_desc desc;
	struct i40e_aqc_nvm_update *cmd =
		(struct i40e_aqc_nvm_update *)&desc.params.raw;
	i40e_status status;

	/* In offset the highest byte must be zeroed. */
	if (offset & 0xFF000000) {
		status = I40E_ERR_PARAM;
		goto i40e_aq_erase_nvm_exit;
	}

	i40e_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_nvm_erase);

	/* If this is the last command in a series, set the proper flag. */
	if (last_command)
		cmd->command_flags |= I40E_AQ_NVM_LAST_CMD;
	cmd->module_pointer = module_pointer;
	cmd->offset = cpu_to_le32(offset);
	cmd->length = cpu_to_le16(length);

	status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details);

i40e_aq_erase_nvm_exit:
	return status;
}

#define I40E_DEV_FUNC_CAP_SWITCH_MODE	0x01
#define I40E_DEV_FUNC_CAP_SWITCH_MODE	0x01
#define I40E_DEV_FUNC_CAP_MGMT_MODE	0x02
#define I40E_DEV_FUNC_CAP_MGMT_MODE	0x02
#define I40E_DEV_FUNC_CAP_NPAR		0x03
#define I40E_DEV_FUNC_CAP_NPAR		0x03
@@ -2350,6 +2391,53 @@ i40e_status i40e_aq_discover_capabilities(struct i40e_hw *hw,
	return status;
	return status;
}
}


/**
 * i40e_aq_update_nvm
 * @hw: pointer to the hw struct
 * @module_pointer: module pointer location in words from the NVM beginning
 * @offset: byte offset from the module beginning
 * @length: length of the section to be written (in bytes from the offset)
 * @data: command buffer (size [bytes] = length)
 * @last_command: tells if this is the last command in a series
 * @cmd_details: pointer to command details structure or NULL
 *
 * Update the NVM using the admin queue commands
 **/
i40e_status i40e_aq_update_nvm(struct i40e_hw *hw, u8 module_pointer,
			       u32 offset, u16 length, void *data,
			       bool last_command,
			       struct i40e_asq_cmd_details *cmd_details)
{
	struct i40e_aq_desc desc;
	struct i40e_aqc_nvm_update *cmd =
		(struct i40e_aqc_nvm_update *)&desc.params.raw;
	i40e_status status;

	/* In offset the highest byte must be zeroed. */
	if (offset & 0xFF000000) {
		status = I40E_ERR_PARAM;
		goto i40e_aq_update_nvm_exit;
	}

	i40e_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_nvm_update);

	/* If this is the last command in a series, set the proper flag. */
	if (last_command)
		cmd->command_flags |= I40E_AQ_NVM_LAST_CMD;
	cmd->module_pointer = module_pointer;
	cmd->offset = cpu_to_le32(offset);
	cmd->length = cpu_to_le16(length);

	desc.flags |= cpu_to_le16((u16)(I40E_AQ_FLAG_BUF | I40E_AQ_FLAG_RD));
	if (length > I40E_AQ_LARGE_BUF)
		desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_LB);

	status = i40e_asq_send_command(hw, &desc, data, length, cmd_details);

i40e_aq_update_nvm_exit:
	return status;
}

/**
/**
 * i40e_aq_get_lldp_mib
 * i40e_aq_get_lldp_mib
 * @hw: pointer to the hw struct
 * @hw: pointer to the hw struct
+2 −2
Original line number Original line Diff line number Diff line
@@ -1238,7 +1238,7 @@ static ssize_t i40e_dbg_command_write(struct file *filp,
	} else if (strncmp(cmd_buf, "add pvid", 8) == 0) {
	} else if (strncmp(cmd_buf, "add pvid", 8) == 0) {
		i40e_status ret;
		i40e_status ret;
		u16 vid;
		u16 vid;
		int v;
		unsigned int v;


		cnt = sscanf(&cmd_buf[8], "%i %u", &vsi_seid, &v);
		cnt = sscanf(&cmd_buf[8], "%i %u", &vsi_seid, &v);
		if (cnt != 2) {
		if (cnt != 2) {
@@ -1254,7 +1254,7 @@ static ssize_t i40e_dbg_command_write(struct file *filp,
			goto command_write_done;
			goto command_write_done;
		}
		}


		vid = (unsigned)v;
		vid = v;
		ret = i40e_vsi_add_pvid(vsi, vid);
		ret = i40e_vsi_add_pvid(vsi, vid);
		if (!ret)
		if (!ret)
			dev_info(&pf->pdev->dev,
			dev_info(&pf->pdev->dev,
+66 −5
Original line number Original line Diff line number Diff line
@@ -630,7 +630,7 @@ static int i40e_set_pauseparam(struct net_device *netdev,
	bool link_up = hw_link_info->link_info & I40E_AQ_LINK_UP;
	bool link_up = hw_link_info->link_info & I40E_AQ_LINK_UP;
	i40e_status status;
	i40e_status status;
	u8 aq_failures;
	u8 aq_failures;
	int err;
	int err = 0;


	if (vsi != pf->vsi[pf->lan_vsi])
	if (vsi != pf->vsi[pf->lan_vsi])
		return -EOPNOTSUPP;
		return -EOPNOTSUPP;
@@ -683,8 +683,12 @@ static int i40e_set_pauseparam(struct net_device *netdev,
		err = -EAGAIN;
		err = -EAGAIN;
	}
	}


	if (!test_bit(__I40E_DOWN, &pf->state)) {
		/* Give it a little more time to try to come back */
		msleep(75);
		if (!test_bit(__I40E_DOWN, &pf->state))
		if (!test_bit(__I40E_DOWN, &pf->state))
			return i40e_nway_reset(netdev);
			return i40e_nway_reset(netdev);
	}


	return err;
	return err;
}
}
@@ -759,10 +763,33 @@ static int i40e_get_eeprom(struct net_device *netdev,
	u8 *eeprom_buff;
	u8 *eeprom_buff;
	u16 i, sectors;
	u16 i, sectors;
	bool last;
	bool last;
	u32 magic;

#define I40E_NVM_SECTOR_SIZE  4096
#define I40E_NVM_SECTOR_SIZE  4096
	if (eeprom->len == 0)
	if (eeprom->len == 0)
		return -EINVAL;
		return -EINVAL;


	/* check for NVMUpdate access method */
	magic = hw->vendor_id | (hw->device_id << 16);
	if (eeprom->magic && eeprom->magic != magic) {
		int errno;

		/* make sure it is the right magic for NVMUpdate */
		if ((eeprom->magic >> 16) != hw->device_id)
			return -EINVAL;

		ret_val = i40e_nvmupd_command(hw,
					      (struct i40e_nvm_access *)eeprom,
					      bytes, &errno);
		if (ret_val)
			dev_info(&pf->pdev->dev,
				 "NVMUpdate read failed err=%d status=0x%x\n",
				 ret_val, hw->aq.asq_last_status);

		return errno;
	}

	/* normal ethtool get_eeprom support */
	eeprom->magic = hw->vendor_id | (hw->device_id << 16);
	eeprom->magic = hw->vendor_id | (hw->device_id << 16);


	eeprom_buff = kzalloc(eeprom->len, GFP_KERNEL);
	eeprom_buff = kzalloc(eeprom->len, GFP_KERNEL);
@@ -789,7 +816,7 @@ static int i40e_get_eeprom(struct net_device *netdev,
		ret_val = i40e_aq_read_nvm(hw, 0x0,
		ret_val = i40e_aq_read_nvm(hw, 0x0,
				eeprom->offset + (I40E_NVM_SECTOR_SIZE * i),
				eeprom->offset + (I40E_NVM_SECTOR_SIZE * i),
				len,
				len,
				eeprom_buff + (I40E_NVM_SECTOR_SIZE * i),
				(u8 *)eeprom_buff + (I40E_NVM_SECTOR_SIZE * i),
				last, NULL);
				last, NULL);
		if (ret_val) {
		if (ret_val) {
			dev_info(&pf->pdev->dev,
			dev_info(&pf->pdev->dev,
@@ -801,7 +828,7 @@ static int i40e_get_eeprom(struct net_device *netdev,


release_nvm:
release_nvm:
	i40e_release_nvm(hw);
	i40e_release_nvm(hw);
	memcpy(bytes, eeprom_buff, eeprom->len);
	memcpy(bytes, (u8 *)eeprom_buff, eeprom->len);
free_buff:
free_buff:
	kfree(eeprom_buff);
	kfree(eeprom_buff);
	return ret_val;
	return ret_val;
@@ -821,6 +848,39 @@ static int i40e_get_eeprom_len(struct net_device *netdev)
	return val;
	return val;
}
}


static int i40e_set_eeprom(struct net_device *netdev,
			   struct ethtool_eeprom *eeprom, u8 *bytes)
{
	struct i40e_netdev_priv *np = netdev_priv(netdev);
	struct i40e_hw *hw = &np->vsi->back->hw;
	struct i40e_pf *pf = np->vsi->back;
	int ret_val = 0;
	int errno;
	u32 magic;

	/* normal ethtool set_eeprom is not supported */
	magic = hw->vendor_id | (hw->device_id << 16);
	if (eeprom->magic == magic)
		return -EOPNOTSUPP;

	/* check for NVMUpdate access method */
	if (!eeprom->magic || (eeprom->magic >> 16) != hw->device_id)
		return -EINVAL;

	if (test_bit(__I40E_RESET_RECOVERY_PENDING, &pf->state) ||
	    test_bit(__I40E_RESET_INTR_RECEIVED, &pf->state))
		return -EBUSY;

	ret_val = i40e_nvmupd_command(hw, (struct i40e_nvm_access *)eeprom,
				      bytes, &errno);
	if (ret_val)
		dev_info(&pf->pdev->dev,
			 "NVMUpdate write failed err=%d status=0x%x\n",
			 ret_val, hw->aq.asq_last_status);

	return errno;
}

static void i40e_get_drvinfo(struct net_device *netdev,
static void i40e_get_drvinfo(struct net_device *netdev,
			     struct ethtool_drvinfo *drvinfo)
			     struct ethtool_drvinfo *drvinfo)
{
{
@@ -2094,6 +2154,7 @@ static const struct ethtool_ops i40e_ethtool_ops = {
	.get_link		= ethtool_op_get_link,
	.get_link		= ethtool_op_get_link,
	.get_wol		= i40e_get_wol,
	.get_wol		= i40e_get_wol,
	.set_wol		= i40e_set_wol,
	.set_wol		= i40e_set_wol,
	.set_eeprom		= i40e_set_eeprom,
	.get_eeprom_len		= i40e_get_eeprom_len,
	.get_eeprom_len		= i40e_get_eeprom_len,
	.get_eeprom		= i40e_get_eeprom,
	.get_eeprom		= i40e_get_eeprom,
	.get_ringparam		= i40e_get_ringparam,
	.get_ringparam		= i40e_get_ringparam,
Loading