Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/e1000/e1000_nvm.c
/****************************************************************************** | /****************************************************************************** | ||||
SPDX-License-Identifier: BSD-3-Clause | SPDX-License-Identifier: BSD-3-Clause | ||||
Copyright (c) 2001-2015, Intel Corporation | Copyright (c) 2001-2020, Intel Corporation | ||||
All rights reserved. | All rights reserved. | ||||
Redistribution and use in source and binary forms, with or without | Redistribution and use in source and binary forms, with or without | ||||
modification, are permitted provided that the following conditions are met: | modification, are permitted provided that the following conditions are met: | ||||
1. Redistributions of source code must retain the above copyright notice, | 1. Redistributions of source code must retain the above copyright notice, | ||||
this list of conditions and the following disclaimer. | this list of conditions and the following disclaimer. | ||||
2. Redistributions in binary form must reproduce the above copyright | 2. Redistributions in binary form must reproduce the above copyright | ||||
notice, this list of conditions and the following disclaimer in the | notice, this list of conditions and the following disclaimer in the | ||||
documentation and/or other materials provided with the distribution. | documentation and/or other materials provided with the distribution. | ||||
3. Neither the name of the Intel Corporation nor the names of its | 3. Neither the name of the Intel Corporation nor the names of its | ||||
contributors may be used to endorse or promote products derived from | contributors may be used to endorse or promote products derived from | ||||
this software without specific prior written permission. | this software without specific prior written permission. | ||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 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 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||||
POSSIBILITY OF SUCH DAMAGE. | POSSIBILITY OF SUCH DAMAGE. | ||||
******************************************************************************/ | ******************************************************************************/ | ||||
/*$FreeBSD$*/ | /*$FreeBSD$*/ | ||||
#include "e1000_api.h" | #include "e1000_api.h" | ||||
Show All 20 Lines | void e1000_init_nvm_ops_generic(struct e1000_hw *hw) | ||||
nvm->ops.valid_led_default = e1000_null_led_default; | nvm->ops.valid_led_default = e1000_null_led_default; | ||||
nvm->ops.validate = e1000_null_ops_generic; | nvm->ops.validate = e1000_null_ops_generic; | ||||
nvm->ops.write = e1000_null_write_nvm; | nvm->ops.write = e1000_null_write_nvm; | ||||
} | } | ||||
/** | /** | ||||
* e1000_null_nvm_read - No-op function, return 0 | * e1000_null_nvm_read - No-op function, return 0 | ||||
* @hw: pointer to the HW structure | * @hw: pointer to the HW structure | ||||
* @a: dummy variable | |||||
* @b: dummy variable | |||||
* @c: dummy variable | |||||
**/ | **/ | ||||
s32 e1000_null_read_nvm(struct e1000_hw E1000_UNUSEDARG *hw, | s32 e1000_null_read_nvm(struct e1000_hw E1000_UNUSEDARG *hw, | ||||
u16 E1000_UNUSEDARG a, u16 E1000_UNUSEDARG b, | u16 E1000_UNUSEDARG a, u16 E1000_UNUSEDARG b, | ||||
u16 E1000_UNUSEDARG *c) | u16 E1000_UNUSEDARG *c) | ||||
{ | { | ||||
DEBUGFUNC("e1000_null_read_nvm"); | DEBUGFUNC("e1000_null_read_nvm"); | ||||
return E1000_SUCCESS; | return E1000_SUCCESS; | ||||
} | } | ||||
/** | /** | ||||
* e1000_null_nvm_generic - No-op function, return void | * e1000_null_nvm_generic - No-op function, return void | ||||
* @hw: pointer to the HW structure | * @hw: pointer to the HW structure | ||||
**/ | **/ | ||||
void e1000_null_nvm_generic(struct e1000_hw E1000_UNUSEDARG *hw) | void e1000_null_nvm_generic(struct e1000_hw E1000_UNUSEDARG *hw) | ||||
{ | { | ||||
DEBUGFUNC("e1000_null_nvm_generic"); | DEBUGFUNC("e1000_null_nvm_generic"); | ||||
return; | return; | ||||
} | } | ||||
/** | /** | ||||
* e1000_null_led_default - No-op function, return 0 | * e1000_null_led_default - No-op function, return 0 | ||||
* @hw: pointer to the HW structure | * @hw: pointer to the HW structure | ||||
* @data: dummy variable | |||||
**/ | **/ | ||||
s32 e1000_null_led_default(struct e1000_hw E1000_UNUSEDARG *hw, | s32 e1000_null_led_default(struct e1000_hw E1000_UNUSEDARG *hw, | ||||
u16 E1000_UNUSEDARG *data) | u16 E1000_UNUSEDARG *data) | ||||
{ | { | ||||
DEBUGFUNC("e1000_null_led_default"); | DEBUGFUNC("e1000_null_led_default"); | ||||
return E1000_SUCCESS; | return E1000_SUCCESS; | ||||
} | } | ||||
/** | /** | ||||
* e1000_null_write_nvm - No-op function, return 0 | * e1000_null_write_nvm - No-op function, return 0 | ||||
* @hw: pointer to the HW structure | * @hw: pointer to the HW structure | ||||
* @a: dummy variable | |||||
* @b: dummy variable | |||||
* @c: dummy variable | |||||
**/ | **/ | ||||
s32 e1000_null_write_nvm(struct e1000_hw E1000_UNUSEDARG *hw, | s32 e1000_null_write_nvm(struct e1000_hw E1000_UNUSEDARG *hw, | ||||
u16 E1000_UNUSEDARG a, u16 E1000_UNUSEDARG b, | u16 E1000_UNUSEDARG a, u16 E1000_UNUSEDARG b, | ||||
u16 E1000_UNUSEDARG *c) | u16 E1000_UNUSEDARG *c) | ||||
{ | { | ||||
DEBUGFUNC("e1000_null_write_nvm"); | DEBUGFUNC("e1000_null_write_nvm"); | ||||
return E1000_SUCCESS; | return E1000_SUCCESS; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 664 Lines • ▼ Show 20 Lines | s32 e1000_read_pba_string_generic(struct e1000_hw *hw, u8 *pba_num, | ||||
s32 ret_val; | s32 ret_val; | ||||
u16 nvm_data; | u16 nvm_data; | ||||
u16 pba_ptr; | u16 pba_ptr; | ||||
u16 offset; | u16 offset; | ||||
u16 length; | u16 length; | ||||
DEBUGFUNC("e1000_read_pba_string_generic"); | DEBUGFUNC("e1000_read_pba_string_generic"); | ||||
if ((hw->mac.type >= e1000_i210) && | if ((hw->mac.type == e1000_i210 || | ||||
hw->mac.type == e1000_i211) && | |||||
!e1000_get_flash_presence_i210(hw)) { | !e1000_get_flash_presence_i210(hw)) { | ||||
DEBUGOUT("Flashless no PBA string\n"); | DEBUGOUT("Flashless no PBA string\n"); | ||||
return -E1000_ERR_NVM_PBA_SECTION; | return -E1000_ERR_NVM_PBA_SECTION; | ||||
} | } | ||||
if (pba_num == NULL) { | if (pba_num == NULL) { | ||||
DEBUGOUT("PBA string buffer was null\n"); | DEBUGOUT("PBA string buffer was null\n"); | ||||
return -E1000_ERR_INVALID_ARGUMENT; | return -E1000_ERR_INVALID_ARGUMENT; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 137 Lines • ▼ Show 20 Lines | s32 e1000_read_pba_length_generic(struct e1000_hw *hw, u32 *pba_num_size) | ||||
/* Convert from length in u16 values to u8 chars, add 1 for NULL, | /* Convert from length in u16 values to u8 chars, add 1 for NULL, | ||||
* and subtract 2 because length field is included in length. | * and subtract 2 because length field is included in length. | ||||
*/ | */ | ||||
*pba_num_size = ((u32)length * 2) - 1; | *pba_num_size = ((u32)length * 2) - 1; | ||||
return E1000_SUCCESS; | return E1000_SUCCESS; | ||||
} | } | ||||
/** | |||||
* e1000_read_pba_num_generic - Read device part number | |||||
* @hw: pointer to the HW structure | |||||
* @pba_num: pointer to device part number | |||||
* | |||||
* Reads the product board assembly (PBA) number from the EEPROM and stores | |||||
* the value in pba_num. | |||||
**/ | |||||
s32 e1000_read_pba_num_generic(struct e1000_hw *hw, u32 *pba_num) | |||||
{ | |||||
s32 ret_val; | |||||
u16 nvm_data; | |||||
DEBUGFUNC("e1000_read_pba_num_generic"); | |||||
ret_val = hw->nvm.ops.read(hw, NVM_PBA_OFFSET_0, 1, &nvm_data); | |||||
if (ret_val) { | |||||
DEBUGOUT("NVM Read Error\n"); | |||||
return ret_val; | |||||
} else if (nvm_data == NVM_PBA_PTR_GUARD) { | |||||
DEBUGOUT("NVM Not Supported\n"); | |||||
return -E1000_NOT_IMPLEMENTED; | |||||
} | |||||
*pba_num = (u32)(nvm_data << 16); | |||||
ret_val = hw->nvm.ops.read(hw, NVM_PBA_OFFSET_1, 1, &nvm_data); | |||||
if (ret_val) { | |||||
DEBUGOUT("NVM Read Error\n"); | |||||
return ret_val; | |||||
} | |||||
*pba_num |= nvm_data; | |||||
return E1000_SUCCESS; | |||||
} | |||||
/** | /** | ||||
* e1000_read_pba_raw | * e1000_read_pba_raw | ||||
* @hw: pointer to the HW structure | * @hw: pointer to the HW structure | ||||
* @eeprom_buf: optional pointer to EEPROM image | * @eeprom_buf: optional pointer to EEPROM image | ||||
* @eeprom_buf_size: size of EEPROM image in words | * @eeprom_buf_size: size of EEPROM image in words | ||||
* @max_pba_block_size: PBA block size limit | * @max_pba_block_size: PBA block size limit | ||||
* @pba: pointer to output PBA structure | * @pba: pointer to output PBA structure | ||||
* | * | ||||
▲ Show 20 Lines • Show All 283 Lines • ▼ Show 20 Lines | static void e1000_reload_nvm_generic(struct e1000_hw *hw) | ||||
DEBUGFUNC("e1000_reload_nvm_generic"); | DEBUGFUNC("e1000_reload_nvm_generic"); | ||||
usec_delay(10); | usec_delay(10); | ||||
ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT); | ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT); | ||||
ctrl_ext |= E1000_CTRL_EXT_EE_RST; | ctrl_ext |= E1000_CTRL_EXT_EE_RST; | ||||
E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext); | E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext); | ||||
E1000_WRITE_FLUSH(hw); | E1000_WRITE_FLUSH(hw); | ||||
} | |||||
/** | |||||
* e1000_get_fw_version - Get firmware version information | |||||
* @hw: pointer to the HW structure | |||||
* @fw_vers: pointer to output version structure | |||||
* | |||||
* unsupported/not present features return 0 in version structure | |||||
**/ | |||||
void e1000_get_fw_version(struct e1000_hw *hw, struct e1000_fw_version *fw_vers) | |||||
{ | |||||
u16 eeprom_verh, eeprom_verl, etrack_test, fw_version; | |||||
u8 q, hval, rem, result; | |||||
u16 comb_verh, comb_verl, comb_offset; | |||||
memset(fw_vers, 0, sizeof(struct e1000_fw_version)); | |||||
/* basic eeprom version numbers, bits used vary by part and by tool | |||||
* used to create the nvm images */ | |||||
/* Check which data format we have */ | |||||
switch (hw->mac.type) { | |||||
case e1000_i211: | |||||
e1000_read_invm_version(hw, fw_vers); | |||||
return; | |||||
case e1000_82575: | |||||
case e1000_82576: | |||||
case e1000_82580: | |||||
case e1000_i354: | |||||
hw->nvm.ops.read(hw, NVM_ETRACK_HIWORD, 1, &etrack_test); | |||||
/* Use this format, unless EETRACK ID exists, | |||||
* then use alternate format | |||||
*/ | |||||
if ((etrack_test & NVM_MAJOR_MASK) != NVM_ETRACK_VALID) { | |||||
hw->nvm.ops.read(hw, NVM_VERSION, 1, &fw_version); | |||||
fw_vers->eep_major = (fw_version & NVM_MAJOR_MASK) | |||||
>> NVM_MAJOR_SHIFT; | |||||
fw_vers->eep_minor = (fw_version & NVM_MINOR_MASK) | |||||
>> NVM_MINOR_SHIFT; | |||||
fw_vers->eep_build = (fw_version & NVM_IMAGE_ID_MASK); | |||||
goto etrack_id; | |||||
} | |||||
break; | |||||
case e1000_i210: | |||||
if (!(e1000_get_flash_presence_i210(hw))) { | |||||
e1000_read_invm_version(hw, fw_vers); | |||||
return; | |||||
} | |||||
/* fall through */ | |||||
case e1000_i350: | |||||
hw->nvm.ops.read(hw, NVM_ETRACK_HIWORD, 1, &etrack_test); | |||||
/* find combo image version */ | |||||
hw->nvm.ops.read(hw, NVM_COMB_VER_PTR, 1, &comb_offset); | |||||
if ((comb_offset != 0x0) && | |||||
(comb_offset != NVM_VER_INVALID)) { | |||||
hw->nvm.ops.read(hw, (NVM_COMB_VER_OFF + comb_offset | |||||
+ 1), 1, &comb_verh); | |||||
hw->nvm.ops.read(hw, (NVM_COMB_VER_OFF + comb_offset), | |||||
1, &comb_verl); | |||||
/* get Option Rom version if it exists and is valid */ | |||||
if ((comb_verh && comb_verl) && | |||||
((comb_verh != NVM_VER_INVALID) && | |||||
(comb_verl != NVM_VER_INVALID))) { | |||||
fw_vers->or_valid = true; | |||||
fw_vers->or_major = | |||||
comb_verl >> NVM_COMB_VER_SHFT; | |||||
fw_vers->or_build = | |||||
(comb_verl << NVM_COMB_VER_SHFT) | |||||
| (comb_verh >> NVM_COMB_VER_SHFT); | |||||
fw_vers->or_patch = | |||||
comb_verh & NVM_COMB_VER_MASK; | |||||
} | |||||
} | |||||
break; | |||||
default: | |||||
hw->nvm.ops.read(hw, NVM_ETRACK_HIWORD, 1, &etrack_test); | |||||
return; | |||||
} | |||||
hw->nvm.ops.read(hw, NVM_VERSION, 1, &fw_version); | |||||
fw_vers->eep_major = (fw_version & NVM_MAJOR_MASK) | |||||
>> NVM_MAJOR_SHIFT; | |||||
/* check for old style version format in newer images*/ | |||||
if ((fw_version & NVM_NEW_DEC_MASK) == 0x0) { | |||||
eeprom_verl = (fw_version & NVM_COMB_VER_MASK); | |||||
} else { | |||||
eeprom_verl = (fw_version & NVM_MINOR_MASK) | |||||
>> NVM_MINOR_SHIFT; | |||||
} | |||||
/* Convert minor value to hex before assigning to output struct | |||||
* Val to be converted will not be higher than 99, per tool output | |||||
*/ | |||||
q = eeprom_verl / NVM_HEX_CONV; | |||||
hval = q * NVM_HEX_TENS; | |||||
rem = eeprom_verl % NVM_HEX_CONV; | |||||
result = hval + rem; | |||||
fw_vers->eep_minor = result; | |||||
etrack_id: | |||||
if ((etrack_test & NVM_MAJOR_MASK) == NVM_ETRACK_VALID) { | |||||
hw->nvm.ops.read(hw, NVM_ETRACK_WORD, 1, &eeprom_verl); | |||||
hw->nvm.ops.read(hw, (NVM_ETRACK_WORD + 1), 1, &eeprom_verh); | |||||
fw_vers->etrack_id = (eeprom_verh << NVM_ETRACK_SHIFT) | |||||
| eeprom_verl; | |||||
} else if ((etrack_test & NVM_ETRACK_VALID) == 0) { | |||||
hw->nvm.ops.read(hw, NVM_ETRACK_WORD, 1, &eeprom_verh); | |||||
hw->nvm.ops.read(hw, (NVM_ETRACK_WORD + 1), 1, &eeprom_verl); | |||||
fw_vers->etrack_id = (eeprom_verh << NVM_ETRACK_SHIFT) | | |||||
eeprom_verl; | |||||
} | |||||
} | } | ||||