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