ar9300_beacon.c revision 250007
1193326Sed/*
2193326Sed * Copyright (c) 2013 Qualcomm Atheros, Inc.
3193326Sed *
4193326Sed * Permission to use, copy, modify, and/or distribute this software for any
5193326Sed * purpose with or without fee is hereby granted, provided that the above
6193326Sed * copyright notice and this permission notice appear in all copies.
7193326Sed *
8193326Sed * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
9243830Sdim * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10243830Sdim * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
11243830Sdim * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12243830Sdim * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
13193326Sed * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14193326Sed * PERFORMANCE OF THIS SOFTWARE.
15193326Sed */
16193326Sed
17193326Sed#include "opt_ah.h"
18249423Sdim
19249423Sdim#ifdef AH_SUPPORT_AR9300
20249423Sdim
21249423Sdim#include "ah.h"
22276479Sdim#include "ah_internal.h"
23249423Sdim
24249423Sdim#include "ar9300/ar9300.h"
25249423Sdim#include "ar9300/ar9300reg.h"
26249423Sdim
27249423Sdim#define TU_TO_USEC(_tu) ((_tu) << 10)
28221345Sdim
29193326Sedextern u_int32_t ar9300_num_tx_pending(struct ath_hal *ah, u_int q);
30193326Sed
31296417Sdim/*
32198893Srdivacky * Initializes all of the hardware registers used to
33206084Srdivacky * send beacons.  Note that for station operation the
34280031Sdim * driver calls ar9300_set_sta_beacon_timers instead.
35221345Sdim */
36193326Sedvoid
37193326Sedar9300_beacon_init(struct ath_hal *ah,
38221345Sdim    u_int32_t next_beacon, u_int32_t beacon_period, HAL_OPMODE opmode)
39203955Srdivacky{
40234353Sdim    struct ath_hal_private  *ap  = AH_PRIVATE(ah);
41193326Sed    u_int32_t               beacon_period_usec;
42276479Sdim
43193326Sed    HALASSERT(opmode == HAL_M_IBSS || opmode == HAL_M_HOSTAP);
44193326Sed    if (opmode == HAL_M_IBSS) {
45193326Sed        OS_REG_SET_BIT(ah, AR_TXCFG, AR_TXCFG_ADHOC_BEACON_ATIM_TX_POLICY);
46193326Sed    }
47193326Sed    OS_REG_WRITE(ah, AR_NEXT_TBTT_TIMER, ONE_EIGHTH_TU_TO_USEC(next_beacon));
48193326Sed    OS_REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT,
49193326Sed        (ONE_EIGHTH_TU_TO_USEC(next_beacon) -
50193326Sed        ap->ah_config.ath_hal_dma_beacon_response_time));
51261991Sdim    OS_REG_WRITE(ah, AR_NEXT_SWBA,
52193326Sed        (ONE_EIGHTH_TU_TO_USEC(next_beacon) -
53199482Srdivacky        ap->ah_config.ath_hal_sw_beacon_response_time));
54201361Srdivacky
55226633Sdim    beacon_period_usec =
56193326Sed        ONE_EIGHTH_TU_TO_USEC(beacon_period & HAL_BEACON_PERIOD_TU8);
57218893Sdim    OS_REG_WRITE(ah, AR_BEACON_PERIOD, beacon_period_usec);
58193326Sed    OS_REG_WRITE(ah, AR_DMA_BEACON_PERIOD, beacon_period_usec);
59261991Sdim    OS_REG_WRITE(ah, AR_SWBA_PERIOD, beacon_period_usec);
60193326Sed
61193326Sed    /* reset TSF if required */
62212904Sdim    if (beacon_period & HAL_BEACON_RESET_TSF) {
63261991Sdim        ar9300_reset_tsf(ah);
64193326Sed    }
65218893Sdim
66198092Srdivacky    /* enable timers */
67193326Sed    OS_REG_SET_BIT(ah, AR_TIMER_MODE,
68249423Sdim        AR_TBTT_TIMER_EN | AR_DBA_TIMER_EN | AR_SWBA_TIMER_EN);
69198092Srdivacky}
70200583Srdivacky
71276479Sdim/*
72198092Srdivacky * Set all the beacon related bits on the h/w for stations
73194179Sed * i.e. initializes the corresponding h/w timers;
74296417Sdim */
75198092Srdivackyvoid
76239462Sdimar9300_set_sta_beacon_timers(struct ath_hal *ah, const HAL_BEACON_STATE *bs)
77239462Sdim{
78239462Sdim    u_int32_t next_tbtt, beaconintval, dtimperiod, beacontimeout;
79239462Sdim    HAL_CAPABILITIES *p_cap = &AH_PRIVATE(ah)->ah_caps;
80280031Sdim
81280031Sdim    HALASSERT(bs->bs_intval != 0);
82280031Sdim
83280031Sdim    /* no cfp setting since h/w automatically takes care */
84280031Sdim    OS_REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(bs->bs_nexttbtt));
85280031Sdim
86280031Sdim    /*
87280031Sdim     * Start the beacon timers by setting the BEACON register
88280031Sdim     * to the beacon interval; no need to write tim offset since
89243830Sdim     * h/w parses IEs.
90243830Sdim     */
91234353Sdim    OS_REG_WRITE(ah, AR_BEACON_PERIOD,
92210299Sed                 TU_TO_USEC(bs->bs_intval & HAL_BEACON_PERIOD));
93210299Sed    OS_REG_WRITE(ah, AR_DMA_BEACON_PERIOD,
94249423Sdim                 TU_TO_USEC(bs->bs_intval & HAL_BEACON_PERIOD));
95218893Sdim    /*
96218893Sdim     * Configure the BMISS interrupt.  Note that we
97218893Sdim     * assume the caller blocks interrupts while enabling
98276479Sdim     * the threshold.
99218893Sdim     */
100218893Sdim    HALASSERT(bs->bs_bmissthreshold <=
101218893Sdim        (AR_RSSI_THR_BM_THR >> AR_RSSI_THR_BM_THR_S));
102218893Sdim    OS_REG_RMW_FIELD(ah, AR_RSSI_THR,
103218893Sdim        AR_RSSI_THR_BM_THR, bs->bs_bmissthreshold);
104218893Sdim
105218893Sdim    /*
106218893Sdim     * Program the sleep registers to correlate with the beacon setup.
107218893Sdim     */
108218893Sdim
109218893Sdim    /*
110218893Sdim     * Current implementation assumes sw processing of beacons -
111221345Sdim     * assuming an interrupt is generated every beacon which
112221345Sdim     * causes the hardware to become awake until the sw tells
113218893Sdim     * it to go to sleep again; beacon timeout is to allow for
114218893Sdim     * beacon jitter; cab timeout is max time to wait for cab
115218893Sdim     * after seeing the last DTIM or MORE CAB bit
116218893Sdim     */
117218893Sdim#define CAB_TIMEOUT_VAL         10 /* in TU */
118218893Sdim#define BEACON_TIMEOUT_VAL      10 /* in TU */
119218893Sdim#define MIN_BEACON_TIMEOUT_VAL   1 /* in 1/8 TU */
120218893Sdim#define SLEEP_SLOP               3 /* in TU */
121210299Sed
122218893Sdim    /*
123218893Sdim     * For max powersave mode we may want to sleep for longer than a
124218893Sdim     * beacon period and not want to receive all beacons; modify the
125218893Sdim     * timers accordingly; make sure to align the next TIM to the
126218893Sdim     * next DTIM if we decide to wake for DTIMs only
127210299Sed     */
128218893Sdim    beaconintval = bs->bs_intval & HAL_BEACON_PERIOD;
129218893Sdim    HALASSERT(beaconintval != 0);
130218893Sdim    if (bs->bs_sleepduration > beaconintval) {
131219077Sdim        HALASSERT(roundup(bs->bs_sleepduration, beaconintval) ==
132226633Sdim                bs->bs_sleepduration);
133218893Sdim        beaconintval = bs->bs_sleepduration;
134296417Sdim    }
135193326Sed    dtimperiod = bs->bs_dtimperiod;
136218893Sdim    if (bs->bs_sleepduration > dtimperiod) {
137218893Sdim        HALASSERT(dtimperiod == 0 ||
138224145Sdim            roundup(bs->bs_sleepduration, dtimperiod) ==
139224145Sdim                bs->bs_sleepduration);
140224145Sdim        dtimperiod = bs->bs_sleepduration;
141224145Sdim    }
142218893Sdim    HALASSERT(beaconintval <= dtimperiod);
143218893Sdim    if (beaconintval == dtimperiod) {
144193326Sed        next_tbtt = bs->bs_nextdtim;
145193326Sed    } else {
146193326Sed        next_tbtt = bs->bs_nexttbtt;
147218893Sdim    }
148218893Sdim
149193326Sed    HALDEBUG(ah, HAL_DEBUG_BEACON,
150193326Sed        "%s: next DTIM %d\n", __func__, bs->bs_nextdtim);
151243830Sdim    HALDEBUG(ah, HAL_DEBUG_BEACON,
152243830Sdim        "%s: next beacon %d\n", __func__, next_tbtt);
153243830Sdim    HALDEBUG(ah, HAL_DEBUG_BEACON,
154218893Sdim        "%s: beacon period %d\n", __func__, beaconintval);
155218893Sdim    HALDEBUG(ah, HAL_DEBUG_BEACON,
156218893Sdim        "%s: DTIM period %d\n", __func__, dtimperiod);
157218893Sdim
158193326Sed    OS_REG_WRITE(ah, AR_NEXT_DTIM, TU_TO_USEC(bs->bs_nextdtim - SLEEP_SLOP));
159243830Sdim    OS_REG_WRITE(ah, AR_NEXT_TIM, TU_TO_USEC(next_tbtt - SLEEP_SLOP));
160280031Sdim
161234353Sdim    /* cab timeout is now in 1/8 TU */
162234353Sdim    OS_REG_WRITE(ah, AR_SLEEP1,
163243830Sdim        SM((CAB_TIMEOUT_VAL << 3), AR_SLEEP1_CAB_TIMEOUT)
164261991Sdim        | AR_SLEEP1_ASSUME_DTIM);
165200583Srdivacky
166198092Srdivacky    /* beacon timeout is now in 1/8 TU */
167198092Srdivacky    if (p_cap->hal_auto_sleep_support) {
168226633Sdim        beacontimeout = (BEACON_TIMEOUT_VAL << 3);
169226633Sdim    } else {
170226633Sdim        /*
171226633Sdim         * Use a very small value to make sure the timeout occurs before
172198092Srdivacky         * the TBTT.  In this case the chip will not go back to sleep
173218893Sdim         * automatically, instead it will wait for the SW to explicitly
174218893Sdim         * set it to that mode.
175218893Sdim         */
176226633Sdim        beacontimeout = MIN_BEACON_TIMEOUT_VAL;
177243830Sdim    }
178226633Sdim
179226633Sdim    OS_REG_WRITE(ah, AR_SLEEP2,
180226633Sdim        SM(beacontimeout, AR_SLEEP2_BEACON_TIMEOUT));
181261991Sdim
182296417Sdim    OS_REG_WRITE(ah, AR_TIM_PERIOD, TU_TO_USEC(beaconintval));
183296417Sdim    OS_REG_WRITE(ah, AR_DTIM_PERIOD, TU_TO_USEC(dtimperiod));
184296417Sdim
185261991Sdim    /* clear HOST AP related timers first */
186261991Sdim    OS_REG_CLR_BIT(ah, AR_TIMER_MODE, (AR_DBA_TIMER_EN | AR_SWBA_TIMER_EN));
187210299Sed
188210299Sed    OS_REG_SET_BIT(ah, AR_TIMER_MODE, AR_TBTT_TIMER_EN | AR_TIM_TIMER_EN
189210299Sed                    | AR_DTIM_TIMER_EN);
190210299Sed
191210299Sed    /* TSF out of range threshold */
192210299Sed    OS_REG_WRITE(ah, AR_TSFOOR_THRESHOLD, bs->bs_tsfoor_threshold);
193210299Sed
194210299Sed#undef CAB_TIMEOUT_VAL
195210299Sed#undef BEACON_TIMEOUT_VAL
196210299Sed#undef SLEEP_SLOP
197210299Sed}
198210299Sed#endif /* AH_SUPPORT_AR9300 */
199210299Sed