From dbe2e91ef705b8176af91f767eb84ee6e738d112 Mon Sep 17 00:00:00 2001 From: jsg Date: Tue, 12 May 2015 02:33:39 +0000 Subject: [PATCH] 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. --- sys/dev/pci/if_em.c | 8 ++- sys/dev/pci/if_em_hw.c | 150 ++++++++++++++++++++++++++++++++++++++++- sys/dev/pci/if_em_hw.h | 35 +++++++++- 3 files changed, 188 insertions(+), 5 deletions(-) diff --git a/sys/dev/pci/if_em.c b/sys/dev/pci/if_em.c index 8717fa45228..cc55e79f685 100644 --- a/sys/dev/pci/if_em.c +++ b/sys/dev/pci/if_em.c @@ -31,7 +31,7 @@ POSSIBILITY OF SUCH DAMAGE. ***************************************************************************/ -/* $OpenBSD: if_em.c,v 1.295 2015/02/11 23:21:47 brad Exp $ */ +/* $OpenBSD: if_em.c,v 1.296 2015/05/12 02:33:39 jsg Exp $ */ /* $FreeBSD: if_em.c,v 1.46 2004/09/29 18:28:28 mlaier Exp $ */ #include @@ -1775,7 +1775,8 @@ em_hardware_init(struct em_softc *sc) sc->tx_fifo_head = 0; /* Make sure we have a good EEPROM before we read from it */ - if (em_validate_eeprom_checksum(&sc->hw) < 0) { + if (em_get_flash_presence_i210(&sc->hw) && + em_validate_eeprom_checksum(&sc->hw) < 0) { /* * Some PCIe parts fail the first check due to * the link being in sleep state, call it again, @@ -1788,7 +1789,8 @@ em_hardware_init(struct em_softc *sc) } } - if (em_read_part_num(&sc->hw, &(sc->part_num)) < 0) { + if (em_get_flash_presence_i210(&sc->hw) && + em_read_part_num(&sc->hw, &(sc->part_num)) < 0) { printf("%s: EEPROM read error while reading part number\n", sc->sc_dv.dv_xname); return (EIO); 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 @@ -6180,6 +6195,28 @@ em_is_onboard_nvm_eeprom(struct em_hw *hw) return TRUE; } +/****************************************************************************** + * 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 * @@ -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) diff --git a/sys/dev/pci/if_em_hw.h b/sys/dev/pci/if_em_hw.h index f7c8d6a2006..bded07a53c4 100644 --- a/sys/dev/pci/if_em_hw.h +++ b/sys/dev/pci/if_em_hw.h @@ -31,7 +31,7 @@ *******************************************************************************/ -/* $OpenBSD: if_em_hw.h,v 1.63 2015/04/01 18:49:32 gsoares Exp $ */ +/* $OpenBSD: if_em_hw.h,v 1.64 2015/05/12 02:33:39 jsg Exp $ */ /* $FreeBSD: if_em_hw.h,v 1.15 2005/05/26 23:32:02 tackerman Exp $ */ /* if_em_hw.h @@ -93,6 +93,7 @@ typedef enum { em_eeprom_microwire, em_eeprom_flash, em_eeprom_ich8, + em_eeprom_invm, em_eeprom_none, /* No NVM support */ em_num_eeprom_types } em_eeprom_type; @@ -409,6 +410,7 @@ int32_t em_validate_eeprom_checksum(struct em_hw *hw); int32_t em_update_eeprom_checksum(struct em_hw *hw); int32_t em_write_eeprom(struct em_hw *hw, uint16_t reg, uint16_t words, uint16_t *data); int32_t em_read_mac_addr(struct em_hw * hw); +boolean_t em_get_flash_presence_i210(struct em_hw *); /* Filters (multicast, vlan, receive) */ void em_mc_addr_list_update(struct em_hw *hw, uint8_t * mc_addr_list, uint32_t mc_addr_count, @@ -2464,6 +2466,9 @@ struct em_host_command_info { #define EEPROM_SIZE_MASK 0x1C00 /* EEPROM Word Offsets */ +#define EEPROM_MAC_ADDR_WORD0 0x0000 +#define EEPROM_MAC_ADDR_WORD1 0x0001 +#define EEPROM_MAC_ADDR_WORD2 0x0002 #define EEPROM_COMPAT 0x0003 #define EEPROM_ID_LED_SETTINGS 0x0004 #define EEPROM_VERSION 0x0005 @@ -2472,8 +2477,11 @@ struct em_host_command_info { #define EEPROM_INIT_CONTROL1_REG 0x000A #define EEPROM_INIT_CONTROL2_REG 0x000F #define EEPROM_SWDEF_PINS_CTRL_PORT_1 0x0010 +#define EEPROM_INIT_CONTROL4_REG 0x0013 #define EEPROM_INIT_CONTROL3_PORT_B 0x0014 #define EEPROM_INIT_3GIO_3 0x001A +#define EEPROM_LED_1_CFG 0x001C +#define EEPROM_LED_0_2_CFG 0x001F #define EEPROM_SWDEF_PINS_CTRL_PORT_0 0x0020 #define EEPROM_INIT_CONTROL3_PORT_A 0x0024 #define EEPROM_CFG 0x0012 @@ -3744,6 +3752,31 @@ union ich8_hws_flash_regacc { #define I82579_MSE_THRESHOLD 0x084F /* Mean Square Error Threshold */ #define I82579_MSE_LINK_DOWN 0x2411 /* MSE count before dropping link */ +/* INVM Registers for i210 */ +#define E1000_INVM_DATA_REG(reg) (0x12120 + 4*(reg)) +#define INVM_SIZE 64 /* Number of INVM Data Registers */ + +/* NVM offset defaults for i211 */ +#define NVM_INIT_CTRL_2_DEFAULT_I211 0x7243 +#define NVM_INIT_CTRL_4_DEFAULT_I211 0x00C1 +#define NVM_LED_1_CFG_DEFAULT_I211 0x0184 +#define NVM_LED_0_2_CFG_DEFAULT_I211 0x200C +#define NVM_RESERVED_WORD 0xFFFF + +#define INVM_DWORD_TO_RECORD_TYPE(dword) ((dword) & 0x7) +#define INVM_DWORD_TO_WORD_ADDRESS(dword) (((dword) & 0x0000FE00) >> 9) +#define INVM_DWORD_TO_WORD_DATA(dword) (((dword) & 0xFFFF0000) >> 16) + +#define INVM_UNINITIALIZED_STRUCTURE 0x0 +#define INVM_WORD_AUTOLOAD_STRUCTURE 0x1 +#define INVM_CSR_AUTOLOAD_STRUCTURE 0x2 +#define INVM_PHY_REGISTER_AUTOLOAD_STRUCTURE 0x3 +#define INVM_RSA_KEY_SHA256_STRUCTURE 0x4 +#define INVM_INVALIDATED_STRUCTURE 0x5 + +#define INVM_RSA_KEY_SHA256_DATA_SIZE_IN_DWORDS 8 +#define INVM_CSR_AUTOLOAD_DATA_SIZE_IN_DWORDS 1 + #define PHY_UPPER_SHIFT 21 #define BM_PHY_REG(page, reg) \ (((reg) & MAX_PHY_REG_ADDRESS) |\ -- 2.20.1