Author: marius Date: Thu Aug 31 23:59:46 2017 New Revision: 323080 URL: https://svnweb.freebsd.org/changeset/base/323080
Log: MFC: r308643, r312427, r312641, r322986 - Update WOL support for newer em(4) devices. [1] - Add support for Kaby Lake generation i219 (4) and i219 (5) devices. - Enable WOL features also for the igb(4) class of devices. [1] - Don't set any WOL enabling hardware bits if WOL isn't requested according to the enabled interface capability bits. PR: 208343 [1] Submitted by: Kaho Tashikazu <k...@elam.kais.kyoto-u.ac.jp> [1] Approved by: re (kib) Modified: stable/10/sys/dev/e1000/e1000_82575.c stable/10/sys/dev/e1000/e1000_82575.h stable/10/sys/dev/e1000/e1000_defines.h stable/10/sys/dev/e1000/e1000_ich8lan.c stable/10/sys/dev/e1000/if_em.c stable/10/sys/dev/e1000/if_igb.c Directory Properties: stable/10/ (props changed) Modified: stable/10/sys/dev/e1000/e1000_82575.c ============================================================================== --- stable/10/sys/dev/e1000/e1000_82575.c Thu Aug 31 23:57:34 2017 (r323079) +++ stable/10/sys/dev/e1000/e1000_82575.c Thu Aug 31 23:59:46 2017 (r323080) @@ -101,7 +101,6 @@ static s32 e1000_validate_nvm_checksum_with_offset(str u16 offset); static s32 e1000_validate_nvm_checksum_i350(struct e1000_hw *hw); static s32 e1000_update_nvm_checksum_i350(struct e1000_hw *hw); -static void e1000_write_vfta_i350(struct e1000_hw *hw, u32 offset, u32 value); static void e1000_clear_vfta_i350(struct e1000_hw *hw); static void e1000_i2c_start(struct e1000_hw *hw); Modified: stable/10/sys/dev/e1000/e1000_82575.h ============================================================================== --- stable/10/sys/dev/e1000/e1000_82575.h Thu Aug 31 23:57:34 2017 (r323079) +++ stable/10/sys/dev/e1000/e1000_82575.h Thu Aug 31 23:59:46 2017 (r323080) @@ -493,6 +493,7 @@ enum e1000_promisc_type { void e1000_vfta_set_vf(struct e1000_hw *, u16, bool); void e1000_rlpml_set_vf(struct e1000_hw *, u16); s32 e1000_promisc_set_vf(struct e1000_hw *, enum e1000_promisc_type type); +void e1000_write_vfta_i350(struct e1000_hw *hw, u32 offset, u32 value); u16 e1000_rxpbs_adjust_82580(u32 data); s32 e1000_read_emi_reg(struct e1000_hw *hw, u16 addr, u16 *data); s32 e1000_set_eee_i350(struct e1000_hw *hw, bool adv1G, bool adv100M); Modified: stable/10/sys/dev/e1000/e1000_defines.h ============================================================================== --- stable/10/sys/dev/e1000/e1000_defines.h Thu Aug 31 23:57:34 2017 (r323079) +++ stable/10/sys/dev/e1000/e1000_defines.h Thu Aug 31 23:59:46 2017 (r323080) @@ -469,6 +469,8 @@ #define ETHERNET_FCS_SIZE 4 #define MAX_JUMBO_FRAME_SIZE 0x3F00 +/* The datasheet maximum supported RX size is 9.5KB (9728 bytes) */ +#define MAX_RX_JUMBO_FRAME_SIZE 0x2600 #define E1000_TX_PTR_GAP 0x1F /* Extended Configuration Control and Size */ Modified: stable/10/sys/dev/e1000/e1000_ich8lan.c ============================================================================== --- stable/10/sys/dev/e1000/e1000_ich8lan.c Thu Aug 31 23:57:34 2017 (r323079) +++ stable/10/sys/dev/e1000/e1000_ich8lan.c Thu Aug 31 23:59:46 2017 (r323080) @@ -243,8 +243,7 @@ static bool e1000_phy_is_accessible_pchlan(struct e100 if (ret_val) return FALSE; out: - if ((hw->mac.type == e1000_pch_lpt) || - (hw->mac.type == e1000_pch_spt)) { + if (hw->mac.type >= e1000_pch_lpt) { /* Only unforce SMBus if ME is not active */ if (!(E1000_READ_REG(hw, E1000_FWSM) & E1000_ICH_FWSM_FW_VALID)) { @@ -641,7 +640,7 @@ static s32 e1000_init_nvm_params_ich8lan(struct e1000_ nvm->type = e1000_nvm_flash_sw; - if (hw->mac.type == e1000_pch_spt) { + if (hw->mac.type >= e1000_pch_spt) { /* in SPT, gfpreg doesn't exist. NVM size is taken from the * STRAP register. This is because in SPT the GbE Flash region * is no longer accessed through the flash registers. Instead, @@ -701,7 +700,7 @@ static s32 e1000_init_nvm_params_ich8lan(struct e1000_ /* Function Pointers */ nvm->ops.acquire = e1000_acquire_nvm_ich8lan; nvm->ops.release = e1000_release_nvm_ich8lan; - if (hw->mac.type == e1000_pch_spt) { + if (hw->mac.type >= e1000_pch_spt) { nvm->ops.read = e1000_read_nvm_spt; nvm->ops.update = e1000_update_nvm_checksum_spt; } else { @@ -815,8 +814,7 @@ static s32 e1000_init_mac_params_ich8lan(struct e1000_ break; } - if ((mac->type == e1000_pch_lpt) || - (mac->type == e1000_pch_spt)) { + if (mac->type >= e1000_pch_lpt) { mac->rar_entry_count = E1000_PCH_LPT_RAR_ENTRIES; mac->ops.rar_set = e1000_rar_set_pch_lpt; mac->ops.setup_physical_interface = e1000_setup_copper_link_pch_lpt; @@ -1576,9 +1574,7 @@ static s32 e1000_check_for_copper_link_ich8lan(struct * aggressive resulting in many collisions. To avoid this, increase * the IPG and reduce Rx latency in the PHY. */ - if (((hw->mac.type == e1000_pch2lan) || - (hw->mac.type == e1000_pch_lpt) || - (hw->mac.type == e1000_pch_spt)) && link) { + if ((hw->mac.type >= e1000_pch2lan) && link) { u16 speed, duplex; e1000_get_speed_and_duplex_copper_generic(hw, &speed, &duplex); @@ -1589,7 +1585,7 @@ static s32 e1000_check_for_copper_link_ich8lan(struct tipg_reg |= 0xFF; /* Reduce Rx latency in analog PHY */ emi_val = 0; - } else if (hw->mac.type == e1000_pch_spt && + } else if (hw->mac.type >= e1000_pch_spt && duplex == FULL_DUPLEX && speed != SPEED_1000) { tipg_reg |= 0xC; emi_val = 1; @@ -1611,8 +1607,8 @@ static s32 e1000_check_for_copper_link_ich8lan(struct emi_addr = I217_RX_CONFIG; ret_val = e1000_write_emi_reg_locked(hw, emi_addr, emi_val); - if (hw->mac.type == e1000_pch_lpt || - hw->mac.type == e1000_pch_spt) { + + if (hw->mac.type >= e1000_pch_lpt) { u16 phy_reg; hw->phy.ops.read_reg_locked(hw, I217_PLL_CLOCK_GATE_REG, @@ -1641,7 +1637,7 @@ static s32 e1000_check_for_copper_link_ich8lan(struct if (ret_val) return ret_val; - if (hw->mac.type == e1000_pch_spt) { + if (hw->mac.type >= e1000_pch_spt) { u16 data; u16 ptr_gap; @@ -1690,8 +1686,7 @@ static s32 e1000_check_for_copper_link_ich8lan(struct * on power up. * Set the Beacon Duration for I217 to 8 usec */ - if ((hw->mac.type == e1000_pch_lpt) || - (hw->mac.type == e1000_pch_spt)) { + if (hw->mac.type >= e1000_pch_lpt) { u32 mac_reg; mac_reg = E1000_READ_REG(hw, E1000_FEXTNVM4); @@ -1709,8 +1704,7 @@ static s32 e1000_check_for_copper_link_ich8lan(struct if (ret_val) return ret_val; } - if ((hw->mac.type == e1000_pch_lpt) || - (hw->mac.type == e1000_pch_spt)) { + if (hw->mac.type >= e1000_pch_lpt) { /* Set platform power management values for * Latency Tolerance Reporting (LTR) * Optimized Buffer Flush/Fill (OBFF) @@ -1723,15 +1717,20 @@ static s32 e1000_check_for_copper_link_ich8lan(struct /* Clear link partner's EEE ability */ hw->dev_spec.ich8lan.eee_lp_ability = 0; - /* FEXTNVM6 K1-off workaround */ - if (hw->mac.type == e1000_pch_spt) { - u32 pcieanacfg = E1000_READ_REG(hw, E1000_PCIEANACFG); + if (hw->mac.type >= e1000_pch_lpt) { u32 fextnvm6 = E1000_READ_REG(hw, E1000_FEXTNVM6); - if ((pcieanacfg & E1000_FEXTNVM6_K1_OFF_ENABLE) && - (hw->dev_spec.ich8lan.disable_k1_off == FALSE)) - fextnvm6 |= E1000_FEXTNVM6_K1_OFF_ENABLE; - else + if (hw->mac.type == e1000_pch_spt) { + /* FEXTNVM6 K1-off workaround - for SPT only */ + u32 pcieanacfg = E1000_READ_REG(hw, E1000_PCIEANACFG); + + if (pcieanacfg & E1000_FEXTNVM6_K1_OFF_ENABLE) + fextnvm6 |= E1000_FEXTNVM6_K1_OFF_ENABLE; + else + fextnvm6 &= ~E1000_FEXTNVM6_K1_OFF_ENABLE; + } + + if (hw->dev_spec.ich8lan.disable_k1_off == TRUE) fextnvm6 &= ~E1000_FEXTNVM6_K1_OFF_ENABLE; E1000_WRITE_REG(hw, E1000_FEXTNVM6, fextnvm6); @@ -3671,7 +3670,7 @@ static s32 e1000_flash_cycle_init_ich8lan(struct e1000 /* Clear FCERR and DAEL in hw status by writing 1 */ hsfsts.hsf_status.flcerr = 1; hsfsts.hsf_status.dael = 1; - if (hw->mac.type == e1000_pch_spt) + if (hw->mac.type >= e1000_pch_spt) E1000_WRITE_FLASH_REG(hw, ICH_FLASH_HSFSTS, hsfsts.regval & 0xFFFF); else @@ -3691,7 +3690,7 @@ static s32 e1000_flash_cycle_init_ich8lan(struct e1000 * Begin by setting Flash Cycle Done. */ hsfsts.hsf_status.flcdone = 1; - if (hw->mac.type == e1000_pch_spt) + if (hw->mac.type >= e1000_pch_spt) E1000_WRITE_FLASH_REG(hw, ICH_FLASH_HSFSTS, hsfsts.regval & 0xFFFF); else @@ -3718,7 +3717,7 @@ static s32 e1000_flash_cycle_init_ich8lan(struct e1000 * now set the Flash Cycle Done. */ hsfsts.hsf_status.flcdone = 1; - if (hw->mac.type == e1000_pch_spt) + if (hw->mac.type >= e1000_pch_spt) E1000_WRITE_FLASH_REG(hw, ICH_FLASH_HSFSTS, hsfsts.regval & 0xFFFF); else @@ -3748,13 +3747,13 @@ static s32 e1000_flash_cycle_ich8lan(struct e1000_hw * DEBUGFUNC("e1000_flash_cycle_ich8lan"); /* Start a cycle by writing 1 in Flash Cycle Go in Hw Flash Control */ - if (hw->mac.type == e1000_pch_spt) + if (hw->mac.type >= e1000_pch_spt) hsflctl.regval = E1000_READ_FLASH_REG(hw, ICH_FLASH_HSFSTS)>>16; else hsflctl.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFCTL); hsflctl.hsf_ctrl.flcgo = 1; - if (hw->mac.type == e1000_pch_spt) + if (hw->mac.type >= e1000_pch_spt) E1000_WRITE_FLASH_REG(hw, ICH_FLASH_HSFSTS, hsflctl.regval << 16); else @@ -3837,7 +3836,7 @@ static s32 e1000_read_flash_byte_ich8lan(struct e1000_ /* In SPT, only 32 bits access is supported, * so this function should not be called. */ - if (hw->mac.type == e1000_pch_spt) + if (hw->mac.type >= e1000_pch_spt) return -E1000_ERR_NVM; else ret_val = e1000_read_flash_data_ich8lan(hw, offset, 1, &word); @@ -3946,7 +3945,7 @@ static s32 e1000_read_flash_data32_ich8lan(struct e100 DEBUGFUNC("e1000_read_flash_data_ich8lan"); if (offset > ICH_FLASH_LINEAR_ADDR_MASK || - hw->mac.type != e1000_pch_spt) + hw->mac.type < e1000_pch_spt) return -E1000_ERR_NVM; flash_linear_addr = ((ICH_FLASH_LINEAR_ADDR_MASK & offset) + hw->nvm.flash_base_addr); @@ -4434,7 +4433,7 @@ static s32 e1000_write_flash_data_ich8lan(struct e1000 DEBUGFUNC("e1000_write_ich8_data"); - if (hw->mac.type == e1000_pch_spt) { + if (hw->mac.type >= e1000_pch_spt) { if (size != 4 || offset > ICH_FLASH_LINEAR_ADDR_MASK) return -E1000_ERR_NVM; } else { @@ -4454,7 +4453,7 @@ static s32 e1000_write_flash_data_ich8lan(struct e1000 /* In SPT, This register is in Lan memory space, not * flash. Therefore, only 32 bit access is supported */ - if (hw->mac.type == e1000_pch_spt) + if (hw->mac.type >= e1000_pch_spt) hsflctl.regval = E1000_READ_FLASH_REG(hw, ICH_FLASH_HSFSTS)>>16; else @@ -4468,7 +4467,7 @@ static s32 e1000_write_flash_data_ich8lan(struct e1000 * not flash. Therefore, only 32 bit access is * supported */ - if (hw->mac.type == e1000_pch_spt) + if (hw->mac.type >= e1000_pch_spt) E1000_WRITE_FLASH_REG(hw, ICH_FLASH_HSFSTS, hsflctl.regval << 16); else @@ -4530,7 +4529,7 @@ static s32 e1000_write_flash_data32_ich8lan(struct e10 DEBUGFUNC("e1000_write_flash_data32_ich8lan"); - if (hw->mac.type == e1000_pch_spt) { + if (hw->mac.type >= e1000_pch_spt) { if (offset > ICH_FLASH_LINEAR_ADDR_MASK) return -E1000_ERR_NVM; } @@ -4546,7 +4545,7 @@ static s32 e1000_write_flash_data32_ich8lan(struct e10 /* In SPT, This register is in Lan memory space, not * flash. Therefore, only 32 bit access is supported */ - if (hw->mac.type == e1000_pch_spt) + if (hw->mac.type >= e1000_pch_spt) hsflctl.regval = E1000_READ_FLASH_REG(hw, ICH_FLASH_HSFSTS) >> 16; @@ -4561,7 +4560,7 @@ static s32 e1000_write_flash_data32_ich8lan(struct e10 * not flash. Therefore, only 32 bit access is * supported */ - if (hw->mac.type == e1000_pch_spt) + if (hw->mac.type >= e1000_pch_spt) E1000_WRITE_FLASH_REG(hw, ICH_FLASH_HSFSTS, hsflctl.regval << 16); else @@ -4763,7 +4762,7 @@ static s32 e1000_erase_flash_bank_ich8lan(struct e1000 /* Write a value 11 (block Erase) in Flash * Cycle field in hw flash control */ - if (hw->mac.type == e1000_pch_spt) + if (hw->mac.type >= e1000_pch_spt) hsflctl.regval = E1000_READ_FLASH_REG(hw, ICH_FLASH_HSFSTS)>>16; @@ -4773,7 +4772,7 @@ static s32 e1000_erase_flash_bank_ich8lan(struct e1000 ICH_FLASH_HSFCTL); hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_ERASE; - if (hw->mac.type == e1000_pch_spt) + if (hw->mac.type >= e1000_pch_spt) E1000_WRITE_FLASH_REG(hw, ICH_FLASH_HSFSTS, hsflctl.regval << 16); else @@ -5211,8 +5210,7 @@ static void e1000_initialize_hw_bits_ich8lan(struct e1 E1000_WRITE_REG(hw, E1000_RFCTL, reg); /* Enable ECC on Lynxpoint */ - if ((hw->mac.type == e1000_pch_lpt) || - (hw->mac.type == e1000_pch_spt)) { + if (hw->mac.type >= e1000_pch_lpt) { reg = E1000_READ_REG(hw, E1000_PBECCSTS); reg |= E1000_PBECCSTS_ECC_ENABLE; E1000_WRITE_REG(hw, E1000_PBECCSTS, reg); @@ -5645,7 +5643,7 @@ void e1000_suspend_workarounds_ich8lan(struct e1000_hw (device_id == E1000_DEV_ID_PCH_LPTLP_I218_V) || (device_id == E1000_DEV_ID_PCH_I218_LM3) || (device_id == E1000_DEV_ID_PCH_I218_V3) || - (hw->mac.type == e1000_pch_spt)) { + (hw->mac.type >= e1000_pch_spt)) { u32 fextnvm6 = E1000_READ_REG(hw, E1000_FEXTNVM6); E1000_WRITE_REG(hw, E1000_FEXTNVM6, Modified: stable/10/sys/dev/e1000/if_em.c ============================================================================== --- stable/10/sys/dev/e1000/if_em.c Thu Aug 31 23:57:34 2017 (r323079) +++ stable/10/sys/dev/e1000/if_em.c Thu Aug 31 23:59:46 2017 (r323080) @@ -198,6 +198,12 @@ static em_vendor_info_t em_vendor_info_array[] = { 0x8086, E1000_DEV_ID_PCH_SPT_I219_LM5, PCI_ANY_ID, PCI_ANY_ID, 0}, { 0x8086, E1000_DEV_ID_PCH_SPT_I219_V5, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_PCH_SPT_I219_LM4, + PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_PCH_SPT_I219_V4, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_PCH_SPT_I219_LM5, + PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_PCH_SPT_I219_V5, PCI_ANY_ID, PCI_ANY_ID, 0}, /* required last entry */ { 0, 0, 0, 0, 0} }; @@ -5317,6 +5323,8 @@ em_get_wakeup(device_t dev) case e1000_ich10lan: case e1000_pchlan: case e1000_pch2lan: + case e1000_pch_lpt: + case e1000_pch_spt: apme_mask = E1000_WUC_APME; adapter->has_amt = TRUE; eeprom_data = E1000_READ_REG(&adapter->hw, E1000_WUC); @@ -5365,32 +5373,13 @@ em_enable_wakeup(device_t dev) { struct adapter *adapter = device_get_softc(dev); struct ifnet *ifp = adapter->ifp; + int error = 0; u32 pmc, ctrl, ctrl_ext, rctl; u16 status; - if ((pci_find_cap(dev, PCIY_PMG, &pmc) != 0)) + if (pci_find_cap(dev, PCIY_PMG, &pmc) != 0) return; - /* Advertise the wakeup capability */ - ctrl = E1000_READ_REG(&adapter->hw, E1000_CTRL); - ctrl |= (E1000_CTRL_SWDPIN2 | E1000_CTRL_SWDPIN3); - E1000_WRITE_REG(&adapter->hw, E1000_CTRL, ctrl); - E1000_WRITE_REG(&adapter->hw, E1000_WUC, E1000_WUC_PME_EN); - - if ((adapter->hw.mac.type == e1000_ich8lan) || - (adapter->hw.mac.type == e1000_pchlan) || - (adapter->hw.mac.type == e1000_ich9lan) || - (adapter->hw.mac.type == e1000_ich10lan)) - e1000_suspend_workarounds_ich8lan(&adapter->hw); - - /* Keep the laser running on Fiber adapters */ - if (adapter->hw.phy.media_type == e1000_media_type_fiber || - adapter->hw.phy.media_type == e1000_media_type_internal_serdes) { - ctrl_ext = E1000_READ_REG(&adapter->hw, E1000_CTRL_EXT); - ctrl_ext |= E1000_CTRL_EXT_SDP3_DATA; - E1000_WRITE_REG(&adapter->hw, E1000_CTRL_EXT, ctrl_ext); - } - /* ** Determine type of Wakeup: note that wol ** is set with all bits on by default. @@ -5406,11 +5395,37 @@ em_enable_wakeup(device_t dev) E1000_WRITE_REG(&adapter->hw, E1000_RCTL, rctl); } - if ((adapter->hw.mac.type == e1000_pchlan) || - (adapter->hw.mac.type == e1000_pch2lan)) { - if (em_enable_phy_wakeup(adapter)) - return; + if (!(adapter->wol & (E1000_WUFC_EX | E1000_WUFC_MAG | E1000_WUFC_MC))) + goto pme; + + /* Advertise the wakeup capability */ + ctrl = E1000_READ_REG(&adapter->hw, E1000_CTRL); + ctrl |= (E1000_CTRL_SWDPIN2 | E1000_CTRL_SWDPIN3); + E1000_WRITE_REG(&adapter->hw, E1000_CTRL, ctrl); + + /* Keep the laser running on Fiber adapters */ + if (adapter->hw.phy.media_type == e1000_media_type_fiber || + adapter->hw.phy.media_type == e1000_media_type_internal_serdes) { + ctrl_ext = E1000_READ_REG(&adapter->hw, E1000_CTRL_EXT); + ctrl_ext |= E1000_CTRL_EXT_SDP3_DATA; + E1000_WRITE_REG(&adapter->hw, E1000_CTRL_EXT, ctrl_ext); + } + + if ((adapter->hw.mac.type == e1000_ich8lan) || + (adapter->hw.mac.type == e1000_pchlan) || + (adapter->hw.mac.type == e1000_ich9lan) || + (adapter->hw.mac.type == e1000_ich10lan)) + e1000_suspend_workarounds_ich8lan(&adapter->hw); + + if ((adapter->hw.mac.type == e1000_pchlan) || + (adapter->hw.mac.type == e1000_pch2lan) || + (adapter->hw.mac.type == e1000_pch_lpt) || + (adapter->hw.mac.type == e1000_pch_spt)) { + error = em_enable_phy_wakeup(adapter); + if (error) + goto pme; } else { + /* Enable wakeup by the MAC */ E1000_WRITE_REG(&adapter->hw, E1000_WUC, E1000_WUC_PME_EN); E1000_WRITE_REG(&adapter->hw, E1000_WUFC, adapter->wol); } @@ -5418,10 +5433,10 @@ em_enable_wakeup(device_t dev) if (adapter->hw.phy.type == e1000_phy_igp_3) e1000_igp3_phy_powerdown_workaround_ich8lan(&adapter->hw); - /* Request PME */ +pme: status = pci_read_config(dev, pmc + PCIR_POWER_STATUS, 2); status &= ~(PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE); - if (ifp->if_capenable & IFCAP_WOL) + if (!error && (ifp->if_capenable & IFCAP_WOL)) status |= PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE; pci_write_config(dev, pmc + PCIR_POWER_STATUS, status, 2); Modified: stable/10/sys/dev/e1000/if_igb.c ============================================================================== --- stable/10/sys/dev/e1000/if_igb.c Thu Aug 31 23:57:34 2017 (r323079) +++ stable/10/sys/dev/e1000/if_igb.c Thu Aug 31 23:59:46 2017 (r323080) @@ -724,12 +724,6 @@ igb_detach(device_t dev) igb_release_manageability(adapter); igb_release_hw_control(adapter); - if (adapter->wol) { - E1000_WRITE_REG(&adapter->hw, E1000_WUC, E1000_WUC_PME_EN); - E1000_WRITE_REG(&adapter->hw, E1000_WUFC, adapter->wol); - igb_enable_wakeup(dev); - } - /* Unregister VLAN events */ if (adapter->vlan_attach != NULL) EVENTHANDLER_DEREGISTER(vlan_config, adapter->vlan_attach); @@ -781,13 +775,8 @@ igb_suspend(device_t dev) igb_release_manageability(adapter); igb_release_hw_control(adapter); + igb_enable_wakeup(dev); - if (adapter->wol) { - E1000_WRITE_REG(&adapter->hw, E1000_WUC, E1000_WUC_PME_EN); - E1000_WRITE_REG(&adapter->hw, E1000_WUFC, adapter->wol); - igb_enable_wakeup(dev); - } - IGB_CORE_UNLOCK(adapter); return bus_generic_suspend(dev); @@ -1216,6 +1205,14 @@ igb_ioctl(struct ifnet *ifp, u_long command, caddr_t d ifp->if_capenable ^= IFCAP_LRO; reinit = 1; } + if (mask & IFCAP_WOL) { + if (mask & IFCAP_WOL_MAGIC) + ifp->if_capenable ^= IFCAP_WOL_MAGIC; + if (mask & IFCAP_WOL_MCAST) + ifp->if_capenable ^= IFCAP_WOL_MCAST; + if (mask & IFCAP_WOL_UCAST) + ifp->if_capenable ^= IFCAP_WOL_UCAST; + } if (reinit && (ifp->if_drv_flags & IFF_DRV_RUNNING)) igb_init(adapter); VLAN_CAPABILITIES(ifp); @@ -2275,7 +2272,7 @@ igb_stop(void *arg) } e1000_reset_hw(&adapter->hw); - E1000_WRITE_REG(&adapter->hw, E1000_WUC, 0); + E1000_WRITE_REG(&adapter->hw, E1000_WUFC, 0); e1000_led_off(&adapter->hw); e1000_cleanup_led(&adapter->hw); @@ -3031,7 +3028,7 @@ igb_reset(struct adapter *adapter) /* Issue a global reset */ e1000_reset_hw(hw); - E1000_WRITE_REG(hw, E1000_WUC, 0); + E1000_WRITE_REG(hw, E1000_WUFC, 0); /* Reset for AutoMediaDetect */ if (adapter->flags & IGB_MEDIA_RESET) { @@ -3122,6 +3119,13 @@ igb_setup_interface(device_t dev, struct adapter *adap | IFCAP_VLAN_MTU; /* + * Enable only WOL MAGIC by default if WOL is enabled in EEPROM. + */ + ifp->if_capabilities |= IFCAP_WOL; + if (adapter->wol) + ifp->if_capenable |= IFCAP_WOL_MAGIC; + + /* ** Don't turn this on by default, if vlans are ** created on another pseudo device (eg. lagg) ** then vlan events are not passed thru, breaking @@ -5311,22 +5315,61 @@ igb_is_valid_ether_addr(uint8_t *addr) static void igb_enable_wakeup(device_t dev) { - u16 cap, status; - u8 id; + struct adapter *adapter = device_get_softc(dev); + struct ifnet *ifp = adapter->ifp; + u32 pmc, ctrl, ctrl_ext, rctl, wuc; + u16 status; - /* First find the capabilities pointer*/ - cap = pci_read_config(dev, PCIR_CAP_PTR, 2); - /* Read the PM Capabilities */ - id = pci_read_config(dev, cap, 1); - if (id != PCIY_PMG) /* Something wrong */ + if (pci_find_cap(dev, PCIY_PMG, &pmc) != 0) return; - /* OK, we have the power capabilities, so - now get the status register */ - cap += PCIR_POWER_STATUS; - status = pci_read_config(dev, cap, 2); - status |= PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE; - pci_write_config(dev, cap, status, 2); - return; + + adapter->wol = E1000_READ_REG(&adapter->hw, E1000_WUFC); + if (ifp->if_capenable & IFCAP_WOL_MAGIC) + adapter->wol |= E1000_WUFC_MAG; + else + adapter->wol &= ~E1000_WUFC_MAG; + + if (ifp->if_capenable & IFCAP_WOL_MCAST) { + adapter->wol |= E1000_WUFC_MC; + rctl = E1000_READ_REG(&adapter->hw, E1000_RCTL); + rctl |= E1000_RCTL_MPE; + E1000_WRITE_REG(&adapter->hw, E1000_RCTL, rctl); + } else + adapter->wol &= ~E1000_WUFC_MC; + + if (ifp->if_capenable & IFCAP_WOL_UCAST) + adapter->wol |= E1000_WUFC_EX; + else + adapter->wol &= ~E1000_WUFC_EX; + + if (!(adapter->wol & (E1000_WUFC_EX | E1000_WUFC_MAG | E1000_WUFC_MC))) + goto pme; + + /* Advertise the wakeup capability */ + ctrl = E1000_READ_REG(&adapter->hw, E1000_CTRL); + ctrl |= (E1000_CTRL_SWDPIN2 | E1000_CTRL_SWDPIN3); + E1000_WRITE_REG(&adapter->hw, E1000_CTRL, ctrl); + + /* Keep the laser running on Fiber adapters */ + if (adapter->hw.phy.media_type == e1000_media_type_fiber || + adapter->hw.phy.media_type == e1000_media_type_internal_serdes) { + ctrl_ext = E1000_READ_REG(&adapter->hw, E1000_CTRL_EXT); + ctrl_ext |= E1000_CTRL_EXT_SDP3_DATA; + E1000_WRITE_REG(&adapter->hw, E1000_CTRL_EXT, ctrl_ext); + } + + /* Enable wakeup by the MAC */ + wuc = E1000_READ_REG(&adapter->hw, E1000_WUC); + wuc |= E1000_WUC_PME_EN | E1000_WUC_APME; + E1000_WRITE_REG(&adapter->hw, E1000_WUC, wuc); + E1000_WRITE_REG(&adapter->hw, E1000_WUFC, adapter->wol); + +pme: + status = pci_read_config(dev, pmc + PCIR_POWER_STATUS, 2); + status &= ~(PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE); + if (ifp->if_capenable & IFCAP_WOL) + status |= PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE; + pci_write_config(dev, pmc + PCIR_POWER_STATUS, status, 2); } static void _______________________________________________ svn-src-stable-10@freebsd.org mailing list https://lists.freebsd.org/mailman/listinfo/svn-src-stable-10 To unsubscribe, send any mail to "svn-src-stable-10-unsubscr...@freebsd.org"