aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2015-01-14 12:12:41 -0500
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>2015-03-01 09:55:09 -0500
commit91a8bcde2e7feb2c2782ddc6a266cf5f5294d16f (patch)
treeb31ec434d582c37c0e230fd38d9219c351717bae
parent777c9b6bba5266ea8eecb19b3fa8b63ad5251bd6 (diff)
iwlwifi: mvm: support radio statistics as global survey
Export the radio statistics from the statistics v10 API (if the firmware also has the capability to fill these statistics) using the global survey data facility. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-fw-file.h2
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api-stats.h17
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api.h1
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mac80211.c58
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mvm.h14
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/ops.c1
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/rx.c27
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/utils.c29
8 files changed, 127 insertions, 22 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h
index 4602e3c7afda..8b9040ef20e0 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h
@@ -286,6 +286,7 @@ enum iwl_ucode_tlv_api {
286 * which also implies support for the scheduler configuration command 286 * which also implies support for the scheduler configuration command
287 * @IWL_UCODE_TLV_CAPA_TDLS_CHANNEL_SWITCH: supports TDLS channel switching 287 * @IWL_UCODE_TLV_CAPA_TDLS_CHANNEL_SWITCH: supports TDLS channel switching
288 * @IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT: supports Hot Spot Command 288 * @IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT: supports Hot Spot Command
289 * @IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS: support radio and beacon statistics
289 */ 290 */
290enum iwl_ucode_tlv_capa { 291enum iwl_ucode_tlv_capa {
291 IWL_UCODE_TLV_CAPA_D0I3_SUPPORT = BIT(0), 292 IWL_UCODE_TLV_CAPA_D0I3_SUPPORT = BIT(0),
@@ -300,6 +301,7 @@ enum iwl_ucode_tlv_capa {
300 IWL_UCODE_TLV_CAPA_DQA_SUPPORT = BIT(12), 301 IWL_UCODE_TLV_CAPA_DQA_SUPPORT = BIT(12),
301 IWL_UCODE_TLV_CAPA_TDLS_CHANNEL_SWITCH = BIT(13), 302 IWL_UCODE_TLV_CAPA_TDLS_CHANNEL_SWITCH = BIT(13),
302 IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT = BIT(18), 303 IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT = BIT(18),
304 IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS = BIT(22),
303}; 305};
304 306
305/* The default calibrate table size if not specified by firmware file */ 307/* The default calibrate table size if not specified by firmware file */
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-stats.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-stats.h
index 5a9dfe074022..709e28d8b1b0 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api-stats.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-stats.h
@@ -290,15 +290,7 @@ struct mvm_statistics_rx {
290 * 290 *
291 * By default, uCode issues this notification after receiving a beacon 291 * By default, uCode issues this notification after receiving a beacon
292 * while associated. To disable this behavior, set DISABLE_NOTIF flag in the 292 * while associated. To disable this behavior, set DISABLE_NOTIF flag in the
293 * REPLY_STATISTICS_CMD 0x9c, above. 293 * STATISTICS_CMD (0x9c), below.
294 *
295 * Statistics counters continue to increment beacon after beacon, but are
296 * cleared when changing channels or when driver issues REPLY_STATISTICS_CMD
297 * 0x9c with CLEAR_STATS bit set (see above).
298 *
299 * uCode also issues this notification during scans. uCode clears statistics
300 * appropriately so that each notification contains statistics for only the
301 * one channel that has just been scanned.
302 */ 294 */
303 295
304struct iwl_notif_statistics_v8 { 296struct iwl_notif_statistics_v8 {
@@ -315,4 +307,11 @@ struct iwl_notif_statistics_v10 {
315 struct mvm_statistics_general_v8 general; 307 struct mvm_statistics_general_v8 general;
316} __packed; /* STATISTICS_NTFY_API_S_VER_10 */ 308} __packed; /* STATISTICS_NTFY_API_S_VER_10 */
317 309
310#define IWL_STATISTICS_FLG_CLEAR 0x1
311#define IWL_STATISTICS_FLG_DISABLE_NOTIF 0x2
312
313struct iwl_statistics_cmd {
314 __le32 flags;
315} __packed; /* STATISTICS_CMD_API_S_VER_1 */
316
318#endif /* __fw_api_stats_h__ */ 317#endif /* __fw_api_stats_h__ */
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
index b56154fe8ec5..c43e5c2bb85c 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
@@ -192,6 +192,7 @@ enum {
192 BEACON_NOTIFICATION = 0x90, 192 BEACON_NOTIFICATION = 0x90,
193 BEACON_TEMPLATE_CMD = 0x91, 193 BEACON_TEMPLATE_CMD = 0x91,
194 TX_ANT_CONFIGURATION_CMD = 0x98, 194 TX_ANT_CONFIGURATION_CMD = 0x98,
195 STATISTICS_CMD = 0x9c,
195 STATISTICS_NOTIFICATION = 0x9d, 196 STATISTICS_NOTIFICATION = 0x9d,
196 EOSP_NOTIFICATION = 0x9e, 197 EOSP_NOTIFICATION = 0x9e,
197 REDUCE_TX_POWER_CMD = 0x9f, 198 REDUCE_TX_POWER_CMD = 0x9f,
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
index 1ff7ec08532d..20e1e898e815 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
@@ -1091,6 +1091,9 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
1091 1091
1092 mvm->vif_count = 0; 1092 mvm->vif_count = 0;
1093 mvm->rx_ba_sessions = 0; 1093 mvm->rx_ba_sessions = 0;
1094
1095 /* keep statistics ticking */
1096 iwl_mvm_accu_radio_stats(mvm);
1094} 1097}
1095 1098
1096int __iwl_mvm_mac_start(struct iwl_mvm *mvm) 1099int __iwl_mvm_mac_start(struct iwl_mvm *mvm)
@@ -1213,6 +1216,11 @@ void __iwl_mvm_mac_stop(struct iwl_mvm *mvm)
1213{ 1216{
1214 lockdep_assert_held(&mvm->mutex); 1217 lockdep_assert_held(&mvm->mutex);
1215 1218
1219 /* firmware counters are obviously reset now, but we shouldn't
1220 * partially track so also clear the fw_reset_accu counters.
1221 */
1222 memset(&mvm->accu_radio_stats, 0, sizeof(mvm->accu_radio_stats));
1223
1216 /* 1224 /*
1217 * Disallow low power states when the FW is down by taking 1225 * Disallow low power states when the FW is down by taking
1218 * the UCODE_DOWN ref. in case of ongoing hw restart the 1226 * the UCODE_DOWN ref. in case of ongoing hw restart the
@@ -3581,6 +3589,55 @@ static void iwl_mvm_mac_flush(struct ieee80211_hw *hw,
3581 } 3589 }
3582} 3590}
3583 3591
3592static int iwl_mvm_mac_get_survey(struct ieee80211_hw *hw, int idx,
3593 struct survey_info *survey)
3594{
3595 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
3596 int ret;
3597
3598 memset(survey, 0, sizeof(*survey));
3599
3600 /* only support global statistics right now */
3601 if (idx != 0)
3602 return -ENOENT;
3603
3604 if (!(mvm->fw->ucode_capa.capa[0] &
3605 IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS))
3606 return -ENOENT;
3607
3608 mutex_lock(&mvm->mutex);
3609
3610 if (mvm->ucode_loaded) {
3611 ret = iwl_mvm_request_statistics(mvm);
3612 if (ret)
3613 goto out;
3614 }
3615
3616 survey->filled = SURVEY_INFO_TIME |
3617 SURVEY_INFO_TIME_RX |
3618 SURVEY_INFO_TIME_TX |
3619 SURVEY_INFO_TIME_SCAN;
3620 survey->time = mvm->accu_radio_stats.on_time_rf +
3621 mvm->radio_stats.on_time_rf;
3622 do_div(survey->time, USEC_PER_MSEC);
3623
3624 survey->time_rx = mvm->accu_radio_stats.rx_time +
3625 mvm->radio_stats.rx_time;
3626 do_div(survey->time_rx, USEC_PER_MSEC);
3627
3628 survey->time_tx = mvm->accu_radio_stats.tx_time +
3629 mvm->radio_stats.tx_time;
3630 do_div(survey->time_tx, USEC_PER_MSEC);
3631
3632 survey->time_scan = mvm->accu_radio_stats.on_time_scan +
3633 mvm->radio_stats.on_time_scan;
3634 do_div(survey->time_scan, USEC_PER_MSEC);
3635
3636 out:
3637 mutex_unlock(&mvm->mutex);
3638 return ret;
3639}
3640
3584const struct ieee80211_ops iwl_mvm_hw_ops = { 3641const struct ieee80211_ops iwl_mvm_hw_ops = {
3585 .tx = iwl_mvm_mac_tx, 3642 .tx = iwl_mvm_mac_tx,
3586 .ampdu_action = iwl_mvm_mac_ampdu_action, 3643 .ampdu_action = iwl_mvm_mac_ampdu_action,
@@ -3647,4 +3704,5 @@ const struct ieee80211_ops iwl_mvm_hw_ops = {
3647#endif 3704#endif
3648 .set_default_unicast_key = iwl_mvm_set_default_unicast_key, 3705 .set_default_unicast_key = iwl_mvm_set_default_unicast_key,
3649#endif 3706#endif
3707 .get_survey = iwl_mvm_mac_get_survey,
3650}; 3708};
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h
index 07b91d6aaf2e..d4f3b8400ccc 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h
@@ -593,6 +593,13 @@ struct iwl_mvm {
593 593
594 struct mvm_statistics_rx rx_stats; 594 struct mvm_statistics_rx rx_stats;
595 595
596 struct {
597 u64 rx_time;
598 u64 tx_time;
599 u64 on_time_rf;
600 u64 on_time_scan;
601 } radio_stats, accu_radio_stats;
602
596 u8 queue_to_mac80211[IWL_MAX_HW_QUEUES]; 603 u8 queue_to_mac80211[IWL_MAX_HW_QUEUES];
597 atomic_t mac80211_queue_stop_count[IEEE80211_MAX_QUEUES]; 604 atomic_t mac80211_queue_stop_count[IEEE80211_MAX_QUEUES];
598 605
@@ -951,12 +958,13 @@ static inline void iwl_mvm_wait_for_async_handlers(struct iwl_mvm *mvm)
951} 958}
952 959
953/* Statistics */ 960/* Statistics */
954int iwl_mvm_rx_reply_statistics(struct iwl_mvm *mvm, 961void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm,
955 struct iwl_rx_cmd_buffer *rxb, 962 struct iwl_rx_packet *pkt);
956 struct iwl_device_cmd *cmd);
957int iwl_mvm_rx_statistics(struct iwl_mvm *mvm, 963int iwl_mvm_rx_statistics(struct iwl_mvm *mvm,
958 struct iwl_rx_cmd_buffer *rxb, 964 struct iwl_rx_cmd_buffer *rxb,
959 struct iwl_device_cmd *cmd); 965 struct iwl_device_cmd *cmd);
966int iwl_mvm_request_statistics(struct iwl_mvm *mvm);
967void iwl_mvm_accu_radio_stats(struct iwl_mvm *mvm);
960 968
961/* NVM */ 969/* NVM */
962int iwl_nvm_init(struct iwl_mvm *mvm, bool read_nvm_from_nic); 970int iwl_nvm_init(struct iwl_mvm *mvm, bool read_nvm_from_nic);
diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c
index 2dffc3600ed3..7a045330ab59 100644
--- a/drivers/net/wireless/iwlwifi/mvm/ops.c
+++ b/drivers/net/wireless/iwlwifi/mvm/ops.c
@@ -311,6 +311,7 @@ static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = {
311 CMD(REPLY_RX_MPDU_CMD), 311 CMD(REPLY_RX_MPDU_CMD),
312 CMD(BEACON_NOTIFICATION), 312 CMD(BEACON_NOTIFICATION),
313 CMD(BEACON_TEMPLATE_CMD), 313 CMD(BEACON_TEMPLATE_CMD),
314 CMD(STATISTICS_CMD),
314 CMD(STATISTICS_NOTIFICATION), 315 CMD(STATISTICS_NOTIFICATION),
315 CMD(EOSP_NOTIFICATION), 316 CMD(EOSP_NOTIFICATION),
316 CMD(REDUCE_TX_POWER_CMD), 317 CMD(REDUCE_TX_POWER_CMD),
diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c
index fffd89d5bdfb..2486931fd861 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rx.c
+++ b/drivers/net/wireless/iwlwifi/mvm/rx.c
@@ -496,16 +496,9 @@ static void iwl_mvm_stat_iterator(void *_data, u8 *mac,
496 } 496 }
497} 497}
498 498
499/* 499void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm,
500 * iwl_mvm_rx_statistics - STATISTICS_NOTIFICATION handler 500 struct iwl_rx_packet *pkt)
501 *
502 * TODO: This handler is implemented partially.
503 */
504int iwl_mvm_rx_statistics(struct iwl_mvm *mvm,
505 struct iwl_rx_cmd_buffer *rxb,
506 struct iwl_device_cmd *cmd)
507{ 501{
508 struct iwl_rx_packet *pkt = rxb_addr(rxb);
509 size_t v8_len = sizeof(struct iwl_notif_statistics_v8); 502 size_t v8_len = sizeof(struct iwl_notif_statistics_v8);
510 size_t v10_len = sizeof(struct iwl_notif_statistics_v10); 503 size_t v10_len = sizeof(struct iwl_notif_statistics_v10);
511 struct iwl_mvm_stat_data data = { 504 struct iwl_mvm_stat_data data = {
@@ -525,6 +518,13 @@ int iwl_mvm_rx_statistics(struct iwl_mvm *mvm,
525 stats->general.beacon_filter_average_energy; 518 stats->general.beacon_filter_average_energy;
526 519
527 iwl_mvm_update_rx_statistics(mvm, &stats->rx); 520 iwl_mvm_update_rx_statistics(mvm, &stats->rx);
521
522 mvm->radio_stats.rx_time = le64_to_cpu(stats->general.rx_time);
523 mvm->radio_stats.tx_time = le64_to_cpu(stats->general.tx_time);
524 mvm->radio_stats.on_time_rf =
525 le64_to_cpu(stats->general.on_time_rf);
526 mvm->radio_stats.on_time_scan =
527 le64_to_cpu(stats->general.on_time_scan);
528 } else { 528 } else {
529 struct iwl_notif_statistics_v8 *stats = (void *)&pkt->data; 529 struct iwl_notif_statistics_v8 *stats = (void *)&pkt->data;
530 530
@@ -549,9 +549,16 @@ int iwl_mvm_rx_statistics(struct iwl_mvm *mvm,
549 IEEE80211_IFACE_ITER_NORMAL, 549 IEEE80211_IFACE_ITER_NORMAL,
550 iwl_mvm_stat_iterator, 550 iwl_mvm_stat_iterator,
551 &data); 551 &data);
552 return 0; 552 return;
553 invalid: 553 invalid:
554 IWL_ERR(mvm, "received invalid statistics size (%d)!\n", 554 IWL_ERR(mvm, "received invalid statistics size (%d)!\n",
555 iwl_rx_packet_payload_len(pkt)); 555 iwl_rx_packet_payload_len(pkt));
556}
557
558int iwl_mvm_rx_statistics(struct iwl_mvm *mvm,
559 struct iwl_rx_cmd_buffer *rxb,
560 struct iwl_device_cmd *cmd)
561{
562 iwl_mvm_handle_rx_statistics(mvm, rxb_addr(rxb));
556 return 0; 563 return 0;
557} 564}
diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c
index 8decf9953229..2b75a0d6d41e 100644
--- a/drivers/net/wireless/iwlwifi/mvm/utils.c
+++ b/drivers/net/wireless/iwlwifi/mvm/utils.c
@@ -643,6 +643,35 @@ void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
643 ieee80211_request_smps(vif, smps_mode); 643 ieee80211_request_smps(vif, smps_mode);
644} 644}
645 645
646int iwl_mvm_request_statistics(struct iwl_mvm *mvm)
647{
648 struct iwl_statistics_cmd scmd = {};
649 struct iwl_host_cmd cmd = {
650 .id = STATISTICS_CMD,
651 .len[0] = sizeof(scmd),
652 .data[0] = &scmd,
653 .flags = CMD_WANT_SKB,
654 };
655 int ret;
656
657 ret = iwl_mvm_send_cmd(mvm, &cmd);
658 if (ret)
659 return ret;
660
661 iwl_mvm_handle_rx_statistics(mvm, cmd.resp_pkt);
662 iwl_free_resp(&cmd);
663
664 return 0;
665}
666
667void iwl_mvm_accu_radio_stats(struct iwl_mvm *mvm)
668{
669 mvm->accu_radio_stats.rx_time += mvm->radio_stats.rx_time;
670 mvm->accu_radio_stats.tx_time += mvm->radio_stats.tx_time;
671 mvm->accu_radio_stats.on_time_rf += mvm->radio_stats.on_time_rf;
672 mvm->accu_radio_stats.on_time_scan += mvm->radio_stats.on_time_scan;
673}
674
646static void iwl_mvm_diversity_iter(void *_data, u8 *mac, 675static void iwl_mvm_diversity_iter(void *_data, u8 *mac,
647 struct ieee80211_vif *vif) 676 struct ieee80211_vif *vif)
648{ 677{