The i211 does not support an external EEPROM only a OTP
authorjsg <jsg@openbsd.org>
Tue, 12 May 2015 02:33:39 +0000 (02:33 +0000)
committerjsg <jsg@openbsd.org>
Tue, 12 May 2015 02:33:39 +0000 (02:33 +0000)
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
sys/dev/pci/if_em_hw.c
sys/dev/pci/if_em_hw.h

index 8717fa4..cc55e79 100644 (file)
@@ -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 <dev/pci/if_em.h>
@@ -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);
index bcd1c04..6a0d4ea 100644 (file)
@@ -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)
index f7c8d6a..bded07a 100644 (file)
@@ -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) |\