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 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 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 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 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 62 static void rt2x00link_antenna_reset(struct rt2x00_dev *rt2x00dev) 63 { 64 ewma_rssi_init(&rt2x00dev->link.ant.rssi_ant); 65 } 66 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 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 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 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 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 247 void rt2x00link_stop_tuner(struct rt2x00_dev *rt2x00dev) 248 { 249 cancel_delayed_work_sync(&rt2x00dev->link.work); 250 } 251 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 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 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 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 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 393 void rt2x00link_stop_watchdog(struct rt2x00_dev *rt2x00dev) 394 { 395 cancel_delayed_work_sync(&rt2x00dev->link.watchdog_work); 396 } 397 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 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