/* * Set all the beacon related bits on the h/w for stations * i.e. initializes the corresponding h/w timers; * also tells the h/w whether to anticipate PCF beacons * * dtim_count and cfp_count from the current beacon - their current * values aren't necessarily maintained in the device struct */ void ar5210SetStaBeaconTimers(struct ath_hal *ah, const HAL_BEACON_STATE *bs) { struct ath_hal_5210 *ahp = AH5210(ah); HALDEBUG(ah, HAL_DEBUG_BEACON, "%s: setting beacon timers\n", __func__); HALASSERT(bs->bs_intval != 0); /* if the AP will do PCF */ if (bs->bs_cfpmaxduration != 0) { /* tell the h/w that the associated AP is PCF capable */ OS_REG_WRITE(ah, AR_STA_ID1, (OS_REG_READ(ah, AR_STA_ID1) &~ AR_STA_ID1_DEFAULT_ANTENNA) | AR_STA_ID1_PCF); /* set CFP_PERIOD(1.024ms) register */ OS_REG_WRITE(ah, AR_CFP_PERIOD, bs->bs_cfpperiod); /* set CFP_DUR(1.024ms) register to max cfp duration */ OS_REG_WRITE(ah, AR_CFP_DUR, bs->bs_cfpmaxduration); /* set TIMER2(128us) to anticipated time of next CFP */ OS_REG_WRITE(ah, AR_TIMER2, bs->bs_cfpnext << 3); } else { /* tell the h/w that the associated AP is not PCF capable */ OS_REG_WRITE(ah, AR_STA_ID1, OS_REG_READ(ah, AR_STA_ID1) &~ (AR_STA_ID1_DEFAULT_ANTENNA | AR_STA_ID1_PCF)); } /* * Set TIMER0(1.024ms) to the anticipated time of the next beacon. */ OS_REG_WRITE(ah, AR_TIMER0, bs->bs_nexttbtt); /* * Start the beacon timers by setting the BEACON register * to the beacon interval; also write the tim offset which * we should know by now. The code, in ar5211WriteAssocid, * also sets the tim offset once the AID is known which can * be left as such for now. */ OS_REG_WRITE(ah, AR_BEACON, (OS_REG_READ(ah, AR_BEACON) &~ (AR_BEACON_PERIOD|AR_BEACON_TIM)) | SM(bs->bs_intval, AR_BEACON_PERIOD) | SM(bs->bs_timoffset ? bs->bs_timoffset + 4 : 0, AR_BEACON_TIM) ); /* * Configure the BMISS interrupt. Note that we * assume the caller blocks interrupts while enabling * the threshold. */ /* * Interrupt works only on Crete. */ if (AH_PRIVATE(ah)->ah_macRev < AR_SREV_CRETE) return; /* * Counter is only 3-bits. * Count of 0 with BMISS interrupt enabled will hang the system * with too many interrupts */ if (AH_PRIVATE(ah)->ah_macRev >= AR_SREV_CRETE && (bs->bs_bmissthreshold&7) == 0) { #ifdef AH_DEBUG ath_hal_printf(ah, "%s: invalid beacon miss threshold %u\n", __func__, bs->bs_bmissthreshold); #endif return; } #define BMISS_MAX (AR_RSSI_THR_BM_THR >> AR_RSSI_THR_BM_THR_S) /* * Configure the BMISS interrupt. Note that we * assume the caller blocks interrupts while enabling * the threshold. * * NB: the beacon miss count field is only 3 bits which * is much smaller than what's found on later parts; * clamp overflow values as a safeguard. */ ahp->ah_rssiThr = (ahp->ah_rssiThr &~ AR_RSSI_THR_BM_THR) | SM(bs->bs_bmissthreshold > BMISS_MAX ? BMISS_MAX : bs->bs_bmissthreshold, AR_RSSI_THR_BM_THR); OS_REG_WRITE(ah, AR_RSSI_THR, ahp->ah_rssiThr); #undef BMISS_MAX }
static HAL_BOOL ar2317SetPowerTable(struct ath_hal *ah, int16_t *minPower, int16_t *maxPower, const struct ieee80211_channel *chan, uint16_t *rfXpdGain) { struct ath_hal_5212 *ahp = AH5212(ah); const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; const RAW_DATA_STRUCT_2317 *pRawDataset = AH_NULL; uint16_t pdGainOverlap_t2; int16_t minCalPower2317_t2; uint16_t *pdadcValues = ahp->ah_pcdacTable; uint16_t gainBoundaries[4]; uint32_t reg32, regoffset; int i, numPdGainsUsed; #ifndef AH_USE_INIPDGAIN uint32_t tpcrg1; #endif HALDEBUG(ah, HAL_DEBUG_RFPARAM, "%s: chan 0x%x flag 0x%x\n", __func__, chan->ic_freq, chan->ic_flags); if (IEEE80211_IS_CHAN_G(chan) || IEEE80211_IS_CHAN_108G(chan)) pRawDataset = &ee->ee_rawDataset2413[headerInfo11G]; else if (IEEE80211_IS_CHAN_B(chan)) pRawDataset = &ee->ee_rawDataset2413[headerInfo11B]; else { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: illegal mode\n", __func__); return AH_FALSE; } pdGainOverlap_t2 = (uint16_t) SM(OS_REG_READ(ah, AR_PHY_TPCRG5), AR_PHY_TPCRG5_PD_GAIN_OVERLAP); numPdGainsUsed = ar2317getGainBoundariesAndPdadcsForPowers(ah, chan->channel, pRawDataset, pdGainOverlap_t2, &minCalPower2317_t2,gainBoundaries, rfXpdGain, pdadcValues); HALASSERT(1 <= numPdGainsUsed && numPdGainsUsed <= 3); #ifdef AH_USE_INIPDGAIN /* * Use pd_gains curve from eeprom; Atheros always uses * the default curve from the ini file but some vendors * (e.g. Zcomax) want to override this curve and not * honoring their settings results in tx power 5dBm low. */ OS_REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN, (pRawDataset->pDataPerChannel[0].numPdGains - 1)); #else tpcrg1 = OS_REG_READ(ah, AR_PHY_TPCRG1); tpcrg1 = (tpcrg1 &~ AR_PHY_TPCRG1_NUM_PD_GAIN) | SM(numPdGainsUsed-1, AR_PHY_TPCRG1_NUM_PD_GAIN); switch (numPdGainsUsed) { case 3: tpcrg1 &= ~AR_PHY_TPCRG1_PDGAIN_SETTING3; tpcrg1 |= SM(rfXpdGain[2], AR_PHY_TPCRG1_PDGAIN_SETTING3); /* fall thru... */ case 2: tpcrg1 &= ~AR_PHY_TPCRG1_PDGAIN_SETTING2; tpcrg1 |= SM(rfXpdGain[1], AR_PHY_TPCRG1_PDGAIN_SETTING2); /* fall thru... */ case 1: tpcrg1 &= ~AR_PHY_TPCRG1_PDGAIN_SETTING1; tpcrg1 |= SM(rfXpdGain[0], AR_PHY_TPCRG1_PDGAIN_SETTING1); break; } #ifdef AH_DEBUG if (tpcrg1 != OS_REG_READ(ah, AR_PHY_TPCRG1)) HALDEBUG(ah, HAL_DEBUG_RFPARAM, "%s: using non-default " "pd_gains (default 0x%x, calculated 0x%x)\n", __func__, OS_REG_READ(ah, AR_PHY_TPCRG1), tpcrg1); #endif OS_REG_WRITE(ah, AR_PHY_TPCRG1, tpcrg1); #endif /* * Note the pdadc table may not start at 0 dBm power, could be * negative or greater than 0. Need to offset the power * values by the amount of minPower for griffin */ if (minCalPower2317_t2 != 0) ahp->ah_txPowerIndexOffset = (int16_t)(0 - minCalPower2317_t2); else ahp->ah_txPowerIndexOffset = 0; /* Finally, write the power values into the baseband power table */ regoffset = 0x9800 + (672 <<2); /* beginning of pdadc table in griffin */ for (i = 0; i < 32; i++) { reg32 = ((pdadcValues[4*i + 0] & 0xFF) << 0) | ((pdadcValues[4*i + 1] & 0xFF) << 8) | ((pdadcValues[4*i + 2] & 0xFF) << 16) | ((pdadcValues[4*i + 3] & 0xFF) << 24) ; OS_REG_WRITE(ah, regoffset, reg32); regoffset += 4; } OS_REG_WRITE(ah, AR_PHY_TPCRG5, SM(pdGainOverlap_t2, AR_PHY_TPCRG5_PD_GAIN_OVERLAP) | SM(gainBoundaries[0], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1) | SM(gainBoundaries[1], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2) | SM(gainBoundaries[2], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3) | SM(gainBoundaries[3], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4)); return AH_TRUE; }
/* * Internal interface to schedule periodic calibration work. */ HAL_BOOL ar5416PerCalibrationN(struct ath_hal *ah, struct ieee80211_channel *chan, u_int rxchainmask, HAL_BOOL longcal, HAL_BOOL *isCalDone) { struct ar5416PerCal *cal = &AH5416(ah)->ah_cal; HAL_CAL_LIST *currCal = cal->cal_curr; HAL_CHANNEL_INTERNAL *ichan; int r; OS_MARK(ah, AH_MARK_PERCAL, chan->ic_freq); *isCalDone = AH_TRUE; /* * Since ath_hal calls the PerCal method with rxchainmask=0x1; * override it with the current chainmask. The upper levels currently * doesn't know about the chainmask. */ rxchainmask = AH5416(ah)->ah_rx_chainmask; /* Invalid channel check */ ichan = ath_hal_checkchannel(ah, chan); if (ichan == AH_NULL) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel %u/0x%x; no mapping\n", __func__, chan->ic_freq, chan->ic_flags); return AH_FALSE; } /* * For given calibration: * 1. Call generic cal routine * 2. When this cal is done (isCalDone) if we have more cals waiting * (eg after reset), mask this to upper layers by not propagating * isCalDone if it is set to TRUE. * Instead, change isCalDone to FALSE and setup the waiting cal(s) * to be run. */ if (currCal != AH_NULL && (currCal->calState == CAL_RUNNING || currCal->calState == CAL_WAITING)) { ar5416DoCalibration(ah, ichan, rxchainmask, currCal, isCalDone); if (*isCalDone == AH_TRUE) { cal->cal_curr = currCal = currCal->calNext; if (currCal->calState == CAL_WAITING) { *isCalDone = AH_FALSE; ar5416ResetMeasurement(ah, currCal); } } } /* Do NF cal only at longer intervals */ if (longcal) { /* Do PA calibration if the chipset supports */ if (AH5416(ah)->ah_cal_pacal) AH5416(ah)->ah_cal_pacal(ah, AH_FALSE); /* Do open-loop temperature compensation if the chipset needs it */ if (ath_hal_eepromGetFlag(ah, AR_EEP_OL_PWRCTRL)) AH5416(ah)->ah_olcTempCompensation(ah); /* * Get the value from the previous NF cal * and update the history buffer. */ r = ar5416GetNf(ah, chan); if (r == 0 || r == -1) { /* NF calibration result isn't valid */ HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "%s: NF calibration" " didn't finish; delaying CCA\n", __func__); } else { /* * NF calibration result is valid. * * Load the NF from history buffer of the current channel. * NF is slow time-variant, so it is OK to use a * historical value. */ ar5416LoadNF(ah, AH_PRIVATE(ah)->ah_curchan); /* start NF calibration, without updating BB NF register*/ ar5416StartNFCal(ah); } } return AH_TRUE; }
static void ar9300_force_agc_gain(struct ath_hal *ah) { struct ath_hal_9300 *ahp = AH9300(ah); int i; static const struct { int rxtx1, rxtx2; } chn_reg[AR9300_MAX_CHAINS] = { {AR_PHY_65NM_CH0_RXTX1, AR_PHY_65NM_CH0_RXTX2}, {AR_PHY_65NM_CH1_RXTX1, AR_PHY_65NM_CH1_RXTX2}, {AR_PHY_65NM_CH2_RXTX1, AR_PHY_65NM_CH2_RXTX2} }; /* * for Osprey 1.0, force Rx gain through long shift (analog) interface * this works for Osprey 2.0 too * TODO: for Osprey 2.0, we can set gain via baseband registers */ for (i = 0; i < AR9300_MAX_CHAINS; i++) { if (ahp->ah_rx_chainmask & (1 << i)) { if (AH_PRIVATE(ah)->ah_curchan != NULL && IS_CHAN_2GHZ(AH_PRIVATE(ah)->ah_curchan)) { // For 2G band: OS_REG_RMW_FIELD(ah, chn_reg[i].rxtx2, AR_PHY_RX1DB_BIQUAD_LONG_SHIFT, 0x1); // 10db=3 OS_REG_RMW_FIELD(ah, chn_reg[i].rxtx2, AR_PHY_RX6DB_BIQUAD_LONG_SHIFT, 0x2); // 10db=2 OS_REG_RMW_FIELD(ah, chn_reg[i].rxtx2, AR_PHY_LNAGAIN_LONG_SHIFT, 0x7); // 10db=6 OS_REG_RMW_FIELD(ah, chn_reg[i].rxtx2, AR_PHY_MXRGAIN_LONG_SHIFT, 0x3); // 10db=3 OS_REG_RMW_FIELD(ah, chn_reg[i].rxtx2, AR_PHY_VGAGAIN_LONG_SHIFT, 0x0); // 10db=0 OS_REG_RMW_FIELD(ah, chn_reg[i].rxtx1, AR_PHY_SCFIR_GAIN_LONG_SHIFT, 0x1); // 10db=1 OS_REG_RMW_FIELD(ah, chn_reg[i].rxtx1, AR_PHY_MANRXGAIN_LONG_SHIFT, 0x1); // 10db=1 /* force external LNA on to disable strong signal mechanism */ OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_CHAIN(i), AR_PHY_SWITCH_TABLE_R0, 0x1); OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_CHAIN(i), AR_PHY_SWITCH_TABLE_R1, 0x1); OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_CHAIN(i), AR_PHY_SWITCH_TABLE_R12, 0x1); } else { // For 5G band: OS_REG_RMW_FIELD(ah, chn_reg[i].rxtx2, AR_PHY_RX1DB_BIQUAD_LONG_SHIFT, 0x2); // was 3=10/15db, // 2=+1db OS_REG_RMW_FIELD(ah, chn_reg[i].rxtx2, AR_PHY_RX6DB_BIQUAD_LONG_SHIFT, 0x2); // was 1 OS_REG_RMW_FIELD(ah, chn_reg[i].rxtx2, AR_PHY_LNAGAIN_LONG_SHIFT, 0x7); OS_REG_RMW_FIELD(ah, chn_reg[i].rxtx2, AR_PHY_MXRGAIN_LONG_SHIFT, 0x3); // was 2=15db, 3=10db OS_REG_RMW_FIELD(ah, chn_reg[i].rxtx2, AR_PHY_VGAGAIN_LONG_SHIFT, 0x6); OS_REG_RMW_FIELD(ah, chn_reg[i].rxtx1, AR_PHY_SCFIR_GAIN_LONG_SHIFT, 0x1); OS_REG_RMW_FIELD(ah, chn_reg[i].rxtx1, AR_PHY_MANRXGAIN_LONG_SHIFT, 0x1); /* force external LNA on to disable strong signal mechanism */ OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_CHAIN(i), AR_PHY_SWITCH_TABLE_R0, 0x0); OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_CHAIN(i), AR_PHY_SWITCH_TABLE_R1, 0x0); OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_CHAIN(i), AR_PHY_SWITCH_TABLE_R12, 0x0); } } } }
/* * Read the transmit power levels from the structures taken from EEPROM * Interpolate read transmit power values for this channel * Organize the transmit power values into a table for writing into the hardware */ static HAL_BOOL ar5111SetPowerTable(struct ath_hal *ah, int16_t *pMinPower, int16_t *pMaxPower, const struct ieee80211_channel *chan, uint16_t *rfXpdGain) { uint16_t freq = ath_hal_gethwchannel(ah, chan); struct ath_hal_5212 *ahp = AH5212(ah); const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; FULL_PCDAC_STRUCT pcdacStruct; int i, j; uint16_t *pPcdacValues; int16_t *pScaledUpDbm; int16_t minScaledPwr; int16_t maxScaledPwr; int16_t pwr; uint16_t pcdacMin = 0; uint16_t pcdacMax = PCDAC_STOP; uint16_t pcdacTableIndex; uint16_t scaledPcdac; PCDACS_EEPROM *pSrcStruct; PCDACS_EEPROM eepromPcdacs; /* setup the pcdac struct to point to the correct info, based on mode */ switch (chan->ic_flags & IEEE80211_CHAN_ALLTURBOFULL) { case IEEE80211_CHAN_A: case IEEE80211_CHAN_ST: eepromPcdacs.numChannels = ee->ee_numChannels11a; eepromPcdacs.pChannelList = ee->ee_channels11a; eepromPcdacs.pDataPerChannel = ee->ee_dataPerChannel11a; break; case IEEE80211_CHAN_B: eepromPcdacs.numChannels = ee->ee_numChannels2_4; eepromPcdacs.pChannelList = ee->ee_channels11b; eepromPcdacs.pDataPerChannel = ee->ee_dataPerChannel11b; break; case IEEE80211_CHAN_G: case IEEE80211_CHAN_108G: eepromPcdacs.numChannels = ee->ee_numChannels2_4; eepromPcdacs.pChannelList = ee->ee_channels11g; eepromPcdacs.pDataPerChannel = ee->ee_dataPerChannel11g; break; default: HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel flags 0x%x\n", __func__, chan->ic_flags); return AH_FALSE; } pSrcStruct = &eepromPcdacs; OS_MEMZERO(&pcdacStruct, sizeof(pcdacStruct)); pPcdacValues = pcdacStruct.PcdacValues; pScaledUpDbm = pcdacStruct.PwrValues; /* Initialize the pcdacs to dBM structs pcdacs to be 1 to 63 */ for (i = PCDAC_START, j = 0; i <= PCDAC_STOP; i+= PCDAC_STEP, j++) pPcdacValues[j] = i; pcdacStruct.numPcdacValues = j; pcdacStruct.pcdacMin = PCDAC_START; pcdacStruct.pcdacMax = PCDAC_STOP; /* Fill out the power values for this channel */ for (j = 0; j < pcdacStruct.numPcdacValues; j++ ) pScaledUpDbm[j] = ar5212GetScaledPower(freq, pPcdacValues[j], pSrcStruct); /* Now scale the pcdac values to fit in the 64 entry power table */ minScaledPwr = pScaledUpDbm[0]; maxScaledPwr = pScaledUpDbm[pcdacStruct.numPcdacValues - 1]; /* find minimum and make monotonic */ for (j = 0; j < pcdacStruct.numPcdacValues; j++) { if (minScaledPwr >= pScaledUpDbm[j]) { minScaledPwr = pScaledUpDbm[j]; pcdacMin = j; } /* * Make the full_hsh monotonically increasing otherwise * interpolation algorithm will get fooled gotta start * working from the top, hence i = 63 - j. */ i = (uint16_t)(pcdacStruct.numPcdacValues - 1 - j); if (i == 0) break; if (pScaledUpDbm[i-1] > pScaledUpDbm[i]) { /* * It could be a glitch, so make the power for * this pcdac the same as the power from the * next highest pcdac. */ pScaledUpDbm[i - 1] = pScaledUpDbm[i]; } } for (j = 0; j < pcdacStruct.numPcdacValues; j++) if (maxScaledPwr < pScaledUpDbm[j]) { maxScaledPwr = pScaledUpDbm[j]; pcdacMax = j; } /* Find the first power level with a pcdac */ pwr = (uint16_t)(PWR_STEP * ((minScaledPwr - PWR_MIN + PWR_STEP / 2) / PWR_STEP) + PWR_MIN); /* Write all the first pcdac entries based off the pcdacMin */ pcdacTableIndex = 0; for (i = 0; i < (2 * (pwr - PWR_MIN) / EEP_SCALE + 1); i++) { HALASSERT(pcdacTableIndex < PWR_TABLE_SIZE); ahp->ah_pcdacTable[pcdacTableIndex++] = pcdacMin; } i = 0; while (pwr < pScaledUpDbm[pcdacStruct.numPcdacValues - 1] && pcdacTableIndex < PWR_TABLE_SIZE) { pwr += PWR_STEP; /* stop if dbM > max_power_possible */ while (pwr < pScaledUpDbm[pcdacStruct.numPcdacValues - 1] && (pwr - pScaledUpDbm[i])*(pwr - pScaledUpDbm[i+1]) > 0) i++; /* scale by 2 and add 1 to enable round up or down as needed */ scaledPcdac = (uint16_t)(interpolate(pwr, pScaledUpDbm[i], pScaledUpDbm[i + 1], (uint16_t)(pPcdacValues[i] * 2), (uint16_t)(pPcdacValues[i + 1] * 2)) + 1); HALASSERT(pcdacTableIndex < PWR_TABLE_SIZE); ahp->ah_pcdacTable[pcdacTableIndex] = scaledPcdac / 2; if (ahp->ah_pcdacTable[pcdacTableIndex] > pcdacMax) ahp->ah_pcdacTable[pcdacTableIndex] = pcdacMax; pcdacTableIndex++; } /* Write all the last pcdac entries based off the last valid pcdac */ while (pcdacTableIndex < PWR_TABLE_SIZE) { ahp->ah_pcdacTable[pcdacTableIndex] = ahp->ah_pcdacTable[pcdacTableIndex - 1]; pcdacTableIndex++; } /* No power table adjustment for 5111 */ ahp->ah_txPowerIndexOffset = 0; return AH_TRUE; }
/* * Attach for an AR9160 part. */ static struct ath_hal * ar9160Attach(uint16_t devid, HAL_SOFTC sc, HAL_BUS_TAG st, HAL_BUS_HANDLE sh, uint16_t *eepromdata, HAL_OPS_CONFIG *ah_config, HAL_STATUS *status) { struct ath_hal_5416 *ahp5416; struct ath_hal_5212 *ahp; struct ath_hal *ah; uint32_t val; HAL_STATUS ecode; HAL_BOOL rfStatus; HALDEBUG(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n", __func__, sc, (void*) st, (void*) sh); /* NB: memory is returned zero'd */ ahp5416 = ath_hal_malloc(sizeof (struct ath_hal_5416)); if (ahp5416 == AH_NULL) { HALDEBUG(AH_NULL, HAL_DEBUG_ANY, "%s: cannot allocate memory for state block\n", __func__); *status = HAL_ENOMEM; return AH_NULL; } ar5416InitState(ahp5416, devid, sc, st, sh, status); ahp = &ahp5416->ah_5212; ah = &ahp->ah_priv.h; /* XXX override with 9160 specific state */ /* override 5416 methods for our needs */ AH5416(ah)->ah_initPLL = ar9160InitPLL; AH5416(ah)->ah_cal.iqCalData.calData = &ar9160_iq_cal; AH5416(ah)->ah_cal.adcGainCalData.calData = &ar9160_adc_gain_cal; AH5416(ah)->ah_cal.adcDcCalData.calData = &ar9160_adc_dc_cal; AH5416(ah)->ah_cal.adcDcCalInitData.calData = &ar9160_adc_init_dc_cal; AH5416(ah)->ah_cal.suppCals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL; if (!ar5416SetResetReg(ah, HAL_RESET_POWER_ON)) { /* reset chip */ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: couldn't reset chip\n", __func__); ecode = HAL_EIO; goto bad; } if (!ar5416SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: couldn't wakeup chip\n", __func__); ecode = HAL_EIO; goto bad; } /* Read Revisions from Chips before taking out of reset */ val = OS_REG_READ(ah, AR_SREV); HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s: ID 0x%x VERSION 0x%x TYPE 0x%x REVISION 0x%x\n", __func__, MS(val, AR_XSREV_ID), MS(val, AR_XSREV_VERSION), MS(val, AR_XSREV_TYPE), MS(val, AR_XSREV_REVISION)); /* NB: include chip type to differentiate from pre-Sowl versions */ AH_PRIVATE(ah)->ah_macVersion = (val & AR_XSREV_VERSION) >> AR_XSREV_TYPE_S; AH_PRIVATE(ah)->ah_macRev = MS(val, AR_XSREV_REVISION); AH_PRIVATE(ah)->ah_ispcie = (val & AR_XSREV_TYPE_HOST_MODE) == 0; /* setup common ini data; rf backends handle remainder */ HAL_INI_INIT(&ahp->ah_ini_modes, ar9160Modes, 6); HAL_INI_INIT(&ahp->ah_ini_common, ar9160Common, 2); HAL_INI_INIT(&AH5416(ah)->ah_ini_bb_rfgain, ar9160BB_RfGain, 3); HAL_INI_INIT(&AH5416(ah)->ah_ini_bank0, ar9160Bank0, 2); HAL_INI_INIT(&AH5416(ah)->ah_ini_bank1, ar9160Bank1, 2); HAL_INI_INIT(&AH5416(ah)->ah_ini_bank2, ar9160Bank2, 2); HAL_INI_INIT(&AH5416(ah)->ah_ini_bank3, ar9160Bank3, 3); HAL_INI_INIT(&AH5416(ah)->ah_ini_bank6, ar9160Bank6TPC, 3); HAL_INI_INIT(&AH5416(ah)->ah_ini_bank7, ar9160Bank7, 2); if (AR_SREV_SOWL_11(ah)) HAL_INI_INIT(&AH5416(ah)->ah_ini_addac, ar9160Addac_1_1, 2); else HAL_INI_INIT(&AH5416(ah)->ah_ini_addac, ar9160Addac, 2); ecode = ath_hal_v14EepromAttach(ah); if (ecode != HAL_OK) goto bad; HAL_INI_INIT(&AH5416(ah)->ah_ini_pcieserdes, ar9160PciePhy, 2); ar5416AttachPCIE(ah); if (!ar5416ChipReset(ah, AH_NULL)) { /* reset chip */ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n", __func__); ecode = HAL_EIO; goto bad; } AH_PRIVATE(ah)->ah_phyRev = OS_REG_READ(ah, AR_PHY_CHIP_ID); if (!ar5212ChipTest(ah)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: hardware self-test failed\n", __func__); ecode = HAL_ESELFTEST; goto bad; } /* * Set correct Baseband to analog shift * setting to access analog chips. */ OS_REG_WRITE(ah, AR_PHY(0), 0x00000007); /* Read Radio Chip Rev Extract */ AH_PRIVATE(ah)->ah_analog5GhzRev = ar5416GetRadioRev(ah); switch (AH_PRIVATE(ah)->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR) { case AR_RAD2133_SREV_MAJOR: /* Sowl: 2G/3x3 */ case AR_RAD5133_SREV_MAJOR: /* Sowl: 2+5G/3x3 */ break; default: if (AH_PRIVATE(ah)->ah_analog5GhzRev == 0) { AH_PRIVATE(ah)->ah_analog5GhzRev = AR_RAD5133_SREV_MAJOR; break; } #ifdef AH_DEBUG HALDEBUG(ah, HAL_DEBUG_ANY, "%s: 5G Radio Chip Rev 0x%02X is not supported by " "this driver\n", __func__, AH_PRIVATE(ah)->ah_analog5GhzRev); ecode = HAL_ENOTSUPP; goto bad; #endif } rfStatus = ar2133RfAttach(ah, &ecode); if (!rfStatus) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: RF setup failed, status %u\n", __func__, ecode); goto bad; } /* * Got everything we need now to setup the capabilities. */ if (!ar9160FillCapabilityInfo(ah)) { ecode = HAL_EEREAD; goto bad; } ecode = ath_hal_eepromGet(ah, AR_EEP_MACADDR, ahp->ah_macaddr); if (ecode != HAL_OK) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: error getting mac address from EEPROM\n", __func__); goto bad; } /* XXX How about the serial number ? */ /* Read Reg Domain */ AH_PRIVATE(ah)->ah_currentRD = ath_hal_eepromGet(ah, AR_EEP_REGDMN_0, AH_NULL); AH_PRIVATE(ah)->ah_currentRDext = ath_hal_eepromGet(ah, AR_EEP_REGDMN_1, AH_NULL); /* * ah_miscMode is populated by ar5416FillCapabilityInfo() * starting from griffin. Set here to make sure that * AR_MISC_MODE_MIC_NEW_LOC_ENABLE is set before a GTK is * placed into hardware. */ if (ahp->ah_miscMode != 0) OS_REG_WRITE(ah, AR_MISC_MODE, OS_REG_READ(ah, AR_MISC_MODE) | ahp->ah_miscMode); ar9160AniSetup(ah); /* Anti Noise Immunity */ /* This just uses the AR5416 NF values */ AH5416(ah)->nf_2g.max = AR_PHY_CCA_MAX_GOOD_VAL_5416_2GHZ; AH5416(ah)->nf_2g.min = AR_PHY_CCA_MIN_GOOD_VAL_5416_2GHZ; AH5416(ah)->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_5416_2GHZ; AH5416(ah)->nf_5g.max = AR_PHY_CCA_MAX_GOOD_VAL_5416_5GHZ; AH5416(ah)->nf_5g.min = AR_PHY_CCA_MIN_GOOD_VAL_5416_5GHZ; AH5416(ah)->nf_5g.nominal = AR_PHY_CCA_NOM_VAL_5416_5GHZ; ar5416InitNfHistBuff(AH5416(ah)->ah_cal.nfCalHist); HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s: return\n", __func__); return ah; bad: if (ahp) ar5416Detach((struct ath_hal *) ahp); if (status) *status = ecode; return AH_NULL; }
HAL_STATUS ath_hal_v4kEepromAttach(struct ath_hal *ah) { #define NW(a) (sizeof(a) / sizeof(uint16_t)) HAL_EEPROM_v4k *ee = AH_PRIVATE(ah)->ah_eeprom; uint16_t *eep_data, magic; HAL_BOOL need_swap; u_int w, off, len; uint32_t sum; HALASSERT(ee == AH_NULL); if (!ath_hal_eepromRead(ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s Error reading Eeprom MAGIC\n", __func__); return HAL_EEREAD; } HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s Eeprom Magic = 0x%x\n", __func__, magic); if (magic != AR5416_EEPROM_MAGIC) { HALDEBUG(ah, HAL_DEBUG_ANY, "Bad magic number\n"); return HAL_EEMAGIC; } ee = ath_hal_malloc(sizeof(HAL_EEPROM_v4k)); if (ee == AH_NULL) { /* XXX message */ return HAL_ENOMEM; } eep_data = (uint16_t *)&ee->ee_base; for (w = 0; w < NW(struct ar5416eeprom_4k); w++) { off = owl_eep_start_loc + w; /* NB: AP71 starts at 0 */ if (!ath_hal_eepromRead(ah, off, &eep_data[w])) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s eeprom read error at offset 0x%x\n", __func__, off); return HAL_EEREAD; } } /* Convert to eeprom native eeprom endian format */ if (isBigEndian()) { for (w = 0; w < NW(struct ar5416eeprom_4k); w++) eep_data[w] = __bswap16(eep_data[w]); } /* * At this point, we're in the native eeprom endian format * Now, determine the eeprom endian by looking at byte 26?? */ need_swap = ((ee->ee_base.baseEepHeader.eepMisc & AR5416_EEPMISC_BIG_ENDIAN) != 0) ^ isBigEndian(); if (need_swap) { HALDEBUG(ah, HAL_DEBUG_ATTACH | HAL_DEBUG_EEPROM, "Byte swap EEPROM contents.\n"); len = __bswap16(ee->ee_base.baseEepHeader.length); } else { len = ee->ee_base.baseEepHeader.length; } len = AH_MIN(len, sizeof(struct ar5416eeprom_4k)) / sizeof(uint16_t); /* Apply the checksum, done in native eeprom format */ /* XXX - Need to check to make sure checksum calculation is done * in the correct endian format. Right now, it seems it would * cast the raw data to host format and do the calculation, which may * not be correct as the calculation may need to be done in the native * eeprom format */ sum = 0; for (w = 0; w < len; w++) { sum ^= eep_data[w]; } /* Check CRC - Attach should fail on a bad checksum */ if (sum != 0xffff) { HALDEBUG(ah, HAL_DEBUG_ANY, "Bad EEPROM checksum 0x%x (Len=%u)\n", sum, len); return HAL_EEBADSUM; } if (need_swap) eepromSwap(&ee->ee_base); /* byte swap multi-byte data */ /* swap words 0+2 so version is at the front */ magic = eep_data[0]; eep_data[0] = eep_data[2]; eep_data[2] = magic; HALDEBUG(ah, HAL_DEBUG_ATTACH | HAL_DEBUG_EEPROM, "%s Eeprom Version %u.%u\n", __func__, owl_get_eep_ver(ee), owl_get_eep_rev(ee)); /* NB: must be after all byte swapping */ if (owl_get_eep_ver(ee) != AR5416_EEP_VER) { HALDEBUG(ah, HAL_DEBUG_ANY, "Bad EEPROM version 0x%x\n", owl_get_eep_ver(ee)); return HAL_EEBADSUM; } v4kEepromReadCTLInfo(ah, ee); /* Get CTLs */ AH_PRIVATE(ah)->ah_eeprom = ee; AH_PRIVATE(ah)->ah_eeversion = ee->ee_base.baseEepHeader.version; AH_PRIVATE(ah)->ah_eepromDetach = v4kEepromDetach; AH_PRIVATE(ah)->ah_eepromGet = v4kEepromGet; AH_PRIVATE(ah)->ah_eepromSet = v4kEepromSet; AH_PRIVATE(ah)->ah_getSpurChan = v4kEepromGetSpurChan; AH_PRIVATE(ah)->ah_eepromDiag = v4kEepromDiag; return HAL_OK; #undef NW }
void __ahdecl ath_hal_wmi_reg_write_single(struct ath_hal *ah, u_int reg, u_int32_t val) { wmi_reg_write_single(AH_PRIVATE(ah)->hal_wmi_handle, reg,val); }
static void ar5312AniSetup(struct ath_hal *ah) { static const struct ar5212AniParams aniparams = { .maxNoiseImmunityLevel = 4, /* levels 0..4 */ .totalSizeDesired = { -41, -41, -48, -48, -48 }, .coarseHigh = { -18, -18, -16, -14, -12 }, .coarseLow = { -56, -56, -60, -60, -60 }, .firpwr = { -72, -72, -75, -78, -80 }, .maxSpurImmunityLevel = 2, .cycPwrThr1 = { 2, 4, 6 }, .maxFirstepLevel = 2, /* levels 0..2 */ .firstep = { 0, 4, 8 }, .ofdmTrigHigh = 500, .ofdmTrigLow = 200, .cckTrigHigh = 200, .cckTrigLow = 100, .rssiThrHigh = 40, .rssiThrLow = 7, .period = 100, }; ar5212AniAttach(ah, &aniparams, &aniparams, AH_TRUE); } /* * Attach for an AR5312 part. */ static struct ath_hal * ar5312Attach(uint16_t devid, HAL_SOFTC sc, HAL_BUS_TAG st, HAL_BUS_HANDLE sh, HAL_STATUS *status) { struct ath_hal_5212 *ahp = AH_NULL; struct ath_hal *ah; struct ath_hal_rf *rf; uint32_t val; uint16_t eeval; HAL_STATUS ecode; HALDEBUG(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n", __func__, sc, st, (void*) sh); /* NB: memory is returned zero'd */ ahp = ath_hal_malloc(sizeof (struct ath_hal_5212)); if (ahp == AH_NULL) { HALDEBUG(AH_NULL, HAL_DEBUG_ANY, "%s: cannot allocate memory for state block\n", __func__); *status = HAL_ENOMEM; return AH_NULL; } ar5212InitState(ahp, devid, sc, st, sh, status); ah = &ahp->ah_priv.h; /* override 5212 methods for our needs */ ah->ah_reset = ar5312Reset; ah->ah_phyDisable = ar5312PhyDisable; ah->ah_setLedState = ar5312SetLedState; ah->ah_detectCardPresent = ar5312DetectCardPresent; ah->ah_setPowerMode = ar5312SetPowerMode; ah->ah_getPowerMode = ar5312GetPowerMode; ah->ah_isInterruptPending = ar5312IsInterruptPending; ahp->ah_priv.ah_eepromRead = ar5312EepromRead; #ifdef AH_SUPPORT_WRITE_EEPROM ahp->ah_priv.ah_eepromWrite = ar5312EepromWrite; #endif #if ( AH_SUPPORT_2316 || AH_SUPPORT_2317) if (IS_5315(ah)) { ahp->ah_priv.ah_gpioCfgOutput = ar5315GpioCfgOutput; ahp->ah_priv.ah_gpioCfgInput = ar5315GpioCfgInput; ahp->ah_priv.ah_gpioGet = ar5315GpioGet; ahp->ah_priv.ah_gpioSet = ar5315GpioSet; ahp->ah_priv.ah_gpioSetIntr = ar5315GpioSetIntr; } else #endif { ahp->ah_priv.ah_gpioCfgOutput = ar5312GpioCfgOutput; ahp->ah_priv.ah_gpioCfgInput = ar5312GpioCfgInput; ahp->ah_priv.ah_gpioGet = ar5312GpioGet; ahp->ah_priv.ah_gpioSet = ar5312GpioSet; ahp->ah_priv.ah_gpioSetIntr = ar5312GpioSetIntr; } ah->ah_gpioCfgInput = ahp->ah_priv.ah_gpioCfgInput; ah->ah_gpioCfgOutput = ahp->ah_priv.ah_gpioCfgOutput; ah->ah_gpioGet = ahp->ah_priv.ah_gpioGet; ah->ah_gpioSet = ahp->ah_priv.ah_gpioSet; ah->ah_gpioSetIntr = ahp->ah_priv.ah_gpioSetIntr; /* setup common ini data; rf backends handle remainder */ HAL_INI_INIT(&ahp->ah_ini_modes, ar5212Modes, 6); HAL_INI_INIT(&ahp->ah_ini_common, ar5212Common, 2); if (!ar5312ChipReset(ah, AH_NULL)) { /* reset chip */ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n", __func__); ecode = HAL_EIO; goto bad; } #if ( AH_SUPPORT_2316 || AH_SUPPORT_2317) if ((devid == AR5212_AR2315_REV6) || (devid == AR5212_AR2315_REV7) || (devid == AR5212_AR2317_REV1) || (devid == AR5212_AR2317_REV2) ) { val = ((OS_REG_READ(ah, (AR5315_RSTIMER_BASE -((uint32_t) sh)) + AR5315_WREV)) >> AR5315_WREV_S) & AR5315_WREV_ID; AH_PRIVATE(ah)->ah_macVersion = val >> AR5315_WREV_ID_S; AH_PRIVATE(ah)->ah_macRev = val & AR5315_WREV_REVISION; HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s: Mac Chip Rev 0x%02x.%x\n" , __func__, AH_PRIVATE(ah)->ah_macVersion, AH_PRIVATE(ah)->ah_macRev); } else #endif {
/* * Return the size of the hardware key cache. */ u_int32_t ar9300_get_key_cache_size(struct ath_hal *ah) { return AH_PRIVATE(ah)->ah_caps.hal_key_cache_size; }
void __ahdecl ath_hal_wmi_reg_write_flush(struct ath_hal *ah) { wmi_reg_write_flush(AH_PRIVATE(ah)->hal_wmi_handle); }
/* * Attach for an AR9280 part. */ static struct ath_hal * ar9280Attach(uint16_t devid, HAL_SOFTC sc, HAL_BUS_TAG st, HAL_BUS_HANDLE sh, HAL_STATUS *status) { struct ath_hal_9280 *ahp9280; struct ath_hal_5212 *ahp; struct ath_hal *ah; uint32_t val; HAL_STATUS ecode; HAL_BOOL rfStatus; HALDEBUG(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n", __func__, sc, (void*) st, (void*) sh); /* NB: memory is returned zero'd */ ahp9280 = ath_hal_malloc(sizeof (struct ath_hal_9280)); if (ahp9280 == AH_NULL) { HALDEBUG(AH_NULL, HAL_DEBUG_ANY, "%s: cannot allocate memory for state block\n", __func__); *status = HAL_ENOMEM; return AH_NULL; } ahp = AH5212(ahp9280); ah = &ahp->ah_priv.h; ar5416InitState(AH5416(ah), devid, sc, st, sh, status); /* XXX override with 9280 specific state */ /* override 5416 methods for our needs */ ah->ah_setAntennaSwitch = ar9280SetAntennaSwitch; ah->ah_configPCIE = ar9280ConfigPCIE; AH5416(ah)->ah_cal.iqCalData.calData = &ar9280_iq_cal; AH5416(ah)->ah_cal.adcGainCalData.calData = &ar9280_adc_gain_cal; AH5416(ah)->ah_cal.adcDcCalData.calData = &ar9280_adc_dc_cal; AH5416(ah)->ah_cal.adcDcCalInitData.calData = &ar9280_adc_init_dc_cal; AH5416(ah)->ah_cal.suppCals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL; AH5416(ah)->ah_spurMitigate = ar9280SpurMitigate; AH5416(ah)->ah_writeIni = ar9280WriteIni; AH5416(ah)->ah_rx_chainmask = AR9280_DEFAULT_RXCHAINMASK; AH5416(ah)->ah_tx_chainmask = AR9280_DEFAULT_TXCHAINMASK; if (!ar5416SetResetReg(ah, HAL_RESET_POWER_ON)) { /* reset chip */ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: couldn't reset chip\n", __func__); ecode = HAL_EIO; goto bad; } if (!ar5416SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: couldn't wakeup chip\n", __func__); ecode = HAL_EIO; goto bad; } /* Read Revisions from Chips before taking out of reset */ val = OS_REG_READ(ah, AR_SREV); HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s: ID 0x%x VERSION 0x%x TYPE 0x%x REVISION 0x%x\n", __func__, MS(val, AR_XSREV_ID), MS(val, AR_XSREV_VERSION), MS(val, AR_XSREV_TYPE), MS(val, AR_XSREV_REVISION)); /* NB: include chip type to differentiate from pre-Sowl versions */ AH_PRIVATE(ah)->ah_macVersion = (val & AR_XSREV_VERSION) >> AR_XSREV_TYPE_S; AH_PRIVATE(ah)->ah_macRev = MS(val, AR_XSREV_REVISION); AH_PRIVATE(ah)->ah_ispcie = (val & AR_XSREV_TYPE_HOST_MODE) == 0; /* setup common ini data; rf backends handle remainder */ if (AR_SREV_MERLIN_20_OR_LATER(ah)) { HAL_INI_INIT(&ahp->ah_ini_modes, ar9280Modes_v2, 6); HAL_INI_INIT(&ahp->ah_ini_common, ar9280Common_v2, 2); HAL_INI_INIT(&AH5416(ah)->ah_ini_pcieserdes, ar9280PciePhy_clkreq_always_on_L1_v2, 2); HAL_INI_INIT(&ahp9280->ah_ini_xmodes, ar9280Modes_fast_clock_v2, 3); } else { HAL_INI_INIT(&ahp->ah_ini_modes, ar9280Modes_v1, 6); HAL_INI_INIT(&ahp->ah_ini_common, ar9280Common_v1, 2); HAL_INI_INIT(&AH5416(ah)->ah_ini_pcieserdes, ar9280PciePhy_v1, 2); } ar5416AttachPCIE(ah); ecode = ath_hal_v14EepromAttach(ah); if (ecode != HAL_OK) goto bad; if (!ar5416ChipReset(ah, AH_NULL)) { /* reset chip */ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n", __func__); ecode = HAL_EIO; goto bad; } AH_PRIVATE(ah)->ah_phyRev = OS_REG_READ(ah, AR_PHY_CHIP_ID); if (!ar5212ChipTest(ah)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: hardware self-test failed\n", __func__); ecode = HAL_ESELFTEST; goto bad; } /* * Set correct Baseband to analog shift * setting to access analog chips. */ OS_REG_WRITE(ah, AR_PHY(0), 0x00000007); /* Read Radio Chip Rev Extract */ AH_PRIVATE(ah)->ah_analog5GhzRev = ar5416GetRadioRev(ah); switch (AH_PRIVATE(ah)->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR) { case AR_RAD2133_SREV_MAJOR: /* Sowl: 2G/3x3 */ case AR_RAD5133_SREV_MAJOR: /* Sowl: 2+5G/3x3 */ break; default: if (AH_PRIVATE(ah)->ah_analog5GhzRev == 0) { AH_PRIVATE(ah)->ah_analog5GhzRev = AR_RAD5133_SREV_MAJOR; break; } #ifdef AH_DEBUG HALDEBUG(ah, HAL_DEBUG_ANY, "%s: 5G Radio Chip Rev 0x%02X is not supported by " "this driver\n", __func__, AH_PRIVATE(ah)->ah_analog5GhzRev); ecode = HAL_ENOTSUPP; goto bad; #endif } rfStatus = ar9280RfAttach(ah, &ecode); if (!rfStatus) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: RF setup failed, status %u\n", __func__, ecode); goto bad; } if (AR_SREV_MERLIN_20_OR_LATER(ah)) { /* setup rxgain table */ switch (ath_hal_eepromGet(ah, AR_EEP_RXGAIN_TYPE, AH_NULL)) { case AR5416_EEP_RXGAIN_13dB_BACKOFF: HAL_INI_INIT(&ahp9280->ah_ini_rxgain, ar9280Modes_backoff_13db_rxgain_v2, 6); break; case AR5416_EEP_RXGAIN_23dB_BACKOFF: HAL_INI_INIT(&ahp9280->ah_ini_rxgain, ar9280Modes_backoff_23db_rxgain_v2, 6); break; case AR5416_EEP_RXGAIN_ORIG: HAL_INI_INIT(&ahp9280->ah_ini_rxgain, ar9280Modes_original_rxgain_v2, 6); break; default: HALASSERT(AH_FALSE); goto bad; /* XXX ? try to continue */ } } if (AR_SREV_MERLIN_20_OR_LATER(ah)) { /* setp txgain table */ switch (ath_hal_eepromGet(ah, AR_EEP_TXGAIN_TYPE, AH_NULL)) { case AR5416_EEP_TXGAIN_HIGH_POWER: HAL_INI_INIT(&ahp9280->ah_ini_txgain, ar9280Modes_high_power_tx_gain_v2, 6); break; case AR5416_EEP_TXGAIN_ORIG: HAL_INI_INIT(&ahp9280->ah_ini_txgain, ar9280Modes_original_tx_gain_v2, 6); break; default: HALASSERT(AH_FALSE); goto bad; /* XXX ? try to continue */ } } /* * Got everything we need now to setup the capabilities. */ if (!ar9280FillCapabilityInfo(ah)) { ecode = HAL_EEREAD; goto bad; } ecode = ath_hal_eepromGet(ah, AR_EEP_MACADDR, ahp->ah_macaddr); if (ecode != HAL_OK) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: error getting mac address from EEPROM\n", __func__); goto bad; } /* XXX How about the serial number ? */ /* Read Reg Domain */ AH_PRIVATE(ah)->ah_currentRD = ath_hal_eepromGet(ah, AR_EEP_REGDMN_0, AH_NULL); /* * ah_miscMode is populated by ar5416FillCapabilityInfo() * starting from griffin. Set here to make sure that * AR_MISC_MODE_MIC_NEW_LOC_ENABLE is set before a GTK is * placed into hardware. */ if (ahp->ah_miscMode != 0) OS_REG_WRITE(ah, AR_MISC_MODE, ahp->ah_miscMode); ar9280AniSetup(ah); /* Anti Noise Immunity */ ar5416InitNfHistBuff(AH5416(ah)->ah_cal.nfCalHist); HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s: return\n", __func__); return ah; bad: if (ah != AH_NULL) ah->ah_detach(ah); if (status) *status = ecode; return AH_NULL; }
/* * Places the device in and out of reset and then places sane * values in the registers based on EEPROM config, initialization * vectors (as determined by the mode), and station configuration * * bChannelChange is used to preserve DMA/PCU registers across * a HW Reset during channel change. */ HAL_BOOL ar5312Reset(struct ath_hal *ah, HAL_OPMODE opmode, struct ieee80211_channel *chan, HAL_BOOL bChannelChange, HAL_STATUS *status) { #define N(a) (sizeof (a) / sizeof (a[0])) #define FAIL(_code) do { ecode = _code; goto bad; } while (0) struct ath_hal_5212 *ahp = AH5212(ah); HAL_CHANNEL_INTERNAL *ichan; const HAL_EEPROM *ee; uint32_t saveFrameSeqCount, saveDefAntenna; uint32_t macStaId1, synthDelay, txFrm2TxDStart; uint16_t rfXpdGain[MAX_NUM_PDGAINS_PER_CHANNEL]; int16_t cckOfdmPwrDelta = 0; u_int modesIndex, freqIndex; HAL_STATUS ecode; int i, regWrites = 0; uint32_t testReg; uint32_t saveLedState = 0; HALASSERT(ah->ah_magic == AR5212_MAGIC); ee = AH_PRIVATE(ah)->ah_eeprom; OS_MARK(ah, AH_MARK_RESET, bChannelChange); /* * Map public channel to private. */ ichan = ath_hal_checkchannel(ah, chan); if (ichan == AH_NULL) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel %u/0x%x; no mapping\n", __func__, chan->ic_freq, chan->ic_flags); FAIL(HAL_EINVAL); } switch (opmode) { case HAL_M_STA: case HAL_M_IBSS: case HAL_M_HOSTAP: case HAL_M_MONITOR: break; default: HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid operating mode %u\n", __func__, opmode); FAIL(HAL_EINVAL); break; } HALASSERT(ahp->ah_eeversion >= AR_EEPROM_VER3); /* Preserve certain DMA hardware registers on a channel change */ if (bChannelChange) { /* * On Venice, the TSF is almost preserved across a reset; * it requires the doubling writes to the RESET_TSF * bit in the AR_BEACON register; it also has the quirk * of the TSF going back in time on the station (station * latches onto the last beacon's tsf during a reset 50% * of the times); the latter is not a problem for adhoc * stations since as long as the TSF is behind, it will * get resynchronized on receiving the next beacon; the * TSF going backwards in time could be a problem for the * sleep operation (supported on infrastructure stations * only) - the best and most general fix for this situation * is to resynchronize the various sleep/beacon timers on * the receipt of the next beacon i.e. when the TSF itself * gets resynchronized to the AP's TSF - power save is * needed to be temporarily disabled until that time * * Need to save the sequence number to restore it after * the reset! */ saveFrameSeqCount = OS_REG_READ(ah, AR_D_SEQNUM); } else saveFrameSeqCount = 0; /* NB: silence compiler */ /* If the channel change is across the same mode - perform a fast channel change */ if ((IS_2413(ah) || IS_5413(ah))) { /* * Channel change can only be used when: * -channel change requested - so it's not the initial reset. * -it's not a change to the current channel - often called when switching modes * on a channel * -the modes of the previous and requested channel are the same - some ugly code for XR */ if (bChannelChange && AH_PRIVATE(ah)->ah_curchan != AH_NULL && (chan->ic_freq != AH_PRIVATE(ah)->ah_curchan->ic_freq) && ((chan->ic_flags & IEEE80211_CHAN_ALLTURBO) == (AH_PRIVATE(ah)->ah_curchan->ic_flags & IEEE80211_CHAN_ALLTURBO))) { if (ar5212ChannelChange(ah, chan)) /* If ChannelChange completed - skip the rest of reset */ return AH_TRUE; } } /* * Preserve the antenna on a channel change */ saveDefAntenna = OS_REG_READ(ah, AR_DEF_ANTENNA); if (saveDefAntenna == 0) /* XXX magic constants */ saveDefAntenna = 1; /* Save hardware flag before chip reset clears the register */ macStaId1 = OS_REG_READ(ah, AR_STA_ID1) & (AR_STA_ID1_BASE_RATE_11B | AR_STA_ID1_USE_DEFANT); /* Save led state from pci config register */ if (!IS_5315(ah)) saveLedState = OS_REG_READ(ah, AR5312_PCICFG) & (AR_PCICFG_LEDCTL | AR_PCICFG_LEDMODE | AR_PCICFG_LEDBLINK | AR_PCICFG_LEDSLOW); ar5312RestoreClock(ah, opmode); /* move to refclk operation */ /* * Adjust gain parameters before reset if * there's an outstanding gain updated. */ (void) ar5212GetRfgain(ah); if (!ar5312ChipReset(ah, chan)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n", __func__); FAIL(HAL_EIO); } /* Setup the indices for the next set of register array writes */ if (IEEE80211_IS_CHAN_2GHZ(chan)) { freqIndex = 2; modesIndex = IEEE80211_IS_CHAN_108G(chan) ? 5 : IEEE80211_IS_CHAN_G(chan) ? 4 : 3; } else { freqIndex = 1; modesIndex = IEEE80211_IS_CHAN_ST(chan) ? 2 : 1; } OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__); /* Set correct Baseband to analog shift setting to access analog chips. */ OS_REG_WRITE(ah, AR_PHY(0), 0x00000007); regWrites = ath_hal_ini_write(ah, &ahp->ah_ini_modes, modesIndex, 0); regWrites = write_common(ah, &ahp->ah_ini_common, bChannelChange, regWrites); ahp->ah_rfHal->writeRegs(ah, modesIndex, freqIndex, regWrites); OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__); if (IEEE80211_IS_CHAN_HALF(chan) || IEEE80211_IS_CHAN_QUARTER(chan)) ar5212SetIFSTiming(ah, chan); /* Overwrite INI values for revised chipsets */ if (AH_PRIVATE(ah)->ah_phyRev >= AR_PHY_CHIP_ID_REV_2) { /* ADC_CTL */ OS_REG_WRITE(ah, AR_PHY_ADC_CTL, SM(2, AR_PHY_ADC_CTL_OFF_INBUFGAIN) | SM(2, AR_PHY_ADC_CTL_ON_INBUFGAIN) | AR_PHY_ADC_CTL_OFF_PWDDAC | AR_PHY_ADC_CTL_OFF_PWDADC); /* TX_PWR_ADJ */ if (chan->channel == 2484) { cckOfdmPwrDelta = SCALE_OC_DELTA(ee->ee_cckOfdmPwrDelta - ee->ee_scaledCh14FilterCckDelta); } else { cckOfdmPwrDelta = SCALE_OC_DELTA(ee->ee_cckOfdmPwrDelta); } if (IEEE80211_IS_CHAN_G(chan)) { OS_REG_WRITE(ah, AR_PHY_TXPWRADJ, SM((ee->ee_cckOfdmPwrDelta*-1), AR_PHY_TXPWRADJ_CCK_GAIN_DELTA) | SM((cckOfdmPwrDelta*-1), AR_PHY_TXPWRADJ_CCK_PCDAC_INDEX)); } else { OS_REG_WRITE(ah, AR_PHY_TXPWRADJ, 0); } /* Add barker RSSI thresh enable as disabled */ OS_REG_CLR_BIT(ah, AR_PHY_DAG_CTRLCCK, AR_PHY_DAG_CTRLCCK_EN_RSSI_THR); OS_REG_RMW_FIELD(ah, AR_PHY_DAG_CTRLCCK, AR_PHY_DAG_CTRLCCK_RSSI_THR, 2); /* Set the mute mask to the correct default */ OS_REG_WRITE(ah, AR_SEQ_MASK, 0x0000000F); } if (AH_PRIVATE(ah)->ah_phyRev >= AR_PHY_CHIP_ID_REV_3) { /* Clear reg to alllow RX_CLEAR line debug */ OS_REG_WRITE(ah, AR_PHY_BLUETOOTH, 0); } if (AH_PRIVATE(ah)->ah_phyRev >= AR_PHY_CHIP_ID_REV_4) { #ifdef notyet /* Enable burst prefetch for the data queues */ OS_REG_RMW_FIELD(ah, AR_D_FPCTL, ... ); /* Enable double-buffering */ OS_REG_CLR_BIT(ah, AR_TXCFG, AR_TXCFG_DBL_BUF_DIS); #endif } if (IS_5312_2_X(ah)) { /* ADC_CTRL */ OS_REG_WRITE(ah, AR_PHY_SIGMA_DELTA, SM(2, AR_PHY_SIGMA_DELTA_ADC_SEL) | SM(4, AR_PHY_SIGMA_DELTA_FILT2) | SM(0x16, AR_PHY_SIGMA_DELTA_FILT1) | SM(0, AR_PHY_SIGMA_DELTA_ADC_CLIP)); if (IEEE80211_IS_CHAN_2GHZ(chan)) OS_REG_RMW_FIELD(ah, AR_PHY_RXGAIN, AR_PHY_RXGAIN_TXRX_RF_MAX, 0x0F); /* CCK Short parameter adjustment in 11B mode */ if (IEEE80211_IS_CHAN_B(chan)) OS_REG_RMW_FIELD(ah, AR_PHY_CCK_RXCTRL4, AR_PHY_CCK_RXCTRL4_FREQ_EST_SHORT, 12); /* Set ADC/DAC select values */ OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x04); /* Increase 11A AGC Settling */ if (IEEE80211_IS_CHAN_A(chan)) OS_REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_AGC, 32); } else { /* Set ADC/DAC select values */ OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0e); } /* Setup the transmit power values. */ if (!ar5212SetTransmitPower(ah, chan, rfXpdGain)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: error init'ing transmit power\n", __func__); FAIL(HAL_EIO); } /* Write the analog registers */ if (!ahp->ah_rfHal->setRfRegs(ah, chan, modesIndex, rfXpdGain)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: ar5212SetRfRegs failed\n", __func__); FAIL(HAL_EIO); } /* Write delta slope for OFDM enabled modes (A, G, Turbo) */ if (IEEE80211_IS_CHAN_OFDM(chan)) { if (IS_5413(ah) || AH_PRIVATE(ah)->ah_eeversion >= AR_EEPROM_VER5_3) ar5212SetSpurMitigation(ah, chan); ar5212SetDeltaSlope(ah, chan); } /* Setup board specific options for EEPROM version 3 */ if (!ar5212SetBoardValues(ah, chan)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: error setting board options\n", __func__); FAIL(HAL_EIO); } /* Restore certain DMA hardware registers on a channel change */ if (bChannelChange) OS_REG_WRITE(ah, AR_D_SEQNUM, saveFrameSeqCount); OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__); OS_REG_WRITE(ah, AR_STA_ID0, LE_READ_4(ahp->ah_macaddr)); OS_REG_WRITE(ah, AR_STA_ID1, LE_READ_2(ahp->ah_macaddr + 4) | macStaId1 | AR_STA_ID1_RTS_USE_DEF | ahp->ah_staId1Defaults ); ar5212SetOperatingMode(ah, opmode); /* Set Venice BSSID mask according to current state */ OS_REG_WRITE(ah, AR_BSSMSKL, LE_READ_4(ahp->ah_bssidmask)); OS_REG_WRITE(ah, AR_BSSMSKU, LE_READ_2(ahp->ah_bssidmask + 4)); /* Restore previous led state */ if (!IS_5315(ah)) OS_REG_WRITE(ah, AR5312_PCICFG, OS_REG_READ(ah, AR_PCICFG) | saveLedState); /* Restore previous antenna */ OS_REG_WRITE(ah, AR_DEF_ANTENNA, saveDefAntenna); /* then our BSSID */ OS_REG_WRITE(ah, AR_BSS_ID0, LE_READ_4(ahp->ah_bssid)); OS_REG_WRITE(ah, AR_BSS_ID1, LE_READ_2(ahp->ah_bssid + 4)); /* Restore bmiss rssi & count thresholds */ OS_REG_WRITE(ah, AR_RSSI_THR, ahp->ah_rssiThr); OS_REG_WRITE(ah, AR_ISR, ~0); /* cleared on write */ if (!ar5212SetChannel(ah, chan)) FAIL(HAL_EIO); OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__); ar5212SetCoverageClass(ah, AH_PRIVATE(ah)->ah_coverageClass, 1); ar5212SetRateDurationTable(ah, chan); /* Set Tx frame start to tx data start delay */ if (IS_RAD5112_ANY(ah) && (IEEE80211_IS_CHAN_HALF(chan) || IEEE80211_IS_CHAN_QUARTER(chan))) { txFrm2TxDStart = IEEE80211_IS_CHAN_HALF(chan) ? TX_FRAME_D_START_HALF_RATE: TX_FRAME_D_START_QUARTER_RATE; OS_REG_RMW_FIELD(ah, AR_PHY_TX_CTL, AR_PHY_TX_FRAME_TO_TX_DATA_START, txFrm2TxDStart); } /* * Setup fast diversity. * Fast diversity can be enabled or disabled via regadd.txt. * Default is enabled. * For reference, * Disable: reg val * 0x00009860 0x00009d18 (if 11a / 11g, else no change) * 0x00009970 0x192bb514 * 0x0000a208 0xd03e4648 * * Enable: 0x00009860 0x00009d10 (if 11a / 11g, else no change) * 0x00009970 0x192fb514 * 0x0000a208 0xd03e6788 */ /* XXX Setup pre PHY ENABLE EAR additions */ /* flush SCAL reg */ if (IS_5312_2_X(ah)) { (void) OS_REG_READ(ah, AR_PHY_SLEEP_SCAL); } /* * Wait for the frequency synth to settle (synth goes on * via AR_PHY_ACTIVE_EN). Read the phy active delay register. * Value is in 100ns increments. */ synthDelay = OS_REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY; if (IEEE80211_IS_CHAN_B(chan)) { synthDelay = (4 * synthDelay) / 22; } else { synthDelay /= 10; } /* Activate the PHY (includes baseband activate and synthesizer on) */ OS_REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); /* * There is an issue if the AP starts the calibration before * the base band timeout completes. This could result in the * rx_clear false triggering. As a workaround we add delay an * extra BASE_ACTIVATE_DELAY usecs to ensure this condition * does not happen. */ if (IEEE80211_IS_CHAN_HALF(chan)) { OS_DELAY((synthDelay << 1) + BASE_ACTIVATE_DELAY); } else if (IEEE80211_IS_CHAN_QUARTER(chan)) { OS_DELAY((synthDelay << 2) + BASE_ACTIVATE_DELAY); } else { OS_DELAY(synthDelay + BASE_ACTIVATE_DELAY); } /* * The udelay method is not reliable with notebooks. * Need to check to see if the baseband is ready */ testReg = OS_REG_READ(ah, AR_PHY_TESTCTRL); /* Selects the Tx hold */ OS_REG_WRITE(ah, AR_PHY_TESTCTRL, AR_PHY_TESTCTRL_TXHOLD); i = 0; while ((i++ < 20) && (OS_REG_READ(ah, 0x9c24) & 0x10)) /* test if baseband not ready */ OS_DELAY(200); OS_REG_WRITE(ah, AR_PHY_TESTCTRL, testReg); /* Calibrate the AGC and start a NF calculation */ OS_REG_WRITE(ah, AR_PHY_AGC_CONTROL, OS_REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_CAL | AR_PHY_AGC_CONTROL_NF); if (!IEEE80211_IS_CHAN_B(chan) && ahp->ah_bIQCalibration != IQ_CAL_DONE) { /* Start IQ calibration w/ 2^(INIT_IQCAL_LOG_COUNT_MAX+1) samples */ OS_REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4, AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX, INIT_IQCAL_LOG_COUNT_MAX); OS_REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4, AR_PHY_TIMING_CTRL4_DO_IQCAL); ahp->ah_bIQCalibration = IQ_CAL_RUNNING; } else ahp->ah_bIQCalibration = IQ_CAL_INACTIVE; /* Setup compression registers */ ar5212SetCompRegs(ah); /* Set 1:1 QCU to DCU mapping for all queues */ for (i = 0; i < AR_NUM_DCU; i++) OS_REG_WRITE(ah, AR_DQCUMASK(i), 1 << i); ahp->ah_intrTxqs = 0; for (i = 0; i < AH_PRIVATE(ah)->ah_caps.halTotalQueues; i++) ar5212ResetTxQueue(ah, i); /* * Setup interrupt handling. Note that ar5212ResetTxQueue * manipulates the secondary IMR's as queues are enabled * and disabled. This is done with RMW ops to insure the * settings we make here are preserved. */ ahp->ah_maskReg = AR_IMR_TXOK | AR_IMR_TXERR | AR_IMR_TXURN | AR_IMR_RXOK | AR_IMR_RXERR | AR_IMR_RXORN | AR_IMR_HIUERR ; if (opmode == HAL_M_HOSTAP) ahp->ah_maskReg |= AR_IMR_MIB; OS_REG_WRITE(ah, AR_IMR, ahp->ah_maskReg); /* Enable bus errors that are OR'd to set the HIUERR bit */ OS_REG_WRITE(ah, AR_IMR_S2, OS_REG_READ(ah, AR_IMR_S2) | AR_IMR_S2_MCABT | AR_IMR_S2_SSERR | AR_IMR_S2_DPERR); if (AH_PRIVATE(ah)->ah_rfkillEnabled) ar5212EnableRfKill(ah); if (!ath_hal_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: offset calibration failed to complete in 1ms;" " noisy environment?\n", __func__); } /* * Set clocks back to 32kHz if they had been using refClk, then * use an external 32kHz crystal when sleeping, if one exists. */ ar5312SetupClock(ah, opmode); /* * Writing to AR_BEACON will start timers. Hence it should * be the last register to be written. Do not reset tsf, do * not enable beacons at this point, but preserve other values * like beaconInterval. */ OS_REG_WRITE(ah, AR_BEACON, (OS_REG_READ(ah, AR_BEACON) &~ (AR_BEACON_EN | AR_BEACON_RESET_TSF))); /* XXX Setup post reset EAR additions */ /* QoS support */ if (AH_PRIVATE(ah)->ah_macVersion > AR_SREV_VERSION_VENICE || (AH_PRIVATE(ah)->ah_macVersion == AR_SREV_VERSION_VENICE && AH_PRIVATE(ah)->ah_macRev >= AR_SREV_GRIFFIN_LITE)) { OS_REG_WRITE(ah, AR_QOS_CONTROL, 0x100aa); /* XXX magic */ OS_REG_WRITE(ah, AR_QOS_SELECT, 0x3210); /* XXX magic */ } /* Turn on NOACK Support for QoS packets */ OS_REG_WRITE(ah, AR_NOACK, SM(2, AR_NOACK_2BIT_VALUE) | SM(5, AR_NOACK_BIT_OFFSET) | SM(0, AR_NOACK_BYTE_OFFSET)); /* Restore user-specified settings */ if (ahp->ah_miscMode != 0) OS_REG_WRITE(ah, AR_MISC_MODE, ahp->ah_miscMode); if (ahp->ah_slottime != (u_int) -1) ar5212SetSlotTime(ah, ahp->ah_slottime); if (ahp->ah_acktimeout != (u_int) -1) ar5212SetAckTimeout(ah, ahp->ah_acktimeout); if (ahp->ah_ctstimeout != (u_int) -1) ar5212SetCTSTimeout(ah, ahp->ah_ctstimeout); if (ahp->ah_sifstime != (u_int) -1) ar5212SetSifsTime(ah, ahp->ah_sifstime); if (AH_PRIVATE(ah)->ah_diagreg != 0) OS_REG_WRITE(ah, AR_DIAG_SW, AH_PRIVATE(ah)->ah_diagreg); AH_PRIVATE(ah)->ah_opmode = opmode; /* record operating mode */ if (bChannelChange && !IEEE80211_IS_CHAN_DFS(chan)) chan->ic_state &= ~IEEE80211_CHANSTATE_CWINT; HALDEBUG(ah, HAL_DEBUG_RESET, "%s: done\n", __func__); OS_MARK(ah, AH_MARK_RESET_DONE, 0); return AH_TRUE; bad: OS_MARK(ah, AH_MARK_RESET_DONE, ecode); if (status != AH_NULL) *status = ecode; return AH_FALSE; #undef FAIL #undef N }
/* * Reads the Interrupt Status Register value from the NIC, thus deasserting * the interrupt line, and returns both the masked and unmasked mapped ISR * values. The value returned is mapped to abstract the hw-specific bit * locations in the Interrupt Status Register. * * Returns: A hardware-abstracted bitmap of all non-masked-out * interrupts pending, as well as an unmasked value */ HAL_BOOL ar5416GetPendingInterrupts(struct ath_hal *ah, HAL_INT *masked) { uint32_t isr, isr0, isr1, sync_cause; /* * Verify there's a mac interrupt and the RTC is on. */ if ((OS_REG_READ(ah, AR_INTR_ASYNC_CAUSE) & AR_INTR_MAC_IRQ) && (OS_REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M) == AR_RTC_STATUS_ON) isr = OS_REG_READ(ah, AR_ISR); else isr = 0; sync_cause = OS_REG_READ(ah, AR_INTR_SYNC_CAUSE); sync_cause &= AR_INTR_SYNC_DEFAULT; if (isr == 0 && sync_cause == 0) { *masked = 0; return AH_FALSE; } if (isr != 0) { struct ath_hal_5212 *ahp = AH5212(ah); uint32_t mask2; mask2 = 0; if (isr & AR_ISR_BCNMISC) { uint32_t isr2 = OS_REG_READ(ah, AR_ISR_S2); if (isr2 & AR_ISR_S2_TIM) mask2 |= HAL_INT_TIM; if (isr2 & AR_ISR_S2_DTIM) mask2 |= HAL_INT_DTIM; if (isr2 & AR_ISR_S2_DTIMSYNC) mask2 |= HAL_INT_DTIMSYNC; if (isr2 & (AR_ISR_S2_CABEND )) mask2 |= HAL_INT_CABEND; if (isr2 & AR_ISR_S2_GTT) mask2 |= HAL_INT_GTT; if (isr2 & AR_ISR_S2_CST) mask2 |= HAL_INT_CST; if (isr2 & AR_ISR_S2_TSFOOR) mask2 |= HAL_INT_TSFOOR; } isr = OS_REG_READ(ah, AR_ISR_RAC); if (isr == 0xffffffff) { *masked = 0; return AH_FALSE;; } *masked = isr & HAL_INT_COMMON; if (isr & (AR_ISR_RXOK | AR_ISR_RXERR)) *masked |= HAL_INT_RX; if (isr & (AR_ISR_TXOK | AR_ISR_TXDESC | AR_ISR_TXERR | AR_ISR_TXEOL)) { *masked |= HAL_INT_TX; isr0 = OS_REG_READ(ah, AR_ISR_S0_S); ahp->ah_intrTxqs |= MS(isr0, AR_ISR_S0_QCU_TXOK); ahp->ah_intrTxqs |= MS(isr0, AR_ISR_S0_QCU_TXDESC); isr1 = OS_REG_READ(ah, AR_ISR_S1_S); ahp->ah_intrTxqs |= MS(isr1, AR_ISR_S1_QCU_TXERR); ahp->ah_intrTxqs |= MS(isr1, AR_ISR_S1_QCU_TXEOL); } /* Interrupt Mitigation on AR5416 */ #ifdef AR5416_INT_MITIGATION if (isr & (AR_ISR_RXMINTR | AR_ISR_RXINTM)) *masked |= HAL_INT_RX; if (isr & (AR_ISR_TXMINTR | AR_ISR_TXINTM)) *masked |= HAL_INT_TX; #endif *masked |= mask2; } if (sync_cause != 0) { if (sync_cause & (AR_INTR_SYNC_HOST1_FATAL | AR_INTR_SYNC_HOST1_PERR)) { *masked |= HAL_INT_FATAL; } if (sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: RADM CPL timeout\n", __func__); OS_REG_WRITE(ah, AR_RC, AR_RC_HOSTIF); OS_REG_WRITE(ah, AR_RC, 0); *masked |= HAL_INT_FATAL; } /* * On fatal errors collect ISR state for debugging. */ if (*masked & HAL_INT_FATAL) { AH_PRIVATE(ah)->ah_fatalState[0] = isr; AH_PRIVATE(ah)->ah_fatalState[1] = sync_cause; HALDEBUG(ah, HAL_DEBUG_ANY, "%s: fatal error, ISR_RAC 0x%x SYNC_CAUSE 0x%x\n", __func__, isr, sync_cause); } OS_REG_WRITE(ah, AR_INTR_SYNC_CAUSE_CLR, sync_cause); /* NB: flush write */ (void) OS_REG_READ(ah, AR_INTR_SYNC_CAUSE_CLR); } return AH_TRUE; }
/* * Process an RX descriptor, and return the status to the caller. * Copy some hardware specific items into the software portion * of the descriptor. * * NB: the caller is responsible for validating the memory contents * of the descriptor (e.g. flushing any cached copy). */ HAL_STATUS ar9300_proc_rx_desc_fast(struct ath_hal *ah, struct ath_desc *ds, u_int32_t pa, struct ath_desc *nds, struct ath_rx_status *rxs, void *buf_addr) { struct ar9300_rxs *rxsp = AR9300RXS(buf_addr); /* ath_hal_printf(ah,"CHH=RX: ds_info 0x%x status1: 0x%x status11: 0x%x\n", rxsp->ds_info,rxsp->status1,rxsp->status11); */ if ((rxsp->status11 & AR_rx_done) == 0) { return HAL_EINPROGRESS; } if (MS(rxsp->ds_info, AR_desc_id) != 0x168c) { #if __PKT_SERIOUS_ERRORS__ /*BUG: 63564-HT */ HALDEBUG(AH_NULL, HAL_DEBUG_UNMASKABLE, "%s: Rx Descriptor error 0x%x\n", __func__, rxsp->ds_info); #endif return HAL_EINVAL; } if ((rxsp->ds_info & (AR_tx_rx_desc | AR_ctrl_stat)) != 0) { #if __PKT_SERIOUS_ERRORS__ HALDEBUG(AH_NULL, HAL_DEBUG_UNMASKABLE, "%s: Rx Descriptor wrong info 0x%x\n", __func__, rxsp->ds_info); #endif return HAL_EINPROGRESS; } rxs->rs_status = 0; rxs->rs_flags = 0; rxs->rs_phyerr = 0; rxs->rs_datalen = rxsp->status2 & AR_data_len; rxs->rs_tstamp = rxsp->status3; /* XXX what about key_cache_miss? */ rxs->rs_rssi = MS(rxsp->status5, AR_rx_rssi_combined); rxs->rs_rssi_ctl0 = MS(rxsp->status1, AR_rx_rssi_ant00); rxs->rs_rssi_ctl1 = MS(rxsp->status1, AR_rx_rssi_ant01); rxs->rs_rssi_ctl2 = MS(rxsp->status1, AR_rx_rssi_ant02); rxs->rs_rssi_ext0 = MS(rxsp->status5, AR_rx_rssi_ant10); rxs->rs_rssi_ext1 = MS(rxsp->status5, AR_rx_rssi_ant11); rxs->rs_rssi_ext2 = MS(rxsp->status5, AR_rx_rssi_ant12); if (rxsp->status11 & AR_rx_key_idx_valid) { rxs->rs_keyix = MS(rxsp->status11, AR_key_idx); } else { rxs->rs_keyix = HAL_RXKEYIX_INVALID; } /* NB: caller expected to do rate table mapping */ rxs->rs_rate = MS(rxsp->status1, AR_rx_rate); rxs->rs_more = (rxsp->status2 & AR_rx_more) ? 1 : 0; rxs->rs_isaggr = (rxsp->status11 & AR_rx_aggr) ? 1 : 0; rxs->rs_moreaggr = (rxsp->status11 & AR_rx_more_aggr) ? 1 : 0; rxs->rs_antenna = (MS(rxsp->status4, AR_rx_antenna) & 0x7); rxs->rs_isapsd = (rxsp->status11 & AR_apsd_trig) ? 1 : 0; rxs->rs_flags = (rxsp->status4 & AR_gi) ? HAL_RX_GI : 0; rxs->rs_flags |= (rxsp->status4 & AR_2040) ? HAL_RX_2040 : 0; /* Copy EVM information */ rxs->evm0 = rxsp->status6; rxs->evm1 = rxsp->status7; rxs->evm2 = rxsp->status8; rxs->evm3 = rxsp->status9; rxs->evm4 = (rxsp->status10 & 0xffff); if (rxsp->status11 & AR_pre_delim_crc_err) { rxs->rs_flags |= HAL_RX_DELIM_CRC_PRE; } if (rxsp->status11 & AR_post_delim_crc_err) { rxs->rs_flags |= HAL_RX_DELIM_CRC_POST; } if (rxsp->status11 & AR_decrypt_busy_err) { rxs->rs_flags |= HAL_RX_DECRYPT_BUSY; } if (rxsp->status11 & AR_hi_rx_chain) { rxs->rs_flags |= HAL_RX_HI_RX_CHAIN; } if (rxsp->status11 & AR_key_miss) { rxs->rs_status |= HAL_RXERR_KEYMISS; } if ((rxsp->status11 & AR_rx_frame_ok) == 0) { /* * These four bits should not be set together. The * 9300 spec states a Michael error can only occur if * decrypt_crc_err not set (and TKIP is used). Experience * indicates however that you can also get Michael errors * when a CRC error is detected, but these are specious. * Consequently we filter them out here so we don't * confuse and/or complicate drivers. */ if (rxsp->status11 & AR_crc_err) { rxs->rs_status |= HAL_RXERR_CRC; /* * ignore CRC flag for phy reports */ if (rxsp->status11 & AR_phyerr) { u_int phyerr = MS(rxsp->status11, AR_phy_err_code); rxs->rs_status |= HAL_RXERR_PHY; rxs->rs_phyerr = phyerr; } } else if (rxsp->status11 & AR_phyerr) { u_int phyerr; /* * Packets with OFDM_RESTART on post delimiter are CRC OK and * usable and MAC ACKs them. * To avoid packet from being lost, we remove the PHY Err flag * so that lmac layer does not drop them. * (EV 70071) */ phyerr = MS(rxsp->status11, AR_phy_err_code); if ((phyerr == HAL_PHYERR_OFDM_RESTART) && (rxsp->status11 & AR_post_delim_crc_err)) { rxs->rs_phyerr = 0; } else { rxs->rs_status |= HAL_RXERR_PHY; rxs->rs_phyerr = phyerr; } } else if (rxsp->status11 & AR_decrypt_crc_err) { rxs->rs_status |= HAL_RXERR_DECRYPT; } else if (rxsp->status11 & AR_michael_err) { rxs->rs_status |= HAL_RXERR_MIC; } } rxs->rs_channel = AH_PRIVATE(ah)->ah_curchan->channel; return HAL_OK; }
/* * Take the MHz channel value and set the Channel value * * ASSUMES: Writes enabled to analog bus */ static HAL_BOOL ar2316SetChannel(struct ath_hal *ah, struct ieee80211_channel *chan) { uint16_t freq = ath_hal_gethwchannel(ah, chan); uint32_t channelSel = 0; uint32_t bModeSynth = 0; uint32_t aModeRefSel = 0; uint32_t reg32 = 0; OS_MARK(ah, AH_MARK_SETCHANNEL, freq); if (freq < 4800) { uint32_t txctl; if (((freq - 2192) % 5) == 0) { channelSel = ((freq - 672) * 2 - 3040)/10; bModeSynth = 0; } else if (((freq - 2224) % 5) == 0) { channelSel = ((freq - 704) * 2 - 3040) / 10; bModeSynth = 1; } else { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel %u MHz\n", __func__, freq); return AH_FALSE; } channelSel = (channelSel << 2) & 0xff; channelSel = ath_hal_reverseBits(channelSel, 8); txctl = OS_REG_READ(ah, AR_PHY_CCK_TX_CTRL); if (freq == 2484) { /* Enable channel spreading for channel 14 */ OS_REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, txctl | AR_PHY_CCK_TX_CTRL_JAPAN); } else { OS_REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, txctl &~ AR_PHY_CCK_TX_CTRL_JAPAN); } } else if ((freq % 20) == 0 && freq >= 5120) { channelSel = ath_hal_reverseBits( ((freq - 4800) / 20 << 2), 8); aModeRefSel = ath_hal_reverseBits(3, 2); } else if ((freq % 10) == 0) { channelSel = ath_hal_reverseBits( ((freq - 4800) / 10 << 1), 8); aModeRefSel = ath_hal_reverseBits(2, 2); } else if ((freq % 5) == 0) { channelSel = ath_hal_reverseBits( (freq - 4800) / 5, 8); aModeRefSel = ath_hal_reverseBits(1, 2); } else { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel %u MHz\n", __func__, freq); return AH_FALSE; } reg32 = (channelSel << 4) | (aModeRefSel << 2) | (bModeSynth << 1) | (1 << 12) | 0x1; OS_REG_WRITE(ah, AR_PHY(0x27), reg32 & 0xff); reg32 >>= 8; OS_REG_WRITE(ah, AR_PHY(0x36), reg32 & 0x7f); AH_PRIVATE(ah)->ah_curchan = chan; return AH_TRUE; }
/* * Set the retry, aifs, cwmin/max, readyTime regs for specified queue */ HAL_BOOL ar5211ResetTxQueue(struct ath_hal *ah, u_int q) { struct ath_hal_5211 *ahp = AH5211(ah); const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan; HAL_TX_QUEUE_INFO *qi; uint32_t cwMin, chanCwMin, value; if (q >= HAL_NUM_TX_QUEUES) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n", __func__, q); return AH_FALSE; } qi = &ahp->ah_txq[q]; if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) { HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: inactive queue %u\n", __func__, q); return AH_TRUE; /* XXX??? */ } if (qi->tqi_cwmin == HAL_TXQ_USEDEFAULT) { /* * Select cwmin according to channel type. * NB: chan can be NULL during attach */ if (chan && IEEE80211_IS_CHAN_B(chan)) chanCwMin = INIT_CWMIN_11B; else chanCwMin = INIT_CWMIN; /* make sure that the CWmin is of the form (2^n - 1) */ for (cwMin = 1; cwMin < chanCwMin; cwMin = (cwMin << 1) | 1) ; } else cwMin = qi->tqi_cwmin; /* set cwMin/Max and AIFS values */ OS_REG_WRITE(ah, AR_DLCL_IFS(q), SM(cwMin, AR_D_LCL_IFS_CWMIN) | SM(qi->tqi_cwmax, AR_D_LCL_IFS_CWMAX) | SM(qi->tqi_aifs, AR_D_LCL_IFS_AIFS)); /* Set retry limit values */ OS_REG_WRITE(ah, AR_DRETRY_LIMIT(q), SM(INIT_SSH_RETRY, AR_D_RETRY_LIMIT_STA_SH) | SM(INIT_SLG_RETRY, AR_D_RETRY_LIMIT_STA_LG) | SM(qi->tqi_lgretry, AR_D_RETRY_LIMIT_FR_LG) | SM(qi->tqi_shretry, AR_D_RETRY_LIMIT_FR_SH) ); /* enable early termination on the QCU */ OS_REG_WRITE(ah, AR_QMISC(q), AR_Q_MISC_DCU_EARLY_TERM_REQ); if (AH_PRIVATE(ah)->ah_macVersion < AR_SREV_VERSION_OAHU) { /* Configure DCU to use the global sequence count */ OS_REG_WRITE(ah, AR_DMISC(q), AR5311_D_MISC_SEQ_NUM_CONTROL); } /* multiqueue support */ if (qi->tqi_cbrPeriod) { OS_REG_WRITE(ah, AR_QCBRCFG(q), SM(qi->tqi_cbrPeriod,AR_Q_CBRCFG_CBR_INTERVAL) | SM(qi->tqi_cbrOverflowLimit, AR_Q_CBRCFG_CBR_OVF_THRESH)); OS_REG_WRITE(ah, AR_QMISC(q), OS_REG_READ(ah, AR_QMISC(q)) | AR_Q_MISC_FSP_CBR | (qi->tqi_cbrOverflowLimit ? AR_Q_MISC_CBR_EXP_CNTR_LIMIT : 0)); } if (qi->tqi_readyTime) { OS_REG_WRITE(ah, AR_QRDYTIMECFG(q), SM(qi->tqi_readyTime, AR_Q_RDYTIMECFG_INT) | AR_Q_RDYTIMECFG_EN); } if (qi->tqi_burstTime) { OS_REG_WRITE(ah, AR_DCHNTIME(q), SM(qi->tqi_burstTime, AR_D_CHNTIME_DUR) | AR_D_CHNTIME_EN); if (qi->tqi_qflags & HAL_TXQ_RDYTIME_EXP_POLICY_ENABLE) { OS_REG_WRITE(ah, AR_QMISC(q), OS_REG_READ(ah, AR_QMISC(q)) | AR_Q_MISC_RDYTIME_EXP_POLICY); } } if (qi->tqi_qflags & HAL_TXQ_BACKOFF_DISABLE) { OS_REG_WRITE(ah, AR_DMISC(q), OS_REG_READ(ah, AR_DMISC(q)) | AR_D_MISC_POST_FR_BKOFF_DIS); } if (qi->tqi_qflags & HAL_TXQ_FRAG_BURST_BACKOFF_ENABLE) { OS_REG_WRITE(ah, AR_DMISC(q), OS_REG_READ(ah, AR_DMISC(q)) | AR_D_MISC_FRAG_BKOFF_EN); } switch (qi->tqi_type) { case HAL_TX_QUEUE_BEACON: /* Configure QCU for beacons */ OS_REG_WRITE(ah, AR_QMISC(q), OS_REG_READ(ah, AR_QMISC(q)) | AR_Q_MISC_FSP_DBA_GATED | AR_Q_MISC_BEACON_USE | AR_Q_MISC_CBR_INCR_DIS1); /* Configure DCU for beacons */ value = (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL << AR_D_MISC_ARB_LOCKOUT_CNTRL_S) | AR_D_MISC_BEACON_USE | AR_D_MISC_POST_FR_BKOFF_DIS; if (AH_PRIVATE(ah)->ah_macVersion < AR_SREV_VERSION_OAHU) value |= AR5311_D_MISC_SEQ_NUM_CONTROL; OS_REG_WRITE(ah, AR_DMISC(q), value); break; case HAL_TX_QUEUE_CAB: /* Configure QCU for CAB (Crap After Beacon) frames */ OS_REG_WRITE(ah, AR_QMISC(q), OS_REG_READ(ah, AR_QMISC(q)) | AR_Q_MISC_FSP_DBA_GATED | AR_Q_MISC_CBR_INCR_DIS1 | AR_Q_MISC_CBR_INCR_DIS0 | AR_Q_MISC_RDYTIME_EXP_POLICY); value = (ahp->ah_beaconInterval - (ah->ah_config.ah_sw_beacon_response_time - ah->ah_config.ah_dma_beacon_response_time) - ah->ah_config.ah_additional_swba_backoff) * 1024; OS_REG_WRITE(ah, AR_QRDYTIMECFG(q), value | AR_Q_RDYTIMECFG_EN); /* Configure DCU for CAB */ value = (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL << AR_D_MISC_ARB_LOCKOUT_CNTRL_S); if (AH_PRIVATE(ah)->ah_macVersion < AR_SREV_VERSION_OAHU) value |= AR5311_D_MISC_SEQ_NUM_CONTROL; OS_REG_WRITE(ah, AR_QMISC(q), value); break; default: /* NB: silence compiler */ break; } /* * Always update the secondary interrupt mask registers - this * could be a new queue getting enabled in a running system or * hw getting re-initialized during a reset! * * Since we don't differentiate between tx interrupts corresponding * to individual queues - secondary tx mask regs are always unmasked; * tx interrupts are enabled/disabled for all queues collectively * using the primary mask reg */ if (qi->tqi_qflags & HAL_TXQ_TXOKINT_ENABLE) ahp->ah_txOkInterruptMask |= 1 << q; else ahp->ah_txOkInterruptMask &= ~(1 << q); if (qi->tqi_qflags & HAL_TXQ_TXERRINT_ENABLE) ahp->ah_txErrInterruptMask |= 1 << q; else ahp->ah_txErrInterruptMask &= ~(1 << q); if (qi->tqi_qflags & HAL_TXQ_TXDESCINT_ENABLE) ahp->ah_txDescInterruptMask |= 1 << q; else ahp->ah_txDescInterruptMask &= ~(1 << q); if (qi->tqi_qflags & HAL_TXQ_TXEOLINT_ENABLE) ahp->ah_txEolInterruptMask |= 1 << q; else ahp->ah_txEolInterruptMask &= ~(1 << q); if (qi->tqi_qflags & HAL_TXQ_TXURNINT_ENABLE) ahp->ah_txUrnInterruptMask |= 1 << q; else ahp->ah_txUrnInterruptMask &= ~(1 << q); setTxQInterrupts(ah, qi); return AH_TRUE; }
/* * Set the GPIO Interrupt Sync and Async interrupts are both set/cleared. * Async GPIO interrupts may not be raised when the chip is put to sleep. */ void ar5416GpioSetIntr(struct ath_hal *ah, u_int gpio, uint32_t ilevel) { uint32_t val, mask; HALASSERT(gpio < AH_PRIVATE(ah)->ah_caps.halNumGpioPins); if (ilevel == HAL_GPIO_INTR_DISABLE) { val = MS(OS_REG_READ(ah, AR_INTR_ASYNC_ENABLE), AR_INTR_ASYNC_ENABLE_GPIO) &~ AR_GPIO_BIT(gpio); OS_REG_RMW_FIELD(ah, AR_INTR_ASYNC_ENABLE, AR_INTR_ASYNC_ENABLE_GPIO, val); mask = MS(OS_REG_READ(ah, AR_INTR_ASYNC_MASK), AR_INTR_ASYNC_MASK_GPIO) &~ AR_GPIO_BIT(gpio); OS_REG_RMW_FIELD(ah, AR_INTR_ASYNC_MASK, AR_INTR_ASYNC_MASK_GPIO, mask); /* Clear synchronous GPIO interrupt registers and pending interrupt flag */ val = MS(OS_REG_READ(ah, AR_INTR_SYNC_ENABLE), AR_INTR_SYNC_ENABLE_GPIO) &~ AR_GPIO_BIT(gpio); OS_REG_RMW_FIELD(ah, AR_INTR_SYNC_ENABLE, AR_INTR_SYNC_ENABLE_GPIO, val); mask = MS(OS_REG_READ(ah, AR_INTR_SYNC_MASK), AR_INTR_SYNC_MASK_GPIO) &~ AR_GPIO_BIT(gpio); OS_REG_RMW_FIELD(ah, AR_INTR_SYNC_MASK, AR_INTR_SYNC_MASK_GPIO, mask); val = MS(OS_REG_READ(ah, AR_INTR_SYNC_CAUSE), AR_INTR_SYNC_ENABLE_GPIO) | AR_GPIO_BIT(gpio); OS_REG_RMW_FIELD(ah, AR_INTR_SYNC_CAUSE, AR_INTR_SYNC_ENABLE_GPIO, val); } else { val = MS(OS_REG_READ(ah, AR_GPIO_INTR_POL), AR_GPIO_INTR_POL_VAL); if (ilevel == HAL_GPIO_INTR_HIGH) { /* 0 == interrupt on pin high */ val &= ~AR_GPIO_BIT(gpio); } else if (ilevel == HAL_GPIO_INTR_LOW) { /* 1 == interrupt on pin low */ val |= AR_GPIO_BIT(gpio); } OS_REG_RMW_FIELD(ah, AR_GPIO_INTR_POL, AR_GPIO_INTR_POL_VAL, val); /* Change the interrupt mask. */ val = MS(OS_REG_READ(ah, AR_INTR_ASYNC_ENABLE), AR_INTR_ASYNC_ENABLE_GPIO) | AR_GPIO_BIT(gpio); OS_REG_RMW_FIELD(ah, AR_INTR_ASYNC_ENABLE, AR_INTR_ASYNC_ENABLE_GPIO, val); mask = MS(OS_REG_READ(ah, AR_INTR_ASYNC_MASK), AR_INTR_ASYNC_MASK_GPIO) | AR_GPIO_BIT(gpio); OS_REG_RMW_FIELD(ah, AR_INTR_ASYNC_MASK, AR_INTR_ASYNC_MASK_GPIO, mask); /* Set synchronous GPIO interrupt registers as well */ val = MS(OS_REG_READ(ah, AR_INTR_SYNC_ENABLE), AR_INTR_SYNC_ENABLE_GPIO) | AR_GPIO_BIT(gpio); OS_REG_RMW_FIELD(ah, AR_INTR_SYNC_ENABLE, AR_INTR_SYNC_ENABLE_GPIO, val); mask = MS(OS_REG_READ(ah, AR_INTR_SYNC_MASK), AR_INTR_SYNC_MASK_GPIO) | AR_GPIO_BIT(gpio); OS_REG_RMW_FIELD(ah, AR_INTR_SYNC_MASK, AR_INTR_SYNC_MASK_GPIO, mask); } AH5416(ah)->ah_gpioMask = mask; /* for ar5416SetInterrupts */ }
static HAL_STATUS v4kEepromGet(struct ath_hal *ah, int param, void *val) { #define CHAN_A_IDX 0 #define CHAN_B_IDX 1 #define IS_VERS(op, v) ((pBase->version & AR5416_EEP_VER_MINOR_MASK) op (v)) HAL_EEPROM_v4k *ee = AH_PRIVATE(ah)->ah_eeprom; const MODAL_EEP4K_HEADER *pModal = &ee->ee_base.modalHeader; const BASE_EEP4K_HEADER *pBase = &ee->ee_base.baseEepHeader; uint32_t sum; uint8_t *macaddr; int i; switch (param) { case AR_EEP_NFTHRESH_2: *(int16_t *)val = pModal->noiseFloorThreshCh[0]; return HAL_OK; case AR_EEP_MACADDR: /* Get MAC Address */ sum = 0; macaddr = val; for (i = 0; i < 6; i++) { macaddr[i] = pBase->macAddr[i]; sum += pBase->macAddr[i]; } if (sum == 0 || sum == 0xffff*3) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad mac address %s\n", __func__, ath_hal_ether_sprintf(macaddr)); return HAL_EEBADMAC; } return HAL_OK; case AR_EEP_REGDMN_0: return pBase->regDmn[0]; case AR_EEP_REGDMN_1: return pBase->regDmn[1]; case AR_EEP_OPCAP: return pBase->deviceCap; case AR_EEP_OPMODE: return pBase->opCapFlags; case AR_EEP_RFSILENT: return pBase->rfSilent; case AR_EEP_OB_2: return pModal->ob; case AR_EEP_DB_2: return pModal->db; case AR_EEP_TXMASK: return pBase->txMask; case AR_EEP_RXMASK: return pBase->rxMask; case AR_EEP_RXGAIN_TYPE: return AR5416_EEP_RXGAIN_ORIG; case AR_EEP_TXGAIN_TYPE: return IS_VERS(>=, AR5416_EEP_MINOR_VER_19) ? pBase->txGainType : AR5416_EEP_TXGAIN_ORIG; case AR_EEP_OL_PWRCTRL: HALASSERT(val == AH_NULL); return HAL_EIO; case AR_EEP_AMODE: HALASSERT(val == AH_NULL); return pBase->opCapFlags & AR5416_OPFLAGS_11A ? HAL_OK : HAL_EIO; case AR_EEP_BMODE: case AR_EEP_GMODE: HALASSERT(val == AH_NULL); return pBase->opCapFlags & AR5416_OPFLAGS_11G ? HAL_OK : HAL_EIO; case AR_EEP_32KHZCRYSTAL: case AR_EEP_COMPRESS: case AR_EEP_FASTFRAME: /* XXX policy decision, h/w can do it */ case AR_EEP_WRITEPROTECT: /* NB: no write protect bit */ HALASSERT(val == AH_NULL); /* fall thru... */ case AR_EEP_MAXQCU: /* NB: not in opCapFlags */ case AR_EEP_KCENTRIES: /* NB: not in opCapFlags */ return HAL_EIO; case AR_EEP_AES: case AR_EEP_BURST: case AR_EEP_RFKILL: case AR_EEP_TURBO2DISABLE: HALASSERT(val == AH_NULL); return HAL_OK; case AR_EEP_ANTGAINMAX_2: *(int8_t *) val = ee->ee_antennaGainMax; return HAL_OK; default: HALASSERT(0); return HAL_EINVAL; } #undef IS_VERS #undef CHAN_A_IDX #undef CHAN_B_IDX }
/* * Attach for an AR9280 part. */ static struct ath_hal * ar9280Attach(uint16_t devid, HAL_SOFTC sc, HAL_BUS_TAG st, HAL_BUS_HANDLE sh, uint16_t *eepromdata, HAL_OPS_CONFIG *ah_config, HAL_STATUS *status) { struct ath_hal_9280 *ahp9280; struct ath_hal_5212 *ahp; struct ath_hal *ah; uint32_t val; HAL_STATUS ecode; HAL_BOOL rfStatus; int8_t pwr_table_offset; uint8_t pwr; HALDEBUG(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n", __func__, sc, (void*) st, (void*) sh); /* NB: memory is returned zero'd */ ahp9280 = ath_hal_malloc(sizeof (struct ath_hal_9280)); if (ahp9280 == AH_NULL) { HALDEBUG(AH_NULL, HAL_DEBUG_ANY, "%s: cannot allocate memory for state block\n", __func__); *status = HAL_ENOMEM; return AH_NULL; } ahp = AH5212(ahp9280); ah = &ahp->ah_priv.h; ar5416InitState(AH5416(ah), devid, sc, st, sh, status); /* * Use the "local" EEPROM data given to us by the higher layers. * This is a private copy out of system flash. The Linux ath9k * commit for the initial AR9130 support mentions MMIO flash * access is "unreliable." -adrian */ if (eepromdata != AH_NULL) { AH_PRIVATE((ah))->ah_eepromRead = ath_hal_EepromDataRead; AH_PRIVATE((ah))->ah_eepromWrite = NULL; ah->ah_eepromdata = eepromdata; } /* XXX override with 9280 specific state */ /* override 5416 methods for our needs */ AH5416(ah)->ah_initPLL = ar9280InitPLL; ah->ah_setAntennaSwitch = ar9280SetAntennaSwitch; ah->ah_configPCIE = ar9280ConfigPCIE; ah->ah_disablePCIE = ar9280DisablePCIE; AH5416(ah)->ah_cal.iqCalData.calData = &ar9280_iq_cal; AH5416(ah)->ah_cal.adcGainCalData.calData = &ar9280_adc_gain_cal; AH5416(ah)->ah_cal.adcDcCalData.calData = &ar9280_adc_dc_cal; AH5416(ah)->ah_cal.adcDcCalInitData.calData = &ar9280_adc_init_dc_cal; AH5416(ah)->ah_cal.suppCals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL; AH5416(ah)->ah_spurMitigate = ar9280SpurMitigate; AH5416(ah)->ah_writeIni = ar9280WriteIni; AH5416(ah)->ah_olcInit = ar9280olcInit; AH5416(ah)->ah_olcTempCompensation = ar9280olcTemperatureCompensation; AH5416(ah)->ah_setPowerCalTable = ar9280SetPowerCalTable; AH5416(ah)->ah_rx_chainmask = AR9280_DEFAULT_RXCHAINMASK; AH5416(ah)->ah_tx_chainmask = AR9280_DEFAULT_TXCHAINMASK; if (!ar5416SetResetReg(ah, HAL_RESET_POWER_ON)) { /* reset chip */ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: couldn't reset chip\n", __func__); ecode = HAL_EIO; goto bad; } if (!ar5416SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: couldn't wakeup chip\n", __func__); ecode = HAL_EIO; goto bad; } /* Read Revisions from Chips before taking out of reset */ val = OS_REG_READ(ah, AR_SREV); HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s: ID 0x%x VERSION 0x%x TYPE 0x%x REVISION 0x%x\n", __func__, MS(val, AR_XSREV_ID), MS(val, AR_XSREV_VERSION), MS(val, AR_XSREV_TYPE), MS(val, AR_XSREV_REVISION)); /* NB: include chip type to differentiate from pre-Sowl versions */ AH_PRIVATE(ah)->ah_macVersion = (val & AR_XSREV_VERSION) >> AR_XSREV_TYPE_S; AH_PRIVATE(ah)->ah_macRev = MS(val, AR_XSREV_REVISION); AH_PRIVATE(ah)->ah_ispcie = (val & AR_XSREV_TYPE_HOST_MODE) == 0; /* setup common ini data; rf backends handle remainder */ if (AR_SREV_MERLIN_20_OR_LATER(ah)) { HAL_INI_INIT(&ahp->ah_ini_modes, ar9280Modes_v2, 6); HAL_INI_INIT(&ahp->ah_ini_common, ar9280Common_v2, 2); HAL_INI_INIT(&AH5416(ah)->ah_ini_pcieserdes, ar9280PciePhy_clkreq_always_on_L1_v2, 2); HAL_INI_INIT(&ahp9280->ah_ini_xmodes, ar9280Modes_fast_clock_v2, 3); } else { HAL_INI_INIT(&ahp->ah_ini_modes, ar9280Modes_v1, 6); HAL_INI_INIT(&ahp->ah_ini_common, ar9280Common_v1, 2); HAL_INI_INIT(&AH5416(ah)->ah_ini_pcieserdes, ar9280PciePhy_v1, 2); } ar5416AttachPCIE(ah); ecode = ath_hal_v14EepromAttach(ah); if (ecode != HAL_OK) goto bad; if (!ar5416ChipReset(ah, AH_NULL)) { /* reset chip */ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n", __func__); ecode = HAL_EIO; goto bad; } AH_PRIVATE(ah)->ah_phyRev = OS_REG_READ(ah, AR_PHY_CHIP_ID); if (!ar5212ChipTest(ah)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: hardware self-test failed\n", __func__); ecode = HAL_ESELFTEST; goto bad; } /* * Set correct Baseband to analog shift * setting to access analog chips. */ OS_REG_WRITE(ah, AR_PHY(0), 0x00000007); /* Read Radio Chip Rev Extract */ AH_PRIVATE(ah)->ah_analog5GhzRev = ar5416GetRadioRev(ah); switch (AH_PRIVATE(ah)->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR) { case AR_RAD2133_SREV_MAJOR: /* Sowl: 2G/3x3 */ case AR_RAD5133_SREV_MAJOR: /* Sowl: 2+5G/3x3 */ break; default: if (AH_PRIVATE(ah)->ah_analog5GhzRev == 0) { AH_PRIVATE(ah)->ah_analog5GhzRev = AR_RAD5133_SREV_MAJOR; break; } #ifdef AH_DEBUG HALDEBUG(ah, HAL_DEBUG_ANY, "%s: 5G Radio Chip Rev 0x%02X is not supported by " "this driver\n", __func__, AH_PRIVATE(ah)->ah_analog5GhzRev); ecode = HAL_ENOTSUPP; goto bad; #endif } rfStatus = ar9280RfAttach(ah, &ecode); if (!rfStatus) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: RF setup failed, status %u\n", __func__, ecode); goto bad; } /* Enable fixup for AR_AN_TOP2 if necessary */ /* * The v14 EEPROM layer returns HAL_EIO if PWDCLKIND isn't supported * by the EEPROM version. * * ath9k checks the EEPROM minor version is >= 0x0a here, instead of * the abstracted EEPROM access layer. */ ecode = ath_hal_eepromGet(ah, AR_EEP_PWDCLKIND, &pwr); if (AR_SREV_MERLIN_20_OR_LATER(ah) && ecode == HAL_OK && pwr == 0) { printf("[ath] enabling AN_TOP2_FIXUP\n"); AH5416(ah)->ah_need_an_top2_fixup = 1; } /* * Check whether the power table offset isn't the default. * This can occur with eeprom minor V21 or greater on Merlin. */ (void) ath_hal_eepromGet(ah, AR_EEP_PWR_TABLE_OFFSET, &pwr_table_offset); if (pwr_table_offset != AR5416_PWR_TABLE_OFFSET_DB) ath_hal_printf(ah, "[ath]: default pwr offset: %d dBm != EEPROM pwr offset: %d dBm; curves will be adjusted.\n", AR5416_PWR_TABLE_OFFSET_DB, (int) pwr_table_offset); /* XXX check for >= minor ver 17 */ if (AR_SREV_MERLIN_20(ah)) { /* setup rxgain table */ switch (ath_hal_eepromGet(ah, AR_EEP_RXGAIN_TYPE, AH_NULL)) { case AR5416_EEP_RXGAIN_13dB_BACKOFF: HAL_INI_INIT(&ahp9280->ah_ini_rxgain, ar9280Modes_backoff_13db_rxgain_v2, 6); break; case AR5416_EEP_RXGAIN_23dB_BACKOFF: HAL_INI_INIT(&ahp9280->ah_ini_rxgain, ar9280Modes_backoff_23db_rxgain_v2, 6); break; case AR5416_EEP_RXGAIN_ORIG: HAL_INI_INIT(&ahp9280->ah_ini_rxgain, ar9280Modes_original_rxgain_v2, 6); break; default: HALASSERT(AH_FALSE); goto bad; /* XXX ? try to continue */ } } /* XXX check for >= minor ver 19 */ if (AR_SREV_MERLIN_20(ah)) { /* setp txgain table */ switch (ath_hal_eepromGet(ah, AR_EEP_TXGAIN_TYPE, AH_NULL)) { case AR5416_EEP_TXGAIN_HIGH_POWER: HAL_INI_INIT(&ahp9280->ah_ini_txgain, ar9280Modes_high_power_tx_gain_v2, 6); break; case AR5416_EEP_TXGAIN_ORIG: HAL_INI_INIT(&ahp9280->ah_ini_txgain, ar9280Modes_original_tx_gain_v2, 6); break; default: HALASSERT(AH_FALSE); goto bad; /* XXX ? try to continue */ } } /* * Got everything we need now to setup the capabilities. */ if (!ar9280FillCapabilityInfo(ah)) { ecode = HAL_EEREAD; goto bad; } ecode = ath_hal_eepromGet(ah, AR_EEP_MACADDR, ahp->ah_macaddr); if (ecode != HAL_OK) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: error getting mac address from EEPROM\n", __func__); goto bad; } /* XXX How about the serial number ? */ /* Read Reg Domain */ AH_PRIVATE(ah)->ah_currentRD = ath_hal_eepromGet(ah, AR_EEP_REGDMN_0, AH_NULL); AH_PRIVATE(ah)->ah_currentRDext = ath_hal_eepromGet(ah, AR_EEP_REGDMN_1, AH_NULL); /* * ah_miscMode is populated by ar5416FillCapabilityInfo() * starting from griffin. Set here to make sure that * AR_MISC_MODE_MIC_NEW_LOC_ENABLE is set before a GTK is * placed into hardware. */ if (ahp->ah_miscMode != 0) OS_REG_WRITE(ah, AR_MISC_MODE, OS_REG_READ(ah, AR_MISC_MODE) | ahp->ah_miscMode); ar9280AniSetup(ah); /* Anti Noise Immunity */ /* Setup noise floor min/max/nominal values */ AH5416(ah)->nf_2g.max = AR_PHY_CCA_MAX_GOOD_VAL_9280_2GHZ; AH5416(ah)->nf_2g.min = AR_PHY_CCA_MIN_GOOD_VAL_9280_2GHZ; AH5416(ah)->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_9280_2GHZ; AH5416(ah)->nf_5g.max = AR_PHY_CCA_MAX_GOOD_VAL_9280_5GHZ; AH5416(ah)->nf_5g.min = AR_PHY_CCA_MIN_GOOD_VAL_9280_5GHZ; AH5416(ah)->nf_5g.nominal = AR_PHY_CCA_NOM_VAL_9280_5GHZ; ar5416InitNfHistBuff(AH5416(ah)->ah_cal.nfCalHist); HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s: return\n", __func__); return ah; bad: if (ah != AH_NULL) ah->ah_detach(ah); if (status) *status = ecode; return AH_NULL; }
/* * Take the MHz channel value and set the Channel value * * ASSUMES: Writes enabled to analog bus */ static HAL_BOOL ar2133SetChannel(struct ath_hal *ah, const struct ieee80211_channel *chan) { uint32_t channelSel = 0; uint32_t bModeSynth = 0; uint32_t aModeRefSel = 0; uint32_t reg32 = 0; uint16_t freq; CHAN_CENTERS centers; OS_MARK(ah, AH_MARK_SETCHANNEL, chan->ic_freq); ar5416GetChannelCenters(ah, chan, ¢ers); freq = centers.synth_center; if (freq < 4800) { uint32_t txctl; if (((freq - 2192) % 5) == 0) { channelSel = ((freq - 672) * 2 - 3040)/10; bModeSynth = 0; } else if (((freq - 2224) % 5) == 0) { channelSel = ((freq - 704) * 2 - 3040) / 10; bModeSynth = 1; } else { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel %u MHz\n", __func__, freq); return AH_FALSE; } channelSel = (channelSel << 2) & 0xff; channelSel = ath_hal_reverseBits(channelSel, 8); txctl = OS_REG_READ(ah, AR_PHY_CCK_TX_CTRL); if (freq == 2484) { /* Enable channel spreading for channel 14 */ OS_REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, txctl | AR_PHY_CCK_TX_CTRL_JAPAN); } else { OS_REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, txctl &~ AR_PHY_CCK_TX_CTRL_JAPAN); } } else if ((freq % 20) == 0 && freq >= 5120) { channelSel = ath_hal_reverseBits(((freq - 4800) / 20 << 2), 8); if (AR_SREV_SOWL_10_OR_LATER(ah)) aModeRefSel = ath_hal_reverseBits(3, 2); else aModeRefSel = ath_hal_reverseBits(1, 2); } else if ((freq % 10) == 0) { channelSel = ath_hal_reverseBits(((freq - 4800) / 10 << 1), 8); if (AR_SREV_SOWL_10_OR_LATER(ah)) aModeRefSel = ath_hal_reverseBits(2, 2); else aModeRefSel = ath_hal_reverseBits(1, 2); } else if ((freq % 5) == 0) { channelSel = ath_hal_reverseBits((freq - 4800) / 5, 8); aModeRefSel = ath_hal_reverseBits(1, 2); } else { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel %u MHz\n", __func__, freq); return AH_FALSE; } reg32 = (channelSel << 8) | (aModeRefSel << 2) | (bModeSynth << 1) | (1 << 5) | 0x1; OS_REG_WRITE(ah, AR_PHY(0x37), reg32); AH_PRIVATE(ah)->ah_curchan = chan; return AH_TRUE; }
static void ar9280ConfigPCIE(struct ath_hal *ah, HAL_BOOL restore, HAL_BOOL power_off) { uint32_t val; if (AH_PRIVATE(ah)->ah_ispcie && !restore) { ath_hal_ini_write(ah, &AH5416(ah)->ah_ini_pcieserdes, 1, 0); OS_DELAY(1000); } /* * Set PCIe workaround bits * * NOTE: * * In Merlin and Kite, bit 14 in WA register (disable L1) should only * be set when device enters D3 and be cleared when device comes back * to D0. */ if (power_off) { /* Power-off */ OS_REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA); val = OS_REG_READ(ah, AR_WA); /* * Disable bit 6 and 7 before entering D3 to prevent * system hang. */ val &= ~(AR_WA_BIT6 | AR_WA_BIT7); /* * XXX Not sure, is specified in the reference HAL. */ val |= AR_WA_BIT22; /* * See above: set AR_WA_D3_L1_DISABLE when entering D3 state. * * XXX The reference HAL does it this way - it only sets * AR_WA_D3_L1_DISABLE if it's set in AR9280_WA_DEFAULT, * which it (currently) isn't. So the following statement * is currently a NOP. */ if (AR9280_WA_DEFAULT & AR_WA_D3_L1_DISABLE) val |= AR_WA_D3_L1_DISABLE; OS_REG_WRITE(ah, AR_WA, val); } else { /* Power-on */ val = AR9280_WA_DEFAULT; /* * See note above: make sure L1_DISABLE is not set. */ val &= (~AR_WA_D3_L1_DISABLE); OS_REG_WRITE(ah, AR_WA, val); /* set bit 19 to allow forcing of pcie core into L1 state */ OS_REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA); } }
/* * Reads EEPROM header info from device structure and programs * all rf registers * * REQUIRES: Access to the analog rf device */ static HAL_BOOL ar5111SetRfRegs(struct ath_hal *ah, const struct ieee80211_channel *chan, uint16_t modesIndex, uint16_t *rfXpdGain) { uint16_t freq = ath_hal_gethwchannel(ah, chan); struct ath_hal_5212 *ahp = AH5212(ah); const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; uint16_t rfXpdGainFixed, rfPloSel, rfPwdXpd, gainI; uint16_t tempOB, tempDB; uint32_t ob2GHz, db2GHz, rfReg[NELEM(ar5212Bank6_5111)]; int i, regWrites = 0; HALDEBUG(ah, HAL_DEBUG_RFPARAM, "%s: chan %u/0x%x modesIndex %u\n", __func__, chan->ic_freq, chan->ic_flags, modesIndex); /* Setup rf parameters */ switch (chan->ic_flags & IEEE80211_CHAN_ALLFULL) { case IEEE80211_CHAN_A: if (4000 < freq && freq < 5260) { tempOB = ee->ee_ob1; tempDB = ee->ee_db1; } else if (5260 <= freq && freq < 5500) { tempOB = ee->ee_ob2; tempDB = ee->ee_db2; } else if (5500 <= freq && freq < 5725) { tempOB = ee->ee_ob3; tempDB = ee->ee_db3; } else if (freq >= 5725) { tempOB = ee->ee_ob4; tempDB = ee->ee_db4; } else { /* XXX when does this happen??? */ tempOB = tempDB = 0; } ob2GHz = db2GHz = 0; rfXpdGainFixed = ee->ee_xgain[headerInfo11A]; rfPloSel = ee->ee_xpd[headerInfo11A]; rfPwdXpd = !ee->ee_xpd[headerInfo11A]; gainI = ee->ee_gainI[headerInfo11A]; break; case IEEE80211_CHAN_B: tempOB = ee->ee_obFor24; tempDB = ee->ee_dbFor24; ob2GHz = ee->ee_ob2GHz[0]; db2GHz = ee->ee_db2GHz[0]; rfXpdGainFixed = ee->ee_xgain[headerInfo11B]; rfPloSel = ee->ee_xpd[headerInfo11B]; rfPwdXpd = !ee->ee_xpd[headerInfo11B]; gainI = ee->ee_gainI[headerInfo11B]; break; case IEEE80211_CHAN_G: case IEEE80211_CHAN_PUREG: /* NB: really 108G */ tempOB = ee->ee_obFor24g; tempDB = ee->ee_dbFor24g; ob2GHz = ee->ee_ob2GHz[1]; db2GHz = ee->ee_db2GHz[1]; rfXpdGainFixed = ee->ee_xgain[headerInfo11G]; rfPloSel = ee->ee_xpd[headerInfo11G]; rfPwdXpd = !ee->ee_xpd[headerInfo11G]; gainI = ee->ee_gainI[headerInfo11G]; break; default: HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel flags 0x%x\n", __func__, chan->ic_flags); return AH_FALSE; } HALASSERT(1 <= tempOB && tempOB <= 5); HALASSERT(1 <= tempDB && tempDB <= 5); /* Bank 0 Write */ for (i = 0; i < NELEM(ar5212Bank0_5111); i++) rfReg[i] = ar5212Bank0_5111[i][modesIndex]; if (IEEE80211_IS_CHAN_2GHZ(chan)) { ar5212ModifyRfBuffer(rfReg, ob2GHz, 3, 119, 0); ar5212ModifyRfBuffer(rfReg, db2GHz, 3, 122, 0); } HAL_INI_WRITE_BANK(ah, ar5212Bank0_5111, rfReg, regWrites); /* Bank 1 Write */ HAL_INI_WRITE_ARRAY(ah, ar5212Bank1_5111, 1, regWrites); /* Bank 2 Write */ HAL_INI_WRITE_ARRAY(ah, ar5212Bank2_5111, modesIndex, regWrites); /* Bank 3 Write */ HAL_INI_WRITE_ARRAY(ah, ar5212Bank3_5111, modesIndex, regWrites); /* Bank 6 Write */ for (i = 0; i < NELEM(ar5212Bank6_5111); i++) rfReg[i] = ar5212Bank6_5111[i][modesIndex]; if (IEEE80211_IS_CHAN_A(chan)) { /* NB: CHANNEL_A | CHANNEL_T */ ar5212ModifyRfBuffer(rfReg, ee->ee_cornerCal.pd84, 1, 51, 3); ar5212ModifyRfBuffer(rfReg, ee->ee_cornerCal.pd90, 1, 45, 3); } ar5212ModifyRfBuffer(rfReg, rfPwdXpd, 1, 95, 0); ar5212ModifyRfBuffer(rfReg, rfXpdGainFixed, 4, 96, 0); /* Set 5212 OB & DB */ ar5212ModifyRfBuffer(rfReg, tempOB, 3, 104, 0); ar5212ModifyRfBuffer(rfReg, tempDB, 3, 107, 0); HAL_INI_WRITE_BANK(ah, ar5212Bank6_5111, rfReg, regWrites); /* Bank 7 Write */ for (i = 0; i < NELEM(ar5212Bank7_5111); i++) rfReg[i] = ar5212Bank7_5111[i][modesIndex]; ar5212ModifyRfBuffer(rfReg, gainI, 6, 29, 0); ar5212ModifyRfBuffer(rfReg, rfPloSel, 1, 4, 0); if (IEEE80211_IS_CHAN_QUARTER(chan) || IEEE80211_IS_CHAN_HALF(chan)) { uint32_t rfWaitI, rfWaitS, rfMaxTime; rfWaitS = 0x1f; rfWaitI = (IEEE80211_IS_CHAN_HALF(chan)) ? 0x10 : 0x1f; rfMaxTime = 3; ar5212ModifyRfBuffer(rfReg, rfWaitS, 5, 19, 0); ar5212ModifyRfBuffer(rfReg, rfWaitI, 5, 24, 0); ar5212ModifyRfBuffer(rfReg, rfMaxTime, 2, 49, 0); } HAL_INI_WRITE_BANK(ah, ar5212Bank7_5111, rfReg, regWrites); /* Now that we have reprogrammed rfgain value, clear the flag. */ ahp->ah_rfgainState = HAL_RFGAIN_INACTIVE; return AH_TRUE; }
static OS_INLINE uint16_t getEepromRD(struct ath_hal *ah) { return AH_PRIVATE(ah)->ah_currentRD &~ WORLDWIDE_ROAMING_FLAG; }
/* * Take the MHz channel value and set the Channel value * * ASSUMES: Writes enabled to analog bus */ static HAL_BOOL ar5111SetChannel(struct ath_hal *ah, const struct ieee80211_channel *chan) { #define CI_2GHZ_INDEX_CORRECTION 19 uint16_t freq = ath_hal_gethwchannel(ah, chan); uint32_t refClk, reg32, data2111; int16_t chan5111, chanIEEE; /* * Structure to hold 11b tuning information for 5111/2111 * 16 MHz mode, divider ratio = 198 = NP+S. N=16, S=4 or 6, P=12 */ typedef struct { uint32_t refClkSel; /* reference clock, 1 for 16 MHz */ uint32_t channelSelect; /* P[7:4]S[3:0] bits */ uint16_t channel5111; /* 11a channel for 5111 */ } CHAN_INFO_2GHZ; static const CHAN_INFO_2GHZ chan2GHzData[] = { { 1, 0x46, 96 }, /* 2312 -19 */ { 1, 0x46, 97 }, /* 2317 -18 */ { 1, 0x46, 98 }, /* 2322 -17 */ { 1, 0x46, 99 }, /* 2327 -16 */ { 1, 0x46, 100 }, /* 2332 -15 */ { 1, 0x46, 101 }, /* 2337 -14 */ { 1, 0x46, 102 }, /* 2342 -13 */ { 1, 0x46, 103 }, /* 2347 -12 */ { 1, 0x46, 104 }, /* 2352 -11 */ { 1, 0x46, 105 }, /* 2357 -10 */ { 1, 0x46, 106 }, /* 2362 -9 */ { 1, 0x46, 107 }, /* 2367 -8 */ { 1, 0x46, 108 }, /* 2372 -7 */ /* index -6 to 0 are pad to make this a nolookup table */ { 1, 0x46, 116 }, /* -6 */ { 1, 0x46, 116 }, /* -5 */ { 1, 0x46, 116 }, /* -4 */ { 1, 0x46, 116 }, /* -3 */ { 1, 0x46, 116 }, /* -2 */ { 1, 0x46, 116 }, /* -1 */ { 1, 0x46, 116 }, /* 0 */ { 1, 0x46, 116 }, /* 2412 1 */ { 1, 0x46, 117 }, /* 2417 2 */ { 1, 0x46, 118 }, /* 2422 3 */ { 1, 0x46, 119 }, /* 2427 4 */ { 1, 0x46, 120 }, /* 2432 5 */ { 1, 0x46, 121 }, /* 2437 6 */ { 1, 0x46, 122 }, /* 2442 7 */ { 1, 0x46, 123 }, /* 2447 8 */ { 1, 0x46, 124 }, /* 2452 9 */ { 1, 0x46, 125 }, /* 2457 10 */ { 1, 0x46, 126 }, /* 2462 11 */ { 1, 0x46, 127 }, /* 2467 12 */ { 1, 0x46, 128 }, /* 2472 13 */ { 1, 0x44, 124 }, /* 2484 14 */ { 1, 0x46, 136 }, /* 2512 15 */ { 1, 0x46, 140 }, /* 2532 16 */ { 1, 0x46, 144 }, /* 2552 17 */ { 1, 0x46, 148 }, /* 2572 18 */ { 1, 0x46, 152 }, /* 2592 19 */ { 1, 0x46, 156 }, /* 2612 20 */ { 1, 0x46, 160 }, /* 2632 21 */ { 1, 0x46, 164 }, /* 2652 22 */ { 1, 0x46, 168 }, /* 2672 23 */ { 1, 0x46, 172 }, /* 2692 24 */ { 1, 0x46, 176 }, /* 2712 25 */ { 1, 0x46, 180 } /* 2732 26 */ }; OS_MARK(ah, AH_MARK_SETCHANNEL, freq); chanIEEE = chan->ic_ieee; if (IEEE80211_IS_CHAN_2GHZ(chan)) { const CHAN_INFO_2GHZ* ci = &chan2GHzData[chanIEEE + CI_2GHZ_INDEX_CORRECTION]; uint32_t txctl; data2111 = ((ath_hal_reverseBits(ci->channelSelect, 8) & 0xff) << 5) | (ci->refClkSel << 4); chan5111 = ci->channel5111; txctl = OS_REG_READ(ah, AR_PHY_CCK_TX_CTRL); if (freq == 2484) { /* Enable channel spreading for channel 14 */ OS_REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, txctl | AR_PHY_CCK_TX_CTRL_JAPAN); } else { OS_REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, txctl &~ AR_PHY_CCK_TX_CTRL_JAPAN); } } else { chan5111 = chanIEEE; /* no conversion needed */ data2111 = 0; } /* Rest of the code is common for 5 GHz and 2.4 GHz. */ if (chan5111 >= 145 || (chan5111 & 0x1)) { reg32 = ath_hal_reverseBits(chan5111 - 24, 8) & 0xff; refClk = 1; } else { reg32 = ath_hal_reverseBits(((chan5111 - 24)/2), 8) & 0xff; refClk = 0; } reg32 = (reg32 << 2) | (refClk << 1) | (1 << 10) | 0x1; OS_REG_WRITE(ah, AR_PHY(0x27), ((data2111 & 0xff) << 8) | (reg32 & 0xff)); reg32 >>= 8; OS_REG_WRITE(ah, AR_PHY(0x34), (data2111 & 0xff00) | (reg32 & 0xff)); AH_PRIVATE(ah)->ah_curchan = chan; return AH_TRUE; #undef CI_2GHZ_INDEX_CORRECTION }
HAL_BOOL ar5210ResetTxQueue(struct ath_hal *ah, u_int q) { struct ath_hal_5210 *ahp = AH5210(ah); const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan; HAL_TX_QUEUE_INFO *qi; uint32_t cwMin; if (q >= HAL_NUM_TX_QUEUES) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n", __func__, q); return AH_FALSE; } qi = &ahp->ah_txq[q]; if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) { HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: inactive queue %u\n", __func__, q); return AH_FALSE; } /* * Ignore any non-data queue(s). */ if (qi->tqi_type != HAL_TX_QUEUE_DATA) return AH_TRUE; /* Set turbo mode / base mode parameters on or off */ if (IEEE80211_IS_CHAN_TURBO(chan)) { OS_REG_WRITE(ah, AR_SLOT_TIME, INIT_SLOT_TIME_TURBO); OS_REG_WRITE(ah, AR_TIME_OUT, INIT_ACK_CTS_TIMEOUT_TURBO); OS_REG_WRITE(ah, AR_USEC, INIT_TRANSMIT_LATENCY_TURBO); OS_REG_WRITE(ah, AR_IFS0, ((INIT_SIFS_TURBO + qi->tqi_aifs * INIT_SLOT_TIME_TURBO) << AR_IFS0_DIFS_S) | INIT_SIFS_TURBO); OS_REG_WRITE(ah, AR_IFS1, INIT_PROTO_TIME_CNTRL_TURBO); OS_REG_WRITE(ah, AR_PHY(17), (OS_REG_READ(ah, AR_PHY(17)) & ~0x7F) | 0x38); OS_REG_WRITE(ah, AR_PHY_FRCTL, AR_PHY_SERVICE_ERR | AR_PHY_TXURN_ERR | AR_PHY_ILLLEN_ERR | AR_PHY_ILLRATE_ERR | AR_PHY_PARITY_ERR | AR_PHY_TIMING_ERR | 0x2020 | AR_PHY_TURBO_MODE | AR_PHY_TURBO_SHORT); } else { OS_REG_WRITE(ah, AR_SLOT_TIME, INIT_SLOT_TIME); OS_REG_WRITE(ah, AR_TIME_OUT, INIT_ACK_CTS_TIMEOUT); OS_REG_WRITE(ah, AR_USEC, INIT_TRANSMIT_LATENCY); OS_REG_WRITE(ah, AR_IFS0, ((INIT_SIFS + qi->tqi_aifs * INIT_SLOT_TIME) << AR_IFS0_DIFS_S) | INIT_SIFS); OS_REG_WRITE(ah, AR_IFS1, INIT_PROTO_TIME_CNTRL); OS_REG_WRITE(ah, AR_PHY(17), (OS_REG_READ(ah, AR_PHY(17)) & ~0x7F) | 0x1C); OS_REG_WRITE(ah, AR_PHY_FRCTL, AR_PHY_SERVICE_ERR | AR_PHY_TXURN_ERR | AR_PHY_ILLLEN_ERR | AR_PHY_ILLRATE_ERR | AR_PHY_PARITY_ERR | AR_PHY_TIMING_ERR | 0x1020); } if (qi->tqi_cwmin == HAL_TXQ_USEDEFAULT) cwMin = INIT_CWMIN; else cwMin = qi->tqi_cwmin; /* Set cwmin and retry limit values */ OS_REG_WRITE(ah, AR_RETRY_LMT, (cwMin << AR_RETRY_LMT_CW_MIN_S) | SM(INIT_SLG_RETRY, AR_RETRY_LMT_SLG_RETRY) | SM(INIT_SSH_RETRY, AR_RETRY_LMT_SSH_RETRY) | SM(qi->tqi_lgretry, AR_RETRY_LMT_LG_RETRY) | SM(qi->tqi_shretry, AR_RETRY_LMT_SH_RETRY) ); if (qi->tqi_qflags & HAL_TXQ_TXOKINT_ENABLE) ahp->ah_txOkInterruptMask |= 1 << q; else ahp->ah_txOkInterruptMask &= ~(1 << q); if (qi->tqi_qflags & HAL_TXQ_TXERRINT_ENABLE) ahp->ah_txErrInterruptMask |= 1 << q; else ahp->ah_txErrInterruptMask &= ~(1 << q); if (qi->tqi_qflags & HAL_TXQ_TXDESCINT_ENABLE) ahp->ah_txDescInterruptMask |= 1 << q; else ahp->ah_txDescInterruptMask &= ~(1 << q); if (qi->tqi_qflags & HAL_TXQ_TXEOLINT_ENABLE) ahp->ah_txEolInterruptMask |= 1 << q; else ahp->ah_txEolInterruptMask &= ~(1 << q); if (qi->tqi_qflags & HAL_TXQ_TXURNINT_ENABLE) ahp->ah_txUrnInterruptMask |= 1 << q; else ahp->ah_txUrnInterruptMask &= ~(1 << q); return AH_TRUE; }
static HAL_BOOL ar2317GetChannelMaxMinPower(struct ath_hal *ah, const struct ieee80211_channel *chan, int16_t *maxPow, int16_t *minPow) { uint16_t freq = chan->ic_freq; /* NB: never mapped */ const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; const RAW_DATA_STRUCT_2317 *pRawDataset = AH_NULL; const RAW_DATA_PER_CHANNEL_2317 *data=AH_NULL; uint16_t numChannels; int totalD,totalF, totalMin,last, i; *maxPow = 0; if (IEEE80211_IS_CHAN_G(chan) || IEEE80211_IS_CHAN_108G(chan)) pRawDataset = &ee->ee_rawDataset2413[headerInfo11G]; else if (IEEE80211_IS_CHAN_B(chan)) pRawDataset = &ee->ee_rawDataset2413[headerInfo11B]; else return(AH_FALSE); numChannels = pRawDataset->numChannels; data = pRawDataset->pDataPerChannel; /* Make sure the channel is in the range of the TP values * (freq piers) */ if (numChannels < 1) return(AH_FALSE); if ((freq < data[0].channelValue) || (freq > data[numChannels-1].channelValue)) { if (freq < data[0].channelValue) { *maxPow = ar2317GetMaxPower(ah, &data[0]); *minPow = ar2317GetMinPower(ah, &data[0]); return(AH_TRUE); } else { *maxPow = ar2317GetMaxPower(ah, &data[numChannels - 1]); *minPow = ar2317GetMinPower(ah, &data[numChannels - 1]); return(AH_TRUE); } } /* Linearly interpolate the power value now */ for (last=0,i=0; (i<numChannels) && (freq > data[i].channelValue); last = i++); totalD = data[i].channelValue - data[last].channelValue; if (totalD > 0) { totalF = ar2317GetMaxPower(ah, &data[i]) - ar2317GetMaxPower(ah, &data[last]); *maxPow = (int8_t) ((totalF*(freq-data[last].channelValue) + ar2317GetMaxPower(ah, &data[last])*totalD)/totalD); totalMin = ar2317GetMinPower(ah, &data[i]) - ar2317GetMinPower(ah, &data[last]); *minPow = (int8_t) ((totalMin*(freq-data[last].channelValue) + ar2317GetMinPower(ah, &data[last])*totalD)/totalD); return(AH_TRUE); } else { if (freq == data[i].channelValue) { *maxPow = ar2317GetMaxPower(ah, &data[i]); *minPow = ar2317GetMinPower(ah, &data[i]); return(AH_TRUE); } else return(AH_FALSE); } }
static void ar9287AniSetup(struct ath_hal *ah) { /* * These are the parameters from the AR5416 ANI code; * they likely need quite a bit of adjustment for the * AR9280. */ static const struct ar5212AniParams aniparams = { .maxNoiseImmunityLevel = 4, /* levels 0..4 */ .totalSizeDesired = { -55, -55, -55, -55, -62 }, .coarseHigh = { -14, -14, -14, -14, -12 }, .coarseLow = { -64, -64, -64, -64, -70 }, .firpwr = { -78, -78, -78, -78, -80 }, .maxSpurImmunityLevel = 2, .cycPwrThr1 = { 2, 4, 6 }, .maxFirstepLevel = 2, /* levels 0..2 */ .firstep = { 0, 4, 8 }, .ofdmTrigHigh = 500, .ofdmTrigLow = 200, .cckTrigHigh = 200, .cckTrigLow = 100, .rssiThrHigh = 40, .rssiThrLow = 7, .period = 100, }; /* NB: disable ANI noise immmunity for reliable RIFS rx */ AH5416(ah)->ah_ani_function &= ~ HAL_ANI_NOISE_IMMUNITY_LEVEL; /* NB: ANI is not enabled yet */ ar5416AniAttach(ah, &aniparams, &aniparams, AH_TRUE); } /* * Attach for an AR9287 part. */ static struct ath_hal * ar9287Attach(uint16_t devid, HAL_SOFTC sc, HAL_BUS_TAG st, HAL_BUS_HANDLE sh, uint16_t *eepromdata, HAL_STATUS *status) { struct ath_hal_9287 *ahp9287; struct ath_hal_5212 *ahp; struct ath_hal *ah; uint32_t val; HAL_STATUS ecode; HAL_BOOL rfStatus; int8_t pwr_table_offset; HALDEBUG_G(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n", __func__, sc, (void*) st, (void*) sh); /* NB: memory is returned zero'd */ ahp9287 = ath_hal_malloc(sizeof (struct ath_hal_9287)); if (ahp9287 == AH_NULL) { HALDEBUG_G(AH_NULL, HAL_DEBUG_ANY, "%s: cannot allocate memory for state block\n", __func__); *status = HAL_ENOMEM; return AH_NULL; } ahp = AH5212(ahp9287); ah = &ahp->ah_priv.h; ar5416InitState(AH5416(ah), devid, sc, st, sh, status); /* XXX override with 9280 specific state */ /* override 5416 methods for our needs */ AH5416(ah)->ah_initPLL = ar9280InitPLL; ah->ah_setAntennaSwitch = ar9287SetAntennaSwitch; ah->ah_configPCIE = ar9287ConfigPCIE; AH5416(ah)->ah_cal.iqCalData.calData = &ar9287_iq_cal; AH5416(ah)->ah_cal.adcGainCalData.calData = &ar9287_adc_gain_cal; AH5416(ah)->ah_cal.adcDcCalData.calData = &ar9287_adc_dc_cal; AH5416(ah)->ah_cal.adcDcCalInitData.calData = &ar9287_adc_init_dc_cal; /* Better performance without ADC Gain Calibration */ AH5416(ah)->ah_cal.suppCals = ADC_DC_CAL | IQ_MISMATCH_CAL; AH5416(ah)->ah_spurMitigate = ar9280SpurMitigate; AH5416(ah)->ah_writeIni = ar9287WriteIni; ah->ah_setTxPower = ar9287SetTransmitPower; ah->ah_setBoardValues = ar9287SetBoardValues; AH5416(ah)->ah_olcInit = ar9287olcInit; AH5416(ah)->ah_olcTempCompensation = ar9287olcTemperatureCompensation; //AH5416(ah)->ah_setPowerCalTable = ar9287SetPowerCalTable; AH5416(ah)->ah_cal_initcal = ar9287InitCalHardware; AH5416(ah)->ah_cal_pacal = ar9287PACal; /* XXX NF calibration */ /* XXX Ini override? (IFS vars - since the kiwi mac clock is faster?) */ /* XXX what else is kiwi-specific in the radio/calibration pathway? */ AH5416(ah)->ah_rx_chainmask = AR9287_DEFAULT_RXCHAINMASK; AH5416(ah)->ah_tx_chainmask = AR9287_DEFAULT_TXCHAINMASK; if (!ar5416SetResetReg(ah, HAL_RESET_POWER_ON)) { /* reset chip */ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: couldn't reset chip\n", __func__); ecode = HAL_EIO; goto bad; } if (!ar5416SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: couldn't wakeup chip\n", __func__); ecode = HAL_EIO; goto bad; } /* Read Revisions from Chips before taking out of reset */ val = OS_REG_READ(ah, AR_SREV); HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s: ID 0x%x VERSION 0x%x TYPE 0x%x REVISION 0x%x\n", __func__, MS(val, AR_XSREV_ID), MS(val, AR_XSREV_VERSION), MS(val, AR_XSREV_TYPE), MS(val, AR_XSREV_REVISION)); /* NB: include chip type to differentiate from pre-Sowl versions */ AH_PRIVATE(ah)->ah_macVersion = (val & AR_XSREV_VERSION) >> AR_XSREV_TYPE_S; AH_PRIVATE(ah)->ah_macRev = MS(val, AR_XSREV_REVISION); AH_PRIVATE(ah)->ah_ispcie = (val & AR_XSREV_TYPE_HOST_MODE) == 0; /* Don't support Kiwi < 1.2; those are pre-release chips */ if (! AR_SREV_KIWI_12_OR_LATER(ah)) { ath_hal_printf(ah, "[ath]: Kiwi < 1.2 is not supported\n"); ecode = HAL_EIO; goto bad; } /* setup common ini data; rf backends handle remainder */ HAL_INI_INIT(&ahp->ah_ini_modes, ar9287Modes_9287_1_1, 6); HAL_INI_INIT(&ahp->ah_ini_common, ar9287Common_9287_1_1, 2); /* If pcie_clock_req */ HAL_INI_INIT(&AH5416(ah)->ah_ini_pcieserdes, ar9287PciePhy_clkreq_always_on_L1_9287_1_1, 2); /* XXX WoW ini values */ /* Else */ #if 0 HAL_INI_INIT(&AH5416(ah)->ah_ini_pcieserdes, ar9287PciePhy_clkreq_off_L1_9287_1_1, 2); #endif /* Initialise Japan arrays */ HAL_INI_INIT(&ahp9287->ah_ini_cckFirNormal, ar9287Common_normal_cck_fir_coeff_9287_1_1, 2); HAL_INI_INIT(&ahp9287->ah_ini_cckFirJapan2484, ar9287Common_japan_2484_cck_fir_coeff_9287_1_1, 2); ar5416AttachPCIE(ah); ecode = ath_hal_9287EepromAttach(ah); if (ecode != HAL_OK) goto bad; if (!ar5416ChipReset(ah, AH_NULL)) { /* reset chip */ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n", __func__); ecode = HAL_EIO; goto bad; } AH_PRIVATE(ah)->ah_phyRev = OS_REG_READ(ah, AR_PHY_CHIP_ID); if (!ar5212ChipTest(ah)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: hardware self-test failed\n", __func__); ecode = HAL_ESELFTEST; goto bad; } /* * Set correct Baseband to analog shift * setting to access analog chips. */ OS_REG_WRITE(ah, AR_PHY(0), 0x00000007); /* Read Radio Chip Rev Extract */ AH_PRIVATE(ah)->ah_analog5GhzRev = ar5416GetRadioRev(ah); switch (AH_PRIVATE(ah)->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR) { case AR_RAD2133_SREV_MAJOR: /* Sowl: 2G/3x3 */ case AR_RAD5133_SREV_MAJOR: /* Sowl: 2+5G/3x3 */ break; default: if (AH_PRIVATE(ah)->ah_analog5GhzRev == 0) { AH_PRIVATE(ah)->ah_analog5GhzRev = AR_RAD5133_SREV_MAJOR; break; } #ifdef AH_DEBUG HALDEBUG(ah, HAL_DEBUG_ANY, "%s: 5G Radio Chip Rev 0x%02X is not supported by " "this driver\n", __func__, AH_PRIVATE(ah)->ah_analog5GhzRev); ecode = HAL_ENOTSUPP; goto bad; #endif } rfStatus = ar9287RfAttach(ah, &ecode); if (!rfStatus) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: RF setup failed, status %u\n", __func__, ecode); goto bad; } /* * We only implement open-loop TX power control * for the AR9287 in this codebase. */ if (! ath_hal_eepromGetFlag(ah, AR_EEP_OL_PWRCTRL)) { ath_hal_printf(ah, "[ath] AR9287 w/ closed-loop TX power control" " isn't supported.\n"); ecode = HAL_ENOTSUPP; goto bad; } /* * Check whether the power table offset isn't the default. * This can occur with eeprom minor V21 or greater on Merlin. */ (void) ath_hal_eepromGet(ah, AR_EEP_PWR_TABLE_OFFSET, &pwr_table_offset); if (pwr_table_offset != AR5416_PWR_TABLE_OFFSET_DB) ath_hal_printf(ah, "[ath]: default pwr offset: %d dBm != EEPROM pwr offset: %d dBm; curves will be adjusted.\n", AR5416_PWR_TABLE_OFFSET_DB, (int) pwr_table_offset); /* setup rxgain table */ HAL_INI_INIT(&ahp9287->ah_ini_rxgain, ar9287Modes_rx_gain_9287_1_1, 6); /* setup txgain table */ HAL_INI_INIT(&ahp9287->ah_ini_txgain, ar9287Modes_tx_gain_9287_1_1, 6); /* * Got everything we need now to setup the capabilities. */ if (!ar9287FillCapabilityInfo(ah)) { ecode = HAL_EEREAD; goto bad; } ecode = ath_hal_eepromGet(ah, AR_EEP_MACADDR, ahp->ah_macaddr); if (ecode != HAL_OK) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: error getting mac address from EEPROM\n", __func__); goto bad; } /* XXX How about the serial number ? */ /* Read Reg Domain */ AH_PRIVATE(ah)->ah_currentRD = ath_hal_eepromGet(ah, AR_EEP_REGDMN_0, AH_NULL); AH_PRIVATE(ah)->ah_currentRDext = AR9287_RDEXT_DEFAULT; /* * ah_miscMode is populated by ar5416FillCapabilityInfo() * starting from griffin. Set here to make sure that * AR_MISC_MODE_MIC_NEW_LOC_ENABLE is set before a GTK is * placed into hardware. */ if (ahp->ah_miscMode != 0) OS_REG_WRITE(ah, AR_MISC_MODE, OS_REG_READ(ah, AR_MISC_MODE) | ahp->ah_miscMode); ar9287AniSetup(ah); /* Anti Noise Immunity */ /* Setup noise floor min/max/nominal values */ AH5416(ah)->nf_2g.max = AR_PHY_CCA_MAX_GOOD_VAL_9287_2GHZ; AH5416(ah)->nf_2g.min = AR_PHY_CCA_MIN_GOOD_VAL_9287_2GHZ; AH5416(ah)->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_9287_2GHZ; AH5416(ah)->nf_5g.max = AR_PHY_CCA_MAX_GOOD_VAL_9287_5GHZ; AH5416(ah)->nf_5g.min = AR_PHY_CCA_MIN_GOOD_VAL_9287_5GHZ; AH5416(ah)->nf_5g.nominal = AR_PHY_CCA_NOM_VAL_9287_5GHZ; ar5416InitNfHistBuff(AH5416(ah)->ah_cal.nfCalHist); HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s: return\n", __func__); return ah; bad: if (ah != AH_NULL) ah->ah_detach(ah); if (status) *status = ecode; return AH_NULL; } static void ar9287ConfigPCIE(struct ath_hal *ah, HAL_BOOL restore) { if (AH_PRIVATE(ah)->ah_ispcie && !restore) { ath_hal_ini_write(ah, &AH5416(ah)->ah_ini_pcieserdes, 1, 0); OS_DELAY(1000); OS_REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA); OS_REG_WRITE(ah, AR_WA, AR9285_WA_DEFAULT); /* Yes, Kiwi uses the Kite PCIe PHY WA */ } } static void ar9287WriteIni(struct ath_hal *ah, const struct ieee80211_channel *chan) { u_int modesIndex, freqIndex; int regWrites = 0; /* Setup the indices for the next set of register array writes */ /* XXX Ignore 11n dynamic mode on the AR5416 for the moment */ if (IEEE80211_IS_CHAN_2GHZ(chan)) { freqIndex = 2; if (IEEE80211_IS_CHAN_HT40(chan)) modesIndex = 3; else if (IEEE80211_IS_CHAN_108G(chan)) modesIndex = 5; else modesIndex = 4; } else { freqIndex = 1; if (IEEE80211_IS_CHAN_HT40(chan) || IEEE80211_IS_CHAN_TURBO(chan)) modesIndex = 2; else modesIndex = 1; } /* Set correct Baseband to analog shift setting to access analog chips. */ OS_REG_WRITE(ah, AR_PHY(0), 0x00000007); OS_REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_INTERNAL_ADDAC); regWrites = ath_hal_ini_write(ah, &AH5212(ah)->ah_ini_modes, modesIndex, regWrites); regWrites = ath_hal_ini_write(ah, &AH9287(ah)->ah_ini_rxgain, modesIndex, regWrites); regWrites = ath_hal_ini_write(ah, &AH9287(ah)->ah_ini_txgain, modesIndex, regWrites); regWrites = ath_hal_ini_write(ah, &AH5212(ah)->ah_ini_common, 1, regWrites); }
/* * Return the size of the hardware key cache. */ u_int32_t ar5416GetKeyCacheSize(struct ath_hal *ah) { return AH_PRIVATE(ah)->ah_caps.halKeyCacheSize; }
/* * Reads the Interrupt Status Register value from the NIC, thus deasserting * the interrupt line, and returns both the masked and unmasked mapped ISR * values. The value returned is mapped to abstract the hw-specific bit * locations in the Interrupt Status Register. * * (*masked) is cleared on initial call. * * Returns: A hardware-abstracted bitmap of all non-masked-out * interrupts pending, as well as an unmasked value */ HAL_BOOL ar5416GetPendingInterrupts(struct ath_hal *ah, HAL_INT *masked) { uint32_t isr, isr0, isr1, sync_cause = 0, o_sync_cause = 0; HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps; #ifdef AH_INTERRUPT_DEBUGGING /* * Blank the interrupt debugging area regardless. */ bzero(&ah->ah_intrstate, sizeof(ah->ah_intrstate)); ah->ah_syncstate = 0; #endif /* * Verify there's a mac interrupt and the RTC is on. */ if (AR_SREV_HOWL(ah)) { *masked = 0; isr = OS_REG_READ(ah, AR_ISR); } else { if ((OS_REG_READ(ah, AR_INTR_ASYNC_CAUSE) & AR_INTR_MAC_IRQ) && (OS_REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M) == AR_RTC_STATUS_ON) isr = OS_REG_READ(ah, AR_ISR); else isr = 0; #ifdef AH_INTERRUPT_DEBUGGING ah->ah_syncstate = #endif o_sync_cause = sync_cause = OS_REG_READ(ah, AR_INTR_SYNC_CAUSE); sync_cause &= AR_INTR_SYNC_DEFAULT; *masked = 0; if (isr == 0 && sync_cause == 0) return AH_FALSE; } #ifdef AH_INTERRUPT_DEBUGGING ah->ah_intrstate[0] = isr; ah->ah_intrstate[1] = OS_REG_READ(ah, AR_ISR_S0); ah->ah_intrstate[2] = OS_REG_READ(ah, AR_ISR_S1); ah->ah_intrstate[3] = OS_REG_READ(ah, AR_ISR_S2); ah->ah_intrstate[4] = OS_REG_READ(ah, AR_ISR_S3); ah->ah_intrstate[5] = OS_REG_READ(ah, AR_ISR_S4); ah->ah_intrstate[6] = OS_REG_READ(ah, AR_ISR_S5); #endif if (isr != 0) { struct ath_hal_5212 *ahp = AH5212(ah); uint32_t mask2; mask2 = 0; if (isr & AR_ISR_BCNMISC) { uint32_t isr2 = OS_REG_READ(ah, AR_ISR_S2); if (isr2 & AR_ISR_S2_TIM) mask2 |= HAL_INT_TIM; if (isr2 & AR_ISR_S2_DTIM) mask2 |= HAL_INT_DTIM; if (isr2 & AR_ISR_S2_DTIMSYNC) mask2 |= HAL_INT_DTIMSYNC; if (isr2 & (AR_ISR_S2_CABEND )) mask2 |= HAL_INT_CABEND; if (isr2 & AR_ISR_S2_GTT) mask2 |= HAL_INT_GTT; if (isr2 & AR_ISR_S2_CST) mask2 |= HAL_INT_CST; if (isr2 & AR_ISR_S2_TSFOOR) mask2 |= HAL_INT_TSFOOR; /* * Don't mask out AR_BCNMISC; instead mask * out what causes it. */ OS_REG_WRITE(ah, AR_ISR_S2, isr2); isr &= ~AR_ISR_BCNMISC; } if (isr == 0xffffffff) { *masked = 0; return AH_FALSE; } *masked = isr & HAL_INT_COMMON; if (isr & (AR_ISR_RXMINTR | AR_ISR_RXINTM)) *masked |= HAL_INT_RX; if (isr & (AR_ISR_TXMINTR | AR_ISR_TXINTM)) *masked |= HAL_INT_TX; /* * When doing RX interrupt mitigation, the RXOK bit is set * in AR_ISR even if the relevant bit in AR_IMR is clear. * Since this interrupt may be due to another source, don't * just automatically set HAL_INT_RX if it's set, otherwise * we could prematurely service the RX queue. * * In some cases, the driver can even handle all the RX * frames just before the mitigation interrupt fires. * The subsequent RX processing trip will then end up * processing 0 frames. */ #ifdef AH_AR5416_INTERRUPT_MITIGATION if (isr & AR_ISR_RXERR) *masked |= HAL_INT_RX; #else if (isr & (AR_ISR_RXOK | AR_ISR_RXERR)) *masked |= HAL_INT_RX; #endif if (isr & (AR_ISR_TXOK | AR_ISR_TXDESC | AR_ISR_TXERR | AR_ISR_TXEOL)) { *masked |= HAL_INT_TX; isr0 = OS_REG_READ(ah, AR_ISR_S0); OS_REG_WRITE(ah, AR_ISR_S0, isr0); isr1 = OS_REG_READ(ah, AR_ISR_S1); OS_REG_WRITE(ah, AR_ISR_S1, isr1); /* * Don't clear the primary ISR TX bits, clear * what causes them (S0/S1.) */ isr &= ~(AR_ISR_TXOK | AR_ISR_TXDESC | AR_ISR_TXERR | AR_ISR_TXEOL); ahp->ah_intrTxqs |= MS(isr0, AR_ISR_S0_QCU_TXOK); ahp->ah_intrTxqs |= MS(isr0, AR_ISR_S0_QCU_TXDESC); ahp->ah_intrTxqs |= MS(isr1, AR_ISR_S1_QCU_TXERR); ahp->ah_intrTxqs |= MS(isr1, AR_ISR_S1_QCU_TXEOL); } if ((isr & AR_ISR_GENTMR) || (! pCap->halAutoSleepSupport)) { uint32_t isr5; isr5 = OS_REG_READ(ah, AR_ISR_S5); OS_REG_WRITE(ah, AR_ISR_S5, isr5); isr &= ~AR_ISR_GENTMR; if (! pCap->halAutoSleepSupport) if (isr5 & AR_ISR_S5_TIM_TIMER) *masked |= HAL_INT_TIM_TIMER; } *masked |= mask2; } /* * Since we're not using AR_ISR_RAC, clear the status bits * for handled interrupts here. For bits whose interrupt * source is a secondary register, those bits should've been * masked out - instead of those bits being written back, * their source (ie, the secondary status registers) should * be cleared. That way there are no race conditions with * new triggers coming in whilst they've been read/cleared. */ OS_REG_WRITE(ah, AR_ISR, isr); /* Flush previous write */ OS_REG_READ(ah, AR_ISR); if (AR_SREV_HOWL(ah)) return AH_TRUE; if (sync_cause != 0) { HALDEBUG(ah, HAL_DEBUG_INTERRUPT, "%s: sync_cause=0x%x\n", __func__, o_sync_cause); if (sync_cause & (AR_INTR_SYNC_HOST1_FATAL | AR_INTR_SYNC_HOST1_PERR)) { *masked |= HAL_INT_FATAL; } if (sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: RADM CPL timeout\n", __func__); OS_REG_WRITE(ah, AR_RC, AR_RC_HOSTIF); OS_REG_WRITE(ah, AR_RC, 0); *masked |= HAL_INT_FATAL; } /* * On fatal errors collect ISR state for debugging. */ if (*masked & HAL_INT_FATAL) { AH_PRIVATE(ah)->ah_fatalState[0] = isr; AH_PRIVATE(ah)->ah_fatalState[1] = sync_cause; HALDEBUG(ah, HAL_DEBUG_ANY, "%s: fatal error, ISR_RAC 0x%x SYNC_CAUSE 0x%x\n", __func__, isr, sync_cause); } OS_REG_WRITE(ah, AR_INTR_SYNC_CAUSE_CLR, sync_cause); /* NB: flush write */ (void) OS_REG_READ(ah, AR_INTR_SYNC_CAUSE_CLR); } return AH_TRUE; }