Path: blob/main/sys/dev/ath/ath_hal/ar5210/ar5210_misc.c
39566 views
/*-1* SPDX-License-Identifier: ISC2*3* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting4* Copyright (c) 2002-2004 Atheros Communications, Inc.5*6* Permission to use, copy, modify, and/or distribute this software for any7* purpose with or without fee is hereby granted, provided that the above8* copyright notice and this permission notice appear in all copies.9*10* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES11* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF12* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR13* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES14* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN15* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF16* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.17*/18#include "opt_ah.h"1920#include "ah.h"21#include "ah_internal.h"2223#include "ar5210/ar5210.h"24#include "ar5210/ar5210reg.h"25#include "ar5210/ar5210phy.h"2627#include "ah_eeprom_v1.h"2829#define AR_NUM_GPIO 6 /* 6 GPIO bits */30#define AR_GPIOD_MASK 0x2f /* 6-bit mask */3132void33ar5210GetMacAddress(struct ath_hal *ah, uint8_t *mac)34{35struct ath_hal_5210 *ahp = AH5210(ah);3637OS_MEMCPY(mac, ahp->ah_macaddr, IEEE80211_ADDR_LEN);38}3940HAL_BOOL41ar5210SetMacAddress(struct ath_hal *ah, const uint8_t *mac)42{43struct ath_hal_5210 *ahp = AH5210(ah);4445OS_MEMCPY(ahp->ah_macaddr, mac, IEEE80211_ADDR_LEN);46return AH_TRUE;47}4849void50ar5210GetBssIdMask(struct ath_hal *ah, uint8_t *mask)51{52static const uint8_t ones[IEEE80211_ADDR_LEN] =53{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };54OS_MEMCPY(mask, ones, IEEE80211_ADDR_LEN);55}5657HAL_BOOL58ar5210SetBssIdMask(struct ath_hal *ah, const uint8_t *mask)59{60return AH_FALSE;61}6263/*64* Read 16 bits of data from the specified EEPROM offset.65*/66HAL_BOOL67ar5210EepromRead(struct ath_hal *ah, u_int off, uint16_t *data)68{69(void) OS_REG_READ(ah, AR_EP_AIR(off)); /* activate read op */70if (!ath_hal_wait(ah, AR_EP_STA,71AR_EP_STA_RDCMPLT | AR_EP_STA_RDERR, AR_EP_STA_RDCMPLT)) {72HALDEBUG(ah, HAL_DEBUG_ANY, "%s: read failed for entry 0x%x\n",73__func__, AR_EP_AIR(off));74return AH_FALSE;75}76*data = OS_REG_READ(ah, AR_EP_RDATA) & 0xffff;77return AH_TRUE;78}7980#ifdef AH_SUPPORT_WRITE_EEPROM81/*82* Write 16 bits of data to the specified EEPROM offset.83*/84HAL_BOOL85ar5210EepromWrite(struct ath_hal *ah, u_int off, uint16_t data)86{87return AH_FALSE;88}89#endif /* AH_SUPPORT_WRITE_EEPROM */9091/*92* Attempt to change the cards operating regulatory domain to the given value93*/94HAL_BOOL95ar5210SetRegulatoryDomain(struct ath_hal *ah,96uint16_t regDomain, HAL_STATUS *status)97{98HAL_STATUS ecode;99100if (AH_PRIVATE(ah)->ah_currentRD == regDomain) {101ecode = HAL_EINVAL;102goto bad;103}104/*105* Check if EEPROM is configured to allow this; must106* be a proper version and the protection bits must107* permit re-writing that segment of the EEPROM.108*/109if (ath_hal_eepromGetFlag(ah, AR_EEP_WRITEPROTECT)) {110ecode = HAL_EEWRITE;111goto bad;112}113ecode = HAL_EIO; /* disallow all writes */114bad:115if (status)116*status = ecode;117return AH_FALSE;118}119120/*121* Return the wireless modes (a,b,g,t) supported by hardware.122*123* This value is what is actually supported by the hardware124* and is unaffected by regulatory/country code settings.125*126*/127u_int128ar5210GetWirelessModes(struct ath_hal *ah)129{130/* XXX could enable turbo mode but can't do all rates */131return HAL_MODE_11A;132}133134/*135* Called if RfKill is supported (according to EEPROM). Set the interrupt and136* GPIO values so the ISR and can disable RF on a switch signal137*/138void139ar5210EnableRfKill(struct ath_hal *ah)140{141uint16_t rfsilent = AH_PRIVATE(ah)->ah_rfsilent;142int select = MS(rfsilent, AR_EEPROM_RFSILENT_GPIO_SEL);143int polarity = MS(rfsilent, AR_EEPROM_RFSILENT_POLARITY);144145/*146* If radio disable switch connection to GPIO bit 0 is enabled147* program GPIO interrupt.148* If rfkill bit on eeprom is 1, setupeeprommap routine has already149* verified that it is a later version of eeprom, it has a place for150* rfkill bit and it is set to 1, indicating that GPIO bit 0 hardware151* connection is present.152*/153ar5210Gpio0SetIntr(ah, select, (ar5210GpioGet(ah, select) == polarity));154}155156/*157* Configure GPIO Output lines158*/159HAL_BOOL160ar5210GpioCfgOutput(struct ath_hal *ah, uint32_t gpio, HAL_GPIO_MUX_TYPE type)161{162HALASSERT(gpio < AR_NUM_GPIO);163164OS_REG_WRITE(ah, AR_GPIOCR,165(OS_REG_READ(ah, AR_GPIOCR) &~ AR_GPIOCR_ALL(gpio))166| AR_GPIOCR_OUT1(gpio));167168return AH_TRUE;169}170171/*172* Configure GPIO Input lines173*/174HAL_BOOL175ar5210GpioCfgInput(struct ath_hal *ah, uint32_t gpio)176{177HALASSERT(gpio < AR_NUM_GPIO);178179OS_REG_WRITE(ah, AR_GPIOCR,180(OS_REG_READ(ah, AR_GPIOCR) &~ AR_GPIOCR_ALL(gpio))181| AR_GPIOCR_IN(gpio));182183return AH_TRUE;184}185186/*187* Once configured for I/O - set output lines188*/189HAL_BOOL190ar5210GpioSet(struct ath_hal *ah, uint32_t gpio, uint32_t val)191{192uint32_t reg;193194HALASSERT(gpio < AR_NUM_GPIO);195196reg = OS_REG_READ(ah, AR_GPIODO);197reg &= ~(1 << gpio);198reg |= (val&1) << gpio;199200OS_REG_WRITE(ah, AR_GPIODO, reg);201return AH_TRUE;202}203204/*205* Once configured for I/O - get input lines206*/207uint32_t208ar5210GpioGet(struct ath_hal *ah, uint32_t gpio)209{210if (gpio < AR_NUM_GPIO) {211uint32_t val = OS_REG_READ(ah, AR_GPIODI);212val = ((val & AR_GPIOD_MASK) >> gpio) & 0x1;213return val;214} else {215return 0xffffffff;216}217}218219/*220* Set the GPIO 0 Interrupt221*/222void223ar5210Gpio0SetIntr(struct ath_hal *ah, u_int gpio, uint32_t ilevel)224{225uint32_t val = OS_REG_READ(ah, AR_GPIOCR);226227/* Clear the bits that we will modify. */228val &= ~(AR_GPIOCR_INT_SEL(gpio) | AR_GPIOCR_INT_SELH | AR_GPIOCR_INT_ENA |229AR_GPIOCR_ALL(gpio));230231val |= AR_GPIOCR_INT_SEL(gpio) | AR_GPIOCR_INT_ENA;232if (ilevel)233val |= AR_GPIOCR_INT_SELH;234235/* Don't need to change anything for low level interrupt. */236OS_REG_WRITE(ah, AR_GPIOCR, val);237238/* Change the interrupt mask. */239ar5210SetInterrupts(ah, AH5210(ah)->ah_maskReg | HAL_INT_GPIO);240}241242/*243* Change the LED blinking pattern to correspond to the connectivity244*/245void246ar5210SetLedState(struct ath_hal *ah, HAL_LED_STATE state)247{248uint32_t val;249250val = OS_REG_READ(ah, AR_PCICFG);251switch (state) {252case HAL_LED_INIT:253val &= ~(AR_PCICFG_LED_PEND | AR_PCICFG_LED_ACT);254break;255case HAL_LED_RUN:256/* normal blink when connected */257val &= ~AR_PCICFG_LED_PEND;258val |= AR_PCICFG_LED_ACT;259break;260default:261val |= AR_PCICFG_LED_PEND;262val &= ~AR_PCICFG_LED_ACT;263break;264}265OS_REG_WRITE(ah, AR_PCICFG, val);266}267268/*269* Return 1 or 2 for the corresponding antenna that is in use270*/271u_int272ar5210GetDefAntenna(struct ath_hal *ah)273{274uint32_t val = OS_REG_READ(ah, AR_STA_ID1);275return (val & AR_STA_ID1_DEFAULT_ANTENNA ? 2 : 1);276}277278void279ar5210SetDefAntenna(struct ath_hal *ah, u_int antenna)280{281uint32_t val = OS_REG_READ(ah, AR_STA_ID1);282283if (antenna != (val & AR_STA_ID1_DEFAULT_ANTENNA ? 2 : 1)) {284/*285* Antenna change requested, force a toggle of the default.286*/287OS_REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_DEFAULT_ANTENNA);288}289}290291HAL_ANT_SETTING292ar5210GetAntennaSwitch(struct ath_hal *ah)293{294return HAL_ANT_VARIABLE;295}296297HAL_BOOL298ar5210SetAntennaSwitch(struct ath_hal *ah, HAL_ANT_SETTING settings)299{300/* XXX not sure how to fix antenna */301return (settings == HAL_ANT_VARIABLE);302}303304/*305* Change association related fields programmed into the hardware.306* Writing a valid BSSID to the hardware effectively enables the hardware307* to synchronize its TSF to the correct beacons and receive frames coming308* from that BSSID. It is called by the SME JOIN operation.309*/310void311ar5210WriteAssocid(struct ath_hal *ah, const uint8_t *bssid, uint16_t assocId)312{313struct ath_hal_5210 *ahp = AH5210(ah);314315/* XXX save bssid for possible re-use on reset */316OS_MEMCPY(ahp->ah_bssid, bssid, IEEE80211_ADDR_LEN);317ahp->ah_associd = assocId;318OS_REG_WRITE(ah, AR_BSS_ID0, LE_READ_4(ahp->ah_bssid));319OS_REG_WRITE(ah, AR_BSS_ID1, LE_READ_2(ahp->ah_bssid+4) |320((assocId & 0x3fff)<<AR_BSS_ID1_AID_S));321if (assocId == 0)322OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_NO_PSPOLL);323else324OS_REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_NO_PSPOLL);325}326327/*328* Get the current hardware tsf for stamlme.329*/330uint64_t331ar5210GetTsf64(struct ath_hal *ah)332{333uint32_t low1, low2, u32;334335/* sync multi-word read */336low1 = OS_REG_READ(ah, AR_TSF_L32);337u32 = OS_REG_READ(ah, AR_TSF_U32);338low2 = OS_REG_READ(ah, AR_TSF_L32);339if (low2 < low1) { /* roll over */340/*341* If we are not preempted this will work. If we are342* then we re-reading AR_TSF_U32 does no good as the343* low bits will be meaningless. Likewise reading344* L32, U32, U32, then comparing the last two reads345* to check for rollover doesn't help if preempted--so346* we take this approach as it costs one less PCI347* read which can be noticeable when doing things348* like timestamping packets in monitor mode.349*/350u32++;351}352return (((uint64_t) u32) << 32) | ((uint64_t) low2);353}354355/*356* Get the current hardware tsf for stamlme.357*/358uint32_t359ar5210GetTsf32(struct ath_hal *ah)360{361return OS_REG_READ(ah, AR_TSF_L32);362}363364/*365* Reset the current hardware tsf for stamlme366*/367void368ar5210ResetTsf(struct ath_hal *ah)369{370uint32_t val = OS_REG_READ(ah, AR_BEACON);371372OS_REG_WRITE(ah, AR_BEACON, val | AR_BEACON_RESET_TSF);373}374375/*376* Grab a semi-random value from hardware registers - may not377* change often378*/379uint32_t380ar5210GetRandomSeed(struct ath_hal *ah)381{382uint32_t nf;383384nf = (OS_REG_READ(ah, AR_PHY_BASE + (25 << 2)) >> 19) & 0x1ff;385if (nf & 0x100)386nf = 0 - ((nf ^ 0x1ff) + 1);387return (OS_REG_READ(ah, AR_TSF_U32) ^388OS_REG_READ(ah, AR_TSF_L32) ^ nf);389}390391/*392* Detect if our card is present393*/394HAL_BOOL395ar5210DetectCardPresent(struct ath_hal *ah)396{397/*398* Read the Silicon Revision register and compare that399* to what we read at attach time. If the same, we say400* a card/device is present.401*/402return (AH_PRIVATE(ah)->ah_macRev == (OS_REG_READ(ah, AR_SREV) & 0xff));403}404405/*406* Update MIB Counters407*/408void409ar5210UpdateMibCounters(struct ath_hal *ah, HAL_MIB_STATS *stats)410{411stats->ackrcv_bad += OS_REG_READ(ah, AR_ACK_FAIL);412stats->rts_bad += OS_REG_READ(ah, AR_RTS_FAIL);413stats->fcs_bad += OS_REG_READ(ah, AR_FCS_FAIL);414stats->rts_good += OS_REG_READ(ah, AR_RTS_OK);415stats->beacons += OS_REG_READ(ah, AR_BEACON_CNT);416}417418HAL_BOOL419ar5210SetSifsTime(struct ath_hal *ah, u_int us)420{421struct ath_hal_5210 *ahp = AH5210(ah);422423if (us > ath_hal_mac_usec(ah, 0x7ff)) {424HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad SIFS time %u\n",425__func__, us);426ahp->ah_sifstime = (u_int) -1; /* restore default handling */427return AH_FALSE;428} else {429/* convert to system clocks */430OS_REG_RMW_FIELD(ah, AR_IFS0, AR_IFS0_SIFS,431ath_hal_mac_clks(ah, us));432ahp->ah_sifstime = us;433return AH_TRUE;434}435}436437u_int438ar5210GetSifsTime(struct ath_hal *ah)439{440u_int clks = OS_REG_READ(ah, AR_IFS0) & 0x7ff;441return ath_hal_mac_usec(ah, clks); /* convert from system clocks */442}443444HAL_BOOL445ar5210SetSlotTime(struct ath_hal *ah, u_int us)446{447struct ath_hal_5210 *ahp = AH5210(ah);448449if (us < HAL_SLOT_TIME_9 || us > ath_hal_mac_usec(ah, 0xffff)) {450HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad slot time %u\n",451__func__, us);452ahp->ah_slottime = (u_int) -1; /* restore default handling */453return AH_FALSE;454} else {455/* convert to system clocks */456OS_REG_WRITE(ah, AR_SLOT_TIME, ath_hal_mac_clks(ah, us));457ahp->ah_slottime = us;458return AH_TRUE;459}460}461462u_int463ar5210GetSlotTime(struct ath_hal *ah)464{465u_int clks = OS_REG_READ(ah, AR_SLOT_TIME) & 0xffff;466return ath_hal_mac_usec(ah, clks); /* convert from system clocks */467}468469HAL_BOOL470ar5210SetAckTimeout(struct ath_hal *ah, u_int us)471{472struct ath_hal_5210 *ahp = AH5210(ah);473474if (us > ath_hal_mac_usec(ah, MS(0xffffffff, AR_TIME_OUT_ACK))) {475HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad ack timeout %u\n",476__func__, us);477ahp->ah_acktimeout = (u_int) -1; /* restore default handling */478return AH_FALSE;479} else {480/* convert to system clocks */481OS_REG_RMW_FIELD(ah, AR_TIME_OUT,482AR_TIME_OUT_ACK, ath_hal_mac_clks(ah, us));483ahp->ah_acktimeout = us;484return AH_TRUE;485}486}487488u_int489ar5210GetAckTimeout(struct ath_hal *ah)490{491u_int clks = MS(OS_REG_READ(ah, AR_TIME_OUT), AR_TIME_OUT_ACK);492return ath_hal_mac_usec(ah, clks); /* convert from system clocks */493}494495u_int496ar5210GetAckCTSRate(struct ath_hal *ah)497{498return ((AH5210(ah)->ah_staId1Defaults & AR_STA_ID1_ACKCTS_6MB) == 0);499}500501HAL_BOOL502ar5210SetAckCTSRate(struct ath_hal *ah, u_int high)503{504struct ath_hal_5210 *ahp = AH5210(ah);505506if (high) {507OS_REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_ACKCTS_6MB);508ahp->ah_staId1Defaults &= ~AR_STA_ID1_ACKCTS_6MB;509} else {510OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_ACKCTS_6MB);511ahp->ah_staId1Defaults |= AR_STA_ID1_ACKCTS_6MB;512}513return AH_TRUE;514}515516HAL_BOOL517ar5210SetCTSTimeout(struct ath_hal *ah, u_int us)518{519struct ath_hal_5210 *ahp = AH5210(ah);520521if (us > ath_hal_mac_usec(ah, MS(0xffffffff, AR_TIME_OUT_CTS))) {522HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad cts timeout %u\n",523__func__, us);524ahp->ah_ctstimeout = (u_int) -1; /* restore default handling */525return AH_FALSE;526} else {527/* convert to system clocks */528OS_REG_RMW_FIELD(ah, AR_TIME_OUT,529AR_TIME_OUT_CTS, ath_hal_mac_clks(ah, us));530ahp->ah_ctstimeout = us;531return AH_TRUE;532}533}534535u_int536ar5210GetCTSTimeout(struct ath_hal *ah)537{538u_int clks = MS(OS_REG_READ(ah, AR_TIME_OUT), AR_TIME_OUT_CTS);539return ath_hal_mac_usec(ah, clks); /* convert from system clocks */540}541542HAL_BOOL543ar5210SetDecompMask(struct ath_hal *ah, uint16_t keyidx, int en)544{545/* nothing to do */546return AH_TRUE;547}548549void550ar5210SetCoverageClass(struct ath_hal *ah, uint8_t coverageclass, int now)551{552}553554HAL_STATUS555ar5210SetQuiet(struct ath_hal *ah, uint32_t period, uint32_t duration,556uint32_t next_start, HAL_QUIET_FLAG flags)557{558return HAL_OK;559}560561/*562* Control Adaptive Noise Immunity Parameters563*/564HAL_BOOL565ar5210AniControl(struct ath_hal *ah, HAL_ANI_CMD cmd, int param)566{567return AH_FALSE;568}569570void571ar5210RxMonitor(struct ath_hal *ah, const HAL_NODE_STATS *stats,572const struct ieee80211_channel *chan)573{574}575576void577ar5210AniPoll(struct ath_hal *ah, const struct ieee80211_channel *chan)578{579}580581void582ar5210MibEvent(struct ath_hal *ah, const HAL_NODE_STATS *stats)583{584}585586HAL_STATUS587ar5210GetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type,588uint32_t capability, uint32_t *result)589{590591switch (type) {592case HAL_CAP_CIPHER: /* cipher handled in hardware */593#if 0594return (capability == HAL_CIPHER_WEP ? HAL_OK : HAL_ENOTSUPP);595#else596return HAL_ENOTSUPP;597#endif598default:599return ath_hal_getcapability(ah, type, capability, result);600}601}602603HAL_BOOL604ar5210SetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type,605uint32_t capability, uint32_t setting, HAL_STATUS *status)606{607608switch (type) {609case HAL_CAP_DIAG: /* hardware diagnostic support */610/*611* NB: could split this up into virtual capabilities,612* (e.g. 1 => ACK, 2 => CTS, etc.) but it hardly613* seems worth the additional complexity.614*/615#ifdef AH_DEBUG616AH_PRIVATE(ah)->ah_diagreg = setting;617#else618AH_PRIVATE(ah)->ah_diagreg = setting & 0x6; /* ACK+CTS */619#endif620ar5210UpdateDiagReg(ah, AH_PRIVATE(ah)->ah_diagreg);621return AH_TRUE;622case HAL_CAP_RXORN_FATAL: /* HAL_INT_RXORN treated as fatal */623return AH_FALSE; /* NB: disallow */624default:625return ath_hal_setcapability(ah, type, capability,626setting, status);627}628}629630HAL_BOOL631ar5210GetDiagState(struct ath_hal *ah, int request,632const void *args, uint32_t argsize,633void **result, uint32_t *resultsize)634{635#ifdef AH_PRIVATE_DIAG636uint32_t pcicfg;637HAL_BOOL ok;638639switch (request) {640case HAL_DIAG_EEPROM:641/* XXX */642break;643case HAL_DIAG_EEREAD:644if (argsize != sizeof(uint16_t))645return AH_FALSE;646pcicfg = OS_REG_READ(ah, AR_PCICFG);647OS_REG_WRITE(ah, AR_PCICFG, pcicfg | AR_PCICFG_EEPROMSEL);648ok = ath_hal_eepromRead(ah, *(const uint16_t *)args, *result);649OS_REG_WRITE(ah, AR_PCICFG, pcicfg);650if (ok)651*resultsize = sizeof(uint16_t);652return ok;653}654#endif655return ath_hal_getdiagstate(ah, request,656args, argsize, result, resultsize);657}658659/*660* Return what percentage of the extension channel is busy.661* This is always disabled for AR5210 series NICs.662*/663uint32_t664ar5210Get11nExtBusy(struct ath_hal *ah)665{666667return (0);668}669670/*671* There's no channel survey support for the AR5210.672*/673HAL_BOOL674ar5210GetMibCycleCounts(struct ath_hal *ah, HAL_SURVEY_SAMPLE *hsample)675{676677return (AH_FALSE);678}679680void681ar5210SetChainMasks(struct ath_hal *ah, uint32_t txchainmask,682uint32_t rxchainmask)683{684}685686void687ar5210EnableDfs(struct ath_hal *ah, HAL_PHYERR_PARAM *pe)688{689}690691void692ar5210GetDfsThresh(struct ath_hal *ah, HAL_PHYERR_PARAM *pe)693{694}695696/*697* Update the diagnostic register.698*699* This merges in the diagnostic register setting with the default700* value, which may or may not involve disabling hardware encryption.701*/702void703ar5210UpdateDiagReg(struct ath_hal *ah, uint32_t val)704{705706/* Disable all hardware encryption */707val |= AR_DIAG_SW_DIS_CRYPTO;708OS_REG_WRITE(ah, AR_DIAG_SW, val);709}710711/*712* Get the current NAV value from the hardware.713*/714u_int715ar5210GetNav(struct ath_hal *ah)716{717uint32_t reg;718719reg = OS_REG_READ(ah, AR_NAV);720return (reg);721}722723/*724* Set the current NAV value to the hardware.725*/726void727ar5210SetNav(struct ath_hal *ah, u_int val)728{729730OS_REG_WRITE(ah, AR_NAV, val);731}732733734735