1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27#include "ath5k.h"
28#include "reg.h"
29#include "debug.h"
30#include "base.h"
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45int ath5k_hw_set_opmode(struct ath5k_hw *ah)
46{
47 u32 pcu_reg, beacon_reg, low_id, high_id;
48
49
50
51 pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000;
52 pcu_reg &= ~(AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_AP
53 | AR5K_STA_ID1_KEYSRCH_MODE
54 | (ah->ah_version == AR5K_AR5210 ?
55 (AR5K_STA_ID1_PWR_SV | AR5K_STA_ID1_NO_PSPOLL) : 0));
56
57 beacon_reg = 0;
58
59 ATH5K_TRACE(ah->ah_sc);
60
61 switch (ah->ah_op_mode) {
62 case NL80211_IFTYPE_ADHOC:
63 pcu_reg |= AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_KEYSRCH_MODE;
64 beacon_reg |= AR5K_BCR_ADHOC;
65 if (ah->ah_version == AR5K_AR5210)
66 pcu_reg |= AR5K_STA_ID1_NO_PSPOLL;
67 else
68 AR5K_REG_ENABLE_BITS(ah, AR5K_CFG, AR5K_CFG_IBSS);
69 break;
70
71 case NL80211_IFTYPE_AP:
72 case NL80211_IFTYPE_MESH_POINT:
73 pcu_reg |= AR5K_STA_ID1_AP | AR5K_STA_ID1_KEYSRCH_MODE;
74 beacon_reg |= AR5K_BCR_AP;
75 if (ah->ah_version == AR5K_AR5210)
76 pcu_reg |= AR5K_STA_ID1_NO_PSPOLL;
77 else
78 AR5K_REG_DISABLE_BITS(ah, AR5K_CFG, AR5K_CFG_IBSS);
79 break;
80
81 case NL80211_IFTYPE_STATION:
82 pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE
83 | (ah->ah_version == AR5K_AR5210 ?
84 AR5K_STA_ID1_PWR_SV : 0);
85 case NL80211_IFTYPE_MONITOR:
86 pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE
87 | (ah->ah_version == AR5K_AR5210 ?
88 AR5K_STA_ID1_NO_PSPOLL : 0);
89 break;
90
91 default:
92 return -EINVAL;
93 }
94
95
96
97
98 low_id = AR5K_LOW_ID(ah->ah_sta_id);
99 high_id = AR5K_HIGH_ID(ah->ah_sta_id);
100 ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0);
101 ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1);
102
103
104
105
106 if (ah->ah_version == AR5K_AR5210)
107 ath5k_hw_reg_write(ah, beacon_reg, AR5K_BCR);
108
109 return 0;
110}
111
112
113
114
115
116
117
118
119
120
121
122void ath5k_hw_update_mib_counters(struct ath5k_hw *ah,
123 struct ieee80211_low_level_stats *stats)
124{
125 ATH5K_TRACE(ah->ah_sc);
126
127
128 stats->dot11ACKFailureCount += ath5k_hw_reg_read(ah, AR5K_ACK_FAIL);
129 stats->dot11RTSFailureCount += ath5k_hw_reg_read(ah, AR5K_RTS_FAIL);
130 stats->dot11RTSSuccessCount += ath5k_hw_reg_read(ah, AR5K_RTS_OK);
131 stats->dot11FCSErrorCount += ath5k_hw_reg_read(ah, AR5K_FCS_FAIL);
132
133
134
135 ath5k_hw_reg_read(ah, AR5K_BEACON_CNT);
136
137
138 if (ah->ah_version == AR5K_AR5212) {
139 ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_TX);
140 ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RX);
141 ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RXCLR);
142 ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_CYCLE);
143 }
144
145
146}
147
148
149
150
151
152
153
154
155
156
157
158
159
160void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, bool high)
161{
162 if (ah->ah_version != AR5K_AR5212)
163 return;
164 else {
165 u32 val = AR5K_STA_ID1_BASE_RATE_11B | AR5K_STA_ID1_ACKCTS_6MB;
166 if (high)
167 AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, val);
168 else
169 AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, val);
170 }
171}
172
173
174
175
176
177
178
179
180
181
182
183unsigned int ath5k_hw_get_ack_timeout(struct ath5k_hw *ah)
184{
185 ATH5K_TRACE(ah->ah_sc);
186
187 return ath5k_hw_clocktoh(AR5K_REG_MS(ath5k_hw_reg_read(ah,
188 AR5K_TIME_OUT), AR5K_TIME_OUT_ACK), ah->ah_turbo);
189}
190
191
192
193
194
195
196
197int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout)
198{
199 ATH5K_TRACE(ah->ah_sc);
200 if (ath5k_hw_clocktoh(AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_ACK),
201 ah->ah_turbo) <= timeout)
202 return -EINVAL;
203
204 AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_ACK,
205 ath5k_hw_htoclock(timeout, ah->ah_turbo));
206
207 return 0;
208}
209
210
211
212
213
214
215unsigned int ath5k_hw_get_cts_timeout(struct ath5k_hw *ah)
216{
217 ATH5K_TRACE(ah->ah_sc);
218 return ath5k_hw_clocktoh(AR5K_REG_MS(ath5k_hw_reg_read(ah,
219 AR5K_TIME_OUT), AR5K_TIME_OUT_CTS), ah->ah_turbo);
220}
221
222
223
224
225
226
227
228int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout)
229{
230 ATH5K_TRACE(ah->ah_sc);
231 if (ath5k_hw_clocktoh(AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_CTS),
232 ah->ah_turbo) <= timeout)
233 return -EINVAL;
234
235 AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_CTS,
236 ath5k_hw_htoclock(timeout, ah->ah_turbo));
237
238 return 0;
239}
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257void ath5k_hw_get_lladdr(struct ath5k_hw *ah, u8 *mac)
258{
259 ATH5K_TRACE(ah->ah_sc);
260 memcpy(mac, ah->ah_sta_id, ETH_ALEN);
261}
262
263
264
265
266
267
268
269
270
271int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac)
272{
273 u32 low_id, high_id;
274 u32 pcu_reg;
275
276 ATH5K_TRACE(ah->ah_sc);
277
278 memcpy(ah->ah_sta_id, mac, ETH_ALEN);
279
280 pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000;
281
282 low_id = AR5K_LOW_ID(mac);
283 high_id = AR5K_HIGH_ID(mac);
284
285 ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0);
286 ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1);
287
288 return 0;
289}
290
291
292
293
294
295
296
297
298
299
300void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id)
301{
302 u32 low_id, high_id;
303 u16 tim_offset = 0;
304
305
306
307
308 if (ah->ah_version == AR5K_AR5212) {
309 ath5k_hw_reg_write(ah, AR5K_LOW_ID(ah->ah_bssid_mask),
310 AR5K_BSS_IDM0);
311 ath5k_hw_reg_write(ah, AR5K_HIGH_ID(ah->ah_bssid_mask),
312 AR5K_BSS_IDM1);
313 }
314
315
316
317
318 low_id = AR5K_LOW_ID(bssid);
319 high_id = AR5K_HIGH_ID(bssid);
320 ath5k_hw_reg_write(ah, low_id, AR5K_BSS_ID0);
321 ath5k_hw_reg_write(ah, high_id | ((assoc_id & 0x3fff) <<
322 AR5K_BSS_ID1_AID_S), AR5K_BSS_ID1);
323
324 if (assoc_id == 0) {
325 ath5k_hw_disable_pspoll(ah);
326 return;
327 }
328
329 AR5K_REG_WRITE_BITS(ah, AR5K_BEACON, AR5K_BEACON_TIM,
330 tim_offset ? tim_offset + 4 : 0);
331
332 ath5k_hw_enable_pspoll(ah, NULL, 0);
333}
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431int ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask)
432{
433 u32 low_id, high_id;
434 ATH5K_TRACE(ah->ah_sc);
435
436
437
438 memcpy(ah->ah_bssid_mask, mask, ETH_ALEN);
439 if (ah->ah_version == AR5K_AR5212) {
440 low_id = AR5K_LOW_ID(mask);
441 high_id = AR5K_HIGH_ID(mask);
442
443 ath5k_hw_reg_write(ah, low_id, AR5K_BSS_IDM0);
444 ath5k_hw_reg_write(ah, high_id, AR5K_BSS_IDM1);
445
446 return 0;
447 }
448
449 return -EIO;
450}
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah)
469{
470 ATH5K_TRACE(ah->ah_sc);
471 AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX);
472}
473
474
475
476
477
478
479
480
481
482
483void ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah)
484{
485 ATH5K_TRACE(ah->ah_sc);
486 AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX);
487}
488
489
490
491
492void ath5k_hw_set_mcast_filter(struct ath5k_hw *ah, u32 filter0, u32 filter1)
493{
494 ATH5K_TRACE(ah->ah_sc);
495
496 ath5k_hw_reg_write(ah, filter0, AR5K_MCAST_FILTER0);
497 ath5k_hw_reg_write(ah, filter1, AR5K_MCAST_FILTER1);
498}
499
500
501
502
503int ath5k_hw_set_mcast_filter_idx(struct ath5k_hw *ah, u32 index)
504{
505
506 ATH5K_TRACE(ah->ah_sc);
507 if (index >= 64)
508 return -EINVAL;
509 else if (index >= 32)
510 AR5K_REG_ENABLE_BITS(ah, AR5K_MCAST_FILTER1,
511 (1 << (index - 32)));
512 else
513 AR5K_REG_ENABLE_BITS(ah, AR5K_MCAST_FILTER0, (1 << index));
514
515 return 0;
516}
517
518
519
520
521int ath5k_hw_clear_mcast_filter_idx(struct ath5k_hw *ah, u32 index)
522{
523
524 ATH5K_TRACE(ah->ah_sc);
525 if (index >= 64)
526 return -EINVAL;
527 else if (index >= 32)
528 AR5K_REG_DISABLE_BITS(ah, AR5K_MCAST_FILTER1,
529 (1 << (index - 32)));
530 else
531 AR5K_REG_DISABLE_BITS(ah, AR5K_MCAST_FILTER0, (1 << index));
532
533 return 0;
534}
535
536
537
538
539
540
541
542
543
544
545
546
547u32 ath5k_hw_get_rx_filter(struct ath5k_hw *ah)
548{
549 u32 data, filter = 0;
550
551 ATH5K_TRACE(ah->ah_sc);
552 filter = ath5k_hw_reg_read(ah, AR5K_RX_FILTER);
553
554
555 if (ah->ah_version == AR5K_AR5212) {
556 data = ath5k_hw_reg_read(ah, AR5K_PHY_ERR_FIL);
557
558 if (data & AR5K_PHY_ERR_FIL_RADAR)
559 filter |= AR5K_RX_FILTER_RADARERR;
560 if (data & (AR5K_PHY_ERR_FIL_OFDM | AR5K_PHY_ERR_FIL_CCK))
561 filter |= AR5K_RX_FILTER_PHYERR;
562 }
563
564 return filter;
565}
566
567
568
569
570
571
572
573
574
575
576
577void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter)
578{
579 u32 data = 0;
580
581 ATH5K_TRACE(ah->ah_sc);
582
583
584 if (ah->ah_version == AR5K_AR5212) {
585 if (filter & AR5K_RX_FILTER_RADARERR)
586 data |= AR5K_PHY_ERR_FIL_RADAR;
587 if (filter & AR5K_RX_FILTER_PHYERR)
588 data |= AR5K_PHY_ERR_FIL_OFDM | AR5K_PHY_ERR_FIL_CCK;
589 }
590
591
592
593
594 if (ah->ah_version == AR5K_AR5210 &&
595 (filter & AR5K_RX_FILTER_RADARERR)) {
596 filter &= ~AR5K_RX_FILTER_RADARERR;
597 filter |= AR5K_RX_FILTER_PROM;
598 }
599
600
601 if (data)
602 AR5K_REG_ENABLE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_ZLFDMA);
603 else
604 AR5K_REG_DISABLE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_ZLFDMA);
605
606
607 ath5k_hw_reg_write(ah, filter & 0xff, AR5K_RX_FILTER);
608
609
610 if (ah->ah_version == AR5K_AR5212)
611 ath5k_hw_reg_write(ah, data, AR5K_PHY_ERR_FIL);
612
613}
614
615
616
617
618
619
620
621
622
623
624
625
626
627u32 ath5k_hw_get_tsf32(struct ath5k_hw *ah)
628{
629 ATH5K_TRACE(ah->ah_sc);
630 return ath5k_hw_reg_read(ah, AR5K_TSF_L32);
631}
632
633
634
635
636
637
638
639
640u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah)
641{
642 u64 tsf = ath5k_hw_reg_read(ah, AR5K_TSF_U32);
643 ATH5K_TRACE(ah->ah_sc);
644
645 return ath5k_hw_reg_read(ah, AR5K_TSF_L32) | (tsf << 32);
646}
647
648
649
650
651
652
653
654
655
656void ath5k_hw_set_tsf64(struct ath5k_hw *ah, u64 tsf64)
657{
658 ATH5K_TRACE(ah->ah_sc);
659
660 ath5k_hw_reg_write(ah, tsf64 & 0xffffffff, AR5K_TSF_L32);
661 ath5k_hw_reg_write(ah, (tsf64 >> 32) & 0xffffffff, AR5K_TSF_U32);
662}
663
664
665
666
667
668
669
670
671void ath5k_hw_reset_tsf(struct ath5k_hw *ah)
672{
673 u32 val;
674
675 ATH5K_TRACE(ah->ah_sc);
676
677 val = ath5k_hw_reg_read(ah, AR5K_BEACON) | AR5K_BEACON_RESET_TSF;
678
679
680
681
682
683
684
685 ath5k_hw_reg_write(ah, val, AR5K_BEACON);
686 ath5k_hw_reg_write(ah, val, AR5K_BEACON);
687}
688
689
690
691
692void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval)
693{
694 u32 timer1, timer2, timer3;
695
696 ATH5K_TRACE(ah->ah_sc);
697
698
699
700 switch (ah->ah_op_mode) {
701 case NL80211_IFTYPE_MONITOR:
702 case NL80211_IFTYPE_STATION:
703
704
705
706
707 if (ah->ah_version == AR5K_AR5210) {
708 timer1 = 0xffffffff;
709 timer2 = 0xffffffff;
710 } else {
711 timer1 = 0x0000ffff;
712 timer2 = 0x0007ffff;
713 }
714
715 AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, AR5K_STA_ID1_PCF);
716 break;
717 case NL80211_IFTYPE_ADHOC:
718 AR5K_REG_ENABLE_BITS(ah, AR5K_TXCFG, AR5K_TXCFG_ADHOC_BCN_ATIM);
719 default:
720
721
722
723 timer1 = (next_beacon - AR5K_TUNE_DMA_BEACON_RESP) << 3;
724 timer2 = (next_beacon - AR5K_TUNE_SW_BEACON_RESP) << 3;
725 break;
726 }
727
728
729
730
731 timer3 = next_beacon + (ah->ah_atim_window ? ah->ah_atim_window : 1);
732
733
734
735
736
737 if (ah->ah_op_mode == NL80211_IFTYPE_AP ||
738 ah->ah_op_mode == NL80211_IFTYPE_MESH_POINT)
739 ath5k_hw_reg_write(ah, 0, AR5K_TIMER0);
740
741 ath5k_hw_reg_write(ah, next_beacon, AR5K_TIMER0);
742 ath5k_hw_reg_write(ah, timer1, AR5K_TIMER1);
743 ath5k_hw_reg_write(ah, timer2, AR5K_TIMER2);
744 ath5k_hw_reg_write(ah, timer3, AR5K_TIMER3);
745
746
747 if (interval & AR5K_BEACON_RESET_TSF)
748 ath5k_hw_reset_tsf(ah);
749
750 ath5k_hw_reg_write(ah, interval & (AR5K_BEACON_PERIOD |
751 AR5K_BEACON_ENABLE),
752 AR5K_BEACON);
753
754
755
756
757
758
759 if (ah->ah_version == AR5K_AR5210)
760 ath5k_hw_reg_write(ah, AR5K_ISR_BMISS, AR5K_ISR);
761 else
762 ath5k_hw_reg_write(ah, AR5K_ISR_BMISS, AR5K_PISR);
763
764
765
766
767 AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, AR5K_STA_ID1_PWR_SV);
768
769}
770
771#if 0
772
773
774
775int ath5k_hw_set_beacon_timers(struct ath5k_hw *ah,
776 const struct ath5k_beacon_state *state)
777{
778 u32 cfp_period, next_cfp, dtim, interval, next_beacon;
779
780
781
782
783
784
785
786
787
788 u32 dtim_count = 0;
789 u32 cfp_count = 0;
790 u32 tsf = 0;
791
792 ATH5K_TRACE(ah->ah_sc);
793
794 if (state->bs_interval < 1)
795 return -EINVAL;
796
797 interval = state->bs_interval;
798 dtim = state->bs_dtim_period;
799
800
801
802
803 if (state->bs_cfp_period > 0) {
804
805
806
807
808 cfp_period = state->bs_cfp_period * state->bs_dtim_period *
809 state->bs_interval;
810 next_cfp = (cfp_count * state->bs_dtim_period + dtim_count) *
811 state->bs_interval;
812
813 AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1,
814 AR5K_STA_ID1_DEFAULT_ANTENNA |
815 AR5K_STA_ID1_PCF);
816 ath5k_hw_reg_write(ah, cfp_period, AR5K_CFP_PERIOD);
817 ath5k_hw_reg_write(ah, state->bs_cfp_max_duration,
818 AR5K_CFP_DUR);
819 ath5k_hw_reg_write(ah, (tsf + (next_cfp == 0 ? cfp_period :
820 next_cfp)) << 3, AR5K_TIMER2);
821 } else {
822
823 AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1,
824 AR5K_STA_ID1_DEFAULT_ANTENNA |
825 AR5K_STA_ID1_PCF);
826 }
827
828
829
830
831 ath5k_hw_reg_write(ah, state->bs_next_beacon, AR5K_TIMER0);
832
833
834
835
836 ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, AR5K_BEACON) &
837 ~(AR5K_BEACON_PERIOD | AR5K_BEACON_TIM)) |
838 AR5K_REG_SM(state->bs_tim_offset ? state->bs_tim_offset + 4 : 0,
839 AR5K_BEACON_TIM) | AR5K_REG_SM(state->bs_interval,
840 AR5K_BEACON_PERIOD), AR5K_BEACON);
841
842
843
844
845
846
847
848
849 AR5K_REG_WRITE_BITS(ah, AR5K_RSSI_THR, AR5K_RSSI_THR_BMISS,
850 state->bs_bmiss_threshold);
851
852
853
854
855
856
857 AR5K_REG_WRITE_BITS(ah, AR5K_SLEEP_CTL, AR5K_SLEEP_CTL_SLDUR,
858 (state->bs_sleep_duration - 3) << 3);
859
860
861
862
863 if (ah->ah_version == AR5K_AR5212) {
864 if (state->bs_sleep_duration > state->bs_interval &&
865 roundup(state->bs_sleep_duration, interval) ==
866 state->bs_sleep_duration)
867 interval = state->bs_sleep_duration;
868
869 if (state->bs_sleep_duration > dtim && (dtim == 0 ||
870 roundup(state->bs_sleep_duration, dtim) ==
871 state->bs_sleep_duration))
872 dtim = state->bs_sleep_duration;
873
874 if (interval > dtim)
875 return -EINVAL;
876
877 next_beacon = interval == dtim ? state->bs_next_dtim :
878 state->bs_next_beacon;
879
880 ath5k_hw_reg_write(ah,
881 AR5K_REG_SM((state->bs_next_dtim - 3) << 3,
882 AR5K_SLEEP0_NEXT_DTIM) |
883 AR5K_REG_SM(10, AR5K_SLEEP0_CABTO) |
884 AR5K_SLEEP0_ENH_SLEEP_EN |
885 AR5K_SLEEP0_ASSUME_DTIM, AR5K_SLEEP0);
886
887 ath5k_hw_reg_write(ah, AR5K_REG_SM((next_beacon - 3) << 3,
888 AR5K_SLEEP1_NEXT_TIM) |
889 AR5K_REG_SM(10, AR5K_SLEEP1_BEACON_TO), AR5K_SLEEP1);
890
891 ath5k_hw_reg_write(ah,
892 AR5K_REG_SM(interval, AR5K_SLEEP2_TIM_PER) |
893 AR5K_REG_SM(dtim, AR5K_SLEEP2_DTIM_PER), AR5K_SLEEP2);
894 }
895
896 return 0;
897}
898
899
900
901
902void ath5k_hw_reset_beacon(struct ath5k_hw *ah)
903{
904 ATH5K_TRACE(ah->ah_sc);
905
906
907
908 ath5k_hw_reg_write(ah, 0, AR5K_TIMER0);
909
910
911
912
913 AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1,
914 AR5K_STA_ID1_DEFAULT_ANTENNA | AR5K_STA_ID1_PCF);
915 ath5k_hw_reg_write(ah, AR5K_BEACON_PERIOD, AR5K_BEACON);
916}
917
918
919
920
921int ath5k_hw_beaconq_finish(struct ath5k_hw *ah, unsigned long phys_addr)
922{
923 unsigned int i;
924 int ret;
925
926 ATH5K_TRACE(ah->ah_sc);
927
928
929 if (ah->ah_version == AR5K_AR5210) {
930
931
932
933
934 for (i = AR5K_TUNE_BEACON_INTERVAL / 2; i > 0; i--) {
935 if (!(ath5k_hw_reg_read(ah, AR5K_BSR) & AR5K_BSR_TXQ1F)
936 ||
937 !(ath5k_hw_reg_read(ah, AR5K_CR) & AR5K_BSR_TXQ1F))
938 break;
939 udelay(10);
940 }
941
942
943 if (i <= 0) {
944
945
946
947 ath5k_hw_reg_write(ah, phys_addr, AR5K_NOQCU_TXDP1);
948 ath5k_hw_reg_write(ah, AR5K_BCR_TQ1V | AR5K_BCR_BDMAE,
949 AR5K_BCR);
950
951 return -EIO;
952 }
953 ret = 0;
954 } else {
955
956 ret = ath5k_hw_register_timeout(ah,
957 AR5K_QUEUE_STATUS(AR5K_TX_QUEUE_ID_BEACON),
958 AR5K_QCU_STS_FRMPENDCNT, 0, false);
959
960 if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, AR5K_TX_QUEUE_ID_BEACON))
961 return -EIO;
962 }
963
964 return ret;
965}
966#endif
967
968
969
970
971
972
973
974
975
976int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry)
977{
978 unsigned int i, type;
979 u16 micentry = entry + AR5K_KEYTABLE_MIC_OFFSET;
980
981 ATH5K_TRACE(ah->ah_sc);
982 AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE);
983
984 type = ath5k_hw_reg_read(ah, AR5K_KEYTABLE_TYPE(entry));
985
986 for (i = 0; i < AR5K_KEYCACHE_SIZE; i++)
987 ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_OFF(entry, i));
988
989
990
991 if (type == AR5K_KEYTABLE_TYPE_TKIP) {
992 AR5K_ASSERT_ENTRY(micentry, AR5K_KEYTABLE_SIZE);
993 for (i = 0; i < AR5K_KEYCACHE_SIZE / 2 ; i++)
994 ath5k_hw_reg_write(ah, 0,
995 AR5K_KEYTABLE_OFF(micentry, i));
996 }
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007 if (ah->ah_version >= AR5K_AR5211) {
1008 ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL,
1009 AR5K_KEYTABLE_TYPE(entry));
1010
1011 if (type == AR5K_KEYTABLE_TYPE_TKIP) {
1012 ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL,
1013 AR5K_KEYTABLE_TYPE(micentry));
1014 }
1015 }
1016
1017 return 0;
1018}
1019
1020
1021
1022
1023int ath5k_hw_is_key_valid(struct ath5k_hw *ah, u16 entry)
1024{
1025 ATH5K_TRACE(ah->ah_sc);
1026 AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE);
1027
1028
1029 return ath5k_hw_reg_read(ah, AR5K_KEYTABLE_MAC1(entry)) &
1030 AR5K_KEYTABLE_VALID;
1031}
1032
1033static
1034int ath5k_keycache_type(const struct ieee80211_key_conf *key)
1035{
1036 switch (key->alg) {
1037 case ALG_TKIP:
1038 return AR5K_KEYTABLE_TYPE_TKIP;
1039 case ALG_CCMP:
1040 return AR5K_KEYTABLE_TYPE_CCM;
1041 case ALG_WEP:
1042 if (key->keylen == WLAN_KEY_LEN_WEP40)
1043 return AR5K_KEYTABLE_TYPE_40;
1044 else if (key->keylen == WLAN_KEY_LEN_WEP104)
1045 return AR5K_KEYTABLE_TYPE_104;
1046 return -EINVAL;
1047 default:
1048 return -EINVAL;
1049 }
1050 return -EINVAL;
1051}
1052
1053
1054
1055
1056int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry,
1057 const struct ieee80211_key_conf *key, const u8 *mac)
1058{
1059 unsigned int i;
1060 int keylen;
1061 __le32 key_v[5] = {};
1062 __le32 key0 = 0, key1 = 0;
1063 __le32 *rxmic, *txmic;
1064 int keytype;
1065 u16 micentry = entry + AR5K_KEYTABLE_MIC_OFFSET;
1066 bool is_tkip;
1067 const u8 *key_ptr;
1068
1069 ATH5K_TRACE(ah->ah_sc);
1070
1071 is_tkip = (key->alg == ALG_TKIP);
1072
1073
1074
1075
1076
1077 keylen = (is_tkip) ? (128 / 8) : key->keylen;
1078
1079 if (entry > AR5K_KEYTABLE_SIZE ||
1080 (is_tkip && micentry > AR5K_KEYTABLE_SIZE))
1081 return -EOPNOTSUPP;
1082
1083 if (unlikely(keylen > 16))
1084 return -EOPNOTSUPP;
1085
1086 keytype = ath5k_keycache_type(key);
1087 if (keytype < 0)
1088 return keytype;
1089
1090
1091
1092
1093
1094 key_ptr = key->key;
1095 for (i = 0; keylen >= 6; keylen -= 6) {
1096 memcpy(&key_v[i], key_ptr, 6);
1097 i += 2;
1098 key_ptr += 6;
1099 }
1100 if (keylen)
1101 memcpy(&key_v[i], key_ptr, keylen);
1102
1103
1104 if (is_tkip) {
1105 key0 = key_v[0] = ~key_v[0];
1106 key1 = key_v[1] = ~key_v[1];
1107 }
1108
1109 for (i = 0; i < ARRAY_SIZE(key_v); i++)
1110 ath5k_hw_reg_write(ah, le32_to_cpu(key_v[i]),
1111 AR5K_KEYTABLE_OFF(entry, i));
1112
1113 ath5k_hw_reg_write(ah, keytype, AR5K_KEYTABLE_TYPE(entry));
1114
1115 if (is_tkip) {
1116
1117 rxmic = (__le32 *) &key->key[16];
1118 txmic = (__le32 *) &key->key[24];
1119
1120 if (ah->ah_combined_mic) {
1121 key_v[0] = rxmic[0];
1122 key_v[1] = cpu_to_le32(le32_to_cpu(txmic[0]) >> 16);
1123 key_v[2] = rxmic[1];
1124 key_v[3] = cpu_to_le32(le32_to_cpu(txmic[0]) & 0xffff);
1125 key_v[4] = txmic[1];
1126 } else {
1127 key_v[0] = rxmic[0];
1128 key_v[1] = 0;
1129 key_v[2] = rxmic[1];
1130 key_v[3] = 0;
1131 key_v[4] = 0;
1132 }
1133 for (i = 0; i < ARRAY_SIZE(key_v); i++)
1134 ath5k_hw_reg_write(ah, le32_to_cpu(key_v[i]),
1135 AR5K_KEYTABLE_OFF(micentry, i));
1136
1137 ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL,
1138 AR5K_KEYTABLE_TYPE(micentry));
1139 ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_MAC0(micentry));
1140 ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_MAC1(micentry));
1141
1142
1143 ath5k_hw_reg_write(ah, le32_to_cpu(~key0),
1144 AR5K_KEYTABLE_OFF(entry, 0));
1145 ath5k_hw_reg_write(ah, le32_to_cpu(~key1),
1146 AR5K_KEYTABLE_OFF(entry, 1));
1147 }
1148
1149 return ath5k_hw_set_key_lladdr(ah, entry, mac);
1150}
1151
1152int ath5k_hw_set_key_lladdr(struct ath5k_hw *ah, u16 entry, const u8 *mac)
1153{
1154 u32 low_id, high_id;
1155
1156 ATH5K_TRACE(ah->ah_sc);
1157
1158 AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE);
1159
1160
1161
1162 if (!mac) {
1163 low_id = 0xffffffff;
1164 high_id = 0xffff | AR5K_KEYTABLE_VALID;
1165 } else {
1166 low_id = AR5K_LOW_ID(mac);
1167 high_id = AR5K_HIGH_ID(mac) | AR5K_KEYTABLE_VALID;
1168 }
1169
1170 ath5k_hw_reg_write(ah, low_id, AR5K_KEYTABLE_MAC0(entry));
1171 ath5k_hw_reg_write(ah, high_id, AR5K_KEYTABLE_MAC1(entry));
1172
1173 return 0;
1174}
1175
1176