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