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 en_adapter: 1001 1002 IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT, 1003 "ipw2100_config(): Enabling adapter\n")); 1004 1005 return (ipw2100_cmd(sc, IPW2100_CMD_ENABLE, NULL, 0)); 1006 } 1007 1008 static int 1009 ipw2100_cmd(struct ipw2100_softc *sc, uint32_t type, void *buf, size_t len) 1010 { 1011 struct ipw2100_bd *txbd; 1012 clock_t clk; 1013 uint32_t idx; 1014 1015 /* 1016 * prepare command buffer 1017 */ 1018 sc->sc_cmd->type = LE_32(type); 1019 sc->sc_cmd->subtype = LE_32(0); 1020 sc->sc_cmd->seq = LE_32(0); 1021 /* 1022 * copy data if any 1023 */ 1024 if (len && buf) 1025 (void) memcpy(sc->sc_cmd->data, buf, len); 1026 sc->sc_cmd->len = LE_32(len); 1027 1028 /* 1029 * get host & device descriptor to submit command 1030 */ 1031 mutex_enter(&sc->sc_tx_lock); 1032 1033 IPW2100_DBG(IPW2100_DBG_RING, (sc->sc_dip, CE_CONT, 1034 "ipw2100_cmd(): tx-free=%d\n", sc->sc_tx_free)); 1035 1036 /* 1037 * command need 1 descriptor 1038 */ 1039 while (sc->sc_tx_free < 1) { 1040 sc->sc_flags |= IPW2100_FLAG_CMD_WAIT; 1041 cv_wait(&sc->sc_tx_cond, &sc->sc_tx_lock); 1042 } 1043 idx = sc->sc_tx_cur; 1044 1045 IPW2100_DBG(IPW2100_DBG_RING, (sc->sc_dip, CE_CONT, 1046 "ipw2100_cmd(): tx-cur=%d\n", idx)); 1047 1048 sc->sc_done = 0; 1049 1050 txbd = &sc->sc_txbd[idx]; 1051 txbd->phyaddr = LE_32(sc->sc_dma_cmd.dr_pbase); 1052 txbd->len = LE_32(sizeof (struct ipw2100_cmd)); 1053 txbd->flags = IPW2100_BD_FLAG_TX_FRAME_COMMAND 1054 | IPW2100_BD_FLAG_TX_LAST_FRAGMENT; 1055 txbd->nfrag = 1; 1056 /* 1057 * sync for device 1058 */ 1059 (void) ddi_dma_sync(sc->sc_dma_cmd.dr_hnd, 0, 1060 sizeof (struct ipw2100_cmd), DDI_DMA_SYNC_FORDEV); 1061 (void) ddi_dma_sync(sc->sc_dma_txbd.dr_hnd, 1062 idx * sizeof (struct ipw2100_bd), 1063 sizeof (struct ipw2100_bd), DDI_DMA_SYNC_FORDEV); 1064 1065 /* 1066 * ring move forward 1067 */ 1068 sc->sc_tx_cur = RING_FORWARD(sc->sc_tx_cur, 1, IPW2100_NUM_TXBD); 1069 sc->sc_tx_free--; 1070 ipw2100_csr_put32(sc, IPW2100_CSR_TX_WRITE_INDEX, sc->sc_tx_cur); 1071 mutex_exit(&sc->sc_tx_lock); 1072 1073 /* 1074 * wait for command done 1075 */ 1076 clk = drv_usectohz(1000000); /* 1 second */ 1077 mutex_enter(&sc->sc_ilock); 1078 while (sc->sc_done == 0) { 1079 /* 1080 * pending for the response 1081 */ 1082 if (cv_reltimedwait(&sc->sc_cmd_cond, &sc->sc_ilock, 1083 clk, TR_CLOCK_TICK) < 0) 1084 break; 1085 } 1086 mutex_exit(&sc->sc_ilock); 1087 1088 IPW2100_DBG(IPW2100_DBG_RING, (sc->sc_dip, CE_CONT, 1089 "ipw2100_cmd(): cmd-done=%s\n", sc->sc_done ? "yes" : "no")); 1090 1091 if (sc->sc_done == 0) 1092 return (DDI_FAILURE); 1093 1094 return (DDI_SUCCESS); 1095 } 1096 1097 int 1098 ipw2100_init(struct ipw2100_softc *sc) 1099 { 1100 int err; 1101 1102 IPW2100_DBG(IPW2100_DBG_INIT, (sc->sc_dip, CE_CONT, 1103 "ipw2100_init(): enter\n")); 1104 1105 /* 1106 * no firmware is available, return fail directly 1107 */ 1108 if (!(sc->sc_flags & IPW2100_FLAG_FW_CACHED)) { 1109 IPW2100_WARN((sc->sc_dip, CE_WARN, 1110 "ipw2100_init(): no firmware is available\n")); 1111 return (DDI_FAILURE); 1112 } 1113 1114 ipw2100_stop(sc); 1115 1116 err = ipw2100_chip_reset(sc); 1117 if (err != DDI_SUCCESS) { 1118 IPW2100_WARN((sc->sc_dip, CE_WARN, 1119 "ipw2100_init(): could not reset adapter\n")); 1120 goto fail; 1121 } 1122 1123 /* 1124 * load microcode 1125 */ 1126 IPW2100_DBG(IPW2100_DBG_INIT, (sc->sc_dip, CE_CONT, 1127 "ipw2100_init(): loading microcode\n")); 1128 err = ipw2100_load_uc(sc); 1129 if (err != DDI_SUCCESS) { 1130 IPW2100_WARN((sc->sc_dip, CE_WARN, 1131 "ipw2100_init(): could not load microcode, try again\n")); 1132 goto fail; 1133 } 1134 1135 ipw2100_master_stop(sc); 1136 1137 ipw2100_ring_hwsetup(sc); 1138 1139 /* 1140 * load firmware 1141 */ 1142 IPW2100_DBG(IPW2100_DBG_INIT, (sc->sc_dip, CE_CONT, 1143 "ipw2100_init(): loading firmware\n")); 1144 err = ipw2100_load_fw(sc); 1145 if (err != DDI_SUCCESS) { 1146 IPW2100_WARN((sc->sc_dip, CE_WARN, 1147 "ipw2100_init(): could not load firmware, try again\n")); 1148 goto fail; 1149 } 1150 1151 /* 1152 * initialize tables 1153 */ 1154 ipw2100_tables_init(sc); 1155 ipw2100_table1_put32(sc, IPW2100_INFO_LOCK, 0); 1156 1157 /* 1158 * Hardware will be enabled after configuration 1159 */ 1160 err = ipw2100_config(sc); 1161 if (err != DDI_SUCCESS) { 1162 IPW2100_WARN((sc->sc_dip, CE_WARN, 1163 "ipw2100_init(): device configuration failed\n")); 1164 goto fail; 1165 } 1166 1167 delay(drv_usectohz(delay_config_stable)); 1168 1169 return (DDI_SUCCESS); 1170 1171 fail: 1172 ipw2100_stop(sc); 1173 1174 return (err); 1175 } 1176 1177 /* 1178 * get hardware configurations from EEPROM embedded within chip 1179 */ 1180 static void 1181 ipw2100_hwconf_get(struct ipw2100_softc *sc) 1182 { 1183 int i; 1184 uint16_t val; 1185 1186 /* 1187 * MAC address 1188 */ 1189 i = 0; 1190 val = ipw2100_rom_get16(sc, IPW2100_ROM_MAC + 0); 1191 sc->sc_macaddr[i++] = val >> 8; 1192 sc->sc_macaddr[i++] = val & 0xff; 1193 val = ipw2100_rom_get16(sc, IPW2100_ROM_MAC + 1); 1194 sc->sc_macaddr[i++] = val >> 8; 1195 sc->sc_macaddr[i++] = val & 0xff; 1196 val = ipw2100_rom_get16(sc, IPW2100_ROM_MAC + 2); 1197 sc->sc_macaddr[i++] = val >> 8; 1198 sc->sc_macaddr[i++] = val & 0xff; 1199 1200 /* 1201 * formatted MAC address string 1202 */ 1203 (void) snprintf(sc->sc_macstr, sizeof (sc->sc_macstr), 1204 "%02x:%02x:%02x:%02x:%02x:%02x", 1205 sc->sc_macaddr[0], sc->sc_macaddr[1], 1206 sc->sc_macaddr[2], sc->sc_macaddr[3], 1207 sc->sc_macaddr[4], sc->sc_macaddr[5]); 1208 1209 /* 1210 * channel mask 1211 */ 1212 val = ipw2100_rom_get16(sc, IPW2100_ROM_CHANNEL_LIST); 1213 if (val == 0) 1214 val = 0x7ff; 1215 sc->sc_chmask = val << 1; 1216 IPW2100_DBG(IPW2100_DBG_HWCAP, (sc->sc_dip, CE_CONT, 1217 "ipw2100_hwconf_get(): channel-mask=0x%08x\n", sc->sc_chmask)); 1218 1219 /* 1220 * radio switch 1221 */ 1222 val = ipw2100_rom_get16(sc, IPW2100_ROM_RADIO); 1223 if (val & 0x08) 1224 sc->sc_flags |= IPW2100_FLAG_HAS_RADIO_SWITCH; 1225 1226 IPW2100_DBG(IPW2100_DBG_HWCAP, (sc->sc_dip, CE_CONT, 1227 "ipw2100_hwconf_get(): has-radio-switch=%s(%u)\n", 1228 (sc->sc_flags & IPW2100_FLAG_HAS_RADIO_SWITCH)? "yes" : "no", 1229 val)); 1230 } 1231 1232 /* 1233 * all ipw2100 interrupts will be masked by this routine 1234 */ 1235 static void 1236 ipw2100_master_stop(struct ipw2100_softc *sc) 1237 { 1238 uint32_t tmp; 1239 int ntries; 1240 1241 /* 1242 * disable interrupts 1243 */ 1244 ipw2100_csr_put32(sc, IPW2100_CSR_INTR_MASK, 0); 1245 1246 ipw2100_csr_put32(sc, IPW2100_CSR_RST, IPW2100_RST_STOP_MASTER); 1247 for (ntries = 0; ntries < 50; ntries++) { 1248 if (ipw2100_csr_get32(sc, IPW2100_CSR_RST) 1249 & IPW2100_RST_MASTER_DISABLED) 1250 break; 1251 drv_usecwait(10); 1252 } 1253 if (ntries == 50 && !(sc->sc_flags & IPW2100_FLAG_QUIESCED)) 1254 IPW2100_WARN((sc->sc_dip, CE_WARN, 1255 "ipw2100_master_stop(): timeout when stop master\n")); 1256 1257 tmp = ipw2100_csr_get32(sc, IPW2100_CSR_RST); 1258 ipw2100_csr_put32(sc, IPW2100_CSR_RST, 1259 tmp | IPW2100_RST_PRINCETON_RESET); 1260 1261 sc->sc_flags &= ~IPW2100_FLAG_FW_INITED; 1262 } 1263 1264 /* 1265 * all ipw2100 interrupts will be masked by this routine 1266 */ 1267 static int 1268 ipw2100_chip_reset(struct ipw2100_softc *sc) 1269 { 1270 int ntries; 1271 uint32_t tmp; 1272 1273 ipw2100_master_stop(sc); 1274 1275 /* 1276 * move adatper to DO state 1277 */ 1278 tmp = ipw2100_csr_get32(sc, IPW2100_CSR_CTL); 1279 ipw2100_csr_put32(sc, IPW2100_CSR_CTL, tmp | IPW2100_CTL_INIT); 1280 1281 /* 1282 * wait for clock stabilization 1283 */ 1284 for (ntries = 0; ntries < 1000; ntries++) { 1285 if (ipw2100_csr_get32(sc, IPW2100_CSR_CTL) 1286 & IPW2100_CTL_CLOCK_READY) 1287 break; 1288 drv_usecwait(200); 1289 } 1290 if (ntries == 1000) 1291 return (DDI_FAILURE); 1292 1293 tmp = ipw2100_csr_get32(sc, IPW2100_CSR_RST); 1294 ipw2100_csr_put32(sc, IPW2100_CSR_RST, tmp | IPW2100_RST_SW_RESET); 1295 1296 drv_usecwait(10); 1297 1298 tmp = ipw2100_csr_get32(sc, IPW2100_CSR_CTL); 1299 ipw2100_csr_put32(sc, IPW2100_CSR_CTL, tmp | IPW2100_CTL_INIT); 1300 1301 return (DDI_SUCCESS); 1302 } 1303 1304 /* 1305 * get the radio status from IPW_CSR_IO, invoked by wificonfig/dladm 1306 */ 1307 int 1308 ipw2100_get_radio(struct ipw2100_softc *sc) 1309 { 1310 if (ipw2100_csr_get32(sc, IPW2100_CSR_IO) & IPW2100_IO_RADIO_DISABLED) 1311 return (0); 1312 else 1313 return (1); 1314 1315 } 1316 /* 1317 * This function is used to get the statistic, invoked by wificonfig/dladm 1318 */ 1319 void 1320 ipw2100_get_statistics(struct ipw2100_softc *sc) 1321 { 1322 struct ieee80211com *ic = &sc->sc_ic; 1323 uint32_t addr, size, i; 1324 uint32_t atbl[256], *datatbl; 1325 1326 datatbl = atbl; 1327 1328 if (!(sc->sc_flags & IPW2100_FLAG_FW_INITED)) { 1329 IPW2100_DBG(IPW2100_DBG_STATISTIC, (sc->sc_dip, CE_CONT, 1330 "ipw2100_get_statistic(): fw doesn't download yet.")); 1331 return; 1332 } 1333 1334 ipw2100_csr_put32(sc, IPW2100_CSR_AUTOINC_ADDR, sc->sc_table1_base); 1335 1336 size = ipw2100_csr_get32(sc, IPW2100_CSR_AUTOINC_DATA); 1337 atbl[0] = size; 1338 for (i = 1, ++datatbl; i < size; i++, datatbl++) { 1339 addr = ipw2100_csr_get32(sc, IPW2100_CSR_AUTOINC_DATA); 1340 *datatbl = ipw2100_imem_get32(sc, addr); 1341 } 1342 1343 /* 1344 * To retrieve the statistic information into proper places. There are 1345 * lot of information. 1346 */ 1347 IPW2100_DBG(IPW2100_DBG_STATISTIC, (sc->sc_dip, CE_CONT, 1348 "ipw2100_get_statistic(): \n" 1349 "operating mode = %u\n" 1350 "type of authentification= %u\n" 1351 "average RSSI= %u\n" 1352 "current channel = %d\n", 1353 atbl[191], atbl[199], atbl[173], atbl[189])); 1354 /* WIFI_STAT_TX_FRAGS */ 1355 ic->ic_stats.is_tx_frags = (uint32_t)atbl[2]; 1356 /* WIFI_STAT_MCAST_TX = (all frame - unicast frame) */ 1357 ic->ic_stats.is_tx_mcast = (uint32_t)atbl[2] - (uint32_t)atbl[3]; 1358 /* WIFI_STAT_TX_RETRANS */ 1359 ic->ic_stats.is_tx_retries = (uint32_t)atbl[42]; 1360 /* WIFI_STAT_TX_FAILED */ 1361 ic->ic_stats.is_tx_failed = (uint32_t)atbl[51]; 1362 /* MAC_STAT_OBYTES */ 1363 ic->ic_stats.is_tx_bytes = (uint32_t)atbl[41]; 1364 /* WIFI_STAT_RX_FRAGS */ 1365 ic->ic_stats.is_rx_frags = (uint32_t)atbl[61]; 1366 /* WIFI_STAT_MCAST_RX */ 1367 ic->ic_stats.is_rx_mcast = (uint32_t)atbl[71]; 1368 /* MAC_STAT_IBYTES */ 1369 ic->ic_stats.is_rx_bytes = (uint32_t)atbl[101]; 1370 /* WIFI_STAT_ACK_FAILURE */ 1371 ic->ic_stats.is_ack_failure = (uint32_t)atbl[59]; 1372 /* WIFI_STAT_RTS_SUCCESS */ 1373 ic->ic_stats.is_rts_success = (uint32_t)atbl[22]; 1374 } 1375 1376 /* 1377 * dma region alloc 1378 */ 1379 static int 1380 ipw2100_dma_region_alloc(struct ipw2100_softc *sc, 1381 struct dma_region *dr, size_t size, uint_t dir, uint_t flags) 1382 { 1383 dev_info_t *dip = sc->sc_dip; 1384 int err; 1385 1386 IPW2100_DBG(IPW2100_DBG_DMA, (dip, CE_CONT, 1387 "ipw2100_dma_region_alloc() name=%s size=%u\n", 1388 dr->dr_name, size)); 1389 1390 err = ddi_dma_alloc_handle(dip, &ipw2100_dma_attr, DDI_DMA_SLEEP, NULL, 1391 &dr->dr_hnd); 1392 if (err != DDI_SUCCESS) { 1393 IPW2100_DBG(IPW2100_DBG_DMA, (dip, CE_CONT, 1394 "ipw2100_dma_region_alloc(): " 1395 "ddi_dma_alloc_handle() failed\n")); 1396 goto fail0; 1397 } 1398 1399 err = ddi_dma_mem_alloc(dr->dr_hnd, size, &ipw2100_dma_accattr, 1400 flags, DDI_DMA_SLEEP, NULL, &dr->dr_base, 1401 &dr->dr_size, &dr->dr_acc); 1402 if (err != DDI_SUCCESS) { 1403 IPW2100_DBG(IPW2100_DBG_DMA, (dip, CE_CONT, 1404 "ipw2100_dma_region_alloc(): " 1405 "ddi_dma_mem_alloc() failed\n")); 1406 goto fail1; 1407 } 1408 1409 err = ddi_dma_addr_bind_handle(dr->dr_hnd, NULL, 1410 dr->dr_base, dr->dr_size, dir | flags, DDI_DMA_SLEEP, NULL, 1411 &dr->dr_cookie, &dr->dr_ccnt); 1412 if (err != DDI_DMA_MAPPED) { 1413 IPW2100_DBG(IPW2100_DBG_DMA, (dip, CE_CONT, 1414 "ipw2100_dma_region_alloc(): " 1415 "ddi_dma_addr_bind_handle() failed\n")); 1416 goto fail2; 1417 } 1418 1419 if (dr->dr_ccnt != 1) { 1420 err = DDI_FAILURE; 1421 goto fail3; 1422 } 1423 dr->dr_pbase = dr->dr_cookie.dmac_address; 1424 1425 IPW2100_DBG(IPW2100_DBG_DMA, (dip, CE_CONT, 1426 "ipw2100_dma_region_alloc(): get physical-base=0x%08x\n", 1427 dr->dr_pbase)); 1428 1429 return (DDI_SUCCESS); 1430 1431 fail3: 1432 (void) ddi_dma_unbind_handle(dr->dr_hnd); 1433 fail2: 1434 ddi_dma_mem_free(&dr->dr_acc); 1435 fail1: 1436 ddi_dma_free_handle(&dr->dr_hnd); 1437 fail0: 1438 return (err); 1439 } 1440 1441 static void 1442 ipw2100_dma_region_free(struct dma_region *dr) 1443 { 1444 (void) ddi_dma_unbind_handle(dr->dr_hnd); 1445 ddi_dma_mem_free(&dr->dr_acc); 1446 ddi_dma_free_handle(&dr->dr_hnd); 1447 } 1448 1449 static int 1450 ipw2100_ring_alloc(struct ipw2100_softc *sc) 1451 { 1452 int err, i; 1453 1454 /* 1455 * tx ring 1456 */ 1457 sc->sc_dma_txbd.dr_name = "ipw2100-tx-ring-bd"; 1458 err = ipw2100_dma_region_alloc(sc, &sc->sc_dma_txbd, 1459 IPW2100_TXBD_SIZE, DDI_DMA_WRITE, DDI_DMA_CONSISTENT); 1460 if (err != DDI_SUCCESS) 1461 goto fail0; 1462 /* 1463 * tx bufs 1464 */ 1465 for (i = 0; i < IPW2100_NUM_TXBUF; i++) { 1466 sc->sc_dma_txbufs[i].dr_name = "ipw2100-tx-buf"; 1467 err = ipw2100_dma_region_alloc(sc, &sc->sc_dma_txbufs[i], 1468 IPW2100_TXBUF_SIZE, DDI_DMA_WRITE, DDI_DMA_STREAMING); 1469 if (err != DDI_SUCCESS) { 1470 while (i > 0) { 1471 i--; 1472 ipw2100_dma_region_free(&sc->sc_dma_txbufs[i]); 1473 } 1474 goto fail1; 1475 } 1476 } 1477 /* 1478 * rx ring 1479 */ 1480 sc->sc_dma_rxbd.dr_name = "ipw2100-rx-ring-bd"; 1481 err = ipw2100_dma_region_alloc(sc, &sc->sc_dma_rxbd, 1482 IPW2100_RXBD_SIZE, DDI_DMA_WRITE, DDI_DMA_CONSISTENT); 1483 if (err != DDI_SUCCESS) 1484 goto fail2; 1485 /* 1486 * rx bufs 1487 */ 1488 for (i = 0; i < IPW2100_NUM_RXBUF; i++) { 1489 sc->sc_dma_rxbufs[i].dr_name = "ipw2100-rx-buf"; 1490 err = ipw2100_dma_region_alloc(sc, &sc->sc_dma_rxbufs[i], 1491 IPW2100_RXBUF_SIZE, DDI_DMA_READ, DDI_DMA_STREAMING); 1492 if (err != DDI_SUCCESS) { 1493 while (i > 0) { 1494 i--; 1495 ipw2100_dma_region_free(&sc->sc_dma_rxbufs[i]); 1496 } 1497 goto fail3; 1498 } 1499 } 1500 /* 1501 * status 1502 */ 1503 sc->sc_dma_status.dr_name = "ipw2100-rx-status"; 1504 err = ipw2100_dma_region_alloc(sc, &sc->sc_dma_status, 1505 IPW2100_STATUS_SIZE, DDI_DMA_READ, DDI_DMA_CONSISTENT); 1506 if (err != DDI_SUCCESS) 1507 goto fail4; 1508 /* 1509 * command 1510 */ 1511 sc->sc_dma_cmd.dr_name = "ipw2100-cmd"; 1512 err = ipw2100_dma_region_alloc(sc, &sc->sc_dma_cmd, IPW2100_CMD_SIZE, 1513 DDI_DMA_WRITE, DDI_DMA_CONSISTENT); 1514 if (err != DDI_SUCCESS) 1515 goto fail5; 1516 1517 return (DDI_SUCCESS); 1518 1519 fail5: 1520 ipw2100_dma_region_free(&sc->sc_dma_status); 1521 fail4: 1522 for (i = 0; i < IPW2100_NUM_RXBUF; i++) 1523 ipw2100_dma_region_free(&sc->sc_dma_rxbufs[i]); 1524 fail3: 1525 ipw2100_dma_region_free(&sc->sc_dma_rxbd); 1526 fail2: 1527 for (i = 0; i < IPW2100_NUM_TXBUF; i++) 1528 ipw2100_dma_region_free(&sc->sc_dma_txbufs[i]); 1529 fail1: 1530 ipw2100_dma_region_free(&sc->sc_dma_txbd); 1531 fail0: 1532 return (err); 1533 } 1534 1535 static void 1536 ipw2100_ring_free(struct ipw2100_softc *sc) 1537 { 1538 int i; 1539 1540 /* 1541 * tx ring 1542 */ 1543 ipw2100_dma_region_free(&sc->sc_dma_txbd); 1544 /* 1545 * tx buf 1546 */ 1547 for (i = 0; i < IPW2100_NUM_TXBUF; i++) 1548 ipw2100_dma_region_free(&sc->sc_dma_txbufs[i]); 1549 /* 1550 * rx ring 1551 */ 1552 ipw2100_dma_region_free(&sc->sc_dma_rxbd); 1553 /* 1554 * rx buf 1555 */ 1556 for (i = 0; i < IPW2100_NUM_RXBUF; i++) 1557 ipw2100_dma_region_free(&sc->sc_dma_rxbufs[i]); 1558 /* 1559 * status 1560 */ 1561 ipw2100_dma_region_free(&sc->sc_dma_status); 1562 /* 1563 * command 1564 */ 1565 ipw2100_dma_region_free(&sc->sc_dma_cmd); 1566 } 1567 1568 static void 1569 ipw2100_ring_reset(struct ipw2100_softc *sc) 1570 { 1571 int i; 1572 1573 /* 1574 * tx ring 1575 */ 1576 sc->sc_tx_cur = 0; 1577 sc->sc_tx_free = IPW2100_NUM_TXBD; 1578 sc->sc_txbd = (struct ipw2100_bd *)sc->sc_dma_txbd.dr_base; 1579 for (i = 0; i < IPW2100_NUM_TXBUF; i++) 1580 sc->sc_txbufs[i] = 1581 (struct ipw2100_txb *)sc->sc_dma_txbufs[i].dr_base; 1582 /* 1583 * rx ring 1584 */ 1585 sc->sc_rx_cur = 0; 1586 sc->sc_rx_free = IPW2100_NUM_RXBD; 1587 sc->sc_status = (struct ipw2100_status *)sc->sc_dma_status.dr_base; 1588 sc->sc_rxbd = (struct ipw2100_bd *)sc->sc_dma_rxbd.dr_base; 1589 for (i = 0; i < IPW2100_NUM_RXBUF; i++) { 1590 sc->sc_rxbufs[i] = 1591 (struct ipw2100_rxb *)sc->sc_dma_rxbufs[i].dr_base; 1592 /* 1593 * initialize Rx buffer descriptors, both host and device 1594 */ 1595 sc->sc_rxbd[i].phyaddr = LE_32(sc->sc_dma_rxbufs[i].dr_pbase); 1596 sc->sc_rxbd[i].len = LE_32(sc->sc_dma_rxbufs[i].dr_size); 1597 sc->sc_rxbd[i].flags = 0; 1598 sc->sc_rxbd[i].nfrag = 1; 1599 } 1600 /* 1601 * command 1602 */ 1603 sc->sc_cmd = (struct ipw2100_cmd *)sc->sc_dma_cmd.dr_base; 1604 } 1605 1606 /* 1607 * tx, rx rings and command initialization 1608 */ 1609 static int 1610 ipw2100_ring_init(struct ipw2100_softc *sc) 1611 { 1612 int err; 1613 1614 err = ipw2100_ring_alloc(sc); 1615 if (err != DDI_SUCCESS) 1616 return (err); 1617 1618 ipw2100_ring_reset(sc); 1619 1620 return (DDI_SUCCESS); 1621 } 1622 1623 static void 1624 ipw2100_ring_hwsetup(struct ipw2100_softc *sc) 1625 { 1626 ipw2100_ring_reset(sc); 1627 /* 1628 * tx ring 1629 */ 1630 ipw2100_csr_put32(sc, IPW2100_CSR_TX_BD_BASE, sc->sc_dma_txbd.dr_pbase); 1631 ipw2100_csr_put32(sc, IPW2100_CSR_TX_BD_SIZE, IPW2100_NUM_TXBD); 1632 /* 1633 * no new packet to transmit, tx-rd-index == tx-wr-index 1634 */ 1635 ipw2100_csr_put32(sc, IPW2100_CSR_TX_READ_INDEX, sc->sc_tx_cur); 1636 ipw2100_csr_put32(sc, IPW2100_CSR_TX_WRITE_INDEX, sc->sc_tx_cur); 1637 /* 1638 * rx ring 1639 */ 1640 ipw2100_csr_put32(sc, IPW2100_CSR_RX_BD_BASE, sc->sc_dma_rxbd.dr_pbase); 1641 ipw2100_csr_put32(sc, IPW2100_CSR_RX_BD_SIZE, IPW2100_NUM_RXBD); 1642 /* 1643 * all rx buffer are empty, rx-rd-index == 0 && rx-wr-index == N-1 1644 */ 1645 IPW2100_DBG(IPW2100_DBG_RING, (sc->sc_dip, CE_CONT, 1646 "ipw2100_ring_hwsetup(): rx-cur=%u, backward=%u\n", 1647 sc->sc_rx_cur, RING_BACKWARD(sc->sc_rx_cur, 1, IPW2100_NUM_RXBD))); 1648 ipw2100_csr_put32(sc, IPW2100_CSR_RX_READ_INDEX, sc->sc_rx_cur); 1649 ipw2100_csr_put32(sc, IPW2100_CSR_RX_WRITE_INDEX, 1650 RING_BACKWARD(sc->sc_rx_cur, 1, IPW2100_NUM_RXBD)); 1651 /* 1652 * status 1653 */ 1654 ipw2100_csr_put32(sc, IPW2100_CSR_RX_STATUS_BASE, 1655 sc->sc_dma_status.dr_pbase); 1656 } 1657 1658 /* 1659 * ieee80211_new_state() is not be used, since the hardware can handle the 1660 * state transfer. Here, we just keep the status of the hardware notification 1661 * result. 1662 */ 1663 /* ARGSUSED */ 1664 static int 1665 ipw2100_newstate(struct ieee80211com *ic, enum ieee80211_state state, int arg) 1666 { 1667 struct ipw2100_softc *sc = (struct ipw2100_softc *)ic; 1668 struct ieee80211_node *in; 1669 uint8_t macaddr[IEEE80211_ADDR_LEN]; 1670 uint32_t len; 1671 wifi_data_t wd = { 0 }; 1672 1673 IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT, 1674 "ipw2100_newstate(): %s -> %s\n", 1675 ieee80211_state_name[ic->ic_state], ieee80211_state_name[state])); 1676 1677 switch (state) { 1678 case IEEE80211_S_RUN: 1679 /* 1680 * we only need to use BSSID as to find the node 1681 */ 1682 drv_usecwait(200); /* firmware needs a short delay here */ 1683 len = IEEE80211_ADDR_LEN; 1684 (void) ipw2100_table2_getbuf(sc, IPW2100_INFO_CURRENT_BSSID, 1685 macaddr, &len); 1686 1687 in = ieee80211_find_node(&ic->ic_scan, macaddr); 1688 if (in == NULL) 1689 break; 1690 1691 (void) ieee80211_sta_join(ic, in); 1692 ieee80211_node_authorize(in); 1693 1694 /* 1695 * We can send data now; update the fastpath with our 1696 * current associated BSSID. 1697 */ 1698 if (ic->ic_flags & IEEE80211_F_PRIVACY) 1699 wd.wd_secalloc = WIFI_SEC_WEP; 1700 else 1701 wd.wd_secalloc = WIFI_SEC_NONE; 1702 wd.wd_opmode = ic->ic_opmode; 1703 IEEE80211_ADDR_COPY(wd.wd_bssid, ic->ic_bss->in_bssid); 1704 (void) mac_pdata_update(ic->ic_mach, &wd, sizeof (wd)); 1705 1706 break; 1707 1708 case IEEE80211_S_INIT: 1709 case IEEE80211_S_SCAN: 1710 case IEEE80211_S_AUTH: 1711 case IEEE80211_S_ASSOC: 1712 break; 1713 } 1714 1715 /* 1716 * notify to update the link 1717 */ 1718 if ((ic->ic_state != IEEE80211_S_RUN) && (state == IEEE80211_S_RUN)) { 1719 /* 1720 * previously disconnected and now connected 1721 */ 1722 sc->sc_linkstate = LINK_STATE_UP; 1723 sc->sc_flags |= IPW2100_FLAG_LINK_CHANGE; 1724 } else if ((ic->ic_state == IEEE80211_S_RUN) && 1725 (state != IEEE80211_S_RUN)) { 1726 /* 1727 * previously connected andd now disconnected 1728 */ 1729 sc->sc_linkstate = LINK_STATE_DOWN; 1730 sc->sc_flags |= IPW2100_FLAG_LINK_CHANGE; 1731 } 1732 1733 ic->ic_state = state; 1734 return (DDI_SUCCESS); 1735 } 1736 1737 /* 1738 * GLD operations 1739 */ 1740 /* ARGSUSED */ 1741 static int 1742 ipw2100_m_stat(void *arg, uint_t stat, uint64_t *val) 1743 { 1744 ieee80211com_t *ic = (ieee80211com_t *)arg; 1745 IPW2100_DBG(IPW2100_DBG_GLD, (((struct ipw2100_softc *)arg)->sc_dip, 1746 CE_CONT, 1747 "ipw2100_m_stat(): enter\n")); 1748 /* 1749 * some of below statistic data are from hardware, some from net80211 1750 */ 1751 switch (stat) { 1752 case MAC_STAT_RBYTES: 1753 *val = ic->ic_stats.is_rx_bytes; 1754 break; 1755 case MAC_STAT_IPACKETS: 1756 *val = ic->ic_stats.is_rx_frags; 1757 break; 1758 case MAC_STAT_OBYTES: 1759 *val = ic->ic_stats.is_tx_bytes; 1760 break; 1761 case MAC_STAT_OPACKETS: 1762 *val = ic->ic_stats.is_tx_frags; 1763 break; 1764 /* 1765 * Get below from hardware statistic, retrieve net80211 value once 1s 1766 */ 1767 case WIFI_STAT_TX_FRAGS: 1768 case WIFI_STAT_MCAST_TX: 1769 case WIFI_STAT_TX_FAILED: 1770 case WIFI_STAT_TX_RETRANS: 1771 case WIFI_STAT_RTS_SUCCESS: 1772 case WIFI_STAT_ACK_FAILURE: 1773 case WIFI_STAT_RX_FRAGS: 1774 case WIFI_STAT_MCAST_RX: 1775 /* 1776 * Get blow information from net80211 1777 */ 1778 case WIFI_STAT_RTS_FAILURE: 1779 case WIFI_STAT_RX_DUPS: 1780 case WIFI_STAT_FCS_ERRORS: 1781 case WIFI_STAT_WEP_ERRORS: 1782 return (ieee80211_stat(ic, stat, val)); 1783 /* 1784 * need be supported in the future 1785 */ 1786 case MAC_STAT_IFSPEED: 1787 case MAC_STAT_NOXMTBUF: 1788 case MAC_STAT_IERRORS: 1789 case MAC_STAT_OERRORS: 1790 default: 1791 return (ENOTSUP); 1792 } 1793 return (0); 1794 } 1795 1796 /* ARGSUSED */ 1797 static int 1798 ipw2100_m_multicst(void *arg, boolean_t add, const uint8_t *mca) 1799 { 1800 /* not supported */ 1801 IPW2100_DBG(IPW2100_DBG_GLD, (((struct ipw2100_softc *)arg)->sc_dip, 1802 CE_CONT, 1803 "ipw2100_m_multicst(): enter\n")); 1804 1805 return (0); 1806 } 1807 1808 /* 1809 * This thread function is used to handle the fatal error. 1810 */ 1811 static void 1812 ipw2100_thread(struct ipw2100_softc *sc) 1813 { 1814 struct ieee80211com *ic = &sc->sc_ic; 1815 int32_t nlstate; 1816 int stat_cnt = 0; 1817 1818 IPW2100_DBG(IPW2100_DBG_SOFTINT, (sc->sc_dip, CE_CONT, 1819 "ipw2100_thread(): into ipw2100 thread--> %d\n", 1820 sc->sc_linkstate)); 1821 1822 mutex_enter(&sc->sc_mflock); 1823 1824 while (sc->sc_mfthread_switch) { 1825 /* 1826 * notify the link state 1827 */ 1828 if (ic->ic_mach && (sc->sc_flags & IPW2100_FLAG_LINK_CHANGE)) { 1829 IPW2100_DBG(IPW2100_DBG_SOFTINT, (sc->sc_dip, CE_CONT, 1830 "ipw2100_thread(): link status --> %d\n", 1831 sc->sc_linkstate)); 1832 1833 sc->sc_flags &= ~IPW2100_FLAG_LINK_CHANGE; 1834 nlstate = sc->sc_linkstate; 1835 1836 mutex_exit(&sc->sc_mflock); 1837 mac_link_update(ic->ic_mach, nlstate); 1838 mutex_enter(&sc->sc_mflock); 1839 } 1840 1841 /* 1842 * recovery interrupt fatal error 1843 */ 1844 if (ic->ic_mach && 1845 (sc->sc_flags & IPW2100_FLAG_HW_ERR_RECOVER)) { 1846 1847 IPW2100_DBG(IPW2100_DBG_FATAL, (sc->sc_dip, CE_CONT, 1848 "try to recover fatal hw error\n")); 1849 sc->sc_flags &= ~IPW2100_FLAG_HW_ERR_RECOVER; 1850 1851 mutex_exit(&sc->sc_mflock); 1852 (void) ipw2100_init(sc); /* Force stat machine */ 1853 delay(drv_usectohz(delay_fatal_recover)); 1854 mutex_enter(&sc->sc_mflock); 1855 } 1856 1857 /* 1858 * get statistic, the value will be retrieved by m_stat 1859 */ 1860 if (stat_cnt == 10) { 1861 stat_cnt = 0; /* re-start */ 1862 1863 mutex_exit(&sc->sc_mflock); 1864 ipw2100_get_statistics(sc); 1865 mutex_enter(&sc->sc_mflock); 1866 } else 1867 stat_cnt++; /* until 1s */ 1868 1869 mutex_exit(&sc->sc_mflock); 1870 delay(drv_usectohz(delay_aux_thread)); 1871 mutex_enter(&sc->sc_mflock); 1872 } 1873 sc->sc_mf_thread = NULL; 1874 cv_broadcast(&sc->sc_mfthread_cv); 1875 mutex_exit(&sc->sc_mflock); 1876 } 1877 1878 static int 1879 ipw2100_m_start(void *arg) 1880 { 1881 struct ipw2100_softc *sc = (struct ipw2100_softc *)arg; 1882 1883 IPW2100_DBG(IPW2100_DBG_GLD, (sc->sc_dip, CE_CONT, 1884 "ipw2100_m_start(): enter\n")); 1885 1886 /* 1887 * initialize ipw2100 hardware 1888 */ 1889 (void) ipw2100_init(sc); 1890 1891 sc->sc_flags |= IPW2100_FLAG_RUNNING; 1892 /* 1893 * fix KCF bug. - workaround, need to fix it in net80211 1894 */ 1895 (void) crypto_mech2id(SUN_CKM_RC4); 1896 1897 return (0); 1898 } 1899 1900 static void 1901 ipw2100_m_stop(void *arg) 1902 { 1903 struct ipw2100_softc *sc = (struct ipw2100_softc *)arg; 1904 1905 IPW2100_DBG(IPW2100_DBG_GLD, (sc->sc_dip, CE_CONT, 1906 "ipw2100_m_stop(): enter\n")); 1907 1908 ipw2100_stop(sc); 1909 1910 sc->sc_flags &= ~IPW2100_FLAG_RUNNING; 1911 } 1912 1913 static int 1914 ipw2100_m_unicst(void *arg, const uint8_t *macaddr) 1915 { 1916 struct ipw2100_softc *sc = (struct ipw2100_softc *)arg; 1917 struct ieee80211com *ic = &sc->sc_ic; 1918 int err; 1919 1920 IPW2100_DBG(IPW2100_DBG_GLD, (sc->sc_dip, CE_CONT, 1921 "ipw2100_m_unicst(): enter\n")); 1922 1923 IPW2100_DBG(IPW2100_DBG_GLD, (sc->sc_dip, CE_CONT, 1924 "ipw2100_m_unicst(): GLD setting MAC address to " 1925 "%02x:%02x:%02x:%02x:%02x:%02x\n", 1926 macaddr[0], macaddr[1], macaddr[2], 1927 macaddr[3], macaddr[4], macaddr[5])); 1928 1929 if (!IEEE80211_ADDR_EQ(ic->ic_macaddr, macaddr)) { 1930 IEEE80211_ADDR_COPY(ic->ic_macaddr, macaddr); 1931 1932 if (sc->sc_flags & IPW2100_FLAG_RUNNING) { 1933 err = ipw2100_config(sc); 1934 if (err != DDI_SUCCESS) { 1935 IPW2100_WARN((sc->sc_dip, CE_WARN, 1936 "ipw2100_m_unicst(): " 1937 "device configuration failed\n")); 1938 goto fail; 1939 } 1940 } 1941 } 1942 1943 return (0); 1944 fail: 1945 return (EIO); 1946 } 1947 1948 static int 1949 ipw2100_m_promisc(void *arg, boolean_t on) 1950 { 1951 struct ipw2100_softc *sc = (struct ipw2100_softc *)arg; 1952 int recfg, err; 1953 1954 IPW2100_DBG(IPW2100_DBG_GLD, (sc->sc_dip, CE_CONT, 1955 "ipw2100_m_promisc(): enter. " 1956 "GLD setting promiscuous mode - %d\n", on)); 1957 1958 recfg = 0; 1959 if (on) 1960 if (!(sc->if_flags & IFF_PROMISC)) { 1961 sc->if_flags |= IFF_PROMISC; 1962 recfg = 1; 1963 } 1964 else 1965 if (sc->if_flags & IFF_PROMISC) { 1966 sc->if_flags &= ~IFF_PROMISC; 1967 recfg = 1; 1968 } 1969 1970 if (recfg && (sc->sc_flags & IPW2100_FLAG_RUNNING)) { 1971 err = ipw2100_config(sc); 1972 if (err != DDI_SUCCESS) { 1973 IPW2100_WARN((sc->sc_dip, CE_WARN, 1974 "ipw2100_m_promisc(): " 1975 "device configuration failed\n")); 1976 goto fail; 1977 } 1978 } 1979 1980 return (0); 1981 fail: 1982 return (EIO); 1983 } 1984 1985 static mblk_t * 1986 ipw2100_m_tx(void *arg, mblk_t *mp) 1987 { 1988 struct ipw2100_softc *sc = (struct ipw2100_softc *)arg; 1989 struct ieee80211com *ic = &sc->sc_ic; 1990 mblk_t *next; 1991 1992 /* 1993 * No data frames go out unless we're associated; this 1994 * should not happen as the 802.11 layer does not enable 1995 * the xmit queue until we enter the RUN state. 1996 */ 1997 if (ic->ic_state != IEEE80211_S_RUN) { 1998 IPW2100_DBG(IPW2100_DBG_GLD, (sc->sc_dip, CE_CONT, 1999 "ipw2100_m_tx(): discard msg, ic_state = %u\n", 2000 ic->ic_state)); 2001 freemsgchain(mp); 2002 return (NULL); 2003 } 2004 2005 while (mp != NULL) { 2006 next = mp->b_next; 2007 mp->b_next = NULL; 2008 if (ipw2100_send(ic, mp, IEEE80211_FC0_TYPE_DATA) != 2009 DDI_SUCCESS) { 2010 mp->b_next = next; 2011 break; 2012 } 2013 mp = next; 2014 } 2015 return (mp); 2016 } 2017 2018 /* ARGSUSED */ 2019 static int 2020 ipw2100_send(ieee80211com_t *ic, mblk_t *mp, uint8_t type) 2021 { 2022 struct ipw2100_softc *sc = (struct ipw2100_softc *)ic; 2023 struct ieee80211_node *in; 2024 struct ieee80211_frame wh, *wh_tmp; 2025 struct ieee80211_key *k; 2026 uint8_t *hdat; 2027 mblk_t *m0, *m; 2028 size_t cnt, off; 2029 struct ipw2100_bd *txbd[2]; 2030 struct ipw2100_txb *txbuf; 2031 struct dma_region *dr; 2032 struct ipw2100_hdr *h; 2033 uint32_t idx, bidx; 2034 int err; 2035 2036 ASSERT(mp->b_next == NULL); 2037 2038 m0 = NULL; 2039 m = NULL; 2040 err = DDI_SUCCESS; 2041 2042 IPW2100_DBG(IPW2100_DBG_GLD, (sc->sc_dip, CE_CONT, 2043 "ipw2100_send(): enter\n")); 2044 2045 if ((type & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_DATA) { 2046 /* 2047 * it is impossible to send non-data 802.11 frame in current 2048 * ipw driver. Therefore, drop the package 2049 */ 2050 freemsg(mp); 2051 err = DDI_SUCCESS; 2052 goto fail0; 2053 } 2054 2055 mutex_enter(&sc->sc_tx_lock); 2056 2057 /* 2058 * need 2 descriptors: 1 for SEND cmd parameter header, 2059 * and the other for payload, i.e., 802.11 frame including 802.11 2060 * frame header 2061 */ 2062 if (sc->sc_tx_free < 2) { 2063 mutex_enter(&sc->sc_resched_lock); 2064 IPW2100_DBG(IPW2100_DBG_RING, (sc->sc_dip, CE_WARN, 2065 "ipw2100_send(): no enough descriptors(%d)\n", 2066 sc->sc_tx_free)); 2067 ic->ic_stats.is_tx_nobuf++; /* no enough buffer */ 2068 sc->sc_flags |= IPW2100_FLAG_TX_SCHED; 2069 err = DDI_FAILURE; 2070 mutex_exit(&sc->sc_resched_lock); 2071 goto fail1; 2072 } 2073 IPW2100_DBG(IPW2100_DBG_RING, (sc->sc_dip, CE_CONT, 2074 "ipw2100_send(): tx-free=%d,tx-curr=%d\n", 2075 sc->sc_tx_free, sc->sc_tx_cur)); 2076 2077 wh_tmp = (struct ieee80211_frame *)mp->b_rptr; 2078 in = ieee80211_find_txnode(ic, wh_tmp->i_addr1); 2079 if (in == NULL) { /* can not find tx node, drop the package */ 2080 freemsg(mp); 2081 err = DDI_SUCCESS; 2082 goto fail1; 2083 } 2084 in->in_inact = 0; 2085 (void) ieee80211_encap(ic, mp, in); 2086 ieee80211_free_node(in); 2087 2088 if (wh_tmp->i_fc[1] & IEEE80211_FC1_WEP) { 2089 /* 2090 * it is very bad that ieee80211_crypto_encap can only accept a 2091 * single continuous buffer. 2092 */ 2093 /* 2094 * allocate 32 more bytes is to be compatible with further 2095 * ieee802.11i standard. 2096 */ 2097 m = allocb(msgdsize(mp) + 32, BPRI_MED); 2098 if (m == NULL) { /* can not alloc buf, drop this package */ 2099 IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT, 2100 "ipw2100_send(): msg allocation failed\n")); 2101 2102 freemsg(mp); 2103 2104 err = DDI_SUCCESS; 2105 goto fail1; 2106 } 2107 off = 0; 2108 m0 = mp; 2109 while (m0) { 2110 cnt = MBLKL(m0); 2111 if (cnt) { 2112 (void) memcpy(m->b_rptr + off, m0->b_rptr, cnt); 2113 off += cnt; 2114 } 2115 m0 = m0->b_cont; 2116 } 2117 m->b_wptr += off; 2118 IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT, 2119 "ipw2100_send(): " 2120 "Encrypting 802.11 frame started, %d, %d\n", 2121 msgdsize(mp), MBLKL(mp))); 2122 k = ieee80211_crypto_encap(ic, m); 2123 if (k == NULL) { /* can not get the key, drop packages */ 2124 IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT, 2125 "ipw2100_send(): " 2126 "Encrypting 802.11 frame failed\n")); 2127 2128 freemsg(mp); 2129 err = DDI_SUCCESS; 2130 goto fail2; 2131 } 2132 IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT, 2133 "ipw2100_send(): " 2134 "Encrypting 802.11 frame finished, %d, %d, k=0x%08x\n", 2135 msgdsize(mp), MBLKL(mp), k->wk_flags)); 2136 } 2137 2138 /* 2139 * header descriptor 2140 */ 2141 idx = sc->sc_tx_cur; 2142 txbd[0] = &sc->sc_txbd[idx]; 2143 if ((idx & 1) == 0) 2144 bidx = idx / 2; 2145 sc->sc_tx_cur = RING_FORWARD(sc->sc_tx_cur, 1, IPW2100_NUM_TXBD); 2146 sc->sc_tx_free--; 2147 2148 /* 2149 * payload descriptor 2150 */ 2151 idx = sc->sc_tx_cur; 2152 txbd[1] = &sc->sc_txbd[idx]; 2153 if ((idx & 1) == 0) 2154 bidx = idx / 2; 2155 sc->sc_tx_cur = RING_FORWARD(sc->sc_tx_cur, 1, IPW2100_NUM_TXBD); 2156 sc->sc_tx_free--; 2157 2158 /* 2159 * one buffer, SEND cmd header and payload buffer 2160 */ 2161 txbuf = sc->sc_txbufs[bidx]; 2162 dr = &sc->sc_dma_txbufs[bidx]; 2163 2164 /* 2165 * extract 802.11 header from message, fill wh from m0 2166 */ 2167 hdat = (uint8_t *)&wh; 2168 off = 0; 2169 if (m) 2170 m0 = m; 2171 else 2172 m0 = mp; 2173 while (off < sizeof (wh)) { 2174 cnt = MBLKL(m0); 2175 if (cnt > (sizeof (wh) - off)) 2176 cnt = sizeof (wh) - off; 2177 if (cnt) { 2178 (void) memcpy(hdat + off, m0->b_rptr, cnt); 2179 off += cnt; 2180 m0->b_rptr += cnt; 2181 } 2182 else 2183 m0 = m0->b_cont; 2184 } 2185 2186 /* 2187 * prepare SEND cmd header 2188 */ 2189 h = &txbuf->txb_hdr; 2190 h->type = LE_32(IPW2100_CMD_SEND); 2191 h->subtype = LE_32(0); 2192 h->encrypted = ic->ic_flags & IEEE80211_F_PRIVACY ? 1 : 0; 2193 h->encrypt = 0; 2194 h->keyidx = 0; 2195 h->keysz = 0; 2196 h->fragsz = LE_16(0); 2197 IEEE80211_ADDR_COPY(h->saddr, wh.i_addr2); 2198 if (ic->ic_opmode == IEEE80211_M_STA) 2199 IEEE80211_ADDR_COPY(h->daddr, wh.i_addr3); 2200 else 2201 IEEE80211_ADDR_COPY(h->daddr, wh.i_addr1); 2202 2203 /* 2204 * extract payload from message into tx data buffer 2205 */ 2206 off = 0; 2207 while (m0) { 2208 cnt = MBLKL(m0); 2209 if (cnt) { 2210 (void) memcpy(&txbuf->txb_dat[off], m0->b_rptr, cnt); 2211 off += cnt; 2212 } 2213 m0 = m0->b_cont; 2214 } 2215 2216 /* 2217 * fill SEND cmd header descriptor 2218 */ 2219 txbd[0]->phyaddr = LE_32(dr->dr_pbase + 2220 OFFSETOF(struct ipw2100_txb, txb_hdr)); 2221 txbd[0]->len = LE_32(sizeof (struct ipw2100_hdr)); 2222 txbd[0]->flags = IPW2100_BD_FLAG_TX_FRAME_802_3 | 2223 IPW2100_BD_FLAG_TX_NOT_LAST_FRAGMENT; 2224 txbd[0]->nfrag = 2; 2225 /* 2226 * fill payload descriptor 2227 */ 2228 txbd[1]->phyaddr = LE_32(dr->dr_pbase + 2229 OFFSETOF(struct ipw2100_txb, txb_dat[0])); 2230 txbd[1]->len = LE_32(off); 2231 txbd[1]->flags = IPW2100_BD_FLAG_TX_FRAME_802_3 | 2232 IPW2100_BD_FLAG_TX_LAST_FRAGMENT; 2233 txbd[1]->nfrag = 0; 2234 2235 /* 2236 * dma sync 2237 */ 2238 (void) ddi_dma_sync(dr->dr_hnd, 0, sizeof (struct ipw2100_txb), 2239 DDI_DMA_SYNC_FORDEV); 2240 (void) ddi_dma_sync(sc->sc_dma_txbd.dr_hnd, 2241 (txbd[0] - sc->sc_txbd) * sizeof (struct ipw2100_bd), 2242 sizeof (struct ipw2100_bd), DDI_DMA_SYNC_FORDEV); 2243 /* 2244 * since txbd[1] may not be successive to txbd[0] due to the ring 2245 * organization, another dma_sync is needed to simplify the logic 2246 */ 2247 (void) ddi_dma_sync(sc->sc_dma_txbd.dr_hnd, 2248 (txbd[1] - sc->sc_txbd) * sizeof (struct ipw2100_bd), 2249 sizeof (struct ipw2100_bd), DDI_DMA_SYNC_FORDEV); 2250 /* 2251 * update txcur 2252 */ 2253 ipw2100_csr_put32(sc, IPW2100_CSR_TX_WRITE_INDEX, sc->sc_tx_cur); 2254 2255 if (mp) /* success, free the original message */ 2256 freemsg(mp); 2257 fail2: 2258 if (m) 2259 freemsg(m); 2260 fail1: 2261 mutex_exit(&sc->sc_tx_lock); 2262 fail0: 2263 IPW2100_DBG(IPW2100_DBG_GLD, (sc->sc_dip, CE_CONT, 2264 "ipw2100_send(): exit - err=%d\n", err)); 2265 2266 return (err); 2267 } 2268 2269 /* 2270 * IOCTL Handler 2271 */ 2272 #define IEEE80211_IOCTL_REQUIRED (1) 2273 #define IEEE80211_IOCTL_NOT_REQUIRED (0) 2274 static void 2275 ipw2100_m_ioctl(void *arg, queue_t *q, mblk_t *m) 2276 { 2277 struct ipw2100_softc *sc = (struct ipw2100_softc *)arg; 2278 struct ieee80211com *ic = &sc->sc_ic; 2279 int err; 2280 2281 IPW2100_DBG(IPW2100_DBG_GLD, (sc->sc_dip, CE_CONT, 2282 "ipw2100_m_ioctl(): enter\n")); 2283 2284 /* 2285 * check whether or not need to handle this in net80211 2286 */ 2287 if (ipw2100_ioctl(sc, q, m) == IEEE80211_IOCTL_NOT_REQUIRED) 2288 return; /* succes or fail */ 2289 2290 err = ieee80211_ioctl(ic, q, m); 2291 if (err == ENETRESET) { 2292 if (sc->sc_flags & IPW2100_FLAG_RUNNING) { 2293 (void) ipw2100_m_start(sc); 2294 (void) ieee80211_new_state(ic, 2295 IEEE80211_S_SCAN, -1); 2296 } 2297 } 2298 if (err == ERESTART) { 2299 if (sc->sc_flags & IPW2100_FLAG_RUNNING) 2300 (void) ipw2100_chip_reset(sc); 2301 } 2302 } 2303 2304 static int 2305 ipw2100_ioctl(struct ipw2100_softc *sc, queue_t *q, mblk_t *m) 2306 { 2307 struct iocblk *iocp; 2308 uint32_t len, ret, cmd; 2309 mblk_t *m0; 2310 boolean_t need_privilege; 2311 boolean_t need_net80211; 2312 2313 if (MBLKL(m) < sizeof (struct iocblk)) { 2314 IPW2100_DBG(IPW2100_DBG_IOCTL, (sc->sc_dip, CE_CONT, 2315 "ipw2100_ioctl(): ioctl buffer too short, %u\n", 2316 MBLKL(m))); 2317 miocnak(q, m, 0, EINVAL); 2318 return (IEEE80211_IOCTL_NOT_REQUIRED); 2319 } 2320 2321 /* 2322 * Validate the command 2323 */ 2324 iocp = (struct iocblk *)(uintptr_t)m->b_rptr; 2325 iocp->ioc_error = 0; 2326 cmd = iocp->ioc_cmd; 2327 need_privilege = B_TRUE; 2328 switch (cmd) { 2329 case WLAN_SET_PARAM: 2330 case WLAN_COMMAND: 2331 break; 2332 case WLAN_GET_PARAM: 2333 need_privilege = B_FALSE; 2334 break; 2335 default: 2336 IPW2100_DBG(IPW2100_DBG_IOCTL, (sc->sc_dip, CE_CONT, 2337 "ieee80211_ioctl(): unknown cmd 0x%x", cmd)); 2338 miocnak(q, m, 0, EINVAL); 2339 return (IEEE80211_IOCTL_NOT_REQUIRED); 2340 } 2341 2342 if (need_privilege && (ret = secpolicy_dl_config(iocp->ioc_cr)) != 0) { 2343 miocnak(q, m, 0, ret); 2344 return (IEEE80211_IOCTL_NOT_REQUIRED); 2345 } 2346 2347 /* 2348 * sanity check 2349 */ 2350 m0 = m->b_cont; 2351 if (iocp->ioc_count == 0 || iocp->ioc_count < sizeof (wldp_t) || 2352 m0 == NULL) { 2353 miocnak(q, m, 0, EINVAL); 2354 return (IEEE80211_IOCTL_NOT_REQUIRED); 2355 } 2356 /* 2357 * assuming single data block 2358 */ 2359 if (m0->b_cont) { 2360 freemsg(m0->b_cont); 2361 m0->b_cont = NULL; 2362 } 2363 2364 need_net80211 = B_FALSE; 2365 ret = ipw2100_getset(sc, m0, cmd, &need_net80211); 2366 if (!need_net80211) { 2367 len = msgdsize(m0); 2368 2369 IPW2100_DBG(IPW2100_DBG_IOCTL, (sc->sc_dip, CE_CONT, 2370 "ipw2100_ioctl(): go to call miocack with " 2371 "ret = %d, len = %d\n", ret, len)); 2372 miocack(q, m, len, ret); 2373 return (IEEE80211_IOCTL_NOT_REQUIRED); 2374 } 2375 2376 /* 2377 * IEEE80211_IOCTL_REQUIRED - need net80211 handle 2378 */ 2379 return (IEEE80211_IOCTL_REQUIRED); 2380 } 2381 2382 static int 2383 ipw2100_getset(struct ipw2100_softc *sc, mblk_t *m, uint32_t cmd, 2384 boolean_t *need_net80211) 2385 { 2386 wldp_t *infp, *outfp; 2387 uint32_t id; 2388 int ret; /* IEEE80211_IOCTL - handled by net80211 */ 2389 2390 infp = (wldp_t *)(uintptr_t)m->b_rptr; 2391 outfp = (wldp_t *)(uintptr_t)m->b_rptr; 2392 outfp->wldp_result = WL_NOTSUPPORTED; 2393 2394 id = infp->wldp_id; 2395 IPW2100_DBG(IPW2100_DBG_IOCTL, (sc->sc_dip, CE_CONT, 2396 "ipw2100_getset(): id = 0x%x\n", id)); 2397 switch (id) { 2398 /* 2399 * which is not supported by net80211, so it 2400 * has to be handled from driver side 2401 */ 2402 case WL_RADIO: 2403 ret = ipw_wificfg_radio(sc, cmd, outfp); 2404 break; 2405 /* 2406 * so far, drier doesn't support fix-rates 2407 */ 2408 case WL_DESIRED_RATES: 2409 ret = ipw_wificfg_desrates(outfp); 2410 break; 2411 /* 2412 * current net80211 implementation clears the bssid while 2413 * this command received, which will result in the all zero 2414 * mac address for scan'ed AP which is just disconnected. 2415 * This is a workaround solution until net80211 find a 2416 * better method. 2417 */ 2418 case WL_DISASSOCIATE: 2419 ret = ipw_wificfg_disassoc(sc, outfp); 2420 break; 2421 default: 2422 /* 2423 * The wifi IOCTL net80211 supported: 2424 * case WL_ESSID: 2425 * case WL_BSSID: 2426 * case WL_WEP_KEY_TAB: 2427 * case WL_WEP_KEY_ID: 2428 * case WL_AUTH_MODE: 2429 * case WL_ENCRYPTION: 2430 * case WL_BSS_TYPE: 2431 * case WL_ESS_LIST: 2432 * case WL_LINKSTATUS: 2433 * case WL_RSSI: 2434 * case WL_SCAN: 2435 * case WL_LOAD_DEFAULTS: 2436 */ 2437 2438 /* 2439 * When radio is off, need to ignore all ioctl. What need to 2440 * do is to check radio status firstly. If radio is ON, pass 2441 * it to net80211, otherwise, return to upper layer directly. 2442 * 2443 * Considering the WL_SUCCESS also means WL_CONNECTED for 2444 * checking linkstatus, one exception for WL_LINKSTATUS is to 2445 * let net80211 handle it. 2446 */ 2447 if ((ipw2100_get_radio(sc) == 0) && 2448 (id != WL_LINKSTATUS)) { 2449 2450 IPW2100_REPORT((sc->sc_dip, CE_WARN, 2451 "ipw: RADIO is OFF\n")); 2452 2453 outfp->wldp_length = WIFI_BUF_OFFSET; 2454 outfp->wldp_result = WL_SUCCESS; 2455 ret = 0; 2456 break; 2457 } 2458 2459 *need_net80211 = B_TRUE; /* let net80211 do the rest */ 2460 return (0); 2461 } 2462 /* 2463 * we will overwrite everything 2464 */ 2465 m->b_wptr = m->b_rptr + outfp->wldp_length; 2466 2467 return (ret); 2468 } 2469 2470 /* 2471 * Call back functions for get/set proporty 2472 */ 2473 static int 2474 ipw2100_m_getprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num, 2475 uint_t wldp_length, void *wldp_buf) 2476 { 2477 struct ipw2100_softc *sc = (struct ipw2100_softc *)arg; 2478 struct ieee80211com *ic = &sc->sc_ic; 2479 int err = 0; 2480 2481 switch (wldp_pr_num) { 2482 /* mac_prop_id */ 2483 case MAC_PROP_WL_DESIRED_RATES: 2484 IPW2100_DBG(IPW2100_DBG_BRUSSELS, (sc->sc_dip, CE_CONT, 2485 "ipw2100_m_getprop(): Not Support DESIRED_RATES\n")); 2486 break; 2487 case MAC_PROP_WL_RADIO: 2488 *(wl_linkstatus_t *)wldp_buf = ipw2100_get_radio(sc); 2489 break; 2490 default: 2491 /* go through net80211 */ 2492 err = ieee80211_getprop(ic, pr_name, wldp_pr_num, 2493 wldp_length, wldp_buf); 2494 break; 2495 } 2496 2497 return (err); 2498 } 2499 2500 static void 2501 ipw2100_m_propinfo(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num, 2502 mac_prop_info_handle_t prh) 2503 { 2504 struct ipw2100_softc *sc = (struct ipw2100_softc *)arg; 2505 struct ieee80211com *ic = &sc->sc_ic; 2506 2507 ieee80211_propinfo(ic, pr_name, wldp_pr_num, prh); 2508 2509 } 2510 2511 static int 2512 ipw2100_m_setprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num, 2513 uint_t wldp_length, const void *wldp_buf) 2514 { 2515 struct ipw2100_softc *sc = (struct ipw2100_softc *)arg; 2516 struct ieee80211com *ic = &sc->sc_ic; 2517 int err; 2518 2519 switch (wldp_pr_num) { 2520 /* mac_prop_id */ 2521 case MAC_PROP_WL_DESIRED_RATES: 2522 IPW2100_DBG(IPW2100_DBG_BRUSSELS, (sc->sc_dip, CE_CONT, 2523 "ipw2100_m_setprop(): Not Support DESIRED_RATES\n")); 2524 err = ENOTSUP; 2525 break; 2526 case MAC_PROP_WL_RADIO: 2527 IPW2100_DBG(IPW2100_DBG_BRUSSELS, (sc->sc_dip, CE_CONT, 2528 "ipw2100_m_setprop(): Not Support RADIO\n")); 2529 err = ENOTSUP; 2530 break; 2531 default: 2532 /* go through net80211 */ 2533 err = ieee80211_setprop(ic, pr_name, wldp_pr_num, wldp_length, 2534 wldp_buf); 2535 break; 2536 } 2537 2538 if (err == ENETRESET) { 2539 if (sc->sc_flags & IPW2100_FLAG_RUNNING) { 2540 (void) ipw2100_m_start(sc); 2541 (void) ieee80211_new_state(ic, 2542 IEEE80211_S_SCAN, -1); 2543 } 2544 2545 err = 0; 2546 } 2547 2548 return (err); 2549 } 2550 2551 static int 2552 ipw_wificfg_radio(struct ipw2100_softc *sc, uint32_t cmd, wldp_t *outfp) 2553 { 2554 uint32_t ret = ENOTSUP; 2555 2556 switch (cmd) { 2557 case WLAN_GET_PARAM: 2558 *(wl_linkstatus_t *)(outfp->wldp_buf) = ipw2100_get_radio(sc); 2559 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_linkstatus_t); 2560 outfp->wldp_result = WL_SUCCESS; 2561 ret = 0; /* command sucess */ 2562 break; 2563 case WLAN_SET_PARAM: 2564 default: 2565 break; 2566 } 2567 return (ret); 2568 } 2569 2570 static int 2571 ipw_wificfg_desrates(wldp_t *outfp) 2572 { 2573 /* 2574 * return success, but with result NOTSUPPORTED 2575 */ 2576 outfp->wldp_length = WIFI_BUF_OFFSET; 2577 outfp->wldp_result = WL_NOTSUPPORTED; 2578 return (0); 2579 } 2580 2581 static int 2582 ipw_wificfg_disassoc(struct ipw2100_softc *sc, wldp_t *outfp) 2583 { 2584 struct ieee80211com *ic = &sc->sc_ic; 2585 2586 /* 2587 * init the state 2588 */ 2589 if (ic->ic_state != IEEE80211_S_INIT) { 2590 (void) ieee80211_new_state(ic, IEEE80211_S_INIT, -1); 2591 } 2592 2593 /* 2594 * return success always 2595 */ 2596 outfp->wldp_length = WIFI_BUF_OFFSET; 2597 outfp->wldp_result = WL_SUCCESS; 2598 return (0); 2599 } 2600 /* End of IOCTL Handler */ 2601 2602 static void 2603 ipw2100_fix_channel(struct ieee80211com *ic, mblk_t *m) 2604 { 2605 struct ieee80211_frame *wh; 2606 uint8_t subtype; 2607 uint8_t *frm, *efrm; 2608 2609 wh = (struct ieee80211_frame *)m->b_rptr; 2610 2611 if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_MGT) 2612 return; 2613 2614 subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; 2615 2616 if (subtype != IEEE80211_FC0_SUBTYPE_BEACON && 2617 subtype != IEEE80211_FC0_SUBTYPE_PROBE_RESP) 2618 return; 2619 2620 /* 2621 * assume the message contains only 1 block 2622 */ 2623 frm = (uint8_t *)(wh + 1); 2624 efrm = (uint8_t *)m->b_wptr; 2625 frm += 12; /* skip tstamp, bintval and capinfo fields */ 2626 while (frm < efrm) { 2627 if (*frm == IEEE80211_ELEMID_DSPARMS) { 2628 #if IEEE80211_CHAN_MAX < 255 2629 if (frm[2] <= IEEE80211_CHAN_MAX) 2630 #endif 2631 { 2632 ic->ic_curchan = &ic->ic_sup_channels[frm[2]]; 2633 } 2634 } 2635 frm += frm[1] + 2; 2636 } 2637 } 2638 2639 static void 2640 ipw2100_rcvpkt(struct ipw2100_softc *sc, struct ipw2100_status *status, 2641 uint8_t *rxbuf) 2642 { 2643 struct ieee80211com *ic = &sc->sc_ic; 2644 mblk_t *m; 2645 struct ieee80211_frame *wh = (struct ieee80211_frame *)rxbuf; 2646 struct ieee80211_node *in; 2647 uint32_t rlen; 2648 2649 in = ieee80211_find_rxnode(ic, wh); 2650 rlen = LE_32(status->len); 2651 m = allocb(rlen, BPRI_MED); 2652 if (m) { 2653 (void) memcpy(m->b_wptr, rxbuf, rlen); 2654 m->b_wptr += rlen; 2655 if (ic->ic_state == IEEE80211_S_SCAN) 2656 ipw2100_fix_channel(ic, m); 2657 (void) ieee80211_input(ic, m, in, status->rssi, 0); 2658 } else 2659 IPW2100_WARN((sc->sc_dip, CE_WARN, 2660 "ipw2100_rcvpkg(): cannot allocate receive message(%u)\n", 2661 LE_32(status->len))); 2662 ieee80211_free_node(in); 2663 } 2664 2665 static uint_t 2666 ipw2100_intr(caddr_t arg) 2667 { 2668 struct ipw2100_softc *sc = (struct ipw2100_softc *)(uintptr_t)arg; 2669 uint32_t ireg, ridx, len, i; 2670 struct ieee80211com *ic = &sc->sc_ic; 2671 struct ipw2100_status *status; 2672 uint8_t *rxbuf; 2673 struct dma_region *dr; 2674 uint32_t state; 2675 #if DEBUG 2676 struct ipw2100_bd *rxbd; 2677 #endif 2678 2679 if (sc->sc_suspended) 2680 return (DDI_INTR_UNCLAIMED); 2681 2682 ireg = ipw2100_csr_get32(sc, IPW2100_CSR_INTR); 2683 2684 if (!(ireg & IPW2100_INTR_MASK_ALL)) 2685 return (DDI_INTR_UNCLAIMED); 2686 2687 /* 2688 * mask all interrupts 2689 */ 2690 ipw2100_csr_put32(sc, IPW2100_CSR_INTR_MASK, 0); 2691 2692 /* 2693 * acknowledge all fired interrupts 2694 */ 2695 ipw2100_csr_put32(sc, IPW2100_CSR_INTR, ireg); 2696 2697 IPW2100_DBG(IPW2100_DBG_INT, (sc->sc_dip, CE_CONT, 2698 "ipw2100_intr(): interrupt is fired. int=0x%08x\n", ireg)); 2699 2700 if (ireg & IPW2100_INTR_MASK_ERR) { 2701 2702 IPW2100_DBG(IPW2100_DBG_FATAL, (sc->sc_dip, CE_CONT, 2703 "ipw2100_intr(): interrupt is fired, MASK = 0x%08x\n", 2704 ireg)); 2705 2706 /* 2707 * inform mfthread to recover hw error 2708 */ 2709 mutex_enter(&sc->sc_mflock); 2710 sc->sc_flags |= IPW2100_FLAG_HW_ERR_RECOVER; 2711 mutex_exit(&sc->sc_mflock); 2712 2713 goto enable_interrupt; 2714 } 2715 2716 /* 2717 * FW intr 2718 */ 2719 if (ireg & IPW2100_INTR_FW_INIT_DONE) { 2720 mutex_enter(&sc->sc_ilock); 2721 sc->sc_flags |= IPW2100_FLAG_FW_INITED; 2722 cv_signal(&sc->sc_fw_cond); 2723 mutex_exit(&sc->sc_ilock); 2724 } 2725 2726 /* 2727 * RX intr 2728 */ 2729 if (ireg & IPW2100_INTR_RX_TRANSFER) { 2730 ridx = ipw2100_csr_get32(sc, 2731 IPW2100_CSR_RX_READ_INDEX); 2732 2733 for (; sc->sc_rx_cur != ridx; 2734 sc->sc_rx_cur = RING_FORWARD( 2735 sc->sc_rx_cur, 1, IPW2100_NUM_RXBD)) { 2736 2737 i = sc->sc_rx_cur; 2738 status = &sc->sc_status[i]; 2739 rxbuf = &sc->sc_rxbufs[i]->rxb_dat[0]; 2740 dr = &sc->sc_dma_rxbufs[i]; 2741 2742 /* 2743 * sync 2744 */ 2745 (void) ddi_dma_sync(sc->sc_dma_status.dr_hnd, 2746 i * sizeof (struct ipw2100_status), 2747 sizeof (struct ipw2100_status), 2748 DDI_DMA_SYNC_FORKERNEL); 2749 (void) ddi_dma_sync(sc->sc_dma_rxbd.dr_hnd, 2750 i * sizeof (struct ipw2100_bd), 2751 sizeof (struct ipw2100_bd), 2752 DDI_DMA_SYNC_FORKERNEL); 2753 (void) ddi_dma_sync(dr->dr_hnd, 0, 2754 sizeof (struct ipw2100_rxb), 2755 DDI_DMA_SYNC_FORKERNEL); 2756 IPW2100_DBG(IPW2100_DBG_INT, (sc->sc_dip, CE_CONT, 2757 "ipw2100_intr(): status code=0x%04x, len=0x%08x, " 2758 "flags=0x%02x, rssi=%02x\n", 2759 LE_16(status->code), LE_32(status->len), 2760 status->flags, status->rssi)); 2761 #if DEBUG 2762 rxbd = &sc->sc_rxbd[i]; 2763 IPW2100_DBG(IPW2100_DBG_INT, (sc->sc_dip, CE_CONT, 2764 "ipw2100_intr(): rxbd,phyaddr=0x%08x, len=0x%08x, " 2765 "flags=0x%02x,nfrag=%02x\n", 2766 LE_32(rxbd->phyaddr), LE_32(rxbd->len), 2767 rxbd->flags, rxbd->nfrag)); 2768 #endif 2769 switch (LE_16(status->code) & 0x0f) { 2770 /* 2771 * command complete response 2772 */ 2773 case IPW2100_STATUS_CODE_COMMAND: 2774 mutex_enter(&sc->sc_ilock); 2775 sc->sc_done = 1; 2776 cv_signal(&sc->sc_cmd_cond); 2777 mutex_exit(&sc->sc_ilock); 2778 break; 2779 /* 2780 * change state 2781 */ 2782 case IPW2100_STATUS_CODE_NEWSTATE: 2783 state = LE_32(* ((uint32_t *)(uintptr_t)rxbuf)); 2784 IPW2100_DBG(IPW2100_DBG_INT, 2785 (sc->sc_dip, CE_CONT, 2786 "ipw2100_intr(): newstate,state=0x%x\n", 2787 state)); 2788 2789 switch (state) { 2790 case IPW2100_STATE_ASSOCIATED: 2791 ieee80211_new_state(ic, 2792 IEEE80211_S_RUN, -1); 2793 break; 2794 case IPW2100_STATE_ASSOCIATION_LOST: 2795 case IPW2100_STATE_DISABLED: 2796 ieee80211_new_state(ic, 2797 IEEE80211_S_INIT, -1); 2798 break; 2799 /* 2800 * When radio is OFF, need a better 2801 * scan approach to ensure scan 2802 * result correct. 2803 */ 2804 case IPW2100_STATE_RADIO_DISABLED: 2805 IPW2100_REPORT((sc->sc_dip, CE_WARN, 2806 "ipw2100_intr(): RADIO is OFF\n")); 2807 ipw2100_stop(sc); 2808 break; 2809 case IPW2100_STATE_SCAN_COMPLETE: 2810 ieee80211_cancel_scan(ic); 2811 break; 2812 case IPW2100_STATE_SCANNING: 2813 if (ic->ic_state != IEEE80211_S_RUN) 2814 ieee80211_new_state(ic, 2815 IEEE80211_S_SCAN, -1); 2816 ic->ic_flags |= IEEE80211_F_SCAN; 2817 2818 break; 2819 default: 2820 break; 2821 } 2822 break; 2823 case IPW2100_STATUS_CODE_DATA_802_11: 2824 case IPW2100_STATUS_CODE_DATA_802_3: 2825 ipw2100_rcvpkt(sc, status, rxbuf); 2826 break; 2827 case IPW2100_STATUS_CODE_NOTIFICATION: 2828 break; 2829 default: 2830 IPW2100_WARN((sc->sc_dip, CE_WARN, 2831 "ipw2100_intr(): " 2832 "unknown status code 0x%04x\n", 2833 LE_16(status->code))); 2834 break; 2835 } 2836 } 2837 /* 2838 * write sc_rx_cur backward 1 step to RX_WRITE_INDEX 2839 */ 2840 ipw2100_csr_put32(sc, IPW2100_CSR_RX_WRITE_INDEX, 2841 RING_BACKWARD(sc->sc_rx_cur, 1, IPW2100_NUM_RXBD)); 2842 } 2843 2844 /* 2845 * TX intr 2846 */ 2847 if (ireg & IPW2100_INTR_TX_TRANSFER) { 2848 mutex_enter(&sc->sc_tx_lock); 2849 ridx = ipw2100_csr_get32(sc, IPW2100_CSR_TX_READ_INDEX); 2850 len = RING_FLEN(RING_FORWARD(sc->sc_tx_cur, 2851 sc->sc_tx_free, IPW2100_NUM_TXBD), 2852 ridx, IPW2100_NUM_TXBD); 2853 sc->sc_tx_free += len; 2854 IPW2100_DBG(IPW2100_DBG_INT, (sc->sc_dip, CE_CONT, 2855 "ipw2100_intr(): len=%d\n", len)); 2856 mutex_exit(&sc->sc_tx_lock); 2857 2858 mutex_enter(&sc->sc_resched_lock); 2859 if (len > 1 && (sc->sc_flags & IPW2100_FLAG_TX_SCHED)) { 2860 sc->sc_flags &= ~IPW2100_FLAG_TX_SCHED; 2861 mac_tx_update(ic->ic_mach); 2862 } 2863 mutex_exit(&sc->sc_resched_lock); 2864 } 2865 2866 enable_interrupt: 2867 /* 2868 * enable all interrupts 2869 */ 2870 ipw2100_csr_put32(sc, IPW2100_CSR_INTR_MASK, IPW2100_INTR_MASK_ALL); 2871 2872 return (DDI_INTR_CLAIMED); 2873 } 2874 2875 2876 /* 2877 * Module Loading Data & Entry Points 2878 */ 2879 DDI_DEFINE_STREAM_OPS(ipw2100_devops, nulldev, nulldev, ipw2100_attach, 2880 ipw2100_detach, nodev, NULL, D_MP, NULL, ipw2100_quiesce); 2881 2882 static struct modldrv ipw2100_modldrv = { 2883 &mod_driverops, 2884 ipw2100_ident, 2885 &ipw2100_devops 2886 }; 2887 2888 static struct modlinkage ipw2100_modlinkage = { 2889 MODREV_1, 2890 &ipw2100_modldrv, 2891 NULL 2892 }; 2893 2894 int 2895 _init(void) 2896 { 2897 int status; 2898 2899 status = ddi_soft_state_init(&ipw2100_ssp, 2900 sizeof (struct ipw2100_softc), 1); 2901 if (status != DDI_SUCCESS) 2902 return (status); 2903 2904 mac_init_ops(&ipw2100_devops, IPW2100_DRV_NAME); 2905 status = mod_install(&ipw2100_modlinkage); 2906 if (status != DDI_SUCCESS) { 2907 mac_fini_ops(&ipw2100_devops); 2908 ddi_soft_state_fini(&ipw2100_ssp); 2909 } 2910 2911 return (status); 2912 } 2913 2914 int 2915 _fini(void) 2916 { 2917 int status; 2918 2919 status = mod_remove(&ipw2100_modlinkage); 2920 if (status == DDI_SUCCESS) { 2921 mac_fini_ops(&ipw2100_devops); 2922 ddi_soft_state_fini(&ipw2100_ssp); 2923 } 2924 2925 return (status); 2926 } 2927 2928 int 2929 _info(struct modinfo *mip) 2930 { 2931 return (mod_info(&ipw2100_modlinkage, mip)); 2932 }