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) |\

Reply via email to