2 * SPDX-License-Identifier: ISC
4 * Copyright (c) 2010-2011 Atheros Communications, Inc.
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.
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.
23 #include "ah_internal.h"
25 #include "ah_desc.h" /* NB: for HAL_PHYERR* */
27 #include "ar5416/ar5416.h"
28 #include "ar5416/ar5416reg.h"
29 #include "ar5416/ar5416phy.h"
31 #include "ah_eeprom_v14.h" /* for owl_get_ntxchains() */
34 * These are default parameters for the AR5416 and
35 * later 802.11n NICs. They simply enable some
36 * radar pulse event generation.
38 * These are very likely not valid for the AR5212 era
41 * Since these define signal sizing and threshold
42 * parameters, they may need changing based on the
43 * specific antenna and receive amplifier
46 #define AR5416_DFS_FIRPWR -33
47 #define AR5416_DFS_RRSSI 20
48 #define AR5416_DFS_HEIGHT 10
49 #define AR5416_DFS_PRSSI 15
50 #define AR5416_DFS_INBAND 15
51 #define AR5416_DFS_RELPWR 8
52 #define AR5416_DFS_RELSTEP 12
53 #define AR5416_DFS_MAXLEN 255
56 ar5416GetDfsDefaultThresh(struct ath_hal *ah, HAL_PHYERR_PARAM *pe)
60 * These are general examples of the parameter values
61 * to use when configuring radar pulse detection for
62 * the AR5416, AR91xx, AR92xx NICs. They are only
63 * for testing and do require tuning depending upon the
64 * hardware and deployment specifics.
66 pe->pe_firpwr = AR5416_DFS_FIRPWR;
67 pe->pe_rrssi = AR5416_DFS_RRSSI;
68 pe->pe_height = AR5416_DFS_HEIGHT;
69 pe->pe_prssi = AR5416_DFS_PRSSI;
70 pe->pe_inband = AR5416_DFS_INBAND;
71 pe->pe_relpwr = AR5416_DFS_RELPWR;
72 pe->pe_relstep = AR5416_DFS_RELSTEP;
73 pe->pe_maxlen = AR5416_DFS_MAXLEN;
79 * Get the radar parameter values and return them in the pe
83 ar5416GetDfsThresh(struct ath_hal *ah, HAL_PHYERR_PARAM *pe)
87 val = OS_REG_READ(ah, AR_PHY_RADAR_0);
89 temp = MS(val,AR_PHY_RADAR_0_FIRPWR);
92 pe->pe_rrssi = MS(val, AR_PHY_RADAR_0_RRSSI);
93 pe->pe_height = MS(val, AR_PHY_RADAR_0_HEIGHT);
94 pe->pe_prssi = MS(val, AR_PHY_RADAR_0_PRSSI);
95 pe->pe_inband = MS(val, AR_PHY_RADAR_0_INBAND);
98 val = OS_REG_READ(ah, AR_PHY_RADAR_1);
99 pe->pe_relpwr = MS(val, AR_PHY_RADAR_1_RELPWR_THRESH);
100 pe->pe_relstep = MS(val, AR_PHY_RADAR_1_RELSTEP_THRESH);
101 pe->pe_maxlen = MS(val, AR_PHY_RADAR_1_MAXLEN);
103 pe->pe_extchannel = !! (OS_REG_READ(ah, AR_PHY_RADAR_EXT) &
104 AR_PHY_RADAR_EXT_ENA);
106 pe->pe_usefir128 = !! (OS_REG_READ(ah, AR_PHY_RADAR_1) &
107 AR_PHY_RADAR_1_USE_FIR128);
108 pe->pe_blockradar = !! (OS_REG_READ(ah, AR_PHY_RADAR_1) &
109 AR_PHY_RADAR_1_BLOCK_CHECK);
110 pe->pe_enmaxrssi = !! (OS_REG_READ(ah, AR_PHY_RADAR_1) &
111 AR_PHY_RADAR_1_MAX_RRSSI);
113 (OS_REG_READ(ah, AR_PHY_RADAR_0) & AR_PHY_RADAR_0_ENA);
114 pe->pe_enrelpwr = !! (OS_REG_READ(ah, AR_PHY_RADAR_1) &
115 AR_PHY_RADAR_1_RELPWR_ENA);
116 pe->pe_en_relstep_check = !! (OS_REG_READ(ah, AR_PHY_RADAR_1) &
117 AR_PHY_RADAR_1_RELSTEP_CHECK);
121 * Enable radar detection and set the radar parameters per the
125 ar5416EnableDfs(struct ath_hal *ah, HAL_PHYERR_PARAM *pe)
129 val = OS_REG_READ(ah, AR_PHY_RADAR_0);
131 if (pe->pe_firpwr != HAL_PHYERR_PARAM_NOVAL) {
132 val &= ~AR_PHY_RADAR_0_FIRPWR;
133 val |= SM(pe->pe_firpwr, AR_PHY_RADAR_0_FIRPWR);
135 if (pe->pe_rrssi != HAL_PHYERR_PARAM_NOVAL) {
136 val &= ~AR_PHY_RADAR_0_RRSSI;
137 val |= SM(pe->pe_rrssi, AR_PHY_RADAR_0_RRSSI);
139 if (pe->pe_height != HAL_PHYERR_PARAM_NOVAL) {
140 val &= ~AR_PHY_RADAR_0_HEIGHT;
141 val |= SM(pe->pe_height, AR_PHY_RADAR_0_HEIGHT);
143 if (pe->pe_prssi != HAL_PHYERR_PARAM_NOVAL) {
144 val &= ~AR_PHY_RADAR_0_PRSSI;
145 val |= SM(pe->pe_prssi, AR_PHY_RADAR_0_PRSSI);
147 if (pe->pe_inband != HAL_PHYERR_PARAM_NOVAL) {
148 val &= ~AR_PHY_RADAR_0_INBAND;
149 val |= SM(pe->pe_inband, AR_PHY_RADAR_0_INBAND);
153 val |= AR_PHY_RADAR_0_FFT_ENA;
154 OS_REG_WRITE(ah, AR_PHY_RADAR_0, val);
156 /* Implicitly enable */
157 if (pe->pe_enabled == 1)
158 OS_REG_SET_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_ENA);
159 else if (pe->pe_enabled == 0)
160 OS_REG_CLR_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_ENA);
162 if (pe->pe_usefir128 == 1)
163 OS_REG_SET_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_USE_FIR128);
164 else if (pe->pe_usefir128 == 0)
165 OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_USE_FIR128);
167 if (pe->pe_enmaxrssi == 1)
168 OS_REG_SET_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_MAX_RRSSI);
169 else if (pe->pe_enmaxrssi == 0)
170 OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_MAX_RRSSI);
172 if (pe->pe_blockradar == 1)
173 OS_REG_SET_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_BLOCK_CHECK);
174 else if (pe->pe_blockradar == 0)
175 OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_BLOCK_CHECK);
177 if (pe->pe_relstep != HAL_PHYERR_PARAM_NOVAL) {
178 val = OS_REG_READ(ah, AR_PHY_RADAR_1);
179 val &= ~AR_PHY_RADAR_1_RELSTEP_THRESH;
180 val |= SM(pe->pe_relstep, AR_PHY_RADAR_1_RELSTEP_THRESH);
181 OS_REG_WRITE(ah, AR_PHY_RADAR_1, val);
183 if (pe->pe_relpwr != HAL_PHYERR_PARAM_NOVAL) {
184 val = OS_REG_READ(ah, AR_PHY_RADAR_1);
185 val &= ~AR_PHY_RADAR_1_RELPWR_THRESH;
186 val |= SM(pe->pe_relpwr, AR_PHY_RADAR_1_RELPWR_THRESH);
187 OS_REG_WRITE(ah, AR_PHY_RADAR_1, val);
190 if (pe->pe_en_relstep_check == 1)
191 OS_REG_SET_BIT(ah, AR_PHY_RADAR_1,
192 AR_PHY_RADAR_1_RELSTEP_CHECK);
193 else if (pe->pe_en_relstep_check == 0)
194 OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1,
195 AR_PHY_RADAR_1_RELSTEP_CHECK);
197 if (pe->pe_enrelpwr == 1)
198 OS_REG_SET_BIT(ah, AR_PHY_RADAR_1,
199 AR_PHY_RADAR_1_RELPWR_ENA);
200 else if (pe->pe_enrelpwr == 0)
201 OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1,
202 AR_PHY_RADAR_1_RELPWR_ENA);
204 if (pe->pe_maxlen != HAL_PHYERR_PARAM_NOVAL) {
205 val = OS_REG_READ(ah, AR_PHY_RADAR_1);
206 val &= ~AR_PHY_RADAR_1_MAXLEN;
207 val |= SM(pe->pe_maxlen, AR_PHY_RADAR_1_MAXLEN);
208 OS_REG_WRITE(ah, AR_PHY_RADAR_1, val);
212 * Enable HT/40 if the upper layer asks;
213 * it should check the channel is HT/40 and HAL_CAP_EXT_CHAN_DFS
216 if (pe->pe_extchannel == 1)
217 OS_REG_SET_BIT(ah, AR_PHY_RADAR_EXT, AR_PHY_RADAR_EXT_ENA);
218 else if (pe->pe_extchannel == 0)
219 OS_REG_CLR_BIT(ah, AR_PHY_RADAR_EXT, AR_PHY_RADAR_EXT_ENA);
223 * Extract the radar event information from the given phy error.
225 * Returns AH_TRUE if the phy error was actually a phy error,
226 * AH_FALSE if the phy error wasn't a phy error.
229 /* Flags for pulse_bw_info */
230 #define PRI_CH_RADAR_FOUND 0x01
231 #define EXT_CH_RADAR_FOUND 0x02
232 #define EXT_CH_RADAR_EARLY_FOUND 0x04
235 ar5416ProcessRadarEvent(struct ath_hal *ah, struct ath_rx_status *rxs,
236 uint64_t fulltsf, const char *buf, HAL_DFS_EVENT *event)
239 HAL_BOOL doDfsEnhanced;
240 HAL_BOOL doDfsCombinedRssi;
242 uint8_t rssi = 0, ext_rssi = 0;
243 uint8_t pulse_bw_info = 0, pulse_length_ext = 0, pulse_length_pri = 0;
245 int pri_found = 1, ext_found = 0;
248 uint16_t datalen; /* length from the RX status field */
250 /* Check whether the given phy error is a radar event */
251 if ((rxs->rs_phyerr != HAL_PHYERR_RADAR) &&
252 (rxs->rs_phyerr != HAL_PHYERR_FALSE_RADAR_EXT)) {
256 /* Grab copies of the capabilities; just to make the code clearer */
257 doDfsExtCh = AH_PRIVATE(ah)->ah_caps.halExtChanDfsSupport;
258 doDfsEnhanced = AH_PRIVATE(ah)->ah_caps.halEnhancedDfsSupport;
259 doDfsCombinedRssi = AH_PRIVATE(ah)->ah_caps.halUseCombinedRadarRssi;
261 datalen = rxs->rs_datalen;
263 /* If hardware supports it, use combined RSSI, else use chain 0 RSSI */
264 if (doDfsCombinedRssi)
265 rssi = (uint8_t) rxs->rs_rssi;
267 rssi = (uint8_t) rxs->rs_rssi_ctl[0];
269 /* Set this; but only use it if doDfsExtCh is set */
270 ext_rssi = (uint8_t) rxs->rs_rssi_ext[0];
272 /* Cap it at 0 if the RSSI is a negative number */
280 * Fetch the relevant data from the frame
286 /* Last three bytes of the frame are of interest */
287 pulse_length_pri = *(buf + datalen - 3);
288 pulse_length_ext = *(buf + datalen - 2);
289 pulse_bw_info = *(buf + datalen - 1);
290 HALDEBUG(ah, HAL_DEBUG_DFS, "%s: rssi=%d, ext_rssi=%d, pulse_length_pri=%d,"
291 " pulse_length_ext=%d, pulse_bw_info=%x\n",
292 __func__, rssi, ext_rssi, pulse_length_pri, pulse_length_ext,
295 /* The pulse width is byte 0 of the data */
297 dur = ((uint8_t) buf[0]) & 0xff;
301 if (dur == 0 && rssi == 0) {
302 HALDEBUG(ah, HAL_DEBUG_DFS, "%s: dur and rssi are 0\n", __func__);
306 HALDEBUG(ah, HAL_DEBUG_DFS, "%s: rssi=%d, dur=%d\n", __func__, rssi, dur);
308 /* Single-channel only */
314 * If doing extended channel data, pulse_bw_info must
315 * have one of the flags set.
317 if (doDfsExtCh && pulse_bw_info == 0x0)
321 * If the extended channel data is available, calculate
322 * which to pay attention to.
325 /* If pulse is on DC, take the larger duration of the two */
326 if ((pulse_bw_info & EXT_CH_RADAR_FOUND) &&
327 (pulse_bw_info & PRI_CH_RADAR_FOUND)) {
329 if (pulse_length_ext > pulse_length_pri) {
330 dur = pulse_length_ext;
334 dur = pulse_length_pri;
338 } else if (pulse_bw_info & EXT_CH_RADAR_EARLY_FOUND) {
339 dur = pulse_length_ext;
343 } else if (pulse_bw_info & PRI_CH_RADAR_FOUND) {
344 dur = pulse_length_pri;
347 } else if (pulse_bw_info & EXT_CH_RADAR_FOUND) {
348 dur = pulse_length_ext;
356 * For enhanced DFS (Merlin and later), pulse_bw_info has
357 * implications for selecting the correct RSSI value.
360 switch (pulse_bw_info & 0x03) {
365 case PRI_CH_RADAR_FOUND:
366 /* Radar in primary channel */
367 /* Cannot use ctrl channel RSSI if ext channel is stronger */
368 if (ext_rssi >= (rssi + 3)) {
372 case EXT_CH_RADAR_FOUND:
373 /* Radar in extended channel */
374 /* Cannot use ext channel RSSI if ctrl channel is stronger */
375 if (rssi >= (ext_rssi + 12)) {
381 case (PRI_CH_RADAR_FOUND | EXT_CH_RADAR_FOUND):
382 /* When both are present, use stronger one */
390 * If not doing enhanced DFS, choose the ext channel if
391 * it is stronger than the main channel
393 if (doDfsExtCh && !doDfsEnhanced) {
394 if ((ext_rssi > rssi) && (ext_rssi < 128))
399 * XXX what happens if the above code decides the RSSI
400 * XXX wasn't valid, an sets it to 0?
404 * Fill out dfs_event structure.
406 event->re_full_ts = fulltsf;
407 event->re_ts = rxs->rs_tstamp;
408 event->re_rssi = rssi;
413 event->re_flags |= HAL_DFS_EVENT_PRICH;
415 event->re_flags |= HAL_DFS_EVENT_EXTCH;
417 event->re_flags |= HAL_DFS_EVENT_EXTEARLY;
419 event->re_flags |= HAL_DFS_EVENT_ISDC;
425 * Return whether fast-clock is currently enabled for this
429 ar5416IsFastClockEnabled(struct ath_hal *ah)
431 struct ath_hal_private *ahp = AH_PRIVATE(ah);
433 return IS_5GHZ_FAST_CLOCK_EN(ah, ahp->ah_curchan);