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