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