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 clk = drv_usectohz(1000000); /* 1 second */ 1075 mutex_enter(&sc->sc_ilock); 1076 while (sc->sc_done == 0) { 1077 /* 1078 * pending for the response 1079 */ 1080 if (cv_reltimedwait(&sc->sc_cmd_cond, &sc->sc_ilock, 1081 clk, TR_CLOCK_TICK) < 0) 1082 break; 1083 } 1084 mutex_exit(&sc->sc_ilock); 1085 1086 IPW2100_DBG(IPW2100_DBG_RING, (sc->sc_dip, CE_CONT, 1087 "ipw2100_cmd(): cmd-done=%s\n", sc->sc_done ? "yes" : "no")); 1088 1089 if (sc->sc_done == 0) 1090 return (DDI_FAILURE); 1091 1092 return (DDI_SUCCESS); 1093 } 1094 1095 int 1096 ipw2100_init(struct ipw2100_softc *sc) 1097 { 1098 int err; 1099 1100 IPW2100_DBG(IPW2100_DBG_INIT, (sc->sc_dip, CE_CONT, 1101 "ipw2100_init(): enter\n")); 1102 1103 /* 1104 * no firmware is available, return fail directly 1105 */ 1106 if (!(sc->sc_flags & IPW2100_FLAG_FW_CACHED)) { 1107 IPW2100_WARN((sc->sc_dip, CE_WARN, 1108 "ipw2100_init(): no firmware is available\n")); 1109 return (DDI_FAILURE); 1110 } 1111 1112 ipw2100_stop(sc); 1113 1114 err = ipw2100_chip_reset(sc); 1115 if (err != DDI_SUCCESS) { 1116 IPW2100_WARN((sc->sc_dip, CE_WARN, 1117 "ipw2100_init(): could not reset adapter\n")); 1118 goto fail; 1119 } 1120 1121 /* 1122 * load microcode 1123 */ 1124 IPW2100_DBG(IPW2100_DBG_INIT, (sc->sc_dip, CE_CONT, 1125 "ipw2100_init(): loading microcode\n")); 1126 err = ipw2100_load_uc(sc); 1127 if (err != DDI_SUCCESS) { 1128 IPW2100_WARN((sc->sc_dip, CE_WARN, 1129 "ipw2100_init(): could not load microcode, try again\n")); 1130 goto fail; 1131 } 1132 1133 ipw2100_master_stop(sc); 1134 1135 ipw2100_ring_hwsetup(sc); 1136 1137 /* 1138 * load firmware 1139 */ 1140 IPW2100_DBG(IPW2100_DBG_INIT, (sc->sc_dip, CE_CONT, 1141 "ipw2100_init(): loading firmware\n")); 1142 err = ipw2100_load_fw(sc); 1143 if (err != DDI_SUCCESS) { 1144 IPW2100_WARN((sc->sc_dip, CE_WARN, 1145 "ipw2100_init(): could not load firmware, try again\n")); 1146 goto fail; 1147 } 1148 1149 /* 1150 * initialize tables 1151 */ 1152 ipw2100_tables_init(sc); 1153 ipw2100_table1_put32(sc, IPW2100_INFO_LOCK, 0); 1154 1155 /* 1156 * Hardware will be enabled after configuration 1157 */ 1158 err = ipw2100_config(sc); 1159 if (err != DDI_SUCCESS) { 1160 IPW2100_WARN((sc->sc_dip, CE_WARN, 1161 "ipw2100_init(): device configuration failed\n")); 1162 goto fail; 1163 } 1164 1165 delay(drv_usectohz(delay_config_stable)); 1166 1167 return (DDI_SUCCESS); 1168 1169 fail: 1170 ipw2100_stop(sc); 1171 1172 return (err); 1173 } 1174 1175 /* 1176 * get hardware configurations from EEPROM embedded within chip 1177 */ 1178 static void 1179 ipw2100_hwconf_get(struct ipw2100_softc *sc) 1180 { 1181 int i; 1182 uint16_t val; 1183 1184 /* 1185 * MAC address 1186 */ 1187 i = 0; 1188 val = ipw2100_rom_get16(sc, IPW2100_ROM_MAC + 0); 1189 sc->sc_macaddr[i++] = val >> 8; 1190 sc->sc_macaddr[i++] = val & 0xff; 1191 val = ipw2100_rom_get16(sc, IPW2100_ROM_MAC + 1); 1192 sc->sc_macaddr[i++] = val >> 8; 1193 sc->sc_macaddr[i++] = val & 0xff; 1194 val = ipw2100_rom_get16(sc, IPW2100_ROM_MAC + 2); 1195 sc->sc_macaddr[i++] = val >> 8; 1196 sc->sc_macaddr[i++] = val & 0xff; 1197 1198 /* 1199 * formatted MAC address string 1200 */ 1201 (void) snprintf(sc->sc_macstr, sizeof (sc->sc_macstr), 1202 "%02x:%02x:%02x:%02x:%02x:%02x", 1203 sc->sc_macaddr[0], sc->sc_macaddr[1], 1204 sc->sc_macaddr[2], sc->sc_macaddr[3], 1205 sc->sc_macaddr[4], sc->sc_macaddr[5]); 1206 1207 /* 1208 * channel mask 1209 */ 1210 val = ipw2100_rom_get16(sc, IPW2100_ROM_CHANNEL_LIST); 1211 if (val == 0) 1212 val = 0x7ff; 1213 sc->sc_chmask = val << 1; 1214 IPW2100_DBG(IPW2100_DBG_HWCAP, (sc->sc_dip, CE_CONT, 1215 "ipw2100_hwconf_get(): channel-mask=0x%08x\n", sc->sc_chmask)); 1216 1217 /* 1218 * radio switch 1219 */ 1220 val = ipw2100_rom_get16(sc, IPW2100_ROM_RADIO); 1221 if (val & 0x08) 1222 sc->sc_flags |= IPW2100_FLAG_HAS_RADIO_SWITCH; 1223 1224 IPW2100_DBG(IPW2100_DBG_HWCAP, (sc->sc_dip, CE_CONT, 1225 "ipw2100_hwconf_get(): has-radio-switch=%s(%u)\n", 1226 (sc->sc_flags & IPW2100_FLAG_HAS_RADIO_SWITCH)? "yes" : "no", 1227 val)); 1228 } 1229 1230 /* 1231 * all ipw2100 interrupts will be masked by this routine 1232 */ 1233 static void 1234 ipw2100_master_stop(struct ipw2100_softc *sc) 1235 { 1236 uint32_t tmp; 1237 int ntries; 1238 1239 /* 1240 * disable interrupts 1241 */ 1242 ipw2100_csr_put32(sc, IPW2100_CSR_INTR_MASK, 0); 1243 1244 ipw2100_csr_put32(sc, IPW2100_CSR_RST, IPW2100_RST_STOP_MASTER); 1245 for (ntries = 0; ntries < 50; ntries++) { 1246 if (ipw2100_csr_get32(sc, IPW2100_CSR_RST) 1247 & IPW2100_RST_MASTER_DISABLED) 1248 break; 1249 drv_usecwait(10); 1250 } 1251 if (ntries == 50 && !(sc->sc_flags & IPW2100_FLAG_QUIESCED)) 1252 IPW2100_WARN((sc->sc_dip, CE_WARN, 1253 "ipw2100_master_stop(): timeout when stop master\n")); 1254 1255 tmp = ipw2100_csr_get32(sc, IPW2100_CSR_RST); 1256 ipw2100_csr_put32(sc, IPW2100_CSR_RST, 1257 tmp | IPW2100_RST_PRINCETON_RESET); 1258 1259 sc->sc_flags &= ~IPW2100_FLAG_FW_INITED; 1260 } 1261 1262 /* 1263 * all ipw2100 interrupts will be masked by this routine 1264 */ 1265 static int 1266 ipw2100_chip_reset(struct ipw2100_softc *sc) 1267 { 1268 int ntries; 1269 uint32_t tmp; 1270 1271 ipw2100_master_stop(sc); 1272 1273 /* 1274 * move adatper to DO state 1275 */ 1276 tmp = ipw2100_csr_get32(sc, IPW2100_CSR_CTL); 1277 ipw2100_csr_put32(sc, IPW2100_CSR_CTL, tmp | IPW2100_CTL_INIT); 1278 1279 /* 1280 * wait for clock stabilization 1281 */ 1282 for (ntries = 0; ntries < 1000; ntries++) { 1283 if (ipw2100_csr_get32(sc, IPW2100_CSR_CTL) 1284 & IPW2100_CTL_CLOCK_READY) 1285 break; 1286 drv_usecwait(200); 1287 } 1288 if (ntries == 1000) 1289 return (DDI_FAILURE); 1290 1291 tmp = ipw2100_csr_get32(sc, IPW2100_CSR_RST); 1292 ipw2100_csr_put32(sc, IPW2100_CSR_RST, tmp | IPW2100_RST_SW_RESET); 1293 1294 drv_usecwait(10); 1295 1296 tmp = ipw2100_csr_get32(sc, IPW2100_CSR_CTL); 1297 ipw2100_csr_put32(sc, IPW2100_CSR_CTL, tmp | IPW2100_CTL_INIT); 1298 1299 return (DDI_SUCCESS); 1300 } 1301 1302 /* 1303 * get the radio status from IPW_CSR_IO, invoked by wificonfig/dladm 1304 */ 1305 int 1306 ipw2100_get_radio(struct ipw2100_softc *sc) 1307 { 1308 if (ipw2100_csr_get32(sc, IPW2100_CSR_IO) & IPW2100_IO_RADIO_DISABLED) 1309 return (0); 1310 else 1311 return (1); 1312 1313 } 1314 /* 1315 * This function is used to get the statistic, invoked by wificonfig/dladm 1316 */ 1317 void 1318 ipw2100_get_statistics(struct ipw2100_softc *sc) 1319 { 1320 struct ieee80211com *ic = &sc->sc_ic; 1321 uint32_t addr, size, i; 1322 uint32_t atbl[256], *datatbl; 1323 1324 datatbl = atbl; 1325 1326 if (!(sc->sc_flags & IPW2100_FLAG_FW_INITED)) { 1327 IPW2100_DBG(IPW2100_DBG_STATISTIC, (sc->sc_dip, CE_CONT, 1328 "ipw2100_get_statistic(): fw doesn't download yet.")); 1329 return; 1330 } 1331 1332 ipw2100_csr_put32(sc, IPW2100_CSR_AUTOINC_ADDR, sc->sc_table1_base); 1333 1334 size = ipw2100_csr_get32(sc, IPW2100_CSR_AUTOINC_DATA); 1335 atbl[0] = size; 1336 for (i = 1, ++datatbl; i < size; i++, datatbl++) { 1337 addr = ipw2100_csr_get32(sc, IPW2100_CSR_AUTOINC_DATA); 1338 *datatbl = ipw2100_imem_get32(sc, addr); 1339 } 1340 1341 /* 1342 * To retrieve the statistic information into proper places. There are 1343 * lot of information. 1344 */ 1345 IPW2100_DBG(IPW2100_DBG_STATISTIC, (sc->sc_dip, CE_CONT, 1346 "ipw2100_get_statistic(): \n" 1347 "operating mode = %u\n" 1348 "type of authentification= %u\n" 1349 "average RSSI= %u\n" 1350 "current channel = %d\n", 1351 atbl[191], atbl[199], atbl[173], atbl[189])); 1352 /* WIFI_STAT_TX_FRAGS */ 1353 ic->ic_stats.is_tx_frags = (uint32_t)atbl[2]; 1354 /* WIFI_STAT_MCAST_TX = (all frame - unicast frame) */ 1355 ic->ic_stats.is_tx_mcast = (uint32_t)atbl[2] - (uint32_t)atbl[3]; 1356 /* WIFI_STAT_TX_RETRANS */ 1357 ic->ic_stats.is_tx_retries = (uint32_t)atbl[42]; 1358 /* WIFI_STAT_TX_FAILED */ 1359 ic->ic_stats.is_tx_failed = (uint32_t)atbl[51]; 1360 /* MAC_STAT_OBYTES */ 1361 ic->ic_stats.is_tx_bytes = (uint32_t)atbl[41]; 1362 /* WIFI_STAT_RX_FRAGS */ 1363 ic->ic_stats.is_rx_frags = (uint32_t)atbl[61]; 1364 /* WIFI_STAT_MCAST_RX */ 1365 ic->ic_stats.is_rx_mcast = (uint32_t)atbl[71]; 1366 /* MAC_STAT_IBYTES */ 1367 ic->ic_stats.is_rx_bytes = (uint32_t)atbl[101]; 1368 /* WIFI_STAT_ACK_FAILURE */ 1369 ic->ic_stats.is_ack_failure = (uint32_t)atbl[59]; 1370 /* WIFI_STAT_RTS_SUCCESS */ 1371 ic->ic_stats.is_rts_success = (uint32_t)atbl[22]; 1372 } 1373 1374 /* 1375 * dma region alloc 1376 */ 1377 static int 1378 ipw2100_dma_region_alloc(struct ipw2100_softc *sc, 1379 struct dma_region *dr, size_t size, uint_t dir, uint_t flags) 1380 { 1381 dev_info_t *dip = sc->sc_dip; 1382 int err; 1383 1384 IPW2100_DBG(IPW2100_DBG_DMA, (dip, CE_CONT, 1385 "ipw2100_dma_region_alloc() name=%s size=%u\n", 1386 dr->dr_name, size)); 1387 1388 err = ddi_dma_alloc_handle(dip, &ipw2100_dma_attr, DDI_DMA_SLEEP, NULL, 1389 &dr->dr_hnd); 1390 if (err != DDI_SUCCESS) { 1391 IPW2100_DBG(IPW2100_DBG_DMA, (dip, CE_CONT, 1392 "ipw2100_dma_region_alloc(): " 1393 "ddi_dma_alloc_handle() failed\n")); 1394 goto fail0; 1395 } 1396 1397 err = ddi_dma_mem_alloc(dr->dr_hnd, size, &ipw2100_dma_accattr, 1398 flags, DDI_DMA_SLEEP, NULL, &dr->dr_base, 1399 &dr->dr_size, &dr->dr_acc); 1400 if (err != DDI_SUCCESS) { 1401 IPW2100_DBG(IPW2100_DBG_DMA, (dip, CE_CONT, 1402 "ipw2100_dma_region_alloc(): " 1403 "ddi_dma_mem_alloc() failed\n")); 1404 goto fail1; 1405 } 1406 1407 err = ddi_dma_addr_bind_handle(dr->dr_hnd, NULL, 1408 dr->dr_base, dr->dr_size, dir | flags, DDI_DMA_SLEEP, NULL, 1409 &dr->dr_cookie, &dr->dr_ccnt); 1410 if (err != DDI_DMA_MAPPED) { 1411 IPW2100_DBG(IPW2100_DBG_DMA, (dip, CE_CONT, 1412 "ipw2100_dma_region_alloc(): " 1413 "ddi_dma_addr_bind_handle() failed\n")); 1414 goto fail2; 1415 } 1416 1417 if (dr->dr_ccnt != 1) { 1418 err = DDI_FAILURE; 1419 goto fail3; 1420 } 1421 dr->dr_pbase = dr->dr_cookie.dmac_address; 1422 1423 IPW2100_DBG(IPW2100_DBG_DMA, (dip, CE_CONT, 1424 "ipw2100_dma_region_alloc(): get physical-base=0x%08x\n", 1425 dr->dr_pbase)); 1426 1427 return (DDI_SUCCESS); 1428 1429 fail3: 1430 (void) ddi_dma_unbind_handle(dr->dr_hnd); 1431 fail2: 1432 ddi_dma_mem_free(&dr->dr_acc); 1433 fail1: 1434 ddi_dma_free_handle(&dr->dr_hnd); 1435 fail0: 1436 return (err); 1437 } 1438 1439 static void 1440 ipw2100_dma_region_free(struct dma_region *dr) 1441 { 1442 (void) ddi_dma_unbind_handle(dr->dr_hnd); 1443 ddi_dma_mem_free(&dr->dr_acc); 1444 ddi_dma_free_handle(&dr->dr_hnd); 1445 } 1446 1447 static int 1448 ipw2100_ring_alloc(struct ipw2100_softc *sc) 1449 { 1450 int err, i; 1451 1452 /* 1453 * tx ring 1454 */ 1455 sc->sc_dma_txbd.dr_name = "ipw2100-tx-ring-bd"; 1456 err = ipw2100_dma_region_alloc(sc, &sc->sc_dma_txbd, 1457 IPW2100_TXBD_SIZE, DDI_DMA_WRITE, DDI_DMA_CONSISTENT); 1458 if (err != DDI_SUCCESS) 1459 goto fail0; 1460 /* 1461 * tx bufs 1462 */ 1463 for (i = 0; i < IPW2100_NUM_TXBUF; i++) { 1464 sc->sc_dma_txbufs[i].dr_name = "ipw2100-tx-buf"; 1465 err = ipw2100_dma_region_alloc(sc, &sc->sc_dma_txbufs[i], 1466 IPW2100_TXBUF_SIZE, DDI_DMA_WRITE, DDI_DMA_STREAMING); 1467 if (err != DDI_SUCCESS) { 1468 while (i > 0) { 1469 i--; 1470 ipw2100_dma_region_free(&sc->sc_dma_txbufs[i]); 1471 } 1472 goto fail1; 1473 } 1474 } 1475 /* 1476 * rx ring 1477 */ 1478 sc->sc_dma_rxbd.dr_name = "ipw2100-rx-ring-bd"; 1479 err = ipw2100_dma_region_alloc(sc, &sc->sc_dma_rxbd, 1480 IPW2100_RXBD_SIZE, DDI_DMA_WRITE, DDI_DMA_CONSISTENT); 1481 if (err != DDI_SUCCESS) 1482 goto fail2; 1483 /* 1484 * rx bufs 1485 */ 1486 for (i = 0; i < IPW2100_NUM_RXBUF; i++) { 1487 sc->sc_dma_rxbufs[i].dr_name = "ipw2100-rx-buf"; 1488 err = ipw2100_dma_region_alloc(sc, &sc->sc_dma_rxbufs[i], 1489 IPW2100_RXBUF_SIZE, DDI_DMA_READ, DDI_DMA_STREAMING); 1490 if (err != DDI_SUCCESS) { 1491 while (i > 0) { 1492 i--; 1493 ipw2100_dma_region_free(&sc->sc_dma_rxbufs[i]); 1494 } 1495 goto fail3; 1496 } 1497 } 1498 /* 1499 * status 1500 */ 1501 sc->sc_dma_status.dr_name = "ipw2100-rx-status"; 1502 err = ipw2100_dma_region_alloc(sc, &sc->sc_dma_status, 1503 IPW2100_STATUS_SIZE, DDI_DMA_READ, DDI_DMA_CONSISTENT); 1504 if (err != DDI_SUCCESS) 1505 goto fail4; 1506 /* 1507 * command 1508 */ 1509 sc->sc_dma_cmd.dr_name = "ipw2100-cmd"; 1510 err = ipw2100_dma_region_alloc(sc, &sc->sc_dma_cmd, IPW2100_CMD_SIZE, 1511 DDI_DMA_WRITE, DDI_DMA_CONSISTENT); 1512 if (err != DDI_SUCCESS) 1513 goto fail5; 1514 1515 return (DDI_SUCCESS); 1516 1517 fail5: 1518 ipw2100_dma_region_free(&sc->sc_dma_status); 1519 fail4: 1520 for (i = 0; i < IPW2100_NUM_RXBUF; i++) 1521 ipw2100_dma_region_free(&sc->sc_dma_rxbufs[i]); 1522 fail3: 1523 ipw2100_dma_region_free(&sc->sc_dma_rxbd); 1524 fail2: 1525 for (i = 0; i < IPW2100_NUM_TXBUF; i++) 1526 ipw2100_dma_region_free(&sc->sc_dma_txbufs[i]); 1527 fail1: 1528 ipw2100_dma_region_free(&sc->sc_dma_txbd); 1529 fail0: 1530 return (err); 1531 } 1532 1533 static void 1534 ipw2100_ring_free(struct ipw2100_softc *sc) 1535 { 1536 int i; 1537 1538 /* 1539 * tx ring 1540 */ 1541 ipw2100_dma_region_free(&sc->sc_dma_txbd); 1542 /* 1543 * tx buf 1544 */ 1545 for (i = 0; i < IPW2100_NUM_TXBUF; i++) 1546 ipw2100_dma_region_free(&sc->sc_dma_txbufs[i]); 1547 /* 1548 * rx ring 1549 */ 1550 ipw2100_dma_region_free(&sc->sc_dma_rxbd); 1551 /* 1552 * rx buf 1553 */ 1554 for (i = 0; i < IPW2100_NUM_RXBUF; i++) 1555 ipw2100_dma_region_free(&sc->sc_dma_rxbufs[i]); 1556 /* 1557 * status 1558 */ 1559 ipw2100_dma_region_free(&sc->sc_dma_status); 1560 /* 1561 * command 1562 */ 1563 ipw2100_dma_region_free(&sc->sc_dma_cmd); 1564 } 1565 1566 static void 1567 ipw2100_ring_reset(struct ipw2100_softc *sc) 1568 { 1569 int i; 1570 1571 /* 1572 * tx ring 1573 */ 1574 sc->sc_tx_cur = 0; 1575 sc->sc_tx_free = IPW2100_NUM_TXBD; 1576 sc->sc_txbd = (struct ipw2100_bd *)sc->sc_dma_txbd.dr_base; 1577 for (i = 0; i < IPW2100_NUM_TXBUF; i++) 1578 sc->sc_txbufs[i] = 1579 (struct ipw2100_txb *)sc->sc_dma_txbufs[i].dr_base; 1580 /* 1581 * rx ring 1582 */ 1583 sc->sc_rx_cur = 0; 1584 sc->sc_rx_free = IPW2100_NUM_RXBD; 1585 sc->sc_status = (struct ipw2100_status *)sc->sc_dma_status.dr_base; 1586 sc->sc_rxbd = (struct ipw2100_bd *)sc->sc_dma_rxbd.dr_base; 1587 for (i = 0; i < IPW2100_NUM_RXBUF; i++) { 1588 sc->sc_rxbufs[i] = 1589 (struct ipw2100_rxb *)sc->sc_dma_rxbufs[i].dr_base; 1590 /* 1591 * initialize Rx buffer descriptors, both host and device 1592 */ 1593 sc->sc_rxbd[i].phyaddr = LE_32(sc->sc_dma_rxbufs[i].dr_pbase); 1594 sc->sc_rxbd[i].len = LE_32(sc->sc_dma_rxbufs[i].dr_size); 1595 sc->sc_rxbd[i].flags = 0; 1596 sc->sc_rxbd[i].nfrag = 1; 1597 } 1598 /* 1599 * command 1600 */ 1601 sc->sc_cmd = (struct ipw2100_cmd *)sc->sc_dma_cmd.dr_base; 1602 } 1603 1604 /* 1605 * tx, rx rings and command initialization 1606 */ 1607 static int 1608 ipw2100_ring_init(struct ipw2100_softc *sc) 1609 { 1610 int err; 1611 1612 err = ipw2100_ring_alloc(sc); 1613 if (err != DDI_SUCCESS) 1614 return (err); 1615 1616 ipw2100_ring_reset(sc); 1617 1618 return (DDI_SUCCESS); 1619 } 1620 1621 static void 1622 ipw2100_ring_hwsetup(struct ipw2100_softc *sc) 1623 { 1624 ipw2100_ring_reset(sc); 1625 /* 1626 * tx ring 1627 */ 1628 ipw2100_csr_put32(sc, IPW2100_CSR_TX_BD_BASE, sc->sc_dma_txbd.dr_pbase); 1629 ipw2100_csr_put32(sc, IPW2100_CSR_TX_BD_SIZE, IPW2100_NUM_TXBD); 1630 /* 1631 * no new packet to transmit, tx-rd-index == tx-wr-index 1632 */ 1633 ipw2100_csr_put32(sc, IPW2100_CSR_TX_READ_INDEX, sc->sc_tx_cur); 1634 ipw2100_csr_put32(sc, IPW2100_CSR_TX_WRITE_INDEX, sc->sc_tx_cur); 1635 /* 1636 * rx ring 1637 */ 1638 ipw2100_csr_put32(sc, IPW2100_CSR_RX_BD_BASE, sc->sc_dma_rxbd.dr_pbase); 1639 ipw2100_csr_put32(sc, IPW2100_CSR_RX_BD_SIZE, IPW2100_NUM_RXBD); 1640 /* 1641 * all rx buffer are empty, rx-rd-index == 0 && rx-wr-index == N-1 1642 */ 1643 IPW2100_DBG(IPW2100_DBG_RING, (sc->sc_dip, CE_CONT, 1644 "ipw2100_ring_hwsetup(): rx-cur=%u, backward=%u\n", 1645 sc->sc_rx_cur, RING_BACKWARD(sc->sc_rx_cur, 1, IPW2100_NUM_RXBD))); 1646 ipw2100_csr_put32(sc, IPW2100_CSR_RX_READ_INDEX, sc->sc_rx_cur); 1647 ipw2100_csr_put32(sc, IPW2100_CSR_RX_WRITE_INDEX, 1648 RING_BACKWARD(sc->sc_rx_cur, 1, IPW2100_NUM_RXBD)); 1649 /* 1650 * status 1651 */ 1652 ipw2100_csr_put32(sc, IPW2100_CSR_RX_STATUS_BASE, 1653 sc->sc_dma_status.dr_pbase); 1654 } 1655 1656 /* 1657 * ieee80211_new_state() is not be used, since the hardware can handle the 1658 * state transfer. Here, we just keep the status of the hardware notification 1659 * result. 1660 */ 1661 /* ARGSUSED */ 1662 static int 1663 ipw2100_newstate(struct ieee80211com *ic, enum ieee80211_state state, int arg) 1664 { 1665 struct ipw2100_softc *sc = (struct ipw2100_softc *)ic; 1666 struct ieee80211_node *in; 1667 uint8_t macaddr[IEEE80211_ADDR_LEN]; 1668 uint32_t len; 1669 wifi_data_t wd = { 0 }; 1670 1671 IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT, 1672 "ipw2100_newstate(): %s -> %s\n", 1673 ieee80211_state_name[ic->ic_state], ieee80211_state_name[state])); 1674 1675 switch (state) { 1676 case IEEE80211_S_RUN: 1677 /* 1678 * we only need to use BSSID as to find the node 1679 */ 1680 drv_usecwait(200); /* firmware needs a short delay here */ 1681 len = IEEE80211_ADDR_LEN; 1682 (void) ipw2100_table2_getbuf(sc, IPW2100_INFO_CURRENT_BSSID, 1683 macaddr, &len); 1684 1685 in = ieee80211_find_node(&ic->ic_scan, macaddr); 1686 if (in == NULL) 1687 break; 1688 1689 (void) ieee80211_sta_join(ic, in); 1690 ieee80211_node_authorize(in); 1691 1692 /* 1693 * We can send data now; update the fastpath with our 1694 * current associated BSSID. 1695 */ 1696 if (ic->ic_flags & IEEE80211_F_PRIVACY) 1697 wd.wd_secalloc = WIFI_SEC_WEP; 1698 else 1699 wd.wd_secalloc = WIFI_SEC_NONE; 1700 wd.wd_opmode = ic->ic_opmode; 1701 IEEE80211_ADDR_COPY(wd.wd_bssid, ic->ic_bss->in_bssid); 1702 (void) mac_pdata_update(ic->ic_mach, &wd, sizeof (wd)); 1703 1704 break; 1705 1706 case IEEE80211_S_INIT: 1707 case IEEE80211_S_SCAN: 1708 case IEEE80211_S_AUTH: 1709 case IEEE80211_S_ASSOC: 1710 break; 1711 } 1712 1713 /* 1714 * notify to update the link 1715 */ 1716 if ((ic->ic_state != IEEE80211_S_RUN) && (state == IEEE80211_S_RUN)) { 1717 /* 1718 * previously disconnected and now connected 1719 */ 1720 sc->sc_linkstate = LINK_STATE_UP; 1721 sc->sc_flags |= IPW2100_FLAG_LINK_CHANGE; 1722 } else if ((ic->ic_state == IEEE80211_S_RUN) && 1723 (state != IEEE80211_S_RUN)) { 1724 /* 1725 * previously connected andd now disconnected 1726 */ 1727 sc->sc_linkstate = LINK_STATE_DOWN; 1728 sc->sc_flags |= IPW2100_FLAG_LINK_CHANGE; 1729 } 1730 1731 ic->ic_state = state; 1732 return (DDI_SUCCESS); 1733 } 1734 1735 /* 1736 * GLD operations 1737 */ 1738 /* ARGSUSED */ 1739 static int 1740 ipw2100_m_stat(void *arg, uint_t stat, uint64_t *val) 1741 { 1742 ieee80211com_t *ic = (ieee80211com_t *)arg; 1743 IPW2100_DBG(IPW2100_DBG_GLD, (((struct ipw2100_softc *)arg)->sc_dip, 1744 CE_CONT, 1745 "ipw2100_m_stat(): enter\n")); 1746 /* 1747 * some of below statistic data are from hardware, some from net80211 1748 */ 1749 switch (stat) { 1750 case MAC_STAT_RBYTES: 1751 *val = ic->ic_stats.is_rx_bytes; 1752 break; 1753 case MAC_STAT_IPACKETS: 1754 *val = ic->ic_stats.is_rx_frags; 1755 break; 1756 case MAC_STAT_OBYTES: 1757 *val = ic->ic_stats.is_tx_bytes; 1758 break; 1759 case MAC_STAT_OPACKETS: 1760 *val = ic->ic_stats.is_tx_frags; 1761 break; 1762 /* 1763 * Get below from hardware statistic, retrieve net80211 value once 1s 1764 */ 1765 case WIFI_STAT_TX_FRAGS: 1766 case WIFI_STAT_MCAST_TX: 1767 case WIFI_STAT_TX_FAILED: 1768 case WIFI_STAT_TX_RETRANS: 1769 case WIFI_STAT_RTS_SUCCESS: 1770 case WIFI_STAT_ACK_FAILURE: 1771 case WIFI_STAT_RX_FRAGS: 1772 case WIFI_STAT_MCAST_RX: 1773 /* 1774 * Get blow information from net80211 1775 */ 1776 case WIFI_STAT_RTS_FAILURE: 1777 case WIFI_STAT_RX_DUPS: 1778 case WIFI_STAT_FCS_ERRORS: 1779 case WIFI_STAT_WEP_ERRORS: 1780 return (ieee80211_stat(ic, stat, val)); 1781 /* 1782 * need be supported in the future 1783 */ 1784 case MAC_STAT_IFSPEED: 1785 case MAC_STAT_NOXMTBUF: 1786 case MAC_STAT_IERRORS: 1787 case MAC_STAT_OERRORS: 1788 default: 1789 return (ENOTSUP); 1790 } 1791 return (0); 1792 } 1793 1794 /* ARGSUSED */ 1795 static int 1796 ipw2100_m_multicst(void *arg, boolean_t add, const uint8_t *mca) 1797 { 1798 /* not supported */ 1799 IPW2100_DBG(IPW2100_DBG_GLD, (((struct ipw2100_softc *)arg)->sc_dip, 1800 CE_CONT, 1801 "ipw2100_m_multicst(): enter\n")); 1802 1803 return (0); 1804 } 1805 1806 /* 1807 * This thread function is used to handle the fatal error. 1808 */ 1809 static void 1810 ipw2100_thread(struct ipw2100_softc *sc) 1811 { 1812 struct ieee80211com *ic = &sc->sc_ic; 1813 int32_t nlstate; 1814 int stat_cnt = 0; 1815 1816 IPW2100_DBG(IPW2100_DBG_SOFTINT, (sc->sc_dip, CE_CONT, 1817 "ipw2100_thread(): into ipw2100 thread--> %d\n", 1818 sc->sc_linkstate)); 1819 1820 mutex_enter(&sc->sc_mflock); 1821 1822 while (sc->sc_mfthread_switch) { 1823 /* 1824 * notify the link state 1825 */ 1826 if (ic->ic_mach && (sc->sc_flags & IPW2100_FLAG_LINK_CHANGE)) { 1827 IPW2100_DBG(IPW2100_DBG_SOFTINT, (sc->sc_dip, CE_CONT, 1828 "ipw2100_thread(): link status --> %d\n", 1829 sc->sc_linkstate)); 1830 1831 sc->sc_flags &= ~IPW2100_FLAG_LINK_CHANGE; 1832 nlstate = sc->sc_linkstate; 1833 1834 mutex_exit(&sc->sc_mflock); 1835 mac_link_update(ic->ic_mach, nlstate); 1836 mutex_enter(&sc->sc_mflock); 1837 } 1838 1839 /* 1840 * recovery interrupt fatal error 1841 */ 1842 if (ic->ic_mach && 1843 (sc->sc_flags & IPW2100_FLAG_HW_ERR_RECOVER)) { 1844 1845 IPW2100_DBG(IPW2100_DBG_FATAL, (sc->sc_dip, CE_CONT, 1846 "try to recover fatal hw error\n")); 1847 sc->sc_flags &= ~IPW2100_FLAG_HW_ERR_RECOVER; 1848 1849 mutex_exit(&sc->sc_mflock); 1850 (void) ipw2100_init(sc); /* Force stat machine */ 1851 delay(drv_usectohz(delay_fatal_recover)); 1852 mutex_enter(&sc->sc_mflock); 1853 } 1854 1855 /* 1856 * get statistic, the value will be retrieved by m_stat 1857 */ 1858 if (stat_cnt == 10) { 1859 stat_cnt = 0; /* re-start */ 1860 1861 mutex_exit(&sc->sc_mflock); 1862 ipw2100_get_statistics(sc); 1863 mutex_enter(&sc->sc_mflock); 1864 } else 1865 stat_cnt++; /* until 1s */ 1866 1867 mutex_exit(&sc->sc_mflock); 1868 delay(drv_usectohz(delay_aux_thread)); 1869 mutex_enter(&sc->sc_mflock); 1870 } 1871 sc->sc_mf_thread = NULL; 1872 cv_broadcast(&sc->sc_mfthread_cv); 1873 mutex_exit(&sc->sc_mflock); 1874 } 1875 1876 static int 1877 ipw2100_m_start(void *arg) 1878 { 1879 struct ipw2100_softc *sc = (struct ipw2100_softc *)arg; 1880 1881 IPW2100_DBG(IPW2100_DBG_GLD, (sc->sc_dip, CE_CONT, 1882 "ipw2100_m_start(): enter\n")); 1883 1884 /* 1885 * initialize ipw2100 hardware 1886 */ 1887 (void) ipw2100_init(sc); 1888 1889 sc->sc_flags |= IPW2100_FLAG_RUNNING; 1890 /* 1891 * fix KCF bug. - workaround, need to fix it in net80211 1892 */ 1893 (void) crypto_mech2id(SUN_CKM_RC4); 1894 1895 return (0); 1896 } 1897 1898 static void 1899 ipw2100_m_stop(void *arg) 1900 { 1901 struct ipw2100_softc *sc = (struct ipw2100_softc *)arg; 1902 1903 IPW2100_DBG(IPW2100_DBG_GLD, (sc->sc_dip, CE_CONT, 1904 "ipw2100_m_stop(): enter\n")); 1905 1906 ipw2100_stop(sc); 1907 1908 sc->sc_flags &= ~IPW2100_FLAG_RUNNING; 1909 } 1910 1911 static int 1912 ipw2100_m_unicst(void *arg, const uint8_t *macaddr) 1913 { 1914 struct ipw2100_softc *sc = (struct ipw2100_softc *)arg; 1915 struct ieee80211com *ic = &sc->sc_ic; 1916 int err; 1917 1918 IPW2100_DBG(IPW2100_DBG_GLD, (sc->sc_dip, CE_CONT, 1919 "ipw2100_m_unicst(): enter\n")); 1920 1921 IPW2100_DBG(IPW2100_DBG_GLD, (sc->sc_dip, CE_CONT, 1922 "ipw2100_m_unicst(): GLD setting MAC address to " 1923 "%02x:%02x:%02x:%02x:%02x:%02x\n", 1924 macaddr[0], macaddr[1], macaddr[2], 1925 macaddr[3], macaddr[4], macaddr[5])); 1926 1927 if (!IEEE80211_ADDR_EQ(ic->ic_macaddr, macaddr)) { 1928 IEEE80211_ADDR_COPY(ic->ic_macaddr, macaddr); 1929 1930 if (sc->sc_flags & IPW2100_FLAG_RUNNING) { 1931 err = ipw2100_config(sc); 1932 if (err != DDI_SUCCESS) { 1933 IPW2100_WARN((sc->sc_dip, CE_WARN, 1934 "ipw2100_m_unicst(): " 1935 "device configuration failed\n")); 1936 goto fail; 1937 } 1938 } 1939 } 1940 1941 return (0); 1942 fail: 1943 return (EIO); 1944 } 1945 1946 static int 1947 ipw2100_m_promisc(void *arg, boolean_t on) 1948 { 1949 struct ipw2100_softc *sc = (struct ipw2100_softc *)arg; 1950 int recfg, err; 1951 1952 IPW2100_DBG(IPW2100_DBG_GLD, (sc->sc_dip, CE_CONT, 1953 "ipw2100_m_promisc(): enter. " 1954 "GLD setting promiscuous mode - %d\n", on)); 1955 1956 recfg = 0; 1957 if (on) 1958 if (!(sc->if_flags & IFF_PROMISC)) { 1959 sc->if_flags |= IFF_PROMISC; 1960 recfg = 1; 1961 } 1962 else 1963 if (sc->if_flags & IFF_PROMISC) { 1964 sc->if_flags &= ~IFF_PROMISC; 1965 recfg = 1; 1966 } 1967 1968 if (recfg && (sc->sc_flags & IPW2100_FLAG_RUNNING)) { 1969 err = ipw2100_config(sc); 1970 if (err != DDI_SUCCESS) { 1971 IPW2100_WARN((sc->sc_dip, CE_WARN, 1972 "ipw2100_m_promisc(): " 1973 "device configuration failed\n")); 1974 goto fail; 1975 } 1976 } 1977 1978 return (0); 1979 fail: 1980 return (EIO); 1981 } 1982 1983 static mblk_t * 1984 ipw2100_m_tx(void *arg, mblk_t *mp) 1985 { 1986 struct ipw2100_softc *sc = (struct ipw2100_softc *)arg; 1987 struct ieee80211com *ic = &sc->sc_ic; 1988 mblk_t *next; 1989 1990 /* 1991 * No data frames go out unless we're associated; this 1992 * should not happen as the 802.11 layer does not enable 1993 * the xmit queue until we enter the RUN state. 1994 */ 1995 if (ic->ic_state != IEEE80211_S_RUN) { 1996 IPW2100_DBG(IPW2100_DBG_GLD, (sc->sc_dip, CE_CONT, 1997 "ipw2100_m_tx(): discard msg, ic_state = %u\n", 1998 ic->ic_state)); 1999 freemsgchain(mp); 2000 return (NULL); 2001 } 2002 2003 while (mp != NULL) { 2004 next = mp->b_next; 2005 mp->b_next = NULL; 2006 if (ipw2100_send(ic, mp, IEEE80211_FC0_TYPE_DATA) != 2007 DDI_SUCCESS) { 2008 mp->b_next = next; 2009 break; 2010 } 2011 mp = next; 2012 } 2013 return (mp); 2014 } 2015 2016 /* ARGSUSED */ 2017 static int 2018 ipw2100_send(ieee80211com_t *ic, mblk_t *mp, uint8_t type) 2019 { 2020 struct ipw2100_softc *sc = (struct ipw2100_softc *)ic; 2021 struct ieee80211_node *in; 2022 struct ieee80211_frame wh, *wh_tmp; 2023 struct ieee80211_key *k; 2024 uint8_t *hdat; 2025 mblk_t *m0, *m; 2026 size_t cnt, off; 2027 struct ipw2100_bd *txbd[2]; 2028 struct ipw2100_txb *txbuf; 2029 struct dma_region *dr; 2030 struct ipw2100_hdr *h; 2031 uint32_t idx, bidx; 2032 int err; 2033 2034 ASSERT(mp->b_next == NULL); 2035 2036 m0 = NULL; 2037 m = NULL; 2038 err = DDI_SUCCESS; 2039 2040 IPW2100_DBG(IPW2100_DBG_GLD, (sc->sc_dip, CE_CONT, 2041 "ipw2100_send(): enter\n")); 2042 2043 if ((type & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_DATA) { 2044 /* 2045 * it is impossible to send non-data 802.11 frame in current 2046 * ipw driver. Therefore, drop the package 2047 */ 2048 freemsg(mp); 2049 err = DDI_SUCCESS; 2050 goto fail0; 2051 } 2052 2053 mutex_enter(&sc->sc_tx_lock); 2054 2055 /* 2056 * need 2 descriptors: 1 for SEND cmd parameter header, 2057 * and the other for payload, i.e., 802.11 frame including 802.11 2058 * frame header 2059 */ 2060 if (sc->sc_tx_free < 2) { 2061 mutex_enter(&sc->sc_resched_lock); 2062 IPW2100_DBG(IPW2100_DBG_RING, (sc->sc_dip, CE_WARN, 2063 "ipw2100_send(): no enough descriptors(%d)\n", 2064 sc->sc_tx_free)); 2065 ic->ic_stats.is_tx_nobuf++; /* no enough buffer */ 2066 sc->sc_flags |= IPW2100_FLAG_TX_SCHED; 2067 err = DDI_FAILURE; 2068 mutex_exit(&sc->sc_resched_lock); 2069 goto fail1; 2070 } 2071 IPW2100_DBG(IPW2100_DBG_RING, (sc->sc_dip, CE_CONT, 2072 "ipw2100_send(): tx-free=%d,tx-curr=%d\n", 2073 sc->sc_tx_free, sc->sc_tx_cur)); 2074 2075 wh_tmp = (struct ieee80211_frame *)mp->b_rptr; 2076 in = ieee80211_find_txnode(ic, wh_tmp->i_addr1); 2077 if (in == NULL) { /* can not find tx node, drop the package */ 2078 freemsg(mp); 2079 err = DDI_SUCCESS; 2080 goto fail1; 2081 } 2082 in->in_inact = 0; 2083 (void) ieee80211_encap(ic, mp, in); 2084 ieee80211_free_node(in); 2085 2086 if (wh_tmp->i_fc[1] & IEEE80211_FC1_WEP) { 2087 /* 2088 * it is very bad that ieee80211_crypto_encap can only accept a 2089 * single continuous buffer. 2090 */ 2091 /* 2092 * allocate 32 more bytes is to be compatible with further 2093 * ieee802.11i standard. 2094 */ 2095 m = allocb(msgdsize(mp) + 32, BPRI_MED); 2096 if (m == NULL) { /* can not alloc buf, drop this package */ 2097 IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT, 2098 "ipw2100_send(): msg allocation failed\n")); 2099 2100 freemsg(mp); 2101 2102 err = DDI_SUCCESS; 2103 goto fail1; 2104 } 2105 off = 0; 2106 m0 = mp; 2107 while (m0) { 2108 cnt = MBLKL(m0); 2109 if (cnt) { 2110 (void) memcpy(m->b_rptr + off, m0->b_rptr, cnt); 2111 off += cnt; 2112 } 2113 m0 = m0->b_cont; 2114 } 2115 m->b_wptr += off; 2116 IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT, 2117 "ipw2100_send(): " 2118 "Encrypting 802.11 frame started, %d, %d\n", 2119 msgdsize(mp), MBLKL(mp))); 2120 k = ieee80211_crypto_encap(ic, m); 2121 if (k == NULL) { /* can not get the key, drop packages */ 2122 IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT, 2123 "ipw2100_send(): " 2124 "Encrypting 802.11 frame failed\n")); 2125 2126 freemsg(mp); 2127 err = DDI_SUCCESS; 2128 goto fail2; 2129 } 2130 IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT, 2131 "ipw2100_send(): " 2132 "Encrypting 802.11 frame finished, %d, %d, k=0x%08x\n", 2133 msgdsize(mp), MBLKL(mp), k->wk_flags)); 2134 } 2135 2136 /* 2137 * header descriptor 2138 */ 2139 idx = sc->sc_tx_cur; 2140 txbd[0] = &sc->sc_txbd[idx]; 2141 if ((idx & 1) == 0) 2142 bidx = idx / 2; 2143 sc->sc_tx_cur = RING_FORWARD(sc->sc_tx_cur, 1, IPW2100_NUM_TXBD); 2144 sc->sc_tx_free--; 2145 2146 /* 2147 * payload descriptor 2148 */ 2149 idx = sc->sc_tx_cur; 2150 txbd[1] = &sc->sc_txbd[idx]; 2151 if ((idx & 1) == 0) 2152 bidx = idx / 2; 2153 sc->sc_tx_cur = RING_FORWARD(sc->sc_tx_cur, 1, IPW2100_NUM_TXBD); 2154 sc->sc_tx_free--; 2155 2156 /* 2157 * one buffer, SEND cmd header and payload buffer 2158 */ 2159 txbuf = sc->sc_txbufs[bidx]; 2160 dr = &sc->sc_dma_txbufs[bidx]; 2161 2162 /* 2163 * extract 802.11 header from message, fill wh from m0 2164 */ 2165 hdat = (uint8_t *)&wh; 2166 off = 0; 2167 if (m) 2168 m0 = m; 2169 else 2170 m0 = mp; 2171 while (off < sizeof (wh)) { 2172 cnt = MBLKL(m0); 2173 if (cnt > (sizeof (wh) - off)) 2174 cnt = sizeof (wh) - off; 2175 if (cnt) { 2176 (void) memcpy(hdat + off, m0->b_rptr, cnt); 2177 off += cnt; 2178 m0->b_rptr += cnt; 2179 } 2180 else 2181 m0 = m0->b_cont; 2182 } 2183 2184 /* 2185 * prepare SEND cmd header 2186 */ 2187 h = &txbuf->txb_hdr; 2188 h->type = LE_32(IPW2100_CMD_SEND); 2189 h->subtype = LE_32(0); 2190 h->encrypted = ic->ic_flags & IEEE80211_F_PRIVACY ? 1 : 0; 2191 h->encrypt = 0; 2192 h->keyidx = 0; 2193 h->keysz = 0; 2194 h->fragsz = LE_16(0); 2195 IEEE80211_ADDR_COPY(h->saddr, wh.i_addr2); 2196 if (ic->ic_opmode == IEEE80211_M_STA) 2197 IEEE80211_ADDR_COPY(h->daddr, wh.i_addr3); 2198 else 2199 IEEE80211_ADDR_COPY(h->daddr, wh.i_addr1); 2200 2201 /* 2202 * extract payload from message into tx data buffer 2203 */ 2204 off = 0; 2205 while (m0) { 2206 cnt = MBLKL(m0); 2207 if (cnt) { 2208 (void) memcpy(&txbuf->txb_dat[off], m0->b_rptr, cnt); 2209 off += cnt; 2210 } 2211 m0 = m0->b_cont; 2212 } 2213 2214 /* 2215 * fill SEND cmd header descriptor 2216 */ 2217 txbd[0]->phyaddr = LE_32(dr->dr_pbase + 2218 OFFSETOF(struct ipw2100_txb, txb_hdr)); 2219 txbd[0]->len = LE_32(sizeof (struct ipw2100_hdr)); 2220 txbd[0]->flags = IPW2100_BD_FLAG_TX_FRAME_802_3 | 2221 IPW2100_BD_FLAG_TX_NOT_LAST_FRAGMENT; 2222 txbd[0]->nfrag = 2; 2223 /* 2224 * fill payload descriptor 2225 */ 2226 txbd[1]->phyaddr = LE_32(dr->dr_pbase + 2227 OFFSETOF(struct ipw2100_txb, txb_dat[0])); 2228 txbd[1]->len = LE_32(off); 2229 txbd[1]->flags = IPW2100_BD_FLAG_TX_FRAME_802_3 | 2230 IPW2100_BD_FLAG_TX_LAST_FRAGMENT; 2231 txbd[1]->nfrag = 0; 2232 2233 /* 2234 * dma sync 2235 */ 2236 (void) ddi_dma_sync(dr->dr_hnd, 0, sizeof (struct ipw2100_txb), 2237 DDI_DMA_SYNC_FORDEV); 2238 (void) ddi_dma_sync(sc->sc_dma_txbd.dr_hnd, 2239 (txbd[0] - sc->sc_txbd) * sizeof (struct ipw2100_bd), 2240 sizeof (struct ipw2100_bd), DDI_DMA_SYNC_FORDEV); 2241 /* 2242 * since txbd[1] may not be successive to txbd[0] due to the ring 2243 * organization, another dma_sync is needed to simplify the logic 2244 */ 2245 (void) ddi_dma_sync(sc->sc_dma_txbd.dr_hnd, 2246 (txbd[1] - sc->sc_txbd) * sizeof (struct ipw2100_bd), 2247 sizeof (struct ipw2100_bd), DDI_DMA_SYNC_FORDEV); 2248 /* 2249 * update txcur 2250 */ 2251 ipw2100_csr_put32(sc, IPW2100_CSR_TX_WRITE_INDEX, sc->sc_tx_cur); 2252 2253 if (mp) /* success, free the original message */ 2254 freemsg(mp); 2255 fail2: 2256 if (m) 2257 freemsg(m); 2258 fail1: 2259 mutex_exit(&sc->sc_tx_lock); 2260 fail0: 2261 IPW2100_DBG(IPW2100_DBG_GLD, (sc->sc_dip, CE_CONT, 2262 "ipw2100_send(): exit - err=%d\n", err)); 2263 2264 return (err); 2265 } 2266 2267 /* 2268 * IOCTL Handler 2269 */ 2270 #define IEEE80211_IOCTL_REQUIRED (1) 2271 #define IEEE80211_IOCTL_NOT_REQUIRED (0) 2272 static void 2273 ipw2100_m_ioctl(void *arg, queue_t *q, mblk_t *m) 2274 { 2275 struct ipw2100_softc *sc = (struct ipw2100_softc *)arg; 2276 struct ieee80211com *ic = &sc->sc_ic; 2277 int err; 2278 2279 IPW2100_DBG(IPW2100_DBG_GLD, (sc->sc_dip, CE_CONT, 2280 "ipw2100_m_ioctl(): enter\n")); 2281 2282 /* 2283 * check whether or not need to handle this in net80211 2284 */ 2285 if (ipw2100_ioctl(sc, q, m) == IEEE80211_IOCTL_NOT_REQUIRED) 2286 return; /* succes or fail */ 2287 2288 err = ieee80211_ioctl(ic, q, m); 2289 if (err == ENETRESET) { 2290 if (sc->sc_flags & IPW2100_FLAG_RUNNING) { 2291 (void) ipw2100_m_start(sc); 2292 (void) ieee80211_new_state(ic, 2293 IEEE80211_S_SCAN, -1); 2294 } 2295 } 2296 if (err == ERESTART) { 2297 if (sc->sc_flags & IPW2100_FLAG_RUNNING) 2298 (void) ipw2100_chip_reset(sc); 2299 } 2300 } 2301 2302 static int 2303 ipw2100_ioctl(struct ipw2100_softc *sc, queue_t *q, mblk_t *m) 2304 { 2305 struct iocblk *iocp; 2306 uint32_t len, ret, cmd; 2307 mblk_t *m0; 2308 boolean_t need_privilege; 2309 boolean_t need_net80211; 2310 2311 if (MBLKL(m) < sizeof (struct iocblk)) { 2312 IPW2100_DBG(IPW2100_DBG_IOCTL, (sc->sc_dip, CE_CONT, 2313 "ipw2100_ioctl(): ioctl buffer too short, %u\n", 2314 MBLKL(m))); 2315 miocnak(q, m, 0, EINVAL); 2316 return (IEEE80211_IOCTL_NOT_REQUIRED); 2317 } 2318 2319 /* 2320 * Validate the command 2321 */ 2322 iocp = (struct iocblk *)(uintptr_t)m->b_rptr; 2323 iocp->ioc_error = 0; 2324 cmd = iocp->ioc_cmd; 2325 need_privilege = B_TRUE; 2326 switch (cmd) { 2327 case WLAN_SET_PARAM: 2328 case WLAN_COMMAND: 2329 break; 2330 case WLAN_GET_PARAM: 2331 need_privilege = B_FALSE; 2332 break; 2333 default: 2334 IPW2100_DBG(IPW2100_DBG_IOCTL, (sc->sc_dip, CE_CONT, 2335 "ieee80211_ioctl(): unknown cmd 0x%x", cmd)); 2336 miocnak(q, m, 0, EINVAL); 2337 return (IEEE80211_IOCTL_NOT_REQUIRED); 2338 } 2339 2340 if (need_privilege && (ret = secpolicy_dl_config(iocp->ioc_cr)) != 0) { 2341 miocnak(q, m, 0, ret); 2342 return (IEEE80211_IOCTL_NOT_REQUIRED); 2343 } 2344 2345 /* 2346 * sanity check 2347 */ 2348 m0 = m->b_cont; 2349 if (iocp->ioc_count == 0 || iocp->ioc_count < sizeof (wldp_t) || 2350 m0 == NULL) { 2351 miocnak(q, m, 0, EINVAL); 2352 return (IEEE80211_IOCTL_NOT_REQUIRED); 2353 } 2354 /* 2355 * assuming single data block 2356 */ 2357 if (m0->b_cont) { 2358 freemsg(m0->b_cont); 2359 m0->b_cont = NULL; 2360 } 2361 2362 need_net80211 = B_FALSE; 2363 ret = ipw2100_getset(sc, m0, cmd, &need_net80211); 2364 if (!need_net80211) { 2365 len = msgdsize(m0); 2366 2367 IPW2100_DBG(IPW2100_DBG_IOCTL, (sc->sc_dip, CE_CONT, 2368 "ipw2100_ioctl(): go to call miocack with " 2369 "ret = %d, len = %d\n", ret, len)); 2370 miocack(q, m, len, ret); 2371 return (IEEE80211_IOCTL_NOT_REQUIRED); 2372 } 2373 2374 /* 2375 * IEEE80211_IOCTL_REQUIRED - need net80211 handle 2376 */ 2377 return (IEEE80211_IOCTL_REQUIRED); 2378 } 2379 2380 static int 2381 ipw2100_getset(struct ipw2100_softc *sc, mblk_t *m, uint32_t cmd, 2382 boolean_t *need_net80211) 2383 { 2384 wldp_t *infp, *outfp; 2385 uint32_t id; 2386 int ret; /* IEEE80211_IOCTL - handled by net80211 */ 2387 2388 infp = (wldp_t *)(uintptr_t)m->b_rptr; 2389 outfp = (wldp_t *)(uintptr_t)m->b_rptr; 2390 outfp->wldp_result = WL_NOTSUPPORTED; 2391 2392 id = infp->wldp_id; 2393 IPW2100_DBG(IPW2100_DBG_IOCTL, (sc->sc_dip, CE_CONT, 2394 "ipw2100_getset(): id = 0x%x\n", id)); 2395 switch (id) { 2396 /* 2397 * which is not supported by net80211, so it 2398 * has to be handled from driver side 2399 */ 2400 case WL_RADIO: 2401 ret = ipw_wificfg_radio(sc, cmd, outfp); 2402 break; 2403 /* 2404 * so far, drier doesn't support fix-rates 2405 */ 2406 case WL_DESIRED_RATES: 2407 ret = ipw_wificfg_desrates(outfp); 2408 break; 2409 /* 2410 * current net80211 implementation clears the bssid while 2411 * this command received, which will result in the all zero 2412 * mac address for scan'ed AP which is just disconnected. 2413 * This is a workaround solution until net80211 find a 2414 * better method. 2415 */ 2416 case WL_DISASSOCIATE: 2417 ret = ipw_wificfg_disassoc(sc, outfp); 2418 break; 2419 default: 2420 /* 2421 * The wifi IOCTL net80211 supported: 2422 * case WL_ESSID: 2423 * case WL_BSSID: 2424 * case WL_WEP_KEY_TAB: 2425 * case WL_WEP_KEY_ID: 2426 * case WL_AUTH_MODE: 2427 * case WL_ENCRYPTION: 2428 * case WL_BSS_TYPE: 2429 * case WL_ESS_LIST: 2430 * case WL_LINKSTATUS: 2431 * case WL_RSSI: 2432 * case WL_SCAN: 2433 * case WL_LOAD_DEFAULTS: 2434 */ 2435 2436 /* 2437 * When radio is off, need to ignore all ioctl. What need to 2438 * do is to check radio status firstly. If radio is ON, pass 2439 * it to net80211, otherwise, return to upper layer directly. 2440 * 2441 * Considering the WL_SUCCESS also means WL_CONNECTED for 2442 * checking linkstatus, one exception for WL_LINKSTATUS is to 2443 * let net80211 handle it. 2444 */ 2445 if ((ipw2100_get_radio(sc) == 0) && 2446 (id != WL_LINKSTATUS)) { 2447 2448 IPW2100_REPORT((sc->sc_dip, CE_WARN, 2449 "ipw: RADIO is OFF\n")); 2450 2451 outfp->wldp_length = WIFI_BUF_OFFSET; 2452 outfp->wldp_result = WL_SUCCESS; 2453 ret = 0; 2454 break; 2455 } 2456 2457 *need_net80211 = B_TRUE; /* let net80211 do the rest */ 2458 return (0); 2459 } 2460 /* 2461 * we will overwrite everything 2462 */ 2463 m->b_wptr = m->b_rptr + outfp->wldp_length; 2464 2465 return (ret); 2466 } 2467 2468 /* 2469 * Call back functions for get/set proporty 2470 */ 2471 static int 2472 ipw2100_m_getprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num, 2473 uint_t pr_flags, uint_t wldp_length, void *wldp_buf, uint_t *perm) 2474 { 2475 struct ipw2100_softc *sc = (struct ipw2100_softc *)arg; 2476 struct ieee80211com *ic = &sc->sc_ic; 2477 int err = 0; 2478 2479 switch (wldp_pr_num) { 2480 /* mac_prop_id */ 2481 case MAC_PROP_WL_DESIRED_RATES: 2482 IPW2100_DBG(IPW2100_DBG_BRUSSELS, (sc->sc_dip, CE_CONT, 2483 "ipw2100_m_getprop(): Not Support DESIRED_RATES\n")); 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