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