Annotation of sys/dev/pci/if_ipw.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: if_ipw.c,v 1.67 2007/07/18 18:10:31 damien Exp $ */
! 2:
! 3: /*-
! 4: * Copyright (c) 2004-2006
! 5: * Damien Bergamini <damien.bergamini@free.fr>. All rights reserved.
! 6: *
! 7: * Redistribution and use in source and binary forms, with or without
! 8: * modification, are permitted provided that the following conditions
! 9: * are met:
! 10: * 1. Redistributions of source code must retain the above copyright
! 11: * notice unmodified, this list of conditions, and the following
! 12: * disclaimer.
! 13: * 2. Redistributions in binary form must reproduce the above copyright
! 14: * notice, this list of conditions and the following disclaimer in the
! 15: * documentation and/or other materials provided with the distribution.
! 16: *
! 17: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
! 18: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 19: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 20: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
! 21: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 22: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 23: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 24: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 25: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 26: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 27: * SUCH DAMAGE.
! 28: */
! 29:
! 30: /*
! 31: * Driver for Intel PRO/Wireless 2100 802.11 network adapters.
! 32: */
! 33:
! 34: #include "bpfilter.h"
! 35:
! 36: #include <sys/param.h>
! 37: #include <sys/sockio.h>
! 38: #include <sys/sysctl.h>
! 39: #include <sys/mbuf.h>
! 40: #include <sys/kernel.h>
! 41: #include <sys/socket.h>
! 42: #include <sys/systm.h>
! 43: #include <sys/malloc.h>
! 44: #include <sys/conf.h>
! 45: #include <sys/device.h>
! 46:
! 47: #include <machine/bus.h>
! 48: #include <machine/endian.h>
! 49: #include <machine/intr.h>
! 50:
! 51: #include <dev/pci/pcireg.h>
! 52: #include <dev/pci/pcivar.h>
! 53: #include <dev/pci/pcidevs.h>
! 54:
! 55: #if NBPFILTER > 0
! 56: #include <net/bpf.h>
! 57: #endif
! 58: #include <net/if.h>
! 59: #include <net/if_arp.h>
! 60: #include <net/if_dl.h>
! 61: #include <net/if_media.h>
! 62: #include <net/if_types.h>
! 63:
! 64: #include <netinet/in.h>
! 65: #include <netinet/in_systm.h>
! 66: #include <netinet/in_var.h>
! 67: #include <netinet/if_ether.h>
! 68: #include <netinet/ip.h>
! 69:
! 70: #include <net80211/ieee80211_var.h>
! 71: #include <net80211/ieee80211_radiotap.h>
! 72:
! 73: #include <dev/pci/if_ipwreg.h>
! 74: #include <dev/pci/if_ipwvar.h>
! 75:
! 76: int ipw_match(struct device *, void *, void *);
! 77: void ipw_attach(struct device *, struct device *, void *);
! 78: void ipw_power(int, void *);
! 79: int ipw_dma_alloc(struct ipw_softc *);
! 80: void ipw_release(struct ipw_softc *);
! 81: int ipw_media_change(struct ifnet *);
! 82: void ipw_media_status(struct ifnet *, struct ifmediareq *);
! 83: int ipw_newstate(struct ieee80211com *, enum ieee80211_state, int);
! 84: uint16_t ipw_read_prom_word(struct ipw_softc *, uint8_t);
! 85: void ipw_command_intr(struct ipw_softc *, struct ipw_soft_buf *);
! 86: void ipw_newstate_intr(struct ipw_softc *, struct ipw_soft_buf *);
! 87: void ipw_data_intr(struct ipw_softc *, struct ipw_status *,
! 88: struct ipw_soft_bd *, struct ipw_soft_buf *);
! 89: void ipw_notification_intr(struct ipw_softc *,
! 90: struct ipw_soft_buf *);
! 91: void ipw_rx_intr(struct ipw_softc *);
! 92: void ipw_release_sbd(struct ipw_softc *, struct ipw_soft_bd *);
! 93: void ipw_tx_intr(struct ipw_softc *);
! 94: int ipw_intr(void *);
! 95: int ipw_cmd(struct ipw_softc *, uint32_t, void *, uint32_t);
! 96: int ipw_tx_start(struct ifnet *, struct mbuf *,
! 97: struct ieee80211_node *);
! 98: void ipw_start(struct ifnet *);
! 99: void ipw_watchdog(struct ifnet *);
! 100: int ipw_ioctl(struct ifnet *, u_long, caddr_t);
! 101: uint32_t ipw_read_table1(struct ipw_softc *, uint32_t);
! 102: void ipw_write_table1(struct ipw_softc *, uint32_t, uint32_t);
! 103: int ipw_read_table2(struct ipw_softc *, uint32_t, void *,
! 104: uint32_t *);
! 105: void ipw_stop_master(struct ipw_softc *);
! 106: int ipw_reset(struct ipw_softc *);
! 107: int ipw_load_ucode(struct ipw_softc *, u_char *, int);
! 108: int ipw_load_firmware(struct ipw_softc *, u_char *, int);
! 109: int ipw_read_firmware(struct ipw_softc *, struct ipw_firmware *);
! 110: int ipw_config(struct ipw_softc *);
! 111: int ipw_init(struct ifnet *);
! 112: void ipw_stop(struct ifnet *, int);
! 113: void ipw_read_mem_1(struct ipw_softc *, bus_size_t, uint8_t *,
! 114: bus_size_t);
! 115: void ipw_write_mem_1(struct ipw_softc *, bus_size_t, uint8_t *,
! 116: bus_size_t);
! 117:
! 118: static __inline uint8_t
! 119: MEM_READ_1(struct ipw_softc *sc, uint32_t addr)
! 120: {
! 121: CSR_WRITE_4(sc, IPW_CSR_INDIRECT_ADDR, addr);
! 122: return CSR_READ_1(sc, IPW_CSR_INDIRECT_DATA);
! 123: }
! 124:
! 125: static __inline uint32_t
! 126: MEM_READ_4(struct ipw_softc *sc, uint32_t addr)
! 127: {
! 128: CSR_WRITE_4(sc, IPW_CSR_INDIRECT_ADDR, addr);
! 129: return CSR_READ_4(sc, IPW_CSR_INDIRECT_DATA);
! 130: }
! 131:
! 132: #ifdef IPW_DEBUG
! 133: #define DPRINTF(x) do { if (ipw_debug > 0) printf x; } while (0)
! 134: #define DPRINTFN(n, x) do { if (ipw_debug >= (n)) printf x; } while (0)
! 135: int ipw_debug = 0;
! 136: #else
! 137: #define DPRINTF(x)
! 138: #define DPRINTFN(n, x)
! 139: #endif
! 140:
! 141: struct cfattach ipw_ca = {
! 142: sizeof (struct ipw_softc), ipw_match, ipw_attach
! 143: };
! 144:
! 145: int
! 146: ipw_match(struct device *parent, void *match, void *aux)
! 147: {
! 148: struct pci_attach_args *pa = aux;
! 149:
! 150: if (PCI_VENDOR (pa->pa_id) == PCI_VENDOR_INTEL &&
! 151: PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_INTEL_PRO_WL_2100)
! 152: return 1;
! 153:
! 154: return 0;
! 155: }
! 156:
! 157: /* Base Address Register */
! 158: #define IPW_PCI_BAR0 0x10
! 159:
! 160: void
! 161: ipw_attach(struct device *parent, struct device *self, void *aux)
! 162: {
! 163: struct ipw_softc *sc = (struct ipw_softc *)self;
! 164: struct ieee80211com *ic = &sc->sc_ic;
! 165: struct ifnet *ifp = &ic->ic_if;
! 166: struct pci_attach_args *pa = aux;
! 167: const char *intrstr;
! 168: bus_space_tag_t memt;
! 169: bus_space_handle_t memh;
! 170: bus_addr_t base;
! 171: pci_intr_handle_t ih;
! 172: pcireg_t data;
! 173: uint16_t val;
! 174: int error, i;
! 175:
! 176: sc->sc_pct = pa->pa_pc;
! 177: sc->sc_pcitag = pa->pa_tag,
! 178:
! 179: /* clear device specific PCI configuration register 0x41 */
! 180: data = pci_conf_read(sc->sc_pct, sc->sc_pcitag, 0x40);
! 181: data &= ~0x0000ff00;
! 182: pci_conf_write(sc->sc_pct, sc->sc_pcitag, 0x40, data);
! 183:
! 184: /* map the register window */
! 185: error = pci_mapreg_map(pa, IPW_PCI_BAR0, PCI_MAPREG_TYPE_MEM |
! 186: PCI_MAPREG_MEM_TYPE_32BIT, 0, &memt, &memh, &base, &sc->sc_sz, 0);
! 187: if (error != 0) {
! 188: printf(": could not map memory space\n");
! 189: return;
! 190: }
! 191:
! 192: sc->sc_st = memt;
! 193: sc->sc_sh = memh;
! 194: sc->sc_dmat = pa->pa_dmat;
! 195:
! 196: /* disable interrupts */
! 197: CSR_WRITE_4(sc, IPW_CSR_INTR_MASK, 0);
! 198:
! 199: if (pci_intr_map(pa, &ih) != 0) {
! 200: printf(": could not map interrupt\n");
! 201: return;
! 202: }
! 203:
! 204: intrstr = pci_intr_string(sc->sc_pct, ih);
! 205: sc->sc_ih = pci_intr_establish(sc->sc_pct, ih, IPL_NET, ipw_intr, sc,
! 206: sc->sc_dev.dv_xname);
! 207: if (sc->sc_ih == NULL) {
! 208: printf(": could not establish interrupt");
! 209: if (intrstr != NULL)
! 210: printf(" at %s", intrstr);
! 211: printf("\n");
! 212: return;
! 213: }
! 214: printf(": %s", intrstr);
! 215:
! 216: if (ipw_reset(sc) != 0) {
! 217: printf(": could not reset adapter\n");
! 218: return;
! 219: }
! 220:
! 221: if (ipw_dma_alloc(sc) != 0) {
! 222: printf(": failed to allocate DMA resources\n");
! 223: return;
! 224: }
! 225:
! 226: ic->ic_phytype = IEEE80211_T_DS;
! 227: ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */
! 228: ic->ic_state = IEEE80211_S_INIT;
! 229:
! 230: /* set device capabilities */
! 231: ic->ic_caps =
! 232: IEEE80211_C_IBSS | /* IBSS mode supported */
! 233: IEEE80211_C_MONITOR | /* monitor mode supported */
! 234: IEEE80211_C_TXPMGT | /* tx power management */
! 235: IEEE80211_C_SHPREAMBLE | /* short preamble supported */
! 236: IEEE80211_C_WEP | /* s/w WEP */
! 237: IEEE80211_C_SCANALL; /* h/w scanning */
! 238:
! 239: /* read MAC address from EEPROM */
! 240: val = ipw_read_prom_word(sc, IPW_EEPROM_MAC + 0);
! 241: ic->ic_myaddr[0] = val >> 8;
! 242: ic->ic_myaddr[1] = val & 0xff;
! 243: val = ipw_read_prom_word(sc, IPW_EEPROM_MAC + 1);
! 244: ic->ic_myaddr[2] = val >> 8;
! 245: ic->ic_myaddr[3] = val & 0xff;
! 246: val = ipw_read_prom_word(sc, IPW_EEPROM_MAC + 2);
! 247: ic->ic_myaddr[4] = val >> 8;
! 248: ic->ic_myaddr[5] = val & 0xff;
! 249:
! 250: printf(", address %s\n", ether_sprintf(ic->ic_myaddr));
! 251:
! 252: /* set supported .11b rates */
! 253: ic->ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b;
! 254:
! 255: /* set supported .11b channels (1 through 14) */
! 256: for (i = 1; i <= 14; i++) {
! 257: ic->ic_channels[i].ic_freq =
! 258: ieee80211_ieee2mhz(i, IEEE80211_CHAN_B);
! 259: ic->ic_channels[i].ic_flags = IEEE80211_CHAN_B;
! 260: }
! 261:
! 262: /* IBSS channel undefined for now */
! 263: ic->ic_ibss_chan = &ic->ic_channels[0];
! 264:
! 265: ifp->if_softc = sc;
! 266: ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
! 267: ifp->if_init = ipw_init;
! 268: ifp->if_ioctl = ipw_ioctl;
! 269: ifp->if_start = ipw_start;
! 270: ifp->if_watchdog = ipw_watchdog;
! 271: IFQ_SET_READY(&ifp->if_snd);
! 272: bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
! 273:
! 274: if_attach(ifp);
! 275: ieee80211_ifattach(ifp);
! 276: /* override state transition machine */
! 277: sc->sc_newstate = ic->ic_newstate;
! 278: ic->ic_newstate = ipw_newstate;
! 279: ieee80211_media_init(ifp, ipw_media_change, ipw_media_status);
! 280:
! 281: sc->powerhook = powerhook_establish(ipw_power, sc);
! 282:
! 283: #if NBPFILTER > 0
! 284: bpfattach(&sc->sc_drvbpf, ifp, DLT_IEEE802_11_RADIO,
! 285: sizeof (struct ieee80211_frame) + IEEE80211_RADIOTAP_HDRLEN);
! 286:
! 287: sc->sc_rxtap_len = sizeof sc->sc_rxtapu;
! 288: sc->sc_rxtap.wr_ihdr.it_len = htole16(sc->sc_rxtap_len);
! 289: sc->sc_rxtap.wr_ihdr.it_present = htole32(IPW_RX_RADIOTAP_PRESENT);
! 290:
! 291: sc->sc_txtap_len = sizeof sc->sc_txtapu;
! 292: sc->sc_txtap.wt_ihdr.it_len = htole16(sc->sc_txtap_len);
! 293: sc->sc_txtap.wt_ihdr.it_present = htole32(IPW_TX_RADIOTAP_PRESENT);
! 294: #endif
! 295: }
! 296:
! 297: void
! 298: ipw_power(int why, void *arg)
! 299: {
! 300: struct ipw_softc *sc = arg;
! 301: struct ifnet *ifp;
! 302: pcireg_t data;
! 303:
! 304: if (why != PWR_RESUME)
! 305: return;
! 306:
! 307: /* clear device specific PCI configuration register 0x41 */
! 308: data = pci_conf_read(sc->sc_pct, sc->sc_pcitag, 0x40);
! 309: data &= ~0x0000ff00;
! 310: pci_conf_write(sc->sc_pct, sc->sc_pcitag, 0x40, data);
! 311:
! 312: ifp = &sc->sc_ic.ic_if;
! 313: if (ifp->if_flags & IFF_UP) {
! 314: ifp->if_init(ifp);
! 315: if (ifp->if_flags & IFF_RUNNING)
! 316: ifp->if_start(ifp);
! 317: }
! 318: }
! 319:
! 320: int
! 321: ipw_dma_alloc(struct ipw_softc *sc)
! 322: {
! 323: struct ipw_soft_bd *sbd;
! 324: struct ipw_soft_hdr *shdr;
! 325: struct ipw_soft_buf *sbuf;
! 326: int i, nsegs, error;
! 327:
! 328: /*
! 329: * Allocate and map tx ring.
! 330: */
! 331: error = bus_dmamap_create(sc->sc_dmat, IPW_TBD_SZ, 1, IPW_TBD_SZ, 0,
! 332: BUS_DMA_NOWAIT, &sc->tbd_map);
! 333: if (error != 0) {
! 334: printf("%s: could not create tx ring DMA map\n",
! 335: sc->sc_dev.dv_xname);
! 336: goto fail;
! 337: }
! 338:
! 339: error = bus_dmamem_alloc(sc->sc_dmat, IPW_TBD_SZ, PAGE_SIZE, 0,
! 340: &sc->tbd_seg, 1, &nsegs, BUS_DMA_NOWAIT);
! 341: if (error != 0) {
! 342: printf("%s: could not allocate tx ring DMA memory\n",
! 343: sc->sc_dev.dv_xname);
! 344: goto fail;
! 345: }
! 346:
! 347: error = bus_dmamem_map(sc->sc_dmat, &sc->tbd_seg, nsegs, IPW_TBD_SZ,
! 348: (caddr_t *)&sc->tbd_list, BUS_DMA_NOWAIT);
! 349: if (error != 0) {
! 350: printf("%s: could not map tx ring DMA memory\n",
! 351: sc->sc_dev.dv_xname);
! 352: goto fail;
! 353: }
! 354:
! 355: error = bus_dmamap_load(sc->sc_dmat, sc->tbd_map, sc->tbd_list,
! 356: IPW_TBD_SZ, NULL, BUS_DMA_NOWAIT);
! 357: if (error != 0) {
! 358: printf("%s: could not load tx ring DMA map\n",
! 359: sc->sc_dev.dv_xname);
! 360: goto fail;
! 361: }
! 362:
! 363: /*
! 364: * Allocate and map rx ring.
! 365: */
! 366: error = bus_dmamap_create(sc->sc_dmat, IPW_RBD_SZ, 1, IPW_RBD_SZ, 0,
! 367: BUS_DMA_NOWAIT, &sc->rbd_map);
! 368: if (error != 0) {
! 369: printf("%s: could not create rx ring DMA map\n",
! 370: sc->sc_dev.dv_xname);
! 371: goto fail;
! 372: }
! 373:
! 374: error = bus_dmamem_alloc(sc->sc_dmat, IPW_RBD_SZ, PAGE_SIZE, 0,
! 375: &sc->rbd_seg, 1, &nsegs, BUS_DMA_NOWAIT);
! 376: if (error != 0) {
! 377: printf("%s: could not allocate rx ring DMA memory\n",
! 378: sc->sc_dev.dv_xname);
! 379: goto fail;
! 380: }
! 381:
! 382: error = bus_dmamem_map(sc->sc_dmat, &sc->rbd_seg, nsegs, IPW_RBD_SZ,
! 383: (caddr_t *)&sc->rbd_list, BUS_DMA_NOWAIT);
! 384: if (error != 0) {
! 385: printf("%s: could not map rx ring DMA memory\n",
! 386: sc->sc_dev.dv_xname);
! 387: goto fail;
! 388: }
! 389:
! 390: error = bus_dmamap_load(sc->sc_dmat, sc->rbd_map, sc->rbd_list,
! 391: IPW_RBD_SZ, NULL, BUS_DMA_NOWAIT);
! 392: if (error != 0) {
! 393: printf("%s: could not load tx ring DMA map\n",
! 394: sc->sc_dev.dv_xname);
! 395: goto fail;
! 396: }
! 397:
! 398: /*
! 399: * Allocate and map status ring.
! 400: */
! 401: error = bus_dmamap_create(sc->sc_dmat, IPW_STATUS_SZ, 1, IPW_STATUS_SZ,
! 402: 0, BUS_DMA_NOWAIT, &sc->status_map);
! 403: if (error != 0) {
! 404: printf("%s: could not create status ring DMA map\n",
! 405: sc->sc_dev.dv_xname);
! 406: goto fail;
! 407: }
! 408:
! 409: error = bus_dmamem_alloc(sc->sc_dmat, IPW_STATUS_SZ, PAGE_SIZE, 0,
! 410: &sc->status_seg, 1, &nsegs, BUS_DMA_NOWAIT);
! 411: if (error != 0) {
! 412: printf("%s: could not allocate status ring DMA memory\n",
! 413: sc->sc_dev.dv_xname);
! 414: goto fail;
! 415: }
! 416:
! 417: error = bus_dmamem_map(sc->sc_dmat, &sc->status_seg, nsegs,
! 418: IPW_STATUS_SZ, (caddr_t *)&sc->status_list, BUS_DMA_NOWAIT);
! 419: if (error != 0) {
! 420: printf("%s: could not map status ring DMA memory\n",
! 421: sc->sc_dev.dv_xname);
! 422: goto fail;
! 423: }
! 424:
! 425: error = bus_dmamap_load(sc->sc_dmat, sc->status_map, sc->status_list,
! 426: IPW_STATUS_SZ, NULL, BUS_DMA_NOWAIT);
! 427: if (error != 0) {
! 428: printf("%s: could not load status ring DMA map\n",
! 429: sc->sc_dev.dv_xname);
! 430: goto fail;
! 431: }
! 432:
! 433: /*
! 434: * Allocate command DMA map.
! 435: */
! 436: error = bus_dmamap_create(sc->sc_dmat, sizeof (struct ipw_cmd), 1,
! 437: sizeof (struct ipw_cmd), 0, BUS_DMA_NOWAIT, &sc->cmd_map);
! 438: if (error != 0) {
! 439: printf("%s: could not create command DMA map\n",
! 440: sc->sc_dev.dv_xname);
! 441: goto fail;
! 442: }
! 443:
! 444: /*
! 445: * Allocate headers DMA maps.
! 446: */
! 447: SLIST_INIT(&sc->free_shdr);
! 448: for (i = 0; i < IPW_NDATA; i++) {
! 449: shdr = &sc->shdr_list[i];
! 450: error = bus_dmamap_create(sc->sc_dmat, sizeof (struct ipw_hdr),
! 451: 1, sizeof (struct ipw_hdr), 0, BUS_DMA_NOWAIT, &shdr->map);
! 452: if (error != 0) {
! 453: printf("%s: could not create header DMA map\n",
! 454: sc->sc_dev.dv_xname);
! 455: goto fail;
! 456: }
! 457: SLIST_INSERT_HEAD(&sc->free_shdr, shdr, next);
! 458: }
! 459:
! 460: /*
! 461: * Allocate tx buffers DMA maps.
! 462: */
! 463: SLIST_INIT(&sc->free_sbuf);
! 464: for (i = 0; i < IPW_NDATA; i++) {
! 465: sbuf = &sc->tx_sbuf_list[i];
! 466: error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, IPW_MAX_NSEG,
! 467: MCLBYTES, 0, BUS_DMA_NOWAIT, &sbuf->map);
! 468: if (error != 0) {
! 469: printf("%s: could not create tx DMA map\n",
! 470: sc->sc_dev.dv_xname);
! 471: goto fail;
! 472: }
! 473: SLIST_INSERT_HEAD(&sc->free_sbuf, sbuf, next);
! 474: }
! 475:
! 476: /*
! 477: * Initialize tx ring.
! 478: */
! 479: for (i = 0; i < IPW_NTBD; i++) {
! 480: sbd = &sc->stbd_list[i];
! 481: sbd->bd = &sc->tbd_list[i];
! 482: sbd->type = IPW_SBD_TYPE_NOASSOC;
! 483: }
! 484:
! 485: /*
! 486: * Pre-allocate rx buffers and DMA maps.
! 487: */
! 488: for (i = 0; i < IPW_NRBD; i++) {
! 489: sbd = &sc->srbd_list[i];
! 490: sbuf = &sc->rx_sbuf_list[i];
! 491: sbd->bd = &sc->rbd_list[i];
! 492:
! 493: MGETHDR(sbuf->m, M_DONTWAIT, MT_DATA);
! 494: if (sbuf->m == NULL) {
! 495: printf("%s: could not allocate rx mbuf\n",
! 496: sc->sc_dev.dv_xname);
! 497: error = ENOMEM;
! 498: goto fail;
! 499: }
! 500:
! 501: MCLGET(sbuf->m, M_DONTWAIT);
! 502: if (!(sbuf->m->m_flags & M_EXT)) {
! 503: m_freem(sbuf->m);
! 504: printf("%s: could not allocate rx mbuf cluster\n",
! 505: sc->sc_dev.dv_xname);
! 506: error = ENOMEM;
! 507: goto fail;
! 508: }
! 509:
! 510: error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, MCLBYTES,
! 511: 0, BUS_DMA_NOWAIT, &sbuf->map);
! 512: if (error != 0) {
! 513: printf("%s: could not create rx DMA map\n",
! 514: sc->sc_dev.dv_xname);
! 515: goto fail;
! 516: }
! 517:
! 518: error = bus_dmamap_load(sc->sc_dmat, sbuf->map,
! 519: mtod(sbuf->m, void *), MCLBYTES, NULL, BUS_DMA_NOWAIT);
! 520: if (error != 0) {
! 521: printf("%s: could not map rx DMA memory\n",
! 522: sc->sc_dev.dv_xname);
! 523: goto fail;
! 524: }
! 525:
! 526: sbd->type = IPW_SBD_TYPE_DATA;
! 527: sbd->priv = sbuf;
! 528: sbd->bd->physaddr = htole32(sbuf->map->dm_segs[0].ds_addr);
! 529: sbd->bd->len = htole32(MCLBYTES);
! 530: }
! 531:
! 532: bus_dmamap_sync(sc->sc_dmat, sc->rbd_map, 0, IPW_RBD_SZ,
! 533: BUS_DMASYNC_PREWRITE);
! 534:
! 535: return 0;
! 536:
! 537: fail: ipw_release(sc);
! 538: return error;
! 539: }
! 540:
! 541: void
! 542: ipw_release(struct ipw_softc *sc)
! 543: {
! 544: struct ipw_soft_buf *sbuf;
! 545: int i;
! 546:
! 547: if (sc->tbd_map != NULL) {
! 548: if (sc->tbd_list != NULL) {
! 549: bus_dmamap_unload(sc->sc_dmat, sc->tbd_map);
! 550: bus_dmamem_unmap(sc->sc_dmat, (caddr_t)sc->tbd_list,
! 551: IPW_TBD_SZ);
! 552: bus_dmamem_free(sc->sc_dmat, &sc->tbd_seg, 1);
! 553: }
! 554: bus_dmamap_destroy(sc->sc_dmat, sc->tbd_map);
! 555: }
! 556:
! 557: if (sc->rbd_map != NULL) {
! 558: if (sc->rbd_list != NULL) {
! 559: bus_dmamap_unload(sc->sc_dmat, sc->rbd_map);
! 560: bus_dmamem_unmap(sc->sc_dmat, (caddr_t)sc->rbd_list,
! 561: IPW_RBD_SZ);
! 562: bus_dmamem_free(sc->sc_dmat, &sc->rbd_seg, 1);
! 563: }
! 564: bus_dmamap_destroy(sc->sc_dmat, sc->rbd_map);
! 565: }
! 566:
! 567: if (sc->status_map != NULL) {
! 568: if (sc->status_list != NULL) {
! 569: bus_dmamap_unload(sc->sc_dmat, sc->status_map);
! 570: bus_dmamem_unmap(sc->sc_dmat, (caddr_t)sc->status_list,
! 571: IPW_RBD_SZ);
! 572: bus_dmamem_free(sc->sc_dmat, &sc->status_seg, 1);
! 573: }
! 574: bus_dmamap_destroy(sc->sc_dmat, sc->status_map);
! 575: }
! 576:
! 577: if (sc->cmd_map != NULL)
! 578: bus_dmamap_destroy(sc->sc_dmat, sc->cmd_map);
! 579:
! 580: for (i = 0; i < IPW_NDATA; i++)
! 581: bus_dmamap_destroy(sc->sc_dmat, sc->shdr_list[i].map);
! 582:
! 583: for (i = 0; i < IPW_NDATA; i++)
! 584: bus_dmamap_destroy(sc->sc_dmat, sc->tx_sbuf_list[i].map);
! 585:
! 586: for (i = 0; i < IPW_NRBD; i++) {
! 587: sbuf = &sc->rx_sbuf_list[i];
! 588: if (sbuf->map != NULL) {
! 589: if (sbuf->m != NULL) {
! 590: bus_dmamap_unload(sc->sc_dmat, sbuf->map);
! 591: m_freem(sbuf->m);
! 592: }
! 593: bus_dmamap_destroy(sc->sc_dmat, sbuf->map);
! 594: }
! 595: }
! 596: }
! 597:
! 598: int
! 599: ipw_media_change(struct ifnet *ifp)
! 600: {
! 601: int error;
! 602:
! 603: error = ieee80211_media_change(ifp);
! 604: if (error != ENETRESET)
! 605: return error;
! 606:
! 607: if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == (IFF_UP | IFF_RUNNING))
! 608: ipw_init(ifp);
! 609:
! 610: return 0;
! 611: }
! 612:
! 613: void
! 614: ipw_media_status(struct ifnet *ifp, struct ifmediareq *imr)
! 615: {
! 616: #define N(a) (sizeof (a) / sizeof (a[0]))
! 617: struct ipw_softc *sc = ifp->if_softc;
! 618: struct ieee80211com *ic = &sc->sc_ic;
! 619: static const struct {
! 620: uint32_t val;
! 621: int rate;
! 622: } rates[] = {
! 623: { IPW_RATE_DS1, 2 },
! 624: { IPW_RATE_DS2, 4 },
! 625: { IPW_RATE_DS5, 11 },
! 626: { IPW_RATE_DS11, 22 },
! 627: };
! 628: uint32_t val;
! 629: int rate, i;
! 630:
! 631: imr->ifm_status = IFM_AVALID;
! 632: imr->ifm_active = IFM_IEEE80211;
! 633: if (ic->ic_state == IEEE80211_S_RUN)
! 634: imr->ifm_status |= IFM_ACTIVE;
! 635:
! 636: /* read current transmission rate from adapter */
! 637: val = ipw_read_table1(sc, IPW_INFO_CURRENT_TX_RATE);
! 638: val &= 0xf;
! 639:
! 640: /* convert rate to 802.11 rate */
! 641: for (i = 0; i < N(rates) && rates[i].val != val; i++);
! 642: rate = (i < N(rates)) ? rates[i].rate : 0;
! 643:
! 644: imr->ifm_active |= IFM_IEEE80211_11B;
! 645: imr->ifm_active |= ieee80211_rate2media(ic, rate, IEEE80211_MODE_11B);
! 646: switch (ic->ic_opmode) {
! 647: case IEEE80211_M_STA:
! 648: break;
! 649:
! 650: case IEEE80211_M_IBSS:
! 651: imr->ifm_active |= IFM_IEEE80211_IBSS;
! 652: break;
! 653:
! 654: case IEEE80211_M_MONITOR:
! 655: imr->ifm_active |= IFM_IEEE80211_MONITOR;
! 656: break;
! 657:
! 658: case IEEE80211_M_AHDEMO:
! 659: case IEEE80211_M_HOSTAP:
! 660: /* should not get there */
! 661: break;
! 662: }
! 663: #undef N
! 664: }
! 665:
! 666: int
! 667: ipw_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
! 668: {
! 669: struct ipw_softc *sc = ic->ic_softc;
! 670: struct ieee80211_node *ni;
! 671: uint8_t macaddr[IEEE80211_ADDR_LEN];
! 672: uint32_t len;
! 673:
! 674: switch (nstate) {
! 675: case IEEE80211_S_RUN:
! 676: DELAY(100); /* firmware needs a short delay here */
! 677:
! 678: len = IEEE80211_ADDR_LEN;
! 679: ipw_read_table2(sc, IPW_INFO_CURRENT_BSSID, macaddr, &len);
! 680:
! 681: ni = ieee80211_find_node(ic, macaddr);
! 682: if (ni == NULL)
! 683: break;
! 684:
! 685: (*ic->ic_node_copy)(ic, ic->ic_bss, ni);
! 686: ieee80211_node_newstate(ni, IEEE80211_STA_BSS);
! 687: break;
! 688:
! 689: case IEEE80211_S_INIT:
! 690: case IEEE80211_S_SCAN:
! 691: case IEEE80211_S_AUTH:
! 692: case IEEE80211_S_ASSOC:
! 693: break;
! 694: }
! 695:
! 696: ic->ic_state = nstate;
! 697: return 0;
! 698: }
! 699:
! 700: /*
! 701: * Read 16 bits at address 'addr' from the Microwire EEPROM.
! 702: * DON'T PLAY WITH THIS CODE UNLESS YOU KNOW *EXACTLY* WHAT YOU'RE DOING!
! 703: */
! 704: uint16_t
! 705: ipw_read_prom_word(struct ipw_softc *sc, uint8_t addr)
! 706: {
! 707: uint32_t tmp;
! 708: uint16_t val;
! 709: int n;
! 710:
! 711: /* clock C once before the first command */
! 712: IPW_EEPROM_CTL(sc, 0);
! 713: IPW_EEPROM_CTL(sc, IPW_EEPROM_S);
! 714: IPW_EEPROM_CTL(sc, IPW_EEPROM_S | IPW_EEPROM_C);
! 715: IPW_EEPROM_CTL(sc, IPW_EEPROM_S);
! 716:
! 717: /* write start bit (1) */
! 718: IPW_EEPROM_CTL(sc, IPW_EEPROM_S | IPW_EEPROM_D);
! 719: IPW_EEPROM_CTL(sc, IPW_EEPROM_S | IPW_EEPROM_D | IPW_EEPROM_C);
! 720:
! 721: /* write READ opcode (10) */
! 722: IPW_EEPROM_CTL(sc, IPW_EEPROM_S | IPW_EEPROM_D);
! 723: IPW_EEPROM_CTL(sc, IPW_EEPROM_S | IPW_EEPROM_D | IPW_EEPROM_C);
! 724: IPW_EEPROM_CTL(sc, IPW_EEPROM_S);
! 725: IPW_EEPROM_CTL(sc, IPW_EEPROM_S | IPW_EEPROM_C);
! 726:
! 727: /* write address A7-A0 */
! 728: for (n = 7; n >= 0; n--) {
! 729: IPW_EEPROM_CTL(sc, IPW_EEPROM_S |
! 730: (((addr >> n) & 1) << IPW_EEPROM_SHIFT_D));
! 731: IPW_EEPROM_CTL(sc, IPW_EEPROM_S |
! 732: (((addr >> n) & 1) << IPW_EEPROM_SHIFT_D) | IPW_EEPROM_C);
! 733: }
! 734:
! 735: IPW_EEPROM_CTL(sc, IPW_EEPROM_S);
! 736:
! 737: /* read data Q15-Q0 */
! 738: val = 0;
! 739: for (n = 15; n >= 0; n--) {
! 740: IPW_EEPROM_CTL(sc, IPW_EEPROM_S | IPW_EEPROM_C);
! 741: IPW_EEPROM_CTL(sc, IPW_EEPROM_S);
! 742: tmp = MEM_READ_4(sc, IPW_MEM_EEPROM_CTL);
! 743: val |= ((tmp & IPW_EEPROM_Q) >> IPW_EEPROM_SHIFT_Q) << n;
! 744: }
! 745:
! 746: IPW_EEPROM_CTL(sc, 0);
! 747:
! 748: /* clear Chip Select and clock C */
! 749: IPW_EEPROM_CTL(sc, IPW_EEPROM_S);
! 750: IPW_EEPROM_CTL(sc, 0);
! 751: IPW_EEPROM_CTL(sc, IPW_EEPROM_C);
! 752:
! 753: return val;
! 754: }
! 755:
! 756: void
! 757: ipw_command_intr(struct ipw_softc *sc, struct ipw_soft_buf *sbuf)
! 758: {
! 759: struct ipw_cmd *cmd;
! 760:
! 761: bus_dmamap_sync(sc->sc_dmat, sbuf->map, 0, sizeof (struct ipw_cmd),
! 762: BUS_DMASYNC_POSTREAD);
! 763:
! 764: cmd = mtod(sbuf->m, struct ipw_cmd *);
! 765:
! 766: DPRINTFN(2, ("RX!CMD!%u!%u!%u!%u!%u\n",
! 767: letoh32(cmd->type), letoh32(cmd->subtype), letoh32(cmd->seq),
! 768: letoh32(cmd->len), letoh32(cmd->status)));
! 769:
! 770: wakeup(sc);
! 771: }
! 772:
! 773: void
! 774: ipw_newstate_intr(struct ipw_softc *sc, struct ipw_soft_buf *sbuf)
! 775: {
! 776: struct ieee80211com *ic = &sc->sc_ic;
! 777: struct ifnet *ifp = &ic->ic_if;
! 778: uint32_t state;
! 779:
! 780: bus_dmamap_sync(sc->sc_dmat, sbuf->map, 0, sizeof state,
! 781: BUS_DMASYNC_POSTREAD);
! 782:
! 783: state = letoh32(*mtod(sbuf->m, uint32_t *));
! 784:
! 785: DPRINTFN(2, ("RX!NEWSTATE!%u\n", state));
! 786:
! 787: switch (state) {
! 788: case IPW_STATE_ASSOCIATED:
! 789: ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
! 790: break;
! 791:
! 792: case IPW_STATE_SCANNING:
! 793: /* don't leave run state on background scan */
! 794: if (ic->ic_state != IEEE80211_S_RUN)
! 795: ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
! 796:
! 797: ic->ic_flags |= IEEE80211_F_ASCAN;
! 798: break;
! 799:
! 800: case IPW_STATE_SCAN_COMPLETE:
! 801: ic->ic_flags &= ~IEEE80211_F_ASCAN;
! 802: break;
! 803:
! 804: case IPW_STATE_ASSOCIATION_LOST:
! 805: ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
! 806: break;
! 807:
! 808: case IPW_STATE_RADIO_DISABLED:
! 809: ifp->if_flags &= ~IFF_UP;
! 810: ipw_stop(&ic->ic_if, 1);
! 811: break;
! 812: }
! 813: }
! 814:
! 815: void
! 816: ipw_data_intr(struct ipw_softc *sc, struct ipw_status *status,
! 817: struct ipw_soft_bd *sbd, struct ipw_soft_buf *sbuf)
! 818: {
! 819: struct ieee80211com *ic = &sc->sc_ic;
! 820: struct ifnet *ifp = &ic->ic_if;
! 821: struct mbuf *mnew, *m;
! 822: struct ieee80211_frame *wh;
! 823: struct ieee80211_node *ni;
! 824: int error;
! 825:
! 826: DPRINTFN(5, ("RX!DATA!%u!%u\n", letoh32(status->len), status->rssi));
! 827:
! 828: /*
! 829: * Try to allocate a new mbuf for this ring element and load it before
! 830: * processing the current mbuf. If the ring element cannot be loaded,
! 831: * drop the received packet and reuse the old mbuf. In the unlikely
! 832: * case that the old mbuf can't be reloaded either, explicitly panic.
! 833: */
! 834: MGETHDR(mnew, M_DONTWAIT, MT_DATA);
! 835: if (mnew == NULL) {
! 836: ifp->if_ierrors++;
! 837: return;
! 838: }
! 839:
! 840: MCLGET(mnew, M_DONTWAIT);
! 841: if (!(mnew->m_flags & M_EXT)) {
! 842: m_freem(mnew);
! 843: ifp->if_ierrors++;
! 844: return;
! 845: }
! 846:
! 847: bus_dmamap_sync(sc->sc_dmat, sbuf->map, 0, letoh32(status->len),
! 848: BUS_DMASYNC_POSTREAD);
! 849: bus_dmamap_unload(sc->sc_dmat, sbuf->map);
! 850:
! 851: error = bus_dmamap_load(sc->sc_dmat, sbuf->map, mtod(mnew, void *),
! 852: MCLBYTES, NULL, BUS_DMA_NOWAIT);
! 853: if (error != 0) {
! 854: m_freem(mnew);
! 855:
! 856: /* try to reload the old mbuf */
! 857: error = bus_dmamap_load(sc->sc_dmat, sbuf->map,
! 858: mtod(sbuf->m, void *), MCLBYTES, NULL, BUS_DMA_NOWAIT);
! 859: if (error != 0) {
! 860: /* very unlikely that it will fail... */
! 861: panic("%s: could not load old rx mbuf",
! 862: sc->sc_dev.dv_xname);
! 863: }
! 864: ifp->if_ierrors++;
! 865: return;
! 866: }
! 867:
! 868: m = sbuf->m;
! 869: sbuf->m = mnew;
! 870: sbd->bd->physaddr = htole32(sbuf->map->dm_segs[0].ds_addr);
! 871:
! 872: /* finalize mbuf */
! 873: m->m_pkthdr.rcvif = ifp;
! 874: m->m_pkthdr.len = m->m_len = letoh32(status->len);
! 875:
! 876: #if NBPFILTER > 0
! 877: if (sc->sc_drvbpf != NULL) {
! 878: struct mbuf mb;
! 879: struct ipw_rx_radiotap_header *tap = &sc->sc_rxtap;
! 880:
! 881: tap->wr_flags = 0;
! 882: tap->wr_antsignal = status->rssi;
! 883: tap->wr_chan_freq = htole16(ic->ic_ibss_chan->ic_freq);
! 884: tap->wr_chan_flags = htole16(ic->ic_ibss_chan->ic_flags);
! 885:
! 886: mb.m_data = (caddr_t)tap;
! 887: mb.m_len = sc->sc_rxtap_len;
! 888: mb.m_next = m;
! 889: mb.m_nextpkt = NULL;
! 890: mb.m_type = 0;
! 891: mb.m_flags = 0;
! 892: bpf_mtap(sc->sc_drvbpf, &mb, BPF_DIRECTION_IN);
! 893: }
! 894: #endif
! 895:
! 896: wh = mtod(m, struct ieee80211_frame *);
! 897:
! 898: ni = ieee80211_find_rxnode(ic, wh);
! 899:
! 900: /* send the frame to the upper layer */
! 901: ieee80211_input(ifp, m, ni, status->rssi, 0);
! 902:
! 903: ieee80211_release_node(ic, ni);
! 904: }
! 905:
! 906: void
! 907: ipw_notification_intr(struct ipw_softc *sc, struct ipw_soft_buf *sbuf)
! 908: {
! 909: DPRINTFN(2, ("RX!NOTIFICATION\n"));
! 910: }
! 911:
! 912: void
! 913: ipw_rx_intr(struct ipw_softc *sc)
! 914: {
! 915: struct ipw_status *status;
! 916: struct ipw_soft_bd *sbd;
! 917: struct ipw_soft_buf *sbuf;
! 918: uint32_t r, i;
! 919:
! 920: r = CSR_READ_4(sc, IPW_CSR_RX_READ_INDEX);
! 921:
! 922: for (i = (sc->rxcur + 1) % IPW_NRBD; i != r; i = (i + 1) % IPW_NRBD) {
! 923:
! 924: bus_dmamap_sync(sc->sc_dmat, sc->rbd_map,
! 925: i * sizeof (struct ipw_bd), sizeof (struct ipw_bd),
! 926: BUS_DMASYNC_POSTREAD);
! 927:
! 928: bus_dmamap_sync(sc->sc_dmat, sc->status_map,
! 929: i * sizeof (struct ipw_status), sizeof (struct ipw_status),
! 930: BUS_DMASYNC_POSTREAD);
! 931:
! 932: status = &sc->status_list[i];
! 933: sbd = &sc->srbd_list[i];
! 934: sbuf = sbd->priv;
! 935:
! 936: switch (letoh16(status->code) & 0xf) {
! 937: case IPW_STATUS_CODE_COMMAND:
! 938: ipw_command_intr(sc, sbuf);
! 939: break;
! 940:
! 941: case IPW_STATUS_CODE_NEWSTATE:
! 942: ipw_newstate_intr(sc, sbuf);
! 943: break;
! 944:
! 945: case IPW_STATUS_CODE_DATA_802_3:
! 946: case IPW_STATUS_CODE_DATA_802_11:
! 947: ipw_data_intr(sc, status, sbd, sbuf);
! 948: break;
! 949:
! 950: case IPW_STATUS_CODE_NOTIFICATION:
! 951: ipw_notification_intr(sc, sbuf);
! 952: break;
! 953:
! 954: default:
! 955: printf("%s: unknown status code %u\n",
! 956: sc->sc_dev.dv_xname, letoh16(status->code));
! 957: }
! 958: sbd->bd->flags = 0;
! 959:
! 960: bus_dmamap_sync(sc->sc_dmat, sc->rbd_map,
! 961: i * sizeof (struct ipw_bd), sizeof (struct ipw_bd),
! 962: BUS_DMASYNC_PREWRITE);
! 963: }
! 964:
! 965: /* tell the firmware what we have processed */
! 966: sc->rxcur = (r == 0) ? IPW_NRBD - 1 : r - 1;
! 967: CSR_WRITE_4(sc, IPW_CSR_RX_WRITE_INDEX, sc->rxcur);
! 968: }
! 969:
! 970: void
! 971: ipw_release_sbd(struct ipw_softc *sc, struct ipw_soft_bd *sbd)
! 972: {
! 973: struct ieee80211com *ic = &sc->sc_ic;
! 974: struct ipw_soft_hdr *shdr;
! 975: struct ipw_soft_buf *sbuf;
! 976:
! 977: switch (sbd->type) {
! 978: case IPW_SBD_TYPE_COMMAND:
! 979: bus_dmamap_unload(sc->sc_dmat, sc->cmd_map);
! 980: break;
! 981:
! 982: case IPW_SBD_TYPE_HEADER:
! 983: shdr = sbd->priv;
! 984: bus_dmamap_unload(sc->sc_dmat, shdr->map);
! 985: SLIST_INSERT_HEAD(&sc->free_shdr, shdr, next);
! 986: break;
! 987:
! 988: case IPW_SBD_TYPE_DATA:
! 989: sbuf = sbd->priv;
! 990: bus_dmamap_unload(sc->sc_dmat, sbuf->map);
! 991: SLIST_INSERT_HEAD(&sc->free_sbuf, sbuf, next);
! 992:
! 993: m_freem(sbuf->m);
! 994:
! 995: if (sbuf->ni != NULL)
! 996: ieee80211_release_node(ic, sbuf->ni);
! 997:
! 998: /* kill watchdog timer */
! 999: sc->sc_tx_timer = 0;
! 1000: break;
! 1001: }
! 1002: sbd->type = IPW_SBD_TYPE_NOASSOC;
! 1003: }
! 1004:
! 1005: void
! 1006: ipw_tx_intr(struct ipw_softc *sc)
! 1007: {
! 1008: struct ifnet *ifp = &sc->sc_ic.ic_if;
! 1009: struct ipw_soft_bd *sbd;
! 1010: uint32_t r, i;
! 1011:
! 1012: r = CSR_READ_4(sc, IPW_CSR_TX_READ_INDEX);
! 1013:
! 1014: for (i = (sc->txold + 1) % IPW_NTBD; i != r; i = (i + 1) % IPW_NTBD) {
! 1015: sbd = &sc->stbd_list[i];
! 1016:
! 1017: if (sbd->type == IPW_SBD_TYPE_DATA)
! 1018: ifp->if_opackets++;
! 1019:
! 1020: ipw_release_sbd(sc, sbd);
! 1021: sc->txfree++;
! 1022: }
! 1023:
! 1024: /* remember what the firmware has processed */
! 1025: sc->txold = (r == 0) ? IPW_NTBD - 1 : r - 1;
! 1026:
! 1027: /* call start() since some buffer descriptors have been released */
! 1028: ifp->if_flags &= ~IFF_OACTIVE;
! 1029: (*ifp->if_start)(ifp);
! 1030: }
! 1031:
! 1032: int
! 1033: ipw_intr(void *arg)
! 1034: {
! 1035: struct ipw_softc *sc = arg;
! 1036: struct ifnet *ifp = &sc->sc_ic.ic_if;
! 1037: uint32_t r;
! 1038:
! 1039: if ((r = CSR_READ_4(sc, IPW_CSR_INTR)) == 0 || r == 0xffffffff)
! 1040: return 0;
! 1041:
! 1042: /* disable interrupts */
! 1043: CSR_WRITE_4(sc, IPW_CSR_INTR_MASK, 0);
! 1044:
! 1045: DPRINTFN(8, ("INTR!0x%08x\n", r));
! 1046:
! 1047: if (r & (IPW_INTR_FATAL_ERROR | IPW_INTR_PARITY_ERROR)) {
! 1048: printf("%s: fatal firmware error\n", sc->sc_dev.dv_xname);
! 1049: ifp->if_flags &= ~IFF_UP;
! 1050: ipw_stop(ifp, 1);
! 1051: return 1;
! 1052: }
! 1053:
! 1054: if (r & IPW_INTR_FW_INIT_DONE)
! 1055: wakeup(sc);
! 1056:
! 1057: if (r & IPW_INTR_RX_TRANSFER)
! 1058: ipw_rx_intr(sc);
! 1059:
! 1060: if (r & IPW_INTR_TX_TRANSFER)
! 1061: ipw_tx_intr(sc);
! 1062:
! 1063: /* acknowledge interrupts */
! 1064: CSR_WRITE_4(sc, IPW_CSR_INTR, r);
! 1065:
! 1066: /* re-enable interrupts */
! 1067: CSR_WRITE_4(sc, IPW_CSR_INTR_MASK, IPW_INTR_MASK);
! 1068:
! 1069: return 1;
! 1070: }
! 1071:
! 1072: int
! 1073: ipw_cmd(struct ipw_softc *sc, uint32_t type, void *data, uint32_t len)
! 1074: {
! 1075: struct ipw_soft_bd *sbd;
! 1076: int error;
! 1077:
! 1078: sbd = &sc->stbd_list[sc->txcur];
! 1079:
! 1080: error = bus_dmamap_load(sc->sc_dmat, sc->cmd_map, &sc->cmd,
! 1081: sizeof (struct ipw_cmd), NULL, BUS_DMA_NOWAIT);
! 1082: if (error != 0) {
! 1083: printf("%s: could not map command DMA memory\n",
! 1084: sc->sc_dev.dv_xname);
! 1085: return error;
! 1086: }
! 1087:
! 1088: sc->cmd.type = htole32(type);
! 1089: sc->cmd.subtype = htole32(0);
! 1090: sc->cmd.len = htole32(len);
! 1091: sc->cmd.seq = htole32(0);
! 1092: if (data != NULL)
! 1093: bcopy(data, sc->cmd.data, len);
! 1094:
! 1095: sbd->type = IPW_SBD_TYPE_COMMAND;
! 1096: sbd->bd->physaddr = htole32(sc->cmd_map->dm_segs[0].ds_addr);
! 1097: sbd->bd->len = htole32(sizeof (struct ipw_cmd));
! 1098: sbd->bd->nfrag = 1;
! 1099: sbd->bd->flags = IPW_BD_FLAG_TX_FRAME_COMMAND |
! 1100: IPW_BD_FLAG_TX_LAST_FRAGMENT;
! 1101:
! 1102: bus_dmamap_sync(sc->sc_dmat, sc->cmd_map, 0, sizeof (struct ipw_cmd),
! 1103: BUS_DMASYNC_PREWRITE);
! 1104:
! 1105: bus_dmamap_sync(sc->sc_dmat, sc->tbd_map,
! 1106: sc->txcur * sizeof (struct ipw_bd), sizeof (struct ipw_bd),
! 1107: BUS_DMASYNC_PREWRITE);
! 1108:
! 1109: sc->txcur = (sc->txcur + 1) % IPW_NTBD;
! 1110: sc->txfree--;
! 1111: CSR_WRITE_4(sc, IPW_CSR_TX_WRITE_INDEX, sc->txcur);
! 1112:
! 1113: DPRINTFN(2, ("TX!CMD!%u!%u!%u!%u\n", type, 0, 0, len));
! 1114:
! 1115: /* wait at most one second for command to complete */
! 1116: return tsleep(sc, 0, "ipwcmd", hz);
! 1117: }
! 1118:
! 1119: int
! 1120: ipw_tx_start(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni)
! 1121: {
! 1122: struct ipw_softc *sc = ifp->if_softc;
! 1123: struct ieee80211com *ic = &sc->sc_ic;
! 1124: struct ieee80211_frame *wh;
! 1125: struct ipw_soft_bd *sbd;
! 1126: struct ipw_soft_hdr *shdr;
! 1127: struct ipw_soft_buf *sbuf;
! 1128: struct mbuf *mnew;
! 1129: int error, i;
! 1130:
! 1131: wh = mtod(m, struct ieee80211_frame *);
! 1132:
! 1133: if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
! 1134: m = ieee80211_wep_crypt(ifp, m, 1);
! 1135: if (m == NULL)
! 1136: return ENOBUFS;
! 1137:
! 1138: /* packet header may have moved, reset our local pointer */
! 1139: wh = mtod(m, struct ieee80211_frame *);
! 1140: }
! 1141:
! 1142: #if NBPFILTER > 0
! 1143: if (sc->sc_drvbpf != NULL) {
! 1144: struct mbuf mb;
! 1145: struct ipw_tx_radiotap_header *tap = &sc->sc_txtap;
! 1146:
! 1147: tap->wt_flags = 0;
! 1148: tap->wt_chan_freq = htole16(ic->ic_ibss_chan->ic_freq);
! 1149: tap->wt_chan_flags = htole16(ic->ic_ibss_chan->ic_flags);
! 1150:
! 1151: mb.m_data = (caddr_t)tap;
! 1152: mb.m_len = sc->sc_txtap_len;
! 1153: mb.m_next = m;
! 1154: mb.m_nextpkt = NULL;
! 1155: mb.m_type = 0;
! 1156: mb.m_flags = 0;
! 1157: bpf_mtap(sc->sc_drvbpf, &mb, BPF_DIRECTION_OUT);
! 1158: }
! 1159: #endif
! 1160:
! 1161: shdr = SLIST_FIRST(&sc->free_shdr);
! 1162: sbuf = SLIST_FIRST(&sc->free_sbuf);
! 1163:
! 1164: shdr->hdr.type = htole32(IPW_HDR_TYPE_SEND);
! 1165: shdr->hdr.subtype = htole32(0);
! 1166: shdr->hdr.encrypted = (wh->i_fc[1] & IEEE80211_FC1_WEP) ? 1 : 0;
! 1167: shdr->hdr.encrypt = 0;
! 1168: shdr->hdr.keyidx = 0;
! 1169: shdr->hdr.keysz = 0;
! 1170: shdr->hdr.fragmentsz = htole16(0);
! 1171: IEEE80211_ADDR_COPY(shdr->hdr.src_addr, wh->i_addr2);
! 1172: if (ic->ic_opmode == IEEE80211_M_STA)
! 1173: IEEE80211_ADDR_COPY(shdr->hdr.dst_addr, wh->i_addr3);
! 1174: else
! 1175: IEEE80211_ADDR_COPY(shdr->hdr.dst_addr, wh->i_addr1);
! 1176:
! 1177: /* trim IEEE802.11 header */
! 1178: m_adj(m, sizeof (struct ieee80211_frame));
! 1179:
! 1180: error = bus_dmamap_load_mbuf(sc->sc_dmat, sbuf->map, m, BUS_DMA_NOWAIT);
! 1181: if (error != 0 && error != EFBIG) {
! 1182: printf("%s: could not map mbuf (error %d)\n",
! 1183: sc->sc_dev.dv_xname, error);
! 1184: m_freem(m);
! 1185: return error;
! 1186: }
! 1187: if (error != 0) {
! 1188: /* too many fragments, linearize */
! 1189:
! 1190: MGETHDR(mnew, M_DONTWAIT, MT_DATA);
! 1191: if (mnew == NULL) {
! 1192: m_freem(m);
! 1193: return ENOMEM;
! 1194: }
! 1195:
! 1196: M_DUP_PKTHDR(mnew, m);
! 1197: if (m->m_pkthdr.len > MHLEN) {
! 1198: MCLGET(mnew, M_DONTWAIT);
! 1199: if (!(mnew->m_flags & M_EXT)) {
! 1200: m_freem(m);
! 1201: m_freem(mnew);
! 1202: return ENOMEM;
! 1203: }
! 1204: }
! 1205:
! 1206: m_copydata(m, 0, m->m_pkthdr.len, mtod(mnew, caddr_t));
! 1207: m_freem(m);
! 1208: mnew->m_len = mnew->m_pkthdr.len;
! 1209: m = mnew;
! 1210:
! 1211: error = bus_dmamap_load_mbuf(sc->sc_dmat, sbuf->map, m,
! 1212: BUS_DMA_NOWAIT);
! 1213: if (error != 0) {
! 1214: printf("%s: could not map mbuf (error %d)\n",
! 1215: sc->sc_dev.dv_xname, error);
! 1216: m_freem(m);
! 1217: return error;
! 1218: }
! 1219: }
! 1220:
! 1221: error = bus_dmamap_load(sc->sc_dmat, shdr->map, &shdr->hdr,
! 1222: sizeof (struct ipw_hdr), NULL, BUS_DMA_NOWAIT);
! 1223: if (error != 0) {
! 1224: printf("%s: could not map header DMA memory (error %d)\n",
! 1225: sc->sc_dev.dv_xname, error);
! 1226: bus_dmamap_unload(sc->sc_dmat, sbuf->map);
! 1227: m_freem(m);
! 1228: return error;
! 1229: }
! 1230:
! 1231: SLIST_REMOVE_HEAD(&sc->free_sbuf, next);
! 1232: SLIST_REMOVE_HEAD(&sc->free_shdr, next);
! 1233:
! 1234: sbd = &sc->stbd_list[sc->txcur];
! 1235: sbd->type = IPW_SBD_TYPE_HEADER;
! 1236: sbd->priv = shdr;
! 1237: sbd->bd->physaddr = htole32(shdr->map->dm_segs[0].ds_addr);
! 1238: sbd->bd->len = htole32(sizeof (struct ipw_hdr));
! 1239: sbd->bd->nfrag = 1 + sbuf->map->dm_nsegs;
! 1240: sbd->bd->flags = IPW_BD_FLAG_TX_FRAME_802_3 |
! 1241: IPW_BD_FLAG_TX_NOT_LAST_FRAGMENT;
! 1242:
! 1243: DPRINTFN(5, ("TX!HDR!%u!%u!%u!%u", shdr->hdr.type, shdr->hdr.subtype,
! 1244: shdr->hdr.encrypted, shdr->hdr.encrypt));
! 1245: DPRINTFN(5, ("!%s", ether_sprintf(shdr->hdr.src_addr)));
! 1246: DPRINTFN(5, ("!%s\n", ether_sprintf(shdr->hdr.dst_addr)));
! 1247:
! 1248: bus_dmamap_sync(sc->sc_dmat, sc->tbd_map,
! 1249: sc->txcur * sizeof (struct ipw_bd),
! 1250: sizeof (struct ipw_bd), BUS_DMASYNC_PREWRITE);
! 1251:
! 1252: sc->txcur = (sc->txcur + 1) % IPW_NTBD;
! 1253: sc->txfree--;
! 1254:
! 1255: sbuf->m = m;
! 1256: sbuf->ni = ni;
! 1257:
! 1258: for (i = 0; i < sbuf->map->dm_nsegs; i++) {
! 1259: sbd = &sc->stbd_list[sc->txcur];
! 1260: sbd->bd->physaddr = htole32(sbuf->map->dm_segs[i].ds_addr);
! 1261: sbd->bd->len = htole32(sbuf->map->dm_segs[i].ds_len);
! 1262: sbd->bd->nfrag = 0; /* used only in first bd */
! 1263: sbd->bd->flags = IPW_BD_FLAG_TX_FRAME_802_3;
! 1264: if (i == sbuf->map->dm_nsegs - 1) {
! 1265: sbd->type = IPW_SBD_TYPE_DATA;
! 1266: sbd->priv = sbuf;
! 1267: sbd->bd->flags |= IPW_BD_FLAG_TX_LAST_FRAGMENT;
! 1268: } else {
! 1269: sbd->type = IPW_SBD_TYPE_NOASSOC;
! 1270: sbd->bd->flags |= IPW_BD_FLAG_TX_NOT_LAST_FRAGMENT;
! 1271: }
! 1272:
! 1273: DPRINTFN(5, ("TX!FRAG!%d!%d\n", i,
! 1274: sbuf->map->dm_segs[i].ds_len));
! 1275:
! 1276: bus_dmamap_sync(sc->sc_dmat, sc->tbd_map,
! 1277: sc->txcur * sizeof (struct ipw_bd),
! 1278: sizeof (struct ipw_bd), BUS_DMASYNC_PREWRITE);
! 1279:
! 1280: sc->txcur = (sc->txcur + 1) % IPW_NTBD;
! 1281: sc->txfree--;
! 1282: }
! 1283:
! 1284: bus_dmamap_sync(sc->sc_dmat, sbuf->map, 0, sbuf->map->dm_mapsize,
! 1285: BUS_DMASYNC_PREWRITE);
! 1286: bus_dmamap_sync(sc->sc_dmat, shdr->map, 0, sizeof (struct ipw_hdr),
! 1287: BUS_DMASYNC_PREWRITE);
! 1288:
! 1289: /* inform firmware about this new packet */
! 1290: CSR_WRITE_4(sc, IPW_CSR_TX_WRITE_INDEX, sc->txcur);
! 1291:
! 1292: return 0;
! 1293: }
! 1294:
! 1295: void
! 1296: ipw_start(struct ifnet *ifp)
! 1297: {
! 1298: struct ipw_softc *sc = ifp->if_softc;
! 1299: struct ieee80211com *ic = &sc->sc_ic;
! 1300: struct mbuf *m;
! 1301: struct ieee80211_node *ni;
! 1302:
! 1303: if (ic->ic_state != IEEE80211_S_RUN)
! 1304: return;
! 1305:
! 1306: for (;;) {
! 1307: IFQ_POLL(&ifp->if_snd, m);
! 1308: if (m == NULL)
! 1309: break;
! 1310:
! 1311: if (sc->txfree < 1 + IPW_MAX_NSEG) {
! 1312: ifp->if_flags |= IFF_OACTIVE;
! 1313: break;
! 1314: }
! 1315: IFQ_DEQUEUE(&ifp->if_snd, m);
! 1316: #if NBPFILTER > 0
! 1317: if (ifp->if_bpf != NULL)
! 1318: bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
! 1319: #endif
! 1320:
! 1321: m = ieee80211_encap(ifp, m, &ni);
! 1322: if (m == NULL)
! 1323: continue;
! 1324:
! 1325: #if NBPFILTER > 0
! 1326: if (ic->ic_rawbpf != NULL)
! 1327: bpf_mtap(ic->ic_rawbpf, m, BPF_DIRECTION_OUT);
! 1328: #endif
! 1329:
! 1330: if (ipw_tx_start(ifp, m, ni) != 0) {
! 1331: if (ni != NULL)
! 1332: ieee80211_release_node(ic, ni);
! 1333: ifp->if_oerrors++;
! 1334: break;
! 1335: }
! 1336:
! 1337: /* start watchdog timer */
! 1338: sc->sc_tx_timer = 5;
! 1339: ifp->if_timer = 1;
! 1340: }
! 1341: }
! 1342:
! 1343: void
! 1344: ipw_watchdog(struct ifnet *ifp)
! 1345: {
! 1346: struct ipw_softc *sc = ifp->if_softc;
! 1347:
! 1348: ifp->if_timer = 0;
! 1349:
! 1350: if (sc->sc_tx_timer > 0) {
! 1351: if (--sc->sc_tx_timer == 0) {
! 1352: printf("%s: device timeout\n", sc->sc_dev.dv_xname);
! 1353: ifp->if_flags &= ~IFF_UP;
! 1354: ipw_stop(ifp, 1);
! 1355: ifp->if_oerrors++;
! 1356: return;
! 1357: }
! 1358: ifp->if_timer = 1;
! 1359: }
! 1360:
! 1361: ieee80211_watchdog(ifp);
! 1362: }
! 1363:
! 1364: int
! 1365: ipw_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
! 1366: {
! 1367: struct ipw_softc *sc = ifp->if_softc;
! 1368: struct ieee80211com *ic = &sc->sc_ic;
! 1369: struct ifaddr *ifa;
! 1370: struct ifreq *ifr;
! 1371: int s, error = 0;
! 1372:
! 1373: s = splnet();
! 1374:
! 1375: switch (cmd) {
! 1376: case SIOCSIFADDR:
! 1377: ifa = (struct ifaddr *)data;
! 1378: ifp->if_flags |= IFF_UP;
! 1379: #ifdef INET
! 1380: if (ifa->ifa_addr->sa_family == AF_INET)
! 1381: arp_ifinit(&ic->ic_ac, ifa);
! 1382: #endif
! 1383: /* FALLTHROUGH */
! 1384: case SIOCSIFFLAGS:
! 1385: if (ifp->if_flags & IFF_UP) {
! 1386: if (!(ifp->if_flags & IFF_RUNNING))
! 1387: ipw_init(ifp);
! 1388: } else {
! 1389: if (ifp->if_flags & IFF_RUNNING)
! 1390: ipw_stop(ifp, 1);
! 1391: }
! 1392: break;
! 1393:
! 1394: case SIOCADDMULTI:
! 1395: case SIOCDELMULTI:
! 1396: ifr = (struct ifreq *)data;
! 1397: error = (cmd == SIOCADDMULTI) ?
! 1398: ether_addmulti(ifr, &ic->ic_ac) :
! 1399: ether_delmulti(ifr, &ic->ic_ac);
! 1400:
! 1401: if (error == ENETRESET)
! 1402: error = 0;
! 1403: break;
! 1404:
! 1405: case SIOCG80211TXPOWER:
! 1406: /*
! 1407: * If the hardware radio transmitter switch is off, report a
! 1408: * tx power of IEEE80211_TXPOWER_MIN to indicate that radio
! 1409: * transmitter is killed.
! 1410: */
! 1411: ((struct ieee80211_txpower *)data)->i_val =
! 1412: (CSR_READ_4(sc, IPW_CSR_IO) & IPW_IO_RADIO_DISABLED) ?
! 1413: IEEE80211_TXPOWER_MIN : sc->sc_ic.ic_txpower;
! 1414: break;
! 1415:
! 1416: default:
! 1417: error = ieee80211_ioctl(ifp, cmd, data);
! 1418: }
! 1419:
! 1420: if (error == ENETRESET) {
! 1421: if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) ==
! 1422: (IFF_UP | IFF_RUNNING))
! 1423: ipw_init(ifp);
! 1424: error = 0;
! 1425: }
! 1426:
! 1427: splx(s);
! 1428: return error;
! 1429: }
! 1430:
! 1431: uint32_t
! 1432: ipw_read_table1(struct ipw_softc *sc, uint32_t off)
! 1433: {
! 1434: return MEM_READ_4(sc, MEM_READ_4(sc, sc->table1_base + off));
! 1435: }
! 1436:
! 1437: void
! 1438: ipw_write_table1(struct ipw_softc *sc, uint32_t off, uint32_t info)
! 1439: {
! 1440: MEM_WRITE_4(sc, MEM_READ_4(sc, sc->table1_base + off), info);
! 1441: }
! 1442:
! 1443: int
! 1444: ipw_read_table2(struct ipw_softc *sc, uint32_t off, void *buf, uint32_t *len)
! 1445: {
! 1446: uint32_t addr, info;
! 1447: uint16_t count, size;
! 1448: uint32_t total;
! 1449:
! 1450: /* addr[4] + count[2] + size[2] */
! 1451: addr = MEM_READ_4(sc, sc->table2_base + off);
! 1452: info = MEM_READ_4(sc, sc->table2_base + off + 4);
! 1453:
! 1454: count = info >> 16;
! 1455: size = info & 0xffff;
! 1456: total = count * size;
! 1457:
! 1458: if (total > *len) {
! 1459: *len = total;
! 1460: return EINVAL;
! 1461: }
! 1462:
! 1463: *len = total;
! 1464: ipw_read_mem_1(sc, addr, buf, total);
! 1465:
! 1466: return 0;
! 1467: }
! 1468:
! 1469: void
! 1470: ipw_stop_master(struct ipw_softc *sc)
! 1471: {
! 1472: int ntries;
! 1473:
! 1474: /* disable interrupts */
! 1475: CSR_WRITE_4(sc, IPW_CSR_INTR_MASK, 0);
! 1476:
! 1477: CSR_WRITE_4(sc, IPW_CSR_RST, IPW_RST_STOP_MASTER);
! 1478: for (ntries = 0; ntries < 50; ntries++) {
! 1479: if (CSR_READ_4(sc, IPW_CSR_RST) & IPW_RST_MASTER_DISABLED)
! 1480: break;
! 1481: DELAY(10);
! 1482: }
! 1483: if (ntries == 50)
! 1484: printf("%s: timeout waiting for master\n",
! 1485: sc->sc_dev.dv_xname);
! 1486:
! 1487: CSR_WRITE_4(sc, IPW_CSR_RST, CSR_READ_4(sc, IPW_CSR_RST) |
! 1488: IPW_RST_PRINCETON_RESET);
! 1489:
! 1490: sc->flags &= ~IPW_FLAG_FW_INITED;
! 1491: }
! 1492:
! 1493: int
! 1494: ipw_reset(struct ipw_softc *sc)
! 1495: {
! 1496: int ntries;
! 1497:
! 1498: ipw_stop_master(sc);
! 1499:
! 1500: /* move adapter to D0 state */
! 1501: CSR_WRITE_4(sc, IPW_CSR_CTL, CSR_READ_4(sc, IPW_CSR_CTL) |
! 1502: IPW_CTL_INIT);
! 1503:
! 1504: /* wait for clock stabilization */
! 1505: for (ntries = 0; ntries < 1000; ntries++) {
! 1506: if (CSR_READ_4(sc, IPW_CSR_CTL) & IPW_CTL_CLOCK_READY)
! 1507: break;
! 1508: DELAY(200);
! 1509: }
! 1510: if (ntries == 1000)
! 1511: return EIO;
! 1512:
! 1513: CSR_WRITE_4(sc, IPW_CSR_RST, CSR_READ_4(sc, IPW_CSR_RST) |
! 1514: IPW_RST_SW_RESET);
! 1515:
! 1516: DELAY(10);
! 1517:
! 1518: CSR_WRITE_4(sc, IPW_CSR_CTL, CSR_READ_4(sc, IPW_CSR_CTL) |
! 1519: IPW_CTL_INIT);
! 1520:
! 1521: return 0;
! 1522: }
! 1523:
! 1524: int
! 1525: ipw_load_ucode(struct ipw_softc *sc, u_char *uc, int size)
! 1526: {
! 1527: int ntries;
! 1528:
! 1529: MEM_WRITE_4(sc, 0x3000e0, 0x80000000);
! 1530: CSR_WRITE_4(sc, IPW_CSR_RST, 0);
! 1531:
! 1532: MEM_WRITE_2(sc, 0x220000, 0x0703);
! 1533: MEM_WRITE_2(sc, 0x220000, 0x0707);
! 1534:
! 1535: MEM_WRITE_1(sc, 0x210014, 0x72);
! 1536: MEM_WRITE_1(sc, 0x210014, 0x72);
! 1537:
! 1538: MEM_WRITE_1(sc, 0x210000, 0x40);
! 1539: MEM_WRITE_1(sc, 0x210000, 0x00);
! 1540: MEM_WRITE_1(sc, 0x210000, 0x40);
! 1541:
! 1542: MEM_WRITE_MULTI_1(sc, 0x210010, uc, size);
! 1543:
! 1544: MEM_WRITE_1(sc, 0x210000, 0x00);
! 1545: MEM_WRITE_1(sc, 0x210000, 0x00);
! 1546: MEM_WRITE_1(sc, 0x210000, 0x80);
! 1547:
! 1548: MEM_WRITE_2(sc, 0x220000, 0x0703);
! 1549: MEM_WRITE_2(sc, 0x220000, 0x0707);
! 1550:
! 1551: MEM_WRITE_1(sc, 0x210014, 0x72);
! 1552: MEM_WRITE_1(sc, 0x210014, 0x72);
! 1553:
! 1554: MEM_WRITE_1(sc, 0x210000, 0x00);
! 1555: MEM_WRITE_1(sc, 0x210000, 0x80);
! 1556:
! 1557: for (ntries = 0; ntries < 100; ntries++) {
! 1558: if (MEM_READ_1(sc, 0x210000) & 1)
! 1559: break;
! 1560: DELAY(1000);
! 1561: }
! 1562: if (ntries == 100) {
! 1563: printf("%s: timeout waiting for ucode to initialize\n",
! 1564: sc->sc_dev.dv_xname);
! 1565: return EIO;
! 1566: }
! 1567:
! 1568: MEM_WRITE_4(sc, 0x3000e0, 0);
! 1569:
! 1570: return 0;
! 1571: }
! 1572:
! 1573: /* set of macros to handle unaligned little endian data in firmware image */
! 1574: #define GETLE32(p) ((p)[0] | (p)[1] << 8 | (p)[2] << 16 | (p)[3] << 24)
! 1575: #define GETLE16(p) ((p)[0] | (p)[1] << 8)
! 1576: int
! 1577: ipw_load_firmware(struct ipw_softc *sc, u_char *fw, int size)
! 1578: {
! 1579: u_char *p, *end;
! 1580: uint32_t dst;
! 1581: uint16_t len;
! 1582: int error;
! 1583:
! 1584: p = fw;
! 1585: end = fw + size;
! 1586: while (p < end) {
! 1587: if (p + 6 > end)
! 1588: return EINVAL;
! 1589:
! 1590: dst = GETLE32(p); p += 4;
! 1591: len = GETLE16(p); p += 2;
! 1592:
! 1593: if (p + len > end)
! 1594: return EINVAL;
! 1595:
! 1596: ipw_write_mem_1(sc, dst, p, len);
! 1597: p += len;
! 1598: }
! 1599:
! 1600: CSR_WRITE_4(sc, IPW_CSR_IO, IPW_IO_GPIO1_ENABLE | IPW_IO_GPIO3_MASK |
! 1601: IPW_IO_LED_OFF);
! 1602:
! 1603: /* allow interrupts so we know when the firmware is inited */
! 1604: CSR_WRITE_4(sc, IPW_CSR_INTR_MASK, IPW_INTR_MASK);
! 1605:
! 1606: /* tell the adapter to initialize the firmware */
! 1607: CSR_WRITE_4(sc, IPW_CSR_RST, 0);
! 1608: CSR_WRITE_4(sc, IPW_CSR_CTL, CSR_READ_4(sc, IPW_CSR_CTL) |
! 1609: IPW_CTL_ALLOW_STANDBY);
! 1610:
! 1611: /* wait at most one second for firmware initialization to complete */
! 1612: if ((error = tsleep(sc, 0, "ipwinit", hz)) != 0) {
! 1613: printf("%s: timeout waiting for firmware initialization to "
! 1614: "complete\n", sc->sc_dev.dv_xname);
! 1615: return error;
! 1616: }
! 1617:
! 1618: CSR_WRITE_4(sc, IPW_CSR_IO, CSR_READ_4(sc, IPW_CSR_IO) |
! 1619: IPW_IO_GPIO1_MASK | IPW_IO_GPIO3_MASK);
! 1620:
! 1621: return 0;
! 1622: }
! 1623:
! 1624: int
! 1625: ipw_read_firmware(struct ipw_softc *sc, struct ipw_firmware *fw)
! 1626: {
! 1627: struct ipw_firmware_hdr *hdr;
! 1628: const char *name;
! 1629: u_char *p;
! 1630: size_t size;
! 1631: int error;
! 1632:
! 1633: switch (sc->sc_ic.ic_opmode) {
! 1634: case IEEE80211_M_STA:
! 1635: case IEEE80211_M_HOSTAP:
! 1636: name = "ipw-bss";
! 1637: break;
! 1638:
! 1639: case IEEE80211_M_IBSS:
! 1640: case IEEE80211_M_AHDEMO:
! 1641: name = "ipw-ibss";
! 1642: break;
! 1643:
! 1644: case IEEE80211_M_MONITOR:
! 1645: name = "ipw-monitor";
! 1646: break;
! 1647: }
! 1648:
! 1649: if ((error = loadfirmware(name, &fw->data, &size)) != 0)
! 1650: return error;
! 1651:
! 1652: if (size < sizeof (struct ipw_firmware_hdr)) {
! 1653: error = EINVAL;
! 1654: goto fail;
! 1655: }
! 1656:
! 1657: p = fw->data;
! 1658: hdr = (struct ipw_firmware_hdr *)p;
! 1659: fw->main_size = letoh32(hdr->main_size);
! 1660: fw->ucode_size = letoh32(hdr->ucode_size);
! 1661:
! 1662: p += sizeof (struct ipw_firmware_hdr);
! 1663: size -= sizeof (struct ipw_firmware_hdr);
! 1664:
! 1665: if (size < fw->main_size + fw->ucode_size) {
! 1666: error = EINVAL;
! 1667: goto fail;
! 1668: }
! 1669:
! 1670: fw->main = p;
! 1671: fw->ucode = p + fw->main_size;
! 1672:
! 1673: return 0;
! 1674:
! 1675: fail: free(fw->data, M_DEVBUF);
! 1676: return error;
! 1677: }
! 1678:
! 1679: int
! 1680: ipw_config(struct ipw_softc *sc)
! 1681: {
! 1682: struct ieee80211com *ic = &sc->sc_ic;
! 1683: struct ifnet *ifp = &ic->ic_if;
! 1684: struct ipw_security security;
! 1685: struct ieee80211_key *k;
! 1686: struct ipw_wep_key wepkey;
! 1687: struct ipw_scan_options options;
! 1688: struct ipw_configuration config;
! 1689: uint32_t data;
! 1690: int error, i;
! 1691:
! 1692: switch (ic->ic_opmode) {
! 1693: case IEEE80211_M_STA:
! 1694: case IEEE80211_M_HOSTAP:
! 1695: data = htole32(IPW_MODE_BSS);
! 1696: break;
! 1697:
! 1698: case IEEE80211_M_IBSS:
! 1699: case IEEE80211_M_AHDEMO:
! 1700: data = htole32(IPW_MODE_IBSS);
! 1701: break;
! 1702:
! 1703: case IEEE80211_M_MONITOR:
! 1704: data = htole32(IPW_MODE_MONITOR);
! 1705: break;
! 1706: }
! 1707: DPRINTF(("Setting mode to %u\n", letoh32(data)));
! 1708: error = ipw_cmd(sc, IPW_CMD_SET_MODE, &data, sizeof data);
! 1709: if (error != 0)
! 1710: return error;
! 1711:
! 1712: if (ic->ic_opmode == IEEE80211_M_IBSS ||
! 1713: ic->ic_opmode == IEEE80211_M_MONITOR) {
! 1714: data = htole32(ieee80211_chan2ieee(ic, ic->ic_ibss_chan));
! 1715: DPRINTF(("Setting channel to %u\n", letoh32(data)));
! 1716: error = ipw_cmd(sc, IPW_CMD_SET_CHANNEL, &data, sizeof data);
! 1717: if (error != 0)
! 1718: return error;
! 1719: }
! 1720:
! 1721: if (ic->ic_opmode == IEEE80211_M_MONITOR) {
! 1722: DPRINTF(("Enabling adapter\n"));
! 1723: return ipw_cmd(sc, IPW_CMD_ENABLE, NULL, 0);
! 1724: }
! 1725:
! 1726: IEEE80211_ADDR_COPY(ic->ic_myaddr, LLADDR(ifp->if_sadl));
! 1727: DPRINTF(("Setting MAC address to %s\n", ether_sprintf(ic->ic_myaddr)));
! 1728: error = ipw_cmd(sc, IPW_CMD_SET_MAC_ADDRESS, ic->ic_myaddr,
! 1729: IEEE80211_ADDR_LEN);
! 1730: if (error != 0)
! 1731: return error;
! 1732:
! 1733: config.flags = htole32(IPW_CFG_BSS_MASK | IPW_CFG_IBSS_MASK |
! 1734: IPW_CFG_PREAMBLE_AUTO | IPW_CFG_802_1x_ENABLE);
! 1735: if (ic->ic_opmode == IEEE80211_M_IBSS)
! 1736: config.flags |= htole32(IPW_CFG_IBSS_AUTO_START);
! 1737: if (ifp->if_flags & IFF_PROMISC)
! 1738: config.flags |= htole32(IPW_CFG_PROMISCUOUS);
! 1739: config.bss_chan = htole32(0x3fff); /* channels 1-14 */
! 1740: config.ibss_chan = htole32(0x7ff); /* channels 1-11 */
! 1741: DPRINTF(("Setting configuration 0x%x\n", config.flags));
! 1742: error = ipw_cmd(sc, IPW_CMD_SET_CONFIGURATION, &config, sizeof config);
! 1743: if (error != 0)
! 1744: return error;
! 1745:
! 1746: data = htole32(0x3); /* 1, 2 */
! 1747: DPRINTF(("Setting basic tx rates to 0x%x\n", letoh32(data)));
! 1748: error = ipw_cmd(sc, IPW_CMD_SET_BASIC_TX_RATES, &data, sizeof data);
! 1749: if (error != 0)
! 1750: return error;
! 1751:
! 1752: data = htole32(0xf); /* 1, 2, 5.5, 11 */
! 1753: DPRINTF(("Setting tx rates to 0x%x\n", letoh32(data)));
! 1754: error = ipw_cmd(sc, IPW_CMD_SET_TX_RATES, &data, sizeof data);
! 1755: if (error != 0)
! 1756: return error;
! 1757:
! 1758: data = htole32(IPW_POWER_MODE_CAM);
! 1759: DPRINTF(("Setting power mode to %u\n", letoh32(data)));
! 1760: error = ipw_cmd(sc, IPW_CMD_SET_POWER_MODE, &data, sizeof data);
! 1761: if (error != 0)
! 1762: return error;
! 1763:
! 1764: if (ic->ic_opmode == IEEE80211_M_IBSS) {
! 1765: data = htole32(32); /* default value */
! 1766: DPRINTF(("Setting tx power index to %u\n", letoh32(data)));
! 1767: error = ipw_cmd(sc, IPW_CMD_SET_TX_POWER_INDEX, &data,
! 1768: sizeof data);
! 1769: if (error != 0)
! 1770: return error;
! 1771: }
! 1772:
! 1773: data = htole32(ic->ic_rtsthreshold);
! 1774: DPRINTF(("Setting RTS threshold to %u\n", letoh32(data)));
! 1775: error = ipw_cmd(sc, IPW_CMD_SET_RTS_THRESHOLD, &data, sizeof data);
! 1776: if (error != 0)
! 1777: return error;
! 1778:
! 1779: data = htole32(ic->ic_fragthreshold);
! 1780: DPRINTF(("Setting frag threshold to %u\n", letoh32(data)));
! 1781: error = ipw_cmd(sc, IPW_CMD_SET_FRAG_THRESHOLD, &data, sizeof data);
! 1782: if (error != 0)
! 1783: return error;
! 1784:
! 1785: #ifdef IPW_DEBUG
! 1786: if (ipw_debug > 0) {
! 1787: printf("Setting ESSID to ");
! 1788: ieee80211_print_essid(ic->ic_des_essid, ic->ic_des_esslen);
! 1789: printf("\n");
! 1790: }
! 1791: #endif
! 1792: error = ipw_cmd(sc, IPW_CMD_SET_ESSID, ic->ic_des_essid,
! 1793: ic->ic_des_esslen);
! 1794: if (error != 0)
! 1795: return error;
! 1796:
! 1797: /* no mandatory BSSID */
! 1798: DPRINTF(("Setting mandatory BSSID to null\n"));
! 1799: error = ipw_cmd(sc, IPW_CMD_SET_MANDATORY_BSSID, NULL, 0);
! 1800: if (error != 0)
! 1801: return error;
! 1802:
! 1803: if (ic->ic_flags & IEEE80211_F_DESBSSID) {
! 1804: DPRINTF(("Setting adapter BSSID to %s\n",
! 1805: ether_sprintf(ic->ic_des_bssid)));
! 1806: error = ipw_cmd(sc, IPW_CMD_SET_DESIRED_BSSID,
! 1807: ic->ic_des_bssid, IEEE80211_ADDR_LEN);
! 1808: if (error != 0)
! 1809: return error;
! 1810: }
! 1811:
! 1812: bzero(&security, sizeof security);
! 1813: security.authmode = IPW_AUTH_OPEN; /* XXX shared mode */
! 1814: security.ciphers = htole32(IPW_CIPHER_NONE);
! 1815: DPRINTF(("Setting authmode to %u\n", security.authmode));
! 1816: error = ipw_cmd(sc, IPW_CMD_SET_SECURITY_INFORMATION, &security,
! 1817: sizeof security);
! 1818: if (error != 0)
! 1819: return error;
! 1820:
! 1821: if (ic->ic_flags & IEEE80211_F_WEPON) {
! 1822: k = ic->ic_nw_keys;
! 1823: for (i = 0; i < IEEE80211_WEP_NKID; i++, k++) {
! 1824: if (k->k_len == 0)
! 1825: continue;
! 1826:
! 1827: wepkey.idx = i;
! 1828: wepkey.len = k->k_len;
! 1829: bzero(wepkey.key, sizeof wepkey.key);
! 1830: bcopy(k->k_key, wepkey.key, k->k_len);
! 1831: DPRINTF(("Setting wep key index %u len %u\n",
! 1832: wepkey.idx, wepkey.len));
! 1833: error = ipw_cmd(sc, IPW_CMD_SET_WEP_KEY, &wepkey,
! 1834: sizeof wepkey);
! 1835: if (error != 0)
! 1836: return error;
! 1837: }
! 1838:
! 1839: data = htole32(ic->ic_wep_txkey);
! 1840: DPRINTF(("Setting wep tx key index to %u\n", letoh32(data)));
! 1841: error = ipw_cmd(sc, IPW_CMD_SET_WEP_KEY_INDEX, &data,
! 1842: sizeof data);
! 1843: if (error != 0)
! 1844: return error;
! 1845: }
! 1846:
! 1847: data = htole32((ic->ic_flags & IEEE80211_F_WEPON) ? IPW_WEPON : 0);
! 1848: DPRINTF(("Setting wep flags to 0x%x\n", letoh32(data)));
! 1849: error = ipw_cmd(sc, IPW_CMD_SET_WEP_FLAGS, &data, sizeof data);
! 1850: if (error != 0)
! 1851: return error;
! 1852:
! 1853: if (ic->ic_opmode == IEEE80211_M_IBSS ||
! 1854: ic->ic_opmode == IEEE80211_M_HOSTAP) {
! 1855: data = htole32(ic->ic_lintval);
! 1856: DPRINTF(("Setting beacon interval to %u\n", letoh32(data)));
! 1857: error = ipw_cmd(sc, IPW_CMD_SET_BEACON_INTERVAL, &data,
! 1858: sizeof data);
! 1859: if (error != 0)
! 1860: return error;
! 1861: }
! 1862:
! 1863: options.flags = htole32(0);
! 1864: options.channels = htole32(0x3fff); /* scan channels 1-14 */
! 1865: DPRINTF(("Setting scan options to 0x%x\n", letoh32(options.flags)));
! 1866: error = ipw_cmd(sc, IPW_CMD_SET_SCAN_OPTIONS, &options, sizeof options);
! 1867: if (error != 0)
! 1868: return error;
! 1869:
! 1870: /* finally, enable adapter (start scanning for an access point) */
! 1871: DPRINTF(("Enabling adapter\n"));
! 1872: return ipw_cmd(sc, IPW_CMD_ENABLE, NULL, 0);
! 1873: }
! 1874:
! 1875: int
! 1876: ipw_init(struct ifnet *ifp)
! 1877: {
! 1878: struct ipw_softc *sc = ifp->if_softc;
! 1879: struct ipw_firmware fw;
! 1880: int error;
! 1881:
! 1882: ipw_stop(ifp, 0);
! 1883:
! 1884: if ((error = ipw_reset(sc)) != 0) {
! 1885: printf("%s: could not reset adapter\n", sc->sc_dev.dv_xname);
! 1886: goto fail1;
! 1887: }
! 1888:
! 1889: if ((error = ipw_read_firmware(sc, &fw)) != NULL) {
! 1890: printf("%s: could not read firmware\n", sc->sc_dev.dv_xname);
! 1891: goto fail1;
! 1892: }
! 1893:
! 1894: if ((error = ipw_load_ucode(sc, fw.ucode, fw.ucode_size)) != 0) {
! 1895: printf("%s: could not load microcode\n", sc->sc_dev.dv_xname);
! 1896: goto fail2;
! 1897: }
! 1898:
! 1899: ipw_stop_master(sc);
! 1900:
! 1901: /*
! 1902: * Setup tx, rx and status rings.
! 1903: */
! 1904: CSR_WRITE_4(sc, IPW_CSR_TX_BD_BASE, sc->tbd_map->dm_segs[0].ds_addr);
! 1905: CSR_WRITE_4(sc, IPW_CSR_TX_BD_SIZE, IPW_NTBD);
! 1906: CSR_WRITE_4(sc, IPW_CSR_TX_READ_INDEX, 0);
! 1907: CSR_WRITE_4(sc, IPW_CSR_TX_WRITE_INDEX, 0);
! 1908: sc->txold = IPW_NTBD - 1; /* latest bd index ack by firmware */
! 1909: sc->txcur = 0; /* bd index to write to */
! 1910: sc->txfree = IPW_NTBD - 2;
! 1911:
! 1912: CSR_WRITE_4(sc, IPW_CSR_RX_BD_BASE, sc->rbd_map->dm_segs[0].ds_addr);
! 1913: CSR_WRITE_4(sc, IPW_CSR_RX_BD_SIZE, IPW_NRBD);
! 1914: CSR_WRITE_4(sc, IPW_CSR_RX_READ_INDEX, 0);
! 1915: CSR_WRITE_4(sc, IPW_CSR_RX_WRITE_INDEX, IPW_NRBD - 1);
! 1916: sc->rxcur = IPW_NRBD - 1; /* latest bd index I've read */
! 1917:
! 1918: CSR_WRITE_4(sc, IPW_CSR_RX_STATUS_BASE,
! 1919: sc->status_map->dm_segs[0].ds_addr);
! 1920:
! 1921: if ((error = ipw_load_firmware(sc, fw.main, fw.main_size)) != 0) {
! 1922: printf("%s: could not load firmware\n", sc->sc_dev.dv_xname);
! 1923: goto fail2;
! 1924: }
! 1925:
! 1926: sc->flags |= IPW_FLAG_FW_INITED;
! 1927:
! 1928: /* retrieve information tables base addresses */
! 1929: sc->table1_base = CSR_READ_4(sc, IPW_CSR_TABLE1_BASE);
! 1930: sc->table2_base = CSR_READ_4(sc, IPW_CSR_TABLE2_BASE);
! 1931:
! 1932: ipw_write_table1(sc, IPW_INFO_LOCK, 0);
! 1933:
! 1934: if ((error = ipw_config(sc)) != 0) {
! 1935: printf("%s: device configuration failed\n",
! 1936: sc->sc_dev.dv_xname);
! 1937: goto fail2;
! 1938: }
! 1939:
! 1940: ifp->if_flags &= ~IFF_OACTIVE;
! 1941: ifp->if_flags |= IFF_RUNNING;
! 1942:
! 1943: return 0;
! 1944:
! 1945: fail2: free(fw.data, M_DEVBUF);
! 1946: fail1: ipw_stop(ifp, 0);
! 1947:
! 1948: return error;
! 1949: }
! 1950:
! 1951: void
! 1952: ipw_stop(struct ifnet *ifp, int disable)
! 1953: {
! 1954: struct ipw_softc *sc = ifp->if_softc;
! 1955: struct ieee80211com *ic = &sc->sc_ic;
! 1956: int i;
! 1957:
! 1958: ipw_stop_master(sc);
! 1959: CSR_WRITE_4(sc, IPW_CSR_RST, IPW_RST_SW_RESET);
! 1960:
! 1961: ifp->if_timer = 0;
! 1962: ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
! 1963:
! 1964: /*
! 1965: * Release tx buffers.
! 1966: */
! 1967: for (i = 0; i < IPW_NTBD; i++)
! 1968: ipw_release_sbd(sc, &sc->stbd_list[i]);
! 1969:
! 1970: ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
! 1971: }
! 1972:
! 1973: void
! 1974: ipw_read_mem_1(struct ipw_softc *sc, bus_size_t offset, uint8_t *datap,
! 1975: bus_size_t count)
! 1976: {
! 1977: for (; count > 0; offset++, datap++, count--) {
! 1978: CSR_WRITE_4(sc, IPW_CSR_INDIRECT_ADDR, offset & ~3);
! 1979: *datap = CSR_READ_1(sc, IPW_CSR_INDIRECT_DATA + (offset & 3));
! 1980: }
! 1981: }
! 1982:
! 1983: void
! 1984: ipw_write_mem_1(struct ipw_softc *sc, bus_size_t offset, uint8_t *datap,
! 1985: bus_size_t count)
! 1986: {
! 1987: for (; count > 0; offset++, datap++, count--) {
! 1988: CSR_WRITE_4(sc, IPW_CSR_INDIRECT_ADDR, offset & ~3);
! 1989: CSR_WRITE_1(sc, IPW_CSR_INDIRECT_DATA + (offset & 3), *datap);
! 1990: }
! 1991: }
! 1992:
! 1993: struct cfdriver ipw_cd = {
! 1994: NULL, "ipw", DV_IFNET
! 1995: };
CVSweb