Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/dev/ath/ath_hal/ar5416/ar5416_radar.c
39566 views
1
/*-
2
* SPDX-License-Identifier: ISC
3
*
4
* Copyright (c) 2010-2011 Atheros Communications, Inc.
5
*
6
* Permission to use, copy, modify, and/or distribute this software for any
7
* purpose with or without fee is hereby granted, provided that the above
8
* copyright notice and this permission notice appear in all copies.
9
*
10
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
*/
18
#include "opt_ah.h"
19
20
#include "ah.h"
21
#include "ah_internal.h"
22
#include "ah_devid.h"
23
#include "ah_desc.h" /* NB: for HAL_PHYERR* */
24
25
#include "ar5416/ar5416.h"
26
#include "ar5416/ar5416reg.h"
27
#include "ar5416/ar5416phy.h"
28
29
#include "ah_eeprom_v14.h" /* for owl_get_ntxchains() */
30
31
/*
32
* These are default parameters for the AR5416 and
33
* later 802.11n NICs. They simply enable some
34
* radar pulse event generation.
35
*
36
* These are very likely not valid for the AR5212 era
37
* NICs.
38
*
39
* Since these define signal sizing and threshold
40
* parameters, they may need changing based on the
41
* specific antenna and receive amplifier
42
* configuration.
43
*/
44
#define AR5416_DFS_FIRPWR -33
45
#define AR5416_DFS_RRSSI 20
46
#define AR5416_DFS_HEIGHT 10
47
#define AR5416_DFS_PRSSI 15
48
#define AR5416_DFS_INBAND 15
49
#define AR5416_DFS_RELPWR 8
50
#define AR5416_DFS_RELSTEP 12
51
#define AR5416_DFS_MAXLEN 255
52
53
HAL_BOOL
54
ar5416GetDfsDefaultThresh(struct ath_hal *ah, HAL_PHYERR_PARAM *pe)
55
{
56
57
/*
58
* These are general examples of the parameter values
59
* to use when configuring radar pulse detection for
60
* the AR5416, AR91xx, AR92xx NICs. They are only
61
* for testing and do require tuning depending upon the
62
* hardware and deployment specifics.
63
*/
64
pe->pe_firpwr = AR5416_DFS_FIRPWR;
65
pe->pe_rrssi = AR5416_DFS_RRSSI;
66
pe->pe_height = AR5416_DFS_HEIGHT;
67
pe->pe_prssi = AR5416_DFS_PRSSI;
68
pe->pe_inband = AR5416_DFS_INBAND;
69
pe->pe_relpwr = AR5416_DFS_RELPWR;
70
pe->pe_relstep = AR5416_DFS_RELSTEP;
71
pe->pe_maxlen = AR5416_DFS_MAXLEN;
72
73
return (AH_TRUE);
74
}
75
76
/*
77
* Get the radar parameter values and return them in the pe
78
* structure
79
*/
80
void
81
ar5416GetDfsThresh(struct ath_hal *ah, HAL_PHYERR_PARAM *pe)
82
{
83
uint32_t val, temp;
84
85
val = OS_REG_READ(ah, AR_PHY_RADAR_0);
86
87
temp = MS(val,AR_PHY_RADAR_0_FIRPWR);
88
temp |= 0xFFFFFF80;
89
pe->pe_firpwr = temp;
90
pe->pe_rrssi = MS(val, AR_PHY_RADAR_0_RRSSI);
91
pe->pe_height = MS(val, AR_PHY_RADAR_0_HEIGHT);
92
pe->pe_prssi = MS(val, AR_PHY_RADAR_0_PRSSI);
93
pe->pe_inband = MS(val, AR_PHY_RADAR_0_INBAND);
94
95
/* RADAR_1 values */
96
val = OS_REG_READ(ah, AR_PHY_RADAR_1);
97
pe->pe_relpwr = MS(val, AR_PHY_RADAR_1_RELPWR_THRESH);
98
pe->pe_relstep = MS(val, AR_PHY_RADAR_1_RELSTEP_THRESH);
99
pe->pe_maxlen = MS(val, AR_PHY_RADAR_1_MAXLEN);
100
101
pe->pe_extchannel = !! (OS_REG_READ(ah, AR_PHY_RADAR_EXT) &
102
AR_PHY_RADAR_EXT_ENA);
103
104
pe->pe_usefir128 = !! (OS_REG_READ(ah, AR_PHY_RADAR_1) &
105
AR_PHY_RADAR_1_USE_FIR128);
106
pe->pe_blockradar = !! (OS_REG_READ(ah, AR_PHY_RADAR_1) &
107
AR_PHY_RADAR_1_BLOCK_CHECK);
108
pe->pe_enmaxrssi = !! (OS_REG_READ(ah, AR_PHY_RADAR_1) &
109
AR_PHY_RADAR_1_MAX_RRSSI);
110
pe->pe_enabled = !!
111
(OS_REG_READ(ah, AR_PHY_RADAR_0) & AR_PHY_RADAR_0_ENA);
112
pe->pe_enrelpwr = !! (OS_REG_READ(ah, AR_PHY_RADAR_1) &
113
AR_PHY_RADAR_1_RELPWR_ENA);
114
pe->pe_en_relstep_check = !! (OS_REG_READ(ah, AR_PHY_RADAR_1) &
115
AR_PHY_RADAR_1_RELSTEP_CHECK);
116
}
117
118
/*
119
* Enable radar detection and set the radar parameters per the
120
* values in pe
121
*/
122
void
123
ar5416EnableDfs(struct ath_hal *ah, HAL_PHYERR_PARAM *pe)
124
{
125
uint32_t val;
126
127
val = OS_REG_READ(ah, AR_PHY_RADAR_0);
128
129
if (pe->pe_firpwr != HAL_PHYERR_PARAM_NOVAL) {
130
val &= ~AR_PHY_RADAR_0_FIRPWR;
131
val |= SM(pe->pe_firpwr, AR_PHY_RADAR_0_FIRPWR);
132
}
133
if (pe->pe_rrssi != HAL_PHYERR_PARAM_NOVAL) {
134
val &= ~AR_PHY_RADAR_0_RRSSI;
135
val |= SM(pe->pe_rrssi, AR_PHY_RADAR_0_RRSSI);
136
}
137
if (pe->pe_height != HAL_PHYERR_PARAM_NOVAL) {
138
val &= ~AR_PHY_RADAR_0_HEIGHT;
139
val |= SM(pe->pe_height, AR_PHY_RADAR_0_HEIGHT);
140
}
141
if (pe->pe_prssi != HAL_PHYERR_PARAM_NOVAL) {
142
val &= ~AR_PHY_RADAR_0_PRSSI;
143
val |= SM(pe->pe_prssi, AR_PHY_RADAR_0_PRSSI);
144
}
145
if (pe->pe_inband != HAL_PHYERR_PARAM_NOVAL) {
146
val &= ~AR_PHY_RADAR_0_INBAND;
147
val |= SM(pe->pe_inband, AR_PHY_RADAR_0_INBAND);
148
}
149
150
/*Enable FFT data*/
151
val |= AR_PHY_RADAR_0_FFT_ENA;
152
OS_REG_WRITE(ah, AR_PHY_RADAR_0, val);
153
154
/* Implicitly enable */
155
if (pe->pe_enabled == 1)
156
OS_REG_SET_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_ENA);
157
else if (pe->pe_enabled == 0)
158
OS_REG_CLR_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_ENA);
159
160
if (pe->pe_usefir128 == 1)
161
OS_REG_SET_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_USE_FIR128);
162
else if (pe->pe_usefir128 == 0)
163
OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_USE_FIR128);
164
165
if (pe->pe_enmaxrssi == 1)
166
OS_REG_SET_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_MAX_RRSSI);
167
else if (pe->pe_enmaxrssi == 0)
168
OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_MAX_RRSSI);
169
170
if (pe->pe_blockradar == 1)
171
OS_REG_SET_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_BLOCK_CHECK);
172
else if (pe->pe_blockradar == 0)
173
OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_BLOCK_CHECK);
174
175
if (pe->pe_relstep != HAL_PHYERR_PARAM_NOVAL) {
176
val = OS_REG_READ(ah, AR_PHY_RADAR_1);
177
val &= ~AR_PHY_RADAR_1_RELSTEP_THRESH;
178
val |= SM(pe->pe_relstep, AR_PHY_RADAR_1_RELSTEP_THRESH);
179
OS_REG_WRITE(ah, AR_PHY_RADAR_1, val);
180
}
181
if (pe->pe_relpwr != HAL_PHYERR_PARAM_NOVAL) {
182
val = OS_REG_READ(ah, AR_PHY_RADAR_1);
183
val &= ~AR_PHY_RADAR_1_RELPWR_THRESH;
184
val |= SM(pe->pe_relpwr, AR_PHY_RADAR_1_RELPWR_THRESH);
185
OS_REG_WRITE(ah, AR_PHY_RADAR_1, val);
186
}
187
188
if (pe->pe_en_relstep_check == 1)
189
OS_REG_SET_BIT(ah, AR_PHY_RADAR_1,
190
AR_PHY_RADAR_1_RELSTEP_CHECK);
191
else if (pe->pe_en_relstep_check == 0)
192
OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1,
193
AR_PHY_RADAR_1_RELSTEP_CHECK);
194
195
if (pe->pe_enrelpwr == 1)
196
OS_REG_SET_BIT(ah, AR_PHY_RADAR_1,
197
AR_PHY_RADAR_1_RELPWR_ENA);
198
else if (pe->pe_enrelpwr == 0)
199
OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1,
200
AR_PHY_RADAR_1_RELPWR_ENA);
201
202
if (pe->pe_maxlen != HAL_PHYERR_PARAM_NOVAL) {
203
val = OS_REG_READ(ah, AR_PHY_RADAR_1);
204
val &= ~AR_PHY_RADAR_1_MAXLEN;
205
val |= SM(pe->pe_maxlen, AR_PHY_RADAR_1_MAXLEN);
206
OS_REG_WRITE(ah, AR_PHY_RADAR_1, val);
207
}
208
209
/*
210
* Enable HT/40 if the upper layer asks;
211
* it should check the channel is HT/40 and HAL_CAP_EXT_CHAN_DFS
212
* is available.
213
*/
214
if (pe->pe_extchannel == 1)
215
OS_REG_SET_BIT(ah, AR_PHY_RADAR_EXT, AR_PHY_RADAR_EXT_ENA);
216
else if (pe->pe_extchannel == 0)
217
OS_REG_CLR_BIT(ah, AR_PHY_RADAR_EXT, AR_PHY_RADAR_EXT_ENA);
218
}
219
220
/*
221
* Extract the radar event information from the given phy error.
222
*
223
* Returns AH_TRUE if the phy error was actually a phy error,
224
* AH_FALSE if the phy error wasn't a phy error.
225
*/
226
227
/* Flags for pulse_bw_info */
228
#define PRI_CH_RADAR_FOUND 0x01
229
#define EXT_CH_RADAR_FOUND 0x02
230
#define EXT_CH_RADAR_EARLY_FOUND 0x04
231
232
HAL_BOOL
233
ar5416ProcessRadarEvent(struct ath_hal *ah, struct ath_rx_status *rxs,
234
uint64_t fulltsf, const char *buf, HAL_DFS_EVENT *event)
235
{
236
HAL_BOOL doDfsExtCh;
237
HAL_BOOL doDfsEnhanced;
238
HAL_BOOL doDfsCombinedRssi;
239
240
uint8_t rssi = 0, ext_rssi = 0;
241
uint8_t pulse_bw_info = 0, pulse_length_ext = 0, pulse_length_pri = 0;
242
uint32_t dur = 0;
243
int pri_found = 1, ext_found = 0;
244
int early_ext = 0;
245
int is_dc = 0;
246
uint16_t datalen; /* length from the RX status field */
247
248
/* Check whether the given phy error is a radar event */
249
if ((rxs->rs_phyerr != HAL_PHYERR_RADAR) &&
250
(rxs->rs_phyerr != HAL_PHYERR_FALSE_RADAR_EXT)) {
251
return AH_FALSE;
252
}
253
254
/* Grab copies of the capabilities; just to make the code clearer */
255
doDfsExtCh = AH_PRIVATE(ah)->ah_caps.halExtChanDfsSupport;
256
doDfsEnhanced = AH_PRIVATE(ah)->ah_caps.halEnhancedDfsSupport;
257
doDfsCombinedRssi = AH_PRIVATE(ah)->ah_caps.halUseCombinedRadarRssi;
258
259
datalen = rxs->rs_datalen;
260
261
/* If hardware supports it, use combined RSSI, else use chain 0 RSSI */
262
if (doDfsCombinedRssi)
263
rssi = (uint8_t) rxs->rs_rssi;
264
else
265
rssi = (uint8_t) rxs->rs_rssi_ctl[0];
266
267
/* Set this; but only use it if doDfsExtCh is set */
268
ext_rssi = (uint8_t) rxs->rs_rssi_ext[0];
269
270
/* Cap it at 0 if the RSSI is a negative number */
271
if (rssi & 0x80)
272
rssi = 0;
273
274
if (ext_rssi & 0x80)
275
ext_rssi = 0;
276
277
/*
278
* Fetch the relevant data from the frame
279
*/
280
if (doDfsExtCh) {
281
if (datalen < 3)
282
return AH_FALSE;
283
284
/* Last three bytes of the frame are of interest */
285
pulse_length_pri = *(buf + datalen - 3);
286
pulse_length_ext = *(buf + datalen - 2);
287
pulse_bw_info = *(buf + datalen - 1);
288
HALDEBUG(ah, HAL_DEBUG_DFS, "%s: rssi=%d, ext_rssi=%d, pulse_length_pri=%d,"
289
" pulse_length_ext=%d, pulse_bw_info=%x\n",
290
__func__, rssi, ext_rssi, pulse_length_pri, pulse_length_ext,
291
pulse_bw_info);
292
} else {
293
/* The pulse width is byte 0 of the data */
294
if (datalen >= 1)
295
dur = ((uint8_t) buf[0]) & 0xff;
296
else
297
dur = 0;
298
299
if (dur == 0 && rssi == 0) {
300
HALDEBUG(ah, HAL_DEBUG_DFS, "%s: dur and rssi are 0\n", __func__);
301
return AH_FALSE;
302
}
303
304
HALDEBUG(ah, HAL_DEBUG_DFS, "%s: rssi=%d, dur=%d\n", __func__, rssi, dur);
305
306
/* Single-channel only */
307
pri_found = 1;
308
ext_found = 0;
309
}
310
311
/*
312
* If doing extended channel data, pulse_bw_info must
313
* have one of the flags set.
314
*/
315
if (doDfsExtCh && pulse_bw_info == 0x0)
316
return AH_FALSE;
317
318
/*
319
* If the extended channel data is available, calculate
320
* which to pay attention to.
321
*/
322
if (doDfsExtCh) {
323
/* If pulse is on DC, take the larger duration of the two */
324
if ((pulse_bw_info & EXT_CH_RADAR_FOUND) &&
325
(pulse_bw_info & PRI_CH_RADAR_FOUND)) {
326
is_dc = 1;
327
if (pulse_length_ext > pulse_length_pri) {
328
dur = pulse_length_ext;
329
pri_found = 0;
330
ext_found = 1;
331
} else {
332
dur = pulse_length_pri;
333
pri_found = 1;
334
ext_found = 0;
335
}
336
} else if (pulse_bw_info & EXT_CH_RADAR_EARLY_FOUND) {
337
dur = pulse_length_ext;
338
pri_found = 0;
339
ext_found = 1;
340
early_ext = 1;
341
} else if (pulse_bw_info & PRI_CH_RADAR_FOUND) {
342
dur = pulse_length_pri;
343
pri_found = 1;
344
ext_found = 0;
345
} else if (pulse_bw_info & EXT_CH_RADAR_FOUND) {
346
dur = pulse_length_ext;
347
pri_found = 0;
348
ext_found = 1;
349
}
350
351
}
352
353
/*
354
* For enhanced DFS (Merlin and later), pulse_bw_info has
355
* implications for selecting the correct RSSI value.
356
*/
357
if (doDfsEnhanced) {
358
switch (pulse_bw_info & 0x03) {
359
case 0:
360
/* No radar? */
361
rssi = 0;
362
break;
363
case PRI_CH_RADAR_FOUND:
364
/* Radar in primary channel */
365
/* Cannot use ctrl channel RSSI if ext channel is stronger */
366
if (ext_rssi >= (rssi + 3)) {
367
rssi = 0;
368
}
369
break;
370
case EXT_CH_RADAR_FOUND:
371
/* Radar in extended channel */
372
/* Cannot use ext channel RSSI if ctrl channel is stronger */
373
if (rssi >= (ext_rssi + 12)) {
374
rssi = 0;
375
} else {
376
rssi = ext_rssi;
377
}
378
break;
379
case (PRI_CH_RADAR_FOUND | EXT_CH_RADAR_FOUND):
380
/* When both are present, use stronger one */
381
if (rssi < ext_rssi)
382
rssi = ext_rssi;
383
break;
384
}
385
}
386
387
/*
388
* If not doing enhanced DFS, choose the ext channel if
389
* it is stronger than the main channel
390
*/
391
if (doDfsExtCh && !doDfsEnhanced) {
392
if ((ext_rssi > rssi) && (ext_rssi < 128))
393
rssi = ext_rssi;
394
}
395
396
/*
397
* XXX what happens if the above code decides the RSSI
398
* XXX wasn't valid, an sets it to 0?
399
*/
400
401
/*
402
* Fill out dfs_event structure.
403
*/
404
event->re_full_ts = fulltsf;
405
event->re_ts = rxs->rs_tstamp;
406
event->re_rssi = rssi;
407
event->re_dur = dur;
408
409
event->re_flags = 0;
410
if (pri_found)
411
event->re_flags |= HAL_DFS_EVENT_PRICH;
412
if (ext_found)
413
event->re_flags |= HAL_DFS_EVENT_EXTCH;
414
if (early_ext)
415
event->re_flags |= HAL_DFS_EVENT_EXTEARLY;
416
if (is_dc)
417
event->re_flags |= HAL_DFS_EVENT_ISDC;
418
419
return AH_TRUE;
420
}
421
422
/*
423
* Return whether fast-clock is currently enabled for this
424
* channel.
425
*/
426
HAL_BOOL
427
ar5416IsFastClockEnabled(struct ath_hal *ah)
428
{
429
struct ath_hal_private *ahp = AH_PRIVATE(ah);
430
431
return IS_5GHZ_FAST_CLOCK_EN(ah, ahp->ah_curchan);
432
}
433
434