summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/dev/pci/if_em.c8
-rw-r--r--sys/dev/pci/if_em_hw.c150
-rw-r--r--sys/dev/pci/if_em_hw.h35
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 <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);
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)
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) |\