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_misc.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) 2002-2008 Sam Leffler, Errno Consulting
    5  * Copyright (c) 2002-2008 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  * $FreeBSD$
   20  */
   21 #include "opt_ah.h"
   22 
   23 #include "ah.h"
   24 #include "ah_internal.h"
   25 #include "ah_devid.h"
   26 #include "ah_desc.h"                    /* NB: for HAL_PHYERR* */
   27 
   28 #include "ar5416/ar5416.h"
   29 #include "ar5416/ar5416reg.h"
   30 #include "ar5416/ar5416phy.h"
   31 
   32 #include "ah_eeprom_v14.h"      /* for owl_get_ntxchains() */
   33 
   34 /*
   35  * Return the wireless modes (a,b,g,n,t) supported by hardware.
   36  *
   37  * This value is what is actually supported by the hardware
   38  * and is unaffected by regulatory/country code settings.
   39  *
   40  */
   41 u_int
   42 ar5416GetWirelessModes(struct ath_hal *ah)
   43 {
   44         u_int mode;
   45         struct ath_hal_private *ahpriv = AH_PRIVATE(ah);
   46         HAL_CAPABILITIES *pCap = &ahpriv->ah_caps;
   47 
   48         mode = ar5212GetWirelessModes(ah);
   49 
   50         /* Only enable HT modes if the NIC supports HT */
   51         if (pCap->halHTSupport == AH_TRUE && (mode & HAL_MODE_11A))
   52                 mode |= HAL_MODE_11NA_HT20
   53                      |  HAL_MODE_11NA_HT40PLUS
   54                      |  HAL_MODE_11NA_HT40MINUS
   55                      ;
   56         if (pCap->halHTSupport == AH_TRUE && (mode & HAL_MODE_11G))
   57                 mode |= HAL_MODE_11NG_HT20
   58                      |  HAL_MODE_11NG_HT40PLUS
   59                      |  HAL_MODE_11NG_HT40MINUS
   60                      ;
   61         return mode;
   62 }
   63 
   64 /*
   65  * Change the LED blinking pattern to correspond to the connectivity
   66  */
   67 void
   68 ar5416SetLedState(struct ath_hal *ah, HAL_LED_STATE state)
   69 {
   70         static const uint32_t ledbits[8] = {
   71                 AR_MAC_LED_ASSOC_NONE,          /* HAL_LED_INIT */
   72                 AR_MAC_LED_ASSOC_PEND,          /* HAL_LED_SCAN */
   73                 AR_MAC_LED_ASSOC_PEND,          /* HAL_LED_AUTH */
   74                 AR_MAC_LED_ASSOC_ACTIVE,        /* HAL_LED_ASSOC*/
   75                 AR_MAC_LED_ASSOC_ACTIVE,        /* HAL_LED_RUN */
   76                 AR_MAC_LED_ASSOC_NONE,
   77                 AR_MAC_LED_ASSOC_NONE,
   78                 AR_MAC_LED_ASSOC_NONE,
   79         };
   80 
   81         if (AR_SREV_HOWL(ah))
   82                 return;
   83 
   84         /*
   85          * Set the blink operating mode.
   86          */
   87         OS_REG_RMW_FIELD(ah, AR_MAC_LED,
   88             AR_MAC_LED_ASSOC, ledbits[state & 0x7]);
   89 
   90         /* XXX Blink slow mode? */
   91         /* XXX Blink threshold? */
   92         /* XXX Blink sleep hystersis? */
   93 
   94         /*
   95          * Set the LED blink configuration to be proportional
   96          * to the current TX and RX filter bytes.  (Ie, RX'ed
   97          * frames that don't match the filter are ignored.)
   98          * This means that higher TX/RX throughput will result
   99          * in the blink rate increasing.
  100          */
  101         OS_REG_RMW_FIELD(ah, AR_MAC_LED, AR_MAC_LED_MODE,
  102             AR_MAC_LED_MODE_PROP);
  103 }
  104 
  105 /*
  106  * Get the current hardware tsf for stamlme
  107  */
  108 uint64_t
  109 ar5416GetTsf64(struct ath_hal *ah)
  110 {
  111         uint32_t low1, low2, u32;
  112 
  113         /* sync multi-word read */
  114         low1 = OS_REG_READ(ah, AR_TSF_L32);
  115         u32 = OS_REG_READ(ah, AR_TSF_U32);
  116         low2 = OS_REG_READ(ah, AR_TSF_L32);
  117         if (low2 < low1) {      /* roll over */
  118                 /*
  119                  * If we are not preempted this will work.  If we are
  120                  * then we re-reading AR_TSF_U32 does no good as the
  121                  * low bits will be meaningless.  Likewise reading
  122                  * L32, U32, U32, then comparing the last two reads
  123                  * to check for rollover doesn't help if preempted--so
  124                  * we take this approach as it costs one less PCI read
  125                  * which can be noticeable when doing things like
  126                  * timestamping packets in monitor mode.
  127                  */
  128                 u32++;
  129         }
  130         return (((uint64_t) u32) << 32) | ((uint64_t) low2);
  131 }
  132 
  133 /*
  134  * Update the TSF.
  135  *
  136  * The full TSF is only updated once the upper 32 bits have
  137  * been written.  Writing only the lower 32 bits of the TSF
  138  * will not actually correctly update the TSF.
  139  *
  140  * The #if 0'ed code is to check whether the previous TSF
  141  * reset or write has completed before writing to the
  142  * TSF.  Strictly speaking, it should be also checked before
  143  * reading the TSF as the write/reset may not have completed.
  144  */
  145 void
  146 ar5416SetTsf64(struct ath_hal *ah, uint64_t tsf64)
  147 {
  148         /* XXX check if this is correct! */
  149 #if 0
  150         int i;
  151         uint32_t v;
  152 
  153         for (i = 0; i < 10; i++) {
  154                 v = OS_REG_READ(ah, AR_SLP32_MODE);
  155                 if ((v & AR_SLP32_TSF_WRITE_STATUS) == 0)
  156                         break;
  157                 OS_DELAY(10);
  158         }
  159         if (i == 10)
  160                 ath_hal_printf(ah, "%s: couldn't slew things right!\n", __func__);
  161 #endif
  162 
  163         OS_REG_WRITE(ah, AR_TSF_L32, tsf64 & 0xffffffff);
  164         OS_REG_WRITE(ah, AR_TSF_U32, (tsf64 >> 32) & 0xffffffff);
  165 }
  166 
  167 /*
  168  * Reset the current hardware tsf for stamlme.
  169  */
  170 void
  171 ar5416ResetTsf(struct ath_hal *ah)
  172 {
  173         uint32_t v;
  174         int i;
  175 
  176         for (i = 0; i < 10; i++) {
  177                 v = OS_REG_READ(ah, AR_SLP32_MODE);
  178                 if ((v & AR_SLP32_TSF_WRITE_STATUS) == 0)
  179                         break;
  180                 OS_DELAY(10);
  181         }
  182         OS_REG_WRITE(ah, AR_RESET_TSF, AR_RESET_TSF_ONCE);      
  183 }
  184 
  185 uint32_t
  186 ar5416GetCurRssi(struct ath_hal *ah)
  187 {
  188         if (AR_SREV_OWL(ah))
  189                 return (OS_REG_READ(ah, AR_PHY_CURRENT_RSSI) & 0xff);
  190         return (OS_REG_READ(ah, AR9130_PHY_CURRENT_RSSI) & 0xff);
  191 }
  192 
  193 HAL_BOOL
  194 ar5416SetAntennaSwitch(struct ath_hal *ah, HAL_ANT_SETTING settings)
  195 {
  196         return AH_TRUE;
  197 }
  198 
  199 /* Setup decompression for given key index */
  200 HAL_BOOL
  201 ar5416SetDecompMask(struct ath_hal *ah, uint16_t keyidx, int en)
  202 {
  203         return AH_TRUE;
  204 }
  205 
  206 /* Setup coverage class */
  207 void
  208 ar5416SetCoverageClass(struct ath_hal *ah, uint8_t coverageclass, int now)
  209 {
  210 
  211         ar5212SetCoverageClass(ah, coverageclass, now);
  212 }
  213 
  214 /*
  215  * Return the busy for rx_frame, rx_clear, and tx_frame
  216  */
  217 HAL_BOOL
  218 ar5416GetMibCycleCounts(struct ath_hal *ah, HAL_SURVEY_SAMPLE *hsample)
  219 {
  220         struct ath_hal_5416 *ahp = AH5416(ah);
  221         u_int32_t good = AH_TRUE;
  222 
  223         /* XXX freeze/unfreeze mib counters */
  224         uint32_t rc = OS_REG_READ(ah, AR_RCCNT);
  225         uint32_t ec = OS_REG_READ(ah, AR_EXTRCCNT);
  226         uint32_t rf = OS_REG_READ(ah, AR_RFCNT);
  227         uint32_t tf = OS_REG_READ(ah, AR_TFCNT);
  228         uint32_t cc = OS_REG_READ(ah, AR_CCCNT); /* read cycles last */
  229 
  230         if (ahp->ah_cycleCount == 0 || ahp->ah_cycleCount > cc) {
  231                 /*
  232                  * Cycle counter wrap (or initial call); it's not possible
  233                  * to accurately calculate a value because the registers
  234                  * right shift rather than wrap--so punt and return 0.
  235                  */
  236                 HALDEBUG(ah, HAL_DEBUG_ANY,
  237                             "%s: cycle counter wrap. ExtBusy = 0\n", __func__);
  238                         good = AH_FALSE;
  239         } else {
  240                 hsample->cycle_count = cc - ahp->ah_cycleCount;
  241                 hsample->chan_busy = rc - ahp->ah_ctlBusy;
  242                 hsample->ext_chan_busy = ec - ahp->ah_extBusy;
  243                 hsample->rx_busy = rf - ahp->ah_rxBusy;
  244                 hsample->tx_busy = tf - ahp->ah_txBusy;
  245         }
  246 
  247         /*
  248          * Keep a copy of the MIB results so the next sample has something
  249          * to work from.
  250          */
  251         ahp->ah_cycleCount = cc;
  252         ahp->ah_rxBusy = rf;
  253         ahp->ah_ctlBusy = rc;
  254         ahp->ah_txBusy = tf;
  255         ahp->ah_extBusy = ec;
  256 
  257         return (good);
  258 }
  259 
  260 /*
  261  * Setup the TX/RX chainmasks - this needs to be done before a call
  262  * to the reset method as it doesn't update the hardware.
  263  */
  264 void
  265 ar5416SetChainMasks(struct ath_hal *ah, uint32_t tx_chainmask,
  266     uint32_t rx_chainmask)
  267 {
  268         HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps;
  269 
  270         AH5416(ah)->ah_tx_chainmask = tx_chainmask & pCap->halTxChainMask;
  271         AH5416(ah)->ah_rx_chainmask = rx_chainmask & pCap->halRxChainMask;
  272 }
  273 
  274 /*
  275  * Return approximation of extension channel busy over an time interval
  276  * 0% (clear) -> 100% (busy)
  277  *
  278  * XXX TODO: update this to correctly sample all the counters,
  279  *           rather than a subset of it.
  280  */
  281 uint32_t
  282 ar5416Get11nExtBusy(struct ath_hal *ah)
  283 {
  284     struct ath_hal_5416 *ahp = AH5416(ah);
  285     uint32_t busy; /* percentage */
  286     uint32_t cycleCount, ctlBusy, extBusy;
  287 
  288     ctlBusy = OS_REG_READ(ah, AR_RCCNT);
  289     extBusy = OS_REG_READ(ah, AR_EXTRCCNT);
  290     cycleCount = OS_REG_READ(ah, AR_CCCNT);
  291 
  292     if (ahp->ah_cycleCount == 0 || ahp->ah_cycleCount > cycleCount) {
  293         /*
  294          * Cycle counter wrap (or initial call); it's not possible
  295          * to accurately calculate a value because the registers
  296          * right shift rather than wrap--so punt and return 0.
  297          */
  298         busy = 0;
  299         HALDEBUG(ah, HAL_DEBUG_ANY, "%s: cycle counter wrap. ExtBusy = 0\n",
  300             __func__);
  301 
  302     } else {
  303         uint32_t cycleDelta = cycleCount - ahp->ah_cycleCount;
  304         uint32_t ctlBusyDelta = ctlBusy - ahp->ah_ctlBusy;
  305         uint32_t extBusyDelta = extBusy - ahp->ah_extBusy;
  306         uint32_t ctlClearDelta = 0;
  307 
  308         /* Compute control channel rxclear.
  309          * The cycle delta may be less than the control channel delta.
  310          * This could be solved by freezing the timers (or an atomic read,
  311          * if one was available). Checking for the condition should be
  312          * sufficient.
  313          */
  314         if (cycleDelta > ctlBusyDelta) {
  315             ctlClearDelta = cycleDelta - ctlBusyDelta;
  316         }
  317 
  318         /* Compute ratio of extension channel busy to control channel clear
  319          * as an approximation to extension channel cleanliness.
  320          *
  321          * According to the hardware folks, ext rxclear is undefined
  322          * if the ctrl rxclear is de-asserted (i.e. busy)
  323          */
  324         if (ctlClearDelta) {
  325             busy = (extBusyDelta * 100) / ctlClearDelta;
  326         } else {
  327             busy = 100;
  328         }
  329         if (busy > 100) {
  330             busy = 100;
  331         }
  332 #if 0
  333         HALDEBUG(ah, HAL_DEBUG_ANY, "%s: cycleDelta 0x%x, ctlBusyDelta 0x%x, "
  334              "extBusyDelta 0x%x, ctlClearDelta 0x%x, "
  335              "busy %d\n",
  336               __func__, cycleDelta, ctlBusyDelta, extBusyDelta, ctlClearDelta, busy);
  337 #endif
  338     }
  339 
  340     ahp->ah_cycleCount = cycleCount;
  341     ahp->ah_ctlBusy = ctlBusy;
  342     ahp->ah_extBusy = extBusy;
  343 
  344     return busy;
  345 }
  346 
  347 /*
  348  * Configure 20/40 operation
  349  *
  350  * 20/40 = joint rx clear (control and extension)
  351  * 20    = rx clear (control)
  352  *
  353  * - NOTE: must stop MAC (tx) and requeue 40 MHz packets as 20 MHz when changing
  354  *         from 20/40 => 20 only
  355  */
  356 void
  357 ar5416Set11nMac2040(struct ath_hal *ah, HAL_HT_MACMODE mode)
  358 {
  359     uint32_t macmode;
  360 
  361     /* Configure MAC for 20/40 operation */
  362     if (mode == HAL_HT_MACMODE_2040) {
  363         macmode = AR_2040_JOINED_RX_CLEAR;
  364     } else {
  365         macmode = 0;
  366     }
  367     OS_REG_WRITE(ah, AR_2040_MODE, macmode);
  368 }
  369 
  370 /*
  371  * Get Rx clear (control/extension channel)
  372  *
  373  * Returns active low (busy) for ctrl/ext channel
  374  * Owl 2.0
  375  */
  376 HAL_HT_RXCLEAR
  377 ar5416Get11nRxClear(struct ath_hal *ah)
  378 {
  379     HAL_HT_RXCLEAR rxclear = 0;
  380     uint32_t val;
  381 
  382     val = OS_REG_READ(ah, AR_DIAG_SW);
  383 
  384     /* control channel */
  385     if (val & AR_DIAG_RXCLEAR_CTL_LOW) {
  386         rxclear |= HAL_RX_CLEAR_CTL_LOW;
  387     }
  388     /* extension channel */
  389     if (val & AR_DIAG_RXCLEAR_EXT_LOW) {
  390         rxclear |= HAL_RX_CLEAR_EXT_LOW;
  391     }
  392     return rxclear;
  393 }
  394 
  395 /*
  396  * Set Rx clear (control/extension channel)
  397  *
  398  * Useful for forcing the channel to appear busy for
  399  * debugging/diagnostics
  400  * Owl 2.0
  401  */
  402 void
  403 ar5416Set11nRxClear(struct ath_hal *ah, HAL_HT_RXCLEAR rxclear)
  404 {
  405     /* control channel */
  406     if (rxclear & HAL_RX_CLEAR_CTL_LOW) {
  407         OS_REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RXCLEAR_CTL_LOW);
  408     } else {
  409         OS_REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_RXCLEAR_CTL_LOW);
  410     }
  411     /* extension channel */
  412     if (rxclear & HAL_RX_CLEAR_EXT_LOW) {
  413         OS_REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RXCLEAR_EXT_LOW);
  414     } else {
  415         OS_REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_RXCLEAR_EXT_LOW);
  416     }
  417 }
  418 
  419 /* XXX shouldn't be here! */
  420 #define TU_TO_USEC(_tu)         ((_tu) << 10)
  421 
  422 HAL_STATUS
  423 ar5416SetQuiet(struct ath_hal *ah, uint32_t period, uint32_t duration,
  424     uint32_t nextStart, HAL_QUIET_FLAG flag)
  425 {
  426         uint32_t period_us = TU_TO_USEC(period); /* convert to us unit */
  427         uint32_t nextStart_us = TU_TO_USEC(nextStart); /* convert to us unit */
  428         if (flag & HAL_QUIET_ENABLE) {
  429                 if ((!nextStart) || (flag & HAL_QUIET_ADD_CURRENT_TSF)) {
  430                         /* Add the nextStart offset to the current TSF */
  431                         nextStart_us += OS_REG_READ(ah, AR_TSF_L32);
  432                 }
  433                 if (flag & HAL_QUIET_ADD_SWBA_RESP_TIME) {
  434                         nextStart_us += ah->ah_config.ah_sw_beacon_response_time;
  435                 }
  436                 OS_REG_RMW_FIELD(ah, AR_QUIET1, AR_QUIET1_QUIET_ACK_CTS_ENABLE, 1);
  437                 OS_REG_WRITE(ah, AR_QUIET2, SM(duration, AR_QUIET2_QUIET_DUR));
  438                 OS_REG_WRITE(ah, AR_QUIET_PERIOD, period_us);
  439                 OS_REG_WRITE(ah, AR_NEXT_QUIET, nextStart_us);
  440                 OS_REG_SET_BIT(ah, AR_TIMER_MODE, AR_TIMER_MODE_QUIET);
  441         } else {
  442                 OS_REG_CLR_BIT(ah, AR_TIMER_MODE, AR_TIMER_MODE_QUIET);
  443         }
  444         return HAL_OK;
  445 }
  446 #undef  TU_TO_USEC
  447 
  448 HAL_STATUS
  449 ar5416GetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type,
  450         uint32_t capability, uint32_t *result)
  451 {
  452         switch (type) {
  453         case HAL_CAP_BB_HANG:
  454                 switch (capability) {
  455                 case HAL_BB_HANG_RIFS:
  456                         return (AR_SREV_HOWL(ah) || AR_SREV_SOWL(ah)) ? HAL_OK : HAL_ENOTSUPP;
  457                 case HAL_BB_HANG_DFS:
  458                         return (AR_SREV_HOWL(ah) || AR_SREV_SOWL(ah)) ? HAL_OK : HAL_ENOTSUPP;
  459                 case HAL_BB_HANG_RX_CLEAR:
  460                         return AR_SREV_MERLIN(ah) ? HAL_OK : HAL_ENOTSUPP;
  461                 }
  462                 break;
  463         case HAL_CAP_MAC_HANG:
  464                 return ((ah->ah_macVersion == AR_XSREV_VERSION_OWL_PCI) ||
  465                     (ah->ah_macVersion == AR_XSREV_VERSION_OWL_PCIE) ||
  466                     AR_SREV_HOWL(ah) || AR_SREV_SOWL(ah)) ?
  467                         HAL_OK : HAL_ENOTSUPP;
  468         case HAL_CAP_DIVERSITY:         /* disable classic fast diversity */
  469                 return HAL_ENXIO;
  470         case HAL_CAP_ENFORCE_TXOP:
  471                 if (capability == 0)
  472                         return (HAL_OK);
  473                 if (capability != 1)
  474                         return (HAL_ENOTSUPP);
  475                 (*result) =
  476                     !! (AH5212(ah)->ah_miscMode & AR_PCU_TXOP_TBTT_LIMIT_ENA);
  477                 return (HAL_OK);
  478         default:
  479                 break;
  480         }
  481         return ar5212GetCapability(ah, type, capability, result);
  482 }
  483 
  484 HAL_BOOL
  485 ar5416SetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type,
  486     u_int32_t capability, u_int32_t setting, HAL_STATUS *status)
  487 {
  488         HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps;
  489 
  490         switch (type) {
  491         case HAL_CAP_RX_CHAINMASK:
  492                 setting &= ath_hal_eepromGet(ah, AR_EEP_RXMASK, NULL);
  493                 pCap->halRxChainMask = setting;
  494                 if (owl_get_ntxchains(setting) > 2)
  495                         pCap->halRxStreams = 2;
  496                 else
  497                         pCap->halRxStreams = 1;
  498                 return AH_TRUE;
  499         case HAL_CAP_TX_CHAINMASK:
  500                 setting &= ath_hal_eepromGet(ah, AR_EEP_TXMASK, NULL);
  501                 pCap->halTxChainMask = setting;
  502                 if (owl_get_ntxchains(setting) > 2)
  503                         pCap->halTxStreams = 2;
  504                 else
  505                         pCap->halTxStreams = 1;
  506                 return AH_TRUE;
  507         case HAL_CAP_ENFORCE_TXOP:
  508                 if (capability != 1)
  509                         return AH_FALSE;
  510                 if (setting) {
  511                         AH5212(ah)->ah_miscMode
  512                             |= AR_PCU_TXOP_TBTT_LIMIT_ENA;
  513                         OS_REG_SET_BIT(ah, AR_MISC_MODE,
  514                             AR_PCU_TXOP_TBTT_LIMIT_ENA);
  515                 } else {
  516                         AH5212(ah)->ah_miscMode
  517                             &= ~AR_PCU_TXOP_TBTT_LIMIT_ENA;
  518                         OS_REG_CLR_BIT(ah, AR_MISC_MODE,
  519                             AR_PCU_TXOP_TBTT_LIMIT_ENA);
  520                 }
  521                 return AH_TRUE;
  522         default:
  523                 break;
  524         }
  525         return ar5212SetCapability(ah, type, capability, setting, status);
  526 }
  527 
  528 static int ar5416DetectMacHang(struct ath_hal *ah);
  529 static int ar5416DetectBBHang(struct ath_hal *ah);
  530 
  531 HAL_BOOL
  532 ar5416GetDiagState(struct ath_hal *ah, int request,
  533         const void *args, uint32_t argsize,
  534         void **result, uint32_t *resultsize)
  535 {
  536         struct ath_hal_5416 *ahp = AH5416(ah);
  537         int hangs;
  538 
  539         if (ath_hal_getdiagstate(ah, request, args, argsize, result, resultsize))
  540                 return AH_TRUE;
  541         switch (request) {
  542         case HAL_DIAG_EEPROM:
  543                 return ath_hal_eepromDiag(ah, request,
  544                     args, argsize, result, resultsize);
  545         case HAL_DIAG_CHECK_HANGS:
  546                 if (argsize != sizeof(int))
  547                         return AH_FALSE;
  548                 hangs = *(const int *) args;
  549                 ahp->ah_hangs = 0;
  550                 if (hangs & HAL_BB_HANGS)
  551                         ahp->ah_hangs |= ar5416DetectBBHang(ah);
  552                 /* NB: if BB is hung MAC will be hung too so skip check */
  553                 if (ahp->ah_hangs == 0 && (hangs & HAL_MAC_HANGS))
  554                         ahp->ah_hangs |= ar5416DetectMacHang(ah);
  555                 *result = &ahp->ah_hangs;
  556                 *resultsize = sizeof(ahp->ah_hangs);
  557                 return AH_TRUE;
  558         }
  559         return ar5212GetDiagState(ah, request,
  560             args, argsize, result, resultsize);
  561 }
  562 
  563 HAL_BOOL
  564 ar5416SetRifsDelay(struct ath_hal *ah, const struct ieee80211_channel *chan,
  565     HAL_BOOL enable)
  566 {
  567         uint32_t val;
  568         HAL_BOOL is_chan_2g = AH_FALSE;
  569         HAL_BOOL is_ht40 = AH_FALSE;
  570 
  571         if (chan)
  572                 is_chan_2g = IEEE80211_IS_CHAN_2GHZ(chan);
  573 
  574         if (chan)
  575                 is_ht40 = IEEE80211_IS_CHAN_HT40(chan);
  576 
  577         /* Only support disabling RIFS delay for now */
  578         HALASSERT(enable == AH_FALSE);
  579 
  580         if (enable == AH_TRUE)
  581                 return AH_FALSE;
  582 
  583         /* Change RIFS init delay to 0 */
  584         val = OS_REG_READ(ah, AR_PHY_HEAVY_CLIP_FACTOR_RIFS);
  585         val &= ~AR_PHY_RIFS_INIT_DELAY;
  586         OS_REG_WRITE(ah, AR_PHY_HEAVY_CLIP_FACTOR_RIFS, val);
  587 
  588         /*
  589          * For Owl, RIFS RX parameters are controlled differently;
  590          * it isn't enabled in the inivals by default.
  591          *
  592          * For Sowl/Howl, RIFS RX is enabled in the inivals by default;
  593          * the following code sets them back to non-RIFS values.
  594          *
  595          * For > Sowl/Howl, RIFS RX can be left on by default and so
  596          * this function shouldn't be called.
  597          */
  598         if ((! AR_SREV_SOWL(ah)) && (! AR_SREV_HOWL(ah)))
  599                 return AH_TRUE;
  600 
  601         /* Reset search delay to default values */
  602         if (is_chan_2g)
  603                 if (is_ht40)
  604                         OS_REG_WRITE(ah, AR_PHY_SEARCH_START_DELAY, 0x268);
  605                 else
  606                         OS_REG_WRITE(ah, AR_PHY_SEARCH_START_DELAY, 0x134);
  607         else
  608                 if (is_ht40)
  609                         OS_REG_WRITE(ah, AR_PHY_SEARCH_START_DELAY, 0x370);
  610                 else
  611                         OS_REG_WRITE(ah, AR_PHY_SEARCH_START_DELAY, 0x1b8);
  612 
  613         return AH_TRUE;
  614 }
  615 
  616 static HAL_BOOL
  617 ar5416CompareDbgHang(struct ath_hal *ah, const mac_dbg_regs_t *regs,
  618     const hal_mac_hang_check_t *check)
  619 {
  620         int found_states;
  621 
  622         found_states = 0;
  623         if (check->states & dcu_chain_state) {
  624                 int i;
  625 
  626                 for (i = 0; i < 6; i++) {
  627                         if (((regs->dma_dbg_4 >> (5*i)) & 0x1f) ==
  628                             check->dcu_chain_state)
  629                                 found_states |= dcu_chain_state;
  630                 }
  631                 for (i = 0; i < 4; i++) {
  632                         if (((regs->dma_dbg_5 >> (5*i)) & 0x1f) ==
  633                             check->dcu_chain_state)
  634                                 found_states |= dcu_chain_state;
  635                 }
  636         }
  637         if (check->states & dcu_complete_state) { 
  638                 if ((regs->dma_dbg_6 & 0x3) == check->dcu_complete_state)
  639                         found_states |= dcu_complete_state;
  640         }
  641         if (check->states & qcu_stitch_state) { 
  642                 if (((regs->dma_dbg_3 >> 18) & 0xf) == check->qcu_stitch_state)
  643                         found_states |= qcu_stitch_state;
  644         }
  645         if (check->states & qcu_fetch_state) { 
  646                 if (((regs->dma_dbg_3 >> 22) & 0xf) == check->qcu_fetch_state)
  647                         found_states |= qcu_fetch_state;
  648         }
  649         if (check->states & qcu_complete_state) { 
  650                 if (((regs->dma_dbg_3 >> 26) & 0x7) == check->qcu_complete_state)
  651                         found_states |= qcu_complete_state;
  652         }
  653         return (found_states == check->states);
  654 }
  655 
  656 #define NUM_STATUS_READS 50
  657 
  658 static int
  659 ar5416DetectMacHang(struct ath_hal *ah)
  660 {
  661         static const hal_mac_hang_check_t hang_sig1 = {
  662                 .dcu_chain_state        = 0x6,
  663                 .dcu_complete_state     = 0x1,
  664                 .states                 = dcu_chain_state
  665                                         | dcu_complete_state,
  666         };
  667         static const hal_mac_hang_check_t hang_sig2 = {
  668                 .qcu_stitch_state       = 0x9,
  669                 .qcu_fetch_state        = 0x8,
  670                 .qcu_complete_state     = 0x4,
  671                 .states                 = qcu_stitch_state
  672                                         | qcu_fetch_state
  673                                         | qcu_complete_state,
  674         };
  675         mac_dbg_regs_t mac_dbg;
  676         int i;
  677 
  678         mac_dbg.dma_dbg_3 = OS_REG_READ(ah, AR_DMADBG_3);
  679         mac_dbg.dma_dbg_4 = OS_REG_READ(ah, AR_DMADBG_4);
  680         mac_dbg.dma_dbg_5 = OS_REG_READ(ah, AR_DMADBG_5);
  681         mac_dbg.dma_dbg_6 = OS_REG_READ(ah, AR_DMADBG_6);
  682         for (i = 1; i <= NUM_STATUS_READS; i++) {
  683                 if (mac_dbg.dma_dbg_3 != OS_REG_READ(ah, AR_DMADBG_3) ||
  684                     mac_dbg.dma_dbg_4 != OS_REG_READ(ah, AR_DMADBG_4) ||
  685                     mac_dbg.dma_dbg_5 != OS_REG_READ(ah, AR_DMADBG_5) ||
  686                     mac_dbg.dma_dbg_6 != OS_REG_READ(ah, AR_DMADBG_6))
  687                         return 0;
  688         }
  689 
  690         if (ar5416CompareDbgHang(ah, &mac_dbg, &hang_sig1))
  691                 return HAL_MAC_HANG_SIG1;
  692         if (ar5416CompareDbgHang(ah, &mac_dbg, &hang_sig2))
  693                 return HAL_MAC_HANG_SIG2;
  694 
  695         HALDEBUG(ah, HAL_DEBUG_HANG, "%s Found an unknown MAC hang signature "
  696             "DMADBG_3=0x%x DMADBG_4=0x%x DMADBG_5=0x%x DMADBG_6=0x%x\n",
  697             __func__, mac_dbg.dma_dbg_3, mac_dbg.dma_dbg_4, mac_dbg.dma_dbg_5,
  698             mac_dbg.dma_dbg_6);
  699 
  700         return 0;
  701 }
  702 
  703 /*
  704  * Determine if the baseband using the Observation Bus Register
  705  */
  706 static int
  707 ar5416DetectBBHang(struct ath_hal *ah)
  708 {
  709 #define N(a) (sizeof(a)/sizeof(a[0]))
  710         /*
  711          * Check the PCU Observation Bus 1 register (0x806c)
  712          * NUM_STATUS_READS times
  713          *
  714          * 4 known BB hang signatures -
  715          * [1] bits 8,9,11 are 0. State machine state (bits 25-31) is 0x1E
  716          * [2] bits 8,9 are 1, bit 11 is 0. State machine state
  717          *     (bits 25-31) is 0x52
  718          * [3] bits 8,9 are 1, bit 11 is 0. State machine state
  719          *     (bits 25-31) is 0x18
  720          * [4] bit 10 is 1, bit 11 is 0. WEP state (bits 12-17) is 0x2,
  721          *     Rx State (bits 20-24) is 0x7.
  722          */
  723         static const struct {
  724                 uint32_t val;
  725                 uint32_t mask;
  726                 int code;
  727         } hang_list[] = {
  728                 /* Reg Value   Reg Mask    Hang Code XXX */
  729                 { 0x1E000000, 0x7E000B00, HAL_BB_HANG_DFS },
  730                 { 0x52000B00, 0x7E000B00, HAL_BB_HANG_RIFS },
  731                 { 0x18000B00, 0x7E000B00, HAL_BB_HANG_RX_CLEAR },
  732                 { 0x00702400, 0x7E7FFFEF, HAL_BB_HANG_RX_CLEAR }
  733         };
  734         uint32_t hang_sig;
  735         int i;
  736 
  737         hang_sig = OS_REG_READ(ah, AR_OBSERV_1);
  738         for (i = 1; i <= NUM_STATUS_READS; i++) {
  739                 if (hang_sig != OS_REG_READ(ah, AR_OBSERV_1))
  740                         return 0;
  741         }
  742         for (i = 0; i < N(hang_list); i++)
  743                 if ((hang_sig & hang_list[i].mask) == hang_list[i].val) {
  744                         HALDEBUG(ah, HAL_DEBUG_HANG,
  745                             "%s BB hang, signature 0x%x, code 0x%x\n",
  746                             __func__, hang_sig, hang_list[i].code);
  747                         return hang_list[i].code;
  748                 }
  749 
  750         HALDEBUG(ah, HAL_DEBUG_HANG, "%s Found an unknown BB hang signature! "
  751             "<0x806c>=0x%x\n", __func__, hang_sig);
  752 
  753         return 0;
  754 #undef N
  755 }
  756 #undef NUM_STATUS_READS

Cache object: a28bafeb75e897caa60b108ad0c5633b


[ 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.