e1000_i210.c revision 49b7860084dbba18bc00b29413d6182197f9fe93
/******************************************************************************
Copyright (c) 2001-2015, Intel Corporation
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
3. Neither the name of the Intel Corporation nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
/*$FreeBSD$*/
#include "e1000_api.h"
/**
* e1000_acquire_nvm_i210 - Request for access to EEPROM
* @hw: pointer to the HW structure
*
* Acquire the necessary semaphores for exclusive access to the EEPROM.
* Set the EEPROM access request bit and wait for EEPROM access grant bit.
* Return successful if access grant bit set, else clear the request for
* EEPROM access and return -E1000_ERR_NVM (-1).
**/
{
DEBUGFUNC("e1000_acquire_nvm_i210");
return ret_val;
}
/**
* e1000_release_nvm_i210 - Release exclusive access to EEPROM
* @hw: pointer to the HW structure
*
* Stop any current commands to the EEPROM and clear the EEPROM request bit,
* then release the semaphores acquired.
**/
{
DEBUGFUNC("e1000_release_nvm_i210");
}
/**
* @hw: pointer to the HW structure
* @mask: specifies which semaphore to acquire
*
* will also specify which port we're acquiring the lock for.
**/
{
DEBUGFUNC("e1000_acquire_swfw_sync_i210");
while (i < timeout) {
if (e1000_get_hw_semaphore_i210(hw)) {
goto out;
}
break;
/*
* Firmware currently using resource (fwmask)
* or other software thread using resource (swmask)
*/
msec_delay_irq(5);
i++;
}
if (i == timeout) {
DEBUGOUT("Driver can't access resource, SW_FW_SYNC timeout.\n");
goto out;
}
out:
return ret_val;
}
/**
* @hw: pointer to the HW structure
* @mask: specifies which semaphore to acquire
*
* will also specify which port we're releasing the lock for.
**/
{
DEBUGFUNC("e1000_release_swfw_sync_i210");
; /* Empty */
}
/**
* e1000_get_hw_semaphore_i210 - Acquire hardware semaphore
* @hw: pointer to the HW structure
*
* Acquire the HW semaphore to access the PHY or NVM
**/
{
s32 i = 0;
DEBUGFUNC("e1000_get_hw_semaphore_i210");
/* Get the SW semaphore */
while (i < timeout) {
if (!(swsm & E1000_SWSM_SMBI))
break;
usec_delay(50);
i++;
}
if (i == timeout) {
/* In rare circumstances, the SW semaphore may already be held
* unintentionally. Clear the semaphore once before giving up.
*/
for (i = 0; i < timeout; i++) {
if (!(swsm & E1000_SWSM_SMBI))
break;
usec_delay(50);
}
}
/* If we do not have the semaphore here, we have to give up. */
if (i == timeout) {
DEBUGOUT("Driver can't access device - SMBI bit is set.\n");
return -E1000_ERR_NVM;
}
}
/* Get the FW semaphore. */
for (i = 0; i < timeout; i++) {
/* Semaphore acquired if bit latched */
break;
usec_delay(50);
}
if (i == timeout) {
/* Release semaphores */
DEBUGOUT("Driver can't access the NVM\n");
return -E1000_ERR_NVM;
}
return E1000_SUCCESS;
}
/**
* e1000_read_nvm_srrd_i210 - Reads Shadow Ram using EERD register
* @hw: pointer to the HW structure
* @offset: offset of word in the Shadow Ram to read
* @words: number of words to read
* @data: word read from the Shadow Ram
*
* Reads a 16 bit word from the Shadow Ram using the EERD register.
* Uses necessary synchronization semaphores.
**/
{
DEBUGFUNC("e1000_read_nvm_srrd_i210");
/* We cannot hold synchronization semaphores for too long,
* because of forceful takeover procedure. However it is more efficient
* to read in bursts than synchronizing access for each word. */
for (i = 0; i < words; i += E1000_EERD_EEWR_MAX_COUNT) {
E1000_EERD_EEWR_MAX_COUNT : (words - i);
data + i);
} else {
}
if (status != E1000_SUCCESS)
break;
}
return status;
}
/**
* e1000_write_nvm_srwr_i210 - Write to Shadow RAM using EEWR
* @hw: pointer to the HW structure
* @offset: offset within the Shadow RAM to be written to
* @words: number of words to write
* @data: 16 bit word(s) to be written to the Shadow RAM
*
* Writes data to Shadow RAM at offset using EEWR register.
*
* If e1000_update_nvm_checksum is not called after this function , the
* data will not be committed to FLASH and also Shadow RAM will most likely
* contain an invalid checksum.
*
* If error code is returned, data and Shadow RAM may be inconsistent - buffer
* partially written.
**/
{
DEBUGFUNC("e1000_write_nvm_srwr_i210");
/* We cannot hold synchronization semaphores for too long,
* because of forceful takeover procedure. However it is more efficient
* to write in bursts than synchronizing access for each word. */
for (i = 0; i < words; i += E1000_EERD_EEWR_MAX_COUNT) {
E1000_EERD_EEWR_MAX_COUNT : (words - i);
data + i);
} else {
}
if (status != E1000_SUCCESS)
break;
}
return status;
}
/**
* e1000_write_nvm_srwr - Write to Shadow Ram using EEWR
* @hw: pointer to the HW structure
* @offset: offset within the Shadow Ram to be written to
* @words: number of words to write
* @data: 16 bit word(s) to be written to the Shadow Ram
*
* Writes data to Shadow Ram at offset using EEWR register.
*
* If e1000_update_nvm_checksum is not called after this function , the
* Shadow Ram will most likely contain an invalid checksum.
**/
{
DEBUGFUNC("e1000_write_nvm_srwr");
/*
* A check for invalid values: offset too large, too many words,
* too many words for the offset, and not enough words.
*/
(words == 0)) {
DEBUGOUT("nvm parameter(s) out of bounds\n");
ret_val = -E1000_ERR_NVM;
goto out;
}
for (i = 0; i < words; i++) {
(data[i] << E1000_NVM_RW_REG_DATA) |
for (k = 0; k < attempts; k++) {
if (E1000_NVM_RW_REG_DONE &
break;
}
usec_delay(5);
}
if (ret_val != E1000_SUCCESS) {
DEBUGOUT("Shadow RAM write EEWR timed out\n");
break;
}
}
out:
return ret_val;
}
/** e1000_read_invm_word_i210 - Reads OTP
* @hw: pointer to the HW structure
* @address: the word address (aka eeprom offset) to read
* @data: pointer to the data read
*
* Reads 16-bit words from the OTP. Return error when the word is not
* stored in OTP.
**/
{
u16 i;
DEBUGFUNC("e1000_read_invm_word_i210");
for (i = 0; i < E1000_INVM_SIZE; i++) {
/* Get record type */
break;
if (word_address == address) {
DEBUGOUT2("Read INVM Word 0x%02x = %x",
break;
}
}
}
if (status != E1000_SUCCESS)
return status;
}
* @hw: pointer to the HW structure
* @address: the word address (aka eeprom offset) to read
* @data: pointer to the data read
*
* Wrapper function to return data formerly found in the NVM.
**/
{
DEBUGFUNC("e1000_read_invm_i210");
/* Only the MAC addr is required to be present in the iNVM */
switch (offset) {
case NVM_MAC_ADDR:
&data[1]);
&data[2]);
if (ret_val != E1000_SUCCESS)
DEBUGOUT("MAC Addr not found in iNVM\n");
break;
case NVM_INIT_CTRL_2:
if (ret_val != E1000_SUCCESS) {
}
break;
case NVM_INIT_CTRL_4:
if (ret_val != E1000_SUCCESS) {
}
break;
case NVM_LED_1_CFG:
if (ret_val != E1000_SUCCESS) {
}
break;
case NVM_LED_0_2_CFG:
if (ret_val != E1000_SUCCESS) {
}
break;
case NVM_ID_LED_SETTINGS:
if (ret_val != E1000_SUCCESS) {
}
break;
case NVM_SUB_DEV_ID:
break;
case NVM_SUB_VEN_ID:
break;
case NVM_DEV_ID:
break;
case NVM_VEN_ID:
break;
default:
break;
}
return ret_val;
}
/**
* e1000_validate_nvm_checksum_i210 - Validate EEPROM checksum
* @hw: pointer to the HW structure
*
* and then verifies that the sum of the EEPROM is equal to 0xBABA.
**/
{
DEBUGFUNC("e1000_validate_nvm_checksum_i210");
/*
* Replace the read function with semaphore grabbing with
* the one that skips this for a while.
* We have semaphore taken already here.
*/
/* Revert original read operation. */
} else {
}
return status;
}
/**
* e1000_update_nvm_checksum_i210 - Update EEPROM checksum
* @hw: pointer to the HW structure
*
* up to the checksum. Then calculates the EEPROM checksum and writes the
* value to the EEPROM. Next commit EEPROM data onto the Flash.
**/
{
DEBUGFUNC("e1000_update_nvm_checksum_i210");
/*
* Read the first word from the EEPROM. If this times out or fails, do
* not continue or we could be in for a very long wait while every
* EEPROM read fails
*/
if (ret_val != E1000_SUCCESS) {
DEBUGOUT("EEPROM read failed\n");
goto out;
}
/*
* Do not use hw->nvm.ops.write, hw->nvm.ops.read
* because we do not want to take the synchronization
* semaphores twice here.
*/
for (i = 0; i < NVM_CHECKSUM_REG; i++) {
if (ret_val) {
DEBUGOUT("NVM Read Error while updating checksum.\n");
goto out;
}
}
&checksum);
if (ret_val != E1000_SUCCESS) {
DEBUGOUT("NVM Write Error while updating checksum.\n");
goto out;
}
} else {
}
out:
return ret_val;
}
/**
* e1000_get_flash_presence_i210 - Check if flash device is detected.
* @hw: pointer to the HW structure
*
**/
{
DEBUGFUNC("e1000_get_flash_presence_i210");
return ret_val;
}
/**
* e1000_update_flash_i210 - Commit EEPROM to the flash
* @hw: pointer to the HW structure
*
**/
{
DEBUGFUNC("e1000_update_flash_i210");
if (ret_val == -E1000_ERR_NVM) {
DEBUGOUT("Flash update time out\n");
goto out;
}
if (ret_val == E1000_SUCCESS)
DEBUGOUT("Flash update complete\n");
else
DEBUGOUT("Flash update time out\n");
out:
return ret_val;
}
/**
* e1000_pool_flash_update_done_i210 - Pool FLUDONE status.
* @hw: pointer to the HW structure
*
**/
{
DEBUGFUNC("e1000_pool_flash_update_done_i210");
for (i = 0; i < E1000_FLUDONE_ATTEMPTS; i++) {
if (reg & E1000_EECD_FLUDONE_I210) {
break;
}
usec_delay(5);
}
return ret_val;
}
/**
* e1000_init_nvm_params_i210 - Initialize i210 NVM function pointers
* @hw: pointer to the HW structure
*
**/
{
DEBUGFUNC("e1000_init_nvm_params_i210");
if (e1000_get_flash_presence_i210(hw)) {
} else {
}
return ret_val;
}
/**
* e1000_init_function_pointers_i210 - Init func ptrs.
* @hw: pointer to the HW structure
*
* Called to initialize all function pointers and parameters.
**/
{
return;
}
/**
* e1000_valid_led_default_i210 - Verify a valid default LED config
* @hw: pointer to the HW structure
* @data: pointer to the NVM (EEPROM)
*
* Read the EEPROM for the current default LED configuration. If the
* LED configuration is not valid, set to a valid LED configuration.
**/
{
DEBUGFUNC("e1000_valid_led_default_i210");
if (ret_val) {
DEBUGOUT("NVM Read Error\n");
goto out;
}
break;
case e1000_media_type_copper:
default:
break;
}
}
out:
return ret_val;
}
/**
* @hw: pointer to the HW structure
* @address: XMDIO address to program
* @dev_addr: device address to program
* @read: boolean flag to indicate read or write
**/
{
DEBUGFUNC("__e1000_access_xmdio_reg");
if (ret_val)
return ret_val;
if (ret_val)
return ret_val;
dev_addr);
if (ret_val)
return ret_val;
if (read)
else
if (ret_val)
return ret_val;
/* Recalibrate the device back to 0 */
if (ret_val)
return ret_val;
return ret_val;
}
/**
* e1000_read_xmdio_reg - Read XMDIO register
* @hw: pointer to the HW structure
* @addr: XMDIO address to program
* @dev_addr: device address to program
* @data: value to be read from the EMI address
**/
{
DEBUGFUNC("e1000_read_xmdio_reg");
}
/**
* e1000_write_xmdio_reg - Write XMDIO register
* @hw: pointer to the HW structure
* @addr: XMDIO address to program
* @dev_addr: device address to program
* @data: value to be written to the XMDIO address
**/
{
DEBUGFUNC("e1000_read_xmdio_reg");
}
/**
* e1000_pll_workaround_i210
* @hw: pointer to the HW structure
*
* Works around an errata in the PLL circuit where it occasionally
* provides the wrong clock frequency after power up.
**/
{
int i;
/* Get and set needed register values */
/* Get data from NVM, or set default */
&nvm_word);
if (ret_val != E1000_SUCCESS)
for (i = 0; i < E1000_MAX_PLL_TRIES; i++) {
/* check current state directly from internal PHY */
if ((phy_word & E1000_PHY_PLL_UNCONF)
!= E1000_PHY_PLL_UNCONF) {
break;
} else {
ret_val = -E1000_ERR_PHY;
}
/* directly reset the internal PHY */
msec_delay(1);
/* restore WUC register */
}
/* restore MDICNFG setting */
return ret_val;
}
/**
* e1000_get_cfg_done_i210 - 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.
**/
{
DEBUGFUNC("e1000_get_cfg_done_i210");
while (timeout) {
break;
msec_delay(1);
timeout--;
}
if (!timeout)
DEBUGOUT("MNG configuration cycle has not completed.\n");
return E1000_SUCCESS;
}
/**
* @hw: pointer to the HW structure
*
* Called to initialize hw for i210 hw family.
**/
{
DEBUGFUNC("e1000_init_hw_i210");
!(e1000_get_flash_presence_i210(hw))) {
if (ret_val != E1000_SUCCESS)
return ret_val;
}
return ret_val;
}