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