ath9k_htc: Add ethtool stats support.
authorBen Greear <greearb@candelatech.com>
Wed, 19 Jun 2013 21:02:15 +0000 (14:02 -0700)
committerJohn W. Linville <linville@tuxdriver.com>
Mon, 24 Jun 2013 18:44:23 +0000 (14:44 -0400)
This provides some of the same info found in
the ath9k_htc debugfs through the standard ethtool stats API.

This logic is only supported when ath9k_htc debugfs kernel
feature is enabled, since that is the only time stats
are actually gathered.

Signed-off-by: Ben Greear <greearb@candelatech.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/ath/ath9k/hif_usb.c
drivers/net/wireless/ath/ath9k/htc.h
drivers/net/wireless/ath/ath9k/htc_drv_debug.c
drivers/net/wireless/ath/ath9k/htc_drv_main.c

index f5dda84176c3d4ae8277c069df06fa3bbc11922d..9e582e14da74609361b689e5f5741d425fd14659 100644 (file)
@@ -234,10 +234,15 @@ static inline void ath9k_skb_queue_complete(struct hif_device_usb *hif_dev,
        struct sk_buff *skb;
 
        while ((skb = __skb_dequeue(queue)) != NULL) {
+#ifdef CONFIG_ATH9K_HTC_DEBUGFS
+               int ln = skb->len;
+#endif
                ath9k_htc_txcompletion_cb(hif_dev->htc_handle,
                                          skb, txok);
-               if (txok)
+               if (txok) {
                        TX_STAT_INC(skb_success);
+                       TX_STAT_ADD(skb_success_bytes, ln);
+               }
                else
                        TX_STAT_INC(skb_failed);
        }
@@ -620,6 +625,7 @@ static void ath9k_hif_usb_rx_stream(struct hif_device_usb *hif_dev,
 
 err:
        for (i = 0; i < pool_index; i++) {
+               RX_STAT_ADD(skb_completed_bytes, skb_pool[i]->len);
                ath9k_htc_rx_msg(hif_dev->htc_handle, skb_pool[i],
                                 skb_pool[i]->len, USB_WLAN_RX_PIPE);
                RX_STAT_INC(skb_completed);
index 6bd556d203ae02e46a71e7169d6d4d619cd80d2d..055d7c25e090bd33ce70de75c8352dc22dbb4003 100644 (file)
@@ -324,7 +324,9 @@ static inline struct ath9k_htc_tx_ctl *HTC_SKB_CB(struct sk_buff *skb)
 #ifdef CONFIG_ATH9K_HTC_DEBUGFS
 
 #define TX_STAT_INC(c) (hif_dev->htc_handle->drv_priv->debug.tx_stats.c++)
+#define TX_STAT_ADD(c, a) (hif_dev->htc_handle->drv_priv->debug.tx_stats.c += a)
 #define RX_STAT_INC(c) (hif_dev->htc_handle->drv_priv->debug.rx_stats.c++)
+#define RX_STAT_ADD(c, a) (hif_dev->htc_handle->drv_priv->debug.rx_stats.c += a)
 #define CAB_STAT_INC   priv->debug.tx_stats.cab_queued++
 
 #define TX_QSTAT_INC(q) (priv->debug.tx_stats.queue_stats[q]++)
@@ -337,6 +339,7 @@ struct ath_tx_stats {
        u32 buf_completed;
        u32 skb_queued;
        u32 skb_success;
+       u32 skb_success_bytes;
        u32 skb_failed;
        u32 cab_queued;
        u32 queue_stats[IEEE80211_NUM_ACS];
@@ -345,6 +348,7 @@ struct ath_tx_stats {
 struct ath_rx_stats {
        u32 skb_allocated;
        u32 skb_completed;
+       u32 skb_completed_bytes;
        u32 skb_dropped;
        u32 err_crc;
        u32 err_decrypt_crc;
@@ -362,10 +366,20 @@ struct ath9k_debug {
        struct ath_rx_stats rx_stats;
 };
 
+void ath9k_htc_get_et_strings(struct ieee80211_hw *hw,
+                             struct ieee80211_vif *vif,
+                             u32 sset, u8 *data);
+int ath9k_htc_get_et_sset_count(struct ieee80211_hw *hw,
+                               struct ieee80211_vif *vif, int sset);
+void ath9k_htc_get_et_stats(struct ieee80211_hw *hw,
+                           struct ieee80211_vif *vif,
+                           struct ethtool_stats *stats, u64 *data);
 #else
 
 #define TX_STAT_INC(c) do { } while (0)
+#define TX_STAT_ADD(c, a) do { } while (0)
 #define RX_STAT_INC(c) do { } while (0)
+#define RX_STAT_ADD(c, a) do { } while (0)
 #define CAB_STAT_INC   do { } while (0)
 
 #define TX_QSTAT_INC(c) do { } while (0)
index 632d13da43e23f3e877075a7d43bdb64adf77f4c..7416d58a122c2ad9b22ebcdc7fbbc64c74b2ad02 100644 (file)
@@ -902,6 +902,87 @@ static const struct file_operations fops_modal_eeprom = {
        .llseek = default_llseek,
 };
 
+
+/* Ethtool support for get-stats */
+#define AMKSTR(nm) #nm "_BE", #nm "_BK", #nm "_VI", #nm "_VO"
+static const char ath9k_htc_gstrings_stats[][ETH_GSTRING_LEN] = {
+       "tx_pkts_nic",
+       "tx_bytes_nic",
+       "rx_pkts_nic",
+       "rx_bytes_nic",
+
+       AMKSTR(d_tx_pkts),
+
+       "d_rx_crc_err",
+       "d_rx_decrypt_crc_err",
+       "d_rx_phy_err",
+       "d_rx_mic_err",
+       "d_rx_pre_delim_crc_err",
+       "d_rx_post_delim_crc_err",
+       "d_rx_decrypt_busy_err",
+
+       "d_rx_phyerr_radar",
+       "d_rx_phyerr_ofdm_timing",
+       "d_rx_phyerr_cck_timing",
+
+};
+#define ATH9K_HTC_SSTATS_LEN ARRAY_SIZE(ath9k_htc_gstrings_stats)
+
+void ath9k_htc_get_et_strings(struct ieee80211_hw *hw,
+                             struct ieee80211_vif *vif,
+                             u32 sset, u8 *data)
+{
+       if (sset == ETH_SS_STATS)
+               memcpy(data, *ath9k_htc_gstrings_stats,
+                      sizeof(ath9k_htc_gstrings_stats));
+}
+
+int ath9k_htc_get_et_sset_count(struct ieee80211_hw *hw,
+                               struct ieee80211_vif *vif, int sset)
+{
+       if (sset == ETH_SS_STATS)
+               return ATH9K_HTC_SSTATS_LEN;
+       return 0;
+}
+
+#define STXBASE priv->debug.tx_stats
+#define SRXBASE priv->debug.rx_stats
+#define ASTXQ(a)                                       \
+       data[i++] = STXBASE.a[IEEE80211_AC_BE];         \
+       data[i++] = STXBASE.a[IEEE80211_AC_BK];         \
+       data[i++] = STXBASE.a[IEEE80211_AC_VI];         \
+       data[i++] = STXBASE.a[IEEE80211_AC_VO]
+
+void ath9k_htc_get_et_stats(struct ieee80211_hw *hw,
+                           struct ieee80211_vif *vif,
+                           struct ethtool_stats *stats, u64 *data)
+{
+       struct ath9k_htc_priv *priv = hw->priv;
+       int i = 0;
+
+       data[i++] = STXBASE.skb_success;
+       data[i++] = STXBASE.skb_success_bytes;
+       data[i++] = SRXBASE.skb_completed;
+       data[i++] = SRXBASE.skb_completed_bytes;
+
+       ASTXQ(queue_stats);
+
+       data[i++] = SRXBASE.err_crc;
+       data[i++] = SRXBASE.err_decrypt_crc;
+       data[i++] = SRXBASE.err_phy;
+       data[i++] = SRXBASE.err_mic;
+       data[i++] = SRXBASE.err_pre_delim;
+       data[i++] = SRXBASE.err_post_delim;
+       data[i++] = SRXBASE.err_decrypt_busy;
+
+       data[i++] = SRXBASE.err_phy_stats[ATH9K_PHYERR_RADAR];
+       data[i++] = SRXBASE.err_phy_stats[ATH9K_PHYERR_OFDM_TIMING];
+       data[i++] = SRXBASE.err_phy_stats[ATH9K_PHYERR_CCK_TIMING];
+
+       WARN_ON(i != ATH9K_HTC_SSTATS_LEN);
+}
+
+
 int ath9k_htc_init_debug(struct ath_hw *ah)
 {
        struct ath_common *common = ath9k_hw_common(ah);
index ef68857f936334ddab27ce8fee15a8077436acf8..be6baf7f651053b691ec6fb883c13d863c0e3bde 100644 (file)
@@ -1837,4 +1837,10 @@ struct ieee80211_ops ath9k_htc_ops = {
        .set_bitrate_mask   = ath9k_htc_set_bitrate_mask,
        .get_stats          = ath9k_htc_get_stats,
        .get_antenna        = ath9k_htc_get_antenna,
+
+#ifdef CONFIG_ATH9K_HTC_DEBUGFS
+       .get_et_sset_count  = ath9k_htc_get_et_sset_count,
+       .get_et_stats       = ath9k_htc_get_et_stats,
+       .get_et_strings     = ath9k_htc_get_et_strings,
+#endif
 };