]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/ath/ath_hal/ar5416/ar5416_radar.c
MFV r365599: import fix for a libexecinfo warning at higher WARNS
[FreeBSD/FreeBSD.git] / sys / dev / ath / ath_hal / ar5416 / ar5416_radar.c
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  * $FreeBSD$
19  */
20 #include "opt_ah.h"
21
22 #include "ah.h"
23 #include "ah_internal.h"
24 #include "ah_devid.h"
25 #include "ah_desc.h"                    /* NB: for HAL_PHYERR* */
26
27 #include "ar5416/ar5416.h"
28 #include "ar5416/ar5416reg.h"
29 #include "ar5416/ar5416phy.h"
30
31 #include "ah_eeprom_v14.h"      /* for owl_get_ntxchains() */
32
33 /*
34  * These are default parameters for the AR5416 and
35  * later 802.11n NICs.  They simply enable some
36  * radar pulse event generation.
37  *
38  * These are very likely not valid for the AR5212 era
39  * NICs.
40  *
41  * Since these define signal sizing and threshold
42  * parameters, they may need changing based on the
43  * specific antenna and receive amplifier
44  * configuration.
45  */
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
54
55 HAL_BOOL
56 ar5416GetDfsDefaultThresh(struct ath_hal *ah, HAL_PHYERR_PARAM *pe)
57 {
58
59         /*
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.
65          */
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;
74
75         return (AH_TRUE);
76 }
77
78 /*
79  * Get the radar parameter values and return them in the pe
80  * structure
81  */
82 void
83 ar5416GetDfsThresh(struct ath_hal *ah, HAL_PHYERR_PARAM *pe)
84 {
85         uint32_t val, temp;
86
87         val = OS_REG_READ(ah, AR_PHY_RADAR_0);
88
89         temp = MS(val,AR_PHY_RADAR_0_FIRPWR);
90         temp |= 0xFFFFFF80;
91         pe->pe_firpwr = temp;
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);
96
97         /* RADAR_1 values */
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);
102
103         pe->pe_extchannel = !! (OS_REG_READ(ah, AR_PHY_RADAR_EXT) &
104             AR_PHY_RADAR_EXT_ENA);
105
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);
112         pe->pe_enabled = !!
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);
118 }
119
120 /*
121  * Enable radar detection and set the radar parameters per the
122  * values in pe
123  */
124 void
125 ar5416EnableDfs(struct ath_hal *ah, HAL_PHYERR_PARAM *pe)
126 {
127         uint32_t val;
128
129         val = OS_REG_READ(ah, AR_PHY_RADAR_0);
130
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);
134         }
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);
138         }
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);
142         }
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);
146         }
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);
150         }
151
152         /*Enable FFT data*/
153         val |= AR_PHY_RADAR_0_FFT_ENA;
154         OS_REG_WRITE(ah, AR_PHY_RADAR_0, val);
155
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);
161
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);
166
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);
171
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);
176
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);
182         }
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);
188         }
189
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);
196
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);
203
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);
209         }
210
211         /*
212          * Enable HT/40 if the upper layer asks;
213          * it should check the channel is HT/40 and HAL_CAP_EXT_CHAN_DFS
214          * is available.
215          */
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);
220 }
221
222 /*
223  * Extract the radar event information from the given phy error.
224  *
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.
227  */
228
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
233
234 HAL_BOOL
235 ar5416ProcessRadarEvent(struct ath_hal *ah, struct ath_rx_status *rxs,
236     uint64_t fulltsf, const char *buf, HAL_DFS_EVENT *event)
237 {
238         HAL_BOOL doDfsExtCh;
239         HAL_BOOL doDfsEnhanced;
240         HAL_BOOL doDfsCombinedRssi;
241
242         uint8_t rssi = 0, ext_rssi = 0;
243         uint8_t pulse_bw_info = 0, pulse_length_ext = 0, pulse_length_pri = 0;
244         uint32_t dur = 0;
245         int pri_found = 1, ext_found = 0;
246         int early_ext = 0;
247         int is_dc = 0;
248         uint16_t datalen;               /* length from the RX status field */
249
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)) {
253                 return AH_FALSE;
254         }
255
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;
260
261         datalen = rxs->rs_datalen;
262
263         /* If hardware supports it, use combined RSSI, else use chain 0 RSSI */
264         if (doDfsCombinedRssi)
265                 rssi = (uint8_t) rxs->rs_rssi;
266         else            
267                 rssi = (uint8_t) rxs->rs_rssi_ctl[0];
268
269         /* Set this; but only use it if doDfsExtCh is set */
270         ext_rssi = (uint8_t) rxs->rs_rssi_ext[0];
271
272         /* Cap it at 0 if the RSSI is a negative number */
273         if (rssi & 0x80)
274                 rssi = 0;
275
276         if (ext_rssi & 0x80)
277                 ext_rssi = 0;
278
279         /*
280          * Fetch the relevant data from the frame
281          */
282         if (doDfsExtCh) {
283                 if (datalen < 3)
284                         return AH_FALSE;
285
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,
293                     pulse_bw_info);
294         } else {
295                 /* The pulse width is byte 0 of the data */
296                 if (datalen >= 1)
297                         dur = ((uint8_t) buf[0]) & 0xff;
298                 else
299                         dur = 0;
300
301                 if (dur == 0 && rssi == 0) {
302                         HALDEBUG(ah, HAL_DEBUG_DFS, "%s: dur and rssi are 0\n", __func__);
303                         return AH_FALSE;
304                 }
305
306                 HALDEBUG(ah, HAL_DEBUG_DFS, "%s: rssi=%d, dur=%d\n", __func__, rssi, dur);
307
308                 /* Single-channel only */
309                 pri_found = 1;
310                 ext_found = 0;
311         }
312
313         /*
314          * If doing extended channel data, pulse_bw_info must
315          * have one of the flags set.
316          */
317         if (doDfsExtCh && pulse_bw_info == 0x0)
318                 return AH_FALSE;
319                 
320         /*
321          * If the extended channel data is available, calculate
322          * which to pay attention to.
323          */
324         if (doDfsExtCh) {
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)) {
328                         is_dc = 1;
329                         if (pulse_length_ext > pulse_length_pri) {
330                                 dur = pulse_length_ext;
331                                 pri_found = 0;
332                                 ext_found = 1;
333                         } else {
334                                 dur = pulse_length_pri;
335                                 pri_found = 1;
336                                 ext_found = 0;
337                         }
338                 } else if (pulse_bw_info & EXT_CH_RADAR_EARLY_FOUND) {
339                         dur = pulse_length_ext;
340                         pri_found = 0;
341                         ext_found = 1;
342                         early_ext = 1;
343                 } else if (pulse_bw_info & PRI_CH_RADAR_FOUND) {
344                         dur = pulse_length_pri;
345                         pri_found = 1;
346                         ext_found = 0;
347                 } else if (pulse_bw_info & EXT_CH_RADAR_FOUND) {
348                         dur = pulse_length_ext;
349                         pri_found = 0;
350                         ext_found = 1;
351                 }
352                 
353         }
354
355         /*
356          * For enhanced DFS (Merlin and later), pulse_bw_info has
357          * implications for selecting the correct RSSI value.
358          */
359         if (doDfsEnhanced) {
360                 switch (pulse_bw_info & 0x03) {
361                 case 0:
362                         /* No radar? */
363                         rssi = 0;
364                         break;
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)) {
369                                 rssi = 0;
370                         }
371                         break;
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)) {
376                                 rssi = 0;
377                         } else {
378                                 rssi = ext_rssi;
379                         }
380                         break;
381                 case (PRI_CH_RADAR_FOUND | EXT_CH_RADAR_FOUND):
382                         /* When both are present, use stronger one */
383                         if (rssi < ext_rssi)
384                                 rssi = ext_rssi;
385                         break;
386                 }
387         }
388
389         /*
390          * If not doing enhanced DFS, choose the ext channel if
391          * it is stronger than the main channel
392          */
393         if (doDfsExtCh && !doDfsEnhanced) {
394                 if ((ext_rssi > rssi) && (ext_rssi < 128))
395                         rssi = ext_rssi;
396         }
397
398         /*
399          * XXX what happens if the above code decides the RSSI
400          * XXX wasn't valid, an sets it to 0?
401          */
402
403         /*
404          * Fill out dfs_event structure.
405          */
406         event->re_full_ts = fulltsf;
407         event->re_ts = rxs->rs_tstamp;
408         event->re_rssi = rssi;
409         event->re_dur = dur;
410
411         event->re_flags = 0;
412         if (pri_found)
413                 event->re_flags |= HAL_DFS_EVENT_PRICH;
414         if (ext_found)
415                 event->re_flags |= HAL_DFS_EVENT_EXTCH;
416         if (early_ext)
417                 event->re_flags |= HAL_DFS_EVENT_EXTEARLY;
418         if (is_dc)
419                 event->re_flags |= HAL_DFS_EVENT_ISDC;
420
421         return AH_TRUE;
422 }
423
424 /*
425  * Return whether fast-clock is currently enabled for this
426  * channel.
427  */
428 HAL_BOOL
429 ar5416IsFastClockEnabled(struct ath_hal *ah)
430 {
431         struct ath_hal_private *ahp = AH_PRIVATE(ah);
432
433         return IS_5GHZ_FAST_CLOCK_EN(ah, ahp->ah_curchan);
434 }