xref: /illumos-gate/usr/src/uts/common/io/iwh/iwh.c (revision 56f33205c9ed776c3c909e07d52e94610a675740)
1 /*
2  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 /*
7  * Copyright (c) 2009, Intel Corporation
8  * All rights reserved.
9  */
10 
11 /*
12  * Copyright (c) 2006
13  * Copyright (c) 2007
14  *	Damien Bergamini <damien.bergamini@free.fr>
15  *
16  * Permission to use, copy, modify, and distribute this software for any
17  * purpose with or without fee is hereby granted, provided that the above
18  * copyright notice and this permission notice appear in all copies.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
21  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
22  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
23  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
24  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
25  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
26  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
27  */
28 
29 /*
30  * Intel(R) WiFi Link 5100/5300 Driver
31  */
32 
33 #include <sys/types.h>
34 #include <sys/byteorder.h>
35 #include <sys/conf.h>
36 #include <sys/cmn_err.h>
37 #include <sys/stat.h>
38 #include <sys/ddi.h>
39 #include <sys/sunddi.h>
40 #include <sys/strsubr.h>
41 #include <sys/ethernet.h>
42 #include <inet/common.h>
43 #include <inet/nd.h>
44 #include <inet/mi.h>
45 #include <sys/note.h>
46 #include <sys/stream.h>
47 #include <sys/strsun.h>
48 #include <sys/modctl.h>
49 #include <sys/devops.h>
50 #include <sys/dlpi.h>
51 #include <sys/mac_provider.h>
52 #include <sys/mac_wifi.h>
53 #include <sys/net80211.h>
54 #include <sys/net80211_proto.h>
55 #include <sys/net80211_ht.h>
56 #include <sys/varargs.h>
57 #include <sys/policy.h>
58 #include <sys/pci.h>
59 
60 #include "iwh_calibration.h"
61 #include "iwh_hw.h"
62 #include "iwh_eeprom.h"
63 #include "iwh_var.h"
64 #include <inet/wifi_ioctl.h>
65 
66 #ifdef DEBUG
67 #define	IWH_DEBUG_80211		(1 << 0)
68 #define	IWH_DEBUG_CMD		(1 << 1)
69 #define	IWH_DEBUG_DMA		(1 << 2)
70 #define	IWH_DEBUG_EEPROM	(1 << 3)
71 #define	IWH_DEBUG_FW		(1 << 4)
72 #define	IWH_DEBUG_HW		(1 << 5)
73 #define	IWH_DEBUG_INTR		(1 << 6)
74 #define	IWH_DEBUG_MRR		(1 << 7)
75 #define	IWH_DEBUG_PIO		(1 << 8)
76 #define	IWH_DEBUG_RX		(1 << 9)
77 #define	IWH_DEBUG_SCAN		(1 << 10)
78 #define	IWH_DEBUG_TX		(1 << 11)
79 #define	IWH_DEBUG_RATECTL	(1 << 12)
80 #define	IWH_DEBUG_RADIO		(1 << 13)
81 #define	IWH_DEBUG_RESUME	(1 << 14)
82 #define	IWH_DEBUG_CALIBRATION	(1 << 15)
83 #define	IWH_DEBUG_BA		(1 << 16)
84 #define	IWH_DEBUG_RXON		(1 << 17)
85 #define	IWH_DEBUG_HWRATE	(1 << 18)
86 #define	IWH_DEBUG_HTRATE	(1 << 19)
87 #define	IWH_DEBUG_QOS		(1 << 20)
88 /*
89  * if want to see debug message of a given section,
90  * please set this flag to one of above values
91  */
92 uint32_t iwh_dbg_flags = 0;
93 #define	IWH_DBG(x) \
94 	iwh_dbg x
95 #else
96 #define	IWH_DBG(x)
97 #endif
98 
99 #define	MS(v, f)    (((v) & f) >> f##_S)
100 
101 static void	*iwh_soft_state_p = NULL;
102 
103 /*
104  * ucode will be compiled into driver image
105  */
106 static uint8_t iwh_fw_5000_bin[] = {
107 #include "fw-iw/fw_5000/iwh_5000.ucode"
108 };
109 
110 static uint8_t iwh_fw_5150_bin[] = {
111 #include "fw-iw/fw_5150/iwh_5150.ucode"
112 };
113 
114 /*
115  * DMA attributes for a shared page
116  */
117 static ddi_dma_attr_t sh_dma_attr = {
118 	DMA_ATTR_V0,	/* version of this structure */
119 	0,		/* lowest usable address */
120 	0xffffffffU,	/* highest usable address */
121 	0xffffffffU,	/* maximum DMAable byte count */
122 	0x1000,		/* alignment in bytes */
123 	0x1000,		/* burst sizes (any?) */
124 	1,		/* minimum transfer */
125 	0xffffffffU,	/* maximum transfer */
126 	0xffffffffU,	/* maximum segment length */
127 	1,		/* maximum number of segments */
128 	1,		/* granularity */
129 	0,		/* flags (reserved) */
130 };
131 
132 /*
133  * DMA attributes for a keep warm DRAM descriptor
134  */
135 static ddi_dma_attr_t kw_dma_attr = {
136 	DMA_ATTR_V0,	/* version of this structure */
137 	0,		/* lowest usable address */
138 	0xffffffffU,	/* highest usable address */
139 	0xffffffffU,	/* maximum DMAable byte count */
140 	0x1000,		/* alignment in bytes */
141 	0x1000,		/* burst sizes (any?) */
142 	1,		/* minimum transfer */
143 	0xffffffffU,	/* maximum transfer */
144 	0xffffffffU,	/* maximum segment length */
145 	1,		/* maximum number of segments */
146 	1,		/* granularity */
147 	0,		/* flags (reserved) */
148 };
149 
150 /*
151  * DMA attributes for a ring descriptor
152  */
153 static ddi_dma_attr_t ring_desc_dma_attr = {
154 	DMA_ATTR_V0,	/* version of this structure */
155 	0,		/* lowest usable address */
156 	0xffffffffU,	/* highest usable address */
157 	0xffffffffU,	/* maximum DMAable byte count */
158 	0x100,		/* alignment in bytes */
159 	0x100,		/* burst sizes (any?) */
160 	1,		/* minimum transfer */
161 	0xffffffffU,	/* maximum transfer */
162 	0xffffffffU,	/* maximum segment length */
163 	1,		/* maximum number of segments */
164 	1,		/* granularity */
165 	0,		/* flags (reserved) */
166 };
167 
168 /*
169  * DMA attributes for a cmd
170  */
171 static ddi_dma_attr_t cmd_dma_attr = {
172 	DMA_ATTR_V0,	/* version of this structure */
173 	0,		/* lowest usable address */
174 	0xffffffffU,	/* highest usable address */
175 	0xffffffffU,	/* maximum DMAable byte count */
176 	4,		/* alignment in bytes */
177 	0x100,		/* burst sizes (any?) */
178 	1,		/* minimum transfer */
179 	0xffffffffU,	/* maximum transfer */
180 	0xffffffffU,	/* maximum segment length */
181 	1,		/* maximum number of segments */
182 	1,		/* granularity */
183 	0,		/* flags (reserved) */
184 };
185 
186 /*
187  * DMA attributes for a rx buffer
188  */
189 static ddi_dma_attr_t rx_buffer_dma_attr = {
190 	DMA_ATTR_V0,	/* version of this structure */
191 	0,		/* lowest usable address */
192 	0xffffffffU,	/* highest usable address */
193 	0xffffffffU,	/* maximum DMAable byte count */
194 	0x100,		/* alignment in bytes */
195 	0x100,		/* burst sizes (any?) */
196 	1,		/* minimum transfer */
197 	0xffffffffU,	/* maximum transfer */
198 	0xffffffffU,	/* maximum segment length */
199 	1,		/* maximum number of segments */
200 	1,		/* granularity */
201 	0,		/* flags (reserved) */
202 };
203 
204 /*
205  * DMA attributes for a tx buffer.
206  * the maximum number of segments is 4 for the hardware.
207  * now all the wifi drivers put the whole frame in a single
208  * descriptor, so we define the maximum  number of segments 1,
209  * just the same as the rx_buffer. we consider leverage the HW
210  * ability in the future, that is why we don't define rx and tx
211  * buffer_dma_attr as the same.
212  */
213 static ddi_dma_attr_t tx_buffer_dma_attr = {
214 	DMA_ATTR_V0,	/* version of this structure */
215 	0,		/* lowest usable address */
216 	0xffffffffU,	/* highest usable address */
217 	0xffffffffU,	/* maximum DMAable byte count */
218 	4,		/* alignment in bytes */
219 	0x100,		/* burst sizes (any?) */
220 	1,		/* minimum transfer */
221 	0xffffffffU,	/* maximum transfer */
222 	0xffffffffU,	/* maximum segment length */
223 	1,		/* maximum number of segments */
224 	1,		/* granularity */
225 	0,		/* flags (reserved) */
226 };
227 
228 /*
229  * DMA attributes for text and data part in the firmware
230  */
231 static ddi_dma_attr_t fw_dma_attr = {
232 	DMA_ATTR_V0,	/* version of this structure */
233 	0,		/* lowest usable address */
234 	0xffffffffU,	/* highest usable address */
235 	0x7fffffff,	/* maximum DMAable byte count */
236 	0x10,		/* alignment in bytes */
237 	0x100,		/* burst sizes (any?) */
238 	1,		/* minimum transfer */
239 	0xffffffffU,	/* maximum transfer */
240 	0xffffffffU,	/* maximum segment length */
241 	1,		/* maximum number of segments */
242 	1,		/* granularity */
243 	0,		/* flags (reserved) */
244 };
245 
246 /*
247  * regs access attributes
248  */
249 static ddi_device_acc_attr_t iwh_reg_accattr = {
250 	DDI_DEVICE_ATTR_V0,
251 	DDI_STRUCTURE_LE_ACC,
252 	DDI_STRICTORDER_ACC,
253 	DDI_DEFAULT_ACC
254 };
255 
256 /*
257  * DMA access attributes for descriptor
258  */
259 static ddi_device_acc_attr_t iwh_dma_descattr = {
260 	DDI_DEVICE_ATTR_V0,
261 	DDI_STRUCTURE_LE_ACC,
262 	DDI_STRICTORDER_ACC,
263 	DDI_DEFAULT_ACC
264 };
265 
266 /*
267  * DMA access attributes
268  */
269 static ddi_device_acc_attr_t iwh_dma_accattr = {
270 	DDI_DEVICE_ATTR_V0,
271 	DDI_NEVERSWAP_ACC,
272 	DDI_STRICTORDER_ACC,
273 	DDI_DEFAULT_ACC
274 };
275 
276 static int	iwh_ring_init(iwh_sc_t *);
277 static void	iwh_ring_free(iwh_sc_t *);
278 static int	iwh_alloc_shared(iwh_sc_t *);
279 static void	iwh_free_shared(iwh_sc_t *);
280 static int	iwh_alloc_kw(iwh_sc_t *);
281 static void	iwh_free_kw(iwh_sc_t *);
282 static int	iwh_alloc_fw_dma(iwh_sc_t *);
283 static void	iwh_free_fw_dma(iwh_sc_t *);
284 static int	iwh_alloc_rx_ring(iwh_sc_t *);
285 static void	iwh_reset_rx_ring(iwh_sc_t *);
286 static void	iwh_free_rx_ring(iwh_sc_t *);
287 static int	iwh_alloc_tx_ring(iwh_sc_t *, iwh_tx_ring_t *,
288     int, int);
289 static void	iwh_reset_tx_ring(iwh_sc_t *, iwh_tx_ring_t *);
290 static void	iwh_free_tx_ring(iwh_tx_ring_t *);
291 static ieee80211_node_t *iwh_node_alloc(ieee80211com_t *);
292 static void	iwh_node_free(ieee80211_node_t *);
293 static int	iwh_newstate(ieee80211com_t *, enum ieee80211_state, int);
294 static void	iwh_mac_access_enter(iwh_sc_t *);
295 static void	iwh_mac_access_exit(iwh_sc_t *);
296 static uint32_t	iwh_reg_read(iwh_sc_t *, uint32_t);
297 static void	iwh_reg_write(iwh_sc_t *, uint32_t, uint32_t);
298 static int	iwh_load_init_firmware(iwh_sc_t *);
299 static int	iwh_load_run_firmware(iwh_sc_t *);
300 static void	iwh_tx_intr(iwh_sc_t *, iwh_rx_desc_t *);
301 static void	iwh_cmd_intr(iwh_sc_t *, iwh_rx_desc_t *);
302 static uint_t   iwh_intr(caddr_t, caddr_t);
303 static int	iwh_eep_load(iwh_sc_t *);
304 static void	iwh_get_mac_from_eep(iwh_sc_t *);
305 static int	iwh_eep_sem_down(iwh_sc_t *);
306 static void	iwh_eep_sem_up(iwh_sc_t *);
307 static uint_t   iwh_rx_softintr(caddr_t, caddr_t);
308 static uint8_t	iwh_rate_to_plcp(int);
309 static int	iwh_cmd(iwh_sc_t *, int, const void *, int, int);
310 static void	iwh_set_led(iwh_sc_t *, uint8_t, uint8_t, uint8_t);
311 static int	iwh_hw_set_before_auth(iwh_sc_t *);
312 static int	iwh_scan(iwh_sc_t *);
313 static int	iwh_config(iwh_sc_t *);
314 static void	iwh_stop_master(iwh_sc_t *);
315 static int	iwh_power_up(iwh_sc_t *);
316 static int	iwh_preinit(iwh_sc_t *);
317 static int	iwh_init(iwh_sc_t *);
318 static void	iwh_stop(iwh_sc_t *);
319 static int	iwh_quiesce(dev_info_t *t);
320 static void	iwh_amrr_init(iwh_amrr_t *);
321 static void	iwh_amrr_timeout(iwh_sc_t *);
322 static void	iwh_amrr_ratectl(void *, ieee80211_node_t *);
323 static void	iwh_ucode_alive(iwh_sc_t *, iwh_rx_desc_t *);
324 static void	iwh_rx_phy_intr(iwh_sc_t *, iwh_rx_desc_t *);
325 static void	iwh_rx_mpdu_intr(iwh_sc_t *, iwh_rx_desc_t *);
326 static void	iwh_release_calib_buffer(iwh_sc_t *);
327 static int	iwh_init_common(iwh_sc_t *);
328 static uint8_t	*iwh_eep_addr_trans(iwh_sc_t *, uint32_t);
329 static int	iwh_put_seg_fw(iwh_sc_t *, uint32_t, uint32_t, uint32_t);
330 static	int	iwh_alive_common(iwh_sc_t *);
331 static void	iwh_save_calib_result(iwh_sc_t *, iwh_rx_desc_t *);
332 static int	iwh_tx_power_table(iwh_sc_t *, int);
333 static int	iwh_attach(dev_info_t *, ddi_attach_cmd_t);
334 static int	iwh_detach(dev_info_t *, ddi_detach_cmd_t);
335 static void	iwh_destroy_locks(iwh_sc_t *);
336 static int	iwh_send(ieee80211com_t *, mblk_t *, uint8_t);
337 static void	iwh_thread(iwh_sc_t *);
338 static int	iwh_run_state_config(iwh_sc_t *);
339 static int	iwh_fast_recover(iwh_sc_t *);
340 static int	iwh_wme_update(ieee80211com_t *);
341 static int	iwh_qosparam_to_hw(iwh_sc_t *, int);
342 static int	iwh_wme_to_qos_ac(int);
343 static uint16_t	iwh_cw_e_to_cw(uint8_t);
344 static int	iwh_wmeparam_check(struct wmeParams *);
345 static inline int	iwh_wme_tid_qos_ac(int);
346 static inline int	iwh_qos_ac_to_txq(int);
347 static int	iwh_wme_tid_to_txq(int);
348 static void	iwh_init_ht_conf(iwh_sc_t *);
349 static void	iwh_overwrite_11n_rateset(iwh_sc_t *);
350 static void	iwh_overwrite_ic_default(iwh_sc_t *);
351 static void	iwh_config_rxon_chain(iwh_sc_t *);
352 static int	iwh_add_ap_sta(iwh_sc_t *);
353 static int	iwh_ap_lq(iwh_sc_t *);
354 static void	iwh_recv_action(struct ieee80211_node *,
355     const uint8_t *, const uint8_t *);
356 static int	iwh_send_action(struct ieee80211_node *,
357     int, int, uint16_t[4]);
358 static int	iwh_is_max_rate(ieee80211_node_t *);
359 static int	iwh_is_min_rate(ieee80211_node_t *);
360 static void	iwh_increase_rate(ieee80211_node_t *);
361 static void	iwh_decrease_rate(ieee80211_node_t *);
362 static int	iwh_alloc_dma_mem(iwh_sc_t *, size_t,
363     ddi_dma_attr_t *, ddi_device_acc_attr_t *,
364     uint_t, iwh_dma_t *);
365 static void	iwh_free_dma_mem(iwh_dma_t *);
366 
367 /*
368  * GLD specific operations
369  */
370 static int	iwh_m_stat(void *, uint_t, uint64_t *);
371 static int	iwh_m_start(void *);
372 static void	iwh_m_stop(void *);
373 static int	iwh_m_unicst(void *, const uint8_t *);
374 static int	iwh_m_multicst(void *, boolean_t, const uint8_t *);
375 static int	iwh_m_promisc(void *, boolean_t);
376 static mblk_t	*iwh_m_tx(void *, mblk_t *);
377 static void	iwh_m_ioctl(void *, queue_t *, mblk_t *);
378 static int	iwh_m_setprop(void *arg, const char *pr_name,
379     mac_prop_id_t wldp_pr_num, uint_t wldp_length, const void *wldp_buf);
380 static int	iwh_m_getprop(void *arg, const char *pr_name,
381     mac_prop_id_t wldp_pr_num, uint_t pr_flags, uint_t wldp_length,
382     void *wldp_buf, uint_t *perm);
383 
384 /*
385  * Supported rates for 802.11b/g modes (in 500Kbps unit).
386  */
387 static const struct ieee80211_rateset iwh_rateset_11b =
388 	{ 4, { 2, 4, 11, 22 } };
389 
390 static const struct ieee80211_rateset iwh_rateset_11g =
391 	{ 12, { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 } };
392 
393 /*
394  * Default 11n reates supported by this station.
395  */
396 extern struct ieee80211_htrateset ieee80211_rateset_11n;
397 
398 /*
399  * For mfthread only
400  */
401 extern pri_t minclsyspri;
402 
403 #define	DRV_NAME_SP	"iwh"
404 
405 /*
406  * Module Loading Data & Entry Points
407  */
408 DDI_DEFINE_STREAM_OPS(iwh_devops, nulldev, nulldev, iwh_attach,
409     iwh_detach, nodev, NULL, D_MP, NULL, iwh_quiesce);
410 
411 static struct modldrv iwh_modldrv = {
412 	&mod_driverops,
413 	"Intel(R) ShirleyPeak/EchoPeak driver(N)",
414 	&iwh_devops
415 };
416 
417 static struct modlinkage iwh_modlinkage = {
418 	MODREV_1,
419 	&iwh_modldrv,
420 	NULL
421 };
422 
423 int
424 _init(void)
425 {
426 	int status;
427 
428 	status = ddi_soft_state_init(&iwh_soft_state_p,
429 	    sizeof (iwh_sc_t), 1);
430 	if (status != DDI_SUCCESS) {
431 		return (status);
432 	}
433 
434 	mac_init_ops(&iwh_devops, DRV_NAME_SP);
435 	status = mod_install(&iwh_modlinkage);
436 	if (status != DDI_SUCCESS) {
437 		mac_fini_ops(&iwh_devops);
438 		ddi_soft_state_fini(&iwh_soft_state_p);
439 	}
440 
441 	return (status);
442 }
443 
444 int
445 _fini(void)
446 {
447 	int status;
448 
449 	status = mod_remove(&iwh_modlinkage);
450 	if (DDI_SUCCESS == status) {
451 		mac_fini_ops(&iwh_devops);
452 		ddi_soft_state_fini(&iwh_soft_state_p);
453 	}
454 
455 	return (status);
456 }
457 
458 int
459 _info(struct modinfo *mip)
460 {
461 	return (mod_info(&iwh_modlinkage, mip));
462 }
463 
464 /*
465  * Mac Call Back entries
466  */
467 mac_callbacks_t	iwh_m_callbacks = {
468 	MC_IOCTL | MC_SETPROP | MC_GETPROP,
469 	iwh_m_stat,
470 	iwh_m_start,
471 	iwh_m_stop,
472 	iwh_m_promisc,
473 	iwh_m_multicst,
474 	iwh_m_unicst,
475 	iwh_m_tx,
476 	iwh_m_ioctl,
477 	NULL,
478 	NULL,
479 	NULL,
480 	iwh_m_setprop,
481 	iwh_m_getprop
482 };
483 
484 #ifdef DEBUG
485 void
486 iwh_dbg(uint32_t flags, const char *fmt, ...)
487 {
488 	va_list	ap;
489 
490 	if (flags & iwh_dbg_flags) {
491 		va_start(ap, fmt);
492 		vcmn_err(CE_NOTE, fmt, ap);
493 		va_end(ap);
494 	}
495 }
496 #endif	/* DEBUG */
497 
498 /*
499  * device operations
500  */
501 int
502 iwh_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
503 {
504 	iwh_sc_t *sc;
505 	ieee80211com_t *ic;
506 	int instance, i;
507 	char strbuf[32];
508 	wifi_data_t wd = { 0 };
509 	mac_register_t *macp;
510 	int intr_type;
511 	int intr_count;
512 	int intr_actual;
513 	int err = DDI_FAILURE;
514 
515 	switch (cmd) {
516 	case DDI_ATTACH:
517 		break;
518 
519 	case DDI_RESUME:
520 		instance = ddi_get_instance(dip);
521 		sc = ddi_get_soft_state(iwh_soft_state_p,
522 		    instance);
523 		ASSERT(sc != NULL);
524 
525 		if (sc->sc_flags & IWH_F_RUNNING) {
526 			(void) iwh_init(sc);
527 		}
528 
529 		atomic_and_32(&sc->sc_flags, ~IWH_F_SUSPEND);
530 
531 		IWH_DBG((IWH_DEBUG_RESUME, "iwh_attach(): "
532 		    "resume\n"));
533 		return (DDI_SUCCESS);
534 
535 	default:
536 		goto attach_fail1;
537 	}
538 
539 	instance = ddi_get_instance(dip);
540 	err = ddi_soft_state_zalloc(iwh_soft_state_p, instance);
541 	if (err != DDI_SUCCESS) {
542 		cmn_err(CE_WARN, "iwh_attach(): "
543 		    "failed to allocate soft state\n");
544 		goto attach_fail1;
545 	}
546 
547 	sc = ddi_get_soft_state(iwh_soft_state_p, instance);
548 	ASSERT(sc != NULL);
549 
550 	sc->sc_dip = dip;
551 
552 	/*
553 	 * map configure space
554 	 */
555 	err = ddi_regs_map_setup(dip, 0, &sc->sc_cfg_base, 0, 0,
556 	    &iwh_reg_accattr, &sc->sc_cfg_handle);
557 	if (err != DDI_SUCCESS) {
558 		cmn_err(CE_WARN, "iwh_attach(): "
559 		    "failed to map config spaces regs\n");
560 		goto attach_fail2;
561 	}
562 
563 	sc->sc_dev_id = ddi_get16(sc->sc_cfg_handle,
564 	    (uint16_t *)(sc->sc_cfg_base + PCI_CONF_DEVID));
565 	if ((sc->sc_dev_id != 0x4232) &&
566 	    (sc->sc_dev_id != 0x4235) &&
567 	    (sc->sc_dev_id != 0x4236) &&
568 	    (sc->sc_dev_id != 0x4237) &&
569 	    (sc->sc_dev_id != 0x423a) &&
570 	    (sc->sc_dev_id != 0x423b) &&
571 	    (sc->sc_dev_id != 0x423c) &&
572 	    (sc->sc_dev_id != 0x423d)) {
573 		cmn_err(CE_WARN, "iwh_attach(): "
574 		    "Do not support this device\n");
575 		goto attach_fail3;
576 	}
577 
578 	iwh_init_ht_conf(sc);
579 	iwh_overwrite_11n_rateset(sc);
580 
581 	sc->sc_rev = ddi_get8(sc->sc_cfg_handle,
582 	    (uint8_t *)(sc->sc_cfg_base + PCI_CONF_REVID));
583 
584 	/*
585 	 * keep from disturbing C3 state of CPU
586 	 */
587 	ddi_put8(sc->sc_cfg_handle, (uint8_t *)(sc->sc_cfg_base +
588 	    PCI_CFG_RETRY_TIMEOUT), 0);
589 
590 	/*
591 	 * determine the size of buffer for frame and command to ucode
592 	 */
593 	sc->sc_clsz = ddi_get16(sc->sc_cfg_handle,
594 	    (uint16_t *)(sc->sc_cfg_base + PCI_CONF_CACHE_LINESZ));
595 	if (!sc->sc_clsz) {
596 		sc->sc_clsz = 16;
597 	}
598 	sc->sc_clsz = (sc->sc_clsz << 2);
599 
600 	sc->sc_dmabuf_sz = roundup(0x2000 + sizeof (struct ieee80211_frame) +
601 	    IEEE80211_MTU + IEEE80211_CRC_LEN +
602 	    (IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN +
603 	    IEEE80211_WEP_CRCLEN), sc->sc_clsz);
604 
605 	/*
606 	 * Map operating registers
607 	 */
608 	err = ddi_regs_map_setup(dip, 1, &sc->sc_base,
609 	    0, 0, &iwh_reg_accattr, &sc->sc_handle);
610 	if (err != DDI_SUCCESS) {
611 		cmn_err(CE_WARN, "iwh_attach(): "
612 		    "failed to map device regs\n");
613 		goto attach_fail3;
614 	}
615 
616 	/*
617 	 * this is used to differentiate type of hardware
618 	 */
619 	sc->sc_hw_rev = IWH_READ(sc, CSR_HW_REV);
620 
621 	err = ddi_intr_get_supported_types(dip, &intr_type);
622 	if ((err != DDI_SUCCESS) || (!(intr_type & DDI_INTR_TYPE_FIXED))) {
623 		cmn_err(CE_WARN, "iwh_attach(): "
624 		    "fixed type interrupt is not supported\n");
625 		goto attach_fail4;
626 	}
627 
628 	err = ddi_intr_get_nintrs(dip, DDI_INTR_TYPE_FIXED, &intr_count);
629 	if ((err != DDI_SUCCESS) || (intr_count != 1)) {
630 		cmn_err(CE_WARN, "iwh_attach(): "
631 		    "no fixed interrupts\n");
632 		goto attach_fail4;
633 	}
634 
635 	sc->sc_intr_htable = kmem_zalloc(sizeof (ddi_intr_handle_t), KM_SLEEP);
636 
637 	err = ddi_intr_alloc(dip, sc->sc_intr_htable, DDI_INTR_TYPE_FIXED, 0,
638 	    intr_count, &intr_actual, 0);
639 	if ((err != DDI_SUCCESS) || (intr_actual != 1)) {
640 		cmn_err(CE_WARN, "iwh_attach(): "
641 		    "ddi_intr_alloc() failed 0x%x\n", err);
642 		goto attach_fail5;
643 	}
644 
645 	err = ddi_intr_get_pri(sc->sc_intr_htable[0], &sc->sc_intr_pri);
646 	if (err != DDI_SUCCESS) {
647 		cmn_err(CE_WARN, "iwh_attach(): "
648 		    "ddi_intr_get_pri() failed 0x%x\n", err);
649 		goto attach_fail6;
650 	}
651 
652 	mutex_init(&sc->sc_glock, NULL, MUTEX_DRIVER,
653 	    DDI_INTR_PRI(sc->sc_intr_pri));
654 	mutex_init(&sc->sc_tx_lock, NULL, MUTEX_DRIVER,
655 	    DDI_INTR_PRI(sc->sc_intr_pri));
656 	mutex_init(&sc->sc_mt_lock, NULL, MUTEX_DRIVER,
657 	    DDI_INTR_PRI(sc->sc_intr_pri));
658 
659 	cv_init(&sc->sc_cmd_cv, NULL, CV_DRIVER, NULL);
660 	cv_init(&sc->sc_put_seg_cv, NULL, CV_DRIVER, NULL);
661 	cv_init(&sc->sc_ucode_cv, NULL, CV_DRIVER, NULL);
662 
663 	/*
664 	 * initialize the mfthread
665 	 */
666 	cv_init(&sc->sc_mt_cv, NULL, CV_DRIVER, NULL);
667 	sc->sc_mf_thread = NULL;
668 	sc->sc_mf_thread_switch = 0;
669 
670 	/*
671 	 * Allocate shared buffer for communication between driver and ucode.
672 	 */
673 	err = iwh_alloc_shared(sc);
674 	if (err != DDI_SUCCESS) {
675 		cmn_err(CE_WARN, "iwh_attach(): "
676 		    "failed to allocate shared page\n");
677 		goto attach_fail7;
678 	}
679 
680 	(void) memset(sc->sc_shared, 0, sizeof (iwh_shared_t));
681 
682 	/*
683 	 * Allocate keep warm page.
684 	 */
685 	err = iwh_alloc_kw(sc);
686 	if (err != DDI_SUCCESS) {
687 		cmn_err(CE_WARN, "iwh_attach(): "
688 		    "failed to allocate keep warm page\n");
689 		goto attach_fail8;
690 	}
691 
692 	/*
693 	 * Do some necessary hardware initializations.
694 	 */
695 	err = iwh_preinit(sc);
696 	if (err != IWH_SUCCESS) {
697 		cmn_err(CE_WARN, "iwh_attach(): "
698 		    "failed to initialize hardware\n");
699 		goto attach_fail9;
700 	}
701 
702 	/*
703 	 * get hardware configurations from eeprom
704 	 */
705 	err = iwh_eep_load(sc);
706 	if (err != IWH_SUCCESS) {
707 		cmn_err(CE_WARN, "iwh_attach(): "
708 		    "failed to load eeprom\n");
709 		goto attach_fail9;
710 	}
711 
712 	if (IWH_READ_EEP_SHORT(sc, EEP_VERSION) < 0x011a) {
713 		IWH_DBG((IWH_DEBUG_EEPROM, "iwh_attach(): "
714 		    "unsupported eeprom detected\n"));
715 		goto attach_fail9;
716 	}
717 
718 	/*
719 	 * get MAC address of this chipset
720 	 */
721 	iwh_get_mac_from_eep(sc);
722 
723 	/*
724 	 * calibration information from EEPROM
725 	 */
726 	sc->sc_eep_calib = (struct iwh_eep_calibration *)
727 	    iwh_eep_addr_trans(sc, EEP_CALIBRATION);
728 
729 	/*
730 	 * initialize TX and RX ring buffers
731 	 */
732 	err = iwh_ring_init(sc);
733 	if (err != DDI_SUCCESS) {
734 		cmn_err(CE_WARN, "iwh_attach(): "
735 		    "failed to allocate and initialize ring\n");
736 		goto attach_fail9;
737 	}
738 
739 	if ((0x423c == sc->sc_dev_id) || (0x423d == sc->sc_dev_id)) {
740 		sc->sc_hdr = (iwh_firmware_hdr_t *)iwh_fw_5150_bin;
741 	} else {
742 		sc->sc_hdr = (iwh_firmware_hdr_t *)iwh_fw_5000_bin;
743 	}
744 
745 	/*
746 	 * copy ucode to dma buffer
747 	 */
748 	err = iwh_alloc_fw_dma(sc);
749 	if (err != DDI_SUCCESS) {
750 		cmn_err(CE_WARN, "iwh_attach(): "
751 		    "failed to allocate firmware dma\n");
752 		goto attach_fail10;
753 	}
754 
755 	/*
756 	 * Initialize the wifi part, which will be used by
757 	 * 802.11 module
758 	 */
759 	ic = &sc->sc_ic;
760 	ic->ic_phytype  = IEEE80211_T_HT;
761 	ic->ic_opmode   = IEEE80211_M_STA; /* default to BSS mode */
762 	ic->ic_state    = IEEE80211_S_INIT;
763 	ic->ic_maxrssi  = 100; /* experimental number */
764 	ic->ic_caps = IEEE80211_C_SHPREAMBLE | IEEE80211_C_TXPMGT |
765 	    IEEE80211_C_PMGT | IEEE80211_C_SHSLOT;
766 
767 	/*
768 	 * Support WPA/WPA2
769 	 */
770 	ic->ic_caps |= IEEE80211_C_WPA;
771 
772 	/*
773 	 * Support QoS/WME
774 	 */
775 	ic->ic_caps |= IEEE80211_C_WME;
776 	ic->ic_wme.wme_update = iwh_wme_update;
777 
778 	/*
779 	 * Support 802.11n/HT
780 	 */
781 	if (sc->sc_ht_conf.ht_support) {
782 		ic->ic_htcaps = IEEE80211_HTC_HT |
783 		    IEEE80211_HTC_AMSDU;
784 		ic->ic_htcaps |= IEEE80211_HTCAP_MAXAMSDU_7935;
785 	}
786 
787 	/*
788 	 * set supported .11b and .11g rates
789 	 */
790 	ic->ic_sup_rates[IEEE80211_MODE_11B] = iwh_rateset_11b;
791 	ic->ic_sup_rates[IEEE80211_MODE_11G] = iwh_rateset_11g;
792 
793 	/*
794 	 * set supported .11b and .11g channels (1 through 11)
795 	 */
796 	for (i = 1; i <= 11; i++) {
797 		ic->ic_sup_channels[i].ich_freq =
798 		    ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ);
799 		ic->ic_sup_channels[i].ich_flags =
800 		    IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM |
801 		    IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ |
802 		    IEEE80211_CHAN_PASSIVE;
803 
804 		if (sc->sc_ht_conf.cap & HT_CAP_SUP_WIDTH) {
805 			ic->ic_sup_channels[i].ich_flags |=
806 			    IEEE80211_CHAN_HT40;
807 		} else {
808 			ic->ic_sup_channels[i].ich_flags |=
809 			    IEEE80211_CHAN_HT20;
810 		}
811 	}
812 
813 	ic->ic_ibss_chan = &ic->ic_sup_channels[0];
814 	ic->ic_xmit = iwh_send;
815 
816 	/*
817 	 * attach to 802.11 module
818 	 */
819 	ieee80211_attach(ic);
820 
821 	/*
822 	 * different instance has different WPA door
823 	 */
824 	(void) snprintf(ic->ic_wpadoor, MAX_IEEE80211STR, "%s_%s%d", WPA_DOOR,
825 	    ddi_driver_name(dip),
826 	    ddi_get_instance(dip));
827 
828 	/*
829 	 * Overwrite 80211 default configurations.
830 	 */
831 	iwh_overwrite_ic_default(sc);
832 
833 	/*
834 	 * initialize 802.11 module
835 	 */
836 	ieee80211_media_init(ic);
837 
838 	/*
839 	 * initialize default tx key
840 	 */
841 	ic->ic_def_txkey = 0;
842 
843 	err = ddi_intr_add_softint(dip, &sc->sc_soft_hdl, DDI_INTR_SOFTPRI_MAX,
844 	    iwh_rx_softintr, (caddr_t)sc);
845 	if (err != DDI_SUCCESS) {
846 		cmn_err(CE_WARN, "iwh_attach(): "
847 		    "add soft interrupt failed\n");
848 		goto attach_fail12;
849 	}
850 
851 	err = ddi_intr_add_handler(sc->sc_intr_htable[0], iwh_intr,
852 	    (caddr_t)sc, NULL);
853 	if (err != DDI_SUCCESS) {
854 		cmn_err(CE_WARN, "iwh_attach(): "
855 		    "ddi_intr_add_handle() failed\n");
856 		goto attach_fail13;
857 	}
858 
859 	err = ddi_intr_enable(sc->sc_intr_htable[0]);
860 	if (err != DDI_SUCCESS) {
861 		cmn_err(CE_WARN, "iwh_attach(): "
862 		    "ddi_intr_enable() failed\n");
863 		goto attach_fail14;
864 	}
865 
866 	/*
867 	 * Initialize pointer to device specific functions
868 	 */
869 	wd.wd_secalloc = WIFI_SEC_NONE;
870 	wd.wd_opmode = ic->ic_opmode;
871 	IEEE80211_ADDR_COPY(wd.wd_bssid, ic->ic_macaddr);
872 
873 	/*
874 	 * create relation to GLD
875 	 */
876 	macp = mac_alloc(MAC_VERSION);
877 	if (NULL == macp) {
878 		cmn_err(CE_WARN, "iwh_attach(): "
879 		    "failed to do mac_alloc()\n");
880 		goto attach_fail15;
881 	}
882 
883 	macp->m_type_ident	= MAC_PLUGIN_IDENT_WIFI;
884 	macp->m_driver		= sc;
885 	macp->m_dip		= dip;
886 	macp->m_src_addr	= ic->ic_macaddr;
887 	macp->m_callbacks	= &iwh_m_callbacks;
888 	macp->m_min_sdu		= 0;
889 	macp->m_max_sdu		= IEEE80211_MTU;
890 	macp->m_pdata		= &wd;
891 	macp->m_pdata_size	= sizeof (wd);
892 
893 	/*
894 	 * Register the macp to mac
895 	 */
896 	err = mac_register(macp, &ic->ic_mach);
897 	mac_free(macp);
898 	if (err != DDI_SUCCESS) {
899 		cmn_err(CE_WARN, "iwh_attach(): "
900 		    "failed to do mac_register()\n");
901 		goto attach_fail15;
902 	}
903 
904 	/*
905 	 * Create minor node of type DDI_NT_NET_WIFI
906 	 */
907 	(void) snprintf(strbuf, sizeof (strbuf), DRV_NAME_SP"%d", instance);
908 	err = ddi_create_minor_node(dip, strbuf, S_IFCHR,
909 	    instance + 1, DDI_NT_NET_WIFI, 0);
910 	if (err != DDI_SUCCESS) {
911 		cmn_err(CE_WARN, "iwh_attach(): "
912 		    "failed to do ddi_create_minor_node()\n");
913 	}
914 
915 	/*
916 	 * Notify link is down now
917 	 */
918 	mac_link_update(ic->ic_mach, LINK_STATE_DOWN);
919 
920 	/*
921 	 * create the mf thread to handle the link status,
922 	 * recovery fatal error, etc.
923 	 */
924 	sc->sc_mf_thread_switch = 1;
925 	if (NULL == sc->sc_mf_thread) {
926 		sc->sc_mf_thread = thread_create((caddr_t)NULL, 0,
927 		    iwh_thread, sc, 0, &p0, TS_RUN, minclsyspri);
928 	}
929 
930 	atomic_or_32(&sc->sc_flags, IWH_F_ATTACHED);
931 
932 	return (DDI_SUCCESS);
933 
934 attach_fail15:
935 	(void) ddi_intr_disable(sc->sc_intr_htable[0]);
936 
937 attach_fail14:
938 	(void) ddi_intr_remove_handler(sc->sc_intr_htable[0]);
939 
940 attach_fail13:
941 	(void) ddi_intr_remove_softint(sc->sc_soft_hdl);
942 	sc->sc_soft_hdl = NULL;
943 
944 attach_fail12:
945 	ieee80211_detach(ic);
946 
947 attach_fail11:
948 	iwh_free_fw_dma(sc);
949 
950 attach_fail10:
951 	iwh_ring_free(sc);
952 
953 attach_fail9:
954 	iwh_free_kw(sc);
955 
956 attach_fail8:
957 	iwh_free_shared(sc);
958 
959 attach_fail7:
960 	iwh_destroy_locks(sc);
961 
962 attach_fail6:
963 	(void) ddi_intr_free(sc->sc_intr_htable[0]);
964 
965 attach_fail5:
966 	kmem_free(sc->sc_intr_htable, sizeof (ddi_intr_handle_t));
967 
968 attach_fail4:
969 	ddi_regs_map_free(&sc->sc_handle);
970 
971 attach_fail3:
972 	ddi_regs_map_free(&sc->sc_cfg_handle);
973 
974 attach_fail2:
975 	ddi_soft_state_free(iwh_soft_state_p, instance);
976 
977 attach_fail1:
978 	return (DDI_FAILURE);
979 }
980 
981 int
982 iwh_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
983 {
984 	iwh_sc_t *sc;
985 	ieee80211com_t *ic;
986 	int err;
987 
988 	sc = ddi_get_soft_state(iwh_soft_state_p, ddi_get_instance(dip));
989 	ASSERT(sc != NULL);
990 	ic = &sc->sc_ic;
991 
992 	switch (cmd) {
993 	case DDI_DETACH:
994 		break;
995 
996 	case DDI_SUSPEND:
997 		atomic_and_32(&sc->sc_flags, ~IWH_F_HW_ERR_RECOVER);
998 		atomic_and_32(&sc->sc_flags, ~IWH_F_RATE_AUTO_CTL);
999 
1000 		atomic_or_32(&sc->sc_flags, IWH_F_SUSPEND);
1001 
1002 		if (sc->sc_flags & IWH_F_RUNNING) {
1003 			ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
1004 			iwh_stop(sc);
1005 		}
1006 
1007 		IWH_DBG((IWH_DEBUG_RESUME, "iwh_detach(): "
1008 		    "suspend\n"));
1009 		return (DDI_SUCCESS);
1010 
1011 	default:
1012 		return (DDI_FAILURE);
1013 	}
1014 
1015 	if (!(sc->sc_flags & IWH_F_ATTACHED)) {
1016 		return (DDI_FAILURE);
1017 	}
1018 
1019 	/*
1020 	 * Destroy the mf_thread
1021 	 */
1022 	sc->sc_mf_thread_switch = 0;
1023 
1024 	mutex_enter(&sc->sc_mt_lock);
1025 	while (sc->sc_mf_thread != NULL) {
1026 		if (cv_wait_sig(&sc->sc_mt_cv, &sc->sc_mt_lock) == 0) {
1027 			break;
1028 		}
1029 	}
1030 	mutex_exit(&sc->sc_mt_lock);
1031 
1032 	err = mac_disable(sc->sc_ic.ic_mach);
1033 	if (err != DDI_SUCCESS) {
1034 		return (err);
1035 	}
1036 
1037 	/*
1038 	 * stop chipset
1039 	 */
1040 	iwh_stop(sc);
1041 
1042 	DELAY(500000);
1043 
1044 	/*
1045 	 * release buffer for calibration
1046 	 */
1047 	iwh_release_calib_buffer(sc);
1048 
1049 	/*
1050 	 * Unregiste from GLD
1051 	 */
1052 	(void) mac_unregister(sc->sc_ic.ic_mach);
1053 
1054 	mutex_enter(&sc->sc_glock);
1055 	iwh_free_fw_dma(sc);
1056 	iwh_ring_free(sc);
1057 	iwh_free_kw(sc);
1058 	iwh_free_shared(sc);
1059 	mutex_exit(&sc->sc_glock);
1060 
1061 	(void) ddi_intr_disable(sc->sc_intr_htable[0]);
1062 	(void) ddi_intr_remove_handler(sc->sc_intr_htable[0]);
1063 	(void) ddi_intr_free(sc->sc_intr_htable[0]);
1064 	kmem_free(sc->sc_intr_htable, sizeof (ddi_intr_handle_t));
1065 
1066 	(void) ddi_intr_remove_softint(sc->sc_soft_hdl);
1067 	sc->sc_soft_hdl = NULL;
1068 
1069 	/*
1070 	 * detach from 80211 module
1071 	 */
1072 	ieee80211_detach(&sc->sc_ic);
1073 
1074 	iwh_destroy_locks(sc);
1075 
1076 	ddi_regs_map_free(&sc->sc_handle);
1077 	ddi_regs_map_free(&sc->sc_cfg_handle);
1078 	ddi_remove_minor_node(dip, NULL);
1079 	ddi_soft_state_free(iwh_soft_state_p, ddi_get_instance(dip));
1080 
1081 	return (DDI_SUCCESS);
1082 }
1083 
1084 /*
1085  * destroy all locks
1086  */
1087 static void
1088 iwh_destroy_locks(iwh_sc_t *sc)
1089 {
1090 	cv_destroy(&sc->sc_mt_cv);
1091 	cv_destroy(&sc->sc_cmd_cv);
1092 	cv_destroy(&sc->sc_put_seg_cv);
1093 	cv_destroy(&sc->sc_ucode_cv);
1094 	mutex_destroy(&sc->sc_mt_lock);
1095 	mutex_destroy(&sc->sc_tx_lock);
1096 	mutex_destroy(&sc->sc_glock);
1097 }
1098 
1099 /*
1100  * Allocate an area of memory and a DMA handle for accessing it
1101  */
1102 static int
1103 iwh_alloc_dma_mem(iwh_sc_t *sc, size_t memsize,
1104     ddi_dma_attr_t *dma_attr_p, ddi_device_acc_attr_t *acc_attr_p,
1105     uint_t dma_flags, iwh_dma_t *dma_p)
1106 {
1107 	caddr_t vaddr;
1108 	int err = DDI_FAILURE;
1109 
1110 	/*
1111 	 * Allocate handle
1112 	 */
1113 	err = ddi_dma_alloc_handle(sc->sc_dip, dma_attr_p,
1114 	    DDI_DMA_SLEEP, NULL, &dma_p->dma_hdl);
1115 	if (err != DDI_SUCCESS) {
1116 		dma_p->dma_hdl = NULL;
1117 		return (DDI_FAILURE);
1118 	}
1119 
1120 	/*
1121 	 * Allocate memory
1122 	 */
1123 	err = ddi_dma_mem_alloc(dma_p->dma_hdl, memsize, acc_attr_p,
1124 	    dma_flags & (DDI_DMA_CONSISTENT | DDI_DMA_STREAMING),
1125 	    DDI_DMA_SLEEP, NULL, &vaddr, &dma_p->alength, &dma_p->acc_hdl);
1126 	if (err != DDI_SUCCESS) {
1127 		ddi_dma_free_handle(&dma_p->dma_hdl);
1128 		dma_p->dma_hdl = NULL;
1129 		dma_p->acc_hdl = NULL;
1130 		return (DDI_FAILURE);
1131 	}
1132 
1133 	/*
1134 	 * Bind the two together
1135 	 */
1136 	dma_p->mem_va = vaddr;
1137 	err = ddi_dma_addr_bind_handle(dma_p->dma_hdl, NULL,
1138 	    vaddr, dma_p->alength, dma_flags, DDI_DMA_SLEEP, NULL,
1139 	    &dma_p->cookie, &dma_p->ncookies);
1140 	if (err != DDI_DMA_MAPPED) {
1141 		ddi_dma_mem_free(&dma_p->acc_hdl);
1142 		ddi_dma_free_handle(&dma_p->dma_hdl);
1143 		dma_p->acc_hdl = NULL;
1144 		dma_p->dma_hdl = NULL;
1145 		return (DDI_FAILURE);
1146 	}
1147 
1148 	dma_p->nslots = ~0U;
1149 	dma_p->size = ~0U;
1150 	dma_p->token = ~0U;
1151 	dma_p->offset = 0;
1152 	return (DDI_SUCCESS);
1153 }
1154 
1155 /*
1156  * Free one allocated area of DMAable memory
1157  */
1158 static void
1159 iwh_free_dma_mem(iwh_dma_t *dma_p)
1160 {
1161 	if (dma_p->dma_hdl != NULL) {
1162 		if (dma_p->ncookies) {
1163 			(void) ddi_dma_unbind_handle(dma_p->dma_hdl);
1164 			dma_p->ncookies = 0;
1165 		}
1166 		ddi_dma_free_handle(&dma_p->dma_hdl);
1167 		dma_p->dma_hdl = NULL;
1168 	}
1169 
1170 	if (dma_p->acc_hdl != NULL) {
1171 		ddi_dma_mem_free(&dma_p->acc_hdl);
1172 		dma_p->acc_hdl = NULL;
1173 	}
1174 }
1175 
1176 /*
1177  * copy ucode into dma buffers
1178  */
1179 static int
1180 iwh_alloc_fw_dma(iwh_sc_t *sc)
1181 {
1182 	int err = DDI_FAILURE;
1183 	iwh_dma_t *dma_p;
1184 	char *t;
1185 
1186 	/*
1187 	 * firmware image layout:
1188 	 * |HDR|<-TEXT->|<-DATA->|<-INIT_TEXT->|<-INIT_DATA->|<-BOOT->|
1189 	 */
1190 
1191 	/*
1192 	 * copy text of runtime ucode
1193 	 */
1194 	t = (char *)(sc->sc_hdr + 1);
1195 	err = iwh_alloc_dma_mem(sc, LE_32(sc->sc_hdr->textsz),
1196 	    &fw_dma_attr, &iwh_dma_accattr,
1197 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1198 	    &sc->sc_dma_fw_text);
1199 	if (err != DDI_SUCCESS) {
1200 		cmn_err(CE_WARN, "iwh_alloc_fw_dma(): "
1201 		    "failed to allocate text dma memory.\n");
1202 		goto fail;
1203 	}
1204 
1205 	dma_p = &sc->sc_dma_fw_text;
1206 
1207 	IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_fw_dma(): "
1208 	    "text[ncookies:%d addr:%lx size:%lx]\n",
1209 	    dma_p->ncookies, dma_p->cookie.dmac_address,
1210 	    dma_p->cookie.dmac_size));
1211 
1212 	bcopy(t, dma_p->mem_va, LE_32(sc->sc_hdr->textsz));
1213 
1214 	/*
1215 	 * copy data and bak-data of runtime ucode
1216 	 */
1217 	t += LE_32(sc->sc_hdr->textsz);
1218 	err = iwh_alloc_dma_mem(sc, LE_32(sc->sc_hdr->datasz),
1219 	    &fw_dma_attr, &iwh_dma_accattr,
1220 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1221 	    &sc->sc_dma_fw_data);
1222 	if (err != DDI_SUCCESS) {
1223 		cmn_err(CE_WARN, "iwh_alloc_fw_dma(): "
1224 		    "failed to allocate data dma memory\n");
1225 		goto fail;
1226 	}
1227 
1228 	dma_p = &sc->sc_dma_fw_data;
1229 
1230 	IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_fw_dma(): "
1231 	    "data[ncookies:%d addr:%lx size:%lx]\n",
1232 	    dma_p->ncookies, dma_p->cookie.dmac_address,
1233 	    dma_p->cookie.dmac_size));
1234 
1235 	bcopy(t, dma_p->mem_va, LE_32(sc->sc_hdr->datasz));
1236 
1237 	err = iwh_alloc_dma_mem(sc, LE_32(sc->sc_hdr->datasz),
1238 	    &fw_dma_attr, &iwh_dma_accattr,
1239 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1240 	    &sc->sc_dma_fw_data_bak);
1241 	if (err != DDI_SUCCESS) {
1242 		cmn_err(CE_WARN, "iwh_alloc_fw_dma(): "
1243 		    "failed to allocate data bakup dma memory\n");
1244 		goto fail;
1245 	}
1246 
1247 	dma_p = &sc->sc_dma_fw_data_bak;
1248 
1249 	IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_fw_dma(): "
1250 	    "data_bak[ncookies:%d addr:%lx "
1251 	    "size:%lx]\n",
1252 	    dma_p->ncookies, dma_p->cookie.dmac_address,
1253 	    dma_p->cookie.dmac_size));
1254 
1255 	bcopy(t, dma_p->mem_va, LE_32(sc->sc_hdr->datasz));
1256 
1257 	/*
1258 	 * copy text of init ucode
1259 	 */
1260 	t += LE_32(sc->sc_hdr->datasz);
1261 	err = iwh_alloc_dma_mem(sc, LE_32(sc->sc_hdr->init_textsz),
1262 	    &fw_dma_attr, &iwh_dma_accattr,
1263 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1264 	    &sc->sc_dma_fw_init_text);
1265 	if (err != DDI_SUCCESS) {
1266 		cmn_err(CE_WARN, "iwh_alloc_fw_dma(): "
1267 		    "failed to allocate init text dma memory\n");
1268 		goto fail;
1269 	}
1270 
1271 	dma_p = &sc->sc_dma_fw_init_text;
1272 
1273 	IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_fw_dma(): "
1274 	    "init_text[ncookies:%d addr:%lx "
1275 	    "size:%lx]\n",
1276 	    dma_p->ncookies, dma_p->cookie.dmac_address,
1277 	    dma_p->cookie.dmac_size));
1278 
1279 	bcopy(t, dma_p->mem_va, LE_32(sc->sc_hdr->init_textsz));
1280 
1281 	/*
1282 	 * copy data of init ucode
1283 	 */
1284 	t += LE_32(sc->sc_hdr->init_textsz);
1285 	err = iwh_alloc_dma_mem(sc, LE_32(sc->sc_hdr->init_datasz),
1286 	    &fw_dma_attr, &iwh_dma_accattr,
1287 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1288 	    &sc->sc_dma_fw_init_data);
1289 	if (err != DDI_SUCCESS) {
1290 		cmn_err(CE_WARN, "iwh_alloc_fw_dma(): "
1291 		    "failed to allocate init data dma memory\n");
1292 		goto fail;
1293 	}
1294 
1295 	dma_p = &sc->sc_dma_fw_init_data;
1296 
1297 	IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_fw_dma(): "
1298 	    "init_data[ncookies:%d addr:%lx "
1299 	    "size:%lx]\n",
1300 	    dma_p->ncookies, dma_p->cookie.dmac_address,
1301 	    dma_p->cookie.dmac_size));
1302 
1303 	bcopy(t, dma_p->mem_va, LE_32(sc->sc_hdr->init_datasz));
1304 
1305 	sc->sc_boot = t + LE_32(sc->sc_hdr->init_datasz);
1306 
1307 fail:
1308 	return (err);
1309 }
1310 
1311 static void
1312 iwh_free_fw_dma(iwh_sc_t *sc)
1313 {
1314 	iwh_free_dma_mem(&sc->sc_dma_fw_text);
1315 	iwh_free_dma_mem(&sc->sc_dma_fw_data);
1316 	iwh_free_dma_mem(&sc->sc_dma_fw_data_bak);
1317 	iwh_free_dma_mem(&sc->sc_dma_fw_init_text);
1318 	iwh_free_dma_mem(&sc->sc_dma_fw_init_data);
1319 }
1320 
1321 /*
1322  * Allocate a shared buffer between host and NIC.
1323  */
1324 static int
1325 iwh_alloc_shared(iwh_sc_t *sc)
1326 {
1327 #ifdef	DEBUG
1328 	iwh_dma_t *dma_p;
1329 #endif
1330 	int err = DDI_FAILURE;
1331 
1332 	/*
1333 	 * must be aligned on a 4K-page boundary
1334 	 */
1335 	err = iwh_alloc_dma_mem(sc, sizeof (iwh_shared_t),
1336 	    &sh_dma_attr, &iwh_dma_descattr,
1337 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1338 	    &sc->sc_dma_sh);
1339 	if (err != DDI_SUCCESS) {
1340 		goto fail;
1341 	}
1342 
1343 	sc->sc_shared = (iwh_shared_t *)sc->sc_dma_sh.mem_va;
1344 
1345 #ifdef	DEBUG
1346 	dma_p = &sc->sc_dma_sh;
1347 #endif
1348 	IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_shared(): "
1349 	    "sh[ncookies:%d addr:%lx size:%lx]\n",
1350 	    dma_p->ncookies, dma_p->cookie.dmac_address,
1351 	    dma_p->cookie.dmac_size));
1352 
1353 	return (err);
1354 
1355 fail:
1356 	iwh_free_shared(sc);
1357 	return (err);
1358 }
1359 
1360 static void
1361 iwh_free_shared(iwh_sc_t *sc)
1362 {
1363 	iwh_free_dma_mem(&sc->sc_dma_sh);
1364 }
1365 
1366 /*
1367  * Allocate a keep warm page.
1368  */
1369 static int
1370 iwh_alloc_kw(iwh_sc_t *sc)
1371 {
1372 #ifdef	DEBUG
1373 	iwh_dma_t *dma_p;
1374 #endif
1375 	int err = DDI_FAILURE;
1376 
1377 	/*
1378 	 * must be aligned on a 4K-page boundary
1379 	 */
1380 	err = iwh_alloc_dma_mem(sc, IWH_KW_SIZE,
1381 	    &kw_dma_attr, &iwh_dma_descattr,
1382 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1383 	    &sc->sc_dma_kw);
1384 	if (err != DDI_SUCCESS) {
1385 		goto fail;
1386 	}
1387 
1388 #ifdef	DEBUG
1389 	dma_p = &sc->sc_dma_kw;
1390 #endif
1391 	IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_kw(): "
1392 	    "kw[ncookies:%d addr:%lx size:%lx]\n",
1393 	    dma_p->ncookies, dma_p->cookie.dmac_address,
1394 	    dma_p->cookie.dmac_size));
1395 
1396 	return (err);
1397 
1398 fail:
1399 	iwh_free_kw(sc);
1400 	return (err);
1401 }
1402 
1403 static void
1404 iwh_free_kw(iwh_sc_t *sc)
1405 {
1406 	iwh_free_dma_mem(&sc->sc_dma_kw);
1407 }
1408 
1409 /*
1410  * initialize RX ring buffers
1411  */
1412 static int
1413 iwh_alloc_rx_ring(iwh_sc_t *sc)
1414 {
1415 	iwh_rx_ring_t *ring;
1416 	iwh_rx_data_t *data;
1417 #ifdef	DEBUG
1418 	iwh_dma_t *dma_p;
1419 #endif
1420 	int i, err = DDI_FAILURE;
1421 
1422 	ring = &sc->sc_rxq;
1423 	ring->cur = 0;
1424 
1425 	/*
1426 	 * allocate RX description ring buffer
1427 	 */
1428 	err = iwh_alloc_dma_mem(sc, RX_QUEUE_SIZE * sizeof (uint32_t),
1429 	    &ring_desc_dma_attr, &iwh_dma_descattr,
1430 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1431 	    &ring->dma_desc);
1432 	if (err != DDI_SUCCESS) {
1433 		IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_rx_ring(): "
1434 		    "dma alloc rx ring desc "
1435 		    "failed\n"));
1436 		goto fail;
1437 	}
1438 
1439 	ring->desc = (uint32_t *)ring->dma_desc.mem_va;
1440 #ifdef	DEBUG
1441 	dma_p = &ring->dma_desc;
1442 #endif
1443 	IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_rx_ring(): "
1444 	    "rx bd[ncookies:%d addr:%lx size:%lx]\n",
1445 	    dma_p->ncookies, dma_p->cookie.dmac_address,
1446 	    dma_p->cookie.dmac_size));
1447 
1448 	/*
1449 	 * Allocate Rx frame buffers.
1450 	 */
1451 	for (i = 0; i < RX_QUEUE_SIZE; i++) {
1452 		data = &ring->data[i];
1453 		err = iwh_alloc_dma_mem(sc, sc->sc_dmabuf_sz,
1454 		    &rx_buffer_dma_attr, &iwh_dma_accattr,
1455 		    DDI_DMA_READ | DDI_DMA_STREAMING,
1456 		    &data->dma_data);
1457 		if (err != DDI_SUCCESS) {
1458 			IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_rx_ring(): "
1459 			    "dma alloc rx ring "
1460 			    "buf[%d] failed\n", i));
1461 			goto fail;
1462 		}
1463 		/*
1464 		 * the physical address bit [8-36] are used,
1465 		 * instead of bit [0-31] in 3945.
1466 		 */
1467 		ring->desc[i] = (uint32_t)
1468 		    (data->dma_data.cookie.dmac_address >> 8);
1469 	}
1470 
1471 #ifdef	DEBUG
1472 	dma_p = &ring->data[0].dma_data;
1473 #endif
1474 	IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_rx_ring(): "
1475 	    "rx buffer[0][ncookies:%d addr:%lx "
1476 	    "size:%lx]\n",
1477 	    dma_p->ncookies, dma_p->cookie.dmac_address,
1478 	    dma_p->cookie.dmac_size));
1479 
1480 	IWH_DMA_SYNC(ring->dma_desc, DDI_DMA_SYNC_FORDEV);
1481 
1482 	return (err);
1483 
1484 fail:
1485 	iwh_free_rx_ring(sc);
1486 	return (err);
1487 }
1488 
1489 /*
1490  * disable RX ring
1491  */
1492 static void
1493 iwh_reset_rx_ring(iwh_sc_t *sc)
1494 {
1495 	int n;
1496 
1497 	iwh_mac_access_enter(sc);
1498 	IWH_WRITE(sc, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
1499 	for (n = 0; n < 2000; n++) {
1500 		if (IWH_READ(sc, FH_MEM_RSSR_RX_STATUS_REG) & (1 << 24)) {
1501 			break;
1502 		}
1503 		DELAY(1000);
1504 	}
1505 #ifdef DEBUG
1506 	if (2000 == n) {
1507 		IWH_DBG((IWH_DEBUG_DMA, "iwh_reset_rx_ring(): "
1508 		    "timeout resetting Rx ring\n"));
1509 	}
1510 #endif
1511 	iwh_mac_access_exit(sc);
1512 
1513 	sc->sc_rxq.cur = 0;
1514 }
1515 
1516 static void
1517 iwh_free_rx_ring(iwh_sc_t *sc)
1518 {
1519 	int i;
1520 
1521 	for (i = 0; i < RX_QUEUE_SIZE; i++) {
1522 		if (sc->sc_rxq.data[i].dma_data.dma_hdl) {
1523 			IWH_DMA_SYNC(sc->sc_rxq.data[i].dma_data,
1524 			    DDI_DMA_SYNC_FORCPU);
1525 		}
1526 
1527 		iwh_free_dma_mem(&sc->sc_rxq.data[i].dma_data);
1528 	}
1529 
1530 	if (sc->sc_rxq.dma_desc.dma_hdl) {
1531 		IWH_DMA_SYNC(sc->sc_rxq.dma_desc, DDI_DMA_SYNC_FORDEV);
1532 	}
1533 
1534 	iwh_free_dma_mem(&sc->sc_rxq.dma_desc);
1535 }
1536 
1537 /*
1538  * initialize TX ring buffers
1539  */
1540 static int
1541 iwh_alloc_tx_ring(iwh_sc_t *sc, iwh_tx_ring_t *ring,
1542     int slots, int qid)
1543 {
1544 	iwh_tx_data_t *data;
1545 	iwh_tx_desc_t *desc_h;
1546 	uint32_t paddr_desc_h;
1547 	iwh_cmd_t *cmd_h;
1548 	uint32_t paddr_cmd_h;
1549 #ifdef	DEBUG
1550 	iwh_dma_t *dma_p;
1551 #endif
1552 	int i, err = DDI_FAILURE;
1553 
1554 	ring->qid = qid;
1555 	ring->count = TFD_QUEUE_SIZE_MAX;
1556 	ring->window = slots;
1557 	ring->queued = 0;
1558 	ring->cur = 0;
1559 	ring->desc_cur = 0;
1560 
1561 	/*
1562 	 * allocate buffer for TX descriptor ring
1563 	 */
1564 	err = iwh_alloc_dma_mem(sc,
1565 	    TFD_QUEUE_SIZE_MAX * sizeof (iwh_tx_desc_t),
1566 	    &ring_desc_dma_attr, &iwh_dma_descattr,
1567 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1568 	    &ring->dma_desc);
1569 	if (err != DDI_SUCCESS) {
1570 		IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_tx_ring(): "
1571 		    "dma alloc tx ring desc[%d] "
1572 		    "failed\n", qid));
1573 		goto fail;
1574 	}
1575 
1576 #ifdef	DEBUG
1577 	dma_p = &ring->dma_desc;
1578 #endif
1579 	IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_tx_ring(): "
1580 	    "tx bd[ncookies:%d addr:%lx size:%lx]\n",
1581 	    dma_p->ncookies, dma_p->cookie.dmac_address,
1582 	    dma_p->cookie.dmac_size));
1583 
1584 	desc_h = (iwh_tx_desc_t *)ring->dma_desc.mem_va;
1585 	paddr_desc_h = ring->dma_desc.cookie.dmac_address;
1586 
1587 	/*
1588 	 * allocate buffer for ucode command
1589 	 */
1590 	err = iwh_alloc_dma_mem(sc,
1591 	    TFD_QUEUE_SIZE_MAX * sizeof (iwh_cmd_t),
1592 	    &cmd_dma_attr, &iwh_dma_accattr,
1593 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1594 	    &ring->dma_cmd);
1595 	if (err != DDI_SUCCESS) {
1596 		IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_tx_ring(): "
1597 		    "dma alloc tx ring cmd[%d]"
1598 		    " failed\n", qid));
1599 		goto fail;
1600 	}
1601 
1602 #ifdef	DEBUG
1603 	dma_p = &ring->dma_cmd;
1604 #endif
1605 	IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_tx_ring(): "
1606 	    "tx cmd[ncookies:%d addr:%lx size:%lx]\n",
1607 	    dma_p->ncookies, dma_p->cookie.dmac_address,
1608 	    dma_p->cookie.dmac_size));
1609 
1610 	cmd_h = (iwh_cmd_t *)ring->dma_cmd.mem_va;
1611 	paddr_cmd_h = ring->dma_cmd.cookie.dmac_address;
1612 
1613 	/*
1614 	 * Allocate Tx frame buffers.
1615 	 */
1616 	ring->data = kmem_zalloc(sizeof (iwh_tx_data_t) * TFD_QUEUE_SIZE_MAX,
1617 	    KM_NOSLEEP);
1618 	if (NULL == ring->data) {
1619 		IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_tx_ring(): "
1620 		    "could not allocate "
1621 		    "tx data slots\n"));
1622 		goto fail;
1623 	}
1624 
1625 	for (i = 0; i < TFD_QUEUE_SIZE_MAX; i++) {
1626 		data = &ring->data[i];
1627 		err = iwh_alloc_dma_mem(sc, sc->sc_dmabuf_sz,
1628 		    &tx_buffer_dma_attr, &iwh_dma_accattr,
1629 		    DDI_DMA_WRITE | DDI_DMA_STREAMING,
1630 		    &data->dma_data);
1631 		if (err != DDI_SUCCESS) {
1632 			IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_tx_ring(): "
1633 			    "dma alloc tx "
1634 			    "ring buf[%d] failed\n", i));
1635 			goto fail;
1636 		}
1637 
1638 		data->desc = desc_h + i;
1639 		data->paddr_desc = paddr_desc_h +
1640 		    _PTRDIFF(data->desc, desc_h);
1641 		data->cmd = cmd_h +  i;
1642 		data->paddr_cmd = paddr_cmd_h +
1643 		    _PTRDIFF(data->cmd, cmd_h);
1644 	}
1645 #ifdef	DEBUG
1646 	dma_p = &ring->data[0].dma_data;
1647 #endif
1648 	IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_tx_ring(): "
1649 	    "tx buffer[0][ncookies:%d addr:%lx "
1650 	    "size:%lx]\n",
1651 	    dma_p->ncookies, dma_p->cookie.dmac_address,
1652 	    dma_p->cookie.dmac_size));
1653 
1654 	return (err);
1655 
1656 fail:
1657 	iwh_free_tx_ring(ring);
1658 
1659 	return (err);
1660 }
1661 
1662 /*
1663  * disable TX ring
1664  */
1665 static void
1666 iwh_reset_tx_ring(iwh_sc_t *sc, iwh_tx_ring_t *ring)
1667 {
1668 	iwh_tx_data_t *data;
1669 	int i, n;
1670 
1671 	iwh_mac_access_enter(sc);
1672 
1673 	IWH_WRITE(sc, IWH_FH_TCSR_CHNL_TX_CONFIG_REG(ring->qid), 0);
1674 	for (n = 0; n < 200; n++) {
1675 		if (IWH_READ(sc, IWH_FH_TSSR_TX_STATUS_REG) &
1676 		    IWH_FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ring->qid)) {
1677 			break;
1678 		}
1679 		DELAY(10);
1680 	}
1681 
1682 #ifdef	DEBUG
1683 	if (200 == n) {
1684 		IWH_DBG((IWH_DEBUG_DMA, "iwh_reset_tx_ring(): "
1685 		    "timeout reset tx ring %d\n",
1686 		    ring->qid));
1687 	}
1688 #endif
1689 
1690 	iwh_mac_access_exit(sc);
1691 
1692 	/*
1693 	 * by pass, if it's quiesce
1694 	 */
1695 	if (!(sc->sc_flags & IWH_F_QUIESCED)) {
1696 		for (i = 0; i < ring->count; i++) {
1697 			data = &ring->data[i];
1698 			IWH_DMA_SYNC(data->dma_data, DDI_DMA_SYNC_FORDEV);
1699 		}
1700 	}
1701 
1702 	ring->queued = 0;
1703 	ring->cur = 0;
1704 	ring->desc_cur = 0;
1705 }
1706 
1707 static void
1708 iwh_free_tx_ring(iwh_tx_ring_t *ring)
1709 {
1710 	int i;
1711 
1712 	if (ring->dma_desc.dma_hdl != NULL) {
1713 		IWH_DMA_SYNC(ring->dma_desc, DDI_DMA_SYNC_FORDEV);
1714 	}
1715 	iwh_free_dma_mem(&ring->dma_desc);
1716 
1717 	if (ring->dma_cmd.dma_hdl != NULL) {
1718 		IWH_DMA_SYNC(ring->dma_cmd, DDI_DMA_SYNC_FORDEV);
1719 	}
1720 	iwh_free_dma_mem(&ring->dma_cmd);
1721 
1722 	if (ring->data != NULL) {
1723 		for (i = 0; i < ring->count; i++) {
1724 			if (ring->data[i].dma_data.dma_hdl) {
1725 				IWH_DMA_SYNC(ring->data[i].dma_data,
1726 				    DDI_DMA_SYNC_FORDEV);
1727 			}
1728 			iwh_free_dma_mem(&ring->data[i].dma_data);
1729 		}
1730 		kmem_free(ring->data, ring->count * sizeof (iwh_tx_data_t));
1731 	}
1732 }
1733 
1734 /*
1735  * initialize TX and RX ring
1736  */
1737 static int
1738 iwh_ring_init(iwh_sc_t *sc)
1739 {
1740 	int i, err = DDI_FAILURE;
1741 
1742 	for (i = 0; i < IWH_NUM_QUEUES; i++) {
1743 		if (IWH_CMD_QUEUE_NUM == i) {
1744 			continue;
1745 		}
1746 
1747 		err = iwh_alloc_tx_ring(sc, &sc->sc_txq[i], TFD_TX_CMD_SLOTS,
1748 		    i);
1749 		if (err != DDI_SUCCESS) {
1750 			goto fail;
1751 		}
1752 	}
1753 
1754 	/*
1755 	 * initialize command queue
1756 	 */
1757 	err = iwh_alloc_tx_ring(sc, &sc->sc_txq[IWH_CMD_QUEUE_NUM],
1758 	    TFD_CMD_SLOTS, IWH_CMD_QUEUE_NUM);
1759 	if (err != DDI_SUCCESS) {
1760 		goto fail;
1761 	}
1762 
1763 	err = iwh_alloc_rx_ring(sc);
1764 	if (err != DDI_SUCCESS) {
1765 		goto fail;
1766 	}
1767 
1768 fail:
1769 	return (err);
1770 }
1771 
1772 static void
1773 iwh_ring_free(iwh_sc_t *sc)
1774 {
1775 	int i = IWH_NUM_QUEUES;
1776 
1777 	iwh_free_rx_ring(sc);
1778 	while (--i >= 0) {
1779 		iwh_free_tx_ring(&sc->sc_txq[i]);
1780 	}
1781 }
1782 
1783 /* ARGSUSED */
1784 static ieee80211_node_t *
1785 iwh_node_alloc(ieee80211com_t *ic)
1786 {
1787 	iwh_amrr_t *amrr;
1788 
1789 	amrr = kmem_zalloc(sizeof (iwh_amrr_t), KM_SLEEP);
1790 	if (NULL == amrr) {
1791 		cmn_err(CE_WARN, "iwh_node_alloc(): "
1792 		    "failed to allocate memory for amrr structure\n");
1793 		return (NULL);
1794 	}
1795 
1796 	iwh_amrr_init(amrr);
1797 
1798 	return (&amrr->in);
1799 }
1800 
1801 static void
1802 iwh_node_free(ieee80211_node_t *in)
1803 {
1804 	ieee80211com_t *ic;
1805 
1806 	if ((NULL == in) ||
1807 	    (NULL == in->in_ic)) {
1808 		cmn_err(CE_WARN, "iwh_node_free() "
1809 		    "Got a NULL point from Net80211 module\n");
1810 		return;
1811 	}
1812 	ic = in->in_ic;
1813 
1814 	if (ic->ic_node_cleanup != NULL) {
1815 		ic->ic_node_cleanup(in);
1816 	}
1817 
1818 	if (in->in_wpa_ie != NULL) {
1819 		ieee80211_free(in->in_wpa_ie);
1820 	}
1821 
1822 	if (in->in_wme_ie != NULL) {
1823 		ieee80211_free(in->in_wme_ie);
1824 	}
1825 
1826 	if (in->in_htcap_ie != NULL) {
1827 		ieee80211_free(in->in_htcap_ie);
1828 	}
1829 
1830 	kmem_free(in, sizeof (iwh_amrr_t));
1831 }
1832 
1833 /*
1834  * change station's state. this function will be invoked by 80211 module
1835  * when need to change staton's state.
1836  */
1837 static int
1838 iwh_newstate(ieee80211com_t *ic, enum ieee80211_state nstate, int arg)
1839 {
1840 	iwh_sc_t *sc;
1841 	ieee80211_node_t *in;
1842 	enum ieee80211_state ostate;
1843 	iwh_add_sta_t node;
1844 	iwh_amrr_t *amrr;
1845 	uint8_t r;
1846 	int i, err = IWH_FAIL;
1847 
1848 	if (NULL == ic) {
1849 		return (err);
1850 	}
1851 	sc = (iwh_sc_t *)ic;
1852 	in = ic->ic_bss;
1853 	ostate = ic->ic_state;
1854 
1855 	mutex_enter(&sc->sc_glock);
1856 
1857 	switch (nstate) {
1858 	case IEEE80211_S_SCAN:
1859 		switch (ostate) {
1860 		case IEEE80211_S_INIT:
1861 			atomic_or_32(&sc->sc_flags, IWH_F_SCANNING);
1862 			iwh_set_led(sc, 2, 10, 2);
1863 
1864 			/*
1865 			 * clear association to receive beacons from
1866 			 * all BSS'es
1867 			 */
1868 			sc->sc_config.assoc_id = 0;
1869 			sc->sc_config.filter_flags &=
1870 			    ~LE_32(RXON_FILTER_ASSOC_MSK);
1871 
1872 			IWH_DBG((IWH_DEBUG_80211, "iwh_newstate(): "
1873 			    "config chan %d "
1874 			    "flags %x filter_flags %x\n",
1875 			    LE_16(sc->sc_config.chan),
1876 			    LE_32(sc->sc_config.flags),
1877 			    LE_32(sc->sc_config.filter_flags)));
1878 
1879 			err = iwh_cmd(sc, REPLY_RXON, &sc->sc_config,
1880 			    sizeof (iwh_rxon_cmd_t), 1);
1881 			if (err != IWH_SUCCESS) {
1882 				cmn_err(CE_WARN, "iwh_newstate(): "
1883 				    "could not clear association\n");
1884 				atomic_and_32(&sc->sc_flags, ~IWH_F_SCANNING);
1885 				mutex_exit(&sc->sc_glock);
1886 				return (err);
1887 			}
1888 
1889 			/*
1890 			 * add broadcast node to send probe request
1891 			 */
1892 			(void) memset(&node, 0, sizeof (node));
1893 			(void) memset(&node.sta.addr, 0xff, IEEE80211_ADDR_LEN);
1894 			node.sta.sta_id = IWH_BROADCAST_ID;
1895 			err = iwh_cmd(sc, REPLY_ADD_STA, &node,
1896 			    sizeof (node), 1);
1897 			if (err != IWH_SUCCESS) {
1898 				cmn_err(CE_WARN, "iwh_newstate(): "
1899 				    "could not add broadcast node\n");
1900 				atomic_and_32(&sc->sc_flags, ~IWH_F_SCANNING);
1901 				mutex_exit(&sc->sc_glock);
1902 				return (err);
1903 			}
1904 			break;
1905 		case IEEE80211_S_SCAN:
1906 			mutex_exit(&sc->sc_glock);
1907 			/* step to next channel before actual FW scan */
1908 			err = sc->sc_newstate(ic, nstate, arg);
1909 			mutex_enter(&sc->sc_glock);
1910 			if ((err != 0) || ((err = iwh_scan(sc)) != 0)) {
1911 				cmn_err(CE_WARN, "iwh_newstate(): "
1912 				    "could not initiate scan\n");
1913 				atomic_and_32(&sc->sc_flags, ~IWH_F_SCANNING);
1914 				ieee80211_cancel_scan(ic);
1915 			}
1916 			mutex_exit(&sc->sc_glock);
1917 			return (err);
1918 		default:
1919 			break;
1920 		}
1921 		sc->sc_clk = 0;
1922 		break;
1923 
1924 	case IEEE80211_S_AUTH:
1925 		if (ostate == IEEE80211_S_SCAN) {
1926 			atomic_and_32(&sc->sc_flags, ~IWH_F_SCANNING);
1927 		}
1928 
1929 		/*
1930 		 * reset state to handle reassociations correctly
1931 		 */
1932 		sc->sc_config.assoc_id = 0;
1933 		sc->sc_config.filter_flags &= ~LE_32(RXON_FILTER_ASSOC_MSK);
1934 
1935 		/*
1936 		 * before sending authentication and association request frame,
1937 		 * we need do something in the hardware, such as setting the
1938 		 * channel same to the target AP...
1939 		 */
1940 		if ((err = iwh_hw_set_before_auth(sc)) != 0) {
1941 			IWH_DBG((IWH_DEBUG_80211, "iwh_newstate(): "
1942 			    "could not send authentication request\n"));
1943 			mutex_exit(&sc->sc_glock);
1944 			return (err);
1945 		}
1946 		break;
1947 
1948 	case IEEE80211_S_RUN:
1949 		if (ostate == IEEE80211_S_SCAN) {
1950 			atomic_and_32(&sc->sc_flags, ~IWH_F_SCANNING);
1951 		}
1952 
1953 		if (IEEE80211_M_MONITOR == ic->ic_opmode) {
1954 			/*
1955 			 * let LED blink when monitoring
1956 			 */
1957 			iwh_set_led(sc, 2, 10, 10);
1958 			break;
1959 		}
1960 
1961 		IWH_DBG((IWH_DEBUG_80211, "iwh_newstate(): "
1962 		    "associated.\n"));
1963 
1964 		err = iwh_run_state_config(sc);
1965 		if (err != IWH_SUCCESS) {
1966 			cmn_err(CE_WARN, "iwh_newstate(): "
1967 			    "failed to set up association\n");
1968 			mutex_exit(&sc->sc_glock);
1969 			return (err);
1970 		}
1971 
1972 		/*
1973 		 * start automatic rate control
1974 		 */
1975 		if ((in->in_flags & IEEE80211_NODE_HT) &&
1976 		    (sc->sc_ht_conf.ht_support) &&
1977 		    (in->in_htrates.rs_nrates > 0) &&
1978 		    (in->in_htrates.rs_nrates <= IEEE80211_HTRATE_MAXSIZE)) {
1979 			amrr = (iwh_amrr_t *)in;
1980 
1981 			for (i = in->in_htrates.rs_nrates - 1; i > 0; i--) {
1982 
1983 				r = in->in_htrates.rs_rates[i] &
1984 				    IEEE80211_RATE_VAL;
1985 				if ((r != 0) && (r <= 0xd) &&
1986 				    (sc->sc_ht_conf.tx_support_mcs[r/8] &
1987 				    (1 << (r%8)))) {
1988 					amrr->ht_mcs_idx = r;
1989 					atomic_or_32(&sc->sc_flags,
1990 					    IWH_F_RATE_AUTO_CTL);
1991 					break;
1992 				}
1993 			}
1994 		} else {
1995 			if (IEEE80211_FIXED_RATE_NONE == ic->ic_fixed_rate) {
1996 				atomic_or_32(&sc->sc_flags,
1997 				    IWH_F_RATE_AUTO_CTL);
1998 
1999 				/*
2000 				 * set rate to some reasonable initial value
2001 				 */
2002 				i = in->in_rates.ir_nrates - 1;
2003 				while (i > 0 && IEEE80211_RATE(i) > 72) {
2004 					i--;
2005 				}
2006 				in->in_txrate = i;
2007 
2008 			} else {
2009 				atomic_and_32(&sc->sc_flags,
2010 				    ~IWH_F_RATE_AUTO_CTL);
2011 			}
2012 		}
2013 
2014 		/*
2015 		 * set LED on after associated
2016 		 */
2017 		iwh_set_led(sc, 2, 0, 1);
2018 		break;
2019 
2020 	case IEEE80211_S_INIT:
2021 		if (ostate == IEEE80211_S_SCAN) {
2022 			atomic_and_32(&sc->sc_flags, ~IWH_F_SCANNING);
2023 		}
2024 		/*
2025 		 * set LED off after init
2026 		 */
2027 		iwh_set_led(sc, 2, 1, 0);
2028 		break;
2029 
2030 	case IEEE80211_S_ASSOC:
2031 		if (ostate == IEEE80211_S_SCAN) {
2032 			atomic_and_32(&sc->sc_flags, ~IWH_F_SCANNING);
2033 		}
2034 		break;
2035 	}
2036 
2037 	mutex_exit(&sc->sc_glock);
2038 
2039 	return (sc->sc_newstate(ic, nstate, arg));
2040 }
2041 
2042 /*
2043  * exclusive access to mac begin.
2044  */
2045 static void
2046 iwh_mac_access_enter(iwh_sc_t *sc)
2047 {
2048 	uint32_t tmp;
2049 	int n;
2050 
2051 	tmp = IWH_READ(sc, CSR_GP_CNTRL);
2052 	IWH_WRITE(sc, CSR_GP_CNTRL,
2053 	    tmp | CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
2054 
2055 	/*
2056 	 * wait until we succeed
2057 	 */
2058 	for (n = 0; n < 1000; n++) {
2059 		if ((IWH_READ(sc, CSR_GP_CNTRL) &
2060 		    (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY |
2061 		    CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP)) ==
2062 		    CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN) {
2063 			break;
2064 		}
2065 		DELAY(10);
2066 	}
2067 
2068 #ifdef	DEBUG
2069 	if (1000 == n) {
2070 		IWH_DBG((IWH_DEBUG_PIO, "iwh_mac_access_enter(): "
2071 		    "could not lock memory\n"));
2072 	}
2073 #endif
2074 }
2075 
2076 /*
2077  * exclusive access to mac end.
2078  */
2079 static void
2080 iwh_mac_access_exit(iwh_sc_t *sc)
2081 {
2082 	uint32_t tmp = IWH_READ(sc, CSR_GP_CNTRL);
2083 	IWH_WRITE(sc, CSR_GP_CNTRL,
2084 	    tmp & ~CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
2085 }
2086 
2087 /*
2088  * this function defined here for future use.
2089  * static uint32_t
2090  * iwh_mem_read(iwh_sc_t *sc, uint32_t addr)
2091  * {
2092  * 	IWH_WRITE(sc, HBUS_TARG_MEM_RADDR, addr);
2093  * 	return (IWH_READ(sc, HBUS_TARG_MEM_RDAT));
2094  * }
2095  */
2096 
2097 /*
2098  * write mac memory
2099  */
2100 static void
2101 iwh_mem_write(iwh_sc_t *sc, uint32_t addr, uint32_t data)
2102 {
2103 	IWH_WRITE(sc, HBUS_TARG_MEM_WADDR, addr);
2104 	IWH_WRITE(sc, HBUS_TARG_MEM_WDAT, data);
2105 }
2106 
2107 /*
2108  * read mac register
2109  */
2110 static uint32_t
2111 iwh_reg_read(iwh_sc_t *sc, uint32_t addr)
2112 {
2113 	IWH_WRITE(sc, HBUS_TARG_PRPH_RADDR, addr | (3 << 24));
2114 	return (IWH_READ(sc, HBUS_TARG_PRPH_RDAT));
2115 }
2116 
2117 /*
2118  * write mac register
2119  */
2120 static void
2121 iwh_reg_write(iwh_sc_t *sc, uint32_t addr, uint32_t data)
2122 {
2123 	IWH_WRITE(sc, HBUS_TARG_PRPH_WADDR, addr | (3 << 24));
2124 	IWH_WRITE(sc, HBUS_TARG_PRPH_WDAT, data);
2125 }
2126 
2127 
2128 /*
2129  * steps of loading ucode:
2130  * load init ucode=>init alive=>calibrate=>
2131  * receive calibration result=>reinitialize NIC=>
2132  * load runtime ucode=>runtime alive=>
2133  * send calibration result=>running.
2134  */
2135 static int
2136 iwh_load_init_firmware(iwh_sc_t *sc)
2137 {
2138 	int err = IWH_FAIL;
2139 	clock_t	clk;
2140 
2141 	atomic_and_32(&sc->sc_flags, ~IWH_F_PUT_SEG);
2142 
2143 	/*
2144 	 * load init_text section of uCode to hardware
2145 	 */
2146 	err = iwh_put_seg_fw(sc, sc->sc_dma_fw_init_text.cookie.dmac_address,
2147 	    RTC_INST_LOWER_BOUND, sc->sc_dma_fw_init_text.cookie.dmac_size);
2148 	if (err != IWH_SUCCESS) {
2149 		cmn_err(CE_WARN, "iwh_load_init_firmware(): "
2150 		    "failed to write init uCode.\n");
2151 		return (err);
2152 	}
2153 
2154 	clk = ddi_get_lbolt() + drv_usectohz(1000000);
2155 
2156 	/*
2157 	 * wait loading init_text until completed or timeout
2158 	 */
2159 	while (!(sc->sc_flags & IWH_F_PUT_SEG)) {
2160 		if (cv_timedwait(&sc->sc_put_seg_cv, &sc->sc_glock, clk) < 0) {
2161 			break;
2162 		}
2163 	}
2164 
2165 	if (!(sc->sc_flags & IWH_F_PUT_SEG)) {
2166 		cmn_err(CE_WARN, "iwh_load_init_firmware(): "
2167 		    "timeout waiting for init uCode load.\n");
2168 		return (IWH_FAIL);
2169 	}
2170 
2171 	atomic_and_32(&sc->sc_flags, ~IWH_F_PUT_SEG);
2172 
2173 	/*
2174 	 * load init_data section of uCode to hardware
2175 	 */
2176 	err = iwh_put_seg_fw(sc, sc->sc_dma_fw_init_data.cookie.dmac_address,
2177 	    RTC_DATA_LOWER_BOUND, sc->sc_dma_fw_init_data.cookie.dmac_size);
2178 	if (err != IWH_SUCCESS) {
2179 		cmn_err(CE_WARN, "iwh_load_init_firmware(): "
2180 		    "failed to write init_data uCode.\n");
2181 		return (err);
2182 	}
2183 
2184 	clk = ddi_get_lbolt() + drv_usectohz(1000000);
2185 
2186 	/*
2187 	 * wait loading init_data until completed or timeout
2188 	 */
2189 	while (!(sc->sc_flags & IWH_F_PUT_SEG)) {
2190 		if (cv_timedwait(&sc->sc_put_seg_cv, &sc->sc_glock, clk) < 0) {
2191 			break;
2192 		}
2193 	}
2194 
2195 	if (!(sc->sc_flags & IWH_F_PUT_SEG)) {
2196 		cmn_err(CE_WARN, "iwh_load_init_firmware(): "
2197 		    "timeout waiting for init_data uCode load.\n");
2198 		return (IWH_FAIL);
2199 	}
2200 
2201 	atomic_and_32(&sc->sc_flags, ~IWH_F_PUT_SEG);
2202 
2203 	return (err);
2204 }
2205 
2206 static int
2207 iwh_load_run_firmware(iwh_sc_t *sc)
2208 {
2209 	int err = IWH_FAIL;
2210 	clock_t	clk;
2211 
2212 	atomic_and_32(&sc->sc_flags, ~IWH_F_PUT_SEG);
2213 
2214 	/*
2215 	 * load init_text section of uCode to hardware
2216 	 */
2217 	err = iwh_put_seg_fw(sc, sc->sc_dma_fw_text.cookie.dmac_address,
2218 	    RTC_INST_LOWER_BOUND, sc->sc_dma_fw_text.cookie.dmac_size);
2219 	if (err != IWH_SUCCESS) {
2220 		cmn_err(CE_WARN, "iwh_load_run_firmware(): "
2221 		    "failed to write run uCode.\n");
2222 		return (err);
2223 	}
2224 
2225 	clk = ddi_get_lbolt() + drv_usectohz(1000000);
2226 
2227 	/*
2228 	 * wait loading run_text until completed or timeout
2229 	 */
2230 	while (!(sc->sc_flags & IWH_F_PUT_SEG)) {
2231 		if (cv_timedwait(&sc->sc_put_seg_cv, &sc->sc_glock, clk) < 0) {
2232 			break;
2233 		}
2234 	}
2235 
2236 	if (!(sc->sc_flags & IWH_F_PUT_SEG)) {
2237 		cmn_err(CE_WARN, "iwh_load_run_firmware(): "
2238 		    "timeout waiting for run uCode load.\n");
2239 		return (IWH_FAIL);
2240 	}
2241 
2242 	atomic_and_32(&sc->sc_flags, ~IWH_F_PUT_SEG);
2243 
2244 	/*
2245 	 * load run_data section of uCode to hardware
2246 	 */
2247 	err = iwh_put_seg_fw(sc, sc->sc_dma_fw_data_bak.cookie.dmac_address,
2248 	    RTC_DATA_LOWER_BOUND, sc->sc_dma_fw_data.cookie.dmac_size);
2249 	if (err != IWH_SUCCESS) {
2250 		cmn_err(CE_WARN, "iwh_load_run_firmware(): "
2251 		    "failed to write run_data uCode.\n");
2252 		return (err);
2253 	}
2254 
2255 	clk = ddi_get_lbolt() + drv_usectohz(1000000);
2256 
2257 	/*
2258 	 * wait loading run_data until completed or timeout
2259 	 */
2260 	while (!(sc->sc_flags & IWH_F_PUT_SEG)) {
2261 		if (cv_timedwait(&sc->sc_put_seg_cv, &sc->sc_glock, clk) < 0) {
2262 			break;
2263 		}
2264 	}
2265 
2266 	if (!(sc->sc_flags & IWH_F_PUT_SEG)) {
2267 		cmn_err(CE_WARN, "iwh_load_run_firmware(): "
2268 		    "timeout waiting for run_data uCode load.\n");
2269 		return (IWH_FAIL);
2270 	}
2271 
2272 	atomic_and_32(&sc->sc_flags, ~IWH_F_PUT_SEG);
2273 
2274 	return (err);
2275 }
2276 
2277 /*
2278  * this function will be invoked to receive phy information
2279  * when a frame is received.
2280  */
2281 static void
2282 iwh_rx_phy_intr(iwh_sc_t *sc, iwh_rx_desc_t *desc)
2283 {
2284 
2285 	sc->sc_rx_phy_res.flag = 1;
2286 
2287 	bcopy((uint8_t *)(desc + 1), sc->sc_rx_phy_res.buf,
2288 	    sizeof (iwh_rx_phy_res_t));
2289 }
2290 
2291 /*
2292  * this function will be invoked to receive body of frame when
2293  * a frame is received.
2294  */
2295 static void
2296 iwh_rx_mpdu_intr(iwh_sc_t *sc, iwh_rx_desc_t *desc)
2297 {
2298 	ieee80211com_t *ic = &sc->sc_ic;
2299 #ifdef	DEBUG
2300 	iwh_rx_ring_t *ring = &sc->sc_rxq;
2301 #endif
2302 	struct ieee80211_frame *wh;
2303 	struct iwh_rx_non_cfg_phy *phyinfo;
2304 	struct iwh_rx_mpdu_body_size *mpdu_size;
2305 	mblk_t *mp;
2306 	int16_t t;
2307 	uint16_t len, rssi, agc;
2308 	uint32_t temp, crc, *tail;
2309 	uint32_t arssi, brssi, crssi, mrssi;
2310 	iwh_rx_phy_res_t *stat;
2311 	ieee80211_node_t *in;
2312 
2313 	/*
2314 	 * assuming not 11n here. cope with 11n in phase-II
2315 	 */
2316 	mpdu_size = (struct iwh_rx_mpdu_body_size *)(desc + 1);
2317 	stat = (iwh_rx_phy_res_t *)sc->sc_rx_phy_res.buf;
2318 	if (stat->cfg_phy_cnt > 20) {
2319 		return;
2320 	}
2321 
2322 	phyinfo = (struct iwh_rx_non_cfg_phy *)stat->non_cfg_phy;
2323 	temp = LE_32(phyinfo->non_cfg_phy[IWH_RX_RES_AGC_IDX]);
2324 	agc = (temp & IWH_OFDM_AGC_MSK) >> IWH_OFDM_AGC_BIT_POS;
2325 
2326 	temp = LE_32(phyinfo->non_cfg_phy[IWH_RX_RES_RSSI_AB_IDX]);
2327 	arssi = (temp & IWH_OFDM_RSSI_A_MSK) >> IWH_OFDM_RSSI_A_BIT_POS;
2328 	brssi = (temp & IWH_OFDM_RSSI_B_MSK) >> IWH_OFDM_RSSI_B_BIT_POS;
2329 
2330 	temp = LE_32(phyinfo->non_cfg_phy[IWH_RX_RES_RSSI_C_IDX]);
2331 	crssi = (temp & IWH_OFDM_RSSI_C_MSK) >> IWH_OFDM_RSSI_C_BIT_POS;
2332 
2333 	mrssi = MAX(arssi, brssi);
2334 	mrssi = MAX(mrssi, crssi);
2335 
2336 	t = mrssi - agc - IWH_RSSI_OFFSET;
2337 	/*
2338 	 * convert dBm to percentage
2339 	 */
2340 	rssi = (100 * 75 * 75 - (-20 - t) * (15 * 75 + 62 * (-20 - t)))
2341 	    / (75 * 75);
2342 	if (rssi > 100) {
2343 		rssi = 100;
2344 	}
2345 	if (rssi < 1) {
2346 		rssi = 1;
2347 	}
2348 
2349 	/*
2350 	 * size of frame, not include FCS
2351 	 */
2352 	len = LE_16(mpdu_size->byte_count);
2353 	tail = (uint32_t *)((uint8_t *)(desc + 1) +
2354 	    sizeof (struct iwh_rx_mpdu_body_size) + len);
2355 	bcopy(tail, &crc, 4);
2356 
2357 	IWH_DBG((IWH_DEBUG_RX, "iwh_rx_mpdu_intr(): "
2358 	    "rx intr: idx=%d phy_len=%x len=%d "
2359 	    "rate=%x chan=%d tstamp=%x non_cfg_phy_count=%x "
2360 	    "cfg_phy_count=%x tail=%x", ring->cur, sizeof (*stat),
2361 	    len, stat->rate.r.s.rate, stat->channel,
2362 	    LE_32(stat->timestampl), stat->non_cfg_phy_cnt,
2363 	    stat->cfg_phy_cnt, LE_32(crc)));
2364 
2365 	if ((len < 16) || (len > sc->sc_dmabuf_sz)) {
2366 		IWH_DBG((IWH_DEBUG_RX, "iwh_rx_mpdu_intr(): "
2367 		    "rx frame oversize\n"));
2368 		return;
2369 	}
2370 
2371 	/*
2372 	 * discard Rx frames with bad CRC
2373 	 */
2374 	if ((LE_32(crc) &
2375 	    (RX_RES_STATUS_NO_CRC32_ERROR | RX_RES_STATUS_NO_RXE_OVERFLOW)) !=
2376 	    (RX_RES_STATUS_NO_CRC32_ERROR | RX_RES_STATUS_NO_RXE_OVERFLOW)) {
2377 		IWH_DBG((IWH_DEBUG_RX, "iwh_rx_mpdu_intr(): "
2378 		    "rx crc error tail: %x\n",
2379 		    LE_32(crc)));
2380 		sc->sc_rx_err++;
2381 		return;
2382 	}
2383 
2384 	wh = (struct ieee80211_frame *)
2385 	    ((uint8_t *)(desc + 1)+ sizeof (struct iwh_rx_mpdu_body_size));
2386 
2387 	if (IEEE80211_FC0_SUBTYPE_ASSOC_RESP == *(uint8_t *)wh) {
2388 		sc->sc_assoc_id = *((uint16_t *)(wh + 1) + 2);
2389 		IWH_DBG((IWH_DEBUG_RX, "iwh_rx_mpdu_intr(): "
2390 		    "rx : association id = %x\n",
2391 		    sc->sc_assoc_id));
2392 	}
2393 
2394 #ifdef DEBUG
2395 	if (iwh_dbg_flags & IWH_DEBUG_RX) {
2396 		ieee80211_dump_pkt((uint8_t *)wh, len, 0, 0);
2397 	}
2398 #endif
2399 
2400 	in = ieee80211_find_rxnode(ic, wh);
2401 	mp = allocb(len, BPRI_MED);
2402 	if (mp) {
2403 		bcopy(wh, mp->b_wptr, len);
2404 		mp->b_wptr += len;
2405 
2406 		/*
2407 		 * send the frame to the 802.11 layer
2408 		 */
2409 		(void) ieee80211_input(ic, mp, in, rssi, 0);
2410 	} else {
2411 		sc->sc_rx_nobuf++;
2412 		IWH_DBG((IWH_DEBUG_RX, "iwh_rx_mpdu_intr(): "
2413 		    "alloc rx buf failed\n"));
2414 	}
2415 
2416 	/*
2417 	 * release node reference
2418 	 */
2419 	ieee80211_free_node(in);
2420 }
2421 
2422 /*
2423  * process correlative affairs after a frame is sent.
2424  */
2425 static void
2426 iwh_tx_intr(iwh_sc_t *sc, iwh_rx_desc_t *desc)
2427 {
2428 	ieee80211com_t *ic = &sc->sc_ic;
2429 	iwh_tx_ring_t *ring = &sc->sc_txq[desc->hdr.qid & 0x3];
2430 	iwh_tx_stat_t *stat = (iwh_tx_stat_t *)(desc + 1);
2431 	iwh_amrr_t *amrr;
2432 
2433 	if (NULL == ic->ic_bss) {
2434 		return;
2435 	}
2436 
2437 	amrr = (iwh_amrr_t *)ic->ic_bss;
2438 
2439 	amrr->txcnt++;
2440 	IWH_DBG((IWH_DEBUG_RATECTL, "iwh_tx_intr(): "
2441 	    "tx: %d cnt\n", amrr->txcnt));
2442 
2443 	if (stat->ntries > 0) {
2444 		amrr->retrycnt++;
2445 		sc->sc_tx_retries++;
2446 		IWH_DBG((IWH_DEBUG_TX, "iwh_tx_intr(): "
2447 		    "tx: %d retries\n",
2448 		    sc->sc_tx_retries));
2449 	}
2450 
2451 	mutex_enter(&sc->sc_mt_lock);
2452 	sc->sc_tx_timer = 0;
2453 	mutex_exit(&sc->sc_mt_lock);
2454 
2455 	mutex_enter(&sc->sc_tx_lock);
2456 
2457 	ring->queued--;
2458 	if (ring->queued < 0) {
2459 		ring->queued = 0;
2460 	}
2461 
2462 	if ((sc->sc_need_reschedule) && (ring->queued <= (ring->count >> 3))) {
2463 		sc->sc_need_reschedule = 0;
2464 		mutex_exit(&sc->sc_tx_lock);
2465 		mac_tx_update(ic->ic_mach);
2466 		mutex_enter(&sc->sc_tx_lock);
2467 	}
2468 
2469 	mutex_exit(&sc->sc_tx_lock);
2470 }
2471 
2472 /*
2473  * inform a given command has been executed
2474  */
2475 static void
2476 iwh_cmd_intr(iwh_sc_t *sc, iwh_rx_desc_t *desc)
2477 {
2478 	if ((desc->hdr.qid & 7) != 4) {
2479 		return;
2480 	}
2481 
2482 	if (sc->sc_cmd_accum > 0) {
2483 		sc->sc_cmd_accum--;
2484 		return;
2485 	}
2486 
2487 	mutex_enter(&sc->sc_glock);
2488 
2489 	sc->sc_cmd_flag = SC_CMD_FLG_DONE;
2490 
2491 	cv_signal(&sc->sc_cmd_cv);
2492 
2493 	mutex_exit(&sc->sc_glock);
2494 
2495 	IWH_DBG((IWH_DEBUG_CMD, "iwh_cmd_intr(): "
2496 	    "qid=%x idx=%d flags=%x type=0x%x\n",
2497 	    desc->hdr.qid, desc->hdr.idx, desc->hdr.flags,
2498 	    desc->hdr.type));
2499 }
2500 
2501 /*
2502  * this function will be invoked when alive notification occur.
2503  */
2504 static void
2505 iwh_ucode_alive(iwh_sc_t *sc, iwh_rx_desc_t *desc)
2506 {
2507 	uint32_t rv;
2508 	struct iwh_calib_cfg_cmd cmd;
2509 	struct iwh_alive_resp *ar =
2510 	    (struct iwh_alive_resp *)(desc + 1);
2511 	struct iwh_calib_results *res_p = &sc->sc_calib_results;
2512 
2513 	/*
2514 	 * the microcontroller is ready
2515 	 */
2516 	IWH_DBG((IWH_DEBUG_FW, "iwh_ucode_alive(): "
2517 	    "microcode alive notification minor: %x major: %x type: "
2518 	    "%x subtype: %x\n",
2519 	    ar->ucode_minor, ar->ucode_minor, ar->ver_type, ar->ver_subtype));
2520 
2521 #ifdef	DEBUG
2522 	if (LE_32(ar->is_valid) != UCODE_VALID_OK) {
2523 		IWH_DBG((IWH_DEBUG_FW, "iwh_ucode_alive(): "
2524 		    "microcontroller initialization failed\n"));
2525 	}
2526 #endif
2527 
2528 	/*
2529 	 * determine if init alive or runtime alive.
2530 	 */
2531 	if (INITIALIZE_SUBTYPE == ar->ver_subtype) {
2532 		IWH_DBG((IWH_DEBUG_FW, "iwh_ucode_alive(): "
2533 		    "initialization alive received.\n"));
2534 
2535 		bcopy(ar, &sc->sc_card_alive_init,
2536 		    sizeof (struct iwh_init_alive_resp));
2537 
2538 		/*
2539 		 * necessary configuration to NIC
2540 		 */
2541 		mutex_enter(&sc->sc_glock);
2542 
2543 		rv = iwh_alive_common(sc);
2544 		if (rv != IWH_SUCCESS) {
2545 			cmn_err(CE_WARN, "iwh_ucode_alive(): "
2546 			    "common alive process failed in init alive.\n");
2547 			mutex_exit(&sc->sc_glock);
2548 			return;
2549 		}
2550 
2551 		(void) memset(&cmd, 0, sizeof (cmd));
2552 
2553 		cmd.ucd_calib_cfg.once.is_enable = IWH_CALIB_INIT_CFG_ALL;
2554 		cmd.ucd_calib_cfg.once.start = IWH_CALIB_INIT_CFG_ALL;
2555 		cmd.ucd_calib_cfg.once.send_res = IWH_CALIB_INIT_CFG_ALL;
2556 		cmd.ucd_calib_cfg.flags = IWH_CALIB_INIT_CFG_ALL;
2557 
2558 		/*
2559 		 * require ucode execute calibration
2560 		 */
2561 		rv = iwh_cmd(sc, CALIBRATION_CFG_CMD, &cmd, sizeof (cmd), 1);
2562 		if (rv != IWH_SUCCESS) {
2563 			cmn_err(CE_WARN, "iwh_ucode_alive(): "
2564 			    "failed to send calibration configure command.\n");
2565 			mutex_exit(&sc->sc_glock);
2566 			return;
2567 		}
2568 
2569 		mutex_exit(&sc->sc_glock);
2570 
2571 	} else {	/* runtime alive */
2572 
2573 		IWH_DBG((IWH_DEBUG_FW, "iwh_ucode_alive(): "
2574 		    "runtime alive received.\n"));
2575 
2576 		bcopy(ar, &sc->sc_card_alive_run,
2577 		    sizeof (struct iwh_alive_resp));
2578 
2579 		mutex_enter(&sc->sc_glock);
2580 
2581 		/*
2582 		 * necessary configuration to NIC
2583 		 */
2584 		rv = iwh_alive_common(sc);
2585 		if (rv != IWH_SUCCESS) {
2586 			cmn_err(CE_WARN, "iwh_ucode_alive(): "
2587 			    "common alive process failed in run alive.\n");
2588 			mutex_exit(&sc->sc_glock);
2589 			return;
2590 		}
2591 
2592 		/*
2593 		 * send the result of local oscilator calibration to uCode.
2594 		 */
2595 		if (res_p->lo_res != NULL) {
2596 			rv = iwh_cmd(sc, REPLY_PHY_CALIBRATION_CMD,
2597 			    res_p->lo_res, res_p->lo_res_len, 1);
2598 			if (rv != IWH_SUCCESS) {
2599 				cmn_err(CE_WARN, "iwh_ucode_alive(): "
2600 				    "failed to send local"
2601 				    "oscilator calibration command.\n");
2602 				mutex_exit(&sc->sc_glock);
2603 				return;
2604 			}
2605 
2606 			DELAY(1000);
2607 		}
2608 
2609 		/*
2610 		 * send the result of TX IQ calibration to uCode.
2611 		 */
2612 		if (res_p->tx_iq_res != NULL) {
2613 			rv = iwh_cmd(sc, REPLY_PHY_CALIBRATION_CMD,
2614 			    res_p->tx_iq_res, res_p->tx_iq_res_len, 1);
2615 			if (rv != IWH_SUCCESS) {
2616 				cmn_err(CE_WARN, "iwh_ucode_alive(): "
2617 				    "failed to send TX IQ"
2618 				    "calibration command.\n");
2619 				mutex_exit(&sc->sc_glock);
2620 				return;
2621 			}
2622 
2623 			DELAY(1000);
2624 		}
2625 
2626 		/*
2627 		 * sned the result of TX IQ perd calibration to uCode.
2628 		 */
2629 		if (res_p->tx_iq_perd_res != NULL) {
2630 			rv = iwh_cmd(sc, REPLY_PHY_CALIBRATION_CMD,
2631 			    res_p->tx_iq_perd_res,
2632 			    res_p->tx_iq_perd_res_len, 1);
2633 			if (rv != IWH_SUCCESS) {
2634 				cmn_err(CE_WARN, "iwh_ucode_alive(): "
2635 				    "failed to send TX IQ perd"
2636 				    "calibration command.\n");
2637 				mutex_exit(&sc->sc_glock);
2638 				return;
2639 			}
2640 
2641 			DELAY(1000);
2642 		}
2643 
2644 		/*
2645 		 * send the result of DC calibration to uCode.
2646 		 */
2647 		if (res_p->dc_res != NULL) {
2648 			rv = iwh_cmd(sc, REPLY_PHY_CALIBRATION_CMD,
2649 			    res_p->dc_res,
2650 			    res_p->dc_res_len, 1);
2651 			if (rv != IWH_SUCCESS) {
2652 				cmn_err(CE_WARN, "iwh_ucode_alive(): "
2653 				    "failed to send DC"
2654 				    "calibration command.\n");
2655 				mutex_exit(&sc->sc_glock);
2656 				return;
2657 			}
2658 
2659 			DELAY(1000);
2660 		}
2661 
2662 		/*
2663 		 * send the result of BASE BAND calibration to uCode.
2664 		 */
2665 		if (res_p->base_band_res != NULL) {
2666 			rv = iwh_cmd(sc, REPLY_PHY_CALIBRATION_CMD,
2667 			    res_p->base_band_res,
2668 			    res_p->base_band_res_len, 1);
2669 			if (rv != IWH_SUCCESS) {
2670 				cmn_err(CE_WARN, "iwh_ucode_alive(): "
2671 				    "failed to send BASE BAND"
2672 				    "calibration command.\n");
2673 				mutex_exit(&sc->sc_glock);
2674 				return;
2675 			}
2676 
2677 			DELAY(1000);
2678 		}
2679 
2680 		atomic_or_32(&sc->sc_flags, IWH_F_FW_INIT);
2681 		cv_signal(&sc->sc_ucode_cv);
2682 
2683 		mutex_exit(&sc->sc_glock);
2684 	}
2685 
2686 }
2687 
2688 /*
2689  * deal with receiving frames, command response
2690  * and all notifications from ucode.
2691  */
2692 /* ARGSUSED */
2693 static uint_t
2694 iwh_rx_softintr(caddr_t arg, caddr_t unused)
2695 {
2696 	iwh_sc_t *sc;
2697 	ieee80211com_t *ic;
2698 	iwh_rx_desc_t *desc;
2699 	iwh_rx_data_t *data;
2700 	uint32_t index;
2701 
2702 	if (NULL == arg) {
2703 		return (DDI_INTR_UNCLAIMED);
2704 	}
2705 	sc = (iwh_sc_t *)arg;
2706 	ic = &sc->sc_ic;
2707 
2708 	/*
2709 	 * firmware has moved the index of the rx queue, driver get it,
2710 	 * and deal with it.
2711 	 */
2712 	index = (sc->sc_shared->val0) & 0xfff;
2713 
2714 	while (sc->sc_rxq.cur != index) {
2715 		data = &sc->sc_rxq.data[sc->sc_rxq.cur];
2716 		desc = (iwh_rx_desc_t *)data->dma_data.mem_va;
2717 
2718 		IWH_DBG((IWH_DEBUG_INTR, "iwh_rx_softintr(): "
2719 		    "rx notification index = %d"
2720 		    " cur = %d qid=%x idx=%d flags=%x type=%x len=%d\n",
2721 		    index, sc->sc_rxq.cur, desc->hdr.qid, desc->hdr.idx,
2722 		    desc->hdr.flags, desc->hdr.type, LE_32(desc->len)));
2723 
2724 		/*
2725 		 * a command other than a tx need to be replied
2726 		 */
2727 		if (!(desc->hdr.qid & 0x80) &&
2728 		    (desc->hdr.type != REPLY_SCAN_CMD) &&
2729 		    (desc->hdr.type != REPLY_TX)) {
2730 			iwh_cmd_intr(sc, desc);
2731 		}
2732 
2733 		switch (desc->hdr.type) {
2734 		case REPLY_RX_PHY_CMD:
2735 			iwh_rx_phy_intr(sc, desc);
2736 			break;
2737 
2738 		case REPLY_RX_MPDU_CMD:
2739 			iwh_rx_mpdu_intr(sc, desc);
2740 			break;
2741 
2742 		case REPLY_TX:
2743 			iwh_tx_intr(sc, desc);
2744 			break;
2745 
2746 		case REPLY_ALIVE:
2747 			iwh_ucode_alive(sc, desc);
2748 			break;
2749 
2750 		case CARD_STATE_NOTIFICATION:
2751 		{
2752 			uint32_t *status = (uint32_t *)(desc + 1);
2753 
2754 			IWH_DBG((IWH_DEBUG_RADIO, "iwh_rx_softintr(): "
2755 			    "state changed to %x\n",
2756 			    LE_32(*status)));
2757 
2758 			if (LE_32(*status) & 1) {
2759 				/*
2760 				 * the radio button has to be pushed(OFF). It
2761 				 * is considered as a hw error, the
2762 				 * iwh_thread() tries to recover it after the
2763 				 * button is pushed again(ON)
2764 				 */
2765 				cmn_err(CE_NOTE, "iwh_rx_softintr(): "
2766 				    "radio transmitter is off\n");
2767 				sc->sc_ostate = sc->sc_ic.ic_state;
2768 				ieee80211_new_state(&sc->sc_ic,
2769 				    IEEE80211_S_INIT, -1);
2770 				atomic_or_32(&sc->sc_flags,
2771 				    (IWH_F_HW_ERR_RECOVER | IWH_F_RADIO_OFF));
2772 			}
2773 
2774 			break;
2775 		}
2776 
2777 		case SCAN_START_NOTIFICATION:
2778 		{
2779 			iwh_start_scan_t *scan =
2780 			    (iwh_start_scan_t *)(desc + 1);
2781 
2782 			IWH_DBG((IWH_DEBUG_SCAN, "iwh_rx_softintr(): "
2783 			    "scanning channel %d status %x\n",
2784 			    scan->chan, LE_32(scan->status)));
2785 
2786 			ic->ic_curchan = &ic->ic_sup_channels[scan->chan];
2787 			break;
2788 		}
2789 
2790 		case SCAN_COMPLETE_NOTIFICATION:
2791 		{
2792 #ifdef	DEBUG
2793 			iwh_stop_scan_t *scan =
2794 			    (iwh_stop_scan_t *)(desc + 1);
2795 
2796 			IWH_DBG((IWH_DEBUG_SCAN, "iwh_rx_softintr(): "
2797 			    "completed channel %d (burst of %d) status %02x\n",
2798 			    scan->chan, scan->nchan, scan->status));
2799 #endif
2800 
2801 			sc->sc_scan_pending++;
2802 			break;
2803 		}
2804 
2805 		case STATISTICS_NOTIFICATION:
2806 		{
2807 			/*
2808 			 * handle statistics notification
2809 			 */
2810 			break;
2811 		}
2812 
2813 		case CALIBRATION_RES_NOTIFICATION:
2814 			iwh_save_calib_result(sc, desc);
2815 			break;
2816 
2817 		case CALIBRATION_COMPLETE_NOTIFICATION:
2818 			mutex_enter(&sc->sc_glock);
2819 			atomic_or_32(&sc->sc_flags, IWH_F_FW_INIT);
2820 			cv_signal(&sc->sc_ucode_cv);
2821 			mutex_exit(&sc->sc_glock);
2822 			break;
2823 
2824 		case MISSED_BEACONS_NOTIFICATION:
2825 			/* handle beacon miss by software mechanism */
2826 			break;
2827 		}
2828 
2829 		sc->sc_rxq.cur = (sc->sc_rxq.cur + 1) % RX_QUEUE_SIZE;
2830 	}
2831 
2832 	/*
2833 	 * driver dealt with what received in rx queue and tell the information
2834 	 * to the firmware.
2835 	 */
2836 	index = (0 == index) ? RX_QUEUE_SIZE - 1 : index - 1;
2837 	IWH_WRITE(sc, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, index & (~7));
2838 
2839 	/*
2840 	 * re-enable interrupts
2841 	 */
2842 	IWH_WRITE(sc, CSR_INT_MASK, CSR_INI_SET_MASK);
2843 
2844 	return (DDI_INTR_CLAIMED);
2845 }
2846 
2847 /*
2848  * the handle of interrupt
2849  */
2850 /* ARGSUSED */
2851 static uint_t
2852 iwh_intr(caddr_t arg, caddr_t unused)
2853 {
2854 	iwh_sc_t *sc;
2855 	uint32_t r, rfh;
2856 
2857 	if (NULL == arg) {
2858 		return (DDI_INTR_UNCLAIMED);
2859 	}
2860 	sc = (iwh_sc_t *)arg;
2861 
2862 	r = IWH_READ(sc, CSR_INT);
2863 	if (0 == r || 0xffffffff == r) {
2864 		return (DDI_INTR_UNCLAIMED);
2865 	}
2866 
2867 	IWH_DBG((IWH_DEBUG_INTR, "iwh_intr(): "
2868 	    "interrupt reg %x\n", r));
2869 
2870 	rfh = IWH_READ(sc, CSR_FH_INT_STATUS);
2871 
2872 	IWH_DBG((IWH_DEBUG_INTR, "iwh_intr(): "
2873 	    "FH interrupt reg %x\n", rfh));
2874 
2875 	/*
2876 	 * disable interrupts
2877 	 */
2878 	IWH_WRITE(sc, CSR_INT_MASK, 0);
2879 
2880 	/*
2881 	 * ack interrupts
2882 	 */
2883 	IWH_WRITE(sc, CSR_INT, r);
2884 	IWH_WRITE(sc, CSR_FH_INT_STATUS, rfh);
2885 
2886 	if (r & (BIT_INT_SWERROR | BIT_INT_ERR)) {
2887 		IWH_DBG((IWH_DEBUG_FW, "iwh_intr(): "
2888 		    "fatal firmware error\n"));
2889 		iwh_stop(sc);
2890 		sc->sc_ostate = sc->sc_ic.ic_state;
2891 
2892 		/*
2893 		 * notify upper layer
2894 		 */
2895 		if (!IWH_CHK_FAST_RECOVER(sc)) {
2896 			ieee80211_new_state(&sc->sc_ic, IEEE80211_S_INIT, -1);
2897 		}
2898 
2899 		atomic_or_32(&sc->sc_flags, IWH_F_HW_ERR_RECOVER);
2900 		return (DDI_INTR_CLAIMED);
2901 	}
2902 
2903 	if (r & BIT_INT_RF_KILL) {
2904 		uint32_t tmp = IWH_READ(sc, CSR_GP_CNTRL);
2905 		if (tmp & (1 << 27)) {
2906 			cmn_err(CE_NOTE, "RF switch: radio on\n");
2907 		}
2908 	}
2909 
2910 	if ((r & (BIT_INT_FH_RX | BIT_INT_SW_RX)) ||
2911 	    (rfh & FH_INT_RX_MASK)) {
2912 		(void) ddi_intr_trigger_softint(sc->sc_soft_hdl, NULL);
2913 		return (DDI_INTR_CLAIMED);
2914 	}
2915 
2916 	if (r & BIT_INT_FH_TX) {
2917 		mutex_enter(&sc->sc_glock);
2918 		atomic_or_32(&sc->sc_flags, IWH_F_PUT_SEG);
2919 		cv_signal(&sc->sc_put_seg_cv);
2920 		mutex_exit(&sc->sc_glock);
2921 	}
2922 
2923 #ifdef	DEBUG
2924 	if (r & BIT_INT_ALIVE)	{
2925 		IWH_DBG((IWH_DEBUG_FW, "iwh_intr(): "
2926 		    "firmware initialized.\n"));
2927 	}
2928 #endif
2929 
2930 	/*
2931 	 * re-enable interrupts
2932 	 */
2933 	IWH_WRITE(sc, CSR_INT_MASK, CSR_INI_SET_MASK);
2934 
2935 	return (DDI_INTR_CLAIMED);
2936 }
2937 
2938 static uint8_t
2939 iwh_rate_to_plcp(int rate)
2940 {
2941 	uint8_t ret;
2942 
2943 	switch (rate) {
2944 	/*
2945 	 * CCK rates
2946 	 */
2947 	case 2:
2948 		ret = 0xa;
2949 		break;
2950 
2951 	case 4:
2952 		ret = 0x14;
2953 		break;
2954 
2955 	case 11:
2956 		ret = 0x37;
2957 		break;
2958 
2959 	case 22:
2960 		ret = 0x6e;
2961 		break;
2962 
2963 	/*
2964 	 * OFDM rates
2965 	 */
2966 	case 12:
2967 		ret = 0xd;
2968 		break;
2969 
2970 	case 18:
2971 		ret = 0xf;
2972 		break;
2973 
2974 	case 24:
2975 		ret = 0x5;
2976 		break;
2977 
2978 	case 36:
2979 		ret = 0x7;
2980 		break;
2981 
2982 	case 48:
2983 		ret = 0x9;
2984 		break;
2985 
2986 	case 72:
2987 		ret = 0xb;
2988 		break;
2989 
2990 	case 96:
2991 		ret = 0x1;
2992 		break;
2993 
2994 	case 108:
2995 		ret = 0x3;
2996 		break;
2997 
2998 	default:
2999 		ret = 0;
3000 		break;
3001 	}
3002 
3003 	return (ret);
3004 }
3005 
3006 /*
3007  * invoked by GLD send frames
3008  */
3009 static mblk_t *
3010 iwh_m_tx(void *arg, mblk_t *mp)
3011 {
3012 	iwh_sc_t *sc;
3013 	ieee80211com_t *ic;
3014 	mblk_t *next;
3015 
3016 	if (NULL == arg) {
3017 		return (NULL);
3018 	}
3019 	sc = (iwh_sc_t *)arg;
3020 	ic = &sc->sc_ic;
3021 
3022 	if (sc->sc_flags & IWH_F_SUSPEND) {
3023 		freemsgchain(mp);
3024 		return (NULL);
3025 	}
3026 
3027 	if (ic->ic_state != IEEE80211_S_RUN) {
3028 		freemsgchain(mp);
3029 		return (NULL);
3030 	}
3031 
3032 	if ((sc->sc_flags & IWH_F_HW_ERR_RECOVER) &&
3033 	    IWH_CHK_FAST_RECOVER(sc)) {
3034 		IWH_DBG((IWH_DEBUG_FW, "iwh_m_tx(): "
3035 		    "hold queue\n"));
3036 		return (mp);
3037 	}
3038 
3039 	while (mp != NULL) {
3040 		next = mp->b_next;
3041 		mp->b_next = NULL;
3042 		if (iwh_send(ic, mp, IEEE80211_FC0_TYPE_DATA) != 0) {
3043 			mp->b_next = next;
3044 			break;
3045 		}
3046 		mp = next;
3047 	}
3048 
3049 	return (mp);
3050 }
3051 
3052 /*
3053  * send frames
3054  */
3055 static int
3056 iwh_send(ieee80211com_t *ic, mblk_t *mp, uint8_t type)
3057 {
3058 	iwh_sc_t *sc;
3059 	iwh_tx_ring_t *ring;
3060 	iwh_tx_desc_t *desc;
3061 	iwh_tx_data_t *data;
3062 	iwh_tx_data_t *desc_data;
3063 	iwh_cmd_t *cmd;
3064 	iwh_tx_cmd_t *tx;
3065 	ieee80211_node_t *in;
3066 	struct ieee80211_frame *wh, *mp_wh;
3067 	struct ieee80211_key *k = NULL;
3068 	mblk_t *m, *m0;
3069 	int hdrlen, len, len0, mblen, off, err = IWH_SUCCESS;
3070 	uint16_t masks = 0;
3071 	uint32_t rate, s_id = 0;
3072 	int txq_id = NON_QOS_TXQ;
3073 	struct ieee80211_qosframe *qwh = NULL;
3074 	int tid = WME_TID_INVALID;
3075 
3076 	if (NULL == ic) {
3077 		return (IWH_FAIL);
3078 	}
3079 	sc = (iwh_sc_t *)ic;
3080 
3081 	if (sc->sc_flags & IWH_F_SUSPEND) {
3082 		if ((type & IEEE80211_FC0_TYPE_MASK) !=
3083 		    IEEE80211_FC0_TYPE_DATA) {
3084 			freemsg(mp);
3085 		}
3086 		err = IWH_FAIL;
3087 		goto exit;
3088 	}
3089 
3090 	if ((NULL == mp) || (MBLKL(mp) <= 0)) {
3091 		return (IWH_FAIL);
3092 	}
3093 
3094 	mp_wh = (struct ieee80211_frame *)mp->b_rptr;
3095 
3096 	/*
3097 	 * Determine send which AP or station in IBSS
3098 	 */
3099 	in = ieee80211_find_txnode(ic, mp_wh->i_addr1);
3100 	if (NULL == in) {
3101 		cmn_err(CE_WARN, "iwh_send(): "
3102 		    "failed to find tx node\n");
3103 		freemsg(mp);
3104 		sc->sc_tx_err++;
3105 		err = IWH_SUCCESS;
3106 		goto exit;
3107 	}
3108 
3109 	/*
3110 	 * Determine TX queue according to traffic ID in frame
3111 	 * if working in QoS mode.
3112 	 */
3113 	if (in->in_flags & IEEE80211_NODE_QOS) {
3114 
3115 		if ((type & IEEE80211_FC0_TYPE_MASK) ==
3116 		    IEEE80211_FC0_TYPE_DATA) {
3117 
3118 			if (mp_wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_QOS) {
3119 				qwh = (struct ieee80211_qosframe *)mp_wh;
3120 
3121 				tid = qwh->i_qos[0] & IEEE80211_QOS_TID;
3122 				txq_id = iwh_wme_tid_to_txq(tid);
3123 
3124 				if (txq_id < TXQ_FOR_AC_MIN ||
3125 				    (txq_id > TXQ_FOR_AC_MAX)) {
3126 					freemsg(mp);
3127 					sc->sc_tx_err++;
3128 					err = IWH_SUCCESS;
3129 					goto exit;
3130 				}
3131 
3132 			} else {
3133 				txq_id = NON_QOS_TXQ;
3134 			}
3135 
3136 		} else if ((type & IEEE80211_FC0_TYPE_MASK) ==
3137 		    IEEE80211_FC0_TYPE_MGT) {
3138 			txq_id = QOS_TXQ_FOR_MGT;
3139 		} else {
3140 			txq_id = NON_QOS_TXQ;
3141 		}
3142 
3143 	} else {
3144 		txq_id = NON_QOS_TXQ;
3145 	}
3146 
3147 	mutex_enter(&sc->sc_tx_lock);
3148 	ring = &sc->sc_txq[txq_id];
3149 	data = &ring->data[ring->cur];
3150 	cmd = data->cmd;
3151 	bzero(cmd, sizeof (*cmd));
3152 
3153 	ring->cur = (ring->cur + 1) % ring->count;
3154 
3155 	/*
3156 	 * Need reschedule TX if TX buffer is full.
3157 	 */
3158 	if (ring->queued > ring->count - IWH_MAX_WIN_SIZE) {
3159 		IWH_DBG((IWH_DEBUG_TX, "iwh_send(): "
3160 		"no txbuf\n"));
3161 
3162 		sc->sc_need_reschedule = 1;
3163 		mutex_exit(&sc->sc_tx_lock);
3164 
3165 		if ((type & IEEE80211_FC0_TYPE_MASK) !=
3166 		    IEEE80211_FC0_TYPE_DATA) {
3167 			freemsg(mp);
3168 		}
3169 		sc->sc_tx_nobuf++;
3170 		err = IWH_FAIL;
3171 		goto exit;
3172 	}
3173 
3174 	ring->queued++;
3175 
3176 	mutex_exit(&sc->sc_tx_lock);
3177 
3178 	hdrlen = ieee80211_hdrspace(ic, mp->b_rptr);
3179 
3180 	m = allocb(msgdsize(mp) + 32, BPRI_MED);
3181 	if (NULL == m) { /* can not alloc buf, drop this package */
3182 		cmn_err(CE_WARN, "iwh_send(): "
3183 		    "failed to allocate msgbuf\n");
3184 		freemsg(mp);
3185 
3186 		mutex_enter(&sc->sc_tx_lock);
3187 		ring->queued--;
3188 		if ((sc->sc_need_reschedule) && (ring->queued <= 0)) {
3189 			sc->sc_need_reschedule = 0;
3190 			mutex_exit(&sc->sc_tx_lock);
3191 			mac_tx_update(ic->ic_mach);
3192 			mutex_enter(&sc->sc_tx_lock);
3193 		}
3194 		mutex_exit(&sc->sc_tx_lock);
3195 
3196 		err = IWH_SUCCESS;
3197 		goto exit;
3198 	}
3199 
3200 	for (off = 0, m0 = mp; m0 != NULL; m0 = m0->b_cont) {
3201 		mblen = MBLKL(m0);
3202 		bcopy(m0->b_rptr, m->b_rptr + off, mblen);
3203 		off += mblen;
3204 	}
3205 
3206 	m->b_wptr += off;
3207 
3208 	wh = (struct ieee80211_frame *)m->b_rptr;
3209 
3210 	/*
3211 	 * Net80211 module encapsulate outbound data frames.
3212 	 * Add some feilds of 80211 frame.
3213 	 */
3214 	if ((type & IEEE80211_FC0_TYPE_MASK) ==
3215 	    IEEE80211_FC0_TYPE_DATA) {
3216 		(void) ieee80211_encap(ic, m, in);
3217 	}
3218 
3219 	freemsg(mp);
3220 
3221 	cmd->hdr.type = REPLY_TX;
3222 	cmd->hdr.flags = 0;
3223 	cmd->hdr.qid = ring->qid;
3224 
3225 	tx = (iwh_tx_cmd_t *)cmd->data;
3226 	tx->tx_flags = 0;
3227 
3228 	if (IEEE80211_IS_MULTICAST(wh->i_addr1)) {
3229 		tx->tx_flags &= ~(LE_32(TX_CMD_FLG_ACK_MSK));
3230 	} else {
3231 		tx->tx_flags |= LE_32(TX_CMD_FLG_ACK_MSK);
3232 	}
3233 
3234 	if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
3235 		k = ieee80211_crypto_encap(ic, m);
3236 		if (NULL == k) {
3237 			freemsg(m);
3238 			sc->sc_tx_err++;
3239 
3240 			mutex_enter(&sc->sc_tx_lock);
3241 			ring->queued--;
3242 			if ((sc->sc_need_reschedule) && (ring->queued <= 0)) {
3243 				sc->sc_need_reschedule = 0;
3244 				mutex_exit(&sc->sc_tx_lock);
3245 				mac_tx_update(ic->ic_mach);
3246 				mutex_enter(&sc->sc_tx_lock);
3247 			}
3248 			mutex_exit(&sc->sc_tx_lock);
3249 
3250 			err = IWH_SUCCESS;
3251 			goto exit;
3252 		}
3253 
3254 		/*
3255 		 * packet header may have moved, reset our local pointer
3256 		 */
3257 		wh = (struct ieee80211_frame *)m->b_rptr;
3258 	}
3259 
3260 	len = msgdsize(m);
3261 
3262 #ifdef DEBUG
3263 	if (iwh_dbg_flags & IWH_DEBUG_TX) {
3264 		ieee80211_dump_pkt((uint8_t *)wh, hdrlen, 0, 0);
3265 	}
3266 #endif
3267 
3268 	tx->rts_retry_limit = IWH_TX_RTS_RETRY_LIMIT;
3269 	tx->data_retry_limit = IWH_TX_DATA_RETRY_LIMIT;
3270 
3271 	/*
3272 	 * specific TX parameters for management frames
3273 	 */
3274 	if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
3275 	    IEEE80211_FC0_TYPE_MGT) {
3276 		/*
3277 		 * mgmt frames are sent at 1M
3278 		 */
3279 		if ((in->in_rates.ir_rates[0] &
3280 		    IEEE80211_RATE_VAL) != 0) {
3281 			rate = in->in_rates.ir_rates[0] & IEEE80211_RATE_VAL;
3282 		} else {
3283 			rate = 2;
3284 		}
3285 
3286 		tx->tx_flags |= LE_32(TX_CMD_FLG_SEQ_CTL_MSK);
3287 
3288 		/*
3289 		 * tell h/w to set timestamp in probe responses
3290 		 */
3291 		if ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) ==
3292 		    IEEE80211_FC0_SUBTYPE_PROBE_RESP) {
3293 			tx->tx_flags |= LE_32(TX_CMD_FLG_TSF_MSK);
3294 
3295 			tx->data_retry_limit = 3;
3296 			if (tx->data_retry_limit < tx->rts_retry_limit) {
3297 				tx->rts_retry_limit = tx->data_retry_limit;
3298 			}
3299 		}
3300 
3301 		if (((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) ==
3302 		    IEEE80211_FC0_SUBTYPE_ASSOC_REQ) ||
3303 		    ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) ==
3304 		    IEEE80211_FC0_SUBTYPE_REASSOC_REQ)) {
3305 			tx->timeout.pm_frame_timeout = LE_16(3);
3306 		} else {
3307 			tx->timeout.pm_frame_timeout = LE_16(2);
3308 		}
3309 
3310 	} else {
3311 		/*
3312 		 * do it here for the software way rate scaling.
3313 		 * later for rate scaling in hardware.
3314 		 *
3315 		 * now the txrate is determined in tx cmd flags, set to the
3316 		 * max value 54M for 11g and 11M for 11b and 96M for 11n
3317 		 * originally.
3318 		 */
3319 		if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE) {
3320 			rate = ic->ic_fixed_rate;
3321 		} else {
3322 			if ((in->in_flags & IEEE80211_NODE_HT) &&
3323 			    (sc->sc_ht_conf.ht_support)) {
3324 				iwh_amrr_t *amrr = (iwh_amrr_t *)in;
3325 				rate = amrr->ht_mcs_idx;
3326 			} else {
3327 				if ((in->in_rates.ir_rates[in->in_txrate] &
3328 				    IEEE80211_RATE_VAL) != 0) {
3329 					rate = in->in_rates.
3330 					    ir_rates[in->in_txrate] &
3331 					    IEEE80211_RATE_VAL;
3332 				}
3333 			}
3334 		}
3335 
3336 		if (tid != WME_TID_INVALID) {
3337 			tx->tid_tspec = (uint8_t)tid;
3338 			tx->tx_flags &= LE_32(~TX_CMD_FLG_SEQ_CTL_MSK);
3339 		} else {
3340 			tx->tx_flags |= LE_32(TX_CMD_FLG_SEQ_CTL_MSK);
3341 		}
3342 
3343 		tx->timeout.pm_frame_timeout = 0;
3344 	}
3345 
3346 	IWH_DBG((IWH_DEBUG_TX, "iwh_send(): "
3347 	    "tx rate[%d of %d] = %x",
3348 	    in->in_txrate, in->in_rates.ir_nrates, rate));
3349 
3350 	len0 = roundup(4 + sizeof (iwh_tx_cmd_t) + hdrlen, 4);
3351 	if (len0 != (4 + sizeof (iwh_tx_cmd_t) + hdrlen)) {
3352 		tx->tx_flags |= LE_32(TX_CMD_FLG_MH_PAD_MSK);
3353 	}
3354 
3355 	/*
3356 	 * retrieve destination node's id
3357 	 */
3358 	if (IEEE80211_IS_MULTICAST(wh->i_addr1)) {
3359 		tx->sta_id = IWH_BROADCAST_ID;
3360 	} else {
3361 		tx->sta_id = IWH_AP_ID;
3362 	}
3363 
3364 	if ((in->in_flags & IEEE80211_NODE_HT) &&
3365 	    (sc->sc_ht_conf.ht_support) &&
3366 	    ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
3367 	    IEEE80211_FC0_TYPE_DATA)) {
3368 		if (rate >= HT_2CHAIN_RATE_MIN_IDX) {
3369 			rate |= LE_32(RATE_MCS_ANT_AB_MSK);
3370 		} else {
3371 			rate |= LE_32(RATE_MCS_ANT_B_MSK);
3372 		}
3373 
3374 		rate |= LE_32((1 << RATE_MCS_HT_POS));
3375 
3376 		tx->rate.r.rate_n_flags = rate;
3377 
3378 	} else {
3379 		if (2 == rate || 4 == rate || 11 == rate || 22 == rate) {
3380 			masks |= RATE_MCS_CCK_MSK;
3381 		}
3382 
3383 		masks |= RATE_MCS_ANT_B_MSK;
3384 		tx->rate.r.rate_n_flags = LE_32(iwh_rate_to_plcp(rate) | masks);
3385 	}
3386 
3387 	IWH_DBG((IWH_DEBUG_TX, "iwh_send(): "
3388 	    "tx flag = %x",
3389 	    tx->tx_flags));
3390 
3391 	tx->stop_time.life_time  = LE_32(0xffffffff);
3392 
3393 	tx->len = LE_16(len);
3394 
3395 	tx->dram_lsb_ptr =
3396 	    LE_32(data->paddr_cmd + 4 + offsetof(iwh_tx_cmd_t, scratch));
3397 	tx->dram_msb_ptr = 0;
3398 	tx->driver_txop = 0;
3399 	tx->next_frame_len = 0;
3400 
3401 	bcopy(m->b_rptr, tx + 1, hdrlen);
3402 	m->b_rptr += hdrlen;
3403 	bcopy(m->b_rptr, data->dma_data.mem_va, (len - hdrlen));
3404 
3405 	IWH_DBG((IWH_DEBUG_TX, "iwh_send(): "
3406 	    "sending data: qid=%d idx=%d len=%d",
3407 	    ring->qid, ring->cur, len));
3408 
3409 	/*
3410 	 * first segment includes the tx cmd plus the 802.11 header,
3411 	 * the second includes the remaining of the 802.11 frame.
3412 	 */
3413 
3414 	mutex_enter(&sc->sc_tx_lock);
3415 	cmd->hdr.idx = ring->desc_cur;
3416 	desc_data = &ring->data[ring->desc_cur];
3417 	desc = desc_data->desc;
3418 	bzero(desc, sizeof (*desc));
3419 	desc->val0 = 2 << 24;
3420 	desc->pa[0].tb1_addr = data->paddr_cmd;
3421 	desc->pa[0].val1 = ((len0 << 4) & 0xfff0) |
3422 	    ((data->dma_data.cookie.dmac_address & 0xffff) << 16);
3423 	desc->pa[0].val2 =
3424 	    ((data->dma_data.cookie.dmac_address & 0xffff0000) >> 16) |
3425 	    ((len - hdrlen) << 20);
3426 	IWH_DBG((IWH_DEBUG_TX, "iwh_send(): "
3427 	    "phy addr1 = 0x%x phy addr2 = 0x%x "
3428 	    "len1 = 0x%x, len2 = 0x%x val1 = 0x%x val2 = 0x%x",
3429 	    data->paddr_cmd, data->dma_data.cookie.dmac_address,
3430 	    len0, len - hdrlen, desc->pa[0].val1, desc->pa[0].val2));
3431 
3432 	/*
3433 	 * kick ring
3434 	 */
3435 	s_id = tx->sta_id;
3436 
3437 	sc->sc_shared->queues_byte_cnt_tbls[ring->qid].
3438 	    tfd_offset[ring->desc_cur].val =
3439 	    (8 + len) | (s_id << 12);
3440 	if (ring->desc_cur < IWH_MAX_WIN_SIZE) {
3441 		sc->sc_shared->queues_byte_cnt_tbls[ring->qid].
3442 		    tfd_offset[IWH_QUEUE_SIZE + ring->desc_cur].val =
3443 		    (8 + len) | (s_id << 12);
3444 	}
3445 
3446 	IWH_DMA_SYNC(data->dma_data, DDI_DMA_SYNC_FORDEV);
3447 	IWH_DMA_SYNC(ring->dma_desc, DDI_DMA_SYNC_FORDEV);
3448 
3449 	ring->desc_cur = (ring->desc_cur + 1) % ring->count;
3450 	IWH_WRITE(sc, HBUS_TARG_WRPTR, ring->qid << 8 | ring->desc_cur);
3451 
3452 	mutex_exit(&sc->sc_tx_lock);
3453 	freemsg(m);
3454 
3455 	/*
3456 	 * release node reference
3457 	 */
3458 	ieee80211_free_node(in);
3459 
3460 	ic->ic_stats.is_tx_bytes += len;
3461 	ic->ic_stats.is_tx_frags++;
3462 
3463 	mutex_enter(&sc->sc_mt_lock);
3464 	if (0 == sc->sc_tx_timer) {
3465 		sc->sc_tx_timer = 4;
3466 	}
3467 	mutex_exit(&sc->sc_mt_lock);
3468 
3469 exit:
3470 	return (err);
3471 }
3472 
3473 /*
3474  * invoked by GLD to deal with IOCTL affaires
3475  */
3476 static void
3477 iwh_m_ioctl(void* arg, queue_t *wq, mblk_t *mp)
3478 {
3479 	iwh_sc_t *sc;
3480 	ieee80211com_t *ic;
3481 	int err = EINVAL;
3482 
3483 	if (NULL == arg) {
3484 		return;
3485 	}
3486 	sc = (iwh_sc_t *)arg;
3487 	ic = &sc->sc_ic;
3488 
3489 	err = ieee80211_ioctl(ic, wq, mp);
3490 	if (ENETRESET == err) {
3491 		/*
3492 		 * This is special for the hidden AP connection.
3493 		 * In any case, we should make sure only one 'scan'
3494 		 * in the driver for a 'connect' CLI command. So
3495 		 * when connecting to a hidden AP, the scan is just
3496 		 * sent out to the air when we know the desired
3497 		 * essid of the AP we want to connect.
3498 		 */
3499 		if (ic->ic_des_esslen) {
3500 			if (sc->sc_flags & IWH_F_RUNNING) {
3501 				iwh_m_stop(sc);
3502 				(void) iwh_m_start(sc);
3503 				(void) ieee80211_new_state(ic,
3504 				    IEEE80211_S_SCAN, -1);
3505 			}
3506 		}
3507 	}
3508 }
3509 
3510 /*
3511  * Call back functions for get/set proporty
3512  */
3513 static int
3514 iwh_m_getprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
3515     uint_t pr_flags, uint_t wldp_length, void *wldp_buf, uint_t *perm)
3516 {
3517 	iwh_sc_t *sc;
3518 	int err = EINVAL;
3519 
3520 	if (NULL == arg) {
3521 		return (EINVAL);
3522 	}
3523 	sc = (iwh_sc_t *)arg;
3524 
3525 	err = ieee80211_getprop(&sc->sc_ic, pr_name, wldp_pr_num,
3526 	    pr_flags, wldp_length, wldp_buf, perm);
3527 
3528 	return (err);
3529 }
3530 
3531 static int
3532 iwh_m_setprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
3533     uint_t wldp_length, const void *wldp_buf)
3534 {
3535 	iwh_sc_t *sc;
3536 	ieee80211com_t *ic;
3537 	int err = EINVAL;
3538 
3539 	if (NULL == arg) {
3540 		return (EINVAL);
3541 	}
3542 	sc = (iwh_sc_t *)arg;
3543 	ic = &sc->sc_ic;
3544 
3545 	err = ieee80211_setprop(ic, pr_name, wldp_pr_num, wldp_length,
3546 	    wldp_buf);
3547 
3548 	if (err == ENETRESET) {
3549 		if (ic->ic_des_esslen) {
3550 			if (sc->sc_flags & IWH_F_RUNNING) {
3551 				iwh_m_stop(sc);
3552 				(void) iwh_m_start(sc);
3553 				(void) ieee80211_new_state(ic,
3554 				    IEEE80211_S_SCAN, -1);
3555 			}
3556 		}
3557 		err = 0;
3558 	}
3559 	return (err);
3560 }
3561 
3562 /*
3563  * invoked by GLD supply statistics NIC and driver
3564  */
3565 static int
3566 iwh_m_stat(void *arg, uint_t stat, uint64_t *val)
3567 {
3568 	iwh_sc_t *sc;
3569 	ieee80211com_t *ic;
3570 	ieee80211_node_t *in;
3571 
3572 	if (NULL == arg) {
3573 		return (EINVAL);
3574 	}
3575 	sc = (iwh_sc_t *)arg;
3576 	ic = &sc->sc_ic;
3577 
3578 	mutex_enter(&sc->sc_glock);
3579 
3580 	switch (stat) {
3581 	case MAC_STAT_IFSPEED:
3582 		in = ic->ic_bss;
3583 		*val = ((IEEE80211_FIXED_RATE_NONE == ic->ic_fixed_rate) ?
3584 		    IEEE80211_RATE(in->in_txrate) :
3585 		    ic->ic_fixed_rate) / 2 * 1000000;
3586 		break;
3587 
3588 	case MAC_STAT_NOXMTBUF:
3589 		*val = sc->sc_tx_nobuf;
3590 		break;
3591 
3592 	case MAC_STAT_NORCVBUF:
3593 		*val = sc->sc_rx_nobuf;
3594 		break;
3595 
3596 	case MAC_STAT_IERRORS:
3597 		*val = sc->sc_rx_err;
3598 		break;
3599 
3600 	case MAC_STAT_RBYTES:
3601 		*val = ic->ic_stats.is_rx_bytes;
3602 		break;
3603 
3604 	case MAC_STAT_IPACKETS:
3605 		*val = ic->ic_stats.is_rx_frags;
3606 		break;
3607 
3608 	case MAC_STAT_OBYTES:
3609 		*val = ic->ic_stats.is_tx_bytes;
3610 		break;
3611 
3612 	case MAC_STAT_OPACKETS:
3613 		*val = ic->ic_stats.is_tx_frags;
3614 		break;
3615 
3616 	case MAC_STAT_OERRORS:
3617 	case WIFI_STAT_TX_FAILED:
3618 		*val = sc->sc_tx_err;
3619 		break;
3620 
3621 	case WIFI_STAT_TX_RETRANS:
3622 		*val = sc->sc_tx_retries;
3623 		break;
3624 
3625 	case WIFI_STAT_FCS_ERRORS:
3626 	case WIFI_STAT_WEP_ERRORS:
3627 	case WIFI_STAT_TX_FRAGS:
3628 	case WIFI_STAT_MCAST_TX:
3629 	case WIFI_STAT_RTS_SUCCESS:
3630 	case WIFI_STAT_RTS_FAILURE:
3631 	case WIFI_STAT_ACK_FAILURE:
3632 	case WIFI_STAT_RX_FRAGS:
3633 	case WIFI_STAT_MCAST_RX:
3634 	case WIFI_STAT_RX_DUPS:
3635 		mutex_exit(&sc->sc_glock);
3636 		return (ieee80211_stat(ic, stat, val));
3637 
3638 	default:
3639 		mutex_exit(&sc->sc_glock);
3640 		return (ENOTSUP);
3641 	}
3642 
3643 	mutex_exit(&sc->sc_glock);
3644 
3645 	return (IWH_SUCCESS);
3646 }
3647 
3648 /*
3649  * invoked by GLD to start or open NIC
3650  */
3651 static int
3652 iwh_m_start(void *arg)
3653 {
3654 	iwh_sc_t *sc;
3655 	ieee80211com_t *ic;
3656 	int err = IWH_FAIL;
3657 
3658 	if (NULL == arg) {
3659 		return (EINVAL);
3660 	}
3661 	sc = (iwh_sc_t *)arg;
3662 	ic = &sc->sc_ic;
3663 
3664 	err = iwh_init(sc);
3665 	if (err != IWH_SUCCESS) {
3666 		/*
3667 		 * The hw init err(eg. RF is OFF). Return Success to make
3668 		 * the 'plumb' succeed. The iwh_thread() tries to re-init
3669 		 * background.
3670 		 */
3671 		atomic_or_32(&sc->sc_flags, IWH_F_HW_ERR_RECOVER);
3672 		return (IWH_SUCCESS);
3673 	}
3674 
3675 	ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
3676 
3677 	atomic_or_32(&sc->sc_flags, IWH_F_RUNNING);
3678 
3679 	return (IWH_SUCCESS);
3680 }
3681 
3682 /*
3683  * invoked by GLD to stop or down NIC
3684  */
3685 static void
3686 iwh_m_stop(void *arg)
3687 {
3688 	iwh_sc_t *sc;
3689 	ieee80211com_t *ic;
3690 
3691 	if (NULL == arg) {
3692 		return;
3693 	}
3694 	sc = (iwh_sc_t *)arg;
3695 	ic = &sc->sc_ic;
3696 
3697 	iwh_stop(sc);
3698 
3699 	/*
3700 	 * release buffer for calibration
3701 	 */
3702 	iwh_release_calib_buffer(sc);
3703 
3704 	ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
3705 
3706 	atomic_and_32(&sc->sc_flags, ~IWH_F_HW_ERR_RECOVER);
3707 	atomic_and_32(&sc->sc_flags, ~IWH_F_RATE_AUTO_CTL);
3708 
3709 	atomic_and_32(&sc->sc_flags, ~IWH_F_RUNNING);
3710 	atomic_and_32(&sc->sc_flags, ~IWH_F_SCANNING);
3711 }
3712 
3713 /*
3714  * invoked by GLD to configure NIC
3715  */
3716 static int
3717 iwh_m_unicst(void *arg, const uint8_t *macaddr)
3718 {
3719 	iwh_sc_t *sc;
3720 	ieee80211com_t *ic;
3721 	int err = IWH_SUCCESS;
3722 
3723 	if (NULL == arg) {
3724 		return (EINVAL);
3725 	}
3726 	sc = (iwh_sc_t *)arg;
3727 	ic = &sc->sc_ic;
3728 
3729 	if (!IEEE80211_ADDR_EQ(ic->ic_macaddr, macaddr)) {
3730 		IEEE80211_ADDR_COPY(ic->ic_macaddr, macaddr);
3731 		mutex_enter(&sc->sc_glock);
3732 		err = iwh_config(sc);
3733 		mutex_exit(&sc->sc_glock);
3734 		if (err != IWH_SUCCESS) {
3735 			cmn_err(CE_WARN, "iwh_m_unicst(): "
3736 			    "failed to configure device\n");
3737 			goto fail;
3738 		}
3739 	}
3740 
3741 fail:
3742 	return (err);
3743 }
3744 
3745 /* ARGSUSED */
3746 static int
3747 iwh_m_multicst(void *arg, boolean_t add, const uint8_t *m)
3748 {
3749 	return (IWH_SUCCESS);
3750 }
3751 
3752 /* ARGSUSED */
3753 static int
3754 iwh_m_promisc(void *arg, boolean_t on)
3755 {
3756 	return (IWH_SUCCESS);
3757 }
3758 
3759 /*
3760  * kernel thread to deal with exceptional situation
3761  */
3762 static void
3763 iwh_thread(iwh_sc_t *sc)
3764 {
3765 	ieee80211com_t *ic = &sc->sc_ic;
3766 	clock_t clk;
3767 	int err, n = 0, timeout = 0;
3768 	uint32_t tmp;
3769 #ifdef	DEBUG
3770 	int times = 0;
3771 #endif
3772 
3773 	while (sc->sc_mf_thread_switch) {
3774 		tmp = IWH_READ(sc, CSR_GP_CNTRL);
3775 		if (tmp & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) {
3776 			atomic_and_32(&sc->sc_flags, ~IWH_F_RADIO_OFF);
3777 		} else {
3778 			atomic_or_32(&sc->sc_flags, IWH_F_RADIO_OFF);
3779 		}
3780 
3781 		/*
3782 		 * If  in SUSPEND or the RF is OFF, do nothing.
3783 		 */
3784 		if (sc->sc_flags & IWH_F_RADIO_OFF) {
3785 			delay(drv_usectohz(100000));
3786 			continue;
3787 		}
3788 
3789 		/*
3790 		 * recovery fatal error
3791 		 */
3792 		if (ic->ic_mach &&
3793 		    (sc->sc_flags & IWH_F_HW_ERR_RECOVER)) {
3794 
3795 			IWH_DBG((IWH_DEBUG_FW, "iwh_thread(): "
3796 			    "try to recover fatal hw error: %d\n", times++));
3797 
3798 			iwh_stop(sc);
3799 
3800 			if (IWH_CHK_FAST_RECOVER(sc)) {
3801 				/*
3802 				 * save runtime configuration
3803 				 */
3804 				bcopy(&sc->sc_config, &sc->sc_config_save,
3805 				    sizeof (sc->sc_config));
3806 			} else {
3807 				ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
3808 				delay(drv_usectohz(2000000 + n*500000));
3809 			}
3810 
3811 			err = iwh_init(sc);
3812 			if (err != IWH_SUCCESS) {
3813 				n++;
3814 				if (n < 20) {
3815 					continue;
3816 				}
3817 			}
3818 
3819 			n = 0;
3820 			if (!err) {
3821 				atomic_or_32(&sc->sc_flags, IWH_F_RUNNING);
3822 			}
3823 
3824 
3825 			if (!IWH_CHK_FAST_RECOVER(sc) ||
3826 			    iwh_fast_recover(sc) != IWH_SUCCESS) {
3827 				atomic_and_32(&sc->sc_flags,
3828 				    ~IWH_F_HW_ERR_RECOVER);
3829 
3830 				delay(drv_usectohz(2000000));
3831 				if (sc->sc_ostate != IEEE80211_S_INIT) {
3832 					ieee80211_new_state(ic,
3833 					    IEEE80211_S_SCAN, 0);
3834 				}
3835 			}
3836 		}
3837 
3838 		if (ic->ic_mach &&
3839 		    (sc->sc_flags & IWH_F_SCANNING) && sc->sc_scan_pending) {
3840 			IWH_DBG((IWH_DEBUG_SCAN, "iwh_thread(): "
3841 			    "wait for probe response\n"));
3842 
3843 			sc->sc_scan_pending--;
3844 			delay(drv_usectohz(200000));
3845 			ieee80211_next_scan(ic);
3846 		}
3847 
3848 		/*
3849 		 * rate ctl
3850 		 */
3851 		if (ic->ic_mach &&
3852 		    (sc->sc_flags & IWH_F_RATE_AUTO_CTL)) {
3853 			clk = ddi_get_lbolt();
3854 			if (clk > sc->sc_clk + drv_usectohz(1000000)) {
3855 				iwh_amrr_timeout(sc);
3856 			}
3857 		}
3858 
3859 		if ((ic->ic_state == IEEE80211_S_RUN) &&
3860 		    (ic->ic_beaconmiss++ > 100)) {	/* 10 seconds */
3861 			cmn_err(CE_WARN, "iwh: beacon missed for 10 seconds\n");
3862 			(void) ieee80211_new_state(ic,
3863 			    IEEE80211_S_INIT, -1);
3864 		}
3865 
3866 		delay(drv_usectohz(100000));
3867 
3868 		mutex_enter(&sc->sc_mt_lock);
3869 		if (sc->sc_tx_timer) {
3870 			timeout++;
3871 			if (10 == timeout) {
3872 				sc->sc_tx_timer--;
3873 				if (0 == sc->sc_tx_timer) {
3874 					atomic_or_32(&sc->sc_flags,
3875 					    IWH_F_HW_ERR_RECOVER);
3876 					sc->sc_ostate = IEEE80211_S_RUN;
3877 					IWH_DBG((IWH_DEBUG_FW, "iwh_thread(): "
3878 					    "try to recover from "
3879 					    "send fail\n"));
3880 				}
3881 				timeout = 0;
3882 			}
3883 		}
3884 		mutex_exit(&sc->sc_mt_lock);
3885 	}
3886 
3887 	mutex_enter(&sc->sc_mt_lock);
3888 	sc->sc_mf_thread = NULL;
3889 	cv_signal(&sc->sc_mt_cv);
3890 	mutex_exit(&sc->sc_mt_lock);
3891 }
3892 
3893 /*
3894  * Send a command to the ucode.
3895  */
3896 static int
3897 iwh_cmd(iwh_sc_t *sc, int code, const void *buf, int size, int async)
3898 {
3899 	iwh_tx_ring_t *ring = &sc->sc_txq[IWH_CMD_QUEUE_NUM];
3900 	iwh_tx_desc_t *desc;
3901 	iwh_cmd_t *cmd;
3902 
3903 	ASSERT(size <= sizeof (cmd->data));
3904 	ASSERT(mutex_owned(&sc->sc_glock));
3905 
3906 	IWH_DBG((IWH_DEBUG_CMD, "iwh_cmd() "
3907 	    "code[%d]", code));
3908 	desc = ring->data[ring->cur].desc;
3909 	cmd = ring->data[ring->cur].cmd;
3910 
3911 	cmd->hdr.type = (uint8_t)code;
3912 	cmd->hdr.flags = 0;
3913 	cmd->hdr.qid = ring->qid;
3914 	cmd->hdr.idx = ring->cur;
3915 	bcopy(buf, cmd->data, size);
3916 	(void) memset(desc, 0, sizeof (*desc));
3917 
3918 	desc->val0 = 1 << 24;
3919 	desc->pa[0].tb1_addr =
3920 	    (uint32_t)(ring->data[ring->cur].paddr_cmd & 0xffffffff);
3921 	desc->pa[0].val1 = ((4 + size) << 4) & 0xfff0;
3922 
3923 	if (async) {
3924 		sc->sc_cmd_accum++;
3925 	}
3926 
3927 	/*
3928 	 * kick cmd ring XXX
3929 	 */
3930 	sc->sc_shared->queues_byte_cnt_tbls[ring->qid].
3931 	    tfd_offset[ring->cur].val = 8;
3932 	if (ring->cur < IWH_MAX_WIN_SIZE) {
3933 		sc->sc_shared->queues_byte_cnt_tbls[ring->qid].
3934 		    tfd_offset[IWH_QUEUE_SIZE + ring->cur].val = 8;
3935 	}
3936 	ring->cur = (ring->cur + 1) % ring->count;
3937 	IWH_WRITE(sc, HBUS_TARG_WRPTR, ring->qid << 8 | ring->cur);
3938 
3939 	if (async) {
3940 		return (IWH_SUCCESS);
3941 	} else {
3942 		clock_t clk;
3943 
3944 		clk = ddi_get_lbolt() + drv_usectohz(2000000);
3945 		while (sc->sc_cmd_flag != SC_CMD_FLG_DONE) {
3946 			if (cv_timedwait(&sc->sc_cmd_cv,
3947 			    &sc->sc_glock, clk) < 0) {
3948 				break;
3949 			}
3950 		}
3951 
3952 		if (SC_CMD_FLG_DONE == sc->sc_cmd_flag) {
3953 			sc->sc_cmd_flag = SC_CMD_FLG_NONE;
3954 			return (IWH_SUCCESS);
3955 		} else {
3956 			sc->sc_cmd_flag = SC_CMD_FLG_NONE;
3957 			return (IWH_FAIL);
3958 		}
3959 	}
3960 }
3961 
3962 /*
3963  * require ucode seting led of NIC
3964  */
3965 static void
3966 iwh_set_led(iwh_sc_t *sc, uint8_t id, uint8_t off, uint8_t on)
3967 {
3968 	iwh_led_cmd_t led;
3969 
3970 	led.interval = LE_32(100000);	/* unit: 100ms */
3971 	led.id = id;
3972 	led.off = off;
3973 	led.on = on;
3974 
3975 	(void) iwh_cmd(sc, REPLY_LEDS_CMD, &led, sizeof (led), 1);
3976 }
3977 
3978 /*
3979  * necessary setting to NIC before authentication
3980  */
3981 static int
3982 iwh_hw_set_before_auth(iwh_sc_t *sc)
3983 {
3984 	ieee80211com_t *ic = &sc->sc_ic;
3985 	ieee80211_node_t *in = ic->ic_bss;
3986 	int err = IWH_FAIL;
3987 
3988 	/*
3989 	 * update adapter's configuration according
3990 	 * the info of target AP
3991 	 */
3992 	IEEE80211_ADDR_COPY(sc->sc_config.bssid, in->in_bssid);
3993 	sc->sc_config.chan = LE_16(ieee80211_chan2ieee(ic, in->in_chan));
3994 
3995 	if (ic->ic_curmode != IEEE80211_MODE_11NG) {
3996 
3997 		sc->sc_config.ofdm_ht_triple_stream_basic_rates = 0;
3998 		sc->sc_config.ofdm_ht_dual_stream_basic_rates = 0;
3999 		sc->sc_config.ofdm_ht_single_stream_basic_rates = 0;
4000 
4001 		if (IEEE80211_MODE_11B == ic->ic_curmode) {
4002 			sc->sc_config.cck_basic_rates  = 0x03;
4003 			sc->sc_config.ofdm_basic_rates = 0;
4004 		} else if ((in->in_chan != IEEE80211_CHAN_ANYC) &&
4005 		    (IEEE80211_IS_CHAN_5GHZ(in->in_chan))) {
4006 			sc->sc_config.cck_basic_rates  = 0;
4007 			sc->sc_config.ofdm_basic_rates = 0x15;
4008 		} else { /* assume 802.11b/g */
4009 			sc->sc_config.cck_basic_rates  = 0x0f;
4010 			sc->sc_config.ofdm_basic_rates = 0xff;
4011 		}
4012 	}
4013 
4014 	sc->sc_config.flags &= ~LE_32(RXON_FLG_SHORT_PREAMBLE_MSK |
4015 	    RXON_FLG_SHORT_SLOT_MSK);
4016 
4017 	if (ic->ic_flags & IEEE80211_F_SHSLOT) {
4018 		sc->sc_config.flags |= LE_32(RXON_FLG_SHORT_SLOT_MSK);
4019 	} else {
4020 		sc->sc_config.flags &= LE_32(~RXON_FLG_SHORT_SLOT_MSK);
4021 	}
4022 
4023 	if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) {
4024 		sc->sc_config.flags |= LE_32(RXON_FLG_SHORT_PREAMBLE_MSK);
4025 	} else {
4026 		sc->sc_config.flags &= LE_32(~RXON_FLG_SHORT_PREAMBLE_MSK);
4027 	}
4028 
4029 	IWH_DBG((IWH_DEBUG_80211, "iwh_hw_set_before_auth(): "
4030 	    "config chan %d flags %x "
4031 	    "filter_flags %x  cck %x ofdm %x"
4032 	    " bssid:%02x:%02x:%02x:%02x:%02x:%2x\n",
4033 	    LE_16(sc->sc_config.chan), LE_32(sc->sc_config.flags),
4034 	    LE_32(sc->sc_config.filter_flags),
4035 	    sc->sc_config.cck_basic_rates, sc->sc_config.ofdm_basic_rates,
4036 	    sc->sc_config.bssid[0], sc->sc_config.bssid[1],
4037 	    sc->sc_config.bssid[2], sc->sc_config.bssid[3],
4038 	    sc->sc_config.bssid[4], sc->sc_config.bssid[5]));
4039 
4040 	err = iwh_cmd(sc, REPLY_RXON, &sc->sc_config,
4041 	    sizeof (iwh_rxon_cmd_t), 1);
4042 	if (err != IWH_SUCCESS) {
4043 		cmn_err(CE_WARN, "iwh_hw_set_before_auth(): "
4044 		    "failed to config chan%d\n", sc->sc_config.chan);
4045 		return (err);
4046 	}
4047 
4048 	if ((sc->sc_dev_id != 0x423c) &&
4049 	    (sc->sc_dev_id != 0x423d)) {
4050 		err = iwh_tx_power_table(sc, 1);
4051 		if (err != IWH_SUCCESS) {
4052 			return (err);
4053 		}
4054 	}
4055 
4056 	/*
4057 	 * add default AP node
4058 	 */
4059 	err = iwh_add_ap_sta(sc);
4060 	if (err != IWH_SUCCESS) {
4061 		return (err);
4062 	}
4063 
4064 	if ((sc->sc_dev_id != 0x423c) &&
4065 	    (sc->sc_dev_id != 0x423d)) {
4066 		/*
4067 		 * set up retry rate table for AP node
4068 		 */
4069 		err = iwh_ap_lq(sc);
4070 		if (err != IWH_SUCCESS) {
4071 			return (err);
4072 		}
4073 	}
4074 
4075 	return (err);
4076 }
4077 
4078 /*
4079  * Send a scan request(assembly scan cmd) to the firmware.
4080  */
4081 static int
4082 iwh_scan(iwh_sc_t *sc)
4083 {
4084 	ieee80211com_t *ic = &sc->sc_ic;
4085 	iwh_tx_ring_t *ring = &sc->sc_txq[IWH_CMD_QUEUE_NUM];
4086 	iwh_tx_desc_t *desc;
4087 	iwh_tx_data_t *data;
4088 	iwh_cmd_t *cmd;
4089 	iwh_scan_hdr_t *hdr;
4090 	iwh_scan_chan_t chan;
4091 	struct ieee80211_frame *wh;
4092 	ieee80211_node_t *in = ic->ic_bss;
4093 	uint8_t essid[IEEE80211_NWID_LEN+1];
4094 	struct ieee80211_rateset *rs;
4095 	enum ieee80211_phymode mode;
4096 	uint8_t *frm;
4097 	int i, pktlen, nrates;
4098 
4099 	data = &ring->data[ring->cur];
4100 	desc = data->desc;
4101 	cmd = (iwh_cmd_t *)data->dma_data.mem_va;
4102 
4103 	cmd->hdr.type = REPLY_SCAN_CMD;
4104 	cmd->hdr.flags = 0;
4105 	cmd->hdr.qid = ring->qid;
4106 	cmd->hdr.idx = ring->cur | 0x40;
4107 
4108 	hdr = (iwh_scan_hdr_t *)cmd->data;
4109 	(void) memset(hdr, 0, sizeof (iwh_scan_hdr_t));
4110 	hdr->nchan = 1;
4111 	hdr->quiet_time = LE_16(50);
4112 	hdr->quiet_plcp_th = LE_16(1);
4113 
4114 	hdr->flags = LE_32(RXON_FLG_BAND_24G_MSK);
4115 	hdr->rx_chain = LE_16(RXON_RX_CHAIN_DRIVER_FORCE_MSK |
4116 	    (0x7 << RXON_RX_CHAIN_VALID_POS) |
4117 	    (0x2 << RXON_RX_CHAIN_FORCE_SEL_POS) |
4118 	    (0x2 << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS));
4119 
4120 	hdr->tx_cmd.tx_flags = LE_32(TX_CMD_FLG_SEQ_CTL_MSK);
4121 	hdr->tx_cmd.sta_id = IWH_BROADCAST_ID;
4122 	hdr->tx_cmd.stop_time.life_time = LE_32(0xffffffff);
4123 	hdr->tx_cmd.rate.r.rate_n_flags = LE_32(iwh_rate_to_plcp(2));
4124 	hdr->tx_cmd.rate.r.rate_n_flags |=
4125 	    LE_32(RATE_MCS_ANT_B_MSK |RATE_MCS_CCK_MSK);
4126 	hdr->direct_scan[0].len = ic->ic_des_esslen;
4127 	hdr->direct_scan[0].id  = IEEE80211_ELEMID_SSID;
4128 
4129 	hdr->filter_flags = LE_32(RXON_FILTER_ACCEPT_GRP_MSK |
4130 	    RXON_FILTER_BCON_AWARE_MSK);
4131 
4132 	if (ic->ic_des_esslen) {
4133 		bcopy(ic->ic_des_essid, essid, ic->ic_des_esslen);
4134 		essid[ic->ic_des_esslen] = '\0';
4135 		IWH_DBG((IWH_DEBUG_SCAN, "iwh_scan(): "
4136 		    "directed scan %s\n", essid));
4137 
4138 		bcopy(ic->ic_des_essid, hdr->direct_scan[0].ssid,
4139 		    ic->ic_des_esslen);
4140 	} else {
4141 		bzero(hdr->direct_scan[0].ssid,
4142 		    sizeof (hdr->direct_scan[0].ssid));
4143 	}
4144 
4145 	/*
4146 	 * a probe request frame is required after the REPLY_SCAN_CMD
4147 	 */
4148 	wh = (struct ieee80211_frame *)(hdr + 1);
4149 	wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT |
4150 	    IEEE80211_FC0_SUBTYPE_PROBE_REQ;
4151 	wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
4152 	(void) memset(wh->i_addr1, 0xff, 6);
4153 	IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_macaddr);
4154 	(void) memset(wh->i_addr3, 0xff, 6);
4155 	*(uint16_t *)&wh->i_dur[0] = 0;
4156 	*(uint16_t *)&wh->i_seq[0] = 0;
4157 
4158 	frm = (uint8_t *)(wh + 1);
4159 
4160 	/*
4161 	 * essid IE
4162 	 */
4163 	if (in->in_esslen) {
4164 		bcopy(in->in_essid, essid, in->in_esslen);
4165 		essid[in->in_esslen] = '\0';
4166 		IWH_DBG((IWH_DEBUG_SCAN, "iwh_scan(): "
4167 		    "probe with ESSID %s\n",
4168 		    essid));
4169 	}
4170 	*frm++ = IEEE80211_ELEMID_SSID;
4171 	*frm++ = in->in_esslen;
4172 	bcopy(in->in_essid, frm, in->in_esslen);
4173 	frm += in->in_esslen;
4174 
4175 	mode = ieee80211_chan2mode(ic, ic->ic_curchan);
4176 	rs = &ic->ic_sup_rates[mode];
4177 
4178 	/*
4179 	 * supported rates IE
4180 	 */
4181 	*frm++ = IEEE80211_ELEMID_RATES;
4182 	nrates = rs->ir_nrates;
4183 	if (nrates > IEEE80211_RATE_SIZE) {
4184 		nrates = IEEE80211_RATE_SIZE;
4185 	}
4186 
4187 	*frm++ = (uint8_t)nrates;
4188 	bcopy(rs->ir_rates, frm, nrates);
4189 	frm += nrates;
4190 
4191 	/*
4192 	 * supported xrates IE
4193 	 */
4194 	if (rs->ir_nrates > IEEE80211_RATE_SIZE) {
4195 		nrates = rs->ir_nrates - IEEE80211_RATE_SIZE;
4196 		*frm++ = IEEE80211_ELEMID_XRATES;
4197 		*frm++ = (uint8_t)nrates;
4198 		bcopy(rs->ir_rates + IEEE80211_RATE_SIZE, frm, nrates);
4199 		frm += nrates;
4200 	}
4201 
4202 	/*
4203 	 * optionnal IE (usually for wpa)
4204 	 */
4205 	if (ic->ic_opt_ie != NULL) {
4206 		bcopy(ic->ic_opt_ie, frm, ic->ic_opt_ie_len);
4207 		frm += ic->ic_opt_ie_len;
4208 	}
4209 
4210 	/* setup length of probe request */
4211 	hdr->tx_cmd.len = LE_16(_PTRDIFF(frm, wh));
4212 	hdr->len = LE_16(hdr->nchan * sizeof (iwh_scan_chan_t) +
4213 	    LE_16(hdr->tx_cmd.len) + sizeof (iwh_scan_hdr_t));
4214 
4215 	/*
4216 	 * the attribute of the scan channels are required after the probe
4217 	 * request frame.
4218 	 */
4219 	for (i = 1; i <= hdr->nchan; i++) {
4220 		if (ic->ic_des_esslen) {
4221 			chan.type = LE_32(3);
4222 		} else {
4223 			chan.type = LE_32(1);
4224 		}
4225 
4226 		chan.chan = LE_16(ieee80211_chan2ieee(ic, ic->ic_curchan));
4227 		chan.tpc.tx_gain = 0x28;
4228 		chan.tpc.dsp_atten = 110;
4229 		chan.active_dwell = LE_16(50);
4230 		chan.passive_dwell = LE_16(120);
4231 
4232 		bcopy(&chan, frm, sizeof (iwh_scan_chan_t));
4233 		frm += sizeof (iwh_scan_chan_t);
4234 	}
4235 
4236 	pktlen = _PTRDIFF(frm, cmd);
4237 
4238 	(void) memset(desc, 0, sizeof (*desc));
4239 	desc->val0 = 1 << 24;
4240 	desc->pa[0].tb1_addr =
4241 	    (uint32_t)(data->dma_data.cookie.dmac_address & 0xffffffff);
4242 	desc->pa[0].val1 = (pktlen << 4) & 0xfff0;
4243 
4244 	/*
4245 	 * maybe for cmd, filling the byte cnt table is not necessary.
4246 	 * anyway, we fill it here.
4247 	 */
4248 	sc->sc_shared->queues_byte_cnt_tbls[ring->qid]
4249 	    .tfd_offset[ring->cur].val = 8;
4250 	if (ring->cur < IWH_MAX_WIN_SIZE) {
4251 		sc->sc_shared->queues_byte_cnt_tbls[ring->qid].
4252 		    tfd_offset[IWH_QUEUE_SIZE + ring->cur].val = 8;
4253 	}
4254 
4255 	/*
4256 	 * kick cmd ring
4257 	 */
4258 	ring->cur = (ring->cur + 1) % ring->count;
4259 	IWH_WRITE(sc, HBUS_TARG_WRPTR, ring->qid << 8 | ring->cur);
4260 
4261 	return (IWH_SUCCESS);
4262 }
4263 
4264 /*
4265  * configure NIC by using ucode commands after loading ucode.
4266  */
4267 static int
4268 iwh_config(iwh_sc_t *sc)
4269 {
4270 	ieee80211com_t *ic = &sc->sc_ic;
4271 	iwh_powertable_cmd_t powertable;
4272 	iwh_bt_cmd_t bt;
4273 	iwh_add_sta_t node;
4274 	iwh_rem_sta_t rm_sta;
4275 	const uint8_t bcast[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
4276 	iwh_link_quality_cmd_t link_quality;
4277 	int i, err = IWH_FAIL;
4278 	uint16_t masks = 0;
4279 
4280 	/*
4281 	 * set power mode. Disable power management at present, do it later
4282 	 */
4283 	(void) memset(&powertable, 0, sizeof (powertable));
4284 	powertable.flags = LE_16(0x8);
4285 	err = iwh_cmd(sc, POWER_TABLE_CMD, &powertable,
4286 	    sizeof (powertable), 0);
4287 	if (err != IWH_SUCCESS) {
4288 		cmn_err(CE_WARN, "iwh_config(): "
4289 		    "failed to set power mode\n");
4290 		return (err);
4291 	}
4292 
4293 	/*
4294 	 * configure bt coexistence
4295 	 */
4296 	(void) memset(&bt, 0, sizeof (bt));
4297 	bt.flags = 3;
4298 	bt.lead_time = 0xaa;
4299 	bt.max_kill = 1;
4300 	err = iwh_cmd(sc, REPLY_BT_CONFIG, &bt,
4301 	    sizeof (bt), 0);
4302 	if (err != IWH_SUCCESS) {
4303 		cmn_err(CE_WARN, "iwh_config(): "
4304 		    "failed to configurate bt coexistence\n");
4305 		return (err);
4306 	}
4307 
4308 	/*
4309 	 * configure rxon
4310 	 */
4311 	(void) memset(&sc->sc_config, 0, sizeof (iwh_rxon_cmd_t));
4312 	IEEE80211_ADDR_COPY(sc->sc_config.node_addr, ic->ic_macaddr);
4313 	IEEE80211_ADDR_COPY(sc->sc_config.wlap_bssid, ic->ic_macaddr);
4314 	sc->sc_config.chan = LE_16(ieee80211_chan2ieee(ic, ic->ic_curchan));
4315 	sc->sc_config.flags = LE_32(RXON_FLG_BAND_24G_MSK);
4316 	sc->sc_config.flags &= LE_32(~(RXON_FLG_CHANNEL_MODE_MIXED_MSK |
4317 	    RXON_FLG_CHANNEL_MODE_PURE_40_MSK));
4318 
4319 	switch (ic->ic_opmode) {
4320 	case IEEE80211_M_STA:
4321 		sc->sc_config.dev_type = RXON_DEV_TYPE_ESS;
4322 		sc->sc_config.filter_flags |= LE_32(RXON_FILTER_ACCEPT_GRP_MSK |
4323 		    RXON_FILTER_DIS_DECRYPT_MSK |
4324 		    RXON_FILTER_DIS_GRP_DECRYPT_MSK);
4325 		break;
4326 
4327 	case IEEE80211_M_IBSS:
4328 	case IEEE80211_M_AHDEMO:
4329 		sc->sc_config.dev_type = RXON_DEV_TYPE_IBSS;
4330 
4331 		sc->sc_config.flags |= LE_32(RXON_FLG_SHORT_PREAMBLE_MSK);
4332 		sc->sc_config.filter_flags = LE_32(RXON_FILTER_ACCEPT_GRP_MSK |
4333 		    RXON_FILTER_DIS_DECRYPT_MSK |
4334 		    RXON_FILTER_DIS_GRP_DECRYPT_MSK);
4335 		break;
4336 
4337 	case IEEE80211_M_HOSTAP:
4338 		sc->sc_config.dev_type = RXON_DEV_TYPE_AP;
4339 		break;
4340 
4341 	case IEEE80211_M_MONITOR:
4342 		sc->sc_config.dev_type = RXON_DEV_TYPE_SNIFFER;
4343 		sc->sc_config.filter_flags |= LE_32(RXON_FILTER_ACCEPT_GRP_MSK |
4344 		    RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_PROMISC_MSK);
4345 		break;
4346 	}
4347 
4348 	/*
4349 	 * Support all CCK rates.
4350 	 */
4351 	sc->sc_config.cck_basic_rates  = 0x0f;
4352 
4353 	/*
4354 	 * Support all OFDM rates.
4355 	 */
4356 	sc->sc_config.ofdm_basic_rates = 0xff;
4357 
4358 	/*
4359 	 * Determine HT supported rates.
4360 	 */
4361 	switch (sc->sc_ht_conf.rx_stream_count) {
4362 	case 3:
4363 		sc->sc_config.ofdm_ht_triple_stream_basic_rates = 0xff;
4364 		sc->sc_config.ofdm_ht_dual_stream_basic_rates = 0xff;
4365 		sc->sc_config.ofdm_ht_single_stream_basic_rates = 0xff;
4366 		break;
4367 	case 2:
4368 		sc->sc_config.ofdm_ht_dual_stream_basic_rates = 0xff;
4369 		sc->sc_config.ofdm_ht_single_stream_basic_rates = 0xff;
4370 		break;
4371 	case 1:
4372 		sc->sc_config.ofdm_ht_single_stream_basic_rates = 0xff;
4373 		break;
4374 	default:
4375 		cmn_err(CE_WARN, "iwh_config(): "
4376 		    "RX stream count %d is not in suitable range\n",
4377 		    sc->sc_ht_conf.rx_stream_count);
4378 		return (IWH_FAIL);
4379 	}
4380 
4381 	/*
4382 	 * set RX chains/antennas.
4383 	 */
4384 	iwh_config_rxon_chain(sc);
4385 
4386 	err = iwh_cmd(sc, REPLY_RXON, &sc->sc_config,
4387 	    sizeof (iwh_rxon_cmd_t), 0);
4388 	if (err != IWH_SUCCESS) {
4389 		cmn_err(CE_WARN, "iwh_config(): "
4390 		    "failed to set configure command\n");
4391 		return (err);
4392 	}
4393 
4394 	/*
4395 	 * remove all nodes in NIC
4396 	 */
4397 	(void) memset(&rm_sta, 0, sizeof (rm_sta));
4398 	rm_sta.num_sta = 1;
4399 	bcopy(bcast, rm_sta.addr, 6);
4400 
4401 	err = iwh_cmd(sc, REPLY_REMOVE_STA, &rm_sta, sizeof (iwh_rem_sta_t), 0);
4402 	if (err != IWH_SUCCESS) {
4403 		cmn_err(CE_WARN, "iwh_config(): "
4404 		    "failed to remove broadcast node in hardware.\n");
4405 		return (err);
4406 	}
4407 
4408 	if ((sc->sc_dev_id != 0x423c) &&
4409 	    (sc->sc_dev_id != 0x423d)) {
4410 		/*
4411 		 * configure TX power table
4412 		 */
4413 		err = iwh_tx_power_table(sc, 0);
4414 		if (err != IWH_SUCCESS) {
4415 			return (err);
4416 		}
4417 	}
4418 
4419 	/*
4420 	 * add broadcast node so that we can send broadcast frame
4421 	 */
4422 	(void) memset(&node, 0, sizeof (node));
4423 	(void) memset(node.sta.addr, 0xff, 6);
4424 	node.mode = 0;
4425 	node.sta.sta_id = IWH_BROADCAST_ID;
4426 	node.station_flags = 0;
4427 
4428 	err = iwh_cmd(sc, REPLY_ADD_STA, &node, sizeof (node), 0);
4429 	if (err != IWH_SUCCESS) {
4430 		cmn_err(CE_WARN, "iwh_config(): "
4431 		    "failed to add broadcast node\n");
4432 		return (err);
4433 	}
4434 
4435 	if ((sc->sc_dev_id != 0x423c) &&
4436 	    (sc->sc_dev_id != 0x423d)) {
4437 		/*
4438 		 * TX_LINK_QUALITY cmd
4439 		 */
4440 		(void) memset(&link_quality, 0, sizeof (link_quality));
4441 		for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) {
4442 			masks |= RATE_MCS_CCK_MSK;
4443 			masks |= RATE_MCS_ANT_B_MSK;
4444 			masks &= ~RATE_MCS_ANT_A_MSK;
4445 			link_quality.rate_n_flags[i] =
4446 			    LE_32(iwh_rate_to_plcp(2) | masks);
4447 		}
4448 
4449 		link_quality.general_params.single_stream_ant_msk = 2;
4450 		link_quality.general_params.dual_stream_ant_msk = 3;
4451 		link_quality.agg_params.agg_dis_start_th = 3;
4452 		link_quality.agg_params.agg_time_limit = LE_16(4000);
4453 		link_quality.sta_id = IWH_BROADCAST_ID;
4454 		err = iwh_cmd(sc, REPLY_TX_LINK_QUALITY_CMD, &link_quality,
4455 		    sizeof (link_quality), 0);
4456 		if (err != IWH_SUCCESS) {
4457 			cmn_err(CE_WARN, "iwh_config(): "
4458 			    "failed to config link quality table\n");
4459 			return (err);
4460 		}
4461 	}
4462 
4463 	return (err);
4464 }
4465 
4466 /*
4467  * quiesce(9E) entry point.
4468  * This function is called when the system is single-threaded at high
4469  * PIL with preemption disabled. Therefore, this function must not be
4470  * blocked.
4471  * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
4472  * DDI_FAILURE indicates an error condition and should almost never happen.
4473  */
4474 static int
4475 iwh_quiesce(dev_info_t *dip)
4476 {
4477 	iwh_sc_t *sc;
4478 
4479 	sc = ddi_get_soft_state(iwh_soft_state_p, ddi_get_instance(dip));
4480 	if (sc == NULL) {
4481 		return (DDI_FAILURE);
4482 	}
4483 
4484 #ifdef DEBUG
4485 	/*
4486 	 * by pass any messages, if it's quiesce
4487 	 */
4488 	iwh_dbg_flags = 0;
4489 #endif
4490 
4491 	/*
4492 	 * No more blocking is allowed while we are in the
4493 	 * quiesce(9E) entry point.
4494 	 */
4495 	atomic_or_32(&sc->sc_flags, IWH_F_QUIESCED);
4496 
4497 	/*
4498 	 * Disable and mask all interrupts.
4499 	 */
4500 	iwh_stop(sc);
4501 
4502 	return (DDI_SUCCESS);
4503 }
4504 
4505 static void
4506 iwh_stop_master(iwh_sc_t *sc)
4507 {
4508 	uint32_t tmp;
4509 	int n;
4510 
4511 	tmp = IWH_READ(sc, CSR_RESET);
4512 	IWH_WRITE(sc, CSR_RESET, tmp | CSR_RESET_REG_FLAG_STOP_MASTER);
4513 
4514 	tmp = IWH_READ(sc, CSR_GP_CNTRL);
4515 	if ((tmp & CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE) ==
4516 	    CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE) {
4517 		return;
4518 	}
4519 
4520 	for (n = 0; n < 2000; n++) {
4521 		if (IWH_READ(sc, CSR_RESET) &
4522 		    CSR_RESET_REG_FLAG_MASTER_DISABLED) {
4523 			break;
4524 		}
4525 		DELAY(1000);
4526 	}
4527 
4528 #ifdef	DEBUG
4529 	if (2000 == n) {
4530 		IWH_DBG((IWH_DEBUG_HW, "iwh_stop_master(): "
4531 		    "timeout waiting for master stop\n"));
4532 	}
4533 #endif
4534 }
4535 
4536 static int
4537 iwh_power_up(iwh_sc_t *sc)
4538 {
4539 	uint32_t tmp;
4540 
4541 	iwh_mac_access_enter(sc);
4542 	tmp = iwh_reg_read(sc, ALM_APMG_PS_CTL);
4543 	tmp &= ~APMG_PS_CTRL_REG_MSK_POWER_SRC;
4544 	tmp |= APMG_PS_CTRL_REG_VAL_POWER_SRC_VMAIN;
4545 	iwh_reg_write(sc, ALM_APMG_PS_CTL, tmp);
4546 	iwh_mac_access_exit(sc);
4547 
4548 	DELAY(5000);
4549 	return (IWH_SUCCESS);
4550 }
4551 
4552 /*
4553  * hardware initialization
4554  */
4555 static int
4556 iwh_preinit(iwh_sc_t *sc)
4557 {
4558 	int n;
4559 	uint8_t vlink;
4560 	uint16_t radio_cfg;
4561 	uint32_t tmp;
4562 
4563 	/*
4564 	 * clear any pending interrupts
4565 	 */
4566 	IWH_WRITE(sc, CSR_INT, 0xffffffff);
4567 
4568 	tmp = IWH_READ(sc, CSR_GIO_CHICKEN_BITS);
4569 	IWH_WRITE(sc, CSR_GIO_CHICKEN_BITS,
4570 	    tmp | CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
4571 
4572 	tmp = IWH_READ(sc, CSR_ANA_PLL_CFG);
4573 	IWH_WRITE(sc, CSR_ANA_PLL_CFG, tmp | IWH_CSR_ANA_PLL_CFG);
4574 
4575 	tmp = IWH_READ(sc, CSR_GP_CNTRL);
4576 	IWH_WRITE(sc, CSR_GP_CNTRL, tmp | CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
4577 
4578 	/*
4579 	 * wait for clock ready
4580 	 */
4581 	for (n = 0; n < 1000; n++) {
4582 		if (IWH_READ(sc, CSR_GP_CNTRL) &
4583 		    CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY) {
4584 			break;
4585 		}
4586 		DELAY(10);
4587 	}
4588 
4589 	if (1000 == n) {
4590 		return (ETIMEDOUT);
4591 	}
4592 
4593 	iwh_mac_access_enter(sc);
4594 
4595 	iwh_reg_write(sc, ALM_APMG_CLK_EN, APMG_CLK_REG_VAL_DMA_CLK_RQT);
4596 
4597 	DELAY(20);
4598 	tmp = iwh_reg_read(sc, ALM_APMG_PCIDEV_STT);
4599 	iwh_reg_write(sc, ALM_APMG_PCIDEV_STT, tmp |
4600 	    APMG_DEV_STATE_REG_VAL_L1_ACTIVE_DISABLE);
4601 	iwh_mac_access_exit(sc);
4602 
4603 	radio_cfg = IWH_READ_EEP_SHORT(sc, EEP_SP_RADIO_CONFIGURATION);
4604 	if (SP_RADIO_TYPE_MSK(radio_cfg) < SP_RADIO_TYPE_MAX) {
4605 		tmp = IWH_READ(sc, CSR_HW_IF_CONFIG_REG);
4606 		IWH_WRITE(sc, CSR_HW_IF_CONFIG_REG,
4607 		    tmp | SP_RADIO_TYPE_MSK(radio_cfg) |
4608 		    SP_RADIO_STEP_MSK(radio_cfg) |
4609 		    SP_RADIO_DASH_MSK(radio_cfg));
4610 	} else {
4611 		cmn_err(CE_WARN, "iwh_preinit(): "
4612 		    "radio configuration information in eeprom is wrong\n");
4613 		return (IWH_FAIL);
4614 	}
4615 
4616 
4617 	IWH_WRITE(sc, CSR_INT_COALESCING, 512 / 32);
4618 
4619 	(void) iwh_power_up(sc);
4620 
4621 	if ((sc->sc_rev & 0x80) == 0x80 && (sc->sc_rev & 0x7f) < 8) {
4622 		tmp = ddi_get32(sc->sc_cfg_handle,
4623 		    (uint32_t *)(sc->sc_cfg_base + 0xe8));
4624 		ddi_put32(sc->sc_cfg_handle,
4625 		    (uint32_t *)(sc->sc_cfg_base + 0xe8),
4626 		    tmp & ~(1 << 11));
4627 	}
4628 
4629 	vlink = ddi_get8(sc->sc_cfg_handle,
4630 	    (uint8_t *)(sc->sc_cfg_base + 0xf0));
4631 	ddi_put8(sc->sc_cfg_handle, (uint8_t *)(sc->sc_cfg_base + 0xf0),
4632 	    vlink & ~2);
4633 
4634 	tmp = IWH_READ(sc, CSR_HW_IF_CONFIG_REG);
4635 	tmp |= CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI |
4636 	    CSR_HW_IF_CONFIG_REG_BIT_MAC_SI;
4637 	IWH_WRITE(sc, CSR_SW_VER, tmp);
4638 
4639 	/*
4640 	 * make sure power supply on each part of the hardware
4641 	 */
4642 	iwh_mac_access_enter(sc);
4643 	tmp = iwh_reg_read(sc, ALM_APMG_PS_CTL);
4644 	tmp |= APMG_PS_CTRL_REG_VAL_ALM_R_RESET_REQ;
4645 	iwh_reg_write(sc, ALM_APMG_PS_CTL, tmp);
4646 	DELAY(5);
4647 
4648 	tmp = iwh_reg_read(sc, ALM_APMG_PS_CTL);
4649 	tmp &= ~APMG_PS_CTRL_REG_VAL_ALM_R_RESET_REQ;
4650 	iwh_reg_write(sc, ALM_APMG_PS_CTL, tmp);
4651 	iwh_mac_access_exit(sc);
4652 
4653 	return (IWH_SUCCESS);
4654 }
4655 
4656 /*
4657  * set up semphore flag to own EEPROM
4658  */
4659 static int
4660 iwh_eep_sem_down(iwh_sc_t *sc)
4661 {
4662 	int count1, count2;
4663 	uint32_t tmp;
4664 
4665 	for (count1 = 0; count1 < 1000; count1++) {
4666 		tmp = IWH_READ(sc, CSR_HW_IF_CONFIG_REG);
4667 		IWH_WRITE(sc, CSR_HW_IF_CONFIG_REG,
4668 		    tmp | CSR_HW_IF_CONFIG_REG_EEP_SEM);
4669 
4670 		for (count2 = 0; count2 < 2; count2++) {
4671 			if (IWH_READ(sc, CSR_HW_IF_CONFIG_REG) &
4672 			    CSR_HW_IF_CONFIG_REG_EEP_SEM) {
4673 				return (IWH_SUCCESS);
4674 			}
4675 			DELAY(10000);
4676 		}
4677 	}
4678 
4679 	return (IWH_FAIL);
4680 }
4681 
4682 /*
4683  * reset semphore flag to release EEPROM
4684  */
4685 static void
4686 iwh_eep_sem_up(iwh_sc_t *sc)
4687 {
4688 	uint32_t tmp;
4689 
4690 	tmp = IWH_READ(sc, CSR_HW_IF_CONFIG_REG);
4691 	IWH_WRITE(sc, CSR_HW_IF_CONFIG_REG,
4692 	    tmp & (~CSR_HW_IF_CONFIG_REG_EEP_SEM));
4693 }
4694 
4695 /*
4696  * This function read all infomation from eeprom
4697  */
4698 static int
4699 iwh_eep_load(iwh_sc_t *sc)
4700 {
4701 	int i, rr;
4702 	uint32_t rv, tmp, eep_gp;
4703 	uint16_t addr, eep_sz = sizeof (sc->sc_eep_map);
4704 	uint16_t *eep_p = (uint16_t *)&sc->sc_eep_map;
4705 
4706 	/*
4707 	 * read eeprom gp register in CSR
4708 	 */
4709 	eep_gp = IWH_READ(sc, CSR_EEPROM_GP);
4710 	if ((eep_gp & CSR_EEPROM_GP_VALID_MSK) ==
4711 	    CSR_EEPROM_GP_BAD_SIGNATURE) {
4712 		IWH_DBG((IWH_DEBUG_EEPROM, "iwh_eep_load(): "
4713 		    "not find eeprom\n"));
4714 		return (IWH_FAIL);
4715 	}
4716 
4717 	rr = iwh_eep_sem_down(sc);
4718 	if (rr != 0) {
4719 		IWH_DBG((IWH_DEBUG_EEPROM, "iwh_eep_load(): "
4720 		    "driver failed to own EEPROM\n"));
4721 		return (IWH_FAIL);
4722 	}
4723 
4724 	for (addr = 0; addr < eep_sz; addr += 2) {
4725 		IWH_WRITE(sc, CSR_EEPROM_REG, addr<<1);
4726 		tmp = IWH_READ(sc, CSR_EEPROM_REG);
4727 		IWH_WRITE(sc, CSR_EEPROM_REG, tmp & ~(0x2));
4728 
4729 		for (i = 0; i < 10; i++) {
4730 			rv = IWH_READ(sc, CSR_EEPROM_REG);
4731 			if (rv & 1) {
4732 				break;
4733 			}
4734 			DELAY(10);
4735 		}
4736 
4737 		if (!(rv & 1)) {
4738 			IWH_DBG((IWH_DEBUG_EEPROM, "iwh_eep_load(): "
4739 			    "time out when read eeprome\n"));
4740 			iwh_eep_sem_up(sc);
4741 			return (IWH_FAIL);
4742 		}
4743 
4744 		eep_p[addr/2] = LE_16(rv >> 16);
4745 	}
4746 
4747 	iwh_eep_sem_up(sc);
4748 	return (IWH_SUCCESS);
4749 }
4750 
4751 /*
4752  * initialize mac address in ieee80211com_t struct
4753  */
4754 static void
4755 iwh_get_mac_from_eep(iwh_sc_t *sc)
4756 {
4757 	ieee80211com_t *ic = &sc->sc_ic;
4758 
4759 	IEEE80211_ADDR_COPY(ic->ic_macaddr, &sc->sc_eep_map[EEP_MAC_ADDRESS]);
4760 
4761 	IWH_DBG((IWH_DEBUG_EEPROM, "iwh_get_mac_from_eep(): "
4762 	    "mac:%2x:%2x:%2x:%2x:%2x:%2x\n",
4763 	    ic->ic_macaddr[0], ic->ic_macaddr[1], ic->ic_macaddr[2],
4764 	    ic->ic_macaddr[3], ic->ic_macaddr[4], ic->ic_macaddr[5]));
4765 }
4766 
4767 /*
4768  * main initialization function
4769  */
4770 static int
4771 iwh_init(iwh_sc_t *sc)
4772 {
4773 	int err = IWH_FAIL;
4774 	clock_t clk;
4775 
4776 	/*
4777 	 * release buffer for calibration
4778 	 */
4779 	iwh_release_calib_buffer(sc);
4780 
4781 	mutex_enter(&sc->sc_glock);
4782 	atomic_and_32(&sc->sc_flags, ~IWH_F_FW_INIT);
4783 
4784 	err = iwh_init_common(sc);
4785 	if (err != IWH_SUCCESS) {
4786 		mutex_exit(&sc->sc_glock);
4787 		return (IWH_FAIL);
4788 	}
4789 
4790 	/*
4791 	 * backup ucode data part for future use.
4792 	 */
4793 	bcopy(sc->sc_dma_fw_data.mem_va,
4794 	    sc->sc_dma_fw_data_bak.mem_va,
4795 	    sc->sc_dma_fw_data.alength);
4796 
4797 	/* load firmware init segment into NIC */
4798 	err = iwh_load_init_firmware(sc);
4799 	if (err != IWH_SUCCESS) {
4800 		cmn_err(CE_WARN, "iwh_init(): "
4801 		    "failed to setup init firmware\n");
4802 		mutex_exit(&sc->sc_glock);
4803 		return (IWH_FAIL);
4804 	}
4805 
4806 	/*
4807 	 * now press "execute" start running
4808 	 */
4809 	IWH_WRITE(sc, CSR_RESET, 0);
4810 
4811 	clk = ddi_get_lbolt() + drv_usectohz(1000000);
4812 	while (!(sc->sc_flags & IWH_F_FW_INIT)) {
4813 		if (cv_timedwait(&sc->sc_ucode_cv,
4814 		    &sc->sc_glock, clk) < 0) {
4815 			break;
4816 		}
4817 	}
4818 
4819 	if (!(sc->sc_flags & IWH_F_FW_INIT)) {
4820 		cmn_err(CE_WARN, "iwh_init(): "
4821 		    "failed to process init alive.\n");
4822 		mutex_exit(&sc->sc_glock);
4823 		return (IWH_FAIL);
4824 	}
4825 
4826 	mutex_exit(&sc->sc_glock);
4827 
4828 	/*
4829 	 * stop chipset for initializing chipset again
4830 	 */
4831 	iwh_stop(sc);
4832 
4833 	mutex_enter(&sc->sc_glock);
4834 	atomic_and_32(&sc->sc_flags, ~IWH_F_FW_INIT);
4835 
4836 	err = iwh_init_common(sc);
4837 	if (err != IWH_SUCCESS) {
4838 		mutex_exit(&sc->sc_glock);
4839 		return (IWH_FAIL);
4840 	}
4841 
4842 	/*
4843 	 * load firmware run segment into NIC
4844 	 */
4845 	err = iwh_load_run_firmware(sc);
4846 	if (err != IWH_SUCCESS) {
4847 		cmn_err(CE_WARN, "iwh_init(): "
4848 		    "failed to setup run firmware\n");
4849 		mutex_exit(&sc->sc_glock);
4850 		return (IWH_FAIL);
4851 	}
4852 
4853 	/*
4854 	 * now press "execute" start running
4855 	 */
4856 	IWH_WRITE(sc, CSR_RESET, 0);
4857 
4858 	clk = ddi_get_lbolt() + drv_usectohz(1000000);
4859 	while (!(sc->sc_flags & IWH_F_FW_INIT)) {
4860 		if (cv_timedwait(&sc->sc_ucode_cv,
4861 		    &sc->sc_glock, clk) < 0) {
4862 			break;
4863 		}
4864 	}
4865 
4866 	if (!(sc->sc_flags & IWH_F_FW_INIT)) {
4867 		cmn_err(CE_WARN, "iwh_init(): "
4868 		    "failed to process runtime alive.\n");
4869 		mutex_exit(&sc->sc_glock);
4870 		return (IWH_FAIL);
4871 	}
4872 
4873 	mutex_exit(&sc->sc_glock);
4874 
4875 	DELAY(1000);
4876 
4877 	mutex_enter(&sc->sc_glock);
4878 	atomic_and_32(&sc->sc_flags, ~IWH_F_FW_INIT);
4879 
4880 	/*
4881 	 * at this point, the firmware is loaded OK, then config the hardware
4882 	 * with the ucode API, including rxon, txpower, etc.
4883 	 */
4884 	err = iwh_config(sc);
4885 	if (err) {
4886 		cmn_err(CE_WARN, "iwh_init(): "
4887 		    "failed to configure device\n");
4888 		mutex_exit(&sc->sc_glock);
4889 		return (IWH_FAIL);
4890 	}
4891 
4892 	/*
4893 	 * at this point, hardware may receive beacons :)
4894 	 */
4895 	mutex_exit(&sc->sc_glock);
4896 	return (IWH_SUCCESS);
4897 }
4898 
4899 /*
4900  * stop or disable NIC
4901  */
4902 static void
4903 iwh_stop(iwh_sc_t *sc)
4904 {
4905 	uint32_t tmp;
4906 	int i;
4907 
4908 	/*
4909 	 * by pass if it's quiesced
4910 	 */
4911 	if (!(sc->sc_flags & IWH_F_QUIESCED)) {
4912 		mutex_enter(&sc->sc_glock);
4913 	}
4914 
4915 	IWH_WRITE(sc, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
4916 	/*
4917 	 * disable interrupts
4918 	 */
4919 	IWH_WRITE(sc, CSR_INT_MASK, 0);
4920 	IWH_WRITE(sc, CSR_INT, CSR_INI_SET_MASK);
4921 	IWH_WRITE(sc, CSR_FH_INT_STATUS, 0xffffffff);
4922 
4923 	/*
4924 	 * reset all Tx rings
4925 	 */
4926 	for (i = 0; i < IWH_NUM_QUEUES; i++) {
4927 		iwh_reset_tx_ring(sc, &sc->sc_txq[i]);
4928 	}
4929 
4930 	/*
4931 	 * reset Rx ring
4932 	 */
4933 	iwh_reset_rx_ring(sc);
4934 
4935 	iwh_mac_access_enter(sc);
4936 	iwh_reg_write(sc, ALM_APMG_CLK_DIS, APMG_CLK_REG_VAL_DMA_CLK_RQT);
4937 	iwh_mac_access_exit(sc);
4938 
4939 	DELAY(5);
4940 
4941 	iwh_stop_master(sc);
4942 
4943 	mutex_enter(&sc->sc_mt_lock);
4944 	sc->sc_tx_timer = 0;
4945 	mutex_exit(&sc->sc_mt_lock);
4946 
4947 	tmp = IWH_READ(sc, CSR_RESET);
4948 	IWH_WRITE(sc, CSR_RESET, tmp | CSR_RESET_REG_FLAG_SW_RESET);
4949 
4950 	/*
4951 	 * by pass if it's quiesced
4952 	 */
4953 	if (!(sc->sc_flags & IWH_F_QUIESCED)) {
4954 		mutex_exit(&sc->sc_glock);
4955 	}
4956 }
4957 
4958 /*
4959  * Naive implementation of the Adaptive Multi Rate Retry algorithm:
4960  * "IEEE 802.11 Rate Adaptation: A Practical Approach"
4961  * Mathieu Lacage, Hossein Manshaei, Thierry Turletti
4962  * INRIA Sophia - Projet Planete
4963  * http://www-sop.inria.fr/rapports/sophia/RR-5208.html
4964  */
4965 #define	is_success(amrr)	\
4966 	((amrr)->retrycnt < (amrr)->txcnt / 10)
4967 #define	is_failure(amrr)	\
4968 	((amrr)->retrycnt > (amrr)->txcnt / 3)
4969 #define	is_enough(amrr)		\
4970 	((amrr)->txcnt > 200)
4971 #define	not_very_few(amrr)	\
4972 	((amrr)->txcnt > 40)
4973 #define	is_min_rate(in)		\
4974 	(0 == (in)->in_txrate)
4975 #define	is_max_rate(in)		\
4976 	((in)->in_rates.ir_nrates - 1 == (in)->in_txrate)
4977 #define	increase_rate(in)	\
4978 	((in)->in_txrate++)
4979 #define	decrease_rate(in)	\
4980 	((in)->in_txrate--)
4981 #define	reset_cnt(amrr)		\
4982 	{ (amrr)->txcnt = (amrr)->retrycnt = 0; }
4983 
4984 #define	IWH_AMRR_MIN_SUCCESS_THRESHOLD	 1
4985 #define	IWH_AMRR_MAX_SUCCESS_THRESHOLD	15
4986 
4987 static void
4988 iwh_amrr_init(iwh_amrr_t *amrr)
4989 {
4990 	amrr->success = 0;
4991 	amrr->recovery = 0;
4992 	amrr->txcnt = amrr->retrycnt = 0;
4993 	amrr->success_threshold = IWH_AMRR_MIN_SUCCESS_THRESHOLD;
4994 	amrr->ht_mcs_idx = 0;	/* 6Mbps */
4995 }
4996 
4997 static void
4998 iwh_amrr_timeout(iwh_sc_t *sc)
4999 {
5000 	ieee80211com_t *ic = &sc->sc_ic;
5001 
5002 	IWH_DBG((IWH_DEBUG_RATECTL, "iwh_amrr_timeout(): "
5003 	    "enter\n"));
5004 
5005 	if (IEEE80211_M_STA == ic->ic_opmode) {
5006 		iwh_amrr_ratectl(NULL, ic->ic_bss);
5007 	} else {
5008 		ieee80211_iterate_nodes(&ic->ic_sta, iwh_amrr_ratectl, NULL);
5009 	}
5010 
5011 	sc->sc_clk = ddi_get_lbolt();
5012 }
5013 
5014 static int
5015 iwh_is_max_rate(ieee80211_node_t *in)
5016 {
5017 	int i;
5018 	iwh_amrr_t *amrr = (iwh_amrr_t *)in;
5019 	uint8_t r = (uint8_t)amrr->ht_mcs_idx;
5020 	ieee80211com_t *ic = in->in_ic;
5021 	iwh_sc_t *sc = (iwh_sc_t *)ic;
5022 
5023 	if (in->in_flags & IEEE80211_NODE_HT) {
5024 		for (i = in->in_htrates.rs_nrates - 1; i >= 0; i--) {
5025 			r = in->in_htrates.rs_rates[i] &
5026 			    IEEE80211_RATE_VAL;
5027 			if (sc->sc_ht_conf.tx_support_mcs[r/8] &
5028 			    (1 << (r%8))) {
5029 				break;
5030 			}
5031 		}
5032 
5033 		return (r == (uint8_t)amrr->ht_mcs_idx);
5034 	} else {
5035 		return (is_max_rate(in));
5036 	}
5037 }
5038 
5039 static int
5040 iwh_is_min_rate(ieee80211_node_t *in)
5041 {
5042 	int i;
5043 	uint8_t r = 0;
5044 	iwh_amrr_t *amrr = (iwh_amrr_t *)in;
5045 	ieee80211com_t *ic = in->in_ic;
5046 	iwh_sc_t *sc = (iwh_sc_t *)ic;
5047 
5048 	if (in->in_flags & IEEE80211_NODE_HT) {
5049 		for (i = 0; i < in->in_htrates.rs_nrates; i++) {
5050 			r = in->in_htrates.rs_rates[i] &
5051 			    IEEE80211_RATE_VAL;
5052 			if (sc->sc_ht_conf.tx_support_mcs[r/8] &
5053 			    (1 << (r%8))) {
5054 				break;
5055 			}
5056 		}
5057 
5058 		return (r == (uint8_t)amrr->ht_mcs_idx);
5059 	} else {
5060 		return (is_min_rate(in));
5061 	}
5062 }
5063 
5064 static void
5065 iwh_increase_rate(ieee80211_node_t *in)
5066 {
5067 	int i;
5068 	uint8_t r;
5069 	iwh_amrr_t *amrr = (iwh_amrr_t *)in;
5070 	ieee80211com_t *ic = in->in_ic;
5071 	iwh_sc_t *sc = (iwh_sc_t *)ic;
5072 
5073 	if (in->in_flags & IEEE80211_NODE_HT) {
5074 again:
5075 		amrr->ht_mcs_idx++;
5076 
5077 		for (i = 0; i < in->in_htrates.rs_nrates; i++) {
5078 			r = in->in_htrates.rs_rates[i] &
5079 			    IEEE80211_RATE_VAL;
5080 			if ((r == (uint8_t)amrr->ht_mcs_idx) &&
5081 			    (sc->sc_ht_conf.tx_support_mcs[r/8] &
5082 			    (1 << (r%8)))) {
5083 				break;
5084 			}
5085 		}
5086 
5087 		if (i >= in->in_htrates.rs_nrates) {
5088 			goto again;
5089 		}
5090 	} else {
5091 		increase_rate(in);
5092 	}
5093 }
5094 
5095 static void
5096 iwh_decrease_rate(ieee80211_node_t *in)
5097 {
5098 	int i;
5099 	uint8_t r;
5100 	iwh_amrr_t *amrr = (iwh_amrr_t *)in;
5101 	ieee80211com_t *ic = in->in_ic;
5102 	iwh_sc_t *sc = (iwh_sc_t *)ic;
5103 
5104 	if (in->in_flags & IEEE80211_NODE_HT) {
5105 again:
5106 		amrr->ht_mcs_idx--;
5107 
5108 		for (i = 0; i < in->in_htrates.rs_nrates; i++) {
5109 			r = in->in_htrates.rs_rates[i] &
5110 			    IEEE80211_RATE_VAL;
5111 			if ((r == (uint8_t)amrr->ht_mcs_idx) &&
5112 			    (sc->sc_ht_conf.tx_support_mcs[r/8] &
5113 			    (1 << (r%8)))) {
5114 				break;
5115 			}
5116 		}
5117 
5118 		if (i >= in->in_htrates.rs_nrates) {
5119 			goto again;
5120 		}
5121 	} else {
5122 		decrease_rate(in);
5123 	}
5124 }
5125 
5126 /* ARGSUSED */
5127 static void
5128 iwh_amrr_ratectl(void *arg, ieee80211_node_t *in)
5129 {
5130 	iwh_amrr_t *amrr = (iwh_amrr_t *)in;
5131 	int need_change = 0;
5132 
5133 	if (is_success(amrr) && is_enough(amrr)) {
5134 		amrr->success++;
5135 		if (amrr->success >= amrr->success_threshold &&
5136 		    !iwh_is_max_rate(in)) {
5137 			amrr->recovery = 1;
5138 			amrr->success = 0;
5139 			iwh_increase_rate(in);
5140 			IWH_DBG((IWH_DEBUG_RATECTL, "iwh_amrr_ratectl(): "
5141 			    "AMRR increasing rate %d "
5142 			    "(txcnt=%d retrycnt=%d), mcs_idx=%d\n",
5143 			    in->in_txrate, amrr->txcnt,
5144 			    amrr->retrycnt, amrr->ht_mcs_idx));
5145 			need_change = 1;
5146 		} else {
5147 			amrr->recovery = 0;
5148 		}
5149 	} else if (not_very_few(amrr) && is_failure(amrr)) {
5150 		amrr->success = 0;
5151 		if (!iwh_is_min_rate(in)) {
5152 			if (amrr->recovery) {
5153 				amrr->success_threshold++;
5154 				if (amrr->success_threshold >
5155 				    IWH_AMRR_MAX_SUCCESS_THRESHOLD) {
5156 					amrr->success_threshold =
5157 					    IWH_AMRR_MAX_SUCCESS_THRESHOLD;
5158 				}
5159 			} else {
5160 				amrr->success_threshold =
5161 				    IWH_AMRR_MIN_SUCCESS_THRESHOLD;
5162 			}
5163 			iwh_decrease_rate(in);
5164 			IWH_DBG((IWH_DEBUG_RATECTL, "iwh_amrr_ratectl(): "
5165 			    "AMRR decreasing rate %d "
5166 			    "(txcnt=%d retrycnt=%d), mcs_idx=%d\n",
5167 			    in->in_txrate, amrr->txcnt,
5168 			    amrr->retrycnt, amrr->ht_mcs_idx));
5169 			need_change = 1;
5170 		}
5171 		amrr->recovery = 0;	/* paper is incorrect */
5172 	}
5173 
5174 	if (is_enough(amrr) || need_change) {
5175 		reset_cnt(amrr);
5176 	}
5177 }
5178 
5179 /*
5180  * translate indirect address in eeprom to direct address
5181  * in eeprom and return address of entry whos indirect address
5182  * is indi_addr
5183  */
5184 static uint8_t *
5185 iwh_eep_addr_trans(iwh_sc_t *sc, uint32_t indi_addr)
5186 {
5187 	uint32_t di_addr;
5188 	uint16_t temp;
5189 
5190 	if (!(indi_addr & INDIRECT_ADDRESS)) {
5191 		di_addr = indi_addr;
5192 		return (&sc->sc_eep_map[di_addr]);
5193 	}
5194 
5195 	switch (indi_addr & INDIRECT_TYPE_MSK) {
5196 	case INDIRECT_GENERAL:
5197 		temp = IWH_READ_EEP_SHORT(sc, EEP_LINK_GENERAL);
5198 		break;
5199 
5200 	case	INDIRECT_HOST:
5201 		temp = IWH_READ_EEP_SHORT(sc, EEP_LINK_HOST);
5202 		break;
5203 
5204 	case	INDIRECT_REGULATORY:
5205 		temp = IWH_READ_EEP_SHORT(sc, EEP_LINK_REGULATORY);
5206 		break;
5207 
5208 	case	INDIRECT_CALIBRATION:
5209 		temp = IWH_READ_EEP_SHORT(sc, EEP_LINK_CALIBRATION);
5210 		break;
5211 
5212 	case	INDIRECT_PROCESS_ADJST:
5213 		temp = IWH_READ_EEP_SHORT(sc, EEP_LINK_PROCESS_ADJST);
5214 		break;
5215 
5216 	case	INDIRECT_OTHERS:
5217 		temp = IWH_READ_EEP_SHORT(sc, EEP_LINK_OTHERS);
5218 		break;
5219 
5220 	default:
5221 		temp = 0;
5222 		cmn_err(CE_WARN, "iwh_eep_addr_trans(): "
5223 		    "incorrect indirect eeprom address.\n");
5224 		break;
5225 	}
5226 
5227 	di_addr = (indi_addr & ADDRESS_MSK) + (temp << 1);
5228 
5229 	return (&sc->sc_eep_map[di_addr]);
5230 }
5231 
5232 /*
5233  * loade a section of ucode into NIC
5234  */
5235 static int
5236 iwh_put_seg_fw(iwh_sc_t *sc, uint32_t addr_s, uint32_t addr_d, uint32_t len)
5237 {
5238 
5239 	iwh_mac_access_enter(sc);
5240 
5241 	IWH_WRITE(sc, IWH_FH_TCSR_CHNL_TX_CONFIG_REG(IWH_FH_SRVC_CHNL),
5242 	    IWH_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE);
5243 
5244 	IWH_WRITE(sc, IWH_FH_SRVC_CHNL_SRAM_ADDR_REG(IWH_FH_SRVC_CHNL), addr_d);
5245 
5246 	IWH_WRITE(sc, IWH_FH_TFDIB_CTRL0_REG(IWH_FH_SRVC_CHNL),
5247 	    (addr_s & FH_MEM_TFDIB_DRAM_ADDR_LSB_MASK));
5248 
5249 	IWH_WRITE(sc, IWH_FH_TFDIB_CTRL1_REG(IWH_FH_SRVC_CHNL), len);
5250 
5251 	IWH_WRITE(sc, IWH_FH_TCSR_CHNL_TX_BUF_STS_REG(IWH_FH_SRVC_CHNL),
5252 	    (1 << IWH_FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM) |
5253 	    (1 << IWH_FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX) |
5254 	    IWH_FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID);
5255 
5256 	IWH_WRITE(sc, IWH_FH_TCSR_CHNL_TX_CONFIG_REG(IWH_FH_SRVC_CHNL),
5257 	    IWH_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
5258 	    IWH_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE_VAL |
5259 	    IWH_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD);
5260 
5261 	iwh_mac_access_exit(sc);
5262 
5263 	return (IWH_SUCCESS);
5264 }
5265 
5266 /*
5267  * necessary setting during alive notification
5268  */
5269 static int
5270 iwh_alive_common(iwh_sc_t *sc)
5271 {
5272 	uint32_t base;
5273 	uint32_t i;
5274 	iwh_wimax_coex_cmd_t w_cmd;
5275 	iwh_calibration_crystal_cmd_t c_cmd;
5276 	uint32_t rv = IWH_FAIL;
5277 
5278 	/*
5279 	 * initialize SCD related registers to make TX work.
5280 	 */
5281 	iwh_mac_access_enter(sc);
5282 
5283 	/*
5284 	 * read sram address of data base.
5285 	 */
5286 	sc->sc_scd_base = iwh_reg_read(sc, IWH_SCD_SRAM_BASE_ADDR);
5287 
5288 	for (base = sc->sc_scd_base + IWH_SCD_CONTEXT_DATA_OFFSET;
5289 	    base < sc->sc_scd_base + IWH_SCD_TX_STTS_BITMAP_OFFSET;
5290 	    base += 4) {
5291 		iwh_mem_write(sc, base, 0);
5292 	}
5293 
5294 	for (; base < sc->sc_scd_base + IWH_SCD_TRANSLATE_TBL_OFFSET;
5295 	    base += 4) {
5296 		iwh_mem_write(sc, base, 0);
5297 	}
5298 
5299 	for (i = 0; i < sizeof (uint16_t) * IWH_NUM_QUEUES; i += 4) {
5300 		iwh_mem_write(sc, base + i, 0);
5301 	}
5302 
5303 	iwh_reg_write(sc, IWH_SCD_DRAM_BASE_ADDR,
5304 	    sc->sc_dma_sh.cookie.dmac_address >> 10);
5305 
5306 	iwh_reg_write(sc, IWH_SCD_QUEUECHAIN_SEL,
5307 	    IWH_SCD_QUEUECHAIN_SEL_ALL(IWH_NUM_QUEUES));
5308 
5309 	iwh_reg_write(sc, IWH_SCD_AGGR_SEL, 0);
5310 
5311 	for (i = 0; i < IWH_NUM_QUEUES; i++) {
5312 		iwh_reg_write(sc, IWH_SCD_QUEUE_RDPTR(i), 0);
5313 		IWH_WRITE(sc, HBUS_TARG_WRPTR, 0 | (i << 8));
5314 		iwh_mem_write(sc, sc->sc_scd_base +
5315 		    IWH_SCD_CONTEXT_QUEUE_OFFSET(i), 0);
5316 		iwh_mem_write(sc, sc->sc_scd_base +
5317 		    IWH_SCD_CONTEXT_QUEUE_OFFSET(i) +
5318 		    sizeof (uint32_t),
5319 		    ((SCD_WIN_SIZE << IWH_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) &
5320 		    IWH_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
5321 		    ((SCD_FRAME_LIMIT <<
5322 		    IWH_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
5323 		    IWH_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));
5324 	}
5325 
5326 	iwh_reg_write(sc, IWH_SCD_INTERRUPT_MASK, (1 << IWH_NUM_QUEUES) - 1);
5327 
5328 	iwh_reg_write(sc, (IWH_SCD_BASE + 0x10),
5329 	    SCD_TXFACT_REG_TXFIFO_MASK(0, 7));
5330 
5331 	IWH_WRITE(sc, HBUS_TARG_WRPTR, (IWH_CMD_QUEUE_NUM << 8));
5332 	iwh_reg_write(sc, IWH_SCD_QUEUE_RDPTR(IWH_CMD_QUEUE_NUM), 0);
5333 
5334 	/*
5335 	 * queue 0-7 map to FIFO 0-7 and
5336 	 * all queues work under FIFO mode(none-scheduler_ack)
5337 	 */
5338 	for (i = 0; i < 4; i++) {
5339 		iwh_reg_write(sc, IWH_SCD_QUEUE_STATUS_BITS(i),
5340 		    (1 << IWH_SCD_QUEUE_STTS_REG_POS_ACTIVE) |
5341 		    ((3-i) << IWH_SCD_QUEUE_STTS_REG_POS_TXF) |
5342 		    (1 << IWH_SCD_QUEUE_STTS_REG_POS_WSL) |
5343 		    IWH_SCD_QUEUE_STTS_REG_MSK);
5344 	}
5345 
5346 	iwh_reg_write(sc, IWH_SCD_QUEUE_STATUS_BITS(IWH_CMD_QUEUE_NUM),
5347 	    (1 << IWH_SCD_QUEUE_STTS_REG_POS_ACTIVE) |
5348 	    (IWH_CMD_FIFO_NUM << IWH_SCD_QUEUE_STTS_REG_POS_TXF) |
5349 	    (1 << IWH_SCD_QUEUE_STTS_REG_POS_WSL) |
5350 	    IWH_SCD_QUEUE_STTS_REG_MSK);
5351 
5352 	for (i = 5; i < 7; i++) {
5353 		iwh_reg_write(sc, IWH_SCD_QUEUE_STATUS_BITS(i),
5354 		    (1 << IWH_SCD_QUEUE_STTS_REG_POS_ACTIVE) |
5355 		    (i << IWH_SCD_QUEUE_STTS_REG_POS_TXF) |
5356 		    (1 << IWH_SCD_QUEUE_STTS_REG_POS_WSL) |
5357 		    IWH_SCD_QUEUE_STTS_REG_MSK);
5358 	}
5359 
5360 	iwh_mac_access_exit(sc);
5361 
5362 	(void) memset(&w_cmd, 0, sizeof (w_cmd));
5363 
5364 	rv = iwh_cmd(sc, COEX_PRIORITY_TABLE_CMD, &w_cmd, sizeof (w_cmd), 1);
5365 	if (rv != IWH_SUCCESS) {
5366 		cmn_err(CE_WARN, "iwh_alive_common(): "
5367 		    "failed to send wimax coexist command.\n");
5368 		return (rv);
5369 	}
5370 
5371 	if ((sc->sc_dev_id != 0x423c) &&
5372 	    (sc->sc_dev_id != 0x423d)) {
5373 		(void) memset(&c_cmd, 0, sizeof (c_cmd));
5374 
5375 		c_cmd.opCode = PHY_CALIBRATE_CRYSTAL_FRQ_CMD;
5376 		c_cmd.data.cap_pin1 = LE_16(sc->sc_eep_calib->xtal_calib[0]);
5377 		c_cmd.data.cap_pin2 = LE_16(sc->sc_eep_calib->xtal_calib[1]);
5378 
5379 		rv = iwh_cmd(sc, REPLY_PHY_CALIBRATION_CMD,
5380 		    &c_cmd, sizeof (c_cmd), 1);
5381 		if (rv != IWH_SUCCESS) {
5382 			cmn_err(CE_WARN, "iwh_alive_common(): "
5383 			    "failed to send crystal"
5384 			    "frq calibration command.\n");
5385 			return (rv);
5386 		}
5387 
5388 		/*
5389 		 * make sure crystal frequency calibration ready
5390 		 * before next operations.
5391 		 */
5392 		DELAY(1000);
5393 	}
5394 
5395 	return (IWH_SUCCESS);
5396 }
5397 
5398 /*
5399  * save results of calibration from ucode
5400  */
5401 static void
5402 iwh_save_calib_result(iwh_sc_t *sc, iwh_rx_desc_t *desc)
5403 {
5404 	struct iwh_calib_results *res_p = &sc->sc_calib_results;
5405 	struct iwh_calib_hdr *calib_hdr = (struct iwh_calib_hdr *)(desc + 1);
5406 	int len = LE_32(desc->len);
5407 
5408 	/*
5409 	 * ensure the size of buffer is not too big
5410 	 */
5411 	len = (len & FH_RSCSR_FRAME_SIZE_MASK) - 4;
5412 
5413 	switch (calib_hdr->op_code) {
5414 	case PHY_CALIBRATE_LO_CMD:
5415 		if (NULL == res_p->lo_res) {
5416 			res_p->lo_res = kmem_alloc(len, KM_NOSLEEP);
5417 		}
5418 
5419 		if (NULL == res_p->lo_res) {
5420 			cmn_err(CE_WARN, "iwh_save_calib_result(): "
5421 			    "failed to allocate memory.\n");
5422 			return;
5423 		}
5424 
5425 		res_p->lo_res_len = len;
5426 		bcopy(calib_hdr, res_p->lo_res, len);
5427 		break;
5428 
5429 	case PHY_CALIBRATE_TX_IQ_CMD:
5430 		if (NULL == res_p->tx_iq_res) {
5431 			res_p->tx_iq_res = kmem_alloc(len, KM_NOSLEEP);
5432 		}
5433 
5434 		if (NULL == res_p->tx_iq_res) {
5435 			cmn_err(CE_WARN, "iwh_save_calib_result(): "
5436 			    "failed to allocate memory.\n");
5437 			return;
5438 		}
5439 
5440 		res_p->tx_iq_res_len = len;
5441 		bcopy(calib_hdr, res_p->tx_iq_res, len);
5442 		break;
5443 
5444 	case PHY_CALIBRATE_TX_IQ_PERD_CMD:
5445 		if (NULL == res_p->tx_iq_perd_res) {
5446 			res_p->tx_iq_perd_res = kmem_alloc(len, KM_NOSLEEP);
5447 		}
5448 
5449 		if (NULL == res_p->tx_iq_perd_res) {
5450 			cmn_err(CE_WARN, "iwh_save_calib_result(): "
5451 			    "failed to allocate memory.\n");
5452 		}
5453 
5454 		res_p->tx_iq_perd_res_len = len;
5455 		bcopy(calib_hdr, res_p->tx_iq_perd_res, len);
5456 		break;
5457 
5458 	case PHY_CALIBRATE_DC_CMD:
5459 		if (NULL == res_p->dc_res) {
5460 			res_p->dc_res = kmem_alloc(len, KM_NOSLEEP);
5461 		}
5462 
5463 		if (NULL == res_p->dc_res) {
5464 			cmn_err(CE_WARN, "iwh_save_calib_result(): "
5465 			    "failed to allocate memory.\n");
5466 		}
5467 
5468 		res_p->dc_res_len = len;
5469 		bcopy(calib_hdr, res_p->dc_res, len);
5470 		break;
5471 
5472 	case PHY_CALIBRATE_BASE_BAND_CMD:
5473 		if (NULL == res_p->base_band_res) {
5474 			res_p->base_band_res = kmem_alloc(len, KM_NOSLEEP);
5475 		}
5476 
5477 		if (NULL == res_p->base_band_res) {
5478 			cmn_err(CE_WARN, "iwh_save_calib_result(): "
5479 			    "failed to allocate memory.\n");
5480 		}
5481 
5482 		res_p->base_band_res_len = len;
5483 		bcopy(calib_hdr, res_p->base_band_res, len);
5484 		break;
5485 
5486 	default:
5487 		cmn_err(CE_WARN, "iwh_save_calib_result(): "
5488 		    "incorrect calibration type(%d).\n", calib_hdr->op_code);
5489 		break;
5490 	}
5491 
5492 }
5493 
5494 /*
5495  * configure TX pwoer table
5496  */
5497 static int
5498 iwh_tx_power_table(iwh_sc_t *sc, int async)
5499 {
5500 	iwh_tx_power_table_cmd_t txpower;
5501 	int i, err = IWH_FAIL;
5502 
5503 	(void) memset(&txpower, 0, sizeof (txpower));
5504 
5505 	txpower.band = 1; /* for 2.4G */
5506 	txpower.channel = (uint8_t)LE_16(sc->sc_config.chan);
5507 	txpower.pa_measurements = 1;
5508 	txpower.max_mcs = 23;
5509 
5510 	for (i = 0; i < 24; i++) {
5511 		txpower.db.ht_ofdm_power[i].s.radio_tx_gain[0] = 0x16;
5512 		txpower.db.ht_ofdm_power[i].s.radio_tx_gain[1] = 0x16;
5513 		txpower.db.ht_ofdm_power[i].s.radio_tx_gain[2] = 0x16;
5514 		txpower.db.ht_ofdm_power[i].s.dsp_predis_atten[0] = 0x6E;
5515 		txpower.db.ht_ofdm_power[i].s.dsp_predis_atten[1] = 0x6E;
5516 		txpower.db.ht_ofdm_power[i].s.dsp_predis_atten[2] = 0x6E;
5517 	}
5518 
5519 	for (i = 0; i < 2; i++) {
5520 		txpower.db.cck_power[i].s.radio_tx_gain[0] = 0x16;
5521 		txpower.db.cck_power[i].s.radio_tx_gain[1] = 0x16;
5522 		txpower.db.cck_power[i].s.radio_tx_gain[2] = 0x16;
5523 		txpower.db.cck_power[i].s.dsp_predis_atten[0] = 0x6E;
5524 		txpower.db.cck_power[i].s.dsp_predis_atten[1] = 0x6E;
5525 		txpower.db.cck_power[i].s.dsp_predis_atten[2] = 0x6E;
5526 	}
5527 
5528 	err = iwh_cmd(sc, REPLY_TX_PWR_TABLE_CMD, &txpower,
5529 	    sizeof (txpower), async);
5530 	if (err != IWH_SUCCESS) {
5531 		cmn_err(CE_WARN, "iwh_tx_power_table(): "
5532 		    "failed to set tx power table.\n");
5533 		return (err);
5534 	}
5535 
5536 	return (err);
5537 }
5538 
5539 static void
5540 iwh_release_calib_buffer(iwh_sc_t *sc)
5541 {
5542 	if (sc->sc_calib_results.lo_res != NULL) {
5543 		kmem_free(sc->sc_calib_results.lo_res,
5544 		    sc->sc_calib_results.lo_res_len);
5545 		sc->sc_calib_results.lo_res = NULL;
5546 	}
5547 
5548 	if (sc->sc_calib_results.tx_iq_res != NULL) {
5549 		kmem_free(sc->sc_calib_results.tx_iq_res,
5550 		    sc->sc_calib_results.tx_iq_res_len);
5551 		sc->sc_calib_results.tx_iq_res = NULL;
5552 	}
5553 
5554 	if (sc->sc_calib_results.tx_iq_perd_res != NULL) {
5555 		kmem_free(sc->sc_calib_results.tx_iq_perd_res,
5556 		    sc->sc_calib_results.tx_iq_perd_res_len);
5557 		sc->sc_calib_results.tx_iq_perd_res = NULL;
5558 	}
5559 
5560 	if (sc->sc_calib_results.dc_res != NULL) {
5561 		kmem_free(sc->sc_calib_results.dc_res,
5562 		    sc->sc_calib_results.dc_res_len);
5563 		sc->sc_calib_results.dc_res = NULL;
5564 	}
5565 
5566 	if (sc->sc_calib_results.base_band_res != NULL) {
5567 		kmem_free(sc->sc_calib_results.base_band_res,
5568 		    sc->sc_calib_results.base_band_res_len);
5569 		sc->sc_calib_results.base_band_res = NULL;
5570 	}
5571 }
5572 
5573 /*
5574  * common section of intialization
5575  */
5576 static int
5577 iwh_init_common(iwh_sc_t *sc)
5578 {
5579 	int32_t	qid;
5580 	uint32_t tmp;
5581 
5582 	(void) iwh_preinit(sc);
5583 
5584 	tmp = IWH_READ(sc, CSR_GP_CNTRL);
5585 	if (!(tmp & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)) {
5586 		cmn_err(CE_NOTE, "iwh_init_common(): "
5587 		    "radio transmitter is off\n");
5588 		return (IWH_FAIL);
5589 	}
5590 
5591 	/*
5592 	 * init Rx ring
5593 	 */
5594 	iwh_mac_access_enter(sc);
5595 	IWH_WRITE(sc, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
5596 
5597 	IWH_WRITE(sc, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0);
5598 	IWH_WRITE(sc, FH_RSCSR_CHNL0_RBDCB_BASE_REG,
5599 	    sc->sc_rxq.dma_desc.cookie.dmac_address >> 8);
5600 
5601 	IWH_WRITE(sc, FH_RSCSR_CHNL0_STTS_WPTR_REG,
5602 	    ((uint32_t)(sc->sc_dma_sh.cookie.dmac_address +
5603 	    offsetof(struct iwh_shared, val0)) >> 4));
5604 
5605 	IWH_WRITE(sc, FH_MEM_RCSR_CHNL0_CONFIG_REG,
5606 	    FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL |
5607 	    FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL |
5608 	    IWH_FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K |
5609 	    (RX_QUEUE_SIZE_LOG <<
5610 	    FH_RCSR_RX_CONFIG_RBDCB_SIZE_BITSHIFT));
5611 	iwh_mac_access_exit(sc);
5612 	IWH_WRITE(sc, FH_RSCSR_CHNL0_RBDCB_WPTR_REG,
5613 	    (RX_QUEUE_SIZE - 1) & ~0x7);
5614 
5615 	/*
5616 	 * init Tx rings
5617 	 */
5618 	iwh_mac_access_enter(sc);
5619 	iwh_reg_write(sc, IWH_SCD_TXFACT, 0);
5620 
5621 	/*
5622 	 * keep warm page
5623 	 */
5624 	IWH_WRITE(sc, IWH_FH_KW_MEM_ADDR_REG,
5625 	    sc->sc_dma_kw.cookie.dmac_address >> 4);
5626 
5627 	for (qid = 0; qid < IWH_NUM_QUEUES; qid++) {
5628 		IWH_WRITE(sc, FH_MEM_CBBC_QUEUE(qid),
5629 		    sc->sc_txq[qid].dma_desc.cookie.dmac_address >> 8);
5630 		IWH_WRITE(sc, IWH_FH_TCSR_CHNL_TX_CONFIG_REG(qid),
5631 		    IWH_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
5632 		    IWH_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL);
5633 	}
5634 
5635 	iwh_mac_access_exit(sc);
5636 
5637 	/*
5638 	 * clear "radio off" and "disable command" bits
5639 	 */
5640 	IWH_WRITE(sc, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
5641 	IWH_WRITE(sc, CSR_UCODE_DRV_GP1_CLR,
5642 	    CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
5643 
5644 	/*
5645 	 * clear any pending interrupts
5646 	 */
5647 	IWH_WRITE(sc, CSR_INT, 0xffffffff);
5648 
5649 	/*
5650 	 * enable interrupts
5651 	 */
5652 	IWH_WRITE(sc, CSR_INT_MASK, CSR_INI_SET_MASK);
5653 
5654 	IWH_WRITE(sc, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
5655 	IWH_WRITE(sc, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
5656 
5657 	return (IWH_SUCCESS);
5658 }
5659 
5660 static int
5661 iwh_fast_recover(iwh_sc_t *sc)
5662 {
5663 	ieee80211com_t *ic = &sc->sc_ic;
5664 	int err = IWH_FAIL;
5665 
5666 	mutex_enter(&sc->sc_glock);
5667 
5668 	/*
5669 	 * restore runtime configuration
5670 	 */
5671 	bcopy(&sc->sc_config_save, &sc->sc_config,
5672 	    sizeof (sc->sc_config));
5673 
5674 	sc->sc_config.assoc_id = 0;
5675 	sc->sc_config.filter_flags &= ~LE_32(RXON_FILTER_ASSOC_MSK);
5676 
5677 	if ((err = iwh_hw_set_before_auth(sc)) != IWH_SUCCESS) {
5678 		cmn_err(CE_WARN, "iwh_fast_recover(): "
5679 		    "could not setup authentication\n");
5680 		mutex_exit(&sc->sc_glock);
5681 		return (err);
5682 	}
5683 
5684 	bcopy(&sc->sc_config_save, &sc->sc_config,
5685 	    sizeof (sc->sc_config));
5686 
5687 	/*
5688 	 * update adapter's configuration
5689 	 */
5690 	err = iwh_run_state_config(sc);
5691 	if (err != IWH_SUCCESS) {
5692 		cmn_err(CE_WARN, "iwh_fast_recover(): "
5693 		    "failed to setup association\n");
5694 		mutex_exit(&sc->sc_glock);
5695 		return (err);
5696 	}
5697 
5698 	/*
5699 	 * set LED on
5700 	 */
5701 	iwh_set_led(sc, 2, 0, 1);
5702 
5703 	mutex_exit(&sc->sc_glock);
5704 
5705 	atomic_and_32(&sc->sc_flags, ~IWH_F_HW_ERR_RECOVER);
5706 
5707 	/*
5708 	 * start queue
5709 	 */
5710 	IWH_DBG((IWH_DEBUG_FW, "iwh_fast_recover(): "
5711 	    "resume xmit\n"));
5712 	mac_tx_update(ic->ic_mach);
5713 
5714 	return (IWH_SUCCESS);
5715 }
5716 
5717 static int
5718 iwh_run_state_config(iwh_sc_t *sc)
5719 {
5720 	struct ieee80211com *ic = &sc->sc_ic;
5721 	ieee80211_node_t *in = ic->ic_bss;
5722 	uint32_t ht_protec = (uint32_t)(-1);
5723 	int err = IWH_FAIL;
5724 
5725 	/*
5726 	 * update adapter's configuration
5727 	 */
5728 	sc->sc_config.assoc_id = in->in_associd & 0x3fff;
5729 
5730 	/*
5731 	 * short preamble/slot time are
5732 	 * negotiated when associating
5733 	 */
5734 	sc->sc_config.flags &=
5735 	    ~LE_32(RXON_FLG_SHORT_PREAMBLE_MSK |
5736 	    RXON_FLG_SHORT_SLOT_MSK);
5737 
5738 	if (ic->ic_flags & IEEE80211_F_SHSLOT) {
5739 		sc->sc_config.flags |=
5740 		    LE_32(RXON_FLG_SHORT_SLOT_MSK);
5741 	}
5742 
5743 	if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) {
5744 		sc->sc_config.flags |=
5745 		    LE_32(RXON_FLG_SHORT_PREAMBLE_MSK);
5746 	}
5747 
5748 	if (in->in_flags & IEEE80211_NODE_HT) {
5749 		ht_protec = in->in_htopmode;
5750 		if (ht_protec > 3) {
5751 			cmn_err(CE_WARN, "iwh_run_state_config(): "
5752 			    "HT protection mode is not correct.\n");
5753 			return (IWH_FAIL);
5754 		} else if (NO_HT_PROT == ht_protec) {
5755 			ht_protec = sc->sc_ht_conf.ht_protection;
5756 		}
5757 
5758 		sc->sc_config.flags |=
5759 		    LE_32(ht_protec << RXON_FLG_HT_OPERATING_MODE_POS);
5760 	}
5761 
5762 	/*
5763 	 * set RX chains/antennas.
5764 	 */
5765 	iwh_config_rxon_chain(sc);
5766 
5767 	sc->sc_config.filter_flags |=
5768 	    LE_32(RXON_FILTER_ASSOC_MSK);
5769 
5770 	if (ic->ic_opmode != IEEE80211_M_STA) {
5771 		sc->sc_config.filter_flags |=
5772 		    LE_32(RXON_FILTER_BCON_AWARE_MSK);
5773 	}
5774 
5775 	IWH_DBG((IWH_DEBUG_80211, "iwh_run_state_config(): "
5776 	    "config chan %d flags %x"
5777 	    " filter_flags %x\n",
5778 	    sc->sc_config.chan, sc->sc_config.flags,
5779 	    sc->sc_config.filter_flags));
5780 
5781 	err = iwh_cmd(sc, REPLY_RXON, &sc->sc_config,
5782 	    sizeof (iwh_rxon_cmd_t), 1);
5783 	if (err != IWH_SUCCESS) {
5784 		cmn_err(CE_WARN, "iwh_run_state_config(): "
5785 		    "could not update configuration\n");
5786 		return (err);
5787 	}
5788 
5789 	if ((sc->sc_dev_id != 0x423c) &&
5790 	    (sc->sc_dev_id != 0x423d)) {
5791 		/*
5792 		 * send tx power table command
5793 		 */
5794 		err = iwh_tx_power_table(sc, 1);
5795 		if (err != IWH_SUCCESS) {
5796 			return (err);
5797 		}
5798 	}
5799 
5800 	/*
5801 	 * Not need to update retry rate table for AP node
5802 	 */
5803 	err = iwh_qosparam_to_hw(sc, 1);
5804 	if (err != IWH_SUCCESS) {
5805 		return (err);
5806 	}
5807 
5808 	return (err);
5809 }
5810 
5811 /*
5812  * This function is only for compatibility with Net80211 module.
5813  * iwh_qosparam_to_hw() is the actual function updating EDCA
5814  * parameters to hardware.
5815  */
5816 /* ARGSUSED */
5817 static int
5818 iwh_wme_update(ieee80211com_t *ic)
5819 {
5820 	return (0);
5821 }
5822 
5823 static int
5824 iwh_wme_to_qos_ac(int wme_ac)
5825 {
5826 	int qos_ac = QOS_AC_INVALID;
5827 
5828 	if (wme_ac < WME_AC_BE || wme_ac > WME_AC_VO) {
5829 		cmn_err(CE_WARN, "iwh_wme_to_qos_ac(): "
5830 		    "WME AC index is not in suitable range.\n");
5831 		return (qos_ac);
5832 	}
5833 
5834 	switch (wme_ac) {
5835 	case WME_AC_BE:
5836 		qos_ac = QOS_AC_BK;
5837 		break;
5838 	case WME_AC_BK:
5839 		qos_ac = QOS_AC_BE;
5840 		break;
5841 	case WME_AC_VI:
5842 		qos_ac = QOS_AC_VI;
5843 		break;
5844 	case WME_AC_VO:
5845 		qos_ac = QOS_AC_VO;
5846 		break;
5847 	}
5848 
5849 	return (qos_ac);
5850 }
5851 
5852 static uint16_t
5853 iwh_cw_e_to_cw(uint8_t cw_e)
5854 {
5855 	uint16_t cw = 1;
5856 
5857 	while (cw_e > 0) {
5858 		cw <<= 1;
5859 		cw_e--;
5860 	}
5861 
5862 	cw -= 1;
5863 	return (cw);
5864 }
5865 
5866 static int
5867 iwh_wmeparam_check(struct wmeParams *wmeparam)
5868 {
5869 	int i;
5870 
5871 	for (i = 0; i < WME_NUM_AC; i++) {
5872 
5873 		if ((wmeparam[i].wmep_logcwmax > QOS_CW_RANGE_MAX) ||
5874 		    (wmeparam[i].wmep_logcwmin >= wmeparam[i].wmep_logcwmax)) {
5875 			cmn_err(CE_WARN, "iwh_wmeparam_check(): "
5876 			    "Contention window is not in suitable range.\n");
5877 			return (IWH_FAIL);
5878 		}
5879 
5880 		if ((wmeparam[i].wmep_aifsn < QOS_AIFSN_MIN) ||
5881 		    (wmeparam[i].wmep_aifsn > QOS_AIFSN_MAX)) {
5882 			cmn_err(CE_WARN, "iwh_wmeparam_check(): "
5883 			    "Arbitration interframe space number"
5884 			    "is not in suitable range.\n");
5885 			return (IWH_FAIL);
5886 		}
5887 	}
5888 
5889 	return (IWH_SUCCESS);
5890 }
5891 
5892 /*
5893  * This function updates EDCA parameters into hardware.
5894  * FIFO0-background, FIFO1-best effort, FIFO2-viedo, FIFO3-voice.
5895  */
5896 static int
5897 iwh_qosparam_to_hw(iwh_sc_t *sc, int async)
5898 {
5899 	ieee80211com_t *ic = &sc->sc_ic;
5900 	ieee80211_node_t *in = ic->ic_bss;
5901 	struct wmeParams *wmeparam;
5902 	iwh_qos_param_cmd_t qosparam_cmd;
5903 	int i, j;
5904 	int err = IWH_FAIL;
5905 
5906 	if ((in->in_flags & IEEE80211_NODE_QOS) &&
5907 	    (IEEE80211_M_STA == ic->ic_opmode)) {
5908 		wmeparam = ic->ic_wme.wme_chanParams.cap_wmeParams;
5909 	} else {
5910 		return (IWH_SUCCESS);
5911 	}
5912 
5913 	(void) memset(&qosparam_cmd, 0, sizeof (qosparam_cmd));
5914 
5915 	err = iwh_wmeparam_check(wmeparam);
5916 	if (err != IWH_SUCCESS) {
5917 		return (err);
5918 	}
5919 
5920 	if (in->in_flags & IEEE80211_NODE_QOS) {
5921 		qosparam_cmd.flags |= QOS_PARAM_FLG_UPDATE_EDCA;
5922 	}
5923 
5924 	if (in->in_flags & (IEEE80211_NODE_QOS | IEEE80211_NODE_HT)) {
5925 		qosparam_cmd.flags |= QOS_PARAM_FLG_TGN;
5926 	}
5927 
5928 	for (i = 0; i < WME_NUM_AC; i++) {
5929 
5930 		j = iwh_wme_to_qos_ac(i);
5931 		if (j < QOS_AC_BK || j > QOS_AC_VO) {
5932 			return (IWH_FAIL);
5933 		}
5934 
5935 		qosparam_cmd.ac[j].cw_min =
5936 		    iwh_cw_e_to_cw(wmeparam[i].wmep_logcwmin);
5937 		qosparam_cmd.ac[j].cw_max =
5938 		    iwh_cw_e_to_cw(wmeparam[i].wmep_logcwmax);
5939 		qosparam_cmd.ac[j].aifsn =
5940 		    wmeparam[i].wmep_aifsn;
5941 		qosparam_cmd.ac[j].txop =
5942 		    (uint16_t)(wmeparam[i].wmep_txopLimit * 32);
5943 	}
5944 
5945 	err = iwh_cmd(sc, REPLY_QOS_PARAM, &qosparam_cmd,
5946 	    sizeof (qosparam_cmd), async);
5947 	if (err != IWH_SUCCESS) {
5948 		cmn_err(CE_WARN, "iwh_qosparam_to_hw(): "
5949 		    "failed to update QoS parameters into hardware.\n");
5950 		return (err);
5951 	}
5952 
5953 #ifdef	DEBUG
5954 	IWH_DBG((IWH_DEBUG_QOS, "iwh_qosparam_to_hw(): "
5955 	    "EDCA parameters are as follows:\n"));
5956 
5957 	IWH_DBG((IWH_DEBUG_QOS, "BK parameters are: "
5958 	    "cw_min = %d, cw_max = %d, aifsn = %d, txop = %d\n",
5959 	    qosparam_cmd.ac[0].cw_min, qosparam_cmd.ac[0].cw_max,
5960 	    qosparam_cmd.ac[0].aifsn, qosparam_cmd.ac[0].txop));
5961 
5962 	IWH_DBG((IWH_DEBUG_QOS, "BE parameters are: "
5963 	    "cw_min = %d, cw_max = %d, aifsn = %d, txop = %d\n",
5964 	    qosparam_cmd.ac[1].cw_min, qosparam_cmd.ac[1].cw_max,
5965 	    qosparam_cmd.ac[1].aifsn, qosparam_cmd.ac[1].txop));
5966 
5967 	IWH_DBG((IWH_DEBUG_QOS, "VI parameters are: "
5968 	    "cw_min = %d, cw_max = %d, aifsn = %d, txop = %d\n",
5969 	    qosparam_cmd.ac[2].cw_min, qosparam_cmd.ac[2].cw_max,
5970 	    qosparam_cmd.ac[2].aifsn, qosparam_cmd.ac[2].txop));
5971 
5972 	IWH_DBG((IWH_DEBUG_QOS, "VO parameters are: "
5973 	    "cw_min = %d, cw_max = %d, aifsn = %d, txop = %d\n",
5974 	    qosparam_cmd.ac[3].cw_min, qosparam_cmd.ac[3].cw_max,
5975 	    qosparam_cmd.ac[3].aifsn, qosparam_cmd.ac[3].txop));
5976 #endif
5977 	return (err);
5978 }
5979 
5980 static inline int
5981 iwh_wme_tid_qos_ac(int tid)
5982 {
5983 	switch (tid) {
5984 	case 1:
5985 	case 2:
5986 		return (QOS_AC_BK);
5987 	case 0:
5988 	case 3:
5989 		return (QOS_AC_BE);
5990 	case 4:
5991 	case 5:
5992 		return (QOS_AC_VI);
5993 	case 6:
5994 	case 7:
5995 		return (QOS_AC_VO);
5996 	}
5997 
5998 	return (QOS_AC_BE);
5999 }
6000 
6001 static inline int
6002 iwh_qos_ac_to_txq(int qos_ac)
6003 {
6004 	switch (qos_ac) {
6005 	case QOS_AC_BK:
6006 		return (QOS_AC_BK_TO_TXQ);
6007 	case QOS_AC_BE:
6008 		return (QOS_AC_BE_TO_TXQ);
6009 	case QOS_AC_VI:
6010 		return (QOS_AC_VI_TO_TXQ);
6011 	case QOS_AC_VO:
6012 		return (QOS_AC_VO_TO_TXQ);
6013 	}
6014 
6015 	return (QOS_AC_BE_TO_TXQ);
6016 }
6017 
6018 static int
6019 iwh_wme_tid_to_txq(int tid)
6020 {
6021 	int queue_n = TXQ_FOR_AC_INVALID;
6022 	int qos_ac;
6023 
6024 	if (tid < WME_TID_MIN ||
6025 	    tid > WME_TID_MAX) {
6026 		cmn_err(CE_WARN, "wme_tid_to_txq(): "
6027 		    "TID is not in suitable range.\n");
6028 		return (queue_n);
6029 	}
6030 
6031 	qos_ac = iwh_wme_tid_qos_ac(tid);
6032 	queue_n = iwh_qos_ac_to_txq(qos_ac);
6033 
6034 	return (queue_n);
6035 }
6036 
6037 /*
6038  * This function is used for intializing HT relevant configurations.
6039  */
6040 static void
6041 iwh_init_ht_conf(iwh_sc_t *sc)
6042 {
6043 	(void) memset(&sc->sc_ht_conf, 0, sizeof (iwh_ht_conf_t));
6044 
6045 	if ((0x4235 == sc->sc_dev_id) ||
6046 	    (0x4236 == sc->sc_dev_id) ||
6047 	    (0x423a == sc->sc_dev_id)) {
6048 		sc->sc_ht_conf.ht_support = 1;
6049 
6050 		sc->sc_ht_conf.valid_chains = 3;
6051 		sc->sc_ht_conf.tx_stream_count = 2;
6052 		sc->sc_ht_conf.rx_stream_count = 2;
6053 
6054 		sc->sc_ht_conf.tx_support_mcs[0] = 0xff;
6055 		sc->sc_ht_conf.tx_support_mcs[1] = 0xff;
6056 		sc->sc_ht_conf.rx_support_mcs[0] = 0xff;
6057 		sc->sc_ht_conf.rx_support_mcs[1] = 0xff;
6058 	} else {
6059 		sc->sc_ht_conf.ht_support = 1;
6060 
6061 		sc->sc_ht_conf.valid_chains = 2;
6062 		sc->sc_ht_conf.tx_stream_count = 1;
6063 		sc->sc_ht_conf.rx_stream_count = 2;
6064 
6065 		sc->sc_ht_conf.tx_support_mcs[0] = 0xff;
6066 		sc->sc_ht_conf.rx_support_mcs[0] = 0xff;
6067 		sc->sc_ht_conf.rx_support_mcs[1] = 0xff;
6068 	}
6069 
6070 	if (sc->sc_ht_conf.ht_support) {
6071 		sc->sc_ht_conf.cap |= HT_CAP_GRN_FLD;
6072 		sc->sc_ht_conf.cap |= HT_CAP_SGI_20;
6073 		sc->sc_ht_conf.cap |= HT_CAP_MAX_AMSDU;
6074 		/* should disable MIMO */
6075 		sc->sc_ht_conf.cap |= HT_CAP_MIMO_PS;
6076 
6077 		sc->sc_ht_conf.ampdu_p.factor = HT_RX_AMPDU_FACTOR;
6078 		sc->sc_ht_conf.ampdu_p.density = HT_MPDU_DENSITY;
6079 
6080 		sc->sc_ht_conf.ht_protection = HT_PROT_CHAN_NON_HT;
6081 	}
6082 }
6083 
6084 /*
6085  * This function overwrites default ieee80211_rateset_11n struc.
6086  */
6087 static void
6088 iwh_overwrite_11n_rateset(iwh_sc_t *sc)
6089 {
6090 	uint8_t *ht_rs = sc->sc_ht_conf.rx_support_mcs;
6091 	int mcs_idx, mcs_count = 0;
6092 	int i, j;
6093 
6094 	for (i = 0; i < HT_RATESET_NUM; i++) {
6095 		for (j = 0; j < 8; j++) {
6096 			if (ht_rs[i] & (1 << j)) {
6097 				mcs_idx = i * 8 + j;
6098 				if (mcs_idx >= IEEE80211_HTRATE_MAXSIZE) {
6099 					break;
6100 				}
6101 
6102 				ieee80211_rateset_11n.rs_rates[mcs_idx] =
6103 				    (uint8_t)mcs_idx;
6104 				mcs_count++;
6105 			}
6106 		}
6107 	}
6108 
6109 	ieee80211_rateset_11n.rs_nrates = (uint8_t)mcs_count;
6110 
6111 #ifdef	DEBUG
6112 	IWH_DBG((IWH_DEBUG_HTRATE, "iwh_overwrite_11n_rateset(): "
6113 	    "HT rates supported by this station is as follows:\n"));
6114 
6115 	for (i = 0; i < ieee80211_rateset_11n.rs_nrates; i++) {
6116 		IWH_DBG((IWH_DEBUG_HTRATE, "Rate %d is %d\n",
6117 		    i, ieee80211_rateset_11n.rs_rates[i]));
6118 	}
6119 #endif
6120 }
6121 
6122 /*
6123  * This function overwrites default configurations of
6124  * ieee80211com structure in Net80211 module.
6125  */
6126 static void
6127 iwh_overwrite_ic_default(iwh_sc_t *sc)
6128 {
6129 	ieee80211com_t *ic = &sc->sc_ic;
6130 
6131 	sc->sc_newstate = ic->ic_newstate;
6132 	ic->ic_newstate = iwh_newstate;
6133 	ic->ic_node_alloc = iwh_node_alloc;
6134 	ic->ic_node_free = iwh_node_free;
6135 
6136 	if (sc->sc_ht_conf.ht_support) {
6137 		sc->sc_recv_action = ic->ic_recv_action;
6138 		ic->ic_recv_action = iwh_recv_action;
6139 		sc->sc_send_action = ic->ic_send_action;
6140 		ic->ic_send_action = iwh_send_action;
6141 
6142 		ic->ic_ampdu_rxmax = sc->sc_ht_conf.ampdu_p.factor;
6143 		ic->ic_ampdu_density = sc->sc_ht_conf.ampdu_p.density;
6144 		ic->ic_ampdu_limit = ic->ic_ampdu_rxmax;
6145 	}
6146 }
6147 
6148 /*
6149  * This function sets "RX chain selection" feild
6150  * in RXON command during plumb driver.
6151  */
6152 static void
6153 iwh_config_rxon_chain(iwh_sc_t *sc)
6154 {
6155 	ieee80211com_t *ic = &sc->sc_ic;
6156 	ieee80211_node_t *in = ic->ic_bss;
6157 
6158 	if (3 == sc->sc_ht_conf.valid_chains) {
6159 		sc->sc_config.rx_chain = LE_16((RXON_RX_CHAIN_A_MSK |
6160 		    RXON_RX_CHAIN_B_MSK | RXON_RX_CHAIN_C_MSK) <<
6161 		    RXON_RX_CHAIN_VALID_POS);
6162 
6163 		sc->sc_config.rx_chain |= LE_16((RXON_RX_CHAIN_A_MSK |
6164 		    RXON_RX_CHAIN_B_MSK | RXON_RX_CHAIN_C_MSK) <<
6165 		    RXON_RX_CHAIN_FORCE_SEL_POS);
6166 
6167 		sc->sc_config.rx_chain |= LE_16((RXON_RX_CHAIN_A_MSK |
6168 		    RXON_RX_CHAIN_B_MSK | RXON_RX_CHAIN_C_MSK) <<
6169 		    RXON_RX_CHAIN_FORCE_MIMO_SEL_POS);
6170 	} else {
6171 		sc->sc_config.rx_chain = LE_16((RXON_RX_CHAIN_A_MSK |
6172 		    RXON_RX_CHAIN_B_MSK) << RXON_RX_CHAIN_VALID_POS);
6173 
6174 		sc->sc_config.rx_chain |= LE_16((RXON_RX_CHAIN_A_MSK |
6175 		    RXON_RX_CHAIN_B_MSK) << RXON_RX_CHAIN_FORCE_SEL_POS);
6176 
6177 		sc->sc_config.rx_chain |= LE_16((RXON_RX_CHAIN_A_MSK |
6178 		    RXON_RX_CHAIN_B_MSK) <<
6179 		    RXON_RX_CHAIN_FORCE_MIMO_SEL_POS);
6180 	}
6181 
6182 	sc->sc_config.rx_chain |= LE_16(RXON_RX_CHAIN_DRIVER_FORCE_MSK);
6183 
6184 	if ((in != NULL) &&
6185 	    (in->in_flags & IEEE80211_NODE_HT) &&
6186 	    sc->sc_ht_conf.ht_support) {
6187 		if (3 == sc->sc_ht_conf.valid_chains) {
6188 			sc->sc_config.rx_chain |= LE_16(3 <<
6189 			    RXON_RX_CHAIN_CNT_POS);
6190 			sc->sc_config.rx_chain |= LE_16(3 <<
6191 			    RXON_RX_CHAIN_MIMO_CNT_POS);
6192 		} else {
6193 			sc->sc_config.rx_chain |= LE_16(2 <<
6194 			    RXON_RX_CHAIN_CNT_POS);
6195 			sc->sc_config.rx_chain |= LE_16(2 <<
6196 			    RXON_RX_CHAIN_MIMO_CNT_POS);
6197 		}
6198 
6199 		sc->sc_config.rx_chain |= LE_16(1 <<
6200 		    RXON_RX_CHAIN_MIMO_FORCE_POS);
6201 	}
6202 
6203 	IWH_DBG((IWH_DEBUG_RXON, "iwh_config_rxon_chain(): "
6204 	    "rxon->rx_chain = %x\n", sc->sc_config.rx_chain));
6205 }
6206 
6207 /*
6208  * This function adds AP station into hardware.
6209  */
6210 static int
6211 iwh_add_ap_sta(iwh_sc_t *sc)
6212 {
6213 	ieee80211com_t *ic = &sc->sc_ic;
6214 	ieee80211_node_t *in = ic->ic_bss;
6215 	iwh_add_sta_t node;
6216 	uint32_t ampdu_factor, ampdu_density;
6217 	int err = IWH_FAIL;
6218 
6219 	/*
6220 	 * Add AP node into hardware.
6221 	 */
6222 	(void) memset(&node, 0, sizeof (node));
6223 	IEEE80211_ADDR_COPY(node.sta.addr, in->in_bssid);
6224 	node.mode = STA_MODE_ADD_MSK;
6225 	node.sta.sta_id = IWH_AP_ID;
6226 
6227 	if (sc->sc_ht_conf.ht_support &&
6228 	    (in->in_htcap_ie != NULL) &&
6229 	    (in->in_htcap != 0) &&
6230 	    (in->in_htparam != 0)) {
6231 
6232 		if (((in->in_htcap & HT_CAP_MIMO_PS) >> 2)
6233 		    == HT_CAP_MIMO_PS_DYNAMIC) {
6234 			node.station_flags |= LE_32(STA_FLG_RTS_MIMO_PROT);
6235 		}
6236 
6237 		ampdu_factor = in->in_htparam & HT_RX_AMPDU_FACTOR_MSK;
6238 		node.station_flags |=
6239 		    LE_32(ampdu_factor << STA_FLG_MAX_AMPDU_POS);
6240 
6241 		ampdu_density = (in->in_htparam & HT_MPDU_DENSITY_MSK) >>
6242 		    HT_MPDU_DENSITY_POS;
6243 		node.station_flags |=
6244 		    LE_32(ampdu_density << STA_FLG_AMPDU_DENSITY_POS);
6245 
6246 		if (in->in_htcap & LE_16(HT_CAP_SUP_WIDTH)) {
6247 			node.station_flags |=
6248 			    LE_32(STA_FLG_FAT_EN);
6249 		}
6250 	}
6251 
6252 	err = iwh_cmd(sc, REPLY_ADD_STA, &node, sizeof (node), 1);
6253 	if (err != IWH_SUCCESS) {
6254 		cmn_err(CE_WARN, "iwh_add_ap_lq(): "
6255 		    "failed to add AP node\n");
6256 		return (err);
6257 	}
6258 
6259 	return (err);
6260 }
6261 
6262 /*
6263  * Each station in the Shirley Peak's internal station table has
6264  * its own table of 16 TX rates and modulation modes for retrying
6265  * TX when an ACK is not received. This function replaces the entire
6266  * table for one station.Station must already be in Shirley Peak's
6267  * station talbe.
6268  */
6269 static int
6270 iwh_ap_lq(iwh_sc_t *sc)
6271 {
6272 	ieee80211com_t *ic = &sc->sc_ic;
6273 	ieee80211_node_t *in = ic->ic_bss;
6274 	iwh_link_quality_cmd_t link_quality;
6275 	const struct ieee80211_rateset *rs_sup = NULL;
6276 	uint32_t masks = 0, rate;
6277 	int i, err = IWH_FAIL;
6278 
6279 	/*
6280 	 * TX_LINK_QUALITY cmd
6281 	 */
6282 	(void) memset(&link_quality, 0, sizeof (link_quality));
6283 	if (in->in_chan == IEEE80211_CHAN_ANYC)	/* skip null node */
6284 		return (err);
6285 	rs_sup = ieee80211_get_suprates(ic, in->in_chan);
6286 
6287 	for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) {
6288 		if (i < rs_sup->ir_nrates) {
6289 			rate = rs_sup->ir_rates[rs_sup->ir_nrates - i] &
6290 			    IEEE80211_RATE_VAL;
6291 		} else {
6292 			rate = 2;
6293 		}
6294 
6295 		if (2 == rate || 4 == rate ||
6296 		    11 == rate || 22 == rate) {
6297 			masks |= LE_32(RATE_MCS_CCK_MSK);
6298 		}
6299 
6300 		masks |= LE_32(RATE_MCS_ANT_B_MSK);
6301 
6302 		link_quality.rate_n_flags[i] =
6303 		    LE_32(iwh_rate_to_plcp(rate) | masks);
6304 	}
6305 
6306 	link_quality.general_params.single_stream_ant_msk = LINK_QUAL_ANT_B_MSK;
6307 	link_quality.general_params.dual_stream_ant_msk = LINK_QUAL_ANT_MSK;
6308 	link_quality.agg_params.agg_dis_start_th = 3;
6309 	link_quality.agg_params.agg_time_limit = LE_16(4000);
6310 	link_quality.sta_id = IWH_AP_ID;
6311 	err = iwh_cmd(sc, REPLY_TX_LINK_QUALITY_CMD, &link_quality,
6312 	    sizeof (link_quality), 1);
6313 	if (err != IWH_SUCCESS) {
6314 		cmn_err(CE_WARN, "iwh_ap_lq(): "
6315 		    "failed to config link quality table\n");
6316 		return (err);
6317 	}
6318 
6319 #ifdef	DEBUG
6320 	IWH_DBG((IWH_DEBUG_HWRATE, "iwh_ap_lq(): "
6321 	    "Rates in HW are as follows:\n"));
6322 
6323 	for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) {
6324 		IWH_DBG((IWH_DEBUG_HWRATE,
6325 		    "Rate %d in HW is %x\n", i, link_quality.rate_n_flags[i]));
6326 	}
6327 #endif
6328 
6329 	return (err);
6330 }
6331 
6332 /*
6333  * When block ACK agreement has been set up between station and AP,
6334  * Net80211 module will call this function to inform hardware about
6335  * informations of this BA agreement.
6336  * When AP wants to delete BA agreement that was originated by it,
6337  * Net80211 modele will call this function to clean up relevant
6338  * information in hardware.
6339  */
6340 static void
6341 iwh_recv_action(struct ieee80211_node *in,
6342     const uint8_t *frm, const uint8_t *efrm)
6343 {
6344 	struct ieee80211com *ic;
6345 	iwh_sc_t *sc;
6346 	const struct ieee80211_action *ia;
6347 	uint16_t baparamset, baseqctl;
6348 	uint32_t tid, ssn;
6349 	iwh_add_sta_t node;
6350 	int err = IWH_FAIL;
6351 
6352 	if ((NULL == in) || (NULL == frm)) {
6353 		return;
6354 	}
6355 
6356 	ic = in->in_ic;
6357 	if (NULL == ic) {
6358 		return;
6359 	}
6360 
6361 	sc = (iwh_sc_t *)ic;
6362 
6363 	sc->sc_recv_action(in, frm, efrm);
6364 
6365 	ia = (const struct ieee80211_action *)frm;
6366 	if (ia->ia_category != IEEE80211_ACTION_CAT_BA) {
6367 		return;
6368 	}
6369 
6370 	switch (ia->ia_action) {
6371 	case IEEE80211_ACTION_BA_ADDBA_REQUEST:
6372 		baparamset = *(uint16_t *)(frm + 3);
6373 		baseqctl = *(uint16_t *)(frm + 7);
6374 
6375 		tid = MS(baparamset, IEEE80211_BAPS_TID);
6376 		ssn = MS(baseqctl, IEEE80211_BASEQ_START);
6377 
6378 		(void) memset(&node, 0, sizeof (node));
6379 		IEEE80211_ADDR_COPY(node.sta.addr, in->in_bssid);
6380 		node.mode = STA_MODE_MODIFY_MSK;
6381 		node.sta.sta_id = IWH_AP_ID;
6382 
6383 		node.station_flags_msk = 0;
6384 		node.sta.modify_mask = STA_MODIFY_ADDBA_TID_MSK;
6385 		node.add_immediate_ba_tid = (uint8_t)tid;
6386 		node.add_immediate_ba_ssn = LE_16(ssn);
6387 
6388 		mutex_enter(&sc->sc_glock);
6389 		err = iwh_cmd(sc, REPLY_ADD_STA, &node, sizeof (node), 1);
6390 		if (err != IWH_SUCCESS) {
6391 			cmn_err(CE_WARN, "iwh_recv_action(): "
6392 			    "failed to setup RX block ACK\n");
6393 			mutex_exit(&sc->sc_glock);
6394 			return;
6395 		}
6396 		mutex_exit(&sc->sc_glock);
6397 
6398 		IWH_DBG((IWH_DEBUG_BA, "iwh_recv_action(): "
6399 		    "RX block ACK "
6400 		    "was setup on TID %d and SSN is %d.\n", tid, ssn));
6401 
6402 		return;
6403 
6404 	case IEEE80211_ACTION_BA_DELBA:
6405 		baparamset = *(uint16_t *)(frm + 2);
6406 
6407 		if ((baparamset & IEEE80211_DELBAPS_INIT) == 0) {
6408 			return;
6409 		}
6410 
6411 		tid = MS(baparamset, IEEE80211_DELBAPS_TID);
6412 
6413 		(void) memset(&node, 0, sizeof (node));
6414 		IEEE80211_ADDR_COPY(node.sta.addr, in->in_bssid);
6415 		node.mode = STA_MODE_MODIFY_MSK;
6416 		node.sta.sta_id = IWH_AP_ID;
6417 
6418 		node.station_flags_msk = 0;
6419 		node.sta.modify_mask = STA_MODIFY_DELBA_TID_MSK;
6420 		node.add_immediate_ba_tid = (uint8_t)tid;
6421 
6422 		mutex_enter(&sc->sc_glock);
6423 		err = iwh_cmd(sc, REPLY_ADD_STA, &node, sizeof (node), 1);
6424 		if (err != IWH_SUCCESS) {
6425 			cmn_err(CE_WARN, "iwh_recv_action(): "
6426 			    "failed to delete RX block ACK\n");
6427 			mutex_exit(&sc->sc_glock);
6428 			return;
6429 		}
6430 		mutex_exit(&sc->sc_glock);
6431 
6432 		IWH_DBG((IWH_DEBUG_BA, "iwh_recv_action(): "
6433 		    "RX block ACK "
6434 		    "was deleted on TID %d.\n", tid));
6435 
6436 		return;
6437 	}
6438 }
6439 
6440 /*
6441  * When local station wants to delete BA agreement that was originated by AP,
6442  * Net80211 module will call this function to clean up relevant information
6443  * in hardware.
6444  */
6445 static int
6446 iwh_send_action(struct ieee80211_node *in,
6447     int category, int action, uint16_t args[4])
6448 {
6449 	struct ieee80211com *ic;
6450 	iwh_sc_t *sc;
6451 	uint32_t tid;
6452 	iwh_add_sta_t node;
6453 	int ret = EIO;
6454 	int err = IWH_FAIL;
6455 
6456 
6457 	if (NULL == in) {
6458 		return (ret);
6459 	}
6460 
6461 	ic = in->in_ic;
6462 	if (NULL == ic) {
6463 		return (ret);
6464 	}
6465 
6466 	sc = (iwh_sc_t *)ic;
6467 
6468 	ret = sc->sc_send_action(in, category, action, args);
6469 
6470 	if (category != IEEE80211_ACTION_CAT_BA) {
6471 		return (ret);
6472 	}
6473 
6474 	switch (action) {
6475 	case IEEE80211_ACTION_BA_DELBA:
6476 		if (IEEE80211_DELBAPS_INIT == args[1]) {
6477 			return (ret);
6478 		}
6479 
6480 		tid = args[0];
6481 
6482 		(void) memset(&node, 0, sizeof (node));
6483 		IEEE80211_ADDR_COPY(node.sta.addr, in->in_bssid);
6484 		node.mode = STA_MODE_MODIFY_MSK;
6485 		node.sta.sta_id = IWH_AP_ID;
6486 
6487 		node.station_flags_msk = 0;
6488 		node.sta.modify_mask = STA_MODIFY_DELBA_TID_MSK;
6489 		node.add_immediate_ba_tid = (uint8_t)tid;
6490 
6491 		mutex_enter(&sc->sc_glock);
6492 		err = iwh_cmd(sc, REPLY_ADD_STA, &node, sizeof (node), 1);
6493 		if (err != IWH_SUCCESS) {
6494 			cmn_err(CE_WARN, "iwh_send_action(): "
6495 			    "failed to delete RX balock ACK\n");
6496 			mutex_exit(&sc->sc_glock);
6497 			return (EIO);
6498 		}
6499 		mutex_exit(&sc->sc_glock);
6500 
6501 		IWH_DBG((IWH_DEBUG_BA, "iwh_send_action(): "
6502 		    "RX block ACK "
6503 		    "was deleted on TID %d.\n", tid));
6504 
6505 		break;
6506 	}
6507 
6508 	return (ret);
6509 }
6510