aboutsummaryrefslogtreecommitdiffstats
path: root/package/kernel
diff options
context:
space:
mode:
authorMarkov Mikhail <markov.mikhail@itmh.ru>2020-10-12 14:46:43 +0500
committerDaniel Golle <daniel@makrotopia.org>2020-10-21 11:56:26 +0100
commit610843f3bc72d2a7c32fbb7c61d0c4416a88d1d9 (patch)
tree53dcaba93330ec637fe4d8722a4888b4f28afbd4 /package/kernel
parentb90a4a8e084640d74d28003f41b81183546f5840 (diff)
downloadupstream-610843f3bc72d2a7c32fbb7c61d0c4416a88d1d9.tar.gz
upstream-610843f3bc72d2a7c32fbb7c61d0c4416a88d1d9.tar.bz2
upstream-610843f3bc72d2a7c32fbb7c61d0c4416a88d1d9.zip
mac80211: rt2x00: save survey for every channel visited
rt2800 olny gives you survey for current channel. Survey-based ACS algorithms are failing to perform their job when working with rt2800. Make rt2800 save survey for every channel visited and be able to give away that information. There is a bug registred https://dev.archive.openwrt.org/ticket/19081 and this patch solves the issue. Signed-off-by: Markov Mikhail <markov.mikhail@itmh.ru>
Diffstat (limited to 'package/kernel')
-rw-r--r--package/kernel/mac80211/patches/rt2x00/992-rt2x00-save-survey-for-every-channel-visited.patch183
1 files changed, 183 insertions, 0 deletions
diff --git a/package/kernel/mac80211/patches/rt2x00/992-rt2x00-save-survey-for-every-channel-visited.patch b/package/kernel/mac80211/patches/rt2x00/992-rt2x00-save-survey-for-every-channel-visited.patch
new file mode 100644
index 0000000000..31a7baeee7
--- /dev/null
+++ b/package/kernel/mac80211/patches/rt2x00/992-rt2x00-save-survey-for-every-channel-visited.patch
@@ -0,0 +1,183 @@
+--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
++++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+@@ -1238,6 +1238,8 @@ void rt2800_watchdog(struct rt2x00_dev *
+ if (test_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags))
+ return;
+
++ rt2800_update_survey(rt2x00dev);
++
+ queue_for_each(rt2x00dev, queue) {
+ switch (queue->qid) {
+ case QID_AC_VO:
+@@ -1274,6 +1276,18 @@ void rt2800_watchdog(struct rt2x00_dev *
+ }
+ EXPORT_SYMBOL_GPL(rt2800_watchdog);
+
++void rt2800_update_survey(struct rt2x00_dev *rt2x00dev)
++{
++ struct ieee80211_channel *chan = rt2x00dev->hw->conf.chandef.chan;
++ struct rt2x00_chan_survey *chan_survey =
++ &rt2x00dev->chan_survey[chan->hw_value];
++
++ chan_survey->time_idle += rt2800_register_read(rt2x00dev, CH_IDLE_STA);
++ chan_survey->time_busy += rt2800_register_read(rt2x00dev, CH_BUSY_STA);
++ chan_survey->time_ext_busy += rt2800_register_read(rt2x00dev, CH_BUSY_STA_SEC);
++}
++EXPORT_SYMBOL_GPL(rt2800_update_survey);
++
+ static unsigned int rt2800_hw_beacon_base(struct rt2x00_dev *rt2x00dev,
+ unsigned int index)
+ {
+@@ -12199,26 +12213,30 @@ int rt2800_get_survey(struct ieee80211_h
+ {
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ struct ieee80211_conf *conf = &hw->conf;
+- u32 idle, busy, busy_ext;
++ struct rt2x00_chan_survey *chan_survey =
++ &rt2x00dev->chan_survey[idx];
++ enum nl80211_band band = NL80211_BAND_2GHZ;
+
+- if (idx != 0)
++ if (idx >= rt2x00dev->bands[band].n_channels) {
++ idx -= rt2x00dev->bands[band].n_channels;
++ band = NL80211_BAND_5GHZ;
++ }
++
++ if (idx >= rt2x00dev->bands[band].n_channels)
+ return -ENOENT;
+
+- survey->channel = conf->chandef.chan;
++ if (idx == 0)
++ rt2800_update_survey(rt2x00dev);
+
+- idle = rt2800_register_read(rt2x00dev, CH_IDLE_STA);
+- busy = rt2800_register_read(rt2x00dev, CH_BUSY_STA);
+- busy_ext = rt2800_register_read(rt2x00dev, CH_BUSY_STA_SEC);
+-
+- if (idle || busy) {
+- survey->filled = SURVEY_INFO_TIME |
+- SURVEY_INFO_TIME_BUSY |
+- SURVEY_INFO_TIME_EXT_BUSY;
+-
+- survey->time = (idle + busy) / 1000;
+- survey->time_busy = busy / 1000;
+- survey->time_ext_busy = busy_ext / 1000;
+- }
++ survey->channel = &rt2x00dev->bands[band].channels[idx];
++
++ survey->filled = SURVEY_INFO_TIME |
++ SURVEY_INFO_TIME_BUSY |
++ SURVEY_INFO_TIME_EXT_BUSY;
++
++ survey->time = div_u64(chan_survey->time_idle + chan_survey->time_busy, 1000);
++ survey->time_busy = div_u64(chan_survey->time_busy, 1000);
++ survey->time_ext_busy = div_u64(chan_survey->time_ext_busy, 1000);
+
+ if (!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL))
+ survey->filled |= SURVEY_INFO_IN_USE;
+--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
++++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
+@@ -243,6 +243,7 @@ bool rt2800_txstatus_timeout(struct rt2x
+ bool rt2800_txstatus_pending(struct rt2x00_dev *rt2x00dev);
+
+ void rt2800_watchdog(struct rt2x00_dev *rt2x00dev);
++void rt2800_update_survey(struct rt2x00_dev *rt2x00dev);
+
+ void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc);
+ void rt2800_clear_beacon(struct queue_entry *entry);
+--- a/drivers/net/wireless/ralink/rt2x00/rt2800pci.c
++++ b/drivers/net/wireless/ralink/rt2x00/rt2800pci.c
+@@ -360,6 +360,7 @@ static const struct rt2x00lib_ops rt2800
+ .gain_calibration = rt2800_gain_calibration,
+ .vco_calibration = rt2800_vco_calibration,
+ .watchdog = rt2800_watchdog,
++ .update_survey = rt2800_update_survey,
+ .start_queue = rt2800mmio_start_queue,
+ .kick_queue = rt2800mmio_kick_queue,
+ .stop_queue = rt2800mmio_stop_queue,
+--- a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
++++ b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
+@@ -214,6 +214,7 @@ static const struct rt2x00lib_ops rt2800
+ .gain_calibration = rt2800_gain_calibration,
+ .vco_calibration = rt2800_vco_calibration,
+ .watchdog = rt2800_watchdog,
++ .update_survey = rt2800_update_survey,
+ .start_queue = rt2800mmio_start_queue,
+ .kick_queue = rt2800mmio_kick_queue,
+ .stop_queue = rt2800mmio_stop_queue,
+--- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
++++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
+@@ -183,6 +183,15 @@ struct rf_channel {
+ };
+
+ /*
++ * Information structure for channel survey.
++ */
++struct rt2x00_chan_survey {
++ u64 time_idle;
++ u64 time_busy;
++ u64 time_ext_busy;
++};
++
++/*
+ * Channel information structure
+ */
+ struct channel_info {
+@@ -567,6 +576,7 @@ struct rt2x00lib_ops {
+ * Data queue handlers.
+ */
+ void (*watchdog) (struct rt2x00_dev *rt2x00dev);
++ void (*update_survey) (struct rt2x00_dev *rt2x00dev);
+ void (*start_queue) (struct data_queue *queue);
+ void (*kick_queue) (struct data_queue *queue);
+ void (*stop_queue) (struct data_queue *queue);
+@@ -755,6 +765,7 @@ struct rt2x00_dev {
+ */
+ struct ieee80211_hw *hw;
+ struct ieee80211_supported_band bands[NUM_NL80211_BANDS];
++ struct rt2x00_chan_survey *chan_survey;
+ enum nl80211_band curr_band;
+ int curr_freq;
+
+--- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
++++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
+@@ -1057,6 +1057,12 @@ static int rt2x00lib_probe_hw_modes(stru
+ if (!rates)
+ goto exit_free_channels;
+
++ rt2x00dev->chan_survey =
++ kcalloc(spec->num_channels, sizeof(struct rt2x00_chan_survey),
++ GFP_KERNEL);
++ if (!rt2x00dev->chan_survey)
++ goto exit_free_rates;
++
+ /*
+ * Initialize Rate list.
+ */
+@@ -1108,6 +1114,8 @@ static int rt2x00lib_probe_hw_modes(stru
+
+ return 0;
+
++ exit_free_rates:
++ kfree(rates);
+ exit_free_channels:
+ kfree(channels);
+ rt2x00_err(rt2x00dev, "Allocation ieee80211 modes failed\n");
+--- a/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c
++++ b/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c
+@@ -317,6 +317,15 @@ int rt2x00mac_config(struct ieee80211_hw
+ return 0;
+
+ /*
++ * To provide correct survey data for survey-based ACS algorithm
++ * we have to save survey data for current channel before switching.
++ */
++ if (rt2x00dev->ops->lib->update_survey &&
++ (changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
++ rt2x00dev->ops->lib->update_survey(rt2x00dev);
++ }
++
++ /*
+ * Some configuration parameters (e.g. channel and antenna values) can
+ * only be set when the radio is enabled, but do require the RX to
+ * be off. During this period we should keep link tuning enabled,