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) 34 { 35 return OS_REG_READ(ah, AR_RXDP); 36 } 37 38 /* 39 * Set the RxDP. 40 */ 41 void 42 ar5210SetRxDP(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 */ 51 void 52 ar5210EnableReceive(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 */ 60 HAL_BOOL 61 ar5210StopDmaReceive(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 */ 82 void 83 ar5210StartPcuReceive(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 */ 92 void 93 ar5210StopPcuReceive(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 */ 103 void 104 ar5210SetMulticastFilter(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 */ 113 HAL_BOOL 114 ar5210ClrMulticastFilterIndex(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 */ 133 HAL_BOOL 134 ar5210SetMulticastFilterIndex(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 */ 153 uint32_t 154 ar5210GetRxFilter(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 */ 163 void 164 ar5210SetRxFilter(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 */ 178 HAL_BOOL 179 ar5210SetupRxDesc(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 */ 208 HAL_STATUS 209 ar5210ProcRxDesc(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