xref: /titanic_44/usr/src/uts/common/io/iwk/iwk2.c (revision 3e7352aecf183df6c5f819be775df62aadcdfd08)
1 /*
2  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 /*
7  * Copyright (c) 2007, 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  * Driver for Intel PRO/Wireless 4965AGN(kedron) 802.11 network adapters.
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 "iwk_calibration.h"
60 #include "iwk_hw.h"
61 #include "iwk_eeprom.h"
62 #include "iwk2_var.h"
63 #include <inet/wifi_ioctl.h>
64 
65 #ifdef DEBUG
66 #define	IWK_DEBUG_80211		(1 << 0)
67 #define	IWK_DEBUG_CMD		(1 << 1)
68 #define	IWK_DEBUG_DMA		(1 << 2)
69 #define	IWK_DEBUG_EEPROM	(1 << 3)
70 #define	IWK_DEBUG_FW		(1 << 4)
71 #define	IWK_DEBUG_HW		(1 << 5)
72 #define	IWK_DEBUG_INTR		(1 << 6)
73 #define	IWK_DEBUG_MRR		(1 << 7)
74 #define	IWK_DEBUG_PIO		(1 << 8)
75 #define	IWK_DEBUG_RX		(1 << 9)
76 #define	IWK_DEBUG_SCAN		(1 << 10)
77 #define	IWK_DEBUG_TX		(1 << 11)
78 #define	IWK_DEBUG_RATECTL	(1 << 12)
79 #define	IWK_DEBUG_RADIO		(1 << 13)
80 #define	IWK_DEBUG_RESUME	(1 << 14)
81 #define	IWK_DEBUG_CALIBRATION	(1 << 15)
82 uint32_t iwk_dbg_flags = 0;
83 #define	IWK_DBG(x) \
84 	iwk_dbg x
85 #else
86 #define	IWK_DBG(x)
87 #endif
88 
89 static void	*iwk_soft_state_p = NULL;
90 static uint8_t iwk_fw_bin [] = {
91 #include "fw-iw/iw4965.ucode.hex"
92 };
93 
94 /* DMA attributes for a shared page */
95 static ddi_dma_attr_t sh_dma_attr = {
96 	DMA_ATTR_V0,	/* version of this structure */
97 	0,		/* lowest usable address */
98 	0xffffffffU,	/* highest usable address */
99 	0xffffffffU,	/* maximum DMAable byte count */
100 	0x1000,		/* alignment in bytes */
101 	0x1000,		/* burst sizes (any?) */
102 	1,		/* minimum transfer */
103 	0xffffffffU,	/* maximum transfer */
104 	0xffffffffU,	/* maximum segment length */
105 	1,		/* maximum number of segments */
106 	1,		/* granularity */
107 	0,		/* flags (reserved) */
108 };
109 
110 /* DMA attributes for a keep warm DRAM descriptor */
111 static ddi_dma_attr_t kw_dma_attr = {
112 	DMA_ATTR_V0,	/* version of this structure */
113 	0,		/* lowest usable address */
114 	0xffffffffU,	/* highest usable address */
115 	0xffffffffU,	/* maximum DMAable byte count */
116 	0x1000,		/* alignment in bytes */
117 	0x1000,		/* burst sizes (any?) */
118 	1,		/* minimum transfer */
119 	0xffffffffU,	/* maximum transfer */
120 	0xffffffffU,	/* maximum segment length */
121 	1,		/* maximum number of segments */
122 	1,		/* granularity */
123 	0,		/* flags (reserved) */
124 };
125 
126 /* DMA attributes for a ring descriptor */
127 static ddi_dma_attr_t ring_desc_dma_attr = {
128 	DMA_ATTR_V0,	/* version of this structure */
129 	0,		/* lowest usable address */
130 	0xffffffffU,	/* highest usable address */
131 	0xffffffffU,	/* maximum DMAable byte count */
132 	0x100,		/* alignment in bytes */
133 	0x100,		/* burst sizes (any?) */
134 	1,		/* minimum transfer */
135 	0xffffffffU,	/* maximum transfer */
136 	0xffffffffU,	/* maximum segment length */
137 	1,		/* maximum number of segments */
138 	1,		/* granularity */
139 	0,		/* flags (reserved) */
140 };
141 
142 /* DMA attributes for a cmd */
143 static ddi_dma_attr_t cmd_dma_attr = {
144 	DMA_ATTR_V0,	/* version of this structure */
145 	0,		/* lowest usable address */
146 	0xffffffffU,	/* highest usable address */
147 	0xffffffffU,	/* maximum DMAable byte count */
148 	4,		/* alignment in bytes */
149 	0x100,		/* burst sizes (any?) */
150 	1,		/* minimum transfer */
151 	0xffffffffU,	/* maximum transfer */
152 	0xffffffffU,	/* maximum segment length */
153 	1,		/* maximum number of segments */
154 	1,		/* granularity */
155 	0,		/* flags (reserved) */
156 };
157 
158 /* DMA attributes for a rx buffer */
159 static ddi_dma_attr_t rx_buffer_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 	0x100,		/* 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 tx buffer.
176  * the maximum number of segments is 4 for the hardware.
177  * now all the wifi drivers put the whole frame in a single
178  * descriptor, so we define the maximum  number of segments 1,
179  * just the same as the rx_buffer. we consider leverage the HW
180  * ability in the future, that is why we don't define rx and tx
181  * buffer_dma_attr as the same.
182  */
183 static ddi_dma_attr_t tx_buffer_dma_attr = {
184 	DMA_ATTR_V0,	/* version of this structure */
185 	0,		/* lowest usable address */
186 	0xffffffffU,	/* highest usable address */
187 	0xffffffffU,	/* maximum DMAable byte count */
188 	4,		/* alignment in bytes */
189 	0x100,		/* burst sizes (any?) */
190 	1,		/* minimum transfer */
191 	0xffffffffU,	/* maximum transfer */
192 	0xffffffffU,	/* maximum segment length */
193 	1,		/* maximum number of segments */
194 	1,		/* granularity */
195 	0,		/* flags (reserved) */
196 };
197 
198 /* DMA attributes for text and data part in the firmware */
199 static ddi_dma_attr_t fw_dma_attr = {
200 	DMA_ATTR_V0,	/* version of this structure */
201 	0,		/* lowest usable address */
202 	0xffffffffU,	/* highest usable address */
203 	0x7fffffff,	/* maximum DMAable byte count */
204 	0x10,		/* alignment in bytes */
205 	0x100,		/* burst sizes (any?) */
206 	1,		/* minimum transfer */
207 	0xffffffffU,	/* maximum transfer */
208 	0xffffffffU,	/* maximum segment length */
209 	1,		/* maximum number of segments */
210 	1,		/* granularity */
211 	0,		/* flags (reserved) */
212 };
213 
214 
215 /* regs access attributes */
216 static ddi_device_acc_attr_t iwk_reg_accattr = {
217 	DDI_DEVICE_ATTR_V0,
218 	DDI_STRUCTURE_LE_ACC,
219 	DDI_STRICTORDER_ACC,
220 	DDI_DEFAULT_ACC
221 };
222 
223 /* DMA access attributes */
224 static ddi_device_acc_attr_t iwk_dma_accattr = {
225 	DDI_DEVICE_ATTR_V0,
226 	DDI_NEVERSWAP_ACC,
227 	DDI_STRICTORDER_ACC,
228 	DDI_DEFAULT_ACC
229 };
230 
231 static int	iwk_ring_init(iwk_sc_t *);
232 static void	iwk_ring_free(iwk_sc_t *);
233 static int	iwk_alloc_shared(iwk_sc_t *);
234 static void	iwk_free_shared(iwk_sc_t *);
235 static int	iwk_alloc_kw(iwk_sc_t *);
236 static void	iwk_free_kw(iwk_sc_t *);
237 static int	iwk_alloc_fw_dma(iwk_sc_t *);
238 static void	iwk_free_fw_dma(iwk_sc_t *);
239 static int	iwk_alloc_rx_ring(iwk_sc_t *);
240 static void	iwk_reset_rx_ring(iwk_sc_t *);
241 static void	iwk_free_rx_ring(iwk_sc_t *);
242 static int	iwk_alloc_tx_ring(iwk_sc_t *, iwk_tx_ring_t *,
243     int, int);
244 static void	iwk_reset_tx_ring(iwk_sc_t *, iwk_tx_ring_t *);
245 static void	iwk_free_tx_ring(iwk_sc_t *, iwk_tx_ring_t *);
246 
247 static ieee80211_node_t *iwk_node_alloc(ieee80211com_t *);
248 static void	iwk_node_free(ieee80211_node_t *);
249 static int	iwk_newstate(ieee80211com_t *, enum ieee80211_state, int);
250 static int	iwk_key_set(ieee80211com_t *, const struct ieee80211_key *,
251     const uint8_t mac[IEEE80211_ADDR_LEN]);
252 static void	iwk_mac_access_enter(iwk_sc_t *);
253 static void	iwk_mac_access_exit(iwk_sc_t *);
254 static uint32_t	iwk_reg_read(iwk_sc_t *, uint32_t);
255 static void	iwk_reg_write(iwk_sc_t *, uint32_t, uint32_t);
256 static void	iwk_reg_write_region_4(iwk_sc_t *, uint32_t,
257 		    uint32_t *, int);
258 static int	iwk_load_firmware(iwk_sc_t *);
259 static void	iwk_rx_intr(iwk_sc_t *, iwk_rx_desc_t *,
260 		    iwk_rx_data_t *);
261 static void	iwk_tx_intr(iwk_sc_t *, iwk_rx_desc_t *,
262 		    iwk_rx_data_t *);
263 static void	iwk_cmd_intr(iwk_sc_t *, iwk_rx_desc_t *);
264 static uint_t   iwk_intr(caddr_t, caddr_t);
265 static int	iwk_eep_load(iwk_sc_t *sc);
266 static void	iwk_get_mac_from_eep(iwk_sc_t *sc);
267 static int	iwk_eep_sem_down(iwk_sc_t *sc);
268 static void	iwk_eep_sem_up(iwk_sc_t *sc);
269 static uint_t   iwk_rx_softintr(caddr_t, caddr_t);
270 static uint8_t	iwk_rate_to_plcp(int);
271 static int	iwk_cmd(iwk_sc_t *, int, const void *, int, int);
272 static void	iwk_set_led(iwk_sc_t *, uint8_t, uint8_t, uint8_t);
273 static int	iwk_hw_set_before_auth(iwk_sc_t *);
274 static int	iwk_scan(iwk_sc_t *);
275 static int	iwk_config(iwk_sc_t *);
276 static void	iwk_stop_master(iwk_sc_t *);
277 static int	iwk_power_up(iwk_sc_t *);
278 static int	iwk_preinit(iwk_sc_t *);
279 static int	iwk_init(iwk_sc_t *);
280 static void	iwk_stop(iwk_sc_t *);
281 static void	iwk_amrr_init(iwk_amrr_t *);
282 static void	iwk_amrr_timeout(iwk_sc_t *);
283 static void	iwk_amrr_ratectl(void *, ieee80211_node_t *);
284 static int32_t	iwk_curr_tempera(iwk_sc_t *sc);
285 static int	iwk_tx_power_calibration(iwk_sc_t *sc);
286 static inline int	iwk_is_24G_band(iwk_sc_t *sc);
287 static inline int	iwk_is_fat_channel(iwk_sc_t *sc);
288 static int	iwk_txpower_grp(uint16_t channel);
289 static struct	iwk_eep_channel *iwk_get_eep_channel(iwk_sc_t *sc,
290     uint16_t channel,
291     int is_24G, int is_fat, int is_hi_chan);
292 static int32_t	iwk_band_number(iwk_sc_t *sc, uint16_t channel);
293 static int	iwk_division(int32_t num, int32_t denom, int32_t *res);
294 static int32_t	iwk_interpolate_value(int32_t x, int32_t x1, int32_t y1,
295     int32_t x2, int32_t y2);
296 static int	iwk_channel_interpolate(iwk_sc_t *sc, uint16_t channel,
297     struct iwk_eep_calib_channel_info *chan_info);
298 static int32_t	iwk_voltage_compensation(int32_t eep_voltage,
299     int32_t curr_voltage);
300 static int32_t	iwk_min_power_index(int32_t rate_pow_idx, int32_t is_24G);
301 static int	iwk_txpower_table_cmd_init(iwk_sc_t *sc,
302     struct iwk_tx_power_db *tp_db);
303 static void	iwk_statistics_notify(iwk_sc_t *sc, iwk_rx_desc_t *desc);
304 static int	iwk_is_associated(iwk_sc_t *sc);
305 static int	iwk_rxgain_diff_init(iwk_sc_t *sc);
306 static int	iwk_rxgain_diff(iwk_sc_t *sc);
307 static int	iwk_rx_sens_init(iwk_sc_t *sc);
308 static int	iwk_rx_sens(iwk_sc_t *sc);
309 static int	iwk_cck_sens(iwk_sc_t *sc, uint32_t actual_rx_time);
310 static int	iwk_ofdm_sens(iwk_sc_t *sc, uint32_t actual_rx_time);
311 
312 static void	iwk_write_event_log(iwk_sc_t *);
313 static void	iwk_write_error_log(iwk_sc_t *);
314 
315 static int	iwk_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
316 static int	iwk_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
317 static int	iwk_quiesce(dev_info_t *dip);
318 
319 /*
320  * GLD specific operations
321  */
322 static int	iwk_m_stat(void *arg, uint_t stat, uint64_t *val);
323 static int	iwk_m_start(void *arg);
324 static void	iwk_m_stop(void *arg);
325 static int	iwk_m_unicst(void *arg, const uint8_t *macaddr);
326 static int	iwk_m_multicst(void *arg, boolean_t add, const uint8_t *m);
327 static int	iwk_m_promisc(void *arg, boolean_t on);
328 static mblk_t 	*iwk_m_tx(void *arg, mblk_t *mp);
329 static void	iwk_m_ioctl(void *arg, queue_t *wq, mblk_t *mp);
330 static int	iwk_m_setprop(void *arg, const char *pr_name,
331 	mac_prop_id_t wldp_pr_name, uint_t wldp_length, const void *wldp_buf);
332 static int	iwk_m_getprop(void *arg, const char *pr_name,
333 	mac_prop_id_t wldp_pr_name, uint_t pr_flags, uint_t wldp_length,
334 	void *wldp_buf, uint_t *perm);
335 static void	iwk_destroy_locks(iwk_sc_t *sc);
336 static int	iwk_send(ieee80211com_t *ic, mblk_t *mp, uint8_t type);
337 static void	iwk_thread(iwk_sc_t *sc);
338 
339 /*
340  * Supported rates for 802.11b/g modes (in 500Kbps unit).
341  * 11a and 11n support will be added later.
342  */
343 static const struct ieee80211_rateset iwk_rateset_11b =
344 	{ 4, { 2, 4, 11, 22 } };
345 
346 static const struct ieee80211_rateset iwk_rateset_11g =
347 	{ 12, { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 } };
348 
349 /*
350  * For mfthread only
351  */
352 extern pri_t minclsyspri;
353 
354 #define	DRV_NAME_4965	"iwk"
355 
356 /*
357  * Module Loading Data & Entry Points
358  */
359 DDI_DEFINE_STREAM_OPS(iwk_devops, nulldev, nulldev, iwk_attach,
360     iwk_detach, nodev, NULL, D_MP, NULL, iwk_quiesce);
361 
362 static struct modldrv iwk_modldrv = {
363 	&mod_driverops,
364 	"Intel(R) 4965AGN driver(N)",
365 	&iwk_devops
366 };
367 
368 static struct modlinkage iwk_modlinkage = {
369 	MODREV_1,
370 	&iwk_modldrv,
371 	NULL
372 };
373 
374 int
375 _init(void)
376 {
377 	int	status;
378 
379 	status = ddi_soft_state_init(&iwk_soft_state_p,
380 	    sizeof (iwk_sc_t), 1);
381 	if (status != DDI_SUCCESS)
382 		return (status);
383 
384 	mac_init_ops(&iwk_devops, DRV_NAME_4965);
385 	status = mod_install(&iwk_modlinkage);
386 	if (status != DDI_SUCCESS) {
387 		mac_fini_ops(&iwk_devops);
388 		ddi_soft_state_fini(&iwk_soft_state_p);
389 	}
390 
391 	return (status);
392 }
393 
394 int
395 _fini(void)
396 {
397 	int status;
398 
399 	status = mod_remove(&iwk_modlinkage);
400 	if (status == DDI_SUCCESS) {
401 		mac_fini_ops(&iwk_devops);
402 		ddi_soft_state_fini(&iwk_soft_state_p);
403 	}
404 
405 	return (status);
406 }
407 
408 int
409 _info(struct modinfo *mip)
410 {
411 	return (mod_info(&iwk_modlinkage, mip));
412 }
413 
414 /*
415  * Mac Call Back entries
416  */
417 mac_callbacks_t	iwk_m_callbacks = {
418 	MC_IOCTL | MC_SETPROP | MC_GETPROP,
419 	iwk_m_stat,
420 	iwk_m_start,
421 	iwk_m_stop,
422 	iwk_m_promisc,
423 	iwk_m_multicst,
424 	iwk_m_unicst,
425 	iwk_m_tx,
426 	NULL,
427 	iwk_m_ioctl,
428 	NULL,
429 	NULL,
430 	NULL,
431 	iwk_m_setprop,
432 	iwk_m_getprop
433 };
434 
435 #ifdef DEBUG
436 void
437 iwk_dbg(uint32_t flags, const char *fmt, ...)
438 {
439 	va_list	ap;
440 
441 	if (flags & iwk_dbg_flags) {
442 		va_start(ap, fmt);
443 		vcmn_err(CE_NOTE, fmt, ap);
444 		va_end(ap);
445 	}
446 }
447 #endif
448 
449 /*
450  * device operations
451  */
452 int
453 iwk_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
454 {
455 	iwk_sc_t		*sc;
456 	ieee80211com_t	*ic;
457 	int			instance, err, i;
458 	char			strbuf[32];
459 	wifi_data_t		wd = { 0 };
460 	mac_register_t		*macp;
461 
462 	int			intr_type;
463 	int			intr_count;
464 	int			intr_actual;
465 
466 	switch (cmd) {
467 	case DDI_ATTACH:
468 		break;
469 	case DDI_RESUME:
470 		sc = ddi_get_soft_state(iwk_soft_state_p,
471 		    ddi_get_instance(dip));
472 		ASSERT(sc != NULL);
473 		mutex_enter(&sc->sc_glock);
474 		sc->sc_flags &= ~IWK_F_SUSPEND;
475 		mutex_exit(&sc->sc_glock);
476 		if (sc->sc_flags & IWK_F_RUNNING) {
477 			(void) iwk_init(sc);
478 			ieee80211_new_state(&sc->sc_ic, IEEE80211_S_INIT, -1);
479 		}
480 		IWK_DBG((IWK_DEBUG_RESUME, "iwk: resume\n"));
481 		return (DDI_SUCCESS);
482 	default:
483 		err = DDI_FAILURE;
484 		goto attach_fail1;
485 	}
486 
487 	instance = ddi_get_instance(dip);
488 	err = ddi_soft_state_zalloc(iwk_soft_state_p, instance);
489 	if (err != DDI_SUCCESS) {
490 		cmn_err(CE_WARN,
491 		    "iwk_attach(): failed to allocate soft state\n");
492 		goto attach_fail1;
493 	}
494 	sc = ddi_get_soft_state(iwk_soft_state_p, instance);
495 	sc->sc_dip = dip;
496 
497 	err = ddi_regs_map_setup(dip, 0, &sc->sc_cfg_base, 0, 0,
498 	    &iwk_reg_accattr, &sc->sc_cfg_handle);
499 	if (err != DDI_SUCCESS) {
500 		cmn_err(CE_WARN,
501 		    "iwk_attach(): failed to map config spaces regs\n");
502 		goto attach_fail2;
503 	}
504 	sc->sc_rev = ddi_get8(sc->sc_cfg_handle,
505 	    (uint8_t *)(sc->sc_cfg_base + PCI_CONF_REVID));
506 	ddi_put8(sc->sc_cfg_handle, (uint8_t *)(sc->sc_cfg_base + 0x41), 0);
507 	sc->sc_clsz = ddi_get16(sc->sc_cfg_handle,
508 	    (uint16_t *)(sc->sc_cfg_base + PCI_CONF_CACHE_LINESZ));
509 	if (!sc->sc_clsz)
510 		sc->sc_clsz = 16;
511 	sc->sc_clsz = (sc->sc_clsz << 2);
512 	sc->sc_dmabuf_sz = roundup(0x1000 + sizeof (struct ieee80211_frame) +
513 	    IEEE80211_MTU + IEEE80211_CRC_LEN +
514 	    (IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN +
515 	    IEEE80211_WEP_CRCLEN), sc->sc_clsz);
516 	/*
517 	 * Map operating registers
518 	 */
519 	err = ddi_regs_map_setup(dip, 1, &sc->sc_base,
520 	    0, 0, &iwk_reg_accattr, &sc->sc_handle);
521 	if (err != DDI_SUCCESS) {
522 		cmn_err(CE_WARN,
523 		    "iwk_attach(): failed to map device regs\n");
524 		goto attach_fail2a;
525 	}
526 
527 	err = ddi_intr_get_supported_types(dip, &intr_type);
528 	if ((err != DDI_SUCCESS) || (!(intr_type & DDI_INTR_TYPE_FIXED))) {
529 		cmn_err(CE_WARN, "iwk_attach(): "
530 		    "Fixed type interrupt is not supported\n");
531 		goto attach_fail_intr_a;
532 	}
533 
534 	err = ddi_intr_get_nintrs(dip, DDI_INTR_TYPE_FIXED, &intr_count);
535 	if ((err != DDI_SUCCESS) || (intr_count != 1)) {
536 		cmn_err(CE_WARN, "iwk_attach(): "
537 		    "No fixed interrupts\n");
538 		goto attach_fail_intr_a;
539 	}
540 
541 	sc->sc_intr_htable = kmem_zalloc(sizeof (ddi_intr_handle_t), KM_SLEEP);
542 
543 	err = ddi_intr_alloc(dip, sc->sc_intr_htable, DDI_INTR_TYPE_FIXED, 0,
544 	    intr_count, &intr_actual, 0);
545 	if ((err != DDI_SUCCESS) || (intr_actual != 1)) {
546 		cmn_err(CE_WARN, "iwk_attach(): "
547 		    "ddi_intr_alloc() failed 0x%x\n", err);
548 		goto attach_fail_intr_b;
549 	}
550 
551 	err = ddi_intr_get_pri(sc->sc_intr_htable[0], &sc->sc_intr_pri);
552 	if (err != DDI_SUCCESS) {
553 		cmn_err(CE_WARN, "iwk_attach(): "
554 		    "ddi_intr_get_pri() failed 0x%x\n", err);
555 		goto attach_fail_intr_c;
556 	}
557 
558 	mutex_init(&sc->sc_glock, NULL, MUTEX_DRIVER,
559 	    DDI_INTR_PRI(sc->sc_intr_pri));
560 	mutex_init(&sc->sc_tx_lock, NULL, MUTEX_DRIVER,
561 	    DDI_INTR_PRI(sc->sc_intr_pri));
562 	mutex_init(&sc->sc_mt_lock, NULL, MUTEX_DRIVER,
563 	    DDI_INTR_PRI(sc->sc_intr_pri));
564 
565 	cv_init(&sc->sc_fw_cv, NULL, CV_DRIVER, NULL);
566 	cv_init(&sc->sc_cmd_cv, NULL, CV_DRIVER, NULL);
567 	cv_init(&sc->sc_tx_cv, "tx-ring", CV_DRIVER, NULL);
568 	/*
569 	 * initialize the mfthread
570 	 */
571 	cv_init(&sc->sc_mt_cv, NULL, CV_DRIVER, NULL);
572 	sc->sc_mf_thread = NULL;
573 	sc->sc_mf_thread_switch = 0;
574 
575 	/*
576 	 * Allocate shared page.
577 	 */
578 	err = iwk_alloc_shared(sc);
579 	if (err != DDI_SUCCESS) {
580 		cmn_err(CE_WARN, "iwk_attach(): "
581 		    "failed to allocate shared page\n");
582 		goto attach_fail3;
583 	}
584 
585 	/*
586 	 * Allocate keep warm page.
587 	 */
588 	err = iwk_alloc_kw(sc);
589 	if (err != DDI_SUCCESS) {
590 		cmn_err(CE_WARN, "iwk_attach(): "
591 		    "failed to allocate keep warm page\n");
592 		goto attach_fail3a;
593 	}
594 
595 	/*
596 	 * Do some necessary hardware initializations.
597 	 */
598 	err = iwk_preinit(sc);
599 	if (err != DDI_SUCCESS) {
600 		cmn_err(CE_WARN, "iwk_attach(): "
601 		    "failed to init hardware\n");
602 		goto attach_fail4;
603 	}
604 
605 	/* initialize EEPROM */
606 	err = iwk_eep_load(sc);  /* get hardware configurations from eeprom */
607 	if (err != 0) {
608 		cmn_err(CE_WARN, "iwk_attach(): failed to load eeprom\n");
609 		goto attach_fail4;
610 	}
611 
612 	if (sc->sc_eep_map.calib_version < EEP_TX_POWER_VERSION_NEW) {
613 		cmn_err(CE_WARN, "older EEPROM detected\n");
614 		goto attach_fail4;
615 	}
616 
617 	iwk_get_mac_from_eep(sc);
618 
619 	err = iwk_ring_init(sc);
620 	if (err != DDI_SUCCESS) {
621 		cmn_err(CE_WARN, "iwk_attach(): "
622 		    "failed to allocate and initialize ring\n");
623 		goto attach_fail4;
624 	}
625 
626 	sc->sc_hdr = (iwk_firmware_hdr_t *)iwk_fw_bin;
627 
628 	err = iwk_alloc_fw_dma(sc);
629 	if (err != DDI_SUCCESS) {
630 		cmn_err(CE_WARN, "iwk_attach(): "
631 		    "failed to allocate firmware dma\n");
632 		goto attach_fail5;
633 	}
634 
635 	/*
636 	 * Initialize the wifi part, which will be used by
637 	 * generic layer
638 	 */
639 	ic = &sc->sc_ic;
640 	ic->ic_phytype  = IEEE80211_T_OFDM;
641 	ic->ic_opmode   = IEEE80211_M_STA; /* default to BSS mode */
642 	ic->ic_state    = IEEE80211_S_INIT;
643 	ic->ic_maxrssi  = 100; /* experimental number */
644 	ic->ic_caps = IEEE80211_C_SHPREAMBLE | IEEE80211_C_TXPMGT |
645 	    IEEE80211_C_PMGT | IEEE80211_C_SHSLOT;
646 	/*
647 	 * use software WEP and TKIP, hardware CCMP;
648 	 */
649 	ic->ic_caps |= IEEE80211_C_AES_CCM;
650 	/*
651 	 * Support WPA/WPA2
652 	 */
653 	ic->ic_caps |= IEEE80211_C_WPA;
654 
655 	/* set supported .11b and .11g rates */
656 	ic->ic_sup_rates[IEEE80211_MODE_11B] = iwk_rateset_11b;
657 	ic->ic_sup_rates[IEEE80211_MODE_11G] = iwk_rateset_11g;
658 
659 	/* set supported .11b and .11g channels (1 through 11) */
660 	for (i = 1; i <= 11; i++) {
661 		ic->ic_sup_channels[i].ich_freq =
662 		    ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ);
663 		ic->ic_sup_channels[i].ich_flags =
664 		    IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM |
665 		    IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ |
666 		    IEEE80211_CHAN_PASSIVE;
667 	}
668 
669 	ic->ic_xmit = iwk_send;
670 	/*
671 	 * init Wifi layer
672 	 */
673 	ieee80211_attach(ic);
674 
675 	/*
676 	 * different instance has different WPA door
677 	 */
678 	(void) snprintf(ic->ic_wpadoor, MAX_IEEE80211STR, "%s_%s%d", WPA_DOOR,
679 	    ddi_driver_name(dip),
680 	    ddi_get_instance(dip));
681 
682 	/*
683 	 * Override 80211 default routines
684 	 */
685 	sc->sc_newstate = ic->ic_newstate;
686 	ic->ic_newstate = iwk_newstate;
687 	sc->sc_recv_mgmt = ic->ic_recv_mgmt;
688 	ic->ic_node_alloc = iwk_node_alloc;
689 	ic->ic_node_free = iwk_node_free;
690 	ic->ic_crypto.cs_key_set = iwk_key_set;
691 	ieee80211_media_init(ic);
692 	/*
693 	 * initialize default tx key
694 	 */
695 	ic->ic_def_txkey = 0;
696 	err = ddi_intr_add_softint(dip, &sc->sc_soft_hdl, DDI_INTR_SOFTPRI_MAX,
697 	    iwk_rx_softintr, (caddr_t)sc);
698 	if (err != DDI_SUCCESS) {
699 		cmn_err(CE_WARN, "iwk_attach(): "
700 		    "add soft interrupt failed\n");
701 		goto attach_fail7;
702 	}
703 
704 	/*
705 	 * Add the interrupt handler
706 	 */
707 	err = ddi_intr_add_handler(sc->sc_intr_htable[0], iwk_intr,
708 	    (caddr_t)sc, NULL);
709 	if (err != DDI_SUCCESS) {
710 		cmn_err(CE_WARN, "iwk_attach(): "
711 		    "ddi_intr_add_handle() failed\n");
712 		goto attach_fail8;
713 	}
714 
715 	err = ddi_intr_enable(sc->sc_intr_htable[0]);
716 	if (err != DDI_SUCCESS) {
717 		cmn_err(CE_WARN, "iwk_attach(): "
718 		    "ddi_intr_enable() failed\n");
719 		goto attach_fail_intr_d;
720 	}
721 
722 	/*
723 	 * Initialize pointer to device specific functions
724 	 */
725 	wd.wd_secalloc = WIFI_SEC_NONE;
726 	wd.wd_opmode = ic->ic_opmode;
727 	IEEE80211_ADDR_COPY(wd.wd_bssid, ic->ic_macaddr);
728 
729 	macp = mac_alloc(MAC_VERSION);
730 	if (err != DDI_SUCCESS) {
731 		cmn_err(CE_WARN,
732 		    "iwk_attach(): failed to do mac_alloc()\n");
733 		goto attach_fail9;
734 	}
735 
736 	macp->m_type_ident	= MAC_PLUGIN_IDENT_WIFI;
737 	macp->m_driver		= sc;
738 	macp->m_dip		= dip;
739 	macp->m_src_addr	= ic->ic_macaddr;
740 	macp->m_callbacks	= &iwk_m_callbacks;
741 	macp->m_min_sdu		= 0;
742 	macp->m_max_sdu		= IEEE80211_MTU;
743 	macp->m_pdata		= &wd;
744 	macp->m_pdata_size	= sizeof (wd);
745 
746 	/*
747 	 * Register the macp to mac
748 	 */
749 	err = mac_register(macp, &ic->ic_mach);
750 	mac_free(macp);
751 	if (err != DDI_SUCCESS) {
752 		cmn_err(CE_WARN,
753 		    "iwk_attach(): failed to do mac_register()\n");
754 		goto attach_fail9;
755 	}
756 
757 	/*
758 	 * Create minor node of type DDI_NT_NET_WIFI
759 	 */
760 	(void) snprintf(strbuf, sizeof (strbuf), DRV_NAME_4965"%d", instance);
761 	err = ddi_create_minor_node(dip, strbuf, S_IFCHR,
762 	    instance + 1, DDI_NT_NET_WIFI, 0);
763 	if (err != DDI_SUCCESS)
764 		cmn_err(CE_WARN,
765 		    "iwk_attach(): failed to do ddi_create_minor_node()\n");
766 
767 	/*
768 	 * Notify link is down now
769 	 */
770 	mac_link_update(ic->ic_mach, LINK_STATE_DOWN);
771 
772 	/*
773 	 * create the mf thread to handle the link status,
774 	 * recovery fatal error, etc.
775 	 */
776 	sc->sc_mf_thread_switch = 1;
777 	if (sc->sc_mf_thread == NULL)
778 		sc->sc_mf_thread = thread_create((caddr_t)NULL, 0,
779 		    iwk_thread, sc, 0, &p0, TS_RUN, minclsyspri);
780 
781 	sc->sc_flags |= IWK_F_ATTACHED;
782 
783 	return (DDI_SUCCESS);
784 attach_fail9:
785 	(void) ddi_intr_disable(sc->sc_intr_htable[0]);
786 attach_fail_intr_d:
787 	(void) ddi_intr_remove_handler(sc->sc_intr_htable[0]);
788 
789 attach_fail8:
790 	(void) ddi_intr_remove_softint(sc->sc_soft_hdl);
791 	sc->sc_soft_hdl = NULL;
792 attach_fail7:
793 	ieee80211_detach(ic);
794 attach_fail6:
795 	iwk_free_fw_dma(sc);
796 attach_fail5:
797 	iwk_ring_free(sc);
798 attach_fail4:
799 	iwk_free_kw(sc);
800 attach_fail3a:
801 	iwk_free_shared(sc);
802 attach_fail3:
803 	iwk_destroy_locks(sc);
804 attach_fail_intr_c:
805 	(void) ddi_intr_free(sc->sc_intr_htable[0]);
806 attach_fail_intr_b:
807 	kmem_free(sc->sc_intr_htable, sizeof (ddi_intr_handle_t));
808 attach_fail_intr_a:
809 	ddi_regs_map_free(&sc->sc_handle);
810 attach_fail2a:
811 	ddi_regs_map_free(&sc->sc_cfg_handle);
812 attach_fail2:
813 	ddi_soft_state_free(iwk_soft_state_p, instance);
814 attach_fail1:
815 	return (err);
816 }
817 
818 int
819 iwk_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
820 {
821 	iwk_sc_t	*sc;
822 	int err;
823 
824 	sc = ddi_get_soft_state(iwk_soft_state_p, ddi_get_instance(dip));
825 	ASSERT(sc != NULL);
826 
827 	switch (cmd) {
828 	case DDI_DETACH:
829 		break;
830 	case DDI_SUSPEND:
831 		if (sc->sc_flags & IWK_F_RUNNING) {
832 			iwk_stop(sc);
833 		}
834 		mutex_enter(&sc->sc_glock);
835 		sc->sc_flags |= IWK_F_SUSPEND;
836 		mutex_exit(&sc->sc_glock);
837 		IWK_DBG((IWK_DEBUG_RESUME, "iwk: suspend\n"));
838 		return (DDI_SUCCESS);
839 	default:
840 		return (DDI_FAILURE);
841 	}
842 
843 	if (!(sc->sc_flags & IWK_F_ATTACHED))
844 		return (DDI_FAILURE);
845 
846 	err = mac_disable(sc->sc_ic.ic_mach);
847 	if (err != DDI_SUCCESS)
848 		return (err);
849 
850 	/*
851 	 * Destroy the mf_thread
852 	 */
853 	mutex_enter(&sc->sc_mt_lock);
854 	sc->sc_mf_thread_switch = 0;
855 	while (sc->sc_mf_thread != NULL) {
856 		if (cv_wait_sig(&sc->sc_mt_cv, &sc->sc_mt_lock) == 0)
857 			break;
858 	}
859 	mutex_exit(&sc->sc_mt_lock);
860 
861 	iwk_stop(sc);
862 	DELAY(500000);
863 
864 	/*
865 	 * Unregiste from the MAC layer subsystem
866 	 */
867 	(void) mac_unregister(sc->sc_ic.ic_mach);
868 
869 	mutex_enter(&sc->sc_glock);
870 	iwk_free_fw_dma(sc);
871 	iwk_ring_free(sc);
872 	iwk_free_kw(sc);
873 	iwk_free_shared(sc);
874 	mutex_exit(&sc->sc_glock);
875 
876 	(void) ddi_intr_disable(sc->sc_intr_htable[0]);
877 	(void) ddi_intr_remove_handler(sc->sc_intr_htable[0]);
878 	(void) ddi_intr_free(sc->sc_intr_htable[0]);
879 	kmem_free(sc->sc_intr_htable, sizeof (ddi_intr_handle_t));
880 
881 	(void) ddi_intr_remove_softint(sc->sc_soft_hdl);
882 	sc->sc_soft_hdl = NULL;
883 
884 	/*
885 	 * detach ieee80211
886 	 */
887 	ieee80211_detach(&sc->sc_ic);
888 
889 	iwk_destroy_locks(sc);
890 
891 	ddi_regs_map_free(&sc->sc_handle);
892 	ddi_regs_map_free(&sc->sc_cfg_handle);
893 	ddi_remove_minor_node(dip, NULL);
894 	ddi_soft_state_free(iwk_soft_state_p, ddi_get_instance(dip));
895 
896 	return (DDI_SUCCESS);
897 }
898 
899 /*
900  * quiesce(9E) entry point.
901  *
902  * This function is called when the system is single-threaded at high
903  * PIL with preemption disabled. Therefore, this function must not be
904  * blocked.
905  *
906  * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
907  * DDI_FAILURE indicates an error condition and should almost never happen.
908  */
909 int
910 iwk_quiesce(dev_info_t *dip)
911 {
912 	iwk_sc_t	*sc;
913 
914 	sc = ddi_get_soft_state(iwk_soft_state_p, ddi_get_instance(dip));
915 	ASSERT(sc != NULL);
916 
917 	/* no message prints and no lock accquisition */
918 #ifdef DEBUG
919 	iwk_dbg_flags = 0;
920 #endif
921 	sc->sc_flags |= IWK_F_QUIESCED;
922 
923 	iwk_stop(sc);
924 
925 	return (DDI_SUCCESS);
926 }
927 
928 static void
929 iwk_destroy_locks(iwk_sc_t *sc)
930 {
931 	cv_destroy(&sc->sc_mt_cv);
932 	mutex_destroy(&sc->sc_mt_lock);
933 	cv_destroy(&sc->sc_tx_cv);
934 	cv_destroy(&sc->sc_cmd_cv);
935 	cv_destroy(&sc->sc_fw_cv);
936 	mutex_destroy(&sc->sc_tx_lock);
937 	mutex_destroy(&sc->sc_glock);
938 }
939 
940 /*
941  * Allocate an area of memory and a DMA handle for accessing it
942  */
943 static int
944 iwk_alloc_dma_mem(iwk_sc_t *sc, size_t memsize,
945     ddi_dma_attr_t *dma_attr_p, ddi_device_acc_attr_t *acc_attr_p,
946     uint_t dma_flags, iwk_dma_t *dma_p)
947 {
948 	caddr_t vaddr;
949 	int err;
950 
951 	/*
952 	 * Allocate handle
953 	 */
954 	err = ddi_dma_alloc_handle(sc->sc_dip, dma_attr_p,
955 	    DDI_DMA_SLEEP, NULL, &dma_p->dma_hdl);
956 	if (err != DDI_SUCCESS) {
957 		dma_p->dma_hdl = NULL;
958 		return (DDI_FAILURE);
959 	}
960 
961 	/*
962 	 * Allocate memory
963 	 */
964 	err = ddi_dma_mem_alloc(dma_p->dma_hdl, memsize, acc_attr_p,
965 	    dma_flags & (DDI_DMA_CONSISTENT | DDI_DMA_STREAMING),
966 	    DDI_DMA_SLEEP, NULL, &vaddr, &dma_p->alength, &dma_p->acc_hdl);
967 	if (err != DDI_SUCCESS) {
968 		ddi_dma_free_handle(&dma_p->dma_hdl);
969 		dma_p->dma_hdl = NULL;
970 		dma_p->acc_hdl = NULL;
971 		return (DDI_FAILURE);
972 	}
973 
974 	/*
975 	 * Bind the two together
976 	 */
977 	dma_p->mem_va = vaddr;
978 	err = ddi_dma_addr_bind_handle(dma_p->dma_hdl, NULL,
979 	    vaddr, dma_p->alength, dma_flags, DDI_DMA_SLEEP, NULL,
980 	    &dma_p->cookie, &dma_p->ncookies);
981 	if (err != DDI_DMA_MAPPED) {
982 		ddi_dma_mem_free(&dma_p->acc_hdl);
983 		ddi_dma_free_handle(&dma_p->dma_hdl);
984 		dma_p->acc_hdl = NULL;
985 		dma_p->dma_hdl = NULL;
986 		return (DDI_FAILURE);
987 	}
988 
989 	dma_p->nslots = ~0U;
990 	dma_p->size = ~0U;
991 	dma_p->token = ~0U;
992 	dma_p->offset = 0;
993 	return (DDI_SUCCESS);
994 }
995 
996 /*
997  * Free one allocated area of DMAable memory
998  */
999 static void
1000 iwk_free_dma_mem(iwk_dma_t *dma_p)
1001 {
1002 	if (dma_p->dma_hdl != NULL) {
1003 		if (dma_p->ncookies) {
1004 			(void) ddi_dma_unbind_handle(dma_p->dma_hdl);
1005 			dma_p->ncookies = 0;
1006 		}
1007 		ddi_dma_free_handle(&dma_p->dma_hdl);
1008 		dma_p->dma_hdl = NULL;
1009 	}
1010 
1011 	if (dma_p->acc_hdl != NULL) {
1012 		ddi_dma_mem_free(&dma_p->acc_hdl);
1013 		dma_p->acc_hdl = NULL;
1014 	}
1015 }
1016 
1017 /*
1018  *
1019  */
1020 static int
1021 iwk_alloc_fw_dma(iwk_sc_t *sc)
1022 {
1023 	int err = DDI_SUCCESS;
1024 	iwk_dma_t *dma_p;
1025 	char *t;
1026 
1027 	/*
1028 	 * firmware image layout:
1029 	 * |HDR|<-TEXT->|<-DATA->|<-INIT_TEXT->|<-INIT_DATA->|<-BOOT->|
1030 	 */
1031 	t = (char *)(sc->sc_hdr + 1);
1032 	err = iwk_alloc_dma_mem(sc, LE_32(sc->sc_hdr->textsz),
1033 	    &fw_dma_attr, &iwk_dma_accattr,
1034 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1035 	    &sc->sc_dma_fw_text);
1036 	dma_p = &sc->sc_dma_fw_text;
1037 	IWK_DBG((IWK_DEBUG_DMA, "text[ncookies:%d addr:%lx size:%lx]\n",
1038 	    dma_p->ncookies, dma_p->cookie.dmac_address,
1039 	    dma_p->cookie.dmac_size));
1040 	if (err != DDI_SUCCESS) {
1041 		cmn_err(CE_WARN, "iwk_alloc_fw_dma(): failed to alloc"
1042 		    " text dma memory");
1043 		goto fail;
1044 	}
1045 	(void) memcpy(dma_p->mem_va, t, LE_32(sc->sc_hdr->textsz));
1046 
1047 	t += LE_32(sc->sc_hdr->textsz);
1048 	err = iwk_alloc_dma_mem(sc, LE_32(sc->sc_hdr->datasz),
1049 	    &fw_dma_attr, &iwk_dma_accattr,
1050 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1051 	    &sc->sc_dma_fw_data);
1052 	dma_p = &sc->sc_dma_fw_data;
1053 	IWK_DBG((IWK_DEBUG_DMA, "data[ncookies:%d addr:%lx size:%lx]\n",
1054 	    dma_p->ncookies, dma_p->cookie.dmac_address,
1055 	    dma_p->cookie.dmac_size));
1056 	if (err != DDI_SUCCESS) {
1057 		cmn_err(CE_WARN, "iwk_alloc_fw_dma(): failed to alloc"
1058 		    " data dma memory");
1059 		goto fail;
1060 	}
1061 	(void) memcpy(dma_p->mem_va, t, LE_32(sc->sc_hdr->datasz));
1062 
1063 	err = iwk_alloc_dma_mem(sc, LE_32(sc->sc_hdr->datasz),
1064 	    &fw_dma_attr, &iwk_dma_accattr,
1065 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1066 	    &sc->sc_dma_fw_data_bak);
1067 	dma_p = &sc->sc_dma_fw_data_bak;
1068 	IWK_DBG((IWK_DEBUG_DMA, "data_bak[ncookies:%d addr:%lx "
1069 	    "size:%lx]\n",
1070 	    dma_p->ncookies, dma_p->cookie.dmac_address,
1071 	    dma_p->cookie.dmac_size));
1072 	if (err != DDI_SUCCESS) {
1073 		cmn_err(CE_WARN, "iwk_alloc_fw_dma(): failed to alloc"
1074 		    " data bakeup dma memory");
1075 		goto fail;
1076 	}
1077 	(void) memcpy(dma_p->mem_va, t, LE_32(sc->sc_hdr->datasz));
1078 
1079 	t += LE_32(sc->sc_hdr->datasz);
1080 	err = iwk_alloc_dma_mem(sc, LE_32(sc->sc_hdr->init_textsz),
1081 	    &fw_dma_attr, &iwk_dma_accattr,
1082 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1083 	    &sc->sc_dma_fw_init_text);
1084 	dma_p = &sc->sc_dma_fw_init_text;
1085 	IWK_DBG((IWK_DEBUG_DMA, "init_text[ncookies:%d addr:%lx "
1086 	    "size:%lx]\n",
1087 	    dma_p->ncookies, dma_p->cookie.dmac_address,
1088 	    dma_p->cookie.dmac_size));
1089 	if (err != DDI_SUCCESS) {
1090 		cmn_err(CE_WARN, "iwk_alloc_fw_dma(): failed to alloc"
1091 		    "init text dma memory");
1092 		goto fail;
1093 	}
1094 	(void) memcpy(dma_p->mem_va, t, LE_32(sc->sc_hdr->init_textsz));
1095 
1096 	t += LE_32(sc->sc_hdr->init_textsz);
1097 	err = iwk_alloc_dma_mem(sc, LE_32(sc->sc_hdr->init_datasz),
1098 	    &fw_dma_attr, &iwk_dma_accattr,
1099 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1100 	    &sc->sc_dma_fw_init_data);
1101 	dma_p = &sc->sc_dma_fw_init_data;
1102 	IWK_DBG((IWK_DEBUG_DMA, "init_data[ncookies:%d addr:%lx "
1103 	    "size:%lx]\n",
1104 	    dma_p->ncookies, dma_p->cookie.dmac_address,
1105 	    dma_p->cookie.dmac_size));
1106 	if (err != DDI_SUCCESS) {
1107 		cmn_err(CE_WARN, "iwk_alloc_fw_dma(): failed to alloc"
1108 		    "init data dma memory");
1109 		goto fail;
1110 	}
1111 	(void) memcpy(dma_p->mem_va, t, LE_32(sc->sc_hdr->init_datasz));
1112 
1113 	sc->sc_boot = t + LE_32(sc->sc_hdr->init_datasz);
1114 fail:
1115 	return (err);
1116 }
1117 
1118 static void
1119 iwk_free_fw_dma(iwk_sc_t *sc)
1120 {
1121 	iwk_free_dma_mem(&sc->sc_dma_fw_text);
1122 	iwk_free_dma_mem(&sc->sc_dma_fw_data);
1123 	iwk_free_dma_mem(&sc->sc_dma_fw_data_bak);
1124 	iwk_free_dma_mem(&sc->sc_dma_fw_init_text);
1125 	iwk_free_dma_mem(&sc->sc_dma_fw_init_data);
1126 }
1127 
1128 /*
1129  * Allocate a shared page between host and NIC.
1130  */
1131 static int
1132 iwk_alloc_shared(iwk_sc_t *sc)
1133 {
1134 	iwk_dma_t *dma_p;
1135 	int err = DDI_SUCCESS;
1136 
1137 	/* must be aligned on a 4K-page boundary */
1138 	err = iwk_alloc_dma_mem(sc, sizeof (iwk_shared_t),
1139 	    &sh_dma_attr, &iwk_dma_accattr,
1140 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1141 	    &sc->sc_dma_sh);
1142 	if (err != DDI_SUCCESS)
1143 		goto fail;
1144 	sc->sc_shared = (iwk_shared_t *)sc->sc_dma_sh.mem_va;
1145 
1146 	dma_p = &sc->sc_dma_sh;
1147 	IWK_DBG((IWK_DEBUG_DMA, "sh[ncookies:%d addr:%lx size:%lx]\n",
1148 	    dma_p->ncookies, dma_p->cookie.dmac_address,
1149 	    dma_p->cookie.dmac_size));
1150 
1151 	return (err);
1152 fail:
1153 	iwk_free_shared(sc);
1154 	return (err);
1155 }
1156 
1157 static void
1158 iwk_free_shared(iwk_sc_t *sc)
1159 {
1160 	iwk_free_dma_mem(&sc->sc_dma_sh);
1161 }
1162 
1163 /*
1164  * Allocate a keep warm page.
1165  */
1166 static int
1167 iwk_alloc_kw(iwk_sc_t *sc)
1168 {
1169 	iwk_dma_t *dma_p;
1170 	int err = DDI_SUCCESS;
1171 
1172 	/* must be aligned on a 4K-page boundary */
1173 	err = iwk_alloc_dma_mem(sc, IWK_KW_SIZE,
1174 	    &kw_dma_attr, &iwk_dma_accattr,
1175 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1176 	    &sc->sc_dma_kw);
1177 	if (err != DDI_SUCCESS)
1178 		goto fail;
1179 
1180 	dma_p = &sc->sc_dma_kw;
1181 	IWK_DBG((IWK_DEBUG_DMA, "kw[ncookies:%d addr:%lx size:%lx]\n",
1182 	    dma_p->ncookies, dma_p->cookie.dmac_address,
1183 	    dma_p->cookie.dmac_size));
1184 
1185 	return (err);
1186 fail:
1187 	iwk_free_kw(sc);
1188 	return (err);
1189 }
1190 
1191 static void
1192 iwk_free_kw(iwk_sc_t *sc)
1193 {
1194 	iwk_free_dma_mem(&sc->sc_dma_kw);
1195 }
1196 
1197 static int
1198 iwk_alloc_rx_ring(iwk_sc_t *sc)
1199 {
1200 	iwk_rx_ring_t *ring;
1201 	iwk_rx_data_t *data;
1202 	iwk_dma_t *dma_p;
1203 	int i, err = DDI_SUCCESS;
1204 
1205 	ring = &sc->sc_rxq;
1206 	ring->cur = 0;
1207 
1208 	err = iwk_alloc_dma_mem(sc, RX_QUEUE_SIZE * sizeof (uint32_t),
1209 	    &ring_desc_dma_attr, &iwk_dma_accattr,
1210 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1211 	    &ring->dma_desc);
1212 	if (err != DDI_SUCCESS) {
1213 		cmn_err(CE_WARN, "dma alloc rx ring desc failed\n");
1214 		goto fail;
1215 	}
1216 	ring->desc = (uint32_t *)ring->dma_desc.mem_va;
1217 	dma_p = &ring->dma_desc;
1218 	IWK_DBG((IWK_DEBUG_DMA, "rx bd[ncookies:%d addr:%lx size:%lx]\n",
1219 	    dma_p->ncookies, dma_p->cookie.dmac_address,
1220 	    dma_p->cookie.dmac_size));
1221 
1222 	/*
1223 	 * Allocate Rx buffers.
1224 	 */
1225 	for (i = 0; i < RX_QUEUE_SIZE; i++) {
1226 		data = &ring->data[i];
1227 		err = iwk_alloc_dma_mem(sc, sc->sc_dmabuf_sz,
1228 		    &rx_buffer_dma_attr, &iwk_dma_accattr,
1229 		    DDI_DMA_READ | DDI_DMA_STREAMING,
1230 		    &data->dma_data);
1231 		if (err != DDI_SUCCESS) {
1232 			cmn_err(CE_WARN, "dma alloc rx ring buf[%d] "
1233 			    "failed\n", i);
1234 			goto fail;
1235 		}
1236 		/*
1237 		 * the physical address bit [8-36] are used,
1238 		 * instead of bit [0-31] in 3945.
1239 		 */
1240 		ring->desc[i] = LE_32((uint32_t)
1241 		    (data->dma_data.cookie.dmac_address >> 8));
1242 	}
1243 	dma_p = &ring->data[0].dma_data;
1244 	IWK_DBG((IWK_DEBUG_DMA, "rx buffer[0][ncookies:%d addr:%lx "
1245 	    "size:%lx]\n",
1246 	    dma_p->ncookies, dma_p->cookie.dmac_address,
1247 	    dma_p->cookie.dmac_size));
1248 
1249 	IWK_DMA_SYNC(ring->dma_desc, DDI_DMA_SYNC_FORDEV);
1250 
1251 	return (err);
1252 
1253 fail:
1254 	iwk_free_rx_ring(sc);
1255 	return (err);
1256 }
1257 
1258 static void
1259 iwk_reset_rx_ring(iwk_sc_t *sc)
1260 {
1261 	int n;
1262 
1263 	iwk_mac_access_enter(sc);
1264 	IWK_WRITE(sc, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
1265 	for (n = 0; n < 2000; n++) {
1266 		if (IWK_READ(sc, FH_MEM_RSSR_RX_STATUS_REG) & (1 << 24))
1267 			break;
1268 		DELAY(1000);
1269 	}
1270 
1271 	if (n == 2000)
1272 		IWK_DBG((IWK_DEBUG_DMA, "timeout resetting Rx ring\n"));
1273 
1274 	iwk_mac_access_exit(sc);
1275 
1276 	sc->sc_rxq.cur = 0;
1277 }
1278 
1279 static void
1280 iwk_free_rx_ring(iwk_sc_t *sc)
1281 {
1282 	int i;
1283 
1284 	for (i = 0; i < RX_QUEUE_SIZE; i++) {
1285 		if (sc->sc_rxq.data[i].dma_data.dma_hdl)
1286 			IWK_DMA_SYNC(sc->sc_rxq.data[i].dma_data,
1287 			    DDI_DMA_SYNC_FORCPU);
1288 		iwk_free_dma_mem(&sc->sc_rxq.data[i].dma_data);
1289 	}
1290 
1291 	if (sc->sc_rxq.dma_desc.dma_hdl)
1292 		IWK_DMA_SYNC(sc->sc_rxq.dma_desc, DDI_DMA_SYNC_FORDEV);
1293 	iwk_free_dma_mem(&sc->sc_rxq.dma_desc);
1294 }
1295 
1296 static int
1297 iwk_alloc_tx_ring(iwk_sc_t *sc, iwk_tx_ring_t *ring,
1298     int slots, int qid)
1299 {
1300 	iwk_tx_data_t *data;
1301 	iwk_tx_desc_t *desc_h;
1302 	uint32_t paddr_desc_h;
1303 	iwk_cmd_t *cmd_h;
1304 	uint32_t paddr_cmd_h;
1305 	iwk_dma_t *dma_p;
1306 	int i, err = DDI_SUCCESS;
1307 
1308 	ring->qid = qid;
1309 	ring->count = TFD_QUEUE_SIZE_MAX;
1310 	ring->window = slots;
1311 	ring->queued = 0;
1312 	ring->cur = 0;
1313 
1314 	err = iwk_alloc_dma_mem(sc,
1315 	    TFD_QUEUE_SIZE_MAX * sizeof (iwk_tx_desc_t),
1316 	    &ring_desc_dma_attr, &iwk_dma_accattr,
1317 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1318 	    &ring->dma_desc);
1319 	if (err != DDI_SUCCESS) {
1320 		cmn_err(CE_WARN, "dma alloc tx ring desc[%d] "
1321 		    "failed\n", qid);
1322 		goto fail;
1323 	}
1324 	dma_p = &ring->dma_desc;
1325 	IWK_DBG((IWK_DEBUG_DMA, "tx bd[ncookies:%d addr:%lx size:%lx]\n",
1326 	    dma_p->ncookies, dma_p->cookie.dmac_address,
1327 	    dma_p->cookie.dmac_size));
1328 
1329 	desc_h = (iwk_tx_desc_t *)ring->dma_desc.mem_va;
1330 	paddr_desc_h = ring->dma_desc.cookie.dmac_address;
1331 
1332 	err = iwk_alloc_dma_mem(sc,
1333 	    TFD_QUEUE_SIZE_MAX * sizeof (iwk_cmd_t),
1334 	    &cmd_dma_attr, &iwk_dma_accattr,
1335 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1336 	    &ring->dma_cmd);
1337 	if (err != DDI_SUCCESS) {
1338 		cmn_err(CE_WARN, "dma alloc tx ring cmd[%d] "
1339 		    "failed\n", qid);
1340 		goto fail;
1341 	}
1342 	dma_p = &ring->dma_cmd;
1343 	IWK_DBG((IWK_DEBUG_DMA, "tx cmd[ncookies:%d addr:%lx size:%lx]\n",
1344 	    dma_p->ncookies, dma_p->cookie.dmac_address,
1345 	    dma_p->cookie.dmac_size));
1346 
1347 	cmd_h = (iwk_cmd_t *)ring->dma_cmd.mem_va;
1348 	paddr_cmd_h = ring->dma_cmd.cookie.dmac_address;
1349 
1350 	/*
1351 	 * Allocate Tx buffers.
1352 	 */
1353 	ring->data = kmem_zalloc(sizeof (iwk_tx_data_t) * TFD_QUEUE_SIZE_MAX,
1354 	    KM_NOSLEEP);
1355 	if (ring->data == NULL) {
1356 		cmn_err(CE_WARN, "could not allocate tx data slots\n");
1357 		goto fail;
1358 	}
1359 
1360 	for (i = 0; i < TFD_QUEUE_SIZE_MAX; i++) {
1361 		data = &ring->data[i];
1362 		err = iwk_alloc_dma_mem(sc, sc->sc_dmabuf_sz,
1363 		    &tx_buffer_dma_attr, &iwk_dma_accattr,
1364 		    DDI_DMA_WRITE | DDI_DMA_STREAMING,
1365 		    &data->dma_data);
1366 		if (err != DDI_SUCCESS) {
1367 			cmn_err(CE_WARN, "dma alloc tx ring "
1368 			    "buf[%d] failed\n", i);
1369 			goto fail;
1370 		}
1371 
1372 		data->desc = desc_h + i;
1373 		data->paddr_desc = paddr_desc_h +
1374 		    _PTRDIFF(data->desc, desc_h);
1375 		data->cmd = cmd_h +  i; /* (i % slots); */
1376 		/* ((i % slots) * sizeof (iwk_cmd_t)); */
1377 		data->paddr_cmd = paddr_cmd_h +
1378 		    _PTRDIFF(data->cmd, cmd_h);
1379 	}
1380 	dma_p = &ring->data[0].dma_data;
1381 	IWK_DBG((IWK_DEBUG_DMA, "tx buffer[0][ncookies:%d addr:%lx "
1382 	    "size:%lx]\n",
1383 	    dma_p->ncookies, dma_p->cookie.dmac_address,
1384 	    dma_p->cookie.dmac_size));
1385 
1386 	return (err);
1387 
1388 fail:
1389 	if (ring->data)
1390 		kmem_free(ring->data,
1391 		    sizeof (iwk_tx_data_t) * TFD_QUEUE_SIZE_MAX);
1392 	iwk_free_tx_ring(sc, ring);
1393 	return (err);
1394 }
1395 
1396 static void
1397 iwk_reset_tx_ring(iwk_sc_t *sc, iwk_tx_ring_t *ring)
1398 {
1399 	iwk_tx_data_t *data;
1400 	int i, n;
1401 
1402 	iwk_mac_access_enter(sc);
1403 
1404 	IWK_WRITE(sc, IWK_FH_TCSR_CHNL_TX_CONFIG_REG(ring->qid), 0);
1405 	for (n = 0; n < 200; n++) {
1406 		if (IWK_READ(sc, IWK_FH_TSSR_TX_STATUS_REG) &
1407 		    IWK_FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ring->qid))
1408 			break;
1409 		DELAY(10);
1410 	}
1411 	if (n == 200) {
1412 		IWK_DBG((IWK_DEBUG_DMA, "timeout reset tx ring %d\n",
1413 		    ring->qid));
1414 	}
1415 	iwk_mac_access_exit(sc);
1416 
1417 	for (i = 0; i < ring->count; i++) {
1418 		data = &ring->data[i];
1419 		IWK_DMA_SYNC(data->dma_data, DDI_DMA_SYNC_FORDEV);
1420 	}
1421 
1422 	ring->queued = 0;
1423 	ring->cur = 0;
1424 }
1425 
1426 /*ARGSUSED*/
1427 static void
1428 iwk_free_tx_ring(iwk_sc_t *sc, iwk_tx_ring_t *ring)
1429 {
1430 	int i;
1431 
1432 	if (ring->dma_desc.dma_hdl != NULL)
1433 		IWK_DMA_SYNC(ring->dma_desc, DDI_DMA_SYNC_FORDEV);
1434 	iwk_free_dma_mem(&ring->dma_desc);
1435 
1436 	if (ring->dma_cmd.dma_hdl != NULL)
1437 		IWK_DMA_SYNC(ring->dma_cmd, DDI_DMA_SYNC_FORDEV);
1438 	iwk_free_dma_mem(&ring->dma_cmd);
1439 
1440 	if (ring->data != NULL) {
1441 		for (i = 0; i < ring->count; i++) {
1442 			if (ring->data[i].dma_data.dma_hdl)
1443 				IWK_DMA_SYNC(ring->data[i].dma_data,
1444 				    DDI_DMA_SYNC_FORDEV);
1445 			iwk_free_dma_mem(&ring->data[i].dma_data);
1446 		}
1447 		kmem_free(ring->data, ring->count * sizeof (iwk_tx_data_t));
1448 	}
1449 }
1450 
1451 static int
1452 iwk_ring_init(iwk_sc_t *sc)
1453 {
1454 	int i, err = DDI_SUCCESS;
1455 
1456 	for (i = 0; i < IWK_NUM_QUEUES; i++) {
1457 		if (i == IWK_CMD_QUEUE_NUM)
1458 			continue;
1459 		err = iwk_alloc_tx_ring(sc, &sc->sc_txq[i], TFD_TX_CMD_SLOTS,
1460 		    i);
1461 		if (err != DDI_SUCCESS)
1462 			goto fail;
1463 	}
1464 	err = iwk_alloc_tx_ring(sc, &sc->sc_txq[IWK_CMD_QUEUE_NUM],
1465 	    TFD_CMD_SLOTS, IWK_CMD_QUEUE_NUM);
1466 	if (err != DDI_SUCCESS)
1467 		goto fail;
1468 	err = iwk_alloc_rx_ring(sc);
1469 	if (err != DDI_SUCCESS)
1470 		goto fail;
1471 	return (err);
1472 
1473 fail:
1474 	return (err);
1475 }
1476 
1477 static void
1478 iwk_ring_free(iwk_sc_t *sc)
1479 {
1480 	int i = IWK_NUM_QUEUES;
1481 
1482 	iwk_free_rx_ring(sc);
1483 	while (--i >= 0) {
1484 		iwk_free_tx_ring(sc, &sc->sc_txq[i]);
1485 	}
1486 }
1487 
1488 /* ARGSUSED */
1489 static ieee80211_node_t *
1490 iwk_node_alloc(ieee80211com_t *ic)
1491 {
1492 	iwk_amrr_t *amrr;
1493 
1494 	amrr = kmem_zalloc(sizeof (iwk_amrr_t), KM_SLEEP);
1495 	if (amrr != NULL)
1496 		iwk_amrr_init(amrr);
1497 	return (&amrr->in);
1498 }
1499 
1500 static void
1501 iwk_node_free(ieee80211_node_t *in)
1502 {
1503 	ieee80211com_t *ic = in->in_ic;
1504 
1505 	ic->ic_node_cleanup(in);
1506 	if (in->in_wpa_ie != NULL)
1507 		ieee80211_free(in->in_wpa_ie);
1508 	kmem_free(in, sizeof (iwk_amrr_t));
1509 }
1510 
1511 /*ARGSUSED*/
1512 static int
1513 iwk_newstate(ieee80211com_t *ic, enum ieee80211_state nstate, int arg)
1514 {
1515 	iwk_sc_t *sc = (iwk_sc_t *)ic;
1516 	ieee80211_node_t *in = ic->ic_bss;
1517 	enum ieee80211_state ostate = ic->ic_state;
1518 	int i, err = IWK_SUCCESS;
1519 
1520 	mutex_enter(&sc->sc_glock);
1521 	switch (nstate) {
1522 	case IEEE80211_S_SCAN:
1523 		switch (ostate) {
1524 		case IEEE80211_S_INIT:
1525 		{
1526 			iwk_add_sta_t node;
1527 
1528 			sc->sc_flags |= IWK_F_SCANNING;
1529 			iwk_set_led(sc, 2, 10, 2);
1530 
1531 			/*
1532 			 * clear association to receive beacons from
1533 			 * all BSS'es
1534 			 */
1535 			sc->sc_config.assoc_id = 0;
1536 			sc->sc_config.filter_flags &=
1537 			    ~LE_32(RXON_FILTER_ASSOC_MSK);
1538 
1539 			IWK_DBG((IWK_DEBUG_80211, "config chan %d "
1540 			    "flags %x filter_flags %x\n", sc->sc_config.chan,
1541 			    sc->sc_config.flags, sc->sc_config.filter_flags));
1542 
1543 			err = iwk_cmd(sc, REPLY_RXON, &sc->sc_config,
1544 			    sizeof (iwk_rxon_cmd_t), 1);
1545 			if (err != IWK_SUCCESS) {
1546 				cmn_err(CE_WARN,
1547 				    "could not clear association\n");
1548 				sc->sc_flags &= ~IWK_F_SCANNING;
1549 				mutex_exit(&sc->sc_glock);
1550 				return (err);
1551 			}
1552 
1553 			/* add broadcast node to send probe request */
1554 			(void) memset(&node, 0, sizeof (node));
1555 			(void) memset(&node.bssid, 0xff, IEEE80211_ADDR_LEN);
1556 			node.id = IWK_BROADCAST_ID;
1557 			err = iwk_cmd(sc, REPLY_ADD_STA, &node,
1558 			    sizeof (node), 1);
1559 			if (err != IWK_SUCCESS) {
1560 				cmn_err(CE_WARN, "could not add "
1561 				    "broadcast node\n");
1562 				sc->sc_flags &= ~IWK_F_SCANNING;
1563 				mutex_exit(&sc->sc_glock);
1564 				return (err);
1565 			}
1566 			break;
1567 		}
1568 		case IEEE80211_S_SCAN:
1569 			mutex_exit(&sc->sc_glock);
1570 			/* step to next channel before actual FW scan */
1571 			err = sc->sc_newstate(ic, nstate, arg);
1572 			mutex_enter(&sc->sc_glock);
1573 			if ((err != 0) || ((err = iwk_scan(sc)) != 0)) {
1574 				cmn_err(CE_WARN,
1575 				    "could not initiate scan\n");
1576 				sc->sc_flags &= ~IWK_F_SCANNING;
1577 				ieee80211_cancel_scan(ic);
1578 			}
1579 			mutex_exit(&sc->sc_glock);
1580 			return (err);
1581 		default:
1582 			break;
1583 
1584 		}
1585 		sc->sc_clk = 0;
1586 		break;
1587 
1588 	case IEEE80211_S_AUTH:
1589 		if (ostate == IEEE80211_S_SCAN) {
1590 			sc->sc_flags &= ~IWK_F_SCANNING;
1591 		}
1592 
1593 		/* reset state to handle reassociations correctly */
1594 		sc->sc_config.assoc_id = 0;
1595 		sc->sc_config.filter_flags &= ~LE_32(RXON_FILTER_ASSOC_MSK);
1596 
1597 		/*
1598 		 * before sending authentication and association request frame,
1599 		 * we need do something in the hardware, such as setting the
1600 		 * channel same to the target AP...
1601 		 */
1602 		if ((err = iwk_hw_set_before_auth(sc)) != 0) {
1603 			cmn_err(CE_WARN, "could not setup firmware for "
1604 			    "authentication\n");
1605 			mutex_exit(&sc->sc_glock);
1606 			return (err);
1607 		}
1608 		break;
1609 
1610 	case IEEE80211_S_RUN:
1611 		if (ostate == IEEE80211_S_SCAN) {
1612 			sc->sc_flags &= ~IWK_F_SCANNING;
1613 		}
1614 
1615 		if (ic->ic_opmode == IEEE80211_M_MONITOR) {
1616 			/* let LED blink when monitoring */
1617 			iwk_set_led(sc, 2, 10, 10);
1618 			break;
1619 		}
1620 		IWK_DBG((IWK_DEBUG_80211, "iwk: associated."));
1621 
1622 		/* none IBSS mode */
1623 		if (ic->ic_opmode != IEEE80211_M_IBSS) {
1624 			/* update adapter's configuration */
1625 			if (sc->sc_assoc_id != in->in_associd) {
1626 				cmn_err(CE_WARN,
1627 				    "associate ID mismatch: expected %d, "
1628 				    "got %d\n",
1629 				    in->in_associd, sc->sc_assoc_id);
1630 			}
1631 			sc->sc_config.assoc_id = in->in_associd & 0x3fff;
1632 			/*
1633 			 * short preamble/slot time are
1634 			 * negotiated when associating
1635 			 */
1636 			sc->sc_config.flags &=
1637 			    ~LE_32(RXON_FLG_SHORT_PREAMBLE_MSK |
1638 			    RXON_FLG_SHORT_SLOT_MSK);
1639 
1640 			if (ic->ic_flags & IEEE80211_F_SHSLOT)
1641 				sc->sc_config.flags |=
1642 				    LE_32(RXON_FLG_SHORT_SLOT_MSK);
1643 
1644 			if (ic->ic_flags & IEEE80211_F_SHPREAMBLE)
1645 				sc->sc_config.flags |=
1646 				    LE_32(RXON_FLG_SHORT_PREAMBLE_MSK);
1647 
1648 			sc->sc_config.filter_flags |=
1649 			    LE_32(RXON_FILTER_ASSOC_MSK);
1650 
1651 			if (ic->ic_opmode != IEEE80211_M_STA)
1652 				sc->sc_config.filter_flags |=
1653 				    LE_32(RXON_FILTER_BCON_AWARE_MSK);
1654 
1655 			IWK_DBG((IWK_DEBUG_80211, "config chan %d flags %x"
1656 			    " filter_flags %x\n",
1657 			    sc->sc_config.chan, sc->sc_config.flags,
1658 			    sc->sc_config.filter_flags));
1659 			err = iwk_cmd(sc, REPLY_RXON, &sc->sc_config,
1660 			    sizeof (iwk_rxon_cmd_t), 1);
1661 			if (err != IWK_SUCCESS) {
1662 				cmn_err(CE_WARN, "could not update "
1663 				    "configuration\n");
1664 				mutex_exit(&sc->sc_glock);
1665 				return (err);
1666 			}
1667 		}
1668 
1669 		/* obtain current temperature of chipset */
1670 		sc->sc_tempera = iwk_curr_tempera(sc);
1671 
1672 		/*
1673 		 * make Tx power calibration to determine
1674 		 * the gains of DSP and radio
1675 		 */
1676 		err = iwk_tx_power_calibration(sc);
1677 		if (err) {
1678 			cmn_err(CE_WARN, "iwk_newstate(): "
1679 			    "failed to set tx power table\n");
1680 			return (err);
1681 		}
1682 
1683 		/* start automatic rate control */
1684 		mutex_enter(&sc->sc_mt_lock);
1685 		if (ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE) {
1686 			sc->sc_flags |= IWK_F_RATE_AUTO_CTL;
1687 			/* set rate to some reasonable initial value */
1688 			i = in->in_rates.ir_nrates - 1;
1689 			while (i > 0 && IEEE80211_RATE(i) > 72)
1690 				i--;
1691 			in->in_txrate = i;
1692 		} else {
1693 			sc->sc_flags &= ~IWK_F_RATE_AUTO_CTL;
1694 		}
1695 		mutex_exit(&sc->sc_mt_lock);
1696 
1697 		/* set LED on after associated */
1698 		iwk_set_led(sc, 2, 0, 1);
1699 		break;
1700 
1701 	case IEEE80211_S_INIT:
1702 		if (ostate == IEEE80211_S_SCAN) {
1703 			sc->sc_flags &= ~IWK_F_SCANNING;
1704 		}
1705 
1706 		/* set LED off after init */
1707 		iwk_set_led(sc, 2, 1, 0);
1708 		break;
1709 	case IEEE80211_S_ASSOC:
1710 		if (ostate == IEEE80211_S_SCAN) {
1711 			sc->sc_flags &= ~IWK_F_SCANNING;
1712 		}
1713 
1714 		break;
1715 	}
1716 
1717 	mutex_exit(&sc->sc_glock);
1718 
1719 	err = sc->sc_newstate(ic, nstate, arg);
1720 
1721 	if (nstate == IEEE80211_S_RUN) {
1722 
1723 		mutex_enter(&sc->sc_glock);
1724 
1725 		/*
1726 		 * make initialization for Receiver
1727 		 * sensitivity calibration
1728 		 */
1729 		err = iwk_rx_sens_init(sc);
1730 		if (err) {
1731 			cmn_err(CE_WARN, "iwk_newstate(): "
1732 			    "failed to init RX sensitivity\n");
1733 			mutex_exit(&sc->sc_glock);
1734 			return (err);
1735 		}
1736 
1737 		/* make initialization for Receiver gain balance */
1738 		err = iwk_rxgain_diff_init(sc);
1739 		if (err) {
1740 			cmn_err(CE_WARN, "iwk_newstate(): "
1741 			    "failed to init phy calibration\n");
1742 			mutex_exit(&sc->sc_glock);
1743 			return (err);
1744 		}
1745 
1746 		mutex_exit(&sc->sc_glock);
1747 
1748 	}
1749 
1750 	return (err);
1751 }
1752 
1753 /*ARGSUSED*/
1754 static int iwk_key_set(ieee80211com_t *ic, const struct ieee80211_key *k,
1755     const uint8_t mac[IEEE80211_ADDR_LEN])
1756 {
1757 	iwk_sc_t *sc = (iwk_sc_t *)ic;
1758 	iwk_add_sta_t node;
1759 	int err;
1760 
1761 	switch (k->wk_cipher->ic_cipher) {
1762 	case IEEE80211_CIPHER_WEP:
1763 	case IEEE80211_CIPHER_TKIP:
1764 		return (1); /* sofeware do it. */
1765 	case IEEE80211_CIPHER_AES_CCM:
1766 		break;
1767 	default:
1768 		return (0);
1769 	}
1770 	sc->sc_config.filter_flags &= ~(RXON_FILTER_DIS_DECRYPT_MSK |
1771 	    RXON_FILTER_DIS_GRP_DECRYPT_MSK);
1772 
1773 	mutex_enter(&sc->sc_glock);
1774 
1775 	/* update ap/multicast node */
1776 	(void) memset(&node, 0, sizeof (node));
1777 	if (IEEE80211_IS_MULTICAST(mac)) {
1778 		(void) memset(node.bssid, 0xff, 6);
1779 		node.id = IWK_BROADCAST_ID;
1780 	} else {
1781 		IEEE80211_ADDR_COPY(node.bssid, ic->ic_bss->in_bssid);
1782 		node.id = IWK_AP_ID;
1783 	}
1784 	if (k->wk_flags & IEEE80211_KEY_XMIT) {
1785 		node.key_flags = 0;
1786 		node.keyp = k->wk_keyix;
1787 	} else {
1788 		node.key_flags = (1 << 14);
1789 		node.keyp = k->wk_keyix + 4;
1790 	}
1791 	(void) memcpy(node.key, k->wk_key, k->wk_keylen);
1792 	node.key_flags |= (STA_KEY_FLG_CCMP | (1 << 3) | (k->wk_keyix << 8));
1793 	node.sta_mask = STA_MODIFY_KEY_MASK;
1794 	node.control = 1;
1795 	err = iwk_cmd(sc, REPLY_ADD_STA, &node, sizeof (node), 1);
1796 	if (err != IWK_SUCCESS) {
1797 		cmn_err(CE_WARN, "iwk_key_set():"
1798 		    "failed to update ap node\n");
1799 		mutex_exit(&sc->sc_glock);
1800 		return (0);
1801 	}
1802 	mutex_exit(&sc->sc_glock);
1803 	return (1);
1804 }
1805 
1806 /*
1807  * exclusive access to mac begin.
1808  */
1809 static void
1810 iwk_mac_access_enter(iwk_sc_t *sc)
1811 {
1812 	uint32_t tmp;
1813 	int n;
1814 
1815 	tmp = IWK_READ(sc, CSR_GP_CNTRL);
1816 	IWK_WRITE(sc, CSR_GP_CNTRL,
1817 	    tmp | CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
1818 
1819 	/* wait until we succeed */
1820 	for (n = 0; n < 1000; n++) {
1821 		if ((IWK_READ(sc, CSR_GP_CNTRL) &
1822 		    (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY |
1823 		    CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP)) ==
1824 		    CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN)
1825 			break;
1826 		DELAY(10);
1827 	}
1828 	if (n == 1000)
1829 		IWK_DBG((IWK_DEBUG_PIO, "could not lock memory\n"));
1830 }
1831 
1832 /*
1833  * exclusive access to mac end.
1834  */
1835 static void
1836 iwk_mac_access_exit(iwk_sc_t *sc)
1837 {
1838 	uint32_t tmp = IWK_READ(sc, CSR_GP_CNTRL);
1839 	IWK_WRITE(sc, CSR_GP_CNTRL,
1840 	    tmp & ~CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
1841 }
1842 
1843 static uint32_t
1844 iwk_mem_read(iwk_sc_t *sc, uint32_t addr)
1845 {
1846 	IWK_WRITE(sc, HBUS_TARG_MEM_RADDR, addr);
1847 	return (IWK_READ(sc, HBUS_TARG_MEM_RDAT));
1848 }
1849 
1850 static void
1851 iwk_mem_write(iwk_sc_t *sc, uint32_t addr, uint32_t data)
1852 {
1853 	IWK_WRITE(sc, HBUS_TARG_MEM_WADDR, addr);
1854 	IWK_WRITE(sc, HBUS_TARG_MEM_WDAT, data);
1855 }
1856 
1857 static uint32_t
1858 iwk_reg_read(iwk_sc_t *sc, uint32_t addr)
1859 {
1860 	IWK_WRITE(sc, HBUS_TARG_PRPH_RADDR, addr | (3 << 24));
1861 	return (IWK_READ(sc, HBUS_TARG_PRPH_RDAT));
1862 }
1863 
1864 static void
1865 iwk_reg_write(iwk_sc_t *sc, uint32_t addr, uint32_t data)
1866 {
1867 	IWK_WRITE(sc, HBUS_TARG_PRPH_WADDR, addr | (3 << 24));
1868 	IWK_WRITE(sc, HBUS_TARG_PRPH_WDAT, data);
1869 }
1870 
1871 static void
1872 iwk_reg_write_region_4(iwk_sc_t *sc, uint32_t addr,
1873     uint32_t *data, int wlen)
1874 {
1875 	for (; wlen > 0; wlen--, data++, addr += 4)
1876 		iwk_reg_write(sc, addr, *data);
1877 }
1878 
1879 
1880 /*
1881  * ucode load/initialization steps:
1882  * 1)  load Bootstrap State Machine (BSM) with "bootstrap" uCode image.
1883  * BSM contains a small memory that *always* stays powered up, so it can
1884  * retain the bootstrap program even when the card is in a power-saving
1885  * power-down state.  The BSM loads the small program into ARC processor's
1886  * instruction memory when triggered by power-up.
1887  * 2)  load Initialize image via bootstrap program.
1888  * The Initialize image sets up regulatory and calibration data for the
1889  * Runtime/Protocol uCode. This sends a REPLY_ALIVE notification when completed.
1890  * The 4965 reply contains calibration data for temperature, voltage and tx gain
1891  * correction.
1892  */
1893 static int
1894 iwk_load_firmware(iwk_sc_t *sc)
1895 {
1896 	uint32_t *boot_fw = (uint32_t *)sc->sc_boot;
1897 	uint32_t size = sc->sc_hdr->bootsz;
1898 	int n, err = IWK_SUCCESS;
1899 
1900 	/*
1901 	 * The physical address bit [4-35] of the initialize uCode.
1902 	 * In the initialize alive notify interrupt the physical address of
1903 	 * the runtime ucode will be set for loading.
1904 	 */
1905 	iwk_mac_access_enter(sc);
1906 
1907 	iwk_reg_write(sc, BSM_DRAM_INST_PTR_REG,
1908 	    sc->sc_dma_fw_init_text.cookie.dmac_address >> 4);
1909 	iwk_reg_write(sc, BSM_DRAM_DATA_PTR_REG,
1910 	    sc->sc_dma_fw_init_data.cookie.dmac_address >> 4);
1911 	iwk_reg_write(sc, BSM_DRAM_INST_BYTECOUNT_REG,
1912 	    sc->sc_dma_fw_init_text.cookie.dmac_size);
1913 	iwk_reg_write(sc, BSM_DRAM_DATA_BYTECOUNT_REG,
1914 	    sc->sc_dma_fw_init_data.cookie.dmac_size);
1915 
1916 	/* load bootstrap code into BSM memory */
1917 	iwk_reg_write_region_4(sc, BSM_SRAM_LOWER_BOUND, boot_fw,
1918 	    size / sizeof (uint32_t));
1919 
1920 	iwk_reg_write(sc, BSM_WR_MEM_SRC_REG, 0);
1921 	iwk_reg_write(sc, BSM_WR_MEM_DST_REG, RTC_INST_LOWER_BOUND);
1922 	iwk_reg_write(sc, BSM_WR_DWCOUNT_REG, size / sizeof (uint32_t));
1923 
1924 	/*
1925 	 * prepare to load initialize uCode
1926 	 */
1927 	iwk_reg_write(sc, BSM_WR_CTRL_REG, BSM_WR_CTRL_REG_BIT_START);
1928 
1929 	/* wait while the adapter is busy loading the firmware */
1930 	for (n = 0; n < 1000; n++) {
1931 		if (!(iwk_reg_read(sc, BSM_WR_CTRL_REG) &
1932 		    BSM_WR_CTRL_REG_BIT_START))
1933 			break;
1934 		DELAY(10);
1935 	}
1936 	if (n == 1000) {
1937 		cmn_err(CE_WARN, "timeout transferring firmware\n");
1938 		err = ETIMEDOUT;
1939 		return (err);
1940 	}
1941 
1942 	/* for future power-save mode use */
1943 	iwk_reg_write(sc, BSM_WR_CTRL_REG, BSM_WR_CTRL_REG_BIT_START_EN);
1944 
1945 	iwk_mac_access_exit(sc);
1946 
1947 	return (err);
1948 }
1949 
1950 /*ARGSUSED*/
1951 static void
1952 iwk_rx_intr(iwk_sc_t *sc, iwk_rx_desc_t *desc, iwk_rx_data_t *data)
1953 {
1954 	ieee80211com_t *ic = &sc->sc_ic;
1955 	iwk_rx_ring_t *ring = &sc->sc_rxq;
1956 	iwk_rx_phy_res_t *stat;
1957 	ieee80211_node_t *in;
1958 	uint32_t *tail;
1959 	struct ieee80211_frame *wh;
1960 	mblk_t *mp;
1961 	uint16_t len, rssi, mrssi, agc;
1962 	int16_t t;
1963 	uint32_t ants, i;
1964 	struct iwk_rx_non_cfg_phy *phyinfo;
1965 
1966 	/* assuming not 11n here. cope with 11n in phase-II */
1967 	stat = (iwk_rx_phy_res_t *)(desc + 1);
1968 	if (stat->cfg_phy_cnt > 20) {
1969 		return;
1970 	}
1971 
1972 	phyinfo = (struct iwk_rx_non_cfg_phy *)stat->non_cfg_phy;
1973 	agc = (phyinfo->agc_info & IWK_AGC_DB_MASK) >> IWK_AGC_DB_POS;
1974 	mrssi = 0;
1975 	ants = (stat->phy_flags & RX_PHY_FLAGS_ANTENNAE_MASK) >>
1976 	    RX_PHY_FLAGS_ANTENNAE_OFFSET;
1977 	for (i = 0; i < 3; i++) {
1978 		if (ants & (1 << i))
1979 			mrssi = MAX(mrssi, phyinfo->rssi_info[i << 1]);
1980 	}
1981 	t = mrssi - agc - 44; /* t is the dBM value */
1982 	/*
1983 	 * convert dBm to percentage ???
1984 	 */
1985 	rssi = (100 * 75 * 75 - (-20 - t) * (15 * 75 + 62 * (-20 - t))) /
1986 	    (75 * 75);
1987 	if (rssi > 100)
1988 		rssi = 100;
1989 	if (rssi < 1)
1990 		rssi = 1;
1991 	len = stat->byte_count;
1992 	tail = (uint32_t *)((uint8_t *)(stat + 1) + stat->cfg_phy_cnt + len);
1993 
1994 	IWK_DBG((IWK_DEBUG_RX, "rx intr: idx=%d phy_len=%x len=%d "
1995 	    "rate=%x chan=%d tstamp=%x non_cfg_phy_count=%x "
1996 	    "cfg_phy_count=%x tail=%x", ring->cur, sizeof (*stat),
1997 	    len, stat->rate.r.s.rate, stat->channel,
1998 	    LE_32(stat->timestampl), stat->non_cfg_phy_cnt,
1999 	    stat->cfg_phy_cnt, LE_32(*tail)));
2000 
2001 	if ((len < 16) || (len > sc->sc_dmabuf_sz)) {
2002 		IWK_DBG((IWK_DEBUG_RX, "rx frame oversize\n"));
2003 		return;
2004 	}
2005 
2006 	/*
2007 	 * discard Rx frames with bad CRC
2008 	 */
2009 	if ((LE_32(*tail) &
2010 	    (RX_RES_STATUS_NO_CRC32_ERROR | RX_RES_STATUS_NO_RXE_OVERFLOW)) !=
2011 	    (RX_RES_STATUS_NO_CRC32_ERROR | RX_RES_STATUS_NO_RXE_OVERFLOW)) {
2012 		IWK_DBG((IWK_DEBUG_RX, "rx crc error tail: %x\n",
2013 		    LE_32(*tail)));
2014 		sc->sc_rx_err++;
2015 		return;
2016 	}
2017 
2018 	wh = (struct ieee80211_frame *)
2019 	    ((uint8_t *)(stat + 1)+ stat->cfg_phy_cnt);
2020 	if (*(uint8_t *)wh == IEEE80211_FC0_SUBTYPE_ASSOC_RESP) {
2021 		sc->sc_assoc_id = *((uint16_t *)(wh + 1) + 2);
2022 		IWK_DBG((IWK_DEBUG_RX, "rx : association id = %x\n",
2023 		    sc->sc_assoc_id));
2024 	}
2025 #ifdef DEBUG
2026 	if (iwk_dbg_flags & IWK_DEBUG_RX)
2027 		ieee80211_dump_pkt((uint8_t *)wh, len, 0, 0);
2028 #endif
2029 	in = ieee80211_find_rxnode(ic, wh);
2030 	mp = allocb(len, BPRI_MED);
2031 	if (mp) {
2032 		(void) memcpy(mp->b_wptr, wh, len);
2033 		mp->b_wptr += len;
2034 
2035 		/* send the frame to the 802.11 layer */
2036 		(void) ieee80211_input(ic, mp, in, rssi, 0);
2037 	} else {
2038 		sc->sc_rx_nobuf++;
2039 		IWK_DBG((IWK_DEBUG_RX,
2040 		    "iwk_rx_intr(): alloc rx buf failed\n"));
2041 	}
2042 	/* release node reference */
2043 	ieee80211_free_node(in);
2044 }
2045 
2046 /*ARGSUSED*/
2047 static void
2048 iwk_tx_intr(iwk_sc_t *sc, iwk_rx_desc_t *desc, iwk_rx_data_t *data)
2049 {
2050 	ieee80211com_t *ic = &sc->sc_ic;
2051 	iwk_tx_ring_t *ring = &sc->sc_txq[desc->hdr.qid & 0x3];
2052 	iwk_tx_stat_t *stat = (iwk_tx_stat_t *)(desc + 1);
2053 	iwk_amrr_t *amrr = (iwk_amrr_t *)ic->ic_bss;
2054 
2055 	IWK_DBG((IWK_DEBUG_TX, "tx done: qid=%d idx=%d"
2056 	    " retries=%d frame_count=%x nkill=%d "
2057 	    "rate=%x duration=%d status=%x\n",
2058 	    desc->hdr.qid, desc->hdr.idx, stat->ntries, stat->frame_count,
2059 	    stat->bt_kill_count, stat->rate.r.s.rate,
2060 	    LE_32(stat->duration), LE_32(stat->status)));
2061 
2062 	amrr->txcnt++;
2063 	IWK_DBG((IWK_DEBUG_RATECTL, "tx: %d cnt\n", amrr->txcnt));
2064 	if (stat->ntries > 0) {
2065 		amrr->retrycnt++;
2066 		sc->sc_tx_retries++;
2067 		IWK_DBG((IWK_DEBUG_TX, "tx: %d retries\n",
2068 		    sc->sc_tx_retries));
2069 	}
2070 
2071 	sc->sc_tx_timer = 0;
2072 
2073 	mutex_enter(&sc->sc_tx_lock);
2074 	ring->queued--;
2075 	if (ring->queued < 0)
2076 		ring->queued = 0;
2077 	if ((sc->sc_need_reschedule) && (ring->queued <= (ring->count << 3))) {
2078 		sc->sc_need_reschedule = 0;
2079 		mutex_exit(&sc->sc_tx_lock);
2080 		mac_tx_update(ic->ic_mach);
2081 		mutex_enter(&sc->sc_tx_lock);
2082 	}
2083 	mutex_exit(&sc->sc_tx_lock);
2084 }
2085 
2086 static void
2087 iwk_cmd_intr(iwk_sc_t *sc, iwk_rx_desc_t *desc)
2088 {
2089 	if ((desc->hdr.qid & 7) != 4) {
2090 		return;
2091 	}
2092 	mutex_enter(&sc->sc_glock);
2093 	sc->sc_flags |= IWK_F_CMD_DONE;
2094 	cv_signal(&sc->sc_cmd_cv);
2095 	mutex_exit(&sc->sc_glock);
2096 	IWK_DBG((IWK_DEBUG_CMD, "rx cmd: "
2097 	    "qid=%x idx=%d flags=%x type=0x%x\n",
2098 	    desc->hdr.qid, desc->hdr.idx, desc->hdr.flags,
2099 	    desc->hdr.type));
2100 }
2101 
2102 static void
2103 iwk_ucode_alive(iwk_sc_t *sc, iwk_rx_desc_t *desc)
2104 {
2105 	uint32_t base, i;
2106 	struct iwk_alive_resp *ar =
2107 	    (struct iwk_alive_resp *)(desc + 1);
2108 
2109 	/* the microcontroller is ready */
2110 	IWK_DBG((IWK_DEBUG_FW,
2111 	    "microcode alive notification minor: %x major: %x type:"
2112 	    " %x subtype: %x\n",
2113 	    ar->ucode_minor, ar->ucode_minor, ar->ver_type, ar->ver_subtype));
2114 
2115 	if (LE_32(ar->is_valid) != UCODE_VALID_OK) {
2116 		IWK_DBG((IWK_DEBUG_FW,
2117 		    "microcontroller initialization failed\n"));
2118 	}
2119 	if (ar->ver_subtype == INITIALIZE_SUBTYPE) {
2120 		IWK_DBG((IWK_DEBUG_FW,
2121 		    "initialization alive received.\n"));
2122 		(void) memcpy(&sc->sc_card_alive_init, ar,
2123 		    sizeof (struct iwk_init_alive_resp));
2124 		/* XXX get temperature */
2125 		iwk_mac_access_enter(sc);
2126 		iwk_reg_write(sc, BSM_DRAM_INST_PTR_REG,
2127 		    sc->sc_dma_fw_text.cookie.dmac_address >> 4);
2128 		iwk_reg_write(sc, BSM_DRAM_DATA_PTR_REG,
2129 		    sc->sc_dma_fw_data_bak.cookie.dmac_address >> 4);
2130 		iwk_reg_write(sc, BSM_DRAM_DATA_BYTECOUNT_REG,
2131 		    sc->sc_dma_fw_data.cookie.dmac_size);
2132 		iwk_reg_write(sc, BSM_DRAM_INST_BYTECOUNT_REG,
2133 		    sc->sc_dma_fw_text.cookie.dmac_size | 0x80000000);
2134 		iwk_mac_access_exit(sc);
2135 	} else {
2136 		IWK_DBG((IWK_DEBUG_FW, "runtime alive received.\n"));
2137 		(void) memcpy(&sc->sc_card_alive_run, ar,
2138 		    sizeof (struct iwk_alive_resp));
2139 
2140 		/*
2141 		 * Init SCD related registers to make Tx work. XXX
2142 		 */
2143 		iwk_mac_access_enter(sc);
2144 
2145 		/* read sram address of data base */
2146 		sc->sc_scd_base = iwk_reg_read(sc, SCD_SRAM_BASE_ADDR);
2147 
2148 		/* clear and init SCD_CONTEXT_DATA_OFFSET area. 128 bytes */
2149 		for (base = sc->sc_scd_base + SCD_CONTEXT_DATA_OFFSET, i = 0;
2150 		    i < 128; i += 4)
2151 			iwk_mem_write(sc, base + i, 0);
2152 
2153 		/* clear and init SCD_TX_STTS_BITMAP_OFFSET area. 256 bytes */
2154 		for (base = sc->sc_scd_base + SCD_TX_STTS_BITMAP_OFFSET;
2155 		    i < 256; i += 4)
2156 			iwk_mem_write(sc, base + i, 0);
2157 
2158 		/* clear and init SCD_TRANSLATE_TBL_OFFSET area. 32 bytes */
2159 		for (base = sc->sc_scd_base + SCD_TRANSLATE_TBL_OFFSET;
2160 		    i < sizeof (uint16_t) * IWK_NUM_QUEUES; i += 4)
2161 			iwk_mem_write(sc, base + i, 0);
2162 
2163 		iwk_reg_write(sc, SCD_DRAM_BASE_ADDR,
2164 		    sc->sc_dma_sh.cookie.dmac_address >> 10);
2165 		iwk_reg_write(sc, SCD_QUEUECHAIN_SEL, 0);
2166 
2167 		/* initiate the tx queues */
2168 		for (i = 0; i < IWK_NUM_QUEUES; i++) {
2169 			iwk_reg_write(sc, SCD_QUEUE_RDPTR(i), 0);
2170 			IWK_WRITE(sc, HBUS_TARG_WRPTR, (i << 8));
2171 			iwk_mem_write(sc, sc->sc_scd_base +
2172 			    SCD_CONTEXT_QUEUE_OFFSET(i),
2173 			    (SCD_WIN_SIZE & 0x7f));
2174 			iwk_mem_write(sc, sc->sc_scd_base +
2175 			    SCD_CONTEXT_QUEUE_OFFSET(i) + sizeof (uint32_t),
2176 			    (SCD_FRAME_LIMIT & 0x7f) << 16);
2177 		}
2178 		/* interrupt enable on each queue0-7 */
2179 		iwk_reg_write(sc, SCD_INTERRUPT_MASK,
2180 		    (1 << IWK_NUM_QUEUES) - 1);
2181 		/* enable  each channel 0-7 */
2182 		iwk_reg_write(sc, SCD_TXFACT,
2183 		    SCD_TXFACT_REG_TXFIFO_MASK(0, 7));
2184 		/*
2185 		 * queue 0-7 maps to FIFO 0-7 and
2186 		 * all queues work under FIFO mode (none-scheduler-ack)
2187 		 */
2188 		for (i = 0; i < 7; i++) {
2189 			iwk_reg_write(sc,
2190 			    SCD_QUEUE_STATUS_BITS(i),
2191 			    (1 << SCD_QUEUE_STTS_REG_POS_ACTIVE)|
2192 			    (i << SCD_QUEUE_STTS_REG_POS_TXF)|
2193 			    SCD_QUEUE_STTS_REG_MSK);
2194 		}
2195 		iwk_mac_access_exit(sc);
2196 
2197 		sc->sc_flags |= IWK_F_FW_INIT;
2198 		cv_signal(&sc->sc_fw_cv);
2199 	}
2200 
2201 }
2202 
2203 static uint_t
2204 /* LINTED: argument unused in function: unused */
2205 iwk_rx_softintr(caddr_t arg, caddr_t unused)
2206 {
2207 	iwk_sc_t *sc = (iwk_sc_t *)arg;
2208 	ieee80211com_t *ic = &sc->sc_ic;
2209 	iwk_rx_desc_t *desc;
2210 	iwk_rx_data_t *data;
2211 	uint32_t index;
2212 
2213 	mutex_enter(&sc->sc_glock);
2214 	if (sc->sc_rx_softint_pending != 1) {
2215 		mutex_exit(&sc->sc_glock);
2216 		return (DDI_INTR_UNCLAIMED);
2217 	}
2218 	/* disable interrupts */
2219 	IWK_WRITE(sc, CSR_INT_MASK, 0);
2220 	mutex_exit(&sc->sc_glock);
2221 
2222 	/*
2223 	 * firmware has moved the index of the rx queue, driver get it,
2224 	 * and deal with it.
2225 	 */
2226 	index = LE_32(sc->sc_shared->val0) & 0xfff;
2227 
2228 	while (sc->sc_rxq.cur != index) {
2229 		data = &sc->sc_rxq.data[sc->sc_rxq.cur];
2230 		desc = (iwk_rx_desc_t *)data->dma_data.mem_va;
2231 
2232 		IWK_DBG((IWK_DEBUG_INTR, "rx notification index = %d"
2233 		    " cur = %d qid=%x idx=%d flags=%x type=%x len=%d\n",
2234 		    index, sc->sc_rxq.cur, desc->hdr.qid, desc->hdr.idx,
2235 		    desc->hdr.flags, desc->hdr.type, LE_32(desc->len)));
2236 
2237 		/* a command other than a tx need to be replied */
2238 		if (!(desc->hdr.qid & 0x80) &&
2239 		    (desc->hdr.type != REPLY_RX_PHY_CMD) &&
2240 		    (desc->hdr.type != REPLY_TX) &&
2241 		    (desc->hdr.type != REPLY_TX_PWR_TABLE_CMD) &&
2242 		    (desc->hdr.type != REPLY_PHY_CALIBRATION_CMD) &&
2243 		    (desc->hdr.type != SENSITIVITY_CMD))
2244 			iwk_cmd_intr(sc, desc);
2245 
2246 		switch (desc->hdr.type) {
2247 		case REPLY_4965_RX:
2248 			iwk_rx_intr(sc, desc, data);
2249 			break;
2250 
2251 		case REPLY_TX:
2252 			iwk_tx_intr(sc, desc, data);
2253 			break;
2254 
2255 		case REPLY_ALIVE:
2256 			iwk_ucode_alive(sc, desc);
2257 			break;
2258 
2259 		case CARD_STATE_NOTIFICATION:
2260 		{
2261 			uint32_t *status = (uint32_t *)(desc + 1);
2262 
2263 			IWK_DBG((IWK_DEBUG_RADIO, "state changed to %x\n",
2264 			    LE_32(*status)));
2265 
2266 			if (LE_32(*status) & 1) {
2267 				/*
2268 				 * the radio button has to be pushed(OFF). It
2269 				 * is considered as a hw error, the
2270 				 * iwk_thread() tries to recover it after the
2271 				 * button is pushed again(ON)
2272 				 */
2273 				cmn_err(CE_NOTE,
2274 				    "iwk_rx_softintr(): "
2275 				    "Radio transmitter is off\n");
2276 				sc->sc_ostate = sc->sc_ic.ic_state;
2277 				ieee80211_new_state(&sc->sc_ic,
2278 				    IEEE80211_S_INIT, -1);
2279 				sc->sc_flags |=
2280 				    (IWK_F_HW_ERR_RECOVER | IWK_F_RADIO_OFF);
2281 			}
2282 			break;
2283 		}
2284 		case SCAN_START_NOTIFICATION:
2285 		{
2286 			iwk_start_scan_t *scan =
2287 			    (iwk_start_scan_t *)(desc + 1);
2288 
2289 			IWK_DBG((IWK_DEBUG_SCAN,
2290 			    "scanning channel %d status %x\n",
2291 			    scan->chan, LE_32(scan->status)));
2292 
2293 			ic->ic_curchan = &ic->ic_sup_channels[scan->chan];
2294 			break;
2295 		}
2296 		case SCAN_COMPLETE_NOTIFICATION:
2297 		{
2298 			iwk_stop_scan_t *scan =
2299 			    (iwk_stop_scan_t *)(desc + 1);
2300 
2301 			IWK_DBG((IWK_DEBUG_SCAN,
2302 			    "completed channel %d (burst of %d) status %02x\n",
2303 			    scan->chan, scan->nchan, scan->status));
2304 
2305 			sc->sc_scan_pending++;
2306 			break;
2307 		}
2308 		case STATISTICS_NOTIFICATION:
2309 			/* handle statistics notification */
2310 			iwk_statistics_notify(sc, desc);
2311 			break;
2312 		}
2313 
2314 		sc->sc_rxq.cur = (sc->sc_rxq.cur + 1) % RX_QUEUE_SIZE;
2315 	}
2316 
2317 	/*
2318 	 * driver dealt with what reveived in rx queue and tell the information
2319 	 * to the firmware.
2320 	 */
2321 	index = (index == 0) ? RX_QUEUE_SIZE - 1 : index - 1;
2322 	IWK_WRITE(sc, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, index & (~7));
2323 
2324 	mutex_enter(&sc->sc_glock);
2325 	/* re-enable interrupts */
2326 	IWK_WRITE(sc, CSR_INT_MASK, CSR_INI_SET_MASK);
2327 	sc->sc_rx_softint_pending = 0;
2328 	mutex_exit(&sc->sc_glock);
2329 
2330 	return (DDI_INTR_CLAIMED);
2331 }
2332 
2333 static uint_t
2334 /* LINTED: argument unused in function: unused */
2335 iwk_intr(caddr_t arg, caddr_t unused)
2336 {
2337 	iwk_sc_t *sc = (iwk_sc_t *)arg;
2338 	uint32_t r, rfh;
2339 
2340 	mutex_enter(&sc->sc_glock);
2341 
2342 	if (sc->sc_flags & IWK_F_SUSPEND) {
2343 		mutex_exit(&sc->sc_glock);
2344 		return (DDI_INTR_UNCLAIMED);
2345 	}
2346 
2347 	r = IWK_READ(sc, CSR_INT);
2348 	if (r == 0 || r == 0xffffffff) {
2349 		mutex_exit(&sc->sc_glock);
2350 		return (DDI_INTR_UNCLAIMED);
2351 	}
2352 
2353 	IWK_DBG((IWK_DEBUG_INTR, "interrupt reg %x\n", r));
2354 
2355 	rfh = IWK_READ(sc, CSR_FH_INT_STATUS);
2356 	IWK_DBG((IWK_DEBUG_INTR, "FH interrupt reg %x\n", rfh));
2357 	/* disable interrupts */
2358 	IWK_WRITE(sc, CSR_INT_MASK, 0);
2359 	/* ack interrupts */
2360 	IWK_WRITE(sc, CSR_INT, r);
2361 	IWK_WRITE(sc, CSR_FH_INT_STATUS, rfh);
2362 
2363 	if (sc->sc_soft_hdl == NULL) {
2364 		mutex_exit(&sc->sc_glock);
2365 		return (DDI_INTR_CLAIMED);
2366 	}
2367 	if (r & (BIT_INT_SWERROR | BIT_INT_ERR)) {
2368 		cmn_err(CE_WARN, "fatal firmware error\n");
2369 		mutex_exit(&sc->sc_glock);
2370 #ifdef DEBUG
2371 		/* dump event and error logs to dmesg */
2372 		iwk_write_error_log(sc);
2373 		iwk_write_event_log(sc);
2374 #endif /* DEBUG */
2375 		iwk_stop(sc);
2376 		sc->sc_ostate = sc->sc_ic.ic_state;
2377 		ieee80211_new_state(&sc->sc_ic, IEEE80211_S_INIT, -1);
2378 		sc->sc_flags |= IWK_F_HW_ERR_RECOVER;
2379 		return (DDI_INTR_CLAIMED);
2380 	}
2381 
2382 	if (r & BIT_INT_RF_KILL) {
2383 		IWK_DBG((IWK_DEBUG_RADIO, "RF kill\n"));
2384 	}
2385 
2386 	if ((r & (BIT_INT_FH_RX | BIT_INT_SW_RX)) ||
2387 	    (rfh & FH_INT_RX_MASK)) {
2388 		sc->sc_rx_softint_pending = 1;
2389 		(void) ddi_intr_trigger_softint(sc->sc_soft_hdl, NULL);
2390 	}
2391 
2392 	if (r & BIT_INT_ALIVE)	{
2393 		IWK_DBG((IWK_DEBUG_FW, "firmware initialized.\n"));
2394 	}
2395 
2396 	/* re-enable interrupts */
2397 	IWK_WRITE(sc, CSR_INT_MASK, CSR_INI_SET_MASK);
2398 	mutex_exit(&sc->sc_glock);
2399 
2400 	return (DDI_INTR_CLAIMED);
2401 }
2402 
2403 static uint8_t
2404 iwk_rate_to_plcp(int rate)
2405 {
2406 	uint8_t ret;
2407 
2408 	switch (rate) {
2409 	/* CCK rates */
2410 	case 2:
2411 		ret = 0xa;
2412 		break;
2413 	case 4:
2414 		ret = 0x14;
2415 		break;
2416 	case 11:
2417 		ret = 0x37;
2418 		break;
2419 	case 22:
2420 		ret = 0x6e;
2421 		break;
2422 	/* OFDM rates */
2423 	case 12:
2424 		ret = 0xd;
2425 		break;
2426 	case 18:
2427 		ret = 0xf;
2428 		break;
2429 	case 24:
2430 		ret = 0x5;
2431 		break;
2432 	case 36:
2433 		ret = 0x7;
2434 		break;
2435 	case 48:
2436 		ret = 0x9;
2437 		break;
2438 	case 72:
2439 		ret = 0xb;
2440 		break;
2441 	case 96:
2442 		ret = 0x1;
2443 		break;
2444 	case 108:
2445 		ret = 0x3;
2446 		break;
2447 	default:
2448 		ret = 0;
2449 		break;
2450 	}
2451 	return (ret);
2452 }
2453 
2454 static mblk_t *
2455 iwk_m_tx(void *arg, mblk_t *mp)
2456 {
2457 	iwk_sc_t	*sc = (iwk_sc_t *)arg;
2458 	ieee80211com_t	*ic = &sc->sc_ic;
2459 	mblk_t			*next;
2460 
2461 	if (sc->sc_flags & IWK_F_SUSPEND) {
2462 		freemsgchain(mp);
2463 		return (NULL);
2464 	}
2465 
2466 	if (ic->ic_state != IEEE80211_S_RUN) {
2467 		freemsgchain(mp);
2468 		return (NULL);
2469 	}
2470 
2471 	while (mp != NULL) {
2472 		next = mp->b_next;
2473 		mp->b_next = NULL;
2474 		if (iwk_send(ic, mp, IEEE80211_FC0_TYPE_DATA) != 0) {
2475 			mp->b_next = next;
2476 			break;
2477 		}
2478 		mp = next;
2479 	}
2480 	return (mp);
2481 }
2482 
2483 /* ARGSUSED */
2484 static int
2485 iwk_send(ieee80211com_t *ic, mblk_t *mp, uint8_t type)
2486 {
2487 	iwk_sc_t *sc = (iwk_sc_t *)ic;
2488 	iwk_tx_ring_t *ring;
2489 	iwk_tx_desc_t *desc;
2490 	iwk_tx_data_t *data;
2491 	iwk_cmd_t *cmd;
2492 	iwk_tx_cmd_t *tx;
2493 	ieee80211_node_t *in;
2494 	struct ieee80211_frame *wh;
2495 	struct ieee80211_key *k = NULL;
2496 	mblk_t *m, *m0;
2497 	int rate, hdrlen, len, len0, mblen, off, err = IWK_SUCCESS;
2498 	uint16_t masks = 0;
2499 
2500 	ring = &sc->sc_txq[0];
2501 	data = &ring->data[ring->cur];
2502 	desc = data->desc;
2503 	cmd = data->cmd;
2504 	bzero(desc, sizeof (*desc));
2505 	bzero(cmd, sizeof (*cmd));
2506 
2507 	mutex_enter(&sc->sc_tx_lock);
2508 	if (sc->sc_flags & IWK_F_SUSPEND) {
2509 		mutex_exit(&sc->sc_tx_lock);
2510 		if ((type & IEEE80211_FC0_TYPE_MASK) !=
2511 		    IEEE80211_FC0_TYPE_DATA) {
2512 			freemsg(mp);
2513 		}
2514 		err = IWK_FAIL;
2515 		goto exit;
2516 	}
2517 
2518 	if (ring->queued > ring->count - 64) {
2519 		IWK_DBG((IWK_DEBUG_TX, "iwk_send(): no txbuf\n"));
2520 		sc->sc_need_reschedule = 1;
2521 		mutex_exit(&sc->sc_tx_lock);
2522 		if ((type & IEEE80211_FC0_TYPE_MASK) !=
2523 		    IEEE80211_FC0_TYPE_DATA) {
2524 			freemsg(mp);
2525 		}
2526 		sc->sc_tx_nobuf++;
2527 		err = IWK_FAIL;
2528 		goto exit;
2529 	}
2530 	mutex_exit(&sc->sc_tx_lock);
2531 
2532 	hdrlen = sizeof (struct ieee80211_frame);
2533 
2534 	m = allocb(msgdsize(mp) + 32, BPRI_MED);
2535 	if (m == NULL) { /* can not alloc buf, drop this package */
2536 		cmn_err(CE_WARN,
2537 		    "iwk_send(): failed to allocate msgbuf\n");
2538 		freemsg(mp);
2539 		err = IWK_SUCCESS;
2540 		goto exit;
2541 	}
2542 	for (off = 0, m0 = mp; m0 != NULL; m0 = m0->b_cont) {
2543 		mblen = MBLKL(m0);
2544 		(void) memcpy(m->b_rptr + off, m0->b_rptr, mblen);
2545 		off += mblen;
2546 	}
2547 	m->b_wptr += off;
2548 	freemsg(mp);
2549 
2550 	wh = (struct ieee80211_frame *)m->b_rptr;
2551 
2552 	in = ieee80211_find_txnode(ic, wh->i_addr1);
2553 	if (in == NULL) {
2554 		cmn_err(CE_WARN, "iwk_send(): failed to find tx node\n");
2555 		freemsg(m);
2556 		sc->sc_tx_err++;
2557 		err = IWK_SUCCESS;
2558 		goto exit;
2559 	}
2560 	(void) ieee80211_encap(ic, m, in);
2561 
2562 	cmd->hdr.type = REPLY_TX;
2563 	cmd->hdr.flags = 0;
2564 	cmd->hdr.qid = ring->qid;
2565 	cmd->hdr.idx = ring->cur;
2566 
2567 	tx = (iwk_tx_cmd_t *)cmd->data;
2568 	tx->tx_flags = 0;
2569 
2570 	if (IEEE80211_IS_MULTICAST(wh->i_addr1)) {
2571 		tx->tx_flags &= ~(LE_32(TX_CMD_FLG_ACK_MSK));
2572 	} else {
2573 		tx->tx_flags |= LE_32(TX_CMD_FLG_ACK_MSK);
2574 	}
2575 
2576 	if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
2577 		k = ieee80211_crypto_encap(ic, m);
2578 		if (k == NULL) {
2579 			freemsg(m);
2580 			sc->sc_tx_err++;
2581 			err = IWK_SUCCESS;
2582 			goto exit;
2583 		}
2584 
2585 		if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_AES_CCM) {
2586 			tx->sec_ctl = 2; /* for CCMP */
2587 			tx->tx_flags |= LE_32(TX_CMD_FLG_ACK_MSK);
2588 			(void) memcpy(&tx->key, k->wk_key, k->wk_keylen);
2589 		}
2590 
2591 		/* packet header may have moved, reset our local pointer */
2592 		wh = (struct ieee80211_frame *)m->b_rptr;
2593 	}
2594 
2595 	len = msgdsize(m);
2596 
2597 #ifdef DEBUG
2598 	if (iwk_dbg_flags & IWK_DEBUG_TX)
2599 		ieee80211_dump_pkt((uint8_t *)wh, hdrlen, 0, 0);
2600 #endif
2601 
2602 	/* pickup a rate */
2603 	if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
2604 	    IEEE80211_FC0_TYPE_MGT) {
2605 		/* mgmt frames are sent at 1M */
2606 		rate = in->in_rates.ir_rates[0];
2607 	} else {
2608 		/*
2609 		 * do it here for the software way rate control.
2610 		 * later for rate scaling in hardware.
2611 		 * maybe like the following, for management frame:
2612 		 * tx->initial_rate_index = LINK_QUAL_MAX_RETRY_NUM - 1;
2613 		 * for data frame:
2614 		 * tx->tx_flags |= (LE_32(TX_CMD_FLG_STA_RATE_MSK));
2615 		 * rate = in->in_rates.ir_rates[in->in_txrate];
2616 		 * tx->initial_rate_index = 1;
2617 		 *
2618 		 * now the txrate is determined in tx cmd flags, set to the
2619 		 * max value 54M for 11g and 11M for 11b.
2620 		 */
2621 
2622 		if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE) {
2623 			rate = ic->ic_fixed_rate;
2624 		} else {
2625 			rate = in->in_rates.ir_rates[in->in_txrate];
2626 		}
2627 	}
2628 	rate &= IEEE80211_RATE_VAL;
2629 	IWK_DBG((IWK_DEBUG_TX, "tx rate[%d of %d] = %x",
2630 	    in->in_txrate, in->in_rates.ir_nrates, rate));
2631 
2632 	tx->tx_flags |= (LE_32(TX_CMD_FLG_SEQ_CTL_MSK));
2633 
2634 	len0 = roundup(4 + sizeof (iwk_tx_cmd_t) + hdrlen, 4);
2635 	if (len0 != (4 + sizeof (iwk_tx_cmd_t) + hdrlen))
2636 		tx->tx_flags |= TX_CMD_FLG_MH_PAD_MSK;
2637 
2638 	/* retrieve destination node's id */
2639 	if (IEEE80211_IS_MULTICAST(wh->i_addr1)) {
2640 		tx->sta_id = IWK_BROADCAST_ID;
2641 	} else {
2642 		if (ic->ic_opmode != IEEE80211_M_IBSS)
2643 			tx->sta_id = IWK_AP_ID;
2644 	}
2645 
2646 	if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
2647 	    IEEE80211_FC0_TYPE_MGT) {
2648 		/* tell h/w to set timestamp in probe responses */
2649 		if ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) ==
2650 		    IEEE80211_FC0_SUBTYPE_PROBE_RESP)
2651 			tx->tx_flags |= LE_32(TX_CMD_FLG_TSF_MSK);
2652 
2653 		if (((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) ==
2654 		    IEEE80211_FC0_SUBTYPE_ASSOC_REQ) ||
2655 		    ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) ==
2656 		    IEEE80211_FC0_SUBTYPE_REASSOC_REQ))
2657 			tx->timeout.pm_frame_timeout = 3;
2658 		else
2659 			tx->timeout.pm_frame_timeout = 2;
2660 	} else
2661 		tx->timeout.pm_frame_timeout = 0;
2662 	if (rate == 2 || rate == 4 || rate == 11 || rate == 22)
2663 		masks |= RATE_MCS_CCK_MSK;
2664 
2665 	masks |= RATE_MCS_ANT_B_MSK;
2666 	tx->rate.r.rate_n_flags = (iwk_rate_to_plcp(rate) | masks);
2667 
2668 	IWK_DBG((IWK_DEBUG_TX, "tx flag = %x",
2669 	    tx->tx_flags));
2670 
2671 	tx->rts_retry_limit = 60;
2672 	tx->data_retry_limit = 15;
2673 
2674 	tx->stop_time.life_time  = LE_32(0xffffffff);
2675 
2676 	tx->len = LE_16(len);
2677 
2678 	tx->dram_lsb_ptr =
2679 	    data->paddr_cmd + 4 + offsetof(iwk_tx_cmd_t, scratch);
2680 	tx->dram_msb_ptr = 0;
2681 	tx->driver_txop = 0;
2682 	tx->next_frame_len = 0;
2683 
2684 	(void) memcpy(tx + 1, m->b_rptr, hdrlen);
2685 	m->b_rptr += hdrlen;
2686 	(void) memcpy(data->dma_data.mem_va, m->b_rptr, len - hdrlen);
2687 
2688 	IWK_DBG((IWK_DEBUG_TX, "sending data: qid=%d idx=%d len=%d",
2689 	    ring->qid, ring->cur, len));
2690 
2691 	/*
2692 	 * first segment includes the tx cmd plus the 802.11 header,
2693 	 * the second includes the remaining of the 802.11 frame.
2694 	 */
2695 	desc->val0 = LE_32(2 << 24);
2696 	desc->pa[0].tb1_addr = LE_32(data->paddr_cmd);
2697 	desc->pa[0].val1 = ((len0 << 4) & 0xfff0) |
2698 	    ((data->dma_data.cookie.dmac_address & 0xffff) << 16);
2699 	desc->pa[0].val2 =
2700 	    ((data->dma_data.cookie.dmac_address & 0xffff0000) >> 16) |
2701 	    ((len - hdrlen) << 20);
2702 	IWK_DBG((IWK_DEBUG_TX, "phy addr1 = 0x%x phy addr2 = 0x%x "
2703 	    "len1 = 0x%x, len2 = 0x%x val1 = 0x%x val2 = 0x%x",
2704 	    data->paddr_cmd, data->dma_data.cookie.dmac_address,
2705 	    len0, len - hdrlen, desc->pa[0].val1, desc->pa[0].val2));
2706 
2707 	mutex_enter(&sc->sc_tx_lock);
2708 	ring->queued++;
2709 	mutex_exit(&sc->sc_tx_lock);
2710 
2711 	/* kick ring */
2712 	sc->sc_shared->queues_byte_cnt_tbls[ring->qid].
2713 	    tfd_offset[ring->cur].val = 8 + len;
2714 	if (ring->cur < IWK_MAX_WIN_SIZE) {
2715 		sc->sc_shared->queues_byte_cnt_tbls[ring->qid].
2716 		    tfd_offset[IWK_QUEUE_SIZE + ring->cur].val = 8 + len;
2717 	}
2718 
2719 	IWK_DMA_SYNC(data->dma_data, DDI_DMA_SYNC_FORDEV);
2720 	IWK_DMA_SYNC(ring->dma_desc, DDI_DMA_SYNC_FORDEV);
2721 
2722 	ring->cur = (ring->cur + 1) % ring->count;
2723 	IWK_WRITE(sc, HBUS_TARG_WRPTR, ring->qid << 8 | ring->cur);
2724 	freemsg(m);
2725 	/* release node reference */
2726 	ieee80211_free_node(in);
2727 
2728 	ic->ic_stats.is_tx_bytes += len;
2729 	ic->ic_stats.is_tx_frags++;
2730 
2731 	if (sc->sc_tx_timer == 0)
2732 		sc->sc_tx_timer = 10;
2733 exit:
2734 	return (err);
2735 }
2736 
2737 static void
2738 iwk_m_ioctl(void* arg, queue_t *wq, mblk_t *mp)
2739 {
2740 	iwk_sc_t	*sc  = (iwk_sc_t *)arg;
2741 	ieee80211com_t	*ic = &sc->sc_ic;
2742 	int		err;
2743 
2744 	err = ieee80211_ioctl(ic, wq, mp);
2745 
2746 	if (err == ENETRESET) {
2747 		/*
2748 		 * This is special for the hidden AP connection.
2749 		 * In any case, we should make sure only one 'scan'
2750 		 * in the driver for a 'connect' CLI command. So
2751 		 * when connecting to a hidden AP, the scan is just
2752 		 * sent out to the air when we know the desired
2753 		 * essid of the AP we want to connect.
2754 		 */
2755 		if (ic->ic_des_esslen) {
2756 			if (sc->sc_flags & IWK_F_RUNNING) {
2757 				iwk_m_stop(sc);
2758 				(void) iwk_m_start(sc);
2759 				(void) ieee80211_new_state(ic,
2760 				    IEEE80211_S_SCAN, -1);
2761 			}
2762 		}
2763 	}
2764 }
2765 
2766 /*
2767  * callback functions for set/get properties
2768  */
2769 /* ARGSUSED */
2770 static int
2771 iwk_m_getprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
2772     uint_t pr_flags, uint_t wldp_length, void *wldp_buf, uint_t *perm)
2773 {
2774 	int		err = 0;
2775 	iwk_sc_t	*sc = (iwk_sc_t *)arg;
2776 
2777 	err = ieee80211_getprop(&sc->sc_ic, pr_name, wldp_pr_num,
2778 	    pr_flags, wldp_length, wldp_buf, perm);
2779 
2780 	return (err);
2781 }
2782 static int
2783 iwk_m_setprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
2784     uint_t wldp_length, const void *wldp_buf)
2785 {
2786 	int		err;
2787 	iwk_sc_t	*sc = (iwk_sc_t *)arg;
2788 	ieee80211com_t	*ic = &sc->sc_ic;
2789 
2790 	err = ieee80211_setprop(ic, pr_name, wldp_pr_num, wldp_length,
2791 	    wldp_buf);
2792 
2793 	if (err == ENETRESET) {
2794 		if (ic->ic_des_esslen) {
2795 			if (sc->sc_flags & IWK_F_RUNNING) {
2796 				iwk_m_stop(sc);
2797 				(void) iwk_m_start(sc);
2798 				(void) ieee80211_new_state(ic,
2799 				    IEEE80211_S_SCAN, -1);
2800 			}
2801 		}
2802 		err = 0;
2803 	}
2804 
2805 	return (err);
2806 }
2807 
2808 /*ARGSUSED*/
2809 static int
2810 iwk_m_stat(void *arg, uint_t stat, uint64_t *val)
2811 {
2812 	iwk_sc_t	*sc  = (iwk_sc_t *)arg;
2813 	ieee80211com_t	*ic = &sc->sc_ic;
2814 	ieee80211_node_t *in = ic->ic_bss;
2815 	struct ieee80211_rateset *rs = &in->in_rates;
2816 
2817 	mutex_enter(&sc->sc_glock);
2818 	switch (stat) {
2819 	case MAC_STAT_IFSPEED:
2820 		*val = ((ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE) ?
2821 		    (rs->ir_rates[in->in_txrate] & IEEE80211_RATE_VAL)
2822 		    : ic->ic_fixed_rate) /2 * 1000000;
2823 		break;
2824 	case MAC_STAT_NOXMTBUF:
2825 		*val = sc->sc_tx_nobuf;
2826 		break;
2827 	case MAC_STAT_NORCVBUF:
2828 		*val = sc->sc_rx_nobuf;
2829 		break;
2830 	case MAC_STAT_IERRORS:
2831 		*val = sc->sc_rx_err;
2832 		break;
2833 	case MAC_STAT_RBYTES:
2834 		*val = ic->ic_stats.is_rx_bytes;
2835 		break;
2836 	case MAC_STAT_IPACKETS:
2837 		*val = ic->ic_stats.is_rx_frags;
2838 		break;
2839 	case MAC_STAT_OBYTES:
2840 		*val = ic->ic_stats.is_tx_bytes;
2841 		break;
2842 	case MAC_STAT_OPACKETS:
2843 		*val = ic->ic_stats.is_tx_frags;
2844 		break;
2845 	case MAC_STAT_OERRORS:
2846 	case WIFI_STAT_TX_FAILED:
2847 		*val = sc->sc_tx_err;
2848 		break;
2849 	case WIFI_STAT_TX_RETRANS:
2850 		*val = sc->sc_tx_retries;
2851 		break;
2852 	case WIFI_STAT_FCS_ERRORS:
2853 	case WIFI_STAT_WEP_ERRORS:
2854 	case WIFI_STAT_TX_FRAGS:
2855 	case WIFI_STAT_MCAST_TX:
2856 	case WIFI_STAT_RTS_SUCCESS:
2857 	case WIFI_STAT_RTS_FAILURE:
2858 	case WIFI_STAT_ACK_FAILURE:
2859 	case WIFI_STAT_RX_FRAGS:
2860 	case WIFI_STAT_MCAST_RX:
2861 	case WIFI_STAT_RX_DUPS:
2862 		mutex_exit(&sc->sc_glock);
2863 		return (ieee80211_stat(ic, stat, val));
2864 	default:
2865 		mutex_exit(&sc->sc_glock);
2866 		return (ENOTSUP);
2867 	}
2868 	mutex_exit(&sc->sc_glock);
2869 
2870 	return (IWK_SUCCESS);
2871 
2872 }
2873 
2874 static int
2875 iwk_m_start(void *arg)
2876 {
2877 	iwk_sc_t *sc = (iwk_sc_t *)arg;
2878 	ieee80211com_t	*ic = &sc->sc_ic;
2879 	int err;
2880 
2881 	err = iwk_init(sc);
2882 
2883 	if (err != IWK_SUCCESS) {
2884 		/*
2885 		 * The hw init err(eg. RF is OFF). Return Success to make
2886 		 * the 'plumb' succeed. The iwk_thread() tries to re-init
2887 		 * background.
2888 		 */
2889 		cmn_err(CE_WARN, "iwk_m_start(): failed to initialize "
2890 		    "hardware\n");
2891 		mutex_enter(&sc->sc_glock);
2892 		sc->sc_flags |= IWK_F_HW_ERR_RECOVER;
2893 		mutex_exit(&sc->sc_glock);
2894 		return (IWK_SUCCESS);
2895 	}
2896 
2897 	ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
2898 
2899 	mutex_enter(&sc->sc_glock);
2900 	sc->sc_flags |= IWK_F_RUNNING;
2901 	mutex_exit(&sc->sc_glock);
2902 
2903 	return (IWK_SUCCESS);
2904 }
2905 
2906 static void
2907 iwk_m_stop(void *arg)
2908 {
2909 	iwk_sc_t *sc = (iwk_sc_t *)arg;
2910 	ieee80211com_t	*ic = &sc->sc_ic;
2911 
2912 	iwk_stop(sc);
2913 	ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
2914 	mutex_enter(&sc->sc_mt_lock);
2915 	sc->sc_flags &= ~IWK_F_HW_ERR_RECOVER;
2916 	sc->sc_flags &= ~IWK_F_RATE_AUTO_CTL;
2917 	mutex_exit(&sc->sc_mt_lock);
2918 	mutex_enter(&sc->sc_glock);
2919 	sc->sc_flags &= ~IWK_F_RUNNING;
2920 	sc->sc_flags &= ~IWK_F_SCANNING;
2921 	mutex_exit(&sc->sc_glock);
2922 }
2923 
2924 /*ARGSUSED*/
2925 static int
2926 iwk_m_unicst(void *arg, const uint8_t *macaddr)
2927 {
2928 	iwk_sc_t *sc = (iwk_sc_t *)arg;
2929 	ieee80211com_t	*ic = &sc->sc_ic;
2930 	int err;
2931 
2932 	if (!IEEE80211_ADDR_EQ(ic->ic_macaddr, macaddr)) {
2933 		IEEE80211_ADDR_COPY(ic->ic_macaddr, macaddr);
2934 		mutex_enter(&sc->sc_glock);
2935 		err = iwk_config(sc);
2936 		mutex_exit(&sc->sc_glock);
2937 		if (err != IWK_SUCCESS) {
2938 			cmn_err(CE_WARN,
2939 			    "iwk_m_unicst(): "
2940 			    "failed to configure device\n");
2941 			goto fail;
2942 		}
2943 	}
2944 	return (IWK_SUCCESS);
2945 fail:
2946 	return (err);
2947 }
2948 
2949 /*ARGSUSED*/
2950 static int
2951 iwk_m_multicst(void *arg, boolean_t add, const uint8_t *m)
2952 {
2953 	return (IWK_SUCCESS);
2954 }
2955 
2956 /*ARGSUSED*/
2957 static int
2958 iwk_m_promisc(void *arg, boolean_t on)
2959 {
2960 	return (IWK_SUCCESS);
2961 }
2962 
2963 static void
2964 iwk_thread(iwk_sc_t *sc)
2965 {
2966 	ieee80211com_t	*ic = &sc->sc_ic;
2967 	clock_t clk;
2968 	int times = 0, err, n = 0, timeout = 0;
2969 	uint32_t tmp;
2970 
2971 	mutex_enter(&sc->sc_mt_lock);
2972 	while (sc->sc_mf_thread_switch) {
2973 		tmp = IWK_READ(sc, CSR_GP_CNTRL);
2974 		if (tmp & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) {
2975 			sc->sc_flags &= ~IWK_F_RADIO_OFF;
2976 		} else {
2977 			sc->sc_flags |= IWK_F_RADIO_OFF;
2978 		}
2979 		/*
2980 		 * If in SUSPEND or the RF is OFF, do nothing
2981 		 */
2982 		if ((sc->sc_flags & IWK_F_SUSPEND) ||
2983 		    (sc->sc_flags & IWK_F_RADIO_OFF)) {
2984 			mutex_exit(&sc->sc_mt_lock);
2985 			delay(drv_usectohz(100000));
2986 			mutex_enter(&sc->sc_mt_lock);
2987 			continue;
2988 		}
2989 
2990 		/*
2991 		 * recovery fatal error
2992 		 */
2993 		if (ic->ic_mach &&
2994 		    (sc->sc_flags & IWK_F_HW_ERR_RECOVER)) {
2995 
2996 			IWK_DBG((IWK_DEBUG_FW,
2997 			    "iwk_thread(): "
2998 			    "try to recover fatal hw error: %d\n", times++));
2999 
3000 			iwk_stop(sc);
3001 
3002 			mutex_exit(&sc->sc_mt_lock);
3003 			ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
3004 			delay(drv_usectohz(2000000 + n*500000));
3005 			mutex_enter(&sc->sc_mt_lock);
3006 
3007 			err = iwk_init(sc);
3008 			if (err != IWK_SUCCESS) {
3009 				n++;
3010 				if (n < 20)
3011 					continue;
3012 			}
3013 			n = 0;
3014 			if (!err)
3015 				sc->sc_flags |= IWK_F_RUNNING;
3016 			sc->sc_flags &= ~IWK_F_HW_ERR_RECOVER;
3017 			mutex_exit(&sc->sc_mt_lock);
3018 			delay(drv_usectohz(2000000));
3019 			if (sc->sc_ostate != IEEE80211_S_INIT)
3020 				ieee80211_new_state(ic, IEEE80211_S_SCAN, 0);
3021 			mutex_enter(&sc->sc_mt_lock);
3022 		}
3023 
3024 		if (ic->ic_mach &&
3025 		    (sc->sc_flags & IWK_F_SCANNING) && sc->sc_scan_pending) {
3026 
3027 			IWK_DBG((IWK_DEBUG_SCAN,
3028 			    "iwk_thread(): "
3029 			    "wait for probe response\n"));
3030 
3031 			sc->sc_scan_pending--;
3032 			mutex_exit(&sc->sc_mt_lock);
3033 			delay(drv_usectohz(200000));
3034 			ieee80211_next_scan(ic);
3035 			mutex_enter(&sc->sc_mt_lock);
3036 		}
3037 
3038 		/*
3039 		 * rate ctl
3040 		 */
3041 		if (ic->ic_mach &&
3042 		    (sc->sc_flags & IWK_F_RATE_AUTO_CTL)) {
3043 			clk = ddi_get_lbolt();
3044 			if (clk > sc->sc_clk + drv_usectohz(500000)) {
3045 				iwk_amrr_timeout(sc);
3046 			}
3047 		}
3048 
3049 		mutex_exit(&sc->sc_mt_lock);
3050 		delay(drv_usectohz(100000));
3051 		mutex_enter(&sc->sc_mt_lock);
3052 
3053 		if (sc->sc_tx_timer) {
3054 			timeout++;
3055 			if (timeout == 10) {
3056 				sc->sc_tx_timer--;
3057 				if (sc->sc_tx_timer == 0) {
3058 					sc->sc_flags |= IWK_F_HW_ERR_RECOVER;
3059 					sc->sc_ostate = IEEE80211_S_RUN;
3060 					IWK_DBG((IWK_DEBUG_FW,
3061 					    "iwk_thread(): try to recover from"
3062 					    " 'send fail\n"));
3063 				}
3064 				timeout = 0;
3065 			}
3066 		}
3067 
3068 	}
3069 	sc->sc_mf_thread = NULL;
3070 	cv_signal(&sc->sc_mt_cv);
3071 	mutex_exit(&sc->sc_mt_lock);
3072 }
3073 
3074 
3075 /*
3076  * Send a command to the firmware.
3077  */
3078 static int
3079 iwk_cmd(iwk_sc_t *sc, int code, const void *buf, int size, int async)
3080 {
3081 	iwk_tx_ring_t *ring = &sc->sc_txq[IWK_CMD_QUEUE_NUM];
3082 	iwk_tx_desc_t *desc;
3083 	iwk_cmd_t *cmd;
3084 	clock_t clk;
3085 
3086 	ASSERT(size <= sizeof (cmd->data));
3087 	ASSERT(mutex_owned(&sc->sc_glock));
3088 
3089 	IWK_DBG((IWK_DEBUG_CMD, "iwk_cmd() code[%d]", code));
3090 	desc = ring->data[ring->cur].desc;
3091 	cmd = ring->data[ring->cur].cmd;
3092 
3093 	cmd->hdr.type = (uint8_t)code;
3094 	cmd->hdr.flags = 0;
3095 	cmd->hdr.qid = ring->qid;
3096 	cmd->hdr.idx = ring->cur;
3097 	(void) memcpy(cmd->data, buf, size);
3098 	(void) memset(desc, 0, sizeof (*desc));
3099 
3100 	desc->val0 = LE_32(1 << 24);
3101 	desc->pa[0].tb1_addr =
3102 	    (uint32_t)(ring->data[ring->cur].paddr_cmd & 0xffffffff);
3103 	desc->pa[0].val1 = ((4 + size) << 4) & 0xfff0;
3104 
3105 	/* kick cmd ring XXX */
3106 	sc->sc_shared->queues_byte_cnt_tbls[ring->qid].
3107 	    tfd_offset[ring->cur].val = 8;
3108 	if (ring->cur < IWK_MAX_WIN_SIZE) {
3109 		sc->sc_shared->queues_byte_cnt_tbls[ring->qid].
3110 		    tfd_offset[IWK_QUEUE_SIZE + ring->cur].val = 8;
3111 	}
3112 	ring->cur = (ring->cur + 1) % ring->count;
3113 	IWK_WRITE(sc, HBUS_TARG_WRPTR, ring->qid << 8 | ring->cur);
3114 
3115 	if (async)
3116 		return (IWK_SUCCESS);
3117 	else {
3118 		sc->sc_flags &= ~IWK_F_CMD_DONE;
3119 		clk = ddi_get_lbolt() + drv_usectohz(2000000);
3120 		while (!(sc->sc_flags & IWK_F_CMD_DONE)) {
3121 			if (cv_timedwait(&sc->sc_cmd_cv, &sc->sc_glock, clk) <
3122 			    0)
3123 				break;
3124 		}
3125 		if (sc->sc_flags & IWK_F_CMD_DONE)
3126 			return (IWK_SUCCESS);
3127 		else
3128 			return (IWK_FAIL);
3129 	}
3130 }
3131 
3132 static void
3133 iwk_set_led(iwk_sc_t *sc, uint8_t id, uint8_t off, uint8_t on)
3134 {
3135 	iwk_led_cmd_t led;
3136 
3137 	led.interval = LE_32(100000);	/* unit: 100ms */
3138 	led.id = id;
3139 	led.off = off;
3140 	led.on = on;
3141 
3142 	(void) iwk_cmd(sc, REPLY_LEDS_CMD, &led, sizeof (led), 1);
3143 }
3144 
3145 static int
3146 iwk_hw_set_before_auth(iwk_sc_t *sc)
3147 {
3148 	ieee80211com_t *ic = &sc->sc_ic;
3149 	ieee80211_node_t *in = ic->ic_bss;
3150 	iwk_add_sta_t node;
3151 	iwk_link_quality_cmd_t link_quality;
3152 	struct ieee80211_rateset rs;
3153 	uint16_t masks = 0, rate;
3154 	int i, err;
3155 
3156 	/* update adapter's configuration according the info of target AP */
3157 	IEEE80211_ADDR_COPY(sc->sc_config.bssid, in->in_bssid);
3158 	sc->sc_config.chan = ieee80211_chan2ieee(ic, in->in_chan);
3159 	if (ic->ic_curmode == IEEE80211_MODE_11B) {
3160 		sc->sc_config.cck_basic_rates  = 0x03;
3161 		sc->sc_config.ofdm_basic_rates = 0;
3162 	} else if ((in->in_chan != IEEE80211_CHAN_ANYC) &&
3163 	    (IEEE80211_IS_CHAN_5GHZ(in->in_chan))) {
3164 		sc->sc_config.cck_basic_rates  = 0;
3165 		sc->sc_config.ofdm_basic_rates = 0x15;
3166 	} else { /* assume 802.11b/g */
3167 		sc->sc_config.cck_basic_rates  = 0x0f;
3168 		sc->sc_config.ofdm_basic_rates = 0xff;
3169 	}
3170 
3171 	sc->sc_config.flags &= ~LE_32(RXON_FLG_SHORT_PREAMBLE_MSK |
3172 	    RXON_FLG_SHORT_SLOT_MSK);
3173 
3174 	if (ic->ic_flags & IEEE80211_F_SHSLOT)
3175 		sc->sc_config.flags |= LE_32(RXON_FLG_SHORT_SLOT_MSK);
3176 	else
3177 		sc->sc_config.flags &= LE_32(~RXON_FLG_SHORT_SLOT_MSK);
3178 
3179 	if (ic->ic_flags & IEEE80211_F_SHPREAMBLE)
3180 		sc->sc_config.flags |= LE_32(RXON_FLG_SHORT_PREAMBLE_MSK);
3181 	else
3182 		sc->sc_config.flags &= LE_32(~RXON_FLG_SHORT_PREAMBLE_MSK);
3183 
3184 	IWK_DBG((IWK_DEBUG_80211, "config chan %d flags %x "
3185 	    "filter_flags %x  cck %x ofdm %x"
3186 	    " bssid:%02x:%02x:%02x:%02x:%02x:%2x\n",
3187 	    sc->sc_config.chan, sc->sc_config.flags,
3188 	    sc->sc_config.filter_flags,
3189 	    sc->sc_config.cck_basic_rates, sc->sc_config.ofdm_basic_rates,
3190 	    sc->sc_config.bssid[0], sc->sc_config.bssid[1],
3191 	    sc->sc_config.bssid[2], sc->sc_config.bssid[3],
3192 	    sc->sc_config.bssid[4], sc->sc_config.bssid[5]));
3193 	err = iwk_cmd(sc, REPLY_RXON, &sc->sc_config,
3194 	    sizeof (iwk_rxon_cmd_t), 1);
3195 	if (err != IWK_SUCCESS) {
3196 		cmn_err(CE_WARN, "iwk_hw_set_before_auth():"
3197 		    " failed to config chan%d\n",
3198 		    sc->sc_config.chan);
3199 		return (err);
3200 	}
3201 
3202 	/* obtain current temperature of chipset */
3203 	sc->sc_tempera = iwk_curr_tempera(sc);
3204 
3205 	/* make Tx power calibration to determine the gains of DSP and radio */
3206 	err = iwk_tx_power_calibration(sc);
3207 	if (err) {
3208 		cmn_err(CE_WARN, "iwk_hw_set_before_auth():"
3209 		    "failed to set tx power table\n");
3210 		return (err);
3211 	}
3212 
3213 	/* add default AP node */
3214 	(void) memset(&node, 0, sizeof (node));
3215 	IEEE80211_ADDR_COPY(node.bssid, in->in_bssid);
3216 	node.id = IWK_AP_ID;
3217 	err = iwk_cmd(sc, REPLY_ADD_STA, &node, sizeof (node), 1);
3218 	if (err != IWK_SUCCESS) {
3219 		cmn_err(CE_WARN, "iwk_hw_set_before_auth(): "
3220 		    "failed to add BSS node\n");
3221 		return (err);
3222 	}
3223 
3224 	/* TX_LINK_QUALITY cmd ? */
3225 	(void) memset(&link_quality, 0, sizeof (link_quality));
3226 	rs = ic->ic_sup_rates[ieee80211_chan2mode(ic, ic->ic_curchan)];
3227 	for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) {
3228 		if (i < rs.ir_nrates)
3229 			rate = rs.ir_rates[rs.ir_nrates - i];
3230 		else
3231 			rate = 2;
3232 		if (rate == 2 || rate == 4 || rate == 11 || rate == 22)
3233 			masks |= RATE_MCS_CCK_MSK;
3234 		masks |= RATE_MCS_ANT_B_MSK;
3235 		masks &= ~RATE_MCS_ANT_A_MSK;
3236 		link_quality.rate_n_flags[i] =
3237 		    iwk_rate_to_plcp(rate) | masks;
3238 	}
3239 
3240 	link_quality.general_params.single_stream_ant_msk = 2;
3241 	link_quality.general_params.dual_stream_ant_msk = 3;
3242 	link_quality.agg_params.agg_dis_start_th = 3;
3243 	link_quality.agg_params.agg_time_limit = LE_16(4000);
3244 	link_quality.sta_id = IWK_AP_ID;
3245 	err = iwk_cmd(sc, REPLY_TX_LINK_QUALITY_CMD, &link_quality,
3246 	    sizeof (link_quality), 1);
3247 	if (err != IWK_SUCCESS) {
3248 		cmn_err(CE_WARN, "iwk_hw_set_before_auth(): "
3249 		    "failed to config link quality table\n");
3250 		return (err);
3251 	}
3252 
3253 	return (IWK_SUCCESS);
3254 }
3255 
3256 /*
3257  * Send a scan request(assembly scan cmd) to the firmware.
3258  */
3259 static int
3260 iwk_scan(iwk_sc_t *sc)
3261 {
3262 	ieee80211com_t *ic = &sc->sc_ic;
3263 	iwk_tx_ring_t *ring = &sc->sc_txq[IWK_CMD_QUEUE_NUM];
3264 	iwk_tx_desc_t *desc;
3265 	iwk_tx_data_t *data;
3266 	iwk_cmd_t *cmd;
3267 	iwk_scan_hdr_t *hdr;
3268 	iwk_scan_chan_t *chan;
3269 	struct ieee80211_frame *wh;
3270 	ieee80211_node_t *in = ic->ic_bss;
3271 	uint8_t essid[IEEE80211_NWID_LEN+1];
3272 	struct ieee80211_rateset *rs;
3273 	enum ieee80211_phymode mode;
3274 	uint8_t *frm;
3275 	int i, pktlen, nrates;
3276 
3277 	data = &ring->data[ring->cur];
3278 	desc = data->desc;
3279 	cmd = (iwk_cmd_t *)data->dma_data.mem_va;
3280 
3281 	cmd->hdr.type = REPLY_SCAN_CMD;
3282 	cmd->hdr.flags = 0;
3283 	cmd->hdr.qid = ring->qid;
3284 	cmd->hdr.idx = ring->cur | 0x40;
3285 
3286 	hdr = (iwk_scan_hdr_t *)cmd->data;
3287 	(void) memset(hdr, 0, sizeof (iwk_scan_hdr_t));
3288 	hdr->nchan = 1;
3289 	hdr->quiet_time = LE_16(50);
3290 	hdr->quiet_plcp_th = LE_16(1);
3291 
3292 	hdr->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK;
3293 	hdr->rx_chain = RXON_RX_CHAIN_DRIVER_FORCE_MSK |
3294 	    LE_16((0x7 << RXON_RX_CHAIN_VALID_POS) |
3295 	    (0x6 << RXON_RX_CHAIN_FORCE_SEL_POS) |
3296 	    (0x7 << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS));
3297 
3298 	hdr->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK;
3299 	hdr->tx_cmd.sta_id = IWK_BROADCAST_ID;
3300 	hdr->tx_cmd.stop_time.life_time = 0xffffffff;
3301 	hdr->tx_cmd.tx_flags |= (0x200);
3302 	hdr->tx_cmd.rate.r.rate_n_flags = iwk_rate_to_plcp(2);
3303 	hdr->tx_cmd.rate.r.rate_n_flags |=
3304 	    (RATE_MCS_ANT_B_MSK|RATE_MCS_CCK_MSK);
3305 	hdr->direct_scan[0].len = ic->ic_des_esslen;
3306 	hdr->direct_scan[0].id  = IEEE80211_ELEMID_SSID;
3307 
3308 	if (ic->ic_des_esslen) {
3309 		bcopy(ic->ic_des_essid, essid, ic->ic_des_esslen);
3310 		essid[ic->ic_des_esslen] = '\0';
3311 		IWK_DBG((IWK_DEBUG_SCAN, "directed scan %s\n", essid));
3312 
3313 		bcopy(ic->ic_des_essid, hdr->direct_scan[0].ssid,
3314 		    ic->ic_des_esslen);
3315 	} else {
3316 		bzero(hdr->direct_scan[0].ssid,
3317 		    sizeof (hdr->direct_scan[0].ssid));
3318 	}
3319 	/*
3320 	 * a probe request frame is required after the REPLY_SCAN_CMD
3321 	 */
3322 	wh = (struct ieee80211_frame *)(hdr + 1);
3323 	wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT |
3324 	    IEEE80211_FC0_SUBTYPE_PROBE_REQ;
3325 	wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
3326 	(void) memset(wh->i_addr1, 0xff, 6);
3327 	IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_macaddr);
3328 	(void) memset(wh->i_addr3, 0xff, 6);
3329 	*(uint16_t *)&wh->i_dur[0] = 0;
3330 	*(uint16_t *)&wh->i_seq[0] = 0;
3331 
3332 	frm = (uint8_t *)(wh + 1);
3333 
3334 	/* essid IE */
3335 	if (in->in_esslen) {
3336 		bcopy(in->in_essid, essid, in->in_esslen);
3337 		essid[in->in_esslen] = '\0';
3338 		IWK_DBG((IWK_DEBUG_SCAN, "probe with ESSID %s\n",
3339 		    essid));
3340 	}
3341 	*frm++ = IEEE80211_ELEMID_SSID;
3342 	*frm++ = in->in_esslen;
3343 	(void) memcpy(frm, in->in_essid, in->in_esslen);
3344 	frm += in->in_esslen;
3345 
3346 	mode = ieee80211_chan2mode(ic, ic->ic_curchan);
3347 	rs = &ic->ic_sup_rates[mode];
3348 
3349 	/* supported rates IE */
3350 	*frm++ = IEEE80211_ELEMID_RATES;
3351 	nrates = rs->ir_nrates;
3352 	if (nrates > IEEE80211_RATE_SIZE)
3353 		nrates = IEEE80211_RATE_SIZE;
3354 	*frm++ = (uint8_t)nrates;
3355 	(void) memcpy(frm, rs->ir_rates, nrates);
3356 	frm += nrates;
3357 
3358 	/* supported xrates IE */
3359 	if (rs->ir_nrates > IEEE80211_RATE_SIZE) {
3360 		nrates = rs->ir_nrates - IEEE80211_RATE_SIZE;
3361 		*frm++ = IEEE80211_ELEMID_XRATES;
3362 		*frm++ = (uint8_t)nrates;
3363 		(void) memcpy(frm, rs->ir_rates + IEEE80211_RATE_SIZE, nrates);
3364 		frm += nrates;
3365 	}
3366 
3367 	/* optionnal IE (usually for wpa) */
3368 	if (ic->ic_opt_ie != NULL) {
3369 		(void) memcpy(frm, ic->ic_opt_ie, ic->ic_opt_ie_len);
3370 		frm += ic->ic_opt_ie_len;
3371 	}
3372 
3373 	/* setup length of probe request */
3374 	hdr->tx_cmd.len = LE_16(_PTRDIFF(frm, wh));
3375 	hdr->len = hdr->nchan * sizeof (iwk_scan_chan_t) +
3376 	    hdr->tx_cmd.len + sizeof (iwk_scan_hdr_t);
3377 
3378 	/*
3379 	 * the attribute of the scan channels are required after the probe
3380 	 * request frame.
3381 	 */
3382 	chan = (iwk_scan_chan_t *)frm;
3383 	for (i = 1; i <= hdr->nchan; i++, chan++) {
3384 		if (ic->ic_des_esslen) {
3385 			chan->type = 3;
3386 		} else {
3387 			chan->type = 1;
3388 		}
3389 
3390 		chan->chan = ieee80211_chan2ieee(ic, ic->ic_curchan);
3391 		chan->tpc.tx_gain = 0x3f;
3392 		chan->tpc.dsp_atten = 110;
3393 		chan->active_dwell = LE_16(50);
3394 		chan->passive_dwell = LE_16(120);
3395 
3396 		frm += sizeof (iwk_scan_chan_t);
3397 	}
3398 
3399 	pktlen = _PTRDIFF(frm, cmd);
3400 
3401 	(void) memset(desc, 0, sizeof (*desc));
3402 	desc->val0 = LE_32(1 << 24);
3403 	desc->pa[0].tb1_addr =
3404 	    (uint32_t)(data->dma_data.cookie.dmac_address & 0xffffffff);
3405 	desc->pa[0].val1 = (pktlen << 4) & 0xfff0;
3406 
3407 	/*
3408 	 * maybe for cmd, filling the byte cnt table is not necessary.
3409 	 * anyway, we fill it here.
3410 	 */
3411 	sc->sc_shared->queues_byte_cnt_tbls[ring->qid].
3412 	    tfd_offset[ring->cur].val = 8;
3413 	if (ring->cur < IWK_MAX_WIN_SIZE) {
3414 		sc->sc_shared->queues_byte_cnt_tbls[ring->qid].
3415 		    tfd_offset[IWK_QUEUE_SIZE + ring->cur].val = 8;
3416 	}
3417 
3418 	/* kick cmd ring */
3419 	ring->cur = (ring->cur + 1) % ring->count;
3420 	IWK_WRITE(sc, HBUS_TARG_WRPTR, ring->qid << 8 | ring->cur);
3421 
3422 	return (IWK_SUCCESS);
3423 }
3424 
3425 static int
3426 iwk_config(iwk_sc_t *sc)
3427 {
3428 	ieee80211com_t *ic = &sc->sc_ic;
3429 	iwk_powertable_cmd_t powertable;
3430 	iwk_bt_cmd_t bt;
3431 	iwk_add_sta_t node;
3432 	iwk_link_quality_cmd_t link_quality;
3433 	int i, err;
3434 	uint16_t masks = 0;
3435 
3436 	/*
3437 	 * set power mode. Disable power management at present, do it later
3438 	 */
3439 	(void) memset(&powertable, 0, sizeof (powertable));
3440 	powertable.flags = LE_16(0x8);
3441 	err = iwk_cmd(sc, POWER_TABLE_CMD, &powertable,
3442 	    sizeof (powertable), 0);
3443 	if (err != IWK_SUCCESS) {
3444 		cmn_err(CE_WARN, "iwk_config(): failed to set power mode\n");
3445 		return (err);
3446 	}
3447 
3448 	/* configure bt coexistence */
3449 	(void) memset(&bt, 0, sizeof (bt));
3450 	bt.flags = 3;
3451 	bt.lead_time = 0xaa;
3452 	bt.max_kill = 1;
3453 	err = iwk_cmd(sc, REPLY_BT_CONFIG, &bt,
3454 	    sizeof (bt), 0);
3455 	if (err != IWK_SUCCESS) {
3456 		cmn_err(CE_WARN,
3457 		    "iwk_config(): "
3458 		    "failed to configurate bt coexistence\n");
3459 		return (err);
3460 	}
3461 
3462 	/* configure rxon */
3463 	(void) memset(&sc->sc_config, 0, sizeof (iwk_rxon_cmd_t));
3464 	IEEE80211_ADDR_COPY(sc->sc_config.node_addr, ic->ic_macaddr);
3465 	IEEE80211_ADDR_COPY(sc->sc_config.wlap_bssid, ic->ic_macaddr);
3466 	sc->sc_config.chan = ieee80211_chan2ieee(ic, ic->ic_curchan);
3467 	sc->sc_config.flags = (RXON_FLG_TSF2HOST_MSK |
3468 	    RXON_FLG_AUTO_DETECT_MSK | RXON_FLG_BAND_24G_MSK);
3469 	sc->sc_config.flags &= (~RXON_FLG_CCK_MSK);
3470 	switch (ic->ic_opmode) {
3471 	case IEEE80211_M_STA:
3472 		sc->sc_config.dev_type = RXON_DEV_TYPE_ESS;
3473 		sc->sc_config.filter_flags |= LE_32(RXON_FILTER_ACCEPT_GRP_MSK |
3474 		    RXON_FILTER_DIS_DECRYPT_MSK |
3475 		    RXON_FILTER_DIS_GRP_DECRYPT_MSK);
3476 		break;
3477 	case IEEE80211_M_AHDEMO:
3478 		sc->sc_config.dev_type = RXON_DEV_TYPE_IBSS;
3479 		sc->sc_config.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
3480 		sc->sc_config.filter_flags = LE_32(RXON_FILTER_ACCEPT_GRP_MSK |
3481 		    RXON_FILTER_DIS_DECRYPT_MSK |
3482 		    RXON_FILTER_DIS_GRP_DECRYPT_MSK);
3483 		break;
3484 	case IEEE80211_M_HOSTAP:
3485 		sc->sc_config.dev_type = RXON_DEV_TYPE_AP;
3486 		break;
3487 	case IEEE80211_M_MONITOR:
3488 		sc->sc_config.dev_type = RXON_DEV_TYPE_SNIFFER;
3489 		sc->sc_config.filter_flags |= LE_32(RXON_FILTER_ACCEPT_GRP_MSK |
3490 		    RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_PROMISC_MSK);
3491 		break;
3492 	}
3493 	sc->sc_config.cck_basic_rates  = 0x0f;
3494 	sc->sc_config.ofdm_basic_rates = 0xff;
3495 
3496 	sc->sc_config.ofdm_ht_single_stream_basic_rates = 0xff;
3497 	sc->sc_config.ofdm_ht_dual_stream_basic_rates = 0xff;
3498 
3499 	/* set antenna */
3500 
3501 	sc->sc_config.rx_chain = RXON_RX_CHAIN_DRIVER_FORCE_MSK |
3502 	    LE_16((0x7 << RXON_RX_CHAIN_VALID_POS) |
3503 	    (0x6 << RXON_RX_CHAIN_FORCE_SEL_POS) |
3504 	    (0x7 << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS));
3505 
3506 	err = iwk_cmd(sc, REPLY_RXON, &sc->sc_config,
3507 	    sizeof (iwk_rxon_cmd_t), 0);
3508 	if (err != IWK_SUCCESS) {
3509 		cmn_err(CE_WARN, "iwk_config(): "
3510 		    "failed to set configure command\n");
3511 		return (err);
3512 	}
3513 	/* obtain current temperature of chipset */
3514 	sc->sc_tempera = iwk_curr_tempera(sc);
3515 
3516 	/* make Tx power calibration to determine the gains of DSP and radio */
3517 	err = iwk_tx_power_calibration(sc);
3518 	if (err) {
3519 		cmn_err(CE_WARN, "iwk_config(): "
3520 		    "failed to set tx power table\n");
3521 		return (err);
3522 	}
3523 
3524 	/* add broadcast node so that we can send broadcast frame */
3525 	(void) memset(&node, 0, sizeof (node));
3526 	(void) memset(node.bssid, 0xff, 6);
3527 	node.id = IWK_BROADCAST_ID;
3528 	err = iwk_cmd(sc, REPLY_ADD_STA, &node, sizeof (node), 0);
3529 	if (err != IWK_SUCCESS) {
3530 		cmn_err(CE_WARN, "iwk_config(): "
3531 		    "failed to add broadcast node\n");
3532 		return (err);
3533 	}
3534 
3535 	/* TX_LINK_QUALITY cmd ? */
3536 	(void) memset(&link_quality, 0, sizeof (link_quality));
3537 	for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) {
3538 		masks |= RATE_MCS_CCK_MSK;
3539 		masks |= RATE_MCS_ANT_B_MSK;
3540 		masks &= ~RATE_MCS_ANT_A_MSK;
3541 		link_quality.rate_n_flags[i] = iwk_rate_to_plcp(2) | masks;
3542 	}
3543 
3544 	link_quality.general_params.single_stream_ant_msk = 2;
3545 	link_quality.general_params.dual_stream_ant_msk = 3;
3546 	link_quality.agg_params.agg_dis_start_th = 3;
3547 	link_quality.agg_params.agg_time_limit = LE_16(4000);
3548 	link_quality.sta_id = IWK_BROADCAST_ID;
3549 	err = iwk_cmd(sc, REPLY_TX_LINK_QUALITY_CMD, &link_quality,
3550 	    sizeof (link_quality), 0);
3551 	if (err != IWK_SUCCESS) {
3552 		cmn_err(CE_WARN, "iwk_config(): "
3553 		    "failed to config link quality table\n");
3554 		return (err);
3555 	}
3556 
3557 	return (IWK_SUCCESS);
3558 }
3559 
3560 static void
3561 iwk_stop_master(iwk_sc_t *sc)
3562 {
3563 	uint32_t tmp;
3564 	int n;
3565 
3566 	tmp = IWK_READ(sc, CSR_RESET);
3567 	IWK_WRITE(sc, CSR_RESET, tmp | CSR_RESET_REG_FLAG_STOP_MASTER);
3568 
3569 	tmp = IWK_READ(sc, CSR_GP_CNTRL);
3570 	if ((tmp & CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE) ==
3571 	    CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE)
3572 		return;
3573 
3574 	for (n = 0; n < 2000; n++) {
3575 		if (IWK_READ(sc, CSR_RESET) &
3576 		    CSR_RESET_REG_FLAG_MASTER_DISABLED)
3577 			break;
3578 		DELAY(1000);
3579 	}
3580 	if (n == 2000)
3581 		IWK_DBG((IWK_DEBUG_HW,
3582 		    "timeout waiting for master stop\n"));
3583 }
3584 
3585 static int
3586 iwk_power_up(iwk_sc_t *sc)
3587 {
3588 	uint32_t tmp;
3589 
3590 	iwk_mac_access_enter(sc);
3591 	tmp = iwk_reg_read(sc, ALM_APMG_PS_CTL);
3592 	tmp &= ~APMG_PS_CTRL_REG_MSK_POWER_SRC;
3593 	tmp |= APMG_PS_CTRL_REG_VAL_POWER_SRC_VMAIN;
3594 	iwk_reg_write(sc, ALM_APMG_PS_CTL, tmp);
3595 	iwk_mac_access_exit(sc);
3596 
3597 	DELAY(5000);
3598 	return (IWK_SUCCESS);
3599 }
3600 
3601 static int
3602 iwk_preinit(iwk_sc_t *sc)
3603 {
3604 	uint32_t tmp;
3605 	int n;
3606 	uint8_t vlink;
3607 
3608 	/* clear any pending interrupts */
3609 	IWK_WRITE(sc, CSR_INT, 0xffffffff);
3610 
3611 	tmp = IWK_READ(sc, CSR_GIO_CHICKEN_BITS);
3612 	IWK_WRITE(sc, CSR_GIO_CHICKEN_BITS,
3613 	    tmp | CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
3614 
3615 	tmp = IWK_READ(sc, CSR_GP_CNTRL);
3616 	IWK_WRITE(sc, CSR_GP_CNTRL, tmp | CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
3617 
3618 	/* wait for clock ready */
3619 	for (n = 0; n < 1000; n++) {
3620 		if (IWK_READ(sc, CSR_GP_CNTRL) &
3621 		    CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY)
3622 			break;
3623 		DELAY(10);
3624 	}
3625 	if (n == 1000) {
3626 		cmn_err(CE_WARN,
3627 		    "iwk_preinit(): timeout waiting for clock ready\n");
3628 		return (ETIMEDOUT);
3629 	}
3630 	iwk_mac_access_enter(sc);
3631 	tmp = iwk_reg_read(sc, APMG_CLK_CTRL_REG);
3632 	iwk_reg_write(sc, APMG_CLK_CTRL_REG, tmp |
3633 	    APMG_CLK_REG_VAL_DMA_CLK_RQT | APMG_CLK_REG_VAL_BSM_CLK_RQT);
3634 
3635 	DELAY(20);
3636 	tmp = iwk_reg_read(sc, ALM_APMG_PCIDEV_STT);
3637 	iwk_reg_write(sc, ALM_APMG_PCIDEV_STT, tmp |
3638 	    APMG_DEV_STATE_REG_VAL_L1_ACTIVE_DISABLE);
3639 	iwk_mac_access_exit(sc);
3640 
3641 	IWK_WRITE(sc, CSR_INT_COALESCING, 512 / 32); /* ??? */
3642 
3643 	(void) iwk_power_up(sc);
3644 
3645 	if ((sc->sc_rev & 0x80) == 0x80 && (sc->sc_rev & 0x7f) < 8) {
3646 		tmp = ddi_get32(sc->sc_cfg_handle,
3647 		    (uint32_t *)(sc->sc_cfg_base + 0xe8));
3648 		ddi_put32(sc->sc_cfg_handle,
3649 		    (uint32_t *)(sc->sc_cfg_base + 0xe8),
3650 		    tmp & ~(1 << 11));
3651 	}
3652 
3653 
3654 	vlink = ddi_get8(sc->sc_cfg_handle,
3655 	    (uint8_t *)(sc->sc_cfg_base + 0xf0));
3656 	ddi_put8(sc->sc_cfg_handle, (uint8_t *)(sc->sc_cfg_base + 0xf0),
3657 	    vlink & ~2);
3658 
3659 	tmp = IWK_READ(sc, CSR_SW_VER);
3660 	tmp |= CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI |
3661 	    CSR_HW_IF_CONFIG_REG_BIT_MAC_SI |
3662 	    CSR_HW_IF_CONFIG_REG_BIT_KEDRON_R;
3663 	IWK_WRITE(sc, CSR_SW_VER, tmp);
3664 
3665 	/* make sure power supply on each part of the hardware */
3666 	iwk_mac_access_enter(sc);
3667 	tmp = iwk_reg_read(sc, ALM_APMG_PS_CTL);
3668 	tmp |= APMG_PS_CTRL_REG_VAL_ALM_R_RESET_REQ;
3669 	iwk_reg_write(sc, ALM_APMG_PS_CTL, tmp);
3670 	DELAY(5);
3671 	tmp = iwk_reg_read(sc, ALM_APMG_PS_CTL);
3672 	tmp &= ~APMG_PS_CTRL_REG_VAL_ALM_R_RESET_REQ;
3673 	iwk_reg_write(sc, ALM_APMG_PS_CTL, tmp);
3674 	iwk_mac_access_exit(sc);
3675 	return (IWK_SUCCESS);
3676 }
3677 
3678 /*
3679  * set up semphore flag to own EEPROM
3680  */
3681 static int iwk_eep_sem_down(iwk_sc_t *sc)
3682 {
3683 	int count1, count2;
3684 	uint32_t tmp;
3685 
3686 	for (count1 = 0; count1 < 1000; count1++) {
3687 		tmp = IWK_READ(sc, CSR_HW_IF_CONFIG_REG);
3688 		IWK_WRITE(sc, CSR_HW_IF_CONFIG_REG,
3689 		    tmp | CSR_HW_IF_CONFIG_REG_EEP_SEM);
3690 
3691 		for (count2 = 0; count2 < 2; count2++) {
3692 			if (IWK_READ(sc, CSR_HW_IF_CONFIG_REG) &
3693 			    CSR_HW_IF_CONFIG_REG_EEP_SEM)
3694 				return (IWK_SUCCESS);
3695 			DELAY(10000);
3696 		}
3697 	}
3698 	return (IWK_FAIL);
3699 }
3700 
3701 /*
3702  * reset semphore flag to release EEPROM
3703  */
3704 static void iwk_eep_sem_up(iwk_sc_t *sc)
3705 {
3706 	uint32_t tmp;
3707 
3708 	tmp = IWK_READ(sc, CSR_HW_IF_CONFIG_REG);
3709 	IWK_WRITE(sc, CSR_HW_IF_CONFIG_REG,
3710 	    tmp & (~CSR_HW_IF_CONFIG_REG_EEP_SEM));
3711 }
3712 
3713 /*
3714  * This function load all infomation in eeprom into iwk_eep
3715  * structure in iwk_sc_t structure
3716  */
3717 static int iwk_eep_load(iwk_sc_t *sc)
3718 {
3719 	int i, rr;
3720 	uint32_t rv, tmp, eep_gp;
3721 	uint16_t addr, eep_sz = sizeof (sc->sc_eep_map);
3722 	uint16_t *eep_p = (uint16_t *)&sc->sc_eep_map;
3723 
3724 	/* read eeprom gp register in CSR */
3725 	eep_gp = IWK_READ(sc, CSR_EEPROM_GP);
3726 	if ((eep_gp & CSR_EEPROM_GP_VALID_MSK) ==
3727 	    CSR_EEPROM_GP_BAD_SIGNATURE) {
3728 		cmn_err(CE_WARN, "EEPROM not found\n");
3729 		return (IWK_FAIL);
3730 	}
3731 
3732 	rr = iwk_eep_sem_down(sc);
3733 	if (rr != 0) {
3734 		cmn_err(CE_WARN, "failed to own EEPROM\n");
3735 		return (IWK_FAIL);
3736 	}
3737 
3738 	for (addr = 0; addr < eep_sz; addr += 2) {
3739 		IWK_WRITE(sc, CSR_EEPROM_REG, addr<<1);
3740 		tmp = IWK_READ(sc, CSR_EEPROM_REG);
3741 		IWK_WRITE(sc, CSR_EEPROM_REG, tmp & ~(0x2));
3742 
3743 		for (i = 0; i < 10; i++) {
3744 			rv = IWK_READ(sc, CSR_EEPROM_REG);
3745 			if (rv & 1)
3746 				break;
3747 			DELAY(10);
3748 		}
3749 
3750 		if (!(rv & 1)) {
3751 			cmn_err(CE_WARN, "time out when read EEPROM\n");
3752 			iwk_eep_sem_up(sc);
3753 			return (IWK_FAIL);
3754 		}
3755 
3756 		eep_p[addr/2] = rv >> 16;
3757 	}
3758 
3759 	iwk_eep_sem_up(sc);
3760 	return (IWK_SUCCESS);
3761 }
3762 
3763 /*
3764  * init mac address in ieee80211com_t struct
3765  */
3766 static void iwk_get_mac_from_eep(iwk_sc_t *sc)
3767 {
3768 	ieee80211com_t *ic = &sc->sc_ic;
3769 	struct iwk_eep *ep = &sc->sc_eep_map;
3770 
3771 	IEEE80211_ADDR_COPY(ic->ic_macaddr, ep->mac_address);
3772 
3773 	IWK_DBG((IWK_DEBUG_EEPROM, "mac:%2x:%2x:%2x:%2x:%2x:%2x\n",
3774 	    ic->ic_macaddr[0], ic->ic_macaddr[1], ic->ic_macaddr[2],
3775 	    ic->ic_macaddr[3], ic->ic_macaddr[4], ic->ic_macaddr[5]));
3776 }
3777 
3778 static int
3779 iwk_init(iwk_sc_t *sc)
3780 {
3781 	int qid, n, err;
3782 	clock_t clk;
3783 	uint32_t tmp;
3784 
3785 	mutex_enter(&sc->sc_glock);
3786 	sc->sc_flags &= ~IWK_F_FW_INIT;
3787 
3788 	(void) iwk_preinit(sc);
3789 
3790 	tmp = IWK_READ(sc, CSR_GP_CNTRL);
3791 	if (!(tmp & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)) {
3792 		cmn_err(CE_WARN, "iwk_init(): Radio transmitter is off\n");
3793 		goto fail1;
3794 	}
3795 
3796 	/* init Rx ring */
3797 	iwk_mac_access_enter(sc);
3798 	IWK_WRITE(sc, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
3799 
3800 	IWK_WRITE(sc, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0);
3801 	IWK_WRITE(sc, FH_RSCSR_CHNL0_RBDCB_BASE_REG,
3802 	    sc->sc_rxq.dma_desc.cookie.dmac_address >> 8);
3803 
3804 	IWK_WRITE(sc, FH_RSCSR_CHNL0_STTS_WPTR_REG,
3805 	    ((uint32_t)(sc->sc_dma_sh.cookie.dmac_address +
3806 	    offsetof(struct iwk_shared, val0)) >> 4));
3807 
3808 	IWK_WRITE(sc, FH_MEM_RCSR_CHNL0_CONFIG_REG,
3809 	    FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL |
3810 	    FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL |
3811 	    IWK_FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K |
3812 	    (RX_QUEUE_SIZE_LOG <<
3813 	    FH_RCSR_RX_CONFIG_RBDCB_SIZE_BITSHIFT));
3814 	iwk_mac_access_exit(sc);
3815 	IWK_WRITE(sc, FH_RSCSR_CHNL0_RBDCB_WPTR_REG,
3816 	    (RX_QUEUE_SIZE - 1) & ~0x7);
3817 
3818 	/* init Tx rings */
3819 	iwk_mac_access_enter(sc);
3820 	iwk_reg_write(sc, SCD_TXFACT, 0);
3821 
3822 	/* keep warm page */
3823 	iwk_reg_write(sc, IWK_FH_KW_MEM_ADDR_REG,
3824 	    sc->sc_dma_kw.cookie.dmac_address >> 4);
3825 
3826 	for (qid = 0; qid < IWK_NUM_QUEUES; qid++) {
3827 		IWK_WRITE(sc, FH_MEM_CBBC_QUEUE(qid),
3828 		    sc->sc_txq[qid].dma_desc.cookie.dmac_address >> 8);
3829 		IWK_WRITE(sc, IWK_FH_TCSR_CHNL_TX_CONFIG_REG(qid),
3830 		    IWK_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
3831 		    IWK_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL);
3832 	}
3833 	iwk_mac_access_exit(sc);
3834 
3835 	/* clear "radio off" and "disable command" bits */
3836 	IWK_WRITE(sc, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
3837 	IWK_WRITE(sc, CSR_UCODE_DRV_GP1_CLR,
3838 	    CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
3839 
3840 	/* clear any pending interrupts */
3841 	IWK_WRITE(sc, CSR_INT, 0xffffffff);
3842 
3843 	/* enable interrupts */
3844 	IWK_WRITE(sc, CSR_INT_MASK, CSR_INI_SET_MASK);
3845 
3846 	IWK_WRITE(sc, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
3847 	IWK_WRITE(sc, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
3848 
3849 	/*
3850 	 * backup ucode data part for future use.
3851 	 */
3852 	(void) memcpy(sc->sc_dma_fw_data_bak.mem_va,
3853 	    sc->sc_dma_fw_data.mem_va,
3854 	    sc->sc_dma_fw_data.alength);
3855 
3856 	for (n = 0; n < 2; n++) {
3857 		/* load firmware init segment into NIC */
3858 		err = iwk_load_firmware(sc);
3859 		if (err != IWK_SUCCESS) {
3860 			cmn_err(CE_WARN, "iwk_init(): "
3861 			    "failed to setup boot firmware\n");
3862 			continue;
3863 		}
3864 
3865 		/* now press "execute" start running */
3866 		IWK_WRITE(sc, CSR_RESET, 0);
3867 		break;
3868 	}
3869 	if (n == 2) {
3870 		cmn_err(CE_WARN, "iwk_init(): failed to load firmware\n");
3871 		goto fail1;
3872 	}
3873 	/* ..and wait at most one second for adapter to initialize */
3874 	clk = ddi_get_lbolt() + drv_usectohz(2000000);
3875 	while (!(sc->sc_flags & IWK_F_FW_INIT)) {
3876 		if (cv_timedwait(&sc->sc_fw_cv, &sc->sc_glock, clk) < 0)
3877 			break;
3878 	}
3879 	if (!(sc->sc_flags & IWK_F_FW_INIT)) {
3880 		cmn_err(CE_WARN,
3881 		    "iwk_init(): timeout waiting for firmware init\n");
3882 		goto fail1;
3883 	}
3884 
3885 	/*
3886 	 * at this point, the firmware is loaded OK, then config the hardware
3887 	 * with the ucode API, including rxon, txpower, etc.
3888 	 */
3889 	err = iwk_config(sc);
3890 	if (err) {
3891 		cmn_err(CE_WARN, "iwk_init(): failed to configure device\n");
3892 		goto fail1;
3893 	}
3894 
3895 	/* at this point, hardware may receive beacons :) */
3896 	mutex_exit(&sc->sc_glock);
3897 	return (IWK_SUCCESS);
3898 
3899 fail1:
3900 	err = IWK_FAIL;
3901 	mutex_exit(&sc->sc_glock);
3902 	return (err);
3903 }
3904 
3905 static void
3906 iwk_stop(iwk_sc_t *sc)
3907 {
3908 	uint32_t tmp;
3909 	int i;
3910 
3911 	if (!(sc->sc_flags & IWK_F_QUIESCED))
3912 		mutex_enter(&sc->sc_glock);
3913 
3914 	IWK_WRITE(sc, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
3915 	/* disable interrupts */
3916 	IWK_WRITE(sc, CSR_INT_MASK, 0);
3917 	IWK_WRITE(sc, CSR_INT, CSR_INI_SET_MASK);
3918 	IWK_WRITE(sc, CSR_FH_INT_STATUS, 0xffffffff);
3919 
3920 	/* reset all Tx rings */
3921 	for (i = 0; i < IWK_NUM_QUEUES; i++)
3922 		iwk_reset_tx_ring(sc, &sc->sc_txq[i]);
3923 
3924 	/* reset Rx ring */
3925 	iwk_reset_rx_ring(sc);
3926 
3927 	iwk_mac_access_enter(sc);
3928 	iwk_reg_write(sc, ALM_APMG_CLK_DIS, APMG_CLK_REG_VAL_DMA_CLK_RQT);
3929 	iwk_mac_access_exit(sc);
3930 
3931 	DELAY(5);
3932 
3933 	iwk_stop_master(sc);
3934 
3935 	sc->sc_tx_timer = 0;
3936 	tmp = IWK_READ(sc, CSR_RESET);
3937 	IWK_WRITE(sc, CSR_RESET, tmp | CSR_RESET_REG_FLAG_SW_RESET);
3938 
3939 	if (!(sc->sc_flags & IWK_F_QUIESCED))
3940 		mutex_exit(&sc->sc_glock);
3941 }
3942 
3943 /*
3944  * Naive implementation of the Adaptive Multi Rate Retry algorithm:
3945  * "IEEE 802.11 Rate Adaptation: A Practical Approach"
3946  * Mathieu Lacage, Hossein Manshaei, Thierry Turletti
3947  * INRIA Sophia - Projet Planete
3948  * http://www-sop.inria.fr/rapports/sophia/RR-5208.html
3949  */
3950 #define	is_success(amrr)	\
3951 	((amrr)->retrycnt < (amrr)->txcnt / 10)
3952 #define	is_failure(amrr)	\
3953 	((amrr)->retrycnt > (amrr)->txcnt / 3)
3954 #define	is_enough(amrr)		\
3955 	((amrr)->txcnt > 100)
3956 #define	is_min_rate(in)		\
3957 	((in)->in_txrate == 0)
3958 #define	is_max_rate(in)		\
3959 	((in)->in_txrate == (in)->in_rates.ir_nrates - 1)
3960 #define	increase_rate(in)	\
3961 	((in)->in_txrate++)
3962 #define	decrease_rate(in)	\
3963 	((in)->in_txrate--)
3964 #define	reset_cnt(amrr)		\
3965 	{ (amrr)->txcnt = (amrr)->retrycnt = 0; }
3966 
3967 #define	IWK_AMRR_MIN_SUCCESS_THRESHOLD	 1
3968 #define	IWK_AMRR_MAX_SUCCESS_THRESHOLD	15
3969 
3970 static void
3971 iwk_amrr_init(iwk_amrr_t *amrr)
3972 {
3973 	amrr->success = 0;
3974 	amrr->recovery = 0;
3975 	amrr->txcnt = amrr->retrycnt = 0;
3976 	amrr->success_threshold = IWK_AMRR_MIN_SUCCESS_THRESHOLD;
3977 }
3978 
3979 static void
3980 iwk_amrr_timeout(iwk_sc_t *sc)
3981 {
3982 	ieee80211com_t *ic = &sc->sc_ic;
3983 
3984 	IWK_DBG((IWK_DEBUG_RATECTL, "iwk_amrr_timeout() enter\n"));
3985 	if (ic->ic_opmode == IEEE80211_M_STA)
3986 		iwk_amrr_ratectl(NULL, ic->ic_bss);
3987 	else
3988 		ieee80211_iterate_nodes(&ic->ic_sta, iwk_amrr_ratectl, NULL);
3989 	sc->sc_clk = ddi_get_lbolt();
3990 }
3991 
3992 /* ARGSUSED */
3993 static void
3994 iwk_amrr_ratectl(void *arg, ieee80211_node_t *in)
3995 {
3996 	iwk_amrr_t *amrr = (iwk_amrr_t *)in;
3997 	int need_change = 0;
3998 
3999 	if (is_success(amrr) && is_enough(amrr)) {
4000 		amrr->success++;
4001 		if (amrr->success >= amrr->success_threshold &&
4002 		    !is_max_rate(in)) {
4003 			amrr->recovery = 1;
4004 			amrr->success = 0;
4005 			increase_rate(in);
4006 			IWK_DBG((IWK_DEBUG_RATECTL,
4007 			    "AMRR increasing rate %d (txcnt=%d retrycnt=%d)\n",
4008 			    in->in_txrate, amrr->txcnt, amrr->retrycnt));
4009 			need_change = 1;
4010 		} else {
4011 			amrr->recovery = 0;
4012 		}
4013 	} else if (is_failure(amrr)) {
4014 		amrr->success = 0;
4015 		if (!is_min_rate(in)) {
4016 			if (amrr->recovery) {
4017 				amrr->success_threshold++;
4018 				if (amrr->success_threshold >
4019 				    IWK_AMRR_MAX_SUCCESS_THRESHOLD)
4020 					amrr->success_threshold =
4021 					    IWK_AMRR_MAX_SUCCESS_THRESHOLD;
4022 			} else {
4023 				amrr->success_threshold =
4024 				    IWK_AMRR_MIN_SUCCESS_THRESHOLD;
4025 			}
4026 			decrease_rate(in);
4027 			IWK_DBG((IWK_DEBUG_RATECTL,
4028 			    "AMRR decreasing rate %d (txcnt=%d retrycnt=%d)\n",
4029 			    in->in_txrate, amrr->txcnt, amrr->retrycnt));
4030 			need_change = 1;
4031 		}
4032 		amrr->recovery = 0;	/* paper is incorrect */
4033 	}
4034 
4035 	if (is_enough(amrr) || need_change)
4036 		reset_cnt(amrr);
4037 }
4038 
4039 /*
4040  * calculate 4965 chipset's kelvin temperature according to
4041  * the data of init alive and satistics notification.
4042  * The details is described in iwk_calibration.h file
4043  */
4044 static int32_t iwk_curr_tempera(iwk_sc_t *sc)
4045 {
4046 	int32_t  tempera;
4047 	int32_t  r1, r2, r3;
4048 	uint32_t  r4_u;
4049 	int32_t   r4_s;
4050 
4051 	if (iwk_is_fat_channel(sc)) {
4052 		r1 = (int32_t)(sc->sc_card_alive_init.therm_r1[1]);
4053 		r2 = (int32_t)(sc->sc_card_alive_init.therm_r2[1]);
4054 		r3 = (int32_t)(sc->sc_card_alive_init.therm_r3[1]);
4055 		r4_u = sc->sc_card_alive_init.therm_r4[1];
4056 	} else {
4057 		r1 = (int32_t)(sc->sc_card_alive_init.therm_r1[0]);
4058 		r2 = (int32_t)(sc->sc_card_alive_init.therm_r2[0]);
4059 		r3 = (int32_t)(sc->sc_card_alive_init.therm_r3[0]);
4060 		r4_u = sc->sc_card_alive_init.therm_r4[0];
4061 	}
4062 
4063 	if (sc->sc_flags & IWK_F_STATISTICS) {
4064 		r4_s = (int32_t)(sc->sc_statistics.general.temperature <<
4065 		    (31-23)) >> (31-23);
4066 	} else {
4067 		r4_s = (int32_t)(r4_u << (31-23)) >> (31-23);
4068 	}
4069 
4070 	IWK_DBG((IWK_DEBUG_CALIBRATION, "temperature R[1-4]: %d %d %d %d\n",
4071 	    r1, r2, r3, r4_s));
4072 
4073 	if (r3 == r1) {
4074 		cmn_err(CE_WARN, "iwk_curr_tempera(): "
4075 		    "failed to calculate temperature"
4076 		    "because r3 = r1\n");
4077 		return (DDI_FAILURE);
4078 	}
4079 
4080 	tempera = TEMPERATURE_CALIB_A_VAL * (r4_s - r2);
4081 	tempera /= (r3 - r1);
4082 	tempera = (tempera*97) / 100 + TEMPERATURE_CALIB_KELVIN_OFFSET;
4083 
4084 	IWK_DBG((IWK_DEBUG_CALIBRATION, "calculated temperature: %dK, %dC\n",
4085 	    tempera, KELVIN_TO_CELSIUS(tempera)));
4086 
4087 	return (tempera);
4088 }
4089 
4090 /* Determine whether 4965 is using 2.4 GHz band */
4091 static inline int iwk_is_24G_band(iwk_sc_t *sc)
4092 {
4093 	return (sc->sc_config.flags & RXON_FLG_BAND_24G_MSK);
4094 }
4095 
4096 /* Determine whether 4965 is using fat channel */
4097 static inline int iwk_is_fat_channel(iwk_sc_t *sc)
4098 {
4099 	return ((sc->sc_config.flags & RXON_FLG_CHANNEL_MODE_PURE_40_MSK) ||
4100 	    (sc->sc_config.flags & RXON_FLG_CHANNEL_MODE_MIXED_MSK));
4101 }
4102 
4103 /*
4104  * In MIMO mode, determine which group 4965's current channel belong to.
4105  * For more infomation about "channel group",
4106  * please refer to iwk_calibration.h file
4107  */
4108 static int iwk_txpower_grp(uint16_t channel)
4109 {
4110 	if (channel >= CALIB_IWK_TX_ATTEN_GR5_FCH &&
4111 	    channel <= CALIB_IWK_TX_ATTEN_GR5_LCH) {
4112 		return (CALIB_CH_GROUP_5);
4113 	}
4114 
4115 	if (channel >= CALIB_IWK_TX_ATTEN_GR1_FCH &&
4116 	    channel <= CALIB_IWK_TX_ATTEN_GR1_LCH) {
4117 		return (CALIB_CH_GROUP_1);
4118 	}
4119 
4120 	if (channel >= CALIB_IWK_TX_ATTEN_GR2_FCH &&
4121 	    channel <= CALIB_IWK_TX_ATTEN_GR2_LCH) {
4122 		return (CALIB_CH_GROUP_2);
4123 	}
4124 
4125 	if (channel >= CALIB_IWK_TX_ATTEN_GR3_FCH &&
4126 	    channel <= CALIB_IWK_TX_ATTEN_GR3_LCH) {
4127 		return (CALIB_CH_GROUP_3);
4128 	}
4129 
4130 	if (channel >= CALIB_IWK_TX_ATTEN_GR4_FCH &&
4131 	    channel <= CALIB_IWK_TX_ATTEN_GR4_LCH) {
4132 		return (CALIB_CH_GROUP_4);
4133 	}
4134 
4135 	cmn_err(CE_WARN, "iwk_txpower_grp(): "
4136 	    "can't find txpower group for channel %d.\n", channel);
4137 
4138 	return (DDI_FAILURE);
4139 }
4140 
4141 /* 2.4 GHz */
4142 static uint16_t iwk_eep_band_1[14] = {
4143 	1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
4144 };
4145 
4146 /* 5.2 GHz bands */
4147 static uint16_t iwk_eep_band_2[13] = {
4148 	183, 184, 185, 187, 188, 189, 192, 196, 7, 8, 11, 12, 16
4149 };
4150 
4151 static uint16_t iwk_eep_band_3[12] = {
4152 	34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64
4153 };
4154 
4155 static uint16_t iwk_eep_band_4[11] = {
4156 	100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140
4157 };
4158 
4159 static uint16_t iwk_eep_band_5[6] = {
4160 	145, 149, 153, 157, 161, 165
4161 };
4162 
4163 static uint16_t iwk_eep_band_6[7] = {
4164 	1, 2, 3, 4, 5, 6, 7
4165 };
4166 
4167 static uint16_t iwk_eep_band_7[11] = {
4168 	36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157
4169 };
4170 
4171 /* Get regulatory data from eeprom for a given channel */
4172 static struct iwk_eep_channel *iwk_get_eep_channel(iwk_sc_t *sc,
4173     uint16_t channel,
4174     int is_24G, int is_fat, int is_hi_chan)
4175 {
4176 	int32_t i;
4177 	uint16_t chan;
4178 
4179 	if (is_fat) {  /* 11n mode */
4180 
4181 		if (is_hi_chan) {
4182 			chan = channel - 4;
4183 		} else {
4184 			chan = channel;
4185 		}
4186 
4187 		for (i = 0; i < 7; i++) {
4188 			if (iwk_eep_band_6[i] == chan) {
4189 				return (&sc->sc_eep_map.band_24_channels[i]);
4190 			}
4191 		}
4192 		for (i = 0; i < 11; i++) {
4193 			if (iwk_eep_band_7[i] == chan) {
4194 				return (&sc->sc_eep_map.band_52_channels[i]);
4195 			}
4196 		}
4197 	} else if (is_24G) {  /* 2.4 GHz band */
4198 		for (i = 0; i < 14; i++) {
4199 			if (iwk_eep_band_1[i] == channel) {
4200 				return (&sc->sc_eep_map.band_1_channels[i]);
4201 			}
4202 		}
4203 	} else {  /* 5 GHz band */
4204 		for (i = 0; i < 13; i++) {
4205 			if (iwk_eep_band_2[i] == channel) {
4206 				return (&sc->sc_eep_map.band_2_channels[i]);
4207 			}
4208 		}
4209 		for (i = 0; i < 12; i++) {
4210 			if (iwk_eep_band_3[i] == channel) {
4211 				return (&sc->sc_eep_map.band_3_channels[i]);
4212 			}
4213 		}
4214 		for (i = 0; i < 11; i++) {
4215 			if (iwk_eep_band_4[i] == channel) {
4216 				return (&sc->sc_eep_map.band_4_channels[i]);
4217 			}
4218 		}
4219 		for (i = 0; i < 6; i++) {
4220 			if (iwk_eep_band_5[i] == channel) {
4221 				return (&sc->sc_eep_map.band_5_channels[i]);
4222 			}
4223 		}
4224 	}
4225 
4226 	return (NULL);
4227 }
4228 
4229 /*
4230  * Determine which subband a given channel belongs
4231  * to in 2.4 GHz or 5 GHz band
4232  */
4233 static int32_t iwk_band_number(iwk_sc_t *sc, uint16_t channel)
4234 {
4235 	int32_t b_n = -1;
4236 
4237 	for (b_n = 0; b_n < EEP_TX_POWER_BANDS; b_n++) {
4238 		if (0 == sc->sc_eep_map.calib_info.band_info_tbl[b_n].ch_from) {
4239 			continue;
4240 		}
4241 
4242 		if ((channel >=
4243 		    (uint16_t)sc->sc_eep_map.calib_info.
4244 		    band_info_tbl[b_n].ch_from) &&
4245 		    (channel <=
4246 		    (uint16_t)sc->sc_eep_map.calib_info.
4247 		    band_info_tbl[b_n].ch_to)) {
4248 			break;
4249 		}
4250 	}
4251 
4252 	return (b_n);
4253 }
4254 
4255 /* Make a special division for interpolation operation */
4256 static int iwk_division(int32_t num, int32_t denom, int32_t *res)
4257 {
4258 	int32_t sign = 1;
4259 
4260 	if (num < 0) {
4261 		sign = -sign;
4262 		num = -num;
4263 	}
4264 
4265 	if (denom < 0) {
4266 		sign = -sign;
4267 		denom = -denom;
4268 	}
4269 
4270 	*res = ((num*2 + denom) / (denom*2)) * sign;
4271 
4272 	return (IWK_SUCCESS);
4273 }
4274 
4275 /* Make interpolation operation */
4276 static int32_t iwk_interpolate_value(int32_t x, int32_t x1, int32_t y1,
4277     int32_t x2, int32_t y2)
4278 {
4279 	int32_t val;
4280 
4281 	if (x2 == x1) {
4282 		return (y1);
4283 	} else {
4284 		(void) iwk_division((x2-x)*(y1-y2), (x2-x1), &val);
4285 		return (val + y2);
4286 	}
4287 }
4288 
4289 /* Get interpolation measurement data of a given channel for all chains. */
4290 static int iwk_channel_interpolate(iwk_sc_t *sc, uint16_t channel,
4291     struct iwk_eep_calib_channel_info *chan_info)
4292 {
4293 	int32_t ban_n;
4294 	uint32_t ch1_n, ch2_n;
4295 	int32_t c, m;
4296 	struct iwk_eep_calib_measure *m1_p, *m2_p, *m_p;
4297 
4298 	/* determine subband number */
4299 	ban_n = iwk_band_number(sc, channel);
4300 	if (ban_n >= EEP_TX_POWER_BANDS) {
4301 		return (DDI_FAILURE);
4302 	}
4303 
4304 	ch1_n =
4305 	    (uint32_t)sc->sc_eep_map.calib_info.band_info_tbl[ban_n].ch1.ch_num;
4306 	ch2_n =
4307 	    (uint32_t)sc->sc_eep_map.calib_info.band_info_tbl[ban_n].ch2.ch_num;
4308 
4309 	chan_info->ch_num = (uint8_t)channel;  /* given channel number */
4310 
4311 	/*
4312 	 * go through all chains on chipset
4313 	 */
4314 	for (c = 0; c < EEP_TX_POWER_TX_CHAINS; c++) {
4315 		/*
4316 		 * go through all factory measurements
4317 		 */
4318 		for (m = 0; m < EEP_TX_POWER_MEASUREMENTS; m++) {
4319 			m1_p =
4320 			    &(sc->sc_eep_map.calib_info.
4321 			    band_info_tbl[ban_n].ch1.measure[c][m]);
4322 			m2_p =
4323 			    &(sc->sc_eep_map.calib_info.band_info_tbl[ban_n].
4324 			    ch2.measure[c][m]);
4325 			m_p = &(chan_info->measure[c][m]);
4326 
4327 			/*
4328 			 * make interpolation to get actual
4329 			 * Tx power for given channel
4330 			 */
4331 			m_p->actual_pow = iwk_interpolate_value(channel,
4332 			    ch1_n, m1_p->actual_pow,
4333 			    ch2_n, m2_p->actual_pow);
4334 
4335 			/* make interpolation to get index into gain table */
4336 			m_p->gain_idx = iwk_interpolate_value(channel,
4337 			    ch1_n, m1_p->gain_idx,
4338 			    ch2_n, m2_p->gain_idx);
4339 
4340 			/* make interpolation to get chipset temperature */
4341 			m_p->temperature = iwk_interpolate_value(channel,
4342 			    ch1_n, m1_p->temperature,
4343 			    ch2_n, m2_p->temperature);
4344 
4345 			/*
4346 			 * make interpolation to get power
4347 			 * amp detector level
4348 			 */
4349 			m_p->pa_det = iwk_interpolate_value(channel, ch1_n,
4350 			    m1_p->pa_det,
4351 			    ch2_n, m2_p->pa_det);
4352 		}
4353 	}
4354 
4355 	return (IWK_SUCCESS);
4356 }
4357 
4358 /*
4359  * Calculate voltage compensation for Tx power. For more infomation,
4360  * please refer to iwk_calibration.h file
4361  */
4362 static int32_t iwk_voltage_compensation(int32_t eep_voltage,
4363     int32_t curr_voltage)
4364 {
4365 	int32_t vol_comp = 0;
4366 
4367 	if ((TX_POWER_IWK_ILLEGAL_VOLTAGE == eep_voltage) ||
4368 	    (TX_POWER_IWK_ILLEGAL_VOLTAGE == curr_voltage)) {
4369 		return (vol_comp);
4370 	}
4371 
4372 	(void) iwk_division(curr_voltage-eep_voltage,
4373 	    TX_POWER_IWK_VOLTAGE_CODES_PER_03V, &vol_comp);
4374 
4375 	if (curr_voltage > eep_voltage) {
4376 		vol_comp *= 2;
4377 	}
4378 	if ((vol_comp < -2) || (vol_comp > 2)) {
4379 		vol_comp = 0;
4380 	}
4381 
4382 	return (vol_comp);
4383 }
4384 
4385 /*
4386  * Thermal compensation values for txpower for various frequency ranges ...
4387  * ratios from 3:1 to 4.5:1 of degrees (Celsius) per half-dB gain adjust
4388  */
4389 static struct iwk_txpower_tempera_comp {
4390 	int32_t degrees_per_05db_a;
4391 	int32_t degrees_per_05db_a_denom;
4392 } txpower_tempera_comp_table[CALIB_CH_GROUP_MAX] = {
4393 	{9, 2},			/* group 0 5.2, ch  34-43 */
4394 	{4, 1},			/* group 1 5.2, ch  44-70 */
4395 	{4, 1},			/* group 2 5.2, ch  71-124 */
4396 	{4, 1},			/* group 3 5.2, ch 125-200 */
4397 	{3, 1}			/* group 4 2.4, ch   all */
4398 };
4399 
4400 /*
4401  * bit-rate-dependent table to prevent Tx distortion, in half-dB units,
4402  * for OFDM 6, 12, 18, 24, 36, 48, 54, 60 MBit, and CCK all rates.
4403  */
4404 static int32_t back_off_table[] = {
4405 	10, 10, 10, 10, 10, 15, 17, 20, /* OFDM SISO 20 MHz */
4406 	10, 10, 10, 10, 10, 15, 17, 20, /* OFDM MIMO 20 MHz */
4407 	10, 10, 10, 10, 10, 15, 17, 20, /* OFDM SISO 40 MHz */
4408 	10, 10, 10, 10, 10, 15, 17, 20, /* OFDM MIMO 40 MHz */
4409 	10			/* CCK */
4410 };
4411 
4412 /* determine minimum Tx power index in gain table */
4413 static int32_t iwk_min_power_index(int32_t rate_pow_idx, int32_t is_24G)
4414 {
4415 	if ((!is_24G) && ((rate_pow_idx & 7) <= 4)) {
4416 		return (MIN_TX_GAIN_INDEX_52GHZ_EXT);
4417 	}
4418 
4419 	return (MIN_TX_GAIN_INDEX);
4420 }
4421 
4422 /*
4423  * Determine DSP and radio gain according to temperature and other factors.
4424  * This function is the majority of Tx power calibration
4425  */
4426 static int iwk_txpower_table_cmd_init(iwk_sc_t *sc,
4427     struct iwk_tx_power_db *tp_db)
4428 {
4429 	int is_24G, is_fat, is_high_chan, is_mimo;
4430 	int c, r;
4431 	int32_t target_power;
4432 	int32_t tx_grp = CALIB_CH_GROUP_MAX;
4433 	uint16_t channel;
4434 	uint8_t saturation_power;
4435 	int32_t regu_power;
4436 	int32_t curr_regu_power;
4437 	struct iwk_eep_channel *eep_chan_p;
4438 	struct iwk_eep_calib_channel_info eep_chan_calib;
4439 	int32_t eep_voltage, init_voltage;
4440 	int32_t voltage_compensation;
4441 	int32_t temperature;
4442 	int32_t degrees_per_05db_num;
4443 	int32_t degrees_per_05db_denom;
4444 	struct iwk_eep_calib_measure *measure_p;
4445 	int32_t interpo_temp;
4446 	int32_t power_limit;
4447 	int32_t atten_value;
4448 	int32_t tempera_comp[2];
4449 	int32_t interpo_gain_idx[2];
4450 	int32_t interpo_actual_pow[2];
4451 	union iwk_tx_power_dual_stream txpower_gains;
4452 	int32_t txpower_gains_idx;
4453 
4454 	channel = sc->sc_config.chan;
4455 
4456 	/* 2.4 GHz or 5 GHz band */
4457 	is_24G = iwk_is_24G_band(sc);
4458 
4459 	/* fat channel or not */
4460 	is_fat = iwk_is_fat_channel(sc);
4461 
4462 	/*
4463 	 * using low half channel number or high half channel number
4464 	 * identify fat channel
4465 	 */
4466 	if (is_fat && (sc->sc_config.flags &
4467 	    RXON_FLG_CONTROL_CHANNEL_LOC_HIGH_MSK)) {
4468 		is_high_chan = 1;
4469 	}
4470 
4471 	if ((channel > 0) && (channel < 200)) {
4472 		/* get regulatory channel data from eeprom */
4473 		eep_chan_p = iwk_get_eep_channel(sc, channel, is_24G,
4474 		    is_fat, is_high_chan);
4475 		if (NULL == eep_chan_p) {
4476 			cmn_err(CE_WARN,
4477 			    "iwk_txpower_table_cmd_init(): "
4478 			    "can't get channel infomation\n");
4479 			return (DDI_FAILURE);
4480 		}
4481 	} else {
4482 		cmn_err(CE_WARN, "iwk_txpower_table_cmd_init(): "
4483 		    "channel(%d) isn't in proper range\n",
4484 		    channel);
4485 		return (DDI_FAILURE);
4486 	}
4487 
4488 	/* initial value of Tx power */
4489 	sc->sc_user_txpower = (int32_t)eep_chan_p->max_power_avg;
4490 	if (sc->sc_user_txpower < IWK_TX_POWER_TARGET_POWER_MIN) {
4491 		cmn_err(CE_WARN, "iwk_txpower_table_cmd_init(): "
4492 		    "user TX power is too weak\n");
4493 		return (DDI_FAILURE);
4494 	} else if (sc->sc_user_txpower > IWK_TX_POWER_TARGET_POWER_MAX) {
4495 		cmn_err(CE_WARN, "iwk_txpower_table_cmd_init(): "
4496 		    "user TX power is too strong\n");
4497 		return (DDI_FAILURE);
4498 	}
4499 
4500 	target_power = 2 * sc->sc_user_txpower;
4501 
4502 	/* determine which group current channel belongs to */
4503 	tx_grp = iwk_txpower_grp(channel);
4504 	if (tx_grp < 0) {
4505 		return (tx_grp);
4506 	}
4507 
4508 
4509 	if (is_fat) {
4510 		if (is_high_chan) {
4511 			channel -= 2;
4512 		} else {
4513 			channel += 2;
4514 		}
4515 	}
4516 
4517 	/* determine saturation power */
4518 	if (is_24G) {
4519 		saturation_power =
4520 		    sc->sc_eep_map.calib_info.saturation_power24;
4521 	} else {
4522 		saturation_power =
4523 		    sc->sc_eep_map.calib_info.saturation_power52;
4524 	}
4525 
4526 	if (saturation_power < IWK_TX_POWER_SATURATION_MIN ||
4527 	    saturation_power > IWK_TX_POWER_SATURATION_MAX) {
4528 		if (is_24G) {
4529 			saturation_power = IWK_TX_POWER_DEFAULT_SATURATION_24;
4530 		} else {
4531 			saturation_power = IWK_TX_POWER_DEFAULT_SATURATION_52;
4532 		}
4533 	}
4534 
4535 	/* determine regulatory power */
4536 	regu_power = (int32_t)eep_chan_p->max_power_avg * 2;
4537 	if ((regu_power < IWK_TX_POWER_REGULATORY_MIN) ||
4538 	    (regu_power > IWK_TX_POWER_REGULATORY_MAX)) {
4539 		if (is_24G) {
4540 			regu_power = IWK_TX_POWER_DEFAULT_REGULATORY_24;
4541 		} else {
4542 			regu_power = IWK_TX_POWER_DEFAULT_REGULATORY_52;
4543 		}
4544 	}
4545 
4546 	/*
4547 	 * get measurement data for current channel
4548 	 * suach as temperature,index to gain table,actual Tx power
4549 	 */
4550 	(void) iwk_channel_interpolate(sc, channel, &eep_chan_calib);
4551 
4552 	eep_voltage = (int32_t)sc->sc_eep_map.calib_info.voltage;
4553 	init_voltage = (int32_t)sc->sc_card_alive_init.voltage;
4554 
4555 	/* calculate voltage compensation to Tx power */
4556 	voltage_compensation =
4557 	    iwk_voltage_compensation(eep_voltage, init_voltage);
4558 
4559 	if (sc->sc_tempera >= IWK_TX_POWER_TEMPERATURE_MIN) {
4560 		temperature = sc->sc_tempera;
4561 	} else {
4562 		temperature = IWK_TX_POWER_TEMPERATURE_MIN;
4563 	}
4564 	if (sc->sc_tempera <= IWK_TX_POWER_TEMPERATURE_MAX) {
4565 		temperature = sc->sc_tempera;
4566 	} else {
4567 		temperature = IWK_TX_POWER_TEMPERATURE_MAX;
4568 	}
4569 	temperature = KELVIN_TO_CELSIUS(temperature);
4570 
4571 	degrees_per_05db_num =
4572 	    txpower_tempera_comp_table[tx_grp].degrees_per_05db_a;
4573 	degrees_per_05db_denom =
4574 	    txpower_tempera_comp_table[tx_grp].degrees_per_05db_a_denom;
4575 
4576 	for (c = 0; c < 2; c++) {  /* go through all chains */
4577 		measure_p = &eep_chan_calib.measure[c][1];
4578 		interpo_temp = measure_p->temperature;
4579 
4580 		/* determine temperature compensation to Tx power */
4581 		(void) iwk_division(
4582 		    (temperature-interpo_temp)*degrees_per_05db_denom,
4583 		    degrees_per_05db_num, &tempera_comp[c]);
4584 
4585 		interpo_gain_idx[c] = measure_p->gain_idx;
4586 		interpo_actual_pow[c] = measure_p->actual_pow;
4587 	}
4588 
4589 	/*
4590 	 * go through all rate entries in Tx power table
4591 	 */
4592 	for (r = 0; r < POWER_TABLE_NUM_ENTRIES; r++) {
4593 		if (r & 0x8) {
4594 			/* need to lower regulatory power for MIMO mode */
4595 			curr_regu_power = regu_power -
4596 			    IWK_TX_POWER_MIMO_REGULATORY_COMPENSATION;
4597 			is_mimo = 1;
4598 		} else {
4599 			curr_regu_power = regu_power;
4600 			is_mimo = 0;
4601 		}
4602 
4603 		power_limit = saturation_power - back_off_table[r];
4604 		if (power_limit > curr_regu_power) {
4605 			/* final Tx power limit */
4606 			power_limit = curr_regu_power;
4607 		}
4608 
4609 		if (target_power > power_limit) {
4610 			target_power = power_limit; /* final target Tx power */
4611 		}
4612 
4613 		for (c = 0; c < 2; c++) {	  /* go through all Tx chains */
4614 			if (is_mimo) {
4615 				atten_value =
4616 				    sc->sc_card_alive_init.tx_atten[tx_grp][c];
4617 			} else {
4618 				atten_value = 0;
4619 			}
4620 
4621 			/*
4622 			 * calculate index in gain table
4623 			 * this step is very important
4624 			 */
4625 			txpower_gains_idx = interpo_gain_idx[c] -
4626 			    (target_power - interpo_actual_pow[c]) -
4627 			    tempera_comp[c] - voltage_compensation +
4628 			    atten_value;
4629 
4630 			if (txpower_gains_idx <
4631 			    iwk_min_power_index(r, is_24G)) {
4632 				txpower_gains_idx =
4633 				    iwk_min_power_index(r, is_24G);
4634 			}
4635 
4636 			if (!is_24G) {
4637 				/*
4638 				 * support negative index for 5 GHz
4639 				 * band
4640 				 */
4641 				txpower_gains_idx += 9;
4642 			}
4643 
4644 			if (POWER_TABLE_CCK_ENTRY == r) {
4645 				/* for CCK mode, make necessary attenuaton */
4646 				txpower_gains_idx +=
4647 				    IWK_TX_POWER_CCK_COMPENSATION_C_STEP;
4648 			}
4649 
4650 			if (txpower_gains_idx > 107) {
4651 				txpower_gains_idx = 107;
4652 			} else if (txpower_gains_idx < 0) {
4653 				txpower_gains_idx = 0;
4654 			}
4655 
4656 			/* search DSP and radio gains in gain table */
4657 			txpower_gains.s.radio_tx_gain[c] =
4658 			    gains_table[is_24G][txpower_gains_idx].radio;
4659 			txpower_gains.s.dsp_predis_atten[c] =
4660 			    gains_table[is_24G][txpower_gains_idx].dsp;
4661 
4662 			IWK_DBG((IWK_DEBUG_CALIBRATION,
4663 			    "rate_index: %d, "
4664 			    "gain_index %d, c: %d,is_mimo: %d\n",
4665 			    r, txpower_gains_idx, c, is_mimo));
4666 		}
4667 
4668 		/* initialize Tx power table */
4669 		if (r < POWER_TABLE_NUM_HT_OFDM_ENTRIES) {
4670 			tp_db->ht_ofdm_power[r].dw = txpower_gains.dw;
4671 		} else {
4672 			tp_db->legacy_cck_power.dw = txpower_gains.dw;
4673 		}
4674 	}
4675 
4676 	return (IWK_SUCCESS);
4677 }
4678 
4679 /*
4680  * make Tx power calibration to adjust Tx power.
4681  * This is completed by sending out Tx power table command.
4682  */
4683 static int iwk_tx_power_calibration(iwk_sc_t *sc)
4684 {
4685 	iwk_tx_power_table_cmd_t cmd;
4686 	int rv;
4687 
4688 	if (sc->sc_flags & IWK_F_SCANNING) {
4689 		return (IWK_SUCCESS);
4690 	}
4691 
4692 	/* necessary initialization to Tx power table command */
4693 	cmd.band = (uint8_t)iwk_is_24G_band(sc);
4694 	cmd.channel = sc->sc_config.chan;
4695 	cmd.channel_normal_width = 0;
4696 
4697 	/* initialize Tx power table */
4698 	rv = iwk_txpower_table_cmd_init(sc, &cmd.tx_power);
4699 	if (rv) {
4700 		cmn_err(CE_NOTE, "rv= %d\n", rv);
4701 		return (rv);
4702 	}
4703 
4704 	/* send out Tx power table command */
4705 	rv = iwk_cmd(sc, REPLY_TX_PWR_TABLE_CMD, &cmd, sizeof (cmd), 1);
4706 	if (rv) {
4707 		return (rv);
4708 	}
4709 
4710 	/* record current temperature */
4711 	sc->sc_last_tempera = sc->sc_tempera;
4712 
4713 	return (IWK_SUCCESS);
4714 }
4715 
4716 /* This function is the handler of statistics notification from uCode */
4717 static void iwk_statistics_notify(iwk_sc_t *sc, iwk_rx_desc_t *desc)
4718 {
4719 	int is_diff;
4720 	struct iwk_notif_statistics *statistics_p =
4721 	    (struct iwk_notif_statistics *)(desc + 1);
4722 
4723 	mutex_enter(&sc->sc_glock);
4724 
4725 	is_diff = (sc->sc_statistics.general.temperature !=
4726 	    statistics_p->general.temperature) ||
4727 	    ((sc->sc_statistics.flag & STATISTICS_REPLY_FLG_FAT_MODE_MSK) !=
4728 	    (statistics_p->flag & STATISTICS_REPLY_FLG_FAT_MODE_MSK));
4729 
4730 	/* update statistics data */
4731 	(void) memcpy(&sc->sc_statistics, statistics_p,
4732 	    sizeof (struct iwk_notif_statistics));
4733 
4734 	sc->sc_flags |= IWK_F_STATISTICS;
4735 
4736 	if (!(sc->sc_flags & IWK_F_SCANNING)) {
4737 		/* make Receiver gain balance calibration */
4738 		(void) iwk_rxgain_diff(sc);
4739 
4740 		/* make Receiver sensitivity calibration */
4741 		(void) iwk_rx_sens(sc);
4742 	}
4743 
4744 
4745 	if (!is_diff) {
4746 		mutex_exit(&sc->sc_glock);
4747 		return;
4748 	}
4749 
4750 	/* calibration current temperature of 4965 chipset */
4751 	sc->sc_tempera = iwk_curr_tempera(sc);
4752 
4753 	/* distinct temperature change will trigger Tx power calibration */
4754 	if (((sc->sc_tempera - sc->sc_last_tempera) >= 3) ||
4755 	    ((sc->sc_last_tempera - sc->sc_tempera) >= 3)) {
4756 		/* make Tx power calibration */
4757 		(void) iwk_tx_power_calibration(sc);
4758 	}
4759 
4760 	mutex_exit(&sc->sc_glock);
4761 }
4762 
4763 /* Determine this station is in associated state or not */
4764 static int iwk_is_associated(iwk_sc_t *sc)
4765 {
4766 	return (sc->sc_config.filter_flags & RXON_FILTER_ASSOC_MSK);
4767 }
4768 
4769 /* Make necessary preparation for Receiver gain balance calibration */
4770 static int iwk_rxgain_diff_init(iwk_sc_t *sc)
4771 {
4772 	int i, rv;
4773 	struct iwk_calibration_cmd cmd;
4774 	struct iwk_rx_gain_diff *gain_diff_p;
4775 
4776 	gain_diff_p = &sc->sc_rxgain_diff;
4777 
4778 	(void) memset(gain_diff_p, 0, sizeof (struct iwk_rx_gain_diff));
4779 	(void) memset(&cmd, 0, sizeof (struct iwk_calibration_cmd));
4780 
4781 	for (i = 0; i < RX_CHAINS_NUM; i++) {
4782 		gain_diff_p->gain_diff_chain[i] = CHAIN_GAIN_DIFF_INIT_VAL;
4783 	}
4784 
4785 	if (iwk_is_associated(sc)) {
4786 		cmd.opCode = PHY_CALIBRATE_DIFF_GAIN_CMD;
4787 		cmd.diff_gain_a = 0;
4788 		cmd.diff_gain_b = 0;
4789 		cmd.diff_gain_c = 0;
4790 
4791 		/* assume the gains of every Rx chains is balanceable */
4792 		rv = iwk_cmd(sc, REPLY_PHY_CALIBRATION_CMD, &cmd,
4793 		    sizeof (cmd), 1);
4794 		if (rv) {
4795 			return (rv);
4796 		}
4797 
4798 		gain_diff_p->state = IWK_GAIN_DIFF_ACCUMULATE;
4799 	}
4800 
4801 	return (IWK_SUCCESS);
4802 }
4803 
4804 /*
4805  * make Receiver gain balance to balance Rx gain between Rx chains
4806  * and determine which chain is disconnected
4807  */
4808 static int iwk_rxgain_diff(iwk_sc_t *sc)
4809 {
4810 	int i, is_24G, rv;
4811 	int max_beacon_chain_n;
4812 	int min_noise_chain_n;
4813 	uint16_t channel_n;
4814 	int32_t beacon_diff;
4815 	int32_t noise_diff;
4816 	uint32_t noise_chain_a, noise_chain_b, noise_chain_c;
4817 	uint32_t beacon_chain_a, beacon_chain_b, beacon_chain_c;
4818 	struct iwk_calibration_cmd cmd;
4819 	uint32_t beacon_aver[RX_CHAINS_NUM] = {0xFFFFFFFF};
4820 	uint32_t noise_aver[RX_CHAINS_NUM] = {0xFFFFFFFF};
4821 	struct statistics_rx_non_phy *rx_general_p =
4822 	    &sc->sc_statistics.rx.general;
4823 	struct iwk_rx_gain_diff *gain_diff_p = &sc->sc_rxgain_diff;
4824 
4825 	if (INTERFERENCE_DATA_AVAILABLE !=
4826 	    rx_general_p->interference_data_flag) {
4827 		return (IWK_SUCCESS);
4828 	}
4829 
4830 	if (IWK_GAIN_DIFF_ACCUMULATE != gain_diff_p->state) {
4831 		return (IWK_SUCCESS);
4832 	}
4833 
4834 	is_24G = iwk_is_24G_band(sc);
4835 	channel_n = sc->sc_config.chan;	 /* channel number */
4836 
4837 	if ((channel_n != (sc->sc_statistics.flag >> 16)) ||
4838 	    ((STATISTICS_REPLY_FLG_BAND_24G_MSK ==
4839 	    (sc->sc_statistics.flag & STATISTICS_REPLY_FLG_BAND_24G_MSK)) &&
4840 	    !is_24G)) {
4841 		return (IWK_SUCCESS);
4842 	}
4843 
4844 	/* Rx chain's noise strength from statistics notification */
4845 	noise_chain_a = rx_general_p->beacon_silence_rssi_a & 0xFF;
4846 	noise_chain_b = rx_general_p->beacon_silence_rssi_b & 0xFF;
4847 	noise_chain_c = rx_general_p->beacon_silence_rssi_c & 0xFF;
4848 
4849 	/* Rx chain's beacon strength from statistics notification */
4850 	beacon_chain_a = rx_general_p->beacon_rssi_a & 0xFF;
4851 	beacon_chain_b = rx_general_p->beacon_rssi_b & 0xFF;
4852 	beacon_chain_c = rx_general_p->beacon_rssi_c & 0xFF;
4853 
4854 	gain_diff_p->beacon_count++;
4855 
4856 	/* accumulate chain's noise strength */
4857 	gain_diff_p->noise_stren_a += noise_chain_a;
4858 	gain_diff_p->noise_stren_b += noise_chain_b;
4859 	gain_diff_p->noise_stren_c += noise_chain_c;
4860 
4861 	/* accumulate chain's beacon strength */
4862 	gain_diff_p->beacon_stren_a += beacon_chain_a;
4863 	gain_diff_p->beacon_stren_b += beacon_chain_b;
4864 	gain_diff_p->beacon_stren_c += beacon_chain_c;
4865 
4866 	if (BEACON_NUM_20 == gain_diff_p->beacon_count) {
4867 		/* calculate average beacon strength */
4868 		beacon_aver[0] = (gain_diff_p->beacon_stren_a) / BEACON_NUM_20;
4869 		beacon_aver[1] = (gain_diff_p->beacon_stren_b) / BEACON_NUM_20;
4870 		beacon_aver[2] = (gain_diff_p->beacon_stren_c) / BEACON_NUM_20;
4871 
4872 		/* calculate average noise strength */
4873 		noise_aver[0] = (gain_diff_p->noise_stren_a) / BEACON_NUM_20;
4874 		noise_aver[1] = (gain_diff_p->noise_stren_b) / BEACON_NUM_20;
4875 		noise_aver[2] = (gain_diff_p->noise_stren_b) / BEACON_NUM_20;
4876 
4877 		/* determine maximum beacon strength among 3 chains */
4878 		if ((beacon_aver[0] >= beacon_aver[1]) &&
4879 		    (beacon_aver[0] >= beacon_aver[2])) {
4880 			max_beacon_chain_n = 0;
4881 			gain_diff_p->connected_chains = 1 << 0;
4882 		} else if (beacon_aver[1] >= beacon_aver[2]) {
4883 			max_beacon_chain_n = 1;
4884 			gain_diff_p->connected_chains = 1 << 1;
4885 		} else {
4886 			max_beacon_chain_n = 2;
4887 			gain_diff_p->connected_chains = 1 << 2;
4888 		}
4889 
4890 		/* determine which chain is disconnected */
4891 		for (i = 0; i < RX_CHAINS_NUM; i++) {
4892 			if (i != max_beacon_chain_n) {
4893 				beacon_diff = beacon_aver[max_beacon_chain_n] -
4894 				    beacon_aver[i];
4895 				if (beacon_diff > MAX_ALLOWED_DIFF) {
4896 					gain_diff_p->disconnect_chain[i] = 1;
4897 				} else {
4898 					gain_diff_p->connected_chains |=
4899 					    (1 << i);
4900 				}
4901 			}
4902 		}
4903 
4904 		/*
4905 		 * if chain A and B are both disconnected,
4906 		 * assume the stronger in beacon strength is connected
4907 		 */
4908 		if (gain_diff_p->disconnect_chain[0] &&
4909 		    gain_diff_p->disconnect_chain[1]) {
4910 			if (beacon_aver[0] >= beacon_aver[1]) {
4911 				gain_diff_p->disconnect_chain[0] = 0;
4912 				gain_diff_p->connected_chains |= (1 << 0);
4913 			} else {
4914 				gain_diff_p->disconnect_chain[1] = 0;
4915 				gain_diff_p->connected_chains |= (1 << 1);
4916 			}
4917 		}
4918 
4919 		/* determine minimum noise strength among 3 chains */
4920 		if (!gain_diff_p->disconnect_chain[0]) {
4921 			min_noise_chain_n = 0;
4922 
4923 			for (i = 0; i < RX_CHAINS_NUM; i++) {
4924 				if (!gain_diff_p->disconnect_chain[i] &&
4925 				    (noise_aver[i] <=
4926 				    noise_aver[min_noise_chain_n])) {
4927 					min_noise_chain_n = i;
4928 				}
4929 
4930 			}
4931 		} else {
4932 			min_noise_chain_n = 1;
4933 
4934 			for (i = 0; i < RX_CHAINS_NUM; i++) {
4935 				if (!gain_diff_p->disconnect_chain[i] &&
4936 				    (noise_aver[i] <=
4937 				    noise_aver[min_noise_chain_n])) {
4938 					min_noise_chain_n = i;
4939 				}
4940 			}
4941 		}
4942 
4943 		gain_diff_p->gain_diff_chain[min_noise_chain_n] = 0;
4944 
4945 		/* determine gain difference between chains */
4946 		for (i = 0; i < RX_CHAINS_NUM; i++) {
4947 			if (!gain_diff_p->disconnect_chain[i] &&
4948 			    (CHAIN_GAIN_DIFF_INIT_VAL ==
4949 			    gain_diff_p->gain_diff_chain[i])) {
4950 
4951 				noise_diff = noise_aver[i] -
4952 				    noise_aver[min_noise_chain_n];
4953 				gain_diff_p->gain_diff_chain[i] =
4954 				    (uint8_t)((noise_diff * 10) / 15);
4955 
4956 				if (gain_diff_p->gain_diff_chain[i] > 3) {
4957 					gain_diff_p->gain_diff_chain[i] = 3;
4958 				}
4959 
4960 				gain_diff_p->gain_diff_chain[i] |= (1 << 2);
4961 			} else {
4962 				gain_diff_p->gain_diff_chain[i] = 0;
4963 			}
4964 		}
4965 
4966 		if (!gain_diff_p->gain_diff_send) {
4967 			gain_diff_p->gain_diff_send = 1;
4968 
4969 			(void) memset(&cmd, 0, sizeof (cmd));
4970 
4971 			cmd.opCode = PHY_CALIBRATE_DIFF_GAIN_CMD;
4972 			cmd.diff_gain_a = gain_diff_p->gain_diff_chain[0];
4973 			cmd.diff_gain_b = gain_diff_p->gain_diff_chain[1];
4974 			cmd.diff_gain_c = gain_diff_p->gain_diff_chain[2];
4975 
4976 			/*
4977 			 * send out PHY calibration command to
4978 			 * adjust every chain's Rx gain
4979 			 */
4980 			rv = iwk_cmd(sc, REPLY_PHY_CALIBRATION_CMD,
4981 			    &cmd, sizeof (cmd), 1);
4982 			if (rv) {
4983 				return (rv);
4984 			}
4985 
4986 			gain_diff_p->state = IWK_GAIN_DIFF_CALIBRATED;
4987 		}
4988 
4989 		gain_diff_p->beacon_stren_a = 0;
4990 		gain_diff_p->beacon_stren_b = 0;
4991 		gain_diff_p->beacon_stren_c = 0;
4992 
4993 		gain_diff_p->noise_stren_a = 0;
4994 		gain_diff_p->noise_stren_b = 0;
4995 		gain_diff_p->noise_stren_c = 0;
4996 	}
4997 
4998 	return (IWK_SUCCESS);
4999 }
5000 
5001 /* Make necessary preparation for Receiver sensitivity calibration */
5002 static int iwk_rx_sens_init(iwk_sc_t *sc)
5003 {
5004 	int i, rv;
5005 	struct iwk_rx_sensitivity_cmd cmd;
5006 	struct iwk_rx_sensitivity *rx_sens_p = &sc->sc_rx_sens;
5007 
5008 	(void) memset(&cmd, 0, sizeof (struct iwk_rx_sensitivity_cmd));
5009 	(void) memset(rx_sens_p, 0, sizeof (struct iwk_rx_sensitivity));
5010 
5011 	rx_sens_p->auto_corr_ofdm_x4 = 90;
5012 	rx_sens_p->auto_corr_mrc_ofdm_x4 = 170;
5013 	rx_sens_p->auto_corr_ofdm_x1 = 105;
5014 	rx_sens_p->auto_corr_mrc_ofdm_x1 = 220;
5015 
5016 	rx_sens_p->auto_corr_cck_x4 = 125;
5017 	rx_sens_p->auto_corr_mrc_cck_x4 = 200;
5018 	rx_sens_p->min_energy_det_cck = 100;
5019 
5020 	rx_sens_p->flags &= (~IWK_SENSITIVITY_CALIB_ALLOW_MSK);
5021 	rx_sens_p->flags &= (~IWK_SENSITIVITY_OFDM_UPDATE_MSK);
5022 	rx_sens_p->flags &= (~IWK_SENSITIVITY_CCK_UPDATE_MSK);
5023 
5024 	rx_sens_p->last_bad_plcp_cnt_ofdm = 0;
5025 	rx_sens_p->last_false_alarm_cnt_ofdm = 0;
5026 	rx_sens_p->last_bad_plcp_cnt_cck = 0;
5027 	rx_sens_p->last_false_alarm_cnt_cck = 0;
5028 
5029 	rx_sens_p->cck_curr_state = IWK_TOO_MANY_FALSE_ALARM;
5030 	rx_sens_p->cck_prev_state = IWK_TOO_MANY_FALSE_ALARM;
5031 	rx_sens_p->cck_no_false_alarm_num = 0;
5032 	rx_sens_p->cck_beacon_idx = 0;
5033 
5034 	for (i = 0; i < 10; i++) {
5035 		rx_sens_p->cck_beacon_min[i] = 0;
5036 	}
5037 
5038 	rx_sens_p->cck_noise_idx = 0;
5039 	rx_sens_p->cck_noise_ref = 0;
5040 
5041 	for (i = 0; i < 20; i++) {
5042 		rx_sens_p->cck_noise_max[i] = 0;
5043 	}
5044 
5045 	rx_sens_p->cck_noise_diff = 0;
5046 	rx_sens_p->cck_no_false_alarm_num = 0;
5047 
5048 	cmd.control = IWK_SENSITIVITY_CONTROL_WORK_TABLE;
5049 
5050 	cmd.table[AUTO_CORR32_X4_TH_ADD_MIN_IDX] =
5051 	    rx_sens_p->auto_corr_ofdm_x4;
5052 	cmd.table[AUTO_CORR32_X4_TH_ADD_MIN_MRC_IDX] =
5053 	    rx_sens_p->auto_corr_mrc_ofdm_x4;
5054 	cmd.table[AUTO_CORR32_X1_TH_ADD_MIN_IDX] =
5055 	    rx_sens_p->auto_corr_ofdm_x1;
5056 	cmd.table[AUTO_CORR32_X1_TH_ADD_MIN_MRC_IDX] =
5057 	    rx_sens_p->auto_corr_mrc_ofdm_x1;
5058 
5059 	cmd.table[AUTO_CORR40_X4_TH_ADD_MIN_IDX] =
5060 	    rx_sens_p->auto_corr_cck_x4;
5061 	cmd.table[AUTO_CORR40_X4_TH_ADD_MIN_MRC_IDX] =
5062 	    rx_sens_p->auto_corr_mrc_cck_x4;
5063 	cmd.table[MIN_ENERGY_CCK_DET_IDX] = rx_sens_p->min_energy_det_cck;
5064 
5065 	cmd.table[MIN_ENERGY_OFDM_DET_IDX] = 100;
5066 	cmd.table[BARKER_CORR_TH_ADD_MIN_IDX] = 190;
5067 	cmd.table[BARKER_CORR_TH_ADD_MIN_MRC_IDX] = 390;
5068 	cmd.table[PTAM_ENERGY_TH_IDX] = 62;
5069 
5070 	/* at first, set up Rx to maximum sensitivity */
5071 	rv = iwk_cmd(sc, SENSITIVITY_CMD, &cmd, sizeof (cmd), 1);
5072 	if (rv) {
5073 		cmn_err(CE_WARN, "iwk_rx_sens_init(): "
5074 		    "in the process of initialization, "
5075 		    "failed to send rx sensitivity command\n");
5076 		return (rv);
5077 	}
5078 
5079 	rx_sens_p->flags |= IWK_SENSITIVITY_CALIB_ALLOW_MSK;
5080 
5081 	return (IWK_SUCCESS);
5082 }
5083 
5084 /*
5085  * make Receiver sensitivity calibration to adjust every chain's Rx sensitivity.
5086  * for more infomation, please refer to iwk_calibration.h file
5087  */
5088 static int iwk_rx_sens(iwk_sc_t *sc)
5089 {
5090 	int rv;
5091 	uint32_t actual_rx_time;
5092 	struct statistics_rx_non_phy *rx_general_p =
5093 	    &sc->sc_statistics.rx.general;
5094 	struct iwk_rx_sensitivity *rx_sens_p = &sc->sc_rx_sens;
5095 	struct iwk_rx_sensitivity_cmd cmd;
5096 
5097 	if (!(rx_sens_p->flags & IWK_SENSITIVITY_CALIB_ALLOW_MSK)) {
5098 		cmn_err(CE_WARN, "iwk_rx_sens(): "
5099 		    "sensitivity initialization has not finished.\n");
5100 		return (DDI_FAILURE);
5101 	}
5102 
5103 	if (INTERFERENCE_DATA_AVAILABLE !=
5104 	    rx_general_p->interference_data_flag) {
5105 		cmn_err(CE_WARN, "iwk_rx_sens(): "
5106 		    "can't make rx sensitivity calibration,"
5107 		    "because of invalid statistics\n");
5108 		return (DDI_FAILURE);
5109 	}
5110 
5111 	actual_rx_time = rx_general_p->channel_load;
5112 	if (!actual_rx_time) {
5113 		IWK_DBG((IWK_DEBUG_CALIBRATION, "iwk_rx_sens(): "
5114 		    "can't make rx sensitivity calibration,"
5115 		    "because has not enough rx time\n"));
5116 		return (DDI_FAILURE);
5117 	}
5118 
5119 	/* make Rx sensitivity calibration for OFDM mode */
5120 	rv = iwk_ofdm_sens(sc, actual_rx_time);
5121 	if (rv) {
5122 		return (rv);
5123 	}
5124 
5125 	/* make Rx sensitivity calibration for CCK mode */
5126 	rv = iwk_cck_sens(sc, actual_rx_time);
5127 	if (rv) {
5128 		return (rv);
5129 	}
5130 
5131 	/*
5132 	 * if the sum of false alarm had not changed, nothing will be done
5133 	 */
5134 	if ((!(rx_sens_p->flags & IWK_SENSITIVITY_OFDM_UPDATE_MSK)) &&
5135 	    (!(rx_sens_p->flags & IWK_SENSITIVITY_CCK_UPDATE_MSK))) {
5136 		return (IWK_SUCCESS);
5137 	}
5138 
5139 	cmd.control = IWK_SENSITIVITY_CONTROL_WORK_TABLE;
5140 
5141 	cmd.table[AUTO_CORR32_X4_TH_ADD_MIN_IDX] =
5142 	    rx_sens_p->auto_corr_ofdm_x4;
5143 	cmd.table[AUTO_CORR32_X4_TH_ADD_MIN_MRC_IDX] =
5144 	    rx_sens_p->auto_corr_mrc_ofdm_x4;
5145 	cmd.table[AUTO_CORR32_X1_TH_ADD_MIN_IDX] =
5146 	    rx_sens_p->auto_corr_ofdm_x1;
5147 	cmd.table[AUTO_CORR32_X1_TH_ADD_MIN_MRC_IDX] =
5148 	    rx_sens_p->auto_corr_mrc_ofdm_x1;
5149 
5150 	cmd.table[AUTO_CORR40_X4_TH_ADD_MIN_IDX] =
5151 	    rx_sens_p->auto_corr_cck_x4;
5152 	cmd.table[AUTO_CORR40_X4_TH_ADD_MIN_MRC_IDX] =
5153 	    rx_sens_p->auto_corr_mrc_cck_x4;
5154 	cmd.table[MIN_ENERGY_CCK_DET_IDX] =
5155 	    rx_sens_p->min_energy_det_cck;
5156 
5157 	cmd.table[MIN_ENERGY_OFDM_DET_IDX] = 100;
5158 	cmd.table[BARKER_CORR_TH_ADD_MIN_IDX] = 190;
5159 	cmd.table[BARKER_CORR_TH_ADD_MIN_MRC_IDX] = 390;
5160 	cmd.table[PTAM_ENERGY_TH_IDX] = 62;
5161 
5162 	/*
5163 	 * send sensitivity command to complete actual sensitivity calibration
5164 	 */
5165 	rv = iwk_cmd(sc, SENSITIVITY_CMD, &cmd, sizeof (cmd), 1);
5166 	if (rv) {
5167 		cmn_err(CE_WARN, "iwk_rx_sens(): "
5168 		    "fail to send rx sensitivity command\n");
5169 		return (rv);
5170 	}
5171 
5172 	return (IWK_SUCCESS);
5173 
5174 }
5175 
5176 /*
5177  * make Rx sensitivity calibration for CCK mode.
5178  * This is preparing parameters for Sensitivity command
5179  */
5180 static int iwk_cck_sens(iwk_sc_t *sc, uint32_t actual_rx_time)
5181 {
5182 	int i;
5183 	uint8_t noise_a, noise_b, noise_c;
5184 	uint8_t max_noise_abc, max_noise_20;
5185 	uint32_t beacon_a, beacon_b, beacon_c;
5186 	uint32_t min_beacon_abc, max_beacon_10;
5187 	uint32_t cck_fa, cck_bp;
5188 	uint32_t cck_sum_fa_bp;
5189 	uint32_t temp;
5190 	struct statistics_rx_non_phy *rx_general_p =
5191 	    &sc->sc_statistics.rx.general;
5192 	struct iwk_rx_sensitivity *rx_sens_p = &sc->sc_rx_sens;
5193 
5194 	cck_fa = sc->sc_statistics.rx.cck.false_alarm_cnt;
5195 	cck_bp = sc->sc_statistics.rx.cck.plcp_err;
5196 
5197 	/* accumulate false alarm */
5198 	if (rx_sens_p->last_false_alarm_cnt_cck > cck_fa) {
5199 		temp = rx_sens_p->last_false_alarm_cnt_cck;
5200 		rx_sens_p->last_false_alarm_cnt_cck = cck_fa;
5201 		cck_fa += (0xFFFFFFFF - temp);
5202 	} else {
5203 		cck_fa -= rx_sens_p->last_false_alarm_cnt_cck;
5204 		rx_sens_p->last_false_alarm_cnt_cck += cck_fa;
5205 	}
5206 
5207 	/* accumulate bad plcp */
5208 	if (rx_sens_p->last_bad_plcp_cnt_cck > cck_bp) {
5209 		temp = rx_sens_p->last_bad_plcp_cnt_cck;
5210 		rx_sens_p->last_bad_plcp_cnt_cck = cck_bp;
5211 		cck_bp += (0xFFFFFFFF - temp);
5212 	} else {
5213 		cck_bp -= rx_sens_p->last_bad_plcp_cnt_cck;
5214 		rx_sens_p->last_bad_plcp_cnt_cck += cck_bp;
5215 	}
5216 
5217 	/*
5218 	 * calculate relative value
5219 	 */
5220 	cck_sum_fa_bp = (cck_fa + cck_bp) * 200 * 1024;
5221 	rx_sens_p->cck_noise_diff = 0;
5222 
5223 	noise_a =
5224 	    (uint8_t)((rx_general_p->beacon_silence_rssi_a & 0xFF00) >> 8);
5225 	noise_b =
5226 	    (uint8_t)((rx_general_p->beacon_silence_rssi_b & 0xFF00) >> 8);
5227 	noise_c =
5228 	    (uint8_t)((rx_general_p->beacon_silence_rssi_c & 0xFF00) >> 8);
5229 
5230 	beacon_a = rx_general_p->beacon_energy_a;
5231 	beacon_b = rx_general_p->beacon_energy_b;
5232 	beacon_c = rx_general_p->beacon_energy_c;
5233 
5234 	/* determine maximum noise among 3 chains */
5235 	if ((noise_a >= noise_b) && (noise_a >= noise_c)) {
5236 		max_noise_abc = noise_a;
5237 	} else if (noise_b >= noise_c) {
5238 		max_noise_abc = noise_b;
5239 	} else {
5240 		max_noise_abc = noise_c;
5241 	}
5242 
5243 	/* record maximum noise among 3 chains */
5244 	rx_sens_p->cck_noise_max[rx_sens_p->cck_noise_idx] = max_noise_abc;
5245 	rx_sens_p->cck_noise_idx++;
5246 	if (rx_sens_p->cck_noise_idx >= 20) {
5247 		rx_sens_p->cck_noise_idx = 0;
5248 	}
5249 
5250 	/* determine maximum noise among 20 max noise */
5251 	max_noise_20 = rx_sens_p->cck_noise_max[0];
5252 	for (i = 0; i < 20; i++) {
5253 		if (rx_sens_p->cck_noise_max[i] >= max_noise_20) {
5254 			max_noise_20 = rx_sens_p->cck_noise_max[i];
5255 		}
5256 	}
5257 
5258 	/* determine minimum beacon among 3 chains */
5259 	if ((beacon_a <= beacon_b) && (beacon_a <= beacon_c)) {
5260 		min_beacon_abc = beacon_a;
5261 	} else if (beacon_b <= beacon_c) {
5262 		min_beacon_abc = beacon_b;
5263 	} else {
5264 		min_beacon_abc = beacon_c;
5265 	}
5266 
5267 	/* record miminum beacon among 3 chains */
5268 	rx_sens_p->cck_beacon_min[rx_sens_p->cck_beacon_idx] = min_beacon_abc;
5269 	rx_sens_p->cck_beacon_idx++;
5270 	if (rx_sens_p->cck_beacon_idx >= 10) {
5271 		rx_sens_p->cck_beacon_idx = 0;
5272 	}
5273 
5274 	/* determine maximum beacon among 10 miminum beacon among 3 chains */
5275 	max_beacon_10 = rx_sens_p->cck_beacon_min[0];
5276 	for (i = 0; i < 10; i++) {
5277 		if (rx_sens_p->cck_beacon_min[i] >= max_beacon_10) {
5278 			max_beacon_10 = rx_sens_p->cck_beacon_min[i];
5279 		}
5280 	}
5281 
5282 	/* add a little margin */
5283 	max_beacon_10 += 6;
5284 
5285 	/* record the count of having no false alarms */
5286 	if (cck_sum_fa_bp < (5 * actual_rx_time)) {
5287 		rx_sens_p->cck_no_false_alarm_num++;
5288 	} else {
5289 		rx_sens_p->cck_no_false_alarm_num = 0;
5290 	}
5291 
5292 	/*
5293 	 * adjust parameters in sensitivity command
5294 	 * according to different status.
5295 	 * for more infomation, please refer to iwk_calibration.h file
5296 	 */
5297 	if (cck_sum_fa_bp > (50 * actual_rx_time)) {
5298 		rx_sens_p->cck_curr_state = IWK_TOO_MANY_FALSE_ALARM;
5299 
5300 		if (rx_sens_p->auto_corr_cck_x4 > 160) {
5301 			rx_sens_p->cck_noise_ref = max_noise_20;
5302 
5303 			if (rx_sens_p->min_energy_det_cck > 2) {
5304 				rx_sens_p->min_energy_det_cck -= 2;
5305 			}
5306 		}
5307 
5308 		if (rx_sens_p->auto_corr_cck_x4 < 160) {
5309 			rx_sens_p->auto_corr_cck_x4 = 160 + 1;
5310 		} else {
5311 			if ((rx_sens_p->auto_corr_cck_x4 + 3) < 200) {
5312 				rx_sens_p->auto_corr_cck_x4 += 3;
5313 			} else {
5314 				rx_sens_p->auto_corr_cck_x4 = 200;
5315 			}
5316 		}
5317 
5318 		if ((rx_sens_p->auto_corr_mrc_cck_x4 + 3) < 400) {
5319 			rx_sens_p->auto_corr_mrc_cck_x4 += 3;
5320 		} else {
5321 			rx_sens_p->auto_corr_mrc_cck_x4 = 400;
5322 		}
5323 
5324 		rx_sens_p->flags |= IWK_SENSITIVITY_CCK_UPDATE_MSK;
5325 
5326 	} else if (cck_sum_fa_bp < (5 * actual_rx_time)) {
5327 		rx_sens_p->cck_curr_state = IWK_TOO_FEW_FALSE_ALARM;
5328 
5329 		rx_sens_p->cck_noise_diff = (int32_t)rx_sens_p->cck_noise_ref -
5330 		    (int32_t)max_noise_20;
5331 
5332 		if ((rx_sens_p->cck_prev_state != IWK_TOO_MANY_FALSE_ALARM) &&
5333 		    ((rx_sens_p->cck_noise_diff > 2) ||
5334 		    (rx_sens_p->cck_no_false_alarm_num > 100))) {
5335 			if ((rx_sens_p->min_energy_det_cck + 2) < 97) {
5336 				rx_sens_p->min_energy_det_cck += 2;
5337 			} else {
5338 				rx_sens_p->min_energy_det_cck = 97;
5339 			}
5340 
5341 			if ((rx_sens_p->auto_corr_cck_x4 - 3) > 125) {
5342 				rx_sens_p->auto_corr_cck_x4 -= 3;
5343 			} else {
5344 				rx_sens_p->auto_corr_cck_x4 = 125;
5345 			}
5346 
5347 			if ((rx_sens_p->auto_corr_mrc_cck_x4 -3) > 200) {
5348 				rx_sens_p->auto_corr_mrc_cck_x4 -= 3;
5349 			} else {
5350 				rx_sens_p->auto_corr_mrc_cck_x4 = 200;
5351 			}
5352 
5353 			rx_sens_p->flags |= IWK_SENSITIVITY_CCK_UPDATE_MSK;
5354 		} else {
5355 			rx_sens_p->flags &= (~IWK_SENSITIVITY_CCK_UPDATE_MSK);
5356 		}
5357 	} else {
5358 		rx_sens_p->cck_curr_state = IWK_GOOD_RANGE_FALSE_ALARM;
5359 
5360 		rx_sens_p->cck_noise_ref = max_noise_20;
5361 
5362 		if (IWK_TOO_MANY_FALSE_ALARM == rx_sens_p->cck_prev_state) {
5363 			rx_sens_p->min_energy_det_cck -= 8;
5364 		}
5365 
5366 		rx_sens_p->flags &= (~IWK_SENSITIVITY_CCK_UPDATE_MSK);
5367 	}
5368 
5369 	if (rx_sens_p->min_energy_det_cck < max_beacon_10) {
5370 		rx_sens_p->min_energy_det_cck = (uint16_t)max_beacon_10;
5371 	}
5372 
5373 	rx_sens_p->cck_prev_state = rx_sens_p->cck_curr_state;
5374 
5375 	return (IWK_SUCCESS);
5376 }
5377 
5378 /*
5379  * make Rx sensitivity calibration for OFDM mode.
5380  * This is preparing parameters for Sensitivity command
5381  */
5382 static int iwk_ofdm_sens(iwk_sc_t *sc, uint32_t actual_rx_time)
5383 {
5384 	uint32_t temp;
5385 	uint16_t temp1;
5386 	uint32_t ofdm_fa, ofdm_bp;
5387 	uint32_t ofdm_sum_fa_bp;
5388 	struct iwk_rx_sensitivity *rx_sens_p = &sc->sc_rx_sens;
5389 
5390 	ofdm_fa = sc->sc_statistics.rx.ofdm.false_alarm_cnt;
5391 	ofdm_bp = sc->sc_statistics.rx.ofdm.plcp_err;
5392 
5393 	/* accumulate false alarm */
5394 	if (rx_sens_p->last_false_alarm_cnt_ofdm > ofdm_fa) {
5395 		temp = rx_sens_p->last_false_alarm_cnt_ofdm;
5396 		rx_sens_p->last_false_alarm_cnt_ofdm = ofdm_fa;
5397 		ofdm_fa += (0xFFFFFFFF - temp);
5398 	} else {
5399 		ofdm_fa -= rx_sens_p->last_false_alarm_cnt_ofdm;
5400 		rx_sens_p->last_false_alarm_cnt_ofdm += ofdm_fa;
5401 	}
5402 
5403 	/* accumulate bad plcp */
5404 	if (rx_sens_p->last_bad_plcp_cnt_ofdm > ofdm_bp) {
5405 		temp = rx_sens_p->last_bad_plcp_cnt_ofdm;
5406 		rx_sens_p->last_bad_plcp_cnt_ofdm = ofdm_bp;
5407 		ofdm_bp += (0xFFFFFFFF - temp);
5408 	} else {
5409 		ofdm_bp -= rx_sens_p->last_bad_plcp_cnt_ofdm;
5410 		rx_sens_p->last_bad_plcp_cnt_ofdm += ofdm_bp;
5411 	}
5412 
5413 	ofdm_sum_fa_bp = (ofdm_fa + ofdm_bp) * 200 * 1024; /* relative value */
5414 
5415 	/*
5416 	 * adjust parameter in sensitivity command according to different status
5417 	 */
5418 	if (ofdm_sum_fa_bp > (50 * actual_rx_time)) {
5419 		temp1 = rx_sens_p->auto_corr_ofdm_x4 + 1;
5420 		rx_sens_p->auto_corr_ofdm_x4 = (temp1 <= 120) ? temp1 : 120;
5421 
5422 		temp1 = rx_sens_p->auto_corr_mrc_ofdm_x4 + 1;
5423 		rx_sens_p->auto_corr_mrc_ofdm_x4 =
5424 		    (temp1 <= 210) ? temp1 : 210;
5425 
5426 		temp1 = rx_sens_p->auto_corr_ofdm_x1 + 1;
5427 		rx_sens_p->auto_corr_ofdm_x1 = (temp1 <= 140) ? temp1 : 140;
5428 
5429 		temp1 = rx_sens_p->auto_corr_mrc_ofdm_x1 + 1;
5430 		rx_sens_p->auto_corr_mrc_ofdm_x1 =
5431 		    (temp1 <= 270) ? temp1 : 270;
5432 
5433 		rx_sens_p->flags |= IWK_SENSITIVITY_OFDM_UPDATE_MSK;
5434 
5435 	} else if (ofdm_sum_fa_bp < (5 * actual_rx_time)) {
5436 		temp1 = rx_sens_p->auto_corr_ofdm_x4 - 1;
5437 		rx_sens_p->auto_corr_ofdm_x4 = (temp1 >= 85) ? temp1 : 85;
5438 
5439 		temp1 = rx_sens_p->auto_corr_mrc_ofdm_x4 - 1;
5440 		rx_sens_p->auto_corr_mrc_ofdm_x4 =
5441 		    (temp1 >= 170) ? temp1 : 170;
5442 
5443 		temp1 = rx_sens_p->auto_corr_ofdm_x1 - 1;
5444 		rx_sens_p->auto_corr_ofdm_x1 = (temp1 >= 105) ? temp1 : 105;
5445 
5446 		temp1 = rx_sens_p->auto_corr_mrc_ofdm_x1 - 1;
5447 		rx_sens_p->auto_corr_mrc_ofdm_x1 =
5448 		    (temp1 >= 220) ? temp1 : 220;
5449 
5450 		rx_sens_p->flags |= IWK_SENSITIVITY_OFDM_UPDATE_MSK;
5451 
5452 	} else {
5453 		rx_sens_p->flags &= (~IWK_SENSITIVITY_OFDM_UPDATE_MSK);
5454 	}
5455 
5456 	return (IWK_SUCCESS);
5457 }
5458 
5459 /*
5460  * 1)  log_event_table_ptr indicates base of the event log.  This traces
5461  *     a 256-entry history of uCode execution within a circular buffer.
5462  *     Its header format is:
5463  *
5464  *	uint32_t log_size;	log capacity (in number of entries)
5465  *	uint32_t type;	(1) timestamp with each entry, (0) no timestamp
5466  *	uint32_t wraps;	# times uCode has wrapped to top of circular buffer
5467  *      uint32_t write_index;	next circular buffer entry that uCode would fill
5468  *
5469  *     The header is followed by the circular buffer of log entries.  Entries
5470  *     with timestamps have the following format:
5471  *
5472  *	uint32_t event_id;     range 0 - 1500
5473  *	uint32_t timestamp;    low 32 bits of TSF (of network, if associated)
5474  *	uint32_t data;         event_id-specific data value
5475  *
5476  *     Entries without timestamps contain only event_id and data.
5477  */
5478 
5479 /*
5480  * iwk_write_event_log - Write event log to dmesg
5481  */
5482 static void iwk_write_event_log(iwk_sc_t *sc)
5483 {
5484 	uint32_t log_event_table_ptr;	/* Start address of event table */
5485 	uint32_t startptr;	/* Start address of log data */
5486 	uint32_t logptr;	/* address of log data entry */
5487 	uint32_t i, n, num_events;
5488 	uint32_t event_id, data1, data2; /* log data */
5489 
5490 	uint32_t log_size;   /* log capacity (in number of entries) */
5491 	uint32_t type;	/* (1)timestamp with each entry,(0) no timestamp */
5492 	uint32_t wraps;	/* # times uCode has wrapped to */
5493 			/* the top of circular buffer */
5494 	uint32_t idx; /* index of entry to be filled in next */
5495 
5496 	log_event_table_ptr = sc->sc_card_alive_run.log_event_table_ptr;
5497 	if (!(log_event_table_ptr)) {
5498 		IWK_DBG((IWK_DEBUG_EEPROM, "NULL event table pointer\n"));
5499 		return;
5500 	}
5501 
5502 	iwk_mac_access_enter(sc);
5503 
5504 	/* Read log header */
5505 	log_size = iwk_mem_read(sc, log_event_table_ptr);
5506 	log_event_table_ptr += sizeof (uint32_t); /* addr of "type" */
5507 	type = iwk_mem_read(sc, log_event_table_ptr);
5508 	log_event_table_ptr += sizeof (uint32_t); /* addr of "wraps" */
5509 	wraps = iwk_mem_read(sc, log_event_table_ptr);
5510 	log_event_table_ptr += sizeof (uint32_t); /* addr of "idx" */
5511 	idx = iwk_mem_read(sc, log_event_table_ptr);
5512 	startptr = log_event_table_ptr +
5513 	    sizeof (uint32_t); /* addr of start of log data */
5514 	if (!log_size & !wraps) {
5515 		IWK_DBG((IWK_DEBUG_EEPROM, "Empty log\n"));
5516 		iwk_mac_access_exit(sc);
5517 		return;
5518 	}
5519 
5520 	if (!wraps) {
5521 		num_events = idx;
5522 		logptr = startptr;
5523 	} else {
5524 		num_events = log_size - idx;
5525 		n = type ? 2 : 3;
5526 		logptr = startptr + (idx * n * sizeof (uint32_t));
5527 	}
5528 
5529 	for (i = 0; i < num_events; i++) {
5530 		event_id = iwk_mem_read(sc, logptr);
5531 		logptr += sizeof (uint32_t);
5532 		data1 = iwk_mem_read(sc, logptr);
5533 		logptr += sizeof (uint32_t);
5534 		if (type == 0) { /* no timestamp */
5535 			IWK_DBG((IWK_DEBUG_EEPROM, "Event ID=%d, Data=%x0x",
5536 			    event_id, data1));
5537 		} else { /* timestamp */
5538 			data2 = iwk_mem_read(sc, logptr);
5539 			printf("Time=%d, Event ID=%d, Data=0x%x\n",
5540 			    data1, event_id, data2);
5541 			IWK_DBG((IWK_DEBUG_EEPROM,
5542 			    "Time=%d, Event ID=%d, Data=0x%x\n",
5543 			    data1, event_id, data2));
5544 			logptr += sizeof (uint32_t);
5545 		}
5546 	}
5547 
5548 	/*
5549 	 * Print the wrapped around entries, if any
5550 	 */
5551 	if (wraps) {
5552 		logptr = startptr;
5553 		for (i = 0; i < idx; i++) {
5554 			event_id = iwk_mem_read(sc, logptr);
5555 			logptr += sizeof (uint32_t);
5556 			data1 = iwk_mem_read(sc, logptr);
5557 			logptr += sizeof (uint32_t);
5558 			if (type == 0) { /* no timestamp */
5559 				IWK_DBG((IWK_DEBUG_EEPROM,
5560 				    "Event ID=%d, Data=%x0x", event_id, data1));
5561 			} else { /* timestamp */
5562 				data2 = iwk_mem_read(sc, logptr);
5563 				IWK_DBG((IWK_DEBUG_EEPROM,
5564 				    "Time = %d, Event ID=%d, Data=0x%x\n",
5565 				    data1, event_id, data2));
5566 				logptr += sizeof (uint32_t);
5567 			}
5568 		}
5569 	}
5570 
5571 	iwk_mac_access_exit(sc);
5572 }
5573 
5574 /*
5575  * error_event_table_ptr indicates base of the error log.  This contains
5576  * information about any uCode error that occurs.  For 4965, the format is:
5577  *
5578  * uint32_t valid;        (nonzero) valid, (0) log is empty
5579  * uint32_t error_id;     type of error
5580  * uint32_t pc;           program counter
5581  * uint32_t blink1;       branch link
5582  * uint32_t blink2;       branch link
5583  * uint32_t ilink1;       interrupt link
5584  * uint32_t ilink2;       interrupt link
5585  * uint32_t data1;        error-specific data
5586  * uint32_t data2;        error-specific data
5587  * uint32_t line;         source code line of error
5588  * uint32_t bcon_time;    beacon timer
5589  * uint32_t tsf_low;      network timestamp function timer
5590  * uint32_t tsf_hi;       network timestamp function timer
5591  */
5592 /*
5593  * iwk_write_error_log - Write error log to dmesg
5594  */
5595 static void iwk_write_error_log(iwk_sc_t *sc)
5596 {
5597 	uint32_t err_ptr;	/* Start address of error log */
5598 	uint32_t valid;		/* is error log valid */
5599 
5600 	err_ptr = sc->sc_card_alive_run.error_event_table_ptr;
5601 	if (!(err_ptr)) {
5602 		IWK_DBG((IWK_DEBUG_EEPROM, "NULL error table pointer\n"));
5603 		return;
5604 	}
5605 
5606 	iwk_mac_access_enter(sc);
5607 
5608 	valid = iwk_mem_read(sc, err_ptr);
5609 	if (!(valid)) {
5610 		IWK_DBG((IWK_DEBUG_EEPROM, "Error data not valid\n"));
5611 		iwk_mac_access_exit(sc);
5612 		return;
5613 	}
5614 	err_ptr += sizeof (uint32_t);
5615 	IWK_DBG((IWK_DEBUG_EEPROM, "err=%d ", iwk_mem_read(sc, err_ptr)));
5616 	err_ptr += sizeof (uint32_t);
5617 	IWK_DBG((IWK_DEBUG_EEPROM, "pc=0x%X ", iwk_mem_read(sc, err_ptr)));
5618 	err_ptr += sizeof (uint32_t);
5619 	IWK_DBG((IWK_DEBUG_EEPROM,
5620 	    "branch link1=0x%X ", iwk_mem_read(sc, err_ptr)));
5621 	err_ptr += sizeof (uint32_t);
5622 	IWK_DBG((IWK_DEBUG_EEPROM,
5623 	    "branch link2=0x%X ", iwk_mem_read(sc, err_ptr)));
5624 	err_ptr += sizeof (uint32_t);
5625 	IWK_DBG((IWK_DEBUG_EEPROM,
5626 	    "interrupt link1=0x%X ", iwk_mem_read(sc, err_ptr)));
5627 	err_ptr += sizeof (uint32_t);
5628 	IWK_DBG((IWK_DEBUG_EEPROM,
5629 	    "interrupt link2=0x%X ", iwk_mem_read(sc, err_ptr)));
5630 	err_ptr += sizeof (uint32_t);
5631 	IWK_DBG((IWK_DEBUG_EEPROM, "data1=0x%X ", iwk_mem_read(sc, err_ptr)));
5632 	err_ptr += sizeof (uint32_t);
5633 	IWK_DBG((IWK_DEBUG_EEPROM, "data2=0x%X ", iwk_mem_read(sc, err_ptr)));
5634 	err_ptr += sizeof (uint32_t);
5635 	IWK_DBG((IWK_DEBUG_EEPROM, "line=%d ", iwk_mem_read(sc, err_ptr)));
5636 	err_ptr += sizeof (uint32_t);
5637 	IWK_DBG((IWK_DEBUG_EEPROM, "bcon_time=%d ", iwk_mem_read(sc, err_ptr)));
5638 	err_ptr += sizeof (uint32_t);
5639 	IWK_DBG((IWK_DEBUG_EEPROM, "tsf_low=%d ", iwk_mem_read(sc, err_ptr)));
5640 	err_ptr += sizeof (uint32_t);
5641 	IWK_DBG((IWK_DEBUG_EEPROM, "tsf_hi=%d\n", iwk_mem_read(sc, err_ptr)));
5642 
5643 	iwk_mac_access_exit(sc);
5644 }
5645