Mercurial > illumos > illumos-gate
changeset 13599:b51e5a82e5e2
2038 Add in I350 and ET2 support into igb
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Dan McDonald <danmcd@nexenta.com>
Reviewed by: Gordon Ross <gwr@nexenta.com>
Reviewed by: Garrett D'Amore <garrett@damore.org>
Approved by: Albert Lee <trisk@nexenta.com>
author | Robert Mustacchi <rm@joyent.com> |
---|---|
date | Mon, 06 Feb 2012 13:23:22 -0500 |
parents | 9db0a4a7c636 |
children | 45e723c4523d |
files | usr/src/pkg/manifests/driver-network-igb.mf usr/src/uts/common/io/igb/igb_82575.c usr/src/uts/common/io/igb/igb_82575.h usr/src/uts/common/io/igb/igb_api.c usr/src/uts/common/io/igb/igb_defines.h usr/src/uts/common/io/igb/igb_hw.h usr/src/uts/common/io/igb/igb_main.c usr/src/uts/common/io/igb/igb_regs.h |
diffstat | 8 files changed, 362 insertions(+), 13 deletions(-) [+] |
line wrap: on
line diff
--- a/usr/src/pkg/manifests/driver-network-igb.mf Mon Feb 06 12:07:49 2012 -0800 +++ b/usr/src/pkg/manifests/driver-network-igb.mf Mon Feb 06 13:23:22 2012 -0500 @@ -21,6 +21,7 @@ # # Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. +# Copyright 2012, Nexenta Systems, Inc. All rights reserved. # # @@ -55,7 +56,9 @@ alias=pciex8086,1510 \ alias=pciex8086,1511 \ alias=pciex8086,1516 \ - alias=pciex8086,1518 + alias=pciex8086,1518 \ + alias=pciex8086,1521 \ + alias=pciex8086,1526 file path=kernel/drv/$(ARCH64)/igb group=sys $(i386_ONLY)file path=kernel/drv/igb group=sys file path=kernel/drv/igb.conf group=sys \
--- a/usr/src/uts/common/io/igb/igb_82575.c Mon Feb 06 12:07:49 2012 -0800 +++ b/usr/src/uts/common/io/igb/igb_82575.c Mon Feb 06 13:23:22 2012 -0500 @@ -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_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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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); + ipcnfg = E1000_READ_REG(hw, E1000_IPCNFG); + eeer = E1000_READ_REG(hw, E1000_EEER); +out: + + return (ret_val); +}
--- a/usr/src/uts/common/io/igb/igb_82575.h Mon Feb 06 12:07:49 2012 -0800 +++ b/usr/src/uts/common/io/igb/igb_82575.h Mon Feb 06 13:23:22 2012 -0500 @@ -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 @@ #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 @@ 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 }
--- a/usr/src/uts/common/io/igb/igb_api.c Mon Feb 06 12:07:49 2012 -0800 +++ b/usr/src/uts/common/io/igb/igb_api.c Mon Feb 06 13:23:22 2012 -0500 @@ -20,7 +20,7 @@ */ /* - * Copyright(c) 2007-2010 Intel Corporation. All rights reserved. + * Copyright (c) 2007-2012 Intel Corporation. All rights reserved. */ /* @@ -139,6 +139,7 @@ case E1000_DEV_ID_82576_FIBER: case E1000_DEV_ID_82576_SERDES: case E1000_DEV_ID_82576_QUAD_COPPER: + case E1000_DEV_ID_82576_QUAD_COPPER_ET2: case E1000_DEV_ID_82576_NS: case E1000_DEV_ID_82576_NS_SERDES: case E1000_DEV_ID_82576_SERDES_QUAD: @@ -151,6 +152,9 @@ 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 +211,7 @@ case e1000_82575: case e1000_82576: case e1000_82580: + case e1000_i350: e1000_init_function_pointers_82575(hw); break; default:
--- a/usr/src/uts/common/io/igb/igb_defines.h Mon Feb 06 12:07:49 2012 -0800 +++ b/usr/src/uts/common/io/igb/igb_defines.h Mon Feb 06 13:23:22 2012 -0500 @@ -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 @@ #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 @@ #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 @@ #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
--- a/usr/src/uts/common/io/igb/igb_hw.h Mon Feb 06 12:07:49 2012 -0800 +++ b/usr/src/uts/common/io/igb/igb_hw.h Mon Feb 06 13:23:22 2012 -0500 @@ -20,7 +20,7 @@ */ /* - * Copyright(c) 2007-2010 Intel Corporation. All rights reserved. + * Copyright (c) 2007-2012 Intel Corporation. All rights reserved. */ /* @@ -46,6 +46,7 @@ #define E1000_DEV_ID_82576_FIBER 0x10E6 #define E1000_DEV_ID_82576_SERDES 0x10E7 #define E1000_DEV_ID_82576_QUAD_COPPER 0x10E8 +#define E1000_DEV_ID_82576_QUAD_COPPER_ET2 0x1526 #define E1000_DEV_ID_82576_NS 0x150A #define E1000_DEV_ID_82576_NS_SERDES 0x1518 #define E1000_DEV_ID_82576_SERDES_QUAD 0x150D @@ -57,6 +58,7 @@ #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 +81,7 @@ e1000_82575, e1000_82576, e1000_82580, + e1000_i350, e1000_num_macs /* List is 1-based, so subtract 1 for true count. */ }; @@ -640,6 +643,7 @@ struct e1000_dev_spec_82575 { bool sgmii_active; bool global_device_reset; + int eee_disable; }; struct e1000_dev_spec_vf {
--- a/usr/src/uts/common/io/igb/igb_main.c Mon Feb 06 12:07:49 2012 -0800 +++ b/usr/src/uts/common/io/igb/igb_main.c Mon Feb 06 13:23:22 2012 -0500 @@ -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 @@ 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_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) + (void) e1000_set_eee_i350(&igb->hw); + return (DDI_SUCCESS); attach_fail: @@ -836,6 +867,9 @@ 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 @@ if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK) goto start_failure; + if (igb->hw.mac.type == e1000_i350) + (void) 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--)
--- a/usr/src/uts/common/io/igb/igb_regs.h Mon Feb 06 12:07:49 2012 -0800 +++ b/usr/src/uts/common/io/igb/igb_regs.h Mon Feb 06 13:23:22 2012 -0500 @@ -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 @@ /* 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