Commit 8c7bbb92 authored by Bruce Allan's avatar Bruce Allan Committed by David S. Miller

e1000e: separate out PHY statistics register updates

The 82577/82578 parts have half-duplex statistics in PHY registers.  These
need only be read when in half-duplex and should all be read at once rather
than one at a time to prevent excessive cycles of acquiring/releasing the
PHY semaphore.
Signed-off-by: default avatarBruce Allan <bruce.w.allan@intel.com>
Tested-by: default avatarJeff Pieper <jeffrey.e.pieper@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 3f0c16e8
......@@ -421,6 +421,7 @@ struct e1000_info {
#define FLAG2_HAS_PHY_WAKEUP (1 << 1)
#define FLAG2_IS_DISCARDING (1 << 2)
#define FLAG2_DISABLE_ASPM_L1 (1 << 3)
#define FLAG2_HAS_PHY_STATS (1 << 4)
#define E1000_RX_DESC_PS(R, i) \
(&(((union e1000_rx_desc_packet_split *)((R).desc))[i]))
......
......@@ -3503,6 +3503,7 @@ struct e1000_info e1000_pch_info = {
| FLAG_HAS_JUMBO_FRAMES
| FLAG_DISABLE_FC_PAUSE_TIME /* errata */
| FLAG_APME_IN_WUC,
.flags2 = FLAG2_HAS_PHY_STATS,
.pba = 26,
.max_hw_frame_size = 4096,
.get_variants = e1000_get_variants_ich8lan,
......
......@@ -3671,6 +3671,110 @@ static void e1000_update_phy_info(unsigned long data)
schedule_work(&adapter->update_phy_task);
}
/**
* e1000e_update_phy_stats - Update the PHY statistics counters
* @adapter: board private structure
**/
static void e1000e_update_phy_stats(struct e1000_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
s32 ret_val;
u16 phy_data;
ret_val = hw->phy.ops.acquire(hw);
if (ret_val)
return;
hw->phy.addr = 1;
#define HV_PHY_STATS_PAGE 778
/*
* A page set is expensive so check if already on desired page.
* If not, set to the page with the PHY status registers.
*/
ret_val = e1000e_read_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT,
&phy_data);
if (ret_val)
goto release;
if (phy_data != (HV_PHY_STATS_PAGE << IGP_PAGE_SHIFT)) {
ret_val = e1000e_write_phy_reg_mdic(hw,
IGP01E1000_PHY_PAGE_SELECT,
(HV_PHY_STATS_PAGE <<
IGP_PAGE_SHIFT));
if (ret_val)
goto release;
}
/* Read/clear the upper 16-bit registers and read/accumulate lower */
/* Single Collision Count */
e1000e_read_phy_reg_mdic(hw, HV_SCC_UPPER & MAX_PHY_REG_ADDRESS,
&phy_data);
ret_val = e1000e_read_phy_reg_mdic(hw,
HV_SCC_LOWER & MAX_PHY_REG_ADDRESS,
&phy_data);
if (!ret_val)
adapter->stats.scc += phy_data;
/* Excessive Collision Count */
e1000e_read_phy_reg_mdic(hw, HV_ECOL_UPPER & MAX_PHY_REG_ADDRESS,
&phy_data);
ret_val = e1000e_read_phy_reg_mdic(hw,
HV_ECOL_LOWER & MAX_PHY_REG_ADDRESS,
&phy_data);
if (!ret_val)
adapter->stats.ecol += phy_data;
/* Multiple Collision Count */
e1000e_read_phy_reg_mdic(hw, HV_MCC_UPPER & MAX_PHY_REG_ADDRESS,
&phy_data);
ret_val = e1000e_read_phy_reg_mdic(hw,
HV_MCC_LOWER & MAX_PHY_REG_ADDRESS,
&phy_data);
if (!ret_val)
adapter->stats.mcc += phy_data;
/* Late Collision Count */
e1000e_read_phy_reg_mdic(hw, HV_LATECOL_UPPER & MAX_PHY_REG_ADDRESS,
&phy_data);
ret_val = e1000e_read_phy_reg_mdic(hw,
HV_LATECOL_LOWER &
MAX_PHY_REG_ADDRESS,
&phy_data);
if (!ret_val)
adapter->stats.latecol += phy_data;
/* Collision Count - also used for adaptive IFS */
e1000e_read_phy_reg_mdic(hw, HV_COLC_UPPER & MAX_PHY_REG_ADDRESS,
&phy_data);
ret_val = e1000e_read_phy_reg_mdic(hw,
HV_COLC_LOWER & MAX_PHY_REG_ADDRESS,
&phy_data);
if (!ret_val)
hw->mac.collision_delta = phy_data;
/* Defer Count */
e1000e_read_phy_reg_mdic(hw, HV_DC_UPPER & MAX_PHY_REG_ADDRESS,
&phy_data);
ret_val = e1000e_read_phy_reg_mdic(hw,
HV_DC_LOWER & MAX_PHY_REG_ADDRESS,
&phy_data);
if (!ret_val)
adapter->stats.dc += phy_data;
/* Transmit with no CRS */
e1000e_read_phy_reg_mdic(hw, HV_TNCRS_UPPER & MAX_PHY_REG_ADDRESS,
&phy_data);
ret_val = e1000e_read_phy_reg_mdic(hw,
HV_TNCRS_LOWER & MAX_PHY_REG_ADDRESS,
&phy_data);
if (!ret_val)
adapter->stats.tncrs += phy_data;
release:
hw->phy.ops.release(hw);
}
/**
* e1000e_update_stats - Update the board statistics counters
* @adapter: board private structure
......@@ -3680,7 +3784,6 @@ void e1000e_update_stats(struct e1000_adapter *adapter)
struct net_device *netdev = adapter->netdev;
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
......@@ -3700,34 +3803,27 @@ void e1000e_update_stats(struct e1000_adapter *adapter)
adapter->stats.roc += er32(ROC);
adapter->stats.mpc += er32(MPC);
if ((hw->phy.type == e1000_phy_82578) ||
(hw->phy.type == e1000_phy_82577)) {
e1e_rphy(hw, HV_SCC_UPPER, &phy_data);
if (!e1e_rphy(hw, HV_SCC_LOWER, &phy_data))
adapter->stats.scc += phy_data;
e1e_rphy(hw, HV_ECOL_UPPER, &phy_data);
if (!e1e_rphy(hw, HV_ECOL_LOWER, &phy_data))
adapter->stats.ecol += phy_data;
e1e_rphy(hw, HV_MCC_UPPER, &phy_data);
if (!e1e_rphy(hw, HV_MCC_LOWER, &phy_data))
adapter->stats.mcc += phy_data;
e1e_rphy(hw, HV_LATECOL_UPPER, &phy_data);
if (!e1e_rphy(hw, HV_LATECOL_LOWER, &phy_data))
adapter->stats.latecol += phy_data;
e1e_rphy(hw, HV_DC_UPPER, &phy_data);
if (!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);
/* Half-duplex statistics */
if (adapter->link_duplex == HALF_DUPLEX) {
if (adapter->flags2 & FLAG2_HAS_PHY_STATS) {
e1000e_update_phy_stats(adapter);
} 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);
hw->mac.collision_delta = er32(COLC);
if ((hw->mac.type != e1000_82574) &&
(hw->mac.type != e1000_82583))
adapter->stats.tncrs += er32(TNCRS);
}
adapter->stats.colc += hw->mac.collision_delta;
}
adapter->stats.xonrxc += er32(XONRXC);
adapter->stats.xontxc += er32(XONTXC);
adapter->stats.xoffrxc += er32(XOFFRXC);
......@@ -3745,28 +3841,9 @@ void e1000e_update_stats(struct e1000_adapter *adapter)
hw->mac.tx_packet_delta = er32(TPT);
adapter->stats.tpt += hw->mac.tx_packet_delta;
if ((hw->phy.type == e1000_phy_82578) ||
(hw->phy.type == e1000_phy_82577)) {
e1e_rphy(hw, HV_COLC_UPPER, &phy_data);
if (!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->phy.type == e1000_phy_82578) ||
(hw->phy.type == e1000_phy_82577)) {
e1e_rphy(hw, HV_TNCRS_UPPER, &phy_data);
if (!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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment