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 1456 /* 1457 * Compact supported channel number(2G) into a single buffer 1458 */ 1459 cnt = 0; 1460 for (i = 0; i <= IEEE80211_CHAN_MAX; i++) { 1461 if (IEEE80211_IS_CHAN_2GHZ(&ic->ic_sup_channels[i]) && 1462 isset(ic->ic_chan_active, i)) { 1463 *++ch = (uint8_t)i; 1464 cnt++; 1465 } 1466 } 1467 *(ch - cnt) = IPW2200_CHAN_2GHZ | cnt; 1468 1469 return (ipw2200_cmd(sc, IPW2200_CMD_SCAN, &scan, sizeof (scan), 1)); 1470 } 1471 1472 int 1473 ipw2200_auth_and_assoc(struct ipw2200_softc *sc) 1474 { 1475 struct ieee80211com *ic = &sc->sc_ic; 1476 struct ieee80211_node *in = ic->ic_bss; 1477 struct ipw2200_configuration cfg; 1478 struct ipw2200_rateset rs; 1479 struct ipw2200_associate assoc; 1480 uint32_t data; 1481 int err; 1482 1483 /* 1484 * set the confiuration 1485 */ 1486 if (IEEE80211_IS_CHAN_2GHZ(in->in_chan)) { 1487 /* enable b/g auto-detection */ 1488 (void) memset(&cfg, 0, sizeof (cfg)); 1489 cfg.bluetooth_coexistence = 1; 1490 cfg.multicast_enabled = 1; 1491 cfg.use_protection = 1; 1492 cfg.answer_pbreq = 1; 1493 cfg.noise_reported = 1; 1494 err = ipw2200_cmd(sc, IPW2200_CMD_SET_CONFIG, 1495 &cfg, sizeof (cfg), 1); 1496 if (err != DDI_SUCCESS) 1497 return (err); 1498 } 1499 1500 /* 1501 * set the essid, may be null/hidden AP 1502 */ 1503 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 1504 "ipw2200_auth_and_assoc(): " 1505 "setting ESSID to(%u),%c%c%c%c%c%c%c%c\n", 1506 in->in_esslen, 1507 in->in_essid[0], in->in_essid[1], 1508 in->in_essid[2], in->in_essid[3], 1509 in->in_essid[4], in->in_essid[5], 1510 in->in_essid[6], in->in_essid[7])); 1511 err = ipw2200_cmd(sc, IPW2200_CMD_SET_ESSID, in->in_essid, 1512 in->in_esslen, 1); 1513 if (err != DDI_SUCCESS) 1514 return (err); 1515 1516 /* 1517 * set the rate: the rate set has already been ''negocitated'' 1518 */ 1519 rs.mode = IEEE80211_IS_CHAN_5GHZ(in->in_chan) ? 1520 IPW2200_MODE_11A : IPW2200_MODE_11G; 1521 rs.type = IPW2200_RATESET_TYPE_NEGOCIATED; 1522 rs.nrates = in->in_rates.ir_nrates; 1523 (void) memcpy(rs.rates, in->in_rates.ir_rates, in->in_rates.ir_nrates); 1524 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 1525 "ipw2200_auth_and_assoc(): " 1526 "setting negotiated rates to(nrates = %u)\n", rs.nrates)); 1527 1528 err = ipw2200_cmd(sc, IPW2200_CMD_SET_RATES, &rs, sizeof (rs), 1); 1529 if (err != DDI_SUCCESS) 1530 return (err); 1531 1532 /* 1533 * set the sensitive 1534 */ 1535 data = LE_32(in->in_rssi); 1536 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 1537 "ipw2200_auth_and_assoc(): " 1538 "setting sensitivity to rssi:(%u)\n", (uint8_t)in->in_rssi)); 1539 err = ipw2200_cmd(sc, IPW2200_CMD_SET_SENSITIVITY, 1540 &data, sizeof (data), 1); 1541 if (err != DDI_SUCCESS) 1542 return (err); 1543 1544 /* 1545 * invoke command associate 1546 */ 1547 (void) memset(&assoc, 0, sizeof (assoc)); 1548 assoc.mode = IEEE80211_IS_CHAN_5GHZ(in->in_chan) ? 1549 IPW2200_MODE_11A : IPW2200_MODE_11G; 1550 assoc.chan = ieee80211_chan2ieee(ic, in->in_chan); 1551 /* 1552 * use the value set to ic_bss to retraive current sharedmode 1553 */ 1554 if (ic->ic_bss->in_authmode == WL_SHAREDKEY) { 1555 assoc.auth = (ic->ic_def_txkey << 4) | IPW2200_AUTH_SHARED; 1556 IPW2200_DBG(IPW2200_DBG_IOCTL, (sc->sc_dip, CE_CONT, 1557 "ipw2200_auth_and_assoc(): " 1558 "associate to shared key mode, set thru. ioctl")); 1559 } 1560 (void) memcpy(assoc.tstamp, in->in_tstamp.data, 8); 1561 assoc.capinfo = LE_16(in->in_capinfo); 1562 assoc.lintval = LE_16(ic->ic_lintval); 1563 assoc.intval = LE_16(in->in_intval); 1564 IEEE80211_ADDR_COPY(assoc.bssid, in->in_bssid); 1565 if (ic->ic_opmode == IEEE80211_M_IBSS) 1566 IEEE80211_ADDR_COPY(assoc.dst, ipw2200_broadcast_addr); 1567 else 1568 IEEE80211_ADDR_COPY(assoc.dst, in->in_bssid); 1569 1570 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 1571 "ipw2200_auth_and_assoc(): " 1572 "associate to bssid(%2x:%2x:%2x:%2x:%2x:%2x:), " 1573 "chan(%u), auth(%u)\n", 1574 assoc.bssid[0], assoc.bssid[1], assoc.bssid[2], 1575 assoc.bssid[3], assoc.bssid[4], assoc.bssid[5], 1576 assoc.chan, assoc.auth)); 1577 return (ipw2200_cmd(sc, IPW2200_CMD_ASSOCIATE, 1578 &assoc, sizeof (assoc), 1)); 1579 } 1580 1581 /* ARGSUSED */ 1582 static int 1583 ipw2200_newstate(struct ieee80211com *ic, enum ieee80211_state state, int arg) 1584 { 1585 struct ipw2200_softc *sc = (struct ipw2200_softc *)ic; 1586 wifi_data_t wd = { 0 }; 1587 1588 switch (state) { 1589 case IEEE80211_S_SCAN: 1590 if (!(sc->sc_flags & IPW2200_FLAG_SCANNING)) { 1591 ic->ic_flags |= IEEE80211_F_SCAN | IEEE80211_F_ASCAN; 1592 (void) ipw2200_start_scan(sc); 1593 } 1594 break; 1595 case IEEE80211_S_AUTH: 1596 (void) ipw2200_auth_and_assoc(sc); 1597 break; 1598 case IEEE80211_S_RUN: 1599 /* 1600 * We can send data now; update the fastpath with our 1601 * current associated BSSID and other relevant settings. 1602 * 1603 * Hardware to ahndle the wep encryption. Set the encryption 1604 * as false. 1605 * wd.wd_wep = ic->ic_flags & IEEE80211_F_WEPON; 1606 */ 1607 wd.wd_secalloc = WIFI_SEC_NONE; 1608 wd.wd_opmode = ic->ic_opmode; 1609 IEEE80211_ADDR_COPY(wd.wd_bssid, ic->ic_bss->in_bssid); 1610 (void) mac_pdata_update(ic->ic_mach, &wd, sizeof (wd)); 1611 break; 1612 case IEEE80211_S_ASSOC: 1613 case IEEE80211_S_INIT: 1614 break; 1615 } 1616 1617 /* 1618 * notify to update the link 1619 */ 1620 if ((ic->ic_state != IEEE80211_S_RUN) && (state == IEEE80211_S_RUN)) { 1621 mac_link_update(ic->ic_mach, LINK_STATE_UP); 1622 } else if ((ic->ic_state == IEEE80211_S_RUN) && 1623 (state != IEEE80211_S_RUN)) { 1624 mac_link_update(ic->ic_mach, LINK_STATE_DOWN); 1625 } 1626 1627 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 1628 "ipw2200_newstat(): %s -> %s\n", 1629 ieee80211_state_name[ic->ic_state], 1630 ieee80211_state_name[state])); 1631 1632 ic->ic_state = state; 1633 return (DDI_SUCCESS); 1634 } 1635 1636 /* 1637 * GLD operations 1638 */ 1639 /* ARGSUSED */ 1640 static int 1641 ipw2200_m_stat(void *arg, uint_t stat, uint64_t *val) 1642 { 1643 ieee80211com_t *ic = (ieee80211com_t *)arg; 1644 1645 IPW2200_DBG(IPW2200_DBG_GLD, (((struct ipw2200_softc *)arg)->sc_dip, 1646 CE_CONT, 1647 "ipw2200_m_stat(): enter\n")); 1648 1649 /* 1650 * Some of below statistic data are from hardware, some from net80211 1651 */ 1652 switch (stat) { 1653 case MAC_STAT_RBYTES: 1654 *val = ic->ic_stats.is_rx_bytes; 1655 break; 1656 case MAC_STAT_IPACKETS: 1657 *val = ic->ic_stats.is_rx_frags; 1658 break; 1659 case MAC_STAT_OBYTES: 1660 *val = ic->ic_stats.is_tx_bytes; 1661 break; 1662 case MAC_STAT_OPACKETS: 1663 *val = ic->ic_stats.is_tx_frags; 1664 break; 1665 /* 1666 * Get below from hardware statistic, retraive net80211 value once 1s 1667 */ 1668 case WIFI_STAT_TX_FRAGS: 1669 case WIFI_STAT_MCAST_TX: 1670 case WIFI_STAT_TX_FAILED: 1671 case WIFI_STAT_TX_RETRANS: 1672 /* 1673 * Get blow information from net80211 1674 */ 1675 case WIFI_STAT_RTS_SUCCESS: 1676 case WIFI_STAT_RTS_FAILURE: 1677 case WIFI_STAT_ACK_FAILURE: 1678 case WIFI_STAT_RX_FRAGS: 1679 case WIFI_STAT_MCAST_RX: 1680 case WIFI_STAT_RX_DUPS: 1681 case WIFI_STAT_FCS_ERRORS: 1682 case WIFI_STAT_WEP_ERRORS: 1683 return (ieee80211_stat(ic, stat, val)); 1684 /* 1685 * Need be supported later 1686 */ 1687 case MAC_STAT_IFSPEED: 1688 case MAC_STAT_NOXMTBUF: 1689 case MAC_STAT_IERRORS: 1690 case MAC_STAT_OERRORS: 1691 default: 1692 return (ENOTSUP); 1693 } 1694 return (0); 1695 } 1696 1697 /* ARGSUSED */ 1698 static int 1699 ipw2200_m_multicst(void *arg, boolean_t add, const uint8_t *mca) 1700 { 1701 /* not supported */ 1702 IPW2200_DBG(IPW2200_DBG_GLD, (((struct ipw2200_softc *)arg)->sc_dip, 1703 CE_CONT, 1704 "ipw2200_m_multicst(): enter\n")); 1705 1706 return (DDI_SUCCESS); 1707 } 1708 1709 /* 1710 * Multithread handler for linkstatus, fatal error recovery, get statistic 1711 */ 1712 static void 1713 ipw2200_thread(struct ipw2200_softc *sc) 1714 { 1715 struct ieee80211com *ic = &sc->sc_ic; 1716 int32_t nlstate; 1717 int stat_cnt = 0; 1718 1719 IPW2200_DBG(IPW2200_DBG_SOFTINT, (sc->sc_dip, CE_CONT, 1720 "ipw2200_thread(): enter, linkstate %d\n", sc->sc_linkstate)); 1721 1722 mutex_enter(&sc->sc_mflock); 1723 1724 while (sc->sc_mfthread_switch) { 1725 /* 1726 * notify the link state 1727 */ 1728 if (ic->ic_mach && (sc->sc_flags & IPW2200_FLAG_LINK_CHANGE)) { 1729 1730 IPW2200_DBG(IPW2200_DBG_SOFTINT, (sc->sc_dip, CE_CONT, 1731 "ipw2200_thread(): link status --> %d\n", 1732 sc->sc_linkstate)); 1733 1734 sc->sc_flags &= ~IPW2200_FLAG_LINK_CHANGE; 1735 nlstate = sc->sc_linkstate; 1736 1737 mutex_exit(&sc->sc_mflock); 1738 mac_link_update(ic->ic_mach, nlstate); 1739 mutex_enter(&sc->sc_mflock); 1740 } 1741 1742 /* 1743 * recovery fatal error 1744 */ 1745 if (ic->ic_mach && 1746 (sc->sc_flags & IPW2200_FLAG_HW_ERR_RECOVER)) { 1747 1748 IPW2200_DBG(IPW2200_DBG_FATAL, (sc->sc_dip, CE_CONT, 1749 "ipw2200_thread(): " 1750 "try to recover fatal hw error\n")); 1751 1752 sc->sc_flags &= ~IPW2200_FLAG_HW_ERR_RECOVER; 1753 1754 mutex_exit(&sc->sc_mflock); 1755 (void) ipw2200_init(sc); /* Force state machine */ 1756 /* 1757 * workround. Delay for a while after init especially 1758 * when something wrong happened already. 1759 */ 1760 delay(drv_usectohz(delay_fatal_recover)); 1761 mutex_enter(&sc->sc_mflock); 1762 } 1763 1764 /* 1765 * get statistic, the value will be retrieved by m_stat 1766 */ 1767 if (stat_cnt == 10) { 1768 1769 stat_cnt = 0; /* re-start */ 1770 mutex_exit(&sc->sc_mflock); 1771 ipw2200_get_statistics(sc); 1772 mutex_enter(&sc->sc_mflock); 1773 1774 } else 1775 stat_cnt++; /* until 1s */ 1776 1777 mutex_exit(&sc->sc_mflock); 1778 delay(drv_usectohz(delay_aux_thread)); 1779 mutex_enter(&sc->sc_mflock); 1780 1781 } 1782 sc->sc_mf_thread = NULL; 1783 cv_signal(&sc->sc_mfthread_cv); 1784 mutex_exit(&sc->sc_mflock); 1785 } 1786 1787 static int 1788 ipw2200_m_start(void *arg) 1789 { 1790 struct ipw2200_softc *sc = (struct ipw2200_softc *)arg; 1791 1792 IPW2200_DBG(IPW2200_DBG_GLD, (sc->sc_dip, CE_CONT, 1793 "ipw2200_m_start(): enter\n")); 1794 /* 1795 * initialize ipw2200 hardware, everything ok will start scan 1796 */ 1797 (void) ipw2200_init(sc); 1798 1799 sc->sc_flags |= IPW2200_FLAG_RUNNING; 1800 1801 return (DDI_SUCCESS); 1802 } 1803 1804 static void 1805 ipw2200_m_stop(void *arg) 1806 { 1807 struct ipw2200_softc *sc = (struct ipw2200_softc *)arg; 1808 1809 IPW2200_DBG(IPW2200_DBG_GLD, (sc->sc_dip, CE_CONT, 1810 "ipw2200_m_stop(): enter\n")); 1811 1812 ipw2200_stop(sc); 1813 1814 sc->sc_flags &= ~IPW2200_FLAG_RUNNING; 1815 } 1816 1817 static int 1818 ipw2200_m_unicst(void *arg, const uint8_t *macaddr) 1819 { 1820 struct ipw2200_softc *sc = (struct ipw2200_softc *)arg; 1821 struct ieee80211com *ic = &sc->sc_ic; 1822 int err; 1823 1824 IPW2200_DBG(IPW2200_DBG_GLD, (sc->sc_dip, CE_CONT, 1825 "ipw2200_m_unicst(): enter\n")); 1826 1827 IPW2200_DBG(IPW2200_DBG_GLD, (sc->sc_dip, CE_CONT, 1828 "ipw2200_m_unicst(): GLD setting MAC address to " 1829 "%02x:%02x:%02x:%02x:%02x:%02x\n", 1830 macaddr[0], macaddr[1], macaddr[2], 1831 macaddr[3], macaddr[4], macaddr[5])); 1832 1833 if (!IEEE80211_ADDR_EQ(ic->ic_macaddr, macaddr)) { 1834 1835 IEEE80211_ADDR_COPY(ic->ic_macaddr, macaddr); 1836 1837 if (sc->sc_flags & IPW2200_FLAG_RUNNING) { 1838 err = ipw2200_config(sc); 1839 if (err != DDI_SUCCESS) { 1840 IPW2200_WARN((sc->sc_dip, CE_WARN, 1841 "ipw2200_m_unicst(): " 1842 "device configuration failed\n")); 1843 goto fail; 1844 } 1845 } 1846 } 1847 return (DDI_SUCCESS); 1848 fail: 1849 return (err); 1850 } 1851 1852 static int 1853 ipw2200_m_promisc(void *arg, boolean_t on) 1854 { 1855 /* not supported */ 1856 struct ipw2200_softc *sc = (struct ipw2200_softc *)arg; 1857 1858 IPW2200_DBG(IPW2200_DBG_GLD, (sc->sc_dip, CE_CONT, 1859 "ipw2200_m_promisc(): enter. " 1860 "GLD setting promiscuous mode - %d\n", on)); 1861 1862 return (DDI_SUCCESS); 1863 } 1864 1865 static mblk_t * 1866 ipw2200_m_tx(void *arg, mblk_t *mp) 1867 { 1868 struct ipw2200_softc *sc = (struct ipw2200_softc *)arg; 1869 struct ieee80211com *ic = &sc->sc_ic; 1870 mblk_t *next; 1871 1872 /* 1873 * No data frames go out unless we're associated; this 1874 * should not happen as the 802.11 layer does not enable 1875 * the xmit queue until we enter the RUN state. 1876 */ 1877 if (ic->ic_state != IEEE80211_S_RUN) { 1878 IPW2200_DBG(IPW2200_DBG_GLD, (sc->sc_dip, CE_CONT, 1879 "ipw2200_m_tx(): discard msg, ic_state = %u\n", 1880 ic->ic_state)); 1881 freemsgchain(mp); 1882 return (NULL); 1883 } 1884 1885 while (mp != NULL) { 1886 next = mp->b_next; 1887 mp->b_next = NULL; 1888 if (ipw2200_send(ic, mp, IEEE80211_FC0_TYPE_DATA) == 1889 DDI_FAILURE) { 1890 mp->b_next = next; 1891 break; 1892 } 1893 mp = next; 1894 } 1895 return (mp); 1896 } 1897 1898 /* ARGSUSED */ 1899 static int 1900 ipw2200_send(ieee80211com_t *ic, mblk_t *mp, uint8_t type) 1901 { 1902 struct ipw2200_softc *sc = (struct ipw2200_softc *)ic; 1903 struct ieee80211_node *in; 1904 struct ieee80211_frame *wh; 1905 mblk_t *m0; 1906 size_t cnt, off; 1907 struct ipw2200_tx_desc *txdsc; 1908 struct dma_region *dr; 1909 uint32_t idx; 1910 int err; 1911 /* tmp pointer, used to pack header and payload */ 1912 uint8_t *p; 1913 1914 ASSERT(mp->b_next == NULL); 1915 1916 IPW2200_DBG(IPW2200_DBG_GLD, (sc->sc_dip, CE_CONT, 1917 "ipw2200_send(): enter\n")); 1918 1919 m0 = NULL; 1920 err = DDI_SUCCESS; 1921 1922 if ((type & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_DATA) { 1923 /* 1924 * skip all management frames since ipw2200 won't generate any 1925 * management frames. Therefore, drop this package. 1926 */ 1927 freemsg(mp); 1928 err = DDI_SUCCESS; 1929 goto fail0; 1930 } 1931 1932 mutex_enter(&sc->sc_tx_lock); 1933 1934 /* 1935 * need 1 empty descriptor 1936 */ 1937 if (sc->sc_tx_free <= IPW2200_TX_RING_MIN) { 1938 IPW2200_DBG(IPW2200_DBG_RING, (sc->sc_dip, CE_WARN, 1939 "ipw2200_send(): no enough descriptors(%d)\n", 1940 sc->sc_tx_free)); 1941 ic->ic_stats.is_tx_nobuf++; /* no enough buffer */ 1942 sc->sc_flags |= IPW2200_FLAG_TX_SCHED; 1943 err = DDI_FAILURE; 1944 goto fail1; 1945 } 1946 IPW2200_DBG(IPW2200_DBG_RING, (sc->sc_dip, CE_CONT, 1947 "ipw2200_send(): tx-free=%d,tx-curr=%d\n", 1948 sc->sc_tx_free, sc->sc_tx_cur)); 1949 1950 wh = (struct ieee80211_frame *)mp->b_rptr; 1951 in = ieee80211_find_txnode(ic, wh->i_addr1); 1952 if (in == NULL) { /* can not find the tx node, drop the package */ 1953 ic->ic_stats.is_tx_failed++; 1954 freemsg(mp); 1955 err = DDI_SUCCESS; 1956 goto fail1; 1957 } 1958 in->in_inact = 0; 1959 (void) ieee80211_encap(ic, mp, in); 1960 ieee80211_free_node(in); 1961 1962 /* 1963 * get txdsc and wh 1964 */ 1965 idx = sc->sc_tx_cur; 1966 txdsc = &sc->sc_txdsc[idx]; 1967 (void) memset(txdsc, 0, sizeof (*txdsc)); 1968 wh = (struct ieee80211_frame *)&txdsc->wh; 1969 1970 /* 1971 * extract header from message 1972 */ 1973 p = (uint8_t *)&txdsc->wh; 1974 off = 0; 1975 m0 = mp; 1976 while (off < sizeof (struct ieee80211_frame)) { 1977 cnt = MBLKL(m0); 1978 if (cnt > (sizeof (struct ieee80211_frame) - off)) 1979 cnt = sizeof (struct ieee80211_frame) - off; 1980 if (cnt) { 1981 (void) memcpy(p + off, m0->b_rptr, cnt); 1982 off += cnt; 1983 m0->b_rptr += cnt; 1984 } else 1985 m0 = m0->b_cont; 1986 } 1987 1988 /* 1989 * extract payload from message 1990 */ 1991 dr = &sc->sc_dma_txbufs[idx]; 1992 p = sc->sc_txbufs[idx]; 1993 off = 0; 1994 while (m0) { 1995 cnt = MBLKL(m0); 1996 if (cnt) 1997 (void) memcpy(p + off, m0->b_rptr, cnt); 1998 off += cnt; 1999 m0 = m0->b_cont; 2000 } 2001 2002 txdsc->hdr.type = IPW2200_HDR_TYPE_DATA; 2003 txdsc->hdr.flags = IPW2200_HDR_FLAG_IRQ; 2004 txdsc->cmd = IPW2200_DATA_CMD_TX; 2005 txdsc->len = LE_16(off); 2006 txdsc->flags = 0; 2007 2008 if (ic->ic_opmode == IEEE80211_M_IBSS) { 2009 if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) 2010 txdsc->flags |= IPW2200_DATA_FLAG_NEED_ACK; 2011 } else if (!IEEE80211_IS_MULTICAST(wh->i_addr3)) 2012 txdsc->flags |= IPW2200_DATA_FLAG_NEED_ACK; 2013 2014 if (ic->ic_flags & IEEE80211_F_PRIVACY) { 2015 wh->i_fc[1] |= IEEE80211_FC1_WEP; 2016 txdsc->wep_txkey = ic->ic_def_txkey; 2017 } 2018 else 2019 txdsc->flags |= IPW2200_DATA_FLAG_NO_WEP; 2020 2021 if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) 2022 txdsc->flags |= IPW2200_DATA_FLAG_SHPREAMBLE; 2023 2024 txdsc->nseg = LE_32(1); 2025 txdsc->seg_addr[0] = LE_32(dr->dr_pbase); 2026 txdsc->seg_len[0] = LE_32(off); 2027 2028 /* 2029 * DMA sync: buffer and desc 2030 */ 2031 (void) ddi_dma_sync(dr->dr_hnd, 0, 2032 IPW2200_TXBUF_SIZE, DDI_DMA_SYNC_FORDEV); 2033 (void) ddi_dma_sync(sc->sc_dma_txdsc.dr_hnd, 2034 idx * sizeof (struct ipw2200_tx_desc), 2035 sizeof (struct ipw2200_tx_desc), DDI_DMA_SYNC_FORDEV); 2036 2037 sc->sc_tx_cur = RING_FORWARD(sc->sc_tx_cur, 1, IPW2200_TX_RING_SIZE); 2038 sc->sc_tx_free--; 2039 2040 /* 2041 * update txcur 2042 */ 2043 ipw2200_csr_put32(sc, IPW2200_CSR_TX1_WRITE_INDEX, sc->sc_tx_cur); 2044 2045 /* 2046 * success, free the original message 2047 */ 2048 if (mp) 2049 freemsg(mp); 2050 2051 fail1: 2052 mutex_exit(&sc->sc_tx_lock); 2053 fail0: 2054 IPW2200_DBG(IPW2200_DBG_GLD, (sc->sc_dip, CE_CONT, 2055 "ipw2200_send(): exit - err=%d\n", err)); 2056 2057 return (err); 2058 } 2059 2060 /* 2061 * IOCTL handlers 2062 */ 2063 #define IEEE80211_IOCTL_REQUIRED (1) 2064 #define IEEE80211_IOCTL_NOT_REQUIRED (0) 2065 static void 2066 ipw2200_m_ioctl(void *arg, queue_t *q, mblk_t *m) 2067 { 2068 struct ipw2200_softc *sc = (struct ipw2200_softc *)arg; 2069 struct ieee80211com *ic = &sc->sc_ic; 2070 uint32_t err; 2071 2072 IPW2200_DBG(IPW2200_DBG_GLD, (sc->sc_dip, CE_CONT, 2073 "ipw2200_m_ioctl(): enter\n")); 2074 2075 /* 2076 * Check whether or not need to handle this in net80211 2077 * 2078 */ 2079 if (ipw2200_ioctl(sc, q, m) == IEEE80211_IOCTL_NOT_REQUIRED) 2080 return; 2081 2082 err = ieee80211_ioctl(ic, q, m); 2083 if (err == ENETRESET) { 2084 if (sc->sc_flags & IPW2200_FLAG_RUNNING) { 2085 (void) ipw2200_m_start(sc); 2086 (void) ieee80211_new_state(ic, 2087 IEEE80211_S_SCAN, -1); 2088 } 2089 } 2090 if (err == ERESTART) { 2091 if (sc->sc_flags & IPW2200_FLAG_RUNNING) 2092 (void) ipw2200_chip_reset(sc); 2093 } 2094 } 2095 static int 2096 ipw2200_ioctl(struct ipw2200_softc *sc, queue_t *q, mblk_t *m) 2097 { 2098 struct iocblk *iocp; 2099 uint32_t len, ret, cmd; 2100 mblk_t *m0; 2101 boolean_t need_privilege; 2102 boolean_t need_net80211; 2103 2104 if (MBLKL(m) < sizeof (struct iocblk)) { 2105 IPW2200_DBG(IPW2200_DBG_IOCTL, (sc->sc_dip, CE_CONT, 2106 "ipw2200_ioctl(): ioctl buffer too short, %u\n", 2107 MBLKL(m))); 2108 miocnak(q, m, 0, EINVAL); 2109 /* 2110 * Buf not enough, do not need net80211 either 2111 */ 2112 return (IEEE80211_IOCTL_NOT_REQUIRED); 2113 } 2114 2115 /* 2116 * Validate the command 2117 */ 2118 iocp = (struct iocblk *)m->b_rptr; 2119 iocp->ioc_error = 0; 2120 cmd = iocp->ioc_cmd; 2121 need_privilege = B_TRUE; 2122 switch (cmd) { 2123 case WLAN_SET_PARAM: 2124 case WLAN_COMMAND: 2125 break; 2126 case WLAN_GET_PARAM: 2127 need_privilege = B_FALSE; 2128 break; 2129 default: 2130 IPW2200_DBG(IPW2200_DBG_IOCTL, (sc->sc_dip, CE_CONT, 2131 "ipw2200_ioctl(): unknown cmd 0x%x", cmd)); 2132 miocnak(q, m, 0, EINVAL); 2133 /* 2134 * Unknown cmd, do not need net80211 either 2135 */ 2136 return (IEEE80211_IOCTL_NOT_REQUIRED); 2137 } 2138 2139 if (need_privilege) { 2140 /* 2141 * Check for specific net_config privilege on Solaris 10+. 2142 * Otherwise just check for root access ... 2143 */ 2144 if (secpolicy_net_config != NULL) 2145 ret = secpolicy_net_config(iocp->ioc_cr, B_FALSE); 2146 else 2147 ret = drv_priv(iocp->ioc_cr); 2148 if (ret != 0) { 2149 miocnak(q, m, 0, ret); 2150 /* 2151 * privilege check fail, do not need net80211 either 2152 */ 2153 return (IEEE80211_IOCTL_NOT_REQUIRED); 2154 } 2155 } 2156 /* 2157 * sanity check 2158 */ 2159 m0 = m->b_cont; 2160 if (iocp->ioc_count == 0 || iocp->ioc_count < sizeof (wldp_t) || 2161 m0 == NULL) { 2162 miocnak(q, m, 0, EINVAL); 2163 /* 2164 * invalid format, do not need net80211 either 2165 */ 2166 return (IEEE80211_IOCTL_NOT_REQUIRED); 2167 } 2168 /* 2169 * assuming single data block 2170 */ 2171 if (m0->b_cont) { 2172 freemsg(m0->b_cont); 2173 m0->b_cont = NULL; 2174 } 2175 2176 need_net80211 = B_FALSE; 2177 ret = ipw2200_getset(sc, m0, cmd, &need_net80211); 2178 if (!need_net80211) { 2179 len = msgdsize(m0); 2180 2181 IPW2200_DBG(IPW2200_DBG_IOCTL, (sc->sc_dip, CE_CONT, 2182 "ipw2200_ioctl(): go to call miocack with " 2183 "ret = %d, len = %d\n", ret, len)); 2184 miocack(q, m, len, ret); 2185 return (IEEE80211_IOCTL_NOT_REQUIRED); 2186 } 2187 2188 /* 2189 * IEEE80211_IOCTL - need net80211 handle 2190 */ 2191 return (IEEE80211_IOCTL_REQUIRED); 2192 } 2193 2194 static int 2195 ipw2200_getset(struct ipw2200_softc *sc, mblk_t *m, uint32_t cmd, 2196 boolean_t *need_net80211) 2197 { 2198 wldp_t *infp, *outfp; 2199 uint32_t id; 2200 int ret; 2201 2202 infp = (wldp_t *)m->b_rptr; 2203 outfp = (wldp_t *)m->b_rptr; 2204 outfp->wldp_result = WL_NOTSUPPORTED; 2205 2206 id = infp->wldp_id; 2207 IPW2200_DBG(IPW2200_DBG_IOCTL, (sc->sc_dip, CE_CONT, 2208 "ipw2200_getset(): id = 0x%x\n", id)); 2209 switch (id) { 2210 case WL_RADIO: /* which is not supported by net80211 */ 2211 ret = iwi_wificfg_radio(sc, cmd, outfp); 2212 break; 2213 case WL_DESIRED_RATES: /* hardware doesn't support fix-rates */ 2214 ret = iwi_wificfg_desrates(outfp); 2215 break; 2216 default: 2217 /* 2218 * The wifi IOCTL net80211 supported: 2219 * case WL_ESSID: 2220 * case WL_BSSID: 2221 * case WL_WEP_KEY_TAB: 2222 * case WL_WEP_KEY_ID: 2223 * case WL_AUTH_MODE: 2224 * case WL_ENCRYPTION: 2225 * case WL_BSS_TYPE: 2226 * case WL_ESS_LIST: 2227 * case WL_LINKSTATUS: 2228 * case WL_RSSI: 2229 * case WL_SCAN: 2230 * case WL_LOAD_DEFAULTS: 2231 * case WL_DISASSOCIATE: 2232 */ 2233 *need_net80211 = B_TRUE; /* let net80211 do the rest */ 2234 return (0); 2235 } 2236 /* 2237 * we will overwrite everything 2238 */ 2239 m->b_wptr = m->b_rptr + outfp->wldp_length; 2240 return (ret); 2241 } 2242 2243 static int 2244 iwi_wificfg_radio(struct ipw2200_softc *sc, uint32_t cmd, wldp_t *outfp) 2245 { 2246 uint32_t ret = ENOTSUP; 2247 2248 switch (cmd) { 2249 case WLAN_GET_PARAM: 2250 *(wl_linkstatus_t *)(outfp->wldp_buf) = 2251 ipw2200_radio_status(sc); 2252 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_linkstatus_t); 2253 outfp->wldp_result = WL_SUCCESS; 2254 ret = 0; /* command success */ 2255 break; 2256 case WLAN_SET_PARAM: 2257 default: 2258 break; 2259 } 2260 return (ret); 2261 } 2262 2263 static int 2264 iwi_wificfg_desrates(wldp_t *outfp) 2265 { 2266 /* return success, but with result NOTSUPPORTED */ 2267 outfp->wldp_length = WIFI_BUF_OFFSET; 2268 outfp->wldp_result = WL_NOTSUPPORTED; 2269 return (0); 2270 } 2271 /* End of IOCTL Handlers */ 2272 2273 void 2274 ipw2200_fix_channel(struct ieee80211com *ic, mblk_t *m) 2275 { 2276 struct ieee80211_frame *wh; 2277 uint8_t subtype; 2278 uint8_t *frm, *efrm; 2279 2280 wh = (struct ieee80211_frame *)m->b_rptr; 2281 2282 if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_MGT) 2283 return; 2284 2285 subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; 2286 2287 if (subtype != IEEE80211_FC0_SUBTYPE_BEACON && 2288 subtype != IEEE80211_FC0_SUBTYPE_PROBE_RESP) 2289 return; 2290 2291 /* 2292 * assume the message contains only 1 block 2293 */ 2294 frm = (uint8_t *)(wh + 1); 2295 efrm = (uint8_t *)m->b_wptr; 2296 frm += 12; /* skip tstamp, bintval and capinfo fields */ 2297 while (frm < efrm) { 2298 if (*frm == IEEE80211_ELEMID_DSPARMS) 2299 #if IEEE80211_CHAN_MAX < 255 2300 if (frm[2] <= IEEE80211_CHAN_MAX) 2301 #endif 2302 ic->ic_curchan = &ic->ic_sup_channels[frm[2]]; 2303 frm += frm[1] + 2; 2304 } 2305 } 2306 2307 static void 2308 ipw2200_rcv_frame(struct ipw2200_softc *sc, struct ipw2200_frame *frame) 2309 { 2310 struct ieee80211com *ic = &sc->sc_ic; 2311 uint8_t *data = (uint8_t *)frame; 2312 uint32_t len; 2313 struct ieee80211_frame *wh; 2314 struct ieee80211_node *in; 2315 mblk_t *m; 2316 int i; 2317 2318 len = LE_16(frame->len); 2319 2320 /* 2321 * Skip the frame header, get the real data from the input 2322 */ 2323 data += sizeof (struct ipw2200_frame); 2324 2325 if ((len < sizeof (struct ieee80211_frame_min)) || 2326 (len > IPW2200_RXBUF_SIZE)) { 2327 IPW2200_DBG(IPW2200_DBG_RX, (sc->sc_dip, CE_CONT, 2328 "ipw2200_rcv_frame(): bad frame length=%u\n", 2329 LE_16(frame->len))); 2330 return; 2331 } 2332 2333 IPW2200_DBG(IPW2200_DBG_RX, (sc->sc_dip, CE_CONT, 2334 "ipw2200_rcv_frame(): chan = %d, length = %d\n", frame->chan, len)); 2335 2336 m = allocb(len, BPRI_MED); 2337 if (m) { 2338 (void) memcpy(m->b_wptr, data, len); 2339 m->b_wptr += len; 2340 2341 wh = (struct ieee80211_frame *)m->b_rptr; 2342 if (wh->i_fc[1] & IEEE80211_FC1_WEP) { 2343 /* 2344 * h/w decyption leaves the WEP bit, iv and CRC fields 2345 */ 2346 wh->i_fc[1] &= ~IEEE80211_FC1_WEP; 2347 for (i = sizeof (struct ieee80211_frame) - 1; 2348 i >= 0; i--) 2349 *(m->b_rptr + IEEE80211_WEP_IVLEN + 2350 IEEE80211_WEP_KIDLEN + i) = 2351 *(m->b_rptr + i); 2352 m->b_rptr += IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN; 2353 m->b_wptr -= IEEE80211_WEP_CRCLEN; 2354 wh = (struct ieee80211_frame *)m->b_rptr; 2355 } 2356 2357 if (ic->ic_state == IEEE80211_S_SCAN) { 2358 ic->ic_ibss_chan = &ic->ic_sup_channels[frame->chan]; 2359 ipw2200_fix_channel(ic, m); 2360 } 2361 2362 in = ieee80211_find_rxnode(ic, wh); 2363 IPW2200_DBG(IPW2200_DBG_RX, (sc->sc_dip, CE_CONT, 2364 "ipw2200_rcv_frame(): " 2365 "ni_esslen:%d, ni_essid[0-5]:%c%c%c%c%c%c\n", 2366 in->in_esslen, 2367 in->in_essid[0], in->in_essid[1], in->in_essid[2], 2368 in->in_essid[3], in->in_essid[4], in->in_essid[5])); 2369 2370 (void) ieee80211_input(ic, m, in, frame->rssi_dbm, 0); 2371 2372 ieee80211_free_node(in); 2373 } 2374 else 2375 IPW2200_WARN((sc->sc_dip, CE_WARN, 2376 "ipw2200_rcv_frame(): " 2377 "cannot allocate receive message(%u)\n", 2378 LE_16(frame->len))); 2379 } 2380 2381 static void 2382 ipw2200_rcv_notif(struct ipw2200_softc *sc, struct ipw2200_notif *notif) 2383 { 2384 struct ieee80211com *ic = &sc->sc_ic; 2385 struct ipw2200_notif_association *assoc; 2386 struct ipw2200_notif_authentication *auth; 2387 uint8_t *ndata = (uint8_t *)notif; 2388 2389 IPW2200_DBG(IPW2200_DBG_NOTIF, (sc->sc_dip, CE_CONT, 2390 "ipw2200_rcv_notif(): type=%u\n", notif->type)); 2391 2392 ndata += sizeof (struct ipw2200_notif); 2393 switch (notif->type) { 2394 case IPW2200_NOTIF_TYPE_ASSOCIATION: 2395 assoc = (struct ipw2200_notif_association *)ndata; 2396 2397 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 2398 "ipw2200_rcv_notif(): association=%u,%u\n", 2399 assoc->state, assoc->status)); 2400 2401 switch (assoc->state) { 2402 case IPW2200_ASSOC_SUCCESS: 2403 ieee80211_new_state(ic, IEEE80211_S_RUN, -1); 2404 break; 2405 case IPW2200_ASSOC_FAIL: 2406 ieee80211_begin_scan(ic, 1); /* reset */ 2407 break; 2408 default: 2409 break; 2410 } 2411 break; 2412 2413 case IPW2200_NOTIF_TYPE_AUTHENTICATION: 2414 auth = (struct ipw2200_notif_authentication *)ndata; 2415 2416 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 2417 "ipw2200_rcv_notif(): authentication=%u\n", auth->state)); 2418 2419 switch (auth->state) { 2420 case IPW2200_AUTH_SUCCESS: 2421 ieee80211_new_state(ic, IEEE80211_S_ASSOC, -1); 2422 break; 2423 case IPW2200_AUTH_FAIL: 2424 break; 2425 default: 2426 IPW2200_DBG(IPW2200_DBG_NOTIF, (sc->sc_dip, CE_CONT, 2427 "ipw2200_rcv_notif(): " 2428 "unknown authentication state(%u)\n", auth->state)); 2429 break; 2430 } 2431 break; 2432 2433 case IPW2200_NOTIF_TYPE_SCAN_CHANNEL: 2434 IPW2200_DBG(IPW2200_DBG_SCAN, (sc->sc_dip, CE_CONT, 2435 "ipw2200_rcv_notif(): scan-channel=%u\n", 2436 ((struct ipw2200_notif_scan_channel *)ndata)->nchan)); 2437 break; 2438 2439 case IPW2200_NOTIF_TYPE_SCAN_COMPLETE: 2440 IPW2200_DBG(IPW2200_DBG_SCAN, (sc->sc_dip, CE_CONT, 2441 "ipw2200_rcv_notif():scan-completed,(%u,%u)\n", 2442 ((struct ipw2200_notif_scan_complete *)ndata)->nchan, 2443 ((struct ipw2200_notif_scan_complete *)ndata)->status)); 2444 2445 /* 2446 * scan complete 2447 */ 2448 sc->sc_flags &= ~IPW2200_FLAG_SCANNING; 2449 ieee80211_end_scan(ic); 2450 break; 2451 2452 case IPW2200_NOTIF_TYPE_BEACON: 2453 case IPW2200_NOTIF_TYPE_CALIBRATION: 2454 case IPW2200_NOTIF_TYPE_NOISE: 2455 /* 2456 * just ignore 2457 */ 2458 break; 2459 default: 2460 IPW2200_DBG(IPW2200_DBG_NOTIF, (sc->sc_dip, CE_CONT, 2461 "ipw2200_rcv_notif(): unknown notification type(%u)\n", 2462 notif->type)); 2463 break; 2464 } 2465 } 2466 2467 static uint_t 2468 ipw2200_intr(caddr_t arg) 2469 { 2470 struct ipw2200_softc *sc = (struct ipw2200_softc *)arg; 2471 struct ieee80211com *ic = &sc->sc_ic; 2472 uint32_t ireg, ridx, len, i; 2473 uint8_t *p, *rxbuf; 2474 struct dma_region *dr; 2475 struct ipw2200_hdr *hdr; 2476 int need_sched; 2477 uint32_t widx; 2478 2479 ireg = ipw2200_csr_get32(sc, IPW2200_CSR_INTR); 2480 2481 if (ireg == 0xffffffff) 2482 return (DDI_INTR_UNCLAIMED); 2483 2484 if (!(ireg & IPW2200_INTR_MASK_ALL)) 2485 return (DDI_INTR_UNCLAIMED); 2486 2487 /* 2488 * mask all interrupts 2489 */ 2490 ipw2200_csr_put32(sc, IPW2200_CSR_INTR_MASK, 0); 2491 2492 /* 2493 * acknowledge all fired interrupts 2494 */ 2495 ipw2200_csr_put32(sc, IPW2200_CSR_INTR, ireg); 2496 2497 IPW2200_DBG(IPW2200_DBG_INT, (sc->sc_dip, CE_CONT, 2498 "ipw2200_intr(): enter. interrupt fired, int=0x%08x\n", ireg)); 2499 2500 if (ireg & IPW2200_INTR_MASK_ERR) { 2501 2502 IPW2200_DBG(IPW2200_DBG_FATAL, (sc->sc_dip, CE_CONT, 2503 "ipw2200 interrupt(): int= 0x%08x\n", ireg)); 2504 2505 /* 2506 * inform mfthread to recover hw error by stopping it 2507 */ 2508 mutex_enter(&sc->sc_mflock); 2509 sc->sc_flags |= IPW2200_FLAG_HW_ERR_RECOVER; 2510 mutex_exit(&sc->sc_mflock); 2511 2512 } else { 2513 if (ireg & IPW2200_INTR_FW_INITED) { 2514 mutex_enter(&sc->sc_ilock); 2515 sc->sc_fw_ok = 1; 2516 cv_signal(&sc->sc_fw_cond); 2517 mutex_exit(&sc->sc_ilock); 2518 } 2519 if (ireg & IPW2200_INTR_RADIO_OFF) { 2520 IPW2200_REPORT((sc->sc_dip, CE_CONT, 2521 "ipw2200_intr(): radio is OFF\n")); 2522 /* 2523 * Stop hardware, will notify LINK is down 2524 */ 2525 ipw2200_stop(sc); 2526 } 2527 if (ireg & IPW2200_INTR_CMD_TRANSFER) { 2528 mutex_enter(&sc->sc_cmd_lock); 2529 ridx = ipw2200_csr_get32(sc, 2530 IPW2200_CSR_CMD_READ_INDEX); 2531 i = RING_FORWARD(sc->sc_cmd_cur, 2532 sc->sc_cmd_free, IPW2200_CMD_RING_SIZE); 2533 len = RING_FLEN(i, ridx, IPW2200_CMD_RING_SIZE); 2534 2535 IPW2200_DBG(IPW2200_DBG_INT, (sc->sc_dip, CE_CONT, 2536 "ipw2200_intr(): cmd-ring,i=%u,ridx=%u,len=%u\n", 2537 i, ridx, len)); 2538 2539 if (len > 0) { 2540 sc->sc_cmd_free += len; 2541 cv_signal(&sc->sc_cmd_cond); 2542 } 2543 for (; i != ridx; 2544 i = RING_FORWARD(i, 1, IPW2200_CMD_RING_SIZE)) 2545 sc->sc_done[i] = 1; 2546 mutex_exit(&sc->sc_cmd_lock); 2547 2548 mutex_enter(&sc->sc_ilock); 2549 cv_signal(&sc->sc_cmd_status_cond); 2550 mutex_exit(&sc->sc_ilock); 2551 } 2552 if (ireg & IPW2200_INTR_RX_TRANSFER) { 2553 ridx = ipw2200_csr_get32(sc, 2554 IPW2200_CSR_RX_READ_INDEX); 2555 widx = ipw2200_csr_get32(sc, 2556 IPW2200_CSR_RX_WRITE_INDEX); 2557 2558 IPW2200_DBG(IPW2200_DBG_INT, (sc->sc_dip, CE_CONT, 2559 "ipw2200_intr(): rx-ring,widx=%u,ridx=%u\n", 2560 ridx, widx)); 2561 2562 for (; sc->sc_rx_cur != ridx; 2563 sc->sc_rx_cur = RING_FORWARD(sc->sc_rx_cur, 1, 2564 IPW2200_RX_RING_SIZE)) { 2565 i = sc->sc_rx_cur; 2566 rxbuf = sc->sc_rxbufs[i]; 2567 dr = &sc->sc_dma_rxbufs[i]; 2568 2569 /* 2570 * DMA sync 2571 */ 2572 (void) ddi_dma_sync(dr->dr_hnd, 0, 2573 IPW2200_RXBUF_SIZE, DDI_DMA_SYNC_FORKERNEL); 2574 /* 2575 * Get rx header(hdr) and rx data(p) from rxbuf 2576 */ 2577 p = rxbuf; 2578 hdr = (struct ipw2200_hdr *)p; 2579 p += sizeof (struct ipw2200_hdr); 2580 2581 IPW2200_DBG(IPW2200_DBG_INT, 2582 (sc->sc_dip, CE_CONT, 2583 "ipw2200_intr(): Rx hdr type %u\n", 2584 hdr->type)); 2585 2586 switch (hdr->type) { 2587 case IPW2200_HDR_TYPE_FRAME: 2588 ipw2200_rcv_frame(sc, 2589 (struct ipw2200_frame *)p); 2590 break; 2591 2592 case IPW2200_HDR_TYPE_NOTIF: 2593 ipw2200_rcv_notif(sc, 2594 (struct ipw2200_notif *)p); 2595 break; 2596 default: 2597 IPW2200_DBG(IPW2200_DBG_INT, 2598 (sc->sc_dip, CE_CONT, 2599 "ipw2200_intr(): " 2600 "unknown Rx hdr type %u\n", 2601 hdr->type)); 2602 break; 2603 } 2604 } 2605 /* 2606 * write sc_rx_cur backward 1 step into RX_WRITE_INDEX 2607 */ 2608 ipw2200_csr_put32(sc, IPW2200_CSR_RX_WRITE_INDEX, 2609 RING_BACKWARD(sc->sc_rx_cur, 1, 2610 IPW2200_RX_RING_SIZE)); 2611 } 2612 if (ireg & IPW2200_INTR_TX1_TRANSFER) { 2613 mutex_enter(&sc->sc_tx_lock); 2614 ridx = ipw2200_csr_get32(sc, 2615 IPW2200_CSR_TX1_READ_INDEX); 2616 len = RING_FLEN(RING_FORWARD(sc->sc_tx_cur, 2617 sc->sc_tx_free, IPW2200_TX_RING_SIZE), 2618 ridx, IPW2200_TX_RING_SIZE); 2619 IPW2200_DBG(IPW2200_DBG_RING, (sc->sc_dip, CE_CONT, 2620 "ipw2200_intr(): tx-ring,ridx=%u,len=%u\n", 2621 ridx, len)); 2622 sc->sc_tx_free += len; 2623 2624 need_sched = 0; 2625 if ((sc->sc_tx_free > IPW2200_TX_RING_MIN) && 2626 (sc->sc_flags & IPW2200_FLAG_TX_SCHED)) { 2627 IPW2200_DBG(IPW2200_DBG_RING, (sc->sc_dip, 2628 CE_CONT, 2629 "ipw2200_intr(): Need Reschedule!")); 2630 need_sched = 1; 2631 sc->sc_flags &= ~IPW2200_FLAG_TX_SCHED; 2632 } 2633 mutex_exit(&sc->sc_tx_lock); 2634 2635 if (need_sched) 2636 mac_tx_update(ic->ic_mach); 2637 } 2638 } 2639 2640 /* 2641 * enable all interrupts 2642 */ 2643 ipw2200_csr_put32(sc, IPW2200_CSR_INTR_MASK, IPW2200_INTR_MASK_ALL); 2644 2645 return (DDI_INTR_CLAIMED); 2646 } 2647 2648 2649 /* 2650 * Module Loading Data & Entry Points 2651 */ 2652 DDI_DEFINE_STREAM_OPS(ipw2200_devops, nulldev, nulldev, ipw2200_attach, 2653 ipw2200_detach, nodev, NULL, D_MP, NULL); 2654 2655 static struct modldrv ipw2200_modldrv = { 2656 &mod_driverops, 2657 ipw2200_ident, 2658 &ipw2200_devops 2659 }; 2660 2661 static struct modlinkage ipw2200_modlinkage = { 2662 MODREV_1, 2663 &ipw2200_modldrv, 2664 NULL 2665 }; 2666 2667 int 2668 _init(void) 2669 { 2670 int status; 2671 2672 status = ddi_soft_state_init(&ipw2200_ssp, 2673 sizeof (struct ipw2200_softc), 1); 2674 if (status != DDI_SUCCESS) 2675 return (status); 2676 2677 mac_init_ops(&ipw2200_devops, IPW2200_DRV_NAME); 2678 status = mod_install(&ipw2200_modlinkage); 2679 if (status != DDI_SUCCESS) { 2680 mac_fini_ops(&ipw2200_devops); 2681 ddi_soft_state_fini(&ipw2200_ssp); 2682 } 2683 2684 return (status); 2685 } 2686 2687 int 2688 _fini(void) 2689 { 2690 int status; 2691 2692 status = mod_remove(&ipw2200_modlinkage); 2693 if (status == DDI_SUCCESS) { 2694 mac_fini_ops(&ipw2200_devops); 2695 ddi_soft_state_fini(&ipw2200_ssp); 2696 } 2697 2698 return (status); 2699 } 2700 2701 int 2702 _info(struct modinfo *modinfop) 2703 { 2704 return (mod_info(&ipw2200_modlinkage, modinfop)); 2705 } 2706