1/* 2 * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting 3 * Copyright (c) 2002-2004 Atheros Communications, Inc. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 * 17 * $Id: ar5210_recv.c,v 1.1.1.1 2008/12/11 04:46:28 alc Exp $ 18 */ 19#include "opt_ah.h" 20 21#include "ah.h" 22#include "ah_internal.h" 23#include "ah_desc.h" 24 25#include "ar5210/ar5210.h" 26#include "ar5210/ar5210reg.h" 27#include "ar5210/ar5210desc.h" 28 29/* 30 * Get the RXDP. 31 */ 32uint32_t 33ar5210GetRxDP(struct ath_hal *ah) 34{ 35 return OS_REG_READ(ah, AR_RXDP); 36} 37 38/* 39 * Set the RxDP. 40 */ 41void 42ar5210SetRxDP(struct ath_hal *ah, uint32_t rxdp) 43{ 44 OS_REG_WRITE(ah, AR_RXDP, rxdp); 45} 46 47 48/* 49 * Set Receive Enable bits. 50 */ 51void 52ar5210EnableReceive(struct ath_hal *ah) 53{ 54 OS_REG_WRITE(ah, AR_CR, AR_CR_RXE); 55} 56 57/* 58 * Stop Receive at the DMA engine 59 */ 60HAL_BOOL 61ar5210StopDmaReceive(struct ath_hal *ah) 62{ 63 int i; 64 65 OS_REG_WRITE(ah, AR_CR, AR_CR_RXD); /* Set receive disable bit */ 66 for (i = 0; i < 1000; i++) { 67 if ((OS_REG_READ(ah, AR_CR) & AR_CR_RXE) == 0) 68 return AH_TRUE; 69 OS_DELAY(10); 70 } 71#ifdef AH_DEBUG 72 ath_hal_printf(ah, "ar5210: dma receive failed to stop in 10ms\n"); 73 ath_hal_printf(ah, "AR_CR=0x%x\n", OS_REG_READ(ah, AR_CR)); 74 ath_hal_printf(ah, "AR_DIAG_SW=0x%x\n", OS_REG_READ(ah, AR_DIAG_SW)); 75#endif 76 return AH_FALSE; 77} 78 79/* 80 * Start Transmit at the PCU engine (unpause receive) 81 */ 82void 83ar5210StartPcuReceive(struct ath_hal *ah) 84{ 85 OS_REG_WRITE(ah, AR_DIAG_SW, 86 OS_REG_READ(ah, AR_DIAG_SW) & ~(AR_DIAG_SW_DIS_RX)); 87} 88 89/* 90 * Stop Transmit at the PCU engine (pause receive) 91 */ 92void 93ar5210StopPcuReceive(struct ath_hal *ah) 94{ 95 OS_REG_WRITE(ah, AR_DIAG_SW, 96 OS_REG_READ(ah, AR_DIAG_SW) | AR_DIAG_SW_DIS_RX); 97} 98 99/* 100 * Set multicast filter 0 (lower 32-bits) 101 * filter 1 (upper 32-bits) 102 */ 103void 104ar5210SetMulticastFilter(struct ath_hal *ah, uint32_t filter0, uint32_t filter1) 105{ 106 OS_REG_WRITE(ah, AR_MCAST_FIL0, filter0); 107 OS_REG_WRITE(ah, AR_MCAST_FIL1, filter1); 108} 109 110/* 111 * Clear multicast filter by index 112 */ 113HAL_BOOL 114ar5210ClrMulticastFilterIndex(struct ath_hal *ah, uint32_t ix) 115{ 116 uint32_t val; 117 118 if (ix >= 64) 119 return AH_FALSE; 120 if (ix >= 32) { 121 val = OS_REG_READ(ah, AR_MCAST_FIL1); 122 OS_REG_WRITE(ah, AR_MCAST_FIL1, (val &~ (1<<(ix-32)))); 123 } else { 124 val = OS_REG_READ(ah, AR_MCAST_FIL0); 125 OS_REG_WRITE(ah, AR_MCAST_FIL0, (val &~ (1<<ix))); 126 } 127 return AH_TRUE; 128} 129 130/* 131 * Set multicast filter by index 132 */ 133HAL_BOOL 134ar5210SetMulticastFilterIndex(struct ath_hal *ah, uint32_t ix) 135{ 136 uint32_t val; 137 138 if (ix >= 64) 139 return AH_FALSE; 140 if (ix >= 32) { 141 val = OS_REG_READ(ah, AR_MCAST_FIL1); 142 OS_REG_WRITE(ah, AR_MCAST_FIL1, (val | (1<<(ix-32)))); 143 } else { 144 val = OS_REG_READ(ah, AR_MCAST_FIL0); 145 OS_REG_WRITE(ah, AR_MCAST_FIL0, (val | (1<<ix))); 146 } 147 return AH_TRUE; 148} 149 150/* 151 * Return the receive packet filter. 152 */ 153uint32_t 154ar5210GetRxFilter(struct ath_hal *ah) 155{ 156 /* XXX can't be sure if promiscuous mode is set because of PHYRADAR */ 157 return OS_REG_READ(ah, AR_RX_FILTER); 158} 159 160/* 161 * Turn off/on bits in the receive packet filter. 162 */ 163void 164ar5210SetRxFilter(struct ath_hal *ah, uint32_t bits) 165{ 166 if (bits & HAL_RX_FILTER_PHYRADAR) { 167 /* must enable promiscuous mode to get radar */ 168 bits = (bits &~ HAL_RX_FILTER_PHYRADAR) | AR_RX_FILTER_PROMISCUOUS; 169 } 170 OS_REG_WRITE(ah, AR_RX_FILTER, bits); 171} 172 173/* 174 * Initialize RX descriptor, by clearing the status and clearing 175 * the size. This is not strictly HW dependent, but we want the 176 * control and status words to be opaque above the hal. 177 */ 178HAL_BOOL 179ar5210SetupRxDesc(struct ath_hal *ah, struct ath_desc *ds, 180 uint32_t size, u_int flags) 181{ 182 struct ar5210_desc *ads = AR5210DESC(ds); 183 184 (void) flags; 185 186 ads->ds_ctl0 = 0; 187 ads->ds_ctl1 = size & AR_BufLen; 188 if (ads->ds_ctl1 != size) { 189 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: buffer size %u too large\n", 190 __func__, size); 191 return AH_FALSE; 192 } 193 if (flags & HAL_RXDESC_INTREQ) 194 ads->ds_ctl1 |= AR_RxInterReq; 195 ads->ds_status0 = ads->ds_status1 = 0; 196 197 return AH_TRUE; 198} 199 200/* 201 * Process an RX descriptor, and return the status to the caller. 202 * Copy some hardware specific items into the software portion 203 * of the descriptor. 204 * 205 * NB: the caller is responsible for validating the memory contents 206 * of the descriptor (e.g. flushing any cached copy). 207 */ 208HAL_STATUS 209ar5210ProcRxDesc(struct ath_hal *ah, struct ath_desc *ds, 210 uint32_t pa, struct ath_desc *nds, uint64_t tsf, 211 struct ath_rx_status *rs) 212{ 213 struct ar5210_desc *ads = AR5210DESC(ds); 214 struct ar5210_desc *ands = AR5210DESC(nds); 215 uint32_t now, rstamp; 216 217 if ((ads->ds_status1 & AR_Done) == 0) 218 return HAL_EINPROGRESS; 219 /* 220 * Given the use of a self-linked tail be very sure that the hw is 221 * done with this descriptor; the hw may have done this descriptor 222 * once and picked it up again...make sure the hw has moved on. 223 */ 224 if ((ands->ds_status1 & AR_Done) == 0 && OS_REG_READ(ah, AR_RXDP) == pa) 225 return HAL_EINPROGRESS; 226 227 rs->rs_datalen = ads->ds_status0 & AR_DataLen; 228 rstamp = MS(ads->ds_status1, AR_RcvTimestamp); 229 /* 230 * Convert timestamp. The value in the 231 * descriptor is bits [10..22] of the TSF. 232 */ 233 now = (OS_REG_READ(ah, AR_TSF_L32) >> 10) & 0xffff; 234 if ((now & 0x1fff) < rstamp) 235 rstamp |= (now - 0x2000) & 0xffff; 236 else 237 rstamp |= now; 238 /* NB: keep only 15 bits for consistency w/ other chips */ 239 rs->rs_tstamp = rstamp & 0x7fff; 240 rs->rs_status = 0; 241 if ((ads->ds_status1 & AR_FrmRcvOK) == 0) { 242 if (ads->ds_status1 & AR_CRCErr) 243 rs->rs_status |= HAL_RXERR_CRC; 244 else if (ads->ds_status1 & AR_DecryptCRCErr) 245 rs->rs_status |= HAL_RXERR_DECRYPT; 246 else if (ads->ds_status1 & AR_FIFOOverrun) 247 rs->rs_status |= HAL_RXERR_FIFO; 248 else { 249 rs->rs_status |= HAL_RXERR_PHY; 250 rs->rs_phyerr = 251 (ads->ds_status1 & AR_PHYErr) >> AR_PHYErr_S; 252 } 253 } 254 /* XXX what about KeyCacheMiss? */ 255 rs->rs_rssi = MS(ads->ds_status0, AR_RcvSigStrength); 256 if (ads->ds_status1 & AR_KeyIdxValid) 257 rs->rs_keyix = MS(ads->ds_status1, AR_KeyIdx); 258 else 259 rs->rs_keyix = HAL_RXKEYIX_INVALID; 260 /* NB: caller expected to do rate table mapping */ 261 rs->rs_rate = MS(ads->ds_status0, AR_RcvRate); 262 rs->rs_antenna = (ads->ds_status0 & AR_RcvAntenna) ? 1 : 0; 263 rs->rs_more = (ads->ds_status0 & AR_More) ? 1 : 0; 264 265 return HAL_OK; 266} 267