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