e1000e: separate out PHY statistics register updates
authorBruce Allan <bruce.w.allan@intel.com>
Wed, 16 Jun 2010 13:26:41 +0000 (13:26 +0000)
committerDavid S. Miller <davem@davemloft.net>
Sat, 19 Jun 2010 05:12:15 +0000 (22:12 -0700)
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: Bruce Allan <bruce.w.allan@intel.com>
Tested-by: Jeff Pieper <jeffrey.e.pieper@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/e1000e/e1000.h
drivers/net/e1000e/ich8lan.c
drivers/net/e1000e/netdev.c

index c0b3db4..79e7c4c 100644 (file)
@@ -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]))
index 5d8fad3..70cd681 100644 (file)
@@ -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,
index 57a7e41..b4c431d 100644 (file)
@@ -3672,6 +3672,110 @@ static void e1000_update_phy_info(unsigned long data)
 }
 
 /**
+ * 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);