aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/ath/ath_hal/ar5210
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/ath/ath_hal/ar5210')
-rw-r--r--sys/dev/ath/ath_hal/ar5210/ar5210.h305
-rw-r--r--sys/dev/ath/ath_hal/ar5210/ar5210_attach.c419
-rw-r--r--sys/dev/ath/ath_hal/ar5210/ar5210_beacon.c202
-rw-r--r--sys/dev/ath/ath_hal/ar5210/ar5210_interrupts.c134
-rw-r--r--sys/dev/ath/ath_hal/ar5210/ar5210_keycache.c156
-rw-r--r--sys/dev/ath/ath_hal/ar5210/ar5210_misc.c733
-rw-r--r--sys/dev/ath/ath_hal/ar5210/ar5210_phy.c85
-rw-r--r--sys/dev/ath/ath_hal/ar5210/ar5210_power.c138
-rw-r--r--sys/dev/ath/ath_hal/ar5210/ar5210_recv.c269
-rw-r--r--sys/dev/ath/ath_hal/ar5210/ar5210_reset.c1005
-rw-r--r--sys/dev/ath/ath_hal/ar5210/ar5210_xmit.c670
-rw-r--r--sys/dev/ath/ath_hal/ar5210/ar5210desc.h130
-rw-r--r--sys/dev/ath/ath_hal/ar5210/ar5210phy.h59
-rw-r--r--sys/dev/ath/ath_hal/ar5210/ar5210reg.h413
-rw-r--r--sys/dev/ath/ath_hal/ar5210/ar5k_0007.ini192
15 files changed, 4910 insertions, 0 deletions
diff --git a/sys/dev/ath/ath_hal/ar5210/ar5210.h b/sys/dev/ath/ath_hal/ar5210/ar5210.h
new file mode 100644
index 000000000000..567fea567cba
--- /dev/null
+++ b/sys/dev/ath/ath_hal/ar5210/ar5210.h
@@ -0,0 +1,305 @@
+/*-
+ * SPDX-License-Identifier: ISC
+ *
+ * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
+ * Copyright (c) 2002-2004 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_AR5210_H_
+#define _ATH_AR5210_H_
+
+#define AR5210_MAGIC 0x19980124
+
+#if 0
+/*
+ * RTS_ENABLE includes LONG_PKT because they essentially
+ * imply the same thing, and are set or not set together
+ * for this chip
+ */
+#define AR5210_TXD_CTRL_A_HDR_LEN(_val) (((_val) ) & 0x0003f)
+#define AR5210_TXD_CTRL_A_TX_RATE(_val) (((_val) << 6) & 0x003c0)
+#define AR5210_TXD_CTRL_A_RTS_ENABLE ( 0x00c00)
+#define AR5210_TXD_CTRL_A_CLEAR_DEST_MASK(_val) (((_val) << 12) & 0x01000)
+#define AR5210_TXD_CTRL_A_ANT_MODE(_val) (((_val) << 13) & 0x02000)
+#define AR5210_TXD_CTRL_A_PKT_TYPE(_val) (((_val) << 14) & 0x1c000)
+#define AR5210_TXD_CTRL_A_INT_REQ ( 0x20000)
+#define AR5210_TXD_CTRL_A_KEY_VALID ( 0x40000)
+#define AR5210_TXD_CTRL_B_KEY_ID(_val) (((_val) ) & 0x0003f)
+#define AR5210_TXD_CTRL_B_RTS_DURATION(_val) (((_val) << 6) & 0x7ffc0)
+#endif
+
+#define INIT_CONFIG_STATUS 0x00000000
+#define INIT_ACKTOPS 0x00000008
+#define INIT_BCON_CNTRL_REG 0x00000000
+#define INIT_SLOT_TIME 0x00000168
+#define INIT_SLOT_TIME_TURBO 0x000001e0 /* More aggressive turbo slot timing = 6 us */
+#define INIT_ACK_CTS_TIMEOUT 0x04000400
+#define INIT_ACK_CTS_TIMEOUT_TURBO 0x08000800
+
+#define INIT_USEC 0x27
+#define INIT_USEC_TURBO 0x4f
+#define INIT_USEC_32 0x1f
+#define INIT_TX_LATENCY 0x36
+#define INIT_RX_LATENCY 0x1D
+#define INIT_TRANSMIT_LATENCY \
+ ((INIT_RX_LATENCY << AR_USEC_RX_LATENCY_S) | \
+ (INIT_TX_LATENCY << AR_USEC_TX_LATENCY_S) | \
+ (INIT_USEC_32 << 7) | INIT_USEC )
+#define INIT_TRANSMIT_LATENCY_TURBO \
+ ((INIT_RX_LATENCY << AR_USEC_RX_LATENCY_S) | \
+ (INIT_TX_LATENCY << AR_USEC_TX_LATENCY_S) | \
+ (INIT_USEC_32 << 7) | INIT_USEC_TURBO)
+
+#define INIT_SIFS 0x230 /* = 16 us - 2 us */
+#define INIT_SIFS_TURBO 0x1E0 /* More aggressive turbo SIFS timing - 8 us - 2 us */
+
+/*
+ * 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_NEXT_CFP_START 0xffffffff
+
+#define INIT_BEACON_PERIOD 0xffff
+#define INIT_BEACON_EN 0 /* this should be set by AP only when it's ready */
+#define INIT_BEACON_CONTROL \
+ ((INIT_RESET_TSF << 24) | (INIT_BEACON_EN << 23) | \
+ (INIT_TIM_OFFSET<<16) | INIT_BEACON_PERIOD)
+
+#define INIT_RSSI_THR 0x00000700 /* Missed beacon counter initialized to max value of 7 */
+#define INIT_ProgIFS 0x398 /* PIFS - 2us */
+#define INIT_ProgIFS_TURBO 0x3C0
+#define INIT_EIFS 0xd70
+#define INIT_EIFS_TURBO 0x1ae0
+#define INIT_CARR_SENSE_EN 1
+#define INIT_PROTO_TIME_CNTRL ( (INIT_CARR_SENSE_EN << 26) | (INIT_EIFS << 12) | \
+ (INIT_ProgIFS) )
+#define INIT_PROTO_TIME_CNTRL_TURBO ( (INIT_CARR_SENSE_EN << 26) | (INIT_EIFS_TURBO << 12) | \
+ (INIT_ProgIFS_TURBO) )
+
+#define AR5210_MAX_RATE_POWER 60
+
+#undef HAL_NUM_TX_QUEUES /* from ah.h */
+#define HAL_NUM_TX_QUEUES 3
+
+struct ath_hal_5210 {
+ struct ath_hal_private ah_priv; /* base definitions */
+
+ uint8_t ah_macaddr[IEEE80211_ADDR_LEN];
+ /*
+ * Runtime state.
+ */
+ uint32_t ah_maskReg; /* shadow of IMR+IER regs */
+ uint32_t ah_txOkInterruptMask;
+ uint32_t ah_txErrInterruptMask;
+ uint32_t ah_txDescInterruptMask;
+ uint32_t ah_txEolInterruptMask;
+ uint32_t ah_txUrnInterruptMask;
+ uint8_t ah_bssid[IEEE80211_ADDR_LEN];
+ HAL_TX_QUEUE_INFO ah_txq[HAL_NUM_TX_QUEUES]; /* beacon+cab+data */
+ /*
+ * Station mode support.
+ */
+ uint32_t ah_staId1Defaults; /* STA_ID1 default settings */
+ 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 */
+
+ uint16_t ah_associd; /* association id */
+};
+#define AH5210(ah) ((struct ath_hal_5210 *)(ah))
+
+struct ath_hal;
+
+extern void ar5210Detach(struct ath_hal *ah);
+extern HAL_BOOL ar5210Reset(struct ath_hal *, HAL_OPMODE,
+ struct ieee80211_channel *, HAL_BOOL bChannelChange,
+ HAL_RESET_TYPE, HAL_STATUS *);
+extern void ar5210SetPCUConfig(struct ath_hal *);
+extern HAL_BOOL ar5210PhyDisable(struct ath_hal *);
+extern HAL_BOOL ar5210Disable(struct ath_hal *);
+extern HAL_BOOL ar5210ChipReset(struct ath_hal *, struct ieee80211_channel *);
+extern HAL_BOOL ar5210PerCalibration(struct ath_hal *, struct ieee80211_channel *, HAL_BOOL *);
+extern HAL_BOOL ar5210PerCalibrationN(struct ath_hal *ah, struct ieee80211_channel *chan,
+ u_int chainMask, HAL_BOOL longCal, HAL_BOOL *isCalDone);
+extern HAL_BOOL ar5210ResetCalValid(struct ath_hal *ah, const struct ieee80211_channel *);
+extern int16_t ar5210GetNoiseFloor(struct ath_hal *);
+extern int16_t ar5210GetNfAdjust(struct ath_hal *,
+ const HAL_CHANNEL_INTERNAL *);
+extern HAL_BOOL ar5210SetTxPowerLimit(struct ath_hal *, uint32_t limit);
+extern HAL_BOOL ar5210SetTransmitPower(struct ath_hal *,
+ const struct ieee80211_channel *);
+extern HAL_BOOL ar5210CalNoiseFloor(struct ath_hal *, HAL_CHANNEL_INTERNAL *);
+extern HAL_BOOL ar5210ResetDma(struct ath_hal *, HAL_OPMODE);
+
+extern HAL_BOOL ar5210SetTxQueueProps(struct ath_hal *ah, int q,
+ const HAL_TXQ_INFO *qInfo);
+extern HAL_BOOL ar5210GetTxQueueProps(struct ath_hal *ah, int q,
+ HAL_TXQ_INFO *qInfo);
+extern int ar5210SetupTxQueue(struct ath_hal *ah, HAL_TX_QUEUE type,
+ const HAL_TXQ_INFO *qInfo);
+extern HAL_BOOL ar5210ReleaseTxQueue(struct ath_hal *ah, u_int q);
+extern HAL_BOOL ar5210ResetTxQueue(struct ath_hal *ah, u_int q);
+extern uint32_t ar5210GetTxDP(struct ath_hal *, u_int);
+extern HAL_BOOL ar5210SetTxDP(struct ath_hal *, u_int, uint32_t txdp);
+extern HAL_BOOL ar5210UpdateTxTrigLevel(struct ath_hal *, HAL_BOOL);
+extern uint32_t ar5210NumTxPending(struct ath_hal *, u_int);
+extern HAL_BOOL ar5210StartTxDma(struct ath_hal *, u_int);
+extern HAL_BOOL ar5210StopTxDma(struct ath_hal *, u_int);
+extern HAL_BOOL ar5210SetupTxDesc(struct ath_hal *, struct ath_desc *,
+ u_int pktLen, u_int hdrLen, HAL_PKT_TYPE type, u_int txPower,
+ u_int txRate0, u_int txRetries0,
+ 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 ar5210SetupXTxDesc(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 ar5210FillTxDesc(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 ar5210ProcTxDesc(struct ath_hal *,
+ struct ath_desc *, struct ath_tx_status *);
+extern void ar5210GetTxIntrQueue(struct ath_hal *ah, uint32_t *);
+extern void ar5210IntrReqTxDesc(struct ath_hal *ah, struct ath_desc *);
+extern HAL_BOOL ar5210GetTxCompletionRates(struct ath_hal *ah,
+ const struct ath_desc *, int *rates, int *tries);
+extern void ar5210SetTxDescLink(struct ath_hal *ah, void *ds,
+ uint32_t link);
+extern void ar5210GetTxDescLink(struct ath_hal *ah, void *ds,
+ uint32_t *link);
+extern void ar5210GetTxDescLinkPtr(struct ath_hal *ah, void *ds,
+ uint32_t **linkptr);
+
+extern uint32_t ar5210GetRxDP(struct ath_hal *, HAL_RX_QUEUE);
+extern void ar5210SetRxDP(struct ath_hal *, uint32_t rxdp, HAL_RX_QUEUE);
+extern void ar5210EnableReceive(struct ath_hal *);
+extern HAL_BOOL ar5210StopDmaReceive(struct ath_hal *);
+extern void ar5210StartPcuReceive(struct ath_hal *, HAL_BOOL);
+extern void ar5210StopPcuReceive(struct ath_hal *);
+extern void ar5210SetMulticastFilter(struct ath_hal *,
+ uint32_t filter0, uint32_t filter1);
+extern HAL_BOOL ar5210ClrMulticastFilterIndex(struct ath_hal *, uint32_t);
+extern HAL_BOOL ar5210SetMulticastFilterIndex(struct ath_hal *, uint32_t);
+extern uint32_t ar5210GetRxFilter(struct ath_hal *);
+extern void ar5210SetRxFilter(struct ath_hal *, uint32_t);
+extern HAL_BOOL ar5210SetupRxDesc(struct ath_hal *, struct ath_desc *,
+ uint32_t, u_int flags);
+extern HAL_STATUS ar5210ProcRxDesc(struct ath_hal *, struct ath_desc *,
+ uint32_t, struct ath_desc *, uint64_t,
+ struct ath_rx_status *);
+
+extern void ar5210GetMacAddress(struct ath_hal *, uint8_t *);
+extern HAL_BOOL ar5210SetMacAddress(struct ath_hal *ah, const uint8_t *);
+extern void ar5210GetBssIdMask(struct ath_hal *, uint8_t *);
+extern HAL_BOOL ar5210SetBssIdMask(struct ath_hal *, const uint8_t *);
+extern HAL_BOOL ar5210EepromRead(struct ath_hal *, u_int off, uint16_t *data);
+extern HAL_BOOL ar5210EepromWrite(struct ath_hal *, u_int off, uint16_t data);
+extern HAL_BOOL ar5210SetRegulatoryDomain(struct ath_hal *,
+ uint16_t, HAL_STATUS *);
+extern u_int ar5210GetWirelessModes(struct ath_hal *ah);
+extern void ar5210EnableRfKill(struct ath_hal *);
+extern HAL_BOOL ar5210GpioCfgInput(struct ath_hal *, uint32_t gpio);
+extern HAL_BOOL ar5210GpioCfgOutput(struct ath_hal *, uint32_t gpio,
+ HAL_GPIO_MUX_TYPE);
+extern uint32_t ar5210GpioGet(struct ath_hal *, uint32_t gpio);
+extern HAL_BOOL ar5210GpioSet(struct ath_hal *, uint32_t gpio, uint32_t);
+extern void ar5210Gpio0SetIntr(struct ath_hal *, u_int, uint32_t ilevel);
+extern void ar5210SetLedState(struct ath_hal *, HAL_LED_STATE);
+extern u_int ar5210GetDefAntenna(struct ath_hal *);
+extern void ar5210SetDefAntenna(struct ath_hal *, u_int);
+extern HAL_ANT_SETTING ar5210GetAntennaSwitch(struct ath_hal *);
+extern HAL_BOOL ar5210SetAntennaSwitch(struct ath_hal *, HAL_ANT_SETTING);
+extern void ar5210WriteAssocid(struct ath_hal *,
+ const uint8_t *bssid, uint16_t assocId);
+extern uint32_t ar5210GetTsf32(struct ath_hal *);
+extern uint64_t ar5210GetTsf64(struct ath_hal *);
+extern void ar5210ResetTsf(struct ath_hal *);
+extern uint32_t ar5210GetRandomSeed(struct ath_hal *);
+extern HAL_BOOL ar5210DetectCardPresent(struct ath_hal *);
+extern void ar5210UpdateMibCounters(struct ath_hal *, HAL_MIB_STATS *);
+extern void ar5210EnableHwEncryption(struct ath_hal *);
+extern void ar5210DisableHwEncryption(struct ath_hal *);
+extern HAL_RFGAIN ar5210GetRfgain(struct ath_hal *);
+extern HAL_BOOL ar5210SetSifsTime(struct ath_hal *, u_int);
+extern u_int ar5210GetSifsTime(struct ath_hal *);
+extern HAL_BOOL ar5210SetSlotTime(struct ath_hal *, u_int);
+extern u_int ar5210GetSlotTime(struct ath_hal *);
+extern HAL_BOOL ar5210SetAckTimeout(struct ath_hal *, u_int);
+extern u_int ar5210GetAckTimeout(struct ath_hal *);
+extern HAL_BOOL ar5210SetAckCTSRate(struct ath_hal *, u_int);
+extern u_int ar5210GetAckCTSRate(struct ath_hal *);
+extern HAL_BOOL ar5210SetCTSTimeout(struct ath_hal *, u_int);
+extern u_int ar5210GetCTSTimeout(struct ath_hal *);
+extern HAL_BOOL ar5210SetDecompMask(struct ath_hal *, uint16_t, int);
+void ar5210SetCoverageClass(struct ath_hal *, uint8_t, int);
+extern HAL_STATUS ar5210SetQuiet(struct ath_hal *, uint32_t, uint32_t,
+ uint32_t, HAL_QUIET_FLAG);
+extern HAL_STATUS ar5210GetCapability(struct ath_hal *, HAL_CAPABILITY_TYPE,
+ uint32_t, uint32_t *);
+extern HAL_BOOL ar5210SetCapability(struct ath_hal *, HAL_CAPABILITY_TYPE,
+ uint32_t, uint32_t, HAL_STATUS *);
+extern HAL_BOOL ar5210GetDiagState(struct ath_hal *ah, int request,
+ const void *args, uint32_t argsize,
+ void **result, uint32_t *resultsize);
+extern uint32_t ar5210Get11nExtBusy(struct ath_hal *);
+extern HAL_BOOL ar5210GetMibCycleCounts(struct ath_hal *,
+ HAL_SURVEY_SAMPLE *);
+extern void ar5210SetChainMasks(struct ath_hal *, uint32_t, uint32_t);
+extern void ar5210EnableDfs(struct ath_hal *, HAL_PHYERR_PARAM *);
+extern void ar5210GetDfsThresh(struct ath_hal *, HAL_PHYERR_PARAM *);
+extern void ar5210UpdateDiagReg(struct ath_hal *ah, uint32_t val);
+extern void ar5210SetNav(struct ath_hal *ah, u_int val);
+extern u_int ar5210GetNav(struct ath_hal *ah);
+
+extern u_int ar5210GetKeyCacheSize(struct ath_hal *);
+extern HAL_BOOL ar5210IsKeyCacheEntryValid(struct ath_hal *, uint16_t);
+extern HAL_BOOL ar5210ResetKeyCacheEntry(struct ath_hal *, uint16_t entry);
+extern HAL_BOOL ar5210SetKeyCacheEntry(struct ath_hal *, uint16_t entry,
+ const HAL_KEYVAL *, const uint8_t *mac, int xorKey);
+extern HAL_BOOL ar5210SetKeyCacheEntryMac(struct ath_hal *,
+ uint16_t, const uint8_t *);
+
+extern HAL_BOOL ar5210SetPowerMode(struct ath_hal *, HAL_POWER_MODE mode,
+ int setChip);
+extern HAL_POWER_MODE ar5210GetPowerMode(struct ath_hal *);
+
+extern void ar5210SetBeaconTimers(struct ath_hal *,
+ const HAL_BEACON_TIMERS *);
+extern void ar5210BeaconInit(struct ath_hal *, uint32_t, uint32_t);
+extern void ar5210SetStaBeaconTimers(struct ath_hal *,
+ const HAL_BEACON_STATE *);
+extern void ar5210ResetStaBeaconTimers(struct ath_hal *);
+extern uint64_t ar5210GetNextTBTT(struct ath_hal *);
+
+extern HAL_BOOL ar5210IsInterruptPending(struct ath_hal *);
+extern HAL_BOOL ar5210GetPendingInterrupts(struct ath_hal *, HAL_INT *);
+extern HAL_INT ar5210GetInterrupts(struct ath_hal *);
+extern HAL_INT ar5210SetInterrupts(struct ath_hal *, HAL_INT ints);
+
+extern const HAL_RATE_TABLE *ar5210GetRateTable(struct ath_hal *, u_int mode);
+
+extern HAL_BOOL ar5210AniControl(struct ath_hal *, HAL_ANI_CMD, int );
+extern void ar5210AniPoll(struct ath_hal *, const struct ieee80211_channel *);
+extern void ar5210RxMonitor(struct ath_hal *, const HAL_NODE_STATS *,
+ const struct ieee80211_channel *);
+extern void ar5210MibEvent(struct ath_hal *, const HAL_NODE_STATS *);
+#endif /* _ATH_AR5210_H_ */
diff --git a/sys/dev/ath/ath_hal/ar5210/ar5210_attach.c b/sys/dev/ath/ath_hal/ar5210/ar5210_attach.c
new file mode 100644
index 000000000000..4f67330ca830
--- /dev/null
+++ b/sys/dev/ath/ath_hal/ar5210/ar5210_attach.c
@@ -0,0 +1,419 @@
+/*-
+ * SPDX-License-Identifier: ISC
+ *
+ * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
+ * Copyright (c) 2002-2004 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 "ar5210/ar5210.h"
+#include "ar5210/ar5210reg.h"
+#include "ar5210/ar5210phy.h"
+
+#include "ah_eeprom_v1.h"
+
+static HAL_BOOL ar5210GetChannelEdges(struct ath_hal *,
+ uint16_t flags, uint16_t *low, uint16_t *high);
+static HAL_BOOL ar5210GetChipPowerLimits(struct ath_hal *ah,
+ struct ieee80211_channel *chan);
+
+static void ar5210ConfigPCIE(struct ath_hal *ah, HAL_BOOL restore,
+ HAL_BOOL power_on);
+static void ar5210DisablePCIE(struct ath_hal *ah);
+
+static const struct ath_hal_private ar5210hal = {{
+ .ah_magic = AR5210_MAGIC,
+
+ .ah_getRateTable = ar5210GetRateTable,
+ .ah_detach = ar5210Detach,
+
+ /* Reset Functions */
+ .ah_reset = ar5210Reset,
+ .ah_phyDisable = ar5210PhyDisable,
+ .ah_disable = ar5210Disable,
+ .ah_configPCIE = ar5210ConfigPCIE,
+ .ah_disablePCIE = ar5210DisablePCIE,
+ .ah_setPCUConfig = ar5210SetPCUConfig,
+ .ah_perCalibration = ar5210PerCalibration,
+ .ah_perCalibrationN = ar5210PerCalibrationN,
+ .ah_resetCalValid = ar5210ResetCalValid,
+ .ah_setTxPowerLimit = ar5210SetTxPowerLimit,
+ .ah_getChanNoise = ath_hal_getChanNoise,
+
+ /* Transmit functions */
+ .ah_updateTxTrigLevel = ar5210UpdateTxTrigLevel,
+ .ah_setupTxQueue = ar5210SetupTxQueue,
+ .ah_setTxQueueProps = ar5210SetTxQueueProps,
+ .ah_getTxQueueProps = ar5210GetTxQueueProps,
+ .ah_releaseTxQueue = ar5210ReleaseTxQueue,
+ .ah_resetTxQueue = ar5210ResetTxQueue,
+ .ah_getTxDP = ar5210GetTxDP,
+ .ah_setTxDP = ar5210SetTxDP,
+ .ah_numTxPending = ar5210NumTxPending,
+ .ah_startTxDma = ar5210StartTxDma,
+ .ah_stopTxDma = ar5210StopTxDma,
+ .ah_setupTxDesc = ar5210SetupTxDesc,
+ .ah_setupXTxDesc = ar5210SetupXTxDesc,
+ .ah_fillTxDesc = ar5210FillTxDesc,
+ .ah_procTxDesc = ar5210ProcTxDesc,
+ .ah_getTxIntrQueue = ar5210GetTxIntrQueue,
+ .ah_reqTxIntrDesc = ar5210IntrReqTxDesc,
+ .ah_getTxCompletionRates = ar5210GetTxCompletionRates,
+ .ah_setTxDescLink = ar5210SetTxDescLink,
+ .ah_getTxDescLink = ar5210GetTxDescLink,
+ .ah_getTxDescLinkPtr = ar5210GetTxDescLinkPtr,
+
+ /* RX Functions */
+ .ah_getRxDP = ar5210GetRxDP,
+ .ah_setRxDP = ar5210SetRxDP,
+ .ah_enableReceive = ar5210EnableReceive,
+ .ah_stopDmaReceive = ar5210StopDmaReceive,
+ .ah_startPcuReceive = ar5210StartPcuReceive,
+ .ah_stopPcuReceive = ar5210StopPcuReceive,
+ .ah_setMulticastFilter = ar5210SetMulticastFilter,
+ .ah_setMulticastFilterIndex = ar5210SetMulticastFilterIndex,
+ .ah_clrMulticastFilterIndex = ar5210ClrMulticastFilterIndex,
+ .ah_getRxFilter = ar5210GetRxFilter,
+ .ah_setRxFilter = ar5210SetRxFilter,
+ .ah_setupRxDesc = ar5210SetupRxDesc,
+ .ah_procRxDesc = ar5210ProcRxDesc,
+ .ah_rxMonitor = ar5210RxMonitor,
+ .ah_aniPoll = ar5210AniPoll,
+ .ah_procMibEvent = ar5210MibEvent,
+
+ /* Misc Functions */
+ .ah_getCapability = ar5210GetCapability,
+ .ah_setCapability = ar5210SetCapability,
+ .ah_getDiagState = ar5210GetDiagState,
+ .ah_getMacAddress = ar5210GetMacAddress,
+ .ah_setMacAddress = ar5210SetMacAddress,
+ .ah_getBssIdMask = ar5210GetBssIdMask,
+ .ah_setBssIdMask = ar5210SetBssIdMask,
+ .ah_setRegulatoryDomain = ar5210SetRegulatoryDomain,
+ .ah_setLedState = ar5210SetLedState,
+ .ah_writeAssocid = ar5210WriteAssocid,
+ .ah_gpioCfgInput = ar5210GpioCfgInput,
+ .ah_gpioCfgOutput = ar5210GpioCfgOutput,
+ .ah_gpioGet = ar5210GpioGet,
+ .ah_gpioSet = ar5210GpioSet,
+ .ah_gpioSetIntr = ar5210Gpio0SetIntr,
+ .ah_getTsf32 = ar5210GetTsf32,
+ .ah_getTsf64 = ar5210GetTsf64,
+ .ah_resetTsf = ar5210ResetTsf,
+ .ah_detectCardPresent = ar5210DetectCardPresent,
+ .ah_updateMibCounters = ar5210UpdateMibCounters,
+ .ah_getRfGain = ar5210GetRfgain,
+ .ah_getDefAntenna = ar5210GetDefAntenna,
+ .ah_setDefAntenna = ar5210SetDefAntenna,
+ .ah_getAntennaSwitch = ar5210GetAntennaSwitch,
+ .ah_setAntennaSwitch = ar5210SetAntennaSwitch,
+ .ah_setSifsTime = ar5210SetSifsTime,
+ .ah_getSifsTime = ar5210GetSifsTime,
+ .ah_setSlotTime = ar5210SetSlotTime,
+ .ah_getSlotTime = ar5210GetSlotTime,
+ .ah_setAckTimeout = ar5210SetAckTimeout,
+ .ah_getAckTimeout = ar5210GetAckTimeout,
+ .ah_setAckCTSRate = ar5210SetAckCTSRate,
+ .ah_getAckCTSRate = ar5210GetAckCTSRate,
+ .ah_setCTSTimeout = ar5210SetCTSTimeout,
+ .ah_getCTSTimeout = ar5210GetCTSTimeout,
+ .ah_setDecompMask = ar5210SetDecompMask,
+ .ah_setCoverageClass = ar5210SetCoverageClass,
+ .ah_setQuiet = ar5210SetQuiet,
+ .ah_get11nExtBusy = ar5210Get11nExtBusy,
+ .ah_getMibCycleCounts = ar5210GetMibCycleCounts,
+ .ah_setChainMasks = ar5210SetChainMasks,
+ .ah_enableDfs = ar5210EnableDfs,
+ .ah_getDfsThresh = ar5210GetDfsThresh,
+ /* XXX procRadarEvent */
+ /* XXX isFastClockEnabled */
+ .ah_getNav = ar5210GetNav,
+ .ah_setNav = ar5210SetNav,
+
+ /* Key Cache Functions */
+ .ah_getKeyCacheSize = ar5210GetKeyCacheSize,
+ .ah_resetKeyCacheEntry = ar5210ResetKeyCacheEntry,
+ .ah_isKeyCacheEntryValid = ar5210IsKeyCacheEntryValid,
+ .ah_setKeyCacheEntry = ar5210SetKeyCacheEntry,
+ .ah_setKeyCacheEntryMac = ar5210SetKeyCacheEntryMac,
+
+ /* Power Management Functions */
+ .ah_setPowerMode = ar5210SetPowerMode,
+ .ah_getPowerMode = ar5210GetPowerMode,
+
+ /* Beacon Functions */
+ .ah_setBeaconTimers = ar5210SetBeaconTimers,
+ .ah_beaconInit = ar5210BeaconInit,
+ .ah_setStationBeaconTimers = ar5210SetStaBeaconTimers,
+ .ah_resetStationBeaconTimers = ar5210ResetStaBeaconTimers,
+ .ah_getNextTBTT = ar5210GetNextTBTT,
+
+ /* Interrupt Functions */
+ .ah_isInterruptPending = ar5210IsInterruptPending,
+ .ah_getPendingInterrupts = ar5210GetPendingInterrupts,
+ .ah_getInterrupts = ar5210GetInterrupts,
+ .ah_setInterrupts = ar5210SetInterrupts },
+
+ .ah_getChannelEdges = ar5210GetChannelEdges,
+ .ah_getWirelessModes = ar5210GetWirelessModes,
+ .ah_eepromRead = ar5210EepromRead,
+#ifdef AH_SUPPORT_WRITE_EEPROM
+ .ah_eepromWrite = ar5210EepromWrite,
+#endif
+ .ah_getChipPowerLimits = ar5210GetChipPowerLimits,
+};
+
+static HAL_BOOL ar5210FillCapabilityInfo(struct ath_hal *ah);
+
+/*
+ * Attach for an AR5210 part.
+ */
+static struct ath_hal *
+ar5210Attach(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_5210 *ahp;
+ struct ath_hal *ah;
+ uint32_t revid, pcicfg;
+ uint16_t eeval;
+ HAL_STATUS ecode;
+ int i;
+
+ HALDEBUG(AH_NULL, HAL_DEBUG_ATTACH,
+ "%s: devid 0x%x sc %p st %p sh %p\n", __func__, devid,
+ sc, (void*) st, (void*) sh);
+
+ /* NB: memory is returned zero'd */
+ ahp = ath_hal_malloc(sizeof (struct ath_hal_5210));
+ if (ahp == AH_NULL) {
+ HALDEBUG(AH_NULL, HAL_DEBUG_ANY,
+ "%s: no memory for state block\n", __func__);
+ ecode = HAL_ENOMEM;
+ goto bad;
+ }
+ ah = &ahp->ah_priv.h;
+ /* set initial values */
+ OS_MEMCPY(&ahp->ah_priv, &ar5210hal, 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 = AR5210_MAX_RATE_POWER;
+ AH_PRIVATE(ah)->ah_tpScale = HAL_TP_SCALE_MAX; /* no scaling */
+
+ ah->ah_powerMode = HAL_PM_UNDEFINED;
+ 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 (!ar5210ChipReset(ah, AH_NULL)) { /* reset chip */
+ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n",
+ __func__);
+ ecode = HAL_EIO;
+ goto bad;
+ }
+
+ /* Read Revisions from Chips */
+ AH_PRIVATE(ah)->ah_macVersion = 1;
+ AH_PRIVATE(ah)->ah_macRev = OS_REG_READ(ah, AR_SREV) & 0xff;
+ AH_PRIVATE(ah)->ah_phyRev = OS_REG_READ(ah, AR_PHY_CHIPID);
+ AH_PRIVATE(ah)->ah_analog2GhzRev = 0;
+
+ /* Read Radio Chip Rev Extract */
+ OS_REG_WRITE(ah, (AR_PHY_BASE + (0x34 << 2)), 0x00001c16);
+ for (i = 0; i < 4; i++)
+ OS_REG_WRITE(ah, (AR_PHY_BASE + (0x20 << 2)), 0x00010000);
+ revid = (OS_REG_READ(ah, AR_PHY_BASE + (256 << 2)) >> 28) & 0xf;
+
+ /* Chip labelling is 1 greater than revision register for AR5110 */
+ AH_PRIVATE(ah)->ah_analog5GhzRev = ath_hal_reverseBits(revid, 4) + 1;
+
+ /*
+ * Read all the settings from the EEPROM and stash
+ * ones we'll use later.
+ */
+ pcicfg = OS_REG_READ(ah, AR_PCICFG);
+ OS_REG_WRITE(ah, AR_PCICFG, pcicfg | AR_PCICFG_EEPROMSEL);
+ ecode = ath_hal_v1EepromAttach(ah);
+ if (ecode != HAL_OK) {
+ goto eebad;
+ }
+ 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 eebad;
+ }
+ AH_PRIVATE(ah)->ah_currentRD = eeval;
+ 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 eebad;
+ }
+ OS_REG_WRITE(ah, AR_PCICFG, pcicfg); /* disable EEPROM access */
+
+ AH_PRIVATE(ah)->ah_getNfAdjust = ar5210GetNfAdjust;
+
+ /*
+ * Got everything we need now to setup the capabilities.
+ */
+ (void) ar5210FillCapabilityInfo(ah);
+
+ HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s: return\n", __func__);
+
+ return ah;
+eebad:
+ OS_REG_WRITE(ah, AR_PCICFG, pcicfg); /* disable EEPROM access */
+bad:
+ if (ahp)
+ ath_hal_free(ahp);
+ if (status)
+ *status = ecode;
+ return AH_NULL;
+#undef N
+}
+
+void
+ar5210Detach(struct ath_hal *ah)
+{
+ HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s:\n", __func__);
+
+ HALASSERT(ah != AH_NULL);
+ HALASSERT(ah->ah_magic == AR5210_MAGIC);
+
+ ath_hal_eepromDetach(ah);
+ ath_hal_free(ah);
+}
+
+/*
+ * Store the channel edges for the requested operational mode
+ */
+static HAL_BOOL
+ar5210GetChannelEdges(struct ath_hal *ah,
+ uint16_t flags, uint16_t *low, uint16_t *high)
+{
+ if (flags & IEEE80211_CHAN_5GHZ) {
+ *low = 5120;
+ *high = 5430;
+ return AH_TRUE;
+ } else {
+ return AH_FALSE;
+ }
+}
+
+static HAL_BOOL
+ar5210GetChipPowerLimits(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 = AR5210_MAX_RATE_POWER;
+ chan->ic_minpower = 0;
+ return AH_TRUE;
+}
+
+static void
+ar5210ConfigPCIE(struct ath_hal *ah, HAL_BOOL restore, HAL_BOOL power_off)
+{
+}
+
+static void
+ar5210DisablePCIE(struct ath_hal *ah)
+{
+}
+
+/*
+ * Fill all software cached or static hardware state information.
+ */
+static HAL_BOOL
+ar5210FillCapabilityInfo(struct ath_hal *ah)
+{
+ struct ath_hal_private *ahpriv = AH_PRIVATE(ah);
+ HAL_CAPABILITIES *pCap = &ahpriv->ah_caps;
+
+ pCap->halWirelessModes |= HAL_MODE_11A;
+
+ pCap->halLow5GhzChan = 5120;
+ pCap->halHigh5GhzChan = 5430;
+
+ pCap->halSleepAfterBeaconBroken = AH_TRUE;
+ pCap->halPSPollBroken = AH_FALSE;
+ pCap->halNumMRRetries = 1; /* No hardware MRR support */
+ pCap->halNumTxMaps = 1; /* Single TX ptr per descr */
+
+ pCap->halTotalQueues = HAL_NUM_TX_QUEUES;
+ pCap->halKeyCacheSize = 64;
+
+ /* 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)) {
+ /*
+ * Setup initial rfsilent settings based on the EEPROM
+ * contents. Pin 0, polarity 0 is fixed; record this
+ * using the EEPROM format found in later parts.
+ */
+ ahpriv->ah_rfsilent = SM(0, AR_EEPROM_RFSILENT_GPIO_SEL)
+ | SM(0, AR_EEPROM_RFSILENT_POLARITY);
+ ahpriv->ah_rfkillEnabled = AH_TRUE;
+ pCap->halRfSilentSupport = AH_TRUE;
+ }
+
+ pCap->halTxTstampPrecision = 16;
+ pCap->halRxTstampPrecision = 15; /* NB: s/w extended from 13 */
+ pCap->halIntrMask = (HAL_INT_COMMON - HAL_INT_BNR)
+ | HAL_INT_RX
+ | HAL_INT_TX
+ | HAL_INT_FATAL
+ ;
+
+ pCap->hal4kbSplitTransSupport = AH_TRUE;
+ pCap->halHasRxSelfLinkedTail = AH_TRUE;
+
+ ahpriv->ah_rxornIsFatal = AH_TRUE;
+ return AH_TRUE;
+}
+
+static const char*
+ar5210Probe(uint16_t vendorid, uint16_t devid)
+{
+ if (vendorid == ATHEROS_VENDOR_ID &&
+ (devid == AR5210_PROD || devid == AR5210_DEFAULT))
+ return "Atheros 5210";
+ return AH_NULL;
+}
+AH_CHIP(AR5210, ar5210Probe, ar5210Attach);
diff --git a/sys/dev/ath/ath_hal/ar5210/ar5210_beacon.c b/sys/dev/ath/ath_hal/ar5210/ar5210_beacon.c
new file mode 100644
index 000000000000..96c31ddc6d70
--- /dev/null
+++ b/sys/dev/ath/ath_hal/ar5210/ar5210_beacon.c
@@ -0,0 +1,202 @@
+/*-
+ * SPDX-License-Identifier: ISC
+ *
+ * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
+ * Copyright (c) 2002-2004 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 "ar5210/ar5210.h"
+#include "ar5210/ar5210reg.h"
+#include "ar5210/ar5210desc.h"
+
+/*
+ * Return the hardware NextTBTT in TSF
+ */
+uint64_t
+ar5210GetNextTBTT(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
+ar5210SetBeaconTimers(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
+ar5210BeaconInit(struct ath_hal *ah,
+ uint32_t next_beacon, uint32_t beacon_period)
+{
+ HAL_BEACON_TIMERS bt;
+
+ bt.bt_nexttbtt = next_beacon;
+
+ if (AH_PRIVATE(ah)->ah_opmode != HAL_M_STA) {
+ 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 */
+ /*
+ * The SWBA interrupt is not used for beacons in ad hoc mode
+ * as we don't yet support ATIMs. So since the beacon never
+ * changes, the beacon descriptor is set up once and read
+ * into a special HW buffer, from which it will be
+ * automagically retrieved at each DMA Beacon Alert (DBA).
+ */
+
+ /* Set the ATIM window */
+ bt.bt_nextatim = next_beacon + 0; /* NB: no ATIMs */
+ } else {
+ bt.bt_nextdba = ~0;
+ bt.bt_nextswba = ~0;
+ bt.bt_nextatim = 1;
+ }
+ bt.bt_intval = beacon_period &
+ (AR_BEACON_PERIOD | AR_BEACON_RESET_TSF | AR_BEACON_EN);
+ ar5210SetBeaconTimers(ah, &bt);
+}
+
+void
+ar5210ResetStaBeaconTimers(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_NO_PSPOLL; /* 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
+ *
+ * dtim_count and cfp_count from the current beacon - their current
+ * values aren't necessarily maintained in the device struct
+ */
+void
+ar5210SetStaBeaconTimers(struct ath_hal *ah, const HAL_BEACON_STATE *bs)
+{
+ struct ath_hal_5210 *ahp = AH5210(ah);
+
+ HALDEBUG(ah, HAL_DEBUG_BEACON, "%s: setting beacon timers\n", __func__);
+
+ HALASSERT(bs->bs_intval != 0);
+ /* if the AP will do PCF */
+ if (bs->bs_cfpmaxduration != 0) {
+ /* tell the h/w that the associated AP is PCF capable */
+ OS_REG_WRITE(ah, AR_STA_ID1,
+ (OS_REG_READ(ah, AR_STA_ID1) &~ AR_STA_ID1_DEFAULT_ANTENNA)
+ | AR_STA_ID1_PCF);
+
+ /* set CFP_PERIOD(1.024ms) register */
+ OS_REG_WRITE(ah, AR_CFP_PERIOD, bs->bs_cfpperiod);
+
+ /* set CFP_DUR(1.024ms) register to max cfp duration */
+ OS_REG_WRITE(ah, AR_CFP_DUR, bs->bs_cfpmaxduration);
+
+ /* set TIMER2(128us) to anticipated time of next CFP */
+ OS_REG_WRITE(ah, AR_TIMER2, bs->bs_cfpnext << 3);
+ } else {
+ /* tell the h/w that the associated AP is not PCF capable */
+ OS_REG_WRITE(ah, AR_STA_ID1,
+ OS_REG_READ(ah, AR_STA_ID1) &~ (AR_STA_ID1_DEFAULT_ANTENNA | AR_STA_ID1_PCF));
+ }
+
+ /*
+ * Set TIMER0(1.024ms) to the anticipated time of the next beacon.
+ */
+ OS_REG_WRITE(ah, AR_TIMER0, bs->bs_nexttbtt);
+
+ /*
+ * Start the beacon timers by setting the BEACON register
+ * to the beacon interval; also write the tim offset which
+ * we should know by now. The code, in ar5211WriteAssocid,
+ * also sets the tim offset once the AID is known which can
+ * be left as such for now.
+ */
+ OS_REG_WRITE(ah, AR_BEACON,
+ (OS_REG_READ(ah, AR_BEACON) &~ (AR_BEACON_PERIOD|AR_BEACON_TIM))
+ | SM(bs->bs_intval, AR_BEACON_PERIOD)
+ | SM(bs->bs_timoffset ? bs->bs_timoffset + 4 : 0, AR_BEACON_TIM)
+ );
+
+ /*
+ * Configure the BMISS interrupt. Note that we
+ * assume the caller blocks interrupts while enabling
+ * the threshold.
+ */
+
+ /*
+ * Interrupt works only on Crete.
+ */
+ if (AH_PRIVATE(ah)->ah_macRev < AR_SREV_CRETE)
+ return;
+ /*
+ * Counter is only 3-bits.
+ * Count of 0 with BMISS interrupt enabled will hang the system
+ * with too many interrupts
+ */
+ if (AH_PRIVATE(ah)->ah_macRev >= AR_SREV_CRETE &&
+ (bs->bs_bmissthreshold&7) == 0) {
+#ifdef AH_DEBUG
+ ath_hal_printf(ah, "%s: invalid beacon miss threshold %u\n",
+ __func__, bs->bs_bmissthreshold);
+#endif
+ return;
+ }
+#define BMISS_MAX (AR_RSSI_THR_BM_THR >> AR_RSSI_THR_BM_THR_S)
+ /*
+ * Configure the BMISS interrupt. Note that we
+ * assume the caller blocks interrupts while enabling
+ * the threshold.
+ *
+ * NB: the beacon miss count field is only 3 bits which
+ * is much smaller than what's found on later parts;
+ * clamp overflow values as a safeguard.
+ */
+ ahp->ah_rssiThr = (ahp->ah_rssiThr &~ AR_RSSI_THR_BM_THR)
+ | SM(bs->bs_bmissthreshold > BMISS_MAX ?
+ BMISS_MAX : bs->bs_bmissthreshold,
+ AR_RSSI_THR_BM_THR);
+ OS_REG_WRITE(ah, AR_RSSI_THR, ahp->ah_rssiThr);
+#undef BMISS_MAX
+}
diff --git a/sys/dev/ath/ath_hal/ar5210/ar5210_interrupts.c b/sys/dev/ath/ath_hal/ar5210/ar5210_interrupts.c
new file mode 100644
index 000000000000..63baafd11d9f
--- /dev/null
+++ b/sys/dev/ath/ath_hal/ar5210/ar5210_interrupts.c
@@ -0,0 +1,134 @@
+/*-
+ * SPDX-License-Identifier: ISC
+ *
+ * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
+ * Copyright (c) 2002-2004 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 "ar5210/ar5210.h"
+#include "ar5210/ar5210reg.h"
+
+/*
+ * Return non-zero if an interrupt is pending.
+ */
+HAL_BOOL
+ar5210IsInterruptPending(struct ath_hal *ah)
+{
+ return (OS_REG_READ(ah, AR_INTPEND) ? AH_TRUE : AH_FALSE);
+}
+
+/*
+ * Read the Interrupt Status Register value and return
+ * an abstracted bitmask of the data found in the ISR.
+ * Note that reading the ISR clear pending interrupts.
+ */
+HAL_BOOL
+ar5210GetPendingInterrupts(struct ath_hal *ah, HAL_INT *masked)
+{
+#define AR_FATAL_INT \
+ (AR_ISR_MCABT_INT | AR_ISR_SSERR_INT | AR_ISR_DPERR_INT | AR_ISR_RXORN_INT)
+ struct ath_hal_5210 *ahp = AH5210(ah);
+ uint32_t isr;
+
+ isr = OS_REG_READ(ah, AR_ISR);
+ if (isr == 0xffffffff) {
+ *masked = 0;
+ return AH_FALSE;
+ }
+
+ /*
+ * Mask interrupts that have no device-independent
+ * representation; these are added back below. We
+ * also masked with the abstracted IMR to insure no
+ * status bits leak through that weren't requested
+ * (e.g. RXNOFRM) and that might confuse the caller.
+ */
+ *masked = (isr & (HAL_INT_COMMON - HAL_INT_BNR)) & ahp->ah_maskReg;
+
+ if (isr & AR_FATAL_INT)
+ *masked |= HAL_INT_FATAL;
+ if (isr & (AR_ISR_RXOK_INT | AR_ISR_RXERR_INT))
+ *masked |= HAL_INT_RX;
+ if (isr & (AR_ISR_TXOK_INT | AR_ISR_TXDESC_INT | AR_ISR_TXERR_INT | AR_ISR_TXEOL_INT))
+ *masked |= HAL_INT_TX;
+
+ /*
+ * On fatal errors collect ISR state for debugging.
+ */
+ if (*masked & HAL_INT_FATAL) {
+ AH_PRIVATE(ah)->ah_fatalState[0] = isr;
+ }
+
+ return AH_TRUE;
+#undef AR_FATAL_INT
+}
+
+HAL_INT
+ar5210GetInterrupts(struct ath_hal *ah)
+{
+ return AH5210(ah)->ah_maskReg;
+}
+
+HAL_INT
+ar5210SetInterrupts(struct ath_hal *ah, HAL_INT ints)
+{
+ struct ath_hal_5210 *ahp = AH5210(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);
+ }
+
+ mask = ints & (HAL_INT_COMMON - HAL_INT_BNR);
+ if (ints & HAL_INT_RX)
+ mask |= AR_IMR_RXOK_INT | AR_IMR_RXERR_INT;
+ if (ints & HAL_INT_TX) {
+ if (ahp->ah_txOkInterruptMask)
+ mask |= AR_IMR_TXOK_INT;
+ if (ahp->ah_txErrInterruptMask)
+ mask |= AR_IMR_TXERR_INT;
+ if (ahp->ah_txDescInterruptMask)
+ mask |= AR_IMR_TXDESC_INT;
+ if (ahp->ah_txEolInterruptMask)
+ mask |= AR_IMR_TXEOL_INT;
+ }
+
+ /* 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/ar5210/ar5210_keycache.c b/sys/dev/ath/ath_hal/ar5210/ar5210_keycache.c
new file mode 100644
index 000000000000..4a04a2760902
--- /dev/null
+++ b/sys/dev/ath/ath_hal/ar5210/ar5210_keycache.c
@@ -0,0 +1,156 @@
+/*-
+ * SPDX-License-Identifier: ISC
+ *
+ * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
+ * Copyright (c) 2002-2004 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 "ar5210/ar5210.h"
+#include "ar5210/ar5210reg.h"
+
+#define AR_KEYTABLE_SIZE 64
+#define KEY_XOR 0xaa
+
+/*
+ * Return the size of the hardware key cache.
+ */
+u_int
+ar5210GetKeyCacheSize(struct ath_hal *ah)
+{
+ return AR_KEYTABLE_SIZE;
+}
+
+/*
+ * Return the size of the hardware key cache.
+ */
+HAL_BOOL
+ar5210IsKeyCacheEntryValid(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
+ar5210ResetKeyCacheEntry(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
+ar5210SetKeyCacheEntryMac(struct ath_hal *ah, uint16_t entry, const uint8_t *mac)
+{
+ uint32_t macHi, macLo;
+
+ if (entry < AR_KEYTABLE_SIZE) {
+ /*
+ * 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;
+ }
+ return AH_FALSE;
+}
+
+/*
+ * Sets the contents of the specified key cache entry.
+ */
+HAL_BOOL
+ar5210SetKeyCacheEntry(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)
+ return AH_FALSE;
+ if (k->kv_type != HAL_CIPHER_WEP) {
+ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: cipher %u not supported\n",
+ __func__, k->kv_type);
+ return AH_FALSE;
+ }
+
+ /* NB: only WEP supported */
+ if (k->kv_len < 40 / NBBY)
+ 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;
+
+ 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 ar5210SetKeyCacheEntryMac(ah, entry, mac);
+}
diff --git a/sys/dev/ath/ath_hal/ar5210/ar5210_misc.c b/sys/dev/ath/ath_hal/ar5210/ar5210_misc.c
new file mode 100644
index 000000000000..209dcfa9114a
--- /dev/null
+++ b/sys/dev/ath/ath_hal/ar5210/ar5210_misc.c
@@ -0,0 +1,733 @@
+/*-
+ * SPDX-License-Identifier: ISC
+ *
+ * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
+ * Copyright (c) 2002-2004 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 "ar5210/ar5210.h"
+#include "ar5210/ar5210reg.h"
+#include "ar5210/ar5210phy.h"
+
+#include "ah_eeprom_v1.h"
+
+#define AR_NUM_GPIO 6 /* 6 GPIO bits */
+#define AR_GPIOD_MASK 0x2f /* 6-bit mask */
+
+void
+ar5210GetMacAddress(struct ath_hal *ah, uint8_t *mac)
+{
+ struct ath_hal_5210 *ahp = AH5210(ah);
+
+ OS_MEMCPY(mac, ahp->ah_macaddr, IEEE80211_ADDR_LEN);
+}
+
+HAL_BOOL
+ar5210SetMacAddress(struct ath_hal *ah, const uint8_t *mac)
+{
+ struct ath_hal_5210 *ahp = AH5210(ah);
+
+ OS_MEMCPY(ahp->ah_macaddr, mac, IEEE80211_ADDR_LEN);
+ return AH_TRUE;
+}
+
+void
+ar5210GetBssIdMask(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
+ar5210SetBssIdMask(struct ath_hal *ah, const uint8_t *mask)
+{
+ return AH_FALSE;
+}
+
+/*
+ * Read 16 bits of data from the specified EEPROM offset.
+ */
+HAL_BOOL
+ar5210EepromRead(struct ath_hal *ah, u_int off, uint16_t *data)
+{
+ (void) OS_REG_READ(ah, AR_EP_AIR(off)); /* activate read op */
+ if (!ath_hal_wait(ah, AR_EP_STA,
+ AR_EP_STA_RDCMPLT | AR_EP_STA_RDERR, AR_EP_STA_RDCMPLT)) {
+ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: read failed for entry 0x%x\n",
+ __func__, AR_EP_AIR(off));
+ return AH_FALSE;
+ }
+ *data = OS_REG_READ(ah, AR_EP_RDATA) & 0xffff;
+ return AH_TRUE;
+}
+
+#ifdef AH_SUPPORT_WRITE_EEPROM
+/*
+ * Write 16 bits of data to the specified EEPROM offset.
+ */
+HAL_BOOL
+ar5210EepromWrite(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
+ar5210SetRegulatoryDomain(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;
+ }
+ ecode = HAL_EIO; /* disallow all writes */
+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
+ar5210GetWirelessModes(struct ath_hal *ah)
+{
+ /* XXX could enable turbo mode but can't do all rates */
+ return HAL_MODE_11A;
+}
+
+/*
+ * 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
+ar5210EnableRfKill(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);
+
+ /*
+ * If radio disable switch connection to GPIO bit 0 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 0 hardware
+ * connection is present.
+ */
+ ar5210Gpio0SetIntr(ah, select, (ar5210GpioGet(ah, select) == polarity));
+}
+
+/*
+ * Configure GPIO Output lines
+ */
+HAL_BOOL
+ar5210GpioCfgOutput(struct ath_hal *ah, uint32_t gpio, HAL_GPIO_MUX_TYPE type)
+{
+ HALASSERT(gpio < AR_NUM_GPIO);
+
+ OS_REG_WRITE(ah, AR_GPIOCR,
+ (OS_REG_READ(ah, AR_GPIOCR) &~ AR_GPIOCR_ALL(gpio))
+ | AR_GPIOCR_OUT1(gpio));
+
+ return AH_TRUE;
+}
+
+/*
+ * Configure GPIO Input lines
+ */
+HAL_BOOL
+ar5210GpioCfgInput(struct ath_hal *ah, uint32_t gpio)
+{
+ HALASSERT(gpio < AR_NUM_GPIO);
+
+ OS_REG_WRITE(ah, AR_GPIOCR,
+ (OS_REG_READ(ah, AR_GPIOCR) &~ AR_GPIOCR_ALL(gpio))
+ | AR_GPIOCR_IN(gpio));
+
+ return AH_TRUE;
+}
+
+/*
+ * Once configured for I/O - set output lines
+ */
+HAL_BOOL
+ar5210GpioSet(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
+ar5210GpioGet(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
+ */
+void
+ar5210Gpio0SetIntr(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_SEL(gpio) | AR_GPIOCR_INT_SELH | AR_GPIOCR_INT_ENA |
+ AR_GPIOCR_ALL(gpio));
+
+ val |= AR_GPIOCR_INT_SEL(gpio) | 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. */
+ ar5210SetInterrupts(ah, AH5210(ah)->ah_maskReg | HAL_INT_GPIO);
+}
+
+/*
+ * Change the LED blinking pattern to correspond to the connectivity
+ */
+void
+ar5210SetLedState(struct ath_hal *ah, HAL_LED_STATE state)
+{
+ uint32_t val;
+
+ val = OS_REG_READ(ah, AR_PCICFG);
+ switch (state) {
+ case HAL_LED_INIT:
+ val &= ~(AR_PCICFG_LED_PEND | AR_PCICFG_LED_ACT);
+ break;
+ case HAL_LED_RUN:
+ /* normal blink when connected */
+ val &= ~AR_PCICFG_LED_PEND;
+ val |= AR_PCICFG_LED_ACT;
+ break;
+ default:
+ val |= AR_PCICFG_LED_PEND;
+ val &= ~AR_PCICFG_LED_ACT;
+ break;
+ }
+ OS_REG_WRITE(ah, AR_PCICFG, val);
+}
+
+/*
+ * Return 1 or 2 for the corresponding antenna that is in use
+ */
+u_int
+ar5210GetDefAntenna(struct ath_hal *ah)
+{
+ uint32_t val = OS_REG_READ(ah, AR_STA_ID1);
+ return (val & AR_STA_ID1_DEFAULT_ANTENNA ? 2 : 1);
+}
+
+void
+ar5210SetDefAntenna(struct ath_hal *ah, u_int antenna)
+{
+ uint32_t val = OS_REG_READ(ah, AR_STA_ID1);
+
+ if (antenna != (val & AR_STA_ID1_DEFAULT_ANTENNA ? 2 : 1)) {
+ /*
+ * Antenna change requested, force a toggle of the default.
+ */
+ OS_REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_DEFAULT_ANTENNA);
+ }
+}
+
+HAL_ANT_SETTING
+ar5210GetAntennaSwitch(struct ath_hal *ah)
+{
+ return HAL_ANT_VARIABLE;
+}
+
+HAL_BOOL
+ar5210SetAntennaSwitch(struct ath_hal *ah, HAL_ANT_SETTING settings)
+{
+ /* XXX not sure how to fix antenna */
+ return (settings == HAL_ANT_VARIABLE);
+}
+
+/*
+ * 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
+ar5210WriteAssocid(struct ath_hal *ah, const uint8_t *bssid, uint16_t assocId)
+{
+ struct ath_hal_5210 *ahp = AH5210(ah);
+
+ /* XXX save bssid for possible re-use on reset */
+ OS_MEMCPY(ahp->ah_bssid, bssid, IEEE80211_ADDR_LEN);
+ ahp->ah_associd = assocId;
+ 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));
+ if (assocId == 0)
+ OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_NO_PSPOLL);
+ else
+ OS_REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_NO_PSPOLL);
+}
+
+/*
+ * Get the current hardware tsf for stamlme.
+ */
+uint64_t
+ar5210GetTsf64(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
+ar5210GetTsf32(struct ath_hal *ah)
+{
+ return OS_REG_READ(ah, AR_TSF_L32);
+}
+
+/*
+ * Reset the current hardware tsf for stamlme
+ */
+void
+ar5210ResetTsf(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
+ar5210GetRandomSeed(struct ath_hal *ah)
+{
+ uint32_t nf;
+
+ nf = (OS_REG_READ(ah, AR_PHY_BASE + (25 << 2)) >> 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
+ar5210DetectCardPresent(struct ath_hal *ah)
+{
+ /*
+ * 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.
+ */
+ return (AH_PRIVATE(ah)->ah_macRev == (OS_REG_READ(ah, AR_SREV) & 0xff));
+}
+
+/*
+ * Update MIB Counters
+ */
+void
+ar5210UpdateMibCounters(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
+ar5210SetSifsTime(struct ath_hal *ah, u_int us)
+{
+ struct ath_hal_5210 *ahp = AH5210(ah);
+
+ if (us > ath_hal_mac_usec(ah, 0x7ff)) {
+ 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_RMW_FIELD(ah, AR_IFS0, AR_IFS0_SIFS,
+ ath_hal_mac_clks(ah, us));
+ ahp->ah_sifstime = us;
+ return AH_TRUE;
+ }
+}
+
+u_int
+ar5210GetSifsTime(struct ath_hal *ah)
+{
+ u_int clks = OS_REG_READ(ah, AR_IFS0) & 0x7ff;
+ return ath_hal_mac_usec(ah, clks); /* convert from system clocks */
+}
+
+HAL_BOOL
+ar5210SetSlotTime(struct ath_hal *ah, u_int us)
+{
+ struct ath_hal_5210 *ahp = AH5210(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 = (u_int) -1; /* restore default handling */
+ return AH_FALSE;
+ } else {
+ /* convert to system clocks */
+ OS_REG_WRITE(ah, AR_SLOT_TIME, ath_hal_mac_clks(ah, us));
+ ahp->ah_slottime = us;
+ return AH_TRUE;
+ }
+}
+
+u_int
+ar5210GetSlotTime(struct ath_hal *ah)
+{
+ u_int clks = OS_REG_READ(ah, AR_SLOT_TIME) & 0xffff;
+ return ath_hal_mac_usec(ah, clks); /* convert from system clocks */
+}
+
+HAL_BOOL
+ar5210SetAckTimeout(struct ath_hal *ah, u_int us)
+{
+ struct ath_hal_5210 *ahp = AH5210(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
+ar5210GetAckTimeout(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
+ar5210GetAckCTSRate(struct ath_hal *ah)
+{
+ return ((AH5210(ah)->ah_staId1Defaults & AR_STA_ID1_ACKCTS_6MB) == 0);
+}
+
+HAL_BOOL
+ar5210SetAckCTSRate(struct ath_hal *ah, u_int high)
+{
+ struct ath_hal_5210 *ahp = AH5210(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
+ar5210SetCTSTimeout(struct ath_hal *ah, u_int us)
+{
+ struct ath_hal_5210 *ahp = AH5210(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
+ar5210GetCTSTimeout(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
+ar5210SetDecompMask(struct ath_hal *ah, uint16_t keyidx, int en)
+{
+ /* nothing to do */
+ return AH_TRUE;
+}
+
+void
+ar5210SetCoverageClass(struct ath_hal *ah, uint8_t coverageclass, int now)
+{
+}
+
+HAL_STATUS
+ar5210SetQuiet(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
+ar5210AniControl(struct ath_hal *ah, HAL_ANI_CMD cmd, int param)
+{
+ return AH_FALSE;
+}
+
+void
+ar5210RxMonitor(struct ath_hal *ah, const HAL_NODE_STATS *stats,
+ const struct ieee80211_channel *chan)
+{
+}
+
+void
+ar5210AniPoll(struct ath_hal *ah, const struct ieee80211_channel *chan)
+{
+}
+
+void
+ar5210MibEvent(struct ath_hal *ah, const HAL_NODE_STATS *stats)
+{
+}
+
+HAL_STATUS
+ar5210GetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type,
+ uint32_t capability, uint32_t *result)
+{
+
+ switch (type) {
+ case HAL_CAP_CIPHER: /* cipher handled in hardware */
+#if 0
+ return (capability == HAL_CIPHER_WEP ? HAL_OK : HAL_ENOTSUPP);
+#else
+ return HAL_ENOTSUPP;
+#endif
+ default:
+ return ath_hal_getcapability(ah, type, capability, result);
+ }
+}
+
+HAL_BOOL
+ar5210SetCapability(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
+ ar5210UpdateDiagReg(ah, AH_PRIVATE(ah)->ah_diagreg);
+ return AH_TRUE;
+ case HAL_CAP_RXORN_FATAL: /* HAL_INT_RXORN treated as fatal */
+ return AH_FALSE; /* NB: disallow */
+ default:
+ return ath_hal_setcapability(ah, type, capability,
+ setting, status);
+ }
+}
+
+HAL_BOOL
+ar5210GetDiagState(struct ath_hal *ah, int request,
+ const void *args, uint32_t argsize,
+ void **result, uint32_t *resultsize)
+{
+#ifdef AH_PRIVATE_DIAG
+ uint32_t pcicfg;
+ HAL_BOOL ok;
+
+ switch (request) {
+ case HAL_DIAG_EEPROM:
+ /* XXX */
+ break;
+ case HAL_DIAG_EEREAD:
+ if (argsize != sizeof(uint16_t))
+ return AH_FALSE;
+ pcicfg = OS_REG_READ(ah, AR_PCICFG);
+ OS_REG_WRITE(ah, AR_PCICFG, pcicfg | AR_PCICFG_EEPROMSEL);
+ ok = ath_hal_eepromRead(ah, *(const uint16_t *)args, *result);
+ OS_REG_WRITE(ah, AR_PCICFG, pcicfg);
+ if (ok)
+ *resultsize = sizeof(uint16_t);
+ return ok;
+ }
+#endif
+ return ath_hal_getdiagstate(ah, request,
+ args, argsize, result, resultsize);
+}
+
+/*
+ * Return what percentage of the extension channel is busy.
+ * This is always disabled for AR5210 series NICs.
+ */
+uint32_t
+ar5210Get11nExtBusy(struct ath_hal *ah)
+{
+
+ return (0);
+}
+
+/*
+ * There's no channel survey support for the AR5210.
+ */
+HAL_BOOL
+ar5210GetMibCycleCounts(struct ath_hal *ah, HAL_SURVEY_SAMPLE *hsample)
+{
+
+ return (AH_FALSE);
+}
+
+void
+ar5210SetChainMasks(struct ath_hal *ah, uint32_t txchainmask,
+ uint32_t rxchainmask)
+{
+}
+
+void
+ar5210EnableDfs(struct ath_hal *ah, HAL_PHYERR_PARAM *pe)
+{
+}
+
+void
+ar5210GetDfsThresh(struct ath_hal *ah, HAL_PHYERR_PARAM *pe)
+{
+}
+
+/*
+ * Update the diagnostic register.
+ *
+ * This merges in the diagnostic register setting with the default
+ * value, which may or may not involve disabling hardware encryption.
+ */
+void
+ar5210UpdateDiagReg(struct ath_hal *ah, uint32_t val)
+{
+
+ /* Disable all hardware encryption */
+ val |= AR_DIAG_SW_DIS_CRYPTO;
+ OS_REG_WRITE(ah, AR_DIAG_SW, val);
+}
+
+/*
+ * Get the current NAV value from the hardware.
+ */
+u_int
+ar5210GetNav(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
+ar5210SetNav(struct ath_hal *ah, u_int val)
+{
+
+ OS_REG_WRITE(ah, AR_NAV, val);
+}
+
diff --git a/sys/dev/ath/ath_hal/ar5210/ar5210_phy.c b/sys/dev/ath/ath_hal/ar5210/ar5210_phy.c
new file mode 100644
index 000000000000..10ac4fe49413
--- /dev/null
+++ b/sys/dev/ath/ath_hal/ar5210/ar5210_phy.c
@@ -0,0 +1,85 @@
+/*-
+ * SPDX-License-Identifier: ISC
+ *
+ * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
+ * Copyright (c) 2002-2004 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 "ar5210/ar5210.h"
+
+/* shorthands to compact tables for readability */
+#define OFDM IEEE80211_T_OFDM
+#define TURBO IEEE80211_T_TURBO
+
+HAL_RATE_TABLE ar5210_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 ar5210_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 }
+ },
+};
+
+#undef OFDM
+#undef TURBO
+
+const HAL_RATE_TABLE *
+ar5210GetRateTable(struct ath_hal *ah, u_int mode)
+{
+ HAL_RATE_TABLE *rt;
+ switch (mode) {
+ case HAL_MODE_11A:
+ rt = &ar5210_11a_table;
+ break;
+ case HAL_MODE_TURBO:
+ rt = &ar5210_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/ar5210/ar5210_power.c b/sys/dev/ath/ath_hal/ar5210/ar5210_power.c
new file mode 100644
index 000000000000..7aa5883ba2a8
--- /dev/null
+++ b/sys/dev/ath/ath_hal/ar5210/ar5210_power.c
@@ -0,0 +1,138 @@
+/*-
+ * SPDX-License-Identifier: ISC
+ *
+ * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
+ * Copyright (c) 2002-2004 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 "ar5210/ar5210.h"
+#include "ar5210/ar5210reg.h"
+
+/*
+ * Notify Power Mgt is disabled in self-generated frames.
+ * If requested, set Power Mode of chip to auto/normal.
+ */
+static void
+ar5210SetPowerModeAuto(struct ath_hal *ah, int setChip)
+{
+ OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SV);
+ if (setChip)
+ OS_REG_RMW_FIELD(ah, AR_SCR, AR_SCR_SLE, AR_SCR_SLE_ALLOW);
+}
+
+/*
+ * 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
+ar5210SetPowerModeAwake(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(2000); /* 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_SV);
+ return AH_TRUE;
+#undef POWER_UP_TIME
+}
+
+/*
+ * Notify Power Mgt is disabled in self-generated frames.
+ * If requested, force chip to sleep.
+ */
+static void
+ar5210SetPowerModeSleep(struct ath_hal *ah, int setChip)
+{
+ OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SV);
+ if (setChip)
+ OS_REG_RMW_FIELD(ah, AR_SCR, AR_SCR_SLE, AR_SCR_SLE_SLP);
+}
+
+HAL_BOOL
+ar5210SetPowerMode(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 = ar5210SetPowerModeAwake(ah, setChip);
+ break;
+ case HAL_PM_FULL_SLEEP:
+ ar5210SetPowerModeSleep(ah, setChip);
+ if (setChip)
+ ah->ah_powerMode = mode;
+ break;
+ case HAL_PM_NETWORK_SLEEP:
+ ar5210SetPowerModeAuto(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
+ar5210GetPowerMode(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/ar5210/ar5210_recv.c b/sys/dev/ath/ath_hal/ar5210/ar5210_recv.c
new file mode 100644
index 000000000000..47ea92688104
--- /dev/null
+++ b/sys/dev/ath/ath_hal/ar5210/ar5210_recv.c
@@ -0,0 +1,269 @@
+/*-
+ * SPDX-License-Identifier: ISC
+ *
+ * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
+ * Copyright (c) 2002-2004 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 "ar5210/ar5210.h"
+#include "ar5210/ar5210reg.h"
+#include "ar5210/ar5210desc.h"
+
+/*
+ * Get the RXDP.
+ */
+uint32_t
+ar5210GetRxDP(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
+ar5210SetRxDP(struct ath_hal *ah, uint32_t rxdp, HAL_RX_QUEUE qtype)
+{
+
+ HALASSERT(qtype == HAL_RX_QUEUE_HP);
+ OS_REG_WRITE(ah, AR_RXDP, rxdp);
+}
+
+/*
+ * Set Receive Enable bits.
+ */
+void
+ar5210EnableReceive(struct ath_hal *ah)
+{
+ OS_REG_WRITE(ah, AR_CR, AR_CR_RXE);
+}
+
+/*
+ * Stop Receive at the DMA engine
+ */
+HAL_BOOL
+ar5210StopDmaReceive(struct ath_hal *ah)
+{
+ int i;
+
+ OS_REG_WRITE(ah, AR_CR, AR_CR_RXD); /* Set receive disable bit */
+ for (i = 0; i < 1000; i++) {
+ if ((OS_REG_READ(ah, AR_CR) & AR_CR_RXE) == 0)
+ return AH_TRUE;
+ OS_DELAY(10);
+ }
+#ifdef AH_DEBUG
+ ath_hal_printf(ah, "ar5210: dma receive failed to stop in 10ms\n");
+ ath_hal_printf(ah, "AR_CR=0x%x\n", OS_REG_READ(ah, AR_CR));
+ ath_hal_printf(ah, "AR_DIAG_SW=0x%x\n", OS_REG_READ(ah, AR_DIAG_SW));
+#endif
+ return AH_FALSE;
+}
+
+/*
+ * Start Transmit at the PCU engine (unpause receive)
+ */
+void
+ar5210StartPcuReceive(struct ath_hal *ah, HAL_BOOL is_scanning)
+{
+ ar5210UpdateDiagReg(ah,
+ OS_REG_READ(ah, AR_DIAG_SW) & ~(AR_DIAG_SW_DIS_RX));
+}
+
+/*
+ * Stop Transmit at the PCU engine (pause receive)
+ */
+void
+ar5210StopPcuReceive(struct ath_hal *ah)
+{
+ ar5210UpdateDiagReg(ah,
+ 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
+ar5210SetMulticastFilter(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
+ar5210ClrMulticastFilterIndex(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
+ar5210SetMulticastFilterIndex(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;
+}
+
+/*
+ * Return the receive packet filter.
+ */
+uint32_t
+ar5210GetRxFilter(struct ath_hal *ah)
+{
+ /* XXX can't be sure if promiscuous mode is set because of PHYRADAR */
+ return OS_REG_READ(ah, AR_RX_FILTER);
+}
+
+/*
+ * Turn off/on bits in the receive packet filter.
+ */
+void
+ar5210SetRxFilter(struct ath_hal *ah, uint32_t bits)
+{
+ if (bits & HAL_RX_FILTER_PHYRADAR) {
+ /* must enable promiscuous mode to get radar */
+ bits = (bits &~ HAL_RX_FILTER_PHYRADAR) | AR_RX_FILTER_PROMISCUOUS;
+ }
+ 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
+ar5210SetupRxDesc(struct ath_hal *ah, struct ath_desc *ds,
+ uint32_t size, u_int flags)
+{
+ struct ar5210_desc *ads = AR5210DESC(ds);
+
+ (void) flags;
+
+ 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
+ar5210ProcRxDesc(struct ath_hal *ah, struct ath_desc *ds,
+ uint32_t pa, struct ath_desc *nds, uint64_t tsf,
+ struct ath_rx_status *rs)
+{
+ struct ar5210_desc *ads = AR5210DESC(ds);
+ struct ar5210_desc *ands = AR5210DESC(nds);
+ uint32_t now, rstamp;
+
+ 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;
+ rstamp = MS(ads->ds_status1, AR_RcvTimestamp);
+ /*
+ * Convert timestamp. The value in the
+ * descriptor is bits [10..22] of the TSF.
+ */
+ now = (OS_REG_READ(ah, AR_TSF_L32) >> 10) & 0xffff;
+ if ((now & 0x1fff) < rstamp)
+ rstamp |= (now - 0x2000) & 0xffff;
+ else
+ rstamp |= now;
+ /* NB: keep only 15 bits for consistency w/ other chips */
+ rs->rs_tstamp = rstamp & 0x7fff;
+ 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 if (ads->ds_status1 & AR_FIFOOverrun)
+ rs->rs_status |= HAL_RXERR_FIFO;
+ else {
+ rs->rs_status |= HAL_RXERR_PHY;
+ rs->rs_phyerr =
+ (ads->ds_status1 & AR_PHYErr) >> AR_PHYErr_S;
+ }
+ }
+ /* 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 = (ads->ds_status0 & AR_RcvAntenna) ? 1 : 0;
+ rs->rs_more = (ads->ds_status0 & AR_More) ? 1 : 0;
+
+ return HAL_OK;
+}
diff --git a/sys/dev/ath/ath_hal/ar5210/ar5210_reset.c b/sys/dev/ath/ath_hal/ar5210/ar5210_reset.c
new file mode 100644
index 000000000000..dc4f002164fa
--- /dev/null
+++ b/sys/dev/ath/ath_hal/ar5210/ar5210_reset.c
@@ -0,0 +1,1005 @@
+/*-
+ * SPDX-License-Identifier: ISC
+ *
+ * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
+ * Copyright (c) 2002-2004 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 "ar5210/ar5210.h"
+#include "ar5210/ar5210reg.h"
+#include "ar5210/ar5210phy.h"
+
+#include "ah_eeprom_v1.h"
+
+typedef struct {
+ uint32_t Offset;
+ uint32_t Value;
+} REGISTER_VAL;
+
+static const REGISTER_VAL ar5k0007_init[] = {
+#include "ar5210/ar5k_0007.ini"
+};
+
+/* Default Power Settings for channels outside of EEPROM range */
+static const uint8_t ar5k0007_pwrSettings[17] = {
+/* gain delta pc dac */
+/* 54 48 36 24 18 12 9 54 48 36 24 18 12 9 6 ob db */
+ 9, 9, 0, 0, 0, 0, 0, 2, 2, 6, 6, 6, 6, 6, 6, 2, 2
+};
+
+/*
+ * The delay, in usecs, between writing AR_RC with a reset
+ * request and waiting for the chip to settle. If this is
+ * too short then the chip does not come out of sleep state.
+ * Note this value was empirically derived and may be dependent
+ * on the host machine (don't know--the problem was identified
+ * on an IBM 570e laptop; 10us delays worked on other systems).
+ */
+#define AR_RC_SETTLE_TIME 20000
+
+static HAL_BOOL ar5210SetResetReg(struct ath_hal *,
+ uint32_t resetMask, u_int delay);
+static HAL_BOOL ar5210SetChannel(struct ath_hal *, struct ieee80211_channel *);
+static void ar5210SetOperatingMode(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
+ar5210Reset(struct ath_hal *ah, HAL_OPMODE opmode,
+ struct ieee80211_channel *chan, HAL_BOOL bChannelChange,
+ HAL_RESET_TYPE resetType,
+ HAL_STATUS *status)
+{
+#define N(a) (sizeof (a) /sizeof (a[0]))
+#define FAIL(_code) do { ecode = _code; goto bad; } while (0)
+ struct ath_hal_5210 *ahp = AH5210(ah);
+ const HAL_EEPROM_v1 *ee = AH_PRIVATE(ah)->ah_eeprom;
+ HAL_CHANNEL_INTERNAL *ichan;
+ HAL_STATUS ecode;
+ uint32_t ledstate;
+ int i, q;
+
+ 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");
+
+ if (!IEEE80211_IS_CHAN_5GHZ(chan)) {
+ /* Only 11a mode */
+ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: channel not 5GHz\n", __func__);
+ FAIL(HAL_EINVAL);
+ }
+ /*
+ * Map public channel to private.
+ */
+ ichan = ath_hal_checkchannel(ah, chan);
+ if (ichan == AH_NULL) {
+ HALDEBUG(ah, HAL_DEBUG_ANY,
+ "%s: invalid channel %u/0x%x; no mapping\n",
+ __func__, chan->ic_freq, chan->ic_flags);
+ FAIL(HAL_EINVAL);
+ }
+ switch (opmode) {
+ case HAL_M_STA:
+ case HAL_M_IBSS:
+ case HAL_M_HOSTAP:
+ case HAL_M_MONITOR:
+ break;
+ default:
+ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid operating mode %u\n",
+ __func__, opmode);
+ FAIL(HAL_EINVAL);
+ break;
+ }
+
+ ledstate = OS_REG_READ(ah, AR_PCICFG) &
+ (AR_PCICFG_LED_PEND | AR_PCICFG_LED_ACT);
+
+ if (!ar5210ChipReset(ah, chan)) {
+ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n",
+ __func__);
+ FAIL(HAL_EIO);
+ }
+
+ 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));
+ ar5210SetOperatingMode(ah, opmode);
+
+ switch (opmode) {
+ case HAL_M_HOSTAP:
+ OS_REG_WRITE(ah, AR_BCR, INIT_BCON_CNTRL_REG);
+ OS_REG_WRITE(ah, AR_PCICFG,
+ AR_PCICFG_LED_ACT | AR_PCICFG_LED_BCTL);
+ break;
+ case HAL_M_IBSS:
+ OS_REG_WRITE(ah, AR_BCR, INIT_BCON_CNTRL_REG | AR_BCR_BCMD);
+ OS_REG_WRITE(ah, AR_PCICFG,
+ AR_PCICFG_CLKRUNEN | AR_PCICFG_LED_PEND | AR_PCICFG_LED_BCTL);
+ break;
+ case HAL_M_STA:
+ OS_REG_WRITE(ah, AR_BCR, INIT_BCON_CNTRL_REG);
+ OS_REG_WRITE(ah, AR_PCICFG,
+ AR_PCICFG_CLKRUNEN | AR_PCICFG_LED_PEND | AR_PCICFG_LED_BCTL);
+ break;
+ case HAL_M_MONITOR:
+ OS_REG_WRITE(ah, AR_BCR, INIT_BCON_CNTRL_REG);
+ OS_REG_WRITE(ah, AR_PCICFG,
+ AR_PCICFG_LED_ACT | AR_PCICFG_LED_BCTL);
+ break;
+ }
+
+ /* Restore previous led state */
+ OS_REG_WRITE(ah, AR_PCICFG, OS_REG_READ(ah, AR_PCICFG) | ledstate);
+
+#if 0
+ 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));
+#endif
+ /* BSSID, association id, ps-poll */
+ ar5210WriteAssocid(ah, ahp->ah_bssid, ahp->ah_associd);
+
+ OS_REG_WRITE(ah, AR_TXDP0, 0);
+ OS_REG_WRITE(ah, AR_TXDP1, 0);
+ OS_REG_WRITE(ah, AR_RXDP, 0);
+
+ /*
+ * Initialize interrupt state.
+ */
+ (void) OS_REG_READ(ah, AR_ISR); /* cleared on read */
+ OS_REG_WRITE(ah, AR_IMR, 0);
+ OS_REG_WRITE(ah, AR_IER, AR_IER_DISABLE);
+ ahp->ah_maskReg = 0;
+
+ (void) OS_REG_READ(ah, AR_BSR); /* cleared on read */
+ OS_REG_WRITE(ah, AR_TXCFG, AR_DMASIZE_128B);
+ OS_REG_WRITE(ah, AR_RXCFG, AR_DMASIZE_128B);
+
+ OS_REG_WRITE(ah, AR_TOPS, 8); /* timeout prescale */
+ OS_REG_WRITE(ah, AR_RXNOFRM, 8); /* RX no frame timeout */
+ OS_REG_WRITE(ah, AR_RPGTO, 0); /* RX frame gap timeout */
+ OS_REG_WRITE(ah, AR_TXNOFRM, 0); /* TX no frame timeout */
+
+ OS_REG_WRITE(ah, AR_SFR, 0);
+ OS_REG_WRITE(ah, AR_MIBC, 0); /* unfreeze ctrs + clr state */
+ OS_REG_WRITE(ah, AR_RSSI_THR, ahp->ah_rssiThr);
+ OS_REG_WRITE(ah, AR_CFP_DUR, 0);
+
+ ar5210SetRxFilter(ah, 0); /* nothing for now */
+ OS_REG_WRITE(ah, AR_MCAST_FIL0, 0); /* multicast filter */
+ OS_REG_WRITE(ah, AR_MCAST_FIL1, 0); /* XXX was 2 */
+
+ OS_REG_WRITE(ah, AR_TX_MASK0, 0);
+ OS_REG_WRITE(ah, AR_TX_MASK1, 0);
+ OS_REG_WRITE(ah, AR_CLR_TMASK, 1);
+ OS_REG_WRITE(ah, AR_TRIG_LEV, 1); /* minimum */
+
+ ar5210UpdateDiagReg(ah, 0);
+
+ OS_REG_WRITE(ah, AR_CFP_PERIOD, 0);
+ OS_REG_WRITE(ah, AR_TIMER0, 0); /* next beacon time */
+ OS_REG_WRITE(ah, AR_TSF_L32, 0); /* local clock */
+ OS_REG_WRITE(ah, AR_TIMER1, ~0); /* next DMA beacon alert */
+ OS_REG_WRITE(ah, AR_TIMER2, ~0); /* next SW beacon alert */
+ OS_REG_WRITE(ah, AR_TIMER3, 1); /* next ATIM window */
+
+ /* Write the INI values for PHYreg initialization */
+ for (i = 0; i < N(ar5k0007_init); i++) {
+ uint32_t reg = ar5k0007_init[i].Offset;
+ /* On channel change, don't reset the PCU registers */
+ if (!(bChannelChange && (0x8000 <= reg && reg < 0x9000)))
+ OS_REG_WRITE(ah, reg, ar5k0007_init[i].Value);
+ }
+
+ /* Setup the transmit power values for cards since 0x0[0-2]05 */
+ if (!ar5210SetTransmitPower(ah, chan)) {
+ HALDEBUG(ah, HAL_DEBUG_ANY,
+ "%s: error init'ing transmit power\n", __func__);
+ FAIL(HAL_EIO);
+ }
+
+ OS_REG_WRITE(ah, AR_PHY(10),
+ (OS_REG_READ(ah, AR_PHY(10)) & 0xFFFF00FF) |
+ (ee->ee_xlnaOn << 8));
+ OS_REG_WRITE(ah, AR_PHY(13),
+ (ee->ee_xpaOff << 24) | (ee->ee_xpaOff << 16) |
+ (ee->ee_xpaOn << 8) | ee->ee_xpaOn);
+ OS_REG_WRITE(ah, AR_PHY(17),
+ (OS_REG_READ(ah, AR_PHY(17)) & 0xFFFFC07F) |
+ ((ee->ee_antenna >> 1) & 0x3F80));
+ OS_REG_WRITE(ah, AR_PHY(18),
+ (OS_REG_READ(ah, AR_PHY(18)) & 0xFFFC0FFF) |
+ ((ee->ee_antenna << 10) & 0x3F000));
+ OS_REG_WRITE(ah, AR_PHY(25),
+ (OS_REG_READ(ah, AR_PHY(25)) & 0xFFF80FFF) |
+ ((ee->ee_thresh62 << 12) & 0x7F000));
+ OS_REG_WRITE(ah, AR_PHY(68),
+ (OS_REG_READ(ah, AR_PHY(68)) & 0xFFFFFFFC) |
+ (ee->ee_antenna & 0x3));
+
+ if (!ar5210SetChannel(ah, chan)) {
+ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unable to set channel\n",
+ __func__);
+ FAIL(HAL_EIO);
+ }
+ if (bChannelChange && !IEEE80211_IS_CHAN_DFS(chan))
+ chan->ic_state &= ~IEEE80211_CHANSTATE_CWINT;
+
+ /* Activate the PHY */
+ OS_REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ENABLE);
+
+ OS_DELAY(1000); /* Wait a bit (1 msec) */
+
+ /* calibrate the HW and poll the bit going to 0 for completion */
+ OS_REG_WRITE(ah, AR_PHY_AGCCTL,
+ OS_REG_READ(ah, AR_PHY_AGCCTL) | AR_PHY_AGC_CAL);
+ (void) ath_hal_wait(ah, AR_PHY_AGCCTL, AR_PHY_AGC_CAL, 0);
+
+ /* Perform noise floor calibration and set status */
+ if (!ar5210CalNoiseFloor(ah, ichan)) {
+ chan->ic_state |= IEEE80211_CHANSTATE_CWINT;
+ HALDEBUG(ah, HAL_DEBUG_ANY,
+ "%s: noise floor calibration failed\n", __func__);
+ FAIL(HAL_EIO);
+ }
+
+ for (q = 0; q < HAL_NUM_TX_QUEUES; q++)
+ ar5210ResetTxQueue(ah, q);
+
+ if (AH_PRIVATE(ah)->ah_rfkillEnabled)
+ ar5210EnableRfKill(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)
+ ar5210SetSifsTime(ah, ahp->ah_sifstime);
+ if (ahp->ah_slottime != (u_int) -1)
+ ar5210SetSlotTime(ah, ahp->ah_slottime);
+ if (ahp->ah_acktimeout != (u_int) -1)
+ ar5210SetAckTimeout(ah, ahp->ah_acktimeout);
+ if (ahp->ah_ctstimeout != (u_int) -1)
+ ar5210SetCTSTimeout(ah, ahp->ah_ctstimeout);
+ if (AH_PRIVATE(ah)->ah_diagreg != 0)
+ ar5210UpdateDiagReg(ah, 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
+}
+
+static void
+ar5210SetOperatingMode(struct ath_hal *ah, int opmode)
+{
+ struct ath_hal_5210 *ahp = AH5210(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_AP
+ | AR_STA_ID1_NO_PSPOLL
+ | AR_STA_ID1_DESC_ANTENNA
+ | ahp->ah_staId1Defaults);
+ break;
+ case HAL_M_IBSS:
+ OS_REG_WRITE(ah, AR_STA_ID1, val
+ | AR_STA_ID1_ADHOC
+ | AR_STA_ID1_NO_PSPOLL
+ | AR_STA_ID1_DESC_ANTENNA
+ | ahp->ah_staId1Defaults);
+ break;
+ case HAL_M_STA:
+ OS_REG_WRITE(ah, AR_STA_ID1, val
+ | AR_STA_ID1_NO_PSPOLL
+ | AR_STA_ID1_PWR_SV
+ | ahp->ah_staId1Defaults);
+ break;
+ case HAL_M_MONITOR:
+ OS_REG_WRITE(ah, AR_STA_ID1, val
+ | AR_STA_ID1_NO_PSPOLL
+ | ahp->ah_staId1Defaults);
+ break;
+ }
+}
+
+void
+ar5210SetPCUConfig(struct ath_hal *ah)
+{
+ ar5210SetOperatingMode(ah, AH_PRIVATE(ah)->ah_opmode);
+}
+
+/*
+ * 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
+ar5210PhyDisable(struct ath_hal *ah)
+{
+ return ar5210SetResetReg(ah, AR_RC_RPHY, 10);
+}
+
+/*
+ * Places all of hardware into reset
+ */
+HAL_BOOL
+ar5210Disable(struct ath_hal *ah)
+{
+#define AR_RC_HW (AR_RC_RPCU | AR_RC_RDMA | AR_RC_RPHY | AR_RC_RMAC)
+ if (!ar5210SetPowerMode(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 (!ar5210SetResetReg(ah, AR_RC_HW, AR_RC_SETTLE_TIME))
+ return AH_FALSE;
+ OS_DELAY(1000);
+ (void) ar5210SetResetReg(ah, AR_RC_HW | AR_RC_RPCI, AR_RC_SETTLE_TIME);
+ OS_DELAY(2100); /* 8245 @ 96Mhz hangs with 2000us. */
+
+ return AH_TRUE;
+#undef AR_RC_HW
+}
+
+/*
+ * Places the hardware into reset and then pulls it out of reset
+ */
+HAL_BOOL
+ar5210ChipReset(struct ath_hal *ah, struct ieee80211_channel *chan)
+{
+#define AR_RC_HW (AR_RC_RPCU | AR_RC_RDMA | AR_RC_RPHY | AR_RC_RMAC)
+
+ HALDEBUG(ah, HAL_DEBUG_RESET, "%s turbo %s\n", __func__,
+ chan && IEEE80211_IS_CHAN_TURBO(chan) ?
+ "enabled" : "disabled");
+
+ if (!ar5210SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE))
+ return AH_FALSE;
+
+ /* Place chip in turbo before reset to cleanly reset clocks */
+ OS_REG_WRITE(ah, AR_PHY_FRCTL,
+ chan && IEEE80211_IS_CHAN_TURBO(chan) ? AR_PHY_TURBO_MODE : 0);
+
+ /*
+ * Reset the HW.
+ * PCI must be reset after the rest of the device has been reset.
+ */
+ if (!ar5210SetResetReg(ah, AR_RC_HW, AR_RC_SETTLE_TIME))
+ return AH_FALSE;
+ OS_DELAY(1000);
+ if (!ar5210SetResetReg(ah, AR_RC_HW | AR_RC_RPCI, AR_RC_SETTLE_TIME))
+ return AH_FALSE;
+ OS_DELAY(2100); /* 8245 @ 96Mhz hangs with 2000us. */
+
+ /*
+ * Bring out of sleep mode (AGAIN)
+ *
+ * WARNING WARNING WARNING
+ *
+ * There is a problem with the chip where it doesn't always indicate
+ * that it's awake, so initializePowerUp() will fail.
+ */
+ if (!ar5210SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE))
+ return AH_FALSE;
+
+ /* Clear warm reset reg */
+ return ar5210SetResetReg(ah, 0, 10);
+#undef AR_RC_HW
+}
+
+enum {
+ FIRPWR_M = 0x03fc0000,
+ FIRPWR_S = 18,
+ KCOARSEHIGH_M = 0x003f8000,
+ KCOARSEHIGH_S = 15,
+ KCOARSELOW_M = 0x00007f80,
+ KCOARSELOW_S = 7,
+ ADCSAT_ICOUNT_M = 0x0001f800,
+ ADCSAT_ICOUNT_S = 11,
+ ADCSAT_THRESH_M = 0x000007e0,
+ ADCSAT_THRESH_S = 5
+};
+
+/*
+ * Recalibrate the lower PHY chips to account for temperature/environment
+ * changes.
+ */
+HAL_BOOL
+ar5210PerCalibrationN(struct ath_hal *ah,
+ struct ieee80211_channel *chan, u_int chainMask,
+ HAL_BOOL longCal, HAL_BOOL *isCalDone)
+{
+ uint32_t regBeacon;
+ uint32_t reg9858, reg985c, reg9868;
+ HAL_CHANNEL_INTERNAL *ichan;
+
+ ichan = ath_hal_checkchannel(ah, chan);
+ if (ichan == AH_NULL)
+ return AH_FALSE;
+ /* Disable tx and rx */
+ ar5210UpdateDiagReg(ah,
+ OS_REG_READ(ah, AR_DIAG_SW) | (AR_DIAG_SW_DIS_TX | AR_DIAG_SW_DIS_RX));
+
+ /* Disable Beacon Enable */
+ regBeacon = OS_REG_READ(ah, AR_BEACON);
+ OS_REG_WRITE(ah, AR_BEACON, regBeacon & ~AR_BEACON_EN);
+
+ /* Delay 4ms to ensure that all tx and rx activity has ceased */
+ OS_DELAY(4000);
+
+ /* Disable AGC to radio traffic */
+ OS_REG_WRITE(ah, 0x9808, OS_REG_READ(ah, 0x9808) | 0x08000000);
+ /* Wait for the AGC traffic to cease. */
+ OS_DELAY(10);
+
+ /* Change Channel to relock synth */
+ if (!ar5210SetChannel(ah, chan))
+ return AH_FALSE;
+
+ /* wait for the synthesizer lock to stabilize */
+ OS_DELAY(1000);
+
+ /* Re-enable AGC to radio traffic */
+ OS_REG_WRITE(ah, 0x9808, OS_REG_READ(ah, 0x9808) & (~0x08000000));
+
+ /*
+ * Configure the AGC so that it is highly unlikely (if not
+ * impossible) for it to send any gain changes to the analog
+ * chip. We store off the current values so that they can
+ * be rewritten below. Setting the following values:
+ * firpwr = -1
+ * Kcoursehigh = -1
+ * Kcourselow = -127
+ * ADCsat_icount = 2
+ * ADCsat_thresh = 12
+ */
+ reg9858 = OS_REG_READ(ah, 0x9858);
+ reg985c = OS_REG_READ(ah, 0x985c);
+ reg9868 = OS_REG_READ(ah, 0x9868);
+
+ OS_REG_WRITE(ah, 0x9858, (reg9858 & ~FIRPWR_M) |
+ ((-1 << FIRPWR_S) & FIRPWR_M));
+ OS_REG_WRITE(ah, 0x985c,
+ (reg985c & ~(KCOARSEHIGH_M | KCOARSELOW_M)) |
+ ((-1 << KCOARSEHIGH_S) & KCOARSEHIGH_M) |
+ ((-127 << KCOARSELOW_S) & KCOARSELOW_M));
+ OS_REG_WRITE(ah, 0x9868,
+ (reg9868 & ~(ADCSAT_ICOUNT_M | ADCSAT_THRESH_M)) |
+ ((2 << ADCSAT_ICOUNT_S) & ADCSAT_ICOUNT_M) |
+ ((12 << ADCSAT_THRESH_S) & ADCSAT_THRESH_M));
+
+ /* Wait for AGC changes to be enacted */
+ OS_DELAY(20);
+
+ /*
+ * We disable RF mix/gain stages for the PGA to avoid a
+ * race condition that will occur with receiving a frame
+ * and performing the AGC calibration. This will be
+ * re-enabled at the end of offset cal. We turn off AGC
+ * writes during this write as it will go over the analog bus.
+ */
+ OS_REG_WRITE(ah, 0x9808, OS_REG_READ(ah, 0x9808) | 0x08000000);
+ OS_DELAY(10); /* wait for the AGC traffic to cease */
+ OS_REG_WRITE(ah, 0x98D4, 0x21);
+ OS_REG_WRITE(ah, 0x9808, OS_REG_READ(ah, 0x9808) & (~0x08000000));
+
+ /* wait to make sure that additional AGC traffic has quiesced */
+ OS_DELAY(1000);
+
+ /* AGC calibration (this was added to make the NF threshold check work) */
+ OS_REG_WRITE(ah, AR_PHY_AGCCTL,
+ OS_REG_READ(ah, AR_PHY_AGCCTL) | AR_PHY_AGC_CAL);
+ if (!ath_hal_wait(ah, AR_PHY_AGCCTL, AR_PHY_AGC_CAL, 0)) {
+ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: AGC calibration timeout\n",
+ __func__);
+ }
+
+ /* Rewrite our AGC values we stored off earlier (return AGC to normal operation) */
+ OS_REG_WRITE(ah, 0x9858, reg9858);
+ OS_REG_WRITE(ah, 0x985c, reg985c);
+ OS_REG_WRITE(ah, 0x9868, reg9868);
+
+ /* Perform noise floor and set status */
+ if (!ar5210CalNoiseFloor(ah, ichan)) {
+ /*
+ * Delay 5ms before retrying the noise floor -
+ * just to make sure. We're in an error
+ * condition here
+ */
+ HALDEBUG(ah, HAL_DEBUG_NFCAL | HAL_DEBUG_PERCAL,
+ "%s: Performing 2nd Noise Cal\n", __func__);
+ OS_DELAY(5000);
+ if (!ar5210CalNoiseFloor(ah, ichan))
+ chan->ic_state |= IEEE80211_CHANSTATE_CWINT;
+ }
+
+ /* Clear tx and rx disable bit */
+ ar5210UpdateDiagReg(ah,
+ OS_REG_READ(ah, AR_DIAG_SW) & ~(AR_DIAG_SW_DIS_TX | AR_DIAG_SW_DIS_RX));
+
+ /* Re-enable Beacons */
+ OS_REG_WRITE(ah, AR_BEACON, regBeacon);
+
+ *isCalDone = AH_TRUE;
+
+ return AH_TRUE;
+}
+
+HAL_BOOL
+ar5210PerCalibration(struct ath_hal *ah, struct ieee80211_channel *chan,
+ HAL_BOOL *isIQdone)
+{
+ return ar5210PerCalibrationN(ah, chan, 0x1, AH_TRUE, isIQdone);
+}
+
+HAL_BOOL
+ar5210ResetCalValid(struct ath_hal *ah, const struct ieee80211_channel *chan)
+{
+ return AH_TRUE;
+}
+
+/*
+ * Writes the given reset bit mask into the reset register
+ */
+static HAL_BOOL
+ar5210SetResetReg(struct ath_hal *ah, uint32_t resetMask, u_int delay)
+{
+ uint32_t mask = resetMask ? resetMask : ~0;
+ HAL_BOOL rt;
+
+ OS_REG_WRITE(ah, AR_RC, resetMask);
+ /* need to wait at least 128 clocks when reseting PCI before read */
+ OS_DELAY(delay);
+
+ resetMask &= AR_RC_RPCU | AR_RC_RDMA | AR_RC_RPHY | AR_RC_RMAC;
+ mask &= AR_RC_RPCU | AR_RC_RDMA | AR_RC_RPHY | AR_RC_RMAC;
+ rt = ath_hal_wait(ah, AR_RC, mask, resetMask);
+ if ((resetMask & AR_RC_RMAC) == 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;
+}
+
+/*
+ * Returns: the pcdac value
+ */
+static uint8_t
+getPcdac(struct ath_hal *ah, const struct tpcMap *pRD, uint8_t dBm)
+{
+ int32_t i;
+ int useNextEntry = AH_FALSE;
+ uint32_t interp;
+
+ for (i = AR_TP_SCALING_ENTRIES - 1; i >= 0; i--) {
+ /* Check for exact entry */
+ if (dBm == AR_I2DBM(i)) {
+ if (pRD->pcdac[i] != 63)
+ return pRD->pcdac[i];
+ useNextEntry = AH_TRUE;
+ } else if (dBm + 1 == AR_I2DBM(i) && i > 0) {
+ /* Interpolate for between entry with a logish scale */
+ if (pRD->pcdac[i] != 63 && pRD->pcdac[i-1] != 63) {
+ interp = (350 * (pRD->pcdac[i] - pRD->pcdac[i-1])) + 999;
+ interp = (interp / 1000) + pRD->pcdac[i-1];
+ return interp;
+ }
+ useNextEntry = AH_TRUE;
+ } else if (useNextEntry == AH_TRUE) {
+ /* Grab the next lowest */
+ if (pRD->pcdac[i] != 63)
+ return pRD->pcdac[i];
+ }
+ }
+
+ /* Return the lowest Entry if we haven't returned */
+ for (i = 0; i < AR_TP_SCALING_ENTRIES; i++)
+ if (pRD->pcdac[i] != 63)
+ return pRD->pcdac[i];
+
+ /* No value to return from table */
+#ifdef AH_DEBUG
+ ath_hal_printf(ah, "%s: empty transmit power table?\n", __func__);
+#endif
+ return 1;
+}
+
+/*
+ * Find or interpolates the gainF value from the table ptr.
+ */
+static uint8_t
+getGainF(struct ath_hal *ah, const struct tpcMap *pRD,
+ uint8_t pcdac, uint8_t *dBm)
+{
+ uint32_t interp;
+ int low, high, i;
+
+ low = high = -1;
+
+ for (i = 0; i < AR_TP_SCALING_ENTRIES; i++) {
+ if(pRD->pcdac[i] == 63)
+ continue;
+ if (pcdac == pRD->pcdac[i]) {
+ *dBm = AR_I2DBM(i);
+ return pRD->gainF[i]; /* Exact Match */
+ }
+ if (pcdac > pRD->pcdac[i])
+ low = i;
+ if (pcdac < pRD->pcdac[i]) {
+ high = i;
+ if (low == -1) {
+ *dBm = AR_I2DBM(i);
+ /* PCDAC is lower than lowest setting */
+ return pRD->gainF[i];
+ }
+ break;
+ }
+ }
+ if (i >= AR_TP_SCALING_ENTRIES && low == -1) {
+ /* No settings were found */
+#ifdef AH_DEBUG
+ ath_hal_printf(ah,
+ "%s: no valid entries in the pcdac table: %d\n",
+ __func__, pcdac);
+#endif
+ return 63;
+ }
+ if (i >= AR_TP_SCALING_ENTRIES) {
+ /* PCDAC setting was above the max setting in the table */
+ *dBm = AR_I2DBM(low);
+ return pRD->gainF[low];
+ }
+ /* Only exact if table has no missing entries */
+ *dBm = (low + high) + 3;
+
+ /*
+ * Perform interpolation between low and high values to find gainF
+ * linearly scale the pcdac between low and high
+ */
+ interp = ((pcdac - pRD->pcdac[low]) * 1000) /
+ (pRD->pcdac[high] - pRD->pcdac[low]);
+ /*
+ * Multiply the scale ratio by the gainF difference
+ * (plus a rnd up factor)
+ */
+ interp = ((interp * (pRD->gainF[high] - pRD->gainF[low])) + 999) / 1000;
+
+ /* Add ratioed gain_f to low gain_f value */
+ return interp + pRD->gainF[low];
+}
+
+HAL_BOOL
+ar5210SetTxPowerLimit(struct ath_hal *ah, uint32_t limit)
+{
+ AH_PRIVATE(ah)->ah_powerLimit = AH_MIN(limit, AR5210_MAX_RATE_POWER);
+ /* XXX flush to h/w */
+ return AH_TRUE;
+}
+
+/*
+ * Get TXPower values and set them in the radio
+ */
+static HAL_BOOL
+setupPowerSettings(struct ath_hal *ah, const struct ieee80211_channel *chan,
+ uint8_t cp[17])
+{
+ uint16_t freq = ath_hal_gethwchannel(ah, chan);
+ const HAL_EEPROM_v1 *ee = AH_PRIVATE(ah)->ah_eeprom;
+ uint8_t gainFRD, gainF36, gainF48, gainF54;
+ uint8_t dBmRD, dBm36, dBm48, dBm54, dontcare;
+ uint32_t rd, group;
+ const struct tpcMap *pRD;
+
+ /* Set OB/DB Values regardless of channel */
+ cp[15] = (ee->ee_biasCurrents >> 4) & 0x7;
+ cp[16] = ee->ee_biasCurrents & 0x7;
+
+ if (freq < 5170 || freq > 5320) {
+ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel %u\n",
+ __func__, freq);
+ return AH_FALSE;
+ }
+
+ HALASSERT(ee->ee_version >= AR_EEPROM_VER1 &&
+ ee->ee_version < AR_EEPROM_VER3);
+
+ /* Match regulatory domain */
+ for (rd = 0; rd < AR_REG_DOMAINS_MAX; rd++)
+ if (AH_PRIVATE(ah)->ah_currentRD == ee->ee_regDomain[rd])
+ break;
+ if (rd == AR_REG_DOMAINS_MAX) {
+#ifdef AH_DEBUG
+ ath_hal_printf(ah,
+ "%s: no calibrated regulatory domain matches the "
+ "current regularly domain (0x%0x)\n", __func__,
+ AH_PRIVATE(ah)->ah_currentRD);
+#endif
+ return AH_FALSE;
+ }
+ group = ((freq - 5170) / 10);
+
+ if (group > 11) {
+ /* Pull 5.29 into the 5.27 group */
+ group--;
+ }
+
+ /* Integer divide will set group from 0 to 4 */
+ group = group / 3;
+ pRD = &ee->ee_tpc[group];
+
+ /* Set PC DAC Values */
+ cp[14] = pRD->regdmn[rd];
+ cp[9] = AH_MIN(pRD->regdmn[rd], pRD->rate36);
+ cp[8] = AH_MIN(pRD->regdmn[rd], pRD->rate48);
+ cp[7] = AH_MIN(pRD->regdmn[rd], pRD->rate54);
+
+ /* Find Corresponding gainF values for RD, 36, 48, 54 */
+ gainFRD = getGainF(ah, pRD, pRD->regdmn[rd], &dBmRD);
+ gainF36 = getGainF(ah, pRD, cp[9], &dBm36);
+ gainF48 = getGainF(ah, pRD, cp[8], &dBm48);
+ gainF54 = getGainF(ah, pRD, cp[7], &dBm54);
+
+ /* Power Scale if requested */
+ if (AH_PRIVATE(ah)->ah_tpScale != HAL_TP_SCALE_MAX) {
+ static const uint16_t tpcScaleReductionTable[5] =
+ { 0, 3, 6, 9, AR5210_MAX_RATE_POWER };
+ uint16_t tpScale;
+
+ tpScale = tpcScaleReductionTable[AH_PRIVATE(ah)->ah_tpScale];
+ if (dBmRD < tpScale+3)
+ dBmRD = 3; /* min */
+ else
+ dBmRD -= tpScale;
+ cp[14] = getPcdac(ah, pRD, dBmRD);
+ gainFRD = getGainF(ah, pRD, cp[14], &dontcare);
+ dBm36 = AH_MIN(dBm36, dBmRD);
+ cp[9] = getPcdac(ah, pRD, dBm36);
+ gainF36 = getGainF(ah, pRD, cp[9], &dontcare);
+ dBm48 = AH_MIN(dBm48, dBmRD);
+ cp[8] = getPcdac(ah, pRD, dBm48);
+ gainF48 = getGainF(ah, pRD, cp[8], &dontcare);
+ dBm54 = AH_MIN(dBm54, dBmRD);
+ cp[7] = getPcdac(ah, pRD, dBm54);
+ gainF54 = getGainF(ah, pRD, cp[7], &dontcare);
+ }
+ /* Record current dBm at rate 6 */
+ AH_PRIVATE(ah)->ah_maxPowerLevel = 2*dBmRD;
+
+ cp[13] = cp[12] = cp[11] = cp[10] = cp[14];
+
+ /* Set GainF Values */
+ cp[0] = gainFRD - gainF54;
+ cp[1] = gainFRD - gainF48;
+ cp[2] = gainFRD - gainF36;
+ /* 9, 12, 18, 24 have no gain_delta from 6 */
+ cp[3] = cp[4] = cp[5] = cp[6] = 0;
+ return AH_TRUE;
+}
+
+/*
+ * 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
+ */
+HAL_BOOL
+ar5210SetTransmitPower(struct ath_hal *ah, const struct ieee80211_channel *chan)
+{
+#define N(a) (sizeof (a) / sizeof (a[0]))
+ static const uint32_t pwr_regs_start[17] = {
+ 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xf0000000,
+ 0xcc000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x0a000000, 0x000000e2,
+ 0x0a000020, 0x01000002, 0x01000018,
+ 0x40000000, 0x00000418
+ };
+ uint16_t i;
+ uint8_t cp[sizeof(ar5k0007_pwrSettings)];
+ uint32_t pwr_regs[17];
+
+ OS_MEMCPY(pwr_regs, pwr_regs_start, sizeof(pwr_regs));
+ OS_MEMCPY(cp, ar5k0007_pwrSettings, sizeof(cp));
+
+ /* Check the EEPROM tx power calibration settings */
+ if (!setupPowerSettings(ah, chan, cp)) {
+#ifdef AH_DEBUG
+ ath_hal_printf(ah, "%s: unable to setup power settings\n",
+ __func__);
+#endif
+ return AH_FALSE;
+ }
+ if (cp[15] < 1 || cp[15] > 5) {
+#ifdef AH_DEBUG
+ ath_hal_printf(ah, "%s: OB out of range (%u)\n",
+ __func__, cp[15]);
+#endif
+ return AH_FALSE;
+ }
+ if (cp[16] < 1 || cp[16] > 5) {
+#ifdef AH_DEBUG
+ ath_hal_printf(ah, "%s: DB out of range (%u)\n",
+ __func__, cp[16]);
+#endif
+ return AH_FALSE;
+ }
+
+ /* reverse bits of the transmit power array */
+ for (i = 0; i < 7; i++)
+ cp[i] = ath_hal_reverseBits(cp[i], 5);
+ for (i = 7; i < 15; i++)
+ cp[i] = ath_hal_reverseBits(cp[i], 6);
+
+ /* merge transmit power values into the register - quite gross */
+ pwr_regs[0] |= ((cp[1] << 5) & 0xE0) | (cp[0] & 0x1F);
+ pwr_regs[1] |= ((cp[3] << 7) & 0x80) | ((cp[2] << 2) & 0x7C) |
+ ((cp[1] >> 3) & 0x03);
+ pwr_regs[2] |= ((cp[4] << 4) & 0xF0) | ((cp[3] >> 1) & 0x0F);
+ pwr_regs[3] |= ((cp[6] << 6) & 0xC0) | ((cp[5] << 1) & 0x3E) |
+ ((cp[4] >> 4) & 0x01);
+ pwr_regs[4] |= ((cp[7] << 3) & 0xF8) | ((cp[6] >> 2) & 0x07);
+ pwr_regs[5] |= ((cp[9] << 7) & 0x80) | ((cp[8] << 1) & 0x7E) |
+ ((cp[7] >> 5) & 0x01);
+ pwr_regs[6] |= ((cp[10] << 5) & 0xE0) | ((cp[9] >> 1) & 0x1F);
+ pwr_regs[7] |= ((cp[11] << 3) & 0xF8) | ((cp[10] >> 3) & 0x07);
+ pwr_regs[8] |= ((cp[12] << 1) & 0x7E) | ((cp[11] >> 5) & 0x01);
+ pwr_regs[9] |= ((cp[13] << 5) & 0xE0);
+ pwr_regs[10] |= ((cp[14] << 3) & 0xF8) | ((cp[13] >> 3) & 0x07);
+ pwr_regs[11] |= ((cp[14] >> 5) & 0x01);
+
+ /* Set OB */
+ pwr_regs[8] |= (ath_hal_reverseBits(cp[15], 3) << 7) & 0x80;
+ pwr_regs[9] |= (ath_hal_reverseBits(cp[15], 3) >> 1) & 0x03;
+
+ /* Set DB */
+ pwr_regs[9] |= (ath_hal_reverseBits(cp[16], 3) << 2) & 0x1C;
+
+ /* Write the registers */
+ for (i = 0; i < N(pwr_regs)-1; i++)
+ OS_REG_WRITE(ah, 0x0000989c, pwr_regs[i]);
+ /* last write is a flush */
+ OS_REG_WRITE(ah, 0x000098d4, pwr_regs[i]);
+
+ return AH_TRUE;
+#undef N
+}
+
+/*
+ * 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
+ar5210SetChannel(struct ath_hal *ah, struct ieee80211_channel *chan)
+{
+ uint16_t freq = ath_hal_gethwchannel(ah, chan);
+ uint32_t data;
+
+ /* Set the Channel */
+ data = ath_hal_reverseBits((freq - 5120)/10, 5);
+ data = (data << 1) | 0x41;
+ OS_REG_WRITE(ah, AR_PHY(0x27), data);
+ OS_REG_WRITE(ah, AR_PHY(0x30), 0);
+ AH_PRIVATE(ah)->ah_curchan = chan;
+ return AH_TRUE;
+}
+
+int16_t
+ar5210GetNoiseFloor(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;
+}
+
+#define NORMAL_NF_THRESH (-72)
+/*
+ * Peform the noisefloor calibration and check for
+ * any constant channel interference
+ *
+ * Returns: TRUE for a successful noise floor calibration; else FALSE
+ */
+HAL_BOOL
+ar5210CalNoiseFloor(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan)
+{
+ int32_t nf, nfLoops;
+
+ /* Calibrate the noise floor */
+ OS_REG_WRITE(ah, AR_PHY_AGCCTL,
+ OS_REG_READ(ah, AR_PHY_AGCCTL) | AR_PHY_AGC_NF);
+
+ /* Do not read noise floor until it has done the first update */
+ if (!ath_hal_wait(ah, AR_PHY_AGCCTL, AR_PHY_AGC_NF, 0)) {
+#ifdef ATH_HAL_DEBUG
+ ath_hal_printf(ah, " -PHY NF Reg state: 0x%x\n",
+ OS_REG_READ(ah, AR_PHY_AGCCTL));
+ ath_hal_printf(ah, " -MAC Reset Reg state: 0x%x\n",
+ OS_REG_READ(ah, AR_RC));
+ ath_hal_printf(ah, " -PHY Active Reg state: 0x%x\n",
+ OS_REG_READ(ah, AR_PHY_ACTIVE));
+#endif /* ATH_HAL_DEBUG */
+ return AH_FALSE;
+ }
+
+ nf = 0;
+ /* Keep checking until the floor is below the threshold or the nf is done */
+ for (nfLoops = 0; ((nfLoops < 21) && (nf > NORMAL_NF_THRESH)); nfLoops++) {
+ OS_DELAY(1000); /* Sleep for 1 ms */
+ nf = ar5210GetNoiseFloor(ah);
+ }
+
+ if (nf > NORMAL_NF_THRESH) {
+ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: Bad noise cal %d\n",
+ __func__, nf);
+ ichan->rawNoiseFloor = 0;
+ return AH_FALSE;
+ }
+ ichan->rawNoiseFloor = nf;
+ return AH_TRUE;
+}
+
+/*
+ * Adjust NF based on statistical values for 5GHz frequencies.
+ */
+int16_t
+ar5210GetNfAdjust(struct ath_hal *ah, const HAL_CHANNEL_INTERNAL *c)
+{
+ return 0;
+}
+
+HAL_RFGAIN
+ar5210GetRfgain(struct ath_hal *ah)
+{
+ return HAL_RFGAIN_INACTIVE;
+}
diff --git a/sys/dev/ath/ath_hal/ar5210/ar5210_xmit.c b/sys/dev/ath/ath_hal/ar5210/ar5210_xmit.c
new file mode 100644
index 000000000000..dbdeaf86a419
--- /dev/null
+++ b/sys/dev/ath/ath_hal/ar5210/ar5210_xmit.c
@@ -0,0 +1,670 @@
+/*-
+ * SPDX-License-Identifier: ISC
+ *
+ * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
+ * Copyright (c) 2002-2004 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 "ar5210/ar5210.h"
+#include "ar5210/ar5210reg.h"
+#include "ar5210/ar5210phy.h"
+#include "ar5210/ar5210desc.h"
+
+/*
+ * Set the properties of the tx queue with the parameters
+ * from qInfo. The queue must previously have been setup
+ * with a call to ar5210SetupTxQueue.
+ */
+HAL_BOOL
+ar5210SetTxQueueProps(struct ath_hal *ah, int q, const HAL_TXQ_INFO *qInfo)
+{
+ struct ath_hal_5210 *ahp = AH5210(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
+ar5210GetTxQueueProps(struct ath_hal *ah, int q, HAL_TXQ_INFO *qInfo)
+{
+ struct ath_hal_5210 *ahp = AH5210(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
+ar5210SetupTxQueue(struct ath_hal *ah, HAL_TX_QUEUE type,
+ const HAL_TXQ_INFO *qInfo)
+{
+ struct ath_hal_5210 *ahp = AH5210(ah);
+ HAL_TX_QUEUE_INFO *qi;
+ int q;
+
+ switch (type) {
+ case HAL_TX_QUEUE_BEACON:
+ q = 2;
+ break;
+ case HAL_TX_QUEUE_CAB:
+ q = 1;
+ break;
+ case HAL_TX_QUEUE_DATA:
+ q = 0;
+ 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_shretry = INIT_SH_RETRY;
+ qi->tqi_lgretry = INIT_LG_RETRY;
+ } else
+ (void) ar5210SetTxQueueProps(ah, q, qInfo);
+ /* NB: must be followed by ar5210ResetTxQueue */
+ return q;
+}
+
+/*
+ * Free a tx DCU/QCU combination.
+ */
+HAL_BOOL
+ar5210ReleaseTxQueue(struct ath_hal *ah, u_int q)
+{
+ struct ath_hal_5210 *ahp = AH5210(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);
+
+ return AH_TRUE;
+#undef N
+}
+
+HAL_BOOL
+ar5210ResetTxQueue(struct ath_hal *ah, u_int q)
+{
+ struct ath_hal_5210 *ahp = AH5210(ah);
+ const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan;
+ HAL_TX_QUEUE_INFO *qi;
+ uint32_t cwMin;
+
+ if (q >= HAL_NUM_TX_QUEUES) {
+ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n",
+ __func__, q);
+ return AH_FALSE;
+ }
+ qi = &ahp->ah_txq[q];
+ if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) {
+ HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: inactive queue %u\n",
+ __func__, q);
+ return AH_FALSE;
+ }
+
+ /*
+ * Ignore any non-data queue(s).
+ */
+ if (qi->tqi_type != HAL_TX_QUEUE_DATA)
+ return AH_TRUE;
+
+ /* Set turbo mode / base mode parameters on or off */
+ if (IEEE80211_IS_CHAN_TURBO(chan)) {
+ OS_REG_WRITE(ah, AR_SLOT_TIME, INIT_SLOT_TIME_TURBO);
+ OS_REG_WRITE(ah, AR_TIME_OUT, INIT_ACK_CTS_TIMEOUT_TURBO);
+ OS_REG_WRITE(ah, AR_USEC, INIT_TRANSMIT_LATENCY_TURBO);
+ OS_REG_WRITE(ah, AR_IFS0,
+ ((INIT_SIFS_TURBO + qi->tqi_aifs * INIT_SLOT_TIME_TURBO)
+ << AR_IFS0_DIFS_S)
+ | INIT_SIFS_TURBO);
+ OS_REG_WRITE(ah, AR_IFS1, INIT_PROTO_TIME_CNTRL_TURBO);
+ OS_REG_WRITE(ah, AR_PHY(17),
+ (OS_REG_READ(ah, AR_PHY(17)) & ~0x7F) | 0x38);
+ OS_REG_WRITE(ah, AR_PHY_FRCTL,
+ AR_PHY_SERVICE_ERR | AR_PHY_TXURN_ERR |
+ AR_PHY_ILLLEN_ERR | AR_PHY_ILLRATE_ERR |
+ AR_PHY_PARITY_ERR | AR_PHY_TIMING_ERR |
+ 0x2020 |
+ AR_PHY_TURBO_MODE | AR_PHY_TURBO_SHORT);
+ } else {
+ OS_REG_WRITE(ah, AR_SLOT_TIME, INIT_SLOT_TIME);
+ OS_REG_WRITE(ah, AR_TIME_OUT, INIT_ACK_CTS_TIMEOUT);
+ OS_REG_WRITE(ah, AR_USEC, INIT_TRANSMIT_LATENCY);
+ OS_REG_WRITE(ah, AR_IFS0,
+ ((INIT_SIFS + qi->tqi_aifs * INIT_SLOT_TIME)
+ << AR_IFS0_DIFS_S)
+ | INIT_SIFS);
+ OS_REG_WRITE(ah, AR_IFS1, INIT_PROTO_TIME_CNTRL);
+ OS_REG_WRITE(ah, AR_PHY(17),
+ (OS_REG_READ(ah, AR_PHY(17)) & ~0x7F) | 0x1C);
+ OS_REG_WRITE(ah, AR_PHY_FRCTL,
+ AR_PHY_SERVICE_ERR | AR_PHY_TXURN_ERR |
+ AR_PHY_ILLLEN_ERR | AR_PHY_ILLRATE_ERR |
+ AR_PHY_PARITY_ERR | AR_PHY_TIMING_ERR | 0x1020);
+ }
+
+ if (qi->tqi_cwmin == HAL_TXQ_USEDEFAULT)
+ cwMin = INIT_CWMIN;
+ else
+ cwMin = qi->tqi_cwmin;
+
+ /* Set cwmin and retry limit values */
+ OS_REG_WRITE(ah, AR_RETRY_LMT,
+ (cwMin << AR_RETRY_LMT_CW_MIN_S)
+ | SM(INIT_SLG_RETRY, AR_RETRY_LMT_SLG_RETRY)
+ | SM(INIT_SSH_RETRY, AR_RETRY_LMT_SSH_RETRY)
+ | SM(qi->tqi_lgretry, AR_RETRY_LMT_LG_RETRY)
+ | SM(qi->tqi_shretry, AR_RETRY_LMT_SH_RETRY)
+ );
+
+ if (qi->tqi_qflags & HAL_TXQ_TXOKINT_ENABLE)
+ ahp->ah_txOkInterruptMask |= 1 << q;
+ else
+ ahp->ah_txOkInterruptMask &= ~(1 << q);
+ if (qi->tqi_qflags & HAL_TXQ_TXERRINT_ENABLE)
+ ahp->ah_txErrInterruptMask |= 1 << q;
+ else
+ ahp->ah_txErrInterruptMask &= ~(1 << q);
+ if (qi->tqi_qflags & HAL_TXQ_TXDESCINT_ENABLE)
+ ahp->ah_txDescInterruptMask |= 1 << q;
+ else
+ ahp->ah_txDescInterruptMask &= ~(1 << q);
+ if (qi->tqi_qflags & HAL_TXQ_TXEOLINT_ENABLE)
+ ahp->ah_txEolInterruptMask |= 1 << q;
+ else
+ ahp->ah_txEolInterruptMask &= ~(1 << q);
+ if (qi->tqi_qflags & HAL_TXQ_TXURNINT_ENABLE)
+ ahp->ah_txUrnInterruptMask |= 1 << q;
+ else
+ ahp->ah_txUrnInterruptMask &= ~(1 << q);
+
+ return AH_TRUE;
+}
+
+/*
+ * Get the TXDP for the "main" data queue. Needs to be extended
+ * for multiple Q functionality
+ */
+uint32_t
+ar5210GetTxDP(struct ath_hal *ah, u_int q)
+{
+ struct ath_hal_5210 *ahp = AH5210(ah);
+ HAL_TX_QUEUE_INFO *qi;
+
+ HALASSERT(q < HAL_NUM_TX_QUEUES);
+
+ qi = &ahp->ah_txq[q];
+ switch (qi->tqi_type) {
+ case HAL_TX_QUEUE_DATA:
+ return OS_REG_READ(ah, AR_TXDP0);
+ case HAL_TX_QUEUE_INACTIVE:
+ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: inactive queue %u\n",
+ __func__, q);
+ /* fall thru... */
+ default:
+ break;
+ }
+ return 0xffffffff;
+}
+
+/*
+ * Set the TxDP for the "main" data queue.
+ */
+HAL_BOOL
+ar5210SetTxDP(struct ath_hal *ah, u_int q, uint32_t txdp)
+{
+ struct ath_hal_5210 *ahp = AH5210(ah);
+ HAL_TX_QUEUE_INFO *qi;
+
+ HALASSERT(q < HAL_NUM_TX_QUEUES);
+
+ HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: queue %u 0x%x\n",
+ __func__, q, txdp);
+ qi = &ahp->ah_txq[q];
+ switch (qi->tqi_type) {
+ case HAL_TX_QUEUE_DATA:
+#ifdef AH_DEBUG
+ /*
+ * Make sure that TXE is deasserted before setting the
+ * TXDP. If TXE is still asserted, setting TXDP will
+ * have no effect.
+ */
+ if (OS_REG_READ(ah, AR_CR) & AR_CR_TXE0)
+ ath_hal_printf(ah, "%s: TXE asserted; AR_CR=0x%x\n",
+ __func__, OS_REG_READ(ah, AR_CR));
+#endif
+ OS_REG_WRITE(ah, AR_TXDP0, txdp);
+ break;
+ case HAL_TX_QUEUE_BEACON:
+ case HAL_TX_QUEUE_CAB:
+ OS_REG_WRITE(ah, AR_TXDP1, txdp);
+ break;
+ case HAL_TX_QUEUE_INACTIVE:
+ HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: inactive queue %u\n",
+ __func__, q);
+ /* fall thru... */
+ default:
+ return AH_FALSE;
+ }
+ return AH_TRUE;
+}
+
+/*
+ * 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
+ar5210UpdateTxTrigLevel(struct ath_hal *ah, HAL_BOOL bIncTrigLevel)
+{
+ uint32_t curTrigLevel;
+ HAL_INT ints = ar5210GetInterrupts(ah);
+
+ /*
+ * Disable chip interrupts. This is because halUpdateTxTrigLevel
+ * is called from both ISR and non-ISR contexts.
+ */
+ (void) ar5210SetInterrupts(ah, ints &~ HAL_INT_GLOBAL);
+ curTrigLevel = OS_REG_READ(ah, AR_TRIG_LEV);
+ 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 */
+ ar5210SetInterrupts(ah, ints);
+ return AH_FALSE;
+ }
+ }
+ /* Update the trigger level */
+ OS_REG_WRITE(ah, AR_TRIG_LEV, curTrigLevel);
+ /* re-enable chip interrupts */
+ ar5210SetInterrupts(ah, ints);
+ return AH_TRUE;
+}
+
+/*
+ * Set Transmit Enable bits for the specified queues.
+ */
+HAL_BOOL
+ar5210StartTxDma(struct ath_hal *ah, u_int q)
+{
+ struct ath_hal_5210 *ahp = AH5210(ah);
+ HAL_TX_QUEUE_INFO *qi;
+
+ HALASSERT(q < HAL_NUM_TX_QUEUES);
+
+ HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: queue %u\n", __func__, q);
+ qi = &ahp->ah_txq[q];
+ switch (qi->tqi_type) {
+ case HAL_TX_QUEUE_DATA:
+ OS_REG_WRITE(ah, AR_CR, AR_CR_TXE0);
+ break;
+ case HAL_TX_QUEUE_CAB:
+ OS_REG_WRITE(ah, AR_CR, AR_CR_TXE1); /* enable altq xmit */
+ OS_REG_WRITE(ah, AR_BCR,
+ AR_BCR_TQ1V | AR_BCR_BDMAE | AR_BCR_TQ1FV);
+ break;
+ case HAL_TX_QUEUE_BEACON:
+ /* XXX add CR_BCR_BCMD if IBSS mode */
+ OS_REG_WRITE(ah, AR_BCR, AR_BCR_TQ1V | AR_BCR_BDMAE);
+ break;
+ case HAL_TX_QUEUE_INACTIVE:
+ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: inactive queue %u\n",
+ __func__, q);
+ /* fal thru... */
+ default:
+ return AH_FALSE;
+ }
+ return AH_TRUE;
+}
+
+uint32_t
+ar5210NumTxPending(struct ath_hal *ah, u_int q)
+{
+ struct ath_hal_5210 *ahp = AH5210(ah);
+ HAL_TX_QUEUE_INFO *qi;
+ uint32_t v;
+
+ HALASSERT(q < HAL_NUM_TX_QUEUES);
+
+ HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: queue %u\n", __func__, q);
+ qi = &ahp->ah_txq[q];
+ switch (qi->tqi_type) {
+ case HAL_TX_QUEUE_DATA:
+ v = OS_REG_READ(ah, AR_CFG);
+ return MS(v, AR_CFG_TXCNT);
+ case HAL_TX_QUEUE_INACTIVE:
+ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: inactive queue %u\n",
+ __func__, q);
+ /* fall thru... */
+ default:
+ break;
+ }
+ return 0;
+}
+
+/*
+ * Stop transmit on the specified queue
+ */
+HAL_BOOL
+ar5210StopTxDma(struct ath_hal *ah, u_int q)
+{
+ struct ath_hal_5210 *ahp = AH5210(ah);
+ HAL_TX_QUEUE_INFO *qi;
+
+ HALASSERT(q < HAL_NUM_TX_QUEUES);
+
+ HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: queue %u\n", __func__, q);
+ qi = &ahp->ah_txq[q];
+ switch (qi->tqi_type) {
+ case HAL_TX_QUEUE_DATA: {
+ int i;
+ OS_REG_WRITE(ah, AR_CR, AR_CR_TXD0);
+ for (i = 0; i < 1000; i++) {
+ if ((OS_REG_READ(ah, AR_CFG) & AR_CFG_TXCNT) == 0)
+ break;
+ OS_DELAY(10);
+ }
+ OS_REG_WRITE(ah, AR_CR, 0);
+ return (i < 1000);
+ }
+ case HAL_TX_QUEUE_BEACON:
+ return ath_hal_wait(ah, AR_BSR, AR_BSR_TXQ1F, 0);
+ case HAL_TX_QUEUE_INACTIVE:
+ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: inactive queue %u\n",
+ __func__, q);
+ /* fall thru... */
+ default:
+ break;
+ }
+ return AH_FALSE;
+}
+
+/*
+ * 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
+ar5210SetupTxDesc(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 ar5210_desc *ads = AR5210DESC(ds);
+ uint32_t frtype;
+
+ (void) txPower;
+ (void) rtsctsDuration;
+
+ HALASSERT(txTries0 != 0);
+ HALASSERT(isValidPktType(type));
+ HALASSERT(isValidTxRate(txRate0));
+
+ if (type == HAL_PKT_TYPE_BEACON || type == HAL_PKT_TYPE_PROBE_RESP)
+ frtype = AR_Frm_NoDelay;
+ else
+ frtype = type << 26;
+ ads->ds_ctl0 = (pktLen & AR_FrameLen)
+ | (txRate0 << AR_XmitRate_S)
+ | ((hdrLen << AR_HdrLen_S) & AR_HdrLen)
+ | frtype
+ | (flags & HAL_TXDESC_CLRDMASK ? AR_ClearDestMask : 0)
+ | (flags & HAL_TXDESC_INTREQ ? AR_TxInterReq : 0)
+ | (antMode ? AR_AntModeXmit : 0)
+ ;
+ if (keyIx != HAL_TXKEYIX_INVALID) {
+ ads->ds_ctl1 = (keyIx << AR_EncryptKeyIdx_S) & AR_EncryptKeyIdx;
+ ads->ds_ctl0 |= AR_EncryptKeyValid;
+ } else
+ ads->ds_ctl1 = 0;
+ if (flags & HAL_TXDESC_RTSENA) {
+ ads->ds_ctl0 |= AR_RTSCTSEnable;
+ ads->ds_ctl1 |= (rtsctsDuration << AR_RTSDuration_S)
+ & AR_RTSDuration;
+ }
+ return AH_TRUE;
+}
+
+HAL_BOOL
+ar5210SetupXTxDesc(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
+ar5210IntrReqTxDesc(struct ath_hal *ah, struct ath_desc *ds)
+{
+ struct ar5210_desc *ads = AR5210DESC(ds);
+
+ ads->ds_ctl0 |= AR_TxInterReq;
+}
+
+HAL_BOOL
+ar5210FillTxDesc(struct ath_hal *ah, struct ath_desc *ds,
+ HAL_DMA_ADDR *bufAddrList, uint32_t *segLenList, u_int descId,
+ u_int qcuId, HAL_BOOL firstSeg, HAL_BOOL lastSeg,
+ const struct ath_desc *ds0)
+{
+ struct ar5210_desc *ads = AR5210DESC(ds);
+ uint32_t segLen = segLenList[0];
+
+ HALASSERT((segLen &~ AR_BufLen) == 0);
+
+ ds->ds_data = bufAddrList[0];
+
+ if (firstSeg) {
+ /*
+ * First descriptor, don't clobber xmit control data
+ * setup by ar5210SetupTxDesc.
+ */
+ 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 = AR5210DESC_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
+ar5210ProcTxDesc(struct ath_hal *ah,
+ struct ath_desc *ds, struct ath_tx_status *ts)
+{
+ struct ar5210_desc *ads = AR5210DESC(ds);
+
+ if ((ads->ds_status1 & AR_Done) == 0)
+ return HAL_EINPROGRESS;
+
+ /* Update software copies of the HW status */
+ ts->ts_seqnum = 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_antenna = 0; /* NB: don't know */
+ ts->ts_finaltsi = 0;
+
+ return HAL_OK;
+}
+
+/*
+ * Determine which tx queues need interrupt servicing.
+ * STUB.
+ */
+void
+ar5210GetTxIntrQueue(struct ath_hal *ah, uint32_t *txqs)
+{
+ return;
+}
+
+/*
+ * Retrieve the rate table from the given TX completion descriptor
+ */
+HAL_BOOL
+ar5210GetTxCompletionRates(struct ath_hal *ah, const struct ath_desc *ds0, int *rates, int *tries)
+{
+ return AH_FALSE;
+}
+
+/*
+ * Set the TX descriptor link pointer
+ */
+void
+ar5210SetTxDescLink(struct ath_hal *ah, void *ds, uint32_t link)
+{
+ struct ar5210_desc *ads = AR5210DESC(ds);
+
+ ads->ds_link = link;
+}
+
+/*
+ * Get the TX descriptor link pointer
+ */
+void
+ar5210GetTxDescLink(struct ath_hal *ah, void *ds, uint32_t *link)
+{
+ struct ar5210_desc *ads = AR5210DESC(ds);
+
+ *link = ads->ds_link;
+}
+
+/*
+ * Get a pointer to the TX descriptor link pointer
+ */
+void
+ar5210GetTxDescLinkPtr(struct ath_hal *ah, void *ds, uint32_t **linkptr)
+{
+ struct ar5210_desc *ads = AR5210DESC(ds);
+
+ *linkptr = &ads->ds_link;
+}
diff --git a/sys/dev/ath/ath_hal/ar5210/ar5210desc.h b/sys/dev/ath/ath_hal/ar5210/ar5210desc.h
new file mode 100644
index 000000000000..9679824f4541
--- /dev/null
+++ b/sys/dev/ath/ath_hal/ar5210/ar5210desc.h
@@ -0,0 +1,130 @@
+/*-
+ * SPDX-License-Identifier: ISC
+ *
+ * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
+ * Copyright (c) 2002-2004 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_AR5210DESC_H
+#define _DEV_ATH_AR5210DESC_H
+
+/*
+ * Defintions for the DMA descriptors used by the Atheros
+ * AR5210/AR5211 and AR5110 Wireless Lan controller parts.
+ */
+
+/* DMA descriptors */
+struct ar5210_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 AR5210DESC(_ds) ((struct ar5210_desc *)(_ds))
+#define AR5210DESC_CONST(_ds) ((const struct ar5210_desc *)(_ds))
+
+/* TX ds_ctl0 */
+#define AR_FrameLen 0x00000fff /* frame length */
+#define AR_HdrLen 0x0003f000 /* header length */
+#define AR_HdrLen_S 12
+#define AR_XmitRate 0x003c0000 /* txrate */
+#define AR_XmitRate_S 18
+#define AR_Rate_6M 0xb
+#define AR_Rate_9M 0xf
+#define AR_Rate_12M 0xa
+#define AR_Rate_18M 0xe
+#define AR_Rate_24M 0x9
+#define AR_Rate_36M 0xd
+#define AR_Rate_48M 0x8
+#define AR_Rate_54M 0xc
+#define AR_RTSCTSEnable 0x00400000 /* RTS/CTS enable */
+#define AR_LongPkt 0x00800000 /* long packet indication */
+#define AR_ClearDestMask 0x01000000 /* Clear destination mask bit */
+#define AR_AntModeXmit 0x02000000 /* TX antenna seslection */
+#define AR_FrmType 0x1c000000 /* frame type indication */
+#define AR_FrmType_S 26
+#define AR_Frm_Normal 0x00000000 /* normal frame */
+#define AR_Frm_ATIM 0x04000000 /* ATIM frame */
+#define AR_Frm_PSPOLL 0x08000000 /* PS poll frame */
+#define AR_Frm_NoDelay 0x0c000000 /* no delay data */
+#define AR_Frm_PIFS 0x10000000 /* PIFS data */
+#define AR_TxInterReq 0x20000000 /* TX interrupt request */
+#define AR_EncryptKeyValid 0x40000000 /* EncryptKeyIdx is valid */
+
+/* TX ds_ctl1 */
+#define AR_BufLen 0x00000fff /* data buffer length */
+#define AR_More 0x00001000 /* more desc in this frame */
+#define AR_EncryptKeyIdx 0x0007e000 /* ecnrypt key table index */
+#define AR_EncryptKeyIdx_S 13
+#define AR_RTSDuration 0xfff80000 /* lower 13bit of duration */
+#define AR_RTSDuration_S 19
+
+/* RX ds_ctl1 */
+/* AR_BufLen 0x00000fff data buffer length */
+#define AR_RxInterReq 0x00002000 /* RX interrupt request */
+
+/* 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_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 */
+#define AR_RcvAntenna 0x00004000 /* received on ant 1 */
+#define AR_RcvRate 0x00078000 /* reception rate */
+#define AR_RcvRate_S 15
+#define AR_RcvSigStrength 0x07f80000 /* receive signal strength */
+#define AR_RcvSigStrength_S 19
+
+/* TX ds_status1 */
+#define AR_Done 0x00000001 /* descripter complete */
+#define AR_SeqNum 0x00001ffe /* TX sequence number */
+#define AR_AckSigStrength 0x001fe000 /* strength of ACK */
+#define AR_AckSigStrength_S 13
+
+/* RX ds_status1 */
+/* AR_Done 0x00000001 descripter complete */
+#define AR_FrmRcvOK 0x00000002 /* frame reception success */
+#define AR_CRCErr 0x00000004 /* CRC error */
+#define AR_FIFOOverrun 0x00000008 /* RX FIFO overrun */
+#define AR_DecryptCRCErr 0x00000010 /* Decryption CRC fiailure */
+#define AR_PHYErr 0x000000e0 /* PHY error */
+#define AR_PHYErr_S 5
+#define AR_PHYErr_NoErr 0x00000000 /* No error */
+#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_QAM 0x000000a0 /* 64 QAM rate */
+#define AR_PHYErr_Srv 0x000000c0 /* Service bit error */
+#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_AR5210DESC_H_ */
diff --git a/sys/dev/ath/ath_hal/ar5210/ar5210phy.h b/sys/dev/ath/ath_hal/ar5210/ar5210phy.h
new file mode 100644
index 000000000000..667533bff8c5
--- /dev/null
+++ b/sys/dev/ath/ath_hal/ar5210/ar5210phy.h
@@ -0,0 +1,59 @@
+/*-
+ * SPDX-License-Identifier: ISC
+ *
+ * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
+ * Copyright (c) 2002-2004 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_AR5210PHY_H
+#define _DEV_ATH_AR5210PHY_H
+
+/*
+ * Definitions for the PHY on the Atheros AR5210 parts.
+ */
+
+/* PHY Registers */
+#define AR_PHY_BASE 0x9800 /* PHY register base */
+#define AR_PHY(_n) (AR_PHY_BASE + ((_n)<<2))
+
+#define AR_PHY_FRCTL 0x9804 /* PHY frame control */
+#define AR_PHY_TURBO_MODE 0x00000001 /* PHY turbo mode */
+#define AR_PHY_TURBO_SHORT 0x00000002 /* PHY turbo short symbol */
+#define AR_PHY_TIMING_ERR 0x01000000 /* Detect PHY timing error */
+#define AR_PHY_PARITY_ERR 0x02000000 /* Detect signal parity err */
+#define AR_PHY_ILLRATE_ERR 0x04000000 /* Detect PHY illegal rate */
+#define AR_PHY_ILLLEN_ERR 0x08000000 /* Detect PHY illegal length */
+#define AR_PHY_SERVICE_ERR 0x20000000 /* Detect PHY nonzero service */
+#define AR_PHY_TXURN_ERR 0x40000000 /* DetectPHY TX underrun */
+#define AR_PHY_FRCTL_BITS \
+ "\20\1TURBO_MODE\2TURBO_SHORT\30TIMING_ERR\31PARITY_ERR\32ILLRATE_ERR"\
+ "\33ILLEN_ERR\35SERVICE_ERR\36TXURN_ERR"
+
+#define AR_PHY_AGC 0x9808 /* PHY AGC command */
+#define AR_PHY_AGC_DISABLE 0x08000000 /* Disable PHY AGC */
+#define AR_PHY_AGC_BITS "\20\33DISABLE"
+
+#define AR_PHY_CHIPID 0x9818 /* PHY chip revision */
+
+#define AR_PHY_ACTIVE 0x981c /* PHY activation */
+#define AR_PHY_ENABLE 0x00000001 /* activate PHY */
+#define AR_PHY_DISABLE 0x00000002 /* deactivate PHY */
+#define AR_PHY_ACTIVE_BITS "\20\1ENABLE\2DISABLE"
+
+#define AR_PHY_AGCCTL 0x9860 /* PHY calibration and noise floor */
+#define AR_PHY_AGC_CAL 0x00000001 /* PHY internal calibration */
+#define AR_PHY_AGC_NF 0x00000002 /* calc PHY noise-floor */
+#define AR_PHY_AGCCTL_BITS "\20\1CAL\2NF"
+
+#endif /* _DEV_ATH_AR5210PHY_H */
diff --git a/sys/dev/ath/ath_hal/ar5210/ar5210reg.h b/sys/dev/ath/ath_hal/ar5210/ar5210reg.h
new file mode 100644
index 000000000000..92e32a06872c
--- /dev/null
+++ b/sys/dev/ath/ath_hal/ar5210/ar5210reg.h
@@ -0,0 +1,413 @@
+/*-
+ * SPDX-License-Identifier: ISC
+ *
+ * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
+ * Copyright (c) 2002-2004 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_AR5210REG_H
+#define _DEV_ATH_AR5210REG_H
+
+/*
+ * Register defintions for the Atheros AR5210/5110 MAC/Basedband
+ * Processor for IEEE 802.11a 5-GHz Wireless LANs.
+ */
+
+#ifndef PCI_VENDOR_ATHEROS
+#define PCI_VENDOR_ATHEROS 0x168c
+#endif
+#define PCI_PRODUCT_ATHEROS_AR5210 0x0007
+#define PCI_PRODUCT_ATHEROS_AR5210_OLD 0x0004
+
+/* DMA Registers */
+#define AR_TXDP0 0x0000 /* TX queue pointer 0 register */
+#define AR_TXDP1 0x0004 /* TX queue pointer 1 register */
+#define AR_CR 0x0008 /* Command register */
+#define AR_RXDP 0x000c /* RX queue descriptor ptr register */
+#define AR_CFG 0x0014 /* Configuration and status register */
+#define AR_ISR 0x001c /* Interrupt status register */
+#define AR_IMR 0x0020 /* Interrupt mask register */
+#define AR_IER 0x0024 /* Interrupt global enable register */
+#define AR_BCR 0x0028 /* Beacon control register */
+#define AR_BSR 0x002c /* Beacon status register */
+#define AR_TXCFG 0x0030 /* TX configuration register */
+#define AR_RXCFG 0x0034 /* RX configuration register */
+#define AR_MIBC 0x0040 /* MIB control register */
+#define AR_TOPS 0x0044 /* Timeout prescale register */
+#define AR_RXNOFRM 0x0048 /* RX no frame timeout register */
+#define AR_TXNOFRM 0x004c /* TX no frame timeout register */
+#define AR_RPGTO 0x0050 /* RX frame gap timeout register */
+#define AR_RFCNT 0x0054 /* RX frame count limit register */
+#define AR_MISC 0x0058 /* Misc control and status register */
+#define AR_RC 0x4000 /* Reset control */
+#define AR_SCR 0x4004 /* Sleep control */
+#define AR_INTPEND 0x4008 /* Interrupt pending */
+#define AR_SFR 0x400c /* Force sleep */
+#define AR_PCICFG 0x4010 /* PCI configuration */
+#define AR_GPIOCR 0x4014 /* GPIO configuration */
+#define AR_GPIODO 0x4018 /* GPIO data output */
+#define AR_GPIODI 0x401c /* GPIO data input */
+#define AR_SREV 0x4020 /* Silicon revision */
+/* EEPROM Access Registers */
+#define AR_EP_AIR_BASE 0x6000 /* EEPROM access initiation regs base */
+#define AR_EP_AIR(n) (AR_EP_AIR_BASE + (n)*4)
+#define AR_EP_RDATA 0x6800 /* EEPROM read data register */
+#define AR_EP_STA 0x6c00 /* EEPROM access status register */
+/* PCU Registers */
+#define AR_STA_ID0 0x8000 /* Lower 32bits of MAC address */
+#define AR_STA_ID1 0x8004 /* Upper 16bits of MAC address */
+#define AR_BSS_ID0 0x8008 /* Lower 32bits of BSSID */
+#define AR_BSS_ID1 0x800c /* Upper 16bits of BSSID */
+#define AR_SLOT_TIME 0x8010 /* Length of a back-off */
+#define AR_TIME_OUT 0x8014 /* Timeout to wait for ACK and CTS */
+#define AR_RSSI_THR 0x8018 /* Beacon RSSI warning threshold */
+#define AR_RETRY_LMT 0x801c /* Short and long frame retry limit */
+#define AR_USEC 0x8020 /* Transmit latency */
+#define AR_BEACON 0x8024 /* Beacon control */
+#define AR_CFP_PERIOD 0x8028 /* CFP period */
+#define AR_TIMER0 0x802c /* Next beacon time */
+#define AR_TIMER1 0x8030 /* Next DMA beacon alert time */
+#define AR_TIMER2 0x8034 /* Next software beacon alert time */
+#define AR_TIMER3 0x8038 /* Next ATIM window time */
+#define AR_IFS0 0x8040 /* Protocol timers */
+#define AR_IFS1 0x8044 /* Protocol time and control */
+#define AR_CFP_DUR 0x8048 /* Maximum CFP duration */
+#define AR_RX_FILTER 0x804c /* Receive filter */
+#define AR_MCAST_FIL0 0x8050 /* Lower 32bits of mcast filter mask */
+#define AR_MCAST_FIL1 0x8054 /* Upper 16bits of mcast filter mask */
+#define AR_TX_MASK0 0x8058 /* Lower 32bits of TX mask */
+#define AR_TX_MASK1 0x805c /* Upper 16bits of TX mask */
+#define AR_CLR_TMASK 0x8060 /* Clear TX mask */
+#define AR_TRIG_LEV 0x8064 /* Minimum FIFO fill level before TX */
+#define AR_DIAG_SW 0x8068 /* PCU control */
+#define AR_TSF_L32 0x806c /* Lower 32bits of local clock */
+#define AR_TSF_U32 0x8070 /* Upper 32bits of local clock */
+#define AR_LAST_TSTP 0x8080 /* Lower 32bits of last beacon tstamp */
+#define AR_RETRY_CNT 0x8084 /* Current short or long retry cnt */
+#define AR_BACKOFF 0x8088 /* Back-off status */
+#define AR_NAV 0x808c /* Current NAV value */
+#define AR_RTS_OK 0x8090 /* RTS success counter */
+#define AR_RTS_FAIL 0x8094 /* RTS failure counter */
+#define AR_ACK_FAIL 0x8098 /* ACK failure counter */
+#define AR_FCS_FAIL 0x809c /* FCS failure counter */
+#define AR_BEACON_CNT 0x80a0 /* Valid beacon counter */
+#define AR_KEYTABLE_0 0x9000 /* Encryption key table */
+#define AR_KEYTABLE(n) (AR_KEYTABLE_0 + ((n)*32))
+
+#define AR_CR_TXE0 0x00000001 /* TX queue 0 enable */
+#define AR_CR_TXE1 0x00000002 /* TX queue 1 enable */
+#define AR_CR_RXE 0x00000004 /* RX enable */
+#define AR_CR_TXD0 0x00000008 /* TX queue 0 disable */
+#define AR_CR_TXD1 0x00000010 /* TX queue 1 disable */
+#define AR_CR_RXD 0x00000020 /* RX disable */
+#define AR_CR_SWI 0x00000040 /* software interrupt */
+#define AR_CR_BITS \
+ "\20\1TXE0\2TXE1\3RXE\4TXD0\5TXD1\6RXD\7SWI"
+
+#define AR_CFG_SWTD 0x00000001 /* BE for TX desc */
+#define AR_CFG_SWTB 0x00000002 /* BE for TX data */
+#define AR_CFG_SWRD 0x00000004 /* BE for RX desc */
+#define AR_CFG_SWRB 0x00000008 /* BE for RX data */
+#define AR_CFG_SWRG 0x00000010 /* BE for registers */
+#define AR_CFG_EEBS 0x00000200 /* EEPROM busy */
+#define AR_CFG_TXCNT 0x00007800 /* number of TX desc in Q */
+#define AR_CFG_TXCNT_S 11
+#define AR_CFG_TXFSTAT 0x00008000 /* TX DMA status */
+#define AR_CFG_TXFSTRT 0x00010000 /* re-enable TX DMA */
+#define AR_CFG_BITS \
+ "\20\1SWTD\2SWTB\3SWRD\4SWRB\5SWRG\14EEBS\17TXFSTAT\20TXFSTRT"
+
+#define AR_ISR_RXOK_INT 0x00000001 /* RX frame OK */
+#define AR_ISR_RXDESC_INT 0x00000002 /* RX intr request */
+#define AR_ISR_RXERR_INT 0x00000004 /* RX error */
+#define AR_ISR_RXNOFRM_INT 0x00000008 /* no frame received */
+#define AR_ISR_RXEOL_INT 0x00000010 /* RX desc empty */
+#define AR_ISR_RXORN_INT 0x00000020 /* RX fifo overrun */
+#define AR_ISR_TXOK_INT 0x00000040 /* TX frame OK */
+#define AR_ISR_TXDESC_INT 0x00000080 /* TX intr request */
+#define AR_ISR_TXERR_INT 0x00000100 /* TX error */
+#define AR_ISR_TXNOFRM_INT 0x00000200 /* no frame transmitted */
+#define AR_ISR_TXEOL_INT 0x00000400 /* TX desc empty */
+#define AR_ISR_TXURN_INT 0x00000800 /* TX fifo underrun */
+#define AR_ISR_MIB_INT 0x00001000 /* MIB interrupt */
+#define AR_ISR_SWI_INT 0x00002000 /* software interrupt */
+#define AR_ISR_RXPHY_INT 0x00004000 /* PHY RX error */
+#define AR_ISR_RXKCM_INT 0x00008000 /* Key cache miss */
+#define AR_ISR_SWBA_INT 0x00010000 /* software beacon alert */
+#define AR_ISR_BRSSI_INT 0x00020000 /* beacon threshold */
+#define AR_ISR_BMISS_INT 0x00040000 /* beacon missed */
+#define AR_ISR_MCABT_INT 0x00100000 /* master cycle abort */
+#define AR_ISR_SSERR_INT 0x00200000 /* SERR on PCI */
+#define AR_ISR_DPERR_INT 0x00400000 /* Parity error on PCI */
+#define AR_ISR_GPIO_INT 0x01000000 /* GPIO interrupt */
+#define AR_ISR_BITS \
+ "\20\1RXOK\2RXDESC\3RXERR\4RXNOFM\5RXEOL\6RXORN\7TXOK\10TXDESC"\
+ "\11TXERR\12TXNOFRM\13TXEOL\14TXURN\15MIB\16SWI\17RXPHY\20RXKCM"\
+ "\21SWBA\22BRSSI\23BMISS\24MCABT\25SSERR\26DPERR\27GPIO"
+
+#define AR_IMR_RXOK_INT 0x00000001 /* RX frame OK */
+#define AR_IMR_RXDESC_INT 0x00000002 /* RX intr request */
+#define AR_IMR_RXERR_INT 0x00000004 /* RX error */
+#define AR_IMR_RXNOFRM_INT 0x00000008 /* no frame received */
+#define AR_IMR_RXEOL_INT 0x00000010 /* RX desc empty */
+#define AR_IMR_RXORN_INT 0x00000020 /* RX fifo overrun */
+#define AR_IMR_TXOK_INT 0x00000040 /* TX frame OK */
+#define AR_IMR_TXDESC_INT 0x00000080 /* TX intr request */
+#define AR_IMR_TXERR_INT 0x00000100 /* TX error */
+#define AR_IMR_TXNOFRM_INT 0x00000200 /* no frame transmitted */
+#define AR_IMR_TXEOL_INT 0x00000400 /* TX desc empty */
+#define AR_IMR_TXURN_INT 0x00000800 /* TX fifo underrun */
+#define AR_IMR_MIB_INT 0x00001000 /* MIB interrupt */
+#define AR_IMR_SWI_INT 0x00002000 /* software interrupt */
+#define AR_IMR_RXPHY_INT 0x00004000 /* PHY RX error */
+#define AR_IMR_RXKCM_INT 0x00008000 /* Key cache miss */
+#define AR_IMR_SWBA_INT 0x00010000 /* software beacon alert */
+#define AR_IMR_BRSSI_INT 0x00020000 /* beacon threshold */
+#define AR_IMR_BMISS_INT 0x00040000 /* beacon missed */
+#define AR_IMR_MCABT_INT 0x00100000 /* master cycle abort */
+#define AR_IMR_SSERR_INT 0x00200000 /* SERR on PCI */
+#define AR_IMR_DPERR_INT 0x00400000 /* Parity error on PCI */
+#define AR_IMR_GPIO_INT 0x01000000 /* GPIO interrupt */
+#define AR_IMR_BITS AR_ISR_BITS
+
+#define AR_IER_DISABLE 0x00000000 /* pseudo-flag */
+#define AR_IER_ENABLE 0x00000001 /* global interrupt enable */
+#define AR_IER_BITS "\20\1ENABLE"
+
+#define AR_BCR_BCMD 0x00000001 /* ad hoc beacon mode */
+#define AR_BCR_BDMAE 0x00000002 /* beacon DMA enable */
+#define AR_BCR_TQ1FV 0x00000004 /* use TXQ1 for non-beacon */
+#define AR_BCR_TQ1V 0x00000008 /* TXQ1 valid for beacon */
+#define AR_BCR_BCGET 0x00000010 /* force a beacon fetch */
+#define AR_BCR_BITS "\20\1BCMD\2BDMAE\3TQ1FV\4TQ1V\5BCGET"
+
+#define AR_BSR_BDLYSW 0x00000001 /* software beacon delay */
+#define AR_BSR_BDLYDMA 0x00000002 /* DMA beacon delay */
+#define AR_BSR_TXQ1F 0x00000004 /* TXQ1 fetch */
+#define AR_BSR_ATIMDLY 0x00000008 /* ATIM delay */
+#define AR_BSR_SNPBCMD 0x00000100 /* snapshot of BCMD */
+#define AR_BSR_SNPBDMAE 0x00000200 /* snapshot of BDMAE */
+#define AR_BSR_SNPTQ1FV 0x00000400 /* snapshot of TQ1FV */
+#define AR_BSR_SNPTQ1V 0x00000800 /* snapshot of TQ1V */
+#define AR_BSR_SNAPPEDBCRVALID 0x00001000 /* snapshot of BCR are valid */
+#define AR_BSR_SWBA_CNT 0x00ff0000 /* software beacon alert cnt */
+#define AR_BSR_BITS \
+ "\20\1BDLYSW\2BDLYDMA\3TXQ1F\4ATIMDLY\11SNPBCMD\12SNPBDMAE"\
+ "\13SNPTQ1FV\14SNPTQ1V\15SNAPPEDBCRVALID"
+
+#define AR_TXCFG_SDMAMR 0x00000007 /* DMA burst size 2^(2+x) */
+#define AR_TXCFG_TXFSTP 0x00000008 /* Stop TX DMA on filtered */
+#define AR_TXCFG_TXFULL 0x00000070 /* TX DMA desc Q full thresh */
+#define AR_TXCFG_TXCONT_EN 0x00000080 /* Enable continuous TX mode */
+#define AR_TXCFG_BITS "\20\3TXFSTP\7TXCONT_EN"
+
+#define AR_RXCFG_SDMAMW 0x00000007 /* DMA burst size 2^(2+x) */
+#define AR_RXCFG_ZLFDMA 0x00000010 /* enable zero length DMA */
+
+/* DMA sizes used for both AR_TXCFG_SDMAMR and AR_RXCFG_SDMAMW */
+#define AR_DMASIZE_4B 0 /* DMA size 4 bytes */
+#define AR_DMASIZE_8B 1 /* DMA size 8 bytes */
+#define AR_DMASIZE_16B 2 /* DMA size 16 bytes */
+#define AR_DMASIZE_32B 3 /* DMA size 32 bytes */
+#define AR_DMASIZE_64B 4 /* DMA size 64 bytes */
+#define AR_DMASIZE_128B 5 /* DMA size 128 bytes */
+#define AR_DMASIZE_256B 6 /* DMA size 256 bytes */
+#define AR_DMASIZE_512B 7 /* DMA size 512 bytes */
+
+#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 */
+
+#define AR_RFCNT_RFCL 0x0000000f /* RX frame count limit */
+
+#define AR_MISC_LED_DECAY 0x001c0000 /* LED decay rate */
+#define AR_MISC_LED_BLINK 0x00e00000 /* LED blink rate */
+
+#define AR_RC_RPCU 0x00000001 /* PCU Warm Reset */
+#define AR_RC_RDMA 0x00000002 /* DMA Warm Reset */
+#define AR_RC_RMAC 0x00000004 /* MAC Warm Reset */
+#define AR_RC_RPHY 0x00000008 /* PHY Warm Reset */
+#define AR_RC_RPCI 0x00000010 /* PCI Core Warm Reset */
+#define AR_RC_BITS "\20\1RPCU\2RDMA\3RMAC\4RPHY\5RPCI"
+
+#define AR_SCR_SLDUR 0x0000ffff /* sleep duration */
+#define AR_SCR_SLE 0x00030000 /* sleep enable */
+#define AR_SCR_SLE_S 16
+/*
+ * The previous values for the following three defines were:
+ *
+ * AR_SCR_SLE_WAKE 0x00000000
+ * AR_SCR_SLE_SLP 0x00010000
+ * AR_SCR_SLE_ALLOW 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_ALLOW 2 /* allow to control sleep */
+#define AR_SCR_BITS "\20\20SLE_SLP\21SLE_ALLOW"
+
+#define AR_INTPEND_IP 0x00000001 /* interrupt pending */
+#define AR_INTPEND_BITS "\20\1IP"
+
+#define AR_SFR_SF 0x00000001 /* force sleep immediately */
+
+#define AR_PCICFG_EEPROMSEL 0x00000001 /* EEPROM access enable */
+#define AR_PCICFG_CLKRUNEN 0x00000004 /* CLKRUN enable */
+#define AR_PCICFG_LED_PEND 0x00000020 /* LED for assoc pending */
+#define AR_PCICFG_LED_ACT 0x00000040 /* LED for assoc active */
+#define AR_PCICFG_SL_INTEN 0x00000800 /* Enable sleep intr */
+#define AR_PCICFG_LED_BCTL 0x00001000 /* LED blink for local act */
+#define AR_PCICFG_SL_INPEN 0x00002800 /* sleep even intr pending */
+#define AR_PCICFG_SPWR_DN 0x00010000 /* sleep indication */
+#define AR_PCICFG_BITS \
+ "\20\1EEPROMSEL\3CLKRUNEN\5LED_PEND\6LED_ACT\13SL_INTEN"\
+ "\14LED_BCTL\20SPWR_DN"
+
+#define AR_GPIOCR_IN(n) (0<<((n)*2)) /* input-only */
+#define AR_GPIOCR_OUT0(n) (1<<((n)*2)) /* output-only if GPIODO = 0 */
+#define AR_GPIOCR_OUT1(n) (2<<((n)*2)) /* output-only if GPIODO = 1 */
+#define AR_GPIOCR_OUT(n) (3<<((n)*2)) /* always output */
+#define AR_GPIOCR_ALL(n) (3<<((n)*2)) /* all bits for pin */
+#define AR_GPIOCR_INT_SEL(n) ((n)<<12) /* GPIO interrupt pin select */
+#define AR_GPIOCR_INT_ENA 0x00008000 /* Enable GPIO interrupt */
+#define AR_GPIOCR_INT_SELL 0x00000000 /* Interrupt if pin is low */
+#define AR_GPIOCR_INT_SELH 0x00010000 /* Interrupt if pin is high */
+
+#define AR_SREV_CRETE 4 /* Crete 1st version */
+#define AR_SREV_CRETE_MS 5 /* Crete FCS version */
+#define AR_SREV_CRETE_23 8 /* Crete version 2.3 */
+
+#define AR_EP_STA_RDERR 0x00000001 /* read error */
+#define AR_EP_STA_RDCMPLT 0x00000002 /* read complete */
+#define AR_EP_STA_WRERR 0x00000004 /* write error */
+#define AR_EP_STA_WRCMPLT 0x00000008 /* write complete */
+#define AR_EP_STA_BITS \
+ "\20\1RDERR\2RDCMPLT\3WRERR\4WRCMPLT"
+
+#define AR_STA_ID1_AP 0x00010000 /* Access Point Operation */
+#define AR_STA_ID1_ADHOC 0x00020000 /* ad hoc Operation */
+#define AR_STA_ID1_PWR_SV 0x00040000 /* power save report enable */
+#define AR_STA_ID1_NO_KEYSRCH 0x00080000 /* key table search disable */
+#define AR_STA_ID1_NO_PSPOLL 0x00100000 /* auto PS-POLL disable */
+#define AR_STA_ID1_PCF 0x00200000 /* PCF observation enable */
+#define AR_STA_ID1_DESC_ANTENNA 0x00400000 /* use antenna in TX desc */
+#define AR_STA_ID1_DEFAULT_ANTENNA 0x00800000 /* toggle default antenna */
+#define AR_STA_ID1_ACKCTS_6MB 0x01000000 /* use 6Mbps for ACK/CTS */
+#define AR_STA_ID1_BITS \
+ "\20\20AP\21ADHOC\22PWR_SV\23NO_KEYSRCH\24NO_PSPOLL\25PCF"\
+ "\26DESC_ANTENNA\27DEFAULT_ANTENNA\30ACKCTS_6MB"
+
+#define AR_BSS_ID1_AID 0xffff0000 /* association ID */
+#define AR_BSS_ID1_AID_S 16
+
+#define AR_TIME_OUT_ACK 0x00001fff /* ACK timeout */
+#define AR_TIME_OUT_ACK_S 0
+#define AR_TIME_OUT_CTS 0x1fff0000 /* CTS timeout */
+#define AR_TIME_OUT_CTS_S 16
+
+#define AR_RSSI_THR_BM_THR 0x00000700 /* missed beacon threshold */
+#define AR_RSSI_THR_BM_THR_S 8
+
+#define AR_RETRY_LMT_SH_RETRY 0x0000000f /* short frame retry limit */
+#define AR_RETRY_LMT_SH_RETRY_S 0
+#define AR_RETRY_LMT_LG_RETRY 0x000000f0 /* long frame retry limit */
+#define AR_RETRY_LMT_LG_RETRY_S 4
+#define AR_RETRY_LMT_SSH_RETRY 0x00003f00 /* short station retry limit */
+#define AR_RETRY_LMT_SSH_RETRY_S 8
+#define AR_RETRY_LMT_SLG_RETRY 0x000fc000 /* long station retry limit */
+#define AR_RETRY_LMT_SLG_RETRY_S 14
+#define AR_RETRY_LMT_CW_MIN 0x3ff00000 /* minimum contention window */
+#define AR_RETRY_LMT_CW_MIN_S 20
+
+#define AR_USEC_1 0x0000007f /* number of clk in 1us */
+#define AR_USEC_1_S 0
+#define AR_USEC_32 0x00003f80 /* number of 32MHz clk in 1us */
+#define AR_USEC_32_S 7
+#define AR_USEC_TX_LATENCY 0x000fc000 /* transmit latency in us */
+#define AR_USEC_TX_LATENCY_S 14
+#define AR_USEC_RX_LATENCY 0x03f00000 /* receive latency in us */
+#define AR_USEC_RX_LATENCY_S 20
+
+#define AR_BEACON_PERIOD 0x0000ffff /* beacon period in TU/ms */
+#define AR_BEACON_PERIOD_S 0
+#define AR_BEACON_TIM 0x007f0000 /* byte offset */
+#define AR_BEACON_TIM_S 16
+#define AR_BEACON_EN 0x00800000 /* beacon transmission enable */
+#define AR_BEACON_RESET_TSF 0x01000000 /* TSF reset oneshot */
+#define AR_BEACON_BITS "\20\27ENABLE\30RESET_TSF"
+
+#define AR_IFS0_SIFS 0x000007ff /* SIFS in core clock cycles */
+#define AR_IFS0_SIFS_S 0
+#define AR_IFS0_DIFS 0x007ff800 /* DIFS in core clock cycles */
+#define AR_IFS0_DIFS_S 11
+
+#define AR_IFS1_PIFS 0x00000fff /* Programmable IFS */
+#define AR_IFS1_PIFS_S 0
+#define AR_IFS1_EIFS 0x03fff000 /* EIFS in core clock cycles */
+#define AR_IFS1_EIFS_S 12
+#define AR_IFS1_CS_EN 0x04000000 /* carrier sense enable */
+
+#define AR_RX_FILTER_UNICAST 0x00000001 /* unicast frame enable */
+#define AR_RX_FILTER_MULTICAST 0x00000002 /* multicast frame enable */
+#define AR_RX_FILTER_BROADCAST 0x00000004 /* broadcast frame enable */
+#define AR_RX_FILTER_CONTROL 0x00000008 /* control frame enable */
+#define AR_RX_FILTER_BEACON 0x00000010 /* beacon frame enable */
+#define AR_RX_FILTER_PROMISCUOUS 0x00000020 /* promiscuous receive enable */
+#define AR_RX_FILTER_BITS \
+ "\20\1UCAST\2MCAST\3BCAST\4CONTROL\5BEACON\6PROMISC"
+
+#define AR_DIAG_SW_DIS_WEP_ACK 0x00000001 /* disable ACK if no key found*/
+#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_ENC 0x00000008 /* encryption disable */
+#define AR_DIAG_SW_DIS_DEC 0x00000010 /* decryption disable */
+#define AR_DIAG_SW_DIS_TX 0x00000020 /* TX disable */
+#define AR_DIAG_SW_DIS_RX 0x00000040 /* RX disable */
+#define AR_DIAG_SW_LOOP_BACK 0x00000080 /* TX data loopback enable */
+#define AR_DIAG_SW_CORR_FCS 0x00000100 /* corrupt FCS enable */
+#define AR_DIAG_SW_CHAN_INFO 0x00000200 /* channel information enable */
+#define AR_DIAG_SW_EN_SCRAM_SEED 0x00000400 /* use fixed scrambler seed */
+#define AR_DIAG_SW_SCVRAM_SEED 0x0003f800 /* fixed scrambler seed */
+#define AR_DIAG_SW_DIS_SEQ_INC 0x00040000 /* seq increment disable */
+#define AR_DIAG_SW_FRAME_NV0 0x00080000 /* accept frame vers != 0 */
+#define AR_DIAG_SW_DIS_CRYPTO (AR_DIAG_SW_DIS_ENC | AR_DIAG_SW_DIS_DEC)
+#define AR_DIAG_SW_BITS \
+ "\20\1DIS_WEP_ACK\2DIS_ACK\3DIS_CTS\4DIS_ENC\5DIS_DEC\6DIS_TX"\
+ "\7DIS_RX\10LOOP_BACK\11CORR_FCS\12CHAN_INFO\13EN_SCRAM_SEED"\
+ "\22DIS_SEQ_INC\24FRAME_NV0"
+
+#define AR_RETRY_CNT_SSH 0x0000003f /* current short retry count */
+#define AR_RETRY_CNT_SLG 0x00000fc0 /* current long retry count */
+
+#define AR_BACKOFF_CW 0x000003ff /* current contention window */
+#define AR_BACKOFF_CNT 0x03ff0000 /* backoff count */
+
+#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 /* 40 bit key */
+#define AR_KEYTABLE_TYPE_104 0x00000001 /* 104 bit key */
+#define AR_KEYTABLE_TYPE_128 0x00000003 /* 128 bit key */
+#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_AR5210REG_H */
diff --git a/sys/dev/ath/ath_hal/ar5210/ar5k_0007.ini b/sys/dev/ath/ath_hal/ar5210/ar5k_0007.ini
new file mode 100644
index 000000000000..ab7fc1a81c92
--- /dev/null
+++ b/sys/dev/ath/ath_hal/ar5210/ar5k_0007.ini
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
+ * Copyright (c) 2002-2004 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.
+ */
+
+ /* crete register init */
+ { 0x00009800, 0x00000047 },
+ { 0x00009808, 0x00000000 },
+ { 0x0000980c, 0x09848ea6 },
+ { 0x00009810, 0x3d32e000 },
+ { 0x00009814, 0x0000076b },
+ { 0x0000981c, 0x00000000 },
+ { 0x00009820, 0x02020200 },
+ { 0x00009824, 0x00000e0e },
+ { 0x00009828, 0x0a020201 },
+ { 0x0000982c, 0x00036ffc },
+ { 0x00009830, 0x00000000 },
+ { 0x00009834, 0x00000e0e },
+ { 0x00009838, 0x00000007 },
+ { 0x0000983c, 0x00020100 },
+ { 0x00009840, 0x89630000 },
+ { 0x00009844, 0x1372169c },
+ { 0x00009848, 0x0018b633 },
+ { 0x0000984c, 0x1284613c },
+ { 0x00009850, 0x0de8b8e0 },
+ { 0x00009854, 0x00074859 },
+ { 0x00009858, 0x7e80beba },
+ { 0x0000985c, 0x313a665e },
+ { 0x00009860, 0x00001d08 },
+ { 0x00009864, 0x0001ce00 },
+ { 0x00009868, 0x409a4190 },
+ { 0x00009870, 0x0000000f },
+ { 0x00009874, 0x00000080 },
+ { 0x00009878, 0x00000004 },
+ { 0x00009900, 0x00000000 },
+ { 0x00009904, 0x00000000 },
+ { 0x00009908, 0x00000000 },
+ { 0x0000990c, 0x00800000 },
+ { 0x00009910, 0x00000003 },
+
+
+ /* bb gain table */
+ { 0x00009b00, 0x00000000 },
+ { 0x00009b04, 0x00000020 },
+ { 0x00009b08, 0x00000010 },
+ { 0x00009b0c, 0x00000030 },
+ { 0x00009b10, 0x00000008 },
+ { 0x00009b14, 0x00000028 },
+ { 0x00009b18, 0x00000028 },
+ { 0x00009b1c, 0x00000004 },
+ { 0x00009b20, 0x00000024 },
+ { 0x00009b24, 0x00000014 },
+ { 0x00009b28, 0x00000034 },
+ { 0x00009b2c, 0x0000000c },
+ { 0x00009b30, 0x0000002c },
+ { 0x00009b34, 0x00000002 },
+ { 0x00009b38, 0x00000022 },
+ { 0x00009b3c, 0x00000012 },
+ { 0x00009b40, 0x00000032 },
+ { 0x00009b44, 0x0000000a },
+ { 0x00009b48, 0x0000002a },
+ { 0x00009b4c, 0x00000001 },
+ { 0x00009b50, 0x00000021 },
+ { 0x00009b54, 0x00000011 },
+ { 0x00009b58, 0x00000031 },
+ { 0x00009b5c, 0x00000009 },
+ { 0x00009b60, 0x00000029 },
+ { 0x00009b64, 0x00000005 },
+ { 0x00009b68, 0x00000025 },
+ { 0x00009b6c, 0x00000015 },
+ { 0x00009b70, 0x00000035 },
+ { 0x00009b74, 0x0000000d },
+ { 0x00009b78, 0x0000002d },
+ { 0x00009b7c, 0x00000003 },
+ { 0x00009b80, 0x00000023 },
+ { 0x00009b84, 0x00000013 },
+ { 0x00009b88, 0x00000033 },
+ { 0x00009b8c, 0x0000000b },
+ { 0x00009b90, 0x0000002b },
+ { 0x00009b94, 0x00000007 },
+ { 0x00009b98, 0x00000027 },
+ { 0x00009b9c, 0x00000017 },
+ { 0x00009ba0, 0x00000037 },
+ { 0x00009ba4, 0x0000000f },
+ { 0x00009ba8, 0x0000002f },
+ { 0x00009bac, 0x0000002f },
+ { 0x00009bb0, 0x0000002f },
+ { 0x00009bb4, 0x0000002f },
+ { 0x00009bb8, 0x0000002f },
+ { 0x00009bbc, 0x0000002f },
+ { 0x00009bc0, 0x0000002f },
+ { 0x00009bc4, 0x0000002f },
+ { 0x00009bc8, 0x0000002f },
+ { 0x00009bcc, 0x0000002f },
+ { 0x00009bd0, 0x0000002f },
+ { 0x00009bd4, 0x0000002f },
+ { 0x00009bd8, 0x0000002f },
+ { 0x00009bdc, 0x0000002f },
+ { 0x00009be0, 0x0000002f },
+ { 0x00009be4, 0x0000002f },
+ { 0x00009be8, 0x0000002f },
+ { 0x00009bec, 0x0000002f },
+ { 0x00009bf0, 0x0000002f },
+ { 0x00009bf4, 0x0000002f },
+ { 0x00009bf8, 0x0000002f },
+ { 0x00009bfc, 0x0000002f },
+
+ /* rf gain table */
+ { 0x00009a00, 0x0000001d },
+ { 0x00009a04, 0x0000005d },
+ { 0x00009a08, 0x0000009d },
+ { 0x00009a0c, 0x000000dd },
+ { 0x00009a10, 0x0000011d },
+ { 0x00009a14, 0x00000021 },
+ { 0x00009a18, 0x00000061 },
+ { 0x00009a1c, 0x000000a1 },
+ { 0x00009a20, 0x000000e1 },
+ { 0x00009a24, 0x00000031 },
+ { 0x00009a28, 0x00000071 },
+ { 0x00009a2c, 0x000000b1 },
+ { 0x00009a30, 0x0000001c },
+ { 0x00009a34, 0x0000005c },
+ { 0x00009a38, 0x00000029 },
+ { 0x00009a3c, 0x00000069 },
+ { 0x00009a40, 0x000000a9 },
+ { 0x00009a44, 0x00000020 },
+ { 0x00009a48, 0x00000019 },
+ { 0x00009a4c, 0x00000059 },
+ { 0x00009a50, 0x00000099 },
+ { 0x00009a54, 0x00000030 },
+ { 0x00009a58, 0x00000005 },
+ { 0x00009a5c, 0x00000025 },
+ { 0x00009a60, 0x00000065 },
+ { 0x00009a64, 0x000000a5 },
+ { 0x00009a68, 0x00000028 },
+ { 0x00009a6c, 0x00000068 },
+ { 0x00009a70, 0x0000001f },
+ { 0x00009a74, 0x0000001e },
+ { 0x00009a78, 0x00000018 },
+ { 0x00009a7c, 0x00000058 },
+ { 0x00009a80, 0x00000098 },
+ { 0x00009a84, 0x00000003 },
+ { 0x00009a88, 0x00000004 },
+ { 0x00009a8c, 0x00000044 },
+ { 0x00009a90, 0x00000084 },
+ { 0x00009a94, 0x00000013 },
+ { 0x00009a98, 0x00000012 },
+ { 0x00009a9c, 0x00000052 },
+ { 0x00009aa0, 0x00000092 },
+ { 0x00009aa4, 0x000000d2 },
+ { 0x00009aa8, 0x0000002b },
+ { 0x00009aac, 0x0000002a },
+ { 0x00009ab0, 0x0000006a },
+ { 0x00009ab4, 0x000000aa },
+ { 0x00009ab8, 0x0000001b },
+ { 0x00009abc, 0x0000001a },
+ { 0x00009ac0, 0x0000005a },
+ { 0x00009ac4, 0x0000009a },
+ { 0x00009ac8, 0x000000da },
+ { 0x00009acc, 0x00000006 },
+ { 0x00009ad0, 0x00000006 },
+ { 0x00009ad4, 0x00000006 },
+ { 0x00009ad8, 0x00000006 },
+ { 0x00009adc, 0x00000006 },
+ { 0x00009ae0, 0x00000006 },
+ { 0x00009ae4, 0x00000006 },
+ { 0x00009ae8, 0x00000006 },
+ { 0x00009aec, 0x00000006 },
+ { 0x00009af0, 0x00000006 },
+ { 0x00009af4, 0x00000006 },
+ { 0x00009af8, 0x00000006 },
+ { 0x00009afc, 0x00000006 },
+
+ /* fez register init */
+ { 0x000098d4, 0x00000020 },
+ { 0x000098cc, 0x00000004 },
+ { 0x000098c8, 0x00060106 },
+ { 0x0000989c, 0x0000006d },
+ { 0x000098c0, 0x00000000 },
+ { 0x000098d0, 0x00000014 },