• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 	Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
4 	<http://rt2x00.serialmonkey.com>
5 
6  */
7 
8 /*
9 	Module: rt2x00lib
10 	Abstract: rt2x00 generic link tuning routines.
11  */
12 
13 #include <linux/kernel.h>
14 #include <linux/module.h>
15 
16 #include "rt2x00.h"
17 #include "rt2x00lib.h"
18 
19 /*
20  * When we lack RSSI information return something less then -80 to
21  * tell the driver to tune the device to maximum sensitivity.
22  */
23 #define DEFAULT_RSSI		-128
24 
rt2x00link_get_avg_rssi(struct ewma_rssi * ewma)25 static inline int rt2x00link_get_avg_rssi(struct ewma_rssi *ewma)
26 {
27 	unsigned long avg;
28 
29 	avg = ewma_rssi_read(ewma);
30 	if (avg)
31 		return -avg;
32 
33 	return DEFAULT_RSSI;
34 }
35 
rt2x00link_antenna_get_link_rssi(struct rt2x00_dev * rt2x00dev)36 static int rt2x00link_antenna_get_link_rssi(struct rt2x00_dev *rt2x00dev)
37 {
38 	struct link_ant *ant = &rt2x00dev->link.ant;
39 
40 	if (rt2x00dev->link.qual.rx_success)
41 		return rt2x00link_get_avg_rssi(&ant->rssi_ant);
42 
43 	return DEFAULT_RSSI;
44 }
45 
rt2x00link_antenna_get_rssi_history(struct rt2x00_dev * rt2x00dev)46 static int rt2x00link_antenna_get_rssi_history(struct rt2x00_dev *rt2x00dev)
47 {
48 	struct link_ant *ant = &rt2x00dev->link.ant;
49 
50 	if (ant->rssi_history)
51 		return ant->rssi_history;
52 	return DEFAULT_RSSI;
53 }
54 
rt2x00link_antenna_update_rssi_history(struct rt2x00_dev * rt2x00dev,int rssi)55 static void rt2x00link_antenna_update_rssi_history(struct rt2x00_dev *rt2x00dev,
56 						   int rssi)
57 {
58 	struct link_ant *ant = &rt2x00dev->link.ant;
59 	ant->rssi_history = rssi;
60 }
61 
rt2x00link_antenna_reset(struct rt2x00_dev * rt2x00dev)62 static void rt2x00link_antenna_reset(struct rt2x00_dev *rt2x00dev)
63 {
64 	ewma_rssi_init(&rt2x00dev->link.ant.rssi_ant);
65 }
66 
rt2x00lib_antenna_diversity_sample(struct rt2x00_dev * rt2x00dev)67 static void rt2x00lib_antenna_diversity_sample(struct rt2x00_dev *rt2x00dev)
68 {
69 	struct link_ant *ant = &rt2x00dev->link.ant;
70 	struct antenna_setup new_ant;
71 	int other_antenna;
72 
73 	int sample_current = rt2x00link_antenna_get_link_rssi(rt2x00dev);
74 	int sample_other = rt2x00link_antenna_get_rssi_history(rt2x00dev);
75 
76 	memcpy(&new_ant, &ant->active, sizeof(new_ant));
77 
78 	/*
79 	 * We are done sampling. Now we should evaluate the results.
80 	 */
81 	ant->flags &= ~ANTENNA_MODE_SAMPLE;
82 
83 	/*
84 	 * During the last period we have sampled the RSSI
85 	 * from both antennas. It now is time to determine
86 	 * which antenna demonstrated the best performance.
87 	 * When we are already on the antenna with the best
88 	 * performance, just create a good starting point
89 	 * for the history and we are done.
90 	 */
91 	if (sample_current >= sample_other) {
92 		rt2x00link_antenna_update_rssi_history(rt2x00dev,
93 			sample_current);
94 		return;
95 	}
96 
97 	other_antenna = (ant->active.rx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A;
98 
99 	if (ant->flags & ANTENNA_RX_DIVERSITY)
100 		new_ant.rx = other_antenna;
101 
102 	if (ant->flags & ANTENNA_TX_DIVERSITY)
103 		new_ant.tx = other_antenna;
104 
105 	rt2x00lib_config_antenna(rt2x00dev, new_ant);
106 }
107 
rt2x00lib_antenna_diversity_eval(struct rt2x00_dev * rt2x00dev)108 static void rt2x00lib_antenna_diversity_eval(struct rt2x00_dev *rt2x00dev)
109 {
110 	struct link_ant *ant = &rt2x00dev->link.ant;
111 	struct antenna_setup new_ant;
112 	int rssi_curr;
113 	int rssi_old;
114 
115 	memcpy(&new_ant, &ant->active, sizeof(new_ant));
116 
117 	/*
118 	 * Get current RSSI value along with the historical value,
119 	 * after that update the history with the current value.
120 	 */
121 	rssi_curr = rt2x00link_antenna_get_link_rssi(rt2x00dev);
122 	rssi_old = rt2x00link_antenna_get_rssi_history(rt2x00dev);
123 	rt2x00link_antenna_update_rssi_history(rt2x00dev, rssi_curr);
124 
125 	/*
126 	 * Legacy driver indicates that we should swap antenna's
127 	 * when the difference in RSSI is greater that 5. This
128 	 * also should be done when the RSSI was actually better
129 	 * then the previous sample.
130 	 * When the difference exceeds the threshold we should
131 	 * sample the rssi from the other antenna to make a valid
132 	 * comparison between the 2 antennas.
133 	 */
134 	if (abs(rssi_curr - rssi_old) < 5)
135 		return;
136 
137 	ant->flags |= ANTENNA_MODE_SAMPLE;
138 
139 	if (ant->flags & ANTENNA_RX_DIVERSITY)
140 		new_ant.rx = (new_ant.rx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A;
141 
142 	if (ant->flags & ANTENNA_TX_DIVERSITY)
143 		new_ant.tx = (new_ant.tx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A;
144 
145 	rt2x00lib_config_antenna(rt2x00dev, new_ant);
146 }
147 
rt2x00lib_antenna_diversity(struct rt2x00_dev * rt2x00dev)148 static bool rt2x00lib_antenna_diversity(struct rt2x00_dev *rt2x00dev)
149 {
150 	struct link_ant *ant = &rt2x00dev->link.ant;
151 
152 	/*
153 	 * Determine if software diversity is enabled for
154 	 * either the TX or RX antenna (or both).
155 	 */
156 	if (!(ant->flags & ANTENNA_RX_DIVERSITY) &&
157 	    !(ant->flags & ANTENNA_TX_DIVERSITY)) {
158 		ant->flags = 0;
159 		return true;
160 	}
161 
162 	/*
163 	 * If we have only sampled the data over the last period
164 	 * we should now harvest the data. Otherwise just evaluate
165 	 * the data. The latter should only be performed once
166 	 * every 2 seconds.
167 	 */
168 	if (ant->flags & ANTENNA_MODE_SAMPLE) {
169 		rt2x00lib_antenna_diversity_sample(rt2x00dev);
170 		return true;
171 	} else if (rt2x00dev->link.count & 1) {
172 		rt2x00lib_antenna_diversity_eval(rt2x00dev);
173 		return true;
174 	}
175 
176 	return false;
177 }
178 
rt2x00link_update_stats(struct rt2x00_dev * rt2x00dev,struct sk_buff * skb,struct rxdone_entry_desc * rxdesc)179 void rt2x00link_update_stats(struct rt2x00_dev *rt2x00dev,
180 			     struct sk_buff *skb,
181 			     struct rxdone_entry_desc *rxdesc)
182 {
183 	struct link *link = &rt2x00dev->link;
184 	struct link_qual *qual = &rt2x00dev->link.qual;
185 	struct link_ant *ant = &rt2x00dev->link.ant;
186 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
187 
188 	/*
189 	 * No need to update the stats for !=STA interfaces
190 	 */
191 	if (!rt2x00dev->intf_sta_count)
192 		return;
193 
194 	/*
195 	 * Frame was received successfully since non-succesfull
196 	 * frames would have been dropped by the hardware.
197 	 */
198 	qual->rx_success++;
199 
200 	/*
201 	 * We are only interested in quality statistics from
202 	 * beacons which came from the BSS which we are
203 	 * associated with.
204 	 */
205 	if (!ieee80211_is_beacon(hdr->frame_control) ||
206 	    !(rxdesc->dev_flags & RXDONE_MY_BSS))
207 		return;
208 
209 	/*
210 	 * Update global RSSI
211 	 */
212 	ewma_rssi_add(&link->avg_rssi, -rxdesc->rssi);
213 
214 	/*
215 	 * Update antenna RSSI
216 	 */
217 	ewma_rssi_add(&ant->rssi_ant, -rxdesc->rssi);
218 }
219 
rt2x00link_start_tuner(struct rt2x00_dev * rt2x00dev)220 void rt2x00link_start_tuner(struct rt2x00_dev *rt2x00dev)
221 {
222 	struct link *link = &rt2x00dev->link;
223 
224 	/*
225 	 * Single monitor mode interfaces should never have
226 	 * work with link tuners.
227 	 */
228 	if (!rt2x00dev->intf_ap_count && !rt2x00dev->intf_sta_count)
229 		return;
230 
231 	/*
232 	 * While scanning, link tuning is disabled. By default
233 	 * the most sensitive settings will be used to make sure
234 	 * that all beacons and probe responses will be received
235 	 * during the scan.
236 	 */
237 	if (test_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags))
238 		return;
239 
240 	rt2x00link_reset_tuner(rt2x00dev, false);
241 
242 	if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
243 		ieee80211_queue_delayed_work(rt2x00dev->hw,
244 					     &link->work, LINK_TUNE_INTERVAL);
245 }
246 
rt2x00link_stop_tuner(struct rt2x00_dev * rt2x00dev)247 void rt2x00link_stop_tuner(struct rt2x00_dev *rt2x00dev)
248 {
249 	cancel_delayed_work_sync(&rt2x00dev->link.work);
250 }
251 
rt2x00link_reset_tuner(struct rt2x00_dev * rt2x00dev,bool antenna)252 void rt2x00link_reset_tuner(struct rt2x00_dev *rt2x00dev, bool antenna)
253 {
254 	struct link_qual *qual = &rt2x00dev->link.qual;
255 	u8 vgc_level = qual->vgc_level_reg;
256 
257 	if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
258 		return;
259 
260 	/*
261 	 * Reset link information.
262 	 * Both the currently active vgc level as well as
263 	 * the link tuner counter should be reset. Resetting
264 	 * the counter is important for devices where the
265 	 * device should only perform link tuning during the
266 	 * first minute after being enabled.
267 	 */
268 	rt2x00dev->link.count = 0;
269 	memset(qual, 0, sizeof(*qual));
270 	ewma_rssi_init(&rt2x00dev->link.avg_rssi);
271 
272 	/*
273 	 * Restore the VGC level as stored in the registers,
274 	 * the driver can use this to determine if the register
275 	 * must be updated during reset or not.
276 	 */
277 	qual->vgc_level_reg = vgc_level;
278 
279 	/*
280 	 * Reset the link tuner.
281 	 */
282 	rt2x00dev->ops->lib->reset_tuner(rt2x00dev, qual);
283 
284 	if (antenna)
285 		rt2x00link_antenna_reset(rt2x00dev);
286 }
287 
rt2x00link_reset_qual(struct rt2x00_dev * rt2x00dev)288 static void rt2x00link_reset_qual(struct rt2x00_dev *rt2x00dev)
289 {
290 	struct link_qual *qual = &rt2x00dev->link.qual;
291 
292 	qual->rx_success = 0;
293 	qual->rx_failed = 0;
294 	qual->tx_success = 0;
295 	qual->tx_failed = 0;
296 }
297 
rt2x00link_tuner_sta(struct rt2x00_dev * rt2x00dev,struct link * link)298 static void rt2x00link_tuner_sta(struct rt2x00_dev *rt2x00dev, struct link *link)
299 {
300 	struct link_qual *qual = &rt2x00dev->link.qual;
301 
302 	/*
303 	 * Update statistics.
304 	 */
305 	rt2x00dev->ops->lib->link_stats(rt2x00dev, qual);
306 	rt2x00dev->low_level_stats.dot11FCSErrorCount += qual->rx_failed;
307 
308 	/*
309 	 * Update quality RSSI for link tuning,
310 	 * when we have received some frames and we managed to
311 	 * collect the RSSI data we could use this. Otherwise we
312 	 * must fallback to the default RSSI value.
313 	 */
314 	if (!qual->rx_success)
315 		qual->rssi = DEFAULT_RSSI;
316 	else
317 		qual->rssi = rt2x00link_get_avg_rssi(&link->avg_rssi);
318 
319 	/*
320 	 * Check if link tuning is supported by the hardware, some hardware
321 	 * do not support link tuning at all, while other devices can disable
322 	 * the feature from the EEPROM.
323 	 */
324 	if (rt2x00_has_cap_link_tuning(rt2x00dev))
325 		rt2x00dev->ops->lib->link_tuner(rt2x00dev, qual, link->count);
326 
327 	/*
328 	 * Send a signal to the led to update the led signal strength.
329 	 */
330 	rt2x00leds_led_quality(rt2x00dev, qual->rssi);
331 
332 	/*
333 	 * Evaluate antenna setup, make this the last step when
334 	 * rt2x00lib_antenna_diversity made changes the quality
335 	 * statistics will be reset.
336 	 */
337 	if (rt2x00lib_antenna_diversity(rt2x00dev))
338 		rt2x00link_reset_qual(rt2x00dev);
339 }
340 
rt2x00link_tuner(struct work_struct * work)341 static void rt2x00link_tuner(struct work_struct *work)
342 {
343 	struct rt2x00_dev *rt2x00dev =
344 	    container_of(work, struct rt2x00_dev, link.work.work);
345 	struct link *link = &rt2x00dev->link;
346 
347 	/*
348 	 * When the radio is shutting down we should
349 	 * immediately cease all link tuning.
350 	 */
351 	if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags) ||
352 	    test_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags))
353 		return;
354 
355 	/* Do not race with rt2x00mac_config(). */
356 	mutex_lock(&rt2x00dev->conf_mutex);
357 
358 	if (rt2x00dev->intf_sta_count)
359 		rt2x00link_tuner_sta(rt2x00dev, link);
360 
361 	if (rt2x00dev->ops->lib->gain_calibration &&
362 	    (link->count % (AGC_SECONDS / LINK_TUNE_SECONDS)) == 0)
363 		rt2x00dev->ops->lib->gain_calibration(rt2x00dev);
364 
365 	if (rt2x00dev->ops->lib->vco_calibration &&
366 	    rt2x00_has_cap_vco_recalibration(rt2x00dev) &&
367 	    (link->count % (VCO_SECONDS / LINK_TUNE_SECONDS)) == 0)
368 		rt2x00dev->ops->lib->vco_calibration(rt2x00dev);
369 
370 	mutex_unlock(&rt2x00dev->conf_mutex);
371 
372 	/*
373 	 * Increase tuner counter, and reschedule the next link tuner run.
374 	 */
375 	link->count++;
376 
377 	if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
378 		ieee80211_queue_delayed_work(rt2x00dev->hw,
379 					     &link->work, LINK_TUNE_INTERVAL);
380 }
381 
rt2x00link_start_watchdog(struct rt2x00_dev * rt2x00dev)382 void rt2x00link_start_watchdog(struct rt2x00_dev *rt2x00dev)
383 {
384 	struct link *link = &rt2x00dev->link;
385 
386 	if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) &&
387 	    rt2x00dev->ops->lib->watchdog && !link->watchdog_disabled)
388 		ieee80211_queue_delayed_work(rt2x00dev->hw,
389 					     &link->watchdog_work,
390 					     link->watchdog_interval);
391 }
392 
rt2x00link_stop_watchdog(struct rt2x00_dev * rt2x00dev)393 void rt2x00link_stop_watchdog(struct rt2x00_dev *rt2x00dev)
394 {
395 	cancel_delayed_work_sync(&rt2x00dev->link.watchdog_work);
396 }
397 
rt2x00link_watchdog(struct work_struct * work)398 static void rt2x00link_watchdog(struct work_struct *work)
399 {
400 	struct rt2x00_dev *rt2x00dev =
401 	    container_of(work, struct rt2x00_dev, link.watchdog_work.work);
402 	struct link *link = &rt2x00dev->link;
403 
404 	/*
405 	 * When the radio is shutting down we should
406 	 * immediately cease the watchdog monitoring.
407 	 */
408 	if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
409 		return;
410 
411 	rt2x00dev->ops->lib->watchdog(rt2x00dev);
412 
413 	if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
414 		ieee80211_queue_delayed_work(rt2x00dev->hw,
415 					     &link->watchdog_work,
416 					     link->watchdog_interval);
417 }
418 
rt2x00link_register(struct rt2x00_dev * rt2x00dev)419 void rt2x00link_register(struct rt2x00_dev *rt2x00dev)
420 {
421 	struct link *link = &rt2x00dev->link;
422 
423 	INIT_DELAYED_WORK(&link->work, rt2x00link_tuner);
424 	INIT_DELAYED_WORK(&link->watchdog_work, rt2x00link_watchdog);
425 
426 	if (link->watchdog_interval == 0)
427 		link->watchdog_interval = WATCHDOG_INTERVAL;
428 }
429