@@ -209,7 +209,6 @@ void ath9k_beacon_assign_slot(struct ath_softc *sc, struct ieee80211_vif *vif)
209
209
}
210
210
211
211
sc -> beacon .bslot [avp -> av_bslot ] = vif ;
212
- sc -> nbcnvifs ++ ;
213
212
214
213
ath_dbg (common , CONFIG , "Added interface at beacon slot: %d\n" ,
215
214
avp -> av_bslot );
@@ -220,15 +219,12 @@ void ath9k_beacon_remove_slot(struct ath_softc *sc, struct ieee80211_vif *vif)
220
219
struct ath_common * common = ath9k_hw_common (sc -> sc_ah );
221
220
struct ath_vif * avp = (void * )vif -> drv_priv ;
222
221
struct ath_buf * bf = avp -> av_bcbuf ;
223
- struct ath_beacon_config * cur_conf = & sc -> cur_chan -> beacon ;
224
222
225
223
ath_dbg (common , CONFIG , "Removing interface at beacon slot: %d\n" ,
226
224
avp -> av_bslot );
227
225
228
226
tasklet_disable (& sc -> bcon_tasklet );
229
227
230
- cur_conf -> enable_beacon &= ~BIT (avp -> av_bslot );
231
-
232
228
if (bf && bf -> bf_mpdu ) {
233
229
struct sk_buff * skb = bf -> bf_mpdu ;
234
230
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)
240
236
241
237
avp -> av_bcbuf = NULL ;
242
238
sc -> beacon .bslot [avp -> av_bslot ] = NULL ;
243
- sc -> nbcnvifs -- ;
244
239
list_add_tail (& bf -> list , & sc -> beacon .bbuf );
245
240
246
241
tasklet_enable (& sc -> bcon_tasklet );
247
242
}
248
243
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
+
249
306
static int ath9k_beacon_choose_slot (struct ath_softc * sc )
250
307
{
251
308
struct ath_common * common = ath9k_hw_common (sc -> sc_ah );
@@ -274,26 +331,33 @@ static int ath9k_beacon_choose_slot(struct ath_softc *sc)
274
331
return slot ;
275
332
}
276
333
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 )
278
336
{
279
337
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 ;
282
338
s64 tsfadjust ;
339
+ int slot ;
283
340
284
- if ( avp -> av_bslot == 0 )
285
- return ;
341
+ for ( slot = 0 ; slot < ATH_BCBUF ; slot ++ ) {
342
+ struct ath_vif * avp ;
286
343
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 ;
294
348
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
+ }
297
361
}
298
362
299
363
bool ath9k_csa_is_finished (struct ath_softc * sc , struct ieee80211_vif * vif )
@@ -447,20 +511,28 @@ void ath9k_beacon_tasklet(unsigned long data)
447
511
* Both nexttbtt and intval have to be in usecs.
448
512
*/
449
513
static void ath9k_beacon_init (struct ath_softc * sc , u32 nexttbtt ,
450
- u32 intval , bool reset_tsf )
514
+ u32 intval )
451
515
{
452
516
struct ath_hw * ah = sc -> sc_ah ;
453
517
454
518
ath9k_hw_disable_interrupts (ah );
455
- if (reset_tsf )
456
- ath9k_hw_reset_tsf (ah );
457
519
ath9k_beaconq_config (sc );
458
520
ath9k_hw_beaconinit (ah , nexttbtt , intval );
521
+ ah -> imask |= ATH9K_INT_SWBA ;
459
522
sc -> beacon .bmisscnt = 0 ;
460
523
ath9k_hw_set_interrupts (ah );
461
524
ath9k_hw_enable_interrupts (ah );
462
525
}
463
526
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
+
464
536
/*
465
537
* For multi-bss ap support beacons are either staggered evenly over N slots or
466
538
* 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,
472
544
struct ath_hw * ah = sc -> sc_ah ;
473
545
474
546
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 );
476
548
}
477
549
478
550
static void ath9k_beacon_config_sta (struct ath_hw * ah ,
@@ -501,7 +573,7 @@ static void ath9k_beacon_config_adhoc(struct ath_softc *sc,
501
573
502
574
ath9k_cmn_beacon_config_adhoc (ah , conf );
503
575
504
- ath9k_beacon_init (sc , conf -> nexttbtt , conf -> intval , conf -> ibss_creator );
576
+ ath9k_beacon_init (sc , conf -> nexttbtt , conf -> intval );
505
577
506
578
/*
507
579
* Set the global 'beacon has been configured' flag for the
@@ -511,44 +583,6 @@ static void ath9k_beacon_config_adhoc(struct ath_softc *sc,
511
583
set_bit (ATH_OP_BEACONS , & common -> op_flags );
512
584
}
513
585
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
-
552
586
static void ath9k_cache_beacon_config (struct ath_softc * sc ,
553
587
struct ath_chanctx * ctx ,
554
588
struct ieee80211_bss_conf * bss_conf )
@@ -584,87 +618,79 @@ static void ath9k_cache_beacon_config(struct ath_softc *sc,
584
618
if (cur_conf -> dtim_period == 0 )
585
619
cur_conf -> dtim_period = 1 ;
586
620
621
+ ath9k_set_tsfadjust (sc , cur_conf );
587
622
}
588
623
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 )
591
626
{
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 ;
597
631
struct ath_beacon_config * cur_conf ;
598
632
unsigned long flags ;
633
+ bool enabled ;
599
634
bool skip_beacon = false;
600
635
601
- if (!ctx )
636
+ if (!beacons ) {
637
+ clear_bit (ATH_OP_BEACONS , & common -> op_flags );
638
+ ath9k_beacon_stop (sc );
602
639
return ;
640
+ }
603
641
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 ))
609
643
return ;
610
644
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 );
615
653
616
654
ath9k_set_beacon (sc );
617
655
set_bit (ATH_OP_BEACONS , & common -> op_flags );
618
656
return ;
619
657
}
620
658
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 );
639
661
640
662
/*
641
663
* Configure the HW beacon registers only when we have a valid
642
664
* beacon interval.
643
665
*/
644
666
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 .
649
671
*/
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 ) {
652
674
spin_lock_irqsave (& sc -> sc_pm_lock , flags );
653
675
sc -> ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON ;
654
676
spin_unlock_irqrestore (& sc -> sc_pm_lock , flags );
655
677
skip_beacon = true;
656
- } else {
657
- ath9k_set_beacon (sc );
658
678
}
659
679
660
680
/*
661
681
* Do not set the ATH_OP_BEACONS flag for IBSS joiner mode
662
682
* here, it is done in ath9k_beacon_config_adhoc().
663
683
*/
664
- if (cur_conf -> enable_beacon && !skip_beacon )
684
+ if (beacons && !skip_beacon ) {
665
685
set_bit (ATH_OP_BEACONS , & common -> op_flags );
666
- else
686
+ ath9k_set_beacon (sc );
687
+ } else {
667
688
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 );
668
694
}
669
695
}
670
696
0 commit comments