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 return (DDI_SUCCESS); /* return successfully */ 972 fail: 973 ipw2200_stop(sc); 974 return (err); 975 } 976 977 /* 978 * get hardware configurations from EEPROM embedded within PRO/2200 979 */ 980 static void 981 ipw2200_hwconf_get(struct ipw2200_softc *sc) 982 { 983 int i; 984 uint16_t val; 985 986 /* 987 * Get mac address 988 */ 989 i = 0; 990 val = ipw2200_rom_get16(sc, IPW2200_EEPROM_MAC + 0); 991 sc->sc_macaddr[i++] = val >> 8; 992 sc->sc_macaddr[i++] = val & 0xff; 993 val = ipw2200_rom_get16(sc, IPW2200_EEPROM_MAC + 1); 994 sc->sc_macaddr[i++] = val >> 8; 995 sc->sc_macaddr[i++] = val & 0xff; 996 val = ipw2200_rom_get16(sc, IPW2200_EEPROM_MAC + 2); 997 sc->sc_macaddr[i++] = val >> 8; 998 sc->sc_macaddr[i++] = val & 0xff; 999 1000 /* 1001 * formatted MAC address string 1002 */ 1003 (void) snprintf(sc->sc_macstr, sizeof (sc->sc_macstr), 1004 "%02x:%02x:%02x:%02x:%02x:%02x", 1005 sc->sc_macaddr[0], sc->sc_macaddr[1], 1006 sc->sc_macaddr[2], sc->sc_macaddr[3], 1007 sc->sc_macaddr[4], sc->sc_macaddr[5]); 1008 1009 } 1010 1011 /* 1012 * all ipw2200 interrupts will be masked by this routine 1013 */ 1014 static void 1015 ipw2200_master_stop(struct ipw2200_softc *sc) 1016 { 1017 int ntries; 1018 1019 /* 1020 * disable interrupts 1021 */ 1022 ipw2200_csr_put32(sc, IPW2200_CSR_INTR_MASK, 0); 1023 ipw2200_csr_put32(sc, IPW2200_CSR_RST, IPW2200_RST_STOP_MASTER); 1024 1025 /* 1026 * wait long enough to ensure hardware stop successfully. 1027 */ 1028 for (ntries = 0; ntries < 500; ntries++) { 1029 if (ipw2200_csr_get32(sc, IPW2200_CSR_RST) & 1030 IPW2200_RST_MASTER_DISABLED) 1031 break; 1032 /* wait for a while */ 1033 drv_usecwait(100); 1034 } 1035 if (ntries == 500) 1036 IPW2200_WARN((sc->sc_dip, CE_WARN, 1037 "ipw2200_master_stop(): timeout\n")); 1038 1039 ipw2200_csr_put32(sc, IPW2200_CSR_RST, 1040 IPW2200_RST_PRINCETON_RESET | 1041 ipw2200_csr_get32(sc, IPW2200_CSR_RST)); 1042 1043 sc->sc_flags &= ~IPW2200_FLAG_FW_INITED; 1044 } 1045 1046 /* 1047 * all ipw2200 interrupts will be masked by this routine 1048 */ 1049 static int 1050 ipw2200_chip_reset(struct ipw2200_softc *sc) 1051 { 1052 uint32_t tmp; 1053 int ntries, i; 1054 1055 ipw2200_master_stop(sc); 1056 1057 /* 1058 * Move adapter to DO state 1059 */ 1060 tmp = ipw2200_csr_get32(sc, IPW2200_CSR_CTL); 1061 ipw2200_csr_put32(sc, IPW2200_CSR_CTL, tmp | IPW2200_CTL_INIT); 1062 1063 /* 1064 * Initialize Phase-Locked Level (PLL) 1065 */ 1066 ipw2200_csr_put32(sc, IPW2200_CSR_READ_INT, IPW2200_READ_INT_INIT_HOST); 1067 1068 /* 1069 * Wait for clock stabilization 1070 */ 1071 for (ntries = 0; ntries < 1000; ntries++) { 1072 if (ipw2200_csr_get32(sc, IPW2200_CSR_CTL) & 1073 IPW2200_CTL_CLOCK_READY) 1074 break; 1075 drv_usecwait(200); 1076 } 1077 if (ntries == 1000) { 1078 IPW2200_WARN((sc->sc_dip, CE_WARN, 1079 "ipw2200_chip_reset(): timeout\n")); 1080 return (DDI_FAILURE); 1081 } 1082 1083 tmp = ipw2200_csr_get32(sc, IPW2200_CSR_RST); 1084 ipw2200_csr_put32(sc, IPW2200_CSR_RST, tmp | IPW2200_RST_SW_RESET); 1085 1086 drv_usecwait(10); 1087 1088 tmp = ipw2200_csr_get32(sc, IPW2200_CSR_CTL); 1089 ipw2200_csr_put32(sc, IPW2200_CSR_CTL, tmp | IPW2200_CTL_INIT); 1090 1091 /* 1092 * clear NIC memory 1093 */ 1094 ipw2200_csr_put32(sc, IPW2200_CSR_AUTOINC_ADDR, 0); 1095 for (i = 0; i < 0xc000; i++) 1096 ipw2200_csr_put32(sc, IPW2200_CSR_AUTOINC_DATA, 0); 1097 1098 return (DDI_SUCCESS); 1099 } 1100 1101 /* 1102 * This function is used by wificonfig/dladm to get the current 1103 * radio status, it is off/on 1104 */ 1105 int 1106 ipw2200_radio_status(struct ipw2200_softc *sc) 1107 { 1108 int val; 1109 1110 val = (ipw2200_csr_get32(sc, IPW2200_CSR_IO) & 1111 IPW2200_IO_RADIO_ENABLED) ? 1 : 0; 1112 1113 return (val); 1114 } 1115 /* 1116 * This function is used to get the statistic 1117 */ 1118 void 1119 ipw2200_get_statistics(struct ipw2200_softc *sc) 1120 { 1121 struct ieee80211com *ic = &sc->sc_ic; 1122 1123 uint32_t size, buf[128]; 1124 1125 if (!(sc->sc_flags & IPW2200_FLAG_FW_INITED)) { 1126 IPW2200_DBG(IPW2200_DBG_IOCTL, (sc->sc_dip, CE_CONT, 1127 "ipw2200_get_statistic(): fw doesn't download yet.")); 1128 return; 1129 } 1130 1131 size = min(ipw2200_csr_get32(sc, IPW2200_CSR_TABLE0_SIZE), 128 - 1); 1132 ipw2200_csr_getbuf32(sc, IPW2200_CSR_TABLE0_BASE, &buf[1], size); 1133 1134 /* 1135 * To retrieve the statistic information into proper places. There are 1136 * lot of information. These table will be read once a second. 1137 * Hopefully, it will not effect the performance. 1138 */ 1139 1140 /* 1141 * For the tx/crc information, we can get them from chip directly; 1142 * For the rx/wep error/(rts) related information, leave them net80211. 1143 */ 1144 /* WIFI_STAT_TX_FRAGS */ 1145 ic->ic_stats.is_tx_frags = (uint32_t)buf[5]; 1146 /* WIFI_STAT_MCAST_TX */ 1147 ic->ic_stats.is_tx_mcast = (uint32_t)buf[31]; 1148 /* WIFI_STAT_TX_RETRANS */ 1149 ic->ic_stats.is_tx_retries = (uint32_t)buf[56]; 1150 /* WIFI_STAT_TX_FAILED */ 1151 ic->ic_stats.is_tx_failed = (uint32_t)buf[57]; 1152 /* MAC_STAT_OBYTES */ 1153 ic->ic_stats.is_tx_bytes = (uint32_t)buf[64]; 1154 } 1155 1156 /* 1157 * DMA region alloc subroutine 1158 */ 1159 int 1160 ipw2200_dma_region_alloc(struct ipw2200_softc *sc, struct dma_region *dr, 1161 size_t size, uint_t dir, uint_t flags) 1162 { 1163 dev_info_t *dip = sc->sc_dip; 1164 int err; 1165 1166 IPW2200_DBG(IPW2200_DBG_DMA, (sc->sc_dip, CE_CONT, 1167 "ipw2200_dma_region_alloc(): size =%u\n", size)); 1168 1169 err = ddi_dma_alloc_handle(dip, &ipw2200_dma_attr, DDI_DMA_SLEEP, NULL, 1170 &dr->dr_hnd); 1171 if (err != DDI_SUCCESS) { 1172 IPW2200_DBG(IPW2200_DBG_DMA, (sc->sc_dip, CE_CONT, 1173 "ipw2200_dma_region_alloc(): " 1174 "ddi_dma_alloc_handle() failed\n")); 1175 goto fail0; 1176 } 1177 1178 err = ddi_dma_mem_alloc(dr->dr_hnd, size, &ipw2200_dma_accattr, 1179 flags, DDI_DMA_SLEEP, NULL, 1180 &dr->dr_base, &dr->dr_size, &dr->dr_acc); 1181 if (err != DDI_SUCCESS) { 1182 IPW2200_DBG(IPW2200_DBG_DMA, (sc->sc_dip, CE_CONT, 1183 "ipw2200_dma_region_alloc(): " 1184 "ddi_dma_mem_alloc() failed\n")); 1185 goto fail1; 1186 } 1187 1188 err = ddi_dma_addr_bind_handle(dr->dr_hnd, NULL, 1189 dr->dr_base, dr->dr_size, 1190 dir | flags, DDI_DMA_SLEEP, NULL, 1191 &dr->dr_cookie, &dr->dr_ccnt); 1192 if (err != DDI_DMA_MAPPED) { 1193 IPW2200_DBG(IPW2200_DBG_DMA, (sc->sc_dip, CE_CONT, 1194 "ipw2200_dma_region_alloc(): " 1195 "ddi_dma_addr_bind_handle() failed\n")); 1196 goto fail2; 1197 } 1198 1199 IPW2200_DBG(IPW2200_DBG_DMA, (sc->sc_dip, CE_CONT, 1200 "ipw2200_dma_region_alloc(): ccnt=%u\n", dr->dr_ccnt)); 1201 1202 if (dr->dr_ccnt != 1) { 1203 err = DDI_FAILURE; 1204 goto fail3; 1205 } 1206 1207 dr->dr_pbase = dr->dr_cookie.dmac_address; 1208 1209 IPW2200_DBG(IPW2200_DBG_DMA, (sc->sc_dip, CE_CONT, 1210 "ipw2200_dma_region_alloc(): get physical-base=0x%08x\n", 1211 dr->dr_pbase)); 1212 1213 return (DDI_SUCCESS); 1214 1215 fail3: 1216 (void) ddi_dma_unbind_handle(dr->dr_hnd); 1217 fail2: 1218 ddi_dma_mem_free(&dr->dr_acc); 1219 fail1: 1220 ddi_dma_free_handle(&dr->dr_hnd); 1221 fail0: 1222 return (err); 1223 } 1224 1225 void 1226 ipw2200_dma_region_free(struct dma_region *dr) 1227 { 1228 (void) ddi_dma_unbind_handle(dr->dr_hnd); 1229 ddi_dma_mem_free(&dr->dr_acc); 1230 ddi_dma_free_handle(&dr->dr_hnd); 1231 } 1232 1233 static int 1234 ipw2200_ring_alloc(struct ipw2200_softc *sc) 1235 { 1236 int err, i; 1237 1238 /* 1239 * tx desc ring 1240 */ 1241 sc->sc_dma_txdsc.dr_name = "ipw2200-tx-desc-ring"; 1242 err = ipw2200_dma_region_alloc(sc, &sc->sc_dma_txdsc, 1243 IPW2200_TX_RING_SIZE * sizeof (struct ipw2200_tx_desc), 1244 DDI_DMA_WRITE, DDI_DMA_CONSISTENT); 1245 if (err != DDI_SUCCESS) 1246 goto fail0; 1247 /* 1248 * tx buffer array 1249 */ 1250 for (i = 0; i < IPW2200_TX_RING_SIZE; i++) { 1251 sc->sc_dma_txbufs[i].dr_name = "ipw2200-tx-buf"; 1252 err = ipw2200_dma_region_alloc(sc, &sc->sc_dma_txbufs[i], 1253 IPW2200_TXBUF_SIZE, DDI_DMA_WRITE, DDI_DMA_STREAMING); 1254 if (err != DDI_SUCCESS) { 1255 while (i >= 0) { 1256 ipw2200_dma_region_free(&sc->sc_dma_txbufs[i]); 1257 i--; 1258 } 1259 goto fail1; 1260 } 1261 } 1262 /* 1263 * rx buffer array 1264 */ 1265 for (i = 0; i < IPW2200_RX_RING_SIZE; i++) { 1266 sc->sc_dma_rxbufs[i].dr_name = "ipw2200-rx-buf"; 1267 err = ipw2200_dma_region_alloc(sc, &sc->sc_dma_rxbufs[i], 1268 IPW2200_RXBUF_SIZE, DDI_DMA_READ, DDI_DMA_STREAMING); 1269 if (err != DDI_SUCCESS) { 1270 while (i >= 0) { 1271 ipw2200_dma_region_free(&sc->sc_dma_rxbufs[i]); 1272 i--; 1273 } 1274 goto fail2; 1275 } 1276 } 1277 /* 1278 * cmd desc ring 1279 */ 1280 sc->sc_dma_cmdsc.dr_name = "ipw2200-cmd-desc-ring"; 1281 err = ipw2200_dma_region_alloc(sc, &sc->sc_dma_cmdsc, 1282 IPW2200_CMD_RING_SIZE * sizeof (struct ipw2200_cmd_desc), 1283 DDI_DMA_WRITE, DDI_DMA_CONSISTENT); 1284 if (err != DDI_SUCCESS) 1285 goto fail3; 1286 1287 return (DDI_SUCCESS); 1288 1289 fail3: 1290 for (i = 0; i < IPW2200_RX_RING_SIZE; i++) 1291 ipw2200_dma_region_free(&sc->sc_dma_rxbufs[i]); 1292 fail2: 1293 for (i = 0; i < IPW2200_TX_RING_SIZE; i++) 1294 ipw2200_dma_region_free(&sc->sc_dma_txbufs[i]); 1295 fail1: 1296 ipw2200_dma_region_free(&sc->sc_dma_txdsc); 1297 fail0: 1298 return (err); 1299 } 1300 1301 static void 1302 ipw2200_ring_free(struct ipw2200_softc *sc) 1303 { 1304 int i; 1305 1306 /* 1307 * tx ring desc 1308 */ 1309 ipw2200_dma_region_free(&sc->sc_dma_txdsc); 1310 /* 1311 * tx buf 1312 */ 1313 for (i = 0; i < IPW2200_TX_RING_SIZE; i++) 1314 ipw2200_dma_region_free(&sc->sc_dma_txbufs[i]); 1315 /* 1316 * rx buf 1317 */ 1318 for (i = 0; i < IPW2200_RX_RING_SIZE; i++) 1319 ipw2200_dma_region_free(&sc->sc_dma_rxbufs[i]); 1320 /* 1321 * command ring desc 1322 */ 1323 ipw2200_dma_region_free(&sc->sc_dma_cmdsc); 1324 } 1325 1326 static void 1327 ipw2200_ring_reset(struct ipw2200_softc *sc) 1328 { 1329 int i; 1330 1331 /* 1332 * tx desc ring & buffer array 1333 */ 1334 sc->sc_tx_cur = 0; 1335 sc->sc_tx_free = IPW2200_TX_RING_SIZE; 1336 sc->sc_txdsc = (struct ipw2200_tx_desc *)sc->sc_dma_txdsc.dr_base; 1337 for (i = 0; i < IPW2200_TX_RING_SIZE; i++) 1338 sc->sc_txbufs[i] = (uint8_t *)sc->sc_dma_txbufs[i].dr_base; 1339 /* 1340 * rx buffer array 1341 */ 1342 sc->sc_rx_cur = 0; 1343 sc->sc_rx_free = IPW2200_RX_RING_SIZE; 1344 for (i = 0; i < IPW2200_RX_RING_SIZE; i++) 1345 sc->sc_rxbufs[i] = (uint8_t *)sc->sc_dma_rxbufs[i].dr_base; 1346 1347 /* 1348 * command desc ring 1349 */ 1350 sc->sc_cmd_cur = 0; 1351 sc->sc_cmd_free = IPW2200_CMD_RING_SIZE; 1352 sc->sc_cmdsc = (struct ipw2200_cmd_desc *)sc->sc_dma_cmdsc.dr_base; 1353 } 1354 1355 /* 1356 * tx, rx rings and command initialization 1357 */ 1358 static int 1359 ipw2200_ring_init(struct ipw2200_softc *sc) 1360 { 1361 int err; 1362 1363 err = ipw2200_ring_alloc(sc); 1364 if (err != DDI_SUCCESS) 1365 return (err); 1366 1367 ipw2200_ring_reset(sc); 1368 1369 return (DDI_SUCCESS); 1370 } 1371 1372 static void 1373 ipw2200_ring_hwsetup(struct ipw2200_softc *sc) 1374 { 1375 int i; 1376 1377 /* 1378 * command desc ring 1379 */ 1380 ipw2200_csr_put32(sc, IPW2200_CSR_CMD_BASE, sc->sc_dma_cmdsc.dr_pbase); 1381 ipw2200_csr_put32(sc, IPW2200_CSR_CMD_SIZE, IPW2200_CMD_RING_SIZE); 1382 ipw2200_csr_put32(sc, IPW2200_CSR_CMD_WRITE_INDEX, sc->sc_cmd_cur); 1383 1384 /* 1385 * tx desc ring. only tx1 is used, tx2, tx3, and tx4 are unused 1386 */ 1387 ipw2200_csr_put32(sc, IPW2200_CSR_TX1_BASE, sc->sc_dma_txdsc.dr_pbase); 1388 ipw2200_csr_put32(sc, IPW2200_CSR_TX1_SIZE, IPW2200_TX_RING_SIZE); 1389 ipw2200_csr_put32(sc, IPW2200_CSR_TX1_WRITE_INDEX, sc->sc_tx_cur); 1390 1391 /* 1392 * tx2, tx3, tx4 is not used 1393 */ 1394 ipw2200_csr_put32(sc, IPW2200_CSR_TX2_BASE, sc->sc_dma_txdsc.dr_pbase); 1395 ipw2200_csr_put32(sc, IPW2200_CSR_TX2_SIZE, IPW2200_TX_RING_SIZE); 1396 ipw2200_csr_put32(sc, IPW2200_CSR_TX2_READ_INDEX, 0); 1397 ipw2200_csr_put32(sc, IPW2200_CSR_TX2_WRITE_INDEX, 0); 1398 ipw2200_csr_put32(sc, IPW2200_CSR_TX3_BASE, sc->sc_dma_txdsc.dr_pbase); 1399 ipw2200_csr_put32(sc, IPW2200_CSR_TX3_SIZE, IPW2200_TX_RING_SIZE); 1400 ipw2200_csr_put32(sc, IPW2200_CSR_TX3_READ_INDEX, 0); 1401 ipw2200_csr_put32(sc, IPW2200_CSR_TX3_WRITE_INDEX, 0); 1402 ipw2200_csr_put32(sc, IPW2200_CSR_TX4_BASE, sc->sc_dma_txdsc.dr_pbase); 1403 ipw2200_csr_put32(sc, IPW2200_CSR_TX4_SIZE, IPW2200_TX_RING_SIZE); 1404 ipw2200_csr_put32(sc, IPW2200_CSR_TX4_READ_INDEX, 0); 1405 ipw2200_csr_put32(sc, IPW2200_CSR_TX4_WRITE_INDEX, 0); 1406 1407 /* 1408 * rx buffer ring 1409 */ 1410 for (i = 0; i < IPW2200_RX_RING_SIZE; i++) 1411 ipw2200_csr_put32(sc, IPW2200_CSR_RX_BASE + i * 4, 1412 sc->sc_dma_rxbufs[i].dr_pbase); 1413 /* 1414 * all rx buffer are empty, rx-rd-index == 0 && rx-wr-index == N-1 1415 */ 1416 ipw2200_csr_put32(sc, IPW2200_CSR_RX_WRITE_INDEX, 1417 RING_BACKWARD(sc->sc_rx_cur, 1, IPW2200_RX_RING_SIZE)); 1418 } 1419 1420 int 1421 ipw2200_start_scan(struct ipw2200_softc *sc) 1422 { 1423 struct ieee80211com *ic = &sc->sc_ic; 1424 struct ipw2200_scan scan; 1425 uint8_t *ch; 1426 int cnt, i; 1427 1428 IPW2200_DBG(IPW2200_DBG_SCAN, (sc->sc_dip, CE_CONT, 1429 "ipw2200_start_scan(): start scanning \n")); 1430 1431 /* 1432 * start scanning 1433 */ 1434 sc->sc_flags |= IPW2200_FLAG_SCANNING; 1435 1436 (void) memset(&scan, 0, sizeof (scan)); 1437 scan.type = (ic->ic_des_esslen != 0) ? IPW2200_SCAN_TYPE_BDIRECTED : 1438 IPW2200_SCAN_TYPE_BROADCAST; 1439 scan.dwelltime = LE_16(40); /* The interval is set up to 40 */ 1440 1441 /* 1442 * Compact supported channel number(5G) into a single buffer 1443 */ 1444 ch = scan.channels; 1445 cnt = 0; 1446 for (i = 0; i <= IEEE80211_CHAN_MAX; i++) { 1447 if (IEEE80211_IS_CHAN_5GHZ(&ic->ic_sup_channels[i]) && 1448 isset(ic->ic_chan_active, i)) { 1449 *++ch = (uint8_t)i; 1450 cnt++; 1451 } 1452 } 1453 *(ch - cnt) = IPW2200_CHAN_5GHZ | (uint8_t)cnt; 1454 ch = (cnt > 0) ? (ch + 1) : (scan.channels); 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 enum ieee80211_state ostate; 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 1757 ostate = ic->ic_state; 1758 (void) ipw2200_init(sc); /* Force state machine */ 1759 /* 1760 * workround. Delay for a while after init especially 1761 * when something wrong happened already. 1762 */ 1763 delay(drv_usectohz(delay_fatal_recover)); 1764 1765 /* 1766 * Init scan will recovery the original connection if 1767 * the original state is run 1768 */ 1769 if (ostate != IEEE80211_S_INIT) 1770 ieee80211_begin_scan(ic, 0); 1771 1772 mutex_enter(&sc->sc_mflock); 1773 } 1774 1775 /* 1776 * get statistic, the value will be retrieved by m_stat 1777 */ 1778 if (stat_cnt == 10) { 1779 1780 stat_cnt = 0; /* re-start */ 1781 mutex_exit(&sc->sc_mflock); 1782 ipw2200_get_statistics(sc); 1783 mutex_enter(&sc->sc_mflock); 1784 1785 } else 1786 stat_cnt++; /* until 1s */ 1787 1788 mutex_exit(&sc->sc_mflock); 1789 delay(drv_usectohz(delay_aux_thread)); 1790 mutex_enter(&sc->sc_mflock); 1791 1792 } 1793 sc->sc_mf_thread = NULL; 1794 cv_signal(&sc->sc_mfthread_cv); 1795 mutex_exit(&sc->sc_mflock); 1796 } 1797 1798 static int 1799 ipw2200_m_start(void *arg) 1800 { 1801 struct ipw2200_softc *sc = (struct ipw2200_softc *)arg; 1802 struct ieee80211com *ic = &sc->sc_ic; 1803 1804 IPW2200_DBG(IPW2200_DBG_GLD, (sc->sc_dip, CE_CONT, 1805 "ipw2200_m_start(): enter\n")); 1806 /* 1807 * initialize ipw2200 hardware, everything ok will start scan 1808 */ 1809 (void) ipw2200_init(sc); 1810 /* 1811 * set the state machine to INIT 1812 */ 1813 ieee80211_new_state(ic, IEEE80211_S_INIT, -1); 1814 1815 sc->sc_flags |= IPW2200_FLAG_RUNNING; 1816 1817 return (DDI_SUCCESS); 1818 } 1819 1820 static void 1821 ipw2200_m_stop(void *arg) 1822 { 1823 struct ipw2200_softc *sc = (struct ipw2200_softc *)arg; 1824 struct ieee80211com *ic = &sc->sc_ic; 1825 1826 IPW2200_DBG(IPW2200_DBG_GLD, (sc->sc_dip, CE_CONT, 1827 "ipw2200_m_stop(): enter\n")); 1828 1829 ipw2200_stop(sc); 1830 /* 1831 * set the state machine to INIT 1832 */ 1833 ieee80211_new_state(ic, IEEE80211_S_INIT, -1); 1834 1835 sc->sc_flags &= ~IPW2200_FLAG_RUNNING; 1836 } 1837 1838 static int 1839 ipw2200_m_unicst(void *arg, const uint8_t *macaddr) 1840 { 1841 struct ipw2200_softc *sc = (struct ipw2200_softc *)arg; 1842 struct ieee80211com *ic = &sc->sc_ic; 1843 int err; 1844 1845 IPW2200_DBG(IPW2200_DBG_GLD, (sc->sc_dip, CE_CONT, 1846 "ipw2200_m_unicst(): enter\n")); 1847 1848 IPW2200_DBG(IPW2200_DBG_GLD, (sc->sc_dip, CE_CONT, 1849 "ipw2200_m_unicst(): GLD setting MAC address to " 1850 "%02x:%02x:%02x:%02x:%02x:%02x\n", 1851 macaddr[0], macaddr[1], macaddr[2], 1852 macaddr[3], macaddr[4], macaddr[5])); 1853 1854 if (!IEEE80211_ADDR_EQ(ic->ic_macaddr, macaddr)) { 1855 1856 IEEE80211_ADDR_COPY(ic->ic_macaddr, macaddr); 1857 1858 if (sc->sc_flags & IPW2200_FLAG_RUNNING) { 1859 err = ipw2200_config(sc); 1860 if (err != DDI_SUCCESS) { 1861 IPW2200_WARN((sc->sc_dip, CE_WARN, 1862 "ipw2200_m_unicst(): " 1863 "device configuration failed\n")); 1864 goto fail; 1865 } 1866 } 1867 } 1868 return (DDI_SUCCESS); 1869 fail: 1870 return (err); 1871 } 1872 1873 static int 1874 ipw2200_m_promisc(void *arg, boolean_t on) 1875 { 1876 /* not supported */ 1877 struct ipw2200_softc *sc = (struct ipw2200_softc *)arg; 1878 1879 IPW2200_DBG(IPW2200_DBG_GLD, (sc->sc_dip, CE_CONT, 1880 "ipw2200_m_promisc(): enter. " 1881 "GLD setting promiscuous mode - %d\n", on)); 1882 1883 return (DDI_SUCCESS); 1884 } 1885 1886 static mblk_t * 1887 ipw2200_m_tx(void *arg, mblk_t *mp) 1888 { 1889 struct ipw2200_softc *sc = (struct ipw2200_softc *)arg; 1890 struct ieee80211com *ic = &sc->sc_ic; 1891 mblk_t *next; 1892 1893 /* 1894 * No data frames go out unless we're associated; this 1895 * should not happen as the 802.11 layer does not enable 1896 * the xmit queue until we enter the RUN state. 1897 */ 1898 if (ic->ic_state != IEEE80211_S_RUN) { 1899 IPW2200_DBG(IPW2200_DBG_GLD, (sc->sc_dip, CE_CONT, 1900 "ipw2200_m_tx(): discard msg, ic_state = %u\n", 1901 ic->ic_state)); 1902 freemsgchain(mp); 1903 return (NULL); 1904 } 1905 1906 while (mp != NULL) { 1907 next = mp->b_next; 1908 mp->b_next = NULL; 1909 if (ipw2200_send(ic, mp, IEEE80211_FC0_TYPE_DATA) == 1910 DDI_FAILURE) { 1911 mp->b_next = next; 1912 break; 1913 } 1914 mp = next; 1915 } 1916 return (mp); 1917 } 1918 1919 /* ARGSUSED */ 1920 static int 1921 ipw2200_send(ieee80211com_t *ic, mblk_t *mp, uint8_t type) 1922 { 1923 struct ipw2200_softc *sc = (struct ipw2200_softc *)ic; 1924 struct ieee80211_node *in; 1925 struct ieee80211_frame *wh; 1926 mblk_t *m0; 1927 size_t cnt, off; 1928 struct ipw2200_tx_desc *txdsc; 1929 struct dma_region *dr; 1930 uint32_t idx; 1931 int err; 1932 /* tmp pointer, used to pack header and payload */ 1933 uint8_t *p; 1934 1935 ASSERT(mp->b_next == NULL); 1936 1937 IPW2200_DBG(IPW2200_DBG_GLD, (sc->sc_dip, CE_CONT, 1938 "ipw2200_send(): enter\n")); 1939 1940 m0 = NULL; 1941 err = DDI_SUCCESS; 1942 1943 if ((type & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_DATA) { 1944 /* 1945 * skip all management frames since ipw2200 won't generate any 1946 * management frames. Therefore, drop this package. 1947 */ 1948 freemsg(mp); 1949 err = DDI_SUCCESS; 1950 goto fail0; 1951 } 1952 1953 mutex_enter(&sc->sc_tx_lock); 1954 1955 /* 1956 * need 1 empty descriptor 1957 */ 1958 if (sc->sc_tx_free <= IPW2200_TX_RING_MIN) { 1959 IPW2200_DBG(IPW2200_DBG_RING, (sc->sc_dip, CE_WARN, 1960 "ipw2200_send(): no enough descriptors(%d)\n", 1961 sc->sc_tx_free)); 1962 ic->ic_stats.is_tx_nobuf++; /* no enough buffer */ 1963 sc->sc_flags |= IPW2200_FLAG_TX_SCHED; 1964 err = DDI_FAILURE; 1965 goto fail1; 1966 } 1967 IPW2200_DBG(IPW2200_DBG_RING, (sc->sc_dip, CE_CONT, 1968 "ipw2200_send(): tx-free=%d,tx-curr=%d\n", 1969 sc->sc_tx_free, sc->sc_tx_cur)); 1970 1971 wh = (struct ieee80211_frame *)mp->b_rptr; 1972 in = ieee80211_find_txnode(ic, wh->i_addr1); 1973 if (in == NULL) { /* can not find the tx node, drop the package */ 1974 ic->ic_stats.is_tx_failed++; 1975 freemsg(mp); 1976 err = DDI_SUCCESS; 1977 goto fail1; 1978 } 1979 in->in_inact = 0; 1980 (void) ieee80211_encap(ic, mp, in); 1981 ieee80211_free_node(in); 1982 1983 /* 1984 * get txdsc and wh 1985 */ 1986 idx = sc->sc_tx_cur; 1987 txdsc = &sc->sc_txdsc[idx]; 1988 (void) memset(txdsc, 0, sizeof (*txdsc)); 1989 wh = (struct ieee80211_frame *)&txdsc->wh; 1990 1991 /* 1992 * extract header from message 1993 */ 1994 p = (uint8_t *)&txdsc->wh; 1995 off = 0; 1996 m0 = mp; 1997 while (off < sizeof (struct ieee80211_frame)) { 1998 cnt = MBLKL(m0); 1999 if (cnt > (sizeof (struct ieee80211_frame) - off)) 2000 cnt = sizeof (struct ieee80211_frame) - off; 2001 if (cnt) { 2002 (void) memcpy(p + off, m0->b_rptr, cnt); 2003 off += cnt; 2004 m0->b_rptr += cnt; 2005 } else 2006 m0 = m0->b_cont; 2007 } 2008 2009 /* 2010 * extract payload from message 2011 */ 2012 dr = &sc->sc_dma_txbufs[idx]; 2013 p = sc->sc_txbufs[idx]; 2014 off = 0; 2015 while (m0) { 2016 cnt = MBLKL(m0); 2017 if (cnt) 2018 (void) memcpy(p + off, m0->b_rptr, cnt); 2019 off += cnt; 2020 m0 = m0->b_cont; 2021 } 2022 2023 txdsc->hdr.type = IPW2200_HDR_TYPE_DATA; 2024 txdsc->hdr.flags = IPW2200_HDR_FLAG_IRQ; 2025 txdsc->cmd = IPW2200_DATA_CMD_TX; 2026 txdsc->len = LE_16(off); 2027 txdsc->flags = 0; 2028 2029 if (ic->ic_opmode == IEEE80211_M_IBSS) { 2030 if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) 2031 txdsc->flags |= IPW2200_DATA_FLAG_NEED_ACK; 2032 } else if (!IEEE80211_IS_MULTICAST(wh->i_addr3)) 2033 txdsc->flags |= IPW2200_DATA_FLAG_NEED_ACK; 2034 2035 if (ic->ic_flags & IEEE80211_F_PRIVACY) { 2036 wh->i_fc[1] |= IEEE80211_FC1_WEP; 2037 txdsc->wep_txkey = ic->ic_def_txkey; 2038 } 2039 else 2040 txdsc->flags |= IPW2200_DATA_FLAG_NO_WEP; 2041 2042 if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) 2043 txdsc->flags |= IPW2200_DATA_FLAG_SHPREAMBLE; 2044 2045 txdsc->nseg = LE_32(1); 2046 txdsc->seg_addr[0] = LE_32(dr->dr_pbase); 2047 txdsc->seg_len[0] = LE_32(off); 2048 2049 /* 2050 * DMA sync: buffer and desc 2051 */ 2052 (void) ddi_dma_sync(dr->dr_hnd, 0, 2053 IPW2200_TXBUF_SIZE, DDI_DMA_SYNC_FORDEV); 2054 (void) ddi_dma_sync(sc->sc_dma_txdsc.dr_hnd, 2055 idx * sizeof (struct ipw2200_tx_desc), 2056 sizeof (struct ipw2200_tx_desc), DDI_DMA_SYNC_FORDEV); 2057 2058 sc->sc_tx_cur = RING_FORWARD(sc->sc_tx_cur, 1, IPW2200_TX_RING_SIZE); 2059 sc->sc_tx_free--; 2060 2061 /* 2062 * update txcur 2063 */ 2064 ipw2200_csr_put32(sc, IPW2200_CSR_TX1_WRITE_INDEX, sc->sc_tx_cur); 2065 2066 /* 2067 * success, free the original message 2068 */ 2069 if (mp) 2070 freemsg(mp); 2071 2072 fail1: 2073 mutex_exit(&sc->sc_tx_lock); 2074 fail0: 2075 IPW2200_DBG(IPW2200_DBG_GLD, (sc->sc_dip, CE_CONT, 2076 "ipw2200_send(): exit - err=%d\n", err)); 2077 2078 return (err); 2079 } 2080 2081 /* 2082 * IOCTL handlers 2083 */ 2084 #define IEEE80211_IOCTL_REQUIRED (1) 2085 #define IEEE80211_IOCTL_NOT_REQUIRED (0) 2086 static void 2087 ipw2200_m_ioctl(void *arg, queue_t *q, mblk_t *m) 2088 { 2089 struct ipw2200_softc *sc = (struct ipw2200_softc *)arg; 2090 struct ieee80211com *ic = &sc->sc_ic; 2091 uint32_t err; 2092 2093 IPW2200_DBG(IPW2200_DBG_GLD, (sc->sc_dip, CE_CONT, 2094 "ipw2200_m_ioctl(): enter\n")); 2095 2096 /* 2097 * Check whether or not need to handle this in net80211 2098 * 2099 */ 2100 if (ipw2200_ioctl(sc, q, m) == IEEE80211_IOCTL_NOT_REQUIRED) 2101 return; 2102 2103 err = ieee80211_ioctl(ic, q, m); 2104 if (err == ENETRESET) { 2105 if (sc->sc_flags & IPW2200_FLAG_RUNNING) { 2106 (void) ipw2200_m_start(sc); 2107 (void) ieee80211_new_state(ic, 2108 IEEE80211_S_SCAN, -1); 2109 } 2110 } 2111 if (err == ERESTART) { 2112 if (sc->sc_flags & IPW2200_FLAG_RUNNING) 2113 (void) ipw2200_chip_reset(sc); 2114 } 2115 } 2116 static int 2117 ipw2200_ioctl(struct ipw2200_softc *sc, queue_t *q, mblk_t *m) 2118 { 2119 struct iocblk *iocp; 2120 uint32_t len, ret, cmd; 2121 mblk_t *m0; 2122 boolean_t need_privilege; 2123 boolean_t need_net80211; 2124 2125 if (MBLKL(m) < sizeof (struct iocblk)) { 2126 IPW2200_DBG(IPW2200_DBG_IOCTL, (sc->sc_dip, CE_CONT, 2127 "ipw2200_ioctl(): ioctl buffer too short, %u\n", 2128 MBLKL(m))); 2129 miocnak(q, m, 0, EINVAL); 2130 /* 2131 * Buf not enough, do not need net80211 either 2132 */ 2133 return (IEEE80211_IOCTL_NOT_REQUIRED); 2134 } 2135 2136 /* 2137 * Validate the command 2138 */ 2139 iocp = (struct iocblk *)m->b_rptr; 2140 iocp->ioc_error = 0; 2141 cmd = iocp->ioc_cmd; 2142 need_privilege = B_TRUE; 2143 switch (cmd) { 2144 case WLAN_SET_PARAM: 2145 case WLAN_COMMAND: 2146 break; 2147 case WLAN_GET_PARAM: 2148 need_privilege = B_FALSE; 2149 break; 2150 default: 2151 IPW2200_DBG(IPW2200_DBG_IOCTL, (sc->sc_dip, CE_CONT, 2152 "ipw2200_ioctl(): unknown cmd 0x%x", cmd)); 2153 miocnak(q, m, 0, EINVAL); 2154 /* 2155 * Unknown cmd, do not need net80211 either 2156 */ 2157 return (IEEE80211_IOCTL_NOT_REQUIRED); 2158 } 2159 2160 if (need_privilege) { 2161 /* 2162 * Check for specific net_config privilege on Solaris 10+. 2163 * Otherwise just check for root access ... 2164 */ 2165 if (secpolicy_net_config != NULL) 2166 ret = secpolicy_net_config(iocp->ioc_cr, B_FALSE); 2167 else 2168 ret = drv_priv(iocp->ioc_cr); 2169 if (ret != 0) { 2170 miocnak(q, m, 0, ret); 2171 /* 2172 * privilege check fail, do not need net80211 either 2173 */ 2174 return (IEEE80211_IOCTL_NOT_REQUIRED); 2175 } 2176 } 2177 /* 2178 * sanity check 2179 */ 2180 m0 = m->b_cont; 2181 if (iocp->ioc_count == 0 || iocp->ioc_count < sizeof (wldp_t) || 2182 m0 == NULL) { 2183 miocnak(q, m, 0, EINVAL); 2184 /* 2185 * invalid format, do not need net80211 either 2186 */ 2187 return (IEEE80211_IOCTL_NOT_REQUIRED); 2188 } 2189 /* 2190 * assuming single data block 2191 */ 2192 if (m0->b_cont) { 2193 freemsg(m0->b_cont); 2194 m0->b_cont = NULL; 2195 } 2196 2197 need_net80211 = B_FALSE; 2198 ret = ipw2200_getset(sc, m0, cmd, &need_net80211); 2199 if (!need_net80211) { 2200 len = msgdsize(m0); 2201 2202 IPW2200_DBG(IPW2200_DBG_IOCTL, (sc->sc_dip, CE_CONT, 2203 "ipw2200_ioctl(): go to call miocack with " 2204 "ret = %d, len = %d\n", ret, len)); 2205 miocack(q, m, len, ret); 2206 return (IEEE80211_IOCTL_NOT_REQUIRED); 2207 } 2208 2209 /* 2210 * IEEE80211_IOCTL - need net80211 handle 2211 */ 2212 return (IEEE80211_IOCTL_REQUIRED); 2213 } 2214 2215 static int 2216 ipw2200_getset(struct ipw2200_softc *sc, mblk_t *m, uint32_t cmd, 2217 boolean_t *need_net80211) 2218 { 2219 wldp_t *infp, *outfp; 2220 uint32_t id; 2221 int ret; 2222 2223 infp = (wldp_t *)m->b_rptr; 2224 outfp = (wldp_t *)m->b_rptr; 2225 outfp->wldp_result = WL_NOTSUPPORTED; 2226 2227 id = infp->wldp_id; 2228 IPW2200_DBG(IPW2200_DBG_IOCTL, (sc->sc_dip, CE_CONT, 2229 "ipw2200_getset(): id = 0x%x\n", id)); 2230 switch (id) { 2231 case WL_RADIO: /* which is not supported by net80211 */ 2232 ret = iwi_wificfg_radio(sc, cmd, outfp); 2233 break; 2234 case WL_DESIRED_RATES: /* hardware doesn't support fix-rates */ 2235 ret = iwi_wificfg_desrates(outfp); 2236 break; 2237 default: 2238 /* 2239 * The wifi IOCTL net80211 supported: 2240 * case WL_ESSID: 2241 * case WL_BSSID: 2242 * case WL_WEP_KEY_TAB: 2243 * case WL_WEP_KEY_ID: 2244 * case WL_AUTH_MODE: 2245 * case WL_ENCRYPTION: 2246 * case WL_BSS_TYPE: 2247 * case WL_ESS_LIST: 2248 * case WL_LINKSTATUS: 2249 * case WL_RSSI: 2250 * case WL_SCAN: 2251 * case WL_LOAD_DEFAULTS: 2252 * case WL_DISASSOCIATE: 2253 */ 2254 *need_net80211 = B_TRUE; /* let net80211 do the rest */ 2255 return (0); 2256 } 2257 /* 2258 * we will overwrite everything 2259 */ 2260 m->b_wptr = m->b_rptr + outfp->wldp_length; 2261 return (ret); 2262 } 2263 2264 static int 2265 iwi_wificfg_radio(struct ipw2200_softc *sc, uint32_t cmd, wldp_t *outfp) 2266 { 2267 uint32_t ret = ENOTSUP; 2268 2269 switch (cmd) { 2270 case WLAN_GET_PARAM: 2271 *(wl_linkstatus_t *)(outfp->wldp_buf) = 2272 ipw2200_radio_status(sc); 2273 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_linkstatus_t); 2274 outfp->wldp_result = WL_SUCCESS; 2275 ret = 0; /* command success */ 2276 break; 2277 case WLAN_SET_PARAM: 2278 default: 2279 break; 2280 } 2281 return (ret); 2282 } 2283 2284 static int 2285 iwi_wificfg_desrates(wldp_t *outfp) 2286 { 2287 /* return success, but with result NOTSUPPORTED */ 2288 outfp->wldp_length = WIFI_BUF_OFFSET; 2289 outfp->wldp_result = WL_NOTSUPPORTED; 2290 return (0); 2291 } 2292 /* End of IOCTL Handlers */ 2293 2294 void 2295 ipw2200_fix_channel(struct ieee80211com *ic, mblk_t *m) 2296 { 2297 struct ieee80211_frame *wh; 2298 uint8_t subtype; 2299 uint8_t *frm, *efrm; 2300 2301 wh = (struct ieee80211_frame *)m->b_rptr; 2302 2303 if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_MGT) 2304 return; 2305 2306 subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; 2307 2308 if (subtype != IEEE80211_FC0_SUBTYPE_BEACON && 2309 subtype != IEEE80211_FC0_SUBTYPE_PROBE_RESP) 2310 return; 2311 2312 /* 2313 * assume the message contains only 1 block 2314 */ 2315 frm = (uint8_t *)(wh + 1); 2316 efrm = (uint8_t *)m->b_wptr; 2317 frm += 12; /* skip tstamp, bintval and capinfo fields */ 2318 while (frm < efrm) { 2319 if (*frm == IEEE80211_ELEMID_DSPARMS) 2320 #if IEEE80211_CHAN_MAX < 255 2321 if (frm[2] <= IEEE80211_CHAN_MAX) 2322 #endif 2323 ic->ic_curchan = &ic->ic_sup_channels[frm[2]]; 2324 frm += frm[1] + 2; 2325 } 2326 } 2327 2328 static void 2329 ipw2200_rcv_frame(struct ipw2200_softc *sc, struct ipw2200_frame *frame) 2330 { 2331 struct ieee80211com *ic = &sc->sc_ic; 2332 uint8_t *data = (uint8_t *)frame; 2333 uint32_t len; 2334 struct ieee80211_frame *wh; 2335 struct ieee80211_node *in; 2336 mblk_t *m; 2337 int i; 2338 2339 len = LE_16(frame->len); 2340 2341 /* 2342 * Skip the frame header, get the real data from the input 2343 */ 2344 data += sizeof (struct ipw2200_frame); 2345 2346 if ((len < sizeof (struct ieee80211_frame_min)) || 2347 (len > IPW2200_RXBUF_SIZE)) { 2348 IPW2200_DBG(IPW2200_DBG_RX, (sc->sc_dip, CE_CONT, 2349 "ipw2200_rcv_frame(): bad frame length=%u\n", 2350 LE_16(frame->len))); 2351 return; 2352 } 2353 2354 IPW2200_DBG(IPW2200_DBG_RX, (sc->sc_dip, CE_CONT, 2355 "ipw2200_rcv_frame(): chan = %d, length = %d\n", frame->chan, len)); 2356 2357 m = allocb(len, BPRI_MED); 2358 if (m) { 2359 (void) memcpy(m->b_wptr, data, len); 2360 m->b_wptr += len; 2361 2362 wh = (struct ieee80211_frame *)m->b_rptr; 2363 if (wh->i_fc[1] & IEEE80211_FC1_WEP) { 2364 /* 2365 * h/w decyption leaves the WEP bit, iv and CRC fields 2366 */ 2367 wh->i_fc[1] &= ~IEEE80211_FC1_WEP; 2368 for (i = sizeof (struct ieee80211_frame) - 1; 2369 i >= 0; i--) 2370 *(m->b_rptr + IEEE80211_WEP_IVLEN + 2371 IEEE80211_WEP_KIDLEN + i) = 2372 *(m->b_rptr + i); 2373 m->b_rptr += IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN; 2374 m->b_wptr -= IEEE80211_WEP_CRCLEN; 2375 wh = (struct ieee80211_frame *)m->b_rptr; 2376 } 2377 2378 if (ic->ic_state == IEEE80211_S_SCAN) { 2379 ic->ic_ibss_chan = &ic->ic_sup_channels[frame->chan]; 2380 ipw2200_fix_channel(ic, m); 2381 } 2382 2383 in = ieee80211_find_rxnode(ic, wh); 2384 IPW2200_DBG(IPW2200_DBG_RX, (sc->sc_dip, CE_CONT, 2385 "ipw2200_rcv_frame(): " 2386 "ni_esslen:%d, ni_essid[0-5]:%c%c%c%c%c%c\n", 2387 in->in_esslen, 2388 in->in_essid[0], in->in_essid[1], in->in_essid[2], 2389 in->in_essid[3], in->in_essid[4], in->in_essid[5])); 2390 2391 (void) ieee80211_input(ic, m, in, frame->rssi_dbm, 0); 2392 2393 ieee80211_free_node(in); 2394 } 2395 else 2396 IPW2200_WARN((sc->sc_dip, CE_WARN, 2397 "ipw2200_rcv_frame(): " 2398 "cannot allocate receive message(%u)\n", 2399 LE_16(frame->len))); 2400 } 2401 2402 static void 2403 ipw2200_rcv_notif(struct ipw2200_softc *sc, struct ipw2200_notif *notif) 2404 { 2405 struct ieee80211com *ic = &sc->sc_ic; 2406 struct ipw2200_notif_association *assoc; 2407 struct ipw2200_notif_authentication *auth; 2408 uint8_t *ndata = (uint8_t *)notif; 2409 2410 IPW2200_DBG(IPW2200_DBG_NOTIF, (sc->sc_dip, CE_CONT, 2411 "ipw2200_rcv_notif(): type=%u\n", notif->type)); 2412 2413 ndata += sizeof (struct ipw2200_notif); 2414 switch (notif->type) { 2415 case IPW2200_NOTIF_TYPE_ASSOCIATION: 2416 assoc = (struct ipw2200_notif_association *)ndata; 2417 2418 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 2419 "ipw2200_rcv_notif(): association=%u,%u\n", 2420 assoc->state, assoc->status)); 2421 2422 switch (assoc->state) { 2423 case IPW2200_ASSOC_SUCCESS: 2424 ieee80211_new_state(ic, IEEE80211_S_RUN, -1); 2425 break; 2426 case IPW2200_ASSOC_FAIL: 2427 ieee80211_begin_scan(ic, 1); /* reset */ 2428 break; 2429 default: 2430 break; 2431 } 2432 break; 2433 2434 case IPW2200_NOTIF_TYPE_AUTHENTICATION: 2435 auth = (struct ipw2200_notif_authentication *)ndata; 2436 2437 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 2438 "ipw2200_rcv_notif(): authentication=%u\n", auth->state)); 2439 2440 switch (auth->state) { 2441 case IPW2200_AUTH_SUCCESS: 2442 ieee80211_new_state(ic, IEEE80211_S_ASSOC, -1); 2443 break; 2444 case IPW2200_AUTH_FAIL: 2445 break; 2446 default: 2447 IPW2200_DBG(IPW2200_DBG_NOTIF, (sc->sc_dip, CE_CONT, 2448 "ipw2200_rcv_notif(): " 2449 "unknown authentication state(%u)\n", auth->state)); 2450 break; 2451 } 2452 break; 2453 2454 case IPW2200_NOTIF_TYPE_SCAN_CHANNEL: 2455 IPW2200_DBG(IPW2200_DBG_SCAN, (sc->sc_dip, CE_CONT, 2456 "ipw2200_rcv_notif(): scan-channel=%u\n", 2457 ((struct ipw2200_notif_scan_channel *)ndata)->nchan)); 2458 break; 2459 2460 case IPW2200_NOTIF_TYPE_SCAN_COMPLETE: 2461 IPW2200_DBG(IPW2200_DBG_SCAN, (sc->sc_dip, CE_CONT, 2462 "ipw2200_rcv_notif():scan-completed,(%u,%u)\n", 2463 ((struct ipw2200_notif_scan_complete *)ndata)->nchan, 2464 ((struct ipw2200_notif_scan_complete *)ndata)->status)); 2465 2466 /* 2467 * scan complete 2468 */ 2469 sc->sc_flags &= ~IPW2200_FLAG_SCANNING; 2470 ieee80211_end_scan(ic); 2471 break; 2472 2473 case IPW2200_NOTIF_TYPE_BEACON: 2474 case IPW2200_NOTIF_TYPE_CALIBRATION: 2475 case IPW2200_NOTIF_TYPE_NOISE: 2476 /* 2477 * just ignore 2478 */ 2479 break; 2480 default: 2481 IPW2200_DBG(IPW2200_DBG_NOTIF, (sc->sc_dip, CE_CONT, 2482 "ipw2200_rcv_notif(): unknown notification type(%u)\n", 2483 notif->type)); 2484 break; 2485 } 2486 } 2487 2488 static uint_t 2489 ipw2200_intr(caddr_t arg) 2490 { 2491 struct ipw2200_softc *sc = (struct ipw2200_softc *)arg; 2492 struct ieee80211com *ic = &sc->sc_ic; 2493 uint32_t ireg, ridx, len, i; 2494 uint8_t *p, *rxbuf; 2495 struct dma_region *dr; 2496 struct ipw2200_hdr *hdr; 2497 int need_sched; 2498 uint32_t widx; 2499 2500 ireg = ipw2200_csr_get32(sc, IPW2200_CSR_INTR); 2501 2502 if (ireg == 0xffffffff) 2503 return (DDI_INTR_UNCLAIMED); 2504 2505 if (!(ireg & IPW2200_INTR_MASK_ALL)) 2506 return (DDI_INTR_UNCLAIMED); 2507 2508 /* 2509 * mask all interrupts 2510 */ 2511 ipw2200_csr_put32(sc, IPW2200_CSR_INTR_MASK, 0); 2512 2513 /* 2514 * acknowledge all fired interrupts 2515 */ 2516 ipw2200_csr_put32(sc, IPW2200_CSR_INTR, ireg); 2517 2518 IPW2200_DBG(IPW2200_DBG_INT, (sc->sc_dip, CE_CONT, 2519 "ipw2200_intr(): enter. interrupt fired, int=0x%08x\n", ireg)); 2520 2521 if (ireg & IPW2200_INTR_MASK_ERR) { 2522 2523 IPW2200_DBG(IPW2200_DBG_FATAL, (sc->sc_dip, CE_CONT, 2524 "ipw2200 interrupt(): int= 0x%08x\n", ireg)); 2525 2526 /* 2527 * inform mfthread to recover hw error by stopping it 2528 */ 2529 mutex_enter(&sc->sc_mflock); 2530 sc->sc_flags |= IPW2200_FLAG_HW_ERR_RECOVER; 2531 mutex_exit(&sc->sc_mflock); 2532 2533 } else { 2534 if (ireg & IPW2200_INTR_FW_INITED) { 2535 mutex_enter(&sc->sc_ilock); 2536 sc->sc_fw_ok = 1; 2537 cv_signal(&sc->sc_fw_cond); 2538 mutex_exit(&sc->sc_ilock); 2539 } 2540 if (ireg & IPW2200_INTR_RADIO_OFF) { 2541 IPW2200_REPORT((sc->sc_dip, CE_CONT, 2542 "ipw2200_intr(): radio is OFF\n")); 2543 /* 2544 * Stop hardware, will notify LINK is down 2545 */ 2546 ipw2200_stop(sc); 2547 } 2548 if (ireg & IPW2200_INTR_CMD_TRANSFER) { 2549 mutex_enter(&sc->sc_cmd_lock); 2550 ridx = ipw2200_csr_get32(sc, 2551 IPW2200_CSR_CMD_READ_INDEX); 2552 i = RING_FORWARD(sc->sc_cmd_cur, 2553 sc->sc_cmd_free, IPW2200_CMD_RING_SIZE); 2554 len = RING_FLEN(i, ridx, IPW2200_CMD_RING_SIZE); 2555 2556 IPW2200_DBG(IPW2200_DBG_INT, (sc->sc_dip, CE_CONT, 2557 "ipw2200_intr(): cmd-ring,i=%u,ridx=%u,len=%u\n", 2558 i, ridx, len)); 2559 2560 if (len > 0) { 2561 sc->sc_cmd_free += len; 2562 cv_signal(&sc->sc_cmd_cond); 2563 } 2564 for (; i != ridx; 2565 i = RING_FORWARD(i, 1, IPW2200_CMD_RING_SIZE)) 2566 sc->sc_done[i] = 1; 2567 mutex_exit(&sc->sc_cmd_lock); 2568 2569 mutex_enter(&sc->sc_ilock); 2570 cv_signal(&sc->sc_cmd_status_cond); 2571 mutex_exit(&sc->sc_ilock); 2572 } 2573 if (ireg & IPW2200_INTR_RX_TRANSFER) { 2574 ridx = ipw2200_csr_get32(sc, 2575 IPW2200_CSR_RX_READ_INDEX); 2576 widx = ipw2200_csr_get32(sc, 2577 IPW2200_CSR_RX_WRITE_INDEX); 2578 2579 IPW2200_DBG(IPW2200_DBG_INT, (sc->sc_dip, CE_CONT, 2580 "ipw2200_intr(): rx-ring,widx=%u,ridx=%u\n", 2581 ridx, widx)); 2582 2583 for (; sc->sc_rx_cur != ridx; 2584 sc->sc_rx_cur = RING_FORWARD(sc->sc_rx_cur, 1, 2585 IPW2200_RX_RING_SIZE)) { 2586 i = sc->sc_rx_cur; 2587 rxbuf = sc->sc_rxbufs[i]; 2588 dr = &sc->sc_dma_rxbufs[i]; 2589 2590 /* 2591 * DMA sync 2592 */ 2593 (void) ddi_dma_sync(dr->dr_hnd, 0, 2594 IPW2200_RXBUF_SIZE, DDI_DMA_SYNC_FORKERNEL); 2595 /* 2596 * Get rx header(hdr) and rx data(p) from rxbuf 2597 */ 2598 p = rxbuf; 2599 hdr = (struct ipw2200_hdr *)p; 2600 p += sizeof (struct ipw2200_hdr); 2601 2602 IPW2200_DBG(IPW2200_DBG_INT, 2603 (sc->sc_dip, CE_CONT, 2604 "ipw2200_intr(): Rx hdr type %u\n", 2605 hdr->type)); 2606 2607 switch (hdr->type) { 2608 case IPW2200_HDR_TYPE_FRAME: 2609 ipw2200_rcv_frame(sc, 2610 (struct ipw2200_frame *)p); 2611 break; 2612 2613 case IPW2200_HDR_TYPE_NOTIF: 2614 ipw2200_rcv_notif(sc, 2615 (struct ipw2200_notif *)p); 2616 break; 2617 default: 2618 IPW2200_DBG(IPW2200_DBG_INT, 2619 (sc->sc_dip, CE_CONT, 2620 "ipw2200_intr(): " 2621 "unknown Rx hdr type %u\n", 2622 hdr->type)); 2623 break; 2624 } 2625 } 2626 /* 2627 * write sc_rx_cur backward 1 step into RX_WRITE_INDEX 2628 */ 2629 ipw2200_csr_put32(sc, IPW2200_CSR_RX_WRITE_INDEX, 2630 RING_BACKWARD(sc->sc_rx_cur, 1, 2631 IPW2200_RX_RING_SIZE)); 2632 } 2633 if (ireg & IPW2200_INTR_TX1_TRANSFER) { 2634 mutex_enter(&sc->sc_tx_lock); 2635 ridx = ipw2200_csr_get32(sc, 2636 IPW2200_CSR_TX1_READ_INDEX); 2637 len = RING_FLEN(RING_FORWARD(sc->sc_tx_cur, 2638 sc->sc_tx_free, IPW2200_TX_RING_SIZE), 2639 ridx, IPW2200_TX_RING_SIZE); 2640 IPW2200_DBG(IPW2200_DBG_RING, (sc->sc_dip, CE_CONT, 2641 "ipw2200_intr(): tx-ring,ridx=%u,len=%u\n", 2642 ridx, len)); 2643 sc->sc_tx_free += len; 2644 2645 need_sched = 0; 2646 if ((sc->sc_tx_free > IPW2200_TX_RING_MIN) && 2647 (sc->sc_flags & IPW2200_FLAG_TX_SCHED)) { 2648 IPW2200_DBG(IPW2200_DBG_RING, (sc->sc_dip, 2649 CE_CONT, 2650 "ipw2200_intr(): Need Reschedule!")); 2651 need_sched = 1; 2652 sc->sc_flags &= ~IPW2200_FLAG_TX_SCHED; 2653 } 2654 mutex_exit(&sc->sc_tx_lock); 2655 2656 if (need_sched) 2657 mac_tx_update(ic->ic_mach); 2658 } 2659 } 2660 2661 /* 2662 * enable all interrupts 2663 */ 2664 ipw2200_csr_put32(sc, IPW2200_CSR_INTR_MASK, IPW2200_INTR_MASK_ALL); 2665 2666 return (DDI_INTR_CLAIMED); 2667 } 2668 2669 2670 /* 2671 * Module Loading Data & Entry Points 2672 */ 2673 DDI_DEFINE_STREAM_OPS(ipw2200_devops, nulldev, nulldev, ipw2200_attach, 2674 ipw2200_detach, nodev, NULL, D_MP, NULL); 2675 2676 static struct modldrv ipw2200_modldrv = { 2677 &mod_driverops, 2678 ipw2200_ident, 2679 &ipw2200_devops 2680 }; 2681 2682 static struct modlinkage ipw2200_modlinkage = { 2683 MODREV_1, 2684 &ipw2200_modldrv, 2685 NULL 2686 }; 2687 2688 int 2689 _init(void) 2690 { 2691 int status; 2692 2693 status = ddi_soft_state_init(&ipw2200_ssp, 2694 sizeof (struct ipw2200_softc), 1); 2695 if (status != DDI_SUCCESS) 2696 return (status); 2697 2698 mac_init_ops(&ipw2200_devops, IPW2200_DRV_NAME); 2699 status = mod_install(&ipw2200_modlinkage); 2700 if (status != DDI_SUCCESS) { 2701 mac_fini_ops(&ipw2200_devops); 2702 ddi_soft_state_fini(&ipw2200_ssp); 2703 } 2704 2705 return (status); 2706 } 2707 2708 int 2709 _fini(void) 2710 { 2711 int status; 2712 2713 status = mod_remove(&ipw2200_modlinkage); 2714 if (status == DDI_SUCCESS) { 2715 mac_fini_ops(&ipw2200_devops); 2716 ddi_soft_state_fini(&ipw2200_ssp); 2717 } 2718 2719 return (status); 2720 } 2721 2722 int 2723 _info(struct modinfo *modinfop) 2724 { 2725 return (mod_info(&ipw2200_modlinkage, modinfop)); 2726 } 2727