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 ieee80211_free_node(in); 1534 (void) mac_pdata_update(ic->ic_mach, &wd, sizeof (wd)); 1535 1536 break; 1537 1538 case IEEE80211_S_INIT: 1539 case IEEE80211_S_SCAN: 1540 case IEEE80211_S_AUTH: 1541 case IEEE80211_S_ASSOC: 1542 break; 1543 } 1544 1545 /* 1546 * notify to update the link 1547 */ 1548 if ((ic->ic_state != IEEE80211_S_RUN) && (state == IEEE80211_S_RUN)) { 1549 /* 1550 * previously disconnected and now connected 1551 */ 1552 sc->sc_linkstate = LINK_STATE_UP; 1553 sc->sc_flags |= IPW2100_FLAG_LINK_CHANGE; 1554 } else if ((ic->ic_state == IEEE80211_S_RUN) && 1555 (state != IEEE80211_S_RUN)) { 1556 /* 1557 * previously connected andd now disconnected 1558 */ 1559 sc->sc_linkstate = LINK_STATE_DOWN; 1560 sc->sc_flags |= IPW2100_FLAG_LINK_CHANGE; 1561 } 1562 1563 ic->ic_state = state; 1564 return (DDI_SUCCESS); 1565 } 1566 1567 /* 1568 * GLD operations 1569 */ 1570 /* ARGSUSED */ 1571 static int 1572 ipw2100_m_stat(void *arg, uint_t stat, uint64_t *val) 1573 { 1574 ieee80211com_t *ic = (ieee80211com_t *)arg; 1575 IPW2100_DBG(IPW2100_DBG_GLD, (((struct ipw2100_softc *)arg)->sc_dip, 1576 CE_CONT, 1577 "ipw2100_m_stat(): enter\n")); 1578 /* 1579 * some of below statistic data are from hardware, some from net80211 1580 */ 1581 switch (stat) { 1582 case MAC_STAT_RBYTES: 1583 *val = ic->ic_stats.is_rx_bytes; 1584 break; 1585 case MAC_STAT_IPACKETS: 1586 *val = ic->ic_stats.is_rx_frags; 1587 break; 1588 case MAC_STAT_OBYTES: 1589 *val = ic->ic_stats.is_tx_bytes; 1590 break; 1591 case MAC_STAT_OPACKETS: 1592 *val = ic->ic_stats.is_tx_frags; 1593 break; 1594 /* 1595 * Get below from hardware statistic, retrieve net80211 value once 1s 1596 */ 1597 case WIFI_STAT_TX_FRAGS: 1598 case WIFI_STAT_MCAST_TX: 1599 case WIFI_STAT_TX_FAILED: 1600 case WIFI_STAT_TX_RETRANS: 1601 case WIFI_STAT_RTS_SUCCESS: 1602 case WIFI_STAT_ACK_FAILURE: 1603 case WIFI_STAT_RX_FRAGS: 1604 case WIFI_STAT_MCAST_RX: 1605 /* 1606 * Get blow information from net80211 1607 */ 1608 case WIFI_STAT_RTS_FAILURE: 1609 case WIFI_STAT_RX_DUPS: 1610 case WIFI_STAT_FCS_ERRORS: 1611 case WIFI_STAT_WEP_ERRORS: 1612 return (ieee80211_stat(ic, stat, val)); 1613 /* 1614 * need be supported in the future 1615 */ 1616 case MAC_STAT_IFSPEED: 1617 case MAC_STAT_NOXMTBUF: 1618 case MAC_STAT_IERRORS: 1619 case MAC_STAT_OERRORS: 1620 default: 1621 return (ENOTSUP); 1622 } 1623 return (0); 1624 } 1625 1626 /* ARGSUSED */ 1627 static int 1628 ipw2100_m_multicst(void *arg, boolean_t add, const uint8_t *mca) 1629 { 1630 /* not supported */ 1631 IPW2100_DBG(IPW2100_DBG_GLD, (((struct ipw2100_softc *)arg)->sc_dip, 1632 CE_CONT, 1633 "ipw2100_m_multicst(): enter\n")); 1634 1635 return (DDI_SUCCESS); 1636 } 1637 1638 /* 1639 * This thread function is used to handle the fatal error. 1640 */ 1641 static void 1642 ipw2100_thread(struct ipw2100_softc *sc) 1643 { 1644 struct ieee80211com *ic = &sc->sc_ic; 1645 int32_t nlstate; 1646 int stat_cnt = 0; 1647 1648 IPW2100_DBG(IPW2100_DBG_SOFTINT, (sc->sc_dip, CE_CONT, 1649 "ipw2100_thread(): into ipw2100 thread--> %d\n", 1650 sc->sc_linkstate)); 1651 1652 mutex_enter(&sc->sc_mflock); 1653 1654 while (sc->sc_mfthread_switch) { 1655 /* 1656 * notify the link state 1657 */ 1658 if (ic->ic_mach && (sc->sc_flags & IPW2100_FLAG_LINK_CHANGE)) { 1659 IPW2100_DBG(IPW2100_DBG_SOFTINT, (sc->sc_dip, CE_CONT, 1660 "ipw2100_thread(): link status --> %d\n", 1661 sc->sc_linkstate)); 1662 1663 sc->sc_flags &= ~IPW2100_FLAG_LINK_CHANGE; 1664 nlstate = sc->sc_linkstate; 1665 1666 mutex_exit(&sc->sc_mflock); 1667 mac_link_update(ic->ic_mach, nlstate); 1668 mutex_enter(&sc->sc_mflock); 1669 } 1670 1671 /* 1672 * recovery interrupt fatal error 1673 */ 1674 if (ic->ic_mach && 1675 (sc->sc_flags & IPW2100_FLAG_HW_ERR_RECOVER)) { 1676 1677 IPW2100_DBG(IPW2100_DBG_FATAL, (sc->sc_dip, CE_CONT, 1678 "try to recover fatal hw error\n")); 1679 sc->sc_flags &= ~IPW2100_FLAG_HW_ERR_RECOVER; 1680 1681 mutex_exit(&sc->sc_mflock); 1682 (void) ipw2100_init(sc); /* Force stat machine */ 1683 delay(drv_usectohz(delay_fatal_recover)); 1684 mutex_enter(&sc->sc_mflock); 1685 } 1686 1687 /* 1688 * get statistic, the value will be retrieved by m_stat 1689 */ 1690 if (stat_cnt == 10) { 1691 stat_cnt = 0; /* re-start */ 1692 1693 mutex_exit(&sc->sc_mflock); 1694 ipw2100_get_statistics(sc); 1695 mutex_enter(&sc->sc_mflock); 1696 } else 1697 stat_cnt++; /* until 1s */ 1698 1699 mutex_exit(&sc->sc_mflock); 1700 delay(drv_usectohz(delay_aux_thread)); 1701 mutex_enter(&sc->sc_mflock); 1702 } 1703 sc->sc_mf_thread = NULL; 1704 cv_broadcast(&sc->sc_mfthread_cv); 1705 mutex_exit(&sc->sc_mflock); 1706 } 1707 1708 static int 1709 ipw2100_m_start(void *arg) 1710 { 1711 struct ipw2100_softc *sc = (struct ipw2100_softc *)arg; 1712 1713 IPW2100_DBG(IPW2100_DBG_GLD, (sc->sc_dip, CE_CONT, 1714 "ipw2100_m_start(): enter\n")); 1715 1716 /* 1717 * initialize ipw2100 hardware 1718 */ 1719 (void) ipw2100_init(sc); 1720 1721 sc->sc_flags |= IPW2100_FLAG_RUNNING; 1722 1723 /* 1724 * fix KCF bug. - workaround, need to fix it in net80211 1725 */ 1726 (void) crypto_mech2id(SUN_CKM_RC4); 1727 1728 return (DDI_SUCCESS); 1729 } 1730 1731 static void 1732 ipw2100_m_stop(void *arg) 1733 { 1734 struct ipw2100_softc *sc = (struct ipw2100_softc *)arg; 1735 1736 IPW2100_DBG(IPW2100_DBG_GLD, (sc->sc_dip, CE_CONT, 1737 "ipw2100_m_stop(): enter\n")); 1738 1739 ipw2100_stop(sc); 1740 1741 sc->sc_flags &= ~IPW2100_FLAG_RUNNING; 1742 } 1743 1744 static int 1745 ipw2100_m_unicst(void *arg, const uint8_t *macaddr) 1746 { 1747 struct ipw2100_softc *sc = (struct ipw2100_softc *)arg; 1748 struct ieee80211com *ic = &sc->sc_ic; 1749 int err; 1750 1751 IPW2100_DBG(IPW2100_DBG_GLD, (sc->sc_dip, CE_CONT, 1752 "ipw2100_m_unicst(): enter\n")); 1753 1754 IPW2100_DBG(IPW2100_DBG_GLD, (sc->sc_dip, CE_CONT, 1755 "ipw2100_m_unicst(): GLD setting MAC address to " 1756 "%02x:%02x:%02x:%02x:%02x:%02x\n", 1757 macaddr[0], macaddr[1], macaddr[2], 1758 macaddr[3], macaddr[4], macaddr[5])); 1759 1760 if (!IEEE80211_ADDR_EQ(ic->ic_macaddr, macaddr)) { 1761 IEEE80211_ADDR_COPY(ic->ic_macaddr, macaddr); 1762 1763 if (sc->sc_flags & IPW2100_FLAG_RUNNING) { 1764 err = ipw2100_config(sc); 1765 if (err != DDI_SUCCESS) { 1766 IPW2100_WARN((sc->sc_dip, CE_WARN, 1767 "ipw2100_m_unicst(): " 1768 "device configuration failed\n")); 1769 goto fail; 1770 } 1771 } 1772 } 1773 1774 return (DDI_SUCCESS); 1775 fail: 1776 return (err); 1777 } 1778 1779 static int 1780 ipw2100_m_promisc(void *arg, boolean_t on) 1781 { 1782 struct ipw2100_softc *sc = (struct ipw2100_softc *)arg; 1783 int recfg, err; 1784 1785 IPW2100_DBG(IPW2100_DBG_GLD, (sc->sc_dip, CE_CONT, 1786 "ipw2100_m_promisc(): enter. " 1787 "GLD setting promiscuous mode - %d\n", on)); 1788 1789 recfg = 0; 1790 if (on) 1791 if (!(sc->if_flags & IFF_PROMISC)) { 1792 sc->if_flags |= IFF_PROMISC; 1793 recfg = 1; 1794 } 1795 else 1796 if (sc->if_flags & IFF_PROMISC) { 1797 sc->if_flags &= ~IFF_PROMISC; 1798 recfg = 1; 1799 } 1800 1801 if (recfg && (sc->sc_flags & IPW2100_FLAG_RUNNING)) { 1802 err = ipw2100_config(sc); 1803 if (err != DDI_SUCCESS) { 1804 IPW2100_WARN((sc->sc_dip, CE_WARN, 1805 "ipw2100_m_promisc(): " 1806 "device configuration failed\n")); 1807 goto fail; 1808 } 1809 } 1810 1811 return (DDI_SUCCESS); 1812 fail: 1813 return (err); 1814 } 1815 1816 static mblk_t * 1817 ipw2100_m_tx(void *arg, mblk_t *mp) 1818 { 1819 struct ipw2100_softc *sc = (struct ipw2100_softc *)arg; 1820 struct ieee80211com *ic = &sc->sc_ic; 1821 mblk_t *next; 1822 1823 /* 1824 * No data frames go out unless we're associated; this 1825 * should not happen as the 802.11 layer does not enable 1826 * the xmit queue until we enter the RUN state. 1827 */ 1828 if (ic->ic_state != IEEE80211_S_RUN) { 1829 IPW2100_DBG(IPW2100_DBG_GLD, (sc->sc_dip, CE_CONT, 1830 "ipw2100_m_tx(): discard msg, ic_state = %u\n", 1831 ic->ic_state)); 1832 freemsgchain(mp); 1833 return (NULL); 1834 } 1835 1836 while (mp != NULL) { 1837 next = mp->b_next; 1838 mp->b_next = NULL; 1839 if (ipw2100_send(ic, mp, IEEE80211_FC0_TYPE_DATA) != 1840 DDI_SUCCESS) { 1841 mp->b_next = next; 1842 break; 1843 } 1844 mp = next; 1845 } 1846 return (mp); 1847 } 1848 1849 /* ARGSUSED */ 1850 static int 1851 ipw2100_send(ieee80211com_t *ic, mblk_t *mp, uint8_t type) 1852 { 1853 struct ipw2100_softc *sc = (struct ipw2100_softc *)ic; 1854 struct ieee80211_node *in; 1855 struct ieee80211_frame wh, *wh_tmp; 1856 struct ieee80211_key *k; 1857 uint8_t *hdat; 1858 mblk_t *m0, *m; 1859 size_t cnt, off; 1860 struct ipw2100_bd *txbd[2]; 1861 struct ipw2100_txb *txbuf; 1862 struct dma_region *dr; 1863 struct ipw2100_hdr *h; 1864 uint32_t idx, bidx; 1865 int err; 1866 1867 ASSERT(mp->b_next == NULL); 1868 1869 m0 = NULL; 1870 m = NULL; 1871 err = DDI_SUCCESS; 1872 1873 IPW2100_DBG(IPW2100_DBG_GLD, (sc->sc_dip, CE_CONT, 1874 "ipw2100_send(): enter\n")); 1875 1876 if ((type & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_DATA) { 1877 /* 1878 * it is impossible to send non-data 802.11 frame in current 1879 * ipw driver. Therefore, drop the package 1880 */ 1881 freemsg(mp); 1882 err = DDI_SUCCESS; 1883 goto fail0; 1884 } 1885 1886 mutex_enter(&sc->sc_tx_lock); 1887 1888 /* 1889 * need 2 descriptors: 1 for SEND cmd parameter header, 1890 * and the other for payload, i.e., 802.11 frame including 802.11 1891 * frame header 1892 */ 1893 if (sc->sc_tx_free < 2) { 1894 mutex_enter(&sc->sc_resched_lock); 1895 IPW2100_DBG(IPW2100_DBG_RING, (sc->sc_dip, CE_WARN, 1896 "ipw2100_send(): no enough descriptors(%d)\n", 1897 sc->sc_tx_free)); 1898 ic->ic_stats.is_tx_nobuf++; /* no enough buffer */ 1899 sc->sc_flags |= IPW2100_FLAG_TX_SCHED; 1900 err = DDI_FAILURE; 1901 mutex_exit(&sc->sc_resched_lock); 1902 goto fail1; 1903 } 1904 IPW2100_DBG(IPW2100_DBG_RING, (sc->sc_dip, CE_CONT, 1905 "ipw2100_send(): tx-free=%d,tx-curr=%d\n", 1906 sc->sc_tx_free, sc->sc_tx_cur)); 1907 1908 wh_tmp = (struct ieee80211_frame *)mp->b_rptr; 1909 in = ieee80211_find_txnode(ic, wh_tmp->i_addr1); 1910 if (in == NULL) { /* can not find tx node, drop the package */ 1911 freemsg(mp); 1912 err = DDI_SUCCESS; 1913 goto fail1; 1914 } 1915 in->in_inact = 0; 1916 (void) ieee80211_encap(ic, mp, in); 1917 ieee80211_free_node(in); 1918 1919 if (wh_tmp->i_fc[1] & IEEE80211_FC1_WEP) { 1920 /* 1921 * it is very bad that ieee80211_crypto_encap can only accept a 1922 * single continuous buffer. 1923 */ 1924 /* 1925 * allocate 32 more bytes is to be compatible with further 1926 * ieee802.11i standard. 1927 */ 1928 m = allocb(msgdsize(mp) + 32, BPRI_MED); 1929 if (m == NULL) { /* can not alloc buf, drop this package */ 1930 IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT, 1931 "ipw2100_send(): msg allocation failed\n")); 1932 1933 freemsg(mp); 1934 1935 err = DDI_SUCCESS; 1936 goto fail1; 1937 } 1938 off = 0; 1939 m0 = mp; 1940 while (m0) { 1941 cnt = MBLKL(m0); 1942 if (cnt) { 1943 (void) memcpy(m->b_rptr + off, m0->b_rptr, cnt); 1944 off += cnt; 1945 } 1946 m0 = m0->b_cont; 1947 } 1948 m->b_wptr += off; 1949 IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT, 1950 "ipw2100_send(): " 1951 "Encrypting 802.11 frame started, %d, %d\n", 1952 msgdsize(mp), MBLKL(mp))); 1953 k = ieee80211_crypto_encap(ic, m); 1954 if (k == NULL) { /* can not get the key, drop packages */ 1955 IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT, 1956 "ipw2100_send(): " 1957 "Encrypting 802.11 frame failed\n")); 1958 1959 freemsg(mp); 1960 err = DDI_SUCCESS; 1961 goto fail2; 1962 } 1963 IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT, 1964 "ipw2100_send(): " 1965 "Encrypting 802.11 frame finished, %d, %d, k=0x%08x\n", 1966 msgdsize(mp), MBLKL(mp), k->wk_flags)); 1967 } 1968 1969 /* 1970 * header descriptor 1971 */ 1972 idx = sc->sc_tx_cur; 1973 txbd[0] = &sc->sc_txbd[idx]; 1974 if ((idx & 1) == 0) 1975 bidx = idx / 2; 1976 sc->sc_tx_cur = RING_FORWARD(sc->sc_tx_cur, 1, IPW2100_NUM_TXBD); 1977 sc->sc_tx_free--; 1978 1979 /* 1980 * payload descriptor 1981 */ 1982 idx = sc->sc_tx_cur; 1983 txbd[1] = &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 * one buffer, SEND cmd header and payload buffer 1991 */ 1992 txbuf = sc->sc_txbufs[bidx]; 1993 dr = &sc->sc_dma_txbufs[bidx]; 1994 1995 /* 1996 * extract 802.11 header from message, fill wh from m0 1997 */ 1998 hdat = (uint8_t *)&wh; 1999 off = 0; 2000 if (m) 2001 m0 = m; 2002 else 2003 m0 = mp; 2004 while (off < sizeof (wh)) { 2005 cnt = MBLKL(m0); 2006 if (cnt > (sizeof (wh) - off)) 2007 cnt = sizeof (wh) - off; 2008 if (cnt) { 2009 (void) memcpy(hdat + off, m0->b_rptr, cnt); 2010 off += cnt; 2011 m0->b_rptr += cnt; 2012 } 2013 else 2014 m0 = m0->b_cont; 2015 } 2016 2017 /* 2018 * prepare SEND cmd header 2019 */ 2020 h = &txbuf->txb_hdr; 2021 h->type = LE_32(IPW2100_CMD_SEND); 2022 h->subtype = LE_32(0); 2023 h->encrypted = ic->ic_flags & IEEE80211_F_PRIVACY ? 1 : 0; 2024 h->encrypt = 0; 2025 h->keyidx = 0; 2026 h->keysz = 0; 2027 h->fragsz = LE_16(0); 2028 IEEE80211_ADDR_COPY(h->saddr, wh.i_addr2); 2029 if (ic->ic_opmode == IEEE80211_M_STA) 2030 IEEE80211_ADDR_COPY(h->daddr, wh.i_addr3); 2031 else 2032 IEEE80211_ADDR_COPY(h->daddr, wh.i_addr1); 2033 2034 /* 2035 * extract payload from message into tx data buffer 2036 */ 2037 off = 0; 2038 while (m0) { 2039 cnt = MBLKL(m0); 2040 if (cnt) { 2041 (void) memcpy(&txbuf->txb_dat[off], m0->b_rptr, cnt); 2042 off += cnt; 2043 } 2044 m0 = m0->b_cont; 2045 } 2046 2047 /* 2048 * fill SEND cmd header descriptor 2049 */ 2050 txbd[0]->phyaddr = LE_32(dr->dr_pbase + 2051 OFFSETOF(struct ipw2100_txb, txb_hdr)); 2052 txbd[0]->len = LE_32(sizeof (struct ipw2100_hdr)); 2053 txbd[0]->flags = IPW2100_BD_FLAG_TX_FRAME_802_3 | 2054 IPW2100_BD_FLAG_TX_NOT_LAST_FRAGMENT; 2055 txbd[0]->nfrag = 2; 2056 /* 2057 * fill payload descriptor 2058 */ 2059 txbd[1]->phyaddr = LE_32(dr->dr_pbase + 2060 OFFSETOF(struct ipw2100_txb, txb_dat[0])); 2061 txbd[1]->len = LE_32(off); 2062 txbd[1]->flags = IPW2100_BD_FLAG_TX_FRAME_802_3 | 2063 IPW2100_BD_FLAG_TX_LAST_FRAGMENT; 2064 txbd[1]->nfrag = 0; 2065 2066 /* 2067 * dma sync 2068 */ 2069 (void) ddi_dma_sync(dr->dr_hnd, 0, sizeof (struct ipw2100_txb), 2070 DDI_DMA_SYNC_FORDEV); 2071 (void) ddi_dma_sync(sc->sc_dma_txbd.dr_hnd, 2072 (txbd[0] - sc->sc_txbd) * sizeof (struct ipw2100_bd), 2073 sizeof (struct ipw2100_bd), DDI_DMA_SYNC_FORDEV); 2074 /* 2075 * since txbd[1] may not be successive to txbd[0] due to the ring 2076 * organization, another dma_sync is needed to simplify the logic 2077 */ 2078 (void) ddi_dma_sync(sc->sc_dma_txbd.dr_hnd, 2079 (txbd[1] - sc->sc_txbd) * sizeof (struct ipw2100_bd), 2080 sizeof (struct ipw2100_bd), DDI_DMA_SYNC_FORDEV); 2081 /* 2082 * update txcur 2083 */ 2084 ipw2100_csr_put32(sc, IPW2100_CSR_TX_WRITE_INDEX, sc->sc_tx_cur); 2085 2086 if (mp) /* success, free the original message */ 2087 freemsg(mp); 2088 fail2: 2089 if (m) 2090 freemsg(m); 2091 fail1: 2092 mutex_exit(&sc->sc_tx_lock); 2093 fail0: 2094 IPW2100_DBG(IPW2100_DBG_GLD, (sc->sc_dip, CE_CONT, 2095 "ipw2100_send(): exit - err=%d\n", err)); 2096 2097 return (err); 2098 } 2099 2100 /* 2101 * IOCTL Handler 2102 */ 2103 #define IEEE80211_IOCTL_REQUIRED (1) 2104 #define IEEE80211_IOCTL_NOT_REQUIRED (0) 2105 static void 2106 ipw2100_m_ioctl(void *arg, queue_t *q, mblk_t *m) 2107 { 2108 struct ipw2100_softc *sc = (struct ipw2100_softc *)arg; 2109 struct ieee80211com *ic = &sc->sc_ic; 2110 int err; 2111 2112 IPW2100_DBG(IPW2100_DBG_GLD, (sc->sc_dip, CE_CONT, 2113 "ipw2100_m_ioctl(): enter\n")); 2114 2115 /* 2116 * check whether or not need to handle this in net80211 2117 */ 2118 if (ipw2100_ioctl(sc, q, m) == IEEE80211_IOCTL_NOT_REQUIRED) 2119 return; /* succes or fail */ 2120 2121 err = ieee80211_ioctl(ic, q, m); 2122 if (err == ENETRESET) { 2123 if (sc->sc_flags & IPW2100_FLAG_RUNNING) { 2124 (void) ipw2100_m_start(sc); 2125 (void) ieee80211_new_state(ic, 2126 IEEE80211_S_SCAN, -1); 2127 } 2128 } 2129 if (err == ERESTART) { 2130 if (sc->sc_flags & IPW2100_FLAG_RUNNING) 2131 (void) ipw2100_chip_reset(sc); 2132 } 2133 } 2134 2135 static int 2136 ipw2100_ioctl(struct ipw2100_softc *sc, queue_t *q, mblk_t *m) 2137 { 2138 struct iocblk *iocp; 2139 uint32_t len, ret, cmd; 2140 mblk_t *m0; 2141 boolean_t need_privilege; 2142 boolean_t need_net80211; 2143 2144 if (MBLKL(m) < sizeof (struct iocblk)) { 2145 IPW2100_DBG(IPW2100_DBG_IOCTL, (sc->sc_dip, CE_CONT, 2146 "ipw2100_ioctl(): ioctl buffer too short, %u\n", 2147 MBLKL(m))); 2148 miocnak(q, m, 0, EINVAL); 2149 return (IEEE80211_IOCTL_NOT_REQUIRED); 2150 } 2151 2152 /* 2153 * Validate the command 2154 */ 2155 iocp = (struct iocblk *)m->b_rptr; 2156 iocp->ioc_error = 0; 2157 cmd = iocp->ioc_cmd; 2158 need_privilege = B_TRUE; 2159 switch (cmd) { 2160 case WLAN_SET_PARAM: 2161 case WLAN_COMMAND: 2162 break; 2163 case WLAN_GET_PARAM: 2164 need_privilege = B_FALSE; 2165 break; 2166 default: 2167 IPW2100_DBG(IPW2100_DBG_IOCTL, (sc->sc_dip, CE_CONT, 2168 "ieee80211_ioctl(): unknown cmd 0x%x", cmd)); 2169 miocnak(q, m, 0, EINVAL); 2170 return (IEEE80211_IOCTL_NOT_REQUIRED); 2171 } 2172 2173 if (need_privilege) { 2174 /* 2175 * Check for specific net_config privilege on Solaris 10+. 2176 * Otherwise just check for root access ... 2177 */ 2178 if (secpolicy_net_config != NULL) 2179 ret = secpolicy_net_config(iocp->ioc_cr, B_FALSE); 2180 else 2181 ret = drv_priv(iocp->ioc_cr); 2182 if (ret != 0) { 2183 miocnak(q, m, 0, ret); 2184 return (IEEE80211_IOCTL_NOT_REQUIRED); 2185 } 2186 } 2187 /* 2188 * sanity check 2189 */ 2190 m0 = m->b_cont; 2191 if (iocp->ioc_count == 0 || iocp->ioc_count < sizeof (wldp_t) || 2192 m0 == NULL) { 2193 miocnak(q, m, 0, EINVAL); 2194 return (IEEE80211_IOCTL_NOT_REQUIRED); 2195 } 2196 /* 2197 * assuming single data block 2198 */ 2199 if (m0->b_cont) { 2200 freemsg(m0->b_cont); 2201 m0->b_cont = NULL; 2202 } 2203 2204 need_net80211 = B_FALSE; 2205 ret = ipw2100_getset(sc, m0, cmd, &need_net80211); 2206 if (!need_net80211) { 2207 len = msgdsize(m0); 2208 2209 IPW2100_DBG(IPW2100_DBG_IOCTL, (sc->sc_dip, CE_CONT, 2210 "ipw2100_ioctl(): go to call miocack with " 2211 "ret = %d, len = %d\n", ret, len)); 2212 miocack(q, m, len, ret); 2213 return (IEEE80211_IOCTL_NOT_REQUIRED); 2214 } 2215 2216 /* 2217 * IEEE80211_IOCTL_REQUIRED - need net80211 handle 2218 */ 2219 return (IEEE80211_IOCTL_REQUIRED); 2220 } 2221 2222 static int 2223 ipw2100_getset(struct ipw2100_softc *sc, mblk_t *m, uint32_t cmd, 2224 boolean_t *need_net80211) 2225 { 2226 wldp_t *infp, *outfp; 2227 uint32_t id; 2228 int ret; /* IEEE80211_IOCTL - handled by net80211 */ 2229 2230 infp = (wldp_t *)m->b_rptr; 2231 outfp = (wldp_t *)m->b_rptr; 2232 outfp->wldp_result = WL_NOTSUPPORTED; 2233 2234 id = infp->wldp_id; 2235 IPW2100_DBG(IPW2100_DBG_IOCTL, (sc->sc_dip, CE_CONT, 2236 "ipw2100_getset(): id = 0x%x\n", id)); 2237 switch (id) { 2238 /* 2239 * which is not supported by net80211, so it 2240 * has to be handled from driver side 2241 */ 2242 case WL_RADIO: 2243 ret = ipw_wificfg_radio(sc, cmd, outfp); 2244 break; 2245 /* 2246 * so far, drier doesn't support fix-rates 2247 */ 2248 case WL_DESIRED_RATES: 2249 ret = ipw_wificfg_desrates(outfp); 2250 break; 2251 /* 2252 * current net80211 implementation clears the bssid while 2253 * this command received, which will result in the all zero 2254 * mac address for scan'ed AP which is just disconnected. 2255 * This is a workaround solution until net80211 find a 2256 * better method. 2257 */ 2258 case WL_DISASSOCIATE: 2259 ret = ipw_wificfg_disassoc(sc, outfp); 2260 break; 2261 default: 2262 /* 2263 * The wifi IOCTL net80211 supported: 2264 * case WL_ESSID: 2265 * case WL_BSSID: 2266 * case WL_WEP_KEY_TAB: 2267 * case WL_WEP_KEY_ID: 2268 * case WL_AUTH_MODE: 2269 * case WL_ENCRYPTION: 2270 * case WL_BSS_TYPE: 2271 * case WL_ESS_LIST: 2272 * case WL_LINKSTATUS: 2273 * case WL_RSSI: 2274 * case WL_SCAN: 2275 * case WL_LOAD_DEFAULTS: 2276 */ 2277 *need_net80211 = B_TRUE; /* let net80211 do the rest */ 2278 return (0); 2279 } 2280 /* 2281 * we will overwrite everything 2282 */ 2283 m->b_wptr = m->b_rptr + outfp->wldp_length; 2284 2285 return (ret); 2286 } 2287 2288 static int 2289 ipw_wificfg_radio(struct ipw2100_softc *sc, uint32_t cmd, wldp_t *outfp) 2290 { 2291 uint32_t ret = ENOTSUP; 2292 2293 switch (cmd) { 2294 case WLAN_GET_PARAM: 2295 *(wl_linkstatus_t *)(outfp->wldp_buf) = ipw2100_get_radio(sc); 2296 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_linkstatus_t); 2297 outfp->wldp_result = WL_SUCCESS; 2298 ret = 0; /* command sucess */ 2299 break; 2300 case WLAN_SET_PARAM: 2301 default: 2302 break; 2303 } 2304 return (ret); 2305 } 2306 2307 static int 2308 ipw_wificfg_desrates(wldp_t *outfp) 2309 { 2310 /* 2311 * return success, but with result NOTSUPPORTED 2312 */ 2313 outfp->wldp_length = WIFI_BUF_OFFSET; 2314 outfp->wldp_result = WL_NOTSUPPORTED; 2315 return (0); 2316 } 2317 2318 static int 2319 ipw_wificfg_disassoc(struct ipw2100_softc *sc, wldp_t *outfp) 2320 { 2321 struct ieee80211com *ic = &sc->sc_ic; 2322 2323 /* 2324 * init the state 2325 */ 2326 if (ic->ic_state != IEEE80211_S_INIT) { 2327 (void) ieee80211_new_state(ic, IEEE80211_S_INIT, -1); 2328 } 2329 2330 /* 2331 * return success always 2332 */ 2333 outfp->wldp_length = WIFI_BUF_OFFSET; 2334 outfp->wldp_result = WL_SUCCESS; 2335 return (0); 2336 } 2337 /* End of IOCTL Handler */ 2338 2339 static void 2340 ipw2100_fix_channel(struct ieee80211com *ic, mblk_t *m) 2341 { 2342 struct ieee80211_frame *wh; 2343 uint8_t subtype; 2344 uint8_t *frm, *efrm; 2345 2346 wh = (struct ieee80211_frame *)m->b_rptr; 2347 2348 if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_MGT) 2349 return; 2350 2351 subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; 2352 2353 if (subtype != IEEE80211_FC0_SUBTYPE_BEACON && 2354 subtype != IEEE80211_FC0_SUBTYPE_PROBE_RESP) 2355 return; 2356 2357 /* 2358 * assume the message contains only 1 block 2359 */ 2360 frm = (uint8_t *)(wh + 1); 2361 efrm = (uint8_t *)m->b_wptr; 2362 frm += 12; /* skip tstamp, bintval and capinfo fields */ 2363 while (frm < efrm) { 2364 if (*frm == IEEE80211_ELEMID_DSPARMS) { 2365 #if IEEE80211_CHAN_MAX < 255 2366 if (frm[2] <= IEEE80211_CHAN_MAX) 2367 #endif 2368 { 2369 ic->ic_curchan = &ic->ic_sup_channels[frm[2]]; 2370 } 2371 } 2372 frm += frm[1] + 2; 2373 } 2374 } 2375 2376 static void 2377 ipw2100_rcvpkt(struct ipw2100_softc *sc, struct ipw2100_status *status, 2378 uint8_t *rxbuf) 2379 { 2380 struct ieee80211com *ic = &sc->sc_ic; 2381 mblk_t *m; 2382 struct ieee80211_frame *wh = (struct ieee80211_frame *)rxbuf; 2383 struct ieee80211_node *in; 2384 uint32_t rlen; 2385 2386 in = ieee80211_find_rxnode(ic, wh); 2387 rlen = LE_32(status->len); 2388 m = allocb(rlen, BPRI_MED); 2389 if (m) { 2390 (void) memcpy(m->b_wptr, rxbuf, rlen); 2391 m->b_wptr += rlen; 2392 if (ic->ic_state == IEEE80211_S_SCAN) 2393 ipw2100_fix_channel(ic, m); 2394 (void) ieee80211_input(ic, m, in, status->rssi, 0); 2395 } else 2396 IPW2100_WARN((sc->sc_dip, CE_WARN, 2397 "ipw2100_rcvpkg(): cannot allocate receive message(%u)\n", 2398 LE_32(status->len))); 2399 ieee80211_free_node(in); 2400 } 2401 2402 static uint_t 2403 ipw2100_intr(caddr_t arg) 2404 { 2405 struct ipw2100_softc *sc = (struct ipw2100_softc *)arg; 2406 uint32_t ireg, ridx, len, i; 2407 struct ieee80211com *ic = &sc->sc_ic; 2408 struct ipw2100_status *status; 2409 uint8_t *rxbuf; 2410 struct dma_region *dr; 2411 uint32_t state; 2412 #if DEBUG 2413 struct ipw2100_bd *rxbd; 2414 #endif 2415 2416 ireg = ipw2100_csr_get32(sc, IPW2100_CSR_INTR); 2417 2418 if (!(ireg & IPW2100_INTR_MASK_ALL)) 2419 return (DDI_INTR_UNCLAIMED); 2420 2421 /* 2422 * mask all interrupts 2423 */ 2424 ipw2100_csr_put32(sc, IPW2100_CSR_INTR_MASK, 0); 2425 2426 /* 2427 * acknowledge all fired interrupts 2428 */ 2429 ipw2100_csr_put32(sc, IPW2100_CSR_INTR, ireg); 2430 2431 IPW2100_DBG(IPW2100_DBG_INT, (sc->sc_dip, CE_CONT, 2432 "ipw2100_intr(): interrupt is fired. int=0x%08x\n", ireg)); 2433 2434 if (ireg & IPW2100_INTR_MASK_ERR) { 2435 2436 IPW2100_DBG(IPW2100_DBG_FATAL, (sc->sc_dip, CE_CONT, 2437 "ipw2100_intr(): interrupt is fired, MASK = 0x%08x\n", 2438 ireg)); 2439 2440 /* 2441 * inform mfthread to recover hw error 2442 */ 2443 mutex_enter(&sc->sc_mflock); 2444 sc->sc_flags |= IPW2100_FLAG_HW_ERR_RECOVER; 2445 mutex_exit(&sc->sc_mflock); 2446 2447 } else { 2448 2449 /* 2450 * FW intr 2451 */ 2452 if (ireg & IPW2100_INTR_FW_INIT_DONE) { 2453 mutex_enter(&sc->sc_ilock); 2454 sc->sc_flags |= IPW2100_FLAG_FW_INITED; 2455 cv_signal(&sc->sc_fw_cond); 2456 mutex_exit(&sc->sc_ilock); 2457 } 2458 2459 /* 2460 * RX intr 2461 */ 2462 if (ireg & IPW2100_INTR_RX_TRANSFER) { 2463 ridx = ipw2100_csr_get32(sc, 2464 IPW2100_CSR_RX_READ_INDEX); 2465 2466 for (; sc->sc_rx_cur != ridx; 2467 sc->sc_rx_cur = RING_FORWARD( 2468 sc->sc_rx_cur, 1, IPW2100_NUM_RXBD)) { 2469 2470 i = sc->sc_rx_cur; 2471 status = &sc->sc_status[i]; 2472 rxbuf = &sc->sc_rxbufs[i]->rxb_dat[0]; 2473 dr = &sc->sc_dma_rxbufs[i]; 2474 2475 /* 2476 * sync 2477 */ 2478 (void) ddi_dma_sync(sc->sc_dma_status.dr_hnd, 2479 i * sizeof (struct ipw2100_status), 2480 sizeof (struct ipw2100_status), 2481 DDI_DMA_SYNC_FORKERNEL); 2482 (void) ddi_dma_sync(sc->sc_dma_rxbd.dr_hnd, 2483 i * sizeof (struct ipw2100_bd), 2484 sizeof (struct ipw2100_bd), 2485 DDI_DMA_SYNC_FORKERNEL); 2486 (void) ddi_dma_sync(dr->dr_hnd, 0, 2487 sizeof (struct ipw2100_rxb), 2488 DDI_DMA_SYNC_FORKERNEL); 2489 IPW2100_DBG(IPW2100_DBG_INT, 2490 (sc->sc_dip, CE_CONT, 2491 "ipw2100_intr(): " 2492 "status code=0x%04x, len=0x%08x, " 2493 "flags=0x%02x, rssi=%02x\n", 2494 LE_16(status->code), LE_32(status->len), 2495 status->flags, status->rssi)); 2496 #if DEBUG 2497 rxbd = &sc->sc_rxbd[i]; 2498 IPW2100_DBG(IPW2100_DBG_INT, 2499 (sc->sc_dip, CE_CONT, 2500 "ipw2100_intr(): " 2501 "rxbd,phyaddr=0x%08x, len=0x%08x, " 2502 "flags=0x%02x,nfrag=%02x\n", 2503 LE_32(rxbd->phyaddr), LE_32(rxbd->len), 2504 rxbd->flags, rxbd->nfrag)); 2505 #endif 2506 switch (LE_16(status->code) & 0x0f) { 2507 /* 2508 * command complete response 2509 */ 2510 case IPW2100_STATUS_CODE_COMMAND: 2511 mutex_enter(&sc->sc_ilock); 2512 sc->sc_done = 1; 2513 cv_signal(&sc->sc_cmd_cond); 2514 mutex_exit(&sc->sc_ilock); 2515 break; 2516 /* 2517 * change state 2518 */ 2519 case IPW2100_STATUS_CODE_NEWSTATE: 2520 state = LE_32(*((uint32_t *)rxbuf)); 2521 IPW2100_DBG(IPW2100_DBG_INT, 2522 (sc->sc_dip, CE_CONT, 2523 "ipw2100_intr(): " 2524 "newstate,state=0x%x\n", state)); 2525 2526 switch (state) { 2527 case IPW2100_STATE_ASSOCIATED: 2528 ieee80211_new_state(ic, 2529 IEEE80211_S_RUN, -1); 2530 break; 2531 case IPW2100_STATE_ASSOCIATION_LOST: 2532 case IPW2100_STATE_DISABLED: 2533 ieee80211_new_state(ic, 2534 IEEE80211_S_INIT, -1); 2535 break; 2536 case IPW2100_STATE_RADIO_DISABLED: 2537 IPW2100_REPORT((sc->sc_dip, 2538 CE_WARN, 2539 "ipw2100_intr(): " 2540 "RADIO is OFF\n")); 2541 ipw2100_stop(sc); 2542 break; 2543 case IPW2100_STATE_SCAN_COMPLETE: 2544 ieee80211_cancel_scan(ic); 2545 break; 2546 case IPW2100_STATE_SCANNING: 2547 if (ic->ic_state != 2548 IEEE80211_S_RUN) 2549 ieee80211_new_state(ic, 2550 IEEE80211_S_SCAN, 2551 -1); 2552 ic->ic_flags |= 2553 IEEE80211_F_SCAN; 2554 2555 break; 2556 default: 2557 break; 2558 } 2559 break; 2560 case IPW2100_STATUS_CODE_DATA_802_11: 2561 case IPW2100_STATUS_CODE_DATA_802_3: 2562 ipw2100_rcvpkt(sc, status, rxbuf); 2563 break; 2564 case IPW2100_STATUS_CODE_NOTIFICATION: 2565 break; 2566 default: 2567 IPW2100_WARN((sc->sc_dip, CE_WARN, 2568 "ipw2100_intr(): " 2569 "unknown status code 0x%04x\n", 2570 LE_16(status->code))); 2571 break; 2572 } 2573 } 2574 /* 2575 * write sc_rx_cur backward 1 step to RX_WRITE_INDEX 2576 */ 2577 ipw2100_csr_put32(sc, IPW2100_CSR_RX_WRITE_INDEX, 2578 RING_BACKWARD(sc->sc_rx_cur, 1, IPW2100_NUM_RXBD)); 2579 } 2580 2581 /* 2582 * TX intr 2583 */ 2584 if (ireg & IPW2100_INTR_TX_TRANSFER) { 2585 mutex_enter(&sc->sc_tx_lock); 2586 ridx = ipw2100_csr_get32(sc, IPW2100_CSR_TX_READ_INDEX); 2587 len = RING_FLEN(RING_FORWARD(sc->sc_tx_cur, 2588 sc->sc_tx_free, IPW2100_NUM_TXBD), 2589 ridx, IPW2100_NUM_TXBD); 2590 sc->sc_tx_free += len; 2591 IPW2100_DBG(IPW2100_DBG_INT, (sc->sc_dip, CE_CONT, 2592 "ipw2100_intr(): len=%d\n", len)); 2593 mutex_exit(&sc->sc_tx_lock); 2594 2595 mutex_enter(&sc->sc_resched_lock); 2596 if (len > 1 && (sc->sc_flags & IPW2100_FLAG_TX_SCHED)) { 2597 sc->sc_flags &= ~IPW2100_FLAG_TX_SCHED; 2598 mac_tx_update(ic->ic_mach); 2599 } 2600 mutex_exit(&sc->sc_resched_lock); 2601 } 2602 } 2603 2604 /* 2605 * enable all interrupts 2606 */ 2607 ipw2100_csr_put32(sc, IPW2100_CSR_INTR_MASK, IPW2100_INTR_MASK_ALL); 2608 2609 return (DDI_INTR_CLAIMED); 2610 } 2611 2612 2613 /* 2614 * Module Loading Data & Entry Points 2615 */ 2616 DDI_DEFINE_STREAM_OPS(ipw2100_devops, nulldev, nulldev, ipw2100_attach, 2617 ipw2100_detach, nodev, NULL, D_MP, NULL); 2618 2619 static struct modldrv ipw2100_modldrv = { 2620 &mod_driverops, 2621 ipw2100_ident, 2622 &ipw2100_devops 2623 }; 2624 2625 static struct modlinkage ipw2100_modlinkage = { 2626 MODREV_1, 2627 &ipw2100_modldrv, 2628 NULL 2629 }; 2630 2631 int 2632 _init(void) 2633 { 2634 int status; 2635 2636 status = ddi_soft_state_init(&ipw2100_ssp, 2637 sizeof (struct ipw2100_softc), 1); 2638 if (status != DDI_SUCCESS) 2639 return (status); 2640 2641 mac_init_ops(&ipw2100_devops, IPW2100_DRV_NAME); 2642 status = mod_install(&ipw2100_modlinkage); 2643 if (status != DDI_SUCCESS) { 2644 mac_fini_ops(&ipw2100_devops); 2645 ddi_soft_state_fini(&ipw2100_ssp); 2646 } 2647 2648 return (status); 2649 } 2650 2651 int 2652 _fini(void) 2653 { 2654 int status; 2655 2656 status = mod_remove(&ipw2100_modlinkage); 2657 if (status == DDI_SUCCESS) { 2658 mac_fini_ops(&ipw2100_devops); 2659 ddi_soft_state_fini(&ipw2100_ssp); 2660 } 2661 2662 return (status); 2663 } 2664 2665 int 2666 _info(struct modinfo *mip) 2667 { 2668 return (mod_info(&ipw2100_modlinkage, mip)); 2669 } 2670