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; 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 err = mac_disable(sc->sc_ic.ic_mach); 667 if (err != DDI_SUCCESS) 668 return (err); 669 670 ipw2200_stop(sc); 671 672 /* 673 * Destroy the mf_thread 674 */ 675 mutex_enter(&sc->sc_mflock); 676 sc->sc_mfthread_switch = 0; 677 while (sc->sc_mf_thread != NULL) { 678 if (cv_wait_sig(&sc->sc_mfthread_cv, &sc->sc_mflock) == 0) 679 break; 680 } 681 mutex_exit(&sc->sc_mflock); 682 683 /* 684 * Unregister from the MAC layer subsystem 685 */ 686 (void) mac_unregister(sc->sc_ic.ic_mach); 687 688 ddi_remove_intr(dip, IPW2200_PCI_INTR_NUM, sc->sc_iblk); 689 690 mutex_destroy(&sc->sc_ilock); 691 mutex_destroy(&sc->sc_cmd_lock); 692 mutex_destroy(&sc->sc_tx_lock); 693 mutex_destroy(&sc->sc_mflock); 694 mutex_destroy(&sc->sc_resched_lock); 695 cv_destroy(&sc->sc_fw_cond); 696 cv_destroy(&sc->sc_cmd_status_cond); 697 cv_destroy(&sc->sc_cmd_cond); 698 cv_destroy(&sc->sc_mfthread_cv); 699 700 /* 701 * Detach ieee80211 702 */ 703 ieee80211_detach(&sc->sc_ic); 704 705 (void) ipw2200_free_firmware(sc); 706 ipw2200_ring_free(sc); 707 708 ddi_regs_map_free(&sc->sc_ioh); 709 ddi_remove_minor_node(dip, NULL); 710 ddi_soft_state_free(ipw2200_ssp, ddi_get_instance(dip)); 711 712 return (DDI_SUCCESS); 713 } 714 715 /* 716 * quiesce(9E) entry point. 717 * This function is called when the system is single-threaded at high 718 * PIL with preemption disabled. Therefore, this function must not be 719 * blocked. 720 * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure. 721 * DDI_FAILURE indicates an error condition and should almost never happen. 722 */ 723 static int 724 ipw2200_quiesce(dev_info_t *dip) 725 { 726 struct ipw2200_softc *sc = 727 ddi_get_soft_state(ipw2200_ssp, ddi_get_instance(dip)); 728 729 if (sc == NULL) 730 return (DDI_FAILURE); 731 732 /* 733 * No more blocking is allowed while we are in the 734 * quiesce(9E) entry point. 735 */ 736 sc->sc_flags |= IPW2200_FLAG_QUIESCED; 737 738 /* 739 * Disable and mask all interrupts. 740 */ 741 ipw2200_stop(sc); 742 return (DDI_SUCCESS); 743 } 744 745 static void 746 ipw2200_stop(struct ipw2200_softc *sc) 747 { 748 struct ieee80211com *ic = &sc->sc_ic; 749 750 IPW2200_DBG(IPW2200_DBG_HWCAP, (sc->sc_dip, CE_CONT, 751 "ipw2200_stop(): enter\n")); 752 753 ipw2200_master_stop(sc); 754 ipw2200_csr_put32(sc, IPW2200_CSR_RST, IPW2200_RST_SW_RESET); 755 756 /* 757 * Reset ring 758 */ 759 ipw2200_ring_reset(sc); 760 761 /* 762 * by-pass, if its' quiesced 763 */ 764 if (!(sc->sc_flags & IPW2200_FLAG_QUIESCED)) 765 ieee80211_new_state(ic, IEEE80211_S_INIT, -1); 766 sc->sc_flags &= ~IPW2200_FLAG_SCANNING; 767 sc->sc_flags &= ~IPW2200_FLAG_ASSOCIATED; 768 769 /* 770 * by-pass, if its' quiesced 771 */ 772 if (!(sc->sc_flags & IPW2200_FLAG_QUIESCED)) 773 IPW2200_DBG(IPW2200_DBG_HWCAP, (sc->sc_dip, CE_CONT, 774 "ipw2200_stop(): exit\n")); 775 } 776 777 static int 778 ipw2200_config(struct ipw2200_softc *sc) 779 { 780 struct ieee80211com *ic = &sc->sc_ic; 781 struct ipw2200_configuration cfg; 782 uint32_t data; 783 struct ipw2200_txpower pwr; 784 struct ipw2200_rateset rs; 785 struct ipw2200_wep_key wkey; 786 int err, i; 787 788 /* 789 * Set the IBSS mode channel: Tx power 790 */ 791 if (ic->ic_opmode == IEEE80211_M_IBSS) { 792 pwr.mode = IPW2200_MODE_11B; 793 pwr.nchan = 11; 794 for (i = 0; i < pwr.nchan; i++) { 795 pwr.chan[i].chan = i + 1; 796 pwr.chan[i].power = IPW2200_TXPOWER_MAX; 797 } 798 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 799 "ipw2200_config(): Setting .11b channels Tx power\n")); 800 err = ipw2200_cmd(sc, IPW2200_CMD_SET_TX_POWER, 801 &pwr, sizeof (pwr), 0); 802 if (err != DDI_SUCCESS) 803 return (err); 804 805 pwr.mode = IPW2200_MODE_11G; 806 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 807 "ipw2200_config(): Setting .11g channels Tx power\n")); 808 err = ipw2200_cmd(sc, IPW2200_CMD_SET_TX_POWER, 809 &pwr, sizeof (pwr), 0); 810 if (err != DDI_SUCCESS) 811 return (err); 812 } 813 814 /* 815 * Set MAC address 816 */ 817 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 818 "ipw2200_config(): Setting MAC address to " 819 "%02x:%02x:%02x:%02x:%02x:%02x\n", 820 ic->ic_macaddr[0], ic->ic_macaddr[1], ic->ic_macaddr[2], 821 ic->ic_macaddr[3], ic->ic_macaddr[4], ic->ic_macaddr[5])); 822 err = ipw2200_cmd(sc, IPW2200_CMD_SET_MAC_ADDRESS, ic->ic_macaddr, 823 IEEE80211_ADDR_LEN, 0); 824 if (err != DDI_SUCCESS) 825 return (err); 826 827 /* 828 * Set basic system config settings: configuration(capabilities) 829 */ 830 (void) memset(&cfg, 0, sizeof (cfg)); 831 cfg.bluetooth_coexistence = 1; 832 cfg.multicast_enabled = 1; 833 cfg.answer_pbreq = 1; 834 cfg.noise_reported = 1; 835 cfg.disable_multicast_decryption = 1; /* WPA */ 836 cfg.disable_unicast_decryption = 1; /* WPA */ 837 838 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 839 "ipw2200_config(): Configuring adapter\n")); 840 err = ipw2200_cmd(sc, IPW2200_CMD_SET_CONFIG, 841 &cfg, sizeof (cfg), 0); 842 if (err != DDI_SUCCESS) 843 return (err); 844 845 /* 846 * Set power mode 847 */ 848 data = LE_32(IPW2200_POWER_MODE_CAM); 849 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 850 "ipw2200_config(): Setting power mode to %u\n", LE_32(data))); 851 err = ipw2200_cmd(sc, IPW2200_CMD_SET_POWER_MODE, 852 &data, sizeof (data), 0); 853 if (err != DDI_SUCCESS) 854 return (err); 855 856 /* 857 * Set supported rates 858 */ 859 rs.mode = IPW2200_MODE_11G; 860 rs.type = IPW2200_RATESET_TYPE_SUPPORTED; 861 rs.nrates = ic->ic_sup_rates[IEEE80211_MODE_11G].ir_nrates; 862 (void) memcpy(rs.rates, ic->ic_sup_rates[IEEE80211_MODE_11G].ir_rates, 863 rs.nrates); 864 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 865 "ipw2200_config(): Setting .11g supported rates(%u)\n", rs.nrates)); 866 err = ipw2200_cmd(sc, IPW2200_CMD_SET_RATES, &rs, sizeof (rs), 0); 867 if (err != DDI_SUCCESS) 868 return (err); 869 870 rs.mode = IPW2200_MODE_11A; 871 rs.type = IPW2200_RATESET_TYPE_SUPPORTED; 872 rs.nrates = ic->ic_sup_rates[IEEE80211_MODE_11A].ir_nrates; 873 (void) memcpy(rs.rates, ic->ic_sup_rates[IEEE80211_MODE_11A].ir_rates, 874 rs.nrates); 875 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 876 "ipw2200_config(): Setting .11a supported rates(%u)\n", rs.nrates)); 877 err = ipw2200_cmd(sc, IPW2200_CMD_SET_RATES, &rs, sizeof (rs), 0); 878 if (err != DDI_SUCCESS) 879 return (err); 880 881 /* 882 * Set RTS(request-to-send) threshold 883 */ 884 data = LE_32(ic->ic_rtsthreshold); 885 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 886 "ipw2200_config(): Setting RTS threshold to %u\n", LE_32(data))); 887 err = ipw2200_cmd(sc, IPW2200_CMD_SET_RTS_THRESHOLD, &data, 888 sizeof (data), 0); 889 if (err != DDI_SUCCESS) 890 return (err); 891 892 /* 893 * Set fragmentation threshold 894 */ 895 data = LE_32(ic->ic_fragthreshold); 896 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 897 "ipw2200_config(): Setting fragmentation threshold to %u\n", 898 LE_32(data))); 899 err = ipw2200_cmd(sc, IPW2200_CMD_SET_FRAG_THRESHOLD, &data, 900 sizeof (data), 0); 901 if (err != DDI_SUCCESS) 902 return (err); 903 904 /* 905 * Set desired ESSID if we have 906 */ 907 if (ic->ic_des_esslen != 0) { 908 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 909 "ipw2200_config(): Setting desired ESSID to " 910 "(%u),%c%c%c%c%c%c%c%c\n", 911 ic->ic_des_esslen, 912 ic->ic_des_essid[0], ic->ic_des_essid[1], 913 ic->ic_des_essid[2], ic->ic_des_essid[3], 914 ic->ic_des_essid[4], ic->ic_des_essid[5], 915 ic->ic_des_essid[6], ic->ic_des_essid[7])); 916 err = ipw2200_cmd(sc, IPW2200_CMD_SET_ESSID, ic->ic_des_essid, 917 ic->ic_des_esslen, 0); 918 if (err != DDI_SUCCESS) 919 return (err); 920 } 921 922 /* 923 * Set WEP initial vector(random seed) 924 */ 925 (void) random_get_pseudo_bytes((uint8_t *)&data, sizeof (data)); 926 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 927 "ipw2200_config(): Setting initialization vector to %u\n", 928 LE_32(data))); 929 err = ipw2200_cmd(sc, IPW2200_CMD_SET_IV, &data, sizeof (data), 0); 930 if (err != DDI_SUCCESS) 931 return (err); 932 933 /* 934 * Set WEP if any 935 */ 936 if (ic->ic_flags & IEEE80211_F_PRIVACY) { 937 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 938 "ipw2200_config(): Setting Wep Key\n", LE_32(data))); 939 for (i = 0; i < IEEE80211_WEP_NKID; i++) { 940 wkey.cmd = IPW2200_WEP_KEY_CMD_SETKEY; 941 wkey.idx = (uint8_t)i; 942 wkey.len = ic->ic_nw_keys[i].wk_keylen; 943 (void) memset(wkey.key, 0, sizeof (wkey.key)); 944 if (ic->ic_nw_keys[i].wk_keylen) 945 (void) memcpy(wkey.key, 946 ic->ic_nw_keys[i].wk_key, 947 ic->ic_nw_keys[i].wk_keylen); 948 err = ipw2200_cmd(sc, IPW2200_CMD_SET_WEP_KEY, 949 &wkey, sizeof (wkey), 0); 950 if (err != DDI_SUCCESS) 951 return (err); 952 } 953 } 954 955 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 956 "ipw2200_config(): Enabling adapter\n")); 957 958 return (ipw2200_cmd(sc, IPW2200_CMD_ENABLE, NULL, 0, 0)); 959 } 960 961 static int 962 ipw2200_cmd(struct ipw2200_softc *sc, 963 uint32_t type, void *buf, size_t len, int async) 964 { 965 struct ipw2200_cmd_desc *cmd; 966 clock_t clk; 967 uint32_t idx; 968 969 mutex_enter(&sc->sc_cmd_lock); 970 while (sc->sc_cmd_free < 1) 971 cv_wait(&sc->sc_cmd_cond, &sc->sc_cmd_lock); 972 973 idx = sc->sc_cmd_cur; 974 cmd = &sc->sc_cmdsc[idx]; 975 (void) memset(cmd, 0, sizeof (*cmd)); 976 977 IPW2200_DBG(IPW2200_DBG_RING, (sc->sc_dip, CE_CONT, 978 "ipw2200_cmd(): cmd-cur=%d\n", idx)); 979 980 cmd->hdr.type = IPW2200_HDR_TYPE_COMMAND; 981 cmd->hdr.flags = IPW2200_HDR_FLAG_IRQ; 982 cmd->type = (uint8_t)type; 983 if (len == 0 || buf == NULL) 984 cmd->len = 0; 985 else { 986 cmd->len = (uint8_t)len; 987 (void) memcpy(cmd->data, buf, len); 988 } 989 sc->sc_done[idx] = 0; 990 991 /* 992 * DMA sync 993 */ 994 (void) ddi_dma_sync(sc->sc_dma_cmdsc.dr_hnd, 995 idx * sizeof (struct ipw2200_cmd_desc), 996 sizeof (struct ipw2200_cmd_desc), DDI_DMA_SYNC_FORDEV); 997 998 sc->sc_cmd_cur = RING_FORWARD(sc->sc_cmd_cur, 1, IPW2200_CMD_RING_SIZE); 999 sc->sc_cmd_free--; 1000 1001 ipw2200_csr_put32(sc, IPW2200_CSR_CMD_WRITE_INDEX, sc->sc_cmd_cur); 1002 1003 mutex_exit(&sc->sc_cmd_lock); 1004 1005 if (async) 1006 goto out; 1007 1008 /* 1009 * Wait for command done 1010 */ 1011 mutex_enter(&sc->sc_ilock); 1012 while (sc->sc_done[idx] == 0) { 1013 /* pending */ 1014 clk = ddi_get_lbolt() + drv_usectohz(5000000); /* 5 second */ 1015 if (cv_timedwait(&sc->sc_cmd_status_cond, &sc->sc_ilock, clk) 1016 < 0) 1017 break; 1018 } 1019 mutex_exit(&sc->sc_ilock); 1020 1021 IPW2200_DBG(IPW2200_DBG_RING, (sc->sc_dip, CE_CONT, 1022 "ipw2200_cmd(): cmd-done=%s\n", sc->sc_done[idx] ? "yes" : "no")); 1023 1024 if (sc->sc_done[idx] == 0) 1025 return (DDI_FAILURE); 1026 1027 out: 1028 return (DDI_SUCCESS); 1029 } 1030 1031 /* 1032 * If init failed, it will call stop internally. Therefore, it's unnecessary 1033 * to call ipw2200_stop() when this subroutine is failed. Otherwise, it may 1034 * be called twice. 1035 */ 1036 int 1037 ipw2200_init(struct ipw2200_softc *sc) 1038 { 1039 int err; 1040 1041 /* 1042 * No firmware is available, failed 1043 */ 1044 if (!(sc->sc_flags & IPW2200_FLAG_FW_CACHED)) { 1045 IPW2200_WARN((sc->sc_dip, CE_WARN, 1046 "ipw2200_init(): no firmware is available\n")); 1047 return (DDI_FAILURE); /* return directly */ 1048 } 1049 1050 ipw2200_stop(sc); 1051 1052 err = ipw2200_chip_reset(sc); 1053 if (err != DDI_SUCCESS) { 1054 IPW2200_WARN((sc->sc_dip, CE_WARN, 1055 "ipw2200_init(): could not reset adapter\n")); 1056 goto fail; 1057 } 1058 1059 /* 1060 * Load boot code 1061 */ 1062 err = ipw2200_load_fw(sc, sc->sc_fw.boot_base, sc->sc_fw.boot_size); 1063 if (err != DDI_SUCCESS) { 1064 IPW2200_WARN((sc->sc_dip, CE_WARN, 1065 "ipw2200_init(): could not load boot code\n")); 1066 goto fail; 1067 } 1068 1069 /* 1070 * Load boot microcode 1071 */ 1072 err = ipw2200_load_uc(sc, sc->sc_fw.uc_base, sc->sc_fw.uc_size); 1073 if (err != DDI_SUCCESS) { 1074 IPW2200_WARN((sc->sc_dip, CE_WARN, 1075 "ipw2200_init(): could not load microcode\n")); 1076 goto fail; 1077 } 1078 1079 ipw2200_master_stop(sc); 1080 ipw2200_ring_hwsetup(sc); 1081 1082 /* 1083 * Load firmware 1084 */ 1085 err = ipw2200_load_fw(sc, sc->sc_fw.fw_base, sc->sc_fw.fw_size); 1086 if (err != DDI_SUCCESS) { 1087 IPW2200_WARN((sc->sc_dip, CE_WARN, 1088 "ipw2200_init(): could not load firmware\n")); 1089 goto fail; 1090 } 1091 1092 sc->sc_flags |= IPW2200_FLAG_FW_INITED; 1093 1094 /* 1095 * Hardware will be enabled after configuration 1096 */ 1097 err = ipw2200_config(sc); 1098 if (err != DDI_SUCCESS) { 1099 IPW2200_WARN((sc->sc_dip, CE_WARN, 1100 "ipw2200_init(): device configuration failed\n")); 1101 goto fail; 1102 } 1103 1104 /* 1105 * workround to prevent too many h/w error. 1106 * delay for a while till h/w is stable. 1107 */ 1108 delay(drv_usectohz(delay_config_stable)); 1109 1110 return (DDI_SUCCESS); /* return successfully */ 1111 fail: 1112 ipw2200_stop(sc); 1113 return (err); 1114 } 1115 1116 /* 1117 * get hardware configurations from EEPROM embedded within PRO/2200 1118 */ 1119 static void 1120 ipw2200_hwconf_get(struct ipw2200_softc *sc) 1121 { 1122 int i; 1123 uint16_t val; 1124 1125 /* 1126 * Get mac address 1127 */ 1128 i = 0; 1129 val = ipw2200_rom_get16(sc, IPW2200_EEPROM_MAC + 0); 1130 sc->sc_macaddr[i++] = val >> 8; 1131 sc->sc_macaddr[i++] = val & 0xff; 1132 val = ipw2200_rom_get16(sc, IPW2200_EEPROM_MAC + 1); 1133 sc->sc_macaddr[i++] = val >> 8; 1134 sc->sc_macaddr[i++] = val & 0xff; 1135 val = ipw2200_rom_get16(sc, IPW2200_EEPROM_MAC + 2); 1136 sc->sc_macaddr[i++] = val >> 8; 1137 sc->sc_macaddr[i++] = val & 0xff; 1138 1139 /* 1140 * formatted MAC address string 1141 */ 1142 (void) snprintf(sc->sc_macstr, sizeof (sc->sc_macstr), 1143 "%02x:%02x:%02x:%02x:%02x:%02x", 1144 sc->sc_macaddr[0], sc->sc_macaddr[1], 1145 sc->sc_macaddr[2], sc->sc_macaddr[3], 1146 sc->sc_macaddr[4], sc->sc_macaddr[5]); 1147 1148 } 1149 1150 /* 1151 * all ipw2200 interrupts will be masked by this routine 1152 */ 1153 static void 1154 ipw2200_master_stop(struct ipw2200_softc *sc) 1155 { 1156 int ntries; 1157 1158 /* 1159 * disable interrupts 1160 */ 1161 ipw2200_csr_put32(sc, IPW2200_CSR_INTR_MASK, 0); 1162 ipw2200_csr_put32(sc, IPW2200_CSR_RST, IPW2200_RST_STOP_MASTER); 1163 1164 /* 1165 * wait long enough to ensure hardware stop successfully. 1166 */ 1167 for (ntries = 0; ntries < 500; ntries++) { 1168 if (ipw2200_csr_get32(sc, IPW2200_CSR_RST) & 1169 IPW2200_RST_MASTER_DISABLED) 1170 break; 1171 /* wait for a while */ 1172 drv_usecwait(100); 1173 } 1174 /* 1175 * by pass warning message, if it's quiesced already 1176 */ 1177 if (ntries == 500 && !(sc->sc_flags & IPW2200_FLAG_QUIESCED)) 1178 IPW2200_WARN((sc->sc_dip, CE_WARN, 1179 "ipw2200_master_stop(): timeout\n")); 1180 1181 ipw2200_csr_put32(sc, IPW2200_CSR_RST, 1182 IPW2200_RST_PRINCETON_RESET | 1183 ipw2200_csr_get32(sc, IPW2200_CSR_RST)); 1184 1185 sc->sc_flags &= ~IPW2200_FLAG_FW_INITED; 1186 } 1187 1188 /* 1189 * all ipw2200 interrupts will be masked by this routine 1190 */ 1191 static int 1192 ipw2200_chip_reset(struct ipw2200_softc *sc) 1193 { 1194 uint32_t tmp; 1195 int ntries, i; 1196 1197 ipw2200_master_stop(sc); 1198 1199 /* 1200 * Move adapter to DO state 1201 */ 1202 tmp = ipw2200_csr_get32(sc, IPW2200_CSR_CTL); 1203 ipw2200_csr_put32(sc, IPW2200_CSR_CTL, tmp | IPW2200_CTL_INIT); 1204 1205 /* 1206 * Initialize Phase-Locked Level (PLL) 1207 */ 1208 ipw2200_csr_put32(sc, IPW2200_CSR_READ_INT, IPW2200_READ_INT_INIT_HOST); 1209 1210 /* 1211 * Wait for clock stabilization 1212 */ 1213 for (ntries = 0; ntries < 1000; ntries++) { 1214 if (ipw2200_csr_get32(sc, IPW2200_CSR_CTL) & 1215 IPW2200_CTL_CLOCK_READY) 1216 break; 1217 drv_usecwait(200); 1218 } 1219 if (ntries == 1000) { 1220 IPW2200_WARN((sc->sc_dip, CE_WARN, 1221 "ipw2200_chip_reset(): timeout\n")); 1222 return (DDI_FAILURE); 1223 } 1224 1225 tmp = ipw2200_csr_get32(sc, IPW2200_CSR_RST); 1226 ipw2200_csr_put32(sc, IPW2200_CSR_RST, tmp | IPW2200_RST_SW_RESET); 1227 1228 drv_usecwait(10); 1229 1230 tmp = ipw2200_csr_get32(sc, IPW2200_CSR_CTL); 1231 ipw2200_csr_put32(sc, IPW2200_CSR_CTL, tmp | IPW2200_CTL_INIT); 1232 1233 /* 1234 * clear NIC memory 1235 */ 1236 ipw2200_csr_put32(sc, IPW2200_CSR_AUTOINC_ADDR, 0); 1237 for (i = 0; i < 0xc000; i++) 1238 ipw2200_csr_put32(sc, IPW2200_CSR_AUTOINC_DATA, 0); 1239 1240 return (DDI_SUCCESS); 1241 } 1242 1243 /* 1244 * This function is used by wificonfig/dladm to get the current 1245 * radio status, it is off/on 1246 */ 1247 int 1248 ipw2200_radio_status(struct ipw2200_softc *sc) 1249 { 1250 int val; 1251 1252 val = (ipw2200_csr_get32(sc, IPW2200_CSR_IO) & 1253 IPW2200_IO_RADIO_ENABLED) ? 1 : 0; 1254 1255 return (val); 1256 } 1257 /* 1258 * This function is used to get the statistic 1259 */ 1260 void 1261 ipw2200_get_statistics(struct ipw2200_softc *sc) 1262 { 1263 struct ieee80211com *ic = &sc->sc_ic; 1264 1265 uint32_t size, buf[128]; 1266 1267 if (!(sc->sc_flags & IPW2200_FLAG_FW_INITED)) { 1268 IPW2200_DBG(IPW2200_DBG_IOCTL, (sc->sc_dip, CE_CONT, 1269 "ipw2200_get_statistic(): fw doesn't download yet.")); 1270 return; 1271 } 1272 1273 size = min(ipw2200_csr_get32(sc, IPW2200_CSR_TABLE0_SIZE), 128 - 1); 1274 ipw2200_csr_getbuf32(sc, IPW2200_CSR_TABLE0_BASE, &buf[1], size); 1275 1276 /* 1277 * To retrieve the statistic information into proper places. There are 1278 * lot of information. These table will be read once a second. 1279 * Hopefully, it will not effect the performance. 1280 */ 1281 1282 /* 1283 * For the tx/crc information, we can get them from chip directly; 1284 * For the rx/wep error/(rts) related information, leave them net80211. 1285 */ 1286 /* WIFI_STAT_TX_FRAGS */ 1287 ic->ic_stats.is_tx_frags = (uint32_t)buf[5]; 1288 /* WIFI_STAT_MCAST_TX */ 1289 ic->ic_stats.is_tx_mcast = (uint32_t)buf[31]; 1290 /* WIFI_STAT_TX_RETRANS */ 1291 ic->ic_stats.is_tx_retries = (uint32_t)buf[56]; 1292 /* WIFI_STAT_TX_FAILED */ 1293 ic->ic_stats.is_tx_failed = (uint32_t)buf[57]; 1294 /* MAC_STAT_OBYTES */ 1295 ic->ic_stats.is_tx_bytes = (uint32_t)buf[64]; 1296 } 1297 1298 /* 1299 * DMA region alloc subroutine 1300 */ 1301 int 1302 ipw2200_dma_region_alloc(struct ipw2200_softc *sc, struct dma_region *dr, 1303 size_t size, uint_t dir, uint_t flags) 1304 { 1305 dev_info_t *dip = sc->sc_dip; 1306 int err; 1307 1308 IPW2200_DBG(IPW2200_DBG_DMA, (sc->sc_dip, CE_CONT, 1309 "ipw2200_dma_region_alloc(): size =%u\n", size)); 1310 1311 err = ddi_dma_alloc_handle(dip, &ipw2200_dma_attr, DDI_DMA_SLEEP, NULL, 1312 &dr->dr_hnd); 1313 if (err != DDI_SUCCESS) { 1314 IPW2200_DBG(IPW2200_DBG_DMA, (sc->sc_dip, CE_CONT, 1315 "ipw2200_dma_region_alloc(): " 1316 "ddi_dma_alloc_handle() failed\n")); 1317 goto fail0; 1318 } 1319 1320 err = ddi_dma_mem_alloc(dr->dr_hnd, size, &ipw2200_dma_accattr, 1321 flags, DDI_DMA_SLEEP, NULL, 1322 &dr->dr_base, &dr->dr_size, &dr->dr_acc); 1323 if (err != DDI_SUCCESS) { 1324 IPW2200_DBG(IPW2200_DBG_DMA, (sc->sc_dip, CE_CONT, 1325 "ipw2200_dma_region_alloc(): " 1326 "ddi_dma_mem_alloc() failed\n")); 1327 goto fail1; 1328 } 1329 1330 err = ddi_dma_addr_bind_handle(dr->dr_hnd, NULL, 1331 dr->dr_base, dr->dr_size, 1332 dir | flags, DDI_DMA_SLEEP, NULL, 1333 &dr->dr_cookie, &dr->dr_ccnt); 1334 if (err != DDI_DMA_MAPPED) { 1335 IPW2200_DBG(IPW2200_DBG_DMA, (sc->sc_dip, CE_CONT, 1336 "ipw2200_dma_region_alloc(): " 1337 "ddi_dma_addr_bind_handle() failed\n")); 1338 goto fail2; 1339 } 1340 1341 IPW2200_DBG(IPW2200_DBG_DMA, (sc->sc_dip, CE_CONT, 1342 "ipw2200_dma_region_alloc(): ccnt=%u\n", dr->dr_ccnt)); 1343 1344 if (dr->dr_ccnt != 1) { 1345 err = DDI_FAILURE; 1346 goto fail3; 1347 } 1348 1349 dr->dr_pbase = dr->dr_cookie.dmac_address; 1350 1351 IPW2200_DBG(IPW2200_DBG_DMA, (sc->sc_dip, CE_CONT, 1352 "ipw2200_dma_region_alloc(): get physical-base=0x%08x\n", 1353 dr->dr_pbase)); 1354 1355 return (DDI_SUCCESS); 1356 1357 fail3: 1358 (void) ddi_dma_unbind_handle(dr->dr_hnd); 1359 fail2: 1360 ddi_dma_mem_free(&dr->dr_acc); 1361 fail1: 1362 ddi_dma_free_handle(&dr->dr_hnd); 1363 fail0: 1364 return (err); 1365 } 1366 1367 void 1368 ipw2200_dma_region_free(struct dma_region *dr) 1369 { 1370 (void) ddi_dma_unbind_handle(dr->dr_hnd); 1371 ddi_dma_mem_free(&dr->dr_acc); 1372 ddi_dma_free_handle(&dr->dr_hnd); 1373 } 1374 1375 static int 1376 ipw2200_ring_alloc(struct ipw2200_softc *sc) 1377 { 1378 int err, i; 1379 1380 /* 1381 * tx desc ring 1382 */ 1383 sc->sc_dma_txdsc.dr_name = "ipw2200-tx-desc-ring"; 1384 err = ipw2200_dma_region_alloc(sc, &sc->sc_dma_txdsc, 1385 IPW2200_TX_RING_SIZE * sizeof (struct ipw2200_tx_desc), 1386 DDI_DMA_WRITE, DDI_DMA_CONSISTENT); 1387 if (err != DDI_SUCCESS) 1388 goto fail0; 1389 /* 1390 * tx buffer array 1391 */ 1392 for (i = 0; i < IPW2200_TX_RING_SIZE; i++) { 1393 sc->sc_dma_txbufs[i].dr_name = "ipw2200-tx-buf"; 1394 err = ipw2200_dma_region_alloc(sc, &sc->sc_dma_txbufs[i], 1395 IPW2200_TXBUF_SIZE, DDI_DMA_WRITE, DDI_DMA_STREAMING); 1396 if (err != DDI_SUCCESS) { 1397 while (i >= 0) { 1398 ipw2200_dma_region_free(&sc->sc_dma_txbufs[i]); 1399 i--; 1400 } 1401 goto fail1; 1402 } 1403 } 1404 /* 1405 * rx buffer array 1406 */ 1407 for (i = 0; i < IPW2200_RX_RING_SIZE; i++) { 1408 sc->sc_dma_rxbufs[i].dr_name = "ipw2200-rx-buf"; 1409 err = ipw2200_dma_region_alloc(sc, &sc->sc_dma_rxbufs[i], 1410 IPW2200_RXBUF_SIZE, DDI_DMA_READ, DDI_DMA_STREAMING); 1411 if (err != DDI_SUCCESS) { 1412 while (i >= 0) { 1413 ipw2200_dma_region_free(&sc->sc_dma_rxbufs[i]); 1414 i--; 1415 } 1416 goto fail2; 1417 } 1418 } 1419 /* 1420 * cmd desc ring 1421 */ 1422 sc->sc_dma_cmdsc.dr_name = "ipw2200-cmd-desc-ring"; 1423 err = ipw2200_dma_region_alloc(sc, &sc->sc_dma_cmdsc, 1424 IPW2200_CMD_RING_SIZE * sizeof (struct ipw2200_cmd_desc), 1425 DDI_DMA_WRITE, DDI_DMA_CONSISTENT); 1426 if (err != DDI_SUCCESS) 1427 goto fail3; 1428 1429 return (DDI_SUCCESS); 1430 1431 fail3: 1432 for (i = 0; i < IPW2200_RX_RING_SIZE; i++) 1433 ipw2200_dma_region_free(&sc->sc_dma_rxbufs[i]); 1434 fail2: 1435 for (i = 0; i < IPW2200_TX_RING_SIZE; i++) 1436 ipw2200_dma_region_free(&sc->sc_dma_txbufs[i]); 1437 fail1: 1438 ipw2200_dma_region_free(&sc->sc_dma_txdsc); 1439 fail0: 1440 return (err); 1441 } 1442 1443 static void 1444 ipw2200_ring_free(struct ipw2200_softc *sc) 1445 { 1446 int i; 1447 1448 /* 1449 * tx ring desc 1450 */ 1451 ipw2200_dma_region_free(&sc->sc_dma_txdsc); 1452 /* 1453 * tx buf 1454 */ 1455 for (i = 0; i < IPW2200_TX_RING_SIZE; i++) 1456 ipw2200_dma_region_free(&sc->sc_dma_txbufs[i]); 1457 /* 1458 * rx buf 1459 */ 1460 for (i = 0; i < IPW2200_RX_RING_SIZE; i++) 1461 ipw2200_dma_region_free(&sc->sc_dma_rxbufs[i]); 1462 /* 1463 * command ring desc 1464 */ 1465 ipw2200_dma_region_free(&sc->sc_dma_cmdsc); 1466 } 1467 1468 static void 1469 ipw2200_ring_reset(struct ipw2200_softc *sc) 1470 { 1471 int i; 1472 1473 /* 1474 * tx desc ring & buffer array 1475 */ 1476 sc->sc_tx_cur = 0; 1477 sc->sc_tx_free = IPW2200_TX_RING_SIZE; 1478 sc->sc_txdsc = (struct ipw2200_tx_desc *)sc->sc_dma_txdsc.dr_base; 1479 for (i = 0; i < IPW2200_TX_RING_SIZE; i++) 1480 sc->sc_txbufs[i] = (uint8_t *)sc->sc_dma_txbufs[i].dr_base; 1481 /* 1482 * rx buffer array 1483 */ 1484 sc->sc_rx_cur = 0; 1485 sc->sc_rx_free = IPW2200_RX_RING_SIZE; 1486 for (i = 0; i < IPW2200_RX_RING_SIZE; i++) 1487 sc->sc_rxbufs[i] = (uint8_t *)sc->sc_dma_rxbufs[i].dr_base; 1488 1489 /* 1490 * command desc ring 1491 */ 1492 sc->sc_cmd_cur = 0; 1493 sc->sc_cmd_free = IPW2200_CMD_RING_SIZE; 1494 sc->sc_cmdsc = (struct ipw2200_cmd_desc *)sc->sc_dma_cmdsc.dr_base; 1495 } 1496 1497 /* 1498 * tx, rx rings and command initialization 1499 */ 1500 static int 1501 ipw2200_ring_init(struct ipw2200_softc *sc) 1502 { 1503 int err; 1504 1505 err = ipw2200_ring_alloc(sc); 1506 if (err != DDI_SUCCESS) 1507 return (err); 1508 1509 ipw2200_ring_reset(sc); 1510 1511 return (DDI_SUCCESS); 1512 } 1513 1514 static void 1515 ipw2200_ring_hwsetup(struct ipw2200_softc *sc) 1516 { 1517 int i; 1518 1519 /* 1520 * command desc ring 1521 */ 1522 ipw2200_csr_put32(sc, IPW2200_CSR_CMD_BASE, sc->sc_dma_cmdsc.dr_pbase); 1523 ipw2200_csr_put32(sc, IPW2200_CSR_CMD_SIZE, IPW2200_CMD_RING_SIZE); 1524 ipw2200_csr_put32(sc, IPW2200_CSR_CMD_WRITE_INDEX, sc->sc_cmd_cur); 1525 1526 /* 1527 * tx desc ring. only tx1 is used, tx2, tx3, and tx4 are unused 1528 */ 1529 ipw2200_csr_put32(sc, IPW2200_CSR_TX1_BASE, sc->sc_dma_txdsc.dr_pbase); 1530 ipw2200_csr_put32(sc, IPW2200_CSR_TX1_SIZE, IPW2200_TX_RING_SIZE); 1531 ipw2200_csr_put32(sc, IPW2200_CSR_TX1_WRITE_INDEX, sc->sc_tx_cur); 1532 1533 /* 1534 * tx2, tx3, tx4 is not used 1535 */ 1536 ipw2200_csr_put32(sc, IPW2200_CSR_TX2_BASE, sc->sc_dma_txdsc.dr_pbase); 1537 ipw2200_csr_put32(sc, IPW2200_CSR_TX2_SIZE, IPW2200_TX_RING_SIZE); 1538 ipw2200_csr_put32(sc, IPW2200_CSR_TX2_READ_INDEX, 0); 1539 ipw2200_csr_put32(sc, IPW2200_CSR_TX2_WRITE_INDEX, 0); 1540 ipw2200_csr_put32(sc, IPW2200_CSR_TX3_BASE, sc->sc_dma_txdsc.dr_pbase); 1541 ipw2200_csr_put32(sc, IPW2200_CSR_TX3_SIZE, IPW2200_TX_RING_SIZE); 1542 ipw2200_csr_put32(sc, IPW2200_CSR_TX3_READ_INDEX, 0); 1543 ipw2200_csr_put32(sc, IPW2200_CSR_TX3_WRITE_INDEX, 0); 1544 ipw2200_csr_put32(sc, IPW2200_CSR_TX4_BASE, sc->sc_dma_txdsc.dr_pbase); 1545 ipw2200_csr_put32(sc, IPW2200_CSR_TX4_SIZE, IPW2200_TX_RING_SIZE); 1546 ipw2200_csr_put32(sc, IPW2200_CSR_TX4_READ_INDEX, 0); 1547 ipw2200_csr_put32(sc, IPW2200_CSR_TX4_WRITE_INDEX, 0); 1548 1549 /* 1550 * rx buffer ring 1551 */ 1552 for (i = 0; i < IPW2200_RX_RING_SIZE; i++) 1553 ipw2200_csr_put32(sc, IPW2200_CSR_RX_BASE + i * 4, 1554 sc->sc_dma_rxbufs[i].dr_pbase); 1555 /* 1556 * all rx buffer are empty, rx-rd-index == 0 && rx-wr-index == N-1 1557 */ 1558 ipw2200_csr_put32(sc, IPW2200_CSR_RX_WRITE_INDEX, 1559 RING_BACKWARD(sc->sc_rx_cur, 1, IPW2200_RX_RING_SIZE)); 1560 } 1561 1562 int 1563 ipw2200_start_scan(struct ipw2200_softc *sc) 1564 { 1565 struct ieee80211com *ic = &sc->sc_ic; 1566 struct ipw2200_scan scan; 1567 uint8_t *ch; 1568 int cnt, i; 1569 1570 IPW2200_DBG(IPW2200_DBG_SCAN, (sc->sc_dip, CE_CONT, 1571 "ipw2200_start_scan(): start scanning \n")); 1572 1573 /* 1574 * start scanning 1575 */ 1576 sc->sc_flags |= IPW2200_FLAG_SCANNING; 1577 1578 (void) memset(&scan, 0, sizeof (scan)); 1579 scan.type = (ic->ic_des_esslen != 0) ? IPW2200_SCAN_TYPE_BDIRECTED : 1580 IPW2200_SCAN_TYPE_BROADCAST; 1581 scan.dwelltime = LE_16(40); /* The interval is set up to 40 */ 1582 1583 /* 1584 * Compact supported channel number(5G) into a single buffer 1585 */ 1586 ch = scan.channels; 1587 cnt = 0; 1588 for (i = 0; i <= IEEE80211_CHAN_MAX; i++) { 1589 if (IEEE80211_IS_CHAN_5GHZ(&ic->ic_sup_channels[i]) && 1590 isset(ic->ic_chan_active, i)) { 1591 *++ch = (uint8_t)i; 1592 cnt++; 1593 } 1594 } 1595 *(ch - cnt) = IPW2200_CHAN_5GHZ | (uint8_t)cnt; 1596 ch = (cnt > 0) ? (ch + 1) : (scan.channels); 1597 1598 /* 1599 * Compact supported channel number(2G) into a single buffer 1600 */ 1601 cnt = 0; 1602 for (i = 0; i <= IEEE80211_CHAN_MAX; i++) { 1603 if (IEEE80211_IS_CHAN_2GHZ(&ic->ic_sup_channels[i]) && 1604 isset(ic->ic_chan_active, i)) { 1605 *++ch = (uint8_t)i; 1606 cnt++; 1607 } 1608 } 1609 *(ch - cnt) = IPW2200_CHAN_2GHZ | cnt; 1610 1611 return (ipw2200_cmd(sc, IPW2200_CMD_SCAN, &scan, sizeof (scan), 1)); 1612 } 1613 1614 int 1615 ipw2200_auth_and_assoc(struct ipw2200_softc *sc) 1616 { 1617 struct ieee80211com *ic = &sc->sc_ic; 1618 struct ieee80211_node *in = ic->ic_bss; 1619 struct ipw2200_configuration cfg; 1620 struct ipw2200_rateset rs; 1621 struct ipw2200_associate assoc; 1622 uint32_t data; 1623 int err; 1624 uint8_t *wpa_level; 1625 1626 if (sc->sc_flags & IPW2200_FLAG_ASSOCIATED) { 1627 /* already associated */ 1628 return (-1); 1629 } 1630 1631 /* 1632 * set the confiuration 1633 */ 1634 if (IEEE80211_IS_CHAN_2GHZ(in->in_chan)) { 1635 /* enable b/g auto-detection */ 1636 (void) memset(&cfg, 0, sizeof (cfg)); 1637 cfg.bluetooth_coexistence = 1; 1638 cfg.multicast_enabled = 1; 1639 cfg.use_protection = 1; 1640 cfg.answer_pbreq = 1; 1641 cfg.noise_reported = 1; 1642 cfg.disable_multicast_decryption = 1; /* WPA */ 1643 cfg.disable_unicast_decryption = 1; /* WPA */ 1644 err = ipw2200_cmd(sc, IPW2200_CMD_SET_CONFIG, 1645 &cfg, sizeof (cfg), 1); 1646 if (err != DDI_SUCCESS) 1647 return (err); 1648 } 1649 1650 /* 1651 * set the essid, may be null/hidden AP 1652 */ 1653 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 1654 "ipw2200_auth_and_assoc(): " 1655 "setting ESSID to(%u),%c%c%c%c%c%c%c%c\n", 1656 in->in_esslen, 1657 in->in_essid[0], in->in_essid[1], 1658 in->in_essid[2], in->in_essid[3], 1659 in->in_essid[4], in->in_essid[5], 1660 in->in_essid[6], in->in_essid[7])); 1661 err = ipw2200_cmd(sc, IPW2200_CMD_SET_ESSID, in->in_essid, 1662 in->in_esslen, 1); 1663 if (err != DDI_SUCCESS) 1664 return (err); 1665 1666 /* 1667 * set the rate: the rate set has already been ''negocitated'' 1668 */ 1669 rs.mode = IEEE80211_IS_CHAN_5GHZ(in->in_chan) ? 1670 IPW2200_MODE_11A : IPW2200_MODE_11G; 1671 rs.type = IPW2200_RATESET_TYPE_NEGOCIATED; 1672 rs.nrates = in->in_rates.ir_nrates; 1673 (void) memcpy(rs.rates, in->in_rates.ir_rates, in->in_rates.ir_nrates); 1674 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 1675 "ipw2200_auth_and_assoc(): " 1676 "setting negotiated rates to(nrates = %u)\n", rs.nrates)); 1677 err = ipw2200_cmd(sc, IPW2200_CMD_SET_RATES, &rs, sizeof (rs), 1); 1678 if (err != DDI_SUCCESS) 1679 return (err); 1680 1681 /* 1682 * invoke command associate 1683 */ 1684 (void) memset(&assoc, 0, sizeof (assoc)); 1685 1686 /* 1687 * set opt_ie to h/w if associated is WPA, opt_ie has been verified 1688 * by net80211 kernel module. 1689 */ 1690 if (ic->ic_opt_ie != NULL) { 1691 1692 wpa_level = (uint8_t *)ic->ic_opt_ie; 1693 1694 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 1695 "ipw2200_auth_and_assoc(): " 1696 "set wpa_ie and wpa_ie_len to h/w. " 1697 "length is %d\n" 1698 "opt_ie[0] = %02X - element vendor\n" 1699 "opt_ie[1] = %02X - length\n" 1700 "opt_ie[2,3,4] = %02X %02X %02X - oui\n" 1701 "opt_ie[5] = %02X - oui type\n" 1702 "opt_ie[6,7] = %02X %02X - spec version \n" 1703 "opt_ie[8,9,10,11] = %02X %02X %02X %02X - gk cipher\n" 1704 "opt_ie[12,13] = %02X %02X - pairwise key cipher(1)\n" 1705 "opt_ie[14,15,16,17] = %02X %02X %02X %02X - ciphers\n" 1706 "opt_ie[18,19] = %02X %02X - authselcont(1) \n" 1707 "opt_ie[20,21,22,23] = %02X %02X %02X %02X - authsels\n", 1708 wpa_level[1], wpa_level[0], wpa_level[1], 1709 wpa_level[2], wpa_level[3], wpa_level[4], 1710 wpa_level[5], wpa_level[6], wpa_level[7], 1711 wpa_level[8], wpa_level[9], wpa_level[10], 1712 wpa_level[11], wpa_level[12], wpa_level[13], 1713 wpa_level[14], wpa_level[15], wpa_level[16], 1714 wpa_level[17], wpa_level[18], wpa_level[19], 1715 wpa_level[20], wpa_level[21], wpa_level[22], 1716 wpa_level[23])); 1717 1718 err = ipw2200_cmd(sc, IPW2200_CMD_SET_OPTIE, 1719 ic->ic_opt_ie, ic->ic_opt_ie_len, 1); 1720 if (err != DDI_SUCCESS) 1721 return (err); 1722 } 1723 1724 /* 1725 * set the sensitive 1726 */ 1727 data = LE_32(in->in_rssi); 1728 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 1729 "ipw2200_auth_and_assoc(): " 1730 "setting sensitivity to rssi:(%u)\n", (uint8_t)in->in_rssi)); 1731 err = ipw2200_cmd(sc, IPW2200_CMD_SET_SENSITIVITY, 1732 &data, sizeof (data), 1); 1733 if (err != DDI_SUCCESS) 1734 return (err); 1735 1736 /* 1737 * set mode and channel for assocation command 1738 */ 1739 assoc.mode = IEEE80211_IS_CHAN_5GHZ(in->in_chan) ? 1740 IPW2200_MODE_11A : IPW2200_MODE_11G; 1741 assoc.chan = ieee80211_chan2ieee(ic, in->in_chan); 1742 1743 /* 1744 * use the value set to ic_bss to retraive current sharedmode 1745 */ 1746 if (ic->ic_bss->in_authmode == WL_SHAREDKEY) { 1747 assoc.auth = (ic->ic_def_txkey << 4) | IPW2200_AUTH_SHARED; 1748 IPW2200_DBG(IPW2200_DBG_IOCTL, (sc->sc_dip, CE_CONT, 1749 "ipw2200_auth_and_assoc(): " 1750 "associate to shared key mode, set thru. ioctl")); 1751 } 1752 1753 if (ic->ic_flags & IEEE80211_F_WPA) 1754 assoc.policy = LE_16(IPW2200_POLICY_WPA); /* RSN/WPA active */ 1755 (void) memcpy(assoc.tstamp, in->in_tstamp.data, 8); 1756 assoc.capinfo = LE_16(in->in_capinfo); 1757 assoc.lintval = LE_16(ic->ic_lintval); 1758 assoc.intval = LE_16(in->in_intval); 1759 IEEE80211_ADDR_COPY(assoc.bssid, in->in_bssid); 1760 if (ic->ic_opmode == IEEE80211_M_IBSS) 1761 IEEE80211_ADDR_COPY(assoc.dst, ipw2200_broadcast_addr); 1762 else 1763 IEEE80211_ADDR_COPY(assoc.dst, in->in_bssid); 1764 1765 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 1766 "ipw2200_auth_and_assoc(): " 1767 "associate to bssid(%2x:%2x:%2x:%2x:%2x:%2x:), " 1768 "chan(%u), auth(%u)\n", 1769 assoc.bssid[0], assoc.bssid[1], assoc.bssid[2], 1770 assoc.bssid[3], assoc.bssid[4], assoc.bssid[5], 1771 assoc.chan, assoc.auth)); 1772 return (ipw2200_cmd(sc, IPW2200_CMD_ASSOCIATE, 1773 &assoc, sizeof (assoc), 1)); 1774 } 1775 1776 /* 1777 * Send the dis-association command to h/w, will receive notification to claim 1778 * the connection is dis-associated. So, it's not marked as disassociated this 1779 * moment. 1780 */ 1781 static int 1782 ipw2200_disassoc(struct ipw2200_softc *sc) 1783 { 1784 struct ipw2200_associate assoc; 1785 assoc.type = 2; 1786 return (ipw2200_cmd(sc, IPW2200_CMD_ASSOCIATE, &assoc, 1787 sizeof (assoc), 1)); 1788 } 1789 1790 /* ARGSUSED */ 1791 static int 1792 ipw2200_newstate(struct ieee80211com *ic, enum ieee80211_state state, int arg) 1793 { 1794 struct ipw2200_softc *sc = (struct ipw2200_softc *)ic; 1795 wifi_data_t wd = { 0 }; 1796 1797 switch (state) { 1798 case IEEE80211_S_SCAN: 1799 if (!(sc->sc_flags & IPW2200_FLAG_SCANNING)) { 1800 ic->ic_flags |= IEEE80211_F_SCAN | IEEE80211_F_ASCAN; 1801 (void) ipw2200_start_scan(sc); 1802 } 1803 break; 1804 case IEEE80211_S_AUTH: 1805 /* 1806 * The firmware will fail if we are already associated 1807 */ 1808 if (sc->sc_flags & IPW2200_FLAG_ASSOCIATED) 1809 (void) ipw2200_disassoc(sc); 1810 (void) ipw2200_auth_and_assoc(sc); 1811 break; 1812 case IEEE80211_S_RUN: 1813 /* 1814 * We can send data now; update the fastpath with our 1815 * current associated BSSID and other relevant settings. 1816 */ 1817 wd.wd_secalloc = ieee80211_crypto_getciphertype(ic); 1818 wd.wd_opmode = ic->ic_opmode; 1819 IEEE80211_ADDR_COPY(wd.wd_bssid, ic->ic_bss->in_bssid); 1820 (void) mac_pdata_update(ic->ic_mach, &wd, sizeof (wd)); 1821 break; 1822 case IEEE80211_S_ASSOC: 1823 case IEEE80211_S_INIT: 1824 break; 1825 } 1826 1827 /* 1828 * notify to update the link, and WPA 1829 */ 1830 if ((ic->ic_state != IEEE80211_S_RUN) && (state == IEEE80211_S_RUN)) { 1831 ieee80211_notify_node_join(ic, ic->ic_bss); 1832 } else if ((ic->ic_state == IEEE80211_S_RUN) && 1833 (state != IEEE80211_S_RUN)) { 1834 ieee80211_notify_node_leave(ic, ic->ic_bss); 1835 } 1836 1837 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 1838 "ipw2200_newstat(): %s -> %s\n", 1839 ieee80211_state_name[ic->ic_state], 1840 ieee80211_state_name[state])); 1841 1842 ic->ic_state = state; 1843 return (DDI_SUCCESS); 1844 } 1845 /* 1846 * GLD operations 1847 */ 1848 /* ARGSUSED */ 1849 static int 1850 ipw2200_m_stat(void *arg, uint_t stat, uint64_t *val) 1851 { 1852 ieee80211com_t *ic = (ieee80211com_t *)arg; 1853 struct ipw2200_softc *sc = (struct ipw2200_softc *)ic; 1854 1855 IPW2200_DBG(IPW2200_DBG_GLD, (((struct ipw2200_softc *)arg)->sc_dip, 1856 CE_CONT, 1857 "ipw2200_m_stat(): enter\n")); 1858 /* 1859 * Some of below statistic data are from hardware, some from net80211 1860 */ 1861 switch (stat) { 1862 case MAC_STAT_NOXMTBUF: 1863 *val = ic->ic_stats.is_tx_nobuf; 1864 break; 1865 case MAC_STAT_IERRORS: 1866 *val = sc->sc_stats.sc_rx_len_err; 1867 break; 1868 case MAC_STAT_OERRORS: 1869 *val = sc->sc_stats.sc_tx_discard + 1870 sc->sc_stats.sc_tx_alloc_fail + 1871 sc->sc_stats.sc_tx_encap_fail + 1872 sc->sc_stats.sc_tx_crypto_fail; 1873 break; 1874 case MAC_STAT_RBYTES: 1875 *val = ic->ic_stats.is_rx_bytes; 1876 break; 1877 case MAC_STAT_IPACKETS: 1878 *val = ic->ic_stats.is_rx_frags; 1879 break; 1880 case MAC_STAT_OBYTES: 1881 *val = ic->ic_stats.is_tx_bytes; 1882 break; 1883 case MAC_STAT_OPACKETS: 1884 *val = ic->ic_stats.is_tx_frags; 1885 break; 1886 /* 1887 * Get below from hardware statistic, retraive net80211 value once 1s 1888 */ 1889 case WIFI_STAT_TX_FRAGS: 1890 case WIFI_STAT_MCAST_TX: 1891 case WIFI_STAT_TX_FAILED: 1892 case WIFI_STAT_TX_RETRANS: 1893 /* 1894 * Get blow information from net80211 1895 */ 1896 case WIFI_STAT_RTS_SUCCESS: 1897 case WIFI_STAT_RTS_FAILURE: 1898 case WIFI_STAT_ACK_FAILURE: 1899 case WIFI_STAT_RX_FRAGS: 1900 case WIFI_STAT_MCAST_RX: 1901 case WIFI_STAT_RX_DUPS: 1902 case WIFI_STAT_FCS_ERRORS: 1903 case WIFI_STAT_WEP_ERRORS: 1904 return (ieee80211_stat(ic, stat, val)); 1905 /* 1906 * Need be supported later 1907 */ 1908 case MAC_STAT_IFSPEED: 1909 default: 1910 return (ENOTSUP); 1911 } 1912 return (0); 1913 } 1914 1915 /* ARGSUSED */ 1916 static int 1917 ipw2200_m_multicst(void *arg, boolean_t add, const uint8_t *mca) 1918 { 1919 /* not supported */ 1920 IPW2200_DBG(IPW2200_DBG_GLD, (((struct ipw2200_softc *)arg)->sc_dip, 1921 CE_CONT, 1922 "ipw2200_m_multicst(): enter\n")); 1923 1924 return (0); 1925 } 1926 1927 /* 1928 * Multithread handler for linkstatus, fatal error recovery, get statistic 1929 */ 1930 static void 1931 ipw2200_thread(struct ipw2200_softc *sc) 1932 { 1933 struct ieee80211com *ic = &sc->sc_ic; 1934 enum ieee80211_state ostate; 1935 int32_t nlstate; 1936 int stat_cnt = 0; 1937 1938 IPW2200_DBG(IPW2200_DBG_SOFTINT, (sc->sc_dip, CE_CONT, 1939 "ipw2200_thread(): enter, linkstate %d\n", sc->sc_linkstate)); 1940 1941 mutex_enter(&sc->sc_mflock); 1942 1943 while (sc->sc_mfthread_switch) { 1944 /* 1945 * when radio is off or SUSPEND status, nothing to do 1946 */ 1947 if ((ipw2200_radio_status(sc) == 0) || 1948 sc->sc_flags & IPW2200_FLAG_SUSPEND) { 1949 goto wait_loop; 1950 } 1951 1952 /* 1953 * notify the link state 1954 */ 1955 if (ic->ic_mach && (sc->sc_flags & IPW2200_FLAG_LINK_CHANGE)) { 1956 1957 IPW2200_DBG(IPW2200_DBG_SOFTINT, (sc->sc_dip, CE_CONT, 1958 "ipw2200_thread(): link status --> %d\n", 1959 sc->sc_linkstate)); 1960 1961 sc->sc_flags &= ~IPW2200_FLAG_LINK_CHANGE; 1962 nlstate = sc->sc_linkstate; 1963 1964 mutex_exit(&sc->sc_mflock); 1965 mac_link_update(ic->ic_mach, nlstate); 1966 mutex_enter(&sc->sc_mflock); 1967 } 1968 1969 /* 1970 * recovery fatal error 1971 */ 1972 if (ic->ic_mach && 1973 (sc->sc_flags & IPW2200_FLAG_HW_ERR_RECOVER)) { 1974 1975 IPW2200_DBG(IPW2200_DBG_FATAL, (sc->sc_dip, CE_CONT, 1976 "ipw2200_thread(): " 1977 "try to recover fatal hw error\n")); 1978 1979 sc->sc_flags &= ~IPW2200_FLAG_HW_ERR_RECOVER; 1980 mutex_exit(&sc->sc_mflock); 1981 1982 /* stop again */ 1983 ostate = ic->ic_state; 1984 (void) ipw2200_init(sc); /* Force state machine */ 1985 1986 /* 1987 * workround. Delay for a while after init especially 1988 * when something wrong happened already. 1989 */ 1990 delay(drv_usectohz(delay_fatal_recover)); 1991 1992 /* 1993 * Init scan will recovery the original connection if 1994 * the original state is run 1995 */ 1996 if (ostate != IEEE80211_S_INIT) 1997 ieee80211_begin_scan(ic, 0); 1998 1999 mutex_enter(&sc->sc_mflock); 2000 } 2001 2002 /* 2003 * get statistic, the value will be retrieved by m_stat 2004 */ 2005 if (stat_cnt == 10) { 2006 2007 stat_cnt = 0; /* re-start */ 2008 mutex_exit(&sc->sc_mflock); 2009 ipw2200_get_statistics(sc); 2010 mutex_enter(&sc->sc_mflock); 2011 2012 } else 2013 stat_cnt++; /* until 1s */ 2014 2015 wait_loop: 2016 mutex_exit(&sc->sc_mflock); 2017 delay(drv_usectohz(delay_aux_thread)); 2018 mutex_enter(&sc->sc_mflock); 2019 2020 } 2021 sc->sc_mf_thread = NULL; 2022 cv_signal(&sc->sc_mfthread_cv); 2023 mutex_exit(&sc->sc_mflock); 2024 } 2025 2026 static int 2027 ipw2200_m_start(void *arg) 2028 { 2029 struct ipw2200_softc *sc = (struct ipw2200_softc *)arg; 2030 struct ieee80211com *ic = &sc->sc_ic; 2031 2032 IPW2200_DBG(IPW2200_DBG_GLD, (sc->sc_dip, CE_CONT, 2033 "ipw2200_m_start(): enter\n")); 2034 /* 2035 * initialize ipw2200 hardware, everything ok will start scan 2036 */ 2037 (void) ipw2200_init(sc); 2038 2039 /* 2040 * set the state machine to INIT 2041 */ 2042 ieee80211_new_state(ic, IEEE80211_S_INIT, -1); 2043 2044 sc->sc_flags |= IPW2200_FLAG_RUNNING; 2045 2046 /* 2047 * fix KCF bug. - workaround, need to fix it in net80211 2048 */ 2049 (void) crypto_mech2id(SUN_CKM_RC4); 2050 2051 return (0); 2052 } 2053 2054 static void 2055 ipw2200_m_stop(void *arg) 2056 { 2057 struct ipw2200_softc *sc = (struct ipw2200_softc *)arg; 2058 struct ieee80211com *ic = &sc->sc_ic; 2059 2060 IPW2200_DBG(IPW2200_DBG_GLD, (sc->sc_dip, CE_CONT, 2061 "ipw2200_m_stop(): enter\n")); 2062 2063 ipw2200_stop(sc); 2064 /* 2065 * set the state machine to INIT 2066 */ 2067 ieee80211_new_state(ic, IEEE80211_S_INIT, -1); 2068 2069 sc->sc_flags &= ~IPW2200_FLAG_RUNNING; 2070 } 2071 2072 static int 2073 ipw2200_m_unicst(void *arg, const uint8_t *macaddr) 2074 { 2075 struct ipw2200_softc *sc = (struct ipw2200_softc *)arg; 2076 struct ieee80211com *ic = &sc->sc_ic; 2077 int err; 2078 2079 IPW2200_DBG(IPW2200_DBG_GLD, (sc->sc_dip, CE_CONT, 2080 "ipw2200_m_unicst(): enter\n")); 2081 2082 IPW2200_DBG(IPW2200_DBG_GLD, (sc->sc_dip, CE_CONT, 2083 "ipw2200_m_unicst(): GLD setting MAC address to " 2084 "%02x:%02x:%02x:%02x:%02x:%02x\n", 2085 macaddr[0], macaddr[1], macaddr[2], 2086 macaddr[3], macaddr[4], macaddr[5])); 2087 2088 if (!IEEE80211_ADDR_EQ(ic->ic_macaddr, macaddr)) { 2089 2090 IEEE80211_ADDR_COPY(ic->ic_macaddr, macaddr); 2091 2092 if (sc->sc_flags & IPW2200_FLAG_RUNNING) { 2093 err = ipw2200_config(sc); 2094 if (err != DDI_SUCCESS) { 2095 IPW2200_WARN((sc->sc_dip, CE_WARN, 2096 "ipw2200_m_unicst(): " 2097 "device configuration failed\n")); 2098 goto fail; 2099 } 2100 } 2101 } 2102 return (0); 2103 fail: 2104 return (EIO); 2105 } 2106 2107 static int 2108 ipw2200_m_promisc(void *arg, boolean_t on) 2109 { 2110 /* not supported */ 2111 struct ipw2200_softc *sc = (struct ipw2200_softc *)arg; 2112 2113 IPW2200_DBG(IPW2200_DBG_GLD, (sc->sc_dip, CE_CONT, 2114 "ipw2200_m_promisc(): enter. " 2115 "GLD setting promiscuous mode - %d\n", on)); 2116 2117 return (0); 2118 } 2119 2120 static mblk_t * 2121 ipw2200_m_tx(void *arg, mblk_t *mp) 2122 { 2123 struct ipw2200_softc *sc = (struct ipw2200_softc *)arg; 2124 struct ieee80211com *ic = &sc->sc_ic; 2125 mblk_t *next; 2126 2127 /* 2128 * when driver in on suspend state, freemsgchain directly 2129 */ 2130 if (sc->sc_flags & IPW2200_FLAG_SUSPEND) { 2131 IPW2200_DBG(IPW2200_DBG_SUSPEND, (sc->sc_dip, CE_CONT, 2132 "ipw2200_m_tx(): suspend status, discard msg\n")); 2133 sc->sc_stats.sc_tx_discard++; /* discard data */ 2134 freemsgchain(mp); 2135 return (NULL); 2136 } 2137 2138 /* 2139 * No data frames go out unless we're associated; this 2140 * should not happen as the 802.11 layer does not enable 2141 * the xmit queue until we enter the RUN state. 2142 */ 2143 if (ic->ic_state != IEEE80211_S_RUN) { 2144 IPW2200_DBG(IPW2200_DBG_GLD, (sc->sc_dip, CE_CONT, 2145 "ipw2200_m_tx(): discard msg, ic_state = %u\n", 2146 ic->ic_state)); 2147 sc->sc_stats.sc_tx_discard++; /* discard data */ 2148 freemsgchain(mp); 2149 return (NULL); 2150 } 2151 2152 while (mp != NULL) { 2153 next = mp->b_next; 2154 mp->b_next = NULL; 2155 if (ipw2200_send(ic, mp, IEEE80211_FC0_TYPE_DATA) == 2156 ENOMEM) { 2157 mp->b_next = next; 2158 break; 2159 } 2160 mp = next; 2161 } 2162 return (mp); 2163 } 2164 2165 /* 2166 * ipw2200_send(): send data. softway to handle crypto_encap. 2167 */ 2168 static int 2169 ipw2200_send(ieee80211com_t *ic, mblk_t *mp, uint8_t type) 2170 { 2171 struct ipw2200_softc *sc = (struct ipw2200_softc *)ic; 2172 struct ieee80211_node *in; 2173 struct ieee80211_frame *wh; 2174 struct ieee80211_key *k; 2175 mblk_t *m0, *m; 2176 size_t cnt, off; 2177 struct ipw2200_tx_desc *txdsc; 2178 struct dma_region *dr; 2179 uint32_t idx; 2180 int err = DDI_SUCCESS; 2181 /* tmp pointer, used to pack header and payload */ 2182 uint8_t *p; 2183 2184 ASSERT(mp->b_next == NULL); 2185 IPW2200_DBG(IPW2200_DBG_GLD, (sc->sc_dip, CE_CONT, 2186 "ipw2200_send(): enter\n")); 2187 2188 if ((type & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_DATA) { 2189 /* 2190 * skip all management frames since ipw2200 won't generate any 2191 * management frames. Therefore, drop this package. 2192 */ 2193 freemsg(mp); 2194 err = DDI_FAILURE; 2195 goto fail0; 2196 } 2197 2198 mutex_enter(&sc->sc_tx_lock); 2199 if (sc->sc_flags & IPW2200_FLAG_SUSPEND) { 2200 /* 2201 * when sending data, system runs into suspend status, 2202 * return fail directly 2203 */ 2204 err = ENXIO; 2205 goto fail0; 2206 } 2207 2208 /* 2209 * need 1 empty descriptor 2210 */ 2211 if (sc->sc_tx_free <= IPW2200_TX_RING_MIN) { 2212 mutex_enter(&sc->sc_resched_lock); 2213 IPW2200_DBG(IPW2200_DBG_RING, (sc->sc_dip, CE_WARN, 2214 "ipw2200_send(): no enough descriptors(%d)\n", 2215 sc->sc_tx_free)); 2216 ic->ic_stats.is_tx_nobuf++; /* no enough buffer */ 2217 sc->sc_flags |= IPW2200_FLAG_TX_SCHED; 2218 err = ENOMEM; 2219 mutex_exit(&sc->sc_resched_lock); 2220 goto fail1; 2221 } 2222 IPW2200_DBG(IPW2200_DBG_RING, (sc->sc_dip, CE_CONT, 2223 "ipw2200_send(): tx-free=%d,tx-curr=%d\n", 2224 sc->sc_tx_free, sc->sc_tx_cur)); 2225 2226 /* 2227 * put the mp into one blk, and use it to do the crypto_encap 2228 * if necessaary. 2229 */ 2230 m = allocb(msgdsize(mp) + 32, BPRI_MED); 2231 if (m == NULL) { /* can not alloc buf, drop this package */ 2232 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 2233 "ipw2200_send(): msg allocation failed\n")); 2234 freemsg(mp); 2235 sc->sc_stats.sc_tx_alloc_fail++; /* alloc fail */ 2236 ic->ic_stats.is_tx_failed++; /* trans failed */ 2237 err = DDI_FAILURE; 2238 goto fail1; 2239 } 2240 for (off = 0, m0 = mp; m0 != NULL; m0 = m0->b_cont) { 2241 cnt = MBLKL(m0); 2242 (void) memcpy(m->b_rptr + off, m0->b_rptr, cnt); 2243 off += cnt; 2244 } 2245 m->b_wptr += off; 2246 2247 /* 2248 * find tx_node, and encapsulate the data 2249 */ 2250 wh = (struct ieee80211_frame *)m->b_rptr; 2251 in = ieee80211_find_txnode(ic, wh->i_addr1); 2252 if (in == NULL) { /* can not find the tx node, drop the package */ 2253 sc->sc_stats.sc_tx_encap_fail++; /* tx encap fail */ 2254 ic->ic_stats.is_tx_failed++; /* trans failed */ 2255 freemsg(mp); 2256 err = DDI_FAILURE; 2257 goto fail2; 2258 } 2259 in->in_inact = 0; 2260 2261 (void) ieee80211_encap(ic, m, in); 2262 ieee80211_free_node(in); 2263 2264 if (wh->i_fc[1] & IEEE80211_FC1_WEP) { 2265 k = ieee80211_crypto_encap(ic, m); 2266 if (k == NULL) { /* can not get the key, drop packages */ 2267 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 2268 "ipw2200_send(): " 2269 "Encrypting 802.11 frame failed\n")); 2270 sc->sc_stats.sc_tx_crypto_fail++; /* tx encap fail */ 2271 ic->ic_stats.is_tx_failed++; /* trans failed */ 2272 freemsg(mp); 2273 err = DDI_FAILURE; 2274 goto fail2; 2275 } 2276 wh = (struct ieee80211_frame *)m->b_rptr; 2277 } 2278 2279 /* 2280 * get txdsc 2281 */ 2282 idx = sc->sc_tx_cur; 2283 txdsc = &sc->sc_txdsc[idx]; 2284 (void) memset(txdsc, 0, sizeof (*txdsc)); 2285 /* 2286 * extract header from message 2287 */ 2288 p = (uint8_t *)&txdsc->wh; 2289 off = sizeof (struct ieee80211_frame); 2290 (void) memcpy(p, m->b_rptr, off); 2291 /* 2292 * extract payload from message 2293 */ 2294 dr = &sc->sc_dma_txbufs[idx]; 2295 p = sc->sc_txbufs[idx]; 2296 cnt = MBLKL(m); 2297 (void) memcpy(p, m->b_rptr + off, cnt - off); 2298 cnt -= off; 2299 2300 txdsc->hdr.type = IPW2200_HDR_TYPE_DATA; 2301 txdsc->hdr.flags = IPW2200_HDR_FLAG_IRQ; 2302 txdsc->cmd = IPW2200_DATA_CMD_TX; 2303 txdsc->len = LE_16(cnt); 2304 txdsc->flags = 0; 2305 2306 if (ic->ic_opmode == IEEE80211_M_IBSS) { 2307 if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) 2308 txdsc->flags |= IPW2200_DATA_FLAG_NEED_ACK; 2309 } else if (!IEEE80211_IS_MULTICAST(wh->i_addr3)) 2310 txdsc->flags |= IPW2200_DATA_FLAG_NEED_ACK; 2311 2312 /* always set it to none wep, because it's handled by software */ 2313 txdsc->flags |= IPW2200_DATA_FLAG_NO_WEP; 2314 2315 if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) 2316 txdsc->flags |= IPW2200_DATA_FLAG_SHPREAMBLE; 2317 2318 txdsc->nseg = LE_32(1); 2319 txdsc->seg_addr[0] = LE_32(dr->dr_pbase); 2320 txdsc->seg_len[0] = LE_32(cnt); 2321 2322 /* 2323 * DMA sync: buffer and desc 2324 */ 2325 (void) ddi_dma_sync(dr->dr_hnd, 0, 2326 IPW2200_TXBUF_SIZE, DDI_DMA_SYNC_FORDEV); 2327 (void) ddi_dma_sync(sc->sc_dma_txdsc.dr_hnd, 2328 idx * sizeof (struct ipw2200_tx_desc), 2329 sizeof (struct ipw2200_tx_desc), DDI_DMA_SYNC_FORDEV); 2330 2331 sc->sc_tx_cur = RING_FORWARD(sc->sc_tx_cur, 1, IPW2200_TX_RING_SIZE); 2332 sc->sc_tx_free--; 2333 2334 /* 2335 * update txcur 2336 */ 2337 ipw2200_csr_put32(sc, IPW2200_CSR_TX1_WRITE_INDEX, sc->sc_tx_cur); 2338 2339 /* 2340 * success, free the original message 2341 */ 2342 if (mp) 2343 freemsg(mp); 2344 fail2: 2345 if (m) 2346 freemsg(m); 2347 fail1: 2348 mutex_exit(&sc->sc_tx_lock); 2349 fail0: 2350 IPW2200_DBG(IPW2200_DBG_GLD, (sc->sc_dip, CE_CONT, 2351 "ipw2200_send(): exit - err=%d\n", err)); 2352 2353 return (err); 2354 } 2355 2356 /* 2357 * IOCTL handlers 2358 */ 2359 #define IEEE80211_IOCTL_REQUIRED (1) 2360 #define IEEE80211_IOCTL_NOT_REQUIRED (0) 2361 static void 2362 ipw2200_m_ioctl(void *arg, queue_t *q, mblk_t *m) 2363 { 2364 struct ipw2200_softc *sc = (struct ipw2200_softc *)arg; 2365 struct ieee80211com *ic = &sc->sc_ic; 2366 uint32_t err; 2367 2368 IPW2200_DBG(IPW2200_DBG_GLD, (sc->sc_dip, CE_CONT, 2369 "ipw2200_m_ioctl(): enter\n")); 2370 2371 /* 2372 * Check whether or not need to handle this in net80211 2373 * 2374 */ 2375 if (ipw2200_ioctl(sc, q, m) == IEEE80211_IOCTL_NOT_REQUIRED) 2376 return; 2377 2378 err = ieee80211_ioctl(ic, q, m); 2379 if (err == ENETRESET) { 2380 if (sc->sc_flags & IPW2200_FLAG_RUNNING) { 2381 (void) ipw2200_m_start(sc); 2382 (void) ieee80211_new_state(ic, 2383 IEEE80211_S_SCAN, -1); 2384 } 2385 } 2386 if (err == ERESTART) { 2387 if (sc->sc_flags & IPW2200_FLAG_RUNNING) 2388 (void) ipw2200_chip_reset(sc); 2389 } 2390 } 2391 static int 2392 ipw2200_ioctl(struct ipw2200_softc *sc, queue_t *q, mblk_t *m) 2393 { 2394 struct iocblk *iocp; 2395 uint32_t len, ret, cmd, mblen; 2396 mblk_t *m0; 2397 boolean_t need_privilege; 2398 boolean_t need_net80211; 2399 2400 mblen = MBLKL(m); 2401 if (mblen < sizeof (struct iocblk)) { 2402 IPW2200_DBG(IPW2200_DBG_IOCTL, (sc->sc_dip, CE_CONT, 2403 "ipw2200_ioctl(): ioctl buffer too short, %u\n", 2404 mblen)); 2405 miocnak(q, m, 0, EINVAL); 2406 /* 2407 * Buf not enough, do not need net80211 either 2408 */ 2409 return (IEEE80211_IOCTL_NOT_REQUIRED); 2410 } 2411 2412 /* 2413 * Validate the command 2414 */ 2415 iocp = (struct iocblk *)(uintptr_t)m->b_rptr; 2416 iocp->ioc_error = 0; 2417 cmd = iocp->ioc_cmd; 2418 need_privilege = B_TRUE; 2419 switch (cmd) { 2420 case WLAN_SET_PARAM: 2421 case WLAN_COMMAND: 2422 break; 2423 case WLAN_GET_PARAM: 2424 need_privilege = B_FALSE; 2425 break; 2426 default: 2427 IPW2200_DBG(IPW2200_DBG_IOCTL, (sc->sc_dip, CE_CONT, 2428 "ipw2200_ioctl(): unknown cmd 0x%x", cmd)); 2429 miocnak(q, m, 0, EINVAL); 2430 /* 2431 * Unknown cmd, do not need net80211 either 2432 */ 2433 return (IEEE80211_IOCTL_NOT_REQUIRED); 2434 } 2435 2436 if (need_privilege && (ret = secpolicy_dl_config(iocp->ioc_cr)) != 0) { 2437 miocnak(q, m, 0, ret); 2438 /* 2439 * privilege check fail, do not need net80211 either 2440 */ 2441 return (IEEE80211_IOCTL_NOT_REQUIRED); 2442 } 2443 2444 /* 2445 * sanity check 2446 */ 2447 m0 = m->b_cont; 2448 if (iocp->ioc_count == 0 || iocp->ioc_count < sizeof (wldp_t) || 2449 m0 == NULL) { 2450 miocnak(q, m, 0, EINVAL); 2451 /* 2452 * invalid format, do not need net80211 either 2453 */ 2454 return (IEEE80211_IOCTL_NOT_REQUIRED); 2455 } 2456 /* 2457 * assuming single data block 2458 */ 2459 if (m0->b_cont) { 2460 freemsg(m0->b_cont); 2461 m0->b_cont = NULL; 2462 } 2463 2464 need_net80211 = B_FALSE; 2465 ret = ipw2200_getset(sc, m0, cmd, &need_net80211); 2466 if (!need_net80211) { 2467 len = msgdsize(m0); 2468 2469 IPW2200_DBG(IPW2200_DBG_IOCTL, (sc->sc_dip, CE_CONT, 2470 "ipw2200_ioctl(): go to call miocack with " 2471 "ret = %d, len = %d\n", ret, len)); 2472 miocack(q, m, len, ret); 2473 return (IEEE80211_IOCTL_NOT_REQUIRED); 2474 } 2475 2476 /* 2477 * IEEE80211_IOCTL - need net80211 handle 2478 */ 2479 return (IEEE80211_IOCTL_REQUIRED); 2480 } 2481 2482 static int 2483 ipw2200_getset(struct ipw2200_softc *sc, mblk_t *m, uint32_t cmd, 2484 boolean_t *need_net80211) 2485 { 2486 wldp_t *infp, *outfp; 2487 uint32_t id; 2488 int ret; 2489 2490 infp = (wldp_t *)(uintptr_t)m->b_rptr; 2491 outfp = (wldp_t *)(uintptr_t)m->b_rptr; 2492 outfp->wldp_result = WL_NOTSUPPORTED; 2493 2494 id = infp->wldp_id; 2495 IPW2200_DBG(IPW2200_DBG_IOCTL, (sc->sc_dip, CE_CONT, 2496 "ipw2200_getset(): id = 0x%x\n", id)); 2497 switch (id) { 2498 case WL_RADIO: /* which is not supported by net80211 */ 2499 ret = iwi_wificfg_radio(sc, cmd, outfp); 2500 break; 2501 case WL_DESIRED_RATES: /* hardware doesn't support fix-rates */ 2502 ret = iwi_wificfg_desrates(outfp); 2503 break; 2504 default: 2505 /* 2506 * The wifi IOCTL net80211 supported: 2507 * case WL_ESSID: 2508 * case WL_BSSID: 2509 * case WL_WEP_KEY_TAB: 2510 * case WL_WEP_KEY_ID: 2511 * case WL_AUTH_MODE: 2512 * case WL_ENCRYPTION: 2513 * case WL_BSS_TYPE: 2514 * case WL_ESS_LIST: 2515 * case WL_LINKSTATUS: 2516 * case WL_RSSI: 2517 * case WL_SCAN: 2518 * case WL_LOAD_DEFAULTS: 2519 * case WL_DISASSOCIATE: 2520 */ 2521 2522 /* 2523 * When radio is off, need to ignore all ioctl. What need to 2524 * do is to check radio status firstly. If radio is ON, pass 2525 * it to net80211, otherwise, return to upper layer directly. 2526 * 2527 * Considering the WL_SUCCESS also means WL_CONNECTED for 2528 * checking linkstatus, one exception for WL_LINKSTATUS is to 2529 * let net80211 handle it. 2530 */ 2531 if ((ipw2200_radio_status(sc) == 0) && 2532 (id != WL_LINKSTATUS)) { 2533 2534 IPW2200_REPORT((sc->sc_dip, CE_CONT, 2535 "iwi: radio is OFF\n")); 2536 2537 outfp->wldp_length = WIFI_BUF_OFFSET; 2538 outfp->wldp_result = WL_SUCCESS; 2539 ret = 0; 2540 break; 2541 } 2542 2543 *need_net80211 = B_TRUE; /* let net80211 do the rest */ 2544 return (0); 2545 } 2546 /* 2547 * we will overwrite everything 2548 */ 2549 m->b_wptr = m->b_rptr + outfp->wldp_length; 2550 return (ret); 2551 } 2552 2553 static int 2554 iwi_wificfg_radio(struct ipw2200_softc *sc, uint32_t cmd, wldp_t *outfp) 2555 { 2556 uint32_t ret = ENOTSUP; 2557 2558 switch (cmd) { 2559 case WLAN_GET_PARAM: 2560 *(wl_linkstatus_t *)(outfp->wldp_buf) = 2561 ipw2200_radio_status(sc); 2562 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_linkstatus_t); 2563 outfp->wldp_result = WL_SUCCESS; 2564 ret = 0; /* command success */ 2565 break; 2566 case WLAN_SET_PARAM: 2567 default: 2568 break; 2569 } 2570 return (ret); 2571 } 2572 2573 static int 2574 iwi_wificfg_desrates(wldp_t *outfp) 2575 { 2576 /* return success, but with result NOTSUPPORTED */ 2577 outfp->wldp_length = WIFI_BUF_OFFSET; 2578 outfp->wldp_result = WL_NOTSUPPORTED; 2579 return (0); 2580 } 2581 /* End of IOCTL Handlers */ 2582 2583 void 2584 ipw2200_fix_channel(struct ieee80211com *ic, mblk_t *m) 2585 { 2586 struct ieee80211_frame *wh; 2587 uint8_t subtype; 2588 uint8_t *frm, *efrm; 2589 2590 wh = (struct ieee80211_frame *)m->b_rptr; 2591 2592 if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_MGT) 2593 return; 2594 2595 subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; 2596 2597 if (subtype != IEEE80211_FC0_SUBTYPE_BEACON && 2598 subtype != IEEE80211_FC0_SUBTYPE_PROBE_RESP) 2599 return; 2600 2601 /* 2602 * assume the message contains only 1 block 2603 */ 2604 frm = (uint8_t *)(wh + 1); 2605 efrm = (uint8_t *)m->b_wptr; 2606 frm += 12; /* skip tstamp, bintval and capinfo fields */ 2607 while (frm < efrm) { 2608 if (*frm == IEEE80211_ELEMID_DSPARMS) 2609 #if IEEE80211_CHAN_MAX < 255 2610 if (frm[2] <= IEEE80211_CHAN_MAX) 2611 #endif 2612 ic->ic_curchan = &ic->ic_sup_channels[frm[2]]; 2613 frm += frm[1] + 2; 2614 } 2615 } 2616 2617 static void 2618 ipw2200_rcv_frame(struct ipw2200_softc *sc, struct ipw2200_frame *frame) 2619 { 2620 struct ieee80211com *ic = &sc->sc_ic; 2621 uint8_t *data = (uint8_t *)frame; 2622 uint32_t len; 2623 struct ieee80211_frame *wh; 2624 struct ieee80211_node *in; 2625 mblk_t *m; 2626 2627 len = LE_16(frame->len); 2628 if ((len < sizeof (struct ieee80211_frame_min)) || 2629 (len > IPW2200_RXBUF_SIZE)) { 2630 IPW2200_DBG(IPW2200_DBG_RX, (sc->sc_dip, CE_CONT, 2631 "ipw2200_rcv_frame(): bad frame length=%u\n", 2632 LE_16(frame->len))); 2633 sc->sc_stats.sc_rx_len_err++; /* length doesn't work */ 2634 return; 2635 } 2636 IPW2200_DBG(IPW2200_DBG_RX, (sc->sc_dip, CE_CONT, 2637 "ipw2200_rcv_frame(): chan = %d, length = %d\n", frame->chan, len)); 2638 2639 /* 2640 * Skip the frame header, get the real data from the input 2641 */ 2642 data += sizeof (struct ipw2200_frame); 2643 2644 m = allocb(len, BPRI_MED); 2645 if (m) { 2646 (void) memcpy(m->b_wptr, data, len); 2647 m->b_wptr += len; 2648 2649 if (ic->ic_state == IEEE80211_S_SCAN) { 2650 ic->ic_ibss_chan = &ic->ic_sup_channels[frame->chan]; 2651 ipw2200_fix_channel(ic, m); 2652 } 2653 wh = (struct ieee80211_frame *)m->b_rptr; 2654 2655 in = ieee80211_find_rxnode(ic, wh); 2656 2657 IPW2200_DBG(IPW2200_DBG_RX, (sc->sc_dip, CE_CONT, 2658 "ipw2200_rcv_frame(): " 2659 "type = %x, subtype = %x, i_fc[1] = %x, " 2660 "ni_esslen:%d, ni_essid[0-5]:%c%c%c%c%c%c\n", 2661 wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK, 2662 wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK, 2663 wh->i_fc[1] & IEEE80211_FC1_WEP, 2664 in->in_esslen, 2665 in->in_essid[0], in->in_essid[1], in->in_essid[2], 2666 in->in_essid[3], in->in_essid[4], in->in_essid[5])); 2667 2668 (void) ieee80211_input(ic, m, in, frame->rssi_dbm, 0); 2669 2670 ieee80211_free_node(in); 2671 } 2672 else 2673 IPW2200_WARN((sc->sc_dip, CE_WARN, 2674 "ipw2200_rcv_frame(): " 2675 "cannot allocate receive message(%u)\n", 2676 LE_16(frame->len))); 2677 } 2678 2679 static void 2680 ipw2200_rcv_notif(struct ipw2200_softc *sc, struct ipw2200_notif *notif) 2681 { 2682 struct ieee80211com *ic = &sc->sc_ic; 2683 struct ipw2200_notif_association *assoc; 2684 struct ipw2200_notif_authentication *auth; 2685 uint8_t *ndata = (uint8_t *)notif; 2686 2687 IPW2200_DBG(IPW2200_DBG_NOTIF, (sc->sc_dip, CE_CONT, 2688 "ipw2200_rcv_notif(): type=%u\n", notif->type)); 2689 2690 ndata += sizeof (struct ipw2200_notif); 2691 switch (notif->type) { 2692 case IPW2200_NOTIF_TYPE_ASSOCIATION: 2693 assoc = (struct ipw2200_notif_association *)ndata; 2694 2695 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 2696 "ipw2200_rcv_notif(): association=%u,%u\n", 2697 assoc->state, assoc->status)); 2698 2699 switch (assoc->state) { 2700 case IPW2200_ASSOC_SUCCESS: 2701 sc->sc_flags |= IPW2200_FLAG_ASSOCIATED; 2702 ieee80211_new_state(ic, IEEE80211_S_RUN, -1); 2703 break; 2704 case IPW2200_ASSOC_FAIL: 2705 sc->sc_flags &= ~IPW2200_FLAG_ASSOCIATED; 2706 ieee80211_begin_scan(ic, 1); 2707 break; 2708 default: 2709 break; 2710 } 2711 break; 2712 2713 case IPW2200_NOTIF_TYPE_AUTHENTICATION: 2714 auth = (struct ipw2200_notif_authentication *)ndata; 2715 2716 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 2717 "ipw2200_rcv_notif(): authentication=%u\n", auth->state)); 2718 2719 switch (auth->state) { 2720 case IPW2200_AUTH_SUCCESS: 2721 ieee80211_new_state(ic, IEEE80211_S_ASSOC, -1); 2722 break; 2723 case IPW2200_AUTH_FAIL: 2724 sc->sc_flags &= ~IPW2200_FLAG_ASSOCIATED; 2725 break; 2726 default: 2727 IPW2200_DBG(IPW2200_DBG_NOTIF, (sc->sc_dip, CE_CONT, 2728 "ipw2200_rcv_notif(): " 2729 "unknown authentication state(%u)\n", auth->state)); 2730 break; 2731 } 2732 break; 2733 2734 case IPW2200_NOTIF_TYPE_SCAN_CHANNEL: 2735 IPW2200_DBG(IPW2200_DBG_SCAN, (sc->sc_dip, CE_CONT, 2736 "ipw2200_rcv_notif(): scan-channel=%u\n", 2737 ((struct ipw2200_notif_scan_channel *)ndata)->nchan)); 2738 break; 2739 2740 case IPW2200_NOTIF_TYPE_SCAN_COMPLETE: 2741 IPW2200_DBG(IPW2200_DBG_SCAN, (sc->sc_dip, CE_CONT, 2742 "ipw2200_rcv_notif():scan-completed,(%u,%u)\n", 2743 ((struct ipw2200_notif_scan_complete *)ndata)->nchan, 2744 ((struct ipw2200_notif_scan_complete *)ndata)->status)); 2745 2746 /* 2747 * scan complete 2748 */ 2749 sc->sc_flags &= ~IPW2200_FLAG_SCANNING; 2750 ieee80211_end_scan(ic); 2751 break; 2752 2753 case IPW2200_NOTIF_TYPE_BEACON: 2754 case IPW2200_NOTIF_TYPE_CALIBRATION: 2755 case IPW2200_NOTIF_TYPE_NOISE: 2756 /* 2757 * just ignore 2758 */ 2759 break; 2760 default: 2761 IPW2200_DBG(IPW2200_DBG_NOTIF, (sc->sc_dip, CE_CONT, 2762 "ipw2200_rcv_notif(): unknown notification type(%u)\n", 2763 notif->type)); 2764 break; 2765 } 2766 } 2767 2768 static uint_t 2769 ipw2200_intr(caddr_t arg) 2770 { 2771 struct ipw2200_softc *sc = (struct ipw2200_softc *)(uintptr_t)arg; 2772 struct ieee80211com *ic = &sc->sc_ic; 2773 uint32_t ireg, ridx, len, i; 2774 uint8_t *p, *rxbuf; 2775 struct dma_region *dr; 2776 struct ipw2200_hdr *hdr; 2777 uint32_t widx; 2778 2779 /* when it is on suspend, unclaim all interrupt directly */ 2780 if (sc->sc_flags & IPW2200_FLAG_SUSPEND) 2781 return (DDI_INTR_UNCLAIMED); 2782 2783 /* unclaim interrupt when it is not for iwi */ 2784 ireg = ipw2200_csr_get32(sc, IPW2200_CSR_INTR); 2785 if (ireg == 0xffffffff || 2786 !(ireg & IPW2200_INTR_MASK_ALL)) 2787 return (DDI_INTR_UNCLAIMED); 2788 2789 /* 2790 * mask all interrupts 2791 */ 2792 ipw2200_csr_put32(sc, IPW2200_CSR_INTR_MASK, 0); 2793 2794 /* 2795 * acknowledge all fired interrupts 2796 */ 2797 ipw2200_csr_put32(sc, IPW2200_CSR_INTR, ireg); 2798 2799 IPW2200_DBG(IPW2200_DBG_INT, (sc->sc_dip, CE_CONT, 2800 "ipw2200_intr(): enter. interrupt fired, int=0x%08x\n", ireg)); 2801 2802 if (ireg & IPW2200_INTR_MASK_ERR) { 2803 2804 IPW2200_DBG(IPW2200_DBG_FATAL, (sc->sc_dip, CE_CONT, 2805 "ipw2200 interrupt(): int= 0x%08x\n", ireg)); 2806 2807 /* 2808 * inform mfthread to recover hw error by stopping it 2809 */ 2810 mutex_enter(&sc->sc_mflock); 2811 sc->sc_flags |= IPW2200_FLAG_HW_ERR_RECOVER; 2812 mutex_exit(&sc->sc_mflock); 2813 2814 goto enable_interrupt; 2815 } 2816 2817 /* 2818 * FW intr 2819 */ 2820 if (ireg & IPW2200_INTR_FW_INITED) { 2821 mutex_enter(&sc->sc_ilock); 2822 sc->sc_fw_ok = 1; 2823 cv_signal(&sc->sc_fw_cond); 2824 mutex_exit(&sc->sc_ilock); 2825 } 2826 2827 /* 2828 * Radio OFF 2829 */ 2830 if (ireg & IPW2200_INTR_RADIO_OFF) { 2831 IPW2200_REPORT((sc->sc_dip, CE_CONT, 2832 "ipw2200_intr(): radio is OFF\n")); 2833 2834 /* 2835 * Stop hardware, will notify LINK is down. 2836 * Need a better scan solution to ensure 2837 * table has right value. 2838 */ 2839 ipw2200_stop(sc); 2840 } 2841 2842 /* 2843 * CMD intr 2844 */ 2845 if (ireg & IPW2200_INTR_CMD_TRANSFER) { 2846 mutex_enter(&sc->sc_cmd_lock); 2847 ridx = ipw2200_csr_get32(sc, 2848 IPW2200_CSR_CMD_READ_INDEX); 2849 i = RING_FORWARD(sc->sc_cmd_cur, 2850 sc->sc_cmd_free, IPW2200_CMD_RING_SIZE); 2851 len = RING_FLEN(i, ridx, IPW2200_CMD_RING_SIZE); 2852 2853 IPW2200_DBG(IPW2200_DBG_INT, (sc->sc_dip, CE_CONT, 2854 "ipw2200_intr(): cmd-ring,i=%u,ridx=%u,len=%u\n", 2855 i, ridx, len)); 2856 2857 if (len > 0) { 2858 sc->sc_cmd_free += len; 2859 cv_signal(&sc->sc_cmd_cond); 2860 } 2861 for (; i != ridx; 2862 i = RING_FORWARD(i, 1, IPW2200_CMD_RING_SIZE)) 2863 sc->sc_done[i] = 1; 2864 mutex_exit(&sc->sc_cmd_lock); 2865 2866 mutex_enter(&sc->sc_ilock); 2867 cv_signal(&sc->sc_cmd_status_cond); 2868 mutex_exit(&sc->sc_ilock); 2869 } 2870 2871 /* 2872 * RX intr 2873 */ 2874 if (ireg & IPW2200_INTR_RX_TRANSFER) { 2875 ridx = ipw2200_csr_get32(sc, 2876 IPW2200_CSR_RX_READ_INDEX); 2877 widx = ipw2200_csr_get32(sc, 2878 IPW2200_CSR_RX_WRITE_INDEX); 2879 2880 IPW2200_DBG(IPW2200_DBG_INT, (sc->sc_dip, CE_CONT, 2881 "ipw2200_intr(): rx-ring,widx=%u,ridx=%u\n", 2882 ridx, widx)); 2883 2884 for (; sc->sc_rx_cur != ridx; 2885 sc->sc_rx_cur = RING_FORWARD(sc->sc_rx_cur, 1, 2886 IPW2200_RX_RING_SIZE)) { 2887 i = sc->sc_rx_cur; 2888 rxbuf = sc->sc_rxbufs[i]; 2889 dr = &sc->sc_dma_rxbufs[i]; 2890 2891 /* 2892 * DMA sync 2893 */ 2894 (void) ddi_dma_sync(dr->dr_hnd, 0, 2895 IPW2200_RXBUF_SIZE, DDI_DMA_SYNC_FORKERNEL); 2896 /* 2897 * Get rx header(hdr) and rx data(p) from rxbuf 2898 */ 2899 p = rxbuf; 2900 hdr = (struct ipw2200_hdr *)p; 2901 p += sizeof (struct ipw2200_hdr); 2902 2903 IPW2200_DBG(IPW2200_DBG_INT, (sc->sc_dip, CE_CONT, 2904 "ipw2200_intr(): Rx hdr type %u\n", 2905 hdr->type)); 2906 2907 switch (hdr->type) { 2908 case IPW2200_HDR_TYPE_FRAME: 2909 ipw2200_rcv_frame(sc, 2910 (struct ipw2200_frame *)p); 2911 break; 2912 2913 case IPW2200_HDR_TYPE_NOTIF: 2914 ipw2200_rcv_notif(sc, 2915 (struct ipw2200_notif *)p); 2916 break; 2917 2918 default: 2919 IPW2200_DBG(IPW2200_DBG_INT, (sc->sc_dip, 2920 CE_CONT, 2921 "ipw2200_intr(): unknown Rx hdr type %u\n", 2922 hdr->type)); 2923 break; 2924 } 2925 } 2926 /* 2927 * write sc_rx_cur backward 1 step into RX_WRITE_INDEX 2928 */ 2929 ipw2200_csr_put32(sc, IPW2200_CSR_RX_WRITE_INDEX, 2930 RING_BACKWARD(sc->sc_rx_cur, 1, 2931 IPW2200_RX_RING_SIZE)); 2932 } 2933 2934 /* 2935 * TX intr 2936 */ 2937 if (ireg & IPW2200_INTR_TX1_TRANSFER) { 2938 mutex_enter(&sc->sc_tx_lock); 2939 ridx = ipw2200_csr_get32(sc, 2940 IPW2200_CSR_TX1_READ_INDEX); 2941 len = RING_FLEN(RING_FORWARD(sc->sc_tx_cur, 2942 sc->sc_tx_free, IPW2200_TX_RING_SIZE), 2943 ridx, IPW2200_TX_RING_SIZE); 2944 sc->sc_tx_free += len; 2945 IPW2200_DBG(IPW2200_DBG_RING, (sc->sc_dip, CE_CONT, 2946 "ipw2200_intr(): tx-ring,ridx=%u,len=%u\n", 2947 ridx, len)); 2948 mutex_exit(&sc->sc_tx_lock); 2949 2950 mutex_enter(&sc->sc_resched_lock); 2951 if ((sc->sc_tx_free > IPW2200_TX_RING_MIN) && 2952 (sc->sc_flags & IPW2200_FLAG_TX_SCHED)) { 2953 IPW2200_DBG(IPW2200_DBG_RING, (sc->sc_dip, 2954 CE_CONT, 2955 "ipw2200_intr(): Need Reschedule!")); 2956 sc->sc_flags &= ~IPW2200_FLAG_TX_SCHED; 2957 mac_tx_update(ic->ic_mach); 2958 } 2959 mutex_exit(&sc->sc_resched_lock); 2960 } 2961 2962 enable_interrupt: 2963 /* 2964 * enable all interrupts 2965 */ 2966 ipw2200_csr_put32(sc, IPW2200_CSR_INTR_MASK, IPW2200_INTR_MASK_ALL); 2967 2968 return (DDI_INTR_CLAIMED); 2969 } 2970 2971 2972 /* 2973 * Module Loading Data & Entry Points 2974 */ 2975 DDI_DEFINE_STREAM_OPS(ipw2200_devops, nulldev, nulldev, ipw2200_attach, 2976 ipw2200_detach, nodev, NULL, D_MP, NULL, ipw2200_quiesce); 2977 2978 static struct modldrv ipw2200_modldrv = { 2979 &mod_driverops, 2980 ipw2200_ident, 2981 &ipw2200_devops 2982 }; 2983 2984 static struct modlinkage ipw2200_modlinkage = { 2985 MODREV_1, 2986 &ipw2200_modldrv, 2987 NULL 2988 }; 2989 2990 int 2991 _init(void) 2992 { 2993 int status; 2994 2995 status = ddi_soft_state_init(&ipw2200_ssp, 2996 sizeof (struct ipw2200_softc), 1); 2997 if (status != DDI_SUCCESS) 2998 return (status); 2999 3000 mac_init_ops(&ipw2200_devops, IPW2200_DRV_NAME); 3001 status = mod_install(&ipw2200_modlinkage); 3002 if (status != DDI_SUCCESS) { 3003 mac_fini_ops(&ipw2200_devops); 3004 ddi_soft_state_fini(&ipw2200_ssp); 3005 } 3006 3007 return (status); 3008 } 3009 3010 int 3011 _fini(void) 3012 { 3013 int status; 3014 3015 status = mod_remove(&ipw2200_modlinkage); 3016 if (status == DDI_SUCCESS) { 3017 mac_fini_ops(&ipw2200_devops); 3018 ddi_soft_state_fini(&ipw2200_ssp); 3019 } 3020 3021 return (status); 3022 } 3023 3024 int 3025 _info(struct modinfo *modinfop) 3026 { 3027 return (mod_info(&ipw2200_modlinkage, modinfop)); 3028 } 3029