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