diff options
Diffstat (limited to 'drivers/net/e1000e/netdev.c')
-rw-r--r-- | drivers/net/e1000e/netdev.c | 206 |
1 files changed, 193 insertions, 13 deletions
diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 4072fbb6493..2cb704dd954 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -62,6 +62,7 @@ static const struct e1000_info *e1000_info_tbl[] = { [board_ich8lan] = &e1000_ich8_info, [board_ich9lan] = &e1000_ich9_info, [board_ich10lan] = &e1000_ich10_info, + [board_pchlan] = &e1000_pch_info, }; #ifdef DEBUG @@ -2308,6 +2309,23 @@ static void e1000_setup_rctl(struct e1000_adapter *adapter) if (adapter->flags2 & FLAG2_CRC_STRIPPING) rctl |= E1000_RCTL_SECRC; + /* Workaround Si errata on 82577 PHY - configure IPG for jumbos */ + if ((hw->phy.type == e1000_phy_82577) && (rctl & E1000_RCTL_LPE)) { + u16 phy_data; + + e1e_rphy(hw, PHY_REG(770, 26), &phy_data); + phy_data &= 0xfff8; + phy_data |= (1 << 2); + e1e_wphy(hw, PHY_REG(770, 26), phy_data); + + e1e_rphy(hw, 22, &phy_data); + phy_data &= 0x0fff; + phy_data |= (1 << 14); + e1e_wphy(hw, 0x10, 0x2823); + e1e_wphy(hw, 0x11, 0x0003); + e1e_wphy(hw, 22, phy_data); + } + /* Setup buffer sizes */ rctl &= ~E1000_RCTL_SZ_4096; rctl |= E1000_RCTL_BSEX; @@ -2789,6 +2807,8 @@ void e1000e_reset(struct e1000_adapter *adapter) e1000_get_hw_control(adapter); ew32(WUC, 0); + if (adapter->flags2 & FLAG2_HAS_PHY_WAKEUP) + e1e_wphy(&adapter->hw, BM_WUC, 0); if (mac->ops.init_hw(hw)) e_err("Hardware Error\n"); @@ -3269,6 +3289,7 @@ void e1000e_update_stats(struct e1000_adapter *adapter) { struct e1000_hw *hw = &adapter->hw; struct pci_dev *pdev = adapter->pdev; + u16 phy_data; /* * Prevent stats update while adapter is being reset, or if the pci @@ -3288,11 +3309,34 @@ void e1000e_update_stats(struct e1000_adapter *adapter) adapter->stats.roc += er32(ROC); adapter->stats.mpc += er32(MPC); - adapter->stats.scc += er32(SCC); - adapter->stats.ecol += er32(ECOL); - adapter->stats.mcc += er32(MCC); - adapter->stats.latecol += er32(LATECOL); - adapter->stats.dc += er32(DC); + if ((hw->phy.type == e1000_phy_82578) || + (hw->phy.type == e1000_phy_82577)) { + e1e_rphy(hw, HV_SCC_UPPER, &phy_data); + e1e_rphy(hw, HV_SCC_LOWER, &phy_data); + adapter->stats.scc += phy_data; + + e1e_rphy(hw, HV_ECOL_UPPER, &phy_data); + e1e_rphy(hw, HV_ECOL_LOWER, &phy_data); + adapter->stats.ecol += phy_data; + + e1e_rphy(hw, HV_MCC_UPPER, &phy_data); + e1e_rphy(hw, HV_MCC_LOWER, &phy_data); + adapter->stats.mcc += phy_data; + + e1e_rphy(hw, HV_LATECOL_UPPER, &phy_data); + e1e_rphy(hw, HV_LATECOL_LOWER, &phy_data); + adapter->stats.latecol += phy_data; + + e1e_rphy(hw, HV_DC_UPPER, &phy_data); + e1e_rphy(hw, HV_DC_LOWER, &phy_data); + adapter->stats.dc += phy_data; + } else { + adapter->stats.scc += er32(SCC); + adapter->stats.ecol += er32(ECOL); + adapter->stats.mcc += er32(MCC); + adapter->stats.latecol += er32(LATECOL); + adapter->stats.dc += er32(DC); + } adapter->stats.xonrxc += er32(XONRXC); adapter->stats.xontxc += er32(XONTXC); adapter->stats.xoffrxc += er32(XOFFRXC); @@ -3310,13 +3354,28 @@ void e1000e_update_stats(struct e1000_adapter *adapter) hw->mac.tx_packet_delta = er32(TPT); adapter->stats.tpt += hw->mac.tx_packet_delta; - hw->mac.collision_delta = er32(COLC); + if ((hw->phy.type == e1000_phy_82578) || + (hw->phy.type == e1000_phy_82577)) { + e1e_rphy(hw, HV_COLC_UPPER, &phy_data); + e1e_rphy(hw, HV_COLC_LOWER, &phy_data); + hw->mac.collision_delta = phy_data; + } else { + hw->mac.collision_delta = er32(COLC); + } adapter->stats.colc += hw->mac.collision_delta; adapter->stats.algnerrc += er32(ALGNERRC); adapter->stats.rxerrc += er32(RXERRC); - if ((hw->mac.type != e1000_82574) && (hw->mac.type != e1000_82583)) - adapter->stats.tncrs += er32(TNCRS); + if ((hw->phy.type == e1000_phy_82578) || + (hw->phy.type == e1000_phy_82577)) { + e1e_rphy(hw, HV_TNCRS_UPPER, &phy_data); + e1e_rphy(hw, HV_TNCRS_LOWER, &phy_data); + adapter->stats.tncrs += phy_data; + } else { + if ((hw->mac.type != e1000_82574) && + (hw->mac.type != e1000_82583)) + adapter->stats.tncrs += er32(TNCRS); + } adapter->stats.cexterr += er32(CEXTERR); adapter->stats.tsctc += er32(TSCTC); adapter->stats.tsctfc += er32(TSCTFC); @@ -4342,6 +4401,81 @@ static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) } } +static int e1000_init_phy_wakeup(struct e1000_adapter *adapter, u32 wufc) +{ + struct e1000_hw *hw = &adapter->hw; + u32 i, mac_reg; + u16 phy_reg; + int retval = 0; + + /* copy MAC RARs to PHY RARs */ + for (i = 0; i < adapter->hw.mac.rar_entry_count; i++) { + mac_reg = er32(RAL(i)); + e1e_wphy(hw, BM_RAR_L(i), (u16)(mac_reg & 0xFFFF)); + e1e_wphy(hw, BM_RAR_M(i), (u16)((mac_reg >> 16) & 0xFFFF)); + mac_reg = er32(RAH(i)); + e1e_wphy(hw, BM_RAR_H(i), (u16)(mac_reg & 0xFFFF)); + e1e_wphy(hw, BM_RAR_CTRL(i), (u16)((mac_reg >> 16) & 0xFFFF)); + } + + /* copy MAC MTA to PHY MTA */ + for (i = 0; i < adapter->hw.mac.mta_reg_count; i++) { + mac_reg = E1000_READ_REG_ARRAY(hw, E1000_MTA, i); + e1e_wphy(hw, BM_MTA(i), (u16)(mac_reg & 0xFFFF)); + e1e_wphy(hw, BM_MTA(i) + 1, (u16)((mac_reg >> 16) & 0xFFFF)); + } + + /* configure PHY Rx Control register */ + e1e_rphy(&adapter->hw, BM_RCTL, &phy_reg); + mac_reg = er32(RCTL); + if (mac_reg & E1000_RCTL_UPE) + phy_reg |= BM_RCTL_UPE; + if (mac_reg & E1000_RCTL_MPE) + phy_reg |= BM_RCTL_MPE; + phy_reg &= ~(BM_RCTL_MO_MASK); + if (mac_reg & E1000_RCTL_MO_3) + phy_reg |= (((mac_reg & E1000_RCTL_MO_3) >> E1000_RCTL_MO_SHIFT) + << BM_RCTL_MO_SHIFT); + if (mac_reg & E1000_RCTL_BAM) + phy_reg |= BM_RCTL_BAM; + if (mac_reg & E1000_RCTL_PMCF) + phy_reg |= BM_RCTL_PMCF; + mac_reg = er32(CTRL); + if (mac_reg & E1000_CTRL_RFCE) + phy_reg |= BM_RCTL_RFCE; + e1e_wphy(&adapter->hw, BM_RCTL, phy_reg); + + /* enable PHY wakeup in MAC register */ + ew32(WUFC, wufc); + ew32(WUC, E1000_WUC_PHY_WAKE | E1000_WUC_PME_EN); + + /* configure and enable PHY wakeup in PHY registers */ + e1e_wphy(&adapter->hw, BM_WUFC, wufc); + e1e_wphy(&adapter->hw, BM_WUC, E1000_WUC_PME_EN); + + /* activate PHY wakeup */ + retval = hw->phy.ops.acquire_phy(hw); + if (retval) { + e_err("Could not acquire PHY\n"); + return retval; + } + e1000e_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT, + (BM_WUC_ENABLE_PAGE << IGP_PAGE_SHIFT)); + retval = e1000e_read_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, &phy_reg); + if (retval) { + e_err("Could not read PHY page 769\n"); + goto out; + } + phy_reg |= BM_WUC_ENABLE_BIT | BM_WUC_HOST_WU_BIT; + retval = e1000e_write_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, phy_reg); + if (retval) + e_err("Could not set PHY Host Wakeup bit\n"); +out: + hw->phy.ops.release_phy(hw); + + return retval; +} + static int __e1000_shutdown(struct pci_dev *pdev, bool *enable_wake) { struct net_device *netdev = pci_get_drvdata(pdev); @@ -4384,8 +4518,9 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool *enable_wake) #define E1000_CTRL_ADVD3WUC 0x00100000 /* phy power management enable */ #define E1000_CTRL_EN_PHY_PWR_MGMT 0x00200000 - ctrl |= E1000_CTRL_ADVD3WUC | - E1000_CTRL_EN_PHY_PWR_MGMT; + ctrl |= E1000_CTRL_ADVD3WUC; + if (!(adapter->flags2 & FLAG2_HAS_PHY_WAKEUP)) + ctrl |= E1000_CTRL_EN_PHY_PWR_MGMT; ew32(CTRL, ctrl); if (adapter->hw.phy.media_type == e1000_media_type_fiber || @@ -4403,8 +4538,17 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool *enable_wake) /* Allow time for pending master requests to run */ e1000e_disable_pcie_master(&adapter->hw); - ew32(WUC, E1000_WUC_PME_EN); - ew32(WUFC, wufc); + if ((adapter->flags2 & FLAG2_HAS_PHY_WAKEUP) && + !(hw->mac.ops.check_mng_mode(hw))) { + /* enable wakeup by the PHY */ + retval = e1000_init_phy_wakeup(adapter, wufc); + if (retval) + return retval; + } else { + /* enable wakeup by the MAC */ + ew32(WUFC, wufc); + ew32(WUC, E1000_WUC_PME_EN); + } } else { ew32(WUC, 0); ew32(WUFC, 0); @@ -4547,8 +4691,37 @@ static int e1000_resume(struct pci_dev *pdev) } e1000e_power_up_phy(adapter); + + /* report the system wakeup cause from S3/S4 */ + if (adapter->flags2 & FLAG2_HAS_PHY_WAKEUP) { + u16 phy_data; + + e1e_rphy(&adapter->hw, BM_WUS, &phy_data); + if (phy_data) { + e_info("PHY Wakeup cause - %s\n", + phy_data & E1000_WUS_EX ? "Unicast Packet" : + phy_data & E1000_WUS_MC ? "Multicast Packet" : + phy_data & E1000_WUS_BC ? "Broadcast Packet" : + phy_data & E1000_WUS_MAG ? "Magic Packet" : + phy_data & E1000_WUS_LNKC ? "Link Status " + " Change" : "other"); + } + e1e_wphy(&adapter->hw, BM_WUS, ~0); + } else { + u32 wus = er32(WUS); + if (wus) { + e_info("MAC Wakeup cause - %s\n", + wus & E1000_WUS_EX ? "Unicast Packet" : + wus & E1000_WUS_MC ? "Multicast Packet" : + wus & E1000_WUS_BC ? "Broadcast Packet" : + wus & E1000_WUS_MAG ? "Magic Packet" : + wus & E1000_WUS_LNKC ? "Link Status Change" : + "other"); + } + ew32(WUS, ~0); + } + e1000e_reset(adapter); - ew32(WUS, ~0); e1000_init_manageability(adapter); @@ -4994,6 +5167,8 @@ static int __devinit e1000_probe(struct pci_dev *pdev, /* APME bit in EEPROM is mapped to WUC.APME */ eeprom_data = er32(WUC); eeprom_apme_mask = E1000_WUC_APME; + if (eeprom_data & E1000_WUC_PHY_WAKE) + adapter->flags2 |= FLAG2_HAS_PHY_WAKEUP; } else if (adapter->flags & FLAG_APME_IN_CTRL3) { if (adapter->flags & FLAG_APME_CHECK_PORT_B && (adapter->hw.bus.func == 1)) @@ -5195,6 +5370,11 @@ static struct pci_device_id e1000_pci_tbl[] = { { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_D_BM_LM), board_ich10lan }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_D_BM_LF), board_ich10lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_M_HV_LM), board_pchlan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_M_HV_LC), board_pchlan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_D_HV_DM), board_pchlan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_D_HV_DC), board_pchlan }, + { } /* terminate list */ }; MODULE_DEVICE_TABLE(pci, e1000_pci_tbl); |