@@ -209,7 +209,6 @@ void ath9k_beacon_assign_slot(struct ath_softc *sc, struct ieee80211_vif *vif)
209209 }
210210
211211 sc -> beacon .bslot [avp -> av_bslot ] = vif ;
212- sc -> nbcnvifs ++ ;
213212
214213 ath_dbg (common , CONFIG , "Added interface at beacon slot: %d\n" ,
215214 avp -> av_bslot );
@@ -220,15 +219,12 @@ void ath9k_beacon_remove_slot(struct ath_softc *sc, struct ieee80211_vif *vif)
220219 struct ath_common * common = ath9k_hw_common (sc -> sc_ah );
221220 struct ath_vif * avp = (void * )vif -> drv_priv ;
222221 struct ath_buf * bf = avp -> av_bcbuf ;
223- struct ath_beacon_config * cur_conf = & sc -> cur_chan -> beacon ;
224222
225223 ath_dbg (common , CONFIG , "Removing interface at beacon slot: %d\n" ,
226224 avp -> av_bslot );
227225
228226 tasklet_disable (& sc -> bcon_tasklet );
229227
230- cur_conf -> enable_beacon &= ~BIT (avp -> av_bslot );
231-
232228 if (bf && bf -> bf_mpdu ) {
233229 struct sk_buff * skb = bf -> bf_mpdu ;
234230 dma_unmap_single (sc -> dev , bf -> bf_buf_addr ,
@@ -240,12 +236,73 @@ void ath9k_beacon_remove_slot(struct ath_softc *sc, struct ieee80211_vif *vif)
240236
241237 avp -> av_bcbuf = NULL ;
242238 sc -> beacon .bslot [avp -> av_bslot ] = NULL ;
243- sc -> nbcnvifs -- ;
244239 list_add_tail (& bf -> list , & sc -> beacon .bbuf );
245240
246241 tasklet_enable (& sc -> bcon_tasklet );
247242}
248243
244+ void ath9k_beacon_ensure_primary_slot (struct ath_softc * sc )
245+ {
246+ struct ath_common * common = ath9k_hw_common (sc -> sc_ah );
247+ struct ieee80211_vif * vif ;
248+ struct ath_vif * avp ;
249+ s64 tsfadjust ;
250+ u32 offset ;
251+ int first_slot = ATH_BCBUF ;
252+ int slot ;
253+
254+ tasklet_disable (& sc -> bcon_tasklet );
255+
256+ /* Find first taken slot. */
257+ for (slot = 0 ; slot < ATH_BCBUF ; slot ++ ) {
258+ if (sc -> beacon .bslot [slot ]) {
259+ first_slot = slot ;
260+ break ;
261+ }
262+ }
263+ if (first_slot == 0 )
264+ goto out ;
265+
266+ /* Re-enumarate all slots, moving them forward. */
267+ for (slot = 0 ; slot < ATH_BCBUF ; slot ++ ) {
268+ if (slot + first_slot < ATH_BCBUF ) {
269+ vif = sc -> beacon .bslot [slot + first_slot ];
270+ sc -> beacon .bslot [slot ] = vif ;
271+
272+ if (vif ) {
273+ avp = (void * )vif -> drv_priv ;
274+ avp -> av_bslot = slot ;
275+ }
276+ } else {
277+ sc -> beacon .bslot [slot ] = NULL ;
278+ }
279+ }
280+
281+ vif = sc -> beacon .bslot [0 ];
282+ if (WARN_ON (!vif ))
283+ goto out ;
284+
285+ /* Get the tsf_adjust value for the new first slot. */
286+ avp = (void * )vif -> drv_priv ;
287+ tsfadjust = le64_to_cpu (avp -> tsf_adjust );
288+
289+ ath_dbg (common , CONFIG ,
290+ "Adjusting global TSF after beacon slot reassignment: %lld\n" ,
291+ (signed long long )tsfadjust );
292+
293+ /* Modify TSF as required and update the HW. */
294+ avp -> chanctx -> tsf_val += tsfadjust ;
295+ if (sc -> cur_chan == avp -> chanctx ) {
296+ offset = ath9k_hw_get_tsf_offset (& avp -> chanctx -> tsf_ts , NULL );
297+ ath9k_hw_settsf64 (sc -> sc_ah , avp -> chanctx -> tsf_val + offset );
298+ }
299+
300+ /* The slots tsf_adjust will be updated by ath9k_beacon_config later. */
301+
302+ out :
303+ tasklet_enable (& sc -> bcon_tasklet );
304+ }
305+
249306static int ath9k_beacon_choose_slot (struct ath_softc * sc )
250307{
251308 struct ath_common * common = ath9k_hw_common (sc -> sc_ah );
@@ -274,26 +331,33 @@ static int ath9k_beacon_choose_slot(struct ath_softc *sc)
274331 return slot ;
275332}
276333
277- static void ath9k_set_tsfadjust (struct ath_softc * sc , struct ieee80211_vif * vif )
334+ static void ath9k_set_tsfadjust (struct ath_softc * sc ,
335+ struct ath_beacon_config * cur_conf )
278336{
279337 struct ath_common * common = ath9k_hw_common (sc -> sc_ah );
280- struct ath_vif * avp = (void * )vif -> drv_priv ;
281- struct ath_beacon_config * cur_conf = & avp -> chanctx -> beacon ;
282338 s64 tsfadjust ;
339+ int slot ;
283340
284- if ( avp -> av_bslot == 0 )
285- return ;
341+ for ( slot = 0 ; slot < ATH_BCBUF ; slot ++ ) {
342+ struct ath_vif * avp ;
286343
287- /* tsf_adjust is added to the TSF value. We send out the beacon late,
288- * so need to adjust the TSF starting point to be later in time (i.e.
289- * the theoretical first beacon has a TSF of 0 after correction).
290- */
291- tsfadjust = cur_conf -> beacon_interval * avp -> av_bslot ;
292- tsfadjust = - TU_TO_USEC (tsfadjust ) / ATH_BCBUF ;
293- avp -> tsf_adjust = cpu_to_le64 (tsfadjust );
344+ if (!sc -> beacon .bslot [slot ])
345+ continue ;
346+
347+ avp = (void * )sc -> beacon .bslot [slot ]-> drv_priv ;
294348
295- ath_dbg (common , CONFIG , "tsfadjust is: %lld for bslot: %d\n" ,
296- (signed long long )tsfadjust , avp -> av_bslot );
349+ /* tsf_adjust is added to the TSF value. We send out the
350+ * beacon late, so need to adjust the TSF starting point to be
351+ * later in time (i.e. the theoretical first beacon has a TSF
352+ * of 0 after correction).
353+ */
354+ tsfadjust = cur_conf -> beacon_interval * avp -> av_bslot ;
355+ tsfadjust = - TU_TO_USEC (tsfadjust ) / ATH_BCBUF ;
356+ avp -> tsf_adjust = cpu_to_le64 (tsfadjust );
357+
358+ ath_dbg (common , CONFIG , "tsfadjust is: %lld for bslot: %d\n" ,
359+ (signed long long )tsfadjust , avp -> av_bslot );
360+ }
297361}
298362
299363bool ath9k_csa_is_finished (struct ath_softc * sc , struct ieee80211_vif * vif )
@@ -447,20 +511,28 @@ void ath9k_beacon_tasklet(unsigned long data)
447511 * Both nexttbtt and intval have to be in usecs.
448512 */
449513static void ath9k_beacon_init (struct ath_softc * sc , u32 nexttbtt ,
450- u32 intval , bool reset_tsf )
514+ u32 intval )
451515{
452516 struct ath_hw * ah = sc -> sc_ah ;
453517
454518 ath9k_hw_disable_interrupts (ah );
455- if (reset_tsf )
456- ath9k_hw_reset_tsf (ah );
457519 ath9k_beaconq_config (sc );
458520 ath9k_hw_beaconinit (ah , nexttbtt , intval );
521+ ah -> imask |= ATH9K_INT_SWBA ;
459522 sc -> beacon .bmisscnt = 0 ;
460523 ath9k_hw_set_interrupts (ah );
461524 ath9k_hw_enable_interrupts (ah );
462525}
463526
527+ static void ath9k_beacon_stop (struct ath_softc * sc )
528+ {
529+ ath9k_hw_disable_interrupts (sc -> sc_ah );
530+ sc -> sc_ah -> imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS );
531+ sc -> beacon .bmisscnt = 0 ;
532+ ath9k_hw_set_interrupts (sc -> sc_ah );
533+ ath9k_hw_enable_interrupts (sc -> sc_ah );
534+ }
535+
464536/*
465537 * For multi-bss ap support beacons are either staggered evenly over N slots or
466538 * burst together. For the former arrange for the SWBA to be delivered for each
@@ -472,7 +544,7 @@ static void ath9k_beacon_config_ap(struct ath_softc *sc,
472544 struct ath_hw * ah = sc -> sc_ah ;
473545
474546 ath9k_cmn_beacon_config_ap (ah , conf , ATH_BCBUF );
475- ath9k_beacon_init (sc , conf -> nexttbtt , conf -> intval , false );
547+ ath9k_beacon_init (sc , conf -> nexttbtt , conf -> intval );
476548}
477549
478550static void ath9k_beacon_config_sta (struct ath_hw * ah ,
@@ -501,7 +573,7 @@ static void ath9k_beacon_config_adhoc(struct ath_softc *sc,
501573
502574 ath9k_cmn_beacon_config_adhoc (ah , conf );
503575
504- ath9k_beacon_init (sc , conf -> nexttbtt , conf -> intval , conf -> ibss_creator );
576+ ath9k_beacon_init (sc , conf -> nexttbtt , conf -> intval );
505577
506578 /*
507579 * Set the global 'beacon has been configured' flag for the
@@ -511,44 +583,6 @@ static void ath9k_beacon_config_adhoc(struct ath_softc *sc,
511583 set_bit (ATH_OP_BEACONS , & common -> op_flags );
512584}
513585
514- static bool ath9k_allow_beacon_config (struct ath_softc * sc ,
515- struct ieee80211_vif * vif )
516- {
517- struct ath_common * common = ath9k_hw_common (sc -> sc_ah );
518- struct ath_vif * avp = (void * )vif -> drv_priv ;
519-
520- if (ath9k_is_chanctx_enabled ()) {
521- /*
522- * If the VIF is not present in the current channel context,
523- * then we can't do the usual opmode checks. Allow the
524- * beacon config for the VIF to be updated in this case and
525- * return immediately.
526- */
527- if (sc -> cur_chan != avp -> chanctx )
528- return true;
529- }
530-
531- if (sc -> sc_ah -> opmode == NL80211_IFTYPE_AP ) {
532- if (vif -> type != NL80211_IFTYPE_AP ) {
533- ath_dbg (common , CONFIG ,
534- "An AP interface is already present !\n" );
535- return false;
536- }
537- }
538-
539- if (sc -> sc_ah -> opmode == NL80211_IFTYPE_STATION ) {
540- if ((vif -> type == NL80211_IFTYPE_STATION ) &&
541- test_bit (ATH_OP_BEACONS , & common -> op_flags ) &&
542- vif != sc -> cur_chan -> primary_sta ) {
543- ath_dbg (common , CONFIG ,
544- "Beacon already configured for a station interface\n" );
545- return false;
546- }
547- }
548-
549- return true;
550- }
551-
552586static void ath9k_cache_beacon_config (struct ath_softc * sc ,
553587 struct ath_chanctx * ctx ,
554588 struct ieee80211_bss_conf * bss_conf )
@@ -584,87 +618,79 @@ static void ath9k_cache_beacon_config(struct ath_softc *sc,
584618 if (cur_conf -> dtim_period == 0 )
585619 cur_conf -> dtim_period = 1 ;
586620
621+ ath9k_set_tsfadjust (sc , cur_conf );
587622}
588623
589- void ath9k_beacon_config (struct ath_softc * sc , struct ieee80211_vif * vif ,
590- u32 changed )
624+ void ath9k_beacon_config (struct ath_softc * sc , struct ieee80211_vif * main_vif ,
625+ bool beacons )
591626{
592- struct ieee80211_bss_conf * bss_conf = & vif -> bss_conf ;
593- struct ath_hw * ah = sc -> sc_ah ;
594- struct ath_common * common = ath9k_hw_common (ah );
595- struct ath_vif * avp = (void * )vif -> drv_priv ;
596- struct ath_chanctx * ctx = avp -> chanctx ;
627+ struct ath_hw * ah = sc -> sc_ah ;
628+ struct ath_common * common = ath9k_hw_common (ah );
629+ struct ath_vif * avp ;
630+ struct ath_chanctx * ctx ;
597631 struct ath_beacon_config * cur_conf ;
598632 unsigned long flags ;
633+ bool enabled ;
599634 bool skip_beacon = false;
600635
601- if (!ctx )
636+ if (!beacons ) {
637+ clear_bit (ATH_OP_BEACONS , & common -> op_flags );
638+ ath9k_beacon_stop (sc );
602639 return ;
640+ }
603641
604- cur_conf = & avp -> chanctx -> beacon ;
605- if (vif -> type == NL80211_IFTYPE_AP )
606- ath9k_set_tsfadjust (sc , vif );
607-
608- if (!ath9k_allow_beacon_config (sc , vif ))
642+ if (WARN_ON (!main_vif ))
609643 return ;
610644
611- if (vif -> type == NL80211_IFTYPE_STATION ) {
612- ath9k_cache_beacon_config (sc , ctx , bss_conf );
613- if (ctx != sc -> cur_chan )
614- return ;
645+ avp = (void * )main_vif -> drv_priv ;
646+ ctx = avp -> chanctx ;
647+ cur_conf = & ctx -> beacon ;
648+ enabled = cur_conf -> enable_beacon ;
649+ cur_conf -> enable_beacon = beacons ;
650+
651+ if (sc -> sc_ah -> opmode == NL80211_IFTYPE_STATION ) {
652+ ath9k_cache_beacon_config (sc , ctx , & main_vif -> bss_conf );
615653
616654 ath9k_set_beacon (sc );
617655 set_bit (ATH_OP_BEACONS , & common -> op_flags );
618656 return ;
619657 }
620658
621- /*
622- * Take care of multiple interfaces when
623- * enabling/disabling SWBA.
624- */
625- if (changed & BSS_CHANGED_BEACON_ENABLED ) {
626- bool enabled = cur_conf -> enable_beacon ;
627-
628- if (!bss_conf -> enable_beacon ) {
629- cur_conf -> enable_beacon &= ~BIT (avp -> av_bslot );
630- } else {
631- cur_conf -> enable_beacon |= BIT (avp -> av_bslot );
632- if (!enabled )
633- ath9k_cache_beacon_config (sc , ctx , bss_conf );
634- }
635- }
636-
637- if (ctx != sc -> cur_chan )
638- return ;
659+ /* Update the beacon configuration. */
660+ ath9k_cache_beacon_config (sc , ctx , & main_vif -> bss_conf );
639661
640662 /*
641663 * Configure the HW beacon registers only when we have a valid
642664 * beacon interval.
643665 */
644666 if (cur_conf -> beacon_interval ) {
645- /*
646- * If we are joining an existing IBSS network, start beaconing
647- * only after a TSF-sync has taken place. Ensure that this
648- * happens by setting the appropriate flags .
667+ /* Special case to sync the TSF when joining an existing IBSS.
668+ * This is only done if no AP interface is active.
669+ * Note that mac80211 always resets the TSF when creating a new
670+ * IBSS interface .
649671 */
650- if (( changed & BSS_CHANGED_IBSS ) && ! bss_conf -> ibss_creator &&
651- bss_conf -> enable_beacon ) {
672+ if (sc -> sc_ah -> opmode == NL80211_IFTYPE_ADHOC &&
673+ ! enabled && beacons && ! main_vif -> bss_conf . ibss_creator ) {
652674 spin_lock_irqsave (& sc -> sc_pm_lock , flags );
653675 sc -> ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON ;
654676 spin_unlock_irqrestore (& sc -> sc_pm_lock , flags );
655677 skip_beacon = true;
656- } else {
657- ath9k_set_beacon (sc );
658678 }
659679
660680 /*
661681 * Do not set the ATH_OP_BEACONS flag for IBSS joiner mode
662682 * here, it is done in ath9k_beacon_config_adhoc().
663683 */
664- if (cur_conf -> enable_beacon && !skip_beacon )
684+ if (beacons && !skip_beacon ) {
665685 set_bit (ATH_OP_BEACONS , & common -> op_flags );
666- else
686+ ath9k_set_beacon (sc );
687+ } else {
667688 clear_bit (ATH_OP_BEACONS , & common -> op_flags );
689+ ath9k_beacon_stop (sc );
690+ }
691+ } else {
692+ clear_bit (ATH_OP_BEACONS , & common -> op_flags );
693+ ath9k_beacon_stop (sc );
668694 }
669695}
670696
0 commit comments