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