aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/ath/ath_hal/ar5211
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/ath/ath_hal/ar5211')
-rw-r--r--sys/dev/ath/ath_hal/ar5211/ar5211.h331
-rw-r--r--sys/dev/ath/ath_hal/ar5211/ar5211_attach.c556
-rw-r--r--sys/dev/ath/ath_hal/ar5211/ar5211_beacon.c184
-rw-r--r--sys/dev/ath/ath_hal/ar5211/ar5211_interrupts.c160
-rw-r--r--sys/dev/ath/ath_hal/ar5211/ar5211_keycache.c177
-rw-r--r--sys/dev/ath/ath_hal/ar5211/ar5211_misc.c756
-rw-r--r--sys/dev/ath/ath_hal/ar5211/ar5211_phy.c103
-rw-r--r--sys/dev/ath/ath_hal/ar5211/ar5211_power.c140
-rw-r--r--sys/dev/ath/ath_hal/ar5211/ar5211_recv.c248
-rw-r--r--sys/dev/ath/ath_hal/ar5211/ar5211_reset.c2120
-rw-r--r--sys/dev/ath/ath_hal/ar5211/ar5211_xmit.c699
-rw-r--r--sys/dev/ath/ath_hal/ar5211/ar5211desc.h132
-rw-r--r--sys/dev/ath/ath_hal/ar5211/ar5211phy.h93
-rw-r--r--sys/dev/ath/ath_hal/ar5211/ar5211reg.h863
-rw-r--r--sys/dev/ath/ath_hal/ar5211/boss.ini356
15 files changed, 6918 insertions, 0 deletions
diff --git a/sys/dev/ath/ath_hal/ar5211/ar5211.h b/sys/dev/ath/ath_hal/ar5211/ar5211.h
new file mode 100644
index 000000000000..08396ed85dcb
--- /dev/null
+++ b/sys/dev/ath/ath_hal/ar5211/ar5211.h
@@ -0,0 +1,331 @@
+/*-
+ * SPDX-License-Identifier: ISC
+ *
+ * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
+ * Copyright (c) 2002-2006 Atheros Communications, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifndef _ATH_AR5211_H_
+#define _ATH_AR5211_H_
+
+#include "ah_eeprom.h"
+
+#define AR5211_MAGIC 0x19570405
+
+/* Classes for WME streams */
+#define AC_BK 0
+#define AC_BE 1
+#define AC_VI 2
+#define AC_VO 3
+
+/* DCU Transmit Filter macros */
+#define CALC_MMR(dcu, idx) \
+ ( (4 * dcu) + (idx < 32 ? 0 : (idx < 64 ? 1 : (idx < 96 ? 2 : 3))) )
+#define TXBLK_FROM_MMR(mmr) \
+ (AR_D_TXBLK_BASE + ((mmr & 0x1f) << 6) + ((mmr & 0x20) >> 3))
+#define CALC_TXBLK_ADDR(dcu, idx) (TXBLK_FROM_MMR(CALC_MMR(dcu, idx)))
+#define CALC_TXBLK_VALUE(idx) (1 << (idx & 0x1f))
+
+/* MAC register values */
+
+#define INIT_INTERRUPT_MASK \
+ ( AR_IMR_TXERR | AR_IMR_TXOK | AR_IMR_RXORN | \
+ AR_IMR_RXERR | AR_IMR_RXOK | AR_IMR_TXURN | \
+ AR_IMR_HIUERR )
+#define INIT_BEACON_CONTROL \
+ ( (INIT_RESET_TSF << 24) | (INIT_BEACON_EN << 23) | \
+ (INIT_TIM_OFFSET << 16) | INIT_BEACON_PERIOD )
+
+#define INIT_CONFIG_STATUS 0x00000000
+#define INIT_RSSI_THR 0x00000700 /* Missed beacon counter initialized to 0x7 (max is 0xff) */
+#define INIT_IQCAL_LOG_COUNT_MAX 0xF
+#define INIT_BCON_CNTRL_REG 0x00000000
+
+#define INIT_BEACON_PERIOD 0xffff
+#define INIT_TIM_OFFSET 0
+#define INIT_BEACON_EN 0 /* this should be set by AP only when it's ready */
+#define INIT_RESET_TSF 0
+
+/*
+ * Various fifo fill before Tx start, in 64-byte units
+ * i.e. put the frame in the air while still DMAing
+ */
+#define MIN_TX_FIFO_THRESHOLD 0x1
+#define MAX_TX_FIFO_THRESHOLD ((IEEE80211_MAX_LEN / 64) + 1)
+#define INIT_TX_FIFO_THRESHOLD MIN_TX_FIFO_THRESHOLD
+
+/*
+ * Gain support.
+ */
+typedef struct _gainOptStep {
+ int16_t paramVal[4];
+ int32_t stepGain;
+ int8_t stepName[16];
+} GAIN_OPTIMIZATION_STEP;
+
+typedef struct {
+ uint32_t numStepsInLadder;
+ uint32_t defaultStepNum;
+ GAIN_OPTIMIZATION_STEP optStep[10];
+} GAIN_OPTIMIZATION_LADDER;
+
+typedef struct {
+ uint32_t currStepNum;
+ uint32_t currGain;
+ uint32_t targetGain;
+ uint32_t loTrig;
+ uint32_t hiTrig;
+ uint32_t active;
+ const GAIN_OPTIMIZATION_STEP *currStep;
+} GAIN_VALUES;
+
+enum {
+ RFGAIN_INACTIVE,
+ RFGAIN_READ_REQUESTED,
+ RFGAIN_NEED_CHANGE
+};
+
+/*
+ * Header Info - general parameters and
+ * values set for each chipset board solution
+ * that are programmed every reset
+ */
+struct ath_hal_5211 {
+ struct ath_hal_private ah_priv; /* base class */
+
+ GAIN_VALUES ah_gainValues;
+
+ uint8_t ah_macaddr[IEEE80211_ADDR_LEN];
+ uint8_t ah_bssid[IEEE80211_ADDR_LEN];
+
+ /*
+ * Runtime state.
+ */
+ uint32_t ah_maskReg; /* copy of AR_IMR */
+ uint32_t ah_txOkInterruptMask;
+ uint32_t ah_txErrInterruptMask;
+ uint32_t ah_txDescInterruptMask;
+ uint32_t ah_txEolInterruptMask;
+ uint32_t ah_txUrnInterruptMask;
+ HAL_TX_QUEUE_INFO ah_txq[HAL_NUM_TX_QUEUES];
+ HAL_ANT_SETTING ah_diversityControl; /* antenna setting */
+ uint32_t ah_calibrationTime;
+ HAL_BOOL ah_bIQCalibration;
+ int ah_rfgainState;
+ uint32_t ah_tx6PowerInHalfDbm; /* power output for 6Mb tx */
+ uint32_t ah_staId1Defaults; /* STA_ID1 default settings */
+ uint32_t ah_beaconInterval;
+ uint32_t ah_rssiThr; /* RSSI_THR settings */
+
+ u_int ah_sifstime; /* user-specified sifs time */
+ u_int ah_slottime; /* user-specified slot time */
+ u_int ah_acktimeout; /* user-specified ack timeout */
+ u_int ah_ctstimeout; /* user-specified cts timeout */
+ /*
+ * RF Silent handling.
+ */
+ uint32_t ah_gpioSelect; /* GPIO pin to use */
+ uint32_t ah_polarity; /* polarity to disable RF */
+ uint32_t ah_gpioBit; /* after init, prev value */
+};
+#define AH5211(ah) ((struct ath_hal_5211 *)(ah))
+
+struct ath_hal;
+
+extern void ar5211Detach(struct ath_hal *);
+
+extern HAL_BOOL ar5211Reset(struct ath_hal *, HAL_OPMODE,
+ struct ieee80211_channel *, HAL_BOOL bChannelChange,
+ HAL_RESET_TYPE,
+ HAL_STATUS *);
+extern HAL_BOOL ar5211PhyDisable(struct ath_hal *);
+extern HAL_BOOL ar5211Disable(struct ath_hal *);
+extern HAL_BOOL ar5211ChipReset(struct ath_hal *,
+ const struct ieee80211_channel *);
+extern HAL_BOOL ar5211PerCalibration(struct ath_hal *, struct ieee80211_channel *, HAL_BOOL *);
+extern HAL_BOOL ar5211PerCalibrationN(struct ath_hal *ah, struct ieee80211_channel *chan,
+ u_int chainMask, HAL_BOOL longCal, HAL_BOOL *isCalDone);
+extern HAL_BOOL ar5211ResetCalValid(struct ath_hal *ah, const struct ieee80211_channel *);
+extern HAL_BOOL ar5211SetTxPowerLimit(struct ath_hal *, uint32_t limit);
+extern HAL_BOOL ar5211CalNoiseFloor(struct ath_hal *,
+ const struct ieee80211_channel *);
+extern HAL_BOOL ar5211SetAntennaSwitchInternal(struct ath_hal *,
+ HAL_ANT_SETTING, const struct ieee80211_channel *);
+extern int16_t ar5211GetNfAdjust(struct ath_hal *,
+ const HAL_CHANNEL_INTERNAL *);
+extern HAL_BOOL ar5211ResetDma(struct ath_hal *, HAL_OPMODE);
+extern void ar5211InitializeGainValues(struct ath_hal *);
+extern HAL_RFGAIN ar5211GetRfgain(struct ath_hal *);
+extern void ar5211SetPCUConfig(struct ath_hal *);
+
+extern HAL_BOOL ar5211SetTxQueueProps(struct ath_hal *ah, int q,
+ const HAL_TXQ_INFO *qInfo);
+extern HAL_BOOL ar5211GetTxQueueProps(struct ath_hal *ah, int q,
+ HAL_TXQ_INFO *qInfo);
+extern int ar5211SetupTxQueue(struct ath_hal *ah, HAL_TX_QUEUE type,
+ const HAL_TXQ_INFO *qInfo);
+extern HAL_BOOL ar5211ReleaseTxQueue(struct ath_hal *ah, u_int q);
+extern HAL_BOOL ar5211ResetTxQueue(struct ath_hal *ah, u_int q);
+extern uint32_t ar5211GetTxDP(struct ath_hal *, u_int);
+extern HAL_BOOL ar5211SetTxDP(struct ath_hal *, u_int, uint32_t txdp);
+extern HAL_BOOL ar5211UpdateTxTrigLevel(struct ath_hal *, HAL_BOOL);
+extern HAL_BOOL ar5211StartTxDma(struct ath_hal *, u_int);
+extern HAL_BOOL ar5211StopTxDma(struct ath_hal *, u_int);
+extern uint32_t ar5211NumTxPending(struct ath_hal *, u_int qnum);
+extern HAL_BOOL ar5211IsTxQueueStopped(struct ath_hal *, u_int);
+extern HAL_BOOL ar5211GetTransmitFilterIndex(struct ath_hal *, uint32_t);
+extern HAL_BOOL ar5211SetupTxDesc(struct ath_hal *, struct ath_desc *,
+ u_int pktLen, u_int hdrLen, HAL_PKT_TYPE type, u_int txPower,
+ u_int txRate0, u_int txTries0,
+ u_int keyIx, u_int antMode, u_int flags,
+ u_int rtsctsRate, u_int rtsctsDuration,
+ u_int compicvLen, u_int compivLen, u_int comp);
+extern HAL_BOOL ar5211SetupXTxDesc(struct ath_hal *, struct ath_desc *,
+ u_int txRate1, u_int txRetries1,
+ u_int txRate2, u_int txRetries2,
+ u_int txRate3, u_int txRetries3);
+extern HAL_BOOL ar5211FillTxDesc(struct ath_hal *, struct ath_desc *,
+ HAL_DMA_ADDR *bufAddrList, uint32_t *segLenList,
+ u_int descId, u_int qcuId, HAL_BOOL firstSeg, HAL_BOOL lastSeg,
+ const struct ath_desc *ds0);
+extern HAL_STATUS ar5211ProcTxDesc(struct ath_hal *,
+ struct ath_desc *, struct ath_tx_status *);
+extern void ar5211GetTxIntrQueue(struct ath_hal *ah, uint32_t *);
+extern void ar5211IntrReqTxDesc(struct ath_hal *ah, struct ath_desc *);
+extern HAL_BOOL ar5211GetTxCompletionRates(struct ath_hal *ah,
+ const struct ath_desc *ds0, int *rates, int *tries);
+extern void ar5211SetTxDescLink(struct ath_hal *ah, void *ds,
+ uint32_t link);
+extern void ar5211GetTxDescLink(struct ath_hal *ah, void *ds,
+ uint32_t *link);
+extern void ar5211GetTxDescLinkPtr(struct ath_hal *ah, void *ds,
+ uint32_t **linkptr);
+
+extern uint32_t ar5211GetRxDP(struct ath_hal *, HAL_RX_QUEUE);
+extern void ar5211SetRxDP(struct ath_hal *, uint32_t rxdp, HAL_RX_QUEUE);
+extern void ar5211EnableReceive(struct ath_hal *);
+extern HAL_BOOL ar5211StopDmaReceive(struct ath_hal *);
+extern void ar5211StartPcuReceive(struct ath_hal *, HAL_BOOL);
+extern void ar5211StopPcuReceive(struct ath_hal *);
+extern void ar5211SetMulticastFilter(struct ath_hal *,
+ uint32_t filter0, uint32_t filter1);
+extern HAL_BOOL ar5211ClrMulticastFilterIndex(struct ath_hal *, uint32_t);
+extern HAL_BOOL ar5211SetMulticastFilterIndex(struct ath_hal *, uint32_t);
+extern uint32_t ar5211GetRxFilter(struct ath_hal *);
+extern void ar5211SetRxFilter(struct ath_hal *, uint32_t);
+extern HAL_BOOL ar5211SetupRxDesc(struct ath_hal *, struct ath_desc *,
+ uint32_t, u_int flags);
+extern HAL_STATUS ar5211ProcRxDesc(struct ath_hal *, struct ath_desc *,
+ uint32_t, struct ath_desc *, uint64_t,
+ struct ath_rx_status *);
+
+extern void ar5211GetMacAddress(struct ath_hal *, uint8_t *);
+extern HAL_BOOL ar5211SetMacAddress(struct ath_hal *ah, const uint8_t *);
+extern void ar5211GetBssIdMask(struct ath_hal *, uint8_t *);
+extern HAL_BOOL ar5211SetBssIdMask(struct ath_hal *, const uint8_t *);
+extern HAL_BOOL ar5211EepromRead(struct ath_hal *, u_int off, uint16_t *data);
+extern HAL_BOOL ar5211EepromWrite(struct ath_hal *, u_int off, uint16_t data);
+extern HAL_BOOL ar5211SetRegulatoryDomain(struct ath_hal *,
+ uint16_t, HAL_STATUS *);
+extern u_int ar5211GetWirelessModes(struct ath_hal *);
+extern void ar5211EnableRfKill(struct ath_hal *);
+extern uint32_t ar5211GpioGet(struct ath_hal *, uint32_t gpio);
+extern void ar5211GpioSetIntr(struct ath_hal *, u_int, uint32_t ilevel);
+extern HAL_BOOL ar5211GpioCfgOutput(struct ath_hal *, uint32_t gpio,
+ HAL_GPIO_MUX_TYPE);
+extern HAL_BOOL ar5211GpioCfgInput(struct ath_hal *, uint32_t gpio);
+extern HAL_BOOL ar5211GpioSet(struct ath_hal *, uint32_t gpio, uint32_t val);
+extern void ar5211SetLedState(struct ath_hal *, HAL_LED_STATE);
+extern u_int ar5211AntennaGet(struct ath_hal *);
+extern void ar5211WriteAssocid(struct ath_hal *,
+ const uint8_t *bssid, uint16_t assocId);
+extern uint64_t ar5211GetTsf64(struct ath_hal *);
+extern uint32_t ar5211GetTsf32(struct ath_hal *);
+extern void ar5211ResetTsf(struct ath_hal *);
+extern uint32_t ar5211GetMaxTurboRate(struct ath_hal *);
+extern uint32_t ar5211GetRandomSeed(struct ath_hal *);
+extern HAL_BOOL ar5211DetectCardPresent(struct ath_hal *);
+extern void ar5211UpdateMibCounters(struct ath_hal *, HAL_MIB_STATS *);
+extern void ar5211EnableHwEncryption(struct ath_hal *);
+extern void ar5211DisableHwEncryption(struct ath_hal *);
+extern HAL_BOOL ar5211SetSlotTime(struct ath_hal *, u_int);
+extern u_int ar5211GetSlotTime(struct ath_hal *);
+extern HAL_BOOL ar5211SetAckTimeout(struct ath_hal *, u_int);
+extern u_int ar5211GetAckTimeout(struct ath_hal *);
+extern HAL_BOOL ar5211SetAckCTSRate(struct ath_hal *, u_int);
+extern u_int ar5211GetAckCTSRate(struct ath_hal *);
+extern HAL_BOOL ar5211SetCTSTimeout(struct ath_hal *, u_int);
+extern u_int ar5211GetCTSTimeout(struct ath_hal *);
+extern HAL_BOOL ar5211SetSifsTime(struct ath_hal *, u_int);
+extern u_int ar5211GetSifsTime(struct ath_hal *);
+extern HAL_BOOL ar5211SetDecompMask(struct ath_hal *, uint16_t, int);
+extern void ar5211SetCoverageClass(struct ath_hal *, uint8_t, int);
+extern HAL_STATUS ar5211SetQuiet(struct ath_hal *, uint32_t, uint32_t,
+ uint32_t, HAL_QUIET_FLAG);
+extern uint32_t ar5211GetCurRssi(struct ath_hal *);
+extern u_int ar5211GetDefAntenna(struct ath_hal *);
+extern void ar5211SetDefAntenna(struct ath_hal *ah, u_int antenna);
+extern HAL_ANT_SETTING ar5211GetAntennaSwitch(struct ath_hal *);
+extern HAL_BOOL ar5211SetAntennaSwitch(struct ath_hal *, HAL_ANT_SETTING);
+extern HAL_STATUS ar5211GetCapability(struct ath_hal *, HAL_CAPABILITY_TYPE,
+ uint32_t, uint32_t *);
+extern HAL_BOOL ar5211SetCapability(struct ath_hal *, HAL_CAPABILITY_TYPE,
+ uint32_t, uint32_t, HAL_STATUS *);
+extern HAL_BOOL ar5211GetDiagState(struct ath_hal *ah, int request,
+ const void *args, uint32_t argsize,
+ void **result, uint32_t *resultsize);
+extern uint32_t ar5211Get11nExtBusy(struct ath_hal *);
+extern HAL_BOOL ar5211GetMibCycleCounts(struct ath_hal *,
+ HAL_SURVEY_SAMPLE *);
+extern void ar5211SetChainMasks(struct ath_hal *ah, uint32_t, uint32_t);
+extern void ar5211SetNav(struct ath_hal *ah, u_int);
+extern u_int ar5211GetNav(struct ath_hal *ah);
+
+extern void ar5211EnableDfs(struct ath_hal *, HAL_PHYERR_PARAM *);
+extern void ar5211GetDfsThresh(struct ath_hal *, HAL_PHYERR_PARAM *);
+
+extern u_int ar5211GetKeyCacheSize(struct ath_hal *);
+extern HAL_BOOL ar5211IsKeyCacheEntryValid(struct ath_hal *, uint16_t);
+extern HAL_BOOL ar5211ResetKeyCacheEntry(struct ath_hal *, uint16_t entry);
+extern HAL_BOOL ar5211SetKeyCacheEntry(struct ath_hal *, uint16_t entry,
+ const HAL_KEYVAL *, const uint8_t *mac,
+ int xorKey);
+extern HAL_BOOL ar5211SetKeyCacheEntryMac(struct ath_hal *,
+ uint16_t, const uint8_t *);
+
+extern HAL_BOOL ar5211SetPowerMode(struct ath_hal *, HAL_POWER_MODE mode,
+ int setChip);
+extern HAL_POWER_MODE ar5211GetPowerMode(struct ath_hal *);
+
+extern void ar5211SetBeaconTimers(struct ath_hal *,
+ const HAL_BEACON_TIMERS *);
+extern void ar5211BeaconInit(struct ath_hal *, uint32_t, uint32_t);
+extern void ar5211SetStaBeaconTimers(struct ath_hal *,
+ const HAL_BEACON_STATE *);
+extern void ar5211ResetStaBeaconTimers(struct ath_hal *);
+extern uint64_t ar5211GetNextTBTT(struct ath_hal *);
+
+extern HAL_BOOL ar5211IsInterruptPending(struct ath_hal *);
+extern HAL_BOOL ar5211GetPendingInterrupts(struct ath_hal *, HAL_INT *);
+extern HAL_INT ar5211GetInterrupts(struct ath_hal *);
+extern HAL_INT ar5211SetInterrupts(struct ath_hal *, HAL_INT ints);
+
+extern const HAL_RATE_TABLE *ar5211GetRateTable(struct ath_hal *, u_int mode);
+
+extern HAL_BOOL ar5211AniControl(struct ath_hal *, HAL_ANI_CMD, int );
+extern void ar5211RxMonitor(struct ath_hal *, const HAL_NODE_STATS *,
+ const struct ieee80211_channel *);
+extern void ar5211AniPoll(struct ath_hal *, const struct ieee80211_channel *);
+extern void ar5211MibEvent(struct ath_hal *, const HAL_NODE_STATS *);
+#endif /* _ATH_AR5211_H_ */
diff --git a/sys/dev/ath/ath_hal/ar5211/ar5211_attach.c b/sys/dev/ath/ath_hal/ar5211/ar5211_attach.c
new file mode 100644
index 000000000000..1b01f2a282b8
--- /dev/null
+++ b/sys/dev/ath/ath_hal/ar5211/ar5211_attach.c
@@ -0,0 +1,556 @@
+/*-
+ * SPDX-License-Identifier: ISC
+ *
+ * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
+ * Copyright (c) 2002-2006 Atheros Communications, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include "opt_ah.h"
+
+#include "ah.h"
+#include "ah_internal.h"
+#include "ah_devid.h"
+
+#include "ar5211/ar5211.h"
+#include "ar5211/ar5211reg.h"
+#include "ar5211/ar5211phy.h"
+
+#include "ah_eeprom_v3.h"
+
+static HAL_BOOL ar5211GetChannelEdges(struct ath_hal *ah,
+ uint16_t flags, uint16_t *low, uint16_t *high);
+static HAL_BOOL ar5211GetChipPowerLimits(struct ath_hal *ah,
+ struct ieee80211_channel *chan);
+
+static void ar5211ConfigPCIE(struct ath_hal *ah, HAL_BOOL restore,
+ HAL_BOOL power_off);
+static void ar5211DisablePCIE(struct ath_hal *ah);
+
+static const struct ath_hal_private ar5211hal = {{
+ .ah_magic = AR5211_MAGIC,
+
+ .ah_getRateTable = ar5211GetRateTable,
+ .ah_detach = ar5211Detach,
+
+ /* Reset Functions */
+ .ah_reset = ar5211Reset,
+ .ah_phyDisable = ar5211PhyDisable,
+ .ah_disable = ar5211Disable,
+ .ah_configPCIE = ar5211ConfigPCIE,
+ .ah_disablePCIE = ar5211DisablePCIE,
+ .ah_setPCUConfig = ar5211SetPCUConfig,
+ .ah_perCalibration = ar5211PerCalibration,
+ .ah_perCalibrationN = ar5211PerCalibrationN,
+ .ah_resetCalValid = ar5211ResetCalValid,
+ .ah_setTxPowerLimit = ar5211SetTxPowerLimit,
+ .ah_getChanNoise = ath_hal_getChanNoise,
+
+ /* Transmit functions */
+ .ah_updateTxTrigLevel = ar5211UpdateTxTrigLevel,
+ .ah_setupTxQueue = ar5211SetupTxQueue,
+ .ah_setTxQueueProps = ar5211SetTxQueueProps,
+ .ah_getTxQueueProps = ar5211GetTxQueueProps,
+ .ah_releaseTxQueue = ar5211ReleaseTxQueue,
+ .ah_resetTxQueue = ar5211ResetTxQueue,
+ .ah_getTxDP = ar5211GetTxDP,
+ .ah_setTxDP = ar5211SetTxDP,
+ .ah_numTxPending = ar5211NumTxPending,
+ .ah_startTxDma = ar5211StartTxDma,
+ .ah_stopTxDma = ar5211StopTxDma,
+ .ah_setupTxDesc = ar5211SetupTxDesc,
+ .ah_setupXTxDesc = ar5211SetupXTxDesc,
+ .ah_fillTxDesc = ar5211FillTxDesc,
+ .ah_procTxDesc = ar5211ProcTxDesc,
+ .ah_getTxIntrQueue = ar5211GetTxIntrQueue,
+ .ah_reqTxIntrDesc = ar5211IntrReqTxDesc,
+ .ah_getTxCompletionRates = ar5211GetTxCompletionRates,
+ .ah_setTxDescLink = ar5211SetTxDescLink,
+ .ah_getTxDescLink = ar5211GetTxDescLink,
+ .ah_getTxDescLinkPtr = ar5211GetTxDescLinkPtr,
+
+ /* RX Functions */
+ .ah_getRxDP = ar5211GetRxDP,
+ .ah_setRxDP = ar5211SetRxDP,
+ .ah_enableReceive = ar5211EnableReceive,
+ .ah_stopDmaReceive = ar5211StopDmaReceive,
+ .ah_startPcuReceive = ar5211StartPcuReceive,
+ .ah_stopPcuReceive = ar5211StopPcuReceive,
+ .ah_setMulticastFilter = ar5211SetMulticastFilter,
+ .ah_setMulticastFilterIndex = ar5211SetMulticastFilterIndex,
+ .ah_clrMulticastFilterIndex = ar5211ClrMulticastFilterIndex,
+ .ah_getRxFilter = ar5211GetRxFilter,
+ .ah_setRxFilter = ar5211SetRxFilter,
+ .ah_setupRxDesc = ar5211SetupRxDesc,
+ .ah_procRxDesc = ar5211ProcRxDesc,
+ .ah_rxMonitor = ar5211RxMonitor,
+ .ah_aniPoll = ar5211AniPoll,
+ .ah_procMibEvent = ar5211MibEvent,
+
+ /* Misc Functions */
+ .ah_getCapability = ar5211GetCapability,
+ .ah_setCapability = ar5211SetCapability,
+ .ah_getDiagState = ar5211GetDiagState,
+ .ah_getMacAddress = ar5211GetMacAddress,
+ .ah_setMacAddress = ar5211SetMacAddress,
+ .ah_getBssIdMask = ar5211GetBssIdMask,
+ .ah_setBssIdMask = ar5211SetBssIdMask,
+ .ah_setRegulatoryDomain = ar5211SetRegulatoryDomain,
+ .ah_setLedState = ar5211SetLedState,
+ .ah_writeAssocid = ar5211WriteAssocid,
+ .ah_gpioCfgInput = ar5211GpioCfgInput,
+ .ah_gpioCfgOutput = ar5211GpioCfgOutput,
+ .ah_gpioGet = ar5211GpioGet,
+ .ah_gpioSet = ar5211GpioSet,
+ .ah_gpioSetIntr = ar5211GpioSetIntr,
+ .ah_getTsf32 = ar5211GetTsf32,
+ .ah_getTsf64 = ar5211GetTsf64,
+ .ah_resetTsf = ar5211ResetTsf,
+ .ah_detectCardPresent = ar5211DetectCardPresent,
+ .ah_updateMibCounters = ar5211UpdateMibCounters,
+ .ah_getRfGain = ar5211GetRfgain,
+ .ah_getDefAntenna = ar5211GetDefAntenna,
+ .ah_setDefAntenna = ar5211SetDefAntenna,
+ .ah_getAntennaSwitch = ar5211GetAntennaSwitch,
+ .ah_setAntennaSwitch = ar5211SetAntennaSwitch,
+ .ah_setSifsTime = ar5211SetSifsTime,
+ .ah_getSifsTime = ar5211GetSifsTime,
+ .ah_setSlotTime = ar5211SetSlotTime,
+ .ah_getSlotTime = ar5211GetSlotTime,
+ .ah_setAckTimeout = ar5211SetAckTimeout,
+ .ah_getAckTimeout = ar5211GetAckTimeout,
+ .ah_setAckCTSRate = ar5211SetAckCTSRate,
+ .ah_getAckCTSRate = ar5211GetAckCTSRate,
+ .ah_setCTSTimeout = ar5211SetCTSTimeout,
+ .ah_getCTSTimeout = ar5211GetCTSTimeout,
+ .ah_setDecompMask = ar5211SetDecompMask,
+ .ah_setCoverageClass = ar5211SetCoverageClass,
+ .ah_setQuiet = ar5211SetQuiet,
+ .ah_get11nExtBusy = ar5211Get11nExtBusy,
+ .ah_getMibCycleCounts = ar5211GetMibCycleCounts,
+ .ah_setChainMasks = ar5211SetChainMasks,
+ .ah_enableDfs = ar5211EnableDfs,
+ .ah_getDfsThresh = ar5211GetDfsThresh,
+ /* XXX procRadarEvent */
+ /* XXX isFastClockEnabled */
+ .ah_setNav = ar5211SetNav,
+ .ah_getNav = ar5211GetNav,
+
+ /* Key Cache Functions */
+ .ah_getKeyCacheSize = ar5211GetKeyCacheSize,
+ .ah_resetKeyCacheEntry = ar5211ResetKeyCacheEntry,
+ .ah_isKeyCacheEntryValid = ar5211IsKeyCacheEntryValid,
+ .ah_setKeyCacheEntry = ar5211SetKeyCacheEntry,
+ .ah_setKeyCacheEntryMac = ar5211SetKeyCacheEntryMac,
+
+ /* Power Management Functions */
+ .ah_setPowerMode = ar5211SetPowerMode,
+ .ah_getPowerMode = ar5211GetPowerMode,
+
+ /* Beacon Functions */
+ .ah_setBeaconTimers = ar5211SetBeaconTimers,
+ .ah_beaconInit = ar5211BeaconInit,
+ .ah_setStationBeaconTimers = ar5211SetStaBeaconTimers,
+ .ah_resetStationBeaconTimers = ar5211ResetStaBeaconTimers,
+ .ah_getNextTBTT = ar5211GetNextTBTT,
+
+ /* Interrupt Functions */
+ .ah_isInterruptPending = ar5211IsInterruptPending,
+ .ah_getPendingInterrupts = ar5211GetPendingInterrupts,
+ .ah_getInterrupts = ar5211GetInterrupts,
+ .ah_setInterrupts = ar5211SetInterrupts },
+
+ .ah_getChannelEdges = ar5211GetChannelEdges,
+ .ah_getWirelessModes = ar5211GetWirelessModes,
+ .ah_eepromRead = ar5211EepromRead,
+#ifdef AH_SUPPORT_WRITE_EEPROM
+ .ah_eepromWrite = ar5211EepromWrite,
+#endif
+ .ah_getChipPowerLimits = ar5211GetChipPowerLimits,
+};
+
+static HAL_BOOL ar5211ChipTest(struct ath_hal *);
+static HAL_BOOL ar5211FillCapabilityInfo(struct ath_hal *ah);
+
+/*
+ * Return the revsion id for the radio chip. This
+ * fetched via the PHY.
+ */
+static uint32_t
+ar5211GetRadioRev(struct ath_hal *ah)
+{
+ uint32_t val;
+ int i;
+
+ OS_REG_WRITE(ah, (AR_PHY_BASE + (0x34 << 2)), 0x00001c16);
+ for (i = 0; i < 8; i++)
+ OS_REG_WRITE(ah, (AR_PHY_BASE + (0x20 << 2)), 0x00010000);
+ val = (OS_REG_READ(ah, AR_PHY_BASE + (256 << 2)) >> 24) & 0xff;
+ val = ((val & 0xf0) >> 4) | ((val & 0x0f) << 4);
+ return ath_hal_reverseBits(val, 8);
+}
+
+/*
+ * Attach for an AR5211 part.
+ */
+static struct ath_hal *
+ar5211Attach(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)
+{
+#define N(a) (sizeof(a)/sizeof(a[0]))
+ struct ath_hal_5211 *ahp;
+ struct ath_hal *ah;
+ 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, (void*) st, (void*) sh);
+
+ /* NB: memory is returned zero'd */
+ ahp = ath_hal_malloc(sizeof (struct ath_hal_5211));
+ if (ahp == AH_NULL) {
+ HALDEBUG(AH_NULL, HAL_DEBUG_ANY,
+ "%s: cannot allocate memory for state block\n", __func__);
+ ecode = HAL_ENOMEM;
+ goto bad;
+ }
+ ah = &ahp->ah_priv.h;
+ /* set initial values */
+ OS_MEMCPY(&ahp->ah_priv, &ar5211hal, sizeof(struct ath_hal_private));
+ ah->ah_sc = sc;
+ ah->ah_st = st;
+ ah->ah_sh = sh;
+
+ ah->ah_devid = devid; /* NB: for AH_DEBUG_ALQ */
+ AH_PRIVATE(ah)->ah_devid = devid;
+ AH_PRIVATE(ah)->ah_subvendorid = 0; /* XXX */
+
+ AH_PRIVATE(ah)->ah_powerLimit = MAX_RATE_POWER;
+ AH_PRIVATE(ah)->ah_tpScale = HAL_TP_SCALE_MAX; /* no scaling */
+
+ ahp->ah_diversityControl = HAL_ANT_VARIABLE;
+ ahp->ah_staId1Defaults = 0;
+ ahp->ah_rssiThr = INIT_RSSI_THR;
+ ahp->ah_sifstime = (u_int) -1;
+ ahp->ah_slottime = (u_int) -1;
+ ahp->ah_acktimeout = (u_int) -1;
+ ahp->ah_ctstimeout = (u_int) -1;
+
+ if (!ar5211ChipReset(ah, AH_NULL)) { /* reset chip */
+ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n", __func__);
+ ecode = HAL_EIO;
+ goto bad;
+ }
+ if (AH_PRIVATE(ah)->ah_devid == AR5211_FPGA11B) {
+ /* set it back to OFDM mode to be able to read analog rev id */
+ OS_REG_WRITE(ah, AR5211_PHY_MODE, AR5211_PHY_MODE_OFDM);
+ OS_REG_WRITE(ah, AR_PHY_PLL_CTL, AR_PHY_PLL_CTL_44);
+ OS_DELAY(1000);
+ }
+
+ /* Read Revisions from Chips */
+ val = OS_REG_READ(ah, AR_SREV) & AR_SREV_ID_M;
+ AH_PRIVATE(ah)->ah_macVersion = val >> AR_SREV_ID_S;
+ AH_PRIVATE(ah)->ah_macRev = val & AR_SREV_REVISION_M;
+
+ if (AH_PRIVATE(ah)->ah_macVersion < AR_SREV_VERSION_MAUI_2 ||
+ AH_PRIVATE(ah)->ah_macVersion > AR_SREV_VERSION_OAHU) {
+ HALDEBUG(ah, HAL_DEBUG_ANY,
+ "%s: Mac Chip Rev 0x%x is not supported by this driver\n",
+ __func__, AH_PRIVATE(ah)->ah_macVersion);
+ ecode = HAL_ENOTSUPP;
+ goto bad;
+ }
+
+ AH_PRIVATE(ah)->ah_phyRev = OS_REG_READ(ah, AR_PHY_CHIP_ID);
+
+ if (!ar5211ChipTest(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. */
+ if (AH_PRIVATE(ah)->ah_macVersion >= AR_SREV_VERSION_OAHU) {
+ OS_REG_WRITE(ah, AR_PHY_BASE, 0x00000007);
+ } else {
+ OS_REG_WRITE(ah, AR_PHY_BASE, 0x00000047);
+ }
+ OS_DELAY(2000);
+
+ /* Read Radio Chip Rev Extract */
+ AH_PRIVATE(ah)->ah_analog5GhzRev = ar5211GetRadioRev(ah);
+ if ((AH_PRIVATE(ah)->ah_analog5GhzRev & 0xf0) != RAD5_SREV_MAJOR) {
+ 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;
+ }
+
+ val = (OS_REG_READ(ah, AR_PCICFG) & AR_PCICFG_EEPROM_SIZE_M) >>
+ AR_PCICFG_EEPROM_SIZE_S;
+ if (val != AR_PCICFG_EEPROM_SIZE_16K) {
+ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unsupported EEPROM size "
+ "%u (0x%x) found\n", __func__, val, val);
+ ecode = HAL_EESIZE;
+ goto bad;
+ }
+ ecode = ath_hal_legacyEepromAttach(ah);
+ if (ecode != HAL_OK) {
+ goto bad;
+ }
+
+ /* If Bmode and AR5211, verify 2.4 analog exists */
+ if (AH_PRIVATE(ah)->ah_macVersion >= AR_SREV_VERSION_OAHU &&
+ ath_hal_eepromGetFlag(ah, AR_EEP_BMODE)) {
+ /* Set correct Baseband to analog shift setting to access analog chips. */
+ OS_REG_WRITE(ah, AR_PHY_BASE, 0x00004007);
+ OS_DELAY(2000);
+ AH_PRIVATE(ah)->ah_analog2GhzRev = ar5211GetRadioRev(ah);
+
+ /* Set baseband for 5GHz chip */
+ OS_REG_WRITE(ah, AR_PHY_BASE, 0x00000007);
+ OS_DELAY(2000);
+ if ((AH_PRIVATE(ah)->ah_analog2GhzRev & 0xF0) != RAD2_SREV_MAJOR) {
+ HALDEBUG(ah, HAL_DEBUG_ANY,
+ "%s: 2G Radio Chip Rev 0x%x is not supported by "
+ "this driver\n", __func__,
+ AH_PRIVATE(ah)->ah_analog2GhzRev);
+ ecode = HAL_ENOTSUPP;
+ goto bad;
+ }
+ } else {
+ ath_hal_eepromSet(ah, AR_EEP_BMODE, AH_FALSE);
+ }
+
+ ecode = ath_hal_eepromGet(ah, AR_EEP_REGDMN_0, &eeval);
+ if (ecode != HAL_OK) {
+ HALDEBUG(ah, HAL_DEBUG_ANY,
+ "%s: cannot read regulatory domain from EEPROM\n",
+ __func__);
+ goto bad;
+ }
+ AH_PRIVATE(ah)->ah_currentRD = eeval;
+ AH_PRIVATE(ah)->ah_getNfAdjust = ar5211GetNfAdjust;
+
+ /*
+ * Got everything we need now to setup the capabilities.
+ */
+ (void) ar5211FillCapabilityInfo(ah);
+
+ /* Initialize gain ladder thermal calibration structure */
+ ar5211InitializeGainValues(ah);
+
+ 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;
+ }
+
+ HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s: return\n", __func__);
+
+ return ah;
+bad:
+ if (ahp)
+ ar5211Detach((struct ath_hal *) ahp);
+ if (status)
+ *status = ecode;
+ return AH_NULL;
+#undef N
+}
+
+void
+ar5211Detach(struct ath_hal *ah)
+{
+ HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s:\n", __func__);
+
+ HALASSERT(ah != AH_NULL);
+ HALASSERT(ah->ah_magic == AR5211_MAGIC);
+
+ ath_hal_eepromDetach(ah);
+ ath_hal_free(ah);
+}
+
+static HAL_BOOL
+ar5211ChipTest(struct ath_hal *ah)
+{
+ uint32_t regAddr[2] = { AR_STA_ID0, AR_PHY_BASE+(8 << 2) };
+ uint32_t regHold[2];
+ uint32_t patternData[4] =
+ { 0x55555555, 0xaaaaaaaa, 0x66666666, 0x99999999 };
+ int i, j;
+
+ /* Test PHY & MAC registers */
+ for (i = 0; i < 2; i++) {
+ uint32_t addr = regAddr[i];
+ uint32_t wrData, rdData;
+
+ regHold[i] = OS_REG_READ(ah, addr);
+ for (j = 0; j < 0x100; j++) {
+ wrData = (j << 16) | j;
+ OS_REG_WRITE(ah, addr, wrData);
+ rdData = OS_REG_READ(ah, addr);
+ if (rdData != wrData) {
+ HALDEBUG(ah, HAL_DEBUG_ANY,
+"%s: address test failed addr: 0x%08x - wr:0x%08x != rd:0x%08x\n",
+ __func__, addr, wrData, rdData);
+ return AH_FALSE;
+ }
+ }
+ for (j = 0; j < 4; j++) {
+ wrData = patternData[j];
+ OS_REG_WRITE(ah, addr, wrData);
+ rdData = OS_REG_READ(ah, addr);
+ if (wrData != rdData) {
+ HALDEBUG(ah, HAL_DEBUG_ANY,
+"%s: address test failed addr: 0x%08x - wr:0x%08x != rd:0x%08x\n",
+ __func__, addr, wrData, rdData);
+ return AH_FALSE;
+ }
+ }
+ OS_REG_WRITE(ah, regAddr[i], regHold[i]);
+ }
+ OS_DELAY(100);
+ return AH_TRUE;
+}
+
+/*
+ * Store the channel edges for the requested operational mode
+ */
+static HAL_BOOL
+ar5211GetChannelEdges(struct ath_hal *ah,
+ uint16_t flags, uint16_t *low, uint16_t *high)
+{
+ if (flags & IEEE80211_CHAN_5GHZ) {
+ *low = 4920;
+ *high = 6100;
+ return AH_TRUE;
+ }
+ if (flags & IEEE80211_CHAN_2GHZ &&
+ ath_hal_eepromGetFlag(ah, AR_EEP_BMODE)) {
+ *low = 2312;
+ *high = 2732;
+ return AH_TRUE;
+ }
+ return AH_FALSE;
+}
+
+static HAL_BOOL
+ar5211GetChipPowerLimits(struct ath_hal *ah, struct ieee80211_channel *chan)
+{
+ /* XXX fill in, this is just a placeholder */
+ HALDEBUG(ah, HAL_DEBUG_ATTACH,
+ "%s: no min/max power for %u/0x%x\n",
+ __func__, chan->ic_freq, chan->ic_flags);
+ chan->ic_maxpower = MAX_RATE_POWER;
+ chan->ic_minpower = 0;
+ return AH_TRUE;
+}
+
+static void
+ar5211ConfigPCIE(struct ath_hal *ah, HAL_BOOL restore, HAL_BOOL power_off)
+{
+}
+
+static void
+ar5211DisablePCIE(struct ath_hal *ah)
+{
+}
+
+/*
+ * Fill all software cached or static hardware state information.
+ */
+static HAL_BOOL
+ar5211FillCapabilityInfo(struct ath_hal *ah)
+{
+ struct ath_hal_private *ahpriv = AH_PRIVATE(ah);
+ HAL_CAPABILITIES *pCap = &ahpriv->ah_caps;
+
+ /* Construct wireless mode from EEPROM */
+ pCap->halWirelessModes = 0;
+ if (ath_hal_eepromGetFlag(ah, AR_EEP_AMODE)) {
+ pCap->halWirelessModes |= HAL_MODE_11A;
+ if (!ath_hal_eepromGetFlag(ah, AR_EEP_TURBO5DISABLE))
+ pCap->halWirelessModes |= HAL_MODE_TURBO;
+ }
+ if (ath_hal_eepromGetFlag(ah, AR_EEP_BMODE))
+ pCap->halWirelessModes |= HAL_MODE_11B;
+
+ pCap->halLow2GhzChan = 2312;
+ pCap->halHigh2GhzChan = 2732;
+ pCap->halLow5GhzChan = 4920;
+ pCap->halHigh5GhzChan = 6100;
+
+ pCap->halChanSpreadSupport = AH_TRUE;
+ pCap->halSleepAfterBeaconBroken = AH_TRUE;
+ pCap->halPSPollBroken = AH_TRUE;
+ pCap->halVEOLSupport = AH_TRUE;
+ pCap->halNumMRRetries = 1; /* No hardware MRR support */
+ pCap->halNumTxMaps = 1; /* Single TX ptr per descr */
+
+ pCap->halTotalQueues = HAL_NUM_TX_QUEUES;
+ pCap->halKeyCacheSize = 128;
+
+ /* XXX not needed */
+ pCap->halChanHalfRate = AH_FALSE;
+ pCap->halChanQuarterRate = AH_FALSE;
+
+ /*
+ * RSSI uses the combined field; some 11n NICs may use
+ * the control chain RSSI.
+ */
+ pCap->halUseCombinedRadarRssi = AH_TRUE;
+
+ if (ath_hal_eepromGetFlag(ah, AR_EEP_RFKILL) &&
+ ath_hal_eepromGet(ah, AR_EEP_RFSILENT, &ahpriv->ah_rfsilent) == HAL_OK) {
+ /* NB: enabled by default */
+ ahpriv->ah_rfkillEnabled = AH_TRUE;
+ pCap->halRfSilentSupport = AH_TRUE;
+ }
+
+ pCap->halRxTstampPrecision = 13;
+ pCap->halTxTstampPrecision = 16;
+ pCap->halIntrMask = HAL_INT_COMMON
+ | HAL_INT_RX
+ | HAL_INT_TX
+ | HAL_INT_FATAL
+ | HAL_INT_BNR
+ | HAL_INT_TIM
+ ;
+
+ pCap->hal4kbSplitTransSupport = AH_TRUE;
+ pCap->halHasRxSelfLinkedTail = AH_TRUE;
+
+ /* XXX might be ok w/ some chip revs */
+ ahpriv->ah_rxornIsFatal = AH_TRUE;
+ return AH_TRUE;
+}
+
+static const char*
+ar5211Probe(uint16_t vendorid, uint16_t devid)
+{
+ if (vendorid == ATHEROS_VENDOR_ID) {
+ if (devid == AR5211_DEVID || devid == AR5311_DEVID ||
+ devid == AR5211_DEFAULT)
+ return "Atheros 5211";
+ if (devid == AR5211_FPGA11B)
+ return "Atheros 5211 (FPGA)";
+ }
+ return AH_NULL;
+}
+AH_CHIP(AR5211, ar5211Probe, ar5211Attach);
diff --git a/sys/dev/ath/ath_hal/ar5211/ar5211_beacon.c b/sys/dev/ath/ath_hal/ar5211/ar5211_beacon.c
new file mode 100644
index 000000000000..06790b58f772
--- /dev/null
+++ b/sys/dev/ath/ath_hal/ar5211/ar5211_beacon.c
@@ -0,0 +1,184 @@
+/*-
+ * SPDX-License-Identifier: ISC
+ *
+ * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
+ * Copyright (c) 2002-2006 Atheros Communications, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include "opt_ah.h"
+
+#include "ah.h"
+#include "ah_internal.h"
+
+#include "ar5211/ar5211.h"
+#include "ar5211/ar5211reg.h"
+#include "ar5211/ar5211desc.h"
+
+/*
+ * Routines used to initialize and generated beacons for the AR5211/AR5311.
+ */
+
+/*
+ * Return the hardware NextTBTT in TSF
+ */
+uint64_t
+ar5211GetNextTBTT(struct ath_hal *ah)
+{
+#define TU_TO_TSF(_tu) (((uint64_t)(_tu)) << 10)
+ return TU_TO_TSF(OS_REG_READ(ah, AR_TIMER0));
+#undef TU_TO_TSF
+}
+
+/*
+ * Initialize all of the hardware registers used to send beacons.
+ */
+void
+ar5211SetBeaconTimers(struct ath_hal *ah, const HAL_BEACON_TIMERS *bt)
+{
+
+ OS_REG_WRITE(ah, AR_TIMER0, bt->bt_nexttbtt);
+ OS_REG_WRITE(ah, AR_TIMER1, bt->bt_nextdba);
+ OS_REG_WRITE(ah, AR_TIMER2, bt->bt_nextswba);
+ OS_REG_WRITE(ah, AR_TIMER3, bt->bt_nextatim);
+ /*
+ * Set the Beacon register after setting all timers.
+ */
+ OS_REG_WRITE(ah, AR_BEACON, bt->bt_intval);
+}
+
+/*
+ * Legacy api to initialize all of the beacon registers.
+ */
+void
+ar5211BeaconInit(struct ath_hal *ah,
+ uint32_t next_beacon, uint32_t beacon_period)
+{
+ HAL_BEACON_TIMERS bt;
+
+ bt.bt_nexttbtt = next_beacon;
+ /*
+ * TIMER1: in AP/adhoc mode this controls the DMA beacon
+ * alert timer; otherwise it controls the next wakeup time.
+ * TIMER2: in AP mode, it controls the SBA beacon alert
+ * interrupt; otherwise it sets the start of the next CFP.
+ */
+ switch (AH_PRIVATE(ah)->ah_opmode) {
+ case HAL_M_STA:
+ case HAL_M_MONITOR:
+ bt.bt_nextdba = 0xffff;
+ bt.bt_nextswba = 0x7ffff;
+ break;
+ case HAL_M_IBSS:
+ case HAL_M_HOSTAP:
+ bt.bt_nextdba = (next_beacon -
+ ah->ah_config.ah_dma_beacon_response_time) << 3; /* 1/8 TU */
+ bt.bt_nextswba = (next_beacon -
+ ah->ah_config.ah_sw_beacon_response_time) << 3; /* 1/8 TU */
+ break;
+ }
+ /*
+ * Set the ATIM window
+ * Our hardware does not support an ATIM window of 0
+ * (beacons will not work). If the ATIM windows is 0,
+ * force it to 1.
+ */
+ bt.bt_nextatim = next_beacon + 1;
+ bt.bt_intval = beacon_period &
+ (AR_BEACON_PERIOD | AR_BEACON_RESET_TSF | AR_BEACON_EN);
+ ar5211SetBeaconTimers(ah, &bt);
+}
+
+void
+ar5211ResetStaBeaconTimers(struct ath_hal *ah)
+{
+ uint32_t val;
+
+ OS_REG_WRITE(ah, AR_TIMER0, 0); /* no beacons */
+ val = OS_REG_READ(ah, AR_STA_ID1);
+ val |= AR_STA_ID1_PWR_SAV; /* XXX */
+ /* tell the h/w that the associated AP is not PCF capable */
+ OS_REG_WRITE(ah, AR_STA_ID1,
+ val & ~(AR_STA_ID1_DEFAULT_ANTENNA | AR_STA_ID1_PCF));
+ OS_REG_WRITE(ah, AR_BEACON, AR_BEACON_PERIOD);
+}
+
+/*
+ * 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
+ar5211SetStaBeaconTimers(struct ath_hal *ah, const HAL_BEACON_STATE *bs)
+{
+ struct ath_hal_5211 *ahp = AH5211(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_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);
+
+ /*
+ * Set the sleep duration in 1/8 TU's.
+ */
+#define SLEEP_SLOP 3
+ OS_REG_RMW_FIELD(ah, AR_SCR, AR_SCR_SLDUR,
+ (bs->bs_sleepduration - SLEEP_SLOP) << 3);
+#undef SLEEP_SLOP
+}
diff --git a/sys/dev/ath/ath_hal/ar5211/ar5211_interrupts.c b/sys/dev/ath/ath_hal/ar5211/ar5211_interrupts.c
new file mode 100644
index 000000000000..8a4086b01d7e
--- /dev/null
+++ b/sys/dev/ath/ath_hal/ar5211/ar5211_interrupts.c
@@ -0,0 +1,160 @@
+/*-
+ * SPDX-License-Identifier: ISC
+ *
+ * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
+ * Copyright (c) 2002-2006 Atheros Communications, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include "opt_ah.h"
+
+#include "ah.h"
+#include "ah_internal.h"
+
+#include "ar5211/ar5211.h"
+#include "ar5211/ar5211reg.h"
+
+/*
+ * Checks to see if an interrupt is pending on our NIC
+ *
+ * Returns: TRUE if an interrupt is pending
+ * FALSE if not
+ */
+HAL_BOOL
+ar5211IsInterruptPending(struct ath_hal *ah)
+{
+ return OS_REG_READ(ah, AR_INTPEND) != 0;
+}
+
+/*
+ * 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
+ar5211GetPendingInterrupts(struct ath_hal *ah, HAL_INT *masked)
+{
+ uint32_t isr;
+
+ 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_HIUERR)
+ *masked |= HAL_INT_FATAL;
+ 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;
+ /*
+ * Receive overrun is usually non-fatal on Oahu/Spirit.
+ * BUT on some parts rx could fail and the chip must be reset.
+ * So we force a hardware reset in all cases.
+ */
+ if ((isr & AR_ISR_RXORN) && AH_PRIVATE(ah)->ah_rxornIsFatal) {
+ HALDEBUG(ah, HAL_DEBUG_ANY,
+ "%s: receive FIFO overrun interrupt\n", __func__);
+ *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] = OS_REG_READ(ah, AR_ISR_S0_S);
+ AH_PRIVATE(ah)->ah_fatalState[2] = OS_REG_READ(ah, AR_ISR_S1_S);
+ AH_PRIVATE(ah)->ah_fatalState[3] = OS_REG_READ(ah, AR_ISR_S2_S);
+ AH_PRIVATE(ah)->ah_fatalState[4] = OS_REG_READ(ah, AR_ISR_S3_S);
+ AH_PRIVATE(ah)->ah_fatalState[5] = OS_REG_READ(ah, AR_ISR_S4_S);
+ HALDEBUG(ah, HAL_DEBUG_ANY,
+ "%s: fatal error, ISR_RAC=0x%x ISR_S2_S=0x%x\n",
+ __func__, isr, AH_PRIVATE(ah)->ah_fatalState[3]);
+ }
+ return AH_TRUE;
+}
+
+HAL_INT
+ar5211GetInterrupts(struct ath_hal *ah)
+{
+ return AH5211(ah)->ah_maskReg;
+}
+
+/*
+ * Atomically enables NIC interrupts. Interrupts are passed in
+ * via the enumerated bitmask in ints.
+ */
+HAL_INT
+ar5211SetInterrupts(struct ath_hal *ah, HAL_INT ints)
+{
+ struct ath_hal_5211 *ahp = AH5211(ah);
+ uint32_t omask = ahp->ah_maskReg;
+ uint32_t mask;
+
+ HALDEBUG(ah, HAL_DEBUG_INTERRUPT, "%s: 0x%x => 0x%x\n",
+ __func__, omask, ints);
+
+ /*
+ * Disable interrupts here before reading & modifying
+ * the mask so that the ISR does not modify the mask
+ * out from under us.
+ */
+ if (omask & HAL_INT_GLOBAL) {
+ HALDEBUG(ah, HAL_DEBUG_INTERRUPT, "%s: disable IER\n", __func__);
+ OS_REG_WRITE(ah, AR_IER, AR_IER_DISABLE);
+ /* XXX??? */
+ (void) OS_REG_READ(ah, AR_IER); /* flush write to HW */
+ }
+
+ mask = ints & HAL_INT_COMMON;
+ if (ints & HAL_INT_TX) {
+ if (ahp->ah_txOkInterruptMask)
+ mask |= AR_IMR_TXOK;
+ if (ahp->ah_txErrInterruptMask)
+ mask |= AR_IMR_TXERR;
+ if (ahp->ah_txDescInterruptMask)
+ mask |= AR_IMR_TXDESC;
+ if (ahp->ah_txEolInterruptMask)
+ mask |= AR_IMR_TXEOL;
+ }
+ if (ints & HAL_INT_RX)
+ mask |= AR_IMR_RXOK | AR_IMR_RXERR | AR_IMR_RXDESC;
+ if (ints & HAL_INT_FATAL) {
+ /*
+ * NB: ar5212Reset sets MCABT+SSERR+DPERR in AR_IMR_S2
+ * so enabling HIUERR enables delivery.
+ */
+ mask |= AR_IMR_HIUERR;
+ }
+
+ /* Write the new IMR and store off our SW copy. */
+ HALDEBUG(ah, HAL_DEBUG_INTERRUPT, "%s: new IMR 0x%x\n", __func__, mask);
+ OS_REG_WRITE(ah, AR_IMR, mask);
+ ahp->ah_maskReg = ints;
+
+ /* Re-enable interrupts as appropriate. */
+ if (ints & HAL_INT_GLOBAL) {
+ HALDEBUG(ah, HAL_DEBUG_INTERRUPT, "%s: enable IER\n", __func__);
+ OS_REG_WRITE(ah, AR_IER, AR_IER_ENABLE);
+ }
+
+ return omask;
+}
diff --git a/sys/dev/ath/ath_hal/ar5211/ar5211_keycache.c b/sys/dev/ath/ath_hal/ar5211/ar5211_keycache.c
new file mode 100644
index 000000000000..19fb8770ef77
--- /dev/null
+++ b/sys/dev/ath/ath_hal/ar5211/ar5211_keycache.c
@@ -0,0 +1,177 @@
+/*-
+ * SPDX-License-Identifier: ISC
+ *
+ * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
+ * Copyright (c) 2002-2006 Atheros Communications, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include "opt_ah.h"
+
+#include "ah.h"
+#include "ah_internal.h"
+
+#include "ar5211/ar5211.h"
+#include "ar5211/ar5211reg.h"
+
+/*
+ * Chips-specific key cache routines.
+ */
+
+#define AR_KEYTABLE_SIZE 128
+#define KEY_XOR 0xaa
+
+/*
+ * Return the size of the hardware key cache.
+ */
+uint32_t
+ar5211GetKeyCacheSize(struct ath_hal *ah)
+{
+ return AR_KEYTABLE_SIZE;
+}
+
+/*
+ * Return true if the specific key cache entry is valid.
+ */
+HAL_BOOL
+ar5211IsKeyCacheEntryValid(struct ath_hal *ah, uint16_t entry)
+{
+ if (entry < AR_KEYTABLE_SIZE) {
+ uint32_t val = OS_REG_READ(ah, AR_KEYTABLE_MAC1(entry));
+ if (val & AR_KEYTABLE_VALID)
+ return AH_TRUE;
+ }
+ return AH_FALSE;
+}
+
+/*
+ * Clear the specified key cache entry
+ */
+HAL_BOOL
+ar5211ResetKeyCacheEntry(struct ath_hal *ah, uint16_t entry)
+{
+ if (entry < AR_KEYTABLE_SIZE) {
+ OS_REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), 0);
+ OS_REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), 0);
+ OS_REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), 0);
+ OS_REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), 0);
+ OS_REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), 0);
+ OS_REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), 0);
+ OS_REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), 0);
+ OS_REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), 0);
+ return AH_TRUE;
+ }
+ return AH_FALSE;
+}
+
+/*
+ * Sets the mac part of the specified key cache entry and mark it valid.
+ */
+HAL_BOOL
+ar5211SetKeyCacheEntryMac(struct ath_hal *ah, uint16_t entry, const uint8_t *mac)
+{
+ uint32_t macHi, macLo;
+
+ if (entry >= AR_KEYTABLE_SIZE) {
+ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: entry %u out of range\n",
+ __func__, entry);
+ return AH_FALSE;
+ }
+
+ /*
+ * Set MAC address -- shifted right by 1. MacLo is
+ * the 4 MSBs, and MacHi is the 2 LSBs.
+ */
+ if (mac != AH_NULL) {
+ macHi = (mac[5] << 8) | mac[4];
+ macLo = (mac[3] << 24)| (mac[2] << 16)
+ | (mac[1] << 8) | mac[0];
+ macLo >>= 1;
+ macLo |= (macHi & 1) << 31; /* carry */
+ macHi >>= 1;
+ } else {
+ macLo = macHi = 0;
+ }
+
+ OS_REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), macLo);
+ OS_REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), macHi | AR_KEYTABLE_VALID);
+ return AH_TRUE;
+}
+
+/*
+ * Sets the contents of the specified key cache entry.
+ */
+HAL_BOOL
+ar5211SetKeyCacheEntry(struct ath_hal *ah, uint16_t entry,
+ const HAL_KEYVAL *k, const uint8_t *mac,
+ int xorKey)
+{
+ uint32_t key0, key1, key2, key3, key4;
+ uint32_t keyType;
+ uint32_t xorMask= xorKey ?
+ (KEY_XOR << 24 | KEY_XOR << 16 | KEY_XOR << 8 | KEY_XOR) : 0;
+
+ if (entry >= AR_KEYTABLE_SIZE) {
+ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: entry %u out of range\n",
+ __func__, entry);
+ return AH_FALSE;
+ }
+ switch (k->kv_type) {
+ case HAL_CIPHER_AES_OCB:
+ keyType = AR_KEYTABLE_TYPE_AES;
+ break;
+ case HAL_CIPHER_WEP:
+ if (k->kv_len < 40 / NBBY) {
+ HALDEBUG(ah, HAL_DEBUG_ANY,
+ "%s: WEP key length %u too small\n",
+ __func__, k->kv_len);
+ return AH_FALSE;
+ }
+ if (k->kv_len <= 40 / NBBY)
+ keyType = AR_KEYTABLE_TYPE_40;
+ else if (k->kv_len <= 104 / NBBY)
+ keyType = AR_KEYTABLE_TYPE_104;
+ else
+ keyType = AR_KEYTABLE_TYPE_128;
+ break;
+ case HAL_CIPHER_CLR:
+ keyType = AR_KEYTABLE_TYPE_CLR;
+ break;
+ default:
+ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: cipher %u not supported\n",
+ __func__, k->kv_type);
+ return AH_FALSE;
+ }
+
+ key0 = LE_READ_4(k->kv_val+0) ^ xorMask;
+ key1 = (LE_READ_2(k->kv_val+4) ^ xorMask) & 0xffff;
+ key2 = LE_READ_4(k->kv_val+6) ^ xorMask;
+ key3 = (LE_READ_2(k->kv_val+10) ^ xorMask) & 0xffff;
+ key4 = LE_READ_4(k->kv_val+12) ^ xorMask;
+ if (k->kv_len <= 104 / NBBY)
+ key4 &= 0xff;
+
+ /*
+ * Note: WEP key cache hardware requires that each double-word
+ * pair be written in even/odd order (since the destination is
+ * a 64-bit register). Don't reorder these writes w/o
+ * understanding this!
+ */
+ OS_REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0);
+ OS_REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1);
+ OS_REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2);
+ OS_REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3);
+ OS_REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4);
+ OS_REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType);
+ return ar5211SetKeyCacheEntryMac(ah, entry, mac);
+}
diff --git a/sys/dev/ath/ath_hal/ar5211/ar5211_misc.c b/sys/dev/ath/ath_hal/ar5211/ar5211_misc.c
new file mode 100644
index 000000000000..4566d1b6f1cd
--- /dev/null
+++ b/sys/dev/ath/ath_hal/ar5211/ar5211_misc.c
@@ -0,0 +1,756 @@
+/*-
+ * SPDX-License-Identifier: ISC
+ *
+ * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
+ * Copyright (c) 2002-2006 Atheros Communications, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include "opt_ah.h"
+
+#include "ah.h"
+#include "ah_internal.h"
+
+#include "ar5211/ar5211.h"
+#include "ar5211/ar5211reg.h"
+#include "ar5211/ar5211phy.h"
+
+#include "ah_eeprom_v3.h"
+
+#define AR_NUM_GPIO 6 /* 6 GPIO bits */
+#define AR_GPIOD_MASK 0x2f /* 6-bit mask */
+
+void
+ar5211GetMacAddress(struct ath_hal *ah, uint8_t *mac)
+{
+ struct ath_hal_5211 *ahp = AH5211(ah);
+
+ OS_MEMCPY(mac, ahp->ah_macaddr, IEEE80211_ADDR_LEN);
+}
+
+HAL_BOOL
+ar5211SetMacAddress(struct ath_hal *ah, const uint8_t *mac)
+{
+ struct ath_hal_5211 *ahp = AH5211(ah);
+
+ OS_MEMCPY(ahp->ah_macaddr, mac, IEEE80211_ADDR_LEN);
+ return AH_TRUE;
+}
+
+void
+ar5211GetBssIdMask(struct ath_hal *ah, uint8_t *mask)
+{
+ static const uint8_t ones[IEEE80211_ADDR_LEN] =
+ { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+ OS_MEMCPY(mask, ones, IEEE80211_ADDR_LEN);
+}
+
+HAL_BOOL
+ar5211SetBssIdMask(struct ath_hal *ah, const uint8_t *mask)
+{
+ return AH_FALSE;
+}
+
+/*
+ * Read 16 bits of data from the specified EEPROM offset.
+ */
+HAL_BOOL
+ar5211EepromRead(struct ath_hal *ah, u_int off, uint16_t *data)
+{
+ OS_REG_WRITE(ah, AR_EEPROM_ADDR, off);
+ OS_REG_WRITE(ah, AR_EEPROM_CMD, AR_EEPROM_CMD_READ);
+
+ if (!ath_hal_wait(ah, AR_EEPROM_STS,
+ AR_EEPROM_STS_READ_COMPLETE | AR_EEPROM_STS_READ_ERROR,
+ AR_EEPROM_STS_READ_COMPLETE)) {
+ HALDEBUG(ah, HAL_DEBUG_ANY,
+ "%s: read failed for entry 0x%x\n", __func__, off);
+ return AH_FALSE;
+ }
+ *data = OS_REG_READ(ah, AR_EEPROM_DATA) & 0xffff;
+ return AH_TRUE;
+}
+
+#ifdef AH_SUPPORT_WRITE_EEPROM
+/*
+ * Write 16 bits of data to the specified EEPROM offset.
+ */
+HAL_BOOL
+ar5211EepromWrite(struct ath_hal *ah, u_int off, uint16_t data)
+{
+ return AH_FALSE;
+}
+#endif /* AH_SUPPORT_WRITE_EEPROM */
+
+/*
+ * Attempt to change the cards operating regulatory domain to the given value
+ */
+HAL_BOOL
+ar5211SetRegulatoryDomain(struct ath_hal *ah,
+ uint16_t regDomain, HAL_STATUS *status)
+{
+ HAL_STATUS ecode;
+
+ if (AH_PRIVATE(ah)->ah_currentRD == regDomain) {
+ ecode = HAL_EINVAL;
+ goto bad;
+ }
+ /*
+ * Check if EEPROM is configured to allow this; must
+ * be a proper version and the protection bits must
+ * permit re-writing that segment of the EEPROM.
+ */
+ if (ath_hal_eepromGetFlag(ah, AR_EEP_WRITEPROTECT)) {
+ ecode = HAL_EEWRITE;
+ goto bad;
+ }
+#ifdef AH_SUPPORT_WRITE_REGDOMAIN
+ if (ar5211EepromWrite(ah, AR_EEPROM_REG_DOMAIN, regDomain)) {
+ HALDEBUG(ah, HAL_DEBUG_ANY,
+ "%s: set regulatory domain to %u (0x%x)\n",
+ __func__, regDomain, regDomain);
+ AH_PRIVATE(ah)->ah_currentRD = regDomain;
+ return AH_TRUE;
+ }
+#endif
+ ecode = HAL_EIO;
+bad:
+ if (status)
+ *status = ecode;
+ return AH_FALSE;
+}
+
+/*
+ * Return the wireless modes (a,b,g,t) supported by hardware.
+ *
+ * This value is what is actually supported by the hardware
+ * and is unaffected by regulatory/country code settings.
+ *
+ */
+u_int
+ar5211GetWirelessModes(struct ath_hal *ah)
+{
+ u_int mode = 0;
+
+ if (ath_hal_eepromGetFlag(ah, AR_EEP_AMODE)) {
+ mode = HAL_MODE_11A;
+ if (!ath_hal_eepromGetFlag(ah, AR_EEP_TURBO5DISABLE))
+ mode |= HAL_MODE_TURBO | HAL_MODE_108A;
+ }
+ if (ath_hal_eepromGetFlag(ah, AR_EEP_BMODE))
+ mode |= HAL_MODE_11B;
+ return mode;
+}
+
+#if 0
+HAL_BOOL
+ar5211GetTurboDisable(struct ath_hal *ah)
+{
+ return (AH5211(ah)->ah_turboDisable != 0);
+}
+#endif
+
+/*
+ * Called if RfKill is supported (according to EEPROM). Set the interrupt and
+ * GPIO values so the ISR and can disable RF on a switch signal
+ */
+void
+ar5211EnableRfKill(struct ath_hal *ah)
+{
+ uint16_t rfsilent = AH_PRIVATE(ah)->ah_rfsilent;
+ int select = MS(rfsilent, AR_EEPROM_RFSILENT_GPIO_SEL);
+ int polarity = MS(rfsilent, AR_EEPROM_RFSILENT_POLARITY);
+
+ /*
+ * Configure the desired GPIO port for input
+ * and enable baseband rf silence.
+ */
+ ar5211GpioCfgInput(ah, select);
+ OS_REG_SET_BIT(ah, AR_PHY_BASE, 0x00002000);
+ /*
+ * If radio disable switch connection to GPIO bit x is enabled
+ * program GPIO interrupt.
+ * If rfkill bit on eeprom is 1, setupeeprommap routine has already
+ * verified that it is a later version of eeprom, it has a place for
+ * rfkill bit and it is set to 1, indicating that GPIO bit x hardware
+ * connection is present.
+ */
+ ar5211GpioSetIntr(ah, select, (ar5211GpioGet(ah, select) != polarity));
+}
+
+/*
+ * Configure GPIO Output lines
+ */
+HAL_BOOL
+ar5211GpioCfgOutput(struct ath_hal *ah, uint32_t gpio, HAL_GPIO_MUX_TYPE type)
+{
+ uint32_t reg;
+
+ HALASSERT(gpio < AR_NUM_GPIO);
+
+ reg = OS_REG_READ(ah, AR_GPIOCR);
+ reg &= ~(AR_GPIOCR_0_CR_A << (gpio * AR_GPIOCR_CR_SHIFT));
+ reg |= AR_GPIOCR_0_CR_A << (gpio * AR_GPIOCR_CR_SHIFT);
+
+ OS_REG_WRITE(ah, AR_GPIOCR, reg);
+ return AH_TRUE;
+}
+
+/*
+ * Configure GPIO Input lines
+ */
+HAL_BOOL
+ar5211GpioCfgInput(struct ath_hal *ah, uint32_t gpio)
+{
+ uint32_t reg;
+
+ HALASSERT(gpio < AR_NUM_GPIO);
+
+ reg = OS_REG_READ(ah, AR_GPIOCR);
+ reg &= ~(AR_GPIOCR_0_CR_A << (gpio * AR_GPIOCR_CR_SHIFT));
+ reg |= AR_GPIOCR_0_CR_N << (gpio * AR_GPIOCR_CR_SHIFT);
+
+ OS_REG_WRITE(ah, AR_GPIOCR, reg);
+ return AH_TRUE;
+}
+
+/*
+ * Once configured for I/O - set output lines
+ */
+HAL_BOOL
+ar5211GpioSet(struct ath_hal *ah, uint32_t gpio, uint32_t val)
+{
+ uint32_t reg;
+
+ HALASSERT(gpio < AR_NUM_GPIO);
+
+ reg = OS_REG_READ(ah, AR_GPIODO);
+ reg &= ~(1 << gpio);
+ reg |= (val&1) << gpio;
+
+ OS_REG_WRITE(ah, AR_GPIODO, reg);
+ return AH_TRUE;
+}
+
+/*
+ * Once configured for I/O - get input lines
+ */
+uint32_t
+ar5211GpioGet(struct ath_hal *ah, uint32_t gpio)
+{
+ if (gpio < AR_NUM_GPIO) {
+ uint32_t val = OS_REG_READ(ah, AR_GPIODI);
+ val = ((val & AR_GPIOD_MASK) >> gpio) & 0x1;
+ return val;
+ } else {
+ return 0xffffffff;
+ }
+}
+
+/*
+ * Set the GPIO 0 Interrupt (gpio is ignored)
+ */
+void
+ar5211GpioSetIntr(struct ath_hal *ah, u_int gpio, uint32_t ilevel)
+{
+ uint32_t val = OS_REG_READ(ah, AR_GPIOCR);
+
+ /* Clear the bits that we will modify. */
+ val &= ~(AR_GPIOCR_INT_SEL0 | AR_GPIOCR_INT_SELH | AR_GPIOCR_INT_ENA |
+ AR_GPIOCR_0_CR_A);
+
+ val |= AR_GPIOCR_INT_SEL0 | AR_GPIOCR_INT_ENA;
+ if (ilevel)
+ val |= AR_GPIOCR_INT_SELH;
+
+ /* Don't need to change anything for low level interrupt. */
+ OS_REG_WRITE(ah, AR_GPIOCR, val);
+
+ /* Change the interrupt mask. */
+ ar5211SetInterrupts(ah, AH5211(ah)->ah_maskReg | HAL_INT_GPIO);
+}
+
+/*
+ * Change the LED blinking pattern to correspond to the connectivity
+ */
+void
+ar5211SetLedState(struct ath_hal *ah, HAL_LED_STATE state)
+{
+ static const uint32_t ledbits[8] = {
+ AR_PCICFG_LEDCTL_NONE|AR_PCICFG_LEDMODE_PROP, /* HAL_LED_INIT */
+ AR_PCICFG_LEDCTL_PEND|AR_PCICFG_LEDMODE_PROP, /* HAL_LED_SCAN */
+ AR_PCICFG_LEDCTL_PEND|AR_PCICFG_LEDMODE_PROP, /* HAL_LED_AUTH */
+ AR_PCICFG_LEDCTL_ASSOC|AR_PCICFG_LEDMODE_PROP,/* HAL_LED_ASSOC*/
+ AR_PCICFG_LEDCTL_ASSOC|AR_PCICFG_LEDMODE_PROP,/* HAL_LED_RUN */
+ AR_PCICFG_LEDCTL_NONE|AR_PCICFG_LEDMODE_RAND,
+ AR_PCICFG_LEDCTL_NONE|AR_PCICFG_LEDMODE_RAND,
+ AR_PCICFG_LEDCTL_NONE|AR_PCICFG_LEDMODE_RAND,
+ };
+ OS_REG_WRITE(ah, AR_PCICFG,
+ (OS_REG_READ(ah, AR_PCICFG) &~
+ (AR_PCICFG_LEDCTL | AR_PCICFG_LEDMODE))
+ | ledbits[state & 0x7]
+ );
+}
+
+/*
+ * Change association related fields programmed into the hardware.
+ * Writing a valid BSSID to the hardware effectively enables the hardware
+ * to synchronize its TSF to the correct beacons and receive frames coming
+ * from that BSSID. It is called by the SME JOIN operation.
+ */
+void
+ar5211WriteAssocid(struct ath_hal *ah, const uint8_t *bssid, uint16_t assocId)
+{
+ struct ath_hal_5211 *ahp = AH5211(ah);
+
+ /* XXX save bssid for possible re-use on reset */
+ OS_MEMCPY(ahp->ah_bssid, bssid, IEEE80211_ADDR_LEN);
+ 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) |
+ ((assocId & 0x3fff)<<AR_BSS_ID1_AID_S));
+}
+
+/*
+ * Get the current hardware tsf for stamlme.
+ */
+uint64_t
+ar5211GetTsf64(struct ath_hal *ah)
+{
+ uint32_t low1, low2, u32;
+
+ /* sync multi-word read */
+ low1 = OS_REG_READ(ah, AR_TSF_L32);
+ u32 = OS_REG_READ(ah, AR_TSF_U32);
+ low2 = OS_REG_READ(ah, AR_TSF_L32);
+ if (low2 < low1) { /* roll over */
+ /*
+ * If we are not preempted this will work. If we are
+ * then we re-reading AR_TSF_U32 does no good as the
+ * low bits will be meaningless. Likewise reading
+ * L32, U32, U32, then comparing the last two reads
+ * to check for rollover doesn't help if preempted--so
+ * we take this approach as it costs one less PCI
+ * read which can be noticeable when doing things
+ * like timestamping packets in monitor mode.
+ */
+ u32++;
+ }
+ return (((uint64_t) u32) << 32) | ((uint64_t) low2);
+}
+
+/*
+ * Get the current hardware tsf for stamlme.
+ */
+uint32_t
+ar5211GetTsf32(struct ath_hal *ah)
+{
+ return OS_REG_READ(ah, AR_TSF_L32);
+}
+
+/*
+ * Reset the current hardware tsf for stamlme
+ */
+void
+ar5211ResetTsf(struct ath_hal *ah)
+{
+ uint32_t val = OS_REG_READ(ah, AR_BEACON);
+
+ OS_REG_WRITE(ah, AR_BEACON, val | AR_BEACON_RESET_TSF);
+}
+
+/*
+ * Grab a semi-random value from hardware registers - may not
+ * change often
+ */
+uint32_t
+ar5211GetRandomSeed(struct ath_hal *ah)
+{
+ uint32_t nf;
+
+ nf = (OS_REG_READ(ah, AR_PHY(25)) >> 19) & 0x1ff;
+ if (nf & 0x100)
+ nf = 0 - ((nf ^ 0x1ff) + 1);
+ return (OS_REG_READ(ah, AR_TSF_U32) ^
+ OS_REG_READ(ah, AR_TSF_L32) ^ nf);
+}
+
+/*
+ * Detect if our card is present
+ */
+HAL_BOOL
+ar5211DetectCardPresent(struct ath_hal *ah)
+{
+ uint16_t macVersion, macRev;
+ uint32_t v;
+
+ /*
+ * Read the Silicon Revision register and compare that
+ * to what we read at attach time. If the same, we say
+ * a card/device is present.
+ */
+ v = OS_REG_READ(ah, AR_SREV) & AR_SREV_ID_M;
+ macVersion = v >> AR_SREV_ID_S;
+ macRev = v & AR_SREV_REVISION_M;
+ return (AH_PRIVATE(ah)->ah_macVersion == macVersion &&
+ AH_PRIVATE(ah)->ah_macRev == macRev);
+}
+
+/*
+ * Update MIB Counters
+ */
+void
+ar5211UpdateMibCounters(struct ath_hal *ah, HAL_MIB_STATS *stats)
+{
+ stats->ackrcv_bad += OS_REG_READ(ah, AR_ACK_FAIL);
+ stats->rts_bad += OS_REG_READ(ah, AR_RTS_FAIL);
+ stats->fcs_bad += OS_REG_READ(ah, AR_FCS_FAIL);
+ stats->rts_good += OS_REG_READ(ah, AR_RTS_OK);
+ stats->beacons += OS_REG_READ(ah, AR_BEACON_CNT);
+}
+
+HAL_BOOL
+ar5211SetSifsTime(struct ath_hal *ah, u_int us)
+{
+ struct ath_hal_5211 *ahp = AH5211(ah);
+
+ if (us > ath_hal_mac_usec(ah, 0xffff)) {
+ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad SIFS time %u\n",
+ __func__, us);
+ ahp->ah_sifstime = (u_int) -1; /* restore default handling */
+ return AH_FALSE;
+ } else {
+ /* convert to system clocks */
+ OS_REG_WRITE(ah, AR_D_GBL_IFS_SIFS, ath_hal_mac_clks(ah, us));
+ ahp->ah_slottime = us;
+ return AH_TRUE;
+ }
+}
+
+u_int
+ar5211GetSifsTime(struct ath_hal *ah)
+{
+ u_int clks = OS_REG_READ(ah, AR_D_GBL_IFS_SIFS) & 0xffff;
+ return ath_hal_mac_usec(ah, clks); /* convert from system clocks */
+}
+
+HAL_BOOL
+ar5211SetSlotTime(struct ath_hal *ah, u_int us)
+{
+ struct ath_hal_5211 *ahp = AH5211(ah);
+
+ if (us < HAL_SLOT_TIME_9 || us > ath_hal_mac_usec(ah, 0xffff)) {
+ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad slot time %u\n",
+ __func__, us);
+ ahp->ah_slottime = us; /* restore default handling */
+ return AH_FALSE;
+ } else {
+ /* convert to system clocks */
+ OS_REG_WRITE(ah, AR_D_GBL_IFS_SLOT, ath_hal_mac_clks(ah, us));
+ ahp->ah_slottime = us;
+ return AH_TRUE;
+ }
+}
+
+u_int
+ar5211GetSlotTime(struct ath_hal *ah)
+{
+ u_int clks = OS_REG_READ(ah, AR_D_GBL_IFS_SLOT) & 0xffff;
+ return ath_hal_mac_usec(ah, clks); /* convert from system clocks */
+}
+
+HAL_BOOL
+ar5211SetAckTimeout(struct ath_hal *ah, u_int us)
+{
+ struct ath_hal_5211 *ahp = AH5211(ah);
+
+ if (us > ath_hal_mac_usec(ah, MS(0xffffffff, AR_TIME_OUT_ACK))) {
+ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad ack timeout %u\n",
+ __func__, us);
+ ahp->ah_acktimeout = (u_int) -1; /* restore default handling */
+ return AH_FALSE;
+ } else {
+ /* convert to system clocks */
+ OS_REG_RMW_FIELD(ah, AR_TIME_OUT,
+ AR_TIME_OUT_ACK, ath_hal_mac_clks(ah, us));
+ ahp->ah_acktimeout = us;
+ return AH_TRUE;
+ }
+}
+
+u_int
+ar5211GetAckTimeout(struct ath_hal *ah)
+{
+ u_int clks = MS(OS_REG_READ(ah, AR_TIME_OUT), AR_TIME_OUT_ACK);
+ return ath_hal_mac_usec(ah, clks); /* convert from system clocks */
+}
+
+u_int
+ar5211GetAckCTSRate(struct ath_hal *ah)
+{
+ return ((AH5211(ah)->ah_staId1Defaults & AR_STA_ID1_ACKCTS_6MB) == 0);
+}
+
+HAL_BOOL
+ar5211SetAckCTSRate(struct ath_hal *ah, u_int high)
+{
+ struct ath_hal_5211 *ahp = AH5211(ah);
+
+ if (high) {
+ OS_REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_ACKCTS_6MB);
+ ahp->ah_staId1Defaults &= ~AR_STA_ID1_ACKCTS_6MB;
+ } else {
+ OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_ACKCTS_6MB);
+ ahp->ah_staId1Defaults |= AR_STA_ID1_ACKCTS_6MB;
+ }
+ return AH_TRUE;
+}
+
+HAL_BOOL
+ar5211SetCTSTimeout(struct ath_hal *ah, u_int us)
+{
+ struct ath_hal_5211 *ahp = AH5211(ah);
+
+ if (us > ath_hal_mac_usec(ah, MS(0xffffffff, AR_TIME_OUT_CTS))) {
+ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad cts timeout %u\n",
+ __func__, us);
+ ahp->ah_ctstimeout = (u_int) -1; /* restore default handling */
+ return AH_FALSE;
+ } else {
+ /* convert to system clocks */
+ OS_REG_RMW_FIELD(ah, AR_TIME_OUT,
+ AR_TIME_OUT_CTS, ath_hal_mac_clks(ah, us));
+ ahp->ah_ctstimeout = us;
+ return AH_TRUE;
+ }
+}
+
+u_int
+ar5211GetCTSTimeout(struct ath_hal *ah)
+{
+ u_int clks = MS(OS_REG_READ(ah, AR_TIME_OUT), AR_TIME_OUT_CTS);
+ return ath_hal_mac_usec(ah, clks); /* convert from system clocks */
+}
+
+HAL_BOOL
+ar5211SetDecompMask(struct ath_hal *ah, uint16_t keyidx, int en)
+{
+ /* nothing to do */
+ return AH_TRUE;
+}
+
+void
+ar5211SetCoverageClass(struct ath_hal *ah, uint8_t coverageclass, int now)
+{
+}
+
+HAL_STATUS
+ar5211SetQuiet(struct ath_hal *ah, uint32_t period, uint32_t duration,
+ uint32_t next_start, HAL_QUIET_FLAG flags)
+{
+ return HAL_OK;
+}
+
+/*
+ * Control Adaptive Noise Immunity Parameters
+ */
+HAL_BOOL
+ar5211AniControl(struct ath_hal *ah, HAL_ANI_CMD cmd, int param)
+{
+ return AH_FALSE;
+}
+
+void
+ar5211AniPoll(struct ath_hal *ah, const struct ieee80211_channel *chan)
+{
+}
+
+void
+ar5211RxMonitor(struct ath_hal *ah, const HAL_NODE_STATS *stats,
+ const struct ieee80211_channel *chan)
+{
+}
+
+void
+ar5211MibEvent(struct ath_hal *ah, const HAL_NODE_STATS *stats)
+{
+}
+
+/*
+ * Get the rssi of frame curently being received.
+ */
+uint32_t
+ar5211GetCurRssi(struct ath_hal *ah)
+{
+ return (OS_REG_READ(ah, AR_PHY_CURRENT_RSSI) & 0xff);
+}
+
+u_int
+ar5211GetDefAntenna(struct ath_hal *ah)
+{
+ return (OS_REG_READ(ah, AR_DEF_ANTENNA) & 0x7);
+}
+
+void
+ar5211SetDefAntenna(struct ath_hal *ah, u_int antenna)
+{
+ OS_REG_WRITE(ah, AR_DEF_ANTENNA, (antenna & 0x7));
+}
+
+HAL_ANT_SETTING
+ar5211GetAntennaSwitch(struct ath_hal *ah)
+{
+ return AH5211(ah)->ah_diversityControl;
+}
+
+HAL_BOOL
+ar5211SetAntennaSwitch(struct ath_hal *ah, HAL_ANT_SETTING settings)
+{
+ const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan;
+
+ if (chan == AH_NULL) {
+ AH5211(ah)->ah_diversityControl = settings;
+ return AH_TRUE;
+ }
+ return ar5211SetAntennaSwitchInternal(ah, settings, chan);
+}
+
+HAL_STATUS
+ar5211GetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type,
+ uint32_t capability, uint32_t *result)
+{
+
+ switch (type) {
+ case HAL_CAP_CIPHER: /* cipher handled in hardware */
+ switch (capability) {
+ case HAL_CIPHER_AES_OCB:
+ case HAL_CIPHER_WEP:
+ case HAL_CIPHER_CLR:
+ return HAL_OK;
+ default:
+ return HAL_ENOTSUPP;
+ }
+ default:
+ return ath_hal_getcapability(ah, type, capability, result);
+ }
+}
+
+HAL_BOOL
+ar5211SetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type,
+ uint32_t capability, uint32_t setting, HAL_STATUS *status)
+{
+ switch (type) {
+ case HAL_CAP_DIAG: /* hardware diagnostic support */
+ /*
+ * NB: could split this up into virtual capabilities,
+ * (e.g. 1 => ACK, 2 => CTS, etc.) but it hardly
+ * seems worth the additional complexity.
+ */
+#ifdef AH_DEBUG
+ AH_PRIVATE(ah)->ah_diagreg = setting;
+#else
+ AH_PRIVATE(ah)->ah_diagreg = setting & 0x6; /* ACK+CTS */
+#endif
+ OS_REG_WRITE(ah, AR_DIAG_SW, AH_PRIVATE(ah)->ah_diagreg);
+ return AH_TRUE;
+ default:
+ return ath_hal_setcapability(ah, type, capability,
+ setting, status);
+ }
+}
+
+HAL_BOOL
+ar5211GetDiagState(struct ath_hal *ah, int request,
+ const void *args, uint32_t argsize,
+ void **result, uint32_t *resultsize)
+{
+ struct ath_hal_5211 *ahp = AH5211(ah);
+
+ (void) ahp;
+ if (ath_hal_getdiagstate(ah, request, args, argsize, result, resultsize))
+ return AH_TRUE;
+ switch (request) {
+ case HAL_DIAG_EEPROM:
+ return ath_hal_eepromDiag(ah, request,
+ args, argsize, result, resultsize);
+ case HAL_DIAG_RFGAIN:
+ *result = &ahp->ah_gainValues;
+ *resultsize = sizeof(GAIN_VALUES);
+ return AH_TRUE;
+ case HAL_DIAG_RFGAIN_CURSTEP:
+ *result = __DECONST(void *, ahp->ah_gainValues.currStep);
+ *resultsize = (*result == AH_NULL) ?
+ 0 : sizeof(GAIN_OPTIMIZATION_STEP);
+ return AH_TRUE;
+ }
+ return AH_FALSE;
+}
+
+/*
+ * Return what percentage of the extension channel is busy.
+ * This is always disabled for AR5211 series NICs.
+ */
+uint32_t
+ar5211Get11nExtBusy(struct ath_hal *ah)
+{
+ return (0);
+}
+
+/*
+ * There's no channel survey support for the AR5211.
+ */
+HAL_BOOL
+ar5211GetMibCycleCounts(struct ath_hal *ah, HAL_SURVEY_SAMPLE *hsample)
+{
+
+ return (AH_FALSE);
+}
+
+void
+ar5211SetChainMasks(struct ath_hal *ah, uint32_t txchainmask,
+ uint32_t rxchainmask)
+{
+}
+
+void
+ar5211EnableDfs(struct ath_hal *ah, HAL_PHYERR_PARAM *pe)
+{
+}
+
+void
+ar5211GetDfsThresh(struct ath_hal *ah, HAL_PHYERR_PARAM *pe)
+{
+}
+
+/*
+ * Get the current NAV value from the hardware.
+ */
+u_int
+ar5211GetNav(struct ath_hal *ah)
+{
+ uint32_t reg;
+
+ reg = OS_REG_READ(ah, AR_NAV);
+ return (reg);
+}
+
+/*
+ * Set the current NAV value to the hardware.
+ */
+void
+ar5211SetNav(struct ath_hal *ah, u_int val)
+{
+
+ OS_REG_WRITE(ah, AR_NAV, val);
+}
+
diff --git a/sys/dev/ath/ath_hal/ar5211/ar5211_phy.c b/sys/dev/ath/ath_hal/ar5211/ar5211_phy.c
new file mode 100644
index 000000000000..601584763058
--- /dev/null
+++ b/sys/dev/ath/ath_hal/ar5211/ar5211_phy.c
@@ -0,0 +1,103 @@
+/*-
+ * SPDX-License-Identifier: ISC
+ *
+ * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
+ * Copyright (c) 2002-2006 Atheros Communications, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include "opt_ah.h"
+
+#include "ah.h"
+#include "ah_internal.h"
+
+#include "ar5211/ar5211.h"
+
+/* shorthands to compact tables for readability */
+#define OFDM IEEE80211_T_OFDM
+#define CCK IEEE80211_T_CCK
+#define TURBO IEEE80211_T_TURBO
+
+HAL_RATE_TABLE ar5211_11a_table = {
+ 8, /* number of rates */
+ { 0 },
+ {
+/* short ctrl */
+/* valid rateCode Preamble dot11Rate Rate */
+/* 6 Mb */ { AH_TRUE, OFDM, 6000, 0x0b, 0x00, (0x80|12), 0 },
+/* 9 Mb */ { AH_TRUE, OFDM, 9000, 0x0f, 0x00, 18, 0 },
+/* 12 Mb */ { AH_TRUE, OFDM, 12000, 0x0a, 0x00, (0x80|24), 2 },
+/* 18 Mb */ { AH_TRUE, OFDM, 18000, 0x0e, 0x00, 36, 2 },
+/* 24 Mb */ { AH_TRUE, OFDM, 24000, 0x09, 0x00, (0x80|48), 4 },
+/* 36 Mb */ { AH_TRUE, OFDM, 36000, 0x0d, 0x00, 72, 4 },
+/* 48 Mb */ { AH_TRUE, OFDM, 48000, 0x08, 0x00, 96, 4 },
+/* 54 Mb */ { AH_TRUE, OFDM, 54000, 0x0c, 0x00, 108, 4 }
+ },
+};
+
+HAL_RATE_TABLE ar5211_turbo_table = {
+ 8, /* number of rates */
+ { 0 },
+ {
+/* short ctrl */
+/* valid rateCode Preamble dot11Rate Rate */
+/* 6 Mb */ { AH_TRUE, TURBO, 12000, 0x0b, 0x00, (0x80|12), 0 },
+/* 9 Mb */ { AH_TRUE, TURBO, 18000, 0x0f, 0x00, 18, 0 },
+/* 12 Mb */ { AH_TRUE, TURBO, 24000, 0x0a, 0x00, (0x80|24), 2 },
+/* 18 Mb */ { AH_TRUE, TURBO, 36000, 0x0e, 0x00, 36, 2 },
+/* 24 Mb */ { AH_TRUE, TURBO, 48000, 0x09, 0x00, (0x80|48), 4 },
+/* 36 Mb */ { AH_TRUE, TURBO, 72000, 0x0d, 0x00, 72, 4 },
+/* 48 Mb */ { AH_TRUE, TURBO, 96000, 0x08, 0x00, 96, 4 },
+/* 54 Mb */ { AH_TRUE, TURBO, 108000, 0x0c, 0x00, 108, 4 }
+ },
+};
+
+HAL_RATE_TABLE ar5211_11b_table = {
+ 4, /* number of rates */
+ { 0 },
+ {
+/* short ctrl */
+/* valid rateCode Preamble dot11Rate Rate */
+/* 1 Mb */ { AH_TRUE, CCK, 1000, 0x0b, 0x00, (0x80| 2), 0 },
+/* 2 Mb */ { AH_TRUE, CCK, 2000, 0x0a, 0x04, (0x80| 4), 1 },
+/* 5.5 Mb */ { AH_TRUE, CCK, 5500, 0x09, 0x04, (0x80|11), 1 },
+/* 11 Mb */ { AH_TRUE, CCK, 11000, 0x08, 0x04, (0x80|22), 1 }
+ },
+};
+
+#undef OFDM
+#undef CCK
+#undef TURBO
+
+const HAL_RATE_TABLE *
+ar5211GetRateTable(struct ath_hal *ah, u_int mode)
+{
+ HAL_RATE_TABLE *rt;
+ switch (mode) {
+ case HAL_MODE_11A:
+ rt = &ar5211_11a_table;
+ break;
+ case HAL_MODE_11B:
+ rt = &ar5211_11b_table;
+ break;
+ case HAL_MODE_TURBO:
+ rt = &ar5211_turbo_table;
+ break;
+ default:
+ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid mode 0x%x\n",
+ __func__, mode);
+ return AH_NULL;
+ }
+ ath_hal_setupratetable(ah, rt);
+ return rt;
+}
diff --git a/sys/dev/ath/ath_hal/ar5211/ar5211_power.c b/sys/dev/ath/ath_hal/ar5211/ar5211_power.c
new file mode 100644
index 000000000000..4fa177b4522e
--- /dev/null
+++ b/sys/dev/ath/ath_hal/ar5211/ar5211_power.c
@@ -0,0 +1,140 @@
+/*-
+ * SPDX-License-Identifier: ISC
+ *
+ * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
+ * Copyright (c) 2002-2006 Atheros Communications, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include "opt_ah.h"
+
+#include "ah.h"
+#include "ah_internal.h"
+
+#include "ar5211/ar5211.h"
+#include "ar5211/ar5211reg.h"
+#include "ar5211/ar5211desc.h"
+
+/*
+ * Notify Power Mgt is enabled in self-generated frames.
+ * If requested, force chip awake.
+ *
+ * Returns A_OK if chip is awake or successfully forced awake.
+ *
+ * WARNING WARNING WARNING
+ * There is a problem with the chip where sometimes it will not wake up.
+ */
+static HAL_BOOL
+ar5211SetPowerModeAwake(struct ath_hal *ah, int setChip)
+{
+#define POWER_UP_TIME 2000
+ uint32_t val;
+ int i;
+
+ if (setChip) {
+ OS_REG_RMW_FIELD(ah, AR_SCR, AR_SCR_SLE, AR_SCR_SLE_WAKE);
+ OS_DELAY(10); /* Give chip the chance to awake */
+
+ for (i = POWER_UP_TIME / 200; i != 0; i--) {
+ val = OS_REG_READ(ah, AR_PCICFG);
+ if ((val & AR_PCICFG_SPWR_DN) == 0)
+ break;
+ OS_DELAY(200);
+ OS_REG_RMW_FIELD(ah, AR_SCR, AR_SCR_SLE,
+ AR_SCR_SLE_WAKE);
+ }
+ if (i == 0) {
+#ifdef AH_DEBUG
+ ath_hal_printf(ah, "%s: Failed to wakeup in %ums\n",
+ __func__, POWER_UP_TIME/20);
+#endif
+ return AH_FALSE;
+ }
+ }
+
+ OS_REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
+ return AH_TRUE;
+#undef POWER_UP_TIME
+}
+
+/*
+ * Notify Power Mgt is disabled in self-generated frames.
+ * If requested, force chip to sleep.
+ */
+static void
+ar5211SetPowerModeSleep(struct ath_hal *ah, int setChip)
+{
+ OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
+ if (setChip)
+ OS_REG_RMW_FIELD(ah, AR_SCR, AR_SCR_SLE, AR_SCR_SLE_SLP);
+}
+
+/*
+ * Notify Power Management is enabled in self-generating
+ * fames. If request, set power mode of chip to
+ * auto/normal. Duration in units of 128us (1/8 TU).
+ */
+static void
+ar5211SetPowerModeNetworkSleep(struct ath_hal *ah, int setChip)
+{
+ OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
+ if (setChip)
+ OS_REG_RMW_FIELD(ah, AR_SCR, AR_SCR_SLE, AR_SCR_SLE_NORM);
+}
+
+HAL_BOOL
+ar5211SetPowerMode(struct ath_hal *ah, HAL_POWER_MODE mode, int setChip)
+{
+#ifdef AH_DEBUG
+ static const char* modes[] = {
+ "AWAKE",
+ "FULL-SLEEP",
+ "NETWORK SLEEP",
+ "UNDEFINED"
+ };
+#endif
+ int status = AH_TRUE;
+
+ HALDEBUG(ah, HAL_DEBUG_POWER, "%s: %s -> %s (%s)\n", __func__,
+ modes[ah->ah_powerMode], modes[mode],
+ setChip ? "set chip " : "");
+ switch (mode) {
+ case HAL_PM_AWAKE:
+ if (setChip)
+ ah->ah_powerMode = mode;
+ status = ar5211SetPowerModeAwake(ah, setChip);
+ break;
+ case HAL_PM_FULL_SLEEP:
+ ar5211SetPowerModeSleep(ah, setChip);
+ if (setChip)
+ ah->ah_powerMode = mode;
+ break;
+ case HAL_PM_NETWORK_SLEEP:
+ ar5211SetPowerModeNetworkSleep(ah, setChip);
+ if (setChip)
+ ah->ah_powerMode = mode;
+ break;
+ default:
+ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unknown power mode %u\n",
+ __func__, mode);
+ return AH_FALSE;
+ }
+ return status;
+}
+
+HAL_POWER_MODE
+ar5211GetPowerMode(struct ath_hal *ah)
+{
+ /* Just so happens the h/w maps directly to the abstracted value */
+ return MS(OS_REG_READ(ah, AR_SCR), AR_SCR_SLE);
+}
diff --git a/sys/dev/ath/ath_hal/ar5211/ar5211_recv.c b/sys/dev/ath/ath_hal/ar5211/ar5211_recv.c
new file mode 100644
index 000000000000..874333e8e752
--- /dev/null
+++ b/sys/dev/ath/ath_hal/ar5211/ar5211_recv.c
@@ -0,0 +1,248 @@
+/*-
+ * SPDX-License-Identifier: ISC
+ *
+ * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
+ * Copyright (c) 2002-2006 Atheros Communications, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include "opt_ah.h"
+
+#include "ah.h"
+#include "ah_internal.h"
+#include "ah_desc.h"
+
+#include "ar5211/ar5211.h"
+#include "ar5211/ar5211reg.h"
+#include "ar5211/ar5211desc.h"
+
+/*
+ * Get the RXDP.
+ */
+uint32_t
+ar5211GetRxDP(struct ath_hal *ah, HAL_RX_QUEUE qtype)
+{
+
+ HALASSERT(qtype == HAL_RX_QUEUE_HP);
+ return OS_REG_READ(ah, AR_RXDP);
+}
+
+/*
+ * Set the RxDP.
+ */
+void
+ar5211SetRxDP(struct ath_hal *ah, uint32_t rxdp, HAL_RX_QUEUE qtype)
+{
+
+ HALASSERT(qtype == HAL_RX_QUEUE_HP);
+ OS_REG_WRITE(ah, AR_RXDP, rxdp);
+ HALASSERT(OS_REG_READ(ah, AR_RXDP) == rxdp);
+}
+
+/*
+ * Set Receive Enable bits.
+ */
+void
+ar5211EnableReceive(struct ath_hal *ah)
+{
+ OS_REG_WRITE(ah, AR_CR, AR_CR_RXE);
+}
+
+/*
+ * Stop Receive at the DMA engine
+ */
+HAL_BOOL
+ar5211StopDmaReceive(struct ath_hal *ah)
+{
+ OS_REG_WRITE(ah, AR_CR, AR_CR_RXD); /* Set receive disable bit */
+ if (!ath_hal_wait(ah, AR_CR, AR_CR_RXE, 0)) {
+#ifdef AH_DEBUG
+ ath_hal_printf(ah, "%s failed to stop in 10ms\n"
+ "AR_CR=0x%08X\nAR_DIAG_SW=0x%08X\n"
+ , __func__
+ , OS_REG_READ(ah, AR_CR)
+ , OS_REG_READ(ah, AR_DIAG_SW)
+ );
+#endif
+ return AH_FALSE;
+ } else {
+ return AH_TRUE;
+ }
+}
+
+/*
+ * Start Transmit at the PCU engine (unpause receive)
+ */
+void
+ar5211StartPcuReceive(struct ath_hal *ah, HAL_BOOL is_scanning)
+{
+ OS_REG_WRITE(ah, AR_DIAG_SW,
+ OS_REG_READ(ah, AR_DIAG_SW) & ~(AR_DIAG_SW_DIS_RX));
+}
+
+/*
+ * Stop Transmit at the PCU engine (pause receive)
+ */
+void
+ar5211StopPcuReceive(struct ath_hal *ah)
+{
+ OS_REG_WRITE(ah, AR_DIAG_SW,
+ OS_REG_READ(ah, AR_DIAG_SW) | AR_DIAG_SW_DIS_RX);
+}
+
+/*
+ * Set multicast filter 0 (lower 32-bits)
+ * filter 1 (upper 32-bits)
+ */
+void
+ar5211SetMulticastFilter(struct ath_hal *ah, uint32_t filter0, uint32_t filter1)
+{
+ OS_REG_WRITE(ah, AR_MCAST_FIL0, filter0);
+ OS_REG_WRITE(ah, AR_MCAST_FIL1, filter1);
+}
+
+/*
+ * Clear multicast filter by index
+ */
+HAL_BOOL
+ar5211ClrMulticastFilterIndex(struct ath_hal *ah, uint32_t ix)
+{
+ uint32_t val;
+
+ if (ix >= 64)
+ return AH_FALSE;
+ if (ix >= 32) {
+ val = OS_REG_READ(ah, AR_MCAST_FIL1);
+ OS_REG_WRITE(ah, AR_MCAST_FIL1, (val &~ (1<<(ix-32))));
+ } else {
+ val = OS_REG_READ(ah, AR_MCAST_FIL0);
+ OS_REG_WRITE(ah, AR_MCAST_FIL0, (val &~ (1<<ix)));
+ }
+ return AH_TRUE;
+}
+
+/*
+ * Set multicast filter by index
+ */
+HAL_BOOL
+ar5211SetMulticastFilterIndex(struct ath_hal *ah, uint32_t ix)
+{
+ uint32_t val;
+
+ if (ix >= 64)
+ return AH_FALSE;
+ if (ix >= 32) {
+ val = OS_REG_READ(ah, AR_MCAST_FIL1);
+ OS_REG_WRITE(ah, AR_MCAST_FIL1, (val | (1<<(ix-32))));
+ } else {
+ val = OS_REG_READ(ah, AR_MCAST_FIL0);
+ OS_REG_WRITE(ah, AR_MCAST_FIL0, (val | (1<<ix)));
+ }
+ return AH_TRUE;
+}
+
+/*
+ * Get receive filter.
+ */
+uint32_t
+ar5211GetRxFilter(struct ath_hal *ah)
+{
+ return OS_REG_READ(ah, AR_RX_FILTER);
+}
+
+/*
+ * Set receive filter.
+ */
+void
+ar5211SetRxFilter(struct ath_hal *ah, uint32_t bits)
+{
+ OS_REG_WRITE(ah, AR_RX_FILTER, bits);
+}
+
+/*
+ * Initialize RX descriptor, by clearing the status and clearing
+ * the size. This is not strictly HW dependent, but we want the
+ * control and status words to be opaque above the hal.
+ */
+HAL_BOOL
+ar5211SetupRxDesc(struct ath_hal *ah, struct ath_desc *ds,
+ uint32_t size, u_int flags)
+{
+ struct ar5211_desc *ads = AR5211DESC(ds);
+
+ ads->ds_ctl0 = 0;
+ ads->ds_ctl1 = size & AR_BufLen;
+ if (ads->ds_ctl1 != size) {
+ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: buffer size %u too large\n",
+ __func__, size);
+ return AH_FALSE;
+ }
+ if (flags & HAL_RXDESC_INTREQ)
+ ads->ds_ctl1 |= AR_RxInterReq;
+ ads->ds_status0 = ads->ds_status1 = 0;
+
+ 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
+ar5211ProcRxDesc(struct ath_hal *ah, struct ath_desc *ds,
+ uint32_t pa, struct ath_desc *nds, uint64_t tsf,
+ struct ath_rx_status *rs)
+{
+ struct ar5211_desc *ads = AR5211DESC(ds);
+ struct ar5211_desc *ands = AR5211DESC(nds);
+
+ if ((ads->ds_status1 & AR_Done) == 0)
+ return HAL_EINPROGRESS;
+ /*
+ * Given the use of a self-linked tail be very sure that the hw is
+ * done with this descriptor; the hw may have done this descriptor
+ * once and picked it up again...make sure the hw has moved on.
+ */
+ if ((ands->ds_status1 & AR_Done) == 0 && OS_REG_READ(ah, AR_RXDP) == pa)
+ return HAL_EINPROGRESS;
+
+ rs->rs_datalen = ads->ds_status0 & AR_DataLen;
+ rs->rs_tstamp = MS(ads->ds_status1, AR_RcvTimestamp);
+ rs->rs_status = 0;
+ if ((ads->ds_status1 & AR_FrmRcvOK) == 0) {
+ if (ads->ds_status1 & AR_CRCErr)
+ rs->rs_status |= HAL_RXERR_CRC;
+ else if (ads->ds_status1 & AR_DecryptCRCErr)
+ rs->rs_status |= HAL_RXERR_DECRYPT;
+ else {
+ rs->rs_status |= HAL_RXERR_PHY;
+ rs->rs_phyerr = MS(ads->ds_status1, AR_PHYErr);
+ }
+ }
+ /* XXX what about KeyCacheMiss? */
+ rs->rs_rssi = MS(ads->ds_status0, AR_RcvSigStrength);
+ if (ads->ds_status1 & AR_KeyIdxValid)
+ rs->rs_keyix = MS(ads->ds_status1, AR_KeyIdx);
+ else
+ rs->rs_keyix = HAL_RXKEYIX_INVALID;
+ /* NB: caller expected to do rate table mapping */
+ rs->rs_rate = MS(ads->ds_status0, AR_RcvRate);
+ rs->rs_antenna = MS(ads->ds_status0, AR_RcvAntenna);
+ rs->rs_more = (ads->ds_status0 & AR_More) ? 1 : 0;
+
+ return HAL_OK;
+}
diff --git a/sys/dev/ath/ath_hal/ar5211/ar5211_reset.c b/sys/dev/ath/ath_hal/ar5211/ar5211_reset.c
new file mode 100644
index 000000000000..fa5293777f02
--- /dev/null
+++ b/sys/dev/ath/ath_hal/ar5211/ar5211_reset.c
@@ -0,0 +1,2120 @@
+/*-
+ * SPDX-License-Identifier: ISC
+ *
+ * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
+ * Copyright (c) 2002-2006 Atheros Communications, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include "opt_ah.h"
+
+/*
+ * Chips specific device attachment and device info collection
+ * Connects Init Reg Vectors, EEPROM Data, and device Functions.
+ */
+#include "ah.h"
+#include "ah_internal.h"
+#include "ah_devid.h"
+
+#include "ar5211/ar5211.h"
+#include "ar5211/ar5211reg.h"
+#include "ar5211/ar5211phy.h"
+
+#include "ah_eeprom_v3.h"
+
+/* Add static register initialization vectors */
+#include "ar5211/boss.ini"
+
+/*
+ * Structure to hold 11b tuning information for Beanie/Sombrero
+ * 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;
+
+#define CI_2GHZ_INDEX_CORRECTION 19
+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 */
+};
+
+/* Power timeouts in usec to wait for chip to wake-up. */
+#define POWER_UP_TIME 2000
+
+#define DELAY_PLL_SETTLE 300 /* 300 us */
+#define DELAY_BASE_ACTIVATE 100 /* 100 us */
+
+#define NUM_RATES 8
+
+static HAL_BOOL ar5211SetResetReg(struct ath_hal *ah, uint32_t resetMask);
+static HAL_BOOL ar5211SetChannel(struct ath_hal *,
+ const struct ieee80211_channel *);
+static int16_t ar5211RunNoiseFloor(struct ath_hal *,
+ uint8_t runTime, int16_t startingNF);
+static HAL_BOOL ar5211IsNfGood(struct ath_hal *,
+ struct ieee80211_channel *chan);
+static HAL_BOOL ar5211SetRf6and7(struct ath_hal *,
+ const struct ieee80211_channel *chan);
+static HAL_BOOL ar5211SetBoardValues(struct ath_hal *,
+ const struct ieee80211_channel *chan);
+static void ar5211SetPowerTable(struct ath_hal *,
+ PCDACS_EEPROM *pSrcStruct, uint16_t channel);
+static HAL_BOOL ar5211SetTransmitPower(struct ath_hal *,
+ const struct ieee80211_channel *);
+static void ar5211SetRateTable(struct ath_hal *,
+ RD_EDGES_POWER *pRdEdgesPower, TRGT_POWER_INFO *pPowerInfo,
+ uint16_t numChannels, const struct ieee80211_channel *chan);
+static uint16_t ar5211GetScaledPower(uint16_t channel, uint16_t pcdacValue,
+ const PCDACS_EEPROM *pSrcStruct);
+static HAL_BOOL ar5211FindValueInList(uint16_t channel, uint16_t pcdacValue,
+ const PCDACS_EEPROM *pSrcStruct, uint16_t *powerValue);
+static uint16_t ar5211GetInterpolatedValue(uint16_t target,
+ uint16_t srcLeft, uint16_t srcRight,
+ uint16_t targetLeft, uint16_t targetRight, HAL_BOOL scaleUp);
+static void ar5211GetLowerUpperValues(uint16_t value,
+ const uint16_t *pList, uint16_t listSize,
+ uint16_t *pLowerValue, uint16_t *pUpperValue);
+static void ar5211GetLowerUpperPcdacs(uint16_t pcdac,
+ uint16_t channel, const PCDACS_EEPROM *pSrcStruct,
+ uint16_t *pLowerPcdac, uint16_t *pUpperPcdac);
+
+static void ar5211SetRfgain(struct ath_hal *, const GAIN_VALUES *);
+static void ar5211RequestRfgain(struct ath_hal *);
+static HAL_BOOL ar5211InvalidGainReadback(struct ath_hal *, GAIN_VALUES *);
+static HAL_BOOL ar5211IsGainAdjustNeeded(struct ath_hal *, const GAIN_VALUES *);
+static int32_t ar5211AdjustGain(struct ath_hal *, GAIN_VALUES *);
+static void ar5211SetOperatingMode(struct ath_hal *, int opmode);
+
+/*
+ * 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
+ar5211Reset(struct ath_hal *ah, HAL_OPMODE opmode,
+ struct ieee80211_channel *chan, HAL_BOOL bChannelChange,
+ HAL_RESET_TYPE resetType,
+ HAL_STATUS *status)
+{
+uint32_t softLedCfg, softLedState;
+#define N(a) (sizeof (a) /sizeof (a[0]))
+#define FAIL(_code) do { ecode = _code; goto bad; } while (0)
+ struct ath_hal_5211 *ahp = AH5211(ah);
+ HAL_CHANNEL_INTERNAL *ichan;
+ uint32_t i, ledstate;
+ HAL_STATUS ecode;
+ int q;
+
+ uint32_t data, synthDelay;
+ uint32_t macStaId1;
+ uint16_t modesIndex = 0, freqIndex = 0;
+ uint32_t saveFrameSeqCount[AR_NUM_DCU];
+ uint32_t saveTsfLow = 0, saveTsfHigh = 0;
+ uint32_t saveDefAntenna;
+
+ HALDEBUG(ah, HAL_DEBUG_RESET,
+ "%s: opmode %u channel %u/0x%x %s channel\n",
+ __func__, opmode, chan->ic_freq, chan->ic_flags,
+ bChannelChange ? "change" : "same");
+
+ OS_MARK(ah, AH_MARK_RESET, bChannelChange);
+ /*
+ * Map public channel to private.
+ */
+ ichan = ath_hal_checkchannel(ah, chan);
+ if (ichan == AH_NULL)
+ 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(AH_PRIVATE(ah)->ah_eeversion >= AR_EEPROM_VER3);
+
+ /* Preserve certain DMA hardware registers on a channel change */
+ if (bChannelChange) {
+ /*
+ * Need to save/restore the TSF because of an issue
+ * that accelerates the TSF during a chip reset.
+ *
+ * We could use system timer routines to more
+ * accurately restore the TSF, but
+ * 1. Timer routines on certain platforms are
+ * not accurate enough (e.g. 1 ms resolution).
+ * 2. It would still not be accurate.
+ *
+ * The most important aspect of this workaround,
+ * is that, after reset, the TSF is behind
+ * other STAs TSFs. This will allow the STA to
+ * properly resynchronize its TSF in adhoc mode.
+ */
+ saveTsfLow = OS_REG_READ(ah, AR_TSF_L32);
+ saveTsfHigh = OS_REG_READ(ah, AR_TSF_U32);
+
+ /* Read frame sequence count */
+ if (AH_PRIVATE(ah)->ah_macVersion >= AR_SREV_VERSION_OAHU) {
+ saveFrameSeqCount[0] = OS_REG_READ(ah, AR_D0_SEQNUM);
+ } else {
+ for (i = 0; i < AR_NUM_DCU; i++)
+ saveFrameSeqCount[i] = OS_REG_READ(ah, AR_DSEQNUM(i));
+ }
+ if (!IEEE80211_IS_CHAN_DFS(chan))
+ chan->ic_state &= ~IEEE80211_CHANSTATE_CWINT;
+ }
+
+ /*
+ * Preserve the antenna on a channel change
+ */
+ saveDefAntenna = OS_REG_READ(ah, AR_DEF_ANTENNA);
+ if (saveDefAntenna == 0)
+ 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;
+
+ /* Save led state from pci config register */
+ ledstate = OS_REG_READ(ah, AR_PCICFG) &
+ (AR_PCICFG_LEDCTL | AR_PCICFG_LEDMODE | AR_PCICFG_LEDBLINK |
+ AR_PCICFG_LEDSLOW);
+ softLedCfg = OS_REG_READ(ah, AR_GPIOCR);
+ softLedState = OS_REG_READ(ah, AR_GPIODO);
+
+ if (!ar5211ChipReset(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_5GHZ(chan)) {
+ freqIndex = 1;
+ if (IEEE80211_IS_CHAN_TURBO(chan))
+ modesIndex = 2;
+ else if (IEEE80211_IS_CHAN_A(chan))
+ modesIndex = 1;
+ else {
+ HALDEBUG(ah, HAL_DEBUG_ANY,
+ "%s: invalid channel %u/0x%x\n",
+ __func__, chan->ic_freq, chan->ic_flags);
+ FAIL(HAL_EINVAL);
+ }
+ } else {
+ freqIndex = 2;
+ if (IEEE80211_IS_CHAN_B(chan))
+ modesIndex = 3;
+ else if (IEEE80211_IS_CHAN_PUREG(chan))
+ modesIndex = 4;
+ else {
+ HALDEBUG(ah, HAL_DEBUG_ANY,
+ "%s: invalid channel %u/0x%x\n",
+ __func__, chan->ic_freq, chan->ic_flags);
+ FAIL(HAL_EINVAL);
+ }
+ }
+
+ /* Set correct Baseband to analog shift setting to access analog chips. */
+ if (AH_PRIVATE(ah)->ah_macVersion >= AR_SREV_VERSION_OAHU) {
+ OS_REG_WRITE(ah, AR_PHY_BASE, 0x00000007);
+ } else {
+ OS_REG_WRITE(ah, AR_PHY_BASE, 0x00000047);
+ }
+
+ /* Write parameters specific to AR5211 */
+ if (AH_PRIVATE(ah)->ah_macVersion >= AR_SREV_VERSION_OAHU) {
+ if (IEEE80211_IS_CHAN_2GHZ(chan) &&
+ AH_PRIVATE(ah)->ah_eeversion >= AR_EEPROM_VER3_1) {
+ HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;
+ uint32_t ob2GHz, db2GHz;
+
+ if (IEEE80211_IS_CHAN_CCK(chan)) {
+ ob2GHz = ee->ee_ob2GHz[0];
+ db2GHz = ee->ee_db2GHz[0];
+ } else {
+ ob2GHz = ee->ee_ob2GHz[1];
+ db2GHz = ee->ee_db2GHz[1];
+ }
+ ob2GHz = ath_hal_reverseBits(ob2GHz, 3);
+ db2GHz = ath_hal_reverseBits(db2GHz, 3);
+ ar5211Mode2_4[25][freqIndex] =
+ (ar5211Mode2_4[25][freqIndex] & ~0xC0) |
+ ((ob2GHz << 6) & 0xC0);
+ ar5211Mode2_4[26][freqIndex] =
+ (ar5211Mode2_4[26][freqIndex] & ~0x0F) |
+ (((ob2GHz >> 2) & 0x1) |
+ ((db2GHz << 1) & 0x0E));
+ }
+ for (i = 0; i < N(ar5211Mode2_4); i++)
+ OS_REG_WRITE(ah, ar5211Mode2_4[i][0],
+ ar5211Mode2_4[i][freqIndex]);
+ }
+
+ /* Write the analog registers 6 and 7 before other config */
+ ar5211SetRf6and7(ah, chan);
+
+ /* Write registers that vary across all modes */
+ for (i = 0; i < N(ar5211Modes); i++)
+ OS_REG_WRITE(ah, ar5211Modes[i][0], ar5211Modes[i][modesIndex]);
+
+ /* Write RFGain Parameters that differ between 2.4 and 5 GHz */
+ for (i = 0; i < N(ar5211BB_RfGain); i++)
+ OS_REG_WRITE(ah, ar5211BB_RfGain[i][0], ar5211BB_RfGain[i][freqIndex]);
+
+ /* Write Common Array Parameters */
+ for (i = 0; i < N(ar5211Common); i++) {
+ uint32_t reg = ar5211Common[i][0];
+ /* On channel change, don't reset the PCU registers */
+ if (!(bChannelChange && (0x8000 <= reg && reg < 0x9000)))
+ OS_REG_WRITE(ah, reg, ar5211Common[i][1]);
+ }
+
+ /* Fix pre-AR5211 register values, this includes AR5311s. */
+ if (AH_PRIVATE(ah)->ah_macVersion < AR_SREV_VERSION_OAHU) {
+ /*
+ * The TX and RX latency values have changed locations
+ * within the USEC register in AR5211. Since they're
+ * set via the .ini, for both AR5211 and AR5311, they
+ * are written properly here for AR5311.
+ */
+ data = OS_REG_READ(ah, AR_USEC);
+ /* Must be 0 for proper write in AR5311 */
+ HALASSERT((data & 0x00700000) == 0);
+ OS_REG_WRITE(ah, AR_USEC,
+ (data & (AR_USEC_M | AR_USEC_32_M | AR5311_USEC_TX_LAT_M)) |
+ ((29 << AR5311_USEC_RX_LAT_S) & AR5311_USEC_RX_LAT_M));
+ /* The following registers exist only on AR5311. */
+ OS_REG_WRITE(ah, AR5311_QDCLKGATE, 0);
+
+ /* Set proper ADC & DAC delays for AR5311. */
+ OS_REG_WRITE(ah, 0x00009878, 0x00000008);
+
+ /* Enable the PCU FIFO corruption ECO on AR5311. */
+ OS_REG_WRITE(ah, AR_DIAG_SW,
+ OS_REG_READ(ah, AR_DIAG_SW) | AR5311_DIAG_SW_USE_ECO);
+ }
+
+ /* Restore certain DMA hardware registers on a channel change */
+ if (bChannelChange) {
+ /* Restore TSF */
+ OS_REG_WRITE(ah, AR_TSF_L32, saveTsfLow);
+ OS_REG_WRITE(ah, AR_TSF_U32, saveTsfHigh);
+
+ if (AH_PRIVATE(ah)->ah_macVersion >= AR_SREV_VERSION_OAHU) {
+ OS_REG_WRITE(ah, AR_D0_SEQNUM, saveFrameSeqCount[0]);
+ } else {
+ for (i = 0; i < AR_NUM_DCU; i++)
+ OS_REG_WRITE(ah, AR_DSEQNUM(i), saveFrameSeqCount[i]);
+ }
+ }
+
+ 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
+ );
+ ar5211SetOperatingMode(ah, opmode);
+
+ /* Restore previous led state */
+ OS_REG_WRITE(ah, AR_PCICFG, OS_REG_READ(ah, AR_PCICFG) | ledstate);
+ OS_REG_WRITE(ah, AR_GPIOCR, softLedCfg);
+ OS_REG_WRITE(ah, AR_GPIODO, softLedState);
+
+ /* Restore previous antenna */
+ OS_REG_WRITE(ah, AR_DEF_ANTENNA, saveDefAntenna);
+
+ 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 */
+
+ /*
+ * for pre-Production Oahu only.
+ * Disable clock gating in all DMA blocks. Helps when using
+ * 11B and AES but results in higher power consumption.
+ */
+ if (AH_PRIVATE(ah)->ah_macVersion == AR_SREV_VERSION_OAHU &&
+ AH_PRIVATE(ah)->ah_macRev < AR_SREV_OAHU_PROD) {
+ OS_REG_WRITE(ah, AR_CFG,
+ OS_REG_READ(ah, AR_CFG) | AR_CFG_CLK_GATE_DIS);
+ }
+
+ /* Setup the transmit power values. */
+ if (!ar5211SetTransmitPower(ah, chan)) {
+ HALDEBUG(ah, HAL_DEBUG_ANY,
+ "%s: error init'ing transmit power\n", __func__);
+ FAIL(HAL_EIO);
+ }
+
+ /*
+ * Configurable OFDM spoofing for 11n compatibility; used
+ * only when operating in station mode.
+ */
+ if (opmode != HAL_M_HOSTAP &&
+ (AH_PRIVATE(ah)->ah_11nCompat & HAL_DIAG_11N_SERVICES) != 0) {
+ /* NB: override the .ini setting */
+ OS_REG_RMW_FIELD(ah, AR_PHY_FRAME_CTL,
+ AR_PHY_FRAME_CTL_ERR_SERV,
+ MS(AH_PRIVATE(ah)->ah_11nCompat, HAL_DIAG_11N_SERVICES)&1);
+ }
+
+ /* Setup board specific options for EEPROM version 3 */
+ ar5211SetBoardValues(ah, chan);
+
+ if (!ar5211SetChannel(ah, chan)) {
+ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unable to set channel\n",
+ __func__);
+ FAIL(HAL_EIO);
+ }
+
+ /* Activate the PHY */
+ if (AH_PRIVATE(ah)->ah_devid == AR5211_FPGA11B &&
+ IEEE80211_IS_CHAN_2GHZ(chan))
+ OS_REG_WRITE(ah, 0xd808, 0x502); /* required for FPGA */
+ OS_REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
+
+ /*
+ * 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.
+ */
+ data = OS_REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_M;
+ if (IEEE80211_IS_CHAN_CCK(chan)) {
+ synthDelay = (4 * data) / 22;
+ } else {
+ synthDelay = data / 10;
+ }
+ /*
+ * There is an issue if the AP starts the calibration before
+ * the baseband timeout completes. This could result in the
+ * rxclear false triggering. Add an extra delay to ensure this
+ * this does not happen.
+ */
+ OS_DELAY(synthDelay + DELAY_BASE_ACTIVATE);
+
+ /* Calibrate the AGC and wait for completion. */
+ OS_REG_WRITE(ah, AR_PHY_AGC_CONTROL,
+ OS_REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_CAL);
+ (void) ath_hal_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0);
+
+ /* Perform noise floor and set status */
+ if (!ar5211CalNoiseFloor(ah, chan)) {
+ if (!IEEE80211_IS_CHAN_CCK(chan))
+ chan->ic_state |= IEEE80211_CHANSTATE_CWINT;
+ HALDEBUG(ah, HAL_DEBUG_ANY,
+ "%s: noise floor calibration failed\n", __func__);
+ FAIL(HAL_EIO);
+ }
+
+ /* Start IQ calibration w/ 2^(INIT_IQCAL_LOG_COUNT_MAX+1) samples */
+ if (ahp->ah_calibrationTime != 0) {
+ OS_REG_WRITE(ah, AR_PHY_TIMING_CTRL4,
+ AR_PHY_TIMING_CTRL4_DO_IQCAL | (INIT_IQCAL_LOG_COUNT_MAX << AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX_S));
+ ahp->ah_bIQCalibration = AH_TRUE;
+ }
+
+ /* set 1:1 QCU to DCU mapping for all queues */
+ for (q = 0; q < AR_NUM_DCU; q++)
+ OS_REG_WRITE(ah, AR_DQCUMASK(q), 1<<q);
+
+ for (q = 0; q < HAL_NUM_TX_QUEUES; q++)
+ ar5211ResetTxQueue(ah, q);
+
+ /* Setup QCU0 transmit interrupt masks (TX_ERR, TX_OK, TX_DESC, TX_URN) */
+ OS_REG_WRITE(ah, AR_IMR_S0,
+ (AR_IMR_S0_QCU_TXOK & AR_QCU_0) |
+ (AR_IMR_S0_QCU_TXDESC & (AR_QCU_0<<AR_IMR_S0_QCU_TXDESC_S)));
+ OS_REG_WRITE(ah, AR_IMR_S1, (AR_IMR_S1_QCU_TXERR & AR_QCU_0));
+ OS_REG_WRITE(ah, AR_IMR_S2, (AR_IMR_S2_QCU_TXURN & AR_QCU_0));
+
+ /*
+ * GBL_EIFS must always be written after writing
+ * to any QCUMASK register.
+ */
+ OS_REG_WRITE(ah, AR_D_GBL_IFS_EIFS, OS_REG_READ(ah, AR_D_GBL_IFS_EIFS));
+
+ /* Now set up the Interrupt Mask Register and save it for future use */
+ OS_REG_WRITE(ah, AR_IMR, INIT_INTERRUPT_MASK);
+ ahp->ah_maskReg = INIT_INTERRUPT_MASK;
+
+ /* Enable bus error interrupts */
+ 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);
+
+ /* Enable interrupts specific to AP */
+ if (opmode == HAL_M_HOSTAP) {
+ OS_REG_WRITE(ah, AR_IMR, OS_REG_READ(ah, AR_IMR) | AR_IMR_MIB);
+ ahp->ah_maskReg |= AR_IMR_MIB;
+ }
+
+ if (AH_PRIVATE(ah)->ah_rfkillEnabled)
+ ar5211EnableRfKill(ah);
+
+ /*
+ * 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)));
+
+ /* Restore user-specified slot time and timeouts */
+ if (ahp->ah_sifstime != (u_int) -1)
+ ar5211SetSifsTime(ah, ahp->ah_sifstime);
+ if (ahp->ah_slottime != (u_int) -1)
+ ar5211SetSlotTime(ah, ahp->ah_slottime);
+ if (ahp->ah_acktimeout != (u_int) -1)
+ ar5211SetAckTimeout(ah, ahp->ah_acktimeout);
+ if (ahp->ah_ctstimeout != (u_int) -1)
+ ar5211SetCTSTimeout(ah, ahp->ah_ctstimeout);
+ 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 */
+
+ HALDEBUG(ah, HAL_DEBUG_RESET, "%s: done\n", __func__);
+
+ return AH_TRUE;
+bad:
+ if (status != AH_NULL)
+ *status = ecode;
+ return AH_FALSE;
+#undef FAIL
+#undef N
+}
+
+/*
+ * Places the PHY and Radio chips into reset. A full reset
+ * must be called to leave this state. The PCI/MAC/PCU are
+ * not placed into reset as we must receive interrupt to
+ * re-enable the hardware.
+ */
+HAL_BOOL
+ar5211PhyDisable(struct ath_hal *ah)
+{
+ return ar5211SetResetReg(ah, AR_RC_BB);
+}
+
+/*
+ * Places all of hardware into reset
+ */
+HAL_BOOL
+ar5211Disable(struct ath_hal *ah)
+{
+ if (!ar5211SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE))
+ return AH_FALSE;
+ /*
+ * Reset the HW - PCI must be reset after the rest of the
+ * device has been reset.
+ */
+ if (!ar5211SetResetReg(ah, AR_RC_MAC | AR_RC_BB | AR_RC_PCI))
+ return AH_FALSE;
+ OS_DELAY(2100); /* 8245 @ 96Mhz hangs with 2000us. */
+
+ return AH_TRUE;
+}
+
+/*
+ * Places the hardware into reset and then pulls it out of reset
+ *
+ * Only write the PLL if we're changing to or from CCK mode
+ *
+ * Attach calls with channelFlags = 0, as the coldreset should have
+ * us in the correct mode and we cannot check the hwchannel flags.
+ */
+HAL_BOOL
+ar5211ChipReset(struct ath_hal *ah, const struct ieee80211_channel *chan)
+{
+ if (!ar5211SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE))
+ return AH_FALSE;
+
+ /* NB: called from attach with chan null */
+ if (chan != AH_NULL) {
+ /* Set CCK and Turbo modes correctly */
+ OS_REG_WRITE(ah, AR_PHY_TURBO, IEEE80211_IS_CHAN_TURBO(chan) ?
+ AR_PHY_FC_TURBO_MODE | AR_PHY_FC_TURBO_SHORT : 0);
+ if (IEEE80211_IS_CHAN_B(chan)) {
+ OS_REG_WRITE(ah, AR5211_PHY_MODE,
+ AR5211_PHY_MODE_CCK | AR5211_PHY_MODE_RF2GHZ);
+ OS_REG_WRITE(ah, AR_PHY_PLL_CTL, AR_PHY_PLL_CTL_44);
+ /* Wait for the PLL to settle */
+ OS_DELAY(DELAY_PLL_SETTLE);
+ } else if (AH_PRIVATE(ah)->ah_devid == AR5211_DEVID) {
+ OS_REG_WRITE(ah, AR_PHY_PLL_CTL, AR_PHY_PLL_CTL_40);
+ OS_DELAY(DELAY_PLL_SETTLE);
+ OS_REG_WRITE(ah, AR5211_PHY_MODE,
+ AR5211_PHY_MODE_OFDM | (IEEE80211_IS_CHAN_2GHZ(chan) ?
+ AR5211_PHY_MODE_RF2GHZ :
+ AR5211_PHY_MODE_RF5GHZ));
+ }
+ }
+
+ /*
+ * Reset the HW - PCI must be reset after the rest of the
+ * device has been reset
+ */
+ if (!ar5211SetResetReg(ah, AR_RC_MAC | AR_RC_BB | AR_RC_PCI))
+ return AH_FALSE;
+ OS_DELAY(2100); /* 8245 @ 96Mhz hangs with 2000us. */
+
+ /* Bring out of sleep mode (AGAIN) */
+ if (!ar5211SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE))
+ return AH_FALSE;
+
+ /* Clear warm reset register */
+ return ar5211SetResetReg(ah, 0);
+}
+
+/*
+ * Recalibrate the lower PHY chips to account for temperature/environment
+ * changes.
+ */
+HAL_BOOL
+ar5211PerCalibrationN(struct ath_hal *ah, struct ieee80211_channel *chan,
+ u_int chainMask, HAL_BOOL longCal, HAL_BOOL *isCalDone)
+{
+ struct ath_hal_5211 *ahp = AH5211(ah);
+ HAL_CHANNEL_INTERNAL *ichan;
+ int32_t qCoff, qCoffDenom;
+ uint32_t data;
+ int32_t iqCorrMeas;
+ int32_t iCoff, iCoffDenom;
+ uint32_t powerMeasQ, powerMeasI;
+
+ 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;
+ }
+ /* IQ calibration in progress. Check to see if it has finished. */
+ if (ahp->ah_bIQCalibration &&
+ !(OS_REG_READ(ah, AR_PHY_TIMING_CTRL4) & AR_PHY_TIMING_CTRL4_DO_IQCAL)) {
+ /* IQ Calibration has finished. */
+ ahp->ah_bIQCalibration = AH_FALSE;
+
+ /* Read calibration results. */
+ powerMeasI = OS_REG_READ(ah, AR_PHY_IQCAL_RES_PWR_MEAS_I);
+ powerMeasQ = OS_REG_READ(ah, AR_PHY_IQCAL_RES_PWR_MEAS_Q);
+ iqCorrMeas = OS_REG_READ(ah, AR_PHY_IQCAL_RES_IQ_CORR_MEAS);
+
+ /*
+ * Prescale these values to remove 64-bit operation requirement at the loss
+ * of a little precision.
+ */
+ iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 128;
+ qCoffDenom = powerMeasQ / 64;
+
+ /* Protect against divide-by-0. */
+ if (iCoffDenom != 0 && qCoffDenom != 0) {
+ iCoff = (-iqCorrMeas) / iCoffDenom;
+ /* IQCORR_Q_I_COFF is a signed 6 bit number */
+ iCoff = iCoff & 0x3f;
+
+ qCoff = ((int32_t)powerMeasI / qCoffDenom) - 64;
+ /* IQCORR_Q_Q_COFF is a signed 5 bit number */
+ qCoff = qCoff & 0x1f;
+
+ HALDEBUG(ah, HAL_DEBUG_PERCAL, "powerMeasI = 0x%08x\n",
+ powerMeasI);
+ HALDEBUG(ah, HAL_DEBUG_PERCAL, "powerMeasQ = 0x%08x\n",
+ powerMeasQ);
+ HALDEBUG(ah, HAL_DEBUG_PERCAL, "iqCorrMeas = 0x%08x\n",
+ iqCorrMeas);
+ HALDEBUG(ah, HAL_DEBUG_PERCAL, "iCoff = %d\n",
+ iCoff);
+ HALDEBUG(ah, HAL_DEBUG_PERCAL, "qCoff = %d\n",
+ qCoff);
+
+ /* Write IQ */
+ data = OS_REG_READ(ah, AR_PHY_TIMING_CTRL4) |
+ AR_PHY_TIMING_CTRL4_IQCORR_ENABLE |
+ (((uint32_t)iCoff) << AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF_S) |
+ ((uint32_t)qCoff);
+ OS_REG_WRITE(ah, AR_PHY_TIMING_CTRL4, data);
+ }
+ }
+ *isCalDone = !ahp->ah_bIQCalibration;
+
+ if (longCal) {
+ /* Perform noise floor and set status */
+ if (!ar5211IsNfGood(ah, chan)) {
+ /* report up and clear internal state */
+ chan->ic_state |= IEEE80211_CHANSTATE_CWINT;
+ return AH_FALSE;
+ }
+ if (!ar5211CalNoiseFloor(ah, chan)) {
+ /*
+ * Delay 5ms before retrying the noise floor
+ * just to make sure, as we are in an error
+ * condition here.
+ */
+ OS_DELAY(5000);
+ if (!ar5211CalNoiseFloor(ah, chan)) {
+ if (!IEEE80211_IS_CHAN_CCK(chan))
+ chan->ic_state |= IEEE80211_CHANSTATE_CWINT;
+ return AH_FALSE;
+ }
+ }
+ ar5211RequestRfgain(ah);
+ }
+ return AH_TRUE;
+}
+
+HAL_BOOL
+ar5211PerCalibration(struct ath_hal *ah, struct ieee80211_channel *chan,
+ HAL_BOOL *isIQdone)
+{
+ return ar5211PerCalibrationN(ah, chan, 0x1, AH_TRUE, isIQdone);
+}
+
+HAL_BOOL
+ar5211ResetCalValid(struct ath_hal *ah, const struct ieee80211_channel *chan)
+{
+ /* XXX */
+ return AH_TRUE;
+}
+
+/*
+ * Writes the given reset bit mask into the reset register
+ */
+static HAL_BOOL
+ar5211SetResetReg(struct ath_hal *ah, uint32_t resetMask)
+{
+ uint32_t mask = resetMask ? resetMask : ~0;
+ HAL_BOOL rt;
+
+ (void) OS_REG_READ(ah, AR_RXDP);/* flush any pending MMR writes */
+ OS_REG_WRITE(ah, AR_RC, resetMask);
+
+ /* need to wait at least 128 clocks when reseting PCI before read */
+ OS_DELAY(15);
+
+ resetMask &= AR_RC_MAC | AR_RC_BB;
+ mask &= AR_RC_MAC | AR_RC_BB;
+ rt = ath_hal_wait(ah, AR_RC, mask, resetMask);
+ if ((resetMask & AR_RC_MAC) == 0) {
+ if (isBigEndian()) {
+ /*
+ * Set CFG, little-endian for descriptor accesses.
+ */
+ mask = INIT_CONFIG_STATUS | AR_CFG_SWTD | AR_CFG_SWRD;
+ OS_REG_WRITE(ah, AR_CFG, mask);
+ } else
+ OS_REG_WRITE(ah, AR_CFG, INIT_CONFIG_STATUS);
+ }
+ return rt;
+}
+
+/*
+ * Takes the MHz channel value and sets the Channel value
+ *
+ * ASSUMES: Writes enabled to analog bus before AGC is active
+ * or by disabling the AGC.
+ */
+static HAL_BOOL
+ar5211SetChannel(struct ath_hal *ah, const struct ieee80211_channel *chan)
+{
+ uint32_t refClk, reg32, data2111;
+ int16_t chan5111, chanIEEE;
+
+ chanIEEE = chan->ic_ieee;
+ if (IEEE80211_IS_CHAN_2GHZ(chan)) {
+ const CHAN_INFO_2GHZ* ci =
+ &chan2GHzData[chanIEEE + CI_2GHZ_INDEX_CORRECTION];
+
+ data2111 = ((ath_hal_reverseBits(ci->channelSelect, 8) & 0xff)
+ << 5)
+ | (ci->refClkSel << 4);
+ chan5111 = ci->channel5111;
+ } else {
+ data2111 = 0;
+ chan5111 = chanIEEE;
+ }
+
+ /* 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;
+}
+
+static int16_t
+ar5211GetNoiseFloor(struct ath_hal *ah)
+{
+ int16_t nf;
+
+ nf = (OS_REG_READ(ah, AR_PHY(25)) >> 19) & 0x1ff;
+ if (nf & 0x100)
+ nf = 0 - ((nf ^ 0x1ff) + 1);
+ return nf;
+}
+
+/*
+ * Peform the noisefloor calibration for the length of time set
+ * in runTime (valid values 1 to 7)
+ *
+ * Returns: The NF value at the end of the given time (or 0 for failure)
+ */
+int16_t
+ar5211RunNoiseFloor(struct ath_hal *ah, uint8_t runTime, int16_t startingNF)
+{
+ int i, searchTime;
+
+ HALASSERT(runTime <= 7);
+
+ /* Setup noise floor run time and starting value */
+ OS_REG_WRITE(ah, AR_PHY(25),
+ (OS_REG_READ(ah, AR_PHY(25)) & ~0xFFF) |
+ ((runTime << 9) & 0xE00) | (startingNF & 0x1FF));
+ /* Calibrate the noise floor */
+ OS_REG_WRITE(ah, AR_PHY_AGC_CONTROL,
+ OS_REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_NF);
+
+ /* Compute the required amount of searchTime needed to finish NF */
+ if (runTime == 0) {
+ /* 8 search windows * 6.4us each */
+ searchTime = 8 * 7;
+ } else {
+ /* 512 * runtime search windows * 6.4us each */
+ searchTime = (runTime * 512) * 7;
+ }
+
+ /*
+ * Do not read noise floor until it has been updated
+ *
+ * As a guesstimate - we may only get 1/60th the time on
+ * the air to see search windows in a heavily congested
+ * network (40 us every 2400 us of time)
+ */
+ for (i = 0; i < 60; i++) {
+ if ((OS_REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) == 0)
+ break;
+ OS_DELAY(searchTime);
+ }
+ if (i >= 60) {
+ HALDEBUG(ah, HAL_DEBUG_NFCAL,
+ "NF with runTime %d failed to end on channel %d\n",
+ runTime, AH_PRIVATE(ah)->ah_curchan->ic_freq);
+ HALDEBUG(ah, HAL_DEBUG_NFCAL,
+ " PHY NF Reg state: 0x%x\n",
+ OS_REG_READ(ah, AR_PHY_AGC_CONTROL));
+ HALDEBUG(ah, HAL_DEBUG_NFCAL,
+ " PHY Active Reg state: 0x%x\n",
+ OS_REG_READ(ah, AR_PHY_ACTIVE));
+ return 0;
+ }
+
+ return ar5211GetNoiseFloor(ah);
+}
+
+static HAL_BOOL
+getNoiseFloorThresh(struct ath_hal *ah, const struct ieee80211_channel *chan,
+ int16_t *nft)
+{
+ HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;
+
+ switch (chan->ic_flags & IEEE80211_CHAN_ALLFULL) {
+ case IEEE80211_CHAN_A:
+ *nft = ee->ee_noiseFloorThresh[0];
+ break;
+ case IEEE80211_CHAN_B:
+ *nft = ee->ee_noiseFloorThresh[1];
+ break;
+ case IEEE80211_CHAN_PUREG:
+ *nft = ee->ee_noiseFloorThresh[2];
+ break;
+ default:
+ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel flags 0x%x\n",
+ __func__, chan->ic_flags);
+ return AH_FALSE;
+ }
+ return AH_TRUE;
+}
+
+/*
+ * Read the NF and check it against the noise floor threshold
+ *
+ * Returns: TRUE if the NF is good
+ */
+static HAL_BOOL
+ar5211IsNfGood(struct ath_hal *ah, struct ieee80211_channel *chan)
+{
+ HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan);
+ int16_t nf, nfThresh;
+
+ if (!getNoiseFloorThresh(ah, chan, &nfThresh))
+ return AH_FALSE;
+ if (OS_REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) {
+ HALDEBUG(ah, HAL_DEBUG_ANY,
+ "%s: NF did not complete in calibration window\n", __func__);
+ }
+ nf = ar5211GetNoiseFloor(ah);
+ if (nf > nfThresh) {
+ HALDEBUG(ah, HAL_DEBUG_ANY,
+ "%s: noise floor failed; detected %u, threshold %u\n",
+ __func__, nf, nfThresh);
+ /*
+ * NB: Don't discriminate 2.4 vs 5Ghz, if this
+ * happens it indicates a problem regardless
+ * of the band.
+ */
+ chan->ic_state |= IEEE80211_CHANSTATE_CWINT;
+ }
+ ichan->rawNoiseFloor = nf;
+ return (nf <= nfThresh);
+}
+
+/*
+ * Peform the noisefloor calibration and check for any constant channel
+ * interference.
+ *
+ * NOTE: preAR5211 have a lengthy carrier wave detection process - hence
+ * it is if'ed for MKK regulatory domain only.
+ *
+ * Returns: TRUE for a successful noise floor calibration; else FALSE
+ */
+HAL_BOOL
+ar5211CalNoiseFloor(struct ath_hal *ah, const struct ieee80211_channel *chan)
+{
+#define N(a) (sizeof (a) / sizeof (a[0]))
+ /* Check for Carrier Wave interference in MKK regulatory zone */
+ if (AH_PRIVATE(ah)->ah_macVersion < AR_SREV_VERSION_OAHU &&
+ (chan->ic_flags & CHANNEL_NFCREQUIRED)) {
+ static const uint8_t runtime[3] = { 0, 2, 7 };
+ HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan);
+ int16_t nf, nfThresh;
+ int i;
+
+ if (!getNoiseFloorThresh(ah, chan, &nfThresh))
+ return AH_FALSE;
+ /*
+ * Run a quick noise floor that will hopefully
+ * complete (decrease delay time).
+ */
+ for (i = 0; i < N(runtime); i++) {
+ nf = ar5211RunNoiseFloor(ah, runtime[i], 0);
+ if (nf > nfThresh) {
+ HALDEBUG(ah, HAL_DEBUG_ANY,
+ "%s: run failed with %u > threshold %u "
+ "(runtime %u)\n", __func__,
+ nf, nfThresh, runtime[i]);
+ ichan->rawNoiseFloor = 0;
+ } else
+ ichan->rawNoiseFloor = nf;
+ }
+ return (i <= N(runtime));
+ } else {
+ /* Calibrate the noise floor */
+ OS_REG_WRITE(ah, AR_PHY_AGC_CONTROL,
+ OS_REG_READ(ah, AR_PHY_AGC_CONTROL) |
+ AR_PHY_AGC_CONTROL_NF);
+ }
+ return AH_TRUE;
+#undef N
+}
+
+/*
+ * Adjust NF based on statistical values for 5GHz frequencies.
+ */
+int16_t
+ar5211GetNfAdjust(struct ath_hal *ah, const HAL_CHANNEL_INTERNAL *c)
+{
+ static const struct {
+ uint16_t freqLow;
+ int16_t adjust;
+ } adjust5111[] = {
+ { 5790, 11 }, /* NB: ordered high -> low */
+ { 5730, 10 },
+ { 5690, 9 },
+ { 5660, 8 },
+ { 5610, 7 },
+ { 5530, 5 },
+ { 5450, 4 },
+ { 5379, 2 },
+ { 5209, 0 }, /* XXX? bogus but doesn't matter */
+ { 0, 1 },
+ };
+ int i;
+
+ for (i = 0; c->channel <= adjust5111[i].freqLow; i++)
+ ;
+ /* NB: placeholder for 5111's less severe requirement */
+ return adjust5111[i].adjust / 3;
+}
+
+/*
+ * Reads EEPROM header info from device structure and programs
+ * analog registers 6 and 7
+ *
+ * REQUIRES: Access to the analog device
+ */
+static HAL_BOOL
+ar5211SetRf6and7(struct ath_hal *ah, const struct ieee80211_channel *chan)
+{
+#define N(a) (sizeof (a) / sizeof (a[0]))
+ uint16_t freq = ath_hal_gethwchannel(ah, chan);
+ HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;
+ struct ath_hal_5211 *ahp = AH5211(ah);
+ uint16_t rfXpdGain, rfPloSel, rfPwdXpd;
+ uint16_t tempOB, tempDB;
+ uint16_t freqIndex;
+ int i;
+
+ freqIndex = IEEE80211_IS_CHAN_2GHZ(chan) ? 2 : 1;
+
+ /*
+ * TODO: This array mode correspondes with the index used
+ * during the read.
+ * For readability, this should be changed to an enum or #define
+ */
+ switch (chan->ic_flags & IEEE80211_CHAN_ALLFULL) {
+ case IEEE80211_CHAN_A:
+ if (freq > 4000 && freq < 5260) {
+ tempOB = ee->ee_ob1;
+ tempDB = ee->ee_db1;
+ } else if (freq >= 5260 && freq < 5500) {
+ tempOB = ee->ee_ob2;
+ tempDB = ee->ee_db2;
+ } else if (freq >= 5500 && freq < 5725) {
+ tempOB = ee->ee_ob3;
+ tempDB = ee->ee_db3;
+ } else if (freq >= 5725) {
+ tempOB = ee->ee_ob4;
+ tempDB = ee->ee_db4;
+ } else {
+ /* XXX panic?? */
+ tempOB = tempDB = 0;
+ }
+
+ rfXpdGain = ee->ee_xgain[0];
+ rfPloSel = ee->ee_xpd[0];
+ rfPwdXpd = !ee->ee_xpd[0];
+
+ ar5211Rf6n7[5][freqIndex] =
+ (ar5211Rf6n7[5][freqIndex] & ~0x10000000) |
+ (ee->ee_cornerCal.pd84<< 28);
+ ar5211Rf6n7[6][freqIndex] =
+ (ar5211Rf6n7[6][freqIndex] & ~0x04000000) |
+ (ee->ee_cornerCal.pd90 << 26);
+ ar5211Rf6n7[21][freqIndex] =
+ (ar5211Rf6n7[21][freqIndex] & ~0x08) |
+ (ee->ee_cornerCal.gSel << 3);
+ break;
+ case IEEE80211_CHAN_B:
+ tempOB = ee->ee_obFor24;
+ tempDB = ee->ee_dbFor24;
+ rfXpdGain = ee->ee_xgain[1];
+ rfPloSel = ee->ee_xpd[1];
+ rfPwdXpd = !ee->ee_xpd[1];
+ break;
+ case IEEE80211_CHAN_PUREG:
+ tempOB = ee->ee_obFor24g;
+ tempDB = ee->ee_dbFor24g;
+ rfXpdGain = ee->ee_xgain[2];
+ rfPloSel = ee->ee_xpd[2];
+ rfPwdXpd = !ee->ee_xpd[2];
+ 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);
+
+ /* Set rfXpdGain and rfPwdXpd */
+ ar5211Rf6n7[11][freqIndex] = (ar5211Rf6n7[11][freqIndex] & ~0xC0) |
+ (((ath_hal_reverseBits(rfXpdGain, 4) << 7) | (rfPwdXpd << 6)) & 0xC0);
+ ar5211Rf6n7[12][freqIndex] = (ar5211Rf6n7[12][freqIndex] & ~0x07) |
+ ((ath_hal_reverseBits(rfXpdGain, 4) >> 1) & 0x07);
+
+ /* Set OB */
+ ar5211Rf6n7[12][freqIndex] = (ar5211Rf6n7[12][freqIndex] & ~0x80) |
+ ((ath_hal_reverseBits(tempOB, 3) << 7) & 0x80);
+ ar5211Rf6n7[13][freqIndex] = (ar5211Rf6n7[13][freqIndex] & ~0x03) |
+ ((ath_hal_reverseBits(tempOB, 3) >> 1) & 0x03);
+
+ /* Set DB */
+ ar5211Rf6n7[13][freqIndex] = (ar5211Rf6n7[13][freqIndex] & ~0x1C) |
+ ((ath_hal_reverseBits(tempDB, 3) << 2) & 0x1C);
+
+ /* Set rfPloSel */
+ ar5211Rf6n7[17][freqIndex] = (ar5211Rf6n7[17][freqIndex] & ~0x08) |
+ ((rfPloSel << 3) & 0x08);
+
+ /* Write the Rf registers 6 & 7 */
+ for (i = 0; i < N(ar5211Rf6n7); i++)
+ OS_REG_WRITE(ah, ar5211Rf6n7[i][0], ar5211Rf6n7[i][freqIndex]);
+
+ /* Now that we have reprogrammed rfgain value, clear the flag. */
+ ahp->ah_rfgainState = RFGAIN_INACTIVE;
+
+ return AH_TRUE;
+#undef N
+}
+
+HAL_BOOL
+ar5211SetAntennaSwitchInternal(struct ath_hal *ah, HAL_ANT_SETTING settings,
+ const struct ieee80211_channel *chan)
+{
+#define ANT_SWITCH_TABLE1 0x9960
+#define ANT_SWITCH_TABLE2 0x9964
+ HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;
+ struct ath_hal_5211 *ahp = AH5211(ah);
+ uint32_t antSwitchA, antSwitchB;
+ int ix;
+
+ switch (chan->ic_flags & IEEE80211_CHAN_ALLFULL) {
+ case IEEE80211_CHAN_A: ix = 0; break;
+ case IEEE80211_CHAN_B: ix = 1; break;
+ case IEEE80211_CHAN_PUREG: ix = 2; break;
+ default:
+ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel flags 0x%x\n",
+ __func__, chan->ic_flags);
+ return AH_FALSE;
+ }
+
+ antSwitchA = ee->ee_antennaControl[1][ix]
+ | (ee->ee_antennaControl[2][ix] << 6)
+ | (ee->ee_antennaControl[3][ix] << 12)
+ | (ee->ee_antennaControl[4][ix] << 18)
+ | (ee->ee_antennaControl[5][ix] << 24)
+ ;
+ antSwitchB = ee->ee_antennaControl[6][ix]
+ | (ee->ee_antennaControl[7][ix] << 6)
+ | (ee->ee_antennaControl[8][ix] << 12)
+ | (ee->ee_antennaControl[9][ix] << 18)
+ | (ee->ee_antennaControl[10][ix] << 24)
+ ;
+ /*
+ * For fixed antenna, give the same setting for both switch banks
+ */
+ switch (settings) {
+ case HAL_ANT_FIXED_A:
+ antSwitchB = antSwitchA;
+ break;
+ case HAL_ANT_FIXED_B:
+ antSwitchA = antSwitchB;
+ break;
+ case HAL_ANT_VARIABLE:
+ break;
+ default:
+ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad antenna setting %u\n",
+ __func__, settings);
+ return AH_FALSE;
+ }
+ ahp->ah_diversityControl = settings;
+
+ OS_REG_WRITE(ah, ANT_SWITCH_TABLE1, antSwitchA);
+ OS_REG_WRITE(ah, ANT_SWITCH_TABLE2, antSwitchB);
+
+ return AH_TRUE;
+#undef ANT_SWITCH_TABLE1
+#undef ANT_SWITCH_TABLE2
+}
+
+/*
+ * Reads EEPROM header info and programs the device for correct operation
+ * given the channel value
+ */
+static HAL_BOOL
+ar5211SetBoardValues(struct ath_hal *ah, const struct ieee80211_channel *chan)
+{
+ HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;
+ struct ath_hal_5211 *ahp = AH5211(ah);
+ int arrayMode, falseDectectBackoff;
+
+ switch (chan->ic_flags & IEEE80211_CHAN_ALLFULL) {
+ case IEEE80211_CHAN_A:
+ arrayMode = 0;
+ OS_REG_RMW_FIELD(ah, AR_PHY_FRAME_CTL,
+ AR_PHY_FRAME_CTL_TX_CLIP, ee->ee_cornerCal.clip);
+ break;
+ case IEEE80211_CHAN_B:
+ arrayMode = 1;
+ break;
+ case IEEE80211_CHAN_PUREG:
+ arrayMode = 2;
+ break;
+ default:
+ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel flags 0x%x\n",
+ __func__, chan->ic_flags);
+ return AH_FALSE;
+ }
+
+ /* Set the antenna register(s) correctly for the chip revision */
+ if (AH_PRIVATE(ah)->ah_macVersion < AR_SREV_VERSION_OAHU) {
+ OS_REG_WRITE(ah, AR_PHY(68),
+ (OS_REG_READ(ah, AR_PHY(68)) & 0xFFFFFFFC) | 0x3);
+ } else {
+ OS_REG_WRITE(ah, AR_PHY(68),
+ (OS_REG_READ(ah, AR_PHY(68)) & 0xFFFFFC06) |
+ (ee->ee_antennaControl[0][arrayMode] << 4) | 0x1);
+
+ ar5211SetAntennaSwitchInternal(ah,
+ ahp->ah_diversityControl, chan);
+
+ /* Set the Noise Floor Thresh on ar5211 devices */
+ OS_REG_WRITE(ah, AR_PHY_BASE + (90 << 2),
+ (ee->ee_noiseFloorThresh[arrayMode] & 0x1FF) | (1<<9));
+ }
+ OS_REG_WRITE(ah, AR_PHY_BASE + (17 << 2),
+ (OS_REG_READ(ah, AR_PHY_BASE + (17 << 2)) & 0xFFFFC07F) |
+ ((ee->ee_switchSettling[arrayMode] << 7) & 0x3F80));
+ OS_REG_WRITE(ah, AR_PHY_BASE + (18 << 2),
+ (OS_REG_READ(ah, AR_PHY_BASE + (18 << 2)) & 0xFFFC0FFF) |
+ ((ee->ee_txrxAtten[arrayMode] << 12) & 0x3F000));
+ OS_REG_WRITE(ah, AR_PHY_BASE + (20 << 2),
+ (OS_REG_READ(ah, AR_PHY_BASE + (20 << 2)) & 0xFFFF0000) |
+ ((ee->ee_pgaDesiredSize[arrayMode] << 8) & 0xFF00) |
+ (ee->ee_adcDesiredSize[arrayMode] & 0x00FF));
+ OS_REG_WRITE(ah, AR_PHY_BASE + (13 << 2),
+ (ee->ee_txEndToXPAOff[arrayMode] << 24) |
+ (ee->ee_txEndToXPAOff[arrayMode] << 16) |
+ (ee->ee_txFrameToXPAOn[arrayMode] << 8) |
+ ee->ee_txFrameToXPAOn[arrayMode]);
+ OS_REG_WRITE(ah, AR_PHY_BASE + (10 << 2),
+ (OS_REG_READ(ah, AR_PHY_BASE + (10 << 2)) & 0xFFFF00FF) |
+ (ee->ee_txEndToXLNAOn[arrayMode] << 8));
+ OS_REG_WRITE(ah, AR_PHY_BASE + (25 << 2),
+ (OS_REG_READ(ah, AR_PHY_BASE + (25 << 2)) & 0xFFF80FFF) |
+ ((ee->ee_thresh62[arrayMode] << 12) & 0x7F000));
+
+#define NO_FALSE_DETECT_BACKOFF 2
+#define CB22_FALSE_DETECT_BACKOFF 6
+ /*
+ * False detect backoff - suspected 32 MHz spur causes
+ * false detects in OFDM, causing Tx Hangs. Decrease
+ * weak signal sensitivity for this card.
+ */
+ falseDectectBackoff = NO_FALSE_DETECT_BACKOFF;
+ if (AH_PRIVATE(ah)->ah_eeversion < AR_EEPROM_VER3_3) {
+ if (AH_PRIVATE(ah)->ah_subvendorid == 0x1022 &&
+ IEEE80211_IS_CHAN_OFDM(chan))
+ falseDectectBackoff += CB22_FALSE_DETECT_BACKOFF;
+ } else {
+ uint16_t freq = ath_hal_gethwchannel(ah, chan);
+ uint32_t remainder = freq % 32;
+
+ if (remainder && (remainder < 10 || remainder > 22))
+ falseDectectBackoff += ee->ee_falseDetectBackoff[arrayMode];
+ }
+ OS_REG_WRITE(ah, 0x9924,
+ (OS_REG_READ(ah, 0x9924) & 0xFFFFFF01)
+ | ((falseDectectBackoff << 1) & 0xF7));
+
+ return AH_TRUE;
+#undef NO_FALSE_DETECT_BACKOFF
+#undef CB22_FALSE_DETECT_BACKOFF
+}
+
+/*
+ * Set the limit on the overall output power. Used for dynamic
+ * transmit power control and the like.
+ *
+ * NOTE: The power is passed in is in units of 0.5 dBm.
+ */
+HAL_BOOL
+ar5211SetTxPowerLimit(struct ath_hal *ah, uint32_t limit)
+{
+
+ AH_PRIVATE(ah)->ah_powerLimit = AH_MIN(limit, MAX_RATE_POWER);
+ OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE_MAX, limit);
+ return AH_TRUE;
+}
+
+/*
+ * Sets the transmit power in the baseband for the given
+ * operating channel and mode.
+ */
+static HAL_BOOL
+ar5211SetTransmitPower(struct ath_hal *ah, const struct ieee80211_channel *chan)
+{
+ uint16_t freq = ath_hal_gethwchannel(ah, chan);
+ HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;
+ TRGT_POWER_INFO *pi;
+ RD_EDGES_POWER *rep;
+ PCDACS_EEPROM eepromPcdacs;
+ u_int nchan, cfgCtl;
+ int i;
+
+ /* setup the pcdac struct to point to the correct info, based on mode */
+ switch (chan->ic_flags & IEEE80211_CHAN_ALLFULL) {
+ case IEEE80211_CHAN_A:
+ eepromPcdacs.numChannels = ee->ee_numChannels11a;
+ eepromPcdacs.pChannelList= ee->ee_channels11a;
+ eepromPcdacs.pDataPerChannel = ee->ee_dataPerChannel11a;
+ nchan = ee->ee_numTargetPwr_11a;
+ pi = ee->ee_trgtPwr_11a;
+ break;
+ case IEEE80211_CHAN_PUREG:
+ eepromPcdacs.numChannels = ee->ee_numChannels2_4;
+ eepromPcdacs.pChannelList= ee->ee_channels11g;
+ eepromPcdacs.pDataPerChannel = ee->ee_dataPerChannel11g;
+ nchan = ee->ee_numTargetPwr_11g;
+ pi = ee->ee_trgtPwr_11g;
+ break;
+ case IEEE80211_CHAN_B:
+ eepromPcdacs.numChannels = ee->ee_numChannels2_4;
+ eepromPcdacs.pChannelList= ee->ee_channels11b;
+ eepromPcdacs.pDataPerChannel = ee->ee_dataPerChannel11b;
+ nchan = ee->ee_numTargetPwr_11b;
+ pi = ee->ee_trgtPwr_11b;
+ break;
+ default:
+ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel flags 0x%x\n",
+ __func__, chan->ic_flags);
+ return AH_FALSE;
+ }
+
+ ar5211SetPowerTable(ah, &eepromPcdacs, freq);
+
+ rep = AH_NULL;
+ /* Match CTL to EEPROM value */
+ cfgCtl = ath_hal_getctl(ah, chan);
+ for (i = 0; i < ee->ee_numCtls; i++)
+ if (ee->ee_ctl[i] != 0 && ee->ee_ctl[i] == cfgCtl) {
+ rep = &ee->ee_rdEdgesPower[i * NUM_EDGES];
+ break;
+ }
+ ar5211SetRateTable(ah, rep, pi, nchan, chan);
+
+ return AH_TRUE;
+}
+
+/*
+ * 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.
+ */
+void
+ar5211SetPowerTable(struct ath_hal *ah, PCDACS_EEPROM *pSrcStruct,
+ uint16_t channel)
+{
+ static FULL_PCDAC_STRUCT pcdacStruct;
+ static uint16_t pcdacTable[PWR_TABLE_SIZE];
+
+ uint16_t i, j;
+ uint16_t *pPcdacValues;
+ int16_t *pScaledUpDbm;
+ int16_t minScaledPwr;
+ int16_t maxScaledPwr;
+ int16_t pwr;
+ uint16_t pcdacMin = 0;
+ uint16_t pcdacMax = 63;
+ uint16_t pcdacTableIndex;
+ uint16_t scaledPcdac;
+ uint32_t addr;
+ uint32_t temp32;
+
+ OS_MEMZERO(&pcdacStruct, sizeof(FULL_PCDAC_STRUCT));
+ OS_MEMZERO(pcdacTable, sizeof(uint16_t) * PWR_TABLE_SIZE);
+ 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] = ar5211GetScaledPower(channel, 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++)
+ pcdacTable[pcdacTableIndex++] = pcdacMin;
+
+ i = 0;
+ while (pwr < pScaledUpDbm[pcdacStruct.numPcdacValues - 1]) {
+ 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)(ar5211GetInterpolatedValue(pwr,
+ pScaledUpDbm[i], pScaledUpDbm[i+1],
+ (uint16_t)(pPcdacValues[i] * 2),
+ (uint16_t)(pPcdacValues[i+1] * 2), 0) + 1);
+
+ pcdacTable[pcdacTableIndex] = scaledPcdac / 2;
+ if (pcdacTable[pcdacTableIndex] > pcdacMax)
+ pcdacTable[pcdacTableIndex] = pcdacMax;
+ pcdacTableIndex++;
+ }
+
+ /* Write all the last pcdac entries based off the last valid pcdac */
+ while (pcdacTableIndex < PWR_TABLE_SIZE) {
+ pcdacTable[pcdacTableIndex] = pcdacTable[pcdacTableIndex - 1];
+ pcdacTableIndex++;
+ }
+
+ /* Finally, write the power values into the baseband power table */
+ addr = AR_PHY_BASE + (608 << 2);
+ for (i = 0; i < 32; i++) {
+ temp32 = 0xffff & ((pcdacTable[2 * i + 1] << 8) | 0xff);
+ temp32 = (temp32 << 16) | (0xffff & ((pcdacTable[2 * i] << 8) | 0xff));
+ OS_REG_WRITE(ah, addr, temp32);
+ addr += 4;
+ }
+
+}
+
+/*
+ * Set the transmit power in the baseband for the given
+ * operating channel and mode.
+ */
+static void
+ar5211SetRateTable(struct ath_hal *ah, RD_EDGES_POWER *pRdEdgesPower,
+ TRGT_POWER_INFO *pPowerInfo, uint16_t numChannels,
+ const struct ieee80211_channel *chan)
+{
+ uint16_t freq = ath_hal_gethwchannel(ah, chan);
+ HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;
+ struct ath_hal_5211 *ahp = AH5211(ah);
+ static uint16_t ratesArray[NUM_RATES];
+ static const uint16_t tpcScaleReductionTable[5] =
+ { 0, 3, 6, 9, MAX_RATE_POWER };
+
+ uint16_t *pRatesPower;
+ uint16_t lowerChannel, lowerIndex=0, lowerPower=0;
+ uint16_t upperChannel, upperIndex=0, upperPower=0;
+ uint16_t twiceMaxEdgePower=63;
+ uint16_t twicePower = 0;
+ uint16_t i, numEdges;
+ uint16_t tempChannelList[NUM_EDGES]; /* temp array for holding edge channels */
+ uint16_t twiceMaxRDPower;
+ int16_t scaledPower = 0; /* for gcc -O2 */
+ uint16_t mask = 0x3f;
+ HAL_BOOL paPreDEnable = 0;
+ int8_t twiceAntennaGain, twiceAntennaReduction = 0;
+
+ pRatesPower = ratesArray;
+ twiceMaxRDPower = chan->ic_maxregpower * 2;
+
+ if (IEEE80211_IS_CHAN_5GHZ(chan)) {
+ twiceAntennaGain = ee->ee_antennaGainMax[0];
+ } else {
+ twiceAntennaGain = ee->ee_antennaGainMax[1];
+ }
+
+ twiceAntennaReduction = ath_hal_getantennareduction(ah, chan, twiceAntennaGain);
+
+ if (pRdEdgesPower) {
+ /* Get the edge power */
+ for (i = 0; i < NUM_EDGES; i++) {
+ if (pRdEdgesPower[i].rdEdge == 0)
+ break;
+ tempChannelList[i] = pRdEdgesPower[i].rdEdge;
+ }
+ numEdges = i;
+
+ ar5211GetLowerUpperValues(freq, tempChannelList,
+ numEdges, &lowerChannel, &upperChannel);
+ /* Get the index for this channel */
+ for (i = 0; i < numEdges; i++)
+ if (lowerChannel == tempChannelList[i])
+ break;
+ HALASSERT(i != numEdges);
+
+ if ((lowerChannel == upperChannel &&
+ lowerChannel == freq) ||
+ pRdEdgesPower[i].flag) {
+ twiceMaxEdgePower = pRdEdgesPower[i].twice_rdEdgePower;
+ HALASSERT(twiceMaxEdgePower > 0);
+ }
+ }
+
+ /* extrapolate the power values for the test Groups */
+ for (i = 0; i < numChannels; i++)
+ tempChannelList[i] = pPowerInfo[i].testChannel;
+
+ ar5211GetLowerUpperValues(freq, tempChannelList,
+ numChannels, &lowerChannel, &upperChannel);
+
+ /* get the index for the channel */
+ for (i = 0; i < numChannels; i++) {
+ if (lowerChannel == tempChannelList[i])
+ lowerIndex = i;
+ if (upperChannel == tempChannelList[i]) {
+ upperIndex = i;
+ break;
+ }
+ }
+
+ for (i = 0; i < NUM_RATES; i++) {
+ if (IEEE80211_IS_CHAN_OFDM(chan)) {
+ /* power for rates 6,9,12,18,24 is all the same */
+ if (i < 5) {
+ lowerPower = pPowerInfo[lowerIndex].twicePwr6_24;
+ upperPower = pPowerInfo[upperIndex].twicePwr6_24;
+ } else if (i == 5) {
+ lowerPower = pPowerInfo[lowerIndex].twicePwr36;
+ upperPower = pPowerInfo[upperIndex].twicePwr36;
+ } else if (i == 6) {
+ lowerPower = pPowerInfo[lowerIndex].twicePwr48;
+ upperPower = pPowerInfo[upperIndex].twicePwr48;
+ } else if (i == 7) {
+ lowerPower = pPowerInfo[lowerIndex].twicePwr54;
+ upperPower = pPowerInfo[upperIndex].twicePwr54;
+ }
+ } else {
+ switch (i) {
+ case 0:
+ case 1:
+ lowerPower = pPowerInfo[lowerIndex].twicePwr6_24;
+ upperPower = pPowerInfo[upperIndex].twicePwr6_24;
+ break;
+ case 2:
+ case 3:
+ lowerPower = pPowerInfo[lowerIndex].twicePwr36;
+ upperPower = pPowerInfo[upperIndex].twicePwr36;
+ break;
+ case 4:
+ case 5:
+ lowerPower = pPowerInfo[lowerIndex].twicePwr48;
+ upperPower = pPowerInfo[upperIndex].twicePwr48;
+ break;
+ case 6:
+ case 7:
+ lowerPower = pPowerInfo[lowerIndex].twicePwr54;
+ upperPower = pPowerInfo[upperIndex].twicePwr54;
+ break;
+ }
+ }
+
+ twicePower = ar5211GetInterpolatedValue(freq,
+ lowerChannel, upperChannel, lowerPower, upperPower, 0);
+
+ /* Reduce power by band edge restrictions */
+ twicePower = AH_MIN(twicePower, twiceMaxEdgePower);
+
+ /*
+ * If turbo is set, reduce power to keep power
+ * consumption under 2 Watts. Note that we always do
+ * this unless specially configured. Then we limit
+ * power only for non-AP operation.
+ */
+ if (IEEE80211_IS_CHAN_TURBO(chan) &&
+ AH_PRIVATE(ah)->ah_eeversion >= AR_EEPROM_VER3_1
+#ifdef AH_ENABLE_AP_SUPPORT
+ && AH_PRIVATE(ah)->ah_opmode != HAL_M_HOSTAP
+#endif
+ ) {
+ twicePower = AH_MIN(twicePower, ee->ee_turbo2WMaxPower5);
+ }
+
+ /* Reduce power by max regulatory domain allowed restrictions */
+ pRatesPower[i] = AH_MIN(twicePower, twiceMaxRDPower - twiceAntennaReduction);
+
+ /* Use 6 Mb power level for transmit power scaling reduction */
+ /* We don't want to reduce higher rates if its not needed */
+ if (i == 0) {
+ scaledPower = pRatesPower[0] -
+ (tpcScaleReductionTable[AH_PRIVATE(ah)->ah_tpScale] * 2);
+ if (scaledPower < 1)
+ scaledPower = 1;
+ }
+
+ pRatesPower[i] = AH_MIN(pRatesPower[i], scaledPower);
+ }
+
+ /* Record txPower at Rate 6 for info gathering */
+ ahp->ah_tx6PowerInHalfDbm = pRatesPower[0];
+
+#ifdef AH_DEBUG
+ HALDEBUG(ah, HAL_DEBUG_RESET,
+ "%s: final output power setting %d MHz:\n",
+ __func__, chan->ic_freq);
+ HALDEBUG(ah, HAL_DEBUG_RESET,
+ "6 Mb %d dBm, MaxRD: %d dBm, MaxEdge %d dBm\n",
+ scaledPower / 2, twiceMaxRDPower / 2, twiceMaxEdgePower / 2);
+ HALDEBUG(ah, HAL_DEBUG_RESET, "TPC Scale %d dBm - Ant Red %d dBm\n",
+ tpcScaleReductionTable[AH_PRIVATE(ah)->ah_tpScale] * 2,
+ twiceAntennaReduction / 2);
+ if (IEEE80211_IS_CHAN_TURBO(chan) &&
+ AH_PRIVATE(ah)->ah_eeversion >= AR_EEPROM_VER3_1)
+ HALDEBUG(ah, HAL_DEBUG_RESET, "Max Turbo %d dBm\n",
+ ee->ee_turbo2WMaxPower5);
+ HALDEBUG(ah, HAL_DEBUG_RESET,
+ " %2d | %2d | %2d | %2d | %2d | %2d | %2d | %2d dBm\n",
+ pRatesPower[0] / 2, pRatesPower[1] / 2, pRatesPower[2] / 2,
+ pRatesPower[3] / 2, pRatesPower[4] / 2, pRatesPower[5] / 2,
+ pRatesPower[6] / 2, pRatesPower[7] / 2);
+#endif /* AH_DEBUG */
+
+ /* Write the power table into the hardware */
+ OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE1,
+ ((paPreDEnable & 1)<< 30) | ((pRatesPower[3] & mask) << 24) |
+ ((paPreDEnable & 1)<< 22) | ((pRatesPower[2] & mask) << 16) |
+ ((paPreDEnable & 1)<< 14) | ((pRatesPower[1] & mask) << 8) |
+ ((paPreDEnable & 1)<< 6 ) | (pRatesPower[0] & mask));
+ OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE2,
+ ((paPreDEnable & 1)<< 30) | ((pRatesPower[7] & mask) << 24) |
+ ((paPreDEnable & 1)<< 22) | ((pRatesPower[6] & mask) << 16) |
+ ((paPreDEnable & 1)<< 14) | ((pRatesPower[5] & mask) << 8) |
+ ((paPreDEnable & 1)<< 6 ) | (pRatesPower[4] & mask));
+
+ /* set max power to the power value at rate 6 */
+ ar5211SetTxPowerLimit(ah, pRatesPower[0]);
+
+ AH_PRIVATE(ah)->ah_maxPowerLevel = pRatesPower[0];
+}
+
+/*
+ * Get or interpolate the pcdac value from the calibrated data
+ */
+uint16_t
+ar5211GetScaledPower(uint16_t channel, uint16_t pcdacValue,
+ const PCDACS_EEPROM *pSrcStruct)
+{
+ uint16_t powerValue;
+ uint16_t lFreq, rFreq; /* left and right frequency values */
+ uint16_t llPcdac, ulPcdac; /* lower and upper left pcdac values */
+ uint16_t lrPcdac, urPcdac; /* lower and upper right pcdac values */
+ uint16_t lPwr, uPwr; /* lower and upper temp pwr values */
+ uint16_t lScaledPwr, rScaledPwr; /* left and right scaled power */
+
+ if (ar5211FindValueInList(channel, pcdacValue, pSrcStruct, &powerValue))
+ /* value was copied from srcStruct */
+ return powerValue;
+
+ ar5211GetLowerUpperValues(channel, pSrcStruct->pChannelList,
+ pSrcStruct->numChannels, &lFreq, &rFreq);
+ ar5211GetLowerUpperPcdacs(pcdacValue, lFreq, pSrcStruct,
+ &llPcdac, &ulPcdac);
+ ar5211GetLowerUpperPcdacs(pcdacValue, rFreq, pSrcStruct,
+ &lrPcdac, &urPcdac);
+
+ /* get the power index for the pcdac value */
+ ar5211FindValueInList(lFreq, llPcdac, pSrcStruct, &lPwr);
+ ar5211FindValueInList(lFreq, ulPcdac, pSrcStruct, &uPwr);
+ lScaledPwr = ar5211GetInterpolatedValue(pcdacValue,
+ llPcdac, ulPcdac, lPwr, uPwr, 0);
+
+ ar5211FindValueInList(rFreq, lrPcdac, pSrcStruct, &lPwr);
+ ar5211FindValueInList(rFreq, urPcdac, pSrcStruct, &uPwr);
+ rScaledPwr = ar5211GetInterpolatedValue(pcdacValue,
+ lrPcdac, urPcdac, lPwr, uPwr, 0);
+
+ return ar5211GetInterpolatedValue(channel, lFreq, rFreq,
+ lScaledPwr, rScaledPwr, 0);
+}
+
+/*
+ * Find the value from the calibrated source data struct
+ */
+HAL_BOOL
+ar5211FindValueInList(uint16_t channel, uint16_t pcdacValue,
+ const PCDACS_EEPROM *pSrcStruct, uint16_t *powerValue)
+{
+ const DATA_PER_CHANNEL *pChannelData;
+ const uint16_t *pPcdac;
+ uint16_t i, j;
+
+ pChannelData = pSrcStruct->pDataPerChannel;
+ for (i = 0; i < pSrcStruct->numChannels; i++ ) {
+ if (pChannelData->channelValue == channel) {
+ pPcdac = pChannelData->PcdacValues;
+ for (j = 0; j < pChannelData->numPcdacValues; j++ ) {
+ if (*pPcdac == pcdacValue) {
+ *powerValue = pChannelData->PwrValues[j];
+ return AH_TRUE;
+ }
+ pPcdac++;
+ }
+ }
+ pChannelData++;
+ }
+ return AH_FALSE;
+}
+
+/*
+ * Returns interpolated or the scaled up interpolated value
+ */
+uint16_t
+ar5211GetInterpolatedValue(uint16_t target,
+ uint16_t srcLeft, uint16_t srcRight,
+ uint16_t targetLeft, uint16_t targetRight,
+ HAL_BOOL scaleUp)
+{
+ uint16_t rv;
+ int16_t lRatio;
+ uint16_t scaleValue = EEP_SCALE;
+
+ /* to get an accurate ratio, always scale, if want to scale, then don't scale back down */
+ if ((targetLeft * targetRight) == 0)
+ return 0;
+ if (scaleUp)
+ scaleValue = 1;
+
+ if (srcRight != srcLeft) {
+ /*
+ * Note the ratio always need to be scaled,
+ * since it will be a fraction.
+ */
+ lRatio = (target - srcLeft) * EEP_SCALE / (srcRight - srcLeft);
+ if (lRatio < 0) {
+ /* Return as Left target if value would be negative */
+ rv = targetLeft * (scaleUp ? EEP_SCALE : 1);
+ } else if (lRatio > EEP_SCALE) {
+ /* Return as Right target if Ratio is greater than 100% (SCALE) */
+ rv = targetRight * (scaleUp ? EEP_SCALE : 1);
+ } else {
+ rv = (lRatio * targetRight + (EEP_SCALE - lRatio) *
+ targetLeft) / scaleValue;
+ }
+ } else {
+ rv = targetLeft;
+ if (scaleUp)
+ rv *= EEP_SCALE;
+ }
+ return rv;
+}
+
+/*
+ * Look for value being within 0.1 of the search values
+ * however, NDIS can't do float calculations, so multiply everything
+ * up by EEP_SCALE so can do integer arithmatic
+ *
+ * INPUT value -value to search for
+ * INPUT pList -ptr to the list to search
+ * INPUT listSize -number of entries in list
+ * OUTPUT pLowerValue -return the lower value
+ * OUTPUT pUpperValue -return the upper value
+ */
+void
+ar5211GetLowerUpperValues(uint16_t value,
+ const uint16_t *pList, uint16_t listSize,
+ uint16_t *pLowerValue, uint16_t *pUpperValue)
+{
+ const uint16_t listEndValue = *(pList + listSize - 1);
+ uint32_t target = value * EEP_SCALE;
+ int i;
+
+ /*
+ * See if value is lower than the first value in the list
+ * if so return first value
+ */
+ if (target < (uint32_t)(*pList * EEP_SCALE - EEP_DELTA)) {
+ *pLowerValue = *pList;
+ *pUpperValue = *pList;
+ return;
+ }
+
+ /*
+ * See if value is greater than last value in list
+ * if so return last value
+ */
+ if (target > (uint32_t)(listEndValue * EEP_SCALE + EEP_DELTA)) {
+ *pLowerValue = listEndValue;
+ *pUpperValue = listEndValue;
+ return;
+ }
+
+ /* look for value being near or between 2 values in list */
+ for (i = 0; i < listSize; i++) {
+ /*
+ * If value is close to the current value of the list
+ * then target is not between values, it is one of the values
+ */
+ if (abs(pList[i] * EEP_SCALE - (int32_t) target) < EEP_DELTA) {
+ *pLowerValue = pList[i];
+ *pUpperValue = pList[i];
+ return;
+ }
+
+ /*
+ * Look for value being between current value and next value
+ * if so return these 2 values
+ */
+ if (target < (uint32_t)(pList[i + 1] * EEP_SCALE - EEP_DELTA)) {
+ *pLowerValue = pList[i];
+ *pUpperValue = pList[i + 1];
+ return;
+ }
+ }
+}
+
+/*
+ * Get the upper and lower pcdac given the channel and the pcdac
+ * used in the search
+ */
+void
+ar5211GetLowerUpperPcdacs(uint16_t pcdac, uint16_t channel,
+ const PCDACS_EEPROM *pSrcStruct,
+ uint16_t *pLowerPcdac, uint16_t *pUpperPcdac)
+{
+ const DATA_PER_CHANNEL *pChannelData;
+ int i;
+
+ /* Find the channel information */
+ pChannelData = pSrcStruct->pDataPerChannel;
+ for (i = 0; i < pSrcStruct->numChannels; i++) {
+ if (pChannelData->channelValue == channel)
+ break;
+ pChannelData++;
+ }
+ ar5211GetLowerUpperValues(pcdac, pChannelData->PcdacValues,
+ pChannelData->numPcdacValues, pLowerPcdac, pUpperPcdac);
+}
+
+#define DYN_ADJ_UP_MARGIN 15
+#define DYN_ADJ_LO_MARGIN 20
+
+static const GAIN_OPTIMIZATION_LADDER gainLadder = {
+ 9, /* numStepsInLadder */
+ 4, /* defaultStepNum */
+ { { {4, 1, 1, 1}, 6, "FG8"},
+ { {4, 0, 1, 1}, 4, "FG7"},
+ { {3, 1, 1, 1}, 3, "FG6"},
+ { {4, 0, 0, 1}, 1, "FG5"},
+ { {4, 1, 1, 0}, 0, "FG4"}, /* noJack */
+ { {4, 0, 1, 0}, -2, "FG3"}, /* halfJack */
+ { {3, 1, 1, 0}, -3, "FG2"}, /* clip3 */
+ { {4, 0, 0, 0}, -4, "FG1"}, /* noJack */
+ { {2, 1, 1, 0}, -6, "FG0"} /* clip2 */
+ }
+};
+
+/*
+ * Initialize the gain structure to good values
+ */
+void
+ar5211InitializeGainValues(struct ath_hal *ah)
+{
+ struct ath_hal_5211 *ahp = AH5211(ah);
+ GAIN_VALUES *gv = &ahp->ah_gainValues;
+
+ /* initialize gain optimization values */
+ gv->currStepNum = gainLadder.defaultStepNum;
+ gv->currStep = &gainLadder.optStep[gainLadder.defaultStepNum];
+ gv->active = AH_TRUE;
+ gv->loTrig = 20;
+ gv->hiTrig = 35;
+}
+
+static HAL_BOOL
+ar5211InvalidGainReadback(struct ath_hal *ah, GAIN_VALUES *gv)
+{
+ const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan;
+ uint32_t gStep, g;
+ uint32_t L1, L2, L3, L4;
+
+ if (IEEE80211_IS_CHAN_CCK(chan)) {
+ gStep = 0x18;
+ L1 = 0;
+ L2 = gStep + 4;
+ L3 = 0x40;
+ L4 = L3 + 50;
+
+ gv->loTrig = L1;
+ gv->hiTrig = L4+5;
+ } else {
+ gStep = 0x3f;
+ L1 = 0;
+ L2 = 50;
+ L3 = L1;
+ L4 = L3 + 50;
+
+ gv->loTrig = L1 + DYN_ADJ_LO_MARGIN;
+ gv->hiTrig = L4 - DYN_ADJ_UP_MARGIN;
+ }
+ g = gv->currGain;
+
+ return !((g >= L1 && g<= L2) || (g >= L3 && g <= L4));
+}
+
+/*
+ * Enable the probe gain check on the next packet
+ */
+static void
+ar5211RequestRfgain(struct ath_hal *ah)
+{
+ struct ath_hal_5211 *ahp = AH5211(ah);
+
+ /* Enable the gain readback probe */
+ OS_REG_WRITE(ah, AR_PHY_PAPD_PROBE,
+ SM(ahp->ah_tx6PowerInHalfDbm, AR_PHY_PAPD_PROBE_POWERTX)
+ | AR_PHY_PAPD_PROBE_NEXT_TX);
+
+ ahp->ah_rfgainState = HAL_RFGAIN_READ_REQUESTED;
+}
+
+/*
+ * Exported call to check for a recent gain reading and return
+ * the current state of the thermal calibration gain engine.
+ */
+HAL_RFGAIN
+ar5211GetRfgain(struct ath_hal *ah)
+{
+ struct ath_hal_5211 *ahp = AH5211(ah);
+ GAIN_VALUES *gv = &ahp->ah_gainValues;
+ uint32_t rddata;
+
+ if (!gv->active)
+ return HAL_RFGAIN_INACTIVE;
+
+ if (ahp->ah_rfgainState == HAL_RFGAIN_READ_REQUESTED) {
+ /* Caller had asked to setup a new reading. Check it. */
+ rddata = OS_REG_READ(ah, AR_PHY_PAPD_PROBE);
+
+ if ((rddata & AR_PHY_PAPD_PROBE_NEXT_TX) == 0) {
+ /* bit got cleared, we have a new reading. */
+ gv->currGain = rddata >> AR_PHY_PAPD_PROBE_GAINF_S;
+ /* inactive by default */
+ ahp->ah_rfgainState = HAL_RFGAIN_INACTIVE;
+
+ if (!ar5211InvalidGainReadback(ah, gv) &&
+ ar5211IsGainAdjustNeeded(ah, gv) &&
+ ar5211AdjustGain(ah, gv) > 0) {
+ /*
+ * Change needed. Copy ladder info
+ * into eeprom info.
+ */
+ ar5211SetRfgain(ah, gv);
+ ahp->ah_rfgainState = HAL_RFGAIN_NEED_CHANGE;
+ }
+ }
+ }
+ return ahp->ah_rfgainState;
+}
+
+/*
+ * Check to see if our readback gain level sits within the linear
+ * region of our current variable attenuation window
+ */
+static HAL_BOOL
+ar5211IsGainAdjustNeeded(struct ath_hal *ah, const GAIN_VALUES *gv)
+{
+ return (gv->currGain <= gv->loTrig || gv->currGain >= gv->hiTrig);
+}
+
+/*
+ * Move the rabbit ears in the correct direction.
+ */
+static int32_t
+ar5211AdjustGain(struct ath_hal *ah, GAIN_VALUES *gv)
+{
+ /* return > 0 for valid adjustments. */
+ if (!gv->active)
+ return -1;
+
+ gv->currStep = &gainLadder.optStep[gv->currStepNum];
+ if (gv->currGain >= gv->hiTrig) {
+ if (gv->currStepNum == 0) {
+ HALDEBUG(ah, HAL_DEBUG_RFPARAM,
+ "%s: Max gain limit.\n", __func__);
+ return -1;
+ }
+ HALDEBUG(ah, HAL_DEBUG_RFPARAM,
+ "%s: Adding gain: currG=%d [%s] --> ",
+ __func__, gv->currGain, gv->currStep->stepName);
+ gv->targetGain = gv->currGain;
+ while (gv->targetGain >= gv->hiTrig && gv->currStepNum > 0) {
+ gv->targetGain -= 2 * (gainLadder.optStep[--(gv->currStepNum)].stepGain -
+ gv->currStep->stepGain);
+ gv->currStep = &gainLadder.optStep[gv->currStepNum];
+ }
+ HALDEBUG(ah, HAL_DEBUG_RFPARAM, "targG=%d [%s]\n",
+ gv->targetGain, gv->currStep->stepName);
+ return 1;
+ }
+ if (gv->currGain <= gv->loTrig) {
+ if (gv->currStepNum == gainLadder.numStepsInLadder-1) {
+ HALDEBUG(ah, HAL_DEBUG_RFPARAM,
+ "%s: Min gain limit.\n", __func__);
+ return -2;
+ }
+ HALDEBUG(ah, HAL_DEBUG_RFPARAM,
+ "%s: Deducting gain: currG=%d [%s] --> ",
+ __func__, gv->currGain, gv->currStep->stepName);
+ gv->targetGain = gv->currGain;
+ while (gv->targetGain <= gv->loTrig &&
+ gv->currStepNum < (gainLadder.numStepsInLadder - 1)) {
+ gv->targetGain -= 2 *
+ (gainLadder.optStep[++(gv->currStepNum)].stepGain - gv->currStep->stepGain);
+ gv->currStep = &gainLadder.optStep[gv->currStepNum];
+ }
+ HALDEBUG(ah, HAL_DEBUG_RFPARAM, "targG=%d [%s]\n",
+ gv->targetGain, gv->currStep->stepName);
+ return 2;
+ }
+ return 0; /* caller didn't call needAdjGain first */
+}
+
+/*
+ * Adjust the 5GHz EEPROM information with the desired calibration values.
+ */
+static void
+ar5211SetRfgain(struct ath_hal *ah, const GAIN_VALUES *gv)
+{
+ HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;
+
+ if (!gv->active)
+ return;
+ ee->ee_cornerCal.clip = gv->currStep->paramVal[0]; /* bb_tx_clip */
+ ee->ee_cornerCal.pd90 = gv->currStep->paramVal[1]; /* rf_pwd_90 */
+ ee->ee_cornerCal.pd84 = gv->currStep->paramVal[2]; /* rf_pwd_84 */
+ ee->ee_cornerCal.gSel = gv->currStep->paramVal[3]; /* rf_rfgainsel */
+}
+
+static void
+ar5211SetOperatingMode(struct ath_hal *ah, int opmode)
+{
+ struct ath_hal_5211 *ahp = AH5211(ah);
+ uint32_t val;
+
+ val = OS_REG_READ(ah, AR_STA_ID1) & 0xffff;
+ switch (opmode) {
+ case HAL_M_HOSTAP:
+ OS_REG_WRITE(ah, AR_STA_ID1, val
+ | AR_STA_ID1_STA_AP
+ | AR_STA_ID1_RTS_USE_DEF
+ | ahp->ah_staId1Defaults);
+ break;
+ case HAL_M_IBSS:
+ OS_REG_WRITE(ah, AR_STA_ID1, val
+ | AR_STA_ID1_ADHOC
+ | AR_STA_ID1_DESC_ANTENNA
+ | ahp->ah_staId1Defaults);
+ break;
+ case HAL_M_STA:
+ case HAL_M_MONITOR:
+ OS_REG_WRITE(ah, AR_STA_ID1, val
+ | AR_STA_ID1_DEFAULT_ANTENNA
+ | ahp->ah_staId1Defaults);
+ break;
+ }
+}
+
+void
+ar5211SetPCUConfig(struct ath_hal *ah)
+{
+ ar5211SetOperatingMode(ah, AH_PRIVATE(ah)->ah_opmode);
+}
diff --git a/sys/dev/ath/ath_hal/ar5211/ar5211_xmit.c b/sys/dev/ath/ath_hal/ar5211/ar5211_xmit.c
new file mode 100644
index 000000000000..b2ad8fcb9f4b
--- /dev/null
+++ b/sys/dev/ath/ath_hal/ar5211/ar5211_xmit.c
@@ -0,0 +1,699 @@
+/*-
+ * SPDX-License-Identifier: ISC
+ *
+ * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
+ * Copyright (c) 2002-2006 Atheros Communications, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include "opt_ah.h"
+
+#include "ah.h"
+#include "ah_internal.h"
+#include "ah_desc.h"
+
+#include "ar5211/ar5211.h"
+#include "ar5211/ar5211reg.h"
+#include "ar5211/ar5211desc.h"
+
+/*
+ * Update Tx FIFO trigger level.
+ *
+ * Set bIncTrigLevel to TRUE to increase the trigger level.
+ * Set bIncTrigLevel to FALSE to decrease the trigger level.
+ *
+ * Returns TRUE if the trigger level was updated
+ */
+HAL_BOOL
+ar5211UpdateTxTrigLevel(struct ath_hal *ah, HAL_BOOL bIncTrigLevel)
+{
+ uint32_t curTrigLevel, txcfg;
+ HAL_INT ints = ar5211GetInterrupts(ah);
+
+ /*
+ * Disable chip interrupts. This is because halUpdateTxTrigLevel
+ * is called from both ISR and non-ISR contexts.
+ */
+ ar5211SetInterrupts(ah, ints &~ HAL_INT_GLOBAL);
+ txcfg = OS_REG_READ(ah, AR_TXCFG);
+ curTrigLevel = (txcfg & AR_TXCFG_FTRIG_M) >> AR_TXCFG_FTRIG_S;
+ if (bIncTrigLevel){
+ /* increase the trigger level */
+ curTrigLevel = curTrigLevel +
+ ((MAX_TX_FIFO_THRESHOLD - curTrigLevel) / 2);
+ } else {
+ /* decrease the trigger level if not already at the minimum */
+ if (curTrigLevel > MIN_TX_FIFO_THRESHOLD) {
+ /* decrease the trigger level */
+ curTrigLevel--;
+ } else {
+ /* no update to the trigger level */
+ /* re-enable chip interrupts */
+ ar5211SetInterrupts(ah, ints);
+ return AH_FALSE;
+ }
+ }
+ /* Update the trigger level */
+ OS_REG_WRITE(ah, AR_TXCFG, (txcfg &~ AR_TXCFG_FTRIG_M) |
+ ((curTrigLevel << AR_TXCFG_FTRIG_S) & AR_TXCFG_FTRIG_M));
+ /* re-enable chip interrupts */
+ ar5211SetInterrupts(ah, ints);
+ return AH_TRUE;
+}
+
+/*
+ * Set the properties of the tx queue with the parameters
+ * from qInfo. The queue must previously have been setup
+ * with a call to ar5211SetupTxQueue.
+ */
+HAL_BOOL
+ar5211SetTxQueueProps(struct ath_hal *ah, int q, const HAL_TXQ_INFO *qInfo)
+{
+ struct ath_hal_5211 *ahp = AH5211(ah);
+
+ if (q >= HAL_NUM_TX_QUEUES) {
+ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n",
+ __func__, q);
+ return AH_FALSE;
+ }
+ return ath_hal_setTxQProps(ah, &ahp->ah_txq[q], qInfo);
+}
+
+/*
+ * Return the properties for the specified tx queue.
+ */
+HAL_BOOL
+ar5211GetTxQueueProps(struct ath_hal *ah, int q, HAL_TXQ_INFO *qInfo)
+{
+ struct ath_hal_5211 *ahp = AH5211(ah);
+
+ if (q >= HAL_NUM_TX_QUEUES) {
+ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n",
+ __func__, q);
+ return AH_FALSE;
+ }
+ return ath_hal_getTxQProps(ah, qInfo, &ahp->ah_txq[q]);
+}
+
+/*
+ * Allocate and initialize a tx DCU/QCU combination.
+ */
+int
+ar5211SetupTxQueue(struct ath_hal *ah, HAL_TX_QUEUE type,
+ const HAL_TXQ_INFO *qInfo)
+{
+ struct ath_hal_5211 *ahp = AH5211(ah);
+ HAL_TX_QUEUE_INFO *qi;
+ int q;
+
+ switch (type) {
+ case HAL_TX_QUEUE_BEACON:
+ q = 9;
+ break;
+ case HAL_TX_QUEUE_CAB:
+ q = 8;
+ break;
+ case HAL_TX_QUEUE_DATA:
+ q = 0;
+ if (ahp->ah_txq[q].tqi_type != HAL_TX_QUEUE_INACTIVE)
+ return q;
+ break;
+ default:
+ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad tx queue type %u\n",
+ __func__, type);
+ return -1;
+ }
+
+ HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: queue %u\n", __func__, q);
+
+ qi = &ahp->ah_txq[q];
+ if (qi->tqi_type != HAL_TX_QUEUE_INACTIVE) {
+ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: tx queue %u already active\n",
+ __func__, q);
+ return -1;
+ }
+ OS_MEMZERO(qi, sizeof(HAL_TX_QUEUE_INFO));
+ qi->tqi_type = type;
+ if (qInfo == AH_NULL) {
+ /* by default enable OK+ERR+DESC+URN interrupts */
+ qi->tqi_qflags =
+ HAL_TXQ_TXOKINT_ENABLE
+ | HAL_TXQ_TXERRINT_ENABLE
+ | HAL_TXQ_TXDESCINT_ENABLE
+ | HAL_TXQ_TXURNINT_ENABLE
+ ;
+ qi->tqi_aifs = INIT_AIFS;
+ qi->tqi_cwmin = HAL_TXQ_USEDEFAULT; /* NB: do at reset */
+ qi->tqi_cwmax = INIT_CWMAX;
+ qi->tqi_shretry = INIT_SH_RETRY;
+ qi->tqi_lgretry = INIT_LG_RETRY;
+ } else
+ (void) ar5211SetTxQueueProps(ah, q, qInfo);
+ return q;
+}
+
+/*
+ * Update the h/w interrupt registers to reflect a tx q's configuration.
+ */
+static void
+setTxQInterrupts(struct ath_hal *ah, HAL_TX_QUEUE_INFO *qi)
+{
+ struct ath_hal_5211 *ahp = AH5211(ah);
+
+ HALDEBUG(ah, HAL_DEBUG_TXQUEUE,
+ "%s: tx ok 0x%x err 0x%x desc 0x%x eol 0x%x urn 0x%x\n", __func__
+ , ahp->ah_txOkInterruptMask
+ , ahp->ah_txErrInterruptMask
+ , ahp->ah_txDescInterruptMask
+ , ahp->ah_txEolInterruptMask
+ , ahp->ah_txUrnInterruptMask
+ );
+
+ OS_REG_WRITE(ah, AR_IMR_S0,
+ SM(ahp->ah_txOkInterruptMask, AR_IMR_S0_QCU_TXOK)
+ | SM(ahp->ah_txDescInterruptMask, AR_IMR_S0_QCU_TXDESC)
+ );
+ OS_REG_WRITE(ah, AR_IMR_S1,
+ SM(ahp->ah_txErrInterruptMask, AR_IMR_S1_QCU_TXERR)
+ | SM(ahp->ah_txEolInterruptMask, AR_IMR_S1_QCU_TXEOL)
+ );
+ OS_REG_RMW_FIELD(ah, AR_IMR_S2,
+ AR_IMR_S2_QCU_TXURN, ahp->ah_txUrnInterruptMask);
+}
+
+/*
+ * Free a tx DCU/QCU combination.
+ */
+HAL_BOOL
+ar5211ReleaseTxQueue(struct ath_hal *ah, u_int q)
+{
+ struct ath_hal_5211 *ahp = AH5211(ah);
+ HAL_TX_QUEUE_INFO *qi;
+
+ 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;
+ }
+
+ HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: release queue %u\n", __func__, q);
+
+ qi->tqi_type = HAL_TX_QUEUE_INACTIVE;
+ ahp->ah_txOkInterruptMask &= ~(1 << q);
+ ahp->ah_txErrInterruptMask &= ~(1 << q);
+ ahp->ah_txDescInterruptMask &= ~(1 << q);
+ ahp->ah_txEolInterruptMask &= ~(1 << q);
+ ahp->ah_txUrnInterruptMask &= ~(1 << q);
+ setTxQInterrupts(ah, qi);
+
+ 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;
+}
+
+/*
+ * Get the TXDP for the specified data queue.
+ */
+uint32_t
+ar5211GetTxDP(struct ath_hal *ah, u_int q)
+{
+ HALASSERT(q < HAL_NUM_TX_QUEUES);
+ return OS_REG_READ(ah, AR_QTXDP(q));
+}
+
+/*
+ * Set the TxDP for the specified tx queue.
+ */
+HAL_BOOL
+ar5211SetTxDP(struct ath_hal *ah, u_int q, uint32_t txdp)
+{
+ HALASSERT(q < HAL_NUM_TX_QUEUES);
+ HALASSERT(AH5211(ah)->ah_txq[q].tqi_type != HAL_TX_QUEUE_INACTIVE);
+
+ /*
+ * Make sure that TXE is deasserted before setting the TXDP. If TXE
+ * is still asserted, setting TXDP will have no effect.
+ */
+ HALASSERT((OS_REG_READ(ah, AR_Q_TXE) & (1 << q)) == 0);
+
+ OS_REG_WRITE(ah, AR_QTXDP(q), txdp);
+
+ return AH_TRUE;
+}
+
+/*
+ * Set Transmit Enable bits for the specified queues.
+ */
+HAL_BOOL
+ar5211StartTxDma(struct ath_hal *ah, u_int q)
+{
+ HALASSERT(q < HAL_NUM_TX_QUEUES);
+ HALASSERT(AH5211(ah)->ah_txq[q].tqi_type != HAL_TX_QUEUE_INACTIVE);
+
+ /* Check that queue is not already active */
+ HALASSERT((OS_REG_READ(ah, AR_Q_TXD) & (1<<q)) == 0);
+
+ HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: queue %u\n", __func__, q);
+
+ /* Check to be sure we're not enabling a q that has its TXD bit set. */
+ HALASSERT((OS_REG_READ(ah, AR_Q_TXD) & (1 << q)) == 0);
+
+ OS_REG_WRITE(ah, AR_Q_TXE, 1 << q);
+ return AH_TRUE;
+}
+
+/*
+ * Return the number of frames pending on the specified queue.
+ */
+uint32_t
+ar5211NumTxPending(struct ath_hal *ah, u_int q)
+{
+ uint32_t n;
+
+ HALASSERT(q < HAL_NUM_TX_QUEUES);
+ HALASSERT(AH5211(ah)->ah_txq[q].tqi_type != HAL_TX_QUEUE_INACTIVE);
+
+ n = OS_REG_READ(ah, AR_QSTS(q)) & AR_Q_STS_PEND_FR_CNT_M;
+ /*
+ * Pending frame count (PFC) can momentarily go to zero
+ * while TXE remains asserted. In other words a PFC of
+ * zero is not sufficient to say that the queue has stopped.
+ */
+ if (n == 0 && (OS_REG_READ(ah, AR_Q_TXE) & (1<<q)))
+ n = 1; /* arbitrarily pick 1 */
+ return n;
+}
+
+/*
+ * Stop transmit on the specified queue
+ */
+HAL_BOOL
+ar5211StopTxDma(struct ath_hal *ah, u_int q)
+{
+ int i;
+
+ HALASSERT(q < HAL_NUM_TX_QUEUES);
+ HALASSERT(AH5211(ah)->ah_txq[q].tqi_type != HAL_TX_QUEUE_INACTIVE);
+
+ OS_REG_WRITE(ah, AR_Q_TXD, 1<<q);
+ for (i = 0; i < 10000; i++) {
+ if (ar5211NumTxPending(ah, q) == 0)
+ break;
+ OS_DELAY(10);
+ }
+ OS_REG_WRITE(ah, AR_Q_TXD, 0);
+
+ return (i < 10000);
+}
+
+/*
+ * Descriptor Access Functions
+ */
+
+#define VALID_PKT_TYPES \
+ ((1<<HAL_PKT_TYPE_NORMAL)|(1<<HAL_PKT_TYPE_ATIM)|\
+ (1<<HAL_PKT_TYPE_PSPOLL)|(1<<HAL_PKT_TYPE_PROBE_RESP)|\
+ (1<<HAL_PKT_TYPE_BEACON))
+#define isValidPktType(_t) ((1<<(_t)) & VALID_PKT_TYPES)
+#define VALID_TX_RATES \
+ ((1<<0x0b)|(1<<0x0f)|(1<<0x0a)|(1<<0x0e)|(1<<0x09)|(1<<0x0d)|\
+ (1<<0x08)|(1<<0x0c)|(1<<0x1b)|(1<<0x1a)|(1<<0x1e)|(1<<0x19)|\
+ (1<<0x1d)|(1<<0x18)|(1<<0x1c))
+#define isValidTxRate(_r) ((1<<(_r)) & VALID_TX_RATES)
+
+HAL_BOOL
+ar5211SetupTxDesc(struct ath_hal *ah, struct ath_desc *ds,
+ u_int pktLen,
+ u_int hdrLen,
+ HAL_PKT_TYPE type,
+ u_int txPower,
+ u_int txRate0, u_int txTries0,
+ u_int keyIx,
+ u_int antMode,
+ u_int flags,
+ u_int rtsctsRate,
+ u_int rtsctsDuration,
+ u_int compicvLen,
+ u_int compivLen,
+ u_int comp)
+{
+ struct ar5211_desc *ads = AR5211DESC(ds);
+
+ (void) hdrLen;
+ (void) txPower;
+ (void) rtsctsRate; (void) rtsctsDuration;
+
+ HALASSERT(txTries0 != 0);
+ HALASSERT(isValidPktType(type));
+ HALASSERT(isValidTxRate(txRate0));
+ /* XXX validate antMode */
+
+ ads->ds_ctl0 = (pktLen & AR_FrameLen)
+ | (txRate0 << AR_XmitRate_S)
+ | (antMode << AR_AntModeXmit_S)
+ | (flags & HAL_TXDESC_CLRDMASK ? AR_ClearDestMask : 0)
+ | (flags & HAL_TXDESC_INTREQ ? AR_TxInterReq : 0)
+ | (flags & HAL_TXDESC_RTSENA ? AR_RTSCTSEnable : 0)
+ | (flags & HAL_TXDESC_VEOL ? AR_VEOL : 0)
+ ;
+ ads->ds_ctl1 = (type << 26)
+ | (flags & HAL_TXDESC_NOACK ? AR_NoAck : 0)
+ ;
+
+ if (keyIx != HAL_TXKEYIX_INVALID) {
+ ads->ds_ctl1 |=
+ (keyIx << AR_EncryptKeyIdx_S) & AR_EncryptKeyIdx;
+ ads->ds_ctl0 |= AR_EncryptKeyValid;
+ }
+ return AH_TRUE;
+#undef RATE
+}
+
+HAL_BOOL
+ar5211SetupXTxDesc(struct ath_hal *ah, struct ath_desc *ds,
+ u_int txRate1, u_int txTries1,
+ u_int txRate2, u_int txTries2,
+ u_int txRate3, u_int txTries3)
+{
+ (void) ah; (void) ds;
+ (void) txRate1; (void) txTries1;
+ (void) txRate2; (void) txTries2;
+ (void) txRate3; (void) txTries3;
+ return AH_FALSE;
+}
+
+void
+ar5211IntrReqTxDesc(struct ath_hal *ah, struct ath_desc *ds)
+{
+ struct ar5211_desc *ads = AR5211DESC(ds);
+
+ ads->ds_ctl0 |= AR_TxInterReq;
+}
+
+HAL_BOOL
+ar5211FillTxDesc(struct ath_hal *ah, struct ath_desc *ds,
+ HAL_DMA_ADDR *bufAddrList, uint32_t *segLenList, u_int qcuId,
+ u_int descId, HAL_BOOL firstSeg, HAL_BOOL lastSeg,
+ const struct ath_desc *ds0)
+{
+ struct ar5211_desc *ads = AR5211DESC(ds);
+ uint32_t segLen = segLenList[0];
+
+ ds->ds_data = bufAddrList[0];
+
+ HALASSERT((segLen &~ AR_BufLen) == 0);
+
+ if (firstSeg) {
+ /*
+ * First descriptor, don't clobber xmit control data
+ * setup by ar5211SetupTxDesc.
+ */
+ ads->ds_ctl1 |= segLen | (lastSeg ? 0 : AR_More);
+ } else if (lastSeg) { /* !firstSeg && lastSeg */
+ /*
+ * Last descriptor in a multi-descriptor frame,
+ * copy the transmit parameters from the first
+ * frame for processing on completion.
+ */
+ ads->ds_ctl0 = AR5211DESC_CONST(ds0)->ds_ctl0;
+ ads->ds_ctl1 = segLen;
+ } else { /* !firstSeg && !lastSeg */
+ /*
+ * Intermediate descriptor in a multi-descriptor frame.
+ */
+ ads->ds_ctl0 = 0;
+ ads->ds_ctl1 = segLen | AR_More;
+ }
+ ads->ds_status0 = ads->ds_status1 = 0;
+ return AH_TRUE;
+}
+
+/*
+ * Processing of HW TX descriptor.
+ */
+HAL_STATUS
+ar5211ProcTxDesc(struct ath_hal *ah,
+ struct ath_desc *ds, struct ath_tx_status *ts)
+{
+ struct ar5211_desc *ads = AR5211DESC(ds);
+
+ if ((ads->ds_status1 & AR_Done) == 0)
+ return HAL_EINPROGRESS;
+
+ /* Update software copies of the HW status */
+ ts->ts_seqnum = MS(ads->ds_status1, AR_SeqNum);
+ ts->ts_tstamp = MS(ads->ds_status0, AR_SendTimestamp);
+ ts->ts_status = 0;
+ if ((ads->ds_status0 & AR_FrmXmitOK) == 0) {
+ if (ads->ds_status0 & AR_ExcessiveRetries)
+ ts->ts_status |= HAL_TXERR_XRETRY;
+ if (ads->ds_status0 & AR_Filtered)
+ ts->ts_status |= HAL_TXERR_FILT;
+ if (ads->ds_status0 & AR_FIFOUnderrun)
+ ts->ts_status |= HAL_TXERR_FIFO;
+ }
+ ts->ts_rate = MS(ads->ds_ctl0, AR_XmitRate);
+ ts->ts_rssi = MS(ads->ds_status1, AR_AckSigStrength);
+ ts->ts_shortretry = MS(ads->ds_status0, AR_ShortRetryCnt);
+ ts->ts_longretry = MS(ads->ds_status0, AR_LongRetryCnt);
+ ts->ts_virtcol = MS(ads->ds_status0, AR_VirtCollCnt);
+ ts->ts_antenna = 0; /* NB: don't know */
+ ts->ts_finaltsi = 0;
+ /*
+ * NB: the number of retries is one less than it should be.
+ * Also, 0 retries and 1 retry are both reported as 0 retries.
+ */
+ if (ts->ts_shortretry > 0)
+ ts->ts_shortretry++;
+ if (ts->ts_longretry > 0)
+ ts->ts_longretry++;
+
+ return HAL_OK;
+}
+
+/*
+ * Determine which tx queues need interrupt servicing.
+ * STUB.
+ */
+void
+ar5211GetTxIntrQueue(struct ath_hal *ah, uint32_t *txqs)
+{
+ return;
+}
+
+/*
+ * Retrieve the rate table from the given TX completion descriptor
+ */
+HAL_BOOL
+ar5211GetTxCompletionRates(struct ath_hal *ah, const struct ath_desc *ds0, int *rates, int *tries)
+{
+ return AH_FALSE;
+}
+
+void
+ar5211SetTxDescLink(struct ath_hal *ah, void *ds, uint32_t link)
+{
+ struct ar5211_desc *ads = AR5211DESC(ds);
+
+ ads->ds_link = link;
+}
+
+void
+ar5211GetTxDescLink(struct ath_hal *ah, void *ds, uint32_t *link)
+{
+ struct ar5211_desc *ads = AR5211DESC(ds);
+
+ *link = ads->ds_link;
+}
+
+void
+ar5211GetTxDescLinkPtr(struct ath_hal *ah, void *ds, uint32_t **linkptr)
+{
+ struct ar5211_desc *ads = AR5211DESC(ds);
+
+ *linkptr = &ads->ds_link;
+}
diff --git a/sys/dev/ath/ath_hal/ar5211/ar5211desc.h b/sys/dev/ath/ath_hal/ar5211/ar5211desc.h
new file mode 100644
index 000000000000..9d5a0b62f006
--- /dev/null
+++ b/sys/dev/ath/ath_hal/ar5211/ar5211desc.h
@@ -0,0 +1,132 @@
+/*-
+ * SPDX-License-Identifier: ISC
+ *
+ * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
+ * Copyright (c) 2002-2006 Atheros Communications, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifndef _DEV_ATH_AR5211DESC_H
+#define _DEV_ATH_AR5211DESC_H
+
+/*
+ * Defintions for the DMA descriptors used by the Atheros
+ * AR5211 and AR5110 Wireless Lan controller parts.
+ */
+
+/* DMA descriptors */
+struct ar5211_desc {
+ uint32_t ds_link; /* link pointer */
+ uint32_t ds_data; /* data buffer pointer */
+ uint32_t ds_ctl0; /* DMA control 0 */
+ uint32_t ds_ctl1; /* DMA control 1 */
+ uint32_t ds_status0; /* DMA status 0 */
+ uint32_t ds_status1; /* DMA status 1 */
+} __packed;
+#define AR5211DESC(_ds) ((struct ar5211_desc *)(_ds))
+#define AR5211DESC_CONST(_ds) ((const struct ar5211_desc *)(_ds))
+
+/* TX ds_ctl0 */
+#define AR_FrameLen 0x00000fff /* frame length */
+/* bits 12-17 are reserved */
+#define AR_XmitRate 0x003c0000 /* txrate */
+#define AR_XmitRate_S 18
+#define AR_RTSCTSEnable 0x00400000 /* RTS/CTS enable */
+#define AR_VEOL 0x00800000 /* virtual end-of-list */
+#define AR_ClearDestMask 0x01000000 /* Clear destination mask bit */
+#define AR_AntModeXmit 0x1e000000 /* TX antenna seslection */
+#define AR_AntModeXmit_S 25
+#define AR_TxInterReq 0x20000000 /* TX interrupt request */
+#define AR_EncryptKeyValid 0x40000000 /* EncryptKeyIdx is valid */
+/* bit 31 is reserved */
+
+/* TX ds_ctl1 */
+#define AR_BufLen 0x00000fff /* data buffer length */
+#define AR_More 0x00001000 /* more desc in this frame */
+#define AR_EncryptKeyIdx 0x000fe000 /* ecnrypt key table index */
+#define AR_EncryptKeyIdx_S 13
+#define AR_FrmType 0x00700000 /* frame type indication */
+#define AR_FrmType_S 20
+#define AR_Frm_Normal 0x00000000 /* normal frame */
+#define AR_Frm_ATIM 0x00100000 /* ATIM frame */
+#define AR_Frm_PSPOLL 0x00200000 /* PS poll frame */
+#define AR_Frm_Beacon 0x00300000 /* Beacon frame */
+#define AR_Frm_ProbeResp 0x00400000 /* no delay data */
+#define AR_NoAck 0x00800000 /* No ACK flag */
+/* bits 24-31 are reserved */
+
+/* RX ds_ctl1 */
+/* AR_BufLen 0x00000fff data buffer length */
+/* bit 12 is reserved */
+#define AR_RxInterReq 0x00002000 /* RX interrupt request */
+/* bits 14-31 are reserved */
+
+/* TX ds_status0 */
+#define AR_FrmXmitOK 0x00000001 /* TX success */
+#define AR_ExcessiveRetries 0x00000002 /* excessive retries */
+#define AR_FIFOUnderrun 0x00000004 /* TX FIFO underrun */
+#define AR_Filtered 0x00000008 /* TX filter indication */
+/* NB: the spec has the Short+Long retry counts reversed */
+#define AR_LongRetryCnt 0x000000f0 /* long retry count */
+#define AR_LongRetryCnt_S 4
+#define AR_ShortRetryCnt 0x00000f00 /* short retry count */
+#define AR_ShortRetryCnt_S 8
+#define AR_VirtCollCnt 0x0000f000 /* virtual collision count */
+#define AR_VirtCollCnt_S 12
+#define AR_SendTimestamp 0xffff0000 /* TX timestamp */
+#define AR_SendTimestamp_S 16
+
+/* RX ds_status0 */
+#define AR_DataLen 0x00000fff /* RX data length */
+/* AR_More 0x00001000 more desc in this frame */
+/* bits 13-14 are reserved */
+#define AR_RcvRate 0x00078000 /* reception rate */
+#define AR_RcvRate_S 15
+#define AR_RcvSigStrength 0x07f80000 /* receive signal strength */
+#define AR_RcvSigStrength_S 19
+#define AR_RcvAntenna 0x38000000 /* receive antenaa */
+#define AR_RcvAntenna_S 27
+/* bits 30-31 are reserved */
+
+/* TX ds_status1 */
+#define AR_Done 0x00000001 /* descripter complete */
+#define AR_SeqNum 0x00001ffe /* TX sequence number */
+#define AR_SeqNum_S 1
+#define AR_AckSigStrength 0x001fe000 /* strength of ACK */
+#define AR_AckSigStrength_S 13
+/* bits 21-31 are reserved */
+
+/* RX ds_status1 */
+/* AR_Done 0x00000001 descripter complete */
+#define AR_FrmRcvOK 0x00000002 /* frame reception success */
+#define AR_CRCErr 0x00000004 /* CRC error */
+/* bit 3 reserved */
+#define AR_DecryptCRCErr 0x00000010 /* Decryption CRC fiailure */
+#define AR_PHYErr 0x000000e0 /* PHY error */
+#define AR_PHYErr_S 5
+#define AR_PHYErr_Underrun 0x00000000 /* Transmit underrun */
+#define AR_PHYErr_Tim 0x00000020 /* Timing error */
+#define AR_PHYErr_Par 0x00000040 /* Parity error */
+#define AR_PHYErr_Rate 0x00000060 /* Illegal rate */
+#define AR_PHYErr_Len 0x00000080 /* Illegal length */
+#define AR_PHYErr_Radar 0x000000a0 /* Radar detect */
+#define AR_PHYErr_Srv 0x000000c0 /* Illegal service */
+#define AR_PHYErr_TOR 0x000000e0 /* Transmit override receive */
+#define AR_KeyIdxValid 0x00000100 /* decryption key index valid */
+#define AR_KeyIdx 0x00007e00 /* Decryption key index */
+#define AR_KeyIdx_S 9
+#define AR_RcvTimestamp 0x0fff8000 /* timestamp */
+#define AR_RcvTimestamp_S 15
+#define AR_KeyCacheMiss 0x10000000 /* key cache miss indication */
+
+#endif /* _DEV_ATH_AR5211DESC_H_ */
diff --git a/sys/dev/ath/ath_hal/ar5211/ar5211phy.h b/sys/dev/ath/ath_hal/ar5211/ar5211phy.h
new file mode 100644
index 000000000000..6b833352eb82
--- /dev/null
+++ b/sys/dev/ath/ath_hal/ar5211/ar5211phy.h
@@ -0,0 +1,93 @@
+/*-
+ * SPDX-License-Identifier: ISC
+ *
+ * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
+ * Copyright (c) 2002-2006 Atheros Communications, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifndef _DEV_ATH_AR5211PHY_H
+#define _DEV_ATH_AR5211PHY_H
+
+/*
+ * Definitions for the PHY on the Atheros AR5211/5311 chipset.
+ */
+
+/* PHY registers */
+#define AR_PHY_BASE 0x9800 /* PHY registers base address */
+#define AR_PHY(_n) (AR_PHY_BASE + ((_n)<<2))
+
+#define AR_PHY_TURBO 0x9804 /* PHY frame control register */
+#define AR_PHY_FC_TURBO_MODE 0x00000001 /* Set turbo mode bits */
+#define AR_PHY_FC_TURBO_SHORT 0x00000002 /* Set short symbols to turbo mode setting */
+
+#define AR_PHY_CHIP_ID 0x9818 /* PHY chip revision ID */
+
+#define AR_PHY_ACTIVE 0x981C /* PHY activation register */
+#define AR_PHY_ACTIVE_EN 0x00000001 /* Activate PHY chips */
+#define AR_PHY_ACTIVE_DIS 0x00000000 /* Deactivate PHY chips */
+
+#define AR_PHY_AGC_CONTROL 0x9860 /* PHY chip calibration and noise floor setting */
+#define AR_PHY_AGC_CONTROL_CAL 0x00000001 /* Perform PHY chip internal calibration */
+#define AR_PHY_AGC_CONTROL_NF 0x00000002 /* Perform PHY chip noise-floor calculation */
+
+#define AR_PHY_PLL_CTL 0x987c /* PLL control register */
+#define AR_PHY_PLL_CTL_44 0x19 /* 44 MHz for 11b channels and FPGA */
+#define AR_PHY_PLL_CTL_40 0x18 /* 40 MHz */
+#define AR_PHY_PLL_CTL_20 0x13 /* 20 MHz half rate 11a for emulation */
+
+#define AR_PHY_RX_DELAY 0x9914 /* PHY analog_power_on_time, in 100ns increments */
+#define AR_PHY_RX_DELAY_M 0x00003FFF /* Mask for delay from active assertion (wake up) */
+ /* to enable_receiver */
+
+#define AR_PHY_TIMING_CTRL4 0x9920 /* PHY */
+#define AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF_M 0x0000001F /* Mask for kcos_theta-1 for q correction */
+#define AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF_M 0x000007E0 /* Mask for sin_theta for i correction */
+#define AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF_S 5 /* Shift for sin_theta for i correction */
+#define AR_PHY_TIMING_CTRL4_IQCORR_ENABLE 0x00000800 /* enable IQ correction */
+#define AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX_M 0x0000F000 /* Mask for max number of samples (logarithmic) */
+#define AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX_S 12 /* Shift for max number of samples */
+#define AR_PHY_TIMING_CTRL4_DO_IQCAL 0x00010000 /* perform IQ calibration */
+
+#define AR_PHY_PAPD_PROBE 0x9930
+#define AR_PHY_PAPD_PROBE_POWERTX 0x00007E00
+#define AR_PHY_PAPD_PROBE_POWERTX_S 9
+#define AR_PHY_PAPD_PROBE_NEXT_TX 0x00008000 /* command to take next reading */
+#define AR_PHY_PAPD_PROBE_GAINF 0xFE000000
+#define AR_PHY_PAPD_PROBE_GAINF_S 25
+
+#define AR_PHY_POWER_TX_RATE1 0x9934
+#define AR_PHY_POWER_TX_RATE2 0x9938
+#define AR_PHY_POWER_TX_RATE_MAX 0x993c
+
+#define AR_PHY_FRAME_CTL 0x9944
+#define AR_PHY_FRAME_CTL_TX_CLIP 0x00000038
+#define AR_PHY_FRAME_CTL_TX_CLIP_S 3
+#define AR_PHY_FRAME_CTL_ERR_SERV 0x20000000
+#define AR_PHY_FRAME_CTL_ERR_SERV_S 29
+
+#define AR_PHY_RADAR_0 0x9954 /* PHY radar detection settings */
+#define AR_PHY_RADAR_0_ENA 0x00000001 /* Enable radar detection */
+
+#define AR_PHY_IQCAL_RES_PWR_MEAS_I 0x9c10 /*PHY IQ calibration results - power measurement for I */
+#define AR_PHY_IQCAL_RES_PWR_MEAS_Q 0x9c14 /*PHY IQ calibration results - power measurement for Q */
+#define AR_PHY_IQCAL_RES_IQ_CORR_MEAS 0x9c18 /*PHY IQ calibration results - IQ correlation measurement */
+#define AR_PHY_CURRENT_RSSI 0x9c1c /* rssi of current frame being received */
+
+#define AR5211_PHY_MODE 0xA200 /* Mode register */
+#define AR5211_PHY_MODE_OFDM 0x0 /* bit 0 = 0 for OFDM */
+#define AR5211_PHY_MODE_CCK 0x1 /* bit 0 = 1 for CCK */
+#define AR5211_PHY_MODE_RF5GHZ 0x0 /* bit 1 = 0 for 5 GHz */
+#define AR5211_PHY_MODE_RF2GHZ 0x2 /* bit 1 = 1 for 2.4 GHz */
+
+#endif /* _DEV_ATH_AR5211PHY_H */
diff --git a/sys/dev/ath/ath_hal/ar5211/ar5211reg.h b/sys/dev/ath/ath_hal/ar5211/ar5211reg.h
new file mode 100644
index 000000000000..54eab6aa9be2
--- /dev/null
+++ b/sys/dev/ath/ath_hal/ar5211/ar5211reg.h
@@ -0,0 +1,863 @@
+/*-
+ * SPDX-License-Identifier: ISC
+ *
+ * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
+ * Copyright (c) 2002-2006 Atheros Communications, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifndef _DEV_ATH_AR5211REG_H
+#define _DEV_ATH_AR5211REG_H
+
+/*
+ * Definitions for the Atheros AR5211/5311 chipset.
+ */
+
+/*
+ * Maui2/Spirit specific registers/fields are indicated by AR5311.
+ * Oahu specific registers/fields are indicated by AR5211.
+ */
+
+/* DMA Control and Interrupt Registers */
+#define AR_CR 0x0008 /* control register */
+#define AR_RXDP 0x000C /* receive queue descriptor pointer */
+#define AR_CFG 0x0014 /* configuration and status register */
+#define AR_IER 0x0024 /* Interrupt enable register */
+#define AR_RTSD0 0x0028 /* RTS Duration Parameters 0 */
+#define AR_RTSD1 0x002c /* RTS Duration Parameters 1 */
+#define AR_TXCFG 0x0030 /* tx DMA size config register */
+#define AR_RXCFG 0x0034 /* rx DMA size config register */
+#define AR5211_JUMBO_LAST 0x0038 /* Jumbo descriptor last address */
+#define AR_MIBC 0x0040 /* MIB control register */
+#define AR_TOPS 0x0044 /* timeout prescale count */
+#define AR_RXNPTO 0x0048 /* no frame received timeout */
+#define AR_TXNPTO 0x004C /* no frame trasmitted timeout */
+#define AR_RFGTO 0x0050 /* receive frame gap timeout */
+#define AR_RFCNT 0x0054 /* receive frame count limit */
+#define AR_MACMISC 0x0058 /* miscellaneous control/status */
+#define AR5311_QDCLKGATE 0x005c /* QCU/DCU clock gating control */
+#define AR_ISR 0x0080 /* Primary interrupt status register */
+#define AR_ISR_S0 0x0084 /* Secondary interrupt status reg 0 */
+#define AR_ISR_S1 0x0088 /* Secondary interrupt status reg 1 */
+#define AR_ISR_S2 0x008c /* Secondary interrupt status reg 2 */
+#define AR_ISR_S3 0x0090 /* Secondary interrupt status reg 3 */
+#define AR_ISR_S4 0x0094 /* Secondary interrupt status reg 4 */
+#define AR_IMR 0x00a0 /* Primary interrupt mask register */
+#define AR_IMR_S0 0x00a4 /* Secondary interrupt mask reg 0 */
+#define AR_IMR_S1 0x00a8 /* Secondary interrupt mask reg 1 */
+#define AR_IMR_S2 0x00ac /* Secondary interrupt mask reg 2 */
+#define AR_IMR_S3 0x00b0 /* Secondary interrupt mask reg 3 */
+#define AR_IMR_S4 0x00b4 /* Secondary interrupt mask reg 4 */
+#define AR_ISR_RAC 0x00c0 /* Primary interrupt status reg, */
+/* Shadow copies with read-and-clear access */
+#define AR_ISR_S0_S 0x00c4 /* Secondary interrupt status reg 0 */
+#define AR_ISR_S1_S 0x00c8 /* Secondary interrupt status reg 1 */
+#define AR_ISR_S2_S 0x00cc /* Secondary interrupt status reg 2 */
+#define AR_ISR_S3_S 0x00d0 /* Secondary interrupt status reg 3 */
+#define AR_ISR_S4_S 0x00d4 /* Secondary interrupt status reg 4 */
+
+#define AR_Q0_TXDP 0x0800 /* Transmit Queue descriptor pointer */
+#define AR_Q1_TXDP 0x0804 /* Transmit Queue descriptor pointer */
+#define AR_Q2_TXDP 0x0808 /* Transmit Queue descriptor pointer */
+#define AR_Q3_TXDP 0x080c /* Transmit Queue descriptor pointer */
+#define AR_Q4_TXDP 0x0810 /* Transmit Queue descriptor pointer */
+#define AR_Q5_TXDP 0x0814 /* Transmit Queue descriptor pointer */
+#define AR_Q6_TXDP 0x0818 /* Transmit Queue descriptor pointer */
+#define AR_Q7_TXDP 0x081c /* Transmit Queue descriptor pointer */
+#define AR_Q8_TXDP 0x0820 /* Transmit Queue descriptor pointer */
+#define AR_Q9_TXDP 0x0824 /* Transmit Queue descriptor pointer */
+#define AR_QTXDP(i) (AR_Q0_TXDP + ((i)<<2))
+
+#define AR_Q_TXE 0x0840 /* Transmit Queue enable */
+#define AR_Q_TXD 0x0880 /* Transmit Queue disable */
+
+#define AR_Q0_CBRCFG 0x08c0 /* CBR configuration */
+#define AR_Q1_CBRCFG 0x08c4 /* CBR configuration */
+#define AR_Q2_CBRCFG 0x08c8 /* CBR configuration */
+#define AR_Q3_CBRCFG 0x08cc /* CBR configuration */
+#define AR_Q4_CBRCFG 0x08d0 /* CBR configuration */
+#define AR_Q5_CBRCFG 0x08d4 /* CBR configuration */
+#define AR_Q6_CBRCFG 0x08d8 /* CBR configuration */
+#define AR_Q7_CBRCFG 0x08dc /* CBR configuration */
+#define AR_Q8_CBRCFG 0x08e0 /* CBR configuration */
+#define AR_Q9_CBRCFG 0x08e4 /* CBR configuration */
+#define AR_QCBRCFG(i) (AR_Q0_CBRCFG + ((i)<<2))
+
+#define AR_Q0_RDYTIMECFG 0x0900 /* ReadyTime configuration */
+#define AR_Q1_RDYTIMECFG 0x0904 /* ReadyTime configuration */
+#define AR_Q2_RDYTIMECFG 0x0908 /* ReadyTime configuration */
+#define AR_Q3_RDYTIMECFG 0x090c /* ReadyTime configuration */
+#define AR_Q4_RDYTIMECFG 0x0910 /* ReadyTime configuration */
+#define AR_Q5_RDYTIMECFG 0x0914 /* ReadyTime configuration */
+#define AR_Q6_RDYTIMECFG 0x0918 /* ReadyTime configuration */
+#define AR_Q7_RDYTIMECFG 0x091c /* ReadyTime configuration */
+#define AR_Q8_RDYTIMECFG 0x0920 /* ReadyTime configuration */
+#define AR_Q9_RDYTIMECFG 0x0924 /* ReadyTime configuration */
+#define AR_QRDYTIMECFG(i) (AR_Q0_RDYTIMECFG + ((i)<<2))
+
+#define AR_Q_ONESHOTARM_SC 0x0940 /* OneShotArm set control */
+#define AR_Q_ONESHOTARM_CC 0x0980 /* OneShotArm clear control */
+
+#define AR_Q0_MISC 0x09c0 /* Miscellaneous QCU settings */
+#define AR_Q1_MISC 0x09c4 /* Miscellaneous QCU settings */
+#define AR_Q2_MISC 0x09c8 /* Miscellaneous QCU settings */
+#define AR_Q3_MISC 0x09cc /* Miscellaneous QCU settings */
+#define AR_Q4_MISC 0x09d0 /* Miscellaneous QCU settings */
+#define AR_Q5_MISC 0x09d4 /* Miscellaneous QCU settings */
+#define AR_Q6_MISC 0x09d8 /* Miscellaneous QCU settings */
+#define AR_Q7_MISC 0x09dc /* Miscellaneous QCU settings */
+#define AR_Q8_MISC 0x09e0 /* Miscellaneous QCU settings */
+#define AR_Q9_MISC 0x09e4 /* Miscellaneous QCU settings */
+#define AR_QMISC(i) (AR_Q0_MISC + ((i)<<2))
+
+#define AR_Q0_STS 0x0a00 /* Miscellaneous QCU status */
+#define AR_Q1_STS 0x0a04 /* Miscellaneous QCU status */
+#define AR_Q2_STS 0x0a08 /* Miscellaneous QCU status */
+#define AR_Q3_STS 0x0a0c /* Miscellaneous QCU status */
+#define AR_Q4_STS 0x0a10 /* Miscellaneous QCU status */
+#define AR_Q5_STS 0x0a14 /* Miscellaneous QCU status */
+#define AR_Q6_STS 0x0a18 /* Miscellaneous QCU status */
+#define AR_Q7_STS 0x0a1c /* Miscellaneous QCU status */
+#define AR_Q8_STS 0x0a20 /* Miscellaneous QCU status */
+#define AR_Q9_STS 0x0a24 /* Miscellaneous QCU status */
+#define AR_QSTS(i) (AR_Q0_STS + ((i)<<2))
+
+#define AR_Q_RDYTIMESHDN 0x0a40 /* ReadyTimeShutdown status */
+#define AR_D0_QCUMASK 0x1000 /* QCU Mask */
+#define AR_D1_QCUMASK 0x1004 /* QCU Mask */
+#define AR_D2_QCUMASK 0x1008 /* QCU Mask */
+#define AR_D3_QCUMASK 0x100c /* QCU Mask */
+#define AR_D4_QCUMASK 0x1010 /* QCU Mask */
+#define AR_D5_QCUMASK 0x1014 /* QCU Mask */
+#define AR_D6_QCUMASK 0x1018 /* QCU Mask */
+#define AR_D7_QCUMASK 0x101c /* QCU Mask */
+#define AR_D8_QCUMASK 0x1020 /* QCU Mask */
+#define AR_D9_QCUMASK 0x1024 /* QCU Mask */
+#define AR_DQCUMASK(i) (AR_D0_QCUMASK + ((i)<<2))
+
+#define AR_D0_LCL_IFS 0x1040 /* DCU-specific IFS settings */
+#define AR_D1_LCL_IFS 0x1044 /* DCU-specific IFS settings */
+#define AR_D2_LCL_IFS 0x1048 /* DCU-specific IFS settings */
+#define AR_D3_LCL_IFS 0x104c /* DCU-specific IFS settings */
+#define AR_D4_LCL_IFS 0x1050 /* DCU-specific IFS settings */
+#define AR_D5_LCL_IFS 0x1054 /* DCU-specific IFS settings */
+#define AR_D6_LCL_IFS 0x1058 /* DCU-specific IFS settings */
+#define AR_D7_LCL_IFS 0x105c /* DCU-specific IFS settings */
+#define AR_D8_LCL_IFS 0x1060 /* DCU-specific IFS settings */
+#define AR_D9_LCL_IFS 0x1064 /* DCU-specific IFS settings */
+#define AR_DLCL_IFS(i) (AR_D0_LCL_IFS + ((i)<<2))
+
+#define AR_D0_RETRY_LIMIT 0x1080 /* Retry limits */
+#define AR_D1_RETRY_LIMIT 0x1084 /* Retry limits */
+#define AR_D2_RETRY_LIMIT 0x1088 /* Retry limits */
+#define AR_D3_RETRY_LIMIT 0x108c /* Retry limits */
+#define AR_D4_RETRY_LIMIT 0x1090 /* Retry limits */
+#define AR_D5_RETRY_LIMIT 0x1094 /* Retry limits */
+#define AR_D6_RETRY_LIMIT 0x1098 /* Retry limits */
+#define AR_D7_RETRY_LIMIT 0x109c /* Retry limits */
+#define AR_D8_RETRY_LIMIT 0x10a0 /* Retry limits */
+#define AR_D9_RETRY_LIMIT 0x10a4 /* Retry limits */
+#define AR_DRETRY_LIMIT(i) (AR_D0_RETRY_LIMIT + ((i)<<2))
+
+#define AR_D0_CHNTIME 0x10c0 /* ChannelTime settings */
+#define AR_D1_CHNTIME 0x10c4 /* ChannelTime settings */
+#define AR_D2_CHNTIME 0x10c8 /* ChannelTime settings */
+#define AR_D3_CHNTIME 0x10cc /* ChannelTime settings */
+#define AR_D4_CHNTIME 0x10d0 /* ChannelTime settings */
+#define AR_D5_CHNTIME 0x10d4 /* ChannelTime settings */
+#define AR_D6_CHNTIME 0x10d8 /* ChannelTime settings */
+#define AR_D7_CHNTIME 0x10dc /* ChannelTime settings */
+#define AR_D8_CHNTIME 0x10e0 /* ChannelTime settings */
+#define AR_D9_CHNTIME 0x10e4 /* ChannelTime settings */
+#define AR_DCHNTIME(i) (AR_D0_CHNTIME + ((i)<<2))
+
+#define AR_D0_MISC 0x1100 /* Misc DCU-specific settings */
+#define AR_D1_MISC 0x1104 /* Misc DCU-specific settings */
+#define AR_D2_MISC 0x1108 /* Misc DCU-specific settings */
+#define AR_D3_MISC 0x110c /* Misc DCU-specific settings */
+#define AR_D4_MISC 0x1110 /* Misc DCU-specific settings */
+#define AR_D5_MISC 0x1114 /* Misc DCU-specific settings */
+#define AR_D6_MISC 0x1118 /* Misc DCU-specific settings */
+#define AR_D7_MISC 0x111c /* Misc DCU-specific settings */
+#define AR_D8_MISC 0x1120 /* Misc DCU-specific settings */
+#define AR_D9_MISC 0x1124 /* Misc DCU-specific settings */
+#define AR_DMISC(i) (AR_D0_MISC + ((i)<<2))
+
+#define AR_D0_SEQNUM 0x1140 /* Frame seqnum control/status */
+#define AR_D1_SEQNUM 0x1144 /* Frame seqnum control/status */
+#define AR_D2_SEQNUM 0x1148 /* Frame seqnum control/status */
+#define AR_D3_SEQNUM 0x114c /* Frame seqnum control/status */
+#define AR_D4_SEQNUM 0x1150 /* Frame seqnum control/status */
+#define AR_D5_SEQNUM 0x1154 /* Frame seqnum control/status */
+#define AR_D6_SEQNUM 0x1158 /* Frame seqnum control/status */
+#define AR_D7_SEQNUM 0x115c /* Frame seqnum control/status */
+#define AR_D8_SEQNUM 0x1160 /* Frame seqnum control/status */
+#define AR_D9_SEQNUM 0x1164 /* Frame seqnum control/status */
+#define AR_DSEQNUM(i) (AR_D0_SEQNUM + ((i<<2)))
+
+/* MAC DCU-global IFS settings */
+#define AR_D_GBL_IFS_SIFS 0x1030 /* DCU global SIFS settings */
+#define AR_D_GBL_IFS_SLOT 0x1070 /* DC global slot interval */
+#define AR_D_GBL_IFS_EIFS 0x10b0 /* DCU global EIFS setting */
+#define AR_D_GBL_IFS_MISC 0x10f0 /* DCU global misc. IFS settings */
+#define AR_D_FPCTL 0x1230 /* DCU frame prefetch settings */
+#define AR_D_TXPSE 0x1270 /* DCU transmit pause control/status */
+#define AR_D_TXBLK_CMD 0x1038 /* DCU transmit filter cmd (w/only) */
+#define AR_D_TXBLK_DATA(i) (AR_D_TXBLK_CMD+(i)) /* DCU transmit filter data */
+#define AR_D_TXBLK_CLR 0x143c /* DCU clear tx filter (w/only) */
+#define AR_D_TXBLK_SET 0x147c /* DCU set tx filter (w/only) */
+
+#define AR_D_TXPSE 0x1270 /* DCU transmit pause control/status */
+
+#define AR_RC 0x4000 /* Warm reset control register */
+#define AR_SCR 0x4004 /* Sleep control register */
+#define AR_INTPEND 0x4008 /* Interrupt Pending register */
+#define AR_SFR 0x400C /* Sleep force register */
+#define AR_PCICFG 0x4010 /* PCI configuration register */
+#define AR_GPIOCR 0x4014 /* GPIO control register */
+#define AR_GPIODO 0x4018 /* GPIO data output access register */
+#define AR_GPIODI 0x401C /* GPIO data input access register */
+#define AR_SREV 0x4020 /* Silicon Revision register */
+
+#define AR_EEPROM_ADDR 0x6000 /* EEPROM address register (10 bit) */
+#define AR_EEPROM_DATA 0x6004 /* EEPROM data register (16 bit) */
+#define AR_EEPROM_CMD 0x6008 /* EEPROM command register */
+#define AR_EEPROM_STS 0x600c /* EEPROM status register */
+#define AR_EEPROM_CFG 0x6010 /* EEPROM configuration register */
+
+#define AR_STA_ID0 0x8000 /* station ID0 - low 32 bits */
+#define AR_STA_ID1 0x8004 /* station ID1 - upper 16 bits */
+#define AR_BSS_ID0 0x8008 /* BSSID low 32 bits */
+#define AR_BSS_ID1 0x800C /* BSSID upper 16 bits / AID */
+#define AR_SLOT_TIME 0x8010 /* Time-out after a collision */
+#define AR_TIME_OUT 0x8014 /* ACK & CTS time-out */
+#define AR_RSSI_THR 0x8018 /* RSSI warning & missed beacon threshold */
+#define AR_USEC 0x801c /* transmit latency register */
+#define AR_BEACON 0x8020 /* beacon control value/mode bits */
+#define AR_CFP_PERIOD 0x8024 /* CFP Interval (TU/msec) */
+#define AR_TIMER0 0x8028 /* Next beacon time (TU/msec) */
+#define AR_TIMER1 0x802c /* DMA beacon alert time (1/8 TU) */
+#define AR_TIMER2 0x8030 /* Software beacon alert (1/8 TU) */
+#define AR_TIMER3 0x8034 /* ATIM window time */
+#define AR_CFP_DUR 0x8038 /* maximum CFP duration in TU */
+#define AR_RX_FILTER 0x803C /* receive filter register */
+#define AR_MCAST_FIL0 0x8040 /* multicast filter lower 32 bits */
+#define AR_MCAST_FIL1 0x8044 /* multicast filter upper 32 bits */
+#define AR_DIAG_SW 0x8048 /* PCU control register */
+#define AR_TSF_L32 0x804c /* local clock lower 32 bits */
+#define AR_TSF_U32 0x8050 /* local clock upper 32 bits */
+#define AR_TST_ADDAC 0x8054 /* ADDAC test register */
+#define AR_DEF_ANTENNA 0x8058 /* default antenna register */
+
+#define AR_LAST_TSTP 0x8080 /* Time stamp of the last beacon rcvd */
+#define AR_NAV 0x8084 /* current NAV value */
+#define AR_RTS_OK 0x8088 /* RTS exchange success counter */
+#define AR_RTS_FAIL 0x808c /* RTS exchange failure counter */
+#define AR_ACK_FAIL 0x8090 /* ACK failure counter */
+#define AR_FCS_FAIL 0x8094 /* FCS check failure counter */
+#define AR_BEACON_CNT 0x8098 /* Valid beacon counter */
+
+#define AR_KEYTABLE_0 0x8800 /* Encryption key table */
+#define AR_KEYTABLE(n) (AR_KEYTABLE_0 + ((n)*32))
+
+#define AR_CR_RXE 0x00000004 /* Receive enable */
+#define AR_CR_RXD 0x00000020 /* Receive disable */
+#define AR_CR_SWI 0x00000040 /* One-shot software interrupt */
+#define AR_CR_BITS "\20\3RXE\6RXD\7SWI"
+
+#define AR_CFG_SWTD 0x00000001 /* byteswap tx descriptor words */
+#define AR_CFG_SWTB 0x00000002 /* byteswap tx data buffer words */
+#define AR_CFG_SWRD 0x00000004 /* byteswap rx descriptor words */
+#define AR_CFG_SWRB 0x00000008 /* byteswap rx data buffer words */
+#define AR_CFG_SWRG 0x00000010 /* byteswap register access data words */
+#define AR_CFG_AP_ADHOC_INDICATION 0x00000020 /* AP/adhoc indication (0-AP, 1-Adhoc) */
+#define AR_CFG_PHOK 0x00000100 /* PHY OK status */
+#define AR_CFG_EEBS 0x00000200 /* EEPROM busy */
+#define AR_CFG_CLK_GATE_DIS 0x00000400 /* Clock gating disable (Oahu only) */
+#define AR_CFG_PCI_MASTER_REQ_Q_THRESH_M 0x00060000 /* Mask of PCI core master request queue full threshold */
+#define AR_CFG_PCI_MASTER_REQ_Q_THRESH_S 17 /* Shift for PCI core master request queue full threshold */
+#define AR_CFG_BITS \
+ "\20\1SWTD\2SWTB\3SWRD\4SWRB\5SWRG\10PHYOK11EEBS"
+
+#define AR_IER_ENABLE 0x00000001 /* Global interrupt enable */
+#define AR_IER_DISABLE 0x00000000 /* Global interrupt disable */
+#define AR_IER_BITS "\20\1ENABLE"
+
+#define AR_RTSD0_RTS_DURATION_6_M 0x000000FF
+#define AR_RTSD0_RTS_DURATION_6_S 0
+#define AR_RTSD0_RTS_DURATION_9_M 0x0000FF00
+#define AR_RTSD0_RTS_DURATION_9_S 8
+#define AR_RTSD0_RTS_DURATION_12_M 0x00FF0000
+#define AR_RTSD0_RTS_DURATION_12_S 16
+#define AR_RTSD0_RTS_DURATION_18_M 0xFF000000
+#define AR_RTSD0_RTS_DURATION_18_S 24
+
+#define AR_RTSD0_RTS_DURATION_24_M 0x000000FF
+#define AR_RTSD0_RTS_DURATION_24_S 0
+#define AR_RTSD0_RTS_DURATION_36_M 0x0000FF00
+#define AR_RTSD0_RTS_DURATION_36_S 8
+#define AR_RTSD0_RTS_DURATION_48_M 0x00FF0000
+#define AR_RTSD0_RTS_DURATION_48_S 16
+#define AR_RTSD0_RTS_DURATION_54_M 0xFF000000
+#define AR_RTSD0_RTS_DURATION_54_S 24
+
+#define AR_DMASIZE_4B 0x00000000 /* DMA size 4 bytes (TXCFG + RXCFG) */
+#define AR_DMASIZE_8B 0x00000001 /* DMA size 8 bytes */
+#define AR_DMASIZE_16B 0x00000002 /* DMA size 16 bytes */
+#define AR_DMASIZE_32B 0x00000003 /* DMA size 32 bytes */
+#define AR_DMASIZE_64B 0x00000004 /* DMA size 64 bytes */
+#define AR_DMASIZE_128B 0x00000005 /* DMA size 128 bytes */
+#define AR_DMASIZE_256B 0x00000006 /* DMA size 256 bytes */
+#define AR_DMASIZE_512B 0x00000007 /* DMA size 512 bytes */
+
+#define AR_TXCFG_FTRIG_M 0x000003F0 /* Mask for Frame trigger level */
+#define AR_TXCFG_FTRIG_S 4 /* Shift for Frame trigger level */
+#define AR_TXCFG_FTRIG_IMMED 0x00000000 /* bytes in PCU TX FIFO before air */
+#define AR_TXCFG_FTRIG_64B 0x00000010 /* default */
+#define AR_TXCFG_FTRIG_128B 0x00000020
+#define AR_TXCFG_FTRIG_192B 0x00000030
+#define AR_TXCFG_FTRIG_256B 0x00000040 /* 5 bits total */
+#define AR_TXCFG_BITS "\20"
+
+#define AR5311_RXCFG_DEF_RX_ANTENNA 0x00000008 /* Default Receive Antenna */
+ /* Maui2/Spirit only - reserved on Oahu */
+#define AR_RXCFG_ZLFDMA 0x00000010 /* Enable DMA of zero-length frame */
+#define AR_RXCFG_EN_JUM 0x00000020 /* Enable jumbo rx descriptors */
+#define AR_RXCFG_WR_JUM 0x00000040 /* Wrap jumbo rx descriptors */
+
+#define AR_MIBC_COW 0x00000001 /* counter overflow warning */
+#define AR_MIBC_FMC 0x00000002 /* freeze MIB counters */
+#define AR_MIBC_CMC 0x00000004 /* clear MIB counters */
+#define AR_MIBC_MCS 0x00000008 /* MIB counter strobe, increment all */
+
+#define AR_TOPS_MASK 0x0000FFFF /* Mask for timeout prescale */
+
+#define AR_RXNPTO_MASK 0x000003FF /* Mask for no frame received timeout */
+
+#define AR_TXNPTO_MASK 0x000003FF /* Mask for no frame transmitted timeout */
+#define AR_TXNPTO_QCU_MASK 0x03FFFC00 /* Mask indicating the set of QCUs */
+ /* for which frame completions will cause */
+ /* a reset of the no frame transmitted timeout */
+
+#define AR_RPGTO_MASK 0x000003FF /* Mask for receive frame gap timeout */
+
+#define AR_RPCNT_MASK 0x0000001F /* Mask for receive frame count limit */
+
+#define AR_MACMISC_DMA_OBS_M 0x000001E0 /* Mask for DMA observation bus mux select */
+#define AR_MACMISC_DMA_OBS_S 5 /* Shift for DMA observation bus mux select */
+#define AR_MACMISC_MISC_OBS_M 0x00000E00 /* Mask for MISC observation bus mux select */
+#define AR_MACMISC_MISC_OBS_S 9 /* Shift for MISC observation bus mux select */
+#define AR_MACMISC_MAC_OBS_BUS_LSB_M 0x00007000 /* Mask for MAC observation bus mux select (lsb) */
+#define AR_MACMISC_MAC_OBS_BUS_LSB_S 12 /* Shift for MAC observation bus mux select (lsb) */
+#define AR_MACMISC_MAC_OBS_BUS_MSB_M 0x00038000 /* Mask for MAC observation bus mux select (msb) */
+#define AR_MACMISC_MAC_OBS_BUS_MSB_S 15 /* Shift for MAC observation bus mux select (msb) */
+
+ /* Maui2/Spirit only. */
+#define AR5311_QDCLKGATE_QCU_M 0x0000FFFF /* Mask for QCU clock disable */
+#define AR5311_QDCLKGATE_DCU_M 0x07FF0000 /* Mask for DCU clock disable */
+
+ /* Interrupt Status Registers */
+#define AR_ISR_RXOK 0x00000001 /* At least one frame received sans errors */
+#define AR_ISR_RXDESC 0x00000002 /* Receive interrupt request */
+#define AR_ISR_RXERR 0x00000004 /* Receive error interrupt */
+#define AR_ISR_RXNOPKT 0x00000008 /* No frame received within timeout clock */
+#define AR_ISR_RXEOL 0x00000010 /* Received descriptor empty interrupt */
+#define AR_ISR_RXORN 0x00000020 /* Receive FIFO overrun interrupt */
+#define AR_ISR_TXOK 0x00000040 /* Transmit okay interrupt */
+#define AR_ISR_TXDESC 0x00000080 /* Transmit interrupt request */
+#define AR_ISR_TXERR 0x00000100 /* Transmit error interrupt */
+#define AR_ISR_TXNOPKT 0x00000200 /* No frame transmitted interrupt */
+#define AR_ISR_TXEOL 0x00000400 /* Transmit descriptor empty interrupt */
+#define AR_ISR_TXURN 0x00000800 /* Transmit FIFO underrun interrupt */
+#define AR_ISR_MIB 0x00001000 /* MIB interrupt - see MIBC */
+#define AR_ISR_SWI 0x00002000 /* Software interrupt */
+#define AR_ISR_RXPHY 0x00004000 /* PHY receive error interrupt */
+#define AR_ISR_RXKCM 0x00008000 /* Key-cache miss interrupt */
+#define AR_ISR_SWBA 0x00010000 /* Software beacon alert interrupt */
+#define AR_ISR_BRSSI 0x00020000 /* Beacon threshold interrupt */
+#define AR_ISR_BMISS 0x00040000 /* Beacon missed interrupt */
+#define AR_ISR_HIUERR 0x00080000 /* An unexpected bus error has occurred */
+#define AR_ISR_BNR 0x00100000 /* Beacon not ready interrupt */
+#define AR_ISR_TIM 0x00800000 /* TIM interrupt */
+#define AR_ISR_GPIO 0x01000000 /* GPIO Interrupt */
+#define AR_ISR_QCBROVF 0x02000000 /* QCU CBR overflow interrupt */
+#define AR_ISR_QCBRURN 0x04000000 /* QCU CBR underrun interrupt */
+#define AR_ISR_QTRIG 0x08000000 /* QCU scheduling trigger interrupt */
+#define AR_ISR_RESV0 0xF0000000 /* Reserved */
+
+#define AR_ISR_S0_QCU_TXOK_M 0x000003FF /* Mask for TXOK (QCU 0-9) */
+#define AR_ISR_S0_QCU_TXDESC_M 0x03FF0000 /* Mask for TXDESC (QCU 0-9) */
+
+#define AR_ISR_S1_QCU_TXERR_M 0x000003FF /* Mask for TXERR (QCU 0-9) */
+#define AR_ISR_S1_QCU_TXEOL_M 0x03FF0000 /* Mask for TXEOL (QCU 0-9) */
+
+#define AR_ISR_S2_QCU_TXURN_M 0x000003FF /* Mask for TXURN (QCU 0-9) */
+#define AR_ISR_S2_MCABT 0x00010000 /* Master cycle abort interrupt */
+#define AR_ISR_S2_SSERR 0x00020000 /* SERR interrupt */
+#define AR_ISR_S2_DPERR 0x00040000 /* PCI bus parity error */
+#define AR_ISR_S2_RESV0 0xFFF80000 /* Reserved */
+
+#define AR_ISR_S3_QCU_QCBROVF_M 0x000003FF /* Mask for QCBROVF (QCU 0-9) */
+#define AR_ISR_S3_QCU_QCBRURN_M 0x03FF0000 /* Mask for QCBRURN (QCU 0-9) */
+
+#define AR_ISR_S4_QCU_QTRIG_M 0x000003FF /* Mask for QTRIG (QCU 0-9) */
+#define AR_ISR_S4_RESV0 0xFFFFFC00 /* Reserved */
+
+ /* Interrupt Mask Registers */
+#define AR_IMR_RXOK 0x00000001 /* At least one frame received sans errors */
+#define AR_IMR_RXDESC 0x00000002 /* Receive interrupt request */
+#define AR_IMR_RXERR 0x00000004 /* Receive error interrupt */
+#define AR_IMR_RXNOPKT 0x00000008 /* No frame received within timeout clock */
+#define AR_IMR_RXEOL 0x00000010 /* Received descriptor empty interrupt */
+#define AR_IMR_RXORN 0x00000020 /* Receive FIFO overrun interrupt */
+#define AR_IMR_TXOK 0x00000040 /* Transmit okay interrupt */
+#define AR_IMR_TXDESC 0x00000080 /* Transmit interrupt request */
+#define AR_IMR_TXERR 0x00000100 /* Transmit error interrupt */
+#define AR_IMR_TXNOPKT 0x00000200 /* No frame transmitted interrupt */
+#define AR_IMR_TXEOL 0x00000400 /* Transmit descriptor empty interrupt */
+#define AR_IMR_TXURN 0x00000800 /* Transmit FIFO underrun interrupt */
+#define AR_IMR_MIB 0x00001000 /* MIB interrupt - see MIBC */
+#define AR_IMR_SWI 0x00002000 /* Software interrupt */
+#define AR_IMR_RXPHY 0x00004000 /* PHY receive error interrupt */
+#define AR_IMR_RXKCM 0x00008000 /* Key-cache miss interrupt */
+#define AR_IMR_SWBA 0x00010000 /* Software beacon alert interrupt */
+#define AR_IMR_BRSSI 0x00020000 /* Beacon threshold interrupt */
+#define AR_IMR_BMISS 0x00040000 /* Beacon missed interrupt */
+#define AR_IMR_HIUERR 0x00080000 /* An unexpected bus error has occurred */
+#define AR_IMR_BNR 0x00100000 /* BNR interrupt */
+#define AR_IMR_TIM 0x00800000 /* TIM interrupt */
+#define AR_IMR_GPIO 0x01000000 /* GPIO Interrupt */
+#define AR_IMR_QCBROVF 0x02000000 /* QCU CBR overflow interrupt */
+#define AR_IMR_QCBRURN 0x04000000 /* QCU CBR underrun interrupt */
+#define AR_IMR_QTRIG 0x08000000 /* QCU scheduling trigger interrupt */
+#define AR_IMR_RESV0 0xF0000000 /* Reserved */
+
+#define AR_IMR_S0_QCU_TXOK 0x000003FF /* Mask for TXOK (QCU 0-9) */
+#define AR_IMR_S0_QCU_TXOK_S 0
+#define AR_IMR_S0_QCU_TXDESC 0x03FF0000 /* Mask for TXDESC (QCU 0-9) */
+#define AR_IMR_S0_QCU_TXDESC_S 16 /* Shift for TXDESC (QCU 0-9) */
+
+#define AR_IMR_S1_QCU_TXERR 0x000003FF /* Mask for TXERR (QCU 0-9) */
+#define AR_IMR_S1_QCU_TXERR_S 0
+#define AR_IMR_S1_QCU_TXEOL 0x03FF0000 /* Mask for TXEOL (QCU 0-9) */
+#define AR_IMR_S1_QCU_TXEOL_S 16 /* Shift for TXEOL (QCU 0-9) */
+
+#define AR_IMR_S2_QCU_TXURN 0x000003FF /* Mask for TXURN (QCU 0-9) */
+#define AR_IMR_S2_QCU_TXURN_S 0
+#define AR_IMR_S2_MCABT 0x00010000 /* Master cycle abort interrupt */
+#define AR_IMR_S2_SSERR 0x00020000 /* SERR interrupt */
+#define AR_IMR_S2_DPERR 0x00040000 /* PCI bus parity error */
+#define AR_IMR_S2_RESV0 0xFFF80000 /* Reserved */
+
+#define AR_IMR_S3_QCU_QCBROVF_M 0x000003FF /* Mask for QCBROVF (QCU 0-9) */
+#define AR_IMR_S3_QCU_QCBRURN_M 0x03FF0000 /* Mask for QCBRURN (QCU 0-9) */
+#define AR_IMR_S3_QCU_QCBRURN_S 16 /* Shift for QCBRURN (QCU 0-9) */
+
+#define AR_IMR_S4_QCU_QTRIG_M 0x000003FF /* Mask for QTRIG (QCU 0-9) */
+#define AR_IMR_S4_RESV0 0xFFFFFC00 /* Reserved */
+
+ /* Interrupt status registers (read-and-clear access, secondary shadow copies) */
+
+ /* QCU registers */
+#define AR_NUM_QCU 10 /* Only use QCU 0-9 for forward QCU compatibility */
+#define AR_QCU_0 0x0001
+#define AR_QCU_1 0x0002
+#define AR_QCU_2 0x0004
+#define AR_QCU_3 0x0008
+#define AR_QCU_4 0x0010
+#define AR_QCU_5 0x0020
+#define AR_QCU_6 0x0040
+#define AR_QCU_7 0x0080
+#define AR_QCU_8 0x0100
+#define AR_QCU_9 0x0200
+
+#define AR_Q_TXE_M 0x000003FF /* Mask for TXE (QCU 0-9) */
+
+#define AR_Q_TXD_M 0x000003FF /* Mask for TXD (QCU 0-9) */
+
+#define AR_Q_CBRCFG_CBR_INTERVAL 0x00FFFFFF /* Mask for CBR interval (us) */
+#define AR_Q_CBRCFG_CBR_INTERVAL_S 0 /* Shift for CBR interval */
+#define AR_Q_CBRCFG_CBR_OVF_THRESH 0xFF000000 /* Mask for CBR overflow threshold */
+#define AR_Q_CBRCFG_CBR_OVF_THRESH_S 24 /* Shift for " " " */
+
+#define AR_Q_RDYTIMECFG_INT 0x00FFFFFF /* CBR interval (us) */
+#define AR_Q_RDYTIMECFG_INT_S 0 /* Shift for ReadyTime Interval (us) */
+#define AR_Q_RDYTIMECFG_DURATION_M 0x00FFFFFF /* Mask for CBR interval (us) */
+#define AR_Q_RDYTIMECFG_EN 0x01000000 /* ReadyTime enable */
+#define AR_Q_RDYTIMECFG_RESV0 0xFE000000 /* Reserved */
+
+#define AR_Q_ONESHOTARM_SC_M 0x0000FFFF /* Mask for MAC_Q_ONESHOTARM_SC (QCU 0-15) */
+#define AR_Q_ONESHOTARM_SC_RESV0 0xFFFF0000 /* Reserved */
+
+#define AR_Q_ONESHOTARM_CC_M 0x0000FFFF /* Mask for MAC_Q_ONESHOTARM_CC (QCU 0-15) */
+#define AR_Q_ONESHOTARM_CC_RESV0 0xFFFF0000 /* Reserved */
+
+#define AR_Q_MISC_FSP_M 0x0000000F /* Mask for Frame Scheduling Policy */
+#define AR_Q_MISC_FSP_ASAP 0 /* ASAP */
+#define AR_Q_MISC_FSP_CBR 1 /* CBR */
+#define AR_Q_MISC_FSP_DBA_GATED 2 /* DMA Beacon Alert gated */
+#define AR_Q_MISC_FSP_TIM_GATED 3 /* TIM gated */
+#define AR_Q_MISC_FSP_BEACON_SENT_GATED 4 /* Beacon-sent-gated */
+#define AR_Q_MISC_ONE_SHOT_EN 0x00000010 /* OneShot enable */
+#define AR_Q_MISC_CBR_INCR_DIS1 0x00000020 /* Disable CBR expired counter
+ incr (empty q) */
+#define AR_Q_MISC_CBR_INCR_DIS0 0x00000040 /* Disable CBR expired counter
+ incr (empty beacon q) */
+#define AR_Q_MISC_BEACON_USE 0x00000080 /* Beacon use indication */
+#define AR_Q_MISC_CBR_EXP_CNTR_LIMIT 0x00000100 /* CBR expired counter limit enable */
+#define AR_Q_MISC_RDYTIME_EXP_POLICY 0x00000200 /* Enable TXE cleared on ReadyTime expired or VEOL */
+#define AR_Q_MISC_RESET_CBR_EXP_CTR 0x00000400 /* Reset CBR expired counter */
+#define AR_Q_MISC_DCU_EARLY_TERM_REQ 0x00000800 /* DCU frame early termination request control */
+#define AR_Q_MISC_RESV0 0xFFFFF000 /* Reserved */
+
+#define AR_Q_STS_PEND_FR_CNT_M 0x00000003 /* Mask for Pending Frame Count */
+#define AR_Q_STS_RESV0 0x000000FC /* Reserved */
+#define AR_Q_STS_CBR_EXP_CNT_M 0x0000FF00 /* Mask for CBR expired counter */
+#define AR_Q_STS_RESV1 0xFFFF0000 /* Reserved */
+
+#define AR_Q_RDYTIMESHDN_M 0x000003FF /* Mask for ReadyTimeShutdown status (QCU 0-9) */
+
+ /* DCU registers */
+#define AR_NUM_DCU 10 /* Only use 10 DCU's for forward QCU/DCU compatibility */
+#define AR_DCU_0 0x0001
+#define AR_DCU_1 0x0002
+#define AR_DCU_2 0x0004
+#define AR_DCU_3 0x0008
+#define AR_DCU_4 0x0010
+#define AR_DCU_5 0x0020
+#define AR_DCU_6 0x0040
+#define AR_DCU_7 0x0080
+#define AR_DCU_8 0x0100
+#define AR_DCU_9 0x0200
+
+#define AR_D_QCUMASK_M 0x000003FF /* Mask for QCU Mask (QCU 0-9) */
+#define AR_D_QCUMASK_RESV0 0xFFFFFC00 /* Reserved */
+
+#define AR_D_LCL_IFS_CWMIN 0x000003FF /* Mask for CW_MIN */
+#define AR_D_LCL_IFS_CWMIN_S 0 /* Shift for CW_MIN */
+#define AR_D_LCL_IFS_CWMAX 0x000FFC00 /* Mask for CW_MAX */
+#define AR_D_LCL_IFS_CWMAX_S 10 /* Shift for CW_MAX */
+#define AR_D_LCL_IFS_AIFS 0x0FF00000 /* Mask for AIFS */
+#define AR_D_LCL_IFS_AIFS_S 20 /* Shift for AIFS */
+#define AR_D_LCL_IFS_RESV0 0xF0000000 /* Reserved */
+
+#define AR_D_RETRY_LIMIT_FR_SH 0x0000000F /* Mask for frame short retry limit */
+#define AR_D_RETRY_LIMIT_FR_SH_S 0 /* Shift for frame short retry limit */
+#define AR_D_RETRY_LIMIT_FR_LG 0x000000F0 /* Mask for frame long retry limit */
+#define AR_D_RETRY_LIMIT_FR_LG_S 4 /* Shift for frame long retry limit */
+#define AR_D_RETRY_LIMIT_STA_SH 0x00003F00 /* Mask for station short retry limit */
+#define AR_D_RETRY_LIMIT_STA_SH_S 8 /* Shift for station short retry limit */
+#define AR_D_RETRY_LIMIT_STA_LG 0x000FC000 /* Mask for station short retry limit */
+#define AR_D_RETRY_LIMIT_STA_LG_S 14 /* Shift for station short retry limit */
+#define AR_D_RETRY_LIMIT_RESV0 0xFFF00000 /* Reserved */
+
+#define AR_D_CHNTIME_EN 0x00100000 /* ChannelTime enable */
+#define AR_D_CHNTIME_RESV0 0xFFE00000 /* Reserved */
+#define AR_D_CHNTIME_DUR 0x000FFFFF /* Mask for ChannelTime duration (us) */
+#define AR_D_CHNTIME_DUR_S 0 /* Shift for ChannelTime duration */
+
+#define AR_D_MISC_BKOFF_THRESH_M 0x000007FF /* Mask for Backoff threshold setting */
+#define AR_D_MISC_FRAG_BKOFF_EN 0x00000200 /* Backoff during a frag burst */
+#define AR_D_MISC_HCF_POLL_EN 0x00000800 /* HFC poll enable */
+#define AR_D_MISC_BKOFF_PERSISTENCE 0x00001000 /* Backoff persistence factor setting */
+#define AR_D_MISC_FR_PREFETCH_EN 0x00002000 /* Frame prefetch enable */
+#define AR_D_MISC_VIR_COL_HANDLING_M 0x0000C000 /* Mask for Virtual collision handling policy */
+#define AR_D_MISC_VIR_COL_HANDLING_NORMAL 0 /* Normal */
+#define AR_D_MISC_VIR_COL_HANDLING_MODIFIED 1 /* Modified */
+#define AR_D_MISC_VIR_COL_HANDLING_IGNORE 2 /* Ignore */
+#define AR_D_MISC_BEACON_USE 0x00010000 /* Beacon use indication */
+#define AR_D_MISC_ARB_LOCKOUT_CNTRL 0x00060000 /* Mask for DCU arbiter lockout control */
+#define AR_D_MISC_ARB_LOCKOUT_CNTRL_S 17 /* Shift for DCU arbiter lockout control */
+#define AR_D_MISC_ARB_LOCKOUT_CNTRL_NONE 0 /* No lockout */
+#define AR_D_MISC_ARB_LOCKOUT_CNTRL_INTRA_FR 1 /* Intra-frame */
+#define AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL 2 /* Global */
+#define AR_D_MISC_ARB_LOCKOUT_IGNORE 0x00080000 /* DCU arbiter lockout ignore control */
+#define AR_D_MISC_SEQ_NUM_INCR_DIS 0x00100000 /* Sequence number increment disable */
+#define AR_D_MISC_POST_FR_BKOFF_DIS 0x00200000 /* Post-frame backoff disable */
+#define AR_D_MISC_VIRT_COLL_POLICY 0x00400000 /* Virtual coll. handling policy */
+#define AR_D_MISC_BLOWN_IFS_POLICY 0x00800000 /* Blown IFS handling policy */
+#define AR5311_D_MISC_SEQ_NUM_CONTROL 0x01000000 /* Sequence Number local or global */
+ /* Maui2/Spirit only, reserved on Oahu */
+#define AR_D_MISC_RESV0 0xFE000000 /* Reserved */
+
+#define AR_D_SEQNUM_M 0x00000FFF /* Mask for value of sequence number */
+#define AR_D_SEQNUM_RESV0 0xFFFFF000 /* Reserved */
+
+#define AR_D_GBL_IFS_MISC_LFSR_SLICE_SEL 0x00000007 /* Mask forLFSR slice select */
+#define AR_D_GBL_IFS_MISC_TURBO_MODE 0x00000008 /* Turbo mode indication */
+#define AR_D_GBL_IFS_MISC_SIFS_DURATION_USEC 0x000003F0 /* Mask for SIFS duration (us) */
+#define AR_D_GBL_IFS_MISC_USEC_DURATION 0x000FFC00 /* Mask for microsecond duration */
+#define AR_D_GBL_IFS_MISC_DCU_ARBITER_DLY 0x00300000 /* Mask for DCU arbiter delay */
+#define AR_D_GBL_IFS_MISC_RESV0 0xFFC00000 /* Reserved */
+
+/* Oahu only */
+#define AR_D_TXPSE_CTRL_M 0x000003FF /* Mask of DCUs to pause (DCUs 0-9) */
+#define AR_D_TXPSE_RESV0 0x0000FC00 /* Reserved */
+#define AR_D_TXPSE_STATUS 0x00010000 /* Transmit pause status */
+#define AR_D_TXPSE_RESV1 0xFFFE0000 /* Reserved */
+
+ /* DMA & PCI Registers in PCI space (usable during sleep) */
+#define AR_RC_MAC 0x00000001 /* MAC reset */
+#define AR_RC_BB 0x00000002 /* Baseband reset */
+#define AR_RC_RESV0 0x00000004 /* Reserved */
+#define AR_RC_RESV1 0x00000008 /* Reserved */
+#define AR_RC_PCI 0x00000010 /* PCI-core reset */
+#define AR_RC_BITS "\20\1MAC\2BB\3RESV0\4RESV1\5RPCI"
+
+#define AR_SCR_SLDUR 0x0000ffff /* sleep duration mask, units of 128us */
+#define AR_SCR_SLDUR_S 0
+#define AR_SCR_SLE 0x00030000 /* sleep enable mask */
+#define AR_SCR_SLE_S 16 /* sleep enable bits shift */
+/*
+ * The previous values for the following three defines were:
+ *
+ * AR_SCR_SLE_WAKE 0x00000000
+ * AR_SCR_SLE_SLP 0x00010000
+ * AR_SCR_SLE_NORM 0x00020000
+ *
+ * However, these have been pre-shifted with AR_SCR_SLE_S. The
+ * OS_REG_READ() macro would attempt to shift them again, effectively
+ * shifting out any of the set bits completely.
+ */
+#define AR_SCR_SLE_WAKE 0 /* force wake */
+#define AR_SCR_SLE_SLP 1 /* force sleep */
+#define AR_SCR_SLE_NORM 2 /* sleep logic normal operation */
+#define AR_SCR_SLE_UNITS 0x00000008 /* SCR units/TU */
+#define AR_SCR_BITS "\20\20SLE_SLP\21SLE"
+
+#define AR_INTPEND_TRUE 0x00000001 /* interrupt pending */
+#define AR_INTPEND_BITS "\20\1IP"
+
+#define AR_SFR_SLEEP 0x00000001 /* force sleep */
+
+#define AR_PCICFG_CLKRUNEN 0x00000004 /* enable PCI CLKRUN function */
+#define AR_PCICFG_EEPROM_SIZE_M 0x00000018 /* Mask for EEPROM size */
+#define AR_PCICFG_EEPROM_SIZE_S 3 /* Mask for EEPROM size */
+#define AR_PCICFG_EEPROM_SIZE_4K 0 /* EEPROM size 4 Kbit */
+#define AR_PCICFG_EEPROM_SIZE_8K 1 /* EEPROM size 8 Kbit */
+#define AR_PCICFG_EEPROM_SIZE_16K 2 /* EEPROM size 16 Kbit */
+#define AR_PCICFG_EEPROM_SIZE_FAILED 3 /* Failure */
+#define AR_PCICFG_LEDCTL 0x00000060 /* LED control Status */
+#define AR_PCICFG_LEDCTL_NONE 0x00000000 /* STA is not associated or trying */
+#define AR_PCICFG_LEDCTL_PEND 0x00000020 /* STA is trying to associate */
+#define AR_PCICFG_LEDCTL_ASSOC 0x00000040 /* STA is associated */
+#define AR_PCICFG_PCI_BUS_SEL_M 0x00000380 /* Mask for PCI observation bus mux select */
+#define AR_PCICFG_DIS_CBE_FIX 0x00000400 /* Disable fix for bad PCI CBE# generation */
+#define AR_PCICFG_SL_INTEN 0x00000800 /* enable interrupt line assertion when asleep */
+#define AR_PCICFG_RESV0 0x00001000 /* Reserved */
+#define AR_PCICFG_SL_INPEN 0x00002000 /* Force asleep when an interrupt is pending */
+#define AR_PCICFG_RESV1 0x0000C000 /* Reserved */
+#define AR_PCICFG_SPWR_DN 0x00010000 /* mask for sleep/awake indication */
+#define AR_PCICFG_LEDMODE 0x000E0000 /* LED mode */
+#define AR_PCICFG_LEDMODE_PROP 0x00000000 /* Blink prop to filtered tx/rx */
+#define AR_PCICFG_LEDMODE_RPROP 0x00020000 /* Blink prop to unfiltered tx/rx */
+#define AR_PCICFG_LEDMODE_SPLIT 0x00040000 /* Blink power for tx/net for rx */
+#define AR_PCICFG_LEDMODE_RAND 0x00060000 /* Blink randomly */
+#define AR_PCICFG_LEDBLINK 0x00700000 /* LED blink threshold select */
+#define AR_PCICFG_LEDBLINK_S 20
+#define AR_PCICFG_LEDSLOW 0x00800000 /* LED slowest blink rate mode */
+#define AR_PCICFG_RESV2 0xFF000000 /* Reserved */
+#define AR_PCICFG_BITS "\20\3CLKRUNEN\13SL_INTEN"
+
+#define AR_GPIOCR_CR_SHIFT 2 /* Each CR is 2 bits */
+#define AR_GPIOCR_0_CR_N 0x00000000 /* Input only mode for GPIODO[0] */
+#define AR_GPIOCR_0_CR_0 0x00000001 /* Output only if GPIODO[0] = 0 */
+#define AR_GPIOCR_0_CR_1 0x00000002 /* Output only if GPIODO[0] = 1 */
+#define AR_GPIOCR_0_CR_A 0x00000003 /* Always output */
+#define AR_GPIOCR_1_CR_N 0x00000000 /* Input only mode for GPIODO[1] */
+#define AR_GPIOCR_1_CR_0 0x00000004 /* Output only if GPIODO[1] = 0 */
+#define AR_GPIOCR_1_CR_1 0x00000008 /* Output only if GPIODO[1] = 1 */
+#define AR_GPIOCR_1_CR_A 0x0000000C /* Always output */
+#define AR_GPIOCR_2_CR_N 0x00000000 /* Input only mode for GPIODO[2] */
+#define AR_GPIOCR_2_CR_0 0x00000010 /* Output only if GPIODO[2] = 0 */
+#define AR_GPIOCR_2_CR_1 0x00000020 /* Output only if GPIODO[2] = 1 */
+#define AR_GPIOCR_2_CR_A 0x00000030 /* Always output */
+#define AR_GPIOCR_3_CR_N 0x00000000 /* Input only mode for GPIODO[3] */
+#define AR_GPIOCR_3_CR_0 0x00000040 /* Output only if GPIODO[3] = 0 */
+#define AR_GPIOCR_3_CR_1 0x00000080 /* Output only if GPIODO[3] = 1 */
+#define AR_GPIOCR_3_CR_A 0x000000C0 /* Always output */
+#define AR_GPIOCR_4_CR_N 0x00000000 /* Input only mode for GPIODO[4] */
+#define AR_GPIOCR_4_CR_0 0x00000100 /* Output only if GPIODO[4] = 0 */
+#define AR_GPIOCR_4_CR_1 0x00000200 /* Output only if GPIODO[4] = 1 */
+#define AR_GPIOCR_4_CR_A 0x00000300 /* Always output */
+#define AR_GPIOCR_5_CR_N 0x00000000 /* Input only mode for GPIODO[5] */
+#define AR_GPIOCR_5_CR_0 0x00000400 /* Output only if GPIODO[5] = 0 */
+#define AR_GPIOCR_5_CR_1 0x00000800 /* Output only if GPIODO[5] = 1 */
+#define AR_GPIOCR_5_CR_A 0x00000C00 /* Always output */
+#define AR_GPIOCR_INT_SHIFT 12 /* Interrupt select field shifter */
+#define AR_GPIOCR_INT_MASK 0x00007000 /* Interrupt select field mask */
+#define AR_GPIOCR_INT_SEL0 0x00000000 /* Select Interrupt Pin GPIO_0 */
+#define AR_GPIOCR_INT_SEL1 0x00001000 /* Select Interrupt Pin GPIO_1 */
+#define AR_GPIOCR_INT_SEL2 0x00002000 /* Select Interrupt Pin GPIO_2 */
+#define AR_GPIOCR_INT_SEL3 0x00003000 /* Select Interrupt Pin GPIO_3 */
+#define AR_GPIOCR_INT_SEL4 0x00004000 /* Select Interrupt Pin GPIO_4 */
+#define AR_GPIOCR_INT_SEL5 0x00005000 /* Select Interrupt Pin GPIO_5 */
+#define AR_GPIOCR_INT_ENA 0x00008000 /* Enable GPIO Interrupt */
+#define AR_GPIOCR_INT_SELL 0x00000000 /* Generate Interrupt if selected pin is low */
+#define AR_GPIOCR_INT_SELH 0x00010000 /* Generate Interrupt if selected pin is high */
+
+#define AR_SREV_ID_M 0x000000FF /* Mask to read SREV info */
+#define AR_PCICFG_EEPROM_SIZE_16K 2 /* EEPROM size 16 Kbit */
+#define AR_SREV_ID_S 4 /* Major Rev Info */
+#define AR_SREV_REVISION_M 0x0000000F /* Chip revision level */
+#define AR_SREV_FPGA 1
+#define AR_SREV_D2PLUS 2
+#define AR_SREV_D2PLUS_MS 3 /* metal spin */
+#define AR_SREV_CRETE 4
+#define AR_SREV_CRETE_MS 5 /* FCS metal spin */
+#define AR_SREV_CRETE_MS23 7 /* 2.3 metal spin (6 skipped) */
+#define AR_SREV_CRETE_23 8 /* 2.3 full tape out */
+#define AR_SREV_VERSION_M 0x000000F0 /* Chip version indication */
+#define AR_SREV_VERSION_CRETE 0
+#define AR_SREV_VERSION_MAUI_1 1
+#define AR_SREV_VERSION_MAUI_2 2
+#define AR_SREV_VERSION_SPIRIT 3
+#define AR_SREV_VERSION_OAHU 4
+#define AR_SREV_OAHU_ES 0 /* Engineering Sample */
+#define AR_SREV_OAHU_PROD 2 /* Production */
+
+#define RAD5_SREV_MAJOR 0x10 /* All current supported ar5211 5 GHz radios are rev 0x10 */
+#define RAD5_SREV_PROD 0x15 /* Current production level radios */
+#define RAD2_SREV_MAJOR 0x20 /* All current supported ar5211 2 GHz radios are rev 0x10 */
+
+ /* EEPROM Registers in the MAC */
+#define AR_EEPROM_CMD_READ 0x00000001
+#define AR_EEPROM_CMD_WRITE 0x00000002
+#define AR_EEPROM_CMD_RESET 0x00000004
+
+#define AR_EEPROM_STS_READ_ERROR 0x00000001
+#define AR_EEPROM_STS_READ_COMPLETE 0x00000002
+#define AR_EEPROM_STS_WRITE_ERROR 0x00000004
+#define AR_EEPROM_STS_WRITE_COMPLETE 0x00000008
+
+#define AR_EEPROM_CFG_SIZE_M 0x00000003 /* Mask for EEPROM size determination override */
+#define AR_EEPROM_CFG_SIZE_AUTO 0
+#define AR_EEPROM_CFG_SIZE_4KBIT 1
+#define AR_EEPROM_CFG_SIZE_8KBIT 2
+#define AR_EEPROM_CFG_SIZE_16KBIT 3
+#define AR_EEPROM_CFG_DIS_WAIT_WRITE_COMPL 0x00000004 /* Disable wait for write completion */
+#define AR_EEPROM_CFG_CLOCK_M 0x00000018 /* Mask for EEPROM clock rate control */
+#define AR_EEPROM_CFG_CLOCK_S 3 /* Shift for EEPROM clock rate control */
+#define AR_EEPROM_CFG_CLOCK_156KHZ 0
+#define AR_EEPROM_CFG_CLOCK_312KHZ 1
+#define AR_EEPROM_CFG_CLOCK_625KHZ 2
+#define AR_EEPROM_CFG_RESV0 0x000000E0 /* Reserved */
+#define AR_EEPROM_CFG_PROT_KEY_M 0x00FFFF00 /* Mask for EEPROM protection key */
+#define AR_EEPROM_CFG_PROT_KEY_S 8 /* Shift for EEPROM protection key */
+#define AR_EEPROM_CFG_EN_L 0x01000000 /* EPRM_EN_L setting */
+
+ /* MAC PCU Registers */
+#define AR_STA_ID1_SADH_MASK 0x0000FFFF /* Mask for upper 16 bits of MAC addr */
+#define AR_STA_ID1_STA_AP 0x00010000 /* Device is AP */
+#define AR_STA_ID1_ADHOC 0x00020000 /* Device is ad-hoc */
+#define AR_STA_ID1_PWR_SAV 0x00040000 /* Power save reporting in self-generated frames */
+#define AR_STA_ID1_KSRCHDIS 0x00080000 /* Key search disable */
+#define AR_STA_ID1_PCF 0x00100000 /* Observe PCF */
+#define AR_STA_ID1_DEFAULT_ANTENNA 0x00200000 /* Use default antenna */
+#define AR_STA_ID1_DESC_ANTENNA 0x00400000 /* Update default antenna w/ TX antenna */
+#define AR_STA_ID1_RTS_USE_DEF 0x00800000 /* Use default antenna to send RTS */
+#define AR_STA_ID1_ACKCTS_6MB 0x01000000 /* Use 6Mb/s rate for ACK & CTS */
+#define AR_STA_ID1_BASE_RATE_11B 0x02000000 /* Use 11b base rate for ACK & CTS */
+#define AR_STA_ID1_BITS \
+ "\20\20AP\21ADHOC\22PWR_SAV\23KSRCHDIS\25PCF"
+
+#define AR_BSS_ID1_U16_M 0x0000FFFF /* Mask for upper 16 bits of BSSID */
+#define AR_BSS_ID1_AID_M 0xFFFF0000 /* Mask for association ID */
+#define AR_BSS_ID1_AID_S 16 /* Shift for association ID */
+
+#define AR_SLOT_TIME_MASK 0x000007FF /* Slot time mask */
+
+#define AR_TIME_OUT_ACK 0x00001FFF /* Mask for ACK time-out */
+#define AR_TIME_OUT_ACK_S 0 /* Shift for ACK time-out */
+#define AR_TIME_OUT_CTS 0x1FFF0000 /* Mask for CTS time-out */
+#define AR_TIME_OUT_CTS_S 16 /* Shift for CTS time-out */
+
+#define AR_RSSI_THR_MASK 0x000000FF /* Mask for Beacon RSSI warning threshold */
+#define AR_RSSI_THR_BM_THR 0x0000FF00 /* Mask for Missed beacon threshold */
+#define AR_RSSI_THR_BM_THR_S 8 /* Shift for Missed beacon threshold */
+
+#define AR_USEC_M 0x0000007F /* Mask for clock cycles in 1 usec */
+#define AR_USEC_32_M 0x00003F80 /* Mask for number of 32MHz clock cycles in 1 usec */
+#define AR_USEC_32_S 7 /* Shift for number of 32MHz clock cycles in 1 usec */
+/*
+ * Tx/Rx latencies are to signal start and are in usecs.
+ *
+ * NOTE: AR5211/AR5311 difference: on Oahu, the TX latency field
+ * has increased from 6 bits to 9 bits. The RX latency field
+ * is unchanged, but is shifted over 3 bits.
+ */
+#define AR5311_USEC_TX_LAT_M 0x000FC000 /* Tx latency */
+#define AR5311_USEC_TX_LAT_S 14
+#define AR5311_USEC_RX_LAT_M 0x03F00000 /* Rx latency */
+#define AR5311_USEC_RX_LAT_S 20
+
+#define AR5211_USEC_TX_LAT_M 0x007FC000 /* Tx latency */
+#define AR5211_USEC_TX_LAT_S 14
+#define AR5211_USEC_RX_LAT_M 0x1F800000 /* Rx latency */
+#define AR5211_USEC_RX_LAT_S 23
+
+#define AR_BEACON_PERIOD 0x0000FFFF /* Beacon period in TU/msec */
+#define AR_BEACON_PERIOD_S 0 /* Byte offset of PERIOD start*/
+#define AR_BEACON_TIM 0x007F0000 /* Byte offset of TIM start */
+#define AR_BEACON_TIM_S 16 /* Byte offset of TIM start */
+#define AR_BEACON_EN 0x00800000 /* beacon enable */
+#define AR_BEACON_RESET_TSF 0x01000000 /* Clears TSF to 0 */
+#define AR_BEACON_BITS "\20\27ENABLE\30RESET_TSF"
+
+#define AR_RX_FILTER_ALL 0x00000000 /* Disallow all frames */
+#define AR_RX_UCAST 0x00000001 /* Allow unicast frames */
+#define AR_RX_MCAST 0x00000002 /* Allow multicast frames */
+#define AR_RX_BCAST 0x00000004 /* Allow broadcast frames */
+#define AR_RX_CONTROL 0x00000008 /* Allow control frames */
+#define AR_RX_BEACON 0x00000010 /* Allow beacon frames */
+#define AR_RX_PROM 0x00000020 /* Promiscuous mode */
+#define AR_RX_PHY_ERR 0x00000040 /* Allow all phy errors */
+#define AR_RX_PHY_RADAR 0x00000080 /* Allow radar phy errors */
+#define AR_RX_FILTER_BITS \
+ "\20\1UCAST\2MCAST\3BCAST\4CONTROL\5BEACON\6PROMISC\7PHY_ERR\10PHY_RADAR"
+
+#define AR_DIAG_SW_CACHE_ACK 0x00000001 /* disable ACK if no valid key*/
+#define AR_DIAG_SW_DIS_ACK 0x00000002 /* disable ACK generation */
+#define AR_DIAG_SW_DIS_CTS 0x00000004 /* disable CTS generation */
+#define AR_DIAG_SW_DIS_ENCRYPT 0x00000008 /* disable encryption */
+#define AR_DIAG_SW_DIS_DECRYPT 0x00000010 /* disable decryption */
+#define AR_DIAG_SW_DIS_RX 0x00000020 /* disable receive */
+#define AR_DIAG_SW_CORR_FCS 0x00000080 /* corrupt FCS */
+#define AR_DIAG_SW_CHAN_INFO 0x00000100 /* dump channel info */
+#define AR_DIAG_SW_EN_SCRAMSD 0x00000200 /* enable fixed scrambler seed*/
+#define AR5311_DIAG_SW_USE_ECO 0x00000400 /* "super secret" use ECO enable bit */
+#define AR_DIAG_SW_SCRAM_SEED_M 0x0001FC00 /* Fixed scrambler seed mask */
+#define AR_DIAG_SW_SCRAM_SEED_S 10 /* Fixed scrambler seed shfit */
+#define AR_DIAG_SW_FRAME_NV0 0x00020000 /* accept frames of non-zero protocol version */
+#define AR_DIAG_SW_OBS_PT_SEL_M 0x000C0000 /* Observation point select */
+#define AR_DIAG_SW_OBS_PT_SEL_S 18 /* Observation point select */
+#define AR_DIAG_SW_BITS \
+ "\20\1DIS_CACHE_ACK\2DIS_ACK\3DIS_CTS\4DIS_ENC\5DIS_DEC\6DIS_RX"\
+ "\11CORR_FCS\12CHAN_INFO\13EN_SCRAM_SEED\14USE_ECO\24FRAME_NV0"
+
+#define AR_KEYTABLE_KEY0(n) (AR_KEYTABLE(n) + 0) /* key bit 0-31 */
+#define AR_KEYTABLE_KEY1(n) (AR_KEYTABLE(n) + 4) /* key bit 32-47 */
+#define AR_KEYTABLE_KEY2(n) (AR_KEYTABLE(n) + 8) /* key bit 48-79 */
+#define AR_KEYTABLE_KEY3(n) (AR_KEYTABLE(n) + 12) /* key bit 80-95 */
+#define AR_KEYTABLE_KEY4(n) (AR_KEYTABLE(n) + 16) /* key bit 96-127 */
+#define AR_KEYTABLE_TYPE(n) (AR_KEYTABLE(n) + 20) /* key type */
+#define AR_KEYTABLE_TYPE_40 0x00000000 /* WEP 40 bit key */
+#define AR_KEYTABLE_TYPE_104 0x00000001 /* WEP 104 bit key */
+#define AR_KEYTABLE_TYPE_128 0x00000003 /* WEP 128 bit key */
+#define AR_KEYTABLE_TYPE_AES 0x00000005 /* AES 128 bit key */
+#define AR_KEYTABLE_TYPE_CLR 0x00000007 /* no encryption */
+#define AR_KEYTABLE_MAC0(n) (AR_KEYTABLE(n) + 24) /* MAC address 1-32 */
+#define AR_KEYTABLE_MAC1(n) (AR_KEYTABLE(n) + 28) /* MAC address 33-47 */
+#define AR_KEYTABLE_VALID 0x00008000 /* key and MAC address valid */
+
+#endif /* _DEV_ATH_AR5211REG_H */
diff --git a/sys/dev/ath/ath_hal/ar5211/boss.ini b/sys/dev/ath/ath_hal/ar5211/boss.ini
new file mode 100644
index 000000000000..5619d01c4a4b
--- /dev/null
+++ b/sys/dev/ath/ath_hal/ar5211/boss.ini
@@ -0,0 +1,356 @@
+/*
+ * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
+ * Copyright (c) 2002-2006 Atheros Communications, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/* Auto Generated PCI Register Writes. Created: 09/12/02 */
+
+static const uint32_t ar5211Modes[][5] = {
+ { 0x00000030, 0x00000015, 0x00000015, 0x0000001d, 0x00000015 },
+ { 0x00001040, 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f },
+ { 0x00001044, 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f },
+ { 0x00001048, 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f },
+ { 0x0000104c, 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f },
+ { 0x00001050, 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f },
+ { 0x00001054, 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f },
+ { 0x00001058, 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f },
+ { 0x0000105c, 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f },
+ { 0x00001060, 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f },
+ { 0x00001064, 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f },
+ { 0x00001070, 0x00000168, 0x000001e0, 0x000001b8, 0x00000168 },
+ { 0x00001030, 0x00000230, 0x000001e0, 0x000000b0, 0x00000230 },
+ { 0x000010b0, 0x00000d98, 0x00001180, 0x00001f48, 0x00000d98 },
+ { 0x000010f0, 0x0000a0e0, 0x00014068, 0x00005880, 0x0000a0e0 },
+ { 0x00008014, 0x04000400, 0x08000800, 0x20003000, 0x04000400 },
+ { 0x0000801c, 0x0e8d8fa7, 0x0e8d8fcf, 0x01608f95, 0x0e8d8fa7 },
+ { 0x00009804, 0x00000000, 0x00000003, 0x00000000, 0x00000000 },
+ { 0x00009820, 0x02020200, 0x02020200, 0x02010200, 0x02020200 },
+ { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000707, 0x00000e0e },
+ { 0x00009828, 0x0a020001, 0x0a020001, 0x05010000, 0x0a020001 },
+ { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e },
+ { 0x00009838, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b },
+ { 0x00009844, 0x1372169c, 0x137216a5, 0x137216a8, 0x1372169c },
+ { 0x00009848, 0x0018ba67, 0x0018ba67, 0x0018ba69, 0x0018ba69 },
+ { 0x00009850, 0x0c28b4e0, 0x0c28b4e0, 0x0c28b4e0, 0x0c28b4e0 },
+ { 0x00009858, 0x7e800d2e, 0x7e800d2e, 0x7ec00d2e, 0x7e800d2e },
+ { 0x0000985c, 0x31375d5e, 0x31375d5e, 0x313a5d5e, 0x31375d5e },
+ { 0x00009860, 0x0000bd10, 0x0000bd10, 0x0000bd38, 0x0000bd10 },
+ { 0x00009864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
+ { 0x00009914, 0x00002710, 0x00002710, 0x0000157c, 0x00002710 },
+ { 0x00009918, 0x00000190, 0x00000190, 0x00000084, 0x00000190 },
+ { 0x00009944, 0x6fe01020, 0x6fe01020, 0x6fe00920, 0x6fe01020 },
+ { 0x0000a180, 0x05ff14ff, 0x05ff14ff, 0x05ff14ff, 0x05ff19ff },
+ { 0x000098d4, 0x00000010, 0x00000014, 0x00000010, 0x00000010 },
+};
+
+static const uint32_t ar5211Common[][2] = {
+ { 0x0000000c, 0x00000000 },
+ { 0x00000028, 0x84849c9c },
+ { 0x0000002c, 0x7c7c7c7c },
+ { 0x00000034, 0x00000005 },
+ { 0x00000040, 0x00000000 },
+ { 0x00000044, 0x00000008 },
+ { 0x00000048, 0x00000008 },
+ { 0x0000004c, 0x00000010 },
+ { 0x00000050, 0x00000000 },
+ { 0x00000054, 0x0000001f },
+ { 0x00000800, 0x00000000 },
+ { 0x00000804, 0x00000000 },
+ { 0x00000808, 0x00000000 },
+ { 0x0000080c, 0x00000000 },
+ { 0x00000810, 0x00000000 },
+ { 0x00000814, 0x00000000 },
+ { 0x00000818, 0x00000000 },
+ { 0x0000081c, 0x00000000 },
+ { 0x00000820, 0x00000000 },
+ { 0x00000824, 0x00000000 },
+ { 0x00001230, 0x00000000 },
+ { 0x00008004, 0x00000000 },
+ { 0x00008008, 0x00000000 },
+ { 0x0000800c, 0x00000000 },
+ { 0x00008018, 0x00000000 },
+ { 0x00008024, 0x00000000 },
+ { 0x00008028, 0x00000030 },
+ { 0x0000802c, 0x0007ffff },
+ { 0x00008030, 0x01ffffff },
+ { 0x00008034, 0x00000031 },
+ { 0x00008038, 0x00000000 },
+ { 0x0000803c, 0x00000000 },
+ { 0x00008040, 0x00000000 },
+ { 0x00008044, 0x00000002 },
+ { 0x00008048, 0x00000000 },
+ { 0x00008054, 0x00000000 },
+ { 0x00008058, 0x00000000 },
+ { 0x00009808, 0x00000000 },
+ { 0x0000980c, 0x2d849093 },
+ { 0x00009810, 0x7d32e000 },
+ { 0x00009814, 0x00000f6b },
+ { 0x0000981c, 0x00000000 },
+ { 0x0000982c, 0x00026ffe },
+ { 0x00009830, 0x00000000 },
+ { 0x0000983c, 0x00020100 },
+ { 0x00009840, 0x206a017a },
+ { 0x0000984c, 0x1284613c },
+ { 0x00009854, 0x00000859 },
+ { 0x00009868, 0x409a4190 },
+ { 0x0000986c, 0x050cb081 },
+ { 0x00009870, 0x0000000f },
+ { 0x00009874, 0x00000080 },
+ { 0x00009878, 0x0000000c },
+ { 0x00009900, 0x00000000 },
+ { 0x00009904, 0x00000000 },
+ { 0x00009908, 0x00000000 },
+ { 0x0000990c, 0x00800000 },
+ { 0x00009910, 0x00000001 },
+ { 0x0000991c, 0x0000092a },
+ { 0x00009920, 0x00000000 },
+ { 0x00009924, 0x00058a05 },
+ { 0x00009928, 0x00000001 },
+ { 0x0000992c, 0x00000000 },
+ { 0x00009930, 0x00000000 },
+ { 0x00009934, 0x00000000 },
+ { 0x00009938, 0x00000000 },
+ { 0x0000993c, 0x0000003f },
+ { 0x00009940, 0x00000004 },
+ { 0x00009948, 0x00000000 },
+ { 0x0000994c, 0x00000000 },
+ { 0x00009950, 0x00000000 },
+ { 0x00009954, 0x5d50f14c },
+ { 0x00009958, 0x00000018 },
+ { 0x0000995c, 0x004b6a8e },
+ { 0x0000a184, 0x06ff05ff },
+ { 0x0000a188, 0x07ff07ff },
+ { 0x0000a18c, 0x08ff08ff },
+ { 0x0000a190, 0x09ff09ff },
+ { 0x0000a194, 0x0aff0aff },
+ { 0x0000a198, 0x0bff0bff },
+ { 0x0000a19c, 0x0cff0cff },
+ { 0x0000a1a0, 0x0dff0dff },
+ { 0x0000a1a4, 0x0fff0eff },
+ { 0x0000a1a8, 0x12ff12ff },
+ { 0x0000a1ac, 0x14ff13ff },
+ { 0x0000a1b0, 0x16ff15ff },
+ { 0x0000a1b4, 0x19ff17ff },
+ { 0x0000a1b8, 0x1bff1aff },
+ { 0x0000a1bc, 0x1eff1dff },
+ { 0x0000a1c0, 0x23ff20ff },
+ { 0x0000a1c4, 0x27ff25ff },
+ { 0x0000a1c8, 0x2cff29ff },
+ { 0x0000a1cc, 0x31ff2fff },
+ { 0x0000a1d0, 0x37ff34ff },
+ { 0x0000a1d4, 0x3aff3aff },
+ { 0x0000a1d8, 0x3aff3aff },
+ { 0x0000a1dc, 0x3aff3aff },
+ { 0x0000a1e0, 0x3aff3aff },
+ { 0x0000a1e4, 0x3aff3aff },
+ { 0x0000a1e8, 0x3aff3aff },
+ { 0x0000a1ec, 0x3aff3aff },
+ { 0x0000a1f0, 0x3aff3aff },
+ { 0x0000a1f4, 0x3aff3aff },
+ { 0x0000a1f8, 0x3aff3aff },
+ { 0x0000a1fc, 0x3aff3aff },
+ { 0x00009b00, 0x00000000 },
+ { 0x00009b04, 0x00000020 },
+ { 0x00009b08, 0x00000010 },
+ { 0x00009b0c, 0x00000030 },
+ { 0x00009b10, 0x00000008 },
+ { 0x00009b14, 0x00000028 },
+ { 0x00009b18, 0x00000004 },
+ { 0x00009b1c, 0x00000024 },
+ { 0x00009b20, 0x00000014 },
+ { 0x00009b24, 0x00000034 },
+ { 0x00009b28, 0x0000000c },
+ { 0x00009b2c, 0x0000002c },
+ { 0x00009b30, 0x00000002 },
+ { 0x00009b34, 0x00000022 },
+ { 0x00009b38, 0x00000012 },
+ { 0x00009b3c, 0x00000032 },
+ { 0x00009b40, 0x0000000a },
+ { 0x00009b44, 0x0000002a },
+ { 0x00009b48, 0x00000006 },
+ { 0x00009b4c, 0x00000026 },
+ { 0x00009b50, 0x00000016 },
+ { 0x00009b54, 0x00000036 },
+ { 0x00009b58, 0x0000000e },
+ { 0x00009b5c, 0x0000002e },
+ { 0x00009b60, 0x00000001 },
+ { 0x00009b64, 0x00000021 },
+ { 0x00009b68, 0x00000011 },
+ { 0x00009b6c, 0x00000031 },
+ { 0x00009b70, 0x00000009 },
+ { 0x00009b74, 0x00000029 },
+ { 0x00009b78, 0x00000005 },
+ { 0x00009b7c, 0x00000025 },
+ { 0x00009b80, 0x00000015 },
+ { 0x00009b84, 0x00000035 },
+ { 0x00009b88, 0x0000000d },
+ { 0x00009b8c, 0x0000002d },
+ { 0x00009b90, 0x00000003 },
+ { 0x00009b94, 0x00000023 },
+ { 0x00009b98, 0x00000013 },
+ { 0x00009b9c, 0x00000033 },
+ { 0x00009ba0, 0x0000000b },
+ { 0x00009ba4, 0x0000002b },
+ { 0x00009ba8, 0x0000002b },
+ { 0x00009bac, 0x0000002b },
+ { 0x00009bb0, 0x0000002b },
+ { 0x00009bb4, 0x0000002b },
+ { 0x00009bb8, 0x0000002b },
+ { 0x00009bbc, 0x0000002b },
+ { 0x00009bc0, 0x0000002b },
+ { 0x00009bc4, 0x0000002b },
+ { 0x00009bc8, 0x0000002b },
+ { 0x00009bcc, 0x0000002b },
+ { 0x00009bd0, 0x0000002b },
+ { 0x00009bd4, 0x0000002b },
+ { 0x00009bd8, 0x0000002b },
+ { 0x00009bdc, 0x0000002b },
+ { 0x00009be0, 0x0000002b },
+ { 0x00009be4, 0x0000002b },
+ { 0x00009be8, 0x0000002b },
+ { 0x00009bec, 0x0000002b },
+ { 0x00009bf0, 0x0000002b },
+ { 0x00009bf4, 0x0000002b },
+ { 0x00009bf8, 0x00000002 },
+ { 0x00009bfc, 0x00000016 },
+ { 0x000098d4, 0x00000020 },
+ { 0x000098d8, 0x00601068 },
+};
+
+static uint32_t ar5211Mode2_4[][3] = {
+ { 0x0000a204, 0x00000000, 0x00000000 },
+ { 0x0000a208, 0x503e4646, 0x503e4646 },
+ { 0x0000a20c, 0x6480416c, 0x6480416c },
+ { 0x0000a210, 0x0199a003, 0x0199a003 },
+ { 0x0000a214, 0x044cd610, 0x044cd610 },
+ { 0x0000a218, 0x13800040, 0x13800040 },
+ { 0x0000a21c, 0x1be00060, 0x1be00060 },
+ { 0x0000a220, 0x0c53800a, 0x0c53800a },
+ { 0x0000a224, 0x0014df3b, 0x0014df3b },
+ { 0x0000a228, 0x000001b5, 0x000001b5 },
+ { 0x0000a22c, 0x00000020, 0x00000020 },
+ { 0x0000989c, 0x00000000, 0x00000000 },
+ { 0x0000989c, 0x00000000, 0x00000000 },
+ { 0x0000989c, 0x00000000, 0x00000000 },
+ { 0x0000989c, 0x00000000, 0x00000000 },
+ { 0x0000989c, 0x00000000, 0x00000000 },
+ { 0x0000989c, 0x00000000, 0x00000000 },
+ { 0x0000989c, 0x00000000, 0x00000000 },
+ { 0x0000989c, 0x00000000, 0x00000000 },
+ { 0x0000989c, 0x00000000, 0x00000000 },
+ { 0x0000989c, 0x00000000, 0x00000000 },
+ { 0x0000989c, 0x00000000, 0x00000000 },
+ { 0x0000989c, 0x00380000, 0x00380000 },
+ { 0x0000989c, 0x00000000, 0x00000000 },
+ { 0x0000989c, 0x00000000, 0x00000000 },
+ { 0x0000989c, 0x00000000, 0x00000000 },
+ { 0x0000989c, 0x000400f9, 0x000400f9 },
+ { 0x000098d4, 0x00000000, 0x00000004 },
+};
+
+static const uint32_t ar5211BB_RfGain[][3] = {
+ { 0x00009a00, 0x000001a9, 0x00000000 },
+ { 0x00009a04, 0x000001e9, 0x00000040 },
+ { 0x00009a08, 0x00000029, 0x00000080 },
+ { 0x00009a0c, 0x00000069, 0x00000150 },
+ { 0x00009a10, 0x00000199, 0x00000190 },
+ { 0x00009a14, 0x000001d9, 0x000001d0 },
+ { 0x00009a18, 0x00000019, 0x00000010 },
+ { 0x00009a1c, 0x00000059, 0x00000044 },
+ { 0x00009a20, 0x00000099, 0x00000084 },
+ { 0x00009a24, 0x000001a5, 0x00000148 },
+ { 0x00009a28, 0x000001e5, 0x00000188 },
+ { 0x00009a2c, 0x00000025, 0x000001c8 },
+ { 0x00009a30, 0x000001c8, 0x00000014 },
+ { 0x00009a34, 0x00000008, 0x00000042 },
+ { 0x00009a38, 0x00000048, 0x00000082 },
+ { 0x00009a3c, 0x00000088, 0x00000178 },
+ { 0x00009a40, 0x00000198, 0x000001b8 },
+ { 0x00009a44, 0x000001d8, 0x000001f8 },
+ { 0x00009a48, 0x00000018, 0x00000012 },
+ { 0x00009a4c, 0x00000058, 0x00000052 },
+ { 0x00009a50, 0x00000098, 0x00000092 },
+ { 0x00009a54, 0x000001a4, 0x0000017c },
+ { 0x00009a58, 0x000001e4, 0x000001bc },
+ { 0x00009a5c, 0x00000024, 0x000001fc },
+ { 0x00009a60, 0x00000064, 0x0000000a },
+ { 0x00009a64, 0x000000a4, 0x0000004a },
+ { 0x00009a68, 0x000000e4, 0x0000008a },
+ { 0x00009a6c, 0x0000010a, 0x0000015a },
+ { 0x00009a70, 0x0000014a, 0x0000019a },
+ { 0x00009a74, 0x0000018a, 0x000001da },
+ { 0x00009a78, 0x000001ca, 0x0000000e },
+ { 0x00009a7c, 0x0000000a, 0x0000004e },
+ { 0x00009a80, 0x0000004a, 0x0000008e },
+ { 0x00009a84, 0x0000008a, 0x0000015e },
+ { 0x00009a88, 0x000001ba, 0x0000019e },
+ { 0x00009a8c, 0x000001fa, 0x000001de },
+ { 0x00009a90, 0x0000003a, 0x00000009 },
+ { 0x00009a94, 0x0000007a, 0x00000049 },
+ { 0x00009a98, 0x00000186, 0x00000089 },
+ { 0x00009a9c, 0x000001c6, 0x00000179 },
+ { 0x00009aa0, 0x00000006, 0x000001b9 },
+ { 0x00009aa4, 0x00000046, 0x000001f9 },
+ { 0x00009aa8, 0x00000086, 0x00000039 },
+ { 0x00009aac, 0x000000c6, 0x00000079 },
+ { 0x00009ab0, 0x000000c6, 0x000000b9 },
+ { 0x00009ab4, 0x000000c6, 0x000001bd },
+ { 0x00009ab8, 0x000000c6, 0x000001fd },
+ { 0x00009abc, 0x000000c6, 0x0000003d },
+ { 0x00009ac0, 0x000000c6, 0x0000007d },
+ { 0x00009ac4, 0x000000c6, 0x000000bd },
+ { 0x00009ac8, 0x000000c6, 0x000000fd },
+ { 0x00009acc, 0x000000c6, 0x000000fd },
+ { 0x00009ad0, 0x000000c6, 0x000000fd },
+ { 0x00009ad4, 0x000000c6, 0x000000fd },
+ { 0x00009ad8, 0x000000c6, 0x000000fd },
+ { 0x00009adc, 0x000000c6, 0x000000fd },
+ { 0x00009ae0, 0x000000c6, 0x000000fd },
+ { 0x00009ae4, 0x000000c6, 0x000000fd },
+ { 0x00009ae8, 0x000000c6, 0x000000fd },
+ { 0x00009aec, 0x000000c6, 0x000000fd },
+ { 0x00009af0, 0x000000c6, 0x000000fd },
+ { 0x00009af4, 0x000000c6, 0x000000fd },
+ { 0x00009af8, 0x000000c6, 0x000000fd },
+ { 0x00009afc, 0x000000c6, 0x000000fd },
+};
+
+static uint32_t ar5211Rf6n7[][3] = {
+ { 0x0000989c, 0x00000000, 0x00000000 },
+ { 0x0000989c, 0x00000000, 0x00000000 },
+ { 0x0000989c, 0x00000000, 0x00000000 },
+ { 0x0000989c, 0x00000000, 0x00000000 },
+ { 0x0000989c, 0x00000000, 0x00000000 },
+ { 0x0000989c, 0x10000000, 0x10000000 },
+ { 0x0000989c, 0x04000000, 0x04000000 },
+ { 0x0000989c, 0x00000000, 0x00000000 },
+ { 0x0000989c, 0x00000000, 0x00000000 },
+ { 0x0000989c, 0x00000000, 0x00000000 },
+ { 0x0000989c, 0x00000000, 0x0a000000 },
+ { 0x0000989c, 0x00380080, 0x02380080 },
+ { 0x0000989c, 0x00020006, 0x00000006 },
+ { 0x0000989c, 0x00000092, 0x00000092 },
+ { 0x0000989c, 0x000000a0, 0x000000a0 },
+ { 0x0000989c, 0x00040007, 0x00040007 },
+ { 0x000098d4, 0x0000001a, 0x0000001a },
+ { 0x0000989c, 0x00000048, 0x00000048 },
+ { 0x0000989c, 0x00000010, 0x00000010 },
+ { 0x0000989c, 0x00000008, 0x00000008 },
+ { 0x0000989c, 0x0000000f, 0x0000000f },
+ { 0x0000989c, 0x000000f2, 0x00000062 },
+ { 0x0000989c, 0x0000904f, 0x0000904c },
+ { 0x0000989c, 0x0000125a, 0x0000129a },
+ { 0x000098cc, 0x0000000e, 0x0000000f },
+};
+