xref: /titanic_41/usr/src/uts/common/io/iwh/iwh.c (revision ddc42f882d0d14ab016a8405099fe8ad93170c00)
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 		{
2826 			struct iwh_beacon_missed *miss =
2827 			    (struct iwh_beacon_missed *)(desc + 1);
2828 
2829 			if ((ic->ic_state == IEEE80211_S_RUN) &&
2830 			    (LE_32(miss->consecutive) > 50)) {
2831 				cmn_err(CE_NOTE, "iwh: iwh_rx_softintr(): "
2832 				    "beacon missed %d/%d\n",
2833 				    LE_32(miss->consecutive),
2834 				    LE_32(miss->total));
2835 				(void) ieee80211_new_state(ic,
2836 				    IEEE80211_S_INIT, -1);
2837 			}
2838 			break;
2839 		}
2840 		}
2841 
2842 		sc->sc_rxq.cur = (sc->sc_rxq.cur + 1) % RX_QUEUE_SIZE;
2843 	}
2844 
2845 	/*
2846 	 * driver dealt with what received in rx queue and tell the information
2847 	 * to the firmware.
2848 	 */
2849 	index = (0 == index) ? RX_QUEUE_SIZE - 1 : index - 1;
2850 	IWH_WRITE(sc, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, index & (~7));
2851 
2852 	/*
2853 	 * re-enable interrupts
2854 	 */
2855 	IWH_WRITE(sc, CSR_INT_MASK, CSR_INI_SET_MASK);
2856 
2857 	return (DDI_INTR_CLAIMED);
2858 }
2859 
2860 /*
2861  * the handle of interrupt
2862  */
2863 /* ARGSUSED */
2864 static uint_t
2865 iwh_intr(caddr_t arg, caddr_t unused)
2866 {
2867 	iwh_sc_t *sc;
2868 	uint32_t r, rfh;
2869 
2870 	if (NULL == arg) {
2871 		return (DDI_INTR_UNCLAIMED);
2872 	}
2873 	sc = (iwh_sc_t *)arg;
2874 
2875 	r = IWH_READ(sc, CSR_INT);
2876 	if (0 == r || 0xffffffff == r) {
2877 		return (DDI_INTR_UNCLAIMED);
2878 	}
2879 
2880 	IWH_DBG((IWH_DEBUG_INTR, "iwh_intr(): "
2881 	    "interrupt reg %x\n", r));
2882 
2883 	rfh = IWH_READ(sc, CSR_FH_INT_STATUS);
2884 
2885 	IWH_DBG((IWH_DEBUG_INTR, "iwh_intr(): "
2886 	    "FH interrupt reg %x\n", rfh));
2887 
2888 	/*
2889 	 * disable interrupts
2890 	 */
2891 	IWH_WRITE(sc, CSR_INT_MASK, 0);
2892 
2893 	/*
2894 	 * ack interrupts
2895 	 */
2896 	IWH_WRITE(sc, CSR_INT, r);
2897 	IWH_WRITE(sc, CSR_FH_INT_STATUS, rfh);
2898 
2899 	if (r & (BIT_INT_SWERROR | BIT_INT_ERR)) {
2900 		IWH_DBG((IWH_DEBUG_FW, "iwh_intr(): "
2901 		    "fatal firmware error\n"));
2902 		iwh_stop(sc);
2903 		sc->sc_ostate = sc->sc_ic.ic_state;
2904 
2905 		/*
2906 		 * notify upper layer
2907 		 */
2908 		if (!IWH_CHK_FAST_RECOVER(sc)) {
2909 			ieee80211_new_state(&sc->sc_ic, IEEE80211_S_INIT, -1);
2910 		}
2911 
2912 		atomic_or_32(&sc->sc_flags, IWH_F_HW_ERR_RECOVER);
2913 		return (DDI_INTR_CLAIMED);
2914 	}
2915 
2916 	if (r & BIT_INT_RF_KILL) {
2917 		uint32_t tmp = IWH_READ(sc, CSR_GP_CNTRL);
2918 		if (tmp & (1 << 27)) {
2919 			cmn_err(CE_NOTE, "RF switch: radio on\n");
2920 		}
2921 	}
2922 
2923 	if ((r & (BIT_INT_FH_RX | BIT_INT_SW_RX)) ||
2924 	    (rfh & FH_INT_RX_MASK)) {
2925 		(void) ddi_intr_trigger_softint(sc->sc_soft_hdl, NULL);
2926 		return (DDI_INTR_CLAIMED);
2927 	}
2928 
2929 	if (r & BIT_INT_FH_TX) {
2930 		mutex_enter(&sc->sc_glock);
2931 		atomic_or_32(&sc->sc_flags, IWH_F_PUT_SEG);
2932 		cv_signal(&sc->sc_put_seg_cv);
2933 		mutex_exit(&sc->sc_glock);
2934 	}
2935 
2936 #ifdef	DEBUG
2937 	if (r & BIT_INT_ALIVE)	{
2938 		IWH_DBG((IWH_DEBUG_FW, "iwh_intr(): "
2939 		    "firmware initialized.\n"));
2940 	}
2941 #endif
2942 
2943 	/*
2944 	 * re-enable interrupts
2945 	 */
2946 	IWH_WRITE(sc, CSR_INT_MASK, CSR_INI_SET_MASK);
2947 
2948 	return (DDI_INTR_CLAIMED);
2949 }
2950 
2951 static uint8_t
2952 iwh_rate_to_plcp(int rate)
2953 {
2954 	uint8_t ret;
2955 
2956 	switch (rate) {
2957 	/*
2958 	 * CCK rates
2959 	 */
2960 	case 2:
2961 		ret = 0xa;
2962 		break;
2963 
2964 	case 4:
2965 		ret = 0x14;
2966 		break;
2967 
2968 	case 11:
2969 		ret = 0x37;
2970 		break;
2971 
2972 	case 22:
2973 		ret = 0x6e;
2974 		break;
2975 
2976 	/*
2977 	 * OFDM rates
2978 	 */
2979 	case 12:
2980 		ret = 0xd;
2981 		break;
2982 
2983 	case 18:
2984 		ret = 0xf;
2985 		break;
2986 
2987 	case 24:
2988 		ret = 0x5;
2989 		break;
2990 
2991 	case 36:
2992 		ret = 0x7;
2993 		break;
2994 
2995 	case 48:
2996 		ret = 0x9;
2997 		break;
2998 
2999 	case 72:
3000 		ret = 0xb;
3001 		break;
3002 
3003 	case 96:
3004 		ret = 0x1;
3005 		break;
3006 
3007 	case 108:
3008 		ret = 0x3;
3009 		break;
3010 
3011 	default:
3012 		ret = 0;
3013 		break;
3014 	}
3015 
3016 	return (ret);
3017 }
3018 
3019 /*
3020  * invoked by GLD send frames
3021  */
3022 static mblk_t *
3023 iwh_m_tx(void *arg, mblk_t *mp)
3024 {
3025 	iwh_sc_t *sc;
3026 	ieee80211com_t *ic;
3027 	mblk_t *next;
3028 
3029 	if (NULL == arg) {
3030 		return (NULL);
3031 	}
3032 	sc = (iwh_sc_t *)arg;
3033 	ic = &sc->sc_ic;
3034 
3035 	if (sc->sc_flags & IWH_F_SUSPEND) {
3036 		freemsgchain(mp);
3037 		return (NULL);
3038 	}
3039 
3040 	if (ic->ic_state != IEEE80211_S_RUN) {
3041 		freemsgchain(mp);
3042 		return (NULL);
3043 	}
3044 
3045 	if ((sc->sc_flags & IWH_F_HW_ERR_RECOVER) &&
3046 	    IWH_CHK_FAST_RECOVER(sc)) {
3047 		IWH_DBG((IWH_DEBUG_FW, "iwh_m_tx(): "
3048 		    "hold queue\n"));
3049 		return (mp);
3050 	}
3051 
3052 	while (mp != NULL) {
3053 		next = mp->b_next;
3054 		mp->b_next = NULL;
3055 		if (iwh_send(ic, mp, IEEE80211_FC0_TYPE_DATA) != 0) {
3056 			mp->b_next = next;
3057 			break;
3058 		}
3059 		mp = next;
3060 	}
3061 
3062 	return (mp);
3063 }
3064 
3065 /*
3066  * send frames
3067  */
3068 static int
3069 iwh_send(ieee80211com_t *ic, mblk_t *mp, uint8_t type)
3070 {
3071 	iwh_sc_t *sc;
3072 	iwh_tx_ring_t *ring;
3073 	iwh_tx_desc_t *desc;
3074 	iwh_tx_data_t *data;
3075 	iwh_tx_data_t *desc_data;
3076 	iwh_cmd_t *cmd;
3077 	iwh_tx_cmd_t *tx;
3078 	ieee80211_node_t *in;
3079 	struct ieee80211_frame *wh, *mp_wh;
3080 	struct ieee80211_key *k = NULL;
3081 	mblk_t *m, *m0;
3082 	int hdrlen, len, len0, mblen, off, err = IWH_SUCCESS;
3083 	uint16_t masks = 0;
3084 	uint32_t rate, s_id = 0;
3085 	int txq_id = NON_QOS_TXQ;
3086 	struct ieee80211_qosframe *qwh = NULL;
3087 	int tid = WME_TID_INVALID;
3088 
3089 	if (NULL == ic) {
3090 		return (IWH_FAIL);
3091 	}
3092 	sc = (iwh_sc_t *)ic;
3093 
3094 	if (sc->sc_flags & IWH_F_SUSPEND) {
3095 		if ((type & IEEE80211_FC0_TYPE_MASK) !=
3096 		    IEEE80211_FC0_TYPE_DATA) {
3097 			freemsg(mp);
3098 		}
3099 		err = IWH_FAIL;
3100 		goto exit;
3101 	}
3102 
3103 	if ((NULL == mp) || (MBLKL(mp) <= 0)) {
3104 		return (IWH_FAIL);
3105 	}
3106 
3107 	mp_wh = (struct ieee80211_frame *)mp->b_rptr;
3108 
3109 	/*
3110 	 * Determine send which AP or station in IBSS
3111 	 */
3112 	in = ieee80211_find_txnode(ic, mp_wh->i_addr1);
3113 	if (NULL == in) {
3114 		cmn_err(CE_WARN, "iwh_send(): "
3115 		    "failed to find tx node\n");
3116 		freemsg(mp);
3117 		sc->sc_tx_err++;
3118 		err = IWH_SUCCESS;
3119 		goto exit;
3120 	}
3121 
3122 	/*
3123 	 * Determine TX queue according to traffic ID in frame
3124 	 * if working in QoS mode.
3125 	 */
3126 	if (in->in_flags & IEEE80211_NODE_QOS) {
3127 
3128 		if ((type & IEEE80211_FC0_TYPE_MASK) ==
3129 		    IEEE80211_FC0_TYPE_DATA) {
3130 
3131 			if (mp_wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_QOS) {
3132 				qwh = (struct ieee80211_qosframe *)mp_wh;
3133 
3134 				tid = qwh->i_qos[0] & IEEE80211_QOS_TID;
3135 				txq_id = iwh_wme_tid_to_txq(tid);
3136 
3137 				if (txq_id < TXQ_FOR_AC_MIN ||
3138 				    (txq_id > TXQ_FOR_AC_MAX)) {
3139 					freemsg(mp);
3140 					sc->sc_tx_err++;
3141 					err = IWH_SUCCESS;
3142 					goto exit;
3143 				}
3144 
3145 			} else {
3146 				txq_id = NON_QOS_TXQ;
3147 			}
3148 
3149 		} else if ((type & IEEE80211_FC0_TYPE_MASK) ==
3150 		    IEEE80211_FC0_TYPE_MGT) {
3151 			txq_id = QOS_TXQ_FOR_MGT;
3152 		} else {
3153 			txq_id = NON_QOS_TXQ;
3154 		}
3155 
3156 	} else {
3157 		txq_id = NON_QOS_TXQ;
3158 	}
3159 
3160 	mutex_enter(&sc->sc_tx_lock);
3161 	ring = &sc->sc_txq[txq_id];
3162 	data = &ring->data[ring->cur];
3163 	cmd = data->cmd;
3164 	bzero(cmd, sizeof (*cmd));
3165 
3166 	ring->cur = (ring->cur + 1) % ring->count;
3167 
3168 	/*
3169 	 * Need reschedule TX if TX buffer is full.
3170 	 */
3171 	if (ring->queued > ring->count - IWH_MAX_WIN_SIZE) {
3172 		IWH_DBG((IWH_DEBUG_TX, "iwh_send(): "
3173 		"no txbuf\n"));
3174 
3175 		sc->sc_need_reschedule = 1;
3176 		mutex_exit(&sc->sc_tx_lock);
3177 
3178 		if ((type & IEEE80211_FC0_TYPE_MASK) !=
3179 		    IEEE80211_FC0_TYPE_DATA) {
3180 			freemsg(mp);
3181 		}
3182 		sc->sc_tx_nobuf++;
3183 		err = IWH_FAIL;
3184 		goto exit;
3185 	}
3186 
3187 	ring->queued++;
3188 
3189 	mutex_exit(&sc->sc_tx_lock);
3190 
3191 	hdrlen = ieee80211_hdrspace(ic, mp->b_rptr);
3192 
3193 	m = allocb(msgdsize(mp) + 32, BPRI_MED);
3194 	if (NULL == m) { /* can not alloc buf, drop this package */
3195 		cmn_err(CE_WARN, "iwh_send(): "
3196 		    "failed to allocate msgbuf\n");
3197 		freemsg(mp);
3198 
3199 		mutex_enter(&sc->sc_tx_lock);
3200 		ring->queued--;
3201 		if ((sc->sc_need_reschedule) && (ring->queued <= 0)) {
3202 			sc->sc_need_reschedule = 0;
3203 			mutex_exit(&sc->sc_tx_lock);
3204 			mac_tx_update(ic->ic_mach);
3205 			mutex_enter(&sc->sc_tx_lock);
3206 		}
3207 		mutex_exit(&sc->sc_tx_lock);
3208 
3209 		err = IWH_SUCCESS;
3210 		goto exit;
3211 	}
3212 
3213 	for (off = 0, m0 = mp; m0 != NULL; m0 = m0->b_cont) {
3214 		mblen = MBLKL(m0);
3215 		bcopy(m0->b_rptr, m->b_rptr + off, mblen);
3216 		off += mblen;
3217 	}
3218 
3219 	m->b_wptr += off;
3220 
3221 	wh = (struct ieee80211_frame *)m->b_rptr;
3222 
3223 	/*
3224 	 * Net80211 module encapsulate outbound data frames.
3225 	 * Add some feilds of 80211 frame.
3226 	 */
3227 	if ((type & IEEE80211_FC0_TYPE_MASK) ==
3228 	    IEEE80211_FC0_TYPE_DATA) {
3229 		(void) ieee80211_encap(ic, m, in);
3230 	}
3231 
3232 	freemsg(mp);
3233 
3234 	cmd->hdr.type = REPLY_TX;
3235 	cmd->hdr.flags = 0;
3236 	cmd->hdr.qid = ring->qid;
3237 
3238 	tx = (iwh_tx_cmd_t *)cmd->data;
3239 	tx->tx_flags = 0;
3240 
3241 	if (IEEE80211_IS_MULTICAST(wh->i_addr1)) {
3242 		tx->tx_flags &= ~(LE_32(TX_CMD_FLG_ACK_MSK));
3243 	} else {
3244 		tx->tx_flags |= LE_32(TX_CMD_FLG_ACK_MSK);
3245 	}
3246 
3247 	if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
3248 		k = ieee80211_crypto_encap(ic, m);
3249 		if (NULL == k) {
3250 			freemsg(m);
3251 			sc->sc_tx_err++;
3252 
3253 			mutex_enter(&sc->sc_tx_lock);
3254 			ring->queued--;
3255 			if ((sc->sc_need_reschedule) && (ring->queued <= 0)) {
3256 				sc->sc_need_reschedule = 0;
3257 				mutex_exit(&sc->sc_tx_lock);
3258 				mac_tx_update(ic->ic_mach);
3259 				mutex_enter(&sc->sc_tx_lock);
3260 			}
3261 			mutex_exit(&sc->sc_tx_lock);
3262 
3263 			err = IWH_SUCCESS;
3264 			goto exit;
3265 		}
3266 
3267 		/*
3268 		 * packet header may have moved, reset our local pointer
3269 		 */
3270 		wh = (struct ieee80211_frame *)m->b_rptr;
3271 	}
3272 
3273 	len = msgdsize(m);
3274 
3275 #ifdef DEBUG
3276 	if (iwh_dbg_flags & IWH_DEBUG_TX) {
3277 		ieee80211_dump_pkt((uint8_t *)wh, hdrlen, 0, 0);
3278 	}
3279 #endif
3280 
3281 	tx->rts_retry_limit = IWH_TX_RTS_RETRY_LIMIT;
3282 	tx->data_retry_limit = IWH_TX_DATA_RETRY_LIMIT;
3283 
3284 	/*
3285 	 * specific TX parameters for management frames
3286 	 */
3287 	if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
3288 	    IEEE80211_FC0_TYPE_MGT) {
3289 		/*
3290 		 * mgmt frames are sent at 1M
3291 		 */
3292 		if ((in->in_rates.ir_rates[0] &
3293 		    IEEE80211_RATE_VAL) != 0) {
3294 			rate = in->in_rates.ir_rates[0] & IEEE80211_RATE_VAL;
3295 		} else {
3296 			rate = 2;
3297 		}
3298 
3299 		tx->tx_flags |= LE_32(TX_CMD_FLG_SEQ_CTL_MSK);
3300 
3301 		/*
3302 		 * tell h/w to set timestamp in probe responses
3303 		 */
3304 		if ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) ==
3305 		    IEEE80211_FC0_SUBTYPE_PROBE_RESP) {
3306 			tx->tx_flags |= LE_32(TX_CMD_FLG_TSF_MSK);
3307 
3308 			tx->data_retry_limit = 3;
3309 			if (tx->data_retry_limit < tx->rts_retry_limit) {
3310 				tx->rts_retry_limit = tx->data_retry_limit;
3311 			}
3312 		}
3313 
3314 		if (((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) ==
3315 		    IEEE80211_FC0_SUBTYPE_ASSOC_REQ) ||
3316 		    ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) ==
3317 		    IEEE80211_FC0_SUBTYPE_REASSOC_REQ)) {
3318 			tx->timeout.pm_frame_timeout = LE_16(3);
3319 		} else {
3320 			tx->timeout.pm_frame_timeout = LE_16(2);
3321 		}
3322 
3323 	} else {
3324 		/*
3325 		 * do it here for the software way rate scaling.
3326 		 * later for rate scaling in hardware.
3327 		 *
3328 		 * now the txrate is determined in tx cmd flags, set to the
3329 		 * max value 54M for 11g and 11M for 11b and 96M for 11n
3330 		 * originally.
3331 		 */
3332 		if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE) {
3333 			rate = ic->ic_fixed_rate;
3334 		} else {
3335 			if ((in->in_flags & IEEE80211_NODE_HT) &&
3336 			    (sc->sc_ht_conf.ht_support)) {
3337 				iwh_amrr_t *amrr = (iwh_amrr_t *)in;
3338 				rate = amrr->ht_mcs_idx;
3339 			} else {
3340 				if ((in->in_rates.ir_rates[in->in_txrate] &
3341 				    IEEE80211_RATE_VAL) != 0) {
3342 					rate = in->in_rates.
3343 					    ir_rates[in->in_txrate] &
3344 					    IEEE80211_RATE_VAL;
3345 				}
3346 			}
3347 		}
3348 
3349 		if (tid != WME_TID_INVALID) {
3350 			tx->tid_tspec = (uint8_t)tid;
3351 			tx->tx_flags &= LE_32(~TX_CMD_FLG_SEQ_CTL_MSK);
3352 		} else {
3353 			tx->tx_flags |= LE_32(TX_CMD_FLG_SEQ_CTL_MSK);
3354 		}
3355 
3356 		tx->timeout.pm_frame_timeout = 0;
3357 	}
3358 
3359 	IWH_DBG((IWH_DEBUG_TX, "iwh_send(): "
3360 	    "tx rate[%d of %d] = %x",
3361 	    in->in_txrate, in->in_rates.ir_nrates, rate));
3362 
3363 	len0 = roundup(4 + sizeof (iwh_tx_cmd_t) + hdrlen, 4);
3364 	if (len0 != (4 + sizeof (iwh_tx_cmd_t) + hdrlen)) {
3365 		tx->tx_flags |= LE_32(TX_CMD_FLG_MH_PAD_MSK);
3366 	}
3367 
3368 	/*
3369 	 * retrieve destination node's id
3370 	 */
3371 	if (IEEE80211_IS_MULTICAST(wh->i_addr1)) {
3372 		tx->sta_id = IWH_BROADCAST_ID;
3373 	} else {
3374 		tx->sta_id = IWH_AP_ID;
3375 	}
3376 
3377 	if ((in->in_flags & IEEE80211_NODE_HT) &&
3378 	    (sc->sc_ht_conf.ht_support) &&
3379 	    ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
3380 	    IEEE80211_FC0_TYPE_DATA)) {
3381 		if (rate >= HT_2CHAIN_RATE_MIN_IDX) {
3382 			rate |= LE_32(RATE_MCS_ANT_AB_MSK);
3383 		} else {
3384 			rate |= LE_32(RATE_MCS_ANT_B_MSK);
3385 		}
3386 
3387 		rate |= LE_32((1 << RATE_MCS_HT_POS));
3388 
3389 		tx->rate.r.rate_n_flags = rate;
3390 
3391 	} else {
3392 		if (2 == rate || 4 == rate || 11 == rate || 22 == rate) {
3393 			masks |= RATE_MCS_CCK_MSK;
3394 		}
3395 
3396 		masks |= RATE_MCS_ANT_B_MSK;
3397 		tx->rate.r.rate_n_flags = LE_32(iwh_rate_to_plcp(rate) | masks);
3398 	}
3399 
3400 	IWH_DBG((IWH_DEBUG_TX, "iwh_send(): "
3401 	    "tx flag = %x",
3402 	    tx->tx_flags));
3403 
3404 	tx->stop_time.life_time  = LE_32(0xffffffff);
3405 
3406 	tx->len = LE_16(len);
3407 
3408 	tx->dram_lsb_ptr =
3409 	    LE_32(data->paddr_cmd + 4 + offsetof(iwh_tx_cmd_t, scratch));
3410 	tx->dram_msb_ptr = 0;
3411 	tx->driver_txop = 0;
3412 	tx->next_frame_len = 0;
3413 
3414 	bcopy(m->b_rptr, tx + 1, hdrlen);
3415 	m->b_rptr += hdrlen;
3416 	bcopy(m->b_rptr, data->dma_data.mem_va, (len - hdrlen));
3417 
3418 	IWH_DBG((IWH_DEBUG_TX, "iwh_send(): "
3419 	    "sending data: qid=%d idx=%d len=%d",
3420 	    ring->qid, ring->cur, len));
3421 
3422 	/*
3423 	 * first segment includes the tx cmd plus the 802.11 header,
3424 	 * the second includes the remaining of the 802.11 frame.
3425 	 */
3426 
3427 	mutex_enter(&sc->sc_tx_lock);
3428 	cmd->hdr.idx = ring->desc_cur;
3429 	desc_data = &ring->data[ring->desc_cur];
3430 	desc = desc_data->desc;
3431 	bzero(desc, sizeof (*desc));
3432 	desc->val0 = 2 << 24;
3433 	desc->pa[0].tb1_addr = data->paddr_cmd;
3434 	desc->pa[0].val1 = ((len0 << 4) & 0xfff0) |
3435 	    ((data->dma_data.cookie.dmac_address & 0xffff) << 16);
3436 	desc->pa[0].val2 =
3437 	    ((data->dma_data.cookie.dmac_address & 0xffff0000) >> 16) |
3438 	    ((len - hdrlen) << 20);
3439 	IWH_DBG((IWH_DEBUG_TX, "iwh_send(): "
3440 	    "phy addr1 = 0x%x phy addr2 = 0x%x "
3441 	    "len1 = 0x%x, len2 = 0x%x val1 = 0x%x val2 = 0x%x",
3442 	    data->paddr_cmd, data->dma_data.cookie.dmac_address,
3443 	    len0, len - hdrlen, desc->pa[0].val1, desc->pa[0].val2));
3444 
3445 	/*
3446 	 * kick ring
3447 	 */
3448 	s_id = tx->sta_id;
3449 
3450 	sc->sc_shared->queues_byte_cnt_tbls[ring->qid].
3451 	    tfd_offset[ring->desc_cur].val =
3452 	    (8 + len) | (s_id << 12);
3453 	if (ring->desc_cur < IWH_MAX_WIN_SIZE) {
3454 		sc->sc_shared->queues_byte_cnt_tbls[ring->qid].
3455 		    tfd_offset[IWH_QUEUE_SIZE + ring->desc_cur].val =
3456 		    (8 + len) | (s_id << 12);
3457 	}
3458 
3459 	IWH_DMA_SYNC(data->dma_data, DDI_DMA_SYNC_FORDEV);
3460 	IWH_DMA_SYNC(ring->dma_desc, DDI_DMA_SYNC_FORDEV);
3461 
3462 	ring->desc_cur = (ring->desc_cur + 1) % ring->count;
3463 	IWH_WRITE(sc, HBUS_TARG_WRPTR, ring->qid << 8 | ring->desc_cur);
3464 
3465 	mutex_exit(&sc->sc_tx_lock);
3466 	freemsg(m);
3467 
3468 	/*
3469 	 * release node reference
3470 	 */
3471 	ieee80211_free_node(in);
3472 
3473 	ic->ic_stats.is_tx_bytes += len;
3474 	ic->ic_stats.is_tx_frags++;
3475 
3476 	mutex_enter(&sc->sc_mt_lock);
3477 	if (0 == sc->sc_tx_timer) {
3478 		sc->sc_tx_timer = 4;
3479 	}
3480 	mutex_exit(&sc->sc_mt_lock);
3481 
3482 exit:
3483 	return (err);
3484 }
3485 
3486 /*
3487  * invoked by GLD to deal with IOCTL affaires
3488  */
3489 static void
3490 iwh_m_ioctl(void* arg, queue_t *wq, mblk_t *mp)
3491 {
3492 	iwh_sc_t *sc;
3493 	ieee80211com_t *ic;
3494 	int err = EINVAL;
3495 
3496 	if (NULL == arg) {
3497 		return;
3498 	}
3499 	sc = (iwh_sc_t *)arg;
3500 	ic = &sc->sc_ic;
3501 
3502 	err = ieee80211_ioctl(ic, wq, mp);
3503 	if (ENETRESET == err) {
3504 		/*
3505 		 * This is special for the hidden AP connection.
3506 		 * In any case, we should make sure only one 'scan'
3507 		 * in the driver for a 'connect' CLI command. So
3508 		 * when connecting to a hidden AP, the scan is just
3509 		 * sent out to the air when we know the desired
3510 		 * essid of the AP we want to connect.
3511 		 */
3512 		if (ic->ic_des_esslen) {
3513 			if (sc->sc_flags & IWH_F_RUNNING) {
3514 				iwh_m_stop(sc);
3515 				(void) iwh_m_start(sc);
3516 				(void) ieee80211_new_state(ic,
3517 				    IEEE80211_S_SCAN, -1);
3518 			}
3519 		}
3520 	}
3521 }
3522 
3523 /*
3524  * Call back functions for get/set proporty
3525  */
3526 static int
3527 iwh_m_getprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
3528     uint_t pr_flags, uint_t wldp_length, void *wldp_buf, uint_t *perm)
3529 {
3530 	iwh_sc_t *sc;
3531 	int err = EINVAL;
3532 
3533 	if (NULL == arg) {
3534 		return (EINVAL);
3535 	}
3536 	sc = (iwh_sc_t *)arg;
3537 
3538 	err = ieee80211_getprop(&sc->sc_ic, pr_name, wldp_pr_num,
3539 	    pr_flags, wldp_length, wldp_buf, perm);
3540 
3541 	return (err);
3542 }
3543 
3544 static int
3545 iwh_m_setprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
3546     uint_t wldp_length, const void *wldp_buf)
3547 {
3548 	iwh_sc_t *sc;
3549 	ieee80211com_t *ic;
3550 	int err = EINVAL;
3551 
3552 	if (NULL == arg) {
3553 		return (EINVAL);
3554 	}
3555 	sc = (iwh_sc_t *)arg;
3556 	ic = &sc->sc_ic;
3557 
3558 	err = ieee80211_setprop(ic, pr_name, wldp_pr_num, wldp_length,
3559 	    wldp_buf);
3560 
3561 	if (err == ENETRESET) {
3562 		if (ic->ic_des_esslen) {
3563 			if (sc->sc_flags & IWH_F_RUNNING) {
3564 				iwh_m_stop(sc);
3565 				(void) iwh_m_start(sc);
3566 				(void) ieee80211_new_state(ic,
3567 				    IEEE80211_S_SCAN, -1);
3568 			}
3569 		}
3570 		err = 0;
3571 	}
3572 	return (err);
3573 }
3574 
3575 /*
3576  * invoked by GLD supply statistics NIC and driver
3577  */
3578 static int
3579 iwh_m_stat(void *arg, uint_t stat, uint64_t *val)
3580 {
3581 	iwh_sc_t *sc;
3582 	ieee80211com_t *ic;
3583 	ieee80211_node_t *in;
3584 
3585 	if (NULL == arg) {
3586 		return (EINVAL);
3587 	}
3588 	sc = (iwh_sc_t *)arg;
3589 	ic = &sc->sc_ic;
3590 
3591 	mutex_enter(&sc->sc_glock);
3592 
3593 	switch (stat) {
3594 	case MAC_STAT_IFSPEED:
3595 		in = ic->ic_bss;
3596 		*val = ((IEEE80211_FIXED_RATE_NONE == ic->ic_fixed_rate) ?
3597 		    IEEE80211_RATE(in->in_txrate) :
3598 		    ic->ic_fixed_rate) / 2 * 1000000;
3599 		break;
3600 
3601 	case MAC_STAT_NOXMTBUF:
3602 		*val = sc->sc_tx_nobuf;
3603 		break;
3604 
3605 	case MAC_STAT_NORCVBUF:
3606 		*val = sc->sc_rx_nobuf;
3607 		break;
3608 
3609 	case MAC_STAT_IERRORS:
3610 		*val = sc->sc_rx_err;
3611 		break;
3612 
3613 	case MAC_STAT_RBYTES:
3614 		*val = ic->ic_stats.is_rx_bytes;
3615 		break;
3616 
3617 	case MAC_STAT_IPACKETS:
3618 		*val = ic->ic_stats.is_rx_frags;
3619 		break;
3620 
3621 	case MAC_STAT_OBYTES:
3622 		*val = ic->ic_stats.is_tx_bytes;
3623 		break;
3624 
3625 	case MAC_STAT_OPACKETS:
3626 		*val = ic->ic_stats.is_tx_frags;
3627 		break;
3628 
3629 	case MAC_STAT_OERRORS:
3630 	case WIFI_STAT_TX_FAILED:
3631 		*val = sc->sc_tx_err;
3632 		break;
3633 
3634 	case WIFI_STAT_TX_RETRANS:
3635 		*val = sc->sc_tx_retries;
3636 		break;
3637 
3638 	case WIFI_STAT_FCS_ERRORS:
3639 	case WIFI_STAT_WEP_ERRORS:
3640 	case WIFI_STAT_TX_FRAGS:
3641 	case WIFI_STAT_MCAST_TX:
3642 	case WIFI_STAT_RTS_SUCCESS:
3643 	case WIFI_STAT_RTS_FAILURE:
3644 	case WIFI_STAT_ACK_FAILURE:
3645 	case WIFI_STAT_RX_FRAGS:
3646 	case WIFI_STAT_MCAST_RX:
3647 	case WIFI_STAT_RX_DUPS:
3648 		mutex_exit(&sc->sc_glock);
3649 		return (ieee80211_stat(ic, stat, val));
3650 
3651 	default:
3652 		mutex_exit(&sc->sc_glock);
3653 		return (ENOTSUP);
3654 	}
3655 
3656 	mutex_exit(&sc->sc_glock);
3657 
3658 	return (IWH_SUCCESS);
3659 }
3660 
3661 /*
3662  * invoked by GLD to start or open NIC
3663  */
3664 static int
3665 iwh_m_start(void *arg)
3666 {
3667 	iwh_sc_t *sc;
3668 	ieee80211com_t *ic;
3669 	int err = IWH_FAIL;
3670 
3671 	if (NULL == arg) {
3672 		return (EINVAL);
3673 	}
3674 	sc = (iwh_sc_t *)arg;
3675 	ic = &sc->sc_ic;
3676 
3677 	err = iwh_init(sc);
3678 	if (err != IWH_SUCCESS) {
3679 		/*
3680 		 * The hw init err(eg. RF is OFF). Return Success to make
3681 		 * the 'plumb' succeed. The iwh_thread() tries to re-init
3682 		 * background.
3683 		 */
3684 		atomic_or_32(&sc->sc_flags, IWH_F_HW_ERR_RECOVER);
3685 		return (IWH_SUCCESS);
3686 	}
3687 
3688 	ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
3689 
3690 	atomic_or_32(&sc->sc_flags, IWH_F_RUNNING);
3691 
3692 	return (IWH_SUCCESS);
3693 }
3694 
3695 /*
3696  * invoked by GLD to stop or down NIC
3697  */
3698 static void
3699 iwh_m_stop(void *arg)
3700 {
3701 	iwh_sc_t *sc;
3702 	ieee80211com_t *ic;
3703 
3704 	if (NULL == arg) {
3705 		return;
3706 	}
3707 	sc = (iwh_sc_t *)arg;
3708 	ic = &sc->sc_ic;
3709 
3710 	iwh_stop(sc);
3711 
3712 	/*
3713 	 * release buffer for calibration
3714 	 */
3715 	iwh_release_calib_buffer(sc);
3716 
3717 	ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
3718 
3719 	atomic_and_32(&sc->sc_flags, ~IWH_F_HW_ERR_RECOVER);
3720 	atomic_and_32(&sc->sc_flags, ~IWH_F_RATE_AUTO_CTL);
3721 
3722 	atomic_and_32(&sc->sc_flags, ~IWH_F_RUNNING);
3723 	atomic_and_32(&sc->sc_flags, ~IWH_F_SCANNING);
3724 }
3725 
3726 /*
3727  * invoked by GLD to configure NIC
3728  */
3729 static int
3730 iwh_m_unicst(void *arg, const uint8_t *macaddr)
3731 {
3732 	iwh_sc_t *sc;
3733 	ieee80211com_t *ic;
3734 	int err = IWH_SUCCESS;
3735 
3736 	if (NULL == arg) {
3737 		return (EINVAL);
3738 	}
3739 	sc = (iwh_sc_t *)arg;
3740 	ic = &sc->sc_ic;
3741 
3742 	if (!IEEE80211_ADDR_EQ(ic->ic_macaddr, macaddr)) {
3743 		IEEE80211_ADDR_COPY(ic->ic_macaddr, macaddr);
3744 		mutex_enter(&sc->sc_glock);
3745 		err = iwh_config(sc);
3746 		mutex_exit(&sc->sc_glock);
3747 		if (err != IWH_SUCCESS) {
3748 			cmn_err(CE_WARN, "iwh_m_unicst(): "
3749 			    "failed to configure device\n");
3750 			goto fail;
3751 		}
3752 	}
3753 
3754 fail:
3755 	return (err);
3756 }
3757 
3758 /* ARGSUSED */
3759 static int
3760 iwh_m_multicst(void *arg, boolean_t add, const uint8_t *m)
3761 {
3762 	return (IWH_SUCCESS);
3763 }
3764 
3765 /* ARGSUSED */
3766 static int
3767 iwh_m_promisc(void *arg, boolean_t on)
3768 {
3769 	return (IWH_SUCCESS);
3770 }
3771 
3772 /*
3773  * kernel thread to deal with exceptional situation
3774  */
3775 static void
3776 iwh_thread(iwh_sc_t *sc)
3777 {
3778 	ieee80211com_t *ic = &sc->sc_ic;
3779 	clock_t clk;
3780 	int err, n = 0, timeout = 0;
3781 	uint32_t tmp;
3782 #ifdef	DEBUG
3783 	int times = 0;
3784 #endif
3785 
3786 	while (sc->sc_mf_thread_switch) {
3787 		tmp = IWH_READ(sc, CSR_GP_CNTRL);
3788 		if (tmp & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) {
3789 			atomic_and_32(&sc->sc_flags, ~IWH_F_RADIO_OFF);
3790 		} else {
3791 			atomic_or_32(&sc->sc_flags, IWH_F_RADIO_OFF);
3792 		}
3793 
3794 		/*
3795 		 * If  in SUSPEND or the RF is OFF, do nothing.
3796 		 */
3797 		if (sc->sc_flags & IWH_F_RADIO_OFF) {
3798 			delay(drv_usectohz(100000));
3799 			continue;
3800 		}
3801 
3802 		/*
3803 		 * recovery fatal error
3804 		 */
3805 		if (ic->ic_mach &&
3806 		    (sc->sc_flags & IWH_F_HW_ERR_RECOVER)) {
3807 
3808 			IWH_DBG((IWH_DEBUG_FW, "iwh_thread(): "
3809 			    "try to recover fatal hw error: %d\n", times++));
3810 
3811 			iwh_stop(sc);
3812 
3813 			if (IWH_CHK_FAST_RECOVER(sc)) {
3814 				/*
3815 				 * save runtime configuration
3816 				 */
3817 				bcopy(&sc->sc_config, &sc->sc_config_save,
3818 				    sizeof (sc->sc_config));
3819 			} else {
3820 				ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
3821 				delay(drv_usectohz(2000000 + n*500000));
3822 			}
3823 
3824 			err = iwh_init(sc);
3825 			if (err != IWH_SUCCESS) {
3826 				n++;
3827 				if (n < 20) {
3828 					continue;
3829 				}
3830 			}
3831 
3832 			n = 0;
3833 			if (!err) {
3834 				atomic_or_32(&sc->sc_flags, IWH_F_RUNNING);
3835 			}
3836 
3837 
3838 			if (!IWH_CHK_FAST_RECOVER(sc) ||
3839 			    iwh_fast_recover(sc) != IWH_SUCCESS) {
3840 				atomic_and_32(&sc->sc_flags,
3841 				    ~IWH_F_HW_ERR_RECOVER);
3842 
3843 				delay(drv_usectohz(2000000));
3844 				if (sc->sc_ostate != IEEE80211_S_INIT) {
3845 					ieee80211_new_state(ic,
3846 					    IEEE80211_S_SCAN, 0);
3847 				}
3848 			}
3849 		}
3850 
3851 		if (ic->ic_mach &&
3852 		    (sc->sc_flags & IWH_F_SCANNING) && sc->sc_scan_pending) {
3853 			IWH_DBG((IWH_DEBUG_SCAN, "iwh_thread(): "
3854 			    "wait for probe response\n"));
3855 
3856 			sc->sc_scan_pending--;
3857 			delay(drv_usectohz(200000));
3858 			ieee80211_next_scan(ic);
3859 		}
3860 
3861 		/*
3862 		 * rate ctl
3863 		 */
3864 		if (ic->ic_mach &&
3865 		    (sc->sc_flags & IWH_F_RATE_AUTO_CTL)) {
3866 			clk = ddi_get_lbolt();
3867 			if (clk > sc->sc_clk + drv_usectohz(1000000)) {
3868 				iwh_amrr_timeout(sc);
3869 			}
3870 		}
3871 
3872 		delay(drv_usectohz(100000));
3873 
3874 		mutex_enter(&sc->sc_mt_lock);
3875 		if (sc->sc_tx_timer) {
3876 			timeout++;
3877 			if (10 == timeout) {
3878 				sc->sc_tx_timer--;
3879 				if (0 == sc->sc_tx_timer) {
3880 					atomic_or_32(&sc->sc_flags,
3881 					    IWH_F_HW_ERR_RECOVER);
3882 					sc->sc_ostate = IEEE80211_S_RUN;
3883 					IWH_DBG((IWH_DEBUG_FW, "iwh_thread(): "
3884 					    "try to recover from "
3885 					    "send fail\n"));
3886 				}
3887 				timeout = 0;
3888 			}
3889 		}
3890 		mutex_exit(&sc->sc_mt_lock);
3891 	}
3892 
3893 	mutex_enter(&sc->sc_mt_lock);
3894 	sc->sc_mf_thread = NULL;
3895 	cv_signal(&sc->sc_mt_cv);
3896 	mutex_exit(&sc->sc_mt_lock);
3897 }
3898 
3899 /*
3900  * Send a command to the ucode.
3901  */
3902 static int
3903 iwh_cmd(iwh_sc_t *sc, int code, const void *buf, int size, int async)
3904 {
3905 	iwh_tx_ring_t *ring = &sc->sc_txq[IWH_CMD_QUEUE_NUM];
3906 	iwh_tx_desc_t *desc;
3907 	iwh_cmd_t *cmd;
3908 
3909 	ASSERT(size <= sizeof (cmd->data));
3910 	ASSERT(mutex_owned(&sc->sc_glock));
3911 
3912 	IWH_DBG((IWH_DEBUG_CMD, "iwh_cmd() "
3913 	    "code[%d]", code));
3914 	desc = ring->data[ring->cur].desc;
3915 	cmd = ring->data[ring->cur].cmd;
3916 
3917 	cmd->hdr.type = (uint8_t)code;
3918 	cmd->hdr.flags = 0;
3919 	cmd->hdr.qid = ring->qid;
3920 	cmd->hdr.idx = ring->cur;
3921 	bcopy(buf, cmd->data, size);
3922 	(void) memset(desc, 0, sizeof (*desc));
3923 
3924 	desc->val0 = 1 << 24;
3925 	desc->pa[0].tb1_addr =
3926 	    (uint32_t)(ring->data[ring->cur].paddr_cmd & 0xffffffff);
3927 	desc->pa[0].val1 = ((4 + size) << 4) & 0xfff0;
3928 
3929 	if (async) {
3930 		sc->sc_cmd_accum++;
3931 	}
3932 
3933 	/*
3934 	 * kick cmd ring XXX
3935 	 */
3936 	sc->sc_shared->queues_byte_cnt_tbls[ring->qid].
3937 	    tfd_offset[ring->cur].val = 8;
3938 	if (ring->cur < IWH_MAX_WIN_SIZE) {
3939 		sc->sc_shared->queues_byte_cnt_tbls[ring->qid].
3940 		    tfd_offset[IWH_QUEUE_SIZE + ring->cur].val = 8;
3941 	}
3942 	ring->cur = (ring->cur + 1) % ring->count;
3943 	IWH_WRITE(sc, HBUS_TARG_WRPTR, ring->qid << 8 | ring->cur);
3944 
3945 	if (async) {
3946 		return (IWH_SUCCESS);
3947 	} else {
3948 		clock_t clk;
3949 
3950 		clk = ddi_get_lbolt() + drv_usectohz(2000000);
3951 		while (sc->sc_cmd_flag != SC_CMD_FLG_DONE) {
3952 			if (cv_timedwait(&sc->sc_cmd_cv,
3953 			    &sc->sc_glock, clk) < 0) {
3954 				break;
3955 			}
3956 		}
3957 
3958 		if (SC_CMD_FLG_DONE == sc->sc_cmd_flag) {
3959 			sc->sc_cmd_flag = SC_CMD_FLG_NONE;
3960 			return (IWH_SUCCESS);
3961 		} else {
3962 			sc->sc_cmd_flag = SC_CMD_FLG_NONE;
3963 			return (IWH_FAIL);
3964 		}
3965 	}
3966 }
3967 
3968 /*
3969  * require ucode seting led of NIC
3970  */
3971 static void
3972 iwh_set_led(iwh_sc_t *sc, uint8_t id, uint8_t off, uint8_t on)
3973 {
3974 	iwh_led_cmd_t led;
3975 
3976 	led.interval = LE_32(100000);	/* unit: 100ms */
3977 	led.id = id;
3978 	led.off = off;
3979 	led.on = on;
3980 
3981 	(void) iwh_cmd(sc, REPLY_LEDS_CMD, &led, sizeof (led), 1);
3982 }
3983 
3984 /*
3985  * necessary setting to NIC before authentication
3986  */
3987 static int
3988 iwh_hw_set_before_auth(iwh_sc_t *sc)
3989 {
3990 	ieee80211com_t *ic = &sc->sc_ic;
3991 	ieee80211_node_t *in = ic->ic_bss;
3992 	int err = IWH_FAIL;
3993 
3994 	/*
3995 	 * update adapter's configuration according
3996 	 * the info of target AP
3997 	 */
3998 	IEEE80211_ADDR_COPY(sc->sc_config.bssid, in->in_bssid);
3999 	sc->sc_config.chan = LE_16(ieee80211_chan2ieee(ic, in->in_chan));
4000 
4001 	if (ic->ic_curmode != IEEE80211_MODE_11NG) {
4002 
4003 		sc->sc_config.ofdm_ht_triple_stream_basic_rates = 0;
4004 		sc->sc_config.ofdm_ht_dual_stream_basic_rates = 0;
4005 		sc->sc_config.ofdm_ht_single_stream_basic_rates = 0;
4006 
4007 		if (IEEE80211_MODE_11B == ic->ic_curmode) {
4008 			sc->sc_config.cck_basic_rates  = 0x03;
4009 			sc->sc_config.ofdm_basic_rates = 0;
4010 		} else if ((in->in_chan != IEEE80211_CHAN_ANYC) &&
4011 		    (IEEE80211_IS_CHAN_5GHZ(in->in_chan))) {
4012 			sc->sc_config.cck_basic_rates  = 0;
4013 			sc->sc_config.ofdm_basic_rates = 0x15;
4014 		} else { /* assume 802.11b/g */
4015 			sc->sc_config.cck_basic_rates  = 0x0f;
4016 			sc->sc_config.ofdm_basic_rates = 0xff;
4017 		}
4018 	}
4019 
4020 	sc->sc_config.flags &= ~LE_32(RXON_FLG_SHORT_PREAMBLE_MSK |
4021 	    RXON_FLG_SHORT_SLOT_MSK);
4022 
4023 	if (ic->ic_flags & IEEE80211_F_SHSLOT) {
4024 		sc->sc_config.flags |= LE_32(RXON_FLG_SHORT_SLOT_MSK);
4025 	} else {
4026 		sc->sc_config.flags &= LE_32(~RXON_FLG_SHORT_SLOT_MSK);
4027 	}
4028 
4029 	if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) {
4030 		sc->sc_config.flags |= LE_32(RXON_FLG_SHORT_PREAMBLE_MSK);
4031 	} else {
4032 		sc->sc_config.flags &= LE_32(~RXON_FLG_SHORT_PREAMBLE_MSK);
4033 	}
4034 
4035 	IWH_DBG((IWH_DEBUG_80211, "iwh_hw_set_before_auth(): "
4036 	    "config chan %d flags %x "
4037 	    "filter_flags %x  cck %x ofdm %x"
4038 	    " bssid:%02x:%02x:%02x:%02x:%02x:%2x\n",
4039 	    LE_16(sc->sc_config.chan), LE_32(sc->sc_config.flags),
4040 	    LE_32(sc->sc_config.filter_flags),
4041 	    sc->sc_config.cck_basic_rates, sc->sc_config.ofdm_basic_rates,
4042 	    sc->sc_config.bssid[0], sc->sc_config.bssid[1],
4043 	    sc->sc_config.bssid[2], sc->sc_config.bssid[3],
4044 	    sc->sc_config.bssid[4], sc->sc_config.bssid[5]));
4045 
4046 	err = iwh_cmd(sc, REPLY_RXON, &sc->sc_config,
4047 	    sizeof (iwh_rxon_cmd_t), 1);
4048 	if (err != IWH_SUCCESS) {
4049 		cmn_err(CE_WARN, "iwh_hw_set_before_auth(): "
4050 		    "failed to config chan%d\n", sc->sc_config.chan);
4051 		return (err);
4052 	}
4053 
4054 	if ((sc->sc_dev_id != 0x423c) &&
4055 	    (sc->sc_dev_id != 0x423d)) {
4056 		err = iwh_tx_power_table(sc, 1);
4057 		if (err != IWH_SUCCESS) {
4058 			return (err);
4059 		}
4060 	}
4061 
4062 	/*
4063 	 * add default AP node
4064 	 */
4065 	err = iwh_add_ap_sta(sc);
4066 	if (err != IWH_SUCCESS) {
4067 		return (err);
4068 	}
4069 
4070 	if ((sc->sc_dev_id != 0x423c) &&
4071 	    (sc->sc_dev_id != 0x423d)) {
4072 		/*
4073 		 * set up retry rate table for AP node
4074 		 */
4075 		err = iwh_ap_lq(sc);
4076 		if (err != IWH_SUCCESS) {
4077 			return (err);
4078 		}
4079 	}
4080 
4081 	return (err);
4082 }
4083 
4084 /*
4085  * Send a scan request(assembly scan cmd) to the firmware.
4086  */
4087 static int
4088 iwh_scan(iwh_sc_t *sc)
4089 {
4090 	ieee80211com_t *ic = &sc->sc_ic;
4091 	iwh_tx_ring_t *ring = &sc->sc_txq[IWH_CMD_QUEUE_NUM];
4092 	iwh_tx_desc_t *desc;
4093 	iwh_tx_data_t *data;
4094 	iwh_cmd_t *cmd;
4095 	iwh_scan_hdr_t *hdr;
4096 	iwh_scan_chan_t chan;
4097 	struct ieee80211_frame *wh;
4098 	ieee80211_node_t *in = ic->ic_bss;
4099 	uint8_t essid[IEEE80211_NWID_LEN+1];
4100 	struct ieee80211_rateset *rs;
4101 	enum ieee80211_phymode mode;
4102 	uint8_t *frm;
4103 	int i, pktlen, nrates;
4104 
4105 	data = &ring->data[ring->cur];
4106 	desc = data->desc;
4107 	cmd = (iwh_cmd_t *)data->dma_data.mem_va;
4108 
4109 	cmd->hdr.type = REPLY_SCAN_CMD;
4110 	cmd->hdr.flags = 0;
4111 	cmd->hdr.qid = ring->qid;
4112 	cmd->hdr.idx = ring->cur | 0x40;
4113 
4114 	hdr = (iwh_scan_hdr_t *)cmd->data;
4115 	(void) memset(hdr, 0, sizeof (iwh_scan_hdr_t));
4116 	hdr->nchan = 1;
4117 	hdr->quiet_time = LE_16(50);
4118 	hdr->quiet_plcp_th = LE_16(1);
4119 
4120 	hdr->flags = LE_32(RXON_FLG_BAND_24G_MSK);
4121 	hdr->rx_chain = LE_16(RXON_RX_CHAIN_DRIVER_FORCE_MSK |
4122 	    (0x7 << RXON_RX_CHAIN_VALID_POS) |
4123 	    (0x2 << RXON_RX_CHAIN_FORCE_SEL_POS) |
4124 	    (0x2 << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS));
4125 
4126 	hdr->tx_cmd.tx_flags = LE_32(TX_CMD_FLG_SEQ_CTL_MSK);
4127 	hdr->tx_cmd.sta_id = IWH_BROADCAST_ID;
4128 	hdr->tx_cmd.stop_time.life_time = LE_32(0xffffffff);
4129 	hdr->tx_cmd.rate.r.rate_n_flags = LE_32(iwh_rate_to_plcp(2));
4130 	hdr->tx_cmd.rate.r.rate_n_flags |=
4131 	    LE_32(RATE_MCS_ANT_B_MSK |RATE_MCS_CCK_MSK);
4132 	hdr->direct_scan[0].len = ic->ic_des_esslen;
4133 	hdr->direct_scan[0].id  = IEEE80211_ELEMID_SSID;
4134 
4135 	hdr->filter_flags = LE_32(RXON_FILTER_ACCEPT_GRP_MSK |
4136 	    RXON_FILTER_BCON_AWARE_MSK);
4137 
4138 	if (ic->ic_des_esslen) {
4139 		bcopy(ic->ic_des_essid, essid, ic->ic_des_esslen);
4140 		essid[ic->ic_des_esslen] = '\0';
4141 		IWH_DBG((IWH_DEBUG_SCAN, "iwh_scan(): "
4142 		    "directed scan %s\n", essid));
4143 
4144 		bcopy(ic->ic_des_essid, hdr->direct_scan[0].ssid,
4145 		    ic->ic_des_esslen);
4146 	} else {
4147 		bzero(hdr->direct_scan[0].ssid,
4148 		    sizeof (hdr->direct_scan[0].ssid));
4149 	}
4150 
4151 	/*
4152 	 * a probe request frame is required after the REPLY_SCAN_CMD
4153 	 */
4154 	wh = (struct ieee80211_frame *)(hdr + 1);
4155 	wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT |
4156 	    IEEE80211_FC0_SUBTYPE_PROBE_REQ;
4157 	wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
4158 	(void) memset(wh->i_addr1, 0xff, 6);
4159 	IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_macaddr);
4160 	(void) memset(wh->i_addr3, 0xff, 6);
4161 	*(uint16_t *)&wh->i_dur[0] = 0;
4162 	*(uint16_t *)&wh->i_seq[0] = 0;
4163 
4164 	frm = (uint8_t *)(wh + 1);
4165 
4166 	/*
4167 	 * essid IE
4168 	 */
4169 	if (in->in_esslen) {
4170 		bcopy(in->in_essid, essid, in->in_esslen);
4171 		essid[in->in_esslen] = '\0';
4172 		IWH_DBG((IWH_DEBUG_SCAN, "iwh_scan(): "
4173 		    "probe with ESSID %s\n",
4174 		    essid));
4175 	}
4176 	*frm++ = IEEE80211_ELEMID_SSID;
4177 	*frm++ = in->in_esslen;
4178 	bcopy(in->in_essid, frm, in->in_esslen);
4179 	frm += in->in_esslen;
4180 
4181 	mode = ieee80211_chan2mode(ic, ic->ic_curchan);
4182 	rs = &ic->ic_sup_rates[mode];
4183 
4184 	/*
4185 	 * supported rates IE
4186 	 */
4187 	*frm++ = IEEE80211_ELEMID_RATES;
4188 	nrates = rs->ir_nrates;
4189 	if (nrates > IEEE80211_RATE_SIZE) {
4190 		nrates = IEEE80211_RATE_SIZE;
4191 	}
4192 
4193 	*frm++ = (uint8_t)nrates;
4194 	bcopy(rs->ir_rates, frm, nrates);
4195 	frm += nrates;
4196 
4197 	/*
4198 	 * supported xrates IE
4199 	 */
4200 	if (rs->ir_nrates > IEEE80211_RATE_SIZE) {
4201 		nrates = rs->ir_nrates - IEEE80211_RATE_SIZE;
4202 		*frm++ = IEEE80211_ELEMID_XRATES;
4203 		*frm++ = (uint8_t)nrates;
4204 		bcopy(rs->ir_rates + IEEE80211_RATE_SIZE, frm, nrates);
4205 		frm += nrates;
4206 	}
4207 
4208 	/*
4209 	 * optionnal IE (usually for wpa)
4210 	 */
4211 	if (ic->ic_opt_ie != NULL) {
4212 		bcopy(ic->ic_opt_ie, frm, ic->ic_opt_ie_len);
4213 		frm += ic->ic_opt_ie_len;
4214 	}
4215 
4216 	/* setup length of probe request */
4217 	hdr->tx_cmd.len = LE_16(_PTRDIFF(frm, wh));
4218 	hdr->len = LE_16(hdr->nchan * sizeof (iwh_scan_chan_t) +
4219 	    LE_16(hdr->tx_cmd.len) + sizeof (iwh_scan_hdr_t));
4220 
4221 	/*
4222 	 * the attribute of the scan channels are required after the probe
4223 	 * request frame.
4224 	 */
4225 	for (i = 1; i <= hdr->nchan; i++) {
4226 		if (ic->ic_des_esslen) {
4227 			chan.type = LE_32(3);
4228 		} else {
4229 			chan.type = LE_32(1);
4230 		}
4231 
4232 		chan.chan = LE_16(ieee80211_chan2ieee(ic, ic->ic_curchan));
4233 		chan.tpc.tx_gain = 0x28;
4234 		chan.tpc.dsp_atten = 110;
4235 		chan.active_dwell = LE_16(50);
4236 		chan.passive_dwell = LE_16(120);
4237 
4238 		bcopy(&chan, frm, sizeof (iwh_scan_chan_t));
4239 		frm += sizeof (iwh_scan_chan_t);
4240 	}
4241 
4242 	pktlen = _PTRDIFF(frm, cmd);
4243 
4244 	(void) memset(desc, 0, sizeof (*desc));
4245 	desc->val0 = 1 << 24;
4246 	desc->pa[0].tb1_addr =
4247 	    (uint32_t)(data->dma_data.cookie.dmac_address & 0xffffffff);
4248 	desc->pa[0].val1 = (pktlen << 4) & 0xfff0;
4249 
4250 	/*
4251 	 * maybe for cmd, filling the byte cnt table is not necessary.
4252 	 * anyway, we fill it here.
4253 	 */
4254 	sc->sc_shared->queues_byte_cnt_tbls[ring->qid]
4255 	    .tfd_offset[ring->cur].val = 8;
4256 	if (ring->cur < IWH_MAX_WIN_SIZE) {
4257 		sc->sc_shared->queues_byte_cnt_tbls[ring->qid].
4258 		    tfd_offset[IWH_QUEUE_SIZE + ring->cur].val = 8;
4259 	}
4260 
4261 	/*
4262 	 * kick cmd ring
4263 	 */
4264 	ring->cur = (ring->cur + 1) % ring->count;
4265 	IWH_WRITE(sc, HBUS_TARG_WRPTR, ring->qid << 8 | ring->cur);
4266 
4267 	return (IWH_SUCCESS);
4268 }
4269 
4270 /*
4271  * configure NIC by using ucode commands after loading ucode.
4272  */
4273 static int
4274 iwh_config(iwh_sc_t *sc)
4275 {
4276 	ieee80211com_t *ic = &sc->sc_ic;
4277 	iwh_powertable_cmd_t powertable;
4278 	iwh_bt_cmd_t bt;
4279 	iwh_add_sta_t node;
4280 	iwh_rem_sta_t rm_sta;
4281 	const uint8_t bcast[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
4282 	iwh_link_quality_cmd_t link_quality;
4283 	int i, err = IWH_FAIL;
4284 	uint16_t masks = 0;
4285 
4286 	/*
4287 	 * set power mode. Disable power management at present, do it later
4288 	 */
4289 	(void) memset(&powertable, 0, sizeof (powertable));
4290 	powertable.flags = LE_16(0x8);
4291 	err = iwh_cmd(sc, POWER_TABLE_CMD, &powertable,
4292 	    sizeof (powertable), 0);
4293 	if (err != IWH_SUCCESS) {
4294 		cmn_err(CE_WARN, "iwh_config(): "
4295 		    "failed to set power mode\n");
4296 		return (err);
4297 	}
4298 
4299 	/*
4300 	 * configure bt coexistence
4301 	 */
4302 	(void) memset(&bt, 0, sizeof (bt));
4303 	bt.flags = 3;
4304 	bt.lead_time = 0xaa;
4305 	bt.max_kill = 1;
4306 	err = iwh_cmd(sc, REPLY_BT_CONFIG, &bt,
4307 	    sizeof (bt), 0);
4308 	if (err != IWH_SUCCESS) {
4309 		cmn_err(CE_WARN, "iwh_config(): "
4310 		    "failed to configurate bt coexistence\n");
4311 		return (err);
4312 	}
4313 
4314 	/*
4315 	 * configure rxon
4316 	 */
4317 	(void) memset(&sc->sc_config, 0, sizeof (iwh_rxon_cmd_t));
4318 	IEEE80211_ADDR_COPY(sc->sc_config.node_addr, ic->ic_macaddr);
4319 	IEEE80211_ADDR_COPY(sc->sc_config.wlap_bssid, ic->ic_macaddr);
4320 	sc->sc_config.chan = LE_16(ieee80211_chan2ieee(ic, ic->ic_curchan));
4321 	sc->sc_config.flags = LE_32(RXON_FLG_BAND_24G_MSK);
4322 	sc->sc_config.flags &= LE_32(~(RXON_FLG_CHANNEL_MODE_MIXED_MSK |
4323 	    RXON_FLG_CHANNEL_MODE_PURE_40_MSK));
4324 
4325 	switch (ic->ic_opmode) {
4326 	case IEEE80211_M_STA:
4327 		sc->sc_config.dev_type = RXON_DEV_TYPE_ESS;
4328 		sc->sc_config.filter_flags |= LE_32(RXON_FILTER_ACCEPT_GRP_MSK |
4329 		    RXON_FILTER_DIS_DECRYPT_MSK |
4330 		    RXON_FILTER_DIS_GRP_DECRYPT_MSK);
4331 		break;
4332 
4333 	case IEEE80211_M_IBSS:
4334 	case IEEE80211_M_AHDEMO:
4335 		sc->sc_config.dev_type = RXON_DEV_TYPE_IBSS;
4336 
4337 		sc->sc_config.flags |= LE_32(RXON_FLG_SHORT_PREAMBLE_MSK);
4338 		sc->sc_config.filter_flags = LE_32(RXON_FILTER_ACCEPT_GRP_MSK |
4339 		    RXON_FILTER_DIS_DECRYPT_MSK |
4340 		    RXON_FILTER_DIS_GRP_DECRYPT_MSK);
4341 		break;
4342 
4343 	case IEEE80211_M_HOSTAP:
4344 		sc->sc_config.dev_type = RXON_DEV_TYPE_AP;
4345 		break;
4346 
4347 	case IEEE80211_M_MONITOR:
4348 		sc->sc_config.dev_type = RXON_DEV_TYPE_SNIFFER;
4349 		sc->sc_config.filter_flags |= LE_32(RXON_FILTER_ACCEPT_GRP_MSK |
4350 		    RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_PROMISC_MSK);
4351 		break;
4352 	}
4353 
4354 	/*
4355 	 * Support all CCK rates.
4356 	 */
4357 	sc->sc_config.cck_basic_rates  = 0x0f;
4358 
4359 	/*
4360 	 * Support all OFDM rates.
4361 	 */
4362 	sc->sc_config.ofdm_basic_rates = 0xff;
4363 
4364 	/*
4365 	 * Determine HT supported rates.
4366 	 */
4367 	switch (sc->sc_ht_conf.rx_stream_count) {
4368 	case 3:
4369 		sc->sc_config.ofdm_ht_triple_stream_basic_rates = 0xff;
4370 		sc->sc_config.ofdm_ht_dual_stream_basic_rates = 0xff;
4371 		sc->sc_config.ofdm_ht_single_stream_basic_rates = 0xff;
4372 		break;
4373 	case 2:
4374 		sc->sc_config.ofdm_ht_dual_stream_basic_rates = 0xff;
4375 		sc->sc_config.ofdm_ht_single_stream_basic_rates = 0xff;
4376 		break;
4377 	case 1:
4378 		sc->sc_config.ofdm_ht_single_stream_basic_rates = 0xff;
4379 		break;
4380 	default:
4381 		cmn_err(CE_WARN, "iwh_config(): "
4382 		    "RX stream count %d is not in suitable range\n",
4383 		    sc->sc_ht_conf.rx_stream_count);
4384 		return (IWH_FAIL);
4385 	}
4386 
4387 	/*
4388 	 * set RX chains/antennas.
4389 	 */
4390 	iwh_config_rxon_chain(sc);
4391 
4392 	err = iwh_cmd(sc, REPLY_RXON, &sc->sc_config,
4393 	    sizeof (iwh_rxon_cmd_t), 0);
4394 	if (err != IWH_SUCCESS) {
4395 		cmn_err(CE_WARN, "iwh_config(): "
4396 		    "failed to set configure command\n");
4397 		return (err);
4398 	}
4399 
4400 	/*
4401 	 * remove all nodes in NIC
4402 	 */
4403 	(void) memset(&rm_sta, 0, sizeof (rm_sta));
4404 	rm_sta.num_sta = 1;
4405 	bcopy(bcast, rm_sta.addr, 6);
4406 
4407 	err = iwh_cmd(sc, REPLY_REMOVE_STA, &rm_sta, sizeof (iwh_rem_sta_t), 0);
4408 	if (err != IWH_SUCCESS) {
4409 		cmn_err(CE_WARN, "iwh_config(): "
4410 		    "failed to remove broadcast node in hardware.\n");
4411 		return (err);
4412 	}
4413 
4414 	if ((sc->sc_dev_id != 0x423c) &&
4415 	    (sc->sc_dev_id != 0x423d)) {
4416 		/*
4417 		 * configure TX power table
4418 		 */
4419 		err = iwh_tx_power_table(sc, 0);
4420 		if (err != IWH_SUCCESS) {
4421 			return (err);
4422 		}
4423 	}
4424 
4425 	/*
4426 	 * add broadcast node so that we can send broadcast frame
4427 	 */
4428 	(void) memset(&node, 0, sizeof (node));
4429 	(void) memset(node.sta.addr, 0xff, 6);
4430 	node.mode = 0;
4431 	node.sta.sta_id = IWH_BROADCAST_ID;
4432 	node.station_flags = 0;
4433 
4434 	err = iwh_cmd(sc, REPLY_ADD_STA, &node, sizeof (node), 0);
4435 	if (err != IWH_SUCCESS) {
4436 		cmn_err(CE_WARN, "iwh_config(): "
4437 		    "failed to add broadcast node\n");
4438 		return (err);
4439 	}
4440 
4441 	if ((sc->sc_dev_id != 0x423c) &&
4442 	    (sc->sc_dev_id != 0x423d)) {
4443 		/*
4444 		 * TX_LINK_QUALITY cmd
4445 		 */
4446 		(void) memset(&link_quality, 0, sizeof (link_quality));
4447 		for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) {
4448 			masks |= RATE_MCS_CCK_MSK;
4449 			masks |= RATE_MCS_ANT_B_MSK;
4450 			masks &= ~RATE_MCS_ANT_A_MSK;
4451 			link_quality.rate_n_flags[i] =
4452 			    LE_32(iwh_rate_to_plcp(2) | masks);
4453 		}
4454 
4455 		link_quality.general_params.single_stream_ant_msk = 2;
4456 		link_quality.general_params.dual_stream_ant_msk = 3;
4457 		link_quality.agg_params.agg_dis_start_th = 3;
4458 		link_quality.agg_params.agg_time_limit = LE_16(4000);
4459 		link_quality.sta_id = IWH_BROADCAST_ID;
4460 		err = iwh_cmd(sc, REPLY_TX_LINK_QUALITY_CMD, &link_quality,
4461 		    sizeof (link_quality), 0);
4462 		if (err != IWH_SUCCESS) {
4463 			cmn_err(CE_WARN, "iwh_config(): "
4464 			    "failed to config link quality table\n");
4465 			return (err);
4466 		}
4467 	}
4468 
4469 	return (err);
4470 }
4471 
4472 /*
4473  * quiesce(9E) entry point.
4474  * This function is called when the system is single-threaded at high
4475  * PIL with preemption disabled. Therefore, this function must not be
4476  * blocked.
4477  * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
4478  * DDI_FAILURE indicates an error condition and should almost never happen.
4479  */
4480 static int
4481 iwh_quiesce(dev_info_t *dip)
4482 {
4483 	iwh_sc_t *sc;
4484 
4485 	sc = ddi_get_soft_state(iwh_soft_state_p, ddi_get_instance(dip));
4486 	if (sc == NULL) {
4487 		return (DDI_FAILURE);
4488 	}
4489 
4490 #ifdef DEBUG
4491 	/*
4492 	 * by pass any messages, if it's quiesce
4493 	 */
4494 	iwh_dbg_flags = 0;
4495 #endif
4496 
4497 	/*
4498 	 * No more blocking is allowed while we are in the
4499 	 * quiesce(9E) entry point.
4500 	 */
4501 	atomic_or_32(&sc->sc_flags, IWH_F_QUIESCED);
4502 
4503 	/*
4504 	 * Disable and mask all interrupts.
4505 	 */
4506 	iwh_stop(sc);
4507 
4508 	return (DDI_SUCCESS);
4509 }
4510 
4511 static void
4512 iwh_stop_master(iwh_sc_t *sc)
4513 {
4514 	uint32_t tmp;
4515 	int n;
4516 
4517 	tmp = IWH_READ(sc, CSR_RESET);
4518 	IWH_WRITE(sc, CSR_RESET, tmp | CSR_RESET_REG_FLAG_STOP_MASTER);
4519 
4520 	tmp = IWH_READ(sc, CSR_GP_CNTRL);
4521 	if ((tmp & CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE) ==
4522 	    CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE) {
4523 		return;
4524 	}
4525 
4526 	for (n = 0; n < 2000; n++) {
4527 		if (IWH_READ(sc, CSR_RESET) &
4528 		    CSR_RESET_REG_FLAG_MASTER_DISABLED) {
4529 			break;
4530 		}
4531 		DELAY(1000);
4532 	}
4533 
4534 #ifdef	DEBUG
4535 	if (2000 == n) {
4536 		IWH_DBG((IWH_DEBUG_HW, "iwh_stop_master(): "
4537 		    "timeout waiting for master stop\n"));
4538 	}
4539 #endif
4540 }
4541 
4542 static int
4543 iwh_power_up(iwh_sc_t *sc)
4544 {
4545 	uint32_t tmp;
4546 
4547 	iwh_mac_access_enter(sc);
4548 	tmp = iwh_reg_read(sc, ALM_APMG_PS_CTL);
4549 	tmp &= ~APMG_PS_CTRL_REG_MSK_POWER_SRC;
4550 	tmp |= APMG_PS_CTRL_REG_VAL_POWER_SRC_VMAIN;
4551 	iwh_reg_write(sc, ALM_APMG_PS_CTL, tmp);
4552 	iwh_mac_access_exit(sc);
4553 
4554 	DELAY(5000);
4555 	return (IWH_SUCCESS);
4556 }
4557 
4558 /*
4559  * hardware initialization
4560  */
4561 static int
4562 iwh_preinit(iwh_sc_t *sc)
4563 {
4564 	int n;
4565 	uint8_t vlink;
4566 	uint16_t radio_cfg;
4567 	uint32_t tmp;
4568 
4569 	/*
4570 	 * clear any pending interrupts
4571 	 */
4572 	IWH_WRITE(sc, CSR_INT, 0xffffffff);
4573 
4574 	tmp = IWH_READ(sc, CSR_GIO_CHICKEN_BITS);
4575 	IWH_WRITE(sc, CSR_GIO_CHICKEN_BITS,
4576 	    tmp | CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
4577 
4578 	tmp = IWH_READ(sc, CSR_ANA_PLL_CFG);
4579 	IWH_WRITE(sc, CSR_ANA_PLL_CFG, tmp | IWH_CSR_ANA_PLL_CFG);
4580 
4581 	tmp = IWH_READ(sc, CSR_GP_CNTRL);
4582 	IWH_WRITE(sc, CSR_GP_CNTRL, tmp | CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
4583 
4584 	/*
4585 	 * wait for clock ready
4586 	 */
4587 	for (n = 0; n < 1000; n++) {
4588 		if (IWH_READ(sc, CSR_GP_CNTRL) &
4589 		    CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY) {
4590 			break;
4591 		}
4592 		DELAY(10);
4593 	}
4594 
4595 	if (1000 == n) {
4596 		return (ETIMEDOUT);
4597 	}
4598 
4599 	iwh_mac_access_enter(sc);
4600 
4601 	iwh_reg_write(sc, ALM_APMG_CLK_EN, APMG_CLK_REG_VAL_DMA_CLK_RQT);
4602 
4603 	DELAY(20);
4604 	tmp = iwh_reg_read(sc, ALM_APMG_PCIDEV_STT);
4605 	iwh_reg_write(sc, ALM_APMG_PCIDEV_STT, tmp |
4606 	    APMG_DEV_STATE_REG_VAL_L1_ACTIVE_DISABLE);
4607 	iwh_mac_access_exit(sc);
4608 
4609 	radio_cfg = IWH_READ_EEP_SHORT(sc, EEP_SP_RADIO_CONFIGURATION);
4610 	if (SP_RADIO_TYPE_MSK(radio_cfg) < SP_RADIO_TYPE_MAX) {
4611 		tmp = IWH_READ(sc, CSR_HW_IF_CONFIG_REG);
4612 		IWH_WRITE(sc, CSR_HW_IF_CONFIG_REG,
4613 		    tmp | SP_RADIO_TYPE_MSK(radio_cfg) |
4614 		    SP_RADIO_STEP_MSK(radio_cfg) |
4615 		    SP_RADIO_DASH_MSK(radio_cfg));
4616 	} else {
4617 		cmn_err(CE_WARN, "iwh_preinit(): "
4618 		    "radio configuration information in eeprom is wrong\n");
4619 		return (IWH_FAIL);
4620 	}
4621 
4622 
4623 	IWH_WRITE(sc, CSR_INT_COALESCING, 512 / 32);
4624 
4625 	(void) iwh_power_up(sc);
4626 
4627 	if ((sc->sc_rev & 0x80) == 0x80 && (sc->sc_rev & 0x7f) < 8) {
4628 		tmp = ddi_get32(sc->sc_cfg_handle,
4629 		    (uint32_t *)(sc->sc_cfg_base + 0xe8));
4630 		ddi_put32(sc->sc_cfg_handle,
4631 		    (uint32_t *)(sc->sc_cfg_base + 0xe8),
4632 		    tmp & ~(1 << 11));
4633 	}
4634 
4635 	vlink = ddi_get8(sc->sc_cfg_handle,
4636 	    (uint8_t *)(sc->sc_cfg_base + 0xf0));
4637 	ddi_put8(sc->sc_cfg_handle, (uint8_t *)(sc->sc_cfg_base + 0xf0),
4638 	    vlink & ~2);
4639 
4640 	tmp = IWH_READ(sc, CSR_HW_IF_CONFIG_REG);
4641 	tmp |= CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI |
4642 	    CSR_HW_IF_CONFIG_REG_BIT_MAC_SI;
4643 	IWH_WRITE(sc, CSR_SW_VER, tmp);
4644 
4645 	/*
4646 	 * make sure power supply on each part of the hardware
4647 	 */
4648 	iwh_mac_access_enter(sc);
4649 	tmp = iwh_reg_read(sc, ALM_APMG_PS_CTL);
4650 	tmp |= APMG_PS_CTRL_REG_VAL_ALM_R_RESET_REQ;
4651 	iwh_reg_write(sc, ALM_APMG_PS_CTL, tmp);
4652 	DELAY(5);
4653 
4654 	tmp = iwh_reg_read(sc, ALM_APMG_PS_CTL);
4655 	tmp &= ~APMG_PS_CTRL_REG_VAL_ALM_R_RESET_REQ;
4656 	iwh_reg_write(sc, ALM_APMG_PS_CTL, tmp);
4657 	iwh_mac_access_exit(sc);
4658 
4659 	return (IWH_SUCCESS);
4660 }
4661 
4662 /*
4663  * set up semphore flag to own EEPROM
4664  */
4665 static int
4666 iwh_eep_sem_down(iwh_sc_t *sc)
4667 {
4668 	int count1, count2;
4669 	uint32_t tmp;
4670 
4671 	for (count1 = 0; count1 < 1000; count1++) {
4672 		tmp = IWH_READ(sc, CSR_HW_IF_CONFIG_REG);
4673 		IWH_WRITE(sc, CSR_HW_IF_CONFIG_REG,
4674 		    tmp | CSR_HW_IF_CONFIG_REG_EEP_SEM);
4675 
4676 		for (count2 = 0; count2 < 2; count2++) {
4677 			if (IWH_READ(sc, CSR_HW_IF_CONFIG_REG) &
4678 			    CSR_HW_IF_CONFIG_REG_EEP_SEM) {
4679 				return (IWH_SUCCESS);
4680 			}
4681 			DELAY(10000);
4682 		}
4683 	}
4684 
4685 	return (IWH_FAIL);
4686 }
4687 
4688 /*
4689  * reset semphore flag to release EEPROM
4690  */
4691 static void
4692 iwh_eep_sem_up(iwh_sc_t *sc)
4693 {
4694 	uint32_t tmp;
4695 
4696 	tmp = IWH_READ(sc, CSR_HW_IF_CONFIG_REG);
4697 	IWH_WRITE(sc, CSR_HW_IF_CONFIG_REG,
4698 	    tmp & (~CSR_HW_IF_CONFIG_REG_EEP_SEM));
4699 }
4700 
4701 /*
4702  * This function read all infomation from eeprom
4703  */
4704 static int
4705 iwh_eep_load(iwh_sc_t *sc)
4706 {
4707 	int i, rr;
4708 	uint32_t rv, tmp, eep_gp;
4709 	uint16_t addr, eep_sz = sizeof (sc->sc_eep_map);
4710 	uint16_t *eep_p = (uint16_t *)&sc->sc_eep_map;
4711 
4712 	/*
4713 	 * read eeprom gp register in CSR
4714 	 */
4715 	eep_gp = IWH_READ(sc, CSR_EEPROM_GP);
4716 	if ((eep_gp & CSR_EEPROM_GP_VALID_MSK) ==
4717 	    CSR_EEPROM_GP_BAD_SIGNATURE) {
4718 		IWH_DBG((IWH_DEBUG_EEPROM, "iwh_eep_load(): "
4719 		    "not find eeprom\n"));
4720 		return (IWH_FAIL);
4721 	}
4722 
4723 	rr = iwh_eep_sem_down(sc);
4724 	if (rr != 0) {
4725 		IWH_DBG((IWH_DEBUG_EEPROM, "iwh_eep_load(): "
4726 		    "driver failed to own EEPROM\n"));
4727 		return (IWH_FAIL);
4728 	}
4729 
4730 	for (addr = 0; addr < eep_sz; addr += 2) {
4731 		IWH_WRITE(sc, CSR_EEPROM_REG, addr<<1);
4732 		tmp = IWH_READ(sc, CSR_EEPROM_REG);
4733 		IWH_WRITE(sc, CSR_EEPROM_REG, tmp & ~(0x2));
4734 
4735 		for (i = 0; i < 10; i++) {
4736 			rv = IWH_READ(sc, CSR_EEPROM_REG);
4737 			if (rv & 1) {
4738 				break;
4739 			}
4740 			DELAY(10);
4741 		}
4742 
4743 		if (!(rv & 1)) {
4744 			IWH_DBG((IWH_DEBUG_EEPROM, "iwh_eep_load(): "
4745 			    "time out when read eeprome\n"));
4746 			iwh_eep_sem_up(sc);
4747 			return (IWH_FAIL);
4748 		}
4749 
4750 		eep_p[addr/2] = LE_16(rv >> 16);
4751 	}
4752 
4753 	iwh_eep_sem_up(sc);
4754 	return (IWH_SUCCESS);
4755 }
4756 
4757 /*
4758  * initialize mac address in ieee80211com_t struct
4759  */
4760 static void
4761 iwh_get_mac_from_eep(iwh_sc_t *sc)
4762 {
4763 	ieee80211com_t *ic = &sc->sc_ic;
4764 
4765 	IEEE80211_ADDR_COPY(ic->ic_macaddr, &sc->sc_eep_map[EEP_MAC_ADDRESS]);
4766 
4767 	IWH_DBG((IWH_DEBUG_EEPROM, "iwh_get_mac_from_eep(): "
4768 	    "mac:%2x:%2x:%2x:%2x:%2x:%2x\n",
4769 	    ic->ic_macaddr[0], ic->ic_macaddr[1], ic->ic_macaddr[2],
4770 	    ic->ic_macaddr[3], ic->ic_macaddr[4], ic->ic_macaddr[5]));
4771 }
4772 
4773 /*
4774  * main initialization function
4775  */
4776 static int
4777 iwh_init(iwh_sc_t *sc)
4778 {
4779 	int err = IWH_FAIL;
4780 	clock_t clk;
4781 
4782 	/*
4783 	 * release buffer for calibration
4784 	 */
4785 	iwh_release_calib_buffer(sc);
4786 
4787 	mutex_enter(&sc->sc_glock);
4788 	atomic_and_32(&sc->sc_flags, ~IWH_F_FW_INIT);
4789 
4790 	err = iwh_init_common(sc);
4791 	if (err != IWH_SUCCESS) {
4792 		mutex_exit(&sc->sc_glock);
4793 		return (IWH_FAIL);
4794 	}
4795 
4796 	/*
4797 	 * backup ucode data part for future use.
4798 	 */
4799 	bcopy(sc->sc_dma_fw_data.mem_va,
4800 	    sc->sc_dma_fw_data_bak.mem_va,
4801 	    sc->sc_dma_fw_data.alength);
4802 
4803 	/* load firmware init segment into NIC */
4804 	err = iwh_load_init_firmware(sc);
4805 	if (err != IWH_SUCCESS) {
4806 		cmn_err(CE_WARN, "iwh_init(): "
4807 		    "failed to setup init firmware\n");
4808 		mutex_exit(&sc->sc_glock);
4809 		return (IWH_FAIL);
4810 	}
4811 
4812 	/*
4813 	 * now press "execute" start running
4814 	 */
4815 	IWH_WRITE(sc, CSR_RESET, 0);
4816 
4817 	clk = ddi_get_lbolt() + drv_usectohz(1000000);
4818 	while (!(sc->sc_flags & IWH_F_FW_INIT)) {
4819 		if (cv_timedwait(&sc->sc_ucode_cv,
4820 		    &sc->sc_glock, clk) < 0) {
4821 			break;
4822 		}
4823 	}
4824 
4825 	if (!(sc->sc_flags & IWH_F_FW_INIT)) {
4826 		cmn_err(CE_WARN, "iwh_init(): "
4827 		    "failed to process init alive.\n");
4828 		mutex_exit(&sc->sc_glock);
4829 		return (IWH_FAIL);
4830 	}
4831 
4832 	mutex_exit(&sc->sc_glock);
4833 
4834 	/*
4835 	 * stop chipset for initializing chipset again
4836 	 */
4837 	iwh_stop(sc);
4838 
4839 	mutex_enter(&sc->sc_glock);
4840 	atomic_and_32(&sc->sc_flags, ~IWH_F_FW_INIT);
4841 
4842 	err = iwh_init_common(sc);
4843 	if (err != IWH_SUCCESS) {
4844 		mutex_exit(&sc->sc_glock);
4845 		return (IWH_FAIL);
4846 	}
4847 
4848 	/*
4849 	 * load firmware run segment into NIC
4850 	 */
4851 	err = iwh_load_run_firmware(sc);
4852 	if (err != IWH_SUCCESS) {
4853 		cmn_err(CE_WARN, "iwh_init(): "
4854 		    "failed to setup run firmware\n");
4855 		mutex_exit(&sc->sc_glock);
4856 		return (IWH_FAIL);
4857 	}
4858 
4859 	/*
4860 	 * now press "execute" start running
4861 	 */
4862 	IWH_WRITE(sc, CSR_RESET, 0);
4863 
4864 	clk = ddi_get_lbolt() + drv_usectohz(1000000);
4865 	while (!(sc->sc_flags & IWH_F_FW_INIT)) {
4866 		if (cv_timedwait(&sc->sc_ucode_cv,
4867 		    &sc->sc_glock, clk) < 0) {
4868 			break;
4869 		}
4870 	}
4871 
4872 	if (!(sc->sc_flags & IWH_F_FW_INIT)) {
4873 		cmn_err(CE_WARN, "iwh_init(): "
4874 		    "failed to process runtime alive.\n");
4875 		mutex_exit(&sc->sc_glock);
4876 		return (IWH_FAIL);
4877 	}
4878 
4879 	mutex_exit(&sc->sc_glock);
4880 
4881 	DELAY(1000);
4882 
4883 	mutex_enter(&sc->sc_glock);
4884 	atomic_and_32(&sc->sc_flags, ~IWH_F_FW_INIT);
4885 
4886 	/*
4887 	 * at this point, the firmware is loaded OK, then config the hardware
4888 	 * with the ucode API, including rxon, txpower, etc.
4889 	 */
4890 	err = iwh_config(sc);
4891 	if (err) {
4892 		cmn_err(CE_WARN, "iwh_init(): "
4893 		    "failed to configure device\n");
4894 		mutex_exit(&sc->sc_glock);
4895 		return (IWH_FAIL);
4896 	}
4897 
4898 	/*
4899 	 * at this point, hardware may receive beacons :)
4900 	 */
4901 	mutex_exit(&sc->sc_glock);
4902 	return (IWH_SUCCESS);
4903 }
4904 
4905 /*
4906  * stop or disable NIC
4907  */
4908 static void
4909 iwh_stop(iwh_sc_t *sc)
4910 {
4911 	uint32_t tmp;
4912 	int i;
4913 
4914 	/*
4915 	 * by pass if it's quiesced
4916 	 */
4917 	if (!(sc->sc_flags & IWH_F_QUIESCED)) {
4918 		mutex_enter(&sc->sc_glock);
4919 	}
4920 
4921 	IWH_WRITE(sc, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
4922 	/*
4923 	 * disable interrupts
4924 	 */
4925 	IWH_WRITE(sc, CSR_INT_MASK, 0);
4926 	IWH_WRITE(sc, CSR_INT, CSR_INI_SET_MASK);
4927 	IWH_WRITE(sc, CSR_FH_INT_STATUS, 0xffffffff);
4928 
4929 	/*
4930 	 * reset all Tx rings
4931 	 */
4932 	for (i = 0; i < IWH_NUM_QUEUES; i++) {
4933 		iwh_reset_tx_ring(sc, &sc->sc_txq[i]);
4934 	}
4935 
4936 	/*
4937 	 * reset Rx ring
4938 	 */
4939 	iwh_reset_rx_ring(sc);
4940 
4941 	iwh_mac_access_enter(sc);
4942 	iwh_reg_write(sc, ALM_APMG_CLK_DIS, APMG_CLK_REG_VAL_DMA_CLK_RQT);
4943 	iwh_mac_access_exit(sc);
4944 
4945 	DELAY(5);
4946 
4947 	iwh_stop_master(sc);
4948 
4949 	mutex_enter(&sc->sc_mt_lock);
4950 	sc->sc_tx_timer = 0;
4951 	mutex_exit(&sc->sc_mt_lock);
4952 
4953 	tmp = IWH_READ(sc, CSR_RESET);
4954 	IWH_WRITE(sc, CSR_RESET, tmp | CSR_RESET_REG_FLAG_SW_RESET);
4955 
4956 	/*
4957 	 * by pass if it's quiesced
4958 	 */
4959 	if (!(sc->sc_flags & IWH_F_QUIESCED)) {
4960 		mutex_exit(&sc->sc_glock);
4961 	}
4962 }
4963 
4964 /*
4965  * Naive implementation of the Adaptive Multi Rate Retry algorithm:
4966  * "IEEE 802.11 Rate Adaptation: A Practical Approach"
4967  * Mathieu Lacage, Hossein Manshaei, Thierry Turletti
4968  * INRIA Sophia - Projet Planete
4969  * http://www-sop.inria.fr/rapports/sophia/RR-5208.html
4970  */
4971 #define	is_success(amrr)	\
4972 	((amrr)->retrycnt < (amrr)->txcnt / 10)
4973 #define	is_failure(amrr)	\
4974 	((amrr)->retrycnt > (amrr)->txcnt / 3)
4975 #define	is_enough(amrr)		\
4976 	((amrr)->txcnt > 200)
4977 #define	not_very_few(amrr)	\
4978 	((amrr)->txcnt > 40)
4979 #define	is_min_rate(in)		\
4980 	(0 == (in)->in_txrate)
4981 #define	is_max_rate(in)		\
4982 	((in)->in_rates.ir_nrates - 1 == (in)->in_txrate)
4983 #define	increase_rate(in)	\
4984 	((in)->in_txrate++)
4985 #define	decrease_rate(in)	\
4986 	((in)->in_txrate--)
4987 #define	reset_cnt(amrr)		\
4988 	{ (amrr)->txcnt = (amrr)->retrycnt = 0; }
4989 
4990 #define	IWH_AMRR_MIN_SUCCESS_THRESHOLD	 1
4991 #define	IWH_AMRR_MAX_SUCCESS_THRESHOLD	15
4992 
4993 static void
4994 iwh_amrr_init(iwh_amrr_t *amrr)
4995 {
4996 	amrr->success = 0;
4997 	amrr->recovery = 0;
4998 	amrr->txcnt = amrr->retrycnt = 0;
4999 	amrr->success_threshold = IWH_AMRR_MIN_SUCCESS_THRESHOLD;
5000 	amrr->ht_mcs_idx = 0;	/* 6Mbps */
5001 }
5002 
5003 static void
5004 iwh_amrr_timeout(iwh_sc_t *sc)
5005 {
5006 	ieee80211com_t *ic = &sc->sc_ic;
5007 
5008 	IWH_DBG((IWH_DEBUG_RATECTL, "iwh_amrr_timeout(): "
5009 	    "enter\n"));
5010 
5011 	if (IEEE80211_M_STA == ic->ic_opmode) {
5012 		iwh_amrr_ratectl(NULL, ic->ic_bss);
5013 	} else {
5014 		ieee80211_iterate_nodes(&ic->ic_sta, iwh_amrr_ratectl, NULL);
5015 	}
5016 
5017 	sc->sc_clk = ddi_get_lbolt();
5018 }
5019 
5020 static int
5021 iwh_is_max_rate(ieee80211_node_t *in)
5022 {
5023 	int i;
5024 	iwh_amrr_t *amrr = (iwh_amrr_t *)in;
5025 	uint8_t r = (uint8_t)amrr->ht_mcs_idx;
5026 	ieee80211com_t *ic = in->in_ic;
5027 	iwh_sc_t *sc = (iwh_sc_t *)ic;
5028 
5029 	if (in->in_flags & IEEE80211_NODE_HT) {
5030 		for (i = in->in_htrates.rs_nrates - 1; i >= 0; i--) {
5031 			r = in->in_htrates.rs_rates[i] &
5032 			    IEEE80211_RATE_VAL;
5033 			if (sc->sc_ht_conf.tx_support_mcs[r/8] &
5034 			    (1 << (r%8))) {
5035 				break;
5036 			}
5037 		}
5038 
5039 		return (r == (uint8_t)amrr->ht_mcs_idx);
5040 	} else {
5041 		return (is_max_rate(in));
5042 	}
5043 }
5044 
5045 static int
5046 iwh_is_min_rate(ieee80211_node_t *in)
5047 {
5048 	int i;
5049 	uint8_t r = 0;
5050 	iwh_amrr_t *amrr = (iwh_amrr_t *)in;
5051 	ieee80211com_t *ic = in->in_ic;
5052 	iwh_sc_t *sc = (iwh_sc_t *)ic;
5053 
5054 	if (in->in_flags & IEEE80211_NODE_HT) {
5055 		for (i = 0; i < in->in_htrates.rs_nrates; i++) {
5056 			r = in->in_htrates.rs_rates[i] &
5057 			    IEEE80211_RATE_VAL;
5058 			if (sc->sc_ht_conf.tx_support_mcs[r/8] &
5059 			    (1 << (r%8))) {
5060 				break;
5061 			}
5062 		}
5063 
5064 		return (r == (uint8_t)amrr->ht_mcs_idx);
5065 	} else {
5066 		return (is_min_rate(in));
5067 	}
5068 }
5069 
5070 static void
5071 iwh_increase_rate(ieee80211_node_t *in)
5072 {
5073 	int i;
5074 	uint8_t r;
5075 	iwh_amrr_t *amrr = (iwh_amrr_t *)in;
5076 	ieee80211com_t *ic = in->in_ic;
5077 	iwh_sc_t *sc = (iwh_sc_t *)ic;
5078 
5079 	if (in->in_flags & IEEE80211_NODE_HT) {
5080 again:
5081 		amrr->ht_mcs_idx++;
5082 
5083 		for (i = 0; i < in->in_htrates.rs_nrates; i++) {
5084 			r = in->in_htrates.rs_rates[i] &
5085 			    IEEE80211_RATE_VAL;
5086 			if ((r == (uint8_t)amrr->ht_mcs_idx) &&
5087 			    (sc->sc_ht_conf.tx_support_mcs[r/8] &
5088 			    (1 << (r%8)))) {
5089 				break;
5090 			}
5091 		}
5092 
5093 		if (i >= in->in_htrates.rs_nrates) {
5094 			goto again;
5095 		}
5096 	} else {
5097 		increase_rate(in);
5098 	}
5099 }
5100 
5101 static void
5102 iwh_decrease_rate(ieee80211_node_t *in)
5103 {
5104 	int i;
5105 	uint8_t r;
5106 	iwh_amrr_t *amrr = (iwh_amrr_t *)in;
5107 	ieee80211com_t *ic = in->in_ic;
5108 	iwh_sc_t *sc = (iwh_sc_t *)ic;
5109 
5110 	if (in->in_flags & IEEE80211_NODE_HT) {
5111 again:
5112 		amrr->ht_mcs_idx--;
5113 
5114 		for (i = 0; i < in->in_htrates.rs_nrates; i++) {
5115 			r = in->in_htrates.rs_rates[i] &
5116 			    IEEE80211_RATE_VAL;
5117 			if ((r == (uint8_t)amrr->ht_mcs_idx) &&
5118 			    (sc->sc_ht_conf.tx_support_mcs[r/8] &
5119 			    (1 << (r%8)))) {
5120 				break;
5121 			}
5122 		}
5123 
5124 		if (i >= in->in_htrates.rs_nrates) {
5125 			goto again;
5126 		}
5127 	} else {
5128 		decrease_rate(in);
5129 	}
5130 }
5131 
5132 /* ARGSUSED */
5133 static void
5134 iwh_amrr_ratectl(void *arg, ieee80211_node_t *in)
5135 {
5136 	iwh_amrr_t *amrr = (iwh_amrr_t *)in;
5137 	int need_change = 0;
5138 
5139 	if (is_success(amrr) && is_enough(amrr)) {
5140 		amrr->success++;
5141 		if (amrr->success >= amrr->success_threshold &&
5142 		    !iwh_is_max_rate(in)) {
5143 			amrr->recovery = 1;
5144 			amrr->success = 0;
5145 			iwh_increase_rate(in);
5146 			IWH_DBG((IWH_DEBUG_RATECTL, "iwh_amrr_ratectl(): "
5147 			    "AMRR increasing rate %d "
5148 			    "(txcnt=%d retrycnt=%d), mcs_idx=%d\n",
5149 			    in->in_txrate, amrr->txcnt,
5150 			    amrr->retrycnt, amrr->ht_mcs_idx));
5151 			need_change = 1;
5152 		} else {
5153 			amrr->recovery = 0;
5154 		}
5155 	} else if (not_very_few(amrr) && is_failure(amrr)) {
5156 		amrr->success = 0;
5157 		if (!iwh_is_min_rate(in)) {
5158 			if (amrr->recovery) {
5159 				amrr->success_threshold++;
5160 				if (amrr->success_threshold >
5161 				    IWH_AMRR_MAX_SUCCESS_THRESHOLD) {
5162 					amrr->success_threshold =
5163 					    IWH_AMRR_MAX_SUCCESS_THRESHOLD;
5164 				}
5165 			} else {
5166 				amrr->success_threshold =
5167 				    IWH_AMRR_MIN_SUCCESS_THRESHOLD;
5168 			}
5169 			iwh_decrease_rate(in);
5170 			IWH_DBG((IWH_DEBUG_RATECTL, "iwh_amrr_ratectl(): "
5171 			    "AMRR decreasing rate %d "
5172 			    "(txcnt=%d retrycnt=%d), mcs_idx=%d\n",
5173 			    in->in_txrate, amrr->txcnt,
5174 			    amrr->retrycnt, amrr->ht_mcs_idx));
5175 			need_change = 1;
5176 		}
5177 		amrr->recovery = 0;	/* paper is incorrect */
5178 	}
5179 
5180 	if (is_enough(amrr) || need_change) {
5181 		reset_cnt(amrr);
5182 	}
5183 }
5184 
5185 /*
5186  * translate indirect address in eeprom to direct address
5187  * in eeprom and return address of entry whos indirect address
5188  * is indi_addr
5189  */
5190 static uint8_t *
5191 iwh_eep_addr_trans(iwh_sc_t *sc, uint32_t indi_addr)
5192 {
5193 	uint32_t di_addr;
5194 	uint16_t temp;
5195 
5196 	if (!(indi_addr & INDIRECT_ADDRESS)) {
5197 		di_addr = indi_addr;
5198 		return (&sc->sc_eep_map[di_addr]);
5199 	}
5200 
5201 	switch (indi_addr & INDIRECT_TYPE_MSK) {
5202 	case INDIRECT_GENERAL:
5203 		temp = IWH_READ_EEP_SHORT(sc, EEP_LINK_GENERAL);
5204 		break;
5205 
5206 	case	INDIRECT_HOST:
5207 		temp = IWH_READ_EEP_SHORT(sc, EEP_LINK_HOST);
5208 		break;
5209 
5210 	case	INDIRECT_REGULATORY:
5211 		temp = IWH_READ_EEP_SHORT(sc, EEP_LINK_REGULATORY);
5212 		break;
5213 
5214 	case	INDIRECT_CALIBRATION:
5215 		temp = IWH_READ_EEP_SHORT(sc, EEP_LINK_CALIBRATION);
5216 		break;
5217 
5218 	case	INDIRECT_PROCESS_ADJST:
5219 		temp = IWH_READ_EEP_SHORT(sc, EEP_LINK_PROCESS_ADJST);
5220 		break;
5221 
5222 	case	INDIRECT_OTHERS:
5223 		temp = IWH_READ_EEP_SHORT(sc, EEP_LINK_OTHERS);
5224 		break;
5225 
5226 	default:
5227 		temp = 0;
5228 		cmn_err(CE_WARN, "iwh_eep_addr_trans(): "
5229 		    "incorrect indirect eeprom address.\n");
5230 		break;
5231 	}
5232 
5233 	di_addr = (indi_addr & ADDRESS_MSK) + (temp << 1);
5234 
5235 	return (&sc->sc_eep_map[di_addr]);
5236 }
5237 
5238 /*
5239  * loade a section of ucode into NIC
5240  */
5241 static int
5242 iwh_put_seg_fw(iwh_sc_t *sc, uint32_t addr_s, uint32_t addr_d, uint32_t len)
5243 {
5244 
5245 	iwh_mac_access_enter(sc);
5246 
5247 	IWH_WRITE(sc, IWH_FH_TCSR_CHNL_TX_CONFIG_REG(IWH_FH_SRVC_CHNL),
5248 	    IWH_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE);
5249 
5250 	IWH_WRITE(sc, IWH_FH_SRVC_CHNL_SRAM_ADDR_REG(IWH_FH_SRVC_CHNL), addr_d);
5251 
5252 	IWH_WRITE(sc, IWH_FH_TFDIB_CTRL0_REG(IWH_FH_SRVC_CHNL),
5253 	    (addr_s & FH_MEM_TFDIB_DRAM_ADDR_LSB_MASK));
5254 
5255 	IWH_WRITE(sc, IWH_FH_TFDIB_CTRL1_REG(IWH_FH_SRVC_CHNL), len);
5256 
5257 	IWH_WRITE(sc, IWH_FH_TCSR_CHNL_TX_BUF_STS_REG(IWH_FH_SRVC_CHNL),
5258 	    (1 << IWH_FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM) |
5259 	    (1 << IWH_FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX) |
5260 	    IWH_FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID);
5261 
5262 	IWH_WRITE(sc, IWH_FH_TCSR_CHNL_TX_CONFIG_REG(IWH_FH_SRVC_CHNL),
5263 	    IWH_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
5264 	    IWH_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE_VAL |
5265 	    IWH_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD);
5266 
5267 	iwh_mac_access_exit(sc);
5268 
5269 	return (IWH_SUCCESS);
5270 }
5271 
5272 /*
5273  * necessary setting during alive notification
5274  */
5275 static int
5276 iwh_alive_common(iwh_sc_t *sc)
5277 {
5278 	uint32_t base;
5279 	uint32_t i;
5280 	iwh_wimax_coex_cmd_t w_cmd;
5281 	iwh_calibration_crystal_cmd_t c_cmd;
5282 	uint32_t rv = IWH_FAIL;
5283 
5284 	/*
5285 	 * initialize SCD related registers to make TX work.
5286 	 */
5287 	iwh_mac_access_enter(sc);
5288 
5289 	/*
5290 	 * read sram address of data base.
5291 	 */
5292 	sc->sc_scd_base = iwh_reg_read(sc, IWH_SCD_SRAM_BASE_ADDR);
5293 
5294 	for (base = sc->sc_scd_base + IWH_SCD_CONTEXT_DATA_OFFSET;
5295 	    base < sc->sc_scd_base + IWH_SCD_TX_STTS_BITMAP_OFFSET;
5296 	    base += 4) {
5297 		iwh_mem_write(sc, base, 0);
5298 	}
5299 
5300 	for (; base < sc->sc_scd_base + IWH_SCD_TRANSLATE_TBL_OFFSET;
5301 	    base += 4) {
5302 		iwh_mem_write(sc, base, 0);
5303 	}
5304 
5305 	for (i = 0; i < sizeof (uint16_t) * IWH_NUM_QUEUES; i += 4) {
5306 		iwh_mem_write(sc, base + i, 0);
5307 	}
5308 
5309 	iwh_reg_write(sc, IWH_SCD_DRAM_BASE_ADDR,
5310 	    sc->sc_dma_sh.cookie.dmac_address >> 10);
5311 
5312 	iwh_reg_write(sc, IWH_SCD_QUEUECHAIN_SEL,
5313 	    IWH_SCD_QUEUECHAIN_SEL_ALL(IWH_NUM_QUEUES));
5314 
5315 	iwh_reg_write(sc, IWH_SCD_AGGR_SEL, 0);
5316 
5317 	for (i = 0; i < IWH_NUM_QUEUES; i++) {
5318 		iwh_reg_write(sc, IWH_SCD_QUEUE_RDPTR(i), 0);
5319 		IWH_WRITE(sc, HBUS_TARG_WRPTR, 0 | (i << 8));
5320 		iwh_mem_write(sc, sc->sc_scd_base +
5321 		    IWH_SCD_CONTEXT_QUEUE_OFFSET(i), 0);
5322 		iwh_mem_write(sc, sc->sc_scd_base +
5323 		    IWH_SCD_CONTEXT_QUEUE_OFFSET(i) +
5324 		    sizeof (uint32_t),
5325 		    ((SCD_WIN_SIZE << IWH_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) &
5326 		    IWH_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
5327 		    ((SCD_FRAME_LIMIT <<
5328 		    IWH_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
5329 		    IWH_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));
5330 	}
5331 
5332 	iwh_reg_write(sc, IWH_SCD_INTERRUPT_MASK, (1 << IWH_NUM_QUEUES) - 1);
5333 
5334 	iwh_reg_write(sc, (IWH_SCD_BASE + 0x10),
5335 	    SCD_TXFACT_REG_TXFIFO_MASK(0, 7));
5336 
5337 	IWH_WRITE(sc, HBUS_TARG_WRPTR, (IWH_CMD_QUEUE_NUM << 8));
5338 	iwh_reg_write(sc, IWH_SCD_QUEUE_RDPTR(IWH_CMD_QUEUE_NUM), 0);
5339 
5340 	/*
5341 	 * queue 0-7 map to FIFO 0-7 and
5342 	 * all queues work under FIFO mode(none-scheduler_ack)
5343 	 */
5344 	for (i = 0; i < 4; i++) {
5345 		iwh_reg_write(sc, IWH_SCD_QUEUE_STATUS_BITS(i),
5346 		    (1 << IWH_SCD_QUEUE_STTS_REG_POS_ACTIVE) |
5347 		    ((3-i) << IWH_SCD_QUEUE_STTS_REG_POS_TXF) |
5348 		    (1 << IWH_SCD_QUEUE_STTS_REG_POS_WSL) |
5349 		    IWH_SCD_QUEUE_STTS_REG_MSK);
5350 	}
5351 
5352 	iwh_reg_write(sc, IWH_SCD_QUEUE_STATUS_BITS(IWH_CMD_QUEUE_NUM),
5353 	    (1 << IWH_SCD_QUEUE_STTS_REG_POS_ACTIVE) |
5354 	    (IWH_CMD_FIFO_NUM << IWH_SCD_QUEUE_STTS_REG_POS_TXF) |
5355 	    (1 << IWH_SCD_QUEUE_STTS_REG_POS_WSL) |
5356 	    IWH_SCD_QUEUE_STTS_REG_MSK);
5357 
5358 	for (i = 5; i < 7; i++) {
5359 		iwh_reg_write(sc, IWH_SCD_QUEUE_STATUS_BITS(i),
5360 		    (1 << IWH_SCD_QUEUE_STTS_REG_POS_ACTIVE) |
5361 		    (i << IWH_SCD_QUEUE_STTS_REG_POS_TXF) |
5362 		    (1 << IWH_SCD_QUEUE_STTS_REG_POS_WSL) |
5363 		    IWH_SCD_QUEUE_STTS_REG_MSK);
5364 	}
5365 
5366 	iwh_mac_access_exit(sc);
5367 
5368 	(void) memset(&w_cmd, 0, sizeof (w_cmd));
5369 
5370 	rv = iwh_cmd(sc, COEX_PRIORITY_TABLE_CMD, &w_cmd, sizeof (w_cmd), 1);
5371 	if (rv != IWH_SUCCESS) {
5372 		cmn_err(CE_WARN, "iwh_alive_common(): "
5373 		    "failed to send wimax coexist command.\n");
5374 		return (rv);
5375 	}
5376 
5377 	if ((sc->sc_dev_id != 0x423c) &&
5378 	    (sc->sc_dev_id != 0x423d)) {
5379 		(void) memset(&c_cmd, 0, sizeof (c_cmd));
5380 
5381 		c_cmd.opCode = PHY_CALIBRATE_CRYSTAL_FRQ_CMD;
5382 		c_cmd.data.cap_pin1 = LE_16(sc->sc_eep_calib->xtal_calib[0]);
5383 		c_cmd.data.cap_pin2 = LE_16(sc->sc_eep_calib->xtal_calib[1]);
5384 
5385 		rv = iwh_cmd(sc, REPLY_PHY_CALIBRATION_CMD,
5386 		    &c_cmd, sizeof (c_cmd), 1);
5387 		if (rv != IWH_SUCCESS) {
5388 			cmn_err(CE_WARN, "iwh_alive_common(): "
5389 			    "failed to send crystal"
5390 			    "frq calibration command.\n");
5391 			return (rv);
5392 		}
5393 
5394 		/*
5395 		 * make sure crystal frequency calibration ready
5396 		 * before next operations.
5397 		 */
5398 		DELAY(1000);
5399 	}
5400 
5401 	return (IWH_SUCCESS);
5402 }
5403 
5404 /*
5405  * save results of calibration from ucode
5406  */
5407 static void
5408 iwh_save_calib_result(iwh_sc_t *sc, iwh_rx_desc_t *desc)
5409 {
5410 	struct iwh_calib_results *res_p = &sc->sc_calib_results;
5411 	struct iwh_calib_hdr *calib_hdr = (struct iwh_calib_hdr *)(desc + 1);
5412 	int len = LE_32(desc->len);
5413 
5414 	/*
5415 	 * ensure the size of buffer is not too big
5416 	 */
5417 	len = (len & FH_RSCSR_FRAME_SIZE_MASK) - 4;
5418 
5419 	switch (calib_hdr->op_code) {
5420 	case PHY_CALIBRATE_LO_CMD:
5421 		if (NULL == res_p->lo_res) {
5422 			res_p->lo_res = kmem_alloc(len, KM_NOSLEEP);
5423 		}
5424 
5425 		if (NULL == res_p->lo_res) {
5426 			cmn_err(CE_WARN, "iwh_save_calib_result(): "
5427 			    "failed to allocate memory.\n");
5428 			return;
5429 		}
5430 
5431 		res_p->lo_res_len = len;
5432 		bcopy(calib_hdr, res_p->lo_res, len);
5433 		break;
5434 
5435 	case PHY_CALIBRATE_TX_IQ_CMD:
5436 		if (NULL == res_p->tx_iq_res) {
5437 			res_p->tx_iq_res = kmem_alloc(len, KM_NOSLEEP);
5438 		}
5439 
5440 		if (NULL == res_p->tx_iq_res) {
5441 			cmn_err(CE_WARN, "iwh_save_calib_result(): "
5442 			    "failed to allocate memory.\n");
5443 			return;
5444 		}
5445 
5446 		res_p->tx_iq_res_len = len;
5447 		bcopy(calib_hdr, res_p->tx_iq_res, len);
5448 		break;
5449 
5450 	case PHY_CALIBRATE_TX_IQ_PERD_CMD:
5451 		if (NULL == res_p->tx_iq_perd_res) {
5452 			res_p->tx_iq_perd_res = kmem_alloc(len, KM_NOSLEEP);
5453 		}
5454 
5455 		if (NULL == res_p->tx_iq_perd_res) {
5456 			cmn_err(CE_WARN, "iwh_save_calib_result(): "
5457 			    "failed to allocate memory.\n");
5458 		}
5459 
5460 		res_p->tx_iq_perd_res_len = len;
5461 		bcopy(calib_hdr, res_p->tx_iq_perd_res, len);
5462 		break;
5463 
5464 	case PHY_CALIBRATE_DC_CMD:
5465 		if (NULL == res_p->dc_res) {
5466 			res_p->dc_res = kmem_alloc(len, KM_NOSLEEP);
5467 		}
5468 
5469 		if (NULL == res_p->dc_res) {
5470 			cmn_err(CE_WARN, "iwh_save_calib_result(): "
5471 			    "failed to allocate memory.\n");
5472 		}
5473 
5474 		res_p->dc_res_len = len;
5475 		bcopy(calib_hdr, res_p->dc_res, len);
5476 		break;
5477 
5478 	case PHY_CALIBRATE_BASE_BAND_CMD:
5479 		if (NULL == res_p->base_band_res) {
5480 			res_p->base_band_res = kmem_alloc(len, KM_NOSLEEP);
5481 		}
5482 
5483 		if (NULL == res_p->base_band_res) {
5484 			cmn_err(CE_WARN, "iwh_save_calib_result(): "
5485 			    "failed to allocate memory.\n");
5486 		}
5487 
5488 		res_p->base_band_res_len = len;
5489 		bcopy(calib_hdr, res_p->base_band_res, len);
5490 		break;
5491 
5492 	default:
5493 		cmn_err(CE_WARN, "iwh_save_calib_result(): "
5494 		    "incorrect calibration type(%d).\n", calib_hdr->op_code);
5495 		break;
5496 	}
5497 
5498 }
5499 
5500 /*
5501  * configure TX pwoer table
5502  */
5503 static int
5504 iwh_tx_power_table(iwh_sc_t *sc, int async)
5505 {
5506 	iwh_tx_power_table_cmd_t txpower;
5507 	int i, err = IWH_FAIL;
5508 
5509 	(void) memset(&txpower, 0, sizeof (txpower));
5510 
5511 	txpower.band = 1; /* for 2.4G */
5512 	txpower.channel = (uint8_t)LE_16(sc->sc_config.chan);
5513 	txpower.pa_measurements = 1;
5514 	txpower.max_mcs = 23;
5515 
5516 	for (i = 0; i < 24; i++) {
5517 		txpower.db.ht_ofdm_power[i].s.radio_tx_gain[0] = 0x16;
5518 		txpower.db.ht_ofdm_power[i].s.radio_tx_gain[1] = 0x16;
5519 		txpower.db.ht_ofdm_power[i].s.radio_tx_gain[2] = 0x16;
5520 		txpower.db.ht_ofdm_power[i].s.dsp_predis_atten[0] = 0x6E;
5521 		txpower.db.ht_ofdm_power[i].s.dsp_predis_atten[1] = 0x6E;
5522 		txpower.db.ht_ofdm_power[i].s.dsp_predis_atten[2] = 0x6E;
5523 	}
5524 
5525 	for (i = 0; i < 2; i++) {
5526 		txpower.db.cck_power[i].s.radio_tx_gain[0] = 0x16;
5527 		txpower.db.cck_power[i].s.radio_tx_gain[1] = 0x16;
5528 		txpower.db.cck_power[i].s.radio_tx_gain[2] = 0x16;
5529 		txpower.db.cck_power[i].s.dsp_predis_atten[0] = 0x6E;
5530 		txpower.db.cck_power[i].s.dsp_predis_atten[1] = 0x6E;
5531 		txpower.db.cck_power[i].s.dsp_predis_atten[2] = 0x6E;
5532 	}
5533 
5534 	err = iwh_cmd(sc, REPLY_TX_PWR_TABLE_CMD, &txpower,
5535 	    sizeof (txpower), async);
5536 	if (err != IWH_SUCCESS) {
5537 		cmn_err(CE_WARN, "iwh_tx_power_table(): "
5538 		    "failed to set tx power table.\n");
5539 		return (err);
5540 	}
5541 
5542 	return (err);
5543 }
5544 
5545 static void
5546 iwh_release_calib_buffer(iwh_sc_t *sc)
5547 {
5548 	if (sc->sc_calib_results.lo_res != NULL) {
5549 		kmem_free(sc->sc_calib_results.lo_res,
5550 		    sc->sc_calib_results.lo_res_len);
5551 		sc->sc_calib_results.lo_res = NULL;
5552 	}
5553 
5554 	if (sc->sc_calib_results.tx_iq_res != NULL) {
5555 		kmem_free(sc->sc_calib_results.tx_iq_res,
5556 		    sc->sc_calib_results.tx_iq_res_len);
5557 		sc->sc_calib_results.tx_iq_res = NULL;
5558 	}
5559 
5560 	if (sc->sc_calib_results.tx_iq_perd_res != NULL) {
5561 		kmem_free(sc->sc_calib_results.tx_iq_perd_res,
5562 		    sc->sc_calib_results.tx_iq_perd_res_len);
5563 		sc->sc_calib_results.tx_iq_perd_res = NULL;
5564 	}
5565 
5566 	if (sc->sc_calib_results.dc_res != NULL) {
5567 		kmem_free(sc->sc_calib_results.dc_res,
5568 		    sc->sc_calib_results.dc_res_len);
5569 		sc->sc_calib_results.dc_res = NULL;
5570 	}
5571 
5572 	if (sc->sc_calib_results.base_band_res != NULL) {
5573 		kmem_free(sc->sc_calib_results.base_band_res,
5574 		    sc->sc_calib_results.base_band_res_len);
5575 		sc->sc_calib_results.base_band_res = NULL;
5576 	}
5577 }
5578 
5579 /*
5580  * common section of intialization
5581  */
5582 static int
5583 iwh_init_common(iwh_sc_t *sc)
5584 {
5585 	int32_t	qid;
5586 	uint32_t tmp;
5587 
5588 	(void) iwh_preinit(sc);
5589 
5590 	tmp = IWH_READ(sc, CSR_GP_CNTRL);
5591 	if (!(tmp & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)) {
5592 		cmn_err(CE_NOTE, "iwh_init_common(): "
5593 		    "radio transmitter is off\n");
5594 		return (IWH_FAIL);
5595 	}
5596 
5597 	/*
5598 	 * init Rx ring
5599 	 */
5600 	iwh_mac_access_enter(sc);
5601 	IWH_WRITE(sc, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
5602 
5603 	IWH_WRITE(sc, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0);
5604 	IWH_WRITE(sc, FH_RSCSR_CHNL0_RBDCB_BASE_REG,
5605 	    sc->sc_rxq.dma_desc.cookie.dmac_address >> 8);
5606 
5607 	IWH_WRITE(sc, FH_RSCSR_CHNL0_STTS_WPTR_REG,
5608 	    ((uint32_t)(sc->sc_dma_sh.cookie.dmac_address +
5609 	    offsetof(struct iwh_shared, val0)) >> 4));
5610 
5611 	IWH_WRITE(sc, FH_MEM_RCSR_CHNL0_CONFIG_REG,
5612 	    FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL |
5613 	    FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL |
5614 	    IWH_FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K |
5615 	    (RX_QUEUE_SIZE_LOG <<
5616 	    FH_RCSR_RX_CONFIG_RBDCB_SIZE_BITSHIFT));
5617 	iwh_mac_access_exit(sc);
5618 	IWH_WRITE(sc, FH_RSCSR_CHNL0_RBDCB_WPTR_REG,
5619 	    (RX_QUEUE_SIZE - 1) & ~0x7);
5620 
5621 	/*
5622 	 * init Tx rings
5623 	 */
5624 	iwh_mac_access_enter(sc);
5625 	iwh_reg_write(sc, IWH_SCD_TXFACT, 0);
5626 
5627 	/*
5628 	 * keep warm page
5629 	 */
5630 	IWH_WRITE(sc, IWH_FH_KW_MEM_ADDR_REG,
5631 	    sc->sc_dma_kw.cookie.dmac_address >> 4);
5632 
5633 	for (qid = 0; qid < IWH_NUM_QUEUES; qid++) {
5634 		IWH_WRITE(sc, FH_MEM_CBBC_QUEUE(qid),
5635 		    sc->sc_txq[qid].dma_desc.cookie.dmac_address >> 8);
5636 		IWH_WRITE(sc, IWH_FH_TCSR_CHNL_TX_CONFIG_REG(qid),
5637 		    IWH_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
5638 		    IWH_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL);
5639 	}
5640 
5641 	iwh_mac_access_exit(sc);
5642 
5643 	/*
5644 	 * clear "radio off" and "disable command" bits
5645 	 */
5646 	IWH_WRITE(sc, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
5647 	IWH_WRITE(sc, CSR_UCODE_DRV_GP1_CLR,
5648 	    CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
5649 
5650 	/*
5651 	 * clear any pending interrupts
5652 	 */
5653 	IWH_WRITE(sc, CSR_INT, 0xffffffff);
5654 
5655 	/*
5656 	 * enable interrupts
5657 	 */
5658 	IWH_WRITE(sc, CSR_INT_MASK, CSR_INI_SET_MASK);
5659 
5660 	IWH_WRITE(sc, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
5661 	IWH_WRITE(sc, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
5662 
5663 	return (IWH_SUCCESS);
5664 }
5665 
5666 static int
5667 iwh_fast_recover(iwh_sc_t *sc)
5668 {
5669 	ieee80211com_t *ic = &sc->sc_ic;
5670 	int err = IWH_FAIL;
5671 
5672 	mutex_enter(&sc->sc_glock);
5673 
5674 	/*
5675 	 * restore runtime configuration
5676 	 */
5677 	bcopy(&sc->sc_config_save, &sc->sc_config,
5678 	    sizeof (sc->sc_config));
5679 
5680 	sc->sc_config.assoc_id = 0;
5681 	sc->sc_config.filter_flags &= ~LE_32(RXON_FILTER_ASSOC_MSK);
5682 
5683 	if ((err = iwh_hw_set_before_auth(sc)) != IWH_SUCCESS) {
5684 		cmn_err(CE_WARN, "iwh_fast_recover(): "
5685 		    "could not setup authentication\n");
5686 		mutex_exit(&sc->sc_glock);
5687 		return (err);
5688 	}
5689 
5690 	bcopy(&sc->sc_config_save, &sc->sc_config,
5691 	    sizeof (sc->sc_config));
5692 
5693 	/*
5694 	 * update adapter's configuration
5695 	 */
5696 	err = iwh_run_state_config(sc);
5697 	if (err != IWH_SUCCESS) {
5698 		cmn_err(CE_WARN, "iwh_fast_recover(): "
5699 		    "failed to setup association\n");
5700 		mutex_exit(&sc->sc_glock);
5701 		return (err);
5702 	}
5703 
5704 	/*
5705 	 * set LED on
5706 	 */
5707 	iwh_set_led(sc, 2, 0, 1);
5708 
5709 	mutex_exit(&sc->sc_glock);
5710 
5711 	atomic_and_32(&sc->sc_flags, ~IWH_F_HW_ERR_RECOVER);
5712 
5713 	/*
5714 	 * start queue
5715 	 */
5716 	IWH_DBG((IWH_DEBUG_FW, "iwh_fast_recover(): "
5717 	    "resume xmit\n"));
5718 	mac_tx_update(ic->ic_mach);
5719 
5720 	return (IWH_SUCCESS);
5721 }
5722 
5723 static int
5724 iwh_run_state_config(iwh_sc_t *sc)
5725 {
5726 	struct ieee80211com *ic = &sc->sc_ic;
5727 	ieee80211_node_t *in = ic->ic_bss;
5728 	uint32_t ht_protec = (uint32_t)(-1);
5729 	int err = IWH_FAIL;
5730 
5731 	/*
5732 	 * update adapter's configuration
5733 	 */
5734 	sc->sc_config.assoc_id = in->in_associd & 0x3fff;
5735 
5736 	/*
5737 	 * short preamble/slot time are
5738 	 * negotiated when associating
5739 	 */
5740 	sc->sc_config.flags &=
5741 	    ~LE_32(RXON_FLG_SHORT_PREAMBLE_MSK |
5742 	    RXON_FLG_SHORT_SLOT_MSK);
5743 
5744 	if (ic->ic_flags & IEEE80211_F_SHSLOT) {
5745 		sc->sc_config.flags |=
5746 		    LE_32(RXON_FLG_SHORT_SLOT_MSK);
5747 	}
5748 
5749 	if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) {
5750 		sc->sc_config.flags |=
5751 		    LE_32(RXON_FLG_SHORT_PREAMBLE_MSK);
5752 	}
5753 
5754 	if (in->in_flags & IEEE80211_NODE_HT) {
5755 		ht_protec = in->in_htopmode;
5756 		if (ht_protec > 3) {
5757 			cmn_err(CE_WARN, "iwh_run_state_config(): "
5758 			    "HT protection mode is not correct.\n");
5759 			return (IWH_FAIL);
5760 		} else if (NO_HT_PROT == ht_protec) {
5761 			ht_protec = sc->sc_ht_conf.ht_protection;
5762 		}
5763 
5764 		sc->sc_config.flags |=
5765 		    LE_32(ht_protec << RXON_FLG_HT_OPERATING_MODE_POS);
5766 	}
5767 
5768 	/*
5769 	 * set RX chains/antennas.
5770 	 */
5771 	iwh_config_rxon_chain(sc);
5772 
5773 	sc->sc_config.filter_flags |=
5774 	    LE_32(RXON_FILTER_ASSOC_MSK);
5775 
5776 	if (ic->ic_opmode != IEEE80211_M_STA) {
5777 		sc->sc_config.filter_flags |=
5778 		    LE_32(RXON_FILTER_BCON_AWARE_MSK);
5779 	}
5780 
5781 	IWH_DBG((IWH_DEBUG_80211, "iwh_run_state_config(): "
5782 	    "config chan %d flags %x"
5783 	    " filter_flags %x\n",
5784 	    sc->sc_config.chan, sc->sc_config.flags,
5785 	    sc->sc_config.filter_flags));
5786 
5787 	err = iwh_cmd(sc, REPLY_RXON, &sc->sc_config,
5788 	    sizeof (iwh_rxon_cmd_t), 1);
5789 	if (err != IWH_SUCCESS) {
5790 		cmn_err(CE_WARN, "iwh_run_state_config(): "
5791 		    "could not update configuration\n");
5792 		return (err);
5793 	}
5794 
5795 	if ((sc->sc_dev_id != 0x423c) &&
5796 	    (sc->sc_dev_id != 0x423d)) {
5797 		/*
5798 		 * send tx power table command
5799 		 */
5800 		err = iwh_tx_power_table(sc, 1);
5801 		if (err != IWH_SUCCESS) {
5802 			return (err);
5803 		}
5804 	}
5805 
5806 	/*
5807 	 * Not need to update retry rate table for AP node
5808 	 */
5809 	err = iwh_qosparam_to_hw(sc, 1);
5810 	if (err != IWH_SUCCESS) {
5811 		return (err);
5812 	}
5813 
5814 	return (err);
5815 }
5816 
5817 /*
5818  * This function is only for compatibility with Net80211 module.
5819  * iwh_qosparam_to_hw() is the actual function updating EDCA
5820  * parameters to hardware.
5821  */
5822 /* ARGSUSED */
5823 static int
5824 iwh_wme_update(ieee80211com_t *ic)
5825 {
5826 	return (0);
5827 }
5828 
5829 static int
5830 iwh_wme_to_qos_ac(int wme_ac)
5831 {
5832 	int qos_ac = QOS_AC_INVALID;
5833 
5834 	if (wme_ac < WME_AC_BE || wme_ac > WME_AC_VO) {
5835 		cmn_err(CE_WARN, "iwh_wme_to_qos_ac(): "
5836 		    "WME AC index is not in suitable range.\n");
5837 		return (qos_ac);
5838 	}
5839 
5840 	switch (wme_ac) {
5841 	case WME_AC_BE:
5842 		qos_ac = QOS_AC_BK;
5843 		break;
5844 	case WME_AC_BK:
5845 		qos_ac = QOS_AC_BE;
5846 		break;
5847 	case WME_AC_VI:
5848 		qos_ac = QOS_AC_VI;
5849 		break;
5850 	case WME_AC_VO:
5851 		qos_ac = QOS_AC_VO;
5852 		break;
5853 	}
5854 
5855 	return (qos_ac);
5856 }
5857 
5858 static uint16_t
5859 iwh_cw_e_to_cw(uint8_t cw_e)
5860 {
5861 	uint16_t cw = 1;
5862 
5863 	while (cw_e > 0) {
5864 		cw <<= 1;
5865 		cw_e--;
5866 	}
5867 
5868 	cw -= 1;
5869 	return (cw);
5870 }
5871 
5872 static int
5873 iwh_wmeparam_check(struct wmeParams *wmeparam)
5874 {
5875 	int i;
5876 
5877 	for (i = 0; i < WME_NUM_AC; i++) {
5878 
5879 		if ((wmeparam[i].wmep_logcwmax > QOS_CW_RANGE_MAX) ||
5880 		    (wmeparam[i].wmep_logcwmin >= wmeparam[i].wmep_logcwmax)) {
5881 			cmn_err(CE_WARN, "iwh_wmeparam_check(): "
5882 			    "Contention window is not in suitable range.\n");
5883 			return (IWH_FAIL);
5884 		}
5885 
5886 		if ((wmeparam[i].wmep_aifsn < QOS_AIFSN_MIN) ||
5887 		    (wmeparam[i].wmep_aifsn > QOS_AIFSN_MAX)) {
5888 			cmn_err(CE_WARN, "iwh_wmeparam_check(): "
5889 			    "Arbitration interframe space number"
5890 			    "is not in suitable range.\n");
5891 			return (IWH_FAIL);
5892 		}
5893 	}
5894 
5895 	return (IWH_SUCCESS);
5896 }
5897 
5898 /*
5899  * This function updates EDCA parameters into hardware.
5900  * FIFO0-background, FIFO1-best effort, FIFO2-viedo, FIFO3-voice.
5901  */
5902 static int
5903 iwh_qosparam_to_hw(iwh_sc_t *sc, int async)
5904 {
5905 	ieee80211com_t *ic = &sc->sc_ic;
5906 	ieee80211_node_t *in = ic->ic_bss;
5907 	struct wmeParams *wmeparam;
5908 	iwh_qos_param_cmd_t qosparam_cmd;
5909 	int i, j;
5910 	int err = IWH_FAIL;
5911 
5912 	if ((in->in_flags & IEEE80211_NODE_QOS) &&
5913 	    (IEEE80211_M_STA == ic->ic_opmode)) {
5914 		wmeparam = ic->ic_wme.wme_chanParams.cap_wmeParams;
5915 	} else {
5916 		return (IWH_SUCCESS);
5917 	}
5918 
5919 	(void) memset(&qosparam_cmd, 0, sizeof (qosparam_cmd));
5920 
5921 	err = iwh_wmeparam_check(wmeparam);
5922 	if (err != IWH_SUCCESS) {
5923 		return (err);
5924 	}
5925 
5926 	if (in->in_flags & IEEE80211_NODE_QOS) {
5927 		qosparam_cmd.flags |= QOS_PARAM_FLG_UPDATE_EDCA;
5928 	}
5929 
5930 	if (in->in_flags & (IEEE80211_NODE_QOS | IEEE80211_NODE_HT)) {
5931 		qosparam_cmd.flags |= QOS_PARAM_FLG_TGN;
5932 	}
5933 
5934 	for (i = 0; i < WME_NUM_AC; i++) {
5935 
5936 		j = iwh_wme_to_qos_ac(i);
5937 		if (j < QOS_AC_BK || j > QOS_AC_VO) {
5938 			return (IWH_FAIL);
5939 		}
5940 
5941 		qosparam_cmd.ac[j].cw_min =
5942 		    iwh_cw_e_to_cw(wmeparam[i].wmep_logcwmin);
5943 		qosparam_cmd.ac[j].cw_max =
5944 		    iwh_cw_e_to_cw(wmeparam[i].wmep_logcwmax);
5945 		qosparam_cmd.ac[j].aifsn =
5946 		    wmeparam[i].wmep_aifsn;
5947 		qosparam_cmd.ac[j].txop =
5948 		    (uint16_t)(wmeparam[i].wmep_txopLimit * 32);
5949 	}
5950 
5951 	err = iwh_cmd(sc, REPLY_QOS_PARAM, &qosparam_cmd,
5952 	    sizeof (qosparam_cmd), async);
5953 	if (err != IWH_SUCCESS) {
5954 		cmn_err(CE_WARN, "iwh_qosparam_to_hw(): "
5955 		    "failed to update QoS parameters into hardware.\n");
5956 		return (err);
5957 	}
5958 
5959 #ifdef	DEBUG
5960 	IWH_DBG((IWH_DEBUG_QOS, "iwh_qosparam_to_hw(): "
5961 	    "EDCA parameters are as follows:\n"));
5962 
5963 	IWH_DBG((IWH_DEBUG_QOS, "BK parameters are: "
5964 	    "cw_min = %d, cw_max = %d, aifsn = %d, txop = %d\n",
5965 	    qosparam_cmd.ac[0].cw_min, qosparam_cmd.ac[0].cw_max,
5966 	    qosparam_cmd.ac[0].aifsn, qosparam_cmd.ac[0].txop));
5967 
5968 	IWH_DBG((IWH_DEBUG_QOS, "BE parameters are: "
5969 	    "cw_min = %d, cw_max = %d, aifsn = %d, txop = %d\n",
5970 	    qosparam_cmd.ac[1].cw_min, qosparam_cmd.ac[1].cw_max,
5971 	    qosparam_cmd.ac[1].aifsn, qosparam_cmd.ac[1].txop));
5972 
5973 	IWH_DBG((IWH_DEBUG_QOS, "VI parameters are: "
5974 	    "cw_min = %d, cw_max = %d, aifsn = %d, txop = %d\n",
5975 	    qosparam_cmd.ac[2].cw_min, qosparam_cmd.ac[2].cw_max,
5976 	    qosparam_cmd.ac[2].aifsn, qosparam_cmd.ac[2].txop));
5977 
5978 	IWH_DBG((IWH_DEBUG_QOS, "VO parameters are: "
5979 	    "cw_min = %d, cw_max = %d, aifsn = %d, txop = %d\n",
5980 	    qosparam_cmd.ac[3].cw_min, qosparam_cmd.ac[3].cw_max,
5981 	    qosparam_cmd.ac[3].aifsn, qosparam_cmd.ac[3].txop));
5982 #endif
5983 	return (err);
5984 }
5985 
5986 static inline int
5987 iwh_wme_tid_qos_ac(int tid)
5988 {
5989 	switch (tid) {
5990 	case 1:
5991 	case 2:
5992 		return (QOS_AC_BK);
5993 	case 0:
5994 	case 3:
5995 		return (QOS_AC_BE);
5996 	case 4:
5997 	case 5:
5998 		return (QOS_AC_VI);
5999 	case 6:
6000 	case 7:
6001 		return (QOS_AC_VO);
6002 	}
6003 
6004 	return (QOS_AC_BE);
6005 }
6006 
6007 static inline int
6008 iwh_qos_ac_to_txq(int qos_ac)
6009 {
6010 	switch (qos_ac) {
6011 	case QOS_AC_BK:
6012 		return (QOS_AC_BK_TO_TXQ);
6013 	case QOS_AC_BE:
6014 		return (QOS_AC_BE_TO_TXQ);
6015 	case QOS_AC_VI:
6016 		return (QOS_AC_VI_TO_TXQ);
6017 	case QOS_AC_VO:
6018 		return (QOS_AC_VO_TO_TXQ);
6019 	}
6020 
6021 	return (QOS_AC_BE_TO_TXQ);
6022 }
6023 
6024 static int
6025 iwh_wme_tid_to_txq(int tid)
6026 {
6027 	int queue_n = TXQ_FOR_AC_INVALID;
6028 	int qos_ac;
6029 
6030 	if (tid < WME_TID_MIN ||
6031 	    tid > WME_TID_MAX) {
6032 		cmn_err(CE_WARN, "wme_tid_to_txq(): "
6033 		    "TID is not in suitable range.\n");
6034 		return (queue_n);
6035 	}
6036 
6037 	qos_ac = iwh_wme_tid_qos_ac(tid);
6038 	queue_n = iwh_qos_ac_to_txq(qos_ac);
6039 
6040 	return (queue_n);
6041 }
6042 
6043 /*
6044  * This function is used for intializing HT relevant configurations.
6045  */
6046 static void
6047 iwh_init_ht_conf(iwh_sc_t *sc)
6048 {
6049 	(void) memset(&sc->sc_ht_conf, 0, sizeof (iwh_ht_conf_t));
6050 
6051 	if ((0x4235 == sc->sc_dev_id) ||
6052 	    (0x4236 == sc->sc_dev_id) ||
6053 	    (0x423a == sc->sc_dev_id)) {
6054 		sc->sc_ht_conf.ht_support = 1;
6055 
6056 		sc->sc_ht_conf.valid_chains = 3;
6057 		sc->sc_ht_conf.tx_stream_count = 2;
6058 		sc->sc_ht_conf.rx_stream_count = 2;
6059 
6060 		sc->sc_ht_conf.tx_support_mcs[0] = 0xff;
6061 		sc->sc_ht_conf.tx_support_mcs[1] = 0xff;
6062 		sc->sc_ht_conf.rx_support_mcs[0] = 0xff;
6063 		sc->sc_ht_conf.rx_support_mcs[1] = 0xff;
6064 	} else {
6065 		sc->sc_ht_conf.ht_support = 1;
6066 
6067 		sc->sc_ht_conf.valid_chains = 2;
6068 		sc->sc_ht_conf.tx_stream_count = 1;
6069 		sc->sc_ht_conf.rx_stream_count = 2;
6070 
6071 		sc->sc_ht_conf.tx_support_mcs[0] = 0xff;
6072 		sc->sc_ht_conf.rx_support_mcs[0] = 0xff;
6073 		sc->sc_ht_conf.rx_support_mcs[1] = 0xff;
6074 	}
6075 
6076 	if (sc->sc_ht_conf.ht_support) {
6077 		sc->sc_ht_conf.cap |= HT_CAP_GRN_FLD;
6078 		sc->sc_ht_conf.cap |= HT_CAP_SGI_20;
6079 		sc->sc_ht_conf.cap |= HT_CAP_MAX_AMSDU;
6080 		/* should disable MIMO */
6081 		sc->sc_ht_conf.cap |= HT_CAP_MIMO_PS;
6082 
6083 		sc->sc_ht_conf.ampdu_p.factor = HT_RX_AMPDU_FACTOR;
6084 		sc->sc_ht_conf.ampdu_p.density = HT_MPDU_DENSITY;
6085 
6086 		sc->sc_ht_conf.ht_protection = HT_PROT_CHAN_NON_HT;
6087 	}
6088 }
6089 
6090 /*
6091  * This function overwrites default ieee80211_rateset_11n struc.
6092  */
6093 static void
6094 iwh_overwrite_11n_rateset(iwh_sc_t *sc)
6095 {
6096 	uint8_t *ht_rs = sc->sc_ht_conf.rx_support_mcs;
6097 	int mcs_idx, mcs_count = 0;
6098 	int i, j;
6099 
6100 	for (i = 0; i < HT_RATESET_NUM; i++) {
6101 		for (j = 0; j < 8; j++) {
6102 			if (ht_rs[i] & (1 << j)) {
6103 				mcs_idx = i * 8 + j;
6104 				if (mcs_idx >= IEEE80211_HTRATE_MAXSIZE) {
6105 					break;
6106 				}
6107 
6108 				ieee80211_rateset_11n.rs_rates[mcs_idx] =
6109 				    (uint8_t)mcs_idx;
6110 				mcs_count++;
6111 			}
6112 		}
6113 	}
6114 
6115 	ieee80211_rateset_11n.rs_nrates = (uint8_t)mcs_count;
6116 
6117 #ifdef	DEBUG
6118 	IWH_DBG((IWH_DEBUG_HTRATE, "iwh_overwrite_11n_rateset(): "
6119 	    "HT rates supported by this station is as follows:\n"));
6120 
6121 	for (i = 0; i < ieee80211_rateset_11n.rs_nrates; i++) {
6122 		IWH_DBG((IWH_DEBUG_HTRATE, "Rate %d is %d\n",
6123 		    i, ieee80211_rateset_11n.rs_rates[i]));
6124 	}
6125 #endif
6126 }
6127 
6128 /*
6129  * This function overwrites default configurations of
6130  * ieee80211com structure in Net80211 module.
6131  */
6132 static void
6133 iwh_overwrite_ic_default(iwh_sc_t *sc)
6134 {
6135 	ieee80211com_t *ic = &sc->sc_ic;
6136 
6137 	sc->sc_newstate = ic->ic_newstate;
6138 	ic->ic_newstate = iwh_newstate;
6139 	ic->ic_node_alloc = iwh_node_alloc;
6140 	ic->ic_node_free = iwh_node_free;
6141 
6142 	if (sc->sc_ht_conf.ht_support) {
6143 		sc->sc_recv_action = ic->ic_recv_action;
6144 		ic->ic_recv_action = iwh_recv_action;
6145 		sc->sc_send_action = ic->ic_send_action;
6146 		ic->ic_send_action = iwh_send_action;
6147 
6148 		ic->ic_ampdu_rxmax = sc->sc_ht_conf.ampdu_p.factor;
6149 		ic->ic_ampdu_density = sc->sc_ht_conf.ampdu_p.density;
6150 		ic->ic_ampdu_limit = ic->ic_ampdu_rxmax;
6151 	}
6152 }
6153 
6154 /*
6155  * This function sets "RX chain selection" feild
6156  * in RXON command during plumb driver.
6157  */
6158 static void
6159 iwh_config_rxon_chain(iwh_sc_t *sc)
6160 {
6161 	ieee80211com_t *ic = &sc->sc_ic;
6162 	ieee80211_node_t *in = ic->ic_bss;
6163 
6164 	if (3 == sc->sc_ht_conf.valid_chains) {
6165 		sc->sc_config.rx_chain = LE_16((RXON_RX_CHAIN_A_MSK |
6166 		    RXON_RX_CHAIN_B_MSK | RXON_RX_CHAIN_C_MSK) <<
6167 		    RXON_RX_CHAIN_VALID_POS);
6168 
6169 		sc->sc_config.rx_chain |= LE_16((RXON_RX_CHAIN_A_MSK |
6170 		    RXON_RX_CHAIN_B_MSK | RXON_RX_CHAIN_C_MSK) <<
6171 		    RXON_RX_CHAIN_FORCE_SEL_POS);
6172 
6173 		sc->sc_config.rx_chain |= LE_16((RXON_RX_CHAIN_A_MSK |
6174 		    RXON_RX_CHAIN_B_MSK | RXON_RX_CHAIN_C_MSK) <<
6175 		    RXON_RX_CHAIN_FORCE_MIMO_SEL_POS);
6176 	} else {
6177 		sc->sc_config.rx_chain = LE_16((RXON_RX_CHAIN_A_MSK |
6178 		    RXON_RX_CHAIN_B_MSK) << RXON_RX_CHAIN_VALID_POS);
6179 
6180 		sc->sc_config.rx_chain |= LE_16((RXON_RX_CHAIN_A_MSK |
6181 		    RXON_RX_CHAIN_B_MSK) << RXON_RX_CHAIN_FORCE_SEL_POS);
6182 
6183 		sc->sc_config.rx_chain |= LE_16((RXON_RX_CHAIN_A_MSK |
6184 		    RXON_RX_CHAIN_B_MSK) <<
6185 		    RXON_RX_CHAIN_FORCE_MIMO_SEL_POS);
6186 	}
6187 
6188 	sc->sc_config.rx_chain |= LE_16(RXON_RX_CHAIN_DRIVER_FORCE_MSK);
6189 
6190 	if ((in != NULL) &&
6191 	    (in->in_flags & IEEE80211_NODE_HT) &&
6192 	    sc->sc_ht_conf.ht_support) {
6193 		if (3 == sc->sc_ht_conf.valid_chains) {
6194 			sc->sc_config.rx_chain |= LE_16(3 <<
6195 			    RXON_RX_CHAIN_CNT_POS);
6196 			sc->sc_config.rx_chain |= LE_16(3 <<
6197 			    RXON_RX_CHAIN_MIMO_CNT_POS);
6198 		} else {
6199 			sc->sc_config.rx_chain |= LE_16(2 <<
6200 			    RXON_RX_CHAIN_CNT_POS);
6201 			sc->sc_config.rx_chain |= LE_16(2 <<
6202 			    RXON_RX_CHAIN_MIMO_CNT_POS);
6203 		}
6204 
6205 		sc->sc_config.rx_chain |= LE_16(1 <<
6206 		    RXON_RX_CHAIN_MIMO_FORCE_POS);
6207 	}
6208 
6209 	IWH_DBG((IWH_DEBUG_RXON, "iwh_config_rxon_chain(): "
6210 	    "rxon->rx_chain = %x\n", sc->sc_config.rx_chain));
6211 }
6212 
6213 /*
6214  * This function adds AP station into hardware.
6215  */
6216 static int
6217 iwh_add_ap_sta(iwh_sc_t *sc)
6218 {
6219 	ieee80211com_t *ic = &sc->sc_ic;
6220 	ieee80211_node_t *in = ic->ic_bss;
6221 	iwh_add_sta_t node;
6222 	uint32_t ampdu_factor, ampdu_density;
6223 	int err = IWH_FAIL;
6224 
6225 	/*
6226 	 * Add AP node into hardware.
6227 	 */
6228 	(void) memset(&node, 0, sizeof (node));
6229 	IEEE80211_ADDR_COPY(node.sta.addr, in->in_bssid);
6230 	node.mode = STA_MODE_ADD_MSK;
6231 	node.sta.sta_id = IWH_AP_ID;
6232 
6233 	if (sc->sc_ht_conf.ht_support &&
6234 	    (in->in_htcap_ie != NULL) &&
6235 	    (in->in_htcap != 0) &&
6236 	    (in->in_htparam != 0)) {
6237 
6238 		if (((in->in_htcap & HT_CAP_MIMO_PS) >> 2)
6239 		    == HT_CAP_MIMO_PS_DYNAMIC) {
6240 			node.station_flags |= LE_32(STA_FLG_RTS_MIMO_PROT);
6241 		}
6242 
6243 		ampdu_factor = in->in_htparam & HT_RX_AMPDU_FACTOR_MSK;
6244 		node.station_flags |=
6245 		    LE_32(ampdu_factor << STA_FLG_MAX_AMPDU_POS);
6246 
6247 		ampdu_density = (in->in_htparam & HT_MPDU_DENSITY_MSK) >>
6248 		    HT_MPDU_DENSITY_POS;
6249 		node.station_flags |=
6250 		    LE_32(ampdu_density << STA_FLG_AMPDU_DENSITY_POS);
6251 
6252 		if (in->in_htcap & LE_16(HT_CAP_SUP_WIDTH)) {
6253 			node.station_flags |=
6254 			    LE_32(STA_FLG_FAT_EN);
6255 		}
6256 	}
6257 
6258 	err = iwh_cmd(sc, REPLY_ADD_STA, &node, sizeof (node), 1);
6259 	if (err != IWH_SUCCESS) {
6260 		cmn_err(CE_WARN, "iwh_add_ap_lq(): "
6261 		    "failed to add AP node\n");
6262 		return (err);
6263 	}
6264 
6265 	return (err);
6266 }
6267 
6268 /*
6269  * Each station in the Shirley Peak's internal station table has
6270  * its own table of 16 TX rates and modulation modes for retrying
6271  * TX when an ACK is not received. This function replaces the entire
6272  * table for one station.Station must already be in Shirley Peak's
6273  * station talbe.
6274  */
6275 static int
6276 iwh_ap_lq(iwh_sc_t *sc)
6277 {
6278 	ieee80211com_t *ic = &sc->sc_ic;
6279 	ieee80211_node_t *in = ic->ic_bss;
6280 	iwh_link_quality_cmd_t link_quality;
6281 	const struct ieee80211_rateset *rs_sup = NULL;
6282 	uint32_t masks = 0, rate;
6283 	int i, err = IWH_FAIL;
6284 
6285 	/*
6286 	 * TX_LINK_QUALITY cmd
6287 	 */
6288 	(void) memset(&link_quality, 0, sizeof (link_quality));
6289 	if (in->in_chan == IEEE80211_CHAN_ANYC)	/* skip null node */
6290 		return (err);
6291 	rs_sup = ieee80211_get_suprates(ic, in->in_chan);
6292 
6293 	for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) {
6294 		if (i < rs_sup->ir_nrates) {
6295 			rate = rs_sup->ir_rates[rs_sup->ir_nrates - i] &
6296 			    IEEE80211_RATE_VAL;
6297 		} else {
6298 			rate = 2;
6299 		}
6300 
6301 		if (2 == rate || 4 == rate ||
6302 		    11 == rate || 22 == rate) {
6303 			masks |= LE_32(RATE_MCS_CCK_MSK);
6304 		}
6305 
6306 		masks |= LE_32(RATE_MCS_ANT_B_MSK);
6307 
6308 		link_quality.rate_n_flags[i] =
6309 		    LE_32(iwh_rate_to_plcp(rate) | masks);
6310 	}
6311 
6312 	link_quality.general_params.single_stream_ant_msk = LINK_QUAL_ANT_B_MSK;
6313 	link_quality.general_params.dual_stream_ant_msk = LINK_QUAL_ANT_MSK;
6314 	link_quality.agg_params.agg_dis_start_th = 3;
6315 	link_quality.agg_params.agg_time_limit = LE_16(4000);
6316 	link_quality.sta_id = IWH_AP_ID;
6317 	err = iwh_cmd(sc, REPLY_TX_LINK_QUALITY_CMD, &link_quality,
6318 	    sizeof (link_quality), 1);
6319 	if (err != IWH_SUCCESS) {
6320 		cmn_err(CE_WARN, "iwh_ap_lq(): "
6321 		    "failed to config link quality table\n");
6322 		return (err);
6323 	}
6324 
6325 #ifdef	DEBUG
6326 	IWH_DBG((IWH_DEBUG_HWRATE, "iwh_ap_lq(): "
6327 	    "Rates in HW are as follows:\n"));
6328 
6329 	for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) {
6330 		IWH_DBG((IWH_DEBUG_HWRATE,
6331 		    "Rate %d in HW is %x\n", i, link_quality.rate_n_flags[i]));
6332 	}
6333 #endif
6334 
6335 	return (err);
6336 }
6337 
6338 /*
6339  * When block ACK agreement has been set up between station and AP,
6340  * Net80211 module will call this function to inform hardware about
6341  * informations of this BA agreement.
6342  * When AP wants to delete BA agreement that was originated by it,
6343  * Net80211 modele will call this function to clean up relevant
6344  * information in hardware.
6345  */
6346 static void
6347 iwh_recv_action(struct ieee80211_node *in,
6348     const uint8_t *frm, const uint8_t *efrm)
6349 {
6350 	struct ieee80211com *ic;
6351 	iwh_sc_t *sc;
6352 	const struct ieee80211_action *ia;
6353 	uint16_t baparamset, baseqctl;
6354 	uint32_t tid, ssn;
6355 	iwh_add_sta_t node;
6356 	int err = IWH_FAIL;
6357 
6358 	if ((NULL == in) || (NULL == frm)) {
6359 		return;
6360 	}
6361 
6362 	ic = in->in_ic;
6363 	if (NULL == ic) {
6364 		return;
6365 	}
6366 
6367 	sc = (iwh_sc_t *)ic;
6368 
6369 	sc->sc_recv_action(in, frm, efrm);
6370 
6371 	ia = (const struct ieee80211_action *)frm;
6372 	if (ia->ia_category != IEEE80211_ACTION_CAT_BA) {
6373 		return;
6374 	}
6375 
6376 	switch (ia->ia_action) {
6377 	case IEEE80211_ACTION_BA_ADDBA_REQUEST:
6378 		baparamset = *(uint16_t *)(frm + 3);
6379 		baseqctl = *(uint16_t *)(frm + 7);
6380 
6381 		tid = MS(baparamset, IEEE80211_BAPS_TID);
6382 		ssn = MS(baseqctl, IEEE80211_BASEQ_START);
6383 
6384 		(void) memset(&node, 0, sizeof (node));
6385 		IEEE80211_ADDR_COPY(node.sta.addr, in->in_bssid);
6386 		node.mode = STA_MODE_MODIFY_MSK;
6387 		node.sta.sta_id = IWH_AP_ID;
6388 
6389 		node.station_flags_msk = 0;
6390 		node.sta.modify_mask = STA_MODIFY_ADDBA_TID_MSK;
6391 		node.add_immediate_ba_tid = (uint8_t)tid;
6392 		node.add_immediate_ba_ssn = LE_16(ssn);
6393 
6394 		mutex_enter(&sc->sc_glock);
6395 		err = iwh_cmd(sc, REPLY_ADD_STA, &node, sizeof (node), 1);
6396 		if (err != IWH_SUCCESS) {
6397 			cmn_err(CE_WARN, "iwh_recv_action(): "
6398 			    "failed to setup RX block ACK\n");
6399 			mutex_exit(&sc->sc_glock);
6400 			return;
6401 		}
6402 		mutex_exit(&sc->sc_glock);
6403 
6404 		IWH_DBG((IWH_DEBUG_BA, "iwh_recv_action(): "
6405 		    "RX block ACK "
6406 		    "was setup on TID %d and SSN is %d.\n", tid, ssn));
6407 
6408 		return;
6409 
6410 	case IEEE80211_ACTION_BA_DELBA:
6411 		baparamset = *(uint16_t *)(frm + 2);
6412 
6413 		if ((baparamset & IEEE80211_DELBAPS_INIT) == 0) {
6414 			return;
6415 		}
6416 
6417 		tid = MS(baparamset, IEEE80211_DELBAPS_TID);
6418 
6419 		(void) memset(&node, 0, sizeof (node));
6420 		IEEE80211_ADDR_COPY(node.sta.addr, in->in_bssid);
6421 		node.mode = STA_MODE_MODIFY_MSK;
6422 		node.sta.sta_id = IWH_AP_ID;
6423 
6424 		node.station_flags_msk = 0;
6425 		node.sta.modify_mask = STA_MODIFY_DELBA_TID_MSK;
6426 		node.add_immediate_ba_tid = (uint8_t)tid;
6427 
6428 		mutex_enter(&sc->sc_glock);
6429 		err = iwh_cmd(sc, REPLY_ADD_STA, &node, sizeof (node), 1);
6430 		if (err != IWH_SUCCESS) {
6431 			cmn_err(CE_WARN, "iwh_recv_action(): "
6432 			    "failed to delete RX block ACK\n");
6433 			mutex_exit(&sc->sc_glock);
6434 			return;
6435 		}
6436 		mutex_exit(&sc->sc_glock);
6437 
6438 		IWH_DBG((IWH_DEBUG_BA, "iwh_recv_action(): "
6439 		    "RX block ACK "
6440 		    "was deleted on TID %d.\n", tid));
6441 
6442 		return;
6443 	}
6444 }
6445 
6446 /*
6447  * When local station wants to delete BA agreement that was originated by AP,
6448  * Net80211 module will call this function to clean up relevant information
6449  * in hardware.
6450  */
6451 static int
6452 iwh_send_action(struct ieee80211_node *in,
6453     int category, int action, uint16_t args[4])
6454 {
6455 	struct ieee80211com *ic;
6456 	iwh_sc_t *sc;
6457 	uint32_t tid;
6458 	iwh_add_sta_t node;
6459 	int ret = EIO;
6460 	int err = IWH_FAIL;
6461 
6462 
6463 	if (NULL == in) {
6464 		return (ret);
6465 	}
6466 
6467 	ic = in->in_ic;
6468 	if (NULL == ic) {
6469 		return (ret);
6470 	}
6471 
6472 	sc = (iwh_sc_t *)ic;
6473 
6474 	ret = sc->sc_send_action(in, category, action, args);
6475 
6476 	if (category != IEEE80211_ACTION_CAT_BA) {
6477 		return (ret);
6478 	}
6479 
6480 	switch (action) {
6481 	case IEEE80211_ACTION_BA_DELBA:
6482 		if (IEEE80211_DELBAPS_INIT == args[1]) {
6483 			return (ret);
6484 		}
6485 
6486 		tid = args[0];
6487 
6488 		(void) memset(&node, 0, sizeof (node));
6489 		IEEE80211_ADDR_COPY(node.sta.addr, in->in_bssid);
6490 		node.mode = STA_MODE_MODIFY_MSK;
6491 		node.sta.sta_id = IWH_AP_ID;
6492 
6493 		node.station_flags_msk = 0;
6494 		node.sta.modify_mask = STA_MODIFY_DELBA_TID_MSK;
6495 		node.add_immediate_ba_tid = (uint8_t)tid;
6496 
6497 		mutex_enter(&sc->sc_glock);
6498 		err = iwh_cmd(sc, REPLY_ADD_STA, &node, sizeof (node), 1);
6499 		if (err != IWH_SUCCESS) {
6500 			cmn_err(CE_WARN, "iwh_send_action(): "
6501 			    "failed to delete RX balock ACK\n");
6502 			mutex_exit(&sc->sc_glock);
6503 			return (EIO);
6504 		}
6505 		mutex_exit(&sc->sc_glock);
6506 
6507 		IWH_DBG((IWH_DEBUG_BA, "iwh_send_action(): "
6508 		    "RX block ACK "
6509 		    "was deleted on TID %d.\n", tid));
6510 
6511 		break;
6512 	}
6513 
6514 	return (ret);
6515 }
6516