Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/dev/ath/ath_hal/ar5210/ar5210_beacon.c
39566 views
1
/*-
2
* SPDX-License-Identifier: ISC
3
*
4
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
5
* Copyright (c) 2002-2004 Atheros Communications, Inc.
6
*
7
* Permission to use, copy, modify, and/or distribute this software for any
8
* purpose with or without fee is hereby granted, provided that the above
9
* copyright notice and this permission notice appear in all copies.
10
*
11
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18
*/
19
#include "opt_ah.h"
20
21
#include "ah.h"
22
#include "ah_internal.h"
23
#include "ah_desc.h"
24
25
#include "ar5210/ar5210.h"
26
#include "ar5210/ar5210reg.h"
27
#include "ar5210/ar5210desc.h"
28
29
/*
30
* Return the hardware NextTBTT in TSF
31
*/
32
uint64_t
33
ar5210GetNextTBTT(struct ath_hal *ah)
34
{
35
#define TU_TO_TSF(_tu) (((uint64_t)(_tu)) << 10)
36
return TU_TO_TSF(OS_REG_READ(ah, AR_TIMER0));
37
#undef TU_TO_TSF
38
}
39
40
/*
41
* Initialize all of the hardware registers used to send beacons.
42
*/
43
void
44
ar5210SetBeaconTimers(struct ath_hal *ah, const HAL_BEACON_TIMERS *bt)
45
{
46
47
OS_REG_WRITE(ah, AR_TIMER0, bt->bt_nexttbtt);
48
OS_REG_WRITE(ah, AR_TIMER1, bt->bt_nextdba);
49
OS_REG_WRITE(ah, AR_TIMER2, bt->bt_nextswba);
50
OS_REG_WRITE(ah, AR_TIMER3, bt->bt_nextatim);
51
/*
52
* Set the Beacon register after setting all timers.
53
*/
54
OS_REG_WRITE(ah, AR_BEACON, bt->bt_intval);
55
}
56
57
/*
58
* Legacy api to Initialize all of the beacon registers.
59
*/
60
void
61
ar5210BeaconInit(struct ath_hal *ah,
62
uint32_t next_beacon, uint32_t beacon_period)
63
{
64
HAL_BEACON_TIMERS bt;
65
66
bt.bt_nexttbtt = next_beacon;
67
68
if (AH_PRIVATE(ah)->ah_opmode != HAL_M_STA) {
69
bt.bt_nextdba = (next_beacon -
70
ah->ah_config.ah_dma_beacon_response_time) << 3; /* 1/8 TU */
71
bt.bt_nextswba = (next_beacon -
72
ah->ah_config.ah_sw_beacon_response_time) << 3; /* 1/8 TU */
73
/*
74
* The SWBA interrupt is not used for beacons in ad hoc mode
75
* as we don't yet support ATIMs. So since the beacon never
76
* changes, the beacon descriptor is set up once and read
77
* into a special HW buffer, from which it will be
78
* automagically retrieved at each DMA Beacon Alert (DBA).
79
*/
80
81
/* Set the ATIM window */
82
bt.bt_nextatim = next_beacon + 0; /* NB: no ATIMs */
83
} else {
84
bt.bt_nextdba = ~0;
85
bt.bt_nextswba = ~0;
86
bt.bt_nextatim = 1;
87
}
88
bt.bt_intval = beacon_period &
89
(AR_BEACON_PERIOD | AR_BEACON_RESET_TSF | AR_BEACON_EN);
90
ar5210SetBeaconTimers(ah, &bt);
91
}
92
93
void
94
ar5210ResetStaBeaconTimers(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_NO_PSPOLL; /* 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
* dtim_count and cfp_count from the current beacon - their current
113
* values aren't necessarily maintained in the device struct
114
*/
115
void
116
ar5210SetStaBeaconTimers(struct ath_hal *ah, const HAL_BEACON_STATE *bs)
117
{
118
struct ath_hal_5210 *ahp = AH5210(ah);
119
120
HALDEBUG(ah, HAL_DEBUG_BEACON, "%s: setting beacon timers\n", __func__);
121
122
HALASSERT(bs->bs_intval != 0);
123
/* if the AP will do PCF */
124
if (bs->bs_cfpmaxduration != 0) {
125
/* tell the h/w that the associated AP is PCF capable */
126
OS_REG_WRITE(ah, AR_STA_ID1,
127
(OS_REG_READ(ah, AR_STA_ID1) &~ AR_STA_ID1_DEFAULT_ANTENNA)
128
| AR_STA_ID1_PCF);
129
130
/* set CFP_PERIOD(1.024ms) register */
131
OS_REG_WRITE(ah, AR_CFP_PERIOD, bs->bs_cfpperiod);
132
133
/* set CFP_DUR(1.024ms) register to max cfp duration */
134
OS_REG_WRITE(ah, AR_CFP_DUR, bs->bs_cfpmaxduration);
135
136
/* set TIMER2(128us) to anticipated time of next CFP */
137
OS_REG_WRITE(ah, AR_TIMER2, bs->bs_cfpnext << 3);
138
} else {
139
/* tell the h/w that the associated AP is not PCF capable */
140
OS_REG_WRITE(ah, AR_STA_ID1,
141
OS_REG_READ(ah, AR_STA_ID1) &~ (AR_STA_ID1_DEFAULT_ANTENNA | AR_STA_ID1_PCF));
142
}
143
144
/*
145
* Set TIMER0(1.024ms) to the anticipated time of the next beacon.
146
*/
147
OS_REG_WRITE(ah, AR_TIMER0, bs->bs_nexttbtt);
148
149
/*
150
* Start the beacon timers by setting the BEACON register
151
* to the beacon interval; also write the tim offset which
152
* we should know by now. The code, in ar5211WriteAssocid,
153
* also sets the tim offset once the AID is known which can
154
* be left as such for now.
155
*/
156
OS_REG_WRITE(ah, AR_BEACON,
157
(OS_REG_READ(ah, AR_BEACON) &~ (AR_BEACON_PERIOD|AR_BEACON_TIM))
158
| SM(bs->bs_intval, AR_BEACON_PERIOD)
159
| SM(bs->bs_timoffset ? bs->bs_timoffset + 4 : 0, AR_BEACON_TIM)
160
);
161
162
/*
163
* Configure the BMISS interrupt. Note that we
164
* assume the caller blocks interrupts while enabling
165
* the threshold.
166
*/
167
168
/*
169
* Interrupt works only on Crete.
170
*/
171
if (AH_PRIVATE(ah)->ah_macRev < AR_SREV_CRETE)
172
return;
173
/*
174
* Counter is only 3-bits.
175
* Count of 0 with BMISS interrupt enabled will hang the system
176
* with too many interrupts
177
*/
178
if (AH_PRIVATE(ah)->ah_macRev >= AR_SREV_CRETE &&
179
(bs->bs_bmissthreshold&7) == 0) {
180
#ifdef AH_DEBUG
181
ath_hal_printf(ah, "%s: invalid beacon miss threshold %u\n",
182
__func__, bs->bs_bmissthreshold);
183
#endif
184
return;
185
}
186
#define BMISS_MAX (AR_RSSI_THR_BM_THR >> AR_RSSI_THR_BM_THR_S)
187
/*
188
* Configure the BMISS interrupt. Note that we
189
* assume the caller blocks interrupts while enabling
190
* the threshold.
191
*
192
* NB: the beacon miss count field is only 3 bits which
193
* is much smaller than what's found on later parts;
194
* clamp overflow values as a safeguard.
195
*/
196
ahp->ah_rssiThr = (ahp->ah_rssiThr &~ AR_RSSI_THR_BM_THR)
197
| SM(bs->bs_bmissthreshold > BMISS_MAX ?
198
BMISS_MAX : bs->bs_bmissthreshold,
199
AR_RSSI_THR_BM_THR);
200
OS_REG_WRITE(ah, AR_RSSI_THR, ahp->ah_rssiThr);
201
#undef BMISS_MAX
202
}
203
204