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