Any updates on this?
> Am 09.03.2015 um 07:32 schrieb Patrick Wildt <m...@patrick-wildt.de>:
>
> Hi,
>
> this diff adds support for a special configuration of i210/i211 chips.
>
> Those can have a OTP chip instead of the usual EEPROM, so this diff
> adds the infrastructure to read needed data from OTP and have it not
> bail out when there's no EEPROM.
>
> \Patrick
>
> diff --git a/sys/dev/pci/if_em.c b/sys/dev/pci/if_em.c
> index 8717fa4..10cdc52 100644
> --- sys/dev/pci/if_em.c
> +++ sys/dev/pci/if_em.c
> @@ -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 16cd3ee..4994c4d 100644
> --- sys/dev/pci/if_em_hw.c
> +++ sys/dev/pci/if_em_hw.c
> @@ -113,6 +113,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);
> @@ -5523,6 +5526,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;
> @@ -5986,6 +5995,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)
> @@ -5998,6 +6008,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
> @@ -6182,6 +6197,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
> @@ -9730,6 +9767,84 @@ 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_ADDRESS:
> + case EEPROM_MAC_ADDRESS_WORD1:
> + case EEPROM_MAC_ADDRESS_WORD2:
> + /* Generate random MAC address if there's none. */
> + ret_val = em_read_invm_word_i210(hw, offset, data);
> + if (ret_val != E1000_SUCCESS) {
> + *data = 0xFFFF;
> + 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;
> + }
> +
> + 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 = E1000_READ_REG(hw, 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 3dd5488..a9bd1ca 100644
> --- sys/dev/pci/if_em_hw.h
> +++ sys/dev/pci/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_ADDRESS 0x0000
> +#define EEPROM_MAC_ADDRESS_WORD1 0x0001
> +#define EEPROM_MAC_ADDRESS_WORD2 0x0002
> #define EEPROM_COMPAT 0x0003
> #define EEPROM_ID_LED_SETTINGS 0x0004
> #define EEPROM_VERSION 0x0005
> @@ -3744,6 +3749,25 @@ 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 E1000_82542_INVM_DATA_REG(reg) E1000_INVM_DATA_REG(reg)
> +#define INVM_SIZE 64 /* Number of INVM Data
> Registers */
> +
> +#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) |\
>