e1000_ich8lan.c revision fe62dec3a38f1f79ffe68417df75dbbb58135bb7
/*
* This file is provided under a CDDLv1 license. When using or
* redistributing this file, you may do so under this license.
* In redistributing this file this license must be included
* and no other modification of this header file is permitted.
*
* CDDL LICENSE SUMMARY
*
* Copyright(c) 1999 - 2008 Intel Corporation. All rights reserved.
*
* The contents of this file are subject to the terms of Version
* 1.0 of the Common Development and Distribution License (the "License").
*
* You should have received a copy of the License with this software.
* You can obtain a copy of the License at
* See the License for the specific language governing permissions
* and limitations under the License.
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms of the CDDLv1.
*/
/*
* IntelVersion: 1.100 v2008-02-29
*/
/*
* e1000_ich8lan
* e1000_ich9lan
*/
#include "e1000_api.h"
#include "e1000_ich8lan.h"
bool active);
bool active);
/* ICH GbE Flash Hardware Sequencing Flash Status Register bit breakdown */
/* Offset 04h HSFSTS */
union ich8_hws_flash_status {
struct ich8_hsfsts {
} hsf_status;
};
/* ICH GbE Flash Hardware Sequencing Flash control Register bit breakdown */
/* Offset 06h FLCTL */
union ich8_hws_flash_ctrl {
struct ich8_hsflctl {
} hsf_ctrl;
};
/* ICH Flash Region Access Permissions */
union ich8_hws_flash_regacc {
struct ich8_flracc {
} hsf_flregacc;
};
struct e1000_shadow_ram {
bool modified;
};
struct e1000_dev_spec_ich8lan {
};
/*
* e1000_init_phy_params_ich8lan - Initialize PHY function pointers
* @hw: pointer to the HW structure
*
* Initialize family-specific PHY parameters and function pointers.
*/
static s32
{
u16 i = 0;
DEBUGFUNC("e1000_init_phy_params_ich8lan");
/*
* We may need to do this twice - once for IGP and if that fails,
* we'll set BM func pointers and try again
*/
if (ret_val) {
if (ret_val) {
DEBUGOUT("Can't determine PHY address. Erroring out\n");
goto out;
}
}
(i++ < 100)) {
msec_delay(1);
if (ret_val)
goto out;
}
/* Verify phy id */
case IGP03E1000_E_PHY_ID:
break;
case IFE_E_PHY_ID:
case IFE_PLUS_E_PHY_ID:
case IFE_C_E_PHY_ID:
break;
case BME1000_E_PHY_ID:
break;
default:
ret_val = -E1000_ERR_PHY;
goto out;
}
out:
return (ret_val);
}
/*
* e1000_init_nvm_params_ich8lan - Initialize NVM function pointers
* @hw: pointer to the HW structure
*
* Initialize family-specific NVM parameters and function
* pointers.
*/
static s32
{
struct e1000_dev_spec_ich8lan *dev_spec;
u16 i;
DEBUGFUNC("e1000_init_nvm_params_ich8lan");
/* Can't read flash registers if the register set isn't mapped. */
if (!hw->flash_address) {
DEBUGOUT("ERROR: Flash registers not mapped\n");
goto out;
}
/*
* 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.
*/
/* flash_base_addr is byte-aligned */
/*
* find total size of the NVM, then cut in half since the total size
* represents two separate NVM banks.
*/
/* Adjust to word count */
if (!dev_spec) {
DEBUGOUT("dev_spec pointer is set to NULL.\n");
goto out;
}
/* Clear shadow ram */
}
/* Function Pointers */
out:
return (ret_val);
}
/*
* e1000_init_mac_params_ich8lan - Initialize MAC function pointers
* @hw: pointer to the HW structure
*
* Initialize family-specific MAC parameters and function
* pointers.
*/
static s32
{
DEBUGFUNC("e1000_init_mac_params_ich8lan");
/* Set media type function pointer */
/* Set mta register count */
/* Set rar entry count */
mac->rar_entry_count--;
/* Set if part includes ASF firmware */
/* Set if manageability features are enabled. */
/* Function pointers */
/* reset */
/* hw initialization */
/* link setup */
/* physical interface setup */
/* check for link */
/* check management mode */
/* link info */
/* multicast address update */
/* setting MTA */
/* blink LED */
/* setup LED */
/* cleanup LED */
/* remove device */
/* clear hardware counters */
/* Device-specific structure allocation */
if (ret_val)
goto out;
/* Enable PCS Lock-loss workaround for ICH8 */
out:
return (ret_val);
}
/*
* e1000_init_function_pointers_ich8lan - Initialize ICH8 function pointers
* @hw: pointer to the HW structure
*
* Initialize family-specific function pointers for PHY, MAC, and NVM.
*/
void
{
DEBUGFUNC("e1000_init_function_pointers_ich8lan");
}
/*
* e1000_acquire_swflag_ich8lan - Acquire software control flag
* @hw: pointer to the HW structure
*
* Acquires the software control flag for performing NVM and PHY
* operations. This is a function pointer entry point only called by
*/
static s32
{
DEBUGFUNC("e1000_acquire_swflag_ich8lan");
while (timeout) {
break;
msec_delay_irq(1);
timeout--;
}
if (!timeout) {
DEBUGOUT("FW or HW has locked the resource for too long.\n");
goto out;
}
out:
return (ret_val);
}
/*
* e1000_release_swflag_ich8lan - Release software control flag
* @hw: pointer to the HW structure
*
* Releases the software control flag for performing NVM and PHY operations.
* routines for the PHY and NVM parts.
*/
static void
{
DEBUGFUNC("e1000_release_swflag_ich8lan");
}
/*
* e1000_check_mng_mode_ich8lan - Checks management mode
* @hw: pointer to the HW structure
*
* This checks if the adapter has manageability enabled.
* routines for the PHY and NVM parts.
*/
static bool
{
DEBUGFUNC("e1000_check_mng_mode_ich8lan");
return ((fwsm & E1000_FWSM_MODE_MASK) ==
}
/*
* e1000_check_reset_block_ich8lan - Check if PHY reset is blocked
* @hw: pointer to the HW structure
*
* Checks if firmware is blocking the reset of the PHY.
* This is a function pointer entry point only called by
* reset routines.
*/
static s32
{
DEBUGFUNC("e1000_check_reset_block_ich8lan");
}
/*
* e1000_phy_force_speed_duplex_ich8lan - Force PHY speed & duplex
* @hw: pointer to the HW structure
*
* Forces the speed and duplex settings of the PHY.
* This is a function pointer entry point only called by
* PHY setup routines.
*/
static s32
{
bool link;
DEBUGFUNC("e1000_phy_force_speed_duplex_ich8lan");
goto out;
}
if (ret_val)
goto out;
if (ret_val)
goto out;
/* Disable MDI-X support for 10/100 */
if (ret_val)
goto out;
data &= ~IFE_PMC_AUTO_MDIX;
data &= ~IFE_PMC_FORCE_MDIX;
if (ret_val)
goto out;
usec_delay(1);
if (phy->autoneg_wait_to_complete) {
100000,
&link);
if (ret_val)
goto out;
if (!link) {
DEBUGOUT("Link taking longer than expected.\n");
}
/* Try once more */
100000,
&link);
if (ret_val)
goto out;
}
out:
return (ret_val);
}
/*
* e1000_phy_hw_reset_ich8lan - Performs a PHY reset
* @hw: pointer to the HW structure
*
* Resets the PHY
* This is a function pointer entry point called by drivers
* or other shared routines.
*/
static s32
{
DEBUGFUNC("e1000_phy_hw_reset_ich8lan");
if (ret_val)
goto out;
/*
* Initialize the PHY from the NVM on ICH platforms. This is needed
* due to an issue where the NVM configuration is not properly
* autoloaded after power transitions. Therefore, after each PHY
* reset, we will load the configuration data out of the NVM manually.
*/
/* Check if SW needs configure the PHY */
else
if (!(data & sw_cfg_mask))
goto out;
/* Wait for basic configuration completes before proceeding */
do {
usec_delay(100);
/*
* If basic configuration is incomplete before the above loop
* count reaches 0, loading the configuration from NVM will
* leave the PHY in a bad state possibly resulting in no link.
*/
if (loop == 0) {
DEBUGOUT("LAN_INIT_DONE not set, increase timeout\n");
}
/* Clear the Init Done bit for the next init event */
/*
* Make sure HW does not configure LCD from PHY extended
* configuration before SW configuration
*/
goto out;
if (!cnf_size)
goto out;
/*
* Configure LCD from extended configuration region.
*/
/* cnf_base_addr is in DWORD */
for (i = 0; i < cnf_size; i++) {
(word_addr + i * 2),
1,
®_data);
if (ret_val)
goto out;
1,
®_addr);
if (ret_val)
goto out;
/* Save off the PHY page for future writes. */
if (reg_addr == IGP01E1000_PHY_PAGE_SELECT) {
continue;
}
reg_data);
if (ret_val)
goto out;
}
}
out:
return (ret_val);
}
/*
* e1000_get_phy_info_ich8lan - Calls appropriate PHY type get_phy_info
* @hw: pointer to the HW structure
*
* Wrapper for calling the get_phy_info routines for the appropriate phy type.
* This is a function pointer entry point called by drivers
* or other shared routines.
*/
static s32
{
DEBUGFUNC("e1000_get_phy_info_ich8lan");
case e1000_phy_ife:
break;
case e1000_phy_igp_3:
case e1000_phy_bm:
break;
default:
break;
}
return (ret_val);
}
/*
* e1000_get_phy_info_ife_ich8lan - Retrieves various IFE PHY states
* @hw: pointer to the HW structure
*
* Populates "phy" structure with various feature states.
* This function is only called by other family-specific
* routines.
*/
static s32
{
bool link;
DEBUGFUNC("e1000_get_phy_info_ife_ich8lan");
if (ret_val)
goto out;
if (!link) {
DEBUGOUT("Phy info is only valid if link is up\n");
goto out;
}
if (ret_val)
goto out;
if (phy->polarity_correction) {
if (ret_val)
goto out;
} else {
/* Polarity is forced */
}
if (ret_val)
goto out;
/* The following parameters are undefined for 10/100 operation. */
out:
return (ret_val);
}
/*
* e1000_check_polarity_ife_ich8lan - Check cable polarity for IFE PHY
* @hw: pointer to the HW structure
*
* Polarity is determined on the polarity reversal feature being enabled.
* This function is only called by other family-specific
* routines.
*/
static s32
{
DEBUGFUNC("e1000_check_polarity_ife_ich8lan");
/*
* Polarity is determined based on the reversal feature being enabled.
*/
if (phy->polarity_correction) {
} else {
}
if (!ret_val)
return (ret_val);
}
/*
* e1000_set_d0_lplu_state_ich8lan - Set Low Power Linkup D0 state
* @hw: pointer to the HW structure
* @active: TRUE to enable LPLU, FALSE to disable
*
* Sets the LPLU D0 state according to the active flag. When
* activating LPLU this function also disables smart speed
* and vice versa. LPLU will not be activated unless the
* device autonegotiation advertisement meets standards of
* either 10 or 10/100 or 10/100/1000 at all duplexes.
* This is a function pointer entry point only called by
* PHY setup routines.
*/
static s32
bool active)
{
DEBUGFUNC("e1000_set_d0_lplu_state_ich8lan");
goto out;
if (active) {
/*
* Call gig speed drop workaround on LPLU before accessing any
* PHY registers
*/
/* When LPLU is enabled, we should disable SmartSpeed */
&data);
data);
if (ret_val)
goto out;
} else {
/*
* LPLU and SmartSpeed are mutually exclusive. LPLU is used
* during Dx states where the power conservation is most
* important. During driver activity we should enable
* SmartSpeed, so performance is maintained.
*/
&data);
if (ret_val)
goto out;
data);
if (ret_val)
goto out;
&data);
if (ret_val)
goto out;
data);
if (ret_val)
goto out;
}
}
out:
return (ret_val);
}
/*
* e1000_set_d3_lplu_state_ich8lan - Set Low Power Linkup D3 state
* @hw: pointer to the HW structure
* @active: TRUE to enable LPLU, FALSE to disable
*
* Sets the LPLU D3 state according to the active flag. When
* activating LPLU this function also disables smart speed
* and vice versa. LPLU will not be activated unless the
* device autonegotiation advertisement meets standards of
* either 10 or 10/100 or 10/100/1000 at all duplexes.
* This is a function pointer entry point only called by
* PHY setup routines.
*/
static s32
bool active)
{
DEBUGFUNC("e1000_set_d3_lplu_state_ich8lan");
if (!active) {
/*
* LPLU and SmartSpeed are mutually exclusive. LPLU is used
* during Dx states where the power conservation is most
* important. During driver activity we should enable
* SmartSpeed, so performance is maintained.
*/
&data);
if (ret_val)
goto out;
data);
if (ret_val)
goto out;
&data);
if (ret_val)
goto out;
data);
if (ret_val)
goto out;
}
/*
* Call gig speed drop workaround on LPLU before accessing any
* PHY registers
*/
/* When LPLU is enabled, we should disable SmartSpeed */
&data);
if (ret_val)
goto out;
data);
}
out:
return (ret_val);
}
/*
* e1000_valid_nvm_bank_detect_ich8lan - finds out the valid bank 0 or 1
* @hw: pointer to the HW structure
* @bank: pointer to the variable that returns the active bank
*
* Reads signature byte from the NVM using the flash access registers.
*/
static s32
{
*bank = 1;
else
*bank = 0;
return (ret_val);
}
/*
* e1000_read_nvm_ich8lan - Read word(s) from the NVM
* @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 using the flash access registers.
*/
static s32
{
struct e1000_dev_spec_ich8lan *dev_spec;
DEBUGFUNC("e1000_read_nvm_ich8lan");
if (!dev_spec) {
DEBUGOUT("dev_spec pointer is set to NULL.\n");
goto out;
}
(words == 0)) {
DEBUGOUT("nvm parameter(s) out of bounds\n");
ret_val = -E1000_ERR_NVM;
goto out;
}
if (ret_val)
goto out;
if (ret_val != E1000_SUCCESS)
goto out;
act_offset += offset;
for (i = 0; i < words; i++) {
if ((dev_spec->shadow_ram) &&
} else {
act_offset + i,
&word);
if (ret_val)
break;
}
}
out:
return (ret_val);
}
/*
* e1000_flash_cycle_init_ich8lan - Initialize flash
* @hw: pointer to the HW structure
*
* can be started.
*/
static s32
{
union ich8_hws_flash_status hsfsts;
s32 i = 0;
DEBUGFUNC("e1000_flash_cycle_init_ich8lan");
/* Check if the flash descriptor is valid */
DEBUGOUT("Flash descriptor invalid. "
"SW Sequencing must be used.");
goto out;
}
/* Clear FCERR and DAEL in hw status by writing 1 */
/*
* Either we should have a hardware SPI cycle in progress bit to check
* against, in order to start a new cycle or FDONE bit should be
* changed in the hardware so that it is 1 after hardware reset, which
* can then be used as an indication whether a cycle is in progress or
* has been completed.
*/
/*
* There is no cycle running at present, so we can start a
* cycle. Begin by setting Flash Cycle Done.
*/
} else {
/*
* Otherwise poll for sometime so the current cycle has a
* chance to end before giving up.
*/
for (i = 0; i < ICH_FLASH_READ_COMMAND_TIMEOUT; i++) {
break;
}
usec_delay(1);
}
if (ret_val == E1000_SUCCESS) {
/*
* Successful in waiting for previous cycle to
* timeout, now set the Flash Cycle Done.
*/
} else {
DEBUGOUT("Flash controller busy, cannot get access");
}
}
out:
return (ret_val);
}
/*
* @hw: pointer to the HW structure
* @timeout: maximum time to wait for completion
*
* This function starts a flash cycle and waits for its completion.
*/
static s32
{
union ich8_hws_flash_ctrl hsflctl;
union ich8_hws_flash_status hsfsts;
u32 i = 0;
DEBUGFUNC("e1000_flash_cycle_ich8lan");
/* Start a cycle by writing 1 in Flash Cycle Go in Hw Flash Control */
/* wait till FDONE bit is set to 1 */
do {
break;
usec_delay(1);
} while (i++ < timeout);
return (ret_val);
}
/*
* e1000_read_flash_word_ich8lan - Read word 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 word at offset into data. Offset is converted
* to bytes before read.
*/
static s32
{
DEBUGFUNC("e1000_read_flash_word_ich8lan");
if (!data) {
ret_val = -E1000_ERR_NVM;
goto out;
}
/* Must convert offset into bytes. */
offset <<= 1;
out:
return (ret_val);
}
/*
* e1000_read_flash_data_ich8lan - Read byte or word from NVM
* @hw: pointer to the HW structure
* @offset: The offset (in bytes) of the byte or word to read.
* @size: Size of data to read, 1=byte 2=word
* @data: Pointer to the word to store the value read.
*
* Reads a byte or word from the NVM using the flash access registers.
*/
static s32
{
union ich8_hws_flash_status hsfsts;
union ich8_hws_flash_ctrl hsflctl;
u32 flash_data = 0;
DEBUGFUNC("e1000_read_flash_data_ich8lan");
goto out;
do {
usec_delay(1);
/* Steps */
if (ret_val != E1000_SUCCESS)
break;
/* 0b/1b corresponds to 1 or 2 byte size, respectively. */
/*
* 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 == E1000_SUCCESS) {
if (size == 1) {
} else if (size == 2) {
}
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.
*/
/* Repeat for some time before giving up. */
continue;
DEBUGOUT("Timeout error - flash cycle "
"did not complete.");
break;
}
}
} while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT);
out:
return (ret_val);
}
/*
* e1000_write_nvm_ich8lan - Write word(s) to the NVM
* @hw: pointer to the HW structure
* @offset: The offset (in bytes) of the word(s) to write.
* @words: Size of data to write in words
* @data: Pointer to the word(s) to write at offset.
*
* Writes a byte or word to the NVM using the flash access registers.
*/
static s32
{
struct e1000_dev_spec_ich8lan *dev_spec;
u16 i;
DEBUGFUNC("e1000_write_nvm_ich8lan");
if (!dev_spec) {
DEBUGOUT("dev_spec pointer is set to NULL.\n");
goto out;
}
(words == 0)) {
DEBUGOUT("nvm parameter(s) out of bounds\n");
ret_val = -E1000_ERR_NVM;
goto out;
}
if (ret_val)
goto out;
for (i = 0; i < words; i++) {
}
out:
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
{
struct e1000_dev_spec_ich8lan *dev_spec;
DEBUGFUNC("e1000_update_nvm_checksum_ich8lan");
if (ret_val)
goto out;
goto out;
if (ret_val)
goto out;
/*
* 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
*/
if (ret_val != E1000_SUCCESS)
goto out;
if (bank == 0) {
old_bank_offset = 0;
} else {
new_bank_offset = 0;
(void) e1000_erase_flash_bank_ich8lan(hw, 0);
}
for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) {
/*
* Determine whether to write the value stored in the other
* NVM bank or a modified value stored in the shadow RAM
*/
} else {
(void) e1000_read_flash_word_ich8lan(hw,
i + old_bank_offset,
&data);
}
/*
* 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)
/* Convert offset to bytes. */
usec_delay(100);
/* Write the bytes to the new bank. */
if (ret_val)
break;
usec_delay(100);
act_offset + 1,
if (ret_val)
break;
}
/*
* Don't bother writing the segment valid bits if sector programming
* failed.
*/
if (ret_val) {
DEBUGOUT("Flash commit failed.\n");
goto out;
}
/*
* 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
*/
data &= 0xBFFF;
if (ret_val) {
goto out;
}
/*
* 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
*/
if (ret_val) {
goto out;
}
/* Great! Everything worked, we can now clear the cached entries. */
for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) {
}
/*
* Reload the EEPROM, or else modifications will not appear until
* after the next adapter reset.
*/
msec_delay(10);
out:
return (ret_val);
}
/*
* e1000_validate_nvm_checksum_ich8lan - Validate EEPROM checksum
* @hw: pointer to the HW structure
*
* Check to see if checksum needs to be fixed by reading bit 6 in word 0x19.
* If the bit is 0, that the EEPROM had been modified, but the checksum was
* not calculated, in which case we need to calculate the checksum and set
* bit 6.
*/
static s32
{
DEBUGFUNC("e1000_validate_nvm_checksum_ich8lan");
/*
* Read 0x19 and check bit 6. If this bit is 0, the checksum needs to
* be fixed. This bit is an indication that the NVM was prepared by
* OEM software and did not calculate the checksum...a likely
* scenario.
*/
if (ret_val)
goto out;
if ((data & 0x40) == 0) {
data |= 0x40;
if (ret_val)
goto out;
if (ret_val)
goto out;
}
out:
return (ret_val);
}
/*
* e1000_write_flash_data_ich8lan - Writes bytes to the NVM
* @hw: pointer to the HW structure
* @size: Size of data to read, 1=byte 2=word
* @data: The byte(s) to write to the NVM.
*
*/
static s32
{
union ich8_hws_flash_status hsfsts;
union ich8_hws_flash_ctrl hsflctl;
u32 flash_data = 0;
DEBUGFUNC("e1000_write_ich8_data");
goto out;
do {
usec_delay(1);
/* Steps */
if (ret_val != E1000_SUCCESS)
break;
/* 0b/1b corresponds to 1 or 2 byte size, respectively. */
if (size == 1)
else
/*
* check if FCERR is set to 1 , if set to 1, clear it and try
* the whole sequence a few more times else done
*/
if (ret_val == E1000_SUCCESS) {
break;
} else {
/*
* 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.
*/
/* Repeat for some time before giving up. */
continue;
DEBUGOUT("Timeout error - flash cycle "
"did not complete.");
break;
}
}
} while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT);
out:
return (ret_val);
}
/*
* e1000_write_flash_byte_ich8lan - Write a single byte to NVM
* @hw: pointer to the HW structure
* @offset: The index of the byte to read.
* @data: The byte to write to the NVM.
*
* Writes a single byte to the NVM using the flash access registers.
*/
static s32
{
DEBUGFUNC("e1000_write_flash_byte_ich8lan");
}
/*
* e1000_retry_write_flash_byte_ich8lan - Writes a single byte to NVM
* @hw: pointer to the HW structure
* @offset: The offset of the byte to write.
* @byte: The byte to write to the NVM.
*
* Writes a single byte to the NVM using the flash access registers.
* Goes through a retry algorithm before giving up.
*/
static s32
{
DEBUGFUNC("e1000_retry_write_flash_byte_ich8lan");
if (ret_val == E1000_SUCCESS)
goto out;
usec_delay(100);
if (ret_val == E1000_SUCCESS)
break;
}
if (program_retries == 100) {
ret_val = -E1000_ERR_NVM;
goto out;
}
out:
return (ret_val);
}
/*
* e1000_erase_flash_bank_ich8lan - Erase a bank (4k) from NVM
* @hw: pointer to the HW structure
* @bank: 0 for first bank, 1 for second bank, etc.
*
* Erases the bank specified. Each bank is a 4k block. Banks are 0 based.
* bank N is 4096 * N + flash_reg_addr.
*/
static s32
{
union ich8_hws_flash_status hsfsts;
union ich8_hws_flash_ctrl hsflctl;
/* bank size is in 16bit words - adjust to bytes */
DEBUGFUNC("e1000_erase_flash_bank_ich8lan");
/*
* Determine HW Sector size: Read BERASE bits of hw flash status
* register
* 00: The Hw sector is 256 bytes, hence we need to erase 16
* consecutive sectors. The start index for the nth Hw sector
* can be calculated as = bank * 4096 + n * 256
* 01: The Hw sector is 4K bytes, hence we need to erase 1 sector.
* The start index for the nth Hw sector can be calculated
* as = bank * 4096
* 10: The Hw sector is 8K bytes, nth sector = bank * 8192
* (ich9 only, otherwise error condition)
* 11: The Hw sector is 64K bytes, nth sector = bank * 65536
*/
case 0:
/* Hw sector size 256 */
break;
case 1:
break;
case 2:
} else {
ret_val = -E1000_ERR_NVM;
goto out;
}
break;
case 3:
break;
default:
ret_val = -E1000_ERR_NVM;
goto out;
}
/* Start with the base address, then add the sector offset. */
for (j = 0; j < iteration; j++) {
do {
/* Steps */
if (ret_val)
goto out;
/*
* Write a value 11 (block Erase) in Flash Cycle field
* in hw flash control
*/
/*
* Write the last 24 bits of an index within the block
* into Flash Linear address field in Flash Address.
*/
flash_linear_addr += (j * sector_size);
if (ret_val == E1000_SUCCESS) {
break;
} else {
/*
* Check if FCERR is set to 1. If 1, clear it
* and try the whole sequence a few more times
* else Done
*/
/*
* repeat for some time before giving up
*/
continue;
goto out;
}
} while (++count < ICH_FLASH_CYCLE_REPEAT_COUNT);
}
out:
return (ret_val);
}
/*
* e1000_valid_led_default_ich8lan - Set the default LED settings
* @hw: pointer to the HW structure
* @data: Pointer to the LED settings
*
* Reads the LED default settings from the NVM to data. If the NVM LED
* settings is all 0's or F's, set the LED default to a valid LED default
* setting.
*/
static s32
{
DEBUGFUNC("e1000_valid_led_default_ich8lan");
if (ret_val) {
DEBUGOUT("NVM Read Error\n");
goto out;
}
if (*data == ID_LED_RESERVED_0000 ||
*data == ID_LED_RESERVED_FFFF)
out:
return (ret_val);
}
/*
* @hw: pointer to the HW structure
*
* ICH8 use the PCI Express bus, but does not contain a PCI Express Capability
* register, so the the bus width is hard coded.
*/
static s32
{
DEBUGFUNC("e1000_get_bus_info_ich8lan");
/*
* ICH devices are "PCI Express"-ish. They have a configuration
* space, but do not contain PCI Express Capability registers, so bus
* width must be hardcoded.
*/
return (ret_val);
}
/*
* e1000_reset_hw_ich8lan - Reset the hardware
* @hw: pointer to the HW structure
*
* Does a full reset of the hardware which includes a reset of the PHY and
* MAC.
*/
static s32
{
DEBUGFUNC("e1000_reset_hw_ich8lan");
/*
* Prevent the PCI-E bus from sticking if there is no TLP connection
*/
if (ret_val) {
DEBUGOUT("PCI-E Master disable polling has failed.\n");
}
DEBUGOUT("Masking off all interrupts\n");
/*
* Disable the Transmit and Receive units. Then delay to allow any
* pending transactions to complete before we hit the MAC with the
* global reset.
*/
msec_delay(10);
/* Workaround for ICH8 bit corruption issue in FIFO memory */
/* Set Tx and Rx buffer allocation to 8k apiece. */
/* Set Packet Buffer Size to 16k. */
}
/*
* PHY HW reset requires MAC CORE reset at the same time to
* make sure the interface between MAC and the external PHY is
* reset.
*/
}
DEBUGOUT("Issuing a global reset to ich8lan");
msec_delay(20);
if (ret_val) {
/*
* When auto config read does not complete, do not return with
* an error. This can happen in situations where there is no
* eeprom and prevents getting link.
*/
DEBUGOUT("Auto Read Done did not complete\n");
}
return (ret_val);
}
/*
* e1000_init_hw_ich8lan - Initialize the hardware
* @hw: pointer to the HW structure
*
* Prepares the hardware for transmit and receive by doing the following:
* - initialize hardware bits
* - initialize LED identification
* - setup receive address registers
* - setup flow control
* - setup transmit descriptors
* - clear statistics
*/
static s32
{
u16 i;
DEBUGFUNC("e1000_init_hw_ich8lan");
/* Initialize identification LED */
if (ret_val) {
DEBUGOUT("Error initializing identification LED\n");
/* This is not fatal and we should not stop init due to this */
}
/* Setup the receive address. */
/* Zero out the Multicast HASH table */
DEBUGOUT("Zeroing the MTA\n");
for (i = 0; i < mac->mta_reg_count; i++)
/* Setup link and flow control */
/* Set the transmit descriptor write-back policy for both queues */
/*
* ICH8 has opposite polarity of no_snoop bits. By default, we should
* use snoop behavior.
*/
else
/*
* Clear all of the statistics registers (clear on read). It is
* important that we do this after we have tried to establish link
* because the symbol error count will increment wildly if there
* is no link.
*/
return (ret_val);
}
/*
* e1000_initialize_hw_bits_ich8lan - Initialize required hardware bits
* @hw: pointer to the HW structure
*
* hardware for transmit and receive.
*/
static void
{
DEBUGFUNC("e1000_initialize_hw_bits_ich8lan");
return;
/* Extended Device Control */
/* Transmit Descriptor Control 0 */
/* Transmit Descriptor Control 1 */
/* Transmit Arbitration Control 0 */
/* Transmit Arbitration Control 1 */
else
/* Device Status */
}
}
/*
* e1000_setup_link_ich8lan - Setup flow control and link settings
* @hw: pointer to the HW structure
*
* Determines which flow control settings to use, then configures flow
* control. Calls the appropriate media-specific link configuration
* function. Assuming the adapter has a valid link partner, a valid link
* should be established. Assumes the hardware has previously been reset
* and the transmitter and receiver are not enabled.
*/
static s32
{
DEBUGFUNC("e1000_setup_link_ich8lan");
goto out;
/*
* ICH parts do not have a word in the NVM to determine the default
* flow control setting, so we explicitly set it to full.
*/
/* Continue to configure the copper link. */
if (ret_val)
goto out;
out:
return (ret_val);
}
/*
* @hw: pointer to the HW structure
*
* Configures the kumeran interface to the PHY to wait the appropriate time
* when polling the PHY, then call the generic setup_copper_link to finish
* configuring the copper link.
*/
static s32
{
DEBUGFUNC("e1000_setup_copper_link_ich8lan");
ctrl |= E1000_CTRL_SLU;
/*
* Set the mac to wait the maximum time between each iteration and
* increase the max iterations when polling the phy; this fixes
* erroneous timeouts at 10Mbps.
*/
if (ret_val)
goto out;
if (ret_val)
goto out;
reg_data |= 0x3F;
if (ret_val)
goto out;
if (ret_val)
goto out;
if (ret_val)
goto out;
}
®_data);
if (ret_val)
goto out;
case 1:
break;
case 2:
break;
case 0:
default:
break;
}
reg_data);
if (ret_val)
goto out;
}
out:
return (ret_val);
}
/*
* e1000_get_link_up_info_ich8lan - Get current link speed and duplex
* @hw: pointer to the HW structure
* @speed: pointer to store current link speed
* @duplex: pointer to store the current link duplex
*
* Calls the generic get_speed_and_duplex to retrieve the current link
* information and then calls the Kumeran lock loss workaround for links at
* gigabit speeds.
*/
static s32
{
DEBUGFUNC("e1000_get_link_up_info_ich8lan");
if (ret_val)
goto out;
(*speed == SPEED_1000)) {
}
out:
return (ret_val);
}
/*
* e1000_kmrn_lock_loss_workaround_ich8lan - Kumeran workaround
* @hw: pointer to the HW structure
*
* Work-around for 82566 Kumeran PCS lock loss:
* On link status change (i.e. PCI reset, speed change) and link is up and
* speed is gigabit-
* 0) if workaround is optionally disabled do nothing
* 1) wait 1ms for Kumeran link to come up
* 2) check Kumeran Diagnostic register PCS lock loss bit
* 3) if not set the link is locked (all is good), otherwise...
* 4) reset the PHY
* 5) repeat up to 10 times
* Note: this is only called for IGP3 copper when speed is 1gb.
*/
static s32
{
struct e1000_dev_spec_ich8lan *dev_spec;
bool link;
DEBUGFUNC("e1000_kmrn_lock_loss_workaround_ich8lan");
if (!dev_spec) {
DEBUGOUT("dev_spec pointer is set to NULL.\n");
goto out;
}
goto out;
/*
* Make sure link is up before proceeding. If not just return.
* Attempting this while link is negotiating fouled up link stability
*/
if (!link) {
goto out;
}
for (i = 0; i < 10; i++) {
/* read once to clear */
if (ret_val)
goto out;
/* and again to get new status */
if (ret_val)
goto out;
/* check for PCS lock */
if (!(data & IGP3_KMRN_DIAG_PCS_LOCK_LOSS)) {
goto out;
}
/* Issue PHY reset */
msec_delay_irq(5);
}
/* Disable GigE link negotiation */
/*
* Call gig speed drop workaround on Gig disable before accessing any
* PHY registers
*/
/* unable to acquire PCS lock */
ret_val = -E1000_ERR_PHY;
out:
return (ret_val);
}
/*
* e1000_set_kmrn_lock_loss_workaround_ich8lan - Set Kumeran workaround state
* @hw: pointer to the HW structure
* @state: boolean value used to set the current Kumeran workaround state
*
* If ICH8, set the current Kumeran workaround state (enabled - TRUE
* /disabled - FALSE).
*/
void
bool state)
{
struct e1000_dev_spec_ich8lan *dev_spec;
DEBUGFUNC("e1000_set_kmrn_lock_loss_workaround_ich8lan");
DEBUGOUT("Workaround applies to ICH8 only.\n");
return;
}
if (!dev_spec) {
DEBUGOUT("dev_spec pointer is set to NULL.\n");
return;
}
}
/*
* e1000_ipg3_phy_powerdown_workaround_ich8lan - Power down workaround on D3
* @hw: pointer to the HW structure
*
* Workaround for 82566 power-down on D3 entry:
* 1) disable gigabit link
* 2) write VR power-down enable
* 3) read it back
* Continue if successful, else issue LCD reset and repeat
*/
void
{
DEBUGFUNC("e1000_igp3_phy_powerdown_workaround_ich8lan");
return;
/* Try the workaround twice (if needed) */
do {
/* Disable link */
/*
* Call gig speed drop workaround on Gig disable before
* accessing any PHY registers
*/
/* Write VR power-down enable */
/* Read it back and test */
break;
/* Issue PHY reset and repeat at most one more time */
retry++;
} while (retry);
}
/*
* e1000_gig_downshift_workaround_ich8lan - WoL from S5 stops working
* @hw: pointer to the HW structure
*
* Steps to take when dropping from 1Gb/s (eg. link cable removal (LSC),
* LPLU, Gig disable, MDIC PHY reset):
* 1) Set Kumeran Near-end loopback
* 2) Clear Kumeran Near-end loopback
* Should only be called for ICH8[m] devices with IGP_3 Phy.
*/
void
{
DEBUGFUNC("e1000_gig_downshift_workaround_ich8lan");
return;
®_data);
if (ret_val)
return;
reg_data);
if (ret_val)
return;
reg_data);
}
/*
* e1000_disable_gig_wol_ich8lan - disable gig during WoL
* @hw: pointer to the HW structure
*
* During S0 to Sx transition, it is possible the link remains at gig
* instead of negotiating to a lower speed. Before going to Sx, set
* 'LPLU Enabled' and 'Gig Disable' to force link speed negotiation
* to a lower speed.
*
* Should only be called for ICH9.
*/
void
{
}
}
/*
* e1000_cleanup_led_ich8lan - Restore the default LED operation
* @hw: pointer to the HW structure
*
* Return the LED back to the default configuration.
*/
static s32
{
DEBUGFUNC("e1000_cleanup_led_ich8lan");
0);
else
return (ret_val);
}
/*
* e1000_led_on_ich8lan - Turn LEDs on
* @hw: pointer to the HW structure
*
* Turn on the LEDs.
*/
static s32
{
DEBUGFUNC("e1000_led_on_ich8lan");
else
return (ret_val);
}
/*
* e1000_led_off_ich8lan - Turn LEDs off
* @hw: pointer to the HW structure
*
* Turn off the LEDs.
*/
static s32
{
DEBUGFUNC("e1000_led_off_ich8lan");
else
return (ret_val);
}
/*
* e1000_get_cfg_done_ich8lan - Read config done bit
* @hw: pointer to the HW structure
*
* Read the management control register for the config done bit for
* completion status. NOTE: silicon which is EEPROM-less will fail trying
* to read the config done bit, so an error is *ONLY* logged and returns
* E1000_SUCCESS. If we were to return with error, EEPROM-less silicon
* would not be able to be reset or change link.
*/
static s32
{
(void) e1000_get_cfg_done_generic(hw);
/* If EEPROM is not marked present, init the IGP 3 PHY manually */
(void) e1000_phy_init_script_igp3(hw);
}
return (ret_val);
}
/*
* e1000_power_down_phy_copper_ich8lan - Remove link during PHY power down
* @hw: pointer to the HW structure
*
* In the case of a PHY power down to save power, or to turn off link during a
* driver unload, or wake on lan is not enabled, remove the link.
*/
static void
{
/* If the management interface is not enabled, then power down */
}
/*
* e1000_clear_hw_cntrs_ich8lan - Clear statistical counters
* @hw: pointer to the HW structure
*
* Clears hardware counters specific to the silicon family and calls
* clear_hw_cntrs_generic to clear all general purpose counters.
*/
static void
{
DEBUGFUNC("e1000_clear_hw_cntrs_ich8lan");
}