/*
* 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];
}
}
//.........这里部分代码省略.........
/*
* 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
*/
void
ar5212SetStaBeaconTimers(struct ath_hal *ah, const HAL_BEACON_STATE *bs)
{
struct ath_hal_5212 *ahp = AH5212(ah);
uint32_t nextTbtt, nextdtim,beaconintval, dtimperiod;
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_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_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.
*/
HALASSERT(bs->bs_bmissthreshold <= MS(0xffffffff, AR_RSSI_THR_BM_THR));
ahp->ah_rssiThr = (ahp->ah_rssiThr &~ AR_RSSI_THR_BM_THR)
| SM(bs->bs_bmissthreshold, AR_RSSI_THR_BM_THR);
OS_REG_WRITE(ah, AR_RSSI_THR, ahp->ah_rssiThr);
/*
* Program the sleep registers to correlate with the beacon setup.
*/
/*
* Oahu beacons timers on the station were used for power
* save operation (waking up in anticipation of a beacon)
* and any CFP function; Venice does sleep/power-save timers
* differently - so this is the right place to set them up;
* don't think the beacon timers are used by venice sta hw
* for any useful purpose anymore
* Setup venice's sleep related timers
* Current implementation assumes sw processing of beacons -
* assuming an interrupt is generated every beacon which
* causes the hardware to become awake until the sw tells
* it to go to sleep again; beacon timeout is to allow for
* beacon jitter; cab timeout is max time to wait for cab
* after seeing the last DTIM or MORE CAB bit
*/
#define CAB_TIMEOUT_VAL 10 /* in TU */
#define BEACON_TIMEOUT_VAL 10 /* in TU */
#define SLEEP_SLOP 3 /* in TU */
/*
* For max powersave mode we may want to sleep for longer than a
* beacon period and not want to receive all beacons; modify the
* timers accordingly; make sure to align the next TIM to the
* next DTIM if we decide to wake for DTIMs only
*/
beaconintval = bs->bs_intval & HAL_BEACON_PERIOD;
HALASSERT(beaconintval != 0);
if (bs->bs_sleepduration > beaconintval) {
HALASSERT(roundup(bs->bs_sleepduration, beaconintval) ==
bs->bs_sleepduration);
beaconintval = bs->bs_sleepduration;
}
dtimperiod = bs->bs_dtimperiod;
if (bs->bs_sleepduration > dtimperiod) {
HALASSERT(dtimperiod == 0 ||
roundup(bs->bs_sleepduration, dtimperiod) ==
//.........这里部分代码省略.........
static void
ar9280WriteIni(struct ath_hal *ah, const struct ieee80211_channel *chan)
{
u_int modesIndex, freqIndex;
int regWrites = 0;
int i;
const HAL_INI_ARRAY *ia;
/* 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);
/*
* This is unwound because at the moment, there's a requirement
* for Merlin (and later, perhaps) to have a specific bit fixed
* in the AR_AN_TOP2 register before writing it.
*/
ia = &AH5212(ah)->ah_ini_modes;
#if 0
regWrites = ath_hal_ini_write(ah, &AH5212(ah)->ah_ini_modes,
modesIndex, regWrites);
#endif
HALASSERT(modesIndex < ia->cols);
for (i = 0; i < ia->rows; i++) {
uint32_t reg = HAL_INI_VAL(ia, i, 0);
uint32_t val = HAL_INI_VAL(ia, i, modesIndex);
if (reg == AR_AN_TOP2 && AH5416(ah)->ah_need_an_top2_fixup)
val &= ~AR_AN_TOP2_PWDCLKIND;
OS_REG_WRITE(ah, reg, val);
/* Analog shift register delay seems needed for Merlin - PR kern/154220 */
if (reg >= 0x7800 && reg < 0x7900)
OS_DELAY(100);
DMA_YIELD(regWrites);
}
if (AR_SREV_MERLIN_20_OR_LATER(ah)) {
regWrites = ath_hal_ini_write(ah, &AH9280(ah)->ah_ini_rxgain,
modesIndex, regWrites);
regWrites = ath_hal_ini_write(ah, &AH9280(ah)->ah_ini_txgain,
modesIndex, regWrites);
}
/* XXX Merlin 100us delay for shift registers */
regWrites = ath_hal_ini_write(ah, &AH5212(ah)->ah_ini_common,
1, regWrites);
if (AR_SREV_MERLIN_20(ah) && IS_5GHZ_FAST_CLOCK_EN(ah, chan)) {
/* 5GHz channels w/ Fast Clock use different modal values */
regWrites = ath_hal_ini_write(ah, &AH9280(ah)->ah_ini_xmodes,
modesIndex, regWrites);
}
}
/*
* 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_RESET_TYPE resetType,
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 */
//.........这里部分代码省略.........
请发表评论