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