The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/ath/ath_hal/ar5416/ar5416_radar.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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 }

Cache object: 3c37ddd84b471f9d7f5025ee022cf883


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.