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 * $FreeBSD: releng/10.3/sys/dev/ath/ath_hal/ar5210/ar5210_recv.c 243317 2012-11-19 23:42:46Z adrian $ 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, HAL_RX_QUEUE qtype) 34{ 35 36 HALASSERT(qtype == HAL_RX_QUEUE_HP); 37 return OS_REG_READ(ah, AR_RXDP); 38} 39 40/* 41 * Set the RxDP. 42 */ 43void 44ar5210SetRxDP(struct ath_hal *ah, uint32_t rxdp, HAL_RX_QUEUE qtype) 45{ 46 47 HALASSERT(qtype == HAL_RX_QUEUE_HP); 48 OS_REG_WRITE(ah, AR_RXDP, rxdp); 49} 50 51 52/* 53 * Set Receive Enable bits. 54 */ 55void 56ar5210EnableReceive(struct ath_hal *ah) 57{ 58 OS_REG_WRITE(ah, AR_CR, AR_CR_RXE); 59} 60 61/* 62 * Stop Receive at the DMA engine 63 */ 64HAL_BOOL 65ar5210StopDmaReceive(struct ath_hal *ah) 66{ 67 int i; 68 69 OS_REG_WRITE(ah, AR_CR, AR_CR_RXD); /* Set receive disable bit */ 70 for (i = 0; i < 1000; i++) { 71 if ((OS_REG_READ(ah, AR_CR) & AR_CR_RXE) == 0) 72 return AH_TRUE; 73 OS_DELAY(10); 74 } 75#ifdef AH_DEBUG 76 ath_hal_printf(ah, "ar5210: dma receive failed to stop in 10ms\n"); 77 ath_hal_printf(ah, "AR_CR=0x%x\n", OS_REG_READ(ah, AR_CR)); 78 ath_hal_printf(ah, "AR_DIAG_SW=0x%x\n", OS_REG_READ(ah, AR_DIAG_SW)); 79#endif 80 return AH_FALSE; 81} 82 83/* 84 * Start Transmit at the PCU engine (unpause receive) 85 */ 86void 87ar5210StartPcuReceive(struct ath_hal *ah) 88{ 89 ar5210UpdateDiagReg(ah, 90 OS_REG_READ(ah, AR_DIAG_SW) & ~(AR_DIAG_SW_DIS_RX)); 91} 92 93/* 94 * Stop Transmit at the PCU engine (pause receive) 95 */ 96void 97ar5210StopPcuReceive(struct ath_hal *ah) 98{ 99 ar5210UpdateDiagReg(ah, 100 OS_REG_READ(ah, AR_DIAG_SW) | AR_DIAG_SW_DIS_RX); 101} 102 103/* 104 * Set multicast filter 0 (lower 32-bits) 105 * filter 1 (upper 32-bits) 106 */ 107void 108ar5210SetMulticastFilter(struct ath_hal *ah, uint32_t filter0, uint32_t filter1) 109{ 110 OS_REG_WRITE(ah, AR_MCAST_FIL0, filter0); 111 OS_REG_WRITE(ah, AR_MCAST_FIL1, filter1); 112} 113 114/* 115 * Clear multicast filter by index 116 */ 117HAL_BOOL 118ar5210ClrMulticastFilterIndex(struct ath_hal *ah, uint32_t ix) 119{ 120 uint32_t val; 121 122 if (ix >= 64) 123 return AH_FALSE; 124 if (ix >= 32) { 125 val = OS_REG_READ(ah, AR_MCAST_FIL1); 126 OS_REG_WRITE(ah, AR_MCAST_FIL1, (val &~ (1<<(ix-32)))); 127 } else { 128 val = OS_REG_READ(ah, AR_MCAST_FIL0); 129 OS_REG_WRITE(ah, AR_MCAST_FIL0, (val &~ (1<<ix))); 130 } 131 return AH_TRUE; 132} 133 134/* 135 * Set multicast filter by index 136 */ 137HAL_BOOL 138ar5210SetMulticastFilterIndex(struct ath_hal *ah, uint32_t ix) 139{ 140 uint32_t val; 141 142 if (ix >= 64) 143 return AH_FALSE; 144 if (ix >= 32) { 145 val = OS_REG_READ(ah, AR_MCAST_FIL1); 146 OS_REG_WRITE(ah, AR_MCAST_FIL1, (val | (1<<(ix-32)))); 147 } else { 148 val = OS_REG_READ(ah, AR_MCAST_FIL0); 149 OS_REG_WRITE(ah, AR_MCAST_FIL0, (val | (1<<ix))); 150 } 151 return AH_TRUE; 152} 153 154/* 155 * Return the receive packet filter. 156 */ 157uint32_t 158ar5210GetRxFilter(struct ath_hal *ah) 159{ 160 /* XXX can't be sure if promiscuous mode is set because of PHYRADAR */ 161 return OS_REG_READ(ah, AR_RX_FILTER); 162} 163 164/* 165 * Turn off/on bits in the receive packet filter. 166 */ 167void 168ar5210SetRxFilter(struct ath_hal *ah, uint32_t bits) 169{ 170 if (bits & HAL_RX_FILTER_PHYRADAR) { 171 /* must enable promiscuous mode to get radar */ 172 bits = (bits &~ HAL_RX_FILTER_PHYRADAR) | AR_RX_FILTER_PROMISCUOUS; 173 } 174 OS_REG_WRITE(ah, AR_RX_FILTER, bits); 175} 176 177/* 178 * Initialize RX descriptor, by clearing the status and clearing 179 * the size. This is not strictly HW dependent, but we want the 180 * control and status words to be opaque above the hal. 181 */ 182HAL_BOOL 183ar5210SetupRxDesc(struct ath_hal *ah, struct ath_desc *ds, 184 uint32_t size, u_int flags) 185{ 186 struct ar5210_desc *ads = AR5210DESC(ds); 187 188 (void) flags; 189 190 ads->ds_ctl0 = 0; 191 ads->ds_ctl1 = size & AR_BufLen; 192 if (ads->ds_ctl1 != size) { 193 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: buffer size %u too large\n", 194 __func__, size); 195 return AH_FALSE; 196 } 197 if (flags & HAL_RXDESC_INTREQ) 198 ads->ds_ctl1 |= AR_RxInterReq; 199 ads->ds_status0 = ads->ds_status1 = 0; 200 201 return AH_TRUE; 202} 203 204/* 205 * Process an RX descriptor, and return the status to the caller. 206 * Copy some hardware specific items into the software portion 207 * of the descriptor. 208 * 209 * NB: the caller is responsible for validating the memory contents 210 * of the descriptor (e.g. flushing any cached copy). 211 */ 212HAL_STATUS 213ar5210ProcRxDesc(struct ath_hal *ah, struct ath_desc *ds, 214 uint32_t pa, struct ath_desc *nds, uint64_t tsf, 215 struct ath_rx_status *rs) 216{ 217 struct ar5210_desc *ads = AR5210DESC(ds); 218 struct ar5210_desc *ands = AR5210DESC(nds); 219 uint32_t now, rstamp; 220 221 if ((ads->ds_status1 & AR_Done) == 0) 222 return HAL_EINPROGRESS; 223 /* 224 * Given the use of a self-linked tail be very sure that the hw is 225 * done with this descriptor; the hw may have done this descriptor 226 * once and picked it up again...make sure the hw has moved on. 227 */ 228 if ((ands->ds_status1 & AR_Done) == 0 && OS_REG_READ(ah, AR_RXDP) == pa) 229 return HAL_EINPROGRESS; 230 231 rs->rs_datalen = ads->ds_status0 & AR_DataLen; 232 rstamp = MS(ads->ds_status1, AR_RcvTimestamp); 233 /* 234 * Convert timestamp. The value in the 235 * descriptor is bits [10..22] of the TSF. 236 */ 237 now = (OS_REG_READ(ah, AR_TSF_L32) >> 10) & 0xffff; 238 if ((now & 0x1fff) < rstamp) 239 rstamp |= (now - 0x2000) & 0xffff; 240 else 241 rstamp |= now; 242 /* NB: keep only 15 bits for consistency w/ other chips */ 243 rs->rs_tstamp = rstamp & 0x7fff; 244 rs->rs_status = 0; 245 if ((ads->ds_status1 & AR_FrmRcvOK) == 0) { 246 if (ads->ds_status1 & AR_CRCErr) 247 rs->rs_status |= HAL_RXERR_CRC; 248 else if (ads->ds_status1 & AR_DecryptCRCErr) 249 rs->rs_status |= HAL_RXERR_DECRYPT; 250 else if (ads->ds_status1 & AR_FIFOOverrun) 251 rs->rs_status |= HAL_RXERR_FIFO; 252 else { 253 rs->rs_status |= HAL_RXERR_PHY; 254 rs->rs_phyerr = 255 (ads->ds_status1 & AR_PHYErr) >> AR_PHYErr_S; 256 } 257 } 258 /* XXX what about KeyCacheMiss? */ 259 rs->rs_rssi = MS(ads->ds_status0, AR_RcvSigStrength); 260 if (ads->ds_status1 & AR_KeyIdxValid) 261 rs->rs_keyix = MS(ads->ds_status1, AR_KeyIdx); 262 else 263 rs->rs_keyix = HAL_RXKEYIX_INVALID; 264 /* NB: caller expected to do rate table mapping */ 265 rs->rs_rate = MS(ads->ds_status0, AR_RcvRate); 266 rs->rs_antenna = (ads->ds_status0 & AR_RcvAntenna) ? 1 : 0; 267 rs->rs_more = (ads->ds_status0 & AR_More) ? 1 : 0; 268 269 return HAL_OK; 270} 271