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

Commit 8f58332b authored by Don Skidmore's avatar Don Skidmore Committed by Jeff Kirsher
Browse files

ixgbe: add support for quad-port x520 adapter



This is a x520 based quad-port (4x10Gbps) NIC with a single QSFP+
connector.  Changes were required to our identify functions due to
different eeprom address which is also included here.

Signed-off-by: default avatarDon Skidmore <donald.c.skidmore@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
parent 674c18b2
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -1331,7 +1331,7 @@ static struct ixgbe_eeprom_operations eeprom_ops_82598 = {

static struct ixgbe_phy_operations phy_ops_82598 = {
	.identify		= &ixgbe_identify_phy_generic,
	.identify_sfp		= &ixgbe_identify_sfp_module_generic,
	.identify_sfp		= &ixgbe_identify_module_generic,
	.init			= &ixgbe_init_phy_ops_82598,
	.reset			= &ixgbe_reset_phy_generic,
	.read_reg		= &ixgbe_read_phy_reg_generic,
+145 −2
Original line number Diff line number Diff line
@@ -58,6 +58,10 @@ static s32 ixgbe_setup_copper_link_82599(struct ixgbe_hw *hw,
                                         ixgbe_link_speed speed,
                                         bool autoneg_wait_to_complete);
static s32 ixgbe_verify_fw_version_82599(struct ixgbe_hw *hw);
static s32 ixgbe_read_i2c_byte_82599(struct ixgbe_hw *hw, u8 byte_offset,
				     u8 dev_addr, u8 *data);
static s32 ixgbe_write_i2c_byte_82599(struct ixgbe_hw *hw, u8 byte_offset,
				      u8 dev_addr, u8 data);

static bool ixgbe_mng_enabled(struct ixgbe_hw *hw)
{
@@ -219,6 +223,25 @@ static s32 ixgbe_init_phy_ops_82599(struct ixgbe_hw *hw)
	struct ixgbe_mac_info *mac = &hw->mac;
	struct ixgbe_phy_info *phy = &hw->phy;
	s32 ret_val = 0;
	u32 esdp;

	if (hw->device_id == IXGBE_DEV_ID_82599_QSFP_SF_QP) {
		/* Store flag indicating I2C bus access control unit. */
		hw->phy.qsfp_shared_i2c_bus = true;

		/* Initialize access to QSFP+ I2C bus */
		esdp = IXGBE_READ_REG(hw, IXGBE_ESDP);
		esdp |= IXGBE_ESDP_SDP0_DIR;
		esdp &= ~IXGBE_ESDP_SDP1_DIR;
		esdp &= ~IXGBE_ESDP_SDP0;
		esdp &= ~IXGBE_ESDP_SDP0_NATIVE;
		esdp &= ~IXGBE_ESDP_SDP1_NATIVE;
		IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp);
		IXGBE_WRITE_FLUSH(hw);

		phy->ops.read_i2c_byte = &ixgbe_read_i2c_byte_82599;
		phy->ops.write_i2c_byte = &ixgbe_write_i2c_byte_82599;
	}

	/* Identify the PHY or SFP module */
	ret_val = phy->ops.identify(hw);
@@ -397,6 +420,9 @@ static enum ixgbe_media_type ixgbe_get_media_type_82599(struct ixgbe_hw *hw)
	case IXGBE_DEV_ID_82599_LS:
		media_type = ixgbe_media_type_fiber_lco;
		break;
	case IXGBE_DEV_ID_82599_QSFP_SF_QP:
		media_type = ixgbe_media_type_fiber_qsfp;
		break;
	default:
		media_type = ixgbe_media_type_unknown;
		break;
@@ -1951,7 +1977,7 @@ static s32 ixgbe_identify_phy_82599(struct ixgbe_hw *hw)
		if (hw->mac.ops.get_media_type(hw) == ixgbe_media_type_copper)
			goto out;
		else
			status = ixgbe_identify_sfp_module_generic(hw);
			status = ixgbe_identify_module_generic(hw);
	}

	/* Set PHY type none if no PHY detected */
@@ -2057,10 +2083,12 @@ sfp_check:
	switch (hw->phy.type) {
	case ixgbe_phy_sfp_passive_tyco:
	case ixgbe_phy_sfp_passive_unknown:
	case ixgbe_phy_qsfp_passive_unknown:
		physical_layer = IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU;
		break;
	case ixgbe_phy_sfp_ftl_active:
	case ixgbe_phy_sfp_active_unknown:
	case ixgbe_phy_qsfp_active_unknown:
		physical_layer = IXGBE_PHYSICAL_LAYER_SFP_ACTIVE_DA;
		break;
	case ixgbe_phy_sfp_avago:
@@ -2078,6 +2106,15 @@ sfp_check:
		else if (comp_codes_1g & IXGBE_SFF_1GBASET_CAPABLE)
			physical_layer = IXGBE_PHYSICAL_LAYER_1000BASE_T;
		break;
	case ixgbe_phy_qsfp_intel:
	case ixgbe_phy_qsfp_unknown:
		hw->phy.ops.read_i2c_eeprom(hw,
			IXGBE_SFF_QSFP_10GBE_COMP, &comp_codes_10g);
		if (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE)
			physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_SR;
		else if (comp_codes_10g & IXGBE_SFF_10GBASELR_CAPABLE)
			physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_LR;
		break;
	default:
		break;
	}
@@ -2315,6 +2352,112 @@ reset_pipeline_out:
	return ret_val;
}

/**
 *  ixgbe_read_i2c_byte_82599 - Reads 8 bit word over I2C
 *  @hw: pointer to hardware structure
 *  @byte_offset: byte offset to read
 *  @data: value read
 *
 *  Performs byte read operation to SFP module's EEPROM over I2C interface at
 *  a specified device address.
 **/
static s32 ixgbe_read_i2c_byte_82599(struct ixgbe_hw *hw, u8 byte_offset,
				     u8 dev_addr, u8 *data)
{
	u32 esdp;
	s32 status;
	s32 timeout = 200;

	if (hw->phy.qsfp_shared_i2c_bus == true) {
		/* Acquire I2C bus ownership. */
		esdp = IXGBE_READ_REG(hw, IXGBE_ESDP);
		esdp |= IXGBE_ESDP_SDP0;
		IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp);
		IXGBE_WRITE_FLUSH(hw);

		while (timeout) {
			esdp = IXGBE_READ_REG(hw, IXGBE_ESDP);
			if (esdp & IXGBE_ESDP_SDP1)
				break;

			usleep_range(5000, 10000);
			timeout--;
		}

		if (!timeout) {
			hw_dbg(hw, "Driver can't access resource, acquiring I2C bus timeout.\n");
			status = IXGBE_ERR_I2C;
			goto release_i2c_access;
		}
	}

	status = ixgbe_read_i2c_byte_generic(hw, byte_offset, dev_addr, data);

release_i2c_access:
	if (hw->phy.qsfp_shared_i2c_bus == true) {
		/* Release I2C bus ownership. */
		esdp = IXGBE_READ_REG(hw, IXGBE_ESDP);
		esdp &= ~IXGBE_ESDP_SDP0;
		IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp);
		IXGBE_WRITE_FLUSH(hw);
	}

	return status;
}

/**
 *  ixgbe_write_i2c_byte_82599 - Writes 8 bit word over I2C
 *  @hw: pointer to hardware structure
 *  @byte_offset: byte offset to write
 *  @data: value to write
 *
 *  Performs byte write operation to SFP module's EEPROM over I2C interface at
 *  a specified device address.
 **/
static s32 ixgbe_write_i2c_byte_82599(struct ixgbe_hw *hw, u8 byte_offset,
				      u8 dev_addr, u8 data)
{
	u32 esdp;
	s32 status;
	s32 timeout = 200;

	if (hw->phy.qsfp_shared_i2c_bus == true) {
		/* Acquire I2C bus ownership. */
		esdp = IXGBE_READ_REG(hw, IXGBE_ESDP);
		esdp |= IXGBE_ESDP_SDP0;
		IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp);
		IXGBE_WRITE_FLUSH(hw);

		while (timeout) {
			esdp = IXGBE_READ_REG(hw, IXGBE_ESDP);
			if (esdp & IXGBE_ESDP_SDP1)
				break;

			usleep_range(5000, 10000);
			timeout--;
		}

		if (!timeout) {
			hw_dbg(hw, "Driver can't access resource, acquiring I2C bus timeout.\n");
			status = IXGBE_ERR_I2C;
			goto release_i2c_access;
		}
	}

	status = ixgbe_write_i2c_byte_generic(hw, byte_offset, dev_addr, data);

release_i2c_access:
	if (hw->phy.qsfp_shared_i2c_bus == true) {
		/* Release I2C bus ownership. */
		esdp = IXGBE_READ_REG(hw, IXGBE_ESDP);
		esdp &= ~IXGBE_ESDP_SDP0;
		IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp);
		IXGBE_WRITE_FLUSH(hw);
	}

	return status;
}

static struct ixgbe_mac_operations mac_ops_82599 = {
	.init_hw                = &ixgbe_init_hw_generic,
	.reset_hw               = &ixgbe_reset_hw_82599,
@@ -2379,7 +2522,7 @@ static struct ixgbe_eeprom_operations eeprom_ops_82599 = {

static struct ixgbe_phy_operations phy_ops_82599 = {
	.identify		= &ixgbe_identify_phy_82599,
	.identify_sfp		= &ixgbe_identify_sfp_module_generic,
	.identify_sfp		= &ixgbe_identify_module_generic,
	.init			= &ixgbe_init_phy_ops_82599,
	.reset			= &ixgbe_reset_phy_generic,
	.read_reg		= &ixgbe_read_phy_reg_generic,
+3 −0
Original line number Diff line number Diff line
@@ -109,6 +109,7 @@ static DEFINE_PCI_DEVICE_TABLE(ixgbe_pci_tbl) = {
	{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X540T), board_X540 },
	{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_SFP_SF2), board_82599 },
	{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_LS), board_82599 },
	{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_QSFP_SF_QP), board_82599 },
	{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599EN_SFP), board_82599 },
	{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_SFP_SF_QP), board_82599 },
	{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X540T1), board_X540 },
@@ -208,6 +209,7 @@ static inline bool ixgbe_pcie_from_parent(struct ixgbe_hw *hw)
{
	switch (hw->device_id) {
	case IXGBE_DEV_ID_82599_SFP_SF_QP:
	case IXGBE_DEV_ID_82599_QSFP_SF_QP:
		return true;
	default:
		return false;
@@ -7347,6 +7349,7 @@ static inline int ixgbe_enumerate_functions(struct ixgbe_adapter *adapter)
	 */
	switch (hw->device_id) {
	case IXGBE_DEV_ID_82599_SFP_SF_QP:
	case IXGBE_DEV_ID_82599_QSFP_SF_QP:
		physfns = 4;
		break;
	default:
+177 −1
Original line number Diff line number Diff line
@@ -840,6 +840,32 @@ out:
	return ret_val;
}

/**
 *  ixgbe_identify_module_generic - Identifies module type
 *  @hw: pointer to hardware structure
 *
 *  Determines HW type and calls appropriate function.
 **/
s32 ixgbe_identify_module_generic(struct ixgbe_hw *hw)
{
	s32 status = IXGBE_ERR_SFP_NOT_PRESENT;

	switch (hw->mac.ops.get_media_type(hw)) {
	case ixgbe_media_type_fiber:
		status = ixgbe_identify_sfp_module_generic(hw);
		break;
	case ixgbe_media_type_fiber_qsfp:
		status = ixgbe_identify_qsfp_module_generic(hw);
		break;
	default:
		hw->phy.sfp_type = ixgbe_sfp_type_not_present;
		status = IXGBE_ERR_SFP_NOT_PRESENT;
		break;
	}

	return status;
}

/**
 *  ixgbe_identify_sfp_module_generic - Identifies SFP modules
 *  @hw: pointer to hardware structure
@@ -1121,6 +1147,156 @@ err_read_i2c_eeprom:
	return IXGBE_ERR_SFP_NOT_PRESENT;
}

/**
 * ixgbe_identify_qsfp_module_generic - Identifies QSFP modules
 * @hw: pointer to hardware structure
 *
 * Searches for and identifies the QSFP module and assigns appropriate PHY type
 **/
s32 ixgbe_identify_qsfp_module_generic(struct ixgbe_hw *hw)
{
	struct ixgbe_adapter *adapter = hw->back;
	s32 status = IXGBE_ERR_PHY_ADDR_INVALID;
	u32 vendor_oui = 0;
	enum ixgbe_sfp_type stored_sfp_type = hw->phy.sfp_type;
	u8 identifier = 0;
	u8 comp_codes_1g = 0;
	u8 comp_codes_10g = 0;
	u8 oui_bytes[3] = {0, 0, 0};
	u16 enforce_sfp = 0;

	if (hw->mac.ops.get_media_type(hw) != ixgbe_media_type_fiber_qsfp) {
		hw->phy.sfp_type = ixgbe_sfp_type_not_present;
		status = IXGBE_ERR_SFP_NOT_PRESENT;
		goto out;
	}

	status = hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_IDENTIFIER,
					     &identifier);

	if (status != 0)
		goto err_read_i2c_eeprom;

	if (identifier != IXGBE_SFF_IDENTIFIER_QSFP_PLUS) {
		hw->phy.type = ixgbe_phy_sfp_unsupported;
		status = IXGBE_ERR_SFP_NOT_SUPPORTED;
		goto out;
	}

	hw->phy.id = identifier;

	/* LAN ID is needed for sfp_type determination */
	hw->mac.ops.set_lan_id(hw);

	status = hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_QSFP_10GBE_COMP,
					     &comp_codes_10g);

	if (status != 0)
		goto err_read_i2c_eeprom;

	if (comp_codes_10g & IXGBE_SFF_QSFP_DA_PASSIVE_CABLE) {
		hw->phy.type = ixgbe_phy_qsfp_passive_unknown;
		if (hw->bus.lan_id == 0)
			hw->phy.sfp_type = ixgbe_sfp_type_da_cu_core0;
		else
			hw->phy.sfp_type = ixgbe_sfp_type_da_cu_core1;
	} else if (comp_codes_10g & IXGBE_SFF_QSFP_DA_ACTIVE_CABLE) {
		hw->phy.type = ixgbe_phy_qsfp_active_unknown;
		if (hw->bus.lan_id == 0)
			hw->phy.sfp_type = ixgbe_sfp_type_da_act_lmt_core0;
		else
			hw->phy.sfp_type = ixgbe_sfp_type_da_act_lmt_core1;
	} else if (comp_codes_10g & (IXGBE_SFF_10GBASESR_CAPABLE |
				     IXGBE_SFF_10GBASELR_CAPABLE)) {
		if (hw->bus.lan_id == 0)
			hw->phy.sfp_type = ixgbe_sfp_type_srlr_core0;
		else
			hw->phy.sfp_type = ixgbe_sfp_type_srlr_core1;
	} else {
		/* unsupported module type */
		hw->phy.type = ixgbe_phy_sfp_unsupported;
		status = IXGBE_ERR_SFP_NOT_SUPPORTED;
		goto out;
	}

	if (hw->phy.sfp_type != stored_sfp_type)
		hw->phy.sfp_setup_needed = true;

	/* Determine if the QSFP+ PHY is dual speed or not. */
	hw->phy.multispeed_fiber = false;
	if (((comp_codes_1g & IXGBE_SFF_1GBASESX_CAPABLE) &&
	     (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE)) ||
	    ((comp_codes_1g & IXGBE_SFF_1GBASELX_CAPABLE) &&
	     (comp_codes_10g & IXGBE_SFF_10GBASELR_CAPABLE)))
		hw->phy.multispeed_fiber = true;

	/* Determine PHY vendor for optical modules */
	if (comp_codes_10g & (IXGBE_SFF_10GBASESR_CAPABLE |
			      IXGBE_SFF_10GBASELR_CAPABLE)) {
		status = hw->phy.ops.read_i2c_eeprom(hw,
					IXGBE_SFF_QSFP_VENDOR_OUI_BYTE0,
					&oui_bytes[0]);

		if (status != 0)
			goto err_read_i2c_eeprom;

		status = hw->phy.ops.read_i2c_eeprom(hw,
					IXGBE_SFF_QSFP_VENDOR_OUI_BYTE1,
					&oui_bytes[1]);

		if (status != 0)
			goto err_read_i2c_eeprom;

		status = hw->phy.ops.read_i2c_eeprom(hw,
					IXGBE_SFF_QSFP_VENDOR_OUI_BYTE2,
					&oui_bytes[2]);

		if (status != 0)
			goto err_read_i2c_eeprom;

		vendor_oui =
			((oui_bytes[0] << IXGBE_SFF_VENDOR_OUI_BYTE0_SHIFT) |
			 (oui_bytes[1] << IXGBE_SFF_VENDOR_OUI_BYTE1_SHIFT) |
			 (oui_bytes[2] << IXGBE_SFF_VENDOR_OUI_BYTE2_SHIFT));

		if (vendor_oui == IXGBE_SFF_VENDOR_OUI_INTEL)
			hw->phy.type = ixgbe_phy_qsfp_intel;
		else
			hw->phy.type = ixgbe_phy_qsfp_unknown;

		hw->mac.ops.get_device_caps(hw, &enforce_sfp);
		if (!(enforce_sfp & IXGBE_DEVICE_CAPS_ALLOW_ANY_SFP)) {
			/* Make sure we're a supported PHY type */
			if (hw->phy.type == ixgbe_phy_qsfp_intel) {
				status = 0;
			} else {
				if (hw->allow_unsupported_sfp == true) {
					e_warn(hw, "WARNING: Intel (R) Network Connections are quality tested using Intel (R) Ethernet Optics. Using untested modules is not supported and may cause unstable operation or damage to the module or the adapter. Intel Corporation is not responsible for any harm caused by using untested modules.\n");
					status = 0;
				} else {
					hw_dbg(hw,
					       "QSFP module not supported\n");
					hw->phy.type =
						ixgbe_phy_sfp_unsupported;
					status = IXGBE_ERR_SFP_NOT_SUPPORTED;
				}
			}
		} else {
			status = 0;
		}
	}

out:
	return status;

err_read_i2c_eeprom:
	hw->phy.sfp_type = ixgbe_sfp_type_not_present;
	hw->phy.id = 0;
	hw->phy.type = ixgbe_phy_unknown;

	return IXGBE_ERR_SFP_NOT_PRESENT;
}

/**
 *  ixgbe_get_sfp_init_sequence_offsets - Provides offset of PHY init sequence
 *  @hw: pointer to hardware structure
+23 −13
Original line number Diff line number Diff line
@@ -46,6 +46,12 @@
#define IXGBE_SFF_SFF_8472_COMP		0x5E
#define IXGBE_SFF_SFF_8472_OSCB		0x6E
#define IXGBE_SFF_SFF_8472_ESCB		0x76
#define IXGBE_SFF_IDENTIFIER_QSFP_PLUS	0xD
#define IXGBE_SFF_QSFP_VENDOR_OUI_BYTE0	0xA5
#define IXGBE_SFF_QSFP_VENDOR_OUI_BYTE1	0xA6
#define IXGBE_SFF_QSFP_VENDOR_OUI_BYTE2	0xA7
#define IXGBE_SFF_QSFP_10GBE_COMP	0x83
#define IXGBE_SFF_QSFP_1GBE_COMP	0x86

/* Bitmasks */
#define IXGBE_SFF_DA_PASSIVE_CABLE           0x4
@@ -60,6 +66,8 @@
#define IXGBE_SFF_SOFT_RS_SELECT_10G	0x8
#define IXGBE_SFF_SOFT_RS_SELECT_1G	0x0
#define IXGBE_SFF_ADDRESSING_MODE	     0x4
#define IXGBE_SFF_QSFP_DA_ACTIVE_CABLE       0x1
#define IXGBE_SFF_QSFP_DA_PASSIVE_CABLE      0x8
#define IXGBE_I2C_EEPROM_READ_MASK           0x100
#define IXGBE_I2C_EEPROM_STATUS_MASK         0x3
#define IXGBE_I2C_EEPROM_STATUS_NO_OPERATION 0x0
@@ -130,7 +138,9 @@ s32 ixgbe_get_phy_firmware_version_generic(struct ixgbe_hw *hw,
                                           u16 *firmware_version);

s32 ixgbe_reset_phy_nl(struct ixgbe_hw *hw);
s32 ixgbe_identify_module_generic(struct ixgbe_hw *hw);
s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw);
s32 ixgbe_identify_qsfp_module_generic(struct ixgbe_hw *hw);
s32 ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw,
                                        u16 *list_offset,
                                        u16 *data_offset);
Loading