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