1 /*
2 * Copyright (c) 2008-2011 Atheros Communications Inc.
3 *
4 * Modified for iPXE by Scott K Logan <logans@cottsay.net> July 2011
5 * Original from Linux kernel 3.0.1
6 *
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20 #include <ipxe/io.h>
21
22 #include "ath9k.h"
23
24 static void ath9k_bss_info_changed(struct net80211_device *dev, u32 changed);
25
ath9k_setpower(struct ath_softc * sc,enum ath9k_power_mode mode)26 int ath9k_setpower(struct ath_softc *sc, enum ath9k_power_mode mode)
27 {
28 int ret;
29
30 ret = ath9k_hw_setpower(sc->sc_ah, mode);
31
32 return ret;
33 }
34
ath_start_ani(struct ath_common * common)35 static void ath_start_ani(struct ath_common *common)
36 {
37 struct ath_hw *ah = common->ah;
38 unsigned long timestamp = ( currticks() * 1000 ) / TICKS_PER_SEC;
39 struct ath_softc *sc = (struct ath_softc *) common->priv;
40
41 if (!(sc->sc_flags & SC_OP_ANI_RUN))
42 return;
43
44 if (sc->sc_flags & SC_OP_OFFCHANNEL)
45 return;
46
47 common->ani.longcal_timer = timestamp;
48 common->ani.shortcal_timer = timestamp;
49 common->ani.checkani_timer = timestamp;
50
51 common->ani.timer = timestamp + ah->config.ani_poll_interval;
52 }
53
ath_update_survey_nf(struct ath_softc * sc,int channel)54 static void ath_update_survey_nf(struct ath_softc *sc, int channel)
55 {
56 struct ath_hw *ah = sc->sc_ah;
57 struct ath9k_channel *chan = &ah->channels[channel];
58 struct survey_info *survey = &sc->survey[channel];
59
60 if (chan->noisefloor) {
61 survey->filled |= SURVEY_INFO_NOISE_DBM;
62 survey->noise = chan->noisefloor;
63 }
64 }
65
66 /*
67 * Updates the survey statistics and returns the busy time since last
68 * update in %, if the measurement duration was long enough for the
69 * result to be useful, -1 otherwise.
70 */
ath_update_survey_stats(struct ath_softc * sc)71 static int ath_update_survey_stats(struct ath_softc *sc)
72 {
73 struct ath_hw *ah = sc->sc_ah;
74 struct ath_common *common = ath9k_hw_common(ah);
75 int pos = ah->curchan - &ah->channels[0];
76 struct survey_info *survey = &sc->survey[pos];
77 struct ath_cycle_counters *cc = &common->cc_survey;
78 unsigned int div = common->clockrate * 1000;
79 int ret = 0;
80
81 if (!ah->curchan)
82 return -1;
83
84 if (ah->power_mode == ATH9K_PM_AWAKE)
85 ath_hw_cycle_counters_update(common);
86
87 if (cc->cycles > 0) {
88 survey->filled |= SURVEY_INFO_CHANNEL_TIME |
89 SURVEY_INFO_CHANNEL_TIME_BUSY |
90 SURVEY_INFO_CHANNEL_TIME_RX |
91 SURVEY_INFO_CHANNEL_TIME_TX;
92 survey->channel_time += cc->cycles / div;
93 survey->channel_time_busy += cc->rx_busy / div;
94 survey->channel_time_rx += cc->rx_frame / div;
95 survey->channel_time_tx += cc->tx_frame / div;
96 }
97
98 if (cc->cycles < div)
99 return -1;
100
101 if (cc->cycles > 0)
102 ret = cc->rx_busy * 100 / cc->cycles;
103
104 memset(cc, 0, sizeof(*cc));
105
106 ath_update_survey_nf(sc, pos);
107
108 return ret;
109 }
110
111 /*
112 * Set/change channels. If the channel is really being changed, it's done
113 * by reseting the chip. To accomplish this we must first cleanup any pending
114 * DMA, then restart stuff.
115 */
ath_set_channel(struct ath_softc * sc,struct net80211_device * dev,struct ath9k_channel * hchan)116 int ath_set_channel(struct ath_softc *sc, struct net80211_device *dev,
117 struct ath9k_channel *hchan)
118 {
119 struct ath_hw *ah = sc->sc_ah;
120 struct ath_common *common = ath9k_hw_common(ah);
121 int fastcc __unused = 1, stopped __unused;
122 struct net80211_channel *channel = dev->channels + dev->channel;
123 struct ath9k_hw_cal_data *caldata = NULL;
124 int r;
125
126 if (sc->sc_flags & SC_OP_INVALID)
127 return -EIO;
128
129 sc->hw_busy_count = 0;
130
131 common->ani.timer = 0;
132 sc->tx_complete_work_timer = 0;
133 sc->hw_pll_work_timer = 0;
134
135 /*
136 * This is only performed if the channel settings have
137 * actually changed.
138 *
139 * To switch channels clear any pending DMA operations;
140 * wait long enough for the RX fifo to drain, reset the
141 * hardware at the new frequency, and then re-enable
142 * the relevant bits of the h/w.
143 */
144 ath9k_hw_disable_interrupts(ah);
145 stopped = ath_drain_all_txq(sc, 0);
146
147 if (!ath_stoprecv(sc))
148 stopped = 0;
149
150 if (!ath9k_hw_check_alive(ah))
151 stopped = 0;
152
153 /* XXX: do not flush receive queue here. We don't want
154 * to flush data frames already in queue because of
155 * changing channel. */
156
157 if (!(sc->sc_flags & SC_OP_OFFCHANNEL))
158 caldata = &sc->caldata;
159
160 DBG2("ath9k: "
161 "(%d MHz) -> (%d MHz)\n",
162 sc->sc_ah->curchan->channel,
163 channel->center_freq);
164
165 r = ath9k_hw_reset(ah, hchan, caldata, fastcc);
166 if (r) {
167 DBG("ath9k: "
168 "Unable to reset channel (%d MHz), reset status %d\n",
169 channel->center_freq, r);
170 goto ps_restore;
171 }
172
173 if (ath_startrecv(sc) != 0) {
174 DBG("ath9k: Unable to restart recv logic\n");
175 r = -EIO;
176 goto ps_restore;
177 }
178
179 ath9k_cmn_update_txpow(ah, sc->curtxpow,
180 sc->config.txpowlimit, &sc->curtxpow);
181 ath9k_hw_set_interrupts(ah, ah->imask);
182
183 if (!(sc->sc_flags & (SC_OP_OFFCHANNEL))) {
184 sc->tx_complete_work(sc);
185 sc->hw_pll_work_timer = (currticks() * 1000 ) / TICKS_PER_SEC + 500;
186 ath_start_ani(common);
187 }
188
189 ps_restore:
190 return r;
191 }
192
193 /*
194 * This routine performs the periodic noise floor calibration function
195 * that is used to adjust and optimize the chip performance. This
196 * takes environmental changes (location, temperature) into account.
197 * When the task is complete, it reschedules itself depending on the
198 * appropriate interval that was calculated.
199 */
ath_ani_calibrate(struct ath_softc * sc)200 void ath_ani_calibrate(struct ath_softc *sc)
201 {
202 struct ath_hw *ah = sc->sc_ah;
203 struct ath_common *common = ath9k_hw_common(ah);
204 int longcal = 0;
205 int shortcal = 0;
206 int aniflag = 0;
207 unsigned int timestamp = (currticks() * 1000 ) / TICKS_PER_SEC;
208 u32 cal_interval, short_cal_interval, long_cal_interval;
209
210 if (ah->caldata && ah->caldata->nfcal_interference)
211 long_cal_interval = ATH_LONG_CALINTERVAL_INT;
212 else
213 long_cal_interval = ATH_LONG_CALINTERVAL;
214
215 short_cal_interval = ATH_STA_SHORT_CALINTERVAL;
216
217 /* Only calibrate if awake */
218 if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE)
219 goto set_timer;
220
221 /* Long calibration runs independently of short calibration. */
222 if ((timestamp - common->ani.longcal_timer) >= long_cal_interval) {
223 longcal = 1;
224 DBG2("ath9k: longcal @%d\n", timestamp);
225 common->ani.longcal_timer = timestamp;
226 }
227
228 /* Short calibration applies only while caldone is false */
229 if (!common->ani.caldone) {
230 if ((timestamp - common->ani.shortcal_timer) >= short_cal_interval) {
231 shortcal = 1;
232 DBG2("ath9k: "
233 "shortcal @%d\n", timestamp);
234 common->ani.shortcal_timer = timestamp;
235 common->ani.resetcal_timer = timestamp;
236 }
237 } else {
238 if ((timestamp - common->ani.resetcal_timer) >=
239 ATH_RESTART_CALINTERVAL) {
240 common->ani.caldone = ath9k_hw_reset_calvalid(ah);
241 if (common->ani.caldone)
242 common->ani.resetcal_timer = timestamp;
243 }
244 }
245
246 /* Verify whether we must check ANI */
247 if ((timestamp - common->ani.checkani_timer) >=
248 ah->config.ani_poll_interval) {
249 aniflag = 1;
250 common->ani.checkani_timer = timestamp;
251 }
252
253 /* Skip all processing if there's nothing to do. */
254 if (longcal || shortcal || aniflag) {
255 /* Call ANI routine if necessary */
256 if (aniflag) {
257 ath9k_hw_ani_monitor(ah, ah->curchan);
258 ath_update_survey_stats(sc);
259 }
260
261 /* Perform calibration if necessary */
262 if (longcal || shortcal) {
263 common->ani.caldone =
264 ath9k_hw_calibrate(ah,
265 ah->curchan,
266 common->rx_chainmask,
267 longcal);
268 }
269 }
270
271 set_timer:
272 /*
273 * Set timer interval based on previous results.
274 * The interval must be the shortest necessary to satisfy ANI,
275 * short calibration and long calibration.
276 */
277 cal_interval = ATH_LONG_CALINTERVAL;
278 if (sc->sc_ah->config.enable_ani)
279 cal_interval = min(cal_interval,
280 (u32)ah->config.ani_poll_interval);
281 if (!common->ani.caldone)
282 cal_interval = min(cal_interval, (u32)short_cal_interval);
283
284 common->ani.timer = timestamp + cal_interval;
285 }
286
ath_hw_check(struct ath_softc * sc)287 void ath_hw_check(struct ath_softc *sc)
288 {
289 int busy;
290
291 if (ath9k_hw_check_alive(sc->sc_ah))
292 goto out;
293
294 busy = ath_update_survey_stats(sc);
295
296 DBG("ath9k: Possible baseband hang, "
297 "busy=%d (try %d)\n", busy, sc->hw_busy_count + 1);
298 if (busy >= 99) {
299 if (++sc->hw_busy_count >= 3)
300 ath_reset(sc, 1);
301 } else if (busy >= 0)
302 sc->hw_busy_count = 0;
303
304 out:
305 return;
306 }
307
ath_hw_pll_rx_hang_check(struct ath_softc * sc,u32 pll_sqsum)308 static void ath_hw_pll_rx_hang_check(struct ath_softc *sc, u32 pll_sqsum)
309 {
310 static int count;
311
312 if (pll_sqsum >= 0x40000) {
313 count++;
314 if (count == 3) {
315 /* Rx is hung for more than 500ms. Reset it */
316 DBG("ath9k: "
317 "Possible RX hang, resetting");
318 ath_reset(sc, 1);
319 count = 0;
320 }
321 } else
322 count = 0;
323 }
324
ath_hw_pll_work(struct ath_softc * sc)325 void ath_hw_pll_work(struct ath_softc *sc)
326 {
327 u32 pll_sqsum;
328
329 if (AR_SREV_9485(sc->sc_ah)) {
330 pll_sqsum = ar9003_get_pll_sqsum_dvc(sc->sc_ah);
331
332 ath_hw_pll_rx_hang_check(sc, pll_sqsum);
333
334 sc->hw_pll_work_timer = (currticks() * 1000 ) / TICKS_PER_SEC + 200;
335 }
336 }
337
338
ath9k_tasklet(struct ath_softc * sc)339 void ath9k_tasklet(struct ath_softc *sc)
340 {
341 struct ath_hw *ah = sc->sc_ah;
342
343 u32 status = sc->intrstatus;
344 u32 rxmask;
345
346 if ((status & ATH9K_INT_FATAL) ||
347 (status & ATH9K_INT_BB_WATCHDOG)) {
348 ath_reset(sc, 1);
349 return;
350 }
351
352 rxmask = (ATH9K_INT_RX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN);
353
354 if (status & rxmask) {
355 ath_rx_tasklet(sc, 0, 0);
356 }
357
358 if (status & ATH9K_INT_TX) {
359 ath_tx_tasklet(sc);
360 }
361
362 /* re-enable hardware interrupt */
363 ath9k_hw_enable_interrupts(ah);
364 }
365
ath_isr(struct net80211_device * dev)366 void ath_isr(struct net80211_device *dev)
367 {
368 #define SCHED_INTR ( \
369 ATH9K_INT_FATAL | \
370 ATH9K_INT_BB_WATCHDOG | \
371 ATH9K_INT_RXORN | \
372 ATH9K_INT_RXEOL | \
373 ATH9K_INT_RX | \
374 ATH9K_INT_RXLP | \
375 ATH9K_INT_RXHP | \
376 ATH9K_INT_TX | \
377 ATH9K_INT_BMISS | \
378 ATH9K_INT_CST | \
379 ATH9K_INT_TSFOOR | \
380 ATH9K_INT_GENTIMER)
381
382 struct ath_softc *sc = dev->priv;
383 struct ath_hw *ah = sc->sc_ah;
384 struct ath_common *common = ath9k_hw_common(ah);
385 enum ath9k_int status;
386 unsigned long timestamp = (currticks() * 1000 ) / TICKS_PER_SEC;
387 int sched = 0;
388
389 /*
390 * The hardware is not ready/present, don't
391 * touch anything. Note this can happen early
392 * on if the IRQ is shared.
393 */
394 if (sc->sc_flags & SC_OP_INVALID)
395 return;
396
397
398 /* Check calibration */
399 if(timestamp >= (unsigned int)common->ani.timer && common->ani.timer)
400 ath_ani_calibrate(sc);
401
402 /* Check tx_complete_work */
403 if(timestamp >= (unsigned int)sc->tx_complete_work_timer && sc->tx_complete_work_timer)
404 sc->tx_complete_work(sc);
405
406 /* Check hw_pll_work */
407 if(timestamp >= (unsigned int)sc->hw_pll_work_timer && sc->hw_pll_work_timer)
408 sc->hw_pll_work(sc);
409
410 /* shared irq, not for us */
411
412 if (!ath9k_hw_intrpend(ah))
413 return;
414
415 /*
416 * Figure out the reason(s) for the interrupt. Note
417 * that the hal returns a pseudo-ISR that may include
418 * bits we haven't explicitly enabled so we mask the
419 * value to insure we only process bits we requested.
420 */
421 ath9k_hw_getisr(ah, &status); /* NB: clears ISR too */
422 status &= ah->imask; /* discard unasked-for bits */
423
424 /*
425 * If there are no status bits set, then this interrupt was not
426 * for me (should have been caught above).
427 */
428 if (!status)
429 return;
430
431 /* Cache the status */
432 sc->intrstatus = status;
433
434 if (status & SCHED_INTR)
435 sched = 1;
436
437 /*
438 * If a FATAL or RXORN interrupt is received, we have to reset the
439 * chip immediately.
440 */
441 if ((status & ATH9K_INT_FATAL) || (status & ATH9K_INT_RXORN))
442 goto chip_reset;
443
444 if (status & ATH9K_INT_TXURN)
445 ath9k_hw_updatetxtriglevel(ah, 1);
446
447 if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
448 if (status & ATH9K_INT_TIM_TIMER) {
449 if (sc->ps_idle)
450 goto chip_reset;
451 /* Clear RxAbort bit so that we can
452 * receive frames */
453 ath9k_setpower(sc, ATH9K_PM_AWAKE);
454 ath9k_hw_setrxabort(sc->sc_ah, 0);
455 sc->ps_flags |= PS_WAIT_FOR_BEACON;
456 }
457
458 chip_reset:
459
460 if (sched) {
461 /* turn off every interrupt */
462 ath9k_hw_disable_interrupts(ah);
463 sc->intr_tq(sc);
464 }
465
466 return;
467
468 #undef SCHED_INTR
469 }
470
ath_radio_disable(struct ath_softc * sc,struct net80211_device * dev)471 void ath_radio_disable(struct ath_softc *sc, struct net80211_device *dev)
472 {
473 struct ath_hw *ah = sc->sc_ah;
474 struct net80211_channel *channel = dev->channels + dev->channel;
475 int r;
476
477 sc->hw_pll_work_timer = 0;
478
479 /*
480 * Keep the LED on when the radio is disabled
481 * during idle unassociated state.
482 */
483 if (!sc->ps_idle) {
484 ath9k_hw_set_gpio(ah, ah->led_pin, 1);
485 ath9k_hw_cfg_gpio_input(ah, ah->led_pin);
486 }
487
488 /* Disable interrupts */
489 ath9k_hw_disable_interrupts(ah);
490
491 ath_drain_all_txq(sc, 0); /* clear pending tx frames */
492
493 ath_stoprecv(sc); /* turn off frame recv */
494 ath_flushrecv(sc); /* flush recv queue */
495
496 if (!ah->curchan)
497 ah->curchan = ath9k_cmn_get_curchannel(dev, ah);
498
499 r = ath9k_hw_reset(ah, ah->curchan, ah->caldata, 0);
500 if (r) {
501 DBG("ath9k: "
502 "Unable to reset channel (%d MHz), reset status %d\n",
503 channel->center_freq, r);
504 }
505
506 ath9k_hw_phy_disable(ah);
507
508 ath9k_hw_configpcipowersave(ah, 1, 1);
509 }
510
ath_reset(struct ath_softc * sc,int retry_tx)511 int ath_reset(struct ath_softc *sc, int retry_tx)
512 {
513 struct ath_hw *ah = sc->sc_ah;
514 struct ath_common *common = ath9k_hw_common(ah);
515 int r;
516
517 sc->hw_busy_count = 0;
518
519 /* Stop ANI */
520 common->ani.timer = 0;
521
522 ath9k_hw_disable_interrupts(ah);
523 ath_drain_all_txq(sc, retry_tx);
524
525 ath_stoprecv(sc);
526 ath_flushrecv(sc);
527
528 r = ath9k_hw_reset(ah, sc->sc_ah->curchan, ah->caldata, 0);
529 if (r)
530 DBG("ath9k: "
531 "Unable to reset hardware; reset status %d\n", r);
532
533 if (ath_startrecv(sc) != 0)
534 DBG("ath9k: Unable to start recv logic\n");
535
536 /*
537 * We may be doing a reset in response to a request
538 * that changes the channel so update any state that
539 * might change as a result.
540 */
541 ath9k_cmn_update_txpow(ah, sc->curtxpow,
542 sc->config.txpowlimit, &sc->curtxpow);
543
544 ath9k_hw_set_interrupts(ah, ah->imask);
545
546 if (retry_tx) {
547 int i;
548 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
549 if (ATH_TXQ_SETUP(sc, i)) {
550 ath_txq_schedule(sc, &sc->tx.txq[i]);
551 }
552 }
553 }
554
555 /* Start ANI */
556 ath_start_ani(common);
557
558 return r;
559 }
560
561 /**********************/
562 /* mac80211 callbacks */
563 /**********************/
564
ath9k_start(struct net80211_device * dev)565 static int ath9k_start(struct net80211_device *dev)
566 {
567 struct ath_softc *sc = dev->priv;
568 struct ath_hw *ah = sc->sc_ah;
569 struct ath_common *common = ath9k_hw_common(ah);
570 struct net80211_channel *curchan = dev->channels + dev->channel;
571 struct ath9k_channel *init_channel;
572 int r;
573
574 DBG("ath9k: "
575 "Starting driver with initial channel: %d MHz\n",
576 curchan->center_freq);
577
578 /* setup initial channel */
579 sc->chan_idx = curchan->hw_value;
580
581 init_channel = ath9k_cmn_get_curchannel(dev, ah);
582
583 /* Reset SERDES registers */
584 ath9k_hw_configpcipowersave(ah, 0, 0);
585
586 /*
587 * The basic interface to setting the hardware in a good
588 * state is ``reset''. On return the hardware is known to
589 * be powered up and with interrupts disabled. This must
590 * be followed by initialization of the appropriate bits
591 * and then setup of the interrupt mask.
592 */
593 r = ath9k_hw_reset(ah, init_channel, ah->caldata, 0);
594 if (r) {
595 DBG("ath9k: "
596 "Unable to reset hardware; reset status %d (freq %d MHz)\n",
597 r, curchan->center_freq);
598 goto mutex_unlock;
599 }
600
601 /*
602 * This is needed only to setup initial state
603 * but it's best done after a reset.
604 */
605 ath9k_cmn_update_txpow(ah, sc->curtxpow,
606 sc->config.txpowlimit, &sc->curtxpow);
607
608 /*
609 * Setup the hardware after reset:
610 * The receive engine is set going.
611 * Frame transmit is handled entirely
612 * in the frame output path; there's nothing to do
613 * here except setup the interrupt mask.
614 */
615 if (ath_startrecv(sc) != 0) {
616 DBG("ath9k: Unable to start recv logic\n");
617 r = -EIO;
618 goto mutex_unlock;
619 }
620
621 /* Setup our intr mask. */
622 ah->imask = ATH9K_INT_TX | ATH9K_INT_RXEOL |
623 ATH9K_INT_RXORN | ATH9K_INT_FATAL |
624 ATH9K_INT_GLOBAL;
625
626 ah->imask |= ATH9K_INT_RX;
627
628 sc->sc_flags &= ~SC_OP_INVALID;
629 sc->sc_ah->is_monitoring = 0;
630
631 ath9k_hw_set_interrupts(ah, ah->imask);
632
633 sc->tx_complete_work(sc);
634
635 if (ah->caps.pcie_lcr_extsync_en && common->bus_ops->extn_synch_en)
636 common->bus_ops->extn_synch_en(common);
637
638 mutex_unlock:
639 return r;
640 }
641
ath9k_tx(struct net80211_device * dev,struct io_buffer * iob)642 static int ath9k_tx(struct net80211_device *dev, struct io_buffer *iob)
643 {
644 struct ath_softc *sc = dev->priv;
645 struct ath_tx_control txctl;
646 int ret = 0;
647
648 memset(&txctl, 0, sizeof(struct ath_tx_control));
649 txctl.txq = sc->tx.txq_map[0];
650
651 DBGIO("ath9k: transmitting packet, iob: %p\n", iob);
652
653 ret = ath_tx_start(dev, iob, &txctl);
654 if (ret) {
655 DBG("ath9k: TX failed\n");
656 goto exit;
657 }
658
659 return ret;
660 exit:
661 free_iob(iob);
662 return ret;
663 }
664
ath9k_stop(struct net80211_device * dev)665 static void ath9k_stop(struct net80211_device *dev)
666 {
667 struct ath_softc *sc = dev->priv;
668 struct ath_hw *ah = sc->sc_ah;
669
670 sc->tx_complete_work_timer = 0;
671 sc->hw_pll_work_timer = 0;
672
673 if (sc->sc_flags & SC_OP_INVALID) {
674 DBG("ath9k: Device not present\n");
675 return;
676 }
677
678 /* prevent tasklets to enable interrupts once we disable them */
679 ah->imask &= ~ATH9K_INT_GLOBAL;
680
681 /* make sure h/w will not generate any interrupt
682 * before setting the invalid flag. */
683 ath9k_hw_disable_interrupts(ah);
684
685 if (!(sc->sc_flags & SC_OP_INVALID)) {
686 ath_drain_all_txq(sc, 0);
687 ath_stoprecv(sc);
688 ath9k_hw_phy_disable(ah);
689 } else
690 sc->rx.rxlink = NULL;
691
692 if (sc->rx.frag) {
693 free_iob(sc->rx.frag);
694 sc->rx.frag = NULL;
695 }
696
697 /* disable HAL and put h/w to sleep */
698 ath9k_hw_disable(ah);
699 ath9k_hw_configpcipowersave(ah, 1, 1);
700
701 ath_radio_disable(sc, dev);
702
703 sc->sc_flags |= SC_OP_INVALID;
704
705 DBG("ath9k: Driver halt\n");
706 }
707
ath9k_config(struct net80211_device * dev,int changed)708 static int ath9k_config(struct net80211_device *dev, int changed)
709 {
710 struct ath_softc *sc = dev->priv;
711 struct ath_hw *ah = sc->sc_ah;
712
713 if ((changed & NET80211_CFG_RATE) ||
714 (changed & NET80211_CFG_PHY_PARAMS)) {
715 int spmbl = (sc->sc_flags & SC_OP_PREAMBLE_SHORT) ? IEEE80211_TX_RC_USE_SHORT_PREAMBLE : 0;
716 u16 rate = dev->rates[dev->rate];
717 u16 slowrate = dev->rates[dev->rtscts_rate];
718 int i;
719
720 for (i = 0; i < NET80211_MAX_RATES; i++) {
721 if (sc->rates[i].bitrate == rate &&
722 (sc->rates[i].flags & spmbl))
723 sc->hw_rix = i;
724
725 if (sc->rates[i].bitrate == slowrate &&
726 (sc->rates[i].flags & spmbl))
727 sc->hw_rix = i;
728 }
729 }
730
731 ath9k_bss_info_changed(dev, changed);
732
733 if (changed & NET80211_CFG_CHANNEL) {
734 struct net80211_channel *curchan = dev->channels + dev->channel;
735 int pos = curchan->hw_value;
736 int old_pos = -1;
737
738 if (ah->curchan)
739 old_pos = ah->curchan - &ah->channels[0];
740
741 sc->sc_flags &= ~SC_OP_OFFCHANNEL;
742
743 DBG2("ath9k: "
744 "Set channel: %d MHz\n",
745 curchan->center_freq);
746
747 ath9k_cmn_update_ichannel(&sc->sc_ah->channels[pos],
748 curchan);
749
750 /* update survey stats for the old channel before switching */
751 ath_update_survey_stats(sc);
752
753 /*
754 * If the operating channel changes, change the survey in-use flags
755 * along with it.
756 * Reset the survey data for the new channel, unless we're switching
757 * back to the operating channel from an off-channel operation.
758 */
759 if (sc->cur_survey != &sc->survey[pos]) {
760
761 if (sc->cur_survey)
762 sc->cur_survey->filled &= ~SURVEY_INFO_IN_USE;
763
764 sc->cur_survey = &sc->survey[pos];
765
766 memset(sc->cur_survey, 0, sizeof(struct survey_info));
767 sc->cur_survey->filled |= SURVEY_INFO_IN_USE;
768 } else if (!(sc->survey[pos].filled & SURVEY_INFO_IN_USE)) {
769 memset(&sc->survey[pos], 0, sizeof(struct survey_info));
770 }
771
772 if (ath_set_channel(sc, dev, &sc->sc_ah->channels[pos]) < 0) {
773 DBG("ath9k: Unable to set channel\n");
774 return -EINVAL;
775 }
776
777 /*
778 * The most recent snapshot of channel->noisefloor for the old
779 * channel is only available after the hardware reset. Copy it to
780 * the survey stats now.
781 */
782 if (old_pos >= 0)
783 ath_update_survey_nf(sc, old_pos);
784 }
785
786 if (changed & NET80211_CFG_CHANNEL) {
787 DBG2("ath9k: "
788 "Set power: %d\n", (dev->channels + dev->channel)->maxpower);
789 sc->config.txpowlimit = 2 * (dev->channels + dev->channel)->maxpower;
790 ath9k_cmn_update_txpow(ah, sc->curtxpow,
791 sc->config.txpowlimit, &sc->curtxpow);
792 }
793
794 return 0;
795 }
796
ath9k_bss_iter(struct ath_softc * sc)797 static void ath9k_bss_iter(struct ath_softc *sc)
798 {
799 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
800
801 if (common->dev->state & NET80211_ASSOCIATED) {
802 sc->sc_flags |= SC_OP_PRIM_STA_VIF;
803 memcpy(common->curbssid, common->dev->bssid, ETH_ALEN);
804 common->curaid = common->dev->aid;
805 ath9k_hw_write_associd(sc->sc_ah);
806 DBG("ath9k: "
807 "Bss Info ASSOC %d, bssid: %pM\n",
808 common->dev->aid, common->curbssid);
809
810 /*
811 * Request a re-configuration of Beacon related timers
812 * on the receipt of the first Beacon frame (i.e.,
813 * after time sync with the AP).
814 */
815 sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;
816 /* Reset rssi stats */
817 sc->last_rssi = ATH_RSSI_DUMMY_MARKER;
818 sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER;
819
820 sc->sc_flags |= SC_OP_ANI_RUN;
821 ath_start_ani(common);
822 }
823 }
824
ath9k_config_bss(struct ath_softc * sc)825 static void ath9k_config_bss(struct ath_softc *sc)
826 {
827 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
828 struct net80211_device *dev = common->dev;
829
830 /* Reconfigure bss info */
831 if (!(dev->state & NET80211_ASSOCIATED)) {
832 DBG2("ath9k: "
833 "ath9k: Bss Info DISASSOC %d, bssid %pM\n",
834 common->curaid, common->curbssid);
835 sc->sc_flags &= ~(SC_OP_PRIM_STA_VIF | SC_OP_BEACONS);
836 memset(common->curbssid, 0, ETH_ALEN);
837 common->curaid = 0;
838 }
839
840 ath9k_bss_iter(sc);
841
842 /*
843 * None of station vifs are associated.
844 * Clear bssid & aid
845 */
846 if (!(sc->sc_flags & SC_OP_PRIM_STA_VIF)) {
847 ath9k_hw_write_associd(sc->sc_ah);
848 /* Stop ANI */
849 sc->sc_flags &= ~SC_OP_ANI_RUN;
850 common->ani.timer = 0;
851 }
852 }
853
ath9k_bss_info_changed(struct net80211_device * dev,u32 changed)854 static void ath9k_bss_info_changed(struct net80211_device *dev,
855 u32 changed)
856 {
857 struct ath_softc *sc = dev->priv;
858 struct ath_hw *ah = sc->sc_ah;
859 struct ath_common *common = ath9k_hw_common(ah);
860 int slottime;
861
862 if (changed & NET80211_CFG_ASSOC) {
863 ath9k_config_bss(sc);
864
865 DBG2("ath9k: BSSID: %pM aid: 0x%x\n",
866 common->curbssid, common->curaid);
867 }
868
869 if (changed & NET80211_CFG_PHY_PARAMS) {
870 if (dev->phy_flags & NET80211_PHY_USE_PROTECTION)
871 slottime = 9;
872 else
873 slottime = 20;
874 ah->slottime = slottime;
875 ath9k_hw_init_global_settings(ah);
876
877 DBG2("ath9k: BSS Changed PREAMBLE %d\n",
878 !!(dev->phy_flags & NET80211_PHY_USE_SHORT_PREAMBLE));
879 if (dev->phy_flags & NET80211_PHY_USE_SHORT_PREAMBLE)
880 sc->sc_flags |= SC_OP_PREAMBLE_SHORT;
881 else
882 sc->sc_flags &= ~SC_OP_PREAMBLE_SHORT;
883
884 DBG2("ath9k: BSS Changed CTS PROT %d\n",
885 !!(dev->phy_flags & NET80211_PHY_USE_PROTECTION));
886 if ((dev->phy_flags & NET80211_PHY_USE_PROTECTION) &&
887 (dev->channels + dev->channel)->band != NET80211_BAND_5GHZ)
888 sc->sc_flags |= SC_OP_PROTECT_ENABLE;
889 else
890 sc->sc_flags &= ~SC_OP_PROTECT_ENABLE;
891 }
892 }
893
ath9k_poll(struct net80211_device * dev)894 static void ath9k_poll(struct net80211_device *dev)
895 {
896 ath_isr(dev);
897 }
898
ath9k_irq(struct net80211_device * dev,int enable)899 static void ath9k_irq(struct net80211_device *dev, int enable)
900 {
901 struct ath_softc *sc = dev->priv;
902 struct ath_hw *ah = sc->sc_ah;
903
904 ah->ah_ier = enable ? AR_IER_ENABLE : AR_IER_DISABLE;
905
906 ath9k_hw_set_interrupts(ah, ah->imask);
907 }
908
909 struct net80211_device_operations ath9k_ops = {
910 .transmit = ath9k_tx,
911 .open = ath9k_start,
912 .close = ath9k_stop,
913 .config = ath9k_config,
914 .poll = ath9k_poll,
915 .irq = ath9k_irq,
916 };
917