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

Commit 2fbe4526 authored by Bruce Allan's avatar Bruce Allan Committed by Jeff Kirsher
Browse files

e1000e: initial support for i217



i217 is the next-generation LOM that will be available on systems with the
Lynx Point Platform Controller Hub (PCH) chipset from Intel.  This patch
provides the initial support for the device.

Signed-off-by: default avatarBruce Allan <bruce.w.allan@intel.com>
Tested-by: default avatarJeff Pieper <jeffrey.e.pieper@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
parent d02c70a8
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -74,7 +74,9 @@
#define E1000_WUS_BC           E1000_WUFC_BC

/* Extended Device Control */
#define E1000_CTRL_EXT_LPCD  0x00000004     /* LCD Power Cycle Done */
#define E1000_CTRL_EXT_SDP3_DATA 0x00000080 /* Value of SW Definable Pin 3 */
#define E1000_CTRL_EXT_FORCE_SMBUS 0x00000004 /* Force SMBus mode*/
#define E1000_CTRL_EXT_EE_RST    0x00002000 /* Reinitialize from EEPROM */
#define E1000_CTRL_EXT_SPD_BYPS  0x00008000 /* Speed Select Bypass */
#define E1000_CTRL_EXT_RO_DIS    0x00020000 /* Relaxed Ordering disable */
@@ -573,6 +575,7 @@
#define NWAY_AR_ASM_DIR          0x0800   /* Asymmetric Pause Direction bit */

/* Link Partner Ability Register (Base Page) */
#define NWAY_LPAR_100TX_FD_CAPS  0x0100 /* LP 100TX Full Dplx Capable */
#define NWAY_LPAR_PAUSE          0x0400 /* LP Pause operation desired */
#define NWAY_LPAR_ASM_DIR        0x0800 /* LP Asymmetric Pause Direction bit */

@@ -739,6 +742,7 @@
#define I82577_E_PHY_ID      0x01540050
#define I82578_E_PHY_ID      0x004DD040
#define I82579_E_PHY_ID      0x01540090
#define I217_E_PHY_ID        0x015400A0

/* M88E1000 Specific Registers */
#define M88E1000_PHY_SPEC_CTRL     0x10  /* PHY Specific Control Register */
@@ -850,4 +854,8 @@
/* SerDes Control */
#define E1000_GEN_POLL_TIMEOUT          640

/* FW Semaphore */
#define E1000_FWSM_WLOCK_MAC_MASK	0x0380
#define E1000_FWSM_WLOCK_MAC_SHIFT	7

#endif /* _E1000_DEFINES_H_ */
+2 −0
Original line number Diff line number Diff line
@@ -206,6 +206,7 @@ enum e1000_boards {
	board_ich10lan,
	board_pchlan,
	board_pch2lan,
	board_pch_lpt,
};

struct e1000_ps_page {
@@ -528,6 +529,7 @@ extern const struct e1000_info e1000_ich9_info;
extern const struct e1000_info e1000_ich10_info;
extern const struct e1000_info e1000_pch_info;
extern const struct e1000_info e1000_pch2_info;
extern const struct e1000_info e1000_pch_lpt_info;
extern const struct e1000_info e1000_es2_info;

extern s32 e1000_read_pba_string_generic(struct e1000_hw *hw, u8 *pba_num,
+15 −2
Original line number Diff line number Diff line
@@ -773,6 +773,7 @@ static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data)
	u32 i;
	u32 toggle;
	u32 mask;
	u32 wlock_mac = 0;

	/*
	 * The status register is Read Only, so a write should fail.
@@ -838,19 +839,31 @@ static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data)
	case e1000_ich10lan:
	case e1000_pchlan:
	case e1000_pch2lan:
	case e1000_pch_lpt:
		mask |= (1 << 18);
		break;
	default:
		break;
	}
	for (i = 0; i < mac->rar_entry_count; i++)

	if (mac->type == e1000_pch_lpt)
		wlock_mac = (er32(FWSM) & E1000_FWSM_WLOCK_MAC_MASK) >>
		    E1000_FWSM_WLOCK_MAC_SHIFT;

	for (i = 0; i < mac->rar_entry_count; i++) {
		/* Cannot test write-protected SHRAL[n] registers */
		if ((wlock_mac == 1) || (wlock_mac && (i > wlock_mac)))
			continue;

		REG_PATTERN_TEST_ARRAY(E1000_RA, ((i << 1) + 1),
				       mask, 0xFFFFFFFF);
	}

	for (i = 0; i < mac->mta_reg_count; i++)
		REG_PATTERN_TEST_ARRAY(E1000_MTA, i, 0xFFFFFFFF, 0xFFFFFFFF);

	*data = 0;

	return 0;
}

+9 −0
Original line number Diff line number Diff line
@@ -200,6 +200,10 @@ enum e1e_registers {
#define E1000_RA        (E1000_RAL(0))
	E1000_RAH_BASE = 0x05404, /* Receive Address High - RW */
#define E1000_RAH(_n)   (E1000_RAH_BASE + ((_n) * 8))
	E1000_SHRAL_PCH_LPT_BASE = 0x05408,
#define E1000_SHRAL_PCH_LPT(_n)   (E1000_SHRAL_PCH_LPT_BASE + ((_n) * 8))
	E1000_SHRAH_PCH_LTP_BASE = 0x0540C,
#define E1000_SHRAH_PCH_LPT(_n)   (E1000_SHRAH_PCH_LTP_BASE + ((_n) * 8))
	E1000_SHRAL_BASE = 0x05438, /* Shared Receive Address Low - RW */
#define E1000_SHRAL(_n)   (E1000_SHRAL_BASE + ((_n) * 8))
	E1000_SHRAH_BASE = 0x0543C, /* Shared Receive Address High - RW */
@@ -406,6 +410,8 @@ enum e1e_registers {
#define E1000_DEV_ID_PCH_D_HV_DC		0x10F0
#define E1000_DEV_ID_PCH2_LV_LM			0x1502
#define E1000_DEV_ID_PCH2_LV_V			0x1503
#define E1000_DEV_ID_PCH_LPT_I217_LM		0x153A
#define E1000_DEV_ID_PCH_LPT_I217_V		0x153B

#define E1000_REVISION_4 4

@@ -426,6 +432,7 @@ enum e1000_mac_type {
	e1000_ich10lan,
	e1000_pchlan,
	e1000_pch2lan,
	e1000_pch_lpt,
};

enum e1000_media_type {
@@ -463,6 +470,7 @@ enum e1000_phy_type {
	e1000_phy_82578,
	e1000_phy_82577,
	e1000_phy_82579,
	e1000_phy_i217,
};

enum e1000_bus_width {
@@ -971,6 +979,7 @@ struct e1000_dev_spec_ich8lan {
	struct e1000_shadow_ram shadow_ram[E1000_ICH8_SHADOW_RAM_WORDS];
	bool nvm_k1_enabled;
	bool eee_disable;
	u16 eee_lp_ability;
};

struct e1000_hw {
+350 −20
Original line number Diff line number Diff line
@@ -116,6 +116,7 @@

#define E1000_ICH_RAR_ENTRIES		7
#define E1000_PCH2_RAR_ENTRIES		5 /* RAR[0], SHRA[0-3] */
#define E1000_PCH_LPT_RAR_ENTRIES	12 /* RAR[0], SHRA[0-10] */

#define PHY_PAGE_SHIFT 5
#define PHY_REG(page, reg) (((page) << PHY_PAGE_SHIFT) | \
@@ -131,11 +132,18 @@

#define SW_FLAG_TIMEOUT    1000 /* SW Semaphore flag timeout in milliseconds */

/* SMBus Control Phy Register */
#define CV_SMB_CTRL		PHY_REG(769, 23)
#define CV_SMB_CTRL_FORCE_SMBUS	0x0001

/* SMBus Address Phy Register */
#define HV_SMB_ADDR            PHY_REG(768, 26)
#define HV_SMB_ADDR_MASK       0x007F
#define HV_SMB_ADDR_PEC_EN     0x0200
#define HV_SMB_ADDR_VALID      0x0080
#define HV_SMB_ADDR_FREQ_MASK           0x1100
#define HV_SMB_ADDR_FREQ_LOW_SHIFT      8
#define HV_SMB_ADDR_FREQ_HIGH_SHIFT     12

/* PHY Power Management Control */
#define HV_PM_CTRL		PHY_REG(770, 17)
@@ -152,11 +160,26 @@
#define I82579_LPI_UPDATE_TIMER 0x4805	/* in 40ns units + 40 ns base value */
#define I82579_MSE_THRESHOLD    0x084F	/* Mean Square Error Threshold */
#define I82579_MSE_LINK_DOWN    0x2411	/* MSE count before dropping link */
#define I217_EEE_ADVERTISEMENT  0x8001	/* IEEE MMD Register 7.60 */
#define I217_EEE_LP_ABILITY     0x8002	/* IEEE MMD Register 7.61 */
#define I217_EEE_100_SUPPORTED  (1 << 1)	/* 100BaseTx EEE supported */

/* Intel Rapid Start Technology Support */
#define I217_PROXY_CTRL                 PHY_REG(BM_WUC_PAGE, 70)
#define I217_PROXY_CTRL_AUTO_DISABLE    0x0080
#define I217_SxCTRL                     PHY_REG(BM_PORT_CTRL_PAGE, 28)
#define I217_SxCTRL_MASK                0x1000
#define I217_CGFREG                     PHY_REG(772, 29)
#define I217_CGFREG_MASK                0x0002
#define I217_MEMPWR                     PHY_REG(772, 26)
#define I217_MEMPWR_MASK                0x0010

/* Strapping Option Register - RO */
#define E1000_STRAP                     0x0000C
#define E1000_STRAP_SMBUS_ADDRESS_MASK  0x00FE0000
#define E1000_STRAP_SMBUS_ADDRESS_SHIFT 17
#define E1000_STRAP_SMT_FREQ_MASK       0x00003000
#define E1000_STRAP_SMT_FREQ_SHIFT      12

/* OEM Bits Phy Register */
#define HV_OEM_BITS            PHY_REG(768, 25)
@@ -261,6 +284,7 @@ static s32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw);
static bool e1000_check_mng_mode_ich8lan(struct e1000_hw *hw);
static bool e1000_check_mng_mode_pchlan(struct e1000_hw *hw);
static void e1000_rar_set_pch2lan(struct e1000_hw *hw, u8 *addr, u32 index);
static void e1000_rar_set_pch_lpt(struct e1000_hw *hw, u8 *addr, u32 index);
static s32 e1000_k1_workaround_lv(struct e1000_hw *hw);
static void e1000_gate_hw_phy_config_ich8lan(struct e1000_hw *hw, bool gate);

@@ -332,6 +356,7 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw)
{
	u32 mac_reg, fwsm = er32(FWSM);
	s32 ret_val;
	u16 phy_reg;

	ret_val = hw->phy.ops.acquire(hw);
	if (ret_val) {
@@ -345,16 +370,42 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw)
	 * LANPHYPC Value bit to force the interconnect to PCIe mode.
	 */
	switch (hw->mac.type) {
	case e1000_pch_lpt:
		if (e1000_phy_is_accessible_pchlan(hw))
			break;

		/*
		 * Before toggling LANPHYPC, see if PHY is accessible by
		 * forcing MAC to SMBus mode first.
		 */
		mac_reg = er32(CTRL_EXT);
		mac_reg |= E1000_CTRL_EXT_FORCE_SMBUS;
		ew32(CTRL_EXT, mac_reg);

		/* fall-through */
	case e1000_pch2lan:
		/*
		 * Gate automatic PHY configuration by hardware on
		 * non-managed 82579
		 */
		if (!(fwsm & E1000_ICH_FWSM_FW_VALID))
		if ((hw->mac.type == e1000_pch2lan) &&
		    !(fwsm & E1000_ICH_FWSM_FW_VALID))
			e1000_gate_hw_phy_config_ich8lan(hw, true);

		if (e1000_phy_is_accessible_pchlan(hw))
		if (e1000_phy_is_accessible_pchlan(hw)) {
			if (hw->mac.type == e1000_pch_lpt) {
				/* Unforce SMBus mode in PHY */
				e1e_rphy_locked(hw, CV_SMB_CTRL, &phy_reg);
				phy_reg &= ~CV_SMB_CTRL_FORCE_SMBUS;
				e1e_wphy_locked(hw, CV_SMB_CTRL, phy_reg);

				/* Unforce SMBus mode in MAC */
				mac_reg = er32(CTRL_EXT);
				mac_reg &= ~E1000_CTRL_EXT_FORCE_SMBUS;
				ew32(CTRL_EXT, mac_reg);
			}
			break;
		}

		/* fall-through */
	case e1000_pchlan:
@@ -385,7 +436,15 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw)
		mac_reg &= ~E1000_CTRL_LANPHYPC_OVERRIDE;
		ew32(CTRL, mac_reg);
		e1e_flush();
		if (hw->mac.type < e1000_pch_lpt) {
			msleep(50);
		} else {
			u16 count = 20;
			do {
				usleep_range(5000, 10000);
			} while (!(er32(CTRL_EXT) &
				   E1000_CTRL_EXT_LPCD) && count--);
		}
		break;
	default:
		break;
@@ -454,6 +513,7 @@ static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw)
				break;
			/* fall-through */
		case e1000_pch2lan:
		case e1000_pch_lpt:
			/*
			 * In case the PHY needs to be in mdio slow mode,
			 * set slow mode and try to get the PHY id again.
@@ -471,6 +531,7 @@ static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw)
	switch (phy->type) {
	case e1000_phy_82577:
	case e1000_phy_82579:
	case e1000_phy_i217:
		phy->ops.check_polarity = e1000_check_polarity_82577;
		phy->ops.force_speed_duplex =
		    e1000_phy_force_speed_duplex_82577;
@@ -655,7 +716,7 @@ static s32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw)
	/* Adaptive IFS supported */
	mac->adaptive_ifs = true;

	/* LED operations */
	/* LED and other operations */
	switch (mac->type) {
	case e1000_ich8lan:
	case e1000_ich9lan:
@@ -678,6 +739,7 @@ static s32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw)
		mac->rar_entry_count = E1000_PCH2_RAR_ENTRIES;
		mac->ops.rar_set = e1000_rar_set_pch2lan;
		/* fall-through */
	case e1000_pch_lpt:
	case e1000_pchlan:
		/* check management mode */
		mac->ops.check_mng_mode = e1000_check_mng_mode_pchlan;
@@ -695,12 +757,20 @@ static s32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw)
		break;
	}

	if (mac->type == e1000_pch_lpt) {
		mac->rar_entry_count = E1000_PCH_LPT_RAR_ENTRIES;
		mac->ops.rar_set = e1000_rar_set_pch_lpt;
	}

	/* Enable PCS Lock-loss workaround for ICH8 */
	if (mac->type == e1000_ich8lan)
		e1000e_set_kmrn_lock_loss_workaround_ich8lan(hw, true);

	/* Gate automatic PHY configuration by hardware on managed 82579 */
	if ((mac->type == e1000_pch2lan) &&
	/*
	 * Gate automatic PHY configuration by hardware on managed
	 * 82579 and i217
	 */
	if ((mac->type == e1000_pch2lan || mac->type == e1000_pch_lpt) &&
	    (er32(FWSM) & E1000_ICH_FWSM_FW_VALID))
		e1000_gate_hw_phy_config_ich8lan(hw, true);

@@ -716,22 +786,50 @@ static s32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw)
 **/
static s32 e1000_set_eee_pchlan(struct e1000_hw *hw)
{
	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
	s32 ret_val = 0;
	u16 phy_reg;

	if (hw->phy.type != e1000_phy_82579)
	if ((hw->phy.type != e1000_phy_82579) &&
	    (hw->phy.type != e1000_phy_i217))
		return 0;

	ret_val = e1e_rphy(hw, I82579_LPI_CTRL, &phy_reg);
	if (ret_val)
		return ret_val;

	if (hw->dev_spec.ich8lan.eee_disable)
	if (dev_spec->eee_disable)
		phy_reg &= ~I82579_LPI_CTRL_ENABLE_MASK;
	else
		phy_reg |= I82579_LPI_CTRL_ENABLE_MASK;

	return e1e_wphy(hw, I82579_LPI_CTRL, phy_reg);
	ret_val = e1e_wphy(hw, I82579_LPI_CTRL, phy_reg);
	if (ret_val)
		return ret_val;

	if ((hw->phy.type == e1000_phy_i217) && !dev_spec->eee_disable) {
		/* Save off link partner's EEE ability */
		ret_val = hw->phy.ops.acquire(hw);
		if (ret_val)
			return ret_val;
		ret_val = e1e_wphy_locked(hw, I82579_EMI_ADDR,
					  I217_EEE_LP_ABILITY);
		if (ret_val)
			goto release;
		e1e_rphy_locked(hw, I82579_EMI_DATA, &dev_spec->eee_lp_ability);

		/*
		 * EEE is not supported in 100Half, so ignore partner's EEE
		 * in 100 ability if full-duplex is not advertised.
		 */
		e1e_rphy_locked(hw, PHY_LP_ABILITY, &phy_reg);
		if (!(phy_reg & NWAY_LPAR_100TX_FD_CAPS))
			dev_spec->eee_lp_ability &= ~I217_EEE_100_SUPPORTED;
release:
		hw->phy.ops.release(hw);
	}

	return 0;
}

/**
@@ -773,6 +871,9 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
			return ret_val;
	}

	/* Clear link partner's EEE ability */
	hw->dev_spec.ich8lan.eee_lp_ability = 0;

	if (!link)
		return 0; /* No link detected */

@@ -868,6 +969,7 @@ static s32 e1000_get_variants_ich8lan(struct e1000_adapter *adapter)
		break;
	case e1000_pchlan:
	case e1000_pch2lan:
	case e1000_pch_lpt:
		rc = e1000_init_phy_params_pchlan(hw);
		break;
	default:
@@ -1116,6 +1218,81 @@ out:
	e_dbg("Failed to write receive address at index %d\n", index);
}

/**
 *  e1000_rar_set_pch_lpt - Set receive address registers
 *  @hw: pointer to the HW structure
 *  @addr: pointer to the receive address
 *  @index: receive address array register
 *
 *  Sets the receive address register array at index to the address passed
 *  in by addr. For LPT, RAR[0] is the base address register that is to
 *  contain the MAC address. SHRA[0-10] are the shared receive address
 *  registers that are shared between the Host and manageability engine (ME).
 **/
static void e1000_rar_set_pch_lpt(struct e1000_hw *hw, u8 *addr, u32 index)
{
	u32 rar_low, rar_high;
	u32 wlock_mac;

	/*
	 * HW expects these in little endian so we reverse the byte order
	 * from network order (big endian) to little endian
	 */
	rar_low = ((u32)addr[0] | ((u32)addr[1] << 8) |
		   ((u32)addr[2] << 16) | ((u32)addr[3] << 24));

	rar_high = ((u32)addr[4] | ((u32)addr[5] << 8));

	/* If MAC address zero, no need to set the AV bit */
	if (rar_low || rar_high)
		rar_high |= E1000_RAH_AV;

	if (index == 0) {
		ew32(RAL(index), rar_low);
		e1e_flush();
		ew32(RAH(index), rar_high);
		e1e_flush();
		return;
	}

	/*
	 * The manageability engine (ME) can lock certain SHRAR registers that
	 * it is using - those registers are unavailable for use.
	 */
	if (index < hw->mac.rar_entry_count) {
		wlock_mac = er32(FWSM) & E1000_FWSM_WLOCK_MAC_MASK;
		wlock_mac >>= E1000_FWSM_WLOCK_MAC_SHIFT;

		/* Check if all SHRAR registers are locked */
		if (wlock_mac == 1)
			goto out;

		if ((wlock_mac == 0) || (index <= wlock_mac)) {
			s32 ret_val;

			ret_val = e1000_acquire_swflag_ich8lan(hw);

			if (ret_val)
				goto out;

			ew32(SHRAL_PCH_LPT(index - 1), rar_low);
			e1e_flush();
			ew32(SHRAH_PCH_LPT(index - 1), rar_high);
			e1e_flush();

			e1000_release_swflag_ich8lan(hw);

			/* verify the register updates */
			if ((er32(SHRAL_PCH_LPT(index - 1)) == rar_low) &&
			    (er32(SHRAH_PCH_LPT(index - 1)) == rar_high))
				return;
		}
	}

out:
	e_dbg("Failed to write receive address at index %d\n", index);
}

/**
 *  e1000_check_reset_block_ich8lan - Check if PHY reset is blocked
 *  @hw: pointer to the HW structure
@@ -1144,6 +1321,8 @@ static s32 e1000_write_smbus_addr(struct e1000_hw *hw)
{
	u16 phy_data;
	u32 strap = er32(STRAP);
	u32 freq = (strap & E1000_STRAP_SMT_FREQ_MASK) >>
	    E1000_STRAP_SMT_FREQ_SHIFT;
	s32 ret_val = 0;

	strap &= E1000_STRAP_SMBUS_ADDRESS_MASK;
@@ -1156,6 +1335,19 @@ static s32 e1000_write_smbus_addr(struct e1000_hw *hw)
	phy_data |= (strap >> E1000_STRAP_SMBUS_ADDRESS_SHIFT);
	phy_data |= HV_SMB_ADDR_PEC_EN | HV_SMB_ADDR_VALID;

	if (hw->phy.type == e1000_phy_i217) {
		/* Restore SMBus frequency */
		if (freq--) {
			phy_data &= ~HV_SMB_ADDR_FREQ_MASK;
			phy_data |= (freq & (1 << 0)) <<
			    HV_SMB_ADDR_FREQ_LOW_SHIFT;
			phy_data |= (freq & (1 << 1)) <<
			    (HV_SMB_ADDR_FREQ_HIGH_SHIFT - 1);
		} else {
			e_dbg("Unsupported SMB frequency in PHY\n");
		}
	}

	return e1000_write_phy_reg_hv_locked(hw, HV_SMB_ADDR, phy_data);
}

@@ -1193,6 +1385,7 @@ static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw)
		/* Fall-thru */
	case e1000_pchlan:
	case e1000_pch2lan:
	case e1000_pch_lpt:
		sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG_ICH8M;
		break;
	default:
@@ -1212,10 +1405,9 @@ static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw)
	 * extended configuration before SW configuration
	 */
	data = er32(EXTCNF_CTRL);
	if (!(hw->mac.type == e1000_pch2lan)) {
		if (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE)
	if ((hw->mac.type < e1000_pch2lan) &&
	    (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE))
		goto release;
	}

	cnf_size = er32(EXTCNF_SIZE);
	cnf_size &= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK;
@@ -1226,9 +1418,9 @@ static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw)
	cnf_base_addr = data & E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK;
	cnf_base_addr >>= E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT;

	if ((!(data & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE) &&
	    (hw->mac.type == e1000_pchlan)) ||
	     (hw->mac.type == e1000_pch2lan)) {
	if (((hw->mac.type == e1000_pchlan) &&
	     !(data & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE)) ||
	    (hw->mac.type > e1000_pchlan)) {
		/*
		 * HW configures the SMBus address and LEDs when the
		 * OEM and LCD Write Enable bits are set in the NVM.
@@ -1425,14 +1617,14 @@ static s32 e1000_oem_bits_config_ich8lan(struct e1000_hw *hw, bool d0_state)
	u32 mac_reg;
	u16 oem_reg;

	if ((hw->mac.type != e1000_pch2lan) && (hw->mac.type != e1000_pchlan))
	if (hw->mac.type < e1000_pchlan)
		return ret_val;

	ret_val = hw->phy.ops.acquire(hw);
	if (ret_val)
		return ret_val;

	if (!(hw->mac.type == e1000_pch2lan)) {
	if (hw->mac.type == e1000_pchlan) {
		mac_reg = er32(EXTCNF_CTRL);
		if (mac_reg & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE)
			goto release;
@@ -1629,7 +1821,7 @@ s32 e1000_lv_jumbo_workaround_ich8lan(struct e1000_hw *hw, bool enable)
	u32 mac_reg;
	u16 i;

	if (hw->mac.type != e1000_pch2lan)
	if (hw->mac.type < e1000_pch2lan)
		return 0;

	/* disable Rx path while enabling/disabling workaround */
@@ -1886,7 +2078,7 @@ static void e1000_gate_hw_phy_config_ich8lan(struct e1000_hw *hw, bool gate)
{
	u32 extcnf_ctrl;

	if (hw->mac.type != e1000_pch2lan)
	if (hw->mac.type < e1000_pch2lan)
		return;

	extcnf_ctrl = er32(EXTCNF_CTRL);
@@ -3525,6 +3717,7 @@ static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw)
	ew32(FCTTV, hw->fc.pause_time);
	if ((hw->phy.type == e1000_phy_82578) ||
	    (hw->phy.type == e1000_phy_82579) ||
	    (hw->phy.type == e1000_phy_i217) ||
	    (hw->phy.type == e1000_phy_82577)) {
		ew32(FCRTV_PCH, hw->fc.refresh_time);

@@ -3588,6 +3781,7 @@ static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw)
		break;
	case e1000_phy_82577:
	case e1000_phy_82579:
	case e1000_phy_i217:
		ret_val = e1000_copper_link_setup_82577(hw);
		if (ret_val)
			return ret_val;
@@ -3834,14 +4028,88 @@ void e1000e_gig_downshift_workaround_ich8lan(struct e1000_hw *hw)
 *  the LPLU setting in the NVM or custom setting.  For PCH and newer parts,
 *  the OEM bits PHY register (LED, GbE disable and LPLU configurations) also
 *  needs to be written.
 *  Parts that support (and are linked to a partner which support) EEE in
 *  100Mbps should disable LPLU since 100Mbps w/ EEE requires less power
 *  than 10Mbps w/o EEE.
 **/
void e1000_suspend_workarounds_ich8lan(struct e1000_hw *hw)
{
	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
	u32 phy_ctrl;
	s32 ret_val;

	phy_ctrl = er32(PHY_CTRL);
	phy_ctrl |= E1000_PHY_CTRL_GBE_DISABLE;
	if (hw->phy.type == e1000_phy_i217) {
		u16 phy_reg;

		ret_val = hw->phy.ops.acquire(hw);
		if (ret_val)
			goto out;

		if (!dev_spec->eee_disable) {
			u16 eee_advert;

			ret_val = e1e_wphy_locked(hw, I82579_EMI_ADDR,
						  I217_EEE_ADVERTISEMENT);
			if (ret_val)
				goto release;
			e1e_rphy_locked(hw, I82579_EMI_DATA, &eee_advert);

			/*
			 * Disable LPLU if both link partners support 100BaseT
			 * EEE and 100Full is advertised on both ends of the
			 * link.
			 */
			if ((eee_advert & I217_EEE_100_SUPPORTED) &&
			    (dev_spec->eee_lp_ability &
			     I217_EEE_100_SUPPORTED) &&
			    (hw->phy.autoneg_advertised & ADVERTISE_100_FULL))
				phy_ctrl &= ~(E1000_PHY_CTRL_D0A_LPLU |
					      E1000_PHY_CTRL_NOND0A_LPLU);
		}

		/*
		 * For i217 Intel Rapid Start Technology support,
		 * when the system is going into Sx and no manageability engine
		 * is present, the driver must configure proxy to reset only on
		 * power good.  LPI (Low Power Idle) state must also reset only
		 * on power good, as well as the MTA (Multicast table array).
		 * The SMBus release must also be disabled on LCD reset.
		 */
		if (!(er32(FWSM) & E1000_ICH_FWSM_FW_VALID)) {

			/* Enable proxy to reset only on power good. */
			e1e_rphy_locked(hw, I217_PROXY_CTRL, &phy_reg);
			phy_reg |= I217_PROXY_CTRL_AUTO_DISABLE;
			e1e_wphy_locked(hw, I217_PROXY_CTRL, phy_reg);

			/*
			 * Set bit enable LPI (EEE) to reset only on
			 * power good.
			 */
			e1e_rphy_locked(hw, I217_SxCTRL, &phy_reg);
			phy_reg |= I217_SxCTRL_MASK;
			e1e_wphy_locked(hw, I217_SxCTRL, phy_reg);

			/* Disable the SMB release on LCD reset. */
			e1e_rphy_locked(hw, I217_MEMPWR, &phy_reg);
			phy_reg &= ~I217_MEMPWR;
			e1e_wphy_locked(hw, I217_MEMPWR, phy_reg);
		}

		/*
		 * Enable MTA to reset for Intel Rapid Start Technology
		 * Support
		 */
		e1e_rphy_locked(hw, I217_CGFREG, &phy_reg);
		phy_reg |= I217_CGFREG_MASK;
		e1e_wphy_locked(hw, I217_CGFREG, phy_reg);

release:
		hw->phy.ops.release(hw);
	}
out:
	ew32(PHY_CTRL, phy_ctrl);

	if (hw->mac.type == e1000_ich8lan)
@@ -3870,6 +4138,7 @@ void e1000_suspend_workarounds_ich8lan(struct e1000_hw *hw)
 *  on which PHY resets are not blocked, if the PHY registers cannot be
 *  accessed properly by the s/w toggle the LANPHYPC value to power cycle
 *  the PHY.
 *  On i217, setup Intel Rapid Start Technology.
 **/
void e1000_resume_workarounds_pchlan(struct e1000_hw *hw)
{
@@ -3883,6 +4152,47 @@ void e1000_resume_workarounds_pchlan(struct e1000_hw *hw)
		e_dbg("Failed to init PHY flow ret_val=%d\n", ret_val);
		return;
	}

	/*
	 * For i217 Intel Rapid Start Technology support when the system
	 * is transitioning from Sx and no manageability engine is present
	 * configure SMBus to restore on reset, disable proxy, and enable
	 * the reset on MTA (Multicast table array).
	 */
	if (hw->phy.type == e1000_phy_i217) {
		u16 phy_reg;

		ret_val = hw->phy.ops.acquire(hw);
		if (ret_val) {
			e_dbg("Failed to setup iRST\n");
			return;
		}

		if (!(er32(FWSM) & E1000_ICH_FWSM_FW_VALID)) {
			/*
			 * Restore clear on SMB if no manageability engine
			 * is present
			 */
			ret_val = e1e_rphy_locked(hw, I217_MEMPWR, &phy_reg);
			if (ret_val)
				goto release;
			phy_reg |= I217_MEMPWR_MASK;
			e1e_wphy_locked(hw, I217_MEMPWR, phy_reg);

			/* Disable Proxy */
			e1e_wphy_locked(hw, I217_PROXY_CTRL, 0);
		}
		/* Enable reset on MTA */
		ret_val = e1e_rphy_locked(hw, I217_CGFREG, &phy_reg);
		if (ret_val)
			goto release;
		phy_reg &= ~I217_CGFREG_MASK;
		e1e_wphy_locked(hw, I217_CGFREG, phy_reg);
release:
		if (ret_val)
			e_dbg("Error %d in resume workarounds\n", ret_val);
		hw->phy.ops.release(hw);
	}
}

/**
@@ -4123,6 +4433,7 @@ static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw)
	/* Clear PHY statistics registers */
	if ((hw->phy.type == e1000_phy_82578) ||
	    (hw->phy.type == e1000_phy_82579) ||
	    (hw->phy.type == e1000_phy_i217) ||
	    (hw->phy.type == e1000_phy_82577)) {
		ret_val = hw->phy.ops.acquire(hw);
		if (ret_val)
@@ -4282,3 +4593,22 @@ const struct e1000_info e1000_pch2_info = {
	.phy_ops		= &ich8_phy_ops,
	.nvm_ops		= &ich8_nvm_ops,
};

const struct e1000_info e1000_pch_lpt_info = {
	.mac			= e1000_pch_lpt,
	.flags			= FLAG_IS_ICH
				  | FLAG_HAS_WOL
				  | FLAG_HAS_CTRLEXT_ON_LOAD
				  | FLAG_HAS_AMT
				  | FLAG_HAS_FLASH
				  | FLAG_HAS_JUMBO_FRAMES
				  | FLAG_APME_IN_WUC,
	.flags2			= FLAG2_HAS_PHY_STATS
				  | FLAG2_HAS_EEE,
	.pba			= 26,
	.max_hw_frame_size	= DEFAULT_JUMBO,
	.get_variants		= e1000_get_variants_ich8lan,
	.mac_ops		= &ich8_mac_ops,
	.phy_ops		= &ich8_phy_ops,
	.nvm_ops		= &ich8_nvm_ops,
};
Loading