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/ah_eeprom_v14.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) 2008 Sam Leffler, Errno Consulting
    5  * Copyright (c) 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_eeprom_v14.h"
   26 
   27 static HAL_STATUS
   28 v14EepromGet(struct ath_hal *ah, int param, void *val)
   29 {
   30 #define CHAN_A_IDX      0
   31 #define CHAN_B_IDX      1
   32 #define IS_VERS(op, v)  ((pBase->version & AR5416_EEP_VER_MINOR_MASK) op (v))
   33         HAL_EEPROM_v14 *ee = AH_PRIVATE(ah)->ah_eeprom;
   34         const MODAL_EEP_HEADER *pModal = ee->ee_base.modalHeader;
   35         const BASE_EEP_HEADER  *pBase  = &ee->ee_base.baseEepHeader;
   36         uint32_t sum;
   37         uint8_t *macaddr;
   38         int i;
   39 
   40         switch (param) {
   41         case AR_EEP_NFTHRESH_5:
   42                 *(int16_t *)val = pModal[0].noiseFloorThreshCh[0];
   43                 return HAL_OK;
   44         case AR_EEP_NFTHRESH_2:
   45                 *(int16_t *)val = pModal[1].noiseFloorThreshCh[0];
   46                 return HAL_OK;
   47         case AR_EEP_MACADDR:            /* Get MAC Address */
   48                 sum = 0;
   49                 macaddr = val;
   50                 for (i = 0; i < 6; i++) {
   51                         macaddr[i] = pBase->macAddr[i];
   52                         sum += pBase->macAddr[i];
   53                 }
   54                 if (sum == 0 || sum == 0xffff*3) {
   55                         HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad mac address %s\n",
   56                             __func__, ath_hal_ether_sprintf(macaddr));
   57                         return HAL_EEBADMAC;
   58                 }
   59                 return HAL_OK;
   60         case AR_EEP_REGDMN_0:
   61                 return pBase->regDmn[0];
   62         case AR_EEP_REGDMN_1:
   63                 return pBase->regDmn[1];
   64         case AR_EEP_OPCAP:
   65                 return pBase->deviceCap;
   66         case AR_EEP_OPMODE:
   67                 return pBase->opCapFlags;
   68         case AR_EEP_RFSILENT:
   69                 return pBase->rfSilent;
   70         case AR_EEP_OB_5:
   71                 return pModal[CHAN_A_IDX].ob;
   72         case AR_EEP_DB_5:
   73                 return pModal[CHAN_A_IDX].db;
   74         case AR_EEP_OB_2:
   75                 return pModal[CHAN_B_IDX].ob;
   76         case AR_EEP_DB_2:
   77                 return pModal[CHAN_B_IDX].db;
   78         case AR_EEP_TXMASK:
   79                 return pBase->txMask;
   80         case AR_EEP_RXMASK:
   81                 return pBase->rxMask;
   82         case AR_EEP_RXGAIN_TYPE:
   83                 return IS_VERS(>=, AR5416_EEP_MINOR_VER_17) ?
   84                     pBase->rxGainType : AR5416_EEP_RXGAIN_ORIG;
   85         case AR_EEP_TXGAIN_TYPE:
   86                 return IS_VERS(>=, AR5416_EEP_MINOR_VER_19) ?
   87                     pBase->txGainType : AR5416_EEP_TXGAIN_ORIG;
   88         case AR_EEP_FSTCLK_5G:
   89                 /* 5ghz fastclock is always enabled for Merlin minor <= 16 */
   90                 if (IS_VERS(<=, AR5416_EEP_MINOR_VER_16))
   91                         return HAL_OK;
   92                 return pBase->fastClk5g ? HAL_OK : HAL_EIO;
   93         case AR_EEP_OL_PWRCTRL:
   94                 HALASSERT(val == AH_NULL);
   95                 return pBase->openLoopPwrCntl ?  HAL_OK : HAL_EIO;
   96         case AR_EEP_DAC_HPWR_5G:
   97                 if (IS_VERS(>=, AR5416_EEP_MINOR_VER_20)) {
   98                         *(uint8_t *) val = pBase->dacHiPwrMode_5G;
   99                         return HAL_OK;
  100                 } else
  101                         return HAL_EIO;
  102         case AR_EEP_FRAC_N_5G:
  103                 if (IS_VERS(>=, AR5416_EEP_MINOR_VER_22)) {
  104                         *(uint8_t *) val = pBase->frac_n_5g;
  105                 } else
  106                         *(uint8_t *) val = 0;
  107                 return HAL_OK;
  108         case AR_EEP_AMODE:
  109                 HALASSERT(val == AH_NULL);
  110                 return pBase->opCapFlags & AR5416_OPFLAGS_11A ?
  111                     HAL_OK : HAL_EIO;
  112         case AR_EEP_BMODE:
  113         case AR_EEP_GMODE:
  114                 HALASSERT(val == AH_NULL);
  115                 return pBase->opCapFlags & AR5416_OPFLAGS_11G ?
  116                     HAL_OK : HAL_EIO;
  117         case AR_EEP_32KHZCRYSTAL:
  118         case AR_EEP_COMPRESS:
  119         case AR_EEP_FASTFRAME:          /* XXX policy decision, h/w can do it */
  120         case AR_EEP_WRITEPROTECT:       /* NB: no write protect bit */
  121                 HALASSERT(val == AH_NULL);
  122                 /* fall thru... */
  123         case AR_EEP_MAXQCU:             /* NB: not in opCapFlags */
  124         case AR_EEP_KCENTRIES:          /* NB: not in opCapFlags */
  125                 return HAL_EIO;
  126         case AR_EEP_AES:
  127         case AR_EEP_BURST:
  128         case AR_EEP_RFKILL:
  129         case AR_EEP_TURBO5DISABLE:
  130         case AR_EEP_TURBO2DISABLE:
  131                 HALASSERT(val == AH_NULL);
  132                 return HAL_OK;
  133         case AR_EEP_ANTGAINMAX_2:
  134                 *(int8_t *) val = ee->ee_antennaGainMax[1];
  135                 return HAL_OK;
  136         case AR_EEP_ANTGAINMAX_5:
  137                 *(int8_t *) val = ee->ee_antennaGainMax[0];
  138                 return HAL_OK;
  139         case AR_EEP_PWR_TABLE_OFFSET:
  140                 if (IS_VERS(>=, AR5416_EEP_MINOR_VER_21))
  141                         *(int8_t *) val = pBase->pwr_table_offset;
  142                 else
  143                         *(int8_t *) val = AR5416_PWR_TABLE_OFFSET_DB;
  144                 return HAL_OK;
  145         case AR_EEP_PWDCLKIND:
  146                 if (IS_VERS(>=, AR5416_EEP_MINOR_VER_10)) {
  147                         *(uint8_t *) val = pBase->pwdclkind;
  148                         return HAL_OK;
  149                 }
  150                 return HAL_EIO;
  151                 
  152         default:
  153                 HALASSERT(0);
  154                 return HAL_EINVAL;
  155         }
  156 #undef IS_VERS
  157 #undef CHAN_A_IDX
  158 #undef CHAN_B_IDX
  159 }
  160 
  161 static HAL_STATUS
  162 v14EepromSet(struct ath_hal *ah, int param, int v)
  163 {
  164         HAL_EEPROM_v14 *ee = AH_PRIVATE(ah)->ah_eeprom;
  165 
  166         switch (param) {
  167         case AR_EEP_ANTGAINMAX_2:
  168                 ee->ee_antennaGainMax[1] = (int8_t) v;
  169                 return HAL_OK;
  170         case AR_EEP_ANTGAINMAX_5:
  171                 ee->ee_antennaGainMax[0] = (int8_t) v;
  172                 return HAL_OK;
  173         }
  174         return HAL_EINVAL;
  175 }
  176 
  177 static HAL_BOOL
  178 v14EepromDiag(struct ath_hal *ah, int request,
  179      const void *args, uint32_t argsize, void **result, uint32_t *resultsize)
  180 {
  181         HAL_EEPROM_v14 *ee = AH_PRIVATE(ah)->ah_eeprom;
  182 
  183         switch (request) {
  184         case HAL_DIAG_EEPROM:
  185                 *result = ee;
  186                 *resultsize = sizeof(HAL_EEPROM_v14);
  187                 return AH_TRUE;
  188         }
  189         return AH_FALSE;
  190 }
  191 
  192 /* Do structure specific swaps if Eeprom format is non native to host */
  193 static void
  194 eepromSwap(struct ar5416eeprom *ee)
  195 {
  196         uint32_t integer, i, j;
  197         uint16_t word;
  198         MODAL_EEP_HEADER *pModal;
  199 
  200         /* convert Base Eep header */
  201         word = __bswap16(ee->baseEepHeader.length);
  202         ee->baseEepHeader.length = word;
  203 
  204         word = __bswap16(ee->baseEepHeader.checksum);
  205         ee->baseEepHeader.checksum = word;
  206 
  207         word = __bswap16(ee->baseEepHeader.version);
  208         ee->baseEepHeader.version = word;
  209 
  210         word = __bswap16(ee->baseEepHeader.regDmn[0]);
  211         ee->baseEepHeader.regDmn[0] = word;
  212 
  213         word = __bswap16(ee->baseEepHeader.regDmn[1]);
  214         ee->baseEepHeader.regDmn[1] = word;
  215 
  216         word = __bswap16(ee->baseEepHeader.rfSilent);
  217         ee->baseEepHeader.rfSilent = word;
  218 
  219         word = __bswap16(ee->baseEepHeader.blueToothOptions);
  220         ee->baseEepHeader.blueToothOptions = word; 
  221 
  222         word = __bswap16(ee->baseEepHeader.deviceCap);
  223         ee->baseEepHeader.deviceCap = word;
  224 
  225         /* convert Modal Eep header */
  226         for (j = 0; j < 2; j++) {
  227                 pModal = &ee->modalHeader[j];
  228 
  229                 /* XXX linux/ah_osdep.h only defines __bswap32 for BE */
  230                 integer = __bswap32(pModal->antCtrlCommon);
  231                 pModal->antCtrlCommon = integer;
  232 
  233                 for (i = 0; i < AR5416_MAX_CHAINS; i++) {
  234                         integer = __bswap32(pModal->antCtrlChain[i]);
  235                         pModal->antCtrlChain[i] = integer;
  236                 }
  237                 for (i = 0; i < 3; i++) {
  238                         word = __bswap16(pModal->xpaBiasLvlFreq[i]);
  239                         pModal->xpaBiasLvlFreq[i] = word;
  240                 }
  241                 for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) {
  242                         word = __bswap16(pModal->spurChans[i].spurChan);
  243                         pModal->spurChans[i].spurChan = word;
  244                 }
  245         }
  246 }
  247 
  248 static uint16_t 
  249 v14EepromGetSpurChan(struct ath_hal *ah, int ix, HAL_BOOL is2GHz)
  250 { 
  251         HAL_EEPROM_v14 *ee = AH_PRIVATE(ah)->ah_eeprom;
  252 
  253         HALASSERT(0 <= ix && ix <  AR5416_EEPROM_MODAL_SPURS);
  254         return ee->ee_base.modalHeader[is2GHz].spurChans[ix].spurChan;
  255 }
  256 
  257 /**************************************************************************
  258  * fbin2freq
  259  *
  260  * Get channel value from binary representation held in eeprom
  261  * RETURNS: the frequency in MHz
  262  */
  263 static uint16_t
  264 fbin2freq(uint8_t fbin, HAL_BOOL is2GHz)
  265 {
  266         /*
  267          * Reserved value 0xFF provides an empty definition both as
  268          * an fbin and as a frequency - do not convert
  269          */
  270         if (fbin == AR5416_BCHAN_UNUSED)
  271                 return fbin;
  272         return (uint16_t)((is2GHz) ? (2300 + fbin) : (4800 + 5 * fbin));
  273 }
  274 
  275 /*
  276  * Copy EEPROM Conformance Testing Limits contents 
  277  * into the allocated space
  278  */
  279 /* USE CTLS from chain zero */ 
  280 #define CTL_CHAIN       0 
  281 
  282 static void
  283 v14EepromReadCTLInfo(struct ath_hal *ah, HAL_EEPROM_v14 *ee)
  284 {
  285         RD_EDGES_POWER *rep = ee->ee_rdEdgesPower;
  286         int i, j;
  287 
  288         HALASSERT(AR5416_NUM_CTLS <= sizeof(ee->ee_rdEdgesPower)/NUM_EDGES);
  289 
  290         for (i = 0; ee->ee_base.ctlIndex[i] != 0 && i < AR5416_NUM_CTLS; i++) {
  291                 for (j = 0; j < NUM_EDGES; j ++) {
  292                         /* XXX Confirm this is the right thing to do when an invalid channel is stored */
  293                         if (ee->ee_base.ctlData[i].ctlEdges[CTL_CHAIN][j].bChannel == AR5416_BCHAN_UNUSED) {
  294                                 rep[j].rdEdge = 0;
  295                                 rep[j].twice_rdEdgePower = 0;
  296                                 rep[j].flag = 0;
  297                         } else {
  298                                 rep[j].rdEdge = fbin2freq(
  299                                     ee->ee_base.ctlData[i].ctlEdges[CTL_CHAIN][j].bChannel,
  300                                     (ee->ee_base.ctlIndex[i] & CTL_MODE_M) != CTL_11A);
  301                                 rep[j].twice_rdEdgePower = MS(ee->ee_base.ctlData[i].ctlEdges[CTL_CHAIN][j].tPowerFlag, CAL_CTL_EDGES_POWER);
  302                                 rep[j].flag = MS(ee->ee_base.ctlData[i].ctlEdges[CTL_CHAIN][j].tPowerFlag, CAL_CTL_EDGES_FLAG) != 0;
  303                         }
  304                 }
  305                 rep += NUM_EDGES;
  306         }
  307         ee->ee_numCtls = i;
  308         HALDEBUG(ah, HAL_DEBUG_ATTACH | HAL_DEBUG_EEPROM,
  309             "%s Numctls = %u\n",__func__,i);
  310 }
  311 
  312 /*
  313  * Reclaim any EEPROM-related storage.
  314  */
  315 static void
  316 v14EepromDetach(struct ath_hal *ah)
  317 {
  318         HAL_EEPROM_v14 *ee = AH_PRIVATE(ah)->ah_eeprom;
  319 
  320         ath_hal_free(ee);
  321         AH_PRIVATE(ah)->ah_eeprom = AH_NULL;
  322 }
  323 
  324 #define owl_get_eep_ver(_ee)   \
  325     (((_ee)->ee_base.baseEepHeader.version >> 12) & 0xF)
  326 #define owl_get_eep_rev(_ee)   \
  327     (((_ee)->ee_base.baseEepHeader.version) & 0xFFF)
  328 
  329 /*
  330  * Howl is (hopefully) a special case where the endian-ness of the EEPROM
  331  * matches the native endian-ness; and that supplied EEPROMs don't have
  332  * a magic value to check.
  333  */
  334 HAL_STATUS
  335 ath_hal_v14EepromAttach(struct ath_hal *ah)
  336 {
  337 #define NW(a)   (sizeof(a) / sizeof(uint16_t))
  338         HAL_EEPROM_v14 *ee = AH_PRIVATE(ah)->ah_eeprom;
  339         uint16_t *eep_data, magic;
  340         HAL_BOOL need_swap;
  341         u_int w, off, len;
  342         uint32_t sum;
  343 
  344         HALASSERT(ee == AH_NULL);
  345 
  346         /*
  347          * Don't check magic if we're supplied with an EEPROM block,
  348          * typically this is from Howl but it may also be from later
  349          * boards w/ an embedded Merlin.
  350          */
  351         if (ah->ah_eepromdata == NULL) {
  352                 if (!ath_hal_eepromRead(ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) {
  353                         HALDEBUG(ah, HAL_DEBUG_ANY,
  354                             "%s Error reading Eeprom MAGIC\n", __func__);
  355                         return HAL_EEREAD;
  356                 }
  357                 HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s Eeprom Magic = 0x%x\n",
  358                     __func__, magic);
  359                 if (magic != AR5416_EEPROM_MAGIC) {
  360                         HALDEBUG(ah, HAL_DEBUG_ANY, "Bad magic number\n");
  361                         return HAL_EEMAGIC;
  362                 }
  363         }
  364 
  365         ee = ath_hal_malloc(sizeof(HAL_EEPROM_v14));
  366         if (ee == AH_NULL) {
  367                 /* XXX message */
  368                 return HAL_ENOMEM;
  369         }
  370 
  371         eep_data = (uint16_t *)&ee->ee_base;
  372         for (w = 0; w < NW(struct ar5416eeprom); w++) {
  373                 off = owl_eep_start_loc + w;    /* NB: AP71 starts at 0 */
  374                 if (!ath_hal_eepromRead(ah, off, &eep_data[w])) {
  375                         HALDEBUG(ah, HAL_DEBUG_ANY,
  376                             "%s eeprom read error at offset 0x%x\n",
  377                             __func__, off);
  378                         return HAL_EEREAD;
  379                 }
  380         }
  381         /* Convert to eeprom native eeprom endian format */
  382         /* XXX this is likely incorrect but will do for now to get howl/ap83 working. */
  383         if (ah->ah_eepromdata == NULL && isBigEndian()) {
  384                 for (w = 0; w < NW(struct ar5416eeprom); w++)
  385                         eep_data[w] = __bswap16(eep_data[w]);
  386         }
  387 
  388         /*
  389          * At this point, we're in the native eeprom endian format
  390          * Now, determine the eeprom endian by looking at byte 26??
  391          */
  392         need_swap = ((ee->ee_base.baseEepHeader.eepMisc & AR5416_EEPMISC_BIG_ENDIAN) != 0) ^ isBigEndian();
  393         if (need_swap) {
  394                 HALDEBUG(ah, HAL_DEBUG_ATTACH | HAL_DEBUG_EEPROM,
  395                     "Byte swap EEPROM contents.\n");
  396                 len = __bswap16(ee->ee_base.baseEepHeader.length);
  397         } else {
  398                 len = ee->ee_base.baseEepHeader.length;
  399         }
  400         len = AH_MIN(len, sizeof(struct ar5416eeprom)) / sizeof(uint16_t);
  401 
  402         /* Apply the checksum, done in native eeprom format */
  403         /* XXX - Need to check to make sure checksum calculation is done
  404          * in the correct endian format.  Right now, it seems it would
  405          * cast the raw data to host format and do the calculation, which may
  406          * not be correct as the calculation may need to be done in the native
  407          * eeprom format 
  408          */
  409         sum = 0;
  410         for (w = 0; w < len; w++)
  411                 sum ^= eep_data[w];
  412         /* Check CRC - Attach should fail on a bad checksum */
  413         if (sum != 0xffff) {
  414                 HALDEBUG(ah, HAL_DEBUG_ANY,
  415                     "Bad EEPROM checksum 0x%x (Len=%u)\n", sum, len);
  416                 return HAL_EEBADSUM;
  417         }
  418 
  419         if (need_swap)
  420                 eepromSwap(&ee->ee_base);       /* byte swap multi-byte data */
  421 
  422         /* swap words 0+2 so version is at the front */
  423         magic = eep_data[0];
  424         eep_data[0] = eep_data[2];
  425         eep_data[2] = magic;
  426 
  427         HALDEBUG(ah, HAL_DEBUG_ATTACH | HAL_DEBUG_EEPROM,
  428             "%s Eeprom Version %u.%u\n", __func__,
  429             owl_get_eep_ver(ee), owl_get_eep_rev(ee));
  430 
  431         /* NB: must be after all byte swapping */
  432         if (owl_get_eep_ver(ee) != AR5416_EEP_VER) {
  433                 HALDEBUG(ah, HAL_DEBUG_ANY,
  434                     "Bad EEPROM version 0x%x\n", owl_get_eep_ver(ee));
  435                 return HAL_EEBADSUM;
  436         }
  437 
  438         v14EepromReadCTLInfo(ah, ee);           /* Get CTLs */
  439 
  440         AH_PRIVATE(ah)->ah_eeprom = ee;
  441         AH_PRIVATE(ah)->ah_eeversion = ee->ee_base.baseEepHeader.version;
  442         AH_PRIVATE(ah)->ah_eepromDetach = v14EepromDetach;
  443         AH_PRIVATE(ah)->ah_eepromGet = v14EepromGet;
  444         AH_PRIVATE(ah)->ah_eepromSet = v14EepromSet;
  445         AH_PRIVATE(ah)->ah_getSpurChan = v14EepromGetSpurChan;
  446         AH_PRIVATE(ah)->ah_eepromDiag = v14EepromDiag;
  447         return HAL_OK;
  448 #undef NW
  449 }

Cache object: 3b577d3adf30f669e1f9da27935c5cc7


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