| 1 | /* $NetBSD: rtw.c,v 1.124 2016/09/15 21:45:37 jdolecek Exp $ */ |
| 2 | /*- |
| 3 | * Copyright (c) 2004, 2005, 2006, 2007 David Young. All rights |
| 4 | * reserved. |
| 5 | * |
| 6 | * Programmed for NetBSD by David Young. |
| 7 | * |
| 8 | * Redistribution and use in source and binary forms, with or without |
| 9 | * modification, are permitted provided that the following conditions |
| 10 | * are met: |
| 11 | * 1. Redistributions of source code must retain the above copyright |
| 12 | * notice, this list of conditions and the following disclaimer. |
| 13 | * 2. Redistributions in binary form must reproduce the above copyright |
| 14 | * notice, this list of conditions and the following disclaimer in the |
| 15 | * documentation and/or other materials provided with the distribution. |
| 16 | * |
| 17 | * THIS SOFTWARE IS PROVIDED BY David Young ``AS IS'' AND ANY |
| 18 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
| 19 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A |
| 20 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL David |
| 21 | * Young BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| 22 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED |
| 23 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 24 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| 25 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| 27 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY |
| 28 | * OF SUCH DAMAGE. |
| 29 | */ |
| 30 | /* |
| 31 | * Device driver for the Realtek RTL8180 802.11 MAC/BBP. |
| 32 | */ |
| 33 | |
| 34 | #include <sys/cdefs.h> |
| 35 | __KERNEL_RCSID(0, "$NetBSD: rtw.c,v 1.124 2016/09/15 21:45:37 jdolecek Exp $" ); |
| 36 | |
| 37 | |
| 38 | #include <sys/param.h> |
| 39 | #include <sys/sysctl.h> |
| 40 | #include <sys/systm.h> |
| 41 | #include <sys/callout.h> |
| 42 | #include <sys/mbuf.h> |
| 43 | #include <sys/malloc.h> |
| 44 | #include <sys/kernel.h> |
| 45 | #include <sys/time.h> |
| 46 | #include <sys/types.h> |
| 47 | #include <sys/device.h> |
| 48 | #include <sys/sockio.h> |
| 49 | |
| 50 | #include <machine/endian.h> |
| 51 | #include <sys/bus.h> |
| 52 | #include <sys/intr.h> /* splnet */ |
| 53 | |
| 54 | #include <net/if.h> |
| 55 | #include <net/if_media.h> |
| 56 | #include <net/if_ether.h> |
| 57 | |
| 58 | #include <net80211/ieee80211_netbsd.h> |
| 59 | #include <net80211/ieee80211_var.h> |
| 60 | #include <net80211/ieee80211_radiotap.h> |
| 61 | |
| 62 | #include <net/bpf.h> |
| 63 | |
| 64 | #include <dev/ic/rtwreg.h> |
| 65 | #include <dev/ic/rtwvar.h> |
| 66 | #include <dev/ic/rtwphyio.h> |
| 67 | #include <dev/ic/rtwphy.h> |
| 68 | |
| 69 | #include <dev/ic/smc93cx6var.h> |
| 70 | |
| 71 | static int rtw_rfprog_fallback = 0; |
| 72 | static int rtw_host_rfio = 0; |
| 73 | |
| 74 | #ifdef RTW_DEBUG |
| 75 | int rtw_debug = 0; |
| 76 | static int rtw_rxbufs_limit = RTW_RXQLEN; |
| 77 | #endif /* RTW_DEBUG */ |
| 78 | |
| 79 | #define NEXT_ATTACH_STATE(sc, state) do { \ |
| 80 | DPRINTF(sc, RTW_DEBUG_ATTACH, \ |
| 81 | ("%s: attach state %s\n", __func__, #state)); \ |
| 82 | sc->sc_attach_state = state; \ |
| 83 | } while (0) |
| 84 | |
| 85 | int rtw_dwelltime = 200; /* milliseconds */ |
| 86 | static struct ieee80211_cipher rtw_cipher_wep; |
| 87 | |
| 88 | static void rtw_disable_interrupts(struct rtw_regs *); |
| 89 | static void rtw_enable_interrupts(struct rtw_softc *); |
| 90 | |
| 91 | static int rtw_init(struct ifnet *); |
| 92 | |
| 93 | static void rtw_start(struct ifnet *); |
| 94 | static void rtw_reset_oactive(struct rtw_softc *); |
| 95 | static struct mbuf *rtw_beacon_alloc(struct rtw_softc *, |
| 96 | struct ieee80211_node *); |
| 97 | static u_int rtw_txring_next(struct rtw_regs *, struct rtw_txdesc_blk *); |
| 98 | |
| 99 | static void rtw_io_enable(struct rtw_softc *, uint8_t, int); |
| 100 | static int rtw_key_delete(struct ieee80211com *, const struct ieee80211_key *); |
| 101 | static int rtw_key_set(struct ieee80211com *, const struct ieee80211_key *, |
| 102 | const u_int8_t[IEEE80211_ADDR_LEN]); |
| 103 | static void rtw_key_update_end(struct ieee80211com *); |
| 104 | static void rtw_key_update_begin(struct ieee80211com *); |
| 105 | static int rtw_wep_decap(struct ieee80211_key *, struct mbuf *, int); |
| 106 | static void rtw_wep_setkeys(struct rtw_softc *, struct ieee80211_key *, int); |
| 107 | |
| 108 | static void rtw_led_attach(struct rtw_led_state *, void *); |
| 109 | static void rtw_led_detach(struct rtw_led_state *); |
| 110 | static void rtw_led_init(struct rtw_regs *); |
| 111 | static void rtw_led_slowblink(void *); |
| 112 | static void rtw_led_fastblink(void *); |
| 113 | static void rtw_led_set(struct rtw_led_state *, struct rtw_regs *, int); |
| 114 | |
| 115 | static int rtw_sysctl_verify_rfio(SYSCTLFN_PROTO); |
| 116 | static int rtw_sysctl_verify_rfprog(SYSCTLFN_PROTO); |
| 117 | #ifdef RTW_DEBUG |
| 118 | static void rtw_dump_rings(struct rtw_softc *sc); |
| 119 | static void rtw_print_txdesc(struct rtw_softc *, const char *, |
| 120 | struct rtw_txsoft *, struct rtw_txdesc_blk *, int); |
| 121 | static int rtw_sysctl_verify_debug(SYSCTLFN_PROTO); |
| 122 | static int rtw_sysctl_verify_rxbufs_limit(SYSCTLFN_PROTO); |
| 123 | #endif /* RTW_DEBUG */ |
| 124 | #ifdef RTW_DIAG |
| 125 | static void rtw_txring_fixup(struct rtw_softc *sc, const char *fn, int ln); |
| 126 | #endif /* RTW_DIAG */ |
| 127 | |
| 128 | /* |
| 129 | * Setup sysctl(3) MIB, hw.rtw.* |
| 130 | * |
| 131 | * TBD condition CTLFLAG_PERMANENT on being a module or not |
| 132 | */ |
| 133 | SYSCTL_SETUP(sysctl_rtw, "sysctl rtw(4) subtree setup" ) |
| 134 | { |
| 135 | int rc; |
| 136 | const struct sysctlnode *cnode, *rnode; |
| 137 | |
| 138 | if ((rc = sysctl_createv(clog, 0, NULL, &rnode, |
| 139 | CTLFLAG_PERMANENT, CTLTYPE_NODE, "rtw" , |
| 140 | "Realtek RTL818x 802.11 controls" , |
| 141 | NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL)) != 0) |
| 142 | goto err; |
| 143 | |
| 144 | #ifdef RTW_DEBUG |
| 145 | /* control debugging printfs */ |
| 146 | if ((rc = sysctl_createv(clog, 0, &rnode, &cnode, |
| 147 | CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, |
| 148 | "debug" , SYSCTL_DESCR("Enable RTL818x debugging output" ), |
| 149 | rtw_sysctl_verify_debug, 0, &rtw_debug, 0, |
| 150 | CTL_CREATE, CTL_EOL)) != 0) |
| 151 | goto err; |
| 152 | |
| 153 | /* Limit rx buffers, for simulating resource exhaustion. */ |
| 154 | if ((rc = sysctl_createv(clog, 0, &rnode, &cnode, |
| 155 | CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, |
| 156 | "rxbufs_limit" , |
| 157 | SYSCTL_DESCR("Set rx buffers limit" ), |
| 158 | rtw_sysctl_verify_rxbufs_limit, 0, &rtw_rxbufs_limit, 0, |
| 159 | CTL_CREATE, CTL_EOL)) != 0) |
| 160 | goto err; |
| 161 | |
| 162 | #endif /* RTW_DEBUG */ |
| 163 | /* set fallback RF programming method */ |
| 164 | if ((rc = sysctl_createv(clog, 0, &rnode, &cnode, |
| 165 | CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, |
| 166 | "rfprog_fallback" , |
| 167 | SYSCTL_DESCR("Set fallback RF programming method" ), |
| 168 | rtw_sysctl_verify_rfprog, 0, &rtw_rfprog_fallback, 0, |
| 169 | CTL_CREATE, CTL_EOL)) != 0) |
| 170 | goto err; |
| 171 | |
| 172 | /* force host to control RF I/O bus */ |
| 173 | if ((rc = sysctl_createv(clog, 0, &rnode, &cnode, |
| 174 | CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, |
| 175 | "host_rfio" , SYSCTL_DESCR("Enable host control of RF I/O" ), |
| 176 | rtw_sysctl_verify_rfio, 0, &rtw_host_rfio, 0, |
| 177 | CTL_CREATE, CTL_EOL)) != 0) |
| 178 | goto err; |
| 179 | |
| 180 | return; |
| 181 | err: |
| 182 | printf("%s: sysctl_createv failed (rc = %d)\n" , __func__, rc); |
| 183 | } |
| 184 | |
| 185 | static int |
| 186 | rtw_sysctl_verify(SYSCTLFN_ARGS, int lower, int upper) |
| 187 | { |
| 188 | int error, t; |
| 189 | struct sysctlnode node; |
| 190 | |
| 191 | node = *rnode; |
| 192 | t = *(int*)rnode->sysctl_data; |
| 193 | node.sysctl_data = &t; |
| 194 | error = sysctl_lookup(SYSCTLFN_CALL(&node)); |
| 195 | if (error || newp == NULL) |
| 196 | return (error); |
| 197 | |
| 198 | if (t < lower || t > upper) |
| 199 | return (EINVAL); |
| 200 | |
| 201 | *(int*)rnode->sysctl_data = t; |
| 202 | |
| 203 | return (0); |
| 204 | } |
| 205 | |
| 206 | static int |
| 207 | rtw_sysctl_verify_rfprog(SYSCTLFN_ARGS) |
| 208 | { |
| 209 | return rtw_sysctl_verify(SYSCTLFN_CALL(__UNCONST(rnode)), 0, |
| 210 | __SHIFTOUT(RTW_CONFIG4_RFTYPE_MASK, RTW_CONFIG4_RFTYPE_MASK)); |
| 211 | } |
| 212 | |
| 213 | static int |
| 214 | rtw_sysctl_verify_rfio(SYSCTLFN_ARGS) |
| 215 | { |
| 216 | return rtw_sysctl_verify(SYSCTLFN_CALL(__UNCONST(rnode)), 0, 1); |
| 217 | } |
| 218 | |
| 219 | #ifdef RTW_DEBUG |
| 220 | static int |
| 221 | rtw_sysctl_verify_debug(SYSCTLFN_ARGS) |
| 222 | { |
| 223 | return rtw_sysctl_verify(SYSCTLFN_CALL(__UNCONST(rnode)), |
| 224 | 0, RTW_DEBUG_MAX); |
| 225 | } |
| 226 | |
| 227 | static int |
| 228 | rtw_sysctl_verify_rxbufs_limit(SYSCTLFN_ARGS) |
| 229 | { |
| 230 | return rtw_sysctl_verify(SYSCTLFN_CALL(__UNCONST(rnode)), |
| 231 | 0, RTW_RXQLEN); |
| 232 | } |
| 233 | |
| 234 | static void |
| 235 | rtw_print_regs(struct rtw_regs *regs, const char *dvname, const char *where) |
| 236 | { |
| 237 | #define PRINTREG32(sc, reg) \ |
| 238 | RTW_DPRINTF(RTW_DEBUG_REGDUMP, \ |
| 239 | ("%s: reg[ " #reg " / %03x ] = %08x\n", \ |
| 240 | dvname, reg, RTW_READ(regs, reg))) |
| 241 | |
| 242 | #define PRINTREG16(sc, reg) \ |
| 243 | RTW_DPRINTF(RTW_DEBUG_REGDUMP, \ |
| 244 | ("%s: reg[ " #reg " / %03x ] = %04x\n", \ |
| 245 | dvname, reg, RTW_READ16(regs, reg))) |
| 246 | |
| 247 | #define PRINTREG8(sc, reg) \ |
| 248 | RTW_DPRINTF(RTW_DEBUG_REGDUMP, \ |
| 249 | ("%s: reg[ " #reg " / %03x ] = %02x\n", \ |
| 250 | dvname, reg, RTW_READ8(regs, reg))) |
| 251 | |
| 252 | RTW_DPRINTF(RTW_DEBUG_REGDUMP, ("%s: %s\n" , dvname, where)); |
| 253 | |
| 254 | PRINTREG32(regs, RTW_IDR0); |
| 255 | PRINTREG32(regs, RTW_IDR1); |
| 256 | PRINTREG32(regs, RTW_MAR0); |
| 257 | PRINTREG32(regs, RTW_MAR1); |
| 258 | PRINTREG32(regs, RTW_TSFTRL); |
| 259 | PRINTREG32(regs, RTW_TSFTRH); |
| 260 | PRINTREG32(regs, RTW_TLPDA); |
| 261 | PRINTREG32(regs, RTW_TNPDA); |
| 262 | PRINTREG32(regs, RTW_THPDA); |
| 263 | PRINTREG32(regs, RTW_TCR); |
| 264 | PRINTREG32(regs, RTW_RCR); |
| 265 | PRINTREG32(regs, RTW_TINT); |
| 266 | PRINTREG32(regs, RTW_TBDA); |
| 267 | PRINTREG32(regs, RTW_ANAPARM); |
| 268 | PRINTREG32(regs, RTW_BB); |
| 269 | PRINTREG32(regs, RTW_PHYCFG); |
| 270 | PRINTREG32(regs, RTW_WAKEUP0L); |
| 271 | PRINTREG32(regs, RTW_WAKEUP0H); |
| 272 | PRINTREG32(regs, RTW_WAKEUP1L); |
| 273 | PRINTREG32(regs, RTW_WAKEUP1H); |
| 274 | PRINTREG32(regs, RTW_WAKEUP2LL); |
| 275 | PRINTREG32(regs, RTW_WAKEUP2LH); |
| 276 | PRINTREG32(regs, RTW_WAKEUP2HL); |
| 277 | PRINTREG32(regs, RTW_WAKEUP2HH); |
| 278 | PRINTREG32(regs, RTW_WAKEUP3LL); |
| 279 | PRINTREG32(regs, RTW_WAKEUP3LH); |
| 280 | PRINTREG32(regs, RTW_WAKEUP3HL); |
| 281 | PRINTREG32(regs, RTW_WAKEUP3HH); |
| 282 | PRINTREG32(regs, RTW_WAKEUP4LL); |
| 283 | PRINTREG32(regs, RTW_WAKEUP4LH); |
| 284 | PRINTREG32(regs, RTW_WAKEUP4HL); |
| 285 | PRINTREG32(regs, RTW_WAKEUP4HH); |
| 286 | PRINTREG32(regs, RTW_DK0); |
| 287 | PRINTREG32(regs, RTW_DK1); |
| 288 | PRINTREG32(regs, RTW_DK2); |
| 289 | PRINTREG32(regs, RTW_DK3); |
| 290 | PRINTREG32(regs, RTW_RETRYCTR); |
| 291 | PRINTREG32(regs, RTW_RDSAR); |
| 292 | PRINTREG32(regs, RTW_FER); |
| 293 | PRINTREG32(regs, RTW_FEMR); |
| 294 | PRINTREG32(regs, RTW_FPSR); |
| 295 | PRINTREG32(regs, RTW_FFER); |
| 296 | |
| 297 | /* 16-bit registers */ |
| 298 | PRINTREG16(regs, RTW_BRSR); |
| 299 | PRINTREG16(regs, RTW_IMR); |
| 300 | PRINTREG16(regs, RTW_ISR); |
| 301 | PRINTREG16(regs, RTW_BCNITV); |
| 302 | PRINTREG16(regs, RTW_ATIMWND); |
| 303 | PRINTREG16(regs, RTW_BINTRITV); |
| 304 | PRINTREG16(regs, RTW_ATIMTRITV); |
| 305 | PRINTREG16(regs, RTW_CRC16ERR); |
| 306 | PRINTREG16(regs, RTW_CRC0); |
| 307 | PRINTREG16(regs, RTW_CRC1); |
| 308 | PRINTREG16(regs, RTW_CRC2); |
| 309 | PRINTREG16(regs, RTW_CRC3); |
| 310 | PRINTREG16(regs, RTW_CRC4); |
| 311 | PRINTREG16(regs, RTW_CWR); |
| 312 | |
| 313 | /* 8-bit registers */ |
| 314 | PRINTREG8(regs, RTW_CR); |
| 315 | PRINTREG8(regs, RTW_9346CR); |
| 316 | PRINTREG8(regs, RTW_CONFIG0); |
| 317 | PRINTREG8(regs, RTW_CONFIG1); |
| 318 | PRINTREG8(regs, RTW_CONFIG2); |
| 319 | PRINTREG8(regs, RTW_MSR); |
| 320 | PRINTREG8(regs, RTW_CONFIG3); |
| 321 | PRINTREG8(regs, RTW_CONFIG4); |
| 322 | PRINTREG8(regs, RTW_TESTR); |
| 323 | PRINTREG8(regs, RTW_PSR); |
| 324 | PRINTREG8(regs, RTW_SCR); |
| 325 | PRINTREG8(regs, RTW_PHYDELAY); |
| 326 | PRINTREG8(regs, RTW_CRCOUNT); |
| 327 | PRINTREG8(regs, RTW_PHYADDR); |
| 328 | PRINTREG8(regs, RTW_PHYDATAW); |
| 329 | PRINTREG8(regs, RTW_PHYDATAR); |
| 330 | PRINTREG8(regs, RTW_CONFIG5); |
| 331 | PRINTREG8(regs, RTW_TPPOLL); |
| 332 | |
| 333 | PRINTREG16(regs, RTW_BSSID16); |
| 334 | PRINTREG32(regs, RTW_BSSID32); |
| 335 | #undef PRINTREG32 |
| 336 | #undef PRINTREG16 |
| 337 | #undef PRINTREG8 |
| 338 | } |
| 339 | #endif /* RTW_DEBUG */ |
| 340 | |
| 341 | void |
| 342 | rtw_continuous_tx_enable(struct rtw_softc *sc, int enable) |
| 343 | { |
| 344 | struct rtw_regs *regs = &sc->sc_regs; |
| 345 | |
| 346 | uint32_t tcr; |
| 347 | tcr = RTW_READ(regs, RTW_TCR); |
| 348 | tcr &= ~RTW_TCR_LBK_MASK; |
| 349 | if (enable) |
| 350 | tcr |= RTW_TCR_LBK_CONT; |
| 351 | else |
| 352 | tcr |= RTW_TCR_LBK_NORMAL; |
| 353 | RTW_WRITE(regs, RTW_TCR, tcr); |
| 354 | RTW_SYNC(regs, RTW_TCR, RTW_TCR); |
| 355 | rtw_set_access(regs, RTW_ACCESS_ANAPARM); |
| 356 | rtw_txdac_enable(sc, !enable); |
| 357 | rtw_set_access(regs, RTW_ACCESS_ANAPARM);/* XXX Voodoo from Linux. */ |
| 358 | rtw_set_access(regs, RTW_ACCESS_NONE); |
| 359 | } |
| 360 | |
| 361 | #ifdef RTW_DEBUG |
| 362 | static const char * |
| 363 | rtw_access_string(enum rtw_access access) |
| 364 | { |
| 365 | switch (access) { |
| 366 | case RTW_ACCESS_NONE: |
| 367 | return "none" ; |
| 368 | case RTW_ACCESS_CONFIG: |
| 369 | return "config" ; |
| 370 | case RTW_ACCESS_ANAPARM: |
| 371 | return "anaparm" ; |
| 372 | default: |
| 373 | return "unknown" ; |
| 374 | } |
| 375 | } |
| 376 | #endif /* RTW_DEBUG */ |
| 377 | |
| 378 | static void |
| 379 | rtw_set_access1(struct rtw_regs *regs, enum rtw_access naccess) |
| 380 | { |
| 381 | KASSERT(/* naccess >= RTW_ACCESS_NONE && */ |
| 382 | naccess <= RTW_ACCESS_ANAPARM); |
| 383 | KASSERT(/* regs->r_access >= RTW_ACCESS_NONE && */ |
| 384 | regs->r_access <= RTW_ACCESS_ANAPARM); |
| 385 | |
| 386 | if (naccess == regs->r_access) |
| 387 | return; |
| 388 | |
| 389 | switch (naccess) { |
| 390 | case RTW_ACCESS_NONE: |
| 391 | switch (regs->r_access) { |
| 392 | case RTW_ACCESS_ANAPARM: |
| 393 | rtw_anaparm_enable(regs, 0); |
| 394 | /*FALLTHROUGH*/ |
| 395 | case RTW_ACCESS_CONFIG: |
| 396 | rtw_config0123_enable(regs, 0); |
| 397 | /*FALLTHROUGH*/ |
| 398 | case RTW_ACCESS_NONE: |
| 399 | break; |
| 400 | } |
| 401 | break; |
| 402 | case RTW_ACCESS_CONFIG: |
| 403 | switch (regs->r_access) { |
| 404 | case RTW_ACCESS_NONE: |
| 405 | rtw_config0123_enable(regs, 1); |
| 406 | /*FALLTHROUGH*/ |
| 407 | case RTW_ACCESS_CONFIG: |
| 408 | break; |
| 409 | case RTW_ACCESS_ANAPARM: |
| 410 | rtw_anaparm_enable(regs, 0); |
| 411 | break; |
| 412 | } |
| 413 | break; |
| 414 | case RTW_ACCESS_ANAPARM: |
| 415 | switch (regs->r_access) { |
| 416 | case RTW_ACCESS_NONE: |
| 417 | rtw_config0123_enable(regs, 1); |
| 418 | /*FALLTHROUGH*/ |
| 419 | case RTW_ACCESS_CONFIG: |
| 420 | rtw_anaparm_enable(regs, 1); |
| 421 | /*FALLTHROUGH*/ |
| 422 | case RTW_ACCESS_ANAPARM: |
| 423 | break; |
| 424 | } |
| 425 | break; |
| 426 | } |
| 427 | } |
| 428 | |
| 429 | void |
| 430 | rtw_set_access(struct rtw_regs *regs, enum rtw_access access) |
| 431 | { |
| 432 | rtw_set_access1(regs, access); |
| 433 | RTW_DPRINTF(RTW_DEBUG_ACCESS, |
| 434 | ("%s: access %s -> %s\n" , __func__, |
| 435 | rtw_access_string(regs->r_access), |
| 436 | rtw_access_string(access))); |
| 437 | regs->r_access = access; |
| 438 | } |
| 439 | |
| 440 | /* |
| 441 | * Enable registers, switch register banks. |
| 442 | */ |
| 443 | void |
| 444 | rtw_config0123_enable(struct rtw_regs *regs, int enable) |
| 445 | { |
| 446 | uint8_t ecr; |
| 447 | ecr = RTW_READ8(regs, RTW_9346CR); |
| 448 | ecr &= ~(RTW_9346CR_EEM_MASK | RTW_9346CR_EECS | RTW_9346CR_EESK); |
| 449 | if (enable) |
| 450 | ecr |= RTW_9346CR_EEM_CONFIG; |
| 451 | else { |
| 452 | RTW_WBW(regs, RTW_9346CR, MAX(RTW_CONFIG0, RTW_CONFIG3)); |
| 453 | ecr |= RTW_9346CR_EEM_NORMAL; |
| 454 | } |
| 455 | RTW_WRITE8(regs, RTW_9346CR, ecr); |
| 456 | RTW_SYNC(regs, RTW_9346CR, RTW_9346CR); |
| 457 | } |
| 458 | |
| 459 | /* requires rtw_config0123_enable(, 1) */ |
| 460 | void |
| 461 | rtw_anaparm_enable(struct rtw_regs *regs, int enable) |
| 462 | { |
| 463 | uint8_t cfg3; |
| 464 | |
| 465 | cfg3 = RTW_READ8(regs, RTW_CONFIG3); |
| 466 | cfg3 |= RTW_CONFIG3_CLKRUNEN; |
| 467 | if (enable) |
| 468 | cfg3 |= RTW_CONFIG3_PARMEN; |
| 469 | else |
| 470 | cfg3 &= ~RTW_CONFIG3_PARMEN; |
| 471 | RTW_WRITE8(regs, RTW_CONFIG3, cfg3); |
| 472 | RTW_SYNC(regs, RTW_CONFIG3, RTW_CONFIG3); |
| 473 | } |
| 474 | |
| 475 | /* requires rtw_anaparm_enable(, 1) */ |
| 476 | void |
| 477 | rtw_txdac_enable(struct rtw_softc *sc, int enable) |
| 478 | { |
| 479 | uint32_t anaparm; |
| 480 | struct rtw_regs *regs = &sc->sc_regs; |
| 481 | |
| 482 | anaparm = RTW_READ(regs, RTW_ANAPARM); |
| 483 | if (enable) |
| 484 | anaparm &= ~RTW_ANAPARM_TXDACOFF; |
| 485 | else |
| 486 | anaparm |= RTW_ANAPARM_TXDACOFF; |
| 487 | RTW_WRITE(regs, RTW_ANAPARM, anaparm); |
| 488 | RTW_SYNC(regs, RTW_ANAPARM, RTW_ANAPARM); |
| 489 | } |
| 490 | |
| 491 | static inline int |
| 492 | rtw_chip_reset1(struct rtw_regs *regs, device_t dev) |
| 493 | { |
| 494 | uint8_t cr; |
| 495 | int i; |
| 496 | |
| 497 | RTW_WRITE8(regs, RTW_CR, RTW_CR_RST); |
| 498 | |
| 499 | RTW_WBR(regs, RTW_CR, RTW_CR); |
| 500 | |
| 501 | for (i = 0; i < 1000; i++) { |
| 502 | if ((cr = RTW_READ8(regs, RTW_CR) & RTW_CR_RST) == 0) { |
| 503 | RTW_DPRINTF(RTW_DEBUG_RESET, |
| 504 | ("%s: reset in %dus\n" , device_xname(dev), i)); |
| 505 | return 0; |
| 506 | } |
| 507 | RTW_RBR(regs, RTW_CR, RTW_CR); |
| 508 | DELAY(10); /* 10us */ |
| 509 | } |
| 510 | |
| 511 | aprint_error_dev(dev, "reset failed\n" ); |
| 512 | return ETIMEDOUT; |
| 513 | } |
| 514 | |
| 515 | static inline int |
| 516 | rtw_chip_reset(struct rtw_regs *regs, device_t dev) |
| 517 | { |
| 518 | uint32_t tcr; |
| 519 | |
| 520 | /* from Linux driver */ |
| 521 | tcr = RTW_TCR_CWMIN | RTW_TCR_MXDMA_2048 | |
| 522 | __SHIFTIN(7, RTW_TCR_SRL_MASK) | __SHIFTIN(7, RTW_TCR_LRL_MASK); |
| 523 | |
| 524 | RTW_WRITE(regs, RTW_TCR, tcr); |
| 525 | |
| 526 | RTW_WBW(regs, RTW_CR, RTW_TCR); |
| 527 | |
| 528 | return rtw_chip_reset1(regs, dev); |
| 529 | } |
| 530 | |
| 531 | static int |
| 532 | rtw_wep_decap(struct ieee80211_key *k, struct mbuf *m, int hdrlen) |
| 533 | { |
| 534 | struct ieee80211_key keycopy; |
| 535 | |
| 536 | RTW_DPRINTF(RTW_DEBUG_KEY, ("%s:\n" , __func__)); |
| 537 | |
| 538 | keycopy = *k; |
| 539 | keycopy.wk_flags &= ~IEEE80211_KEY_SWCRYPT; |
| 540 | |
| 541 | return (*ieee80211_cipher_wep.ic_decap)(&keycopy, m, hdrlen); |
| 542 | } |
| 543 | |
| 544 | static int |
| 545 | rtw_key_delete(struct ieee80211com *ic, const struct ieee80211_key *k) |
| 546 | { |
| 547 | struct rtw_softc *sc = ic->ic_ifp->if_softc; |
| 548 | |
| 549 | DPRINTF(sc, RTW_DEBUG_KEY, ("%s: delete key %u\n" , __func__, |
| 550 | k->wk_keyix)); |
| 551 | |
| 552 | KASSERT(k->wk_keyix < IEEE80211_WEP_NKID); |
| 553 | |
| 554 | if (k->wk_keylen != 0 && |
| 555 | k->wk_cipher->ic_cipher == IEEE80211_CIPHER_WEP) |
| 556 | sc->sc_flags &= ~RTW_F_DK_VALID; |
| 557 | |
| 558 | return 1; |
| 559 | } |
| 560 | |
| 561 | static int |
| 562 | rtw_key_set(struct ieee80211com *ic, const struct ieee80211_key *k, |
| 563 | const u_int8_t mac[IEEE80211_ADDR_LEN]) |
| 564 | { |
| 565 | struct rtw_softc *sc = ic->ic_ifp->if_softc; |
| 566 | |
| 567 | DPRINTF(sc, RTW_DEBUG_KEY, ("%s: set key %u\n" , __func__, k->wk_keyix)); |
| 568 | |
| 569 | KASSERT(k->wk_keyix < IEEE80211_WEP_NKID); |
| 570 | |
| 571 | sc->sc_flags &= ~RTW_F_DK_VALID; |
| 572 | |
| 573 | return 1; |
| 574 | } |
| 575 | |
| 576 | static void |
| 577 | rtw_key_update_begin(struct ieee80211com *ic) |
| 578 | { |
| 579 | #ifdef RTW_DEBUG |
| 580 | struct ifnet *ifp = ic->ic_ifp; |
| 581 | struct rtw_softc *sc = ifp->if_softc; |
| 582 | #endif |
| 583 | |
| 584 | DPRINTF(sc, RTW_DEBUG_KEY, ("%s:\n" , __func__)); |
| 585 | } |
| 586 | |
| 587 | static void |
| 588 | rtw_tx_kick(struct rtw_regs *regs, uint8_t ringsel) |
| 589 | { |
| 590 | uint8_t tppoll; |
| 591 | |
| 592 | tppoll = RTW_READ8(regs, RTW_TPPOLL); |
| 593 | tppoll &= ~RTW_TPPOLL_SALL; |
| 594 | tppoll |= ringsel & RTW_TPPOLL_ALL; |
| 595 | RTW_WRITE8(regs, RTW_TPPOLL, tppoll); |
| 596 | RTW_SYNC(regs, RTW_TPPOLL, RTW_TPPOLL); |
| 597 | } |
| 598 | |
| 599 | static void |
| 600 | rtw_key_update_end(struct ieee80211com *ic) |
| 601 | { |
| 602 | struct ifnet *ifp = ic->ic_ifp; |
| 603 | struct rtw_softc *sc = ifp->if_softc; |
| 604 | |
| 605 | DPRINTF(sc, RTW_DEBUG_KEY, ("%s:\n" , __func__)); |
| 606 | |
| 607 | if ((sc->sc_flags & RTW_F_DK_VALID) != 0 || |
| 608 | !device_is_active(sc->sc_dev)) |
| 609 | return; |
| 610 | |
| 611 | rtw_io_enable(sc, RTW_CR_RE | RTW_CR_TE, 0); |
| 612 | rtw_wep_setkeys(sc, ic->ic_nw_keys, ic->ic_def_txkey); |
| 613 | rtw_io_enable(sc, RTW_CR_RE | RTW_CR_TE, |
| 614 | (ifp->if_flags & IFF_RUNNING) != 0); |
| 615 | } |
| 616 | |
| 617 | static bool |
| 618 | rtw_key_hwsupp(uint32_t flags, const struct ieee80211_key *k) |
| 619 | { |
| 620 | if (k->wk_cipher->ic_cipher != IEEE80211_CIPHER_WEP) |
| 621 | return false; |
| 622 | |
| 623 | return ((flags & RTW_C_RXWEP_40) != 0 && k->wk_keylen == 5) || |
| 624 | ((flags & RTW_C_RXWEP_104) != 0 && k->wk_keylen == 13); |
| 625 | } |
| 626 | |
| 627 | static void |
| 628 | rtw_wep_setkeys(struct rtw_softc *sc, struct ieee80211_key *wk, int txkey) |
| 629 | { |
| 630 | uint8_t psr, scr; |
| 631 | int i, keylen = 0; |
| 632 | struct rtw_regs *regs; |
| 633 | union rtw_keys *rk; |
| 634 | |
| 635 | regs = &sc->sc_regs; |
| 636 | rk = &sc->sc_keys; |
| 637 | |
| 638 | (void)memset(rk, 0, sizeof(*rk)); |
| 639 | |
| 640 | /* Temporarily use software crypto for all keys. */ |
| 641 | for (i = 0; i < IEEE80211_WEP_NKID; i++) { |
| 642 | if (wk[i].wk_cipher == &rtw_cipher_wep) |
| 643 | wk[i].wk_cipher = &ieee80211_cipher_wep; |
| 644 | } |
| 645 | |
| 646 | rtw_set_access(regs, RTW_ACCESS_CONFIG); |
| 647 | |
| 648 | psr = RTW_READ8(regs, RTW_PSR); |
| 649 | scr = RTW_READ8(regs, RTW_SCR); |
| 650 | scr &= ~(RTW_SCR_KM_MASK | RTW_SCR_TXSECON | RTW_SCR_RXSECON); |
| 651 | |
| 652 | if ((sc->sc_ic.ic_flags & IEEE80211_F_PRIVACY) == 0) |
| 653 | goto out; |
| 654 | |
| 655 | for (i = 0; i < IEEE80211_WEP_NKID; i++) { |
| 656 | if (!rtw_key_hwsupp(sc->sc_flags, &wk[i])) |
| 657 | continue; |
| 658 | if (i == txkey) { |
| 659 | keylen = wk[i].wk_keylen; |
| 660 | break; |
| 661 | } |
| 662 | keylen = MAX(keylen, wk[i].wk_keylen); |
| 663 | } |
| 664 | |
| 665 | if (keylen == 5) |
| 666 | scr |= RTW_SCR_KM_WEP40 | RTW_SCR_RXSECON; |
| 667 | else if (keylen == 13) |
| 668 | scr |= RTW_SCR_KM_WEP104 | RTW_SCR_RXSECON; |
| 669 | |
| 670 | for (i = 0; i < IEEE80211_WEP_NKID; i++) { |
| 671 | if (wk[i].wk_keylen != keylen || |
| 672 | wk[i].wk_cipher->ic_cipher != IEEE80211_CIPHER_WEP) |
| 673 | continue; |
| 674 | /* h/w will decrypt, s/w still strips headers */ |
| 675 | wk[i].wk_cipher = &rtw_cipher_wep; |
| 676 | (void)memcpy(rk->rk_keys[i], wk[i].wk_key, wk[i].wk_keylen); |
| 677 | } |
| 678 | |
| 679 | out: |
| 680 | RTW_WRITE8(regs, RTW_PSR, psr & ~RTW_PSR_PSEN); |
| 681 | |
| 682 | bus_space_write_region_stream_4(regs->r_bt, regs->r_bh, |
| 683 | RTW_DK0, rk->rk_words, __arraycount(rk->rk_words)); |
| 684 | |
| 685 | bus_space_barrier(regs->r_bt, regs->r_bh, RTW_DK0, sizeof(rk->rk_words), |
| 686 | BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE); |
| 687 | |
| 688 | RTW_DPRINTF(RTW_DEBUG_KEY, |
| 689 | ("%s.%d: scr %02" PRIx8 ", keylen %d\n" , __func__, __LINE__, scr, |
| 690 | keylen)); |
| 691 | |
| 692 | RTW_WBW(regs, RTW_DK0, RTW_PSR); |
| 693 | RTW_WRITE8(regs, RTW_PSR, psr); |
| 694 | RTW_WBW(regs, RTW_PSR, RTW_SCR); |
| 695 | RTW_WRITE8(regs, RTW_SCR, scr); |
| 696 | RTW_SYNC(regs, RTW_SCR, RTW_SCR); |
| 697 | rtw_set_access(regs, RTW_ACCESS_NONE); |
| 698 | sc->sc_flags |= RTW_F_DK_VALID; |
| 699 | } |
| 700 | |
| 701 | static inline int |
| 702 | rtw_recall_eeprom(struct rtw_regs *regs, device_t dev) |
| 703 | { |
| 704 | int i; |
| 705 | uint8_t ecr; |
| 706 | |
| 707 | ecr = RTW_READ8(regs, RTW_9346CR); |
| 708 | ecr = (ecr & ~RTW_9346CR_EEM_MASK) | RTW_9346CR_EEM_AUTOLOAD; |
| 709 | RTW_WRITE8(regs, RTW_9346CR, ecr); |
| 710 | |
| 711 | RTW_WBR(regs, RTW_9346CR, RTW_9346CR); |
| 712 | |
| 713 | /* wait 25ms for completion */ |
| 714 | for (i = 0; i < 250; i++) { |
| 715 | ecr = RTW_READ8(regs, RTW_9346CR); |
| 716 | if ((ecr & RTW_9346CR_EEM_MASK) == RTW_9346CR_EEM_NORMAL) { |
| 717 | RTW_DPRINTF(RTW_DEBUG_RESET, |
| 718 | ("%s: recall EEPROM in %dus\n" , device_xname(dev), |
| 719 | i * 100)); |
| 720 | return 0; |
| 721 | } |
| 722 | RTW_RBR(regs, RTW_9346CR, RTW_9346CR); |
| 723 | DELAY(100); |
| 724 | } |
| 725 | aprint_error_dev(dev, "recall EEPROM failed\n" ); |
| 726 | return ETIMEDOUT; |
| 727 | } |
| 728 | |
| 729 | static inline int |
| 730 | rtw_reset(struct rtw_softc *sc) |
| 731 | { |
| 732 | int rc; |
| 733 | uint8_t config1; |
| 734 | |
| 735 | sc->sc_flags &= ~RTW_F_DK_VALID; |
| 736 | |
| 737 | if ((rc = rtw_chip_reset(&sc->sc_regs, sc->sc_dev)) != 0) |
| 738 | return rc; |
| 739 | |
| 740 | rc = rtw_recall_eeprom(&sc->sc_regs, sc->sc_dev); |
| 741 | |
| 742 | config1 = RTW_READ8(&sc->sc_regs, RTW_CONFIG1); |
| 743 | RTW_WRITE8(&sc->sc_regs, RTW_CONFIG1, config1 & ~RTW_CONFIG1_PMEN); |
| 744 | /* TBD turn off maximum power saving? */ |
| 745 | |
| 746 | return 0; |
| 747 | } |
| 748 | |
| 749 | static inline int |
| 750 | rtw_txdesc_dmamaps_create(bus_dma_tag_t dmat, struct rtw_txsoft *descs, |
| 751 | u_int ndescs) |
| 752 | { |
| 753 | int i, rc = 0; |
| 754 | for (i = 0; i < ndescs; i++) { |
| 755 | rc = bus_dmamap_create(dmat, MCLBYTES, RTW_MAXPKTSEGS, MCLBYTES, |
| 756 | 0, 0, &descs[i].ts_dmamap); |
| 757 | if (rc != 0) |
| 758 | break; |
| 759 | } |
| 760 | return rc; |
| 761 | } |
| 762 | |
| 763 | static inline int |
| 764 | rtw_rxdesc_dmamaps_create(bus_dma_tag_t dmat, struct rtw_rxsoft *descs, |
| 765 | u_int ndescs) |
| 766 | { |
| 767 | int i, rc = 0; |
| 768 | for (i = 0; i < ndescs; i++) { |
| 769 | rc = bus_dmamap_create(dmat, MCLBYTES, 1, MCLBYTES, 0, 0, |
| 770 | &descs[i].rs_dmamap); |
| 771 | if (rc != 0) |
| 772 | break; |
| 773 | } |
| 774 | return rc; |
| 775 | } |
| 776 | |
| 777 | static inline void |
| 778 | rtw_rxdesc_dmamaps_destroy(bus_dma_tag_t dmat, struct rtw_rxsoft *descs, |
| 779 | u_int ndescs) |
| 780 | { |
| 781 | int i; |
| 782 | for (i = 0; i < ndescs; i++) { |
| 783 | if (descs[i].rs_dmamap != NULL) |
| 784 | bus_dmamap_destroy(dmat, descs[i].rs_dmamap); |
| 785 | } |
| 786 | } |
| 787 | |
| 788 | static inline void |
| 789 | rtw_txdesc_dmamaps_destroy(bus_dma_tag_t dmat, struct rtw_txsoft *descs, |
| 790 | u_int ndescs) |
| 791 | { |
| 792 | int i; |
| 793 | for (i = 0; i < ndescs; i++) { |
| 794 | if (descs[i].ts_dmamap != NULL) |
| 795 | bus_dmamap_destroy(dmat, descs[i].ts_dmamap); |
| 796 | } |
| 797 | } |
| 798 | |
| 799 | static inline void |
| 800 | rtw_srom_free(struct rtw_srom *sr) |
| 801 | { |
| 802 | sr->sr_size = 0; |
| 803 | if (sr->sr_content == NULL) |
| 804 | return; |
| 805 | free(sr->sr_content, M_DEVBUF); |
| 806 | sr->sr_content = NULL; |
| 807 | } |
| 808 | |
| 809 | static void |
| 810 | rtw_srom_defaults(struct rtw_srom *sr, uint32_t *flags, |
| 811 | uint8_t *cs_threshold, enum rtw_rfchipid *rfchipid, uint32_t *rcr) |
| 812 | { |
| 813 | *flags |= (RTW_F_DIGPHY|RTW_F_ANTDIV); |
| 814 | *cs_threshold = RTW_SR_ENERGYDETTHR_DEFAULT; |
| 815 | *rcr |= RTW_RCR_ENCS1; |
| 816 | *rfchipid = RTW_RFCHIPID_PHILIPS; |
| 817 | } |
| 818 | |
| 819 | static int |
| 820 | rtw_srom_parse(struct rtw_srom *sr, uint32_t *flags, uint8_t *cs_threshold, |
| 821 | enum rtw_rfchipid *rfchipid, uint32_t *rcr, enum rtw_locale *locale, |
| 822 | device_t dev) |
| 823 | { |
| 824 | int i; |
| 825 | const char *rfname, *paname; |
| 826 | char scratch[sizeof("unknown 0xXX" )]; |
| 827 | uint16_t srom_version; |
| 828 | |
| 829 | *flags &= ~(RTW_F_DIGPHY|RTW_F_DFLANTB|RTW_F_ANTDIV); |
| 830 | *rcr &= ~(RTW_RCR_ENCS1 | RTW_RCR_ENCS2); |
| 831 | |
| 832 | srom_version = RTW_SR_GET16(sr, RTW_SR_VERSION); |
| 833 | |
| 834 | if (srom_version <= 0x0101) { |
| 835 | aprint_error_dev(dev, |
| 836 | "SROM version %d.%d is not understood, " |
| 837 | "limping along with defaults\n" , |
| 838 | srom_version >> 8, srom_version & 0xff); |
| 839 | rtw_srom_defaults(sr, flags, cs_threshold, rfchipid, rcr); |
| 840 | return 0; |
| 841 | } else { |
| 842 | aprint_verbose_dev(dev, "SROM version %d.%d\n" , |
| 843 | srom_version >> 8, srom_version & 0xff); |
| 844 | } |
| 845 | |
| 846 | uint8_t mac[IEEE80211_ADDR_LEN]; |
| 847 | for (i = 0; i < IEEE80211_ADDR_LEN; i++) |
| 848 | mac[i] = RTW_SR_GET(sr, RTW_SR_MAC + i); |
| 849 | __USE(mac); |
| 850 | |
| 851 | RTW_DPRINTF(RTW_DEBUG_ATTACH, |
| 852 | ("%s: EEPROM MAC %s\n" , device_xname(dev), ether_sprintf(mac))); |
| 853 | |
| 854 | *cs_threshold = RTW_SR_GET(sr, RTW_SR_ENERGYDETTHR); |
| 855 | |
| 856 | if ((RTW_SR_GET(sr, RTW_SR_CONFIG2) & RTW_CONFIG2_ANT) != 0) |
| 857 | *flags |= RTW_F_ANTDIV; |
| 858 | |
| 859 | /* Note well: the sense of the RTW_SR_RFPARM_DIGPHY bit seems |
| 860 | * to be reversed. |
| 861 | */ |
| 862 | if ((RTW_SR_GET(sr, RTW_SR_RFPARM) & RTW_SR_RFPARM_DIGPHY) == 0) |
| 863 | *flags |= RTW_F_DIGPHY; |
| 864 | if ((RTW_SR_GET(sr, RTW_SR_RFPARM) & RTW_SR_RFPARM_DFLANTB) != 0) |
| 865 | *flags |= RTW_F_DFLANTB; |
| 866 | |
| 867 | *rcr |= __SHIFTIN(__SHIFTOUT(RTW_SR_GET(sr, RTW_SR_RFPARM), |
| 868 | RTW_SR_RFPARM_CS_MASK), RTW_RCR_ENCS1); |
| 869 | |
| 870 | if ((RTW_SR_GET(sr, RTW_SR_CONFIG0) & RTW_CONFIG0_WEP104) != 0) |
| 871 | *flags |= RTW_C_RXWEP_104; |
| 872 | |
| 873 | *flags |= RTW_C_RXWEP_40; /* XXX */ |
| 874 | |
| 875 | *rfchipid = RTW_SR_GET(sr, RTW_SR_RFCHIPID); |
| 876 | switch (*rfchipid) { |
| 877 | case RTW_RFCHIPID_GCT: /* this combo seen in the wild */ |
| 878 | rfname = "GCT GRF5101" ; |
| 879 | paname = "Winspring WS9901" ; |
| 880 | break; |
| 881 | case RTW_RFCHIPID_MAXIM: |
| 882 | rfname = "Maxim MAX2820" ; /* guess */ |
| 883 | paname = "Maxim MAX2422" ; /* guess */ |
| 884 | break; |
| 885 | case RTW_RFCHIPID_INTERSIL: |
| 886 | rfname = "Intersil HFA3873" ; /* guess */ |
| 887 | paname = "Intersil <unknown>" ; |
| 888 | break; |
| 889 | case RTW_RFCHIPID_PHILIPS: /* this combo seen in the wild */ |
| 890 | rfname = "Philips SA2400A" ; |
| 891 | paname = "Philips SA2411" ; |
| 892 | break; |
| 893 | case RTW_RFCHIPID_RFMD: |
| 894 | /* this is the same front-end as an atw(4)! */ |
| 895 | rfname = "RFMD RF2948B, " /* mentioned in Realtek docs */ |
| 896 | "LNA: RFMD RF2494, " /* mentioned in Realtek docs */ |
| 897 | "SYN: Silicon Labs Si4126" ; /* inferred from |
| 898 | * reference driver |
| 899 | */ |
| 900 | paname = "RFMD RF2189" ; /* mentioned in Realtek docs */ |
| 901 | break; |
| 902 | case RTW_RFCHIPID_RESERVED: |
| 903 | rfname = paname = "reserved" ; |
| 904 | break; |
| 905 | default: |
| 906 | snprintf(scratch, sizeof(scratch), "unknown 0x%02x" , *rfchipid); |
| 907 | rfname = paname = scratch; |
| 908 | } |
| 909 | aprint_normal_dev(dev, "RF: %s, PA: %s\n" , rfname, paname); |
| 910 | |
| 911 | switch (RTW_SR_GET(sr, RTW_SR_CONFIG0) & RTW_CONFIG0_GL_MASK) { |
| 912 | case RTW_CONFIG0_GL_USA: |
| 913 | case _RTW_CONFIG0_GL_USA: |
| 914 | *locale = RTW_LOCALE_USA; |
| 915 | break; |
| 916 | case RTW_CONFIG0_GL_EUROPE: |
| 917 | *locale = RTW_LOCALE_EUROPE; |
| 918 | break; |
| 919 | case RTW_CONFIG0_GL_JAPAN: |
| 920 | *locale = RTW_LOCALE_JAPAN; |
| 921 | break; |
| 922 | default: |
| 923 | *locale = RTW_LOCALE_UNKNOWN; |
| 924 | break; |
| 925 | } |
| 926 | return 0; |
| 927 | } |
| 928 | |
| 929 | /* Returns -1 on failure. */ |
| 930 | static int |
| 931 | rtw_srom_read(struct rtw_regs *regs, uint32_t flags, struct rtw_srom *sr, |
| 932 | device_t dev) |
| 933 | { |
| 934 | int rc; |
| 935 | struct seeprom_descriptor sd; |
| 936 | uint8_t ecr; |
| 937 | |
| 938 | (void)memset(&sd, 0, sizeof(sd)); |
| 939 | |
| 940 | ecr = RTW_READ8(regs, RTW_9346CR); |
| 941 | |
| 942 | if ((flags & RTW_F_9356SROM) != 0) { |
| 943 | RTW_DPRINTF(RTW_DEBUG_ATTACH, ("%s: 93c56 SROM\n" , |
| 944 | device_xname(dev))); |
| 945 | sr->sr_size = 256; |
| 946 | sd.sd_chip = C56_66; |
| 947 | } else { |
| 948 | RTW_DPRINTF(RTW_DEBUG_ATTACH, ("%s: 93c46 SROM\n" , |
| 949 | device_xname(dev))); |
| 950 | sr->sr_size = 128; |
| 951 | sd.sd_chip = C46; |
| 952 | } |
| 953 | |
| 954 | ecr &= ~(RTW_9346CR_EEDI | RTW_9346CR_EEDO | RTW_9346CR_EESK | |
| 955 | RTW_9346CR_EEM_MASK | RTW_9346CR_EECS); |
| 956 | ecr |= RTW_9346CR_EEM_PROGRAM; |
| 957 | |
| 958 | RTW_WRITE8(regs, RTW_9346CR, ecr); |
| 959 | |
| 960 | sr->sr_content = malloc(sr->sr_size, M_DEVBUF, M_NOWAIT); |
| 961 | |
| 962 | if (sr->sr_content == NULL) { |
| 963 | aprint_error_dev(dev, "unable to allocate SROM buffer\n" ); |
| 964 | return ENOMEM; |
| 965 | } |
| 966 | |
| 967 | (void)memset(sr->sr_content, 0, sr->sr_size); |
| 968 | |
| 969 | /* RTL8180 has a single 8-bit register for controlling the |
| 970 | * 93cx6 SROM. There is no "ready" bit. The RTL8180 |
| 971 | * input/output sense is the reverse of read_seeprom's. |
| 972 | */ |
| 973 | sd.sd_tag = regs->r_bt; |
| 974 | sd.sd_bsh = regs->r_bh; |
| 975 | sd.sd_regsize = 1; |
| 976 | sd.sd_control_offset = RTW_9346CR; |
| 977 | sd.sd_status_offset = RTW_9346CR; |
| 978 | sd.sd_dataout_offset = RTW_9346CR; |
| 979 | sd.sd_CK = RTW_9346CR_EESK; |
| 980 | sd.sd_CS = RTW_9346CR_EECS; |
| 981 | sd.sd_DI = RTW_9346CR_EEDO; |
| 982 | sd.sd_DO = RTW_9346CR_EEDI; |
| 983 | /* make read_seeprom enter EEPROM read/write mode */ |
| 984 | sd.sd_MS = ecr; |
| 985 | sd.sd_RDY = 0; |
| 986 | |
| 987 | /* TBD bus barriers */ |
| 988 | if (!read_seeprom(&sd, sr->sr_content, 0, sr->sr_size/2)) { |
| 989 | aprint_error_dev(dev, "could not read SROM\n" ); |
| 990 | free(sr->sr_content, M_DEVBUF); |
| 991 | sr->sr_content = NULL; |
| 992 | return -1; /* XXX */ |
| 993 | } |
| 994 | |
| 995 | /* end EEPROM read/write mode */ |
| 996 | RTW_WRITE8(regs, RTW_9346CR, |
| 997 | (ecr & ~RTW_9346CR_EEM_MASK) | RTW_9346CR_EEM_NORMAL); |
| 998 | RTW_WBRW(regs, RTW_9346CR, RTW_9346CR); |
| 999 | |
| 1000 | if ((rc = rtw_recall_eeprom(regs, dev)) != 0) |
| 1001 | return rc; |
| 1002 | |
| 1003 | #ifdef RTW_DEBUG |
| 1004 | { |
| 1005 | int i; |
| 1006 | RTW_DPRINTF(RTW_DEBUG_ATTACH, |
| 1007 | ("\n%s: serial ROM:\n\t" , device_xname(dev))); |
| 1008 | for (i = 0; i < sr->sr_size/2; i++) { |
| 1009 | if (((i % 8) == 0) && (i != 0)) |
| 1010 | RTW_DPRINTF(RTW_DEBUG_ATTACH, ("\n\t" )); |
| 1011 | RTW_DPRINTF(RTW_DEBUG_ATTACH, |
| 1012 | (" %04x" , sr->sr_content[i])); |
| 1013 | } |
| 1014 | RTW_DPRINTF(RTW_DEBUG_ATTACH, ("\n" )); |
| 1015 | } |
| 1016 | #endif /* RTW_DEBUG */ |
| 1017 | return 0; |
| 1018 | } |
| 1019 | |
| 1020 | static void |
| 1021 | rtw_set_rfprog(struct rtw_regs *regs, enum rtw_rfchipid rfchipid, |
| 1022 | device_t dev) |
| 1023 | { |
| 1024 | uint8_t cfg4; |
| 1025 | const char *method; |
| 1026 | |
| 1027 | cfg4 = RTW_READ8(regs, RTW_CONFIG4) & ~RTW_CONFIG4_RFTYPE_MASK; |
| 1028 | |
| 1029 | switch (rfchipid) { |
| 1030 | default: |
| 1031 | cfg4 |= __SHIFTIN(rtw_rfprog_fallback, RTW_CONFIG4_RFTYPE_MASK); |
| 1032 | method = "fallback" ; |
| 1033 | break; |
| 1034 | case RTW_RFCHIPID_INTERSIL: |
| 1035 | cfg4 |= RTW_CONFIG4_RFTYPE_INTERSIL; |
| 1036 | method = "Intersil" ; |
| 1037 | break; |
| 1038 | case RTW_RFCHIPID_PHILIPS: |
| 1039 | cfg4 |= RTW_CONFIG4_RFTYPE_PHILIPS; |
| 1040 | method = "Philips" ; |
| 1041 | break; |
| 1042 | case RTW_RFCHIPID_GCT: /* XXX a guess */ |
| 1043 | case RTW_RFCHIPID_RFMD: |
| 1044 | cfg4 |= RTW_CONFIG4_RFTYPE_RFMD; |
| 1045 | method = "RFMD" ; |
| 1046 | break; |
| 1047 | } |
| 1048 | |
| 1049 | RTW_WRITE8(regs, RTW_CONFIG4, cfg4); |
| 1050 | |
| 1051 | RTW_WBR(regs, RTW_CONFIG4, RTW_CONFIG4); |
| 1052 | |
| 1053 | #ifdef RTW_DEBUG |
| 1054 | RTW_DPRINTF(RTW_DEBUG_INIT, |
| 1055 | ("%s: %s RF programming method, %#02x\n" , device_xname(dev), method, |
| 1056 | RTW_READ8(regs, RTW_CONFIG4))); |
| 1057 | #else |
| 1058 | __USE(method); |
| 1059 | #endif |
| 1060 | } |
| 1061 | |
| 1062 | static inline void |
| 1063 | rtw_init_channels(enum rtw_locale locale, |
| 1064 | struct ieee80211_channel (*chans)[IEEE80211_CHAN_MAX+1], device_t dev) |
| 1065 | { |
| 1066 | int i; |
| 1067 | const char *name = NULL; |
| 1068 | #define ADD_CHANNEL(_chans, _chan) do { \ |
| 1069 | (*_chans)[_chan].ic_flags = IEEE80211_CHAN_B; \ |
| 1070 | (*_chans)[_chan].ic_freq = \ |
| 1071 | ieee80211_ieee2mhz(_chan, (*_chans)[_chan].ic_flags);\ |
| 1072 | } while (0) |
| 1073 | |
| 1074 | switch (locale) { |
| 1075 | case RTW_LOCALE_USA: /* 1-11 */ |
| 1076 | name = "USA" ; |
| 1077 | for (i = 1; i <= 11; i++) |
| 1078 | ADD_CHANNEL(chans, i); |
| 1079 | break; |
| 1080 | case RTW_LOCALE_JAPAN: /* 1-14 */ |
| 1081 | name = "Japan" ; |
| 1082 | ADD_CHANNEL(chans, 14); |
| 1083 | for (i = 1; i <= 14; i++) |
| 1084 | ADD_CHANNEL(chans, i); |
| 1085 | break; |
| 1086 | case RTW_LOCALE_EUROPE: /* 1-13 */ |
| 1087 | name = "Europe" ; |
| 1088 | for (i = 1; i <= 13; i++) |
| 1089 | ADD_CHANNEL(chans, i); |
| 1090 | break; |
| 1091 | default: /* 10-11 allowed by most countries */ |
| 1092 | name = "<unknown>" ; |
| 1093 | for (i = 10; i <= 11; i++) |
| 1094 | ADD_CHANNEL(chans, i); |
| 1095 | break; |
| 1096 | } |
| 1097 | aprint_normal_dev(dev, "Geographic Location %s\n" , name); |
| 1098 | #undef ADD_CHANNEL |
| 1099 | } |
| 1100 | |
| 1101 | |
| 1102 | static inline void |
| 1103 | rtw_identify_country(struct rtw_regs *regs, enum rtw_locale *locale) |
| 1104 | { |
| 1105 | uint8_t cfg0 = RTW_READ8(regs, RTW_CONFIG0); |
| 1106 | |
| 1107 | switch (cfg0 & RTW_CONFIG0_GL_MASK) { |
| 1108 | case RTW_CONFIG0_GL_USA: |
| 1109 | case _RTW_CONFIG0_GL_USA: |
| 1110 | *locale = RTW_LOCALE_USA; |
| 1111 | break; |
| 1112 | case RTW_CONFIG0_GL_JAPAN: |
| 1113 | *locale = RTW_LOCALE_JAPAN; |
| 1114 | break; |
| 1115 | case RTW_CONFIG0_GL_EUROPE: |
| 1116 | *locale = RTW_LOCALE_EUROPE; |
| 1117 | break; |
| 1118 | default: |
| 1119 | *locale = RTW_LOCALE_UNKNOWN; |
| 1120 | break; |
| 1121 | } |
| 1122 | } |
| 1123 | |
| 1124 | static inline int |
| 1125 | rtw_identify_sta(struct rtw_regs *regs, uint8_t (*addr)[IEEE80211_ADDR_LEN], |
| 1126 | device_t dev) |
| 1127 | { |
| 1128 | static const uint8_t empty_macaddr[IEEE80211_ADDR_LEN] = { |
| 1129 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 |
| 1130 | }; |
| 1131 | uint32_t idr0 = RTW_READ(regs, RTW_IDR0), |
| 1132 | idr1 = RTW_READ(regs, RTW_IDR1); |
| 1133 | |
| 1134 | (*addr)[0] = __SHIFTOUT(idr0, __BITS(0, 7)); |
| 1135 | (*addr)[1] = __SHIFTOUT(idr0, __BITS(8, 15)); |
| 1136 | (*addr)[2] = __SHIFTOUT(idr0, __BITS(16, 23)); |
| 1137 | (*addr)[3] = __SHIFTOUT(idr0, __BITS(24 ,31)); |
| 1138 | |
| 1139 | (*addr)[4] = __SHIFTOUT(idr1, __BITS(0, 7)); |
| 1140 | (*addr)[5] = __SHIFTOUT(idr1, __BITS(8, 15)); |
| 1141 | |
| 1142 | if (IEEE80211_ADDR_EQ(addr, empty_macaddr)) { |
| 1143 | aprint_error_dev(dev, |
| 1144 | "could not get mac address, attach failed\n" ); |
| 1145 | return ENXIO; |
| 1146 | } |
| 1147 | |
| 1148 | aprint_normal_dev(dev, "802.11 address %s\n" , ether_sprintf(*addr)); |
| 1149 | |
| 1150 | return 0; |
| 1151 | } |
| 1152 | |
| 1153 | static uint8_t |
| 1154 | rtw_chan2txpower(struct rtw_srom *sr, struct ieee80211com *ic, |
| 1155 | struct ieee80211_channel *chan) |
| 1156 | { |
| 1157 | u_int idx = RTW_SR_TXPOWER1 + ieee80211_chan2ieee(ic, chan) - 1; |
| 1158 | KASSERT(idx >= RTW_SR_TXPOWER1 && idx <= RTW_SR_TXPOWER14); |
| 1159 | return RTW_SR_GET(sr, idx); |
| 1160 | } |
| 1161 | |
| 1162 | static void |
| 1163 | rtw_txdesc_blk_init_all(struct rtw_txdesc_blk *tdb) |
| 1164 | { |
| 1165 | int pri; |
| 1166 | /* nfree: the number of free descriptors in each ring. |
| 1167 | * The beacon ring is a special case: I do not let the |
| 1168 | * driver use all of the descriptors on the beacon ring. |
| 1169 | * The reasons are two-fold: |
| 1170 | * |
| 1171 | * (1) A BEACON descriptor's OWN bit is (apparently) not |
| 1172 | * updated, so the driver cannot easily know if the descriptor |
| 1173 | * belongs to it, or if it is racing the NIC. If the NIC |
| 1174 | * does not OWN every descriptor, then the driver can safely |
| 1175 | * update the descriptors when RTW_TBDA points at tdb_next. |
| 1176 | * |
| 1177 | * (2) I hope that the NIC will process more than one BEACON |
| 1178 | * descriptor in a single beacon interval, since that will |
| 1179 | * enable multiple-BSS support. Since the NIC does not |
| 1180 | * clear the OWN bit, there is no natural place for it to |
| 1181 | * stop processing BEACON desciptors. Maybe it will *not* |
| 1182 | * stop processing them! I do not want to chance the NIC |
| 1183 | * looping around and around a saturated beacon ring, so |
| 1184 | * I will leave one descriptor unOWNed at all times. |
| 1185 | */ |
| 1186 | u_int nfree[RTW_NTXPRI] = |
| 1187 | {RTW_NTXDESCLO, RTW_NTXDESCMD, RTW_NTXDESCHI, |
| 1188 | RTW_NTXDESCBCN - 1}; |
| 1189 | |
| 1190 | for (pri = 0; pri < RTW_NTXPRI; pri++) { |
| 1191 | tdb[pri].tdb_nfree = nfree[pri]; |
| 1192 | tdb[pri].tdb_next = 0; |
| 1193 | } |
| 1194 | } |
| 1195 | |
| 1196 | static int |
| 1197 | rtw_txsoft_blk_init(struct rtw_txsoft_blk *tsb) |
| 1198 | { |
| 1199 | int i; |
| 1200 | struct rtw_txsoft *ts; |
| 1201 | |
| 1202 | SIMPLEQ_INIT(&tsb->tsb_dirtyq); |
| 1203 | SIMPLEQ_INIT(&tsb->tsb_freeq); |
| 1204 | for (i = 0; i < tsb->tsb_ndesc; i++) { |
| 1205 | ts = &tsb->tsb_desc[i]; |
| 1206 | ts->ts_mbuf = NULL; |
| 1207 | SIMPLEQ_INSERT_TAIL(&tsb->tsb_freeq, ts, ts_q); |
| 1208 | } |
| 1209 | tsb->tsb_tx_timer = 0; |
| 1210 | return 0; |
| 1211 | } |
| 1212 | |
| 1213 | static void |
| 1214 | rtw_txsoft_blk_init_all(struct rtw_txsoft_blk *tsb) |
| 1215 | { |
| 1216 | int pri; |
| 1217 | for (pri = 0; pri < RTW_NTXPRI; pri++) |
| 1218 | rtw_txsoft_blk_init(&tsb[pri]); |
| 1219 | } |
| 1220 | |
| 1221 | static inline void |
| 1222 | rtw_rxdescs_sync(struct rtw_rxdesc_blk *rdb, int desc0, int nsync, int ops) |
| 1223 | { |
| 1224 | KASSERT(nsync <= rdb->rdb_ndesc); |
| 1225 | /* sync to end of ring */ |
| 1226 | if (desc0 + nsync > rdb->rdb_ndesc) { |
| 1227 | bus_dmamap_sync(rdb->rdb_dmat, rdb->rdb_dmamap, |
| 1228 | offsetof(struct rtw_descs, hd_rx[desc0]), |
| 1229 | sizeof(struct rtw_rxdesc) * (rdb->rdb_ndesc - desc0), ops); |
| 1230 | nsync -= (rdb->rdb_ndesc - desc0); |
| 1231 | desc0 = 0; |
| 1232 | } |
| 1233 | |
| 1234 | KASSERT(desc0 < rdb->rdb_ndesc); |
| 1235 | KASSERT(nsync <= rdb->rdb_ndesc); |
| 1236 | KASSERT(desc0 + nsync <= rdb->rdb_ndesc); |
| 1237 | |
| 1238 | /* sync what remains */ |
| 1239 | bus_dmamap_sync(rdb->rdb_dmat, rdb->rdb_dmamap, |
| 1240 | offsetof(struct rtw_descs, hd_rx[desc0]), |
| 1241 | sizeof(struct rtw_rxdesc) * nsync, ops); |
| 1242 | } |
| 1243 | |
| 1244 | static void |
| 1245 | rtw_txdescs_sync(struct rtw_txdesc_blk *tdb, u_int desc0, u_int nsync, int ops) |
| 1246 | { |
| 1247 | /* sync to end of ring */ |
| 1248 | if (desc0 + nsync > tdb->tdb_ndesc) { |
| 1249 | bus_dmamap_sync(tdb->tdb_dmat, tdb->tdb_dmamap, |
| 1250 | tdb->tdb_ofs + sizeof(struct rtw_txdesc) * desc0, |
| 1251 | sizeof(struct rtw_txdesc) * (tdb->tdb_ndesc - desc0), |
| 1252 | ops); |
| 1253 | nsync -= (tdb->tdb_ndesc - desc0); |
| 1254 | desc0 = 0; |
| 1255 | } |
| 1256 | |
| 1257 | /* sync what remains */ |
| 1258 | bus_dmamap_sync(tdb->tdb_dmat, tdb->tdb_dmamap, |
| 1259 | tdb->tdb_ofs + sizeof(struct rtw_txdesc) * desc0, |
| 1260 | sizeof(struct rtw_txdesc) * nsync, ops); |
| 1261 | } |
| 1262 | |
| 1263 | static void |
| 1264 | rtw_txdescs_sync_all(struct rtw_txdesc_blk *tdb) |
| 1265 | { |
| 1266 | int pri; |
| 1267 | for (pri = 0; pri < RTW_NTXPRI; pri++) { |
| 1268 | rtw_txdescs_sync(&tdb[pri], 0, tdb[pri].tdb_ndesc, |
| 1269 | BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); |
| 1270 | } |
| 1271 | } |
| 1272 | |
| 1273 | static void |
| 1274 | rtw_rxbufs_release(bus_dma_tag_t dmat, struct rtw_rxsoft *desc) |
| 1275 | { |
| 1276 | int i; |
| 1277 | struct rtw_rxsoft *rs; |
| 1278 | |
| 1279 | for (i = 0; i < RTW_RXQLEN; i++) { |
| 1280 | rs = &desc[i]; |
| 1281 | if (rs->rs_mbuf == NULL) |
| 1282 | continue; |
| 1283 | bus_dmamap_sync(dmat, rs->rs_dmamap, 0, |
| 1284 | rs->rs_dmamap->dm_mapsize, BUS_DMASYNC_POSTREAD); |
| 1285 | bus_dmamap_unload(dmat, rs->rs_dmamap); |
| 1286 | m_freem(rs->rs_mbuf); |
| 1287 | rs->rs_mbuf = NULL; |
| 1288 | } |
| 1289 | } |
| 1290 | |
| 1291 | static inline int |
| 1292 | rtw_rxsoft_alloc(bus_dma_tag_t dmat, struct rtw_rxsoft *rs) |
| 1293 | { |
| 1294 | int rc; |
| 1295 | struct mbuf *m; |
| 1296 | |
| 1297 | MGETHDR(m, M_DONTWAIT, MT_DATA); |
| 1298 | if (m == NULL) |
| 1299 | return ENOBUFS; |
| 1300 | |
| 1301 | MCLGET(m, M_DONTWAIT); |
| 1302 | if ((m->m_flags & M_EXT) == 0) { |
| 1303 | m_freem(m); |
| 1304 | return ENOBUFS; |
| 1305 | } |
| 1306 | |
| 1307 | m->m_pkthdr.len = m->m_len = m->m_ext.ext_size; |
| 1308 | |
| 1309 | if (rs->rs_mbuf != NULL) |
| 1310 | bus_dmamap_unload(dmat, rs->rs_dmamap); |
| 1311 | |
| 1312 | rs->rs_mbuf = NULL; |
| 1313 | |
| 1314 | rc = bus_dmamap_load_mbuf(dmat, rs->rs_dmamap, m, BUS_DMA_NOWAIT); |
| 1315 | if (rc != 0) { |
| 1316 | m_freem(m); |
| 1317 | return -1; |
| 1318 | } |
| 1319 | |
| 1320 | rs->rs_mbuf = m; |
| 1321 | |
| 1322 | return 0; |
| 1323 | } |
| 1324 | |
| 1325 | static int |
| 1326 | rtw_rxsoft_init_all(bus_dma_tag_t dmat, struct rtw_rxsoft *desc, |
| 1327 | int *ndesc, device_t dev) |
| 1328 | { |
| 1329 | int i, rc = 0; |
| 1330 | struct rtw_rxsoft *rs; |
| 1331 | |
| 1332 | for (i = 0; i < RTW_RXQLEN; i++) { |
| 1333 | rs = &desc[i]; |
| 1334 | /* we're in rtw_init, so there should be no mbufs allocated */ |
| 1335 | KASSERT(rs->rs_mbuf == NULL); |
| 1336 | #ifdef RTW_DEBUG |
| 1337 | if (i == rtw_rxbufs_limit) { |
| 1338 | aprint_error_dev(dev, "TEST hit %d-buffer limit\n" , i); |
| 1339 | rc = ENOBUFS; |
| 1340 | break; |
| 1341 | } |
| 1342 | #endif /* RTW_DEBUG */ |
| 1343 | if ((rc = rtw_rxsoft_alloc(dmat, rs)) != 0) { |
| 1344 | aprint_error_dev(dev, |
| 1345 | "rtw_rxsoft_alloc failed, %d buffers, rc %d\n" , |
| 1346 | i, rc); |
| 1347 | break; |
| 1348 | } |
| 1349 | } |
| 1350 | *ndesc = i; |
| 1351 | return rc; |
| 1352 | } |
| 1353 | |
| 1354 | static inline void |
| 1355 | rtw_rxdesc_init(struct rtw_rxdesc_blk *rdb, struct rtw_rxsoft *rs, |
| 1356 | int idx, int kick) |
| 1357 | { |
| 1358 | int is_last = (idx == rdb->rdb_ndesc - 1); |
| 1359 | uint32_t ctl, octl, obuf; |
| 1360 | struct rtw_rxdesc *rd = &rdb->rdb_desc[idx]; |
| 1361 | |
| 1362 | /* sync the mbuf before the descriptor */ |
| 1363 | bus_dmamap_sync(rdb->rdb_dmat, rs->rs_dmamap, 0, |
| 1364 | rs->rs_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD); |
| 1365 | |
| 1366 | obuf = rd->rd_buf; |
| 1367 | rd->rd_buf = htole32(rs->rs_dmamap->dm_segs[0].ds_addr); |
| 1368 | |
| 1369 | ctl = __SHIFTIN(rs->rs_mbuf->m_len, RTW_RXCTL_LENGTH_MASK) | |
| 1370 | RTW_RXCTL_OWN | RTW_RXCTL_FS | RTW_RXCTL_LS; |
| 1371 | |
| 1372 | if (is_last) |
| 1373 | ctl |= RTW_RXCTL_EOR; |
| 1374 | |
| 1375 | octl = rd->rd_ctl; |
| 1376 | rd->rd_ctl = htole32(ctl); |
| 1377 | |
| 1378 | #ifdef RTW_DEBUG |
| 1379 | RTW_DPRINTF( |
| 1380 | kick ? (RTW_DEBUG_RECV_DESC | RTW_DEBUG_IO_KICK) |
| 1381 | : RTW_DEBUG_RECV_DESC, |
| 1382 | ("%s: rd %p buf %08x -> %08x ctl %08x -> %08x\n" , __func__, rd, |
| 1383 | le32toh(obuf), le32toh(rd->rd_buf), le32toh(octl), |
| 1384 | le32toh(rd->rd_ctl))); |
| 1385 | #else |
| 1386 | __USE(octl); |
| 1387 | __USE(obuf); |
| 1388 | #endif |
| 1389 | |
| 1390 | /* sync the descriptor */ |
| 1391 | bus_dmamap_sync(rdb->rdb_dmat, rdb->rdb_dmamap, |
| 1392 | RTW_DESC_OFFSET(hd_rx, idx), sizeof(struct rtw_rxdesc), |
| 1393 | BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); |
| 1394 | } |
| 1395 | |
| 1396 | static void |
| 1397 | rtw_rxdesc_init_all(struct rtw_rxdesc_blk *rdb, struct rtw_rxsoft *ctl, int kick) |
| 1398 | { |
| 1399 | int i; |
| 1400 | struct rtw_rxsoft *rs; |
| 1401 | |
| 1402 | for (i = 0; i < rdb->rdb_ndesc; i++) { |
| 1403 | rs = &ctl[i]; |
| 1404 | rtw_rxdesc_init(rdb, rs, i, kick); |
| 1405 | } |
| 1406 | } |
| 1407 | |
| 1408 | static void |
| 1409 | rtw_io_enable(struct rtw_softc *sc, uint8_t flags, int enable) |
| 1410 | { |
| 1411 | struct rtw_regs *regs = &sc->sc_regs; |
| 1412 | uint8_t cr; |
| 1413 | |
| 1414 | RTW_DPRINTF(RTW_DEBUG_IOSTATE, ("%s: %s 0x%02x\n" , __func__, |
| 1415 | enable ? "enable" : "disable" , flags)); |
| 1416 | |
| 1417 | cr = RTW_READ8(regs, RTW_CR); |
| 1418 | |
| 1419 | /* XXX reference source does not enable MULRW */ |
| 1420 | /* enable PCI Read/Write Multiple */ |
| 1421 | cr |= RTW_CR_MULRW; |
| 1422 | |
| 1423 | /* The receive engine will always start at RDSAR. */ |
| 1424 | if (enable && (flags & ~cr & RTW_CR_RE)) { |
| 1425 | struct rtw_rxdesc_blk *rdb; |
| 1426 | rdb = &sc->sc_rxdesc_blk; |
| 1427 | rdb->rdb_next = 0; |
| 1428 | } |
| 1429 | |
| 1430 | RTW_RBW(regs, RTW_CR, RTW_CR); /* XXX paranoia? */ |
| 1431 | if (enable) |
| 1432 | cr |= flags; |
| 1433 | else |
| 1434 | cr &= ~flags; |
| 1435 | RTW_WRITE8(regs, RTW_CR, cr); |
| 1436 | RTW_SYNC(regs, RTW_CR, RTW_CR); |
| 1437 | |
| 1438 | #ifdef RTW_DIAG |
| 1439 | if (cr & RTW_CR_TE) |
| 1440 | rtw_txring_fixup(sc, __func__, __LINE__); |
| 1441 | #endif |
| 1442 | if (cr & RTW_CR_TE) { |
| 1443 | rtw_tx_kick(&sc->sc_regs, |
| 1444 | RTW_TPPOLL_HPQ | RTW_TPPOLL_NPQ | RTW_TPPOLL_LPQ); |
| 1445 | } |
| 1446 | } |
| 1447 | |
| 1448 | static void |
| 1449 | rtw_intr_rx(struct rtw_softc *sc, uint16_t isr) |
| 1450 | { |
| 1451 | #define IS_BEACON(__fc0) \ |
| 1452 | ((__fc0 & (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) ==\ |
| 1453 | (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_BEACON)) |
| 1454 | |
| 1455 | static const int ratetbl[4] = {2, 4, 11, 22}; /* convert rates: |
| 1456 | * hardware -> net80211 |
| 1457 | */ |
| 1458 | u_int next, nproc = 0; |
| 1459 | int hwrate, len, rate, , sq; |
| 1460 | uint32_t , hstat, htsfth, htsftl; |
| 1461 | struct rtw_rxdesc *rd; |
| 1462 | struct rtw_rxsoft *rs; |
| 1463 | struct rtw_rxdesc_blk *rdb; |
| 1464 | struct mbuf *m; |
| 1465 | struct ifnet *ifp = &sc->sc_if; |
| 1466 | |
| 1467 | struct ieee80211_node *ni; |
| 1468 | struct ieee80211_frame_min *wh; |
| 1469 | |
| 1470 | rdb = &sc->sc_rxdesc_blk; |
| 1471 | |
| 1472 | for (next = rdb->rdb_next; ; next = rdb->rdb_next) { |
| 1473 | KASSERT(next < rdb->rdb_ndesc); |
| 1474 | |
| 1475 | rtw_rxdescs_sync(rdb, next, 1, |
| 1476 | BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); |
| 1477 | rd = &rdb->rdb_desc[next]; |
| 1478 | rs = &sc->sc_rxsoft[next]; |
| 1479 | |
| 1480 | hstat = le32toh(rd->rd_stat); |
| 1481 | hrssi = le32toh(rd->rd_rssi); |
| 1482 | htsfth = le32toh(rd->rd_tsfth); |
| 1483 | htsftl = le32toh(rd->rd_tsftl); |
| 1484 | |
| 1485 | RTW_DPRINTF(RTW_DEBUG_RECV_DESC, |
| 1486 | ("%s: rxdesc[%d] hstat %08x hrssi %08x htsft %08x%08x\n" , |
| 1487 | __func__, next, hstat, hrssi, htsfth, htsftl)); |
| 1488 | |
| 1489 | ++nproc; |
| 1490 | |
| 1491 | /* still belongs to NIC */ |
| 1492 | if ((hstat & RTW_RXSTAT_OWN) != 0) { |
| 1493 | rtw_rxdescs_sync(rdb, next, 1, BUS_DMASYNC_PREREAD); |
| 1494 | break; |
| 1495 | } |
| 1496 | |
| 1497 | /* ieee80211_input() might reset the receive engine |
| 1498 | * (e.g. by indirectly calling rtw_tune()), so save |
| 1499 | * the next pointer here and retrieve it again on |
| 1500 | * the next round. |
| 1501 | */ |
| 1502 | rdb->rdb_next = (next + 1) % rdb->rdb_ndesc; |
| 1503 | |
| 1504 | #ifdef RTW_DEBUG |
| 1505 | #define PRINTSTAT(flag) do { \ |
| 1506 | if ((hstat & flag) != 0) { \ |
| 1507 | printf("%s" #flag, delim); \ |
| 1508 | delim = ","; \ |
| 1509 | } \ |
| 1510 | } while (0) |
| 1511 | if ((rtw_debug & RTW_DEBUG_RECV_DESC) != 0) { |
| 1512 | const char *delim = "<" ; |
| 1513 | printf("%s: " , device_xname(sc->sc_dev)); |
| 1514 | if ((hstat & RTW_RXSTAT_DEBUG) != 0) { |
| 1515 | printf("status %08x" , hstat); |
| 1516 | PRINTSTAT(RTW_RXSTAT_SPLCP); |
| 1517 | PRINTSTAT(RTW_RXSTAT_MAR); |
| 1518 | PRINTSTAT(RTW_RXSTAT_PAR); |
| 1519 | PRINTSTAT(RTW_RXSTAT_BAR); |
| 1520 | PRINTSTAT(RTW_RXSTAT_PWRMGT); |
| 1521 | PRINTSTAT(RTW_RXSTAT_CRC32); |
| 1522 | PRINTSTAT(RTW_RXSTAT_ICV); |
| 1523 | printf(">, " ); |
| 1524 | } |
| 1525 | } |
| 1526 | #endif /* RTW_DEBUG */ |
| 1527 | |
| 1528 | if ((hstat & RTW_RXSTAT_IOERROR) != 0) { |
| 1529 | aprint_error_dev(sc->sc_dev, |
| 1530 | "DMA error/FIFO overflow %08" PRIx32 ", " |
| 1531 | "rx descriptor %d\n" , hstat, next); |
| 1532 | ifp->if_ierrors++; |
| 1533 | goto next; |
| 1534 | } |
| 1535 | |
| 1536 | len = __SHIFTOUT(hstat, RTW_RXSTAT_LENGTH_MASK); |
| 1537 | if (len < IEEE80211_MIN_LEN) { |
| 1538 | sc->sc_ic.ic_stats.is_rx_tooshort++; |
| 1539 | goto next; |
| 1540 | } |
| 1541 | if (len > rs->rs_mbuf->m_len) { |
| 1542 | aprint_error_dev(sc->sc_dev, |
| 1543 | "rx frame too long, %d > %d, %08" PRIx32 |
| 1544 | ", desc %d\n" , |
| 1545 | len, rs->rs_mbuf->m_len, hstat, next); |
| 1546 | ifp->if_ierrors++; |
| 1547 | goto next; |
| 1548 | } |
| 1549 | |
| 1550 | hwrate = __SHIFTOUT(hstat, RTW_RXSTAT_RATE_MASK); |
| 1551 | if (hwrate >= __arraycount(ratetbl)) { |
| 1552 | aprint_error_dev(sc->sc_dev, |
| 1553 | "unknown rate #%" __PRIuBITS "\n" , |
| 1554 | __SHIFTOUT(hstat, RTW_RXSTAT_RATE_MASK)); |
| 1555 | ifp->if_ierrors++; |
| 1556 | goto next; |
| 1557 | } |
| 1558 | rate = ratetbl[hwrate]; |
| 1559 | |
| 1560 | #ifdef RTW_DEBUG |
| 1561 | RTW_DPRINTF(RTW_DEBUG_RECV_DESC, |
| 1562 | ("rate %d.%d Mb/s, time %08x%08x\n" , (rate * 5) / 10, |
| 1563 | (rate * 5) % 10, htsfth, htsftl)); |
| 1564 | #endif /* RTW_DEBUG */ |
| 1565 | |
| 1566 | /* if bad flags, skip descriptor */ |
| 1567 | if ((hstat & RTW_RXSTAT_ONESEG) != RTW_RXSTAT_ONESEG) { |
| 1568 | aprint_error_dev(sc->sc_dev, "too many rx segments, " |
| 1569 | "next=%d, %08" PRIx32 "\n" , next, hstat); |
| 1570 | goto next; |
| 1571 | } |
| 1572 | |
| 1573 | bus_dmamap_sync(sc->sc_dmat, rs->rs_dmamap, 0, |
| 1574 | rs->rs_dmamap->dm_mapsize, BUS_DMASYNC_POSTREAD); |
| 1575 | |
| 1576 | m = rs->rs_mbuf; |
| 1577 | |
| 1578 | /* if temporarily out of memory, re-use mbuf */ |
| 1579 | switch (rtw_rxsoft_alloc(sc->sc_dmat, rs)) { |
| 1580 | case 0: |
| 1581 | break; |
| 1582 | case ENOBUFS: |
| 1583 | aprint_error_dev(sc->sc_dev, |
| 1584 | "rtw_rxsoft_alloc(, %d) failed, dropping packet\n" , |
| 1585 | next); |
| 1586 | goto next; |
| 1587 | default: |
| 1588 | /* XXX shorten rx ring, instead? */ |
| 1589 | aprint_error_dev(sc->sc_dev, |
| 1590 | "could not load DMA map\n" ); |
| 1591 | } |
| 1592 | |
| 1593 | sq = __SHIFTOUT(hrssi, RTW_RXRSSI_SQ); |
| 1594 | |
| 1595 | if (sc->sc_rfchipid == RTW_RFCHIPID_PHILIPS) |
| 1596 | rssi = UINT8_MAX - sq; |
| 1597 | else { |
| 1598 | rssi = __SHIFTOUT(hrssi, RTW_RXRSSI_IMR_RSSI); |
| 1599 | /* TBD find out each front-end's LNA gain in the |
| 1600 | * front-end's units |
| 1601 | */ |
| 1602 | if ((hrssi & RTW_RXRSSI_IMR_LNA) == 0) |
| 1603 | rssi |= 0x80; |
| 1604 | } |
| 1605 | |
| 1606 | /* Note well: now we cannot recycle the rs_mbuf unless |
| 1607 | * we restore its original length. |
| 1608 | */ |
| 1609 | m_set_rcvif(m, ifp); |
| 1610 | m->m_pkthdr.len = m->m_len = len; |
| 1611 | |
| 1612 | wh = mtod(m, struct ieee80211_frame_min *); |
| 1613 | |
| 1614 | if (!IS_BEACON(wh->i_fc[0])) |
| 1615 | sc->sc_led_state.ls_event |= RTW_LED_S_RX; |
| 1616 | |
| 1617 | sc->sc_tsfth = htsfth; |
| 1618 | |
| 1619 | #ifdef RTW_DEBUG |
| 1620 | if ((ifp->if_flags & (IFF_DEBUG|IFF_LINK2)) == |
| 1621 | (IFF_DEBUG|IFF_LINK2)) { |
| 1622 | ieee80211_dump_pkt(mtod(m, uint8_t *), m->m_pkthdr.len, |
| 1623 | rate, rssi); |
| 1624 | } |
| 1625 | #endif /* RTW_DEBUG */ |
| 1626 | |
| 1627 | if (sc->sc_radiobpf != NULL) { |
| 1628 | struct rtw_rx_radiotap_header *rr = &sc->sc_rxtap; |
| 1629 | |
| 1630 | rr->rr_tsft = |
| 1631 | htole64(((uint64_t)htsfth << 32) | htsftl); |
| 1632 | |
| 1633 | rr->rr_flags = IEEE80211_RADIOTAP_F_FCS; |
| 1634 | |
| 1635 | if ((hstat & RTW_RXSTAT_SPLCP) != 0) |
| 1636 | rr->rr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; |
| 1637 | if ((hstat & RTW_RXSTAT_CRC32) != 0) |
| 1638 | rr->rr_flags |= IEEE80211_RADIOTAP_F_BADFCS; |
| 1639 | |
| 1640 | rr->rr_rate = rate; |
| 1641 | |
| 1642 | if (sc->sc_rfchipid == RTW_RFCHIPID_PHILIPS) |
| 1643 | rr->rr_u.u_philips.p_antsignal = rssi; |
| 1644 | else { |
| 1645 | rr->rr_u.u_other.o_antsignal = rssi; |
| 1646 | rr->rr_u.u_other.o_barker_lock = |
| 1647 | htole16(UINT8_MAX - sq); |
| 1648 | } |
| 1649 | |
| 1650 | bpf_mtap2(sc->sc_radiobpf, |
| 1651 | rr, sizeof(sc->sc_rxtapu), m); |
| 1652 | } |
| 1653 | |
| 1654 | if ((hstat & RTW_RXSTAT_RES) != 0) { |
| 1655 | m_freem(m); |
| 1656 | goto next; |
| 1657 | } |
| 1658 | |
| 1659 | /* CRC is included with the packet; trim it off. */ |
| 1660 | m_adj(m, -IEEE80211_CRC_LEN); |
| 1661 | |
| 1662 | /* TBD use _MAR, _BAR, _PAR flags as hints to _find_rxnode? */ |
| 1663 | ni = ieee80211_find_rxnode(&sc->sc_ic, wh); |
| 1664 | ieee80211_input(&sc->sc_ic, m, ni, rssi, htsftl); |
| 1665 | ieee80211_free_node(ni); |
| 1666 | next: |
| 1667 | rtw_rxdesc_init(rdb, rs, next, 0); |
| 1668 | } |
| 1669 | #undef IS_BEACON |
| 1670 | } |
| 1671 | |
| 1672 | static void |
| 1673 | rtw_txsoft_release(bus_dma_tag_t dmat, struct ieee80211com *ic, |
| 1674 | struct rtw_txsoft *ts) |
| 1675 | { |
| 1676 | struct mbuf *m; |
| 1677 | struct ieee80211_node *ni; |
| 1678 | |
| 1679 | m = ts->ts_mbuf; |
| 1680 | ni = ts->ts_ni; |
| 1681 | KASSERT(m != NULL); |
| 1682 | KASSERT(ni != NULL); |
| 1683 | ts->ts_mbuf = NULL; |
| 1684 | ts->ts_ni = NULL; |
| 1685 | |
| 1686 | bus_dmamap_sync(dmat, ts->ts_dmamap, 0, ts->ts_dmamap->dm_mapsize, |
| 1687 | BUS_DMASYNC_POSTWRITE); |
| 1688 | bus_dmamap_unload(dmat, ts->ts_dmamap); |
| 1689 | m_freem(m); |
| 1690 | ieee80211_free_node(ni); |
| 1691 | } |
| 1692 | |
| 1693 | static void |
| 1694 | rtw_txsofts_release(bus_dma_tag_t dmat, struct ieee80211com *ic, |
| 1695 | struct rtw_txsoft_blk *tsb) |
| 1696 | { |
| 1697 | struct rtw_txsoft *ts; |
| 1698 | |
| 1699 | while ((ts = SIMPLEQ_FIRST(&tsb->tsb_dirtyq)) != NULL) { |
| 1700 | rtw_txsoft_release(dmat, ic, ts); |
| 1701 | SIMPLEQ_REMOVE_HEAD(&tsb->tsb_dirtyq, ts_q); |
| 1702 | SIMPLEQ_INSERT_TAIL(&tsb->tsb_freeq, ts, ts_q); |
| 1703 | } |
| 1704 | tsb->tsb_tx_timer = 0; |
| 1705 | } |
| 1706 | |
| 1707 | static inline void |
| 1708 | rtw_collect_txpkt(struct rtw_softc *sc, struct rtw_txdesc_blk *tdb, |
| 1709 | struct rtw_txsoft *ts, int ndesc) |
| 1710 | { |
| 1711 | uint32_t hstat; |
| 1712 | int data_retry, rts_retry; |
| 1713 | struct rtw_txdesc *tdn; |
| 1714 | const char *condstring; |
| 1715 | struct ifnet *ifp = &sc->sc_if; |
| 1716 | |
| 1717 | rtw_txsoft_release(sc->sc_dmat, &sc->sc_ic, ts); |
| 1718 | |
| 1719 | tdb->tdb_nfree += ndesc; |
| 1720 | |
| 1721 | tdn = &tdb->tdb_desc[ts->ts_last]; |
| 1722 | |
| 1723 | hstat = le32toh(tdn->td_stat); |
| 1724 | rts_retry = __SHIFTOUT(hstat, RTW_TXSTAT_RTSRETRY_MASK); |
| 1725 | data_retry = __SHIFTOUT(hstat, RTW_TXSTAT_DRC_MASK); |
| 1726 | |
| 1727 | ifp->if_collisions += rts_retry + data_retry; |
| 1728 | |
| 1729 | if ((hstat & RTW_TXSTAT_TOK) != 0) |
| 1730 | condstring = "ok" ; |
| 1731 | else { |
| 1732 | ifp->if_oerrors++; |
| 1733 | condstring = "error" ; |
| 1734 | } |
| 1735 | |
| 1736 | #ifdef RTW_DEBUG |
| 1737 | DPRINTF(sc, RTW_DEBUG_XMIT_DESC, |
| 1738 | ("%s: ts %p txdesc[%d, %d] %s tries rts %u data %u\n" , |
| 1739 | device_xname(sc->sc_dev), ts, ts->ts_first, ts->ts_last, |
| 1740 | condstring, rts_retry, data_retry)); |
| 1741 | #else |
| 1742 | __USE(condstring); |
| 1743 | #endif |
| 1744 | } |
| 1745 | |
| 1746 | static void |
| 1747 | rtw_reset_oactive(struct rtw_softc *sc) |
| 1748 | { |
| 1749 | short oflags; |
| 1750 | int pri; |
| 1751 | struct rtw_txsoft_blk *tsb; |
| 1752 | struct rtw_txdesc_blk *tdb; |
| 1753 | oflags = sc->sc_if.if_flags; |
| 1754 | for (pri = 0; pri < RTW_NTXPRI; pri++) { |
| 1755 | tsb = &sc->sc_txsoft_blk[pri]; |
| 1756 | tdb = &sc->sc_txdesc_blk[pri]; |
| 1757 | if (!SIMPLEQ_EMPTY(&tsb->tsb_freeq) && tdb->tdb_nfree > 0) |
| 1758 | sc->sc_if.if_flags &= ~IFF_OACTIVE; |
| 1759 | } |
| 1760 | if (oflags != sc->sc_if.if_flags) { |
| 1761 | DPRINTF(sc, RTW_DEBUG_OACTIVE, |
| 1762 | ("%s: reset OACTIVE\n" , __func__)); |
| 1763 | } |
| 1764 | } |
| 1765 | |
| 1766 | /* Collect transmitted packets. */ |
| 1767 | static bool |
| 1768 | rtw_collect_txring(struct rtw_softc *sc, struct rtw_txsoft_blk *tsb, |
| 1769 | struct rtw_txdesc_blk *tdb, int force) |
| 1770 | { |
| 1771 | bool collected = false; |
| 1772 | int ndesc; |
| 1773 | struct rtw_txsoft *ts; |
| 1774 | |
| 1775 | #ifdef RTW_DEBUG |
| 1776 | rtw_dump_rings(sc); |
| 1777 | #endif |
| 1778 | |
| 1779 | while ((ts = SIMPLEQ_FIRST(&tsb->tsb_dirtyq)) != NULL) { |
| 1780 | /* If we're clearing a failed transmission, only clear |
| 1781 | up to the last packet the hardware has processed. */ |
| 1782 | if (ts->ts_first == rtw_txring_next(&sc->sc_regs, tdb)) |
| 1783 | break; |
| 1784 | |
| 1785 | ndesc = 1 + ts->ts_last - ts->ts_first; |
| 1786 | if (ts->ts_last < ts->ts_first) |
| 1787 | ndesc += tdb->tdb_ndesc; |
| 1788 | |
| 1789 | KASSERT(ndesc > 0); |
| 1790 | |
| 1791 | rtw_txdescs_sync(tdb, ts->ts_first, ndesc, |
| 1792 | BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); |
| 1793 | |
| 1794 | if (force) { |
| 1795 | int next; |
| 1796 | #ifdef RTW_DIAG |
| 1797 | printf("%s: clearing packet, stats" , __func__); |
| 1798 | #endif |
| 1799 | for (next = ts->ts_first; ; |
| 1800 | next = RTW_NEXT_IDX(tdb, next)) { |
| 1801 | #ifdef RTW_DIAG |
| 1802 | printf(" %" PRIx32 "/%" PRIx32 "/%" PRIx32 "/%" PRIu32 "/%" PRIx32, le32toh(tdb->tdb_desc[next].td_stat), le32toh(tdb->tdb_desc[next].td_ctl1), le32toh(tdb->tdb_desc[next].td_buf), le32toh(tdb->tdb_desc[next].td_len), le32toh(tdb->tdb_desc[next].td_next)); |
| 1803 | #endif |
| 1804 | tdb->tdb_desc[next].td_stat &= |
| 1805 | ~htole32(RTW_TXSTAT_OWN); |
| 1806 | if (next == ts->ts_last) |
| 1807 | break; |
| 1808 | } |
| 1809 | rtw_txdescs_sync(tdb, ts->ts_first, ndesc, |
| 1810 | BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); |
| 1811 | #ifdef RTW_DIAG |
| 1812 | next = RTW_NEXT_IDX(tdb, next); |
| 1813 | printf(" -> end %u stat %" PRIx32 ", was %u\n" , next, |
| 1814 | le32toh(tdb->tdb_desc[next].td_stat), |
| 1815 | rtw_txring_next(&sc->sc_regs, tdb)); |
| 1816 | #endif |
| 1817 | } else if ((tdb->tdb_desc[ts->ts_last].td_stat & |
| 1818 | htole32(RTW_TXSTAT_OWN)) != 0) { |
| 1819 | rtw_txdescs_sync(tdb, ts->ts_last, 1, |
| 1820 | BUS_DMASYNC_PREREAD); |
| 1821 | break; |
| 1822 | } |
| 1823 | |
| 1824 | collected = true; |
| 1825 | |
| 1826 | rtw_collect_txpkt(sc, tdb, ts, ndesc); |
| 1827 | SIMPLEQ_REMOVE_HEAD(&tsb->tsb_dirtyq, ts_q); |
| 1828 | SIMPLEQ_INSERT_TAIL(&tsb->tsb_freeq, ts, ts_q); |
| 1829 | } |
| 1830 | |
| 1831 | /* no more pending transmissions, cancel watchdog */ |
| 1832 | if (ts == NULL) |
| 1833 | tsb->tsb_tx_timer = 0; |
| 1834 | rtw_reset_oactive(sc); |
| 1835 | |
| 1836 | return collected; |
| 1837 | } |
| 1838 | |
| 1839 | static void |
| 1840 | rtw_intr_tx(struct rtw_softc *sc, uint16_t isr) |
| 1841 | { |
| 1842 | int pri; |
| 1843 | struct rtw_txsoft_blk *tsb; |
| 1844 | struct rtw_txdesc_blk *tdb; |
| 1845 | struct ifnet *ifp = &sc->sc_if; |
| 1846 | |
| 1847 | for (pri = 0; pri < RTW_NTXPRI; pri++) { |
| 1848 | tsb = &sc->sc_txsoft_blk[pri]; |
| 1849 | tdb = &sc->sc_txdesc_blk[pri]; |
| 1850 | rtw_collect_txring(sc, tsb, tdb, 0); |
| 1851 | } |
| 1852 | |
| 1853 | if ((isr & RTW_INTR_TX) != 0) |
| 1854 | rtw_start(ifp); |
| 1855 | |
| 1856 | return; |
| 1857 | } |
| 1858 | |
| 1859 | static void |
| 1860 | rtw_intr_beacon(struct rtw_softc *sc, uint16_t isr) |
| 1861 | { |
| 1862 | u_int next; |
| 1863 | uint32_t tsfth, tsftl; |
| 1864 | struct ieee80211com *ic; |
| 1865 | struct rtw_txdesc_blk *tdb = &sc->sc_txdesc_blk[RTW_TXPRIBCN]; |
| 1866 | struct rtw_txsoft_blk *tsb = &sc->sc_txsoft_blk[RTW_TXPRIBCN]; |
| 1867 | struct mbuf *m; |
| 1868 | |
| 1869 | tsfth = RTW_READ(&sc->sc_regs, RTW_TSFTRH); |
| 1870 | tsftl = RTW_READ(&sc->sc_regs, RTW_TSFTRL); |
| 1871 | |
| 1872 | if ((isr & (RTW_INTR_TBDOK|RTW_INTR_TBDER)) != 0) { |
| 1873 | next = rtw_txring_next(&sc->sc_regs, tdb); |
| 1874 | #ifdef RTW_DEBUG |
| 1875 | RTW_DPRINTF(RTW_DEBUG_BEACON, |
| 1876 | ("%s: beacon ring %sprocessed, isr = %#04" PRIx16 |
| 1877 | ", next %u expected %u, %" PRIu64 "\n" , __func__, |
| 1878 | (next == tdb->tdb_next) ? "" : "un" , isr, next, |
| 1879 | tdb->tdb_next, (uint64_t)tsfth << 32 | tsftl)); |
| 1880 | #else |
| 1881 | __USE(next); |
| 1882 | __USE(tsfth); |
| 1883 | __USE(tsftl); |
| 1884 | #endif |
| 1885 | if ((RTW_READ8(&sc->sc_regs, RTW_TPPOLL) & RTW_TPPOLL_BQ) == 0) |
| 1886 | rtw_collect_txring(sc, tsb, tdb, 1); |
| 1887 | } |
| 1888 | /* Start beacon transmission. */ |
| 1889 | |
| 1890 | if ((isr & RTW_INTR_BCNINT) != 0 && |
| 1891 | sc->sc_ic.ic_state == IEEE80211_S_RUN && |
| 1892 | SIMPLEQ_EMPTY(&tsb->tsb_dirtyq)) { |
| 1893 | RTW_DPRINTF(RTW_DEBUG_BEACON, |
| 1894 | ("%s: beacon prep. time, isr = %#04" PRIx16 |
| 1895 | ", %16" PRIu64 "\n" , __func__, isr, |
| 1896 | (uint64_t)tsfth << 32 | tsftl)); |
| 1897 | ic = &sc->sc_ic; |
| 1898 | m = rtw_beacon_alloc(sc, ic->ic_bss); |
| 1899 | |
| 1900 | if (m == NULL) { |
| 1901 | aprint_error_dev(sc->sc_dev, |
| 1902 | "could not allocate beacon\n" ); |
| 1903 | return; |
| 1904 | } |
| 1905 | M_SETCTX(m, ieee80211_ref_node(ic->ic_bss)); |
| 1906 | IF_ENQUEUE(&sc->sc_beaconq, m); |
| 1907 | rtw_start(&sc->sc_if); |
| 1908 | } |
| 1909 | } |
| 1910 | |
| 1911 | static void |
| 1912 | rtw_intr_atim(struct rtw_softc *sc) |
| 1913 | { |
| 1914 | /* TBD */ |
| 1915 | return; |
| 1916 | } |
| 1917 | |
| 1918 | #ifdef RTW_DEBUG |
| 1919 | static void |
| 1920 | rtw_dump_rings(struct rtw_softc *sc) |
| 1921 | { |
| 1922 | struct rtw_txdesc_blk *tdb; |
| 1923 | struct rtw_rxdesc *rd; |
| 1924 | struct rtw_rxdesc_blk *rdb; |
| 1925 | int desc, pri; |
| 1926 | |
| 1927 | if ((rtw_debug & RTW_DEBUG_IO_KICK) == 0) |
| 1928 | return; |
| 1929 | |
| 1930 | for (pri = 0; pri < RTW_NTXPRI; pri++) { |
| 1931 | tdb = &sc->sc_txdesc_blk[pri]; |
| 1932 | printf("%s: txpri %d ndesc %d nfree %d\n" , __func__, pri, |
| 1933 | tdb->tdb_ndesc, tdb->tdb_nfree); |
| 1934 | for (desc = 0; desc < tdb->tdb_ndesc; desc++) |
| 1935 | rtw_print_txdesc(sc, "." , NULL, tdb, desc); |
| 1936 | } |
| 1937 | |
| 1938 | rdb = &sc->sc_rxdesc_blk; |
| 1939 | |
| 1940 | for (desc = 0; desc < RTW_RXQLEN; desc++) { |
| 1941 | rd = &rdb->rdb_desc[desc]; |
| 1942 | printf("%s: %sctl %08x rsvd0/rssi %08x buf/tsftl %08x " |
| 1943 | "rsvd1/tsfth %08x\n" , __func__, |
| 1944 | (desc >= rdb->rdb_ndesc) ? "UNUSED " : "" , |
| 1945 | le32toh(rd->rd_ctl), le32toh(rd->rd_rssi), |
| 1946 | le32toh(rd->rd_buf), le32toh(rd->rd_tsfth)); |
| 1947 | } |
| 1948 | } |
| 1949 | #endif /* RTW_DEBUG */ |
| 1950 | |
| 1951 | static void |
| 1952 | rtw_hwring_setup(struct rtw_softc *sc) |
| 1953 | { |
| 1954 | int pri; |
| 1955 | struct rtw_regs *regs = &sc->sc_regs; |
| 1956 | struct rtw_txdesc_blk *tdb; |
| 1957 | |
| 1958 | sc->sc_txdesc_blk[RTW_TXPRILO].tdb_basereg = RTW_TLPDA; |
| 1959 | sc->sc_txdesc_blk[RTW_TXPRILO].tdb_base = RTW_RING_BASE(sc, hd_txlo); |
| 1960 | sc->sc_txdesc_blk[RTW_TXPRIMD].tdb_basereg = RTW_TNPDA; |
| 1961 | sc->sc_txdesc_blk[RTW_TXPRIMD].tdb_base = RTW_RING_BASE(sc, hd_txmd); |
| 1962 | sc->sc_txdesc_blk[RTW_TXPRIHI].tdb_basereg = RTW_THPDA; |
| 1963 | sc->sc_txdesc_blk[RTW_TXPRIHI].tdb_base = RTW_RING_BASE(sc, hd_txhi); |
| 1964 | sc->sc_txdesc_blk[RTW_TXPRIBCN].tdb_basereg = RTW_TBDA; |
| 1965 | sc->sc_txdesc_blk[RTW_TXPRIBCN].tdb_base = RTW_RING_BASE(sc, hd_bcn); |
| 1966 | |
| 1967 | for (pri = 0; pri < RTW_NTXPRI; pri++) { |
| 1968 | tdb = &sc->sc_txdesc_blk[pri]; |
| 1969 | RTW_WRITE(regs, tdb->tdb_basereg, tdb->tdb_base); |
| 1970 | RTW_DPRINTF(RTW_DEBUG_XMIT_DESC, |
| 1971 | ("%s: reg[tdb->tdb_basereg] <- %" PRIxPTR "\n" , __func__, |
| 1972 | (uintptr_t)tdb->tdb_base)); |
| 1973 | } |
| 1974 | |
| 1975 | RTW_WRITE(regs, RTW_RDSAR, RTW_RING_BASE(sc, hd_rx)); |
| 1976 | |
| 1977 | RTW_DPRINTF(RTW_DEBUG_RECV_DESC, |
| 1978 | ("%s: reg[RDSAR] <- %" PRIxPTR "\n" , __func__, |
| 1979 | (uintptr_t)RTW_RING_BASE(sc, hd_rx))); |
| 1980 | |
| 1981 | RTW_SYNC(regs, RTW_TLPDA, RTW_RDSAR); |
| 1982 | |
| 1983 | } |
| 1984 | |
| 1985 | static int |
| 1986 | rtw_swring_setup(struct rtw_softc *sc) |
| 1987 | { |
| 1988 | int rc; |
| 1989 | struct rtw_rxdesc_blk *rdb; |
| 1990 | |
| 1991 | rtw_txdesc_blk_init_all(&sc->sc_txdesc_blk[0]); |
| 1992 | |
| 1993 | rtw_txsoft_blk_init_all(&sc->sc_txsoft_blk[0]); |
| 1994 | |
| 1995 | rdb = &sc->sc_rxdesc_blk; |
| 1996 | if ((rc = rtw_rxsoft_init_all(sc->sc_dmat, sc->sc_rxsoft, &rdb->rdb_ndesc, |
| 1997 | sc->sc_dev)) != 0 && rdb->rdb_ndesc == 0) { |
| 1998 | aprint_error_dev(sc->sc_dev, "could not allocate rx buffers\n" ); |
| 1999 | return rc; |
| 2000 | } |
| 2001 | |
| 2002 | rdb = &sc->sc_rxdesc_blk; |
| 2003 | rtw_rxdescs_sync(rdb, 0, rdb->rdb_ndesc, |
| 2004 | BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); |
| 2005 | rtw_rxdesc_init_all(rdb, sc->sc_rxsoft, 1); |
| 2006 | rdb->rdb_next = 0; |
| 2007 | |
| 2008 | rtw_txdescs_sync_all(&sc->sc_txdesc_blk[0]); |
| 2009 | return 0; |
| 2010 | } |
| 2011 | |
| 2012 | static void |
| 2013 | rtw_txdesc_blk_init(struct rtw_txdesc_blk *tdb) |
| 2014 | { |
| 2015 | int i; |
| 2016 | |
| 2017 | (void)memset(tdb->tdb_desc, 0, |
| 2018 | sizeof(tdb->tdb_desc[0]) * tdb->tdb_ndesc); |
| 2019 | for (i = 0; i < tdb->tdb_ndesc; i++) |
| 2020 | tdb->tdb_desc[i].td_next = htole32(RTW_NEXT_DESC(tdb, i)); |
| 2021 | } |
| 2022 | |
| 2023 | static u_int |
| 2024 | rtw_txring_next(struct rtw_regs *regs, struct rtw_txdesc_blk *tdb) |
| 2025 | { |
| 2026 | return (le32toh(RTW_READ(regs, tdb->tdb_basereg)) - tdb->tdb_base) / |
| 2027 | sizeof(struct rtw_txdesc); |
| 2028 | } |
| 2029 | |
| 2030 | #ifdef RTW_DIAG |
| 2031 | static void |
| 2032 | rtw_txring_fixup(struct rtw_softc *sc, const char *fn, int ln) |
| 2033 | { |
| 2034 | int pri; |
| 2035 | u_int next; |
| 2036 | struct rtw_txdesc_blk *tdb; |
| 2037 | struct rtw_regs *regs = &sc->sc_regs; |
| 2038 | |
| 2039 | for (pri = 0; pri < RTW_NTXPRI; pri++) { |
| 2040 | int i; |
| 2041 | tdb = &sc->sc_txdesc_blk[pri]; |
| 2042 | next = rtw_txring_next(regs, tdb); |
| 2043 | if (tdb->tdb_next == next) |
| 2044 | continue; |
| 2045 | for (i = 0; next != tdb->tdb_next; |
| 2046 | next = RTW_NEXT_IDX(tdb, next), i++) { |
| 2047 | if ((tdb->tdb_desc[next].td_stat & htole32(RTW_TXSTAT_OWN)) == 0) |
| 2048 | break; |
| 2049 | } |
| 2050 | printf("%s:%d: tx-ring %d expected next %u, read %u+%d -> %s\n" , fn, |
| 2051 | ln, pri, tdb->tdb_next, next, i, tdb->tdb_next == next ? "okay" : "BAD" ); |
| 2052 | if (tdb->tdb_next == next) |
| 2053 | continue; |
| 2054 | tdb->tdb_next = MIN(next, tdb->tdb_ndesc - 1); |
| 2055 | } |
| 2056 | } |
| 2057 | #endif |
| 2058 | |
| 2059 | static void |
| 2060 | rtw_txdescs_reset(struct rtw_softc *sc) |
| 2061 | { |
| 2062 | int pri; |
| 2063 | struct rtw_txsoft_blk *tsb; |
| 2064 | struct rtw_txdesc_blk *tdb; |
| 2065 | |
| 2066 | for (pri = 0; pri < RTW_NTXPRI; pri++) { |
| 2067 | tsb = &sc->sc_txsoft_blk[pri]; |
| 2068 | tdb = &sc->sc_txdesc_blk[pri]; |
| 2069 | rtw_collect_txring(sc, tsb, tdb, 1); |
| 2070 | #ifdef RTW_DIAG |
| 2071 | if (!SIMPLEQ_EMPTY(&tsb->tsb_dirtyq)) |
| 2072 | printf("%s: packets left in ring %d\n" , __func__, pri); |
| 2073 | #endif |
| 2074 | } |
| 2075 | } |
| 2076 | |
| 2077 | static void |
| 2078 | rtw_intr_ioerror(struct rtw_softc *sc, uint16_t isr) |
| 2079 | { |
| 2080 | aprint_error_dev(sc->sc_dev, "tx fifo underflow\n" ); |
| 2081 | |
| 2082 | RTW_DPRINTF(RTW_DEBUG_BUGS, ("%s: cleaning up xmit, isr %" PRIx16 |
| 2083 | "\n" , device_xname(sc->sc_dev), isr)); |
| 2084 | |
| 2085 | #ifdef RTW_DEBUG |
| 2086 | rtw_dump_rings(sc); |
| 2087 | #endif /* RTW_DEBUG */ |
| 2088 | |
| 2089 | /* Collect tx'd packets. XXX let's hope this stops the transmit |
| 2090 | * timeouts. |
| 2091 | */ |
| 2092 | rtw_txdescs_reset(sc); |
| 2093 | |
| 2094 | #ifdef RTW_DEBUG |
| 2095 | rtw_dump_rings(sc); |
| 2096 | #endif /* RTW_DEBUG */ |
| 2097 | } |
| 2098 | |
| 2099 | static inline void |
| 2100 | rtw_suspend_ticks(struct rtw_softc *sc) |
| 2101 | { |
| 2102 | RTW_DPRINTF(RTW_DEBUG_TIMEOUT, |
| 2103 | ("%s: suspending ticks\n" , device_xname(sc->sc_dev))); |
| 2104 | sc->sc_do_tick = 0; |
| 2105 | } |
| 2106 | |
| 2107 | static inline void |
| 2108 | rtw_resume_ticks(struct rtw_softc *sc) |
| 2109 | { |
| 2110 | uint32_t tsftrl0, tsftrl1, next_tint; |
| 2111 | |
| 2112 | tsftrl0 = RTW_READ(&sc->sc_regs, RTW_TSFTRL); |
| 2113 | |
| 2114 | tsftrl1 = RTW_READ(&sc->sc_regs, RTW_TSFTRL); |
| 2115 | next_tint = tsftrl1 + 1000000; |
| 2116 | RTW_WRITE(&sc->sc_regs, RTW_TINT, next_tint); |
| 2117 | |
| 2118 | sc->sc_do_tick = 1; |
| 2119 | |
| 2120 | #ifdef RTW_DEBUG |
| 2121 | RTW_DPRINTF(RTW_DEBUG_TIMEOUT, |
| 2122 | ("%s: resume ticks delta %#08x now %#08x next %#08x\n" , |
| 2123 | device_xname(sc->sc_dev), tsftrl1 - tsftrl0, tsftrl1, next_tint)); |
| 2124 | #else |
| 2125 | __USE(tsftrl0); |
| 2126 | #endif |
| 2127 | } |
| 2128 | |
| 2129 | static void |
| 2130 | rtw_intr_timeout(struct rtw_softc *sc) |
| 2131 | { |
| 2132 | RTW_DPRINTF(RTW_DEBUG_TIMEOUT, ("%s: timeout\n" , device_xname(sc->sc_dev))); |
| 2133 | if (sc->sc_do_tick) |
| 2134 | rtw_resume_ticks(sc); |
| 2135 | return; |
| 2136 | } |
| 2137 | |
| 2138 | int |
| 2139 | rtw_intr(void *arg) |
| 2140 | { |
| 2141 | int i; |
| 2142 | struct rtw_softc *sc = arg; |
| 2143 | struct rtw_regs *regs = &sc->sc_regs; |
| 2144 | uint16_t isr; |
| 2145 | struct ifnet *ifp = &sc->sc_if; |
| 2146 | |
| 2147 | /* |
| 2148 | * If the interface isn't running, the interrupt couldn't |
| 2149 | * possibly have come from us. |
| 2150 | */ |
| 2151 | if ((ifp->if_flags & IFF_RUNNING) == 0 || |
| 2152 | !device_activation(sc->sc_dev, DEVACT_LEVEL_DRIVER)) { |
| 2153 | RTW_DPRINTF(RTW_DEBUG_INTR, ("%s: stray interrupt\n" , |
| 2154 | device_xname(sc->sc_dev))); |
| 2155 | return (0); |
| 2156 | } |
| 2157 | |
| 2158 | for (i = 0; i < 10; i++) { |
| 2159 | isr = RTW_READ16(regs, RTW_ISR); |
| 2160 | |
| 2161 | RTW_WRITE16(regs, RTW_ISR, isr); |
| 2162 | RTW_WBR(regs, RTW_ISR, RTW_ISR); |
| 2163 | |
| 2164 | if (sc->sc_intr_ack != NULL) |
| 2165 | (*sc->sc_intr_ack)(regs); |
| 2166 | |
| 2167 | if (isr == 0) |
| 2168 | break; |
| 2169 | |
| 2170 | #ifdef RTW_DEBUG |
| 2171 | #define PRINTINTR(flag) do { \ |
| 2172 | if ((isr & flag) != 0) { \ |
| 2173 | printf("%s" #flag, delim); \ |
| 2174 | delim = ","; \ |
| 2175 | } \ |
| 2176 | } while (0) |
| 2177 | |
| 2178 | if ((rtw_debug & RTW_DEBUG_INTR) != 0 && isr != 0) { |
| 2179 | const char *delim = "<" ; |
| 2180 | |
| 2181 | printf("%s: reg[ISR] = %x" , device_xname(sc->sc_dev), |
| 2182 | isr); |
| 2183 | |
| 2184 | PRINTINTR(RTW_INTR_TXFOVW); |
| 2185 | PRINTINTR(RTW_INTR_TIMEOUT); |
| 2186 | PRINTINTR(RTW_INTR_BCNINT); |
| 2187 | PRINTINTR(RTW_INTR_ATIMINT); |
| 2188 | PRINTINTR(RTW_INTR_TBDER); |
| 2189 | PRINTINTR(RTW_INTR_TBDOK); |
| 2190 | PRINTINTR(RTW_INTR_THPDER); |
| 2191 | PRINTINTR(RTW_INTR_THPDOK); |
| 2192 | PRINTINTR(RTW_INTR_TNPDER); |
| 2193 | PRINTINTR(RTW_INTR_TNPDOK); |
| 2194 | PRINTINTR(RTW_INTR_RXFOVW); |
| 2195 | PRINTINTR(RTW_INTR_RDU); |
| 2196 | PRINTINTR(RTW_INTR_TLPDER); |
| 2197 | PRINTINTR(RTW_INTR_TLPDOK); |
| 2198 | PRINTINTR(RTW_INTR_RER); |
| 2199 | PRINTINTR(RTW_INTR_ROK); |
| 2200 | |
| 2201 | printf(">\n" ); |
| 2202 | } |
| 2203 | #undef PRINTINTR |
| 2204 | #endif /* RTW_DEBUG */ |
| 2205 | |
| 2206 | if ((isr & RTW_INTR_RX) != 0) |
| 2207 | rtw_intr_rx(sc, isr); |
| 2208 | if ((isr & RTW_INTR_TX) != 0) |
| 2209 | rtw_intr_tx(sc, isr); |
| 2210 | if ((isr & RTW_INTR_BEACON) != 0) |
| 2211 | rtw_intr_beacon(sc, isr); |
| 2212 | if ((isr & RTW_INTR_ATIMINT) != 0) |
| 2213 | rtw_intr_atim(sc); |
| 2214 | if ((isr & RTW_INTR_IOERROR) != 0) |
| 2215 | rtw_intr_ioerror(sc, isr); |
| 2216 | if ((isr & RTW_INTR_TIMEOUT) != 0) |
| 2217 | rtw_intr_timeout(sc); |
| 2218 | } |
| 2219 | |
| 2220 | return 1; |
| 2221 | } |
| 2222 | |
| 2223 | /* Must be called at splnet. */ |
| 2224 | static void |
| 2225 | rtw_stop(struct ifnet *ifp, int disable) |
| 2226 | { |
| 2227 | int pri; |
| 2228 | struct rtw_softc *sc = (struct rtw_softc *)ifp->if_softc; |
| 2229 | struct ieee80211com *ic = &sc->sc_ic; |
| 2230 | struct rtw_regs *regs = &sc->sc_regs; |
| 2231 | |
| 2232 | rtw_suspend_ticks(sc); |
| 2233 | |
| 2234 | ieee80211_new_state(ic, IEEE80211_S_INIT, -1); |
| 2235 | |
| 2236 | if (device_has_power(sc->sc_dev)) { |
| 2237 | /* Disable interrupts. */ |
| 2238 | RTW_WRITE16(regs, RTW_IMR, 0); |
| 2239 | |
| 2240 | RTW_WBW(regs, RTW_TPPOLL, RTW_IMR); |
| 2241 | |
| 2242 | /* Stop the transmit and receive processes. First stop DMA, |
| 2243 | * then disable receiver and transmitter. |
| 2244 | */ |
| 2245 | RTW_WRITE8(regs, RTW_TPPOLL, RTW_TPPOLL_SALL); |
| 2246 | |
| 2247 | RTW_SYNC(regs, RTW_TPPOLL, RTW_IMR); |
| 2248 | |
| 2249 | rtw_io_enable(sc, RTW_CR_RE | RTW_CR_TE, 0); |
| 2250 | } |
| 2251 | |
| 2252 | for (pri = 0; pri < RTW_NTXPRI; pri++) { |
| 2253 | rtw_txsofts_release(sc->sc_dmat, &sc->sc_ic, |
| 2254 | &sc->sc_txsoft_blk[pri]); |
| 2255 | } |
| 2256 | |
| 2257 | rtw_rxbufs_release(sc->sc_dmat, &sc->sc_rxsoft[0]); |
| 2258 | |
| 2259 | /* Mark the interface as not running. Cancel the watchdog timer. */ |
| 2260 | ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); |
| 2261 | ifp->if_timer = 0; |
| 2262 | |
| 2263 | if (disable) |
| 2264 | pmf_device_suspend(sc->sc_dev, &sc->sc_qual); |
| 2265 | |
| 2266 | return; |
| 2267 | } |
| 2268 | |
| 2269 | const char * |
| 2270 | rtw_pwrstate_string(enum rtw_pwrstate power) |
| 2271 | { |
| 2272 | switch (power) { |
| 2273 | case RTW_ON: |
| 2274 | return "on" ; |
| 2275 | case RTW_SLEEP: |
| 2276 | return "sleep" ; |
| 2277 | case RTW_OFF: |
| 2278 | return "off" ; |
| 2279 | default: |
| 2280 | return "unknown" ; |
| 2281 | } |
| 2282 | } |
| 2283 | |
| 2284 | /* XXX For Maxim, I am using the RFMD settings gleaned from the |
| 2285 | * reference driver, plus a magic Maxim "ON" value that comes from |
| 2286 | * the Realtek document "Windows PG for Rtl8180." |
| 2287 | */ |
| 2288 | static void |
| 2289 | rtw_maxim_pwrstate(struct rtw_regs *regs, enum rtw_pwrstate power, |
| 2290 | int before_rf, int digphy) |
| 2291 | { |
| 2292 | uint32_t anaparm; |
| 2293 | |
| 2294 | anaparm = RTW_READ(regs, RTW_ANAPARM); |
| 2295 | anaparm &= ~(RTW_ANAPARM_RFPOW_MASK | RTW_ANAPARM_TXDACOFF); |
| 2296 | |
| 2297 | switch (power) { |
| 2298 | case RTW_OFF: |
| 2299 | if (before_rf) |
| 2300 | return; |
| 2301 | anaparm |= RTW_ANAPARM_RFPOW_MAXIM_OFF; |
| 2302 | anaparm |= RTW_ANAPARM_TXDACOFF; |
| 2303 | break; |
| 2304 | case RTW_SLEEP: |
| 2305 | if (!before_rf) |
| 2306 | return; |
| 2307 | anaparm |= RTW_ANAPARM_RFPOW_MAXIM_SLEEP; |
| 2308 | anaparm |= RTW_ANAPARM_TXDACOFF; |
| 2309 | break; |
| 2310 | case RTW_ON: |
| 2311 | if (!before_rf) |
| 2312 | return; |
| 2313 | anaparm |= RTW_ANAPARM_RFPOW_MAXIM_ON; |
| 2314 | break; |
| 2315 | } |
| 2316 | RTW_DPRINTF(RTW_DEBUG_PWR, |
| 2317 | ("%s: power state %s, %s RF, reg[ANAPARM] <- %08x\n" , |
| 2318 | __func__, rtw_pwrstate_string(power), |
| 2319 | (before_rf) ? "before" : "after" , anaparm)); |
| 2320 | |
| 2321 | RTW_WRITE(regs, RTW_ANAPARM, anaparm); |
| 2322 | RTW_SYNC(regs, RTW_ANAPARM, RTW_ANAPARM); |
| 2323 | } |
| 2324 | |
| 2325 | /* XXX I am using the RFMD settings gleaned from the reference |
| 2326 | * driver. They agree |
| 2327 | */ |
| 2328 | static void |
| 2329 | rtw_rfmd_pwrstate(struct rtw_regs *regs, enum rtw_pwrstate power, |
| 2330 | int before_rf, int digphy) |
| 2331 | { |
| 2332 | uint32_t anaparm; |
| 2333 | |
| 2334 | anaparm = RTW_READ(regs, RTW_ANAPARM); |
| 2335 | anaparm &= ~(RTW_ANAPARM_RFPOW_MASK | RTW_ANAPARM_TXDACOFF); |
| 2336 | |
| 2337 | switch (power) { |
| 2338 | case RTW_OFF: |
| 2339 | if (before_rf) |
| 2340 | return; |
| 2341 | anaparm |= RTW_ANAPARM_RFPOW_RFMD_OFF; |
| 2342 | anaparm |= RTW_ANAPARM_TXDACOFF; |
| 2343 | break; |
| 2344 | case RTW_SLEEP: |
| 2345 | if (!before_rf) |
| 2346 | return; |
| 2347 | anaparm |= RTW_ANAPARM_RFPOW_RFMD_SLEEP; |
| 2348 | anaparm |= RTW_ANAPARM_TXDACOFF; |
| 2349 | break; |
| 2350 | case RTW_ON: |
| 2351 | if (!before_rf) |
| 2352 | return; |
| 2353 | anaparm |= RTW_ANAPARM_RFPOW_RFMD_ON; |
| 2354 | break; |
| 2355 | } |
| 2356 | RTW_DPRINTF(RTW_DEBUG_PWR, |
| 2357 | ("%s: power state %s, %s RF, reg[ANAPARM] <- %08x\n" , |
| 2358 | __func__, rtw_pwrstate_string(power), |
| 2359 | (before_rf) ? "before" : "after" , anaparm)); |
| 2360 | |
| 2361 | RTW_WRITE(regs, RTW_ANAPARM, anaparm); |
| 2362 | RTW_SYNC(regs, RTW_ANAPARM, RTW_ANAPARM); |
| 2363 | } |
| 2364 | |
| 2365 | static void |
| 2366 | rtw_philips_pwrstate(struct rtw_regs *regs, enum rtw_pwrstate power, |
| 2367 | int before_rf, int digphy) |
| 2368 | { |
| 2369 | uint32_t anaparm; |
| 2370 | |
| 2371 | anaparm = RTW_READ(regs, RTW_ANAPARM); |
| 2372 | anaparm &= ~(RTW_ANAPARM_RFPOW_MASK | RTW_ANAPARM_TXDACOFF); |
| 2373 | |
| 2374 | switch (power) { |
| 2375 | case RTW_OFF: |
| 2376 | if (before_rf) |
| 2377 | return; |
| 2378 | anaparm |= RTW_ANAPARM_RFPOW_PHILIPS_OFF; |
| 2379 | anaparm |= RTW_ANAPARM_TXDACOFF; |
| 2380 | break; |
| 2381 | case RTW_SLEEP: |
| 2382 | if (!before_rf) |
| 2383 | return; |
| 2384 | anaparm |= RTW_ANAPARM_RFPOW_PHILIPS_SLEEP; |
| 2385 | anaparm |= RTW_ANAPARM_TXDACOFF; |
| 2386 | break; |
| 2387 | case RTW_ON: |
| 2388 | if (!before_rf) |
| 2389 | return; |
| 2390 | if (digphy) { |
| 2391 | anaparm |= RTW_ANAPARM_RFPOW_DIG_PHILIPS_ON; |
| 2392 | /* XXX guess */ |
| 2393 | anaparm |= RTW_ANAPARM_TXDACOFF; |
| 2394 | } else |
| 2395 | anaparm |= RTW_ANAPARM_RFPOW_ANA_PHILIPS_ON; |
| 2396 | break; |
| 2397 | } |
| 2398 | RTW_DPRINTF(RTW_DEBUG_PWR, |
| 2399 | ("%s: power state %s, %s RF, reg[ANAPARM] <- %08x\n" , |
| 2400 | __func__, rtw_pwrstate_string(power), |
| 2401 | (before_rf) ? "before" : "after" , anaparm)); |
| 2402 | |
| 2403 | RTW_WRITE(regs, RTW_ANAPARM, anaparm); |
| 2404 | RTW_SYNC(regs, RTW_ANAPARM, RTW_ANAPARM); |
| 2405 | } |
| 2406 | |
| 2407 | static void |
| 2408 | rtw_pwrstate0(struct rtw_softc *sc, enum rtw_pwrstate power, int before_rf, |
| 2409 | int digphy) |
| 2410 | { |
| 2411 | struct rtw_regs *regs = &sc->sc_regs; |
| 2412 | |
| 2413 | rtw_set_access(regs, RTW_ACCESS_ANAPARM); |
| 2414 | |
| 2415 | (*sc->sc_pwrstate_cb)(regs, power, before_rf, digphy); |
| 2416 | |
| 2417 | rtw_set_access(regs, RTW_ACCESS_NONE); |
| 2418 | |
| 2419 | return; |
| 2420 | } |
| 2421 | |
| 2422 | static int |
| 2423 | rtw_pwrstate(struct rtw_softc *sc, enum rtw_pwrstate power) |
| 2424 | { |
| 2425 | int rc; |
| 2426 | |
| 2427 | RTW_DPRINTF(RTW_DEBUG_PWR, |
| 2428 | ("%s: %s->%s\n" , __func__, |
| 2429 | rtw_pwrstate_string(sc->sc_pwrstate), rtw_pwrstate_string(power))); |
| 2430 | |
| 2431 | if (sc->sc_pwrstate == power) |
| 2432 | return 0; |
| 2433 | |
| 2434 | rtw_pwrstate0(sc, power, 1, sc->sc_flags & RTW_F_DIGPHY); |
| 2435 | rc = rtw_rf_pwrstate(sc->sc_rf, power); |
| 2436 | rtw_pwrstate0(sc, power, 0, sc->sc_flags & RTW_F_DIGPHY); |
| 2437 | |
| 2438 | switch (power) { |
| 2439 | case RTW_ON: |
| 2440 | /* TBD set LEDs */ |
| 2441 | break; |
| 2442 | case RTW_SLEEP: |
| 2443 | /* TBD */ |
| 2444 | break; |
| 2445 | case RTW_OFF: |
| 2446 | /* TBD */ |
| 2447 | break; |
| 2448 | } |
| 2449 | if (rc == 0) |
| 2450 | sc->sc_pwrstate = power; |
| 2451 | else |
| 2452 | sc->sc_pwrstate = RTW_OFF; |
| 2453 | return rc; |
| 2454 | } |
| 2455 | |
| 2456 | static int |
| 2457 | rtw_tune(struct rtw_softc *sc) |
| 2458 | { |
| 2459 | struct ieee80211com *ic = &sc->sc_ic; |
| 2460 | struct rtw_tx_radiotap_header *rt = &sc->sc_txtap; |
| 2461 | struct rtw_rx_radiotap_header *rr = &sc->sc_rxtap; |
| 2462 | u_int chan; |
| 2463 | int rc; |
| 2464 | int antdiv = sc->sc_flags & RTW_F_ANTDIV, |
| 2465 | dflantb = sc->sc_flags & RTW_F_DFLANTB; |
| 2466 | |
| 2467 | chan = ieee80211_chan2ieee(ic, ic->ic_curchan); |
| 2468 | KASSERT(chan != IEEE80211_CHAN_ANY); |
| 2469 | |
| 2470 | rt->rt_chan_freq = htole16(ic->ic_curchan->ic_freq); |
| 2471 | rt->rt_chan_flags = htole16(ic->ic_curchan->ic_flags); |
| 2472 | |
| 2473 | rr->rr_chan_freq = htole16(ic->ic_curchan->ic_freq); |
| 2474 | rr->rr_chan_flags = htole16(ic->ic_curchan->ic_flags); |
| 2475 | |
| 2476 | if (chan == sc->sc_cur_chan) { |
| 2477 | RTW_DPRINTF(RTW_DEBUG_TUNE, |
| 2478 | ("%s: already tuned chan #%d\n" , __func__, chan)); |
| 2479 | return 0; |
| 2480 | } |
| 2481 | |
| 2482 | rtw_suspend_ticks(sc); |
| 2483 | |
| 2484 | rtw_io_enable(sc, RTW_CR_RE | RTW_CR_TE, 0); |
| 2485 | |
| 2486 | /* TBD wait for Tx to complete */ |
| 2487 | |
| 2488 | KASSERT(device_has_power(sc->sc_dev)); |
| 2489 | |
| 2490 | if ((rc = rtw_phy_init(&sc->sc_regs, sc->sc_rf, |
| 2491 | rtw_chan2txpower(&sc->sc_srom, ic, ic->ic_curchan), sc->sc_csthr, |
| 2492 | ic->ic_curchan->ic_freq, antdiv, dflantb, RTW_ON)) != 0) { |
| 2493 | /* XXX condition on powersaving */ |
| 2494 | aprint_error_dev(sc->sc_dev, "phy init failed\n" ); |
| 2495 | } |
| 2496 | |
| 2497 | sc->sc_cur_chan = chan; |
| 2498 | |
| 2499 | rtw_io_enable(sc, RTW_CR_RE | RTW_CR_TE, 1); |
| 2500 | |
| 2501 | rtw_resume_ticks(sc); |
| 2502 | |
| 2503 | return rc; |
| 2504 | } |
| 2505 | |
| 2506 | bool |
| 2507 | rtw_suspend(device_t self, const pmf_qual_t *qual) |
| 2508 | { |
| 2509 | int rc; |
| 2510 | struct rtw_softc *sc = device_private(self); |
| 2511 | |
| 2512 | sc->sc_flags &= ~RTW_F_DK_VALID; |
| 2513 | |
| 2514 | if (!device_has_power(self)) |
| 2515 | return false; |
| 2516 | |
| 2517 | /* turn off PHY */ |
| 2518 | if ((rc = rtw_pwrstate(sc, RTW_OFF)) != 0) { |
| 2519 | aprint_error_dev(self, "failed to turn off PHY (%d)\n" , rc); |
| 2520 | return false; |
| 2521 | } |
| 2522 | |
| 2523 | rtw_disable_interrupts(&sc->sc_regs); |
| 2524 | |
| 2525 | return true; |
| 2526 | } |
| 2527 | |
| 2528 | bool |
| 2529 | rtw_resume(device_t self, const pmf_qual_t *qual) |
| 2530 | { |
| 2531 | struct rtw_softc *sc = device_private(self); |
| 2532 | |
| 2533 | /* Power may have been removed, resetting WEP keys. |
| 2534 | */ |
| 2535 | sc->sc_flags &= ~RTW_F_DK_VALID; |
| 2536 | rtw_enable_interrupts(sc); |
| 2537 | |
| 2538 | return true; |
| 2539 | } |
| 2540 | |
| 2541 | static void |
| 2542 | rtw_transmit_config(struct rtw_regs *regs) |
| 2543 | { |
| 2544 | uint32_t tcr; |
| 2545 | |
| 2546 | tcr = RTW_READ(regs, RTW_TCR); |
| 2547 | |
| 2548 | tcr |= RTW_TCR_CWMIN; |
| 2549 | tcr &= ~RTW_TCR_MXDMA_MASK; |
| 2550 | tcr |= RTW_TCR_MXDMA_256; |
| 2551 | tcr |= RTW_TCR_SAT; /* send ACK as fast as possible */ |
| 2552 | tcr &= ~RTW_TCR_LBK_MASK; |
| 2553 | tcr |= RTW_TCR_LBK_NORMAL; /* normal operating mode */ |
| 2554 | |
| 2555 | /* set short/long retry limits */ |
| 2556 | tcr &= ~(RTW_TCR_SRL_MASK|RTW_TCR_LRL_MASK); |
| 2557 | tcr |= __SHIFTIN(4, RTW_TCR_SRL_MASK) | __SHIFTIN(4, RTW_TCR_LRL_MASK); |
| 2558 | |
| 2559 | tcr &= ~RTW_TCR_CRC; /* NIC appends CRC32 */ |
| 2560 | |
| 2561 | RTW_WRITE(regs, RTW_TCR, tcr); |
| 2562 | RTW_SYNC(regs, RTW_TCR, RTW_TCR); |
| 2563 | } |
| 2564 | |
| 2565 | static void |
| 2566 | rtw_disable_interrupts(struct rtw_regs *regs) |
| 2567 | { |
| 2568 | RTW_WRITE16(regs, RTW_IMR, 0); |
| 2569 | RTW_WBW(regs, RTW_IMR, RTW_ISR); |
| 2570 | RTW_WRITE16(regs, RTW_ISR, 0xffff); |
| 2571 | RTW_SYNC(regs, RTW_IMR, RTW_ISR); |
| 2572 | } |
| 2573 | |
| 2574 | static void |
| 2575 | rtw_enable_interrupts(struct rtw_softc *sc) |
| 2576 | { |
| 2577 | struct rtw_regs *regs = &sc->sc_regs; |
| 2578 | |
| 2579 | sc->sc_inten = RTW_INTR_RX|RTW_INTR_TX|RTW_INTR_BEACON|RTW_INTR_ATIMINT; |
| 2580 | sc->sc_inten |= RTW_INTR_IOERROR|RTW_INTR_TIMEOUT; |
| 2581 | |
| 2582 | RTW_WRITE16(regs, RTW_IMR, sc->sc_inten); |
| 2583 | RTW_WBW(regs, RTW_IMR, RTW_ISR); |
| 2584 | RTW_WRITE16(regs, RTW_ISR, 0xffff); |
| 2585 | RTW_SYNC(regs, RTW_IMR, RTW_ISR); |
| 2586 | |
| 2587 | /* XXX necessary? */ |
| 2588 | if (sc->sc_intr_ack != NULL) |
| 2589 | (*sc->sc_intr_ack)(regs); |
| 2590 | } |
| 2591 | |
| 2592 | static void |
| 2593 | rtw_set_nettype(struct rtw_softc *sc, enum ieee80211_opmode opmode) |
| 2594 | { |
| 2595 | uint8_t msr; |
| 2596 | |
| 2597 | /* I'm guessing that MSR is protected as CONFIG[0123] are. */ |
| 2598 | rtw_set_access(&sc->sc_regs, RTW_ACCESS_CONFIG); |
| 2599 | |
| 2600 | msr = RTW_READ8(&sc->sc_regs, RTW_MSR) & ~RTW_MSR_NETYPE_MASK; |
| 2601 | |
| 2602 | switch (opmode) { |
| 2603 | case IEEE80211_M_AHDEMO: |
| 2604 | case IEEE80211_M_IBSS: |
| 2605 | msr |= RTW_MSR_NETYPE_ADHOC_OK; |
| 2606 | break; |
| 2607 | case IEEE80211_M_HOSTAP: |
| 2608 | msr |= RTW_MSR_NETYPE_AP_OK; |
| 2609 | break; |
| 2610 | case IEEE80211_M_MONITOR: |
| 2611 | /* XXX */ |
| 2612 | msr |= RTW_MSR_NETYPE_NOLINK; |
| 2613 | break; |
| 2614 | case IEEE80211_M_STA: |
| 2615 | msr |= RTW_MSR_NETYPE_INFRA_OK; |
| 2616 | break; |
| 2617 | } |
| 2618 | RTW_WRITE8(&sc->sc_regs, RTW_MSR, msr); |
| 2619 | |
| 2620 | rtw_set_access(&sc->sc_regs, RTW_ACCESS_NONE); |
| 2621 | } |
| 2622 | |
| 2623 | #define rtw_calchash(addr) \ |
| 2624 | (ether_crc32_be((addr), IEEE80211_ADDR_LEN) >> 26) |
| 2625 | |
| 2626 | static void |
| 2627 | rtw_pktfilt_load(struct rtw_softc *sc) |
| 2628 | { |
| 2629 | struct rtw_regs *regs = &sc->sc_regs; |
| 2630 | struct ieee80211com *ic = &sc->sc_ic; |
| 2631 | struct ethercom *ec = &sc->sc_ec; |
| 2632 | struct ifnet *ifp = &sc->sc_if; |
| 2633 | int hash; |
| 2634 | uint32_t hashes[2] = { 0, 0 }; |
| 2635 | struct ether_multi *enm; |
| 2636 | struct ether_multistep step; |
| 2637 | |
| 2638 | /* XXX might be necessary to stop Rx/Tx engines while setting filters */ |
| 2639 | |
| 2640 | sc->sc_rcr &= ~RTW_RCR_PKTFILTER_MASK; |
| 2641 | sc->sc_rcr &= ~(RTW_RCR_MXDMA_MASK | RTW_RCR_RXFTH_MASK); |
| 2642 | |
| 2643 | sc->sc_rcr |= RTW_RCR_PKTFILTER_DEFAULT; |
| 2644 | /* MAC auto-reset PHY (huh?) */ |
| 2645 | sc->sc_rcr |= RTW_RCR_ENMARP; |
| 2646 | /* DMA whole Rx packets, only. Set Tx DMA burst size to 1024 bytes. */ |
| 2647 | sc->sc_rcr |= RTW_RCR_MXDMA_1024 | RTW_RCR_RXFTH_WHOLE; |
| 2648 | |
| 2649 | switch (ic->ic_opmode) { |
| 2650 | case IEEE80211_M_MONITOR: |
| 2651 | sc->sc_rcr |= RTW_RCR_MONITOR; |
| 2652 | break; |
| 2653 | case IEEE80211_M_AHDEMO: |
| 2654 | case IEEE80211_M_IBSS: |
| 2655 | /* receive broadcasts in our BSS */ |
| 2656 | sc->sc_rcr |= RTW_RCR_ADD3; |
| 2657 | break; |
| 2658 | default: |
| 2659 | break; |
| 2660 | } |
| 2661 | |
| 2662 | ifp->if_flags &= ~IFF_ALLMULTI; |
| 2663 | |
| 2664 | /* |
| 2665 | * Program the 64-bit multicast hash filter. |
| 2666 | */ |
| 2667 | ETHER_FIRST_MULTI(step, ec, enm); |
| 2668 | while (enm != NULL) { |
| 2669 | /* XXX */ |
| 2670 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, |
| 2671 | ETHER_ADDR_LEN) != 0) { |
| 2672 | ifp->if_flags |= IFF_ALLMULTI; |
| 2673 | break; |
| 2674 | } |
| 2675 | |
| 2676 | hash = rtw_calchash(enm->enm_addrlo); |
| 2677 | hashes[hash >> 5] |= (1 << (hash & 0x1f)); |
| 2678 | ETHER_NEXT_MULTI(step, enm); |
| 2679 | } |
| 2680 | |
| 2681 | /* XXX accept all broadcast if scanning */ |
| 2682 | if ((ifp->if_flags & IFF_BROADCAST) != 0) |
| 2683 | sc->sc_rcr |= RTW_RCR_AB; /* accept all broadcast */ |
| 2684 | |
| 2685 | if (ifp->if_flags & IFF_PROMISC) { |
| 2686 | sc->sc_rcr |= RTW_RCR_AB; /* accept all broadcast */ |
| 2687 | sc->sc_rcr |= RTW_RCR_ACRC32; /* accept frames failing CRC */ |
| 2688 | sc->sc_rcr |= RTW_RCR_AICV; /* accept frames failing ICV */ |
| 2689 | ifp->if_flags |= IFF_ALLMULTI; |
| 2690 | } |
| 2691 | |
| 2692 | if (ifp->if_flags & IFF_ALLMULTI) |
| 2693 | hashes[0] = hashes[1] = 0xffffffff; |
| 2694 | |
| 2695 | if ((hashes[0] | hashes[1]) != 0) |
| 2696 | sc->sc_rcr |= RTW_RCR_AM; /* accept multicast */ |
| 2697 | |
| 2698 | RTW_WRITE(regs, RTW_MAR0, hashes[0]); |
| 2699 | RTW_WRITE(regs, RTW_MAR1, hashes[1]); |
| 2700 | RTW_WRITE(regs, RTW_RCR, sc->sc_rcr); |
| 2701 | RTW_SYNC(regs, RTW_MAR0, RTW_RCR); /* RTW_MAR0 < RTW_MAR1 < RTW_RCR */ |
| 2702 | |
| 2703 | DPRINTF(sc, RTW_DEBUG_PKTFILT, |
| 2704 | ("%s: RTW_MAR0 %08x RTW_MAR1 %08x RTW_RCR %08x\n" , |
| 2705 | device_xname(sc->sc_dev), RTW_READ(regs, RTW_MAR0), |
| 2706 | RTW_READ(regs, RTW_MAR1), RTW_READ(regs, RTW_RCR))); |
| 2707 | } |
| 2708 | |
| 2709 | static struct mbuf * |
| 2710 | rtw_beacon_alloc(struct rtw_softc *sc, struct ieee80211_node *ni) |
| 2711 | { |
| 2712 | struct ieee80211com *ic = &sc->sc_ic; |
| 2713 | struct mbuf *m; |
| 2714 | struct ieee80211_beacon_offsets boff; |
| 2715 | |
| 2716 | if ((m = ieee80211_beacon_alloc(ic, ni, &boff)) != NULL) { |
| 2717 | RTW_DPRINTF(RTW_DEBUG_BEACON, |
| 2718 | ("%s: m %p len %u\n" , __func__, m, m->m_len)); |
| 2719 | } |
| 2720 | return m; |
| 2721 | } |
| 2722 | |
| 2723 | /* Must be called at splnet. */ |
| 2724 | static int |
| 2725 | rtw_init(struct ifnet *ifp) |
| 2726 | { |
| 2727 | struct rtw_softc *sc = (struct rtw_softc *)ifp->if_softc; |
| 2728 | struct ieee80211com *ic = &sc->sc_ic; |
| 2729 | struct rtw_regs *regs = &sc->sc_regs; |
| 2730 | int rc; |
| 2731 | |
| 2732 | if (device_is_active(sc->sc_dev)) { |
| 2733 | /* Cancel pending I/O and reset. */ |
| 2734 | rtw_stop(ifp, 0); |
| 2735 | } else if (!pmf_device_resume(sc->sc_dev, &sc->sc_qual) || |
| 2736 | !device_is_active(sc->sc_dev)) |
| 2737 | return 0; |
| 2738 | |
| 2739 | DPRINTF(sc, RTW_DEBUG_TUNE, ("%s: channel %d freq %d flags 0x%04x\n" , |
| 2740 | __func__, ieee80211_chan2ieee(ic, ic->ic_curchan), |
| 2741 | ic->ic_curchan->ic_freq, ic->ic_curchan->ic_flags)); |
| 2742 | |
| 2743 | if ((rc = rtw_pwrstate(sc, RTW_OFF)) != 0) |
| 2744 | goto out; |
| 2745 | |
| 2746 | if ((rc = rtw_swring_setup(sc)) != 0) |
| 2747 | goto out; |
| 2748 | |
| 2749 | rtw_transmit_config(regs); |
| 2750 | |
| 2751 | rtw_set_access(regs, RTW_ACCESS_CONFIG); |
| 2752 | |
| 2753 | RTW_WRITE8(regs, RTW_MSR, 0x0); /* no link */ |
| 2754 | RTW_WBW(regs, RTW_MSR, RTW_BRSR); |
| 2755 | |
| 2756 | /* long PLCP header, 1Mb/2Mb basic rate */ |
| 2757 | RTW_WRITE16(regs, RTW_BRSR, RTW_BRSR_MBR8180_2MBPS); |
| 2758 | RTW_SYNC(regs, RTW_BRSR, RTW_BRSR); |
| 2759 | |
| 2760 | rtw_set_access(regs, RTW_ACCESS_ANAPARM); |
| 2761 | rtw_set_access(regs, RTW_ACCESS_NONE); |
| 2762 | |
| 2763 | /* XXX from reference sources */ |
| 2764 | RTW_WRITE(regs, RTW_FEMR, 0xffff); |
| 2765 | RTW_SYNC(regs, RTW_FEMR, RTW_FEMR); |
| 2766 | |
| 2767 | rtw_set_rfprog(regs, sc->sc_rfchipid, sc->sc_dev); |
| 2768 | |
| 2769 | RTW_WRITE8(regs, RTW_PHYDELAY, sc->sc_phydelay); |
| 2770 | /* from Linux driver */ |
| 2771 | RTW_WRITE8(regs, RTW_CRCOUNT, RTW_CRCOUNT_MAGIC); |
| 2772 | |
| 2773 | RTW_SYNC(regs, RTW_PHYDELAY, RTW_CRCOUNT); |
| 2774 | |
| 2775 | rtw_enable_interrupts(sc); |
| 2776 | |
| 2777 | rtw_pktfilt_load(sc); |
| 2778 | |
| 2779 | rtw_hwring_setup(sc); |
| 2780 | |
| 2781 | rtw_wep_setkeys(sc, ic->ic_nw_keys, ic->ic_def_txkey); |
| 2782 | |
| 2783 | rtw_io_enable(sc, RTW_CR_RE | RTW_CR_TE, 1); |
| 2784 | |
| 2785 | ifp->if_flags |= IFF_RUNNING; |
| 2786 | ic->ic_state = IEEE80211_S_INIT; |
| 2787 | |
| 2788 | RTW_WRITE16(regs, RTW_BSSID16, 0x0); |
| 2789 | RTW_WRITE(regs, RTW_BSSID32, 0x0); |
| 2790 | |
| 2791 | rtw_resume_ticks(sc); |
| 2792 | |
| 2793 | rtw_set_nettype(sc, IEEE80211_M_MONITOR); |
| 2794 | |
| 2795 | if (ic->ic_opmode == IEEE80211_M_MONITOR) |
| 2796 | return ieee80211_new_state(ic, IEEE80211_S_RUN, -1); |
| 2797 | else |
| 2798 | return ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); |
| 2799 | |
| 2800 | out: |
| 2801 | aprint_error_dev(sc->sc_dev, "interface not running\n" ); |
| 2802 | return rc; |
| 2803 | } |
| 2804 | |
| 2805 | static inline void |
| 2806 | rtw_led_init(struct rtw_regs *regs) |
| 2807 | { |
| 2808 | uint8_t cfg0, cfg1; |
| 2809 | |
| 2810 | rtw_set_access(regs, RTW_ACCESS_CONFIG); |
| 2811 | |
| 2812 | cfg0 = RTW_READ8(regs, RTW_CONFIG0); |
| 2813 | cfg0 |= RTW_CONFIG0_LEDGPOEN; |
| 2814 | RTW_WRITE8(regs, RTW_CONFIG0, cfg0); |
| 2815 | |
| 2816 | cfg1 = RTW_READ8(regs, RTW_CONFIG1); |
| 2817 | RTW_DPRINTF(RTW_DEBUG_LED, |
| 2818 | ("%s: read %" PRIx8 " from reg[CONFIG1]\n" , __func__, cfg1)); |
| 2819 | |
| 2820 | cfg1 &= ~RTW_CONFIG1_LEDS_MASK; |
| 2821 | cfg1 |= RTW_CONFIG1_LEDS_TX_RX; |
| 2822 | RTW_WRITE8(regs, RTW_CONFIG1, cfg1); |
| 2823 | |
| 2824 | rtw_set_access(regs, RTW_ACCESS_NONE); |
| 2825 | } |
| 2826 | |
| 2827 | /* |
| 2828 | * IEEE80211_S_INIT: LED1 off |
| 2829 | * |
| 2830 | * IEEE80211_S_AUTH, |
| 2831 | * IEEE80211_S_ASSOC, |
| 2832 | * IEEE80211_S_SCAN: LED1 blinks @ 1 Hz, blinks at 5Hz for tx/rx |
| 2833 | * |
| 2834 | * IEEE80211_S_RUN: LED1 on, blinks @ 5Hz for tx/rx |
| 2835 | */ |
| 2836 | static void |
| 2837 | rtw_led_newstate(struct rtw_softc *sc, enum ieee80211_state nstate) |
| 2838 | { |
| 2839 | struct rtw_led_state *ls; |
| 2840 | |
| 2841 | ls = &sc->sc_led_state; |
| 2842 | |
| 2843 | switch (nstate) { |
| 2844 | case IEEE80211_S_INIT: |
| 2845 | rtw_led_init(&sc->sc_regs); |
| 2846 | aprint_debug_dev(sc->sc_dev, "stopping blink\n" ); |
| 2847 | callout_stop(&ls->ls_slow_ch); |
| 2848 | callout_stop(&ls->ls_fast_ch); |
| 2849 | ls->ls_slowblink = 0; |
| 2850 | ls->ls_actblink = 0; |
| 2851 | ls->ls_default = 0; |
| 2852 | break; |
| 2853 | case IEEE80211_S_SCAN: |
| 2854 | aprint_debug_dev(sc->sc_dev, "scheduling blink\n" ); |
| 2855 | callout_schedule(&ls->ls_slow_ch, RTW_LED_SLOW_TICKS); |
| 2856 | callout_schedule(&ls->ls_fast_ch, RTW_LED_FAST_TICKS); |
| 2857 | /*FALLTHROUGH*/ |
| 2858 | case IEEE80211_S_AUTH: |
| 2859 | case IEEE80211_S_ASSOC: |
| 2860 | ls->ls_default = RTW_LED1; |
| 2861 | ls->ls_actblink = RTW_LED1; |
| 2862 | ls->ls_slowblink = RTW_LED1; |
| 2863 | break; |
| 2864 | case IEEE80211_S_RUN: |
| 2865 | ls->ls_slowblink = 0; |
| 2866 | break; |
| 2867 | } |
| 2868 | rtw_led_set(ls, &sc->sc_regs, sc->sc_hwverid); |
| 2869 | } |
| 2870 | |
| 2871 | static void |
| 2872 | rtw_led_set(struct rtw_led_state *ls, struct rtw_regs *regs, int hwverid) |
| 2873 | { |
| 2874 | uint8_t led_condition; |
| 2875 | bus_size_t ofs; |
| 2876 | uint8_t mask, newval, val; |
| 2877 | |
| 2878 | led_condition = ls->ls_default; |
| 2879 | |
| 2880 | if (ls->ls_state & RTW_LED_S_SLOW) |
| 2881 | led_condition ^= ls->ls_slowblink; |
| 2882 | if (ls->ls_state & (RTW_LED_S_RX|RTW_LED_S_TX)) |
| 2883 | led_condition ^= ls->ls_actblink; |
| 2884 | |
| 2885 | RTW_DPRINTF(RTW_DEBUG_LED, |
| 2886 | ("%s: LED condition %" PRIx8 "\n" , __func__, led_condition)); |
| 2887 | |
| 2888 | switch (hwverid) { |
| 2889 | default: |
| 2890 | case 'F': |
| 2891 | ofs = RTW_PSR; |
| 2892 | newval = mask = RTW_PSR_LEDGPO0 | RTW_PSR_LEDGPO1; |
| 2893 | if (led_condition & RTW_LED0) |
| 2894 | newval &= ~RTW_PSR_LEDGPO0; |
| 2895 | if (led_condition & RTW_LED1) |
| 2896 | newval &= ~RTW_PSR_LEDGPO1; |
| 2897 | break; |
| 2898 | case 'D': |
| 2899 | ofs = RTW_9346CR; |
| 2900 | mask = RTW_9346CR_EEM_MASK | RTW_9346CR_EEDI | RTW_9346CR_EECS; |
| 2901 | newval = RTW_9346CR_EEM_PROGRAM; |
| 2902 | if (led_condition & RTW_LED0) |
| 2903 | newval |= RTW_9346CR_EEDI; |
| 2904 | if (led_condition & RTW_LED1) |
| 2905 | newval |= RTW_9346CR_EECS; |
| 2906 | break; |
| 2907 | } |
| 2908 | val = RTW_READ8(regs, ofs); |
| 2909 | RTW_DPRINTF(RTW_DEBUG_LED, |
| 2910 | ("%s: read %" PRIx8 " from reg[%#02" PRIxPTR "]\n" , __func__, val, |
| 2911 | (uintptr_t)ofs)); |
| 2912 | val &= ~mask; |
| 2913 | val |= newval; |
| 2914 | RTW_WRITE8(regs, ofs, val); |
| 2915 | RTW_DPRINTF(RTW_DEBUG_LED, |
| 2916 | ("%s: wrote %" PRIx8 " to reg[%#02" PRIxPTR "]\n" , __func__, val, |
| 2917 | (uintptr_t)ofs)); |
| 2918 | RTW_SYNC(regs, ofs, ofs); |
| 2919 | } |
| 2920 | |
| 2921 | static void |
| 2922 | rtw_led_fastblink(void *arg) |
| 2923 | { |
| 2924 | int ostate, s; |
| 2925 | struct rtw_softc *sc = (struct rtw_softc *)arg; |
| 2926 | struct rtw_led_state *ls = &sc->sc_led_state; |
| 2927 | |
| 2928 | s = splnet(); |
| 2929 | ostate = ls->ls_state; |
| 2930 | ls->ls_state ^= ls->ls_event; |
| 2931 | |
| 2932 | if ((ls->ls_event & RTW_LED_S_TX) == 0) |
| 2933 | ls->ls_state &= ~RTW_LED_S_TX; |
| 2934 | |
| 2935 | if ((ls->ls_event & RTW_LED_S_RX) == 0) |
| 2936 | ls->ls_state &= ~RTW_LED_S_RX; |
| 2937 | |
| 2938 | ls->ls_event = 0; |
| 2939 | |
| 2940 | if (ostate != ls->ls_state) |
| 2941 | rtw_led_set(ls, &sc->sc_regs, sc->sc_hwverid); |
| 2942 | splx(s); |
| 2943 | |
| 2944 | aprint_debug_dev(sc->sc_dev, "scheduling fast blink\n" ); |
| 2945 | callout_schedule(&ls->ls_fast_ch, RTW_LED_FAST_TICKS); |
| 2946 | } |
| 2947 | |
| 2948 | static void |
| 2949 | rtw_led_slowblink(void *arg) |
| 2950 | { |
| 2951 | int s; |
| 2952 | struct rtw_softc *sc = (struct rtw_softc *)arg; |
| 2953 | struct rtw_led_state *ls = &sc->sc_led_state; |
| 2954 | |
| 2955 | s = splnet(); |
| 2956 | ls->ls_state ^= RTW_LED_S_SLOW; |
| 2957 | rtw_led_set(ls, &sc->sc_regs, sc->sc_hwverid); |
| 2958 | splx(s); |
| 2959 | aprint_debug_dev(sc->sc_dev, "scheduling slow blink\n" ); |
| 2960 | callout_schedule(&ls->ls_slow_ch, RTW_LED_SLOW_TICKS); |
| 2961 | } |
| 2962 | |
| 2963 | static void |
| 2964 | rtw_led_detach(struct rtw_led_state *ls) |
| 2965 | { |
| 2966 | callout_destroy(&ls->ls_fast_ch); |
| 2967 | callout_destroy(&ls->ls_slow_ch); |
| 2968 | } |
| 2969 | |
| 2970 | static void |
| 2971 | rtw_led_attach(struct rtw_led_state *ls, void *arg) |
| 2972 | { |
| 2973 | callout_init(&ls->ls_fast_ch, 0); |
| 2974 | callout_init(&ls->ls_slow_ch, 0); |
| 2975 | callout_setfunc(&ls->ls_fast_ch, rtw_led_fastblink, arg); |
| 2976 | callout_setfunc(&ls->ls_slow_ch, rtw_led_slowblink, arg); |
| 2977 | } |
| 2978 | |
| 2979 | static int |
| 2980 | rtw_ioctl(struct ifnet *ifp, u_long cmd, void *data) |
| 2981 | { |
| 2982 | int rc = 0, s; |
| 2983 | struct rtw_softc *sc = ifp->if_softc; |
| 2984 | |
| 2985 | s = splnet(); |
| 2986 | if (cmd == SIOCSIFFLAGS) { |
| 2987 | if ((rc = ifioctl_common(ifp, cmd, data)) != 0) |
| 2988 | ; |
| 2989 | else switch (ifp->if_flags & (IFF_UP|IFF_RUNNING)) { |
| 2990 | case IFF_UP: |
| 2991 | rc = rtw_init(ifp); |
| 2992 | RTW_PRINT_REGS(&sc->sc_regs, ifp->if_xname, __func__); |
| 2993 | break; |
| 2994 | case IFF_UP|IFF_RUNNING: |
| 2995 | if (device_activation(sc->sc_dev, DEVACT_LEVEL_DRIVER)) |
| 2996 | rtw_pktfilt_load(sc); |
| 2997 | RTW_PRINT_REGS(&sc->sc_regs, ifp->if_xname, __func__); |
| 2998 | break; |
| 2999 | case IFF_RUNNING: |
| 3000 | RTW_PRINT_REGS(&sc->sc_regs, ifp->if_xname, __func__); |
| 3001 | rtw_stop(ifp, 1); |
| 3002 | break; |
| 3003 | default: |
| 3004 | break; |
| 3005 | } |
| 3006 | } else if ((rc = ieee80211_ioctl(&sc->sc_ic, cmd, data)) != ENETRESET) |
| 3007 | ; /* nothing to do */ |
| 3008 | else if (cmd == SIOCADDMULTI || cmd == SIOCDELMULTI) { |
| 3009 | /* reload packet filter if running */ |
| 3010 | if (ifp->if_flags & IFF_RUNNING) |
| 3011 | rtw_pktfilt_load(sc); |
| 3012 | rc = 0; |
| 3013 | } else if ((ifp->if_flags & IFF_UP) != 0) |
| 3014 | rc = rtw_init(ifp); |
| 3015 | else |
| 3016 | rc = 0; |
| 3017 | splx(s); |
| 3018 | return rc; |
| 3019 | } |
| 3020 | |
| 3021 | /* Select a transmit ring with at least one h/w and s/w descriptor free. |
| 3022 | * Return 0 on success, -1 on failure. |
| 3023 | */ |
| 3024 | static inline int |
| 3025 | rtw_txring_choose(struct rtw_softc *sc, struct rtw_txsoft_blk **tsbp, |
| 3026 | struct rtw_txdesc_blk **tdbp, int pri) |
| 3027 | { |
| 3028 | struct rtw_txsoft_blk *tsb; |
| 3029 | struct rtw_txdesc_blk *tdb; |
| 3030 | |
| 3031 | KASSERT(pri >= 0 && pri < RTW_NTXPRI); |
| 3032 | |
| 3033 | tsb = &sc->sc_txsoft_blk[pri]; |
| 3034 | tdb = &sc->sc_txdesc_blk[pri]; |
| 3035 | |
| 3036 | if (SIMPLEQ_EMPTY(&tsb->tsb_freeq) || tdb->tdb_nfree == 0) { |
| 3037 | if (tsb->tsb_tx_timer == 0) |
| 3038 | tsb->tsb_tx_timer = 5; |
| 3039 | *tsbp = NULL; |
| 3040 | *tdbp = NULL; |
| 3041 | return -1; |
| 3042 | } |
| 3043 | *tsbp = tsb; |
| 3044 | *tdbp = tdb; |
| 3045 | return 0; |
| 3046 | } |
| 3047 | |
| 3048 | static inline struct mbuf * |
| 3049 | rtw_80211_dequeue(struct rtw_softc *sc, struct ifqueue *ifq, int pri, |
| 3050 | struct rtw_txsoft_blk **tsbp, struct rtw_txdesc_blk **tdbp, |
| 3051 | struct ieee80211_node **nip, short *if_flagsp) |
| 3052 | { |
| 3053 | struct mbuf *m; |
| 3054 | |
| 3055 | if (IF_IS_EMPTY(ifq)) |
| 3056 | return NULL; |
| 3057 | if (rtw_txring_choose(sc, tsbp, tdbp, pri) == -1) { |
| 3058 | DPRINTF(sc, RTW_DEBUG_XMIT_RSRC, ("%s: no ring %d descriptor\n" , |
| 3059 | __func__, pri)); |
| 3060 | *if_flagsp |= IFF_OACTIVE; |
| 3061 | sc->sc_if.if_timer = 1; |
| 3062 | return NULL; |
| 3063 | } |
| 3064 | IF_DEQUEUE(ifq, m); |
| 3065 | *nip = M_GETCTX(m, struct ieee80211_node *); |
| 3066 | M_SETCTX(m, NULL); |
| 3067 | KASSERT(*nip != NULL); |
| 3068 | return m; |
| 3069 | } |
| 3070 | |
| 3071 | /* Point *mp at the next 802.11 frame to transmit. Point *tsbp |
| 3072 | * at the driver's selection of transmit control block for the packet. |
| 3073 | */ |
| 3074 | static inline int |
| 3075 | rtw_dequeue(struct ifnet *ifp, struct rtw_txsoft_blk **tsbp, |
| 3076 | struct rtw_txdesc_blk **tdbp, struct mbuf **mp, |
| 3077 | struct ieee80211_node **nip) |
| 3078 | { |
| 3079 | int pri; |
| 3080 | struct ether_header *eh; |
| 3081 | struct mbuf *m0; |
| 3082 | struct rtw_softc *sc; |
| 3083 | short *if_flagsp; |
| 3084 | |
| 3085 | *mp = NULL; |
| 3086 | |
| 3087 | sc = (struct rtw_softc *)ifp->if_softc; |
| 3088 | |
| 3089 | DPRINTF(sc, RTW_DEBUG_XMIT, |
| 3090 | ("%s: enter %s\n" , device_xname(sc->sc_dev), __func__)); |
| 3091 | |
| 3092 | if_flagsp = &ifp->if_flags; |
| 3093 | |
| 3094 | if (sc->sc_ic.ic_state == IEEE80211_S_RUN && |
| 3095 | (*mp = rtw_80211_dequeue(sc, &sc->sc_beaconq, RTW_TXPRIBCN, tsbp, |
| 3096 | tdbp, nip, if_flagsp)) != NULL) { |
| 3097 | DPRINTF(sc, RTW_DEBUG_XMIT, ("%s: dequeue beacon frame\n" , |
| 3098 | __func__)); |
| 3099 | return 0; |
| 3100 | } |
| 3101 | |
| 3102 | if ((*mp = rtw_80211_dequeue(sc, &sc->sc_ic.ic_mgtq, RTW_TXPRIMD, tsbp, |
| 3103 | tdbp, nip, if_flagsp)) != NULL) { |
| 3104 | DPRINTF(sc, RTW_DEBUG_XMIT, ("%s: dequeue mgt frame\n" , |
| 3105 | __func__)); |
| 3106 | return 0; |
| 3107 | } |
| 3108 | |
| 3109 | if (sc->sc_ic.ic_state != IEEE80211_S_RUN) { |
| 3110 | DPRINTF(sc, RTW_DEBUG_XMIT, ("%s: not running\n" , __func__)); |
| 3111 | return 0; |
| 3112 | } |
| 3113 | |
| 3114 | IFQ_POLL(&ifp->if_snd, m0); |
| 3115 | if (m0 == NULL) { |
| 3116 | DPRINTF(sc, RTW_DEBUG_XMIT, ("%s: no frame ready\n" , |
| 3117 | __func__)); |
| 3118 | return 0; |
| 3119 | } |
| 3120 | |
| 3121 | pri = ((m0->m_flags & M_PWR_SAV) != 0) ? RTW_TXPRIHI : RTW_TXPRIMD; |
| 3122 | |
| 3123 | if (rtw_txring_choose(sc, tsbp, tdbp, pri) == -1) { |
| 3124 | DPRINTF(sc, RTW_DEBUG_XMIT_RSRC, ("%s: no ring %d descriptor\n" , |
| 3125 | __func__, pri)); |
| 3126 | *if_flagsp |= IFF_OACTIVE; |
| 3127 | sc->sc_if.if_timer = 1; |
| 3128 | return 0; |
| 3129 | } |
| 3130 | |
| 3131 | IFQ_DEQUEUE(&ifp->if_snd, m0); |
| 3132 | if (m0 == NULL) { |
| 3133 | DPRINTF(sc, RTW_DEBUG_XMIT, ("%s: no frame ready\n" , |
| 3134 | __func__)); |
| 3135 | return 0; |
| 3136 | } |
| 3137 | DPRINTF(sc, RTW_DEBUG_XMIT, ("%s: dequeue data frame\n" , __func__)); |
| 3138 | ifp->if_opackets++; |
| 3139 | bpf_mtap(ifp, m0); |
| 3140 | eh = mtod(m0, struct ether_header *); |
| 3141 | *nip = ieee80211_find_txnode(&sc->sc_ic, eh->ether_dhost); |
| 3142 | if (*nip == NULL) { |
| 3143 | /* NB: ieee80211_find_txnode does stat+msg */ |
| 3144 | m_freem(m0); |
| 3145 | return -1; |
| 3146 | } |
| 3147 | if ((m0 = ieee80211_encap(&sc->sc_ic, m0, *nip)) == NULL) { |
| 3148 | DPRINTF(sc, RTW_DEBUG_XMIT, ("%s: encap error\n" , __func__)); |
| 3149 | ifp->if_oerrors++; |
| 3150 | return -1; |
| 3151 | } |
| 3152 | DPRINTF(sc, RTW_DEBUG_XMIT, ("%s: leave\n" , __func__)); |
| 3153 | *mp = m0; |
| 3154 | return 0; |
| 3155 | } |
| 3156 | |
| 3157 | static int |
| 3158 | rtw_seg_too_short(bus_dmamap_t dmamap) |
| 3159 | { |
| 3160 | int i; |
| 3161 | for (i = 0; i < dmamap->dm_nsegs; i++) { |
| 3162 | if (dmamap->dm_segs[i].ds_len < 4) |
| 3163 | return 1; |
| 3164 | } |
| 3165 | return 0; |
| 3166 | } |
| 3167 | |
| 3168 | /* TBD factor with atw_start */ |
| 3169 | static struct mbuf * |
| 3170 | rtw_dmamap_load_txbuf(bus_dma_tag_t dmat, bus_dmamap_t dmam, struct mbuf *chain, |
| 3171 | u_int ndescfree, device_t dev) |
| 3172 | { |
| 3173 | int first, rc; |
| 3174 | struct mbuf *m, *m0; |
| 3175 | |
| 3176 | m0 = chain; |
| 3177 | |
| 3178 | /* |
| 3179 | * Load the DMA map. Copy and try (once) again if the packet |
| 3180 | * didn't fit in the alloted number of segments. |
| 3181 | */ |
| 3182 | for (first = 1; |
| 3183 | ((rc = bus_dmamap_load_mbuf(dmat, dmam, m0, |
| 3184 | BUS_DMA_WRITE|BUS_DMA_NOWAIT)) != 0 || |
| 3185 | dmam->dm_nsegs > ndescfree || rtw_seg_too_short(dmam)) && first; |
| 3186 | first = 0) { |
| 3187 | if (rc == 0) { |
| 3188 | #ifdef RTW_DIAGxxx |
| 3189 | if (rtw_seg_too_short(dmam)) { |
| 3190 | printf("%s: short segment, mbuf lengths:" , __func__); |
| 3191 | for (m = m0; m; m = m->m_next) |
| 3192 | printf(" %d" , m->m_len); |
| 3193 | printf("\n" ); |
| 3194 | } |
| 3195 | #endif |
| 3196 | bus_dmamap_unload(dmat, dmam); |
| 3197 | } |
| 3198 | MGETHDR(m, M_DONTWAIT, MT_DATA); |
| 3199 | if (m == NULL) { |
| 3200 | aprint_error_dev(dev, "unable to allocate Tx mbuf\n" ); |
| 3201 | break; |
| 3202 | } |
| 3203 | if (m0->m_pkthdr.len > MHLEN) { |
| 3204 | MCLGET(m, M_DONTWAIT); |
| 3205 | if ((m->m_flags & M_EXT) == 0) { |
| 3206 | aprint_error_dev(dev, |
| 3207 | "cannot allocate Tx cluster\n" ); |
| 3208 | m_freem(m); |
| 3209 | break; |
| 3210 | } |
| 3211 | } |
| 3212 | m_copydata(m0, 0, m0->m_pkthdr.len, mtod(m, void *)); |
| 3213 | m->m_pkthdr.len = m->m_len = m0->m_pkthdr.len; |
| 3214 | m_freem(m0); |
| 3215 | m0 = m; |
| 3216 | m = NULL; |
| 3217 | } |
| 3218 | if (rc != 0) { |
| 3219 | aprint_error_dev(dev, "cannot load Tx buffer, rc = %d\n" , rc); |
| 3220 | m_freem(m0); |
| 3221 | return NULL; |
| 3222 | } else if (rtw_seg_too_short(dmam)) { |
| 3223 | aprint_error_dev(dev, |
| 3224 | "cannot load Tx buffer, segment too short\n" ); |
| 3225 | bus_dmamap_unload(dmat, dmam); |
| 3226 | m_freem(m0); |
| 3227 | return NULL; |
| 3228 | } else if (dmam->dm_nsegs > ndescfree) { |
| 3229 | aprint_error_dev(dev, "too many tx segments\n" ); |
| 3230 | bus_dmamap_unload(dmat, dmam); |
| 3231 | m_freem(m0); |
| 3232 | return NULL; |
| 3233 | } |
| 3234 | return m0; |
| 3235 | } |
| 3236 | |
| 3237 | #ifdef RTW_DEBUG |
| 3238 | static void |
| 3239 | rtw_print_txdesc(struct rtw_softc *sc, const char *action, |
| 3240 | struct rtw_txsoft *ts, struct rtw_txdesc_blk *tdb, int desc) |
| 3241 | { |
| 3242 | struct rtw_txdesc *td = &tdb->tdb_desc[desc]; |
| 3243 | DPRINTF(sc, RTW_DEBUG_XMIT_DESC, ("%s: %p %s txdesc[%d] next %#08x " |
| 3244 | "buf %#08x ctl0 %#08x ctl1 %#08x len %#08x\n" , |
| 3245 | device_xname(sc->sc_dev), ts, action, desc, |
| 3246 | le32toh(td->td_buf), le32toh(td->td_next), |
| 3247 | le32toh(td->td_ctl0), le32toh(td->td_ctl1), |
| 3248 | le32toh(td->td_len))); |
| 3249 | } |
| 3250 | #endif /* RTW_DEBUG */ |
| 3251 | |
| 3252 | static void |
| 3253 | rtw_start(struct ifnet *ifp) |
| 3254 | { |
| 3255 | int desc, i, lastdesc, npkt, rate; |
| 3256 | uint32_t proto_ctl0, ctl0, ctl1; |
| 3257 | bus_dmamap_t dmamap; |
| 3258 | struct ieee80211com *ic; |
| 3259 | struct ieee80211_duration *d0; |
| 3260 | struct ieee80211_frame_min *wh; |
| 3261 | struct ieee80211_node *ni = NULL; /* XXX: GCC */ |
| 3262 | struct mbuf *m0; |
| 3263 | struct rtw_softc *sc; |
| 3264 | struct rtw_txsoft_blk *tsb = NULL; /* XXX: GCC */ |
| 3265 | struct rtw_txdesc_blk *tdb = NULL; /* XXX: GCC */ |
| 3266 | struct rtw_txsoft *ts; |
| 3267 | struct rtw_txdesc *td; |
| 3268 | struct ieee80211_key *k; |
| 3269 | |
| 3270 | sc = (struct rtw_softc *)ifp->if_softc; |
| 3271 | ic = &sc->sc_ic; |
| 3272 | |
| 3273 | DPRINTF(sc, RTW_DEBUG_XMIT, |
| 3274 | ("%s: enter %s\n" , device_xname(sc->sc_dev), __func__)); |
| 3275 | |
| 3276 | if ((ifp->if_flags & (IFF_RUNNING|IFF_OACTIVE)) != IFF_RUNNING) |
| 3277 | goto out; |
| 3278 | |
| 3279 | /* XXX do real rate control */ |
| 3280 | proto_ctl0 = RTW_TXCTL0_RTSRATE_1MBPS; |
| 3281 | |
| 3282 | if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) != 0) |
| 3283 | proto_ctl0 |= RTW_TXCTL0_SPLCP; |
| 3284 | |
| 3285 | for (;;) { |
| 3286 | if (rtw_dequeue(ifp, &tsb, &tdb, &m0, &ni) == -1) |
| 3287 | continue; |
| 3288 | if (m0 == NULL) |
| 3289 | break; |
| 3290 | |
| 3291 | wh = mtod(m0, struct ieee80211_frame_min *); |
| 3292 | |
| 3293 | if ((wh->i_fc[1] & IEEE80211_FC1_WEP) != 0 && |
| 3294 | (k = ieee80211_crypto_encap(ic, ni, m0)) == NULL) { |
| 3295 | m_freem(m0); |
| 3296 | break; |
| 3297 | } else |
| 3298 | k = NULL; |
| 3299 | |
| 3300 | ts = SIMPLEQ_FIRST(&tsb->tsb_freeq); |
| 3301 | |
| 3302 | dmamap = ts->ts_dmamap; |
| 3303 | |
| 3304 | m0 = rtw_dmamap_load_txbuf(sc->sc_dmat, dmamap, m0, |
| 3305 | tdb->tdb_nfree, sc->sc_dev); |
| 3306 | |
| 3307 | if (m0 == NULL || dmamap->dm_nsegs == 0) { |
| 3308 | DPRINTF(sc, RTW_DEBUG_XMIT, |
| 3309 | ("%s: fail dmamap load\n" , __func__)); |
| 3310 | goto post_dequeue_err; |
| 3311 | } |
| 3312 | |
| 3313 | /* Note well: rtw_dmamap_load_txbuf may have created |
| 3314 | * a new chain, so we must find the header once |
| 3315 | * more. |
| 3316 | */ |
| 3317 | wh = mtod(m0, struct ieee80211_frame_min *); |
| 3318 | |
| 3319 | /* XXX do real rate control */ |
| 3320 | if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == |
| 3321 | IEEE80211_FC0_TYPE_MGT) |
| 3322 | rate = 2; |
| 3323 | else |
| 3324 | rate = MAX(2, ieee80211_get_rate(ni)); |
| 3325 | |
| 3326 | #ifdef RTW_DEBUG |
| 3327 | if ((ifp->if_flags & (IFF_DEBUG|IFF_LINK2)) == |
| 3328 | (IFF_DEBUG|IFF_LINK2)) { |
| 3329 | ieee80211_dump_pkt(mtod(m0, uint8_t *), |
| 3330 | (dmamap->dm_nsegs == 1) ? m0->m_pkthdr.len |
| 3331 | : sizeof(wh), |
| 3332 | rate, 0); |
| 3333 | } |
| 3334 | #endif /* RTW_DEBUG */ |
| 3335 | ctl0 = proto_ctl0 | |
| 3336 | __SHIFTIN(m0->m_pkthdr.len, RTW_TXCTL0_TPKTSIZE_MASK); |
| 3337 | |
| 3338 | switch (rate) { |
| 3339 | default: |
| 3340 | case 2: |
| 3341 | ctl0 |= RTW_TXCTL0_RATE_1MBPS; |
| 3342 | break; |
| 3343 | case 4: |
| 3344 | ctl0 |= RTW_TXCTL0_RATE_2MBPS; |
| 3345 | break; |
| 3346 | case 11: |
| 3347 | ctl0 |= RTW_TXCTL0_RATE_5MBPS; |
| 3348 | break; |
| 3349 | case 22: |
| 3350 | ctl0 |= RTW_TXCTL0_RATE_11MBPS; |
| 3351 | break; |
| 3352 | } |
| 3353 | /* XXX >= ? Compare after fragmentation? */ |
| 3354 | if (m0->m_pkthdr.len > ic->ic_rtsthreshold) |
| 3355 | ctl0 |= RTW_TXCTL0_RTSEN; |
| 3356 | |
| 3357 | /* XXX Sometimes writes a bogus keyid; h/w doesn't |
| 3358 | * seem to care, since we don't activate h/w Tx |
| 3359 | * encryption. |
| 3360 | */ |
| 3361 | if (k != NULL && |
| 3362 | k->wk_cipher->ic_cipher == IEEE80211_CIPHER_WEP) { |
| 3363 | ctl0 |= __SHIFTIN(k->wk_keyix, RTW_TXCTL0_KEYID_MASK) & |
| 3364 | RTW_TXCTL0_KEYID_MASK; |
| 3365 | } |
| 3366 | |
| 3367 | if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == |
| 3368 | IEEE80211_FC0_TYPE_MGT) { |
| 3369 | ctl0 &= ~(RTW_TXCTL0_SPLCP | RTW_TXCTL0_RTSEN); |
| 3370 | if ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == |
| 3371 | IEEE80211_FC0_SUBTYPE_BEACON) |
| 3372 | ctl0 |= RTW_TXCTL0_BEACON; |
| 3373 | } |
| 3374 | |
| 3375 | if (ieee80211_compute_duration(wh, k, m0->m_pkthdr.len, |
| 3376 | ic->ic_flags, ic->ic_fragthreshold, |
| 3377 | rate, &ts->ts_d0, &ts->ts_dn, &npkt, |
| 3378 | (ifp->if_flags & (IFF_DEBUG|IFF_LINK2)) == |
| 3379 | (IFF_DEBUG|IFF_LINK2)) == -1) { |
| 3380 | DPRINTF(sc, RTW_DEBUG_XMIT, |
| 3381 | ("%s: fail compute duration\n" , __func__)); |
| 3382 | goto post_load_err; |
| 3383 | } |
| 3384 | |
| 3385 | d0 = &ts->ts_d0; |
| 3386 | |
| 3387 | *(uint16_t*)wh->i_dur = htole16(d0->d_data_dur); |
| 3388 | |
| 3389 | ctl1 = __SHIFTIN(d0->d_plcp_len, RTW_TXCTL1_LENGTH_MASK) | |
| 3390 | __SHIFTIN(d0->d_rts_dur, RTW_TXCTL1_RTSDUR_MASK); |
| 3391 | |
| 3392 | if (d0->d_residue) |
| 3393 | ctl1 |= RTW_TXCTL1_LENGEXT; |
| 3394 | |
| 3395 | /* TBD fragmentation */ |
| 3396 | |
| 3397 | ts->ts_first = tdb->tdb_next; |
| 3398 | |
| 3399 | rtw_txdescs_sync(tdb, ts->ts_first, dmamap->dm_nsegs, |
| 3400 | BUS_DMASYNC_PREWRITE); |
| 3401 | |
| 3402 | KASSERT(ts->ts_first < tdb->tdb_ndesc); |
| 3403 | |
| 3404 | bpf_mtap3(ic->ic_rawbpf, m0); |
| 3405 | |
| 3406 | if (sc->sc_radiobpf != NULL) { |
| 3407 | struct rtw_tx_radiotap_header *rt = &sc->sc_txtap; |
| 3408 | |
| 3409 | rt->rt_rate = rate; |
| 3410 | |
| 3411 | bpf_mtap2(sc->sc_radiobpf, rt, sizeof(sc->sc_txtapu), |
| 3412 | m0); |
| 3413 | } |
| 3414 | |
| 3415 | for (i = 0, lastdesc = desc = ts->ts_first; |
| 3416 | i < dmamap->dm_nsegs; |
| 3417 | i++, desc = RTW_NEXT_IDX(tdb, desc)) { |
| 3418 | if (dmamap->dm_segs[i].ds_len > RTW_TXLEN_LENGTH_MASK) { |
| 3419 | DPRINTF(sc, RTW_DEBUG_XMIT_DESC, |
| 3420 | ("%s: seg too long\n" , __func__)); |
| 3421 | goto post_load_err; |
| 3422 | } |
| 3423 | td = &tdb->tdb_desc[desc]; |
| 3424 | td->td_ctl0 = htole32(ctl0); |
| 3425 | td->td_ctl1 = htole32(ctl1); |
| 3426 | td->td_buf = htole32(dmamap->dm_segs[i].ds_addr); |
| 3427 | td->td_len = htole32(dmamap->dm_segs[i].ds_len); |
| 3428 | td->td_next = htole32(RTW_NEXT_DESC(tdb, desc)); |
| 3429 | if (i != 0) |
| 3430 | td->td_ctl0 |= htole32(RTW_TXCTL0_OWN); |
| 3431 | lastdesc = desc; |
| 3432 | #ifdef RTW_DEBUG |
| 3433 | rtw_print_txdesc(sc, "load" , ts, tdb, desc); |
| 3434 | #endif /* RTW_DEBUG */ |
| 3435 | } |
| 3436 | |
| 3437 | KASSERT(desc < tdb->tdb_ndesc); |
| 3438 | |
| 3439 | ts->ts_ni = ni; |
| 3440 | KASSERT(ni != NULL); |
| 3441 | ts->ts_mbuf = m0; |
| 3442 | ts->ts_last = lastdesc; |
| 3443 | tdb->tdb_desc[ts->ts_last].td_ctl0 |= htole32(RTW_TXCTL0_LS); |
| 3444 | tdb->tdb_desc[ts->ts_first].td_ctl0 |= |
| 3445 | htole32(RTW_TXCTL0_FS); |
| 3446 | |
| 3447 | #ifdef RTW_DEBUG |
| 3448 | rtw_print_txdesc(sc, "FS on" , ts, tdb, ts->ts_first); |
| 3449 | rtw_print_txdesc(sc, "LS on" , ts, tdb, ts->ts_last); |
| 3450 | #endif /* RTW_DEBUG */ |
| 3451 | |
| 3452 | tdb->tdb_nfree -= dmamap->dm_nsegs; |
| 3453 | tdb->tdb_next = desc; |
| 3454 | |
| 3455 | rtw_txdescs_sync(tdb, ts->ts_first, dmamap->dm_nsegs, |
| 3456 | BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); |
| 3457 | |
| 3458 | tdb->tdb_desc[ts->ts_first].td_ctl0 |= |
| 3459 | htole32(RTW_TXCTL0_OWN); |
| 3460 | |
| 3461 | #ifdef RTW_DEBUG |
| 3462 | rtw_print_txdesc(sc, "OWN on" , ts, tdb, ts->ts_first); |
| 3463 | #endif /* RTW_DEBUG */ |
| 3464 | |
| 3465 | rtw_txdescs_sync(tdb, ts->ts_first, 1, |
| 3466 | BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); |
| 3467 | |
| 3468 | SIMPLEQ_REMOVE_HEAD(&tsb->tsb_freeq, ts_q); |
| 3469 | SIMPLEQ_INSERT_TAIL(&tsb->tsb_dirtyq, ts, ts_q); |
| 3470 | |
| 3471 | if (tsb != &sc->sc_txsoft_blk[RTW_TXPRIBCN]) |
| 3472 | sc->sc_led_state.ls_event |= RTW_LED_S_TX; |
| 3473 | tsb->tsb_tx_timer = 5; |
| 3474 | ifp->if_timer = 1; |
| 3475 | rtw_tx_kick(&sc->sc_regs, tsb->tsb_poll); |
| 3476 | } |
| 3477 | out: |
| 3478 | DPRINTF(sc, RTW_DEBUG_XMIT, ("%s: leave\n" , __func__)); |
| 3479 | return; |
| 3480 | post_load_err: |
| 3481 | bus_dmamap_unload(sc->sc_dmat, dmamap); |
| 3482 | m_freem(m0); |
| 3483 | post_dequeue_err: |
| 3484 | ieee80211_free_node(ni); |
| 3485 | return; |
| 3486 | } |
| 3487 | |
| 3488 | static void |
| 3489 | rtw_idle(struct rtw_regs *regs) |
| 3490 | { |
| 3491 | int active; |
| 3492 | uint8_t tppoll; |
| 3493 | |
| 3494 | /* request stop DMA; wait for packets to stop transmitting. */ |
| 3495 | |
| 3496 | RTW_WRITE8(regs, RTW_TPPOLL, RTW_TPPOLL_SALL); |
| 3497 | RTW_WBR(regs, RTW_TPPOLL, RTW_TPPOLL); |
| 3498 | |
| 3499 | for (active = 0; active < 300 && |
| 3500 | (tppoll = RTW_READ8(regs, RTW_TPPOLL) & RTW_TPPOLL_ACTIVE) != 0; |
| 3501 | active++) |
| 3502 | DELAY(10); |
| 3503 | printf("%s: transmit DMA idle in %dus, tppoll %02" PRIx8 "\n" , __func__, |
| 3504 | active * 10, tppoll); |
| 3505 | } |
| 3506 | |
| 3507 | static void |
| 3508 | rtw_watchdog(struct ifnet *ifp) |
| 3509 | { |
| 3510 | int pri, tx_timeouts = 0; |
| 3511 | struct rtw_softc *sc; |
| 3512 | struct rtw_txsoft_blk *tsb; |
| 3513 | |
| 3514 | sc = ifp->if_softc; |
| 3515 | |
| 3516 | ifp->if_timer = 0; |
| 3517 | |
| 3518 | if (!device_is_active(sc->sc_dev)) |
| 3519 | return; |
| 3520 | |
| 3521 | for (pri = 0; pri < RTW_NTXPRI; pri++) { |
| 3522 | tsb = &sc->sc_txsoft_blk[pri]; |
| 3523 | |
| 3524 | if (tsb->tsb_tx_timer == 0) |
| 3525 | continue; |
| 3526 | else if (--tsb->tsb_tx_timer == 0) { |
| 3527 | if (SIMPLEQ_EMPTY(&tsb->tsb_dirtyq)) |
| 3528 | continue; |
| 3529 | else if (rtw_collect_txring(sc, tsb, |
| 3530 | &sc->sc_txdesc_blk[pri], 0)) |
| 3531 | continue; |
| 3532 | printf("%s: transmit timeout, priority %d\n" , |
| 3533 | ifp->if_xname, pri); |
| 3534 | ifp->if_oerrors++; |
| 3535 | if (pri != RTW_TXPRIBCN) |
| 3536 | tx_timeouts++; |
| 3537 | } else |
| 3538 | ifp->if_timer = 1; |
| 3539 | } |
| 3540 | |
| 3541 | if (tx_timeouts > 0) { |
| 3542 | /* Stop Tx DMA, disable xmtr, flush Tx rings, enable xmtr, |
| 3543 | * reset s/w tx-ring pointers, and start transmission. |
| 3544 | * |
| 3545 | * TBD Stop/restart just the broken rings? |
| 3546 | */ |
| 3547 | rtw_idle(&sc->sc_regs); |
| 3548 | rtw_io_enable(sc, RTW_CR_RE | RTW_CR_TE, 0); |
| 3549 | rtw_txdescs_reset(sc); |
| 3550 | rtw_io_enable(sc, RTW_CR_RE | RTW_CR_TE, 1); |
| 3551 | rtw_start(ifp); |
| 3552 | } |
| 3553 | ieee80211_watchdog(&sc->sc_ic); |
| 3554 | return; |
| 3555 | } |
| 3556 | |
| 3557 | static void |
| 3558 | rtw_next_scan(void *arg) |
| 3559 | { |
| 3560 | struct ieee80211com *ic = arg; |
| 3561 | int s; |
| 3562 | |
| 3563 | /* don't call rtw_start w/o network interrupts blocked */ |
| 3564 | s = splnet(); |
| 3565 | if (ic->ic_state == IEEE80211_S_SCAN) |
| 3566 | ieee80211_next_scan(ic); |
| 3567 | splx(s); |
| 3568 | } |
| 3569 | |
| 3570 | static void |
| 3571 | rtw_join_bss(struct rtw_softc *sc, uint8_t *bssid, uint16_t intval0) |
| 3572 | { |
| 3573 | uint16_t bcnitv, bintritv, intval; |
| 3574 | int i; |
| 3575 | struct rtw_regs *regs = &sc->sc_regs; |
| 3576 | |
| 3577 | for (i = 0; i < IEEE80211_ADDR_LEN; i++) |
| 3578 | RTW_WRITE8(regs, RTW_BSSID + i, bssid[i]); |
| 3579 | |
| 3580 | RTW_SYNC(regs, RTW_BSSID16, RTW_BSSID32); |
| 3581 | |
| 3582 | rtw_set_access(regs, RTW_ACCESS_CONFIG); |
| 3583 | |
| 3584 | intval = MIN(intval0, __SHIFTOUT_MASK(RTW_BCNITV_BCNITV_MASK)); |
| 3585 | |
| 3586 | bcnitv = RTW_READ16(regs, RTW_BCNITV) & ~RTW_BCNITV_BCNITV_MASK; |
| 3587 | bcnitv |= __SHIFTIN(intval, RTW_BCNITV_BCNITV_MASK); |
| 3588 | RTW_WRITE16(regs, RTW_BCNITV, bcnitv); |
| 3589 | /* interrupt host 1ms before the TBTT */ |
| 3590 | bintritv = RTW_READ16(regs, RTW_BINTRITV) & ~RTW_BINTRITV_BINTRITV; |
| 3591 | bintritv |= __SHIFTIN(1000, RTW_BINTRITV_BINTRITV); |
| 3592 | RTW_WRITE16(regs, RTW_BINTRITV, bintritv); |
| 3593 | /* magic from Linux */ |
| 3594 | RTW_WRITE16(regs, RTW_ATIMWND, __SHIFTIN(1, RTW_ATIMWND_ATIMWND)); |
| 3595 | RTW_WRITE16(regs, RTW_ATIMTRITV, __SHIFTIN(2, RTW_ATIMTRITV_ATIMTRITV)); |
| 3596 | rtw_set_access(regs, RTW_ACCESS_NONE); |
| 3597 | |
| 3598 | rtw_io_enable(sc, RTW_CR_RE | RTW_CR_TE, 1); |
| 3599 | } |
| 3600 | |
| 3601 | /* Synchronize the hardware state with the software state. */ |
| 3602 | static int |
| 3603 | rtw_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) |
| 3604 | { |
| 3605 | struct ifnet *ifp = ic->ic_ifp; |
| 3606 | struct rtw_softc *sc = (struct rtw_softc *)ifp->if_softc; |
| 3607 | enum ieee80211_state ostate; |
| 3608 | int error; |
| 3609 | |
| 3610 | ostate = ic->ic_state; |
| 3611 | |
| 3612 | aprint_debug_dev(sc->sc_dev, "%s: l.%d\n" , __func__, __LINE__); |
| 3613 | rtw_led_newstate(sc, nstate); |
| 3614 | |
| 3615 | aprint_debug_dev(sc->sc_dev, "%s: l.%d\n" , __func__, __LINE__); |
| 3616 | if (nstate == IEEE80211_S_INIT) { |
| 3617 | callout_stop(&sc->sc_scan_ch); |
| 3618 | sc->sc_cur_chan = IEEE80211_CHAN_ANY; |
| 3619 | return (*sc->sc_mtbl.mt_newstate)(ic, nstate, arg); |
| 3620 | } |
| 3621 | |
| 3622 | if (ostate == IEEE80211_S_INIT && nstate != IEEE80211_S_INIT) |
| 3623 | rtw_pwrstate(sc, RTW_ON); |
| 3624 | |
| 3625 | if ((error = rtw_tune(sc)) != 0) |
| 3626 | return error; |
| 3627 | |
| 3628 | switch (nstate) { |
| 3629 | case IEEE80211_S_INIT: |
| 3630 | panic("%s: unexpected state IEEE80211_S_INIT\n" , __func__); |
| 3631 | break; |
| 3632 | case IEEE80211_S_SCAN: |
| 3633 | if (ostate != IEEE80211_S_SCAN) { |
| 3634 | (void)memset(ic->ic_bss->ni_bssid, 0, |
| 3635 | IEEE80211_ADDR_LEN); |
| 3636 | rtw_set_nettype(sc, IEEE80211_M_MONITOR); |
| 3637 | } |
| 3638 | |
| 3639 | callout_reset(&sc->sc_scan_ch, rtw_dwelltime * hz / 1000, |
| 3640 | rtw_next_scan, ic); |
| 3641 | |
| 3642 | break; |
| 3643 | case IEEE80211_S_RUN: |
| 3644 | switch (ic->ic_opmode) { |
| 3645 | case IEEE80211_M_HOSTAP: |
| 3646 | case IEEE80211_M_IBSS: |
| 3647 | rtw_set_nettype(sc, IEEE80211_M_MONITOR); |
| 3648 | /*FALLTHROUGH*/ |
| 3649 | case IEEE80211_M_AHDEMO: |
| 3650 | case IEEE80211_M_STA: |
| 3651 | rtw_join_bss(sc, ic->ic_bss->ni_bssid, |
| 3652 | ic->ic_bss->ni_intval); |
| 3653 | break; |
| 3654 | case IEEE80211_M_MONITOR: |
| 3655 | break; |
| 3656 | } |
| 3657 | rtw_set_nettype(sc, ic->ic_opmode); |
| 3658 | break; |
| 3659 | case IEEE80211_S_ASSOC: |
| 3660 | case IEEE80211_S_AUTH: |
| 3661 | break; |
| 3662 | } |
| 3663 | |
| 3664 | if (nstate != IEEE80211_S_SCAN) |
| 3665 | callout_stop(&sc->sc_scan_ch); |
| 3666 | |
| 3667 | return (*sc->sc_mtbl.mt_newstate)(ic, nstate, arg); |
| 3668 | } |
| 3669 | |
| 3670 | /* Extend a 32-bit TSF timestamp to a 64-bit timestamp. */ |
| 3671 | static uint64_t |
| 3672 | rtw_tsf_extend(struct rtw_regs *regs, uint32_t rstamp) |
| 3673 | { |
| 3674 | uint32_t tsftl, tsfth; |
| 3675 | |
| 3676 | tsfth = RTW_READ(regs, RTW_TSFTRH); |
| 3677 | tsftl = RTW_READ(regs, RTW_TSFTRL); |
| 3678 | if (tsftl < rstamp) /* Compensate for rollover. */ |
| 3679 | tsfth--; |
| 3680 | return ((uint64_t)tsfth << 32) | rstamp; |
| 3681 | } |
| 3682 | |
| 3683 | static void |
| 3684 | rtw_recv_mgmt(struct ieee80211com *ic, struct mbuf *m, |
| 3685 | struct ieee80211_node *ni, int subtype, int , uint32_t rstamp) |
| 3686 | { |
| 3687 | struct ifnet *ifp = ic->ic_ifp; |
| 3688 | struct rtw_softc *sc = (struct rtw_softc *)ifp->if_softc; |
| 3689 | |
| 3690 | (*sc->sc_mtbl.mt_recv_mgmt)(ic, m, ni, subtype, rssi, rstamp); |
| 3691 | |
| 3692 | switch (subtype) { |
| 3693 | case IEEE80211_FC0_SUBTYPE_PROBE_RESP: |
| 3694 | case IEEE80211_FC0_SUBTYPE_BEACON: |
| 3695 | if (ic->ic_opmode == IEEE80211_M_IBSS && |
| 3696 | ic->ic_state == IEEE80211_S_RUN && |
| 3697 | device_is_active(sc->sc_dev)) { |
| 3698 | uint64_t tsf = rtw_tsf_extend(&sc->sc_regs, rstamp); |
| 3699 | if (le64toh(ni->ni_tstamp.tsf) >= tsf) |
| 3700 | (void)ieee80211_ibss_merge(ni); |
| 3701 | } |
| 3702 | break; |
| 3703 | default: |
| 3704 | break; |
| 3705 | } |
| 3706 | return; |
| 3707 | } |
| 3708 | |
| 3709 | static struct ieee80211_node * |
| 3710 | rtw_node_alloc(struct ieee80211_node_table *nt) |
| 3711 | { |
| 3712 | struct ifnet *ifp = nt->nt_ic->ic_ifp; |
| 3713 | struct rtw_softc *sc = (struct rtw_softc *)ifp->if_softc; |
| 3714 | struct ieee80211_node *ni = (*sc->sc_mtbl.mt_node_alloc)(nt); |
| 3715 | |
| 3716 | DPRINTF(sc, RTW_DEBUG_NODE, |
| 3717 | ("%s: alloc node %p\n" , device_xname(sc->sc_dev), ni)); |
| 3718 | return ni; |
| 3719 | } |
| 3720 | |
| 3721 | static void |
| 3722 | rtw_node_free(struct ieee80211_node *ni) |
| 3723 | { |
| 3724 | struct ieee80211com *ic = ni->ni_ic; |
| 3725 | struct ifnet *ifp = ic->ic_ifp; |
| 3726 | struct rtw_softc *sc = (struct rtw_softc *)ifp->if_softc; |
| 3727 | |
| 3728 | DPRINTF(sc, RTW_DEBUG_NODE, |
| 3729 | ("%s: freeing node %p %s\n" , device_xname(sc->sc_dev), ni, |
| 3730 | ether_sprintf(ni->ni_bssid))); |
| 3731 | (*sc->sc_mtbl.mt_node_free)(ni); |
| 3732 | } |
| 3733 | |
| 3734 | static int |
| 3735 | rtw_media_change(struct ifnet *ifp) |
| 3736 | { |
| 3737 | int error; |
| 3738 | |
| 3739 | error = ieee80211_media_change(ifp); |
| 3740 | if (error == ENETRESET) { |
| 3741 | if ((ifp->if_flags & (IFF_RUNNING|IFF_UP)) == |
| 3742 | (IFF_RUNNING|IFF_UP)) |
| 3743 | rtw_init(ifp); /* XXX lose error */ |
| 3744 | error = 0; |
| 3745 | } |
| 3746 | return error; |
| 3747 | } |
| 3748 | |
| 3749 | static void |
| 3750 | rtw_media_status(struct ifnet *ifp, struct ifmediareq *imr) |
| 3751 | { |
| 3752 | struct rtw_softc *sc = ifp->if_softc; |
| 3753 | |
| 3754 | if (!device_is_active(sc->sc_dev)) { |
| 3755 | imr->ifm_active = IFM_IEEE80211 | IFM_NONE; |
| 3756 | imr->ifm_status = 0; |
| 3757 | return; |
| 3758 | } |
| 3759 | ieee80211_media_status(ifp, imr); |
| 3760 | } |
| 3761 | |
| 3762 | static inline void |
| 3763 | rtw_setifprops(struct ifnet *ifp, const char *dvname, void *softc) |
| 3764 | { |
| 3765 | (void)strlcpy(ifp->if_xname, dvname, IFNAMSIZ); |
| 3766 | ifp->if_softc = softc; |
| 3767 | ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST | |
| 3768 | IFF_NOTRAILERS; |
| 3769 | ifp->if_ioctl = rtw_ioctl; |
| 3770 | ifp->if_start = rtw_start; |
| 3771 | ifp->if_watchdog = rtw_watchdog; |
| 3772 | ifp->if_init = rtw_init; |
| 3773 | ifp->if_stop = rtw_stop; |
| 3774 | } |
| 3775 | |
| 3776 | static inline void |
| 3777 | rtw_set80211props(struct ieee80211com *ic) |
| 3778 | { |
| 3779 | int nrate; |
| 3780 | ic->ic_phytype = IEEE80211_T_DS; |
| 3781 | ic->ic_opmode = IEEE80211_M_STA; |
| 3782 | ic->ic_caps = IEEE80211_C_PMGT | IEEE80211_C_IBSS | |
| 3783 | IEEE80211_C_HOSTAP | IEEE80211_C_MONITOR | IEEE80211_C_WEP; |
| 3784 | |
| 3785 | nrate = 0; |
| 3786 | ic->ic_sup_rates[IEEE80211_MODE_11B].rs_rates[nrate++] = |
| 3787 | IEEE80211_RATE_BASIC | 2; |
| 3788 | ic->ic_sup_rates[IEEE80211_MODE_11B].rs_rates[nrate++] = |
| 3789 | IEEE80211_RATE_BASIC | 4; |
| 3790 | ic->ic_sup_rates[IEEE80211_MODE_11B].rs_rates[nrate++] = 11; |
| 3791 | ic->ic_sup_rates[IEEE80211_MODE_11B].rs_rates[nrate++] = 22; |
| 3792 | ic->ic_sup_rates[IEEE80211_MODE_11B].rs_nrates = nrate; |
| 3793 | } |
| 3794 | |
| 3795 | static inline void |
| 3796 | rtw_set80211methods(struct rtw_mtbl *mtbl, struct ieee80211com *ic) |
| 3797 | { |
| 3798 | mtbl->mt_newstate = ic->ic_newstate; |
| 3799 | ic->ic_newstate = rtw_newstate; |
| 3800 | |
| 3801 | mtbl->mt_recv_mgmt = ic->ic_recv_mgmt; |
| 3802 | ic->ic_recv_mgmt = rtw_recv_mgmt; |
| 3803 | |
| 3804 | mtbl->mt_node_free = ic->ic_node_free; |
| 3805 | ic->ic_node_free = rtw_node_free; |
| 3806 | |
| 3807 | mtbl->mt_node_alloc = ic->ic_node_alloc; |
| 3808 | ic->ic_node_alloc = rtw_node_alloc; |
| 3809 | |
| 3810 | ic->ic_crypto.cs_key_delete = rtw_key_delete; |
| 3811 | ic->ic_crypto.cs_key_set = rtw_key_set; |
| 3812 | ic->ic_crypto.cs_key_update_begin = rtw_key_update_begin; |
| 3813 | ic->ic_crypto.cs_key_update_end = rtw_key_update_end; |
| 3814 | } |
| 3815 | |
| 3816 | static inline void |
| 3817 | rtw_init_radiotap(struct rtw_softc *sc) |
| 3818 | { |
| 3819 | uint32_t present; |
| 3820 | |
| 3821 | memset(&sc->sc_rxtapu, 0, sizeof(sc->sc_rxtapu)); |
| 3822 | sc->sc_rxtap.rr_ihdr.it_len = htole16(sizeof(sc->sc_rxtapu)); |
| 3823 | |
| 3824 | if (sc->sc_rfchipid == RTW_RFCHIPID_PHILIPS) |
| 3825 | present = htole32(RTW_PHILIPS_RX_RADIOTAP_PRESENT); |
| 3826 | else |
| 3827 | present = htole32(RTW_RX_RADIOTAP_PRESENT); |
| 3828 | sc->sc_rxtap.rr_ihdr.it_present = present; |
| 3829 | |
| 3830 | memset(&sc->sc_txtapu, 0, sizeof(sc->sc_txtapu)); |
| 3831 | sc->sc_txtap.rt_ihdr.it_len = htole16(sizeof(sc->sc_txtapu)); |
| 3832 | sc->sc_txtap.rt_ihdr.it_present = htole32(RTW_TX_RADIOTAP_PRESENT); |
| 3833 | } |
| 3834 | |
| 3835 | static int |
| 3836 | rtw_txsoft_blk_setup(struct rtw_txsoft_blk *tsb, u_int qlen) |
| 3837 | { |
| 3838 | SIMPLEQ_INIT(&tsb->tsb_dirtyq); |
| 3839 | SIMPLEQ_INIT(&tsb->tsb_freeq); |
| 3840 | tsb->tsb_ndesc = qlen; |
| 3841 | tsb->tsb_desc = malloc(qlen * sizeof(*tsb->tsb_desc), M_DEVBUF, |
| 3842 | M_NOWAIT); |
| 3843 | if (tsb->tsb_desc == NULL) |
| 3844 | return ENOMEM; |
| 3845 | return 0; |
| 3846 | } |
| 3847 | |
| 3848 | static void |
| 3849 | rtw_txsoft_blk_cleanup_all(struct rtw_softc *sc) |
| 3850 | { |
| 3851 | int pri; |
| 3852 | struct rtw_txsoft_blk *tsb; |
| 3853 | |
| 3854 | for (pri = 0; pri < RTW_NTXPRI; pri++) { |
| 3855 | tsb = &sc->sc_txsoft_blk[pri]; |
| 3856 | free(tsb->tsb_desc, M_DEVBUF); |
| 3857 | tsb->tsb_desc = NULL; |
| 3858 | } |
| 3859 | } |
| 3860 | |
| 3861 | static int |
| 3862 | rtw_txsoft_blk_setup_all(struct rtw_softc *sc) |
| 3863 | { |
| 3864 | int pri, rc = 0; |
| 3865 | int qlen[RTW_NTXPRI] = |
| 3866 | {RTW_TXQLENLO, RTW_TXQLENMD, RTW_TXQLENHI, RTW_TXQLENBCN}; |
| 3867 | struct rtw_txsoft_blk *tsbs; |
| 3868 | |
| 3869 | tsbs = sc->sc_txsoft_blk; |
| 3870 | |
| 3871 | for (pri = 0; pri < RTW_NTXPRI; pri++) { |
| 3872 | rc = rtw_txsoft_blk_setup(&tsbs[pri], qlen[pri]); |
| 3873 | if (rc != 0) |
| 3874 | break; |
| 3875 | } |
| 3876 | tsbs[RTW_TXPRILO].tsb_poll = RTW_TPPOLL_LPQ | RTW_TPPOLL_SLPQ; |
| 3877 | tsbs[RTW_TXPRIMD].tsb_poll = RTW_TPPOLL_NPQ | RTW_TPPOLL_SNPQ; |
| 3878 | tsbs[RTW_TXPRIHI].tsb_poll = RTW_TPPOLL_HPQ | RTW_TPPOLL_SHPQ; |
| 3879 | tsbs[RTW_TXPRIBCN].tsb_poll = RTW_TPPOLL_BQ | RTW_TPPOLL_SBQ; |
| 3880 | return rc; |
| 3881 | } |
| 3882 | |
| 3883 | static void |
| 3884 | rtw_txdesc_blk_setup(struct rtw_txdesc_blk *tdb, struct rtw_txdesc *desc, |
| 3885 | u_int ndesc, bus_addr_t ofs, bus_addr_t physbase) |
| 3886 | { |
| 3887 | tdb->tdb_ndesc = ndesc; |
| 3888 | tdb->tdb_desc = desc; |
| 3889 | tdb->tdb_physbase = physbase; |
| 3890 | tdb->tdb_ofs = ofs; |
| 3891 | |
| 3892 | (void)memset(tdb->tdb_desc, 0, |
| 3893 | sizeof(tdb->tdb_desc[0]) * tdb->tdb_ndesc); |
| 3894 | |
| 3895 | rtw_txdesc_blk_init(tdb); |
| 3896 | tdb->tdb_next = 0; |
| 3897 | } |
| 3898 | |
| 3899 | static void |
| 3900 | rtw_txdesc_blk_setup_all(struct rtw_softc *sc) |
| 3901 | { |
| 3902 | rtw_txdesc_blk_setup(&sc->sc_txdesc_blk[RTW_TXPRILO], |
| 3903 | &sc->sc_descs->hd_txlo[0], RTW_NTXDESCLO, |
| 3904 | RTW_RING_OFFSET(hd_txlo), RTW_RING_BASE(sc, hd_txlo)); |
| 3905 | |
| 3906 | rtw_txdesc_blk_setup(&sc->sc_txdesc_blk[RTW_TXPRIMD], |
| 3907 | &sc->sc_descs->hd_txmd[0], RTW_NTXDESCMD, |
| 3908 | RTW_RING_OFFSET(hd_txmd), RTW_RING_BASE(sc, hd_txmd)); |
| 3909 | |
| 3910 | rtw_txdesc_blk_setup(&sc->sc_txdesc_blk[RTW_TXPRIHI], |
| 3911 | &sc->sc_descs->hd_txhi[0], RTW_NTXDESCHI, |
| 3912 | RTW_RING_OFFSET(hd_txhi), RTW_RING_BASE(sc, hd_txhi)); |
| 3913 | |
| 3914 | rtw_txdesc_blk_setup(&sc->sc_txdesc_blk[RTW_TXPRIBCN], |
| 3915 | &sc->sc_descs->hd_bcn[0], RTW_NTXDESCBCN, |
| 3916 | RTW_RING_OFFSET(hd_bcn), RTW_RING_BASE(sc, hd_bcn)); |
| 3917 | } |
| 3918 | |
| 3919 | static struct rtw_rf * |
| 3920 | rtw_rf_attach(struct rtw_softc *sc, enum rtw_rfchipid rfchipid, int digphy) |
| 3921 | { |
| 3922 | rtw_rf_write_t rf_write; |
| 3923 | struct rtw_rf *rf; |
| 3924 | |
| 3925 | switch (rfchipid) { |
| 3926 | default: |
| 3927 | rf_write = rtw_rf_hostwrite; |
| 3928 | break; |
| 3929 | case RTW_RFCHIPID_INTERSIL: |
| 3930 | case RTW_RFCHIPID_PHILIPS: |
| 3931 | case RTW_RFCHIPID_GCT: /* XXX a guess */ |
| 3932 | case RTW_RFCHIPID_RFMD: |
| 3933 | rf_write = (rtw_host_rfio) ? rtw_rf_hostwrite : rtw_rf_macwrite; |
| 3934 | break; |
| 3935 | } |
| 3936 | |
| 3937 | switch (rfchipid) { |
| 3938 | case RTW_RFCHIPID_GCT: |
| 3939 | rf = rtw_grf5101_create(&sc->sc_regs, rf_write, 0); |
| 3940 | sc->sc_pwrstate_cb = rtw_maxim_pwrstate; |
| 3941 | break; |
| 3942 | case RTW_RFCHIPID_MAXIM: |
| 3943 | rf = rtw_max2820_create(&sc->sc_regs, rf_write, 0); |
| 3944 | sc->sc_pwrstate_cb = rtw_maxim_pwrstate; |
| 3945 | break; |
| 3946 | case RTW_RFCHIPID_PHILIPS: |
| 3947 | rf = rtw_sa2400_create(&sc->sc_regs, rf_write, digphy); |
| 3948 | sc->sc_pwrstate_cb = rtw_philips_pwrstate; |
| 3949 | break; |
| 3950 | case RTW_RFCHIPID_RFMD: |
| 3951 | /* XXX RFMD has no RF constructor */ |
| 3952 | sc->sc_pwrstate_cb = rtw_rfmd_pwrstate; |
| 3953 | /*FALLTHROUGH*/ |
| 3954 | default: |
| 3955 | return NULL; |
| 3956 | } |
| 3957 | rf->rf_continuous_tx_cb = |
| 3958 | (rtw_continuous_tx_cb_t)rtw_continuous_tx_enable; |
| 3959 | rf->rf_continuous_tx_arg = (void *)sc; |
| 3960 | return rf; |
| 3961 | } |
| 3962 | |
| 3963 | /* Revision C and later use a different PHY delay setting than |
| 3964 | * revisions A and B. |
| 3965 | */ |
| 3966 | static uint8_t |
| 3967 | rtw_check_phydelay(struct rtw_regs *regs, uint32_t old_rcr) |
| 3968 | { |
| 3969 | #define REVAB (RTW_RCR_MXDMA_UNLIMITED | RTW_RCR_AICV) |
| 3970 | #define REVC (REVAB | RTW_RCR_RXFTH_WHOLE) |
| 3971 | |
| 3972 | uint8_t phydelay = __SHIFTIN(0x6, RTW_PHYDELAY_PHYDELAY); |
| 3973 | |
| 3974 | RTW_WRITE(regs, RTW_RCR, REVAB); |
| 3975 | RTW_WBW(regs, RTW_RCR, RTW_RCR); |
| 3976 | RTW_WRITE(regs, RTW_RCR, REVC); |
| 3977 | |
| 3978 | RTW_WBR(regs, RTW_RCR, RTW_RCR); |
| 3979 | if ((RTW_READ(regs, RTW_RCR) & REVC) == REVC) |
| 3980 | phydelay |= RTW_PHYDELAY_REVC_MAGIC; |
| 3981 | |
| 3982 | RTW_WRITE(regs, RTW_RCR, old_rcr); /* restore RCR */ |
| 3983 | RTW_SYNC(regs, RTW_RCR, RTW_RCR); |
| 3984 | |
| 3985 | return phydelay; |
| 3986 | #undef REVC |
| 3987 | } |
| 3988 | |
| 3989 | void |
| 3990 | rtw_attach(struct rtw_softc *sc) |
| 3991 | { |
| 3992 | struct ifnet *ifp = &sc->sc_if; |
| 3993 | struct ieee80211com *ic = &sc->sc_ic; |
| 3994 | struct rtw_txsoft_blk *tsb; |
| 3995 | int pri, rc; |
| 3996 | |
| 3997 | pmf_self_suspensor_init(sc->sc_dev, &sc->sc_suspensor, &sc->sc_qual); |
| 3998 | |
| 3999 | rtw_cipher_wep = ieee80211_cipher_wep; |
| 4000 | rtw_cipher_wep.ic_decap = rtw_wep_decap; |
| 4001 | |
| 4002 | NEXT_ATTACH_STATE(sc, DETACHED); |
| 4003 | |
| 4004 | switch (RTW_READ(&sc->sc_regs, RTW_TCR) & RTW_TCR_HWVERID_MASK) { |
| 4005 | case RTW_TCR_HWVERID_F: |
| 4006 | sc->sc_hwverid = 'F'; |
| 4007 | break; |
| 4008 | case RTW_TCR_HWVERID_D: |
| 4009 | sc->sc_hwverid = 'D'; |
| 4010 | break; |
| 4011 | default: |
| 4012 | sc->sc_hwverid = '?'; |
| 4013 | break; |
| 4014 | } |
| 4015 | aprint_verbose_dev(sc->sc_dev, "hardware version %c\n" , |
| 4016 | sc->sc_hwverid); |
| 4017 | |
| 4018 | rc = bus_dmamem_alloc(sc->sc_dmat, sizeof(struct rtw_descs), |
| 4019 | RTW_DESC_ALIGNMENT, 0, &sc->sc_desc_segs, 1, &sc->sc_desc_nsegs, |
| 4020 | 0); |
| 4021 | |
| 4022 | if (rc != 0) { |
| 4023 | aprint_error_dev(sc->sc_dev, |
| 4024 | "could not allocate hw descriptors, error %d\n" , rc); |
| 4025 | goto err; |
| 4026 | } |
| 4027 | |
| 4028 | NEXT_ATTACH_STATE(sc, FINISH_DESC_ALLOC); |
| 4029 | |
| 4030 | rc = bus_dmamem_map(sc->sc_dmat, &sc->sc_desc_segs, |
| 4031 | sc->sc_desc_nsegs, sizeof(struct rtw_descs), |
| 4032 | (void **)&sc->sc_descs, BUS_DMA_COHERENT); |
| 4033 | |
| 4034 | if (rc != 0) { |
| 4035 | aprint_error_dev(sc->sc_dev, |
| 4036 | "could not map hw descriptors, error %d\n" , rc); |
| 4037 | goto err; |
| 4038 | } |
| 4039 | NEXT_ATTACH_STATE(sc, FINISH_DESC_MAP); |
| 4040 | |
| 4041 | rc = bus_dmamap_create(sc->sc_dmat, sizeof(struct rtw_descs), 1, |
| 4042 | sizeof(struct rtw_descs), 0, 0, &sc->sc_desc_dmamap); |
| 4043 | |
| 4044 | if (rc != 0) { |
| 4045 | aprint_error_dev(sc->sc_dev, |
| 4046 | "could not create DMA map for hw descriptors, error %d\n" , |
| 4047 | rc); |
| 4048 | goto err; |
| 4049 | } |
| 4050 | NEXT_ATTACH_STATE(sc, FINISH_DESCMAP_CREATE); |
| 4051 | |
| 4052 | sc->sc_rxdesc_blk.rdb_dmat = sc->sc_dmat; |
| 4053 | sc->sc_rxdesc_blk.rdb_dmamap = sc->sc_desc_dmamap; |
| 4054 | |
| 4055 | for (pri = 0; pri < RTW_NTXPRI; pri++) { |
| 4056 | sc->sc_txdesc_blk[pri].tdb_dmat = sc->sc_dmat; |
| 4057 | sc->sc_txdesc_blk[pri].tdb_dmamap = sc->sc_desc_dmamap; |
| 4058 | } |
| 4059 | |
| 4060 | rc = bus_dmamap_load(sc->sc_dmat, sc->sc_desc_dmamap, sc->sc_descs, |
| 4061 | sizeof(struct rtw_descs), NULL, 0); |
| 4062 | |
| 4063 | if (rc != 0) { |
| 4064 | aprint_error_dev(sc->sc_dev, |
| 4065 | "could not load DMA map for hw descriptors, error %d\n" , |
| 4066 | rc); |
| 4067 | goto err; |
| 4068 | } |
| 4069 | NEXT_ATTACH_STATE(sc, FINISH_DESCMAP_LOAD); |
| 4070 | |
| 4071 | if (rtw_txsoft_blk_setup_all(sc) != 0) |
| 4072 | goto err; |
| 4073 | NEXT_ATTACH_STATE(sc, FINISH_TXCTLBLK_SETUP); |
| 4074 | |
| 4075 | rtw_txdesc_blk_setup_all(sc); |
| 4076 | |
| 4077 | NEXT_ATTACH_STATE(sc, FINISH_TXDESCBLK_SETUP); |
| 4078 | |
| 4079 | sc->sc_rxdesc_blk.rdb_desc = &sc->sc_descs->hd_rx[0]; |
| 4080 | |
| 4081 | for (pri = 0; pri < RTW_NTXPRI; pri++) { |
| 4082 | tsb = &sc->sc_txsoft_blk[pri]; |
| 4083 | |
| 4084 | if ((rc = rtw_txdesc_dmamaps_create(sc->sc_dmat, |
| 4085 | &tsb->tsb_desc[0], tsb->tsb_ndesc)) != 0) { |
| 4086 | aprint_error_dev(sc->sc_dev, |
| 4087 | "could not load DMA map for hw tx descriptors, " |
| 4088 | "error %d\n" , rc); |
| 4089 | goto err; |
| 4090 | } |
| 4091 | } |
| 4092 | |
| 4093 | NEXT_ATTACH_STATE(sc, FINISH_TXMAPS_CREATE); |
| 4094 | if ((rc = rtw_rxdesc_dmamaps_create(sc->sc_dmat, &sc->sc_rxsoft[0], |
| 4095 | RTW_RXQLEN)) != 0) { |
| 4096 | aprint_error_dev(sc->sc_dev, |
| 4097 | "could not load DMA map for hw rx descriptors, error %d\n" , |
| 4098 | rc); |
| 4099 | goto err; |
| 4100 | } |
| 4101 | NEXT_ATTACH_STATE(sc, FINISH_RXMAPS_CREATE); |
| 4102 | |
| 4103 | /* Reset the chip to a known state. */ |
| 4104 | if (rtw_reset(sc) != 0) |
| 4105 | goto err; |
| 4106 | NEXT_ATTACH_STATE(sc, FINISH_RESET); |
| 4107 | |
| 4108 | sc->sc_rcr = RTW_READ(&sc->sc_regs, RTW_RCR); |
| 4109 | |
| 4110 | if ((sc->sc_rcr & RTW_RCR_9356SEL) != 0) |
| 4111 | sc->sc_flags |= RTW_F_9356SROM; |
| 4112 | |
| 4113 | if (rtw_srom_read(&sc->sc_regs, sc->sc_flags, &sc->sc_srom, |
| 4114 | sc->sc_dev) != 0) |
| 4115 | goto err; |
| 4116 | |
| 4117 | NEXT_ATTACH_STATE(sc, FINISH_READ_SROM); |
| 4118 | |
| 4119 | if (rtw_srom_parse(&sc->sc_srom, &sc->sc_flags, &sc->sc_csthr, |
| 4120 | &sc->sc_rfchipid, &sc->sc_rcr, &sc->sc_locale, |
| 4121 | sc->sc_dev) != 0) { |
| 4122 | aprint_error_dev(sc->sc_dev, |
| 4123 | "attach failed, malformed serial ROM\n" ); |
| 4124 | goto err; |
| 4125 | } |
| 4126 | |
| 4127 | aprint_verbose_dev(sc->sc_dev, "%s PHY\n" , |
| 4128 | ((sc->sc_flags & RTW_F_DIGPHY) != 0) ? "digital" : "analog" ); |
| 4129 | |
| 4130 | aprint_verbose_dev(sc->sc_dev, "carrier-sense threshold %u\n" , |
| 4131 | sc->sc_csthr); |
| 4132 | |
| 4133 | NEXT_ATTACH_STATE(sc, FINISH_PARSE_SROM); |
| 4134 | |
| 4135 | sc->sc_rf = rtw_rf_attach(sc, sc->sc_rfchipid, |
| 4136 | sc->sc_flags & RTW_F_DIGPHY); |
| 4137 | |
| 4138 | if (sc->sc_rf == NULL) { |
| 4139 | aprint_verbose_dev(sc->sc_dev, |
| 4140 | "attach failed, could not attach RF\n" ); |
| 4141 | goto err; |
| 4142 | } |
| 4143 | |
| 4144 | NEXT_ATTACH_STATE(sc, FINISH_RF_ATTACH); |
| 4145 | |
| 4146 | sc->sc_phydelay = rtw_check_phydelay(&sc->sc_regs, sc->sc_rcr); |
| 4147 | |
| 4148 | RTW_DPRINTF(RTW_DEBUG_ATTACH, |
| 4149 | ("%s: PHY delay %d\n" , device_xname(sc->sc_dev), sc->sc_phydelay)); |
| 4150 | |
| 4151 | if (sc->sc_locale == RTW_LOCALE_UNKNOWN) |
| 4152 | rtw_identify_country(&sc->sc_regs, &sc->sc_locale); |
| 4153 | |
| 4154 | rtw_init_channels(sc->sc_locale, &sc->sc_ic.ic_channels, sc->sc_dev); |
| 4155 | |
| 4156 | if (rtw_identify_sta(&sc->sc_regs, &sc->sc_ic.ic_myaddr, |
| 4157 | sc->sc_dev) != 0) |
| 4158 | goto err; |
| 4159 | NEXT_ATTACH_STATE(sc, FINISH_ID_STA); |
| 4160 | |
| 4161 | rtw_setifprops(ifp, device_xname(sc->sc_dev), (void*)sc); |
| 4162 | |
| 4163 | IFQ_SET_READY(&ifp->if_snd); |
| 4164 | |
| 4165 | sc->sc_ic.ic_ifp = ifp; |
| 4166 | rtw_set80211props(&sc->sc_ic); |
| 4167 | |
| 4168 | rtw_led_attach(&sc->sc_led_state, (void *)sc); |
| 4169 | |
| 4170 | /* |
| 4171 | * Call MI attach routines. |
| 4172 | */ |
| 4173 | if_attach(ifp); |
| 4174 | ieee80211_ifattach(&sc->sc_ic); |
| 4175 | |
| 4176 | rtw_set80211methods(&sc->sc_mtbl, &sc->sc_ic); |
| 4177 | |
| 4178 | /* possibly we should fill in our own sc_send_prresp, since |
| 4179 | * the RTL8180 is probably sending probe responses in ad hoc |
| 4180 | * mode. |
| 4181 | */ |
| 4182 | |
| 4183 | /* complete initialization */ |
| 4184 | ieee80211_media_init(&sc->sc_ic, rtw_media_change, rtw_media_status); |
| 4185 | callout_init(&sc->sc_scan_ch, 0); |
| 4186 | |
| 4187 | rtw_init_radiotap(sc); |
| 4188 | |
| 4189 | bpf_attach2(ifp, DLT_IEEE802_11_RADIO, |
| 4190 | sizeof(struct ieee80211_frame) + 64, &sc->sc_radiobpf); |
| 4191 | |
| 4192 | NEXT_ATTACH_STATE(sc, FINISHED); |
| 4193 | |
| 4194 | ieee80211_announce(ic); |
| 4195 | return; |
| 4196 | err: |
| 4197 | rtw_detach(sc); |
| 4198 | return; |
| 4199 | } |
| 4200 | |
| 4201 | int |
| 4202 | rtw_detach(struct rtw_softc *sc) |
| 4203 | { |
| 4204 | struct ifnet *ifp = &sc->sc_if; |
| 4205 | int pri, s; |
| 4206 | |
| 4207 | s = splnet(); |
| 4208 | |
| 4209 | switch (sc->sc_attach_state) { |
| 4210 | case FINISHED: |
| 4211 | rtw_stop(ifp, 1); |
| 4212 | |
| 4213 | pmf_device_deregister(sc->sc_dev); |
| 4214 | callout_stop(&sc->sc_scan_ch); |
| 4215 | ieee80211_ifdetach(&sc->sc_ic); |
| 4216 | if_detach(ifp); |
| 4217 | rtw_led_detach(&sc->sc_led_state); |
| 4218 | /*FALLTHROUGH*/ |
| 4219 | case FINISH_ID_STA: |
| 4220 | case FINISH_RF_ATTACH: |
| 4221 | rtw_rf_destroy(sc->sc_rf); |
| 4222 | sc->sc_rf = NULL; |
| 4223 | /*FALLTHROUGH*/ |
| 4224 | case FINISH_PARSE_SROM: |
| 4225 | case FINISH_READ_SROM: |
| 4226 | rtw_srom_free(&sc->sc_srom); |
| 4227 | /*FALLTHROUGH*/ |
| 4228 | case FINISH_RESET: |
| 4229 | case FINISH_RXMAPS_CREATE: |
| 4230 | rtw_rxdesc_dmamaps_destroy(sc->sc_dmat, &sc->sc_rxsoft[0], |
| 4231 | RTW_RXQLEN); |
| 4232 | /*FALLTHROUGH*/ |
| 4233 | case FINISH_TXMAPS_CREATE: |
| 4234 | for (pri = 0; pri < RTW_NTXPRI; pri++) { |
| 4235 | rtw_txdesc_dmamaps_destroy(sc->sc_dmat, |
| 4236 | sc->sc_txsoft_blk[pri].tsb_desc, |
| 4237 | sc->sc_txsoft_blk[pri].tsb_ndesc); |
| 4238 | } |
| 4239 | /*FALLTHROUGH*/ |
| 4240 | case FINISH_TXDESCBLK_SETUP: |
| 4241 | case FINISH_TXCTLBLK_SETUP: |
| 4242 | rtw_txsoft_blk_cleanup_all(sc); |
| 4243 | /*FALLTHROUGH*/ |
| 4244 | case FINISH_DESCMAP_LOAD: |
| 4245 | bus_dmamap_unload(sc->sc_dmat, sc->sc_desc_dmamap); |
| 4246 | /*FALLTHROUGH*/ |
| 4247 | case FINISH_DESCMAP_CREATE: |
| 4248 | bus_dmamap_destroy(sc->sc_dmat, sc->sc_desc_dmamap); |
| 4249 | /*FALLTHROUGH*/ |
| 4250 | case FINISH_DESC_MAP: |
| 4251 | bus_dmamem_unmap(sc->sc_dmat, (void *)sc->sc_descs, |
| 4252 | sizeof(struct rtw_descs)); |
| 4253 | /*FALLTHROUGH*/ |
| 4254 | case FINISH_DESC_ALLOC: |
| 4255 | bus_dmamem_free(sc->sc_dmat, &sc->sc_desc_segs, |
| 4256 | sc->sc_desc_nsegs); |
| 4257 | /*FALLTHROUGH*/ |
| 4258 | case DETACHED: |
| 4259 | NEXT_ATTACH_STATE(sc, DETACHED); |
| 4260 | break; |
| 4261 | } |
| 4262 | splx(s); |
| 4263 | return 0; |
| 4264 | } |
| 4265 | |