1185377Ssam/* 2185377Ssam * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting 3185377Ssam * Copyright (c) 2002-2008 Atheros Communications, Inc. 4185377Ssam * 5185377Ssam * Permission to use, copy, modify, and/or distribute this software for any 6185377Ssam * purpose with or without fee is hereby granted, provided that the above 7185377Ssam * copyright notice and this permission notice appear in all copies. 8185377Ssam * 9185377Ssam * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10185377Ssam * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11185377Ssam * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12185377Ssam * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13185377Ssam * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14185377Ssam * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15185377Ssam * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16185377Ssam * 17195114Ssam * $FreeBSD$ 18185377Ssam */ 19185377Ssam#include "opt_ah.h" 20185377Ssam 21185377Ssam#include "ah.h" 22185377Ssam#include "ah_internal.h" 23243169Sadrian#include "ah_desc.h" 24185377Ssam 25185377Ssam#include "ar5212/ar5212.h" 26185377Ssam#include "ar5212/ar5212reg.h" 27185377Ssam#include "ar5212/ar5212desc.h" 28185377Ssam 29185377Ssam/* 30185377Ssam * Get the RXDP. 31185377Ssam */ 32185377Ssamuint32_t 33238278Sadrianar5212GetRxDP(struct ath_hal *ath, HAL_RX_QUEUE qtype) 34185377Ssam{ 35238278Sadrian 36238278Sadrian HALASSERT(qtype == HAL_RX_QUEUE_HP); 37185377Ssam return OS_REG_READ(ath, AR_RXDP); 38185377Ssam} 39185377Ssam 40185377Ssam/* 41185377Ssam * Set the RxDP. 42185377Ssam */ 43185377Ssamvoid 44238278Sadrianar5212SetRxDP(struct ath_hal *ah, uint32_t rxdp, HAL_RX_QUEUE qtype) 45185377Ssam{ 46238278Sadrian 47238278Sadrian HALASSERT(qtype == HAL_RX_QUEUE_HP); 48185377Ssam OS_REG_WRITE(ah, AR_RXDP, rxdp); 49185377Ssam HALASSERT(OS_REG_READ(ah, AR_RXDP) == rxdp); 50185377Ssam} 51185377Ssam 52185377Ssam/* 53185377Ssam * Set Receive Enable bits. 54185377Ssam */ 55185377Ssamvoid 56185377Ssamar5212EnableReceive(struct ath_hal *ah) 57185377Ssam{ 58185377Ssam OS_REG_WRITE(ah, AR_CR, AR_CR_RXE); 59185377Ssam} 60185377Ssam 61185377Ssam/* 62185377Ssam * Stop Receive at the DMA engine 63185377Ssam */ 64185377SsamHAL_BOOL 65185377Ssamar5212StopDmaReceive(struct ath_hal *ah) 66185377Ssam{ 67220423Sadrian OS_MARK(ah, AH_MARK_RX_CTL, AH_MARK_RX_CTL_DMA_STOP); 68185377Ssam OS_REG_WRITE(ah, AR_CR, AR_CR_RXD); /* Set receive disable bit */ 69185377Ssam if (!ath_hal_wait(ah, AR_CR, AR_CR_RXE, 0)) { 70220423Sadrian OS_MARK(ah, AH_MARK_RX_CTL, AH_MARK_RX_CTL_DMA_STOP_ERR); 71185377Ssam#ifdef AH_DEBUG 72185377Ssam ath_hal_printf(ah, "%s: dma failed to stop in 10ms\n" 73185377Ssam "AR_CR=0x%08x\nAR_DIAG_SW=0x%08x\n", 74185377Ssam __func__, 75185377Ssam OS_REG_READ(ah, AR_CR), 76185377Ssam OS_REG_READ(ah, AR_DIAG_SW)); 77185377Ssam#endif 78185377Ssam return AH_FALSE; 79185377Ssam } else { 80185377Ssam return AH_TRUE; 81185377Ssam } 82185377Ssam} 83185377Ssam 84185377Ssam/* 85185377Ssam * Start Transmit at the PCU engine (unpause receive) 86185377Ssam */ 87185377Ssamvoid 88185377Ssamar5212StartPcuReceive(struct ath_hal *ah) 89185377Ssam{ 90185377Ssam struct ath_hal_private *ahp = AH_PRIVATE(ah); 91185377Ssam 92220423Sadrian OS_MARK(ah, AH_MARK_RX_CTL, AH_MARK_RX_CTL_PCU_START); 93185377Ssam OS_REG_WRITE(ah, AR_DIAG_SW, 94185377Ssam OS_REG_READ(ah, AR_DIAG_SW) &~ AR_DIAG_RX_DIS); 95185377Ssam ar5212EnableMibCounters(ah); 96185377Ssam /* NB: restore current settings */ 97185377Ssam ar5212AniReset(ah, ahp->ah_curchan, ahp->ah_opmode, AH_TRUE); 98185377Ssam} 99185377Ssam 100185377Ssam/* 101185377Ssam * Stop Transmit at the PCU engine (pause receive) 102185377Ssam */ 103185377Ssamvoid 104185377Ssamar5212StopPcuReceive(struct ath_hal *ah) 105185377Ssam{ 106220423Sadrian OS_MARK(ah, AH_MARK_RX_CTL, AH_MARK_RX_CTL_PCU_STOP); 107185377Ssam OS_REG_WRITE(ah, AR_DIAG_SW, 108185377Ssam OS_REG_READ(ah, AR_DIAG_SW) | AR_DIAG_RX_DIS); 109185377Ssam ar5212DisableMibCounters(ah); 110185377Ssam} 111185377Ssam 112185377Ssam/* 113185377Ssam * Set multicast filter 0 (lower 32-bits) 114185377Ssam * filter 1 (upper 32-bits) 115185377Ssam */ 116185377Ssamvoid 117185377Ssamar5212SetMulticastFilter(struct ath_hal *ah, uint32_t filter0, uint32_t filter1) 118185377Ssam{ 119185377Ssam OS_REG_WRITE(ah, AR_MCAST_FIL0, filter0); 120185377Ssam OS_REG_WRITE(ah, AR_MCAST_FIL1, filter1); 121185377Ssam} 122185377Ssam 123185377Ssam/* 124185377Ssam * Clear multicast filter by index 125185377Ssam */ 126185377SsamHAL_BOOL 127185377Ssamar5212ClrMulticastFilterIndex(struct ath_hal *ah, uint32_t ix) 128185377Ssam{ 129185377Ssam uint32_t val; 130185377Ssam 131185377Ssam if (ix >= 64) 132185377Ssam return AH_FALSE; 133185377Ssam if (ix >= 32) { 134185377Ssam val = OS_REG_READ(ah, AR_MCAST_FIL1); 135185377Ssam OS_REG_WRITE(ah, AR_MCAST_FIL1, (val &~ (1<<(ix-32)))); 136185377Ssam } else { 137185377Ssam val = OS_REG_READ(ah, AR_MCAST_FIL0); 138185377Ssam OS_REG_WRITE(ah, AR_MCAST_FIL0, (val &~ (1<<ix))); 139185377Ssam } 140185377Ssam return AH_TRUE; 141185377Ssam} 142185377Ssam 143185377Ssam/* 144185377Ssam * Set multicast filter by index 145185377Ssam */ 146185377SsamHAL_BOOL 147185377Ssamar5212SetMulticastFilterIndex(struct ath_hal *ah, uint32_t ix) 148185377Ssam{ 149185377Ssam uint32_t val; 150185377Ssam 151185377Ssam if (ix >= 64) 152185377Ssam return AH_FALSE; 153185377Ssam if (ix >= 32) { 154185377Ssam val = OS_REG_READ(ah, AR_MCAST_FIL1); 155185377Ssam OS_REG_WRITE(ah, AR_MCAST_FIL1, (val | (1<<(ix-32)))); 156185377Ssam } else { 157185377Ssam val = OS_REG_READ(ah, AR_MCAST_FIL0); 158185377Ssam OS_REG_WRITE(ah, AR_MCAST_FIL0, (val | (1<<ix))); 159185377Ssam } 160185377Ssam return AH_TRUE; 161185377Ssam} 162185377Ssam 163185377Ssam/* 164185377Ssam * Get the receive filter. 165185377Ssam */ 166185377Ssamuint32_t 167185377Ssamar5212GetRxFilter(struct ath_hal *ah) 168185377Ssam{ 169185377Ssam uint32_t bits = OS_REG_READ(ah, AR_RX_FILTER); 170185377Ssam uint32_t phybits = OS_REG_READ(ah, AR_PHY_ERR); 171185377Ssam if (phybits & AR_PHY_ERR_RADAR) 172185377Ssam bits |= HAL_RX_FILTER_PHYRADAR; 173185377Ssam if (phybits & (AR_PHY_ERR_OFDM_TIMING|AR_PHY_ERR_CCK_TIMING)) 174185377Ssam bits |= HAL_RX_FILTER_PHYERR; 175195114Ssam if (AH_PRIVATE(ah)->ah_caps.halBssidMatchSupport && 176195809Ssam (AH5212(ah)->ah_miscMode & AR_MISC_MODE_BSSID_MATCH_FORCE)) 177195114Ssam bits |= HAL_RX_FILTER_BSSID; 178185377Ssam return bits; 179185377Ssam} 180185377Ssam 181185377Ssam/* 182185377Ssam * Set the receive filter. 183185377Ssam */ 184185377Ssamvoid 185185377Ssamar5212SetRxFilter(struct ath_hal *ah, uint32_t bits) 186185377Ssam{ 187195809Ssam struct ath_hal_5212 *ahp = AH5212(ah); 188185377Ssam uint32_t phybits; 189185377Ssam 190185377Ssam OS_REG_WRITE(ah, AR_RX_FILTER, 191195114Ssam bits &~ (HAL_RX_FILTER_PHYRADAR|HAL_RX_FILTER_PHYERR| 192195114Ssam HAL_RX_FILTER_BSSID)); 193185377Ssam phybits = 0; 194185377Ssam if (bits & HAL_RX_FILTER_PHYRADAR) 195185377Ssam phybits |= AR_PHY_ERR_RADAR; 196185377Ssam if (bits & HAL_RX_FILTER_PHYERR) 197185377Ssam phybits |= AR_PHY_ERR_OFDM_TIMING | AR_PHY_ERR_CCK_TIMING; 198185377Ssam OS_REG_WRITE(ah, AR_PHY_ERR, phybits); 199185377Ssam if (phybits) { 200185377Ssam OS_REG_WRITE(ah, AR_RXCFG, 201185377Ssam OS_REG_READ(ah, AR_RXCFG) | AR_RXCFG_ZLFDMA); 202185377Ssam } else { 203185377Ssam OS_REG_WRITE(ah, AR_RXCFG, 204185377Ssam OS_REG_READ(ah, AR_RXCFG) &~ AR_RXCFG_ZLFDMA); 205185377Ssam } 206195114Ssam if (AH_PRIVATE(ah)->ah_caps.halBssidMatchSupport) { 207195114Ssam if (bits & HAL_RX_FILTER_BSSID) 208195809Ssam ahp->ah_miscMode |= AR_MISC_MODE_BSSID_MATCH_FORCE; 209195114Ssam else 210195809Ssam ahp->ah_miscMode &= ~AR_MISC_MODE_BSSID_MATCH_FORCE; 211219771Sadrian OS_REG_WRITE(ah, AR_MISC_MODE, OS_REG_READ(ah, AR_MISC_MODE) | ahp->ah_miscMode); 212195114Ssam } 213185377Ssam} 214185377Ssam 215185377Ssam/* 216185377Ssam * Initialize RX descriptor, by clearing the status and setting 217185377Ssam * the size (and any other flags). 218185377Ssam */ 219185377SsamHAL_BOOL 220185377Ssamar5212SetupRxDesc(struct ath_hal *ah, struct ath_desc *ds, 221185377Ssam uint32_t size, u_int flags) 222185377Ssam{ 223185377Ssam struct ar5212_desc *ads = AR5212DESC(ds); 224185377Ssam 225185377Ssam HALASSERT((size &~ AR_BufLen) == 0); 226185377Ssam 227185377Ssam ads->ds_ctl0 = 0; 228185377Ssam ads->ds_ctl1 = size & AR_BufLen; 229185377Ssam 230185377Ssam if (flags & HAL_RXDESC_INTREQ) 231185377Ssam ads->ds_ctl1 |= AR_RxInterReq; 232185377Ssam ads->ds_rxstatus0 = ads->ds_rxstatus1 = 0; 233185377Ssam 234185377Ssam return AH_TRUE; 235185377Ssam} 236185377Ssam 237185377Ssam/* 238185377Ssam * Process an RX descriptor, and return the status to the caller. 239185377Ssam * Copy some hardware specific items into the software portion 240185377Ssam * of the descriptor. 241185377Ssam * 242185377Ssam * NB: the caller is responsible for validating the memory contents 243185377Ssam * of the descriptor (e.g. flushing any cached copy). 244185377Ssam */ 245185377SsamHAL_STATUS 246185377Ssamar5212ProcRxDesc(struct ath_hal *ah, struct ath_desc *ds, 247185377Ssam uint32_t pa, struct ath_desc *nds, uint64_t tsf, 248185377Ssam struct ath_rx_status *rs) 249185377Ssam{ 250185377Ssam struct ar5212_desc *ads = AR5212DESC(ds); 251185377Ssam struct ar5212_desc *ands = AR5212DESC(nds); 252185377Ssam 253185377Ssam if ((ads->ds_rxstatus1 & AR_Done) == 0) 254185377Ssam return HAL_EINPROGRESS; 255185377Ssam /* 256185377Ssam * Given the use of a self-linked tail be very sure that the hw is 257185377Ssam * done with this descriptor; the hw may have done this descriptor 258185377Ssam * once and picked it up again...make sure the hw has moved on. 259185377Ssam */ 260185377Ssam if ((ands->ds_rxstatus1&AR_Done) == 0 && OS_REG_READ(ah, AR_RXDP) == pa) 261185377Ssam return HAL_EINPROGRESS; 262185377Ssam 263185377Ssam rs->rs_datalen = ads->ds_rxstatus0 & AR_DataLen; 264185377Ssam rs->rs_tstamp = MS(ads->ds_rxstatus1, AR_RcvTimestamp); 265185377Ssam rs->rs_status = 0; 266185377Ssam /* XXX what about KeyCacheMiss? */ 267185377Ssam rs->rs_rssi = MS(ads->ds_rxstatus0, AR_RcvSigStrength); 268185377Ssam /* discard invalid h/w rssi data */ 269185377Ssam if (rs->rs_rssi == -128) 270185377Ssam rs->rs_rssi = 0; 271185377Ssam if (ads->ds_rxstatus1 & AR_KeyIdxValid) 272185377Ssam rs->rs_keyix = MS(ads->ds_rxstatus1, AR_KeyIdx); 273185377Ssam else 274185377Ssam rs->rs_keyix = HAL_RXKEYIX_INVALID; 275185377Ssam /* NB: caller expected to do rate table mapping */ 276185377Ssam rs->rs_rate = MS(ads->ds_rxstatus0, AR_RcvRate); 277185377Ssam rs->rs_antenna = MS(ads->ds_rxstatus0, AR_RcvAntenna); 278185377Ssam rs->rs_more = (ads->ds_rxstatus0 & AR_More) ? 1 : 0; 279185377Ssam 280239966Sadrian /* 281239966Sadrian * The AR5413 (at least) sometimes sets both AR_CRCErr and 282239966Sadrian * AR_PHYErr when reporting radar pulses. In this instance 283239966Sadrian * set HAL_RXERR_PHY as well as HAL_RXERR_CRC and 284239966Sadrian * let the driver layer figure out what to do. 285239966Sadrian * 286239966Sadrian * See PR kern/169362. 287239966Sadrian */ 288185377Ssam if ((ads->ds_rxstatus1 & AR_FrmRcvOK) == 0) { 289185377Ssam /* 290185377Ssam * These four bits should not be set together. The 291185377Ssam * 5212 spec states a Michael error can only occur if 292185377Ssam * DecryptCRCErr not set (and TKIP is used). Experience 293185377Ssam * indicates however that you can also get Michael errors 294185377Ssam * when a CRC error is detected, but these are specious. 295185377Ssam * Consequently we filter them out here so we don't 296185377Ssam * confuse and/or complicate drivers. 297185377Ssam */ 298239966Sadrian if (ads->ds_rxstatus1 & AR_PHYErr) { 299185377Ssam u_int phyerr; 300185377Ssam 301185377Ssam rs->rs_status |= HAL_RXERR_PHY; 302185377Ssam phyerr = MS(ads->ds_rxstatus1, AR_PHYErrCode); 303185377Ssam rs->rs_phyerr = phyerr; 304185377Ssam if (!AH5212(ah)->ah_hasHwPhyCounters && 305185377Ssam phyerr != HAL_PHYERR_RADAR) 306185377Ssam ar5212AniPhyErrReport(ah, rs); 307239966Sadrian } 308239966Sadrian 309239966Sadrian if (ads->ds_rxstatus1 & AR_CRCErr) 310239966Sadrian rs->rs_status |= HAL_RXERR_CRC; 311239966Sadrian else if (ads->ds_rxstatus1 & AR_DecryptCRCErr) 312185377Ssam rs->rs_status |= HAL_RXERR_DECRYPT; 313185377Ssam else if (ads->ds_rxstatus1 & AR_MichaelErr) 314185377Ssam rs->rs_status |= HAL_RXERR_MIC; 315185377Ssam } 316185377Ssam return HAL_OK; 317185377Ssam} 318