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_bss->in_bssid); 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 (0); 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 * fix KCF bug. - workaround, need to fix it in net80211 1737 */ 1738 (void) crypto_mech2id(SUN_CKM_RC4); 1739 1740 return (0); 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 (0); 1787 fail: 1788 return (EIO); 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 (0); 1824 fail: 1825 return (EIO); 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 *)(uintptr_t)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); /* ret is errno */ 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 *)(uintptr_t)m->b_rptr; 2243 outfp = (wldp_t *)(uintptr_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 *)(uintptr_t)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 goto enable_interrupt; 2482 } 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, (sc->sc_dip, CE_CONT, 2525 "ipw2100_intr(): status code=0x%04x, len=0x%08x, " 2526 "flags=0x%02x, rssi=%02x\n", 2527 LE_16(status->code), LE_32(status->len), 2528 status->flags, status->rssi)); 2529 #if DEBUG 2530 rxbd = &sc->sc_rxbd[i]; 2531 IPW2100_DBG(IPW2100_DBG_INT, (sc->sc_dip, CE_CONT, 2532 "ipw2100_intr(): rxbd,phyaddr=0x%08x, len=0x%08x, " 2533 "flags=0x%02x,nfrag=%02x\n", 2534 LE_32(rxbd->phyaddr), LE_32(rxbd->len), 2535 rxbd->flags, rxbd->nfrag)); 2536 #endif 2537 switch (LE_16(status->code) & 0x0f) { 2538 /* 2539 * command complete response 2540 */ 2541 case IPW2100_STATUS_CODE_COMMAND: 2542 mutex_enter(&sc->sc_ilock); 2543 sc->sc_done = 1; 2544 cv_signal(&sc->sc_cmd_cond); 2545 mutex_exit(&sc->sc_ilock); 2546 break; 2547 /* 2548 * change state 2549 */ 2550 case IPW2100_STATUS_CODE_NEWSTATE: 2551 state = LE_32(* ((uint32_t *)(uintptr_t)rxbuf)); 2552 IPW2100_DBG(IPW2100_DBG_INT, 2553 (sc->sc_dip, CE_CONT, 2554 "ipw2100_intr(): newstate,state=0x%x\n", 2555 state)); 2556 2557 switch (state) { 2558 case IPW2100_STATE_ASSOCIATED: 2559 ieee80211_new_state(ic, 2560 IEEE80211_S_RUN, -1); 2561 break; 2562 case IPW2100_STATE_ASSOCIATION_LOST: 2563 case IPW2100_STATE_DISABLED: 2564 ieee80211_new_state(ic, 2565 IEEE80211_S_INIT, -1); 2566 break; 2567 /* 2568 * When radio is OFF, need a better 2569 * scan approach to ensure scan 2570 * result correct. 2571 */ 2572 case IPW2100_STATE_RADIO_DISABLED: 2573 IPW2100_REPORT((sc->sc_dip, CE_WARN, 2574 "ipw2100_intr(): RADIO is OFF\n")); 2575 ipw2100_stop(sc); 2576 break; 2577 case IPW2100_STATE_SCAN_COMPLETE: 2578 ieee80211_cancel_scan(ic); 2579 break; 2580 case IPW2100_STATE_SCANNING: 2581 if (ic->ic_state != IEEE80211_S_RUN) 2582 ieee80211_new_state(ic, 2583 IEEE80211_S_SCAN, -1); 2584 ic->ic_flags |= IEEE80211_F_SCAN; 2585 2586 break; 2587 default: 2588 break; 2589 } 2590 break; 2591 case IPW2100_STATUS_CODE_DATA_802_11: 2592 case IPW2100_STATUS_CODE_DATA_802_3: 2593 ipw2100_rcvpkt(sc, status, rxbuf); 2594 break; 2595 case IPW2100_STATUS_CODE_NOTIFICATION: 2596 break; 2597 default: 2598 IPW2100_WARN((sc->sc_dip, CE_WARN, 2599 "ipw2100_intr(): " 2600 "unknown status code 0x%04x\n", 2601 LE_16(status->code))); 2602 break; 2603 } 2604 } 2605 /* 2606 * write sc_rx_cur backward 1 step to RX_WRITE_INDEX 2607 */ 2608 ipw2100_csr_put32(sc, IPW2100_CSR_RX_WRITE_INDEX, 2609 RING_BACKWARD(sc->sc_rx_cur, 1, IPW2100_NUM_RXBD)); 2610 } 2611 2612 /* 2613 * TX intr 2614 */ 2615 if (ireg & IPW2100_INTR_TX_TRANSFER) { 2616 mutex_enter(&sc->sc_tx_lock); 2617 ridx = ipw2100_csr_get32(sc, IPW2100_CSR_TX_READ_INDEX); 2618 len = RING_FLEN(RING_FORWARD(sc->sc_tx_cur, 2619 sc->sc_tx_free, IPW2100_NUM_TXBD), 2620 ridx, IPW2100_NUM_TXBD); 2621 sc->sc_tx_free += len; 2622 IPW2100_DBG(IPW2100_DBG_INT, (sc->sc_dip, CE_CONT, 2623 "ipw2100_intr(): len=%d\n", len)); 2624 mutex_exit(&sc->sc_tx_lock); 2625 2626 mutex_enter(&sc->sc_resched_lock); 2627 if (len > 1 && (sc->sc_flags & IPW2100_FLAG_TX_SCHED)) { 2628 sc->sc_flags &= ~IPW2100_FLAG_TX_SCHED; 2629 mac_tx_update(ic->ic_mach); 2630 } 2631 mutex_exit(&sc->sc_resched_lock); 2632 } 2633 2634 enable_interrupt: 2635 /* 2636 * enable all interrupts 2637 */ 2638 ipw2100_csr_put32(sc, IPW2100_CSR_INTR_MASK, IPW2100_INTR_MASK_ALL); 2639 2640 return (DDI_INTR_CLAIMED); 2641 } 2642 2643 2644 /* 2645 * Module Loading Data & Entry Points 2646 */ 2647 DDI_DEFINE_STREAM_OPS(ipw2100_devops, nulldev, nulldev, ipw2100_attach, 2648 ipw2100_detach, ipw2100_reset, NULL, D_MP, NULL); 2649 2650 static struct modldrv ipw2100_modldrv = { 2651 &mod_driverops, 2652 ipw2100_ident, 2653 &ipw2100_devops 2654 }; 2655 2656 static struct modlinkage ipw2100_modlinkage = { 2657 MODREV_1, 2658 &ipw2100_modldrv, 2659 NULL 2660 }; 2661 2662 int 2663 _init(void) 2664 { 2665 int status; 2666 2667 status = ddi_soft_state_init(&ipw2100_ssp, 2668 sizeof (struct ipw2100_softc), 1); 2669 if (status != DDI_SUCCESS) 2670 return (status); 2671 2672 mac_init_ops(&ipw2100_devops, IPW2100_DRV_NAME); 2673 status = mod_install(&ipw2100_modlinkage); 2674 if (status != DDI_SUCCESS) { 2675 mac_fini_ops(&ipw2100_devops); 2676 ddi_soft_state_fini(&ipw2100_ssp); 2677 } 2678 2679 return (status); 2680 } 2681 2682 int 2683 _fini(void) 2684 { 2685 int status; 2686 2687 status = mod_remove(&ipw2100_modlinkage); 2688 if (status == DDI_SUCCESS) { 2689 mac_fini_ops(&ipw2100_devops); 2690 ddi_soft_state_fini(&ipw2100_ssp); 2691 } 2692 2693 return (status); 2694 } 2695 2696 int 2697 _info(struct modinfo *mip) 2698 { 2699 return (mod_info(&ipw2100_modlinkage, mip)); 2700 } 2701