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