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