1 /* 2 * Copyright 2010 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 wldp_length, void *wldp_buf); 144 static void ipw2100_m_propinfo(void *, const char *, mac_prop_id_t, 145 mac_prop_info_handle_t); 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 | MC_PROPINFO, 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 NULL, 193 ipw2100_m_ioctl, 194 NULL, 195 NULL, 196 NULL, 197 ipw2100_m_setprop, 198 ipw2100_m_getprop, 199 ipw2100_m_propinfo 200 }; 201 202 203 /* 204 * DEBUG Facility 205 */ 206 #define MAX_MSG (128) 207 uint32_t ipw2100_debug = 0; 208 /* 209 * supported debug marsks: 210 * | IPW2100_DBG_INIT 211 * | IPW2100_DBG_GLD 212 * | IPW2100_DBG_TABLE 213 * | IPW2100_DBG_SOFTINT 214 * | IPW2100_DBG_CSR 215 * | IPW2100_DBG_INT 216 * | IPW2100_DBG_FW 217 * | IPW2100_DBG_IOCTL 218 * | IPW2100_DBG_HWCAP 219 * | IPW2100_DBG_STATISTIC 220 * | IPW2100_DBG_RING 221 * | IPW2100_DBG_WIFI 222 * | IPW2100_DBG_BRUSSELS 223 */ 224 225 /* 226 * global tuning parameters to work around unknown hardware issues 227 */ 228 static uint32_t delay_config_stable = 100000; /* 100ms */ 229 static uint32_t delay_fatal_recover = 100000 * 20; /* 2s */ 230 static uint32_t delay_aux_thread = 100000; /* 100ms */ 231 232 void 233 ipw2100_dbg(dev_info_t *dip, int level, const char *fmt, ...) 234 { 235 va_list ap; 236 char buf[MAX_MSG]; 237 int instance; 238 239 va_start(ap, fmt); 240 (void) vsnprintf(buf, sizeof (buf), fmt, ap); 241 va_end(ap); 242 243 if (dip) { 244 instance = ddi_get_instance(dip); 245 cmn_err(level, "%s%d: %s", IPW2100_DRV_NAME, instance, buf); 246 } else 247 cmn_err(level, "%s: %s", IPW2100_DRV_NAME, buf); 248 } 249 250 /* 251 * device operations 252 */ 253 int 254 ipw2100_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 255 { 256 struct ipw2100_softc *sc; 257 ddi_acc_handle_t cfgh; 258 caddr_t regs; 259 struct ieee80211com *ic; 260 int instance, err, i; 261 char strbuf[32]; 262 wifi_data_t wd = { 0 }; 263 mac_register_t *macp; 264 265 switch (cmd) { 266 case DDI_ATTACH: 267 break; 268 case DDI_RESUME: 269 sc = ddi_get_soft_state(ipw2100_ssp, ddi_get_instance(dip)); 270 if (sc == NULL) { 271 err = DDI_FAILURE; 272 goto fail1; 273 } 274 return (ipw2100_cpr_resume(sc)); 275 default: 276 err = DDI_FAILURE; 277 goto fail1; 278 } 279 280 instance = ddi_get_instance(dip); 281 err = ddi_soft_state_zalloc(ipw2100_ssp, instance); 282 if (err != DDI_SUCCESS) { 283 IPW2100_WARN((dip, CE_WARN, 284 "ipw2100_attach(): unable to allocate soft state\n")); 285 goto fail1; 286 } 287 sc = ddi_get_soft_state(ipw2100_ssp, instance); 288 sc->sc_dip = dip; 289 290 /* 291 * Map config spaces register 292 */ 293 err = ddi_regs_map_setup(dip, IPW2100_PCI_CFG_RNUM, ®s, 294 0, 0, &ipw2100_csr_accattr, &cfgh); 295 if (err != DDI_SUCCESS) { 296 IPW2100_WARN((dip, CE_WARN, 297 "ipw2100_attach(): unable to map spaces regs\n")); 298 goto fail2; 299 } 300 ddi_put8(cfgh, (uint8_t *)(regs + 0x41), 0); 301 ddi_regs_map_free(&cfgh); 302 303 /* 304 * Map operating registers 305 */ 306 err = ddi_regs_map_setup(dip, IPW2100_PCI_CSR_RNUM, &sc->sc_regs, 307 0, 0, &ipw2100_csr_accattr, &sc->sc_ioh); 308 if (err != DDI_SUCCESS) { 309 IPW2100_WARN((dip, CE_WARN, 310 "ipw2100_attach(): unable to map device regs\n")); 311 goto fail2; 312 } 313 314 /* 315 * Reset the chip 316 */ 317 err = ipw2100_chip_reset(sc); 318 if (err != DDI_SUCCESS) { 319 IPW2100_WARN((dip, CE_WARN, 320 "ipw2100_attach(): reset failed\n")); 321 goto fail3; 322 } 323 324 /* 325 * Get the hw conf, including MAC address, then init all rings. 326 */ 327 ipw2100_hwconf_get(sc); 328 err = ipw2100_ring_init(sc); 329 if (err != DDI_SUCCESS) { 330 IPW2100_WARN((dip, CE_WARN, 331 "ipw2100_attach(): " 332 "unable to allocate and initialize rings\n")); 333 goto fail3; 334 } 335 336 /* 337 * Initialize mutexs and condvars 338 */ 339 err = ddi_get_iblock_cookie(dip, 0, &sc->sc_iblk); 340 if (err != DDI_SUCCESS) { 341 IPW2100_WARN((dip, CE_WARN, 342 "ipw2100_attach(): ddi_get_iblock_cookie() failed\n")); 343 goto fail4; 344 } 345 /* 346 * interrupt lock 347 */ 348 mutex_init(&sc->sc_ilock, "interrupt-lock", MUTEX_DRIVER, 349 (void *) sc->sc_iblk); 350 cv_init(&sc->sc_fw_cond, "firmware", CV_DRIVER, NULL); 351 cv_init(&sc->sc_cmd_cond, "command", CV_DRIVER, NULL); 352 /* 353 * tx ring lock 354 */ 355 mutex_init(&sc->sc_tx_lock, "tx-ring", MUTEX_DRIVER, 356 (void *) sc->sc_iblk); 357 cv_init(&sc->sc_tx_cond, "tx-ring", CV_DRIVER, NULL); 358 /* 359 * rescheuled lock 360 */ 361 mutex_init(&sc->sc_resched_lock, "reschedule-lock", MUTEX_DRIVER, 362 (void *) sc->sc_iblk); 363 /* 364 * initialize the mfthread 365 */ 366 mutex_init(&sc->sc_mflock, "function-lock", MUTEX_DRIVER, 367 (void *) sc->sc_iblk); 368 cv_init(&sc->sc_mfthread_cv, NULL, CV_DRIVER, NULL); 369 sc->sc_mf_thread = NULL; 370 sc->sc_mfthread_switch = 0; 371 /* 372 * Initialize the wifi part, which will be used by 373 * generic layer 374 */ 375 ic = &sc->sc_ic; 376 ic->ic_phytype = IEEE80211_T_DS; 377 ic->ic_opmode = IEEE80211_M_STA; 378 ic->ic_state = IEEE80211_S_INIT; 379 ic->ic_maxrssi = 49; 380 /* 381 * Future, could use s/w to handle encryption: IEEE80211_C_WEP 382 * and need to add support for IEEE80211_C_IBSS 383 */ 384 ic->ic_caps = IEEE80211_C_SHPREAMBLE | IEEE80211_C_TXPMGT | 385 IEEE80211_C_PMGT; 386 ic->ic_sup_rates[IEEE80211_MODE_11B] = ipw2100_rateset_11b; 387 IEEE80211_ADDR_COPY(ic->ic_macaddr, sc->sc_macaddr); 388 for (i = 1; i < 16; i++) { 389 if (sc->sc_chmask &(1 << i)) { 390 /* IEEE80211_CHAN_B */ 391 ic->ic_sup_channels[i].ich_freq = ieee80211_ieee2mhz(i, 392 IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_CCK); 393 ic->ic_sup_channels[i].ich_flags = 394 IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_CCK; 395 } 396 } 397 ic->ic_ibss_chan = &ic->ic_sup_channels[0]; 398 ic->ic_xmit = ipw2100_send; 399 /* 400 * init Wifi layer 401 */ 402 ieee80211_attach(ic); 403 404 /* 405 * Override 80211 default routines 406 */ 407 ieee80211_media_init(ic); 408 sc->sc_newstate = ic->ic_newstate; 409 ic->ic_newstate = ipw2100_newstate; 410 /* 411 * initialize default tx key 412 */ 413 ic->ic_def_txkey = 0; 414 /* 415 * Set the Authentication to AUTH_Open only. 416 */ 417 sc->sc_authmode = IEEE80211_AUTH_OPEN; 418 419 /* 420 * Add the interrupt handler 421 */ 422 err = ddi_add_intr(dip, 0, &sc->sc_iblk, NULL, 423 ipw2100_intr, (caddr_t)sc); 424 if (err != DDI_SUCCESS) { 425 IPW2100_WARN((dip, CE_WARN, 426 "ipw2100_attach(): ddi_add_intr() failed\n")); 427 goto fail5; 428 } 429 430 /* 431 * Initialize pointer to device specific functions 432 */ 433 wd.wd_secalloc = WIFI_SEC_NONE; 434 wd.wd_opmode = ic->ic_opmode; 435 IEEE80211_ADDR_COPY(wd.wd_bssid, ic->ic_bss->in_bssid); 436 437 macp = mac_alloc(MAC_VERSION); 438 if (err != 0) { 439 IPW2100_WARN((dip, CE_WARN, 440 "ipw2100_attach(): mac_alloc() failed\n")); 441 goto fail6; 442 } 443 444 macp->m_type_ident = MAC_PLUGIN_IDENT_WIFI; 445 macp->m_driver = sc; 446 macp->m_dip = dip; 447 macp->m_src_addr = ic->ic_macaddr; 448 macp->m_callbacks = &ipw2100_m_callbacks; 449 macp->m_min_sdu = 0; 450 macp->m_max_sdu = IEEE80211_MTU; 451 macp->m_pdata = &wd; 452 macp->m_pdata_size = sizeof (wd); 453 454 /* 455 * Register the macp to mac 456 */ 457 err = mac_register(macp, &ic->ic_mach); 458 mac_free(macp); 459 if (err != DDI_SUCCESS) { 460 IPW2100_WARN((dip, CE_WARN, 461 "ipw2100_attach(): mac_register() failed\n")); 462 goto fail6; 463 } 464 465 /* 466 * Create minor node of type DDI_NT_NET_WIFI 467 */ 468 (void) snprintf(strbuf, sizeof (strbuf), "%s%d", 469 IPW2100_DRV_NAME, instance); 470 err = ddi_create_minor_node(dip, strbuf, S_IFCHR, 471 instance + 1, DDI_NT_NET_WIFI, 0); 472 if (err != DDI_SUCCESS) 473 IPW2100_WARN((dip, CE_WARN, 474 "ipw2100_attach(): ddi_create_minor_node() failed\n")); 475 476 /* 477 * Cache firmware, always return true 478 */ 479 (void) ipw2100_cache_firmware(sc); 480 481 /* 482 * Notify link is down now 483 */ 484 mac_link_update(ic->ic_mach, LINK_STATE_DOWN); 485 486 /* 487 * create the mf thread to handle the link status, 488 * recovery fatal error, etc. 489 */ 490 sc->sc_mfthread_switch = 1; 491 if (sc->sc_mf_thread == NULL) 492 sc->sc_mf_thread = thread_create((caddr_t)NULL, 0, 493 ipw2100_thread, sc, 0, &p0, TS_RUN, minclsyspri); 494 495 return (DDI_SUCCESS); 496 497 fail6: 498 ddi_remove_intr(dip, 0, sc->sc_iblk); 499 fail5: 500 ieee80211_detach(ic); 501 502 mutex_destroy(&sc->sc_ilock); 503 mutex_destroy(&sc->sc_tx_lock); 504 mutex_destroy(&sc->sc_mflock); 505 mutex_destroy(&sc->sc_resched_lock); 506 cv_destroy(&sc->sc_mfthread_cv); 507 cv_destroy(&sc->sc_tx_cond); 508 cv_destroy(&sc->sc_cmd_cond); 509 cv_destroy(&sc->sc_fw_cond); 510 fail4: 511 ipw2100_ring_free(sc); 512 fail3: 513 ddi_regs_map_free(&sc->sc_ioh); 514 fail2: 515 ddi_soft_state_free(ipw2100_ssp, instance); 516 fail1: 517 return (err); 518 } 519 520 int 521 ipw2100_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 522 { 523 struct ipw2100_softc *sc = 524 ddi_get_soft_state(ipw2100_ssp, ddi_get_instance(dip)); 525 int err; 526 527 ASSERT(sc != NULL); 528 529 switch (cmd) { 530 case DDI_DETACH: 531 break; 532 case DDI_SUSPEND: 533 return (ipw2100_cpr_suspend(sc)); 534 default: 535 return (DDI_FAILURE); 536 } 537 538 /* 539 * Destroy the mf_thread 540 */ 541 mutex_enter(&sc->sc_mflock); 542 sc->sc_mfthread_switch = 0; 543 while (sc->sc_mf_thread != NULL) { 544 if (cv_wait_sig(&sc->sc_mfthread_cv, &sc->sc_mflock) == 0) 545 break; 546 } 547 mutex_exit(&sc->sc_mflock); 548 549 /* 550 * Unregister from the MAC layer subsystem 551 */ 552 err = mac_unregister(sc->sc_ic.ic_mach); 553 if (err != DDI_SUCCESS) 554 return (err); 555 556 ddi_remove_intr(dip, 0, sc->sc_iblk); 557 558 /* 559 * destroy the cv 560 */ 561 mutex_destroy(&sc->sc_ilock); 562 mutex_destroy(&sc->sc_tx_lock); 563 mutex_destroy(&sc->sc_mflock); 564 mutex_destroy(&sc->sc_resched_lock); 565 cv_destroy(&sc->sc_mfthread_cv); 566 cv_destroy(&sc->sc_tx_cond); 567 cv_destroy(&sc->sc_cmd_cond); 568 cv_destroy(&sc->sc_fw_cond); 569 570 /* 571 * detach ieee80211 572 */ 573 ieee80211_detach(&sc->sc_ic); 574 575 (void) ipw2100_free_firmware(sc); 576 ipw2100_ring_free(sc); 577 578 ddi_regs_map_free(&sc->sc_ioh); 579 ddi_remove_minor_node(dip, NULL); 580 ddi_soft_state_free(ipw2100_ssp, ddi_get_instance(dip)); 581 582 return (DDI_SUCCESS); 583 } 584 585 int 586 ipw2100_cpr_suspend(struct ipw2100_softc *sc) 587 { 588 IPW2100_DBG(IPW2100_DBG_INIT, (sc->sc_dip, CE_CONT, 589 "ipw2100_cpr_suspend(): enter\n")); 590 591 /* 592 * Destroy the mf_thread 593 */ 594 mutex_enter(&sc->sc_mflock); 595 sc->sc_mfthread_switch = 0; 596 while (sc->sc_mf_thread != NULL) { 597 if (cv_wait_sig(&sc->sc_mfthread_cv, &sc->sc_mflock) == 0) 598 break; 599 } 600 mutex_exit(&sc->sc_mflock); 601 602 /* 603 * stop the hardware; this mask all interrupts 604 */ 605 ipw2100_stop(sc); 606 sc->sc_flags &= ~IPW2100_FLAG_RUNNING; 607 sc->sc_suspended = 1; 608 609 (void) ipw2100_free_firmware(sc); 610 ipw2100_ring_free(sc); 611 612 return (DDI_SUCCESS); 613 } 614 615 int 616 ipw2100_cpr_resume(struct ipw2100_softc *sc) 617 { 618 struct ieee80211com *ic = &sc->sc_ic; 619 dev_info_t *dip = sc->sc_dip; 620 int err; 621 622 IPW2100_DBG(IPW2100_DBG_INIT, (sc->sc_dip, CE_CONT, 623 "ipw2100_cpr_resume(): enter\n")); 624 625 /* 626 * Reset the chip 627 */ 628 err = ipw2100_chip_reset(sc); 629 if (err != DDI_SUCCESS) { 630 IPW2100_WARN((dip, CE_WARN, 631 "ipw2100_attach(): reset failed\n")); 632 return (DDI_FAILURE); 633 } 634 635 /* 636 * Get the hw conf, including MAC address, then init all rings. 637 */ 638 /* ipw2100_hwconf_get(sc); */ 639 err = ipw2100_ring_init(sc); 640 if (err != DDI_SUCCESS) { 641 IPW2100_WARN((dip, CE_WARN, 642 "ipw2100_attach(): " 643 "unable to allocate and initialize rings\n")); 644 return (DDI_FAILURE); 645 } 646 647 /* 648 * Cache firmware, always return true 649 */ 650 (void) ipw2100_cache_firmware(sc); 651 652 /* 653 * Notify link is down now 654 */ 655 mac_link_update(ic->ic_mach, LINK_STATE_DOWN); 656 657 /* 658 * create the mf thread to handle the link status, 659 * recovery fatal error, etc. 660 */ 661 sc->sc_mfthread_switch = 1; 662 if (sc->sc_mf_thread == NULL) 663 sc->sc_mf_thread = thread_create((caddr_t)NULL, 0, 664 ipw2100_thread, sc, 0, &p0, TS_RUN, minclsyspri); 665 666 /* 667 * enable all interrupts 668 */ 669 sc->sc_suspended = 0; 670 ipw2100_csr_put32(sc, IPW2100_CSR_INTR_MASK, IPW2100_INTR_MASK_ALL); 671 672 /* 673 * initialize ipw2100 hardware 674 */ 675 (void) ipw2100_init(sc); 676 677 sc->sc_flags |= IPW2100_FLAG_RUNNING; 678 679 return (DDI_SUCCESS); 680 } 681 682 /* 683 * quiesce(9E) entry point. 684 * This function is called when the system is single-threaded at high 685 * PIL with preemption disabled. Therefore, this function must not be 686 * blocked. 687 * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure. 688 * DDI_FAILURE indicates an error condition and should almost never happen. 689 * Contributed by Juergen Keil, <jk@tools.de>. 690 */ 691 static int 692 ipw2100_quiesce(dev_info_t *dip) 693 { 694 struct ipw2100_softc *sc = 695 ddi_get_soft_state(ipw2100_ssp, ddi_get_instance(dip)); 696 697 if (sc == NULL) 698 return (DDI_FAILURE); 699 700 /* 701 * No more blocking is allowed while we are in the 702 * quiesce(9E) entry point. 703 */ 704 sc->sc_flags |= IPW2100_FLAG_QUIESCED; 705 706 /* 707 * Disable and mask all interrupts. 708 */ 709 ipw2100_stop(sc); 710 return (DDI_SUCCESS); 711 } 712 713 static void 714 ipw2100_tables_init(struct ipw2100_softc *sc) 715 { 716 sc->sc_table1_base = ipw2100_csr_get32(sc, IPW2100_CSR_TABLE1_BASE); 717 sc->sc_table2_base = ipw2100_csr_get32(sc, IPW2100_CSR_TABLE2_BASE); 718 } 719 720 static void 721 ipw2100_stop(struct ipw2100_softc *sc) 722 { 723 struct ieee80211com *ic = &sc->sc_ic; 724 725 ipw2100_master_stop(sc); 726 ipw2100_csr_put32(sc, IPW2100_CSR_RST, IPW2100_RST_SW_RESET); 727 sc->sc_flags &= ~IPW2100_FLAG_FW_INITED; 728 729 if (!(sc->sc_flags & IPW2100_FLAG_QUIESCED)) 730 ieee80211_new_state(ic, IEEE80211_S_INIT, -1); 731 } 732 733 static int 734 ipw2100_config(struct ipw2100_softc *sc) 735 { 736 struct ieee80211com *ic = &sc->sc_ic; 737 struct ipw2100_security sec; 738 struct ipw2100_wep_key wkey; 739 struct ipw2100_scan_options sopt; 740 struct ipw2100_configuration cfg; 741 uint32_t data; 742 int err, i; 743 744 /* 745 * operation mode 746 */ 747 switch (ic->ic_opmode) { 748 case IEEE80211_M_STA: 749 case IEEE80211_M_HOSTAP: 750 data = LE_32(IPW2100_MODE_BSS); 751 break; 752 753 case IEEE80211_M_IBSS: 754 case IEEE80211_M_AHDEMO: 755 data = LE_32(IPW2100_MODE_IBSS); 756 break; 757 } 758 759 IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT, 760 "ipw2100_config(): Setting mode to %u\n", LE_32(data))); 761 762 err = ipw2100_cmd(sc, IPW2100_CMD_SET_MODE, 763 &data, sizeof (data)); 764 if (err != DDI_SUCCESS) 765 return (err); 766 767 /* 768 * operation channel if IBSS or MONITOR 769 */ 770 if (ic->ic_opmode == IEEE80211_M_IBSS) { 771 772 data = LE_32(ieee80211_chan2ieee(ic, ic->ic_ibss_chan)); 773 774 IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT, 775 "ipw2100_config(): Setting channel to %u\n", LE_32(data))); 776 777 err = ipw2100_cmd(sc, IPW2100_CMD_SET_CHANNEL, 778 &data, sizeof (data)); 779 if (err != DDI_SUCCESS) 780 return (err); 781 } 782 783 /* 784 * set MAC address 785 */ 786 IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT, 787 "ipw2100_config(): Setting MAC address to " 788 "%02x:%02x:%02x:%02x:%02x:%02x\n", 789 ic->ic_macaddr[0], ic->ic_macaddr[1], ic->ic_macaddr[2], 790 ic->ic_macaddr[3], ic->ic_macaddr[4], ic->ic_macaddr[5])); 791 err = ipw2100_cmd(sc, IPW2100_CMD_SET_MAC_ADDRESS, ic->ic_macaddr, 792 IEEE80211_ADDR_LEN); 793 if (err != DDI_SUCCESS) 794 return (err); 795 796 /* 797 * configuration capabilities 798 */ 799 cfg.flags = IPW2100_CFG_BSS_MASK | IPW2100_CFG_IBSS_MASK | 800 IPW2100_CFG_PREAMBLE_AUTO | IPW2100_CFG_802_1x_ENABLE; 801 if (ic->ic_opmode == IEEE80211_M_IBSS) 802 cfg.flags |= IPW2100_CFG_IBSS_AUTO_START; 803 if (sc->if_flags & IFF_PROMISC) 804 cfg.flags |= IPW2100_CFG_PROMISCUOUS; 805 cfg.flags = LE_32(cfg.flags); 806 cfg.bss_chan = LE_32(sc->sc_chmask >> 1); 807 cfg.ibss_chan = LE_32(sc->sc_chmask >> 1); 808 809 IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT, 810 "ipw2100_config(): Setting configuration to 0x%x\n", 811 LE_32(cfg.flags))); 812 813 err = ipw2100_cmd(sc, IPW2100_CMD_SET_CONFIGURATION, 814 &cfg, sizeof (cfg)); 815 816 if (err != DDI_SUCCESS) 817 return (err); 818 819 /* 820 * set 802.11 Tx rates 821 */ 822 data = LE_32(0x3); /* 1, 2 */ 823 IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT, 824 "ipw2100_config(): Setting 802.11 Tx rates to 0x%x\n", 825 LE_32(data))); 826 err = ipw2100_cmd(sc, IPW2100_CMD_SET_BASIC_TX_RATES, 827 &data, sizeof (data)); 828 if (err != DDI_SUCCESS) 829 return (err); 830 831 /* 832 * set 802.11b Tx rates 833 */ 834 data = LE_32(0xf); /* 1, 2, 5.5, 11 */ 835 IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT, 836 "ipw2100_config(): Setting 802.11b Tx rates to 0x%x\n", 837 LE_32(data))); 838 err = ipw2100_cmd(sc, IPW2100_CMD_SET_TX_RATES, &data, sizeof (data)); 839 if (err != DDI_SUCCESS) 840 return (err); 841 842 /* 843 * set power mode 844 */ 845 data = LE_32(IPW2100_POWER_MODE_CAM); 846 IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT, 847 "ipw2100_config(): Setting power mode to %u\n", LE_32(data))); 848 err = ipw2100_cmd(sc, IPW2100_CMD_SET_POWER_MODE, &data, sizeof (data)); 849 if (err != DDI_SUCCESS) 850 return (err); 851 852 /* 853 * set power index 854 */ 855 if (ic->ic_opmode == IEEE80211_M_IBSS) { 856 data = LE_32(32); 857 IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT, 858 "ipw2100_config(): Setting Tx power index to %u\n", 859 LE_32(data))); 860 err = ipw2100_cmd(sc, IPW2100_CMD_SET_TX_POWER_INDEX, 861 &data, sizeof (data)); 862 if (err != DDI_SUCCESS) 863 return (err); 864 } 865 866 /* 867 * set RTS threshold 868 */ 869 ic->ic_rtsthreshold = 2346; 870 data = LE_32(ic->ic_rtsthreshold); 871 IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT, 872 "ipw2100_config(): Setting RTS threshold to %u\n", LE_32(data))); 873 err = ipw2100_cmd(sc, IPW2100_CMD_SET_RTS_THRESHOLD, 874 &data, sizeof (data)); 875 if (err != DDI_SUCCESS) 876 return (err); 877 878 /* 879 * set frag threshold 880 */ 881 ic->ic_fragthreshold = 2346; 882 data = LE_32(ic->ic_fragthreshold); 883 IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT, 884 "ipw2100_config(): Setting frag threshold to %u\n", LE_32(data))); 885 err = ipw2100_cmd(sc, IPW2100_CMD_SET_FRAG_THRESHOLD, 886 &data, sizeof (data)); 887 if (err != DDI_SUCCESS) 888 return (err); 889 890 /* 891 * set ESSID 892 */ 893 IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT, 894 "ipw2100_config(): Setting ESSID to %u, ESSID[0]%c\n", 895 ic->ic_des_esslen, ic->ic_des_essid[0])); 896 err = ipw2100_cmd(sc, IPW2100_CMD_SET_ESSID, 897 ic->ic_des_essid, ic->ic_des_esslen); 898 if (err != DDI_SUCCESS) 899 return (err); 900 901 /* 902 * no mandatory BSSID 903 */ 904 err = ipw2100_cmd(sc, IPW2100_CMD_SET_MANDATORY_BSSID, NULL, 0); 905 if (err != DDI_SUCCESS) 906 return (err); 907 908 /* 909 * set BSSID, if any 910 */ 911 if (ic->ic_flags & IEEE80211_F_DESBSSID) { 912 IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT, 913 "ipw2100_config(): Setting BSSID to %u\n", 914 IEEE80211_ADDR_LEN)); 915 err = ipw2100_cmd(sc, IPW2100_CMD_SET_DESIRED_BSSID, 916 ic->ic_des_bssid, IEEE80211_ADDR_LEN); 917 if (err != DDI_SUCCESS) 918 return (err); 919 } 920 921 /* 922 * set security information 923 */ 924 (void) memset(&sec, 0, sizeof (sec)); 925 /* 926 * use the value set to ic_bss to retrieve current sharedmode 927 */ 928 sec.authmode = (ic->ic_bss->in_authmode == WL_SHAREDKEY) ? 929 IPW2100_AUTH_SHARED : IPW2100_AUTH_OPEN; 930 sec.ciphers = LE_32(IPW2100_CIPHER_NONE); 931 IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT, 932 "ipw2100_config(): Setting authmode to %u\n", sec.authmode)); 933 err = ipw2100_cmd(sc, IPW2100_CMD_SET_SECURITY_INFORMATION, 934 &sec, sizeof (sec)); 935 if (err != DDI_SUCCESS) 936 return (err); 937 938 /* 939 * set WEP if any 940 */ 941 if (ic->ic_flags & IEEE80211_F_PRIVACY) { 942 for (i = 0; i < IEEE80211_WEP_NKID; i++) { 943 if (ic->ic_nw_keys[i].wk_keylen == 0) 944 continue; 945 wkey.idx = (uint8_t)i; 946 wkey.len = ic->ic_nw_keys[i].wk_keylen; 947 (void) memset(wkey.key, 0, sizeof (wkey.key)); 948 if (ic->ic_nw_keys[i].wk_keylen) 949 (void) memcpy(wkey.key, 950 ic->ic_nw_keys[i].wk_key, 951 ic->ic_nw_keys[i].wk_keylen); 952 err = ipw2100_cmd(sc, IPW2100_CMD_SET_WEP_KEY, 953 &wkey, sizeof (wkey)); 954 if (err != DDI_SUCCESS) 955 return (err); 956 } 957 data = LE_32(ic->ic_def_txkey); 958 err = ipw2100_cmd(sc, IPW2100_CMD_SET_WEP_KEY_INDEX, 959 &data, sizeof (data)); 960 if (err != DDI_SUCCESS) 961 return (err); 962 } 963 964 /* 965 * turn on WEP 966 */ 967 data = LE_32((ic->ic_flags & IEEE80211_F_PRIVACY) ? 0x8 : 0); 968 IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT, 969 "ipw2100_config(): Setting WEP flags to %u\n", LE_32(data))); 970 err = ipw2100_cmd(sc, IPW2100_CMD_SET_WEP_FLAGS, &data, sizeof (data)); 971 if (err != DDI_SUCCESS) 972 return (err); 973 974 /* 975 * set beacon interval if IBSS or HostAP 976 */ 977 if (ic->ic_opmode == IEEE80211_M_IBSS || 978 ic->ic_opmode == IEEE80211_M_HOSTAP) { 979 980 data = LE_32(ic->ic_lintval); 981 IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT, 982 "ipw2100_config(): Setting beacon interval to %u\n", 983 LE_32(data))); 984 err = ipw2100_cmd(sc, IPW2100_CMD_SET_BEACON_INTERVAL, 985 &data, sizeof (data)); 986 if (err != DDI_SUCCESS) 987 return (err); 988 } 989 990 /* 991 * set scan options 992 */ 993 sopt.flags = LE_32(0); 994 sopt.channels = LE_32(sc->sc_chmask >> 1); 995 err = ipw2100_cmd(sc, IPW2100_CMD_SET_SCAN_OPTIONS, 996 &sopt, sizeof (sopt)); 997 if (err != DDI_SUCCESS) 998 return (err); 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 adapter 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 wldp_length, void *wldp_buf) 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, 2491 wldp_length, wldp_buf); 2492 break; 2493 } 2494 2495 return (err); 2496 } 2497 2498 static void 2499 ipw2100_m_propinfo(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num, 2500 mac_prop_info_handle_t prh) 2501 { 2502 struct ipw2100_softc *sc = (struct ipw2100_softc *)arg; 2503 struct ieee80211com *ic = &sc->sc_ic; 2504 2505 ieee80211_propinfo(ic, pr_name, wldp_pr_num, prh); 2506 2507 } 2508 2509 static int 2510 ipw2100_m_setprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num, 2511 uint_t wldp_length, const void *wldp_buf) 2512 { 2513 struct ipw2100_softc *sc = (struct ipw2100_softc *)arg; 2514 struct ieee80211com *ic = &sc->sc_ic; 2515 int err; 2516 2517 switch (wldp_pr_num) { 2518 /* mac_prop_id */ 2519 case MAC_PROP_WL_DESIRED_RATES: 2520 IPW2100_DBG(IPW2100_DBG_BRUSSELS, (sc->sc_dip, CE_CONT, 2521 "ipw2100_m_setprop(): Not Support DESIRED_RATES\n")); 2522 err = ENOTSUP; 2523 break; 2524 case MAC_PROP_WL_RADIO: 2525 IPW2100_DBG(IPW2100_DBG_BRUSSELS, (sc->sc_dip, CE_CONT, 2526 "ipw2100_m_setprop(): Not Support RADIO\n")); 2527 err = ENOTSUP; 2528 break; 2529 default: 2530 /* go through net80211 */ 2531 err = ieee80211_setprop(ic, pr_name, wldp_pr_num, wldp_length, 2532 wldp_buf); 2533 break; 2534 } 2535 2536 if (err == ENETRESET) { 2537 if (sc->sc_flags & IPW2100_FLAG_RUNNING) { 2538 (void) ipw2100_m_start(sc); 2539 (void) ieee80211_new_state(ic, 2540 IEEE80211_S_SCAN, -1); 2541 } 2542 2543 err = 0; 2544 } 2545 2546 return (err); 2547 } 2548 2549 static int 2550 ipw_wificfg_radio(struct ipw2100_softc *sc, uint32_t cmd, wldp_t *outfp) 2551 { 2552 uint32_t ret = ENOTSUP; 2553 2554 switch (cmd) { 2555 case WLAN_GET_PARAM: 2556 *(wl_linkstatus_t *)(outfp->wldp_buf) = ipw2100_get_radio(sc); 2557 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_linkstatus_t); 2558 outfp->wldp_result = WL_SUCCESS; 2559 ret = 0; /* command sucess */ 2560 break; 2561 case WLAN_SET_PARAM: 2562 default: 2563 break; 2564 } 2565 return (ret); 2566 } 2567 2568 static int 2569 ipw_wificfg_desrates(wldp_t *outfp) 2570 { 2571 /* 2572 * return success, but with result NOTSUPPORTED 2573 */ 2574 outfp->wldp_length = WIFI_BUF_OFFSET; 2575 outfp->wldp_result = WL_NOTSUPPORTED; 2576 return (0); 2577 } 2578 2579 static int 2580 ipw_wificfg_disassoc(struct ipw2100_softc *sc, wldp_t *outfp) 2581 { 2582 struct ieee80211com *ic = &sc->sc_ic; 2583 2584 /* 2585 * init the state 2586 */ 2587 if (ic->ic_state != IEEE80211_S_INIT) { 2588 (void) ieee80211_new_state(ic, IEEE80211_S_INIT, -1); 2589 } 2590 2591 /* 2592 * return success always 2593 */ 2594 outfp->wldp_length = WIFI_BUF_OFFSET; 2595 outfp->wldp_result = WL_SUCCESS; 2596 return (0); 2597 } 2598 /* End of IOCTL Handler */ 2599 2600 static void 2601 ipw2100_fix_channel(struct ieee80211com *ic, mblk_t *m) 2602 { 2603 struct ieee80211_frame *wh; 2604 uint8_t subtype; 2605 uint8_t *frm, *efrm; 2606 2607 wh = (struct ieee80211_frame *)m->b_rptr; 2608 2609 if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_MGT) 2610 return; 2611 2612 subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; 2613 2614 if (subtype != IEEE80211_FC0_SUBTYPE_BEACON && 2615 subtype != IEEE80211_FC0_SUBTYPE_PROBE_RESP) 2616 return; 2617 2618 /* 2619 * assume the message contains only 1 block 2620 */ 2621 frm = (uint8_t *)(wh + 1); 2622 efrm = (uint8_t *)m->b_wptr; 2623 frm += 12; /* skip tstamp, bintval and capinfo fields */ 2624 while (frm < efrm) { 2625 if (*frm == IEEE80211_ELEMID_DSPARMS) { 2626 #if IEEE80211_CHAN_MAX < 255 2627 if (frm[2] <= IEEE80211_CHAN_MAX) 2628 #endif 2629 { 2630 ic->ic_curchan = &ic->ic_sup_channels[frm[2]]; 2631 } 2632 } 2633 frm += frm[1] + 2; 2634 } 2635 } 2636 2637 static void 2638 ipw2100_rcvpkt(struct ipw2100_softc *sc, struct ipw2100_status *status, 2639 uint8_t *rxbuf) 2640 { 2641 struct ieee80211com *ic = &sc->sc_ic; 2642 mblk_t *m; 2643 struct ieee80211_frame *wh = (struct ieee80211_frame *)rxbuf; 2644 struct ieee80211_node *in; 2645 uint32_t rlen; 2646 2647 in = ieee80211_find_rxnode(ic, wh); 2648 rlen = LE_32(status->len); 2649 m = allocb(rlen, BPRI_MED); 2650 if (m) { 2651 (void) memcpy(m->b_wptr, rxbuf, rlen); 2652 m->b_wptr += rlen; 2653 if (ic->ic_state == IEEE80211_S_SCAN) 2654 ipw2100_fix_channel(ic, m); 2655 (void) ieee80211_input(ic, m, in, status->rssi, 0); 2656 } else 2657 IPW2100_WARN((sc->sc_dip, CE_WARN, 2658 "ipw2100_rcvpkg(): cannot allocate receive message(%u)\n", 2659 LE_32(status->len))); 2660 ieee80211_free_node(in); 2661 } 2662 2663 static uint_t 2664 ipw2100_intr(caddr_t arg) 2665 { 2666 struct ipw2100_softc *sc = (struct ipw2100_softc *)(uintptr_t)arg; 2667 uint32_t ireg, ridx, len, i; 2668 struct ieee80211com *ic = &sc->sc_ic; 2669 struct ipw2100_status *status; 2670 uint8_t *rxbuf; 2671 struct dma_region *dr; 2672 uint32_t state; 2673 #if DEBUG 2674 struct ipw2100_bd *rxbd; 2675 #endif 2676 2677 if (sc->sc_suspended) 2678 return (DDI_INTR_UNCLAIMED); 2679 2680 ireg = ipw2100_csr_get32(sc, IPW2100_CSR_INTR); 2681 2682 if (!(ireg & IPW2100_INTR_MASK_ALL)) 2683 return (DDI_INTR_UNCLAIMED); 2684 2685 /* 2686 * mask all interrupts 2687 */ 2688 ipw2100_csr_put32(sc, IPW2100_CSR_INTR_MASK, 0); 2689 2690 /* 2691 * acknowledge all fired interrupts 2692 */ 2693 ipw2100_csr_put32(sc, IPW2100_CSR_INTR, ireg); 2694 2695 IPW2100_DBG(IPW2100_DBG_INT, (sc->sc_dip, CE_CONT, 2696 "ipw2100_intr(): interrupt is fired. int=0x%08x\n", ireg)); 2697 2698 if (ireg & IPW2100_INTR_MASK_ERR) { 2699 2700 IPW2100_DBG(IPW2100_DBG_FATAL, (sc->sc_dip, CE_CONT, 2701 "ipw2100_intr(): interrupt is fired, MASK = 0x%08x\n", 2702 ireg)); 2703 2704 /* 2705 * inform mfthread to recover hw error 2706 */ 2707 mutex_enter(&sc->sc_mflock); 2708 sc->sc_flags |= IPW2100_FLAG_HW_ERR_RECOVER; 2709 mutex_exit(&sc->sc_mflock); 2710 2711 goto enable_interrupt; 2712 } 2713 2714 /* 2715 * FW intr 2716 */ 2717 if (ireg & IPW2100_INTR_FW_INIT_DONE) { 2718 mutex_enter(&sc->sc_ilock); 2719 sc->sc_flags |= IPW2100_FLAG_FW_INITED; 2720 cv_signal(&sc->sc_fw_cond); 2721 mutex_exit(&sc->sc_ilock); 2722 } 2723 2724 /* 2725 * RX intr 2726 */ 2727 if (ireg & IPW2100_INTR_RX_TRANSFER) { 2728 ridx = ipw2100_csr_get32(sc, 2729 IPW2100_CSR_RX_READ_INDEX); 2730 2731 for (; sc->sc_rx_cur != ridx; 2732 sc->sc_rx_cur = RING_FORWARD( 2733 sc->sc_rx_cur, 1, IPW2100_NUM_RXBD)) { 2734 2735 i = sc->sc_rx_cur; 2736 status = &sc->sc_status[i]; 2737 rxbuf = &sc->sc_rxbufs[i]->rxb_dat[0]; 2738 dr = &sc->sc_dma_rxbufs[i]; 2739 2740 /* 2741 * sync 2742 */ 2743 (void) ddi_dma_sync(sc->sc_dma_status.dr_hnd, 2744 i * sizeof (struct ipw2100_status), 2745 sizeof (struct ipw2100_status), 2746 DDI_DMA_SYNC_FORKERNEL); 2747 (void) ddi_dma_sync(sc->sc_dma_rxbd.dr_hnd, 2748 i * sizeof (struct ipw2100_bd), 2749 sizeof (struct ipw2100_bd), 2750 DDI_DMA_SYNC_FORKERNEL); 2751 (void) ddi_dma_sync(dr->dr_hnd, 0, 2752 sizeof (struct ipw2100_rxb), 2753 DDI_DMA_SYNC_FORKERNEL); 2754 IPW2100_DBG(IPW2100_DBG_INT, (sc->sc_dip, CE_CONT, 2755 "ipw2100_intr(): status code=0x%04x, len=0x%08x, " 2756 "flags=0x%02x, rssi=%02x\n", 2757 LE_16(status->code), LE_32(status->len), 2758 status->flags, status->rssi)); 2759 #if DEBUG 2760 rxbd = &sc->sc_rxbd[i]; 2761 IPW2100_DBG(IPW2100_DBG_INT, (sc->sc_dip, CE_CONT, 2762 "ipw2100_intr(): rxbd,phyaddr=0x%08x, len=0x%08x, " 2763 "flags=0x%02x,nfrag=%02x\n", 2764 LE_32(rxbd->phyaddr), LE_32(rxbd->len), 2765 rxbd->flags, rxbd->nfrag)); 2766 #endif 2767 switch (LE_16(status->code) & 0x0f) { 2768 /* 2769 * command complete response 2770 */ 2771 case IPW2100_STATUS_CODE_COMMAND: 2772 mutex_enter(&sc->sc_ilock); 2773 sc->sc_done = 1; 2774 cv_signal(&sc->sc_cmd_cond); 2775 mutex_exit(&sc->sc_ilock); 2776 break; 2777 /* 2778 * change state 2779 */ 2780 case IPW2100_STATUS_CODE_NEWSTATE: 2781 state = LE_32(* ((uint32_t *)(uintptr_t)rxbuf)); 2782 IPW2100_DBG(IPW2100_DBG_INT, 2783 (sc->sc_dip, CE_CONT, 2784 "ipw2100_intr(): newstate,state=0x%x\n", 2785 state)); 2786 2787 switch (state) { 2788 case IPW2100_STATE_ASSOCIATED: 2789 ieee80211_new_state(ic, 2790 IEEE80211_S_RUN, -1); 2791 break; 2792 case IPW2100_STATE_ASSOCIATION_LOST: 2793 case IPW2100_STATE_DISABLED: 2794 ieee80211_new_state(ic, 2795 IEEE80211_S_INIT, -1); 2796 break; 2797 /* 2798 * When radio is OFF, need a better 2799 * scan approach to ensure scan 2800 * result correct. 2801 */ 2802 case IPW2100_STATE_RADIO_DISABLED: 2803 IPW2100_REPORT((sc->sc_dip, CE_WARN, 2804 "ipw2100_intr(): RADIO is OFF\n")); 2805 ipw2100_stop(sc); 2806 break; 2807 case IPW2100_STATE_SCAN_COMPLETE: 2808 ieee80211_cancel_scan(ic); 2809 break; 2810 case IPW2100_STATE_SCANNING: 2811 if (ic->ic_state != IEEE80211_S_RUN) 2812 ieee80211_new_state(ic, 2813 IEEE80211_S_SCAN, -1); 2814 ic->ic_flags |= IEEE80211_F_SCAN; 2815 2816 break; 2817 default: 2818 break; 2819 } 2820 break; 2821 case IPW2100_STATUS_CODE_DATA_802_11: 2822 case IPW2100_STATUS_CODE_DATA_802_3: 2823 ipw2100_rcvpkt(sc, status, rxbuf); 2824 break; 2825 case IPW2100_STATUS_CODE_NOTIFICATION: 2826 break; 2827 default: 2828 IPW2100_WARN((sc->sc_dip, CE_WARN, 2829 "ipw2100_intr(): " 2830 "unknown status code 0x%04x\n", 2831 LE_16(status->code))); 2832 break; 2833 } 2834 } 2835 /* 2836 * write sc_rx_cur backward 1 step to RX_WRITE_INDEX 2837 */ 2838 ipw2100_csr_put32(sc, IPW2100_CSR_RX_WRITE_INDEX, 2839 RING_BACKWARD(sc->sc_rx_cur, 1, IPW2100_NUM_RXBD)); 2840 } 2841 2842 /* 2843 * TX intr 2844 */ 2845 if (ireg & IPW2100_INTR_TX_TRANSFER) { 2846 mutex_enter(&sc->sc_tx_lock); 2847 ridx = ipw2100_csr_get32(sc, IPW2100_CSR_TX_READ_INDEX); 2848 len = RING_FLEN(RING_FORWARD(sc->sc_tx_cur, 2849 sc->sc_tx_free, IPW2100_NUM_TXBD), 2850 ridx, IPW2100_NUM_TXBD); 2851 sc->sc_tx_free += len; 2852 IPW2100_DBG(IPW2100_DBG_INT, (sc->sc_dip, CE_CONT, 2853 "ipw2100_intr(): len=%d\n", len)); 2854 mutex_exit(&sc->sc_tx_lock); 2855 2856 mutex_enter(&sc->sc_resched_lock); 2857 if (len > 1 && (sc->sc_flags & IPW2100_FLAG_TX_SCHED)) { 2858 sc->sc_flags &= ~IPW2100_FLAG_TX_SCHED; 2859 mac_tx_update(ic->ic_mach); 2860 } 2861 mutex_exit(&sc->sc_resched_lock); 2862 } 2863 2864 enable_interrupt: 2865 /* 2866 * enable all interrupts 2867 */ 2868 ipw2100_csr_put32(sc, IPW2100_CSR_INTR_MASK, IPW2100_INTR_MASK_ALL); 2869 2870 return (DDI_INTR_CLAIMED); 2871 } 2872 2873 2874 /* 2875 * Module Loading Data & Entry Points 2876 */ 2877 DDI_DEFINE_STREAM_OPS(ipw2100_devops, nulldev, nulldev, ipw2100_attach, 2878 ipw2100_detach, nodev, NULL, D_MP, NULL, ipw2100_quiesce); 2879 2880 static struct modldrv ipw2100_modldrv = { 2881 &mod_driverops, 2882 ipw2100_ident, 2883 &ipw2100_devops 2884 }; 2885 2886 static struct modlinkage ipw2100_modlinkage = { 2887 MODREV_1, 2888 &ipw2100_modldrv, 2889 NULL 2890 }; 2891 2892 int 2893 _init(void) 2894 { 2895 int status; 2896 2897 status = ddi_soft_state_init(&ipw2100_ssp, 2898 sizeof (struct ipw2100_softc), 1); 2899 if (status != DDI_SUCCESS) 2900 return (status); 2901 2902 mac_init_ops(&ipw2100_devops, IPW2100_DRV_NAME); 2903 status = mod_install(&ipw2100_modlinkage); 2904 if (status != DDI_SUCCESS) { 2905 mac_fini_ops(&ipw2100_devops); 2906 ddi_soft_state_fini(&ipw2100_ssp); 2907 } 2908 2909 return (status); 2910 } 2911 2912 int 2913 _fini(void) 2914 { 2915 int status; 2916 2917 status = mod_remove(&ipw2100_modlinkage); 2918 if (status == DDI_SUCCESS) { 2919 mac_fini_ops(&ipw2100_devops); 2920 ddi_soft_state_fini(&ipw2100_ssp); 2921 } 2922 2923 return (status); 2924 } 2925 2926 int 2927 _info(struct modinfo *mip) 2928 { 2929 return (mod_info(&ipw2100_modlinkage, mip)); 2930 } 2931