diff options
author | Michal Kazior <michal.kazior@tieto.com> | 2013-07-31 04:32:40 -0400 |
---|---|---|
committer | Kalle Valo <kvalo@qca.qualcomm.com> | 2013-08-02 02:35:21 -0400 |
commit | 2e1dea40512d7e99a7e91ac88a6f434a5d7c6fde (patch) | |
tree | c8abfc11810c59cbacb2edf37de630e86f8bd3a5 /drivers | |
parent | 7c199997ded6c90fd45a50f49e9ac63adaacb95e (diff) |
ath10k: implement get_survey()
This implements a limited subset of what can be
reported in the survey dump.
This can be used for assessing approximate channel
load, e.g. for automatic channel selection.
Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/wireless/ath/ath10k/core.h | 7 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/mac.c | 36 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/wmi.c | 75 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/wmi.h | 5 |
4 files changed, 122 insertions, 1 deletions
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index ff42bb744d9e..e4bba563ed42 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h | |||
@@ -38,6 +38,7 @@ | |||
38 | #define ATH10K_SCAN_ID 0 | 38 | #define ATH10K_SCAN_ID 0 |
39 | #define WMI_READY_TIMEOUT (5 * HZ) | 39 | #define WMI_READY_TIMEOUT (5 * HZ) |
40 | #define ATH10K_FLUSH_TIMEOUT_HZ (5*HZ) | 40 | #define ATH10K_FLUSH_TIMEOUT_HZ (5*HZ) |
41 | #define ATH10K_NUM_CHANS 38 | ||
41 | 42 | ||
42 | /* Antenna noise floor */ | 43 | /* Antenna noise floor */ |
43 | #define ATH10K_DEFAULT_NOISE_FLOOR -95 | 44 | #define ATH10K_DEFAULT_NOISE_FLOOR -95 |
@@ -375,6 +376,12 @@ struct ath10k { | |||
375 | 376 | ||
376 | struct work_struct restart_work; | 377 | struct work_struct restart_work; |
377 | 378 | ||
379 | /* cycle count is reported twice for each visited channel during scan. | ||
380 | * access protected by data_lock */ | ||
381 | u32 survey_last_rx_clear_count; | ||
382 | u32 survey_last_cycle_count; | ||
383 | struct survey_info survey[ATH10K_NUM_CHANS]; | ||
384 | |||
378 | #ifdef CONFIG_ATH10K_DEBUGFS | 385 | #ifdef CONFIG_ATH10K_DEBUGFS |
379 | struct ath10k_debug debug; | 386 | struct ath10k_debug debug; |
380 | #endif | 387 | #endif |
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 57843377fa0b..9ea31f89b748 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c | |||
@@ -2934,6 +2934,41 @@ static void ath10k_restart_complete(struct ieee80211_hw *hw) | |||
2934 | mutex_unlock(&ar->conf_mutex); | 2934 | mutex_unlock(&ar->conf_mutex); |
2935 | } | 2935 | } |
2936 | 2936 | ||
2937 | static int ath10k_get_survey(struct ieee80211_hw *hw, int idx, | ||
2938 | struct survey_info *survey) | ||
2939 | { | ||
2940 | struct ath10k *ar = hw->priv; | ||
2941 | struct ieee80211_supported_band *sband; | ||
2942 | struct survey_info *ar_survey = &ar->survey[idx]; | ||
2943 | int ret = 0; | ||
2944 | |||
2945 | mutex_lock(&ar->conf_mutex); | ||
2946 | |||
2947 | sband = hw->wiphy->bands[IEEE80211_BAND_2GHZ]; | ||
2948 | if (sband && idx >= sband->n_channels) { | ||
2949 | idx -= sband->n_channels; | ||
2950 | sband = NULL; | ||
2951 | } | ||
2952 | |||
2953 | if (!sband) | ||
2954 | sband = hw->wiphy->bands[IEEE80211_BAND_5GHZ]; | ||
2955 | |||
2956 | if (!sband || idx >= sband->n_channels) { | ||
2957 | ret = -ENOENT; | ||
2958 | goto exit; | ||
2959 | } | ||
2960 | |||
2961 | spin_lock_bh(&ar->data_lock); | ||
2962 | memcpy(survey, ar_survey, sizeof(*survey)); | ||
2963 | spin_unlock_bh(&ar->data_lock); | ||
2964 | |||
2965 | survey->channel = &sband->channels[idx]; | ||
2966 | |||
2967 | exit: | ||
2968 | mutex_unlock(&ar->conf_mutex); | ||
2969 | return ret; | ||
2970 | } | ||
2971 | |||
2937 | static const struct ieee80211_ops ath10k_ops = { | 2972 | static const struct ieee80211_ops ath10k_ops = { |
2938 | .tx = ath10k_tx, | 2973 | .tx = ath10k_tx, |
2939 | .start = ath10k_start, | 2974 | .start = ath10k_start, |
@@ -2955,6 +2990,7 @@ static const struct ieee80211_ops ath10k_ops = { | |||
2955 | .flush = ath10k_flush, | 2990 | .flush = ath10k_flush, |
2956 | .tx_last_beacon = ath10k_tx_last_beacon, | 2991 | .tx_last_beacon = ath10k_tx_last_beacon, |
2957 | .restart_complete = ath10k_restart_complete, | 2992 | .restart_complete = ath10k_restart_complete, |
2993 | .get_survey = ath10k_get_survey, | ||
2958 | #ifdef CONFIG_PM | 2994 | #ifdef CONFIG_PM |
2959 | .suspend = ath10k_suspend, | 2995 | .suspend = ath10k_suspend, |
2960 | .resume = ath10k_resume, | 2996 | .resume = ath10k_resume, |
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 1cbcb2ea12f7..55f90c761868 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c | |||
@@ -390,9 +390,82 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) | |||
390 | return 0; | 390 | return 0; |
391 | } | 391 | } |
392 | 392 | ||
393 | static int freq_to_idx(struct ath10k *ar, int freq) | ||
394 | { | ||
395 | struct ieee80211_supported_band *sband; | ||
396 | int band, ch, idx = 0; | ||
397 | |||
398 | for (band = IEEE80211_BAND_2GHZ; band < IEEE80211_NUM_BANDS; band++) { | ||
399 | sband = ar->hw->wiphy->bands[band]; | ||
400 | if (!sband) | ||
401 | continue; | ||
402 | |||
403 | for (ch = 0; ch < sband->n_channels; ch++, idx++) | ||
404 | if (sband->channels[ch].center_freq == freq) | ||
405 | goto exit; | ||
406 | } | ||
407 | |||
408 | exit: | ||
409 | return idx; | ||
410 | } | ||
411 | |||
393 | static void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb) | 412 | static void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb) |
394 | { | 413 | { |
395 | ath10k_dbg(ATH10K_DBG_WMI, "WMI_CHAN_INFO_EVENTID\n"); | 414 | struct wmi_chan_info_event *ev; |
415 | struct survey_info *survey; | ||
416 | u32 err_code, freq, cmd_flags, noise_floor, rx_clear_count, cycle_count; | ||
417 | int idx; | ||
418 | |||
419 | ev = (struct wmi_chan_info_event *)skb->data; | ||
420 | |||
421 | err_code = __le32_to_cpu(ev->err_code); | ||
422 | freq = __le32_to_cpu(ev->freq); | ||
423 | cmd_flags = __le32_to_cpu(ev->cmd_flags); | ||
424 | noise_floor = __le32_to_cpu(ev->noise_floor); | ||
425 | rx_clear_count = __le32_to_cpu(ev->rx_clear_count); | ||
426 | cycle_count = __le32_to_cpu(ev->cycle_count); | ||
427 | |||
428 | ath10k_dbg(ATH10K_DBG_WMI, | ||
429 | "chan info err_code %d freq %d cmd_flags %d noise_floor %d rx_clear_count %d cycle_count %d\n", | ||
430 | err_code, freq, cmd_flags, noise_floor, rx_clear_count, | ||
431 | cycle_count); | ||
432 | |||
433 | spin_lock_bh(&ar->data_lock); | ||
434 | |||
435 | if (!ar->scan.in_progress) { | ||
436 | ath10k_warn("chan info event without a scan request?\n"); | ||
437 | goto exit; | ||
438 | } | ||
439 | |||
440 | idx = freq_to_idx(ar, freq); | ||
441 | if (idx >= ARRAY_SIZE(ar->survey)) { | ||
442 | ath10k_warn("chan info: invalid frequency %d (idx %d out of bounds)\n", | ||
443 | freq, idx); | ||
444 | goto exit; | ||
445 | } | ||
446 | |||
447 | if (cmd_flags & WMI_CHAN_INFO_FLAG_COMPLETE) { | ||
448 | /* During scanning chan info is reported twice for each | ||
449 | * visited channel. The reported cycle count is global | ||
450 | * and per-channel cycle count must be calculated */ | ||
451 | |||
452 | cycle_count -= ar->survey_last_cycle_count; | ||
453 | rx_clear_count -= ar->survey_last_rx_clear_count; | ||
454 | |||
455 | survey = &ar->survey[idx]; | ||
456 | survey->channel_time = WMI_CHAN_INFO_MSEC(cycle_count); | ||
457 | survey->channel_time_rx = WMI_CHAN_INFO_MSEC(rx_clear_count); | ||
458 | survey->noise = noise_floor; | ||
459 | survey->filled = SURVEY_INFO_CHANNEL_TIME | | ||
460 | SURVEY_INFO_CHANNEL_TIME_RX | | ||
461 | SURVEY_INFO_NOISE_DBM; | ||
462 | } | ||
463 | |||
464 | ar->survey_last_rx_clear_count = rx_clear_count; | ||
465 | ar->survey_last_cycle_count = cycle_count; | ||
466 | |||
467 | exit: | ||
468 | spin_unlock_bh(&ar->data_lock); | ||
396 | } | 469 | } |
397 | 470 | ||
398 | static void ath10k_wmi_event_echo(struct ath10k *ar, struct sk_buff *skb) | 471 | static void ath10k_wmi_event_echo(struct ath10k *ar, struct sk_buff *skb) |
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index da3b2bc4c88a..2c5a4f8daf2e 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h | |||
@@ -2931,6 +2931,11 @@ struct wmi_chan_info_event { | |||
2931 | __le32 cycle_count; | 2931 | __le32 cycle_count; |
2932 | } __packed; | 2932 | } __packed; |
2933 | 2933 | ||
2934 | #define WMI_CHAN_INFO_FLAG_COMPLETE BIT(0) | ||
2935 | |||
2936 | /* FIXME: empirically extrapolated */ | ||
2937 | #define WMI_CHAN_INFO_MSEC(x) ((x) / 76595) | ||
2938 | |||
2934 | /* Beacon filter wmi command info */ | 2939 | /* Beacon filter wmi command info */ |
2935 | #define BCN_FLT_MAX_SUPPORTED_IES 256 | 2940 | #define BCN_FLT_MAX_SUPPORTED_IES 256 |
2936 | #define BCN_FLT_MAX_ELEMS_IE_LIST (BCN_FLT_MAX_SUPPORTED_IES / 32) | 2941 | #define BCN_FLT_MAX_ELEMS_IE_LIST (BCN_FLT_MAX_SUPPORTED_IES / 32) |