2 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
8 * Damien Bergamini <damien.bergamini@free.fr>. All rights reserved.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice unmodified, this list of conditions, and the following
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.
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
33 #include <sys/types.h>
34 #include <sys/byteorder.h>
36 #include <sys/cmn_err.h>
39 #include <sys/sunddi.h>
40 #include <sys/strsubr.h>
41 #include <sys/ethernet.h>
42 #include <inet/common.h>
46 #include <sys/stream.h>
47 #include <sys/strsun.h>
48 #include <sys/modctl.h>
49 #include <sys/devops.h>
51 #include <sys/mac_provider.h>
53 #include <sys/mac_wifi.h>
54 #include <sys/varargs.h>
55 #include <sys/policy.h>
58 #include "ipw2100_impl.h"
59 #include <inet/wifi_ioctl.h>
62 * kCF framework include files
64 #include <sys/crypto/common.h>
65 #include <sys/crypto/api.h>
67 static void *ipw2100_ssp
= NULL
;
68 static char ipw2100_ident
[] = IPW2100_DRV_DESC
;
71 * PIO access attribute for register
73 static ddi_device_acc_attr_t ipw2100_csr_accattr
= {
79 static ddi_device_acc_attr_t ipw2100_dma_accattr
= {
85 static ddi_dma_attr_t ipw2100_dma_attr
= {
87 0x0000000000000000ULL
,
88 0x00000000ffffffffULL
,
89 0x00000000ffffffffULL
,
90 0x0000000000000004ULL
,
93 0x00000000ffffffffULL
,
94 0x00000000ffffffffULL
,
100 static const struct ieee80211_rateset ipw2100_rateset_11b
= { 4,
107 extern pri_t minclsyspri
;
110 * ipw2100 specific hardware operations
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
);
130 * GLD specific operations
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
);
148 * Interrupt and Data transferring operations
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
);
156 * WiFi specific operations
158 static int ipw2100_newstate(struct ieee80211com
*ic
,
159 enum ieee80211_state state
, int arg
);
160 static void ipw2100_thread(struct ipw2100_softc
*sc
);
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
,
175 * Suspend / Resume operations
177 static int ipw2100_cpr_suspend(struct ipw2100_softc
*sc
);
178 static int ipw2100_cpr_resume(struct ipw2100_softc
*sc
);
181 * Mac Call Back entries
183 mac_callbacks_t ipw2100_m_callbacks
= {
184 MC_IOCTL
| MC_SETPROP
| MC_GETPROP
| MC_PROPINFO
,
206 #define MAX_MSG (128)
207 uint32_t ipw2100_debug
= 0;
209 * supported debug marsks:
212 * | IPW2100_DBG_TABLE
213 * | IPW2100_DBG_SOFTINT
217 * | IPW2100_DBG_IOCTL
218 * | IPW2100_DBG_HWCAP
219 * | IPW2100_DBG_STATISTIC
222 * | IPW2100_DBG_BRUSSELS
226 * global tuning parameters to work around unknown hardware issues
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 */
233 ipw2100_dbg(dev_info_t
*dip
, int level
, const char *fmt
, ...)
240 (void) vsnprintf(buf
, sizeof (buf
), fmt
, ap
);
244 instance
= ddi_get_instance(dip
);
245 cmn_err(level
, "%s%d: %s", IPW2100_DRV_NAME
, instance
, buf
);
247 cmn_err(level
, "%s: %s", IPW2100_DRV_NAME
, buf
);
254 ipw2100_attach(dev_info_t
*dip
, ddi_attach_cmd_t cmd
)
256 struct ipw2100_softc
*sc
;
257 ddi_acc_handle_t cfgh
;
259 struct ieee80211com
*ic
;
260 int instance
, err
, i
;
262 wifi_data_t wd
= { 0 };
263 mac_register_t
*macp
;
269 sc
= ddi_get_soft_state(ipw2100_ssp
, ddi_get_instance(dip
));
274 return (ipw2100_cpr_resume(sc
));
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"));
287 sc
= ddi_get_soft_state(ipw2100_ssp
, instance
);
291 * Map config spaces register
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"));
300 ddi_put8(cfgh
, (uint8_t *)(regs
+ 0x41), 0);
301 ddi_regs_map_free(&cfgh
);
304 * Map operating registers
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"));
317 err
= ipw2100_chip_reset(sc
);
318 if (err
!= DDI_SUCCESS
) {
319 IPW2100_WARN((dip
, CE_WARN
,
320 "ipw2100_attach(): reset failed\n"));
325 * Get the hw conf, including MAC address, then init all rings.
327 ipw2100_hwconf_get(sc
);
328 err
= ipw2100_ring_init(sc
);
329 if (err
!= DDI_SUCCESS
) {
330 IPW2100_WARN((dip
, CE_WARN
,
332 "unable to allocate and initialize rings\n"));
337 * Initialize mutexs and condvars
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"));
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
);
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
);
361 mutex_init(&sc
->sc_resched_lock
, "reschedule-lock", MUTEX_DRIVER
,
362 (void *) sc
->sc_iblk
);
364 * initialize the mfthread
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;
372 * Initialize the wifi part, which will be used by
376 ic
->ic_phytype
= IEEE80211_T_DS
;
377 ic
->ic_opmode
= IEEE80211_M_STA
;
378 ic
->ic_state
= IEEE80211_S_INIT
;
381 * Future, could use s/w to handle encryption: IEEE80211_C_WEP
382 * and need to add support for IEEE80211_C_IBSS
384 ic
->ic_caps
= IEEE80211_C_SHPREAMBLE
| IEEE80211_C_TXPMGT
|
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
;
397 ic
->ic_ibss_chan
= &ic
->ic_sup_channels
[0];
398 ic
->ic_xmit
= ipw2100_send
;
402 ieee80211_attach(ic
);
405 * Override 80211 default routines
407 ieee80211_media_init(ic
);
408 sc
->sc_newstate
= ic
->ic_newstate
;
409 ic
->ic_newstate
= ipw2100_newstate
;
411 * initialize default tx key
413 ic
->ic_def_txkey
= 0;
415 * Set the Authentication to AUTH_Open only.
417 sc
->sc_authmode
= IEEE80211_AUTH_OPEN
;
420 * Add the interrupt handler
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"));
431 * Initialize pointer to device specific functions
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
);
437 macp
= mac_alloc(MAC_VERSION
);
439 IPW2100_WARN((dip
, CE_WARN
,
440 "ipw2100_attach(): mac_alloc() failed\n"));
444 macp
->m_type_ident
= MAC_PLUGIN_IDENT_WIFI
;
447 macp
->m_src_addr
= ic
->ic_macaddr
;
448 macp
->m_callbacks
= &ipw2100_m_callbacks
;
450 macp
->m_max_sdu
= IEEE80211_MTU
;
452 macp
->m_pdata_size
= sizeof (wd
);
455 * Register the macp to mac
457 err
= mac_register(macp
, &ic
->ic_mach
);
459 if (err
!= DDI_SUCCESS
) {
460 IPW2100_WARN((dip
, CE_WARN
,
461 "ipw2100_attach(): mac_register() failed\n"));
466 * Create minor node of type DDI_NT_NET_WIFI
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"));
477 * Cache firmware, always return true
479 (void) ipw2100_cache_firmware(sc
);
482 * Notify link is down now
484 mac_link_update(ic
->ic_mach
, LINK_STATE_DOWN
);
487 * create the mf thread to handle the link status,
488 * recovery fatal error, etc.
490 sc
->sc_mfthread_switch
= 1;
491 if (sc
->sc_mf_thread
== NULL
)
492 sc
->sc_mf_thread
= thread_create(NULL
, 0,
493 ipw2100_thread
, sc
, 0, &p0
, TS_RUN
, minclsyspri
);
495 return (DDI_SUCCESS
);
498 ddi_remove_intr(dip
, 0, sc
->sc_iblk
);
500 ieee80211_detach(ic
);
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
);
511 ipw2100_ring_free(sc
);
513 ddi_regs_map_free(&sc
->sc_ioh
);
515 ddi_soft_state_free(ipw2100_ssp
, instance
);
521 ipw2100_detach(dev_info_t
*dip
, ddi_detach_cmd_t cmd
)
523 struct ipw2100_softc
*sc
=
524 ddi_get_soft_state(ipw2100_ssp
, ddi_get_instance(dip
));
533 return (ipw2100_cpr_suspend(sc
));
535 return (DDI_FAILURE
);
539 * Destroy the mf_thread
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)
547 mutex_exit(&sc
->sc_mflock
);
550 * Unregister from the MAC layer subsystem
552 err
= mac_unregister(sc
->sc_ic
.ic_mach
);
553 if (err
!= DDI_SUCCESS
)
556 ddi_remove_intr(dip
, 0, sc
->sc_iblk
);
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
);
573 ieee80211_detach(&sc
->sc_ic
);
575 (void) ipw2100_free_firmware(sc
);
576 ipw2100_ring_free(sc
);
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
));
582 return (DDI_SUCCESS
);
586 ipw2100_cpr_suspend(struct ipw2100_softc
*sc
)
588 IPW2100_DBG(IPW2100_DBG_INIT
, (sc
->sc_dip
, CE_CONT
,
589 "ipw2100_cpr_suspend(): enter\n"));
592 * Destroy the mf_thread
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)
600 mutex_exit(&sc
->sc_mflock
);
603 * stop the hardware; this mask all interrupts
606 sc
->sc_flags
&= ~IPW2100_FLAG_RUNNING
;
607 sc
->sc_suspended
= 1;
609 (void) ipw2100_free_firmware(sc
);
610 ipw2100_ring_free(sc
);
612 return (DDI_SUCCESS
);
616 ipw2100_cpr_resume(struct ipw2100_softc
*sc
)
618 struct ieee80211com
*ic
= &sc
->sc_ic
;
619 dev_info_t
*dip
= sc
->sc_dip
;
622 IPW2100_DBG(IPW2100_DBG_INIT
, (sc
->sc_dip
, CE_CONT
,
623 "ipw2100_cpr_resume(): enter\n"));
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
);
636 * Get the hw conf, including MAC address, then init all rings.
638 /* ipw2100_hwconf_get(sc); */
639 err
= ipw2100_ring_init(sc
);
640 if (err
!= DDI_SUCCESS
) {
641 IPW2100_WARN((dip
, CE_WARN
,
643 "unable to allocate and initialize rings\n"));
644 return (DDI_FAILURE
);
648 * Cache firmware, always return true
650 (void) ipw2100_cache_firmware(sc
);
653 * Notify link is down now
655 mac_link_update(ic
->ic_mach
, LINK_STATE_DOWN
);
658 * create the mf thread to handle the link status,
659 * recovery fatal error, etc.
661 sc
->sc_mfthread_switch
= 1;
662 if (sc
->sc_mf_thread
== NULL
)
663 sc
->sc_mf_thread
= thread_create(NULL
, 0,
664 ipw2100_thread
, sc
, 0, &p0
, TS_RUN
, minclsyspri
);
667 * enable all interrupts
669 sc
->sc_suspended
= 0;
670 ipw2100_csr_put32(sc
, IPW2100_CSR_INTR_MASK
, IPW2100_INTR_MASK_ALL
);
673 * initialize ipw2100 hardware
675 (void) ipw2100_init(sc
);
677 sc
->sc_flags
|= IPW2100_FLAG_RUNNING
;
679 return (DDI_SUCCESS
);
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
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>.
692 ipw2100_quiesce(dev_info_t
*dip
)
694 struct ipw2100_softc
*sc
=
695 ddi_get_soft_state(ipw2100_ssp
, ddi_get_instance(dip
));
698 return (DDI_FAILURE
);
701 * No more blocking is allowed while we are in the
702 * quiesce(9E) entry point.
704 sc
->sc_flags
|= IPW2100_FLAG_QUIESCED
;
707 * Disable and mask all interrupts.
710 return (DDI_SUCCESS
);
714 ipw2100_tables_init(struct ipw2100_softc
*sc
)
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
);
721 ipw2100_stop(struct ipw2100_softc
*sc
)
723 struct ieee80211com
*ic
= &sc
->sc_ic
;
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
;
729 if (!(sc
->sc_flags
& IPW2100_FLAG_QUIESCED
))
730 ieee80211_new_state(ic
, IEEE80211_S_INIT
, -1);
734 ipw2100_config(struct ipw2100_softc
*sc
)
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
;
747 switch (ic
->ic_opmode
) {
748 case IEEE80211_M_STA
:
749 case IEEE80211_M_HOSTAP
:
750 data
= LE_32(IPW2100_MODE_BSS
);
753 case IEEE80211_M_IBSS
:
754 case IEEE80211_M_AHDEMO
:
755 data
= LE_32(IPW2100_MODE_IBSS
);
759 IPW2100_DBG(IPW2100_DBG_WIFI
, (sc
->sc_dip
, CE_CONT
,
760 "ipw2100_config(): Setting mode to %u\n", LE_32(data
)));
762 err
= ipw2100_cmd(sc
, IPW2100_CMD_SET_MODE
,
763 &data
, sizeof (data
));
764 if (err
!= DDI_SUCCESS
)
768 * operation channel if IBSS or MONITOR
770 if (ic
->ic_opmode
== IEEE80211_M_IBSS
) {
772 data
= LE_32(ieee80211_chan2ieee(ic
, ic
->ic_ibss_chan
));
774 IPW2100_DBG(IPW2100_DBG_WIFI
, (sc
->sc_dip
, CE_CONT
,
775 "ipw2100_config(): Setting channel to %u\n", LE_32(data
)));
777 err
= ipw2100_cmd(sc
, IPW2100_CMD_SET_CHANNEL
,
778 &data
, sizeof (data
));
779 if (err
!= DDI_SUCCESS
)
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
,
793 if (err
!= DDI_SUCCESS
)
797 * configuration capabilities
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);
809 IPW2100_DBG(IPW2100_DBG_WIFI
, (sc
->sc_dip
, CE_CONT
,
810 "ipw2100_config(): Setting configuration to 0x%x\n",
813 err
= ipw2100_cmd(sc
, IPW2100_CMD_SET_CONFIGURATION
,
816 if (err
!= DDI_SUCCESS
)
820 * set 802.11 Tx rates
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",
826 err
= ipw2100_cmd(sc
, IPW2100_CMD_SET_BASIC_TX_RATES
,
827 &data
, sizeof (data
));
828 if (err
!= DDI_SUCCESS
)
832 * set 802.11b Tx rates
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",
838 err
= ipw2100_cmd(sc
, IPW2100_CMD_SET_TX_RATES
, &data
, sizeof (data
));
839 if (err
!= DDI_SUCCESS
)
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
)
855 if (ic
->ic_opmode
== IEEE80211_M_IBSS
) {
857 IPW2100_DBG(IPW2100_DBG_WIFI
, (sc
->sc_dip
, CE_CONT
,
858 "ipw2100_config(): Setting Tx power index to %u\n",
860 err
= ipw2100_cmd(sc
, IPW2100_CMD_SET_TX_POWER_INDEX
,
861 &data
, sizeof (data
));
862 if (err
!= DDI_SUCCESS
)
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
)
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
)
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
)
904 err
= ipw2100_cmd(sc
, IPW2100_CMD_SET_MANDATORY_BSSID
, NULL
, 0);
905 if (err
!= DDI_SUCCESS
)
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
)
922 * set security information
924 (void) memset(&sec
, 0, sizeof (sec
));
926 * use the value set to ic_bss to retrieve current sharedmode
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
,
935 if (err
!= DDI_SUCCESS
)
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)
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
)
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
)
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
)
975 * set beacon interval if IBSS or HostAP
977 if (ic
->ic_opmode
== IEEE80211_M_IBSS
||
978 ic
->ic_opmode
== IEEE80211_M_HOSTAP
) {
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",
984 err
= ipw2100_cmd(sc
, IPW2100_CMD_SET_BEACON_INTERVAL
,
985 &data
, sizeof (data
));
986 if (err
!= DDI_SUCCESS
)
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
)
1002 IPW2100_DBG(IPW2100_DBG_WIFI
, (sc
->sc_dip
, CE_CONT
,
1003 "ipw2100_config(): Enabling adapter\n"));
1005 return (ipw2100_cmd(sc
, IPW2100_CMD_ENABLE
, NULL
, 0));
1009 ipw2100_cmd(struct ipw2100_softc
*sc
, uint32_t type
, void *buf
, size_t len
)
1011 struct ipw2100_bd
*txbd
;
1016 * prepare command buffer
1018 sc
->sc_cmd
->type
= LE_32(type
);
1019 sc
->sc_cmd
->subtype
= LE_32(0);
1020 sc
->sc_cmd
->seq
= LE_32(0);
1025 (void) memcpy(sc
->sc_cmd
->data
, buf
, len
);
1026 sc
->sc_cmd
->len
= LE_32(len
);
1029 * get host & device descriptor to submit command
1031 mutex_enter(&sc
->sc_tx_lock
);
1033 IPW2100_DBG(IPW2100_DBG_RING
, (sc
->sc_dip
, CE_CONT
,
1034 "ipw2100_cmd(): tx-free=%d\n", sc
->sc_tx_free
));
1037 * command need 1 descriptor
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
);
1043 idx
= sc
->sc_tx_cur
;
1045 IPW2100_DBG(IPW2100_DBG_RING
, (sc
->sc_dip
, CE_CONT
,
1046 "ipw2100_cmd(): tx-cur=%d\n", idx
));
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
;
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
);
1068 sc
->sc_tx_cur
= RING_FORWARD(sc
->sc_tx_cur
, 1, IPW2100_NUM_TXBD
);
1070 ipw2100_csr_put32(sc
, IPW2100_CSR_TX_WRITE_INDEX
, sc
->sc_tx_cur
);
1071 mutex_exit(&sc
->sc_tx_lock
);
1074 * wait for command done
1076 clk
= drv_usectohz(1000000); /* 1 second */
1077 mutex_enter(&sc
->sc_ilock
);
1078 while (sc
->sc_done
== 0) {
1080 * pending for the response
1082 if (cv_reltimedwait(&sc
->sc_cmd_cond
, &sc
->sc_ilock
,
1083 clk
, TR_CLOCK_TICK
) < 0)
1086 mutex_exit(&sc
->sc_ilock
);
1088 IPW2100_DBG(IPW2100_DBG_RING
, (sc
->sc_dip
, CE_CONT
,
1089 "ipw2100_cmd(): cmd-done=%s\n", sc
->sc_done
? "yes" : "no"));
1091 if (sc
->sc_done
== 0)
1092 return (DDI_FAILURE
);
1094 return (DDI_SUCCESS
);
1098 ipw2100_init(struct ipw2100_softc
*sc
)
1102 IPW2100_DBG(IPW2100_DBG_INIT
, (sc
->sc_dip
, CE_CONT
,
1103 "ipw2100_init(): enter\n"));
1106 * no firmware is available, return fail directly
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
);
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"));
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"));
1135 ipw2100_master_stop(sc
);
1137 ipw2100_ring_hwsetup(sc
);
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"));
1154 ipw2100_tables_init(sc
);
1155 ipw2100_table1_put32(sc
, IPW2100_INFO_LOCK
, 0);
1158 * Hardware will be enabled after configuration
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"));
1167 delay(drv_usectohz(delay_config_stable
));
1169 return (DDI_SUCCESS
);
1178 * get hardware configurations from EEPROM embedded within chip
1181 ipw2100_hwconf_get(struct ipw2100_softc
*sc
)
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;
1201 * formatted MAC address string
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]);
1212 val
= ipw2100_rom_get16(sc
, IPW2100_ROM_CHANNEL_LIST
);
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
));
1222 val
= ipw2100_rom_get16(sc
, IPW2100_ROM_RADIO
);
1224 sc
->sc_flags
|= IPW2100_FLAG_HAS_RADIO_SWITCH
;
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",
1233 * all ipw2100 interrupts will be masked by this routine
1236 ipw2100_master_stop(struct ipw2100_softc
*sc
)
1242 * disable interrupts
1244 ipw2100_csr_put32(sc
, IPW2100_CSR_INTR_MASK
, 0);
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
)
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"));
1257 tmp
= ipw2100_csr_get32(sc
, IPW2100_CSR_RST
);
1258 ipw2100_csr_put32(sc
, IPW2100_CSR_RST
,
1259 tmp
| IPW2100_RST_PRINCETON_RESET
);
1261 sc
->sc_flags
&= ~IPW2100_FLAG_FW_INITED
;
1265 * all ipw2100 interrupts will be masked by this routine
1268 ipw2100_chip_reset(struct ipw2100_softc
*sc
)
1273 ipw2100_master_stop(sc
);
1276 * move adapter to DO state
1278 tmp
= ipw2100_csr_get32(sc
, IPW2100_CSR_CTL
);
1279 ipw2100_csr_put32(sc
, IPW2100_CSR_CTL
, tmp
| IPW2100_CTL_INIT
);
1282 * wait for clock stabilization
1284 for (ntries
= 0; ntries
< 1000; ntries
++) {
1285 if (ipw2100_csr_get32(sc
, IPW2100_CSR_CTL
)
1286 & IPW2100_CTL_CLOCK_READY
)
1291 return (DDI_FAILURE
);
1293 tmp
= ipw2100_csr_get32(sc
, IPW2100_CSR_RST
);
1294 ipw2100_csr_put32(sc
, IPW2100_CSR_RST
, tmp
| IPW2100_RST_SW_RESET
);
1298 tmp
= ipw2100_csr_get32(sc
, IPW2100_CSR_CTL
);
1299 ipw2100_csr_put32(sc
, IPW2100_CSR_CTL
, tmp
| IPW2100_CTL_INIT
);
1301 return (DDI_SUCCESS
);
1305 * get the radio status from IPW_CSR_IO, invoked by wificonfig/dladm
1308 ipw2100_get_radio(struct ipw2100_softc
*sc
)
1310 if (ipw2100_csr_get32(sc
, IPW2100_CSR_IO
) & IPW2100_IO_RADIO_DISABLED
)
1317 * This function is used to get the statistic, invoked by wificonfig/dladm
1320 ipw2100_get_statistics(struct ipw2100_softc
*sc
)
1322 struct ieee80211com
*ic
= &sc
->sc_ic
;
1323 uint32_t addr
, size
, i
;
1324 uint32_t atbl
[256], *datatbl
;
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."));
1334 ipw2100_csr_put32(sc
, IPW2100_CSR_AUTOINC_ADDR
, sc
->sc_table1_base
);
1336 size
= ipw2100_csr_get32(sc
, IPW2100_CSR_AUTOINC_DATA
);
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
);
1344 * To retrieve the statistic information into proper places. There are
1345 * lot of information.
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];
1380 ipw2100_dma_region_alloc(struct ipw2100_softc
*sc
,
1381 struct dma_region
*dr
, size_t size
, uint_t dir
, uint_t flags
)
1383 dev_info_t
*dip
= sc
->sc_dip
;
1386 IPW2100_DBG(IPW2100_DBG_DMA
, (dip
, CE_CONT
,
1387 "ipw2100_dma_region_alloc() name=%s size=%u\n",
1388 dr
->dr_name
, size
));
1390 err
= ddi_dma_alloc_handle(dip
, &ipw2100_dma_attr
, DDI_DMA_SLEEP
, NULL
,
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"));
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"));
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"));
1419 if (dr
->dr_ccnt
!= 1) {
1423 dr
->dr_pbase
= dr
->dr_cookie
.dmac_address
;
1425 IPW2100_DBG(IPW2100_DBG_DMA
, (dip
, CE_CONT
,
1426 "ipw2100_dma_region_alloc(): get physical-base=0x%08x\n",
1429 return (DDI_SUCCESS
);
1432 (void) ddi_dma_unbind_handle(dr
->dr_hnd
);
1434 ddi_dma_mem_free(&dr
->dr_acc
);
1436 ddi_dma_free_handle(&dr
->dr_hnd
);
1442 ipw2100_dma_region_free(struct dma_region
*dr
)
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
);
1450 ipw2100_ring_alloc(struct ipw2100_softc
*sc
)
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
)
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
) {
1472 ipw2100_dma_region_free(&sc
->sc_dma_txbufs
[i
]);
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
)
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
) {
1495 ipw2100_dma_region_free(&sc
->sc_dma_rxbufs
[i
]);
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
)
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
)
1517 return (DDI_SUCCESS
);
1520 ipw2100_dma_region_free(&sc
->sc_dma_status
);
1522 for (i
= 0; i
< IPW2100_NUM_RXBUF
; i
++)
1523 ipw2100_dma_region_free(&sc
->sc_dma_rxbufs
[i
]);
1525 ipw2100_dma_region_free(&sc
->sc_dma_rxbd
);
1527 for (i
= 0; i
< IPW2100_NUM_TXBUF
; i
++)
1528 ipw2100_dma_region_free(&sc
->sc_dma_txbufs
[i
]);
1530 ipw2100_dma_region_free(&sc
->sc_dma_txbd
);
1536 ipw2100_ring_free(struct ipw2100_softc
*sc
)
1543 ipw2100_dma_region_free(&sc
->sc_dma_txbd
);
1547 for (i
= 0; i
< IPW2100_NUM_TXBUF
; i
++)
1548 ipw2100_dma_region_free(&sc
->sc_dma_txbufs
[i
]);
1552 ipw2100_dma_region_free(&sc
->sc_dma_rxbd
);
1556 for (i
= 0; i
< IPW2100_NUM_RXBUF
; i
++)
1557 ipw2100_dma_region_free(&sc
->sc_dma_rxbufs
[i
]);
1561 ipw2100_dma_region_free(&sc
->sc_dma_status
);
1565 ipw2100_dma_region_free(&sc
->sc_dma_cmd
);
1569 ipw2100_ring_reset(struct ipw2100_softc
*sc
)
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
++)
1581 (struct ipw2100_txb
*)sc
->sc_dma_txbufs
[i
].dr_base
;
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
++) {
1591 (struct ipw2100_rxb
*)sc
->sc_dma_rxbufs
[i
].dr_base
;
1593 * initialize Rx buffer descriptors, both host and device
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;
1603 sc
->sc_cmd
= (struct ipw2100_cmd
*)sc
->sc_dma_cmd
.dr_base
;
1607 * tx, rx rings and command initialization
1610 ipw2100_ring_init(struct ipw2100_softc
*sc
)
1614 err
= ipw2100_ring_alloc(sc
);
1615 if (err
!= DDI_SUCCESS
)
1618 ipw2100_ring_reset(sc
);
1620 return (DDI_SUCCESS
);
1624 ipw2100_ring_hwsetup(struct ipw2100_softc
*sc
)
1626 ipw2100_ring_reset(sc
);
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
);
1633 * no new packet to transmit, tx-rd-index == tx-wr-index
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
);
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
);
1643 * all rx buffer are empty, rx-rd-index == 0 && rx-wr-index == N-1
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
));
1654 ipw2100_csr_put32(sc
, IPW2100_CSR_RX_STATUS_BASE
,
1655 sc
->sc_dma_status
.dr_pbase
);
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
1665 ipw2100_newstate(struct ieee80211com
*ic
, enum ieee80211_state state
, int arg
)
1667 struct ipw2100_softc
*sc
= (struct ipw2100_softc
*)ic
;
1668 struct ieee80211_node
*in
;
1669 uint8_t macaddr
[IEEE80211_ADDR_LEN
];
1671 wifi_data_t wd
= { 0 };
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
]));
1678 case IEEE80211_S_RUN
:
1680 * we only need to use BSSID as to find the node
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
,
1687 in
= ieee80211_find_node(&ic
->ic_scan
, macaddr
);
1691 (void) ieee80211_sta_join(ic
, in
);
1692 ieee80211_node_authorize(in
);
1695 * We can send data now; update the fastpath with our
1696 * current associated BSSID.
1698 if (ic
->ic_flags
& IEEE80211_F_PRIVACY
)
1699 wd
.wd_secalloc
= WIFI_SEC_WEP
;
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
));
1708 case IEEE80211_S_INIT
:
1709 case IEEE80211_S_SCAN
:
1710 case IEEE80211_S_AUTH
:
1711 case IEEE80211_S_ASSOC
:
1716 * notify to update the link
1718 if ((ic
->ic_state
!= IEEE80211_S_RUN
) && (state
== IEEE80211_S_RUN
)) {
1720 * previously disconnected and now connected
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
)) {
1727 * previously connected andd now disconnected
1729 sc
->sc_linkstate
= LINK_STATE_DOWN
;
1730 sc
->sc_flags
|= IPW2100_FLAG_LINK_CHANGE
;
1733 ic
->ic_state
= state
;
1734 return (DDI_SUCCESS
);
1742 ipw2100_m_stat(void *arg
, uint_t stat
, uint64_t *val
)
1744 ieee80211com_t
*ic
= (ieee80211com_t
*)arg
;
1745 IPW2100_DBG(IPW2100_DBG_GLD
, (((struct ipw2100_softc
*)arg
)->sc_dip
,
1747 "ipw2100_m_stat(): enter\n"));
1749 * some of below statistic data are from hardware, some from net80211
1752 case MAC_STAT_RBYTES
:
1753 *val
= ic
->ic_stats
.is_rx_bytes
;
1755 case MAC_STAT_IPACKETS
:
1756 *val
= ic
->ic_stats
.is_rx_frags
;
1758 case MAC_STAT_OBYTES
:
1759 *val
= ic
->ic_stats
.is_tx_bytes
;
1761 case MAC_STAT_OPACKETS
:
1762 *val
= ic
->ic_stats
.is_tx_frags
;
1765 * Get below from hardware statistic, retrieve net80211 value once 1s
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
:
1776 * Get blow information from net80211
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
));
1784 * need be supported in the future
1786 case MAC_STAT_IFSPEED
:
1787 case MAC_STAT_NOXMTBUF
:
1788 case MAC_STAT_IERRORS
:
1789 case MAC_STAT_OERRORS
:
1798 ipw2100_m_multicst(void *arg
, boolean_t add
, const uint8_t *mca
)
1801 IPW2100_DBG(IPW2100_DBG_GLD
, (((struct ipw2100_softc
*)arg
)->sc_dip
,
1803 "ipw2100_m_multicst(): enter\n"));
1809 * This thread function is used to handle the fatal error.
1812 ipw2100_thread(struct ipw2100_softc
*sc
)
1814 struct ieee80211com
*ic
= &sc
->sc_ic
;
1818 IPW2100_DBG(IPW2100_DBG_SOFTINT
, (sc
->sc_dip
, CE_CONT
,
1819 "ipw2100_thread(): into ipw2100 thread--> %d\n",
1822 mutex_enter(&sc
->sc_mflock
);
1824 while (sc
->sc_mfthread_switch
) {
1826 * notify the link state
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",
1833 sc
->sc_flags
&= ~IPW2100_FLAG_LINK_CHANGE
;
1834 nlstate
= sc
->sc_linkstate
;
1836 mutex_exit(&sc
->sc_mflock
);
1837 mac_link_update(ic
->ic_mach
, nlstate
);
1838 mutex_enter(&sc
->sc_mflock
);
1842 * recovery interrupt fatal error
1845 (sc
->sc_flags
& IPW2100_FLAG_HW_ERR_RECOVER
)) {
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
;
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
);
1858 * get statistic, the value will be retrieved by m_stat
1860 if (stat_cnt
== 10) {
1861 stat_cnt
= 0; /* re-start */
1863 mutex_exit(&sc
->sc_mflock
);
1864 ipw2100_get_statistics(sc
);
1865 mutex_enter(&sc
->sc_mflock
);
1867 stat_cnt
++; /* until 1s */
1869 mutex_exit(&sc
->sc_mflock
);
1870 delay(drv_usectohz(delay_aux_thread
));
1871 mutex_enter(&sc
->sc_mflock
);
1873 sc
->sc_mf_thread
= NULL
;
1874 cv_broadcast(&sc
->sc_mfthread_cv
);
1875 mutex_exit(&sc
->sc_mflock
);
1879 ipw2100_m_start(void *arg
)
1881 struct ipw2100_softc
*sc
= (struct ipw2100_softc
*)arg
;
1883 IPW2100_DBG(IPW2100_DBG_GLD
, (sc
->sc_dip
, CE_CONT
,
1884 "ipw2100_m_start(): enter\n"));
1887 * initialize ipw2100 hardware
1889 (void) ipw2100_init(sc
);
1891 sc
->sc_flags
|= IPW2100_FLAG_RUNNING
;
1893 * fix KCF bug. - workaround, need to fix it in net80211
1895 (void) crypto_mech2id(SUN_CKM_RC4
);
1901 ipw2100_m_stop(void *arg
)
1903 struct ipw2100_softc
*sc
= (struct ipw2100_softc
*)arg
;
1905 IPW2100_DBG(IPW2100_DBG_GLD
, (sc
->sc_dip
, CE_CONT
,
1906 "ipw2100_m_stop(): enter\n"));
1910 sc
->sc_flags
&= ~IPW2100_FLAG_RUNNING
;
1914 ipw2100_m_unicst(void *arg
, const uint8_t *macaddr
)
1916 struct ipw2100_softc
*sc
= (struct ipw2100_softc
*)arg
;
1917 struct ieee80211com
*ic
= &sc
->sc_ic
;
1920 IPW2100_DBG(IPW2100_DBG_GLD
, (sc
->sc_dip
, CE_CONT
,
1921 "ipw2100_m_unicst(): enter\n"));
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]));
1929 if (!IEEE80211_ADDR_EQ(ic
->ic_macaddr
, macaddr
)) {
1930 IEEE80211_ADDR_COPY(ic
->ic_macaddr
, macaddr
);
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"));
1949 ipw2100_m_promisc(void *arg
, boolean_t on
)
1951 struct ipw2100_softc
*sc
= (struct ipw2100_softc
*)arg
;
1954 IPW2100_DBG(IPW2100_DBG_GLD
, (sc
->sc_dip
, CE_CONT
,
1955 "ipw2100_m_promisc(): enter. "
1956 "GLD setting promiscuous mode - %d\n", on
));
1960 if (!(sc
->if_flags
& IFF_PROMISC
)) {
1961 sc
->if_flags
|= IFF_PROMISC
;
1965 if (sc
->if_flags
& IFF_PROMISC
) {
1966 sc
->if_flags
&= ~IFF_PROMISC
;
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"));
1986 ipw2100_m_tx(void *arg
, mblk_t
*mp
)
1988 struct ipw2100_softc
*sc
= (struct ipw2100_softc
*)arg
;
1989 struct ieee80211com
*ic
= &sc
->sc_ic
;
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.
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",
2005 while (mp
!= NULL
) {
2008 if (ipw2100_send(ic
, mp
, IEEE80211_FC0_TYPE_DATA
) !=
2020 ipw2100_send(ieee80211com_t
*ic
, mblk_t
*mp
, uint8_t type
)
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
;
2029 struct ipw2100_bd
*txbd
[2];
2030 struct ipw2100_txb
*txbuf
;
2031 struct dma_region
*dr
;
2032 struct ipw2100_hdr
*h
;
2036 ASSERT(mp
->b_next
== NULL
);
2042 IPW2100_DBG(IPW2100_DBG_GLD
, (sc
->sc_dip
, CE_CONT
,
2043 "ipw2100_send(): enter\n"));
2045 if ((type
& IEEE80211_FC0_TYPE_MASK
) != IEEE80211_FC0_TYPE_DATA
) {
2047 * it is impossible to send non-data 802.11 frame in current
2048 * ipw driver. Therefore, drop the package
2055 mutex_enter(&sc
->sc_tx_lock
);
2058 * need 2 descriptors: 1 for SEND cmd parameter header,
2059 * and the other for payload, i.e., 802.11 frame including 802.11
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",
2067 ic
->ic_stats
.is_tx_nobuf
++; /* no enough buffer */
2068 sc
->sc_flags
|= IPW2100_FLAG_TX_SCHED
;
2070 mutex_exit(&sc
->sc_resched_lock
);
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
));
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 */
2085 (void) ieee80211_encap(ic
, mp
, in
);
2086 ieee80211_free_node(in
);
2088 if (wh_tmp
->i_fc
[1] & IEEE80211_FC1_WEP
) {
2090 * it is very bad that ieee80211_crypto_encap can only accept a
2091 * single continuous buffer.
2094 * allocate 32 more bytes is to be compatible with further
2095 * ieee802.11i standard.
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"));
2112 (void) memcpy(m
->b_rptr
+ off
, m0
->b_rptr
, cnt
);
2118 IPW2100_DBG(IPW2100_DBG_WIFI
, (sc
->sc_dip
, CE_CONT
,
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
,
2126 "Encrypting 802.11 frame failed\n"));
2132 IPW2100_DBG(IPW2100_DBG_WIFI
, (sc
->sc_dip
, CE_CONT
,
2134 "Encrypting 802.11 frame finished, %d, %d, k=0x%08x\n",
2135 msgdsize(mp
), MBLKL(mp
), k
->wk_flags
));
2141 idx
= sc
->sc_tx_cur
;
2142 txbd
[0] = &sc
->sc_txbd
[idx
];
2145 sc
->sc_tx_cur
= RING_FORWARD(sc
->sc_tx_cur
, 1, IPW2100_NUM_TXBD
);
2149 * payload descriptor
2151 idx
= sc
->sc_tx_cur
;
2152 txbd
[1] = &sc
->sc_txbd
[idx
];
2155 sc
->sc_tx_cur
= RING_FORWARD(sc
->sc_tx_cur
, 1, IPW2100_NUM_TXBD
);
2159 * one buffer, SEND cmd header and payload buffer
2161 txbuf
= sc
->sc_txbufs
[bidx
];
2162 dr
= &sc
->sc_dma_txbufs
[bidx
];
2165 * extract 802.11 header from message, fill wh from m0
2167 hdat
= (uint8_t *)&wh
;
2173 while (off
< sizeof (wh
)) {
2175 if (cnt
> (sizeof (wh
) - off
))
2176 cnt
= sizeof (wh
) - off
;
2178 (void) memcpy(hdat
+ off
, m0
->b_rptr
, cnt
);
2187 * prepare SEND cmd header
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;
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
);
2201 IEEE80211_ADDR_COPY(h
->daddr
, wh
.i_addr1
);
2204 * extract payload from message into tx data buffer
2210 (void) memcpy(&txbuf
->txb_dat
[off
], m0
->b_rptr
, cnt
);
2217 * fill SEND cmd header descriptor
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
;
2226 * fill payload descriptor
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
;
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
);
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
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
);
2253 ipw2100_csr_put32(sc
, IPW2100_CSR_TX_WRITE_INDEX
, sc
->sc_tx_cur
);
2255 if (mp
) /* success, free the original message */
2261 mutex_exit(&sc
->sc_tx_lock
);
2263 IPW2100_DBG(IPW2100_DBG_GLD
, (sc
->sc_dip
, CE_CONT
,
2264 "ipw2100_send(): exit - err=%d\n", err
));
2272 #define IEEE80211_IOCTL_REQUIRED (1)
2273 #define IEEE80211_IOCTL_NOT_REQUIRED (0)
2275 ipw2100_m_ioctl(void *arg
, queue_t
*q
, mblk_t
*m
)
2277 struct ipw2100_softc
*sc
= (struct ipw2100_softc
*)arg
;
2278 struct ieee80211com
*ic
= &sc
->sc_ic
;
2281 IPW2100_DBG(IPW2100_DBG_GLD
, (sc
->sc_dip
, CE_CONT
,
2282 "ipw2100_m_ioctl(): enter\n"));
2285 * check whether or not need to handle this in net80211
2287 if (ipw2100_ioctl(sc
, q
, m
) == IEEE80211_IOCTL_NOT_REQUIRED
)
2288 return; /* succes or fail */
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);
2298 if (err
== ERESTART
) {
2299 if (sc
->sc_flags
& IPW2100_FLAG_RUNNING
)
2300 (void) ipw2100_chip_reset(sc
);
2305 ipw2100_ioctl(struct ipw2100_softc
*sc
, queue_t
*q
, mblk_t
*m
)
2307 struct iocblk
*iocp
;
2308 uint32_t len
, ret
, cmd
;
2310 boolean_t need_privilege
;
2311 boolean_t need_net80211
;
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",
2317 miocnak(q
, m
, 0, EINVAL
);
2318 return (IEEE80211_IOCTL_NOT_REQUIRED
);
2322 * Validate the command
2324 iocp
= (struct iocblk
*)(uintptr_t)m
->b_rptr
;
2325 iocp
->ioc_error
= 0;
2326 cmd
= iocp
->ioc_cmd
;
2327 need_privilege
= B_TRUE
;
2329 case WLAN_SET_PARAM
:
2332 case WLAN_GET_PARAM
:
2333 need_privilege
= B_FALSE
;
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
);
2342 if (need_privilege
&& (ret
= secpolicy_dl_config(iocp
->ioc_cr
)) != 0) {
2343 miocnak(q
, m
, 0, ret
);
2344 return (IEEE80211_IOCTL_NOT_REQUIRED
);
2351 if (iocp
->ioc_count
== 0 || iocp
->ioc_count
< sizeof (wldp_t
) ||
2353 miocnak(q
, m
, 0, EINVAL
);
2354 return (IEEE80211_IOCTL_NOT_REQUIRED
);
2357 * assuming single data block
2360 freemsg(m0
->b_cont
);
2364 need_net80211
= B_FALSE
;
2365 ret
= ipw2100_getset(sc
, m0
, cmd
, &need_net80211
);
2366 if (!need_net80211
) {
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
);
2377 * IEEE80211_IOCTL_REQUIRED - need net80211 handle
2379 return (IEEE80211_IOCTL_REQUIRED
);
2383 ipw2100_getset(struct ipw2100_softc
*sc
, mblk_t
*m
, uint32_t cmd
,
2384 boolean_t
*need_net80211
)
2386 wldp_t
*infp
, *outfp
;
2388 int ret
; /* IEEE80211_IOCTL - handled by net80211 */
2390 infp
= (wldp_t
*)(uintptr_t)m
->b_rptr
;
2391 outfp
= (wldp_t
*)(uintptr_t)m
->b_rptr
;
2392 outfp
->wldp_result
= WL_NOTSUPPORTED
;
2395 IPW2100_DBG(IPW2100_DBG_IOCTL
, (sc
->sc_dip
, CE_CONT
,
2396 "ipw2100_getset(): id = 0x%x\n", id
));
2399 * which is not supported by net80211, so it
2400 * has to be handled from driver side
2403 ret
= ipw_wificfg_radio(sc
, cmd
, outfp
);
2406 * so far, drier doesn't support fix-rates
2408 case WL_DESIRED_RATES
:
2409 ret
= ipw_wificfg_desrates(outfp
);
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
2418 case WL_DISASSOCIATE
:
2419 ret
= ipw_wificfg_disassoc(sc
, outfp
);
2423 * The wifi IOCTL net80211 supported:
2426 * case WL_WEP_KEY_TAB:
2427 * case WL_WEP_KEY_ID:
2428 * case WL_AUTH_MODE:
2429 * case WL_ENCRYPTION:
2432 * case WL_LINKSTATUS:
2435 * case WL_LOAD_DEFAULTS:
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.
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.
2447 if ((ipw2100_get_radio(sc
) == 0) &&
2448 (id
!= WL_LINKSTATUS
)) {
2450 IPW2100_REPORT((sc
->sc_dip
, CE_WARN
,
2451 "ipw: RADIO is OFF\n"));
2453 outfp
->wldp_length
= WIFI_BUF_OFFSET
;
2454 outfp
->wldp_result
= WL_SUCCESS
;
2459 *need_net80211
= B_TRUE
; /* let net80211 do the rest */
2463 * we will overwrite everything
2465 m
->b_wptr
= m
->b_rptr
+ outfp
->wldp_length
;
2471 * Call back functions for get/set proporty
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
)
2477 struct ipw2100_softc
*sc
= (struct ipw2100_softc
*)arg
;
2478 struct ieee80211com
*ic
= &sc
->sc_ic
;
2481 switch (wldp_pr_num
) {
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"));
2487 case MAC_PROP_WL_RADIO
:
2488 *(wl_linkstatus_t
*)wldp_buf
= ipw2100_get_radio(sc
);
2491 /* go through net80211 */
2492 err
= ieee80211_getprop(ic
, pr_name
, wldp_pr_num
,
2493 wldp_length
, wldp_buf
);
2501 ipw2100_m_propinfo(void *arg
, const char *pr_name
, mac_prop_id_t wldp_pr_num
,
2502 mac_prop_info_handle_t prh
)
2504 struct ipw2100_softc
*sc
= (struct ipw2100_softc
*)arg
;
2505 struct ieee80211com
*ic
= &sc
->sc_ic
;
2507 ieee80211_propinfo(ic
, pr_name
, wldp_pr_num
, prh
);
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
)
2515 struct ipw2100_softc
*sc
= (struct ipw2100_softc
*)arg
;
2516 struct ieee80211com
*ic
= &sc
->sc_ic
;
2519 switch (wldp_pr_num
) {
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"));
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"));
2532 /* go through net80211 */
2533 err
= ieee80211_setprop(ic
, pr_name
, wldp_pr_num
, wldp_length
,
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);
2552 ipw_wificfg_radio(struct ipw2100_softc
*sc
, uint32_t cmd
, wldp_t
*outfp
)
2554 uint32_t ret
= ENOTSUP
;
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 */
2563 case WLAN_SET_PARAM
:
2571 ipw_wificfg_desrates(wldp_t
*outfp
)
2574 * return success, but with result NOTSUPPORTED
2576 outfp
->wldp_length
= WIFI_BUF_OFFSET
;
2577 outfp
->wldp_result
= WL_NOTSUPPORTED
;
2582 ipw_wificfg_disassoc(struct ipw2100_softc
*sc
, wldp_t
*outfp
)
2584 struct ieee80211com
*ic
= &sc
->sc_ic
;
2589 if (ic
->ic_state
!= IEEE80211_S_INIT
) {
2590 (void) ieee80211_new_state(ic
, IEEE80211_S_INIT
, -1);
2594 * return success always
2596 outfp
->wldp_length
= WIFI_BUF_OFFSET
;
2597 outfp
->wldp_result
= WL_SUCCESS
;
2600 /* End of IOCTL Handler */
2603 ipw2100_fix_channel(struct ieee80211com
*ic
, mblk_t
*m
)
2605 struct ieee80211_frame
*wh
;
2607 uint8_t *frm
, *efrm
;
2609 wh
= (struct ieee80211_frame
*)m
->b_rptr
;
2611 if ((wh
->i_fc
[0] & IEEE80211_FC0_TYPE_MASK
) != IEEE80211_FC0_TYPE_MGT
)
2614 subtype
= wh
->i_fc
[0] & IEEE80211_FC0_SUBTYPE_MASK
;
2616 if (subtype
!= IEEE80211_FC0_SUBTYPE_BEACON
&&
2617 subtype
!= IEEE80211_FC0_SUBTYPE_PROBE_RESP
)
2621 * assume the message contains only 1 block
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
)
2632 ic
->ic_curchan
= &ic
->ic_sup_channels
[frm
[2]];
2640 ipw2100_rcvpkt(struct ipw2100_softc
*sc
, struct ipw2100_status
*status
,
2643 struct ieee80211com
*ic
= &sc
->sc_ic
;
2645 struct ieee80211_frame
*wh
= (struct ieee80211_frame
*)rxbuf
;
2646 struct ieee80211_node
*in
;
2649 in
= ieee80211_find_rxnode(ic
, wh
);
2650 rlen
= LE_32(status
->len
);
2651 m
= allocb(rlen
, BPRI_MED
);
2653 (void) memcpy(m
->b_wptr
, rxbuf
, 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);
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
);
2666 ipw2100_intr(caddr_t arg
)
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
;
2673 struct dma_region
*dr
;
2676 struct ipw2100_bd
*rxbd
;
2679 if (sc
->sc_suspended
)
2680 return (DDI_INTR_UNCLAIMED
);
2682 ireg
= ipw2100_csr_get32(sc
, IPW2100_CSR_INTR
);
2684 if (!(ireg
& IPW2100_INTR_MASK_ALL
))
2685 return (DDI_INTR_UNCLAIMED
);
2688 * mask all interrupts
2690 ipw2100_csr_put32(sc
, IPW2100_CSR_INTR_MASK
, 0);
2693 * acknowledge all fired interrupts
2695 ipw2100_csr_put32(sc
, IPW2100_CSR_INTR
, ireg
);
2697 IPW2100_DBG(IPW2100_DBG_INT
, (sc
->sc_dip
, CE_CONT
,
2698 "ipw2100_intr(): interrupt is fired. int=0x%08x\n", ireg
));
2700 if (ireg
& IPW2100_INTR_MASK_ERR
) {
2702 IPW2100_DBG(IPW2100_DBG_FATAL
, (sc
->sc_dip
, CE_CONT
,
2703 "ipw2100_intr(): interrupt is fired, MASK = 0x%08x\n",
2707 * inform mfthread to recover hw error
2709 mutex_enter(&sc
->sc_mflock
);
2710 sc
->sc_flags
|= IPW2100_FLAG_HW_ERR_RECOVER
;
2711 mutex_exit(&sc
->sc_mflock
);
2713 goto enable_interrupt
;
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
);
2729 if (ireg
& IPW2100_INTR_RX_TRANSFER
) {
2730 ridx
= ipw2100_csr_get32(sc
,
2731 IPW2100_CSR_RX_READ_INDEX
);
2733 for (; sc
->sc_rx_cur
!= ridx
;
2734 sc
->sc_rx_cur
= RING_FORWARD(
2735 sc
->sc_rx_cur
, 1, IPW2100_NUM_RXBD
)) {
2738 status
= &sc
->sc_status
[i
];
2739 rxbuf
= &sc
->sc_rxbufs
[i
]->rxb_dat
[0];
2740 dr
= &sc
->sc_dma_rxbufs
[i
];
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
));
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
));
2769 switch (LE_16(status
->code
) & 0x0f) {
2771 * command complete response
2773 case IPW2100_STATUS_CODE_COMMAND
:
2774 mutex_enter(&sc
->sc_ilock
);
2776 cv_signal(&sc
->sc_cmd_cond
);
2777 mutex_exit(&sc
->sc_ilock
);
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",
2790 case IPW2100_STATE_ASSOCIATED
:
2791 ieee80211_new_state(ic
,
2792 IEEE80211_S_RUN
, -1);
2794 case IPW2100_STATE_ASSOCIATION_LOST
:
2795 case IPW2100_STATE_DISABLED
:
2796 ieee80211_new_state(ic
,
2797 IEEE80211_S_INIT
, -1);
2800 * When radio is OFF, need a better
2801 * scan approach to ensure scan
2804 case IPW2100_STATE_RADIO_DISABLED
:
2805 IPW2100_REPORT((sc
->sc_dip
, CE_WARN
,
2806 "ipw2100_intr(): RADIO is OFF\n"));
2809 case IPW2100_STATE_SCAN_COMPLETE
:
2810 ieee80211_cancel_scan(ic
);
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
;
2823 case IPW2100_STATUS_CODE_DATA_802_11
:
2824 case IPW2100_STATUS_CODE_DATA_802_3
:
2825 ipw2100_rcvpkt(sc
, status
, rxbuf
);
2827 case IPW2100_STATUS_CODE_NOTIFICATION
:
2830 IPW2100_WARN((sc
->sc_dip
, CE_WARN
,
2832 "unknown status code 0x%04x\n",
2833 LE_16(status
->code
)));
2838 * write sc_rx_cur backward 1 step to RX_WRITE_INDEX
2840 ipw2100_csr_put32(sc
, IPW2100_CSR_RX_WRITE_INDEX
,
2841 RING_BACKWARD(sc
->sc_rx_cur
, 1, IPW2100_NUM_RXBD
));
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
);
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
);
2863 mutex_exit(&sc
->sc_resched_lock
);
2868 * enable all interrupts
2870 ipw2100_csr_put32(sc
, IPW2100_CSR_INTR_MASK
, IPW2100_INTR_MASK_ALL
);
2872 return (DDI_INTR_CLAIMED
);
2877 * Module Loading Data & Entry Points
2879 DDI_DEFINE_STREAM_OPS(ipw2100_devops
, nulldev
, nulldev
, ipw2100_attach
,
2880 ipw2100_detach
, nodev
, NULL
, D_MP
, NULL
, ipw2100_quiesce
);
2882 static struct modldrv ipw2100_modldrv
= {
2888 static struct modlinkage ipw2100_modlinkage
= {
2899 status
= ddi_soft_state_init(&ipw2100_ssp
,
2900 sizeof (struct ipw2100_softc
), 1);
2901 if (status
!= DDI_SUCCESS
)
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
);
2919 status
= mod_remove(&ipw2100_modlinkage
);
2920 if (status
== DDI_SUCCESS
) {
2921 mac_fini_ops(&ipw2100_devops
);
2922 ddi_soft_state_fini(&ipw2100_ssp
);
2929 _info(struct modinfo
*mip
)
2931 return (mod_info(&ipw2100_modlinkage
, mip
));