ar5212_recv.c revision 220423
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: head/sys/dev/ath/ath_hal/ar5212/ar5212_recv.c 220423 2011-04-07 13:14:51Z adrian $ 18185377Ssam */ 19185377Ssam#include "opt_ah.h" 20185377Ssam 21185377Ssam#include "ah.h" 22185377Ssam#include "ah_internal.h" 23185377Ssam 24185377Ssam#include "ar5212/ar5212.h" 25185377Ssam#include "ar5212/ar5212reg.h" 26185377Ssam#include "ar5212/ar5212desc.h" 27185377Ssam 28185377Ssam/* 29185377Ssam * Get the RXDP. 30185377Ssam */ 31185377Ssamuint32_t 32185377Ssamar5212GetRxDP(struct ath_hal *ath) 33185377Ssam{ 34185377Ssam return OS_REG_READ(ath, AR_RXDP); 35185377Ssam} 36185377Ssam 37185377Ssam/* 38185377Ssam * Set the RxDP. 39185377Ssam */ 40185377Ssamvoid 41185377Ssamar5212SetRxDP(struct ath_hal *ah, uint32_t rxdp) 42185377Ssam{ 43185377Ssam OS_REG_WRITE(ah, AR_RXDP, rxdp); 44185377Ssam HALASSERT(OS_REG_READ(ah, AR_RXDP) == rxdp); 45185377Ssam} 46185377Ssam 47185377Ssam/* 48185377Ssam * Set Receive Enable bits. 49185377Ssam */ 50185377Ssamvoid 51185377Ssamar5212EnableReceive(struct ath_hal *ah) 52185377Ssam{ 53185377Ssam OS_REG_WRITE(ah, AR_CR, AR_CR_RXE); 54185377Ssam} 55185377Ssam 56185377Ssam/* 57185377Ssam * Stop Receive at the DMA engine 58185377Ssam */ 59185377SsamHAL_BOOL 60185377Ssamar5212StopDmaReceive(struct ath_hal *ah) 61185377Ssam{ 62220423Sadrian OS_MARK(ah, AH_MARK_RX_CTL, AH_MARK_RX_CTL_DMA_STOP); 63185377Ssam OS_REG_WRITE(ah, AR_CR, AR_CR_RXD); /* Set receive disable bit */ 64185377Ssam if (!ath_hal_wait(ah, AR_CR, AR_CR_RXE, 0)) { 65220423Sadrian OS_MARK(ah, AH_MARK_RX_CTL, AH_MARK_RX_CTL_DMA_STOP_ERR); 66185377Ssam#ifdef AH_DEBUG 67185377Ssam ath_hal_printf(ah, "%s: dma failed to stop in 10ms\n" 68185377Ssam "AR_CR=0x%08x\nAR_DIAG_SW=0x%08x\n", 69185377Ssam __func__, 70185377Ssam OS_REG_READ(ah, AR_CR), 71185377Ssam OS_REG_READ(ah, AR_DIAG_SW)); 72185377Ssam#endif 73185377Ssam return AH_FALSE; 74185377Ssam } else { 75185377Ssam return AH_TRUE; 76185377Ssam } 77185377Ssam} 78185377Ssam 79185377Ssam/* 80185377Ssam * Start Transmit at the PCU engine (unpause receive) 81185377Ssam */ 82185377Ssamvoid 83185377Ssamar5212StartPcuReceive(struct ath_hal *ah) 84185377Ssam{ 85185377Ssam struct ath_hal_private *ahp = AH_PRIVATE(ah); 86185377Ssam 87220423Sadrian OS_MARK(ah, AH_MARK_RX_CTL, AH_MARK_RX_CTL_PCU_START); 88185377Ssam OS_REG_WRITE(ah, AR_DIAG_SW, 89185377Ssam OS_REG_READ(ah, AR_DIAG_SW) &~ AR_DIAG_RX_DIS); 90185377Ssam ar5212EnableMibCounters(ah); 91185377Ssam /* NB: restore current settings */ 92185377Ssam ar5212AniReset(ah, ahp->ah_curchan, ahp->ah_opmode, AH_TRUE); 93185377Ssam} 94185377Ssam 95185377Ssam/* 96185377Ssam * Stop Transmit at the PCU engine (pause receive) 97185377Ssam */ 98185377Ssamvoid 99185377Ssamar5212StopPcuReceive(struct ath_hal *ah) 100185377Ssam{ 101220423Sadrian OS_MARK(ah, AH_MARK_RX_CTL, AH_MARK_RX_CTL_PCU_STOP); 102185377Ssam OS_REG_WRITE(ah, AR_DIAG_SW, 103185377Ssam OS_REG_READ(ah, AR_DIAG_SW) | AR_DIAG_RX_DIS); 104185377Ssam ar5212DisableMibCounters(ah); 105185377Ssam} 106185377Ssam 107185377Ssam/* 108185377Ssam * Set multicast filter 0 (lower 32-bits) 109185377Ssam * filter 1 (upper 32-bits) 110185377Ssam */ 111185377Ssamvoid 112185377Ssamar5212SetMulticastFilter(struct ath_hal *ah, uint32_t filter0, uint32_t filter1) 113185377Ssam{ 114185377Ssam OS_REG_WRITE(ah, AR_MCAST_FIL0, filter0); 115185377Ssam OS_REG_WRITE(ah, AR_MCAST_FIL1, filter1); 116185377Ssam} 117185377Ssam 118185377Ssam/* 119185377Ssam * Clear multicast filter by index 120185377Ssam */ 121185377SsamHAL_BOOL 122185377Ssamar5212ClrMulticastFilterIndex(struct ath_hal *ah, uint32_t ix) 123185377Ssam{ 124185377Ssam uint32_t val; 125185377Ssam 126185377Ssam if (ix >= 64) 127185377Ssam return AH_FALSE; 128185377Ssam if (ix >= 32) { 129185377Ssam val = OS_REG_READ(ah, AR_MCAST_FIL1); 130185377Ssam OS_REG_WRITE(ah, AR_MCAST_FIL1, (val &~ (1<<(ix-32)))); 131185377Ssam } else { 132185377Ssam val = OS_REG_READ(ah, AR_MCAST_FIL0); 133185377Ssam OS_REG_WRITE(ah, AR_MCAST_FIL0, (val &~ (1<<ix))); 134185377Ssam } 135185377Ssam return AH_TRUE; 136185377Ssam} 137185377Ssam 138185377Ssam/* 139185377Ssam * Set multicast filter by index 140185377Ssam */ 141185377SsamHAL_BOOL 142185377Ssamar5212SetMulticastFilterIndex(struct ath_hal *ah, uint32_t ix) 143185377Ssam{ 144185377Ssam uint32_t val; 145185377Ssam 146185377Ssam if (ix >= 64) 147185377Ssam return AH_FALSE; 148185377Ssam if (ix >= 32) { 149185377Ssam val = OS_REG_READ(ah, AR_MCAST_FIL1); 150185377Ssam OS_REG_WRITE(ah, AR_MCAST_FIL1, (val | (1<<(ix-32)))); 151185377Ssam } else { 152185377Ssam val = OS_REG_READ(ah, AR_MCAST_FIL0); 153185377Ssam OS_REG_WRITE(ah, AR_MCAST_FIL0, (val | (1<<ix))); 154185377Ssam } 155185377Ssam return AH_TRUE; 156185377Ssam} 157185377Ssam 158185377Ssam/* 159185377Ssam * Get the receive filter. 160185377Ssam */ 161185377Ssamuint32_t 162185377Ssamar5212GetRxFilter(struct ath_hal *ah) 163185377Ssam{ 164185377Ssam uint32_t bits = OS_REG_READ(ah, AR_RX_FILTER); 165185377Ssam uint32_t phybits = OS_REG_READ(ah, AR_PHY_ERR); 166185377Ssam if (phybits & AR_PHY_ERR_RADAR) 167185377Ssam bits |= HAL_RX_FILTER_PHYRADAR; 168185377Ssam if (phybits & (AR_PHY_ERR_OFDM_TIMING|AR_PHY_ERR_CCK_TIMING)) 169185377Ssam bits |= HAL_RX_FILTER_PHYERR; 170195114Ssam if (AH_PRIVATE(ah)->ah_caps.halBssidMatchSupport && 171195809Ssam (AH5212(ah)->ah_miscMode & AR_MISC_MODE_BSSID_MATCH_FORCE)) 172195114Ssam bits |= HAL_RX_FILTER_BSSID; 173185377Ssam return bits; 174185377Ssam} 175185377Ssam 176185377Ssam/* 177185377Ssam * Set the receive filter. 178185377Ssam */ 179185377Ssamvoid 180185377Ssamar5212SetRxFilter(struct ath_hal *ah, uint32_t bits) 181185377Ssam{ 182195809Ssam struct ath_hal_5212 *ahp = AH5212(ah); 183185377Ssam uint32_t phybits; 184185377Ssam 185185377Ssam OS_REG_WRITE(ah, AR_RX_FILTER, 186195114Ssam bits &~ (HAL_RX_FILTER_PHYRADAR|HAL_RX_FILTER_PHYERR| 187195114Ssam HAL_RX_FILTER_BSSID)); 188185377Ssam phybits = 0; 189185377Ssam if (bits & HAL_RX_FILTER_PHYRADAR) 190185377Ssam phybits |= AR_PHY_ERR_RADAR; 191185377Ssam if (bits & HAL_RX_FILTER_PHYERR) 192185377Ssam phybits |= AR_PHY_ERR_OFDM_TIMING | AR_PHY_ERR_CCK_TIMING; 193185377Ssam OS_REG_WRITE(ah, AR_PHY_ERR, phybits); 194185377Ssam if (phybits) { 195185377Ssam OS_REG_WRITE(ah, AR_RXCFG, 196185377Ssam OS_REG_READ(ah, AR_RXCFG) | AR_RXCFG_ZLFDMA); 197185377Ssam } else { 198185377Ssam OS_REG_WRITE(ah, AR_RXCFG, 199185377Ssam OS_REG_READ(ah, AR_RXCFG) &~ AR_RXCFG_ZLFDMA); 200185377Ssam } 201195114Ssam if (AH_PRIVATE(ah)->ah_caps.halBssidMatchSupport) { 202195114Ssam if (bits & HAL_RX_FILTER_BSSID) 203195809Ssam ahp->ah_miscMode |= AR_MISC_MODE_BSSID_MATCH_FORCE; 204195114Ssam else 205195809Ssam ahp->ah_miscMode &= ~AR_MISC_MODE_BSSID_MATCH_FORCE; 206219771Sadrian OS_REG_WRITE(ah, AR_MISC_MODE, OS_REG_READ(ah, AR_MISC_MODE) | ahp->ah_miscMode); 207195114Ssam } 208185377Ssam} 209185377Ssam 210185377Ssam/* 211185377Ssam * Initialize RX descriptor, by clearing the status and setting 212185377Ssam * the size (and any other flags). 213185377Ssam */ 214185377SsamHAL_BOOL 215185377Ssamar5212SetupRxDesc(struct ath_hal *ah, struct ath_desc *ds, 216185377Ssam uint32_t size, u_int flags) 217185377Ssam{ 218185377Ssam struct ar5212_desc *ads = AR5212DESC(ds); 219185377Ssam 220185377Ssam HALASSERT((size &~ AR_BufLen) == 0); 221185377Ssam 222185377Ssam ads->ds_ctl0 = 0; 223185377Ssam ads->ds_ctl1 = size & AR_BufLen; 224185377Ssam 225185377Ssam if (flags & HAL_RXDESC_INTREQ) 226185377Ssam ads->ds_ctl1 |= AR_RxInterReq; 227185377Ssam ads->ds_rxstatus0 = ads->ds_rxstatus1 = 0; 228185377Ssam 229185377Ssam return AH_TRUE; 230185377Ssam} 231185377Ssam 232185377Ssam/* 233185377Ssam * Process an RX descriptor, and return the status to the caller. 234185377Ssam * Copy some hardware specific items into the software portion 235185377Ssam * of the descriptor. 236185377Ssam * 237185377Ssam * NB: the caller is responsible for validating the memory contents 238185377Ssam * of the descriptor (e.g. flushing any cached copy). 239185377Ssam */ 240185377SsamHAL_STATUS 241185377Ssamar5212ProcRxDesc(struct ath_hal *ah, struct ath_desc *ds, 242185377Ssam uint32_t pa, struct ath_desc *nds, uint64_t tsf, 243185377Ssam struct ath_rx_status *rs) 244185377Ssam{ 245185377Ssam struct ar5212_desc *ads = AR5212DESC(ds); 246185377Ssam struct ar5212_desc *ands = AR5212DESC(nds); 247185377Ssam 248185377Ssam if ((ads->ds_rxstatus1 & AR_Done) == 0) 249185377Ssam return HAL_EINPROGRESS; 250185377Ssam /* 251185377Ssam * Given the use of a self-linked tail be very sure that the hw is 252185377Ssam * done with this descriptor; the hw may have done this descriptor 253185377Ssam * once and picked it up again...make sure the hw has moved on. 254185377Ssam */ 255185377Ssam if ((ands->ds_rxstatus1&AR_Done) == 0 && OS_REG_READ(ah, AR_RXDP) == pa) 256185377Ssam return HAL_EINPROGRESS; 257185377Ssam 258185377Ssam rs->rs_datalen = ads->ds_rxstatus0 & AR_DataLen; 259185377Ssam rs->rs_tstamp = MS(ads->ds_rxstatus1, AR_RcvTimestamp); 260185377Ssam rs->rs_status = 0; 261185377Ssam /* XXX what about KeyCacheMiss? */ 262185377Ssam rs->rs_rssi = MS(ads->ds_rxstatus0, AR_RcvSigStrength); 263185377Ssam /* discard invalid h/w rssi data */ 264185377Ssam if (rs->rs_rssi == -128) 265185377Ssam rs->rs_rssi = 0; 266185377Ssam if (ads->ds_rxstatus1 & AR_KeyIdxValid) 267185377Ssam rs->rs_keyix = MS(ads->ds_rxstatus1, AR_KeyIdx); 268185377Ssam else 269185377Ssam rs->rs_keyix = HAL_RXKEYIX_INVALID; 270185377Ssam /* NB: caller expected to do rate table mapping */ 271185377Ssam rs->rs_rate = MS(ads->ds_rxstatus0, AR_RcvRate); 272185377Ssam rs->rs_antenna = MS(ads->ds_rxstatus0, AR_RcvAntenna); 273185377Ssam rs->rs_more = (ads->ds_rxstatus0 & AR_More) ? 1 : 0; 274185377Ssam 275185377Ssam if ((ads->ds_rxstatus1 & AR_FrmRcvOK) == 0) { 276185377Ssam /* 277185377Ssam * These four bits should not be set together. The 278185377Ssam * 5212 spec states a Michael error can only occur if 279185377Ssam * DecryptCRCErr not set (and TKIP is used). Experience 280185377Ssam * indicates however that you can also get Michael errors 281185377Ssam * when a CRC error is detected, but these are specious. 282185377Ssam * Consequently we filter them out here so we don't 283185377Ssam * confuse and/or complicate drivers. 284185377Ssam */ 285185377Ssam if (ads->ds_rxstatus1 & AR_CRCErr) 286185377Ssam rs->rs_status |= HAL_RXERR_CRC; 287185377Ssam else if (ads->ds_rxstatus1 & AR_PHYErr) { 288185377Ssam u_int phyerr; 289185377Ssam 290185377Ssam rs->rs_status |= HAL_RXERR_PHY; 291185377Ssam phyerr = MS(ads->ds_rxstatus1, AR_PHYErrCode); 292185377Ssam rs->rs_phyerr = phyerr; 293185377Ssam if (!AH5212(ah)->ah_hasHwPhyCounters && 294185377Ssam phyerr != HAL_PHYERR_RADAR) 295185377Ssam ar5212AniPhyErrReport(ah, rs); 296185377Ssam } else if (ads->ds_rxstatus1 & AR_DecryptCRCErr) 297185377Ssam rs->rs_status |= HAL_RXERR_DECRYPT; 298185377Ssam else if (ads->ds_rxstatus1 & AR_MichaelErr) 299185377Ssam rs->rs_status |= HAL_RXERR_MIC; 300185377Ssam } 301185377Ssam return HAL_OK; 302185377Ssam} 303