xref: /freebsd/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_beacon.c (revision 8ddb146abcdf061be9f2c0db7e391697dafad85c)
1 /*
2  * Copyright (c) 2013 Qualcomm Atheros, Inc.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
9  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10  * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
11  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
13  * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14  * PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 #include "opt_ah.h"
18 
19 #include "ah.h"
20 #include "ah_internal.h"
21 
22 #include "ar9300/ar9300.h"
23 #include "ar9300/ar9300reg.h"
24 
25 #define TU_TO_USEC(_tu) ((_tu) << 10)
26 #define	ONE_EIGHTH_TU_TO_USEC(_tu8) ((_tu8) << 7)
27 
28 extern u_int32_t ar9300_num_tx_pending(struct ath_hal *ah, u_int q);
29 
30 /*
31  * Initializes all of the hardware registers used to
32  * send beacons.  Note that for station operation the
33  * driver calls ar9300_set_sta_beacon_timers instead.
34  */
35 void
36 ar9300_beacon_init(struct ath_hal *ah,
37     u_int32_t next_beacon, u_int32_t beacon_period,
38     u_int32_t beacon_period_fraction, HAL_OPMODE opmode)
39 {
40     u_int32_t               beacon_period_usec;
41 
42     HALASSERT(opmode == HAL_M_IBSS || opmode == HAL_M_HOSTAP);
43     if (opmode == HAL_M_IBSS) {
44         OS_REG_SET_BIT(ah, AR_TXCFG, AR_TXCFG_ADHOC_BEACON_ATIM_TX_POLICY);
45     }
46     OS_REG_WRITE(ah, AR_NEXT_TBTT_TIMER, ONE_EIGHTH_TU_TO_USEC(next_beacon));
47     OS_REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT,
48         (ONE_EIGHTH_TU_TO_USEC(next_beacon) -
49         ah->ah_config.ah_dma_beacon_response_time));
50     OS_REG_WRITE(ah, AR_NEXT_SWBA,
51         (ONE_EIGHTH_TU_TO_USEC(next_beacon) -
52         ah->ah_config.ah_sw_beacon_response_time));
53 
54     beacon_period_usec =
55         ONE_EIGHTH_TU_TO_USEC(beacon_period & HAL_BEACON_PERIOD_TU8);
56 
57     /* Add the fraction adjustment lost due to unit conversions. */
58     beacon_period_usec += beacon_period_fraction;
59 
60     HALDEBUG(ah, HAL_DEBUG_BEACON,
61         "%s: next_beacon=0x%08x, beacon_period=%d, opmode=%d, beacon_period_usec=%d\n",
62         __func__, next_beacon, beacon_period, opmode, beacon_period_usec);
63 
64     OS_REG_WRITE(ah, AR_BEACON_PERIOD, beacon_period_usec);
65     OS_REG_WRITE(ah, AR_DMA_BEACON_PERIOD, beacon_period_usec);
66     OS_REG_WRITE(ah, AR_SWBA_PERIOD, beacon_period_usec);
67 
68     /* reset TSF if required */
69     if (beacon_period & HAL_BEACON_RESET_TSF) {
70         ar9300_reset_tsf(ah);
71     }
72 
73     /* enable timers */
74     OS_REG_SET_BIT(ah, AR_TIMER_MODE,
75         AR_TBTT_TIMER_EN | AR_DBA_TIMER_EN | AR_SWBA_TIMER_EN);
76 }
77 
78 /*
79  * Set all the beacon related bits on the h/w for stations
80  * i.e. initializes the corresponding h/w timers;
81  */
82 void
83 ar9300_set_sta_beacon_timers(struct ath_hal *ah, const HAL_BEACON_STATE *bs)
84 {
85     u_int32_t next_tbtt, beaconintval, dtimperiod, beacontimeout;
86     HAL_CAPABILITIES *p_cap = &AH_PRIVATE(ah)->ah_caps;
87 
88     HALASSERT(bs->bs_intval != 0);
89 
90     /* no cfp setting since h/w automatically takes care */
91     OS_REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(bs->bs_nexttbtt));
92 
93     /*
94      * Start the beacon timers by setting the BEACON register
95      * to the beacon interval; no need to write tim offset since
96      * h/w parses IEs.
97      */
98     OS_REG_WRITE(ah, AR_BEACON_PERIOD,
99                  TU_TO_USEC(bs->bs_intval & HAL_BEACON_PERIOD));
100     OS_REG_WRITE(ah, AR_DMA_BEACON_PERIOD,
101                  TU_TO_USEC(bs->bs_intval & HAL_BEACON_PERIOD));
102     /*
103      * Configure the BMISS interrupt.  Note that we
104      * assume the caller blocks interrupts while enabling
105      * the threshold.
106      */
107     HALASSERT(bs->bs_bmissthreshold <=
108         (AR_RSSI_THR_BM_THR >> AR_RSSI_THR_BM_THR_S));
109     OS_REG_RMW_FIELD(ah, AR_RSSI_THR,
110         AR_RSSI_THR_BM_THR, bs->bs_bmissthreshold);
111 
112     /*
113      * Program the sleep registers to correlate with the beacon setup.
114      */
115 
116     /*
117      * Current implementation assumes sw processing of beacons -
118      * assuming an interrupt is generated every beacon which
119      * causes the hardware to become awake until the sw tells
120      * it to go to sleep again; beacon timeout is to allow for
121      * beacon jitter; cab timeout is max time to wait for cab
122      * after seeing the last DTIM or MORE CAB bit
123      */
124 #define CAB_TIMEOUT_VAL         10 /* in TU */
125 #define BEACON_TIMEOUT_VAL      10 /* in TU */
126 #define MIN_BEACON_TIMEOUT_VAL   1 /* in 1/8 TU */
127 #define SLEEP_SLOP               3 /* in TU */
128 
129     /*
130      * For max powersave mode we may want to sleep for longer than a
131      * beacon period and not want to receive all beacons; modify the
132      * timers accordingly; make sure to align the next TIM to the
133      * next DTIM if we decide to wake for DTIMs only
134      */
135     beaconintval = bs->bs_intval & HAL_BEACON_PERIOD;
136     HALASSERT(beaconintval != 0);
137     if (bs->bs_sleepduration > beaconintval) {
138         HALASSERT(roundup(bs->bs_sleepduration, beaconintval) ==
139                 bs->bs_sleepduration);
140         beaconintval = bs->bs_sleepduration;
141     }
142     dtimperiod = bs->bs_dtimperiod;
143     if (bs->bs_sleepduration > dtimperiod) {
144         HALASSERT(dtimperiod == 0 ||
145             roundup(bs->bs_sleepduration, dtimperiod) ==
146                 bs->bs_sleepduration);
147         dtimperiod = bs->bs_sleepduration;
148     }
149     HALASSERT(beaconintval <= dtimperiod);
150     if (beaconintval == dtimperiod) {
151         next_tbtt = bs->bs_nextdtim;
152     } else {
153         next_tbtt = bs->bs_nexttbtt;
154     }
155 
156     HALDEBUG(ah, HAL_DEBUG_BEACON,
157         "%s: next DTIM %d\n", __func__, bs->bs_nextdtim);
158     HALDEBUG(ah, HAL_DEBUG_BEACON,
159         "%s: next beacon %d\n", __func__, next_tbtt);
160     HALDEBUG(ah, HAL_DEBUG_BEACON,
161         "%s: beacon period %d\n", __func__, beaconintval);
162     HALDEBUG(ah, HAL_DEBUG_BEACON,
163         "%s: DTIM period %d\n", __func__, dtimperiod);
164 
165     OS_REG_WRITE(ah, AR_NEXT_DTIM, TU_TO_USEC(bs->bs_nextdtim - SLEEP_SLOP));
166     OS_REG_WRITE(ah, AR_NEXT_TIM, TU_TO_USEC(next_tbtt - SLEEP_SLOP));
167 
168     /* cab timeout is now in 1/8 TU */
169     OS_REG_WRITE(ah, AR_SLEEP1,
170         SM((CAB_TIMEOUT_VAL << 3), AR_SLEEP1_CAB_TIMEOUT)
171         | AR_SLEEP1_ASSUME_DTIM);
172 
173     /* beacon timeout is now in 1/8 TU */
174     if (p_cap->halAutoSleepSupport) {
175         beacontimeout = (BEACON_TIMEOUT_VAL << 3);
176     } else {
177         /*
178          * Use a very small value to make sure the timeout occurs before
179          * the TBTT.  In this case the chip will not go back to sleep
180          * automatically, instead it will wait for the SW to explicitly
181          * set it to that mode.
182          */
183         beacontimeout = MIN_BEACON_TIMEOUT_VAL;
184     }
185 
186     OS_REG_WRITE(ah, AR_SLEEP2,
187         SM(beacontimeout, AR_SLEEP2_BEACON_TIMEOUT));
188 
189     OS_REG_WRITE(ah, AR_TIM_PERIOD, TU_TO_USEC(beaconintval));
190     OS_REG_WRITE(ah, AR_DTIM_PERIOD, TU_TO_USEC(dtimperiod));
191 
192     /* clear HOST AP related timers first */
193     OS_REG_CLR_BIT(ah, AR_TIMER_MODE, (AR_DBA_TIMER_EN | AR_SWBA_TIMER_EN));
194 
195     OS_REG_SET_BIT(ah, AR_TIMER_MODE, AR_TBTT_TIMER_EN | AR_TIM_TIMER_EN
196                     | AR_DTIM_TIMER_EN);
197 
198     /* TSF out of range threshold */
199     OS_REG_WRITE(ah, AR_TSFOOR_THRESHOLD, bs->bs_tsfoor_threshold);
200 
201 #undef CAB_TIMEOUT_VAL
202 #undef BEACON_TIMEOUT_VAL
203 #undef SLEEP_SLOP
204 }
205