ar5211_recv.c revision 185377
1214152Sed/* 2214152Sed * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting 3214152Sed * Copyright (c) 2002-2006 Atheros Communications, Inc. 4214152Sed * 5222656Sed * Permission to use, copy, modify, and/or distribute this software for any 6222656Sed * purpose with or without fee is hereby granted, provided that the above 7214152Sed * copyright notice and this permission notice appear in all copies. 8214152Sed * 9214152Sed * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10214152Sed * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11214152Sed * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12214152Sed * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13214152Sed * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14214152Sed * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15214152Sed * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16214152Sed * 17222656Sed * $Id: ar5211_recv.c,v 1.4 2008/11/10 04:08:02 sam Exp $ 18214152Sed */ 19214152Sed#include "opt_ah.h" 20214152Sed 21222656Sed#ifdef AH_SUPPORT_AR5211 22214152Sed 23214152Sed#include "ah.h" 24214152Sed#include "ah_internal.h" 25214152Sed#include "ah_desc.h" 26214152Sed 27214152Sed#include "ar5211/ar5211.h" 28214152Sed#include "ar5211/ar5211reg.h" 29214152Sed#include "ar5211/ar5211desc.h" 30214152Sed 31214152Sed/* 32214152Sed * Get the RXDP. 33 */ 34uint32_t 35ar5211GetRxDP(struct ath_hal *ah) 36{ 37 return OS_REG_READ(ah, AR_RXDP); 38} 39 40/* 41 * Set the RxDP. 42 */ 43void 44ar5211SetRxDP(struct ath_hal *ah, uint32_t rxdp) 45{ 46 OS_REG_WRITE(ah, AR_RXDP, rxdp); 47 HALASSERT(OS_REG_READ(ah, AR_RXDP) == rxdp); 48} 49 50 51/* 52 * Set Receive Enable bits. 53 */ 54void 55ar5211EnableReceive(struct ath_hal *ah) 56{ 57 OS_REG_WRITE(ah, AR_CR, AR_CR_RXE); 58} 59 60/* 61 * Stop Receive at the DMA engine 62 */ 63HAL_BOOL 64ar5211StopDmaReceive(struct ath_hal *ah) 65{ 66 OS_REG_WRITE(ah, AR_CR, AR_CR_RXD); /* Set receive disable bit */ 67 if (!ath_hal_wait(ah, AR_CR, AR_CR_RXE, 0)) { 68#ifdef AH_DEBUG 69 ath_hal_printf(ah, "%s failed to stop in 10ms\n" 70 "AR_CR=0x%08X\nAR_DIAG_SW=0x%08X\n" 71 , __func__ 72 , OS_REG_READ(ah, AR_CR) 73 , OS_REG_READ(ah, AR_DIAG_SW) 74 ); 75#endif 76 return AH_FALSE; 77 } else { 78 return AH_TRUE; 79 } 80} 81 82/* 83 * Start Transmit at the PCU engine (unpause receive) 84 */ 85void 86ar5211StartPcuReceive(struct ath_hal *ah) 87{ 88 OS_REG_WRITE(ah, AR_DIAG_SW, 89 OS_REG_READ(ah, AR_DIAG_SW) & ~(AR_DIAG_SW_DIS_RX)); 90} 91 92/* 93 * Stop Transmit at the PCU engine (pause receive) 94 */ 95void 96ar5211StopPcuReceive(struct ath_hal *ah) 97{ 98 OS_REG_WRITE(ah, AR_DIAG_SW, 99 OS_REG_READ(ah, AR_DIAG_SW) | AR_DIAG_SW_DIS_RX); 100} 101 102/* 103 * Set multicast filter 0 (lower 32-bits) 104 * filter 1 (upper 32-bits) 105 */ 106void 107ar5211SetMulticastFilter(struct ath_hal *ah, uint32_t filter0, uint32_t filter1) 108{ 109 OS_REG_WRITE(ah, AR_MCAST_FIL0, filter0); 110 OS_REG_WRITE(ah, AR_MCAST_FIL1, filter1); 111} 112 113/* 114 * Clear multicast filter by index 115 */ 116HAL_BOOL 117ar5211ClrMulticastFilterIndex(struct ath_hal *ah, uint32_t ix) 118{ 119 uint32_t val; 120 121 if (ix >= 64) 122 return AH_FALSE; 123 if (ix >= 32) { 124 val = OS_REG_READ(ah, AR_MCAST_FIL1); 125 OS_REG_WRITE(ah, AR_MCAST_FIL1, (val &~ (1<<(ix-32)))); 126 } else { 127 val = OS_REG_READ(ah, AR_MCAST_FIL0); 128 OS_REG_WRITE(ah, AR_MCAST_FIL0, (val &~ (1<<ix))); 129 } 130 return AH_TRUE; 131} 132 133/* 134 * Set multicast filter by index 135 */ 136HAL_BOOL 137ar5211SetMulticastFilterIndex(struct ath_hal *ah, uint32_t ix) 138{ 139 uint32_t val; 140 141 if (ix >= 64) 142 return AH_FALSE; 143 if (ix >= 32) { 144 val = OS_REG_READ(ah, AR_MCAST_FIL1); 145 OS_REG_WRITE(ah, AR_MCAST_FIL1, (val | (1<<(ix-32)))); 146 } else { 147 val = OS_REG_READ(ah, AR_MCAST_FIL0); 148 OS_REG_WRITE(ah, AR_MCAST_FIL0, (val | (1<<ix))); 149 } 150 return AH_TRUE; 151} 152 153/* 154 * Get receive filter. 155 */ 156uint32_t 157ar5211GetRxFilter(struct ath_hal *ah) 158{ 159 return OS_REG_READ(ah, AR_RX_FILTER); 160} 161 162/* 163 * Set receive filter. 164 */ 165void 166ar5211SetRxFilter(struct ath_hal *ah, uint32_t bits) 167{ 168 OS_REG_WRITE(ah, AR_RX_FILTER, bits); 169} 170 171/* 172 * Initialize RX descriptor, by clearing the status and clearing 173 * the size. This is not strictly HW dependent, but we want the 174 * control and status words to be opaque above the hal. 175 */ 176HAL_BOOL 177ar5211SetupRxDesc(struct ath_hal *ah, struct ath_desc *ds, 178 uint32_t size, u_int flags) 179{ 180 struct ar5211_desc *ads = AR5211DESC(ds); 181 182 ads->ds_ctl0 = 0; 183 ads->ds_ctl1 = size & AR_BufLen; 184 if (ads->ds_ctl1 != size) { 185 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: buffer size %u too large\n", 186 __func__, size); 187 return AH_FALSE; 188 } 189 if (flags & HAL_RXDESC_INTREQ) 190 ads->ds_ctl1 |= AR_RxInterReq; 191 ads->ds_status0 = ads->ds_status1 = 0; 192 193 return AH_TRUE; 194} 195 196/* 197 * Process an RX descriptor, and return the status to the caller. 198 * Copy some hardware specific items into the software portion 199 * of the descriptor. 200 * 201 * NB: the caller is responsible for validating the memory contents 202 * of the descriptor (e.g. flushing any cached copy). 203 */ 204HAL_STATUS 205ar5211ProcRxDesc(struct ath_hal *ah, struct ath_desc *ds, 206 uint32_t pa, struct ath_desc *nds, uint64_t tsf, 207 struct ath_rx_status *rs) 208{ 209 struct ar5211_desc *ads = AR5211DESC(ds); 210 struct ar5211_desc *ands = AR5211DESC(nds); 211 212 if ((ads->ds_status1 & AR_Done) == 0) 213 return HAL_EINPROGRESS; 214 /* 215 * Given the use of a self-linked tail be very sure that the hw is 216 * done with this descriptor; the hw may have done this descriptor 217 * once and picked it up again...make sure the hw has moved on. 218 */ 219 if ((ands->ds_status1 & AR_Done) == 0 && OS_REG_READ(ah, AR_RXDP) == pa) 220 return HAL_EINPROGRESS; 221 222 rs->rs_datalen = ads->ds_status0 & AR_DataLen; 223 rs->rs_tstamp = MS(ads->ds_status1, AR_RcvTimestamp); 224 rs->rs_status = 0; 225 if ((ads->ds_status1 & AR_FrmRcvOK) == 0) { 226 if (ads->ds_status1 & AR_CRCErr) 227 rs->rs_status |= HAL_RXERR_CRC; 228 else if (ads->ds_status1 & AR_DecryptCRCErr) 229 rs->rs_status |= HAL_RXERR_DECRYPT; 230 else { 231 rs->rs_status |= HAL_RXERR_PHY; 232 rs->rs_phyerr = MS(ads->ds_status1, AR_PHYErr); 233 } 234 } 235 /* XXX what about KeyCacheMiss? */ 236 rs->rs_rssi = MS(ads->ds_status0, AR_RcvSigStrength); 237 if (ads->ds_status1 & AR_KeyIdxValid) 238 rs->rs_keyix = MS(ads->ds_status1, AR_KeyIdx); 239 else 240 rs->rs_keyix = HAL_RXKEYIX_INVALID; 241 /* NB: caller expected to do rate table mapping */ 242 rs->rs_rate = MS(ads->ds_status0, AR_RcvRate); 243 rs->rs_antenna = MS(ads->ds_status0, AR_RcvAntenna); 244 rs->rs_more = (ads->ds_status0 & AR_More) ? 1 : 0; 245 246 return HAL_OK; 247} 248#endif /* AH_SUPPORT_AR5211 */ 249