diff options
author | Robert Mustacchi <rm@joyent.com> | 2012-01-09 21:46:46 +0000 |
---|---|---|
committer | Robert Mustacchi <rm@joyent.com> | 2012-01-09 23:20:18 +0000 |
commit | 4b5a316acf0f02f1c4823637cdfa088b8bd2340b (patch) | |
tree | fb6cf6e08b23db92af58bc657dde0f2a40660e55 | |
parent | 4d2d8dff541450ab7fae5a4da53ae2b243414f8d (diff) | |
download | illumos-joyent-4b5a316acf0f02f1c4823637cdfa088b8bd2340b.tar.gz |
OS-850 Add support for Intel copper quad I350 to igb.
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
-rw-r--r-- | usr/src/uts/common/io/igb/igb_82575.c | 286 | ||||
-rw-r--r-- | usr/src/uts/common/io/igb/igb_82575.h | 4 | ||||
-rw-r--r-- | usr/src/uts/common/io/igb/igb_api.c | 6 | ||||
-rw-r--r-- | usr/src/uts/common/io/igb/igb_defines.h | 16 | ||||
-rw-r--r-- | usr/src/uts/common/io/igb/igb_hw.h | 5 | ||||
-rw-r--r-- | usr/src/uts/common/io/igb/igb_main.c | 41 | ||||
-rw-r--r-- | usr/src/uts/common/io/igb/igb_regs.h | 10 |
7 files changed, 356 insertions, 12 deletions
diff --git a/usr/src/uts/common/io/igb/igb_82575.c b/usr/src/uts/common/io/igb/igb_82575.c index 3a3fcc2d4f..462107a49d 100644 --- a/usr/src/uts/common/io/igb/igb_82575.c +++ b/usr/src/uts/common/io/igb/igb_82575.c @@ -20,7 +20,7 @@ */ /* - * Copyright(c) 2007-2010 Intel Corporation. All rights reserved. + * Copyright(c) 2007-2012 Intel Corporation. All rights reserved. */ /* @@ -80,6 +80,15 @@ static void e1000_power_down_phy_copper_82575(struct e1000_hw *hw); static void e1000_shutdown_serdes_link_82575(struct e1000_hw *hw); static s32 e1000_set_pcie_completion_timeout(struct e1000_hw *hw); +static s32 e1000_update_nvm_checksum_with_offset(struct e1000_hw *hw, + u16 offset); +static s32 e1000_validate_nvm_checksum_with_offset(struct e1000_hw *hw, + u16 offset); +static s32 e1000_validate_nvm_checksum_i350(struct e1000_hw *hw); +static s32 e1000_update_nvm_checksum_i350(struct e1000_hw *hw); +static void e1000_write_vfta_i350(struct e1000_hw *hw, u32 offset, u32 value); +static void e1000_clear_vfta_i350(struct e1000_hw *hw); + static const u16 e1000_82580_rxpbs_table[] = {36, 72, 144, 1, 2, 4, 8, 16, 35, 70, 140}; #define E1000_82580_RXPBS_TABLE_SIZE \ @@ -151,6 +160,7 @@ e1000_init_phy_params_82575(struct e1000_hw *hw) phy->ops.set_d3_lplu_state = e1000_set_d3_lplu_state_generic; break; case I82580_I_PHY_ID: + case I350_I_PHY_ID: phy->type = e1000_phy_82580; phy->ops.check_polarity = e1000_check_polarity_82577; phy->ops.force_speed_duplex = @@ -222,6 +232,17 @@ e1000_init_nvm_params_82575(struct e1000_hw *hw) nvm->ops.validate = e1000_validate_nvm_checksum_generic; nvm->ops.write = e1000_write_nvm_spi; + /* override genric family function pointers for specific descendants */ + switch (hw->mac.type) { + case e1000_i350: + nvm->ops.validate = e1000_validate_nvm_checksum_i350; + nvm->ops.update = e1000_update_nvm_checksum_i350; + break; + default: + break; + } + + return (E1000_SUCCESS); } @@ -284,6 +305,11 @@ e1000_init_mac_params_82575(struct e1000_hw *hw) mac->rar_entry_count = E1000_RAR_ENTRIES_82576; if (mac->type == e1000_82580) mac->rar_entry_count = E1000_RAR_ENTRIES_82580; + if (mac->type == e1000_i350) { + mac->rar_entry_count = E1000_RAR_ENTRIES_I350; + /* Enable EEE default settings for i350 */ + dev_spec->eee_disable = B_FALSE; + } /* Set if part includes ASF firmware */ mac->asf_firmware_present = true; /* Set if manageability features are enabled. */ @@ -319,10 +345,18 @@ e1000_init_mac_params_82575(struct e1000_hw *hw) mac->ops.read_mac_addr = e1000_read_mac_addr_82575; /* multicast address update */ mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic; - /* writing VFTA */ - mac->ops.write_vfta = e1000_write_vfta_generic; - /* clearing VFTA */ - mac->ops.clear_vfta = e1000_clear_vfta_generic; + + if (hw->mac.type == e1000_i350) { + /* writing VFTA */ + mac->ops.write_vfta = e1000_write_vfta_i350; + /* clearing VFTA */ + mac->ops.clear_vfta = e1000_clear_vfta_i350; + } else { + /* writing VFTA */ + mac->ops.write_vfta = e1000_write_vfta_generic; + /* clearing VFTA */ + mac->ops.clear_vfta = e1000_clear_vfta_generic; + } /* setting MTA */ mac->ops.mta_set = e1000_mta_set_generic; /* ID LED init */ @@ -697,6 +731,22 @@ e1000_acquire_nvm_82575(struct e1000_hw *hw) if (ret_val) goto out; + /* + * Check if there is some access + * error this access may hook on + */ + if (hw->mac.type == e1000_i350) { + u32 eecd = E1000_READ_REG(hw, E1000_EECD); + if (eecd & (E1000_EECD_BLOCKED | E1000_EECD_ABORT | + E1000_EECD_TIMEOUT)) { + /* Clear all access error flags */ + E1000_WRITE_REG(hw, E1000_EECD, eecd | + E1000_EECD_ERROR_CLR); + DEBUGOUT("Nvm bit banging access error " + "detected and cleared.\n"); + } + } + ret_val = e1000_acquire_nvm_generic(hw); if (ret_val) @@ -1866,3 +1916,229 @@ e1000_rxpbs_adjust_82580(u32 data) return (ret_val); } + +/* + * Due to a hw errata, if the host tries to configure the VFTA register + * while performing queries from the BMC or DMA, then the VFTA in some + * cases won't be written. + */ + +/* + * e1000_clear_vfta_i350 - Clear VLAN filter table + * @hw: pointer to the HW structure + * + * Clears the register array which contains the VLAN filter table by + * setting all the values to 0. + */ +void +e1000_clear_vfta_i350(struct e1000_hw *hw) +{ + u32 offset; + int i; + + DEBUGFUNC("e1000_clear_vfta_350"); + + for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) { + for (i = 0; i < 10; i++) + E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, 0); + + E1000_WRITE_FLUSH(hw); + } +} + +/* + * e1000_write_vfta_i350 - Write value to VLAN filter table + * @hw: pointer to the HW structure + * @offset: register offset in VLAN filter table + * @value: register value written to VLAN filter table + * + * Writes value at the given offset in the register array which stores + * the VLAN filter table. + */ +void +e1000_write_vfta_i350(struct e1000_hw *hw, u32 offset, u32 value) +{ + int i; + + DEBUGFUNC("e1000_write_vfta_350"); + + for (i = 0; i < 10; i++) + E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, value); + + E1000_WRITE_FLUSH(hw); +} + +/* + * e1000_validate_nvm_checksum_with_offset - Validate EEPROM + * checksum + * @hw: pointer to the HW structure + * @offset: offset in words of the checksum protected region + * + * Calculates the EEPROM checksum by reading/adding each word of the EEPROM + * and then verifies that the sum of the EEPROM is equal to 0xBABA. + */ +s32 +e1000_validate_nvm_checksum_with_offset(struct e1000_hw *hw, u16 offset) +{ + s32 ret_val = E1000_SUCCESS; + u16 checksum = 0; + u16 i, nvm_data; + + DEBUGFUNC("e1000_validate_nvm_checksum_with_offset"); + + for (i = offset; i < ((NVM_CHECKSUM_REG + offset) + 1); i++) { + ret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data); + if (ret_val) { + DEBUGOUT("NVM Read Error\n"); + goto out; + } + checksum += nvm_data; + } + + if (checksum != (u16) NVM_SUM) { + DEBUGOUT("NVM Checksum Invalid\n"); + ret_val = -E1000_ERR_NVM; + goto out; + } + +out: + return (ret_val); +} + +/* + * e1000_update_nvm_checksum_with_offset - Update EEPROM + * checksum + * @hw: pointer to the HW structure + * @offset: offset in words of the checksum protected region + * + * Updates the EEPROM checksum by reading/adding each word of the EEPROM + * up to the checksum. Then calculates the EEPROM checksum and writes the + * value to the EEPROM. + */ +s32 +e1000_update_nvm_checksum_with_offset(struct e1000_hw *hw, u16 offset) +{ + s32 ret_val; + u16 checksum = 0; + u16 i, nvm_data; + + DEBUGFUNC("e1000_update_nvm_checksum_with_offset"); + + for (i = offset; i < (NVM_CHECKSUM_REG + offset); i++) { + ret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data); + if (ret_val) { + DEBUGOUT("NVM Read Error while updating checksum.\n"); + goto out; + } + checksum += nvm_data; + } + checksum = (u16) NVM_SUM - checksum; + ret_val = hw->nvm.ops.write(hw, (NVM_CHECKSUM_REG + offset), 1, + &checksum); + if (ret_val) + DEBUGOUT("NVM Write Error while updating checksum.\n"); + +out: + return (ret_val); +} + +/* + * e1000_validate_nvm_checksum_i350 - Validate EEPROM checksum + * @hw: pointer to the HW structure + * + * Calculates the EEPROM section checksum by reading/adding each word of + * the EEPROM and then verifies that the sum of the EEPROM is + * equal to 0xBABA. + */ +static s32 +e1000_validate_nvm_checksum_i350(struct e1000_hw *hw) +{ + s32 ret_val = E1000_SUCCESS; + u16 j; + u16 nvm_offset; + + DEBUGFUNC("e1000_validate_nvm_checksum_i350"); + + for (j = 0; j < 4; j++) { + nvm_offset = NVM_82580_LAN_FUNC_OFFSET(j); + ret_val = e1000_validate_nvm_checksum_with_offset(hw, + nvm_offset); + if (ret_val != E1000_SUCCESS) + goto out; + } + +out: + return (ret_val); +} + +/* + * e1000_update_nvm_checksum_i350 - Update EEPROM checksum + * @hw: pointer to the HW structure + * + * Updates the EEPROM section checksums for all 4 ports by reading/adding + * each word of the EEPROM up to the checksum. Then calculates the EEPROM + * checksum and writes the value to the EEPROM. + */ +static s32 +e1000_update_nvm_checksum_i350(struct e1000_hw *hw) +{ + s32 ret_val = E1000_SUCCESS; + u16 j; + u16 nvm_offset; + + DEBUGFUNC("e1000_update_nvm_checksum_i350"); + + for (j = 0; j < 4; j++) { + nvm_offset = NVM_82580_LAN_FUNC_OFFSET(j); + ret_val = e1000_update_nvm_checksum_with_offset(hw, nvm_offset); + if (ret_val != E1000_SUCCESS) + goto out; + } + +out: + return (ret_val); +} + + + +/* + * e1000_set_eee_i350 - Enable/disable EEE support + * @hw: pointer to the HW structure + * + * Enable/disable EEE based on setting in dev_spec structure. + * + */ +s32 +e1000_set_eee_i350(struct e1000_hw *hw) +{ + + s32 ret_val = E1000_SUCCESS; + u32 ipcnfg, eeer; + + DEBUGFUNC("e1000_set_eee_i350"); + + if ((hw->mac.type < e1000_i350) || + (hw->phy.media_type != e1000_media_type_copper)) + goto out; + ipcnfg = E1000_READ_REG(hw, E1000_IPCNFG); + eeer = E1000_READ_REG(hw, E1000_EEER); + + /* enable or disable per user setting */ + if (!(hw->dev_spec._82575.eee_disable)) { + ipcnfg |= (E1000_IPCNFG_EEE_1G_AN | E1000_IPCNFG_EEE_100M_AN); + eeer |= (E1000_EEER_TX_LPI_EN | E1000_EEER_RX_LPI_EN | + E1000_EEER_LPI_FC); + + } else { + ipcnfg &= ~(E1000_IPCNFG_EEE_1G_AN | E1000_IPCNFG_EEE_100M_AN); + eeer &= ~(E1000_EEER_TX_LPI_EN | E1000_EEER_RX_LPI_EN | + E1000_EEER_LPI_FC); + } + E1000_WRITE_REG(hw, E1000_IPCNFG, ipcnfg); + E1000_WRITE_REG(hw, E1000_EEER, eeer); + E1000_READ_REG(hw, E1000_IPCNFG); + E1000_READ_REG(hw, E1000_EEER); +out: + + return (ret_val); +} diff --git a/usr/src/uts/common/io/igb/igb_82575.h b/usr/src/uts/common/io/igb/igb_82575.h index 8f0add0b4b..2d9c657447 100644 --- a/usr/src/uts/common/io/igb/igb_82575.h +++ b/usr/src/uts/common/io/igb/igb_82575.h @@ -20,7 +20,7 @@ */ /* - * Copyright(c) 2007-2010 Intel Corporation. All rights reserved. + * Copyright(c) 2007-2012 Intel Corporation. All rights reserved. */ /* @@ -54,6 +54,7 @@ extern "C" { #define E1000_RAR_ENTRIES_82575 16 #define E1000_RAR_ENTRIES_82576 24 #define E1000_RAR_ENTRIES_82580 24 +#define E1000_RAR_ENTRIES_I350 32 #define E1000_SW_SYNCH_MB 0x00000100 #define E1000_STAT_DEV_RST_SET 0x00100000 #define E1000_CTRL_DEV_RST 0x20000000 @@ -466,6 +467,7 @@ struct e1000_adv_tx_context_desc { void e1000_vmdq_set_loopback_pf(struct e1000_hw *hw, bool enable); void e1000_vmdq_set_replication_pf(struct e1000_hw *hw, bool enable); u16 e1000_rxpbs_adjust_82580(u32 data); +s32 e1000_set_eee_i350(struct e1000_hw *hw); #ifdef __cplusplus } diff --git a/usr/src/uts/common/io/igb/igb_api.c b/usr/src/uts/common/io/igb/igb_api.c index 2da7c1926a..c966508281 100644 --- a/usr/src/uts/common/io/igb/igb_api.c +++ b/usr/src/uts/common/io/igb/igb_api.c @@ -20,7 +20,7 @@ */ /* - * Copyright(c) 2007-2010 Intel Corporation. All rights reserved. + * Copyright(c) 2007-2012 Intel Corporation. All rights reserved. */ /* @@ -151,6 +151,9 @@ e1000_set_mac_type(struct e1000_hw *hw) case E1000_DEV_ID_82580_COPPER_DUAL: mac->type = e1000_82580; break; + case E1000_DEV_ID_I350_COPPER: + mac->type = e1000_i350; + break; default: /* Should never have loaded on this device */ ret_val = -E1000_ERR_MAC_INIT; @@ -207,6 +210,7 @@ e1000_setup_init_funcs(struct e1000_hw *hw, bool init_device) case e1000_82575: case e1000_82576: case e1000_82580: + case e1000_i350: e1000_init_function_pointers_82575(hw); break; default: diff --git a/usr/src/uts/common/io/igb/igb_defines.h b/usr/src/uts/common/io/igb/igb_defines.h index 8545a82b9c..a152f3fb1a 100644 --- a/usr/src/uts/common/io/igb/igb_defines.h +++ b/usr/src/uts/common/io/igb/igb_defines.h @@ -20,7 +20,7 @@ */ /* - * Copyright(c) 2007-2010 Intel Corporation. All rights reserved. + * Copyright(c) 2007-2012 Intel Corporation. All rights reserved. */ /* @@ -1007,6 +1007,14 @@ extern "C" { #define E1000_IMIR_PRIORITY_SHIFT 29 /* IMIR Priority Shift */ #define E1000_IMIREXT_CLEAR_MASK 0x7FFFF /* IMIREXT Reg Clear Mask */ +/* I350 EEE defines */ +#define E1000_IPCNFG_EEE_1G_AN 0x00000008 /* IPCNFG EEE Ena 1G AN */ +#define E1000_IPCNFG_EEE_100M_AN 0x00000004 /* IPCNFG EEE Ena 100M AN */ +#define E1000_EEER_TX_LPI_EN 0x00010000 /* EEER Tx LPI Enable */ +#define E1000_EEER_RX_LPI_EN 0x00020000 /* EEER Rx LPI Enable */ +#define E1000_EEER_LPI_FC 0x00040000 /* EEER Ena on Flow Cntrl */ + + /* PCI Express Control */ #define E1000_GCR_RXD_NO_SNOOP 0x00000001 #define E1000_GCR_RXDSCW_NO_SNOOP 0x00000002 @@ -1148,6 +1156,11 @@ extern "C" { #define E1000_EECD_GNT 0x00000080 /* NVM Access Grant */ #define E1000_EECD_PRES 0x00000100 /* NVM Present */ #define E1000_EECD_SIZE 0x00000200 /* NVM Size (0=64 word 1=256 word) */ +#define E1000_EECD_BLOCKED 0x00008000 /* Bit banging access blocked flag */ +#define E1000_EECD_ABORT 0x00010000 /* NVM operation aborted flag */ +#define E1000_EECD_TIMEOUT 0x00020000 /* NVM read operation timeout flag */ +#define E1000_EECD_ERROR_CLR 0x00040000 /* NVM error status clear bit */ + /* NVM Addressing bits based on type 0=small, 1=large */ #define E1000_EECD_ADDR_BITS 0x00000400 #define E1000_EECD_TYPE 0x00002000 /* NVM Type (1-SPI, 0-Microwire) */ @@ -1307,6 +1320,7 @@ extern "C" { #define IFE_PLUS_E_PHY_ID 0x02A80320 #define IFE_C_E_PHY_ID 0x02A80310 #define I82580_I_PHY_ID 0x015403A0 +#define I350_I_PHY_ID 0x015403B0 #define IGP04E1000_E_PHY_ID 0x02A80391 #define M88_VENDOR 0x0141 diff --git a/usr/src/uts/common/io/igb/igb_hw.h b/usr/src/uts/common/io/igb/igb_hw.h index fbeef29b94..68082f977d 100644 --- a/usr/src/uts/common/io/igb/igb_hw.h +++ b/usr/src/uts/common/io/igb/igb_hw.h @@ -20,7 +20,7 @@ */ /* - * Copyright(c) 2007-2010 Intel Corporation. All rights reserved. + * Copyright(c) 2007-2012 Intel Corporation. All rights reserved. */ /* @@ -57,6 +57,7 @@ struct e1000_hw; #define E1000_DEV_ID_82580_SERDES 0x1510 #define E1000_DEV_ID_82580_SGMII 0x1511 #define E1000_DEV_ID_82580_COPPER_DUAL 0x1516 +#define E1000_DEV_ID_I350_COPPER 0x1521 #define E1000_REVISION_0 0 #define E1000_REVISION_1 1 @@ -79,6 +80,7 @@ enum e1000_mac_type { e1000_82575, e1000_82576, e1000_82580, + e1000_i350, e1000_num_macs /* List is 1-based, so subtract 1 for true count. */ }; @@ -640,6 +642,7 @@ struct e1000_fc_info { struct e1000_dev_spec_82575 { bool sgmii_active; bool global_device_reset; + int eee_disable; }; struct e1000_dev_spec_vf { diff --git a/usr/src/uts/common/io/igb/igb_main.c b/usr/src/uts/common/io/igb/igb_main.c index 2d5d813198..200f0bd1a1 100644 --- a/usr/src/uts/common/io/igb/igb_main.c +++ b/usr/src/uts/common/io/igb/igb_main.c @@ -20,7 +20,7 @@ */ /* - * Copyright(c) 2007-2010 Intel Corporation. All rights reserved. + * Copyright(c) 2007-2012 Intel Corporation. All rights reserved. */ /* @@ -30,7 +30,7 @@ #include "igb_sw.h" static char ident[] = "Intel 1Gb Ethernet"; -static char igb_version[] = "igb 1.1.17"; +static char igb_version[] = "igb 1.1.18"; /* * Local function protoypes @@ -285,6 +285,30 @@ static adapter_info_t igb_82580_cap = { 0xffe00000 /* mask for RXDCTL register */ }; +static adapter_info_t igb_i350_cap = { + /* limits */ + 8, /* maximum number of rx queues */ + 1, /* minimum number of rx queues */ + 4, /* default number of rx queues */ + 8, /* maximum number of tx queues */ + 1, /* minimum number of tx queues */ + 4, /* default number of tx queues */ + 65535, /* maximum interrupt throttle rate */ + 0, /* minimum interrupt throttle rate */ + 200, /* default interrupt throttle rate */ + + /* function pointers */ + igb_enable_adapter_interrupts_82580, + igb_setup_msix_82580, + + /* capabilities */ + (IGB_FLAG_HAS_DCA | /* capability flags */ + IGB_FLAG_VMDQ_POOL | + IGB_FLAG_NEED_CTX_IDX), + + 0xffe00000 /* mask for RXDCTL register */ +}; + /* * Module Initialization Functions */ @@ -517,6 +541,13 @@ igb_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd) igb_log(igb, "%s", igb_version); atomic_or_32(&igb->igb_state, IGB_INITIALIZED); + /* + * Newer models have Energy Efficient Ethernet, let's disable this by + * default. + */ + if (igb->hw.mac.type == e1000_i350) + e1000_set_eee_i350(&igb->hw); + return (DDI_SUCCESS); attach_fail: @@ -836,6 +867,9 @@ igb_identify_hardware(igb_t *igb) case e1000_82580: igb->capab = &igb_82580_cap; break; + case e1000_i350: + igb->capab = &igb_i350_cap; + break; default: return (IGB_FAILURE); } @@ -1699,6 +1733,9 @@ igb_start(igb_t *igb, boolean_t alloc_buffer) if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK) goto start_failure; + if (igb->hw.mac.type == e1000_i350) + e1000_set_eee_i350(&igb->hw); + for (i = igb->num_tx_rings - 1; i >= 0; i--) mutex_exit(&igb->tx_rings[i].tx_lock); for (i = igb->num_rx_rings - 1; i >= 0; i--) diff --git a/usr/src/uts/common/io/igb/igb_regs.h b/usr/src/uts/common/io/igb/igb_regs.h index ac7c5847f5..0d0f2c4228 100644 --- a/usr/src/uts/common/io/igb/igb_regs.h +++ b/usr/src/uts/common/io/igb/igb_regs.h @@ -20,7 +20,7 @@ */ /* - * Copyright(c) 2007-2010 Intel Corporation. All rights reserved. + * Copyright(c) 2007-2012 Intel Corporation. All rights reserved. */ /* @@ -570,6 +570,14 @@ extern "C" { /* PCIe Parity Status Register */ #define E1000_PCIEERRSTS 0x05BA8 +/* Energy Efficient Ethernet "EEE" registers */ +#define E1000_IPCNFG 0x0E38 /* Internal PHY Configuration */ +#define E1000_LTRC 0x01A0 /* Latency Tolerance Reporting Control */ +#define E1000_EEER 0x0E30 /* Energy Efficient Ethernet "EEE" */ +#define E1000_EEE_SU 0x0E34 /* EEE Setup */ +#define E1000_TLPIC 0x4148 /* EEE Tx LPI Count - TLPIC */ +#define E1000_RLPIC 0x414C /* EEE Rx LPI Count - RLPIC */ + #ifdef __cplusplus } #endif |