summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormarius <marius@FreeBSD.org>2017-08-31 23:59:46 +0000
committermarius <marius@FreeBSD.org>2017-08-31 23:59:46 +0000
commit9ff449866a4d982d4e8309dcf9d802685e045b1e (patch)
treec13f1e4634100e30abab59c64a2c9a512d5a94c9
parent276a2c239a551f8c003fc01fbc1a704177dfb609 (diff)
downloadFreeBSD-src-9ff449866a4d982d4e8309dcf9d802685e045b1e.zip
FreeBSD-src-9ff449866a4d982d4e8309dcf9d802685e045b1e.tar.gz
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 <kaho@elam.kais.kyoto-u.ac.jp> [1] Approved by: re (kib)
-rw-r--r--sys/dev/e1000/e1000_82575.c1
-rw-r--r--sys/dev/e1000/e1000_82575.h1
-rw-r--r--sys/dev/e1000/e1000_defines.h2
-rw-r--r--sys/dev/e1000/e1000_ich8lan.c82
-rw-r--r--sys/dev/e1000/if_em.c69
-rw-r--r--sys/dev/e1000/if_igb.c101
6 files changed, 157 insertions, 99 deletions
diff --git a/sys/dev/e1000/e1000_82575.c b/sys/dev/e1000/e1000_82575.c
index 38770a3..abb3019 100644
--- a/sys/dev/e1000/e1000_82575.c
+++ b/sys/dev/e1000/e1000_82575.c
@@ -101,7 +101,6 @@ static s32 e1000_validate_nvm_checksum_with_offset(struct e1000_hw *hw,
u16 offset);
static s32 e1000_validate_nvm_checksum_i350(struct e1000_hw *hw);
static s32 e1000_update_nvm_checksum_i350(struct e1000_hw *hw);
-static void e1000_write_vfta_i350(struct e1000_hw *hw, u32 offset, u32 value);
static void e1000_clear_vfta_i350(struct e1000_hw *hw);
static void e1000_i2c_start(struct e1000_hw *hw);
diff --git a/sys/dev/e1000/e1000_82575.h b/sys/dev/e1000/e1000_82575.h
index 45fe132..f817956 100644
--- a/sys/dev/e1000/e1000_82575.h
+++ b/sys/dev/e1000/e1000_82575.h
@@ -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);
diff --git a/sys/dev/e1000/e1000_defines.h b/sys/dev/e1000/e1000_defines.h
index e33fe0f..4c2b090 100644
--- a/sys/dev/e1000/e1000_defines.h
+++ b/sys/dev/e1000/e1000_defines.h
@@ -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 */
diff --git a/sys/dev/e1000/e1000_ich8lan.c b/sys/dev/e1000/e1000_ich8lan.c
index 4c93662..46c903d 100644
--- a/sys/dev/e1000/e1000_ich8lan.c
+++ b/sys/dev/e1000/e1000_ich8lan.c
@@ -243,8 +243,7 @@ static bool e1000_phy_is_accessible_pchlan(struct e1000_hw *hw)
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_hw *hw)
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_hw *hw)
/* 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_hw *hw)
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 e1000_hw *hw)
* 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 e1000_hw *hw)
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 e1000_hw *hw)
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 e1000_hw *hw)
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 e1000_hw *hw)
* 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 e1000_hw *hw)
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 e1000_hw *hw)
/* 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_hw *hw)
/* 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_hw *hw)
* 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_hw *hw)
* 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 *hw, u32 timeout)
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_hw *hw, u32 offset,
/* 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 e1000_hw *hw, u32 offset,
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_hw *hw, u32 offset,
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_hw *hw, u32 offset,
/* 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_hw *hw, u32 offset,
* 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 e1000_hw *hw, u32 offset,
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 e1000_hw *hw, u32 offset,
/* 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 e1000_hw *hw, u32 offset,
* 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_hw *hw, u32 bank)
/* 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_hw *hw, u32 bank)
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 e1000_hw *hw)
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 *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,
diff --git a/sys/dev/e1000/if_em.c b/sys/dev/e1000/if_em.c
index fdcc72b..6576430 100644
--- a/sys/dev/e1000/if_em.c
+++ b/sys/dev/e1000/if_em.c
@@ -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);
diff --git a/sys/dev/e1000/if_igb.c b/sys/dev/e1000/if_igb.c
index ae3679b..5396868 100644
--- a/sys/dev/e1000/if_igb.c
+++ b/sys/dev/e1000/if_igb.c
@@ -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,12 +775,7 @@ igb_suspend(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);
- }
+ igb_enable_wakeup(dev);
IGB_CORE_UNLOCK(adapter);
@@ -1216,6 +1205,14 @@ igb_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
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 *adapter)
| 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;
-
- /* 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 */
+ struct adapter *adapter = device_get_softc(dev);
+ struct ifnet *ifp = adapter->ifp;
+ u32 pmc, ctrl, ctrl_ext, rctl, wuc;
+ u16 status;
+
+ 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
OpenPOWER on IntegriCloud