1 /* 2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* 7 * Copyright (c) 2004, 2005 8 * Damien Bergamini <damien.bergamini@free.fr>. All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice unmodified, this list of conditions, and the following 15 * disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #include <sys/types.h> 34 #include <sys/byteorder.h> 35 #include <sys/conf.h> 36 #include <sys/cmn_err.h> 37 #include <sys/stat.h> 38 #include <sys/ddi.h> 39 #include <sys/sunddi.h> 40 #include <sys/strsubr.h> 41 #include <sys/ethernet.h> 42 #include <inet/common.h> 43 #include <inet/nd.h> 44 #include <inet/mi.h> 45 #include <sys/note.h> 46 #include <sys/stream.h> 47 #include <sys/strsun.h> 48 #include <sys/modctl.h> 49 #include <sys/devops.h> 50 #include <sys/dlpi.h> 51 #include <sys/mac.h> 52 #include <sys/mac_wifi.h> 53 #include <sys/varargs.h> 54 #include <sys/pci.h> 55 #include <sys/policy.h> 56 #include <sys/random.h> 57 #include <sys/crypto/common.h> 58 #include <sys/crypto/api.h> 59 60 #include "ipw2200.h" 61 #include "ipw2200_impl.h" 62 #include <inet/wifi_ioctl.h> 63 64 /* 65 * for net80211 kernel usage 66 */ 67 #include <sys/net80211.h> 68 #include <sys/net80211_proto.h> 69 70 /* 71 * minimal size reserved in tx-ring 72 */ 73 #define IPW2200_TX_RING_MIN (8) 74 #define IPW2200_TXBUF_SIZE (IEEE80211_MAX_LEN) 75 #define IPW2200_RXBUF_SIZE (4096) 76 77 static void *ipw2200_ssp = NULL; 78 static char ipw2200_ident[] = IPW2200_DRV_DESC " " IPW2200_DRV_REV; 79 80 /* 81 * PIO access attributor for registers 82 */ 83 static ddi_device_acc_attr_t ipw2200_csr_accattr = { 84 DDI_DEVICE_ATTR_V0, 85 DDI_STRUCTURE_LE_ACC, 86 DDI_STRICTORDER_ACC 87 }; 88 89 /* 90 * DMA access attributor for descriptors 91 */ 92 static ddi_device_acc_attr_t ipw2200_dma_accattr = { 93 DDI_DEVICE_ATTR_V0, 94 DDI_NEVERSWAP_ACC, 95 DDI_STRICTORDER_ACC 96 }; 97 98 /* 99 * Describes the chip's DMA engine 100 */ 101 static ddi_dma_attr_t ipw2200_dma_attr = { 102 DMA_ATTR_V0, /* version */ 103 0x0000000000000000ULL, /* addr_lo */ 104 0x00000000ffffffffULL, /* addr_hi */ 105 0x00000000ffffffffULL, /* counter */ 106 0x0000000000000004ULL, /* alignment */ 107 0xfff, /* burst */ 108 1, /* min xfer */ 109 0x00000000ffffffffULL, /* max xfer */ 110 0x00000000ffffffffULL, /* seg boud */ 111 1, /* s/g list */ 112 1, /* granularity */ 113 0 /* flags */ 114 }; 115 116 static uint8_t ipw2200_broadcast_addr[] = { 117 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 118 }; 119 static const struct ieee80211_rateset ipw2200_rateset_11a = { 8, 120 {12, 18, 24, 36, 48, 72, 96, 108} 121 }; 122 static const struct ieee80211_rateset ipw2200_rateset_11b = { 4, 123 {2, 4, 11, 22} 124 }; 125 static const struct ieee80211_rateset ipw2200_rateset_11g = { 12, 126 {2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108} 127 }; 128 129 /* 130 * Used by multi function thread 131 */ 132 extern pri_t minclsyspri; 133 134 /* 135 * ipw2200 specific hardware operations 136 */ 137 static void ipw2200_hwconf_get(struct ipw2200_softc *sc); 138 static int ipw2200_chip_reset(struct ipw2200_softc *sc); 139 static void ipw2200_master_stop(struct ipw2200_softc *sc); 140 static void ipw2200_stop(struct ipw2200_softc *sc); 141 static int ipw2200_config(struct ipw2200_softc *sc); 142 static int ipw2200_cmd(struct ipw2200_softc *sc, 143 uint32_t type, void *buf, size_t len, int async); 144 static void ipw2200_ring_hwsetup(struct ipw2200_softc *sc); 145 static int ipw2200_ring_alloc(struct ipw2200_softc *sc); 146 static void ipw2200_ring_free(struct ipw2200_softc *sc); 147 static void ipw2200_ring_reset(struct ipw2200_softc *sc); 148 static int ipw2200_ring_init(struct ipw2200_softc *sc); 149 150 /* 151 * GLD specific operations 152 */ 153 static int ipw2200_m_stat(void *arg, uint_t stat, uint64_t *val); 154 static int ipw2200_m_start(void *arg); 155 static void ipw2200_m_stop(void *arg); 156 static int ipw2200_m_unicst(void *arg, const uint8_t *macaddr); 157 static int ipw2200_m_multicst(void *arg, boolean_t add, const uint8_t *m); 158 static int ipw2200_m_promisc(void *arg, boolean_t on); 159 static void ipw2200_m_ioctl(void *arg, queue_t *wq, mblk_t *mp); 160 static mblk_t *ipw2200_m_tx(void *arg, mblk_t *mp); 161 162 /* 163 * Interrupt and Data transferring operations 164 */ 165 static uint_t ipw2200_intr(caddr_t arg); 166 static int ipw2200_send(struct ieee80211com *ic, mblk_t *mp, uint8_t type); 167 static void ipw2200_rcv_frame(struct ipw2200_softc *sc, 168 struct ipw2200_frame *frame); 169 static void ipw2200_rcv_notif(struct ipw2200_softc *sc, 170 struct ipw2200_notif *notif); 171 172 /* 173 * WiFi specific operations 174 */ 175 static int ipw2200_newstate(struct ieee80211com *ic, 176 enum ieee80211_state state, int arg); 177 static void ipw2200_thread(struct ipw2200_softc *sc); 178 179 /* 180 * IOCTL Handler 181 */ 182 static int ipw2200_ioctl(struct ipw2200_softc *sc, queue_t *q, mblk_t *m); 183 static int ipw2200_getset(struct ipw2200_softc *sc, 184 mblk_t *m, uint32_t cmd, boolean_t *need_net80211); 185 static int iwi_wificfg_radio(struct ipw2200_softc *sc, 186 uint32_t cmd, wldp_t *outfp); 187 static int iwi_wificfg_desrates(wldp_t *outfp); 188 189 /* 190 * net80211 functions 191 */ 192 extern uint8_t ieee80211_crypto_getciphertype(ieee80211com_t *ic); 193 extern void ieee80211_notify_node_join(ieee80211com_t *ic, 194 ieee80211_node_t *in); 195 extern void ieee80211_notify_node_leave(ieee80211com_t *ic, 196 ieee80211_node_t *in); 197 198 /* 199 * Mac Call Back entries 200 */ 201 mac_callbacks_t ipw2200_m_callbacks = { 202 MC_IOCTL, 203 ipw2200_m_stat, 204 ipw2200_m_start, 205 ipw2200_m_stop, 206 ipw2200_m_promisc, 207 ipw2200_m_multicst, 208 ipw2200_m_unicst, 209 ipw2200_m_tx, 210 NULL, 211 ipw2200_m_ioctl 212 }; 213 214 /* 215 * DEBUG Facility 216 */ 217 #define MAX_MSG (128) 218 uint32_t ipw2200_debug = 0; 219 /* 220 * supported debug marks are: 221 * | IPW2200_DBG_CSR 222 * | IPW2200_DBG_TABLE 223 * | IPW2200_DBG_HWCAP 224 * | IPW2200_DBG_TX 225 * | IPW2200_DBG_INIT 226 * | IPW2200_DBG_FW 227 * | IPW2200_DBG_NOTIF 228 * | IPW2200_DBG_SCAN 229 * | IPW2200_DBG_IOCTL 230 * | IPW2200_DBG_RING 231 * | IPW2200_DBG_INT 232 * | IPW2200_DBG_RX 233 * | IPW2200_DBG_DMA 234 * | IPW2200_DBG_GLD 235 * | IPW2200_DBG_WIFI 236 * | IPW2200_DBG_SOFTINT 237 * | IPW2200_DBG_SUSPEND 238 */ 239 240 /* 241 * Global tunning parameter to work around unknown hardware issues 242 */ 243 static uint32_t delay_config_stable = 100000; /* 100ms */ 244 static uint32_t delay_fatal_recover = 100000 * 20; /* 2s */ 245 static uint32_t delay_aux_thread = 100000; /* 100ms */ 246 247 #define IEEE80211_IS_CHAN_2GHZ(_c) \ 248 (((_c)->ich_flags & IEEE80211_CHAN_2GHZ) != 0) 249 #define IEEE80211_IS_CHAN_5GHZ(_c) \ 250 (((_c)->ich_flags & IEEE80211_CHAN_5GHZ) != 0) 251 #define isset(a, i) ((a)[(i)/NBBY] & (1 << ((i)%NBBY))) 252 253 void 254 ipw2200_dbg(dev_info_t *dip, int level, const char *fmt, ...) 255 { 256 va_list ap; 257 char buf[MAX_MSG]; 258 int instance; 259 260 va_start(ap, fmt); 261 (void) vsnprintf(buf, sizeof (buf), fmt, ap); 262 va_end(ap); 263 264 if (dip) { 265 instance = ddi_get_instance(dip); 266 cmn_err(level, "%s%d: %s", IPW2200_DRV_NAME, instance, buf); 267 } else 268 cmn_err(level, "%s: %s", IPW2200_DRV_NAME, buf); 269 270 } 271 272 /* 273 * Set up pci 274 */ 275 int 276 ipw2200_setup_pci(dev_info_t *dip, struct ipw2200_softc *sc) 277 { 278 ddi_acc_handle_t cfgh; 279 caddr_t regs; 280 int err; 281 282 /* 283 * Map config spaces register to read the vendor id, device id, sub 284 * vendor id, and sub device id. 285 */ 286 err = ddi_regs_map_setup(dip, IPW2200_PCI_CFG_RNUM, ®s, 287 0, 0, &ipw2200_csr_accattr, &cfgh); 288 if (err != DDI_SUCCESS) { 289 IPW2200_WARN((dip, CE_WARN, 290 "ipw2200_attach(): unable to map spaces regs\n")); 291 return (DDI_FAILURE); 292 } 293 294 ddi_put8(cfgh, (uint8_t *)(regs + 0x41), 0); 295 sc->sc_vendor = ddi_get16(cfgh, 296 (uint16_t *)((uintptr_t)regs + PCI_CONF_VENID)); 297 sc->sc_device = ddi_get16(cfgh, 298 (uint16_t *)((uintptr_t)regs + PCI_CONF_DEVID)); 299 sc->sc_subven = ddi_get16(cfgh, 300 (uint16_t *)((uintptr_t)regs + PCI_CONF_SUBVENID)); 301 sc->sc_subdev = ddi_get16(cfgh, 302 (uint16_t *)((uintptr_t)regs + PCI_CONF_SUBSYSID)); 303 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 304 "ipw2200_setup_pci(): vendor = 0x%04x, devic = 0x%04x," 305 "subversion = 0x%04x, subdev = 0x%04x", 306 sc->sc_vendor, sc->sc_device, sc->sc_subven, sc->sc_subdev)); 307 308 ddi_regs_map_free(&cfgh); 309 310 return (DDI_SUCCESS); 311 312 } 313 314 /* 315 * Device operations 316 */ 317 int 318 ipw2200_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 319 { 320 struct ipw2200_softc *sc; 321 struct ieee80211com *ic; 322 int instance, err, i; 323 char strbuf[32]; 324 wifi_data_t wd = { 0 }; 325 mac_register_t *macp; 326 327 switch (cmd) { 328 case DDI_ATTACH: 329 break; 330 case DDI_RESUME: 331 sc = ddi_get_soft_state(ipw2200_ssp, ddi_get_instance(dip)); 332 ASSERT(sc != NULL); 333 334 /* 335 * set up pci 336 */ 337 err = ipw2200_setup_pci(dip, sc); 338 if (err != DDI_SUCCESS) { 339 IPW2200_DBG(IPW2200_DBG_SUSPEND, (sc->sc_dip, CE_CONT, 340 "ipw2200_attach(): resume failure\n")); 341 return (DDI_FAILURE); 342 } 343 344 /* 345 * resume hardware. 346 * If it was on runnning status, reset to INIT state 347 */ 348 sc->sc_flags &= ~IPW2200_FLAG_SUSPEND; 349 if (sc->sc_flags & IPW2200_FLAG_RUNNING) 350 (void) ipw2200_init(sc); 351 352 IPW2200_DBG(IPW2200_DBG_SUSPEND, (sc->sc_dip, CE_CONT, 353 "ipw2200_attach(): resume successful\n")); 354 return (DDI_SUCCESS); 355 default: 356 return (DDI_FAILURE); 357 } 358 359 instance = ddi_get_instance(dip); 360 err = ddi_soft_state_zalloc(ipw2200_ssp, instance); 361 if (err != DDI_SUCCESS) { 362 IPW2200_WARN((dip, CE_WARN, 363 "ipw2200_attach(): unable to allocate soft state\n")); 364 goto fail1; 365 } 366 sc = ddi_get_soft_state(ipw2200_ssp, instance); 367 sc->sc_dip = dip; 368 369 /* set up pci, put reg+0x41 0 */ 370 err = ipw2200_setup_pci(dip, sc); 371 if (err != DDI_SUCCESS) { 372 IPW2200_WARN((dip, CE_WARN, 373 "ipw2200_attach(): unable to setup pci\n")); 374 goto fail2; 375 } 376 377 /* 378 * Map operating registers 379 */ 380 err = ddi_regs_map_setup(dip, IPW2200_PCI_CSR_RNUM, &sc->sc_regs, 381 0, 0, &ipw2200_csr_accattr, &sc->sc_ioh); 382 if (err != DDI_SUCCESS) { 383 IPW2200_WARN((dip, CE_WARN, 384 "ipw2200_attach(): ddi_regs_map_setup() failed\n")); 385 goto fail2; 386 } 387 388 /* 389 * Reset the chip 390 */ 391 err = ipw2200_chip_reset(sc); 392 if (err != DDI_SUCCESS) { 393 IPW2200_WARN((dip, CE_WARN, 394 "ipw2200_attach(): ipw2200_chip_reset() failed\n")); 395 goto fail3; 396 } 397 398 /* 399 * Get the hardware configuration, including the MAC address 400 * Then, init all the rings needed. 401 */ 402 ipw2200_hwconf_get(sc); 403 err = ipw2200_ring_init(sc); 404 if (err != DDI_SUCCESS) { 405 IPW2200_WARN((dip, CE_WARN, 406 "ipw2200_attach(): ipw2200_ring_init() failed\n")); 407 goto fail3; 408 } 409 410 /* 411 * Initialize mutexs and condvars 412 */ 413 err = ddi_get_iblock_cookie(dip, 0, &sc->sc_iblk); 414 if (err != DDI_SUCCESS) { 415 IPW2200_WARN((dip, CE_WARN, 416 "ipw2200_attach(): ddi_get_iblock_cookie() failed\n")); 417 goto fail4; 418 } 419 420 /* 421 * interrupt lock 422 */ 423 mutex_init(&sc->sc_ilock, "intr-lock", MUTEX_DRIVER, 424 (void *) sc->sc_iblk); 425 cv_init(&sc->sc_fw_cond, "firmware-ok", CV_DRIVER, NULL); 426 cv_init(&sc->sc_cmd_status_cond, "cmd-status-ring", CV_DRIVER, NULL); 427 428 /* 429 * command ring lock 430 */ 431 mutex_init(&sc->sc_cmd_lock, "cmd-ring", MUTEX_DRIVER, 432 (void *) sc->sc_iblk); 433 cv_init(&sc->sc_cmd_cond, "cmd-ring", CV_DRIVER, NULL); 434 435 /* 436 * tx ring lock 437 */ 438 mutex_init(&sc->sc_tx_lock, "tx-ring", MUTEX_DRIVER, 439 (void *) sc->sc_iblk); 440 441 /* 442 * rescheduled lock 443 */ 444 mutex_init(&sc->sc_resched_lock, "reschedule-lock", MUTEX_DRIVER, 445 (void *) sc->sc_iblk); 446 447 /* 448 * multi-function lock, may acquire this during interrupt 449 */ 450 mutex_init(&sc->sc_mflock, "function-lock", MUTEX_DRIVER, 451 (void *) sc->sc_iblk); 452 cv_init(&sc->sc_mfthread_cv, NULL, CV_DRIVER, NULL); 453 sc->sc_mf_thread = NULL; 454 sc->sc_mfthread_switch = 0; 455 456 /* 457 * Initialize the WiFi part 458 */ 459 ic = &sc->sc_ic; 460 ic->ic_phytype = IEEE80211_T_OFDM; 461 ic->ic_opmode = IEEE80211_M_STA; 462 ic->ic_state = IEEE80211_S_INIT; 463 ic->ic_maxrssi = 100; /* experimental number */ 464 ic->ic_caps = 465 IEEE80211_C_SHPREAMBLE | 466 IEEE80211_C_TXPMGT | 467 IEEE80211_C_PMGT | 468 IEEE80211_C_WPA; 469 470 /* 471 * set mac addr 472 */ 473 IEEE80211_ADDR_COPY(ic->ic_macaddr, sc->sc_macaddr); 474 475 /* 476 * set supported .11a rates and channel - (2915ABG only) 477 */ 478 if (sc->sc_device >= 0x4223) { 479 /* .11a rates */ 480 ic->ic_sup_rates[IEEE80211_MODE_11A] = ipw2200_rateset_11a; 481 /* .11a channels */ 482 for (i = 36; i <= 64; i += 4) { 483 ic->ic_sup_channels[i].ich_freq = 484 ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ); 485 ic->ic_sup_channels[i].ich_flags = /* CHAN_A */ 486 IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM; 487 } 488 for (i = 149; i <= 165; i += 4) { 489 ic->ic_sup_channels[i].ich_freq = 490 ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ); 491 ic->ic_sup_channels[i].ich_flags = /* CHAN_A */ 492 IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM; 493 } 494 } 495 496 /* 497 * set supported .11b and .11g rates 498 */ 499 ic->ic_sup_rates[IEEE80211_MODE_11B] = ipw2200_rateset_11b; 500 ic->ic_sup_rates[IEEE80211_MODE_11G] = ipw2200_rateset_11g; 501 502 /* 503 * set supported .11b and .11g channels(1 through 14) 504 */ 505 for (i = 1; i < 14; i++) { 506 ic->ic_sup_channels[i].ich_freq = 507 ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ); 508 ic->ic_sup_channels[i].ich_flags = 509 IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM | 510 IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ; 511 } 512 513 /* 514 * IBSS channal undefined for now 515 */ 516 ic->ic_ibss_chan = &ic->ic_sup_channels[0]; 517 ic->ic_xmit = ipw2200_send; 518 519 /* 520 * init generic layer, then override state transition machine 521 */ 522 ieee80211_attach(ic); 523 524 /* 525 * different instance has different WPA door 526 */ 527 ieee80211_register_door(ic, ddi_driver_name(dip), instance); 528 529 /* 530 * Override 80211 default routines 531 */ 532 ieee80211_media_init(ic); /* initial the node table and bss */ 533 sc->sc_newstate = ic->ic_newstate; 534 ic->ic_newstate = ipw2200_newstate; 535 ic->ic_def_txkey = 0; 536 sc->sc_authmode = IEEE80211_AUTH_OPEN; 537 538 /* 539 * Add the interrupt handler 540 */ 541 err = ddi_add_intr(dip, 0, &sc->sc_iblk, NULL, 542 ipw2200_intr, (caddr_t)sc); 543 if (err != DDI_SUCCESS) { 544 IPW2200_WARN((dip, CE_WARN, 545 "ipw2200_attach(): ddi_add_intr() failed\n")); 546 goto fail5; 547 } 548 549 /* 550 * Initialize pointer to device specific functions 551 */ 552 wd.wd_secalloc = WIFI_SEC_NONE; 553 wd.wd_opmode = ic->ic_opmode; 554 IEEE80211_ADDR_COPY(wd.wd_bssid, ic->ic_bss->in_bssid); 555 556 macp = mac_alloc(MAC_VERSION); 557 if (err != 0) { 558 IPW2200_WARN((dip, CE_WARN, 559 "ipw2200_attach(): mac_alloc() failed\n")); 560 goto fail6; 561 } 562 563 macp->m_type_ident = MAC_PLUGIN_IDENT_WIFI; 564 macp->m_driver = sc; 565 macp->m_dip = dip; 566 macp->m_src_addr = ic->ic_macaddr; 567 macp->m_callbacks = &ipw2200_m_callbacks; 568 macp->m_min_sdu = 0; 569 macp->m_max_sdu = IEEE80211_MTU; 570 macp->m_pdata = &wd; 571 macp->m_pdata_size = sizeof (wd); 572 573 /* 574 * Register the macp to mac 575 */ 576 err = mac_register(macp, &ic->ic_mach); 577 mac_free(macp); 578 if (err != DDI_SUCCESS) { 579 IPW2200_WARN((dip, CE_WARN, 580 "ipw2200_attach(): mac_register() failed\n")); 581 goto fail6; 582 } 583 584 /* 585 * Create minor node of type DDI_NT_NET_WIFI 586 */ 587 (void) snprintf(strbuf, sizeof (strbuf), "%s%d", 588 IPW2200_DRV_NAME, instance); 589 err = ddi_create_minor_node(dip, strbuf, S_IFCHR, 590 instance + 1, DDI_NT_NET_WIFI, 0); 591 if (err != DDI_SUCCESS) 592 IPW2200_WARN((dip, CE_WARN, 593 "ipw2200_attach(): ddi_create_minor_node() failed\n")); 594 595 /* 596 * Cache firmware will always be true 597 */ 598 (void) ipw2200_cache_firmware(sc); 599 600 /* 601 * Notify link is down now 602 */ 603 mac_link_update(ic->ic_mach, LINK_STATE_DOWN); 604 605 /* 606 * Create the mf thread to handle the link status, 607 * recovery fatal error, etc. 608 */ 609 sc->sc_mfthread_switch = 1; 610 if (sc->sc_mf_thread == NULL) 611 sc->sc_mf_thread = thread_create((caddr_t)NULL, 0, 612 ipw2200_thread, sc, 0, &p0, TS_RUN, minclsyspri); 613 614 return (DDI_SUCCESS); 615 616 fail6: 617 ddi_remove_intr(dip, 0, sc->sc_iblk); 618 fail5: 619 ieee80211_detach(ic); 620 621 mutex_destroy(&sc->sc_ilock); 622 mutex_destroy(&sc->sc_cmd_lock); 623 mutex_destroy(&sc->sc_tx_lock); 624 mutex_destroy(&sc->sc_mflock); 625 mutex_destroy(&sc->sc_resched_lock); 626 cv_destroy(&sc->sc_fw_cond); 627 cv_destroy(&sc->sc_cmd_status_cond); 628 cv_destroy(&sc->sc_cmd_cond); 629 cv_destroy(&sc->sc_mfthread_cv); 630 fail4: 631 ipw2200_ring_free(sc); 632 fail3: 633 ddi_regs_map_free(&sc->sc_ioh); 634 fail2: 635 ddi_soft_state_free(ipw2200_ssp, instance); 636 fail1: 637 return (err); 638 } 639 640 641 int 642 ipw2200_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 643 { 644 struct ipw2200_softc *sc; 645 int err; 646 647 sc = ddi_get_soft_state(ipw2200_ssp, ddi_get_instance(dip)); 648 ASSERT(sc != NULL); 649 650 switch (cmd) { 651 case DDI_DETACH: 652 break; 653 case DDI_SUSPEND: 654 if (sc->sc_flags & IPW2200_FLAG_RUNNING) { 655 ipw2200_stop(sc); 656 } 657 sc->sc_flags |= IPW2200_FLAG_SUSPEND; 658 659 IPW2200_DBG(IPW2200_DBG_SUSPEND, (sc->sc_dip, CE_CONT, 660 "ipw2200_detach(): suspend\n")); 661 return (DDI_SUCCESS); 662 default: 663 return (DDI_FAILURE); 664 } 665 666 ipw2200_stop(sc); 667 668 /* 669 * Destroy the mf_thread 670 */ 671 mutex_enter(&sc->sc_mflock); 672 sc->sc_mfthread_switch = 0; 673 while (sc->sc_mf_thread != NULL) { 674 if (cv_wait_sig(&sc->sc_mfthread_cv, &sc->sc_mflock) == 0) 675 break; 676 } 677 mutex_exit(&sc->sc_mflock); 678 679 /* 680 * Unregister from the MAC layer subsystem 681 */ 682 err = mac_unregister(sc->sc_ic.ic_mach); 683 if (err != DDI_SUCCESS) 684 return (err); 685 686 ddi_remove_intr(dip, IPW2200_PCI_INTR_NUM, sc->sc_iblk); 687 688 mutex_destroy(&sc->sc_ilock); 689 mutex_destroy(&sc->sc_cmd_lock); 690 mutex_destroy(&sc->sc_tx_lock); 691 mutex_destroy(&sc->sc_mflock); 692 mutex_destroy(&sc->sc_resched_lock); 693 cv_destroy(&sc->sc_fw_cond); 694 cv_destroy(&sc->sc_cmd_status_cond); 695 cv_destroy(&sc->sc_cmd_cond); 696 cv_destroy(&sc->sc_mfthread_cv); 697 698 /* 699 * Detach ieee80211 700 */ 701 ieee80211_detach(&sc->sc_ic); 702 703 (void) ipw2200_free_firmware(sc); 704 ipw2200_ring_free(sc); 705 706 ddi_regs_map_free(&sc->sc_ioh); 707 ddi_remove_minor_node(dip, NULL); 708 ddi_soft_state_free(ipw2200_ssp, ddi_get_instance(dip)); 709 710 return (DDI_SUCCESS); 711 } 712 713 /* ARGSUSED */ 714 int 715 ipw2200_reset(dev_info_t *dip, ddi_reset_cmd_t cmd) 716 { 717 struct ipw2200_softc *sc = 718 ddi_get_soft_state(ipw2200_ssp, ddi_get_instance(dip)); 719 ASSERT(sc != NULL); 720 721 ipw2200_stop(sc); 722 723 return (DDI_SUCCESS); 724 } 725 726 static void 727 ipw2200_stop(struct ipw2200_softc *sc) 728 { 729 struct ieee80211com *ic = &sc->sc_ic; 730 731 IPW2200_DBG(IPW2200_DBG_HWCAP, (sc->sc_dip, CE_CONT, 732 "ipw2200_stop(): enter\n")); 733 734 ipw2200_master_stop(sc); 735 ipw2200_csr_put32(sc, IPW2200_CSR_RST, IPW2200_RST_SW_RESET); 736 737 /* 738 * Reset ring 739 */ 740 ipw2200_ring_reset(sc); 741 742 ieee80211_new_state(ic, IEEE80211_S_INIT, -1); 743 sc->sc_flags &= ~IPW2200_FLAG_SCANNING; 744 sc->sc_flags &= ~IPW2200_FLAG_ASSOCIATED; 745 746 IPW2200_DBG(IPW2200_DBG_HWCAP, (sc->sc_dip, CE_CONT, 747 "ipw2200_stop(): exit\n")); 748 } 749 750 static int 751 ipw2200_config(struct ipw2200_softc *sc) 752 { 753 struct ieee80211com *ic = &sc->sc_ic; 754 struct ipw2200_configuration cfg; 755 uint32_t data; 756 struct ipw2200_txpower pwr; 757 struct ipw2200_rateset rs; 758 struct ipw2200_wep_key wkey; 759 int err, i; 760 761 /* 762 * Set the IBSS mode channel: Tx power 763 */ 764 if (ic->ic_opmode == IEEE80211_M_IBSS) { 765 pwr.mode = IPW2200_MODE_11B; 766 pwr.nchan = 11; 767 for (i = 0; i < pwr.nchan; i++) { 768 pwr.chan[i].chan = i + 1; 769 pwr.chan[i].power = IPW2200_TXPOWER_MAX; 770 } 771 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 772 "ipw2200_config(): Setting .11b channels Tx power\n")); 773 err = ipw2200_cmd(sc, IPW2200_CMD_SET_TX_POWER, 774 &pwr, sizeof (pwr), 0); 775 if (err != DDI_SUCCESS) 776 return (err); 777 778 pwr.mode = IPW2200_MODE_11G; 779 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 780 "ipw2200_config(): Setting .11g channels Tx power\n")); 781 err = ipw2200_cmd(sc, IPW2200_CMD_SET_TX_POWER, 782 &pwr, sizeof (pwr), 0); 783 if (err != DDI_SUCCESS) 784 return (err); 785 } 786 787 /* 788 * Set MAC address 789 */ 790 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 791 "ipw2200_config(): Setting MAC address to " 792 "%02x:%02x:%02x:%02x:%02x:%02x\n", 793 ic->ic_macaddr[0], ic->ic_macaddr[1], ic->ic_macaddr[2], 794 ic->ic_macaddr[3], ic->ic_macaddr[4], ic->ic_macaddr[5])); 795 err = ipw2200_cmd(sc, IPW2200_CMD_SET_MAC_ADDRESS, ic->ic_macaddr, 796 IEEE80211_ADDR_LEN, 0); 797 if (err != DDI_SUCCESS) 798 return (err); 799 800 /* 801 * Set basic system config settings: configuration(capabilities) 802 */ 803 (void) memset(&cfg, 0, sizeof (cfg)); 804 cfg.bluetooth_coexistence = 1; 805 cfg.multicast_enabled = 1; 806 cfg.answer_pbreq = 1; 807 cfg.noise_reported = 1; 808 cfg.disable_multicast_decryption = 1; /* WPA */ 809 cfg.disable_unicast_decryption = 1; /* WPA */ 810 811 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 812 "ipw2200_config(): Configuring adapter\n")); 813 err = ipw2200_cmd(sc, IPW2200_CMD_SET_CONFIG, 814 &cfg, sizeof (cfg), 0); 815 if (err != DDI_SUCCESS) 816 return (err); 817 818 /* 819 * Set power mode 820 */ 821 data = LE_32(IPW2200_POWER_MODE_CAM); 822 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 823 "ipw2200_config(): Setting power mode to %u\n", LE_32(data))); 824 err = ipw2200_cmd(sc, IPW2200_CMD_SET_POWER_MODE, 825 &data, sizeof (data), 0); 826 if (err != DDI_SUCCESS) 827 return (err); 828 829 /* 830 * Set supported rates 831 */ 832 rs.mode = IPW2200_MODE_11G; 833 rs.type = IPW2200_RATESET_TYPE_SUPPORTED; 834 rs.nrates = ic->ic_sup_rates[IEEE80211_MODE_11G].ir_nrates; 835 (void) memcpy(rs.rates, ic->ic_sup_rates[IEEE80211_MODE_11G].ir_rates, 836 rs.nrates); 837 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 838 "ipw2200_config(): Setting .11g supported rates(%u)\n", rs.nrates)); 839 err = ipw2200_cmd(sc, IPW2200_CMD_SET_RATES, &rs, sizeof (rs), 0); 840 if (err != DDI_SUCCESS) 841 return (err); 842 843 rs.mode = IPW2200_MODE_11A; 844 rs.type = IPW2200_RATESET_TYPE_SUPPORTED; 845 rs.nrates = ic->ic_sup_rates[IEEE80211_MODE_11A].ir_nrates; 846 (void) memcpy(rs.rates, ic->ic_sup_rates[IEEE80211_MODE_11A].ir_rates, 847 rs.nrates); 848 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 849 "ipw2200_config(): Setting .11a supported rates(%u)\n", rs.nrates)); 850 err = ipw2200_cmd(sc, IPW2200_CMD_SET_RATES, &rs, sizeof (rs), 0); 851 if (err != DDI_SUCCESS) 852 return (err); 853 854 /* 855 * Set RTS(request-to-send) threshold 856 */ 857 data = LE_32(ic->ic_rtsthreshold); 858 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 859 "ipw2200_config(): Setting RTS threshold to %u\n", LE_32(data))); 860 err = ipw2200_cmd(sc, IPW2200_CMD_SET_RTS_THRESHOLD, &data, 861 sizeof (data), 0); 862 if (err != DDI_SUCCESS) 863 return (err); 864 865 /* 866 * Set fragmentation threshold 867 */ 868 data = LE_32(ic->ic_fragthreshold); 869 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 870 "ipw2200_config(): Setting fragmentation threshold to %u\n", 871 LE_32(data))); 872 err = ipw2200_cmd(sc, IPW2200_CMD_SET_FRAG_THRESHOLD, &data, 873 sizeof (data), 0); 874 if (err != DDI_SUCCESS) 875 return (err); 876 877 /* 878 * Set desired ESSID if we have 879 */ 880 if (ic->ic_des_esslen != 0) { 881 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 882 "ipw2200_config(): Setting desired ESSID to " 883 "(%u),%c%c%c%c%c%c%c%c\n", 884 ic->ic_des_esslen, 885 ic->ic_des_essid[0], ic->ic_des_essid[1], 886 ic->ic_des_essid[2], ic->ic_des_essid[3], 887 ic->ic_des_essid[4], ic->ic_des_essid[5], 888 ic->ic_des_essid[6], ic->ic_des_essid[7])); 889 err = ipw2200_cmd(sc, IPW2200_CMD_SET_ESSID, ic->ic_des_essid, 890 ic->ic_des_esslen, 0); 891 if (err != DDI_SUCCESS) 892 return (err); 893 } 894 895 /* 896 * Set WEP initial vector(random seed) 897 */ 898 (void) random_get_pseudo_bytes((uint8_t *)&data, sizeof (data)); 899 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 900 "ipw2200_config(): Setting initialization vector to %u\n", 901 LE_32(data))); 902 err = ipw2200_cmd(sc, IPW2200_CMD_SET_IV, &data, sizeof (data), 0); 903 if (err != DDI_SUCCESS) 904 return (err); 905 906 /* 907 * Set WEP if any 908 */ 909 if (ic->ic_flags & IEEE80211_F_PRIVACY) { 910 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 911 "ipw2200_config(): Setting Wep Key\n", LE_32(data))); 912 for (i = 0; i < IEEE80211_WEP_NKID; i++) { 913 wkey.cmd = IPW2200_WEP_KEY_CMD_SETKEY; 914 wkey.idx = (uint8_t)i; 915 wkey.len = ic->ic_nw_keys[i].wk_keylen; 916 (void) memset(wkey.key, 0, sizeof (wkey.key)); 917 if (ic->ic_nw_keys[i].wk_keylen) 918 (void) memcpy(wkey.key, 919 ic->ic_nw_keys[i].wk_key, 920 ic->ic_nw_keys[i].wk_keylen); 921 err = ipw2200_cmd(sc, IPW2200_CMD_SET_WEP_KEY, 922 &wkey, sizeof (wkey), 0); 923 if (err != DDI_SUCCESS) 924 return (err); 925 } 926 } 927 928 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 929 "ipw2200_config(): Enabling adapter\n")); 930 931 return (ipw2200_cmd(sc, IPW2200_CMD_ENABLE, NULL, 0, 0)); 932 } 933 934 static int 935 ipw2200_cmd(struct ipw2200_softc *sc, 936 uint32_t type, void *buf, size_t len, int async) 937 { 938 struct ipw2200_cmd_desc *cmd; 939 clock_t clk; 940 uint32_t idx; 941 942 mutex_enter(&sc->sc_cmd_lock); 943 while (sc->sc_cmd_free < 1) 944 cv_wait(&sc->sc_cmd_cond, &sc->sc_cmd_lock); 945 946 idx = sc->sc_cmd_cur; 947 cmd = &sc->sc_cmdsc[idx]; 948 (void) memset(cmd, 0, sizeof (*cmd)); 949 950 IPW2200_DBG(IPW2200_DBG_RING, (sc->sc_dip, CE_CONT, 951 "ipw2200_cmd(): cmd-cur=%d\n", idx)); 952 953 cmd->hdr.type = IPW2200_HDR_TYPE_COMMAND; 954 cmd->hdr.flags = IPW2200_HDR_FLAG_IRQ; 955 cmd->type = (uint8_t)type; 956 if (len == 0 || buf == NULL) 957 cmd->len = 0; 958 else { 959 cmd->len = (uint8_t)len; 960 (void) memcpy(cmd->data, buf, len); 961 } 962 sc->sc_done[idx] = 0; 963 964 /* 965 * DMA sync 966 */ 967 (void) ddi_dma_sync(sc->sc_dma_cmdsc.dr_hnd, 968 idx * sizeof (struct ipw2200_cmd_desc), 969 sizeof (struct ipw2200_cmd_desc), DDI_DMA_SYNC_FORDEV); 970 971 sc->sc_cmd_cur = RING_FORWARD(sc->sc_cmd_cur, 1, IPW2200_CMD_RING_SIZE); 972 sc->sc_cmd_free--; 973 974 ipw2200_csr_put32(sc, IPW2200_CSR_CMD_WRITE_INDEX, sc->sc_cmd_cur); 975 976 mutex_exit(&sc->sc_cmd_lock); 977 978 if (async) 979 goto out; 980 981 /* 982 * Wait for command done 983 */ 984 mutex_enter(&sc->sc_ilock); 985 while (sc->sc_done[idx] == 0) { 986 /* pending */ 987 clk = ddi_get_lbolt() + drv_usectohz(5000000); /* 5 second */ 988 if (cv_timedwait(&sc->sc_cmd_status_cond, &sc->sc_ilock, clk) 989 < 0) 990 break; 991 } 992 mutex_exit(&sc->sc_ilock); 993 994 IPW2200_DBG(IPW2200_DBG_RING, (sc->sc_dip, CE_CONT, 995 "ipw2200_cmd(): cmd-done=%s\n", sc->sc_done[idx] ? "yes" : "no")); 996 997 if (sc->sc_done[idx] == 0) 998 return (DDI_FAILURE); 999 1000 out: 1001 return (DDI_SUCCESS); 1002 } 1003 1004 /* 1005 * If init failed, it will call stop internally. Therefore, it's unnecessary 1006 * to call ipw2200_stop() when this subroutine is failed. Otherwise, it may 1007 * be called twice. 1008 */ 1009 int 1010 ipw2200_init(struct ipw2200_softc *sc) 1011 { 1012 int err; 1013 1014 /* 1015 * No firmware is available, failed 1016 */ 1017 if (!(sc->sc_flags & IPW2200_FLAG_FW_CACHED)) { 1018 IPW2200_WARN((sc->sc_dip, CE_WARN, 1019 "ipw2200_init(): no firmware is available\n")); 1020 return (DDI_FAILURE); /* return directly */ 1021 } 1022 1023 ipw2200_stop(sc); 1024 1025 err = ipw2200_chip_reset(sc); 1026 if (err != DDI_SUCCESS) { 1027 IPW2200_WARN((sc->sc_dip, CE_WARN, 1028 "ipw2200_init(): could not reset adapter\n")); 1029 goto fail; 1030 } 1031 1032 /* 1033 * Load boot code 1034 */ 1035 err = ipw2200_load_fw(sc, sc->sc_fw.boot_base, sc->sc_fw.boot_size); 1036 if (err != DDI_SUCCESS) { 1037 IPW2200_WARN((sc->sc_dip, CE_WARN, 1038 "ipw2200_init(): could not load boot code\n")); 1039 goto fail; 1040 } 1041 1042 /* 1043 * Load boot microcode 1044 */ 1045 err = ipw2200_load_uc(sc, sc->sc_fw.uc_base, sc->sc_fw.uc_size); 1046 if (err != DDI_SUCCESS) { 1047 IPW2200_WARN((sc->sc_dip, CE_WARN, 1048 "ipw2200_init(): could not load microcode\n")); 1049 goto fail; 1050 } 1051 1052 ipw2200_master_stop(sc); 1053 ipw2200_ring_hwsetup(sc); 1054 1055 /* 1056 * Load firmware 1057 */ 1058 err = ipw2200_load_fw(sc, sc->sc_fw.fw_base, sc->sc_fw.fw_size); 1059 if (err != DDI_SUCCESS) { 1060 IPW2200_WARN((sc->sc_dip, CE_WARN, 1061 "ipw2200_init(): could not load firmware\n")); 1062 goto fail; 1063 } 1064 1065 sc->sc_flags |= IPW2200_FLAG_FW_INITED; 1066 1067 /* 1068 * Hardware will be enabled after configuration 1069 */ 1070 err = ipw2200_config(sc); 1071 if (err != DDI_SUCCESS) { 1072 IPW2200_WARN((sc->sc_dip, CE_WARN, 1073 "ipw2200_init(): device configuration failed\n")); 1074 goto fail; 1075 } 1076 1077 /* 1078 * workround to prevent too many h/w error. 1079 * delay for a while till h/w is stable. 1080 */ 1081 delay(drv_usectohz(delay_config_stable)); 1082 1083 return (DDI_SUCCESS); /* return successfully */ 1084 fail: 1085 ipw2200_stop(sc); 1086 return (err); 1087 } 1088 1089 /* 1090 * get hardware configurations from EEPROM embedded within PRO/2200 1091 */ 1092 static void 1093 ipw2200_hwconf_get(struct ipw2200_softc *sc) 1094 { 1095 int i; 1096 uint16_t val; 1097 1098 /* 1099 * Get mac address 1100 */ 1101 i = 0; 1102 val = ipw2200_rom_get16(sc, IPW2200_EEPROM_MAC + 0); 1103 sc->sc_macaddr[i++] = val >> 8; 1104 sc->sc_macaddr[i++] = val & 0xff; 1105 val = ipw2200_rom_get16(sc, IPW2200_EEPROM_MAC + 1); 1106 sc->sc_macaddr[i++] = val >> 8; 1107 sc->sc_macaddr[i++] = val & 0xff; 1108 val = ipw2200_rom_get16(sc, IPW2200_EEPROM_MAC + 2); 1109 sc->sc_macaddr[i++] = val >> 8; 1110 sc->sc_macaddr[i++] = val & 0xff; 1111 1112 /* 1113 * formatted MAC address string 1114 */ 1115 (void) snprintf(sc->sc_macstr, sizeof (sc->sc_macstr), 1116 "%02x:%02x:%02x:%02x:%02x:%02x", 1117 sc->sc_macaddr[0], sc->sc_macaddr[1], 1118 sc->sc_macaddr[2], sc->sc_macaddr[3], 1119 sc->sc_macaddr[4], sc->sc_macaddr[5]); 1120 1121 } 1122 1123 /* 1124 * all ipw2200 interrupts will be masked by this routine 1125 */ 1126 static void 1127 ipw2200_master_stop(struct ipw2200_softc *sc) 1128 { 1129 int ntries; 1130 1131 /* 1132 * disable interrupts 1133 */ 1134 ipw2200_csr_put32(sc, IPW2200_CSR_INTR_MASK, 0); 1135 ipw2200_csr_put32(sc, IPW2200_CSR_RST, IPW2200_RST_STOP_MASTER); 1136 1137 /* 1138 * wait long enough to ensure hardware stop successfully. 1139 */ 1140 for (ntries = 0; ntries < 500; ntries++) { 1141 if (ipw2200_csr_get32(sc, IPW2200_CSR_RST) & 1142 IPW2200_RST_MASTER_DISABLED) 1143 break; 1144 /* wait for a while */ 1145 drv_usecwait(100); 1146 } 1147 if (ntries == 500) 1148 IPW2200_WARN((sc->sc_dip, CE_WARN, 1149 "ipw2200_master_stop(): timeout\n")); 1150 1151 ipw2200_csr_put32(sc, IPW2200_CSR_RST, 1152 IPW2200_RST_PRINCETON_RESET | 1153 ipw2200_csr_get32(sc, IPW2200_CSR_RST)); 1154 1155 sc->sc_flags &= ~IPW2200_FLAG_FW_INITED; 1156 } 1157 1158 /* 1159 * all ipw2200 interrupts will be masked by this routine 1160 */ 1161 static int 1162 ipw2200_chip_reset(struct ipw2200_softc *sc) 1163 { 1164 uint32_t tmp; 1165 int ntries, i; 1166 1167 ipw2200_master_stop(sc); 1168 1169 /* 1170 * Move adapter to DO state 1171 */ 1172 tmp = ipw2200_csr_get32(sc, IPW2200_CSR_CTL); 1173 ipw2200_csr_put32(sc, IPW2200_CSR_CTL, tmp | IPW2200_CTL_INIT); 1174 1175 /* 1176 * Initialize Phase-Locked Level (PLL) 1177 */ 1178 ipw2200_csr_put32(sc, IPW2200_CSR_READ_INT, IPW2200_READ_INT_INIT_HOST); 1179 1180 /* 1181 * Wait for clock stabilization 1182 */ 1183 for (ntries = 0; ntries < 1000; ntries++) { 1184 if (ipw2200_csr_get32(sc, IPW2200_CSR_CTL) & 1185 IPW2200_CTL_CLOCK_READY) 1186 break; 1187 drv_usecwait(200); 1188 } 1189 if (ntries == 1000) { 1190 IPW2200_WARN((sc->sc_dip, CE_WARN, 1191 "ipw2200_chip_reset(): timeout\n")); 1192 return (DDI_FAILURE); 1193 } 1194 1195 tmp = ipw2200_csr_get32(sc, IPW2200_CSR_RST); 1196 ipw2200_csr_put32(sc, IPW2200_CSR_RST, tmp | IPW2200_RST_SW_RESET); 1197 1198 drv_usecwait(10); 1199 1200 tmp = ipw2200_csr_get32(sc, IPW2200_CSR_CTL); 1201 ipw2200_csr_put32(sc, IPW2200_CSR_CTL, tmp | IPW2200_CTL_INIT); 1202 1203 /* 1204 * clear NIC memory 1205 */ 1206 ipw2200_csr_put32(sc, IPW2200_CSR_AUTOINC_ADDR, 0); 1207 for (i = 0; i < 0xc000; i++) 1208 ipw2200_csr_put32(sc, IPW2200_CSR_AUTOINC_DATA, 0); 1209 1210 return (DDI_SUCCESS); 1211 } 1212 1213 /* 1214 * This function is used by wificonfig/dladm to get the current 1215 * radio status, it is off/on 1216 */ 1217 int 1218 ipw2200_radio_status(struct ipw2200_softc *sc) 1219 { 1220 int val; 1221 1222 val = (ipw2200_csr_get32(sc, IPW2200_CSR_IO) & 1223 IPW2200_IO_RADIO_ENABLED) ? 1 : 0; 1224 1225 return (val); 1226 } 1227 /* 1228 * This function is used to get the statistic 1229 */ 1230 void 1231 ipw2200_get_statistics(struct ipw2200_softc *sc) 1232 { 1233 struct ieee80211com *ic = &sc->sc_ic; 1234 1235 uint32_t size, buf[128]; 1236 1237 if (!(sc->sc_flags & IPW2200_FLAG_FW_INITED)) { 1238 IPW2200_DBG(IPW2200_DBG_IOCTL, (sc->sc_dip, CE_CONT, 1239 "ipw2200_get_statistic(): fw doesn't download yet.")); 1240 return; 1241 } 1242 1243 size = min(ipw2200_csr_get32(sc, IPW2200_CSR_TABLE0_SIZE), 128 - 1); 1244 ipw2200_csr_getbuf32(sc, IPW2200_CSR_TABLE0_BASE, &buf[1], size); 1245 1246 /* 1247 * To retrieve the statistic information into proper places. There are 1248 * lot of information. These table will be read once a second. 1249 * Hopefully, it will not effect the performance. 1250 */ 1251 1252 /* 1253 * For the tx/crc information, we can get them from chip directly; 1254 * For the rx/wep error/(rts) related information, leave them net80211. 1255 */ 1256 /* WIFI_STAT_TX_FRAGS */ 1257 ic->ic_stats.is_tx_frags = (uint32_t)buf[5]; 1258 /* WIFI_STAT_MCAST_TX */ 1259 ic->ic_stats.is_tx_mcast = (uint32_t)buf[31]; 1260 /* WIFI_STAT_TX_RETRANS */ 1261 ic->ic_stats.is_tx_retries = (uint32_t)buf[56]; 1262 /* WIFI_STAT_TX_FAILED */ 1263 ic->ic_stats.is_tx_failed = (uint32_t)buf[57]; 1264 /* MAC_STAT_OBYTES */ 1265 ic->ic_stats.is_tx_bytes = (uint32_t)buf[64]; 1266 } 1267 1268 /* 1269 * DMA region alloc subroutine 1270 */ 1271 int 1272 ipw2200_dma_region_alloc(struct ipw2200_softc *sc, struct dma_region *dr, 1273 size_t size, uint_t dir, uint_t flags) 1274 { 1275 dev_info_t *dip = sc->sc_dip; 1276 int err; 1277 1278 IPW2200_DBG(IPW2200_DBG_DMA, (sc->sc_dip, CE_CONT, 1279 "ipw2200_dma_region_alloc(): size =%u\n", size)); 1280 1281 err = ddi_dma_alloc_handle(dip, &ipw2200_dma_attr, DDI_DMA_SLEEP, NULL, 1282 &dr->dr_hnd); 1283 if (err != DDI_SUCCESS) { 1284 IPW2200_DBG(IPW2200_DBG_DMA, (sc->sc_dip, CE_CONT, 1285 "ipw2200_dma_region_alloc(): " 1286 "ddi_dma_alloc_handle() failed\n")); 1287 goto fail0; 1288 } 1289 1290 err = ddi_dma_mem_alloc(dr->dr_hnd, size, &ipw2200_dma_accattr, 1291 flags, DDI_DMA_SLEEP, NULL, 1292 &dr->dr_base, &dr->dr_size, &dr->dr_acc); 1293 if (err != DDI_SUCCESS) { 1294 IPW2200_DBG(IPW2200_DBG_DMA, (sc->sc_dip, CE_CONT, 1295 "ipw2200_dma_region_alloc(): " 1296 "ddi_dma_mem_alloc() failed\n")); 1297 goto fail1; 1298 } 1299 1300 err = ddi_dma_addr_bind_handle(dr->dr_hnd, NULL, 1301 dr->dr_base, dr->dr_size, 1302 dir | flags, DDI_DMA_SLEEP, NULL, 1303 &dr->dr_cookie, &dr->dr_ccnt); 1304 if (err != DDI_DMA_MAPPED) { 1305 IPW2200_DBG(IPW2200_DBG_DMA, (sc->sc_dip, CE_CONT, 1306 "ipw2200_dma_region_alloc(): " 1307 "ddi_dma_addr_bind_handle() failed\n")); 1308 goto fail2; 1309 } 1310 1311 IPW2200_DBG(IPW2200_DBG_DMA, (sc->sc_dip, CE_CONT, 1312 "ipw2200_dma_region_alloc(): ccnt=%u\n", dr->dr_ccnt)); 1313 1314 if (dr->dr_ccnt != 1) { 1315 err = DDI_FAILURE; 1316 goto fail3; 1317 } 1318 1319 dr->dr_pbase = dr->dr_cookie.dmac_address; 1320 1321 IPW2200_DBG(IPW2200_DBG_DMA, (sc->sc_dip, CE_CONT, 1322 "ipw2200_dma_region_alloc(): get physical-base=0x%08x\n", 1323 dr->dr_pbase)); 1324 1325 return (DDI_SUCCESS); 1326 1327 fail3: 1328 (void) ddi_dma_unbind_handle(dr->dr_hnd); 1329 fail2: 1330 ddi_dma_mem_free(&dr->dr_acc); 1331 fail1: 1332 ddi_dma_free_handle(&dr->dr_hnd); 1333 fail0: 1334 return (err); 1335 } 1336 1337 void 1338 ipw2200_dma_region_free(struct dma_region *dr) 1339 { 1340 (void) ddi_dma_unbind_handle(dr->dr_hnd); 1341 ddi_dma_mem_free(&dr->dr_acc); 1342 ddi_dma_free_handle(&dr->dr_hnd); 1343 } 1344 1345 static int 1346 ipw2200_ring_alloc(struct ipw2200_softc *sc) 1347 { 1348 int err, i; 1349 1350 /* 1351 * tx desc ring 1352 */ 1353 sc->sc_dma_txdsc.dr_name = "ipw2200-tx-desc-ring"; 1354 err = ipw2200_dma_region_alloc(sc, &sc->sc_dma_txdsc, 1355 IPW2200_TX_RING_SIZE * sizeof (struct ipw2200_tx_desc), 1356 DDI_DMA_WRITE, DDI_DMA_CONSISTENT); 1357 if (err != DDI_SUCCESS) 1358 goto fail0; 1359 /* 1360 * tx buffer array 1361 */ 1362 for (i = 0; i < IPW2200_TX_RING_SIZE; i++) { 1363 sc->sc_dma_txbufs[i].dr_name = "ipw2200-tx-buf"; 1364 err = ipw2200_dma_region_alloc(sc, &sc->sc_dma_txbufs[i], 1365 IPW2200_TXBUF_SIZE, DDI_DMA_WRITE, DDI_DMA_STREAMING); 1366 if (err != DDI_SUCCESS) { 1367 while (i >= 0) { 1368 ipw2200_dma_region_free(&sc->sc_dma_txbufs[i]); 1369 i--; 1370 } 1371 goto fail1; 1372 } 1373 } 1374 /* 1375 * rx buffer array 1376 */ 1377 for (i = 0; i < IPW2200_RX_RING_SIZE; i++) { 1378 sc->sc_dma_rxbufs[i].dr_name = "ipw2200-rx-buf"; 1379 err = ipw2200_dma_region_alloc(sc, &sc->sc_dma_rxbufs[i], 1380 IPW2200_RXBUF_SIZE, DDI_DMA_READ, DDI_DMA_STREAMING); 1381 if (err != DDI_SUCCESS) { 1382 while (i >= 0) { 1383 ipw2200_dma_region_free(&sc->sc_dma_rxbufs[i]); 1384 i--; 1385 } 1386 goto fail2; 1387 } 1388 } 1389 /* 1390 * cmd desc ring 1391 */ 1392 sc->sc_dma_cmdsc.dr_name = "ipw2200-cmd-desc-ring"; 1393 err = ipw2200_dma_region_alloc(sc, &sc->sc_dma_cmdsc, 1394 IPW2200_CMD_RING_SIZE * sizeof (struct ipw2200_cmd_desc), 1395 DDI_DMA_WRITE, DDI_DMA_CONSISTENT); 1396 if (err != DDI_SUCCESS) 1397 goto fail3; 1398 1399 return (DDI_SUCCESS); 1400 1401 fail3: 1402 for (i = 0; i < IPW2200_RX_RING_SIZE; i++) 1403 ipw2200_dma_region_free(&sc->sc_dma_rxbufs[i]); 1404 fail2: 1405 for (i = 0; i < IPW2200_TX_RING_SIZE; i++) 1406 ipw2200_dma_region_free(&sc->sc_dma_txbufs[i]); 1407 fail1: 1408 ipw2200_dma_region_free(&sc->sc_dma_txdsc); 1409 fail0: 1410 return (err); 1411 } 1412 1413 static void 1414 ipw2200_ring_free(struct ipw2200_softc *sc) 1415 { 1416 int i; 1417 1418 /* 1419 * tx ring desc 1420 */ 1421 ipw2200_dma_region_free(&sc->sc_dma_txdsc); 1422 /* 1423 * tx buf 1424 */ 1425 for (i = 0; i < IPW2200_TX_RING_SIZE; i++) 1426 ipw2200_dma_region_free(&sc->sc_dma_txbufs[i]); 1427 /* 1428 * rx buf 1429 */ 1430 for (i = 0; i < IPW2200_RX_RING_SIZE; i++) 1431 ipw2200_dma_region_free(&sc->sc_dma_rxbufs[i]); 1432 /* 1433 * command ring desc 1434 */ 1435 ipw2200_dma_region_free(&sc->sc_dma_cmdsc); 1436 } 1437 1438 static void 1439 ipw2200_ring_reset(struct ipw2200_softc *sc) 1440 { 1441 int i; 1442 1443 /* 1444 * tx desc ring & buffer array 1445 */ 1446 sc->sc_tx_cur = 0; 1447 sc->sc_tx_free = IPW2200_TX_RING_SIZE; 1448 sc->sc_txdsc = (struct ipw2200_tx_desc *)sc->sc_dma_txdsc.dr_base; 1449 for (i = 0; i < IPW2200_TX_RING_SIZE; i++) 1450 sc->sc_txbufs[i] = (uint8_t *)sc->sc_dma_txbufs[i].dr_base; 1451 /* 1452 * rx buffer array 1453 */ 1454 sc->sc_rx_cur = 0; 1455 sc->sc_rx_free = IPW2200_RX_RING_SIZE; 1456 for (i = 0; i < IPW2200_RX_RING_SIZE; i++) 1457 sc->sc_rxbufs[i] = (uint8_t *)sc->sc_dma_rxbufs[i].dr_base; 1458 1459 /* 1460 * command desc ring 1461 */ 1462 sc->sc_cmd_cur = 0; 1463 sc->sc_cmd_free = IPW2200_CMD_RING_SIZE; 1464 sc->sc_cmdsc = (struct ipw2200_cmd_desc *)sc->sc_dma_cmdsc.dr_base; 1465 } 1466 1467 /* 1468 * tx, rx rings and command initialization 1469 */ 1470 static int 1471 ipw2200_ring_init(struct ipw2200_softc *sc) 1472 { 1473 int err; 1474 1475 err = ipw2200_ring_alloc(sc); 1476 if (err != DDI_SUCCESS) 1477 return (err); 1478 1479 ipw2200_ring_reset(sc); 1480 1481 return (DDI_SUCCESS); 1482 } 1483 1484 static void 1485 ipw2200_ring_hwsetup(struct ipw2200_softc *sc) 1486 { 1487 int i; 1488 1489 /* 1490 * command desc ring 1491 */ 1492 ipw2200_csr_put32(sc, IPW2200_CSR_CMD_BASE, sc->sc_dma_cmdsc.dr_pbase); 1493 ipw2200_csr_put32(sc, IPW2200_CSR_CMD_SIZE, IPW2200_CMD_RING_SIZE); 1494 ipw2200_csr_put32(sc, IPW2200_CSR_CMD_WRITE_INDEX, sc->sc_cmd_cur); 1495 1496 /* 1497 * tx desc ring. only tx1 is used, tx2, tx3, and tx4 are unused 1498 */ 1499 ipw2200_csr_put32(sc, IPW2200_CSR_TX1_BASE, sc->sc_dma_txdsc.dr_pbase); 1500 ipw2200_csr_put32(sc, IPW2200_CSR_TX1_SIZE, IPW2200_TX_RING_SIZE); 1501 ipw2200_csr_put32(sc, IPW2200_CSR_TX1_WRITE_INDEX, sc->sc_tx_cur); 1502 1503 /* 1504 * tx2, tx3, tx4 is not used 1505 */ 1506 ipw2200_csr_put32(sc, IPW2200_CSR_TX2_BASE, sc->sc_dma_txdsc.dr_pbase); 1507 ipw2200_csr_put32(sc, IPW2200_CSR_TX2_SIZE, IPW2200_TX_RING_SIZE); 1508 ipw2200_csr_put32(sc, IPW2200_CSR_TX2_READ_INDEX, 0); 1509 ipw2200_csr_put32(sc, IPW2200_CSR_TX2_WRITE_INDEX, 0); 1510 ipw2200_csr_put32(sc, IPW2200_CSR_TX3_BASE, sc->sc_dma_txdsc.dr_pbase); 1511 ipw2200_csr_put32(sc, IPW2200_CSR_TX3_SIZE, IPW2200_TX_RING_SIZE); 1512 ipw2200_csr_put32(sc, IPW2200_CSR_TX3_READ_INDEX, 0); 1513 ipw2200_csr_put32(sc, IPW2200_CSR_TX3_WRITE_INDEX, 0); 1514 ipw2200_csr_put32(sc, IPW2200_CSR_TX4_BASE, sc->sc_dma_txdsc.dr_pbase); 1515 ipw2200_csr_put32(sc, IPW2200_CSR_TX4_SIZE, IPW2200_TX_RING_SIZE); 1516 ipw2200_csr_put32(sc, IPW2200_CSR_TX4_READ_INDEX, 0); 1517 ipw2200_csr_put32(sc, IPW2200_CSR_TX4_WRITE_INDEX, 0); 1518 1519 /* 1520 * rx buffer ring 1521 */ 1522 for (i = 0; i < IPW2200_RX_RING_SIZE; i++) 1523 ipw2200_csr_put32(sc, IPW2200_CSR_RX_BASE + i * 4, 1524 sc->sc_dma_rxbufs[i].dr_pbase); 1525 /* 1526 * all rx buffer are empty, rx-rd-index == 0 && rx-wr-index == N-1 1527 */ 1528 ipw2200_csr_put32(sc, IPW2200_CSR_RX_WRITE_INDEX, 1529 RING_BACKWARD(sc->sc_rx_cur, 1, IPW2200_RX_RING_SIZE)); 1530 } 1531 1532 int 1533 ipw2200_start_scan(struct ipw2200_softc *sc) 1534 { 1535 struct ieee80211com *ic = &sc->sc_ic; 1536 struct ipw2200_scan scan; 1537 uint8_t *ch; 1538 int cnt, i; 1539 1540 IPW2200_DBG(IPW2200_DBG_SCAN, (sc->sc_dip, CE_CONT, 1541 "ipw2200_start_scan(): start scanning \n")); 1542 1543 /* 1544 * start scanning 1545 */ 1546 sc->sc_flags |= IPW2200_FLAG_SCANNING; 1547 1548 (void) memset(&scan, 0, sizeof (scan)); 1549 scan.type = (ic->ic_des_esslen != 0) ? IPW2200_SCAN_TYPE_BDIRECTED : 1550 IPW2200_SCAN_TYPE_BROADCAST; 1551 scan.dwelltime = LE_16(40); /* The interval is set up to 40 */ 1552 1553 /* 1554 * Compact supported channel number(5G) into a single buffer 1555 */ 1556 ch = scan.channels; 1557 cnt = 0; 1558 for (i = 0; i <= IEEE80211_CHAN_MAX; i++) { 1559 if (IEEE80211_IS_CHAN_5GHZ(&ic->ic_sup_channels[i]) && 1560 isset(ic->ic_chan_active, i)) { 1561 *++ch = (uint8_t)i; 1562 cnt++; 1563 } 1564 } 1565 *(ch - cnt) = IPW2200_CHAN_5GHZ | (uint8_t)cnt; 1566 ch = (cnt > 0) ? (ch + 1) : (scan.channels); 1567 1568 /* 1569 * Compact supported channel number(2G) into a single buffer 1570 */ 1571 cnt = 0; 1572 for (i = 0; i <= IEEE80211_CHAN_MAX; i++) { 1573 if (IEEE80211_IS_CHAN_2GHZ(&ic->ic_sup_channels[i]) && 1574 isset(ic->ic_chan_active, i)) { 1575 *++ch = (uint8_t)i; 1576 cnt++; 1577 } 1578 } 1579 *(ch - cnt) = IPW2200_CHAN_2GHZ | cnt; 1580 1581 return (ipw2200_cmd(sc, IPW2200_CMD_SCAN, &scan, sizeof (scan), 1)); 1582 } 1583 1584 int 1585 ipw2200_auth_and_assoc(struct ipw2200_softc *sc) 1586 { 1587 struct ieee80211com *ic = &sc->sc_ic; 1588 struct ieee80211_node *in = ic->ic_bss; 1589 struct ipw2200_configuration cfg; 1590 struct ipw2200_rateset rs; 1591 struct ipw2200_associate assoc; 1592 uint32_t data; 1593 int err; 1594 uint8_t *wpa_level; 1595 1596 if (sc->sc_flags & IPW2200_FLAG_ASSOCIATED) { 1597 /* already associated */ 1598 return (-1); 1599 } 1600 1601 /* 1602 * set the confiuration 1603 */ 1604 if (IEEE80211_IS_CHAN_2GHZ(in->in_chan)) { 1605 /* enable b/g auto-detection */ 1606 (void) memset(&cfg, 0, sizeof (cfg)); 1607 cfg.bluetooth_coexistence = 1; 1608 cfg.multicast_enabled = 1; 1609 cfg.use_protection = 1; 1610 cfg.answer_pbreq = 1; 1611 cfg.noise_reported = 1; 1612 cfg.disable_multicast_decryption = 1; /* WPA */ 1613 cfg.disable_unicast_decryption = 1; /* WPA */ 1614 err = ipw2200_cmd(sc, IPW2200_CMD_SET_CONFIG, 1615 &cfg, sizeof (cfg), 1); 1616 if (err != DDI_SUCCESS) 1617 return (err); 1618 } 1619 1620 /* 1621 * set the essid, may be null/hidden AP 1622 */ 1623 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 1624 "ipw2200_auth_and_assoc(): " 1625 "setting ESSID to(%u),%c%c%c%c%c%c%c%c\n", 1626 in->in_esslen, 1627 in->in_essid[0], in->in_essid[1], 1628 in->in_essid[2], in->in_essid[3], 1629 in->in_essid[4], in->in_essid[5], 1630 in->in_essid[6], in->in_essid[7])); 1631 err = ipw2200_cmd(sc, IPW2200_CMD_SET_ESSID, in->in_essid, 1632 in->in_esslen, 1); 1633 if (err != DDI_SUCCESS) 1634 return (err); 1635 1636 /* 1637 * set the rate: the rate set has already been ''negocitated'' 1638 */ 1639 rs.mode = IEEE80211_IS_CHAN_5GHZ(in->in_chan) ? 1640 IPW2200_MODE_11A : IPW2200_MODE_11G; 1641 rs.type = IPW2200_RATESET_TYPE_NEGOCIATED; 1642 rs.nrates = in->in_rates.ir_nrates; 1643 (void) memcpy(rs.rates, in->in_rates.ir_rates, in->in_rates.ir_nrates); 1644 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 1645 "ipw2200_auth_and_assoc(): " 1646 "setting negotiated rates to(nrates = %u)\n", rs.nrates)); 1647 err = ipw2200_cmd(sc, IPW2200_CMD_SET_RATES, &rs, sizeof (rs), 1); 1648 if (err != DDI_SUCCESS) 1649 return (err); 1650 1651 /* 1652 * invoke command associate 1653 */ 1654 (void) memset(&assoc, 0, sizeof (assoc)); 1655 1656 /* 1657 * set opt_ie to h/w if associated is WPA, opt_ie has been verified 1658 * by net80211 kernel module. 1659 */ 1660 if (ic->ic_opt_ie != NULL) { 1661 1662 wpa_level = (uint8_t *)ic->ic_opt_ie; 1663 1664 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 1665 "ipw2200_auth_and_assoc(): " 1666 "set wpa_ie and wpa_ie_len to h/w. " 1667 "length is %d\n" 1668 "opt_ie[0] = %02X - element vendor\n" 1669 "opt_ie[1] = %02X - length\n" 1670 "opt_ie[2,3,4] = %02X %02X %02X - oui\n" 1671 "opt_ie[5] = %02X - oui type\n" 1672 "opt_ie[6,7] = %02X %02X - spec version \n" 1673 "opt_ie[8,9,10,11] = %02X %02X %02X %02X - gk cipher\n" 1674 "opt_ie[12,13] = %02X %02X - pairwise key cipher(1)\n" 1675 "opt_ie[14,15,16,17] = %02X %02X %02X %02X - ciphers\n" 1676 "opt_ie[18,19] = %02X %02X - authselcont(1) \n" 1677 "opt_ie[20,21,22,23] = %02X %02X %02X %02X - authsels\n", 1678 wpa_level[1], wpa_level[0], wpa_level[1], 1679 wpa_level[2], wpa_level[3], wpa_level[4], 1680 wpa_level[5], wpa_level[6], wpa_level[7], 1681 wpa_level[8], wpa_level[9], wpa_level[10], 1682 wpa_level[11], wpa_level[12], wpa_level[13], 1683 wpa_level[14], wpa_level[15], wpa_level[16], 1684 wpa_level[17], wpa_level[18], wpa_level[19], 1685 wpa_level[20], wpa_level[21], wpa_level[22], 1686 wpa_level[23])); 1687 1688 err = ipw2200_cmd(sc, IPW2200_CMD_SET_OPTIE, 1689 ic->ic_opt_ie, ic->ic_opt_ie_len, 1); 1690 if (err != DDI_SUCCESS) 1691 return (err); 1692 } 1693 1694 /* 1695 * set the sensitive 1696 */ 1697 data = LE_32(in->in_rssi); 1698 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 1699 "ipw2200_auth_and_assoc(): " 1700 "setting sensitivity to rssi:(%u)\n", (uint8_t)in->in_rssi)); 1701 err = ipw2200_cmd(sc, IPW2200_CMD_SET_SENSITIVITY, 1702 &data, sizeof (data), 1); 1703 if (err != DDI_SUCCESS) 1704 return (err); 1705 1706 /* 1707 * set mode and channel for assocation command 1708 */ 1709 assoc.mode = IEEE80211_IS_CHAN_5GHZ(in->in_chan) ? 1710 IPW2200_MODE_11A : IPW2200_MODE_11G; 1711 assoc.chan = ieee80211_chan2ieee(ic, in->in_chan); 1712 1713 /* 1714 * use the value set to ic_bss to retraive current sharedmode 1715 */ 1716 if (ic->ic_bss->in_authmode == WL_SHAREDKEY) { 1717 assoc.auth = (ic->ic_def_txkey << 4) | IPW2200_AUTH_SHARED; 1718 IPW2200_DBG(IPW2200_DBG_IOCTL, (sc->sc_dip, CE_CONT, 1719 "ipw2200_auth_and_assoc(): " 1720 "associate to shared key mode, set thru. ioctl")); 1721 } 1722 1723 if (ic->ic_flags & IEEE80211_F_WPA) 1724 assoc.policy = LE_16(IPW2200_POLICY_WPA); /* RSN/WPA active */ 1725 (void) memcpy(assoc.tstamp, in->in_tstamp.data, 8); 1726 assoc.capinfo = LE_16(in->in_capinfo); 1727 assoc.lintval = LE_16(ic->ic_lintval); 1728 assoc.intval = LE_16(in->in_intval); 1729 IEEE80211_ADDR_COPY(assoc.bssid, in->in_bssid); 1730 if (ic->ic_opmode == IEEE80211_M_IBSS) 1731 IEEE80211_ADDR_COPY(assoc.dst, ipw2200_broadcast_addr); 1732 else 1733 IEEE80211_ADDR_COPY(assoc.dst, in->in_bssid); 1734 1735 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 1736 "ipw2200_auth_and_assoc(): " 1737 "associate to bssid(%2x:%2x:%2x:%2x:%2x:%2x:), " 1738 "chan(%u), auth(%u)\n", 1739 assoc.bssid[0], assoc.bssid[1], assoc.bssid[2], 1740 assoc.bssid[3], assoc.bssid[4], assoc.bssid[5], 1741 assoc.chan, assoc.auth)); 1742 return (ipw2200_cmd(sc, IPW2200_CMD_ASSOCIATE, 1743 &assoc, sizeof (assoc), 1)); 1744 } 1745 1746 /* 1747 * Send the dis-association command to h/w, will receive notification to claim 1748 * the connection is dis-associated. So, it's not marked as disassociated this 1749 * moment. 1750 */ 1751 static int 1752 ipw2200_disassoc(struct ipw2200_softc *sc) 1753 { 1754 struct ipw2200_associate assoc; 1755 assoc.type = 2; 1756 return (ipw2200_cmd(sc, IPW2200_CMD_ASSOCIATE, &assoc, 1757 sizeof (assoc), 1)); 1758 } 1759 1760 /* ARGSUSED */ 1761 static int 1762 ipw2200_newstate(struct ieee80211com *ic, enum ieee80211_state state, int arg) 1763 { 1764 struct ipw2200_softc *sc = (struct ipw2200_softc *)ic; 1765 wifi_data_t wd = { 0 }; 1766 1767 switch (state) { 1768 case IEEE80211_S_SCAN: 1769 if (!(sc->sc_flags & IPW2200_FLAG_SCANNING)) { 1770 ic->ic_flags |= IEEE80211_F_SCAN | IEEE80211_F_ASCAN; 1771 (void) ipw2200_start_scan(sc); 1772 } 1773 break; 1774 case IEEE80211_S_AUTH: 1775 /* 1776 * The firmware will fail if we are already associated 1777 */ 1778 if (sc->sc_flags & IPW2200_FLAG_ASSOCIATED) 1779 (void) ipw2200_disassoc(sc); 1780 (void) ipw2200_auth_and_assoc(sc); 1781 break; 1782 case IEEE80211_S_RUN: 1783 /* 1784 * We can send data now; update the fastpath with our 1785 * current associated BSSID and other relevant settings. 1786 */ 1787 wd.wd_secalloc = ieee80211_crypto_getciphertype(ic); 1788 wd.wd_opmode = ic->ic_opmode; 1789 IEEE80211_ADDR_COPY(wd.wd_bssid, ic->ic_bss->in_bssid); 1790 (void) mac_pdata_update(ic->ic_mach, &wd, sizeof (wd)); 1791 break; 1792 case IEEE80211_S_ASSOC: 1793 case IEEE80211_S_INIT: 1794 break; 1795 } 1796 1797 /* 1798 * notify to update the link, and WPA 1799 */ 1800 if ((ic->ic_state != IEEE80211_S_RUN) && (state == IEEE80211_S_RUN)) { 1801 ieee80211_notify_node_join(ic, ic->ic_bss); 1802 } else if ((ic->ic_state == IEEE80211_S_RUN) && 1803 (state != IEEE80211_S_RUN)) { 1804 ieee80211_notify_node_leave(ic, ic->ic_bss); 1805 } 1806 1807 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 1808 "ipw2200_newstat(): %s -> %s\n", 1809 ieee80211_state_name[ic->ic_state], 1810 ieee80211_state_name[state])); 1811 1812 ic->ic_state = state; 1813 return (DDI_SUCCESS); 1814 } 1815 /* 1816 * GLD operations 1817 */ 1818 /* ARGSUSED */ 1819 static int 1820 ipw2200_m_stat(void *arg, uint_t stat, uint64_t *val) 1821 { 1822 ieee80211com_t *ic = (ieee80211com_t *)arg; 1823 struct ipw2200_softc *sc = (struct ipw2200_softc *)ic; 1824 1825 IPW2200_DBG(IPW2200_DBG_GLD, (((struct ipw2200_softc *)arg)->sc_dip, 1826 CE_CONT, 1827 "ipw2200_m_stat(): enter\n")); 1828 /* 1829 * Some of below statistic data are from hardware, some from net80211 1830 */ 1831 switch (stat) { 1832 case MAC_STAT_NOXMTBUF: 1833 *val = ic->ic_stats.is_tx_nobuf; 1834 break; 1835 case MAC_STAT_IERRORS: 1836 *val = sc->sc_stats.sc_rx_len_err; 1837 break; 1838 case MAC_STAT_OERRORS: 1839 *val = sc->sc_stats.sc_tx_discard + 1840 sc->sc_stats.sc_tx_alloc_fail + 1841 sc->sc_stats.sc_tx_encap_fail + 1842 sc->sc_stats.sc_tx_crypto_fail; 1843 break; 1844 case MAC_STAT_RBYTES: 1845 *val = ic->ic_stats.is_rx_bytes; 1846 break; 1847 case MAC_STAT_IPACKETS: 1848 *val = ic->ic_stats.is_rx_frags; 1849 break; 1850 case MAC_STAT_OBYTES: 1851 *val = ic->ic_stats.is_tx_bytes; 1852 break; 1853 case MAC_STAT_OPACKETS: 1854 *val = ic->ic_stats.is_tx_frags; 1855 break; 1856 /* 1857 * Get below from hardware statistic, retraive net80211 value once 1s 1858 */ 1859 case WIFI_STAT_TX_FRAGS: 1860 case WIFI_STAT_MCAST_TX: 1861 case WIFI_STAT_TX_FAILED: 1862 case WIFI_STAT_TX_RETRANS: 1863 /* 1864 * Get blow information from net80211 1865 */ 1866 case WIFI_STAT_RTS_SUCCESS: 1867 case WIFI_STAT_RTS_FAILURE: 1868 case WIFI_STAT_ACK_FAILURE: 1869 case WIFI_STAT_RX_FRAGS: 1870 case WIFI_STAT_MCAST_RX: 1871 case WIFI_STAT_RX_DUPS: 1872 case WIFI_STAT_FCS_ERRORS: 1873 case WIFI_STAT_WEP_ERRORS: 1874 return (ieee80211_stat(ic, stat, val)); 1875 /* 1876 * Need be supported later 1877 */ 1878 case MAC_STAT_IFSPEED: 1879 default: 1880 return (ENOTSUP); 1881 } 1882 return (0); 1883 } 1884 1885 /* ARGSUSED */ 1886 static int 1887 ipw2200_m_multicst(void *arg, boolean_t add, const uint8_t *mca) 1888 { 1889 /* not supported */ 1890 IPW2200_DBG(IPW2200_DBG_GLD, (((struct ipw2200_softc *)arg)->sc_dip, 1891 CE_CONT, 1892 "ipw2200_m_multicst(): enter\n")); 1893 1894 return (0); 1895 } 1896 1897 /* 1898 * Multithread handler for linkstatus, fatal error recovery, get statistic 1899 */ 1900 static void 1901 ipw2200_thread(struct ipw2200_softc *sc) 1902 { 1903 struct ieee80211com *ic = &sc->sc_ic; 1904 enum ieee80211_state ostate; 1905 int32_t nlstate; 1906 int stat_cnt = 0; 1907 1908 IPW2200_DBG(IPW2200_DBG_SOFTINT, (sc->sc_dip, CE_CONT, 1909 "ipw2200_thread(): enter, linkstate %d\n", sc->sc_linkstate)); 1910 1911 mutex_enter(&sc->sc_mflock); 1912 1913 while (sc->sc_mfthread_switch) { 1914 /* 1915 * when radio is off or SUSPEND status, nothing to do 1916 */ 1917 if ((ipw2200_radio_status(sc) == 0) || 1918 sc->sc_flags & IPW2200_FLAG_SUSPEND) { 1919 goto wait_loop; 1920 } 1921 1922 /* 1923 * notify the link state 1924 */ 1925 if (ic->ic_mach && (sc->sc_flags & IPW2200_FLAG_LINK_CHANGE)) { 1926 1927 IPW2200_DBG(IPW2200_DBG_SOFTINT, (sc->sc_dip, CE_CONT, 1928 "ipw2200_thread(): link status --> %d\n", 1929 sc->sc_linkstate)); 1930 1931 sc->sc_flags &= ~IPW2200_FLAG_LINK_CHANGE; 1932 nlstate = sc->sc_linkstate; 1933 1934 mutex_exit(&sc->sc_mflock); 1935 mac_link_update(ic->ic_mach, nlstate); 1936 mutex_enter(&sc->sc_mflock); 1937 } 1938 1939 /* 1940 * recovery fatal error 1941 */ 1942 if (ic->ic_mach && 1943 (sc->sc_flags & IPW2200_FLAG_HW_ERR_RECOVER)) { 1944 1945 IPW2200_DBG(IPW2200_DBG_FATAL, (sc->sc_dip, CE_CONT, 1946 "ipw2200_thread(): " 1947 "try to recover fatal hw error\n")); 1948 1949 sc->sc_flags &= ~IPW2200_FLAG_HW_ERR_RECOVER; 1950 mutex_exit(&sc->sc_mflock); 1951 1952 /* stop again */ 1953 ostate = ic->ic_state; 1954 (void) ipw2200_init(sc); /* Force state machine */ 1955 1956 /* 1957 * workround. Delay for a while after init especially 1958 * when something wrong happened already. 1959 */ 1960 delay(drv_usectohz(delay_fatal_recover)); 1961 1962 /* 1963 * Init scan will recovery the original connection if 1964 * the original state is run 1965 */ 1966 if (ostate != IEEE80211_S_INIT) 1967 ieee80211_begin_scan(ic, 0); 1968 1969 mutex_enter(&sc->sc_mflock); 1970 } 1971 1972 /* 1973 * get statistic, the value will be retrieved by m_stat 1974 */ 1975 if (stat_cnt == 10) { 1976 1977 stat_cnt = 0; /* re-start */ 1978 mutex_exit(&sc->sc_mflock); 1979 ipw2200_get_statistics(sc); 1980 mutex_enter(&sc->sc_mflock); 1981 1982 } else 1983 stat_cnt++; /* until 1s */ 1984 1985 wait_loop: 1986 mutex_exit(&sc->sc_mflock); 1987 delay(drv_usectohz(delay_aux_thread)); 1988 mutex_enter(&sc->sc_mflock); 1989 1990 } 1991 sc->sc_mf_thread = NULL; 1992 cv_signal(&sc->sc_mfthread_cv); 1993 mutex_exit(&sc->sc_mflock); 1994 } 1995 1996 static int 1997 ipw2200_m_start(void *arg) 1998 { 1999 struct ipw2200_softc *sc = (struct ipw2200_softc *)arg; 2000 struct ieee80211com *ic = &sc->sc_ic; 2001 2002 IPW2200_DBG(IPW2200_DBG_GLD, (sc->sc_dip, CE_CONT, 2003 "ipw2200_m_start(): enter\n")); 2004 /* 2005 * initialize ipw2200 hardware, everything ok will start scan 2006 */ 2007 (void) ipw2200_init(sc); 2008 2009 /* 2010 * set the state machine to INIT 2011 */ 2012 ieee80211_new_state(ic, IEEE80211_S_INIT, -1); 2013 2014 sc->sc_flags |= IPW2200_FLAG_RUNNING; 2015 2016 /* 2017 * fix KCF bug. - workaround, need to fix it in net80211 2018 */ 2019 (void) crypto_mech2id(SUN_CKM_RC4); 2020 2021 return (0); 2022 } 2023 2024 static void 2025 ipw2200_m_stop(void *arg) 2026 { 2027 struct ipw2200_softc *sc = (struct ipw2200_softc *)arg; 2028 struct ieee80211com *ic = &sc->sc_ic; 2029 2030 IPW2200_DBG(IPW2200_DBG_GLD, (sc->sc_dip, CE_CONT, 2031 "ipw2200_m_stop(): enter\n")); 2032 2033 ipw2200_stop(sc); 2034 /* 2035 * set the state machine to INIT 2036 */ 2037 ieee80211_new_state(ic, IEEE80211_S_INIT, -1); 2038 2039 sc->sc_flags &= ~IPW2200_FLAG_RUNNING; 2040 } 2041 2042 static int 2043 ipw2200_m_unicst(void *arg, const uint8_t *macaddr) 2044 { 2045 struct ipw2200_softc *sc = (struct ipw2200_softc *)arg; 2046 struct ieee80211com *ic = &sc->sc_ic; 2047 int err; 2048 2049 IPW2200_DBG(IPW2200_DBG_GLD, (sc->sc_dip, CE_CONT, 2050 "ipw2200_m_unicst(): enter\n")); 2051 2052 IPW2200_DBG(IPW2200_DBG_GLD, (sc->sc_dip, CE_CONT, 2053 "ipw2200_m_unicst(): GLD setting MAC address to " 2054 "%02x:%02x:%02x:%02x:%02x:%02x\n", 2055 macaddr[0], macaddr[1], macaddr[2], 2056 macaddr[3], macaddr[4], macaddr[5])); 2057 2058 if (!IEEE80211_ADDR_EQ(ic->ic_macaddr, macaddr)) { 2059 2060 IEEE80211_ADDR_COPY(ic->ic_macaddr, macaddr); 2061 2062 if (sc->sc_flags & IPW2200_FLAG_RUNNING) { 2063 err = ipw2200_config(sc); 2064 if (err != DDI_SUCCESS) { 2065 IPW2200_WARN((sc->sc_dip, CE_WARN, 2066 "ipw2200_m_unicst(): " 2067 "device configuration failed\n")); 2068 goto fail; 2069 } 2070 } 2071 } 2072 return (0); 2073 fail: 2074 return (EIO); 2075 } 2076 2077 static int 2078 ipw2200_m_promisc(void *arg, boolean_t on) 2079 { 2080 /* not supported */ 2081 struct ipw2200_softc *sc = (struct ipw2200_softc *)arg; 2082 2083 IPW2200_DBG(IPW2200_DBG_GLD, (sc->sc_dip, CE_CONT, 2084 "ipw2200_m_promisc(): enter. " 2085 "GLD setting promiscuous mode - %d\n", on)); 2086 2087 return (0); 2088 } 2089 2090 static mblk_t * 2091 ipw2200_m_tx(void *arg, mblk_t *mp) 2092 { 2093 struct ipw2200_softc *sc = (struct ipw2200_softc *)arg; 2094 struct ieee80211com *ic = &sc->sc_ic; 2095 mblk_t *next; 2096 2097 /* 2098 * when driver in on suspend state, freemsgchain directly 2099 */ 2100 if (sc->sc_flags & IPW2200_FLAG_SUSPEND) { 2101 IPW2200_DBG(IPW2200_DBG_SUSPEND, (sc->sc_dip, CE_CONT, 2102 "ipw2200_m_tx(): suspend status, discard msg\n")); 2103 sc->sc_stats.sc_tx_discard++; /* discard data */ 2104 freemsgchain(mp); 2105 return (NULL); 2106 } 2107 2108 /* 2109 * No data frames go out unless we're associated; this 2110 * should not happen as the 802.11 layer does not enable 2111 * the xmit queue until we enter the RUN state. 2112 */ 2113 if (ic->ic_state != IEEE80211_S_RUN) { 2114 IPW2200_DBG(IPW2200_DBG_GLD, (sc->sc_dip, CE_CONT, 2115 "ipw2200_m_tx(): discard msg, ic_state = %u\n", 2116 ic->ic_state)); 2117 sc->sc_stats.sc_tx_discard++; /* discard data */ 2118 freemsgchain(mp); 2119 return (NULL); 2120 } 2121 2122 while (mp != NULL) { 2123 next = mp->b_next; 2124 mp->b_next = NULL; 2125 if (ipw2200_send(ic, mp, IEEE80211_FC0_TYPE_DATA) == 2126 ENOMEM) { 2127 mp->b_next = next; 2128 break; 2129 } 2130 mp = next; 2131 } 2132 return (mp); 2133 } 2134 2135 /* 2136 * ipw2200_send(): send data. softway to handle crypto_encap. 2137 */ 2138 static int 2139 ipw2200_send(ieee80211com_t *ic, mblk_t *mp, uint8_t type) 2140 { 2141 struct ipw2200_softc *sc = (struct ipw2200_softc *)ic; 2142 struct ieee80211_node *in; 2143 struct ieee80211_frame *wh; 2144 struct ieee80211_key *k; 2145 mblk_t *m0, *m; 2146 size_t cnt, off; 2147 struct ipw2200_tx_desc *txdsc; 2148 struct dma_region *dr; 2149 uint32_t idx; 2150 int err = DDI_SUCCESS; 2151 /* tmp pointer, used to pack header and payload */ 2152 uint8_t *p; 2153 2154 ASSERT(mp->b_next == NULL); 2155 IPW2200_DBG(IPW2200_DBG_GLD, (sc->sc_dip, CE_CONT, 2156 "ipw2200_send(): enter\n")); 2157 2158 if ((type & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_DATA) { 2159 /* 2160 * skip all management frames since ipw2200 won't generate any 2161 * management frames. Therefore, drop this package. 2162 */ 2163 freemsg(mp); 2164 err = DDI_FAILURE; 2165 goto fail0; 2166 } 2167 2168 mutex_enter(&sc->sc_tx_lock); 2169 if (sc->sc_flags & IPW2200_FLAG_SUSPEND) { 2170 /* 2171 * when sending data, system runs into suspend status, 2172 * return fail directly 2173 */ 2174 err = ENXIO; 2175 goto fail0; 2176 } 2177 2178 /* 2179 * need 1 empty descriptor 2180 */ 2181 if (sc->sc_tx_free <= IPW2200_TX_RING_MIN) { 2182 mutex_enter(&sc->sc_resched_lock); 2183 IPW2200_DBG(IPW2200_DBG_RING, (sc->sc_dip, CE_WARN, 2184 "ipw2200_send(): no enough descriptors(%d)\n", 2185 sc->sc_tx_free)); 2186 ic->ic_stats.is_tx_nobuf++; /* no enough buffer */ 2187 sc->sc_flags |= IPW2200_FLAG_TX_SCHED; 2188 err = ENOMEM; 2189 mutex_exit(&sc->sc_resched_lock); 2190 goto fail1; 2191 } 2192 IPW2200_DBG(IPW2200_DBG_RING, (sc->sc_dip, CE_CONT, 2193 "ipw2200_send(): tx-free=%d,tx-curr=%d\n", 2194 sc->sc_tx_free, sc->sc_tx_cur)); 2195 2196 /* 2197 * put the mp into one blk, and use it to do the crypto_encap 2198 * if necessaary. 2199 */ 2200 m = allocb(msgdsize(mp) + 32, BPRI_MED); 2201 if (m == NULL) { /* can not alloc buf, drop this package */ 2202 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 2203 "ipw2200_send(): msg allocation failed\n")); 2204 freemsg(mp); 2205 sc->sc_stats.sc_tx_alloc_fail++; /* alloc fail */ 2206 ic->ic_stats.is_tx_failed++; /* trans failed */ 2207 err = DDI_FAILURE; 2208 goto fail1; 2209 } 2210 for (off = 0, m0 = mp; m0 != NULL; m0 = m0->b_cont) { 2211 cnt = MBLKL(m0); 2212 (void) memcpy(m->b_rptr + off, m0->b_rptr, cnt); 2213 off += cnt; 2214 } 2215 m->b_wptr += off; 2216 2217 /* 2218 * find tx_node, and encapsulate the data 2219 */ 2220 wh = (struct ieee80211_frame *)m->b_rptr; 2221 in = ieee80211_find_txnode(ic, wh->i_addr1); 2222 if (in == NULL) { /* can not find the tx node, drop the package */ 2223 sc->sc_stats.sc_tx_encap_fail++; /* tx encap fail */ 2224 ic->ic_stats.is_tx_failed++; /* trans failed */ 2225 freemsg(mp); 2226 err = DDI_FAILURE; 2227 goto fail2; 2228 } 2229 in->in_inact = 0; 2230 2231 (void) ieee80211_encap(ic, m, in); 2232 ieee80211_free_node(in); 2233 2234 if (wh->i_fc[1] & IEEE80211_FC1_WEP) { 2235 k = ieee80211_crypto_encap(ic, m); 2236 if (k == NULL) { /* can not get the key, drop packages */ 2237 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 2238 "ipw2200_send(): " 2239 "Encrypting 802.11 frame failed\n")); 2240 sc->sc_stats.sc_tx_crypto_fail++; /* tx encap fail */ 2241 ic->ic_stats.is_tx_failed++; /* trans failed */ 2242 freemsg(mp); 2243 err = DDI_FAILURE; 2244 goto fail2; 2245 } 2246 wh = (struct ieee80211_frame *)m->b_rptr; 2247 } 2248 2249 /* 2250 * get txdsc 2251 */ 2252 idx = sc->sc_tx_cur; 2253 txdsc = &sc->sc_txdsc[idx]; 2254 (void) memset(txdsc, 0, sizeof (*txdsc)); 2255 /* 2256 * extract header from message 2257 */ 2258 p = (uint8_t *)&txdsc->wh; 2259 off = sizeof (struct ieee80211_frame); 2260 (void) memcpy(p, m->b_rptr, off); 2261 /* 2262 * extract payload from message 2263 */ 2264 dr = &sc->sc_dma_txbufs[idx]; 2265 p = sc->sc_txbufs[idx]; 2266 cnt = MBLKL(m); 2267 (void) memcpy(p, m->b_rptr + off, cnt - off); 2268 cnt -= off; 2269 2270 txdsc->hdr.type = IPW2200_HDR_TYPE_DATA; 2271 txdsc->hdr.flags = IPW2200_HDR_FLAG_IRQ; 2272 txdsc->cmd = IPW2200_DATA_CMD_TX; 2273 txdsc->len = LE_16(cnt); 2274 txdsc->flags = 0; 2275 2276 if (ic->ic_opmode == IEEE80211_M_IBSS) { 2277 if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) 2278 txdsc->flags |= IPW2200_DATA_FLAG_NEED_ACK; 2279 } else if (!IEEE80211_IS_MULTICAST(wh->i_addr3)) 2280 txdsc->flags |= IPW2200_DATA_FLAG_NEED_ACK; 2281 2282 /* always set it to none wep, because it's handled by software */ 2283 txdsc->flags |= IPW2200_DATA_FLAG_NO_WEP; 2284 2285 if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) 2286 txdsc->flags |= IPW2200_DATA_FLAG_SHPREAMBLE; 2287 2288 txdsc->nseg = LE_32(1); 2289 txdsc->seg_addr[0] = LE_32(dr->dr_pbase); 2290 txdsc->seg_len[0] = LE_32(cnt); 2291 2292 /* 2293 * DMA sync: buffer and desc 2294 */ 2295 (void) ddi_dma_sync(dr->dr_hnd, 0, 2296 IPW2200_TXBUF_SIZE, DDI_DMA_SYNC_FORDEV); 2297 (void) ddi_dma_sync(sc->sc_dma_txdsc.dr_hnd, 2298 idx * sizeof (struct ipw2200_tx_desc), 2299 sizeof (struct ipw2200_tx_desc), DDI_DMA_SYNC_FORDEV); 2300 2301 sc->sc_tx_cur = RING_FORWARD(sc->sc_tx_cur, 1, IPW2200_TX_RING_SIZE); 2302 sc->sc_tx_free--; 2303 2304 /* 2305 * update txcur 2306 */ 2307 ipw2200_csr_put32(sc, IPW2200_CSR_TX1_WRITE_INDEX, sc->sc_tx_cur); 2308 2309 /* 2310 * success, free the original message 2311 */ 2312 if (mp) 2313 freemsg(mp); 2314 fail2: 2315 if (m) 2316 freemsg(m); 2317 fail1: 2318 mutex_exit(&sc->sc_tx_lock); 2319 fail0: 2320 IPW2200_DBG(IPW2200_DBG_GLD, (sc->sc_dip, CE_CONT, 2321 "ipw2200_send(): exit - err=%d\n", err)); 2322 2323 return (err); 2324 } 2325 2326 /* 2327 * IOCTL handlers 2328 */ 2329 #define IEEE80211_IOCTL_REQUIRED (1) 2330 #define IEEE80211_IOCTL_NOT_REQUIRED (0) 2331 static void 2332 ipw2200_m_ioctl(void *arg, queue_t *q, mblk_t *m) 2333 { 2334 struct ipw2200_softc *sc = (struct ipw2200_softc *)arg; 2335 struct ieee80211com *ic = &sc->sc_ic; 2336 uint32_t err; 2337 2338 IPW2200_DBG(IPW2200_DBG_GLD, (sc->sc_dip, CE_CONT, 2339 "ipw2200_m_ioctl(): enter\n")); 2340 2341 /* 2342 * Check whether or not need to handle this in net80211 2343 * 2344 */ 2345 if (ipw2200_ioctl(sc, q, m) == IEEE80211_IOCTL_NOT_REQUIRED) 2346 return; 2347 2348 err = ieee80211_ioctl(ic, q, m); 2349 if (err == ENETRESET) { 2350 if (sc->sc_flags & IPW2200_FLAG_RUNNING) { 2351 (void) ipw2200_m_start(sc); 2352 (void) ieee80211_new_state(ic, 2353 IEEE80211_S_SCAN, -1); 2354 } 2355 } 2356 if (err == ERESTART) { 2357 if (sc->sc_flags & IPW2200_FLAG_RUNNING) 2358 (void) ipw2200_chip_reset(sc); 2359 } 2360 } 2361 static int 2362 ipw2200_ioctl(struct ipw2200_softc *sc, queue_t *q, mblk_t *m) 2363 { 2364 struct iocblk *iocp; 2365 uint32_t len, ret, cmd, mblen; 2366 mblk_t *m0; 2367 boolean_t need_privilege; 2368 boolean_t need_net80211; 2369 2370 mblen = MBLKL(m); 2371 if (mblen < sizeof (struct iocblk)) { 2372 IPW2200_DBG(IPW2200_DBG_IOCTL, (sc->sc_dip, CE_CONT, 2373 "ipw2200_ioctl(): ioctl buffer too short, %u\n", 2374 mblen)); 2375 miocnak(q, m, 0, EINVAL); 2376 /* 2377 * Buf not enough, do not need net80211 either 2378 */ 2379 return (IEEE80211_IOCTL_NOT_REQUIRED); 2380 } 2381 2382 /* 2383 * Validate the command 2384 */ 2385 iocp = (struct iocblk *)(uintptr_t)m->b_rptr; 2386 iocp->ioc_error = 0; 2387 cmd = iocp->ioc_cmd; 2388 need_privilege = B_TRUE; 2389 switch (cmd) { 2390 case WLAN_SET_PARAM: 2391 case WLAN_COMMAND: 2392 break; 2393 case WLAN_GET_PARAM: 2394 need_privilege = B_FALSE; 2395 break; 2396 default: 2397 IPW2200_DBG(IPW2200_DBG_IOCTL, (sc->sc_dip, CE_CONT, 2398 "ipw2200_ioctl(): unknown cmd 0x%x", cmd)); 2399 miocnak(q, m, 0, EINVAL); 2400 /* 2401 * Unknown cmd, do not need net80211 either 2402 */ 2403 return (IEEE80211_IOCTL_NOT_REQUIRED); 2404 } 2405 2406 if (need_privilege && (ret = secpolicy_dl_config(iocp->ioc_cr)) != 0) { 2407 miocnak(q, m, 0, ret); 2408 /* 2409 * privilege check fail, do not need net80211 either 2410 */ 2411 return (IEEE80211_IOCTL_NOT_REQUIRED); 2412 } 2413 2414 /* 2415 * sanity check 2416 */ 2417 m0 = m->b_cont; 2418 if (iocp->ioc_count == 0 || iocp->ioc_count < sizeof (wldp_t) || 2419 m0 == NULL) { 2420 miocnak(q, m, 0, EINVAL); 2421 /* 2422 * invalid format, do not need net80211 either 2423 */ 2424 return (IEEE80211_IOCTL_NOT_REQUIRED); 2425 } 2426 /* 2427 * assuming single data block 2428 */ 2429 if (m0->b_cont) { 2430 freemsg(m0->b_cont); 2431 m0->b_cont = NULL; 2432 } 2433 2434 need_net80211 = B_FALSE; 2435 ret = ipw2200_getset(sc, m0, cmd, &need_net80211); 2436 if (!need_net80211) { 2437 len = msgdsize(m0); 2438 2439 IPW2200_DBG(IPW2200_DBG_IOCTL, (sc->sc_dip, CE_CONT, 2440 "ipw2200_ioctl(): go to call miocack with " 2441 "ret = %d, len = %d\n", ret, len)); 2442 miocack(q, m, len, ret); 2443 return (IEEE80211_IOCTL_NOT_REQUIRED); 2444 } 2445 2446 /* 2447 * IEEE80211_IOCTL - need net80211 handle 2448 */ 2449 return (IEEE80211_IOCTL_REQUIRED); 2450 } 2451 2452 static int 2453 ipw2200_getset(struct ipw2200_softc *sc, mblk_t *m, uint32_t cmd, 2454 boolean_t *need_net80211) 2455 { 2456 wldp_t *infp, *outfp; 2457 uint32_t id; 2458 int ret; 2459 2460 infp = (wldp_t *)(uintptr_t)m->b_rptr; 2461 outfp = (wldp_t *)(uintptr_t)m->b_rptr; 2462 outfp->wldp_result = WL_NOTSUPPORTED; 2463 2464 id = infp->wldp_id; 2465 IPW2200_DBG(IPW2200_DBG_IOCTL, (sc->sc_dip, CE_CONT, 2466 "ipw2200_getset(): id = 0x%x\n", id)); 2467 switch (id) { 2468 case WL_RADIO: /* which is not supported by net80211 */ 2469 ret = iwi_wificfg_radio(sc, cmd, outfp); 2470 break; 2471 case WL_DESIRED_RATES: /* hardware doesn't support fix-rates */ 2472 ret = iwi_wificfg_desrates(outfp); 2473 break; 2474 default: 2475 /* 2476 * The wifi IOCTL net80211 supported: 2477 * case WL_ESSID: 2478 * case WL_BSSID: 2479 * case WL_WEP_KEY_TAB: 2480 * case WL_WEP_KEY_ID: 2481 * case WL_AUTH_MODE: 2482 * case WL_ENCRYPTION: 2483 * case WL_BSS_TYPE: 2484 * case WL_ESS_LIST: 2485 * case WL_LINKSTATUS: 2486 * case WL_RSSI: 2487 * case WL_SCAN: 2488 * case WL_LOAD_DEFAULTS: 2489 * case WL_DISASSOCIATE: 2490 */ 2491 2492 /* 2493 * When radio is off, need to ignore all ioctl. What need to 2494 * do is to check radio status firstly. If radio is ON, pass 2495 * it to net80211, otherwise, return to upper layer directly. 2496 * 2497 * Considering the WL_SUCCESS also means WL_CONNECTED for 2498 * checking linkstatus, one exception for WL_LINKSTATUS is to 2499 * let net80211 handle it. 2500 */ 2501 if ((ipw2200_radio_status(sc) == 0) && 2502 (id != WL_LINKSTATUS)) { 2503 2504 IPW2200_REPORT((sc->sc_dip, CE_CONT, 2505 "iwi: radio is OFF\n")); 2506 2507 outfp->wldp_length = WIFI_BUF_OFFSET; 2508 outfp->wldp_result = WL_SUCCESS; 2509 ret = 0; 2510 break; 2511 } 2512 2513 *need_net80211 = B_TRUE; /* let net80211 do the rest */ 2514 return (0); 2515 } 2516 /* 2517 * we will overwrite everything 2518 */ 2519 m->b_wptr = m->b_rptr + outfp->wldp_length; 2520 return (ret); 2521 } 2522 2523 static int 2524 iwi_wificfg_radio(struct ipw2200_softc *sc, uint32_t cmd, wldp_t *outfp) 2525 { 2526 uint32_t ret = ENOTSUP; 2527 2528 switch (cmd) { 2529 case WLAN_GET_PARAM: 2530 *(wl_linkstatus_t *)(outfp->wldp_buf) = 2531 ipw2200_radio_status(sc); 2532 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_linkstatus_t); 2533 outfp->wldp_result = WL_SUCCESS; 2534 ret = 0; /* command success */ 2535 break; 2536 case WLAN_SET_PARAM: 2537 default: 2538 break; 2539 } 2540 return (ret); 2541 } 2542 2543 static int 2544 iwi_wificfg_desrates(wldp_t *outfp) 2545 { 2546 /* return success, but with result NOTSUPPORTED */ 2547 outfp->wldp_length = WIFI_BUF_OFFSET; 2548 outfp->wldp_result = WL_NOTSUPPORTED; 2549 return (0); 2550 } 2551 /* End of IOCTL Handlers */ 2552 2553 void 2554 ipw2200_fix_channel(struct ieee80211com *ic, mblk_t *m) 2555 { 2556 struct ieee80211_frame *wh; 2557 uint8_t subtype; 2558 uint8_t *frm, *efrm; 2559 2560 wh = (struct ieee80211_frame *)m->b_rptr; 2561 2562 if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_MGT) 2563 return; 2564 2565 subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; 2566 2567 if (subtype != IEEE80211_FC0_SUBTYPE_BEACON && 2568 subtype != IEEE80211_FC0_SUBTYPE_PROBE_RESP) 2569 return; 2570 2571 /* 2572 * assume the message contains only 1 block 2573 */ 2574 frm = (uint8_t *)(wh + 1); 2575 efrm = (uint8_t *)m->b_wptr; 2576 frm += 12; /* skip tstamp, bintval and capinfo fields */ 2577 while (frm < efrm) { 2578 if (*frm == IEEE80211_ELEMID_DSPARMS) 2579 #if IEEE80211_CHAN_MAX < 255 2580 if (frm[2] <= IEEE80211_CHAN_MAX) 2581 #endif 2582 ic->ic_curchan = &ic->ic_sup_channels[frm[2]]; 2583 frm += frm[1] + 2; 2584 } 2585 } 2586 2587 static void 2588 ipw2200_rcv_frame(struct ipw2200_softc *sc, struct ipw2200_frame *frame) 2589 { 2590 struct ieee80211com *ic = &sc->sc_ic; 2591 uint8_t *data = (uint8_t *)frame; 2592 uint32_t len; 2593 struct ieee80211_frame *wh; 2594 struct ieee80211_node *in; 2595 mblk_t *m; 2596 2597 len = LE_16(frame->len); 2598 if ((len < sizeof (struct ieee80211_frame_min)) || 2599 (len > IPW2200_RXBUF_SIZE)) { 2600 IPW2200_DBG(IPW2200_DBG_RX, (sc->sc_dip, CE_CONT, 2601 "ipw2200_rcv_frame(): bad frame length=%u\n", 2602 LE_16(frame->len))); 2603 sc->sc_stats.sc_rx_len_err++; /* length doesn't work */ 2604 return; 2605 } 2606 IPW2200_DBG(IPW2200_DBG_RX, (sc->sc_dip, CE_CONT, 2607 "ipw2200_rcv_frame(): chan = %d, length = %d\n", frame->chan, len)); 2608 2609 /* 2610 * Skip the frame header, get the real data from the input 2611 */ 2612 data += sizeof (struct ipw2200_frame); 2613 2614 m = allocb(len, BPRI_MED); 2615 if (m) { 2616 (void) memcpy(m->b_wptr, data, len); 2617 m->b_wptr += len; 2618 2619 if (ic->ic_state == IEEE80211_S_SCAN) { 2620 ic->ic_ibss_chan = &ic->ic_sup_channels[frame->chan]; 2621 ipw2200_fix_channel(ic, m); 2622 } 2623 wh = (struct ieee80211_frame *)m->b_rptr; 2624 2625 in = ieee80211_find_rxnode(ic, wh); 2626 2627 IPW2200_DBG(IPW2200_DBG_RX, (sc->sc_dip, CE_CONT, 2628 "ipw2200_rcv_frame(): " 2629 "type = %x, subtype = %x, i_fc[1] = %x, " 2630 "ni_esslen:%d, ni_essid[0-5]:%c%c%c%c%c%c\n", 2631 wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK, 2632 wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK, 2633 wh->i_fc[1] & IEEE80211_FC1_WEP, 2634 in->in_esslen, 2635 in->in_essid[0], in->in_essid[1], in->in_essid[2], 2636 in->in_essid[3], in->in_essid[4], in->in_essid[5])); 2637 2638 (void) ieee80211_input(ic, m, in, frame->rssi_dbm, 0); 2639 2640 ieee80211_free_node(in); 2641 } 2642 else 2643 IPW2200_WARN((sc->sc_dip, CE_WARN, 2644 "ipw2200_rcv_frame(): " 2645 "cannot allocate receive message(%u)\n", 2646 LE_16(frame->len))); 2647 } 2648 2649 static void 2650 ipw2200_rcv_notif(struct ipw2200_softc *sc, struct ipw2200_notif *notif) 2651 { 2652 struct ieee80211com *ic = &sc->sc_ic; 2653 struct ipw2200_notif_association *assoc; 2654 struct ipw2200_notif_authentication *auth; 2655 uint8_t *ndata = (uint8_t *)notif; 2656 2657 IPW2200_DBG(IPW2200_DBG_NOTIF, (sc->sc_dip, CE_CONT, 2658 "ipw2200_rcv_notif(): type=%u\n", notif->type)); 2659 2660 ndata += sizeof (struct ipw2200_notif); 2661 switch (notif->type) { 2662 case IPW2200_NOTIF_TYPE_ASSOCIATION: 2663 assoc = (struct ipw2200_notif_association *)ndata; 2664 2665 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 2666 "ipw2200_rcv_notif(): association=%u,%u\n", 2667 assoc->state, assoc->status)); 2668 2669 switch (assoc->state) { 2670 case IPW2200_ASSOC_SUCCESS: 2671 sc->sc_flags |= IPW2200_FLAG_ASSOCIATED; 2672 ieee80211_new_state(ic, IEEE80211_S_RUN, -1); 2673 break; 2674 case IPW2200_ASSOC_FAIL: 2675 sc->sc_flags &= ~IPW2200_FLAG_ASSOCIATED; 2676 ieee80211_begin_scan(ic, 1); 2677 break; 2678 default: 2679 break; 2680 } 2681 break; 2682 2683 case IPW2200_NOTIF_TYPE_AUTHENTICATION: 2684 auth = (struct ipw2200_notif_authentication *)ndata; 2685 2686 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 2687 "ipw2200_rcv_notif(): authentication=%u\n", auth->state)); 2688 2689 switch (auth->state) { 2690 case IPW2200_AUTH_SUCCESS: 2691 ieee80211_new_state(ic, IEEE80211_S_ASSOC, -1); 2692 break; 2693 case IPW2200_AUTH_FAIL: 2694 sc->sc_flags &= ~IPW2200_FLAG_ASSOCIATED; 2695 break; 2696 default: 2697 IPW2200_DBG(IPW2200_DBG_NOTIF, (sc->sc_dip, CE_CONT, 2698 "ipw2200_rcv_notif(): " 2699 "unknown authentication state(%u)\n", auth->state)); 2700 break; 2701 } 2702 break; 2703 2704 case IPW2200_NOTIF_TYPE_SCAN_CHANNEL: 2705 IPW2200_DBG(IPW2200_DBG_SCAN, (sc->sc_dip, CE_CONT, 2706 "ipw2200_rcv_notif(): scan-channel=%u\n", 2707 ((struct ipw2200_notif_scan_channel *)ndata)->nchan)); 2708 break; 2709 2710 case IPW2200_NOTIF_TYPE_SCAN_COMPLETE: 2711 IPW2200_DBG(IPW2200_DBG_SCAN, (sc->sc_dip, CE_CONT, 2712 "ipw2200_rcv_notif():scan-completed,(%u,%u)\n", 2713 ((struct ipw2200_notif_scan_complete *)ndata)->nchan, 2714 ((struct ipw2200_notif_scan_complete *)ndata)->status)); 2715 2716 /* 2717 * scan complete 2718 */ 2719 sc->sc_flags &= ~IPW2200_FLAG_SCANNING; 2720 ieee80211_end_scan(ic); 2721 break; 2722 2723 case IPW2200_NOTIF_TYPE_BEACON: 2724 case IPW2200_NOTIF_TYPE_CALIBRATION: 2725 case IPW2200_NOTIF_TYPE_NOISE: 2726 /* 2727 * just ignore 2728 */ 2729 break; 2730 default: 2731 IPW2200_DBG(IPW2200_DBG_NOTIF, (sc->sc_dip, CE_CONT, 2732 "ipw2200_rcv_notif(): unknown notification type(%u)\n", 2733 notif->type)); 2734 break; 2735 } 2736 } 2737 2738 static uint_t 2739 ipw2200_intr(caddr_t arg) 2740 { 2741 struct ipw2200_softc *sc = (struct ipw2200_softc *)(uintptr_t)arg; 2742 struct ieee80211com *ic = &sc->sc_ic; 2743 uint32_t ireg, ridx, len, i; 2744 uint8_t *p, *rxbuf; 2745 struct dma_region *dr; 2746 struct ipw2200_hdr *hdr; 2747 uint32_t widx; 2748 2749 /* when it is on suspend, unclaim all interrupt directly */ 2750 if (sc->sc_flags & IPW2200_FLAG_SUSPEND) 2751 return (DDI_INTR_UNCLAIMED); 2752 2753 /* unclaim interrupt when it is not for iwi */ 2754 ireg = ipw2200_csr_get32(sc, IPW2200_CSR_INTR); 2755 if (ireg == 0xffffffff || 2756 !(ireg & IPW2200_INTR_MASK_ALL)) 2757 return (DDI_INTR_UNCLAIMED); 2758 2759 /* 2760 * mask all interrupts 2761 */ 2762 ipw2200_csr_put32(sc, IPW2200_CSR_INTR_MASK, 0); 2763 2764 /* 2765 * acknowledge all fired interrupts 2766 */ 2767 ipw2200_csr_put32(sc, IPW2200_CSR_INTR, ireg); 2768 2769 IPW2200_DBG(IPW2200_DBG_INT, (sc->sc_dip, CE_CONT, 2770 "ipw2200_intr(): enter. interrupt fired, int=0x%08x\n", ireg)); 2771 2772 if (ireg & IPW2200_INTR_MASK_ERR) { 2773 2774 IPW2200_DBG(IPW2200_DBG_FATAL, (sc->sc_dip, CE_CONT, 2775 "ipw2200 interrupt(): int= 0x%08x\n", ireg)); 2776 2777 /* 2778 * inform mfthread to recover hw error by stopping it 2779 */ 2780 mutex_enter(&sc->sc_mflock); 2781 sc->sc_flags |= IPW2200_FLAG_HW_ERR_RECOVER; 2782 mutex_exit(&sc->sc_mflock); 2783 2784 goto enable_interrupt; 2785 } 2786 2787 /* 2788 * FW intr 2789 */ 2790 if (ireg & IPW2200_INTR_FW_INITED) { 2791 mutex_enter(&sc->sc_ilock); 2792 sc->sc_fw_ok = 1; 2793 cv_signal(&sc->sc_fw_cond); 2794 mutex_exit(&sc->sc_ilock); 2795 } 2796 2797 /* 2798 * Radio OFF 2799 */ 2800 if (ireg & IPW2200_INTR_RADIO_OFF) { 2801 IPW2200_REPORT((sc->sc_dip, CE_CONT, 2802 "ipw2200_intr(): radio is OFF\n")); 2803 2804 /* 2805 * Stop hardware, will notify LINK is down. 2806 * Need a better scan solution to ensure 2807 * table has right value. 2808 */ 2809 ipw2200_stop(sc); 2810 } 2811 2812 /* 2813 * CMD intr 2814 */ 2815 if (ireg & IPW2200_INTR_CMD_TRANSFER) { 2816 mutex_enter(&sc->sc_cmd_lock); 2817 ridx = ipw2200_csr_get32(sc, 2818 IPW2200_CSR_CMD_READ_INDEX); 2819 i = RING_FORWARD(sc->sc_cmd_cur, 2820 sc->sc_cmd_free, IPW2200_CMD_RING_SIZE); 2821 len = RING_FLEN(i, ridx, IPW2200_CMD_RING_SIZE); 2822 2823 IPW2200_DBG(IPW2200_DBG_INT, (sc->sc_dip, CE_CONT, 2824 "ipw2200_intr(): cmd-ring,i=%u,ridx=%u,len=%u\n", 2825 i, ridx, len)); 2826 2827 if (len > 0) { 2828 sc->sc_cmd_free += len; 2829 cv_signal(&sc->sc_cmd_cond); 2830 } 2831 for (; i != ridx; 2832 i = RING_FORWARD(i, 1, IPW2200_CMD_RING_SIZE)) 2833 sc->sc_done[i] = 1; 2834 mutex_exit(&sc->sc_cmd_lock); 2835 2836 mutex_enter(&sc->sc_ilock); 2837 cv_signal(&sc->sc_cmd_status_cond); 2838 mutex_exit(&sc->sc_ilock); 2839 } 2840 2841 /* 2842 * RX intr 2843 */ 2844 if (ireg & IPW2200_INTR_RX_TRANSFER) { 2845 ridx = ipw2200_csr_get32(sc, 2846 IPW2200_CSR_RX_READ_INDEX); 2847 widx = ipw2200_csr_get32(sc, 2848 IPW2200_CSR_RX_WRITE_INDEX); 2849 2850 IPW2200_DBG(IPW2200_DBG_INT, (sc->sc_dip, CE_CONT, 2851 "ipw2200_intr(): rx-ring,widx=%u,ridx=%u\n", 2852 ridx, widx)); 2853 2854 for (; sc->sc_rx_cur != ridx; 2855 sc->sc_rx_cur = RING_FORWARD(sc->sc_rx_cur, 1, 2856 IPW2200_RX_RING_SIZE)) { 2857 i = sc->sc_rx_cur; 2858 rxbuf = sc->sc_rxbufs[i]; 2859 dr = &sc->sc_dma_rxbufs[i]; 2860 2861 /* 2862 * DMA sync 2863 */ 2864 (void) ddi_dma_sync(dr->dr_hnd, 0, 2865 IPW2200_RXBUF_SIZE, DDI_DMA_SYNC_FORKERNEL); 2866 /* 2867 * Get rx header(hdr) and rx data(p) from rxbuf 2868 */ 2869 p = rxbuf; 2870 hdr = (struct ipw2200_hdr *)p; 2871 p += sizeof (struct ipw2200_hdr); 2872 2873 IPW2200_DBG(IPW2200_DBG_INT, (sc->sc_dip, CE_CONT, 2874 "ipw2200_intr(): Rx hdr type %u\n", 2875 hdr->type)); 2876 2877 switch (hdr->type) { 2878 case IPW2200_HDR_TYPE_FRAME: 2879 ipw2200_rcv_frame(sc, 2880 (struct ipw2200_frame *)p); 2881 break; 2882 2883 case IPW2200_HDR_TYPE_NOTIF: 2884 ipw2200_rcv_notif(sc, 2885 (struct ipw2200_notif *)p); 2886 break; 2887 2888 default: 2889 IPW2200_DBG(IPW2200_DBG_INT, (sc->sc_dip, 2890 CE_CONT, 2891 "ipw2200_intr(): unknown Rx hdr type %u\n", 2892 hdr->type)); 2893 break; 2894 } 2895 } 2896 /* 2897 * write sc_rx_cur backward 1 step into RX_WRITE_INDEX 2898 */ 2899 ipw2200_csr_put32(sc, IPW2200_CSR_RX_WRITE_INDEX, 2900 RING_BACKWARD(sc->sc_rx_cur, 1, 2901 IPW2200_RX_RING_SIZE)); 2902 } 2903 2904 /* 2905 * TX intr 2906 */ 2907 if (ireg & IPW2200_INTR_TX1_TRANSFER) { 2908 mutex_enter(&sc->sc_tx_lock); 2909 ridx = ipw2200_csr_get32(sc, 2910 IPW2200_CSR_TX1_READ_INDEX); 2911 len = RING_FLEN(RING_FORWARD(sc->sc_tx_cur, 2912 sc->sc_tx_free, IPW2200_TX_RING_SIZE), 2913 ridx, IPW2200_TX_RING_SIZE); 2914 sc->sc_tx_free += len; 2915 IPW2200_DBG(IPW2200_DBG_RING, (sc->sc_dip, CE_CONT, 2916 "ipw2200_intr(): tx-ring,ridx=%u,len=%u\n", 2917 ridx, len)); 2918 mutex_exit(&sc->sc_tx_lock); 2919 2920 mutex_enter(&sc->sc_resched_lock); 2921 if ((sc->sc_tx_free > IPW2200_TX_RING_MIN) && 2922 (sc->sc_flags & IPW2200_FLAG_TX_SCHED)) { 2923 IPW2200_DBG(IPW2200_DBG_RING, (sc->sc_dip, 2924 CE_CONT, 2925 "ipw2200_intr(): Need Reschedule!")); 2926 sc->sc_flags &= ~IPW2200_FLAG_TX_SCHED; 2927 mac_tx_update(ic->ic_mach); 2928 } 2929 mutex_exit(&sc->sc_resched_lock); 2930 } 2931 2932 enable_interrupt: 2933 /* 2934 * enable all interrupts 2935 */ 2936 ipw2200_csr_put32(sc, IPW2200_CSR_INTR_MASK, IPW2200_INTR_MASK_ALL); 2937 2938 return (DDI_INTR_CLAIMED); 2939 } 2940 2941 2942 /* 2943 * Module Loading Data & Entry Points 2944 */ 2945 DDI_DEFINE_STREAM_OPS(ipw2200_devops, nulldev, nulldev, ipw2200_attach, 2946 ipw2200_detach, ipw2200_reset, NULL, D_MP, NULL); 2947 2948 static struct modldrv ipw2200_modldrv = { 2949 &mod_driverops, 2950 ipw2200_ident, 2951 &ipw2200_devops 2952 }; 2953 2954 static struct modlinkage ipw2200_modlinkage = { 2955 MODREV_1, 2956 &ipw2200_modldrv, 2957 NULL 2958 }; 2959 2960 int 2961 _init(void) 2962 { 2963 int status; 2964 2965 status = ddi_soft_state_init(&ipw2200_ssp, 2966 sizeof (struct ipw2200_softc), 1); 2967 if (status != DDI_SUCCESS) 2968 return (status); 2969 2970 mac_init_ops(&ipw2200_devops, IPW2200_DRV_NAME); 2971 status = mod_install(&ipw2200_modlinkage); 2972 if (status != DDI_SUCCESS) { 2973 mac_fini_ops(&ipw2200_devops); 2974 ddi_soft_state_fini(&ipw2200_ssp); 2975 } 2976 2977 return (status); 2978 } 2979 2980 int 2981 _fini(void) 2982 { 2983 int status; 2984 2985 status = mod_remove(&ipw2200_modlinkage); 2986 if (status == DDI_SUCCESS) { 2987 mac_fini_ops(&ipw2200_devops); 2988 ddi_soft_state_fini(&ipw2200_ssp); 2989 } 2990 2991 return (status); 2992 } 2993 2994 int 2995 _info(struct modinfo *modinfop) 2996 { 2997 return (mod_info(&ipw2200_modlinkage, modinfop)); 2998 } 2999