Annotation of sys/dev/pci/if_wpi.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: if_wpi.c,v 1.50 2007/08/10 16:29:27 jasper Exp $ */
! 2:
! 3: /*-
! 4: * Copyright (c) 2006, 2007
! 5: * Damien Bergamini <damien.bergamini@free.fr>
! 6: *
! 7: * Permission to use, copy, modify, and distribute this software for any
! 8: * purpose with or without fee is hereby granted, provided that the above
! 9: * copyright notice and this permission notice appear in all copies.
! 10: *
! 11: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
! 12: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
! 13: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
! 14: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
! 15: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
! 16: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
! 17: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
! 18: */
! 19:
! 20: /*
! 21: * Driver for Intel PRO/Wireless 3945ABG 802.11 network adapters.
! 22: */
! 23:
! 24: #include "bpfilter.h"
! 25:
! 26: #include <sys/param.h>
! 27: #include <sys/sockio.h>
! 28: #include <sys/sysctl.h>
! 29: #include <sys/mbuf.h>
! 30: #include <sys/kernel.h>
! 31: #include <sys/socket.h>
! 32: #include <sys/systm.h>
! 33: #include <sys/malloc.h>
! 34: #include <sys/conf.h>
! 35: #include <sys/device.h>
! 36: #include <sys/sensors.h>
! 37:
! 38: #include <machine/bus.h>
! 39: #include <machine/endian.h>
! 40: #include <machine/intr.h>
! 41:
! 42: #include <dev/pci/pcireg.h>
! 43: #include <dev/pci/pcivar.h>
! 44: #include <dev/pci/pcidevs.h>
! 45:
! 46: #if NBPFILTER > 0
! 47: #include <net/bpf.h>
! 48: #endif
! 49: #include <net/if.h>
! 50: #include <net/if_arp.h>
! 51: #include <net/if_dl.h>
! 52: #include <net/if_media.h>
! 53: #include <net/if_types.h>
! 54:
! 55: #include <netinet/in.h>
! 56: #include <netinet/in_systm.h>
! 57: #include <netinet/in_var.h>
! 58: #include <netinet/if_ether.h>
! 59: #include <netinet/ip.h>
! 60:
! 61: #include <net80211/ieee80211_var.h>
! 62: #include <net80211/ieee80211_amrr.h>
! 63: #include <net80211/ieee80211_radiotap.h>
! 64:
! 65: #include <dev/pci/if_wpireg.h>
! 66: #include <dev/pci/if_wpivar.h>
! 67:
! 68: static const struct pci_matchid wpi_devices[] = {
! 69: { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_PRO_WL_3945ABG_1 },
! 70: { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_PRO_WL_3945ABG_2 }
! 71: };
! 72:
! 73: int wpi_match(struct device *, void *, void *);
! 74: void wpi_attach(struct device *, struct device *, void *);
! 75: void wpi_power(int, void *);
! 76: int wpi_dma_contig_alloc(bus_dma_tag_t, struct wpi_dma_info *,
! 77: void **, bus_size_t, bus_size_t, int);
! 78: void wpi_dma_contig_free(struct wpi_dma_info *);
! 79: int wpi_alloc_shared(struct wpi_softc *);
! 80: void wpi_free_shared(struct wpi_softc *);
! 81: int wpi_alloc_fwmem(struct wpi_softc *);
! 82: void wpi_free_fwmem(struct wpi_softc *);
! 83: struct wpi_rbuf *wpi_alloc_rbuf(struct wpi_softc *);
! 84: void wpi_free_rbuf(caddr_t, u_int, void *);
! 85: int wpi_alloc_rpool(struct wpi_softc *);
! 86: void wpi_free_rpool(struct wpi_softc *);
! 87: int wpi_alloc_rx_ring(struct wpi_softc *, struct wpi_rx_ring *);
! 88: void wpi_reset_rx_ring(struct wpi_softc *, struct wpi_rx_ring *);
! 89: void wpi_free_rx_ring(struct wpi_softc *, struct wpi_rx_ring *);
! 90: int wpi_alloc_tx_ring(struct wpi_softc *, struct wpi_tx_ring *,
! 91: int, int);
! 92: void wpi_reset_tx_ring(struct wpi_softc *, struct wpi_tx_ring *);
! 93: void wpi_free_tx_ring(struct wpi_softc *, struct wpi_tx_ring *);
! 94: struct ieee80211_node *wpi_node_alloc(struct ieee80211com *);
! 95: void wpi_newassoc(struct ieee80211com *, struct ieee80211_node *,
! 96: int);
! 97: int wpi_media_change(struct ifnet *);
! 98: int wpi_newstate(struct ieee80211com *, enum ieee80211_state, int);
! 99: void wpi_mem_lock(struct wpi_softc *);
! 100: void wpi_mem_unlock(struct wpi_softc *);
! 101: uint32_t wpi_mem_read(struct wpi_softc *, uint16_t);
! 102: void wpi_mem_write(struct wpi_softc *, uint16_t, uint32_t);
! 103: void wpi_mem_write_region_4(struct wpi_softc *, uint16_t,
! 104: const uint32_t *, int);
! 105: int wpi_read_prom_data(struct wpi_softc *, uint32_t, void *, int);
! 106: int wpi_load_microcode(struct wpi_softc *, const uint8_t *, int);
! 107: int wpi_load_firmware(struct wpi_softc *);
! 108: void wpi_calib_timeout(void *);
! 109: void wpi_iter_func(void *, struct ieee80211_node *);
! 110: void wpi_power_calibration(struct wpi_softc *, int);
! 111: void wpi_rx_intr(struct wpi_softc *, struct wpi_rx_desc *,
! 112: struct wpi_rx_data *);
! 113: void wpi_tx_intr(struct wpi_softc *, struct wpi_rx_desc *);
! 114: void wpi_cmd_intr(struct wpi_softc *, struct wpi_rx_desc *);
! 115: void wpi_notif_intr(struct wpi_softc *);
! 116: int wpi_intr(void *);
! 117: void wpi_read_eeprom(struct wpi_softc *);
! 118: void wpi_read_eeprom_channels(struct wpi_softc *, int);
! 119: void wpi_read_eeprom_group(struct wpi_softc *, int);
! 120: uint8_t wpi_plcp_signal(int);
! 121: int wpi_tx_data(struct wpi_softc *, struct mbuf *,
! 122: struct ieee80211_node *, int);
! 123: void wpi_start(struct ifnet *);
! 124: void wpi_watchdog(struct ifnet *);
! 125: int wpi_ioctl(struct ifnet *, u_long, caddr_t);
! 126: int wpi_cmd(struct wpi_softc *, int, const void *, int, int);
! 127: int wpi_mrr_setup(struct wpi_softc *);
! 128: void wpi_set_led(struct wpi_softc *, uint8_t, uint8_t, uint8_t);
! 129: void wpi_enable_tsf(struct wpi_softc *, struct ieee80211_node *);
! 130: int wpi_set_txpower(struct wpi_softc *,
! 131: struct ieee80211_channel *, int);
! 132: int wpi_get_power_index(struct wpi_softc *,
! 133: struct wpi_power_group *, struct ieee80211_channel *, int);
! 134: #ifdef notyet
! 135: int wpi_setup_beacon(struct wpi_softc *, struct ieee80211_node *);
! 136: #endif
! 137: int wpi_auth(struct wpi_softc *);
! 138: int wpi_scan(struct wpi_softc *, uint16_t);
! 139: int wpi_config(struct wpi_softc *);
! 140: void wpi_stop_master(struct wpi_softc *);
! 141: int wpi_power_up(struct wpi_softc *);
! 142: int wpi_reset(struct wpi_softc *);
! 143: void wpi_hw_config(struct wpi_softc *);
! 144: int wpi_init(struct ifnet *);
! 145: void wpi_stop(struct ifnet *, int);
! 146:
! 147: #ifdef WPI_DEBUG
! 148: #define DPRINTF(x) do { if (wpi_debug > 0) printf x; } while (0)
! 149: #define DPRINTFN(n, x) do { if (wpi_debug >= (n)) printf x; } while (0)
! 150: int wpi_debug = 1;
! 151: #else
! 152: #define DPRINTF(x)
! 153: #define DPRINTFN(n, x)
! 154: #endif
! 155:
! 156: struct cfattach wpi_ca = {
! 157: sizeof (struct wpi_softc), wpi_match, wpi_attach
! 158: };
! 159:
! 160: int
! 161: wpi_match(struct device *parent, void *match, void *aux)
! 162: {
! 163: return pci_matchbyid((struct pci_attach_args *)aux, wpi_devices,
! 164: sizeof (wpi_devices) / sizeof (wpi_devices[0]));
! 165: }
! 166:
! 167: /* Base Address Register */
! 168: #define WPI_PCI_BAR0 0x10
! 169:
! 170: void
! 171: wpi_attach(struct device *parent, struct device *self, void *aux)
! 172: {
! 173: struct wpi_softc *sc = (struct wpi_softc *)self;
! 174: struct ieee80211com *ic = &sc->sc_ic;
! 175: struct ifnet *ifp = &ic->ic_if;
! 176: struct pci_attach_args *pa = aux;
! 177: const char *intrstr;
! 178: bus_space_tag_t memt;
! 179: bus_space_handle_t memh;
! 180: pci_intr_handle_t ih;
! 181: pcireg_t data;
! 182: int ac, error;
! 183:
! 184: sc->sc_pct = pa->pa_pc;
! 185: sc->sc_pcitag = pa->pa_tag;
! 186:
! 187: /* clear device specific PCI configuration register 0x41 */
! 188: data = pci_conf_read(sc->sc_pct, sc->sc_pcitag, 0x40);
! 189: data &= ~0x0000ff00;
! 190: pci_conf_write(sc->sc_pct, sc->sc_pcitag, 0x40, data);
! 191:
! 192: /* map the register window */
! 193: error = pci_mapreg_map(pa, WPI_PCI_BAR0, PCI_MAPREG_TYPE_MEM |
! 194: PCI_MAPREG_MEM_TYPE_32BIT, 0, &memt, &memh, NULL, &sc->sc_sz, 0);
! 195: if (error != 0) {
! 196: printf(": could not map memory space\n");
! 197: return;
! 198: }
! 199:
! 200: sc->sc_st = memt;
! 201: sc->sc_sh = memh;
! 202: sc->sc_dmat = pa->pa_dmat;
! 203:
! 204: if (pci_intr_map(pa, &ih) != 0) {
! 205: printf(": could not map interrupt\n");
! 206: return;
! 207: }
! 208:
! 209: intrstr = pci_intr_string(sc->sc_pct, ih);
! 210: sc->sc_ih = pci_intr_establish(sc->sc_pct, ih, IPL_NET, wpi_intr, sc,
! 211: sc->sc_dev.dv_xname);
! 212: if (sc->sc_ih == NULL) {
! 213: printf(": could not establish interrupt");
! 214: if (intrstr != NULL)
! 215: printf(" at %s", intrstr);
! 216: printf("\n");
! 217: return;
! 218: }
! 219: printf(": %s", intrstr);
! 220:
! 221: /*
! 222: * Put adapter into a known state.
! 223: */
! 224: if ((error = wpi_reset(sc)) != 0) {
! 225: printf(": could not reset adapter\n");
! 226: return;
! 227: }
! 228:
! 229: /*
! 230: * Allocate DMA memory for firmware transfers.
! 231: */
! 232: if ((error = wpi_alloc_fwmem(sc)) != 0) {
! 233: printf(": could not allocate firmware memory\n");
! 234: return;
! 235: }
! 236:
! 237: /*
! 238: * Allocate shared page and Tx/Rx rings.
! 239: */
! 240: if ((error = wpi_alloc_shared(sc)) != 0) {
! 241: printf(": could not allocate shared area\n");
! 242: goto fail1;
! 243: }
! 244:
! 245: if ((error = wpi_alloc_rpool(sc)) != 0) {
! 246: printf(": could not allocate Rx buffers\n");
! 247: goto fail2;
! 248: }
! 249:
! 250: for (ac = 0; ac < 4; ac++) {
! 251: error = wpi_alloc_tx_ring(sc, &sc->txq[ac], WPI_TX_RING_COUNT,
! 252: ac);
! 253: if (error != 0) {
! 254: printf(": could not allocate Tx ring %d\n", ac);
! 255: goto fail3;
! 256: }
! 257: }
! 258:
! 259: error = wpi_alloc_tx_ring(sc, &sc->cmdq, WPI_CMD_RING_COUNT, 4);
! 260: if (error != 0) {
! 261: printf(": could not allocate command ring\n");
! 262: goto fail3;
! 263: }
! 264:
! 265: error = wpi_alloc_rx_ring(sc, &sc->rxq);
! 266: if (error != 0) {
! 267: printf(": could not allocate Rx ring\n");
! 268: goto fail4;
! 269: }
! 270:
! 271: ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */
! 272: ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */
! 273: ic->ic_state = IEEE80211_S_INIT;
! 274:
! 275: /* set device capabilities */
! 276: ic->ic_caps =
! 277: IEEE80211_C_WEP | /* s/w WEP */
! 278: IEEE80211_C_MONITOR | /* monitor mode supported */
! 279: IEEE80211_C_TXPMGT | /* tx power management */
! 280: IEEE80211_C_SHSLOT | /* short slot time supported */
! 281: IEEE80211_C_SHPREAMBLE; /* short preamble supported */
! 282:
! 283: /* read supported channels and MAC address from EEPROM */
! 284: wpi_read_eeprom(sc);
! 285:
! 286: /* set supported .11a, .11b and .11g rates */
! 287: ic->ic_sup_rates[IEEE80211_MODE_11A] = ieee80211_std_rateset_11a;
! 288: ic->ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b;
! 289: ic->ic_sup_rates[IEEE80211_MODE_11G] = ieee80211_std_rateset_11g;
! 290:
! 291: /* IBSS channel undefined for now */
! 292: ic->ic_ibss_chan = &ic->ic_channels[0];
! 293:
! 294: ifp->if_softc = sc;
! 295: ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
! 296: ifp->if_init = wpi_init;
! 297: ifp->if_ioctl = wpi_ioctl;
! 298: ifp->if_start = wpi_start;
! 299: ifp->if_watchdog = wpi_watchdog;
! 300: IFQ_SET_READY(&ifp->if_snd);
! 301: memcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ);
! 302:
! 303: if_attach(ifp);
! 304: ieee80211_ifattach(ifp);
! 305: ic->ic_node_alloc = wpi_node_alloc;
! 306: ic->ic_newassoc = wpi_newassoc;
! 307:
! 308: /* override state transition machine */
! 309: sc->sc_newstate = ic->ic_newstate;
! 310: ic->ic_newstate = wpi_newstate;
! 311: ieee80211_media_init(ifp, wpi_media_change, ieee80211_media_status);
! 312:
! 313: sc->amrr.amrr_min_success_threshold = 1;
! 314: sc->amrr.amrr_max_success_threshold = 15;
! 315:
! 316: /* register thermal sensor with the sensor framework */
! 317: strlcpy(sc->sensordev.xname, sc->sc_dev.dv_xname,
! 318: sizeof sc->sensordev.xname);
! 319: strlcpy(sc->sensor.desc, "temperature 0 - 285",
! 320: sizeof sc->sensor.desc);
! 321: sc->sensor.type = SENSOR_INTEGER; /* not in muK! */
! 322: /* temperature invalid until interface is up */
! 323: sc->sensor.value = 0;
! 324: sc->sensor.flags = SENSOR_FINVALID;
! 325: sensor_attach(&sc->sensordev, &sc->sensor);
! 326: sensordev_install(&sc->sensordev);
! 327:
! 328: timeout_set(&sc->calib_to, wpi_calib_timeout, sc);
! 329:
! 330: sc->powerhook = powerhook_establish(wpi_power, sc);
! 331:
! 332: #if NBPFILTER > 0
! 333: bpfattach(&sc->sc_drvbpf, ifp, DLT_IEEE802_11_RADIO,
! 334: sizeof (struct ieee80211_frame) + IEEE80211_RADIOTAP_HDRLEN);
! 335:
! 336: sc->sc_rxtap_len = sizeof sc->sc_rxtapu;
! 337: sc->sc_rxtap.wr_ihdr.it_len = htole16(sc->sc_rxtap_len);
! 338: sc->sc_rxtap.wr_ihdr.it_present = htole32(WPI_RX_RADIOTAP_PRESENT);
! 339:
! 340: sc->sc_txtap_len = sizeof sc->sc_txtapu;
! 341: sc->sc_txtap.wt_ihdr.it_len = htole16(sc->sc_txtap_len);
! 342: sc->sc_txtap.wt_ihdr.it_present = htole32(WPI_TX_RADIOTAP_PRESENT);
! 343: #endif
! 344:
! 345: return;
! 346:
! 347: /* free allocated memory if something failed during attachment */
! 348: fail4: wpi_free_tx_ring(sc, &sc->cmdq);
! 349: fail3: while (--ac >= 0)
! 350: wpi_free_tx_ring(sc, &sc->txq[ac]);
! 351: wpi_free_rpool(sc);
! 352: fail2: wpi_free_shared(sc);
! 353: fail1: wpi_free_fwmem(sc);
! 354: }
! 355:
! 356: void
! 357: wpi_power(int why, void *arg)
! 358: {
! 359: struct wpi_softc *sc = arg;
! 360: struct ifnet *ifp;
! 361: pcireg_t data;
! 362: int s;
! 363:
! 364: if (why != PWR_RESUME)
! 365: return;
! 366:
! 367: /* clear device specific PCI configuration register 0x41 */
! 368: data = pci_conf_read(sc->sc_pct, sc->sc_pcitag, 0x40);
! 369: data &= ~0x0000ff00;
! 370: pci_conf_write(sc->sc_pct, sc->sc_pcitag, 0x40, data);
! 371:
! 372: s = splnet();
! 373: ifp = &sc->sc_ic.ic_if;
! 374: if (ifp->if_flags & IFF_UP) {
! 375: ifp->if_init(ifp);
! 376: if (ifp->if_flags & IFF_RUNNING)
! 377: ifp->if_start(ifp);
! 378: }
! 379: splx(s);
! 380: }
! 381:
! 382: int
! 383: wpi_dma_contig_alloc(bus_dma_tag_t tag, struct wpi_dma_info *dma, void **kvap,
! 384: bus_size_t size, bus_size_t alignment, int flags)
! 385: {
! 386: int nsegs, error;
! 387:
! 388: dma->tag = tag;
! 389: dma->size = size;
! 390:
! 391: error = bus_dmamap_create(tag, size, 1, size, 0, flags, &dma->map);
! 392: if (error != 0)
! 393: goto fail;
! 394:
! 395: error = bus_dmamem_alloc(tag, size, alignment, 0, &dma->seg, 1, &nsegs,
! 396: flags);
! 397: if (error != 0)
! 398: goto fail;
! 399:
! 400: error = bus_dmamem_map(tag, &dma->seg, 1, size, &dma->vaddr, flags);
! 401: if (error != 0)
! 402: goto fail;
! 403:
! 404: error = bus_dmamap_load_raw(tag, dma->map, &dma->seg, 1, size, flags);
! 405: if (error != 0)
! 406: goto fail;
! 407:
! 408: memset(dma->vaddr, 0, size);
! 409:
! 410: dma->paddr = dma->map->dm_segs[0].ds_addr;
! 411: if (kvap != NULL)
! 412: *kvap = dma->vaddr;
! 413:
! 414: return 0;
! 415:
! 416: fail: wpi_dma_contig_free(dma);
! 417: return error;
! 418: }
! 419:
! 420: void
! 421: wpi_dma_contig_free(struct wpi_dma_info *dma)
! 422: {
! 423: if (dma->map != NULL) {
! 424: if (dma->vaddr != NULL) {
! 425: bus_dmamap_unload(dma->tag, dma->map);
! 426: bus_dmamem_unmap(dma->tag, dma->vaddr, dma->size);
! 427: bus_dmamem_free(dma->tag, &dma->seg, 1);
! 428: dma->vaddr = NULL;
! 429: }
! 430: bus_dmamap_destroy(dma->tag, dma->map);
! 431: dma->map = NULL;
! 432: }
! 433: }
! 434:
! 435: /*
! 436: * Allocate a shared page between host and NIC.
! 437: */
! 438: int
! 439: wpi_alloc_shared(struct wpi_softc *sc)
! 440: {
! 441: /* must be aligned on a 4K-page boundary */
! 442: return wpi_dma_contig_alloc(sc->sc_dmat, &sc->shared_dma,
! 443: (void **)&sc->shared, sizeof (struct wpi_shared), PAGE_SIZE,
! 444: BUS_DMA_NOWAIT);
! 445: }
! 446:
! 447: void
! 448: wpi_free_shared(struct wpi_softc *sc)
! 449: {
! 450: wpi_dma_contig_free(&sc->shared_dma);
! 451: }
! 452:
! 453: /*
! 454: * Allocate DMA-safe memory for firmware transfer.
! 455: */
! 456: int
! 457: wpi_alloc_fwmem(struct wpi_softc *sc)
! 458: {
! 459: /* allocate enough contiguous space to store text and data */
! 460: return wpi_dma_contig_alloc(sc->sc_dmat, &sc->fw_dma, NULL,
! 461: WPI_FW_MAIN_TEXT_MAXSZ + WPI_FW_MAIN_DATA_MAXSZ, 0,
! 462: BUS_DMA_NOWAIT);
! 463: }
! 464:
! 465: void
! 466: wpi_free_fwmem(struct wpi_softc *sc)
! 467: {
! 468: wpi_dma_contig_free(&sc->fw_dma);
! 469: }
! 470:
! 471: struct wpi_rbuf *
! 472: wpi_alloc_rbuf(struct wpi_softc *sc)
! 473: {
! 474: struct wpi_rbuf *rbuf;
! 475:
! 476: rbuf = SLIST_FIRST(&sc->rxq.freelist);
! 477: if (rbuf == NULL)
! 478: return NULL;
! 479: SLIST_REMOVE_HEAD(&sc->rxq.freelist, next);
! 480: return rbuf;
! 481: }
! 482:
! 483: /*
! 484: * This is called automatically by the network stack when the mbuf to which our
! 485: * Rx buffer is attached is freed.
! 486: */
! 487: void
! 488: wpi_free_rbuf(caddr_t buf, u_int size, void *arg)
! 489: {
! 490: struct wpi_rbuf *rbuf = arg;
! 491: struct wpi_softc *sc = rbuf->sc;
! 492:
! 493: /* put the buffer back in the free list */
! 494: SLIST_INSERT_HEAD(&sc->rxq.freelist, rbuf, next);
! 495: }
! 496:
! 497: int
! 498: wpi_alloc_rpool(struct wpi_softc *sc)
! 499: {
! 500: struct wpi_rx_ring *ring = &sc->rxq;
! 501: int i, error;
! 502:
! 503: /* allocate a big chunk of DMA'able memory.. */
! 504: error = wpi_dma_contig_alloc(sc->sc_dmat, &ring->buf_dma, NULL,
! 505: WPI_RBUF_COUNT * WPI_RBUF_SIZE, PAGE_SIZE, BUS_DMA_NOWAIT);
! 506: if (error != 0) {
! 507: printf("%s: could not allocate Rx buffers DMA memory\n",
! 508: sc->sc_dev.dv_xname);
! 509: return error;
! 510: }
! 511:
! 512: /* ..and split it into 3KB chunks */
! 513: SLIST_INIT(&ring->freelist);
! 514: for (i = 0; i < WPI_RBUF_COUNT; i++) {
! 515: struct wpi_rbuf *rbuf = &ring->rbuf[i];
! 516:
! 517: rbuf->sc = sc; /* backpointer for callbacks */
! 518: rbuf->vaddr = ring->buf_dma.vaddr + i * WPI_RBUF_SIZE;
! 519: rbuf->paddr = ring->buf_dma.paddr + i * WPI_RBUF_SIZE;
! 520:
! 521: SLIST_INSERT_HEAD(&ring->freelist, rbuf, next);
! 522: }
! 523: return 0;
! 524: }
! 525:
! 526: void
! 527: wpi_free_rpool(struct wpi_softc *sc)
! 528: {
! 529: wpi_dma_contig_free(&sc->rxq.buf_dma);
! 530: }
! 531:
! 532: int
! 533: wpi_alloc_rx_ring(struct wpi_softc *sc, struct wpi_rx_ring *ring)
! 534: {
! 535: int i, error;
! 536:
! 537: ring->cur = 0;
! 538:
! 539: error = wpi_dma_contig_alloc(sc->sc_dmat, &ring->desc_dma,
! 540: (void **)&ring->desc, WPI_RX_RING_COUNT * sizeof (uint32_t),
! 541: WPI_RING_DMA_ALIGN, BUS_DMA_NOWAIT);
! 542: if (error != 0) {
! 543: printf("%s: could not allocate rx ring DMA memory\n",
! 544: sc->sc_dev.dv_xname);
! 545: goto fail;
! 546: }
! 547:
! 548: /*
! 549: * Setup Rx buffers.
! 550: */
! 551: for (i = 0; i < WPI_RX_RING_COUNT; i++) {
! 552: struct wpi_rx_data *data = &ring->data[i];
! 553: struct wpi_rbuf *rbuf;
! 554:
! 555: MGETHDR(data->m, M_DONTWAIT, MT_DATA);
! 556: if (data->m == NULL) {
! 557: printf("%s: could not allocate rx mbuf\n",
! 558: sc->sc_dev.dv_xname);
! 559: error = ENOMEM;
! 560: goto fail;
! 561: }
! 562: if ((rbuf = wpi_alloc_rbuf(sc)) == NULL) {
! 563: m_freem(data->m);
! 564: data->m = NULL;
! 565: printf("%s: could not allocate rx buffer\n",
! 566: sc->sc_dev.dv_xname);
! 567: error = ENOMEM;
! 568: goto fail;
! 569: }
! 570: /* attach Rx buffer to mbuf */
! 571: MEXTADD(data->m, rbuf->vaddr, WPI_RBUF_SIZE, 0, wpi_free_rbuf,
! 572: rbuf);
! 573:
! 574: ring->desc[i] = htole32(rbuf->paddr);
! 575: }
! 576:
! 577: return 0;
! 578:
! 579: fail: wpi_free_rx_ring(sc, ring);
! 580: return error;
! 581: }
! 582:
! 583: void
! 584: wpi_reset_rx_ring(struct wpi_softc *sc, struct wpi_rx_ring *ring)
! 585: {
! 586: int ntries;
! 587:
! 588: wpi_mem_lock(sc);
! 589:
! 590: WPI_WRITE(sc, WPI_RX_CONFIG, 0);
! 591: for (ntries = 0; ntries < 100; ntries++) {
! 592: if (WPI_READ(sc, WPI_RX_STATUS) & WPI_RX_IDLE)
! 593: break;
! 594: DELAY(10);
! 595: }
! 596: #ifdef WPI_DEBUG
! 597: if (ntries == 100 && wpi_debug > 0)
! 598: printf("%s: timeout resetting Rx ring\n", sc->sc_dev.dv_xname);
! 599: #endif
! 600: wpi_mem_unlock(sc);
! 601:
! 602: ring->cur = 0;
! 603: }
! 604:
! 605: void
! 606: wpi_free_rx_ring(struct wpi_softc *sc, struct wpi_rx_ring *ring)
! 607: {
! 608: int i;
! 609:
! 610: wpi_dma_contig_free(&ring->desc_dma);
! 611:
! 612: for (i = 0; i < WPI_RX_RING_COUNT; i++) {
! 613: if (ring->data[i].m != NULL)
! 614: m_freem(ring->data[i].m);
! 615: }
! 616: }
! 617:
! 618: int
! 619: wpi_alloc_tx_ring(struct wpi_softc *sc, struct wpi_tx_ring *ring, int count,
! 620: int qid)
! 621: {
! 622: int i, error;
! 623:
! 624: ring->qid = qid;
! 625: ring->count = count;
! 626: ring->queued = 0;
! 627: ring->cur = 0;
! 628:
! 629: error = wpi_dma_contig_alloc(sc->sc_dmat, &ring->desc_dma,
! 630: (void **)&ring->desc, count * sizeof (struct wpi_tx_desc),
! 631: WPI_RING_DMA_ALIGN, BUS_DMA_NOWAIT);
! 632: if (error != 0) {
! 633: printf("%s: could not allocate tx ring DMA memory\n",
! 634: sc->sc_dev.dv_xname);
! 635: goto fail;
! 636: }
! 637:
! 638: /* update shared page with ring's base address */
! 639: sc->shared->txbase[qid] = htole32(ring->desc_dma.paddr);
! 640:
! 641: error = wpi_dma_contig_alloc(sc->sc_dmat, &ring->cmd_dma,
! 642: (void **)&ring->cmd, count * sizeof (struct wpi_tx_cmd), 4,
! 643: BUS_DMA_NOWAIT);
! 644: if (error != 0) {
! 645: printf("%s: could not allocate tx cmd DMA memory\n",
! 646: sc->sc_dev.dv_xname);
! 647: goto fail;
! 648: }
! 649:
! 650: ring->data = malloc(count * sizeof (struct wpi_tx_data), M_DEVBUF,
! 651: M_NOWAIT);
! 652: if (ring->data == NULL) {
! 653: printf("%s: could not allocate tx data slots\n",
! 654: sc->sc_dev.dv_xname);
! 655: goto fail;
! 656: }
! 657:
! 658: memset(ring->data, 0, count * sizeof (struct wpi_tx_data));
! 659:
! 660: for (i = 0; i < count; i++) {
! 661: struct wpi_tx_data *data = &ring->data[i];
! 662:
! 663: error = bus_dmamap_create(sc->sc_dmat, MCLBYTES,
! 664: WPI_MAX_SCATTER - 1, MCLBYTES, 0, BUS_DMA_NOWAIT,
! 665: &data->map);
! 666: if (error != 0) {
! 667: printf("%s: could not create tx buf DMA map\n",
! 668: sc->sc_dev.dv_xname);
! 669: goto fail;
! 670: }
! 671: }
! 672:
! 673: return 0;
! 674:
! 675: fail: wpi_free_tx_ring(sc, ring);
! 676: return error;
! 677: }
! 678:
! 679: void
! 680: wpi_reset_tx_ring(struct wpi_softc *sc, struct wpi_tx_ring *ring)
! 681: {
! 682: int i, ntries;
! 683:
! 684: wpi_mem_lock(sc);
! 685:
! 686: WPI_WRITE(sc, WPI_TX_CONFIG(ring->qid), 0);
! 687: for (ntries = 0; ntries < 100; ntries++) {
! 688: if (WPI_READ(sc, WPI_TX_STATUS) & WPI_TX_IDLE(ring->qid))
! 689: break;
! 690: DELAY(10);
! 691: }
! 692: #ifdef WPI_DEBUG
! 693: if (ntries == 100 && wpi_debug > 0) {
! 694: printf("%s: timeout resetting Tx ring %d\n",
! 695: sc->sc_dev.dv_xname, ring->qid);
! 696: }
! 697: #endif
! 698: wpi_mem_unlock(sc);
! 699:
! 700: for (i = 0; i < ring->count; i++) {
! 701: struct wpi_tx_data *data = &ring->data[i];
! 702:
! 703: if (data->m != NULL) {
! 704: bus_dmamap_unload(sc->sc_dmat, data->map);
! 705: m_freem(data->m);
! 706: data->m = NULL;
! 707: }
! 708: }
! 709:
! 710: ring->queued = 0;
! 711: ring->cur = 0;
! 712: }
! 713:
! 714: void
! 715: wpi_free_tx_ring(struct wpi_softc *sc, struct wpi_tx_ring *ring)
! 716: {
! 717: int i;
! 718:
! 719: wpi_dma_contig_free(&ring->desc_dma);
! 720: wpi_dma_contig_free(&ring->cmd_dma);
! 721:
! 722: if (ring->data != NULL) {
! 723: for (i = 0; i < ring->count; i++) {
! 724: struct wpi_tx_data *data = &ring->data[i];
! 725:
! 726: if (data->m != NULL) {
! 727: bus_dmamap_unload(sc->sc_dmat, data->map);
! 728: m_freem(data->m);
! 729: }
! 730: }
! 731: free(ring->data, M_DEVBUF);
! 732: }
! 733: }
! 734:
! 735: struct ieee80211_node *
! 736: wpi_node_alloc(struct ieee80211com *ic)
! 737: {
! 738: struct wpi_node *wn;
! 739:
! 740: wn = malloc(sizeof (struct wpi_node), M_DEVBUF, M_NOWAIT);
! 741: if (wn != NULL)
! 742: memset(wn, 0, sizeof (struct wpi_node));
! 743: return (struct ieee80211_node *)wn;
! 744: }
! 745:
! 746: void
! 747: wpi_newassoc(struct ieee80211com *ic, struct ieee80211_node *ni, int isnew)
! 748: {
! 749: struct wpi_softc *sc = ic->ic_if.if_softc;
! 750: int i;
! 751:
! 752: ieee80211_amrr_node_init(&sc->amrr, &((struct wpi_node *)ni)->amn);
! 753:
! 754: /* set rate to some reasonable initial value */
! 755: for (i = ni->ni_rates.rs_nrates - 1;
! 756: i > 0 && (ni->ni_rates.rs_rates[i] & IEEE80211_RATE_VAL) > 72;
! 757: i--);
! 758: ni->ni_txrate = i;
! 759: }
! 760:
! 761: int
! 762: wpi_media_change(struct ifnet *ifp)
! 763: {
! 764: int error;
! 765:
! 766: error = ieee80211_media_change(ifp);
! 767: if (error != ENETRESET)
! 768: return error;
! 769:
! 770: if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == (IFF_UP | IFF_RUNNING))
! 771: wpi_init(ifp);
! 772:
! 773: return 0;
! 774: }
! 775:
! 776: int
! 777: wpi_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
! 778: {
! 779: struct ifnet *ifp = &ic->ic_if;
! 780: struct wpi_softc *sc = ifp->if_softc;
! 781: struct ieee80211_node *ni;
! 782: int error;
! 783:
! 784: timeout_del(&sc->calib_to);
! 785:
! 786: if (ic->ic_state == IEEE80211_S_SCAN)
! 787: ic->ic_scan_lock = IEEE80211_SCAN_UNLOCKED;
! 788:
! 789: switch (nstate) {
! 790: case IEEE80211_S_SCAN:
! 791: /* make the link LED blink while we're scanning */
! 792: wpi_set_led(sc, WPI_LED_LINK, 20, 2);
! 793:
! 794: if ((error = wpi_scan(sc, IEEE80211_CHAN_G)) != 0) {
! 795: printf("%s: could not initiate scan\n",
! 796: sc->sc_dev.dv_xname);
! 797: return error;
! 798: }
! 799: ic->ic_state = nstate;
! 800: return 0;
! 801:
! 802: case IEEE80211_S_ASSOC:
! 803: if (ic->ic_state != IEEE80211_S_RUN)
! 804: break;
! 805: /* FALLTHROUGH */
! 806: case IEEE80211_S_AUTH:
! 807: /* reset state to handle reassociations correctly */
! 808: sc->config.associd = 0;
! 809: sc->config.filter &= ~htole32(WPI_FILTER_BSS);
! 810:
! 811: if ((error = wpi_auth(sc)) != 0) {
! 812: printf("%s: could not send authentication request\n",
! 813: sc->sc_dev.dv_xname);
! 814: return error;
! 815: }
! 816: break;
! 817:
! 818: case IEEE80211_S_RUN:
! 819: if (ic->ic_opmode == IEEE80211_M_MONITOR) {
! 820: /* link LED blinks while monitoring */
! 821: wpi_set_led(sc, WPI_LED_LINK, 5, 5);
! 822: break;
! 823: }
! 824: ni = ic->ic_bss;
! 825:
! 826: wpi_enable_tsf(sc, ni);
! 827:
! 828: /* update adapter's configuration */
! 829: sc->config.associd = htole16(ni->ni_associd & ~0xc000);
! 830: /* short preamble/slot time are negotiated when associating */
! 831: sc->config.flags &= ~htole32(WPI_CONFIG_SHPREAMBLE |
! 832: WPI_CONFIG_SHSLOT);
! 833: if (ic->ic_flags & IEEE80211_F_SHSLOT)
! 834: sc->config.flags |= htole32(WPI_CONFIG_SHSLOT);
! 835: if (ic->ic_flags & IEEE80211_F_SHPREAMBLE)
! 836: sc->config.flags |= htole32(WPI_CONFIG_SHPREAMBLE);
! 837: sc->config.filter |= htole32(WPI_FILTER_BSS);
! 838:
! 839: DPRINTF(("config chan %d flags %x\n", sc->config.chan,
! 840: sc->config.flags));
! 841: error = wpi_cmd(sc, WPI_CMD_CONFIGURE, &sc->config,
! 842: sizeof (struct wpi_config), 1);
! 843: if (error != 0) {
! 844: printf("%s: could not update configuration\n",
! 845: sc->sc_dev.dv_xname);
! 846: return error;
! 847: }
! 848:
! 849: /* configuration has changed, set Tx power accordingly */
! 850: if ((error = wpi_set_txpower(sc, ni->ni_chan, 1)) != 0) {
! 851: printf("%s: could not set Tx power\n",
! 852: sc->sc_dev.dv_xname);
! 853: return error;
! 854: }
! 855:
! 856: if (ic->ic_opmode == IEEE80211_M_STA) {
! 857: /* fake a join to init the tx rate */
! 858: wpi_newassoc(ic, ni, 1);
! 859: }
! 860:
! 861: /* start periodic calibration timer */
! 862: sc->calib_cnt = 0;
! 863: timeout_add(&sc->calib_to, hz / 2);
! 864:
! 865: /* link LED always on while associated */
! 866: wpi_set_led(sc, WPI_LED_LINK, 0, 1);
! 867: break;
! 868:
! 869: case IEEE80211_S_INIT:
! 870: break;
! 871: }
! 872:
! 873: return sc->sc_newstate(ic, nstate, arg);
! 874: }
! 875:
! 876: /*
! 877: * Grab exclusive access to NIC memory.
! 878: */
! 879: void
! 880: wpi_mem_lock(struct wpi_softc *sc)
! 881: {
! 882: uint32_t tmp;
! 883: int ntries;
! 884:
! 885: tmp = WPI_READ(sc, WPI_GPIO_CTL);
! 886: WPI_WRITE(sc, WPI_GPIO_CTL, tmp | WPI_GPIO_MAC);
! 887:
! 888: /* spin until we actually get the lock */
! 889: for (ntries = 0; ntries < 1000; ntries++) {
! 890: if ((WPI_READ(sc, WPI_GPIO_CTL) &
! 891: (WPI_GPIO_CLOCK | WPI_GPIO_SLEEP)) == WPI_GPIO_CLOCK)
! 892: break;
! 893: DELAY(10);
! 894: }
! 895: if (ntries == 1000)
! 896: printf("%s: could not lock memory\n", sc->sc_dev.dv_xname);
! 897: }
! 898:
! 899: /*
! 900: * Release lock on NIC memory.
! 901: */
! 902: void
! 903: wpi_mem_unlock(struct wpi_softc *sc)
! 904: {
! 905: uint32_t tmp = WPI_READ(sc, WPI_GPIO_CTL);
! 906: WPI_WRITE(sc, WPI_GPIO_CTL, tmp & ~WPI_GPIO_MAC);
! 907: }
! 908:
! 909: uint32_t
! 910: wpi_mem_read(struct wpi_softc *sc, uint16_t addr)
! 911: {
! 912: WPI_WRITE(sc, WPI_READ_MEM_ADDR, WPI_MEM_4 | addr);
! 913: return WPI_READ(sc, WPI_READ_MEM_DATA);
! 914: }
! 915:
! 916: void
! 917: wpi_mem_write(struct wpi_softc *sc, uint16_t addr, uint32_t data)
! 918: {
! 919: WPI_WRITE(sc, WPI_WRITE_MEM_ADDR, WPI_MEM_4 | addr);
! 920: WPI_WRITE(sc, WPI_WRITE_MEM_DATA, data);
! 921: }
! 922:
! 923: void
! 924: wpi_mem_write_region_4(struct wpi_softc *sc, uint16_t addr,
! 925: const uint32_t *data, int wlen)
! 926: {
! 927: for (; wlen > 0; wlen--, data++, addr += 4)
! 928: wpi_mem_write(sc, addr, *data);
! 929: }
! 930:
! 931: /*
! 932: * Read `len' bytes from the EEPROM. We access the EEPROM through the MAC
! 933: * instead of using the traditional bit-bang method.
! 934: */
! 935: int
! 936: wpi_read_prom_data(struct wpi_softc *sc, uint32_t addr, void *data, int len)
! 937: {
! 938: uint8_t *out = data;
! 939: uint32_t val;
! 940: int ntries;
! 941:
! 942: wpi_mem_lock(sc);
! 943: for (; len > 0; len -= 2, addr++) {
! 944: WPI_WRITE(sc, WPI_EEPROM_CTL, addr << 2);
! 945:
! 946: for (ntries = 0; ntries < 10; ntries++) {
! 947: if ((val = WPI_READ(sc, WPI_EEPROM_CTL)) &
! 948: WPI_EEPROM_READY)
! 949: break;
! 950: DELAY(5);
! 951: }
! 952: if (ntries == 10) {
! 953: printf("%s: could not read EEPROM\n",
! 954: sc->sc_dev.dv_xname);
! 955: return ETIMEDOUT;
! 956: }
! 957: *out++ = val >> 16;
! 958: if (len > 1)
! 959: *out++ = val >> 24;
! 960: }
! 961: wpi_mem_unlock(sc);
! 962:
! 963: return 0;
! 964: }
! 965:
! 966: /*
! 967: * The firmware boot code is small and is intended to be copied directly into
! 968: * the NIC internal memory.
! 969: */
! 970: int
! 971: wpi_load_microcode(struct wpi_softc *sc, const uint8_t *ucode, int size)
! 972: {
! 973: int ntries;
! 974:
! 975: size /= sizeof (uint32_t);
! 976:
! 977: wpi_mem_lock(sc);
! 978:
! 979: /* copy microcode image into NIC memory */
! 980: wpi_mem_write_region_4(sc, WPI_MEM_UCODE_BASE,
! 981: (const uint32_t *)ucode, size);
! 982:
! 983: wpi_mem_write(sc, WPI_MEM_UCODE_SRC, 0);
! 984: wpi_mem_write(sc, WPI_MEM_UCODE_DST, WPI_FW_TEXT);
! 985: wpi_mem_write(sc, WPI_MEM_UCODE_SIZE, size);
! 986:
! 987: /* run microcode */
! 988: wpi_mem_write(sc, WPI_MEM_UCODE_CTL, WPI_UC_RUN);
! 989:
! 990: /* wait for transfer to complete */
! 991: for (ntries = 0; ntries < 1000; ntries++) {
! 992: if (!(wpi_mem_read(sc, WPI_MEM_UCODE_CTL) & WPI_UC_RUN))
! 993: break;
! 994: DELAY(10);
! 995: }
! 996: if (ntries == 1000) {
! 997: wpi_mem_unlock(sc);
! 998: printf("%s: could not load boot firmware\n",
! 999: sc->sc_dev.dv_xname);
! 1000: return ETIMEDOUT;
! 1001: }
! 1002: wpi_mem_write(sc, WPI_MEM_UCODE_CTL, WPI_UC_ENABLE);
! 1003:
! 1004: wpi_mem_unlock(sc);
! 1005:
! 1006: return 0;
! 1007: }
! 1008:
! 1009: int
! 1010: wpi_load_firmware(struct wpi_softc *sc)
! 1011: {
! 1012: struct wpi_dma_info *dma = &sc->fw_dma;
! 1013: const struct wpi_firmware_hdr *hdr;
! 1014: const uint8_t *init_text, *init_data, *main_text, *main_data;
! 1015: const uint8_t *boot_text;
! 1016: uint32_t init_textsz, init_datasz, main_textsz, main_datasz;
! 1017: uint32_t boot_textsz;
! 1018: u_char *fw;
! 1019: size_t size;
! 1020: int error;
! 1021:
! 1022: /* load firmware image from disk */
! 1023: if ((error = loadfirmware("wpi-3945abg", &fw, &size)) != 0) {
! 1024: printf("%s: could not read firmware file\n",
! 1025: sc->sc_dev.dv_xname);
! 1026: goto fail1;
! 1027: }
! 1028:
! 1029: /* extract firmware header information */
! 1030: if (size < sizeof (struct wpi_firmware_hdr)) {
! 1031: printf("%s: truncated firmware header: %d bytes\n",
! 1032: sc->sc_dev.dv_xname, size);
! 1033: error = EINVAL;
! 1034: goto fail2;
! 1035: }
! 1036: hdr = (const struct wpi_firmware_hdr *)fw;
! 1037: main_textsz = letoh32(hdr->main_textsz);
! 1038: main_datasz = letoh32(hdr->main_datasz);
! 1039: init_textsz = letoh32(hdr->init_textsz);
! 1040: init_datasz = letoh32(hdr->init_datasz);
! 1041: boot_textsz = letoh32(hdr->boot_textsz);
! 1042:
! 1043: /* sanity-check firmware segments sizes */
! 1044: if (main_textsz > WPI_FW_MAIN_TEXT_MAXSZ ||
! 1045: main_datasz > WPI_FW_MAIN_DATA_MAXSZ ||
! 1046: init_textsz > WPI_FW_INIT_TEXT_MAXSZ ||
! 1047: init_datasz > WPI_FW_INIT_DATA_MAXSZ ||
! 1048: boot_textsz > WPI_FW_BOOT_TEXT_MAXSZ ||
! 1049: (boot_textsz & 3) != 0) {
! 1050: printf("%s: invalid firmware header\n", sc->sc_dev.dv_xname);
! 1051: error = EINVAL;
! 1052: goto fail2;
! 1053: }
! 1054:
! 1055: /* check that all firmware segments are present */
! 1056: if (size < sizeof (struct wpi_firmware_hdr) + main_textsz +
! 1057: main_datasz + init_textsz + init_datasz + boot_textsz) {
! 1058: printf("%s: firmware file too short: %d bytes\n",
! 1059: sc->sc_dev.dv_xname, size);
! 1060: error = EINVAL;
! 1061: goto fail2;
! 1062: }
! 1063:
! 1064: /* get pointers to firmware segments */
! 1065: main_text = (const uint8_t *)(hdr + 1);
! 1066: main_data = main_text + main_textsz;
! 1067: init_text = main_data + main_datasz;
! 1068: init_data = init_text + init_textsz;
! 1069: boot_text = init_data + init_datasz;
! 1070:
! 1071: /* copy initialization images into pre-allocated DMA-safe memory */
! 1072: memcpy(dma->vaddr, init_data, init_datasz);
! 1073: memcpy(dma->vaddr + WPI_FW_INIT_DATA_MAXSZ, init_text, init_textsz);
! 1074:
! 1075: /* tell adapter where to find initialization images */
! 1076: wpi_mem_lock(sc);
! 1077: wpi_mem_write(sc, WPI_MEM_DATA_BASE, dma->paddr);
! 1078: wpi_mem_write(sc, WPI_MEM_DATA_SIZE, init_datasz);
! 1079: wpi_mem_write(sc, WPI_MEM_TEXT_BASE,
! 1080: dma->paddr + WPI_FW_INIT_DATA_MAXSZ);
! 1081: wpi_mem_write(sc, WPI_MEM_TEXT_SIZE, init_textsz);
! 1082: wpi_mem_unlock(sc);
! 1083:
! 1084: /* load firmware boot code */
! 1085: if ((error = wpi_load_microcode(sc, boot_text, boot_textsz)) != 0) {
! 1086: printf("%s: could not load boot firmware\n",
! 1087: sc->sc_dev.dv_xname);
! 1088: goto fail2;
! 1089: }
! 1090:
! 1091: /* now press "execute" ;-) */
! 1092: WPI_WRITE(sc, WPI_RESET, 0);
! 1093:
! 1094: /* wait at most one second for first alive notification */
! 1095: if ((error = tsleep(sc, PCATCH, "wpiinit", hz)) != 0) {
! 1096: /* this isn't what was supposed to happen.. */
! 1097: printf("%s: timeout waiting for adapter to initialize\n",
! 1098: sc->sc_dev.dv_xname);
! 1099: goto fail2;
! 1100: }
! 1101:
! 1102: /* copy runtime images into pre-allocated DMA-safe memory */
! 1103: memcpy(dma->vaddr, main_data, main_datasz);
! 1104: memcpy(dma->vaddr + WPI_FW_MAIN_DATA_MAXSZ, main_text, main_textsz);
! 1105:
! 1106: /* tell adapter where to find runtime images */
! 1107: wpi_mem_lock(sc);
! 1108: wpi_mem_write(sc, WPI_MEM_DATA_BASE, dma->paddr);
! 1109: wpi_mem_write(sc, WPI_MEM_DATA_SIZE, main_datasz);
! 1110: wpi_mem_write(sc, WPI_MEM_TEXT_BASE,
! 1111: dma->paddr + WPI_FW_MAIN_DATA_MAXSZ);
! 1112: wpi_mem_write(sc, WPI_MEM_TEXT_SIZE, WPI_FW_UPDATED | main_textsz);
! 1113: wpi_mem_unlock(sc);
! 1114:
! 1115: /* wait at most one second for second alive notification */
! 1116: if ((error = tsleep(sc, PCATCH, "wpiinit", hz)) != 0) {
! 1117: /* this isn't what was supposed to happen.. */
! 1118: printf("%s: timeout waiting for adapter to initialize\n",
! 1119: sc->sc_dev.dv_xname);
! 1120: }
! 1121:
! 1122: fail2: free(fw, M_DEVBUF);
! 1123: fail1: return error;
! 1124: }
! 1125:
! 1126: void
! 1127: wpi_calib_timeout(void *arg)
! 1128: {
! 1129: struct wpi_softc *sc = arg;
! 1130: struct ieee80211com *ic = &sc->sc_ic;
! 1131: int temp, s;
! 1132:
! 1133: /* automatic rate control triggered every 500ms */
! 1134: if (ic->ic_fixed_rate == -1) {
! 1135: s = splnet();
! 1136: if (ic->ic_opmode == IEEE80211_M_STA)
! 1137: wpi_iter_func(sc, ic->ic_bss);
! 1138: else
! 1139: ieee80211_iterate_nodes(ic, wpi_iter_func, sc);
! 1140: splx(s);
! 1141: }
! 1142:
! 1143: /* update sensor data */
! 1144: temp = (int)WPI_READ(sc, WPI_TEMPERATURE);
! 1145: sc->sensor.value = temp + 260;
! 1146:
! 1147: /* automatic power calibration every 60s */
! 1148: if (++sc->calib_cnt >= 120) {
! 1149: wpi_power_calibration(sc, temp);
! 1150: sc->calib_cnt = 0;
! 1151: }
! 1152:
! 1153: timeout_add(&sc->calib_to, hz / 2);
! 1154: }
! 1155:
! 1156: void
! 1157: wpi_iter_func(void *arg, struct ieee80211_node *ni)
! 1158: {
! 1159: struct wpi_softc *sc = arg;
! 1160: struct wpi_node *wn = (struct wpi_node *)ni;
! 1161:
! 1162: ieee80211_amrr_choose(&sc->amrr, ni, &wn->amn);
! 1163: }
! 1164:
! 1165: /*
! 1166: * This function is called periodically (every 60 seconds) to adjust output
! 1167: * power to temperature changes.
! 1168: */
! 1169: void
! 1170: wpi_power_calibration(struct wpi_softc *sc, int temp)
! 1171: {
! 1172: /* sanity-check read value */
! 1173: if (temp < -260 || temp > 25) {
! 1174: /* this can't be correct, ignore */
! 1175: DPRINTF(("out-of-range temperature reported: %d\n", temp));
! 1176: return;
! 1177: }
! 1178:
! 1179: DPRINTF(("temperature %d->%d\n", sc->temp, temp));
! 1180:
! 1181: /* adjust Tx power if need be */
! 1182: if (abs(temp - sc->temp) <= 6)
! 1183: return;
! 1184:
! 1185: sc->temp = temp;
! 1186:
! 1187: if (wpi_set_txpower(sc, sc->sc_ic.ic_bss->ni_chan, 1) != 0) {
! 1188: /* just warn, too bad for the automatic calibration... */
! 1189: printf("%s: could not adjust Tx power\n",
! 1190: sc->sc_dev.dv_xname);
! 1191: }
! 1192: }
! 1193:
! 1194: void
! 1195: wpi_rx_intr(struct wpi_softc *sc, struct wpi_rx_desc *desc,
! 1196: struct wpi_rx_data *data)
! 1197: {
! 1198: struct ieee80211com *ic = &sc->sc_ic;
! 1199: struct ifnet *ifp = &ic->ic_if;
! 1200: struct wpi_rx_ring *ring = &sc->rxq;
! 1201: struct wpi_rx_stat *stat;
! 1202: struct wpi_rx_head *head;
! 1203: struct wpi_rx_tail *tail;
! 1204: struct wpi_rbuf *rbuf;
! 1205: struct ieee80211_frame *wh;
! 1206: struct ieee80211_node *ni;
! 1207: struct mbuf *m, *mnew;
! 1208:
! 1209: stat = (struct wpi_rx_stat *)(desc + 1);
! 1210:
! 1211: if (stat->len > WPI_STAT_MAXLEN) {
! 1212: printf("%s: invalid rx statistic header\n",
! 1213: sc->sc_dev.dv_xname);
! 1214: ifp->if_ierrors++;
! 1215: return;
! 1216: }
! 1217:
! 1218: head = (struct wpi_rx_head *)((caddr_t)(stat + 1) + stat->len);
! 1219: tail = (struct wpi_rx_tail *)((caddr_t)(head + 1) + letoh16(head->len));
! 1220:
! 1221: DPRINTFN(4, ("rx intr: idx=%d len=%d stat len=%d rssi=%d rate=%x "
! 1222: "chan=%d tstamp=%llu\n", ring->cur, letoh32(desc->len),
! 1223: letoh16(head->len), (int8_t)stat->rssi, head->rate, head->chan,
! 1224: letoh64(tail->tstamp)));
! 1225:
! 1226: /*
! 1227: * Discard Rx frames with bad CRC early (XXX we may want to pass them
! 1228: * to radiotap in monitor mode).
! 1229: */
! 1230: if ((letoh32(tail->flags) & WPI_RX_NOERROR) != WPI_RX_NOERROR) {
! 1231: DPRINTFN(2, ("rx tail flags error %x\n",
! 1232: letoh32(tail->flags)));
! 1233: ifp->if_ierrors++;
! 1234: return;
! 1235: }
! 1236:
! 1237: MGETHDR(mnew, M_DONTWAIT, MT_DATA);
! 1238: if (mnew == NULL) {
! 1239: ifp->if_ierrors++;
! 1240: return;
! 1241: }
! 1242: if ((rbuf = wpi_alloc_rbuf(sc)) == NULL) {
! 1243: m_freem(mnew);
! 1244: ifp->if_ierrors++;
! 1245: return;
! 1246: }
! 1247: /* attach Rx buffer to mbuf */
! 1248: MEXTADD(mnew, rbuf->vaddr, WPI_RBUF_SIZE, 0, wpi_free_rbuf, rbuf);
! 1249:
! 1250: m = data->m;
! 1251: data->m = mnew;
! 1252:
! 1253: /* update Rx descriptor */
! 1254: ring->desc[ring->cur] = htole32(rbuf->paddr);
! 1255:
! 1256: /* finalize mbuf */
! 1257: m->m_pkthdr.rcvif = ifp;
! 1258: m->m_data = (caddr_t)(head + 1);
! 1259: m->m_pkthdr.len = m->m_len = letoh16(head->len);
! 1260:
! 1261: #if NBPFILTER > 0
! 1262: if (sc->sc_drvbpf != NULL) {
! 1263: struct mbuf mb;
! 1264: struct wpi_rx_radiotap_header *tap = &sc->sc_rxtap;
! 1265:
! 1266: tap->wr_flags = 0;
! 1267: tap->wr_chan_freq =
! 1268: htole16(ic->ic_channels[head->chan].ic_freq);
! 1269: tap->wr_chan_flags =
! 1270: htole16(ic->ic_channels[head->chan].ic_flags);
! 1271: tap->wr_dbm_antsignal = (int8_t)(stat->rssi - WPI_RSSI_OFFSET);
! 1272: tap->wr_dbm_antnoise = (int8_t)letoh16(stat->noise);
! 1273: tap->wr_tsft = tail->tstamp;
! 1274: tap->wr_antenna = (letoh16(head->flags) >> 4) & 0xf;
! 1275: switch (head->rate) {
! 1276: /* CCK rates */
! 1277: case 10: tap->wr_rate = 2; break;
! 1278: case 20: tap->wr_rate = 4; break;
! 1279: case 55: tap->wr_rate = 11; break;
! 1280: case 110: tap->wr_rate = 22; break;
! 1281: /* OFDM rates */
! 1282: case 0xd: tap->wr_rate = 12; break;
! 1283: case 0xf: tap->wr_rate = 18; break;
! 1284: case 0x5: tap->wr_rate = 24; break;
! 1285: case 0x7: tap->wr_rate = 36; break;
! 1286: case 0x9: tap->wr_rate = 48; break;
! 1287: case 0xb: tap->wr_rate = 72; break;
! 1288: case 0x1: tap->wr_rate = 96; break;
! 1289: case 0x3: tap->wr_rate = 108; break;
! 1290: /* unknown rate: should not happen */
! 1291: default: tap->wr_rate = 0;
! 1292: }
! 1293: if (letoh16(head->flags) & 0x4)
! 1294: tap->wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
! 1295:
! 1296: mb.m_data = (caddr_t)tap;
! 1297: mb.m_len = sc->sc_rxtap_len;
! 1298: mb.m_next = m;
! 1299: mb.m_nextpkt = NULL;
! 1300: mb.m_type = 0;
! 1301: mb.m_flags = 0;
! 1302: bpf_mtap(sc->sc_drvbpf, &mb, BPF_DIRECTION_IN);
! 1303: }
! 1304: #endif
! 1305:
! 1306: /* grab a reference to the source node */
! 1307: wh = mtod(m, struct ieee80211_frame *);
! 1308: ni = ieee80211_find_rxnode(ic, wh);
! 1309:
! 1310: /* send the frame to the 802.11 layer */
! 1311: ieee80211_input(ifp, m, ni, stat->rssi, 0);
! 1312:
! 1313: /* node is no longer needed */
! 1314: ieee80211_release_node(ic, ni);
! 1315: }
! 1316:
! 1317: void
! 1318: wpi_tx_intr(struct wpi_softc *sc, struct wpi_rx_desc *desc)
! 1319: {
! 1320: struct ieee80211com *ic = &sc->sc_ic;
! 1321: struct ifnet *ifp = &ic->ic_if;
! 1322: struct wpi_tx_ring *ring = &sc->txq[desc->qid & 0x3];
! 1323: struct wpi_tx_data *data = &ring->data[desc->idx];
! 1324: struct wpi_tx_stat *stat = (struct wpi_tx_stat *)(desc + 1);
! 1325: struct wpi_node *wn = (struct wpi_node *)data->ni;
! 1326:
! 1327: DPRINTFN(4, ("tx done: qid=%d idx=%d retries=%d nkill=%d rate=%x "
! 1328: "duration=%d status=%x\n", desc->qid, desc->idx, stat->ntries,
! 1329: stat->nkill, stat->rate, letoh32(stat->duration),
! 1330: letoh32(stat->status)));
! 1331:
! 1332: /*
! 1333: * Update rate control statistics for the node.
! 1334: * XXX we should not count mgmt frames since they're always sent at
! 1335: * the lowest available bit-rate.
! 1336: */
! 1337: wn->amn.amn_txcnt++;
! 1338: if (stat->ntries > 0) {
! 1339: DPRINTFN(3, ("tx intr ntries %d\n", stat->ntries));
! 1340: wn->amn.amn_retrycnt++;
! 1341: }
! 1342:
! 1343: if ((letoh32(stat->status) & 0xff) != 1)
! 1344: ifp->if_oerrors++;
! 1345: else
! 1346: ifp->if_opackets++;
! 1347:
! 1348: bus_dmamap_unload(sc->sc_dmat, data->map);
! 1349: m_freem(data->m);
! 1350: data->m = NULL;
! 1351: ieee80211_release_node(ic, data->ni);
! 1352: data->ni = NULL;
! 1353:
! 1354: ring->queued--;
! 1355:
! 1356: sc->sc_tx_timer = 0;
! 1357: ifp->if_flags &= ~IFF_OACTIVE;
! 1358: (*ifp->if_start)(ifp);
! 1359: }
! 1360:
! 1361: void
! 1362: wpi_cmd_intr(struct wpi_softc *sc, struct wpi_rx_desc *desc)
! 1363: {
! 1364: struct wpi_tx_ring *ring = &sc->cmdq;
! 1365: struct wpi_tx_data *data;
! 1366:
! 1367: if ((desc->qid & 7) != 4)
! 1368: return; /* not a command ack */
! 1369:
! 1370: data = &ring->data[desc->idx];
! 1371:
! 1372: /* if the command was mapped in a mbuf, free it */
! 1373: if (data->m != NULL) {
! 1374: bus_dmamap_unload(sc->sc_dmat, data->map);
! 1375: m_freem(data->m);
! 1376: data->m = NULL;
! 1377: }
! 1378:
! 1379: wakeup(&ring->cmd[desc->idx]);
! 1380: }
! 1381:
! 1382: void
! 1383: wpi_notif_intr(struct wpi_softc *sc)
! 1384: {
! 1385: struct ieee80211com *ic = &sc->sc_ic;
! 1386: struct ifnet *ifp = &ic->ic_if;
! 1387: uint32_t hw;
! 1388:
! 1389: hw = letoh32(sc->shared->next);
! 1390: while (sc->rxq.cur != hw) {
! 1391: struct wpi_rx_data *data = &sc->rxq.data[sc->rxq.cur];
! 1392: struct wpi_rx_desc *desc = mtod(data->m, struct wpi_rx_desc *);
! 1393:
! 1394: DPRINTFN(4, ("rx notification qid=%x idx=%d flags=%x type=%d "
! 1395: "len=%d\n", desc->qid, desc->idx, desc->flags, desc->type,
! 1396: letoh32(desc->len)));
! 1397:
! 1398: if (!(desc->qid & 0x80)) /* reply to a command */
! 1399: wpi_cmd_intr(sc, desc);
! 1400:
! 1401: switch (desc->type) {
! 1402: case WPI_RX_DONE:
! 1403: /* a 802.11 frame was received */
! 1404: wpi_rx_intr(sc, desc, data);
! 1405: break;
! 1406:
! 1407: case WPI_TX_DONE:
! 1408: /* a 802.11 frame has been transmitted */
! 1409: wpi_tx_intr(sc, desc);
! 1410: break;
! 1411:
! 1412: case WPI_UC_READY:
! 1413: {
! 1414: struct wpi_ucode_info *uc =
! 1415: (struct wpi_ucode_info *)(desc + 1);
! 1416:
! 1417: /* the microcontroller is ready */
! 1418: DPRINTF(("microcode alive notification version %x "
! 1419: "alive %x\n", letoh32(uc->version),
! 1420: letoh32(uc->valid)));
! 1421:
! 1422: if (letoh32(uc->valid) != 1) {
! 1423: printf("%s: microcontroller initialization "
! 1424: "failed\n", sc->sc_dev.dv_xname);
! 1425: }
! 1426: break;
! 1427: }
! 1428: case WPI_STATE_CHANGED:
! 1429: {
! 1430: uint32_t *status = (uint32_t *)(desc + 1);
! 1431:
! 1432: /* enabled/disabled notification */
! 1433: DPRINTF(("state changed to %x\n", letoh32(*status)));
! 1434:
! 1435: if (letoh32(*status) & 1) {
! 1436: /* the radio button has to be pushed */
! 1437: printf("%s: Radio transmitter is off\n",
! 1438: sc->sc_dev.dv_xname);
! 1439: /* turn the interface down */
! 1440: ifp->if_flags &= ~IFF_UP;
! 1441: wpi_stop(ifp, 1);
! 1442: return; /* no further processing */
! 1443: }
! 1444: break;
! 1445: }
! 1446: case WPI_START_SCAN:
! 1447: {
! 1448: struct wpi_start_scan *scan =
! 1449: (struct wpi_start_scan *)(desc + 1);
! 1450:
! 1451: DPRINTFN(2, ("scanning channel %d status %x\n",
! 1452: scan->chan, letoh32(scan->status)));
! 1453:
! 1454: /* fix current channel */
! 1455: ic->ic_bss->ni_chan = &ic->ic_channels[scan->chan];
! 1456: break;
! 1457: }
! 1458: case WPI_STOP_SCAN:
! 1459: {
! 1460: struct wpi_stop_scan *scan =
! 1461: (struct wpi_stop_scan *)(desc + 1);
! 1462:
! 1463: DPRINTF(("scan finished nchan=%d status=%d chan=%d\n",
! 1464: scan->nchan, scan->status, scan->chan));
! 1465:
! 1466: if (scan->status == 1 && scan->chan <= 14) {
! 1467: /*
! 1468: * We just finished scanning 802.11g channels,
! 1469: * start scanning 802.11a ones.
! 1470: */
! 1471: if (wpi_scan(sc, IEEE80211_CHAN_A) == 0)
! 1472: break;
! 1473: }
! 1474: ieee80211_end_scan(ifp);
! 1475: break;
! 1476: }
! 1477: }
! 1478:
! 1479: sc->rxq.cur = (sc->rxq.cur + 1) % WPI_RX_RING_COUNT;
! 1480: }
! 1481:
! 1482: /* tell the firmware what we have processed */
! 1483: hw = (hw == 0) ? WPI_RX_RING_COUNT - 1 : hw - 1;
! 1484: WPI_WRITE(sc, WPI_RX_WIDX, hw & ~7);
! 1485: }
! 1486:
! 1487: int
! 1488: wpi_intr(void *arg)
! 1489: {
! 1490: struct wpi_softc *sc = arg;
! 1491: struct ifnet *ifp = &sc->sc_ic.ic_if;
! 1492: uint32_t r;
! 1493:
! 1494: r = WPI_READ(sc, WPI_INTR);
! 1495: if (r == 0 || r == 0xffffffff)
! 1496: return 0; /* not for us */
! 1497:
! 1498: DPRINTFN(6, ("interrupt reg %x\n", r));
! 1499:
! 1500: /* disable interrupts */
! 1501: WPI_WRITE(sc, WPI_MASK, 0);
! 1502: /* ack interrupts */
! 1503: WPI_WRITE(sc, WPI_INTR, r);
! 1504:
! 1505: if (r & (WPI_SW_ERROR | WPI_HW_ERROR)) {
! 1506: /* SYSTEM FAILURE, SYSTEM FAILURE */
! 1507: printf("%s: fatal firmware error\n", sc->sc_dev.dv_xname);
! 1508: ifp->if_flags &= ~IFF_UP;
! 1509: wpi_stop(ifp, 1);
! 1510: return 1;
! 1511: }
! 1512:
! 1513: if (r & WPI_RX_INTR)
! 1514: wpi_notif_intr(sc);
! 1515:
! 1516: if (r & WPI_ALIVE_INTR) /* firmware initialized */
! 1517: wakeup(sc);
! 1518:
! 1519: /* re-enable interrupts */
! 1520: if (ifp->if_flags & IFF_UP)
! 1521: WPI_WRITE(sc, WPI_MASK, WPI_INTR_MASK);
! 1522:
! 1523: return 1;
! 1524: }
! 1525:
! 1526: uint8_t
! 1527: wpi_plcp_signal(int rate)
! 1528: {
! 1529: switch (rate) {
! 1530: /* CCK rates (returned values are device-dependent) */
! 1531: case 2: return 10;
! 1532: case 4: return 20;
! 1533: case 11: return 55;
! 1534: case 22: return 110;
! 1535:
! 1536: /* OFDM rates (cf IEEE Std 802.11a-1999, pp. 14 Table 80) */
! 1537: /* R1-R4, (u)ral is R4-R1 */
! 1538: case 12: return 0xd;
! 1539: case 18: return 0xf;
! 1540: case 24: return 0x5;
! 1541: case 36: return 0x7;
! 1542: case 48: return 0x9;
! 1543: case 72: return 0xb;
! 1544: case 96: return 0x1;
! 1545: case 108: return 0x3;
! 1546:
! 1547: /* unsupported rates (should not get there) */
! 1548: default: return 0;
! 1549: }
! 1550: }
! 1551:
! 1552: /* quickly determine if a given rate is CCK or OFDM */
! 1553: #define WPI_RATE_IS_OFDM(rate) ((rate) >= 12 && (rate) != 22)
! 1554:
! 1555: int
! 1556: wpi_tx_data(struct wpi_softc *sc, struct mbuf *m0, struct ieee80211_node *ni,
! 1557: int ac)
! 1558: {
! 1559: struct ieee80211com *ic = &sc->sc_ic;
! 1560: struct wpi_tx_ring *ring = &sc->txq[ac];
! 1561: struct wpi_tx_desc *desc;
! 1562: struct wpi_tx_data *data;
! 1563: struct wpi_tx_cmd *cmd;
! 1564: struct wpi_cmd_data *tx;
! 1565: struct ieee80211_frame *wh;
! 1566: struct mbuf *mnew;
! 1567: int i, rate, error, ovhd = 0;
! 1568:
! 1569: desc = &ring->desc[ring->cur];
! 1570: data = &ring->data[ring->cur];
! 1571:
! 1572: wh = mtod(m0, struct ieee80211_frame *);
! 1573:
! 1574: /* pickup a rate */
! 1575: if (IEEE80211_IS_MULTICAST(wh->i_addr1) ||
! 1576: ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
! 1577: IEEE80211_FC0_TYPE_MGT)) {
! 1578: /* mgmt/multicast frames are sent at the lowest avail. rate */
! 1579: rate = ni->ni_rates.rs_rates[0];
! 1580: } else if (ic->ic_fixed_rate != -1) {
! 1581: rate = ic->ic_sup_rates[ic->ic_curmode].
! 1582: rs_rates[ic->ic_fixed_rate];
! 1583: } else
! 1584: rate = ni->ni_rates.rs_rates[ni->ni_txrate];
! 1585: rate &= IEEE80211_RATE_VAL;
! 1586:
! 1587: #if NBPFILTER > 0
! 1588: if (sc->sc_drvbpf != NULL) {
! 1589: struct mbuf mb;
! 1590: struct wpi_tx_radiotap_header *tap = &sc->sc_txtap;
! 1591:
! 1592: tap->wt_flags = 0;
! 1593: tap->wt_chan_freq = htole16(ni->ni_chan->ic_freq);
! 1594: tap->wt_chan_flags = htole16(ni->ni_chan->ic_flags);
! 1595: tap->wt_rate = rate;
! 1596: tap->wt_hwqueue = ac;
! 1597: if (wh->i_fc[1] & IEEE80211_FC1_WEP)
! 1598: tap->wt_flags |= IEEE80211_RADIOTAP_F_WEP;
! 1599:
! 1600: mb.m_data = (caddr_t)tap;
! 1601: mb.m_len = sc->sc_txtap_len;
! 1602: mb.m_next = m0;
! 1603: mb.m_nextpkt = NULL;
! 1604: mb.m_type = 0;
! 1605: mb.m_flags = 0;
! 1606: bpf_mtap(sc->sc_drvbpf, &mb, BPF_DIRECTION_OUT);
! 1607: }
! 1608: #endif
! 1609:
! 1610: cmd = &ring->cmd[ring->cur];
! 1611: cmd->code = WPI_CMD_TX_DATA;
! 1612: cmd->flags = 0;
! 1613: cmd->qid = ring->qid;
! 1614: cmd->idx = ring->cur;
! 1615:
! 1616: tx = (struct wpi_cmd_data *)cmd->data;
! 1617: /* no need to zero tx, all fields are reinitialized here */
! 1618: tx->flags = 0;
! 1619:
! 1620: if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
! 1621: const struct ieee80211_key *key =
! 1622: &ic->ic_nw_keys[ic->ic_wep_txkey];
! 1623: if (key->k_cipher == IEEE80211_CIPHER_WEP40)
! 1624: tx->security = WPI_CIPHER_WEP40;
! 1625: else
! 1626: tx->security = WPI_CIPHER_WEP104;
! 1627: tx->security |= ic->ic_wep_txkey << 6;
! 1628: memcpy(&tx->key[3], key->k_key, key->k_len);
! 1629: /* compute crypto overhead */
! 1630: ovhd = IEEE80211_WEP_TOTLEN;
! 1631: } else
! 1632: tx->security = 0;
! 1633:
! 1634: if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
! 1635: tx->id = WPI_ID_BSS;
! 1636: tx->flags |= htole32(WPI_TX_NEED_ACK);
! 1637: } else
! 1638: tx->id = WPI_ID_BROADCAST;
! 1639:
! 1640: /* check if RTS/CTS or CTS-to-self protection must be used */
! 1641: if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
! 1642: /* multicast frames are not sent at OFDM rates in 802.11b/g */
! 1643: if (m0->m_pkthdr.len + ovhd + IEEE80211_CRC_LEN >
! 1644: ic->ic_rtsthreshold) {
! 1645: tx->flags |= htole32(WPI_TX_NEED_RTS |
! 1646: WPI_TX_FULL_TXOP);
! 1647: } else if ((ic->ic_flags & IEEE80211_F_USEPROT) &&
! 1648: WPI_RATE_IS_OFDM(rate)) {
! 1649: if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) {
! 1650: tx->flags |= htole32(WPI_TX_NEED_CTS |
! 1651: WPI_TX_FULL_TXOP);
! 1652: } else if (ic->ic_protmode == IEEE80211_PROT_RTSCTS) {
! 1653: tx->flags |= htole32(WPI_TX_NEED_RTS |
! 1654: WPI_TX_FULL_TXOP);
! 1655: }
! 1656: }
! 1657: }
! 1658:
! 1659: tx->flags |= htole32(WPI_TX_AUTO_SEQ);
! 1660:
! 1661: if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
! 1662: IEEE80211_FC0_TYPE_MGT) {
! 1663: uint8_t subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
! 1664:
! 1665: /* tell h/w to set timestamp in probe responses */
! 1666: if (subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP)
! 1667: tx->flags |= htole32(WPI_TX_INSERT_TSTAMP);
! 1668:
! 1669: if (subtype == IEEE80211_FC0_SUBTYPE_ASSOC_REQ ||
! 1670: subtype == IEEE80211_FC0_SUBTYPE_REASSOC_REQ)
! 1671: tx->timeout = htole16(3);
! 1672: else
! 1673: tx->timeout = htole16(2);
! 1674: } else
! 1675: tx->timeout = htole16(0);
! 1676:
! 1677: tx->rate = wpi_plcp_signal(rate);
! 1678:
! 1679: /* be very persistant at sending frames out */
! 1680: tx->rts_ntries = 7;
! 1681: tx->data_ntries = 15;
! 1682:
! 1683: tx->ofdm_mask = 0xff;
! 1684: tx->cck_mask = 0x0f;
! 1685: tx->lifetime = htole32(WPI_LIFETIME_INFINITE);
! 1686:
! 1687: tx->len = htole16(m0->m_pkthdr.len);
! 1688:
! 1689: /* save and trim IEEE802.11 header */
! 1690: m_copydata(m0, 0, sizeof (struct ieee80211_frame), (caddr_t)&tx->wh);
! 1691: m_adj(m0, sizeof (struct ieee80211_frame));
! 1692:
! 1693: error = bus_dmamap_load_mbuf(sc->sc_dmat, data->map, m0,
! 1694: BUS_DMA_NOWAIT);
! 1695: if (error != 0 && error != EFBIG) {
! 1696: printf("%s: could not map mbuf (error %d)\n",
! 1697: sc->sc_dev.dv_xname, error);
! 1698: m_freem(m0);
! 1699: return error;
! 1700: }
! 1701: if (error != 0) {
! 1702: /* too many fragments, linearize */
! 1703:
! 1704: MGETHDR(mnew, M_DONTWAIT, MT_DATA);
! 1705: if (mnew == NULL) {
! 1706: m_freem(m0);
! 1707: return ENOMEM;
! 1708: }
! 1709: M_DUP_PKTHDR(mnew, m0);
! 1710: if (m0->m_pkthdr.len > MHLEN) {
! 1711: MCLGET(mnew, M_DONTWAIT);
! 1712: if (!(mnew->m_flags & M_EXT)) {
! 1713: m_freem(m0);
! 1714: m_freem(mnew);
! 1715: return ENOMEM;
! 1716: }
! 1717: }
! 1718:
! 1719: m_copydata(m0, 0, m0->m_pkthdr.len, mtod(mnew, caddr_t));
! 1720: m_freem(m0);
! 1721: mnew->m_len = mnew->m_pkthdr.len;
! 1722: m0 = mnew;
! 1723:
! 1724: error = bus_dmamap_load_mbuf(sc->sc_dmat, data->map, m0,
! 1725: BUS_DMA_NOWAIT);
! 1726: if (error != 0) {
! 1727: printf("%s: could not map mbuf (error %d)\n",
! 1728: sc->sc_dev.dv_xname, error);
! 1729: m_freem(m0);
! 1730: return error;
! 1731: }
! 1732: }
! 1733:
! 1734: data->m = m0;
! 1735: data->ni = ni;
! 1736:
! 1737: DPRINTFN(4, ("sending data: qid=%d idx=%d len=%d nsegs=%d\n",
! 1738: ring->qid, ring->cur, m0->m_pkthdr.len, data->map->dm_nsegs));
! 1739:
! 1740: /* first scatter/gather segment is used by the tx data command */
! 1741: desc->flags = htole32(WPI_PAD32(m0->m_pkthdr.len) << 28 |
! 1742: (1 + data->map->dm_nsegs) << 24);
! 1743: desc->segs[0].addr = htole32(ring->cmd_dma.paddr +
! 1744: ring->cur * sizeof (struct wpi_tx_cmd));
! 1745: desc->segs[0].len = htole32(4 + sizeof (struct wpi_cmd_data));
! 1746: for (i = 1; i <= data->map->dm_nsegs; i++) {
! 1747: desc->segs[i].addr =
! 1748: htole32(data->map->dm_segs[i - 1].ds_addr);
! 1749: desc->segs[i].len =
! 1750: htole32(data->map->dm_segs[i - 1].ds_len);
! 1751: }
! 1752:
! 1753: ring->queued++;
! 1754:
! 1755: /* kick ring */
! 1756: ring->cur = (ring->cur + 1) % WPI_TX_RING_COUNT;
! 1757: WPI_WRITE(sc, WPI_TX_WIDX, ring->qid << 8 | ring->cur);
! 1758:
! 1759: return 0;
! 1760: }
! 1761:
! 1762: void
! 1763: wpi_start(struct ifnet *ifp)
! 1764: {
! 1765: struct wpi_softc *sc = ifp->if_softc;
! 1766: struct ieee80211com *ic = &sc->sc_ic;
! 1767: struct ieee80211_node *ni;
! 1768: struct mbuf *m0;
! 1769:
! 1770: /*
! 1771: * net80211 may still try to send management frames even if the
! 1772: * IFF_RUNNING flag is not set...
! 1773: */
! 1774: if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
! 1775: return;
! 1776:
! 1777: for (;;) {
! 1778: IF_POLL(&ic->ic_mgtq, m0);
! 1779: if (m0 != NULL) {
! 1780: /* management frames go into ring 0 */
! 1781: if (sc->txq[0].queued >= sc->txq[0].count - 8) {
! 1782: ifp->if_flags |= IFF_OACTIVE;
! 1783: break;
! 1784: }
! 1785: IF_DEQUEUE(&ic->ic_mgtq, m0);
! 1786:
! 1787: ni = (struct ieee80211_node *)m0->m_pkthdr.rcvif;
! 1788: m0->m_pkthdr.rcvif = NULL;
! 1789: #if NBPFILTER > 0
! 1790: if (ic->ic_rawbpf != NULL)
! 1791: bpf_mtap(ic->ic_rawbpf, m0, BPF_DIRECTION_OUT);
! 1792: #endif
! 1793: if (wpi_tx_data(sc, m0, ni, 0) != 0)
! 1794: break;
! 1795:
! 1796: } else {
! 1797: if (ic->ic_state != IEEE80211_S_RUN)
! 1798: break;
! 1799: IFQ_POLL(&ifp->if_snd, m0);
! 1800: if (m0 == NULL)
! 1801: break;
! 1802: if (sc->txq[0].queued >= sc->txq[0].count - 8) {
! 1803: /* there is no place left in this ring */
! 1804: ifp->if_flags |= IFF_OACTIVE;
! 1805: break;
! 1806: }
! 1807: IFQ_DEQUEUE(&ifp->if_snd, m0);
! 1808: #if NBPFILTER > 0
! 1809: if (ifp->if_bpf != NULL)
! 1810: bpf_mtap(ifp->if_bpf, m0, BPF_DIRECTION_OUT);
! 1811: #endif
! 1812: m0 = ieee80211_encap(ifp, m0, &ni);
! 1813: if (m0 == NULL)
! 1814: continue;
! 1815: #if NBPFILTER > 0
! 1816: if (ic->ic_rawbpf != NULL)
! 1817: bpf_mtap(ic->ic_rawbpf, m0, BPF_DIRECTION_OUT);
! 1818: #endif
! 1819: if (wpi_tx_data(sc, m0, ni, 0) != 0) {
! 1820: if (ni != NULL)
! 1821: ieee80211_release_node(ic, ni);
! 1822: ifp->if_oerrors++;
! 1823: break;
! 1824: }
! 1825: }
! 1826:
! 1827: sc->sc_tx_timer = 5;
! 1828: ifp->if_timer = 1;
! 1829: }
! 1830: }
! 1831:
! 1832: void
! 1833: wpi_watchdog(struct ifnet *ifp)
! 1834: {
! 1835: struct wpi_softc *sc = ifp->if_softc;
! 1836:
! 1837: ifp->if_timer = 0;
! 1838:
! 1839: if (sc->sc_tx_timer > 0) {
! 1840: if (--sc->sc_tx_timer == 0) {
! 1841: printf("%s: device timeout\n", sc->sc_dev.dv_xname);
! 1842: ifp->if_flags &= ~IFF_UP;
! 1843: wpi_stop(ifp, 1);
! 1844: ifp->if_oerrors++;
! 1845: return;
! 1846: }
! 1847: ifp->if_timer = 1;
! 1848: }
! 1849:
! 1850: ieee80211_watchdog(ifp);
! 1851: }
! 1852:
! 1853: int
! 1854: wpi_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
! 1855: {
! 1856: struct wpi_softc *sc = ifp->if_softc;
! 1857: struct ieee80211com *ic = &sc->sc_ic;
! 1858: struct ifaddr *ifa;
! 1859: struct ifreq *ifr;
! 1860: int s, error = 0;
! 1861:
! 1862: s = splnet();
! 1863:
! 1864: switch (cmd) {
! 1865: case SIOCSIFADDR:
! 1866: ifa = (struct ifaddr *)data;
! 1867: ifp->if_flags |= IFF_UP;
! 1868: #ifdef INET
! 1869: if (ifa->ifa_addr->sa_family == AF_INET)
! 1870: arp_ifinit(&ic->ic_ac, ifa);
! 1871: #endif
! 1872: /* FALLTHROUGH */
! 1873: case SIOCSIFFLAGS:
! 1874: if (ifp->if_flags & IFF_UP) {
! 1875: if (!(ifp->if_flags & IFF_RUNNING))
! 1876: wpi_init(ifp);
! 1877: } else {
! 1878: if (ifp->if_flags & IFF_RUNNING)
! 1879: wpi_stop(ifp, 1);
! 1880: }
! 1881: break;
! 1882:
! 1883: case SIOCADDMULTI:
! 1884: case SIOCDELMULTI:
! 1885: ifr = (struct ifreq *)data;
! 1886: error = (cmd == SIOCADDMULTI) ?
! 1887: ether_addmulti(ifr, &ic->ic_ac) :
! 1888: ether_delmulti(ifr, &ic->ic_ac);
! 1889:
! 1890: if (error == ENETRESET)
! 1891: error = 0;
! 1892: break;
! 1893:
! 1894: default:
! 1895: error = ieee80211_ioctl(ifp, cmd, data);
! 1896: }
! 1897:
! 1898: if (error == ENETRESET) {
! 1899: if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) ==
! 1900: (IFF_UP | IFF_RUNNING))
! 1901: wpi_init(ifp);
! 1902: error = 0;
! 1903: }
! 1904:
! 1905: splx(s);
! 1906: return error;
! 1907: }
! 1908:
! 1909: void
! 1910: wpi_read_eeprom(struct wpi_softc *sc)
! 1911: {
! 1912: struct ieee80211com *ic = &sc->sc_ic;
! 1913: char domain[4];
! 1914: int i;
! 1915:
! 1916: wpi_read_prom_data(sc, WPI_EEPROM_CAPABILITIES, &sc->cap, 1);
! 1917: wpi_read_prom_data(sc, WPI_EEPROM_REVISION, &sc->rev, 2);
! 1918: wpi_read_prom_data(sc, WPI_EEPROM_TYPE, &sc->type, 1);
! 1919:
! 1920: DPRINTF(("cap=%x rev=%x type=%x\n", sc->cap, letoh16(sc->rev),
! 1921: sc->type));
! 1922:
! 1923: /* read and print regulatory domain */
! 1924: wpi_read_prom_data(sc, WPI_EEPROM_DOMAIN, domain, 4);
! 1925: printf(", %.4s", domain);
! 1926:
! 1927: /* read and print MAC address */
! 1928: wpi_read_prom_data(sc, WPI_EEPROM_MAC, ic->ic_myaddr, 6);
! 1929: printf(", address %s\n", ether_sprintf(ic->ic_myaddr));
! 1930:
! 1931: /* read the list of authorized channels */
! 1932: for (i = 0; i < WPI_CHAN_BANDS_COUNT; i++)
! 1933: wpi_read_eeprom_channels(sc, i);
! 1934:
! 1935: /* read the list of power groups */
! 1936: for (i = 0; i < WPI_POWER_GROUPS_COUNT; i++)
! 1937: wpi_read_eeprom_group(sc, i);
! 1938: }
! 1939:
! 1940: void
! 1941: wpi_read_eeprom_channels(struct wpi_softc *sc, int n)
! 1942: {
! 1943: struct ieee80211com *ic = &sc->sc_ic;
! 1944: const struct wpi_chan_band *band = &wpi_bands[n];
! 1945: struct wpi_eeprom_chan channels[WPI_MAX_CHAN_PER_BAND];
! 1946: int chan, i;
! 1947:
! 1948: wpi_read_prom_data(sc, band->addr, channels,
! 1949: band->nchan * sizeof (struct wpi_eeprom_chan));
! 1950:
! 1951: for (i = 0; i < band->nchan; i++) {
! 1952: if (!(channels[i].flags & WPI_EEPROM_CHAN_VALID))
! 1953: continue;
! 1954:
! 1955: chan = band->chan[i];
! 1956:
! 1957: if (n == 0) { /* 2GHz band */
! 1958: ic->ic_channels[chan].ic_freq =
! 1959: ieee80211_ieee2mhz(chan, IEEE80211_CHAN_2GHZ);
! 1960: ic->ic_channels[chan].ic_flags =
! 1961: IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM |
! 1962: IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ;
! 1963:
! 1964: } else { /* 5GHz band */
! 1965: /*
! 1966: * Some 3945ABG adapters support channels 7, 8, 11
! 1967: * and 12 in the 2GHz *and* 5GHz bands.
! 1968: * Because of limitations in our net80211(9) stack,
! 1969: * we can't support these channels in 5GHz band.
! 1970: */
! 1971: if (chan <= 14)
! 1972: continue;
! 1973:
! 1974: ic->ic_channels[chan].ic_freq =
! 1975: ieee80211_ieee2mhz(chan, IEEE80211_CHAN_5GHZ);
! 1976: ic->ic_channels[chan].ic_flags = IEEE80211_CHAN_A;
! 1977: }
! 1978:
! 1979: /* is active scan allowed on this channel? */
! 1980: if (!(channels[i].flags & WPI_EEPROM_CHAN_ACTIVE)) {
! 1981: ic->ic_channels[chan].ic_flags |=
! 1982: IEEE80211_CHAN_PASSIVE;
! 1983: }
! 1984:
! 1985: /* save maximum allowed power for this channel */
! 1986: sc->maxpwr[chan] = channels[i].maxpwr;
! 1987:
! 1988: DPRINTF(("adding chan %d flags=0x%x maxpwr=%d\n",
! 1989: chan, channels[i].flags, sc->maxpwr[chan]));
! 1990: }
! 1991: }
! 1992:
! 1993: void
! 1994: wpi_read_eeprom_group(struct wpi_softc *sc, int n)
! 1995: {
! 1996: struct wpi_power_group *group = &sc->groups[n];
! 1997: struct wpi_eeprom_group rgroup;
! 1998: int i;
! 1999:
! 2000: wpi_read_prom_data(sc, WPI_EEPROM_POWER_GRP + n * 32, &rgroup,
! 2001: sizeof rgroup);
! 2002:
! 2003: /* save power group information */
! 2004: group->chan = rgroup.chan;
! 2005: group->maxpwr = rgroup.maxpwr;
! 2006: /* temperature at which the samples were taken */
! 2007: group->temp = (int16_t)letoh16(rgroup.temp);
! 2008:
! 2009: DPRINTF(("power group %d: chan=%d maxpwr=%d temp=%d\n", n,
! 2010: group->chan, group->maxpwr, group->temp));
! 2011:
! 2012: for (i = 0; i < WPI_SAMPLES_COUNT; i++) {
! 2013: group->samples[i].index = rgroup.samples[i].index;
! 2014: group->samples[i].power = rgroup.samples[i].power;
! 2015:
! 2016: DPRINTF(("\tsample %d: index=%d power=%d\n", i,
! 2017: group->samples[i].index, group->samples[i].power));
! 2018: }
! 2019: }
! 2020:
! 2021: /*
! 2022: * Send a command to the firmware.
! 2023: */
! 2024: int
! 2025: wpi_cmd(struct wpi_softc *sc, int code, const void *buf, int size, int async)
! 2026: {
! 2027: struct wpi_tx_ring *ring = &sc->cmdq;
! 2028: struct wpi_tx_desc *desc;
! 2029: struct wpi_tx_cmd *cmd;
! 2030:
! 2031: KASSERT(size <= sizeof cmd->data);
! 2032:
! 2033: desc = &ring->desc[ring->cur];
! 2034: cmd = &ring->cmd[ring->cur];
! 2035:
! 2036: cmd->code = code;
! 2037: cmd->flags = 0;
! 2038: cmd->qid = ring->qid;
! 2039: cmd->idx = ring->cur;
! 2040: memcpy(cmd->data, buf, size);
! 2041:
! 2042: desc->flags = htole32(WPI_PAD32(size) << 28 | 1 << 24);
! 2043: desc->segs[0].addr = htole32(ring->cmd_dma.paddr +
! 2044: ring->cur * sizeof (struct wpi_tx_cmd));
! 2045: desc->segs[0].len = htole32(4 + size);
! 2046:
! 2047: /* kick cmd ring */
! 2048: ring->cur = (ring->cur + 1) % WPI_CMD_RING_COUNT;
! 2049: WPI_WRITE(sc, WPI_TX_WIDX, ring->qid << 8 | ring->cur);
! 2050:
! 2051: return async ? 0 : tsleep(cmd, PCATCH, "wpicmd", hz);
! 2052: }
! 2053:
! 2054: /*
! 2055: * Configure h/w multi-rate retries.
! 2056: */
! 2057: int
! 2058: wpi_mrr_setup(struct wpi_softc *sc)
! 2059: {
! 2060: struct ieee80211com *ic = &sc->sc_ic;
! 2061: struct wpi_mrr_setup mrr;
! 2062: int i, error;
! 2063:
! 2064: /* CCK rates (not used with 802.11a) */
! 2065: for (i = WPI_CCK1; i <= WPI_CCK11; i++) {
! 2066: mrr.rates[i].flags = 0;
! 2067: mrr.rates[i].plcp = wpi_ridx_to_plcp[i];
! 2068: /* fallback to the immediate lower CCK rate (if any) */
! 2069: mrr.rates[i].next = (i == WPI_CCK1) ? WPI_CCK1 : i - 1;
! 2070: /* try one time at this rate before falling back to "next" */
! 2071: mrr.rates[i].ntries = 1;
! 2072: }
! 2073:
! 2074: /* OFDM rates (not used with 802.11b) */
! 2075: for (i = WPI_OFDM6; i <= WPI_OFDM54; i++) {
! 2076: mrr.rates[i].flags = 0;
! 2077: mrr.rates[i].plcp = wpi_ridx_to_plcp[i];
! 2078: /* fallback to the immediate lower rate (if any) */
! 2079: /* we allow fallback from OFDM/6 to CCK/2 in 11b/g mode */
! 2080: mrr.rates[i].next = (i == WPI_OFDM6) ?
! 2081: ((ic->ic_curmode == IEEE80211_MODE_11A) ?
! 2082: WPI_OFDM6 : WPI_CCK2) :
! 2083: i - 1;
! 2084: /* try one time at this rate before falling back to "next" */
! 2085: mrr.rates[i].ntries = 1;
! 2086: }
! 2087:
! 2088: /* setup MRR for control frames */
! 2089: mrr.which = htole32(WPI_MRR_CTL);
! 2090: error = wpi_cmd(sc, WPI_CMD_MRR_SETUP, &mrr, sizeof mrr, 0);
! 2091: if (error != 0) {
! 2092: printf("%s: could not setup MRR for control frames\n",
! 2093: sc->sc_dev.dv_xname);
! 2094: return error;
! 2095: }
! 2096:
! 2097: /* setup MRR for data frames */
! 2098: mrr.which = htole32(WPI_MRR_DATA);
! 2099: error = wpi_cmd(sc, WPI_CMD_MRR_SETUP, &mrr, sizeof mrr, 0);
! 2100: if (error != 0) {
! 2101: printf("%s: could not setup MRR for data frames\n",
! 2102: sc->sc_dev.dv_xname);
! 2103: return error;
! 2104: }
! 2105:
! 2106: return 0;
! 2107: }
! 2108:
! 2109: void
! 2110: wpi_set_led(struct wpi_softc *sc, uint8_t which, uint8_t off, uint8_t on)
! 2111: {
! 2112: struct wpi_cmd_led led;
! 2113:
! 2114: led.which = which;
! 2115: led.unit = htole32(100000); /* on/off in unit of 100ms */
! 2116: led.off = off;
! 2117: led.on = on;
! 2118:
! 2119: (void)wpi_cmd(sc, WPI_CMD_SET_LED, &led, sizeof led, 1);
! 2120: }
! 2121:
! 2122: void
! 2123: wpi_enable_tsf(struct wpi_softc *sc, struct ieee80211_node *ni)
! 2124: {
! 2125: struct wpi_cmd_tsf tsf;
! 2126: uint64_t val, mod;
! 2127:
! 2128: memset(&tsf, 0, sizeof tsf);
! 2129: memcpy(&tsf.tstamp, ni->ni_tstamp, sizeof (uint64_t));
! 2130: tsf.bintval = htole16(ni->ni_intval);
! 2131: tsf.lintval = htole16(10);
! 2132:
! 2133: /* compute remaining time until next beacon */
! 2134: val = (uint64_t)ni->ni_intval * 1024; /* msecs -> usecs */
! 2135: mod = letoh64(tsf.tstamp) % val;
! 2136: tsf.binitval = htole32((uint32_t)(val - mod));
! 2137:
! 2138: DPRINTF(("TSF bintval=%u tstamp=%llu, init=%u\n",
! 2139: ni->ni_intval, letoh64(tsf.tstamp), (uint32_t)(val - mod)));
! 2140:
! 2141: if (wpi_cmd(sc, WPI_CMD_TSF, &tsf, sizeof tsf, 1) != 0)
! 2142: printf("%s: could not enable TSF\n", sc->sc_dev.dv_xname);
! 2143: }
! 2144:
! 2145: /*
! 2146: * Update Tx power to match what is defined for channel `c'.
! 2147: */
! 2148: int
! 2149: wpi_set_txpower(struct wpi_softc *sc, struct ieee80211_channel *c, int async)
! 2150: {
! 2151: struct ieee80211com *ic = &sc->sc_ic;
! 2152: struct wpi_power_group *group;
! 2153: struct wpi_cmd_txpower txpower;
! 2154: u_int chan;
! 2155: int i;
! 2156:
! 2157: /* get channel number */
! 2158: chan = ieee80211_chan2ieee(ic, c);
! 2159:
! 2160: /* find the power group to which this channel belongs */
! 2161: if (IEEE80211_IS_CHAN_5GHZ(c)) {
! 2162: for (group = &sc->groups[1]; group < &sc->groups[4]; group++)
! 2163: if (chan <= group->chan)
! 2164: break;
! 2165: } else
! 2166: group = &sc->groups[0];
! 2167:
! 2168: memset(&txpower, 0, sizeof txpower);
! 2169: txpower.band = IEEE80211_IS_CHAN_5GHZ(c) ? 0 : 1;
! 2170: txpower.chan = htole16(chan);
! 2171:
! 2172: /* set Tx power for all OFDM and CCK rates */
! 2173: for (i = 0; i <= 11 ; i++) {
! 2174: /* retrieve Tx power for this channel/rate combination */
! 2175: int idx = wpi_get_power_index(sc, group, c,
! 2176: wpi_ridx_to_rate[i]);
! 2177:
! 2178: txpower.rates[i].plcp = wpi_ridx_to_plcp[i];
! 2179:
! 2180: if (IEEE80211_IS_CHAN_5GHZ(c)) {
! 2181: txpower.rates[i].rf_gain = wpi_rf_gain_5ghz[idx];
! 2182: txpower.rates[i].dsp_gain = wpi_dsp_gain_5ghz[idx];
! 2183: } else {
! 2184: txpower.rates[i].rf_gain = wpi_rf_gain_2ghz[idx];
! 2185: txpower.rates[i].dsp_gain = wpi_dsp_gain_2ghz[idx];
! 2186: }
! 2187: DPRINTF(("chan %d/rate %d: power index %d\n", chan,
! 2188: wpi_ridx_to_rate[i], idx));
! 2189: }
! 2190:
! 2191: return wpi_cmd(sc, WPI_CMD_TXPOWER, &txpower, sizeof txpower, async);
! 2192: }
! 2193:
! 2194: /*
! 2195: * Determine Tx power index for a given channel/rate combination.
! 2196: * This takes into account the regulatory information from EEPROM and the
! 2197: * current temperature.
! 2198: */
! 2199: int
! 2200: wpi_get_power_index(struct wpi_softc *sc, struct wpi_power_group *group,
! 2201: struct ieee80211_channel *c, int rate)
! 2202: {
! 2203: /* fixed-point arithmetic division using a n-bit fractional part */
! 2204: #define fdivround(a, b, n) \
! 2205: ((((1 << n) * (a)) / (b) + (1 << n) / 2) / (1 << n))
! 2206:
! 2207: /* linear interpolation */
! 2208: #define interpolate(x, x1, y1, x2, y2, n) \
! 2209: ((y1) + fdivround(((x) - (x1)) * ((y2) - (y1)), (x2) - (x1), n))
! 2210:
! 2211: struct ieee80211com *ic = &sc->sc_ic;
! 2212: struct wpi_power_sample *sample;
! 2213: int pwr, idx;
! 2214: u_int chan;
! 2215:
! 2216: /* get channel number */
! 2217: chan = ieee80211_chan2ieee(ic, c);
! 2218:
! 2219: /* default power is group's maximum power - 3dB */
! 2220: pwr = group->maxpwr / 2;
! 2221:
! 2222: /* decrease power for highest OFDM rates to reduce distortion */
! 2223: switch (rate) {
! 2224: case 72: /* 36Mb/s */
! 2225: pwr -= IEEE80211_IS_CHAN_2GHZ(c) ? 0 : 5;
! 2226: break;
! 2227: case 96: /* 48Mb/s */
! 2228: pwr -= IEEE80211_IS_CHAN_2GHZ(c) ? 7 : 10;
! 2229: break;
! 2230: case 108: /* 54Mb/s */
! 2231: pwr -= IEEE80211_IS_CHAN_2GHZ(c) ? 9 : 12;
! 2232: break;
! 2233: }
! 2234:
! 2235: /* never exceed channel's maximum allowed Tx power */
! 2236: pwr = min(pwr, sc->maxpwr[chan]);
! 2237:
! 2238: /* retrieve power index into gain tables from samples */
! 2239: for (sample = group->samples; sample < &group->samples[3]; sample++)
! 2240: if (pwr > sample[1].power)
! 2241: break;
! 2242: /* fixed-point linear interpolation using a 19-bit fractional part */
! 2243: idx = interpolate(pwr, sample[0].power, sample[0].index,
! 2244: sample[1].power, sample[1].index, 19);
! 2245:
! 2246: /*-
! 2247: * Adjust power index based on current temperature:
! 2248: * - if cooler than factory-calibrated: decrease output power
! 2249: * - if warmer than factory-calibrated: increase output power
! 2250: */
! 2251: idx -= (sc->temp - group->temp) * 11 / 100;
! 2252:
! 2253: /* decrease power for CCK rates (-5dB) */
! 2254: if (!WPI_RATE_IS_OFDM(rate))
! 2255: idx += 10;
! 2256:
! 2257: /* keep power index in a valid range */
! 2258: if (idx < 0)
! 2259: return 0;
! 2260: if (idx > WPI_MAX_PWR_INDEX)
! 2261: return WPI_MAX_PWR_INDEX;
! 2262: return idx;
! 2263:
! 2264: #undef interpolate
! 2265: #undef fdivround
! 2266: }
! 2267:
! 2268: /*
! 2269: * Build a beacon frame that the firmware will broadcast periodically in
! 2270: * IBSS or HostAP modes.
! 2271: */
! 2272: #ifdef notyet
! 2273: int
! 2274: wpi_setup_beacon(struct wpi_softc *sc, struct ieee80211_node *ni)
! 2275: {
! 2276: struct ieee80211com *ic = &sc->sc_ic;
! 2277: struct wpi_tx_ring *ring = &sc->cmdq;
! 2278: struct wpi_tx_desc *desc;
! 2279: struct wpi_tx_data *data;
! 2280: struct wpi_tx_cmd *cmd;
! 2281: struct wpi_cmd_beacon *bcn;
! 2282: struct mbuf *m0;
! 2283: int error;
! 2284:
! 2285: desc = &ring->desc[ring->cur];
! 2286: data = &ring->data[ring->cur];
! 2287:
! 2288: m0 = ieee80211_beacon_alloc(ic, ni);
! 2289: if (m0 == NULL) {
! 2290: printf("%s: could not allocate beacon frame\n",
! 2291: sc->sc_dev.dv_xname);
! 2292: return ENOMEM;
! 2293: }
! 2294:
! 2295: cmd = &ring->cmd[ring->cur];
! 2296: cmd->code = WPI_CMD_SET_BEACON;
! 2297: cmd->flags = 0;
! 2298: cmd->qid = ring->qid;
! 2299: cmd->idx = ring->cur;
! 2300:
! 2301: bcn = (struct wpi_cmd_beacon *)cmd->data;
! 2302: memset(bcn, 0, sizeof (struct wpi_cmd_beacon));
! 2303: bcn->id = WPI_ID_BROADCAST;
! 2304: bcn->ofdm_mask = 0xff;
! 2305: bcn->cck_mask = 0x0f;
! 2306: bcn->lifetime = htole32(WPI_LIFETIME_INFINITE);
! 2307: bcn->len = htole16(m0->m_pkthdr.len);
! 2308: bcn->rate = (ic->ic_curmode == IEEE80211_MODE_11A) ?
! 2309: wpi_plcp_signal(12) : wpi_plcp_signal(2);
! 2310: bcn->flags = htole32(WPI_TX_AUTO_SEQ | WPI_TX_INSERT_TSTAMP);
! 2311:
! 2312: /* save and trim IEEE802.11 header */
! 2313: m_copydata(m0, 0, sizeof (struct ieee80211_frame), (caddr_t)&bcn->wh);
! 2314: m_adj(m0, sizeof (struct ieee80211_frame));
! 2315:
! 2316: /* assume beacon frame is contiguous */
! 2317: error = bus_dmamap_load(sc->sc_dmat, data->map, mtod(m0, void *),
! 2318: m0->m_pkthdr.len, NULL, BUS_DMA_NOWAIT);
! 2319: if (error != 0) {
! 2320: printf("%s: could not map beacon\n", sc->sc_dev.dv_xname);
! 2321: m_freem(m0);
! 2322: return error;
! 2323: }
! 2324:
! 2325: data->m = m0;
! 2326:
! 2327: /* first scatter/gather segment is used by the beacon command */
! 2328: desc->flags = htole32(WPI_PAD32(m0->m_pkthdr.len) << 28 | 2 << 24);
! 2329: desc->segs[0].addr = htole32(ring->cmd_dma.paddr +
! 2330: ring->cur * sizeof (struct wpi_tx_cmd));
! 2331: desc->segs[0].len = htole32(4 + sizeof (struct wpi_cmd_beacon));
! 2332: desc->segs[1].addr = htole32(data->map->dm_segs[0].ds_addr);
! 2333: desc->segs[1].len = htole32(data->map->dm_segs[0].ds_len);
! 2334:
! 2335: /* kick cmd ring */
! 2336: ring->cur = (ring->cur + 1) % WPI_CMD_RING_COUNT;
! 2337: WPI_WRITE(sc, WPI_TX_WIDX, ring->qid << 8 | ring->cur);
! 2338:
! 2339: return 0;
! 2340: }
! 2341: #endif
! 2342:
! 2343: int
! 2344: wpi_auth(struct wpi_softc *sc)
! 2345: {
! 2346: struct ieee80211com *ic = &sc->sc_ic;
! 2347: struct ieee80211_node *ni = ic->ic_bss;
! 2348: struct wpi_node_info node;
! 2349: int error;
! 2350:
! 2351: /* update adapter's configuration */
! 2352: IEEE80211_ADDR_COPY(sc->config.bssid, ni->ni_bssid);
! 2353: sc->config.chan = ieee80211_chan2ieee(ic, ni->ni_chan);
! 2354: if (IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) {
! 2355: sc->config.flags |= htole32(WPI_CONFIG_AUTO |
! 2356: WPI_CONFIG_24GHZ);
! 2357: }
! 2358: switch (ic->ic_curmode) {
! 2359: case IEEE80211_MODE_11A:
! 2360: sc->config.cck_mask = 0;
! 2361: sc->config.ofdm_mask = 0x15;
! 2362: break;
! 2363: case IEEE80211_MODE_11B:
! 2364: sc->config.cck_mask = 0x03;
! 2365: sc->config.ofdm_mask = 0;
! 2366: break;
! 2367: default: /* assume 802.11b/g */
! 2368: sc->config.cck_mask = 0x0f;
! 2369: sc->config.ofdm_mask = 0x15;
! 2370: }
! 2371: if (ic->ic_flags & IEEE80211_F_SHSLOT)
! 2372: sc->config.flags |= htole32(WPI_CONFIG_SHSLOT);
! 2373: if (ic->ic_flags & IEEE80211_F_SHPREAMBLE)
! 2374: sc->config.flags |= htole32(WPI_CONFIG_SHPREAMBLE);
! 2375: DPRINTF(("config chan %d flags %x cck %x ofdm %x\n", sc->config.chan,
! 2376: sc->config.flags, sc->config.cck_mask, sc->config.ofdm_mask));
! 2377: error = wpi_cmd(sc, WPI_CMD_CONFIGURE, &sc->config,
! 2378: sizeof (struct wpi_config), 1);
! 2379: if (error != 0) {
! 2380: printf("%s: could not configure\n", sc->sc_dev.dv_xname);
! 2381: return error;
! 2382: }
! 2383:
! 2384: /* configuration has changed, set Tx power accordingly */
! 2385: if ((error = wpi_set_txpower(sc, ni->ni_chan, 1)) != 0) {
! 2386: printf("%s: could not set Tx power\n", sc->sc_dev.dv_xname);
! 2387: return error;
! 2388: }
! 2389:
! 2390: /* add default node */
! 2391: memset(&node, 0, sizeof node);
! 2392: IEEE80211_ADDR_COPY(node.bssid, ni->ni_bssid);
! 2393: node.id = WPI_ID_BSS;
! 2394: node.rate = (ic->ic_curmode == IEEE80211_MODE_11A) ?
! 2395: wpi_plcp_signal(12) : wpi_plcp_signal(2);
! 2396: node.action = htole32(WPI_ACTION_SET_RATE);
! 2397: node.antenna = WPI_ANTENNA_BOTH;
! 2398: error = wpi_cmd(sc, WPI_CMD_ADD_NODE, &node, sizeof node, 1);
! 2399: if (error != 0) {
! 2400: printf("%s: could not add BSS node\n", sc->sc_dev.dv_xname);
! 2401: return error;
! 2402: }
! 2403:
! 2404: return 0;
! 2405: }
! 2406:
! 2407: /*
! 2408: * Send a scan request to the firmware. Since this command is huge, we map it
! 2409: * into a mbuf instead of using the pre-allocated set of commands.
! 2410: */
! 2411: int
! 2412: wpi_scan(struct wpi_softc *sc, uint16_t flags)
! 2413: {
! 2414: struct ieee80211com *ic = &sc->sc_ic;
! 2415: struct wpi_tx_ring *ring = &sc->cmdq;
! 2416: struct wpi_tx_desc *desc;
! 2417: struct wpi_tx_data *data;
! 2418: struct wpi_tx_cmd *cmd;
! 2419: struct wpi_scan_hdr *hdr;
! 2420: struct wpi_scan_chan *chan;
! 2421: struct ieee80211_frame *wh;
! 2422: struct ieee80211_rateset *rs;
! 2423: struct ieee80211_channel *c;
! 2424: enum ieee80211_phymode mode;
! 2425: uint8_t *frm;
! 2426: int pktlen, error;
! 2427:
! 2428: desc = &ring->desc[ring->cur];
! 2429: data = &ring->data[ring->cur];
! 2430:
! 2431: MGETHDR(data->m, M_DONTWAIT, MT_DATA);
! 2432: if (data->m == NULL) {
! 2433: printf("%s: could not allocate mbuf for scan command\n",
! 2434: sc->sc_dev.dv_xname);
! 2435: return ENOMEM;
! 2436: }
! 2437: MCLGET(data->m, M_DONTWAIT);
! 2438: if (!(data->m->m_flags & M_EXT)) {
! 2439: m_freem(data->m);
! 2440: data->m = NULL;
! 2441: printf("%s: could not allocate mbuf for scan command\n",
! 2442: sc->sc_dev.dv_xname);
! 2443: return ENOMEM;
! 2444: }
! 2445:
! 2446: cmd = mtod(data->m, struct wpi_tx_cmd *);
! 2447: cmd->code = WPI_CMD_SCAN;
! 2448: cmd->flags = 0;
! 2449: cmd->qid = ring->qid;
! 2450: cmd->idx = ring->cur;
! 2451:
! 2452: hdr = (struct wpi_scan_hdr *)cmd->data;
! 2453: memset(hdr, 0, sizeof (struct wpi_scan_hdr));
! 2454: hdr->txflags = htole32(WPI_TX_AUTO_SEQ);
! 2455: hdr->id = WPI_ID_BROADCAST;
! 2456: hdr->lifetime = htole32(WPI_LIFETIME_INFINITE);
! 2457: /*
! 2458: * Move to the next channel if no packets are received within 5 msecs
! 2459: * after sending the probe request (this helps to reduce the duration
! 2460: * of active scans).
! 2461: */
! 2462: hdr->quiet = htole16(5); /* timeout in milliseconds */
! 2463: hdr->plcp_threshold = htole16(1); /* min # of packets */
! 2464:
! 2465: if (flags & IEEE80211_CHAN_A) {
! 2466: hdr->crc_threshold = htole16(1);
! 2467: /* send probe requests at 6Mbps */
! 2468: hdr->rate = wpi_plcp_signal(12);
! 2469: } else {
! 2470: hdr->flags = htole32(WPI_CONFIG_24GHZ | WPI_CONFIG_AUTO);
! 2471: /* send probe requests at 1Mbps */
! 2472: hdr->rate = wpi_plcp_signal(2);
! 2473: }
! 2474:
! 2475: /* for directed scans, firmware inserts the essid IE itself */
! 2476: hdr->essid[0].id = IEEE80211_ELEMID_SSID;
! 2477: hdr->essid[0].len = ic->ic_des_esslen;
! 2478: memcpy(hdr->essid[0].data, ic->ic_des_essid, ic->ic_des_esslen);
! 2479:
! 2480: /*
! 2481: * Build a probe request frame. Most of the following code is a
! 2482: * copy & paste of what is done in net80211.
! 2483: */
! 2484: wh = (struct ieee80211_frame *)(hdr + 1);
! 2485: wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT |
! 2486: IEEE80211_FC0_SUBTYPE_PROBE_REQ;
! 2487: wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
! 2488: IEEE80211_ADDR_COPY(wh->i_addr1, etherbroadcastaddr);
! 2489: IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_myaddr);
! 2490: IEEE80211_ADDR_COPY(wh->i_addr3, etherbroadcastaddr);
! 2491: *(u_int16_t *)&wh->i_dur[0] = 0; /* filled by h/w */
! 2492: *(u_int16_t *)&wh->i_seq[0] = 0; /* filled by h/w */
! 2493:
! 2494: frm = (uint8_t *)(wh + 1);
! 2495:
! 2496: /* add empty essid IE (firmware generates it for directed scans) */
! 2497: *frm++ = IEEE80211_ELEMID_SSID;
! 2498: *frm++ = 0;
! 2499:
! 2500: mode = ieee80211_chan2mode(ic, ic->ic_ibss_chan);
! 2501: rs = &ic->ic_sup_rates[mode];
! 2502:
! 2503: /* add supported rates IE */
! 2504: frm = ieee80211_add_rates(frm, rs);
! 2505:
! 2506: /* add supported xrates IE */
! 2507: if (rs->rs_nrates > IEEE80211_RATE_SIZE)
! 2508: frm = ieee80211_add_xrates(frm, rs);
! 2509:
! 2510: /* setup length of probe request */
! 2511: hdr->paylen = htole16(frm - (uint8_t *)wh);
! 2512:
! 2513: chan = (struct wpi_scan_chan *)frm;
! 2514: for (c = &ic->ic_channels[1];
! 2515: c <= &ic->ic_channels[IEEE80211_CHAN_MAX]; c++) {
! 2516: if ((c->ic_flags & flags) != flags)
! 2517: continue;
! 2518:
! 2519: chan->chan = ieee80211_chan2ieee(ic, c);
! 2520: chan->flags = 0;
! 2521: if (!(c->ic_flags & IEEE80211_CHAN_PASSIVE)) {
! 2522: chan->flags |= WPI_CHAN_ACTIVE;
! 2523: if (ic->ic_des_esslen != 0)
! 2524: chan->flags |= WPI_CHAN_DIRECT;
! 2525: }
! 2526: chan->dsp_gain = 0x6e;
! 2527: if (IEEE80211_IS_CHAN_5GHZ(c)) {
! 2528: chan->rf_gain = 0x3b;
! 2529: chan->active = htole16(10);
! 2530: chan->passive = htole16(110);
! 2531: } else {
! 2532: chan->rf_gain = 0x28;
! 2533: chan->active = htole16(20);
! 2534: chan->passive = htole16(120);
! 2535: }
! 2536: hdr->nchan++;
! 2537: chan++;
! 2538:
! 2539: frm += sizeof (struct wpi_scan_chan);
! 2540: }
! 2541:
! 2542: hdr->len = htole16(frm - (uint8_t *)hdr);
! 2543: pktlen = frm - (uint8_t *)cmd;
! 2544:
! 2545: error = bus_dmamap_load(sc->sc_dmat, data->map, cmd, pktlen, NULL,
! 2546: BUS_DMA_NOWAIT);
! 2547: if (error != 0) {
! 2548: printf("%s: could not map scan command\n",
! 2549: sc->sc_dev.dv_xname);
! 2550: m_freem(data->m);
! 2551: data->m = NULL;
! 2552: return error;
! 2553: }
! 2554:
! 2555: desc->flags = htole32(WPI_PAD32(pktlen) << 28 | 1 << 24);
! 2556: desc->segs[0].addr = htole32(data->map->dm_segs[0].ds_addr);
! 2557: desc->segs[0].len = htole32(data->map->dm_segs[0].ds_len);
! 2558:
! 2559: /* kick cmd ring */
! 2560: ring->cur = (ring->cur + 1) % WPI_CMD_RING_COUNT;
! 2561: WPI_WRITE(sc, WPI_TX_WIDX, ring->qid << 8 | ring->cur);
! 2562:
! 2563: return 0; /* will be notified async. of failure/success */
! 2564: }
! 2565:
! 2566: int
! 2567: wpi_config(struct wpi_softc *sc)
! 2568: {
! 2569: struct ieee80211com *ic = &sc->sc_ic;
! 2570: struct ifnet *ifp = &ic->ic_if;
! 2571: struct wpi_power power;
! 2572: struct wpi_bluetooth bluetooth;
! 2573: struct wpi_node_info node;
! 2574: int error;
! 2575:
! 2576: /* set power mode */
! 2577: memset(&power, 0, sizeof power);
! 2578: power.flags = htole32(WPI_POWER_CAM | 0x8);
! 2579: error = wpi_cmd(sc, WPI_CMD_SET_POWER_MODE, &power, sizeof power, 0);
! 2580: if (error != 0) {
! 2581: printf("%s: could not set power mode\n", sc->sc_dev.dv_xname);
! 2582: return error;
! 2583: }
! 2584:
! 2585: /* configure bluetooth coexistence */
! 2586: memset(&bluetooth, 0, sizeof bluetooth);
! 2587: bluetooth.flags = 3;
! 2588: bluetooth.lead = 0xaa;
! 2589: bluetooth.kill = 1;
! 2590: error = wpi_cmd(sc, WPI_CMD_BLUETOOTH, &bluetooth, sizeof bluetooth,
! 2591: 0);
! 2592: if (error != 0) {
! 2593: printf("%s: could not configure bluetooth coexistence\n",
! 2594: sc->sc_dev.dv_xname);
! 2595: return error;
! 2596: }
! 2597:
! 2598: /* configure adapter */
! 2599: memset(&sc->config, 0, sizeof (struct wpi_config));
! 2600: IEEE80211_ADDR_COPY(ic->ic_myaddr, LLADDR(ifp->if_sadl));
! 2601: IEEE80211_ADDR_COPY(sc->config.myaddr, ic->ic_myaddr);
! 2602: /* set default channel */
! 2603: sc->config.chan = ieee80211_chan2ieee(ic, ic->ic_ibss_chan);
! 2604: sc->config.flags = htole32(WPI_CONFIG_TSF);
! 2605: if (IEEE80211_IS_CHAN_2GHZ(ic->ic_ibss_chan)) {
! 2606: sc->config.flags |= htole32(WPI_CONFIG_AUTO |
! 2607: WPI_CONFIG_24GHZ);
! 2608: }
! 2609: sc->config.filter = 0;
! 2610: switch (ic->ic_opmode) {
! 2611: case IEEE80211_M_STA:
! 2612: sc->config.mode = WPI_MODE_STA;
! 2613: sc->config.filter |= htole32(WPI_FILTER_MULTICAST);
! 2614: break;
! 2615: case IEEE80211_M_IBSS:
! 2616: case IEEE80211_M_AHDEMO:
! 2617: sc->config.mode = WPI_MODE_IBSS;
! 2618: break;
! 2619: case IEEE80211_M_HOSTAP:
! 2620: sc->config.mode = WPI_MODE_HOSTAP;
! 2621: break;
! 2622: case IEEE80211_M_MONITOR:
! 2623: sc->config.mode = WPI_MODE_MONITOR;
! 2624: sc->config.filter |= htole32(WPI_FILTER_MULTICAST |
! 2625: WPI_FILTER_CTL | WPI_FILTER_PROMISC);
! 2626: break;
! 2627: }
! 2628: sc->config.cck_mask = 0x0f; /* not yet negotiated */
! 2629: sc->config.ofdm_mask = 0xff; /* not yet negotiated */
! 2630: error = wpi_cmd(sc, WPI_CMD_CONFIGURE, &sc->config,
! 2631: sizeof (struct wpi_config), 0);
! 2632: if (error != 0) {
! 2633: printf("%s: configure command failed\n", sc->sc_dev.dv_xname);
! 2634: return error;
! 2635: }
! 2636:
! 2637: /* configuration has changed, set Tx power accordingly */
! 2638: if ((error = wpi_set_txpower(sc, ic->ic_ibss_chan, 0)) != 0) {
! 2639: printf("%s: could not set Tx power\n", sc->sc_dev.dv_xname);
! 2640: return error;
! 2641: }
! 2642:
! 2643: /* add broadcast node */
! 2644: memset(&node, 0, sizeof node);
! 2645: IEEE80211_ADDR_COPY(node.bssid, etherbroadcastaddr);
! 2646: node.id = WPI_ID_BROADCAST;
! 2647: node.rate = wpi_plcp_signal(2);
! 2648: node.action = htole32(WPI_ACTION_SET_RATE);
! 2649: node.antenna = WPI_ANTENNA_BOTH;
! 2650: error = wpi_cmd(sc, WPI_CMD_ADD_NODE, &node, sizeof node, 0);
! 2651: if (error != 0) {
! 2652: printf("%s: could not add broadcast node\n",
! 2653: sc->sc_dev.dv_xname);
! 2654: return error;
! 2655: }
! 2656:
! 2657: if ((error = wpi_mrr_setup(sc)) != 0) {
! 2658: printf("%s: could not setup MRR\n", sc->sc_dev.dv_xname);
! 2659: return error;
! 2660: }
! 2661:
! 2662: return 0;
! 2663: }
! 2664:
! 2665: void
! 2666: wpi_stop_master(struct wpi_softc *sc)
! 2667: {
! 2668: uint32_t tmp;
! 2669: int ntries;
! 2670:
! 2671: tmp = WPI_READ(sc, WPI_RESET);
! 2672: WPI_WRITE(sc, WPI_RESET, tmp | WPI_STOP_MASTER);
! 2673:
! 2674: tmp = WPI_READ(sc, WPI_GPIO_CTL);
! 2675: if ((tmp & WPI_GPIO_PWR_STATUS) == WPI_GPIO_PWR_SLEEP)
! 2676: return; /* already asleep */
! 2677:
! 2678: for (ntries = 0; ntries < 100; ntries++) {
! 2679: if (WPI_READ(sc, WPI_RESET) & WPI_MASTER_DISABLED)
! 2680: break;
! 2681: DELAY(10);
! 2682: }
! 2683: if (ntries == 100) {
! 2684: printf("%s: timeout waiting for master\n",
! 2685: sc->sc_dev.dv_xname);
! 2686: }
! 2687: }
! 2688:
! 2689: int
! 2690: wpi_power_up(struct wpi_softc *sc)
! 2691: {
! 2692: uint32_t tmp;
! 2693: int ntries;
! 2694:
! 2695: wpi_mem_lock(sc);
! 2696: tmp = wpi_mem_read(sc, WPI_MEM_POWER);
! 2697: wpi_mem_write(sc, WPI_MEM_POWER, tmp & ~0x03000000);
! 2698: wpi_mem_unlock(sc);
! 2699:
! 2700: for (ntries = 0; ntries < 5000; ntries++) {
! 2701: if (WPI_READ(sc, WPI_GPIO_STATUS) & WPI_POWERED)
! 2702: break;
! 2703: DELAY(10);
! 2704: }
! 2705: if (ntries == 5000) {
! 2706: printf("%s: timeout waiting for NIC to power up\n",
! 2707: sc->sc_dev.dv_xname);
! 2708: return ETIMEDOUT;
! 2709: }
! 2710: return 0;
! 2711: }
! 2712:
! 2713: int
! 2714: wpi_reset(struct wpi_softc *sc)
! 2715: {
! 2716: uint32_t tmp;
! 2717: int ntries;
! 2718:
! 2719: /* clear any pending interrupts */
! 2720: WPI_WRITE(sc, WPI_INTR, 0xffffffff);
! 2721:
! 2722: tmp = WPI_READ(sc, WPI_PLL_CTL);
! 2723: WPI_WRITE(sc, WPI_PLL_CTL, tmp | WPI_PLL_INIT);
! 2724:
! 2725: tmp = WPI_READ(sc, WPI_CHICKEN);
! 2726: WPI_WRITE(sc, WPI_CHICKEN, tmp | WPI_CHICKEN_RXNOLOS);
! 2727:
! 2728: tmp = WPI_READ(sc, WPI_GPIO_CTL);
! 2729: WPI_WRITE(sc, WPI_GPIO_CTL, tmp | WPI_GPIO_INIT);
! 2730:
! 2731: /* wait for clock stabilization */
! 2732: for (ntries = 0; ntries < 1000; ntries++) {
! 2733: if (WPI_READ(sc, WPI_GPIO_CTL) & WPI_GPIO_CLOCK)
! 2734: break;
! 2735: DELAY(10);
! 2736: }
! 2737: if (ntries == 1000) {
! 2738: printf("%s: timeout waiting for clock stabilization\n",
! 2739: sc->sc_dev.dv_xname);
! 2740: return ETIMEDOUT;
! 2741: }
! 2742:
! 2743: /* initialize EEPROM */
! 2744: tmp = WPI_READ(sc, WPI_EEPROM_STATUS);
! 2745: if ((tmp & WPI_EEPROM_VERSION) == 0) {
! 2746: printf("%s: EEPROM not found\n", sc->sc_dev.dv_xname);
! 2747: return EIO;
! 2748: }
! 2749: WPI_WRITE(sc, WPI_EEPROM_STATUS, tmp & ~WPI_EEPROM_LOCKED);
! 2750:
! 2751: return 0;
! 2752: }
! 2753:
! 2754: void
! 2755: wpi_hw_config(struct wpi_softc *sc)
! 2756: {
! 2757: uint32_t rev, hw;
! 2758:
! 2759: /* voodoo from the reference driver */
! 2760: hw = WPI_READ(sc, WPI_HWCONFIG);
! 2761:
! 2762: rev = pci_conf_read(sc->sc_pct, sc->sc_pcitag, PCI_CLASS_REG);
! 2763: rev = PCI_REVISION(rev);
! 2764: if ((rev & 0xc0) == 0x40)
! 2765: hw |= WPI_HW_ALM_MB;
! 2766: else if (!(rev & 0x80))
! 2767: hw |= WPI_HW_ALM_MM;
! 2768:
! 2769: if (sc->cap == 0x80)
! 2770: hw |= WPI_HW_SKU_MRC;
! 2771:
! 2772: hw &= ~WPI_HW_REV_D;
! 2773: if ((letoh16(sc->rev) & 0xf0) == 0xd0)
! 2774: hw |= WPI_HW_REV_D;
! 2775:
! 2776: if (sc->type > 1)
! 2777: hw |= WPI_HW_TYPE_B;
! 2778:
! 2779: DPRINTF(("setting h/w config %x\n", hw));
! 2780: WPI_WRITE(sc, WPI_HWCONFIG, hw);
! 2781: }
! 2782:
! 2783: int
! 2784: wpi_init(struct ifnet *ifp)
! 2785: {
! 2786: struct wpi_softc *sc = ifp->if_softc;
! 2787: struct ieee80211com *ic = &sc->sc_ic;
! 2788: uint32_t tmp;
! 2789: int qid, ntries, error;
! 2790:
! 2791: (void)wpi_reset(sc);
! 2792:
! 2793: wpi_mem_lock(sc);
! 2794: wpi_mem_write(sc, WPI_MEM_CLOCK1, 0xa00);
! 2795: DELAY(20);
! 2796: tmp = wpi_mem_read(sc, WPI_MEM_PCIDEV);
! 2797: wpi_mem_write(sc, WPI_MEM_PCIDEV, tmp | 0x800);
! 2798: wpi_mem_unlock(sc);
! 2799:
! 2800: (void)wpi_power_up(sc);
! 2801: wpi_hw_config(sc);
! 2802:
! 2803: /* init Rx ring */
! 2804: wpi_mem_lock(sc);
! 2805: WPI_WRITE(sc, WPI_RX_BASE, sc->rxq.desc_dma.paddr);
! 2806: WPI_WRITE(sc, WPI_RX_RIDX_PTR, sc->shared_dma.paddr +
! 2807: offsetof(struct wpi_shared, next));
! 2808: WPI_WRITE(sc, WPI_RX_WIDX, (WPI_RX_RING_COUNT - 1) & ~7);
! 2809: WPI_WRITE(sc, WPI_RX_CONFIG, 0xa9601010);
! 2810: wpi_mem_unlock(sc);
! 2811:
! 2812: /* init Tx rings */
! 2813: wpi_mem_lock(sc);
! 2814: wpi_mem_write(sc, WPI_MEM_MODE, 2); /* bypass mode */
! 2815: wpi_mem_write(sc, WPI_MEM_RA, 1); /* enable RA0 */
! 2816: wpi_mem_write(sc, WPI_MEM_TXCFG, 0x3f); /* enable all 6 Tx rings */
! 2817: wpi_mem_write(sc, WPI_MEM_BYPASS1, 0x10000);
! 2818: wpi_mem_write(sc, WPI_MEM_BYPASS2, 0x30002);
! 2819: wpi_mem_write(sc, WPI_MEM_MAGIC4, 4);
! 2820: wpi_mem_write(sc, WPI_MEM_MAGIC5, 5);
! 2821:
! 2822: WPI_WRITE(sc, WPI_TX_BASE_PTR, sc->shared_dma.paddr);
! 2823: WPI_WRITE(sc, WPI_MSG_CONFIG, 0xffff05a5);
! 2824:
! 2825: for (qid = 0; qid < 6; qid++) {
! 2826: WPI_WRITE(sc, WPI_TX_CTL(qid), 0);
! 2827: WPI_WRITE(sc, WPI_TX_BASE(qid), 0);
! 2828: WPI_WRITE(sc, WPI_TX_CONFIG(qid), 0x80200008);
! 2829: }
! 2830: wpi_mem_unlock(sc);
! 2831:
! 2832: /* clear "radio off" and "disable command" bits (reversed logic) */
! 2833: WPI_WRITE(sc, WPI_UCODE_CLR, WPI_RADIO_OFF);
! 2834: WPI_WRITE(sc, WPI_UCODE_CLR, WPI_DISABLE_CMD);
! 2835:
! 2836: /* clear any pending interrupts */
! 2837: WPI_WRITE(sc, WPI_INTR, 0xffffffff);
! 2838: /* enable interrupts */
! 2839: WPI_WRITE(sc, WPI_MASK, WPI_INTR_MASK);
! 2840:
! 2841: /* not sure why/if this is necessary... */
! 2842: WPI_WRITE(sc, WPI_UCODE_CLR, WPI_RADIO_OFF);
! 2843: WPI_WRITE(sc, WPI_UCODE_CLR, WPI_RADIO_OFF);
! 2844:
! 2845: if ((error = wpi_load_firmware(sc)) != 0) {
! 2846: printf("%s: could not load firmware\n", sc->sc_dev.dv_xname);
! 2847: goto fail1;
! 2848: }
! 2849:
! 2850: /* wait for thermal sensors to calibrate */
! 2851: for (ntries = 0; ntries < 1000; ntries++) {
! 2852: if ((sc->temp = (int)WPI_READ(sc, WPI_TEMPERATURE)) != 0)
! 2853: break;
! 2854: DELAY(10);
! 2855: }
! 2856: if (ntries == 1000) {
! 2857: printf("%s: timeout waiting for thermal sensors calibration\n",
! 2858: sc->sc_dev.dv_xname);
! 2859: error = ETIMEDOUT;
! 2860: goto fail1;
! 2861: }
! 2862: DPRINTF(("temperature %d\n", sc->temp));
! 2863: sc->sensor.value = sc->temp + 260;
! 2864: sc->sensor.flags &= ~SENSOR_FINVALID;
! 2865:
! 2866: if ((error = wpi_config(sc)) != 0) {
! 2867: printf("%s: could not configure device\n",
! 2868: sc->sc_dev.dv_xname);
! 2869: goto fail1;
! 2870: }
! 2871:
! 2872: ifp->if_flags &= ~IFF_OACTIVE;
! 2873: ifp->if_flags |= IFF_RUNNING;
! 2874:
! 2875: if (ic->ic_opmode != IEEE80211_M_MONITOR)
! 2876: ieee80211_begin_scan(ifp);
! 2877: else
! 2878: ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
! 2879:
! 2880: return 0;
! 2881:
! 2882: fail1: wpi_stop(ifp, 1);
! 2883: return error;
! 2884: }
! 2885:
! 2886: void
! 2887: wpi_stop(struct ifnet *ifp, int disable)
! 2888: {
! 2889: struct wpi_softc *sc = ifp->if_softc;
! 2890: struct ieee80211com *ic = &sc->sc_ic;
! 2891: uint32_t tmp;
! 2892: int ac;
! 2893:
! 2894: ifp->if_timer = sc->sc_tx_timer = 0;
! 2895: ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
! 2896:
! 2897: ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
! 2898:
! 2899: /* disable interrupts */
! 2900: WPI_WRITE(sc, WPI_MASK, 0);
! 2901: WPI_WRITE(sc, WPI_INTR, WPI_INTR_MASK);
! 2902: WPI_WRITE(sc, WPI_INTR_STATUS, 0xff);
! 2903: WPI_WRITE(sc, WPI_INTR_STATUS, 0x00070000);
! 2904:
! 2905: wpi_mem_lock(sc);
! 2906: wpi_mem_write(sc, WPI_MEM_MODE, 0);
! 2907: wpi_mem_unlock(sc);
! 2908:
! 2909: /* reset all Tx rings */
! 2910: for (ac = 0; ac < 4; ac++)
! 2911: wpi_reset_tx_ring(sc, &sc->txq[ac]);
! 2912: wpi_reset_tx_ring(sc, &sc->cmdq);
! 2913:
! 2914: /* reset Rx ring */
! 2915: wpi_reset_rx_ring(sc, &sc->rxq);
! 2916:
! 2917: /* temperature is no longer valid */
! 2918: sc->sensor.value = 0;
! 2919: sc->sensor.flags |= SENSOR_FINVALID;
! 2920:
! 2921: wpi_mem_lock(sc);
! 2922: wpi_mem_write(sc, WPI_MEM_CLOCK2, 0x200);
! 2923: wpi_mem_unlock(sc);
! 2924:
! 2925: DELAY(5);
! 2926:
! 2927: wpi_stop_master(sc);
! 2928:
! 2929: tmp = WPI_READ(sc, WPI_RESET);
! 2930: WPI_WRITE(sc, WPI_RESET, tmp | WPI_SW_RESET);
! 2931: }
! 2932:
! 2933: struct cfdriver wpi_cd = {
! 2934: NULL, "wpi", DV_IFNET
! 2935: };
CVSweb