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