diff options
author | Johannes Berg <johannes.berg@intel.com> | 2015-01-14 11:58:57 -0500 |
---|---|---|
committer | Emmanuel Grumbach <emmanuel.grumbach@intel.com> | 2015-03-01 09:55:08 -0500 |
commit | 777c9b6bba5266ea8eecb19b3fa8b63ad5251bd6 (patch) | |
tree | c92233bf65b0b3080b04618ae7bc2b032375fe84 | |
parent | a2227ce2a32cf9faeab1299894fe09d03e6a12b7 (diff) |
iwlwifi: mvm: add statistics API version 10
New firmware versions will report statistics using a new version 10
of the API, instead of the current version 8. Add support for this.
This enables getting beacon and radio statistics.
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.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/fw-api-stats.h | 47 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/rx.c | 62 |
4 files changed, 90 insertions, 22 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h index 016d91384681..4602e3c7afda 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h | |||
@@ -250,6 +250,7 @@ enum iwl_ucode_tlv_flag { | |||
250 | * @IWL_UCODE_TLV_API_SINGLE_SCAN_EBS: EBS is supported for single scans too. | 250 | * @IWL_UCODE_TLV_API_SINGLE_SCAN_EBS: EBS is supported for single scans too. |
251 | * @IWL_UCODE_TLV_API_ASYNC_DTM: Async temperature notifications are supported. | 251 | * @IWL_UCODE_TLV_API_ASYNC_DTM: Async temperature notifications are supported. |
252 | * @IWL_UCODE_TLV_API_LQ_SS_PARAMS: Configure STBC/BFER via LQ CMD ss_params | 252 | * @IWL_UCODE_TLV_API_LQ_SS_PARAMS: Configure STBC/BFER via LQ CMD ss_params |
253 | * @IWL_UCODE_TLV_API_STATS_V10: uCode supports/uses statistics API version 10 | ||
253 | */ | 254 | */ |
254 | enum iwl_ucode_tlv_api { | 255 | enum iwl_ucode_tlv_api { |
255 | IWL_UCODE_TLV_API_BT_COEX_SPLIT = BIT(3), | 256 | IWL_UCODE_TLV_API_BT_COEX_SPLIT = BIT(3), |
@@ -263,6 +264,7 @@ enum iwl_ucode_tlv_api { | |||
263 | IWL_UCODE_TLV_API_SINGLE_SCAN_EBS = BIT(16), | 264 | IWL_UCODE_TLV_API_SINGLE_SCAN_EBS = BIT(16), |
264 | IWL_UCODE_TLV_API_ASYNC_DTM = BIT(17), | 265 | IWL_UCODE_TLV_API_ASYNC_DTM = BIT(17), |
265 | IWL_UCODE_TLV_API_LQ_SS_PARAMS = BIT(18), | 266 | IWL_UCODE_TLV_API_LQ_SS_PARAMS = BIT(18), |
267 | IWL_UCODE_TLV_API_STATS_V10 = BIT(19), | ||
266 | }; | 268 | }; |
267 | 269 | ||
268 | /** | 270 | /** |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h index c405cda1025f..aabaedd3b3ee 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h | |||
@@ -70,6 +70,7 @@ | |||
70 | #define MAC_INDEX_AUX 4 | 70 | #define MAC_INDEX_AUX 4 |
71 | #define MAC_INDEX_MIN_DRIVER 0 | 71 | #define MAC_INDEX_MIN_DRIVER 0 |
72 | #define NUM_MAC_INDEX_DRIVER MAC_INDEX_AUX | 72 | #define NUM_MAC_INDEX_DRIVER MAC_INDEX_AUX |
73 | #define NUM_MAC_INDEX (MAC_INDEX_AUX + 1) | ||
73 | 74 | ||
74 | enum iwl_ac { | 75 | enum iwl_ac { |
75 | AC_BK, | 76 | AC_BK, |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-stats.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-stats.h index 928168b18346..5a9dfe074022 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-stats.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-stats.h | |||
@@ -65,6 +65,7 @@ | |||
65 | 65 | ||
66 | #ifndef __fw_api_stats_h__ | 66 | #ifndef __fw_api_stats_h__ |
67 | #define __fw_api_stats_h__ | 67 | #define __fw_api_stats_h__ |
68 | #include "fw-api-mac.h" | ||
68 | 69 | ||
69 | struct mvm_statistics_dbg { | 70 | struct mvm_statistics_dbg { |
70 | __le32 burst_check; | 71 | __le32 burst_check; |
@@ -218,7 +219,7 @@ struct mvm_statistics_bt_activity { | |||
218 | __le32 lo_priority_rx_denied_cnt; | 219 | __le32 lo_priority_rx_denied_cnt; |
219 | } __packed; /* STATISTICS_BT_ACTIVITY_API_S_VER_1 */ | 220 | } __packed; /* STATISTICS_BT_ACTIVITY_API_S_VER_1 */ |
220 | 221 | ||
221 | struct mvm_statistics_general { | 222 | struct mvm_statistics_general_v5 { |
222 | __le32 radio_temperature; | 223 | __le32 radio_temperature; |
223 | __le32 radio_voltage; | 224 | __le32 radio_voltage; |
224 | struct mvm_statistics_dbg dbg; | 225 | struct mvm_statistics_dbg dbg; |
@@ -244,6 +245,39 @@ struct mvm_statistics_general { | |||
244 | struct mvm_statistics_bt_activity bt_activity; | 245 | struct mvm_statistics_bt_activity bt_activity; |
245 | } __packed; /* STATISTICS_GENERAL_API_S_VER_5 */ | 246 | } __packed; /* STATISTICS_GENERAL_API_S_VER_5 */ |
246 | 247 | ||
248 | struct mvm_statistics_general_v8 { | ||
249 | __le32 radio_temperature; | ||
250 | __le32 radio_voltage; | ||
251 | struct mvm_statistics_dbg dbg; | ||
252 | __le32 sleep_time; | ||
253 | __le32 slots_out; | ||
254 | __le32 slots_idle; | ||
255 | __le32 ttl_timestamp; | ||
256 | struct mvm_statistics_div slow_div; | ||
257 | __le32 rx_enable_counter; | ||
258 | /* | ||
259 | * num_of_sos_states: | ||
260 | * count the number of times we have to re-tune | ||
261 | * in order to get out of bad PHY status | ||
262 | */ | ||
263 | __le32 num_of_sos_states; | ||
264 | __le32 beacon_filtered; | ||
265 | __le32 missed_beacons; | ||
266 | __s8 beacon_filter_average_energy; | ||
267 | __s8 beacon_filter_reason; | ||
268 | __s8 beacon_filter_current_energy; | ||
269 | __s8 beacon_filter_reserved; | ||
270 | __le32 beacon_filter_delta_time; | ||
271 | struct mvm_statistics_bt_activity bt_activity; | ||
272 | __le64 rx_time; | ||
273 | __le64 on_time_rf; | ||
274 | __le64 on_time_scan; | ||
275 | __le64 tx_time; | ||
276 | __le32 beacon_counter[NUM_MAC_INDEX]; | ||
277 | u8 beacon_average_energy[NUM_MAC_INDEX]; | ||
278 | u8 reserved[4 - (NUM_MAC_INDEX % 4)]; | ||
279 | } __packed; /* STATISTICS_GENERAL_API_S_VER_8 */ | ||
280 | |||
247 | struct mvm_statistics_rx { | 281 | struct mvm_statistics_rx { |
248 | struct mvm_statistics_rx_phy ofdm; | 282 | struct mvm_statistics_rx_phy ofdm; |
249 | struct mvm_statistics_rx_phy cck; | 283 | struct mvm_statistics_rx_phy cck; |
@@ -267,11 +301,18 @@ struct mvm_statistics_rx { | |||
267 | * one channel that has just been scanned. | 301 | * one channel that has just been scanned. |
268 | */ | 302 | */ |
269 | 303 | ||
270 | struct iwl_notif_statistics { | 304 | struct iwl_notif_statistics_v8 { |
271 | __le32 flag; | 305 | __le32 flag; |
272 | struct mvm_statistics_rx rx; | 306 | struct mvm_statistics_rx rx; |
273 | struct mvm_statistics_tx tx; | 307 | struct mvm_statistics_tx tx; |
274 | struct mvm_statistics_general general; | 308 | struct mvm_statistics_general_v5 general; |
275 | } __packed; /* STATISTICS_NTFY_API_S_VER_8 */ | 309 | } __packed; /* STATISTICS_NTFY_API_S_VER_8 */ |
276 | 310 | ||
311 | struct iwl_notif_statistics_v10 { | ||
312 | __le32 flag; | ||
313 | struct mvm_statistics_rx rx; | ||
314 | struct mvm_statistics_tx tx; | ||
315 | struct mvm_statistics_general_v8 general; | ||
316 | } __packed; /* STATISTICS_NTFY_API_S_VER_10 */ | ||
317 | |||
277 | #endif /* __fw_api_stats_h__ */ | 318 | #endif /* __fw_api_stats_h__ */ |
diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c index f922131b4eab..fffd89d5bdfb 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/iwlwifi/mvm/rx.c | |||
@@ -6,7 +6,7 @@ | |||
6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
7 | * | 7 | * |
8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
9 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | 9 | * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH |
10 | * | 10 | * |
11 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
12 | * it under the terms of version 2 of the GNU General Public License as | 12 | * it under the terms of version 2 of the GNU General Public License as |
@@ -32,7 +32,7 @@ | |||
32 | * BSD LICENSE | 32 | * BSD LICENSE |
33 | * | 33 | * |
34 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 34 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
35 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | 35 | * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH |
36 | * All rights reserved. | 36 | * All rights reserved. |
37 | * | 37 | * |
38 | * Redistribution and use in source and binary forms, with or without | 38 | * Redistribution and use in source and binary forms, with or without |
@@ -416,33 +416,29 @@ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | |||
416 | } | 416 | } |
417 | 417 | ||
418 | static void iwl_mvm_update_rx_statistics(struct iwl_mvm *mvm, | 418 | static void iwl_mvm_update_rx_statistics(struct iwl_mvm *mvm, |
419 | struct iwl_notif_statistics *stats) | 419 | struct mvm_statistics_rx *rx_stats) |
420 | { | 420 | { |
421 | /* | ||
422 | * NOTE FW aggregates the statistics - BUT the statistics are cleared | ||
423 | * when the driver issues REPLY_STATISTICS_CMD 0x9c with CLEAR_STATS | ||
424 | * bit set. | ||
425 | */ | ||
426 | lockdep_assert_held(&mvm->mutex); | 421 | lockdep_assert_held(&mvm->mutex); |
427 | memcpy(&mvm->rx_stats, &stats->rx, sizeof(struct mvm_statistics_rx)); | 422 | |
423 | mvm->rx_stats = *rx_stats; | ||
428 | } | 424 | } |
429 | 425 | ||
430 | struct iwl_mvm_stat_data { | 426 | struct iwl_mvm_stat_data { |
431 | struct iwl_notif_statistics *stats; | ||
432 | struct iwl_mvm *mvm; | 427 | struct iwl_mvm *mvm; |
428 | __le32 mac_id; | ||
429 | __s8 beacon_filter_average_energy; | ||
433 | }; | 430 | }; |
434 | 431 | ||
435 | static void iwl_mvm_stat_iterator(void *_data, u8 *mac, | 432 | static void iwl_mvm_stat_iterator(void *_data, u8 *mac, |
436 | struct ieee80211_vif *vif) | 433 | struct ieee80211_vif *vif) |
437 | { | 434 | { |
438 | struct iwl_mvm_stat_data *data = _data; | 435 | struct iwl_mvm_stat_data *data = _data; |
439 | struct iwl_notif_statistics *stats = data->stats; | ||
440 | struct iwl_mvm *mvm = data->mvm; | 436 | struct iwl_mvm *mvm = data->mvm; |
441 | int sig = -stats->general.beacon_filter_average_energy; | 437 | int sig = -data->beacon_filter_average_energy; |
442 | int last_event; | 438 | int last_event; |
443 | int thold = vif->bss_conf.cqm_rssi_thold; | 439 | int thold = vif->bss_conf.cqm_rssi_thold; |
444 | int hyst = vif->bss_conf.cqm_rssi_hyst; | 440 | int hyst = vif->bss_conf.cqm_rssi_hyst; |
445 | u16 id = le32_to_cpu(stats->rx.general.mac_id); | 441 | u16 id = le32_to_cpu(data->mac_id); |
446 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 442 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
447 | 443 | ||
448 | if (mvmvif->id != id) | 444 | if (mvmvif->id != id) |
@@ -510,24 +506,52 @@ int iwl_mvm_rx_statistics(struct iwl_mvm *mvm, | |||
510 | struct iwl_device_cmd *cmd) | 506 | struct iwl_device_cmd *cmd) |
511 | { | 507 | { |
512 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | 508 | struct iwl_rx_packet *pkt = rxb_addr(rxb); |
513 | struct iwl_notif_statistics *stats = (void *)&pkt->data; | 509 | size_t v8_len = sizeof(struct iwl_notif_statistics_v8); |
510 | size_t v10_len = sizeof(struct iwl_notif_statistics_v10); | ||
514 | struct iwl_mvm_stat_data data = { | 511 | struct iwl_mvm_stat_data data = { |
515 | .stats = stats, | ||
516 | .mvm = mvm, | 512 | .mvm = mvm, |
517 | }; | 513 | }; |
514 | u32 temperature; | ||
515 | |||
516 | if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_STATS_V10) { | ||
517 | struct iwl_notif_statistics_v10 *stats = (void *)&pkt->data; | ||
518 | |||
519 | if (iwl_rx_packet_payload_len(pkt) != v10_len) | ||
520 | goto invalid; | ||
521 | |||
522 | temperature = le32_to_cpu(stats->general.radio_temperature); | ||
523 | data.mac_id = stats->rx.general.mac_id; | ||
524 | data.beacon_filter_average_energy = | ||
525 | stats->general.beacon_filter_average_energy; | ||
526 | |||
527 | iwl_mvm_update_rx_statistics(mvm, &stats->rx); | ||
528 | } else { | ||
529 | struct iwl_notif_statistics_v8 *stats = (void *)&pkt->data; | ||
530 | |||
531 | if (iwl_rx_packet_payload_len(pkt) != v8_len) | ||
532 | goto invalid; | ||
533 | |||
534 | temperature = le32_to_cpu(stats->general.radio_temperature); | ||
535 | data.mac_id = stats->rx.general.mac_id; | ||
536 | data.beacon_filter_average_energy = | ||
537 | stats->general.beacon_filter_average_energy; | ||
538 | |||
539 | iwl_mvm_update_rx_statistics(mvm, &stats->rx); | ||
540 | } | ||
518 | 541 | ||
519 | /* Only handle rx statistics temperature changes if async temp | 542 | /* Only handle rx statistics temperature changes if async temp |
520 | * notifications are not supported | 543 | * notifications are not supported |
521 | */ | 544 | */ |
522 | if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_ASYNC_DTM)) | 545 | if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_ASYNC_DTM)) |
523 | iwl_mvm_tt_temp_changed(mvm, | 546 | iwl_mvm_tt_temp_changed(mvm, temperature); |
524 | le32_to_cpu(stats->general.radio_temperature)); | ||
525 | |||
526 | iwl_mvm_update_rx_statistics(mvm, stats); | ||
527 | 547 | ||
528 | ieee80211_iterate_active_interfaces(mvm->hw, | 548 | ieee80211_iterate_active_interfaces(mvm->hw, |
529 | IEEE80211_IFACE_ITER_NORMAL, | 549 | IEEE80211_IFACE_ITER_NORMAL, |
530 | iwl_mvm_stat_iterator, | 550 | iwl_mvm_stat_iterator, |
531 | &data); | 551 | &data); |
532 | return 0; | 552 | return 0; |
553 | invalid: | ||
554 | IWL_ERR(mvm, "received invalid statistics size (%d)!\n", | ||
555 | iwl_rx_packet_payload_len(pkt)); | ||
556 | return 0; | ||
533 | } | 557 | } |