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 IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT,
1001 "ipw2100_config(): Enabling adapter\n"));
1002
1003 return (ipw2100_cmd(sc, IPW2100_CMD_ENABLE, NULL, 0));
1004 }
1005
1006 static int
ipw2100_cmd(struct ipw2100_softc * sc,uint32_t type,void * buf,size_t len)1007 ipw2100_cmd(struct ipw2100_softc *sc, uint32_t type, void *buf, size_t len)
1008 {
1009 struct ipw2100_bd *txbd;
1010 clock_t clk;
1011 uint32_t idx;
1012
1013 /*
1014 * prepare command buffer
1015 */
1016 sc->sc_cmd->type = LE_32(type);
1017 sc->sc_cmd->subtype = LE_32(0);
1018 sc->sc_cmd->seq = LE_32(0);
1019 /*
1020 * copy data if any
1021 */
1022 if (len && buf)
1023 (void) memcpy(sc->sc_cmd->data, buf, len);
1024 sc->sc_cmd->len = LE_32(len);
1025
1026 /*
1027 * get host & device descriptor to submit command
1028 */
1029 mutex_enter(&sc->sc_tx_lock);
1030
1031 IPW2100_DBG(IPW2100_DBG_RING, (sc->sc_dip, CE_CONT,
1032 "ipw2100_cmd(): tx-free=%d\n", sc->sc_tx_free));
1033
1034 /*
1035 * command need 1 descriptor
1036 */
1037 while (sc->sc_tx_free < 1) {
1038 sc->sc_flags |= IPW2100_FLAG_CMD_WAIT;
1039 cv_wait(&sc->sc_tx_cond, &sc->sc_tx_lock);
1040 }
1041 idx = sc->sc_tx_cur;
1042
1043 IPW2100_DBG(IPW2100_DBG_RING, (sc->sc_dip, CE_CONT,
1044 "ipw2100_cmd(): tx-cur=%d\n", idx));
1045
1046 sc->sc_done = 0;
1047
1048 txbd = &sc->sc_txbd[idx];
1049 txbd->phyaddr = LE_32(sc->sc_dma_cmd.dr_pbase);
1050 txbd->len = LE_32(sizeof (struct ipw2100_cmd));
1051 txbd->flags = IPW2100_BD_FLAG_TX_FRAME_COMMAND
1052 | IPW2100_BD_FLAG_TX_LAST_FRAGMENT;
1053 txbd->nfrag = 1;
1054 /*
1055 * sync for device
1056 */
1057 (void) ddi_dma_sync(sc->sc_dma_cmd.dr_hnd, 0,
1058 sizeof (struct ipw2100_cmd), DDI_DMA_SYNC_FORDEV);
1059 (void) ddi_dma_sync(sc->sc_dma_txbd.dr_hnd,
1060 idx * sizeof (struct ipw2100_bd),
1061 sizeof (struct ipw2100_bd), DDI_DMA_SYNC_FORDEV);
1062
1063 /*
1064 * ring move forward
1065 */
1066 sc->sc_tx_cur = RING_FORWARD(sc->sc_tx_cur, 1, IPW2100_NUM_TXBD);
1067 sc->sc_tx_free--;
1068 ipw2100_csr_put32(sc, IPW2100_CSR_TX_WRITE_INDEX, sc->sc_tx_cur);
1069 mutex_exit(&sc->sc_tx_lock);
1070
1071 /*
1072 * wait for command done
1073 */
1074 clk = drv_usectohz(1000000); /* 1 second */
1075 mutex_enter(&sc->sc_ilock);
1076 while (sc->sc_done == 0) {
1077 /*
1078 * pending for the response
1079 */
1080 if (cv_reltimedwait(&sc->sc_cmd_cond, &sc->sc_ilock,
1081 clk, TR_CLOCK_TICK) < 0)
1082 break;
1083 }
1084 mutex_exit(&sc->sc_ilock);
1085
1086 IPW2100_DBG(IPW2100_DBG_RING, (sc->sc_dip, CE_CONT,
1087 "ipw2100_cmd(): cmd-done=%s\n", sc->sc_done ? "yes" : "no"));
1088
1089 if (sc->sc_done == 0)
1090 return (DDI_FAILURE);
1091
1092 return (DDI_SUCCESS);
1093 }
1094
1095 int
ipw2100_init(struct ipw2100_softc * sc)1096 ipw2100_init(struct ipw2100_softc *sc)
1097 {
1098 int err;
1099
1100 IPW2100_DBG(IPW2100_DBG_INIT, (sc->sc_dip, CE_CONT,
1101 "ipw2100_init(): enter\n"));
1102
1103 /*
1104 * no firmware is available, return fail directly
1105 */
1106 if (!(sc->sc_flags & IPW2100_FLAG_FW_CACHED)) {
1107 IPW2100_WARN((sc->sc_dip, CE_WARN,
1108 "ipw2100_init(): no firmware is available\n"));
1109 return (DDI_FAILURE);
1110 }
1111
1112 ipw2100_stop(sc);
1113
1114 err = ipw2100_chip_reset(sc);
1115 if (err != DDI_SUCCESS) {
1116 IPW2100_WARN((sc->sc_dip, CE_WARN,
1117 "ipw2100_init(): could not reset adapter\n"));
1118 goto fail;
1119 }
1120
1121 /*
1122 * load microcode
1123 */
1124 IPW2100_DBG(IPW2100_DBG_INIT, (sc->sc_dip, CE_CONT,
1125 "ipw2100_init(): loading microcode\n"));
1126 err = ipw2100_load_uc(sc);
1127 if (err != DDI_SUCCESS) {
1128 IPW2100_WARN((sc->sc_dip, CE_WARN,
1129 "ipw2100_init(): could not load microcode, try again\n"));
1130 goto fail;
1131 }
1132
1133 ipw2100_master_stop(sc);
1134
1135 ipw2100_ring_hwsetup(sc);
1136
1137 /*
1138 * load firmware
1139 */
1140 IPW2100_DBG(IPW2100_DBG_INIT, (sc->sc_dip, CE_CONT,
1141 "ipw2100_init(): loading firmware\n"));
1142 err = ipw2100_load_fw(sc);
1143 if (err != DDI_SUCCESS) {
1144 IPW2100_WARN((sc->sc_dip, CE_WARN,
1145 "ipw2100_init(): could not load firmware, try again\n"));
1146 goto fail;
1147 }
1148
1149 /*
1150 * initialize tables
1151 */
1152 ipw2100_tables_init(sc);
1153 ipw2100_table1_put32(sc, IPW2100_INFO_LOCK, 0);
1154
1155 /*
1156 * Hardware will be enabled after configuration
1157 */
1158 err = ipw2100_config(sc);
1159 if (err != DDI_SUCCESS) {
1160 IPW2100_WARN((sc->sc_dip, CE_WARN,
1161 "ipw2100_init(): device configuration failed\n"));
1162 goto fail;
1163 }
1164
1165 delay(drv_usectohz(delay_config_stable));
1166
1167 return (DDI_SUCCESS);
1168
1169 fail:
1170 ipw2100_stop(sc);
1171
1172 return (err);
1173 }
1174
1175 /*
1176 * get hardware configurations from EEPROM embedded within chip
1177 */
1178 static void
ipw2100_hwconf_get(struct ipw2100_softc * sc)1179 ipw2100_hwconf_get(struct ipw2100_softc *sc)
1180 {
1181 int i;
1182 uint16_t val;
1183
1184 /*
1185 * MAC address
1186 */
1187 i = 0;
1188 val = ipw2100_rom_get16(sc, IPW2100_ROM_MAC + 0);
1189 sc->sc_macaddr[i++] = val >> 8;
1190 sc->sc_macaddr[i++] = val & 0xff;
1191 val = ipw2100_rom_get16(sc, IPW2100_ROM_MAC + 1);
1192 sc->sc_macaddr[i++] = val >> 8;
1193 sc->sc_macaddr[i++] = val & 0xff;
1194 val = ipw2100_rom_get16(sc, IPW2100_ROM_MAC + 2);
1195 sc->sc_macaddr[i++] = val >> 8;
1196 sc->sc_macaddr[i++] = val & 0xff;
1197
1198 /*
1199 * formatted MAC address string
1200 */
1201 (void) snprintf(sc->sc_macstr, sizeof (sc->sc_macstr),
1202 "%02x:%02x:%02x:%02x:%02x:%02x",
1203 sc->sc_macaddr[0], sc->sc_macaddr[1],
1204 sc->sc_macaddr[2], sc->sc_macaddr[3],
1205 sc->sc_macaddr[4], sc->sc_macaddr[5]);
1206
1207 /*
1208 * channel mask
1209 */
1210 val = ipw2100_rom_get16(sc, IPW2100_ROM_CHANNEL_LIST);
1211 if (val == 0)
1212 val = 0x7ff;
1213 sc->sc_chmask = val << 1;
1214 IPW2100_DBG(IPW2100_DBG_HWCAP, (sc->sc_dip, CE_CONT,
1215 "ipw2100_hwconf_get(): channel-mask=0x%08x\n", sc->sc_chmask));
1216
1217 /*
1218 * radio switch
1219 */
1220 val = ipw2100_rom_get16(sc, IPW2100_ROM_RADIO);
1221 if (val & 0x08)
1222 sc->sc_flags |= IPW2100_FLAG_HAS_RADIO_SWITCH;
1223
1224 IPW2100_DBG(IPW2100_DBG_HWCAP, (sc->sc_dip, CE_CONT,
1225 "ipw2100_hwconf_get(): has-radio-switch=%s(%u)\n",
1226 (sc->sc_flags & IPW2100_FLAG_HAS_RADIO_SWITCH)? "yes" : "no",
1227 val));
1228 }
1229
1230 /*
1231 * all ipw2100 interrupts will be masked by this routine
1232 */
1233 static void
ipw2100_master_stop(struct ipw2100_softc * sc)1234 ipw2100_master_stop(struct ipw2100_softc *sc)
1235 {
1236 uint32_t tmp;
1237 int ntries;
1238
1239 /*
1240 * disable interrupts
1241 */
1242 ipw2100_csr_put32(sc, IPW2100_CSR_INTR_MASK, 0);
1243
1244 ipw2100_csr_put32(sc, IPW2100_CSR_RST, IPW2100_RST_STOP_MASTER);
1245 for (ntries = 0; ntries < 50; ntries++) {
1246 if (ipw2100_csr_get32(sc, IPW2100_CSR_RST)
1247 & IPW2100_RST_MASTER_DISABLED)
1248 break;
1249 drv_usecwait(10);
1250 }
1251 if (ntries == 50 && !(sc->sc_flags & IPW2100_FLAG_QUIESCED))
1252 IPW2100_WARN((sc->sc_dip, CE_WARN,
1253 "ipw2100_master_stop(): timeout when stop master\n"));
1254
1255 tmp = ipw2100_csr_get32(sc, IPW2100_CSR_RST);
1256 ipw2100_csr_put32(sc, IPW2100_CSR_RST,
1257 tmp | IPW2100_RST_PRINCETON_RESET);
1258
1259 sc->sc_flags &= ~IPW2100_FLAG_FW_INITED;
1260 }
1261
1262 /*
1263 * all ipw2100 interrupts will be masked by this routine
1264 */
1265 static int
ipw2100_chip_reset(struct ipw2100_softc * sc)1266 ipw2100_chip_reset(struct ipw2100_softc *sc)
1267 {
1268 int ntries;
1269 uint32_t tmp;
1270
1271 ipw2100_master_stop(sc);
1272
1273 /*
1274 * move adapter to DO state
1275 */
1276 tmp = ipw2100_csr_get32(sc, IPW2100_CSR_CTL);
1277 ipw2100_csr_put32(sc, IPW2100_CSR_CTL, tmp | IPW2100_CTL_INIT);
1278
1279 /*
1280 * wait for clock stabilization
1281 */
1282 for (ntries = 0; ntries < 1000; ntries++) {
1283 if (ipw2100_csr_get32(sc, IPW2100_CSR_CTL)
1284 & IPW2100_CTL_CLOCK_READY)
1285 break;
1286 drv_usecwait(200);
1287 }
1288 if (ntries == 1000)
1289 return (DDI_FAILURE);
1290
1291 tmp = ipw2100_csr_get32(sc, IPW2100_CSR_RST);
1292 ipw2100_csr_put32(sc, IPW2100_CSR_RST, tmp | IPW2100_RST_SW_RESET);
1293
1294 drv_usecwait(10);
1295
1296 tmp = ipw2100_csr_get32(sc, IPW2100_CSR_CTL);
1297 ipw2100_csr_put32(sc, IPW2100_CSR_CTL, tmp | IPW2100_CTL_INIT);
1298
1299 return (DDI_SUCCESS);
1300 }
1301
1302 /*
1303 * get the radio status from IPW_CSR_IO, invoked by wificonfig/dladm
1304 */
1305 int
ipw2100_get_radio(struct ipw2100_softc * sc)1306 ipw2100_get_radio(struct ipw2100_softc *sc)
1307 {
1308 if (ipw2100_csr_get32(sc, IPW2100_CSR_IO) & IPW2100_IO_RADIO_DISABLED)
1309 return (0);
1310 else
1311 return (1);
1312
1313 }
1314 /*
1315 * This function is used to get the statistic, invoked by wificonfig/dladm
1316 */
1317 void
ipw2100_get_statistics(struct ipw2100_softc * sc)1318 ipw2100_get_statistics(struct ipw2100_softc *sc)
1319 {
1320 struct ieee80211com *ic = &sc->sc_ic;
1321 uint32_t addr, size, i;
1322 uint32_t atbl[256], *datatbl;
1323
1324 datatbl = atbl;
1325
1326 if (!(sc->sc_flags & IPW2100_FLAG_FW_INITED)) {
1327 IPW2100_DBG(IPW2100_DBG_STATISTIC, (sc->sc_dip, CE_CONT,
1328 "ipw2100_get_statistic(): fw doesn't download yet."));
1329 return;
1330 }
1331
1332 ipw2100_csr_put32(sc, IPW2100_CSR_AUTOINC_ADDR, sc->sc_table1_base);
1333
1334 size = ipw2100_csr_get32(sc, IPW2100_CSR_AUTOINC_DATA);
1335 atbl[0] = size;
1336 for (i = 1, ++datatbl; i < size; i++, datatbl++) {
1337 addr = ipw2100_csr_get32(sc, IPW2100_CSR_AUTOINC_DATA);
1338 *datatbl = ipw2100_imem_get32(sc, addr);
1339 }
1340
1341 /*
1342 * To retrieve the statistic information into proper places. There are
1343 * lot of information.
1344 */
1345 IPW2100_DBG(IPW2100_DBG_STATISTIC, (sc->sc_dip, CE_CONT,
1346 "ipw2100_get_statistic(): \n"
1347 "operating mode = %u\n"
1348 "type of authentification= %u\n"
1349 "average RSSI= %u\n"
1350 "current channel = %d\n",
1351 atbl[191], atbl[199], atbl[173], atbl[189]));
1352 /* WIFI_STAT_TX_FRAGS */
1353 ic->ic_stats.is_tx_frags = (uint32_t)atbl[2];
1354 /* WIFI_STAT_MCAST_TX = (all frame - unicast frame) */
1355 ic->ic_stats.is_tx_mcast = (uint32_t)atbl[2] - (uint32_t)atbl[3];
1356 /* WIFI_STAT_TX_RETRANS */
1357 ic->ic_stats.is_tx_retries = (uint32_t)atbl[42];
1358 /* WIFI_STAT_TX_FAILED */
1359 ic->ic_stats.is_tx_failed = (uint32_t)atbl[51];
1360 /* MAC_STAT_OBYTES */
1361 ic->ic_stats.is_tx_bytes = (uint32_t)atbl[41];
1362 /* WIFI_STAT_RX_FRAGS */
1363 ic->ic_stats.is_rx_frags = (uint32_t)atbl[61];
1364 /* WIFI_STAT_MCAST_RX */
1365 ic->ic_stats.is_rx_mcast = (uint32_t)atbl[71];
1366 /* MAC_STAT_IBYTES */
1367 ic->ic_stats.is_rx_bytes = (uint32_t)atbl[101];
1368 /* WIFI_STAT_ACK_FAILURE */
1369 ic->ic_stats.is_ack_failure = (uint32_t)atbl[59];
1370 /* WIFI_STAT_RTS_SUCCESS */
1371 ic->ic_stats.is_rts_success = (uint32_t)atbl[22];
1372 }
1373
1374 /*
1375 * dma region alloc
1376 */
1377 static int
ipw2100_dma_region_alloc(struct ipw2100_softc * sc,struct dma_region * dr,size_t size,uint_t dir,uint_t flags)1378 ipw2100_dma_region_alloc(struct ipw2100_softc *sc,
1379 struct dma_region *dr, size_t size, uint_t dir, uint_t flags)
1380 {
1381 dev_info_t *dip = sc->sc_dip;
1382 int err;
1383
1384 IPW2100_DBG(IPW2100_DBG_DMA, (dip, CE_CONT,
1385 "ipw2100_dma_region_alloc() name=%s size=%u\n",
1386 dr->dr_name, size));
1387
1388 err = ddi_dma_alloc_handle(dip, &ipw2100_dma_attr, DDI_DMA_SLEEP, NULL,
1389 &dr->dr_hnd);
1390 if (err != DDI_SUCCESS) {
1391 IPW2100_DBG(IPW2100_DBG_DMA, (dip, CE_CONT,
1392 "ipw2100_dma_region_alloc(): "
1393 "ddi_dma_alloc_handle() failed\n"));
1394 goto fail0;
1395 }
1396
1397 err = ddi_dma_mem_alloc(dr->dr_hnd, size, &ipw2100_dma_accattr,
1398 flags, DDI_DMA_SLEEP, NULL, &dr->dr_base,
1399 &dr->dr_size, &dr->dr_acc);
1400 if (err != DDI_SUCCESS) {
1401 IPW2100_DBG(IPW2100_DBG_DMA, (dip, CE_CONT,
1402 "ipw2100_dma_region_alloc(): "
1403 "ddi_dma_mem_alloc() failed\n"));
1404 goto fail1;
1405 }
1406
1407 err = ddi_dma_addr_bind_handle(dr->dr_hnd, NULL,
1408 dr->dr_base, dr->dr_size, dir | flags, DDI_DMA_SLEEP, NULL,
1409 &dr->dr_cookie, &dr->dr_ccnt);
1410 if (err != DDI_DMA_MAPPED) {
1411 IPW2100_DBG(IPW2100_DBG_DMA, (dip, CE_CONT,
1412 "ipw2100_dma_region_alloc(): "
1413 "ddi_dma_addr_bind_handle() failed\n"));
1414 goto fail2;
1415 }
1416
1417 if (dr->dr_ccnt != 1) {
1418 err = DDI_FAILURE;
1419 goto fail3;
1420 }
1421 dr->dr_pbase = dr->dr_cookie.dmac_address;
1422
1423 IPW2100_DBG(IPW2100_DBG_DMA, (dip, CE_CONT,
1424 "ipw2100_dma_region_alloc(): get physical-base=0x%08x\n",
1425 dr->dr_pbase));
1426
1427 return (DDI_SUCCESS);
1428
1429 fail3:
1430 (void) ddi_dma_unbind_handle(dr->dr_hnd);
1431 fail2:
1432 ddi_dma_mem_free(&dr->dr_acc);
1433 fail1:
1434 ddi_dma_free_handle(&dr->dr_hnd);
1435 fail0:
1436 return (err);
1437 }
1438
1439 static void
ipw2100_dma_region_free(struct dma_region * dr)1440 ipw2100_dma_region_free(struct dma_region *dr)
1441 {
1442 (void) ddi_dma_unbind_handle(dr->dr_hnd);
1443 ddi_dma_mem_free(&dr->dr_acc);
1444 ddi_dma_free_handle(&dr->dr_hnd);
1445 }
1446
1447 static int
ipw2100_ring_alloc(struct ipw2100_softc * sc)1448 ipw2100_ring_alloc(struct ipw2100_softc *sc)
1449 {
1450 int err, i;
1451
1452 /*
1453 * tx ring
1454 */
1455 sc->sc_dma_txbd.dr_name = "ipw2100-tx-ring-bd";
1456 err = ipw2100_dma_region_alloc(sc, &sc->sc_dma_txbd,
1457 IPW2100_TXBD_SIZE, DDI_DMA_WRITE, DDI_DMA_CONSISTENT);
1458 if (err != DDI_SUCCESS)
1459 goto fail0;
1460 /*
1461 * tx bufs
1462 */
1463 for (i = 0; i < IPW2100_NUM_TXBUF; i++) {
1464 sc->sc_dma_txbufs[i].dr_name = "ipw2100-tx-buf";
1465 err = ipw2100_dma_region_alloc(sc, &sc->sc_dma_txbufs[i],
1466 IPW2100_TXBUF_SIZE, DDI_DMA_WRITE, DDI_DMA_STREAMING);
1467 if (err != DDI_SUCCESS) {
1468 while (i > 0) {
1469 i--;
1470 ipw2100_dma_region_free(&sc->sc_dma_txbufs[i]);
1471 }
1472 goto fail1;
1473 }
1474 }
1475 /*
1476 * rx ring
1477 */
1478 sc->sc_dma_rxbd.dr_name = "ipw2100-rx-ring-bd";
1479 err = ipw2100_dma_region_alloc(sc, &sc->sc_dma_rxbd,
1480 IPW2100_RXBD_SIZE, DDI_DMA_WRITE, DDI_DMA_CONSISTENT);
1481 if (err != DDI_SUCCESS)
1482 goto fail2;
1483 /*
1484 * rx bufs
1485 */
1486 for (i = 0; i < IPW2100_NUM_RXBUF; i++) {
1487 sc->sc_dma_rxbufs[i].dr_name = "ipw2100-rx-buf";
1488 err = ipw2100_dma_region_alloc(sc, &sc->sc_dma_rxbufs[i],
1489 IPW2100_RXBUF_SIZE, DDI_DMA_READ, DDI_DMA_STREAMING);
1490 if (err != DDI_SUCCESS) {
1491 while (i > 0) {
1492 i--;
1493 ipw2100_dma_region_free(&sc->sc_dma_rxbufs[i]);
1494 }
1495 goto fail3;
1496 }
1497 }
1498 /*
1499 * status
1500 */
1501 sc->sc_dma_status.dr_name = "ipw2100-rx-status";
1502 err = ipw2100_dma_region_alloc(sc, &sc->sc_dma_status,
1503 IPW2100_STATUS_SIZE, DDI_DMA_READ, DDI_DMA_CONSISTENT);
1504 if (err != DDI_SUCCESS)
1505 goto fail4;
1506 /*
1507 * command
1508 */
1509 sc->sc_dma_cmd.dr_name = "ipw2100-cmd";
1510 err = ipw2100_dma_region_alloc(sc, &sc->sc_dma_cmd, IPW2100_CMD_SIZE,
1511 DDI_DMA_WRITE, DDI_DMA_CONSISTENT);
1512 if (err != DDI_SUCCESS)
1513 goto fail5;
1514
1515 return (DDI_SUCCESS);
1516
1517 fail5:
1518 ipw2100_dma_region_free(&sc->sc_dma_status);
1519 fail4:
1520 for (i = 0; i < IPW2100_NUM_RXBUF; i++)
1521 ipw2100_dma_region_free(&sc->sc_dma_rxbufs[i]);
1522 fail3:
1523 ipw2100_dma_region_free(&sc->sc_dma_rxbd);
1524 fail2:
1525 for (i = 0; i < IPW2100_NUM_TXBUF; i++)
1526 ipw2100_dma_region_free(&sc->sc_dma_txbufs[i]);
1527 fail1:
1528 ipw2100_dma_region_free(&sc->sc_dma_txbd);
1529 fail0:
1530 return (err);
1531 }
1532
1533 static void
ipw2100_ring_free(struct ipw2100_softc * sc)1534 ipw2100_ring_free(struct ipw2100_softc *sc)
1535 {
1536 int i;
1537
1538 /*
1539 * tx ring
1540 */
1541 ipw2100_dma_region_free(&sc->sc_dma_txbd);
1542 /*
1543 * tx buf
1544 */
1545 for (i = 0; i < IPW2100_NUM_TXBUF; i++)
1546 ipw2100_dma_region_free(&sc->sc_dma_txbufs[i]);
1547 /*
1548 * rx ring
1549 */
1550 ipw2100_dma_region_free(&sc->sc_dma_rxbd);
1551 /*
1552 * rx buf
1553 */
1554 for (i = 0; i < IPW2100_NUM_RXBUF; i++)
1555 ipw2100_dma_region_free(&sc->sc_dma_rxbufs[i]);
1556 /*
1557 * status
1558 */
1559 ipw2100_dma_region_free(&sc->sc_dma_status);
1560 /*
1561 * command
1562 */
1563 ipw2100_dma_region_free(&sc->sc_dma_cmd);
1564 }
1565
1566 static void
ipw2100_ring_reset(struct ipw2100_softc * sc)1567 ipw2100_ring_reset(struct ipw2100_softc *sc)
1568 {
1569 int i;
1570
1571 /*
1572 * tx ring
1573 */
1574 sc->sc_tx_cur = 0;
1575 sc->sc_tx_free = IPW2100_NUM_TXBD;
1576 sc->sc_txbd = (struct ipw2100_bd *)sc->sc_dma_txbd.dr_base;
1577 for (i = 0; i < IPW2100_NUM_TXBUF; i++)
1578 sc->sc_txbufs[i] =
1579 (struct ipw2100_txb *)sc->sc_dma_txbufs[i].dr_base;
1580 /*
1581 * rx ring
1582 */
1583 sc->sc_rx_cur = 0;
1584 sc->sc_rx_free = IPW2100_NUM_RXBD;
1585 sc->sc_status = (struct ipw2100_status *)sc->sc_dma_status.dr_base;
1586 sc->sc_rxbd = (struct ipw2100_bd *)sc->sc_dma_rxbd.dr_base;
1587 for (i = 0; i < IPW2100_NUM_RXBUF; i++) {
1588 sc->sc_rxbufs[i] =
1589 (struct ipw2100_rxb *)sc->sc_dma_rxbufs[i].dr_base;
1590 /*
1591 * initialize Rx buffer descriptors, both host and device
1592 */
1593 sc->sc_rxbd[i].phyaddr = LE_32(sc->sc_dma_rxbufs[i].dr_pbase);
1594 sc->sc_rxbd[i].len = LE_32(sc->sc_dma_rxbufs[i].dr_size);
1595 sc->sc_rxbd[i].flags = 0;
1596 sc->sc_rxbd[i].nfrag = 1;
1597 }
1598 /*
1599 * command
1600 */
1601 sc->sc_cmd = (struct ipw2100_cmd *)sc->sc_dma_cmd.dr_base;
1602 }
1603
1604 /*
1605 * tx, rx rings and command initialization
1606 */
1607 static int
ipw2100_ring_init(struct ipw2100_softc * sc)1608 ipw2100_ring_init(struct ipw2100_softc *sc)
1609 {
1610 int err;
1611
1612 err = ipw2100_ring_alloc(sc);
1613 if (err != DDI_SUCCESS)
1614 return (err);
1615
1616 ipw2100_ring_reset(sc);
1617
1618 return (DDI_SUCCESS);
1619 }
1620
1621 static void
ipw2100_ring_hwsetup(struct ipw2100_softc * sc)1622 ipw2100_ring_hwsetup(struct ipw2100_softc *sc)
1623 {
1624 ipw2100_ring_reset(sc);
1625 /*
1626 * tx ring
1627 */
1628 ipw2100_csr_put32(sc, IPW2100_CSR_TX_BD_BASE, sc->sc_dma_txbd.dr_pbase);
1629 ipw2100_csr_put32(sc, IPW2100_CSR_TX_BD_SIZE, IPW2100_NUM_TXBD);
1630 /*
1631 * no new packet to transmit, tx-rd-index == tx-wr-index
1632 */
1633 ipw2100_csr_put32(sc, IPW2100_CSR_TX_READ_INDEX, sc->sc_tx_cur);
1634 ipw2100_csr_put32(sc, IPW2100_CSR_TX_WRITE_INDEX, sc->sc_tx_cur);
1635 /*
1636 * rx ring
1637 */
1638 ipw2100_csr_put32(sc, IPW2100_CSR_RX_BD_BASE, sc->sc_dma_rxbd.dr_pbase);
1639 ipw2100_csr_put32(sc, IPW2100_CSR_RX_BD_SIZE, IPW2100_NUM_RXBD);
1640 /*
1641 * all rx buffer are empty, rx-rd-index == 0 && rx-wr-index == N-1
1642 */
1643 IPW2100_DBG(IPW2100_DBG_RING, (sc->sc_dip, CE_CONT,
1644 "ipw2100_ring_hwsetup(): rx-cur=%u, backward=%u\n",
1645 sc->sc_rx_cur, RING_BACKWARD(sc->sc_rx_cur, 1, IPW2100_NUM_RXBD)));
1646 ipw2100_csr_put32(sc, IPW2100_CSR_RX_READ_INDEX, sc->sc_rx_cur);
1647 ipw2100_csr_put32(sc, IPW2100_CSR_RX_WRITE_INDEX,
1648 RING_BACKWARD(sc->sc_rx_cur, 1, IPW2100_NUM_RXBD));
1649 /*
1650 * status
1651 */
1652 ipw2100_csr_put32(sc, IPW2100_CSR_RX_STATUS_BASE,
1653 sc->sc_dma_status.dr_pbase);
1654 }
1655
1656 /*
1657 * ieee80211_new_state() is not be used, since the hardware can handle the
1658 * state transfer. Here, we just keep the status of the hardware notification
1659 * result.
1660 */
1661 /* ARGSUSED */
1662 static int
ipw2100_newstate(struct ieee80211com * ic,enum ieee80211_state state,int arg)1663 ipw2100_newstate(struct ieee80211com *ic, enum ieee80211_state state, int arg)
1664 {
1665 struct ipw2100_softc *sc = (struct ipw2100_softc *)ic;
1666 struct ieee80211_node *in;
1667 uint8_t macaddr[IEEE80211_ADDR_LEN];
1668 uint32_t len;
1669 wifi_data_t wd = { 0 };
1670
1671 IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT,
1672 "ipw2100_newstate(): %s -> %s\n",
1673 ieee80211_state_name[ic->ic_state], ieee80211_state_name[state]));
1674
1675 switch (state) {
1676 case IEEE80211_S_RUN:
1677 /*
1678 * we only need to use BSSID as to find the node
1679 */
1680 drv_usecwait(200); /* firmware needs a short delay here */
1681 len = IEEE80211_ADDR_LEN;
1682 (void) ipw2100_table2_getbuf(sc, IPW2100_INFO_CURRENT_BSSID,
1683 macaddr, &len);
1684
1685 in = ieee80211_find_node(&ic->ic_scan, macaddr);
1686 if (in == NULL)
1687 break;
1688
1689 (void) ieee80211_sta_join(ic, in);
1690 ieee80211_node_authorize(in);
1691
1692 /*
1693 * We can send data now; update the fastpath with our
1694 * current associated BSSID.
1695 */
1696 if (ic->ic_flags & IEEE80211_F_PRIVACY)
1697 wd.wd_secalloc = WIFI_SEC_WEP;
1698 else
1699 wd.wd_secalloc = WIFI_SEC_NONE;
1700 wd.wd_opmode = ic->ic_opmode;
1701 IEEE80211_ADDR_COPY(wd.wd_bssid, ic->ic_bss->in_bssid);
1702 (void) mac_pdata_update(ic->ic_mach, &wd, sizeof (wd));
1703
1704 break;
1705
1706 case IEEE80211_S_INIT:
1707 case IEEE80211_S_SCAN:
1708 case IEEE80211_S_AUTH:
1709 case IEEE80211_S_ASSOC:
1710 break;
1711 }
1712
1713 /*
1714 * notify to update the link
1715 */
1716 if ((ic->ic_state != IEEE80211_S_RUN) && (state == IEEE80211_S_RUN)) {
1717 /*
1718 * previously disconnected and now connected
1719 */
1720 sc->sc_linkstate = LINK_STATE_UP;
1721 sc->sc_flags |= IPW2100_FLAG_LINK_CHANGE;
1722 } else if ((ic->ic_state == IEEE80211_S_RUN) &&
1723 (state != IEEE80211_S_RUN)) {
1724 /*
1725 * previously connected andd now disconnected
1726 */
1727 sc->sc_linkstate = LINK_STATE_DOWN;
1728 sc->sc_flags |= IPW2100_FLAG_LINK_CHANGE;
1729 }
1730
1731 ic->ic_state = state;
1732 return (DDI_SUCCESS);
1733 }
1734
1735 /*
1736 * GLD operations
1737 */
1738 /* ARGSUSED */
1739 static int
ipw2100_m_stat(void * arg,uint_t stat,uint64_t * val)1740 ipw2100_m_stat(void *arg, uint_t stat, uint64_t *val)
1741 {
1742 ieee80211com_t *ic = (ieee80211com_t *)arg;
1743 IPW2100_DBG(IPW2100_DBG_GLD, (((struct ipw2100_softc *)arg)->sc_dip,
1744 CE_CONT,
1745 "ipw2100_m_stat(): enter\n"));
1746 /*
1747 * some of below statistic data are from hardware, some from net80211
1748 */
1749 switch (stat) {
1750 case MAC_STAT_RBYTES:
1751 *val = ic->ic_stats.is_rx_bytes;
1752 break;
1753 case MAC_STAT_IPACKETS:
1754 *val = ic->ic_stats.is_rx_frags;
1755 break;
1756 case MAC_STAT_OBYTES:
1757 *val = ic->ic_stats.is_tx_bytes;
1758 break;
1759 case MAC_STAT_OPACKETS:
1760 *val = ic->ic_stats.is_tx_frags;
1761 break;
1762 /*
1763 * Get below from hardware statistic, retrieve net80211 value once 1s
1764 */
1765 case WIFI_STAT_TX_FRAGS:
1766 case WIFI_STAT_MCAST_TX:
1767 case WIFI_STAT_TX_FAILED:
1768 case WIFI_STAT_TX_RETRANS:
1769 case WIFI_STAT_RTS_SUCCESS:
1770 case WIFI_STAT_ACK_FAILURE:
1771 case WIFI_STAT_RX_FRAGS:
1772 case WIFI_STAT_MCAST_RX:
1773 /*
1774 * Get blow information from net80211
1775 */
1776 case WIFI_STAT_RTS_FAILURE:
1777 case WIFI_STAT_RX_DUPS:
1778 case WIFI_STAT_FCS_ERRORS:
1779 case WIFI_STAT_WEP_ERRORS:
1780 return (ieee80211_stat(ic, stat, val));
1781 /*
1782 * need be supported in the future
1783 */
1784 case MAC_STAT_IFSPEED:
1785 case MAC_STAT_NOXMTBUF:
1786 case MAC_STAT_IERRORS:
1787 case MAC_STAT_OERRORS:
1788 default:
1789 return (ENOTSUP);
1790 }
1791 return (0);
1792 }
1793
1794 /* ARGSUSED */
1795 static int
ipw2100_m_multicst(void * arg,boolean_t add,const uint8_t * mca)1796 ipw2100_m_multicst(void *arg, boolean_t add, const uint8_t *mca)
1797 {
1798 /* not supported */
1799 IPW2100_DBG(IPW2100_DBG_GLD, (((struct ipw2100_softc *)arg)->sc_dip,
1800 CE_CONT,
1801 "ipw2100_m_multicst(): enter\n"));
1802
1803 return (0);
1804 }
1805
1806 /*
1807 * This thread function is used to handle the fatal error.
1808 */
1809 static void
ipw2100_thread(struct ipw2100_softc * sc)1810 ipw2100_thread(struct ipw2100_softc *sc)
1811 {
1812 struct ieee80211com *ic = &sc->sc_ic;
1813 int32_t nlstate;
1814 int stat_cnt = 0;
1815
1816 IPW2100_DBG(IPW2100_DBG_SOFTINT, (sc->sc_dip, CE_CONT,
1817 "ipw2100_thread(): into ipw2100 thread--> %d\n",
1818 sc->sc_linkstate));
1819
1820 mutex_enter(&sc->sc_mflock);
1821
1822 while (sc->sc_mfthread_switch) {
1823 /*
1824 * notify the link state
1825 */
1826 if (ic->ic_mach && (sc->sc_flags & IPW2100_FLAG_LINK_CHANGE)) {
1827 IPW2100_DBG(IPW2100_DBG_SOFTINT, (sc->sc_dip, CE_CONT,
1828 "ipw2100_thread(): link status --> %d\n",
1829 sc->sc_linkstate));
1830
1831 sc->sc_flags &= ~IPW2100_FLAG_LINK_CHANGE;
1832 nlstate = sc->sc_linkstate;
1833
1834 mutex_exit(&sc->sc_mflock);
1835 mac_link_update(ic->ic_mach, nlstate);
1836 mutex_enter(&sc->sc_mflock);
1837 }
1838
1839 /*
1840 * recovery interrupt fatal error
1841 */
1842 if (ic->ic_mach &&
1843 (sc->sc_flags & IPW2100_FLAG_HW_ERR_RECOVER)) {
1844
1845 IPW2100_DBG(IPW2100_DBG_FATAL, (sc->sc_dip, CE_CONT,
1846 "try to recover fatal hw error\n"));
1847 sc->sc_flags &= ~IPW2100_FLAG_HW_ERR_RECOVER;
1848
1849 mutex_exit(&sc->sc_mflock);
1850 (void) ipw2100_init(sc); /* Force stat machine */
1851 delay(drv_usectohz(delay_fatal_recover));
1852 mutex_enter(&sc->sc_mflock);
1853 }
1854
1855 /*
1856 * get statistic, the value will be retrieved by m_stat
1857 */
1858 if (stat_cnt == 10) {
1859 stat_cnt = 0; /* re-start */
1860
1861 mutex_exit(&sc->sc_mflock);
1862 ipw2100_get_statistics(sc);
1863 mutex_enter(&sc->sc_mflock);
1864 } else
1865 stat_cnt++; /* until 1s */
1866
1867 mutex_exit(&sc->sc_mflock);
1868 delay(drv_usectohz(delay_aux_thread));
1869 mutex_enter(&sc->sc_mflock);
1870 }
1871 sc->sc_mf_thread = NULL;
1872 cv_broadcast(&sc->sc_mfthread_cv);
1873 mutex_exit(&sc->sc_mflock);
1874 }
1875
1876 static int
ipw2100_m_start(void * arg)1877 ipw2100_m_start(void *arg)
1878 {
1879 struct ipw2100_softc *sc = (struct ipw2100_softc *)arg;
1880
1881 IPW2100_DBG(IPW2100_DBG_GLD, (sc->sc_dip, CE_CONT,
1882 "ipw2100_m_start(): enter\n"));
1883
1884 /*
1885 * initialize ipw2100 hardware
1886 */
1887 (void) ipw2100_init(sc);
1888
1889 sc->sc_flags |= IPW2100_FLAG_RUNNING;
1890 /*
1891 * fix KCF bug. - workaround, need to fix it in net80211
1892 */
1893 (void) crypto_mech2id(SUN_CKM_RC4);
1894
1895 return (0);
1896 }
1897
1898 static void
ipw2100_m_stop(void * arg)1899 ipw2100_m_stop(void *arg)
1900 {
1901 struct ipw2100_softc *sc = (struct ipw2100_softc *)arg;
1902
1903 IPW2100_DBG(IPW2100_DBG_GLD, (sc->sc_dip, CE_CONT,
1904 "ipw2100_m_stop(): enter\n"));
1905
1906 ipw2100_stop(sc);
1907
1908 sc->sc_flags &= ~IPW2100_FLAG_RUNNING;
1909 }
1910
1911 static int
ipw2100_m_unicst(void * arg,const uint8_t * macaddr)1912 ipw2100_m_unicst(void *arg, const uint8_t *macaddr)
1913 {
1914 struct ipw2100_softc *sc = (struct ipw2100_softc *)arg;
1915 struct ieee80211com *ic = &sc->sc_ic;
1916 int err;
1917
1918 IPW2100_DBG(IPW2100_DBG_GLD, (sc->sc_dip, CE_CONT,
1919 "ipw2100_m_unicst(): enter\n"));
1920
1921 IPW2100_DBG(IPW2100_DBG_GLD, (sc->sc_dip, CE_CONT,
1922 "ipw2100_m_unicst(): GLD setting MAC address to "
1923 "%02x:%02x:%02x:%02x:%02x:%02x\n",
1924 macaddr[0], macaddr[1], macaddr[2],
1925 macaddr[3], macaddr[4], macaddr[5]));
1926
1927 if (!IEEE80211_ADDR_EQ(ic->ic_macaddr, macaddr)) {
1928 IEEE80211_ADDR_COPY(ic->ic_macaddr, macaddr);
1929
1930 if (sc->sc_flags & IPW2100_FLAG_RUNNING) {
1931 err = ipw2100_config(sc);
1932 if (err != DDI_SUCCESS) {
1933 IPW2100_WARN((sc->sc_dip, CE_WARN,
1934 "ipw2100_m_unicst(): "
1935 "device configuration failed\n"));
1936 goto fail;
1937 }
1938 }
1939 }
1940
1941 return (0);
1942 fail:
1943 return (EIO);
1944 }
1945
1946 static int
ipw2100_m_promisc(void * arg,boolean_t on)1947 ipw2100_m_promisc(void *arg, boolean_t on)
1948 {
1949 struct ipw2100_softc *sc = (struct ipw2100_softc *)arg;
1950 int recfg, err;
1951
1952 IPW2100_DBG(IPW2100_DBG_GLD, (sc->sc_dip, CE_CONT,
1953 "ipw2100_m_promisc(): enter. "
1954 "GLD setting promiscuous mode - %d\n", on));
1955
1956 recfg = 0;
1957 if (on)
1958 if (!(sc->if_flags & IFF_PROMISC)) {
1959 sc->if_flags |= IFF_PROMISC;
1960 recfg = 1;
1961 }
1962 else
1963 if (sc->if_flags & IFF_PROMISC) {
1964 sc->if_flags &= ~IFF_PROMISC;
1965 recfg = 1;
1966 }
1967
1968 if (recfg && (sc->sc_flags & IPW2100_FLAG_RUNNING)) {
1969 err = ipw2100_config(sc);
1970 if (err != DDI_SUCCESS) {
1971 IPW2100_WARN((sc->sc_dip, CE_WARN,
1972 "ipw2100_m_promisc(): "
1973 "device configuration failed\n"));
1974 goto fail;
1975 }
1976 }
1977
1978 return (0);
1979 fail:
1980 return (EIO);
1981 }
1982
1983 static mblk_t *
ipw2100_m_tx(void * arg,mblk_t * mp)1984 ipw2100_m_tx(void *arg, mblk_t *mp)
1985 {
1986 struct ipw2100_softc *sc = (struct ipw2100_softc *)arg;
1987 struct ieee80211com *ic = &sc->sc_ic;
1988 mblk_t *next;
1989
1990 /*
1991 * No data frames go out unless we're associated; this
1992 * should not happen as the 802.11 layer does not enable
1993 * the xmit queue until we enter the RUN state.
1994 */
1995 if (ic->ic_state != IEEE80211_S_RUN) {
1996 IPW2100_DBG(IPW2100_DBG_GLD, (sc->sc_dip, CE_CONT,
1997 "ipw2100_m_tx(): discard msg, ic_state = %u\n",
1998 ic->ic_state));
1999 freemsgchain(mp);
2000 return (NULL);
2001 }
2002
2003 while (mp != NULL) {
2004 next = mp->b_next;
2005 mp->b_next = NULL;
2006 if (ipw2100_send(ic, mp, IEEE80211_FC0_TYPE_DATA) !=
2007 DDI_SUCCESS) {
2008 mp->b_next = next;
2009 break;
2010 }
2011 mp = next;
2012 }
2013 return (mp);
2014 }
2015
2016 /* ARGSUSED */
2017 static int
ipw2100_send(ieee80211com_t * ic,mblk_t * mp,uint8_t type)2018 ipw2100_send(ieee80211com_t *ic, mblk_t *mp, uint8_t type)
2019 {
2020 struct ipw2100_softc *sc = (struct ipw2100_softc *)ic;
2021 struct ieee80211_node *in;
2022 struct ieee80211_frame wh, *wh_tmp;
2023 struct ieee80211_key *k;
2024 uint8_t *hdat;
2025 mblk_t *m0, *m;
2026 size_t cnt, off;
2027 struct ipw2100_bd *txbd[2];
2028 struct ipw2100_txb *txbuf;
2029 struct dma_region *dr;
2030 struct ipw2100_hdr *h;
2031 uint32_t idx, bidx;
2032 int err;
2033
2034 ASSERT(mp->b_next == NULL);
2035
2036 m0 = NULL;
2037 m = NULL;
2038 err = DDI_SUCCESS;
2039
2040 IPW2100_DBG(IPW2100_DBG_GLD, (sc->sc_dip, CE_CONT,
2041 "ipw2100_send(): enter\n"));
2042
2043 if ((type & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_DATA) {
2044 /*
2045 * it is impossible to send non-data 802.11 frame in current
2046 * ipw driver. Therefore, drop the package
2047 */
2048 freemsg(mp);
2049 err = DDI_SUCCESS;
2050 goto fail0;
2051 }
2052
2053 mutex_enter(&sc->sc_tx_lock);
2054
2055 /*
2056 * need 2 descriptors: 1 for SEND cmd parameter header,
2057 * and the other for payload, i.e., 802.11 frame including 802.11
2058 * frame header
2059 */
2060 if (sc->sc_tx_free < 2) {
2061 mutex_enter(&sc->sc_resched_lock);
2062 IPW2100_DBG(IPW2100_DBG_RING, (sc->sc_dip, CE_WARN,
2063 "ipw2100_send(): no enough descriptors(%d)\n",
2064 sc->sc_tx_free));
2065 ic->ic_stats.is_tx_nobuf++; /* no enough buffer */
2066 sc->sc_flags |= IPW2100_FLAG_TX_SCHED;
2067 err = DDI_FAILURE;
2068 mutex_exit(&sc->sc_resched_lock);
2069 goto fail1;
2070 }
2071 IPW2100_DBG(IPW2100_DBG_RING, (sc->sc_dip, CE_CONT,
2072 "ipw2100_send(): tx-free=%d,tx-curr=%d\n",
2073 sc->sc_tx_free, sc->sc_tx_cur));
2074
2075 wh_tmp = (struct ieee80211_frame *)mp->b_rptr;
2076 in = ieee80211_find_txnode(ic, wh_tmp->i_addr1);
2077 if (in == NULL) { /* can not find tx node, drop the package */
2078 freemsg(mp);
2079 err = DDI_SUCCESS;
2080 goto fail1;
2081 }
2082 in->in_inact = 0;
2083 (void) ieee80211_encap(ic, mp, in);
2084 ieee80211_free_node(in);
2085
2086 if (wh_tmp->i_fc[1] & IEEE80211_FC1_WEP) {
2087 /*
2088 * it is very bad that ieee80211_crypto_encap can only accept a
2089 * single continuous buffer.
2090 */
2091 /*
2092 * allocate 32 more bytes is to be compatible with further
2093 * ieee802.11i standard.
2094 */
2095 m = allocb(msgdsize(mp) + 32, BPRI_MED);
2096 if (m == NULL) { /* can not alloc buf, drop this package */
2097 IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT,
2098 "ipw2100_send(): msg allocation failed\n"));
2099
2100 freemsg(mp);
2101
2102 err = DDI_SUCCESS;
2103 goto fail1;
2104 }
2105 off = 0;
2106 m0 = mp;
2107 while (m0) {
2108 cnt = MBLKL(m0);
2109 if (cnt) {
2110 (void) memcpy(m->b_rptr + off, m0->b_rptr, cnt);
2111 off += cnt;
2112 }
2113 m0 = m0->b_cont;
2114 }
2115 m->b_wptr += off;
2116 IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT,
2117 "ipw2100_send(): "
2118 "Encrypting 802.11 frame started, %d, %d\n",
2119 msgdsize(mp), MBLKL(mp)));
2120 k = ieee80211_crypto_encap(ic, m);
2121 if (k == NULL) { /* can not get the key, drop packages */
2122 IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT,
2123 "ipw2100_send(): "
2124 "Encrypting 802.11 frame failed\n"));
2125
2126 freemsg(mp);
2127 err = DDI_SUCCESS;
2128 goto fail2;
2129 }
2130 IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT,
2131 "ipw2100_send(): "
2132 "Encrypting 802.11 frame finished, %d, %d, k=0x%08x\n",
2133 msgdsize(mp), MBLKL(mp), k->wk_flags));
2134 }
2135
2136 /*
2137 * header descriptor
2138 */
2139 idx = sc->sc_tx_cur;
2140 txbd[0] = &sc->sc_txbd[idx];
2141 if ((idx & 1) == 0)
2142 bidx = idx / 2;
2143 sc->sc_tx_cur = RING_FORWARD(sc->sc_tx_cur, 1, IPW2100_NUM_TXBD);
2144 sc->sc_tx_free--;
2145
2146 /*
2147 * payload descriptor
2148 */
2149 idx = sc->sc_tx_cur;
2150 txbd[1] = &sc->sc_txbd[idx];
2151 if ((idx & 1) == 0)
2152 bidx = idx / 2;
2153 sc->sc_tx_cur = RING_FORWARD(sc->sc_tx_cur, 1, IPW2100_NUM_TXBD);
2154 sc->sc_tx_free--;
2155
2156 /*
2157 * one buffer, SEND cmd header and payload buffer
2158 */
2159 txbuf = sc->sc_txbufs[bidx];
2160 dr = &sc->sc_dma_txbufs[bidx];
2161
2162 /*
2163 * extract 802.11 header from message, fill wh from m0
2164 */
2165 hdat = (uint8_t *)&wh;
2166 off = 0;
2167 if (m)
2168 m0 = m;
2169 else
2170 m0 = mp;
2171 while (off < sizeof (wh)) {
2172 cnt = MBLKL(m0);
2173 if (cnt > (sizeof (wh) - off))
2174 cnt = sizeof (wh) - off;
2175 if (cnt) {
2176 (void) memcpy(hdat + off, m0->b_rptr, cnt);
2177 off += cnt;
2178 m0->b_rptr += cnt;
2179 }
2180 else
2181 m0 = m0->b_cont;
2182 }
2183
2184 /*
2185 * prepare SEND cmd header
2186 */
2187 h = &txbuf->txb_hdr;
2188 h->type = LE_32(IPW2100_CMD_SEND);
2189 h->subtype = LE_32(0);
2190 h->encrypted = ic->ic_flags & IEEE80211_F_PRIVACY ? 1 : 0;
2191 h->encrypt = 0;
2192 h->keyidx = 0;
2193 h->keysz = 0;
2194 h->fragsz = LE_16(0);
2195 IEEE80211_ADDR_COPY(h->saddr, wh.i_addr2);
2196 if (ic->ic_opmode == IEEE80211_M_STA)
2197 IEEE80211_ADDR_COPY(h->daddr, wh.i_addr3);
2198 else
2199 IEEE80211_ADDR_COPY(h->daddr, wh.i_addr1);
2200
2201 /*
2202 * extract payload from message into tx data buffer
2203 */
2204 off = 0;
2205 while (m0) {
2206 cnt = MBLKL(m0);
2207 if (cnt) {
2208 (void) memcpy(&txbuf->txb_dat[off], m0->b_rptr, cnt);
2209 off += cnt;
2210 }
2211 m0 = m0->b_cont;
2212 }
2213
2214 /*
2215 * fill SEND cmd header descriptor
2216 */
2217 txbd[0]->phyaddr = LE_32(dr->dr_pbase +
2218 OFFSETOF(struct ipw2100_txb, txb_hdr));
2219 txbd[0]->len = LE_32(sizeof (struct ipw2100_hdr));
2220 txbd[0]->flags = IPW2100_BD_FLAG_TX_FRAME_802_3 |
2221 IPW2100_BD_FLAG_TX_NOT_LAST_FRAGMENT;
2222 txbd[0]->nfrag = 2;
2223 /*
2224 * fill payload descriptor
2225 */
2226 txbd[1]->phyaddr = LE_32(dr->dr_pbase +
2227 OFFSETOF(struct ipw2100_txb, txb_dat[0]));
2228 txbd[1]->len = LE_32(off);
2229 txbd[1]->flags = IPW2100_BD_FLAG_TX_FRAME_802_3 |
2230 IPW2100_BD_FLAG_TX_LAST_FRAGMENT;
2231 txbd[1]->nfrag = 0;
2232
2233 /*
2234 * dma sync
2235 */
2236 (void) ddi_dma_sync(dr->dr_hnd, 0, sizeof (struct ipw2100_txb),
2237 DDI_DMA_SYNC_FORDEV);
2238 (void) ddi_dma_sync(sc->sc_dma_txbd.dr_hnd,
2239 (txbd[0] - sc->sc_txbd) * sizeof (struct ipw2100_bd),
2240 sizeof (struct ipw2100_bd), DDI_DMA_SYNC_FORDEV);
2241 /*
2242 * since txbd[1] may not be successive to txbd[0] due to the ring
2243 * organization, another dma_sync is needed to simplify the logic
2244 */
2245 (void) ddi_dma_sync(sc->sc_dma_txbd.dr_hnd,
2246 (txbd[1] - sc->sc_txbd) * sizeof (struct ipw2100_bd),
2247 sizeof (struct ipw2100_bd), DDI_DMA_SYNC_FORDEV);
2248 /*
2249 * update txcur
2250 */
2251 ipw2100_csr_put32(sc, IPW2100_CSR_TX_WRITE_INDEX, sc->sc_tx_cur);
2252
2253 if (mp) /* success, free the original message */
2254 freemsg(mp);
2255 fail2:
2256 if (m)
2257 freemsg(m);
2258 fail1:
2259 mutex_exit(&sc->sc_tx_lock);
2260 fail0:
2261 IPW2100_DBG(IPW2100_DBG_GLD, (sc->sc_dip, CE_CONT,
2262 "ipw2100_send(): exit - err=%d\n", err));
2263
2264 return (err);
2265 }
2266
2267 /*
2268 * IOCTL Handler
2269 */
2270 #define IEEE80211_IOCTL_REQUIRED (1)
2271 #define IEEE80211_IOCTL_NOT_REQUIRED (0)
2272 static void
ipw2100_m_ioctl(void * arg,queue_t * q,mblk_t * m)2273 ipw2100_m_ioctl(void *arg, queue_t *q, mblk_t *m)
2274 {
2275 struct ipw2100_softc *sc = (struct ipw2100_softc *)arg;
2276 struct ieee80211com *ic = &sc->sc_ic;
2277 int err;
2278
2279 IPW2100_DBG(IPW2100_DBG_GLD, (sc->sc_dip, CE_CONT,
2280 "ipw2100_m_ioctl(): enter\n"));
2281
2282 /*
2283 * check whether or not need to handle this in net80211
2284 */
2285 if (ipw2100_ioctl(sc, q, m) == IEEE80211_IOCTL_NOT_REQUIRED)
2286 return; /* succes or fail */
2287
2288 err = ieee80211_ioctl(ic, q, m);
2289 if (err == ENETRESET) {
2290 if (sc->sc_flags & IPW2100_FLAG_RUNNING) {
2291 (void) ipw2100_m_start(sc);
2292 (void) ieee80211_new_state(ic,
2293 IEEE80211_S_SCAN, -1);
2294 }
2295 }
2296 if (err == ERESTART) {
2297 if (sc->sc_flags & IPW2100_FLAG_RUNNING)
2298 (void) ipw2100_chip_reset(sc);
2299 }
2300 }
2301
2302 static int
ipw2100_ioctl(struct ipw2100_softc * sc,queue_t * q,mblk_t * m)2303 ipw2100_ioctl(struct ipw2100_softc *sc, queue_t *q, mblk_t *m)
2304 {
2305 struct iocblk *iocp;
2306 uint32_t len, ret, cmd;
2307 mblk_t *m0;
2308 boolean_t need_privilege;
2309 boolean_t need_net80211;
2310
2311 if (MBLKL(m) < sizeof (struct iocblk)) {
2312 IPW2100_DBG(IPW2100_DBG_IOCTL, (sc->sc_dip, CE_CONT,
2313 "ipw2100_ioctl(): ioctl buffer too short, %u\n",
2314 MBLKL(m)));
2315 miocnak(q, m, 0, EINVAL);
2316 return (IEEE80211_IOCTL_NOT_REQUIRED);
2317 }
2318
2319 /*
2320 * Validate the command
2321 */
2322 iocp = (struct iocblk *)(uintptr_t)m->b_rptr;
2323 iocp->ioc_error = 0;
2324 cmd = iocp->ioc_cmd;
2325 need_privilege = B_TRUE;
2326 switch (cmd) {
2327 case WLAN_SET_PARAM:
2328 case WLAN_COMMAND:
2329 break;
2330 case WLAN_GET_PARAM:
2331 need_privilege = B_FALSE;
2332 break;
2333 default:
2334 IPW2100_DBG(IPW2100_DBG_IOCTL, (sc->sc_dip, CE_CONT,
2335 "ieee80211_ioctl(): unknown cmd 0x%x", cmd));
2336 miocnak(q, m, 0, EINVAL);
2337 return (IEEE80211_IOCTL_NOT_REQUIRED);
2338 }
2339
2340 if (need_privilege && (ret = secpolicy_dl_config(iocp->ioc_cr)) != 0) {
2341 miocnak(q, m, 0, ret);
2342 return (IEEE80211_IOCTL_NOT_REQUIRED);
2343 }
2344
2345 /*
2346 * sanity check
2347 */
2348 m0 = m->b_cont;
2349 if (iocp->ioc_count == 0 || iocp->ioc_count < sizeof (wldp_t) ||
2350 m0 == NULL) {
2351 miocnak(q, m, 0, EINVAL);
2352 return (IEEE80211_IOCTL_NOT_REQUIRED);
2353 }
2354 /*
2355 * assuming single data block
2356 */
2357 if (m0->b_cont) {
2358 freemsg(m0->b_cont);
2359 m0->b_cont = NULL;
2360 }
2361
2362 need_net80211 = B_FALSE;
2363 ret = ipw2100_getset(sc, m0, cmd, &need_net80211);
2364 if (!need_net80211) {
2365 len = msgdsize(m0);
2366
2367 IPW2100_DBG(IPW2100_DBG_IOCTL, (sc->sc_dip, CE_CONT,
2368 "ipw2100_ioctl(): go to call miocack with "
2369 "ret = %d, len = %d\n", ret, len));
2370 miocack(q, m, len, ret);
2371 return (IEEE80211_IOCTL_NOT_REQUIRED);
2372 }
2373
2374 /*
2375 * IEEE80211_IOCTL_REQUIRED - need net80211 handle
2376 */
2377 return (IEEE80211_IOCTL_REQUIRED);
2378 }
2379
2380 static int
ipw2100_getset(struct ipw2100_softc * sc,mblk_t * m,uint32_t cmd,boolean_t * need_net80211)2381 ipw2100_getset(struct ipw2100_softc *sc, mblk_t *m, uint32_t cmd,
2382 boolean_t *need_net80211)
2383 {
2384 wldp_t *infp, *outfp;
2385 uint32_t id;
2386 int ret; /* IEEE80211_IOCTL - handled by net80211 */
2387
2388 infp = (wldp_t *)(uintptr_t)m->b_rptr;
2389 outfp = (wldp_t *)(uintptr_t)m->b_rptr;
2390 outfp->wldp_result = WL_NOTSUPPORTED;
2391
2392 id = infp->wldp_id;
2393 IPW2100_DBG(IPW2100_DBG_IOCTL, (sc->sc_dip, CE_CONT,
2394 "ipw2100_getset(): id = 0x%x\n", id));
2395 switch (id) {
2396 /*
2397 * which is not supported by net80211, so it
2398 * has to be handled from driver side
2399 */
2400 case WL_RADIO:
2401 ret = ipw_wificfg_radio(sc, cmd, outfp);
2402 break;
2403 /*
2404 * so far, drier doesn't support fix-rates
2405 */
2406 case WL_DESIRED_RATES:
2407 ret = ipw_wificfg_desrates(outfp);
2408 break;
2409 /*
2410 * current net80211 implementation clears the bssid while
2411 * this command received, which will result in the all zero
2412 * mac address for scan'ed AP which is just disconnected.
2413 * This is a workaround solution until net80211 find a
2414 * better method.
2415 */
2416 case WL_DISASSOCIATE:
2417 ret = ipw_wificfg_disassoc(sc, outfp);
2418 break;
2419 default:
2420 /*
2421 * The wifi IOCTL net80211 supported:
2422 * case WL_ESSID:
2423 * case WL_BSSID:
2424 * case WL_WEP_KEY_TAB:
2425 * case WL_WEP_KEY_ID:
2426 * case WL_AUTH_MODE:
2427 * case WL_ENCRYPTION:
2428 * case WL_BSS_TYPE:
2429 * case WL_ESS_LIST:
2430 * case WL_LINKSTATUS:
2431 * case WL_RSSI:
2432 * case WL_SCAN:
2433 * case WL_LOAD_DEFAULTS:
2434 */
2435
2436 /*
2437 * When radio is off, need to ignore all ioctl. What need to
2438 * do is to check radio status firstly. If radio is ON, pass
2439 * it to net80211, otherwise, return to upper layer directly.
2440 *
2441 * Considering the WL_SUCCESS also means WL_CONNECTED for
2442 * checking linkstatus, one exception for WL_LINKSTATUS is to
2443 * let net80211 handle it.
2444 */
2445 if ((ipw2100_get_radio(sc) == 0) &&
2446 (id != WL_LINKSTATUS)) {
2447
2448 IPW2100_REPORT((sc->sc_dip, CE_WARN,
2449 "ipw: RADIO is OFF\n"));
2450
2451 outfp->wldp_length = WIFI_BUF_OFFSET;
2452 outfp->wldp_result = WL_SUCCESS;
2453 ret = 0;
2454 break;
2455 }
2456
2457 *need_net80211 = B_TRUE; /* let net80211 do the rest */
2458 return (0);
2459 }
2460 /*
2461 * we will overwrite everything
2462 */
2463 m->b_wptr = m->b_rptr + outfp->wldp_length;
2464
2465 return (ret);
2466 }
2467
2468 /*
2469 * Call back functions for get/set proporty
2470 */
2471 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)2472 ipw2100_m_getprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
2473 uint_t wldp_length, void *wldp_buf)
2474 {
2475 struct ipw2100_softc *sc = (struct ipw2100_softc *)arg;
2476 struct ieee80211com *ic = &sc->sc_ic;
2477 int err = 0;
2478
2479 switch (wldp_pr_num) {
2480 /* mac_prop_id */
2481 case MAC_PROP_WL_DESIRED_RATES:
2482 IPW2100_DBG(IPW2100_DBG_BRUSSELS, (sc->sc_dip, CE_CONT,
2483 "ipw2100_m_getprop(): Not Support DESIRED_RATES\n"));
2484 break;
2485 case MAC_PROP_WL_RADIO:
2486 *(wl_linkstatus_t *)wldp_buf = ipw2100_get_radio(sc);
2487 break;
2488 default:
2489 /* go through net80211 */
2490 err = ieee80211_getprop(ic, pr_name, wldp_pr_num,
2491 wldp_length, wldp_buf);
2492 break;
2493 }
2494
2495 return (err);
2496 }
2497
2498 static void
ipw2100_m_propinfo(void * arg,const char * pr_name,mac_prop_id_t wldp_pr_num,mac_prop_info_handle_t prh)2499 ipw2100_m_propinfo(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
2500 mac_prop_info_handle_t prh)
2501 {
2502 struct ipw2100_softc *sc = (struct ipw2100_softc *)arg;
2503 struct ieee80211com *ic = &sc->sc_ic;
2504
2505 ieee80211_propinfo(ic, pr_name, wldp_pr_num, prh);
2506
2507 }
2508
2509 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)2510 ipw2100_m_setprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
2511 uint_t wldp_length, const void *wldp_buf)
2512 {
2513 struct ipw2100_softc *sc = (struct ipw2100_softc *)arg;
2514 struct ieee80211com *ic = &sc->sc_ic;
2515 int err;
2516
2517 switch (wldp_pr_num) {
2518 /* mac_prop_id */
2519 case MAC_PROP_WL_DESIRED_RATES:
2520 IPW2100_DBG(IPW2100_DBG_BRUSSELS, (sc->sc_dip, CE_CONT,
2521 "ipw2100_m_setprop(): Not Support DESIRED_RATES\n"));
2522 err = ENOTSUP;
2523 break;
2524 case MAC_PROP_WL_RADIO:
2525 IPW2100_DBG(IPW2100_DBG_BRUSSELS, (sc->sc_dip, CE_CONT,
2526 "ipw2100_m_setprop(): Not Support RADIO\n"));
2527 err = ENOTSUP;
2528 break;
2529 default:
2530 /* go through net80211 */
2531 err = ieee80211_setprop(ic, pr_name, wldp_pr_num, wldp_length,
2532 wldp_buf);
2533 break;
2534 }
2535
2536 if (err == ENETRESET) {
2537 if (sc->sc_flags & IPW2100_FLAG_RUNNING) {
2538 (void) ipw2100_m_start(sc);
2539 (void) ieee80211_new_state(ic,
2540 IEEE80211_S_SCAN, -1);
2541 }
2542
2543 err = 0;
2544 }
2545
2546 return (err);
2547 }
2548
2549 static int
ipw_wificfg_radio(struct ipw2100_softc * sc,uint32_t cmd,wldp_t * outfp)2550 ipw_wificfg_radio(struct ipw2100_softc *sc, uint32_t cmd, wldp_t *outfp)
2551 {
2552 uint32_t ret = ENOTSUP;
2553
2554 switch (cmd) {
2555 case WLAN_GET_PARAM:
2556 *(wl_linkstatus_t *)(outfp->wldp_buf) = ipw2100_get_radio(sc);
2557 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_linkstatus_t);
2558 outfp->wldp_result = WL_SUCCESS;
2559 ret = 0; /* command sucess */
2560 break;
2561 case WLAN_SET_PARAM:
2562 default:
2563 break;
2564 }
2565 return (ret);
2566 }
2567
2568 static int
ipw_wificfg_desrates(wldp_t * outfp)2569 ipw_wificfg_desrates(wldp_t *outfp)
2570 {
2571 /*
2572 * return success, but with result NOTSUPPORTED
2573 */
2574 outfp->wldp_length = WIFI_BUF_OFFSET;
2575 outfp->wldp_result = WL_NOTSUPPORTED;
2576 return (0);
2577 }
2578
2579 static int
ipw_wificfg_disassoc(struct ipw2100_softc * sc,wldp_t * outfp)2580 ipw_wificfg_disassoc(struct ipw2100_softc *sc, wldp_t *outfp)
2581 {
2582 struct ieee80211com *ic = &sc->sc_ic;
2583
2584 /*
2585 * init the state
2586 */
2587 if (ic->ic_state != IEEE80211_S_INIT) {
2588 (void) ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
2589 }
2590
2591 /*
2592 * return success always
2593 */
2594 outfp->wldp_length = WIFI_BUF_OFFSET;
2595 outfp->wldp_result = WL_SUCCESS;
2596 return (0);
2597 }
2598 /* End of IOCTL Handler */
2599
2600 static void
ipw2100_fix_channel(struct ieee80211com * ic,mblk_t * m)2601 ipw2100_fix_channel(struct ieee80211com *ic, mblk_t *m)
2602 {
2603 struct ieee80211_frame *wh;
2604 uint8_t subtype;
2605 uint8_t *frm, *efrm;
2606
2607 wh = (struct ieee80211_frame *)m->b_rptr;
2608
2609 if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_MGT)
2610 return;
2611
2612 subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
2613
2614 if (subtype != IEEE80211_FC0_SUBTYPE_BEACON &&
2615 subtype != IEEE80211_FC0_SUBTYPE_PROBE_RESP)
2616 return;
2617
2618 /*
2619 * assume the message contains only 1 block
2620 */
2621 frm = (uint8_t *)(wh + 1);
2622 efrm = (uint8_t *)m->b_wptr;
2623 frm += 12; /* skip tstamp, bintval and capinfo fields */
2624 while (frm < efrm) {
2625 if (*frm == IEEE80211_ELEMID_DSPARMS) {
2626 #if IEEE80211_CHAN_MAX < 255
2627 if (frm[2] <= IEEE80211_CHAN_MAX)
2628 #endif
2629 {
2630 ic->ic_curchan = &ic->ic_sup_channels[frm[2]];
2631 }
2632 }
2633 frm += frm[1] + 2;
2634 }
2635 }
2636
2637 static void
ipw2100_rcvpkt(struct ipw2100_softc * sc,struct ipw2100_status * status,uint8_t * rxbuf)2638 ipw2100_rcvpkt(struct ipw2100_softc *sc, struct ipw2100_status *status,
2639 uint8_t *rxbuf)
2640 {
2641 struct ieee80211com *ic = &sc->sc_ic;
2642 mblk_t *m;
2643 struct ieee80211_frame *wh = (struct ieee80211_frame *)rxbuf;
2644 struct ieee80211_node *in;
2645 uint32_t rlen;
2646
2647 in = ieee80211_find_rxnode(ic, wh);
2648 rlen = LE_32(status->len);
2649 m = allocb(rlen, BPRI_MED);
2650 if (m) {
2651 (void) memcpy(m->b_wptr, rxbuf, rlen);
2652 m->b_wptr += rlen;
2653 if (ic->ic_state == IEEE80211_S_SCAN)
2654 ipw2100_fix_channel(ic, m);
2655 (void) ieee80211_input(ic, m, in, status->rssi, 0);
2656 } else
2657 IPW2100_WARN((sc->sc_dip, CE_WARN,
2658 "ipw2100_rcvpkg(): cannot allocate receive message(%u)\n",
2659 LE_32(status->len)));
2660 ieee80211_free_node(in);
2661 }
2662
2663 static uint_t
ipw2100_intr(caddr_t arg)2664 ipw2100_intr(caddr_t arg)
2665 {
2666 struct ipw2100_softc *sc = (struct ipw2100_softc *)(uintptr_t)arg;
2667 uint32_t ireg, ridx, len, i;
2668 struct ieee80211com *ic = &sc->sc_ic;
2669 struct ipw2100_status *status;
2670 uint8_t *rxbuf;
2671 struct dma_region *dr;
2672 uint32_t state;
2673 #if DEBUG
2674 struct ipw2100_bd *rxbd;
2675 #endif
2676
2677 if (sc->sc_suspended)
2678 return (DDI_INTR_UNCLAIMED);
2679
2680 ireg = ipw2100_csr_get32(sc, IPW2100_CSR_INTR);
2681
2682 if (!(ireg & IPW2100_INTR_MASK_ALL))
2683 return (DDI_INTR_UNCLAIMED);
2684
2685 /*
2686 * mask all interrupts
2687 */
2688 ipw2100_csr_put32(sc, IPW2100_CSR_INTR_MASK, 0);
2689
2690 /*
2691 * acknowledge all fired interrupts
2692 */
2693 ipw2100_csr_put32(sc, IPW2100_CSR_INTR, ireg);
2694
2695 IPW2100_DBG(IPW2100_DBG_INT, (sc->sc_dip, CE_CONT,
2696 "ipw2100_intr(): interrupt is fired. int=0x%08x\n", ireg));
2697
2698 if (ireg & IPW2100_INTR_MASK_ERR) {
2699
2700 IPW2100_DBG(IPW2100_DBG_FATAL, (sc->sc_dip, CE_CONT,
2701 "ipw2100_intr(): interrupt is fired, MASK = 0x%08x\n",
2702 ireg));
2703
2704 /*
2705 * inform mfthread to recover hw error
2706 */
2707 mutex_enter(&sc->sc_mflock);
2708 sc->sc_flags |= IPW2100_FLAG_HW_ERR_RECOVER;
2709 mutex_exit(&sc->sc_mflock);
2710
2711 goto enable_interrupt;
2712 }
2713
2714 /*
2715 * FW intr
2716 */
2717 if (ireg & IPW2100_INTR_FW_INIT_DONE) {
2718 mutex_enter(&sc->sc_ilock);
2719 sc->sc_flags |= IPW2100_FLAG_FW_INITED;
2720 cv_signal(&sc->sc_fw_cond);
2721 mutex_exit(&sc->sc_ilock);
2722 }
2723
2724 /*
2725 * RX intr
2726 */
2727 if (ireg & IPW2100_INTR_RX_TRANSFER) {
2728 ridx = ipw2100_csr_get32(sc,
2729 IPW2100_CSR_RX_READ_INDEX);
2730
2731 for (; sc->sc_rx_cur != ridx;
2732 sc->sc_rx_cur = RING_FORWARD(
2733 sc->sc_rx_cur, 1, IPW2100_NUM_RXBD)) {
2734
2735 i = sc->sc_rx_cur;
2736 status = &sc->sc_status[i];
2737 rxbuf = &sc->sc_rxbufs[i]->rxb_dat[0];
2738 dr = &sc->sc_dma_rxbufs[i];
2739
2740 /*
2741 * sync
2742 */
2743 (void) ddi_dma_sync(sc->sc_dma_status.dr_hnd,
2744 i * sizeof (struct ipw2100_status),
2745 sizeof (struct ipw2100_status),
2746 DDI_DMA_SYNC_FORKERNEL);
2747 (void) ddi_dma_sync(sc->sc_dma_rxbd.dr_hnd,
2748 i * sizeof (struct ipw2100_bd),
2749 sizeof (struct ipw2100_bd),
2750 DDI_DMA_SYNC_FORKERNEL);
2751 (void) ddi_dma_sync(dr->dr_hnd, 0,
2752 sizeof (struct ipw2100_rxb),
2753 DDI_DMA_SYNC_FORKERNEL);
2754 IPW2100_DBG(IPW2100_DBG_INT, (sc->sc_dip, CE_CONT,
2755 "ipw2100_intr(): status code=0x%04x, len=0x%08x, "
2756 "flags=0x%02x, rssi=%02x\n",
2757 LE_16(status->code), LE_32(status->len),
2758 status->flags, status->rssi));
2759 #if DEBUG
2760 rxbd = &sc->sc_rxbd[i];
2761 IPW2100_DBG(IPW2100_DBG_INT, (sc->sc_dip, CE_CONT,
2762 "ipw2100_intr(): rxbd,phyaddr=0x%08x, len=0x%08x, "
2763 "flags=0x%02x,nfrag=%02x\n",
2764 LE_32(rxbd->phyaddr), LE_32(rxbd->len),
2765 rxbd->flags, rxbd->nfrag));
2766 #endif
2767 switch (LE_16(status->code) & 0x0f) {
2768 /*
2769 * command complete response
2770 */
2771 case IPW2100_STATUS_CODE_COMMAND:
2772 mutex_enter(&sc->sc_ilock);
2773 sc->sc_done = 1;
2774 cv_signal(&sc->sc_cmd_cond);
2775 mutex_exit(&sc->sc_ilock);
2776 break;
2777 /*
2778 * change state
2779 */
2780 case IPW2100_STATUS_CODE_NEWSTATE:
2781 state = LE_32(* ((uint32_t *)(uintptr_t)rxbuf));
2782 IPW2100_DBG(IPW2100_DBG_INT,
2783 (sc->sc_dip, CE_CONT,
2784 "ipw2100_intr(): newstate,state=0x%x\n",
2785 state));
2786
2787 switch (state) {
2788 case IPW2100_STATE_ASSOCIATED:
2789 ieee80211_new_state(ic,
2790 IEEE80211_S_RUN, -1);
2791 break;
2792 case IPW2100_STATE_ASSOCIATION_LOST:
2793 case IPW2100_STATE_DISABLED:
2794 ieee80211_new_state(ic,
2795 IEEE80211_S_INIT, -1);
2796 break;
2797 /*
2798 * When radio is OFF, need a better
2799 * scan approach to ensure scan
2800 * result correct.
2801 */
2802 case IPW2100_STATE_RADIO_DISABLED:
2803 IPW2100_REPORT((sc->sc_dip, CE_WARN,
2804 "ipw2100_intr(): RADIO is OFF\n"));
2805 ipw2100_stop(sc);
2806 break;
2807 case IPW2100_STATE_SCAN_COMPLETE:
2808 ieee80211_cancel_scan(ic);
2809 break;
2810 case IPW2100_STATE_SCANNING:
2811 if (ic->ic_state != IEEE80211_S_RUN)
2812 ieee80211_new_state(ic,
2813 IEEE80211_S_SCAN, -1);
2814 ic->ic_flags |= IEEE80211_F_SCAN;
2815
2816 break;
2817 default:
2818 break;
2819 }
2820 break;
2821 case IPW2100_STATUS_CODE_DATA_802_11:
2822 case IPW2100_STATUS_CODE_DATA_802_3:
2823 ipw2100_rcvpkt(sc, status, rxbuf);
2824 break;
2825 case IPW2100_STATUS_CODE_NOTIFICATION:
2826 break;
2827 default:
2828 IPW2100_WARN((sc->sc_dip, CE_WARN,
2829 "ipw2100_intr(): "
2830 "unknown status code 0x%04x\n",
2831 LE_16(status->code)));
2832 break;
2833 }
2834 }
2835 /*
2836 * write sc_rx_cur backward 1 step to RX_WRITE_INDEX
2837 */
2838 ipw2100_csr_put32(sc, IPW2100_CSR_RX_WRITE_INDEX,
2839 RING_BACKWARD(sc->sc_rx_cur, 1, IPW2100_NUM_RXBD));
2840 }
2841
2842 /*
2843 * TX intr
2844 */
2845 if (ireg & IPW2100_INTR_TX_TRANSFER) {
2846 mutex_enter(&sc->sc_tx_lock);
2847 ridx = ipw2100_csr_get32(sc, IPW2100_CSR_TX_READ_INDEX);
2848 len = RING_FLEN(RING_FORWARD(sc->sc_tx_cur,
2849 sc->sc_tx_free, IPW2100_NUM_TXBD),
2850 ridx, IPW2100_NUM_TXBD);
2851 sc->sc_tx_free += len;
2852 IPW2100_DBG(IPW2100_DBG_INT, (sc->sc_dip, CE_CONT,
2853 "ipw2100_intr(): len=%d\n", len));
2854 mutex_exit(&sc->sc_tx_lock);
2855
2856 mutex_enter(&sc->sc_resched_lock);
2857 if (len > 1 && (sc->sc_flags & IPW2100_FLAG_TX_SCHED)) {
2858 sc->sc_flags &= ~IPW2100_FLAG_TX_SCHED;
2859 mac_tx_update(ic->ic_mach);
2860 }
2861 mutex_exit(&sc->sc_resched_lock);
2862 }
2863
2864 enable_interrupt:
2865 /*
2866 * enable all interrupts
2867 */
2868 ipw2100_csr_put32(sc, IPW2100_CSR_INTR_MASK, IPW2100_INTR_MASK_ALL);
2869
2870 return (DDI_INTR_CLAIMED);
2871 }
2872
2873
2874 /*
2875 * Module Loading Data & Entry Points
2876 */
2877 DDI_DEFINE_STREAM_OPS(ipw2100_devops, nulldev, nulldev, ipw2100_attach,
2878 ipw2100_detach, nodev, NULL, D_MP, NULL, ipw2100_quiesce);
2879
2880 static struct modldrv ipw2100_modldrv = {
2881 &mod_driverops,
2882 ipw2100_ident,
2883 &ipw2100_devops
2884 };
2885
2886 static struct modlinkage ipw2100_modlinkage = {
2887 MODREV_1,
2888 &ipw2100_modldrv,
2889 NULL
2890 };
2891
2892 int
_init(void)2893 _init(void)
2894 {
2895 int status;
2896
2897 status = ddi_soft_state_init(&ipw2100_ssp,
2898 sizeof (struct ipw2100_softc), 1);
2899 if (status != DDI_SUCCESS)
2900 return (status);
2901
2902 mac_init_ops(&ipw2100_devops, IPW2100_DRV_NAME);
2903 status = mod_install(&ipw2100_modlinkage);
2904 if (status != DDI_SUCCESS) {
2905 mac_fini_ops(&ipw2100_devops);
2906 ddi_soft_state_fini(&ipw2100_ssp);
2907 }
2908
2909 return (status);
2910 }
2911
2912 int
_fini(void)2913 _fini(void)
2914 {
2915 int status;
2916
2917 status = mod_remove(&ipw2100_modlinkage);
2918 if (status == DDI_SUCCESS) {
2919 mac_fini_ops(&ipw2100_devops);
2920 ddi_soft_state_fini(&ipw2100_ssp);
2921 }
2922
2923 return (status);
2924 }
2925
2926 int
_info(struct modinfo * mip)2927 _info(struct modinfo *mip)
2928 {
2929 return (mod_info(&ipw2100_modlinkage, mip));
2930 }
2931