aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/wireless/ath9k/ath9k.h1
-rw-r--r--drivers/net/wireless/ath9k/beacon.c406
-rw-r--r--drivers/net/wireless/ath9k/main.c3
3 files changed, 203 insertions, 207 deletions
diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h
index f5d099f0ab4c..0769a252dfe1 100644
--- a/drivers/net/wireless/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath9k/ath9k.h
@@ -458,7 +458,6 @@ void ath_beacon_config(struct ath_softc *sc, int if_id);
458int ath_beaconq_setup(struct ath_hw *ah); 458int ath_beaconq_setup(struct ath_hw *ah);
459int ath_beacon_alloc(struct ath_softc *sc, int if_id); 459int ath_beacon_alloc(struct ath_softc *sc, int if_id);
460void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp); 460void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp);
461void ath_beacon_sync(struct ath_softc *sc, int if_id);
462 461
463/*******/ 462/*******/
464/* ANI */ 463/* ANI */
diff --git a/drivers/net/wireless/ath9k/beacon.c b/drivers/net/wireless/ath9k/beacon.c
index 349904c761e4..74916431f575 100644
--- a/drivers/net/wireless/ath9k/beacon.c
+++ b/drivers/net/wireless/ath9k/beacon.c
@@ -16,6 +16,8 @@
16 16
17#include "ath9k.h" 17#include "ath9k.h"
18 18
19#define FUDGE 2
20
19/* 21/*
20 * This function will modify certain transmit queue properties depending on 22 * This function will modify certain transmit queue properties depending on
21 * the operating mode of the station (AP or AdHoc). Parameters are AIFS 23 * the operating mode of the station (AP or AdHoc). Parameters are AIFS
@@ -498,235 +500,231 @@ void ath_beacon_tasklet(unsigned long data)
498} 500}
499 501
500/* 502/*
501 * Configure the beacon and sleep timers. 503 * For multi-bss ap support beacons are either staggered evenly over N slots or
502 * 504 * burst together. For the former arrange for the SWBA to be delivered for each
503 * When operating as an AP this resets the TSF and sets 505 * slot. Slots that are not occupied will generate nothing.
504 * up the hardware to notify us when we need to issue beacons.
505 *
506 * When operating in station mode this sets up the beacon
507 * timers according to the timestamp of the last received
508 * beacon and the current TSF, configures PCF and DTIM
509 * handling, programs the sleep registers so the hardware
510 * will wakeup in time to receive beacons, and configures
511 * the beacon miss handling so we'll receive a BMISS
512 * interrupt when we stop seeing beacons from the AP
513 * we've associated with.
514 */ 506 */
515void ath_beacon_config(struct ath_softc *sc, int if_id) 507static void ath_beacon_config_ap(struct ath_softc *sc,
508 struct ath_beacon_config *conf,
509 struct ath_vif *avp)
516{ 510{
517 struct ieee80211_vif *vif;
518 struct ath_hw *ah = sc->sc_ah;
519 struct ath_beacon_config conf;
520 struct ath_vif *avp;
521 enum nl80211_iftype opmode;
522 u32 nexttbtt, intval; 511 u32 nexttbtt, intval;
523 512
524 if (if_id != ATH_IF_ID_ANY) { 513 /* NB: the beacon interval is kept internally in TU's */
525 vif = sc->vifs[if_id]; 514 intval = conf->beacon_interval & ATH9K_BEACON_PERIOD;
526 avp = (void *)vif->drv_priv; 515 intval /= ATH_BCBUF; /* for staggered beacons */
527 opmode = avp->av_opmode; 516 nexttbtt = intval;
528 } else { 517 intval |= ATH9K_BEACON_RESET_TSF;
529 opmode = sc->sc_ah->opmode;
530 }
531 518
532 memset(&conf, 0, sizeof(struct ath_beacon_config)); 519 /*
520 * In AP mode we enable the beacon timers and SWBA interrupts to
521 * prepare beacon frames.
522 */
523 intval |= ATH9K_BEACON_ENA;
524 sc->imask |= ATH9K_INT_SWBA;
525 ath_beaconq_config(sc);
533 526
534 conf.beacon_interval = sc->hw->conf.beacon_int ? 527 /* Set the computed AP beacon timers */
535 sc->hw->conf.beacon_int : ATH_DEFAULT_BINTVAL;
536 conf.listen_interval = 1;
537 conf.dtim_period = conf.beacon_interval;
538 conf.dtim_count = 1;
539 conf.bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * conf.beacon_interval;
540 528
541 /* extract tstamp from last beacon and convert to TU */ 529 ath9k_hw_set_interrupts(sc->sc_ah, 0);
542 nexttbtt = TSF_TO_TU(sc->beacon.bc_tstamp >> 32, sc->beacon.bc_tstamp); 530 ath9k_hw_beaconinit(sc->sc_ah, nexttbtt, intval);
531 sc->beacon.bmisscnt = 0;
532 ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
533}
543 534
544 /* XXX conditionalize multi-bss support? */ 535/*
545 if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) { 536 * This sets up the beacon timers according to the timestamp of the last
546 /* 537 * received beacon and the current TSF, configures PCF and DTIM
547 * For multi-bss ap support beacons are either staggered 538 * handling, programs the sleep registers so the hardware will wakeup in
548 * evenly over N slots or burst together. For the former 539 * time to receive beacons, and configures the beacon miss handling so
549 * arrange for the SWBA to be delivered for each slot. 540 * we'll receive a BMISS interrupt when we stop seeing beacons from the AP
550 * Slots that are not occupied will generate nothing. 541 * we've associated with.
551 */ 542 */
552 /* NB: the beacon interval is kept internally in TU's */ 543static void ath_beacon_config_sta(struct ath_softc *sc,
553 intval = conf.beacon_interval & ATH9K_BEACON_PERIOD; 544 struct ath_beacon_config *conf,
554 intval /= ATH_BCBUF; /* for staggered beacons */ 545 struct ath_vif *avp)
546{
547 struct ath9k_beacon_state bs;
548 int dtimperiod, dtimcount, sleepduration;
549 int cfpperiod, cfpcount;
550 u32 nexttbtt = 0, intval, tsftu;
551 u64 tsf;
552
553 memset(&bs, 0, sizeof(bs));
554 intval = conf->beacon_interval & ATH9K_BEACON_PERIOD;
555
556 /*
557 * Setup dtim and cfp parameters according to
558 * last beacon we received (which may be none).
559 */
560 dtimperiod = conf->dtim_period;
561 if (dtimperiod <= 0) /* NB: 0 if not known */
562 dtimperiod = 1;
563 dtimcount = conf->dtim_count;
564 if (dtimcount >= dtimperiod) /* NB: sanity check */
565 dtimcount = 0;
566 cfpperiod = 1; /* NB: no PCF support yet */
567 cfpcount = 0;
568
569 sleepduration = conf->listen_interval * intval;
570 if (sleepduration <= 0)
571 sleepduration = intval;
572
573 /*
574 * Pull nexttbtt forward to reflect the current
575 * TSF and calculate dtim+cfp state for the result.
576 */
577 tsf = ath9k_hw_gettsf64(sc->sc_ah);
578 tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE;
579 do {
580 nexttbtt += intval;
581 if (--dtimcount < 0) {
582 dtimcount = dtimperiod - 1;
583 if (--cfpcount < 0)
584 cfpcount = cfpperiod - 1;
585 }
586 } while (nexttbtt < tsftu);
587
588 bs.bs_intval = intval;
589 bs.bs_nexttbtt = nexttbtt;
590 bs.bs_dtimperiod = dtimperiod*intval;
591 bs.bs_nextdtim = bs.bs_nexttbtt + dtimcount*intval;
592 bs.bs_cfpperiod = cfpperiod*bs.bs_dtimperiod;
593 bs.bs_cfpnext = bs.bs_nextdtim + cfpcount*bs.bs_dtimperiod;
594 bs.bs_cfpmaxduration = 0;
595
596 /*
597 * Calculate the number of consecutive beacons to miss* before taking
598 * a BMISS interrupt. The configuration is specified in TU so we only
599 * need calculate based on the beacon interval. Note that we clamp the
600 * result to at most 15 beacons.
601 */
602 if (sleepduration > intval) {
603 bs.bs_bmissthreshold = conf->listen_interval *
604 ATH_DEFAULT_BMISS_LIMIT / 2;
555 } else { 605 } else {
556 intval = conf.beacon_interval & ATH9K_BEACON_PERIOD; 606 bs.bs_bmissthreshold = DIV_ROUND_UP(conf->bmiss_timeout, intval);
607 if (bs.bs_bmissthreshold > 15)
608 bs.bs_bmissthreshold = 15;
609 else if (bs.bs_bmissthreshold <= 0)
610 bs.bs_bmissthreshold = 1;
557 } 611 }
558 612
559 if (nexttbtt == 0) /* e.g. for ap mode */ 613 /*
560 nexttbtt = intval; 614 * Calculate sleep duration. The configuration is given in ms.
561 else if (intval) /* NB: can be 0 for monitor mode */ 615 * We ensure a multiple of the beacon period is used. Also, if the sleep
562 nexttbtt = roundup(nexttbtt, intval); 616 * duration is greater than the DTIM period then it makes senses
617 * to make it a multiple of that.
618 *
619 * XXX fixed at 100ms
620 */
563 621
564 DPRINTF(sc, ATH_DBG_BEACON, "nexttbtt %u intval %u (%u)\n", 622 bs.bs_sleepduration = roundup(IEEE80211_MS_TO_TU(100), sleepduration);
565 nexttbtt, intval, conf.beacon_interval); 623 if (bs.bs_sleepduration > bs.bs_dtimperiod)
624 bs.bs_sleepduration = bs.bs_dtimperiod;
566 625
567 /* Check for NL80211_IFTYPE_AP and sc_nostabeacons for WDS client */ 626 /* TSF out of range threshold fixed at 1 second */
568 if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) { 627 bs.bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD;
569 struct ath9k_beacon_state bs;
570 u64 tsf;
571 u32 tsftu;
572 int dtimperiod, dtimcount, sleepduration;
573 int cfpperiod, cfpcount;
574 628
575 /* 629 DPRINTF(sc, ATH_DBG_BEACON, "tsf: %llu tsftu: %u\n", tsf, tsftu);
576 * Setup dtim and cfp parameters according to 630 DPRINTF(sc, ATH_DBG_BEACON,
577 * last beacon we received (which may be none). 631 "bmiss: %u sleep: %u cfp-period: %u maxdur: %u next: %u\n",
578 */ 632 bs.bs_bmissthreshold, bs.bs_sleepduration,
579 dtimperiod = conf.dtim_period; 633 bs.bs_cfpperiod, bs.bs_cfpmaxduration, bs.bs_cfpnext);
580 if (dtimperiod <= 0) /* NB: 0 if not known */
581 dtimperiod = 1;
582 dtimcount = conf.dtim_count;
583 if (dtimcount >= dtimperiod) /* NB: sanity check */
584 dtimcount = 0;
585 cfpperiod = 1; /* NB: no PCF support yet */
586 cfpcount = 0;
587
588 sleepduration = conf.listen_interval * intval;
589 if (sleepduration <= 0)
590 sleepduration = intval;
591 634
592#define FUDGE 2 635 /* Set the computed STA beacon timers */
593 /*
594 * Pull nexttbtt forward to reflect the current
595 * TSF and calculate dtim+cfp state for the result.
596 */
597 tsf = ath9k_hw_gettsf64(ah);
598 tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE;
599 do {
600 nexttbtt += intval;
601 if (--dtimcount < 0) {
602 dtimcount = dtimperiod - 1;
603 if (--cfpcount < 0)
604 cfpcount = cfpperiod - 1;
605 }
606 } while (nexttbtt < tsftu);
607#undef FUDGE
608 memset(&bs, 0, sizeof(bs));
609 bs.bs_intval = intval;
610 bs.bs_nexttbtt = nexttbtt;
611 bs.bs_dtimperiod = dtimperiod*intval;
612 bs.bs_nextdtim = bs.bs_nexttbtt + dtimcount*intval;
613 bs.bs_cfpperiod = cfpperiod*bs.bs_dtimperiod;
614 bs.bs_cfpnext = bs.bs_nextdtim + cfpcount*bs.bs_dtimperiod;
615 bs.bs_cfpmaxduration = 0;
616 636
617 /* 637 ath9k_hw_set_interrupts(sc->sc_ah, 0);
618 * Calculate the number of consecutive beacons to miss 638 ath9k_hw_set_sta_beacon_timers(sc->sc_ah, &bs);
619 * before taking a BMISS interrupt. The configuration 639 sc->imask |= ATH9K_INT_BMISS;
620 * is specified in TU so we only need calculate based 640 ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
621 * on the beacon interval. Note that we clamp the 641}
622 * result to at most 15 beacons.
623 */
624 if (sleepduration > intval) {
625 bs.bs_bmissthreshold = conf.listen_interval *
626 ATH_DEFAULT_BMISS_LIMIT / 2;
627 } else {
628 bs.bs_bmissthreshold =
629 DIV_ROUND_UP(conf.bmiss_timeout, intval);
630 if (bs.bs_bmissthreshold > 15)
631 bs.bs_bmissthreshold = 15;
632 else if (bs.bs_bmissthreshold <= 0)
633 bs.bs_bmissthreshold = 1;
634 }
635 642
636 /* 643static void ath_beacon_config_adhoc(struct ath_softc *sc,
637 * Calculate sleep duration. The configuration is 644 struct ath_beacon_config *conf,
638 * given in ms. We insure a multiple of the beacon 645 struct ath_vif *avp)
639 * period is used. Also, if the sleep duration is 646{
640 * greater than the DTIM period then it makes senses 647 u64 tsf;
641 * to make it a multiple of that. 648 u32 tsftu, intval, nexttbtt;
642 *
643 * XXX fixed at 100ms
644 */
645 649
646 bs.bs_sleepduration = roundup(IEEE80211_MS_TO_TU(100), 650 intval = conf->beacon_interval & ATH9K_BEACON_PERIOD;
647 sleepduration);
648 if (bs.bs_sleepduration > bs.bs_dtimperiod)
649 bs.bs_sleepduration = bs.bs_dtimperiod;
650 651
651 /* TSF out of range threshold fixed at 1 second */ 652 /* Pull nexttbtt forward to reflect the current TSF */
652 bs.bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD;
653 653
654 DPRINTF(sc, ATH_DBG_BEACON, 654 nexttbtt = TSF_TO_TU(sc->beacon.bc_tstamp >> 32, sc->beacon.bc_tstamp);
655 "tsf: %llu tsftu: %u\n", tsf, tsftu); 655 if (nexttbtt == 0)
656 DPRINTF(sc, ATH_DBG_BEACON, 656 nexttbtt = intval;
657 "bmiss: %u sleep: %u cfp-period: %u maxdur: %u next: %u\n", 657 else if (intval)
658 bs.bs_bmissthreshold, bs.bs_sleepduration, 658 nexttbtt = roundup(nexttbtt, intval);
659 bs.bs_cfpperiod, bs.bs_cfpmaxduration, bs.bs_cfpnext);
660
661 ath9k_hw_set_interrupts(ah, 0);
662 ath9k_hw_set_sta_beacon_timers(ah, &bs);
663 sc->imask |= ATH9K_INT_BMISS;
664 ath9k_hw_set_interrupts(ah, sc->imask);
665 } else {
666 u64 tsf;
667 u32 tsftu;
668 659
669 ath9k_hw_set_interrupts(ah, 0); 660 tsf = ath9k_hw_gettsf64(sc->sc_ah);
670 if (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC) { 661 tsftu = TSF_TO_TU((u32)(tsf>>32), (u32)tsf) + FUDGE;
671 /* Pull nexttbtt forward to reflect the current TSF */ 662 do {
672#define FUDGE 2 663 nexttbtt += intval;
673 if (!(intval & ATH9K_BEACON_RESET_TSF)) { 664 } while (nexttbtt < tsftu);
674 tsf = ath9k_hw_gettsf64(ah);
675 tsftu = TSF_TO_TU((u32)(tsf>>32),
676 (u32)tsf) + FUDGE;
677 do {
678 nexttbtt += intval;
679 } while (nexttbtt < tsftu);
680 }
681#undef FUDGE
682 DPRINTF(sc, ATH_DBG_BEACON,
683 "IBSS nexttbtt %u intval %u (%u)\n",
684 nexttbtt, intval & ~ATH9K_BEACON_RESET_TSF,
685 conf.beacon_interval);
686 665
687 /* 666 DPRINTF(sc, ATH_DBG_BEACON,
688 * In IBSS mode enable the beacon timers but only 667 "IBSS nexttbtt %u intval %u (%u)\n",
689 * enable SWBA interrupts if we need to manually 668 nexttbtt, intval, conf->beacon_interval);
690 * prepare beacon frames. Otherwise we use a
691 * self-linked tx descriptor and let the hardware
692 * deal with things.
693 */
694 intval |= ATH9K_BEACON_ENA;
695 if (!(ah->caps.hw_caps & ATH9K_HW_CAP_VEOL))
696 sc->imask |= ATH9K_INT_SWBA;
697 ath_beaconq_config(sc);
698 } else if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) {
699 if (nexttbtt == intval)
700 intval |= ATH9K_BEACON_RESET_TSF;
701 /*
702 * In AP mode we enable the beacon timers and
703 * SWBA interrupts to prepare beacon frames.
704 */
705 intval |= ATH9K_BEACON_ENA;
706 sc->imask |= ATH9K_INT_SWBA;
707 ath_beaconq_config(sc);
708 }
709 669
710 ath9k_hw_beaconinit(ah, nexttbtt, intval); 670 /*
711 sc->beacon.bmisscnt = 0; 671 * In IBSS mode enable the beacon timers but only enable SWBA interrupts
712 ath9k_hw_set_interrupts(ah, sc->imask); 672 * if we need to manually prepare beacon frames. Otherwise we use a
673 * self-linked tx descriptor and let the hardware deal with things.
674 */
675 intval |= ATH9K_BEACON_ENA;
676 if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_VEOL))
677 sc->imask |= ATH9K_INT_SWBA;
713 678
714 /* 679 ath_beaconq_config(sc);
715 * When using a self-linked beacon descriptor in 680
716 * ibss mode load it once here. 681 /* Set the computed ADHOC beacon timers */
717 */ 682
718 if (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC && 683 ath9k_hw_set_interrupts(sc->sc_ah, 0);
719 (ah->caps.hw_caps & ATH9K_HW_CAP_VEOL)) 684 ath9k_hw_beaconinit(sc->sc_ah, nexttbtt, intval);
720 ath_beacon_start_adhoc(sc, 0); 685 sc->beacon.bmisscnt = 0;
721 } 686 ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
687
688 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_VEOL)
689 ath_beacon_start_adhoc(sc, 0);
722} 690}
723 691
724void ath_beacon_sync(struct ath_softc *sc, int if_id) 692void ath_beacon_config(struct ath_softc *sc, int if_id)
725{ 693{
726 /* 694 struct ath_beacon_config conf;
727 * Resync beacon timers using the tsf of the 695 struct ath_vif *avp;
728 * beacon frame we just received. 696 struct ieee80211_vif *vif;
729 */ 697
730 ath_beacon_config(sc, if_id); 698 /* Setup the beacon configuration parameters */
731 sc->sc_flags |= SC_OP_BEACONS; 699
700 memset(&conf, 0, sizeof(struct ath_beacon_config));
701 conf.beacon_interval = sc->hw->conf.beacon_int ?
702 sc->hw->conf.beacon_int : ATH_DEFAULT_BINTVAL;
703 conf.listen_interval = 1;
704 conf.dtim_period = conf.beacon_interval;
705 conf.dtim_count = 1;
706 conf.bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * conf.beacon_interval;
707
708 if (if_id != ATH_IF_ID_ANY) {
709 vif = sc->vifs[if_id];
710 avp = (struct ath_vif *)vif->drv_priv;
711
712 switch(avp->av_opmode) {
713 case NL80211_IFTYPE_AP:
714 ath_beacon_config_ap(sc, &conf, avp);
715 break;
716 case NL80211_IFTYPE_ADHOC:
717 ath_beacon_config_adhoc(sc, &conf, avp);
718 break;
719 case NL80211_IFTYPE_STATION:
720 ath_beacon_config_sta(sc, &conf, avp);
721 break;
722 default:
723 DPRINTF(sc, ATH_DBG_CONFIG,
724 "Unsupported beaconing mode\n");
725 return;
726 }
727
728 sc->sc_flags |= SC_OP_BEACONS;
729 }
732} 730}
diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c
index 94297b6d69fb..9e8f954877c9 100644
--- a/drivers/net/wireless/ath9k/main.c
+++ b/drivers/net/wireless/ath9k/main.c
@@ -926,7 +926,6 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc,
926 926
927 /* Configure the beacon */ 927 /* Configure the beacon */
928 ath_beacon_config(sc, 0); 928 ath_beacon_config(sc, 0);
929 sc->sc_flags |= SC_OP_BEACONS;
930 929
931 /* Reset rssi stats */ 930 /* Reset rssi stats */
932 sc->nodestats.ns_avgbrssi = ATH_RSSI_DUMMY_MARKER; 931 sc->nodestats.ns_avgbrssi = ATH_RSSI_DUMMY_MARKER;
@@ -2365,7 +2364,7 @@ static int ath9k_config_interface(struct ieee80211_hw *hw,
2365 if (error != 0) 2364 if (error != 0)
2366 return error; 2365 return error;
2367 2366
2368 ath_beacon_sync(sc, 0); 2367 ath_beacon_config(sc, 0);
2369 } 2368 }
2370 } 2369 }
2371 2370