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