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