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