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

Commit a4b6fc6b authored by Emil Tantilov's avatar Emil Tantilov Committed by Jeff Kirsher
Browse files

ixgbe: fix SFF data dumps of SFP+ modules



This patch fixes several issues with the previous implementation of the
SFF data dump of SFP+ modules:

- removed the __IXGBE_READ_I2C flag - I2C access locking is handled in the
  HW specific routines

- fixed the read loop to read data from ee->offset to ee->len

- the reads fail if __IXGBE_IN_SFP_INIT is set in the process - this is
  needed because on some HW I2C operations can take long time and disrupt
  the SFP and link detection process

Signed-off-by: default avatarEmil Tantilov <emil.s.tantilov@intel.com>
Reported-by: default avatarBen Hutchings <bhutchings@solarflare.com>
Tested-by: default avatarPhil Schmitt <phillip.j.schmitt@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
parent 3dcc2f41
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -754,7 +754,6 @@ enum ixgbe_state_t {
	__IXGBE_DOWN,
	__IXGBE_SERVICE_SCHED,
	__IXGBE_IN_SFP_INIT,
	__IXGBE_READ_I2C,
};

struct ixgbe_cb {
+18 −55
Original line number Diff line number Diff line
@@ -2910,33 +2910,21 @@ static int ixgbe_get_module_info(struct net_device *dev,
	struct ixgbe_hw *hw = &adapter->hw;
	u32 status;
	u8 sff8472_rev, addr_mode;
	int ret_val = 0;
	bool page_swap = false;

	/* avoid concurent i2c reads */
	while (test_bit(__IXGBE_IN_SFP_INIT, &adapter->state))
		msleep(100);

	/* used by the service task */
	set_bit(__IXGBE_READ_I2C, &adapter->state);

	/* Check whether we support SFF-8472 or not */
	status = hw->phy.ops.read_i2c_eeprom(hw,
					     IXGBE_SFF_SFF_8472_COMP,
					     &sff8472_rev);
	if (status != 0) {
		ret_val = -EIO;
		goto err_out;
	}
	if (status != 0)
		return -EIO;

	/* addressing mode is not supported */
	status = hw->phy.ops.read_i2c_eeprom(hw,
					     IXGBE_SFF_SFF_8472_SWAP,
					     &addr_mode);
	if (status != 0) {
		ret_val = -EIO;
		goto err_out;
	}
	if (status != 0)
		return -EIO;

	if (addr_mode & IXGBE_SFF_ADDRESSING_MODE) {
		e_err(drv, "Address change required to access page 0xA2, but not supported. Please report the module type to the driver maintainers.\n");
@@ -2953,9 +2941,7 @@ static int ixgbe_get_module_info(struct net_device *dev,
		modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
	}

err_out:
	clear_bit(__IXGBE_READ_I2C, &adapter->state);
	return ret_val;
	return 0;
}

static int ixgbe_get_module_eeprom(struct net_device *dev,
@@ -2969,47 +2955,24 @@ static int ixgbe_get_module_eeprom(struct net_device *dev,
	int i = 0;
	int ret_val = 0;

	/* ixgbe_get_module_info is called before this function in all
	 * cases, so we do not need any checks we already do above,
	 * and can trust ee->len to be a known value.
	 */
	if (ee->len == 0)
		return -EINVAL;

	while (test_bit(__IXGBE_IN_SFP_INIT, &adapter->state))
		msleep(100);
	set_bit(__IXGBE_READ_I2C, &adapter->state);
	for (i = ee->offset; i < ee->len; i++) {
		/* I2C reads can take long time */
		if (test_bit(__IXGBE_IN_SFP_INIT, &adapter->state))
			return -EBUSY;

	/* Read the first block, SFF-8079 */
	for (i = 0; i < ETH_MODULE_SFF_8079_LEN; i++) {
		if (i < ETH_MODULE_SFF_8079_LEN)
			status  = hw->phy.ops.read_i2c_eeprom(hw, i, &databyte);
		if (status != 0) {
			/* Error occured while reading module */
			ret_val = -EIO;
			goto err_out;
		}
		data[i] = databyte;
	}

	/* If the second block is requested, check if SFF-8472 is supported. */
	if (ee->len == ETH_MODULE_SFF_8472_LEN) {
		if (data[IXGBE_SFF_SFF_8472_COMP] == IXGBE_SFF_SFF_8472_UNSUP)
			return -EOPNOTSUPP;
		else
			status = hw->phy.ops.read_i2c_sff8472(hw, i, &databyte);

		/* Read the second block, SFF-8472 */
		for (i = ETH_MODULE_SFF_8079_LEN;
		     i < ETH_MODULE_SFF_8472_LEN; i++) {
			status = hw->phy.ops.read_i2c_sff8472(hw,
				i - ETH_MODULE_SFF_8079_LEN, &databyte);
			if (status != 0) {
				/* Error occured while reading module */
		if (status != 0)
			ret_val = -EIO;
				goto err_out;
			}
			data[i] = databyte;
		}
	}

err_out:
	clear_bit(__IXGBE_READ_I2C, &adapter->state);
		data[i - ee->offset] = databyte;
	}

	return ret_val;
}
+0 −4
Original line number Diff line number Diff line
@@ -5832,10 +5832,6 @@ static void ixgbe_sfp_detection_subtask(struct ixgbe_adapter *adapter)
	    !(adapter->flags2 & IXGBE_FLAG2_SFP_NEEDS_RESET))
		return;

	/* concurent i2c reads are not supported */
	if (test_bit(__IXGBE_READ_I2C, &adapter->state))
		return;

	/* someone else is in init, wait until next service event */
	if (test_and_set_bit(__IXGBE_IN_SFP_INIT, &adapter->state))
		return;