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