summaryrefslogtreecommitdiff
path: root/sys/dev/pci/if_em_hw.c
diff options
context:
space:
mode:
authorJonathan Gray <jsg@cvs.openbsd.org>2015-05-12 02:33:40 +0000
committerJonathan Gray <jsg@cvs.openbsd.org>2015-05-12 02:33:40 +0000
commit1d0334cdb878ca5d092d4ccc042bc38c5d6c020b (patch)
treea35f36aeedc987b34031fa3473268e930301a539 /sys/dev/pci/if_em_hw.c
parent4bd7915bc930dc864492e3a2a19d3eb1ce4a186a (diff)
The i211 does not support an external EEPROM only a OTP
Internal Non-Volatile Memory (iNVM). Add support for reading words out of it instead of an EEPROM. From Patrick Wildt with some more offsets added.
Diffstat (limited to 'sys/dev/pci/if_em_hw.c')
-rw-r--r--sys/dev/pci/if_em_hw.c150
1 files changed, 149 insertions, 1 deletions
diff --git a/sys/dev/pci/if_em_hw.c b/sys/dev/pci/if_em_hw.c
index bcd1c0421ba..6a0d4ea0d30 100644
--- a/sys/dev/pci/if_em_hw.c
+++ b/sys/dev/pci/if_em_hw.c
@@ -31,7 +31,7 @@
*******************************************************************************/
-/* $OpenBSD: if_em_hw.c,v 1.83 2015/03/14 03:38:48 jsg Exp $ */
+/* $OpenBSD: if_em_hw.c,v 1.84 2015/05/12 02:33:39 jsg Exp $ */
/*
* if_em_hw.c Shared functions for accessing and configuring the MAC
*/
@@ -112,6 +112,9 @@ static int32_t em_read_eeprom_ich8(struct em_hw *, uint16_t, uint16_t,
uint16_t *);
static int32_t em_write_eeprom_ich8(struct em_hw *, uint16_t, uint16_t,
uint16_t *);
+static int32_t em_read_invm_i210(struct em_hw *, uint16_t, uint16_t,
+ uint16_t *);
+static int32_t em_read_invm_word_i210(struct em_hw *, uint16_t, uint16_t *);
static void em_release_software_flag(struct em_hw *);
static int32_t em_set_d3_lplu_state(struct em_hw *, boolean_t);
static int32_t em_set_d0_lplu_state(struct em_hw *, boolean_t);
@@ -5522,6 +5525,12 @@ em_init_eeprom_params(struct em_hw *hw)
eecd &= ~E1000_EECD_AUPDEN;
E1000_WRITE_REG(hw, EECD, eecd);
}
+ if (em_get_flash_presence_i210(hw) == FALSE) {
+ eeprom->type = em_eeprom_invm;
+ eeprom->word_size = INVM_SIZE;
+ eeprom->use_eerd = FALSE;
+ eeprom->use_eewr = FALSE;
+ }
break;
case em_80003es2lan:
eeprom->type = em_eeprom_spi;
@@ -5985,6 +5994,7 @@ em_read_eeprom(struct em_hw *hw, uint16_t offset, uint16_t words,
* FW or other port software does not interrupt.
*/
if (em_is_onboard_nvm_eeprom(hw) == TRUE &&
+ em_get_flash_presence_i210(hw) == TRUE &&
hw->eeprom.use_eerd == FALSE) {
/* Prepare the EEPROM for bit-bang reading */
if (em_acquire_eeprom(hw) != E1000_SUCCESS)
@@ -5997,6 +6007,11 @@ em_read_eeprom(struct em_hw *hw, uint16_t offset, uint16_t words,
/* ICH EEPROM access is done via the ICH flash controller */
if (eeprom->type == em_eeprom_ich8)
return em_read_eeprom_ich8(hw, offset, words, data);
+
+ /* Some i210/i211 have a special OTP chip */
+ if (eeprom->type == em_eeprom_invm)
+ return em_read_invm_i210(hw, offset, words, data);
+
/*
* Set up the SPI or Microwire EEPROM for bit-bang reading. We have
* acquired the EEPROM at this point, so any returns should relase it
@@ -6181,6 +6196,28 @@ em_is_onboard_nvm_eeprom(struct em_hw *hw)
}
/******************************************************************************
+ * Check if flash device is detected.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+boolean_t
+em_get_flash_presence_i210(struct em_hw *hw)
+{
+ uint32_t eecd;
+ DEBUGFUNC("em_get_flash_presence_i210");
+
+ if (hw->mac_type != em_i210)
+ return TRUE;
+
+ eecd = E1000_READ_REG(hw, EECD);
+
+ if (eecd & E1000_EECD_FLUPD)
+ return TRUE;
+
+ return FALSE;
+}
+
+/******************************************************************************
* Verifies that the EEPROM has a valid checksum
*
* hw - Struct containing variables accessed by shared code
@@ -9729,6 +9766,117 @@ em_erase_ich8_4k_segment(struct em_hw *hw, uint32_t bank)
return error;
}
+/******************************************************************************
+ * Reads 16-bit words from the OTP. Return error when the word is not
+ * stored in OTP.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - offset of word in the OTP to read
+ * data - word read from the OTP
+ * words - number of words to read
+ *****************************************************************************/
+STATIC int32_t
+em_read_invm_i210(struct em_hw *hw, uint16_t offset, uint16_t words,
+ uint16_t *data)
+{
+ int32_t ret_val = E1000_SUCCESS;
+
+ switch (offset)
+ {
+ case EEPROM_MAC_ADDR_WORD0:
+ case EEPROM_MAC_ADDR_WORD1:
+ case EEPROM_MAC_ADDR_WORD2:
+ /* Generate random MAC address if there's none. */
+ ret_val = em_read_invm_word_i210(hw, offset, data);
+ if (ret_val != E1000_SUCCESS) {
+ DEBUGOUT("MAC Addr not found in iNVM\n");
+ *data = 0xFFFF;
+ ret_val = E1000_SUCCESS;
+ }
+ break;
+ case EEPROM_INIT_CONTROL2_REG:
+ ret_val = em_read_invm_word_i210(hw, offset, data);
+ if (ret_val != E1000_SUCCESS) {
+ *data = NVM_INIT_CTRL_2_DEFAULT_I211;
+ ret_val = E1000_SUCCESS;
+ }
+ break;
+ case EEPROM_INIT_CONTROL4_REG:
+ ret_val = em_read_invm_word_i210(hw, offset, data);
+ if (ret_val != E1000_SUCCESS) {
+ *data = NVM_INIT_CTRL_4_DEFAULT_I211;
+ ret_val = E1000_SUCCESS;
+ }
+ break;
+ case EEPROM_LED_1_CFG:
+ ret_val = em_read_invm_word_i210(hw, offset, data);
+ if (ret_val != E1000_SUCCESS) {
+ *data = NVM_LED_1_CFG_DEFAULT_I211;
+ ret_val = E1000_SUCCESS;
+ }
+ break;
+ case EEPROM_LED_0_2_CFG:
+ ret_val = em_read_invm_word_i210(hw, offset, data);
+ if (ret_val != E1000_SUCCESS) {
+ *data = NVM_LED_0_2_CFG_DEFAULT_I211;
+ ret_val = E1000_SUCCESS;
+ }
+ break;
+ case EEPROM_ID_LED_SETTINGS:
+ ret_val = em_read_invm_word_i210(hw, offset, data);
+ if (ret_val != E1000_SUCCESS) {
+ *data = ID_LED_RESERVED_FFFF;
+ ret_val = E1000_SUCCESS;
+ }
+ break;
+ default:
+ DEBUGOUT1("NVM word 0x%02x is not mapped.\n", offset);
+ *data = NVM_RESERVED_WORD;
+ break;
+ }
+
+ return ret_val;
+}
+
+/******************************************************************************
+ * Reads 16-bit words from the OTP. Return error when the word is not
+ * stored in OTP.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - offset of word in the OTP to read
+ * data - word read from the OTP
+ *****************************************************************************/
+STATIC int32_t
+em_read_invm_word_i210(struct em_hw *hw, uint16_t address, uint16_t *data)
+{
+ int32_t error = -E1000_NOT_IMPLEMENTED;
+ uint32_t invm_dword;
+ uint16_t i;
+ uint8_t record_type, word_address;
+
+ for (i = 0; i < INVM_SIZE; i++) {
+ invm_dword = EM_READ_REG(hw, E1000_INVM_DATA_REG(i));
+ /* Get record type */
+ record_type = INVM_DWORD_TO_RECORD_TYPE(invm_dword);
+ if (record_type == INVM_UNINITIALIZED_STRUCTURE)
+ break;
+ if (record_type == INVM_CSR_AUTOLOAD_STRUCTURE)
+ i += INVM_CSR_AUTOLOAD_DATA_SIZE_IN_DWORDS;
+ if (record_type == INVM_RSA_KEY_SHA256_STRUCTURE)
+ i += INVM_RSA_KEY_SHA256_DATA_SIZE_IN_DWORDS;
+ if (record_type == INVM_WORD_AUTOLOAD_STRUCTURE) {
+ word_address = INVM_DWORD_TO_WORD_ADDRESS(invm_dword);
+ if (word_address == address) {
+ *data = INVM_DWORD_TO_WORD_DATA(invm_dword);
+ error = E1000_SUCCESS;
+ break;
+ }
+ }
+ }
+
+ return error;
+}
+
STATIC int32_t
em_init_lcd_from_nvm_config_region(struct em_hw *hw, uint32_t cnf_base_addr,
uint32_t cnf_size)