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