1 /* 2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* 7 * Copyright (c) 2004, 2005 8 * Damien Bergamini <damien.bergamini@free.fr>. All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice unmodified, this list of conditions, and the following 15 * disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #pragma ident "%Z%%M% %I% %E% SMI" 34 35 #include <sys/types.h> 36 #include <sys/byteorder.h> 37 #include <sys/conf.h> 38 #include <sys/cmn_err.h> 39 #include <sys/stat.h> 40 #include <sys/ddi.h> 41 #include <sys/sunddi.h> 42 #include <sys/strsubr.h> 43 #include <sys/ethernet.h> 44 #include <inet/common.h> 45 #include <inet/nd.h> 46 #include <inet/mi.h> 47 #include <sys/note.h> 48 #include <sys/stream.h> 49 #include <sys/strsun.h> 50 #include <sys/modctl.h> 51 #include <sys/devops.h> 52 #include <sys/dlpi.h> 53 #include <sys/mac.h> 54 #include <sys/mac_wifi.h> 55 #include <sys/varargs.h> 56 #include <sys/pci.h> 57 #include <sys/policy.h> 58 #include <sys/random.h> 59 #include <sys/crypto/common.h> 60 #include <sys/crypto/api.h> 61 62 #include "ipw2200.h" 63 #include "ipw2200_impl.h" 64 #include <inet/wifi_ioctl.h> 65 66 /* 67 * for net80211 kernel usage 68 */ 69 #include <sys/net80211.h> 70 #include <sys/net80211_proto.h> 71 72 /* 73 * minimal size reserved in tx-ring 74 */ 75 #define IPW2200_TX_RING_MIN (8) 76 #define IPW2200_TXBUF_SIZE (IEEE80211_MAX_LEN) 77 #define IPW2200_RXBUF_SIZE (4096) 78 79 static void *ipw2200_ssp = NULL; 80 static char ipw2200_ident[] = IPW2200_DRV_DESC " " IPW2200_DRV_REV; 81 82 /* 83 * PIO access attributor for registers 84 */ 85 static ddi_device_acc_attr_t ipw2200_csr_accattr = { 86 DDI_DEVICE_ATTR_V0, 87 DDI_STRUCTURE_LE_ACC, 88 DDI_STRICTORDER_ACC 89 }; 90 91 /* 92 * DMA access attributor for descriptors 93 */ 94 static ddi_device_acc_attr_t ipw2200_dma_accattr = { 95 DDI_DEVICE_ATTR_V0, 96 DDI_NEVERSWAP_ACC, 97 DDI_STRICTORDER_ACC 98 }; 99 100 /* 101 * Describes the chip's DMA engine 102 */ 103 static ddi_dma_attr_t ipw2200_dma_attr = { 104 DMA_ATTR_V0, /* version */ 105 0x0000000000000000ULL, /* addr_lo */ 106 0x00000000ffffffffULL, /* addr_hi */ 107 0x00000000ffffffffULL, /* counter */ 108 0x0000000000000004ULL, /* alignment */ 109 0xfff, /* burst */ 110 1, /* min xfer */ 111 0x00000000ffffffffULL, /* max xfer */ 112 0x00000000ffffffffULL, /* seg boud */ 113 1, /* s/g list */ 114 1, /* granularity */ 115 0 /* flags */ 116 }; 117 118 static uint8_t ipw2200_broadcast_addr[] = { 119 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 120 }; 121 static const struct ieee80211_rateset ipw2200_rateset_11a = { 8, 122 {12, 18, 24, 36, 48, 72, 96, 108} 123 }; 124 static const struct ieee80211_rateset ipw2200_rateset_11b = { 4, 125 {2, 4, 11, 22} 126 }; 127 static const struct ieee80211_rateset ipw2200_rateset_11g = { 12, 128 {2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108} 129 }; 130 131 /* 132 * Used by multi function thread 133 */ 134 extern pri_t minclsyspri; 135 136 /* 137 * ipw2200 specific hardware operations 138 */ 139 static void ipw2200_hwconf_get(struct ipw2200_softc *sc); 140 static int ipw2200_chip_reset(struct ipw2200_softc *sc); 141 static void ipw2200_master_stop(struct ipw2200_softc *sc); 142 static void ipw2200_stop(struct ipw2200_softc *sc); 143 static int ipw2200_config(struct ipw2200_softc *sc); 144 static int ipw2200_cmd(struct ipw2200_softc *sc, 145 uint32_t type, void *buf, size_t len, int async); 146 static void ipw2200_ring_hwsetup(struct ipw2200_softc *sc); 147 static int ipw2200_ring_alloc(struct ipw2200_softc *sc); 148 static void ipw2200_ring_free(struct ipw2200_softc *sc); 149 static void ipw2200_ring_reset(struct ipw2200_softc *sc); 150 static int ipw2200_ring_init(struct ipw2200_softc *sc); 151 152 /* 153 * GLD specific operations 154 */ 155 static int ipw2200_m_stat(void *arg, uint_t stat, uint64_t *val); 156 static int ipw2200_m_start(void *arg); 157 static void ipw2200_m_stop(void *arg); 158 static int ipw2200_m_unicst(void *arg, const uint8_t *macaddr); 159 static int ipw2200_m_multicst(void *arg, boolean_t add, const uint8_t *m); 160 static int ipw2200_m_promisc(void *arg, boolean_t on); 161 static void ipw2200_m_ioctl(void *arg, queue_t *wq, mblk_t *mp); 162 static mblk_t *ipw2200_m_tx(void *arg, mblk_t *mp); 163 164 /* 165 * Interrupt and Data transferring operations 166 */ 167 static uint_t ipw2200_intr(caddr_t arg); 168 static int ipw2200_send(struct ieee80211com *ic, mblk_t *mp, uint8_t type); 169 static void ipw2200_rcv_frame(struct ipw2200_softc *sc, 170 struct ipw2200_frame *frame); 171 static void ipw2200_rcv_notif(struct ipw2200_softc *sc, 172 struct ipw2200_notif *notif); 173 174 /* 175 * WiFi specific operations 176 */ 177 static int ipw2200_newstate(struct ieee80211com *ic, 178 enum ieee80211_state state, int arg); 179 static void ipw2200_thread(struct ipw2200_softc *sc); 180 181 /* 182 * IOCTL Handler 183 */ 184 static int ipw2200_ioctl(struct ipw2200_softc *sc, queue_t *q, mblk_t *m); 185 static int ipw2200_getset(struct ipw2200_softc *sc, 186 mblk_t *m, uint32_t cmd, boolean_t *need_net80211); 187 static int iwi_wificfg_radio(struct ipw2200_softc *sc, 188 uint32_t cmd, wldp_t *outfp); 189 static int iwi_wificfg_desrates(wldp_t *outfp); 190 191 /* 192 * net80211 functions 193 */ 194 extern uint8_t ieee80211_crypto_getciphertype(ieee80211com_t *ic); 195 extern void ieee80211_notify_node_join(ieee80211com_t *ic, 196 ieee80211_node_t *in); 197 extern void ieee80211_notify_node_leave(ieee80211com_t *ic, 198 ieee80211_node_t *in); 199 200 /* 201 * Mac Call Back entries 202 */ 203 mac_callbacks_t ipw2200_m_callbacks = { 204 MC_IOCTL, 205 ipw2200_m_stat, 206 ipw2200_m_start, 207 ipw2200_m_stop, 208 ipw2200_m_promisc, 209 ipw2200_m_multicst, 210 ipw2200_m_unicst, 211 ipw2200_m_tx, 212 NULL, 213 ipw2200_m_ioctl 214 }; 215 216 /* 217 * DEBUG Facility 218 */ 219 #define MAX_MSG (128) 220 uint32_t ipw2200_debug = 0; 221 /* 222 * supported debug marks are: 223 * | IPW2200_DBG_CSR 224 * | IPW2200_DBG_TABLE 225 * | IPW2200_DBG_HWCAP 226 * | IPW2200_DBG_TX 227 * | IPW2200_DBG_INIT 228 * | IPW2200_DBG_FW 229 * | IPW2200_DBG_NOTIF 230 * | IPW2200_DBG_SCAN 231 * | IPW2200_DBG_IOCTL 232 * | IPW2200_DBG_RING 233 * | IPW2200_DBG_INT 234 * | IPW2200_DBG_RX 235 * | IPW2200_DBG_DMA 236 * | IPW2200_DBG_GLD 237 * | IPW2200_DBG_WIFI 238 * | IPW2200_DBG_SOFTINT 239 */ 240 241 /* 242 * Global tunning parameter to work around unknown hardware issues 243 */ 244 static uint32_t delay_config_stable = 100000; /* 100ms */ 245 static uint32_t delay_fatal_recover = 100000 * 20; /* 2s */ 246 static uint32_t delay_aux_thread = 100000; /* 100ms */ 247 248 #define IEEE80211_IS_CHAN_2GHZ(_c) \ 249 (((_c)->ich_flags & IEEE80211_CHAN_2GHZ) != 0) 250 #define IEEE80211_IS_CHAN_5GHZ(_c) \ 251 (((_c)->ich_flags & IEEE80211_CHAN_5GHZ) != 0) 252 #define isset(a, i) ((a)[(i)/NBBY] & (1 << ((i)%NBBY))) 253 254 void 255 ipw2200_dbg(dev_info_t *dip, int level, const char *fmt, ...) 256 { 257 va_list ap; 258 char buf[MAX_MSG]; 259 int instance; 260 261 va_start(ap, fmt); 262 (void) vsnprintf(buf, sizeof (buf), fmt, ap); 263 va_end(ap); 264 265 if (dip) { 266 instance = ddi_get_instance(dip); 267 cmn_err(level, "%s%d: %s", IPW2200_DRV_NAME, instance, buf); 268 } else 269 cmn_err(level, "%s: %s", IPW2200_DRV_NAME, buf); 270 271 } 272 273 /* 274 * Device operations 275 */ 276 int 277 ipw2200_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 278 { 279 struct ipw2200_softc *sc; 280 ddi_acc_handle_t cfgh; 281 caddr_t regs; 282 struct ieee80211com *ic; 283 int instance, err, i; 284 char strbuf[32]; 285 wifi_data_t wd = { 0 }; 286 mac_register_t *macp; 287 uint16_t vendor, device, subven, subdev; 288 289 if (cmd != DDI_ATTACH) { 290 err = DDI_FAILURE; 291 goto fail1; 292 } 293 294 instance = ddi_get_instance(dip); 295 err = ddi_soft_state_zalloc(ipw2200_ssp, instance); 296 if (err != DDI_SUCCESS) { 297 IPW2200_WARN((dip, CE_WARN, 298 "ipw2200_attach(): unable to allocate soft state\n")); 299 goto fail1; 300 } 301 sc = ddi_get_soft_state(ipw2200_ssp, instance); 302 sc->sc_dip = dip; 303 304 /* 305 * Map config spaces register to read the vendor id, device id, sub 306 * vendor id, and sub device id. 307 */ 308 err = ddi_regs_map_setup(dip, IPW2200_PCI_CFG_RNUM, ®s, 309 0, 0, &ipw2200_csr_accattr, &cfgh); 310 if (err != DDI_SUCCESS) { 311 IPW2200_WARN((dip, CE_WARN, 312 "ipw2200_attach(): unable to map spaces regs\n")); 313 goto fail2; 314 } 315 ddi_put8(cfgh, (uint8_t *)(regs + 0x41), 0); 316 vendor = ddi_get16(cfgh, (uint16_t *)(regs + PCI_CONF_VENID)); 317 device = ddi_get16(cfgh, (uint16_t *)(regs + PCI_CONF_DEVID)); 318 subven = ddi_get16(cfgh, (uint16_t *)(regs + PCI_CONF_SUBVENID)); 319 subdev = ddi_get16(cfgh, (uint16_t *)(regs + PCI_CONF_SUBSYSID)); 320 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 321 "ipw2200_attach(): vendor = 0x%04x, devic = 0x%04x," 322 "subversion = 0x%04x, subdev = 0x%04x", 323 vendor, device, subven, subdev)); 324 ddi_regs_map_free(&cfgh); 325 326 /* 327 * Map operating registers 328 */ 329 err = ddi_regs_map_setup(dip, IPW2200_PCI_CSR_RNUM, &sc->sc_regs, 330 0, 0, &ipw2200_csr_accattr, &sc->sc_ioh); 331 if (err != DDI_SUCCESS) { 332 IPW2200_WARN((dip, CE_WARN, 333 "ipw2200_attach(): ddi_regs_map_setup() failed\n")); 334 goto fail2; 335 } 336 337 /* 338 * Reset the chip 339 */ 340 err = ipw2200_chip_reset(sc); 341 if (err != DDI_SUCCESS) { 342 IPW2200_WARN((dip, CE_WARN, 343 "ipw2200_attach(): ipw2200_chip_reset() failed\n")); 344 goto fail3; 345 } 346 347 /* 348 * Get the hardware configuration, including the MAC address 349 * Then, init all the rings needed. 350 */ 351 ipw2200_hwconf_get(sc); 352 err = ipw2200_ring_init(sc); 353 if (err != DDI_SUCCESS) { 354 IPW2200_WARN((dip, CE_WARN, 355 "ipw2200_attach(): ipw2200_ring_init() failed\n")); 356 goto fail3; 357 } 358 359 /* 360 * Initialize mutexs and condvars 361 */ 362 err = ddi_get_iblock_cookie(dip, 0, &sc->sc_iblk); 363 if (err != DDI_SUCCESS) { 364 IPW2200_WARN((dip, CE_WARN, 365 "ipw2200_attach(): ddi_get_iblock_cookie() failed\n")); 366 goto fail4; 367 } 368 369 /* 370 * interrupt lock 371 */ 372 mutex_init(&sc->sc_ilock, "intr-lock", MUTEX_DRIVER, 373 (void *) sc->sc_iblk); 374 cv_init(&sc->sc_fw_cond, "firmware-ok", CV_DRIVER, NULL); 375 cv_init(&sc->sc_cmd_status_cond, "cmd-status-ring", CV_DRIVER, NULL); 376 377 /* 378 * command ring lock 379 */ 380 mutex_init(&sc->sc_cmd_lock, "cmd-ring", MUTEX_DRIVER, 381 (void *) sc->sc_iblk); 382 cv_init(&sc->sc_cmd_cond, "cmd-ring", CV_DRIVER, NULL); 383 384 /* 385 * tx ring lock 386 */ 387 mutex_init(&sc->sc_tx_lock, "tx-ring", MUTEX_DRIVER, 388 (void *) sc->sc_iblk); 389 390 /* 391 * rescheduled lock 392 */ 393 mutex_init(&sc->sc_resched_lock, "reschedule-lock", MUTEX_DRIVER, 394 (void *) sc->sc_iblk); 395 396 /* 397 * multi-function lock, may acquire this during interrupt 398 */ 399 mutex_init(&sc->sc_mflock, "function-lock", MUTEX_DRIVER, 400 (void *) sc->sc_iblk); 401 cv_init(&sc->sc_mfthread_cv, NULL, CV_DRIVER, NULL); 402 sc->sc_mf_thread = NULL; 403 sc->sc_mfthread_switch = 0; 404 405 /* 406 * Initialize the WiFi part 407 */ 408 ic = &sc->sc_ic; 409 ic->ic_phytype = IEEE80211_T_OFDM; 410 ic->ic_opmode = IEEE80211_M_STA; 411 ic->ic_state = IEEE80211_S_INIT; 412 ic->ic_maxrssi = 100; /* experimental number */ 413 ic->ic_caps = 414 IEEE80211_C_SHPREAMBLE | 415 IEEE80211_C_TXPMGT | 416 IEEE80211_C_PMGT | 417 IEEE80211_C_WPA; 418 419 /* 420 * set mac addr 421 */ 422 IEEE80211_ADDR_COPY(ic->ic_macaddr, sc->sc_macaddr); 423 424 /* 425 * set supported .11a rates and channel - (2915ABG only) 426 */ 427 if (device >= 0x4223) { 428 /* .11a rates */ 429 ic->ic_sup_rates[IEEE80211_MODE_11A] = ipw2200_rateset_11a; 430 /* .11a channels */ 431 for (i = 36; i <= 64; i += 4) { 432 ic->ic_sup_channels[i].ich_freq = 433 ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ); 434 ic->ic_sup_channels[i].ich_flags = /* CHAN_A */ 435 IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM; 436 } 437 for (i = 149; i <= 165; i += 4) { 438 ic->ic_sup_channels[i].ich_freq = 439 ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ); 440 ic->ic_sup_channels[i].ich_flags = /* CHAN_A */ 441 IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM; 442 } 443 } 444 445 /* 446 * set supported .11b and .11g rates 447 */ 448 ic->ic_sup_rates[IEEE80211_MODE_11B] = ipw2200_rateset_11b; 449 ic->ic_sup_rates[IEEE80211_MODE_11G] = ipw2200_rateset_11g; 450 451 /* 452 * set supported .11b and .11g channels(1 through 14) 453 */ 454 for (i = 1; i < 14; i++) { 455 ic->ic_sup_channels[i].ich_freq = 456 ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ); 457 ic->ic_sup_channels[i].ich_flags = 458 IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM | 459 IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ; 460 } 461 462 /* 463 * IBSS channal undefined for now 464 */ 465 ic->ic_ibss_chan = &ic->ic_sup_channels[0]; 466 ic->ic_xmit = ipw2200_send; 467 468 /* 469 * init generic layer, then override state transition machine 470 */ 471 ieee80211_attach(ic); 472 473 /* 474 * different instance has different WPA door 475 */ 476 ieee80211_register_door(ic, ddi_driver_name(dip), instance); 477 478 /* 479 * Override 80211 default routines 480 */ 481 ieee80211_media_init(ic); /* initial the node table and bss */ 482 sc->sc_newstate = ic->ic_newstate; 483 ic->ic_newstate = ipw2200_newstate; 484 ic->ic_def_txkey = 0; 485 sc->sc_authmode = IEEE80211_AUTH_OPEN; 486 487 /* 488 * Add the interrupt handler 489 */ 490 err = ddi_add_intr(dip, 0, &sc->sc_iblk, NULL, 491 ipw2200_intr, (caddr_t)sc); 492 if (err != DDI_SUCCESS) { 493 IPW2200_WARN((dip, CE_WARN, 494 "ipw2200_attach(): ddi_add_intr() failed\n")); 495 goto fail5; 496 } 497 498 /* 499 * Initialize pointer to device specific functions 500 */ 501 wd.wd_secalloc = WIFI_SEC_NONE; 502 wd.wd_opmode = ic->ic_opmode; 503 IEEE80211_ADDR_COPY(wd.wd_bssid, ic->ic_bss->in_bssid); 504 505 macp = mac_alloc(MAC_VERSION); 506 if (err != 0) { 507 IPW2200_WARN((dip, CE_WARN, 508 "ipw2200_attach(): mac_alloc() failed\n")); 509 goto fail6; 510 } 511 512 macp->m_type_ident = MAC_PLUGIN_IDENT_WIFI; 513 macp->m_driver = sc; 514 macp->m_dip = dip; 515 macp->m_src_addr = ic->ic_macaddr; 516 macp->m_callbacks = &ipw2200_m_callbacks; 517 macp->m_min_sdu = 0; 518 macp->m_max_sdu = IEEE80211_MTU; 519 macp->m_pdata = &wd; 520 macp->m_pdata_size = sizeof (wd); 521 522 /* 523 * Register the macp to mac 524 */ 525 err = mac_register(macp, &ic->ic_mach); 526 mac_free(macp); 527 if (err != DDI_SUCCESS) { 528 IPW2200_WARN((dip, CE_WARN, 529 "ipw2200_attach(): mac_register() failed\n")); 530 goto fail6; 531 } 532 533 /* 534 * Create minor node of type DDI_NT_NET_WIFI 535 */ 536 (void) snprintf(strbuf, sizeof (strbuf), "%s%d", 537 IPW2200_DRV_NAME, instance); 538 err = ddi_create_minor_node(dip, strbuf, S_IFCHR, 539 instance + 1, DDI_NT_NET_WIFI, 0); 540 if (err != DDI_SUCCESS) 541 IPW2200_WARN((dip, CE_WARN, 542 "ipw2200_attach(): ddi_create_minor_node() failed\n")); 543 544 /* 545 * Cache firmware will always be true 546 */ 547 (void) ipw2200_cache_firmware(sc); 548 549 /* 550 * Notify link is down now 551 */ 552 mac_link_update(ic->ic_mach, LINK_STATE_DOWN); 553 554 /* 555 * Create the mf thread to handle the link status, 556 * recovery fatal error, etc. 557 */ 558 sc->sc_mfthread_switch = 1; 559 if (sc->sc_mf_thread == NULL) 560 sc->sc_mf_thread = thread_create((caddr_t)NULL, 0, 561 ipw2200_thread, sc, 0, &p0, TS_RUN, minclsyspri); 562 563 return (DDI_SUCCESS); 564 565 fail6: 566 ddi_remove_intr(dip, 0, sc->sc_iblk); 567 fail5: 568 ieee80211_detach(ic); 569 570 mutex_destroy(&sc->sc_ilock); 571 mutex_destroy(&sc->sc_cmd_lock); 572 mutex_destroy(&sc->sc_tx_lock); 573 mutex_destroy(&sc->sc_mflock); 574 mutex_destroy(&sc->sc_resched_lock); 575 cv_destroy(&sc->sc_fw_cond); 576 cv_destroy(&sc->sc_cmd_status_cond); 577 cv_destroy(&sc->sc_cmd_cond); 578 cv_destroy(&sc->sc_mfthread_cv); 579 fail4: 580 ipw2200_ring_free(sc); 581 fail3: 582 ddi_regs_map_free(&sc->sc_ioh); 583 fail2: 584 ddi_soft_state_free(ipw2200_ssp, instance); 585 fail1: 586 return (err); 587 } 588 589 590 int 591 ipw2200_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 592 { 593 struct ipw2200_softc *sc = 594 ddi_get_soft_state(ipw2200_ssp, ddi_get_instance(dip)); 595 int err; 596 ASSERT(sc != NULL); 597 598 if (cmd != DDI_DETACH) 599 return (DDI_FAILURE); 600 601 ipw2200_stop(sc); 602 603 /* 604 * Destroy the mf_thread 605 */ 606 mutex_enter(&sc->sc_mflock); 607 sc->sc_mfthread_switch = 0; 608 while (sc->sc_mf_thread != NULL) { 609 if (cv_wait_sig(&sc->sc_mfthread_cv, &sc->sc_mflock) == 0) 610 break; 611 } 612 mutex_exit(&sc->sc_mflock); 613 614 /* 615 * Unregister from the MAC layer subsystem 616 */ 617 err = mac_unregister(sc->sc_ic.ic_mach); 618 if (err != DDI_SUCCESS) 619 return (err); 620 621 ddi_remove_intr(dip, IPW2200_PCI_INTR_NUM, sc->sc_iblk); 622 623 mutex_destroy(&sc->sc_ilock); 624 mutex_destroy(&sc->sc_cmd_lock); 625 mutex_destroy(&sc->sc_tx_lock); 626 mutex_destroy(&sc->sc_mflock); 627 mutex_destroy(&sc->sc_resched_lock); 628 cv_destroy(&sc->sc_fw_cond); 629 cv_destroy(&sc->sc_cmd_status_cond); 630 cv_destroy(&sc->sc_cmd_cond); 631 cv_destroy(&sc->sc_mfthread_cv); 632 633 /* 634 * Detach ieee80211 635 */ 636 ieee80211_detach(&sc->sc_ic); 637 638 (void) ipw2200_free_firmware(sc); 639 ipw2200_ring_free(sc); 640 641 ddi_regs_map_free(&sc->sc_ioh); 642 ddi_remove_minor_node(dip, NULL); 643 ddi_soft_state_free(ipw2200_ssp, ddi_get_instance(dip)); 644 645 return (DDI_SUCCESS); 646 } 647 648 /* ARGSUSED */ 649 int 650 ipw2200_reset(dev_info_t *dip, ddi_reset_cmd_t cmd) 651 { 652 struct ipw2200_softc *sc = 653 ddi_get_soft_state(ipw2200_ssp, ddi_get_instance(dip)); 654 ASSERT(sc != NULL); 655 656 ipw2200_stop(sc); 657 658 return (DDI_SUCCESS); 659 } 660 661 static void 662 ipw2200_stop(struct ipw2200_softc *sc) 663 { 664 struct ieee80211com *ic = &sc->sc_ic; 665 666 IPW2200_DBG(IPW2200_DBG_HWCAP, (sc->sc_dip, CE_CONT, 667 "ipw2200_stop(): enter\n")); 668 669 ipw2200_master_stop(sc); 670 ipw2200_csr_put32(sc, IPW2200_CSR_RST, IPW2200_RST_SW_RESET); 671 672 /* 673 * Reset ring 674 */ 675 ipw2200_ring_reset(sc); 676 677 ieee80211_new_state(ic, IEEE80211_S_INIT, -1); 678 sc->sc_flags &= ~IPW2200_FLAG_SCANNING; 679 sc->sc_flags &= ~IPW2200_FLAG_ASSOCIATED; 680 681 IPW2200_DBG(IPW2200_DBG_HWCAP, (sc->sc_dip, CE_CONT, 682 "ipw2200_stop(): exit\n")); 683 } 684 685 static int 686 ipw2200_config(struct ipw2200_softc *sc) 687 { 688 struct ieee80211com *ic = &sc->sc_ic; 689 struct ipw2200_configuration cfg; 690 uint32_t data; 691 struct ipw2200_txpower pwr; 692 struct ipw2200_rateset rs; 693 struct ipw2200_wep_key wkey; 694 int err, i; 695 696 /* 697 * Set the IBSS mode channel: Tx power 698 */ 699 if (ic->ic_opmode == IEEE80211_M_IBSS) { 700 pwr.mode = IPW2200_MODE_11B; 701 pwr.nchan = 11; 702 for (i = 0; i < pwr.nchan; i++) { 703 pwr.chan[i].chan = i + 1; 704 pwr.chan[i].power = IPW2200_TXPOWER_MAX; 705 } 706 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 707 "ipw2200_config(): Setting .11b channels Tx power\n")); 708 err = ipw2200_cmd(sc, IPW2200_CMD_SET_TX_POWER, 709 &pwr, sizeof (pwr), 0); 710 if (err != DDI_SUCCESS) 711 return (err); 712 713 pwr.mode = IPW2200_MODE_11G; 714 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 715 "ipw2200_config(): Setting .11g channels Tx power\n")); 716 err = ipw2200_cmd(sc, IPW2200_CMD_SET_TX_POWER, 717 &pwr, sizeof (pwr), 0); 718 if (err != DDI_SUCCESS) 719 return (err); 720 } 721 722 /* 723 * Set MAC address 724 */ 725 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 726 "ipw2200_config(): Setting MAC address to " 727 "%02x:%02x:%02x:%02x:%02x:%02x\n", 728 ic->ic_macaddr[0], ic->ic_macaddr[1], ic->ic_macaddr[2], 729 ic->ic_macaddr[3], ic->ic_macaddr[4], ic->ic_macaddr[5])); 730 err = ipw2200_cmd(sc, IPW2200_CMD_SET_MAC_ADDRESS, ic->ic_macaddr, 731 IEEE80211_ADDR_LEN, 0); 732 if (err != DDI_SUCCESS) 733 return (err); 734 735 /* 736 * Set basic system config settings: configuration(capabilities) 737 */ 738 (void) memset(&cfg, 0, sizeof (cfg)); 739 cfg.bluetooth_coexistence = 1; 740 cfg.multicast_enabled = 1; 741 cfg.answer_pbreq = 1; 742 cfg.noise_reported = 1; 743 cfg.disable_multicast_decryption = 1; /* WPA */ 744 cfg.disable_unicast_decryption = 1; /* WPA */ 745 746 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 747 "ipw2200_config(): Configuring adapter\n")); 748 err = ipw2200_cmd(sc, IPW2200_CMD_SET_CONFIG, 749 &cfg, sizeof (cfg), 0); 750 if (err != DDI_SUCCESS) 751 return (err); 752 753 /* 754 * Set power mode 755 */ 756 data = LE_32(IPW2200_POWER_MODE_CAM); 757 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 758 "ipw2200_config(): Setting power mode to %u\n", LE_32(data))); 759 err = ipw2200_cmd(sc, IPW2200_CMD_SET_POWER_MODE, 760 &data, sizeof (data), 0); 761 if (err != DDI_SUCCESS) 762 return (err); 763 764 /* 765 * Set supported rates 766 */ 767 rs.mode = IPW2200_MODE_11G; 768 rs.type = IPW2200_RATESET_TYPE_SUPPORTED; 769 rs.nrates = ic->ic_sup_rates[IEEE80211_MODE_11G].ir_nrates; 770 (void) memcpy(rs.rates, ic->ic_sup_rates[IEEE80211_MODE_11G].ir_rates, 771 rs.nrates); 772 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 773 "ipw2200_config(): Setting .11g supported rates(%u)\n", rs.nrates)); 774 err = ipw2200_cmd(sc, IPW2200_CMD_SET_RATES, &rs, sizeof (rs), 0); 775 if (err != DDI_SUCCESS) 776 return (err); 777 778 rs.mode = IPW2200_MODE_11A; 779 rs.type = IPW2200_RATESET_TYPE_SUPPORTED; 780 rs.nrates = ic->ic_sup_rates[IEEE80211_MODE_11A].ir_nrates; 781 (void) memcpy(rs.rates, ic->ic_sup_rates[IEEE80211_MODE_11A].ir_rates, 782 rs.nrates); 783 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 784 "ipw2200_config(): Setting .11a supported rates(%u)\n", rs.nrates)); 785 err = ipw2200_cmd(sc, IPW2200_CMD_SET_RATES, &rs, sizeof (rs), 0); 786 if (err != DDI_SUCCESS) 787 return (err); 788 789 /* 790 * Set RTS(request-to-send) threshold 791 */ 792 data = LE_32(ic->ic_rtsthreshold); 793 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 794 "ipw2200_config(): Setting RTS threshold to %u\n", LE_32(data))); 795 err = ipw2200_cmd(sc, IPW2200_CMD_SET_RTS_THRESHOLD, &data, 796 sizeof (data), 0); 797 if (err != DDI_SUCCESS) 798 return (err); 799 800 /* 801 * Set fragmentation threshold 802 */ 803 data = LE_32(ic->ic_fragthreshold); 804 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 805 "ipw2200_config(): Setting fragmentation threshold to %u\n", 806 LE_32(data))); 807 err = ipw2200_cmd(sc, IPW2200_CMD_SET_FRAG_THRESHOLD, &data, 808 sizeof (data), 0); 809 if (err != DDI_SUCCESS) 810 return (err); 811 812 /* 813 * Set desired ESSID if we have 814 */ 815 if (ic->ic_des_esslen != 0) { 816 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 817 "ipw2200_config(): Setting desired ESSID to " 818 "(%u),%c%c%c%c%c%c%c%c\n", 819 ic->ic_des_esslen, 820 ic->ic_des_essid[0], ic->ic_des_essid[1], 821 ic->ic_des_essid[2], ic->ic_des_essid[3], 822 ic->ic_des_essid[4], ic->ic_des_essid[5], 823 ic->ic_des_essid[6], ic->ic_des_essid[7])); 824 err = ipw2200_cmd(sc, IPW2200_CMD_SET_ESSID, ic->ic_des_essid, 825 ic->ic_des_esslen, 0); 826 if (err != DDI_SUCCESS) 827 return (err); 828 } 829 830 /* 831 * Set WEP initial vector(random seed) 832 */ 833 (void) random_get_pseudo_bytes((uint8_t *)&data, sizeof (data)); 834 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 835 "ipw2200_config(): Setting initialization vector to %u\n", 836 LE_32(data))); 837 err = ipw2200_cmd(sc, IPW2200_CMD_SET_IV, &data, sizeof (data), 0); 838 if (err != DDI_SUCCESS) 839 return (err); 840 841 /* 842 * Set WEP if any 843 */ 844 if (ic->ic_flags & IEEE80211_F_PRIVACY) { 845 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 846 "ipw2200_config(): Setting Wep Key\n", LE_32(data))); 847 for (i = 0; i < IEEE80211_WEP_NKID; i++) { 848 wkey.cmd = IPW2200_WEP_KEY_CMD_SETKEY; 849 wkey.idx = (uint8_t)i; 850 wkey.len = ic->ic_nw_keys[i].wk_keylen; 851 (void) memset(wkey.key, 0, sizeof (wkey.key)); 852 if (ic->ic_nw_keys[i].wk_keylen) 853 (void) memcpy(wkey.key, 854 ic->ic_nw_keys[i].wk_key, 855 ic->ic_nw_keys[i].wk_keylen); 856 err = ipw2200_cmd(sc, IPW2200_CMD_SET_WEP_KEY, 857 &wkey, sizeof (wkey), 0); 858 if (err != DDI_SUCCESS) 859 return (err); 860 } 861 } 862 863 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 864 "ipw2200_config(): Enabling adapter\n")); 865 866 return (ipw2200_cmd(sc, IPW2200_CMD_ENABLE, NULL, 0, 0)); 867 } 868 869 static int 870 ipw2200_cmd(struct ipw2200_softc *sc, 871 uint32_t type, void *buf, size_t len, int async) 872 { 873 struct ipw2200_cmd_desc *cmd; 874 clock_t clk; 875 uint32_t idx; 876 877 mutex_enter(&sc->sc_cmd_lock); 878 while (sc->sc_cmd_free < 1) 879 cv_wait(&sc->sc_cmd_cond, &sc->sc_cmd_lock); 880 881 idx = sc->sc_cmd_cur; 882 cmd = &sc->sc_cmdsc[idx]; 883 (void) memset(cmd, 0, sizeof (*cmd)); 884 885 IPW2200_DBG(IPW2200_DBG_RING, (sc->sc_dip, CE_CONT, 886 "ipw2200_cmd(): cmd-cur=%d\n", idx)); 887 888 cmd->hdr.type = IPW2200_HDR_TYPE_COMMAND; 889 cmd->hdr.flags = IPW2200_HDR_FLAG_IRQ; 890 cmd->type = (uint8_t)type; 891 if (len == 0 || buf == NULL) 892 cmd->len = 0; 893 else { 894 cmd->len = (uint8_t)len; 895 (void) memcpy(cmd->data, buf, len); 896 } 897 sc->sc_done[idx] = 0; 898 899 /* 900 * DMA sync 901 */ 902 (void) ddi_dma_sync(sc->sc_dma_cmdsc.dr_hnd, 903 idx * sizeof (struct ipw2200_cmd_desc), 904 sizeof (struct ipw2200_cmd_desc), DDI_DMA_SYNC_FORDEV); 905 906 sc->sc_cmd_cur = RING_FORWARD(sc->sc_cmd_cur, 1, IPW2200_CMD_RING_SIZE); 907 sc->sc_cmd_free--; 908 909 ipw2200_csr_put32(sc, IPW2200_CSR_CMD_WRITE_INDEX, sc->sc_cmd_cur); 910 911 mutex_exit(&sc->sc_cmd_lock); 912 913 if (async) 914 goto out; 915 916 /* 917 * Wait for command done 918 */ 919 mutex_enter(&sc->sc_ilock); 920 while (sc->sc_done[idx] == 0) { 921 /* pending */ 922 clk = ddi_get_lbolt() + drv_usectohz(5000000); /* 5 second */ 923 if (cv_timedwait(&sc->sc_cmd_status_cond, &sc->sc_ilock, clk) 924 < 0) 925 break; 926 } 927 mutex_exit(&sc->sc_ilock); 928 929 IPW2200_DBG(IPW2200_DBG_RING, (sc->sc_dip, CE_CONT, 930 "ipw2200_cmd(): cmd-done=%s\n", sc->sc_done[idx] ? "yes" : "no")); 931 932 if (sc->sc_done[idx] == 0) 933 return (DDI_FAILURE); 934 935 out: 936 return (DDI_SUCCESS); 937 } 938 939 /* 940 * If init failed, it will call stop internally. Therefore, it's unnecessary 941 * to call ipw2200_stop() when this subroutine is failed. Otherwise, it may 942 * be called twice. 943 */ 944 int 945 ipw2200_init(struct ipw2200_softc *sc) 946 { 947 int err; 948 949 /* 950 * No firmware is available, failed 951 */ 952 if (!(sc->sc_flags & IPW2200_FLAG_FW_CACHED)) { 953 IPW2200_WARN((sc->sc_dip, CE_WARN, 954 "ipw2200_init(): no firmware is available\n")); 955 return (DDI_FAILURE); /* return directly */ 956 } 957 958 ipw2200_stop(sc); 959 960 err = ipw2200_chip_reset(sc); 961 if (err != DDI_SUCCESS) { 962 IPW2200_WARN((sc->sc_dip, CE_WARN, 963 "ipw2200_init(): could not reset adapter\n")); 964 goto fail; 965 } 966 967 /* 968 * Load boot code 969 */ 970 err = ipw2200_load_fw(sc, sc->sc_fw.boot_base, sc->sc_fw.boot_size); 971 if (err != DDI_SUCCESS) { 972 IPW2200_WARN((sc->sc_dip, CE_WARN, 973 "ipw2200_init(): could not load boot code\n")); 974 goto fail; 975 } 976 977 /* 978 * Load boot microcode 979 */ 980 err = ipw2200_load_uc(sc, sc->sc_fw.uc_base, sc->sc_fw.uc_size); 981 if (err != DDI_SUCCESS) { 982 IPW2200_WARN((sc->sc_dip, CE_WARN, 983 "ipw2200_init(): could not load microcode\n")); 984 goto fail; 985 } 986 987 ipw2200_master_stop(sc); 988 ipw2200_ring_hwsetup(sc); 989 990 /* 991 * Load firmware 992 */ 993 err = ipw2200_load_fw(sc, sc->sc_fw.fw_base, sc->sc_fw.fw_size); 994 if (err != DDI_SUCCESS) { 995 IPW2200_WARN((sc->sc_dip, CE_WARN, 996 "ipw2200_init(): could not load firmware\n")); 997 goto fail; 998 } 999 1000 sc->sc_flags |= IPW2200_FLAG_FW_INITED; 1001 1002 /* 1003 * Hardware will be enabled after configuration 1004 */ 1005 err = ipw2200_config(sc); 1006 if (err != DDI_SUCCESS) { 1007 IPW2200_WARN((sc->sc_dip, CE_WARN, 1008 "ipw2200_init(): device configuration failed\n")); 1009 goto fail; 1010 } 1011 1012 /* 1013 * workround to prevent too many h/w error. 1014 * delay for a while till h/w is stable. 1015 */ 1016 delay(drv_usectohz(delay_config_stable)); 1017 1018 return (DDI_SUCCESS); /* return successfully */ 1019 fail: 1020 ipw2200_stop(sc); 1021 return (err); 1022 } 1023 1024 /* 1025 * get hardware configurations from EEPROM embedded within PRO/2200 1026 */ 1027 static void 1028 ipw2200_hwconf_get(struct ipw2200_softc *sc) 1029 { 1030 int i; 1031 uint16_t val; 1032 1033 /* 1034 * Get mac address 1035 */ 1036 i = 0; 1037 val = ipw2200_rom_get16(sc, IPW2200_EEPROM_MAC + 0); 1038 sc->sc_macaddr[i++] = val >> 8; 1039 sc->sc_macaddr[i++] = val & 0xff; 1040 val = ipw2200_rom_get16(sc, IPW2200_EEPROM_MAC + 1); 1041 sc->sc_macaddr[i++] = val >> 8; 1042 sc->sc_macaddr[i++] = val & 0xff; 1043 val = ipw2200_rom_get16(sc, IPW2200_EEPROM_MAC + 2); 1044 sc->sc_macaddr[i++] = val >> 8; 1045 sc->sc_macaddr[i++] = val & 0xff; 1046 1047 /* 1048 * formatted MAC address string 1049 */ 1050 (void) snprintf(sc->sc_macstr, sizeof (sc->sc_macstr), 1051 "%02x:%02x:%02x:%02x:%02x:%02x", 1052 sc->sc_macaddr[0], sc->sc_macaddr[1], 1053 sc->sc_macaddr[2], sc->sc_macaddr[3], 1054 sc->sc_macaddr[4], sc->sc_macaddr[5]); 1055 1056 } 1057 1058 /* 1059 * all ipw2200 interrupts will be masked by this routine 1060 */ 1061 static void 1062 ipw2200_master_stop(struct ipw2200_softc *sc) 1063 { 1064 int ntries; 1065 1066 /* 1067 * disable interrupts 1068 */ 1069 ipw2200_csr_put32(sc, IPW2200_CSR_INTR_MASK, 0); 1070 ipw2200_csr_put32(sc, IPW2200_CSR_RST, IPW2200_RST_STOP_MASTER); 1071 1072 /* 1073 * wait long enough to ensure hardware stop successfully. 1074 */ 1075 for (ntries = 0; ntries < 500; ntries++) { 1076 if (ipw2200_csr_get32(sc, IPW2200_CSR_RST) & 1077 IPW2200_RST_MASTER_DISABLED) 1078 break; 1079 /* wait for a while */ 1080 drv_usecwait(100); 1081 } 1082 if (ntries == 500) 1083 IPW2200_WARN((sc->sc_dip, CE_WARN, 1084 "ipw2200_master_stop(): timeout\n")); 1085 1086 ipw2200_csr_put32(sc, IPW2200_CSR_RST, 1087 IPW2200_RST_PRINCETON_RESET | 1088 ipw2200_csr_get32(sc, IPW2200_CSR_RST)); 1089 1090 sc->sc_flags &= ~IPW2200_FLAG_FW_INITED; 1091 } 1092 1093 /* 1094 * all ipw2200 interrupts will be masked by this routine 1095 */ 1096 static int 1097 ipw2200_chip_reset(struct ipw2200_softc *sc) 1098 { 1099 uint32_t tmp; 1100 int ntries, i; 1101 1102 ipw2200_master_stop(sc); 1103 1104 /* 1105 * Move adapter to DO state 1106 */ 1107 tmp = ipw2200_csr_get32(sc, IPW2200_CSR_CTL); 1108 ipw2200_csr_put32(sc, IPW2200_CSR_CTL, tmp | IPW2200_CTL_INIT); 1109 1110 /* 1111 * Initialize Phase-Locked Level (PLL) 1112 */ 1113 ipw2200_csr_put32(sc, IPW2200_CSR_READ_INT, IPW2200_READ_INT_INIT_HOST); 1114 1115 /* 1116 * Wait for clock stabilization 1117 */ 1118 for (ntries = 0; ntries < 1000; ntries++) { 1119 if (ipw2200_csr_get32(sc, IPW2200_CSR_CTL) & 1120 IPW2200_CTL_CLOCK_READY) 1121 break; 1122 drv_usecwait(200); 1123 } 1124 if (ntries == 1000) { 1125 IPW2200_WARN((sc->sc_dip, CE_WARN, 1126 "ipw2200_chip_reset(): timeout\n")); 1127 return (DDI_FAILURE); 1128 } 1129 1130 tmp = ipw2200_csr_get32(sc, IPW2200_CSR_RST); 1131 ipw2200_csr_put32(sc, IPW2200_CSR_RST, tmp | IPW2200_RST_SW_RESET); 1132 1133 drv_usecwait(10); 1134 1135 tmp = ipw2200_csr_get32(sc, IPW2200_CSR_CTL); 1136 ipw2200_csr_put32(sc, IPW2200_CSR_CTL, tmp | IPW2200_CTL_INIT); 1137 1138 /* 1139 * clear NIC memory 1140 */ 1141 ipw2200_csr_put32(sc, IPW2200_CSR_AUTOINC_ADDR, 0); 1142 for (i = 0; i < 0xc000; i++) 1143 ipw2200_csr_put32(sc, IPW2200_CSR_AUTOINC_DATA, 0); 1144 1145 return (DDI_SUCCESS); 1146 } 1147 1148 /* 1149 * This function is used by wificonfig/dladm to get the current 1150 * radio status, it is off/on 1151 */ 1152 int 1153 ipw2200_radio_status(struct ipw2200_softc *sc) 1154 { 1155 int val; 1156 1157 val = (ipw2200_csr_get32(sc, IPW2200_CSR_IO) & 1158 IPW2200_IO_RADIO_ENABLED) ? 1 : 0; 1159 1160 return (val); 1161 } 1162 /* 1163 * This function is used to get the statistic 1164 */ 1165 void 1166 ipw2200_get_statistics(struct ipw2200_softc *sc) 1167 { 1168 struct ieee80211com *ic = &sc->sc_ic; 1169 1170 uint32_t size, buf[128]; 1171 1172 if (!(sc->sc_flags & IPW2200_FLAG_FW_INITED)) { 1173 IPW2200_DBG(IPW2200_DBG_IOCTL, (sc->sc_dip, CE_CONT, 1174 "ipw2200_get_statistic(): fw doesn't download yet.")); 1175 return; 1176 } 1177 1178 size = min(ipw2200_csr_get32(sc, IPW2200_CSR_TABLE0_SIZE), 128 - 1); 1179 ipw2200_csr_getbuf32(sc, IPW2200_CSR_TABLE0_BASE, &buf[1], size); 1180 1181 /* 1182 * To retrieve the statistic information into proper places. There are 1183 * lot of information. These table will be read once a second. 1184 * Hopefully, it will not effect the performance. 1185 */ 1186 1187 /* 1188 * For the tx/crc information, we can get them from chip directly; 1189 * For the rx/wep error/(rts) related information, leave them net80211. 1190 */ 1191 /* WIFI_STAT_TX_FRAGS */ 1192 ic->ic_stats.is_tx_frags = (uint32_t)buf[5]; 1193 /* WIFI_STAT_MCAST_TX */ 1194 ic->ic_stats.is_tx_mcast = (uint32_t)buf[31]; 1195 /* WIFI_STAT_TX_RETRANS */ 1196 ic->ic_stats.is_tx_retries = (uint32_t)buf[56]; 1197 /* WIFI_STAT_TX_FAILED */ 1198 ic->ic_stats.is_tx_failed = (uint32_t)buf[57]; 1199 /* MAC_STAT_OBYTES */ 1200 ic->ic_stats.is_tx_bytes = (uint32_t)buf[64]; 1201 } 1202 1203 /* 1204 * DMA region alloc subroutine 1205 */ 1206 int 1207 ipw2200_dma_region_alloc(struct ipw2200_softc *sc, struct dma_region *dr, 1208 size_t size, uint_t dir, uint_t flags) 1209 { 1210 dev_info_t *dip = sc->sc_dip; 1211 int err; 1212 1213 IPW2200_DBG(IPW2200_DBG_DMA, (sc->sc_dip, CE_CONT, 1214 "ipw2200_dma_region_alloc(): size =%u\n", size)); 1215 1216 err = ddi_dma_alloc_handle(dip, &ipw2200_dma_attr, DDI_DMA_SLEEP, NULL, 1217 &dr->dr_hnd); 1218 if (err != DDI_SUCCESS) { 1219 IPW2200_DBG(IPW2200_DBG_DMA, (sc->sc_dip, CE_CONT, 1220 "ipw2200_dma_region_alloc(): " 1221 "ddi_dma_alloc_handle() failed\n")); 1222 goto fail0; 1223 } 1224 1225 err = ddi_dma_mem_alloc(dr->dr_hnd, size, &ipw2200_dma_accattr, 1226 flags, DDI_DMA_SLEEP, NULL, 1227 &dr->dr_base, &dr->dr_size, &dr->dr_acc); 1228 if (err != DDI_SUCCESS) { 1229 IPW2200_DBG(IPW2200_DBG_DMA, (sc->sc_dip, CE_CONT, 1230 "ipw2200_dma_region_alloc(): " 1231 "ddi_dma_mem_alloc() failed\n")); 1232 goto fail1; 1233 } 1234 1235 err = ddi_dma_addr_bind_handle(dr->dr_hnd, NULL, 1236 dr->dr_base, dr->dr_size, 1237 dir | flags, DDI_DMA_SLEEP, NULL, 1238 &dr->dr_cookie, &dr->dr_ccnt); 1239 if (err != DDI_DMA_MAPPED) { 1240 IPW2200_DBG(IPW2200_DBG_DMA, (sc->sc_dip, CE_CONT, 1241 "ipw2200_dma_region_alloc(): " 1242 "ddi_dma_addr_bind_handle() failed\n")); 1243 goto fail2; 1244 } 1245 1246 IPW2200_DBG(IPW2200_DBG_DMA, (sc->sc_dip, CE_CONT, 1247 "ipw2200_dma_region_alloc(): ccnt=%u\n", dr->dr_ccnt)); 1248 1249 if (dr->dr_ccnt != 1) { 1250 err = DDI_FAILURE; 1251 goto fail3; 1252 } 1253 1254 dr->dr_pbase = dr->dr_cookie.dmac_address; 1255 1256 IPW2200_DBG(IPW2200_DBG_DMA, (sc->sc_dip, CE_CONT, 1257 "ipw2200_dma_region_alloc(): get physical-base=0x%08x\n", 1258 dr->dr_pbase)); 1259 1260 return (DDI_SUCCESS); 1261 1262 fail3: 1263 (void) ddi_dma_unbind_handle(dr->dr_hnd); 1264 fail2: 1265 ddi_dma_mem_free(&dr->dr_acc); 1266 fail1: 1267 ddi_dma_free_handle(&dr->dr_hnd); 1268 fail0: 1269 return (err); 1270 } 1271 1272 void 1273 ipw2200_dma_region_free(struct dma_region *dr) 1274 { 1275 (void) ddi_dma_unbind_handle(dr->dr_hnd); 1276 ddi_dma_mem_free(&dr->dr_acc); 1277 ddi_dma_free_handle(&dr->dr_hnd); 1278 } 1279 1280 static int 1281 ipw2200_ring_alloc(struct ipw2200_softc *sc) 1282 { 1283 int err, i; 1284 1285 /* 1286 * tx desc ring 1287 */ 1288 sc->sc_dma_txdsc.dr_name = "ipw2200-tx-desc-ring"; 1289 err = ipw2200_dma_region_alloc(sc, &sc->sc_dma_txdsc, 1290 IPW2200_TX_RING_SIZE * sizeof (struct ipw2200_tx_desc), 1291 DDI_DMA_WRITE, DDI_DMA_CONSISTENT); 1292 if (err != DDI_SUCCESS) 1293 goto fail0; 1294 /* 1295 * tx buffer array 1296 */ 1297 for (i = 0; i < IPW2200_TX_RING_SIZE; i++) { 1298 sc->sc_dma_txbufs[i].dr_name = "ipw2200-tx-buf"; 1299 err = ipw2200_dma_region_alloc(sc, &sc->sc_dma_txbufs[i], 1300 IPW2200_TXBUF_SIZE, DDI_DMA_WRITE, DDI_DMA_STREAMING); 1301 if (err != DDI_SUCCESS) { 1302 while (i >= 0) { 1303 ipw2200_dma_region_free(&sc->sc_dma_txbufs[i]); 1304 i--; 1305 } 1306 goto fail1; 1307 } 1308 } 1309 /* 1310 * rx buffer array 1311 */ 1312 for (i = 0; i < IPW2200_RX_RING_SIZE; i++) { 1313 sc->sc_dma_rxbufs[i].dr_name = "ipw2200-rx-buf"; 1314 err = ipw2200_dma_region_alloc(sc, &sc->sc_dma_rxbufs[i], 1315 IPW2200_RXBUF_SIZE, DDI_DMA_READ, DDI_DMA_STREAMING); 1316 if (err != DDI_SUCCESS) { 1317 while (i >= 0) { 1318 ipw2200_dma_region_free(&sc->sc_dma_rxbufs[i]); 1319 i--; 1320 } 1321 goto fail2; 1322 } 1323 } 1324 /* 1325 * cmd desc ring 1326 */ 1327 sc->sc_dma_cmdsc.dr_name = "ipw2200-cmd-desc-ring"; 1328 err = ipw2200_dma_region_alloc(sc, &sc->sc_dma_cmdsc, 1329 IPW2200_CMD_RING_SIZE * sizeof (struct ipw2200_cmd_desc), 1330 DDI_DMA_WRITE, DDI_DMA_CONSISTENT); 1331 if (err != DDI_SUCCESS) 1332 goto fail3; 1333 1334 return (DDI_SUCCESS); 1335 1336 fail3: 1337 for (i = 0; i < IPW2200_RX_RING_SIZE; i++) 1338 ipw2200_dma_region_free(&sc->sc_dma_rxbufs[i]); 1339 fail2: 1340 for (i = 0; i < IPW2200_TX_RING_SIZE; i++) 1341 ipw2200_dma_region_free(&sc->sc_dma_txbufs[i]); 1342 fail1: 1343 ipw2200_dma_region_free(&sc->sc_dma_txdsc); 1344 fail0: 1345 return (err); 1346 } 1347 1348 static void 1349 ipw2200_ring_free(struct ipw2200_softc *sc) 1350 { 1351 int i; 1352 1353 /* 1354 * tx ring desc 1355 */ 1356 ipw2200_dma_region_free(&sc->sc_dma_txdsc); 1357 /* 1358 * tx buf 1359 */ 1360 for (i = 0; i < IPW2200_TX_RING_SIZE; i++) 1361 ipw2200_dma_region_free(&sc->sc_dma_txbufs[i]); 1362 /* 1363 * rx buf 1364 */ 1365 for (i = 0; i < IPW2200_RX_RING_SIZE; i++) 1366 ipw2200_dma_region_free(&sc->sc_dma_rxbufs[i]); 1367 /* 1368 * command ring desc 1369 */ 1370 ipw2200_dma_region_free(&sc->sc_dma_cmdsc); 1371 } 1372 1373 static void 1374 ipw2200_ring_reset(struct ipw2200_softc *sc) 1375 { 1376 int i; 1377 1378 /* 1379 * tx desc ring & buffer array 1380 */ 1381 sc->sc_tx_cur = 0; 1382 sc->sc_tx_free = IPW2200_TX_RING_SIZE; 1383 sc->sc_txdsc = (struct ipw2200_tx_desc *)sc->sc_dma_txdsc.dr_base; 1384 for (i = 0; i < IPW2200_TX_RING_SIZE; i++) 1385 sc->sc_txbufs[i] = (uint8_t *)sc->sc_dma_txbufs[i].dr_base; 1386 /* 1387 * rx buffer array 1388 */ 1389 sc->sc_rx_cur = 0; 1390 sc->sc_rx_free = IPW2200_RX_RING_SIZE; 1391 for (i = 0; i < IPW2200_RX_RING_SIZE; i++) 1392 sc->sc_rxbufs[i] = (uint8_t *)sc->sc_dma_rxbufs[i].dr_base; 1393 1394 /* 1395 * command desc ring 1396 */ 1397 sc->sc_cmd_cur = 0; 1398 sc->sc_cmd_free = IPW2200_CMD_RING_SIZE; 1399 sc->sc_cmdsc = (struct ipw2200_cmd_desc *)sc->sc_dma_cmdsc.dr_base; 1400 } 1401 1402 /* 1403 * tx, rx rings and command initialization 1404 */ 1405 static int 1406 ipw2200_ring_init(struct ipw2200_softc *sc) 1407 { 1408 int err; 1409 1410 err = ipw2200_ring_alloc(sc); 1411 if (err != DDI_SUCCESS) 1412 return (err); 1413 1414 ipw2200_ring_reset(sc); 1415 1416 return (DDI_SUCCESS); 1417 } 1418 1419 static void 1420 ipw2200_ring_hwsetup(struct ipw2200_softc *sc) 1421 { 1422 int i; 1423 1424 /* 1425 * command desc ring 1426 */ 1427 ipw2200_csr_put32(sc, IPW2200_CSR_CMD_BASE, sc->sc_dma_cmdsc.dr_pbase); 1428 ipw2200_csr_put32(sc, IPW2200_CSR_CMD_SIZE, IPW2200_CMD_RING_SIZE); 1429 ipw2200_csr_put32(sc, IPW2200_CSR_CMD_WRITE_INDEX, sc->sc_cmd_cur); 1430 1431 /* 1432 * tx desc ring. only tx1 is used, tx2, tx3, and tx4 are unused 1433 */ 1434 ipw2200_csr_put32(sc, IPW2200_CSR_TX1_BASE, sc->sc_dma_txdsc.dr_pbase); 1435 ipw2200_csr_put32(sc, IPW2200_CSR_TX1_SIZE, IPW2200_TX_RING_SIZE); 1436 ipw2200_csr_put32(sc, IPW2200_CSR_TX1_WRITE_INDEX, sc->sc_tx_cur); 1437 1438 /* 1439 * tx2, tx3, tx4 is not used 1440 */ 1441 ipw2200_csr_put32(sc, IPW2200_CSR_TX2_BASE, sc->sc_dma_txdsc.dr_pbase); 1442 ipw2200_csr_put32(sc, IPW2200_CSR_TX2_SIZE, IPW2200_TX_RING_SIZE); 1443 ipw2200_csr_put32(sc, IPW2200_CSR_TX2_READ_INDEX, 0); 1444 ipw2200_csr_put32(sc, IPW2200_CSR_TX2_WRITE_INDEX, 0); 1445 ipw2200_csr_put32(sc, IPW2200_CSR_TX3_BASE, sc->sc_dma_txdsc.dr_pbase); 1446 ipw2200_csr_put32(sc, IPW2200_CSR_TX3_SIZE, IPW2200_TX_RING_SIZE); 1447 ipw2200_csr_put32(sc, IPW2200_CSR_TX3_READ_INDEX, 0); 1448 ipw2200_csr_put32(sc, IPW2200_CSR_TX3_WRITE_INDEX, 0); 1449 ipw2200_csr_put32(sc, IPW2200_CSR_TX4_BASE, sc->sc_dma_txdsc.dr_pbase); 1450 ipw2200_csr_put32(sc, IPW2200_CSR_TX4_SIZE, IPW2200_TX_RING_SIZE); 1451 ipw2200_csr_put32(sc, IPW2200_CSR_TX4_READ_INDEX, 0); 1452 ipw2200_csr_put32(sc, IPW2200_CSR_TX4_WRITE_INDEX, 0); 1453 1454 /* 1455 * rx buffer ring 1456 */ 1457 for (i = 0; i < IPW2200_RX_RING_SIZE; i++) 1458 ipw2200_csr_put32(sc, IPW2200_CSR_RX_BASE + i * 4, 1459 sc->sc_dma_rxbufs[i].dr_pbase); 1460 /* 1461 * all rx buffer are empty, rx-rd-index == 0 && rx-wr-index == N-1 1462 */ 1463 ipw2200_csr_put32(sc, IPW2200_CSR_RX_WRITE_INDEX, 1464 RING_BACKWARD(sc->sc_rx_cur, 1, IPW2200_RX_RING_SIZE)); 1465 } 1466 1467 int 1468 ipw2200_start_scan(struct ipw2200_softc *sc) 1469 { 1470 struct ieee80211com *ic = &sc->sc_ic; 1471 struct ipw2200_scan scan; 1472 uint8_t *ch; 1473 int cnt, i; 1474 1475 IPW2200_DBG(IPW2200_DBG_SCAN, (sc->sc_dip, CE_CONT, 1476 "ipw2200_start_scan(): start scanning \n")); 1477 1478 /* 1479 * start scanning 1480 */ 1481 sc->sc_flags |= IPW2200_FLAG_SCANNING; 1482 1483 (void) memset(&scan, 0, sizeof (scan)); 1484 scan.type = (ic->ic_des_esslen != 0) ? IPW2200_SCAN_TYPE_BDIRECTED : 1485 IPW2200_SCAN_TYPE_BROADCAST; 1486 scan.dwelltime = LE_16(40); /* The interval is set up to 40 */ 1487 1488 /* 1489 * Compact supported channel number(5G) into a single buffer 1490 */ 1491 ch = scan.channels; 1492 cnt = 0; 1493 for (i = 0; i <= IEEE80211_CHAN_MAX; i++) { 1494 if (IEEE80211_IS_CHAN_5GHZ(&ic->ic_sup_channels[i]) && 1495 isset(ic->ic_chan_active, i)) { 1496 *++ch = (uint8_t)i; 1497 cnt++; 1498 } 1499 } 1500 *(ch - cnt) = IPW2200_CHAN_5GHZ | (uint8_t)cnt; 1501 ch = (cnt > 0) ? (ch + 1) : (scan.channels); 1502 1503 /* 1504 * Compact supported channel number(2G) into a single buffer 1505 */ 1506 cnt = 0; 1507 for (i = 0; i <= IEEE80211_CHAN_MAX; i++) { 1508 if (IEEE80211_IS_CHAN_2GHZ(&ic->ic_sup_channels[i]) && 1509 isset(ic->ic_chan_active, i)) { 1510 *++ch = (uint8_t)i; 1511 cnt++; 1512 } 1513 } 1514 *(ch - cnt) = IPW2200_CHAN_2GHZ | cnt; 1515 1516 return (ipw2200_cmd(sc, IPW2200_CMD_SCAN, &scan, sizeof (scan), 1)); 1517 } 1518 1519 int 1520 ipw2200_auth_and_assoc(struct ipw2200_softc *sc) 1521 { 1522 struct ieee80211com *ic = &sc->sc_ic; 1523 struct ieee80211_node *in = ic->ic_bss; 1524 struct ipw2200_configuration cfg; 1525 struct ipw2200_rateset rs; 1526 struct ipw2200_associate assoc; 1527 uint32_t data; 1528 int err; 1529 uint8_t *wpa_level; 1530 1531 if (sc->sc_flags & IPW2200_FLAG_ASSOCIATED) { 1532 /* already associated */ 1533 return (-1); 1534 } 1535 1536 /* 1537 * set the confiuration 1538 */ 1539 if (IEEE80211_IS_CHAN_2GHZ(in->in_chan)) { 1540 /* enable b/g auto-detection */ 1541 (void) memset(&cfg, 0, sizeof (cfg)); 1542 cfg.bluetooth_coexistence = 1; 1543 cfg.multicast_enabled = 1; 1544 cfg.use_protection = 1; 1545 cfg.answer_pbreq = 1; 1546 cfg.noise_reported = 1; 1547 cfg.disable_multicast_decryption = 1; /* WPA */ 1548 cfg.disable_unicast_decryption = 1; /* WPA */ 1549 err = ipw2200_cmd(sc, IPW2200_CMD_SET_CONFIG, 1550 &cfg, sizeof (cfg), 1); 1551 if (err != DDI_SUCCESS) 1552 return (err); 1553 } 1554 1555 /* 1556 * set the essid, may be null/hidden AP 1557 */ 1558 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 1559 "ipw2200_auth_and_assoc(): " 1560 "setting ESSID to(%u),%c%c%c%c%c%c%c%c\n", 1561 in->in_esslen, 1562 in->in_essid[0], in->in_essid[1], 1563 in->in_essid[2], in->in_essid[3], 1564 in->in_essid[4], in->in_essid[5], 1565 in->in_essid[6], in->in_essid[7])); 1566 err = ipw2200_cmd(sc, IPW2200_CMD_SET_ESSID, in->in_essid, 1567 in->in_esslen, 1); 1568 if (err != DDI_SUCCESS) 1569 return (err); 1570 1571 /* 1572 * set the rate: the rate set has already been ''negocitated'' 1573 */ 1574 rs.mode = IEEE80211_IS_CHAN_5GHZ(in->in_chan) ? 1575 IPW2200_MODE_11A : IPW2200_MODE_11G; 1576 rs.type = IPW2200_RATESET_TYPE_NEGOCIATED; 1577 rs.nrates = in->in_rates.ir_nrates; 1578 (void) memcpy(rs.rates, in->in_rates.ir_rates, in->in_rates.ir_nrates); 1579 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 1580 "ipw2200_auth_and_assoc(): " 1581 "setting negotiated rates to(nrates = %u)\n", rs.nrates)); 1582 err = ipw2200_cmd(sc, IPW2200_CMD_SET_RATES, &rs, sizeof (rs), 1); 1583 if (err != DDI_SUCCESS) 1584 return (err); 1585 1586 /* 1587 * invoke command associate 1588 */ 1589 (void) memset(&assoc, 0, sizeof (assoc)); 1590 1591 /* 1592 * set opt_ie to h/w if associated is WPA, opt_ie has been verified 1593 * by net80211 kernel module. 1594 */ 1595 if (ic->ic_opt_ie != NULL) { 1596 1597 wpa_level = (uint8_t *)ic->ic_opt_ie; 1598 1599 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 1600 "ipw2200_auth_and_assoc(): " 1601 "set wpa_ie and wpa_ie_len to h/w. " 1602 "length is %d\n" 1603 "opt_ie[0] = %02X - element vendor\n" 1604 "opt_ie[1] = %02X - length\n" 1605 "opt_ie[2,3,4] = %02X %02X %02X - oui\n" 1606 "opt_ie[5] = %02X - oui type\n" 1607 "opt_ie[6,7] = %02X %02X - spec version \n" 1608 "opt_ie[8,9,10,11] = %02X %02X %02X %02X - gk cipher\n" 1609 "opt_ie[12,13] = %02X %02X - pairwise key cipher(1)\n" 1610 "opt_ie[14,15,16,17] = %02X %02X %02X %02X - ciphers\n" 1611 "opt_ie[18,19] = %02X %02X - authselcont(1) \n" 1612 "opt_ie[20,21,22,23] = %02X %02X %02X %02X - authsels\n", 1613 wpa_level[1], wpa_level[0], wpa_level[1], 1614 wpa_level[2], wpa_level[3], wpa_level[4], 1615 wpa_level[5], wpa_level[6], wpa_level[7], 1616 wpa_level[8], wpa_level[9], wpa_level[10], 1617 wpa_level[11], wpa_level[12], wpa_level[13], 1618 wpa_level[14], wpa_level[15], wpa_level[16], 1619 wpa_level[17], wpa_level[18], wpa_level[19], 1620 wpa_level[20], wpa_level[21], wpa_level[22], 1621 wpa_level[23])); 1622 1623 err = ipw2200_cmd(sc, IPW2200_CMD_SET_OPTIE, 1624 ic->ic_opt_ie, ic->ic_opt_ie_len, 1); 1625 if (err != DDI_SUCCESS) 1626 return (err); 1627 } 1628 1629 /* 1630 * set the sensitive 1631 */ 1632 data = LE_32(in->in_rssi); 1633 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 1634 "ipw2200_auth_and_assoc(): " 1635 "setting sensitivity to rssi:(%u)\n", (uint8_t)in->in_rssi)); 1636 err = ipw2200_cmd(sc, IPW2200_CMD_SET_SENSITIVITY, 1637 &data, sizeof (data), 1); 1638 if (err != DDI_SUCCESS) 1639 return (err); 1640 1641 /* 1642 * set mode and channel for assocation command 1643 */ 1644 assoc.mode = IEEE80211_IS_CHAN_5GHZ(in->in_chan) ? 1645 IPW2200_MODE_11A : IPW2200_MODE_11G; 1646 assoc.chan = ieee80211_chan2ieee(ic, in->in_chan); 1647 1648 /* 1649 * use the value set to ic_bss to retraive current sharedmode 1650 */ 1651 if (ic->ic_bss->in_authmode == WL_SHAREDKEY) { 1652 assoc.auth = (ic->ic_def_txkey << 4) | IPW2200_AUTH_SHARED; 1653 IPW2200_DBG(IPW2200_DBG_IOCTL, (sc->sc_dip, CE_CONT, 1654 "ipw2200_auth_and_assoc(): " 1655 "associate to shared key mode, set thru. ioctl")); 1656 } 1657 1658 if (ic->ic_flags & IEEE80211_F_WPA) 1659 assoc.policy = LE_16(IPW2200_POLICY_WPA); /* RSN/WPA active */ 1660 (void) memcpy(assoc.tstamp, in->in_tstamp.data, 8); 1661 assoc.capinfo = LE_16(in->in_capinfo); 1662 assoc.lintval = LE_16(ic->ic_lintval); 1663 assoc.intval = LE_16(in->in_intval); 1664 IEEE80211_ADDR_COPY(assoc.bssid, in->in_bssid); 1665 if (ic->ic_opmode == IEEE80211_M_IBSS) 1666 IEEE80211_ADDR_COPY(assoc.dst, ipw2200_broadcast_addr); 1667 else 1668 IEEE80211_ADDR_COPY(assoc.dst, in->in_bssid); 1669 1670 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 1671 "ipw2200_auth_and_assoc(): " 1672 "associate to bssid(%2x:%2x:%2x:%2x:%2x:%2x:), " 1673 "chan(%u), auth(%u)\n", 1674 assoc.bssid[0], assoc.bssid[1], assoc.bssid[2], 1675 assoc.bssid[3], assoc.bssid[4], assoc.bssid[5], 1676 assoc.chan, assoc.auth)); 1677 return (ipw2200_cmd(sc, IPW2200_CMD_ASSOCIATE, 1678 &assoc, sizeof (assoc), 1)); 1679 } 1680 1681 /* 1682 * Send the dis-association command to h/w, will receive notification to claim 1683 * the connection is dis-associated. So, it's not marked as disassociated this 1684 * moment. 1685 */ 1686 static int 1687 ipw2200_disassoc(struct ipw2200_softc *sc) 1688 { 1689 struct ipw2200_associate assoc; 1690 assoc.type = 2; 1691 return (ipw2200_cmd(sc, IPW2200_CMD_ASSOCIATE, &assoc, 1692 sizeof (assoc), 1)); 1693 } 1694 1695 /* ARGSUSED */ 1696 static int 1697 ipw2200_newstate(struct ieee80211com *ic, enum ieee80211_state state, int arg) 1698 { 1699 struct ipw2200_softc *sc = (struct ipw2200_softc *)ic; 1700 wifi_data_t wd = { 0 }; 1701 1702 switch (state) { 1703 case IEEE80211_S_SCAN: 1704 if (!(sc->sc_flags & IPW2200_FLAG_SCANNING)) { 1705 ic->ic_flags |= IEEE80211_F_SCAN | IEEE80211_F_ASCAN; 1706 (void) ipw2200_start_scan(sc); 1707 } 1708 break; 1709 case IEEE80211_S_AUTH: 1710 /* 1711 * The firmware will fail if we are already associated 1712 */ 1713 if (sc->sc_flags & IPW2200_FLAG_ASSOCIATED) 1714 (void) ipw2200_disassoc(sc); 1715 (void) ipw2200_auth_and_assoc(sc); 1716 break; 1717 case IEEE80211_S_RUN: 1718 /* 1719 * We can send data now; update the fastpath with our 1720 * current associated BSSID and other relevant settings. 1721 */ 1722 wd.wd_secalloc = ieee80211_crypto_getciphertype(ic); 1723 wd.wd_opmode = ic->ic_opmode; 1724 IEEE80211_ADDR_COPY(wd.wd_bssid, ic->ic_bss->in_bssid); 1725 (void) mac_pdata_update(ic->ic_mach, &wd, sizeof (wd)); 1726 break; 1727 case IEEE80211_S_ASSOC: 1728 case IEEE80211_S_INIT: 1729 break; 1730 } 1731 1732 /* 1733 * notify to update the link, and WPA 1734 */ 1735 if ((ic->ic_state != IEEE80211_S_RUN) && (state == IEEE80211_S_RUN)) { 1736 ieee80211_notify_node_join(ic, ic->ic_bss); 1737 } else if ((ic->ic_state == IEEE80211_S_RUN) && 1738 (state != IEEE80211_S_RUN)) { 1739 ieee80211_notify_node_leave(ic, ic->ic_bss); 1740 } 1741 1742 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 1743 "ipw2200_newstat(): %s -> %s\n", 1744 ieee80211_state_name[ic->ic_state], 1745 ieee80211_state_name[state])); 1746 1747 ic->ic_state = state; 1748 return (DDI_SUCCESS); 1749 } 1750 /* 1751 * GLD operations 1752 */ 1753 /* ARGSUSED */ 1754 static int 1755 ipw2200_m_stat(void *arg, uint_t stat, uint64_t *val) 1756 { 1757 ieee80211com_t *ic = (ieee80211com_t *)arg; 1758 1759 IPW2200_DBG(IPW2200_DBG_GLD, (((struct ipw2200_softc *)arg)->sc_dip, 1760 CE_CONT, 1761 "ipw2200_m_stat(): enter\n")); 1762 1763 /* 1764 * Some of below statistic data are from hardware, some from net80211 1765 */ 1766 switch (stat) { 1767 case MAC_STAT_RBYTES: 1768 *val = ic->ic_stats.is_rx_bytes; 1769 break; 1770 case MAC_STAT_IPACKETS: 1771 *val = ic->ic_stats.is_rx_frags; 1772 break; 1773 case MAC_STAT_OBYTES: 1774 *val = ic->ic_stats.is_tx_bytes; 1775 break; 1776 case MAC_STAT_OPACKETS: 1777 *val = ic->ic_stats.is_tx_frags; 1778 break; 1779 /* 1780 * Get below from hardware statistic, retraive net80211 value once 1s 1781 */ 1782 case WIFI_STAT_TX_FRAGS: 1783 case WIFI_STAT_MCAST_TX: 1784 case WIFI_STAT_TX_FAILED: 1785 case WIFI_STAT_TX_RETRANS: 1786 /* 1787 * Get blow information from net80211 1788 */ 1789 case WIFI_STAT_RTS_SUCCESS: 1790 case WIFI_STAT_RTS_FAILURE: 1791 case WIFI_STAT_ACK_FAILURE: 1792 case WIFI_STAT_RX_FRAGS: 1793 case WIFI_STAT_MCAST_RX: 1794 case WIFI_STAT_RX_DUPS: 1795 case WIFI_STAT_FCS_ERRORS: 1796 case WIFI_STAT_WEP_ERRORS: 1797 return (ieee80211_stat(ic, stat, val)); 1798 /* 1799 * Need be supported later 1800 */ 1801 case MAC_STAT_IFSPEED: 1802 case MAC_STAT_NOXMTBUF: 1803 case MAC_STAT_IERRORS: 1804 case MAC_STAT_OERRORS: 1805 default: 1806 return (ENOTSUP); 1807 } 1808 return (0); 1809 } 1810 1811 /* ARGSUSED */ 1812 static int 1813 ipw2200_m_multicst(void *arg, boolean_t add, const uint8_t *mca) 1814 { 1815 /* not supported */ 1816 IPW2200_DBG(IPW2200_DBG_GLD, (((struct ipw2200_softc *)arg)->sc_dip, 1817 CE_CONT, 1818 "ipw2200_m_multicst(): enter\n")); 1819 1820 return (DDI_SUCCESS); 1821 } 1822 1823 /* 1824 * Multithread handler for linkstatus, fatal error recovery, get statistic 1825 */ 1826 static void 1827 ipw2200_thread(struct ipw2200_softc *sc) 1828 { 1829 struct ieee80211com *ic = &sc->sc_ic; 1830 enum ieee80211_state ostate; 1831 int32_t nlstate; 1832 int stat_cnt = 0; 1833 1834 IPW2200_DBG(IPW2200_DBG_SOFTINT, (sc->sc_dip, CE_CONT, 1835 "ipw2200_thread(): enter, linkstate %d\n", sc->sc_linkstate)); 1836 1837 mutex_enter(&sc->sc_mflock); 1838 1839 while (sc->sc_mfthread_switch) { 1840 /* 1841 * notify the link state 1842 */ 1843 if (ic->ic_mach && (sc->sc_flags & IPW2200_FLAG_LINK_CHANGE)) { 1844 1845 IPW2200_DBG(IPW2200_DBG_SOFTINT, (sc->sc_dip, CE_CONT, 1846 "ipw2200_thread(): link status --> %d\n", 1847 sc->sc_linkstate)); 1848 1849 sc->sc_flags &= ~IPW2200_FLAG_LINK_CHANGE; 1850 nlstate = sc->sc_linkstate; 1851 1852 mutex_exit(&sc->sc_mflock); 1853 mac_link_update(ic->ic_mach, nlstate); 1854 mutex_enter(&sc->sc_mflock); 1855 } 1856 1857 /* 1858 * recovery fatal error 1859 */ 1860 if (ic->ic_mach && 1861 (sc->sc_flags & IPW2200_FLAG_HW_ERR_RECOVER)) { 1862 1863 IPW2200_DBG(IPW2200_DBG_FATAL, (sc->sc_dip, CE_CONT, 1864 "ipw2200_thread(): " 1865 "try to recover fatal hw error\n")); 1866 1867 sc->sc_flags &= ~IPW2200_FLAG_HW_ERR_RECOVER; 1868 mutex_exit(&sc->sc_mflock); 1869 1870 /* stop again */ 1871 ostate = ic->ic_state; 1872 (void) ipw2200_init(sc); /* Force state machine */ 1873 1874 /* 1875 * workround. Delay for a while after init especially 1876 * when something wrong happened already. 1877 */ 1878 delay(drv_usectohz(delay_fatal_recover)); 1879 1880 /* 1881 * Init scan will recovery the original connection if 1882 * the original state is run 1883 */ 1884 if (ostate != IEEE80211_S_INIT) 1885 ieee80211_begin_scan(ic, 0); 1886 1887 mutex_enter(&sc->sc_mflock); 1888 } 1889 1890 /* 1891 * get statistic, the value will be retrieved by m_stat 1892 */ 1893 if (stat_cnt == 10) { 1894 1895 stat_cnt = 0; /* re-start */ 1896 mutex_exit(&sc->sc_mflock); 1897 ipw2200_get_statistics(sc); 1898 mutex_enter(&sc->sc_mflock); 1899 1900 } else 1901 stat_cnt++; /* until 1s */ 1902 1903 mutex_exit(&sc->sc_mflock); 1904 delay(drv_usectohz(delay_aux_thread)); 1905 mutex_enter(&sc->sc_mflock); 1906 1907 } 1908 sc->sc_mf_thread = NULL; 1909 cv_signal(&sc->sc_mfthread_cv); 1910 mutex_exit(&sc->sc_mflock); 1911 } 1912 1913 static int 1914 ipw2200_m_start(void *arg) 1915 { 1916 struct ipw2200_softc *sc = (struct ipw2200_softc *)arg; 1917 struct ieee80211com *ic = &sc->sc_ic; 1918 1919 IPW2200_DBG(IPW2200_DBG_GLD, (sc->sc_dip, CE_CONT, 1920 "ipw2200_m_start(): enter\n")); 1921 /* 1922 * initialize ipw2200 hardware, everything ok will start scan 1923 */ 1924 (void) ipw2200_init(sc); 1925 1926 /* 1927 * set the state machine to INIT 1928 */ 1929 ieee80211_new_state(ic, IEEE80211_S_INIT, -1); 1930 1931 sc->sc_flags |= IPW2200_FLAG_RUNNING; 1932 1933 /* 1934 * fix KCF bug. - workaround, need to fix it in net80211 1935 */ 1936 (void) crypto_mech2id(SUN_CKM_RC4); 1937 1938 return (DDI_SUCCESS); 1939 } 1940 1941 static void 1942 ipw2200_m_stop(void *arg) 1943 { 1944 struct ipw2200_softc *sc = (struct ipw2200_softc *)arg; 1945 struct ieee80211com *ic = &sc->sc_ic; 1946 1947 IPW2200_DBG(IPW2200_DBG_GLD, (sc->sc_dip, CE_CONT, 1948 "ipw2200_m_stop(): enter\n")); 1949 1950 ipw2200_stop(sc); 1951 /* 1952 * set the state machine to INIT 1953 */ 1954 ieee80211_new_state(ic, IEEE80211_S_INIT, -1); 1955 1956 sc->sc_flags &= ~IPW2200_FLAG_RUNNING; 1957 } 1958 1959 static int 1960 ipw2200_m_unicst(void *arg, const uint8_t *macaddr) 1961 { 1962 struct ipw2200_softc *sc = (struct ipw2200_softc *)arg; 1963 struct ieee80211com *ic = &sc->sc_ic; 1964 int err; 1965 1966 IPW2200_DBG(IPW2200_DBG_GLD, (sc->sc_dip, CE_CONT, 1967 "ipw2200_m_unicst(): enter\n")); 1968 1969 IPW2200_DBG(IPW2200_DBG_GLD, (sc->sc_dip, CE_CONT, 1970 "ipw2200_m_unicst(): GLD setting MAC address to " 1971 "%02x:%02x:%02x:%02x:%02x:%02x\n", 1972 macaddr[0], macaddr[1], macaddr[2], 1973 macaddr[3], macaddr[4], macaddr[5])); 1974 1975 if (!IEEE80211_ADDR_EQ(ic->ic_macaddr, macaddr)) { 1976 1977 IEEE80211_ADDR_COPY(ic->ic_macaddr, macaddr); 1978 1979 if (sc->sc_flags & IPW2200_FLAG_RUNNING) { 1980 err = ipw2200_config(sc); 1981 if (err != DDI_SUCCESS) { 1982 IPW2200_WARN((sc->sc_dip, CE_WARN, 1983 "ipw2200_m_unicst(): " 1984 "device configuration failed\n")); 1985 goto fail; 1986 } 1987 } 1988 } 1989 return (DDI_SUCCESS); 1990 fail: 1991 return (err); 1992 } 1993 1994 static int 1995 ipw2200_m_promisc(void *arg, boolean_t on) 1996 { 1997 /* not supported */ 1998 struct ipw2200_softc *sc = (struct ipw2200_softc *)arg; 1999 2000 IPW2200_DBG(IPW2200_DBG_GLD, (sc->sc_dip, CE_CONT, 2001 "ipw2200_m_promisc(): enter. " 2002 "GLD setting promiscuous mode - %d\n", on)); 2003 2004 return (DDI_SUCCESS); 2005 } 2006 2007 static mblk_t * 2008 ipw2200_m_tx(void *arg, mblk_t *mp) 2009 { 2010 struct ipw2200_softc *sc = (struct ipw2200_softc *)arg; 2011 struct ieee80211com *ic = &sc->sc_ic; 2012 mblk_t *next; 2013 2014 /* 2015 * No data frames go out unless we're associated; this 2016 * should not happen as the 802.11 layer does not enable 2017 * the xmit queue until we enter the RUN state. 2018 */ 2019 if (ic->ic_state != IEEE80211_S_RUN) { 2020 IPW2200_DBG(IPW2200_DBG_GLD, (sc->sc_dip, CE_CONT, 2021 "ipw2200_m_tx(): discard msg, ic_state = %u\n", 2022 ic->ic_state)); 2023 freemsgchain(mp); 2024 return (NULL); 2025 } 2026 2027 while (mp != NULL) { 2028 next = mp->b_next; 2029 mp->b_next = NULL; 2030 if (ipw2200_send(ic, mp, IEEE80211_FC0_TYPE_DATA) == 2031 ENOMEM) { 2032 mp->b_next = next; 2033 break; 2034 } 2035 mp = next; 2036 } 2037 return (mp); 2038 } 2039 2040 /* 2041 * ipw2200_send(): send data. softway to handle crypto_encap. 2042 */ 2043 static int 2044 ipw2200_send(ieee80211com_t *ic, mblk_t *mp, uint8_t type) 2045 { 2046 struct ipw2200_softc *sc = (struct ipw2200_softc *)ic; 2047 struct ieee80211_node *in; 2048 struct ieee80211_frame *wh; 2049 struct ieee80211_key *k; 2050 mblk_t *m0, *m; 2051 size_t cnt, off; 2052 struct ipw2200_tx_desc *txdsc; 2053 struct dma_region *dr; 2054 uint32_t idx; 2055 int err = DDI_SUCCESS; 2056 /* tmp pointer, used to pack header and payload */ 2057 uint8_t *p; 2058 2059 ASSERT(mp->b_next == NULL); 2060 IPW2200_DBG(IPW2200_DBG_GLD, (sc->sc_dip, CE_CONT, 2061 "ipw2200_send(): enter\n")); 2062 2063 if ((type & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_DATA) { 2064 /* 2065 * skip all management frames since ipw2200 won't generate any 2066 * management frames. Therefore, drop this package. 2067 */ 2068 freemsg(mp); 2069 err = DDI_FAILURE; 2070 goto fail0; 2071 } 2072 2073 mutex_enter(&sc->sc_tx_lock); 2074 2075 /* 2076 * need 1 empty descriptor 2077 */ 2078 if (sc->sc_tx_free <= IPW2200_TX_RING_MIN) { 2079 mutex_enter(&sc->sc_resched_lock); 2080 IPW2200_DBG(IPW2200_DBG_RING, (sc->sc_dip, CE_WARN, 2081 "ipw2200_send(): no enough descriptors(%d)\n", 2082 sc->sc_tx_free)); 2083 ic->ic_stats.is_tx_nobuf++; /* no enough buffer */ 2084 sc->sc_flags |= IPW2200_FLAG_TX_SCHED; 2085 err = ENOMEM; 2086 mutex_exit(&sc->sc_resched_lock); 2087 goto fail1; 2088 } 2089 IPW2200_DBG(IPW2200_DBG_RING, (sc->sc_dip, CE_CONT, 2090 "ipw2200_send(): tx-free=%d,tx-curr=%d\n", 2091 sc->sc_tx_free, sc->sc_tx_cur)); 2092 2093 /* 2094 * put the mp into one blk, and use it to do the crypto_encap 2095 * if necessaary. 2096 */ 2097 m = allocb(msgdsize(mp) + 32, BPRI_MED); 2098 if (m == NULL) { /* can not alloc buf, drop this package */ 2099 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 2100 "ipw2200_send(): msg allocation failed\n")); 2101 freemsg(mp); 2102 err = DDI_FAILURE; 2103 goto fail1; 2104 } 2105 for (off = 0, m0 = mp; m0 != NULL; m0 = m0->b_cont) { 2106 cnt = MBLKL(m0); 2107 (void) memcpy(m->b_rptr + off, m0->b_rptr, cnt); 2108 off += cnt; 2109 } 2110 m->b_wptr += off; 2111 2112 /* 2113 * find tx_node, and encapsulate the data 2114 */ 2115 wh = (struct ieee80211_frame *)m->b_rptr; 2116 in = ieee80211_find_txnode(ic, wh->i_addr1); 2117 if (in == NULL) { /* can not find the tx node, drop the package */ 2118 ic->ic_stats.is_tx_failed++; 2119 freemsg(mp); 2120 err = DDI_FAILURE; 2121 goto fail2; 2122 } 2123 in->in_inact = 0; 2124 2125 (void) ieee80211_encap(ic, m, in); 2126 ieee80211_free_node(in); 2127 2128 if (wh->i_fc[1] & IEEE80211_FC1_WEP) { 2129 k = ieee80211_crypto_encap(ic, m); 2130 if (k == NULL) { /* can not get the key, drop packages */ 2131 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 2132 "ipw2200_send(): " 2133 "Encrypting 802.11 frame failed\n")); 2134 freemsg(mp); 2135 err = DDI_FAILURE; 2136 goto fail2; 2137 } 2138 wh = (struct ieee80211_frame *)m->b_rptr; 2139 } 2140 2141 /* 2142 * get txdsc 2143 */ 2144 idx = sc->sc_tx_cur; 2145 txdsc = &sc->sc_txdsc[idx]; 2146 (void) memset(txdsc, 0, sizeof (*txdsc)); 2147 /* 2148 * extract header from message 2149 */ 2150 p = (uint8_t *)&txdsc->wh; 2151 off = sizeof (struct ieee80211_frame); 2152 (void) memcpy(p, m->b_rptr, off); 2153 /* 2154 * extract payload from message 2155 */ 2156 dr = &sc->sc_dma_txbufs[idx]; 2157 p = sc->sc_txbufs[idx]; 2158 cnt = MBLKL(m); 2159 (void) memcpy(p, m->b_rptr + off, cnt - off); 2160 cnt -= off; 2161 2162 txdsc->hdr.type = IPW2200_HDR_TYPE_DATA; 2163 txdsc->hdr.flags = IPW2200_HDR_FLAG_IRQ; 2164 txdsc->cmd = IPW2200_DATA_CMD_TX; 2165 txdsc->len = LE_16(cnt); 2166 txdsc->flags = 0; 2167 2168 if (ic->ic_opmode == IEEE80211_M_IBSS) { 2169 if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) 2170 txdsc->flags |= IPW2200_DATA_FLAG_NEED_ACK; 2171 } else if (!IEEE80211_IS_MULTICAST(wh->i_addr3)) 2172 txdsc->flags |= IPW2200_DATA_FLAG_NEED_ACK; 2173 2174 /* always set it to none wep, because it's handled by software */ 2175 txdsc->flags |= IPW2200_DATA_FLAG_NO_WEP; 2176 2177 if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) 2178 txdsc->flags |= IPW2200_DATA_FLAG_SHPREAMBLE; 2179 2180 txdsc->nseg = LE_32(1); 2181 txdsc->seg_addr[0] = LE_32(dr->dr_pbase); 2182 txdsc->seg_len[0] = LE_32(cnt); 2183 2184 /* 2185 * DMA sync: buffer and desc 2186 */ 2187 (void) ddi_dma_sync(dr->dr_hnd, 0, 2188 IPW2200_TXBUF_SIZE, DDI_DMA_SYNC_FORDEV); 2189 (void) ddi_dma_sync(sc->sc_dma_txdsc.dr_hnd, 2190 idx * sizeof (struct ipw2200_tx_desc), 2191 sizeof (struct ipw2200_tx_desc), DDI_DMA_SYNC_FORDEV); 2192 2193 sc->sc_tx_cur = RING_FORWARD(sc->sc_tx_cur, 1, IPW2200_TX_RING_SIZE); 2194 sc->sc_tx_free--; 2195 2196 /* 2197 * update txcur 2198 */ 2199 ipw2200_csr_put32(sc, IPW2200_CSR_TX1_WRITE_INDEX, sc->sc_tx_cur); 2200 2201 /* 2202 * success, free the original message 2203 */ 2204 if (mp) 2205 freemsg(mp); 2206 fail2: 2207 if (m) 2208 freemsg(m); 2209 fail1: 2210 mutex_exit(&sc->sc_tx_lock); 2211 fail0: 2212 IPW2200_DBG(IPW2200_DBG_GLD, (sc->sc_dip, CE_CONT, 2213 "ipw2200_send(): exit - err=%d\n", err)); 2214 2215 return (err); 2216 } 2217 2218 /* 2219 * IOCTL handlers 2220 */ 2221 #define IEEE80211_IOCTL_REQUIRED (1) 2222 #define IEEE80211_IOCTL_NOT_REQUIRED (0) 2223 static void 2224 ipw2200_m_ioctl(void *arg, queue_t *q, mblk_t *m) 2225 { 2226 struct ipw2200_softc *sc = (struct ipw2200_softc *)arg; 2227 struct ieee80211com *ic = &sc->sc_ic; 2228 uint32_t err; 2229 2230 IPW2200_DBG(IPW2200_DBG_GLD, (sc->sc_dip, CE_CONT, 2231 "ipw2200_m_ioctl(): enter\n")); 2232 2233 /* 2234 * Check whether or not need to handle this in net80211 2235 * 2236 */ 2237 if (ipw2200_ioctl(sc, q, m) == IEEE80211_IOCTL_NOT_REQUIRED) 2238 return; 2239 2240 err = ieee80211_ioctl(ic, q, m); 2241 if (err == ENETRESET) { 2242 if (sc->sc_flags & IPW2200_FLAG_RUNNING) { 2243 (void) ipw2200_m_start(sc); 2244 (void) ieee80211_new_state(ic, 2245 IEEE80211_S_SCAN, -1); 2246 } 2247 } 2248 if (err == ERESTART) { 2249 if (sc->sc_flags & IPW2200_FLAG_RUNNING) 2250 (void) ipw2200_chip_reset(sc); 2251 } 2252 } 2253 static int 2254 ipw2200_ioctl(struct ipw2200_softc *sc, queue_t *q, mblk_t *m) 2255 { 2256 struct iocblk *iocp; 2257 uint32_t len, ret, cmd; 2258 mblk_t *m0; 2259 boolean_t need_privilege; 2260 boolean_t need_net80211; 2261 2262 if (MBLKL(m) < sizeof (struct iocblk)) { 2263 IPW2200_DBG(IPW2200_DBG_IOCTL, (sc->sc_dip, CE_CONT, 2264 "ipw2200_ioctl(): ioctl buffer too short, %u\n", 2265 MBLKL(m))); 2266 miocnak(q, m, 0, EINVAL); 2267 /* 2268 * Buf not enough, do not need net80211 either 2269 */ 2270 return (IEEE80211_IOCTL_NOT_REQUIRED); 2271 } 2272 2273 /* 2274 * Validate the command 2275 */ 2276 iocp = (struct iocblk *)m->b_rptr; 2277 iocp->ioc_error = 0; 2278 cmd = iocp->ioc_cmd; 2279 need_privilege = B_TRUE; 2280 switch (cmd) { 2281 case WLAN_SET_PARAM: 2282 case WLAN_COMMAND: 2283 break; 2284 case WLAN_GET_PARAM: 2285 need_privilege = B_FALSE; 2286 break; 2287 default: 2288 IPW2200_DBG(IPW2200_DBG_IOCTL, (sc->sc_dip, CE_CONT, 2289 "ipw2200_ioctl(): unknown cmd 0x%x", cmd)); 2290 miocnak(q, m, 0, EINVAL); 2291 /* 2292 * Unknown cmd, do not need net80211 either 2293 */ 2294 return (IEEE80211_IOCTL_NOT_REQUIRED); 2295 } 2296 2297 if (need_privilege) { 2298 /* 2299 * Check for specific net_config privilege on Solaris 10+. 2300 * Otherwise just check for root access ... 2301 */ 2302 if (secpolicy_net_config != NULL) 2303 ret = secpolicy_net_config(iocp->ioc_cr, B_FALSE); 2304 else 2305 ret = drv_priv(iocp->ioc_cr); 2306 if (ret != 0) { 2307 miocnak(q, m, 0, ret); 2308 /* 2309 * privilege check fail, do not need net80211 either 2310 */ 2311 return (IEEE80211_IOCTL_NOT_REQUIRED); 2312 } 2313 } 2314 /* 2315 * sanity check 2316 */ 2317 m0 = m->b_cont; 2318 if (iocp->ioc_count == 0 || iocp->ioc_count < sizeof (wldp_t) || 2319 m0 == NULL) { 2320 miocnak(q, m, 0, EINVAL); 2321 /* 2322 * invalid format, do not need net80211 either 2323 */ 2324 return (IEEE80211_IOCTL_NOT_REQUIRED); 2325 } 2326 /* 2327 * assuming single data block 2328 */ 2329 if (m0->b_cont) { 2330 freemsg(m0->b_cont); 2331 m0->b_cont = NULL; 2332 } 2333 2334 need_net80211 = B_FALSE; 2335 ret = ipw2200_getset(sc, m0, cmd, &need_net80211); 2336 if (!need_net80211) { 2337 len = msgdsize(m0); 2338 2339 IPW2200_DBG(IPW2200_DBG_IOCTL, (sc->sc_dip, CE_CONT, 2340 "ipw2200_ioctl(): go to call miocack with " 2341 "ret = %d, len = %d\n", ret, len)); 2342 miocack(q, m, len, ret); 2343 return (IEEE80211_IOCTL_NOT_REQUIRED); 2344 } 2345 2346 /* 2347 * IEEE80211_IOCTL - need net80211 handle 2348 */ 2349 return (IEEE80211_IOCTL_REQUIRED); 2350 } 2351 2352 static int 2353 ipw2200_getset(struct ipw2200_softc *sc, mblk_t *m, uint32_t cmd, 2354 boolean_t *need_net80211) 2355 { 2356 wldp_t *infp, *outfp; 2357 uint32_t id; 2358 int ret; 2359 2360 infp = (wldp_t *)m->b_rptr; 2361 outfp = (wldp_t *)m->b_rptr; 2362 outfp->wldp_result = WL_NOTSUPPORTED; 2363 2364 id = infp->wldp_id; 2365 IPW2200_DBG(IPW2200_DBG_IOCTL, (sc->sc_dip, CE_CONT, 2366 "ipw2200_getset(): id = 0x%x\n", id)); 2367 switch (id) { 2368 case WL_RADIO: /* which is not supported by net80211 */ 2369 ret = iwi_wificfg_radio(sc, cmd, outfp); 2370 break; 2371 case WL_DESIRED_RATES: /* hardware doesn't support fix-rates */ 2372 ret = iwi_wificfg_desrates(outfp); 2373 break; 2374 default: 2375 /* 2376 * The wifi IOCTL net80211 supported: 2377 * case WL_ESSID: 2378 * case WL_BSSID: 2379 * case WL_WEP_KEY_TAB: 2380 * case WL_WEP_KEY_ID: 2381 * case WL_AUTH_MODE: 2382 * case WL_ENCRYPTION: 2383 * case WL_BSS_TYPE: 2384 * case WL_ESS_LIST: 2385 * case WL_LINKSTATUS: 2386 * case WL_RSSI: 2387 * case WL_SCAN: 2388 * case WL_LOAD_DEFAULTS: 2389 * case WL_DISASSOCIATE: 2390 */ 2391 2392 /* 2393 * When radio is off, need to ignore all ioctl. What need to 2394 * do is to check radio status firstly. If radio is ON, pass 2395 * it to net80211, otherwise, return to upper layer directly. 2396 * 2397 * Considering the WL_SUCCESS also means WL_CONNECTED for 2398 * checking linkstatus, one exception for WL_LINKSTATUS is to 2399 * let net80211 handle it. 2400 */ 2401 if ((ipw2200_radio_status(sc) == 0) && 2402 (id != WL_LINKSTATUS)) { 2403 2404 IPW2200_REPORT((sc->sc_dip, CE_CONT, 2405 "iwi: radio is OFF\n")); 2406 2407 outfp->wldp_length = WIFI_BUF_OFFSET; 2408 outfp->wldp_result = WL_SUCCESS; 2409 ret = 0; 2410 break; 2411 } 2412 2413 *need_net80211 = B_TRUE; /* let net80211 do the rest */ 2414 return (0); 2415 } 2416 /* 2417 * we will overwrite everything 2418 */ 2419 m->b_wptr = m->b_rptr + outfp->wldp_length; 2420 return (ret); 2421 } 2422 2423 static int 2424 iwi_wificfg_radio(struct ipw2200_softc *sc, uint32_t cmd, wldp_t *outfp) 2425 { 2426 uint32_t ret = ENOTSUP; 2427 2428 switch (cmd) { 2429 case WLAN_GET_PARAM: 2430 *(wl_linkstatus_t *)(outfp->wldp_buf) = 2431 ipw2200_radio_status(sc); 2432 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_linkstatus_t); 2433 outfp->wldp_result = WL_SUCCESS; 2434 ret = 0; /* command success */ 2435 break; 2436 case WLAN_SET_PARAM: 2437 default: 2438 break; 2439 } 2440 return (ret); 2441 } 2442 2443 static int 2444 iwi_wificfg_desrates(wldp_t *outfp) 2445 { 2446 /* return success, but with result NOTSUPPORTED */ 2447 outfp->wldp_length = WIFI_BUF_OFFSET; 2448 outfp->wldp_result = WL_NOTSUPPORTED; 2449 return (0); 2450 } 2451 /* End of IOCTL Handlers */ 2452 2453 void 2454 ipw2200_fix_channel(struct ieee80211com *ic, mblk_t *m) 2455 { 2456 struct ieee80211_frame *wh; 2457 uint8_t subtype; 2458 uint8_t *frm, *efrm; 2459 2460 wh = (struct ieee80211_frame *)m->b_rptr; 2461 2462 if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_MGT) 2463 return; 2464 2465 subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; 2466 2467 if (subtype != IEEE80211_FC0_SUBTYPE_BEACON && 2468 subtype != IEEE80211_FC0_SUBTYPE_PROBE_RESP) 2469 return; 2470 2471 /* 2472 * assume the message contains only 1 block 2473 */ 2474 frm = (uint8_t *)(wh + 1); 2475 efrm = (uint8_t *)m->b_wptr; 2476 frm += 12; /* skip tstamp, bintval and capinfo fields */ 2477 while (frm < efrm) { 2478 if (*frm == IEEE80211_ELEMID_DSPARMS) 2479 #if IEEE80211_CHAN_MAX < 255 2480 if (frm[2] <= IEEE80211_CHAN_MAX) 2481 #endif 2482 ic->ic_curchan = &ic->ic_sup_channels[frm[2]]; 2483 frm += frm[1] + 2; 2484 } 2485 } 2486 2487 static void 2488 ipw2200_rcv_frame(struct ipw2200_softc *sc, struct ipw2200_frame *frame) 2489 { 2490 struct ieee80211com *ic = &sc->sc_ic; 2491 uint8_t *data = (uint8_t *)frame; 2492 uint32_t len; 2493 struct ieee80211_frame *wh; 2494 struct ieee80211_node *in; 2495 mblk_t *m; 2496 2497 len = LE_16(frame->len); 2498 if ((len < sizeof (struct ieee80211_frame_min)) || 2499 (len > IPW2200_RXBUF_SIZE)) { 2500 IPW2200_DBG(IPW2200_DBG_RX, (sc->sc_dip, CE_CONT, 2501 "ipw2200_rcv_frame(): bad frame length=%u\n", 2502 LE_16(frame->len))); 2503 return; 2504 } 2505 IPW2200_DBG(IPW2200_DBG_RX, (sc->sc_dip, CE_CONT, 2506 "ipw2200_rcv_frame(): chan = %d, length = %d\n", frame->chan, len)); 2507 2508 /* 2509 * Skip the frame header, get the real data from the input 2510 */ 2511 data += sizeof (struct ipw2200_frame); 2512 2513 m = allocb(len, BPRI_MED); 2514 if (m) { 2515 (void) memcpy(m->b_wptr, data, len); 2516 m->b_wptr += len; 2517 2518 if (ic->ic_state == IEEE80211_S_SCAN) { 2519 ic->ic_ibss_chan = &ic->ic_sup_channels[frame->chan]; 2520 ipw2200_fix_channel(ic, m); 2521 } 2522 wh = (struct ieee80211_frame *)m->b_rptr; 2523 2524 in = ieee80211_find_rxnode(ic, wh); 2525 2526 IPW2200_DBG(IPW2200_DBG_RX, (sc->sc_dip, CE_CONT, 2527 "ipw2200_rcv_frame(): " 2528 "type = %x, subtype = %x, i_fc[1] = %x, " 2529 "ni_esslen:%d, ni_essid[0-5]:%c%c%c%c%c%c\n", 2530 wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK, 2531 wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK, 2532 wh->i_fc[1] & IEEE80211_FC1_WEP, 2533 in->in_esslen, 2534 in->in_essid[0], in->in_essid[1], in->in_essid[2], 2535 in->in_essid[3], in->in_essid[4], in->in_essid[5])); 2536 2537 (void) ieee80211_input(ic, m, in, frame->rssi_dbm, 0); 2538 2539 ieee80211_free_node(in); 2540 } 2541 else 2542 IPW2200_WARN((sc->sc_dip, CE_WARN, 2543 "ipw2200_rcv_frame(): " 2544 "cannot allocate receive message(%u)\n", 2545 LE_16(frame->len))); 2546 } 2547 2548 static void 2549 ipw2200_rcv_notif(struct ipw2200_softc *sc, struct ipw2200_notif *notif) 2550 { 2551 struct ieee80211com *ic = &sc->sc_ic; 2552 struct ipw2200_notif_association *assoc; 2553 struct ipw2200_notif_authentication *auth; 2554 uint8_t *ndata = (uint8_t *)notif; 2555 2556 IPW2200_DBG(IPW2200_DBG_NOTIF, (sc->sc_dip, CE_CONT, 2557 "ipw2200_rcv_notif(): type=%u\n", notif->type)); 2558 2559 ndata += sizeof (struct ipw2200_notif); 2560 switch (notif->type) { 2561 case IPW2200_NOTIF_TYPE_ASSOCIATION: 2562 assoc = (struct ipw2200_notif_association *)ndata; 2563 2564 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 2565 "ipw2200_rcv_notif(): association=%u,%u\n", 2566 assoc->state, assoc->status)); 2567 2568 switch (assoc->state) { 2569 case IPW2200_ASSOC_SUCCESS: 2570 sc->sc_flags |= IPW2200_FLAG_ASSOCIATED; 2571 ieee80211_new_state(ic, IEEE80211_S_RUN, -1); 2572 break; 2573 case IPW2200_ASSOC_FAIL: 2574 sc->sc_flags &= ~IPW2200_FLAG_ASSOCIATED; 2575 ieee80211_begin_scan(ic, 1); 2576 break; 2577 default: 2578 break; 2579 } 2580 break; 2581 2582 case IPW2200_NOTIF_TYPE_AUTHENTICATION: 2583 auth = (struct ipw2200_notif_authentication *)ndata; 2584 2585 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT, 2586 "ipw2200_rcv_notif(): authentication=%u\n", auth->state)); 2587 2588 switch (auth->state) { 2589 case IPW2200_AUTH_SUCCESS: 2590 ieee80211_new_state(ic, IEEE80211_S_ASSOC, -1); 2591 break; 2592 case IPW2200_AUTH_FAIL: 2593 sc->sc_flags &= ~IPW2200_FLAG_ASSOCIATED; 2594 break; 2595 default: 2596 IPW2200_DBG(IPW2200_DBG_NOTIF, (sc->sc_dip, CE_CONT, 2597 "ipw2200_rcv_notif(): " 2598 "unknown authentication state(%u)\n", auth->state)); 2599 break; 2600 } 2601 break; 2602 2603 case IPW2200_NOTIF_TYPE_SCAN_CHANNEL: 2604 IPW2200_DBG(IPW2200_DBG_SCAN, (sc->sc_dip, CE_CONT, 2605 "ipw2200_rcv_notif(): scan-channel=%u\n", 2606 ((struct ipw2200_notif_scan_channel *)ndata)->nchan)); 2607 break; 2608 2609 case IPW2200_NOTIF_TYPE_SCAN_COMPLETE: 2610 IPW2200_DBG(IPW2200_DBG_SCAN, (sc->sc_dip, CE_CONT, 2611 "ipw2200_rcv_notif():scan-completed,(%u,%u)\n", 2612 ((struct ipw2200_notif_scan_complete *)ndata)->nchan, 2613 ((struct ipw2200_notif_scan_complete *)ndata)->status)); 2614 2615 /* 2616 * scan complete 2617 */ 2618 sc->sc_flags &= ~IPW2200_FLAG_SCANNING; 2619 ieee80211_end_scan(ic); 2620 break; 2621 2622 case IPW2200_NOTIF_TYPE_BEACON: 2623 case IPW2200_NOTIF_TYPE_CALIBRATION: 2624 case IPW2200_NOTIF_TYPE_NOISE: 2625 /* 2626 * just ignore 2627 */ 2628 break; 2629 default: 2630 IPW2200_DBG(IPW2200_DBG_NOTIF, (sc->sc_dip, CE_CONT, 2631 "ipw2200_rcv_notif(): unknown notification type(%u)\n", 2632 notif->type)); 2633 break; 2634 } 2635 } 2636 2637 static uint_t 2638 ipw2200_intr(caddr_t arg) 2639 { 2640 struct ipw2200_softc *sc = (struct ipw2200_softc *)arg; 2641 struct ieee80211com *ic = &sc->sc_ic; 2642 uint32_t ireg, ridx, len, i; 2643 uint8_t *p, *rxbuf; 2644 struct dma_region *dr; 2645 struct ipw2200_hdr *hdr; 2646 uint32_t widx; 2647 2648 ireg = ipw2200_csr_get32(sc, IPW2200_CSR_INTR); 2649 2650 if (ireg == 0xffffffff) 2651 return (DDI_INTR_UNCLAIMED); 2652 2653 if (!(ireg & IPW2200_INTR_MASK_ALL)) 2654 return (DDI_INTR_UNCLAIMED); 2655 2656 /* 2657 * mask all interrupts 2658 */ 2659 ipw2200_csr_put32(sc, IPW2200_CSR_INTR_MASK, 0); 2660 2661 /* 2662 * acknowledge all fired interrupts 2663 */ 2664 ipw2200_csr_put32(sc, IPW2200_CSR_INTR, ireg); 2665 2666 IPW2200_DBG(IPW2200_DBG_INT, (sc->sc_dip, CE_CONT, 2667 "ipw2200_intr(): enter. interrupt fired, int=0x%08x\n", ireg)); 2668 2669 if (ireg & IPW2200_INTR_MASK_ERR) { 2670 2671 IPW2200_DBG(IPW2200_DBG_FATAL, (sc->sc_dip, CE_CONT, 2672 "ipw2200 interrupt(): int= 0x%08x\n", ireg)); 2673 2674 /* 2675 * inform mfthread to recover hw error by stopping it 2676 */ 2677 mutex_enter(&sc->sc_mflock); 2678 sc->sc_flags |= IPW2200_FLAG_HW_ERR_RECOVER; 2679 mutex_exit(&sc->sc_mflock); 2680 2681 } else { 2682 /* 2683 * FW intr 2684 */ 2685 if (ireg & IPW2200_INTR_FW_INITED) { 2686 mutex_enter(&sc->sc_ilock); 2687 sc->sc_fw_ok = 1; 2688 cv_signal(&sc->sc_fw_cond); 2689 mutex_exit(&sc->sc_ilock); 2690 } 2691 2692 /* 2693 * Radio OFF 2694 */ 2695 if (ireg & IPW2200_INTR_RADIO_OFF) { 2696 IPW2200_REPORT((sc->sc_dip, CE_CONT, 2697 "ipw2200_intr(): radio is OFF\n")); 2698 2699 /* 2700 * Stop hardware, will notify LINK is down. 2701 * Need a better scan solution to ensure 2702 * table has right value. 2703 */ 2704 ipw2200_stop(sc); 2705 } 2706 2707 /* 2708 * CMD intr 2709 */ 2710 if (ireg & IPW2200_INTR_CMD_TRANSFER) { 2711 mutex_enter(&sc->sc_cmd_lock); 2712 ridx = ipw2200_csr_get32(sc, 2713 IPW2200_CSR_CMD_READ_INDEX); 2714 i = RING_FORWARD(sc->sc_cmd_cur, 2715 sc->sc_cmd_free, IPW2200_CMD_RING_SIZE); 2716 len = RING_FLEN(i, ridx, IPW2200_CMD_RING_SIZE); 2717 2718 IPW2200_DBG(IPW2200_DBG_INT, (sc->sc_dip, CE_CONT, 2719 "ipw2200_intr(): cmd-ring,i=%u,ridx=%u,len=%u\n", 2720 i, ridx, len)); 2721 2722 if (len > 0) { 2723 sc->sc_cmd_free += len; 2724 cv_signal(&sc->sc_cmd_cond); 2725 } 2726 for (; i != ridx; 2727 i = RING_FORWARD(i, 1, IPW2200_CMD_RING_SIZE)) 2728 sc->sc_done[i] = 1; 2729 mutex_exit(&sc->sc_cmd_lock); 2730 2731 mutex_enter(&sc->sc_ilock); 2732 cv_signal(&sc->sc_cmd_status_cond); 2733 mutex_exit(&sc->sc_ilock); 2734 } 2735 2736 /* 2737 * RX intr 2738 */ 2739 if (ireg & IPW2200_INTR_RX_TRANSFER) { 2740 ridx = ipw2200_csr_get32(sc, 2741 IPW2200_CSR_RX_READ_INDEX); 2742 widx = ipw2200_csr_get32(sc, 2743 IPW2200_CSR_RX_WRITE_INDEX); 2744 2745 IPW2200_DBG(IPW2200_DBG_INT, (sc->sc_dip, CE_CONT, 2746 "ipw2200_intr(): rx-ring,widx=%u,ridx=%u\n", 2747 ridx, widx)); 2748 2749 for (; sc->sc_rx_cur != ridx; 2750 sc->sc_rx_cur = RING_FORWARD(sc->sc_rx_cur, 1, 2751 IPW2200_RX_RING_SIZE)) { 2752 i = sc->sc_rx_cur; 2753 rxbuf = sc->sc_rxbufs[i]; 2754 dr = &sc->sc_dma_rxbufs[i]; 2755 2756 /* 2757 * DMA sync 2758 */ 2759 (void) ddi_dma_sync(dr->dr_hnd, 0, 2760 IPW2200_RXBUF_SIZE, DDI_DMA_SYNC_FORKERNEL); 2761 /* 2762 * Get rx header(hdr) and rx data(p) from rxbuf 2763 */ 2764 p = rxbuf; 2765 hdr = (struct ipw2200_hdr *)p; 2766 p += sizeof (struct ipw2200_hdr); 2767 2768 IPW2200_DBG(IPW2200_DBG_INT, 2769 (sc->sc_dip, CE_CONT, 2770 "ipw2200_intr(): Rx hdr type %u\n", 2771 hdr->type)); 2772 2773 switch (hdr->type) { 2774 case IPW2200_HDR_TYPE_FRAME: 2775 ipw2200_rcv_frame(sc, 2776 (struct ipw2200_frame *)p); 2777 break; 2778 2779 case IPW2200_HDR_TYPE_NOTIF: 2780 ipw2200_rcv_notif(sc, 2781 (struct ipw2200_notif *)p); 2782 break; 2783 default: 2784 IPW2200_DBG(IPW2200_DBG_INT, 2785 (sc->sc_dip, CE_CONT, 2786 "ipw2200_intr(): " 2787 "unknown Rx hdr type %u\n", 2788 hdr->type)); 2789 break; 2790 } 2791 } 2792 /* 2793 * write sc_rx_cur backward 1 step into RX_WRITE_INDEX 2794 */ 2795 ipw2200_csr_put32(sc, IPW2200_CSR_RX_WRITE_INDEX, 2796 RING_BACKWARD(sc->sc_rx_cur, 1, 2797 IPW2200_RX_RING_SIZE)); 2798 } 2799 2800 /* 2801 * TX intr 2802 */ 2803 if (ireg & IPW2200_INTR_TX1_TRANSFER) { 2804 mutex_enter(&sc->sc_tx_lock); 2805 ridx = ipw2200_csr_get32(sc, 2806 IPW2200_CSR_TX1_READ_INDEX); 2807 len = RING_FLEN(RING_FORWARD(sc->sc_tx_cur, 2808 sc->sc_tx_free, IPW2200_TX_RING_SIZE), 2809 ridx, IPW2200_TX_RING_SIZE); 2810 sc->sc_tx_free += len; 2811 IPW2200_DBG(IPW2200_DBG_RING, (sc->sc_dip, CE_CONT, 2812 "ipw2200_intr(): tx-ring,ridx=%u,len=%u\n", 2813 ridx, len)); 2814 mutex_exit(&sc->sc_tx_lock); 2815 2816 mutex_enter(&sc->sc_resched_lock); 2817 if ((sc->sc_tx_free > IPW2200_TX_RING_MIN) && 2818 (sc->sc_flags & IPW2200_FLAG_TX_SCHED)) { 2819 IPW2200_DBG(IPW2200_DBG_RING, (sc->sc_dip, 2820 CE_CONT, 2821 "ipw2200_intr(): Need Reschedule!")); 2822 sc->sc_flags &= ~IPW2200_FLAG_TX_SCHED; 2823 mac_tx_update(ic->ic_mach); 2824 } 2825 mutex_exit(&sc->sc_resched_lock); 2826 } 2827 } 2828 2829 /* 2830 * enable all interrupts 2831 */ 2832 ipw2200_csr_put32(sc, IPW2200_CSR_INTR_MASK, IPW2200_INTR_MASK_ALL); 2833 2834 return (DDI_INTR_CLAIMED); 2835 } 2836 2837 2838 /* 2839 * Module Loading Data & Entry Points 2840 */ 2841 DDI_DEFINE_STREAM_OPS(ipw2200_devops, nulldev, nulldev, ipw2200_attach, 2842 ipw2200_detach, ipw2200_reset, NULL, D_MP, NULL); 2843 2844 static struct modldrv ipw2200_modldrv = { 2845 &mod_driverops, 2846 ipw2200_ident, 2847 &ipw2200_devops 2848 }; 2849 2850 static struct modlinkage ipw2200_modlinkage = { 2851 MODREV_1, 2852 &ipw2200_modldrv, 2853 NULL 2854 }; 2855 2856 int 2857 _init(void) 2858 { 2859 int status; 2860 2861 status = ddi_soft_state_init(&ipw2200_ssp, 2862 sizeof (struct ipw2200_softc), 1); 2863 if (status != DDI_SUCCESS) 2864 return (status); 2865 2866 mac_init_ops(&ipw2200_devops, IPW2200_DRV_NAME); 2867 status = mod_install(&ipw2200_modlinkage); 2868 if (status != DDI_SUCCESS) { 2869 mac_fini_ops(&ipw2200_devops); 2870 ddi_soft_state_fini(&ipw2200_ssp); 2871 } 2872 2873 return (status); 2874 } 2875 2876 int 2877 _fini(void) 2878 { 2879 int status; 2880 2881 status = mod_remove(&ipw2200_modlinkage); 2882 if (status == DDI_SUCCESS) { 2883 mac_fini_ops(&ipw2200_devops); 2884 ddi_soft_state_fini(&ipw2200_ssp); 2885 } 2886 2887 return (status); 2888 } 2889 2890 int 2891 _info(struct modinfo *modinfop) 2892 { 2893 return (mod_info(&ipw2200_modlinkage, modinfop)); 2894 } 2895