|
@@ -123,6 +123,14 @@ static s32 e1000_read_flash_word_ich8lan(struct e1000_hw *hw, u32 offset,
|
|
|
u16 *data);
|
|
|
static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
|
|
|
u8 size, u16 *data);
|
|
|
+static s32 e1000_read_flash_data32_ich8lan(struct e1000_hw *hw, u32 offset,
|
|
|
+ u32 *data);
|
|
|
+static s32 e1000_read_flash_dword_ich8lan(struct e1000_hw *hw,
|
|
|
+ u32 offset, u32 *data);
|
|
|
+static s32 e1000_write_flash_data32_ich8lan(struct e1000_hw *hw,
|
|
|
+ u32 offset, u32 data);
|
|
|
+static s32 e1000_retry_write_flash_dword_ich8lan(struct e1000_hw *hw,
|
|
|
+ u32 offset, u32 dword);
|
|
|
static s32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw);
|
|
|
static s32 e1000_cleanup_led_ich8lan(struct e1000_hw *hw);
|
|
|
static s32 e1000_led_on_ich8lan(struct e1000_hw *hw);
|
|
@@ -229,7 +237,8 @@ static bool e1000_phy_is_accessible_pchlan(struct e1000_hw *hw)
|
|
|
if (ret_val)
|
|
|
return false;
|
|
|
out:
|
|
|
- if (hw->mac.type == e1000_pch_lpt) {
|
|
|
+ if ((hw->mac.type == e1000_pch_lpt) ||
|
|
|
+ (hw->mac.type == e1000_pch_spt)) {
|
|
|
/* Unforce SMBus mode in PHY */
|
|
|
e1e_rphy_locked(hw, CV_SMB_CTRL, &phy_reg);
|
|
|
phy_reg &= ~CV_SMB_CTRL_FORCE_SMBUS;
|
|
@@ -321,6 +330,7 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw)
|
|
|
*/
|
|
|
switch (hw->mac.type) {
|
|
|
case e1000_pch_lpt:
|
|
|
+ case e1000_pch_spt:
|
|
|
if (e1000_phy_is_accessible_pchlan(hw))
|
|
|
break;
|
|
|
|
|
@@ -461,6 +471,7 @@ static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw)
|
|
|
/* fall-through */
|
|
|
case e1000_pch2lan:
|
|
|
case e1000_pch_lpt:
|
|
|
+ case e1000_pch_spt:
|
|
|
/* In case the PHY needs to be in mdio slow mode,
|
|
|
* set slow mode and try to get the PHY id again.
|
|
|
*/
|
|
@@ -590,35 +601,50 @@ static s32 e1000_init_nvm_params_ich8lan(struct e1000_hw *hw)
|
|
|
struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
|
|
|
u32 gfpreg, sector_base_addr, sector_end_addr;
|
|
|
u16 i;
|
|
|
+ u32 nvm_size;
|
|
|
|
|
|
/* Can't read flash registers if the register set isn't mapped. */
|
|
|
- if (!hw->flash_address) {
|
|
|
- e_dbg("ERROR: Flash registers not mapped\n");
|
|
|
- return -E1000_ERR_CONFIG;
|
|
|
- }
|
|
|
-
|
|
|
nvm->type = e1000_nvm_flash_sw;
|
|
|
+ /* in SPT, gfpreg doesn't exist. NVM size is taken from the
|
|
|
+ * STRAP register
|
|
|
+ */
|
|
|
+ if (hw->mac.type == e1000_pch_spt) {
|
|
|
+ nvm->flash_base_addr = 0;
|
|
|
+ nvm_size = (((er32(STRAP) >> 1) & 0x1F) + 1)
|
|
|
+ * NVM_SIZE_MULTIPLIER;
|
|
|
+ nvm->flash_bank_size = nvm_size / 2;
|
|
|
+ /* Adjust to word count */
|
|
|
+ nvm->flash_bank_size /= sizeof(u16);
|
|
|
+ /* Set the base address for flash register access */
|
|
|
+ hw->flash_address = hw->hw_addr + E1000_FLASH_BASE_ADDR;
|
|
|
+ } else {
|
|
|
+ if (!hw->flash_address) {
|
|
|
+ e_dbg("ERROR: Flash registers not mapped\n");
|
|
|
+ return -E1000_ERR_CONFIG;
|
|
|
+ }
|
|
|
|
|
|
- gfpreg = er32flash(ICH_FLASH_GFPREG);
|
|
|
+ gfpreg = er32flash(ICH_FLASH_GFPREG);
|
|
|
|
|
|
- /* sector_X_addr is a "sector"-aligned address (4096 bytes)
|
|
|
- * Add 1 to sector_end_addr since this sector is included in
|
|
|
- * the overall size.
|
|
|
- */
|
|
|
- sector_base_addr = gfpreg & FLASH_GFPREG_BASE_MASK;
|
|
|
- sector_end_addr = ((gfpreg >> 16) & FLASH_GFPREG_BASE_MASK) + 1;
|
|
|
+ /* sector_X_addr is a "sector"-aligned address (4096 bytes)
|
|
|
+ * Add 1 to sector_end_addr since this sector is included in
|
|
|
+ * the overall size.
|
|
|
+ */
|
|
|
+ sector_base_addr = gfpreg & FLASH_GFPREG_BASE_MASK;
|
|
|
+ sector_end_addr = ((gfpreg >> 16) & FLASH_GFPREG_BASE_MASK) + 1;
|
|
|
|
|
|
- /* flash_base_addr is byte-aligned */
|
|
|
- nvm->flash_base_addr = sector_base_addr << FLASH_SECTOR_ADDR_SHIFT;
|
|
|
+ /* flash_base_addr is byte-aligned */
|
|
|
+ nvm->flash_base_addr = sector_base_addr
|
|
|
+ << FLASH_SECTOR_ADDR_SHIFT;
|
|
|
|
|
|
- /* find total size of the NVM, then cut in half since the total
|
|
|
- * size represents two separate NVM banks.
|
|
|
- */
|
|
|
- nvm->flash_bank_size = ((sector_end_addr - sector_base_addr)
|
|
|
- << FLASH_SECTOR_ADDR_SHIFT);
|
|
|
- nvm->flash_bank_size /= 2;
|
|
|
- /* Adjust to word count */
|
|
|
- nvm->flash_bank_size /= sizeof(u16);
|
|
|
+ /* find total size of the NVM, then cut in half since the total
|
|
|
+ * size represents two separate NVM banks.
|
|
|
+ */
|
|
|
+ nvm->flash_bank_size = ((sector_end_addr - sector_base_addr)
|
|
|
+ << FLASH_SECTOR_ADDR_SHIFT);
|
|
|
+ nvm->flash_bank_size /= 2;
|
|
|
+ /* Adjust to word count */
|
|
|
+ nvm->flash_bank_size /= sizeof(u16);
|
|
|
+ }
|
|
|
|
|
|
nvm->word_size = E1000_ICH8_SHADOW_RAM_WORDS;
|
|
|
|
|
@@ -682,6 +708,7 @@ static s32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw)
|
|
|
mac->ops.rar_set = e1000_rar_set_pch2lan;
|
|
|
/* fall-through */
|
|
|
case e1000_pch_lpt:
|
|
|
+ case e1000_pch_spt:
|
|
|
case e1000_pchlan:
|
|
|
/* check management mode */
|
|
|
mac->ops.check_mng_mode = e1000_check_mng_mode_pchlan;
|
|
@@ -699,7 +726,7 @@ static s32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw)
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
- if (mac->type == e1000_pch_lpt) {
|
|
|
+ if ((mac->type == e1000_pch_lpt) || (mac->type == e1000_pch_spt)) {
|
|
|
mac->rar_entry_count = E1000_PCH_LPT_RAR_ENTRIES;
|
|
|
mac->ops.rar_set = e1000_rar_set_pch_lpt;
|
|
|
mac->ops.setup_physical_interface =
|
|
@@ -919,8 +946,9 @@ release:
|
|
|
/* clear FEXTNVM6 bit 8 on link down or 10/100 */
|
|
|
fextnvm6 &= ~E1000_FEXTNVM6_REQ_PLL_CLK;
|
|
|
|
|
|
- if (!link || ((status & E1000_STATUS_SPEED_100) &&
|
|
|
- (status & E1000_STATUS_FD)))
|
|
|
+ if ((hw->phy.revision > 5) || !link ||
|
|
|
+ ((status & E1000_STATUS_SPEED_100) &&
|
|
|
+ (status & E1000_STATUS_FD)))
|
|
|
goto update_fextnvm6;
|
|
|
|
|
|
ret_val = e1e_rphy(hw, I217_INBAND_CTRL, ®);
|
|
@@ -1100,6 +1128,21 @@ s32 e1000_enable_ulp_lpt_lp(struct e1000_hw *hw, bool to_sx)
|
|
|
if (ret_val)
|
|
|
goto out;
|
|
|
|
|
|
+ /* Si workaround for ULP entry flow on i127/rev6 h/w. Enable
|
|
|
+ * LPLU and disable Gig speed when entering ULP
|
|
|
+ */
|
|
|
+ if ((hw->phy.type == e1000_phy_i217) && (hw->phy.revision == 6)) {
|
|
|
+ ret_val = e1000_read_phy_reg_hv_locked(hw, HV_OEM_BITS,
|
|
|
+ &phy_reg);
|
|
|
+ if (ret_val)
|
|
|
+ goto release;
|
|
|
+ phy_reg |= HV_OEM_BITS_LPLU | HV_OEM_BITS_GBE_DIS;
|
|
|
+ ret_val = e1000_write_phy_reg_hv_locked(hw, HV_OEM_BITS,
|
|
|
+ phy_reg);
|
|
|
+ if (ret_val)
|
|
|
+ goto release;
|
|
|
+ }
|
|
|
+
|
|
|
/* Force SMBus mode in PHY */
|
|
|
ret_val = e1000_read_phy_reg_hv_locked(hw, CV_SMB_CTRL, &phy_reg);
|
|
|
if (ret_val)
|
|
@@ -1302,7 +1345,8 @@ out:
|
|
|
static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
|
|
|
{
|
|
|
struct e1000_mac_info *mac = &hw->mac;
|
|
|
- s32 ret_val;
|
|
|
+ s32 ret_val, tipg_reg = 0;
|
|
|
+ u16 emi_addr, emi_val = 0;
|
|
|
bool link;
|
|
|
u16 phy_reg;
|
|
|
|
|
@@ -1333,48 +1377,55 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
|
|
|
* the IPG and reduce Rx latency in the PHY.
|
|
|
*/
|
|
|
if (((hw->mac.type == e1000_pch2lan) ||
|
|
|
- (hw->mac.type == e1000_pch_lpt)) && link) {
|
|
|
+ (hw->mac.type == e1000_pch_lpt) ||
|
|
|
+ (hw->mac.type == e1000_pch_spt)) && link) {
|
|
|
u32 reg;
|
|
|
|
|
|
reg = er32(STATUS);
|
|
|
+ tipg_reg = er32(TIPG);
|
|
|
+ tipg_reg &= ~E1000_TIPG_IPGT_MASK;
|
|
|
+
|
|
|
if (!(reg & (E1000_STATUS_FD | E1000_STATUS_SPEED_MASK))) {
|
|
|
- u16 emi_addr;
|
|
|
+ tipg_reg |= 0xFF;
|
|
|
+ /* Reduce Rx latency in analog PHY */
|
|
|
+ emi_val = 0;
|
|
|
+ } else {
|
|
|
|
|
|
- reg = er32(TIPG);
|
|
|
- reg &= ~E1000_TIPG_IPGT_MASK;
|
|
|
- reg |= 0xFF;
|
|
|
- ew32(TIPG, reg);
|
|
|
+ /* Roll back the default values */
|
|
|
+ tipg_reg |= 0x08;
|
|
|
+ emi_val = 1;
|
|
|
+ }
|
|
|
|
|
|
- /* Reduce Rx latency in analog PHY */
|
|
|
- ret_val = hw->phy.ops.acquire(hw);
|
|
|
- if (ret_val)
|
|
|
- return ret_val;
|
|
|
+ ew32(TIPG, tipg_reg);
|
|
|
|
|
|
- if (hw->mac.type == e1000_pch2lan)
|
|
|
- emi_addr = I82579_RX_CONFIG;
|
|
|
- else
|
|
|
- emi_addr = I217_RX_CONFIG;
|
|
|
+ ret_val = hw->phy.ops.acquire(hw);
|
|
|
+ if (ret_val)
|
|
|
+ return ret_val;
|
|
|
|
|
|
- ret_val = e1000_write_emi_reg_locked(hw, emi_addr, 0);
|
|
|
+ if (hw->mac.type == e1000_pch2lan)
|
|
|
+ emi_addr = I82579_RX_CONFIG;
|
|
|
+ else
|
|
|
+ emi_addr = I217_RX_CONFIG;
|
|
|
+ ret_val = e1000_write_emi_reg_locked(hw, emi_addr, emi_val);
|
|
|
|
|
|
- hw->phy.ops.release(hw);
|
|
|
+ hw->phy.ops.release(hw);
|
|
|
|
|
|
- if (ret_val)
|
|
|
- return ret_val;
|
|
|
- }
|
|
|
+ if (ret_val)
|
|
|
+ return ret_val;
|
|
|
}
|
|
|
|
|
|
/* Work-around I218 hang issue */
|
|
|
if ((hw->adapter->pdev->device == E1000_DEV_ID_PCH_LPTLP_I218_LM) ||
|
|
|
(hw->adapter->pdev->device == E1000_DEV_ID_PCH_LPTLP_I218_V) ||
|
|
|
(hw->adapter->pdev->device == E1000_DEV_ID_PCH_I218_LM3) ||
|
|
|
- (hw->adapter->pdev->device == E1000_DEV_ID_PCH_I218_V3)) {
|
|
|
+ (hw->adapter->pdev->device == E1000_DEV_ID_PCH_I218_V3) ||
|
|
|
+ (hw->mac.type == e1000_pch_spt)) {
|
|
|
ret_val = e1000_k1_workaround_lpt_lp(hw, link);
|
|
|
if (ret_val)
|
|
|
return ret_val;
|
|
|
}
|
|
|
-
|
|
|
- if (hw->mac.type == e1000_pch_lpt) {
|
|
|
+ if ((hw->mac.type == e1000_pch_lpt) ||
|
|
|
+ (hw->mac.type == e1000_pch_spt)) {
|
|
|
/* Set platform power management values for
|
|
|
* Latency Tolerance Reporting (LTR)
|
|
|
*/
|
|
@@ -1386,6 +1437,19 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
|
|
|
/* Clear link partner's EEE ability */
|
|
|
hw->dev_spec.ich8lan.eee_lp_ability = 0;
|
|
|
|
|
|
+ /* FEXTNVM6 K1-off workaround */
|
|
|
+ if (hw->mac.type == e1000_pch_spt) {
|
|
|
+ u32 pcieanacfg = er32(PCIEANACFG);
|
|
|
+ u32 fextnvm6 = er32(FEXTNVM6);
|
|
|
+
|
|
|
+ if (pcieanacfg & E1000_FEXTNVM6_K1_OFF_ENABLE)
|
|
|
+ fextnvm6 |= E1000_FEXTNVM6_K1_OFF_ENABLE;
|
|
|
+ else
|
|
|
+ fextnvm6 &= ~E1000_FEXTNVM6_K1_OFF_ENABLE;
|
|
|
+
|
|
|
+ ew32(FEXTNVM6, fextnvm6);
|
|
|
+ }
|
|
|
+
|
|
|
if (!link)
|
|
|
return 0; /* No link detected */
|
|
|
|
|
@@ -1479,6 +1543,7 @@ static s32 e1000_get_variants_ich8lan(struct e1000_adapter *adapter)
|
|
|
case e1000_pchlan:
|
|
|
case e1000_pch2lan:
|
|
|
case e1000_pch_lpt:
|
|
|
+ case e1000_pch_spt:
|
|
|
rc = e1000_init_phy_params_pchlan(hw);
|
|
|
break;
|
|
|
default:
|
|
@@ -1929,6 +1994,7 @@ static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw)
|
|
|
case e1000_pchlan:
|
|
|
case e1000_pch2lan:
|
|
|
case e1000_pch_lpt:
|
|
|
+ case e1000_pch_spt:
|
|
|
sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG_ICH8M;
|
|
|
break;
|
|
|
default:
|
|
@@ -2961,6 +3027,20 @@ static s32 e1000_valid_nvm_bank_detect_ich8lan(struct e1000_hw *hw, u32 *bank)
|
|
|
s32 ret_val;
|
|
|
|
|
|
switch (hw->mac.type) {
|
|
|
+ /* In SPT, read from the CTRL_EXT reg instead of
|
|
|
+ * accessing the sector valid bits from the nvm
|
|
|
+ */
|
|
|
+ case e1000_pch_spt:
|
|
|
+ *bank = er32(CTRL_EXT)
|
|
|
+ & E1000_CTRL_EXT_NVMVS;
|
|
|
+ if ((*bank == 0) || (*bank == 1)) {
|
|
|
+ e_dbg("ERROR: No valid NVM bank present\n");
|
|
|
+ return -E1000_ERR_NVM;
|
|
|
+ } else {
|
|
|
+ *bank = *bank - 2;
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ break;
|
|
|
case e1000_ich8lan:
|
|
|
case e1000_ich9lan:
|
|
|
eecd = er32(EECD);
|
|
@@ -3007,6 +3087,99 @@ static s32 e1000_valid_nvm_bank_detect_ich8lan(struct e1000_hw *hw, u32 *bank)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * e1000_read_nvm_spt - NVM access for SPT
|
|
|
+ * @hw: pointer to the HW structure
|
|
|
+ * @offset: The offset (in bytes) of the word(s) to read.
|
|
|
+ * @words: Size of data to read in words.
|
|
|
+ * @data: pointer to the word(s) to read at offset.
|
|
|
+ *
|
|
|
+ * Reads a word(s) from the NVM
|
|
|
+ **/
|
|
|
+static s32 e1000_read_nvm_spt(struct e1000_hw *hw, u16 offset, u16 words,
|
|
|
+ u16 *data)
|
|
|
+{
|
|
|
+ struct e1000_nvm_info *nvm = &hw->nvm;
|
|
|
+ struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
|
|
|
+ u32 act_offset;
|
|
|
+ s32 ret_val = 0;
|
|
|
+ u32 bank = 0;
|
|
|
+ u32 dword = 0;
|
|
|
+ u16 offset_to_read;
|
|
|
+ u16 i;
|
|
|
+
|
|
|
+ if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) ||
|
|
|
+ (words == 0)) {
|
|
|
+ e_dbg("nvm parameter(s) out of bounds\n");
|
|
|
+ ret_val = -E1000_ERR_NVM;
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ nvm->ops.acquire(hw);
|
|
|
+
|
|
|
+ ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank);
|
|
|
+ if (ret_val) {
|
|
|
+ e_dbg("Could not detect valid bank, assuming bank 0\n");
|
|
|
+ bank = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ act_offset = (bank) ? nvm->flash_bank_size : 0;
|
|
|
+ act_offset += offset;
|
|
|
+
|
|
|
+ ret_val = 0;
|
|
|
+
|
|
|
+ for (i = 0; i < words; i += 2) {
|
|
|
+ if (words - i == 1) {
|
|
|
+ if (dev_spec->shadow_ram[offset + i].modified) {
|
|
|
+ data[i] =
|
|
|
+ dev_spec->shadow_ram[offset + i].value;
|
|
|
+ } else {
|
|
|
+ offset_to_read = act_offset + i -
|
|
|
+ ((act_offset + i) % 2);
|
|
|
+ ret_val =
|
|
|
+ e1000_read_flash_dword_ich8lan(hw,
|
|
|
+ offset_to_read,
|
|
|
+ &dword);
|
|
|
+ if (ret_val)
|
|
|
+ break;
|
|
|
+ if ((act_offset + i) % 2 == 0)
|
|
|
+ data[i] = (u16)(dword & 0xFFFF);
|
|
|
+ else
|
|
|
+ data[i] = (u16)((dword >> 16) & 0xFFFF);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ offset_to_read = act_offset + i;
|
|
|
+ if (!(dev_spec->shadow_ram[offset + i].modified) ||
|
|
|
+ !(dev_spec->shadow_ram[offset + i + 1].modified)) {
|
|
|
+ ret_val =
|
|
|
+ e1000_read_flash_dword_ich8lan(hw,
|
|
|
+ offset_to_read,
|
|
|
+ &dword);
|
|
|
+ if (ret_val)
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ if (dev_spec->shadow_ram[offset + i].modified)
|
|
|
+ data[i] =
|
|
|
+ dev_spec->shadow_ram[offset + i].value;
|
|
|
+ else
|
|
|
+ data[i] = (u16)(dword & 0xFFFF);
|
|
|
+ if (dev_spec->shadow_ram[offset + i].modified)
|
|
|
+ data[i + 1] =
|
|
|
+ dev_spec->shadow_ram[offset + i + 1].value;
|
|
|
+ else
|
|
|
+ data[i + 1] = (u16)(dword >> 16 & 0xFFFF);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ nvm->ops.release(hw);
|
|
|
+
|
|
|
+out:
|
|
|
+ if (ret_val)
|
|
|
+ e_dbg("NVM read error: %d\n", ret_val);
|
|
|
+
|
|
|
+ return ret_val;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* e1000_read_nvm_ich8lan - Read word(s) from the NVM
|
|
|
* @hw: pointer to the HW structure
|
|
@@ -3090,8 +3263,10 @@ static s32 e1000_flash_cycle_init_ich8lan(struct e1000_hw *hw)
|
|
|
/* Clear FCERR and DAEL in hw status by writing 1 */
|
|
|
hsfsts.hsf_status.flcerr = 1;
|
|
|
hsfsts.hsf_status.dael = 1;
|
|
|
-
|
|
|
- ew16flash(ICH_FLASH_HSFSTS, hsfsts.regval);
|
|
|
+ if (hw->mac.type == e1000_pch_spt)
|
|
|
+ ew32flash(ICH_FLASH_HSFSTS, hsfsts.regval & 0xFFFF);
|
|
|
+ else
|
|
|
+ ew16flash(ICH_FLASH_HSFSTS, hsfsts.regval);
|
|
|
|
|
|
/* Either we should have a hardware SPI cycle in progress
|
|
|
* bit to check against, in order to start a new cycle or
|
|
@@ -3107,7 +3282,10 @@ static s32 e1000_flash_cycle_init_ich8lan(struct e1000_hw *hw)
|
|
|
* Begin by setting Flash Cycle Done.
|
|
|
*/
|
|
|
hsfsts.hsf_status.flcdone = 1;
|
|
|
- ew16flash(ICH_FLASH_HSFSTS, hsfsts.regval);
|
|
|
+ if (hw->mac.type == e1000_pch_spt)
|
|
|
+ ew32flash(ICH_FLASH_HSFSTS, hsfsts.regval & 0xFFFF);
|
|
|
+ else
|
|
|
+ ew16flash(ICH_FLASH_HSFSTS, hsfsts.regval);
|
|
|
ret_val = 0;
|
|
|
} else {
|
|
|
s32 i;
|
|
@@ -3128,7 +3306,11 @@ static s32 e1000_flash_cycle_init_ich8lan(struct e1000_hw *hw)
|
|
|
* now set the Flash Cycle Done.
|
|
|
*/
|
|
|
hsfsts.hsf_status.flcdone = 1;
|
|
|
- ew16flash(ICH_FLASH_HSFSTS, hsfsts.regval);
|
|
|
+ if (hw->mac.type == e1000_pch_spt)
|
|
|
+ ew32flash(ICH_FLASH_HSFSTS,
|
|
|
+ hsfsts.regval & 0xFFFF);
|
|
|
+ else
|
|
|
+ ew16flash(ICH_FLASH_HSFSTS, hsfsts.regval);
|
|
|
} else {
|
|
|
e_dbg("Flash controller busy, cannot get access\n");
|
|
|
}
|
|
@@ -3151,9 +3333,16 @@ static s32 e1000_flash_cycle_ich8lan(struct e1000_hw *hw, u32 timeout)
|
|
|
u32 i = 0;
|
|
|
|
|
|
/* Start a cycle by writing 1 in Flash Cycle Go in Hw Flash Control */
|
|
|
- hsflctl.regval = er16flash(ICH_FLASH_HSFCTL);
|
|
|
+ if (hw->mac.type == e1000_pch_spt)
|
|
|
+ hsflctl.regval = er32flash(ICH_FLASH_HSFSTS) >> 16;
|
|
|
+ else
|
|
|
+ hsflctl.regval = er16flash(ICH_FLASH_HSFCTL);
|
|
|
hsflctl.hsf_ctrl.flcgo = 1;
|
|
|
- ew16flash(ICH_FLASH_HSFCTL, hsflctl.regval);
|
|
|
+
|
|
|
+ if (hw->mac.type == e1000_pch_spt)
|
|
|
+ ew32flash(ICH_FLASH_HSFSTS, hsflctl.regval << 16);
|
|
|
+ else
|
|
|
+ ew16flash(ICH_FLASH_HSFCTL, hsflctl.regval);
|
|
|
|
|
|
/* wait till FDONE bit is set to 1 */
|
|
|
do {
|
|
@@ -3169,6 +3358,23 @@ static s32 e1000_flash_cycle_ich8lan(struct e1000_hw *hw, u32 timeout)
|
|
|
return -E1000_ERR_NVM;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * e1000_read_flash_dword_ich8lan - Read dword from flash
|
|
|
+ * @hw: pointer to the HW structure
|
|
|
+ * @offset: offset to data location
|
|
|
+ * @data: pointer to the location for storing the data
|
|
|
+ *
|
|
|
+ * Reads the flash dword at offset into data. Offset is converted
|
|
|
+ * to bytes before read.
|
|
|
+ **/
|
|
|
+static s32 e1000_read_flash_dword_ich8lan(struct e1000_hw *hw, u32 offset,
|
|
|
+ u32 *data)
|
|
|
+{
|
|
|
+ /* Must convert word offset into bytes. */
|
|
|
+ offset <<= 1;
|
|
|
+ return e1000_read_flash_data32_ich8lan(hw, offset, data);
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* e1000_read_flash_word_ich8lan - Read word from flash
|
|
|
* @hw: pointer to the HW structure
|
|
@@ -3201,7 +3407,14 @@ static s32 e1000_read_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset,
|
|
|
s32 ret_val;
|
|
|
u16 word = 0;
|
|
|
|
|
|
- ret_val = e1000_read_flash_data_ich8lan(hw, offset, 1, &word);
|
|
|
+ /* In SPT, only 32 bits access is supported,
|
|
|
+ * so this function should not be called.
|
|
|
+ */
|
|
|
+ if (hw->mac.type == e1000_pch_spt)
|
|
|
+ return -E1000_ERR_NVM;
|
|
|
+ else
|
|
|
+ ret_val = e1000_read_flash_data_ich8lan(hw, offset, 1, &word);
|
|
|
+
|
|
|
if (ret_val)
|
|
|
return ret_val;
|
|
|
|
|
@@ -3286,6 +3499,82 @@ static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
|
|
|
return ret_val;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * e1000_read_flash_data32_ich8lan - Read dword from NVM
|
|
|
+ * @hw: pointer to the HW structure
|
|
|
+ * @offset: The offset (in bytes) of the dword to read.
|
|
|
+ * @data: Pointer to the dword to store the value read.
|
|
|
+ *
|
|
|
+ * Reads a byte or word from the NVM using the flash access registers.
|
|
|
+ **/
|
|
|
+
|
|
|
+static s32 e1000_read_flash_data32_ich8lan(struct e1000_hw *hw, u32 offset,
|
|
|
+ u32 *data)
|
|
|
+{
|
|
|
+ union ich8_hws_flash_status hsfsts;
|
|
|
+ union ich8_hws_flash_ctrl hsflctl;
|
|
|
+ u32 flash_linear_addr;
|
|
|
+ s32 ret_val = -E1000_ERR_NVM;
|
|
|
+ u8 count = 0;
|
|
|
+
|
|
|
+ if (offset > ICH_FLASH_LINEAR_ADDR_MASK ||
|
|
|
+ hw->mac.type != e1000_pch_spt)
|
|
|
+ return -E1000_ERR_NVM;
|
|
|
+ flash_linear_addr = ((ICH_FLASH_LINEAR_ADDR_MASK & offset) +
|
|
|
+ hw->nvm.flash_base_addr);
|
|
|
+
|
|
|
+ do {
|
|
|
+ udelay(1);
|
|
|
+ /* Steps */
|
|
|
+ ret_val = e1000_flash_cycle_init_ich8lan(hw);
|
|
|
+ if (ret_val)
|
|
|
+ break;
|
|
|
+ /* In SPT, This register is in Lan memory space, not flash.
|
|
|
+ * Therefore, only 32 bit access is supported
|
|
|
+ */
|
|
|
+ hsflctl.regval = er32flash(ICH_FLASH_HSFSTS) >> 16;
|
|
|
+
|
|
|
+ /* 0b/1b corresponds to 1 or 2 byte size, respectively. */
|
|
|
+ hsflctl.hsf_ctrl.fldbcount = sizeof(u32) - 1;
|
|
|
+ hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_READ;
|
|
|
+ /* In SPT, This register is in Lan memory space, not flash.
|
|
|
+ * Therefore, only 32 bit access is supported
|
|
|
+ */
|
|
|
+ ew32flash(ICH_FLASH_HSFSTS, (u32)hsflctl.regval << 16);
|
|
|
+ ew32flash(ICH_FLASH_FADDR, flash_linear_addr);
|
|
|
+
|
|
|
+ ret_val =
|
|
|
+ e1000_flash_cycle_ich8lan(hw,
|
|
|
+ ICH_FLASH_READ_COMMAND_TIMEOUT);
|
|
|
+
|
|
|
+ /* Check if FCERR is set to 1, if set to 1, clear it
|
|
|
+ * and try the whole sequence a few more times, else
|
|
|
+ * read in (shift in) the Flash Data0, the order is
|
|
|
+ * least significant byte first msb to lsb
|
|
|
+ */
|
|
|
+ if (!ret_val) {
|
|
|
+ *data = er32flash(ICH_FLASH_FDATA0);
|
|
|
+ break;
|
|
|
+ } else {
|
|
|
+ /* If we've gotten here, then things are probably
|
|
|
+ * completely hosed, but if the error condition is
|
|
|
+ * detected, it won't hurt to give it another try...
|
|
|
+ * ICH_FLASH_CYCLE_REPEAT_COUNT times.
|
|
|
+ */
|
|
|
+ hsfsts.regval = er16flash(ICH_FLASH_HSFSTS);
|
|
|
+ if (hsfsts.hsf_status.flcerr) {
|
|
|
+ /* Repeat for some time before giving up. */
|
|
|
+ continue;
|
|
|
+ } else if (!hsfsts.hsf_status.flcdone) {
|
|
|
+ e_dbg("Timeout error - flash cycle did not complete.\n");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT);
|
|
|
+
|
|
|
+ return ret_val;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* e1000_write_nvm_ich8lan - Write word(s) to the NVM
|
|
|
* @hw: pointer to the HW structure
|
|
@@ -3321,7 +3610,7 @@ static s32 e1000_write_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words,
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * e1000_update_nvm_checksum_ich8lan - Update the checksum for NVM
|
|
|
+ * e1000_update_nvm_checksum_spt - Update the checksum for NVM
|
|
|
* @hw: pointer to the HW structure
|
|
|
*
|
|
|
* The NVM checksum is updated by calling the generic update_nvm_checksum,
|
|
@@ -3331,13 +3620,13 @@ static s32 e1000_write_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words,
|
|
|
* After a successful commit, the shadow ram is cleared and is ready for
|
|
|
* future writes.
|
|
|
**/
|
|
|
-static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
|
|
|
+static s32 e1000_update_nvm_checksum_spt(struct e1000_hw *hw)
|
|
|
{
|
|
|
struct e1000_nvm_info *nvm = &hw->nvm;
|
|
|
struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
|
|
|
u32 i, act_offset, new_bank_offset, old_bank_offset, bank;
|
|
|
s32 ret_val;
|
|
|
- u16 data;
|
|
|
+ u32 dword = 0;
|
|
|
|
|
|
ret_val = e1000e_update_nvm_checksum_generic(hw);
|
|
|
if (ret_val)
|
|
@@ -3371,12 +3660,175 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
|
|
|
if (ret_val)
|
|
|
goto release;
|
|
|
}
|
|
|
-
|
|
|
- for (i = 0; i < E1000_ICH8_SHADOW_RAM_WORDS; i++) {
|
|
|
+ for (i = 0; i < E1000_ICH8_SHADOW_RAM_WORDS; i += 2) {
|
|
|
/* Determine whether to write the value stored
|
|
|
* in the other NVM bank or a modified value stored
|
|
|
* in the shadow RAM
|
|
|
*/
|
|
|
+ ret_val = e1000_read_flash_dword_ich8lan(hw,
|
|
|
+ i + old_bank_offset,
|
|
|
+ &dword);
|
|
|
+
|
|
|
+ if (dev_spec->shadow_ram[i].modified) {
|
|
|
+ dword &= 0xffff0000;
|
|
|
+ dword |= (dev_spec->shadow_ram[i].value & 0xffff);
|
|
|
+ }
|
|
|
+ if (dev_spec->shadow_ram[i + 1].modified) {
|
|
|
+ dword &= 0x0000ffff;
|
|
|
+ dword |= ((dev_spec->shadow_ram[i + 1].value & 0xffff)
|
|
|
+ << 16);
|
|
|
+ }
|
|
|
+ if (ret_val)
|
|
|
+ break;
|
|
|
+
|
|
|
+ /* If the word is 0x13, then make sure the signature bits
|
|
|
+ * (15:14) are 11b until the commit has completed.
|
|
|
+ * This will allow us to write 10b which indicates the
|
|
|
+ * signature is valid. We want to do this after the write
|
|
|
+ * has completed so that we don't mark the segment valid
|
|
|
+ * while the write is still in progress
|
|
|
+ */
|
|
|
+ if (i == E1000_ICH_NVM_SIG_WORD - 1)
|
|
|
+ dword |= E1000_ICH_NVM_SIG_MASK << 16;
|
|
|
+
|
|
|
+ /* Convert offset to bytes. */
|
|
|
+ act_offset = (i + new_bank_offset) << 1;
|
|
|
+
|
|
|
+ usleep_range(100, 200);
|
|
|
+
|
|
|
+ /* Write the data to the new bank. Offset in words */
|
|
|
+ act_offset = i + new_bank_offset;
|
|
|
+ ret_val = e1000_retry_write_flash_dword_ich8lan(hw, act_offset,
|
|
|
+ dword);
|
|
|
+ if (ret_val)
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Don't bother writing the segment valid bits if sector
|
|
|
+ * programming failed.
|
|
|
+ */
|
|
|
+ if (ret_val) {
|
|
|
+ /* Possibly read-only, see e1000e_write_protect_nvm_ich8lan() */
|
|
|
+ e_dbg("Flash commit failed.\n");
|
|
|
+ goto release;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Finally validate the new segment by setting bit 15:14
|
|
|
+ * to 10b in word 0x13 , this can be done without an
|
|
|
+ * erase as well since these bits are 11 to start with
|
|
|
+ * and we need to change bit 14 to 0b
|
|
|
+ */
|
|
|
+ act_offset = new_bank_offset + E1000_ICH_NVM_SIG_WORD;
|
|
|
+
|
|
|
+ /*offset in words but we read dword */
|
|
|
+ --act_offset;
|
|
|
+ ret_val = e1000_read_flash_dword_ich8lan(hw, act_offset, &dword);
|
|
|
+
|
|
|
+ if (ret_val)
|
|
|
+ goto release;
|
|
|
+
|
|
|
+ dword &= 0xBFFFFFFF;
|
|
|
+ ret_val = e1000_retry_write_flash_dword_ich8lan(hw, act_offset, dword);
|
|
|
+
|
|
|
+ if (ret_val)
|
|
|
+ goto release;
|
|
|
+
|
|
|
+ /* And invalidate the previously valid segment by setting
|
|
|
+ * its signature word (0x13) high_byte to 0b. This can be
|
|
|
+ * done without an erase because flash erase sets all bits
|
|
|
+ * to 1's. We can write 1's to 0's without an erase
|
|
|
+ */
|
|
|
+ act_offset = (old_bank_offset + E1000_ICH_NVM_SIG_WORD) * 2 + 1;
|
|
|
+
|
|
|
+ /* offset in words but we read dword */
|
|
|
+ act_offset = old_bank_offset + E1000_ICH_NVM_SIG_WORD - 1;
|
|
|
+ ret_val = e1000_read_flash_dword_ich8lan(hw, act_offset, &dword);
|
|
|
+
|
|
|
+ if (ret_val)
|
|
|
+ goto release;
|
|
|
+
|
|
|
+ dword &= 0x00FFFFFF;
|
|
|
+ ret_val = e1000_retry_write_flash_dword_ich8lan(hw, act_offset, dword);
|
|
|
+
|
|
|
+ if (ret_val)
|
|
|
+ goto release;
|
|
|
+
|
|
|
+ /* Great! Everything worked, we can now clear the cached entries. */
|
|
|
+ for (i = 0; i < E1000_ICH8_SHADOW_RAM_WORDS; i++) {
|
|
|
+ dev_spec->shadow_ram[i].modified = false;
|
|
|
+ dev_spec->shadow_ram[i].value = 0xFFFF;
|
|
|
+ }
|
|
|
+
|
|
|
+release:
|
|
|
+ nvm->ops.release(hw);
|
|
|
+
|
|
|
+ /* Reload the EEPROM, or else modifications will not appear
|
|
|
+ * until after the next adapter reset.
|
|
|
+ */
|
|
|
+ if (!ret_val) {
|
|
|
+ nvm->ops.reload(hw);
|
|
|
+ usleep_range(10000, 20000);
|
|
|
+ }
|
|
|
+
|
|
|
+out:
|
|
|
+ if (ret_val)
|
|
|
+ e_dbg("NVM update error: %d\n", ret_val);
|
|
|
+
|
|
|
+ return ret_val;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * e1000_update_nvm_checksum_ich8lan - Update the checksum for NVM
|
|
|
+ * @hw: pointer to the HW structure
|
|
|
+ *
|
|
|
+ * The NVM checksum is updated by calling the generic update_nvm_checksum,
|
|
|
+ * which writes the checksum to the shadow ram. The changes in the shadow
|
|
|
+ * ram are then committed to the EEPROM by processing each bank at a time
|
|
|
+ * checking for the modified bit and writing only the pending changes.
|
|
|
+ * After a successful commit, the shadow ram is cleared and is ready for
|
|
|
+ * future writes.
|
|
|
+ **/
|
|
|
+static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
|
|
|
+{
|
|
|
+ struct e1000_nvm_info *nvm = &hw->nvm;
|
|
|
+ struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
|
|
|
+ u32 i, act_offset, new_bank_offset, old_bank_offset, bank;
|
|
|
+ s32 ret_val;
|
|
|
+ u16 data = 0;
|
|
|
+
|
|
|
+ ret_val = e1000e_update_nvm_checksum_generic(hw);
|
|
|
+ if (ret_val)
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ if (nvm->type != e1000_nvm_flash_sw)
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ nvm->ops.acquire(hw);
|
|
|
+
|
|
|
+ /* We're writing to the opposite bank so if we're on bank 1,
|
|
|
+ * write to bank 0 etc. We also need to erase the segment that
|
|
|
+ * is going to be written
|
|
|
+ */
|
|
|
+ ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank);
|
|
|
+ if (ret_val) {
|
|
|
+ e_dbg("Could not detect valid bank, assuming bank 0\n");
|
|
|
+ bank = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (bank == 0) {
|
|
|
+ new_bank_offset = nvm->flash_bank_size;
|
|
|
+ old_bank_offset = 0;
|
|
|
+ ret_val = e1000_erase_flash_bank_ich8lan(hw, 1);
|
|
|
+ if (ret_val)
|
|
|
+ goto release;
|
|
|
+ } else {
|
|
|
+ old_bank_offset = nvm->flash_bank_size;
|
|
|
+ new_bank_offset = 0;
|
|
|
+ ret_val = e1000_erase_flash_bank_ich8lan(hw, 0);
|
|
|
+ if (ret_val)
|
|
|
+ goto release;
|
|
|
+ }
|
|
|
+ for (i = 0; i < E1000_ICH8_SHADOW_RAM_WORDS; i++) {
|
|
|
if (dev_spec->shadow_ram[i].modified) {
|
|
|
data = dev_spec->shadow_ram[i].value;
|
|
|
} else {
|
|
@@ -3498,6 +3950,7 @@ static s32 e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw)
|
|
|
*/
|
|
|
switch (hw->mac.type) {
|
|
|
case e1000_pch_lpt:
|
|
|
+ case e1000_pch_spt:
|
|
|
word = NVM_COMPAT;
|
|
|
valid_csum_mask = NVM_COMPAT_VALID_CSUM;
|
|
|
break;
|
|
@@ -3583,9 +4036,13 @@ static s32 e1000_write_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
|
|
|
s32 ret_val;
|
|
|
u8 count = 0;
|
|
|
|
|
|
- if (size < 1 || size > 2 || data > size * 0xff ||
|
|
|
- offset > ICH_FLASH_LINEAR_ADDR_MASK)
|
|
|
- return -E1000_ERR_NVM;
|
|
|
+ if (hw->mac.type == e1000_pch_spt) {
|
|
|
+ if (size != 4 || offset > ICH_FLASH_LINEAR_ADDR_MASK)
|
|
|
+ return -E1000_ERR_NVM;
|
|
|
+ } else {
|
|
|
+ if (size < 1 || size > 2 || offset > ICH_FLASH_LINEAR_ADDR_MASK)
|
|
|
+ return -E1000_ERR_NVM;
|
|
|
+ }
|
|
|
|
|
|
flash_linear_addr = ((ICH_FLASH_LINEAR_ADDR_MASK & offset) +
|
|
|
hw->nvm.flash_base_addr);
|
|
@@ -3596,12 +4053,25 @@ static s32 e1000_write_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
|
|
|
ret_val = e1000_flash_cycle_init_ich8lan(hw);
|
|
|
if (ret_val)
|
|
|
break;
|
|
|
+ /* In SPT, This register is in Lan memory space, not
|
|
|
+ * flash. Therefore, only 32 bit access is supported
|
|
|
+ */
|
|
|
+ if (hw->mac.type == e1000_pch_spt)
|
|
|
+ hsflctl.regval = er32flash(ICH_FLASH_HSFSTS) >> 16;
|
|
|
+ else
|
|
|
+ hsflctl.regval = er16flash(ICH_FLASH_HSFCTL);
|
|
|
|
|
|
- hsflctl.regval = er16flash(ICH_FLASH_HSFCTL);
|
|
|
/* 0b/1b corresponds to 1 or 2 byte size, respectively. */
|
|
|
hsflctl.hsf_ctrl.fldbcount = size - 1;
|
|
|
hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_WRITE;
|
|
|
- ew16flash(ICH_FLASH_HSFCTL, hsflctl.regval);
|
|
|
+ /* In SPT, This register is in Lan memory space,
|
|
|
+ * not flash. Therefore, only 32 bit access is
|
|
|
+ * supported
|
|
|
+ */
|
|
|
+ if (hw->mac.type == e1000_pch_spt)
|
|
|
+ ew32flash(ICH_FLASH_HSFSTS, hsflctl.regval << 16);
|
|
|
+ else
|
|
|
+ ew16flash(ICH_FLASH_HSFCTL, hsflctl.regval);
|
|
|
|
|
|
ew32flash(ICH_FLASH_FADDR, flash_linear_addr);
|
|
|
|
|
@@ -3639,6 +4109,90 @@ static s32 e1000_write_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
|
|
|
return ret_val;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+* e1000_write_flash_data32_ich8lan - Writes 4 bytes to the NVM
|
|
|
+* @hw: pointer to the HW structure
|
|
|
+* @offset: The offset (in bytes) of the dwords to read.
|
|
|
+* @data: The 4 bytes to write to the NVM.
|
|
|
+*
|
|
|
+* Writes one/two/four bytes to the NVM using the flash access registers.
|
|
|
+**/
|
|
|
+static s32 e1000_write_flash_data32_ich8lan(struct e1000_hw *hw, u32 offset,
|
|
|
+ u32 data)
|
|
|
+{
|
|
|
+ union ich8_hws_flash_status hsfsts;
|
|
|
+ union ich8_hws_flash_ctrl hsflctl;
|
|
|
+ u32 flash_linear_addr;
|
|
|
+ s32 ret_val;
|
|
|
+ u8 count = 0;
|
|
|
+
|
|
|
+ if (hw->mac.type == e1000_pch_spt) {
|
|
|
+ if (offset > ICH_FLASH_LINEAR_ADDR_MASK)
|
|
|
+ return -E1000_ERR_NVM;
|
|
|
+ }
|
|
|
+ flash_linear_addr = ((ICH_FLASH_LINEAR_ADDR_MASK & offset) +
|
|
|
+ hw->nvm.flash_base_addr);
|
|
|
+ do {
|
|
|
+ udelay(1);
|
|
|
+ /* Steps */
|
|
|
+ ret_val = e1000_flash_cycle_init_ich8lan(hw);
|
|
|
+ if (ret_val)
|
|
|
+ break;
|
|
|
+
|
|
|
+ /* In SPT, This register is in Lan memory space, not
|
|
|
+ * flash. Therefore, only 32 bit access is supported
|
|
|
+ */
|
|
|
+ if (hw->mac.type == e1000_pch_spt)
|
|
|
+ hsflctl.regval = er32flash(ICH_FLASH_HSFSTS)
|
|
|
+ >> 16;
|
|
|
+ else
|
|
|
+ hsflctl.regval = er16flash(ICH_FLASH_HSFCTL);
|
|
|
+
|
|
|
+ hsflctl.hsf_ctrl.fldbcount = sizeof(u32) - 1;
|
|
|
+ hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_WRITE;
|
|
|
+
|
|
|
+ /* In SPT, This register is in Lan memory space,
|
|
|
+ * not flash. Therefore, only 32 bit access is
|
|
|
+ * supported
|
|
|
+ */
|
|
|
+ if (hw->mac.type == e1000_pch_spt)
|
|
|
+ ew32flash(ICH_FLASH_HSFSTS, hsflctl.regval << 16);
|
|
|
+ else
|
|
|
+ ew16flash(ICH_FLASH_HSFCTL, hsflctl.regval);
|
|
|
+
|
|
|
+ ew32flash(ICH_FLASH_FADDR, flash_linear_addr);
|
|
|
+
|
|
|
+ ew32flash(ICH_FLASH_FDATA0, data);
|
|
|
+
|
|
|
+ /* check if FCERR is set to 1 , if set to 1, clear it
|
|
|
+ * and try the whole sequence a few more times else done
|
|
|
+ */
|
|
|
+ ret_val =
|
|
|
+ e1000_flash_cycle_ich8lan(hw,
|
|
|
+ ICH_FLASH_WRITE_COMMAND_TIMEOUT);
|
|
|
+
|
|
|
+ if (!ret_val)
|
|
|
+ break;
|
|
|
+
|
|
|
+ /* If we're here, then things are most likely
|
|
|
+ * completely hosed, but if the error condition
|
|
|
+ * is detected, it won't hurt to give it another
|
|
|
+ * try...ICH_FLASH_CYCLE_REPEAT_COUNT times.
|
|
|
+ */
|
|
|
+ hsfsts.regval = er16flash(ICH_FLASH_HSFSTS);
|
|
|
+
|
|
|
+ if (hsfsts.hsf_status.flcerr)
|
|
|
+ /* Repeat for some time before giving up. */
|
|
|
+ continue;
|
|
|
+ if (!hsfsts.hsf_status.flcdone) {
|
|
|
+ e_dbg("Timeout error - flash cycle did not complete.\n");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ } while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT);
|
|
|
+
|
|
|
+ return ret_val;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* e1000_write_flash_byte_ich8lan - Write a single byte to NVM
|
|
|
* @hw: pointer to the HW structure
|
|
@@ -3655,6 +4209,40 @@ static s32 e1000_write_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset,
|
|
|
return e1000_write_flash_data_ich8lan(hw, offset, 1, word);
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+* e1000_retry_write_flash_dword_ich8lan - Writes a dword to NVM
|
|
|
+* @hw: pointer to the HW structure
|
|
|
+* @offset: The offset of the word to write.
|
|
|
+* @dword: The dword to write to the NVM.
|
|
|
+*
|
|
|
+* Writes a single dword to the NVM using the flash access registers.
|
|
|
+* Goes through a retry algorithm before giving up.
|
|
|
+**/
|
|
|
+static s32 e1000_retry_write_flash_dword_ich8lan(struct e1000_hw *hw,
|
|
|
+ u32 offset, u32 dword)
|
|
|
+{
|
|
|
+ s32 ret_val;
|
|
|
+ u16 program_retries;
|
|
|
+
|
|
|
+ /* Must convert word offset into bytes. */
|
|
|
+ offset <<= 1;
|
|
|
+ ret_val = e1000_write_flash_data32_ich8lan(hw, offset, dword);
|
|
|
+
|
|
|
+ if (!ret_val)
|
|
|
+ return ret_val;
|
|
|
+ for (program_retries = 0; program_retries < 100; program_retries++) {
|
|
|
+ e_dbg("Retrying Byte %8.8X at offset %u\n", dword, offset);
|
|
|
+ usleep_range(100, 200);
|
|
|
+ ret_val = e1000_write_flash_data32_ich8lan(hw, offset, dword);
|
|
|
+ if (!ret_val)
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ if (program_retries == 100)
|
|
|
+ return -E1000_ERR_NVM;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* e1000_retry_write_flash_byte_ich8lan - Writes a single byte to NVM
|
|
|
* @hw: pointer to the HW structure
|
|
@@ -3759,9 +4347,18 @@ static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank)
|
|
|
/* Write a value 11 (block Erase) in Flash
|
|
|
* Cycle field in hw flash control
|
|
|
*/
|
|
|
- hsflctl.regval = er16flash(ICH_FLASH_HSFCTL);
|
|
|
+ if (hw->mac.type == e1000_pch_spt)
|
|
|
+ hsflctl.regval =
|
|
|
+ er32flash(ICH_FLASH_HSFSTS) >> 16;
|
|
|
+ else
|
|
|
+ hsflctl.regval = er16flash(ICH_FLASH_HSFCTL);
|
|
|
+
|
|
|
hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_ERASE;
|
|
|
- ew16flash(ICH_FLASH_HSFCTL, hsflctl.regval);
|
|
|
+ if (hw->mac.type == e1000_pch_spt)
|
|
|
+ ew32flash(ICH_FLASH_HSFSTS,
|
|
|
+ hsflctl.regval << 16);
|
|
|
+ else
|
|
|
+ ew16flash(ICH_FLASH_HSFCTL, hsflctl.regval);
|
|
|
|
|
|
/* Write the last 24 bits of an index within the
|
|
|
* block into Flash Linear address field in Flash
|
|
@@ -4180,7 +4777,8 @@ static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw)
|
|
|
ew32(RFCTL, reg);
|
|
|
|
|
|
/* Enable ECC on Lynxpoint */
|
|
|
- if (hw->mac.type == e1000_pch_lpt) {
|
|
|
+ if ((hw->mac.type == e1000_pch_lpt) ||
|
|
|
+ (hw->mac.type == e1000_pch_spt)) {
|
|
|
reg = er32(PBECCSTS);
|
|
|
reg |= E1000_PBECCSTS_ECC_ENABLE;
|
|
|
ew32(PBECCSTS, reg);
|
|
@@ -4583,7 +5181,8 @@ void e1000_suspend_workarounds_ich8lan(struct e1000_hw *hw)
|
|
|
if ((device_id == E1000_DEV_ID_PCH_LPTLP_I218_LM) ||
|
|
|
(device_id == E1000_DEV_ID_PCH_LPTLP_I218_V) ||
|
|
|
(device_id == E1000_DEV_ID_PCH_I218_LM3) ||
|
|
|
- (device_id == E1000_DEV_ID_PCH_I218_V3)) {
|
|
|
+ (device_id == E1000_DEV_ID_PCH_I218_V3) ||
|
|
|
+ (hw->mac.type == e1000_pch_spt)) {
|
|
|
u32 fextnvm6 = er32(FEXTNVM6);
|
|
|
|
|
|
ew32(FEXTNVM6, fextnvm6 & ~E1000_FEXTNVM6_REQ_PLL_CLK);
|
|
@@ -5058,6 +5657,17 @@ static const struct e1000_nvm_operations ich8_nvm_ops = {
|
|
|
.write = e1000_write_nvm_ich8lan,
|
|
|
};
|
|
|
|
|
|
+static const struct e1000_nvm_operations spt_nvm_ops = {
|
|
|
+ .acquire = e1000_acquire_nvm_ich8lan,
|
|
|
+ .release = e1000_release_nvm_ich8lan,
|
|
|
+ .read = e1000_read_nvm_spt,
|
|
|
+ .update = e1000_update_nvm_checksum_spt,
|
|
|
+ .reload = e1000e_reload_nvm_generic,
|
|
|
+ .valid_led_default = e1000_valid_led_default_ich8lan,
|
|
|
+ .validate = e1000_validate_nvm_checksum_ich8lan,
|
|
|
+ .write = e1000_write_nvm_ich8lan,
|
|
|
+};
|
|
|
+
|
|
|
const struct e1000_info e1000_ich8_info = {
|
|
|
.mac = e1000_ich8lan,
|
|
|
.flags = FLAG_HAS_WOL
|
|
@@ -5166,3 +5776,23 @@ const struct e1000_info e1000_pch_lpt_info = {
|
|
|
.phy_ops = &ich8_phy_ops,
|
|
|
.nvm_ops = &ich8_nvm_ops,
|
|
|
};
|
|
|
+
|
|
|
+const struct e1000_info e1000_pch_spt_info = {
|
|
|
+ .mac = e1000_pch_spt,
|
|
|
+ .flags = FLAG_IS_ICH
|
|
|
+ | FLAG_HAS_WOL
|
|
|
+ | FLAG_HAS_HW_TIMESTAMP
|
|
|
+ | 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 = 9018,
|
|
|
+ .get_variants = e1000_get_variants_ich8lan,
|
|
|
+ .mac_ops = &ich8_mac_ops,
|
|
|
+ .phy_ops = &ich8_phy_ops,
|
|
|
+ .nvm_ops = &spt_nvm_ops,
|
|
|
+};
|