aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/wireless/ath/ath9k/ath9k.h8
-rw-r--r--drivers/net/wireless/ath/ath9k/beacon.c226
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c24
-rw-r--r--drivers/net/wireless/ath/ath9k/recv.c2
4 files changed, 98 insertions, 162 deletions
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 9dd8fbb847fd..4cce997d6867 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -389,6 +389,7 @@ struct ath_beacon_config {
389 u16 dtim_period; 389 u16 dtim_period;
390 u16 bmiss_timeout; 390 u16 bmiss_timeout;
391 u8 dtim_count; 391 u8 dtim_count;
392 bool enable_beacon;
392}; 393};
393 394
394struct ath_beacon { 395struct ath_beacon {
@@ -415,11 +416,13 @@ struct ath_beacon {
415}; 416};
416 417
417void ath_beacon_tasklet(unsigned long data); 418void ath_beacon_tasklet(unsigned long data);
418void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif); 419bool ath9k_allow_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif);
420void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif,
421 u32 changed);
419void ath9k_beacon_assign_slot(struct ath_softc *sc, struct ieee80211_vif *vif); 422void ath9k_beacon_assign_slot(struct ath_softc *sc, struct ieee80211_vif *vif);
420void ath9k_beacon_remove_slot(struct ath_softc *sc, struct ieee80211_vif *vif); 423void ath9k_beacon_remove_slot(struct ath_softc *sc, struct ieee80211_vif *vif);
421int ath_beaconq_config(struct ath_softc *sc); 424int ath_beaconq_config(struct ath_softc *sc);
422void ath_set_beacon(struct ath_softc *sc); 425void ath9k_set_beacon(struct ath_softc *sc);
423void ath9k_set_beaconing_status(struct ath_softc *sc, bool status); 426void ath9k_set_beaconing_status(struct ath_softc *sc, bool status);
424 427
425/*******************/ 428/*******************/
@@ -622,7 +625,6 @@ enum sc_op_flags {
622 SC_OP_INVALID, 625 SC_OP_INVALID,
623 SC_OP_BEACONS, 626 SC_OP_BEACONS,
624 SC_OP_RXFLUSH, 627 SC_OP_RXFLUSH,
625 SC_OP_TSF_RESET,
626 SC_OP_ANI_RUN, 628 SC_OP_ANI_RUN,
627 SC_OP_PRIM_STA_VIF, 629 SC_OP_PRIM_STA_VIF,
628 SC_OP_HW_RESET, 630 SC_OP_HW_RESET,
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c
index 351ded55c798..a79ec4572c2f 100644
--- a/drivers/net/wireless/ath/ath9k/beacon.c
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
@@ -315,7 +315,6 @@ void ath_beacon_tasklet(unsigned long data)
315 } else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) { 315 } else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) {
316 ath_dbg(common, BSTUCK, "beacon is officially stuck\n"); 316 ath_dbg(common, BSTUCK, "beacon is officially stuck\n");
317 sc->beacon.bmisscnt = 0; 317 sc->beacon.bmisscnt = 0;
318 set_bit(SC_OP_TSF_RESET, &sc->sc_flags);
319 ieee80211_queue_work(sc->hw, &sc->hw_reset_work); 318 ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
320 } 319 }
321 320
@@ -401,21 +400,16 @@ void ath_beacon_tasklet(unsigned long data)
401 } 400 }
402} 401}
403 402
404static void ath9k_beacon_init(struct ath_softc *sc, 403static void ath9k_beacon_init(struct ath_softc *sc, u32 nexttbtt, u32 intval)
405 u32 next_beacon,
406 u32 beacon_period)
407{ 404{
408 if (test_bit(SC_OP_TSF_RESET, &sc->sc_flags)) { 405 struct ath_hw *ah = sc->sc_ah;
409 ath9k_ps_wakeup(sc);
410 ath9k_hw_reset_tsf(sc->sc_ah);
411 }
412
413 ath9k_hw_beaconinit(sc->sc_ah, next_beacon, beacon_period);
414 406
415 if (test_bit(SC_OP_TSF_RESET, &sc->sc_flags)) { 407 ath9k_hw_disable_interrupts(ah);
416 ath9k_ps_restore(sc); 408 ath9k_hw_reset_tsf(ah);
417 clear_bit(SC_OP_TSF_RESET, &sc->sc_flags); 409 ath9k_hw_beaconinit(ah, nexttbtt, intval);
418 } 410 sc->beacon.bmisscnt = 0;
411 ath9k_hw_set_interrupts(ah);
412 ath9k_hw_enable_interrupts(ah);
419} 413}
420 414
421/* 415/*
@@ -423,32 +417,28 @@ static void ath9k_beacon_init(struct ath_softc *sc,
423 * burst together. For the former arrange for the SWBA to be delivered for each 417 * burst together. For the former arrange for the SWBA to be delivered for each
424 * slot. Slots that are not occupied will generate nothing. 418 * slot. Slots that are not occupied will generate nothing.
425 */ 419 */
426static void ath_beacon_config_ap(struct ath_softc *sc, 420static void ath9k_beacon_config_ap(struct ath_softc *sc,
427 struct ath_beacon_config *conf) 421 struct ath_beacon_config *conf)
428{ 422{
429 struct ath_hw *ah = sc->sc_ah; 423 struct ath_hw *ah = sc->sc_ah;
424 struct ath_common *common = ath9k_hw_common(ah);
430 u32 nexttbtt, intval; 425 u32 nexttbtt, intval;
431 426
432 /* NB: the beacon interval is kept internally in TU's */ 427 /* NB: the beacon interval is kept internally in TU's */
433 intval = TU_TO_USEC(conf->beacon_interval); 428 intval = TU_TO_USEC(conf->beacon_interval);
434 intval /= ATH_BCBUF; /* for staggered beacons */ 429 intval /= ATH_BCBUF;
435 nexttbtt = intval; 430 nexttbtt = intval;
436 431
437 /* 432 if (conf->enable_beacon)
438 * In AP mode we enable the beacon timers and SWBA interrupts to 433 ah->imask |= ATH9K_INT_SWBA;
439 * prepare beacon frames. 434 else
440 */ 435 ah->imask &= ~ATH9K_INT_SWBA;
441 ah->imask |= ATH9K_INT_SWBA;
442 ath_beaconq_config(sc);
443 436
444 /* Set the computed AP beacon timers */ 437 ath_dbg(common, BEACON, "AP nexttbtt: %u intval: %u conf_intval: %u\n",
438 nexttbtt, intval, conf->beacon_interval);
445 439
446 ath9k_hw_disable_interrupts(ah); 440 ath_beaconq_config(sc);
447 set_bit(SC_OP_TSF_RESET, &sc->sc_flags);
448 ath9k_beacon_init(sc, nexttbtt, intval); 441 ath9k_beacon_init(sc, nexttbtt, intval);
449 sc->beacon.bmisscnt = 0;
450 ath9k_hw_set_interrupts(ah);
451 ath9k_hw_enable_interrupts(ah);
452} 442}
453 443
454/* 444/*
@@ -459,8 +449,8 @@ static void ath_beacon_config_ap(struct ath_softc *sc,
459 * we'll receive a BMISS interrupt when we stop seeing beacons from the AP 449 * we'll receive a BMISS interrupt when we stop seeing beacons from the AP
460 * we've associated with. 450 * we've associated with.
461 */ 451 */
462static void ath_beacon_config_sta(struct ath_softc *sc, 452static void ath9k_beacon_config_sta(struct ath_softc *sc,
463 struct ath_beacon_config *conf) 453 struct ath_beacon_config *conf)
464{ 454{
465 struct ath_hw *ah = sc->sc_ah; 455 struct ath_hw *ah = sc->sc_ah;
466 struct ath_common *common = ath9k_hw_common(ah); 456 struct ath_common *common = ath9k_hw_common(ah);
@@ -579,97 +569,66 @@ static void ath_beacon_config_sta(struct ath_softc *sc,
579 ath9k_hw_enable_interrupts(ah); 569 ath9k_hw_enable_interrupts(ah);
580} 570}
581 571
582static void ath_beacon_config_adhoc(struct ath_softc *sc, 572static void ath9k_beacon_config_adhoc(struct ath_softc *sc,
583 struct ath_beacon_config *conf) 573 struct ath_beacon_config *conf)
584{ 574{
585 struct ath_hw *ah = sc->sc_ah; 575 struct ath_hw *ah = sc->sc_ah;
586 struct ath_common *common = ath9k_hw_common(ah); 576 struct ath_common *common = ath9k_hw_common(ah);
587 u32 tsf, intval, nexttbtt; 577 u32 intval, nexttbtt;
588 578
589 ath9k_reset_beacon_status(sc); 579 ath9k_reset_beacon_status(sc);
590 if (!test_bit(SC_OP_BEACONS, &sc->sc_flags))
591 ath9k_hw_settsf64(ah, sc->beacon.bc_tstamp);
592 580
593 intval = TU_TO_USEC(conf->beacon_interval); 581 intval = TU_TO_USEC(conf->beacon_interval);
594 tsf = roundup(ath9k_hw_gettsf32(ah) + TU_TO_USEC(FUDGE), intval); 582 nexttbtt = intval;
595 nexttbtt = tsf + intval;
596 583
597 ath_dbg(common, BEACON, "IBSS nexttbtt %u intval %u (%u)\n", 584 if (conf->enable_beacon)
598 nexttbtt, intval, conf->beacon_interval); 585 ah->imask |= ATH9K_INT_SWBA;
586 else
587 ah->imask &= ~ATH9K_INT_SWBA;
599 588
600 /* 589 ath_dbg(common, BEACON, "IBSS nexttbtt: %u intval: %u conf_intval: %u\n",
601 * In IBSS mode enable the beacon timers but only enable SWBA interrupts 590 nexttbtt, intval, conf->beacon_interval);
602 * if we need to manually prepare beacon frames. Otherwise we use a
603 * self-linked tx descriptor and let the hardware deal with things.
604 */
605 ah->imask |= ATH9K_INT_SWBA;
606 591
607 ath_beaconq_config(sc); 592 ath_beaconq_config(sc);
608
609 /* Set the computed ADHOC beacon timers */
610
611 ath9k_hw_disable_interrupts(ah);
612 ath9k_beacon_init(sc, nexttbtt, intval); 593 ath9k_beacon_init(sc, nexttbtt, intval);
613 sc->beacon.bmisscnt = 0;
614
615 ath9k_hw_set_interrupts(ah);
616 ath9k_hw_enable_interrupts(ah);
617} 594}
618 595
619static bool ath9k_allow_beacon_config(struct ath_softc *sc, 596bool ath9k_allow_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
620 struct ieee80211_vif *vif)
621{ 597{
622 struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
623 struct ath_common *common = ath9k_hw_common(sc->sc_ah); 598 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
624 struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
625 struct ath_vif *avp = (void *)vif->drv_priv; 599 struct ath_vif *avp = (void *)vif->drv_priv;
626 600
627 /* 601 if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) {
628 * Can not have different beacon interval on multiple 602 if ((vif->type != NL80211_IFTYPE_AP) ||
629 * AP interface case 603 (sc->nbcnvifs > 1)) {
630 */ 604 ath_dbg(common, CONFIG,
631 if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) && 605 "An AP interface is already present !\n");
632 (sc->nbcnvifs > 1) && 606 return false;
633 (vif->type == NL80211_IFTYPE_AP) && 607 }
634 (cur_conf->beacon_interval != bss_conf->beacon_int)) {
635 ath_dbg(common, CONFIG,
636 "Changing beacon interval of multiple AP interfaces !\n");
637 return false;
638 }
639 /*
640 * Can not configure station vif's beacon config
641 * while on AP opmode
642 */
643 if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) &&
644 (vif->type != NL80211_IFTYPE_AP)) {
645 ath_dbg(common, CONFIG,
646 "STA vif's beacon not allowed on AP mode\n");
647 return false;
648 } 608 }
649 /* 609
650 * Do not allow beacon config if HW was already configured 610 if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) {
651 * with another STA vif 611 if ((vif->type == NL80211_IFTYPE_STATION) &&
652 */ 612 test_bit(SC_OP_BEACONS, &sc->sc_flags) &&
653 if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) && 613 !avp->primary_sta_vif) {
654 (vif->type == NL80211_IFTYPE_STATION) && 614 ath_dbg(common, CONFIG,
655 test_bit(SC_OP_BEACONS, &sc->sc_flags) && 615 "Beacon already configured for a station interface\n");
656 !avp->primary_sta_vif) { 616 return false;
657 ath_dbg(common, CONFIG, 617 }
658 "Beacon already configured for a station interface\n");
659 return false;
660 } 618 }
619
661 return true; 620 return true;
662} 621}
663 622
664void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) 623static void ath9k_cache_beacon_config(struct ath_softc *sc,
624 struct ieee80211_bss_conf *bss_conf)
665{ 625{
626 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
666 struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; 627 struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
667 struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
668 628
669 if (!ath9k_allow_beacon_config(sc, vif)) 629 ath_dbg(common, BEACON,
670 return; 630 "Caching beacon data for BSS: %pM\n", bss_conf->bssid);
671 631
672 /* Setup the beacon configuration parameters */
673 cur_conf->beacon_interval = bss_conf->beacon_int; 632 cur_conf->beacon_interval = bss_conf->beacon_int;
674 cur_conf->dtim_period = bss_conf->dtim_period; 633 cur_conf->dtim_period = bss_conf->dtim_period;
675 cur_conf->listen_interval = 1; 634 cur_conf->listen_interval = 1;
@@ -694,73 +653,62 @@ void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
694 if (cur_conf->dtim_period == 0) 653 if (cur_conf->dtim_period == 0)
695 cur_conf->dtim_period = 1; 654 cur_conf->dtim_period = 1;
696 655
697 ath_set_beacon(sc);
698} 656}
699 657
700static bool ath_has_valid_bslot(struct ath_softc *sc) 658void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif,
659 u32 changed)
701{ 660{
702 struct ath_vif *avp; 661 struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
703 int slot; 662 struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
704 bool found = false;
705 663
706 for (slot = 0; slot < ATH_BCBUF; slot++) { 664 if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) {
707 if (sc->beacon.bslot[slot]) { 665 ath9k_cache_beacon_config(sc, bss_conf);
708 avp = (void *)sc->beacon.bslot[slot]->drv_priv; 666 ath9k_set_beacon(sc);
709 if (avp->is_bslot_active) { 667 set_bit(SC_OP_BEACONS, &sc->sc_flags);
710 found = true; 668 } else {
711 break; 669 /*
670 * Take care of multiple interfaces when
671 * enabling/disabling SWBA.
672 */
673 if (changed & BSS_CHANGED_BEACON_ENABLED) {
674 if (!bss_conf->enable_beacon &&
675 (sc->nbcnvifs <= 1)) {
676 cur_conf->enable_beacon = false;
677 } else if (bss_conf->enable_beacon) {
678 cur_conf->enable_beacon = true;
679 ath9k_cache_beacon_config(sc, bss_conf);
712 } 680 }
713 } 681 }
682
683 if (cur_conf->beacon_interval) {
684 ath9k_set_beacon(sc);
685
686 if (cur_conf->enable_beacon)
687 set_bit(SC_OP_BEACONS, &sc->sc_flags);
688 else
689 clear_bit(SC_OP_BEACONS, &sc->sc_flags);
690 }
714 } 691 }
715 return found;
716} 692}
717 693
718 694void ath9k_set_beacon(struct ath_softc *sc)
719void ath_set_beacon(struct ath_softc *sc)
720{ 695{
721 struct ath_common *common = ath9k_hw_common(sc->sc_ah); 696 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
722 struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; 697 struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
723 698
724 switch (sc->sc_ah->opmode) { 699 switch (sc->sc_ah->opmode) {
725 case NL80211_IFTYPE_AP: 700 case NL80211_IFTYPE_AP:
726 if (ath_has_valid_bslot(sc)) 701 ath9k_beacon_config_ap(sc, cur_conf);
727 ath_beacon_config_ap(sc, cur_conf);
728 break; 702 break;
729 case NL80211_IFTYPE_ADHOC: 703 case NL80211_IFTYPE_ADHOC:
730 case NL80211_IFTYPE_MESH_POINT: 704 case NL80211_IFTYPE_MESH_POINT:
731 ath_beacon_config_adhoc(sc, cur_conf); 705 ath9k_beacon_config_adhoc(sc, cur_conf);
732 break; 706 break;
733 case NL80211_IFTYPE_STATION: 707 case NL80211_IFTYPE_STATION:
734 ath_beacon_config_sta(sc, cur_conf); 708 ath9k_beacon_config_sta(sc, cur_conf);
735 break; 709 break;
736 default: 710 default:
737 ath_dbg(common, CONFIG, "Unsupported beaconing mode\n"); 711 ath_dbg(common, CONFIG, "Unsupported beaconing mode\n");
738 return; 712 return;
739 } 713 }
740
741 set_bit(SC_OP_BEACONS, &sc->sc_flags);
742}
743
744void ath9k_set_beaconing_status(struct ath_softc *sc, bool status)
745{
746 struct ath_hw *ah = sc->sc_ah;
747
748 if (!ath_has_valid_bslot(sc)) {
749 clear_bit(SC_OP_BEACONS, &sc->sc_flags);
750 return;
751 }
752
753 ath9k_ps_wakeup(sc);
754 if (status) {
755 /* Re-enable beaconing */
756 ah->imask |= ATH9K_INT_SWBA;
757 ath9k_hw_set_interrupts(ah);
758 } else {
759 /* Disable SWBA interrupt */
760 ah->imask &= ~ATH9K_INT_SWBA;
761 ath9k_hw_set_interrupts(ah);
762 tasklet_kill(&sc->bcon_tasklet);
763 ath9k_hw_stop_dma_queue(ah, sc->beacon.beaconq);
764 }
765 ath9k_ps_restore(sc);
766} 714}
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 2a155ce2d461..e411189abd7d 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -236,7 +236,7 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start)
236 if (!test_bit(SC_OP_BEACONS, &sc->sc_flags)) 236 if (!test_bit(SC_OP_BEACONS, &sc->sc_flags))
237 goto work; 237 goto work;
238 238
239 ath_set_beacon(sc); 239 ath9k_set_beacon(sc);
240 240
241 if (ah->opmode == NL80211_IFTYPE_STATION && 241 if (ah->opmode == NL80211_IFTYPE_STATION &&
242 test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) { 242 test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) {
@@ -1533,24 +1533,10 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
1533 } 1533 }
1534 } 1534 }
1535 1535
1536 /* 1536 if ((changed & BSS_CHANGED_BEACON_ENABLED) ||
1537 * In case of AP mode, the HW TSF has to be reset 1537 (changed & BSS_CHANGED_BEACON_INT)) {
1538 * when the beacon interval changes. 1538 if (ath9k_allow_beacon_config(sc, vif))
1539 */ 1539 ath9k_beacon_config(sc, vif, changed);
1540 if ((changed & BSS_CHANGED_BEACON_INT) &&
1541 (vif->type == NL80211_IFTYPE_AP))
1542 set_bit(SC_OP_TSF_RESET, &sc->sc_flags);
1543
1544 /* Configure beaconing (AP, IBSS, MESH) */
1545 if (ath9k_uses_beacons(vif->type) &&
1546 ((changed & BSS_CHANGED_BEACON) ||
1547 (changed & BSS_CHANGED_BEACON_ENABLED) ||
1548 (changed & BSS_CHANGED_BEACON_INT))) {
1549 ath9k_set_beaconing_status(sc, false);
1550 if (!bss_conf->enable_beacon)
1551 avp->is_bslot_active = false;
1552 ath_beacon_config(sc, vif);
1553 ath9k_set_beaconing_status(sc, true);
1554 } 1540 }
1555 1541
1556 if (changed & BSS_CHANGED_ERP_SLOT) { 1542 if (changed & BSS_CHANGED_ERP_SLOT) {
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index 11f3703a420a..12aca02228c2 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -553,7 +553,7 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
553 sc->ps_flags &= ~PS_BEACON_SYNC; 553 sc->ps_flags &= ~PS_BEACON_SYNC;
554 ath_dbg(common, PS, 554 ath_dbg(common, PS,
555 "Reconfigure Beacon timers based on timestamp from the AP\n"); 555 "Reconfigure Beacon timers based on timestamp from the AP\n");
556 ath_set_beacon(sc); 556 ath9k_set_beacon(sc);
557 } 557 }
558 558
559 if (ath_beacon_dtim_pending_cab(skb)) { 559 if (ath_beacon_dtim_pending_cab(skb)) {