Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2e1dea40 authored by Michal Kazior's avatar Michal Kazior Committed by Kalle Valo
Browse files

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: default avatarMichal Kazior <michal.kazior@tieto.com>
Signed-off-by: default avatarKalle Valo <kvalo@qca.qualcomm.com>
parent 7c199997
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@
#define ATH10K_SCAN_ID 0
#define WMI_READY_TIMEOUT (5 * HZ)
#define ATH10K_FLUSH_TIMEOUT_HZ (5*HZ)
#define ATH10K_NUM_CHANS 38

/* Antenna noise floor */
#define ATH10K_DEFAULT_NOISE_FLOOR -95
@@ -375,6 +376,12 @@ struct ath10k {

	struct work_struct restart_work;

	/* cycle count is reported twice for each visited channel during scan.
	 * access protected by data_lock */
	u32 survey_last_rx_clear_count;
	u32 survey_last_cycle_count;
	struct survey_info survey[ATH10K_NUM_CHANS];

#ifdef CONFIG_ATH10K_DEBUGFS
	struct ath10k_debug debug;
#endif
+36 −0
Original line number Diff line number Diff line
@@ -2934,6 +2934,41 @@ static void ath10k_restart_complete(struct ieee80211_hw *hw)
	mutex_unlock(&ar->conf_mutex);
}

static int ath10k_get_survey(struct ieee80211_hw *hw, int idx,
			     struct survey_info *survey)
{
	struct ath10k *ar = hw->priv;
	struct ieee80211_supported_band *sband;
	struct survey_info *ar_survey = &ar->survey[idx];
	int ret = 0;

	mutex_lock(&ar->conf_mutex);

	sband = hw->wiphy->bands[IEEE80211_BAND_2GHZ];
	if (sband && idx >= sband->n_channels) {
		idx -= sband->n_channels;
		sband = NULL;
	}

	if (!sband)
		sband = hw->wiphy->bands[IEEE80211_BAND_5GHZ];

	if (!sband || idx >= sband->n_channels) {
		ret = -ENOENT;
		goto exit;
	}

	spin_lock_bh(&ar->data_lock);
	memcpy(survey, ar_survey, sizeof(*survey));
	spin_unlock_bh(&ar->data_lock);

	survey->channel = &sband->channels[idx];

exit:
	mutex_unlock(&ar->conf_mutex);
	return ret;
}

static const struct ieee80211_ops ath10k_ops = {
	.tx				= ath10k_tx,
	.start				= ath10k_start,
@@ -2955,6 +2990,7 @@ static const struct ieee80211_ops ath10k_ops = {
	.flush				= ath10k_flush,
	.tx_last_beacon			= ath10k_tx_last_beacon,
	.restart_complete		= ath10k_restart_complete,
	.get_survey			= ath10k_get_survey,
#ifdef CONFIG_PM
	.suspend			= ath10k_suspend,
	.resume				= ath10k_resume,
+74 −1
Original line number Diff line number Diff line
@@ -390,9 +390,82 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
	return 0;
}

static int freq_to_idx(struct ath10k *ar, int freq)
{
	struct ieee80211_supported_band *sband;
	int band, ch, idx = 0;

	for (band = IEEE80211_BAND_2GHZ; band < IEEE80211_NUM_BANDS; band++) {
		sband = ar->hw->wiphy->bands[band];
		if (!sband)
			continue;

		for (ch = 0; ch < sband->n_channels; ch++, idx++)
			if (sband->channels[ch].center_freq == freq)
				goto exit;
	}

exit:
	return idx;
}

static void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb)
{
	ath10k_dbg(ATH10K_DBG_WMI, "WMI_CHAN_INFO_EVENTID\n");
	struct wmi_chan_info_event *ev;
	struct survey_info *survey;
	u32 err_code, freq, cmd_flags, noise_floor, rx_clear_count, cycle_count;
	int idx;

	ev = (struct wmi_chan_info_event *)skb->data;

	err_code = __le32_to_cpu(ev->err_code);
	freq = __le32_to_cpu(ev->freq);
	cmd_flags = __le32_to_cpu(ev->cmd_flags);
	noise_floor = __le32_to_cpu(ev->noise_floor);
	rx_clear_count = __le32_to_cpu(ev->rx_clear_count);
	cycle_count = __le32_to_cpu(ev->cycle_count);

	ath10k_dbg(ATH10K_DBG_WMI,
		   "chan info err_code %d freq %d cmd_flags %d noise_floor %d rx_clear_count %d cycle_count %d\n",
		   err_code, freq, cmd_flags, noise_floor, rx_clear_count,
		   cycle_count);

	spin_lock_bh(&ar->data_lock);

	if (!ar->scan.in_progress) {
		ath10k_warn("chan info event without a scan request?\n");
		goto exit;
	}

	idx = freq_to_idx(ar, freq);
	if (idx >= ARRAY_SIZE(ar->survey)) {
		ath10k_warn("chan info: invalid frequency %d (idx %d out of bounds)\n",
			    freq, idx);
		goto exit;
	}

	if (cmd_flags & WMI_CHAN_INFO_FLAG_COMPLETE) {
		/* During scanning chan info is reported twice for each
		 * visited channel. The reported cycle count is global
		 * and per-channel cycle count must be calculated */

		cycle_count -= ar->survey_last_cycle_count;
		rx_clear_count -= ar->survey_last_rx_clear_count;

		survey = &ar->survey[idx];
		survey->channel_time = WMI_CHAN_INFO_MSEC(cycle_count);
		survey->channel_time_rx = WMI_CHAN_INFO_MSEC(rx_clear_count);
		survey->noise = noise_floor;
		survey->filled = SURVEY_INFO_CHANNEL_TIME |
				 SURVEY_INFO_CHANNEL_TIME_RX |
				 SURVEY_INFO_NOISE_DBM;
	}

	ar->survey_last_rx_clear_count = rx_clear_count;
	ar->survey_last_cycle_count = cycle_count;

exit:
	spin_unlock_bh(&ar->data_lock);
}

static void ath10k_wmi_event_echo(struct ath10k *ar, struct sk_buff *skb)
+5 −0
Original line number Diff line number Diff line
@@ -2931,6 +2931,11 @@ struct wmi_chan_info_event {
	__le32 cycle_count;
} __packed;

#define WMI_CHAN_INFO_FLAG_COMPLETE BIT(0)

/* FIXME: empirically extrapolated */
#define WMI_CHAN_INFO_MSEC(x) ((x) / 76595)

/* Beacon filter wmi command info */
#define BCN_FLT_MAX_SUPPORTED_IES	256
#define BCN_FLT_MAX_ELEMS_IE_LIST	(BCN_FLT_MAX_SUPPORTED_IES / 32)