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