Mercurial > illumos > illumos-gate
changeset 10680:45bda3640f27
6797885 need to add support for network device (8086,10ea) in a new Intel system
6803799 need to add network device support (8086,10ef) for a new Intel system
6808388 e1000g inteface experience packet lost when switch between joining and leaving a multicast stream
line wrap: on
line diff
--- a/usr/src/pkgdefs/SUNWintgige/postinstall Tue Sep 29 11:19:43 2009 +0800 +++ b/usr/src/pkgdefs/SUNWintgige/postinstall Tue Sep 29 12:12:23 2009 +0800 @@ -208,8 +208,15 @@ "pci8086,10de" "pci8086,10df" "pci8086,10e5" + "pci8086,10ea" + "pci8086,10eb" + "pci8086,10ef" + "pci8086,10f0" "pci8086,10f5" + "pci8086,10f6" + "pci8086,150c" "pci8086,294c" + "pci8086,f0fe" "pciex8086,1049" "pciex8086,104a" "pciex8086,104b" @@ -250,6 +257,13 @@ "pciex8086,10de" "pciex8086,10df" "pciex8086,10e5" + "pciex8086,10ea" + "pciex8086,10eb" + "pciex8086,10ef" + "pciex8086,10f0" "pciex8086,10f5" - "pciex8086,294c"' \ + "pciex8086,10f6" + "pciex8086,150c" + "pciex8086,294c" + "pciex8086,f0fe"' \ -m '* 0666 root sys' e1000g
--- a/usr/src/uts/common/io/e1000g/README Tue Sep 29 11:19:43 2009 +0800 +++ b/usr/src/uts/common/io/e1000g/README Tue Sep 29 12:12:23 2009 +0800 @@ -685,9 +685,9 @@ 5.3.12 ==== - This version has the following fix: - 6846262 T2000 fma shows fault.io.pciex.device-interr in snv_115 - 6870404 e1000g_reset can call e1000g_start after releasing dma resources + This version has the following fix: + 6846262 T2000 fma shows fault.io.pciex.device-interr in snv_115 + 6870404 e1000g_reset can call e1000g_start after releasing dma resources 5.3.13 ==== @@ -700,3 +700,10 @@ This version has the following fix: 6820747 kstat output incorrect for MMF version of e1000g making it impossible to troubleshoot 6847888 HW initialization updates for 82541 and 82547 chips + +5.3.15 +====== + This version has the following fix: + 6797885 need to add support for network device (8086,10ea) in a new Intel system + 6803799 need to add network device support (8086,10ef) for a new Intel system + 6808388 e1000g inteface experience packet lost when switch between joining and leaving a multicast stream
--- a/usr/src/uts/common/io/e1000g/e1000_80003es2lan.c Tue Sep 29 11:19:43 2009 +0800 +++ b/usr/src/uts/common/io/e1000g/e1000_80003es2lan.c Tue Sep 29 12:12:23 2009 +0800 @@ -24,7 +24,7 @@ */ /* - * IntelVersion: 1.76 sol_anvik_patch + * IntelVersion: 1.86 v3-1-3_2009-8-20 */ /* * 80003ES2LAN Gigabit Ethernet Controller (Copper) @@ -37,9 +37,7 @@ static s32 e1000_init_nvm_params_80003es2lan(struct e1000_hw *hw); static s32 e1000_init_mac_params_80003es2lan(struct e1000_hw *hw); static s32 e1000_acquire_phy_80003es2lan(struct e1000_hw *hw); -static s32 e1000_acquire_mac_csr_80003es2lan(struct e1000_hw *hw); static void e1000_release_phy_80003es2lan(struct e1000_hw *hw); -static void e1000_release_mac_csr_80003es2lan(struct e1000_hw *hw); static s32 e1000_acquire_nvm_80003es2lan(struct e1000_hw *hw); static void e1000_release_nvm_80003es2lan(struct e1000_hw *hw); static s32 e1000_read_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw, @@ -177,6 +175,7 @@ * for setting word_size. */ size += NVM_WORD_SIZE_BASE_SHIFT; + /* EEPROM access above 16k is unsupported */ if (size > 14) size = 14; @@ -269,6 +268,8 @@ mac->ops.mta_set = e1000_mta_set_generic; /* read mac address */ mac->ops.read_mac_addr = e1000_read_mac_addr_80003es2lan; + /* ID LED init */ + mac->ops.id_led_init = e1000_id_led_init_generic; /* blink LED */ mac->ops.blink_led = e1000_blink_led_generic; /* setup LED */ @@ -283,6 +284,8 @@ /* link info */ mac->ops.get_link_up_info = e1000_get_link_up_info_80003es2lan; + /* set lan id for port to determine which phy lock to use */ + hw->mac.ops.set_lan_id(hw); out: return (ret_val); } @@ -301,7 +304,6 @@ hw->mac.ops.init_params = e1000_init_mac_params_80003es2lan; hw->nvm.ops.init_params = e1000_init_nvm_params_80003es2lan; hw->phy.ops.init_params = e1000_init_phy_params_80003es2lan; - (void) e1000_get_bus_info_pcie_generic(hw); } /* @@ -536,29 +538,35 @@ goto out; } - /* - * The "ready" bit in the MDIC register may be incorrectly set - * before the device has completed the "Page Select" MDI - * transaction. So we wait 200us after each MDI command... - */ - usec_delay(200); + if (hw->dev_spec._80003es2lan.mdic_wa_enable == true) { + /* + * The "ready" bit in the MDIC register may be incorrectly set + * before the device has completed the "Page Select" MDI + * transaction. So we wait 200us after each MDI command... + */ + usec_delay(200); - /* ...and verify the command was successful. */ - ret_val = e1000_read_phy_reg_mdic(hw, page_select, &temp); + /* ...and verify the command was successful. */ + ret_val = e1000_read_phy_reg_mdic(hw, page_select, &temp); - if (((u16)offset >> GG82563_PAGE_SHIFT) != temp) { - ret_val = -E1000_ERR_PHY; - e1000_release_phy_80003es2lan(hw); - goto out; - } + if (((u16)offset >> GG82563_PAGE_SHIFT) != temp) { + ret_val = -E1000_ERR_PHY; + e1000_release_phy_80003es2lan(hw); + goto out; + } + + usec_delay(200); - usec_delay(200); + ret_val = e1000_read_phy_reg_mdic(hw, + MAX_PHY_REG_ADDRESS & offset, + data); - ret_val = e1000_read_phy_reg_mdic(hw, - MAX_PHY_REG_ADDRESS & offset, - data); + usec_delay(200); + } else + ret_val = e1000_read_phy_reg_mdic(hw, + MAX_PHY_REG_ADDRESS & offset, + data); - usec_delay(200); e1000_release_phy_80003es2lan(hw); out: @@ -605,29 +613,35 @@ goto out; } - /* - * The "ready" bit in the MDIC register may be incorrectly set - * before the device has completed the "Page Select" MDI - * transaction. So we wait 200us after each MDI command... - */ - usec_delay(200); + if (hw->dev_spec._80003es2lan.mdic_wa_enable == true) { + /* + * The "ready" bit in the MDIC register may be incorrectly set + * before the device has completed the "Page Select" MDI + * transaction. So we wait 200us after each MDI command... + */ + usec_delay(200); - /* ...and verify the command was successful. */ - ret_val = e1000_read_phy_reg_mdic(hw, page_select, &temp); + /* ...and verify the command was successful. */ + ret_val = e1000_read_phy_reg_mdic(hw, page_select, &temp); - if (((u16)offset >> GG82563_PAGE_SHIFT) != temp) { - ret_val = -E1000_ERR_PHY; - e1000_release_phy_80003es2lan(hw); - goto out; - } + if (((u16)offset >> GG82563_PAGE_SHIFT) != temp) { + ret_val = -E1000_ERR_PHY; + e1000_release_phy_80003es2lan(hw); + goto out; + } + + usec_delay(200); - usec_delay(200); + ret_val = e1000_write_phy_reg_mdic(hw, + MAX_PHY_REG_ADDRESS & offset, + data); - ret_val = e1000_write_phy_reg_mdic(hw, - MAX_PHY_REG_ADDRESS & offset, - data); + usec_delay(200); + } else + ret_val = e1000_write_phy_reg_mdic(hw, + MAX_PHY_REG_ADDRESS & offset, + data); - usec_delay(200); e1000_release_phy_80003es2lan(hw); out: @@ -697,7 +711,7 @@ static s32 e1000_phy_force_speed_duplex_80003es2lan(struct e1000_hw *hw) { - s32 ret_val; + s32 ret_val = E1000_SUCCESS; u16 phy_data; bool link; @@ -814,16 +828,15 @@ index = phy_data & GG82563_DSPD_CABLE_LENGTH; - if (index < GG82563_CABLE_LENGTH_TABLE_SIZE + 5) { - phy->min_cable_length = e1000_gg82563_cable_length_table[index]; - phy->max_cable_length = - e1000_gg82563_cable_length_table[index+5]; + if (index >= GG82563_CABLE_LENGTH_TABLE_SIZE - 5) { + ret_val = E1000_ERR_PHY; + goto out; + } - phy->cable_length = (phy->min_cable_length + - phy->max_cable_length) / 2; - } else { - ret_val = E1000_ERR_PHY; - } + phy->min_cable_length = e1000_gg82563_cable_length_table[index]; + phy->max_cable_length = e1000_gg82563_cable_length_table[index + 5]; + + phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2; out: return (ret_val); @@ -905,7 +918,7 @@ E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff); (void) E1000_READ_REG(hw, E1000_ICR); - (void) e1000_check_alt_mac_addr_generic(hw); + ret_val = e1000_check_alt_mac_addr_generic(hw); out: return (ret_val); @@ -930,7 +943,7 @@ e1000_initialize_hw_bits_80003es2lan(hw); /* Initialize identification LED */ - ret_val = e1000_id_led_init_generic(hw); + ret_val = mac->ops.id_led_init(hw); if (ret_val) { DEBUGOUT("Error initializing identification LED\n"); /* This is not fatal and we should not stop init due to this */ @@ -984,6 +997,19 @@ reg_data &= ~0x00100000; E1000_WRITE_REG_ARRAY(hw, E1000_FFLT, 0x0001, reg_data); + /* default to true to enable the MDIC W/A */ + hw->dev_spec._80003es2lan.mdic_wa_enable = true; + + ret_val = e1000_read_kmrn_reg_80003es2lan(hw, + E1000_KMRNCTRLSTA_OFFSET >> + E1000_KMRNCTRLSTA_OFFSET_SHIFT, + &i); + if (!ret_val) { + if ((i & E1000_KMRNCTRLSTA_OPMODE_MASK) == + E1000_KMRNCTRLSTA_OPMODE_INBAND_MDIO) + hw->dev_spec._80003es2lan.mdic_wa_enable = false; + } + /* * Clear all of the statistics registers (clear on read). It is * important that we do this after we have tried to establish link @@ -1164,21 +1190,18 @@ if (!(hw->mac.ops.check_mng_mode(hw))) { /* Enable Electrical Idle on the PHY */ data |= GG82563_PMCR_ENABLE_ELECTRICAL_IDLE; - ret_val = hw->phy.ops.write_reg(hw, - GG82563_PHY_PWR_MGMT_CTRL, + ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_PWR_MGMT_CTRL, data); if (ret_val) goto out; - ret_val = hw->phy.ops.read_reg(hw, - GG82563_PHY_KMRN_MODE_CTRL, + ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, &data); if (ret_val) goto out; data &= ~GG82563_KMCR_PASS_FALSE_CARRIER; - ret_val = hw->phy.ops.write_reg(hw, - GG82563_PHY_KMRN_MODE_CTRL, + ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, data); if (ret_val) @@ -1417,7 +1440,7 @@ * using the kumeran interface. The information retrieved is stored in data. * Release the semaphore before exiting. */ -s32 +static s32 e1000_read_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset, u16 *data) { u32 kmrnctrlsta; @@ -1454,7 +1477,7 @@ * at the offset using the kumeran interface. Release semaphore * before exiting. */ -s32 +static s32 e1000_write_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset, u16 data) { u32 kmrnctrlsta; @@ -1488,9 +1511,18 @@ s32 ret_val = E1000_SUCCESS; DEBUGFUNC("e1000_read_mac_addr_80003es2lan"); - if (e1000_check_alt_mac_addr_generic(hw)) - ret_val = e1000_read_mac_addr_generic(hw); + /* + * If there's an alternate MAC address place it in RAR0 + * so that it will override the Si installed default perm + * address. + */ + ret_val = e1000_check_alt_mac_addr_generic(hw); + if (ret_val) + goto out; + ret_val = e1000_read_mac_addr_generic(hw); + +out: return (ret_val); }
--- a/usr/src/uts/common/io/e1000g/e1000_80003es2lan.h Tue Sep 29 11:19:43 2009 +0800 +++ b/usr/src/uts/common/io/e1000g/e1000_80003es2lan.h Tue Sep 29 12:12:23 2009 +0800 @@ -24,7 +24,7 @@ */ /* - * IntelVersion: 1.9 sol_anvik_patch + * IntelVersion: 1.10 v3-1-3_2009-8-20 */ #ifndef _E1000_80003ES2LAN_H_ #define _E1000_80003ES2LAN_H_ @@ -46,8 +46,11 @@ #define E1000_KMRNCTRLSTA_HD_CTRL_1000_DEFAULT 0x0000 #define E1000_KMRNCTRLSTA_OPMODE_E_IDLE 0x2000 +#define E1000_KMRNCTRLSTA_OPMODE_MASK 0x000C +#define E1000_KMRNCTRLSTA_OPMODE_INBAND_MDIO 0x0004 + /* Gigabit Carry Extend Padding */ -#define E1000_TCTL_EXT_GCEX_MASK 0x000FFC00 +#define E1000_TCTL_EXT_GCEX_MASK 0x000FFC00 #define DEFAULT_TCTL_EXT_GCEX_80003ES2LAN 0x00010000
--- a/usr/src/uts/common/io/e1000g/e1000_82540.c Tue Sep 29 11:19:43 2009 +0800 +++ b/usr/src/uts/common/io/e1000g/e1000_82540.c Tue Sep 29 12:12:23 2009 +0800 @@ -24,7 +24,7 @@ */ /* - * IntelVersion: 1.54 sol_anvik_patch + * IntelVersion: 1.57 v3-1-3_2009-8-20 */ /* @@ -52,6 +52,7 @@ static s32 e1000_setup_copper_link_82540(struct e1000_hw *hw); static s32 e1000_setup_fiber_serdes_link_82540(struct e1000_hw *hw); static void e1000_power_down_phy_copper_82540(struct e1000_hw *hw); +static s32 e1000_read_mac_addr_82540(struct e1000_hw *hw); /* * e1000_init_phy_params_82540 - Init PHY func ptrs. @@ -184,6 +185,8 @@ /* bus type/speed/width */ mac->ops.get_bus_info = e1000_get_bus_info_pci_generic; + /* function id */ + mac->ops.set_lan_id = e1000_set_lan_id_multi_port_pci; /* reset */ mac->ops.reset_hw = e1000_reset_hw_82540; /* hw initialization */ @@ -223,8 +226,12 @@ mac->ops.clear_vfta = e1000_clear_vfta_generic; /* setting MTA */ mac->ops.mta_set = e1000_mta_set_generic; + /* ID LED init */ + mac->ops.id_led_init = e1000_id_led_init_generic; /* setup LED */ mac->ops.setup_led = e1000_setup_led_generic; + /* read mac address */ + mac->ops.read_mac_addr = e1000_read_mac_addr_82540; /* cleanup LED */ mac->ops.cleanup_led = e1000_cleanup_led_generic; /* turn on/off LED */ @@ -254,10 +261,10 @@ } /* - * e1000_reset_hw_82540 - Reset hardware - * @hw: pointer to the HW structure + * e1000_reset_hw_82540 - Reset hardware + * @hw: pointer to the HW structure * - * This resets the hardware into a known state. + * This resets the hardware into a known state. */ static s32 e1000_reset_hw_82540(struct e1000_hw *hw) @@ -313,10 +320,10 @@ } /* - * e1000_init_hw_82540 - Initialize hardware - * @hw: pointer to the HW structure + * e1000_init_hw_82540 - Initialize hardware + * @hw: pointer to the HW structure * - * This inits the hardware readying it for operation. + * This inits the hardware readying it for operation. */ static s32 e1000_init_hw_82540(struct e1000_hw *hw) @@ -329,7 +336,7 @@ DEBUGFUNC("e1000_init_hw_82540"); /* Initialize identification LED */ - ret_val = e1000_id_led_init_generic(hw); + ret_val = mac->ops.id_led_init(hw); if (ret_val) { DEBUGOUT("Error initializing identification LED\n"); /* This is not fatal and we should not stop init due to this */ @@ -393,13 +400,13 @@ } /* - * e1000_setup_copper_link_82540 - Configure copper link settings - * @hw: pointer to the HW structure + * e1000_setup_copper_link_82540 - Configure copper link settings + * @hw: pointer to the HW structure * - * Calls the appropriate function to configure the link for auto-neg or forced - * speed and duplex. Then we check for link, once link is established calls - * to configure collision distance and flow control are called. If link is - * not established, we return -E1000_ERR_PHY (-2). + * Calls the appropriate function to configure the link for auto-neg or forced + * speed and duplex. Then we check for link, once link is established calls + * to configure collision distance and flow control are called. If link is + * not established, we return -E1000_ERR_PHY (-2). */ static s32 e1000_setup_copper_link_82540(struct e1000_hw *hw) @@ -442,13 +449,13 @@ } /* - * e1000_setup_fiber_serdes_link_82540 - Setup link for fiber/serdes - * @hw: pointer to the HW structure + * e1000_setup_fiber_serdes_link_82540 - Setup link for fiber/serdes + * @hw: pointer to the HW structure * - * Set the output amplitude to the value in the EEPROM and adjust the VCO - * speed to improve Bit Error Rate (BER) performance. Configures collision - * distance and flow control for fiber and serdes links. Upon successful - * setup, poll for link. + * Set the output amplitude to the value in the EEPROM and adjust the VCO + * speed to improve Bit Error Rate (BER) performance. Configures collision + * distance and flow control for fiber and serdes links. Upon successful + * setup, poll for link. */ static s32 e1000_setup_fiber_serdes_link_82540(struct e1000_hw *hw) @@ -485,10 +492,10 @@ } /* - * e1000_adjust_serdes_amplitude_82540 - Adjust amplitude based on EEPROM - * @hw: pointer to the HW structure + * e1000_adjust_serdes_amplitude_82540 - Adjust amplitude based on EEPROM + * @hw: pointer to the HW structure * - * Adjust the SERDES output amplitude based on the EEPROM settings. + * Adjust the SERDES output amplitude based on the EEPROM settings. */ static s32 e1000_adjust_serdes_amplitude_82540(struct e1000_hw *hw) @@ -516,10 +523,10 @@ } /* - * e1000_set_vco_speed_82540 - Set VCO speed for better performance - * @hw: pointer to the HW structure + * e1000_set_vco_speed_82540 - Set VCO speed for better performance + * @hw: pointer to the HW structure * - * Set the VCO speed to improve Bit Error Rate (BER) performance. + * Set the VCO speed to improve Bit Error Rate (BER) performance. */ static s32 e1000_set_vco_speed_82540(struct e1000_hw *hw) @@ -574,13 +581,13 @@ } /* - * e1000_set_phy_mode_82540 - Set PHY to class A mode - * @hw: pointer to the HW structure + * e1000_set_phy_mode_82540 - Set PHY to class A mode + * @hw: pointer to the HW structure * - * Sets the PHY to class A mode and assumes the following operations will - * follow to enable the new class mode: - * 1. Do a PHY soft reset. - * 2. Restart auto-negotiation or force link. + * Sets the PHY to class A mode and assumes the following operations will + * follow to enable the new class mode: + * 1. Do a PHY soft reset. + * 2. Restart auto-negotiation or force link. */ static s32 e1000_set_phy_mode_82540(struct e1000_hw *hw) @@ -638,10 +645,10 @@ } /* - * e1000_clear_hw_cntrs_82540 - Clear device specific hardware counters - * @hw: pointer to the HW structure + * e1000_clear_hw_cntrs_82540 - Clear device specific hardware counters + * @hw: pointer to the HW structure * - * Clears the hardware counters by reading the counter registers. + * Clears the hardware counters by reading the counter registers. */ static void e1000_clear_hw_cntrs_82540(struct e1000_hw *hw) @@ -674,3 +681,47 @@ (void) E1000_READ_REG(hw, E1000_MGTPDC); (void) E1000_READ_REG(hw, E1000_MGTPTC); } + +/* + * e1000_read_mac_addr_82540 - Read device MAC address + * @hw: pointer to the HW structure + * + * Reads the device MAC address from the EEPROM and stores the value. + * Since devices with two ports use the same EEPROM, we increment the + * last bit in the MAC address for the second port. + * + * This version is being used over generic because of customer issues + * with VmWare and Virtual Box when using generic. It seems in + * the emulated 82545, RAR[0] does NOT have a valid address after a + * reset, this older method works and using this breaks nothing for + * these legacy adapters. + */ +s32 +e1000_read_mac_addr_82540(struct e1000_hw *hw) +{ + s32 ret_val = E1000_SUCCESS; + u16 offset, nvm_data, i; + + DEBUGFUNC("e1000_read_mac_addr"); + + for (i = 0; i < ETH_ADDR_LEN; i += 2) { + offset = i >> 1; + ret_val = hw->nvm.ops.read(hw, offset, 1, &nvm_data); + if (ret_val) { + DEBUGOUT("NVM Read Error\n"); + goto out; + } + hw->mac.perm_addr[i] = (u8)(nvm_data & 0xFF); + hw->mac.perm_addr[i+1] = (u8)(nvm_data >> 8); + } + + /* Flip last bit of mac address if we're on second port */ + if (hw->bus.func == E1000_FUNC_1) + hw->mac.perm_addr[5] ^= 1; + + for (i = 0; i < ETH_ADDR_LEN; i++) + hw->mac.addr[i] = hw->mac.perm_addr[i]; + +out: + return (ret_val); +}
--- a/usr/src/uts/common/io/e1000g/e1000_82541.c Tue Sep 29 11:19:43 2009 +0800 +++ b/usr/src/uts/common/io/e1000g/e1000_82541.c Tue Sep 29 12:12:23 2009 +0800 @@ -24,7 +24,7 @@ */ /* - * IntelVersion: 1.64 sol_anvik_patch + * IntelVersion: 1.68 v3-1-3_2009-8-20 */ /* @@ -112,6 +112,7 @@ ret_val = -E1000_ERR_PHY; goto out; } + out: return (ret_val); } @@ -237,6 +238,8 @@ /* bus type/speed/width */ mac->ops.get_bus_info = e1000_get_bus_info_pci_generic; + /* function id */ + mac->ops.set_lan_id = e1000_set_lan_id_single_port; /* reset */ mac->ops.reset_hw = e1000_reset_hw_82541; /* hw initialization */ @@ -257,6 +260,8 @@ mac->ops.clear_vfta = e1000_clear_vfta_generic; /* setting MTA */ mac->ops.mta_set = e1000_mta_set_generic; + /* ID LED init */ + mac->ops.id_led_init = e1000_id_led_init_generic; /* setup LED */ mac->ops.setup_led = e1000_setup_led_82541; /* cleanup LED */ @@ -385,20 +390,17 @@ DEBUGFUNC("e1000_init_hw_82541"); /* Initialize identification LED */ - ret_val = e1000_id_led_init_generic(hw); + ret_val = mac->ops.id_led_init(hw); if (ret_val) { DEBUGOUT("Error initializing identification LED\n"); /* This is not fatal and we should not stop init due to this */ } - /* - * workaround - Store Default value in dev_spec->spd_default for - * later use - */ - ret_val = hw->phy.ops.read_reg(hw, - IGP01E1000_GMII_FIFO, - &dev_spec->spd_default); - if (ret_val) + /* Storing the Speed Power Down value for later use */ + ret_val = hw->phy.ops.read_reg(hw, + IGP01E1000_GMII_FIFO, + &dev_spec->spd_default); + if (ret_val) goto out; pba = E1000_READ_REG(hw, E1000_PBA);
--- a/usr/src/uts/common/io/e1000g/e1000_82541.h Tue Sep 29 11:19:43 2009 +0800 +++ b/usr/src/uts/common/io/e1000g/e1000_82541.h Tue Sep 29 12:12:23 2009 +0800 @@ -24,7 +24,7 @@ */ /* - * IntelVersion: 1.9 sol_anvik_patch + * IntelVersion: 1.9 v3-1-3_2009-8-20 */ #ifndef _E1000_82541_H_ #define _E1000_82541_H_
--- a/usr/src/uts/common/io/e1000g/e1000_82542.c Tue Sep 29 11:19:43 2009 +0800 +++ b/usr/src/uts/common/io/e1000g/e1000_82542.c Tue Sep 29 12:12:23 2009 +0800 @@ -24,7 +24,7 @@ */ /* - * IntelVersion: 1.50 sol_anvik_patch + * IntelVersion: 1.53 v3-1-3_2009-8-20 */ /* @@ -44,6 +44,7 @@ static s32 e1000_led_off_82542(struct e1000_hw *hw); static void e1000_rar_set_82542(struct e1000_hw *hw, u8 *addr, u32 index); static void e1000_clear_hw_cntrs_82542(struct e1000_hw *hw); +static s32 e1000_read_mac_addr_82542(struct e1000_hw *hw); /* * e1000_init_phy_params_82542 - Init PHY func ptrs. @@ -112,6 +113,8 @@ /* bus type/speed/width */ mac->ops.get_bus_info = e1000_get_bus_info_82542; + /* function id */ + mac->ops.set_lan_id = e1000_set_lan_id_multi_port_pci; /* reset */ mac->ops.reset_hw = e1000_reset_hw_82542; /* hw initialization */ @@ -131,6 +134,8 @@ mac->ops.clear_vfta = e1000_clear_vfta_generic; /* setting MTA */ mac->ops.mta_set = e1000_mta_set_generic; + /* read mac address */ + mac->ops.read_mac_addr = e1000_read_mac_addr_82542; /* set RAR */ mac->ops.rar_set = e1000_rar_set_82542; /* turn on/off LED */ @@ -561,3 +566,35 @@ (void) E1000_READ_REG(hw, E1000_PTC1023); (void) E1000_READ_REG(hw, E1000_PTC1522); } + +/* + * e1000_read_mac_addr_82542 - Read device MAC address + * @hw: pointer to the HW structure + * + * Reads the device MAC address from the EEPROM and stores the value. + */ +s32 +e1000_read_mac_addr_82542(struct e1000_hw *hw) +{ + s32 ret_val = E1000_SUCCESS; + u16 offset, nvm_data, i; + + DEBUGFUNC("e1000_read_mac_addr"); + + for (i = 0; i < ETH_ADDR_LEN; i += 2) { + offset = i >> 1; + ret_val = hw->nvm.ops.read(hw, offset, 1, &nvm_data); + if (ret_val) { + DEBUGOUT("NVM Read Error\n"); + goto out; + } + hw->mac.perm_addr[i] = (u8)(nvm_data & 0xFF); + hw->mac.perm_addr[i+1] = (u8)(nvm_data >> 8); + } + + for (i = 0; i < ETH_ADDR_LEN; i++) + hw->mac.addr[i] = hw->mac.perm_addr[i]; + + out: + return (ret_val); +}
--- a/usr/src/uts/common/io/e1000g/e1000_82543.c Tue Sep 29 11:19:43 2009 +0800 +++ b/usr/src/uts/common/io/e1000g/e1000_82543.c Tue Sep 29 12:12:23 2009 +0800 @@ -24,7 +24,7 @@ */ /* - * IntelVersion: 1.67 sol_anvik_patch + * IntelVersion: 1.68 v3-1-3_2009-8-20 */ /* @@ -212,6 +212,8 @@ /* bus type/speed/width */ mac->ops.get_bus_info = e1000_get_bus_info_pci_generic; + /* function id */ + mac->ops.set_lan_id = e1000_set_lan_id_multi_port_pci; /* reset */ mac->ops.reset_hw = e1000_reset_hw_82543; /* hw initialization */
--- a/usr/src/uts/common/io/e1000g/e1000_82543.h Tue Sep 29 11:19:43 2009 +0800 +++ b/usr/src/uts/common/io/e1000g/e1000_82543.h Tue Sep 29 12:12:23 2009 +0800 @@ -24,7 +24,7 @@ */ /* - * IntelVersion: 1.8 sol_anvik_patch + * IntelVersion: 1.8 v3-1-3_2009-8-20 */ #ifndef _E1000_82543_H_ #define _E1000_82543_H_
--- a/usr/src/uts/common/io/e1000g/e1000_82571.c Tue Sep 29 11:19:43 2009 +0800 +++ b/usr/src/uts/common/io/e1000g/e1000_82571.c Tue Sep 29 12:12:23 2009 +0800 @@ -24,7 +24,7 @@ */ /* - * IntelVersion: 1.94 sol_anvik_patch + * IntelVersion: 1.113 v3-1-3_2009-8-20 */ /* @@ -41,6 +41,7 @@ * 82573E Gigabit Ethernet Controller (Copper) * 82573L Gigabit Ethernet Controller * 82574L Gigabit Network Connection + * 82583V Gigabit Network Connection */ #include "e1000_api.h" @@ -62,15 +63,13 @@ static void e1000_clear_vfta_82571(struct e1000_hw *hw); static bool e1000_check_mng_mode_82574(struct e1000_hw *hw); static s32 e1000_led_on_82574(struct e1000_hw *hw); -static void e1000_update_mc_addr_list_82571(struct e1000_hw *hw, - u8 *mc_addr_list, u32 mc_addr_count, - u32 rar_used_count, u32 rar_count); static s32 e1000_setup_link_82571(struct e1000_hw *hw); static s32 e1000_setup_copper_link_82571(struct e1000_hw *hw); +static s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw); static s32 e1000_setup_fiber_serdes_link_82571(struct e1000_hw *hw); static s32 e1000_valid_led_default_82571(struct e1000_hw *hw, u16 *data); static void e1000_clear_hw_cntrs_82571(struct e1000_hw *hw); -static s32 e1000_get_hw_semaphore_82571(struct e1000_hw *hw); +static s32 e1000_get_hw_semaphore_82571(struct e1000_hw *hw); static s32 e1000_fix_nvm_checksum_82571(struct e1000_hw *hw); static s32 e1000_get_phy_id_82571(struct e1000_hw *hw); static void e1000_put_hw_semaphore_82571(struct e1000_hw *hw); @@ -152,6 +151,7 @@ } break; case e1000_82574: + case e1000_82583: phy->type = e1000_phy_bm; phy->ops.get_cfg_done = e1000_get_cfg_done_generic; phy->ops.get_info = e1000_get_phy_info_m88; @@ -212,6 +212,7 @@ switch (hw->mac.type) { case e1000_82573: case e1000_82574: + case e1000_82583: if (((eecd >> 15) & 0x3) == 0x3) { nvm->type = e1000_nvm_flash_hw; nvm->word_size = 2048; @@ -262,6 +263,9 @@ { struct e1000_mac_info *mac = &hw->mac; s32 ret_val = E1000_SUCCESS; + u32 swsm = 0; + u32 swsm2 = 0; + bool force_clear_smbi = false; DEBUGFUNC("e1000_init_mac_params_82571"); @@ -298,6 +302,16 @@ /* bus type/speed/width */ mac->ops.get_bus_info = e1000_get_bus_info_pcie_generic; + /* function id */ + switch (hw->mac.type) { + case e1000_82573: + case e1000_82574: + case e1000_82583: + mac->ops.set_lan_id = e1000_set_lan_id_single_port; + break; + default: + break; + } /* reset */ mac->ops.reset_hw = e1000_reset_hw_82571; /* hw initialization */ @@ -318,7 +332,7 @@ mac->ops.check_for_link = e1000_check_for_fiber_link_generic; break; case e1000_media_type_internal_serdes: - mac->ops.check_for_link = e1000_check_for_serdes_link_generic; + mac->ops.check_for_link = e1000_check_for_serdes_link_82571; break; default: ret_val = -E1000_ERR_CONFIG; @@ -327,6 +341,7 @@ /* check management mode */ switch (hw->mac.type) { case e1000_82574: + case e1000_82583: mac->ops.check_mng_mode = e1000_check_mng_mode_82574; break; default: @@ -334,7 +349,7 @@ break; } /* multicast address update */ - mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_82571; + mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic; /* writing VFTA */ mac->ops.write_vfta = e1000_write_vfta_generic; /* clearing VFTA */ @@ -343,6 +358,8 @@ mac->ops.mta_set = e1000_mta_set_generic; /* read mac address */ mac->ops.read_mac_addr = e1000_read_mac_addr_82571; + /* ID LED init */ + mac->ops.id_led_init = e1000_id_led_init_generic; /* blink LED */ mac->ops.blink_led = e1000_blink_led_generic; /* setup LED */ @@ -352,6 +369,7 @@ /* turn on/off LED */ switch (hw->mac.type) { case e1000_82574: + case e1000_82583: mac->ops.led_on = e1000_led_on_82574; break; default: @@ -367,6 +385,51 @@ ? e1000_get_speed_and_duplex_copper_generic : e1000_get_speed_and_duplex_fiber_serdes_generic; + /* + * Ensure that the inter-port SWSM.SMBI lock bit is clear before + * first NVM or PHY acess. This should be done for single-port + * devices, and for one port only on dual-port devices so that + * for those devices we can still use the SMBI lock to synchronize + * inter-port accesses to the PHY & NVM. + */ + switch (hw->mac.type) { + case e1000_82571: + case e1000_82572: + swsm2 = E1000_READ_REG(hw, E1000_SWSM2); + + if (!(swsm2 & E1000_SWSM2_LOCK)) { + /* Only do this for the first interface on this card */ + E1000_WRITE_REG(hw, E1000_SWSM2, + swsm2 | E1000_SWSM2_LOCK); + force_clear_smbi = true; + } else + force_clear_smbi = false; + break; + default: + force_clear_smbi = true; + break; + } + + if (force_clear_smbi) { + /* Make sure SWSM.SMBI is clear */ + swsm = E1000_READ_REG(hw, E1000_SWSM); + if (swsm & E1000_SWSM_SMBI) { + /* + * This bit should not be set on a first interface, and + * indicates that the bootagent or EFI code has + * improperly left this bit enabled + */ + DEBUGOUT("Please update your 82571 Bootagent\n"); + } + E1000_WRITE_REG(hw, E1000_SWSM, swsm & ~E1000_SWSM_SMBI); + } + + /* + * Initialze device specific counter of SMBI acquisition + * timeouts. + */ + hw->dev_spec._82571.smb_counter = 0; + out: return (ret_val); } @@ -417,6 +480,7 @@ ret_val = e1000_get_phy_id(hw); break; case e1000_82574: + case e1000_82583: ret_val = phy->ops.read_reg(hw, PHY_ID1, &phy_id); if (ret_val) goto out; @@ -445,18 +509,44 @@ * * Acquire the HW semaphore to access the PHY or NVM */ -static s32 +s32 e1000_get_hw_semaphore_82571(struct e1000_hw *hw) { u32 swsm; s32 ret_val = E1000_SUCCESS; - s32 timeout = hw->nvm.word_size + 1; + s32 sw_timeout = hw->nvm.word_size + 1; + s32 fw_timeout = hw->nvm.word_size + 1; s32 i = 0; DEBUGFUNC("e1000_get_hw_semaphore_82571"); + /* + * If we have timedout 3 times on trying to acquire + * the inter-port SMBI semaphore, there is old code + * operating on the other port, and it is not + * releasing SMBI. Modify the number of times that + * we try for the semaphore to interwork with this + * older code. + */ + if (hw->dev_spec._82571.smb_counter > 2) + sw_timeout = 1; + + /* Get the SW semaphore */ + while (i < sw_timeout) { + swsm = E1000_READ_REG(hw, E1000_SWSM); + if (!(swsm & E1000_SWSM_SMBI)) + break; + + usec_delay(50); + i++; + } + + if (i == sw_timeout) { + DEBUGOUT("Driver can't access device - SMBI bit is set.\n"); + hw->dev_spec._82571.smb_counter++; + } /* Get the FW semaphore. */ - for (i = 0; i < timeout; i++) { + for (i = 0; i < fw_timeout; i++) { swsm = E1000_READ_REG(hw, E1000_SWSM); E1000_WRITE_REG(hw, E1000_SWSM, swsm | E1000_SWSM_SWESMBI); @@ -467,9 +557,9 @@ usec_delay(50); } - if (i == timeout) { + if (i == fw_timeout) { /* Release semaphores */ - e1000_put_hw_semaphore_generic(hw); + e1000_put_hw_semaphore_82571(hw); DEBUGOUT("Driver can't access the NVM\n"); ret_val = -E1000_ERR_NVM; goto out; @@ -485,16 +575,16 @@ * * Release hardware semaphore used to access the PHY or NVM */ -static void +void e1000_put_hw_semaphore_82571(struct e1000_hw *hw) { u32 swsm; - DEBUGFUNC("e1000_put_hw_semaphore_82571"); + DEBUGFUNC("e1000_put_hw_semaphore_generic"); swsm = E1000_READ_REG(hw, E1000_SWSM); - swsm &= ~E1000_SWSM_SWESMBI; + swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI); E1000_WRITE_REG(hw, E1000_SWSM, swsm); } @@ -519,8 +609,15 @@ if (ret_val) goto out; - if (hw->mac.type != e1000_82573 && hw->mac.type != e1000_82574) + switch (hw->mac.type) { + case e1000_82573: + case e1000_82574: + case e1000_82583: + break; + default: ret_val = e1000_acquire_nvm_generic(hw); + break; + } if (ret_val) e1000_put_hw_semaphore_82571(hw); @@ -567,6 +664,7 @@ switch (hw->mac.type) { case e1000_82573: case e1000_82574: + case e1000_82583: ret_val = e1000_write_nvm_eewr_82571(hw, offset, words, data); break; case e1000_82571: @@ -747,6 +845,7 @@ } if (!timeout) { DEBUGOUT("MNG configuration cycle has not completed.\n"); + ret_val = -E1000_ERR_RESET; goto out; } @@ -875,7 +974,10 @@ * Must acquire the MDIO ownership before MAC reset. Ownership * defaults to firmware after a reset. */ - if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) { + switch (hw->mac.type) { + case e1000_82573: + case e1000_82574: + case e1000_82583: extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP; @@ -891,6 +993,9 @@ msec_delay(2); i++; } while (i < MDIO_OWNERSHIP_TIMEOUT); + break; + default: + break; } ctrl = E1000_READ_REG(hw, E1000_CTRL); @@ -916,15 +1021,30 @@ * Need to wait for Phy configuration completion before accessing * NVM and Phy. */ - if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) + switch (hw->mac.type) { + case e1000_82573: + case e1000_82574: + case e1000_82583: msec_delay(25); + break; + default: + break; + } /* Clear any pending interrupt events. */ E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff); (void) E1000_READ_REG(hw, E1000_ICR); - if (!(e1000_check_alt_mac_addr_generic(hw))) - e1000_set_laa_state_82571(hw, true); + /* Install any alternate MAC address into RAR0 */ + ret_val = e1000_check_alt_mac_addr_generic(hw); + if (ret_val) + goto out; + + e1000_set_laa_state_82571(hw, true); + + /* Reinitialize the 82571 serdes link state machine */ + if (hw->phy.media_type == e1000_media_type_internal_serdes) + hw->mac.serdes_link_state = e1000_serdes_link_down; out: return (ret_val); @@ -949,7 +1069,7 @@ e1000_initialize_hw_bits_82571(hw); /* Initialize identification LED */ - ret_val = e1000_id_led_init_generic(hw); + ret_val = mac->ops.id_led_init(hw); if (ret_val) { DEBUGOUT("Error initializing identification LED\n"); /* This is not fatal and we should not stop init due to this */ @@ -985,17 +1105,22 @@ E1000_WRITE_REG(hw, E1000_TXDCTL(0), reg_data); /* ...for both queues. */ - if (mac->type != e1000_82573 && mac->type != e1000_82574) { + switch (mac->type) { + case e1000_82573: + case e1000_82574: + case e1000_82583: + e1000_enable_tx_pkt_filtering_generic(hw); + reg_data = E1000_READ_REG(hw, E1000_GCR); + reg_data |= E1000_GCR_L1_ACT_WITHOUT_L0S_RX; + E1000_WRITE_REG(hw, E1000_GCR, reg_data); + break; + default: reg_data = E1000_READ_REG(hw, E1000_TXDCTL(1)); reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) | E1000_TXDCTL_FULL_TX_DESC_WB | E1000_TXDCTL_COUNT_DESC; E1000_WRITE_REG(hw, E1000_TXDCTL(1), reg_data); - } else { - (void) e1000_enable_tx_pkt_filtering_generic(hw); - reg_data = E1000_READ_REG(hw, E1000_GCR); - reg_data |= E1000_GCR_L1_ACT_WITHOUT_L0S_RX; - E1000_WRITE_REG(hw, E1000_GCR, reg_data); + break; } /* @@ -1063,25 +1188,69 @@ } /* Device Control */ - if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) { + switch (hw->mac.type) { + case e1000_82573: + case e1000_82574: + case e1000_82583: reg = E1000_READ_REG(hw, E1000_CTRL); reg &= ~(1 << 29); E1000_WRITE_REG(hw, E1000_CTRL, reg); + break; + default: + break; } /* Extended Device Control */ - if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) { + switch (hw->mac.type) { + case e1000_82573: + case e1000_82574: + case e1000_82583: reg = E1000_READ_REG(hw, E1000_CTRL_EXT); reg &= ~(1 << 23); reg |= (1 << 22); E1000_WRITE_REG(hw, E1000_CTRL_EXT, reg); + break; + default: + break; + } + + if (hw->mac.type == e1000_82571) { + reg = E1000_READ_REG(hw, E1000_PBA_ECC); + reg |= E1000_PBA_ECC_CORR_EN; + E1000_WRITE_REG(hw, E1000_PBA_ECC, reg); } - /* PCI-Ex Control Register */ - if (hw->mac.type == e1000_82574) { + /* + * Workaround for hardware errata. + * Ensure that DMA Dynamic Clock gating is disabled on 82571 and 82572 + */ + if ((hw->mac.type == e1000_82571) || + (hw->mac.type == e1000_82572)) { + reg = E1000_READ_REG(hw, E1000_CTRL_EXT); + reg &= ~E1000_CTRL_EXT_DMA_DYN_CLK_EN; + E1000_WRITE_REG(hw, E1000_CTRL_EXT, reg); + } + + /* PCI-Ex Control Registers */ + switch (hw->mac.type) { + case e1000_82574: + case e1000_82583: reg = E1000_READ_REG(hw, E1000_GCR); reg |= (1 << 22); E1000_WRITE_REG(hw, E1000_GCR, reg); + /* + * Workaround for hardware errata. + * apply workaround for hardware errata documented in errata + * docs Fixes issue where some error prone or unreliable PCIe + * completions are occurring, particularly with ASPM enabled. + * Without fix, issue can cause tx timeouts. + */ + reg = E1000_READ_REG(hw, E1000_GCR2); + reg |= 1; + E1000_WRITE_REG(hw, E1000_GCR2, reg); + break; + default: + break; } } @@ -1102,31 +1271,41 @@ DEBUGFUNC("e1000_clear_vfta_82571"); - if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) { + switch (hw->mac.type) { + case e1000_82573: + case e1000_82574: + case e1000_82583: if (hw->mng_cookie.vlan_id != 0) { /* - * The VFTA is a 4096b bit-field, each identifying a - * single VLAN ID. The following operations determine - * which 32b entry (i.e. offset) into the array we - * want to set the VLAN ID (i.e. bit) of the - * manageability unit. + * The VFTA is a 4096b bit-field, each identifying + * a single VLAN ID. The following operations + * determine which 32b entry (i.e. offset) into the + * array we want to set the VLAN ID (i.e. bit) of + * the manageability unit. */ vfta_offset = (hw->mng_cookie.vlan_id >> - E1000_VFTA_ENTRY_SHIFT) & - E1000_VFTA_ENTRY_MASK; + E1000_VFTA_ENTRY_SHIFT) & E1000_VFTA_ENTRY_MASK; + vfta_bit_in_reg = 1 << (hw->mng_cookie.vlan_id & E1000_VFTA_ENTRY_BIT_SHIFT_MASK); } - } - for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) { - /* - * If the offset we want to clear is the same offset of the - * manageability VLAN ID, then clear all bits except that of - * the manageability unit. - */ - vfta_value = (offset == vfta_offset) ? vfta_bit_in_reg : 0; - E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, vfta_value); - E1000_WRITE_FLUSH(hw); + + for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; + offset ++) { + /* + * If the offset we want to clear is the same offset of + * the manageability VLAN ID, then clear all bits except + * that of the manageability unit + */ + vfta_value = (offset == vfta_offset) ? + vfta_bit_in_reg : 0; + E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, + vfta_value); + E1000_WRITE_FLUSH(hw); + } + break; + default: + break; } } @@ -1179,33 +1358,6 @@ } /* - * e1000_update_mc_addr_list_82571 - Update Multicast addresses - * @hw: pointer to the HW structure - * @mc_addr_list: array of multicast addresses to program - * @mc_addr_count: number of multicast addresses to program - * @rar_used_count: the first RAR register free to program - * @rar_count: total number of supported Receive Address Registers - * - * Updates the Receive Address Registers and Multicast Table Array. - * The caller must have a packed mc_addr_list of multicast addresses. - * The parameter rar_count will usually be hw->mac.rar_entry_count - * unless there are workarounds that change this. - */ -static void -e1000_update_mc_addr_list_82571(struct e1000_hw *hw, - u8 *mc_addr_list, u32 mc_addr_count, - u32 rar_used_count, u32 rar_count) -{ - DEBUGFUNC("e1000_update_mc_addr_list_82571"); - - if (e1000_get_laa_state_82571(hw)) - rar_count--; - - e1000_update_mc_addr_list_generic(hw, mc_addr_list, mc_addr_count, - rar_used_count, rar_count); -} - -/* * e1000_setup_link_82571 - Setup flow control and link settings * @hw: pointer to the HW structure * @@ -1224,10 +1376,16 @@ * 82573 does not have a word in the NVM to determine the default flow * control setting, so we explicitly set it to full. */ - if ((hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) && - hw->fc.requested_mode == e1000_fc_default) - hw->fc.requested_mode = e1000_fc_full; - + switch (hw->mac.type) { + case e1000_82573: + case e1000_82574: + case e1000_82583: + if (hw->fc.requested_mode == e1000_fc_default) + hw->fc.requested_mode = e1000_fc_full; + break; + default: + break; + } return (e1000_setup_link_generic(hw)); } @@ -1242,7 +1400,7 @@ static s32 e1000_setup_copper_link_82571(struct e1000_hw *hw) { - u32 ctrl, led_ctrl; + u32 ctrl; s32 ret_val; DEBUGFUNC("e1000_setup_copper_link_82571"); @@ -1259,11 +1417,6 @@ break; case e1000_phy_igp_2: ret_val = e1000_copper_link_setup_igp(hw); - /* Setup activity LED */ - led_ctrl = E1000_READ_REG(hw, E1000_LEDCTL); - led_ctrl &= IGP_ACTIVITY_LED_MASK; - led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE); - E1000_WRITE_REG(hw, E1000_LEDCTL, led_ctrl); break; default: ret_val = -E1000_ERR_PHY; @@ -1312,6 +1465,157 @@ } /* + * e1000_check_for_serdes_link_82571 - Check for link (Serdes) + * @hw: pointer to the HW structure + * + * Reports the link state as up or down. + * + * If autonegotiation is supported by the link partner, the link state is + * determined by the result of autongotiation. This is the most likely case. + * If autonegotiation is not supported by the link partner, and the link + * has a valid signal, force the link up. + * + * The link state is represented internally here by 4 states: + * + * 1) down + * 2) autoneg_progress + * 3) autoneg_complete (the link sucessfully autonegotiated) + * 4) forced_up (the link has been forced up, it did not autonegotiate) + */ +s32 +e1000_check_for_serdes_link_82571(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + u32 rxcw; + u32 ctrl; + u32 status; + s32 ret_val = E1000_SUCCESS; + + DEBUGFUNC("e1000_check_for_serdes_link_82571"); + + ctrl = E1000_READ_REG(hw, E1000_CTRL); + status = E1000_READ_REG(hw, E1000_STATUS); + rxcw = E1000_READ_REG(hw, E1000_RXCW); + + if ((rxcw & E1000_RXCW_SYNCH) && !(rxcw & E1000_RXCW_IV)) { + + /* Receiver is synchronized with no invalid bits. */ + switch (mac->serdes_link_state) { + case e1000_serdes_link_autoneg_complete: + if (!(status & E1000_STATUS_LU)) { + /* + * We have lost link, retry autoneg before + * reporting link failure + */ + mac->serdes_link_state = + e1000_serdes_link_autoneg_progress; + mac->serdes_has_link = false; + DEBUGOUT("AN_UP -> AN_PROG\n"); + } + break; + + case e1000_serdes_link_forced_up: + /* + * If we are receiving /C/ ordered sets, re-enable + * auto-negotiation in the TXCW register and disable + * forced link in the Device Control register in an + * attempt to auto-negotiate with our link partner. + */ + if (rxcw & E1000_RXCW_C) { + /* Enable autoneg, and unforce link up */ + E1000_WRITE_REG(hw, E1000_TXCW, mac->txcw); + E1000_WRITE_REG(hw, E1000_CTRL, + (ctrl & ~E1000_CTRL_SLU)); + mac->serdes_link_state = + e1000_serdes_link_autoneg_progress; + mac->serdes_has_link = false; + DEBUGOUT("FORCED_UP -> AN_PROG\n"); + } + break; + + case e1000_serdes_link_autoneg_progress: + if (rxcw & E1000_RXCW_C) { + /* + * We received /C/ ordered sets, meaning the + * link partner has autonegotiated, and we can + * trust the Link Up (LU) status bit + */ + if (status & E1000_STATUS_LU) { + mac->serdes_link_state = + e1000_serdes_link_autoneg_complete; + DEBUGOUT("AN_PROG -> AN_UP\n"); + mac->serdes_has_link = true; + } else { + /* Autoneg completed, but failed */ + mac->serdes_link_state = + e1000_serdes_link_down; + DEBUGOUT("AN_PROG -> DOWN\n"); + } + } else { + /* + * The link partner did not autoneg. + * Force link up and full duplex, and change + * state to forced. + */ + E1000_WRITE_REG(hw, E1000_TXCW, + (mac->txcw & ~E1000_TXCW_ANE)); + ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD); + E1000_WRITE_REG(hw, E1000_CTRL, ctrl); + + /* Configure Flow Control after link up. */ + ret_val = + e1000_config_fc_after_link_up_generic(hw); + if (ret_val) { + DEBUGOUT("Error config flow control\n"); + break; + } + mac->serdes_link_state = + e1000_serdes_link_forced_up; + mac->serdes_has_link = true; + DEBUGOUT("AN_PROG -> FORCED_UP\n"); + } + break; + + case e1000_serdes_link_down: + default: + /* + * The link was down but the receiver has now gained + * valid sync, so lets see if we can bring the link + * up. + */ + E1000_WRITE_REG(hw, E1000_TXCW, mac->txcw); + E1000_WRITE_REG(hw, E1000_CTRL, + (ctrl & ~E1000_CTRL_SLU)); + mac->serdes_link_state = + e1000_serdes_link_autoneg_progress; + DEBUGOUT("DOWN -> AN_PROG\n"); + break; + } + } else { + if (!(rxcw & E1000_RXCW_SYNCH)) { + mac->serdes_has_link = false; + mac->serdes_link_state = e1000_serdes_link_down; + DEBUGOUT("ANYSTATE -> DOWN\n"); + } else { + /* + * We have sync, and can tolerate one + * invalid (IV) codeword before declaring + * link down, so reread to look again + */ + usec_delay(10); + rxcw = E1000_READ_REG(hw, E1000_RXCW); + if (rxcw & E1000_RXCW_IV) { + mac->serdes_link_state = e1000_serdes_link_down; + mac->serdes_has_link = false; + DEBUGOUT("ANYSTATE -> DOWN\n"); + } + } + } + + return (ret_val); +} + +/* * e1000_valid_led_default_82571 - Verify a valid default LED config * @hw: pointer to the HW structure * @data: pointer to the NVM (EEPROM) @@ -1332,11 +1636,19 @@ goto out; } - if ((hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) && - *data == ID_LED_RESERVED_F746) - *data = ID_LED_DEFAULT_82573; - else if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF) - *data = ID_LED_DEFAULT; + switch (hw->mac.type) { + case e1000_82573: + case e1000_82574: + case e1000_82583: + if (*data == ID_LED_RESERVED_F746) + *data = ID_LED_DEFAULT_82573; + break; + default: + if (*data == ID_LED_RESERVED_0000 || + *data == ID_LED_RESERVED_FFFF) + *data = ID_LED_DEFAULT; + break; + } out: return (ret_val); @@ -1455,9 +1767,19 @@ s32 ret_val = E1000_SUCCESS; DEBUGFUNC("e1000_read_mac_addr_82571"); - if (e1000_check_alt_mac_addr_generic(hw)) - ret_val = e1000_read_mac_addr_generic(hw); + /* + * If there's an alternate MAC address place it in RAR0 + * so that it will override the Si installed default perm + * address. + */ + ret_val = e1000_check_alt_mac_addr_generic(hw); + if (ret_val) + goto out; + + ret_val = e1000_read_mac_addr_generic(hw); + +out: return (ret_val); } @@ -1494,6 +1816,7 @@ DEBUGFUNC("e1000_clear_hw_cntrs_82571"); e1000_clear_hw_cntrs_base_generic(hw); + (void) E1000_READ_REG(hw, E1000_PRC64); (void) E1000_READ_REG(hw, E1000_PRC127); (void) E1000_READ_REG(hw, E1000_PRC255);
--- a/usr/src/uts/common/io/e1000g/e1000_82571.h Tue Sep 29 11:19:43 2009 +0800 +++ b/usr/src/uts/common/io/e1000g/e1000_82571.h Tue Sep 29 12:12:23 2009 +0800 @@ -24,7 +24,7 @@ */ /* - * IntelVersion: 1.16 sol_anvik_patch + * IntelVersion: 1.16 v3-1-3_2009-8-20 */ #ifndef _E1000_82571_H_ #define _E1000_82571_H_
--- a/usr/src/uts/common/io/e1000g/e1000_api.c Tue Sep 29 11:19:43 2009 +0800 +++ b/usr/src/uts/common/io/e1000g/e1000_api.c Tue Sep 29 12:12:23 2009 +0800 @@ -24,7 +24,7 @@ */ /* - * IntelVersion: 1.107 sol_anvik_patch + * IntelVersion: 1.124 v3-1-3_2009-8-20 */ #include "e1000_api.h" @@ -211,8 +211,12 @@ mac->type = e1000_82573; break; case E1000_DEV_ID_82574L: + case E1000_DEV_ID_82574LA: mac->type = e1000_82574; break; + case E1000_DEV_ID_82583V: + mac->type = e1000_82583; + break; case E1000_DEV_ID_80003ES2LAN_COPPER_DPT: case E1000_DEV_ID_80003ES2LAN_SERDES_DPT: case E1000_DEV_ID_80003ES2LAN_COPPER_SPT: @@ -244,8 +248,15 @@ break; case E1000_DEV_ID_ICH10_D_BM_LM: case E1000_DEV_ID_ICH10_D_BM_LF: + case E1000_DEV_ID_ICH10_HANKSVILLE: mac->type = e1000_ich10lan; break; + case E1000_DEV_ID_PCH_D_HV_DM: + case E1000_DEV_ID_PCH_D_HV_DC: + case E1000_DEV_ID_PCH_M_HV_LM: + case E1000_DEV_ID_PCH_M_HV_LC: + mac->type = e1000_pchlan; + break; default: /* Should never have loaded on this device */ ret_val = -E1000_ERR_MAC_INIT; @@ -278,6 +289,7 @@ DEBUGOUT("ERROR: MAC type could not be set properly.\n"); goto out; } + if (!hw->hw_addr) { DEBUGOUT("ERROR: Registers not mapped\n"); ret_val = -E1000_ERR_CONFIG; @@ -322,6 +334,7 @@ case e1000_82572: case e1000_82573: case e1000_82574: + case e1000_82583: e1000_init_function_pointers_82571(hw); break; case e1000_80003es2lan: @@ -330,6 +343,7 @@ case e1000_ich8lan: case e1000_ich9lan: case e1000_ich10lan: + case e1000_pchlan: e1000_init_function_pointers_ich8lan(hw); break; default: @@ -354,7 +368,6 @@ ret_val = e1000_init_phy_params(hw); if (ret_val) goto out; - } out: @@ -413,26 +426,17 @@ * @hw: pointer to the HW structure * @mc_addr_list: array of multicast addresses to program * @mc_addr_count: number of multicast addresses to program - * @rar_used_count: the first RAR register free to program - * @rar_count: total number of supported Receive Address Registers * - * Updates the Receive Address Registers and Multicast Table Array. + * Updates the Multicast Table Array. * The caller must have a packed mc_addr_list of multicast addresses. - * The parameter rar_count will usually be hw->mac.rar_entry_count - * unless there are workarounds that change this. Currently no func pointer - * exists and all implementations are handled in the generic version of this - * function. */ void e1000_update_mc_addr_list(struct e1000_hw *hw, u8 *mc_addr_list, - u32 mc_addr_count, u32 rar_used_count, u32 rar_count) + u32 mc_addr_count) { if (hw->mac.ops.update_mc_addr_list) - hw->mac.ops.update_mc_addr_list(hw, - mc_addr_list, - mc_addr_count, - rar_used_count, - rar_count); + hw->mac.ops.update_mc_addr_list(hw, mc_addr_list, + mc_addr_count); } /* @@ -615,6 +619,22 @@ } /* + * e1000_id_led_init - store LED configurations in SW + * @hw: pointer to the HW structure + * + * Initializes the LED config in SW. This is a function pointer entry point + * called by drivers. + */ +s32 +e1000_id_led_init(struct e1000_hw *hw) +{ + if (hw->mac.ops.id_led_init) + return (hw->mac.ops.id_led_init(hw)); + + return (E1000_SUCCESS); +} + +/* * e1000_led_on - Turn on SW controllable LED * @hw: pointer to the HW structure *
--- a/usr/src/uts/common/io/e1000g/e1000_api.h Tue Sep 29 11:19:43 2009 +0800 +++ b/usr/src/uts/common/io/e1000g/e1000_api.h Tue Sep 29 12:12:23 2009 +0800 @@ -24,7 +24,7 @@ */ /* - * IntelVersion: 1.50 sol_anvik_patch + * IntelVersion: 1.53 v3-1-3_2009-8-20 */ #ifndef _E1000_API_H_ #define _E1000_API_H_ @@ -63,14 +63,14 @@ void e1000_mta_set(struct e1000_hw *hw, u32 hash_value); u32 e1000_hash_mc_addr(struct e1000_hw *hw, u8 *mc_addr); void e1000_update_mc_addr_list(struct e1000_hw *hw, - u8 *mc_addr_list, u32 mc_addr_count, - u32 rar_used_count, u32 rar_count); + u8 *mc_addr_list, u32 mc_addr_count); s32 e1000_setup_led(struct e1000_hw *hw); s32 e1000_cleanup_led(struct e1000_hw *hw); s32 e1000_check_reset_block(struct e1000_hw *hw); s32 e1000_blink_led(struct e1000_hw *hw); s32 e1000_led_on(struct e1000_hw *hw); s32 e1000_led_off(struct e1000_hw *hw); +s32 e1000_id_led_init(struct e1000_hw *hw); void e1000_reset_adaptive(struct e1000_hw *hw); void e1000_update_adaptive(struct e1000_hw *hw); s32 e1000_get_cable_length(struct e1000_hw *hw); @@ -86,7 +86,7 @@ void e1000_power_up_phy(struct e1000_hw *hw); void e1000_power_down_phy(struct e1000_hw *hw); s32 e1000_read_mac_addr(struct e1000_hw *hw); -s32 e1000_read_pba_num(struct e1000_hw *hw, u32 *pba_num); +s32 e1000_read_pba_num(struct e1000_hw *hw, u32 *part_num); void e1000_reload_nvm(struct e1000_hw *hw); s32 e1000_update_nvm_checksum(struct e1000_hw *hw); s32 e1000_validate_nvm_checksum(struct e1000_hw *hw);
--- a/usr/src/uts/common/io/e1000g/e1000_defines.h Tue Sep 29 11:19:43 2009 +0800 +++ b/usr/src/uts/common/io/e1000g/e1000_defines.h Tue Sep 29 12:12:23 2009 +0800 @@ -24,15 +24,11 @@ */ /* - * IntelVersion: 1.79 sol_anvik_patch + * IntelVersion: 1.116 v3-1-3_2009-8-20 */ #ifndef _E1000_DEFINES_H_ #define _E1000_DEFINES_H_ -#ifdef __cplusplus -extern "C" { -#endif - /* Number of Transmit and Receive Descriptors must be a multiple of 8 */ #define REQ_TX_DESCRIPTOR_MULTIPLE 8 #define REQ_RX_DESCRIPTOR_MULTIPLE 8 @@ -62,19 +58,33 @@ #define E1000_WUFC_FLX1_PHY 0x00002000 /* Flexible Filter 1 Enable */ #define E1000_WUFC_FLX2_PHY 0x00004000 /* Flexible Filter 2 Enable */ #define E1000_WUFC_FLX3_PHY 0x00008000 /* Flexible Filter 3 Enable */ +#define E1000_WUFC_FLX4_PHY 0x00000200 /* Flexible Filter 4 Enable */ +#define E1000_WUFC_FLX5_PHY 0x00000400 /* Flexible Filter 5 Enable */ #define E1000_WUFC_IGNORE_TCO 0x00008000 /* Ignore WakeOn TCO packets */ #define E1000_WUFC_FLX0 0x00010000 /* Flexible Filter 0 Enable */ #define E1000_WUFC_FLX1 0x00020000 /* Flexible Filter 1 Enable */ #define E1000_WUFC_FLX2 0x00040000 /* Flexible Filter 2 Enable */ #define E1000_WUFC_FLX3 0x00080000 /* Flexible Filter 3 Enable */ +#define E1000_WUFC_FLX4 0x00100000 /* Flexible Filter 4 Enable */ +#define E1000_WUFC_FLX5 0x00200000 /* Flexible Filter 5 Enable */ /* Mask for all wakeup filters */ #define E1000_WUFC_ALL_FILTERS_PHY_4 0x0000F0FF #define E1000_WUFC_FLX_OFFSET_PHY 12 /* Offset to the Flexible Filters bits */ /* Mask for 4 flexible filters */ -#define E1000_WUFC_FLX_FILTERS_PHY_4 0x0000F000 +#define E1000_WUFC_FLX_FILTERS_PHY_4 0x0000F000 +/* Mask for 6 wakeup filters */ +#define E1000_WUFC_ALL_FILTERS_PHY_6 0x0000F6FF +/* Mask for 6 flexible filters */ +#define E1000_WUFC_FLX_FILTERS_PHY_6 0x0000F600 #define E1000_WUFC_ALL_FILTERS 0x000F00FF /* Mask for all wakeup filters */ -#define E1000_WUFC_FLX_OFFSET 16 /* Offset to the Flexible Filters bits */ -#define E1000_WUFC_FLX_FILTERS 0x000F0000 /* Mask for the 4 flexible filters */ +/* Mask for all 6 wakeup filters */ +#define E1000_WUFC_ALL_FILTERS_6 0x003F00FF +/* Offset to the Flexible Filters bits */ +#define E1000_WUFC_FLX_OFFSET 16 +/* Mask for the 4 flexible filters */ +#define E1000_WUFC_FLX_FILTERS 0x000F0000 +/* Mask for 6 flexible filters */ +#define E1000_WUFC_FLX_FILTERS_6 0x003F0000 /* Wake Up Status */ #define E1000_WUS_LNKC E1000_WUFC_LNKC @@ -89,23 +99,34 @@ #define E1000_WUS_FLX1_PHY E1000_WUFC_FLX1_PHY #define E1000_WUS_FLX2_PHY E1000_WUFC_FLX2_PHY #define E1000_WUS_FLX3_PHY E1000_WUFC_FLX3_PHY +#define E1000_WUS_FLX4_PHY E1000_WUFC_FLX4_PHY +#define E1000_WUS_FLX5_PHY E1000_WUFC_FLX5_PHY + #define E1000_WUS_FLX_FILTERS_PHY_4 E1000_WUFC_FLX_FILTERS_PHY_4 #define E1000_WUS_FLX0 E1000_WUFC_FLX0 #define E1000_WUS_FLX1 E1000_WUFC_FLX1 #define E1000_WUS_FLX2 E1000_WUFC_FLX2 #define E1000_WUS_FLX3 E1000_WUFC_FLX3 +#define E1000_WUS_FLX4 E1000_WUFC_FLX4 +#define E1000_WUS_FLX5 E1000_WUFC_FLX5 + #define E1000_WUS_FLX_FILTERS E1000_WUFC_FLX_FILTERS +#define E1000_WUS_FLX_FILTERS_6 E1000_WUFC_FLX_FILTERS_6 +#define E1000_WUS_FLX_FILTERS_PHY_6 E1000_WUFC_FLX_FILTERS_PHY_6 /* Wake Up Packet Length */ #define E1000_WUPL_LENGTH_MASK 0x0FFF /* Only the lower 12 bits are valid */ /* Four Flexible Filters are supported */ #define E1000_FLEXIBLE_FILTER_COUNT_MAX 4 +/* Six Flexible Filters are supported */ +#define E1000_FLEXIBLE_FILTER_COUNT_MAX_6 6 /* Each Flexible Filter is at most 128 (0x80) bytes in length */ #define E1000_FLEXIBLE_FILTER_SIZE_MAX 128 #define E1000_FFLT_SIZE E1000_FLEXIBLE_FILTER_COUNT_MAX +#define E1000_FFLT_SIZE_6 E1000_FLEXIBLE_FILTER_COUNT_MAX_6 #define E1000_FFMT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX #define E1000_FFVT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX @@ -120,17 +141,19 @@ #define E1000_CTRL_EXT_SDP5_DATA 0x00000020 /* Value of SW Definable Pin 5 */ #define E1000_CTRL_EXT_PHY_INT E1000_CTRL_EXT_SDP5_DATA #define E1000_CTRL_EXT_SDP6_DATA 0x00000040 /* Value of SW Definable Pin 6 */ -#define E1000_CTRL_EXT_SDP7_DATA 0x00000080 /* Value of SW Definable Pin 7 */ +#define E1000_CTRL_EXT_SDP3_DATA 0x00000080 /* Value of SW Definable Pin 3 */ /* SDP 4/5 (bits 8,9) are reserved in >= 82575 */ #define E1000_CTRL_EXT_SDP4_DIR 0x00000100 /* Direction of SDP4 0=in 1=out */ #define E1000_CTRL_EXT_SDP5_DIR 0x00000200 /* Direction of SDP5 0=in 1=out */ #define E1000_CTRL_EXT_SDP6_DIR 0x00000400 /* Direction of SDP6 0=in 1=out */ -#define E1000_CTRL_EXT_SDP7_DIR 0x00000800 /* Direction of SDP7 0=in 1=out */ +#define E1000_CTRL_EXT_SDP3_DIR 0x00000800 /* Direction of SDP3 0=in 1=out */ #define E1000_CTRL_EXT_ASDCHK 0x00001000 /* Initiate an ASD sequence */ #define E1000_CTRL_EXT_EE_RST 0x00002000 /* Reinitialize from EEPROM */ #define E1000_CTRL_EXT_IPS 0x00004000 /* Invert Power State */ #define E1000_CTRL_EXT_SPD_BYPS 0x00008000 /* Speed Select Bypass */ #define E1000_CTRL_EXT_RO_DIS 0x00020000 /* Relaxed Ordering disable */ +/* DMA Dynamic Clock Gating */ +#define E1000_CTRL_EXT_DMA_DYN_CLK_EN 0x00080000 #define E1000_CTRL_EXT_LINK_MODE_MASK 0x00C00000 #define E1000_CTRL_EXT_LINK_MODE_GMII 0x00000000 #define E1000_CTRL_EXT_LINK_MODE_TBI 0x00C00000 @@ -149,8 +172,6 @@ #define E1000_CTRL_EXT_DRV_LOAD 0x10000000 /* Driver loaded bit for FW */ /* IAME enable bit (27) was removed in >= 82575 */ #define E1000_CTRL_EXT_IAME 0x08000000 /* Int acknowledge Auto-mask */ -/* Clear Interrupt timers after IMS clear */ -#define E1000_CTRL_EXT_INT_TIMER_CLR 0x20000000 /* packet buffer parity error detection enabled */ #define E1000_CRTL_EXT_PB_PAREN 0x01000000 /* descriptor FIFO parity error detection enable */ @@ -158,6 +179,7 @@ #define E1000_CTRL_EXT_GHOST_PAREN 0x40000000 #define E1000_CTRL_EXT_PBA_CLR 0x80000000 /* PBA Clear */ #define E1000_CTRL_EXT_LSECCK 0x00001000 +#define E1000_CTRL_EXT_PHYPDEN 0x00100000 #define E1000_I2CCMD_REG_ADDR_SHIFT 16 #define E1000_I2CCMD_REG_ADDR 0x00FF0000 #define E1000_I2CCMD_PHY_ADDR_SHIFT 24 @@ -283,8 +305,8 @@ #define E1000_RCTL_RST 0x00000001 /* Software reset */ #define E1000_RCTL_EN 0x00000002 /* enable */ #define E1000_RCTL_SBP 0x00000004 /* store bad packet */ -#define E1000_RCTL_UPE 0x00000008 /* unicast promiscuous enable */ -#define E1000_RCTL_MPE 0x00000010 /* multicast promiscuous enab */ +#define E1000_RCTL_UPE 0x00000008 /* unicast promisc enable */ +#define E1000_RCTL_MPE 0x00000010 /* multicast promisc enable */ #define E1000_RCTL_LPE 0x00000020 /* long packet enable */ #define E1000_RCTL_LBM_NO 0x00000000 /* no loopback mode */ #define E1000_RCTL_LBM_MAC 0x00000040 /* MAC loopback mode */ @@ -292,9 +314,9 @@ #define E1000_RCTL_LBM_TCVR 0x000000C0 /* tcvr loopback mode */ #define E1000_RCTL_DTYP_MASK 0x00000C00 /* Descriptor type mask */ #define E1000_RCTL_DTYP_PS 0x00000400 /* Packet Split descriptor */ -#define E1000_RCTL_RDMTS_HALF 0x00000000 /* rx desc min threshold size */ -#define E1000_RCTL_RDMTS_QUAT 0x00000100 /* rx desc min threshold size */ -#define E1000_RCTL_RDMTS_EIGTH 0x00000200 /* rx desc min threshold size */ +#define E1000_RCTL_RDMTS_HALF 0x00000000 /* rx desc min thresh size */ +#define E1000_RCTL_RDMTS_QUAT 0x00000100 /* rx desc min thresh size */ +#define E1000_RCTL_RDMTS_EIGTH 0x00000200 /* rx desc min thresh size */ #define E1000_RCTL_MO_SHIFT 12 /* multicast offset shift */ #define E1000_RCTL_MO_0 0x00000000 /* multicast offset 11:0 */ #define E1000_RCTL_MO_1 0x00001000 /* multicast offset 12:1 */ @@ -349,10 +371,10 @@ #define E1000_PSRCTL_BSIZE3_SHIFT 14 /* Shift _left_ 14 */ /* SWFW_SYNC Definitions */ -#define E1000_SWFW_EEP_SM 0x1 -#define E1000_SWFW_PHY0_SM 0x2 -#define E1000_SWFW_PHY1_SM 0x4 -#define E1000_SWFW_CSR_SM 0x8 +#define E1000_SWFW_EEP_SM 0x01 +#define E1000_SWFW_PHY0_SM 0x02 +#define E1000_SWFW_PHY1_SM 0x04 +#define E1000_SWFW_CSR_SM 0x08 /* FACTPS Definitions */ #define E1000_FACTPS_LFS 0x40000000 /* LAN Function Select */ @@ -360,7 +382,7 @@ #define E1000_CTRL_FD 0x00000001 /* Full duplex.0=half; 1=full */ #define E1000_CTRL_BEM 0x00000002 /* Endian Mode.0=little,1=big */ #define E1000_CTRL_PRIOR 0x00000004 /* Priority on PCI. 0=rx,1=fair */ -#define E1000_CTRL_GIO_MASTER_DISABLE 0x00000004 /* Block new Master requests */ +#define E1000_CTRL_GIO_MASTER_DISABLE 0x00000004 /* Block new Master reqs */ #define E1000_CTRL_LRST 0x00000008 /* Link reset. 0=normal,1=reset */ #define E1000_CTRL_TME 0x00000010 /* Test mode. 0=normal,1=test */ #define E1000_CTRL_SLE 0x00000020 /* Serial Link on 0=dis,1=en */ @@ -460,6 +482,7 @@ #define E1000_STATUS_SPEED_1000 0x00000080 /* Speed 1000Mb/s */ #define E1000_STATUS_LAN_INIT_DONE 0x00000200 /* Lan Init Completion by NVM */ #define E1000_STATUS_ASDV 0x00000300 /* Auto speed detect value */ +#define E1000_STATUS_PHYRA 0x00000400 /* PHY Reset Asserted */ /* Change in Dock/Undock state. Clear on write '0'. */ #define E1000_STATUS_DOCK_CI 0x00000800 /* Master request status */ @@ -519,6 +542,11 @@ #define AUTONEG_ADVERTISE_SPEED_DEFAULT E1000_ALL_SPEED_DUPLEX /* LED Control */ +#define E1000_PHY_LED0_MODE_MASK 0x00000007 +#define E1000_PHY_LED0_IVRT 0x00000008 +#define E1000_PHY_LED0_BLINK 0x00000010 +#define E1000_PHY_LED0_MASK 0x0000001F + #define E1000_LEDCTL_LED0_MODE_MASK 0x0000000F #define E1000_LEDCTL_LED0_MODE_SHIFT 0 #define E1000_LEDCTL_LED0_BLINK_RATE 0x00000020 @@ -680,14 +708,19 @@ /* PBA constants */ #define E1000_PBA_6K 0x0006 /* 6KB */ #define E1000_PBA_8K 0x0008 /* 8KB */ +#define E1000_PBA_10K 0x000A /* 10KB */ #define E1000_PBA_12K 0x000C /* 12KB */ +#define E1000_PBA_14K 0x000E /* 14KB */ #define E1000_PBA_16K 0x0010 /* 16KB */ +#define E1000_PBA_18K 0x0012 #define E1000_PBA_20K 0x0014 #define E1000_PBA_22K 0x0016 #define E1000_PBA_24K 0x0018 +#define E1000_PBA_26K 0x001A #define E1000_PBA_30K 0x001E #define E1000_PBA_32K 0x0020 #define E1000_PBA_34K 0x0022 +#define E1000_PBA_35K 0x0023 #define E1000_PBA_38K 0x0026 #define E1000_PBA_40K 0x0028 #define E1000_PBA_48K 0x0030 /* 48KB */ @@ -708,6 +741,9 @@ #define E1000_SWSM_WMNG 0x00000004 /* Wake MNG Clock */ #define E1000_SWSM_DRV_LOAD 0x00000008 /* Driver Loaded Bit */ +/* Secondary driver semaphore bit */ +#define E1000_SWSM2_LOCK 0x00000002 + /* Interrupt Cause Read */ #define E1000_ICR_TXDW 0x00000001 /* Transmit desc written back */ #define E1000_ICR_TXQE 0x00000002 /* Transmit Queue empty */ @@ -758,6 +794,15 @@ #define E1000_ICR_TXQ1 0x00800000 /* Tx Queue 1 Interrupt */ #define E1000_ICR_OTHER 0x01000000 /* Other Interrupts */ +/* PBA ECC Register */ +#define E1000_PBA_ECC_COUNTER_MASK 0xFFF00000 /* ECC counter mask */ +#define E1000_PBA_ECC_COUNTER_SHIFT 20 /* ECC counter shift value */ +/* Enable ECC error correction */ +#define E1000_PBA_ECC_CORR_EN 0x00000001 +#define E1000_PBA_ECC_STAT_CLR 0x00000002 /* Clear ECC error counter */ +/* Enable ICR bit 5 on ECC error */ +#define E1000_PBA_ECC_INT_EN 0x00000004 + /* * This defines the bits that are set in the Interrupt Mask * Set/Read Register. Each bit is documented below: @@ -785,7 +830,7 @@ E1000_IMS_LSC) /* Interrupt Mask Set */ -#define E1000_IMS_TXDW E1000_ICR_TXDW /* Transmit desc written back */ +#define E1000_IMS_TXDW E1000_ICR_TXDW /* Tx desc written back */ #define E1000_IMS_TXQE E1000_ICR_TXQE /* Transmit Queue empty */ #define E1000_IMS_LSC E1000_ICR_LSC /* Link Status Change */ #define E1000_IMS_VMMB E1000_ICR_VMMB /* Mail box activity */ @@ -827,7 +872,7 @@ #define E1000_IMS_OTHER E1000_ICR_OTHER /* Other Interrupts */ /* Interrupt Cause Set */ -#define E1000_ICS_TXDW E1000_ICR_TXDW /* Transmit desc written back */ +#define E1000_ICS_TXDW E1000_ICR_TXDW /* Tx desc written back */ #define E1000_ICS_TXQE E1000_ICR_TXQE /* Transmit Queue empty */ #define E1000_ICS_LSC E1000_ICR_LSC /* Link Status Change */ #define E1000_ICS_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */ @@ -892,6 +937,10 @@ */ #define E1000_RAR_ENTRIES 15 #define E1000_RAH_AV 0x80000000 /* Receive descriptor valid */ +#define E1000_RAL_MAC_ADDR_LEN 4 +#define E1000_RAH_MAC_ADDR_LEN 2 +#define E1000_RAH_POOL_MASK 0x03FC0000 +#define E1000_RAH_POOL_1 0x00040000 /* Error Codes */ #define E1000_SUCCESS 0 @@ -907,6 +956,7 @@ #define E1000_BLK_PHY_RESET 12 #define E1000_ERR_SWFW_SYNC 13 #define E1000_NOT_IMPLEMENTED 14 +#define E1000_ERR_MBX 15 /* Loop limit on how long we wait for auto-negotiation to complete */ #define FIBER_LINK_UP_LIMIT 50 @@ -956,6 +1006,10 @@ #define E1000_GCR_TXD_NO_SNOOP 0x00000008 #define E1000_GCR_TXDSCW_NO_SNOOP 0x00000010 #define E1000_GCR_TXDSCR_NO_SNOOP 0x00000020 +#define E1000_GCR_CMPL_TMOUT_MASK 0x0000F000 +#define E1000_GCR_CMPL_TMOUT_10ms 0x00001000 +#define E1000_GCR_CMPL_TMOUT_RESEND 0x00010000 +#define E1000_GCR_CAP_VER2 0x00040000 #define PCIE_NO_SNOOP_ALL (E1000_GCR_RXD_NO_SNOOP | \ E1000_GCR_RXDSCW_NO_SNOOP | \ @@ -1071,6 +1125,8 @@ #define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */ #define PHY_EXT_STATUS 0x0F /* Extended Status Reg */ +#define PHY_CONTROL_LB 0x4000 /* PHY Loopback bit */ + /* NVM Control */ #define E1000_EECD_SK 0x00000001 /* NVM Clock */ #define E1000_EECD_CS 0x00000002 /* NVM Chip Select */ @@ -1101,6 +1157,7 @@ #define E1000_EECD_SHADV 0x00200000 /* Shadow RAM Data Valid */ #define E1000_EECD_SEC1VAL 0x00400000 /* Sector One Valid */ #define E1000_EECD_SECVAL_SHIFT 22 +#define E1000_EECD_SEC1VAL_VALID_MASK (E1000_EECD_AUTO_RD | E1000_EECD_PRES) #define E1000_NVM_SWDPIN0 0x0001 /* SWDPIN 0 NVM Value */ #define E1000_NVM_LED_LOGIC 0x0020 /* Led Logic Word */ @@ -1132,8 +1189,10 @@ #define NVM_ALT_MAC_ADDR_PTR 0x0037 #define NVM_CHECKSUM_REG 0x003F -#define E1000_NVM_CFG_DONE_PORT_0 0x40000 /* MNG config cycle done */ -#define E1000_NVM_CFG_DONE_PORT_1 0x80000 /* ...for second port */ +/* MNG config cycle done */ +#define E1000_NVM_CFG_DONE_PORT_0 0x040000 +/* ...for second port */ +#define E1000_NVM_CFG_DONE_PORT_1 0x080000 /* Mask bits for fields in Word 0x0f of the NVM */ #define NVM_WORD0F_PAUSE_MASK 0x3000 @@ -1211,6 +1270,7 @@ #define PCIX_STATUS_REGISTER_HI 0xEA #define PCI_HEADER_TYPE_REGISTER 0x0E #define PCIE_LINK_STATUS 0x12 +#define PCIE_DEVICE_CONTROL2 0x28 #define PCIX_COMMAND_MMRBC_MASK 0x000C #define PCIX_COMMAND_MMRBC_SHIFT 0x2 @@ -1222,6 +1282,7 @@ #define PCI_HEADER_TYPE_MULTIFUNC 0x80 #define PCIE_LINK_WIDTH_MASK 0x3F0 #define PCIE_LINK_WIDTH_SHIFT 4 +#define PCIE_DEVICE_CONTROL2_16ms 0x0005 #ifndef ETH_ADDR_LEN #define ETH_ADDR_LEN 6 @@ -1249,6 +1310,8 @@ #define IFE_C_E_PHY_ID 0x02A80310 #define BME1000_E_PHY_ID 0x01410CB0 #define BME1000_E_PHY_ID_R2 0x01410CB1 +#define I82577_E_PHY_ID 0x01540050 +#define I82578_E_PHY_ID 0x004DD040 #define M88_VENDOR 0x0141 /* M88E1000 Specific Registers */ @@ -1267,7 +1330,7 @@ /* M88E1000 PHY Specific Control Register */ #define M88E1000_PSCR_JABBER_DISABLE 0x0001 /* 1=Jabber Function disabled */ -#define M88E1000_PSCR_POLARITY_REVERSAL 0x0002 /* 1=Polarity Reversal enabled */ +#define M88E1000_PSCR_POLARITY_REVERSAL 0x0002 /* 1=Polarity Reverse enabled */ #define M88E1000_PSCR_SQE_TEST 0x0004 /* 1=SQE Test enabled */ /* 1=CLK125 low, 0=CLK125 toggling */ #define M88E1000_PSCR_CLK125_DISABLE 0x0010 @@ -1287,7 +1350,7 @@ #define M88E1000_PSCR_MII_5BIT_ENABLE 0x0100 #define M88E1000_PSCR_SCRAMBLER_DISABLE 0x0200 /* 1=Scrambler disable */ #define M88E1000_PSCR_FORCE_LINK_GOOD 0x0400 /* 1=Force link good */ -#define M88E1000_PSCR_ASSERT_CRS_ON_TX 0x0800 /* 1=Assert CRS on Transmit */ +#define M88E1000_PSCR_ASSERT_CRS_ON_TX 0x0800 /* 1=Assert CRS on Tx */ /* M88E1000 PHY Specific Status Register */ #define M88E1000_PSSR_JABBER 0x0001 /* 1=Jabber */ @@ -1355,6 +1418,9 @@ #define M88EC018_EPSCR_DOWNSHIFT_COUNTER_7X 0x0C00 #define M88EC018_EPSCR_DOWNSHIFT_COUNTER_8X 0x0E00 +#define I82578_EPSCR_DOWNSHIFT_ENABLE 0x0020 +#define I82578_EPSCR_DOWNSHIFT_COUNTER_MASK 0x001C + /* BME1000 PHY Specific Control Register */ #define BME1000_PSCR_ENABLE_DOWNSHIFT 0x0800 /* 1 = enable downshift */ @@ -1449,8 +1515,4 @@ #define E1000_GEN_CTL_ADDRESS_SHIFT 8 #define E1000_GEN_POLL_TIMEOUT 640 -#ifdef __cplusplus -} -#endif - #endif /* _E1000_DEFINES_H_ */
--- a/usr/src/uts/common/io/e1000g/e1000_hw.h Tue Sep 29 11:19:43 2009 +0800 +++ b/usr/src/uts/common/io/e1000g/e1000_hw.h Tue Sep 29 12:12:23 2009 +0800 @@ -24,7 +24,7 @@ */ /* - * IntelVersion: 1.398 sol_anvik_patch + * IntelVersion: 1.432 v3-1-3_2009-8-20 */ #ifndef _E1000_HW_H_ #define _E1000_HW_H_ @@ -92,6 +92,8 @@ #define E1000_DEV_ID_82573E_IAMT 0x108C #define E1000_DEV_ID_82573L 0x109A #define E1000_DEV_ID_82574L 0x10D3 +#define E1000_DEV_ID_82574LA 0x10F6 +#define E1000_DEV_ID_82583V 0x150C #define E1000_DEV_ID_80003ES2LAN_COPPER_DPT 0x1096 #define E1000_DEV_ID_80003ES2LAN_SERDES_DPT 0x1098 #define E1000_DEV_ID_80003ES2LAN_COPPER_SPT 0x10BA @@ -115,8 +117,13 @@ #define E1000_DEV_ID_ICH10_R_BM_LM 0x10CC #define E1000_DEV_ID_ICH10_R_BM_LF 0x10CD #define E1000_DEV_ID_ICH10_R_BM_V 0x10CE +#define E1000_DEV_ID_ICH10_HANKSVILLE 0xF0FE #define E1000_DEV_ID_ICH10_D_BM_LM 0x10DE #define E1000_DEV_ID_ICH10_D_BM_LF 0x10DF +#define E1000_DEV_ID_PCH_M_HV_LM 0x10EA +#define E1000_DEV_ID_PCH_M_HV_LC 0x10EB +#define E1000_DEV_ID_PCH_D_HV_DM 0x10EF +#define E1000_DEV_ID_PCH_D_HV_DC 0x10F0 #define E1000_REVISION_0 0 #define E1000_REVISION_1 1 @@ -127,6 +134,12 @@ #define E1000_FUNC_0 0 #define E1000_FUNC_1 1 +#define E1000_ALT_MAC_ADDRESS_OFFSET_LAN0 0 +#define E1000_ALT_MAC_ADDRESS_OFFSET_LAN1 3 + +/* Maximum size of the MTA register table in all supported adapters */ +#define MAX_MTA_REG 128 + enum e1000_mac_type { e1000_undefined = 0, e1000_82542, @@ -145,10 +158,12 @@ e1000_82572, e1000_82573, e1000_82574, + e1000_82583, e1000_80003es2lan, e1000_ich8lan, e1000_ich9lan, e1000_ich10lan, + e1000_pchlan, e1000_num_macs /* List is 1-based, so subtract 1 for true count. */ }; @@ -187,7 +202,8 @@ e1000_phy_igp_3, e1000_phy_ife, e1000_phy_bm, - e1000_phy_vf + e1000_phy_82578, + e1000_phy_82577, }; enum e1000_bus_type { @@ -267,6 +283,13 @@ e1000_smart_speed_off }; +enum e1000_serdes_link_state { + e1000_serdes_link_down = 0, + e1000_serdes_link_autoneg_progress, + e1000_serdes_link_autoneg_complete, + e1000_serdes_link_forced_up +}; + /* Receive Descriptor */ struct e1000_rx_desc { __le64 buffer_addr; /* Address of the descriptor's data buffer */ @@ -537,6 +560,7 @@ struct e1000_mac_operations { /* Function pointers for the MAC. */ s32 (*init_params)(struct e1000_hw *); + s32 (*id_led_init)(struct e1000_hw *); s32 (*blink_led)(struct e1000_hw *); s32 (*check_for_link)(struct e1000_hw *); bool (*check_mng_mode)(struct e1000_hw *hw); @@ -544,10 +568,11 @@ void (*clear_hw_cntrs)(struct e1000_hw *); void (*clear_vfta)(struct e1000_hw *); s32 (*get_bus_info)(struct e1000_hw *); + void (*set_lan_id)(struct e1000_hw *); s32 (*get_link_up_info)(struct e1000_hw *, u16 *, u16 *); s32 (*led_on)(struct e1000_hw *); s32 (*led_off)(struct e1000_hw *); - void (*update_mc_addr_list)(struct e1000_hw *, u8 *, u32, u32, u32); + void (*update_mc_addr_list)(struct e1000_hw *, u8 *, u32); s32 (*reset_hw)(struct e1000_hw *); s32 (*init_hw)(struct e1000_hw *); s32 (*setup_link)(struct e1000_hw *); @@ -620,6 +645,7 @@ u16 ifs_ratio; u16 ifs_step_size; u16 mta_reg_count; + u32 mta_shadow[MAX_MTA_REG]; u16 rar_entry_count; u8 forced_speed_duplex; @@ -632,6 +658,7 @@ bool get_link_status; bool in_ifs_mode; bool report_tx_early; + enum e1000_serdes_link_state serdes_link_state; bool serdes_has_link; bool tx_pkt_filtering; }; @@ -728,6 +755,11 @@ struct e1000_dev_spec_82571 { bool laa_is_present; + u32 smb_counter; +}; + +struct e1000_dev_spec_80003es2lan { + bool mdic_wa_enable; }; struct e1000_shadow_ram { @@ -740,6 +772,8 @@ struct e1000_dev_spec_ich8lan { bool kmrn_lock_loss_workaround_enabled; struct e1000_shadow_ram shadow_ram[E1000_SHADOW_RAM_WORDS]; + E1000_MUTEX nvm_mutex; + E1000_MUTEX swflag_mutex; }; struct e1000_hw { @@ -761,6 +795,7 @@ struct e1000_dev_spec_82542 _82542; struct e1000_dev_spec_82543 _82543; struct e1000_dev_spec_82571 _82571; + struct e1000_dev_spec_80003es2lan _80003es2lan; struct e1000_dev_spec_ich8lan ich8lan; } dev_spec; @@ -782,6 +817,7 @@ void e1000_pci_clear_mwi(struct e1000_hw *hw); void e1000_pci_set_mwi(struct e1000_hw *hw); s32 e1000_read_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value); +s32 e1000_write_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value); void e1000_read_pci_cfg(struct e1000_hw *hw, u32 reg, u16 *value); void e1000_write_pci_cfg(struct e1000_hw *hw, u32 reg, u16 *value);
--- a/usr/src/uts/common/io/e1000g/e1000_ich8lan.c Tue Sep 29 11:19:43 2009 +0800 +++ b/usr/src/uts/common/io/e1000g/e1000_ich8lan.c Tue Sep 29 12:12:23 2009 +0800 @@ -24,7 +24,7 @@ */ /* - * IntelVersion: 1.136 sol_anvik_patch + * IntelVersion: 1.180 v3-1-3_2009-8-20 */ /* @@ -49,19 +49,24 @@ * 82567LF-3 Gigabit Network Connection * 82567LM-3 Gigabit Network Connection * 82567LM-4 Gigabit Network Connection + * 82577LM Gigabit Network Connection + * 82577LC Gigabit Network Connection + * 82578DM Gigabit Network Connection + * 82578DC Gigabit Network Connection */ #include "e1000_api.h" static s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw); +static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw); static s32 e1000_init_nvm_params_ich8lan(struct e1000_hw *hw); static s32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw); static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw); static void e1000_release_swflag_ich8lan(struct e1000_hw *hw); +static s32 e1000_acquire_nvm_ich8lan(struct e1000_hw *hw); +static void e1000_release_nvm_ich8lan(struct e1000_hw *hw); static bool e1000_check_mng_mode_ich8lan(struct e1000_hw *hw); -static s32 e1000_check_polarity_ife_ich8lan(struct e1000_hw *hw); static s32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw); -static s32 e1000_phy_force_speed_duplex_ich8lan(struct e1000_hw *hw); static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw); static s32 e1000_get_phy_info_ich8lan(struct e1000_hw *hw); static s32 e1000_set_d0_lplu_state_ich8lan(struct e1000_hw *hw, @@ -76,6 +81,7 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw); static s32 e1000_valid_led_default_ich8lan(struct e1000_hw *hw, u16 *data); +static s32 e1000_id_led_init_pchlan(struct e1000_hw *hw); static s32 e1000_get_bus_info_ich8lan(struct e1000_hw *hw); static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw); static s32 e1000_init_hw_ich8lan(struct e1000_hw *hw); @@ -86,6 +92,10 @@ static s32 e1000_cleanup_led_ich8lan(struct e1000_hw *hw); static s32 e1000_led_on_ich8lan(struct e1000_hw *hw); static s32 e1000_led_off_ich8lan(struct e1000_hw *hw); +static s32 e1000_setup_led_pchlan(struct e1000_hw *hw); +static s32 e1000_cleanup_led_pchlan(struct e1000_hw *hw); +static s32 e1000_led_on_pchlan(struct e1000_hw *hw); +static s32 e1000_led_off_pchlan(struct e1000_hw *hw); static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw); static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank); static s32 e1000_flash_cycle_ich8lan(struct e1000_hw *hw, u32 timeout); @@ -107,6 +117,7 @@ u8 size, u16 data); static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw); static void e1000_power_down_phy_copper_ich8lan(struct e1000_hw *hw); +static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw); /* ICH GbE Flash Hardware Sequencing Flash Status Register bit breakdown */ /* Offset 04h HSFSTS */ @@ -150,6 +161,56 @@ }; /* + * e1000_init_phy_params_pchlan - Initialize PHY function pointers + * @hw: pointer to the HW structure + * + * Initialize family-specific PHY parameters and function pointers. + */ +static s32 +e1000_init_phy_params_pchlan(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val = E1000_SUCCESS; + + DEBUGFUNC("e1000_init_phy_params_pchlan"); + + phy->addr = 1; + phy->reset_delay_us = 100; + + phy->ops.acquire = e1000_acquire_swflag_ich8lan; + phy->ops.check_polarity = e1000_check_polarity_ife; + phy->ops.check_reset_block = e1000_check_reset_block_ich8lan; + phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_ife; + phy->ops.get_cable_length = e1000_get_cable_length_igp_2; + phy->ops.get_cfg_done = e1000_get_cfg_done_ich8lan; + phy->ops.get_info = e1000_get_phy_info_ich8lan; + phy->ops.read_reg = e1000_read_phy_reg_hv; + phy->ops.release = e1000_release_swflag_ich8lan; + phy->ops.reset = e1000_phy_hw_reset_ich8lan; + phy->ops.set_d0_lplu_state = e1000_set_d0_lplu_state_ich8lan; + phy->ops.set_d3_lplu_state = e1000_set_d3_lplu_state_ich8lan; + phy->ops.write_reg = e1000_write_phy_reg_hv; + phy->ops.power_up = e1000_power_up_phy_copper; + phy->ops.power_down = e1000_power_down_phy_copper_ich8lan; + phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; + + phy->id = e1000_phy_unknown; + e1000_get_phy_id(hw); + phy->type = e1000_get_phy_type_from_id(phy->id); + + if (phy->type == e1000_phy_82577) { + phy->ops.check_polarity = e1000_check_polarity_82577; + phy->ops.force_speed_duplex = + e1000_phy_force_speed_duplex_82577; + phy->ops.get_cable_length = e1000_get_cable_length_82577; + phy->ops.get_info = e1000_get_phy_info_82577; + phy->ops.commit = e1000_phy_sw_reset_generic; + } + + return (ret_val); +} + +/* * e1000_init_phy_params_ich8lan - Initialize PHY function pointers * @hw: pointer to the HW structure * @@ -168,9 +229,9 @@ phy->reset_delay_us = 100; phy->ops.acquire = e1000_acquire_swflag_ich8lan; - phy->ops.check_polarity = e1000_check_polarity_ife_ich8lan; + phy->ops.check_polarity = e1000_check_polarity_ife; phy->ops.check_reset_block = e1000_check_reset_block_ich8lan; - phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_ich8lan; + phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_ife; phy->ops.get_cable_length = e1000_get_cable_length_igp_2; phy->ops.get_cfg_done = e1000_get_cfg_done_ich8lan; phy->ops.get_info = e1000_get_phy_info_ich8lan; @@ -292,10 +353,13 @@ dev_spec->shadow_ram[i].value = 0xFFFF; } + E1000_MUTEX_INIT(&dev_spec->nvm_mutex); + E1000_MUTEX_INIT(&dev_spec->swflag_mutex); + /* Function Pointers */ - nvm->ops.acquire = e1000_acquire_swflag_ich8lan; + nvm->ops.acquire = e1000_acquire_nvm_ich8lan; + nvm->ops.release = e1000_release_nvm_ich8lan; nvm->ops.read = e1000_read_nvm_ich8lan; - nvm->ops.release = e1000_release_swflag_ich8lan; nvm->ops.update = e1000_update_nvm_checksum_ich8lan; nvm->ops.valid_led_default = e1000_valid_led_default_ich8lan; nvm->ops.validate = e1000_validate_nvm_checksum_ich8lan; @@ -337,6 +401,8 @@ /* bus type/speed/width */ mac->ops.get_bus_info = e1000_get_bus_info_ich8lan; + /* function id */ + mac->ops.set_lan_id = e1000_set_lan_id_single_port; /* reset */ mac->ops.reset_hw = e1000_reset_hw_ich8lan; /* hw initialization */ @@ -346,7 +412,7 @@ /* physical interface setup */ mac->ops.setup_physical_interface = e1000_setup_copper_link_ich8lan; /* check for link */ - mac->ops.check_for_link = e1000_check_for_copper_link_generic; + mac->ops.check_for_link = e1000_check_for_copper_link_ich8lan; /* check management mode */ mac->ops.check_mng_mode = e1000_check_mng_mode_ich8lan; /* link info */ @@ -355,18 +421,41 @@ mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic; /* setting MTA */ mac->ops.mta_set = e1000_mta_set_generic; - /* blink LED */ - mac->ops.blink_led = e1000_blink_led_generic; - /* setup LED */ - mac->ops.setup_led = e1000_setup_led_generic; - /* cleanup LED */ - mac->ops.cleanup_led = e1000_cleanup_led_ich8lan; - /* turn on/off LED */ - mac->ops.led_on = e1000_led_on_ich8lan; - mac->ops.led_off = e1000_led_off_ich8lan; /* clear hardware counters */ mac->ops.clear_hw_cntrs = e1000_clear_hw_cntrs_ich8lan; + /* LED operations */ + switch (mac->type) { + case e1000_ich8lan: + case e1000_ich9lan: + case e1000_ich10lan: + /* ID LED init */ + mac->ops.id_led_init = e1000_id_led_init_generic; + /* blink LED */ + mac->ops.blink_led = e1000_blink_led_generic; + /* setup LED */ + mac->ops.setup_led = e1000_setup_led_generic; + /* cleanup LED */ + mac->ops.cleanup_led = e1000_cleanup_led_ich8lan; + /* turn on/off LED */ + mac->ops.led_on = e1000_led_on_ich8lan; + mac->ops.led_off = e1000_led_off_ich8lan; + break; + case e1000_pchlan: + /* ID LED init */ + mac->ops.id_led_init = e1000_id_led_init_pchlan; + /* setup LED */ + mac->ops.setup_led = e1000_setup_led_pchlan; + /* cleanup LED */ + mac->ops.cleanup_led = e1000_cleanup_led_pchlan; + /* turn on/off LED */ + mac->ops.led_on = e1000_led_on_pchlan; + mac->ops.led_off = e1000_led_off_pchlan; + break; + default: + break; + } + /* Enable PCS Lock-loss workaround for ICH8 */ if (mac->type == e1000_ich8lan) e1000_set_kmrn_lock_loss_workaround_ich8lan(hw, true); @@ -375,6 +464,98 @@ } /* + * e1000_check_for_copper_link_ich8lan - Check for link (Copper) + * @hw: pointer to the HW structure + * + * Checks to see of the link status of the hardware has changed. If a + * change in link status has been detected, then we read the PHY registers + * to get the current speed/duplex if link exists. + */ +static s32 +e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + s32 ret_val; + bool link; + + DEBUGFUNC("e1000_check_for_copper_link_ich8lan"); + + /* + * We only want to go out to the PHY registers to see if Auto-Neg + * has completed and/or if our link status has changed. The + * get_link_status flag is set upon receiving a Link Status + * Change or Rx Sequence Error interrupt. + */ + if (!mac->get_link_status) { + ret_val = E1000_SUCCESS; + goto out; + } + + if (hw->mac.type == e1000_pchlan) { + ret_val = e1000_write_kmrn_reg_generic(hw, + E1000_KMRNCTRLSTA_K1_CONFIG, + E1000_KMRNCTRLSTA_K1_ENABLE); + if (ret_val) + goto out; + } + + /* + * First we want to see if the MII Status Register reports + * link. If so, then we want to get the current speed/duplex + * of the PHY. + */ + ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link); + if (ret_val) + goto out; + + if (!link) + goto out; /* No link detected */ + + mac->get_link_status = false; + + if (hw->phy.type == e1000_phy_82578) { + ret_val = e1000_link_stall_workaround_hv(hw); + if (ret_val) + goto out; + } + + /* + * Check if there was DownShift, must be checked + * immediately after link-up + */ + e1000_check_downshift_generic(hw); + + /* + * If we are forcing speed/duplex, then we simply return since + * we have already determined whether we have link or not. + */ + if (!mac->autoneg) { + ret_val = -E1000_ERR_CONFIG; + goto out; + } + + /* + * Auto-Neg is enabled. Auto Speed Detection takes care + * of MAC speed/duplex configuration. So we only need to + * configure Collision Distance in the MAC. + */ + e1000_config_collision_dist_generic(hw); + + /* + * Configure Flow Control now that Auto-Neg has completed. + * First, we need to restore the desired flow control + * settings because we may have had to re-autoneg with a + * different link partner. + */ + ret_val = e1000_config_fc_after_link_up_generic(hw); + if (ret_val) + DEBUGOUT("Error configuring flow control\n"); + +out: + return (ret_val); +} + +/* * e1000_init_function_pointers_ich8lan - Initialize ICH8 function pointers * @hw: pointer to the HW structure * @@ -387,7 +568,48 @@ hw->mac.ops.init_params = e1000_init_mac_params_ich8lan; hw->nvm.ops.init_params = e1000_init_nvm_params_ich8lan; - hw->phy.ops.init_params = e1000_init_phy_params_ich8lan; + switch (hw->mac.type) { + case e1000_ich8lan: + case e1000_ich9lan: + case e1000_ich10lan: + hw->phy.ops.init_params = e1000_init_phy_params_ich8lan; + break; + case e1000_pchlan: + hw->phy.ops.init_params = e1000_init_phy_params_pchlan; + break; + default: + break; + } +} + +/* + * e1000_acquire_nvm_ich8lan - Acquire NVM mutex + * @hw: pointer to the HW structure + * + * Acquires the mutex for performing NVM operations. + */ +static s32 +e1000_acquire_nvm_ich8lan(struct e1000_hw *hw) +{ + DEBUGFUNC("e1000_acquire_nvm_ich8lan"); + + E1000_MUTEX_LOCK(&hw->dev_spec.ich8lan.nvm_mutex); + + return (E1000_SUCCESS); +} + +/* + * e1000_release_nvm_ich8lan - Release NVM mutex + * @hw: pointer to the HW structure + * + * Releases the mutex used while performing NVM operations. + */ +static void +e1000_release_nvm_ich8lan(struct e1000_hw *hw) +{ + DEBUGFUNC("e1000_release_nvm_ich8lan"); + + E1000_MUTEX_UNLOCK(&hw->dev_spec.ich8lan.nvm_mutex); } /* @@ -406,20 +628,40 @@ DEBUGFUNC("e1000_acquire_swflag_ich8lan"); + E1000_MUTEX_LOCK(&hw->dev_spec.ich8lan.swflag_mutex); + while (timeout) { extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); - extcnf_ctrl |= E1000_EXTCNF_CTRL_SWFLAG; - E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl); - - extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); - if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG) + if (!(extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG)) break; + msec_delay_irq(1); timeout--; } if (!timeout) { - DEBUGOUT("FW or HW has locked the resource for too long.\n"); + DEBUGOUT("SW/FW/HW has locked the resource for too long.\n"); + ret_val = -E1000_ERR_CONFIG; + goto out; + } + + /* In some cases, hardware will take up to 400ms to set the SW flag. */ + timeout = SW_FLAG_TIMEOUT; + + extcnf_ctrl |= E1000_EXTCNF_CTRL_SWFLAG; + E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl); + + while (timeout) { + extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); + if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG) + break; + + msec_delay_irq(1); + timeout--; + } + + if (!timeout) { + DEBUGOUT("Failed to acquire the semaphore.\n"); extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG; E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl); ret_val = -E1000_ERR_CONFIG; @@ -427,6 +669,9 @@ } out: + if (ret_val) + E1000_MUTEX_UNLOCK(&hw->dev_spec.ich8lan.swflag_mutex); + return (ret_val); } @@ -448,6 +693,8 @@ extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG; E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl); + + E1000_MUTEX_UNLOCK(&hw->dev_spec.ich8lan.swflag_mutex); } /* @@ -493,80 +740,118 @@ } /* - * e1000_phy_force_speed_duplex_ich8lan - Force PHY speed & duplex - * @hw: pointer to the HW structure - * - * Forces the speed and duplex settings of the PHY. - * This is a function pointer entry point only called by - * PHY setup routines. + * e1000_hv_phy_workarounds_ich8lan - A series of Phy workarounds to be + * done after every PHY reset. */ static s32 -e1000_phy_force_speed_duplex_ich8lan(struct e1000_hw *hw) +e1000_hv_phy_workarounds_ich8lan(struct e1000_hw *hw) { - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; - u16 data; - bool link; - - DEBUGFUNC("e1000_phy_force_speed_duplex_ich8lan"); - - if (phy->type != e1000_phy_ife) { - ret_val = e1000_phy_force_speed_duplex_igp(hw); - goto out; + s32 ret_val = E1000_SUCCESS; + + if (hw->mac.type != e1000_pchlan) + return (ret_val); + + if (((hw->phy.type == e1000_phy_82577) && + ((hw->phy.revision == 1) || (hw->phy.revision == 2))) || + ((hw->phy.type == e1000_phy_82578) && (hw->phy.revision == 1))) { + /* Disable generation of early preamble */ + ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 25), 0x4431); + if (ret_val) + return (ret_val); + + /* Preamble tuning for SSC */ + ret_val = hw->phy.ops.write_reg(hw, PHY_REG(770, 16), 0xA204); + if (ret_val) + return (ret_val); } - ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &data); + + if (hw->phy.type == e1000_phy_82578) { + /* + * Return registers to default by doing a soft reset then + * writing 0x3140 to the control register. + */ + if (hw->phy.revision < 2) { + e1000_phy_sw_reset_generic(hw); + ret_val = hw->phy.ops.write_reg(hw, PHY_CONTROL, + 0x3140); + } + } + + /* Select page 0 */ + ret_val = hw->phy.ops.acquire(hw); if (ret_val) - goto out; - - e1000_phy_force_speed_duplex_setup(hw, &data); - - ret_val = phy->ops.write_reg(hw, PHY_CONTROL, data); + return (ret_val); + + hw->phy.addr = 1; + e1000_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT, 0); + hw->phy.ops.release(hw); + + return (ret_val); +} + +/* + * e1000_hv_phy_tuning_workaround_ich8lan - This is a Phy tuning work around + * needed for Nahum3 + Hanksville testing, requested by HW team + */ +static s32 +e1000_hv_phy_tuning_workaround_ich8lan(struct e1000_hw *hw) +{ + s32 ret_val = E1000_SUCCESS; + + ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 25), 0x4431); if (ret_val) goto out; - /* Disable MDI-X support for 10/100 */ - ret_val = phy->ops.read_reg(hw, IFE_PHY_MDIX_CONTROL, &data); - if (ret_val) - goto out; - - data &= ~IFE_PMC_AUTO_MDIX; - data &= ~IFE_PMC_FORCE_MDIX; - - ret_val = phy->ops.write_reg(hw, IFE_PHY_MDIX_CONTROL, data); + ret_val = hw->phy.ops.write_reg(hw, PHY_REG(770, 16), 0xA204); if (ret_val) goto out; - DEBUGOUT1("IFE PMC: %X\n", data); - - usec_delay(1); - - if (phy->autoneg_wait_to_complete) { - DEBUGOUT("Waiting for forced speed/duplex link on IFE phy.\n"); - - ret_val = e1000_phy_has_link_generic(hw, - PHY_FORCE_LIMIT, - 100000, - &link); - if (ret_val) - goto out; - - if (!link) - DEBUGOUT("Link taking longer than expected.\n"); - - /* Try once more */ - ret_val = e1000_phy_has_link_generic(hw, - PHY_FORCE_LIMIT, - 100000, - &link); - if (ret_val) - goto out; - } + ret_val = hw->phy.ops.write_reg(hw, (1 << 6) | 0x29, 0x66C0); + if (ret_val) + goto out; + + ret_val = hw->phy.ops.write_reg(hw, (1 << 6) | 0x1E, 0xFFFF); out: return (ret_val); } /* + * e1000_lan_init_done_ich8lan - Check for PHY config completion + * @hw: pointer to the HW structure + * + * Check the appropriate indication the MAC has finished configuring the + * PHY after a software reset. + */ +static void +e1000_lan_init_done_ich8lan(struct e1000_hw *hw) +{ + u32 data, loop = E1000_ICH8_LAN_INIT_TIMEOUT; + + DEBUGFUNC("e1000_lan_init_done_ich8lan"); + + /* Wait for basic configuration completes before proceeding */ + do { + data = E1000_READ_REG(hw, E1000_STATUS); + data &= E1000_STATUS_LAN_INIT_DONE; + usec_delay(100); + } while ((!data) && --loop); + + /* + * If basic configuration is incomplete before the above loop + * count reaches 0, loading the configuration from NVM will + * leave the PHY in a bad state possibly resulting in no link. + */ + if (loop == 0) + DEBUGOUT("LAN_INIT_DONE not set, increase timeout\n"); + + /* Clear the Init Done bit for the next init event */ + data = E1000_READ_REG(hw, E1000_STATUS); + data &= ~E1000_STATUS_LAN_INIT_DONE; + E1000_WRITE_REG(hw, E1000_STATUS, data); +} + +/* * e1000_phy_hw_reset_ich8lan - Performs a PHY reset * @hw: pointer to the HW structure * @@ -580,7 +865,6 @@ struct e1000_phy_info *phy = &hw->phy; u32 i, data, cnf_size, cnf_base_addr, sw_cfg_mask; s32 ret_val; - u16 loop = E1000_ICH8_LAN_INIT_TIMEOUT; u16 word_addr, reg_data, reg_addr, phy_page = 0; DEBUGFUNC("e1000_phy_hw_reset_ich8lan"); @@ -589,6 +873,21 @@ if (ret_val) goto out; + /* Allow time for h/w to get to a quiescent state after reset */ + msec_delay(10); + + if (hw->mac.type == e1000_pchlan) { + ret_val = e1000_hv_phy_workarounds_ich8lan(hw); + if (ret_val) + goto out; + } + + if (hw->device_id == E1000_DEV_ID_ICH10_HANKSVILLE) { + ret_val = e1000_hv_phy_tuning_workaround_ich8lan(hw); + if (ret_val) + goto out; + } + /* * Initialize the PHY from the NVM on ICH platforms. This is needed * due to an issue where the NVM configuration is not properly @@ -608,24 +907,7 @@ goto out; /* Wait for basic configuration completes before proceeding */ - do { - data = E1000_READ_REG(hw, E1000_STATUS); - data &= E1000_STATUS_LAN_INIT_DONE; - usec_delay(100); - } while ((!data) && --loop); - - /* - * If basic configuration is incomplete before the above loop - * count reaches 0, loading the configuration from NVM will - * leave the PHY in a bad state possibly resulting in no link. - */ - if (loop == 0) - DEBUGOUT("LAN_INIT_DONE not set, increase timeout\n"); - - /* Clear the Init Done bit for the next init event */ - data = E1000_READ_REG(hw, E1000_STATUS); - data &= ~E1000_STATUS_LAN_INIT_DONE; - E1000_WRITE_REG(hw, E1000_STATUS, data); + e1000_lan_init_done_ich8lan(hw); /* * Make sure HW does not configure LCD from PHY extended @@ -705,6 +987,8 @@ break; case e1000_phy_igp_3: case e1000_phy_bm: + case e1000_phy_82578: + case e1000_phy_82577: ret_val = e1000_get_phy_info_igp(hw); break; default: @@ -749,7 +1033,7 @@ ? false : true; if (phy->polarity_correction) { - ret_val = e1000_check_polarity_ife_ich8lan(hw); + ret_val = e1000_check_polarity_ife(hw); if (ret_val) goto out; } else { @@ -775,44 +1059,6 @@ } /* - * e1000_check_polarity_ife_ich8lan - Check cable polarity for IFE PHY - * @hw: pointer to the HW structure - * - * Polarity is determined on the polarity reversal feature being enabled. - * This function is only called by other family-specific - * routines. - */ -static s32 -e1000_check_polarity_ife_ich8lan(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; - u16 phy_data, offset, mask; - - DEBUGFUNC("e1000_check_polarity_ife_ich8lan"); - - /* - * Polarity is determined based on the reversal feature being enabled. - */ - if (phy->polarity_correction) { - offset = IFE_PHY_EXTENDED_STATUS_CONTROL; - mask = IFE_PESC_POLARITY_REVERSED; - } else { - offset = IFE_PHY_SPECIAL_CONTROL; - mask = IFE_PSC_FORCE_POLARITY; - } - - ret_val = phy->ops.read_reg(hw, offset, &phy_data); - - if (!ret_val) - phy->cable_polarity = (phy_data & mask) - ? e1000_rev_polarity_reversed - : e1000_rev_polarity_normal; - - return (ret_val); -} - -/* * e1000_set_d0_lplu_state_ich8lan - Set Low Power Linkup D0 state * @hw: pointer to the HW structure * @active: true to enable LPLU, false to disable @@ -844,12 +1090,14 @@ phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU; E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl); + if (phy->type != e1000_phy_igp_3) + goto out; + /* * Call gig speed drop workaround on LPLU before accessing any * PHY registers */ - if ((hw->mac.type == e1000_ich8lan) && - (hw->phy.type == e1000_phy_igp_3)) + if (hw->mac.type == e1000_ich8lan) e1000_gig_downshift_workaround_ich8lan(hw); /* When LPLU is enabled, we should disable SmartSpeed */ @@ -866,6 +1114,9 @@ phy_ctrl &= ~E1000_PHY_CTRL_D0A_LPLU; E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl); + if (phy->type != e1000_phy_igp_3) + goto out; + /* * LPLU and SmartSpeed are mutually exclusive. LPLU is used * during Dx states where the power conservation is most @@ -933,6 +1184,10 @@ if (!active) { phy_ctrl &= ~E1000_PHY_CTRL_NOND0A_LPLU; E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl); + + if (phy->type != e1000_phy_igp_3) + goto out; + /* * LPLU and SmartSpeed are mutually exclusive. LPLU is used * during Dx states where the power conservation is most @@ -972,12 +1227,14 @@ phy_ctrl |= E1000_PHY_CTRL_NOND0A_LPLU; E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl); + if (phy->type != e1000_phy_igp_3) + goto out; + /* * Call gig speed drop workaround on LPLU before accessing any * PHY registers */ - if ((hw->mac.type == e1000_ich8lan) && - (hw->phy.type == e1000_phy_igp_3)) + if (hw->mac.type == e1000_ich8lan) e1000_gig_downshift_workaround_ich8lan(hw); /* When LPLU is enabled, we should disable SmartSpeed */ @@ -1003,50 +1260,65 @@ * @bank: pointer to the variable that returns the active bank * * Reads signature byte from the NVM using the flash access registers. + * Word 0x13 bits 15:14 = 10b indicate a valid signature for that bank. */ static s32 e1000_valid_nvm_bank_detect_ich8lan(struct e1000_hw *hw, u32 *bank) { - s32 ret_val = E1000_SUCCESS; + u32 eecd; struct e1000_nvm_info *nvm = &hw->nvm; - /* flash bank size is in words */ u32 bank1_offset = nvm->flash_bank_size * sizeof (u16); u32 act_offset = E1000_ICH_NVM_SIG_WORD * 2 + 1; - u8 bank_high_byte = 0; - - if (hw->mac.type != e1000_ich10lan) { - if (E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_SEC1VAL) - *bank = 1; - else - *bank = 0; - } else { - /* - * Make sure the signature for bank 0 is valid, - * if not check for bank1 - */ - (void) e1000_read_flash_byte_ich8lan(hw, - act_offset, &bank_high_byte); - if ((bank_high_byte & 0xC0) == 0x80) { + u8 sig_byte = 0; + s32 ret_val = E1000_SUCCESS; + + switch (hw->mac.type) { + case e1000_ich8lan: + case e1000_ich9lan: + eecd = E1000_READ_REG(hw, E1000_EECD); + if ((eecd & E1000_EECD_SEC1VAL_VALID_MASK) == + E1000_EECD_SEC1VAL_VALID_MASK) { + if (eecd & E1000_EECD_SEC1VAL) + *bank = 1; + else + *bank = 0; + + goto out; + } + DEBUGOUT("Unable to determine valid NVM bank via EEC - " + "reading flash signature\n"); + /* fall-thru */ + default: + /* set bank to 0 in case flash read fails */ + *bank = 0; + + /* Check bank 0 */ + ret_val = e1000_read_flash_byte_ich8lan(hw, act_offset, + &sig_byte); + if (ret_val) + goto out; + if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) == + E1000_ICH_NVM_SIG_VALUE) { *bank = 0; - } else { - /* - * find if segment 1 is valid by verifying - * bit 15:14 = 10b in word 0x13 - */ - (void) e1000_read_flash_byte_ich8lan(hw, - act_offset + bank1_offset, - &bank_high_byte); - - /* bank1 has a valid signature equivalent to SEC1V */ - if ((bank_high_byte & 0xC0) == 0x80) { - *bank = 1; - } else { - DEBUGOUT("ERROR: EEPROM not present\n"); - ret_val = -E1000_ERR_NVM; - } + goto out; } + + /* Check bank 1 */ + ret_val = e1000_read_flash_byte_ich8lan(hw, act_offset + + bank1_offset, &sig_byte); + if (ret_val) + goto out; + if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) == + E1000_ICH_NVM_SIG_VALUE) { + *bank = 1; + goto out; + } + + DEBUGOUT("ERROR: No valid NVM bank present\n"); + ret_val = -E1000_ERR_NVM; + break; } - +out: return (ret_val); } @@ -1079,17 +1351,18 @@ goto out; } - ret_val = nvm->ops.acquire(hw); - if (ret_val) - goto out; + nvm->ops.acquire(hw); ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank); - if (ret_val != E1000_SUCCESS) - goto out; + if (ret_val != E1000_SUCCESS) { + DEBUGOUT("Could not detect valid bank, assuming bank 0\n"); + bank = 0; + } act_offset = (bank) ? nvm->flash_bank_size : 0; act_offset += offset; + ret_val = E1000_SUCCESS; for (i = 0; i < words; i++) { if ((dev_spec->shadow_ram) && (dev_spec->shadow_ram[offset + i].modified)) { @@ -1107,6 +1380,9 @@ nvm->ops.release(hw); out: + if (ret_val) + DEBUGOUT1("NVM read error: %d\n", ret_val); + return (ret_val); } @@ -1388,9 +1664,7 @@ goto out; } - ret_val = nvm->ops.acquire(hw); - if (ret_val) - goto out; + nvm->ops.acquire(hw); for (i = 0; i < words; i++) { dev_spec->shadow_ram[offset + i].modified = true; @@ -1432,9 +1706,7 @@ if (nvm->type != e1000_nvm_flash_sw) goto out; - ret_val = nvm->ops.acquire(hw); - if (ret_val) - goto out; + nvm->ops.acquire(hw); /* * We're writing to the opposite bank so if we're on bank 1, write to @@ -1442,17 +1714,27 @@ * written */ ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank); - if (ret_val != E1000_SUCCESS) - goto out; + if (ret_val != E1000_SUCCESS) { + DEBUGOUT("Could not detect valid bank, assuming bank 0\n"); + bank = 0; + } if (bank == 0) { new_bank_offset = nvm->flash_bank_size; old_bank_offset = 0; - (void) e1000_erase_flash_bank_ich8lan(hw, 1); + ret_val = e1000_erase_flash_bank_ich8lan(hw, 1); + if (ret_val) { + nvm->ops.release(hw); + goto out; + } } else { old_bank_offset = nvm->flash_bank_size; new_bank_offset = 0; - (void) e1000_erase_flash_bank_ich8lan(hw, 0); + ret_val = e1000_erase_flash_bank_ich8lan(hw, 0); + if (ret_val) { + nvm->ops.release(hw); + goto out; + } } for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) { @@ -1463,9 +1745,11 @@ if (dev_spec->shadow_ram[i].modified) { data = dev_spec->shadow_ram[i].value; } else { - (void) e1000_read_flash_word_ich8lan(hw, + ret_val = e1000_read_flash_word_ich8lan(hw, i + old_bank_offset, &data); + if (ret_val) + break; } /* @@ -1514,7 +1798,12 @@ * bits are 11 to start with and we need to change bit 14 to 0b */ act_offset = new_bank_offset + E1000_ICH_NVM_SIG_WORD; - (void) e1000_read_flash_word_ich8lan(hw, act_offset, &data); + ret_val = e1000_read_flash_word_ich8lan(hw, act_offset, &data); + if (ret_val) { + nvm->ops.release(hw); + goto out; + } + data &= 0xBFFF; ret_val = e1000_retry_write_flash_byte_ich8lan(hw, act_offset * 2 + 1, @@ -1553,6 +1842,9 @@ msec_delay(10); out: + if (ret_val) + DEBUGOUT1("NVM update error: %d\n", ret_val); + return (ret_val); } @@ -1782,20 +2074,15 @@ break; case 1: sector_size = ICH_FLASH_SEG_SIZE_4K; - iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_4K; + iteration = 1; break; case 2: - if (hw->mac.type == e1000_ich9lan) { sector_size = ICH_FLASH_SEG_SIZE_8K; - iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_8K; - } else { - ret_val = -E1000_ERR_NVM; - goto out; - } + iteration = 1; break; case 3: sector_size = ICH_FLASH_SEG_SIZE_64K; - iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_64K; + iteration = 1; break; default: ret_val = -E1000_ERR_NVM; @@ -1804,7 +2091,7 @@ /* Start with the base address, then add the sector offset. */ flash_linear_addr = hw->nvm.flash_base_addr; - flash_linear_addr += (bank) ? (sector_size * iteration) : 0; + flash_linear_addr += (bank) ? flash_bank_size : 0; for (j = 0; j < iteration; j++) { do { @@ -1888,6 +2175,82 @@ } /* + * e1000_id_led_init_pchlan - store LED configurations + * @hw: pointer to the HW structure + * + * PCH does not control LEDs via the LEDCTL register, rather it uses + * the PHY LED configuration register. + * + * PCH also does not have an "always on" or "always off" mode which + * complicates the ID feature. Instead of using the "on" mode to indicate + * in ledctl_mode2 the LEDs to use for ID (see e1000_id_led_init_generic()), + * use "link_up" mode. The LEDs will still ID on request if there is no + * link based on logic in e1000_led_[on|off]_pchlan(). + */ +static s32 +e1000_id_led_init_pchlan(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + s32 ret_val; + const u32 ledctl_on = E1000_LEDCTL_MODE_LINK_UP; + const u32 ledctl_off = E1000_LEDCTL_MODE_LINK_UP | E1000_PHY_LED0_IVRT; + u16 data, i, temp, shift; + + DEBUGFUNC("e1000_id_led_init_pchlan"); + + /* Get default ID LED modes */ + ret_val = hw->nvm.ops.valid_led_default(hw, &data); + if (ret_val) + goto out; + + mac->ledctl_default = E1000_READ_REG(hw, E1000_LEDCTL); + mac->ledctl_mode1 = mac->ledctl_default; + mac->ledctl_mode2 = mac->ledctl_default; + + for (i = 0; i < 4; i++) { + temp = (data >> (i << 2)) & E1000_LEDCTL_LED0_MODE_MASK; + shift = (i * 5); + switch (temp) { + case ID_LED_ON1_DEF2: + case ID_LED_ON1_ON2: + case ID_LED_ON1_OFF2: + mac->ledctl_mode1 &= ~(E1000_PHY_LED0_MASK << shift); + mac->ledctl_mode1 |= (ledctl_on << shift); + break; + case ID_LED_OFF1_DEF2: + case ID_LED_OFF1_ON2: + case ID_LED_OFF1_OFF2: + mac->ledctl_mode1 &= ~(E1000_PHY_LED0_MASK << shift); + mac->ledctl_mode1 |= (ledctl_off << shift); + break; + default: + /* Do nothing */ + break; + } + switch (temp) { + case ID_LED_DEF1_ON2: + case ID_LED_ON1_ON2: + case ID_LED_OFF1_ON2: + mac->ledctl_mode2 &= ~(E1000_PHY_LED0_MASK << shift); + mac->ledctl_mode2 |= (ledctl_on << shift); + break; + case ID_LED_DEF1_OFF2: + case ID_LED_ON1_OFF2: + case ID_LED_OFF1_OFF2: + mac->ledctl_mode2 &= ~(E1000_PHY_LED0_MASK << shift); + mac->ledctl_mode2 |= (ledctl_off << shift); + break; + default: + /* Do nothing */ + break; + } + } + +out: + return (ret_val); +} + +/* * e1000_get_bus_info_ich8lan - Get/Set the bus type and width * @hw: pointer to the HW structure * @@ -1963,6 +2326,13 @@ ctrl = E1000_READ_REG(hw, E1000_CTRL); if (!hw->phy.ops.check_reset_block(hw) && !hw->phy.reset_disable) { + /* Clear PHY Reset Asserted bit */ + if (hw->mac.type >= e1000_pchlan) { + u32 status = E1000_READ_REG(hw, E1000_STATUS); + E1000_WRITE_REG(hw, E1000_STATUS, status & + ~E1000_STATUS_PHYRA); + } + /* * PHY HW reset requires MAC CORE reset at the same time to * make sure the interface between MAC and the external PHY is @@ -1972,20 +2342,39 @@ } ret_val = e1000_acquire_swflag_ich8lan(hw); - DEBUGOUT("Issuing a global reset to ich8lan"); + + DEBUGOUT("Issuing a global reset to ich8lan\n"); E1000_WRITE_REG(hw, E1000_CTRL, (ctrl | E1000_CTRL_RST)); msec_delay(20); - ret_val = e1000_get_auto_rd_done_generic(hw); - if (ret_val) { - /* - * When auto config read does not complete, do not return with - * an error. This can happen in situations where there is no - * eeprom and prevents getting link. - */ - DEBUGOUT("Auto Read Done did not complete\n"); + if (!ret_val) + e1000_release_swflag_ich8lan(hw); + + if (ctrl & E1000_CTRL_PHY_RST) + ret_val = hw->phy.ops.get_cfg_done(hw); + + if (hw->mac.type >= e1000_ich10lan) { + e1000_lan_init_done_ich8lan(hw); + } else { + ret_val = e1000_get_auto_rd_done_generic(hw); + if (ret_val) { + /* + * When auto config read does not complete, do not + * return with an error. This can happen in situations + * where there is no eeprom and prevents getting link. + */ + DEBUGOUT("Auto Read Done did not complete\n"); + } } + /* + * For PCH, this write will make sure that any noise + * will be detected as a CRC error and be dropped rather than show up + * as a bad packet to the DMA engine. + */ + if (hw->mac.type == e1000_pchlan) + E1000_WRITE_REG(hw, E1000_CRC_OFFSET, 0x65656565); + E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff); (void) E1000_READ_REG(hw, E1000_ICR); @@ -1993,6 +2382,16 @@ kab |= E1000_KABGTXD_BGSQLBIAS; E1000_WRITE_REG(hw, E1000_KABGTXD, kab); + if (hw->mac.type == e1000_pchlan) + ret_val = e1000_hv_phy_workarounds_ich8lan(hw); + + if (ret_val) + goto out; + + if (hw->device_id == E1000_DEV_ID_ICH10_HANKSVILLE) + ret_val = e1000_hv_phy_tuning_workaround_ich8lan(hw); + +out: return (ret_val); } @@ -2001,12 +2400,12 @@ * @hw: pointer to the HW structure * * Prepares the hardware for transmit and receive by doing the following: - * - initialize hardware bits - * - initialize LED identification - * - setup receive address registers - * - setup flow control - * - setup transmit descriptors - * - clear statistics + * - initialize hardware bits + * - initialize LED identification + * - setup receive address registers + * - setup flow control + * - setup transmit descriptors + * - clear statistics */ static s32 e1000_init_hw_ich8lan(struct e1000_hw *hw) @@ -2021,11 +2420,10 @@ e1000_initialize_hw_bits_ich8lan(hw); /* Initialize identification LED */ - ret_val = e1000_id_led_init_generic(hw); - if (ret_val) { + ret_val = mac->ops.id_led_init(hw); + if (ret_val) + /* This is not fatal and we should not stop init due to this */ DEBUGOUT("Error initializing identification LED\n"); - /* This is not fatal and we should not stop init due to this */ - } /* Setup the receive address. */ e1000_init_rx_addrs_generic(hw, mac->rar_entry_count); @@ -2035,6 +2433,18 @@ for (i = 0; i < mac->mta_reg_count; i++) E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0); + /* + * The 82578 Rx buffer will stall if wakeup is enabled in host and + * the ME. Reading the BM_WUC register will clear the host wakeup bit. + * Reset the phy after disabling host wakeup to reset the Rx buffer. + */ + if (hw->phy.type == e1000_phy_82578) { + hw->phy.ops.read_reg(hw, BM_WUC, &i); + ret_val = e1000_phy_hw_reset_ich8lan(hw); + if (ret_val) + return (ret_val); + } + /* Setup link and flow control */ ret_val = mac->ops.setup_link(hw); @@ -2094,6 +2504,9 @@ /* Extended Device Control */ reg = E1000_READ_REG(hw, E1000_CTRL_EXT); reg |= (1 << 22); + /* Enable PHY low-power state when MAC is at D3 w/o WoL */ + if (hw->mac.type >= e1000_pchlan) + reg |= E1000_CTRL_EXT_PHYPDEN; E1000_WRITE_REG(hw, E1000_CTRL_EXT, reg); /* Transmit Descriptor Control 0 */ @@ -2171,6 +2584,14 @@ goto out; E1000_WRITE_REG(hw, E1000_FCTTV, hw->fc.pause_time); + if ((hw->phy.type == e1000_phy_82578) || + (hw->phy.type == e1000_phy_82577)) { + ret_val = hw->phy.ops.write_reg(hw, + PHY_REG(BM_PORT_CTRL_PAGE, 27), + hw->fc.pause_time); + if (ret_val) + goto out; + } ret_val = e1000_set_fc_watermarks_generic(hw); @@ -2205,31 +2626,38 @@ * increase the max iterations when polling the phy; this fixes * erroneous timeouts at 10Mbps. */ - ret_val = e1000_write_kmrn_reg_generic(hw, GG82563_REG(0x34, 4), - 0xFFFF); + ret_val = e1000_write_kmrn_reg_generic(hw, + E1000_KMRNCTRLSTA_TIMEOUTS, 0xFFFF); if (ret_val) goto out; - ret_val = e1000_read_kmrn_reg_generic(hw, GG82563_REG(0x34, 9), - ®_data); + ret_val = e1000_read_kmrn_reg_generic(hw, + E1000_KMRNCTRLSTA_INBAND_PARAM, ®_data); if (ret_val) goto out; reg_data |= 0x3F; - ret_val = e1000_write_kmrn_reg_generic(hw, GG82563_REG(0x34, 9), - reg_data); + ret_val = e1000_write_kmrn_reg_generic(hw, + E1000_KMRNCTRLSTA_INBAND_PARAM, reg_data); if (ret_val) goto out; - if (hw->phy.type == e1000_phy_igp_3) { + switch (hw->phy.type) { + case e1000_phy_igp_3: ret_val = e1000_copper_link_setup_igp(hw); if (ret_val) goto out; - } else if (hw->phy.type == e1000_phy_bm) { + break; + case e1000_phy_bm: + case e1000_phy_82578: ret_val = e1000_copper_link_setup_m88(hw); if (ret_val) goto out; - } - - if (hw->phy.type == e1000_phy_ife) { + break; + case e1000_phy_82577: + ret_val = e1000_copper_link_setup_82577(hw); + if (ret_val) + goto out; + break; + case e1000_phy_ife: ret_val = hw->phy.ops.read_reg(hw, IFE_PHY_MDIX_CONTROL, ®_data); if (ret_val) @@ -2253,6 +2681,9 @@ reg_data); if (ret_val) goto out; + break; + default: + break; } ret_val = e1000_setup_copper_link_generic(hw); @@ -2281,6 +2712,14 @@ if (ret_val) goto out; + if ((hw->mac.type == e1000_pchlan) && (*speed == SPEED_1000)) { + ret_val = e1000_write_kmrn_reg_generic(hw, + E1000_KMRNCTRLSTA_K1_CONFIG, + E1000_KMRNCTRLSTA_K1_DISABLE); + if (ret_val) + goto out; + } + if ((hw->mac.type == e1000_ich8lan) && (hw->phy.type == e1000_phy_igp_3) && (*speed == SPEED_1000)) { @@ -2298,12 +2737,12 @@ * Work-around for 82566 Kumeran PCS lock loss: * On link status change (i.e. PCI reset, speed change) and link is up and * speed is gigabit- - * 0) if workaround is optionally disabled do nothing - * 1) wait 1ms for Kumeran link to come up - * 2) check Kumeran Diagnostic register PCS lock loss bit - * 3) if not set the link is locked (all is good), otherwise... - * 4) reset the PHY - * 5) repeat up to 10 times + * 0) if workaround is optionally disabled do nothing + * 1) wait 1ms for Kumeran link to come up + * 2) check Kumeran Diagnostic register PCS lock loss bit + * 3) if not set the link is locked (all is good), otherwise... + * 4) reset the PHY + * 5) repeat up to 10 times * Note: this is only called for IGP3 copper when speed is 1gb. */ static s32 @@ -2398,9 +2837,9 @@ * @hw: pointer to the HW structure * * Workaround for 82566 power-down on D3 entry: - * 1) disable gigabit link - * 2) write VR power-down enable - * 3) read it back + * 1) disable gigabit link + * 2) write VR power-down enable + * 3) read it back * Continue if successful, else issue LCD reset and repeat */ void @@ -2455,8 +2894,8 @@ * * Steps to take when dropping from 1Gb/s (eg. link cable removal (LSC), * LPLU, Gig disable, MDIC PHY reset): - * 1) Set Kumeran Near-end loopback - * 2) Clear Kumeran Near-end loopback + * 1) Set Kumeran Near-end loopback + * 2) Clear Kumeran Near-end loopback * Should only be called for ICH8[m] devices with IGP_3 Phy. */ void @@ -2496,19 +2935,27 @@ * 'LPLU Enabled' and 'Gig Disable' to force link speed negotiation * to a lower speed. * - * Should only be called for ICH9 and ICH10 devices. + * Should only be called for applicable parts. */ void e1000_disable_gig_wol_ich8lan(struct e1000_hw *hw) { u32 phy_ctrl; - if ((hw->mac.type == e1000_ich10lan) || - (hw->mac.type == e1000_ich9lan)) { + switch (hw->mac.type) { + case e1000_ich9lan: + case e1000_ich10lan: + case e1000_pchlan: phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL); phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU | E1000_PHY_CTRL_GBE_DISABLE; E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl); + + /* Workaround SWFLAG unexpectedly set during S0->Sx */ + if (hw->mac.type == e1000_pchlan) + usec_delay(500); + default: + break; } } @@ -2581,6 +3028,104 @@ } /* + * e1000_setup_led_pchlan - Configures SW controllable LED + * @hw: pointer to the HW structure + * + * This prepares the SW controllable LED for use. + */ +static s32 +e1000_setup_led_pchlan(struct e1000_hw *hw) +{ + DEBUGFUNC("e1000_setup_led_pchlan"); + + return (hw->phy.ops.write_reg(hw, HV_LED_CONFIG, + (u16)hw->mac.ledctl_mode1)); +} + +/* + * e1000_cleanup_led_pchlan - Restore the default LED operation + * @hw: pointer to the HW structure + * + * Return the LED back to the default configuration. + */ +static s32 +e1000_cleanup_led_pchlan(struct e1000_hw *hw) +{ + DEBUGFUNC("e1000_cleanup_led_pchlan"); + + return (hw->phy.ops.write_reg(hw, HV_LED_CONFIG, + (u16)hw->mac.ledctl_default)); +} + +/* + * e1000_led_on_pchlan - Turn LEDs on + * @hw: pointer to the HW structure + * + * Turn on the LEDs. + */ +static s32 +e1000_led_on_pchlan(struct e1000_hw *hw) +{ + u16 data = (u16)hw->mac.ledctl_mode2; + u32 i, led; + + DEBUGFUNC("e1000_led_on_pchlan"); + + /* + * If no link, then turn LED on by setting the invert bit + * for each LED that's mode is "link_up" in ledctl_mode2. + */ + if (!(E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU)) { + for (i = 0; i < 3; i++) { + led = (data >> (i * 5)) & E1000_PHY_LED0_MASK; + if ((led & E1000_PHY_LED0_MODE_MASK) != + E1000_LEDCTL_MODE_LINK_UP) + continue; + if (led & E1000_PHY_LED0_IVRT) + data &= ~(E1000_PHY_LED0_IVRT << (i * 5)); + else + data |= (E1000_PHY_LED0_IVRT << (i * 5)); + } + } + + return (hw->phy.ops.write_reg(hw, HV_LED_CONFIG, data)); +} + +/* + * e1000_led_off_pchlan - Turn LEDs off + * @hw: pointer to the HW structure + * + * Turn off the LEDs. + */ +static s32 +e1000_led_off_pchlan(struct e1000_hw *hw) +{ + u16 data = (u16)hw->mac.ledctl_mode1; + u32 i, led; + + DEBUGFUNC("e1000_led_off_pchlan"); + + /* + * If no link, then turn LED off by clearing the invert bit + * for each LED that's mode is "link_up" in ledctl_mode1. + */ + if (!(E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU)) { + for (i = 0; i < 3; i++) { + led = (data >> (i * 5)) & E1000_PHY_LED0_MASK; + if ((led & E1000_PHY_LED0_MODE_MASK) != + E1000_LEDCTL_MODE_LINK_UP) + continue; + if (led & E1000_PHY_LED0_IVRT) + data &= ~(E1000_PHY_LED0_IVRT << (i * 5)); + else + data |= (E1000_PHY_LED0_IVRT << (i * 5)); + } + } + + return (hw->phy.ops.write_reg(hw, HV_LED_CONFIG, data)); +} + +/* * e1000_get_cfg_done_ich8lan - Read config done bit * @hw: pointer to the HW structure * @@ -2596,10 +3141,21 @@ s32 ret_val = E1000_SUCCESS; u32 bank = 0; + if (hw->mac.type >= e1000_pchlan) { + u32 status = E1000_READ_REG(hw, E1000_STATUS); + + if (status & E1000_STATUS_PHYRA) { + E1000_WRITE_REG(hw, E1000_STATUS, status & + ~E1000_STATUS_PHYRA); + } else + DEBUGOUT("PHY Reset Asserted not set - needs delay\n"); + } + (void) e1000_get_cfg_done_generic(hw); /* If EEPROM is not marked present, init the IGP 3 PHY manually */ - if (hw->mac.type != e1000_ich10lan) { + if ((hw->mac.type != e1000_ich10lan) && + (hw->mac.type != e1000_pchlan)) { if (((E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_PRES) == 0) && (hw->phy.type == e1000_phy_igp_3)) { (void) e1000_phy_init_script_igp3(hw); @@ -2641,6 +3197,8 @@ static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw) { + u16 phy_data; + DEBUGFUNC("e1000_clear_hw_cntrs_ich8lan"); e1000_clear_hw_cntrs_base_generic(hw); @@ -2658,4 +3216,23 @@ (void) E1000_READ_REG(hw, E1000_IAC); (void) E1000_READ_REG(hw, E1000_ICRXOC); + + /* Clear PHY statistics registers */ + if ((hw->phy.type == e1000_phy_82578) || + (hw->phy.type == e1000_phy_82577)) { + (void) hw->phy.ops.read_reg(hw, HV_SCC_UPPER, &phy_data); + (void) hw->phy.ops.read_reg(hw, HV_SCC_LOWER, &phy_data); + (void) hw->phy.ops.read_reg(hw, HV_ECOL_UPPER, &phy_data); + (void) hw->phy.ops.read_reg(hw, HV_ECOL_LOWER, &phy_data); + (void) hw->phy.ops.read_reg(hw, HV_MCC_UPPER, &phy_data); + (void) hw->phy.ops.read_reg(hw, HV_MCC_LOWER, &phy_data); + (void) hw->phy.ops.read_reg(hw, HV_LATECOL_UPPER, &phy_data); + (void) hw->phy.ops.read_reg(hw, HV_LATECOL_LOWER, &phy_data); + (void) hw->phy.ops.read_reg(hw, HV_COLC_UPPER, &phy_data); + (void) hw->phy.ops.read_reg(hw, HV_COLC_LOWER, &phy_data); + (void) hw->phy.ops.read_reg(hw, HV_DC_UPPER, &phy_data); + (void) hw->phy.ops.read_reg(hw, HV_DC_LOWER, &phy_data); + (void) hw->phy.ops.read_reg(hw, HV_TNCRS_UPPER, &phy_data); + (void) hw->phy.ops.read_reg(hw, HV_TNCRS_LOWER, &phy_data); + } }
--- a/usr/src/uts/common/io/e1000g/e1000_ich8lan.h Tue Sep 29 11:19:43 2009 +0800 +++ b/usr/src/uts/common/io/e1000g/e1000_ich8lan.h Tue Sep 29 12:12:23 2009 +0800 @@ -24,7 +24,7 @@ */ /* - * IntelVersion: 1.25 sol_anvik_patch + * IntelVersion: 1.37 v3-1-3_2009-8-20 */ #ifndef _E1000_ICH8LAN_H_ #define _E1000_ICH8LAN_H_ @@ -39,9 +39,10 @@ #define ICH_FLASH_FADDR 0x0008 #define ICH_FLASH_FDATA0 0x0010 -#define ICH_FLASH_READ_COMMAND_TIMEOUT 500 -#define ICH_FLASH_WRITE_COMMAND_TIMEOUT 500 -#define ICH_FLASH_ERASE_COMMAND_TIMEOUT 3000000 +/* Requires up to 10 seconds when MNG might be accessing part. */ +#define ICH_FLASH_READ_COMMAND_TIMEOUT 10000000 +#define ICH_FLASH_WRITE_COMMAND_TIMEOUT 10000000 +#define ICH_FLASH_ERASE_COMMAND_TIMEOUT 10000000 #define ICH_FLASH_LINEAR_ADDR_MASK 0x00FFFFFF #define ICH_FLASH_CYCLE_REPEAT_COUNT 10 @@ -68,12 +69,14 @@ #define E1000_ICH_MNG_IAMT_MODE 0x2 #define ID_LED_DEFAULT_ICH8LAN ((ID_LED_DEF1_DEF2 << 12) | \ - (ID_LED_DEF1_OFF2 << 8) | \ - (ID_LED_DEF1_ON2 << 4) | \ + (ID_LED_OFF1_OFF2 << 8) | \ + (ID_LED_OFF1_ON2 << 4) | \ (ID_LED_DEF1_DEF2)) #define E1000_ICH_NVM_SIG_WORD 0x13 #define E1000_ICH_NVM_SIG_MASK 0xC000 +#define E1000_ICH_NVM_VALID_SIG_MASK 0xC0 +#define E1000_ICH_NVM_SIG_VALUE 0x80 #define E1000_ICH8_LAN_INIT_TIMEOUT 1500 @@ -97,6 +100,49 @@ #define IGP3_VR_CTRL_MODE_SHUTDOWN 0x0200 #define IGP3_PM_CTRL_FORCE_PWR_DOWN 0x0020 +/* PHY Wakeup Registers and defines */ +#define BM_RCTL PHY_REG(BM_WUC_PAGE, 0) +#define BM_WUC PHY_REG(BM_WUC_PAGE, 1) +#define BM_WUFC PHY_REG(BM_WUC_PAGE, 2) +#define BM_WUS PHY_REG(BM_WUC_PAGE, 3) +#define BM_RAR_L(_i) (BM_PHY_REG(BM_WUC_PAGE, 16 + ((_i) << 2))) +#define BM_RAR_M(_i) (BM_PHY_REG(BM_WUC_PAGE, 17 + ((_i) << 2))) +#define BM_RAR_H(_i) (BM_PHY_REG(BM_WUC_PAGE, 18 + ((_i) << 2))) +#define BM_RAR_CTRL(_i) (BM_PHY_REG(BM_WUC_PAGE, 19 + ((_i) << 2))) +#define BM_MTA(_i) (BM_PHY_REG(BM_WUC_PAGE, 128 + ((_i) << 1))) + +#define BM_RCTL_UPE 0x0001 /* Unicast Promiscuous Mode */ +#define BM_RCTL_MPE 0x0002 /* Multicast Promiscuous Mode */ +#define BM_RCTL_MO_SHIFT 3 /* Multicast Offset Shift */ +#define BM_RCTL_MO_MASK (3 << 3) /* Multicast Offset Mask */ +#define BM_RCTL_BAM 0x0020 /* Broadcast Accept Mode */ +#define BM_RCTL_PMCF 0x0040 /* Pass MAC Control Frames */ +#define BM_RCTL_RFCE 0x0080 /* Rx Flow Control Enable */ + +#define HV_LED_CONFIG PHY_REG(768, 30) /* LED Configuration */ +#define HV_MUX_DATA_CTRL PHY_REG(776, 16) +#define HV_MUX_DATA_CTRL_GEN_TO_MAC 0x0400 +#define HV_MUX_DATA_CTRL_FORCE_SPEED 0x0004 +#define HV_SCC_UPPER PHY_REG(778, 16) /* Single Collision Count */ +#define HV_SCC_LOWER PHY_REG(778, 17) +#define HV_ECOL_UPPER PHY_REG(778, 18) /* Excessive Collision Count */ +#define HV_ECOL_LOWER PHY_REG(778, 19) +#define HV_MCC_UPPER PHY_REG(778, 20) /* Multiple Collision Count */ +#define HV_MCC_LOWER PHY_REG(778, 21) +#define HV_LATECOL_UPPER PHY_REG(778, 23) /* Late Collision Count */ +#define HV_LATECOL_LOWER PHY_REG(778, 24) +#define HV_COLC_UPPER PHY_REG(778, 25) /* Collision Count */ +#define HV_COLC_LOWER PHY_REG(778, 26) +#define HV_DC_UPPER PHY_REG(778, 27) /* Defer Count */ +#define HV_DC_LOWER PHY_REG(778, 28) +#define HV_TNCRS_UPPER PHY_REG(778, 29) /* Transmit with no CRS */ +#define HV_TNCRS_LOWER PHY_REG(778, 30) + +/* PCH Flow Control Refresh Timer Value */ +#define E1000_FCRTV_PCH 0x05F40 +/* SW Semaphore flag timeout in milliseconds */ +#define SW_FLAG_TIMEOUT 400 + /* * Additional interrupts need to be handled for ICH family: * DSW = The FW changed the status of the DISSW bit in FWSM
--- a/usr/src/uts/common/io/e1000g/e1000_mac.c Tue Sep 29 11:19:43 2009 +0800 +++ b/usr/src/uts/common/io/e1000g/e1000_mac.c Tue Sep 29 12:12:23 2009 +0800 @@ -24,11 +24,12 @@ */ /* - * IntelVersion: 1.92.4.1 sol_anvik_patch + * IntelVersion: 1.108 v3-1-3_2009-8-20 */ #include "e1000_api.h" static s32 e1000_validate_mdi_setting_generic(struct e1000_hw *hw); +static void e1000_set_lan_id_multi_port_pcie(struct e1000_hw *hw); /* * e1000_init_mac_ops_generic - Initialize MAC function pointers @@ -48,6 +49,7 @@ mac->ops.reset_hw = e1000_null_ops_generic; mac->ops.setup_physical_interface = e1000_null_ops_generic; mac->ops.get_bus_info = e1000_null_ops_generic; + mac->ops.set_lan_id = e1000_set_lan_id_multi_port_pcie; mac->ops.read_mac_addr = e1000_read_mac_addr_generic; mac->ops.config_collision_dist = e1000_config_collision_dist_generic; mac->ops.clear_hw_cntrs = e1000_null_mac_generic; @@ -128,10 +130,10 @@ * @hw: pointer to the HW structure */ void -e1000_null_update_mc(struct e1000_hw *hw, u8 *h, u32 a, u32 b, u32 c) +e1000_null_update_mc(struct e1000_hw *hw, u8 *h, u32 a) { DEBUGFUNC("e1000_null_update_mc"); - UNREFERENCED_5PARAMETER(hw, h, a, b, c); + UNREFERENCED_3PARAMETER(hw, h, a); } /* @@ -178,10 +180,10 @@ s32 e1000_get_bus_info_pci_generic(struct e1000_hw *hw) { + struct e1000_mac_info *mac = &hw->mac; struct e1000_bus_info *bus = &hw->bus; u32 status = E1000_READ_REG(hw, E1000_STATUS); s32 ret_val = E1000_SUCCESS; - u16 pci_header_type; DEBUGFUNC("e1000_get_bus_info_pci_generic"); @@ -218,12 +220,7 @@ : e1000_bus_width_32; /* Which PCI(-X) function? */ - e1000_read_pci_cfg(hw, PCI_HEADER_TYPE_REGISTER, &pci_header_type); - if (pci_header_type & PCI_HEADER_TYPE_MULTIFUNC) - bus->func = (status & E1000_STATUS_FUNC_MASK) - >> E1000_STATUS_FUNC_SHIFT; - else - bus->func = 0; + mac->ops.set_lan_id(hw); return (ret_val); } @@ -239,10 +236,10 @@ s32 e1000_get_bus_info_pcie_generic(struct e1000_hw *hw) { + struct e1000_mac_info *mac = &hw->mac; struct e1000_bus_info *bus = &hw->bus; s32 ret_val; - u32 status; - u16 pcie_link_status, pci_header_type; + u16 pcie_link_status; DEBUGFUNC("e1000_get_bus_info_pcie_generic"); @@ -259,6 +256,46 @@ PCIE_LINK_WIDTH_MASK) >> PCIE_LINK_WIDTH_SHIFT); + mac->ops.set_lan_id(hw); + + return (E1000_SUCCESS); +} + +/* + * e1000_set_lan_id_multi_port_pcie - Set LAN id for PCIe multiple port devices + * + * @hw: pointer to the HW structure + * + * Determines the LAN function id by reading memory-mapped registers + * and swaps the port value if requested. + */ +static void +e1000_set_lan_id_multi_port_pcie(struct e1000_hw *hw) +{ + struct e1000_bus_info *bus = &hw->bus; + u32 reg; + + /* + * The status register reports the correct function number + * for the device regardless of function swap state. + */ + reg = E1000_READ_REG(hw, E1000_STATUS); + bus->func = (reg & E1000_STATUS_FUNC_MASK) >> E1000_STATUS_FUNC_SHIFT; +} + +/* + * e1000_set_lan_id_multi_port_pci - Set LAN id for PCI multiple port devices + * @hw: pointer to the HW structure + * + * Determines the LAN function id by reading PCI config space. + */ +void +e1000_set_lan_id_multi_port_pci(struct e1000_hw *hw) +{ + struct e1000_bus_info *bus = &hw->bus; + u16 pci_header_type; + u32 status; + e1000_read_pci_cfg(hw, PCI_HEADER_TYPE_REGISTER, &pci_header_type); if (pci_header_type & PCI_HEADER_TYPE_MULTIFUNC) { status = E1000_READ_REG(hw, E1000_STATUS); @@ -267,8 +304,20 @@ } else { bus->func = 0; } +} - return (E1000_SUCCESS); +/* + * e1000_set_lan_id_single_port - Set LAN id for a single port device + * @hw: pointer to the HW structure + * + * Sets the LAN function id to zero for a single port device. + */ +void +e1000_set_lan_id_single_port(struct e1000_hw *hw) +{ + struct e1000_bus_info *bus = &hw->bus; + + bus->func = 0; } /* @@ -322,6 +371,7 @@ e1000_init_rx_addrs_generic(struct e1000_hw *hw, u16 rar_count) { u32 i; + u8 mac_addr[ETH_ADDR_LEN] = {0}; DEBUGFUNC("e1000_init_rx_addrs_generic"); @@ -332,12 +382,9 @@ /* Zero out the other (rar_entry_count - 1) receive addresses */ DEBUGOUT1("Clearing RAR[1-%u]\n", rar_count - 1); - for (i = 1; i < rar_count; i++) { - E1000_WRITE_REG_ARRAY(hw, E1000_RA, (i << 1), 0); - E1000_WRITE_FLUSH(hw); - E1000_WRITE_REG_ARRAY(hw, E1000_RA, ((i << 1) + 1), 0); - E1000_WRITE_FLUSH(hw); - } + for (i = 1; i < rar_count; i++) + hw->mac.ops.rar_set(hw, mac_addr, i); + } /* @@ -347,9 +394,10 @@ * Checks the nvm for an alternate MAC address. An alternate MAC address * can be setup by pre-boot software and must be treated like a permanent * address and must override the actual permanent MAC address. If an - * alternate MAC address is found it is saved in the hw struct and - * programmed into RAR0 and the function returns success, otherwise the - * function returns an error. + * alternate MAC address is found it is programmed into RAR0, replacing + * the permanent address that was installed into RAR0 by the Si on reset. + * This function will return SUCCESS unless it encounters an error while + * reading the EEPROM. */ s32 e1000_check_alt_mac_addr_generic(struct e1000_hw *hw) @@ -369,12 +417,12 @@ } if (nvm_alt_mac_addr_offset == 0xFFFF) { - ret_val = -(E1000_NOT_IMPLEMENTED); + /* There is no Alternate MAC Address */ goto out; } if (hw->bus.func == E1000_FUNC_1) - nvm_alt_mac_addr_offset += ETH_ADDR_LEN / sizeof (u16); + nvm_alt_mac_addr_offset += E1000_ALT_MAC_ADDRESS_OFFSET_LAN1; for (i = 0; i < ETH_ADDR_LEN; i += 2) { offset = nvm_alt_mac_addr_offset + (i >> 1); @@ -390,14 +438,16 @@ /* if multicast bit is set, the alternate address will not be used */ if (alt_mac_addr[0] & 0x01) { - ret_val = -(E1000_NOT_IMPLEMENTED); + DEBUGOUT("Ignoring Alternate Mac Address with MC bit set\n"); goto out; } - for (i = 0; i < ETH_ADDR_LEN; i++) - hw->mac.addr[i] = hw->mac.perm_addr[i] = alt_mac_addr[i]; - - hw->mac.ops.rar_set(hw, hw->mac.perm_addr, 0); + /* + * We have a valid alternate MAC address, and we want to treat it the + * same as the normal permanent MAC address stored by the HW into the + * RAR. Do this by mapping this address into RAR0. + */ + hw->mac.ops.rar_set(hw, alt_mac_addr, 0); out: return (ret_val); @@ -435,12 +485,13 @@ /* * Some bridges will combine consecutive 32-bit writes into - * a single burst write, which will malfunction on some - * 82546 parts. The flush avoids this. + * a single burst write, which will malfunction on some parts. + * The flushes avoid this. */ E1000_WRITE_REG(hw, E1000_RAL(index), rar_low); E1000_WRITE_FLUSH(hw); E1000_WRITE_REG(hw, E1000_RAH(index), rar_high); + E1000_WRITE_FLUSH(hw); } /* @@ -485,56 +536,37 @@ * @hw: pointer to the HW structure * @mc_addr_list: array of multicast addresses to program * @mc_addr_count: number of multicast addresses to program - * @rar_used_count: the first RAR register free to program - * @rar_count: total number of supported Receive Address Registers * - * Updates the Receive Address Registers and Multicast Table Array. + * Updates entire Multicast Table Array. * The caller must have a packed mc_addr_list of multicast addresses. - * The parameter rar_count will usually be hw->mac.rar_entry_count - * unless there are workarounds that change this. */ void e1000_update_mc_addr_list_generic(struct e1000_hw *hw, - u8 *mc_addr_list, u32 mc_addr_count, - u32 rar_used_count, u32 rar_count) + u8 *mc_addr_list, u32 mc_addr_count) { - u32 hash_value; - u32 i; + u32 hash_value, hash_bit, hash_reg; + int i; DEBUGFUNC("e1000_update_mc_addr_list_generic"); - /* - * Load the first set of multicast addresses into the exact filters - * (RAR). If there are not enough to fill the RAR array, clear the - * filters. - */ - for (i = rar_used_count; i < rar_count; i++) { - if (mc_addr_count) { - hw->mac.ops.rar_set(hw, mc_addr_list, i); - mc_addr_count--; - mc_addr_list += ETH_ADDR_LEN; - } else { - E1000_WRITE_REG_ARRAY(hw, E1000_RA, i << 1, 0); - E1000_WRITE_FLUSH(hw); - E1000_WRITE_REG_ARRAY(hw, E1000_RA, (i << 1) + 1, 0); - E1000_WRITE_FLUSH(hw); - } + /* clear mta_shadow */ + memset(&hw->mac.mta_shadow, 0, sizeof (hw->mac.mta_shadow)); + + /* update mta_shadow from mc_addr_list */ + for (i = 0; (u32) i < mc_addr_count; i++) { + hash_value = e1000_hash_mc_addr_generic(hw, mc_addr_list); + + hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1); + hash_bit = hash_value & 0x1F; + + hw->mac.mta_shadow[hash_reg] |= (1 << hash_bit); + mc_addr_list += (ETH_ADDR_LEN); } - /* Clear the old settings from the MTA */ - DEBUGOUT("Clearing MTA\n"); - for (i = 0; i < hw->mac.mta_reg_count; i++) { - E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0); - E1000_WRITE_FLUSH(hw); - } - - /* Load any remaining multicast addresses into the hash table. */ - for (; mc_addr_count > 0; mc_addr_count--) { - hash_value = e1000_hash_mc_addr_generic(hw, mc_addr_list); - DEBUGOUT1("Hash value = 0x%03X\n", hash_value); - hw->mac.ops.mta_set(hw, hash_value); - mc_addr_list += ETH_ADDR_LEN; - } + /* replace the entire MTA table */ + for (i = hw->mac.mta_reg_count - 1; i >= 0; i--) + E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, hw->mac.mta_shadow[i]); + E1000_WRITE_FLUSH(hw); } /*
--- a/usr/src/uts/common/io/e1000g/e1000_mac.h Tue Sep 29 11:19:43 2009 +0800 +++ b/usr/src/uts/common/io/e1000g/e1000_mac.h Tue Sep 29 12:12:23 2009 +0800 @@ -24,7 +24,7 @@ */ /* - * IntelVersion: 1.29 sol_anvik_patch + * IntelVersion: 1.32 v3-1-3_2009-8-20 */ #ifndef _E1000_MAC_H_ #define _E1000_MAC_H_ @@ -42,7 +42,7 @@ s32 e1000_null_ops_generic(struct e1000_hw *hw); s32 e1000_null_link_info(struct e1000_hw *hw, u16 *s, u16 *d); bool e1000_null_mng_mode(struct e1000_hw *hw); -void e1000_null_update_mc(struct e1000_hw *hw, u8 *h, u32 a, u32 b, u32 c); +void e1000_null_update_mc(struct e1000_hw *hw, u8 *h, u32 a); void e1000_null_write_vfta(struct e1000_hw *hw, u32 a, u32 b); void e1000_null_mta_set(struct e1000_hw *hw, u32 a); void e1000_null_rar_set(struct e1000_hw *hw, u8 *h, u32 a); @@ -59,6 +59,8 @@ s32 e1000_get_auto_rd_done_generic(struct e1000_hw *hw); s32 e1000_get_bus_info_pci_generic(struct e1000_hw *hw); s32 e1000_get_bus_info_pcie_generic(struct e1000_hw *hw); +void e1000_set_lan_id_single_port(struct e1000_hw *hw); +void e1000_set_lan_id_multi_port_pci(struct e1000_hw *hw); s32 e1000_get_hw_semaphore_generic(struct e1000_hw *hw); s32 e1000_get_speed_and_duplex_copper_generic(struct e1000_hw *hw, u16 *speed, u16 *duplex); @@ -68,8 +70,7 @@ s32 e1000_led_on_generic(struct e1000_hw *hw); s32 e1000_led_off_generic(struct e1000_hw *hw); void e1000_update_mc_addr_list_generic(struct e1000_hw *hw, - u8 *mc_addr_list, u32 mc_addr_count, - u32 rar_used_count, u32 rar_count); + u8 *mc_addr_list, u32 mc_addr_count); s32 e1000_set_default_fc_generic(struct e1000_hw *hw); s32 e1000_set_fc_watermarks_generic(struct e1000_hw *hw); s32 e1000_setup_fiber_serdes_link_generic(struct e1000_hw *hw);
--- a/usr/src/uts/common/io/e1000g/e1000_manage.c Tue Sep 29 11:19:43 2009 +0800 +++ b/usr/src/uts/common/io/e1000g/e1000_manage.c Tue Sep 29 12:12:23 2009 +0800 @@ -24,7 +24,7 @@ */ /* - * IntelVersion: 1.27 sol_anvik_patch + * IntelVersion: 1.27 v3-1-3_2009-8-20 */ #include "e1000_api.h"
--- a/usr/src/uts/common/io/e1000g/e1000_manage.h Tue Sep 29 11:19:43 2009 +0800 +++ b/usr/src/uts/common/io/e1000g/e1000_manage.h Tue Sep 29 12:12:23 2009 +0800 @@ -24,7 +24,7 @@ */ /* - * IntelVersion: 1.18 sol_anvik_patch + * IntelVersion: 1.18 v3-1-3_2009-8-20 */ #ifndef _E1000_MANAGE_H_ #define _E1000_MANAGE_H_
--- a/usr/src/uts/common/io/e1000g/e1000_nvm.c Tue Sep 29 11:19:43 2009 +0800 +++ b/usr/src/uts/common/io/e1000g/e1000_nvm.c Tue Sep 29 12:12:23 2009 +0800 @@ -24,7 +24,7 @@ */ /* - * IntelVersion: 1.46 sol_anvik_patch + * IntelVersion: 1.49 v3-1-3_2009-8-20 */ #include "e1000_api.h" @@ -831,31 +831,23 @@ s32 e1000_read_mac_addr_generic(struct e1000_hw *hw) { - s32 ret_val = E1000_SUCCESS; - u16 offset, nvm_data, i; - - DEBUGFUNC("e1000_read_mac_addr"); + u32 rar_high; + u32 rar_low; + u16 i; - for (i = 0; i < ETH_ADDR_LEN; i += 2) { - offset = i >> 1; - ret_val = hw->nvm.ops.read(hw, offset, 1, &nvm_data); - if (ret_val) { - DEBUGOUT("NVM Read Error\n"); - goto out; - } - hw->mac.perm_addr[i] = (u8)(nvm_data & 0xFF); - hw->mac.perm_addr[i + 1] = (u8)(nvm_data >> 8); - } + rar_high = E1000_READ_REG(hw, E1000_RAH(0)); + rar_low = E1000_READ_REG(hw, E1000_RAL(0)); - /* Flip last bit of mac address if we're on second port */ - if (hw->bus.func == E1000_FUNC_1) - hw->mac.perm_addr[5] ^= 1; + for (i = 0; i < E1000_RAL_MAC_ADDR_LEN; i++) + hw->mac.perm_addr[i] = (u8)(rar_low >> (i*8)); + + for (i = 0; i < E1000_RAH_MAC_ADDR_LEN; i++) + hw->mac.perm_addr[i+4] = (u8)(rar_high >> (i*8)); for (i = 0; i < ETH_ADDR_LEN; i++) hw->mac.addr[i] = hw->mac.perm_addr[i]; -out: - return (ret_val); + return (E1000_SUCCESS); } /*
--- a/usr/src/uts/common/io/e1000g/e1000_nvm.h Tue Sep 29 11:19:43 2009 +0800 +++ b/usr/src/uts/common/io/e1000g/e1000_nvm.h Tue Sep 29 12:12:23 2009 +0800 @@ -24,7 +24,7 @@ */ /* - * IntelVersion: 1.18 sol_anvik_patch + * IntelVersion: 1.18 v3-1-3_2009-8-20 */ #ifndef _E1000_NVM_H_ #define _E1000_NVM_H_
--- a/usr/src/uts/common/io/e1000g/e1000_osdep.c Tue Sep 29 11:19:43 2009 +0800 +++ b/usr/src/uts/common/io/e1000g/e1000_osdep.c Tue Sep 29 12:12:23 2009 +0800 @@ -58,7 +58,7 @@ /* * phy_spd_state - set smart-power-down (SPD) state * - * This only acts on the 82541/47 family and the 82571/72 family. + * This only acts on the silicon families that have the SPD feature. * For any others, return without doing anything. */ void @@ -78,6 +78,9 @@ break; case e1000_82571: case e1000_82572: + case e1000_82573: + case e1000_82574: + case e1000_82583: offset = IGP02E1000_PHY_POWER_MGMT; spd_bit = IGP02E1000_PM_SPD; break; @@ -112,21 +115,27 @@ } /* - * Enables PCI-Express master access. - * - * hw: Struct containing variables accessed by shared code - * - * returns: - none. + * For some hardware types, access to NVM & PHY need to be serialized by mutex. + * The necessary mutexes will have been created by shared code. Here we destroy + * that mutexes for just the hardware types that need it. */ void -e1000_enable_pciex_master(struct e1000_hw *hw) +e1000_destroy_hw_mutex(struct e1000_hw *hw) { - uint32_t ctrl; + struct e1000_dev_spec_ich8lan *dev_spec; - if (hw->bus.type != e1000_bus_type_pci_express) - return; + switch (hw->mac.type) { + case e1000_ich8lan: + case e1000_ich9lan: + case e1000_ich10lan: + case e1000_pchlan: + cmn_err(CE_WARN, "destroy mutexes in e1000_destroy_hw_mutex\n"); + dev_spec = &hw->dev_spec.ich8lan; + E1000_MUTEX_DESTROY(&dev_spec->nvm_mutex); + E1000_MUTEX_DESTROY(&dev_spec->swflag_mutex); + break; - ctrl = E1000_READ_REG(hw, E1000_CTRL); - ctrl &= ~E1000_CTRL_GIO_MASTER_DISABLE; - E1000_WRITE_REG(hw, E1000_CTRL, ctrl); + default: + break; /* no action */ + } }
--- a/usr/src/uts/common/io/e1000g/e1000_osdep.h Tue Sep 29 11:19:43 2009 +0800 +++ b/usr/src/uts/common/io/e1000g/e1000_osdep.h Tue Sep 29 12:12:23 2009 +0800 @@ -46,6 +46,7 @@ #include <sys/pci.h> #include <sys/atomic.h> #include <sys/note.h> +#include <sys/mutex.h> #include "e1000g_debug.h" #define usec_delay(x) drv_usecwait(x) @@ -75,6 +76,7 @@ #define false 0 #define true 1 + #define CMD_MEM_WRT_INVALIDATE 0x0010 /* BIT_4 */ #define PCI_COMMAND_REGISTER 0x04 #define PCI_EX_CONF_CAP 0xE0 @@ -193,6 +195,16 @@ struct e1000g *adapter; }; +/* Shared Code Mutex Defines */ +#define E1000_MUTEX kmutex_t +#define E1000_MUTEX_INIT(mutex) mutex_init(mutex, NULL, \ + MUTEX_DRIVER, NULL) +#define E1000_MUTEX_DESTROY(mutex) mutex_destroy(mutex) + +#define E1000_MUTEX_LOCK(mutex) mutex_enter(mutex) +#define E1000_MUTEX_TRYLOCK(mutex) mutex_tryenter(mutex) +#define E1000_MUTEX_UNLOCK(mutex) mutex_exit(mutex) + #ifdef __sparc /* on SPARC, use only memory-mapped routines */ #define E1000_WRITE_REG_IO E1000_WRITE_REG #else /* on x86, use port io routines */
--- a/usr/src/uts/common/io/e1000g/e1000_phy.c Tue Sep 29 11:19:43 2009 +0800 +++ b/usr/src/uts/common/io/e1000g/e1000_phy.c Tue Sep 29 12:12:23 2009 +0800 @@ -24,7 +24,7 @@ */ /* - * IntelVersion: 1.112 sol_anvik_patch + * IntelVersion: 1.143 v3-1-3_2009-8-20 */ #include "e1000_api.h" @@ -32,6 +32,10 @@ static s32 e1000_access_phy_wakeup_reg_bm(struct e1000_hw *hw, u32 offset, u16 *data, bool read); +static u32 e1000_get_phy_addr_for_hv_page(u32 page); +static s32 e1000_access_phy_debug_regs_hv(struct e1000_hw *hw, u32 offset, + u16 *data, bool read); + /* Cable length tables */ static const u16 e1000_m88_cable_length_table[] = {0, 50, 80, 110, 140, 140, E1000_CABLE_LENGTH_UNDEFINED}; @@ -168,26 +172,47 @@ struct e1000_phy_info *phy = &hw->phy; s32 ret_val = E1000_SUCCESS; u16 phy_id; + u16 retry_count = 0; DEBUGFUNC("e1000_get_phy_id"); if (!(phy->ops.read_reg)) goto out; - ret_val = phy->ops.read_reg(hw, PHY_ID1, &phy_id); - if (ret_val) - goto out; - - phy->id = (u32)(phy_id << 16); - usec_delay(20); - ret_val = phy->ops.read_reg(hw, PHY_ID2, &phy_id); - if (ret_val) - goto out; - - phy->id |= (u32)(phy_id & PHY_REVISION_MASK); - phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK); - + while (retry_count < 2) { + ret_val = phy->ops.read_reg(hw, PHY_ID1, &phy_id); + if (ret_val) + goto out; + + phy->id = (u32)(phy_id << 16); + usec_delay(20); + ret_val = phy->ops.read_reg(hw, PHY_ID2, &phy_id); + if (ret_val) + goto out; + + phy->id |= (u32)(phy_id & PHY_REVISION_MASK); + phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK); + + if (phy->id != 0 && phy->id != PHY_REVISION_MASK) + goto out; + + /* + * If the PHY ID is still unknown, we may have an 82577 without + * link. We will try again after setting Slow MDIC mode. No + * harm in trying again in this case since the PHY ID is + * unknown at this point anyway + */ + ret_val = e1000_set_mdio_slow_mode_hv(hw, true); + if (ret_val) + goto out; + + retry_count++; + } out: + /* Revert to MDIO fast mode, if applicable */ + if (retry_count) + ret_val = e1000_set_mdio_slow_mode_hv(hw, false); + return (ret_val); } @@ -558,6 +583,51 @@ } /* + * e1000_copper_link_setup_82577 - Setup 82577 PHY for copper link + * @hw: pointer to the HW structure + * + * Sets up Carrier-sense on Transmit and downshift values. + */ +s32 +e1000_copper_link_setup_82577(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 phy_data; + + DEBUGFUNC("e1000_copper_link_setup_82577"); + + if (phy->reset_disable) { + ret_val = E1000_SUCCESS; + goto out; + } + + /* Enable CRS on TX. This must be set for half-duplex operation. */ + ret_val = phy->ops.read_reg(hw, I82577_CFG_REG, &phy_data); + if (ret_val) + goto out; + + phy_data |= I82577_CFG_ASSERT_CRS_ON_TX; + + /* Enable downshift */ + phy_data |= I82577_CFG_ENABLE_DOWNSHIFT; + + ret_val = phy->ops.write_reg(hw, I82577_CFG_REG, phy_data); + if (ret_val) + goto out; + + /* Set number of link attempts before downshift */ + ret_val = phy->ops.read_reg(hw, I82577_CTRL_REG, &phy_data); + if (ret_val) + goto out; + phy_data &= ~I82577_CTRL_DOWNSHIFT_MASK; + ret_val = phy->ops.write_reg(hw, I82577_CTRL_REG, phy_data); + +out: + return (ret_val); +} + +/* * e1000_copper_link_setup_m88 - Setup m88 PHY's for copper link * @hw: pointer to the HW structure * @@ -583,8 +653,8 @@ if (ret_val) goto out; - /* For newer PHYs this bit is downshift enable */ - if (phy->type == e1000_phy_m88) + /* For BM PHY this bit is downshift enable */ + if (phy->type != e1000_phy_bm) phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX; /* @@ -685,6 +755,21 @@ goto out; } + if (phy->type == e1000_phy_82578) { + ret_val = phy->ops.read_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, + &phy_data); + if (ret_val) + goto out; + + /* 82578 PHY - set the downshift count to 1x. */ + phy_data |= I82578_EPSCR_DOWNSHIFT_ENABLE; + phy_data &= ~I82578_EPSCR_DOWNSHIFT_COUNTER_MASK; + ret_val = phy->ops.write_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, + phy_data); + if (ret_val) + goto out; +} + out: return (ret_val); } @@ -1315,6 +1400,77 @@ } /* + * e1000_phy_force_speed_duplex_ife - Force PHY speed & duplex + * @hw: pointer to the HW structure + * + * Forces the speed and duplex settings of the PHY. + * This is a function pointer entry point only called by + * PHY setup routines. + */ +s32 +e1000_phy_force_speed_duplex_ife(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 data; + bool link; + + DEBUGFUNC("e1000_phy_force_speed_duplex_ife"); + + if (phy->type != e1000_phy_ife) { + ret_val = e1000_phy_force_speed_duplex_igp(hw); + goto out; + } + + ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &data); + if (ret_val) + goto out; + + e1000_phy_force_speed_duplex_setup(hw, &data); + + ret_val = phy->ops.write_reg(hw, PHY_CONTROL, data); + if (ret_val) + goto out; + + /* Disable MDI-X support for 10/100 */ + ret_val = phy->ops.read_reg(hw, IFE_PHY_MDIX_CONTROL, &data); + if (ret_val) + goto out; + + data &= ~IFE_PMC_AUTO_MDIX; + data &= ~IFE_PMC_FORCE_MDIX; + + ret_val = phy->ops.write_reg(hw, IFE_PHY_MDIX_CONTROL, data); + if (ret_val) + goto out; + + DEBUGOUT1("IFE PMC: %X\n", data); + + usec_delay(1); + + if (phy->autoneg_wait_to_complete) { + DEBUGOUT("Waiting for forced speed/duplex link on IFE phy.\n"); + + ret_val = e1000_phy_has_link_generic(hw, + PHY_FORCE_LIMIT, 100000, &link); + if (ret_val) + goto out; + + if (!link) + DEBUGOUT("Link taking longer than expected.\n"); + + /* Try once more */ + ret_val = e1000_phy_has_link_generic(hw, + PHY_FORCE_LIMIT, 100000, &link); + if (ret_val) + goto out; + } + +out: + return (ret_val); +} + +/* * e1000_phy_force_speed_duplex_setup - Configure forced PHY speed/duplex * @hw: pointer to the HW structure * @phy_ctrl: pointer to current value of PHY_CONTROL @@ -1367,8 +1523,7 @@ DEBUGOUT("Forcing 100mb\n"); } else { ctrl &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100); - /* OR 0x0000 constant for documenting intent */ - /* LINTED E_EXPR_NULL_EFFECT */ + /* LINTED */ *phy_ctrl |= MII_CR_SPEED_10; *phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_100); DEBUGOUT("Forcing 10mb\n"); @@ -1497,6 +1652,7 @@ case e1000_phy_m88: case e1000_phy_gg82563: case e1000_phy_bm: + case e1000_phy_82578: offset = M88E1000_PHY_SPEC_STATUS; mask = M88E1000_PSSR_DOWNSHIFT; break; @@ -1599,6 +1755,41 @@ } /* + * e1000_check_polarity_ife - Check cable polarity for IFE PHY + * @hw: pointer to the HW structure + * + * Polarity is determined on the polarity reversal feature being enabled. + */ +s32 +e1000_check_polarity_ife(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 phy_data, offset, mask; + + DEBUGFUNC("e1000_check_polarity_ife"); + + /* + * Polarity is determined based on the reversal feature being enabled. + */ + if (phy->polarity_correction) { + offset = IFE_PHY_EXTENDED_STATUS_CONTROL; + mask = IFE_PESC_POLARITY_REVERSED; + } else { + offset = IFE_PHY_SPECIAL_CONTROL; + mask = IFE_PSC_FORCE_POLARITY; + } + + ret_val = phy->ops.read_reg(hw, offset, &phy_data); + + if (!ret_val) + phy->cable_polarity = (phy_data & mask) + ? e1000_rev_polarity_reversed : e1000_rev_polarity_normal; + + return (ret_val); +} + +/* * e1000_wait_autoneg_generic - Wait for auto-neg completion * @hw: pointer to the HW structure * @@ -1664,9 +1855,16 @@ * the board. */ ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status); - if (ret_val) - break; - ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status); + if (ret_val) { + /* + * If the first read fails, another entity may have + * ownership of the resources, wait and try again to + * see if they have relinquished the resources yet. + */ + usec_delay(usec_interval); + } + ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, + &phy_status); if (ret_val) break; if (phy_status & MII_SR_LINK_STATUS) @@ -1713,15 +1911,14 @@ index = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >> M88E1000_PSSR_CABLE_LENGTH_SHIFT; - if (index < M88E1000_CABLE_LENGTH_TABLE_SIZE + 1) { - phy->min_cable_length = e1000_m88_cable_length_table[index]; - phy->max_cable_length = e1000_m88_cable_length_table[index + 1]; - - phy->cable_length = (phy->min_cable_length + - phy->max_cable_length) / 2; - } else { + if (index >= M88E1000_CABLE_LENGTH_TABLE_SIZE - 1) { ret_val = E1000_ERR_PHY; + goto out; } + phy->min_cable_length = e1000_m88_cable_length_table[index]; + phy->max_cable_length = e1000_m88_cable_length_table[index + 1]; + + phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2; out: return (ret_val); @@ -2171,6 +2368,12 @@ case BME1000_E_PHY_ID_R2: phy_type = e1000_phy_bm; break; + case I82578_E_PHY_ID: + phy_type = e1000_phy_82578; + break; + case I82577_E_PHY_ID: + phy_type = e1000_phy_82577; + break; default: phy_type = e1000_phy_unknown; break; @@ -2194,6 +2397,8 @@ u32 i; enum e1000_phy_type phy_type = e1000_phy_unknown; + hw->phy.id = phy_type; + for (phy_addr = 0; phy_addr < E1000_MAX_PHY_ADDR; phy_addr++) { hw->phy.addr = phy_addr; i = 0; @@ -2487,11 +2692,17 @@ u32 offset, u16 *data, bool read) { s32 ret_val; - u16 reg = ((u16)offset); + u16 reg = BM_PHY_REG_NUM(offset); u16 phy_reg = 0; u8 phy_acquired = 1; - DEBUGFUNC("e1000_read_phy_wakeup_reg_bm"); + DEBUGFUNC("e1000_access_phy_wakeup_reg_bm"); + + /* Gig must be disabled for MDIO accesses to page 800 */ + if ((hw->mac.type == e1000_pchlan) && + (!(E1000_READ_REG(hw, E1000_PHY_CTRL) & + E1000_PHY_CTRL_GBE_DISABLE))) + DEBUGOUT("Attempting to access page 800 while gig enabled.\n"); ret_val = hw->phy.ops.acquire(hw); if (ret_val) { @@ -2546,13 +2757,13 @@ ret_val = e1000_read_phy_reg_mdic(hw, BM_WUC_DATA_OPCODE, data); } else { - /* Read the page 800 value using opcode 0x12 */ + /* Write the page 800 value using opcode 0x12 */ ret_val = e1000_write_phy_reg_mdic(hw, BM_WUC_DATA_OPCODE, *data); } if (ret_val) { - DEBUGOUT("Could not read data value from page 800\n"); + DEBUGOUT("Could not access data value from page 800\n"); goto out; } @@ -2613,3 +2824,542 @@ hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg); msec_delay(1); } + +s32 +e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw, bool slow) +{ + s32 ret_val = E1000_SUCCESS; + u16 data = 0; + + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + return (ret_val); + + /* Set MDIO mode - page 769, register 16: 0x2580==slow, 0x2180==fast */ + hw->phy.addr = 1; + ret_val = e1000_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT, + (BM_PORT_CTRL_PAGE << IGP_PAGE_SHIFT)); + if (ret_val) + goto out; + + ret_val = e1000_write_phy_reg_mdic(hw, BM_CS_CTRL1, + (0x2180 | (slow << 10))); + + if (ret_val) + goto out; + + /* dummy read when reverting to fast mode - throw away result */ + if (!slow) + ret_val = e1000_read_phy_reg_mdic(hw, BM_CS_CTRL1, &data); + +out: + hw->phy.ops.release(hw); + return (ret_val); +} + +/* + * e1000_read_phy_reg_hv - Read HV PHY register + * @hw: pointer to the HW structure + * @offset: register offset to be read + * @data: pointer to the read data + * + * Acquires semaphore, if necessary, then reads the PHY register at offset + * and storing the retrieved information in data. Release any acquired + * semaphore before exiting. + */ +s32 +e1000_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data) +{ + s32 ret_val; + u16 page = BM_PHY_REG_PAGE(offset); + u16 reg = BM_PHY_REG_NUM(offset); + bool in_slow_mode = false; + + DEBUGFUNC("e1000_read_phy_reg_hv"); + + /* Workaround failure in MDIO access while cable is disconnected */ + if ((hw->phy.type == e1000_phy_82577) && + !(E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU)) { + ret_val = e1000_set_mdio_slow_mode_hv(hw, true); + if (ret_val) + goto out; + + in_slow_mode = true; + } + + /* Page 800 works differently than the rest so it has its own func */ + if (page == BM_WUC_PAGE) { + ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, + data, true); + goto out; + } + + if (page > 0 && page < HV_INTC_FC_PAGE_START) { + ret_val = e1000_access_phy_debug_regs_hv(hw, offset, + data, true); + goto out; + } + + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + goto out; + + hw->phy.addr = e1000_get_phy_addr_for_hv_page(page); + + if (page == HV_INTC_FC_PAGE_START) + page = 0; + + if (reg > MAX_PHY_MULTI_PAGE_REG) { + u32 phy_addr = hw->phy.addr; + hw->phy.addr = 1; + + /* Page is shifted left, PHY expects (page x 32) */ + ret_val = e1000_write_phy_reg_mdic(hw, + IGP01E1000_PHY_PAGE_SELECT, + (page << IGP_PAGE_SHIFT)); + hw->phy.addr = phy_addr; + + if (ret_val) { + hw->phy.ops.release(hw); + goto out; + } + } + + ret_val = e1000_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & reg, + data); + hw->phy.ops.release(hw); + +out: + /* Revert to MDIO fast mode, if applicable */ + if ((hw->phy.type == e1000_phy_82577) && in_slow_mode) + ret_val = e1000_set_mdio_slow_mode_hv(hw, false); + + return (ret_val); +} + +/* + * e1000_write_phy_reg_hv - Write HV PHY register + * @hw: pointer to the HW structure + * @offset: register offset to write to + * @data: data to write at register offset + * + * Acquires semaphore, if necessary, then writes the data to PHY register + * at the offset. Release any acquired semaphores before exiting. + */ +s32 +e1000_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data) +{ + s32 ret_val; + u16 page = BM_PHY_REG_PAGE(offset); + u16 reg = BM_PHY_REG_NUM(offset); + bool in_slow_mode = false; + + DEBUGFUNC("e1000_write_phy_reg_hv"); + + /* Workaround failure in MDIO access while cable is disconnected */ + if ((hw->phy.type == e1000_phy_82577) && + !(E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU)) { + ret_val = e1000_set_mdio_slow_mode_hv(hw, true); + if (ret_val) + goto out; + + in_slow_mode = true; + } + + /* Page 800 works differently than the rest so it has its own func */ + if (page == BM_WUC_PAGE) { + ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, + &data, false); + goto out; + } + + if (page > 0 && page < HV_INTC_FC_PAGE_START) { + ret_val = e1000_access_phy_debug_regs_hv(hw, offset, + &data, false); + goto out; + } + + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + goto out; + + hw->phy.addr = e1000_get_phy_addr_for_hv_page(page); + + if (page == HV_INTC_FC_PAGE_START) + page = 0; + + /* + * Workaround MDIO accesses being disabled after entering IEEE Power + * Down (whenever bit 11 of the PHY Control register is set) + */ + if ((hw->phy.type == e1000_phy_82578) && + (hw->phy.revision >= 1) && + (hw->phy.addr == 2) && + ((MAX_PHY_REG_ADDRESS & reg) == 0) && + (data & (1 << 11))) { + u16 data2 = 0x7EFF; + hw->phy.ops.release(hw); + ret_val = e1000_access_phy_debug_regs_hv(hw, (1 << 6) | 0x3, + &data2, false); + if (ret_val) + goto out; + + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + goto out; + } + + if (reg > MAX_PHY_MULTI_PAGE_REG) { + u32 phy_addr = hw->phy.addr; + hw->phy.addr = 1; + + /* Page is shifted left, PHY expects (page x 32) */ + ret_val = e1000_write_phy_reg_mdic(hw, + IGP01E1000_PHY_PAGE_SELECT, + (page << IGP_PAGE_SHIFT)); + hw->phy.addr = phy_addr; + + if (ret_val) { + hw->phy.ops.release(hw); + goto out; + } + } + + ret_val = e1000_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & reg, + data); + hw->phy.ops.release(hw); + +out: + /* Revert to MDIO fast mode, if applicable */ + if ((hw->phy.type == e1000_phy_82577) && in_slow_mode) + ret_val = e1000_set_mdio_slow_mode_hv(hw, false); + + return (ret_val); +} + +/* + * e1000_get_phy_addr_for_hv_page - Get PHY adrress based on page + * @page: page to be accessed + */ +static u32 +e1000_get_phy_addr_for_hv_page(u32 page) +{ + u32 phy_addr = 2; + + if (page >= HV_INTC_FC_PAGE_START) + phy_addr = 1; + + return (phy_addr); +} + +/* + * e1000_access_phy_debug_regs_hv - Read HV PHY vendor specific high registers + * @hw: pointer to the HW structure + * @offset: register offset to be read or written + * @data: pointer to the data to be read or written + * @read: determines if operation is read or written + * + * Acquires semaphore, if necessary, then reads the PHY register at offset + * and storing the retreived information in data. Release any acquired + * semaphores before exiting. Note that the procedure to read these regs + * uses the address port and data port to read/write. + */ +static s32 +e1000_access_phy_debug_regs_hv(struct e1000_hw *hw, u32 offset, + u16 *data, bool read) +{ + s32 ret_val; + u32 addr_reg = 0; + u32 data_reg = 0; + u8 phy_acquired = 1; + + DEBUGFUNC("e1000_access_phy_debug_regs_hv"); + + /* This takes care of the difference with desktop vs mobile phy */ + addr_reg = (hw->phy.type == e1000_phy_82578) ? + I82578_ADDR_REG : I82577_ADDR_REG; + data_reg = addr_reg + 1; + + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) { + DEBUGOUT("Could not acquire PHY\n"); + phy_acquired = 0; + goto out; + } + + /* All operations in this function are phy address 2 */ + hw->phy.addr = 2; + + /* masking with 0x3F to remove the page from offset */ + ret_val = e1000_write_phy_reg_mdic(hw, addr_reg, (u16)offset & 0x3F); + if (ret_val) { + DEBUGOUT("Could not write PHY the HV address register\n"); + goto out; + } + + /* Read or write the data value next */ + if (read) + ret_val = e1000_read_phy_reg_mdic(hw, data_reg, data); + else + ret_val = e1000_write_phy_reg_mdic(hw, data_reg, *data); + + if (ret_val) { + DEBUGOUT("Could not read data value from HV data register\n"); + goto out; + } + +out: + if (phy_acquired == 1) + hw->phy.ops.release(hw); + return (ret_val); +} + +/* + * e1000_link_stall_workaround_hv - Si workaround + * @hw: pointer to the HW structure + * + * This function works around a Si bug where the link partner can get + * a link up indication before the PHY does. If small packets are sent + * by the link partner they can be placed in the packet buffer without + * being properly accounted for by the PHY and will stall preventing + * further packets from being received. The workaround is to clear the + * packet buffer after the PHY detects link up. + */ +s32 +e1000_link_stall_workaround_hv(struct e1000_hw *hw) +{ + s32 ret_val = E1000_SUCCESS; + u16 data; + + DEBUGFUNC("e1000_link_stall_workaround_hv"); + + if (hw->phy.type != e1000_phy_82578) + goto out; + + /* Do not apply workaround if in PHY loopback bit 14 set */ + hw->phy.ops.read_reg(hw, PHY_CONTROL, &data); + if (data & PHY_CONTROL_LB) + goto out; + + /* check if link is up and at 1Gbps */ + ret_val = hw->phy.ops.read_reg(hw, BM_CS_STATUS, &data); + if (ret_val) + goto out; + + data &= BM_CS_STATUS_LINK_UP | + BM_CS_STATUS_RESOLVED | + BM_CS_STATUS_SPEED_MASK; + + if (data != (BM_CS_STATUS_LINK_UP | + BM_CS_STATUS_RESOLVED | + BM_CS_STATUS_SPEED_1000)) + goto out; + + msec_delay(200); + + /* flush the packets in the fifo buffer */ + ret_val = hw->phy.ops.write_reg(hw, HV_MUX_DATA_CTRL, + HV_MUX_DATA_CTRL_GEN_TO_MAC | HV_MUX_DATA_CTRL_FORCE_SPEED); + if (ret_val) + goto out; + + ret_val = hw->phy.ops.write_reg(hw, HV_MUX_DATA_CTRL, + HV_MUX_DATA_CTRL_GEN_TO_MAC); + +out: + return (ret_val); +} + +/* + * e1000_check_polarity_82577 - Checks the polarity. + * @hw: pointer to the HW structure + * + * Success returns 0, Failure returns -E1000_ERR_PHY (-2) + * + * Polarity is determined based on the PHY specific status register. + */ +s32 +e1000_check_polarity_82577(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 data; + + DEBUGFUNC("e1000_check_polarity_82577"); + + ret_val = phy->ops.read_reg(hw, I82577_PHY_STATUS_2, &data); + + if (!ret_val) + phy->cable_polarity = (data & I82577_PHY_STATUS2_REV_POLARITY) + ? e1000_rev_polarity_reversed + : e1000_rev_polarity_normal; + + return (ret_val); +} + +/* + * e1000_phy_force_speed_duplex_82577 - Force speed/duplex for I82577 PHY + * @hw: pointer to the HW structure + * + * Calls the PHY setup function to force speed and duplex. Clears the + * auto-crossover to force MDI manually. Waits for link and returns + * successful if link up is successful, else -E1000_ERR_PHY (-2). + */ +s32 +e1000_phy_force_speed_duplex_82577(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 phy_data; + bool link; + + DEBUGFUNC("e1000_phy_force_speed_duplex_82577"); + + ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_data); + if (ret_val) + goto out; + + e1000_phy_force_speed_duplex_setup(hw, &phy_data); + + ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_data); + if (ret_val) + goto out; + + /* + * Clear Auto-Crossover to force MDI manually. 82577 requires MDI + * forced whenever speed and duplex are forced. + */ + ret_val = phy->ops.read_reg(hw, I82577_PHY_CTRL_2, &phy_data); + if (ret_val) + goto out; + + phy_data &= ~I82577_PHY_CTRL2_AUTO_MDIX; + phy_data &= ~I82577_PHY_CTRL2_FORCE_MDI_MDIX; + + ret_val = phy->ops.write_reg(hw, I82577_PHY_CTRL_2, phy_data); + if (ret_val) + goto out; + + DEBUGOUT1("I82577_PHY_CTRL_2: %X\n", phy_data); + + usec_delay(1); + + if (phy->autoneg_wait_to_complete) { + DEBUGOUT("Waiting for forced speed/duplex link on 82577 phy\n"); + + ret_val = e1000_phy_has_link_generic(hw, + PHY_FORCE_LIMIT, 100000, &link); + if (ret_val) + goto out; + + if (!link) + DEBUGOUT("Link taking longer than expected.\n"); + + /* Try once more */ + ret_val = e1000_phy_has_link_generic(hw, + PHY_FORCE_LIMIT, 100000, &link); + if (ret_val) + goto out; + } + +out: + return (ret_val); +} + +/* + * e1000_get_phy_info_82577 - Retrieve I82577 PHY information + * @hw: pointer to the HW structure + * + * Read PHY status to determine if link is up. If link is up, then + * set/determine 10base-T extended distance and polarity correction. Read + * PHY port status to determine MDI/MDIx and speed. Based on the speed, + * determine on the cable length, local and remote receiver. + */ +s32 +e1000_get_phy_info_82577(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 data; + bool link; + + DEBUGFUNC("e1000_get_phy_info_82577"); + + ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link); + if (ret_val) + goto out; + + if (!link) { + DEBUGOUT("Phy info is only valid if link is up\n"); + ret_val = -E1000_ERR_CONFIG; + goto out; + } + + phy->polarity_correction = true; + + ret_val = e1000_check_polarity_82577(hw); + if (ret_val) + goto out; + + ret_val = phy->ops.read_reg(hw, I82577_PHY_STATUS_2, &data); + if (ret_val) + goto out; + + phy->is_mdix = (data & I82577_PHY_STATUS2_MDIX) ? true : false; + + if ((data & I82577_PHY_STATUS2_SPEED_MASK) == + I82577_PHY_STATUS2_SPEED_1000MBPS) { + ret_val = hw->phy.ops.get_cable_length(hw); + if (ret_val) + goto out; + + ret_val = phy->ops.read_reg(hw, PHY_1000T_STATUS, &data); + if (ret_val) + goto out; + + phy->local_rx = (data & SR_1000T_LOCAL_RX_STATUS) + ? e1000_1000t_rx_status_ok : e1000_1000t_rx_status_not_ok; + + phy->remote_rx = (data & SR_1000T_REMOTE_RX_STATUS) + ? e1000_1000t_rx_status_ok : e1000_1000t_rx_status_not_ok; + } else { + phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED; + phy->local_rx = e1000_1000t_rx_status_undefined; + phy->remote_rx = e1000_1000t_rx_status_undefined; + } + +out: + return (ret_val); +} + +/* + * e1000_get_cable_length_82577 - Determine cable length for 82577 PHY + * @hw: pointer to the HW structure + * + * Reads the diagnostic status register and verifies result is valid before + * placing it in the phy_cable_length field. + */ +s32 +e1000_get_cable_length_82577(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 phy_data, length; + + DEBUGFUNC("e1000_get_cable_length_82577"); + + ret_val = phy->ops.read_reg(hw, I82577_PHY_DIAG_STATUS, &phy_data); + if (ret_val) + goto out; + + length = (phy_data & I82577_DSTATUS_CABLE_LENGTH) >> + I82577_DSTATUS_CABLE_LENGTH_SHIFT; + + if (length == E1000_CABLE_LENGTH_UNDEFINED) + ret_val = E1000_ERR_PHY; + + phy->cable_length = length; + +out: + return (ret_val); +}
--- a/usr/src/uts/common/io/e1000g/e1000_phy.h Tue Sep 29 11:19:43 2009 +0800 +++ b/usr/src/uts/common/io/e1000g/e1000_phy.h Tue Sep 29 12:12:23 2009 +0800 @@ -24,7 +24,7 @@ */ /* - * IntelVersion: 1.55 sol_anvik_patch + * IntelVersion: 1.70 v3-1-3_2009-8-20 */ #ifndef _E1000_PHY_H_ #define _E1000_PHY_H_ @@ -41,12 +41,14 @@ s32 e1000_check_downshift_generic(struct e1000_hw *hw); s32 e1000_check_polarity_m88(struct e1000_hw *hw); s32 e1000_check_polarity_igp(struct e1000_hw *hw); +s32 e1000_check_polarity_ife(struct e1000_hw *hw); s32 e1000_check_reset_block_generic(struct e1000_hw *hw); s32 e1000_copper_link_autoneg(struct e1000_hw *hw); s32 e1000_copper_link_setup_igp(struct e1000_hw *hw); s32 e1000_copper_link_setup_m88(struct e1000_hw *hw); s32 e1000_phy_force_speed_duplex_igp(struct e1000_hw *hw); s32 e1000_phy_force_speed_duplex_m88(struct e1000_hw *hw); +s32 e1000_phy_force_speed_duplex_ife(struct e1000_hw *hw); s32 e1000_get_cable_length_m88(struct e1000_hw *hw); s32 e1000_get_cable_length_igp_2(struct e1000_hw *hw); s32 e1000_get_cfg_done_generic(struct e1000_hw *hw); @@ -81,6 +83,15 @@ void e1000_power_down_phy_copper(struct e1000_hw *hw); s32 e1000_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data); s32 e1000_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data); +s32 e1000_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data); +s32 e1000_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data); +s32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw, bool slow); +s32 e1000_link_stall_workaround_hv(struct e1000_hw *hw); +s32 e1000_copper_link_setup_82577(struct e1000_hw *hw); +s32 e1000_check_polarity_82577(struct e1000_hw *hw); +s32 e1000_get_phy_info_82577(struct e1000_hw *hw); +s32 e1000_phy_force_speed_duplex_82577(struct e1000_hw *hw); +s32 e1000_get_cable_length_82577(struct e1000_hw *hw); #define E1000_MAX_PHY_ADDR 4 @@ -97,21 +108,70 @@ #define IGP_PAGE_SHIFT 5 #define PHY_REG_MASK 0x1F +/* BM/HV Specific Registers */ +#define BM_PORT_CTRL_PAGE 769 +#define BM_PCIE_PAGE 770 #define BM_WUC_PAGE 800 #define BM_WUC_ADDRESS_OPCODE 0x11 #define BM_WUC_DATA_OPCODE 0x12 -#define BM_WUC_ENABLE_PAGE 769 +#define BM_WUC_ENABLE_PAGE BM_PORT_CTRL_PAGE #define BM_WUC_ENABLE_REG 17 #define BM_WUC_ENABLE_BIT (1 << 2) #define BM_WUC_HOST_WU_BIT (1 << 4) +#define PHY_UPPER_SHIFT 21 +#define BM_PHY_REG(page, reg) \ + (((reg) & MAX_PHY_REG_ADDRESS) |\ + (((page) & 0xFFFF) << PHY_PAGE_SHIFT) |\ + (((reg) & ~MAX_PHY_REG_ADDRESS) << (PHY_UPPER_SHIFT - PHY_PAGE_SHIFT))) +#define BM_PHY_REG_PAGE(offset) \ + ((u16)(((offset) >> PHY_PAGE_SHIFT) & 0xFFFF)) +#define BM_PHY_REG_NUM(offset) \ + ((u16)(((offset) & MAX_PHY_REG_ADDRESS) |\ + (((offset) >> (PHY_UPPER_SHIFT - PHY_PAGE_SHIFT)) &\ + ~MAX_PHY_REG_ADDRESS))) + +#define HV_INTC_FC_PAGE_START 768 +#define I82578_ADDR_REG 29 +#define I82577_ADDR_REG 16 +#define I82577_CFG_REG 22 +#define I82577_CFG_ASSERT_CRS_ON_TX (1 << 15) +#define I82577_CFG_ENABLE_DOWNSHIFT (3 << 10) /* auto downshift 100/10 */ +#define I82577_CTRL_REG 23 +#define I82577_CTRL_DOWNSHIFT_MASK (7 << 10) + +/* 82577 specific PHY registers */ +#define I82577_PHY_CTRL_2 18 +#define I82577_PHY_LBK_CTRL 19 +#define I82577_PHY_STATUS_2 26 +#define I82577_PHY_DIAG_STATUS 31 + +/* I82577 PHY Status 2 */ +#define I82577_PHY_STATUS2_REV_POLARITY 0x0400 +#define I82577_PHY_STATUS2_MDIX 0x0800 +#define I82577_PHY_STATUS2_SPEED_MASK 0x0300 +#define I82577_PHY_STATUS2_SPEED_1000MBPS 0x0200 +#define I82577_PHY_STATUS2_SPEED_100MBPS 0x0100 + +/* I82577 PHY Control 2 */ +#define I82577_PHY_CTRL2_AUTO_MDIX 0x0400 +#define I82577_PHY_CTRL2_FORCE_MDI_MDIX 0x0200 + +/* I82577 PHY Diagnostics Status */ +#define I82577_DSTATUS_CABLE_LENGTH 0x03FC +#define I82577_DSTATUS_CABLE_LENGTH_SHIFT 2 + /* BM PHY Copper Specific Control 1 */ #define BM_CS_CTRL1 16 #define BM_CS_CTRL1_ENERGY_DETECT 0x0300 /* Enable Energy Detect */ -/* BM PHY Copper Specific States */ +/* BM PHY Copper Specific Status */ #define BM_CS_STATUS 17 #define BM_CS_STATUS_ENERGY_DETECT 0x0010 /* Energy Detect Status */ +#define BM_CS_STATUS_LINK_UP 0x0400 +#define BM_CS_STATUS_RESOLVED 0x0800 +#define BM_CS_STATUS_SPEED_MASK 0xC000 +#define BM_CS_STATUS_SPEED_1000 0x8000 #define IGP01E1000_PHY_PCS_INIT_REG 0x00B4 #define IGP01E1000_PHY_POLARITY_MASK 0x0078 @@ -132,7 +192,7 @@ #define IGP01E1000_PLHR_SS_DOWNGRADE 0x8000 #define IGP01E1000_PSSR_POLARITY_REVERSED 0x0002 -#define IGP01E1000_PSSR_MDIX 0x0008 +#define IGP01E1000_PSSR_MDIX 0x0800 #define IGP01E1000_PSSR_SPEED_MASK 0xC000 #define IGP01E1000_PSSR_SPEED_1000MBPS 0xC000 @@ -155,7 +215,12 @@ #define E1000_KMRNCTRLSTA_OFFSET_SHIFT 16 #define E1000_KMRNCTRLSTA_REN 0x00200000 #define E1000_KMRNCTRLSTA_DIAG_OFFSET 0x3 /* Kumeran Diagnostic */ +#define E1000_KMRNCTRLSTA_TIMEOUTS 0x4 /* Kumeran Timeouts */ +#define E1000_KMRNCTRLSTA_INBAND_PARAM 0x9 /* Kumeran InBand Parameters */ #define E1000_KMRNCTRLSTA_DIAG_NELPBK 0x1000 /* Nearend Loopback mode */ +#define E1000_KMRNCTRLSTA_K1_CONFIG 0x7 +#define E1000_KMRNCTRLSTA_K1_ENABLE 0x140E +#define E1000_KMRNCTRLSTA_K1_DISABLE 0x1400 #define IFE_PHY_EXTENDED_STATUS_CONTROL 0x10 #define IFE_PHY_SPECIAL_CONTROL 0x11 /* 100BaseTx PHY Special Control */
--- a/usr/src/uts/common/io/e1000g/e1000_regs.h Tue Sep 29 11:19:43 2009 +0800 +++ b/usr/src/uts/common/io/e1000g/e1000_regs.h Tue Sep 29 12:12:23 2009 +0800 @@ -24,7 +24,7 @@ */ /* - * IntelVersion: 1.61 sol_anvik_patch + * IntelVersion: 1.76 v3-1-3_2009-8-20 */ #ifndef _E1000_REGS_H_ #define _E1000_REGS_H_ @@ -56,10 +56,13 @@ #define E1000_IMC 0x000D8 /* Interrupt Mask Clear - WO */ #define E1000_IAM 0x000E0 /* Interrupt Acknowledge Auto Mask */ #define E1000_IVAR 0x000E4 /* Interrupt Vector Allocation Register - RW */ +#define E1000_SVCR 0x000F0 +#define E1000_SVT 0x000F4 #define E1000_RCTL 0x00100 /* Rx Control - RW */ #define E1000_FCTTV 0x00170 /* Flow Control Transmit Timer Value - RW */ #define E1000_TXCW 0x00178 /* Tx Configuration Word - RW */ #define E1000_RXCW 0x00180 /* Rx Configuration Word - RO */ +#define E1000_PBA_ECC 0x01100 /* PBA ECC Register */ #define E1000_TCTL 0x00400 /* Tx Control - RW */ #define E1000_TCTL_EXT 0x00404 /* Extended Tx Control - RW */ #define E1000_TIPG 0x00410 /* Tx Inter-packet gap -RW */ @@ -247,6 +250,8 @@ /* Interrupt Cause Receiver Overrun Count */ #define E1000_ICRXOC 0x04124 +#define E1000_CRC_OFFSET 0x05F50 /* CRC Offset register */ + #define E1000_PCS_CFG0 0x04200 /* PCS Configuration 0 - RW */ #define E1000_PCS_LCTL 0x04208 /* PCS Link Control - RW */ #define E1000_PCS_LSTAT 0x0420C /* PCS Link Status - RO */ @@ -301,6 +306,7 @@ #define E1000_GIOCTL 0x05B44 /* GIO Analog Control Register */ #define E1000_SCCTL 0x05B4C /* PCIc PLL Configuration Register */ #define E1000_GCR 0x05B00 /* PCI-Ex Control */ +#define E1000_GCR2 0x05B64 /* PCI-Ex Control #2 */ #define E1000_GSCL_1 0x05B10 /* PCI-Ex Statistic Control #1 */ #define E1000_GSCL_2 0x05B14 /* PCI-Ex Statistic Control #2 */ #define E1000_GSCL_3 0x05B18 /* PCI-Ex Statistic Control #3 */ @@ -308,6 +314,8 @@ #define E1000_FACTPS 0x05B30 /* Function Active and Power State to MNG */ #define E1000_SWSM 0x05B50 /* SW Semaphore */ #define E1000_FWSM 0x05B54 /* FW Semaphore */ +/* Driver-only SW semaphore (not used by BOOT agents) */ +#define E1000_SWSM2 0x05B58 #define E1000_DCA_ID 0x05B70 /* DCA Requester ID Information - RO */ #define E1000_DCA_CTRL 0x05B74 /* DCA Control - RW */ #define E1000_FFLT_DBG 0x05F04 /* Debug Register */
--- a/usr/src/uts/common/io/e1000g/e1000g.conf Tue Sep 29 11:19:43 2009 +0800 +++ b/usr/src/uts/common/io/e1000g/e1000g.conf Tue Sep 29 12:12:23 2009 +0800 @@ -6,7 +6,7 @@ # # CDDL LICENSE SUMMARY # -# Copyright(c) 1999 - 2007 Intel Corporation. All rights reserved. +# Copyright(c) 1999 - 2009 Intel Corporation. All rights reserved. # # The contents of this file are subject to the terms of Version # 1.0 of the Common Development and Distribution License (the "License"). @@ -18,12 +18,10 @@ # and limitations under the License. # # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms of the CDDLv1. # # -# ident "%Z%%M% %I% %E% SMI" -# # Driver.conf file for Intel e1000g Gigabit Ethernet Adapter # ForceSpeedDuplex=7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7; @@ -54,11 +52,17 @@ # 1 is for upto 4k size frames. # 2 is for upto 8k size frames. # 3 is for upto 16k size frames. - # These are maximum frame limits, not the actual ethernet frame - # size. Your actual ethernet frame size would be determined by - # protocol stack configuration (please refer to ndd command man pages) - # For Jumbo Frame Support (9k ethernet packet) - # use 3 (upto 16k size frames) + # + # These are maximum frame limits, not the ethernet payload size + # (usually called MTU). Your actual ethernet MTU is determined by frame + # size limit and protocol stack configuration (please refer to ndd + # command man pages) + # + # For Jumbo Frame Support (9k ethernet packet) use 3 (upto 16k size + # frames). On PCH adapter type (82577 and 82578) you can configure up + # to 4k size frames. The 4k size is only allowed at 1gig speed, so if + # you select 4k frames size, you cannot force or autonegotiate the + # 10/100 speed options. FlowControl=3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3; # 0: Flow control is completely disabled # 1: Rx flow control is enabled (we can receive pause frames
--- a/usr/src/uts/common/io/e1000g/e1000g_debug.c Tue Sep 29 11:19:43 2009 +0800 +++ b/usr/src/uts/common/io/e1000g/e1000g_debug.c Tue Sep 29 12:12:23 2009 +0800 @@ -6,7 +6,7 @@ * * CDDL LICENSE SUMMARY * - * Copyright(c) 1999 - 2008 Intel Corporation. All rights reserved. + * Copyright(c) 1999 - 2009 Intel Corporation. All rights reserved. * * The contents of this file are subject to the terms of Version * 1.0 of the Common Development and Distribution License (the "License"). @@ -19,7 +19,7 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms of the CDDLv1. */ @@ -56,8 +56,9 @@ char name[10]; uint32_t offset; } Regi_t; + int e1000g_debug = E1000G_WARN_LEVEL; -#endif +#endif /* E1000G_DEBUG */ int e1000g_log_mode = E1000G_LOG_PRINT; void @@ -595,4 +596,4 @@ name, base, tag_type, size, tag_mem); } } -#endif +#endif /* E1000G_DEBUG */
--- a/usr/src/uts/common/io/e1000g/e1000g_main.c Tue Sep 29 11:19:43 2009 +0800 +++ b/usr/src/uts/common/io/e1000g/e1000g_main.c Tue Sep 29 12:12:23 2009 +0800 @@ -46,7 +46,7 @@ static char ident[] = "Intel PRO/1000 Ethernet"; static char e1000g_string[] = "Intel(R) PRO/1000 Network Connection"; -static char e1000g_version[] = "Driver Ver. 5.3.14"; +static char e1000g_version[] = "Driver Ver. 5.3.15"; /* * Proto types for DDI entry points @@ -94,6 +94,8 @@ static int e1000g_unicst_set(struct e1000g *, const uint8_t *, int); static int e1000g_alloc_rx_data(struct e1000g *); static void e1000g_release_multicast(struct e1000g *); +static void e1000g_pch_limits(struct e1000g *); +static uint32_t e1000g_mtu2maxframe(uint32_t); /* * Local routines @@ -116,6 +118,7 @@ static void stop_link_timer(struct e1000g *); static void stop_82547_timer(e1000g_tx_ring_t *); static void e1000g_force_speed_duplex(struct e1000g *); +static void e1000g_setup_max_mtu(struct e1000g *); static void e1000g_get_max_frame_size(struct e1000g *); static boolean_t is_valid_mac_addr(uint8_t *); static void e1000g_unattach(dev_info_t *, struct e1000g *); @@ -668,7 +671,8 @@ /* ICH needs to map flash memory */ if (hw->mac.type == e1000_ich8lan || hw->mac.type == e1000_ich9lan || - hw->mac.type == e1000_ich10lan) { + hw->mac.type == e1000_ich10lan || + hw->mac.type == e1000_pchlan) { /* get flash size */ if (ddi_dev_regsize(devinfo, ICH_FLASH_REG_SET, &mem_size) != DDI_SUCCESS) { @@ -766,6 +770,9 @@ Adapter->strip_crc = B_FALSE; #endif + /* setup the maximum MTU size of the chip */ + e1000g_setup_max_mtu(Adapter); + /* Get conf file properties */ e1000g_get_conf(Adapter); @@ -777,6 +784,9 @@ /* Get Jumbo Frames settings in conf file */ e1000g_get_max_frame_size(Adapter); + /* enforce PCH limits */ + e1000g_pch_limits(Adapter); + /* Set Rx/Tx buffer size */ e1000g_set_bufsize(Adapter); @@ -810,6 +820,47 @@ } static void +e1000g_setup_max_mtu(struct e1000g *Adapter) +{ + struct e1000_mac_info *mac = &Adapter->shared.mac; + struct e1000_phy_info *phy = &Adapter->shared.phy; + + switch (mac->type) { + /* types that do not support jumbo frames */ + case e1000_ich8lan: + case e1000_82573: + case e1000_82583: + Adapter->max_mtu = ETHERMTU; + break; + /* ich9 supports jumbo frames except on one phy type */ + case e1000_ich9lan: + if (phy->type == e1000_phy_ife) + Adapter->max_mtu = ETHERMTU; + else + Adapter->max_mtu = MAXIMUM_MTU_9K; + break; + /* pch can do jumbo frames up to 4K */ + case e1000_pchlan: + Adapter->max_mtu = MAXIMUM_MTU_4K; + break; + /* types with a special limit */ + case e1000_82571: + case e1000_82572: + case e1000_82574: + case e1000_80003es2lan: + case e1000_ich10lan: + Adapter->max_mtu = MAXIMUM_MTU_9K; + break; + /* default limit is 16K */ + default: + Adapter->max_mtu = FRAME_SIZE_UPTO_16K - + sizeof (struct ether_vlan_header) - ETHERFCSL - + E1000G_IPALIGNPRESERVEROOM; + break; + } +} + +static void e1000g_set_bufsize(struct e1000g *Adapter) { struct e1000_mac_info *mac = &Adapter->shared.mac; @@ -1099,6 +1150,9 @@ mutex_destroy(&Adapter->link_lock); mutex_destroy(&Adapter->watchdog_lock); rw_destroy(&Adapter->chip_lock); + + /* destory mutex initialized in shared code */ + e1000_destroy_hw_mutex(&Adapter->shared); } static int @@ -1280,6 +1334,8 @@ pba = E1000_PBA_10K; } else if (hw->mac.type == e1000_ich10lan) { pba = E1000_PBA_10K; + } else if (hw->mac.type == e1000_pchlan) { + pba = E1000_PBA_26K; } else { /* * Total FIFO is 40K @@ -1378,7 +1434,8 @@ * Setup and initialize the mctable structures. After this routine * completes Multicast table will be set */ - e1000g_setup_multicast(Adapter); + e1000_update_mc_addr_list(hw, + (uint8_t *)Adapter->mcast_table, Adapter->mcast_count); msec_delay(5); /* @@ -1408,11 +1465,6 @@ } mutex_exit(&Adapter->link_lock); - /* Enable PCI-Ex master */ - if (hw->bus.type == e1000_bus_type_pci_express) { - e1000_enable_pciex_master(hw); - } - /* Save the state of the phy */ e1000g_get_phy_state(Adapter); @@ -1497,20 +1549,33 @@ static boolean_t e1000g_link_up(struct e1000g *Adapter) { - struct e1000_hw *hw; - boolean_t link_up; - - hw = &Adapter->shared; - - (void) e1000_check_for_link(hw); - - if ((E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU) || - ((!hw->mac.get_link_status) && (hw->mac.type == e1000_82543)) || - ((hw->phy.media_type == e1000_media_type_internal_serdes) && - (hw->mac.serdes_has_link))) { - link_up = B_TRUE; - } else { - link_up = B_FALSE; + struct e1000_hw *hw = &Adapter->shared; + boolean_t link_up = B_FALSE; + + /* + * get_link_status is set in the interrupt handler on link-status-change + * or rx sequence error interrupt. get_link_status will stay + * false until the e1000_check_for_link establishes link only + * for copper adapters. + */ + switch (hw->phy.media_type) { + case e1000_media_type_copper: + if (hw->mac.get_link_status) { + (void) e1000_check_for_link(hw); + link_up = !hw->mac.get_link_status; + } else { + link_up = B_TRUE; + } + break; + case e1000_media_type_fiber: + (void) e1000_check_for_link(hw); + link_up = (E1000_READ_REG(hw, E1000_STATUS) & + E1000_STATUS_LU); + break; + case e1000_media_type_internal_serdes: + (void) e1000_check_for_link(hw); + link_up = hw->mac.serdes_has_link; + break; } return (link_up); @@ -2403,11 +2468,8 @@ */ e1000g_clear_interrupt(Adapter); - e1000g_setup_multicast(Adapter); - - if ((hw->mac.type == e1000_82542) && - (hw->revision_id == E1000_REVISION_2)) - e1000g_rx_setup(Adapter); + e1000_update_mc_addr_list(hw, + (uint8_t *)Adapter->mcast_table, Adapter->mcast_count); e1000g_mask_interrupt(Adapter); @@ -2463,11 +2525,8 @@ */ e1000g_clear_interrupt(Adapter); - e1000g_setup_multicast(Adapter); - - if ((hw->mac.type == e1000_82542) && - (hw->revision_id == E1000_REVISION_2)) - e1000g_rx_setup(Adapter); + e1000_update_mc_addr_list(hw, + (uint8_t *)Adapter->mcast_table, Adapter->mcast_count); e1000g_mask_interrupt(Adapter); @@ -2489,98 +2548,6 @@ } } -/* - * e1000g_setup_multicast - setup multicast data structures - * - * This routine initializes all of the multicast related structures. - */ -void -e1000g_setup_multicast(struct e1000g *Adapter) -{ - uint8_t *mc_addr_list; - uint32_t mc_addr_count; - uint32_t rctl; - struct e1000_hw *hw; - - hw = &Adapter->shared; - - /* - * The e1000g has the ability to do perfect filtering of 16 - * addresses. The driver uses one of the e1000g's 16 receive - * address registers for its node/network/mac/individual address. - * So, we have room for up to 15 multicast addresses in the CAM, - * additional MC addresses are handled by the MTA (Multicast Table - * Array) - */ - - rctl = E1000_READ_REG(hw, E1000_RCTL); - - mc_addr_list = (uint8_t *)Adapter->mcast_table; - - ASSERT(Adapter->mcast_count <= Adapter->mcast_max_num); - - mc_addr_count = Adapter->mcast_count; - /* - * The Wiseman 2.0 silicon has an errata by which the receiver will - * hang while writing to the receive address registers if the receiver - * is not in reset before writing to the registers. Updating the RAR - * is done during the setting up of the multicast table, hence the - * receiver has to be put in reset before updating the multicast table - * and then taken out of reset at the end - */ - /* - * if WMI was enabled then dis able it before issueing the global - * reset to the hardware. - */ - /* - * Only required for WISEMAN_2_0 - */ - if ((hw->mac.type == e1000_82542) && - (hw->revision_id == E1000_REVISION_2)) { - e1000_pci_clear_mwi(hw); - /* - * The e1000g must be in reset before changing any RA - * registers. Reset receive unit. The chip will remain in - * the reset state until software explicitly restarts it. - */ - E1000_WRITE_REG(hw, E1000_RCTL, E1000_RCTL_RST); - /* Allow receiver time to go in to reset */ - msec_delay(5); - } - - e1000_update_mc_addr_list(hw, mc_addr_list, mc_addr_count, - Adapter->unicst_total, hw->mac.rar_entry_count); - - /* - * Only for Wiseman_2_0 - * If MWI was enabled then re-enable it after issueing (as we - * disabled it up there) the receive reset command. - * Wainwright does not have a receive reset command and only thing - * close to it is global reset which will require tx setup also - */ - if ((hw->mac.type == e1000_82542) && - (hw->revision_id == E1000_REVISION_2)) { - /* - * if WMI was enabled then reenable it after issueing the - * global or receive reset to the hardware. - */ - - /* - * Take receiver out of reset - * clear E1000_RCTL_RST bit (and all others) - */ - E1000_WRITE_REG(hw, E1000_RCTL, 0); - msec_delay(5); - if (hw->bus.pci_cmd_word & CMD_MEM_WRT_INVALIDATE) - e1000_pci_set_mwi(hw); - } - - /* - * Restore original value - */ - E1000_WRITE_REG(hw, E1000_RCTL, rctl); -} - int e1000g_m_multicst(void *arg, boolean_t add, const uint8_t *addr) { @@ -2995,14 +2962,11 @@ uint_t pr_valsize, const void *pr_val) { struct e1000g *Adapter = arg; - struct e1000_mac_info *mac = &Adapter->shared.mac; - struct e1000_phy_info *phy = &Adapter->shared.phy; struct e1000_hw *hw = &Adapter->shared; struct e1000_fc_info *fc = &Adapter->shared.fc; int err = 0; link_flowctrl_t flowctrl; uint32_t cur_mtu, new_mtu; - uint64_t tmp = 0; rw_enter(&Adapter->chip_lock, RW_WRITER); @@ -3092,6 +3056,8 @@ } reset: if (err == 0) { + /* check PCH limits & reset the link */ + e1000g_pch_limits(Adapter); if (e1000g_reset_link(Adapter) != DDI_SUCCESS) err = EINVAL; } @@ -3109,43 +3075,40 @@ err = ENOTSUP; /* read-only prop. Can't set this. */ break; case MAC_PROP_MTU: + /* adapter must be stopped for an MTU change */ + if (Adapter->e1000g_state & E1000G_STARTED) { + err = EBUSY; + break; + } + cur_mtu = Adapter->default_mtu; + + /* get new requested MTU */ bcopy(pr_val, &new_mtu, sizeof (new_mtu)); if (new_mtu == cur_mtu) { err = 0; break; } - tmp = new_mtu + sizeof (struct ether_vlan_header) + - ETHERFCSL; - if ((tmp < DEFAULT_FRAME_SIZE) || - (tmp > MAXIMUM_FRAME_SIZE)) { - err = EINVAL; - break; - } - - /* ich8 does not support jumbo frames */ - if ((mac->type == e1000_ich8lan) && - (tmp > DEFAULT_FRAME_SIZE)) { + if ((new_mtu < DEFAULT_MTU) || + (new_mtu > Adapter->max_mtu)) { err = EINVAL; break; } - /* ich9 does not do jumbo frames on one phy type */ - if ((mac->type == e1000_ich9lan) && - (phy->type == e1000_phy_ife) && - (tmp > DEFAULT_FRAME_SIZE)) { - err = EINVAL; - break; - } - if (Adapter->e1000g_state & E1000G_STARTED) { - err = EBUSY; - break; - } - + + /* inform MAC framework of new MTU */ err = mac_maxsdu_update(Adapter->mh, new_mtu); + if (err == 0) { - Adapter->max_frame_size = (uint32_t)tmp; Adapter->default_mtu = new_mtu; + Adapter->max_frame_size = + e1000g_mtu2maxframe(new_mtu); + + /* + * check PCH limits & set buffer sizes to + * match new MTU + */ + e1000g_pch_limits(Adapter); e1000g_set_bufsize(Adapter); } break; @@ -3299,7 +3262,7 @@ range.mpr_count = 1; range.mpr_type = MAC_PROPVAL_UINT32; range.range_uint32[0].mpur_min = DEFAULT_MTU; - range.range_uint32[0].mpur_max = MAXIMUM_MTU; + range.range_uint32[0].mpur_max = Adapter->max_mtu; /* following MAC type do not support jumbo frames */ if ((mac->type == e1000_ich8lan) || ((mac->type == e1000_ich9lan) && (phy->type == @@ -4016,12 +3979,10 @@ if (invalid) { e1000g_log(Adapter, CE_WARN, - "Invalid link sets. Setup link to" + "Invalid link settings. Setup link to " "support autonegotiation with all link capabilities."); mac->autoneg = B_TRUE; - phy->autoneg_advertised = ADVERTISE_1000_FULL | - ADVERTISE_100_FULL | ADVERTISE_100_HALF | - ADVERTISE_10_FULL | ADVERTISE_10_HALF; + phy->autoneg_advertised = AUTONEG_ADVERTISE_SPEED_DEFAULT; } out: @@ -4259,8 +4220,6 @@ e1000g_get_max_frame_size(struct e1000g *Adapter) { int max_frame; - struct e1000_mac_info *mac = &Adapter->shared.mac; - struct e1000_phy_info *phy = &Adapter->shared.phy; /* * get value out of config file @@ -4286,35 +4245,68 @@ E1000G_IPALIGNPRESERVEROOM; break; case 3: - if (mac->type >= e1000_82571) - Adapter->default_mtu = MAXIMUM_MTU; - else - Adapter->default_mtu = FRAME_SIZE_UPTO_16K - - sizeof (struct ether_vlan_header) - ETHERFCSL - - E1000G_IPALIGNPRESERVEROOM; + Adapter->default_mtu = FRAME_SIZE_UPTO_16K - + sizeof (struct ether_vlan_header) - ETHERFCSL - + E1000G_IPALIGNPRESERVEROOM; break; default: Adapter->default_mtu = ETHERMTU; break; } /* switch */ - Adapter->max_frame_size = Adapter->default_mtu + - sizeof (struct ether_vlan_header) + ETHERFCSL; - - /* ich8 does not do jumbo frames */ - if (mac->type == e1000_ich8lan) { - Adapter->default_mtu = ETHERMTU; - Adapter->max_frame_size = ETHERMTU + - sizeof (struct ether_vlan_header) + ETHERFCSL; - } - - /* ich9 does not do jumbo frames on one phy type */ - if ((mac->type == e1000_ich9lan) && - (phy->type == e1000_phy_ife)) { - Adapter->default_mtu = ETHERMTU; - Adapter->max_frame_size = ETHERMTU + - sizeof (struct ether_vlan_header) + ETHERFCSL; - } + /* + * If the user configed MTU is larger than the deivce's maximum MTU, + * the MTU is set to the deivce's maximum value. + */ + if (Adapter->default_mtu > Adapter->max_mtu) + Adapter->default_mtu = Adapter->max_mtu; + + Adapter->max_frame_size = e1000g_mtu2maxframe(Adapter->default_mtu); +} + +/* + * e1000g_pch_limits - Apply limits of the PCH silicon type + * + * At any frame size larger than the ethernet default, + * prevent linking at 10/100 speeds. + */ +static void +e1000g_pch_limits(struct e1000g *Adapter) +{ + struct e1000_hw *hw = &Adapter->shared; + + /* only applies to PCH silicon type */ + if (hw->mac.type != e1000_pchlan) + return; + + /* only applies to frames larger than ethernet default */ + if (Adapter->max_frame_size > DEFAULT_FRAME_SIZE) { + hw->mac.autoneg = B_TRUE; + hw->phy.autoneg_advertised = ADVERTISE_1000_FULL; + + Adapter->param_adv_autoneg = 1; + Adapter->param_adv_1000fdx = 1; + + Adapter->param_adv_100fdx = 0; + Adapter->param_adv_100hdx = 0; + Adapter->param_adv_10fdx = 0; + Adapter->param_adv_10hdx = 0; + + e1000g_param_sync(Adapter); + } +} + +/* + * e1000g_mtu2maxframe - convert given MTU to maximum frame size + */ +static uint32_t +e1000g_mtu2maxframe(uint32_t mtu) +{ + uint32_t maxframe; + + maxframe = mtu + sizeof (struct ether_vlan_header) + ETHERFCSL; + + return (maxframe); } static void @@ -5290,10 +5282,10 @@ ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT); ctrl_ext |= (E1000_CTRL_EXT_SDP4_DATA | E1000_CTRL_EXT_SDP6_DATA | - E1000_CTRL_EXT_SDP7_DATA | + E1000_CTRL_EXT_SDP3_DATA | E1000_CTRL_EXT_SDP4_DIR | E1000_CTRL_EXT_SDP6_DIR | - E1000_CTRL_EXT_SDP7_DIR); /* 0x0DD0 */ + E1000_CTRL_EXT_SDP3_DIR); /* 0x0DD0 */ E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext); /* @@ -6204,6 +6196,7 @@ case e1000_ich8lan: case e1000_ich9lan: case e1000_ich10lan: + case e1000_pchlan: ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT); E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext | E1000_CTRL_EXT_DRV_LOAD); @@ -6237,6 +6230,7 @@ case e1000_ich8lan: case e1000_ich9lan: case e1000_ich10lan: + case e1000_pchlan: ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT); E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext & ~E1000_CTRL_EXT_DRV_LOAD);
--- a/usr/src/uts/common/io/e1000g/e1000g_rx.c Tue Sep 29 11:19:43 2009 +0800 +++ b/usr/src/uts/common/io/e1000g/e1000g_rx.c Tue Sep 29 12:12:23 2009 +0800 @@ -149,6 +149,7 @@ uint32_t rctl; uint32_t rxdctl; uint32_t ert; + uint16_t phy_data; int i; int size; e1000g_rx_data_t *rx_data; @@ -320,6 +321,25 @@ E1000_WRITE_REG(hw, E1000_ERT, ert); } + /* Workaround errata on 82577/8 adapters with large frames */ + if ((hw->mac.type == e1000_pchlan) && + (Adapter->default_mtu > ETHERMTU)) { + + e1000_read_phy_reg(hw, PHY_REG(770, 26), &phy_data); + phy_data &= 0xfff8; + phy_data |= (1 << 2); + e1000_write_phy_reg(hw, PHY_REG(770, 26), phy_data); + + if (hw->phy.type == e1000_phy_82577) { + e1000_read_phy_reg(hw, 22, &phy_data); + phy_data &= 0x0fff; + phy_data |= (1 << 14); + e1000_write_phy_reg(hw, 0x10, 0x2823); + e1000_write_phy_reg(hw, 0x11, 0x0003); + e1000_write_phy_reg(hw, 22, phy_data); + } + } + reg_val = E1000_RXCSUM_TUOFL | /* TCP/UDP checksum offload Enable */ E1000_RXCSUM_IPOFL; /* IP checksum offload Enable */
--- a/usr/src/uts/common/io/e1000g/e1000g_stat.c Tue Sep 29 11:19:43 2009 +0800 +++ b/usr/src/uts/common/io/e1000g/e1000g_stat.c Tue Sep 29 12:12:23 2009 +0800 @@ -36,6 +36,7 @@ #include "e1000g_debug.h" static int e1000g_update_stats(kstat_t *ksp, int rw); +static uint32_t e1000g_read_phy_stat(struct e1000_hw *hw, int reg); /* * e1000_tbi_adjust_stats @@ -217,7 +218,8 @@ if ((hw->mac.type != e1000_ich8lan) && (hw->mac.type != e1000_ich9lan) && - (hw->mac.type != e1000_ich10lan)) { + (hw->mac.type != e1000_ich10lan) && + (hw->mac.type != e1000_pchlan)) { e1000g_ksp->Symerrs.value.ul += E1000_READ_REG(hw, E1000_SYMERRS); #ifdef E1000G_DEBUG @@ -256,7 +258,7 @@ e1000g_ksp->Roc.value.ul += E1000_READ_REG(hw, E1000_ROC); e1000g_ksp->Rjc.value.ul += E1000_READ_REG(hw, E1000_RJC); e1000g_ksp->Tpr.value.ul += E1000_READ_REG(hw, E1000_TPR); - e1000g_ksp->Tncrs.value.ul += E1000_READ_REG(hw, E1000_TNCRS); + e1000g_ksp->Tncrs.value.ul += e1000g_read_phy_stat(hw, E1000_TNCRS); e1000g_ksp->Tsctc.value.ul += E1000_READ_REG(hw, E1000_TSCTC); e1000g_ksp->Tsctfc.value.ul += E1000_READ_REG(hw, E1000_TSCTFC); @@ -387,13 +389,13 @@ case MAC_STAT_OERRORS: e1000g_ksp->Ecol.value.ul += - E1000_READ_REG(hw, E1000_ECOL); + e1000g_read_phy_stat(hw, E1000_ECOL); *val = e1000g_ksp->Ecol.value.ul; break; case MAC_STAT_COLLISIONS: e1000g_ksp->Colc.value.ul += - E1000_READ_REG(hw, E1000_COLC); + e1000g_read_phy_stat(hw, E1000_COLC); *val = e1000g_ksp->Colc.value.ul; break; @@ -467,31 +469,31 @@ case ETHER_STAT_EX_COLLISIONS: e1000g_ksp->Ecol.value.ul += - E1000_READ_REG(hw, E1000_ECOL); + e1000g_read_phy_stat(hw, E1000_ECOL); *val = e1000g_ksp->Ecol.value.ul; break; case ETHER_STAT_TX_LATE_COLLISIONS: e1000g_ksp->Latecol.value.ul += - E1000_READ_REG(hw, E1000_LATECOL); + e1000g_read_phy_stat(hw, E1000_LATECOL); *val = e1000g_ksp->Latecol.value.ul; break; case ETHER_STAT_DEFER_XMTS: e1000g_ksp->Dc.value.ul += - E1000_READ_REG(hw, E1000_DC); + e1000g_read_phy_stat(hw, E1000_DC); *val = e1000g_ksp->Dc.value.ul; break; case ETHER_STAT_FIRST_COLLISIONS: e1000g_ksp->Scc.value.ul += - E1000_READ_REG(hw, E1000_SCC); + e1000g_read_phy_stat(hw, E1000_SCC); *val = e1000g_ksp->Scc.value.ul; break; case ETHER_STAT_MULTI_COLLISIONS: e1000g_ksp->Mcc.value.ul += - E1000_READ_REG(hw, E1000_MCC); + e1000g_read_phy_stat(hw, E1000_MCC); *val = e1000g_ksp->Mcc.value.ul; break; @@ -503,7 +505,7 @@ case ETHER_STAT_MACXMT_ERRORS: e1000g_ksp->Ecol.value.ul += - E1000_READ_REG(hw, E1000_ECOL); + e1000g_read_phy_stat(hw, E1000_ECOL); *val = e1000g_ksp->Ecol.value.ul; break; @@ -885,3 +887,79 @@ return (DDI_SUCCESS); } + +/* + * e1000g_read_phy_stat - read certain PHY statistics + * + * Certain statistics are read from MAC registers on some silicon types + * but are read from the PHY on other silicon types. This routine + * handles that difference as needed. + */ +static uint32_t +e1000g_read_phy_stat(struct e1000_hw *hw, int reg) +{ + uint16_t phy_low, phy_high; + uint32_t val; + + /* get statistic from PHY in these cases */ + if ((hw->phy.type == e1000_phy_82578) || + (hw->phy.type == e1000_phy_82577)) { + + switch (reg) { + case E1000_SCC: + (void) e1000_read_phy_reg(hw, HV_SCC_UPPER, &phy_high); + (void) e1000_read_phy_reg(hw, HV_SCC_LOWER, &phy_low); + val = ((uint32_t)phy_high << 16) | (uint32_t)phy_low; + break; + + case E1000_MCC: + (void) e1000_read_phy_reg(hw, HV_MCC_UPPER, &phy_high); + (void) e1000_read_phy_reg(hw, HV_MCC_LOWER, &phy_low); + val = ((uint32_t)phy_high << 16) | (uint32_t)phy_low; + break; + + case E1000_ECOL: + (void) e1000_read_phy_reg(hw, HV_ECOL_UPPER, &phy_high); + (void) e1000_read_phy_reg(hw, HV_ECOL_LOWER, &phy_low); + val = ((uint32_t)phy_high << 16) | (uint32_t)phy_low; + break; + + case E1000_COLC: + (void) e1000_read_phy_reg(hw, HV_COLC_UPPER, &phy_high); + (void) e1000_read_phy_reg(hw, HV_COLC_LOWER, &phy_low); + val = ((uint32_t)phy_high << 16) | (uint32_t)phy_low; + break; + + case E1000_LATECOL: + (void) e1000_read_phy_reg(hw, HV_LATECOL_UPPER, + &phy_high); + (void) e1000_read_phy_reg(hw, HV_LATECOL_LOWER, + &phy_low); + val = ((uint32_t)phy_high << 16) | (uint32_t)phy_low; + break; + + case E1000_DC: + (void) e1000_read_phy_reg(hw, HV_DC_UPPER, &phy_high); + (void) e1000_read_phy_reg(hw, HV_DC_LOWER, &phy_low); + val = ((uint32_t)phy_high << 16) | (uint32_t)phy_low; + break; + + case E1000_TNCRS: + (void) e1000_read_phy_reg(hw, HV_TNCRS_UPPER, + &phy_high); + (void) e1000_read_phy_reg(hw, HV_TNCRS_LOWER, + &phy_low); + val = ((uint32_t)phy_high << 16) | (uint32_t)phy_low; + break; + + default: + break; + } + + /* get statistic from MAC otherwise */ + } else { + val = E1000_READ_REG(hw, reg); + } + + return (val); +}
--- a/usr/src/uts/common/io/e1000g/e1000g_sw.h Tue Sep 29 11:19:43 2009 +0800 +++ b/usr/src/uts/common/io/e1000g/e1000g_sw.h Tue Sep 29 12:12:23 2009 +0800 @@ -102,7 +102,6 @@ /* * constants used in setting flow control thresholds */ -#define E1000_PBA_10K 0x000A #define E1000_PBA_MASK 0xffff #define E1000_PBA_SHIFT 10 #define E1000_FC_HIGH_DIFF 0x1638 /* High: 5688 bytes below Rx FIFO size */ @@ -266,8 +265,9 @@ #define FRAME_SIZE_UPTO_16K 16384 #define FRAME_SIZE_UPTO_9K 9234 -#define MAXIMUM_MTU 9216 #define DEFAULT_MTU ETHERMTU +#define MAXIMUM_MTU_4K 4096 +#define MAXIMUM_MTU_9K 9216 #define DEFAULT_FRAME_SIZE \ (DEFAULT_MTU + sizeof (struct ether_vlan_header) + ETHERFCSL) @@ -878,6 +878,7 @@ uint32_t intr_throttling_rate; uint32_t default_mtu; + uint32_t max_mtu; uint32_t max_frame_size; uint32_t min_frame_size; @@ -1018,7 +1019,6 @@ void e1000g_free_rx_sw_packet(p_rx_sw_packet_t packet, boolean_t full_release); void e1000g_tx_setup(struct e1000g *Adapter); void e1000g_rx_setup(struct e1000g *Adapter); -void e1000g_setup_multicast(struct e1000g *Adapter); int e1000g_recycle(e1000g_tx_ring_t *tx_ring); void e1000g_free_tx_swpkt(p_tx_sw_packet_t packet); @@ -1039,6 +1039,7 @@ void e1000g_clear_tx_interrupt(struct e1000g *Adapter); void e1000g_mask_tx_interrupt(struct e1000g *Adapter); void phy_spd_state(struct e1000_hw *hw, boolean_t enable); +void e1000_destroy_hw_mutex(struct e1000_hw *hw); void e1000_enable_pciex_master(struct e1000_hw *hw); int e1000g_check_acc_handle(ddi_acc_handle_t handle); int e1000g_check_dma_handle(ddi_dma_handle_t handle);