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