1 | /* |
2 | * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting |
3 | * Copyright (c) 2002-2006 Atheros Communications, Inc. |
4 | * |
5 | * Permission to use, copy, modify, and/or distribute this software for any |
6 | * purpose with or without fee is hereby granted, provided that the above |
7 | * copyright notice and this permission notice appear in all copies. |
8 | * |
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
16 | * |
17 | * $Id: ar5211_beacon.c,v 1.2 2009/01/06 06:03:57 mrg Exp $ |
18 | */ |
19 | #include "opt_ah.h" |
20 | |
21 | #include "ah.h" |
22 | #include "ah_internal.h" |
23 | |
24 | #include "ar5211/ar5211.h" |
25 | #include "ar5211/ar5211reg.h" |
26 | #include "ar5211/ar5211desc.h" |
27 | |
28 | /* |
29 | * Routines used to initialize and generated beacons for the AR5211/AR5311. |
30 | */ |
31 | |
32 | /* |
33 | * Initialize all of the hardware registers used to send beacons. |
34 | */ |
35 | void |
36 | ar5211SetBeaconTimers(struct ath_hal *ah, const HAL_BEACON_TIMERS *bt) |
37 | { |
38 | |
39 | OS_REG_WRITE(ah, AR_TIMER0, bt->bt_nexttbtt); |
40 | OS_REG_WRITE(ah, AR_TIMER1, bt->bt_nextdba); |
41 | OS_REG_WRITE(ah, AR_TIMER2, bt->bt_nextswba); |
42 | OS_REG_WRITE(ah, AR_TIMER3, bt->bt_nextatim); |
43 | /* |
44 | * Set the Beacon register after setting all timers. |
45 | */ |
46 | OS_REG_WRITE(ah, AR_BEACON, bt->bt_intval); |
47 | } |
48 | |
49 | /* |
50 | * Legacy api to initialize all of the beacon registers. |
51 | */ |
52 | void |
53 | ar5211BeaconInit(struct ath_hal *ah, |
54 | uint32_t next_beacon, uint32_t beacon_period) |
55 | { |
56 | HAL_BEACON_TIMERS bt; |
57 | |
58 | bt.bt_nextdba = 0; |
59 | bt.bt_nextswba = 0; |
60 | bt.bt_nexttbtt = next_beacon; |
61 | /* |
62 | * TIMER1: in AP/adhoc mode this controls the DMA beacon |
63 | * alert timer; otherwise it controls the next wakeup time. |
64 | * TIMER2: in AP mode, it controls the SBA beacon alert |
65 | * interrupt; otherwise it sets the start of the next CFP. |
66 | */ |
67 | switch (AH_PRIVATE(ah)->ah_opmode) { |
68 | case HAL_M_STA: |
69 | case HAL_M_MONITOR: |
70 | bt.bt_nextdba = 0xffff; |
71 | bt.bt_nextswba = 0x7ffff; |
72 | break; |
73 | case HAL_M_IBSS: |
74 | case HAL_M_HOSTAP: |
75 | bt.bt_nextdba = (next_beacon - |
76 | ath_hal_dma_beacon_response_time) << 3; /* 1/8 TU */ |
77 | bt.bt_nextswba = (next_beacon - |
78 | ath_hal_sw_beacon_response_time) << 3; /* 1/8 TU */ |
79 | break; |
80 | } |
81 | /* |
82 | * Set the ATIM window |
83 | * Our hardware does not support an ATIM window of 0 |
84 | * (beacons will not work). If the ATIM windows is 0, |
85 | * force it to 1. |
86 | */ |
87 | bt.bt_nextatim = next_beacon + 1; |
88 | bt.bt_intval = beacon_period & |
89 | (AR_BEACON_PERIOD | AR_BEACON_RESET_TSF | AR_BEACON_EN); |
90 | ar5211SetBeaconTimers(ah, &bt); |
91 | } |
92 | |
93 | void |
94 | ar5211ResetStaBeaconTimers(struct ath_hal *ah) |
95 | { |
96 | uint32_t val; |
97 | |
98 | OS_REG_WRITE(ah, AR_TIMER0, 0); /* no beacons */ |
99 | val = OS_REG_READ(ah, AR_STA_ID1); |
100 | val |= AR_STA_ID1_PWR_SAV; /* XXX */ |
101 | /* tell the h/w that the associated AP is not PCF capable */ |
102 | OS_REG_WRITE(ah, AR_STA_ID1, |
103 | val & ~(AR_STA_ID1_DEFAULT_ANTENNA | AR_STA_ID1_PCF)); |
104 | OS_REG_WRITE(ah, AR_BEACON, AR_BEACON_PERIOD); |
105 | } |
106 | |
107 | /* |
108 | * Set all the beacon related bits on the h/w for stations |
109 | * i.e. initializes the corresponding h/w timers; |
110 | * also tells the h/w whether to anticipate PCF beacons |
111 | */ |
112 | void |
113 | ar5211SetStaBeaconTimers(struct ath_hal *ah, const HAL_BEACON_STATE *bs) |
114 | { |
115 | struct ath_hal_5211 *ahp = AH5211(ah); |
116 | |
117 | HALDEBUG(ah, HAL_DEBUG_BEACON, "%s: setting beacon timers\n" , __func__); |
118 | |
119 | HALASSERT(bs->bs_intval != 0); |
120 | /* if the AP will do PCF */ |
121 | if (bs->bs_cfpmaxduration != 0) { |
122 | /* tell the h/w that the associated AP is PCF capable */ |
123 | OS_REG_WRITE(ah, AR_STA_ID1, |
124 | OS_REG_READ(ah, AR_STA_ID1) | AR_STA_ID1_PCF); |
125 | |
126 | /* set CFP_PERIOD(1.024ms) register */ |
127 | OS_REG_WRITE(ah, AR_CFP_PERIOD, bs->bs_cfpperiod); |
128 | |
129 | /* set CFP_DUR(1.024ms) register to max cfp duration */ |
130 | OS_REG_WRITE(ah, AR_CFP_DUR, bs->bs_cfpmaxduration); |
131 | |
132 | /* set TIMER2(128us) to anticipated time of next CFP */ |
133 | OS_REG_WRITE(ah, AR_TIMER2, bs->bs_cfpnext << 3); |
134 | } else { |
135 | /* tell the h/w that the associated AP is not PCF capable */ |
136 | OS_REG_WRITE(ah, AR_STA_ID1, |
137 | OS_REG_READ(ah, AR_STA_ID1) &~ AR_STA_ID1_PCF); |
138 | } |
139 | |
140 | /* |
141 | * Set TIMER0(1.024ms) to the anticipated time of the next beacon. |
142 | */ |
143 | OS_REG_WRITE(ah, AR_TIMER0, bs->bs_nexttbtt); |
144 | |
145 | /* |
146 | * Start the beacon timers by setting the BEACON register |
147 | * to the beacon interval; also write the tim offset which |
148 | * we should know by now. The code, in ar5211WriteAssocid, |
149 | * also sets the tim offset once the AID is known which can |
150 | * be left as such for now. |
151 | */ |
152 | OS_REG_WRITE(ah, AR_BEACON, |
153 | (OS_REG_READ(ah, AR_BEACON) &~ (AR_BEACON_PERIOD|AR_BEACON_TIM)) |
154 | | SM(bs->bs_intval, AR_BEACON_PERIOD) |
155 | | SM(bs->bs_timoffset ? bs->bs_timoffset + 4 : 0, AR_BEACON_TIM) |
156 | ); |
157 | |
158 | /* |
159 | * Configure the BMISS interrupt. Note that we |
160 | * assume the caller blocks interrupts while enabling |
161 | * the threshold. |
162 | */ |
163 | HALASSERT(bs->bs_bmissthreshold <= MS(0xffffffff, AR_RSSI_THR_BM_THR)); |
164 | ahp->ah_rssiThr = (ahp->ah_rssiThr &~ AR_RSSI_THR_BM_THR) |
165 | | SM(bs->bs_bmissthreshold, AR_RSSI_THR_BM_THR); |
166 | OS_REG_WRITE(ah, AR_RSSI_THR, ahp->ah_rssiThr); |
167 | |
168 | /* |
169 | * Set the sleep duration in 1/8 TU's. |
170 | */ |
171 | #define SLEEP_SLOP 3 |
172 | OS_REG_RMW_FIELD(ah, AR_SCR, AR_SCR_SLDUR, |
173 | (bs->bs_sleepduration - SLEEP_SLOP) << 3); |
174 | #undef SLEEP_SLOP |
175 | } |
176 | |