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