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$ 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 */ 32 uint32_t 33 ar5210GetRxDP(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 */ 43 void 44 ar5210SetRxDP(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 */ 55 void 56 ar5210EnableReceive(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 */ 64 HAL_BOOL 65 ar5210StopDmaReceive(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 */ 86 void 87 ar5210StartPcuReceive(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 */ 96 void 97 ar5210StopPcuReceive(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 */ 107 void 108 ar5210SetMulticastFilter(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 */ 117 HAL_BOOL 118 ar5210ClrMulticastFilterIndex(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 */ 137 HAL_BOOL 138 ar5210SetMulticastFilterIndex(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 */ 157 uint32_t 158 ar5210GetRxFilter(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 */ 167 void 168 ar5210SetRxFilter(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 */ 182 HAL_BOOL 183 ar5210SetupRxDesc(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 */ 212 HAL_STATUS 213 ar5210ProcRxDesc(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