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