Skip to content

Commit fc61222

Browse files
benzeajmberg-intel
authored andcommitted
wifi: iwlwifi: mvm: record and return channel survey information
While doing a passive scan, the firmware will report per-channel survey information. This information is primarily useful for hostapd when doing an ACS (Automatic Channel Selection). Collect this information and add it to the result set when getting the survey information. Signed-off-by: Benjamin Berg <[email protected]> Signed-off-by: Miri Korenblit <[email protected]> Link: https://msgid.link/20240506095953.9287591a5999.I54a3f9f6480d3694e67eea1cb4f5853beace2780@changeid Signed-off-by: Johannes Berg <[email protected]>
1 parent 9732088 commit fc61222

File tree

6 files changed

+430
-8
lines changed

6 files changed

+430
-8
lines changed

drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c

Lines changed: 67 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5899,6 +5899,65 @@ void iwl_mvm_mac_flush_sta(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
58995899
mutex_unlock(&mvm->mutex);
59005900
}
59015901

5902+
static int iwl_mvm_mac_get_acs_survey(struct iwl_mvm *mvm, int idx,
5903+
struct survey_info *survey)
5904+
{
5905+
int chan_idx;
5906+
enum nl80211_band band;
5907+
int ret;
5908+
5909+
mutex_lock(&mvm->mutex);
5910+
5911+
if (!mvm->acs_survey) {
5912+
ret = -ENOENT;
5913+
goto out;
5914+
}
5915+
5916+
/* Find and return the next entry that has a non-zero active time */
5917+
for (band = 0; band < NUM_NL80211_BANDS; band++) {
5918+
struct ieee80211_supported_band *sband =
5919+
mvm->hw->wiphy->bands[band];
5920+
5921+
if (!sband)
5922+
continue;
5923+
5924+
for (chan_idx = 0; chan_idx < sband->n_channels; chan_idx++) {
5925+
struct iwl_mvm_acs_survey_channel *info =
5926+
&mvm->acs_survey->bands[band][chan_idx];
5927+
5928+
if (!info->time)
5929+
continue;
5930+
5931+
/* Found (the next) channel to report */
5932+
survey->channel = &sband->channels[chan_idx];
5933+
survey->filled = SURVEY_INFO_TIME |
5934+
SURVEY_INFO_TIME_BUSY |
5935+
SURVEY_INFO_TIME_RX |
5936+
SURVEY_INFO_TIME_TX;
5937+
survey->time = info->time;
5938+
survey->time_busy = info->time_busy;
5939+
survey->time_rx = info->time_rx;
5940+
survey->time_tx = info->time_tx;
5941+
survey->noise = info->noise;
5942+
if (survey->noise < 0)
5943+
survey->filled |= SURVEY_INFO_NOISE_DBM;
5944+
5945+
/* Clear time so that channel is only reported once */
5946+
info->time = 0;
5947+
5948+
ret = 0;
5949+
goto out;
5950+
}
5951+
}
5952+
5953+
ret = -ENOENT;
5954+
5955+
out:
5956+
mutex_unlock(&mvm->mutex);
5957+
5958+
return ret;
5959+
}
5960+
59025961
int iwl_mvm_mac_get_survey(struct ieee80211_hw *hw, int idx,
59035962
struct survey_info *survey)
59045963
{
@@ -5911,14 +5970,18 @@ int iwl_mvm_mac_get_survey(struct ieee80211_hw *hw, int idx,
59115970

59125971
memset(survey, 0, sizeof(*survey));
59135972

5914-
/* only support global statistics right now */
5915-
if (idx != 0)
5916-
return -ENOENT;
5917-
59185973
if (!fw_has_capa(&mvm->fw->ucode_capa,
59195974
IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS))
59205975
return -ENOENT;
59215976

5977+
/*
5978+
* Return the beacon stats at index zero and pass on following indices
5979+
* to the function returning the full survey, most likely for ACS
5980+
* (Automatic Channel Selection).
5981+
*/
5982+
if (idx > 0)
5983+
return iwl_mvm_mac_get_acs_survey(mvm, idx - 1, survey);
5984+
59225985
mutex_lock(&mvm->mutex);
59235986

59245987
if (iwl_mvm_firmware_running(mvm)) {

drivers/net/wireless/intel/iwlwifi/mvm/mvm.h

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -918,6 +918,35 @@ struct iwl_mei_scan_filter {
918918
struct work_struct scan_work;
919919
};
920920

921+
/**
922+
* struct iwl_mvm_acs_survey_channel - per-channel survey information
923+
*
924+
* Stripped down version of &struct survey_info.
925+
*
926+
* @time: time in ms the radio was on the channel
927+
* @time_busy: time in ms the channel was sensed busy
928+
* @time_tx: time in ms spent transmitting data
929+
* @time_rx: time in ms spent receiving data
930+
* @noise: channel noise in dBm
931+
*/
932+
struct iwl_mvm_acs_survey_channel {
933+
u32 time;
934+
u32 time_busy;
935+
u32 time_tx;
936+
u32 time_rx;
937+
s8 noise;
938+
};
939+
940+
struct iwl_mvm_acs_survey {
941+
struct iwl_mvm_acs_survey_channel *bands[NUM_NL80211_BANDS];
942+
943+
/* Overall number of channels */
944+
int n_channels;
945+
946+
/* Storage space for per-channel information follows */
947+
struct iwl_mvm_acs_survey_channel channels[] __counted_by(n_channels);
948+
};
949+
921950
struct iwl_mvm {
922951
/* for logger access */
923952
struct device *dev;
@@ -1287,6 +1316,8 @@ struct iwl_mvm {
12871316

12881317
struct iwl_mei_scan_filter mei_scan_filter;
12891318

1319+
struct iwl_mvm_acs_survey *acs_survey;
1320+
12901321
bool statistics_clear;
12911322
};
12921323

@@ -2033,6 +2064,8 @@ unsigned int iwl_mvm_get_link_grade(struct ieee80211_bss_conf *link_conf);
20332064
bool iwl_mvm_mld_valid_link_pair(struct ieee80211_vif *vif,
20342065
const struct iwl_mvm_link_sel_data *a,
20352066
const struct iwl_mvm_link_sel_data *b);
2067+
2068+
s8 iwl_mvm_average_dbm_values(const struct iwl_umac_scan_channel_survey_notif *notif);
20362069
#endif
20372070

20382071
/* AP and IBSS */
@@ -2115,6 +2148,8 @@ int iwl_mvm_max_scan_ie_len(struct iwl_mvm *mvm);
21152148
void iwl_mvm_report_scan_aborted(struct iwl_mvm *mvm);
21162149
void iwl_mvm_scan_timeout_wk(struct work_struct *work);
21172150
int iwl_mvm_int_mlo_scan(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
2151+
void iwl_mvm_rx_channel_survey_notif(struct iwl_mvm *mvm,
2152+
struct iwl_rx_cmd_buffer *rxb);
21182153

21192154
/* Scheduled scan */
21202155
void iwl_mvm_rx_lmac_scan_complete_notif(struct iwl_mvm *mvm,

drivers/net/wireless/intel/iwlwifi/mvm/ops.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,9 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {
473473
RX_HANDLER_GRP(MAC_CONF_GROUP, ROC_NOTIF,
474474
iwl_mvm_rx_roc_notif, RX_HANDLER_SYNC,
475475
struct iwl_roc_notif),
476+
RX_HANDLER_GRP(SCAN_GROUP, CHANNEL_SURVEY_NOTIF,
477+
iwl_mvm_rx_channel_survey_notif, RX_HANDLER_ASYNC_LOCKED,
478+
struct iwl_umac_scan_channel_survey_notif),
476479
};
477480
#undef RX_HANDLER
478481
#undef RX_HANDLER_GRP
@@ -1582,6 +1585,7 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode)
15821585
kfree(mvm->temp_nvm_data);
15831586
for (i = 0; i < NVM_MAX_NUM_SECTIONS; i++)
15841587
kfree(mvm->nvm_sections[i].data);
1588+
kfree(mvm->acs_survey);
15851589

15861590
cancel_delayed_work_sync(&mvm->tcm.work);
15871591

0 commit comments

Comments
 (0)