1 /* 2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* 7 * Copyright(c) 2004 8 * Damien Bergamini <damien.bergamini@free.fr>. All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice unmodified, this list of conditions, and the following 15 * disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #include <sys/types.h> 34 #include <sys/byteorder.h> 35 #include <sys/conf.h> 36 #include <sys/cmn_err.h> 37 #include <sys/stat.h> 38 #include <sys/ddi.h> 39 #include <sys/sunddi.h> 40 #include <sys/strsubr.h> 41 #include <sys/ethernet.h> 42 #include <inet/common.h> 43 #include <inet/nd.h> 44 #include <inet/mi.h> 45 #include <sys/note.h> 46 #include <sys/stream.h> 47 #include <sys/strsun.h> 48 #include <sys/modctl.h> 49 #include <sys/devops.h> 50 #include <sys/dlpi.h> 51 #include <sys/mac_provider.h> 52 #include <net/if.h> 53 #include <sys/mac_wifi.h> 54 #include <sys/varargs.h> 55 #include <sys/policy.h> 56 57 #include "ipw2100.h" 58 #include "ipw2100_impl.h" 59 #include <inet/wifi_ioctl.h> 60 61 /* 62 * kCF framework include files 63 */ 64 #include <sys/crypto/common.h> 65 #include <sys/crypto/api.h> 66 67 static void *ipw2100_ssp = NULL; 68 static char ipw2100_ident[] = IPW2100_DRV_DESC; 69 70 /* 71 * PIO access attribute for register 72 */ 73 static ddi_device_acc_attr_t ipw2100_csr_accattr = { 74 DDI_DEVICE_ATTR_V0, 75 DDI_STRUCTURE_LE_ACC, 76 DDI_STRICTORDER_ACC 77 }; 78 79 static ddi_device_acc_attr_t ipw2100_dma_accattr = { 80 DDI_DEVICE_ATTR_V0, 81 DDI_NEVERSWAP_ACC, 82 DDI_STRICTORDER_ACC 83 }; 84 85 static ddi_dma_attr_t ipw2100_dma_attr = { 86 DMA_ATTR_V0, 87 0x0000000000000000ULL, 88 0x00000000ffffffffULL, 89 0x00000000ffffffffULL, 90 0x0000000000000004ULL, 91 0xfff, 92 1, 93 0x00000000ffffffffULL, 94 0x00000000ffffffffULL, 95 1, 96 1, 97 0 98 }; 99 100 static const struct ieee80211_rateset ipw2100_rateset_11b = { 4, 101 {2, 4, 11, 22} 102 }; 103 104 /* 105 * For mfthread only 106 */ 107 extern pri_t minclsyspri; 108 109 /* 110 * ipw2100 specific hardware operations 111 */ 112 static void ipw2100_hwconf_get(struct ipw2100_softc *sc); 113 static int ipw2100_chip_reset(struct ipw2100_softc *sc); 114 static void ipw2100_master_stop(struct ipw2100_softc *sc); 115 static void ipw2100_stop(struct ipw2100_softc *sc); 116 static int ipw2100_config(struct ipw2100_softc *sc); 117 static int ipw2100_cmd(struct ipw2100_softc *sc, uint32_t type, 118 void *buf, size_t len); 119 static int ipw2100_dma_region_alloc(struct ipw2100_softc *sc, 120 struct dma_region *dr, size_t size, uint_t dir, uint_t flags); 121 static void ipw2100_dma_region_free(struct dma_region *dr); 122 static void ipw2100_tables_init(struct ipw2100_softc *sc); 123 static void ipw2100_ring_hwsetup(struct ipw2100_softc *sc); 124 static int ipw2100_ring_alloc(struct ipw2100_softc *sc); 125 static void ipw2100_ring_free(struct ipw2100_softc *sc); 126 static void ipw2100_ring_reset(struct ipw2100_softc *sc); 127 static int ipw2100_ring_init(struct ipw2100_softc *sc); 128 129 /* 130 * GLD specific operations 131 */ 132 static int ipw2100_m_stat(void *arg, uint_t stat, uint64_t *val); 133 static int ipw2100_m_start(void *arg); 134 static void ipw2100_m_stop(void *arg); 135 static int ipw2100_m_unicst(void *arg, const uint8_t *macaddr); 136 static int ipw2100_m_multicst(void *arg, boolean_t add, const uint8_t *m); 137 static int ipw2100_m_promisc(void *arg, boolean_t on); 138 static mblk_t *ipw2100_m_tx(void *arg, mblk_t *mp); 139 static void ipw2100_m_ioctl(void *arg, queue_t *wq, mblk_t *mp); 140 static int ipw2100_m_setprop(void *arg, const char *pr_name, 141 mac_prop_id_t wldp_pr_num, uint_t wldp_length, const void *wldp_buf); 142 static int ipw2100_m_getprop(void *arg, const char *pr_name, 143 mac_prop_id_t wldp_pr_num, uint_t pr_flags, uint_t wldp_length, 144 void *wldp_buf, uint_t *perm); 145 146 147 /* 148 * Interrupt and Data transferring operations 149 */ 150 static uint_t ipw2100_intr(caddr_t arg); 151 static int ipw2100_send(struct ieee80211com *ic, mblk_t *mp, uint8_t type); 152 static void ipw2100_rcvpkt(struct ipw2100_softc *sc, 153 struct ipw2100_status *status, uint8_t *rxbuf); 154 155 /* 156 * WiFi specific operations 157 */ 158 static int ipw2100_newstate(struct ieee80211com *ic, 159 enum ieee80211_state state, int arg); 160 static void ipw2100_thread(struct ipw2100_softc *sc); 161 162 /* 163 * IOCTL Handler 164 */ 165 static int ipw2100_ioctl(struct ipw2100_softc *sc, queue_t *q, mblk_t *m); 166 static int ipw2100_getset(struct ipw2100_softc *sc, 167 mblk_t *m, uint32_t cmd, boolean_t *need_net80211); 168 static int ipw_wificfg_radio(struct ipw2100_softc *sc, 169 uint32_t cmd, wldp_t *outfp); 170 static int ipw_wificfg_desrates(wldp_t *outfp); 171 static int ipw_wificfg_disassoc(struct ipw2100_softc *sc, 172 wldp_t *outfp); 173 174 /* 175 * Suspend / Resume operations 176 */ 177 static int ipw2100_cpr_suspend(struct ipw2100_softc *sc); 178 static int ipw2100_cpr_resume(struct ipw2100_softc *sc); 179 180 /* 181 * Mac Call Back entries 182 */ 183 mac_callbacks_t ipw2100_m_callbacks = { 184 MC_IOCTL | MC_SETPROP | MC_GETPROP, 185 ipw2100_m_stat, 186 ipw2100_m_start, 187 ipw2100_m_stop, 188 ipw2100_m_promisc, 189 ipw2100_m_multicst, 190 ipw2100_m_unicst, 191 ipw2100_m_tx, 192 ipw2100_m_ioctl, 193 NULL, 194 NULL, 195 NULL, 196 ipw2100_m_setprop, 197 ipw2100_m_getprop 198 }; 199 200 201 /* 202 * DEBUG Facility 203 */ 204 #define MAX_MSG (128) 205 uint32_t ipw2100_debug = 0; 206 /* 207 * supported debug marsks: 208 * | IPW2100_DBG_INIT 209 * | IPW2100_DBG_GLD 210 * | IPW2100_DBG_TABLE 211 * | IPW2100_DBG_SOFTINT 212 * | IPW2100_DBG_CSR 213 * | IPW2100_DBG_INT 214 * | IPW2100_DBG_FW 215 * | IPW2100_DBG_IOCTL 216 * | IPW2100_DBG_HWCAP 217 * | IPW2100_DBG_STATISTIC 218 * | IPW2100_DBG_RING 219 * | IPW2100_DBG_WIFI 220 * | IPW2100_DBG_BRUSSELS 221 */ 222 223 /* 224 * global tuning parameters to work around unknown hardware issues 225 */ 226 static uint32_t delay_config_stable = 100000; /* 100ms */ 227 static uint32_t delay_fatal_recover = 100000 * 20; /* 2s */ 228 static uint32_t delay_aux_thread = 100000; /* 100ms */ 229 230 void 231 ipw2100_dbg(dev_info_t *dip, int level, const char *fmt, ...) 232 { 233 va_list ap; 234 char buf[MAX_MSG]; 235 int instance; 236 237 va_start(ap, fmt); 238 (void) vsnprintf(buf, sizeof (buf), fmt, ap); 239 va_end(ap); 240 241 if (dip) { 242 instance = ddi_get_instance(dip); 243 cmn_err(level, "%s%d: %s", IPW2100_DRV_NAME, instance, buf); 244 } else 245 cmn_err(level, "%s: %s", IPW2100_DRV_NAME, buf); 246 } 247 248 /* 249 * device operations 250 */ 251 int 252 ipw2100_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 253 { 254 struct ipw2100_softc *sc; 255 ddi_acc_handle_t cfgh; 256 caddr_t regs; 257 struct ieee80211com *ic; 258 int instance, err, i; 259 char strbuf[32]; 260 wifi_data_t wd = { 0 }; 261 mac_register_t *macp; 262 263 switch (cmd) { 264 case DDI_ATTACH: 265 break; 266 case DDI_RESUME: 267 sc = ddi_get_soft_state(ipw2100_ssp, ddi_get_instance(dip)); 268 if (sc == NULL) { 269 err = DDI_FAILURE; 270 goto fail1; 271 } 272 return (ipw2100_cpr_resume(sc)); 273 default: 274 err = DDI_FAILURE; 275 goto fail1; 276 } 277 278 instance = ddi_get_instance(dip); 279 err = ddi_soft_state_zalloc(ipw2100_ssp, instance); 280 if (err != DDI_SUCCESS) { 281 IPW2100_WARN((dip, CE_WARN, 282 "ipw2100_attach(): unable to allocate soft state\n")); 283 goto fail1; 284 } 285 sc = ddi_get_soft_state(ipw2100_ssp, instance); 286 sc->sc_dip = dip; 287 288 /* 289 * Map config spaces register 290 */ 291 err = ddi_regs_map_setup(dip, IPW2100_PCI_CFG_RNUM, ®s, 292 0, 0, &ipw2100_csr_accattr, &cfgh); 293 if (err != DDI_SUCCESS) { 294 IPW2100_WARN((dip, CE_WARN, 295 "ipw2100_attach(): unable to map spaces regs\n")); 296 goto fail2; 297 } 298 ddi_put8(cfgh, (uint8_t *)(regs + 0x41), 0); 299 ddi_regs_map_free(&cfgh); 300 301 /* 302 * Map operating registers 303 */ 304 err = ddi_regs_map_setup(dip, IPW2100_PCI_CSR_RNUM, &sc->sc_regs, 305 0, 0, &ipw2100_csr_accattr, &sc->sc_ioh); 306 if (err != DDI_SUCCESS) { 307 IPW2100_WARN((dip, CE_WARN, 308 "ipw2100_attach(): unable to map device regs\n")); 309 goto fail2; 310 } 311 312 /* 313 * Reset the chip 314 */ 315 err = ipw2100_chip_reset(sc); 316 if (err != DDI_SUCCESS) { 317 IPW2100_WARN((dip, CE_WARN, 318 "ipw2100_attach(): reset failed\n")); 319 goto fail3; 320 } 321 322 /* 323 * Get the hw conf, including MAC address, then init all rings. 324 */ 325 ipw2100_hwconf_get(sc); 326 err = ipw2100_ring_init(sc); 327 if (err != DDI_SUCCESS) { 328 IPW2100_WARN((dip, CE_WARN, 329 "ipw2100_attach(): " 330 "unable to allocate and initialize rings\n")); 331 goto fail3; 332 } 333 334 /* 335 * Initialize mutexs and condvars 336 */ 337 err = ddi_get_iblock_cookie(dip, 0, &sc->sc_iblk); 338 if (err != DDI_SUCCESS) { 339 IPW2100_WARN((dip, CE_WARN, 340 "ipw2100_attach(): ddi_get_iblock_cookie() failed\n")); 341 goto fail4; 342 } 343 /* 344 * interrupt lock 345 */ 346 mutex_init(&sc->sc_ilock, "interrupt-lock", MUTEX_DRIVER, 347 (void *) sc->sc_iblk); 348 cv_init(&sc->sc_fw_cond, "firmware", CV_DRIVER, NULL); 349 cv_init(&sc->sc_cmd_cond, "command", CV_DRIVER, NULL); 350 /* 351 * tx ring lock 352 */ 353 mutex_init(&sc->sc_tx_lock, "tx-ring", MUTEX_DRIVER, 354 (void *) sc->sc_iblk); 355 cv_init(&sc->sc_tx_cond, "tx-ring", CV_DRIVER, NULL); 356 /* 357 * rescheuled lock 358 */ 359 mutex_init(&sc->sc_resched_lock, "reschedule-lock", MUTEX_DRIVER, 360 (void *) sc->sc_iblk); 361 /* 362 * initialize the mfthread 363 */ 364 mutex_init(&sc->sc_mflock, "function-lock", MUTEX_DRIVER, 365 (void *) sc->sc_iblk); 366 cv_init(&sc->sc_mfthread_cv, NULL, CV_DRIVER, NULL); 367 sc->sc_mf_thread = NULL; 368 sc->sc_mfthread_switch = 0; 369 /* 370 * Initialize the wifi part, which will be used by 371 * generic layer 372 */ 373 ic = &sc->sc_ic; 374 ic->ic_phytype = IEEE80211_T_DS; 375 ic->ic_opmode = IEEE80211_M_STA; 376 ic->ic_state = IEEE80211_S_INIT; 377 ic->ic_maxrssi = 49; 378 /* 379 * Future, could use s/w to handle encryption: IEEE80211_C_WEP 380 * and need to add support for IEEE80211_C_IBSS 381 */ 382 ic->ic_caps = IEEE80211_C_SHPREAMBLE | IEEE80211_C_TXPMGT | 383 IEEE80211_C_PMGT; 384 ic->ic_sup_rates[IEEE80211_MODE_11B] = ipw2100_rateset_11b; 385 IEEE80211_ADDR_COPY(ic->ic_macaddr, sc->sc_macaddr); 386 for (i = 1; i < 16; i++) { 387 if (sc->sc_chmask &(1 << i)) { 388 /* IEEE80211_CHAN_B */ 389 ic->ic_sup_channels[i].ich_freq = ieee80211_ieee2mhz(i, 390 IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_CCK); 391 ic->ic_sup_channels[i].ich_flags = 392 IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_CCK; 393 } 394 } 395 ic->ic_ibss_chan = &ic->ic_sup_channels[0]; 396 ic->ic_xmit = ipw2100_send; 397 /* 398 * init Wifi layer 399 */ 400 ieee80211_attach(ic); 401 402 /* 403 * Override 80211 default routines 404 */ 405 ieee80211_media_init(ic); 406 sc->sc_newstate = ic->ic_newstate; 407 ic->ic_newstate = ipw2100_newstate; 408 /* 409 * initialize default tx key 410 */ 411 ic->ic_def_txkey = 0; 412 /* 413 * Set the Authentication to AUTH_Open only. 414 */ 415 sc->sc_authmode = IEEE80211_AUTH_OPEN; 416 417 /* 418 * Add the interrupt handler 419 */ 420 err = ddi_add_intr(dip, 0, &sc->sc_iblk, NULL, 421 ipw2100_intr, (caddr_t)sc); 422 if (err != DDI_SUCCESS) { 423 IPW2100_WARN((dip, CE_WARN, 424 "ipw2100_attach(): ddi_add_intr() failed\n")); 425 goto fail5; 426 } 427 428 /* 429 * Initialize pointer to device specific functions 430 */ 431 wd.wd_secalloc = WIFI_SEC_NONE; 432 wd.wd_opmode = ic->ic_opmode; 433 IEEE80211_ADDR_COPY(wd.wd_bssid, ic->ic_bss->in_bssid); 434 435 macp = mac_alloc(MAC_VERSION); 436 if (err != 0) { 437 IPW2100_WARN((dip, CE_WARN, 438 "ipw2100_attach(): mac_alloc() failed\n")); 439 goto fail6; 440 } 441 442 macp->m_type_ident = MAC_PLUGIN_IDENT_WIFI; 443 macp->m_driver = sc; 444 macp->m_dip = dip; 445 macp->m_src_addr = ic->ic_macaddr; 446 macp->m_callbacks = &ipw2100_m_callbacks; 447 macp->m_min_sdu = 0; 448 macp->m_max_sdu = IEEE80211_MTU; 449 macp->m_pdata = &wd; 450 macp->m_pdata_size = sizeof (wd); 451 452 /* 453 * Register the macp to mac 454 */ 455 err = mac_register(macp, &ic->ic_mach); 456 mac_free(macp); 457 if (err != DDI_SUCCESS) { 458 IPW2100_WARN((dip, CE_WARN, 459 "ipw2100_attach(): mac_register() failed\n")); 460 goto fail6; 461 } 462 463 /* 464 * Create minor node of type DDI_NT_NET_WIFI 465 */ 466 (void) snprintf(strbuf, sizeof (strbuf), "%s%d", 467 IPW2100_DRV_NAME, instance); 468 err = ddi_create_minor_node(dip, strbuf, S_IFCHR, 469 instance + 1, DDI_NT_NET_WIFI, 0); 470 if (err != DDI_SUCCESS) 471 IPW2100_WARN((dip, CE_WARN, 472 "ipw2100_attach(): ddi_create_minor_node() failed\n")); 473 474 /* 475 * Cache firmware, always return true 476 */ 477 (void) ipw2100_cache_firmware(sc); 478 479 /* 480 * Notify link is down now 481 */ 482 mac_link_update(ic->ic_mach, LINK_STATE_DOWN); 483 484 /* 485 * create the mf thread to handle the link status, 486 * recovery fatal error, etc. 487 */ 488 sc->sc_mfthread_switch = 1; 489 if (sc->sc_mf_thread == NULL) 490 sc->sc_mf_thread = thread_create((caddr_t)NULL, 0, 491 ipw2100_thread, sc, 0, &p0, TS_RUN, minclsyspri); 492 493 return (DDI_SUCCESS); 494 495 fail6: 496 ddi_remove_intr(dip, 0, sc->sc_iblk); 497 fail5: 498 ieee80211_detach(ic); 499 500 mutex_destroy(&sc->sc_ilock); 501 mutex_destroy(&sc->sc_tx_lock); 502 mutex_destroy(&sc->sc_mflock); 503 mutex_destroy(&sc->sc_resched_lock); 504 cv_destroy(&sc->sc_mfthread_cv); 505 cv_destroy(&sc->sc_tx_cond); 506 cv_destroy(&sc->sc_cmd_cond); 507 cv_destroy(&sc->sc_fw_cond); 508 fail4: 509 ipw2100_ring_free(sc); 510 fail3: 511 ddi_regs_map_free(&sc->sc_ioh); 512 fail2: 513 ddi_soft_state_free(ipw2100_ssp, instance); 514 fail1: 515 return (err); 516 } 517 518 int 519 ipw2100_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 520 { 521 struct ipw2100_softc *sc = 522 ddi_get_soft_state(ipw2100_ssp, ddi_get_instance(dip)); 523 int err; 524 525 ASSERT(sc != NULL); 526 527 switch (cmd) { 528 case DDI_DETACH: 529 break; 530 case DDI_SUSPEND: 531 return (ipw2100_cpr_suspend(sc)); 532 default: 533 return (DDI_FAILURE); 534 } 535 536 /* 537 * Destroy the mf_thread 538 */ 539 mutex_enter(&sc->sc_mflock); 540 sc->sc_mfthread_switch = 0; 541 while (sc->sc_mf_thread != NULL) { 542 if (cv_wait_sig(&sc->sc_mfthread_cv, &sc->sc_mflock) == 0) 543 break; 544 } 545 mutex_exit(&sc->sc_mflock); 546 547 /* 548 * Unregister from the MAC layer subsystem 549 */ 550 err = mac_unregister(sc->sc_ic.ic_mach); 551 if (err != DDI_SUCCESS) 552 return (err); 553 554 ddi_remove_intr(dip, 0, sc->sc_iblk); 555 556 /* 557 * destroy the cv 558 */ 559 mutex_destroy(&sc->sc_ilock); 560 mutex_destroy(&sc->sc_tx_lock); 561 mutex_destroy(&sc->sc_mflock); 562 mutex_destroy(&sc->sc_resched_lock); 563 cv_destroy(&sc->sc_mfthread_cv); 564 cv_destroy(&sc->sc_tx_cond); 565 cv_destroy(&sc->sc_cmd_cond); 566 cv_destroy(&sc->sc_fw_cond); 567 568 /* 569 * detach ieee80211 570 */ 571 ieee80211_detach(&sc->sc_ic); 572 573 (void) ipw2100_free_firmware(sc); 574 ipw2100_ring_free(sc); 575 576 ddi_regs_map_free(&sc->sc_ioh); 577 ddi_remove_minor_node(dip, NULL); 578 ddi_soft_state_free(ipw2100_ssp, ddi_get_instance(dip)); 579 580 return (DDI_SUCCESS); 581 } 582 583 int 584 ipw2100_cpr_suspend(struct ipw2100_softc *sc) 585 { 586 IPW2100_DBG(IPW2100_DBG_INIT, (sc->sc_dip, CE_CONT, 587 "ipw2100_cpr_suspend(): enter\n")); 588 589 /* 590 * Destroy the mf_thread 591 */ 592 mutex_enter(&sc->sc_mflock); 593 sc->sc_mfthread_switch = 0; 594 while (sc->sc_mf_thread != NULL) { 595 if (cv_wait_sig(&sc->sc_mfthread_cv, &sc->sc_mflock) == 0) 596 break; 597 } 598 mutex_exit(&sc->sc_mflock); 599 600 /* 601 * stop the hardware; this mask all interrupts 602 */ 603 ipw2100_stop(sc); 604 sc->sc_flags &= ~IPW2100_FLAG_RUNNING; 605 sc->sc_suspended = 1; 606 607 (void) ipw2100_free_firmware(sc); 608 ipw2100_ring_free(sc); 609 610 return (DDI_SUCCESS); 611 } 612 613 int 614 ipw2100_cpr_resume(struct ipw2100_softc *sc) 615 { 616 struct ieee80211com *ic = &sc->sc_ic; 617 dev_info_t *dip = sc->sc_dip; 618 int err; 619 620 IPW2100_DBG(IPW2100_DBG_INIT, (sc->sc_dip, CE_CONT, 621 "ipw2100_cpr_resume(): enter\n")); 622 623 /* 624 * Reset the chip 625 */ 626 err = ipw2100_chip_reset(sc); 627 if (err != DDI_SUCCESS) { 628 IPW2100_WARN((dip, CE_WARN, 629 "ipw2100_attach(): reset failed\n")); 630 return (DDI_FAILURE); 631 } 632 633 /* 634 * Get the hw conf, including MAC address, then init all rings. 635 */ 636 /* ipw2100_hwconf_get(sc); */ 637 err = ipw2100_ring_init(sc); 638 if (err != DDI_SUCCESS) { 639 IPW2100_WARN((dip, CE_WARN, 640 "ipw2100_attach(): " 641 "unable to allocate and initialize rings\n")); 642 return (DDI_FAILURE); 643 } 644 645 /* 646 * Cache firmware, always return true 647 */ 648 (void) ipw2100_cache_firmware(sc); 649 650 /* 651 * Notify link is down now 652 */ 653 mac_link_update(ic->ic_mach, LINK_STATE_DOWN); 654 655 /* 656 * create the mf thread to handle the link status, 657 * recovery fatal error, etc. 658 */ 659 sc->sc_mfthread_switch = 1; 660 if (sc->sc_mf_thread == NULL) 661 sc->sc_mf_thread = thread_create((caddr_t)NULL, 0, 662 ipw2100_thread, sc, 0, &p0, TS_RUN, minclsyspri); 663 664 /* 665 * enable all interrupts 666 */ 667 sc->sc_suspended = 0; 668 ipw2100_csr_put32(sc, IPW2100_CSR_INTR_MASK, IPW2100_INTR_MASK_ALL); 669 670 /* 671 * initialize ipw2100 hardware 672 */ 673 (void) ipw2100_init(sc); 674 675 sc->sc_flags |= IPW2100_FLAG_RUNNING; 676 677 return (DDI_SUCCESS); 678 } 679 680 /* 681 * quiesce(9E) entry point. 682 * This function is called when the system is single-threaded at high 683 * PIL with preemption disabled. Therefore, this function must not be 684 * blocked. 685 * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure. 686 * DDI_FAILURE indicates an error condition and should almost never happen. 687 * Contributed by Juergen Keil, <jk@tools.de>. 688 */ 689 static int 690 ipw2100_quiesce(dev_info_t *dip) 691 { 692 struct ipw2100_softc *sc = 693 ddi_get_soft_state(ipw2100_ssp, ddi_get_instance(dip)); 694 695 if (sc == NULL) 696 return (DDI_FAILURE); 697 698 /* 699 * No more blocking is allowed while we are in the 700 * quiesce(9E) entry point. 701 */ 702 sc->sc_flags |= IPW2100_FLAG_QUIESCED; 703 704 /* 705 * Disable and mask all interrupts. 706 */ 707 ipw2100_stop(sc); 708 return (DDI_SUCCESS); 709 } 710 711 static void 712 ipw2100_tables_init(struct ipw2100_softc *sc) 713 { 714 sc->sc_table1_base = ipw2100_csr_get32(sc, IPW2100_CSR_TABLE1_BASE); 715 sc->sc_table2_base = ipw2100_csr_get32(sc, IPW2100_CSR_TABLE2_BASE); 716 } 717 718 static void 719 ipw2100_stop(struct ipw2100_softc *sc) 720 { 721 struct ieee80211com *ic = &sc->sc_ic; 722 723 ipw2100_master_stop(sc); 724 ipw2100_csr_put32(sc, IPW2100_CSR_RST, IPW2100_RST_SW_RESET); 725 sc->sc_flags &= ~IPW2100_FLAG_FW_INITED; 726 727 if (!(sc->sc_flags & IPW2100_FLAG_QUIESCED)) 728 ieee80211_new_state(ic, IEEE80211_S_INIT, -1); 729 } 730 731 static int 732 ipw2100_config(struct ipw2100_softc *sc) 733 { 734 struct ieee80211com *ic = &sc->sc_ic; 735 struct ipw2100_security sec; 736 struct ipw2100_wep_key wkey; 737 struct ipw2100_scan_options sopt; 738 struct ipw2100_configuration cfg; 739 uint32_t data; 740 int err, i; 741 742 /* 743 * operation mode 744 */ 745 switch (ic->ic_opmode) { 746 case IEEE80211_M_STA: 747 case IEEE80211_M_HOSTAP: 748 data = LE_32(IPW2100_MODE_BSS); 749 break; 750 751 case IEEE80211_M_IBSS: 752 case IEEE80211_M_AHDEMO: 753 data = LE_32(IPW2100_MODE_IBSS); 754 break; 755 } 756 757 IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT, 758 "ipw2100_config(): Setting mode to %u\n", LE_32(data))); 759 760 err = ipw2100_cmd(sc, IPW2100_CMD_SET_MODE, 761 &data, sizeof (data)); 762 if (err != DDI_SUCCESS) 763 return (err); 764 765 /* 766 * operation channel if IBSS or MONITOR 767 */ 768 if (ic->ic_opmode == IEEE80211_M_IBSS) { 769 770 data = LE_32(ieee80211_chan2ieee(ic, ic->ic_ibss_chan)); 771 772 IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT, 773 "ipw2100_config(): Setting channel to %u\n", LE_32(data))); 774 775 err = ipw2100_cmd(sc, IPW2100_CMD_SET_CHANNEL, 776 &data, sizeof (data)); 777 if (err != DDI_SUCCESS) 778 return (err); 779 } 780 781 /* 782 * set MAC address 783 */ 784 IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT, 785 "ipw2100_config(): Setting MAC address to " 786 "%02x:%02x:%02x:%02x:%02x:%02x\n", 787 ic->ic_macaddr[0], ic->ic_macaddr[1], ic->ic_macaddr[2], 788 ic->ic_macaddr[3], ic->ic_macaddr[4], ic->ic_macaddr[5])); 789 err = ipw2100_cmd(sc, IPW2100_CMD_SET_MAC_ADDRESS, ic->ic_macaddr, 790 IEEE80211_ADDR_LEN); 791 if (err != DDI_SUCCESS) 792 return (err); 793 794 /* 795 * configuration capabilities 796 */ 797 cfg.flags = IPW2100_CFG_BSS_MASK | IPW2100_CFG_IBSS_MASK | 798 IPW2100_CFG_PREAMBLE_AUTO | IPW2100_CFG_802_1x_ENABLE; 799 if (ic->ic_opmode == IEEE80211_M_IBSS) 800 cfg.flags |= IPW2100_CFG_IBSS_AUTO_START; 801 if (sc->if_flags & IFF_PROMISC) 802 cfg.flags |= IPW2100_CFG_PROMISCUOUS; 803 cfg.flags = LE_32(cfg.flags); 804 cfg.bss_chan = LE_32(sc->sc_chmask >> 1); 805 cfg.ibss_chan = LE_32(sc->sc_chmask >> 1); 806 807 IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT, 808 "ipw2100_config(): Setting configuration to 0x%x\n", 809 LE_32(cfg.flags))); 810 811 err = ipw2100_cmd(sc, IPW2100_CMD_SET_CONFIGURATION, 812 &cfg, sizeof (cfg)); 813 814 if (err != DDI_SUCCESS) 815 return (err); 816 817 /* 818 * set 802.11 Tx rates 819 */ 820 data = LE_32(0x3); /* 1, 2 */ 821 IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT, 822 "ipw2100_config(): Setting 802.11 Tx rates to 0x%x\n", 823 LE_32(data))); 824 err = ipw2100_cmd(sc, IPW2100_CMD_SET_BASIC_TX_RATES, 825 &data, sizeof (data)); 826 if (err != DDI_SUCCESS) 827 return (err); 828 829 /* 830 * set 802.11b Tx rates 831 */ 832 data = LE_32(0xf); /* 1, 2, 5.5, 11 */ 833 IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT, 834 "ipw2100_config(): Setting 802.11b Tx rates to 0x%x\n", 835 LE_32(data))); 836 err = ipw2100_cmd(sc, IPW2100_CMD_SET_TX_RATES, &data, sizeof (data)); 837 if (err != DDI_SUCCESS) 838 return (err); 839 840 /* 841 * set power mode 842 */ 843 data = LE_32(IPW2100_POWER_MODE_CAM); 844 IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT, 845 "ipw2100_config(): Setting power mode to %u\n", LE_32(data))); 846 err = ipw2100_cmd(sc, IPW2100_CMD_SET_POWER_MODE, &data, sizeof (data)); 847 if (err != DDI_SUCCESS) 848 return (err); 849 850 /* 851 * set power index 852 */ 853 if (ic->ic_opmode == IEEE80211_M_IBSS) { 854 data = LE_32(32); 855 IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT, 856 "ipw2100_config(): Setting Tx power index to %u\n", 857 LE_32(data))); 858 err = ipw2100_cmd(sc, IPW2100_CMD_SET_TX_POWER_INDEX, 859 &data, sizeof (data)); 860 if (err != DDI_SUCCESS) 861 return (err); 862 } 863 864 /* 865 * set RTS threshold 866 */ 867 ic->ic_rtsthreshold = 2346; 868 data = LE_32(ic->ic_rtsthreshold); 869 IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT, 870 "ipw2100_config(): Setting RTS threshold to %u\n", LE_32(data))); 871 err = ipw2100_cmd(sc, IPW2100_CMD_SET_RTS_THRESHOLD, 872 &data, sizeof (data)); 873 if (err != DDI_SUCCESS) 874 return (err); 875 876 /* 877 * set frag threshold 878 */ 879 ic->ic_fragthreshold = 2346; 880 data = LE_32(ic->ic_fragthreshold); 881 IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT, 882 "ipw2100_config(): Setting frag threshold to %u\n", LE_32(data))); 883 err = ipw2100_cmd(sc, IPW2100_CMD_SET_FRAG_THRESHOLD, 884 &data, sizeof (data)); 885 if (err != DDI_SUCCESS) 886 return (err); 887 888 /* 889 * set ESSID 890 */ 891 IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT, 892 "ipw2100_config(): Setting ESSID to %u, ESSID[0]%c\n", 893 ic->ic_des_esslen, ic->ic_des_essid[0])); 894 err = ipw2100_cmd(sc, IPW2100_CMD_SET_ESSID, 895 ic->ic_des_essid, ic->ic_des_esslen); 896 if (err != DDI_SUCCESS) 897 return (err); 898 899 /* 900 * no mandatory BSSID 901 */ 902 err = ipw2100_cmd(sc, IPW2100_CMD_SET_MANDATORY_BSSID, NULL, 0); 903 if (err != DDI_SUCCESS) 904 return (err); 905 906 /* 907 * set BSSID, if any 908 */ 909 if (ic->ic_flags & IEEE80211_F_DESBSSID) { 910 IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT, 911 "ipw2100_config(): Setting BSSID to %u\n", 912 IEEE80211_ADDR_LEN)); 913 err = ipw2100_cmd(sc, IPW2100_CMD_SET_DESIRED_BSSID, 914 ic->ic_des_bssid, IEEE80211_ADDR_LEN); 915 if (err != DDI_SUCCESS) 916 return (err); 917 } 918 919 /* 920 * set security information 921 */ 922 (void) memset(&sec, 0, sizeof (sec)); 923 /* 924 * use the value set to ic_bss to retrieve current sharedmode 925 */ 926 sec.authmode = (ic->ic_bss->in_authmode == WL_SHAREDKEY) ? 927 IPW2100_AUTH_SHARED : IPW2100_AUTH_OPEN; 928 sec.ciphers = LE_32(IPW2100_CIPHER_NONE); 929 IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT, 930 "ipw2100_config(): Setting authmode to %u\n", sec.authmode)); 931 err = ipw2100_cmd(sc, IPW2100_CMD_SET_SECURITY_INFORMATION, 932 &sec, sizeof (sec)); 933 if (err != DDI_SUCCESS) 934 return (err); 935 936 /* 937 * set WEP if any 938 */ 939 if (ic->ic_flags & IEEE80211_F_PRIVACY) { 940 for (i = 0; i < IEEE80211_WEP_NKID; i++) { 941 if (ic->ic_nw_keys[i].wk_keylen == 0) 942 continue; 943 wkey.idx = (uint8_t)i; 944 wkey.len = ic->ic_nw_keys[i].wk_keylen; 945 (void) memset(wkey.key, 0, sizeof (wkey.key)); 946 if (ic->ic_nw_keys[i].wk_keylen) 947 (void) memcpy(wkey.key, 948 ic->ic_nw_keys[i].wk_key, 949 ic->ic_nw_keys[i].wk_keylen); 950 err = ipw2100_cmd(sc, IPW2100_CMD_SET_WEP_KEY, 951 &wkey, sizeof (wkey)); 952 if (err != DDI_SUCCESS) 953 return (err); 954 } 955 data = LE_32(ic->ic_def_txkey); 956 err = ipw2100_cmd(sc, IPW2100_CMD_SET_WEP_KEY_INDEX, 957 &data, sizeof (data)); 958 if (err != DDI_SUCCESS) 959 return (err); 960 } 961 962 /* 963 * turn on WEP 964 */ 965 data = LE_32((ic->ic_flags & IEEE80211_F_PRIVACY) ? 0x8 : 0); 966 IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT, 967 "ipw2100_config(): Setting WEP flags to %u\n", LE_32(data))); 968 err = ipw2100_cmd(sc, IPW2100_CMD_SET_WEP_FLAGS, &data, sizeof (data)); 969 if (err != DDI_SUCCESS) 970 return (err); 971 972 /* 973 * set beacon interval if IBSS or HostAP 974 */ 975 if (ic->ic_opmode == IEEE80211_M_IBSS || 976 ic->ic_opmode == IEEE80211_M_HOSTAP) { 977 978 data = LE_32(ic->ic_lintval); 979 IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT, 980 "ipw2100_config(): Setting beacon interval to %u\n", 981 LE_32(data))); 982 err = ipw2100_cmd(sc, IPW2100_CMD_SET_BEACON_INTERVAL, 983 &data, sizeof (data)); 984 if (err != DDI_SUCCESS) 985 return (err); 986 } 987 988 /* 989 * set scan options 990 */ 991 sopt.flags = LE_32(0); 992 sopt.channels = LE_32(sc->sc_chmask >> 1); 993 err = ipw2100_cmd(sc, IPW2100_CMD_SET_SCAN_OPTIONS, 994 &sopt, sizeof (sopt)); 995 if (err != DDI_SUCCESS) 996 return (err); 997 998 en_adapter: 999 1000 IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT, 1001 "ipw2100_config(): Enabling adapter\n")); 1002 1003 return (ipw2100_cmd(sc, IPW2100_CMD_ENABLE, NULL, 0)); 1004 } 1005 1006 static int 1007 ipw2100_cmd(struct ipw2100_softc *sc, uint32_t type, void *buf, size_t len) 1008 { 1009 struct ipw2100_bd *txbd; 1010 clock_t clk; 1011 uint32_t idx; 1012 1013 /* 1014 * prepare command buffer 1015 */ 1016 sc->sc_cmd->type = LE_32(type); 1017 sc->sc_cmd->subtype = LE_32(0); 1018 sc->sc_cmd->seq = LE_32(0); 1019 /* 1020 * copy data if any 1021 */ 1022 if (len && buf) 1023 (void) memcpy(sc->sc_cmd->data, buf, len); 1024 sc->sc_cmd->len = LE_32(len); 1025 1026 /* 1027 * get host & device descriptor to submit command 1028 */ 1029 mutex_enter(&sc->sc_tx_lock); 1030 1031 IPW2100_DBG(IPW2100_DBG_RING, (sc->sc_dip, CE_CONT, 1032 "ipw2100_cmd(): tx-free=%d\n", sc->sc_tx_free)); 1033 1034 /* 1035 * command need 1 descriptor 1036 */ 1037 while (sc->sc_tx_free < 1) { 1038 sc->sc_flags |= IPW2100_FLAG_CMD_WAIT; 1039 cv_wait(&sc->sc_tx_cond, &sc->sc_tx_lock); 1040 } 1041 idx = sc->sc_tx_cur; 1042 1043 IPW2100_DBG(IPW2100_DBG_RING, (sc->sc_dip, CE_CONT, 1044 "ipw2100_cmd(): tx-cur=%d\n", idx)); 1045 1046 sc->sc_done = 0; 1047 1048 txbd = &sc->sc_txbd[idx]; 1049 txbd->phyaddr = LE_32(sc->sc_dma_cmd.dr_pbase); 1050 txbd->len = LE_32(sizeof (struct ipw2100_cmd)); 1051 txbd->flags = IPW2100_BD_FLAG_TX_FRAME_COMMAND 1052 | IPW2100_BD_FLAG_TX_LAST_FRAGMENT; 1053 txbd->nfrag = 1; 1054 /* 1055 * sync for device 1056 */ 1057 (void) ddi_dma_sync(sc->sc_dma_cmd.dr_hnd, 0, 1058 sizeof (struct ipw2100_cmd), DDI_DMA_SYNC_FORDEV); 1059 (void) ddi_dma_sync(sc->sc_dma_txbd.dr_hnd, 1060 idx * sizeof (struct ipw2100_bd), 1061 sizeof (struct ipw2100_bd), DDI_DMA_SYNC_FORDEV); 1062 1063 /* 1064 * ring move forward 1065 */ 1066 sc->sc_tx_cur = RING_FORWARD(sc->sc_tx_cur, 1, IPW2100_NUM_TXBD); 1067 sc->sc_tx_free--; 1068 ipw2100_csr_put32(sc, IPW2100_CSR_TX_WRITE_INDEX, sc->sc_tx_cur); 1069 mutex_exit(&sc->sc_tx_lock); 1070 1071 /* 1072 * wait for command done 1073 */ 1074 mutex_enter(&sc->sc_ilock); 1075 while (sc->sc_done == 0) { 1076 /* 1077 * pending for the response 1078 */ 1079 clk = ddi_get_lbolt() + drv_usectohz(1000000); /* 1 second */ 1080 if (cv_timedwait(&sc->sc_cmd_cond, &sc->sc_ilock, clk) < 0) 1081 break; 1082 } 1083 mutex_exit(&sc->sc_ilock); 1084 1085 IPW2100_DBG(IPW2100_DBG_RING, (sc->sc_dip, CE_CONT, 1086 "ipw2100_cmd(): cmd-done=%s\n", sc->sc_done ? "yes" : "no")); 1087 1088 if (sc->sc_done == 0) 1089 return (DDI_FAILURE); 1090 1091 return (DDI_SUCCESS); 1092 } 1093 1094 int 1095 ipw2100_init(struct ipw2100_softc *sc) 1096 { 1097 int err; 1098 1099 IPW2100_DBG(IPW2100_DBG_INIT, (sc->sc_dip, CE_CONT, 1100 "ipw2100_init(): enter\n")); 1101 1102 /* 1103 * no firmware is available, return fail directly 1104 */ 1105 if (!(sc->sc_flags & IPW2100_FLAG_FW_CACHED)) { 1106 IPW2100_WARN((sc->sc_dip, CE_WARN, 1107 "ipw2100_init(): no firmware is available\n")); 1108 return (DDI_FAILURE); 1109 } 1110 1111 ipw2100_stop(sc); 1112 1113 err = ipw2100_chip_reset(sc); 1114 if (err != DDI_SUCCESS) { 1115 IPW2100_WARN((sc->sc_dip, CE_WARN, 1116 "ipw2100_init(): could not reset adapter\n")); 1117 goto fail; 1118 } 1119 1120 /* 1121 * load microcode 1122 */ 1123 IPW2100_DBG(IPW2100_DBG_INIT, (sc->sc_dip, CE_CONT, 1124 "ipw2100_init(): loading microcode\n")); 1125 err = ipw2100_load_uc(sc); 1126 if (err != DDI_SUCCESS) { 1127 IPW2100_WARN((sc->sc_dip, CE_WARN, 1128 "ipw2100_init(): could not load microcode, try again\n")); 1129 goto fail; 1130 } 1131 1132 ipw2100_master_stop(sc); 1133 1134 ipw2100_ring_hwsetup(sc); 1135 1136 /* 1137 * load firmware 1138 */ 1139 IPW2100_DBG(IPW2100_DBG_INIT, (sc->sc_dip, CE_CONT, 1140 "ipw2100_init(): loading firmware\n")); 1141 err = ipw2100_load_fw(sc); 1142 if (err != DDI_SUCCESS) { 1143 IPW2100_WARN((sc->sc_dip, CE_WARN, 1144 "ipw2100_init(): could not load firmware, try again\n")); 1145 goto fail; 1146 } 1147 1148 /* 1149 * initialize tables 1150 */ 1151 ipw2100_tables_init(sc); 1152 ipw2100_table1_put32(sc, IPW2100_INFO_LOCK, 0); 1153 1154 /* 1155 * Hardware will be enabled after configuration 1156 */ 1157 err = ipw2100_config(sc); 1158 if (err != DDI_SUCCESS) { 1159 IPW2100_WARN((sc->sc_dip, CE_WARN, 1160 "ipw2100_init(): device configuration failed\n")); 1161 goto fail; 1162 } 1163 1164 delay(drv_usectohz(delay_config_stable)); 1165 1166 return (DDI_SUCCESS); 1167 1168 fail: 1169 ipw2100_stop(sc); 1170 1171 return (err); 1172 } 1173 1174 /* 1175 * get hardware configurations from EEPROM embedded within chip 1176 */ 1177 static void 1178 ipw2100_hwconf_get(struct ipw2100_softc *sc) 1179 { 1180 int i; 1181 uint16_t val; 1182 1183 /* 1184 * MAC address 1185 */ 1186 i = 0; 1187 val = ipw2100_rom_get16(sc, IPW2100_ROM_MAC + 0); 1188 sc->sc_macaddr[i++] = val >> 8; 1189 sc->sc_macaddr[i++] = val & 0xff; 1190 val = ipw2100_rom_get16(sc, IPW2100_ROM_MAC + 1); 1191 sc->sc_macaddr[i++] = val >> 8; 1192 sc->sc_macaddr[i++] = val & 0xff; 1193 val = ipw2100_rom_get16(sc, IPW2100_ROM_MAC + 2); 1194 sc->sc_macaddr[i++] = val >> 8; 1195 sc->sc_macaddr[i++] = val & 0xff; 1196 1197 /* 1198 * formatted MAC address string 1199 */ 1200 (void) snprintf(sc->sc_macstr, sizeof (sc->sc_macstr), 1201 "%02x:%02x:%02x:%02x:%02x:%02x", 1202 sc->sc_macaddr[0], sc->sc_macaddr[1], 1203 sc->sc_macaddr[2], sc->sc_macaddr[3], 1204 sc->sc_macaddr[4], sc->sc_macaddr[5]); 1205 1206 /* 1207 * channel mask 1208 */ 1209 val = ipw2100_rom_get16(sc, IPW2100_ROM_CHANNEL_LIST); 1210 if (val == 0) 1211 val = 0x7ff; 1212 sc->sc_chmask = val << 1; 1213 IPW2100_DBG(IPW2100_DBG_HWCAP, (sc->sc_dip, CE_CONT, 1214 "ipw2100_hwconf_get(): channel-mask=0x%08x\n", sc->sc_chmask)); 1215 1216 /* 1217 * radio switch 1218 */ 1219 val = ipw2100_rom_get16(sc, IPW2100_ROM_RADIO); 1220 if (val & 0x08) 1221 sc->sc_flags |= IPW2100_FLAG_HAS_RADIO_SWITCH; 1222 1223 IPW2100_DBG(IPW2100_DBG_HWCAP, (sc->sc_dip, CE_CONT, 1224 "ipw2100_hwconf_get(): has-radio-switch=%s(%u)\n", 1225 (sc->sc_flags & IPW2100_FLAG_HAS_RADIO_SWITCH)? "yes" : "no", 1226 val)); 1227 } 1228 1229 /* 1230 * all ipw2100 interrupts will be masked by this routine 1231 */ 1232 static void 1233 ipw2100_master_stop(struct ipw2100_softc *sc) 1234 { 1235 uint32_t tmp; 1236 int ntries; 1237 1238 /* 1239 * disable interrupts 1240 */ 1241 ipw2100_csr_put32(sc, IPW2100_CSR_INTR_MASK, 0); 1242 1243 ipw2100_csr_put32(sc, IPW2100_CSR_RST, IPW2100_RST_STOP_MASTER); 1244 for (ntries = 0; ntries < 50; ntries++) { 1245 if (ipw2100_csr_get32(sc, IPW2100_CSR_RST) 1246 & IPW2100_RST_MASTER_DISABLED) 1247 break; 1248 drv_usecwait(10); 1249 } 1250 if (ntries == 50 && !(sc->sc_flags & IPW2100_FLAG_QUIESCED)) 1251 IPW2100_WARN((sc->sc_dip, CE_WARN, 1252 "ipw2100_master_stop(): timeout when stop master\n")); 1253 1254 tmp = ipw2100_csr_get32(sc, IPW2100_CSR_RST); 1255 ipw2100_csr_put32(sc, IPW2100_CSR_RST, 1256 tmp | IPW2100_RST_PRINCETON_RESET); 1257 1258 sc->sc_flags &= ~IPW2100_FLAG_FW_INITED; 1259 } 1260 1261 /* 1262 * all ipw2100 interrupts will be masked by this routine 1263 */ 1264 static int 1265 ipw2100_chip_reset(struct ipw2100_softc *sc) 1266 { 1267 int ntries; 1268 uint32_t tmp; 1269 1270 ipw2100_master_stop(sc); 1271 1272 /* 1273 * move adatper to DO state 1274 */ 1275 tmp = ipw2100_csr_get32(sc, IPW2100_CSR_CTL); 1276 ipw2100_csr_put32(sc, IPW2100_CSR_CTL, tmp | IPW2100_CTL_INIT); 1277 1278 /* 1279 * wait for clock stabilization 1280 */ 1281 for (ntries = 0; ntries < 1000; ntries++) { 1282 if (ipw2100_csr_get32(sc, IPW2100_CSR_CTL) 1283 & IPW2100_CTL_CLOCK_READY) 1284 break; 1285 drv_usecwait(200); 1286 } 1287 if (ntries == 1000) 1288 return (DDI_FAILURE); 1289 1290 tmp = ipw2100_csr_get32(sc, IPW2100_CSR_RST); 1291 ipw2100_csr_put32(sc, IPW2100_CSR_RST, tmp | IPW2100_RST_SW_RESET); 1292 1293 drv_usecwait(10); 1294 1295 tmp = ipw2100_csr_get32(sc, IPW2100_CSR_CTL); 1296 ipw2100_csr_put32(sc, IPW2100_CSR_CTL, tmp | IPW2100_CTL_INIT); 1297 1298 return (DDI_SUCCESS); 1299 } 1300 1301 /* 1302 * get the radio status from IPW_CSR_IO, invoked by wificonfig/dladm 1303 */ 1304 int 1305 ipw2100_get_radio(struct ipw2100_softc *sc) 1306 { 1307 if (ipw2100_csr_get32(sc, IPW2100_CSR_IO) & IPW2100_IO_RADIO_DISABLED) 1308 return (0); 1309 else 1310 return (1); 1311 1312 } 1313 /* 1314 * This function is used to get the statistic, invoked by wificonfig/dladm 1315 */ 1316 void 1317 ipw2100_get_statistics(struct ipw2100_softc *sc) 1318 { 1319 struct ieee80211com *ic = &sc->sc_ic; 1320 uint32_t addr, size, i; 1321 uint32_t atbl[256], *datatbl; 1322 1323 datatbl = atbl; 1324 1325 if (!(sc->sc_flags & IPW2100_FLAG_FW_INITED)) { 1326 IPW2100_DBG(IPW2100_DBG_STATISTIC, (sc->sc_dip, CE_CONT, 1327 "ipw2100_get_statistic(): fw doesn't download yet.")); 1328 return; 1329 } 1330 1331 ipw2100_csr_put32(sc, IPW2100_CSR_AUTOINC_ADDR, sc->sc_table1_base); 1332 1333 size = ipw2100_csr_get32(sc, IPW2100_CSR_AUTOINC_DATA); 1334 atbl[0] = size; 1335 for (i = 1, ++datatbl; i < size; i++, datatbl++) { 1336 addr = ipw2100_csr_get32(sc, IPW2100_CSR_AUTOINC_DATA); 1337 *datatbl = ipw2100_imem_get32(sc, addr); 1338 } 1339 1340 /* 1341 * To retrieve the statistic information into proper places. There are 1342 * lot of information. 1343 */ 1344 IPW2100_DBG(IPW2100_DBG_STATISTIC, (sc->sc_dip, CE_CONT, 1345 "ipw2100_get_statistic(): \n" 1346 "operating mode = %u\n" 1347 "type of authentification= %u\n" 1348 "average RSSI= %u\n" 1349 "current channel = %d\n", 1350 atbl[191], atbl[199], atbl[173], atbl[189])); 1351 /* WIFI_STAT_TX_FRAGS */ 1352 ic->ic_stats.is_tx_frags = (uint32_t)atbl[2]; 1353 /* WIFI_STAT_MCAST_TX = (all frame - unicast frame) */ 1354 ic->ic_stats.is_tx_mcast = (uint32_t)atbl[2] - (uint32_t)atbl[3]; 1355 /* WIFI_STAT_TX_RETRANS */ 1356 ic->ic_stats.is_tx_retries = (uint32_t)atbl[42]; 1357 /* WIFI_STAT_TX_FAILED */ 1358 ic->ic_stats.is_tx_failed = (uint32_t)atbl[51]; 1359 /* MAC_STAT_OBYTES */ 1360 ic->ic_stats.is_tx_bytes = (uint32_t)atbl[41]; 1361 /* WIFI_STAT_RX_FRAGS */ 1362 ic->ic_stats.is_rx_frags = (uint32_t)atbl[61]; 1363 /* WIFI_STAT_MCAST_RX */ 1364 ic->ic_stats.is_rx_mcast = (uint32_t)atbl[71]; 1365 /* MAC_STAT_IBYTES */ 1366 ic->ic_stats.is_rx_bytes = (uint32_t)atbl[101]; 1367 /* WIFI_STAT_ACK_FAILURE */ 1368 ic->ic_stats.is_ack_failure = (uint32_t)atbl[59]; 1369 /* WIFI_STAT_RTS_SUCCESS */ 1370 ic->ic_stats.is_rts_success = (uint32_t)atbl[22]; 1371 } 1372 1373 /* 1374 * dma region alloc 1375 */ 1376 static int 1377 ipw2100_dma_region_alloc(struct ipw2100_softc *sc, 1378 struct dma_region *dr, size_t size, uint_t dir, uint_t flags) 1379 { 1380 dev_info_t *dip = sc->sc_dip; 1381 int err; 1382 1383 IPW2100_DBG(IPW2100_DBG_DMA, (dip, CE_CONT, 1384 "ipw2100_dma_region_alloc() name=%s size=%u\n", 1385 dr->dr_name, size)); 1386 1387 err = ddi_dma_alloc_handle(dip, &ipw2100_dma_attr, DDI_DMA_SLEEP, NULL, 1388 &dr->dr_hnd); 1389 if (err != DDI_SUCCESS) { 1390 IPW2100_DBG(IPW2100_DBG_DMA, (dip, CE_CONT, 1391 "ipw2100_dma_region_alloc(): " 1392 "ddi_dma_alloc_handle() failed\n")); 1393 goto fail0; 1394 } 1395 1396 err = ddi_dma_mem_alloc(dr->dr_hnd, size, &ipw2100_dma_accattr, 1397 flags, DDI_DMA_SLEEP, NULL, &dr->dr_base, 1398 &dr->dr_size, &dr->dr_acc); 1399 if (err != DDI_SUCCESS) { 1400 IPW2100_DBG(IPW2100_DBG_DMA, (dip, CE_CONT, 1401 "ipw2100_dma_region_alloc(): " 1402 "ddi_dma_mem_alloc() failed\n")); 1403 goto fail1; 1404 } 1405 1406 err = ddi_dma_addr_bind_handle(dr->dr_hnd, NULL, 1407 dr->dr_base, dr->dr_size, dir | flags, DDI_DMA_SLEEP, NULL, 1408 &dr->dr_cookie, &dr->dr_ccnt); 1409 if (err != DDI_DMA_MAPPED) { 1410 IPW2100_DBG(IPW2100_DBG_DMA, (dip, CE_CONT, 1411 "ipw2100_dma_region_alloc(): " 1412 "ddi_dma_addr_bind_handle() failed\n")); 1413 goto fail2; 1414 } 1415 1416 if (dr->dr_ccnt != 1) { 1417 err = DDI_FAILURE; 1418 goto fail3; 1419 } 1420 dr->dr_pbase = dr->dr_cookie.dmac_address; 1421 1422 IPW2100_DBG(IPW2100_DBG_DMA, (dip, CE_CONT, 1423 "ipw2100_dma_region_alloc(): get physical-base=0x%08x\n", 1424 dr->dr_pbase)); 1425 1426 return (DDI_SUCCESS); 1427 1428 fail3: 1429 (void) ddi_dma_unbind_handle(dr->dr_hnd); 1430 fail2: 1431 ddi_dma_mem_free(&dr->dr_acc); 1432 fail1: 1433 ddi_dma_free_handle(&dr->dr_hnd); 1434 fail0: 1435 return (err); 1436 } 1437 1438 static void 1439 ipw2100_dma_region_free(struct dma_region *dr) 1440 { 1441 (void) ddi_dma_unbind_handle(dr->dr_hnd); 1442 ddi_dma_mem_free(&dr->dr_acc); 1443 ddi_dma_free_handle(&dr->dr_hnd); 1444 } 1445 1446 static int 1447 ipw2100_ring_alloc(struct ipw2100_softc *sc) 1448 { 1449 int err, i; 1450 1451 /* 1452 * tx ring 1453 */ 1454 sc->sc_dma_txbd.dr_name = "ipw2100-tx-ring-bd"; 1455 err = ipw2100_dma_region_alloc(sc, &sc->sc_dma_txbd, 1456 IPW2100_TXBD_SIZE, DDI_DMA_WRITE, DDI_DMA_CONSISTENT); 1457 if (err != DDI_SUCCESS) 1458 goto fail0; 1459 /* 1460 * tx bufs 1461 */ 1462 for (i = 0; i < IPW2100_NUM_TXBUF; i++) { 1463 sc->sc_dma_txbufs[i].dr_name = "ipw2100-tx-buf"; 1464 err = ipw2100_dma_region_alloc(sc, &sc->sc_dma_txbufs[i], 1465 IPW2100_TXBUF_SIZE, DDI_DMA_WRITE, DDI_DMA_STREAMING); 1466 if (err != DDI_SUCCESS) { 1467 while (i > 0) { 1468 i--; 1469 ipw2100_dma_region_free(&sc->sc_dma_txbufs[i]); 1470 } 1471 goto fail1; 1472 } 1473 } 1474 /* 1475 * rx ring 1476 */ 1477 sc->sc_dma_rxbd.dr_name = "ipw2100-rx-ring-bd"; 1478 err = ipw2100_dma_region_alloc(sc, &sc->sc_dma_rxbd, 1479 IPW2100_RXBD_SIZE, DDI_DMA_WRITE, DDI_DMA_CONSISTENT); 1480 if (err != DDI_SUCCESS) 1481 goto fail2; 1482 /* 1483 * rx bufs 1484 */ 1485 for (i = 0; i < IPW2100_NUM_RXBUF; i++) { 1486 sc->sc_dma_rxbufs[i].dr_name = "ipw2100-rx-buf"; 1487 err = ipw2100_dma_region_alloc(sc, &sc->sc_dma_rxbufs[i], 1488 IPW2100_RXBUF_SIZE, DDI_DMA_READ, DDI_DMA_STREAMING); 1489 if (err != DDI_SUCCESS) { 1490 while (i > 0) { 1491 i--; 1492 ipw2100_dma_region_free(&sc->sc_dma_rxbufs[i]); 1493 } 1494 goto fail3; 1495 } 1496 } 1497 /* 1498 * status 1499 */ 1500 sc->sc_dma_status.dr_name = "ipw2100-rx-status"; 1501 err = ipw2100_dma_region_alloc(sc, &sc->sc_dma_status, 1502 IPW2100_STATUS_SIZE, DDI_DMA_READ, DDI_DMA_CONSISTENT); 1503 if (err != DDI_SUCCESS) 1504 goto fail4; 1505 /* 1506 * command 1507 */ 1508 sc->sc_dma_cmd.dr_name = "ipw2100-cmd"; 1509 err = ipw2100_dma_region_alloc(sc, &sc->sc_dma_cmd, IPW2100_CMD_SIZE, 1510 DDI_DMA_WRITE, DDI_DMA_CONSISTENT); 1511 if (err != DDI_SUCCESS) 1512 goto fail5; 1513 1514 return (DDI_SUCCESS); 1515 1516 fail5: 1517 ipw2100_dma_region_free(&sc->sc_dma_status); 1518 fail4: 1519 for (i = 0; i < IPW2100_NUM_RXBUF; i++) 1520 ipw2100_dma_region_free(&sc->sc_dma_rxbufs[i]); 1521 fail3: 1522 ipw2100_dma_region_free(&sc->sc_dma_rxbd); 1523 fail2: 1524 for (i = 0; i < IPW2100_NUM_TXBUF; i++) 1525 ipw2100_dma_region_free(&sc->sc_dma_txbufs[i]); 1526 fail1: 1527 ipw2100_dma_region_free(&sc->sc_dma_txbd); 1528 fail0: 1529 return (err); 1530 } 1531 1532 static void 1533 ipw2100_ring_free(struct ipw2100_softc *sc) 1534 { 1535 int i; 1536 1537 /* 1538 * tx ring 1539 */ 1540 ipw2100_dma_region_free(&sc->sc_dma_txbd); 1541 /* 1542 * tx buf 1543 */ 1544 for (i = 0; i < IPW2100_NUM_TXBUF; i++) 1545 ipw2100_dma_region_free(&sc->sc_dma_txbufs[i]); 1546 /* 1547 * rx ring 1548 */ 1549 ipw2100_dma_region_free(&sc->sc_dma_rxbd); 1550 /* 1551 * rx buf 1552 */ 1553 for (i = 0; i < IPW2100_NUM_RXBUF; i++) 1554 ipw2100_dma_region_free(&sc->sc_dma_rxbufs[i]); 1555 /* 1556 * status 1557 */ 1558 ipw2100_dma_region_free(&sc->sc_dma_status); 1559 /* 1560 * command 1561 */ 1562 ipw2100_dma_region_free(&sc->sc_dma_cmd); 1563 } 1564 1565 static void 1566 ipw2100_ring_reset(struct ipw2100_softc *sc) 1567 { 1568 int i; 1569 1570 /* 1571 * tx ring 1572 */ 1573 sc->sc_tx_cur = 0; 1574 sc->sc_tx_free = IPW2100_NUM_TXBD; 1575 sc->sc_txbd = (struct ipw2100_bd *)sc->sc_dma_txbd.dr_base; 1576 for (i = 0; i < IPW2100_NUM_TXBUF; i++) 1577 sc->sc_txbufs[i] = 1578 (struct ipw2100_txb *)sc->sc_dma_txbufs[i].dr_base; 1579 /* 1580 * rx ring 1581 */ 1582 sc->sc_rx_cur = 0; 1583 sc->sc_rx_free = IPW2100_NUM_RXBD; 1584 sc->sc_status = (struct ipw2100_status *)sc->sc_dma_status.dr_base; 1585 sc->sc_rxbd = (struct ipw2100_bd *)sc->sc_dma_rxbd.dr_base; 1586 for (i = 0; i < IPW2100_NUM_RXBUF; i++) { 1587 sc->sc_rxbufs[i] = 1588 (struct ipw2100_rxb *)sc->sc_dma_rxbufs[i].dr_base; 1589 /* 1590 * initialize Rx buffer descriptors, both host and device 1591 */ 1592 sc->sc_rxbd[i].phyaddr = LE_32(sc->sc_dma_rxbufs[i].dr_pbase); 1593 sc->sc_rxbd[i].len = LE_32(sc->sc_dma_rxbufs[i].dr_size); 1594 sc->sc_rxbd[i].flags = 0; 1595 sc->sc_rxbd[i].nfrag = 1; 1596 } 1597 /* 1598 * command 1599 */ 1600 sc->sc_cmd = (struct ipw2100_cmd *)sc->sc_dma_cmd.dr_base; 1601 } 1602 1603 /* 1604 * tx, rx rings and command initialization 1605 */ 1606 static int 1607 ipw2100_ring_init(struct ipw2100_softc *sc) 1608 { 1609 int err; 1610 1611 err = ipw2100_ring_alloc(sc); 1612 if (err != DDI_SUCCESS) 1613 return (err); 1614 1615 ipw2100_ring_reset(sc); 1616 1617 return (DDI_SUCCESS); 1618 } 1619 1620 static void 1621 ipw2100_ring_hwsetup(struct ipw2100_softc *sc) 1622 { 1623 ipw2100_ring_reset(sc); 1624 /* 1625 * tx ring 1626 */ 1627 ipw2100_csr_put32(sc, IPW2100_CSR_TX_BD_BASE, sc->sc_dma_txbd.dr_pbase); 1628 ipw2100_csr_put32(sc, IPW2100_CSR_TX_BD_SIZE, IPW2100_NUM_TXBD); 1629 /* 1630 * no new packet to transmit, tx-rd-index == tx-wr-index 1631 */ 1632 ipw2100_csr_put32(sc, IPW2100_CSR_TX_READ_INDEX, sc->sc_tx_cur); 1633 ipw2100_csr_put32(sc, IPW2100_CSR_TX_WRITE_INDEX, sc->sc_tx_cur); 1634 /* 1635 * rx ring 1636 */ 1637 ipw2100_csr_put32(sc, IPW2100_CSR_RX_BD_BASE, sc->sc_dma_rxbd.dr_pbase); 1638 ipw2100_csr_put32(sc, IPW2100_CSR_RX_BD_SIZE, IPW2100_NUM_RXBD); 1639 /* 1640 * all rx buffer are empty, rx-rd-index == 0 && rx-wr-index == N-1 1641 */ 1642 IPW2100_DBG(IPW2100_DBG_RING, (sc->sc_dip, CE_CONT, 1643 "ipw2100_ring_hwsetup(): rx-cur=%u, backward=%u\n", 1644 sc->sc_rx_cur, RING_BACKWARD(sc->sc_rx_cur, 1, IPW2100_NUM_RXBD))); 1645 ipw2100_csr_put32(sc, IPW2100_CSR_RX_READ_INDEX, sc->sc_rx_cur); 1646 ipw2100_csr_put32(sc, IPW2100_CSR_RX_WRITE_INDEX, 1647 RING_BACKWARD(sc->sc_rx_cur, 1, IPW2100_NUM_RXBD)); 1648 /* 1649 * status 1650 */ 1651 ipw2100_csr_put32(sc, IPW2100_CSR_RX_STATUS_BASE, 1652 sc->sc_dma_status.dr_pbase); 1653 } 1654 1655 /* 1656 * ieee80211_new_state() is not be used, since the hardware can handle the 1657 * state transfer. Here, we just keep the status of the hardware notification 1658 * result. 1659 */ 1660 /* ARGSUSED */ 1661 static int 1662 ipw2100_newstate(struct ieee80211com *ic, enum ieee80211_state state, int arg) 1663 { 1664 struct ipw2100_softc *sc = (struct ipw2100_softc *)ic; 1665 struct ieee80211_node *in; 1666 uint8_t macaddr[IEEE80211_ADDR_LEN]; 1667 uint32_t len; 1668 wifi_data_t wd = { 0 }; 1669 1670 IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT, 1671 "ipw2100_newstate(): %s -> %s\n", 1672 ieee80211_state_name[ic->ic_state], ieee80211_state_name[state])); 1673 1674 switch (state) { 1675 case IEEE80211_S_RUN: 1676 /* 1677 * we only need to use BSSID as to find the node 1678 */ 1679 drv_usecwait(200); /* firmware needs a short delay here */ 1680 len = IEEE80211_ADDR_LEN; 1681 (void) ipw2100_table2_getbuf(sc, IPW2100_INFO_CURRENT_BSSID, 1682 macaddr, &len); 1683 1684 in = ieee80211_find_node(&ic->ic_scan, macaddr); 1685 if (in == NULL) 1686 break; 1687 1688 (void) ieee80211_sta_join(ic, in); 1689 ieee80211_node_authorize(in); 1690 1691 /* 1692 * We can send data now; update the fastpath with our 1693 * current associated BSSID. 1694 */ 1695 if (ic->ic_flags & IEEE80211_F_PRIVACY) 1696 wd.wd_secalloc = WIFI_SEC_WEP; 1697 else 1698 wd.wd_secalloc = WIFI_SEC_NONE; 1699 wd.wd_opmode = ic->ic_opmode; 1700 IEEE80211_ADDR_COPY(wd.wd_bssid, ic->ic_bss->in_bssid); 1701 (void) mac_pdata_update(ic->ic_mach, &wd, sizeof (wd)); 1702 1703 break; 1704 1705 case IEEE80211_S_INIT: 1706 case IEEE80211_S_SCAN: 1707 case IEEE80211_S_AUTH: 1708 case IEEE80211_S_ASSOC: 1709 break; 1710 } 1711 1712 /* 1713 * notify to update the link 1714 */ 1715 if ((ic->ic_state != IEEE80211_S_RUN) && (state == IEEE80211_S_RUN)) { 1716 /* 1717 * previously disconnected and now connected 1718 */ 1719 sc->sc_linkstate = LINK_STATE_UP; 1720 sc->sc_flags |= IPW2100_FLAG_LINK_CHANGE; 1721 } else if ((ic->ic_state == IEEE80211_S_RUN) && 1722 (state != IEEE80211_S_RUN)) { 1723 /* 1724 * previously connected andd now disconnected 1725 */ 1726 sc->sc_linkstate = LINK_STATE_DOWN; 1727 sc->sc_flags |= IPW2100_FLAG_LINK_CHANGE; 1728 } 1729 1730 ic->ic_state = state; 1731 return (DDI_SUCCESS); 1732 } 1733 1734 /* 1735 * GLD operations 1736 */ 1737 /* ARGSUSED */ 1738 static int 1739 ipw2100_m_stat(void *arg, uint_t stat, uint64_t *val) 1740 { 1741 ieee80211com_t *ic = (ieee80211com_t *)arg; 1742 IPW2100_DBG(IPW2100_DBG_GLD, (((struct ipw2100_softc *)arg)->sc_dip, 1743 CE_CONT, 1744 "ipw2100_m_stat(): enter\n")); 1745 /* 1746 * some of below statistic data are from hardware, some from net80211 1747 */ 1748 switch (stat) { 1749 case MAC_STAT_RBYTES: 1750 *val = ic->ic_stats.is_rx_bytes; 1751 break; 1752 case MAC_STAT_IPACKETS: 1753 *val = ic->ic_stats.is_rx_frags; 1754 break; 1755 case MAC_STAT_OBYTES: 1756 *val = ic->ic_stats.is_tx_bytes; 1757 break; 1758 case MAC_STAT_OPACKETS: 1759 *val = ic->ic_stats.is_tx_frags; 1760 break; 1761 /* 1762 * Get below from hardware statistic, retrieve net80211 value once 1s 1763 */ 1764 case WIFI_STAT_TX_FRAGS: 1765 case WIFI_STAT_MCAST_TX: 1766 case WIFI_STAT_TX_FAILED: 1767 case WIFI_STAT_TX_RETRANS: 1768 case WIFI_STAT_RTS_SUCCESS: 1769 case WIFI_STAT_ACK_FAILURE: 1770 case WIFI_STAT_RX_FRAGS: 1771 case WIFI_STAT_MCAST_RX: 1772 /* 1773 * Get blow information from net80211 1774 */ 1775 case WIFI_STAT_RTS_FAILURE: 1776 case WIFI_STAT_RX_DUPS: 1777 case WIFI_STAT_FCS_ERRORS: 1778 case WIFI_STAT_WEP_ERRORS: 1779 return (ieee80211_stat(ic, stat, val)); 1780 /* 1781 * need be supported in the future 1782 */ 1783 case MAC_STAT_IFSPEED: 1784 case MAC_STAT_NOXMTBUF: 1785 case MAC_STAT_IERRORS: 1786 case MAC_STAT_OERRORS: 1787 default: 1788 return (ENOTSUP); 1789 } 1790 return (0); 1791 } 1792 1793 /* ARGSUSED */ 1794 static int 1795 ipw2100_m_multicst(void *arg, boolean_t add, const uint8_t *mca) 1796 { 1797 /* not supported */ 1798 IPW2100_DBG(IPW2100_DBG_GLD, (((struct ipw2100_softc *)arg)->sc_dip, 1799 CE_CONT, 1800 "ipw2100_m_multicst(): enter\n")); 1801 1802 return (0); 1803 } 1804 1805 /* 1806 * This thread function is used to handle the fatal error. 1807 */ 1808 static void 1809 ipw2100_thread(struct ipw2100_softc *sc) 1810 { 1811 struct ieee80211com *ic = &sc->sc_ic; 1812 int32_t nlstate; 1813 int stat_cnt = 0; 1814 1815 IPW2100_DBG(IPW2100_DBG_SOFTINT, (sc->sc_dip, CE_CONT, 1816 "ipw2100_thread(): into ipw2100 thread--> %d\n", 1817 sc->sc_linkstate)); 1818 1819 mutex_enter(&sc->sc_mflock); 1820 1821 while (sc->sc_mfthread_switch) { 1822 /* 1823 * notify the link state 1824 */ 1825 if (ic->ic_mach && (sc->sc_flags & IPW2100_FLAG_LINK_CHANGE)) { 1826 IPW2100_DBG(IPW2100_DBG_SOFTINT, (sc->sc_dip, CE_CONT, 1827 "ipw2100_thread(): link status --> %d\n", 1828 sc->sc_linkstate)); 1829 1830 sc->sc_flags &= ~IPW2100_FLAG_LINK_CHANGE; 1831 nlstate = sc->sc_linkstate; 1832 1833 mutex_exit(&sc->sc_mflock); 1834 mac_link_update(ic->ic_mach, nlstate); 1835 mutex_enter(&sc->sc_mflock); 1836 } 1837 1838 /* 1839 * recovery interrupt fatal error 1840 */ 1841 if (ic->ic_mach && 1842 (sc->sc_flags & IPW2100_FLAG_HW_ERR_RECOVER)) { 1843 1844 IPW2100_DBG(IPW2100_DBG_FATAL, (sc->sc_dip, CE_CONT, 1845 "try to recover fatal hw error\n")); 1846 sc->sc_flags &= ~IPW2100_FLAG_HW_ERR_RECOVER; 1847 1848 mutex_exit(&sc->sc_mflock); 1849 (void) ipw2100_init(sc); /* Force stat machine */ 1850 delay(drv_usectohz(delay_fatal_recover)); 1851 mutex_enter(&sc->sc_mflock); 1852 } 1853 1854 /* 1855 * get statistic, the value will be retrieved by m_stat 1856 */ 1857 if (stat_cnt == 10) { 1858 stat_cnt = 0; /* re-start */ 1859 1860 mutex_exit(&sc->sc_mflock); 1861 ipw2100_get_statistics(sc); 1862 mutex_enter(&sc->sc_mflock); 1863 } else 1864 stat_cnt++; /* until 1s */ 1865 1866 mutex_exit(&sc->sc_mflock); 1867 delay(drv_usectohz(delay_aux_thread)); 1868 mutex_enter(&sc->sc_mflock); 1869 } 1870 sc->sc_mf_thread = NULL; 1871 cv_broadcast(&sc->sc_mfthread_cv); 1872 mutex_exit(&sc->sc_mflock); 1873 } 1874 1875 static int 1876 ipw2100_m_start(void *arg) 1877 { 1878 struct ipw2100_softc *sc = (struct ipw2100_softc *)arg; 1879 1880 IPW2100_DBG(IPW2100_DBG_GLD, (sc->sc_dip, CE_CONT, 1881 "ipw2100_m_start(): enter\n")); 1882 1883 /* 1884 * initialize ipw2100 hardware 1885 */ 1886 (void) ipw2100_init(sc); 1887 1888 sc->sc_flags |= IPW2100_FLAG_RUNNING; 1889 /* 1890 * fix KCF bug. - workaround, need to fix it in net80211 1891 */ 1892 (void) crypto_mech2id(SUN_CKM_RC4); 1893 1894 return (0); 1895 } 1896 1897 static void 1898 ipw2100_m_stop(void *arg) 1899 { 1900 struct ipw2100_softc *sc = (struct ipw2100_softc *)arg; 1901 1902 IPW2100_DBG(IPW2100_DBG_GLD, (sc->sc_dip, CE_CONT, 1903 "ipw2100_m_stop(): enter\n")); 1904 1905 ipw2100_stop(sc); 1906 1907 sc->sc_flags &= ~IPW2100_FLAG_RUNNING; 1908 } 1909 1910 static int 1911 ipw2100_m_unicst(void *arg, const uint8_t *macaddr) 1912 { 1913 struct ipw2100_softc *sc = (struct ipw2100_softc *)arg; 1914 struct ieee80211com *ic = &sc->sc_ic; 1915 int err; 1916 1917 IPW2100_DBG(IPW2100_DBG_GLD, (sc->sc_dip, CE_CONT, 1918 "ipw2100_m_unicst(): enter\n")); 1919 1920 IPW2100_DBG(IPW2100_DBG_GLD, (sc->sc_dip, CE_CONT, 1921 "ipw2100_m_unicst(): GLD setting MAC address to " 1922 "%02x:%02x:%02x:%02x:%02x:%02x\n", 1923 macaddr[0], macaddr[1], macaddr[2], 1924 macaddr[3], macaddr[4], macaddr[5])); 1925 1926 if (!IEEE80211_ADDR_EQ(ic->ic_macaddr, macaddr)) { 1927 IEEE80211_ADDR_COPY(ic->ic_macaddr, macaddr); 1928 1929 if (sc->sc_flags & IPW2100_FLAG_RUNNING) { 1930 err = ipw2100_config(sc); 1931 if (err != DDI_SUCCESS) { 1932 IPW2100_WARN((sc->sc_dip, CE_WARN, 1933 "ipw2100_m_unicst(): " 1934 "device configuration failed\n")); 1935 goto fail; 1936 } 1937 } 1938 } 1939 1940 return (0); 1941 fail: 1942 return (EIO); 1943 } 1944 1945 static int 1946 ipw2100_m_promisc(void *arg, boolean_t on) 1947 { 1948 struct ipw2100_softc *sc = (struct ipw2100_softc *)arg; 1949 int recfg, err; 1950 1951 IPW2100_DBG(IPW2100_DBG_GLD, (sc->sc_dip, CE_CONT, 1952 "ipw2100_m_promisc(): enter. " 1953 "GLD setting promiscuous mode - %d\n", on)); 1954 1955 recfg = 0; 1956 if (on) 1957 if (!(sc->if_flags & IFF_PROMISC)) { 1958 sc->if_flags |= IFF_PROMISC; 1959 recfg = 1; 1960 } 1961 else 1962 if (sc->if_flags & IFF_PROMISC) { 1963 sc->if_flags &= ~IFF_PROMISC; 1964 recfg = 1; 1965 } 1966 1967 if (recfg && (sc->sc_flags & IPW2100_FLAG_RUNNING)) { 1968 err = ipw2100_config(sc); 1969 if (err != DDI_SUCCESS) { 1970 IPW2100_WARN((sc->sc_dip, CE_WARN, 1971 "ipw2100_m_promisc(): " 1972 "device configuration failed\n")); 1973 goto fail; 1974 } 1975 } 1976 1977 return (0); 1978 fail: 1979 return (EIO); 1980 } 1981 1982 static mblk_t * 1983 ipw2100_m_tx(void *arg, mblk_t *mp) 1984 { 1985 struct ipw2100_softc *sc = (struct ipw2100_softc *)arg; 1986 struct ieee80211com *ic = &sc->sc_ic; 1987 mblk_t *next; 1988 1989 /* 1990 * No data frames go out unless we're associated; this 1991 * should not happen as the 802.11 layer does not enable 1992 * the xmit queue until we enter the RUN state. 1993 */ 1994 if (ic->ic_state != IEEE80211_S_RUN) { 1995 IPW2100_DBG(IPW2100_DBG_GLD, (sc->sc_dip, CE_CONT, 1996 "ipw2100_m_tx(): discard msg, ic_state = %u\n", 1997 ic->ic_state)); 1998 freemsgchain(mp); 1999 return (NULL); 2000 } 2001 2002 while (mp != NULL) { 2003 next = mp->b_next; 2004 mp->b_next = NULL; 2005 if (ipw2100_send(ic, mp, IEEE80211_FC0_TYPE_DATA) != 2006 DDI_SUCCESS) { 2007 mp->b_next = next; 2008 break; 2009 } 2010 mp = next; 2011 } 2012 return (mp); 2013 } 2014 2015 /* ARGSUSED */ 2016 static int 2017 ipw2100_send(ieee80211com_t *ic, mblk_t *mp, uint8_t type) 2018 { 2019 struct ipw2100_softc *sc = (struct ipw2100_softc *)ic; 2020 struct ieee80211_node *in; 2021 struct ieee80211_frame wh, *wh_tmp; 2022 struct ieee80211_key *k; 2023 uint8_t *hdat; 2024 mblk_t *m0, *m; 2025 size_t cnt, off; 2026 struct ipw2100_bd *txbd[2]; 2027 struct ipw2100_txb *txbuf; 2028 struct dma_region *dr; 2029 struct ipw2100_hdr *h; 2030 uint32_t idx, bidx; 2031 int err; 2032 2033 ASSERT(mp->b_next == NULL); 2034 2035 m0 = NULL; 2036 m = NULL; 2037 err = DDI_SUCCESS; 2038 2039 IPW2100_DBG(IPW2100_DBG_GLD, (sc->sc_dip, CE_CONT, 2040 "ipw2100_send(): enter\n")); 2041 2042 if ((type & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_DATA) { 2043 /* 2044 * it is impossible to send non-data 802.11 frame in current 2045 * ipw driver. Therefore, drop the package 2046 */ 2047 freemsg(mp); 2048 err = DDI_SUCCESS; 2049 goto fail0; 2050 } 2051 2052 mutex_enter(&sc->sc_tx_lock); 2053 2054 /* 2055 * need 2 descriptors: 1 for SEND cmd parameter header, 2056 * and the other for payload, i.e., 802.11 frame including 802.11 2057 * frame header 2058 */ 2059 if (sc->sc_tx_free < 2) { 2060 mutex_enter(&sc->sc_resched_lock); 2061 IPW2100_DBG(IPW2100_DBG_RING, (sc->sc_dip, CE_WARN, 2062 "ipw2100_send(): no enough descriptors(%d)\n", 2063 sc->sc_tx_free)); 2064 ic->ic_stats.is_tx_nobuf++; /* no enough buffer */ 2065 sc->sc_flags |= IPW2100_FLAG_TX_SCHED; 2066 err = DDI_FAILURE; 2067 mutex_exit(&sc->sc_resched_lock); 2068 goto fail1; 2069 } 2070 IPW2100_DBG(IPW2100_DBG_RING, (sc->sc_dip, CE_CONT, 2071 "ipw2100_send(): tx-free=%d,tx-curr=%d\n", 2072 sc->sc_tx_free, sc->sc_tx_cur)); 2073 2074 wh_tmp = (struct ieee80211_frame *)mp->b_rptr; 2075 in = ieee80211_find_txnode(ic, wh_tmp->i_addr1); 2076 if (in == NULL) { /* can not find tx node, drop the package */ 2077 freemsg(mp); 2078 err = DDI_SUCCESS; 2079 goto fail1; 2080 } 2081 in->in_inact = 0; 2082 (void) ieee80211_encap(ic, mp, in); 2083 ieee80211_free_node(in); 2084 2085 if (wh_tmp->i_fc[1] & IEEE80211_FC1_WEP) { 2086 /* 2087 * it is very bad that ieee80211_crypto_encap can only accept a 2088 * single continuous buffer. 2089 */ 2090 /* 2091 * allocate 32 more bytes is to be compatible with further 2092 * ieee802.11i standard. 2093 */ 2094 m = allocb(msgdsize(mp) + 32, BPRI_MED); 2095 if (m == NULL) { /* can not alloc buf, drop this package */ 2096 IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT, 2097 "ipw2100_send(): msg allocation failed\n")); 2098 2099 freemsg(mp); 2100 2101 err = DDI_SUCCESS; 2102 goto fail1; 2103 } 2104 off = 0; 2105 m0 = mp; 2106 while (m0) { 2107 cnt = MBLKL(m0); 2108 if (cnt) { 2109 (void) memcpy(m->b_rptr + off, m0->b_rptr, cnt); 2110 off += cnt; 2111 } 2112 m0 = m0->b_cont; 2113 } 2114 m->b_wptr += off; 2115 IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT, 2116 "ipw2100_send(): " 2117 "Encrypting 802.11 frame started, %d, %d\n", 2118 msgdsize(mp), MBLKL(mp))); 2119 k = ieee80211_crypto_encap(ic, m); 2120 if (k == NULL) { /* can not get the key, drop packages */ 2121 IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT, 2122 "ipw2100_send(): " 2123 "Encrypting 802.11 frame failed\n")); 2124 2125 freemsg(mp); 2126 err = DDI_SUCCESS; 2127 goto fail2; 2128 } 2129 IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT, 2130 "ipw2100_send(): " 2131 "Encrypting 802.11 frame finished, %d, %d, k=0x%08x\n", 2132 msgdsize(mp), MBLKL(mp), k->wk_flags)); 2133 } 2134 2135 /* 2136 * header descriptor 2137 */ 2138 idx = sc->sc_tx_cur; 2139 txbd[0] = &sc->sc_txbd[idx]; 2140 if ((idx & 1) == 0) 2141 bidx = idx / 2; 2142 sc->sc_tx_cur = RING_FORWARD(sc->sc_tx_cur, 1, IPW2100_NUM_TXBD); 2143 sc->sc_tx_free--; 2144 2145 /* 2146 * payload descriptor 2147 */ 2148 idx = sc->sc_tx_cur; 2149 txbd[1] = &sc->sc_txbd[idx]; 2150 if ((idx & 1) == 0) 2151 bidx = idx / 2; 2152 sc->sc_tx_cur = RING_FORWARD(sc->sc_tx_cur, 1, IPW2100_NUM_TXBD); 2153 sc->sc_tx_free--; 2154 2155 /* 2156 * one buffer, SEND cmd header and payload buffer 2157 */ 2158 txbuf = sc->sc_txbufs[bidx]; 2159 dr = &sc->sc_dma_txbufs[bidx]; 2160 2161 /* 2162 * extract 802.11 header from message, fill wh from m0 2163 */ 2164 hdat = (uint8_t *)&wh; 2165 off = 0; 2166 if (m) 2167 m0 = m; 2168 else 2169 m0 = mp; 2170 while (off < sizeof (wh)) { 2171 cnt = MBLKL(m0); 2172 if (cnt > (sizeof (wh) - off)) 2173 cnt = sizeof (wh) - off; 2174 if (cnt) { 2175 (void) memcpy(hdat + off, m0->b_rptr, cnt); 2176 off += cnt; 2177 m0->b_rptr += cnt; 2178 } 2179 else 2180 m0 = m0->b_cont; 2181 } 2182 2183 /* 2184 * prepare SEND cmd header 2185 */ 2186 h = &txbuf->txb_hdr; 2187 h->type = LE_32(IPW2100_CMD_SEND); 2188 h->subtype = LE_32(0); 2189 h->encrypted = ic->ic_flags & IEEE80211_F_PRIVACY ? 1 : 0; 2190 h->encrypt = 0; 2191 h->keyidx = 0; 2192 h->keysz = 0; 2193 h->fragsz = LE_16(0); 2194 IEEE80211_ADDR_COPY(h->saddr, wh.i_addr2); 2195 if (ic->ic_opmode == IEEE80211_M_STA) 2196 IEEE80211_ADDR_COPY(h->daddr, wh.i_addr3); 2197 else 2198 IEEE80211_ADDR_COPY(h->daddr, wh.i_addr1); 2199 2200 /* 2201 * extract payload from message into tx data buffer 2202 */ 2203 off = 0; 2204 while (m0) { 2205 cnt = MBLKL(m0); 2206 if (cnt) { 2207 (void) memcpy(&txbuf->txb_dat[off], m0->b_rptr, cnt); 2208 off += cnt; 2209 } 2210 m0 = m0->b_cont; 2211 } 2212 2213 /* 2214 * fill SEND cmd header descriptor 2215 */ 2216 txbd[0]->phyaddr = LE_32(dr->dr_pbase + 2217 OFFSETOF(struct ipw2100_txb, txb_hdr)); 2218 txbd[0]->len = LE_32(sizeof (struct ipw2100_hdr)); 2219 txbd[0]->flags = IPW2100_BD_FLAG_TX_FRAME_802_3 | 2220 IPW2100_BD_FLAG_TX_NOT_LAST_FRAGMENT; 2221 txbd[0]->nfrag = 2; 2222 /* 2223 * fill payload descriptor 2224 */ 2225 txbd[1]->phyaddr = LE_32(dr->dr_pbase + 2226 OFFSETOF(struct ipw2100_txb, txb_dat[0])); 2227 txbd[1]->len = LE_32(off); 2228 txbd[1]->flags = IPW2100_BD_FLAG_TX_FRAME_802_3 | 2229 IPW2100_BD_FLAG_TX_LAST_FRAGMENT; 2230 txbd[1]->nfrag = 0; 2231 2232 /* 2233 * dma sync 2234 */ 2235 (void) ddi_dma_sync(dr->dr_hnd, 0, sizeof (struct ipw2100_txb), 2236 DDI_DMA_SYNC_FORDEV); 2237 (void) ddi_dma_sync(sc->sc_dma_txbd.dr_hnd, 2238 (txbd[0] - sc->sc_txbd) * sizeof (struct ipw2100_bd), 2239 sizeof (struct ipw2100_bd), DDI_DMA_SYNC_FORDEV); 2240 /* 2241 * since txbd[1] may not be successive to txbd[0] due to the ring 2242 * organization, another dma_sync is needed to simplify the logic 2243 */ 2244 (void) ddi_dma_sync(sc->sc_dma_txbd.dr_hnd, 2245 (txbd[1] - sc->sc_txbd) * sizeof (struct ipw2100_bd), 2246 sizeof (struct ipw2100_bd), DDI_DMA_SYNC_FORDEV); 2247 /* 2248 * update txcur 2249 */ 2250 ipw2100_csr_put32(sc, IPW2100_CSR_TX_WRITE_INDEX, sc->sc_tx_cur); 2251 2252 if (mp) /* success, free the original message */ 2253 freemsg(mp); 2254 fail2: 2255 if (m) 2256 freemsg(m); 2257 fail1: 2258 mutex_exit(&sc->sc_tx_lock); 2259 fail0: 2260 IPW2100_DBG(IPW2100_DBG_GLD, (sc->sc_dip, CE_CONT, 2261 "ipw2100_send(): exit - err=%d\n", err)); 2262 2263 return (err); 2264 } 2265 2266 /* 2267 * IOCTL Handler 2268 */ 2269 #define IEEE80211_IOCTL_REQUIRED (1) 2270 #define IEEE80211_IOCTL_NOT_REQUIRED (0) 2271 static void 2272 ipw2100_m_ioctl(void *arg, queue_t *q, mblk_t *m) 2273 { 2274 struct ipw2100_softc *sc = (struct ipw2100_softc *)arg; 2275 struct ieee80211com *ic = &sc->sc_ic; 2276 int err; 2277 2278 IPW2100_DBG(IPW2100_DBG_GLD, (sc->sc_dip, CE_CONT, 2279 "ipw2100_m_ioctl(): enter\n")); 2280 2281 /* 2282 * check whether or not need to handle this in net80211 2283 */ 2284 if (ipw2100_ioctl(sc, q, m) == IEEE80211_IOCTL_NOT_REQUIRED) 2285 return; /* succes or fail */ 2286 2287 err = ieee80211_ioctl(ic, q, m); 2288 if (err == ENETRESET) { 2289 if (sc->sc_flags & IPW2100_FLAG_RUNNING) { 2290 (void) ipw2100_m_start(sc); 2291 (void) ieee80211_new_state(ic, 2292 IEEE80211_S_SCAN, -1); 2293 } 2294 } 2295 if (err == ERESTART) { 2296 if (sc->sc_flags & IPW2100_FLAG_RUNNING) 2297 (void) ipw2100_chip_reset(sc); 2298 } 2299 } 2300 2301 static int 2302 ipw2100_ioctl(struct ipw2100_softc *sc, queue_t *q, mblk_t *m) 2303 { 2304 struct iocblk *iocp; 2305 uint32_t len, ret, cmd; 2306 mblk_t *m0; 2307 boolean_t need_privilege; 2308 boolean_t need_net80211; 2309 2310 if (MBLKL(m) < sizeof (struct iocblk)) { 2311 IPW2100_DBG(IPW2100_DBG_IOCTL, (sc->sc_dip, CE_CONT, 2312 "ipw2100_ioctl(): ioctl buffer too short, %u\n", 2313 MBLKL(m))); 2314 miocnak(q, m, 0, EINVAL); 2315 return (IEEE80211_IOCTL_NOT_REQUIRED); 2316 } 2317 2318 /* 2319 * Validate the command 2320 */ 2321 iocp = (struct iocblk *)(uintptr_t)m->b_rptr; 2322 iocp->ioc_error = 0; 2323 cmd = iocp->ioc_cmd; 2324 need_privilege = B_TRUE; 2325 switch (cmd) { 2326 case WLAN_SET_PARAM: 2327 case WLAN_COMMAND: 2328 break; 2329 case WLAN_GET_PARAM: 2330 need_privilege = B_FALSE; 2331 break; 2332 default: 2333 IPW2100_DBG(IPW2100_DBG_IOCTL, (sc->sc_dip, CE_CONT, 2334 "ieee80211_ioctl(): unknown cmd 0x%x", cmd)); 2335 miocnak(q, m, 0, EINVAL); 2336 return (IEEE80211_IOCTL_NOT_REQUIRED); 2337 } 2338 2339 if (need_privilege && (ret = secpolicy_dl_config(iocp->ioc_cr)) != 0) { 2340 miocnak(q, m, 0, ret); 2341 return (IEEE80211_IOCTL_NOT_REQUIRED); 2342 } 2343 2344 /* 2345 * sanity check 2346 */ 2347 m0 = m->b_cont; 2348 if (iocp->ioc_count == 0 || iocp->ioc_count < sizeof (wldp_t) || 2349 m0 == NULL) { 2350 miocnak(q, m, 0, EINVAL); 2351 return (IEEE80211_IOCTL_NOT_REQUIRED); 2352 } 2353 /* 2354 * assuming single data block 2355 */ 2356 if (m0->b_cont) { 2357 freemsg(m0->b_cont); 2358 m0->b_cont = NULL; 2359 } 2360 2361 need_net80211 = B_FALSE; 2362 ret = ipw2100_getset(sc, m0, cmd, &need_net80211); 2363 if (!need_net80211) { 2364 len = msgdsize(m0); 2365 2366 IPW2100_DBG(IPW2100_DBG_IOCTL, (sc->sc_dip, CE_CONT, 2367 "ipw2100_ioctl(): go to call miocack with " 2368 "ret = %d, len = %d\n", ret, len)); 2369 miocack(q, m, len, ret); 2370 return (IEEE80211_IOCTL_NOT_REQUIRED); 2371 } 2372 2373 /* 2374 * IEEE80211_IOCTL_REQUIRED - need net80211 handle 2375 */ 2376 return (IEEE80211_IOCTL_REQUIRED); 2377 } 2378 2379 static int 2380 ipw2100_getset(struct ipw2100_softc *sc, mblk_t *m, uint32_t cmd, 2381 boolean_t *need_net80211) 2382 { 2383 wldp_t *infp, *outfp; 2384 uint32_t id; 2385 int ret; /* IEEE80211_IOCTL - handled by net80211 */ 2386 2387 infp = (wldp_t *)(uintptr_t)m->b_rptr; 2388 outfp = (wldp_t *)(uintptr_t)m->b_rptr; 2389 outfp->wldp_result = WL_NOTSUPPORTED; 2390 2391 id = infp->wldp_id; 2392 IPW2100_DBG(IPW2100_DBG_IOCTL, (sc->sc_dip, CE_CONT, 2393 "ipw2100_getset(): id = 0x%x\n", id)); 2394 switch (id) { 2395 /* 2396 * which is not supported by net80211, so it 2397 * has to be handled from driver side 2398 */ 2399 case WL_RADIO: 2400 ret = ipw_wificfg_radio(sc, cmd, outfp); 2401 break; 2402 /* 2403 * so far, drier doesn't support fix-rates 2404 */ 2405 case WL_DESIRED_RATES: 2406 ret = ipw_wificfg_desrates(outfp); 2407 break; 2408 /* 2409 * current net80211 implementation clears the bssid while 2410 * this command received, which will result in the all zero 2411 * mac address for scan'ed AP which is just disconnected. 2412 * This is a workaround solution until net80211 find a 2413 * better method. 2414 */ 2415 case WL_DISASSOCIATE: 2416 ret = ipw_wificfg_disassoc(sc, outfp); 2417 break; 2418 default: 2419 /* 2420 * The wifi IOCTL net80211 supported: 2421 * case WL_ESSID: 2422 * case WL_BSSID: 2423 * case WL_WEP_KEY_TAB: 2424 * case WL_WEP_KEY_ID: 2425 * case WL_AUTH_MODE: 2426 * case WL_ENCRYPTION: 2427 * case WL_BSS_TYPE: 2428 * case WL_ESS_LIST: 2429 * case WL_LINKSTATUS: 2430 * case WL_RSSI: 2431 * case WL_SCAN: 2432 * case WL_LOAD_DEFAULTS: 2433 */ 2434 2435 /* 2436 * When radio is off, need to ignore all ioctl. What need to 2437 * do is to check radio status firstly. If radio is ON, pass 2438 * it to net80211, otherwise, return to upper layer directly. 2439 * 2440 * Considering the WL_SUCCESS also means WL_CONNECTED for 2441 * checking linkstatus, one exception for WL_LINKSTATUS is to 2442 * let net80211 handle it. 2443 */ 2444 if ((ipw2100_get_radio(sc) == 0) && 2445 (id != WL_LINKSTATUS)) { 2446 2447 IPW2100_REPORT((sc->sc_dip, CE_WARN, 2448 "ipw: RADIO is OFF\n")); 2449 2450 outfp->wldp_length = WIFI_BUF_OFFSET; 2451 outfp->wldp_result = WL_SUCCESS; 2452 ret = 0; 2453 break; 2454 } 2455 2456 *need_net80211 = B_TRUE; /* let net80211 do the rest */ 2457 return (0); 2458 } 2459 /* 2460 * we will overwrite everything 2461 */ 2462 m->b_wptr = m->b_rptr + outfp->wldp_length; 2463 2464 return (ret); 2465 } 2466 2467 /* 2468 * Call back functions for get/set proporty 2469 */ 2470 static int 2471 ipw2100_m_getprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num, 2472 uint_t pr_flags, uint_t wldp_length, void *wldp_buf, uint_t *perm) 2473 { 2474 struct ipw2100_softc *sc = (struct ipw2100_softc *)arg; 2475 struct ieee80211com *ic = &sc->sc_ic; 2476 int err = 0; 2477 2478 switch (wldp_pr_num) { 2479 /* mac_prop_id */ 2480 case MAC_PROP_WL_DESIRED_RATES: 2481 IPW2100_DBG(IPW2100_DBG_BRUSSELS, (sc->sc_dip, CE_CONT, 2482 "ipw2100_m_getprop(): Not Support DESIRED_RATES\n")); 2483 err = ENOTSUP; 2484 break; 2485 case MAC_PROP_WL_RADIO: 2486 *(wl_linkstatus_t *)wldp_buf = ipw2100_get_radio(sc); 2487 break; 2488 default: 2489 /* go through net80211 */ 2490 err = ieee80211_getprop(ic, pr_name, wldp_pr_num, pr_flags, 2491 wldp_length, wldp_buf, perm); 2492 break; 2493 } 2494 2495 return (err); 2496 } 2497 2498 static int 2499 ipw2100_m_setprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num, 2500 uint_t wldp_length, const void *wldp_buf) 2501 { 2502 struct ipw2100_softc *sc = (struct ipw2100_softc *)arg; 2503 struct ieee80211com *ic = &sc->sc_ic; 2504 int err; 2505 2506 switch (wldp_pr_num) { 2507 /* mac_prop_id */ 2508 case MAC_PROP_WL_DESIRED_RATES: 2509 IPW2100_DBG(IPW2100_DBG_BRUSSELS, (sc->sc_dip, CE_CONT, 2510 "ipw2100_m_setprop(): Not Support DESIRED_RATES\n")); 2511 err = ENOTSUP; 2512 break; 2513 case MAC_PROP_WL_RADIO: 2514 IPW2100_DBG(IPW2100_DBG_BRUSSELS, (sc->sc_dip, CE_CONT, 2515 "ipw2100_m_setprop(): Not Support RADIO\n")); 2516 err = ENOTSUP; 2517 break; 2518 default: 2519 /* go through net80211 */ 2520 err = ieee80211_setprop(ic, pr_name, wldp_pr_num, wldp_length, 2521 wldp_buf); 2522 break; 2523 } 2524 2525 if (err == ENETRESET) { 2526 if (sc->sc_flags & IPW2100_FLAG_RUNNING) { 2527 (void) ipw2100_m_start(sc); 2528 (void) ieee80211_new_state(ic, 2529 IEEE80211_S_SCAN, -1); 2530 } 2531 2532 err = 0; 2533 } 2534 2535 return (err); 2536 } 2537 2538 static int 2539 ipw_wificfg_radio(struct ipw2100_softc *sc, uint32_t cmd, wldp_t *outfp) 2540 { 2541 uint32_t ret = ENOTSUP; 2542 2543 switch (cmd) { 2544 case WLAN_GET_PARAM: 2545 *(wl_linkstatus_t *)(outfp->wldp_buf) = ipw2100_get_radio(sc); 2546 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_linkstatus_t); 2547 outfp->wldp_result = WL_SUCCESS; 2548 ret = 0; /* command sucess */ 2549 break; 2550 case WLAN_SET_PARAM: 2551 default: 2552 break; 2553 } 2554 return (ret); 2555 } 2556 2557 static int 2558 ipw_wificfg_desrates(wldp_t *outfp) 2559 { 2560 /* 2561 * return success, but with result NOTSUPPORTED 2562 */ 2563 outfp->wldp_length = WIFI_BUF_OFFSET; 2564 outfp->wldp_result = WL_NOTSUPPORTED; 2565 return (0); 2566 } 2567 2568 static int 2569 ipw_wificfg_disassoc(struct ipw2100_softc *sc, wldp_t *outfp) 2570 { 2571 struct ieee80211com *ic = &sc->sc_ic; 2572 2573 /* 2574 * init the state 2575 */ 2576 if (ic->ic_state != IEEE80211_S_INIT) { 2577 (void) ieee80211_new_state(ic, IEEE80211_S_INIT, -1); 2578 } 2579 2580 /* 2581 * return success always 2582 */ 2583 outfp->wldp_length = WIFI_BUF_OFFSET; 2584 outfp->wldp_result = WL_SUCCESS; 2585 return (0); 2586 } 2587 /* End of IOCTL Handler */ 2588 2589 static void 2590 ipw2100_fix_channel(struct ieee80211com *ic, mblk_t *m) 2591 { 2592 struct ieee80211_frame *wh; 2593 uint8_t subtype; 2594 uint8_t *frm, *efrm; 2595 2596 wh = (struct ieee80211_frame *)m->b_rptr; 2597 2598 if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_MGT) 2599 return; 2600 2601 subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; 2602 2603 if (subtype != IEEE80211_FC0_SUBTYPE_BEACON && 2604 subtype != IEEE80211_FC0_SUBTYPE_PROBE_RESP) 2605 return; 2606 2607 /* 2608 * assume the message contains only 1 block 2609 */ 2610 frm = (uint8_t *)(wh + 1); 2611 efrm = (uint8_t *)m->b_wptr; 2612 frm += 12; /* skip tstamp, bintval and capinfo fields */ 2613 while (frm < efrm) { 2614 if (*frm == IEEE80211_ELEMID_DSPARMS) { 2615 #if IEEE80211_CHAN_MAX < 255 2616 if (frm[2] <= IEEE80211_CHAN_MAX) 2617 #endif 2618 { 2619 ic->ic_curchan = &ic->ic_sup_channels[frm[2]]; 2620 } 2621 } 2622 frm += frm[1] + 2; 2623 } 2624 } 2625 2626 static void 2627 ipw2100_rcvpkt(struct ipw2100_softc *sc, struct ipw2100_status *status, 2628 uint8_t *rxbuf) 2629 { 2630 struct ieee80211com *ic = &sc->sc_ic; 2631 mblk_t *m; 2632 struct ieee80211_frame *wh = (struct ieee80211_frame *)rxbuf; 2633 struct ieee80211_node *in; 2634 uint32_t rlen; 2635 2636 in = ieee80211_find_rxnode(ic, wh); 2637 rlen = LE_32(status->len); 2638 m = allocb(rlen, BPRI_MED); 2639 if (m) { 2640 (void) memcpy(m->b_wptr, rxbuf, rlen); 2641 m->b_wptr += rlen; 2642 if (ic->ic_state == IEEE80211_S_SCAN) 2643 ipw2100_fix_channel(ic, m); 2644 (void) ieee80211_input(ic, m, in, status->rssi, 0); 2645 } else 2646 IPW2100_WARN((sc->sc_dip, CE_WARN, 2647 "ipw2100_rcvpkg(): cannot allocate receive message(%u)\n", 2648 LE_32(status->len))); 2649 ieee80211_free_node(in); 2650 } 2651 2652 static uint_t 2653 ipw2100_intr(caddr_t arg) 2654 { 2655 struct ipw2100_softc *sc = (struct ipw2100_softc *)(uintptr_t)arg; 2656 uint32_t ireg, ridx, len, i; 2657 struct ieee80211com *ic = &sc->sc_ic; 2658 struct ipw2100_status *status; 2659 uint8_t *rxbuf; 2660 struct dma_region *dr; 2661 uint32_t state; 2662 #if DEBUG 2663 struct ipw2100_bd *rxbd; 2664 #endif 2665 2666 if (sc->sc_suspended) 2667 return (DDI_INTR_UNCLAIMED); 2668 2669 ireg = ipw2100_csr_get32(sc, IPW2100_CSR_INTR); 2670 2671 if (!(ireg & IPW2100_INTR_MASK_ALL)) 2672 return (DDI_INTR_UNCLAIMED); 2673 2674 /* 2675 * mask all interrupts 2676 */ 2677 ipw2100_csr_put32(sc, IPW2100_CSR_INTR_MASK, 0); 2678 2679 /* 2680 * acknowledge all fired interrupts 2681 */ 2682 ipw2100_csr_put32(sc, IPW2100_CSR_INTR, ireg); 2683 2684 IPW2100_DBG(IPW2100_DBG_INT, (sc->sc_dip, CE_CONT, 2685 "ipw2100_intr(): interrupt is fired. int=0x%08x\n", ireg)); 2686 2687 if (ireg & IPW2100_INTR_MASK_ERR) { 2688 2689 IPW2100_DBG(IPW2100_DBG_FATAL, (sc->sc_dip, CE_CONT, 2690 "ipw2100_intr(): interrupt is fired, MASK = 0x%08x\n", 2691 ireg)); 2692 2693 /* 2694 * inform mfthread to recover hw error 2695 */ 2696 mutex_enter(&sc->sc_mflock); 2697 sc->sc_flags |= IPW2100_FLAG_HW_ERR_RECOVER; 2698 mutex_exit(&sc->sc_mflock); 2699 2700 goto enable_interrupt; 2701 } 2702 2703 /* 2704 * FW intr 2705 */ 2706 if (ireg & IPW2100_INTR_FW_INIT_DONE) { 2707 mutex_enter(&sc->sc_ilock); 2708 sc->sc_flags |= IPW2100_FLAG_FW_INITED; 2709 cv_signal(&sc->sc_fw_cond); 2710 mutex_exit(&sc->sc_ilock); 2711 } 2712 2713 /* 2714 * RX intr 2715 */ 2716 if (ireg & IPW2100_INTR_RX_TRANSFER) { 2717 ridx = ipw2100_csr_get32(sc, 2718 IPW2100_CSR_RX_READ_INDEX); 2719 2720 for (; sc->sc_rx_cur != ridx; 2721 sc->sc_rx_cur = RING_FORWARD( 2722 sc->sc_rx_cur, 1, IPW2100_NUM_RXBD)) { 2723 2724 i = sc->sc_rx_cur; 2725 status = &sc->sc_status[i]; 2726 rxbuf = &sc->sc_rxbufs[i]->rxb_dat[0]; 2727 dr = &sc->sc_dma_rxbufs[i]; 2728 2729 /* 2730 * sync 2731 */ 2732 (void) ddi_dma_sync(sc->sc_dma_status.dr_hnd, 2733 i * sizeof (struct ipw2100_status), 2734 sizeof (struct ipw2100_status), 2735 DDI_DMA_SYNC_FORKERNEL); 2736 (void) ddi_dma_sync(sc->sc_dma_rxbd.dr_hnd, 2737 i * sizeof (struct ipw2100_bd), 2738 sizeof (struct ipw2100_bd), 2739 DDI_DMA_SYNC_FORKERNEL); 2740 (void) ddi_dma_sync(dr->dr_hnd, 0, 2741 sizeof (struct ipw2100_rxb), 2742 DDI_DMA_SYNC_FORKERNEL); 2743 IPW2100_DBG(IPW2100_DBG_INT, (sc->sc_dip, CE_CONT, 2744 "ipw2100_intr(): status code=0x%04x, len=0x%08x, " 2745 "flags=0x%02x, rssi=%02x\n", 2746 LE_16(status->code), LE_32(status->len), 2747 status->flags, status->rssi)); 2748 #if DEBUG 2749 rxbd = &sc->sc_rxbd[i]; 2750 IPW2100_DBG(IPW2100_DBG_INT, (sc->sc_dip, CE_CONT, 2751 "ipw2100_intr(): rxbd,phyaddr=0x%08x, len=0x%08x, " 2752 "flags=0x%02x,nfrag=%02x\n", 2753 LE_32(rxbd->phyaddr), LE_32(rxbd->len), 2754 rxbd->flags, rxbd->nfrag)); 2755 #endif 2756 switch (LE_16(status->code) & 0x0f) { 2757 /* 2758 * command complete response 2759 */ 2760 case IPW2100_STATUS_CODE_COMMAND: 2761 mutex_enter(&sc->sc_ilock); 2762 sc->sc_done = 1; 2763 cv_signal(&sc->sc_cmd_cond); 2764 mutex_exit(&sc->sc_ilock); 2765 break; 2766 /* 2767 * change state 2768 */ 2769 case IPW2100_STATUS_CODE_NEWSTATE: 2770 state = LE_32(* ((uint32_t *)(uintptr_t)rxbuf)); 2771 IPW2100_DBG(IPW2100_DBG_INT, 2772 (sc->sc_dip, CE_CONT, 2773 "ipw2100_intr(): newstate,state=0x%x\n", 2774 state)); 2775 2776 switch (state) { 2777 case IPW2100_STATE_ASSOCIATED: 2778 ieee80211_new_state(ic, 2779 IEEE80211_S_RUN, -1); 2780 break; 2781 case IPW2100_STATE_ASSOCIATION_LOST: 2782 case IPW2100_STATE_DISABLED: 2783 ieee80211_new_state(ic, 2784 IEEE80211_S_INIT, -1); 2785 break; 2786 /* 2787 * When radio is OFF, need a better 2788 * scan approach to ensure scan 2789 * result correct. 2790 */ 2791 case IPW2100_STATE_RADIO_DISABLED: 2792 IPW2100_REPORT((sc->sc_dip, CE_WARN, 2793 "ipw2100_intr(): RADIO is OFF\n")); 2794 ipw2100_stop(sc); 2795 break; 2796 case IPW2100_STATE_SCAN_COMPLETE: 2797 ieee80211_cancel_scan(ic); 2798 break; 2799 case IPW2100_STATE_SCANNING: 2800 if (ic->ic_state != IEEE80211_S_RUN) 2801 ieee80211_new_state(ic, 2802 IEEE80211_S_SCAN, -1); 2803 ic->ic_flags |= IEEE80211_F_SCAN; 2804 2805 break; 2806 default: 2807 break; 2808 } 2809 break; 2810 case IPW2100_STATUS_CODE_DATA_802_11: 2811 case IPW2100_STATUS_CODE_DATA_802_3: 2812 ipw2100_rcvpkt(sc, status, rxbuf); 2813 break; 2814 case IPW2100_STATUS_CODE_NOTIFICATION: 2815 break; 2816 default: 2817 IPW2100_WARN((sc->sc_dip, CE_WARN, 2818 "ipw2100_intr(): " 2819 "unknown status code 0x%04x\n", 2820 LE_16(status->code))); 2821 break; 2822 } 2823 } 2824 /* 2825 * write sc_rx_cur backward 1 step to RX_WRITE_INDEX 2826 */ 2827 ipw2100_csr_put32(sc, IPW2100_CSR_RX_WRITE_INDEX, 2828 RING_BACKWARD(sc->sc_rx_cur, 1, IPW2100_NUM_RXBD)); 2829 } 2830 2831 /* 2832 * TX intr 2833 */ 2834 if (ireg & IPW2100_INTR_TX_TRANSFER) { 2835 mutex_enter(&sc->sc_tx_lock); 2836 ridx = ipw2100_csr_get32(sc, IPW2100_CSR_TX_READ_INDEX); 2837 len = RING_FLEN(RING_FORWARD(sc->sc_tx_cur, 2838 sc->sc_tx_free, IPW2100_NUM_TXBD), 2839 ridx, IPW2100_NUM_TXBD); 2840 sc->sc_tx_free += len; 2841 IPW2100_DBG(IPW2100_DBG_INT, (sc->sc_dip, CE_CONT, 2842 "ipw2100_intr(): len=%d\n", len)); 2843 mutex_exit(&sc->sc_tx_lock); 2844 2845 mutex_enter(&sc->sc_resched_lock); 2846 if (len > 1 && (sc->sc_flags & IPW2100_FLAG_TX_SCHED)) { 2847 sc->sc_flags &= ~IPW2100_FLAG_TX_SCHED; 2848 mac_tx_update(ic->ic_mach); 2849 } 2850 mutex_exit(&sc->sc_resched_lock); 2851 } 2852 2853 enable_interrupt: 2854 /* 2855 * enable all interrupts 2856 */ 2857 ipw2100_csr_put32(sc, IPW2100_CSR_INTR_MASK, IPW2100_INTR_MASK_ALL); 2858 2859 return (DDI_INTR_CLAIMED); 2860 } 2861 2862 2863 /* 2864 * Module Loading Data & Entry Points 2865 */ 2866 DDI_DEFINE_STREAM_OPS(ipw2100_devops, nulldev, nulldev, ipw2100_attach, 2867 ipw2100_detach, nodev, NULL, D_MP, NULL, ipw2100_quiesce); 2868 2869 static struct modldrv ipw2100_modldrv = { 2870 &mod_driverops, 2871 ipw2100_ident, 2872 &ipw2100_devops 2873 }; 2874 2875 static struct modlinkage ipw2100_modlinkage = { 2876 MODREV_1, 2877 &ipw2100_modldrv, 2878 NULL 2879 }; 2880 2881 int 2882 _init(void) 2883 { 2884 int status; 2885 2886 status = ddi_soft_state_init(&ipw2100_ssp, 2887 sizeof (struct ipw2100_softc), 1); 2888 if (status != DDI_SUCCESS) 2889 return (status); 2890 2891 mac_init_ops(&ipw2100_devops, IPW2100_DRV_NAME); 2892 status = mod_install(&ipw2100_modlinkage); 2893 if (status != DDI_SUCCESS) { 2894 mac_fini_ops(&ipw2100_devops); 2895 ddi_soft_state_fini(&ipw2100_ssp); 2896 } 2897 2898 return (status); 2899 } 2900 2901 int 2902 _fini(void) 2903 { 2904 int status; 2905 2906 status = mod_remove(&ipw2100_modlinkage); 2907 if (status == DDI_SUCCESS) { 2908 mac_fini_ops(&ipw2100_devops); 2909 ddi_soft_state_fini(&ipw2100_ssp); 2910 } 2911 2912 return (status); 2913 } 2914 2915 int 2916 _info(struct modinfo *mip) 2917 { 2918 return (mod_info(&ipw2100_modlinkage, mip)); 2919 } 2920