xref: /onnv-gate/usr/src/uts/common/io/iwp/iwp.c (revision 11878:ac93462db6d7)
110893SQuaker.Fang@Sun.COM /*
2*11878SVenu.Iyer@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
310893SQuaker.Fang@Sun.COM  * Use is subject to license terms.
410893SQuaker.Fang@Sun.COM  */
510893SQuaker.Fang@Sun.COM 
610893SQuaker.Fang@Sun.COM /*
710893SQuaker.Fang@Sun.COM  * Copyright (c) 2009, Intel Corporation
810893SQuaker.Fang@Sun.COM  * All rights reserved.
910893SQuaker.Fang@Sun.COM  */
1010893SQuaker.Fang@Sun.COM 
1110893SQuaker.Fang@Sun.COM /*
1210893SQuaker.Fang@Sun.COM  * Copyright (c) 2006
1310893SQuaker.Fang@Sun.COM  * Copyright (c) 2007
1410893SQuaker.Fang@Sun.COM  *	Damien Bergamini <damien.bergamini@free.fr>
1510893SQuaker.Fang@Sun.COM  *
1610893SQuaker.Fang@Sun.COM  * Permission to use, copy, modify, and distribute this software for any
1710893SQuaker.Fang@Sun.COM  * purpose with or without fee is hereby granted, provided that the above
1810893SQuaker.Fang@Sun.COM  * copyright notice and this permission notice appear in all copies.
1910893SQuaker.Fang@Sun.COM  *
2010893SQuaker.Fang@Sun.COM  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
2110893SQuaker.Fang@Sun.COM  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
2210893SQuaker.Fang@Sun.COM  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
2310893SQuaker.Fang@Sun.COM  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
2410893SQuaker.Fang@Sun.COM  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
2510893SQuaker.Fang@Sun.COM  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
2610893SQuaker.Fang@Sun.COM  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
2710893SQuaker.Fang@Sun.COM  */
2810893SQuaker.Fang@Sun.COM 
2910893SQuaker.Fang@Sun.COM /*
3010893SQuaker.Fang@Sun.COM  * Intel(R) WiFi Link 6000 Driver
3110893SQuaker.Fang@Sun.COM  */
3210893SQuaker.Fang@Sun.COM 
3310893SQuaker.Fang@Sun.COM #include <sys/types.h>
3410893SQuaker.Fang@Sun.COM #include <sys/byteorder.h>
3510893SQuaker.Fang@Sun.COM #include <sys/conf.h>
3610893SQuaker.Fang@Sun.COM #include <sys/cmn_err.h>
3710893SQuaker.Fang@Sun.COM #include <sys/stat.h>
3810893SQuaker.Fang@Sun.COM #include <sys/ddi.h>
3910893SQuaker.Fang@Sun.COM #include <sys/sunddi.h>
4010893SQuaker.Fang@Sun.COM #include <sys/strsubr.h>
4110893SQuaker.Fang@Sun.COM #include <sys/ethernet.h>
4210893SQuaker.Fang@Sun.COM #include <inet/common.h>
4310893SQuaker.Fang@Sun.COM #include <inet/nd.h>
4410893SQuaker.Fang@Sun.COM #include <inet/mi.h>
4510893SQuaker.Fang@Sun.COM #include <sys/note.h>
4610893SQuaker.Fang@Sun.COM #include <sys/stream.h>
4710893SQuaker.Fang@Sun.COM #include <sys/strsun.h>
4810893SQuaker.Fang@Sun.COM #include <sys/modctl.h>
4910893SQuaker.Fang@Sun.COM #include <sys/devops.h>
5010893SQuaker.Fang@Sun.COM #include <sys/dlpi.h>
5110893SQuaker.Fang@Sun.COM #include <sys/mac_provider.h>
5210893SQuaker.Fang@Sun.COM #include <sys/mac_wifi.h>
5310893SQuaker.Fang@Sun.COM #include <sys/net80211.h>
5410893SQuaker.Fang@Sun.COM #include <sys/net80211_proto.h>
5510893SQuaker.Fang@Sun.COM #include <sys/varargs.h>
5610893SQuaker.Fang@Sun.COM #include <sys/policy.h>
5710893SQuaker.Fang@Sun.COM #include <sys/pci.h>
5810893SQuaker.Fang@Sun.COM 
5910893SQuaker.Fang@Sun.COM #include "iwp_calibration.h"
6010893SQuaker.Fang@Sun.COM #include "iwp_hw.h"
6110893SQuaker.Fang@Sun.COM #include "iwp_eeprom.h"
6210893SQuaker.Fang@Sun.COM #include "iwp_var.h"
6310893SQuaker.Fang@Sun.COM #include <inet/wifi_ioctl.h>
6410893SQuaker.Fang@Sun.COM 
6510893SQuaker.Fang@Sun.COM #ifdef DEBUG
6610893SQuaker.Fang@Sun.COM #define	IWP_DEBUG_80211		(1 << 0)
6710893SQuaker.Fang@Sun.COM #define	IWP_DEBUG_CMD		(1 << 1)
6810893SQuaker.Fang@Sun.COM #define	IWP_DEBUG_DMA		(1 << 2)
6910893SQuaker.Fang@Sun.COM #define	IWP_DEBUG_EEPROM	(1 << 3)
7010893SQuaker.Fang@Sun.COM #define	IWP_DEBUG_FW		(1 << 4)
7110893SQuaker.Fang@Sun.COM #define	IWP_DEBUG_HW		(1 << 5)
7210893SQuaker.Fang@Sun.COM #define	IWP_DEBUG_INTR		(1 << 6)
7310893SQuaker.Fang@Sun.COM #define	IWP_DEBUG_MRR		(1 << 7)
7410893SQuaker.Fang@Sun.COM #define	IWP_DEBUG_PIO		(1 << 8)
7510893SQuaker.Fang@Sun.COM #define	IWP_DEBUG_RX		(1 << 9)
7610893SQuaker.Fang@Sun.COM #define	IWP_DEBUG_SCAN		(1 << 10)
7710893SQuaker.Fang@Sun.COM #define	IWP_DEBUG_TX		(1 << 11)
7810893SQuaker.Fang@Sun.COM #define	IWP_DEBUG_RATECTL	(1 << 12)
7910893SQuaker.Fang@Sun.COM #define	IWP_DEBUG_RADIO		(1 << 13)
8010893SQuaker.Fang@Sun.COM #define	IWP_DEBUG_RESUME	(1 << 14)
8110893SQuaker.Fang@Sun.COM #define	IWP_DEBUG_CALIBRATION	(1 << 15)
8210893SQuaker.Fang@Sun.COM /*
8310893SQuaker.Fang@Sun.COM  * if want to see debug message of a given section,
8410893SQuaker.Fang@Sun.COM  * please set this flag to one of above values
8510893SQuaker.Fang@Sun.COM  */
8610893SQuaker.Fang@Sun.COM uint32_t iwp_dbg_flags = 0;
8710893SQuaker.Fang@Sun.COM #define	IWP_DBG(x) \
8810893SQuaker.Fang@Sun.COM 	iwp_dbg x
8910893SQuaker.Fang@Sun.COM #else
9010893SQuaker.Fang@Sun.COM #define	IWP_DBG(x)
9110893SQuaker.Fang@Sun.COM #endif
9210893SQuaker.Fang@Sun.COM 
9310893SQuaker.Fang@Sun.COM static void	*iwp_soft_state_p = NULL;
9410893SQuaker.Fang@Sun.COM 
9510893SQuaker.Fang@Sun.COM /*
9610893SQuaker.Fang@Sun.COM  * ucode will be compiled into driver image
9710893SQuaker.Fang@Sun.COM  */
9810893SQuaker.Fang@Sun.COM static uint8_t iwp_fw_bin [] = {
9910893SQuaker.Fang@Sun.COM #include "fw-iw/iwp.ucode"
10010893SQuaker.Fang@Sun.COM };
10110893SQuaker.Fang@Sun.COM 
10210893SQuaker.Fang@Sun.COM /*
10310893SQuaker.Fang@Sun.COM  * DMA attributes for a shared page
10410893SQuaker.Fang@Sun.COM  */
10510893SQuaker.Fang@Sun.COM static ddi_dma_attr_t sh_dma_attr = {
10610893SQuaker.Fang@Sun.COM 	DMA_ATTR_V0,	/* version of this structure */
10710893SQuaker.Fang@Sun.COM 	0,		/* lowest usable address */
10810893SQuaker.Fang@Sun.COM 	0xffffffffU,	/* highest usable address */
10910893SQuaker.Fang@Sun.COM 	0xffffffffU,	/* maximum DMAable byte count */
11010893SQuaker.Fang@Sun.COM 	0x1000,		/* alignment in bytes */
11110893SQuaker.Fang@Sun.COM 	0x1000,		/* burst sizes (any?) */
11210893SQuaker.Fang@Sun.COM 	1,		/* minimum transfer */
11310893SQuaker.Fang@Sun.COM 	0xffffffffU,	/* maximum transfer */
11410893SQuaker.Fang@Sun.COM 	0xffffffffU,	/* maximum segment length */
11510893SQuaker.Fang@Sun.COM 	1,		/* maximum number of segments */
11610893SQuaker.Fang@Sun.COM 	1,		/* granularity */
11710893SQuaker.Fang@Sun.COM 	0,		/* flags (reserved) */
11810893SQuaker.Fang@Sun.COM };
11910893SQuaker.Fang@Sun.COM 
12010893SQuaker.Fang@Sun.COM /*
12110893SQuaker.Fang@Sun.COM  * DMA attributes for a keep warm DRAM descriptor
12210893SQuaker.Fang@Sun.COM  */
12310893SQuaker.Fang@Sun.COM static ddi_dma_attr_t kw_dma_attr = {
12410893SQuaker.Fang@Sun.COM 	DMA_ATTR_V0,	/* version of this structure */
12510893SQuaker.Fang@Sun.COM 	0,		/* lowest usable address */
12610893SQuaker.Fang@Sun.COM 	0xffffffffU,	/* highest usable address */
12710893SQuaker.Fang@Sun.COM 	0xffffffffU,	/* maximum DMAable byte count */
12810893SQuaker.Fang@Sun.COM 	0x1000,		/* alignment in bytes */
12910893SQuaker.Fang@Sun.COM 	0x1000,		/* burst sizes (any?) */
13010893SQuaker.Fang@Sun.COM 	1,		/* minimum transfer */
13110893SQuaker.Fang@Sun.COM 	0xffffffffU,	/* maximum transfer */
13210893SQuaker.Fang@Sun.COM 	0xffffffffU,	/* maximum segment length */
13310893SQuaker.Fang@Sun.COM 	1,		/* maximum number of segments */
13410893SQuaker.Fang@Sun.COM 	1,		/* granularity */
13510893SQuaker.Fang@Sun.COM 	0,		/* flags (reserved) */
13610893SQuaker.Fang@Sun.COM };
13710893SQuaker.Fang@Sun.COM 
13810893SQuaker.Fang@Sun.COM /*
13910893SQuaker.Fang@Sun.COM  * DMA attributes for a ring descriptor
14010893SQuaker.Fang@Sun.COM  */
14110893SQuaker.Fang@Sun.COM static ddi_dma_attr_t ring_desc_dma_attr = {
14210893SQuaker.Fang@Sun.COM 	DMA_ATTR_V0,	/* version of this structure */
14310893SQuaker.Fang@Sun.COM 	0,		/* lowest usable address */
14410893SQuaker.Fang@Sun.COM 	0xffffffffU,	/* highest usable address */
14510893SQuaker.Fang@Sun.COM 	0xffffffffU,	/* maximum DMAable byte count */
14610893SQuaker.Fang@Sun.COM 	0x100,		/* alignment in bytes */
14710893SQuaker.Fang@Sun.COM 	0x100,		/* burst sizes (any?) */
14810893SQuaker.Fang@Sun.COM 	1,		/* minimum transfer */
14910893SQuaker.Fang@Sun.COM 	0xffffffffU,	/* maximum transfer */
15010893SQuaker.Fang@Sun.COM 	0xffffffffU,	/* maximum segment length */
15110893SQuaker.Fang@Sun.COM 	1,		/* maximum number of segments */
15210893SQuaker.Fang@Sun.COM 	1,		/* granularity */
15310893SQuaker.Fang@Sun.COM 	0,		/* flags (reserved) */
15410893SQuaker.Fang@Sun.COM };
15510893SQuaker.Fang@Sun.COM 
15610893SQuaker.Fang@Sun.COM /*
15710893SQuaker.Fang@Sun.COM  * DMA attributes for a cmd
15810893SQuaker.Fang@Sun.COM  */
15910893SQuaker.Fang@Sun.COM static ddi_dma_attr_t cmd_dma_attr = {
16010893SQuaker.Fang@Sun.COM 	DMA_ATTR_V0,	/* version of this structure */
16110893SQuaker.Fang@Sun.COM 	0,		/* lowest usable address */
16210893SQuaker.Fang@Sun.COM 	0xffffffffU,	/* highest usable address */
16310893SQuaker.Fang@Sun.COM 	0xffffffffU,	/* maximum DMAable byte count */
16410893SQuaker.Fang@Sun.COM 	4,		/* alignment in bytes */
16510893SQuaker.Fang@Sun.COM 	0x100,		/* burst sizes (any?) */
16610893SQuaker.Fang@Sun.COM 	1,		/* minimum transfer */
16710893SQuaker.Fang@Sun.COM 	0xffffffffU,	/* maximum transfer */
16810893SQuaker.Fang@Sun.COM 	0xffffffffU,	/* maximum segment length */
16910893SQuaker.Fang@Sun.COM 	1,		/* maximum number of segments */
17010893SQuaker.Fang@Sun.COM 	1,		/* granularity */
17110893SQuaker.Fang@Sun.COM 	0,		/* flags (reserved) */
17210893SQuaker.Fang@Sun.COM };
17310893SQuaker.Fang@Sun.COM 
17410893SQuaker.Fang@Sun.COM /*
17510893SQuaker.Fang@Sun.COM  * DMA attributes for a rx buffer
17610893SQuaker.Fang@Sun.COM  */
17710893SQuaker.Fang@Sun.COM static ddi_dma_attr_t rx_buffer_dma_attr = {
17810893SQuaker.Fang@Sun.COM 	DMA_ATTR_V0,	/* version of this structure */
17910893SQuaker.Fang@Sun.COM 	0,		/* lowest usable address */
18010893SQuaker.Fang@Sun.COM 	0xffffffffU,	/* highest usable address */
18110893SQuaker.Fang@Sun.COM 	0xffffffffU,	/* maximum DMAable byte count */
18210893SQuaker.Fang@Sun.COM 	0x100,		/* alignment in bytes */
18310893SQuaker.Fang@Sun.COM 	0x100,		/* burst sizes (any?) */
18410893SQuaker.Fang@Sun.COM 	1,		/* minimum transfer */
18510893SQuaker.Fang@Sun.COM 	0xffffffffU,	/* maximum transfer */
18610893SQuaker.Fang@Sun.COM 	0xffffffffU,	/* maximum segment length */
18710893SQuaker.Fang@Sun.COM 	1,		/* maximum number of segments */
18810893SQuaker.Fang@Sun.COM 	1,		/* granularity */
18910893SQuaker.Fang@Sun.COM 	0,		/* flags (reserved) */
19010893SQuaker.Fang@Sun.COM };
19110893SQuaker.Fang@Sun.COM 
19210893SQuaker.Fang@Sun.COM /*
19310893SQuaker.Fang@Sun.COM  * DMA attributes for a tx buffer.
19410893SQuaker.Fang@Sun.COM  * the maximum number of segments is 4 for the hardware.
19510893SQuaker.Fang@Sun.COM  * now all the wifi drivers put the whole frame in a single
19610893SQuaker.Fang@Sun.COM  * descriptor, so we define the maximum  number of segments 1,
19710893SQuaker.Fang@Sun.COM  * just the same as the rx_buffer. we consider leverage the HW
19810893SQuaker.Fang@Sun.COM  * ability in the future, that is why we don't define rx and tx
19910893SQuaker.Fang@Sun.COM  * buffer_dma_attr as the same.
20010893SQuaker.Fang@Sun.COM  */
20110893SQuaker.Fang@Sun.COM static ddi_dma_attr_t tx_buffer_dma_attr = {
20210893SQuaker.Fang@Sun.COM 	DMA_ATTR_V0,	/* version of this structure */
20310893SQuaker.Fang@Sun.COM 	0,		/* lowest usable address */
20410893SQuaker.Fang@Sun.COM 	0xffffffffU,	/* highest usable address */
20510893SQuaker.Fang@Sun.COM 	0xffffffffU,	/* maximum DMAable byte count */
20610893SQuaker.Fang@Sun.COM 	4,		/* alignment in bytes */
20710893SQuaker.Fang@Sun.COM 	0x100,		/* burst sizes (any?) */
20810893SQuaker.Fang@Sun.COM 	1,		/* minimum transfer */
20910893SQuaker.Fang@Sun.COM 	0xffffffffU,	/* maximum transfer */
21010893SQuaker.Fang@Sun.COM 	0xffffffffU,	/* maximum segment length */
21110893SQuaker.Fang@Sun.COM 	1,		/* maximum number of segments */
21210893SQuaker.Fang@Sun.COM 	1,		/* granularity */
21310893SQuaker.Fang@Sun.COM 	0,		/* flags (reserved) */
21410893SQuaker.Fang@Sun.COM };
21510893SQuaker.Fang@Sun.COM 
21610893SQuaker.Fang@Sun.COM /*
21710893SQuaker.Fang@Sun.COM  * DMA attributes for text and data part in the firmware
21810893SQuaker.Fang@Sun.COM  */
21910893SQuaker.Fang@Sun.COM static ddi_dma_attr_t fw_dma_attr = {
22010893SQuaker.Fang@Sun.COM 	DMA_ATTR_V0,	/* version of this structure */
22110893SQuaker.Fang@Sun.COM 	0,		/* lowest usable address */
22210893SQuaker.Fang@Sun.COM 	0xffffffffU,	/* highest usable address */
22310893SQuaker.Fang@Sun.COM 	0x7fffffff,	/* maximum DMAable byte count */
22410893SQuaker.Fang@Sun.COM 	0x10,		/* alignment in bytes */
22510893SQuaker.Fang@Sun.COM 	0x100,		/* burst sizes (any?) */
22610893SQuaker.Fang@Sun.COM 	1,		/* minimum transfer */
22710893SQuaker.Fang@Sun.COM 	0xffffffffU,	/* maximum transfer */
22810893SQuaker.Fang@Sun.COM 	0xffffffffU,	/* maximum segment length */
22910893SQuaker.Fang@Sun.COM 	1,		/* maximum number of segments */
23010893SQuaker.Fang@Sun.COM 	1,		/* granularity */
23110893SQuaker.Fang@Sun.COM 	0,		/* flags (reserved) */
23210893SQuaker.Fang@Sun.COM };
23310893SQuaker.Fang@Sun.COM 
23410893SQuaker.Fang@Sun.COM /*
23510893SQuaker.Fang@Sun.COM  * regs access attributes
23610893SQuaker.Fang@Sun.COM  */
23710893SQuaker.Fang@Sun.COM static ddi_device_acc_attr_t iwp_reg_accattr = {
23810893SQuaker.Fang@Sun.COM 	DDI_DEVICE_ATTR_V0,
23910893SQuaker.Fang@Sun.COM 	DDI_STRUCTURE_LE_ACC,
24010893SQuaker.Fang@Sun.COM 	DDI_STRICTORDER_ACC,
24110893SQuaker.Fang@Sun.COM 	DDI_DEFAULT_ACC
24210893SQuaker.Fang@Sun.COM };
24310893SQuaker.Fang@Sun.COM 
24410893SQuaker.Fang@Sun.COM /*
24510893SQuaker.Fang@Sun.COM  * DMA access attributes for descriptor
24610893SQuaker.Fang@Sun.COM  */
24710893SQuaker.Fang@Sun.COM static ddi_device_acc_attr_t iwp_dma_descattr = {
24810893SQuaker.Fang@Sun.COM 	DDI_DEVICE_ATTR_V0,
24910893SQuaker.Fang@Sun.COM 	DDI_STRUCTURE_LE_ACC,
25010893SQuaker.Fang@Sun.COM 	DDI_STRICTORDER_ACC,
25110893SQuaker.Fang@Sun.COM 	DDI_DEFAULT_ACC
25210893SQuaker.Fang@Sun.COM };
25310893SQuaker.Fang@Sun.COM 
25410893SQuaker.Fang@Sun.COM /*
25510893SQuaker.Fang@Sun.COM  * DMA access attributes
25610893SQuaker.Fang@Sun.COM  */
25710893SQuaker.Fang@Sun.COM static ddi_device_acc_attr_t iwp_dma_accattr = {
25810893SQuaker.Fang@Sun.COM 	DDI_DEVICE_ATTR_V0,
25910893SQuaker.Fang@Sun.COM 	DDI_NEVERSWAP_ACC,
26010893SQuaker.Fang@Sun.COM 	DDI_STRICTORDER_ACC,
26110893SQuaker.Fang@Sun.COM 	DDI_DEFAULT_ACC
26210893SQuaker.Fang@Sun.COM };
26310893SQuaker.Fang@Sun.COM 
26410893SQuaker.Fang@Sun.COM static int	iwp_ring_init(iwp_sc_t *);
26510893SQuaker.Fang@Sun.COM static void	iwp_ring_free(iwp_sc_t *);
26610893SQuaker.Fang@Sun.COM static int	iwp_alloc_shared(iwp_sc_t *);
26710893SQuaker.Fang@Sun.COM static void	iwp_free_shared(iwp_sc_t *);
26810893SQuaker.Fang@Sun.COM static int	iwp_alloc_kw(iwp_sc_t *);
26910893SQuaker.Fang@Sun.COM static void	iwp_free_kw(iwp_sc_t *);
27010893SQuaker.Fang@Sun.COM static int	iwp_alloc_fw_dma(iwp_sc_t *);
27110893SQuaker.Fang@Sun.COM static void	iwp_free_fw_dma(iwp_sc_t *);
27210893SQuaker.Fang@Sun.COM static int	iwp_alloc_rx_ring(iwp_sc_t *);
27310893SQuaker.Fang@Sun.COM static void	iwp_reset_rx_ring(iwp_sc_t *);
27410893SQuaker.Fang@Sun.COM static void	iwp_free_rx_ring(iwp_sc_t *);
27510893SQuaker.Fang@Sun.COM static int	iwp_alloc_tx_ring(iwp_sc_t *, iwp_tx_ring_t *,
27610893SQuaker.Fang@Sun.COM     int, int);
27710893SQuaker.Fang@Sun.COM static void	iwp_reset_tx_ring(iwp_sc_t *, iwp_tx_ring_t *);
27810893SQuaker.Fang@Sun.COM static void	iwp_free_tx_ring(iwp_tx_ring_t *);
27910893SQuaker.Fang@Sun.COM static ieee80211_node_t *iwp_node_alloc(ieee80211com_t *);
28010893SQuaker.Fang@Sun.COM static void	iwp_node_free(ieee80211_node_t *);
28110893SQuaker.Fang@Sun.COM static int	iwp_newstate(ieee80211com_t *, enum ieee80211_state, int);
28210893SQuaker.Fang@Sun.COM static void	iwp_mac_access_enter(iwp_sc_t *);
28310893SQuaker.Fang@Sun.COM static void	iwp_mac_access_exit(iwp_sc_t *);
28410893SQuaker.Fang@Sun.COM static uint32_t	iwp_reg_read(iwp_sc_t *, uint32_t);
28510893SQuaker.Fang@Sun.COM static void	iwp_reg_write(iwp_sc_t *, uint32_t, uint32_t);
28610893SQuaker.Fang@Sun.COM static int	iwp_load_init_firmware(iwp_sc_t *);
28710893SQuaker.Fang@Sun.COM static int	iwp_load_run_firmware(iwp_sc_t *);
28810893SQuaker.Fang@Sun.COM static void	iwp_tx_intr(iwp_sc_t *, iwp_rx_desc_t *);
28910893SQuaker.Fang@Sun.COM static void	iwp_cmd_intr(iwp_sc_t *, iwp_rx_desc_t *);
29010893SQuaker.Fang@Sun.COM static uint_t   iwp_intr(caddr_t, caddr_t);
29110893SQuaker.Fang@Sun.COM static int	iwp_eep_load(iwp_sc_t *);
29210893SQuaker.Fang@Sun.COM static void	iwp_get_mac_from_eep(iwp_sc_t *);
29310893SQuaker.Fang@Sun.COM static int	iwp_eep_sem_down(iwp_sc_t *);
29410893SQuaker.Fang@Sun.COM static void	iwp_eep_sem_up(iwp_sc_t *);
29510893SQuaker.Fang@Sun.COM static uint_t   iwp_rx_softintr(caddr_t, caddr_t);
29610893SQuaker.Fang@Sun.COM static uint8_t	iwp_rate_to_plcp(int);
29710893SQuaker.Fang@Sun.COM static int	iwp_cmd(iwp_sc_t *, int, const void *, int, int);
29810893SQuaker.Fang@Sun.COM static void	iwp_set_led(iwp_sc_t *, uint8_t, uint8_t, uint8_t);
29910893SQuaker.Fang@Sun.COM static int	iwp_hw_set_before_auth(iwp_sc_t *);
30010893SQuaker.Fang@Sun.COM static int	iwp_scan(iwp_sc_t *);
30110893SQuaker.Fang@Sun.COM static int	iwp_config(iwp_sc_t *);
30210893SQuaker.Fang@Sun.COM static void	iwp_stop_master(iwp_sc_t *);
30310893SQuaker.Fang@Sun.COM static int	iwp_power_up(iwp_sc_t *);
30410893SQuaker.Fang@Sun.COM static int	iwp_preinit(iwp_sc_t *);
30510893SQuaker.Fang@Sun.COM static int	iwp_init(iwp_sc_t *);
30610893SQuaker.Fang@Sun.COM static void	iwp_stop(iwp_sc_t *);
30710893SQuaker.Fang@Sun.COM static int	iwp_quiesce(dev_info_t *t);
30810893SQuaker.Fang@Sun.COM static void	iwp_amrr_init(iwp_amrr_t *);
30910893SQuaker.Fang@Sun.COM static void	iwp_amrr_timeout(iwp_sc_t *);
31010893SQuaker.Fang@Sun.COM static void	iwp_amrr_ratectl(void *, ieee80211_node_t *);
31110893SQuaker.Fang@Sun.COM static void	iwp_ucode_alive(iwp_sc_t *, iwp_rx_desc_t *);
31210893SQuaker.Fang@Sun.COM static void	iwp_rx_phy_intr(iwp_sc_t *, iwp_rx_desc_t *);
31310893SQuaker.Fang@Sun.COM static void	iwp_rx_mpdu_intr(iwp_sc_t *, iwp_rx_desc_t *);
31410893SQuaker.Fang@Sun.COM static void	iwp_release_calib_buffer(iwp_sc_t *);
31510893SQuaker.Fang@Sun.COM static int	iwp_init_common(iwp_sc_t *);
31610893SQuaker.Fang@Sun.COM static uint8_t	*iwp_eep_addr_trans(iwp_sc_t *, uint32_t);
31710893SQuaker.Fang@Sun.COM static int	iwp_put_seg_fw(iwp_sc_t *, uint32_t, uint32_t, uint32_t);
31810893SQuaker.Fang@Sun.COM static	int	iwp_alive_common(iwp_sc_t *);
31910893SQuaker.Fang@Sun.COM static void	iwp_save_calib_result(iwp_sc_t *, iwp_rx_desc_t *);
32010893SQuaker.Fang@Sun.COM static int	iwp_attach(dev_info_t *, ddi_attach_cmd_t);
32110893SQuaker.Fang@Sun.COM static int	iwp_detach(dev_info_t *, ddi_detach_cmd_t);
32210893SQuaker.Fang@Sun.COM static void	iwp_destroy_locks(iwp_sc_t *);
32310893SQuaker.Fang@Sun.COM static int	iwp_send(ieee80211com_t *, mblk_t *, uint8_t);
32410893SQuaker.Fang@Sun.COM static void	iwp_thread(iwp_sc_t *);
32510893SQuaker.Fang@Sun.COM static int	iwp_run_state_config(iwp_sc_t *);
32610893SQuaker.Fang@Sun.COM static int	iwp_fast_recover(iwp_sc_t *);
32710893SQuaker.Fang@Sun.COM static void	iwp_overwrite_ic_default(iwp_sc_t *);
32810893SQuaker.Fang@Sun.COM static int	iwp_add_ap_sta(iwp_sc_t *);
32910893SQuaker.Fang@Sun.COM static int	iwp_alloc_dma_mem(iwp_sc_t *, size_t,
33010893SQuaker.Fang@Sun.COM     ddi_dma_attr_t *, ddi_device_acc_attr_t *,
33110893SQuaker.Fang@Sun.COM     uint_t, iwp_dma_t *);
33210893SQuaker.Fang@Sun.COM static void	iwp_free_dma_mem(iwp_dma_t *);
33310893SQuaker.Fang@Sun.COM static int	iwp_eep_ver_chk(iwp_sc_t *);
33410893SQuaker.Fang@Sun.COM static void	iwp_set_chip_param(iwp_sc_t *);
33510893SQuaker.Fang@Sun.COM 
33610893SQuaker.Fang@Sun.COM /*
33710893SQuaker.Fang@Sun.COM  * GLD specific operations
33810893SQuaker.Fang@Sun.COM  */
33910893SQuaker.Fang@Sun.COM static int	iwp_m_stat(void *, uint_t, uint64_t *);
34010893SQuaker.Fang@Sun.COM static int	iwp_m_start(void *);
34110893SQuaker.Fang@Sun.COM static void	iwp_m_stop(void *);
34210893SQuaker.Fang@Sun.COM static int	iwp_m_unicst(void *, const uint8_t *);
34310893SQuaker.Fang@Sun.COM static int	iwp_m_multicst(void *, boolean_t, const uint8_t *);
34410893SQuaker.Fang@Sun.COM static int	iwp_m_promisc(void *, boolean_t);
34510893SQuaker.Fang@Sun.COM static mblk_t	*iwp_m_tx(void *, mblk_t *);
34610893SQuaker.Fang@Sun.COM static void	iwp_m_ioctl(void *, queue_t *, mblk_t *);
34710893SQuaker.Fang@Sun.COM static int	iwp_m_setprop(void *arg, const char *pr_name,
34810893SQuaker.Fang@Sun.COM     mac_prop_id_t wldp_pr_num, uint_t wldp_length, const void *wldp_buf);
34910893SQuaker.Fang@Sun.COM static int	iwp_m_getprop(void *arg, const char *pr_name,
350*11878SVenu.Iyer@Sun.COM     mac_prop_id_t wldp_pr_num, uint_t wldp_length, void *wldp_buf);
351*11878SVenu.Iyer@Sun.COM static void	iwp_m_propinfo(void *, const char *, mac_prop_id_t,
352*11878SVenu.Iyer@Sun.COM     mac_prop_info_handle_t);
35310893SQuaker.Fang@Sun.COM 
35410893SQuaker.Fang@Sun.COM /*
35510893SQuaker.Fang@Sun.COM  * Supported rates for 802.11b/g modes (in 500Kbps unit).
35610893SQuaker.Fang@Sun.COM  */
35710893SQuaker.Fang@Sun.COM static const struct ieee80211_rateset iwp_rateset_11b =
35810893SQuaker.Fang@Sun.COM 	{ 4, { 2, 4, 11, 22 } };
35910893SQuaker.Fang@Sun.COM 
36010893SQuaker.Fang@Sun.COM static const struct ieee80211_rateset iwp_rateset_11g =
36110893SQuaker.Fang@Sun.COM 	{ 12, { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 } };
36210893SQuaker.Fang@Sun.COM 
36310893SQuaker.Fang@Sun.COM /*
36410893SQuaker.Fang@Sun.COM  * For mfthread only
36510893SQuaker.Fang@Sun.COM  */
36610893SQuaker.Fang@Sun.COM extern pri_t minclsyspri;
36710893SQuaker.Fang@Sun.COM 
36810893SQuaker.Fang@Sun.COM #define	DRV_NAME_SP	"iwp"
36910893SQuaker.Fang@Sun.COM 
37010893SQuaker.Fang@Sun.COM /*
37110893SQuaker.Fang@Sun.COM  * Module Loading Data & Entry Points
37210893SQuaker.Fang@Sun.COM  */
37310893SQuaker.Fang@Sun.COM DDI_DEFINE_STREAM_OPS(iwp_devops, nulldev, nulldev, iwp_attach,
37410893SQuaker.Fang@Sun.COM     iwp_detach, nodev, NULL, D_MP, NULL, iwp_quiesce);
37510893SQuaker.Fang@Sun.COM 
37610893SQuaker.Fang@Sun.COM static struct modldrv iwp_modldrv = {
37710893SQuaker.Fang@Sun.COM 	&mod_driverops,
37810893SQuaker.Fang@Sun.COM 	"Intel(R) PumaPeak driver(N)",
37910893SQuaker.Fang@Sun.COM 	&iwp_devops
38010893SQuaker.Fang@Sun.COM };
38110893SQuaker.Fang@Sun.COM 
38210893SQuaker.Fang@Sun.COM static struct modlinkage iwp_modlinkage = {
38310893SQuaker.Fang@Sun.COM 	MODREV_1,
38410893SQuaker.Fang@Sun.COM 	&iwp_modldrv,
38510893SQuaker.Fang@Sun.COM 	NULL
38610893SQuaker.Fang@Sun.COM };
38710893SQuaker.Fang@Sun.COM 
38810893SQuaker.Fang@Sun.COM int
_init(void)38910893SQuaker.Fang@Sun.COM _init(void)
39010893SQuaker.Fang@Sun.COM {
39110893SQuaker.Fang@Sun.COM 	int	status;
39210893SQuaker.Fang@Sun.COM 
39310893SQuaker.Fang@Sun.COM 	status = ddi_soft_state_init(&iwp_soft_state_p,
39410893SQuaker.Fang@Sun.COM 	    sizeof (iwp_sc_t), 1);
39510893SQuaker.Fang@Sun.COM 	if (status != DDI_SUCCESS) {
39610893SQuaker.Fang@Sun.COM 		return (status);
39710893SQuaker.Fang@Sun.COM 	}
39810893SQuaker.Fang@Sun.COM 
39910893SQuaker.Fang@Sun.COM 	mac_init_ops(&iwp_devops, DRV_NAME_SP);
40010893SQuaker.Fang@Sun.COM 	status = mod_install(&iwp_modlinkage);
40110893SQuaker.Fang@Sun.COM 	if (status != DDI_SUCCESS) {
40210893SQuaker.Fang@Sun.COM 		mac_fini_ops(&iwp_devops);
40310893SQuaker.Fang@Sun.COM 		ddi_soft_state_fini(&iwp_soft_state_p);
40410893SQuaker.Fang@Sun.COM 	}
40510893SQuaker.Fang@Sun.COM 
40610893SQuaker.Fang@Sun.COM 	return (status);
40710893SQuaker.Fang@Sun.COM }
40810893SQuaker.Fang@Sun.COM 
40910893SQuaker.Fang@Sun.COM int
_fini(void)41010893SQuaker.Fang@Sun.COM _fini(void)
41110893SQuaker.Fang@Sun.COM {
41210893SQuaker.Fang@Sun.COM 	int status;
41310893SQuaker.Fang@Sun.COM 
41410893SQuaker.Fang@Sun.COM 	status = mod_remove(&iwp_modlinkage);
41510893SQuaker.Fang@Sun.COM 	if (DDI_SUCCESS == status) {
41610893SQuaker.Fang@Sun.COM 		mac_fini_ops(&iwp_devops);
41710893SQuaker.Fang@Sun.COM 		ddi_soft_state_fini(&iwp_soft_state_p);
41810893SQuaker.Fang@Sun.COM 	}
41910893SQuaker.Fang@Sun.COM 
42010893SQuaker.Fang@Sun.COM 	return (status);
42110893SQuaker.Fang@Sun.COM }
42210893SQuaker.Fang@Sun.COM 
42310893SQuaker.Fang@Sun.COM int
_info(struct modinfo * mip)42410893SQuaker.Fang@Sun.COM _info(struct modinfo *mip)
42510893SQuaker.Fang@Sun.COM {
42610893SQuaker.Fang@Sun.COM 	return (mod_info(&iwp_modlinkage, mip));
42710893SQuaker.Fang@Sun.COM }
42810893SQuaker.Fang@Sun.COM 
42910893SQuaker.Fang@Sun.COM /*
43010893SQuaker.Fang@Sun.COM  * Mac Call Back entries
43110893SQuaker.Fang@Sun.COM  */
43210893SQuaker.Fang@Sun.COM mac_callbacks_t	iwp_m_callbacks = {
433*11878SVenu.Iyer@Sun.COM 	MC_IOCTL | MC_SETPROP | MC_GETPROP | MC_PROPINFO,
43410893SQuaker.Fang@Sun.COM 	iwp_m_stat,
43510893SQuaker.Fang@Sun.COM 	iwp_m_start,
43610893SQuaker.Fang@Sun.COM 	iwp_m_stop,
43710893SQuaker.Fang@Sun.COM 	iwp_m_promisc,
43810893SQuaker.Fang@Sun.COM 	iwp_m_multicst,
43910893SQuaker.Fang@Sun.COM 	iwp_m_unicst,
44010893SQuaker.Fang@Sun.COM 	iwp_m_tx,
441*11878SVenu.Iyer@Sun.COM 	NULL,
44210893SQuaker.Fang@Sun.COM 	iwp_m_ioctl,
44310893SQuaker.Fang@Sun.COM 	NULL,
44410893SQuaker.Fang@Sun.COM 	NULL,
44510893SQuaker.Fang@Sun.COM 	NULL,
44610893SQuaker.Fang@Sun.COM 	iwp_m_setprop,
447*11878SVenu.Iyer@Sun.COM 	iwp_m_getprop,
448*11878SVenu.Iyer@Sun.COM 	iwp_m_propinfo
44910893SQuaker.Fang@Sun.COM };
45010893SQuaker.Fang@Sun.COM 
45110893SQuaker.Fang@Sun.COM #ifdef DEBUG
45210893SQuaker.Fang@Sun.COM void
iwp_dbg(uint32_t flags,const char * fmt,...)45310893SQuaker.Fang@Sun.COM iwp_dbg(uint32_t flags, const char *fmt, ...)
45410893SQuaker.Fang@Sun.COM {
45510893SQuaker.Fang@Sun.COM 	va_list	ap;
45610893SQuaker.Fang@Sun.COM 
45710893SQuaker.Fang@Sun.COM 	if (flags & iwp_dbg_flags) {
45810893SQuaker.Fang@Sun.COM 		va_start(ap, fmt);
45910893SQuaker.Fang@Sun.COM 		vcmn_err(CE_NOTE, fmt, ap);
46010893SQuaker.Fang@Sun.COM 		va_end(ap);
46110893SQuaker.Fang@Sun.COM 	}
46210893SQuaker.Fang@Sun.COM }
46310893SQuaker.Fang@Sun.COM #endif	/* DEBUG */
46410893SQuaker.Fang@Sun.COM 
46510893SQuaker.Fang@Sun.COM /*
46610893SQuaker.Fang@Sun.COM  * device operations
46710893SQuaker.Fang@Sun.COM  */
46810893SQuaker.Fang@Sun.COM int
iwp_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)46910893SQuaker.Fang@Sun.COM iwp_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
47010893SQuaker.Fang@Sun.COM {
47110893SQuaker.Fang@Sun.COM 	iwp_sc_t		*sc;
47210893SQuaker.Fang@Sun.COM 	ieee80211com_t		*ic;
47310893SQuaker.Fang@Sun.COM 	int			instance, i;
47410893SQuaker.Fang@Sun.COM 	char			strbuf[32];
47510893SQuaker.Fang@Sun.COM 	wifi_data_t		wd = { 0 };
47610893SQuaker.Fang@Sun.COM 	mac_register_t		*macp;
47710893SQuaker.Fang@Sun.COM 	int			intr_type;
47810893SQuaker.Fang@Sun.COM 	int			intr_count;
47910893SQuaker.Fang@Sun.COM 	int			intr_actual;
48010893SQuaker.Fang@Sun.COM 	int			err = DDI_FAILURE;
48110893SQuaker.Fang@Sun.COM 
48210893SQuaker.Fang@Sun.COM 	switch (cmd) {
48310893SQuaker.Fang@Sun.COM 	case DDI_ATTACH:
48410893SQuaker.Fang@Sun.COM 		break;
48510893SQuaker.Fang@Sun.COM 	case DDI_RESUME:
48610893SQuaker.Fang@Sun.COM 		instance = ddi_get_instance(dip);
48710893SQuaker.Fang@Sun.COM 		sc = ddi_get_soft_state(iwp_soft_state_p,
48810893SQuaker.Fang@Sun.COM 		    instance);
48910893SQuaker.Fang@Sun.COM 		ASSERT(sc != NULL);
49010893SQuaker.Fang@Sun.COM 
49110893SQuaker.Fang@Sun.COM 		if (sc->sc_flags & IWP_F_RUNNING) {
49210893SQuaker.Fang@Sun.COM 			(void) iwp_init(sc);
49310893SQuaker.Fang@Sun.COM 		}
49410893SQuaker.Fang@Sun.COM 
49510893SQuaker.Fang@Sun.COM 		atomic_and_32(&sc->sc_flags, ~IWP_F_SUSPEND);
49610893SQuaker.Fang@Sun.COM 
49710893SQuaker.Fang@Sun.COM 		IWP_DBG((IWP_DEBUG_RESUME, "iwp_attach(): "
49810893SQuaker.Fang@Sun.COM 		    "resume\n"));
49910893SQuaker.Fang@Sun.COM 		return (DDI_SUCCESS);
50010893SQuaker.Fang@Sun.COM 	default:
50110893SQuaker.Fang@Sun.COM 		goto attach_fail1;
50210893SQuaker.Fang@Sun.COM 	}
50310893SQuaker.Fang@Sun.COM 
50410893SQuaker.Fang@Sun.COM 	instance = ddi_get_instance(dip);
50510893SQuaker.Fang@Sun.COM 	err = ddi_soft_state_zalloc(iwp_soft_state_p, instance);
50610893SQuaker.Fang@Sun.COM 	if (err != DDI_SUCCESS) {
50710893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_attach(): "
50810893SQuaker.Fang@Sun.COM 		    "failed to allocate soft state\n");
50910893SQuaker.Fang@Sun.COM 		goto attach_fail1;
51010893SQuaker.Fang@Sun.COM 	}
51110893SQuaker.Fang@Sun.COM 
51210893SQuaker.Fang@Sun.COM 	sc = ddi_get_soft_state(iwp_soft_state_p, instance);
51310893SQuaker.Fang@Sun.COM 	ASSERT(sc != NULL);
51410893SQuaker.Fang@Sun.COM 
51510893SQuaker.Fang@Sun.COM 	sc->sc_dip = dip;
51610893SQuaker.Fang@Sun.COM 
51710893SQuaker.Fang@Sun.COM 	/*
51810893SQuaker.Fang@Sun.COM 	 * map configure space
51910893SQuaker.Fang@Sun.COM 	 */
52010893SQuaker.Fang@Sun.COM 	err = ddi_regs_map_setup(dip, 0, &sc->sc_cfg_base, 0, 0,
52110893SQuaker.Fang@Sun.COM 	    &iwp_reg_accattr, &sc->sc_cfg_handle);
52210893SQuaker.Fang@Sun.COM 	if (err != DDI_SUCCESS) {
52310893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_attach(): "
52410893SQuaker.Fang@Sun.COM 		    "failed to map config spaces regs\n");
52510893SQuaker.Fang@Sun.COM 		goto attach_fail2;
52610893SQuaker.Fang@Sun.COM 	}
52710893SQuaker.Fang@Sun.COM 
52810893SQuaker.Fang@Sun.COM 	sc->sc_dev_id = ddi_get16(sc->sc_cfg_handle,
52910893SQuaker.Fang@Sun.COM 	    (uint16_t *)(sc->sc_cfg_base + PCI_CONF_DEVID));
53010893SQuaker.Fang@Sun.COM 	if ((sc->sc_dev_id != 0x422B) &&
53110893SQuaker.Fang@Sun.COM 	    (sc->sc_dev_id != 0x422C) &&
53210893SQuaker.Fang@Sun.COM 	    (sc->sc_dev_id != 0x4238) &&
53310893SQuaker.Fang@Sun.COM 	    (sc->sc_dev_id != 0x4239) &&
53410893SQuaker.Fang@Sun.COM 	    (sc->sc_dev_id != 0x008d) &&
53510893SQuaker.Fang@Sun.COM 	    (sc->sc_dev_id != 0x008e)) {
53610893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_attach(): "
53710893SQuaker.Fang@Sun.COM 		    "Do not support this device\n");
53810893SQuaker.Fang@Sun.COM 		goto attach_fail3;
53910893SQuaker.Fang@Sun.COM 	}
54010893SQuaker.Fang@Sun.COM 
54110893SQuaker.Fang@Sun.COM 	iwp_set_chip_param(sc);
54210893SQuaker.Fang@Sun.COM 
54310893SQuaker.Fang@Sun.COM 	sc->sc_rev = ddi_get8(sc->sc_cfg_handle,
54410893SQuaker.Fang@Sun.COM 	    (uint8_t *)(sc->sc_cfg_base + PCI_CONF_REVID));
54510893SQuaker.Fang@Sun.COM 
54610893SQuaker.Fang@Sun.COM 	/*
54710893SQuaker.Fang@Sun.COM 	 * keep from disturbing C3 state of CPU
54810893SQuaker.Fang@Sun.COM 	 */
54910893SQuaker.Fang@Sun.COM 	ddi_put8(sc->sc_cfg_handle, (uint8_t *)(sc->sc_cfg_base +
55010893SQuaker.Fang@Sun.COM 	    PCI_CFG_RETRY_TIMEOUT), 0);
55110893SQuaker.Fang@Sun.COM 
55210893SQuaker.Fang@Sun.COM 	/*
55310893SQuaker.Fang@Sun.COM 	 * determine the size of buffer for frame and command to ucode
55410893SQuaker.Fang@Sun.COM 	 */
55510893SQuaker.Fang@Sun.COM 	sc->sc_clsz = ddi_get16(sc->sc_cfg_handle,
55610893SQuaker.Fang@Sun.COM 	    (uint16_t *)(sc->sc_cfg_base + PCI_CONF_CACHE_LINESZ));
55710893SQuaker.Fang@Sun.COM 	if (!sc->sc_clsz) {
55810893SQuaker.Fang@Sun.COM 		sc->sc_clsz = 16;
55910893SQuaker.Fang@Sun.COM 	}
56010893SQuaker.Fang@Sun.COM 	sc->sc_clsz = (sc->sc_clsz << 2);
56110893SQuaker.Fang@Sun.COM 
56210893SQuaker.Fang@Sun.COM 	sc->sc_dmabuf_sz = roundup(0x1000 + sizeof (struct ieee80211_frame) +
56310893SQuaker.Fang@Sun.COM 	    IEEE80211_MTU + IEEE80211_CRC_LEN +
56410893SQuaker.Fang@Sun.COM 	    (IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN +
56510893SQuaker.Fang@Sun.COM 	    IEEE80211_WEP_CRCLEN), sc->sc_clsz);
56610893SQuaker.Fang@Sun.COM 
56710893SQuaker.Fang@Sun.COM 	/*
56810893SQuaker.Fang@Sun.COM 	 * Map operating registers
56910893SQuaker.Fang@Sun.COM 	 */
57010893SQuaker.Fang@Sun.COM 	err = ddi_regs_map_setup(dip, 1, &sc->sc_base,
57110893SQuaker.Fang@Sun.COM 	    0, 0, &iwp_reg_accattr, &sc->sc_handle);
57210893SQuaker.Fang@Sun.COM 	if (err != DDI_SUCCESS) {
57310893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_attach(): "
57410893SQuaker.Fang@Sun.COM 		    "failed to map device regs\n");
57510893SQuaker.Fang@Sun.COM 		goto attach_fail3;
57610893SQuaker.Fang@Sun.COM 	}
57710893SQuaker.Fang@Sun.COM 
57810893SQuaker.Fang@Sun.COM 	/*
57910893SQuaker.Fang@Sun.COM 	 * this is used to differentiate type of hardware
58010893SQuaker.Fang@Sun.COM 	 */
58110893SQuaker.Fang@Sun.COM 	sc->sc_hw_rev = IWP_READ(sc, CSR_HW_REV);
58210893SQuaker.Fang@Sun.COM 
58310893SQuaker.Fang@Sun.COM 	err = ddi_intr_get_supported_types(dip, &intr_type);
58410893SQuaker.Fang@Sun.COM 	if ((err != DDI_SUCCESS) || (!(intr_type & DDI_INTR_TYPE_FIXED))) {
58510893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_attach(): "
58610893SQuaker.Fang@Sun.COM 		    "fixed type interrupt is not supported\n");
58710893SQuaker.Fang@Sun.COM 		goto attach_fail4;
58810893SQuaker.Fang@Sun.COM 	}
58910893SQuaker.Fang@Sun.COM 
59010893SQuaker.Fang@Sun.COM 	err = ddi_intr_get_nintrs(dip, DDI_INTR_TYPE_FIXED, &intr_count);
59110893SQuaker.Fang@Sun.COM 	if ((err != DDI_SUCCESS) || (intr_count != 1)) {
59210893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_attach(): "
59310893SQuaker.Fang@Sun.COM 		    "no fixed interrupts\n");
59410893SQuaker.Fang@Sun.COM 		goto attach_fail4;
59510893SQuaker.Fang@Sun.COM 	}
59610893SQuaker.Fang@Sun.COM 
59710893SQuaker.Fang@Sun.COM 	sc->sc_intr_htable = kmem_zalloc(sizeof (ddi_intr_handle_t), KM_SLEEP);
59810893SQuaker.Fang@Sun.COM 
59910893SQuaker.Fang@Sun.COM 	err = ddi_intr_alloc(dip, sc->sc_intr_htable, DDI_INTR_TYPE_FIXED, 0,
60010893SQuaker.Fang@Sun.COM 	    intr_count, &intr_actual, 0);
60110893SQuaker.Fang@Sun.COM 	if ((err != DDI_SUCCESS) || (intr_actual != 1)) {
60210893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_attach(): "
60310893SQuaker.Fang@Sun.COM 		    "ddi_intr_alloc() failed 0x%x\n", err);
60410893SQuaker.Fang@Sun.COM 		goto attach_fail5;
60510893SQuaker.Fang@Sun.COM 	}
60610893SQuaker.Fang@Sun.COM 
60710893SQuaker.Fang@Sun.COM 	err = ddi_intr_get_pri(sc->sc_intr_htable[0], &sc->sc_intr_pri);
60810893SQuaker.Fang@Sun.COM 	if (err != DDI_SUCCESS) {
60910893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_attach(): "
61010893SQuaker.Fang@Sun.COM 		    "ddi_intr_get_pri() failed 0x%x\n", err);
61110893SQuaker.Fang@Sun.COM 		goto attach_fail6;
61210893SQuaker.Fang@Sun.COM 	}
61310893SQuaker.Fang@Sun.COM 
61410893SQuaker.Fang@Sun.COM 	mutex_init(&sc->sc_glock, NULL, MUTEX_DRIVER,
61510893SQuaker.Fang@Sun.COM 	    DDI_INTR_PRI(sc->sc_intr_pri));
61610893SQuaker.Fang@Sun.COM 	mutex_init(&sc->sc_tx_lock, NULL, MUTEX_DRIVER,
61710893SQuaker.Fang@Sun.COM 	    DDI_INTR_PRI(sc->sc_intr_pri));
61810893SQuaker.Fang@Sun.COM 	mutex_init(&sc->sc_mt_lock, NULL, MUTEX_DRIVER,
61910893SQuaker.Fang@Sun.COM 	    DDI_INTR_PRI(sc->sc_intr_pri));
62010893SQuaker.Fang@Sun.COM 
62110893SQuaker.Fang@Sun.COM 	cv_init(&sc->sc_cmd_cv, NULL, CV_DRIVER, NULL);
62210893SQuaker.Fang@Sun.COM 	cv_init(&sc->sc_put_seg_cv, NULL, CV_DRIVER, NULL);
62310893SQuaker.Fang@Sun.COM 	cv_init(&sc->sc_ucode_cv, NULL, CV_DRIVER, NULL);
62410893SQuaker.Fang@Sun.COM 
62510893SQuaker.Fang@Sun.COM 	/*
62610893SQuaker.Fang@Sun.COM 	 * initialize the mfthread
62710893SQuaker.Fang@Sun.COM 	 */
62810893SQuaker.Fang@Sun.COM 	cv_init(&sc->sc_mt_cv, NULL, CV_DRIVER, NULL);
62910893SQuaker.Fang@Sun.COM 	sc->sc_mf_thread = NULL;
63010893SQuaker.Fang@Sun.COM 	sc->sc_mf_thread_switch = 0;
63110893SQuaker.Fang@Sun.COM 
63210893SQuaker.Fang@Sun.COM 	/*
63310893SQuaker.Fang@Sun.COM 	 * Allocate shared buffer for communication between driver and ucode.
63410893SQuaker.Fang@Sun.COM 	 */
63510893SQuaker.Fang@Sun.COM 	err = iwp_alloc_shared(sc);
63610893SQuaker.Fang@Sun.COM 	if (err != DDI_SUCCESS) {
63710893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_attach(): "
63810893SQuaker.Fang@Sun.COM 		    "failed to allocate shared page\n");
63910893SQuaker.Fang@Sun.COM 		goto attach_fail7;
64010893SQuaker.Fang@Sun.COM 	}
64110893SQuaker.Fang@Sun.COM 
64210893SQuaker.Fang@Sun.COM 	(void) memset(sc->sc_shared, 0, sizeof (iwp_shared_t));
64310893SQuaker.Fang@Sun.COM 
64410893SQuaker.Fang@Sun.COM 	/*
64510893SQuaker.Fang@Sun.COM 	 * Allocate keep warm page.
64610893SQuaker.Fang@Sun.COM 	 */
64710893SQuaker.Fang@Sun.COM 	err = iwp_alloc_kw(sc);
64810893SQuaker.Fang@Sun.COM 	if (err != DDI_SUCCESS) {
64910893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_attach(): "
65010893SQuaker.Fang@Sun.COM 		    "failed to allocate keep warm page\n");
65110893SQuaker.Fang@Sun.COM 		goto attach_fail8;
65210893SQuaker.Fang@Sun.COM 	}
65310893SQuaker.Fang@Sun.COM 
65410893SQuaker.Fang@Sun.COM 	/*
65510893SQuaker.Fang@Sun.COM 	 * Do some necessary hardware initializations.
65610893SQuaker.Fang@Sun.COM 	 */
65710893SQuaker.Fang@Sun.COM 	err = iwp_preinit(sc);
65810893SQuaker.Fang@Sun.COM 	if (err != IWP_SUCCESS) {
65910893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_attach(): "
66010893SQuaker.Fang@Sun.COM 		    "failed to initialize hardware\n");
66110893SQuaker.Fang@Sun.COM 		goto attach_fail9;
66210893SQuaker.Fang@Sun.COM 	}
66310893SQuaker.Fang@Sun.COM 
66410893SQuaker.Fang@Sun.COM 	/*
66510893SQuaker.Fang@Sun.COM 	 * get hardware configurations from eeprom
66610893SQuaker.Fang@Sun.COM 	 */
66710893SQuaker.Fang@Sun.COM 	err = iwp_eep_load(sc);
66810893SQuaker.Fang@Sun.COM 	if (err != IWP_SUCCESS) {
66910893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_attach(): "
67010893SQuaker.Fang@Sun.COM 		    "failed to load eeprom\n");
67110893SQuaker.Fang@Sun.COM 		goto attach_fail9;
67210893SQuaker.Fang@Sun.COM 	}
67310893SQuaker.Fang@Sun.COM 
67410893SQuaker.Fang@Sun.COM 	/*
67510893SQuaker.Fang@Sun.COM 	 * calibration information from EEPROM
67610893SQuaker.Fang@Sun.COM 	 */
67710893SQuaker.Fang@Sun.COM 	sc->sc_eep_calib = (struct iwp_eep_calibration *)
67810893SQuaker.Fang@Sun.COM 	    iwp_eep_addr_trans(sc, EEP_CALIBRATION);
67910893SQuaker.Fang@Sun.COM 
68010893SQuaker.Fang@Sun.COM 	err = iwp_eep_ver_chk(sc);
68110893SQuaker.Fang@Sun.COM 	if (err != IWP_SUCCESS) {
68210893SQuaker.Fang@Sun.COM 		goto attach_fail9;
68310893SQuaker.Fang@Sun.COM 	}
68410893SQuaker.Fang@Sun.COM 
68510893SQuaker.Fang@Sun.COM 	/*
68610893SQuaker.Fang@Sun.COM 	 * get MAC address of this chipset
68710893SQuaker.Fang@Sun.COM 	 */
68810893SQuaker.Fang@Sun.COM 	iwp_get_mac_from_eep(sc);
68910893SQuaker.Fang@Sun.COM 
69010893SQuaker.Fang@Sun.COM 
69110893SQuaker.Fang@Sun.COM 	/*
69210893SQuaker.Fang@Sun.COM 	 * initialize TX and RX ring buffers
69310893SQuaker.Fang@Sun.COM 	 */
69410893SQuaker.Fang@Sun.COM 	err = iwp_ring_init(sc);
69510893SQuaker.Fang@Sun.COM 	if (err != DDI_SUCCESS) {
69610893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_attach(): "
69710893SQuaker.Fang@Sun.COM 		    "failed to allocate and initialize ring\n");
69810893SQuaker.Fang@Sun.COM 		goto attach_fail9;
69910893SQuaker.Fang@Sun.COM 	}
70010893SQuaker.Fang@Sun.COM 
70110893SQuaker.Fang@Sun.COM 	sc->sc_hdr = (iwp_firmware_hdr_t *)iwp_fw_bin;
70210893SQuaker.Fang@Sun.COM 
70310893SQuaker.Fang@Sun.COM 	/*
70410893SQuaker.Fang@Sun.COM 	 * copy ucode to dma buffer
70510893SQuaker.Fang@Sun.COM 	 */
70610893SQuaker.Fang@Sun.COM 	err = iwp_alloc_fw_dma(sc);
70710893SQuaker.Fang@Sun.COM 	if (err != DDI_SUCCESS) {
70810893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_attach(): "
70910893SQuaker.Fang@Sun.COM 		    "failed to allocate firmware dma\n");
71010893SQuaker.Fang@Sun.COM 		goto attach_fail10;
71110893SQuaker.Fang@Sun.COM 	}
71210893SQuaker.Fang@Sun.COM 
71310893SQuaker.Fang@Sun.COM 	/*
71410893SQuaker.Fang@Sun.COM 	 * Initialize the wifi part, which will be used by
71510893SQuaker.Fang@Sun.COM 	 * 802.11 module
71610893SQuaker.Fang@Sun.COM 	 */
71710893SQuaker.Fang@Sun.COM 	ic = &sc->sc_ic;
71810893SQuaker.Fang@Sun.COM 	ic->ic_phytype  = IEEE80211_T_OFDM;
71910893SQuaker.Fang@Sun.COM 	ic->ic_opmode   = IEEE80211_M_STA; /* default to BSS mode */
72010893SQuaker.Fang@Sun.COM 	ic->ic_state    = IEEE80211_S_INIT;
72110893SQuaker.Fang@Sun.COM 	ic->ic_maxrssi  = 100; /* experimental number */
72210893SQuaker.Fang@Sun.COM 	ic->ic_caps = IEEE80211_C_SHPREAMBLE | IEEE80211_C_TXPMGT |
72310893SQuaker.Fang@Sun.COM 	    IEEE80211_C_PMGT | IEEE80211_C_SHSLOT;
72410893SQuaker.Fang@Sun.COM 
72510893SQuaker.Fang@Sun.COM 	/*
72610893SQuaker.Fang@Sun.COM 	 * Support WPA/WPA2
72710893SQuaker.Fang@Sun.COM 	 */
72810893SQuaker.Fang@Sun.COM 	ic->ic_caps |= IEEE80211_C_WPA;
72910893SQuaker.Fang@Sun.COM 
73010893SQuaker.Fang@Sun.COM 	/*
73110893SQuaker.Fang@Sun.COM 	 * set supported .11b and .11g rates
73210893SQuaker.Fang@Sun.COM 	 */
73310893SQuaker.Fang@Sun.COM 	ic->ic_sup_rates[IEEE80211_MODE_11B] = iwp_rateset_11b;
73410893SQuaker.Fang@Sun.COM 	ic->ic_sup_rates[IEEE80211_MODE_11G] = iwp_rateset_11g;
73510893SQuaker.Fang@Sun.COM 
73610893SQuaker.Fang@Sun.COM 	/*
73710893SQuaker.Fang@Sun.COM 	 * set supported .11b and .11g channels (1 through 11)
73810893SQuaker.Fang@Sun.COM 	 */
73910893SQuaker.Fang@Sun.COM 	for (i = 1; i <= 11; i++) {
74010893SQuaker.Fang@Sun.COM 		ic->ic_sup_channels[i].ich_freq =
74110893SQuaker.Fang@Sun.COM 		    ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ);
74210893SQuaker.Fang@Sun.COM 		ic->ic_sup_channels[i].ich_flags =
74310893SQuaker.Fang@Sun.COM 		    IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM |
74410893SQuaker.Fang@Sun.COM 		    IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ |
74510893SQuaker.Fang@Sun.COM 		    IEEE80211_CHAN_PASSIVE;
74610893SQuaker.Fang@Sun.COM 	}
74710893SQuaker.Fang@Sun.COM 
74810893SQuaker.Fang@Sun.COM 	ic->ic_ibss_chan = &ic->ic_sup_channels[0];
74910893SQuaker.Fang@Sun.COM 	ic->ic_xmit = iwp_send;
75010893SQuaker.Fang@Sun.COM 
75110893SQuaker.Fang@Sun.COM 	/*
75210893SQuaker.Fang@Sun.COM 	 * attach to 802.11 module
75310893SQuaker.Fang@Sun.COM 	 */
75410893SQuaker.Fang@Sun.COM 	ieee80211_attach(ic);
75510893SQuaker.Fang@Sun.COM 
75610893SQuaker.Fang@Sun.COM 	/*
75710893SQuaker.Fang@Sun.COM 	 * different instance has different WPA door
75810893SQuaker.Fang@Sun.COM 	 */
75910893SQuaker.Fang@Sun.COM 	(void) snprintf(ic->ic_wpadoor, MAX_IEEE80211STR, "%s_%s%d", WPA_DOOR,
76010893SQuaker.Fang@Sun.COM 	    ddi_driver_name(dip),
76110893SQuaker.Fang@Sun.COM 	    ddi_get_instance(dip));
76210893SQuaker.Fang@Sun.COM 
76310893SQuaker.Fang@Sun.COM 	/*
76410893SQuaker.Fang@Sun.COM 	 * Overwrite 80211 default configurations.
76510893SQuaker.Fang@Sun.COM 	 */
76610893SQuaker.Fang@Sun.COM 	iwp_overwrite_ic_default(sc);
76710893SQuaker.Fang@Sun.COM 
76810893SQuaker.Fang@Sun.COM 	/*
76910893SQuaker.Fang@Sun.COM 	 * initialize 802.11 module
77010893SQuaker.Fang@Sun.COM 	 */
77110893SQuaker.Fang@Sun.COM 	ieee80211_media_init(ic);
77210893SQuaker.Fang@Sun.COM 
77310893SQuaker.Fang@Sun.COM 	/*
77410893SQuaker.Fang@Sun.COM 	 * initialize default tx key
77510893SQuaker.Fang@Sun.COM 	 */
77610893SQuaker.Fang@Sun.COM 	ic->ic_def_txkey = 0;
77710893SQuaker.Fang@Sun.COM 
77810893SQuaker.Fang@Sun.COM 	err = ddi_intr_add_softint(dip, &sc->sc_soft_hdl, DDI_INTR_SOFTPRI_MAX,
77910893SQuaker.Fang@Sun.COM 	    iwp_rx_softintr, (caddr_t)sc);
78010893SQuaker.Fang@Sun.COM 	if (err != DDI_SUCCESS) {
78110893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_attach(): "
78210893SQuaker.Fang@Sun.COM 		    "add soft interrupt failed\n");
78310893SQuaker.Fang@Sun.COM 		goto attach_fail12;
78410893SQuaker.Fang@Sun.COM 	}
78510893SQuaker.Fang@Sun.COM 
78610893SQuaker.Fang@Sun.COM 	err = ddi_intr_add_handler(sc->sc_intr_htable[0], iwp_intr,
78710893SQuaker.Fang@Sun.COM 	    (caddr_t)sc, NULL);
78810893SQuaker.Fang@Sun.COM 	if (err != DDI_SUCCESS) {
78910893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_attach(): "
79010893SQuaker.Fang@Sun.COM 		    "ddi_intr_add_handle() failed\n");
79110893SQuaker.Fang@Sun.COM 		goto attach_fail13;
79210893SQuaker.Fang@Sun.COM 	}
79310893SQuaker.Fang@Sun.COM 
79410893SQuaker.Fang@Sun.COM 	err = ddi_intr_enable(sc->sc_intr_htable[0]);
79510893SQuaker.Fang@Sun.COM 	if (err != DDI_SUCCESS) {
79610893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_attach(): "
79710893SQuaker.Fang@Sun.COM 		    "ddi_intr_enable() failed\n");
79810893SQuaker.Fang@Sun.COM 		goto attach_fail14;
79910893SQuaker.Fang@Sun.COM 	}
80010893SQuaker.Fang@Sun.COM 
80110893SQuaker.Fang@Sun.COM 	/*
80210893SQuaker.Fang@Sun.COM 	 * Initialize pointer to device specific functions
80310893SQuaker.Fang@Sun.COM 	 */
80410893SQuaker.Fang@Sun.COM 	wd.wd_secalloc = WIFI_SEC_NONE;
80510893SQuaker.Fang@Sun.COM 	wd.wd_opmode = ic->ic_opmode;
80610893SQuaker.Fang@Sun.COM 	IEEE80211_ADDR_COPY(wd.wd_bssid, ic->ic_macaddr);
80710893SQuaker.Fang@Sun.COM 
80810893SQuaker.Fang@Sun.COM 	/*
80910893SQuaker.Fang@Sun.COM 	 * create relation to GLD
81010893SQuaker.Fang@Sun.COM 	 */
81110893SQuaker.Fang@Sun.COM 	macp = mac_alloc(MAC_VERSION);
81210893SQuaker.Fang@Sun.COM 	if (NULL == macp) {
81310893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_attach(): "
81410893SQuaker.Fang@Sun.COM 		    "failed to do mac_alloc()\n");
81510893SQuaker.Fang@Sun.COM 		goto attach_fail15;
81610893SQuaker.Fang@Sun.COM 	}
81710893SQuaker.Fang@Sun.COM 
81810893SQuaker.Fang@Sun.COM 	macp->m_type_ident	= MAC_PLUGIN_IDENT_WIFI;
81910893SQuaker.Fang@Sun.COM 	macp->m_driver		= sc;
82010893SQuaker.Fang@Sun.COM 	macp->m_dip		= dip;
82110893SQuaker.Fang@Sun.COM 	macp->m_src_addr	= ic->ic_macaddr;
82210893SQuaker.Fang@Sun.COM 	macp->m_callbacks	= &iwp_m_callbacks;
82310893SQuaker.Fang@Sun.COM 	macp->m_min_sdu		= 0;
82410893SQuaker.Fang@Sun.COM 	macp->m_max_sdu		= IEEE80211_MTU;
82510893SQuaker.Fang@Sun.COM 	macp->m_pdata		= &wd;
82610893SQuaker.Fang@Sun.COM 	macp->m_pdata_size	= sizeof (wd);
82710893SQuaker.Fang@Sun.COM 
82810893SQuaker.Fang@Sun.COM 	/*
82910893SQuaker.Fang@Sun.COM 	 * Register the macp to mac
83010893SQuaker.Fang@Sun.COM 	 */
83110893SQuaker.Fang@Sun.COM 	err = mac_register(macp, &ic->ic_mach);
83210893SQuaker.Fang@Sun.COM 	mac_free(macp);
83310893SQuaker.Fang@Sun.COM 	if (err != DDI_SUCCESS) {
83410893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_attach(): "
83510893SQuaker.Fang@Sun.COM 		    "failed to do mac_register()\n");
83610893SQuaker.Fang@Sun.COM 		goto attach_fail15;
83710893SQuaker.Fang@Sun.COM 	}
83810893SQuaker.Fang@Sun.COM 
83910893SQuaker.Fang@Sun.COM 	/*
84010893SQuaker.Fang@Sun.COM 	 * Create minor node of type DDI_NT_NET_WIFI
84110893SQuaker.Fang@Sun.COM 	 */
84210893SQuaker.Fang@Sun.COM 	(void) snprintf(strbuf, sizeof (strbuf), DRV_NAME_SP"%d", instance);
84310893SQuaker.Fang@Sun.COM 	err = ddi_create_minor_node(dip, strbuf, S_IFCHR,
84410893SQuaker.Fang@Sun.COM 	    instance + 1, DDI_NT_NET_WIFI, 0);
84510893SQuaker.Fang@Sun.COM 	if (err != DDI_SUCCESS) {
84610893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_attach(): "
84710893SQuaker.Fang@Sun.COM 		    "failed to do ddi_create_minor_node()\n");
84810893SQuaker.Fang@Sun.COM 	}
84910893SQuaker.Fang@Sun.COM 
85010893SQuaker.Fang@Sun.COM 	/*
85110893SQuaker.Fang@Sun.COM 	 * Notify link is down now
85210893SQuaker.Fang@Sun.COM 	 */
85310893SQuaker.Fang@Sun.COM 	mac_link_update(ic->ic_mach, LINK_STATE_DOWN);
85410893SQuaker.Fang@Sun.COM 
85510893SQuaker.Fang@Sun.COM 	/*
85610893SQuaker.Fang@Sun.COM 	 * create the mf thread to handle the link status,
85710893SQuaker.Fang@Sun.COM 	 * recovery fatal error, etc.
85810893SQuaker.Fang@Sun.COM 	 */
85910893SQuaker.Fang@Sun.COM 	sc->sc_mf_thread_switch = 1;
86010893SQuaker.Fang@Sun.COM 	if (NULL == sc->sc_mf_thread) {
86110893SQuaker.Fang@Sun.COM 		sc->sc_mf_thread = thread_create((caddr_t)NULL, 0,
86210893SQuaker.Fang@Sun.COM 		    iwp_thread, sc, 0, &p0, TS_RUN, minclsyspri);
86310893SQuaker.Fang@Sun.COM 	}
86410893SQuaker.Fang@Sun.COM 
86510893SQuaker.Fang@Sun.COM 	atomic_or_32(&sc->sc_flags, IWP_F_ATTACHED);
86610893SQuaker.Fang@Sun.COM 
86710893SQuaker.Fang@Sun.COM 	return (DDI_SUCCESS);
86810893SQuaker.Fang@Sun.COM 
86910893SQuaker.Fang@Sun.COM attach_fail15:
87010893SQuaker.Fang@Sun.COM 	(void) ddi_intr_disable(sc->sc_intr_htable[0]);
87110893SQuaker.Fang@Sun.COM attach_fail14:
87210893SQuaker.Fang@Sun.COM 	(void) ddi_intr_remove_handler(sc->sc_intr_htable[0]);
87310893SQuaker.Fang@Sun.COM attach_fail13:
87410893SQuaker.Fang@Sun.COM 	(void) ddi_intr_remove_softint(sc->sc_soft_hdl);
87510893SQuaker.Fang@Sun.COM 	sc->sc_soft_hdl = NULL;
87610893SQuaker.Fang@Sun.COM attach_fail12:
87710893SQuaker.Fang@Sun.COM 	ieee80211_detach(ic);
87810893SQuaker.Fang@Sun.COM attach_fail11:
87910893SQuaker.Fang@Sun.COM 	iwp_free_fw_dma(sc);
88010893SQuaker.Fang@Sun.COM attach_fail10:
88110893SQuaker.Fang@Sun.COM 	iwp_ring_free(sc);
88210893SQuaker.Fang@Sun.COM attach_fail9:
88310893SQuaker.Fang@Sun.COM 	iwp_free_kw(sc);
88410893SQuaker.Fang@Sun.COM attach_fail8:
88510893SQuaker.Fang@Sun.COM 	iwp_free_shared(sc);
88610893SQuaker.Fang@Sun.COM attach_fail7:
88710893SQuaker.Fang@Sun.COM 	iwp_destroy_locks(sc);
88810893SQuaker.Fang@Sun.COM attach_fail6:
88910893SQuaker.Fang@Sun.COM 	(void) ddi_intr_free(sc->sc_intr_htable[0]);
89010893SQuaker.Fang@Sun.COM attach_fail5:
89110893SQuaker.Fang@Sun.COM 	kmem_free(sc->sc_intr_htable, sizeof (ddi_intr_handle_t));
89210893SQuaker.Fang@Sun.COM attach_fail4:
89310893SQuaker.Fang@Sun.COM 	ddi_regs_map_free(&sc->sc_handle);
89410893SQuaker.Fang@Sun.COM attach_fail3:
89510893SQuaker.Fang@Sun.COM 	ddi_regs_map_free(&sc->sc_cfg_handle);
89610893SQuaker.Fang@Sun.COM attach_fail2:
89710893SQuaker.Fang@Sun.COM 	ddi_soft_state_free(iwp_soft_state_p, instance);
89810893SQuaker.Fang@Sun.COM attach_fail1:
89910893SQuaker.Fang@Sun.COM 	return (DDI_FAILURE);
90010893SQuaker.Fang@Sun.COM }
90110893SQuaker.Fang@Sun.COM 
90210893SQuaker.Fang@Sun.COM int
iwp_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)90310893SQuaker.Fang@Sun.COM iwp_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
90410893SQuaker.Fang@Sun.COM {
90510893SQuaker.Fang@Sun.COM 	iwp_sc_t *sc;
90610893SQuaker.Fang@Sun.COM 	ieee80211com_t	*ic;
90710893SQuaker.Fang@Sun.COM 	int err;
90810893SQuaker.Fang@Sun.COM 
90910893SQuaker.Fang@Sun.COM 	sc = ddi_get_soft_state(iwp_soft_state_p, ddi_get_instance(dip));
91010893SQuaker.Fang@Sun.COM 	ASSERT(sc != NULL);
91110893SQuaker.Fang@Sun.COM 	ic = &sc->sc_ic;
91210893SQuaker.Fang@Sun.COM 
91310893SQuaker.Fang@Sun.COM 	switch (cmd) {
91410893SQuaker.Fang@Sun.COM 	case DDI_DETACH:
91510893SQuaker.Fang@Sun.COM 		break;
91610893SQuaker.Fang@Sun.COM 	case DDI_SUSPEND:
91710893SQuaker.Fang@Sun.COM 		atomic_and_32(&sc->sc_flags, ~IWP_F_HW_ERR_RECOVER);
91810893SQuaker.Fang@Sun.COM 		atomic_and_32(&sc->sc_flags, ~IWP_F_RATE_AUTO_CTL);
91910893SQuaker.Fang@Sun.COM 
92010893SQuaker.Fang@Sun.COM 		atomic_or_32(&sc->sc_flags, IWP_F_SUSPEND);
92110893SQuaker.Fang@Sun.COM 
92210893SQuaker.Fang@Sun.COM 		if (sc->sc_flags & IWP_F_RUNNING) {
92310893SQuaker.Fang@Sun.COM 			iwp_stop(sc);
92410893SQuaker.Fang@Sun.COM 			ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
92510893SQuaker.Fang@Sun.COM 
92610893SQuaker.Fang@Sun.COM 		}
92710893SQuaker.Fang@Sun.COM 
92810893SQuaker.Fang@Sun.COM 		IWP_DBG((IWP_DEBUG_RESUME, "iwp_detach(): "
92910893SQuaker.Fang@Sun.COM 		    "suspend\n"));
93010893SQuaker.Fang@Sun.COM 		return (DDI_SUCCESS);
93110893SQuaker.Fang@Sun.COM 	default:
93210893SQuaker.Fang@Sun.COM 		return (DDI_FAILURE);
93310893SQuaker.Fang@Sun.COM 	}
93410893SQuaker.Fang@Sun.COM 
93510893SQuaker.Fang@Sun.COM 	if (!(sc->sc_flags & IWP_F_ATTACHED)) {
93610893SQuaker.Fang@Sun.COM 		return (DDI_FAILURE);
93710893SQuaker.Fang@Sun.COM 	}
93810893SQuaker.Fang@Sun.COM 
93910893SQuaker.Fang@Sun.COM 	/*
94010893SQuaker.Fang@Sun.COM 	 * Destroy the mf_thread
94110893SQuaker.Fang@Sun.COM 	 */
94210893SQuaker.Fang@Sun.COM 	sc->sc_mf_thread_switch = 0;
94310893SQuaker.Fang@Sun.COM 
94410893SQuaker.Fang@Sun.COM 	mutex_enter(&sc->sc_mt_lock);
94510893SQuaker.Fang@Sun.COM 	while (sc->sc_mf_thread != NULL) {
94610893SQuaker.Fang@Sun.COM 		if (cv_wait_sig(&sc->sc_mt_cv, &sc->sc_mt_lock) == 0) {
94710893SQuaker.Fang@Sun.COM 			break;
94810893SQuaker.Fang@Sun.COM 		}
94910893SQuaker.Fang@Sun.COM 	}
95010893SQuaker.Fang@Sun.COM 	mutex_exit(&sc->sc_mt_lock);
95110893SQuaker.Fang@Sun.COM 
95210893SQuaker.Fang@Sun.COM 	err = mac_disable(sc->sc_ic.ic_mach);
95310893SQuaker.Fang@Sun.COM 	if (err != DDI_SUCCESS) {
95410893SQuaker.Fang@Sun.COM 		return (err);
95510893SQuaker.Fang@Sun.COM 	}
95610893SQuaker.Fang@Sun.COM 
95710893SQuaker.Fang@Sun.COM 	/*
95810893SQuaker.Fang@Sun.COM 	 * stop chipset
95910893SQuaker.Fang@Sun.COM 	 */
96010893SQuaker.Fang@Sun.COM 	iwp_stop(sc);
96110893SQuaker.Fang@Sun.COM 
96210893SQuaker.Fang@Sun.COM 	DELAY(500000);
96310893SQuaker.Fang@Sun.COM 
96410893SQuaker.Fang@Sun.COM 	/*
96510893SQuaker.Fang@Sun.COM 	 * release buffer for calibration
96610893SQuaker.Fang@Sun.COM 	 */
96710893SQuaker.Fang@Sun.COM 	iwp_release_calib_buffer(sc);
96810893SQuaker.Fang@Sun.COM 
96910893SQuaker.Fang@Sun.COM 	/*
97010893SQuaker.Fang@Sun.COM 	 * Unregiste from GLD
97110893SQuaker.Fang@Sun.COM 	 */
97210893SQuaker.Fang@Sun.COM 	(void) mac_unregister(sc->sc_ic.ic_mach);
97310893SQuaker.Fang@Sun.COM 
97410893SQuaker.Fang@Sun.COM 	mutex_enter(&sc->sc_glock);
97510893SQuaker.Fang@Sun.COM 	iwp_free_fw_dma(sc);
97610893SQuaker.Fang@Sun.COM 	iwp_ring_free(sc);
97710893SQuaker.Fang@Sun.COM 	iwp_free_kw(sc);
97810893SQuaker.Fang@Sun.COM 	iwp_free_shared(sc);
97910893SQuaker.Fang@Sun.COM 	mutex_exit(&sc->sc_glock);
98010893SQuaker.Fang@Sun.COM 
98110893SQuaker.Fang@Sun.COM 	(void) ddi_intr_disable(sc->sc_intr_htable[0]);
98210893SQuaker.Fang@Sun.COM 	(void) ddi_intr_remove_handler(sc->sc_intr_htable[0]);
98310893SQuaker.Fang@Sun.COM 	(void) ddi_intr_free(sc->sc_intr_htable[0]);
98410893SQuaker.Fang@Sun.COM 	kmem_free(sc->sc_intr_htable, sizeof (ddi_intr_handle_t));
98510893SQuaker.Fang@Sun.COM 
98610893SQuaker.Fang@Sun.COM 	(void) ddi_intr_remove_softint(sc->sc_soft_hdl);
98710893SQuaker.Fang@Sun.COM 	sc->sc_soft_hdl = NULL;
98810893SQuaker.Fang@Sun.COM 
98910893SQuaker.Fang@Sun.COM 	/*
99010893SQuaker.Fang@Sun.COM 	 * detach from 80211 module
99110893SQuaker.Fang@Sun.COM 	 */
99210893SQuaker.Fang@Sun.COM 	ieee80211_detach(&sc->sc_ic);
99310893SQuaker.Fang@Sun.COM 
99410893SQuaker.Fang@Sun.COM 	iwp_destroy_locks(sc);
99510893SQuaker.Fang@Sun.COM 
99610893SQuaker.Fang@Sun.COM 	ddi_regs_map_free(&sc->sc_handle);
99710893SQuaker.Fang@Sun.COM 	ddi_regs_map_free(&sc->sc_cfg_handle);
99810893SQuaker.Fang@Sun.COM 	ddi_remove_minor_node(dip, NULL);
99910893SQuaker.Fang@Sun.COM 	ddi_soft_state_free(iwp_soft_state_p, ddi_get_instance(dip));
100010893SQuaker.Fang@Sun.COM 
100110893SQuaker.Fang@Sun.COM 	return (DDI_SUCCESS);
100210893SQuaker.Fang@Sun.COM }
100310893SQuaker.Fang@Sun.COM 
100410893SQuaker.Fang@Sun.COM /*
100510893SQuaker.Fang@Sun.COM  * destroy all locks
100610893SQuaker.Fang@Sun.COM  */
100710893SQuaker.Fang@Sun.COM static void
iwp_destroy_locks(iwp_sc_t * sc)100810893SQuaker.Fang@Sun.COM iwp_destroy_locks(iwp_sc_t *sc)
100910893SQuaker.Fang@Sun.COM {
101010893SQuaker.Fang@Sun.COM 	cv_destroy(&sc->sc_mt_cv);
101110893SQuaker.Fang@Sun.COM 	cv_destroy(&sc->sc_cmd_cv);
101210893SQuaker.Fang@Sun.COM 	cv_destroy(&sc->sc_put_seg_cv);
101310893SQuaker.Fang@Sun.COM 	cv_destroy(&sc->sc_ucode_cv);
101410893SQuaker.Fang@Sun.COM 	mutex_destroy(&sc->sc_mt_lock);
101510893SQuaker.Fang@Sun.COM 	mutex_destroy(&sc->sc_tx_lock);
101610893SQuaker.Fang@Sun.COM 	mutex_destroy(&sc->sc_glock);
101710893SQuaker.Fang@Sun.COM }
101810893SQuaker.Fang@Sun.COM 
101910893SQuaker.Fang@Sun.COM /*
102010893SQuaker.Fang@Sun.COM  * Allocate an area of memory and a DMA handle for accessing it
102110893SQuaker.Fang@Sun.COM  */
102210893SQuaker.Fang@Sun.COM static int
iwp_alloc_dma_mem(iwp_sc_t * sc,size_t memsize,ddi_dma_attr_t * dma_attr_p,ddi_device_acc_attr_t * acc_attr_p,uint_t dma_flags,iwp_dma_t * dma_p)102310893SQuaker.Fang@Sun.COM iwp_alloc_dma_mem(iwp_sc_t *sc, size_t memsize,
102410893SQuaker.Fang@Sun.COM     ddi_dma_attr_t *dma_attr_p, ddi_device_acc_attr_t *acc_attr_p,
102510893SQuaker.Fang@Sun.COM     uint_t dma_flags, iwp_dma_t *dma_p)
102610893SQuaker.Fang@Sun.COM {
102710893SQuaker.Fang@Sun.COM 	caddr_t vaddr;
102810893SQuaker.Fang@Sun.COM 	int err = DDI_FAILURE;
102910893SQuaker.Fang@Sun.COM 
103010893SQuaker.Fang@Sun.COM 	/*
103110893SQuaker.Fang@Sun.COM 	 * Allocate handle
103210893SQuaker.Fang@Sun.COM 	 */
103310893SQuaker.Fang@Sun.COM 	err = ddi_dma_alloc_handle(sc->sc_dip, dma_attr_p,
103410893SQuaker.Fang@Sun.COM 	    DDI_DMA_SLEEP, NULL, &dma_p->dma_hdl);
103510893SQuaker.Fang@Sun.COM 	if (err != DDI_SUCCESS) {
103610893SQuaker.Fang@Sun.COM 		dma_p->dma_hdl = NULL;
103710893SQuaker.Fang@Sun.COM 		return (DDI_FAILURE);
103810893SQuaker.Fang@Sun.COM 	}
103910893SQuaker.Fang@Sun.COM 
104010893SQuaker.Fang@Sun.COM 	/*
104110893SQuaker.Fang@Sun.COM 	 * Allocate memory
104210893SQuaker.Fang@Sun.COM 	 */
104310893SQuaker.Fang@Sun.COM 	err = ddi_dma_mem_alloc(dma_p->dma_hdl, memsize, acc_attr_p,
104410893SQuaker.Fang@Sun.COM 	    dma_flags & (DDI_DMA_CONSISTENT | DDI_DMA_STREAMING),
104510893SQuaker.Fang@Sun.COM 	    DDI_DMA_SLEEP, NULL, &vaddr, &dma_p->alength, &dma_p->acc_hdl);
104610893SQuaker.Fang@Sun.COM 	if (err != DDI_SUCCESS) {
104710893SQuaker.Fang@Sun.COM 		ddi_dma_free_handle(&dma_p->dma_hdl);
104810893SQuaker.Fang@Sun.COM 		dma_p->dma_hdl = NULL;
104910893SQuaker.Fang@Sun.COM 		dma_p->acc_hdl = NULL;
105010893SQuaker.Fang@Sun.COM 		return (DDI_FAILURE);
105110893SQuaker.Fang@Sun.COM 	}
105210893SQuaker.Fang@Sun.COM 
105310893SQuaker.Fang@Sun.COM 	/*
105410893SQuaker.Fang@Sun.COM 	 * Bind the two together
105510893SQuaker.Fang@Sun.COM 	 */
105610893SQuaker.Fang@Sun.COM 	dma_p->mem_va = vaddr;
105710893SQuaker.Fang@Sun.COM 	err = ddi_dma_addr_bind_handle(dma_p->dma_hdl, NULL,
105810893SQuaker.Fang@Sun.COM 	    vaddr, dma_p->alength, dma_flags, DDI_DMA_SLEEP, NULL,
105910893SQuaker.Fang@Sun.COM 	    &dma_p->cookie, &dma_p->ncookies);
106010893SQuaker.Fang@Sun.COM 	if (err != DDI_DMA_MAPPED) {
106110893SQuaker.Fang@Sun.COM 		ddi_dma_mem_free(&dma_p->acc_hdl);
106210893SQuaker.Fang@Sun.COM 		ddi_dma_free_handle(&dma_p->dma_hdl);
106310893SQuaker.Fang@Sun.COM 		dma_p->acc_hdl = NULL;
106410893SQuaker.Fang@Sun.COM 		dma_p->dma_hdl = NULL;
106510893SQuaker.Fang@Sun.COM 		return (DDI_FAILURE);
106610893SQuaker.Fang@Sun.COM 	}
106710893SQuaker.Fang@Sun.COM 
106810893SQuaker.Fang@Sun.COM 	dma_p->nslots = ~0U;
106910893SQuaker.Fang@Sun.COM 	dma_p->size = ~0U;
107010893SQuaker.Fang@Sun.COM 	dma_p->token = ~0U;
107110893SQuaker.Fang@Sun.COM 	dma_p->offset = 0;
107210893SQuaker.Fang@Sun.COM 	return (DDI_SUCCESS);
107310893SQuaker.Fang@Sun.COM }
107410893SQuaker.Fang@Sun.COM 
107510893SQuaker.Fang@Sun.COM /*
107610893SQuaker.Fang@Sun.COM  * Free one allocated area of DMAable memory
107710893SQuaker.Fang@Sun.COM  */
107810893SQuaker.Fang@Sun.COM static void
iwp_free_dma_mem(iwp_dma_t * dma_p)107910893SQuaker.Fang@Sun.COM iwp_free_dma_mem(iwp_dma_t *dma_p)
108010893SQuaker.Fang@Sun.COM {
108110893SQuaker.Fang@Sun.COM 	if (dma_p->dma_hdl != NULL) {
108210893SQuaker.Fang@Sun.COM 		if (dma_p->ncookies) {
108310893SQuaker.Fang@Sun.COM 			(void) ddi_dma_unbind_handle(dma_p->dma_hdl);
108410893SQuaker.Fang@Sun.COM 			dma_p->ncookies = 0;
108510893SQuaker.Fang@Sun.COM 		}
108610893SQuaker.Fang@Sun.COM 		ddi_dma_free_handle(&dma_p->dma_hdl);
108710893SQuaker.Fang@Sun.COM 		dma_p->dma_hdl = NULL;
108810893SQuaker.Fang@Sun.COM 	}
108910893SQuaker.Fang@Sun.COM 
109010893SQuaker.Fang@Sun.COM 	if (dma_p->acc_hdl != NULL) {
109110893SQuaker.Fang@Sun.COM 		ddi_dma_mem_free(&dma_p->acc_hdl);
109210893SQuaker.Fang@Sun.COM 		dma_p->acc_hdl = NULL;
109310893SQuaker.Fang@Sun.COM 	}
109410893SQuaker.Fang@Sun.COM }
109510893SQuaker.Fang@Sun.COM 
109610893SQuaker.Fang@Sun.COM /*
109710893SQuaker.Fang@Sun.COM  * copy ucode into dma buffers
109810893SQuaker.Fang@Sun.COM  */
109910893SQuaker.Fang@Sun.COM static int
iwp_alloc_fw_dma(iwp_sc_t * sc)110010893SQuaker.Fang@Sun.COM iwp_alloc_fw_dma(iwp_sc_t *sc)
110110893SQuaker.Fang@Sun.COM {
110210893SQuaker.Fang@Sun.COM 	int err = DDI_FAILURE;
110310893SQuaker.Fang@Sun.COM 	iwp_dma_t *dma_p;
110410893SQuaker.Fang@Sun.COM 	char *t;
110510893SQuaker.Fang@Sun.COM 
110610893SQuaker.Fang@Sun.COM 	/*
110710893SQuaker.Fang@Sun.COM 	 * firmware image layout:
110810893SQuaker.Fang@Sun.COM 	 * |HDR|<-TEXT->|<-DATA->|<-INIT_TEXT->|<-INIT_DATA->|<-BOOT->|
110910893SQuaker.Fang@Sun.COM 	 */
111010893SQuaker.Fang@Sun.COM 
111110893SQuaker.Fang@Sun.COM 	/*
111210893SQuaker.Fang@Sun.COM 	 * Check firmware image size.
111310893SQuaker.Fang@Sun.COM 	 */
111410893SQuaker.Fang@Sun.COM 	if (LE_32(sc->sc_hdr->init_textsz) > RTC_INST_SIZE) {
111510893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_alloc_fw_dma(): "
111610893SQuaker.Fang@Sun.COM 		    "firmware init text size 0x%x is too large\n",
111710893SQuaker.Fang@Sun.COM 		    LE_32(sc->sc_hdr->init_textsz));
111810893SQuaker.Fang@Sun.COM 
111910893SQuaker.Fang@Sun.COM 		goto fail;
112010893SQuaker.Fang@Sun.COM 	}
112110893SQuaker.Fang@Sun.COM 
112210893SQuaker.Fang@Sun.COM 	if (LE_32(sc->sc_hdr->init_datasz) > RTC_DATA_SIZE) {
112310893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_alloc_fw_dma(): "
112410893SQuaker.Fang@Sun.COM 		    "firmware init data size 0x%x is too large\n",
112510893SQuaker.Fang@Sun.COM 		    LE_32(sc->sc_hdr->init_datasz));
112610893SQuaker.Fang@Sun.COM 
112710893SQuaker.Fang@Sun.COM 		goto fail;
112810893SQuaker.Fang@Sun.COM 	}
112910893SQuaker.Fang@Sun.COM 
113010893SQuaker.Fang@Sun.COM 	if (LE_32(sc->sc_hdr->textsz) > RTC_INST_SIZE) {
113110893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_alloc_fw_dma(): "
113210893SQuaker.Fang@Sun.COM 		    "firmware text size 0x%x is too large\n",
113310893SQuaker.Fang@Sun.COM 		    LE_32(sc->sc_hdr->textsz));
113410893SQuaker.Fang@Sun.COM 
113510893SQuaker.Fang@Sun.COM 		goto fail;
113610893SQuaker.Fang@Sun.COM 	}
113710893SQuaker.Fang@Sun.COM 
113810893SQuaker.Fang@Sun.COM 	if (LE_32(sc->sc_hdr->datasz) > RTC_DATA_SIZE) {
113910893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_alloc_fw_dma(): "
114010893SQuaker.Fang@Sun.COM 		    "firmware data size 0x%x is too large\n",
114110893SQuaker.Fang@Sun.COM 		    LE_32(sc->sc_hdr->datasz));
114210893SQuaker.Fang@Sun.COM 
114310893SQuaker.Fang@Sun.COM 		goto fail;
114410893SQuaker.Fang@Sun.COM 	}
114510893SQuaker.Fang@Sun.COM 
114610893SQuaker.Fang@Sun.COM 	/*
114710893SQuaker.Fang@Sun.COM 	 * copy text of runtime ucode
114810893SQuaker.Fang@Sun.COM 	 */
114910893SQuaker.Fang@Sun.COM 	t = (char *)(sc->sc_hdr + 1);
115010893SQuaker.Fang@Sun.COM 	err = iwp_alloc_dma_mem(sc, LE_32(sc->sc_hdr->textsz),
115110893SQuaker.Fang@Sun.COM 	    &fw_dma_attr, &iwp_dma_accattr,
115210893SQuaker.Fang@Sun.COM 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
115310893SQuaker.Fang@Sun.COM 	    &sc->sc_dma_fw_text);
115410893SQuaker.Fang@Sun.COM 	if (err != DDI_SUCCESS) {
115510893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_alloc_fw_dma(): "
115610893SQuaker.Fang@Sun.COM 		    "failed to allocate text dma memory.\n");
115710893SQuaker.Fang@Sun.COM 		goto fail;
115810893SQuaker.Fang@Sun.COM 	}
115910893SQuaker.Fang@Sun.COM 
116010893SQuaker.Fang@Sun.COM 	dma_p = &sc->sc_dma_fw_text;
116110893SQuaker.Fang@Sun.COM 
116210893SQuaker.Fang@Sun.COM 	IWP_DBG((IWP_DEBUG_DMA, "iwp_alloc_fw_dma(): "
116310893SQuaker.Fang@Sun.COM 	    "text[ncookies:%d addr:%lx size:%lx]\n",
116410893SQuaker.Fang@Sun.COM 	    dma_p->ncookies, dma_p->cookie.dmac_address,
116510893SQuaker.Fang@Sun.COM 	    dma_p->cookie.dmac_size));
116610893SQuaker.Fang@Sun.COM 
116710893SQuaker.Fang@Sun.COM 	(void) memcpy(dma_p->mem_va, t, LE_32(sc->sc_hdr->textsz));
116810893SQuaker.Fang@Sun.COM 
116910893SQuaker.Fang@Sun.COM 	/*
117010893SQuaker.Fang@Sun.COM 	 * copy data and bak-data of runtime ucode
117110893SQuaker.Fang@Sun.COM 	 */
117210893SQuaker.Fang@Sun.COM 	t += LE_32(sc->sc_hdr->textsz);
117310893SQuaker.Fang@Sun.COM 	err = iwp_alloc_dma_mem(sc, LE_32(sc->sc_hdr->datasz),
117410893SQuaker.Fang@Sun.COM 	    &fw_dma_attr, &iwp_dma_accattr,
117510893SQuaker.Fang@Sun.COM 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
117610893SQuaker.Fang@Sun.COM 	    &sc->sc_dma_fw_data);
117710893SQuaker.Fang@Sun.COM 	if (err != DDI_SUCCESS) {
117810893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_alloc_fw_dma(): "
117910893SQuaker.Fang@Sun.COM 		    "failed to allocate data dma memory\n");
118010893SQuaker.Fang@Sun.COM 		goto fail;
118110893SQuaker.Fang@Sun.COM 	}
118210893SQuaker.Fang@Sun.COM 
118310893SQuaker.Fang@Sun.COM 	dma_p = &sc->sc_dma_fw_data;
118410893SQuaker.Fang@Sun.COM 
118510893SQuaker.Fang@Sun.COM 	IWP_DBG((IWP_DEBUG_DMA, "iwp_alloc_fw_dma(): "
118610893SQuaker.Fang@Sun.COM 	    "data[ncookies:%d addr:%lx size:%lx]\n",
118710893SQuaker.Fang@Sun.COM 	    dma_p->ncookies, dma_p->cookie.dmac_address,
118810893SQuaker.Fang@Sun.COM 	    dma_p->cookie.dmac_size));
118910893SQuaker.Fang@Sun.COM 
119010893SQuaker.Fang@Sun.COM 	(void) memcpy(dma_p->mem_va, t, LE_32(sc->sc_hdr->datasz));
119110893SQuaker.Fang@Sun.COM 
119210893SQuaker.Fang@Sun.COM 	err = iwp_alloc_dma_mem(sc, LE_32(sc->sc_hdr->datasz),
119310893SQuaker.Fang@Sun.COM 	    &fw_dma_attr, &iwp_dma_accattr,
119410893SQuaker.Fang@Sun.COM 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
119510893SQuaker.Fang@Sun.COM 	    &sc->sc_dma_fw_data_bak);
119610893SQuaker.Fang@Sun.COM 	if (err != DDI_SUCCESS) {
119710893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_alloc_fw_dma(): "
119810893SQuaker.Fang@Sun.COM 		    "failed to allocate data bakup dma memory\n");
119910893SQuaker.Fang@Sun.COM 		goto fail;
120010893SQuaker.Fang@Sun.COM 	}
120110893SQuaker.Fang@Sun.COM 
120210893SQuaker.Fang@Sun.COM 	dma_p = &sc->sc_dma_fw_data_bak;
120310893SQuaker.Fang@Sun.COM 
120410893SQuaker.Fang@Sun.COM 	IWP_DBG((IWP_DEBUG_DMA, "iwp_alloc_fw_dma(): "
120510893SQuaker.Fang@Sun.COM 	    "data_bak[ncookies:%d addr:%lx "
120610893SQuaker.Fang@Sun.COM 	    "size:%lx]\n",
120710893SQuaker.Fang@Sun.COM 	    dma_p->ncookies, dma_p->cookie.dmac_address,
120810893SQuaker.Fang@Sun.COM 	    dma_p->cookie.dmac_size));
120910893SQuaker.Fang@Sun.COM 
121010893SQuaker.Fang@Sun.COM 	(void) memcpy(dma_p->mem_va, t, LE_32(sc->sc_hdr->datasz));
121110893SQuaker.Fang@Sun.COM 
121210893SQuaker.Fang@Sun.COM 	/*
121310893SQuaker.Fang@Sun.COM 	 * copy text of init ucode
121410893SQuaker.Fang@Sun.COM 	 */
121510893SQuaker.Fang@Sun.COM 	t += LE_32(sc->sc_hdr->datasz);
121610893SQuaker.Fang@Sun.COM 	err = iwp_alloc_dma_mem(sc, LE_32(sc->sc_hdr->init_textsz),
121710893SQuaker.Fang@Sun.COM 	    &fw_dma_attr, &iwp_dma_accattr,
121810893SQuaker.Fang@Sun.COM 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
121910893SQuaker.Fang@Sun.COM 	    &sc->sc_dma_fw_init_text);
122010893SQuaker.Fang@Sun.COM 	if (err != DDI_SUCCESS) {
122110893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_alloc_fw_dma(): "
122210893SQuaker.Fang@Sun.COM 		    "failed to allocate init text dma memory\n");
122310893SQuaker.Fang@Sun.COM 		goto fail;
122410893SQuaker.Fang@Sun.COM 	}
122510893SQuaker.Fang@Sun.COM 
122610893SQuaker.Fang@Sun.COM 	dma_p = &sc->sc_dma_fw_init_text;
122710893SQuaker.Fang@Sun.COM 
122810893SQuaker.Fang@Sun.COM 	IWP_DBG((IWP_DEBUG_DMA, "iwp_alloc_fw_dma(): "
122910893SQuaker.Fang@Sun.COM 	    "init_text[ncookies:%d addr:%lx "
123010893SQuaker.Fang@Sun.COM 	    "size:%lx]\n",
123110893SQuaker.Fang@Sun.COM 	    dma_p->ncookies, dma_p->cookie.dmac_address,
123210893SQuaker.Fang@Sun.COM 	    dma_p->cookie.dmac_size));
123310893SQuaker.Fang@Sun.COM 
123410893SQuaker.Fang@Sun.COM 	(void) memcpy(dma_p->mem_va, t, LE_32(sc->sc_hdr->init_textsz));
123510893SQuaker.Fang@Sun.COM 
123610893SQuaker.Fang@Sun.COM 	/*
123710893SQuaker.Fang@Sun.COM 	 * copy data of init ucode
123810893SQuaker.Fang@Sun.COM 	 */
123910893SQuaker.Fang@Sun.COM 	t += LE_32(sc->sc_hdr->init_textsz);
124010893SQuaker.Fang@Sun.COM 	err = iwp_alloc_dma_mem(sc, LE_32(sc->sc_hdr->init_datasz),
124110893SQuaker.Fang@Sun.COM 	    &fw_dma_attr, &iwp_dma_accattr,
124210893SQuaker.Fang@Sun.COM 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
124310893SQuaker.Fang@Sun.COM 	    &sc->sc_dma_fw_init_data);
124410893SQuaker.Fang@Sun.COM 	if (err != DDI_SUCCESS) {
124510893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_alloc_fw_dma(): "
124610893SQuaker.Fang@Sun.COM 		    "failed to allocate init data dma memory\n");
124710893SQuaker.Fang@Sun.COM 		goto fail;
124810893SQuaker.Fang@Sun.COM 	}
124910893SQuaker.Fang@Sun.COM 
125010893SQuaker.Fang@Sun.COM 	dma_p = &sc->sc_dma_fw_init_data;
125110893SQuaker.Fang@Sun.COM 
125210893SQuaker.Fang@Sun.COM 	IWP_DBG((IWP_DEBUG_DMA, "iwp_alloc_fw_dma(): "
125310893SQuaker.Fang@Sun.COM 	    "init_data[ncookies:%d addr:%lx "
125410893SQuaker.Fang@Sun.COM 	    "size:%lx]\n",
125510893SQuaker.Fang@Sun.COM 	    dma_p->ncookies, dma_p->cookie.dmac_address,
125610893SQuaker.Fang@Sun.COM 	    dma_p->cookie.dmac_size));
125710893SQuaker.Fang@Sun.COM 
125810893SQuaker.Fang@Sun.COM 	(void) memcpy(dma_p->mem_va, t, LE_32(sc->sc_hdr->init_datasz));
125910893SQuaker.Fang@Sun.COM 
126010893SQuaker.Fang@Sun.COM 	sc->sc_boot = t + LE_32(sc->sc_hdr->init_datasz);
126110893SQuaker.Fang@Sun.COM fail:
126210893SQuaker.Fang@Sun.COM 	return (err);
126310893SQuaker.Fang@Sun.COM }
126410893SQuaker.Fang@Sun.COM 
126510893SQuaker.Fang@Sun.COM static void
iwp_free_fw_dma(iwp_sc_t * sc)126610893SQuaker.Fang@Sun.COM iwp_free_fw_dma(iwp_sc_t *sc)
126710893SQuaker.Fang@Sun.COM {
126810893SQuaker.Fang@Sun.COM 	iwp_free_dma_mem(&sc->sc_dma_fw_text);
126910893SQuaker.Fang@Sun.COM 	iwp_free_dma_mem(&sc->sc_dma_fw_data);
127010893SQuaker.Fang@Sun.COM 	iwp_free_dma_mem(&sc->sc_dma_fw_data_bak);
127110893SQuaker.Fang@Sun.COM 	iwp_free_dma_mem(&sc->sc_dma_fw_init_text);
127210893SQuaker.Fang@Sun.COM 	iwp_free_dma_mem(&sc->sc_dma_fw_init_data);
127310893SQuaker.Fang@Sun.COM }
127410893SQuaker.Fang@Sun.COM 
127510893SQuaker.Fang@Sun.COM /*
127610893SQuaker.Fang@Sun.COM  * Allocate a shared buffer between host and NIC.
127710893SQuaker.Fang@Sun.COM  */
127810893SQuaker.Fang@Sun.COM static int
iwp_alloc_shared(iwp_sc_t * sc)127910893SQuaker.Fang@Sun.COM iwp_alloc_shared(iwp_sc_t *sc)
128010893SQuaker.Fang@Sun.COM {
128110893SQuaker.Fang@Sun.COM #ifdef	DEBUG
128210893SQuaker.Fang@Sun.COM 	iwp_dma_t *dma_p;
128310893SQuaker.Fang@Sun.COM #endif
128410893SQuaker.Fang@Sun.COM 	int err = DDI_FAILURE;
128510893SQuaker.Fang@Sun.COM 
128610893SQuaker.Fang@Sun.COM 	/*
128710893SQuaker.Fang@Sun.COM 	 * must be aligned on a 4K-page boundary
128810893SQuaker.Fang@Sun.COM 	 */
128910893SQuaker.Fang@Sun.COM 	err = iwp_alloc_dma_mem(sc, sizeof (iwp_shared_t),
129010893SQuaker.Fang@Sun.COM 	    &sh_dma_attr, &iwp_dma_descattr,
129110893SQuaker.Fang@Sun.COM 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
129210893SQuaker.Fang@Sun.COM 	    &sc->sc_dma_sh);
129310893SQuaker.Fang@Sun.COM 	if (err != DDI_SUCCESS) {
129410893SQuaker.Fang@Sun.COM 		goto fail;
129510893SQuaker.Fang@Sun.COM 	}
129610893SQuaker.Fang@Sun.COM 
129710893SQuaker.Fang@Sun.COM 	sc->sc_shared = (iwp_shared_t *)sc->sc_dma_sh.mem_va;
129810893SQuaker.Fang@Sun.COM 
129910893SQuaker.Fang@Sun.COM #ifdef	DEBUG
130010893SQuaker.Fang@Sun.COM 	dma_p = &sc->sc_dma_sh;
130110893SQuaker.Fang@Sun.COM #endif
130210893SQuaker.Fang@Sun.COM 	IWP_DBG((IWP_DEBUG_DMA, "iwp_alloc_shared(): "
130310893SQuaker.Fang@Sun.COM 	    "sh[ncookies:%d addr:%lx size:%lx]\n",
130410893SQuaker.Fang@Sun.COM 	    dma_p->ncookies, dma_p->cookie.dmac_address,
130510893SQuaker.Fang@Sun.COM 	    dma_p->cookie.dmac_size));
130610893SQuaker.Fang@Sun.COM 
130710893SQuaker.Fang@Sun.COM 	return (err);
130810893SQuaker.Fang@Sun.COM fail:
130910893SQuaker.Fang@Sun.COM 	iwp_free_shared(sc);
131010893SQuaker.Fang@Sun.COM 	return (err);
131110893SQuaker.Fang@Sun.COM }
131210893SQuaker.Fang@Sun.COM 
131310893SQuaker.Fang@Sun.COM static void
iwp_free_shared(iwp_sc_t * sc)131410893SQuaker.Fang@Sun.COM iwp_free_shared(iwp_sc_t *sc)
131510893SQuaker.Fang@Sun.COM {
131610893SQuaker.Fang@Sun.COM 	iwp_free_dma_mem(&sc->sc_dma_sh);
131710893SQuaker.Fang@Sun.COM }
131810893SQuaker.Fang@Sun.COM 
131910893SQuaker.Fang@Sun.COM /*
132010893SQuaker.Fang@Sun.COM  * Allocate a keep warm page.
132110893SQuaker.Fang@Sun.COM  */
132210893SQuaker.Fang@Sun.COM static int
iwp_alloc_kw(iwp_sc_t * sc)132310893SQuaker.Fang@Sun.COM iwp_alloc_kw(iwp_sc_t *sc)
132410893SQuaker.Fang@Sun.COM {
132510893SQuaker.Fang@Sun.COM #ifdef	DEBUG
132610893SQuaker.Fang@Sun.COM 	iwp_dma_t *dma_p;
132710893SQuaker.Fang@Sun.COM #endif
132810893SQuaker.Fang@Sun.COM 	int err = DDI_FAILURE;
132910893SQuaker.Fang@Sun.COM 
133010893SQuaker.Fang@Sun.COM 	/*
133110893SQuaker.Fang@Sun.COM 	 * must be aligned on a 4K-page boundary
133210893SQuaker.Fang@Sun.COM 	 */
133310893SQuaker.Fang@Sun.COM 	err = iwp_alloc_dma_mem(sc, IWP_KW_SIZE,
133410893SQuaker.Fang@Sun.COM 	    &kw_dma_attr, &iwp_dma_descattr,
133510893SQuaker.Fang@Sun.COM 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
133610893SQuaker.Fang@Sun.COM 	    &sc->sc_dma_kw);
133710893SQuaker.Fang@Sun.COM 	if (err != DDI_SUCCESS) {
133810893SQuaker.Fang@Sun.COM 		goto fail;
133910893SQuaker.Fang@Sun.COM 	}
134010893SQuaker.Fang@Sun.COM 
134110893SQuaker.Fang@Sun.COM #ifdef	DEBUG
134210893SQuaker.Fang@Sun.COM 	dma_p = &sc->sc_dma_kw;
134310893SQuaker.Fang@Sun.COM #endif
134410893SQuaker.Fang@Sun.COM 	IWP_DBG((IWP_DEBUG_DMA, "iwp_alloc_kw(): "
134510893SQuaker.Fang@Sun.COM 	    "kw[ncookies:%d addr:%lx size:%lx]\n",
134610893SQuaker.Fang@Sun.COM 	    dma_p->ncookies, dma_p->cookie.dmac_address,
134710893SQuaker.Fang@Sun.COM 	    dma_p->cookie.dmac_size));
134810893SQuaker.Fang@Sun.COM 
134910893SQuaker.Fang@Sun.COM 	return (err);
135010893SQuaker.Fang@Sun.COM fail:
135110893SQuaker.Fang@Sun.COM 	iwp_free_kw(sc);
135210893SQuaker.Fang@Sun.COM 	return (err);
135310893SQuaker.Fang@Sun.COM }
135410893SQuaker.Fang@Sun.COM 
135510893SQuaker.Fang@Sun.COM static void
iwp_free_kw(iwp_sc_t * sc)135610893SQuaker.Fang@Sun.COM iwp_free_kw(iwp_sc_t *sc)
135710893SQuaker.Fang@Sun.COM {
135810893SQuaker.Fang@Sun.COM 	iwp_free_dma_mem(&sc->sc_dma_kw);
135910893SQuaker.Fang@Sun.COM }
136010893SQuaker.Fang@Sun.COM 
136110893SQuaker.Fang@Sun.COM /*
136210893SQuaker.Fang@Sun.COM  * initialize RX ring buffers
136310893SQuaker.Fang@Sun.COM  */
136410893SQuaker.Fang@Sun.COM static int
iwp_alloc_rx_ring(iwp_sc_t * sc)136510893SQuaker.Fang@Sun.COM iwp_alloc_rx_ring(iwp_sc_t *sc)
136610893SQuaker.Fang@Sun.COM {
136710893SQuaker.Fang@Sun.COM 	iwp_rx_ring_t *ring;
136810893SQuaker.Fang@Sun.COM 	iwp_rx_data_t *data;
136910893SQuaker.Fang@Sun.COM #ifdef	DEBUG
137010893SQuaker.Fang@Sun.COM 	iwp_dma_t *dma_p;
137110893SQuaker.Fang@Sun.COM #endif
137210893SQuaker.Fang@Sun.COM 	int i, err = DDI_FAILURE;
137310893SQuaker.Fang@Sun.COM 
137410893SQuaker.Fang@Sun.COM 	ring = &sc->sc_rxq;
137510893SQuaker.Fang@Sun.COM 	ring->cur = 0;
137610893SQuaker.Fang@Sun.COM 
137710893SQuaker.Fang@Sun.COM 	/*
137810893SQuaker.Fang@Sun.COM 	 * allocate RX description ring buffer
137910893SQuaker.Fang@Sun.COM 	 */
138010893SQuaker.Fang@Sun.COM 	err = iwp_alloc_dma_mem(sc, RX_QUEUE_SIZE * sizeof (uint32_t),
138110893SQuaker.Fang@Sun.COM 	    &ring_desc_dma_attr, &iwp_dma_descattr,
138210893SQuaker.Fang@Sun.COM 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
138310893SQuaker.Fang@Sun.COM 	    &ring->dma_desc);
138410893SQuaker.Fang@Sun.COM 	if (err != DDI_SUCCESS) {
138510893SQuaker.Fang@Sun.COM 		IWP_DBG((IWP_DEBUG_DMA, "iwp_alloc_rx_ring(): "
138610893SQuaker.Fang@Sun.COM 		    "dma alloc rx ring desc "
138710893SQuaker.Fang@Sun.COM 		    "failed\n"));
138810893SQuaker.Fang@Sun.COM 		goto fail;
138910893SQuaker.Fang@Sun.COM 	}
139010893SQuaker.Fang@Sun.COM 
139110893SQuaker.Fang@Sun.COM 	ring->desc = (uint32_t *)ring->dma_desc.mem_va;
139210893SQuaker.Fang@Sun.COM #ifdef	DEBUG
139310893SQuaker.Fang@Sun.COM 	dma_p = &ring->dma_desc;
139410893SQuaker.Fang@Sun.COM #endif
139510893SQuaker.Fang@Sun.COM 	IWP_DBG((IWP_DEBUG_DMA, "iwp_alloc_rx_ring(): "
139610893SQuaker.Fang@Sun.COM 	    "rx bd[ncookies:%d addr:%lx size:%lx]\n",
139710893SQuaker.Fang@Sun.COM 	    dma_p->ncookies, dma_p->cookie.dmac_address,
139810893SQuaker.Fang@Sun.COM 	    dma_p->cookie.dmac_size));
139910893SQuaker.Fang@Sun.COM 
140010893SQuaker.Fang@Sun.COM 	/*
140110893SQuaker.Fang@Sun.COM 	 * Allocate Rx frame buffers.
140210893SQuaker.Fang@Sun.COM 	 */
140310893SQuaker.Fang@Sun.COM 	for (i = 0; i < RX_QUEUE_SIZE; i++) {
140410893SQuaker.Fang@Sun.COM 		data = &ring->data[i];
140510893SQuaker.Fang@Sun.COM 		err = iwp_alloc_dma_mem(sc, sc->sc_dmabuf_sz,
140610893SQuaker.Fang@Sun.COM 		    &rx_buffer_dma_attr, &iwp_dma_accattr,
140710893SQuaker.Fang@Sun.COM 		    DDI_DMA_READ | DDI_DMA_STREAMING,
140810893SQuaker.Fang@Sun.COM 		    &data->dma_data);
140910893SQuaker.Fang@Sun.COM 		if (err != DDI_SUCCESS) {
141010893SQuaker.Fang@Sun.COM 			IWP_DBG((IWP_DEBUG_DMA, "iwp_alloc_rx_ring(): "
141110893SQuaker.Fang@Sun.COM 			    "dma alloc rx ring "
141210893SQuaker.Fang@Sun.COM 			    "buf[%d] failed\n", i));
141310893SQuaker.Fang@Sun.COM 			goto fail;
141410893SQuaker.Fang@Sun.COM 		}
141510893SQuaker.Fang@Sun.COM 		/*
141610893SQuaker.Fang@Sun.COM 		 * the physical address bit [8-36] are used,
141710893SQuaker.Fang@Sun.COM 		 * instead of bit [0-31] in 3945.
141810893SQuaker.Fang@Sun.COM 		 */
141910893SQuaker.Fang@Sun.COM 		ring->desc[i] = (uint32_t)
142010893SQuaker.Fang@Sun.COM 		    (data->dma_data.cookie.dmac_address >> 8);
142110893SQuaker.Fang@Sun.COM 	}
142210893SQuaker.Fang@Sun.COM 
142310893SQuaker.Fang@Sun.COM #ifdef	DEBUG
142410893SQuaker.Fang@Sun.COM 	dma_p = &ring->data[0].dma_data;
142510893SQuaker.Fang@Sun.COM #endif
142610893SQuaker.Fang@Sun.COM 	IWP_DBG((IWP_DEBUG_DMA, "iwp_alloc_rx_ring(): "
142710893SQuaker.Fang@Sun.COM 	    "rx buffer[0][ncookies:%d addr:%lx "
142810893SQuaker.Fang@Sun.COM 	    "size:%lx]\n",
142910893SQuaker.Fang@Sun.COM 	    dma_p->ncookies, dma_p->cookie.dmac_address,
143010893SQuaker.Fang@Sun.COM 	    dma_p->cookie.dmac_size));
143110893SQuaker.Fang@Sun.COM 
143210893SQuaker.Fang@Sun.COM 	IWP_DMA_SYNC(ring->dma_desc, DDI_DMA_SYNC_FORDEV);
143310893SQuaker.Fang@Sun.COM 
143410893SQuaker.Fang@Sun.COM 	return (err);
143510893SQuaker.Fang@Sun.COM 
143610893SQuaker.Fang@Sun.COM fail:
143710893SQuaker.Fang@Sun.COM 	iwp_free_rx_ring(sc);
143810893SQuaker.Fang@Sun.COM 	return (err);
143910893SQuaker.Fang@Sun.COM }
144010893SQuaker.Fang@Sun.COM 
144110893SQuaker.Fang@Sun.COM /*
144210893SQuaker.Fang@Sun.COM  * disable RX ring
144310893SQuaker.Fang@Sun.COM  */
144410893SQuaker.Fang@Sun.COM static void
iwp_reset_rx_ring(iwp_sc_t * sc)144510893SQuaker.Fang@Sun.COM iwp_reset_rx_ring(iwp_sc_t *sc)
144610893SQuaker.Fang@Sun.COM {
144710893SQuaker.Fang@Sun.COM 	int n;
144810893SQuaker.Fang@Sun.COM 
144910893SQuaker.Fang@Sun.COM 	iwp_mac_access_enter(sc);
145010893SQuaker.Fang@Sun.COM 	IWP_WRITE(sc, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
145110893SQuaker.Fang@Sun.COM 	for (n = 0; n < 2000; n++) {
145210893SQuaker.Fang@Sun.COM 		if (IWP_READ(sc, FH_MEM_RSSR_RX_STATUS_REG) & (1 << 24)) {
145310893SQuaker.Fang@Sun.COM 			break;
145410893SQuaker.Fang@Sun.COM 		}
145510893SQuaker.Fang@Sun.COM 		DELAY(1000);
145610893SQuaker.Fang@Sun.COM 	}
145710893SQuaker.Fang@Sun.COM #ifdef DEBUG
145810893SQuaker.Fang@Sun.COM 	if (2000 == n) {
145910893SQuaker.Fang@Sun.COM 		IWP_DBG((IWP_DEBUG_DMA, "iwp_reset_rx_ring(): "
146010893SQuaker.Fang@Sun.COM 		    "timeout resetting Rx ring\n"));
146110893SQuaker.Fang@Sun.COM 	}
146210893SQuaker.Fang@Sun.COM #endif
146310893SQuaker.Fang@Sun.COM 	iwp_mac_access_exit(sc);
146410893SQuaker.Fang@Sun.COM 
146510893SQuaker.Fang@Sun.COM 	sc->sc_rxq.cur = 0;
146610893SQuaker.Fang@Sun.COM }
146710893SQuaker.Fang@Sun.COM 
146810893SQuaker.Fang@Sun.COM static void
iwp_free_rx_ring(iwp_sc_t * sc)146910893SQuaker.Fang@Sun.COM iwp_free_rx_ring(iwp_sc_t *sc)
147010893SQuaker.Fang@Sun.COM {
147110893SQuaker.Fang@Sun.COM 	int i;
147210893SQuaker.Fang@Sun.COM 
147310893SQuaker.Fang@Sun.COM 	for (i = 0; i < RX_QUEUE_SIZE; i++) {
147410893SQuaker.Fang@Sun.COM 		if (sc->sc_rxq.data[i].dma_data.dma_hdl) {
147510893SQuaker.Fang@Sun.COM 			IWP_DMA_SYNC(sc->sc_rxq.data[i].dma_data,
147610893SQuaker.Fang@Sun.COM 			    DDI_DMA_SYNC_FORCPU);
147710893SQuaker.Fang@Sun.COM 		}
147810893SQuaker.Fang@Sun.COM 
147910893SQuaker.Fang@Sun.COM 		iwp_free_dma_mem(&sc->sc_rxq.data[i].dma_data);
148010893SQuaker.Fang@Sun.COM 	}
148110893SQuaker.Fang@Sun.COM 
148210893SQuaker.Fang@Sun.COM 	if (sc->sc_rxq.dma_desc.dma_hdl) {
148310893SQuaker.Fang@Sun.COM 		IWP_DMA_SYNC(sc->sc_rxq.dma_desc, DDI_DMA_SYNC_FORDEV);
148410893SQuaker.Fang@Sun.COM 	}
148510893SQuaker.Fang@Sun.COM 
148610893SQuaker.Fang@Sun.COM 	iwp_free_dma_mem(&sc->sc_rxq.dma_desc);
148710893SQuaker.Fang@Sun.COM }
148810893SQuaker.Fang@Sun.COM 
148910893SQuaker.Fang@Sun.COM /*
149010893SQuaker.Fang@Sun.COM  * initialize TX ring buffers
149110893SQuaker.Fang@Sun.COM  */
149210893SQuaker.Fang@Sun.COM static int
iwp_alloc_tx_ring(iwp_sc_t * sc,iwp_tx_ring_t * ring,int slots,int qid)149310893SQuaker.Fang@Sun.COM iwp_alloc_tx_ring(iwp_sc_t *sc, iwp_tx_ring_t *ring,
149410893SQuaker.Fang@Sun.COM     int slots, int qid)
149510893SQuaker.Fang@Sun.COM {
149610893SQuaker.Fang@Sun.COM 	iwp_tx_data_t *data;
149710893SQuaker.Fang@Sun.COM 	iwp_tx_desc_t *desc_h;
149810893SQuaker.Fang@Sun.COM 	uint32_t paddr_desc_h;
149910893SQuaker.Fang@Sun.COM 	iwp_cmd_t *cmd_h;
150010893SQuaker.Fang@Sun.COM 	uint32_t paddr_cmd_h;
150110893SQuaker.Fang@Sun.COM #ifdef	DEBUG
150210893SQuaker.Fang@Sun.COM 	iwp_dma_t *dma_p;
150310893SQuaker.Fang@Sun.COM #endif
150410893SQuaker.Fang@Sun.COM 	int i, err = DDI_FAILURE;
150510893SQuaker.Fang@Sun.COM 	ring->qid = qid;
150610893SQuaker.Fang@Sun.COM 	ring->count = TFD_QUEUE_SIZE_MAX;
150710893SQuaker.Fang@Sun.COM 	ring->window = slots;
150810893SQuaker.Fang@Sun.COM 	ring->queued = 0;
150910893SQuaker.Fang@Sun.COM 	ring->cur = 0;
151010893SQuaker.Fang@Sun.COM 	ring->desc_cur = 0;
151110893SQuaker.Fang@Sun.COM 
151210893SQuaker.Fang@Sun.COM 	/*
151310893SQuaker.Fang@Sun.COM 	 * allocate buffer for TX descriptor ring
151410893SQuaker.Fang@Sun.COM 	 */
151510893SQuaker.Fang@Sun.COM 	err = iwp_alloc_dma_mem(sc,
151610893SQuaker.Fang@Sun.COM 	    TFD_QUEUE_SIZE_MAX * sizeof (iwp_tx_desc_t),
151710893SQuaker.Fang@Sun.COM 	    &ring_desc_dma_attr, &iwp_dma_descattr,
151810893SQuaker.Fang@Sun.COM 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
151910893SQuaker.Fang@Sun.COM 	    &ring->dma_desc);
152010893SQuaker.Fang@Sun.COM 	if (err != DDI_SUCCESS) {
152110893SQuaker.Fang@Sun.COM 		IWP_DBG((IWP_DEBUG_DMA, "iwp_alloc_tx_ring(): "
152210893SQuaker.Fang@Sun.COM 		    "dma alloc tx ring desc[%d] "
152310893SQuaker.Fang@Sun.COM 		    "failed\n", qid));
152410893SQuaker.Fang@Sun.COM 		goto fail;
152510893SQuaker.Fang@Sun.COM 	}
152610893SQuaker.Fang@Sun.COM 
152710893SQuaker.Fang@Sun.COM #ifdef	DEBUG
152810893SQuaker.Fang@Sun.COM 	dma_p = &ring->dma_desc;
152910893SQuaker.Fang@Sun.COM #endif
153010893SQuaker.Fang@Sun.COM 	IWP_DBG((IWP_DEBUG_DMA, "iwp_alloc_tx_ring(): "
153110893SQuaker.Fang@Sun.COM 	    "tx bd[ncookies:%d addr:%lx size:%lx]\n",
153210893SQuaker.Fang@Sun.COM 	    dma_p->ncookies, dma_p->cookie.dmac_address,
153310893SQuaker.Fang@Sun.COM 	    dma_p->cookie.dmac_size));
153410893SQuaker.Fang@Sun.COM 
153510893SQuaker.Fang@Sun.COM 	desc_h = (iwp_tx_desc_t *)ring->dma_desc.mem_va;
153610893SQuaker.Fang@Sun.COM 	paddr_desc_h = ring->dma_desc.cookie.dmac_address;
153710893SQuaker.Fang@Sun.COM 
153810893SQuaker.Fang@Sun.COM 	/*
153910893SQuaker.Fang@Sun.COM 	 * allocate buffer for ucode command
154010893SQuaker.Fang@Sun.COM 	 */
154110893SQuaker.Fang@Sun.COM 	err = iwp_alloc_dma_mem(sc,
154210893SQuaker.Fang@Sun.COM 	    TFD_QUEUE_SIZE_MAX * sizeof (iwp_cmd_t),
154310893SQuaker.Fang@Sun.COM 	    &cmd_dma_attr, &iwp_dma_accattr,
154410893SQuaker.Fang@Sun.COM 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
154510893SQuaker.Fang@Sun.COM 	    &ring->dma_cmd);
154610893SQuaker.Fang@Sun.COM 	if (err != DDI_SUCCESS) {
154710893SQuaker.Fang@Sun.COM 		IWP_DBG((IWP_DEBUG_DMA, "iwp_alloc_tx_ring(): "
154810893SQuaker.Fang@Sun.COM 		    "dma alloc tx ring cmd[%d]"
154910893SQuaker.Fang@Sun.COM 		    " failed\n", qid));
155010893SQuaker.Fang@Sun.COM 		goto fail;
155110893SQuaker.Fang@Sun.COM 	}
155210893SQuaker.Fang@Sun.COM 
155310893SQuaker.Fang@Sun.COM #ifdef	DEBUG
155410893SQuaker.Fang@Sun.COM 	dma_p = &ring->dma_cmd;
155510893SQuaker.Fang@Sun.COM #endif
155610893SQuaker.Fang@Sun.COM 	IWP_DBG((IWP_DEBUG_DMA, "iwp_alloc_tx_ring(): "
155710893SQuaker.Fang@Sun.COM 	    "tx cmd[ncookies:%d addr:%lx size:%lx]\n",
155810893SQuaker.Fang@Sun.COM 	    dma_p->ncookies, dma_p->cookie.dmac_address,
155910893SQuaker.Fang@Sun.COM 	    dma_p->cookie.dmac_size));
156010893SQuaker.Fang@Sun.COM 
156110893SQuaker.Fang@Sun.COM 	cmd_h = (iwp_cmd_t *)ring->dma_cmd.mem_va;
156210893SQuaker.Fang@Sun.COM 	paddr_cmd_h = ring->dma_cmd.cookie.dmac_address;
156310893SQuaker.Fang@Sun.COM 
156410893SQuaker.Fang@Sun.COM 	/*
156510893SQuaker.Fang@Sun.COM 	 * Allocate Tx frame buffers.
156610893SQuaker.Fang@Sun.COM 	 */
156710893SQuaker.Fang@Sun.COM 	ring->data = kmem_zalloc(sizeof (iwp_tx_data_t) * TFD_QUEUE_SIZE_MAX,
156810893SQuaker.Fang@Sun.COM 	    KM_NOSLEEP);
156910893SQuaker.Fang@Sun.COM 	if (NULL == ring->data) {
157010893SQuaker.Fang@Sun.COM 		IWP_DBG((IWP_DEBUG_DMA, "iwp_alloc_tx_ring(): "
157110893SQuaker.Fang@Sun.COM 		    "could not allocate "
157210893SQuaker.Fang@Sun.COM 		    "tx data slots\n"));
157310893SQuaker.Fang@Sun.COM 		goto fail;
157410893SQuaker.Fang@Sun.COM 	}
157510893SQuaker.Fang@Sun.COM 
157610893SQuaker.Fang@Sun.COM 	for (i = 0; i < TFD_QUEUE_SIZE_MAX; i++) {
157710893SQuaker.Fang@Sun.COM 		data = &ring->data[i];
157810893SQuaker.Fang@Sun.COM 		err = iwp_alloc_dma_mem(sc, sc->sc_dmabuf_sz,
157910893SQuaker.Fang@Sun.COM 		    &tx_buffer_dma_attr, &iwp_dma_accattr,
158010893SQuaker.Fang@Sun.COM 		    DDI_DMA_WRITE | DDI_DMA_STREAMING,
158110893SQuaker.Fang@Sun.COM 		    &data->dma_data);
158210893SQuaker.Fang@Sun.COM 		if (err != DDI_SUCCESS) {
158310893SQuaker.Fang@Sun.COM 			IWP_DBG((IWP_DEBUG_DMA, "iwp_alloc_tx_ring(): "
158410893SQuaker.Fang@Sun.COM 			    "dma alloc tx "
158510893SQuaker.Fang@Sun.COM 			    "ring buf[%d] failed\n", i));
158610893SQuaker.Fang@Sun.COM 			goto fail;
158710893SQuaker.Fang@Sun.COM 		}
158810893SQuaker.Fang@Sun.COM 
158910893SQuaker.Fang@Sun.COM 		data->desc = desc_h + i;
159010893SQuaker.Fang@Sun.COM 		data->paddr_desc = paddr_desc_h +
159110893SQuaker.Fang@Sun.COM 		    _PTRDIFF(data->desc, desc_h);
159210893SQuaker.Fang@Sun.COM 		data->cmd = cmd_h +  i;
159310893SQuaker.Fang@Sun.COM 		data->paddr_cmd = paddr_cmd_h +
159410893SQuaker.Fang@Sun.COM 		    _PTRDIFF(data->cmd, cmd_h);
159510893SQuaker.Fang@Sun.COM 	}
159610893SQuaker.Fang@Sun.COM #ifdef	DEBUG
159710893SQuaker.Fang@Sun.COM 	dma_p = &ring->data[0].dma_data;
159810893SQuaker.Fang@Sun.COM #endif
159910893SQuaker.Fang@Sun.COM 	IWP_DBG((IWP_DEBUG_DMA, "iwp_alloc_tx_ring(): "
160010893SQuaker.Fang@Sun.COM 	    "tx buffer[0][ncookies:%d addr:%lx "
160110893SQuaker.Fang@Sun.COM 	    "size:%lx]\n",
160210893SQuaker.Fang@Sun.COM 	    dma_p->ncookies, dma_p->cookie.dmac_address,
160310893SQuaker.Fang@Sun.COM 	    dma_p->cookie.dmac_size));
160410893SQuaker.Fang@Sun.COM 
160510893SQuaker.Fang@Sun.COM 	return (err);
160610893SQuaker.Fang@Sun.COM 
160710893SQuaker.Fang@Sun.COM fail:
160810893SQuaker.Fang@Sun.COM 	iwp_free_tx_ring(ring);
160910893SQuaker.Fang@Sun.COM 
161010893SQuaker.Fang@Sun.COM 	return (err);
161110893SQuaker.Fang@Sun.COM }
161210893SQuaker.Fang@Sun.COM 
161310893SQuaker.Fang@Sun.COM /*
161410893SQuaker.Fang@Sun.COM  * disable TX ring
161510893SQuaker.Fang@Sun.COM  */
161610893SQuaker.Fang@Sun.COM static void
iwp_reset_tx_ring(iwp_sc_t * sc,iwp_tx_ring_t * ring)161710893SQuaker.Fang@Sun.COM iwp_reset_tx_ring(iwp_sc_t *sc, iwp_tx_ring_t *ring)
161810893SQuaker.Fang@Sun.COM {
161910893SQuaker.Fang@Sun.COM 	iwp_tx_data_t *data;
162010893SQuaker.Fang@Sun.COM 	int i, n;
162110893SQuaker.Fang@Sun.COM 
162210893SQuaker.Fang@Sun.COM 	iwp_mac_access_enter(sc);
162310893SQuaker.Fang@Sun.COM 
162410893SQuaker.Fang@Sun.COM 	IWP_WRITE(sc, IWP_FH_TCSR_CHNL_TX_CONFIG_REG(ring->qid), 0);
162510893SQuaker.Fang@Sun.COM 	for (n = 0; n < 200; n++) {
162610893SQuaker.Fang@Sun.COM 		if (IWP_READ(sc, IWP_FH_TSSR_TX_STATUS_REG) &
162710893SQuaker.Fang@Sun.COM 		    IWP_FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ring->qid)) {
162810893SQuaker.Fang@Sun.COM 			break;
162910893SQuaker.Fang@Sun.COM 		}
163010893SQuaker.Fang@Sun.COM 		DELAY(10);
163110893SQuaker.Fang@Sun.COM 	}
163210893SQuaker.Fang@Sun.COM 
163310893SQuaker.Fang@Sun.COM #ifdef	DEBUG
163410893SQuaker.Fang@Sun.COM 	if (200 == n) {
163510893SQuaker.Fang@Sun.COM 		IWP_DBG((IWP_DEBUG_DMA, "iwp_reset_tx_ring(): "
163610893SQuaker.Fang@Sun.COM 		    "timeout reset tx ring %d\n",
163710893SQuaker.Fang@Sun.COM 		    ring->qid));
163810893SQuaker.Fang@Sun.COM 	}
163910893SQuaker.Fang@Sun.COM #endif
164010893SQuaker.Fang@Sun.COM 
164110893SQuaker.Fang@Sun.COM 	iwp_mac_access_exit(sc);
164210893SQuaker.Fang@Sun.COM 
164310893SQuaker.Fang@Sun.COM 	/* by pass, if it's quiesce */
164410893SQuaker.Fang@Sun.COM 	if (!(sc->sc_flags & IWP_F_QUIESCED)) {
164510893SQuaker.Fang@Sun.COM 		for (i = 0; i < ring->count; i++) {
164610893SQuaker.Fang@Sun.COM 			data = &ring->data[i];
164710893SQuaker.Fang@Sun.COM 			IWP_DMA_SYNC(data->dma_data, DDI_DMA_SYNC_FORDEV);
164810893SQuaker.Fang@Sun.COM 		}
164910893SQuaker.Fang@Sun.COM 	}
165010893SQuaker.Fang@Sun.COM 
165110893SQuaker.Fang@Sun.COM 	ring->queued = 0;
165210893SQuaker.Fang@Sun.COM 	ring->cur = 0;
165310893SQuaker.Fang@Sun.COM 	ring->desc_cur = 0;
165410893SQuaker.Fang@Sun.COM }
165510893SQuaker.Fang@Sun.COM 
165610893SQuaker.Fang@Sun.COM static void
iwp_free_tx_ring(iwp_tx_ring_t * ring)165710893SQuaker.Fang@Sun.COM iwp_free_tx_ring(iwp_tx_ring_t *ring)
165810893SQuaker.Fang@Sun.COM {
165910893SQuaker.Fang@Sun.COM 	int i;
166010893SQuaker.Fang@Sun.COM 
166110893SQuaker.Fang@Sun.COM 	if (ring->dma_desc.dma_hdl != NULL) {
166210893SQuaker.Fang@Sun.COM 		IWP_DMA_SYNC(ring->dma_desc, DDI_DMA_SYNC_FORDEV);
166310893SQuaker.Fang@Sun.COM 	}
166410893SQuaker.Fang@Sun.COM 	iwp_free_dma_mem(&ring->dma_desc);
166510893SQuaker.Fang@Sun.COM 
166610893SQuaker.Fang@Sun.COM 	if (ring->dma_cmd.dma_hdl != NULL) {
166710893SQuaker.Fang@Sun.COM 		IWP_DMA_SYNC(ring->dma_cmd, DDI_DMA_SYNC_FORDEV);
166810893SQuaker.Fang@Sun.COM 	}
166910893SQuaker.Fang@Sun.COM 	iwp_free_dma_mem(&ring->dma_cmd);
167010893SQuaker.Fang@Sun.COM 
167110893SQuaker.Fang@Sun.COM 	if (ring->data != NULL) {
167210893SQuaker.Fang@Sun.COM 		for (i = 0; i < ring->count; i++) {
167310893SQuaker.Fang@Sun.COM 			if (ring->data[i].dma_data.dma_hdl) {
167410893SQuaker.Fang@Sun.COM 				IWP_DMA_SYNC(ring->data[i].dma_data,
167510893SQuaker.Fang@Sun.COM 				    DDI_DMA_SYNC_FORDEV);
167610893SQuaker.Fang@Sun.COM 			}
167710893SQuaker.Fang@Sun.COM 			iwp_free_dma_mem(&ring->data[i].dma_data);
167810893SQuaker.Fang@Sun.COM 		}
167910893SQuaker.Fang@Sun.COM 		kmem_free(ring->data, ring->count * sizeof (iwp_tx_data_t));
168010893SQuaker.Fang@Sun.COM 	}
168110893SQuaker.Fang@Sun.COM }
168210893SQuaker.Fang@Sun.COM 
168310893SQuaker.Fang@Sun.COM /*
168410893SQuaker.Fang@Sun.COM  * initialize TX and RX ring
168510893SQuaker.Fang@Sun.COM  */
168610893SQuaker.Fang@Sun.COM static int
iwp_ring_init(iwp_sc_t * sc)168710893SQuaker.Fang@Sun.COM iwp_ring_init(iwp_sc_t *sc)
168810893SQuaker.Fang@Sun.COM {
168910893SQuaker.Fang@Sun.COM 	int i, err = DDI_FAILURE;
169010893SQuaker.Fang@Sun.COM 
169110893SQuaker.Fang@Sun.COM 	for (i = 0; i < IWP_NUM_QUEUES; i++) {
169210893SQuaker.Fang@Sun.COM 		if (IWP_CMD_QUEUE_NUM == i) {
169310893SQuaker.Fang@Sun.COM 			continue;
169410893SQuaker.Fang@Sun.COM 		}
169510893SQuaker.Fang@Sun.COM 
169610893SQuaker.Fang@Sun.COM 		err = iwp_alloc_tx_ring(sc, &sc->sc_txq[i], TFD_TX_CMD_SLOTS,
169710893SQuaker.Fang@Sun.COM 		    i);
169810893SQuaker.Fang@Sun.COM 		if (err != DDI_SUCCESS) {
169910893SQuaker.Fang@Sun.COM 			goto fail;
170010893SQuaker.Fang@Sun.COM 		}
170110893SQuaker.Fang@Sun.COM 	}
170210893SQuaker.Fang@Sun.COM 
170310893SQuaker.Fang@Sun.COM 	/*
170410893SQuaker.Fang@Sun.COM 	 * initialize command queue
170510893SQuaker.Fang@Sun.COM 	 */
170610893SQuaker.Fang@Sun.COM 	err = iwp_alloc_tx_ring(sc, &sc->sc_txq[IWP_CMD_QUEUE_NUM],
170710893SQuaker.Fang@Sun.COM 	    TFD_CMD_SLOTS, IWP_CMD_QUEUE_NUM);
170810893SQuaker.Fang@Sun.COM 	if (err != DDI_SUCCESS) {
170910893SQuaker.Fang@Sun.COM 		goto fail;
171010893SQuaker.Fang@Sun.COM 	}
171110893SQuaker.Fang@Sun.COM 
171210893SQuaker.Fang@Sun.COM 	err = iwp_alloc_rx_ring(sc);
171310893SQuaker.Fang@Sun.COM 	if (err != DDI_SUCCESS) {
171410893SQuaker.Fang@Sun.COM 		goto fail;
171510893SQuaker.Fang@Sun.COM 	}
171610893SQuaker.Fang@Sun.COM 
171710893SQuaker.Fang@Sun.COM fail:
171810893SQuaker.Fang@Sun.COM 	return (err);
171910893SQuaker.Fang@Sun.COM }
172010893SQuaker.Fang@Sun.COM 
172110893SQuaker.Fang@Sun.COM static void
iwp_ring_free(iwp_sc_t * sc)172210893SQuaker.Fang@Sun.COM iwp_ring_free(iwp_sc_t *sc)
172310893SQuaker.Fang@Sun.COM {
172410893SQuaker.Fang@Sun.COM 	int i = IWP_NUM_QUEUES;
172510893SQuaker.Fang@Sun.COM 
172610893SQuaker.Fang@Sun.COM 	iwp_free_rx_ring(sc);
172710893SQuaker.Fang@Sun.COM 	while (--i >= 0) {
172810893SQuaker.Fang@Sun.COM 		iwp_free_tx_ring(&sc->sc_txq[i]);
172910893SQuaker.Fang@Sun.COM 	}
173010893SQuaker.Fang@Sun.COM }
173110893SQuaker.Fang@Sun.COM 
173210893SQuaker.Fang@Sun.COM /* ARGSUSED */
173310893SQuaker.Fang@Sun.COM static ieee80211_node_t *
iwp_node_alloc(ieee80211com_t * ic)173410893SQuaker.Fang@Sun.COM iwp_node_alloc(ieee80211com_t *ic)
173510893SQuaker.Fang@Sun.COM {
173610893SQuaker.Fang@Sun.COM 	iwp_amrr_t *amrr;
173710893SQuaker.Fang@Sun.COM 
173810893SQuaker.Fang@Sun.COM 	amrr = kmem_zalloc(sizeof (iwp_amrr_t), KM_SLEEP);
173910893SQuaker.Fang@Sun.COM 	if (NULL == amrr) {
174010893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_node_alloc(): "
174110893SQuaker.Fang@Sun.COM 		    "failed to allocate memory for amrr structure\n");
174210893SQuaker.Fang@Sun.COM 		return (NULL);
174310893SQuaker.Fang@Sun.COM 	}
174410893SQuaker.Fang@Sun.COM 
174510893SQuaker.Fang@Sun.COM 	iwp_amrr_init(amrr);
174610893SQuaker.Fang@Sun.COM 
174710893SQuaker.Fang@Sun.COM 	return (&amrr->in);
174810893SQuaker.Fang@Sun.COM }
174910893SQuaker.Fang@Sun.COM 
175010893SQuaker.Fang@Sun.COM static void
iwp_node_free(ieee80211_node_t * in)175110893SQuaker.Fang@Sun.COM iwp_node_free(ieee80211_node_t *in)
175210893SQuaker.Fang@Sun.COM {
175310893SQuaker.Fang@Sun.COM 	ieee80211com_t *ic;
175410893SQuaker.Fang@Sun.COM 
175510893SQuaker.Fang@Sun.COM 	if ((NULL == in) ||
175610893SQuaker.Fang@Sun.COM 	    (NULL == in->in_ic)) {
175710893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_node_free() "
175810893SQuaker.Fang@Sun.COM 		    "Got a NULL point from Net80211 module\n");
175910893SQuaker.Fang@Sun.COM 		return;
176010893SQuaker.Fang@Sun.COM 	}
176110893SQuaker.Fang@Sun.COM 	ic = in->in_ic;
176210893SQuaker.Fang@Sun.COM 
176310893SQuaker.Fang@Sun.COM 	if (ic->ic_node_cleanup != NULL) {
176410893SQuaker.Fang@Sun.COM 		ic->ic_node_cleanup(in);
176510893SQuaker.Fang@Sun.COM 	}
176610893SQuaker.Fang@Sun.COM 
176710893SQuaker.Fang@Sun.COM 	if (in->in_wpa_ie != NULL) {
176810893SQuaker.Fang@Sun.COM 		ieee80211_free(in->in_wpa_ie);
176910893SQuaker.Fang@Sun.COM 	}
177010893SQuaker.Fang@Sun.COM 
177110893SQuaker.Fang@Sun.COM 	if (in->in_wme_ie != NULL) {
177210893SQuaker.Fang@Sun.COM 		ieee80211_free(in->in_wme_ie);
177310893SQuaker.Fang@Sun.COM 	}
177410893SQuaker.Fang@Sun.COM 
177510893SQuaker.Fang@Sun.COM 	if (in->in_htcap_ie != NULL) {
177610893SQuaker.Fang@Sun.COM 		ieee80211_free(in->in_htcap_ie);
177710893SQuaker.Fang@Sun.COM 	}
177810893SQuaker.Fang@Sun.COM 
177910893SQuaker.Fang@Sun.COM 	kmem_free(in, sizeof (iwp_amrr_t));
178010893SQuaker.Fang@Sun.COM }
178110893SQuaker.Fang@Sun.COM 
178210893SQuaker.Fang@Sun.COM 
178310893SQuaker.Fang@Sun.COM /*
178410893SQuaker.Fang@Sun.COM  * change station's state. this function will be invoked by 80211 module
178510893SQuaker.Fang@Sun.COM  * when need to change staton's state.
178610893SQuaker.Fang@Sun.COM  */
178710893SQuaker.Fang@Sun.COM static int
iwp_newstate(ieee80211com_t * ic,enum ieee80211_state nstate,int arg)178810893SQuaker.Fang@Sun.COM iwp_newstate(ieee80211com_t *ic, enum ieee80211_state nstate, int arg)
178910893SQuaker.Fang@Sun.COM {
179010893SQuaker.Fang@Sun.COM 	iwp_sc_t *sc;
179110893SQuaker.Fang@Sun.COM 	ieee80211_node_t *in;
179210893SQuaker.Fang@Sun.COM 	enum ieee80211_state ostate;
179310893SQuaker.Fang@Sun.COM 	iwp_add_sta_t node;
179410893SQuaker.Fang@Sun.COM 	int i, err = IWP_FAIL;
179510893SQuaker.Fang@Sun.COM 
179610893SQuaker.Fang@Sun.COM 	if (NULL == ic) {
179710893SQuaker.Fang@Sun.COM 		return (err);
179810893SQuaker.Fang@Sun.COM 	}
179910893SQuaker.Fang@Sun.COM 	sc = (iwp_sc_t *)ic;
180010893SQuaker.Fang@Sun.COM 	in = ic->ic_bss;
180110893SQuaker.Fang@Sun.COM 	ostate = ic->ic_state;
180210893SQuaker.Fang@Sun.COM 
180310893SQuaker.Fang@Sun.COM 	mutex_enter(&sc->sc_glock);
180410893SQuaker.Fang@Sun.COM 
180510893SQuaker.Fang@Sun.COM 	switch (nstate) {
180610893SQuaker.Fang@Sun.COM 	case IEEE80211_S_SCAN:
180710893SQuaker.Fang@Sun.COM 		switch (ostate) {
180810893SQuaker.Fang@Sun.COM 		case IEEE80211_S_INIT:
180910893SQuaker.Fang@Sun.COM 			atomic_or_32(&sc->sc_flags, IWP_F_SCANNING);
181010893SQuaker.Fang@Sun.COM 			iwp_set_led(sc, 2, 10, 2);
181110893SQuaker.Fang@Sun.COM 
181210893SQuaker.Fang@Sun.COM 			/*
181310893SQuaker.Fang@Sun.COM 			 * clear association to receive beacons from
181410893SQuaker.Fang@Sun.COM 			 * all BSS'es
181510893SQuaker.Fang@Sun.COM 			 */
181610893SQuaker.Fang@Sun.COM 			sc->sc_config.assoc_id = 0;
181710893SQuaker.Fang@Sun.COM 			sc->sc_config.filter_flags &=
181810893SQuaker.Fang@Sun.COM 			    ~LE_32(RXON_FILTER_ASSOC_MSK);
181910893SQuaker.Fang@Sun.COM 
182010893SQuaker.Fang@Sun.COM 			IWP_DBG((IWP_DEBUG_80211, "iwp_newstate(): "
182110893SQuaker.Fang@Sun.COM 			    "config chan %d "
182210893SQuaker.Fang@Sun.COM 			    "flags %x filter_flags %x\n",
182310893SQuaker.Fang@Sun.COM 			    LE_16(sc->sc_config.chan),
182410893SQuaker.Fang@Sun.COM 			    LE_32(sc->sc_config.flags),
182510893SQuaker.Fang@Sun.COM 			    LE_32(sc->sc_config.filter_flags)));
182610893SQuaker.Fang@Sun.COM 
182710893SQuaker.Fang@Sun.COM 			err = iwp_cmd(sc, REPLY_RXON, &sc->sc_config,
182810893SQuaker.Fang@Sun.COM 			    sizeof (iwp_rxon_cmd_t), 1);
182910893SQuaker.Fang@Sun.COM 			if (err != IWP_SUCCESS) {
183010893SQuaker.Fang@Sun.COM 				cmn_err(CE_WARN, "iwp_newstate(): "
183110893SQuaker.Fang@Sun.COM 				    "could not clear association\n");
183210893SQuaker.Fang@Sun.COM 				atomic_and_32(&sc->sc_flags, ~IWP_F_SCANNING);
183310893SQuaker.Fang@Sun.COM 				mutex_exit(&sc->sc_glock);
183410893SQuaker.Fang@Sun.COM 				return (err);
183510893SQuaker.Fang@Sun.COM 			}
183610893SQuaker.Fang@Sun.COM 
183710893SQuaker.Fang@Sun.COM 			/* add broadcast node to send probe request */
183810893SQuaker.Fang@Sun.COM 			(void) memset(&node, 0, sizeof (node));
183910893SQuaker.Fang@Sun.COM 			(void) memset(&node.sta.addr, 0xff, IEEE80211_ADDR_LEN);
184010893SQuaker.Fang@Sun.COM 			node.sta.sta_id = IWP_BROADCAST_ID;
184110893SQuaker.Fang@Sun.COM 			err = iwp_cmd(sc, REPLY_ADD_STA, &node,
184210893SQuaker.Fang@Sun.COM 			    sizeof (node), 1);
184310893SQuaker.Fang@Sun.COM 			if (err != IWP_SUCCESS) {
184410893SQuaker.Fang@Sun.COM 				cmn_err(CE_WARN, "iwp_newstate(): "
184510893SQuaker.Fang@Sun.COM 				    "could not add broadcast node\n");
184610893SQuaker.Fang@Sun.COM 				atomic_and_32(&sc->sc_flags, ~IWP_F_SCANNING);
184710893SQuaker.Fang@Sun.COM 				mutex_exit(&sc->sc_glock);
184810893SQuaker.Fang@Sun.COM 				return (err);
184910893SQuaker.Fang@Sun.COM 			}
185010893SQuaker.Fang@Sun.COM 			break;
185110893SQuaker.Fang@Sun.COM 		case IEEE80211_S_SCAN:
185210893SQuaker.Fang@Sun.COM 			mutex_exit(&sc->sc_glock);
185310893SQuaker.Fang@Sun.COM 			/* step to next channel before actual FW scan */
185410893SQuaker.Fang@Sun.COM 			err = sc->sc_newstate(ic, nstate, arg);
185510893SQuaker.Fang@Sun.COM 			mutex_enter(&sc->sc_glock);
185610893SQuaker.Fang@Sun.COM 			if ((err != 0) || ((err = iwp_scan(sc)) != 0)) {
185710893SQuaker.Fang@Sun.COM 				cmn_err(CE_WARN, "iwp_newstate(): "
185810893SQuaker.Fang@Sun.COM 				    "could not initiate scan\n");
185910893SQuaker.Fang@Sun.COM 				atomic_and_32(&sc->sc_flags, ~IWP_F_SCANNING);
186010893SQuaker.Fang@Sun.COM 				ieee80211_cancel_scan(ic);
186110893SQuaker.Fang@Sun.COM 			}
186210893SQuaker.Fang@Sun.COM 			mutex_exit(&sc->sc_glock);
186310893SQuaker.Fang@Sun.COM 			return (err);
186410893SQuaker.Fang@Sun.COM 		default:
186510893SQuaker.Fang@Sun.COM 			break;
186610893SQuaker.Fang@Sun.COM 		}
186710893SQuaker.Fang@Sun.COM 		sc->sc_clk = 0;
186810893SQuaker.Fang@Sun.COM 		break;
186910893SQuaker.Fang@Sun.COM 
187010893SQuaker.Fang@Sun.COM 	case IEEE80211_S_AUTH:
187110893SQuaker.Fang@Sun.COM 		if (ostate == IEEE80211_S_SCAN) {
187210893SQuaker.Fang@Sun.COM 			atomic_and_32(&sc->sc_flags, ~IWP_F_SCANNING);
187310893SQuaker.Fang@Sun.COM 		}
187410893SQuaker.Fang@Sun.COM 
187510893SQuaker.Fang@Sun.COM 		/*
187610893SQuaker.Fang@Sun.COM 		 * reset state to handle reassociations correctly
187710893SQuaker.Fang@Sun.COM 		 */
187810893SQuaker.Fang@Sun.COM 		sc->sc_config.assoc_id = 0;
187910893SQuaker.Fang@Sun.COM 		sc->sc_config.filter_flags &= ~LE_32(RXON_FILTER_ASSOC_MSK);
188010893SQuaker.Fang@Sun.COM 
188110893SQuaker.Fang@Sun.COM 		/*
188210893SQuaker.Fang@Sun.COM 		 * before sending authentication and association request frame,
188310893SQuaker.Fang@Sun.COM 		 * we need do something in the hardware, such as setting the
188410893SQuaker.Fang@Sun.COM 		 * channel same to the target AP...
188510893SQuaker.Fang@Sun.COM 		 */
188610893SQuaker.Fang@Sun.COM 		if ((err = iwp_hw_set_before_auth(sc)) != 0) {
188710893SQuaker.Fang@Sun.COM 			IWP_DBG((IWP_DEBUG_80211, "iwp_newstate(): "
188810893SQuaker.Fang@Sun.COM 			    "could not send authentication request\n"));
188910893SQuaker.Fang@Sun.COM 			mutex_exit(&sc->sc_glock);
189010893SQuaker.Fang@Sun.COM 			return (err);
189110893SQuaker.Fang@Sun.COM 		}
189210893SQuaker.Fang@Sun.COM 		break;
189310893SQuaker.Fang@Sun.COM 
189410893SQuaker.Fang@Sun.COM 	case IEEE80211_S_RUN:
189510893SQuaker.Fang@Sun.COM 		if (ostate == IEEE80211_S_SCAN) {
189610893SQuaker.Fang@Sun.COM 			atomic_and_32(&sc->sc_flags, ~IWP_F_SCANNING);
189710893SQuaker.Fang@Sun.COM 		}
189810893SQuaker.Fang@Sun.COM 
189910893SQuaker.Fang@Sun.COM 		if (IEEE80211_M_MONITOR == ic->ic_opmode) {
190010893SQuaker.Fang@Sun.COM 			/* let LED blink when monitoring */
190110893SQuaker.Fang@Sun.COM 			iwp_set_led(sc, 2, 10, 10);
190210893SQuaker.Fang@Sun.COM 			break;
190310893SQuaker.Fang@Sun.COM 		}
190410893SQuaker.Fang@Sun.COM 
190510893SQuaker.Fang@Sun.COM 		IWP_DBG((IWP_DEBUG_80211, "iwp_newstate(): "
190610893SQuaker.Fang@Sun.COM 		    "associated.\n"));
190710893SQuaker.Fang@Sun.COM 
190810893SQuaker.Fang@Sun.COM 		err = iwp_run_state_config(sc);
190910893SQuaker.Fang@Sun.COM 		if (err != IWP_SUCCESS) {
191010893SQuaker.Fang@Sun.COM 			cmn_err(CE_WARN, "iwp_newstate(): "
191110893SQuaker.Fang@Sun.COM 			    "failed to set up association\n");
191210893SQuaker.Fang@Sun.COM 			mutex_exit(&sc->sc_glock);
191310893SQuaker.Fang@Sun.COM 			return (err);
191410893SQuaker.Fang@Sun.COM 		}
191510893SQuaker.Fang@Sun.COM 
191610893SQuaker.Fang@Sun.COM 		/*
191710893SQuaker.Fang@Sun.COM 		 * start automatic rate control
191810893SQuaker.Fang@Sun.COM 		 */
191910893SQuaker.Fang@Sun.COM 		if (IEEE80211_FIXED_RATE_NONE == ic->ic_fixed_rate) {
192010893SQuaker.Fang@Sun.COM 			atomic_or_32(&sc->sc_flags, IWP_F_RATE_AUTO_CTL);
192110893SQuaker.Fang@Sun.COM 
192210893SQuaker.Fang@Sun.COM 			/*
192310893SQuaker.Fang@Sun.COM 			 * set rate to some reasonable initial value
192410893SQuaker.Fang@Sun.COM 			 */
192510893SQuaker.Fang@Sun.COM 			i = in->in_rates.ir_nrates - 1;
192610893SQuaker.Fang@Sun.COM 			while (i > 0 && IEEE80211_RATE(i) > 72) {
192710893SQuaker.Fang@Sun.COM 				i--;
192810893SQuaker.Fang@Sun.COM 			}
192910893SQuaker.Fang@Sun.COM 			in->in_txrate = i;
193010893SQuaker.Fang@Sun.COM 
193110893SQuaker.Fang@Sun.COM 		} else {
193210893SQuaker.Fang@Sun.COM 			atomic_and_32(&sc->sc_flags, ~IWP_F_RATE_AUTO_CTL);
193310893SQuaker.Fang@Sun.COM 		}
193410893SQuaker.Fang@Sun.COM 
193510893SQuaker.Fang@Sun.COM 		/*
193610893SQuaker.Fang@Sun.COM 		 * set LED on after associated
193710893SQuaker.Fang@Sun.COM 		 */
193810893SQuaker.Fang@Sun.COM 		iwp_set_led(sc, 2, 0, 1);
193910893SQuaker.Fang@Sun.COM 		break;
194010893SQuaker.Fang@Sun.COM 
194110893SQuaker.Fang@Sun.COM 	case IEEE80211_S_INIT:
194210893SQuaker.Fang@Sun.COM 		if (ostate == IEEE80211_S_SCAN) {
194310893SQuaker.Fang@Sun.COM 			atomic_and_32(&sc->sc_flags, ~IWP_F_SCANNING);
194410893SQuaker.Fang@Sun.COM 		}
194510893SQuaker.Fang@Sun.COM 		/*
194610893SQuaker.Fang@Sun.COM 		 * set LED off after init
194710893SQuaker.Fang@Sun.COM 		 */
194810893SQuaker.Fang@Sun.COM 		iwp_set_led(sc, 2, 1, 0);
194910893SQuaker.Fang@Sun.COM 		break;
195010893SQuaker.Fang@Sun.COM 
195110893SQuaker.Fang@Sun.COM 	case IEEE80211_S_ASSOC:
195210893SQuaker.Fang@Sun.COM 		if (ostate == IEEE80211_S_SCAN) {
195310893SQuaker.Fang@Sun.COM 			atomic_and_32(&sc->sc_flags, ~IWP_F_SCANNING);
195410893SQuaker.Fang@Sun.COM 		}
195510893SQuaker.Fang@Sun.COM 		break;
195610893SQuaker.Fang@Sun.COM 	}
195710893SQuaker.Fang@Sun.COM 
195810893SQuaker.Fang@Sun.COM 	mutex_exit(&sc->sc_glock);
195910893SQuaker.Fang@Sun.COM 
196010893SQuaker.Fang@Sun.COM 	return (sc->sc_newstate(ic, nstate, arg));
196110893SQuaker.Fang@Sun.COM }
196210893SQuaker.Fang@Sun.COM 
196310893SQuaker.Fang@Sun.COM /*
196410893SQuaker.Fang@Sun.COM  * exclusive access to mac begin.
196510893SQuaker.Fang@Sun.COM  */
196610893SQuaker.Fang@Sun.COM static void
iwp_mac_access_enter(iwp_sc_t * sc)196710893SQuaker.Fang@Sun.COM iwp_mac_access_enter(iwp_sc_t *sc)
196810893SQuaker.Fang@Sun.COM {
196910893SQuaker.Fang@Sun.COM 	uint32_t tmp;
197010893SQuaker.Fang@Sun.COM 	int n;
197110893SQuaker.Fang@Sun.COM 
197210893SQuaker.Fang@Sun.COM 	tmp = IWP_READ(sc, CSR_GP_CNTRL);
197310893SQuaker.Fang@Sun.COM 	IWP_WRITE(sc, CSR_GP_CNTRL,
197410893SQuaker.Fang@Sun.COM 	    tmp | CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
197510893SQuaker.Fang@Sun.COM 
197610893SQuaker.Fang@Sun.COM 	/* wait until we succeed */
197710893SQuaker.Fang@Sun.COM 	for (n = 0; n < 1000; n++) {
197810893SQuaker.Fang@Sun.COM 		if ((IWP_READ(sc, CSR_GP_CNTRL) &
197910893SQuaker.Fang@Sun.COM 		    (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY |
198010893SQuaker.Fang@Sun.COM 		    CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP)) ==
198110893SQuaker.Fang@Sun.COM 		    CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN) {
198210893SQuaker.Fang@Sun.COM 			break;
198310893SQuaker.Fang@Sun.COM 		}
198410893SQuaker.Fang@Sun.COM 		DELAY(10);
198510893SQuaker.Fang@Sun.COM 	}
198610893SQuaker.Fang@Sun.COM 
198710893SQuaker.Fang@Sun.COM #ifdef	DEBUG
198810893SQuaker.Fang@Sun.COM 	if (1000 == n) {
198910893SQuaker.Fang@Sun.COM 		IWP_DBG((IWP_DEBUG_PIO, "iwp_mac_access_enter(): "
199010893SQuaker.Fang@Sun.COM 		    "could not lock memory\n"));
199110893SQuaker.Fang@Sun.COM 	}
199210893SQuaker.Fang@Sun.COM #endif
199310893SQuaker.Fang@Sun.COM }
199410893SQuaker.Fang@Sun.COM 
199510893SQuaker.Fang@Sun.COM /*
199610893SQuaker.Fang@Sun.COM  * exclusive access to mac end.
199710893SQuaker.Fang@Sun.COM  */
199810893SQuaker.Fang@Sun.COM static void
iwp_mac_access_exit(iwp_sc_t * sc)199910893SQuaker.Fang@Sun.COM iwp_mac_access_exit(iwp_sc_t *sc)
200010893SQuaker.Fang@Sun.COM {
200110893SQuaker.Fang@Sun.COM 	uint32_t tmp = IWP_READ(sc, CSR_GP_CNTRL);
200210893SQuaker.Fang@Sun.COM 	IWP_WRITE(sc, CSR_GP_CNTRL,
200310893SQuaker.Fang@Sun.COM 	    tmp & ~CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
200410893SQuaker.Fang@Sun.COM }
200510893SQuaker.Fang@Sun.COM 
200610893SQuaker.Fang@Sun.COM /*
200710893SQuaker.Fang@Sun.COM  * this function defined here for future use.
200810893SQuaker.Fang@Sun.COM  * static uint32_t
200910893SQuaker.Fang@Sun.COM  * iwp_mem_read(iwp_sc_t *sc, uint32_t addr)
201010893SQuaker.Fang@Sun.COM  * {
201110893SQuaker.Fang@Sun.COM  * 	IWP_WRITE(sc, HBUS_TARG_MEM_RADDR, addr);
201210893SQuaker.Fang@Sun.COM  * 	return (IWP_READ(sc, HBUS_TARG_MEM_RDAT));
201310893SQuaker.Fang@Sun.COM  * }
201410893SQuaker.Fang@Sun.COM  */
201510893SQuaker.Fang@Sun.COM 
201610893SQuaker.Fang@Sun.COM /*
201710893SQuaker.Fang@Sun.COM  * write mac memory
201810893SQuaker.Fang@Sun.COM  */
201910893SQuaker.Fang@Sun.COM static void
iwp_mem_write(iwp_sc_t * sc,uint32_t addr,uint32_t data)202010893SQuaker.Fang@Sun.COM iwp_mem_write(iwp_sc_t *sc, uint32_t addr, uint32_t data)
202110893SQuaker.Fang@Sun.COM {
202210893SQuaker.Fang@Sun.COM 	IWP_WRITE(sc, HBUS_TARG_MEM_WADDR, addr);
202310893SQuaker.Fang@Sun.COM 	IWP_WRITE(sc, HBUS_TARG_MEM_WDAT, data);
202410893SQuaker.Fang@Sun.COM }
202510893SQuaker.Fang@Sun.COM 
202610893SQuaker.Fang@Sun.COM /*
202710893SQuaker.Fang@Sun.COM  * read mac register
202810893SQuaker.Fang@Sun.COM  */
202910893SQuaker.Fang@Sun.COM static uint32_t
iwp_reg_read(iwp_sc_t * sc,uint32_t addr)203010893SQuaker.Fang@Sun.COM iwp_reg_read(iwp_sc_t *sc, uint32_t addr)
203110893SQuaker.Fang@Sun.COM {
203210893SQuaker.Fang@Sun.COM 	IWP_WRITE(sc, HBUS_TARG_PRPH_RADDR, addr | (3 << 24));
203310893SQuaker.Fang@Sun.COM 	return (IWP_READ(sc, HBUS_TARG_PRPH_RDAT));
203410893SQuaker.Fang@Sun.COM }
203510893SQuaker.Fang@Sun.COM 
203610893SQuaker.Fang@Sun.COM /*
203710893SQuaker.Fang@Sun.COM  * write mac register
203810893SQuaker.Fang@Sun.COM  */
203910893SQuaker.Fang@Sun.COM static void
iwp_reg_write(iwp_sc_t * sc,uint32_t addr,uint32_t data)204010893SQuaker.Fang@Sun.COM iwp_reg_write(iwp_sc_t *sc, uint32_t addr, uint32_t data)
204110893SQuaker.Fang@Sun.COM {
204210893SQuaker.Fang@Sun.COM 	IWP_WRITE(sc, HBUS_TARG_PRPH_WADDR, addr | (3 << 24));
204310893SQuaker.Fang@Sun.COM 	IWP_WRITE(sc, HBUS_TARG_PRPH_WDAT, data);
204410893SQuaker.Fang@Sun.COM }
204510893SQuaker.Fang@Sun.COM 
204610893SQuaker.Fang@Sun.COM 
204710893SQuaker.Fang@Sun.COM /*
204810893SQuaker.Fang@Sun.COM  * steps of loading ucode:
204910893SQuaker.Fang@Sun.COM  * load init ucode=>init alive=>calibrate=>
205010893SQuaker.Fang@Sun.COM  * receive calibration result=>reinitialize NIC=>
205110893SQuaker.Fang@Sun.COM  * load runtime ucode=>runtime alive=>
205210893SQuaker.Fang@Sun.COM  * send calibration result=>running.
205310893SQuaker.Fang@Sun.COM  */
205410893SQuaker.Fang@Sun.COM static int
iwp_load_init_firmware(iwp_sc_t * sc)205510893SQuaker.Fang@Sun.COM iwp_load_init_firmware(iwp_sc_t *sc)
205610893SQuaker.Fang@Sun.COM {
205710893SQuaker.Fang@Sun.COM 	int	err = IWP_FAIL;
205810893SQuaker.Fang@Sun.COM 	clock_t	clk;
205910893SQuaker.Fang@Sun.COM 
206010893SQuaker.Fang@Sun.COM 	atomic_and_32(&sc->sc_flags, ~IWP_F_PUT_SEG);
206110893SQuaker.Fang@Sun.COM 
206210893SQuaker.Fang@Sun.COM 	/*
206310893SQuaker.Fang@Sun.COM 	 * load init_text section of uCode to hardware
206410893SQuaker.Fang@Sun.COM 	 */
206510893SQuaker.Fang@Sun.COM 	err = iwp_put_seg_fw(sc, sc->sc_dma_fw_init_text.cookie.dmac_address,
206610893SQuaker.Fang@Sun.COM 	    RTC_INST_LOWER_BOUND, sc->sc_dma_fw_init_text.cookie.dmac_size);
206710893SQuaker.Fang@Sun.COM 	if (err != IWP_SUCCESS) {
206810893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_load_init_firmware(): "
206910893SQuaker.Fang@Sun.COM 		    "failed to write init uCode.\n");
207010893SQuaker.Fang@Sun.COM 		return (err);
207110893SQuaker.Fang@Sun.COM 	}
207210893SQuaker.Fang@Sun.COM 
207310893SQuaker.Fang@Sun.COM 	clk = ddi_get_lbolt() + drv_usectohz(1000000);
207410893SQuaker.Fang@Sun.COM 
207510893SQuaker.Fang@Sun.COM 	/* wait loading init_text until completed or timeout */
207610893SQuaker.Fang@Sun.COM 	while (!(sc->sc_flags & IWP_F_PUT_SEG)) {
207710893SQuaker.Fang@Sun.COM 		if (cv_timedwait(&sc->sc_put_seg_cv, &sc->sc_glock, clk) < 0) {
207810893SQuaker.Fang@Sun.COM 			break;
207910893SQuaker.Fang@Sun.COM 		}
208010893SQuaker.Fang@Sun.COM 	}
208110893SQuaker.Fang@Sun.COM 
208210893SQuaker.Fang@Sun.COM 	if (!(sc->sc_flags & IWP_F_PUT_SEG)) {
208310893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_load_init_firmware(): "
208410893SQuaker.Fang@Sun.COM 		    "timeout waiting for init uCode load.\n");
208510893SQuaker.Fang@Sun.COM 		return (IWP_FAIL);
208610893SQuaker.Fang@Sun.COM 	}
208710893SQuaker.Fang@Sun.COM 
208810893SQuaker.Fang@Sun.COM 	atomic_and_32(&sc->sc_flags, ~IWP_F_PUT_SEG);
208910893SQuaker.Fang@Sun.COM 
209010893SQuaker.Fang@Sun.COM 	/*
209110893SQuaker.Fang@Sun.COM 	 * load init_data section of uCode to hardware
209210893SQuaker.Fang@Sun.COM 	 */
209310893SQuaker.Fang@Sun.COM 	err = iwp_put_seg_fw(sc, sc->sc_dma_fw_init_data.cookie.dmac_address,
209410893SQuaker.Fang@Sun.COM 	    RTC_DATA_LOWER_BOUND, sc->sc_dma_fw_init_data.cookie.dmac_size);
209510893SQuaker.Fang@Sun.COM 	if (err != IWP_SUCCESS) {
209610893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_load_init_firmware(): "
209710893SQuaker.Fang@Sun.COM 		    "failed to write init_data uCode.\n");
209810893SQuaker.Fang@Sun.COM 		return (err);
209910893SQuaker.Fang@Sun.COM 	}
210010893SQuaker.Fang@Sun.COM 
210110893SQuaker.Fang@Sun.COM 	clk = ddi_get_lbolt() + drv_usectohz(1000000);
210210893SQuaker.Fang@Sun.COM 
210310893SQuaker.Fang@Sun.COM 	/*
210410893SQuaker.Fang@Sun.COM 	 * wait loading init_data until completed or timeout
210510893SQuaker.Fang@Sun.COM 	 */
210610893SQuaker.Fang@Sun.COM 	while (!(sc->sc_flags & IWP_F_PUT_SEG)) {
210710893SQuaker.Fang@Sun.COM 		if (cv_timedwait(&sc->sc_put_seg_cv, &sc->sc_glock, clk) < 0) {
210810893SQuaker.Fang@Sun.COM 			break;
210910893SQuaker.Fang@Sun.COM 		}
211010893SQuaker.Fang@Sun.COM 	}
211110893SQuaker.Fang@Sun.COM 
211210893SQuaker.Fang@Sun.COM 	if (!(sc->sc_flags & IWP_F_PUT_SEG)) {
211310893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_load_init_firmware(): "
211410893SQuaker.Fang@Sun.COM 		    "timeout waiting for init_data uCode load.\n");
211510893SQuaker.Fang@Sun.COM 		return (IWP_FAIL);
211610893SQuaker.Fang@Sun.COM 	}
211710893SQuaker.Fang@Sun.COM 
211810893SQuaker.Fang@Sun.COM 	atomic_and_32(&sc->sc_flags, ~IWP_F_PUT_SEG);
211910893SQuaker.Fang@Sun.COM 
212010893SQuaker.Fang@Sun.COM 	return (err);
212110893SQuaker.Fang@Sun.COM }
212210893SQuaker.Fang@Sun.COM 
212310893SQuaker.Fang@Sun.COM static int
iwp_load_run_firmware(iwp_sc_t * sc)212410893SQuaker.Fang@Sun.COM iwp_load_run_firmware(iwp_sc_t *sc)
212510893SQuaker.Fang@Sun.COM {
212610893SQuaker.Fang@Sun.COM 	int	err = IWP_FAIL;
212710893SQuaker.Fang@Sun.COM 	clock_t	clk;
212810893SQuaker.Fang@Sun.COM 
212910893SQuaker.Fang@Sun.COM 	atomic_and_32(&sc->sc_flags, ~IWP_F_PUT_SEG);
213010893SQuaker.Fang@Sun.COM 
213110893SQuaker.Fang@Sun.COM 	/*
213210893SQuaker.Fang@Sun.COM 	 * load init_text section of uCode to hardware
213310893SQuaker.Fang@Sun.COM 	 */
213410893SQuaker.Fang@Sun.COM 	err = iwp_put_seg_fw(sc, sc->sc_dma_fw_text.cookie.dmac_address,
213510893SQuaker.Fang@Sun.COM 	    RTC_INST_LOWER_BOUND, sc->sc_dma_fw_text.cookie.dmac_size);
213610893SQuaker.Fang@Sun.COM 	if (err != IWP_SUCCESS) {
213710893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_load_run_firmware(): "
213810893SQuaker.Fang@Sun.COM 		    "failed to write run uCode.\n");
213910893SQuaker.Fang@Sun.COM 		return (err);
214010893SQuaker.Fang@Sun.COM 	}
214110893SQuaker.Fang@Sun.COM 
214210893SQuaker.Fang@Sun.COM 	clk = ddi_get_lbolt() + drv_usectohz(1000000);
214310893SQuaker.Fang@Sun.COM 
214410893SQuaker.Fang@Sun.COM 	/* wait loading run_text until completed or timeout */
214510893SQuaker.Fang@Sun.COM 	while (!(sc->sc_flags & IWP_F_PUT_SEG)) {
214610893SQuaker.Fang@Sun.COM 		if (cv_timedwait(&sc->sc_put_seg_cv, &sc->sc_glock, clk) < 0) {
214710893SQuaker.Fang@Sun.COM 			break;
214810893SQuaker.Fang@Sun.COM 		}
214910893SQuaker.Fang@Sun.COM 	}
215010893SQuaker.Fang@Sun.COM 
215110893SQuaker.Fang@Sun.COM 	if (!(sc->sc_flags & IWP_F_PUT_SEG)) {
215210893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_load_run_firmware(): "
215310893SQuaker.Fang@Sun.COM 		    "timeout waiting for run uCode load.\n");
215410893SQuaker.Fang@Sun.COM 		return (IWP_FAIL);
215510893SQuaker.Fang@Sun.COM 	}
215610893SQuaker.Fang@Sun.COM 
215710893SQuaker.Fang@Sun.COM 	atomic_and_32(&sc->sc_flags, ~IWP_F_PUT_SEG);
215810893SQuaker.Fang@Sun.COM 
215910893SQuaker.Fang@Sun.COM 	/*
216010893SQuaker.Fang@Sun.COM 	 * load run_data section of uCode to hardware
216110893SQuaker.Fang@Sun.COM 	 */
216210893SQuaker.Fang@Sun.COM 	err = iwp_put_seg_fw(sc, sc->sc_dma_fw_data_bak.cookie.dmac_address,
216310893SQuaker.Fang@Sun.COM 	    RTC_DATA_LOWER_BOUND, sc->sc_dma_fw_data.cookie.dmac_size);
216410893SQuaker.Fang@Sun.COM 	if (err != IWP_SUCCESS) {
216510893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_load_run_firmware(): "
216610893SQuaker.Fang@Sun.COM 		    "failed to write run_data uCode.\n");
216710893SQuaker.Fang@Sun.COM 		return (err);
216810893SQuaker.Fang@Sun.COM 	}
216910893SQuaker.Fang@Sun.COM 
217010893SQuaker.Fang@Sun.COM 	clk = ddi_get_lbolt() + drv_usectohz(1000000);
217110893SQuaker.Fang@Sun.COM 
217210893SQuaker.Fang@Sun.COM 	/*
217310893SQuaker.Fang@Sun.COM 	 * wait loading run_data until completed or timeout
217410893SQuaker.Fang@Sun.COM 	 */
217510893SQuaker.Fang@Sun.COM 	while (!(sc->sc_flags & IWP_F_PUT_SEG)) {
217610893SQuaker.Fang@Sun.COM 		if (cv_timedwait(&sc->sc_put_seg_cv, &sc->sc_glock, clk) < 0) {
217710893SQuaker.Fang@Sun.COM 			break;
217810893SQuaker.Fang@Sun.COM 		}
217910893SQuaker.Fang@Sun.COM 	}
218010893SQuaker.Fang@Sun.COM 
218110893SQuaker.Fang@Sun.COM 	if (!(sc->sc_flags & IWP_F_PUT_SEG)) {
218210893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_load_run_firmware(): "
218310893SQuaker.Fang@Sun.COM 		    "timeout waiting for run_data uCode load.\n");
218410893SQuaker.Fang@Sun.COM 		return (IWP_FAIL);
218510893SQuaker.Fang@Sun.COM 	}
218610893SQuaker.Fang@Sun.COM 
218710893SQuaker.Fang@Sun.COM 	atomic_and_32(&sc->sc_flags, ~IWP_F_PUT_SEG);
218810893SQuaker.Fang@Sun.COM 
218910893SQuaker.Fang@Sun.COM 	return (err);
219010893SQuaker.Fang@Sun.COM }
219110893SQuaker.Fang@Sun.COM 
219210893SQuaker.Fang@Sun.COM /*
219310893SQuaker.Fang@Sun.COM  * this function will be invoked to receive phy information
219410893SQuaker.Fang@Sun.COM  * when a frame is received.
219510893SQuaker.Fang@Sun.COM  */
219610893SQuaker.Fang@Sun.COM static void
iwp_rx_phy_intr(iwp_sc_t * sc,iwp_rx_desc_t * desc)219710893SQuaker.Fang@Sun.COM iwp_rx_phy_intr(iwp_sc_t *sc, iwp_rx_desc_t *desc)
219810893SQuaker.Fang@Sun.COM {
219910893SQuaker.Fang@Sun.COM 
220010893SQuaker.Fang@Sun.COM 	sc->sc_rx_phy_res.flag = 1;
220110893SQuaker.Fang@Sun.COM 
220210893SQuaker.Fang@Sun.COM 	(void) memcpy(sc->sc_rx_phy_res.buf, (uint8_t *)(desc + 1),
220310893SQuaker.Fang@Sun.COM 	    sizeof (iwp_rx_phy_res_t));
220410893SQuaker.Fang@Sun.COM }
220510893SQuaker.Fang@Sun.COM 
220610893SQuaker.Fang@Sun.COM /*
220710893SQuaker.Fang@Sun.COM  * this function will be invoked to receive body of frame when
220810893SQuaker.Fang@Sun.COM  * a frame is received.
220910893SQuaker.Fang@Sun.COM  */
221010893SQuaker.Fang@Sun.COM static void
iwp_rx_mpdu_intr(iwp_sc_t * sc,iwp_rx_desc_t * desc)221110893SQuaker.Fang@Sun.COM iwp_rx_mpdu_intr(iwp_sc_t *sc, iwp_rx_desc_t *desc)
221210893SQuaker.Fang@Sun.COM {
221310893SQuaker.Fang@Sun.COM 	ieee80211com_t	*ic = &sc->sc_ic;
221410893SQuaker.Fang@Sun.COM #ifdef	DEBUG
221510893SQuaker.Fang@Sun.COM 	iwp_rx_ring_t	*ring = &sc->sc_rxq;
221610893SQuaker.Fang@Sun.COM #endif
221710893SQuaker.Fang@Sun.COM 	struct ieee80211_frame		*wh;
221810893SQuaker.Fang@Sun.COM 	struct iwp_rx_non_cfg_phy	*phyinfo;
221910893SQuaker.Fang@Sun.COM 	struct	iwp_rx_mpdu_body_size	*mpdu_size;
222010893SQuaker.Fang@Sun.COM 
222110893SQuaker.Fang@Sun.COM 	mblk_t			*mp;
222210893SQuaker.Fang@Sun.COM 	int16_t			t;
222310893SQuaker.Fang@Sun.COM 	uint16_t		len, rssi, agc;
222410893SQuaker.Fang@Sun.COM 	uint32_t		temp, crc, *tail;
222510893SQuaker.Fang@Sun.COM 	uint32_t		arssi, brssi, crssi, mrssi;
222610893SQuaker.Fang@Sun.COM 	iwp_rx_phy_res_t	*stat;
222710893SQuaker.Fang@Sun.COM 	ieee80211_node_t	*in;
222810893SQuaker.Fang@Sun.COM 
222910893SQuaker.Fang@Sun.COM 	/*
223010893SQuaker.Fang@Sun.COM 	 * assuming not 11n here. cope with 11n in phase-II
223110893SQuaker.Fang@Sun.COM 	 */
223210893SQuaker.Fang@Sun.COM 	mpdu_size = (struct iwp_rx_mpdu_body_size *)(desc + 1);
223310893SQuaker.Fang@Sun.COM 	stat = (iwp_rx_phy_res_t *)sc->sc_rx_phy_res.buf;
223410893SQuaker.Fang@Sun.COM 	if (stat->cfg_phy_cnt > 20) {
223510893SQuaker.Fang@Sun.COM 		return;
223610893SQuaker.Fang@Sun.COM 	}
223710893SQuaker.Fang@Sun.COM 
223810893SQuaker.Fang@Sun.COM 	phyinfo = (struct iwp_rx_non_cfg_phy *)stat->non_cfg_phy;
223910893SQuaker.Fang@Sun.COM 	temp = LE_32(phyinfo->non_cfg_phy[IWP_RX_RES_AGC_IDX]);
224010893SQuaker.Fang@Sun.COM 	agc = (temp & IWP_OFDM_AGC_MSK) >> IWP_OFDM_AGC_BIT_POS;
224110893SQuaker.Fang@Sun.COM 
224210893SQuaker.Fang@Sun.COM 	temp = LE_32(phyinfo->non_cfg_phy[IWP_RX_RES_RSSI_AB_IDX]);
224310893SQuaker.Fang@Sun.COM 	arssi = (temp & IWP_OFDM_RSSI_A_MSK) >> IWP_OFDM_RSSI_A_BIT_POS;
224410893SQuaker.Fang@Sun.COM 	brssi = (temp & IWP_OFDM_RSSI_B_MSK) >> IWP_OFDM_RSSI_B_BIT_POS;
224510893SQuaker.Fang@Sun.COM 
224610893SQuaker.Fang@Sun.COM 	temp = LE_32(phyinfo->non_cfg_phy[IWP_RX_RES_RSSI_C_IDX]);
224710893SQuaker.Fang@Sun.COM 	crssi = (temp & IWP_OFDM_RSSI_C_MSK) >> IWP_OFDM_RSSI_C_BIT_POS;
224810893SQuaker.Fang@Sun.COM 
224910893SQuaker.Fang@Sun.COM 	mrssi = MAX(arssi, brssi);
225010893SQuaker.Fang@Sun.COM 	mrssi = MAX(mrssi, crssi);
225110893SQuaker.Fang@Sun.COM 
225210893SQuaker.Fang@Sun.COM 	t = mrssi - agc - IWP_RSSI_OFFSET;
225310893SQuaker.Fang@Sun.COM 	/*
225410893SQuaker.Fang@Sun.COM 	 * convert dBm to percentage
225510893SQuaker.Fang@Sun.COM 	 */
225610893SQuaker.Fang@Sun.COM 	rssi = (100 * 75 * 75 - (-20 - t) * (15 * 75 + 62 * (-20 - t)))
225710893SQuaker.Fang@Sun.COM 	    / (75 * 75);
225810893SQuaker.Fang@Sun.COM 	if (rssi > 100) {
225910893SQuaker.Fang@Sun.COM 		rssi = 100;
226010893SQuaker.Fang@Sun.COM 	}
226110893SQuaker.Fang@Sun.COM 	if (rssi < 1) {
226210893SQuaker.Fang@Sun.COM 		rssi = 1;
226310893SQuaker.Fang@Sun.COM 	}
226410893SQuaker.Fang@Sun.COM 
226510893SQuaker.Fang@Sun.COM 	/*
226610893SQuaker.Fang@Sun.COM 	 * size of frame, not include FCS
226710893SQuaker.Fang@Sun.COM 	 */
226810893SQuaker.Fang@Sun.COM 	len = LE_16(mpdu_size->byte_count);
226910893SQuaker.Fang@Sun.COM 	tail = (uint32_t *)((uint8_t *)(desc + 1) +
227010893SQuaker.Fang@Sun.COM 	    sizeof (struct iwp_rx_mpdu_body_size) + len);
227110893SQuaker.Fang@Sun.COM 	bcopy(tail, &crc, 4);
227210893SQuaker.Fang@Sun.COM 
227310893SQuaker.Fang@Sun.COM 	IWP_DBG((IWP_DEBUG_RX, "iwp_rx_mpdu_intr(): "
227410893SQuaker.Fang@Sun.COM 	    "rx intr: idx=%d phy_len=%x len=%d "
227510893SQuaker.Fang@Sun.COM 	    "rate=%x chan=%d tstamp=%x non_cfg_phy_count=%x "
227610893SQuaker.Fang@Sun.COM 	    "cfg_phy_count=%x tail=%x", ring->cur, sizeof (*stat),
227710893SQuaker.Fang@Sun.COM 	    len, stat->rate.r.s.rate, stat->channel,
227810893SQuaker.Fang@Sun.COM 	    LE_32(stat->timestampl), stat->non_cfg_phy_cnt,
227910893SQuaker.Fang@Sun.COM 	    stat->cfg_phy_cnt, LE_32(crc)));
228010893SQuaker.Fang@Sun.COM 
228110893SQuaker.Fang@Sun.COM 	if ((len < 16) || (len > sc->sc_dmabuf_sz)) {
228210893SQuaker.Fang@Sun.COM 		IWP_DBG((IWP_DEBUG_RX, "iwp_rx_mpdu_intr(): "
228310893SQuaker.Fang@Sun.COM 		    "rx frame oversize\n"));
228410893SQuaker.Fang@Sun.COM 		return;
228510893SQuaker.Fang@Sun.COM 	}
228610893SQuaker.Fang@Sun.COM 
228710893SQuaker.Fang@Sun.COM 	/*
228810893SQuaker.Fang@Sun.COM 	 * discard Rx frames with bad CRC
228910893SQuaker.Fang@Sun.COM 	 */
229010893SQuaker.Fang@Sun.COM 	if ((LE_32(crc) &
229110893SQuaker.Fang@Sun.COM 	    (RX_RES_STATUS_NO_CRC32_ERROR | RX_RES_STATUS_NO_RXE_OVERFLOW)) !=
229210893SQuaker.Fang@Sun.COM 	    (RX_RES_STATUS_NO_CRC32_ERROR | RX_RES_STATUS_NO_RXE_OVERFLOW)) {
229310893SQuaker.Fang@Sun.COM 		IWP_DBG((IWP_DEBUG_RX, "iwp_rx_mpdu_intr(): "
229410893SQuaker.Fang@Sun.COM 		    "rx crc error tail: %x\n",
229510893SQuaker.Fang@Sun.COM 		    LE_32(crc)));
229610893SQuaker.Fang@Sun.COM 		sc->sc_rx_err++;
229710893SQuaker.Fang@Sun.COM 		return;
229810893SQuaker.Fang@Sun.COM 	}
229910893SQuaker.Fang@Sun.COM 
230010893SQuaker.Fang@Sun.COM 	wh = (struct ieee80211_frame *)
230110893SQuaker.Fang@Sun.COM 	    ((uint8_t *)(desc + 1)+ sizeof (struct iwp_rx_mpdu_body_size));
230210893SQuaker.Fang@Sun.COM 
230310893SQuaker.Fang@Sun.COM 	if (IEEE80211_FC0_SUBTYPE_ASSOC_RESP == *(uint8_t *)wh) {
230410893SQuaker.Fang@Sun.COM 		sc->sc_assoc_id = *((uint16_t *)(wh + 1) + 2);
230510893SQuaker.Fang@Sun.COM 		IWP_DBG((IWP_DEBUG_RX, "iwp_rx_mpdu_intr(): "
230610893SQuaker.Fang@Sun.COM 		    "rx : association id = %x\n",
230710893SQuaker.Fang@Sun.COM 		    sc->sc_assoc_id));
230810893SQuaker.Fang@Sun.COM 	}
230910893SQuaker.Fang@Sun.COM 
231010893SQuaker.Fang@Sun.COM #ifdef DEBUG
231110893SQuaker.Fang@Sun.COM 	if (iwp_dbg_flags & IWP_DEBUG_RX) {
231210893SQuaker.Fang@Sun.COM 		ieee80211_dump_pkt((uint8_t *)wh, len, 0, 0);
231310893SQuaker.Fang@Sun.COM 	}
231410893SQuaker.Fang@Sun.COM #endif
231510893SQuaker.Fang@Sun.COM 
231610893SQuaker.Fang@Sun.COM 	in = ieee80211_find_rxnode(ic, wh);
231710893SQuaker.Fang@Sun.COM 	mp = allocb(len, BPRI_MED);
231810893SQuaker.Fang@Sun.COM 	if (mp) {
231910893SQuaker.Fang@Sun.COM 		(void) memcpy(mp->b_wptr, wh, len);
232010893SQuaker.Fang@Sun.COM 		mp->b_wptr += len;
232110893SQuaker.Fang@Sun.COM 
232210893SQuaker.Fang@Sun.COM 		/*
232310893SQuaker.Fang@Sun.COM 		 * send the frame to the 802.11 layer
232410893SQuaker.Fang@Sun.COM 		 */
232510893SQuaker.Fang@Sun.COM 		(void) ieee80211_input(ic, mp, in, rssi, 0);
232610893SQuaker.Fang@Sun.COM 	} else {
232710893SQuaker.Fang@Sun.COM 		sc->sc_rx_nobuf++;
232810893SQuaker.Fang@Sun.COM 		IWP_DBG((IWP_DEBUG_RX, "iwp_rx_mpdu_intr(): "
232910893SQuaker.Fang@Sun.COM 		    "alloc rx buf failed\n"));
233010893SQuaker.Fang@Sun.COM 	}
233110893SQuaker.Fang@Sun.COM 
233210893SQuaker.Fang@Sun.COM 	/*
233310893SQuaker.Fang@Sun.COM 	 * release node reference
233410893SQuaker.Fang@Sun.COM 	 */
233510893SQuaker.Fang@Sun.COM 	ieee80211_free_node(in);
233610893SQuaker.Fang@Sun.COM }
233710893SQuaker.Fang@Sun.COM 
233810893SQuaker.Fang@Sun.COM /*
233910893SQuaker.Fang@Sun.COM  * process correlative affairs after a frame is sent.
234010893SQuaker.Fang@Sun.COM  */
234110893SQuaker.Fang@Sun.COM static void
iwp_tx_intr(iwp_sc_t * sc,iwp_rx_desc_t * desc)234210893SQuaker.Fang@Sun.COM iwp_tx_intr(iwp_sc_t *sc, iwp_rx_desc_t *desc)
234310893SQuaker.Fang@Sun.COM {
234410893SQuaker.Fang@Sun.COM 	ieee80211com_t *ic = &sc->sc_ic;
234510893SQuaker.Fang@Sun.COM 	iwp_tx_ring_t *ring = &sc->sc_txq[desc->hdr.qid & 0x3];
234610893SQuaker.Fang@Sun.COM 	iwp_tx_stat_t *stat = (iwp_tx_stat_t *)(desc + 1);
234710893SQuaker.Fang@Sun.COM 	iwp_amrr_t *amrr;
234810893SQuaker.Fang@Sun.COM 
234910893SQuaker.Fang@Sun.COM 	if (NULL == ic->ic_bss) {
235010893SQuaker.Fang@Sun.COM 		return;
235110893SQuaker.Fang@Sun.COM 	}
235210893SQuaker.Fang@Sun.COM 
235310893SQuaker.Fang@Sun.COM 	amrr = (iwp_amrr_t *)ic->ic_bss;
235410893SQuaker.Fang@Sun.COM 
235510893SQuaker.Fang@Sun.COM 	amrr->txcnt++;
235610893SQuaker.Fang@Sun.COM 	IWP_DBG((IWP_DEBUG_RATECTL, "iwp_tx_intr(): "
235710893SQuaker.Fang@Sun.COM 	    "tx: %d cnt\n", amrr->txcnt));
235810893SQuaker.Fang@Sun.COM 
235910893SQuaker.Fang@Sun.COM 	if (stat->ntries > 0) {
236010893SQuaker.Fang@Sun.COM 		amrr->retrycnt++;
236110893SQuaker.Fang@Sun.COM 		sc->sc_tx_retries++;
236210893SQuaker.Fang@Sun.COM 		IWP_DBG((IWP_DEBUG_TX, "iwp_tx_intr(): "
236310893SQuaker.Fang@Sun.COM 		    "tx: %d retries\n",
236410893SQuaker.Fang@Sun.COM 		    sc->sc_tx_retries));
236510893SQuaker.Fang@Sun.COM 	}
236610893SQuaker.Fang@Sun.COM 
236710893SQuaker.Fang@Sun.COM 	mutex_enter(&sc->sc_mt_lock);
236810893SQuaker.Fang@Sun.COM 	sc->sc_tx_timer = 0;
236910893SQuaker.Fang@Sun.COM 	mutex_exit(&sc->sc_mt_lock);
237010893SQuaker.Fang@Sun.COM 
237110893SQuaker.Fang@Sun.COM 	mutex_enter(&sc->sc_tx_lock);
237210893SQuaker.Fang@Sun.COM 
237310893SQuaker.Fang@Sun.COM 	ring->queued--;
237410893SQuaker.Fang@Sun.COM 	if (ring->queued < 0) {
237510893SQuaker.Fang@Sun.COM 		ring->queued = 0;
237610893SQuaker.Fang@Sun.COM 	}
237710893SQuaker.Fang@Sun.COM 
237810893SQuaker.Fang@Sun.COM 	if ((sc->sc_need_reschedule) && (ring->queued <= (ring->count >> 3))) {
237910893SQuaker.Fang@Sun.COM 		sc->sc_need_reschedule = 0;
238010893SQuaker.Fang@Sun.COM 		mutex_exit(&sc->sc_tx_lock);
238110893SQuaker.Fang@Sun.COM 		mac_tx_update(ic->ic_mach);
238210893SQuaker.Fang@Sun.COM 		mutex_enter(&sc->sc_tx_lock);
238310893SQuaker.Fang@Sun.COM 	}
238410893SQuaker.Fang@Sun.COM 
238510893SQuaker.Fang@Sun.COM 	mutex_exit(&sc->sc_tx_lock);
238610893SQuaker.Fang@Sun.COM }
238710893SQuaker.Fang@Sun.COM 
238810893SQuaker.Fang@Sun.COM /*
238910893SQuaker.Fang@Sun.COM  * inform a given command has been executed
239010893SQuaker.Fang@Sun.COM  */
239110893SQuaker.Fang@Sun.COM static void
iwp_cmd_intr(iwp_sc_t * sc,iwp_rx_desc_t * desc)239210893SQuaker.Fang@Sun.COM iwp_cmd_intr(iwp_sc_t *sc, iwp_rx_desc_t *desc)
239310893SQuaker.Fang@Sun.COM {
239410893SQuaker.Fang@Sun.COM 	if ((desc->hdr.qid & 7) != 4) {
239510893SQuaker.Fang@Sun.COM 		return;
239610893SQuaker.Fang@Sun.COM 	}
239710893SQuaker.Fang@Sun.COM 
239810893SQuaker.Fang@Sun.COM 	if (sc->sc_cmd_accum > 0) {
239910893SQuaker.Fang@Sun.COM 		sc->sc_cmd_accum--;
240010893SQuaker.Fang@Sun.COM 		return;
240110893SQuaker.Fang@Sun.COM 	}
240210893SQuaker.Fang@Sun.COM 
240310893SQuaker.Fang@Sun.COM 	mutex_enter(&sc->sc_glock);
240410893SQuaker.Fang@Sun.COM 
240510893SQuaker.Fang@Sun.COM 	sc->sc_cmd_flag = SC_CMD_FLG_DONE;
240610893SQuaker.Fang@Sun.COM 
240710893SQuaker.Fang@Sun.COM 	cv_signal(&sc->sc_cmd_cv);
240810893SQuaker.Fang@Sun.COM 
240910893SQuaker.Fang@Sun.COM 	mutex_exit(&sc->sc_glock);
241010893SQuaker.Fang@Sun.COM 
241110893SQuaker.Fang@Sun.COM 	IWP_DBG((IWP_DEBUG_CMD, "iwp_cmd_intr(): "
241210893SQuaker.Fang@Sun.COM 	    "qid=%x idx=%d flags=%x type=0x%x\n",
241310893SQuaker.Fang@Sun.COM 	    desc->hdr.qid, desc->hdr.idx, desc->hdr.flags,
241410893SQuaker.Fang@Sun.COM 	    desc->hdr.type));
241510893SQuaker.Fang@Sun.COM }
241610893SQuaker.Fang@Sun.COM 
241710893SQuaker.Fang@Sun.COM /*
241810893SQuaker.Fang@Sun.COM  * this function will be invoked when alive notification occur.
241910893SQuaker.Fang@Sun.COM  */
242010893SQuaker.Fang@Sun.COM static void
iwp_ucode_alive(iwp_sc_t * sc,iwp_rx_desc_t * desc)242110893SQuaker.Fang@Sun.COM iwp_ucode_alive(iwp_sc_t *sc, iwp_rx_desc_t *desc)
242210893SQuaker.Fang@Sun.COM {
242310893SQuaker.Fang@Sun.COM 	uint32_t rv;
242410893SQuaker.Fang@Sun.COM 	struct iwp_calib_cfg_cmd cmd;
242510893SQuaker.Fang@Sun.COM 	struct iwp_alive_resp *ar =
242610893SQuaker.Fang@Sun.COM 	    (struct iwp_alive_resp *)(desc + 1);
242710893SQuaker.Fang@Sun.COM 	struct iwp_calib_results *res_p = &sc->sc_calib_results;
242810893SQuaker.Fang@Sun.COM 
242910893SQuaker.Fang@Sun.COM 	/*
243010893SQuaker.Fang@Sun.COM 	 * the microcontroller is ready
243110893SQuaker.Fang@Sun.COM 	 */
243210893SQuaker.Fang@Sun.COM 	IWP_DBG((IWP_DEBUG_FW, "iwp_ucode_alive(): "
243310893SQuaker.Fang@Sun.COM 	    "microcode alive notification minor: %x major: %x type: "
243410893SQuaker.Fang@Sun.COM 	    "%x subtype: %x\n",
243510893SQuaker.Fang@Sun.COM 	    ar->ucode_minor, ar->ucode_minor, ar->ver_type, ar->ver_subtype));
243610893SQuaker.Fang@Sun.COM 
243710893SQuaker.Fang@Sun.COM #ifdef	DEBUG
243810893SQuaker.Fang@Sun.COM 	if (LE_32(ar->is_valid) != UCODE_VALID_OK) {
243910893SQuaker.Fang@Sun.COM 		IWP_DBG((IWP_DEBUG_FW, "iwp_ucode_alive(): "
244010893SQuaker.Fang@Sun.COM 		    "microcontroller initialization failed\n"));
244110893SQuaker.Fang@Sun.COM 	}
244210893SQuaker.Fang@Sun.COM #endif
244310893SQuaker.Fang@Sun.COM 
244410893SQuaker.Fang@Sun.COM 	/*
244510893SQuaker.Fang@Sun.COM 	 * determine if init alive or runtime alive.
244610893SQuaker.Fang@Sun.COM 	 */
244710893SQuaker.Fang@Sun.COM 	if (INITIALIZE_SUBTYPE == ar->ver_subtype) {
244810893SQuaker.Fang@Sun.COM 		IWP_DBG((IWP_DEBUG_FW, "iwp_ucode_alive(): "
244910893SQuaker.Fang@Sun.COM 		    "initialization alive received.\n"));
245010893SQuaker.Fang@Sun.COM 
245110893SQuaker.Fang@Sun.COM 		(void) memcpy(&sc->sc_card_alive_init, ar,
245210893SQuaker.Fang@Sun.COM 		    sizeof (struct iwp_init_alive_resp));
245310893SQuaker.Fang@Sun.COM 
245410893SQuaker.Fang@Sun.COM 		/*
245510893SQuaker.Fang@Sun.COM 		 * necessary configuration to NIC
245610893SQuaker.Fang@Sun.COM 		 */
245710893SQuaker.Fang@Sun.COM 		mutex_enter(&sc->sc_glock);
245810893SQuaker.Fang@Sun.COM 
245910893SQuaker.Fang@Sun.COM 		rv = iwp_alive_common(sc);
246010893SQuaker.Fang@Sun.COM 		if (rv != IWP_SUCCESS) {
246110893SQuaker.Fang@Sun.COM 			cmn_err(CE_WARN, "iwp_ucode_alive(): "
246210893SQuaker.Fang@Sun.COM 			    "common alive process failed in init alive.\n");
246310893SQuaker.Fang@Sun.COM 			mutex_exit(&sc->sc_glock);
246410893SQuaker.Fang@Sun.COM 			return;
246510893SQuaker.Fang@Sun.COM 		}
246610893SQuaker.Fang@Sun.COM 
246710893SQuaker.Fang@Sun.COM 		(void) memset(&cmd, 0, sizeof (cmd));
246810893SQuaker.Fang@Sun.COM 
246910893SQuaker.Fang@Sun.COM 		cmd.ucd_calib_cfg.once.is_enable = IWP_CALIB_INIT_CFG_ALL;
247010893SQuaker.Fang@Sun.COM 		cmd.ucd_calib_cfg.once.start = IWP_CALIB_INIT_CFG_ALL;
247110893SQuaker.Fang@Sun.COM 		cmd.ucd_calib_cfg.once.send_res = IWP_CALIB_INIT_CFG_ALL;
247210893SQuaker.Fang@Sun.COM 		cmd.ucd_calib_cfg.flags = IWP_CALIB_INIT_CFG_ALL;
247310893SQuaker.Fang@Sun.COM 
247410893SQuaker.Fang@Sun.COM 		/*
247510893SQuaker.Fang@Sun.COM 		 * require ucode execute calibration
247610893SQuaker.Fang@Sun.COM 		 */
247710893SQuaker.Fang@Sun.COM 		rv = iwp_cmd(sc, CALIBRATION_CFG_CMD, &cmd, sizeof (cmd), 1);
247810893SQuaker.Fang@Sun.COM 		if (rv != IWP_SUCCESS) {
247910893SQuaker.Fang@Sun.COM 			cmn_err(CE_WARN, "iwp_ucode_alive(): "
248010893SQuaker.Fang@Sun.COM 			    "failed to send calibration configure command.\n");
248110893SQuaker.Fang@Sun.COM 			mutex_exit(&sc->sc_glock);
248210893SQuaker.Fang@Sun.COM 			return;
248310893SQuaker.Fang@Sun.COM 		}
248410893SQuaker.Fang@Sun.COM 
248510893SQuaker.Fang@Sun.COM 		mutex_exit(&sc->sc_glock);
248610893SQuaker.Fang@Sun.COM 
248710893SQuaker.Fang@Sun.COM 	} else {	/* runtime alive */
248810893SQuaker.Fang@Sun.COM 
248910893SQuaker.Fang@Sun.COM 		IWP_DBG((IWP_DEBUG_FW, "iwp_ucode_alive(): "
249010893SQuaker.Fang@Sun.COM 		    "runtime alive received.\n"));
249110893SQuaker.Fang@Sun.COM 
249210893SQuaker.Fang@Sun.COM 		(void) memcpy(&sc->sc_card_alive_run, ar,
249310893SQuaker.Fang@Sun.COM 		    sizeof (struct iwp_alive_resp));
249410893SQuaker.Fang@Sun.COM 
249510893SQuaker.Fang@Sun.COM 		mutex_enter(&sc->sc_glock);
249610893SQuaker.Fang@Sun.COM 
249710893SQuaker.Fang@Sun.COM 		/*
249810893SQuaker.Fang@Sun.COM 		 * necessary configuration to NIC
249910893SQuaker.Fang@Sun.COM 		 */
250010893SQuaker.Fang@Sun.COM 		rv = iwp_alive_common(sc);
250110893SQuaker.Fang@Sun.COM 		if (rv != IWP_SUCCESS) {
250210893SQuaker.Fang@Sun.COM 			cmn_err(CE_WARN, "iwp_ucode_alive(): "
250310893SQuaker.Fang@Sun.COM 			    "common alive process failed in run alive.\n");
250410893SQuaker.Fang@Sun.COM 			mutex_exit(&sc->sc_glock);
250510893SQuaker.Fang@Sun.COM 			return;
250610893SQuaker.Fang@Sun.COM 		}
250710893SQuaker.Fang@Sun.COM 
250810893SQuaker.Fang@Sun.COM 		/*
250910893SQuaker.Fang@Sun.COM 		 * send the result of local oscilator calibration to uCode.
251010893SQuaker.Fang@Sun.COM 		 */
251110893SQuaker.Fang@Sun.COM 		if (res_p->lo_res != NULL) {
251210893SQuaker.Fang@Sun.COM 			rv = iwp_cmd(sc, REPLY_PHY_CALIBRATION_CMD,
251310893SQuaker.Fang@Sun.COM 			    res_p->lo_res, res_p->lo_res_len, 1);
251410893SQuaker.Fang@Sun.COM 			if (rv != IWP_SUCCESS) {
251510893SQuaker.Fang@Sun.COM 				cmn_err(CE_WARN, "iwp_ucode_alive(): "
251610893SQuaker.Fang@Sun.COM 				    "failed to send local"
251710893SQuaker.Fang@Sun.COM 				    "oscilator calibration command.\n");
251810893SQuaker.Fang@Sun.COM 				mutex_exit(&sc->sc_glock);
251910893SQuaker.Fang@Sun.COM 				return;
252010893SQuaker.Fang@Sun.COM 			}
252110893SQuaker.Fang@Sun.COM 
252210893SQuaker.Fang@Sun.COM 			DELAY(1000);
252310893SQuaker.Fang@Sun.COM 		}
252410893SQuaker.Fang@Sun.COM 
252510893SQuaker.Fang@Sun.COM 		/*
252610893SQuaker.Fang@Sun.COM 		 * send the result of TX IQ calibration to uCode.
252710893SQuaker.Fang@Sun.COM 		 */
252810893SQuaker.Fang@Sun.COM 		if (res_p->tx_iq_res != NULL) {
252910893SQuaker.Fang@Sun.COM 			rv = iwp_cmd(sc, REPLY_PHY_CALIBRATION_CMD,
253010893SQuaker.Fang@Sun.COM 			    res_p->tx_iq_res, res_p->tx_iq_res_len, 1);
253110893SQuaker.Fang@Sun.COM 			if (rv != IWP_SUCCESS) {
253210893SQuaker.Fang@Sun.COM 				cmn_err(CE_WARN, "iwp_ucode_alive(): "
253310893SQuaker.Fang@Sun.COM 				    "failed to send TX IQ"
253410893SQuaker.Fang@Sun.COM 				    "calibration command.\n");
253510893SQuaker.Fang@Sun.COM 				mutex_exit(&sc->sc_glock);
253610893SQuaker.Fang@Sun.COM 				return;
253710893SQuaker.Fang@Sun.COM 			}
253810893SQuaker.Fang@Sun.COM 
253910893SQuaker.Fang@Sun.COM 			DELAY(1000);
254010893SQuaker.Fang@Sun.COM 		}
254110893SQuaker.Fang@Sun.COM 
254210893SQuaker.Fang@Sun.COM 		/*
254310893SQuaker.Fang@Sun.COM 		 * send the result of TX IQ perd calibration to uCode.
254410893SQuaker.Fang@Sun.COM 		 */
254510893SQuaker.Fang@Sun.COM 		if (res_p->tx_iq_perd_res != NULL) {
254610893SQuaker.Fang@Sun.COM 			rv = iwp_cmd(sc, REPLY_PHY_CALIBRATION_CMD,
254710893SQuaker.Fang@Sun.COM 			    res_p->tx_iq_perd_res,
254810893SQuaker.Fang@Sun.COM 			    res_p->tx_iq_perd_res_len, 1);
254910893SQuaker.Fang@Sun.COM 			if (rv != IWP_SUCCESS) {
255010893SQuaker.Fang@Sun.COM 				cmn_err(CE_WARN, "iwp_ucode_alive(): "
255110893SQuaker.Fang@Sun.COM 				    "failed to send TX IQ perd"
255210893SQuaker.Fang@Sun.COM 				    "calibration command.\n");
255310893SQuaker.Fang@Sun.COM 				mutex_exit(&sc->sc_glock);
255410893SQuaker.Fang@Sun.COM 				return;
255510893SQuaker.Fang@Sun.COM 			}
255610893SQuaker.Fang@Sun.COM 
255710893SQuaker.Fang@Sun.COM 			DELAY(1000);
255810893SQuaker.Fang@Sun.COM 		}
255910893SQuaker.Fang@Sun.COM 
256010893SQuaker.Fang@Sun.COM 		/*
256110893SQuaker.Fang@Sun.COM 		 * send the result of Base Band calibration to uCode.
256210893SQuaker.Fang@Sun.COM 		 */
256310893SQuaker.Fang@Sun.COM 		if (res_p->base_band_res != NULL) {
256410893SQuaker.Fang@Sun.COM 			rv = iwp_cmd(sc, REPLY_PHY_CALIBRATION_CMD,
256510893SQuaker.Fang@Sun.COM 			    res_p->base_band_res,
256610893SQuaker.Fang@Sun.COM 			    res_p->base_band_res_len, 1);
256710893SQuaker.Fang@Sun.COM 			if (rv != IWP_SUCCESS) {
256810893SQuaker.Fang@Sun.COM 				cmn_err(CE_WARN, "iwp_ucode_alive(): "
256910893SQuaker.Fang@Sun.COM 				    "failed to send Base Band"
257010893SQuaker.Fang@Sun.COM 				    "calibration command.\n");
257110893SQuaker.Fang@Sun.COM 				mutex_exit(&sc->sc_glock);
257210893SQuaker.Fang@Sun.COM 				return;
257310893SQuaker.Fang@Sun.COM 			}
257410893SQuaker.Fang@Sun.COM 
257510893SQuaker.Fang@Sun.COM 			DELAY(1000);
257610893SQuaker.Fang@Sun.COM 		}
257710893SQuaker.Fang@Sun.COM 
257810893SQuaker.Fang@Sun.COM 		atomic_or_32(&sc->sc_flags, IWP_F_FW_INIT);
257910893SQuaker.Fang@Sun.COM 		cv_signal(&sc->sc_ucode_cv);
258010893SQuaker.Fang@Sun.COM 
258110893SQuaker.Fang@Sun.COM 		mutex_exit(&sc->sc_glock);
258210893SQuaker.Fang@Sun.COM 	}
258310893SQuaker.Fang@Sun.COM 
258410893SQuaker.Fang@Sun.COM }
258510893SQuaker.Fang@Sun.COM 
258610893SQuaker.Fang@Sun.COM /*
258710893SQuaker.Fang@Sun.COM  * deal with receiving frames, command response
258810893SQuaker.Fang@Sun.COM  * and all notifications from ucode.
258910893SQuaker.Fang@Sun.COM  */
259010893SQuaker.Fang@Sun.COM /* ARGSUSED */
259110893SQuaker.Fang@Sun.COM static uint_t
iwp_rx_softintr(caddr_t arg,caddr_t unused)259210893SQuaker.Fang@Sun.COM iwp_rx_softintr(caddr_t arg, caddr_t unused)
259310893SQuaker.Fang@Sun.COM {
259410893SQuaker.Fang@Sun.COM 	iwp_sc_t *sc;
259510893SQuaker.Fang@Sun.COM 	ieee80211com_t *ic;
259610893SQuaker.Fang@Sun.COM 	iwp_rx_desc_t *desc;
259710893SQuaker.Fang@Sun.COM 	iwp_rx_data_t *data;
259810893SQuaker.Fang@Sun.COM 	uint32_t index;
259910893SQuaker.Fang@Sun.COM 
260010893SQuaker.Fang@Sun.COM 	if (NULL == arg) {
260110893SQuaker.Fang@Sun.COM 		return (DDI_INTR_UNCLAIMED);
260210893SQuaker.Fang@Sun.COM 	}
260310893SQuaker.Fang@Sun.COM 	sc = (iwp_sc_t *)arg;
260410893SQuaker.Fang@Sun.COM 	ic = &sc->sc_ic;
260510893SQuaker.Fang@Sun.COM 
260610893SQuaker.Fang@Sun.COM 	/*
260710893SQuaker.Fang@Sun.COM 	 * firmware has moved the index of the rx queue, driver get it,
260810893SQuaker.Fang@Sun.COM 	 * and deal with it.
260910893SQuaker.Fang@Sun.COM 	 */
261010893SQuaker.Fang@Sun.COM 	index = (sc->sc_shared->val0) & 0xfff;
261110893SQuaker.Fang@Sun.COM 
261210893SQuaker.Fang@Sun.COM 	while (sc->sc_rxq.cur != index) {
261310893SQuaker.Fang@Sun.COM 		data = &sc->sc_rxq.data[sc->sc_rxq.cur];
261410893SQuaker.Fang@Sun.COM 		desc = (iwp_rx_desc_t *)data->dma_data.mem_va;
261510893SQuaker.Fang@Sun.COM 
261610893SQuaker.Fang@Sun.COM 		IWP_DBG((IWP_DEBUG_INTR, "iwp_rx_softintr(): "
261710893SQuaker.Fang@Sun.COM 		    "rx notification index = %d"
261810893SQuaker.Fang@Sun.COM 		    " cur = %d qid=%x idx=%d flags=%x type=%x len=%d\n",
261910893SQuaker.Fang@Sun.COM 		    index, sc->sc_rxq.cur, desc->hdr.qid, desc->hdr.idx,
262010893SQuaker.Fang@Sun.COM 		    desc->hdr.flags, desc->hdr.type, LE_32(desc->len)));
262110893SQuaker.Fang@Sun.COM 
262210893SQuaker.Fang@Sun.COM 		/*
262310893SQuaker.Fang@Sun.COM 		 * a command other than a tx need to be replied
262410893SQuaker.Fang@Sun.COM 		 */
262510893SQuaker.Fang@Sun.COM 		if (!(desc->hdr.qid & 0x80) &&
262610893SQuaker.Fang@Sun.COM 		    (desc->hdr.type != REPLY_SCAN_CMD) &&
262710893SQuaker.Fang@Sun.COM 		    (desc->hdr.type != REPLY_TX)) {
262810893SQuaker.Fang@Sun.COM 			iwp_cmd_intr(sc, desc);
262910893SQuaker.Fang@Sun.COM 		}
263010893SQuaker.Fang@Sun.COM 
263110893SQuaker.Fang@Sun.COM 		switch (desc->hdr.type) {
263210893SQuaker.Fang@Sun.COM 		case REPLY_RX_PHY_CMD:
263310893SQuaker.Fang@Sun.COM 			iwp_rx_phy_intr(sc, desc);
263410893SQuaker.Fang@Sun.COM 			break;
263510893SQuaker.Fang@Sun.COM 
263610893SQuaker.Fang@Sun.COM 		case REPLY_RX_MPDU_CMD:
263710893SQuaker.Fang@Sun.COM 			iwp_rx_mpdu_intr(sc, desc);
263810893SQuaker.Fang@Sun.COM 			break;
263910893SQuaker.Fang@Sun.COM 
264010893SQuaker.Fang@Sun.COM 		case REPLY_TX:
264110893SQuaker.Fang@Sun.COM 			iwp_tx_intr(sc, desc);
264210893SQuaker.Fang@Sun.COM 			break;
264310893SQuaker.Fang@Sun.COM 
264410893SQuaker.Fang@Sun.COM 		case REPLY_ALIVE:
264510893SQuaker.Fang@Sun.COM 			iwp_ucode_alive(sc, desc);
264610893SQuaker.Fang@Sun.COM 			break;
264710893SQuaker.Fang@Sun.COM 
264810893SQuaker.Fang@Sun.COM 		case CARD_STATE_NOTIFICATION:
264910893SQuaker.Fang@Sun.COM 		{
265010893SQuaker.Fang@Sun.COM 			uint32_t *status = (uint32_t *)(desc + 1);
265110893SQuaker.Fang@Sun.COM 
265210893SQuaker.Fang@Sun.COM 			IWP_DBG((IWP_DEBUG_RADIO, "iwp_rx_softintr(): "
265310893SQuaker.Fang@Sun.COM 			    "state changed to %x\n",
265410893SQuaker.Fang@Sun.COM 			    LE_32(*status)));
265510893SQuaker.Fang@Sun.COM 
265610893SQuaker.Fang@Sun.COM 			if (LE_32(*status) & 1) {
265710893SQuaker.Fang@Sun.COM 				/*
265810893SQuaker.Fang@Sun.COM 				 * the radio button has to be pushed(OFF). It
265910893SQuaker.Fang@Sun.COM 				 * is considered as a hw error, the
266010893SQuaker.Fang@Sun.COM 				 * iwp_thread() tries to recover it after the
266110893SQuaker.Fang@Sun.COM 				 * button is pushed again(ON)
266210893SQuaker.Fang@Sun.COM 				 */
266310893SQuaker.Fang@Sun.COM 				cmn_err(CE_NOTE, "iwp_rx_softintr(): "
266410893SQuaker.Fang@Sun.COM 				    "radio transmitter is off\n");
266510893SQuaker.Fang@Sun.COM 				sc->sc_ostate = sc->sc_ic.ic_state;
266610893SQuaker.Fang@Sun.COM 				ieee80211_new_state(&sc->sc_ic,
266710893SQuaker.Fang@Sun.COM 				    IEEE80211_S_INIT, -1);
266810893SQuaker.Fang@Sun.COM 				atomic_or_32(&sc->sc_flags,
266910893SQuaker.Fang@Sun.COM 				    IWP_F_HW_ERR_RECOVER | IWP_F_RADIO_OFF);
267010893SQuaker.Fang@Sun.COM 			}
267110893SQuaker.Fang@Sun.COM 
267210893SQuaker.Fang@Sun.COM 			break;
267310893SQuaker.Fang@Sun.COM 		}
267410893SQuaker.Fang@Sun.COM 
267510893SQuaker.Fang@Sun.COM 		case SCAN_START_NOTIFICATION:
267610893SQuaker.Fang@Sun.COM 		{
267710893SQuaker.Fang@Sun.COM 			iwp_start_scan_t *scan =
267810893SQuaker.Fang@Sun.COM 			    (iwp_start_scan_t *)(desc + 1);
267910893SQuaker.Fang@Sun.COM 
268010893SQuaker.Fang@Sun.COM 			IWP_DBG((IWP_DEBUG_SCAN, "iwp_rx_softintr(): "
268110893SQuaker.Fang@Sun.COM 			    "scanning channel %d status %x\n",
268210893SQuaker.Fang@Sun.COM 			    scan->chan, LE_32(scan->status)));
268310893SQuaker.Fang@Sun.COM 
268410893SQuaker.Fang@Sun.COM 			ic->ic_curchan = &ic->ic_sup_channels[scan->chan];
268510893SQuaker.Fang@Sun.COM 			break;
268610893SQuaker.Fang@Sun.COM 		}
268710893SQuaker.Fang@Sun.COM 
268810893SQuaker.Fang@Sun.COM 		case SCAN_COMPLETE_NOTIFICATION:
268910893SQuaker.Fang@Sun.COM 		{
269010893SQuaker.Fang@Sun.COM #ifdef	DEBUG
269110893SQuaker.Fang@Sun.COM 			iwp_stop_scan_t *scan =
269210893SQuaker.Fang@Sun.COM 			    (iwp_stop_scan_t *)(desc + 1);
269310893SQuaker.Fang@Sun.COM 
269410893SQuaker.Fang@Sun.COM 			IWP_DBG((IWP_DEBUG_SCAN, "iwp_rx_softintr(): "
269510893SQuaker.Fang@Sun.COM 			    "completed channel %d (burst of %d) status %02x\n",
269610893SQuaker.Fang@Sun.COM 			    scan->chan, scan->nchan, scan->status));
269710893SQuaker.Fang@Sun.COM #endif
269810893SQuaker.Fang@Sun.COM 
269910893SQuaker.Fang@Sun.COM 			sc->sc_scan_pending++;
270010893SQuaker.Fang@Sun.COM 			break;
270110893SQuaker.Fang@Sun.COM 		}
270210893SQuaker.Fang@Sun.COM 
270310893SQuaker.Fang@Sun.COM 		case STATISTICS_NOTIFICATION:
270410893SQuaker.Fang@Sun.COM 		{
270510893SQuaker.Fang@Sun.COM 			/*
270610893SQuaker.Fang@Sun.COM 			 * handle statistics notification
270710893SQuaker.Fang@Sun.COM 			 */
270810893SQuaker.Fang@Sun.COM 			break;
270910893SQuaker.Fang@Sun.COM 		}
271010893SQuaker.Fang@Sun.COM 
271110893SQuaker.Fang@Sun.COM 		case CALIBRATION_RES_NOTIFICATION:
271210893SQuaker.Fang@Sun.COM 			iwp_save_calib_result(sc, desc);
271310893SQuaker.Fang@Sun.COM 			break;
271410893SQuaker.Fang@Sun.COM 
271510893SQuaker.Fang@Sun.COM 		case CALIBRATION_COMPLETE_NOTIFICATION:
271610893SQuaker.Fang@Sun.COM 			mutex_enter(&sc->sc_glock);
271710893SQuaker.Fang@Sun.COM 			atomic_or_32(&sc->sc_flags, IWP_F_FW_INIT);
271810893SQuaker.Fang@Sun.COM 			cv_signal(&sc->sc_ucode_cv);
271910893SQuaker.Fang@Sun.COM 			mutex_exit(&sc->sc_glock);
272010893SQuaker.Fang@Sun.COM 			break;
272110893SQuaker.Fang@Sun.COM 
272210893SQuaker.Fang@Sun.COM 		case MISSED_BEACONS_NOTIFICATION:
272310893SQuaker.Fang@Sun.COM 		{
272410893SQuaker.Fang@Sun.COM 			struct iwp_beacon_missed *miss =
272510893SQuaker.Fang@Sun.COM 			    (struct iwp_beacon_missed *)(desc + 1);
272610893SQuaker.Fang@Sun.COM 
272710893SQuaker.Fang@Sun.COM 			if ((ic->ic_state == IEEE80211_S_RUN) &&
272810893SQuaker.Fang@Sun.COM 			    (LE_32(miss->consecutive) > 50)) {
272910893SQuaker.Fang@Sun.COM 				cmn_err(CE_NOTE, "iwp: iwp_rx_softintr(): "
273010893SQuaker.Fang@Sun.COM 				    "beacon missed %d/%d\n",
273110893SQuaker.Fang@Sun.COM 				    LE_32(miss->consecutive),
273210893SQuaker.Fang@Sun.COM 				    LE_32(miss->total));
273310893SQuaker.Fang@Sun.COM 				(void) ieee80211_new_state(ic,
273410893SQuaker.Fang@Sun.COM 				    IEEE80211_S_INIT, -1);
273510893SQuaker.Fang@Sun.COM 			}
273610893SQuaker.Fang@Sun.COM 			break;
273710893SQuaker.Fang@Sun.COM 		}
273810893SQuaker.Fang@Sun.COM 		}
273910893SQuaker.Fang@Sun.COM 
274010893SQuaker.Fang@Sun.COM 		sc->sc_rxq.cur = (sc->sc_rxq.cur + 1) % RX_QUEUE_SIZE;
274110893SQuaker.Fang@Sun.COM 	}
274210893SQuaker.Fang@Sun.COM 
274310893SQuaker.Fang@Sun.COM 	/*
274410893SQuaker.Fang@Sun.COM 	 * driver dealt with what received in rx queue and tell the information
274510893SQuaker.Fang@Sun.COM 	 * to the firmware.
274610893SQuaker.Fang@Sun.COM 	 */
274710893SQuaker.Fang@Sun.COM 	index = (0 == index) ? RX_QUEUE_SIZE - 1 : index - 1;
274810893SQuaker.Fang@Sun.COM 	IWP_WRITE(sc, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, index & (~7));
274910893SQuaker.Fang@Sun.COM 
275010893SQuaker.Fang@Sun.COM 	/*
275110893SQuaker.Fang@Sun.COM 	 * re-enable interrupts
275210893SQuaker.Fang@Sun.COM 	 */
275310893SQuaker.Fang@Sun.COM 	IWP_WRITE(sc, CSR_INT_MASK, CSR_INI_SET_MASK);
275410893SQuaker.Fang@Sun.COM 
275510893SQuaker.Fang@Sun.COM 	return (DDI_INTR_CLAIMED);
275610893SQuaker.Fang@Sun.COM }
275710893SQuaker.Fang@Sun.COM 
275810893SQuaker.Fang@Sun.COM /*
275910893SQuaker.Fang@Sun.COM  * the handle of interrupt
276010893SQuaker.Fang@Sun.COM  */
276110893SQuaker.Fang@Sun.COM /* ARGSUSED */
276210893SQuaker.Fang@Sun.COM static uint_t
iwp_intr(caddr_t arg,caddr_t unused)276310893SQuaker.Fang@Sun.COM iwp_intr(caddr_t arg, caddr_t unused)
276410893SQuaker.Fang@Sun.COM {
276510893SQuaker.Fang@Sun.COM 	iwp_sc_t *sc;
276610893SQuaker.Fang@Sun.COM 	uint32_t r, rfh;
276710893SQuaker.Fang@Sun.COM 
276810893SQuaker.Fang@Sun.COM 	if (NULL == arg) {
276910893SQuaker.Fang@Sun.COM 		return (DDI_INTR_UNCLAIMED);
277010893SQuaker.Fang@Sun.COM 	}
277110893SQuaker.Fang@Sun.COM 	sc = (iwp_sc_t *)arg;
277210893SQuaker.Fang@Sun.COM 
277310893SQuaker.Fang@Sun.COM 	r = IWP_READ(sc, CSR_INT);
277410893SQuaker.Fang@Sun.COM 	if (0 == r || 0xffffffff == r) {
277510893SQuaker.Fang@Sun.COM 		return (DDI_INTR_UNCLAIMED);
277610893SQuaker.Fang@Sun.COM 	}
277710893SQuaker.Fang@Sun.COM 
277810893SQuaker.Fang@Sun.COM 	IWP_DBG((IWP_DEBUG_INTR, "iwp_intr(): "
277910893SQuaker.Fang@Sun.COM 	    "interrupt reg %x\n", r));
278010893SQuaker.Fang@Sun.COM 
278110893SQuaker.Fang@Sun.COM 	rfh = IWP_READ(sc, CSR_FH_INT_STATUS);
278210893SQuaker.Fang@Sun.COM 
278310893SQuaker.Fang@Sun.COM 	IWP_DBG((IWP_DEBUG_INTR, "iwp_intr(): "
278410893SQuaker.Fang@Sun.COM 	    "FH interrupt reg %x\n", rfh));
278510893SQuaker.Fang@Sun.COM 
278610893SQuaker.Fang@Sun.COM 	/*
278710893SQuaker.Fang@Sun.COM 	 * disable interrupts
278810893SQuaker.Fang@Sun.COM 	 */
278910893SQuaker.Fang@Sun.COM 	IWP_WRITE(sc, CSR_INT_MASK, 0);
279010893SQuaker.Fang@Sun.COM 
279110893SQuaker.Fang@Sun.COM 	/*
279210893SQuaker.Fang@Sun.COM 	 * ack interrupts
279310893SQuaker.Fang@Sun.COM 	 */
279410893SQuaker.Fang@Sun.COM 	IWP_WRITE(sc, CSR_INT, r);
279510893SQuaker.Fang@Sun.COM 	IWP_WRITE(sc, CSR_FH_INT_STATUS, rfh);
279610893SQuaker.Fang@Sun.COM 
279710893SQuaker.Fang@Sun.COM 	if (r & (BIT_INT_SWERROR | BIT_INT_ERR)) {
279810893SQuaker.Fang@Sun.COM 		IWP_DBG((IWP_DEBUG_FW, "iwp_intr(): "
279910893SQuaker.Fang@Sun.COM 		    "fatal firmware error\n"));
280010893SQuaker.Fang@Sun.COM 		iwp_stop(sc);
280110893SQuaker.Fang@Sun.COM 		sc->sc_ostate = sc->sc_ic.ic_state;
280210893SQuaker.Fang@Sun.COM 
280310893SQuaker.Fang@Sun.COM 		/* notify upper layer */
280410893SQuaker.Fang@Sun.COM 		if (!IWP_CHK_FAST_RECOVER(sc)) {
280510893SQuaker.Fang@Sun.COM 			ieee80211_new_state(&sc->sc_ic, IEEE80211_S_INIT, -1);
280610893SQuaker.Fang@Sun.COM 		}
280710893SQuaker.Fang@Sun.COM 
280810893SQuaker.Fang@Sun.COM 		atomic_or_32(&sc->sc_flags, IWP_F_HW_ERR_RECOVER);
280910893SQuaker.Fang@Sun.COM 		return (DDI_INTR_CLAIMED);
281010893SQuaker.Fang@Sun.COM 	}
281110893SQuaker.Fang@Sun.COM 
281210893SQuaker.Fang@Sun.COM 	if (r & BIT_INT_RF_KILL) {
281310893SQuaker.Fang@Sun.COM 		uint32_t tmp = IWP_READ(sc, CSR_GP_CNTRL);
281410893SQuaker.Fang@Sun.COM 		if (tmp & (1 << 27)) {
281510893SQuaker.Fang@Sun.COM 			cmn_err(CE_NOTE, "RF switch: radio on\n");
281610893SQuaker.Fang@Sun.COM 		}
281710893SQuaker.Fang@Sun.COM 	}
281810893SQuaker.Fang@Sun.COM 
281910893SQuaker.Fang@Sun.COM 	if ((r & (BIT_INT_FH_RX | BIT_INT_SW_RX)) ||
282010893SQuaker.Fang@Sun.COM 	    (rfh & FH_INT_RX_MASK)) {
282110893SQuaker.Fang@Sun.COM 		(void) ddi_intr_trigger_softint(sc->sc_soft_hdl, NULL);
282210893SQuaker.Fang@Sun.COM 		return (DDI_INTR_CLAIMED);
282310893SQuaker.Fang@Sun.COM 	}
282410893SQuaker.Fang@Sun.COM 
282510893SQuaker.Fang@Sun.COM 	if (r & BIT_INT_FH_TX) {
282610893SQuaker.Fang@Sun.COM 		mutex_enter(&sc->sc_glock);
282710893SQuaker.Fang@Sun.COM 		atomic_or_32(&sc->sc_flags, IWP_F_PUT_SEG);
282810893SQuaker.Fang@Sun.COM 		cv_signal(&sc->sc_put_seg_cv);
282910893SQuaker.Fang@Sun.COM 		mutex_exit(&sc->sc_glock);
283010893SQuaker.Fang@Sun.COM 	}
283110893SQuaker.Fang@Sun.COM 
283210893SQuaker.Fang@Sun.COM #ifdef	DEBUG
283310893SQuaker.Fang@Sun.COM 	if (r & BIT_INT_ALIVE)	{
283410893SQuaker.Fang@Sun.COM 		IWP_DBG((IWP_DEBUG_FW, "iwp_intr(): "
283510893SQuaker.Fang@Sun.COM 		    "firmware initialized.\n"));
283610893SQuaker.Fang@Sun.COM 	}
283710893SQuaker.Fang@Sun.COM #endif
283810893SQuaker.Fang@Sun.COM 
283910893SQuaker.Fang@Sun.COM 	/*
284010893SQuaker.Fang@Sun.COM 	 * re-enable interrupts
284110893SQuaker.Fang@Sun.COM 	 */
284210893SQuaker.Fang@Sun.COM 	IWP_WRITE(sc, CSR_INT_MASK, CSR_INI_SET_MASK);
284310893SQuaker.Fang@Sun.COM 
284410893SQuaker.Fang@Sun.COM 	return (DDI_INTR_CLAIMED);
284510893SQuaker.Fang@Sun.COM }
284610893SQuaker.Fang@Sun.COM 
284710893SQuaker.Fang@Sun.COM static uint8_t
iwp_rate_to_plcp(int rate)284810893SQuaker.Fang@Sun.COM iwp_rate_to_plcp(int rate)
284910893SQuaker.Fang@Sun.COM {
285010893SQuaker.Fang@Sun.COM 	uint8_t ret;
285110893SQuaker.Fang@Sun.COM 
285210893SQuaker.Fang@Sun.COM 	switch (rate) {
285310893SQuaker.Fang@Sun.COM 	/*
285410893SQuaker.Fang@Sun.COM 	 * CCK rates
285510893SQuaker.Fang@Sun.COM 	 */
285610893SQuaker.Fang@Sun.COM 	case 2:
285710893SQuaker.Fang@Sun.COM 		ret = 0xa;
285810893SQuaker.Fang@Sun.COM 		break;
285910893SQuaker.Fang@Sun.COM 
286010893SQuaker.Fang@Sun.COM 	case 4:
286110893SQuaker.Fang@Sun.COM 		ret = 0x14;
286210893SQuaker.Fang@Sun.COM 		break;
286310893SQuaker.Fang@Sun.COM 
286410893SQuaker.Fang@Sun.COM 	case 11:
286510893SQuaker.Fang@Sun.COM 		ret = 0x37;
286610893SQuaker.Fang@Sun.COM 		break;
286710893SQuaker.Fang@Sun.COM 
286810893SQuaker.Fang@Sun.COM 	case 22:
286910893SQuaker.Fang@Sun.COM 		ret = 0x6e;
287010893SQuaker.Fang@Sun.COM 		break;
287110893SQuaker.Fang@Sun.COM 
287210893SQuaker.Fang@Sun.COM 	/*
287310893SQuaker.Fang@Sun.COM 	 * OFDM rates
287410893SQuaker.Fang@Sun.COM 	 */
287510893SQuaker.Fang@Sun.COM 	case 12:
287610893SQuaker.Fang@Sun.COM 		ret = 0xd;
287710893SQuaker.Fang@Sun.COM 		break;
287810893SQuaker.Fang@Sun.COM 
287910893SQuaker.Fang@Sun.COM 	case 18:
288010893SQuaker.Fang@Sun.COM 		ret = 0xf;
288110893SQuaker.Fang@Sun.COM 		break;
288210893SQuaker.Fang@Sun.COM 
288310893SQuaker.Fang@Sun.COM 	case 24:
288410893SQuaker.Fang@Sun.COM 		ret = 0x5;
288510893SQuaker.Fang@Sun.COM 		break;
288610893SQuaker.Fang@Sun.COM 
288710893SQuaker.Fang@Sun.COM 	case 36:
288810893SQuaker.Fang@Sun.COM 		ret = 0x7;
288910893SQuaker.Fang@Sun.COM 		break;
289010893SQuaker.Fang@Sun.COM 
289110893SQuaker.Fang@Sun.COM 	case 48:
289210893SQuaker.Fang@Sun.COM 		ret = 0x9;
289310893SQuaker.Fang@Sun.COM 		break;
289410893SQuaker.Fang@Sun.COM 
289510893SQuaker.Fang@Sun.COM 	case 72:
289610893SQuaker.Fang@Sun.COM 		ret = 0xb;
289710893SQuaker.Fang@Sun.COM 		break;
289810893SQuaker.Fang@Sun.COM 
289910893SQuaker.Fang@Sun.COM 	case 96:
290010893SQuaker.Fang@Sun.COM 		ret = 0x1;
290110893SQuaker.Fang@Sun.COM 		break;
290210893SQuaker.Fang@Sun.COM 
290310893SQuaker.Fang@Sun.COM 	case 108:
290410893SQuaker.Fang@Sun.COM 		ret = 0x3;
290510893SQuaker.Fang@Sun.COM 		break;
290610893SQuaker.Fang@Sun.COM 
290710893SQuaker.Fang@Sun.COM 	default:
290810893SQuaker.Fang@Sun.COM 		ret = 0;
290910893SQuaker.Fang@Sun.COM 		break;
291010893SQuaker.Fang@Sun.COM 	}
291110893SQuaker.Fang@Sun.COM 
291210893SQuaker.Fang@Sun.COM 	return (ret);
291310893SQuaker.Fang@Sun.COM }
291410893SQuaker.Fang@Sun.COM 
291510893SQuaker.Fang@Sun.COM /*
291610893SQuaker.Fang@Sun.COM  * invoked by GLD send frames
291710893SQuaker.Fang@Sun.COM  */
291810893SQuaker.Fang@Sun.COM static mblk_t *
iwp_m_tx(void * arg,mblk_t * mp)291910893SQuaker.Fang@Sun.COM iwp_m_tx(void *arg, mblk_t *mp)
292010893SQuaker.Fang@Sun.COM {
292110893SQuaker.Fang@Sun.COM 	iwp_sc_t	*sc;
292210893SQuaker.Fang@Sun.COM 	ieee80211com_t	*ic;
292310893SQuaker.Fang@Sun.COM 	mblk_t		*next;
292410893SQuaker.Fang@Sun.COM 
292510893SQuaker.Fang@Sun.COM 	if (NULL == arg) {
292610893SQuaker.Fang@Sun.COM 		return (NULL);
292710893SQuaker.Fang@Sun.COM 	}
292810893SQuaker.Fang@Sun.COM 	sc = (iwp_sc_t *)arg;
292910893SQuaker.Fang@Sun.COM 	ic = &sc->sc_ic;
293010893SQuaker.Fang@Sun.COM 
293110893SQuaker.Fang@Sun.COM 	if (sc->sc_flags & IWP_F_SUSPEND) {
293210893SQuaker.Fang@Sun.COM 		freemsgchain(mp);
293310893SQuaker.Fang@Sun.COM 		return (NULL);
293410893SQuaker.Fang@Sun.COM 	}
293510893SQuaker.Fang@Sun.COM 
293610893SQuaker.Fang@Sun.COM 	if (ic->ic_state != IEEE80211_S_RUN) {
293710893SQuaker.Fang@Sun.COM 		freemsgchain(mp);
293810893SQuaker.Fang@Sun.COM 		return (NULL);
293910893SQuaker.Fang@Sun.COM 	}
294010893SQuaker.Fang@Sun.COM 
294110893SQuaker.Fang@Sun.COM 	if ((sc->sc_flags & IWP_F_HW_ERR_RECOVER) &&
294210893SQuaker.Fang@Sun.COM 	    IWP_CHK_FAST_RECOVER(sc)) {
294310893SQuaker.Fang@Sun.COM 		IWP_DBG((IWP_DEBUG_FW, "iwp_m_tx(): "
294410893SQuaker.Fang@Sun.COM 		    "hold queue\n"));
294510893SQuaker.Fang@Sun.COM 		return (mp);
294610893SQuaker.Fang@Sun.COM 	}
294710893SQuaker.Fang@Sun.COM 
294810893SQuaker.Fang@Sun.COM 
294910893SQuaker.Fang@Sun.COM 	while (mp != NULL) {
295010893SQuaker.Fang@Sun.COM 		next = mp->b_next;
295110893SQuaker.Fang@Sun.COM 		mp->b_next = NULL;
295210893SQuaker.Fang@Sun.COM 		if (iwp_send(ic, mp, IEEE80211_FC0_TYPE_DATA) != 0) {
295310893SQuaker.Fang@Sun.COM 			mp->b_next = next;
295410893SQuaker.Fang@Sun.COM 			break;
295510893SQuaker.Fang@Sun.COM 		}
295610893SQuaker.Fang@Sun.COM 		mp = next;
295710893SQuaker.Fang@Sun.COM 	}
295810893SQuaker.Fang@Sun.COM 
295910893SQuaker.Fang@Sun.COM 	return (mp);
296010893SQuaker.Fang@Sun.COM }
296110893SQuaker.Fang@Sun.COM 
296210893SQuaker.Fang@Sun.COM /*
296310893SQuaker.Fang@Sun.COM  * send frames
296410893SQuaker.Fang@Sun.COM  */
296510893SQuaker.Fang@Sun.COM static int
iwp_send(ieee80211com_t * ic,mblk_t * mp,uint8_t type)296610893SQuaker.Fang@Sun.COM iwp_send(ieee80211com_t *ic, mblk_t *mp, uint8_t type)
296710893SQuaker.Fang@Sun.COM {
296810893SQuaker.Fang@Sun.COM 	iwp_sc_t *sc;
296910893SQuaker.Fang@Sun.COM 	iwp_tx_ring_t *ring;
297010893SQuaker.Fang@Sun.COM 	iwp_tx_desc_t *desc;
297110893SQuaker.Fang@Sun.COM 	iwp_tx_data_t *data;
297210893SQuaker.Fang@Sun.COM 	iwp_tx_data_t *desc_data;
297310893SQuaker.Fang@Sun.COM 	iwp_cmd_t *cmd;
297410893SQuaker.Fang@Sun.COM 	iwp_tx_cmd_t *tx;
297510893SQuaker.Fang@Sun.COM 	ieee80211_node_t *in;
297610893SQuaker.Fang@Sun.COM 	struct ieee80211_frame *wh;
297710893SQuaker.Fang@Sun.COM 	struct ieee80211_key *k = NULL;
297810893SQuaker.Fang@Sun.COM 	mblk_t *m, *m0;
297910893SQuaker.Fang@Sun.COM 	int hdrlen, len, len0, mblen, off, err = IWP_SUCCESS;
298010893SQuaker.Fang@Sun.COM 	uint16_t masks = 0;
298110893SQuaker.Fang@Sun.COM 	uint32_t rate, s_id = 0;
298210893SQuaker.Fang@Sun.COM 
298310893SQuaker.Fang@Sun.COM 	if (NULL == ic) {
298410893SQuaker.Fang@Sun.COM 		return (IWP_FAIL);
298510893SQuaker.Fang@Sun.COM 	}
298610893SQuaker.Fang@Sun.COM 	sc = (iwp_sc_t *)ic;
298710893SQuaker.Fang@Sun.COM 
298810893SQuaker.Fang@Sun.COM 	if (sc->sc_flags & IWP_F_SUSPEND) {
298910893SQuaker.Fang@Sun.COM 		if ((type & IEEE80211_FC0_TYPE_MASK) !=
299010893SQuaker.Fang@Sun.COM 		    IEEE80211_FC0_TYPE_DATA) {
299110893SQuaker.Fang@Sun.COM 			freemsg(mp);
299210893SQuaker.Fang@Sun.COM 		}
299310893SQuaker.Fang@Sun.COM 		err = IWP_FAIL;
299410893SQuaker.Fang@Sun.COM 		goto exit;
299510893SQuaker.Fang@Sun.COM 	}
299610893SQuaker.Fang@Sun.COM 
299710893SQuaker.Fang@Sun.COM 	mutex_enter(&sc->sc_tx_lock);
299810893SQuaker.Fang@Sun.COM 	ring = &sc->sc_txq[0];
299910893SQuaker.Fang@Sun.COM 	data = &ring->data[ring->cur];
300010893SQuaker.Fang@Sun.COM 	cmd = data->cmd;
300110893SQuaker.Fang@Sun.COM 	bzero(cmd, sizeof (*cmd));
300210893SQuaker.Fang@Sun.COM 
300310893SQuaker.Fang@Sun.COM 	ring->cur = (ring->cur + 1) % ring->count;
300410893SQuaker.Fang@Sun.COM 
300510893SQuaker.Fang@Sun.COM 	/*
300610893SQuaker.Fang@Sun.COM 	 * Need reschedule TX if TX buffer is full.
300710893SQuaker.Fang@Sun.COM 	 */
300810893SQuaker.Fang@Sun.COM 	if (ring->queued > ring->count - IWP_MAX_WIN_SIZE) {
300910893SQuaker.Fang@Sun.COM 		IWP_DBG((IWP_DEBUG_TX, "iwp_send(): "
301010893SQuaker.Fang@Sun.COM 		"no txbuf\n"));
301110893SQuaker.Fang@Sun.COM 
301210893SQuaker.Fang@Sun.COM 		sc->sc_need_reschedule = 1;
301310893SQuaker.Fang@Sun.COM 		mutex_exit(&sc->sc_tx_lock);
301410893SQuaker.Fang@Sun.COM 
301510893SQuaker.Fang@Sun.COM 		if ((type & IEEE80211_FC0_TYPE_MASK) !=
301610893SQuaker.Fang@Sun.COM 		    IEEE80211_FC0_TYPE_DATA) {
301710893SQuaker.Fang@Sun.COM 			freemsg(mp);
301810893SQuaker.Fang@Sun.COM 		}
301910893SQuaker.Fang@Sun.COM 		sc->sc_tx_nobuf++;
302010893SQuaker.Fang@Sun.COM 		err = IWP_FAIL;
302110893SQuaker.Fang@Sun.COM 		goto exit;
302210893SQuaker.Fang@Sun.COM 	}
302310893SQuaker.Fang@Sun.COM 
302410893SQuaker.Fang@Sun.COM 	ring->queued++;
302510893SQuaker.Fang@Sun.COM 
302610893SQuaker.Fang@Sun.COM 	mutex_exit(&sc->sc_tx_lock);
302710893SQuaker.Fang@Sun.COM 
302810893SQuaker.Fang@Sun.COM 	hdrlen = ieee80211_hdrspace(ic, mp->b_rptr);
302910893SQuaker.Fang@Sun.COM 
303010893SQuaker.Fang@Sun.COM 	m = allocb(msgdsize(mp) + 32, BPRI_MED);
303110893SQuaker.Fang@Sun.COM 	if (NULL == m) { /* can not alloc buf, drop this package */
303210893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_send(): "
303310893SQuaker.Fang@Sun.COM 		    "failed to allocate msgbuf\n");
303410893SQuaker.Fang@Sun.COM 		freemsg(mp);
303510893SQuaker.Fang@Sun.COM 
303610893SQuaker.Fang@Sun.COM 		mutex_enter(&sc->sc_tx_lock);
303710893SQuaker.Fang@Sun.COM 		ring->queued--;
303810893SQuaker.Fang@Sun.COM 		if ((sc->sc_need_reschedule) && (ring->queued <= 0)) {
303910893SQuaker.Fang@Sun.COM 			sc->sc_need_reschedule = 0;
304010893SQuaker.Fang@Sun.COM 			mutex_exit(&sc->sc_tx_lock);
304110893SQuaker.Fang@Sun.COM 			mac_tx_update(ic->ic_mach);
304210893SQuaker.Fang@Sun.COM 			mutex_enter(&sc->sc_tx_lock);
304310893SQuaker.Fang@Sun.COM 		}
304410893SQuaker.Fang@Sun.COM 		mutex_exit(&sc->sc_tx_lock);
304510893SQuaker.Fang@Sun.COM 
304610893SQuaker.Fang@Sun.COM 		err = IWP_SUCCESS;
304710893SQuaker.Fang@Sun.COM 		goto exit;
304810893SQuaker.Fang@Sun.COM 	}
304910893SQuaker.Fang@Sun.COM 
305010893SQuaker.Fang@Sun.COM 	for (off = 0, m0 = mp; m0 != NULL; m0 = m0->b_cont) {
305110893SQuaker.Fang@Sun.COM 		mblen = MBLKL(m0);
305210893SQuaker.Fang@Sun.COM 		(void) memcpy(m->b_rptr + off, m0->b_rptr, mblen);
305310893SQuaker.Fang@Sun.COM 		off += mblen;
305410893SQuaker.Fang@Sun.COM 	}
305510893SQuaker.Fang@Sun.COM 
305610893SQuaker.Fang@Sun.COM 	m->b_wptr += off;
305710893SQuaker.Fang@Sun.COM 
305810893SQuaker.Fang@Sun.COM 	wh = (struct ieee80211_frame *)m->b_rptr;
305910893SQuaker.Fang@Sun.COM 
306010893SQuaker.Fang@Sun.COM 	/*
306110893SQuaker.Fang@Sun.COM 	 * determine send which AP or station in IBSS
306210893SQuaker.Fang@Sun.COM 	 */
306310893SQuaker.Fang@Sun.COM 	in = ieee80211_find_txnode(ic, wh->i_addr1);
306410893SQuaker.Fang@Sun.COM 	if (NULL == in) {
306510893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_send(): "
306610893SQuaker.Fang@Sun.COM 		    "failed to find tx node\n");
306710893SQuaker.Fang@Sun.COM 		freemsg(mp);
306810893SQuaker.Fang@Sun.COM 		freemsg(m);
306910893SQuaker.Fang@Sun.COM 		sc->sc_tx_err++;
307010893SQuaker.Fang@Sun.COM 
307110893SQuaker.Fang@Sun.COM 		mutex_enter(&sc->sc_tx_lock);
307210893SQuaker.Fang@Sun.COM 		ring->queued--;
307310893SQuaker.Fang@Sun.COM 		if ((sc->sc_need_reschedule) && (ring->queued <= 0)) {
307410893SQuaker.Fang@Sun.COM 			sc->sc_need_reschedule = 0;
307510893SQuaker.Fang@Sun.COM 			mutex_exit(&sc->sc_tx_lock);
307610893SQuaker.Fang@Sun.COM 			mac_tx_update(ic->ic_mach);
307710893SQuaker.Fang@Sun.COM 			mutex_enter(&sc->sc_tx_lock);
307810893SQuaker.Fang@Sun.COM 		}
307910893SQuaker.Fang@Sun.COM 		mutex_exit(&sc->sc_tx_lock);
308010893SQuaker.Fang@Sun.COM 
308110893SQuaker.Fang@Sun.COM 		err = IWP_SUCCESS;
308210893SQuaker.Fang@Sun.COM 		goto exit;
308310893SQuaker.Fang@Sun.COM 	}
308410893SQuaker.Fang@Sun.COM 
308510893SQuaker.Fang@Sun.COM 	/*
308610893SQuaker.Fang@Sun.COM 	 * Net80211 module encapsulate outbound data frames.
308710893SQuaker.Fang@Sun.COM 	 * Add some feilds of 80211 frame.
308810893SQuaker.Fang@Sun.COM 	 */
308910893SQuaker.Fang@Sun.COM 	if ((type & IEEE80211_FC0_TYPE_MASK) ==
309010893SQuaker.Fang@Sun.COM 	    IEEE80211_FC0_TYPE_DATA) {
309110893SQuaker.Fang@Sun.COM 		(void) ieee80211_encap(ic, m, in);
309210893SQuaker.Fang@Sun.COM 	}
309310893SQuaker.Fang@Sun.COM 
309410893SQuaker.Fang@Sun.COM 	freemsg(mp);
309510893SQuaker.Fang@Sun.COM 
309610893SQuaker.Fang@Sun.COM 	cmd->hdr.type = REPLY_TX;
309710893SQuaker.Fang@Sun.COM 	cmd->hdr.flags = 0;
309810893SQuaker.Fang@Sun.COM 	cmd->hdr.qid = ring->qid;
309910893SQuaker.Fang@Sun.COM 
310010893SQuaker.Fang@Sun.COM 	tx = (iwp_tx_cmd_t *)cmd->data;
310110893SQuaker.Fang@Sun.COM 	tx->tx_flags = 0;
310210893SQuaker.Fang@Sun.COM 
310310893SQuaker.Fang@Sun.COM 	if (IEEE80211_IS_MULTICAST(wh->i_addr1)) {
310410893SQuaker.Fang@Sun.COM 		tx->tx_flags &= ~(LE_32(TX_CMD_FLG_ACK_MSK));
310510893SQuaker.Fang@Sun.COM 	} else {
310610893SQuaker.Fang@Sun.COM 		tx->tx_flags |= LE_32(TX_CMD_FLG_ACK_MSK);
310710893SQuaker.Fang@Sun.COM 	}
310810893SQuaker.Fang@Sun.COM 
310910893SQuaker.Fang@Sun.COM 	if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
311010893SQuaker.Fang@Sun.COM 		k = ieee80211_crypto_encap(ic, m);
311110893SQuaker.Fang@Sun.COM 		if (NULL == k) {
311210893SQuaker.Fang@Sun.COM 			freemsg(m);
311310893SQuaker.Fang@Sun.COM 			sc->sc_tx_err++;
311410893SQuaker.Fang@Sun.COM 
311510893SQuaker.Fang@Sun.COM 			mutex_enter(&sc->sc_tx_lock);
311610893SQuaker.Fang@Sun.COM 			ring->queued--;
311710893SQuaker.Fang@Sun.COM 			if ((sc->sc_need_reschedule) && (ring->queued <= 0)) {
311810893SQuaker.Fang@Sun.COM 				sc->sc_need_reschedule = 0;
311910893SQuaker.Fang@Sun.COM 				mutex_exit(&sc->sc_tx_lock);
312010893SQuaker.Fang@Sun.COM 				mac_tx_update(ic->ic_mach);
312110893SQuaker.Fang@Sun.COM 				mutex_enter(&sc->sc_tx_lock);
312210893SQuaker.Fang@Sun.COM 			}
312310893SQuaker.Fang@Sun.COM 			mutex_exit(&sc->sc_tx_lock);
312410893SQuaker.Fang@Sun.COM 
312510893SQuaker.Fang@Sun.COM 			err = IWP_SUCCESS;
312610893SQuaker.Fang@Sun.COM 			goto exit;
312710893SQuaker.Fang@Sun.COM 		}
312810893SQuaker.Fang@Sun.COM 
312910893SQuaker.Fang@Sun.COM 		/* packet header may have moved, reset our local pointer */
313010893SQuaker.Fang@Sun.COM 		wh = (struct ieee80211_frame *)m->b_rptr;
313110893SQuaker.Fang@Sun.COM 	}
313210893SQuaker.Fang@Sun.COM 
313310893SQuaker.Fang@Sun.COM 	len = msgdsize(m);
313410893SQuaker.Fang@Sun.COM 
313510893SQuaker.Fang@Sun.COM #ifdef DEBUG
313610893SQuaker.Fang@Sun.COM 	if (iwp_dbg_flags & IWP_DEBUG_TX) {
313710893SQuaker.Fang@Sun.COM 		ieee80211_dump_pkt((uint8_t *)wh, hdrlen, 0, 0);
313810893SQuaker.Fang@Sun.COM 	}
313910893SQuaker.Fang@Sun.COM #endif
314010893SQuaker.Fang@Sun.COM 
314110893SQuaker.Fang@Sun.COM 	tx->rts_retry_limit = IWP_TX_RTS_RETRY_LIMIT;
314210893SQuaker.Fang@Sun.COM 	tx->data_retry_limit = IWP_TX_DATA_RETRY_LIMIT;
314310893SQuaker.Fang@Sun.COM 
314410893SQuaker.Fang@Sun.COM 	/*
314510893SQuaker.Fang@Sun.COM 	 * specific TX parameters for management frames
314610893SQuaker.Fang@Sun.COM 	 */
314710893SQuaker.Fang@Sun.COM 	if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
314810893SQuaker.Fang@Sun.COM 	    IEEE80211_FC0_TYPE_MGT) {
314910893SQuaker.Fang@Sun.COM 		/*
315010893SQuaker.Fang@Sun.COM 		 * mgmt frames are sent at 1M
315110893SQuaker.Fang@Sun.COM 		 */
315210893SQuaker.Fang@Sun.COM 		if ((in->in_rates.ir_rates[0] &
315310893SQuaker.Fang@Sun.COM 		    IEEE80211_RATE_VAL) != 0) {
315410893SQuaker.Fang@Sun.COM 			rate = in->in_rates.ir_rates[0] & IEEE80211_RATE_VAL;
315510893SQuaker.Fang@Sun.COM 		} else {
315610893SQuaker.Fang@Sun.COM 			rate = 2;
315710893SQuaker.Fang@Sun.COM 		}
315810893SQuaker.Fang@Sun.COM 
315910893SQuaker.Fang@Sun.COM 		tx->tx_flags |= LE_32(TX_CMD_FLG_SEQ_CTL_MSK);
316010893SQuaker.Fang@Sun.COM 
316110893SQuaker.Fang@Sun.COM 		/*
316210893SQuaker.Fang@Sun.COM 		 * tell h/w to set timestamp in probe responses
316310893SQuaker.Fang@Sun.COM 		 */
316410893SQuaker.Fang@Sun.COM 		if ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) ==
316510893SQuaker.Fang@Sun.COM 		    IEEE80211_FC0_SUBTYPE_PROBE_RESP) {
316610893SQuaker.Fang@Sun.COM 			tx->tx_flags |= LE_32(TX_CMD_FLG_TSF_MSK);
316710893SQuaker.Fang@Sun.COM 
316810893SQuaker.Fang@Sun.COM 			tx->data_retry_limit = 3;
316910893SQuaker.Fang@Sun.COM 			if (tx->data_retry_limit < tx->rts_retry_limit) {
317010893SQuaker.Fang@Sun.COM 				tx->rts_retry_limit = tx->data_retry_limit;
317110893SQuaker.Fang@Sun.COM 			}
317210893SQuaker.Fang@Sun.COM 		}
317310893SQuaker.Fang@Sun.COM 
317410893SQuaker.Fang@Sun.COM 		if (((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) ==
317510893SQuaker.Fang@Sun.COM 		    IEEE80211_FC0_SUBTYPE_ASSOC_REQ) ||
317610893SQuaker.Fang@Sun.COM 		    ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) ==
317710893SQuaker.Fang@Sun.COM 		    IEEE80211_FC0_SUBTYPE_REASSOC_REQ)) {
317810893SQuaker.Fang@Sun.COM 			tx->timeout.pm_frame_timeout = LE_16(3);
317910893SQuaker.Fang@Sun.COM 		} else {
318010893SQuaker.Fang@Sun.COM 			tx->timeout.pm_frame_timeout = LE_16(2);
318110893SQuaker.Fang@Sun.COM 		}
318210893SQuaker.Fang@Sun.COM 
318310893SQuaker.Fang@Sun.COM 	} else {
318410893SQuaker.Fang@Sun.COM 		/*
318510893SQuaker.Fang@Sun.COM 		 * do it here for the software way rate scaling.
318610893SQuaker.Fang@Sun.COM 		 * later for rate scaling in hardware.
318710893SQuaker.Fang@Sun.COM 		 *
318810893SQuaker.Fang@Sun.COM 		 * now the txrate is determined in tx cmd flags, set to the
318910893SQuaker.Fang@Sun.COM 		 * max value 54M for 11g and 11M for 11b originally.
319010893SQuaker.Fang@Sun.COM 		 */
319110893SQuaker.Fang@Sun.COM 		if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE) {
319210893SQuaker.Fang@Sun.COM 			rate = ic->ic_fixed_rate;
319310893SQuaker.Fang@Sun.COM 		} else {
319410893SQuaker.Fang@Sun.COM 			if ((in->in_rates.ir_rates[in->in_txrate] &
319510893SQuaker.Fang@Sun.COM 			    IEEE80211_RATE_VAL) != 0) {
319610893SQuaker.Fang@Sun.COM 				rate = in->in_rates.
319710893SQuaker.Fang@Sun.COM 				    ir_rates[in->in_txrate] &
319810893SQuaker.Fang@Sun.COM 				    IEEE80211_RATE_VAL;
319910893SQuaker.Fang@Sun.COM 			}
320010893SQuaker.Fang@Sun.COM 		}
320110893SQuaker.Fang@Sun.COM 
320210893SQuaker.Fang@Sun.COM 		tx->tx_flags |= LE_32(TX_CMD_FLG_SEQ_CTL_MSK);
320310893SQuaker.Fang@Sun.COM 
320410893SQuaker.Fang@Sun.COM 		tx->timeout.pm_frame_timeout = 0;
320510893SQuaker.Fang@Sun.COM 	}
320610893SQuaker.Fang@Sun.COM 
320710893SQuaker.Fang@Sun.COM 	IWP_DBG((IWP_DEBUG_TX, "iwp_send(): "
320810893SQuaker.Fang@Sun.COM 	    "tx rate[%d of %d] = %x",
320910893SQuaker.Fang@Sun.COM 	    in->in_txrate, in->in_rates.ir_nrates, rate));
321010893SQuaker.Fang@Sun.COM 
321110893SQuaker.Fang@Sun.COM 	len0 = roundup(4 + sizeof (iwp_tx_cmd_t) + hdrlen, 4);
321210893SQuaker.Fang@Sun.COM 	if (len0 != (4 + sizeof (iwp_tx_cmd_t) + hdrlen)) {
321310893SQuaker.Fang@Sun.COM 		tx->tx_flags |= LE_32(TX_CMD_FLG_MH_PAD_MSK);
321410893SQuaker.Fang@Sun.COM 	}
321510893SQuaker.Fang@Sun.COM 
321610893SQuaker.Fang@Sun.COM 	/*
321710893SQuaker.Fang@Sun.COM 	 * retrieve destination node's id
321810893SQuaker.Fang@Sun.COM 	 */
321910893SQuaker.Fang@Sun.COM 	if (IEEE80211_IS_MULTICAST(wh->i_addr1)) {
322010893SQuaker.Fang@Sun.COM 		tx->sta_id = IWP_BROADCAST_ID;
322110893SQuaker.Fang@Sun.COM 	} else {
322210893SQuaker.Fang@Sun.COM 		tx->sta_id = IWP_AP_ID;
322310893SQuaker.Fang@Sun.COM 	}
322410893SQuaker.Fang@Sun.COM 
322510893SQuaker.Fang@Sun.COM 	if (2 == rate || 4 == rate || 11 == rate || 22 == rate) {
322610893SQuaker.Fang@Sun.COM 		masks |= RATE_MCS_CCK_MSK;
322710893SQuaker.Fang@Sun.COM 	}
322810893SQuaker.Fang@Sun.COM 
322910893SQuaker.Fang@Sun.COM 	masks |= RATE_MCS_ANT_B_MSK;
323010893SQuaker.Fang@Sun.COM 	tx->rate.r.rate_n_flags = LE_32(iwp_rate_to_plcp(rate) | masks);
323110893SQuaker.Fang@Sun.COM 
323210893SQuaker.Fang@Sun.COM 	IWP_DBG((IWP_DEBUG_TX, "iwp_send(): "
323310893SQuaker.Fang@Sun.COM 	    "tx flag = %x",
323410893SQuaker.Fang@Sun.COM 	    tx->tx_flags));
323510893SQuaker.Fang@Sun.COM 
323610893SQuaker.Fang@Sun.COM 	tx->stop_time.life_time  = LE_32(0xffffffff);
323710893SQuaker.Fang@Sun.COM 
323810893SQuaker.Fang@Sun.COM 	tx->len = LE_16(len);
323910893SQuaker.Fang@Sun.COM 
324010893SQuaker.Fang@Sun.COM 	tx->dram_lsb_ptr =
324110893SQuaker.Fang@Sun.COM 	    LE_32(data->paddr_cmd + 4 + offsetof(iwp_tx_cmd_t, scratch));
324210893SQuaker.Fang@Sun.COM 	tx->dram_msb_ptr = 0;
324310893SQuaker.Fang@Sun.COM 	tx->driver_txop = 0;
324410893SQuaker.Fang@Sun.COM 	tx->next_frame_len = 0;
324510893SQuaker.Fang@Sun.COM 
324610893SQuaker.Fang@Sun.COM 	(void) memcpy(tx + 1, m->b_rptr, hdrlen);
324710893SQuaker.Fang@Sun.COM 	m->b_rptr += hdrlen;
324810893SQuaker.Fang@Sun.COM 	(void) memcpy(data->dma_data.mem_va, m->b_rptr, len - hdrlen);
324910893SQuaker.Fang@Sun.COM 
325010893SQuaker.Fang@Sun.COM 	IWP_DBG((IWP_DEBUG_TX, "iwp_send(): "
325110893SQuaker.Fang@Sun.COM 	    "sending data: qid=%d idx=%d len=%d",
325210893SQuaker.Fang@Sun.COM 	    ring->qid, ring->cur, len));
325310893SQuaker.Fang@Sun.COM 
325410893SQuaker.Fang@Sun.COM 	/*
325510893SQuaker.Fang@Sun.COM 	 * first segment includes the tx cmd plus the 802.11 header,
325610893SQuaker.Fang@Sun.COM 	 * the second includes the remaining of the 802.11 frame.
325710893SQuaker.Fang@Sun.COM 	 */
325810893SQuaker.Fang@Sun.COM 	mutex_enter(&sc->sc_tx_lock);
325910893SQuaker.Fang@Sun.COM 
326010893SQuaker.Fang@Sun.COM 	cmd->hdr.idx = ring->desc_cur;
326110893SQuaker.Fang@Sun.COM 
326210893SQuaker.Fang@Sun.COM 	desc_data = &ring->data[ring->desc_cur];
326310893SQuaker.Fang@Sun.COM 	desc = desc_data->desc;
326410893SQuaker.Fang@Sun.COM 	bzero(desc, sizeof (*desc));
326510893SQuaker.Fang@Sun.COM 	desc->val0 = 2 << 24;
326610893SQuaker.Fang@Sun.COM 	desc->pa[0].tb1_addr = data->paddr_cmd;
326710893SQuaker.Fang@Sun.COM 	desc->pa[0].val1 = ((len0 << 4) & 0xfff0) |
326810893SQuaker.Fang@Sun.COM 	    ((data->dma_data.cookie.dmac_address & 0xffff) << 16);
326910893SQuaker.Fang@Sun.COM 	desc->pa[0].val2 =
327010893SQuaker.Fang@Sun.COM 	    ((data->dma_data.cookie.dmac_address & 0xffff0000) >> 16) |
327110893SQuaker.Fang@Sun.COM 	    ((len - hdrlen) << 20);
327210893SQuaker.Fang@Sun.COM 	IWP_DBG((IWP_DEBUG_TX, "iwp_send(): "
327310893SQuaker.Fang@Sun.COM 	    "phy addr1 = 0x%x phy addr2 = 0x%x "
327410893SQuaker.Fang@Sun.COM 	    "len1 = 0x%x, len2 = 0x%x val1 = 0x%x val2 = 0x%x",
327510893SQuaker.Fang@Sun.COM 	    data->paddr_cmd, data->dma_data.cookie.dmac_address,
327610893SQuaker.Fang@Sun.COM 	    len0, len - hdrlen, desc->pa[0].val1, desc->pa[0].val2));
327710893SQuaker.Fang@Sun.COM 
327810893SQuaker.Fang@Sun.COM 	/*
327910893SQuaker.Fang@Sun.COM 	 * kick ring
328010893SQuaker.Fang@Sun.COM 	 */
328110893SQuaker.Fang@Sun.COM 	s_id = tx->sta_id;
328210893SQuaker.Fang@Sun.COM 
328310893SQuaker.Fang@Sun.COM 	sc->sc_shared->queues_byte_cnt_tbls[ring->qid].
328410893SQuaker.Fang@Sun.COM 	    tfd_offset[ring->desc_cur].val =
328510893SQuaker.Fang@Sun.COM 	    (8 + len) | (s_id << 12);
328610893SQuaker.Fang@Sun.COM 	if (ring->desc_cur < IWP_MAX_WIN_SIZE) {
328710893SQuaker.Fang@Sun.COM 		sc->sc_shared->queues_byte_cnt_tbls[ring->qid].
328810893SQuaker.Fang@Sun.COM 		    tfd_offset[IWP_QUEUE_SIZE + ring->desc_cur].val =
328910893SQuaker.Fang@Sun.COM 		    (8 + len) | (s_id << 12);
329010893SQuaker.Fang@Sun.COM 	}
329110893SQuaker.Fang@Sun.COM 
329210893SQuaker.Fang@Sun.COM 	IWP_DMA_SYNC(data->dma_data, DDI_DMA_SYNC_FORDEV);
329310893SQuaker.Fang@Sun.COM 	IWP_DMA_SYNC(ring->dma_desc, DDI_DMA_SYNC_FORDEV);
329410893SQuaker.Fang@Sun.COM 
329510893SQuaker.Fang@Sun.COM 	ring->desc_cur = (ring->desc_cur + 1) % ring->count;
329610893SQuaker.Fang@Sun.COM 	IWP_WRITE(sc, HBUS_TARG_WRPTR, ring->qid << 8 | ring->desc_cur);
329710893SQuaker.Fang@Sun.COM 
329810893SQuaker.Fang@Sun.COM 	mutex_exit(&sc->sc_tx_lock);
329910893SQuaker.Fang@Sun.COM 	freemsg(m);
330010893SQuaker.Fang@Sun.COM 
330110893SQuaker.Fang@Sun.COM 	/*
330210893SQuaker.Fang@Sun.COM 	 * release node reference
330310893SQuaker.Fang@Sun.COM 	 */
330410893SQuaker.Fang@Sun.COM 	ieee80211_free_node(in);
330510893SQuaker.Fang@Sun.COM 
330610893SQuaker.Fang@Sun.COM 	ic->ic_stats.is_tx_bytes += len;
330710893SQuaker.Fang@Sun.COM 	ic->ic_stats.is_tx_frags++;
330810893SQuaker.Fang@Sun.COM 
330910893SQuaker.Fang@Sun.COM 	mutex_enter(&sc->sc_mt_lock);
331010893SQuaker.Fang@Sun.COM 	if (0 == sc->sc_tx_timer) {
331110893SQuaker.Fang@Sun.COM 		sc->sc_tx_timer = 4;
331210893SQuaker.Fang@Sun.COM 	}
331310893SQuaker.Fang@Sun.COM 	mutex_exit(&sc->sc_mt_lock);
331410893SQuaker.Fang@Sun.COM 
331510893SQuaker.Fang@Sun.COM exit:
331610893SQuaker.Fang@Sun.COM 	return (err);
331710893SQuaker.Fang@Sun.COM }
331810893SQuaker.Fang@Sun.COM 
331910893SQuaker.Fang@Sun.COM /*
332010893SQuaker.Fang@Sun.COM  * invoked by GLD to deal with IOCTL affaires
332110893SQuaker.Fang@Sun.COM  */
332210893SQuaker.Fang@Sun.COM static void
iwp_m_ioctl(void * arg,queue_t * wq,mblk_t * mp)332310893SQuaker.Fang@Sun.COM iwp_m_ioctl(void* arg, queue_t *wq, mblk_t *mp)
332410893SQuaker.Fang@Sun.COM {
332510893SQuaker.Fang@Sun.COM 	iwp_sc_t	*sc;
332610893SQuaker.Fang@Sun.COM 	ieee80211com_t	*ic;
332710893SQuaker.Fang@Sun.COM 	int		err = EINVAL;
332810893SQuaker.Fang@Sun.COM 
332910893SQuaker.Fang@Sun.COM 	if (NULL == arg) {
333010893SQuaker.Fang@Sun.COM 		return;
333110893SQuaker.Fang@Sun.COM 	}
333210893SQuaker.Fang@Sun.COM 	sc = (iwp_sc_t *)arg;
333310893SQuaker.Fang@Sun.COM 	ic = &sc->sc_ic;
333410893SQuaker.Fang@Sun.COM 
333510893SQuaker.Fang@Sun.COM 	err = ieee80211_ioctl(ic, wq, mp);
333610893SQuaker.Fang@Sun.COM 	if (ENETRESET == err) {
333710893SQuaker.Fang@Sun.COM 		/*
333810893SQuaker.Fang@Sun.COM 		 * This is special for the hidden AP connection.
333910893SQuaker.Fang@Sun.COM 		 * In any case, we should make sure only one 'scan'
334010893SQuaker.Fang@Sun.COM 		 * in the driver for a 'connect' CLI command. So
334110893SQuaker.Fang@Sun.COM 		 * when connecting to a hidden AP, the scan is just
334210893SQuaker.Fang@Sun.COM 		 * sent out to the air when we know the desired
334310893SQuaker.Fang@Sun.COM 		 * essid of the AP we want to connect.
334410893SQuaker.Fang@Sun.COM 		 */
334510893SQuaker.Fang@Sun.COM 		if (ic->ic_des_esslen) {
334610893SQuaker.Fang@Sun.COM 			if (sc->sc_flags & IWP_F_RUNNING) {
334710893SQuaker.Fang@Sun.COM 				iwp_m_stop(sc);
334810893SQuaker.Fang@Sun.COM 				(void) iwp_m_start(sc);
334910893SQuaker.Fang@Sun.COM 				(void) ieee80211_new_state(ic,
335010893SQuaker.Fang@Sun.COM 				    IEEE80211_S_SCAN, -1);
335110893SQuaker.Fang@Sun.COM 			}
335210893SQuaker.Fang@Sun.COM 		}
335310893SQuaker.Fang@Sun.COM 	}
335410893SQuaker.Fang@Sun.COM }
335510893SQuaker.Fang@Sun.COM 
335610893SQuaker.Fang@Sun.COM /*
335710893SQuaker.Fang@Sun.COM  * Call back functions for get/set proporty
335810893SQuaker.Fang@Sun.COM  */
335910893SQuaker.Fang@Sun.COM static int
iwp_m_getprop(void * arg,const char * pr_name,mac_prop_id_t wldp_pr_num,uint_t wldp_length,void * wldp_buf)336010893SQuaker.Fang@Sun.COM iwp_m_getprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
3361*11878SVenu.Iyer@Sun.COM     uint_t wldp_length, void *wldp_buf)
336210893SQuaker.Fang@Sun.COM {
336310893SQuaker.Fang@Sun.COM 	iwp_sc_t	*sc;
336410893SQuaker.Fang@Sun.COM 	int		err = EINVAL;
336510893SQuaker.Fang@Sun.COM 
336610893SQuaker.Fang@Sun.COM 	if (NULL == arg) {
336710893SQuaker.Fang@Sun.COM 		return (EINVAL);
336810893SQuaker.Fang@Sun.COM 	}
336910893SQuaker.Fang@Sun.COM 	sc = (iwp_sc_t *)arg;
337010893SQuaker.Fang@Sun.COM 
337110893SQuaker.Fang@Sun.COM 	err = ieee80211_getprop(&sc->sc_ic, pr_name, wldp_pr_num,
3372*11878SVenu.Iyer@Sun.COM 	    wldp_length, wldp_buf);
337310893SQuaker.Fang@Sun.COM 
337410893SQuaker.Fang@Sun.COM 	return (err);
337510893SQuaker.Fang@Sun.COM }
337610893SQuaker.Fang@Sun.COM 
3377*11878SVenu.Iyer@Sun.COM static void
iwp_m_propinfo(void * arg,const char * pr_name,mac_prop_id_t wldp_pr_num,mac_prop_info_handle_t prh)3378*11878SVenu.Iyer@Sun.COM iwp_m_propinfo(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
3379*11878SVenu.Iyer@Sun.COM     mac_prop_info_handle_t prh)
3380*11878SVenu.Iyer@Sun.COM {
3381*11878SVenu.Iyer@Sun.COM 	iwp_sc_t	*sc;
3382*11878SVenu.Iyer@Sun.COM 
3383*11878SVenu.Iyer@Sun.COM 	sc = (iwp_sc_t *)arg;
3384*11878SVenu.Iyer@Sun.COM 	ieee80211_propinfo(&sc->sc_ic, pr_name, wldp_pr_num, prh);
3385*11878SVenu.Iyer@Sun.COM }
3386*11878SVenu.Iyer@Sun.COM 
338710893SQuaker.Fang@Sun.COM static int
iwp_m_setprop(void * arg,const char * pr_name,mac_prop_id_t wldp_pr_num,uint_t wldp_length,const void * wldp_buf)338810893SQuaker.Fang@Sun.COM iwp_m_setprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
338910893SQuaker.Fang@Sun.COM     uint_t wldp_length, const void *wldp_buf)
339010893SQuaker.Fang@Sun.COM {
339110893SQuaker.Fang@Sun.COM 	iwp_sc_t		*sc;
339210893SQuaker.Fang@Sun.COM 	ieee80211com_t		*ic;
339310893SQuaker.Fang@Sun.COM 	int			err = EINVAL;
339410893SQuaker.Fang@Sun.COM 
339510893SQuaker.Fang@Sun.COM 	if (NULL == arg) {
339610893SQuaker.Fang@Sun.COM 		return (EINVAL);
339710893SQuaker.Fang@Sun.COM 	}
339810893SQuaker.Fang@Sun.COM 	sc = (iwp_sc_t *)arg;
339910893SQuaker.Fang@Sun.COM 	ic = &sc->sc_ic;
340010893SQuaker.Fang@Sun.COM 
340110893SQuaker.Fang@Sun.COM 	err = ieee80211_setprop(ic, pr_name, wldp_pr_num, wldp_length,
340210893SQuaker.Fang@Sun.COM 	    wldp_buf);
340310893SQuaker.Fang@Sun.COM 
340410893SQuaker.Fang@Sun.COM 	if (err == ENETRESET) {
340510893SQuaker.Fang@Sun.COM 		if (ic->ic_des_esslen) {
340610893SQuaker.Fang@Sun.COM 			if (sc->sc_flags & IWP_F_RUNNING) {
340710893SQuaker.Fang@Sun.COM 				iwp_m_stop(sc);
340810893SQuaker.Fang@Sun.COM 				(void) iwp_m_start(sc);
340910893SQuaker.Fang@Sun.COM 				(void) ieee80211_new_state(ic,
341010893SQuaker.Fang@Sun.COM 				    IEEE80211_S_SCAN, -1);
341110893SQuaker.Fang@Sun.COM 			}
341210893SQuaker.Fang@Sun.COM 		}
341310893SQuaker.Fang@Sun.COM 		err = 0;
341410893SQuaker.Fang@Sun.COM 	}
341510893SQuaker.Fang@Sun.COM 	return (err);
341610893SQuaker.Fang@Sun.COM }
341710893SQuaker.Fang@Sun.COM 
341810893SQuaker.Fang@Sun.COM /*
341910893SQuaker.Fang@Sun.COM  * invoked by GLD supply statistics NIC and driver
342010893SQuaker.Fang@Sun.COM  */
342110893SQuaker.Fang@Sun.COM static int
iwp_m_stat(void * arg,uint_t stat,uint64_t * val)342210893SQuaker.Fang@Sun.COM iwp_m_stat(void *arg, uint_t stat, uint64_t *val)
342310893SQuaker.Fang@Sun.COM {
342410893SQuaker.Fang@Sun.COM 	iwp_sc_t	*sc;
342510893SQuaker.Fang@Sun.COM 	ieee80211com_t	*ic;
342610893SQuaker.Fang@Sun.COM 	ieee80211_node_t *in;
342710893SQuaker.Fang@Sun.COM 
342810893SQuaker.Fang@Sun.COM 	if (NULL == arg) {
342910893SQuaker.Fang@Sun.COM 		return (EINVAL);
343010893SQuaker.Fang@Sun.COM 	}
343110893SQuaker.Fang@Sun.COM 	sc = (iwp_sc_t *)arg;
343210893SQuaker.Fang@Sun.COM 	ic = &sc->sc_ic;
343310893SQuaker.Fang@Sun.COM 
343410893SQuaker.Fang@Sun.COM 	mutex_enter(&sc->sc_glock);
343510893SQuaker.Fang@Sun.COM 
343610893SQuaker.Fang@Sun.COM 	switch (stat) {
343710893SQuaker.Fang@Sun.COM 	case MAC_STAT_IFSPEED:
343810893SQuaker.Fang@Sun.COM 		in = ic->ic_bss;
343910893SQuaker.Fang@Sun.COM 		*val = ((IEEE80211_FIXED_RATE_NONE == ic->ic_fixed_rate) ?
344010893SQuaker.Fang@Sun.COM 		    IEEE80211_RATE(in->in_txrate) :
344110893SQuaker.Fang@Sun.COM 		    ic->ic_fixed_rate) / 2 * 1000000;
344210893SQuaker.Fang@Sun.COM 		break;
344310893SQuaker.Fang@Sun.COM 	case MAC_STAT_NOXMTBUF:
344410893SQuaker.Fang@Sun.COM 		*val = sc->sc_tx_nobuf;
344510893SQuaker.Fang@Sun.COM 		break;
344610893SQuaker.Fang@Sun.COM 	case MAC_STAT_NORCVBUF:
344710893SQuaker.Fang@Sun.COM 		*val = sc->sc_rx_nobuf;
344810893SQuaker.Fang@Sun.COM 		break;
344910893SQuaker.Fang@Sun.COM 	case MAC_STAT_IERRORS:
345010893SQuaker.Fang@Sun.COM 		*val = sc->sc_rx_err;
345110893SQuaker.Fang@Sun.COM 		break;
345210893SQuaker.Fang@Sun.COM 	case MAC_STAT_RBYTES:
345310893SQuaker.Fang@Sun.COM 		*val = ic->ic_stats.is_rx_bytes;
345410893SQuaker.Fang@Sun.COM 		break;
345510893SQuaker.Fang@Sun.COM 	case MAC_STAT_IPACKETS:
345610893SQuaker.Fang@Sun.COM 		*val = ic->ic_stats.is_rx_frags;
345710893SQuaker.Fang@Sun.COM 		break;
345810893SQuaker.Fang@Sun.COM 	case MAC_STAT_OBYTES:
345910893SQuaker.Fang@Sun.COM 		*val = ic->ic_stats.is_tx_bytes;
346010893SQuaker.Fang@Sun.COM 		break;
346110893SQuaker.Fang@Sun.COM 	case MAC_STAT_OPACKETS:
346210893SQuaker.Fang@Sun.COM 		*val = ic->ic_stats.is_tx_frags;
346310893SQuaker.Fang@Sun.COM 		break;
346410893SQuaker.Fang@Sun.COM 	case MAC_STAT_OERRORS:
346510893SQuaker.Fang@Sun.COM 	case WIFI_STAT_TX_FAILED:
346610893SQuaker.Fang@Sun.COM 		*val = sc->sc_tx_err;
346710893SQuaker.Fang@Sun.COM 		break;
346810893SQuaker.Fang@Sun.COM 	case WIFI_STAT_TX_RETRANS:
346910893SQuaker.Fang@Sun.COM 		*val = sc->sc_tx_retries;
347010893SQuaker.Fang@Sun.COM 		break;
347110893SQuaker.Fang@Sun.COM 	case WIFI_STAT_FCS_ERRORS:
347210893SQuaker.Fang@Sun.COM 	case WIFI_STAT_WEP_ERRORS:
347310893SQuaker.Fang@Sun.COM 	case WIFI_STAT_TX_FRAGS:
347410893SQuaker.Fang@Sun.COM 	case WIFI_STAT_MCAST_TX:
347510893SQuaker.Fang@Sun.COM 	case WIFI_STAT_RTS_SUCCESS:
347610893SQuaker.Fang@Sun.COM 	case WIFI_STAT_RTS_FAILURE:
347710893SQuaker.Fang@Sun.COM 	case WIFI_STAT_ACK_FAILURE:
347810893SQuaker.Fang@Sun.COM 	case WIFI_STAT_RX_FRAGS:
347910893SQuaker.Fang@Sun.COM 	case WIFI_STAT_MCAST_RX:
348010893SQuaker.Fang@Sun.COM 	case WIFI_STAT_RX_DUPS:
348110893SQuaker.Fang@Sun.COM 		mutex_exit(&sc->sc_glock);
348210893SQuaker.Fang@Sun.COM 		return (ieee80211_stat(ic, stat, val));
348310893SQuaker.Fang@Sun.COM 	default:
348410893SQuaker.Fang@Sun.COM 		mutex_exit(&sc->sc_glock);
348510893SQuaker.Fang@Sun.COM 		return (ENOTSUP);
348610893SQuaker.Fang@Sun.COM 	}
348710893SQuaker.Fang@Sun.COM 
348810893SQuaker.Fang@Sun.COM 	mutex_exit(&sc->sc_glock);
348910893SQuaker.Fang@Sun.COM 
349010893SQuaker.Fang@Sun.COM 	return (IWP_SUCCESS);
349110893SQuaker.Fang@Sun.COM 
349210893SQuaker.Fang@Sun.COM }
349310893SQuaker.Fang@Sun.COM 
349410893SQuaker.Fang@Sun.COM /*
349510893SQuaker.Fang@Sun.COM  * invoked by GLD to start or open NIC
349610893SQuaker.Fang@Sun.COM  */
349710893SQuaker.Fang@Sun.COM static int
iwp_m_start(void * arg)349810893SQuaker.Fang@Sun.COM iwp_m_start(void *arg)
349910893SQuaker.Fang@Sun.COM {
350010893SQuaker.Fang@Sun.COM 	iwp_sc_t *sc;
350110893SQuaker.Fang@Sun.COM 	ieee80211com_t	*ic;
350210893SQuaker.Fang@Sun.COM 	int err = IWP_FAIL;
350310893SQuaker.Fang@Sun.COM 
350410893SQuaker.Fang@Sun.COM 	if (NULL == arg) {
350510893SQuaker.Fang@Sun.COM 		return (EINVAL);
350610893SQuaker.Fang@Sun.COM 	}
350710893SQuaker.Fang@Sun.COM 	sc = (iwp_sc_t *)arg;
350810893SQuaker.Fang@Sun.COM 	ic = &sc->sc_ic;
350910893SQuaker.Fang@Sun.COM 
351010893SQuaker.Fang@Sun.COM 	err = iwp_init(sc);
351110893SQuaker.Fang@Sun.COM 	if (err != IWP_SUCCESS) {
351210893SQuaker.Fang@Sun.COM 		/*
351310893SQuaker.Fang@Sun.COM 		 * The hw init err(eg. RF is OFF). Return Success to make
351410893SQuaker.Fang@Sun.COM 		 * the 'plumb' succeed. The iwp_thread() tries to re-init
351510893SQuaker.Fang@Sun.COM 		 * background.
351610893SQuaker.Fang@Sun.COM 		 */
351710893SQuaker.Fang@Sun.COM 		atomic_or_32(&sc->sc_flags, IWP_F_HW_ERR_RECOVER);
351810893SQuaker.Fang@Sun.COM 		return (IWP_SUCCESS);
351910893SQuaker.Fang@Sun.COM 	}
352010893SQuaker.Fang@Sun.COM 
352110893SQuaker.Fang@Sun.COM 	ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
352210893SQuaker.Fang@Sun.COM 
352310893SQuaker.Fang@Sun.COM 	atomic_or_32(&sc->sc_flags, IWP_F_RUNNING);
352410893SQuaker.Fang@Sun.COM 
352510893SQuaker.Fang@Sun.COM 	return (IWP_SUCCESS);
352610893SQuaker.Fang@Sun.COM }
352710893SQuaker.Fang@Sun.COM 
352810893SQuaker.Fang@Sun.COM /*
352910893SQuaker.Fang@Sun.COM  * invoked by GLD to stop or down NIC
353010893SQuaker.Fang@Sun.COM  */
353110893SQuaker.Fang@Sun.COM static void
iwp_m_stop(void * arg)353210893SQuaker.Fang@Sun.COM iwp_m_stop(void *arg)
353310893SQuaker.Fang@Sun.COM {
353410893SQuaker.Fang@Sun.COM 	iwp_sc_t *sc;
353510893SQuaker.Fang@Sun.COM 	ieee80211com_t	*ic;
353610893SQuaker.Fang@Sun.COM 
353710893SQuaker.Fang@Sun.COM 	if (NULL == arg) {
353810893SQuaker.Fang@Sun.COM 		return;
353910893SQuaker.Fang@Sun.COM 	}
354010893SQuaker.Fang@Sun.COM 	sc = (iwp_sc_t *)arg;
354110893SQuaker.Fang@Sun.COM 	ic = &sc->sc_ic;
354210893SQuaker.Fang@Sun.COM 
354310893SQuaker.Fang@Sun.COM 	iwp_stop(sc);
354410893SQuaker.Fang@Sun.COM 
354510893SQuaker.Fang@Sun.COM 	/*
354610893SQuaker.Fang@Sun.COM 	 * release buffer for calibration
354710893SQuaker.Fang@Sun.COM 	 */
354810893SQuaker.Fang@Sun.COM 	iwp_release_calib_buffer(sc);
354910893SQuaker.Fang@Sun.COM 
355010893SQuaker.Fang@Sun.COM 	ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
355110893SQuaker.Fang@Sun.COM 
355210893SQuaker.Fang@Sun.COM 	atomic_and_32(&sc->sc_flags, ~IWP_F_HW_ERR_RECOVER);
355310893SQuaker.Fang@Sun.COM 	atomic_and_32(&sc->sc_flags, ~IWP_F_RATE_AUTO_CTL);
355410893SQuaker.Fang@Sun.COM 
355510893SQuaker.Fang@Sun.COM 	atomic_and_32(&sc->sc_flags, ~IWP_F_RUNNING);
355610893SQuaker.Fang@Sun.COM 	atomic_and_32(&sc->sc_flags, ~IWP_F_SCANNING);
355710893SQuaker.Fang@Sun.COM }
355810893SQuaker.Fang@Sun.COM 
355910893SQuaker.Fang@Sun.COM /*
356010893SQuaker.Fang@Sun.COM  * invoked by GLD to configure NIC
356110893SQuaker.Fang@Sun.COM  */
356210893SQuaker.Fang@Sun.COM static int
iwp_m_unicst(void * arg,const uint8_t * macaddr)356310893SQuaker.Fang@Sun.COM iwp_m_unicst(void *arg, const uint8_t *macaddr)
356410893SQuaker.Fang@Sun.COM {
356510893SQuaker.Fang@Sun.COM 	iwp_sc_t *sc;
356610893SQuaker.Fang@Sun.COM 	ieee80211com_t	*ic;
356710893SQuaker.Fang@Sun.COM 	int err = IWP_SUCCESS;
356810893SQuaker.Fang@Sun.COM 
356910893SQuaker.Fang@Sun.COM 	if (NULL == arg) {
357010893SQuaker.Fang@Sun.COM 		return (EINVAL);
357110893SQuaker.Fang@Sun.COM 	}
357210893SQuaker.Fang@Sun.COM 	sc = (iwp_sc_t *)arg;
357310893SQuaker.Fang@Sun.COM 	ic = &sc->sc_ic;
357410893SQuaker.Fang@Sun.COM 
357510893SQuaker.Fang@Sun.COM 	if (!IEEE80211_ADDR_EQ(ic->ic_macaddr, macaddr)) {
357610893SQuaker.Fang@Sun.COM 		IEEE80211_ADDR_COPY(ic->ic_macaddr, macaddr);
357710893SQuaker.Fang@Sun.COM 		mutex_enter(&sc->sc_glock);
357810893SQuaker.Fang@Sun.COM 		err = iwp_config(sc);
357910893SQuaker.Fang@Sun.COM 		mutex_exit(&sc->sc_glock);
358010893SQuaker.Fang@Sun.COM 		if (err != IWP_SUCCESS) {
358110893SQuaker.Fang@Sun.COM 			cmn_err(CE_WARN, "iwp_m_unicst(): "
358210893SQuaker.Fang@Sun.COM 			    "failed to configure device\n");
358310893SQuaker.Fang@Sun.COM 			goto fail;
358410893SQuaker.Fang@Sun.COM 		}
358510893SQuaker.Fang@Sun.COM 	}
358610893SQuaker.Fang@Sun.COM 
358710893SQuaker.Fang@Sun.COM 	return (err);
358810893SQuaker.Fang@Sun.COM 
358910893SQuaker.Fang@Sun.COM fail:
359010893SQuaker.Fang@Sun.COM 	return (err);
359110893SQuaker.Fang@Sun.COM }
359210893SQuaker.Fang@Sun.COM 
359310893SQuaker.Fang@Sun.COM /* ARGSUSED */
359410893SQuaker.Fang@Sun.COM static int
iwp_m_multicst(void * arg,boolean_t add,const uint8_t * m)359510893SQuaker.Fang@Sun.COM iwp_m_multicst(void *arg, boolean_t add, const uint8_t *m)
359610893SQuaker.Fang@Sun.COM {
359710893SQuaker.Fang@Sun.COM 	return (IWP_SUCCESS);
359810893SQuaker.Fang@Sun.COM }
359910893SQuaker.Fang@Sun.COM 
360010893SQuaker.Fang@Sun.COM /* ARGSUSED */
360110893SQuaker.Fang@Sun.COM static int
iwp_m_promisc(void * arg,boolean_t on)360210893SQuaker.Fang@Sun.COM iwp_m_promisc(void *arg, boolean_t on)
360310893SQuaker.Fang@Sun.COM {
360410893SQuaker.Fang@Sun.COM 	return (IWP_SUCCESS);
360510893SQuaker.Fang@Sun.COM }
360610893SQuaker.Fang@Sun.COM 
360710893SQuaker.Fang@Sun.COM /*
360810893SQuaker.Fang@Sun.COM  * kernel thread to deal with exceptional situation
360910893SQuaker.Fang@Sun.COM  */
361010893SQuaker.Fang@Sun.COM static void
iwp_thread(iwp_sc_t * sc)361110893SQuaker.Fang@Sun.COM iwp_thread(iwp_sc_t *sc)
361210893SQuaker.Fang@Sun.COM {
361310893SQuaker.Fang@Sun.COM 	ieee80211com_t	*ic = &sc->sc_ic;
361410893SQuaker.Fang@Sun.COM 	clock_t clk;
361510893SQuaker.Fang@Sun.COM 	int err, n = 0, timeout = 0;
361610893SQuaker.Fang@Sun.COM 	uint32_t tmp;
361710893SQuaker.Fang@Sun.COM #ifdef	DEBUG
361810893SQuaker.Fang@Sun.COM 	int times = 0;
361910893SQuaker.Fang@Sun.COM #endif
362010893SQuaker.Fang@Sun.COM 
362110893SQuaker.Fang@Sun.COM 	while (sc->sc_mf_thread_switch) {
362210893SQuaker.Fang@Sun.COM 		tmp = IWP_READ(sc, CSR_GP_CNTRL);
362310893SQuaker.Fang@Sun.COM 		if (tmp & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) {
362410893SQuaker.Fang@Sun.COM 			atomic_and_32(&sc->sc_flags, ~IWP_F_RADIO_OFF);
362510893SQuaker.Fang@Sun.COM 		} else {
362610893SQuaker.Fang@Sun.COM 			atomic_or_32(&sc->sc_flags, IWP_F_RADIO_OFF);
362710893SQuaker.Fang@Sun.COM 		}
362810893SQuaker.Fang@Sun.COM 
362910893SQuaker.Fang@Sun.COM 		/*
363010893SQuaker.Fang@Sun.COM 		 * If  in SUSPEND or the RF is OFF, do nothing.
363110893SQuaker.Fang@Sun.COM 		 */
363210893SQuaker.Fang@Sun.COM 		if (sc->sc_flags & IWP_F_RADIO_OFF) {
363310893SQuaker.Fang@Sun.COM 			delay(drv_usectohz(100000));
363410893SQuaker.Fang@Sun.COM 			continue;
363510893SQuaker.Fang@Sun.COM 		}
363610893SQuaker.Fang@Sun.COM 
363710893SQuaker.Fang@Sun.COM 		/*
363810893SQuaker.Fang@Sun.COM 		 * recovery fatal error
363910893SQuaker.Fang@Sun.COM 		 */
364010893SQuaker.Fang@Sun.COM 		if (ic->ic_mach &&
364110893SQuaker.Fang@Sun.COM 		    (sc->sc_flags & IWP_F_HW_ERR_RECOVER)) {
364210893SQuaker.Fang@Sun.COM 
364310893SQuaker.Fang@Sun.COM 			IWP_DBG((IWP_DEBUG_FW, "iwp_thread(): "
364410893SQuaker.Fang@Sun.COM 			    "try to recover fatal hw error: %d\n", times++));
364510893SQuaker.Fang@Sun.COM 
364610893SQuaker.Fang@Sun.COM 			iwp_stop(sc);
364710893SQuaker.Fang@Sun.COM 
364810893SQuaker.Fang@Sun.COM 			if (IWP_CHK_FAST_RECOVER(sc)) {
364910893SQuaker.Fang@Sun.COM 				/* save runtime configuration */
365010893SQuaker.Fang@Sun.COM 				bcopy(&sc->sc_config, &sc->sc_config_save,
365110893SQuaker.Fang@Sun.COM 				    sizeof (sc->sc_config));
365210893SQuaker.Fang@Sun.COM 			} else {
365310893SQuaker.Fang@Sun.COM 				ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
365410893SQuaker.Fang@Sun.COM 				delay(drv_usectohz(2000000 + n*500000));
365510893SQuaker.Fang@Sun.COM 			}
365610893SQuaker.Fang@Sun.COM 
365710893SQuaker.Fang@Sun.COM 			err = iwp_init(sc);
365810893SQuaker.Fang@Sun.COM 			if (err != IWP_SUCCESS) {
365910893SQuaker.Fang@Sun.COM 				n++;
366010893SQuaker.Fang@Sun.COM 				if (n < 20) {
366110893SQuaker.Fang@Sun.COM 					continue;
366210893SQuaker.Fang@Sun.COM 				}
366310893SQuaker.Fang@Sun.COM 			}
366410893SQuaker.Fang@Sun.COM 
366510893SQuaker.Fang@Sun.COM 			n = 0;
366610893SQuaker.Fang@Sun.COM 			if (!err) {
366710893SQuaker.Fang@Sun.COM 				atomic_or_32(&sc->sc_flags, IWP_F_RUNNING);
366810893SQuaker.Fang@Sun.COM 			}
366910893SQuaker.Fang@Sun.COM 
367010893SQuaker.Fang@Sun.COM 
367110893SQuaker.Fang@Sun.COM 			if (!IWP_CHK_FAST_RECOVER(sc) ||
367210893SQuaker.Fang@Sun.COM 			    iwp_fast_recover(sc) != IWP_SUCCESS) {
367310893SQuaker.Fang@Sun.COM 				atomic_and_32(&sc->sc_flags,
367410893SQuaker.Fang@Sun.COM 				    ~IWP_F_HW_ERR_RECOVER);
367510893SQuaker.Fang@Sun.COM 
367610893SQuaker.Fang@Sun.COM 				delay(drv_usectohz(2000000));
367710893SQuaker.Fang@Sun.COM 				if (sc->sc_ostate != IEEE80211_S_INIT) {
367810893SQuaker.Fang@Sun.COM 					ieee80211_new_state(ic,
367910893SQuaker.Fang@Sun.COM 					    IEEE80211_S_SCAN, 0);
368010893SQuaker.Fang@Sun.COM 				}
368110893SQuaker.Fang@Sun.COM 			}
368210893SQuaker.Fang@Sun.COM 		}
368310893SQuaker.Fang@Sun.COM 
368410893SQuaker.Fang@Sun.COM 		if (ic->ic_mach &&
368510893SQuaker.Fang@Sun.COM 		    (sc->sc_flags & IWP_F_SCANNING) && sc->sc_scan_pending) {
368610893SQuaker.Fang@Sun.COM 			IWP_DBG((IWP_DEBUG_SCAN, "iwp_thread(): "
368710893SQuaker.Fang@Sun.COM 			    "wait for probe response\n"));
368810893SQuaker.Fang@Sun.COM 
368910893SQuaker.Fang@Sun.COM 			sc->sc_scan_pending--;
369010893SQuaker.Fang@Sun.COM 			delay(drv_usectohz(200000));
369110893SQuaker.Fang@Sun.COM 			ieee80211_next_scan(ic);
369210893SQuaker.Fang@Sun.COM 		}
369310893SQuaker.Fang@Sun.COM 
369410893SQuaker.Fang@Sun.COM 		/*
369510893SQuaker.Fang@Sun.COM 		 * rate ctl
369610893SQuaker.Fang@Sun.COM 		 */
369710893SQuaker.Fang@Sun.COM 		if (ic->ic_mach &&
369810893SQuaker.Fang@Sun.COM 		    (sc->sc_flags & IWP_F_RATE_AUTO_CTL)) {
369910893SQuaker.Fang@Sun.COM 			clk = ddi_get_lbolt();
370010893SQuaker.Fang@Sun.COM 			if (clk > sc->sc_clk + drv_usectohz(1000000)) {
370110893SQuaker.Fang@Sun.COM 				iwp_amrr_timeout(sc);
370210893SQuaker.Fang@Sun.COM 			}
370310893SQuaker.Fang@Sun.COM 		}
370410893SQuaker.Fang@Sun.COM 
370510893SQuaker.Fang@Sun.COM 		delay(drv_usectohz(100000));
370610893SQuaker.Fang@Sun.COM 
370710893SQuaker.Fang@Sun.COM 		mutex_enter(&sc->sc_mt_lock);
370810893SQuaker.Fang@Sun.COM 		if (sc->sc_tx_timer) {
370910893SQuaker.Fang@Sun.COM 			timeout++;
371010893SQuaker.Fang@Sun.COM 			if (10 == timeout) {
371110893SQuaker.Fang@Sun.COM 				sc->sc_tx_timer--;
371210893SQuaker.Fang@Sun.COM 				if (0 == sc->sc_tx_timer) {
371310893SQuaker.Fang@Sun.COM 					atomic_or_32(&sc->sc_flags,
371410893SQuaker.Fang@Sun.COM 					    IWP_F_HW_ERR_RECOVER);
371510893SQuaker.Fang@Sun.COM 					sc->sc_ostate = IEEE80211_S_RUN;
371610893SQuaker.Fang@Sun.COM 					IWP_DBG((IWP_DEBUG_FW, "iwp_thread(): "
371710893SQuaker.Fang@Sun.COM 					    "try to recover from "
371810893SQuaker.Fang@Sun.COM 					    "send fail\n"));
371910893SQuaker.Fang@Sun.COM 				}
372010893SQuaker.Fang@Sun.COM 				timeout = 0;
372110893SQuaker.Fang@Sun.COM 			}
372210893SQuaker.Fang@Sun.COM 		}
372310893SQuaker.Fang@Sun.COM 		mutex_exit(&sc->sc_mt_lock);
372410893SQuaker.Fang@Sun.COM 	}
372510893SQuaker.Fang@Sun.COM 
372610893SQuaker.Fang@Sun.COM 	mutex_enter(&sc->sc_mt_lock);
372710893SQuaker.Fang@Sun.COM 	sc->sc_mf_thread = NULL;
372810893SQuaker.Fang@Sun.COM 	cv_signal(&sc->sc_mt_cv);
372910893SQuaker.Fang@Sun.COM 	mutex_exit(&sc->sc_mt_lock);
373010893SQuaker.Fang@Sun.COM }
373110893SQuaker.Fang@Sun.COM 
373210893SQuaker.Fang@Sun.COM 
373310893SQuaker.Fang@Sun.COM /*
373410893SQuaker.Fang@Sun.COM  * Send a command to the ucode.
373510893SQuaker.Fang@Sun.COM  */
373610893SQuaker.Fang@Sun.COM static int
iwp_cmd(iwp_sc_t * sc,int code,const void * buf,int size,int async)373710893SQuaker.Fang@Sun.COM iwp_cmd(iwp_sc_t *sc, int code, const void *buf, int size, int async)
373810893SQuaker.Fang@Sun.COM {
373910893SQuaker.Fang@Sun.COM 	iwp_tx_ring_t *ring = &sc->sc_txq[IWP_CMD_QUEUE_NUM];
374010893SQuaker.Fang@Sun.COM 	iwp_tx_desc_t *desc;
374110893SQuaker.Fang@Sun.COM 	iwp_cmd_t *cmd;
374210893SQuaker.Fang@Sun.COM 
374310893SQuaker.Fang@Sun.COM 	ASSERT(size <= sizeof (cmd->data));
374410893SQuaker.Fang@Sun.COM 	ASSERT(mutex_owned(&sc->sc_glock));
374510893SQuaker.Fang@Sun.COM 
374610893SQuaker.Fang@Sun.COM 	IWP_DBG((IWP_DEBUG_CMD, "iwp_cmd() "
374710893SQuaker.Fang@Sun.COM 	    "code[%d]", code));
374810893SQuaker.Fang@Sun.COM 	desc = ring->data[ring->cur].desc;
374910893SQuaker.Fang@Sun.COM 	cmd = ring->data[ring->cur].cmd;
375010893SQuaker.Fang@Sun.COM 
375110893SQuaker.Fang@Sun.COM 	cmd->hdr.type = (uint8_t)code;
375210893SQuaker.Fang@Sun.COM 	cmd->hdr.flags = 0;
375310893SQuaker.Fang@Sun.COM 	cmd->hdr.qid = ring->qid;
375410893SQuaker.Fang@Sun.COM 	cmd->hdr.idx = ring->cur;
375510893SQuaker.Fang@Sun.COM 	(void) memcpy(cmd->data, buf, size);
375610893SQuaker.Fang@Sun.COM 	(void) memset(desc, 0, sizeof (*desc));
375710893SQuaker.Fang@Sun.COM 
375810893SQuaker.Fang@Sun.COM 	desc->val0 = 1 << 24;
375910893SQuaker.Fang@Sun.COM 	desc->pa[0].tb1_addr =
376010893SQuaker.Fang@Sun.COM 	    (uint32_t)(ring->data[ring->cur].paddr_cmd & 0xffffffff);
376110893SQuaker.Fang@Sun.COM 	desc->pa[0].val1 = ((4 + size) << 4) & 0xfff0;
376210893SQuaker.Fang@Sun.COM 
376310893SQuaker.Fang@Sun.COM 	if (async) {
376410893SQuaker.Fang@Sun.COM 		sc->sc_cmd_accum++;
376510893SQuaker.Fang@Sun.COM 	}
376610893SQuaker.Fang@Sun.COM 
376710893SQuaker.Fang@Sun.COM 	/*
376810893SQuaker.Fang@Sun.COM 	 * kick cmd ring XXX
376910893SQuaker.Fang@Sun.COM 	 */
377010893SQuaker.Fang@Sun.COM 	sc->sc_shared->queues_byte_cnt_tbls[ring->qid].
377110893SQuaker.Fang@Sun.COM 	    tfd_offset[ring->cur].val = 8;
377210893SQuaker.Fang@Sun.COM 	if (ring->cur < IWP_MAX_WIN_SIZE) {
377310893SQuaker.Fang@Sun.COM 		sc->sc_shared->queues_byte_cnt_tbls[ring->qid].
377410893SQuaker.Fang@Sun.COM 		    tfd_offset[IWP_QUEUE_SIZE + ring->cur].val = 8;
377510893SQuaker.Fang@Sun.COM 	}
377610893SQuaker.Fang@Sun.COM 	ring->cur = (ring->cur + 1) % ring->count;
377710893SQuaker.Fang@Sun.COM 	IWP_WRITE(sc, HBUS_TARG_WRPTR, ring->qid << 8 | ring->cur);
377810893SQuaker.Fang@Sun.COM 
377910893SQuaker.Fang@Sun.COM 	if (async) {
378010893SQuaker.Fang@Sun.COM 		return (IWP_SUCCESS);
378110893SQuaker.Fang@Sun.COM 	} else {
378210893SQuaker.Fang@Sun.COM 		clock_t clk;
378310893SQuaker.Fang@Sun.COM 
378410893SQuaker.Fang@Sun.COM 		clk = ddi_get_lbolt() + drv_usectohz(2000000);
378510893SQuaker.Fang@Sun.COM 		while (sc->sc_cmd_flag != SC_CMD_FLG_DONE) {
378610893SQuaker.Fang@Sun.COM 			if (cv_timedwait(&sc->sc_cmd_cv,
378710893SQuaker.Fang@Sun.COM 			    &sc->sc_glock, clk) < 0) {
378810893SQuaker.Fang@Sun.COM 				break;
378910893SQuaker.Fang@Sun.COM 			}
379010893SQuaker.Fang@Sun.COM 		}
379110893SQuaker.Fang@Sun.COM 
379210893SQuaker.Fang@Sun.COM 		if (SC_CMD_FLG_DONE == sc->sc_cmd_flag) {
379310893SQuaker.Fang@Sun.COM 			sc->sc_cmd_flag = SC_CMD_FLG_NONE;
379410893SQuaker.Fang@Sun.COM 			return (IWP_SUCCESS);
379510893SQuaker.Fang@Sun.COM 		} else {
379610893SQuaker.Fang@Sun.COM 			sc->sc_cmd_flag = SC_CMD_FLG_NONE;
379710893SQuaker.Fang@Sun.COM 			return (IWP_FAIL);
379810893SQuaker.Fang@Sun.COM 		}
379910893SQuaker.Fang@Sun.COM 	}
380010893SQuaker.Fang@Sun.COM }
380110893SQuaker.Fang@Sun.COM 
380210893SQuaker.Fang@Sun.COM /*
380310893SQuaker.Fang@Sun.COM  * require ucode seting led of NIC
380410893SQuaker.Fang@Sun.COM  */
380510893SQuaker.Fang@Sun.COM static void
iwp_set_led(iwp_sc_t * sc,uint8_t id,uint8_t off,uint8_t on)380610893SQuaker.Fang@Sun.COM iwp_set_led(iwp_sc_t *sc, uint8_t id, uint8_t off, uint8_t on)
380710893SQuaker.Fang@Sun.COM {
380810893SQuaker.Fang@Sun.COM 	iwp_led_cmd_t led;
380910893SQuaker.Fang@Sun.COM 
381010893SQuaker.Fang@Sun.COM 	led.interval = LE_32(100000);	/* unit: 100ms */
381110893SQuaker.Fang@Sun.COM 	led.id = id;
381210893SQuaker.Fang@Sun.COM 	led.off = off;
381310893SQuaker.Fang@Sun.COM 	led.on = on;
381410893SQuaker.Fang@Sun.COM 
381510893SQuaker.Fang@Sun.COM 	(void) iwp_cmd(sc, REPLY_LEDS_CMD, &led, sizeof (led), 1);
381610893SQuaker.Fang@Sun.COM }
381710893SQuaker.Fang@Sun.COM 
381810893SQuaker.Fang@Sun.COM /*
381910893SQuaker.Fang@Sun.COM  * necessary setting to NIC before authentication
382010893SQuaker.Fang@Sun.COM  */
382110893SQuaker.Fang@Sun.COM static int
iwp_hw_set_before_auth(iwp_sc_t * sc)382210893SQuaker.Fang@Sun.COM iwp_hw_set_before_auth(iwp_sc_t *sc)
382310893SQuaker.Fang@Sun.COM {
382410893SQuaker.Fang@Sun.COM 	ieee80211com_t *ic = &sc->sc_ic;
382510893SQuaker.Fang@Sun.COM 	ieee80211_node_t *in = ic->ic_bss;
382610893SQuaker.Fang@Sun.COM 	int err = IWP_FAIL;
382710893SQuaker.Fang@Sun.COM 
382810893SQuaker.Fang@Sun.COM 	/*
382910893SQuaker.Fang@Sun.COM 	 * update adapter's configuration according
383010893SQuaker.Fang@Sun.COM 	 * the info of target AP
383110893SQuaker.Fang@Sun.COM 	 */
383210893SQuaker.Fang@Sun.COM 	IEEE80211_ADDR_COPY(sc->sc_config.bssid, in->in_bssid);
383310893SQuaker.Fang@Sun.COM 	sc->sc_config.chan = LE_16(ieee80211_chan2ieee(ic, in->in_chan));
383410893SQuaker.Fang@Sun.COM 
383510893SQuaker.Fang@Sun.COM 		sc->sc_config.ofdm_ht_triple_stream_basic_rates = 0;
383610893SQuaker.Fang@Sun.COM 		sc->sc_config.ofdm_ht_dual_stream_basic_rates = 0;
383710893SQuaker.Fang@Sun.COM 		sc->sc_config.ofdm_ht_single_stream_basic_rates = 0;
383810893SQuaker.Fang@Sun.COM 
383910893SQuaker.Fang@Sun.COM 		if (IEEE80211_MODE_11B == ic->ic_curmode) {
384010893SQuaker.Fang@Sun.COM 			sc->sc_config.cck_basic_rates  = 0x03;
384110893SQuaker.Fang@Sun.COM 			sc->sc_config.ofdm_basic_rates = 0;
384210893SQuaker.Fang@Sun.COM 		} else if ((in->in_chan != IEEE80211_CHAN_ANYC) &&
384310893SQuaker.Fang@Sun.COM 		    (IEEE80211_IS_CHAN_5GHZ(in->in_chan))) {
384410893SQuaker.Fang@Sun.COM 			sc->sc_config.cck_basic_rates  = 0;
384510893SQuaker.Fang@Sun.COM 			sc->sc_config.ofdm_basic_rates = 0x15;
384610893SQuaker.Fang@Sun.COM 		} else { /* assume 802.11b/g */
384710893SQuaker.Fang@Sun.COM 			sc->sc_config.cck_basic_rates  = 0x0f;
384810893SQuaker.Fang@Sun.COM 			sc->sc_config.ofdm_basic_rates = 0xff;
384910893SQuaker.Fang@Sun.COM 		}
385010893SQuaker.Fang@Sun.COM 
385110893SQuaker.Fang@Sun.COM 	sc->sc_config.flags &= ~LE_32(RXON_FLG_SHORT_PREAMBLE_MSK |
385210893SQuaker.Fang@Sun.COM 	    RXON_FLG_SHORT_SLOT_MSK);
385310893SQuaker.Fang@Sun.COM 
385410893SQuaker.Fang@Sun.COM 	if (ic->ic_flags & IEEE80211_F_SHSLOT) {
385510893SQuaker.Fang@Sun.COM 		sc->sc_config.flags |= LE_32(RXON_FLG_SHORT_SLOT_MSK);
385610893SQuaker.Fang@Sun.COM 	} else {
385710893SQuaker.Fang@Sun.COM 		sc->sc_config.flags &= LE_32(~RXON_FLG_SHORT_SLOT_MSK);
385810893SQuaker.Fang@Sun.COM 	}
385910893SQuaker.Fang@Sun.COM 
386010893SQuaker.Fang@Sun.COM 	if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) {
386110893SQuaker.Fang@Sun.COM 		sc->sc_config.flags |= LE_32(RXON_FLG_SHORT_PREAMBLE_MSK);
386210893SQuaker.Fang@Sun.COM 	} else {
386310893SQuaker.Fang@Sun.COM 		sc->sc_config.flags &= LE_32(~RXON_FLG_SHORT_PREAMBLE_MSK);
386410893SQuaker.Fang@Sun.COM 	}
386510893SQuaker.Fang@Sun.COM 
386610893SQuaker.Fang@Sun.COM 	IWP_DBG((IWP_DEBUG_80211, "iwp_hw_set_before_auth(): "
386710893SQuaker.Fang@Sun.COM 	    "config chan %d flags %x "
386810893SQuaker.Fang@Sun.COM 	    "filter_flags %x  cck %x ofdm %x"
386910893SQuaker.Fang@Sun.COM 	    " bssid:%02x:%02x:%02x:%02x:%02x:%2x\n",
387010893SQuaker.Fang@Sun.COM 	    LE_16(sc->sc_config.chan), LE_32(sc->sc_config.flags),
387110893SQuaker.Fang@Sun.COM 	    LE_32(sc->sc_config.filter_flags),
387210893SQuaker.Fang@Sun.COM 	    sc->sc_config.cck_basic_rates, sc->sc_config.ofdm_basic_rates,
387310893SQuaker.Fang@Sun.COM 	    sc->sc_config.bssid[0], sc->sc_config.bssid[1],
387410893SQuaker.Fang@Sun.COM 	    sc->sc_config.bssid[2], sc->sc_config.bssid[3],
387510893SQuaker.Fang@Sun.COM 	    sc->sc_config.bssid[4], sc->sc_config.bssid[5]));
387610893SQuaker.Fang@Sun.COM 
387710893SQuaker.Fang@Sun.COM 	err = iwp_cmd(sc, REPLY_RXON, &sc->sc_config,
387810893SQuaker.Fang@Sun.COM 	    sizeof (iwp_rxon_cmd_t), 1);
387910893SQuaker.Fang@Sun.COM 	if (err != IWP_SUCCESS) {
388010893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_hw_set_before_auth(): "
388110893SQuaker.Fang@Sun.COM 		    "failed to config chan%d\n", sc->sc_config.chan);
388210893SQuaker.Fang@Sun.COM 		return (err);
388310893SQuaker.Fang@Sun.COM 	}
388410893SQuaker.Fang@Sun.COM 
388510893SQuaker.Fang@Sun.COM 	/*
388610893SQuaker.Fang@Sun.COM 	 * add default AP node
388710893SQuaker.Fang@Sun.COM 	 */
388810893SQuaker.Fang@Sun.COM 	err = iwp_add_ap_sta(sc);
388910893SQuaker.Fang@Sun.COM 	if (err != IWP_SUCCESS) {
389010893SQuaker.Fang@Sun.COM 		return (err);
389110893SQuaker.Fang@Sun.COM 	}
389210893SQuaker.Fang@Sun.COM 
389310893SQuaker.Fang@Sun.COM 
389410893SQuaker.Fang@Sun.COM 	return (err);
389510893SQuaker.Fang@Sun.COM }
389610893SQuaker.Fang@Sun.COM 
389710893SQuaker.Fang@Sun.COM /*
389810893SQuaker.Fang@Sun.COM  * Send a scan request(assembly scan cmd) to the firmware.
389910893SQuaker.Fang@Sun.COM  */
390010893SQuaker.Fang@Sun.COM static int
iwp_scan(iwp_sc_t * sc)390110893SQuaker.Fang@Sun.COM iwp_scan(iwp_sc_t *sc)
390210893SQuaker.Fang@Sun.COM {
390310893SQuaker.Fang@Sun.COM 	ieee80211com_t *ic = &sc->sc_ic;
390410893SQuaker.Fang@Sun.COM 	iwp_tx_ring_t *ring = &sc->sc_txq[IWP_CMD_QUEUE_NUM];
390510893SQuaker.Fang@Sun.COM 	iwp_tx_desc_t *desc;
390610893SQuaker.Fang@Sun.COM 	iwp_tx_data_t *data;
390710893SQuaker.Fang@Sun.COM 	iwp_cmd_t *cmd;
390810893SQuaker.Fang@Sun.COM 	iwp_scan_hdr_t *hdr;
390910893SQuaker.Fang@Sun.COM 	iwp_scan_chan_t chan;
391010893SQuaker.Fang@Sun.COM 	struct ieee80211_frame *wh;
391110893SQuaker.Fang@Sun.COM 	ieee80211_node_t *in = ic->ic_bss;
391210893SQuaker.Fang@Sun.COM 	uint8_t essid[IEEE80211_NWID_LEN+1];
391310893SQuaker.Fang@Sun.COM 	struct ieee80211_rateset *rs;
391410893SQuaker.Fang@Sun.COM 	enum ieee80211_phymode mode;
391510893SQuaker.Fang@Sun.COM 	uint8_t *frm;
391610893SQuaker.Fang@Sun.COM 	int i, pktlen, nrates;
391710893SQuaker.Fang@Sun.COM 
391810893SQuaker.Fang@Sun.COM 	data = &ring->data[ring->cur];
391910893SQuaker.Fang@Sun.COM 	desc = data->desc;
392010893SQuaker.Fang@Sun.COM 	cmd = (iwp_cmd_t *)data->dma_data.mem_va;
392110893SQuaker.Fang@Sun.COM 
392210893SQuaker.Fang@Sun.COM 	cmd->hdr.type = REPLY_SCAN_CMD;
392310893SQuaker.Fang@Sun.COM 	cmd->hdr.flags = 0;
392410893SQuaker.Fang@Sun.COM 	cmd->hdr.qid = ring->qid;
392510893SQuaker.Fang@Sun.COM 	cmd->hdr.idx = ring->cur | 0x40;
392610893SQuaker.Fang@Sun.COM 
392710893SQuaker.Fang@Sun.COM 	hdr = (iwp_scan_hdr_t *)cmd->data;
392810893SQuaker.Fang@Sun.COM 	(void) memset(hdr, 0, sizeof (iwp_scan_hdr_t));
392910893SQuaker.Fang@Sun.COM 	hdr->nchan = 1;
393010893SQuaker.Fang@Sun.COM 	hdr->quiet_time = LE_16(50);
393110893SQuaker.Fang@Sun.COM 	hdr->quiet_plcp_th = LE_16(1);
393210893SQuaker.Fang@Sun.COM 
393310893SQuaker.Fang@Sun.COM 	hdr->flags = LE_32(RXON_FLG_BAND_24G_MSK);
393410893SQuaker.Fang@Sun.COM 	hdr->rx_chain = LE_16(RXON_RX_CHAIN_DRIVER_FORCE_MSK |
393510893SQuaker.Fang@Sun.COM 	    (0x7 << RXON_RX_CHAIN_VALID_POS) |
393610893SQuaker.Fang@Sun.COM 	    (0x2 << RXON_RX_CHAIN_FORCE_SEL_POS) |
393710893SQuaker.Fang@Sun.COM 	    (0x2 << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS));
393810893SQuaker.Fang@Sun.COM 
393910893SQuaker.Fang@Sun.COM 	hdr->tx_cmd.tx_flags = LE_32(TX_CMD_FLG_SEQ_CTL_MSK);
394010893SQuaker.Fang@Sun.COM 	hdr->tx_cmd.sta_id = IWP_BROADCAST_ID;
394110893SQuaker.Fang@Sun.COM 	hdr->tx_cmd.stop_time.life_time = LE_32(0xffffffff);
394210893SQuaker.Fang@Sun.COM 	hdr->tx_cmd.rate.r.rate_n_flags = LE_32(iwp_rate_to_plcp(2));
394310893SQuaker.Fang@Sun.COM 	hdr->tx_cmd.rate.r.rate_n_flags |=
394410893SQuaker.Fang@Sun.COM 	    LE_32(RATE_MCS_ANT_B_MSK |RATE_MCS_CCK_MSK);
394510893SQuaker.Fang@Sun.COM 	hdr->direct_scan[0].len = ic->ic_des_esslen;
394610893SQuaker.Fang@Sun.COM 	hdr->direct_scan[0].id  = IEEE80211_ELEMID_SSID;
394710893SQuaker.Fang@Sun.COM 
394810893SQuaker.Fang@Sun.COM 	hdr->filter_flags = LE_32(RXON_FILTER_ACCEPT_GRP_MSK |
394910893SQuaker.Fang@Sun.COM 	    RXON_FILTER_BCON_AWARE_MSK);
395010893SQuaker.Fang@Sun.COM 
395110893SQuaker.Fang@Sun.COM 	if (ic->ic_des_esslen) {
395210893SQuaker.Fang@Sun.COM 		bcopy(ic->ic_des_essid, essid, ic->ic_des_esslen);
395310893SQuaker.Fang@Sun.COM 		essid[ic->ic_des_esslen] = '\0';
395410893SQuaker.Fang@Sun.COM 		IWP_DBG((IWP_DEBUG_SCAN, "iwp_scan(): "
395510893SQuaker.Fang@Sun.COM 		    "directed scan %s\n", essid));
395610893SQuaker.Fang@Sun.COM 
395710893SQuaker.Fang@Sun.COM 		bcopy(ic->ic_des_essid, hdr->direct_scan[0].ssid,
395810893SQuaker.Fang@Sun.COM 		    ic->ic_des_esslen);
395910893SQuaker.Fang@Sun.COM 	} else {
396010893SQuaker.Fang@Sun.COM 		bzero(hdr->direct_scan[0].ssid,
396110893SQuaker.Fang@Sun.COM 		    sizeof (hdr->direct_scan[0].ssid));
396210893SQuaker.Fang@Sun.COM 	}
396310893SQuaker.Fang@Sun.COM 
396410893SQuaker.Fang@Sun.COM 	/*
396510893SQuaker.Fang@Sun.COM 	 * a probe request frame is required after the REPLY_SCAN_CMD
396610893SQuaker.Fang@Sun.COM 	 */
396710893SQuaker.Fang@Sun.COM 	wh = (struct ieee80211_frame *)(hdr + 1);
396810893SQuaker.Fang@Sun.COM 	wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT |
396910893SQuaker.Fang@Sun.COM 	    IEEE80211_FC0_SUBTYPE_PROBE_REQ;
397010893SQuaker.Fang@Sun.COM 	wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
397110893SQuaker.Fang@Sun.COM 	(void) memset(wh->i_addr1, 0xff, 6);
397210893SQuaker.Fang@Sun.COM 	IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_macaddr);
397310893SQuaker.Fang@Sun.COM 	(void) memset(wh->i_addr3, 0xff, 6);
397410893SQuaker.Fang@Sun.COM 	*(uint16_t *)&wh->i_dur[0] = 0;
397510893SQuaker.Fang@Sun.COM 	*(uint16_t *)&wh->i_seq[0] = 0;
397610893SQuaker.Fang@Sun.COM 
397710893SQuaker.Fang@Sun.COM 	frm = (uint8_t *)(wh + 1);
397810893SQuaker.Fang@Sun.COM 
397910893SQuaker.Fang@Sun.COM 	/*
398010893SQuaker.Fang@Sun.COM 	 * essid IE
398110893SQuaker.Fang@Sun.COM 	 */
398210893SQuaker.Fang@Sun.COM 	if (in->in_esslen) {
398310893SQuaker.Fang@Sun.COM 		bcopy(in->in_essid, essid, in->in_esslen);
398410893SQuaker.Fang@Sun.COM 		essid[in->in_esslen] = '\0';
398510893SQuaker.Fang@Sun.COM 		IWP_DBG((IWP_DEBUG_SCAN, "iwp_scan(): "
398610893SQuaker.Fang@Sun.COM 		    "probe with ESSID %s\n",
398710893SQuaker.Fang@Sun.COM 		    essid));
398810893SQuaker.Fang@Sun.COM 	}
398910893SQuaker.Fang@Sun.COM 	*frm++ = IEEE80211_ELEMID_SSID;
399010893SQuaker.Fang@Sun.COM 	*frm++ = in->in_esslen;
399110893SQuaker.Fang@Sun.COM 	(void) memcpy(frm, in->in_essid, in->in_esslen);
399210893SQuaker.Fang@Sun.COM 	frm += in->in_esslen;
399310893SQuaker.Fang@Sun.COM 
399410893SQuaker.Fang@Sun.COM 	mode = ieee80211_chan2mode(ic, ic->ic_curchan);
399510893SQuaker.Fang@Sun.COM 	rs = &ic->ic_sup_rates[mode];
399610893SQuaker.Fang@Sun.COM 
399710893SQuaker.Fang@Sun.COM 	/*
399810893SQuaker.Fang@Sun.COM 	 * supported rates IE
399910893SQuaker.Fang@Sun.COM 	 */
400010893SQuaker.Fang@Sun.COM 	*frm++ = IEEE80211_ELEMID_RATES;
400110893SQuaker.Fang@Sun.COM 	nrates = rs->ir_nrates;
400210893SQuaker.Fang@Sun.COM 	if (nrates > IEEE80211_RATE_SIZE) {
400310893SQuaker.Fang@Sun.COM 		nrates = IEEE80211_RATE_SIZE;
400410893SQuaker.Fang@Sun.COM 	}
400510893SQuaker.Fang@Sun.COM 
400610893SQuaker.Fang@Sun.COM 	*frm++ = (uint8_t)nrates;
400710893SQuaker.Fang@Sun.COM 	(void) memcpy(frm, rs->ir_rates, nrates);
400810893SQuaker.Fang@Sun.COM 	frm += nrates;
400910893SQuaker.Fang@Sun.COM 
401010893SQuaker.Fang@Sun.COM 	/*
401110893SQuaker.Fang@Sun.COM 	 * supported xrates IE
401210893SQuaker.Fang@Sun.COM 	 */
401310893SQuaker.Fang@Sun.COM 	if (rs->ir_nrates > IEEE80211_RATE_SIZE) {
401410893SQuaker.Fang@Sun.COM 		nrates = rs->ir_nrates - IEEE80211_RATE_SIZE;
401510893SQuaker.Fang@Sun.COM 		*frm++ = IEEE80211_ELEMID_XRATES;
401610893SQuaker.Fang@Sun.COM 		*frm++ = (uint8_t)nrates;
401710893SQuaker.Fang@Sun.COM 		(void) memcpy(frm, rs->ir_rates + IEEE80211_RATE_SIZE, nrates);
401810893SQuaker.Fang@Sun.COM 		frm += nrates;
401910893SQuaker.Fang@Sun.COM 	}
402010893SQuaker.Fang@Sun.COM 
402110893SQuaker.Fang@Sun.COM 	/*
402210893SQuaker.Fang@Sun.COM 	 * optionnal IE (usually for wpa)
402310893SQuaker.Fang@Sun.COM 	 */
402410893SQuaker.Fang@Sun.COM 	if (ic->ic_opt_ie != NULL) {
402510893SQuaker.Fang@Sun.COM 		(void) memcpy(frm, ic->ic_opt_ie, ic->ic_opt_ie_len);
402610893SQuaker.Fang@Sun.COM 		frm += ic->ic_opt_ie_len;
402710893SQuaker.Fang@Sun.COM 	}
402810893SQuaker.Fang@Sun.COM 
402910893SQuaker.Fang@Sun.COM 	/* setup length of probe request */
403010893SQuaker.Fang@Sun.COM 	hdr->tx_cmd.len = LE_16(_PTRDIFF(frm, wh));
403110893SQuaker.Fang@Sun.COM 	hdr->len = LE_16(hdr->nchan * sizeof (iwp_scan_chan_t) +
403210893SQuaker.Fang@Sun.COM 	    LE_16(hdr->tx_cmd.len) + sizeof (iwp_scan_hdr_t));
403310893SQuaker.Fang@Sun.COM 
403410893SQuaker.Fang@Sun.COM 	/*
403510893SQuaker.Fang@Sun.COM 	 * the attribute of the scan channels are required after the probe
403610893SQuaker.Fang@Sun.COM 	 * request frame.
403710893SQuaker.Fang@Sun.COM 	 */
403810893SQuaker.Fang@Sun.COM 	for (i = 1; i <= hdr->nchan; i++) {
403910893SQuaker.Fang@Sun.COM 		if (ic->ic_des_esslen) {
404010893SQuaker.Fang@Sun.COM 			chan.type = LE_32(3);
404110893SQuaker.Fang@Sun.COM 		} else {
404210893SQuaker.Fang@Sun.COM 			chan.type = LE_32(1);
404310893SQuaker.Fang@Sun.COM 		}
404410893SQuaker.Fang@Sun.COM 
404510893SQuaker.Fang@Sun.COM 		chan.chan = LE_16(ieee80211_chan2ieee(ic, ic->ic_curchan));
404610893SQuaker.Fang@Sun.COM 		chan.tpc.tx_gain = 0x28;
404710893SQuaker.Fang@Sun.COM 		chan.tpc.dsp_atten = 110;
404810893SQuaker.Fang@Sun.COM 		chan.active_dwell = LE_16(50);
404910893SQuaker.Fang@Sun.COM 		chan.passive_dwell = LE_16(120);
405010893SQuaker.Fang@Sun.COM 
405110893SQuaker.Fang@Sun.COM 		bcopy(&chan, frm, sizeof (iwp_scan_chan_t));
405210893SQuaker.Fang@Sun.COM 		frm += sizeof (iwp_scan_chan_t);
405310893SQuaker.Fang@Sun.COM 	}
405410893SQuaker.Fang@Sun.COM 
405510893SQuaker.Fang@Sun.COM 	pktlen = _PTRDIFF(frm, cmd);
405610893SQuaker.Fang@Sun.COM 
405710893SQuaker.Fang@Sun.COM 	(void) memset(desc, 0, sizeof (*desc));
405810893SQuaker.Fang@Sun.COM 	desc->val0 = 1 << 24;
405910893SQuaker.Fang@Sun.COM 	desc->pa[0].tb1_addr =
406010893SQuaker.Fang@Sun.COM 	    (uint32_t)(data->dma_data.cookie.dmac_address & 0xffffffff);
406110893SQuaker.Fang@Sun.COM 	desc->pa[0].val1 = (pktlen << 4) & 0xfff0;
406210893SQuaker.Fang@Sun.COM 
406310893SQuaker.Fang@Sun.COM 	/*
406410893SQuaker.Fang@Sun.COM 	 * maybe for cmd, filling the byte cnt table is not necessary.
406510893SQuaker.Fang@Sun.COM 	 * anyway, we fill it here.
406610893SQuaker.Fang@Sun.COM 	 */
406710893SQuaker.Fang@Sun.COM 	sc->sc_shared->queues_byte_cnt_tbls[ring->qid]
406810893SQuaker.Fang@Sun.COM 	    .tfd_offset[ring->cur].val = 8;
406910893SQuaker.Fang@Sun.COM 	if (ring->cur < IWP_MAX_WIN_SIZE) {
407010893SQuaker.Fang@Sun.COM 		sc->sc_shared->queues_byte_cnt_tbls[ring->qid].
407110893SQuaker.Fang@Sun.COM 		    tfd_offset[IWP_QUEUE_SIZE + ring->cur].val = 8;
407210893SQuaker.Fang@Sun.COM 	}
407310893SQuaker.Fang@Sun.COM 
407410893SQuaker.Fang@Sun.COM 	/*
407510893SQuaker.Fang@Sun.COM 	 * kick cmd ring
407610893SQuaker.Fang@Sun.COM 	 */
407710893SQuaker.Fang@Sun.COM 	ring->cur = (ring->cur + 1) % ring->count;
407810893SQuaker.Fang@Sun.COM 	IWP_WRITE(sc, HBUS_TARG_WRPTR, ring->qid << 8 | ring->cur);
407910893SQuaker.Fang@Sun.COM 
408010893SQuaker.Fang@Sun.COM 	return (IWP_SUCCESS);
408110893SQuaker.Fang@Sun.COM }
408210893SQuaker.Fang@Sun.COM 
408310893SQuaker.Fang@Sun.COM /*
408410893SQuaker.Fang@Sun.COM  * configure NIC by using ucode commands after loading ucode.
408510893SQuaker.Fang@Sun.COM  */
408610893SQuaker.Fang@Sun.COM static int
iwp_config(iwp_sc_t * sc)408710893SQuaker.Fang@Sun.COM iwp_config(iwp_sc_t *sc)
408810893SQuaker.Fang@Sun.COM {
408910893SQuaker.Fang@Sun.COM 	ieee80211com_t *ic = &sc->sc_ic;
409010893SQuaker.Fang@Sun.COM 	iwp_powertable_cmd_t powertable;
409110893SQuaker.Fang@Sun.COM 	iwp_bt_cmd_t bt;
409210893SQuaker.Fang@Sun.COM 	iwp_add_sta_t node;
409310893SQuaker.Fang@Sun.COM 	iwp_rem_sta_t	rm_sta;
409410893SQuaker.Fang@Sun.COM 	const uint8_t bcast[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
409510893SQuaker.Fang@Sun.COM 	int err = IWP_FAIL;
409610893SQuaker.Fang@Sun.COM 
409710893SQuaker.Fang@Sun.COM 	/*
409810893SQuaker.Fang@Sun.COM 	 * set power mode. Disable power management at present, do it later
409910893SQuaker.Fang@Sun.COM 	 */
410010893SQuaker.Fang@Sun.COM 	(void) memset(&powertable, 0, sizeof (powertable));
410110893SQuaker.Fang@Sun.COM 	powertable.flags = LE_16(0x8);
410210893SQuaker.Fang@Sun.COM 	err = iwp_cmd(sc, POWER_TABLE_CMD, &powertable,
410310893SQuaker.Fang@Sun.COM 	    sizeof (powertable), 0);
410410893SQuaker.Fang@Sun.COM 	if (err != IWP_SUCCESS) {
410510893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_config(): "
410610893SQuaker.Fang@Sun.COM 		    "failed to set power mode\n");
410710893SQuaker.Fang@Sun.COM 		return (err);
410810893SQuaker.Fang@Sun.COM 	}
410910893SQuaker.Fang@Sun.COM 
411010893SQuaker.Fang@Sun.COM 	/*
411110893SQuaker.Fang@Sun.COM 	 * configure bt coexistence
411210893SQuaker.Fang@Sun.COM 	 */
411310893SQuaker.Fang@Sun.COM 	(void) memset(&bt, 0, sizeof (bt));
411410893SQuaker.Fang@Sun.COM 	bt.flags = 3;
411510893SQuaker.Fang@Sun.COM 	bt.lead_time = 0xaa;
411610893SQuaker.Fang@Sun.COM 	bt.max_kill = 1;
411710893SQuaker.Fang@Sun.COM 	err = iwp_cmd(sc, REPLY_BT_CONFIG, &bt,
411810893SQuaker.Fang@Sun.COM 	    sizeof (bt), 0);
411910893SQuaker.Fang@Sun.COM 	if (err != IWP_SUCCESS) {
412010893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_config(): "
412110893SQuaker.Fang@Sun.COM 		    "failed to configurate bt coexistence\n");
412210893SQuaker.Fang@Sun.COM 		return (err);
412310893SQuaker.Fang@Sun.COM 	}
412410893SQuaker.Fang@Sun.COM 
412510893SQuaker.Fang@Sun.COM 	/*
412610893SQuaker.Fang@Sun.COM 	 * configure rxon
412710893SQuaker.Fang@Sun.COM 	 */
412810893SQuaker.Fang@Sun.COM 	(void) memset(&sc->sc_config, 0, sizeof (iwp_rxon_cmd_t));
412910893SQuaker.Fang@Sun.COM 	IEEE80211_ADDR_COPY(sc->sc_config.node_addr, ic->ic_macaddr);
413010893SQuaker.Fang@Sun.COM 	IEEE80211_ADDR_COPY(sc->sc_config.wlap_bssid, ic->ic_macaddr);
413110893SQuaker.Fang@Sun.COM 	sc->sc_config.chan = LE_16(ieee80211_chan2ieee(ic, ic->ic_curchan));
413210893SQuaker.Fang@Sun.COM 	sc->sc_config.flags = LE_32(RXON_FLG_BAND_24G_MSK);
413310893SQuaker.Fang@Sun.COM 	sc->sc_config.flags &= LE_32(~(RXON_FLG_CHANNEL_MODE_MIXED_MSK |
413410893SQuaker.Fang@Sun.COM 	    RXON_FLG_CHANNEL_MODE_PURE_40_MSK));
413510893SQuaker.Fang@Sun.COM 
413610893SQuaker.Fang@Sun.COM 	switch (ic->ic_opmode) {
413710893SQuaker.Fang@Sun.COM 	case IEEE80211_M_STA:
413810893SQuaker.Fang@Sun.COM 		sc->sc_config.dev_type = RXON_DEV_TYPE_ESS;
413910893SQuaker.Fang@Sun.COM 		sc->sc_config.filter_flags |= LE_32(RXON_FILTER_ACCEPT_GRP_MSK |
414010893SQuaker.Fang@Sun.COM 		    RXON_FILTER_DIS_DECRYPT_MSK |
414110893SQuaker.Fang@Sun.COM 		    RXON_FILTER_DIS_GRP_DECRYPT_MSK);
414210893SQuaker.Fang@Sun.COM 		break;
414310893SQuaker.Fang@Sun.COM 	case IEEE80211_M_IBSS:
414410893SQuaker.Fang@Sun.COM 	case IEEE80211_M_AHDEMO:
414510893SQuaker.Fang@Sun.COM 		sc->sc_config.dev_type = RXON_DEV_TYPE_IBSS;
414610893SQuaker.Fang@Sun.COM 
414710893SQuaker.Fang@Sun.COM 		sc->sc_config.flags |= LE_32(RXON_FLG_SHORT_PREAMBLE_MSK);
414810893SQuaker.Fang@Sun.COM 		sc->sc_config.filter_flags = LE_32(RXON_FILTER_ACCEPT_GRP_MSK |
414910893SQuaker.Fang@Sun.COM 		    RXON_FILTER_DIS_DECRYPT_MSK |
415010893SQuaker.Fang@Sun.COM 		    RXON_FILTER_DIS_GRP_DECRYPT_MSK);
415110893SQuaker.Fang@Sun.COM 		break;
415210893SQuaker.Fang@Sun.COM 	case IEEE80211_M_HOSTAP:
415310893SQuaker.Fang@Sun.COM 		sc->sc_config.dev_type = RXON_DEV_TYPE_AP;
415410893SQuaker.Fang@Sun.COM 		break;
415510893SQuaker.Fang@Sun.COM 	case IEEE80211_M_MONITOR:
415610893SQuaker.Fang@Sun.COM 		sc->sc_config.dev_type = RXON_DEV_TYPE_SNIFFER;
415710893SQuaker.Fang@Sun.COM 		sc->sc_config.filter_flags |= LE_32(RXON_FILTER_ACCEPT_GRP_MSK |
415810893SQuaker.Fang@Sun.COM 		    RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_PROMISC_MSK);
415910893SQuaker.Fang@Sun.COM 		break;
416010893SQuaker.Fang@Sun.COM 	}
416110893SQuaker.Fang@Sun.COM 
416210893SQuaker.Fang@Sun.COM 	/*
416310893SQuaker.Fang@Sun.COM 	 * Support all CCK rates.
416410893SQuaker.Fang@Sun.COM 	 */
416510893SQuaker.Fang@Sun.COM 	sc->sc_config.cck_basic_rates  = 0x0f;
416610893SQuaker.Fang@Sun.COM 
416710893SQuaker.Fang@Sun.COM 	/*
416810893SQuaker.Fang@Sun.COM 	 * Support all OFDM rates.
416910893SQuaker.Fang@Sun.COM 	 */
417010893SQuaker.Fang@Sun.COM 	sc->sc_config.ofdm_basic_rates = 0xff;
417110893SQuaker.Fang@Sun.COM 
417210893SQuaker.Fang@Sun.COM 	sc->sc_config.rx_chain = LE_16(RXON_RX_CHAIN_DRIVER_FORCE_MSK |
417310893SQuaker.Fang@Sun.COM 	    (0x7 << RXON_RX_CHAIN_VALID_POS) |
417410893SQuaker.Fang@Sun.COM 	    (0x2 << RXON_RX_CHAIN_FORCE_SEL_POS) |
417510893SQuaker.Fang@Sun.COM 	    (0x2 << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS));
417610893SQuaker.Fang@Sun.COM 
417710893SQuaker.Fang@Sun.COM 	err = iwp_cmd(sc, REPLY_RXON, &sc->sc_config,
417810893SQuaker.Fang@Sun.COM 	    sizeof (iwp_rxon_cmd_t), 0);
417910893SQuaker.Fang@Sun.COM 	if (err != IWP_SUCCESS) {
418010893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_config(): "
418110893SQuaker.Fang@Sun.COM 		    "failed to set configure command\n");
418210893SQuaker.Fang@Sun.COM 		return (err);
418310893SQuaker.Fang@Sun.COM 	}
418410893SQuaker.Fang@Sun.COM 
418510893SQuaker.Fang@Sun.COM 	/*
418610893SQuaker.Fang@Sun.COM 	 * remove all nodes in NIC
418710893SQuaker.Fang@Sun.COM 	 */
418810893SQuaker.Fang@Sun.COM 	(void) memset(&rm_sta, 0, sizeof (rm_sta));
418910893SQuaker.Fang@Sun.COM 	rm_sta.num_sta = 1;
419010893SQuaker.Fang@Sun.COM 	(void) memcpy(rm_sta.addr, bcast, 6);
419110893SQuaker.Fang@Sun.COM 
419210893SQuaker.Fang@Sun.COM 	err = iwp_cmd(sc, REPLY_REMOVE_STA, &rm_sta, sizeof (iwp_rem_sta_t), 0);
419310893SQuaker.Fang@Sun.COM 	if (err != IWP_SUCCESS) {
419410893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_config(): "
419510893SQuaker.Fang@Sun.COM 		    "failed to remove broadcast node in hardware.\n");
419610893SQuaker.Fang@Sun.COM 		return (err);
419710893SQuaker.Fang@Sun.COM 	}
419810893SQuaker.Fang@Sun.COM 
419910893SQuaker.Fang@Sun.COM 	/*
420010893SQuaker.Fang@Sun.COM 	 * add broadcast node so that we can send broadcast frame
420110893SQuaker.Fang@Sun.COM 	 */
420210893SQuaker.Fang@Sun.COM 	(void) memset(&node, 0, sizeof (node));
420310893SQuaker.Fang@Sun.COM 	(void) memset(node.sta.addr, 0xff, 6);
420410893SQuaker.Fang@Sun.COM 	node.mode = 0;
420510893SQuaker.Fang@Sun.COM 	node.sta.sta_id = IWP_BROADCAST_ID;
420610893SQuaker.Fang@Sun.COM 	node.station_flags = 0;
420710893SQuaker.Fang@Sun.COM 
420810893SQuaker.Fang@Sun.COM 	err = iwp_cmd(sc, REPLY_ADD_STA, &node, sizeof (node), 0);
420910893SQuaker.Fang@Sun.COM 	if (err != IWP_SUCCESS) {
421010893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_config(): "
421110893SQuaker.Fang@Sun.COM 		    "failed to add broadcast node\n");
421210893SQuaker.Fang@Sun.COM 		return (err);
421310893SQuaker.Fang@Sun.COM 	}
421410893SQuaker.Fang@Sun.COM 
421510893SQuaker.Fang@Sun.COM 	return (err);
421610893SQuaker.Fang@Sun.COM }
421710893SQuaker.Fang@Sun.COM 
421810893SQuaker.Fang@Sun.COM /*
421910893SQuaker.Fang@Sun.COM  * quiesce(9E) entry point.
422010893SQuaker.Fang@Sun.COM  * This function is called when the system is single-threaded at high
422110893SQuaker.Fang@Sun.COM  * PIL with preemption disabled. Therefore, this function must not be
422210893SQuaker.Fang@Sun.COM  * blocked.
422310893SQuaker.Fang@Sun.COM  * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
422410893SQuaker.Fang@Sun.COM  * DDI_FAILURE indicates an error condition and should almost never happen.
422510893SQuaker.Fang@Sun.COM  */
422610893SQuaker.Fang@Sun.COM static int
iwp_quiesce(dev_info_t * dip)422710893SQuaker.Fang@Sun.COM iwp_quiesce(dev_info_t *dip)
422810893SQuaker.Fang@Sun.COM {
422910893SQuaker.Fang@Sun.COM 	iwp_sc_t *sc;
423010893SQuaker.Fang@Sun.COM 
423110893SQuaker.Fang@Sun.COM 	sc = ddi_get_soft_state(iwp_soft_state_p, ddi_get_instance(dip));
423210893SQuaker.Fang@Sun.COM 	if (NULL == sc) {
423310893SQuaker.Fang@Sun.COM 		return (DDI_FAILURE);
423410893SQuaker.Fang@Sun.COM 	}
423510893SQuaker.Fang@Sun.COM 
423610893SQuaker.Fang@Sun.COM #ifdef DEBUG
423710893SQuaker.Fang@Sun.COM 	/* by pass any messages, if it's quiesce */
423810893SQuaker.Fang@Sun.COM 	iwp_dbg_flags = 0;
423910893SQuaker.Fang@Sun.COM #endif
424010893SQuaker.Fang@Sun.COM 
424110893SQuaker.Fang@Sun.COM 	/*
424210893SQuaker.Fang@Sun.COM 	 * No more blocking is allowed while we are in the
424310893SQuaker.Fang@Sun.COM 	 * quiesce(9E) entry point.
424410893SQuaker.Fang@Sun.COM 	 */
424510893SQuaker.Fang@Sun.COM 	atomic_or_32(&sc->sc_flags, IWP_F_QUIESCED);
424610893SQuaker.Fang@Sun.COM 
424710893SQuaker.Fang@Sun.COM 	/*
424810893SQuaker.Fang@Sun.COM 	 * Disable and mask all interrupts.
424910893SQuaker.Fang@Sun.COM 	 */
425010893SQuaker.Fang@Sun.COM 	iwp_stop(sc);
425110893SQuaker.Fang@Sun.COM 
425210893SQuaker.Fang@Sun.COM 	return (DDI_SUCCESS);
425310893SQuaker.Fang@Sun.COM }
425410893SQuaker.Fang@Sun.COM 
425510893SQuaker.Fang@Sun.COM static void
iwp_stop_master(iwp_sc_t * sc)425610893SQuaker.Fang@Sun.COM iwp_stop_master(iwp_sc_t *sc)
425710893SQuaker.Fang@Sun.COM {
425810893SQuaker.Fang@Sun.COM 	uint32_t tmp;
425910893SQuaker.Fang@Sun.COM 	int n;
426010893SQuaker.Fang@Sun.COM 
426110893SQuaker.Fang@Sun.COM 	tmp = IWP_READ(sc, CSR_RESET);
426210893SQuaker.Fang@Sun.COM 	IWP_WRITE(sc, CSR_RESET, tmp | CSR_RESET_REG_FLAG_STOP_MASTER);
426310893SQuaker.Fang@Sun.COM 
426410893SQuaker.Fang@Sun.COM 	tmp = IWP_READ(sc, CSR_GP_CNTRL);
426510893SQuaker.Fang@Sun.COM 	if ((tmp & CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE) ==
426610893SQuaker.Fang@Sun.COM 	    CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE) {
426710893SQuaker.Fang@Sun.COM 		return;
426810893SQuaker.Fang@Sun.COM 	}
426910893SQuaker.Fang@Sun.COM 
427010893SQuaker.Fang@Sun.COM 	for (n = 0; n < 2000; n++) {
427110893SQuaker.Fang@Sun.COM 		if (IWP_READ(sc, CSR_RESET) &
427210893SQuaker.Fang@Sun.COM 		    CSR_RESET_REG_FLAG_MASTER_DISABLED) {
427310893SQuaker.Fang@Sun.COM 			break;
427410893SQuaker.Fang@Sun.COM 		}
427510893SQuaker.Fang@Sun.COM 		DELAY(1000);
427610893SQuaker.Fang@Sun.COM 	}
427710893SQuaker.Fang@Sun.COM 
427810893SQuaker.Fang@Sun.COM #ifdef	DEBUG
427910893SQuaker.Fang@Sun.COM 	if (2000 == n) {
428010893SQuaker.Fang@Sun.COM 		IWP_DBG((IWP_DEBUG_HW, "iwp_stop_master(): "
428110893SQuaker.Fang@Sun.COM 		    "timeout waiting for master stop\n"));
428210893SQuaker.Fang@Sun.COM 	}
428310893SQuaker.Fang@Sun.COM #endif
428410893SQuaker.Fang@Sun.COM }
428510893SQuaker.Fang@Sun.COM 
428610893SQuaker.Fang@Sun.COM static int
iwp_power_up(iwp_sc_t * sc)428710893SQuaker.Fang@Sun.COM iwp_power_up(iwp_sc_t *sc)
428810893SQuaker.Fang@Sun.COM {
428910893SQuaker.Fang@Sun.COM 	uint32_t tmp;
429010893SQuaker.Fang@Sun.COM 
429110893SQuaker.Fang@Sun.COM 	iwp_mac_access_enter(sc);
429210893SQuaker.Fang@Sun.COM 	tmp = iwp_reg_read(sc, ALM_APMG_PS_CTL);
429310893SQuaker.Fang@Sun.COM 	tmp &= ~APMG_PS_CTRL_REG_MSK_POWER_SRC;
429410893SQuaker.Fang@Sun.COM 	tmp |= APMG_PS_CTRL_REG_VAL_POWER_SRC_VMAIN;
429510893SQuaker.Fang@Sun.COM 	iwp_reg_write(sc, ALM_APMG_PS_CTL, tmp);
429610893SQuaker.Fang@Sun.COM 	iwp_mac_access_exit(sc);
429710893SQuaker.Fang@Sun.COM 
429810893SQuaker.Fang@Sun.COM 	DELAY(5000);
429910893SQuaker.Fang@Sun.COM 	return (IWP_SUCCESS);
430010893SQuaker.Fang@Sun.COM }
430110893SQuaker.Fang@Sun.COM 
430210893SQuaker.Fang@Sun.COM /*
430310893SQuaker.Fang@Sun.COM  * hardware initialization
430410893SQuaker.Fang@Sun.COM  */
430510893SQuaker.Fang@Sun.COM static int
iwp_preinit(iwp_sc_t * sc)430610893SQuaker.Fang@Sun.COM iwp_preinit(iwp_sc_t *sc)
430710893SQuaker.Fang@Sun.COM {
430810893SQuaker.Fang@Sun.COM 	int		n;
430910893SQuaker.Fang@Sun.COM 	uint8_t		vlink;
431010893SQuaker.Fang@Sun.COM 	uint16_t	radio_cfg;
431110893SQuaker.Fang@Sun.COM 	uint32_t	tmp;
431210893SQuaker.Fang@Sun.COM 
431310893SQuaker.Fang@Sun.COM 	/*
431410893SQuaker.Fang@Sun.COM 	 * clear any pending interrupts
431510893SQuaker.Fang@Sun.COM 	 */
431610893SQuaker.Fang@Sun.COM 	IWP_WRITE(sc, CSR_INT, 0xffffffff);
431710893SQuaker.Fang@Sun.COM 
431810893SQuaker.Fang@Sun.COM 	tmp = IWP_READ(sc, CSR_GIO_CHICKEN_BITS);
431910893SQuaker.Fang@Sun.COM 	IWP_WRITE(sc, CSR_GIO_CHICKEN_BITS,
432010893SQuaker.Fang@Sun.COM 	    tmp | CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
432110893SQuaker.Fang@Sun.COM 
432210893SQuaker.Fang@Sun.COM 	tmp = IWP_READ(sc, CSR_GP_CNTRL);
432310893SQuaker.Fang@Sun.COM 	IWP_WRITE(sc, CSR_GP_CNTRL, tmp | CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
432410893SQuaker.Fang@Sun.COM 
432510893SQuaker.Fang@Sun.COM 	/*
432610893SQuaker.Fang@Sun.COM 	 * wait for clock ready
432710893SQuaker.Fang@Sun.COM 	 */
432810893SQuaker.Fang@Sun.COM 	for (n = 0; n < 1000; n++) {
432910893SQuaker.Fang@Sun.COM 		if (IWP_READ(sc, CSR_GP_CNTRL) &
433010893SQuaker.Fang@Sun.COM 		    CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY) {
433110893SQuaker.Fang@Sun.COM 			break;
433210893SQuaker.Fang@Sun.COM 		}
433310893SQuaker.Fang@Sun.COM 		DELAY(10);
433410893SQuaker.Fang@Sun.COM 	}
433510893SQuaker.Fang@Sun.COM 
433610893SQuaker.Fang@Sun.COM 	if (1000 == n) {
433710893SQuaker.Fang@Sun.COM 		return (ETIMEDOUT);
433810893SQuaker.Fang@Sun.COM 	}
433910893SQuaker.Fang@Sun.COM 
434010893SQuaker.Fang@Sun.COM 	iwp_mac_access_enter(sc);
434110893SQuaker.Fang@Sun.COM 
434210893SQuaker.Fang@Sun.COM 	iwp_reg_write(sc, ALM_APMG_CLK_EN, APMG_CLK_REG_VAL_DMA_CLK_RQT);
434310893SQuaker.Fang@Sun.COM 
434410893SQuaker.Fang@Sun.COM 	DELAY(20);
434510893SQuaker.Fang@Sun.COM 	tmp = iwp_reg_read(sc, ALM_APMG_PCIDEV_STT);
434610893SQuaker.Fang@Sun.COM 	iwp_reg_write(sc, ALM_APMG_PCIDEV_STT, tmp |
434710893SQuaker.Fang@Sun.COM 	    APMG_DEV_STATE_REG_VAL_L1_ACTIVE_DISABLE);
434810893SQuaker.Fang@Sun.COM 	iwp_mac_access_exit(sc);
434910893SQuaker.Fang@Sun.COM 
435010893SQuaker.Fang@Sun.COM 	radio_cfg = IWP_READ_EEP_SHORT(sc, EEP_SP_RADIO_CONFIGURATION);
435110893SQuaker.Fang@Sun.COM 	if (SP_RADIO_TYPE_MSK(radio_cfg) < SP_RADIO_TYPE_MAX) {
435210893SQuaker.Fang@Sun.COM 		tmp = IWP_READ(sc, CSR_HW_IF_CONFIG_REG);
435310893SQuaker.Fang@Sun.COM 		IWP_WRITE(sc, CSR_HW_IF_CONFIG_REG,
435410893SQuaker.Fang@Sun.COM 		    tmp | SP_RADIO_TYPE_MSK(radio_cfg) |
435510893SQuaker.Fang@Sun.COM 		    SP_RADIO_STEP_MSK(radio_cfg) |
435610893SQuaker.Fang@Sun.COM 		    SP_RADIO_DASH_MSK(radio_cfg));
435710893SQuaker.Fang@Sun.COM 	} else {
435810893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_preinit(): "
435910893SQuaker.Fang@Sun.COM 		    "radio configuration information in eeprom is wrong\n");
436010893SQuaker.Fang@Sun.COM 		return (IWP_FAIL);
436110893SQuaker.Fang@Sun.COM 	}
436210893SQuaker.Fang@Sun.COM 
436310893SQuaker.Fang@Sun.COM 
436410893SQuaker.Fang@Sun.COM 	IWP_WRITE(sc, CSR_INT_COALESCING, 512 / 32);
436510893SQuaker.Fang@Sun.COM 
436610893SQuaker.Fang@Sun.COM 	(void) iwp_power_up(sc);
436710893SQuaker.Fang@Sun.COM 
436810893SQuaker.Fang@Sun.COM 	if ((sc->sc_rev & 0x80) == 0x80 && (sc->sc_rev & 0x7f) < 8) {
436910893SQuaker.Fang@Sun.COM 		tmp = ddi_get32(sc->sc_cfg_handle,
437010893SQuaker.Fang@Sun.COM 		    (uint32_t *)(sc->sc_cfg_base + 0xe8));
437110893SQuaker.Fang@Sun.COM 		ddi_put32(sc->sc_cfg_handle,
437210893SQuaker.Fang@Sun.COM 		    (uint32_t *)(sc->sc_cfg_base + 0xe8),
437310893SQuaker.Fang@Sun.COM 		    tmp & ~(1 << 11));
437410893SQuaker.Fang@Sun.COM 	}
437510893SQuaker.Fang@Sun.COM 
437610893SQuaker.Fang@Sun.COM 	vlink = ddi_get8(sc->sc_cfg_handle,
437710893SQuaker.Fang@Sun.COM 	    (uint8_t *)(sc->sc_cfg_base + 0xf0));
437810893SQuaker.Fang@Sun.COM 	ddi_put8(sc->sc_cfg_handle, (uint8_t *)(sc->sc_cfg_base + 0xf0),
437910893SQuaker.Fang@Sun.COM 	    vlink & ~2);
438010893SQuaker.Fang@Sun.COM 
438110893SQuaker.Fang@Sun.COM 	tmp = IWP_READ(sc, CSR_HW_IF_CONFIG_REG);
438210893SQuaker.Fang@Sun.COM 	tmp |= CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI |
438310893SQuaker.Fang@Sun.COM 	    CSR_HW_IF_CONFIG_REG_BIT_MAC_SI;
438410893SQuaker.Fang@Sun.COM 	IWP_WRITE(sc, CSR_HW_IF_CONFIG_REG, tmp);
438510893SQuaker.Fang@Sun.COM 
438610893SQuaker.Fang@Sun.COM 	/*
438710893SQuaker.Fang@Sun.COM 	 * make sure power supply on each part of the hardware
438810893SQuaker.Fang@Sun.COM 	 */
438910893SQuaker.Fang@Sun.COM 	iwp_mac_access_enter(sc);
439010893SQuaker.Fang@Sun.COM 	tmp = iwp_reg_read(sc, ALM_APMG_PS_CTL);
439110893SQuaker.Fang@Sun.COM 	tmp |= APMG_PS_CTRL_REG_VAL_ALM_R_RESET_REQ;
439210893SQuaker.Fang@Sun.COM 	iwp_reg_write(sc, ALM_APMG_PS_CTL, tmp);
439310893SQuaker.Fang@Sun.COM 	DELAY(5);
439410893SQuaker.Fang@Sun.COM 
439510893SQuaker.Fang@Sun.COM 	tmp = iwp_reg_read(sc, ALM_APMG_PS_CTL);
439610893SQuaker.Fang@Sun.COM 	tmp &= ~APMG_PS_CTRL_REG_VAL_ALM_R_RESET_REQ;
439710893SQuaker.Fang@Sun.COM 	iwp_reg_write(sc, ALM_APMG_PS_CTL, tmp);
439810893SQuaker.Fang@Sun.COM 	iwp_mac_access_exit(sc);
439910893SQuaker.Fang@Sun.COM 
440010893SQuaker.Fang@Sun.COM 	if (PA_TYPE_MIX == sc->sc_chip_param.pa_type) {
440110893SQuaker.Fang@Sun.COM 		IWP_WRITE(sc, CSR_GP_DRIVER_REG,
440210893SQuaker.Fang@Sun.COM 		    CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_MIX);
440310893SQuaker.Fang@Sun.COM 	}
440410893SQuaker.Fang@Sun.COM 
440510893SQuaker.Fang@Sun.COM 	if (PA_TYPE_INTER == sc->sc_chip_param.pa_type) {
440610893SQuaker.Fang@Sun.COM 
440710893SQuaker.Fang@Sun.COM 		IWP_WRITE(sc, CSR_GP_DRIVER_REG,
440810893SQuaker.Fang@Sun.COM 		    CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_IPA);
440910893SQuaker.Fang@Sun.COM 	}
441010893SQuaker.Fang@Sun.COM 
441110893SQuaker.Fang@Sun.COM 	return (IWP_SUCCESS);
441210893SQuaker.Fang@Sun.COM }
441310893SQuaker.Fang@Sun.COM 
441410893SQuaker.Fang@Sun.COM /*
441510893SQuaker.Fang@Sun.COM  * set up semphore flag to own EEPROM
441610893SQuaker.Fang@Sun.COM  */
441710893SQuaker.Fang@Sun.COM static int
iwp_eep_sem_down(iwp_sc_t * sc)441810893SQuaker.Fang@Sun.COM iwp_eep_sem_down(iwp_sc_t *sc)
441910893SQuaker.Fang@Sun.COM {
442010893SQuaker.Fang@Sun.COM 	int count1, count2;
442110893SQuaker.Fang@Sun.COM 	uint32_t tmp;
442210893SQuaker.Fang@Sun.COM 
442310893SQuaker.Fang@Sun.COM 	for (count1 = 0; count1 < 1000; count1++) {
442410893SQuaker.Fang@Sun.COM 		tmp = IWP_READ(sc, CSR_HW_IF_CONFIG_REG);
442510893SQuaker.Fang@Sun.COM 		IWP_WRITE(sc, CSR_HW_IF_CONFIG_REG,
442610893SQuaker.Fang@Sun.COM 		    tmp | CSR_HW_IF_CONFIG_REG_EEP_SEM);
442710893SQuaker.Fang@Sun.COM 
442810893SQuaker.Fang@Sun.COM 		for (count2 = 0; count2 < 2; count2++) {
442910893SQuaker.Fang@Sun.COM 			if (IWP_READ(sc, CSR_HW_IF_CONFIG_REG) &
443010893SQuaker.Fang@Sun.COM 			    CSR_HW_IF_CONFIG_REG_EEP_SEM) {
443110893SQuaker.Fang@Sun.COM 				return (IWP_SUCCESS);
443210893SQuaker.Fang@Sun.COM 			}
443310893SQuaker.Fang@Sun.COM 			DELAY(10000);
443410893SQuaker.Fang@Sun.COM 		}
443510893SQuaker.Fang@Sun.COM 	}
443610893SQuaker.Fang@Sun.COM 	return (IWP_FAIL);
443710893SQuaker.Fang@Sun.COM }
443810893SQuaker.Fang@Sun.COM 
443910893SQuaker.Fang@Sun.COM /*
444010893SQuaker.Fang@Sun.COM  * reset semphore flag to release EEPROM
444110893SQuaker.Fang@Sun.COM  */
444210893SQuaker.Fang@Sun.COM static void
iwp_eep_sem_up(iwp_sc_t * sc)444310893SQuaker.Fang@Sun.COM iwp_eep_sem_up(iwp_sc_t *sc)
444410893SQuaker.Fang@Sun.COM {
444510893SQuaker.Fang@Sun.COM 	uint32_t tmp;
444610893SQuaker.Fang@Sun.COM 
444710893SQuaker.Fang@Sun.COM 	tmp = IWP_READ(sc, CSR_HW_IF_CONFIG_REG);
444810893SQuaker.Fang@Sun.COM 	IWP_WRITE(sc, CSR_HW_IF_CONFIG_REG,
444910893SQuaker.Fang@Sun.COM 	    tmp & (~CSR_HW_IF_CONFIG_REG_EEP_SEM));
445010893SQuaker.Fang@Sun.COM }
445110893SQuaker.Fang@Sun.COM 
445210893SQuaker.Fang@Sun.COM /*
445310893SQuaker.Fang@Sun.COM  * This function read all infomation from eeprom
445410893SQuaker.Fang@Sun.COM  */
445510893SQuaker.Fang@Sun.COM static int
iwp_eep_load(iwp_sc_t * sc)445610893SQuaker.Fang@Sun.COM iwp_eep_load(iwp_sc_t *sc)
445710893SQuaker.Fang@Sun.COM {
445810893SQuaker.Fang@Sun.COM 	int i, rr;
445910893SQuaker.Fang@Sun.COM 	uint32_t rv, tmp, eep_gp;
446010893SQuaker.Fang@Sun.COM 	uint16_t addr, eep_sz = sizeof (sc->sc_eep_map);
446110893SQuaker.Fang@Sun.COM 	uint16_t *eep_p = (uint16_t *)&sc->sc_eep_map;
446210893SQuaker.Fang@Sun.COM 
446310893SQuaker.Fang@Sun.COM 	/*
446410893SQuaker.Fang@Sun.COM 	 * read eeprom gp register in CSR
446510893SQuaker.Fang@Sun.COM 	 */
446610893SQuaker.Fang@Sun.COM 	eep_gp = IWP_READ(sc, CSR_EEPROM_GP);
446710893SQuaker.Fang@Sun.COM 	if ((eep_gp & CSR_EEPROM_GP_VALID_MSK) ==
446810893SQuaker.Fang@Sun.COM 	    CSR_EEPROM_GP_BAD_SIGNATURE) {
446910893SQuaker.Fang@Sun.COM 		IWP_DBG((IWP_DEBUG_EEPROM, "iwp_eep_load(): "
447010893SQuaker.Fang@Sun.COM 		    "not find eeprom\n"));
447110893SQuaker.Fang@Sun.COM 		return (IWP_FAIL);
447210893SQuaker.Fang@Sun.COM 	}
447310893SQuaker.Fang@Sun.COM 
447410893SQuaker.Fang@Sun.COM 	rr = iwp_eep_sem_down(sc);
447510893SQuaker.Fang@Sun.COM 	if (rr != 0) {
447610893SQuaker.Fang@Sun.COM 		IWP_DBG((IWP_DEBUG_EEPROM, "iwp_eep_load(): "
447710893SQuaker.Fang@Sun.COM 		    "driver failed to own EEPROM\n"));
447810893SQuaker.Fang@Sun.COM 		return (IWP_FAIL);
447910893SQuaker.Fang@Sun.COM 	}
448010893SQuaker.Fang@Sun.COM 
448110893SQuaker.Fang@Sun.COM 	for (addr = 0; addr < eep_sz; addr += 2) {
448210893SQuaker.Fang@Sun.COM 		IWP_WRITE(sc, CSR_EEPROM_REG, addr<<1);
448310893SQuaker.Fang@Sun.COM 		tmp = IWP_READ(sc, CSR_EEPROM_REG);
448410893SQuaker.Fang@Sun.COM 		IWP_WRITE(sc, CSR_EEPROM_REG, tmp & ~(0x2));
448510893SQuaker.Fang@Sun.COM 
448610893SQuaker.Fang@Sun.COM 		for (i = 0; i < 10; i++) {
448710893SQuaker.Fang@Sun.COM 			rv = IWP_READ(sc, CSR_EEPROM_REG);
448810893SQuaker.Fang@Sun.COM 			if (rv & 1) {
448910893SQuaker.Fang@Sun.COM 				break;
449010893SQuaker.Fang@Sun.COM 			}
449110893SQuaker.Fang@Sun.COM 			DELAY(10);
449210893SQuaker.Fang@Sun.COM 		}
449310893SQuaker.Fang@Sun.COM 
449410893SQuaker.Fang@Sun.COM 		if (!(rv & 1)) {
449510893SQuaker.Fang@Sun.COM 			IWP_DBG((IWP_DEBUG_EEPROM, "iwp_eep_load(): "
449610893SQuaker.Fang@Sun.COM 			    "time out when read eeprome\n"));
449710893SQuaker.Fang@Sun.COM 			iwp_eep_sem_up(sc);
449810893SQuaker.Fang@Sun.COM 			return (IWP_FAIL);
449910893SQuaker.Fang@Sun.COM 		}
450010893SQuaker.Fang@Sun.COM 
450110893SQuaker.Fang@Sun.COM 		eep_p[addr/2] = LE_16(rv >> 16);
450210893SQuaker.Fang@Sun.COM 	}
450310893SQuaker.Fang@Sun.COM 
450410893SQuaker.Fang@Sun.COM 	iwp_eep_sem_up(sc);
450510893SQuaker.Fang@Sun.COM 	return (IWP_SUCCESS);
450610893SQuaker.Fang@Sun.COM }
450710893SQuaker.Fang@Sun.COM 
450810893SQuaker.Fang@Sun.COM /*
450910893SQuaker.Fang@Sun.COM  * initialize mac address in ieee80211com_t struct
451010893SQuaker.Fang@Sun.COM  */
451110893SQuaker.Fang@Sun.COM static void
iwp_get_mac_from_eep(iwp_sc_t * sc)451210893SQuaker.Fang@Sun.COM iwp_get_mac_from_eep(iwp_sc_t *sc)
451310893SQuaker.Fang@Sun.COM {
451410893SQuaker.Fang@Sun.COM 	ieee80211com_t *ic = &sc->sc_ic;
451510893SQuaker.Fang@Sun.COM 
451610893SQuaker.Fang@Sun.COM 	IEEE80211_ADDR_COPY(ic->ic_macaddr, &sc->sc_eep_map[EEP_MAC_ADDRESS]);
451710893SQuaker.Fang@Sun.COM 
451810893SQuaker.Fang@Sun.COM 	IWP_DBG((IWP_DEBUG_EEPROM, "iwp_get_mac_from_eep(): "
451910893SQuaker.Fang@Sun.COM 	    "mac:%2x:%2x:%2x:%2x:%2x:%2x\n",
452010893SQuaker.Fang@Sun.COM 	    ic->ic_macaddr[0], ic->ic_macaddr[1], ic->ic_macaddr[2],
452110893SQuaker.Fang@Sun.COM 	    ic->ic_macaddr[3], ic->ic_macaddr[4], ic->ic_macaddr[5]));
452210893SQuaker.Fang@Sun.COM }
452310893SQuaker.Fang@Sun.COM 
452410893SQuaker.Fang@Sun.COM /*
452510893SQuaker.Fang@Sun.COM  * main initialization function
452610893SQuaker.Fang@Sun.COM  */
452710893SQuaker.Fang@Sun.COM static int
iwp_init(iwp_sc_t * sc)452810893SQuaker.Fang@Sun.COM iwp_init(iwp_sc_t *sc)
452910893SQuaker.Fang@Sun.COM {
453010893SQuaker.Fang@Sun.COM 	int err = IWP_FAIL;
453110893SQuaker.Fang@Sun.COM 	clock_t clk;
453210893SQuaker.Fang@Sun.COM 
453310893SQuaker.Fang@Sun.COM 	/*
453410893SQuaker.Fang@Sun.COM 	 * release buffer for calibration
453510893SQuaker.Fang@Sun.COM 	 */
453610893SQuaker.Fang@Sun.COM 	iwp_release_calib_buffer(sc);
453710893SQuaker.Fang@Sun.COM 
453810893SQuaker.Fang@Sun.COM 	mutex_enter(&sc->sc_glock);
453910893SQuaker.Fang@Sun.COM 	atomic_and_32(&sc->sc_flags, ~IWP_F_FW_INIT);
454010893SQuaker.Fang@Sun.COM 
454110893SQuaker.Fang@Sun.COM 	err = iwp_init_common(sc);
454210893SQuaker.Fang@Sun.COM 	if (err != IWP_SUCCESS) {
454310893SQuaker.Fang@Sun.COM 		mutex_exit(&sc->sc_glock);
454410893SQuaker.Fang@Sun.COM 		return (IWP_FAIL);
454510893SQuaker.Fang@Sun.COM 	}
454610893SQuaker.Fang@Sun.COM 
454710893SQuaker.Fang@Sun.COM 	/*
454810893SQuaker.Fang@Sun.COM 	 * backup ucode data part for future use.
454910893SQuaker.Fang@Sun.COM 	 */
455010893SQuaker.Fang@Sun.COM 	(void) memcpy(sc->sc_dma_fw_data_bak.mem_va,
455110893SQuaker.Fang@Sun.COM 	    sc->sc_dma_fw_data.mem_va,
455210893SQuaker.Fang@Sun.COM 	    sc->sc_dma_fw_data.alength);
455310893SQuaker.Fang@Sun.COM 
455410893SQuaker.Fang@Sun.COM 	/* load firmware init segment into NIC */
455510893SQuaker.Fang@Sun.COM 	err = iwp_load_init_firmware(sc);
455610893SQuaker.Fang@Sun.COM 	if (err != IWP_SUCCESS) {
455710893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_init(): "
455810893SQuaker.Fang@Sun.COM 		    "failed to setup init firmware\n");
455910893SQuaker.Fang@Sun.COM 		mutex_exit(&sc->sc_glock);
456010893SQuaker.Fang@Sun.COM 		return (IWP_FAIL);
456110893SQuaker.Fang@Sun.COM 	}
456210893SQuaker.Fang@Sun.COM 
456310893SQuaker.Fang@Sun.COM 	/*
456410893SQuaker.Fang@Sun.COM 	 * now press "execute" start running
456510893SQuaker.Fang@Sun.COM 	 */
456610893SQuaker.Fang@Sun.COM 	IWP_WRITE(sc, CSR_RESET, 0);
456710893SQuaker.Fang@Sun.COM 
456810893SQuaker.Fang@Sun.COM 	clk = ddi_get_lbolt() + drv_usectohz(1000000);
456910893SQuaker.Fang@Sun.COM 	while (!(sc->sc_flags & IWP_F_FW_INIT)) {
457010893SQuaker.Fang@Sun.COM 		if (cv_timedwait(&sc->sc_ucode_cv,
457110893SQuaker.Fang@Sun.COM 		    &sc->sc_glock, clk) < 0) {
457210893SQuaker.Fang@Sun.COM 			break;
457310893SQuaker.Fang@Sun.COM 		}
457410893SQuaker.Fang@Sun.COM 	}
457510893SQuaker.Fang@Sun.COM 
457610893SQuaker.Fang@Sun.COM 	if (!(sc->sc_flags & IWP_F_FW_INIT)) {
457710893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_init(): "
457810893SQuaker.Fang@Sun.COM 		    "failed to process init alive.\n");
457910893SQuaker.Fang@Sun.COM 		mutex_exit(&sc->sc_glock);
458010893SQuaker.Fang@Sun.COM 		return (IWP_FAIL);
458110893SQuaker.Fang@Sun.COM 	}
458210893SQuaker.Fang@Sun.COM 
458310893SQuaker.Fang@Sun.COM 	mutex_exit(&sc->sc_glock);
458410893SQuaker.Fang@Sun.COM 
458510893SQuaker.Fang@Sun.COM 	/*
458610893SQuaker.Fang@Sun.COM 	 * stop chipset for initializing chipset again
458710893SQuaker.Fang@Sun.COM 	 */
458810893SQuaker.Fang@Sun.COM 	iwp_stop(sc);
458910893SQuaker.Fang@Sun.COM 
459010893SQuaker.Fang@Sun.COM 	mutex_enter(&sc->sc_glock);
459110893SQuaker.Fang@Sun.COM 	atomic_and_32(&sc->sc_flags, ~IWP_F_FW_INIT);
459210893SQuaker.Fang@Sun.COM 
459310893SQuaker.Fang@Sun.COM 	err = iwp_init_common(sc);
459410893SQuaker.Fang@Sun.COM 	if (err != IWP_SUCCESS) {
459510893SQuaker.Fang@Sun.COM 		mutex_exit(&sc->sc_glock);
459610893SQuaker.Fang@Sun.COM 		return (IWP_FAIL);
459710893SQuaker.Fang@Sun.COM 	}
459810893SQuaker.Fang@Sun.COM 
459910893SQuaker.Fang@Sun.COM 	/*
460010893SQuaker.Fang@Sun.COM 	 * load firmware run segment into NIC
460110893SQuaker.Fang@Sun.COM 	 */
460210893SQuaker.Fang@Sun.COM 	err = iwp_load_run_firmware(sc);
460310893SQuaker.Fang@Sun.COM 	if (err != IWP_SUCCESS) {
460410893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_init(): "
460510893SQuaker.Fang@Sun.COM 		    "failed to setup run firmware\n");
460610893SQuaker.Fang@Sun.COM 		mutex_exit(&sc->sc_glock);
460710893SQuaker.Fang@Sun.COM 		return (IWP_FAIL);
460810893SQuaker.Fang@Sun.COM 	}
460910893SQuaker.Fang@Sun.COM 
461010893SQuaker.Fang@Sun.COM 	/*
461110893SQuaker.Fang@Sun.COM 	 * now press "execute" start running
461210893SQuaker.Fang@Sun.COM 	 */
461310893SQuaker.Fang@Sun.COM 	IWP_WRITE(sc, CSR_RESET, 0);
461410893SQuaker.Fang@Sun.COM 
461510893SQuaker.Fang@Sun.COM 	clk = ddi_get_lbolt() + drv_usectohz(1000000);
461610893SQuaker.Fang@Sun.COM 	while (!(sc->sc_flags & IWP_F_FW_INIT)) {
461710893SQuaker.Fang@Sun.COM 		if (cv_timedwait(&sc->sc_ucode_cv,
461810893SQuaker.Fang@Sun.COM 		    &sc->sc_glock, clk) < 0) {
461910893SQuaker.Fang@Sun.COM 			break;
462010893SQuaker.Fang@Sun.COM 		}
462110893SQuaker.Fang@Sun.COM 	}
462210893SQuaker.Fang@Sun.COM 
462310893SQuaker.Fang@Sun.COM 	if (!(sc->sc_flags & IWP_F_FW_INIT)) {
462410893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_init(): "
462510893SQuaker.Fang@Sun.COM 		    "failed to process runtime alive.\n");
462610893SQuaker.Fang@Sun.COM 		mutex_exit(&sc->sc_glock);
462710893SQuaker.Fang@Sun.COM 		return (IWP_FAIL);
462810893SQuaker.Fang@Sun.COM 	}
462910893SQuaker.Fang@Sun.COM 
463010893SQuaker.Fang@Sun.COM 	mutex_exit(&sc->sc_glock);
463110893SQuaker.Fang@Sun.COM 
463210893SQuaker.Fang@Sun.COM 	DELAY(1000);
463310893SQuaker.Fang@Sun.COM 
463410893SQuaker.Fang@Sun.COM 	mutex_enter(&sc->sc_glock);
463510893SQuaker.Fang@Sun.COM 	atomic_and_32(&sc->sc_flags, ~IWP_F_FW_INIT);
463610893SQuaker.Fang@Sun.COM 
463710893SQuaker.Fang@Sun.COM 	/*
463810893SQuaker.Fang@Sun.COM 	 * at this point, the firmware is loaded OK, then config the hardware
463910893SQuaker.Fang@Sun.COM 	 * with the ucode API, including rxon, txpower, etc.
464010893SQuaker.Fang@Sun.COM 	 */
464110893SQuaker.Fang@Sun.COM 	err = iwp_config(sc);
464210893SQuaker.Fang@Sun.COM 	if (err) {
464310893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_init(): "
464410893SQuaker.Fang@Sun.COM 		    "failed to configure device\n");
464510893SQuaker.Fang@Sun.COM 		mutex_exit(&sc->sc_glock);
464610893SQuaker.Fang@Sun.COM 		return (IWP_FAIL);
464710893SQuaker.Fang@Sun.COM 	}
464810893SQuaker.Fang@Sun.COM 
464910893SQuaker.Fang@Sun.COM 	/*
465010893SQuaker.Fang@Sun.COM 	 * at this point, hardware may receive beacons :)
465110893SQuaker.Fang@Sun.COM 	 */
465210893SQuaker.Fang@Sun.COM 	mutex_exit(&sc->sc_glock);
465310893SQuaker.Fang@Sun.COM 	return (IWP_SUCCESS);
465410893SQuaker.Fang@Sun.COM }
465510893SQuaker.Fang@Sun.COM 
465610893SQuaker.Fang@Sun.COM /*
465710893SQuaker.Fang@Sun.COM  * stop or disable NIC
465810893SQuaker.Fang@Sun.COM  */
465910893SQuaker.Fang@Sun.COM static void
iwp_stop(iwp_sc_t * sc)466010893SQuaker.Fang@Sun.COM iwp_stop(iwp_sc_t *sc)
466110893SQuaker.Fang@Sun.COM {
466210893SQuaker.Fang@Sun.COM 	uint32_t tmp;
466310893SQuaker.Fang@Sun.COM 	int i;
466410893SQuaker.Fang@Sun.COM 
466510893SQuaker.Fang@Sun.COM 	/* by pass if it's quiesced */
466610893SQuaker.Fang@Sun.COM 	if (!(sc->sc_flags & IWP_F_QUIESCED)) {
466710893SQuaker.Fang@Sun.COM 		mutex_enter(&sc->sc_glock);
466810893SQuaker.Fang@Sun.COM 	}
466910893SQuaker.Fang@Sun.COM 
467010893SQuaker.Fang@Sun.COM 	IWP_WRITE(sc, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
467110893SQuaker.Fang@Sun.COM 	/*
467210893SQuaker.Fang@Sun.COM 	 * disable interrupts
467310893SQuaker.Fang@Sun.COM 	 */
467410893SQuaker.Fang@Sun.COM 	IWP_WRITE(sc, CSR_INT_MASK, 0);
467510893SQuaker.Fang@Sun.COM 	IWP_WRITE(sc, CSR_INT, CSR_INI_SET_MASK);
467610893SQuaker.Fang@Sun.COM 	IWP_WRITE(sc, CSR_FH_INT_STATUS, 0xffffffff);
467710893SQuaker.Fang@Sun.COM 
467810893SQuaker.Fang@Sun.COM 	/*
467910893SQuaker.Fang@Sun.COM 	 * reset all Tx rings
468010893SQuaker.Fang@Sun.COM 	 */
468110893SQuaker.Fang@Sun.COM 	for (i = 0; i < IWP_NUM_QUEUES; i++) {
468210893SQuaker.Fang@Sun.COM 		iwp_reset_tx_ring(sc, &sc->sc_txq[i]);
468310893SQuaker.Fang@Sun.COM 	}
468410893SQuaker.Fang@Sun.COM 
468510893SQuaker.Fang@Sun.COM 	/*
468610893SQuaker.Fang@Sun.COM 	 * reset Rx ring
468710893SQuaker.Fang@Sun.COM 	 */
468810893SQuaker.Fang@Sun.COM 	iwp_reset_rx_ring(sc);
468910893SQuaker.Fang@Sun.COM 
469010893SQuaker.Fang@Sun.COM 	iwp_mac_access_enter(sc);
469110893SQuaker.Fang@Sun.COM 	iwp_reg_write(sc, ALM_APMG_CLK_DIS, APMG_CLK_REG_VAL_DMA_CLK_RQT);
469210893SQuaker.Fang@Sun.COM 	iwp_mac_access_exit(sc);
469310893SQuaker.Fang@Sun.COM 
469410893SQuaker.Fang@Sun.COM 	DELAY(5);
469510893SQuaker.Fang@Sun.COM 
469610893SQuaker.Fang@Sun.COM 	iwp_stop_master(sc);
469710893SQuaker.Fang@Sun.COM 
469810893SQuaker.Fang@Sun.COM 	mutex_enter(&sc->sc_mt_lock);
469910893SQuaker.Fang@Sun.COM 	sc->sc_tx_timer = 0;
470010893SQuaker.Fang@Sun.COM 	mutex_exit(&sc->sc_mt_lock);
470110893SQuaker.Fang@Sun.COM 
470210893SQuaker.Fang@Sun.COM 	tmp = IWP_READ(sc, CSR_RESET);
470310893SQuaker.Fang@Sun.COM 	IWP_WRITE(sc, CSR_RESET, tmp | CSR_RESET_REG_FLAG_SW_RESET);
470410893SQuaker.Fang@Sun.COM 
470510893SQuaker.Fang@Sun.COM 	/* by pass if it's quiesced */
470610893SQuaker.Fang@Sun.COM 	if (!(sc->sc_flags & IWP_F_QUIESCED)) {
470710893SQuaker.Fang@Sun.COM 		mutex_exit(&sc->sc_glock);
470810893SQuaker.Fang@Sun.COM 	}
470910893SQuaker.Fang@Sun.COM }
471010893SQuaker.Fang@Sun.COM 
471110893SQuaker.Fang@Sun.COM /*
471210893SQuaker.Fang@Sun.COM  * Naive implementation of the Adaptive Multi Rate Retry algorithm:
471310893SQuaker.Fang@Sun.COM  * "IEEE 802.11 Rate Adaptation: A Practical Approach"
471410893SQuaker.Fang@Sun.COM  * Mathieu Lacage, Hossein Manshaei, Thierry Turletti
471510893SQuaker.Fang@Sun.COM  * INRIA Sophia - Projet Planete
471610893SQuaker.Fang@Sun.COM  * http://www-sop.inria.fr/rapports/sophia/RR-5208.html
471710893SQuaker.Fang@Sun.COM  */
471810893SQuaker.Fang@Sun.COM #define	is_success(amrr)	\
471910893SQuaker.Fang@Sun.COM 	((amrr)->retrycnt < (amrr)->txcnt / 10)
472010893SQuaker.Fang@Sun.COM #define	is_failure(amrr)	\
472110893SQuaker.Fang@Sun.COM 	((amrr)->retrycnt > (amrr)->txcnt / 3)
472210893SQuaker.Fang@Sun.COM #define	is_enough(amrr)		\
472310893SQuaker.Fang@Sun.COM 	((amrr)->txcnt > 200)
472410893SQuaker.Fang@Sun.COM #define	not_very_few(amrr)	\
472510893SQuaker.Fang@Sun.COM 	((amrr)->txcnt > 40)
472610893SQuaker.Fang@Sun.COM #define	is_min_rate(in)		\
472710893SQuaker.Fang@Sun.COM 	(0 == (in)->in_txrate)
472810893SQuaker.Fang@Sun.COM #define	is_max_rate(in)		\
472910893SQuaker.Fang@Sun.COM 	((in)->in_rates.ir_nrates - 1 == (in)->in_txrate)
473010893SQuaker.Fang@Sun.COM #define	increase_rate(in)	\
473110893SQuaker.Fang@Sun.COM 	((in)->in_txrate++)
473210893SQuaker.Fang@Sun.COM #define	decrease_rate(in)	\
473310893SQuaker.Fang@Sun.COM 	((in)->in_txrate--)
473410893SQuaker.Fang@Sun.COM #define	reset_cnt(amrr)		\
473510893SQuaker.Fang@Sun.COM 	{ (amrr)->txcnt = (amrr)->retrycnt = 0; }
473610893SQuaker.Fang@Sun.COM 
473710893SQuaker.Fang@Sun.COM #define	IWP_AMRR_MIN_SUCCESS_THRESHOLD	 1
473810893SQuaker.Fang@Sun.COM #define	IWP_AMRR_MAX_SUCCESS_THRESHOLD	15
473910893SQuaker.Fang@Sun.COM 
474010893SQuaker.Fang@Sun.COM static void
iwp_amrr_init(iwp_amrr_t * amrr)474110893SQuaker.Fang@Sun.COM iwp_amrr_init(iwp_amrr_t *amrr)
474210893SQuaker.Fang@Sun.COM {
474310893SQuaker.Fang@Sun.COM 	amrr->success = 0;
474410893SQuaker.Fang@Sun.COM 	amrr->recovery = 0;
474510893SQuaker.Fang@Sun.COM 	amrr->txcnt = amrr->retrycnt = 0;
474610893SQuaker.Fang@Sun.COM 	amrr->success_threshold = IWP_AMRR_MIN_SUCCESS_THRESHOLD;
474710893SQuaker.Fang@Sun.COM }
474810893SQuaker.Fang@Sun.COM 
474910893SQuaker.Fang@Sun.COM static void
iwp_amrr_timeout(iwp_sc_t * sc)475010893SQuaker.Fang@Sun.COM iwp_amrr_timeout(iwp_sc_t *sc)
475110893SQuaker.Fang@Sun.COM {
475210893SQuaker.Fang@Sun.COM 	ieee80211com_t *ic = &sc->sc_ic;
475310893SQuaker.Fang@Sun.COM 
475410893SQuaker.Fang@Sun.COM 	IWP_DBG((IWP_DEBUG_RATECTL, "iwp_amrr_timeout(): "
475510893SQuaker.Fang@Sun.COM 	    "enter\n"));
475610893SQuaker.Fang@Sun.COM 
475710893SQuaker.Fang@Sun.COM 	if (IEEE80211_M_STA == ic->ic_opmode) {
475810893SQuaker.Fang@Sun.COM 		iwp_amrr_ratectl(NULL, ic->ic_bss);
475910893SQuaker.Fang@Sun.COM 	} else {
476010893SQuaker.Fang@Sun.COM 		ieee80211_iterate_nodes(&ic->ic_sta, iwp_amrr_ratectl, NULL);
476110893SQuaker.Fang@Sun.COM 	}
476210893SQuaker.Fang@Sun.COM 
476310893SQuaker.Fang@Sun.COM 	sc->sc_clk = ddi_get_lbolt();
476410893SQuaker.Fang@Sun.COM }
476510893SQuaker.Fang@Sun.COM 
476610893SQuaker.Fang@Sun.COM /* ARGSUSED */
476710893SQuaker.Fang@Sun.COM static void
iwp_amrr_ratectl(void * arg,ieee80211_node_t * in)476810893SQuaker.Fang@Sun.COM iwp_amrr_ratectl(void *arg, ieee80211_node_t *in)
476910893SQuaker.Fang@Sun.COM {
477010893SQuaker.Fang@Sun.COM 	iwp_amrr_t *amrr = (iwp_amrr_t *)in;
477110893SQuaker.Fang@Sun.COM 	int need_change = 0;
477210893SQuaker.Fang@Sun.COM 
477310893SQuaker.Fang@Sun.COM 	if (is_success(amrr) && is_enough(amrr)) {
477410893SQuaker.Fang@Sun.COM 		amrr->success++;
477510893SQuaker.Fang@Sun.COM 		if (amrr->success >= amrr->success_threshold &&
477610893SQuaker.Fang@Sun.COM 		    !is_max_rate(in)) {
477710893SQuaker.Fang@Sun.COM 			amrr->recovery = 1;
477810893SQuaker.Fang@Sun.COM 			amrr->success = 0;
477910893SQuaker.Fang@Sun.COM 			increase_rate(in);
478010893SQuaker.Fang@Sun.COM 			IWP_DBG((IWP_DEBUG_RATECTL, "iwp_amrr_ratectl(): "
478110893SQuaker.Fang@Sun.COM 			    "AMRR increasing rate %d "
478210893SQuaker.Fang@Sun.COM 			    "(txcnt=%d retrycnt=%d)\n",
478310893SQuaker.Fang@Sun.COM 			    in->in_txrate, amrr->txcnt,
478410893SQuaker.Fang@Sun.COM 			    amrr->retrycnt));
478510893SQuaker.Fang@Sun.COM 			need_change = 1;
478610893SQuaker.Fang@Sun.COM 		} else {
478710893SQuaker.Fang@Sun.COM 			amrr->recovery = 0;
478810893SQuaker.Fang@Sun.COM 		}
478910893SQuaker.Fang@Sun.COM 	} else if (not_very_few(amrr) && is_failure(amrr)) {
479010893SQuaker.Fang@Sun.COM 		amrr->success = 0;
479110893SQuaker.Fang@Sun.COM 		if (!is_min_rate(in)) {
479210893SQuaker.Fang@Sun.COM 			if (amrr->recovery) {
479310893SQuaker.Fang@Sun.COM 				amrr->success_threshold++;
479410893SQuaker.Fang@Sun.COM 				if (amrr->success_threshold >
479510893SQuaker.Fang@Sun.COM 				    IWP_AMRR_MAX_SUCCESS_THRESHOLD) {
479610893SQuaker.Fang@Sun.COM 					amrr->success_threshold =
479710893SQuaker.Fang@Sun.COM 					    IWP_AMRR_MAX_SUCCESS_THRESHOLD;
479810893SQuaker.Fang@Sun.COM 				}
479910893SQuaker.Fang@Sun.COM 			} else {
480010893SQuaker.Fang@Sun.COM 				amrr->success_threshold =
480110893SQuaker.Fang@Sun.COM 				    IWP_AMRR_MIN_SUCCESS_THRESHOLD;
480210893SQuaker.Fang@Sun.COM 			}
480310893SQuaker.Fang@Sun.COM 			decrease_rate(in);
480410893SQuaker.Fang@Sun.COM 			IWP_DBG((IWP_DEBUG_RATECTL, "iwp_amrr_ratectl(): "
480510893SQuaker.Fang@Sun.COM 			    "AMRR decreasing rate %d "
480610893SQuaker.Fang@Sun.COM 			    "(txcnt=%d retrycnt=%d)\n",
480710893SQuaker.Fang@Sun.COM 			    in->in_txrate, amrr->txcnt,
480810893SQuaker.Fang@Sun.COM 			    amrr->retrycnt));
480910893SQuaker.Fang@Sun.COM 			need_change = 1;
481010893SQuaker.Fang@Sun.COM 		}
481110893SQuaker.Fang@Sun.COM 		amrr->recovery = 0;	/* paper is incorrect */
481210893SQuaker.Fang@Sun.COM 	}
481310893SQuaker.Fang@Sun.COM 
481410893SQuaker.Fang@Sun.COM 	if (is_enough(amrr) || need_change) {
481510893SQuaker.Fang@Sun.COM 		reset_cnt(amrr);
481610893SQuaker.Fang@Sun.COM 	}
481710893SQuaker.Fang@Sun.COM }
481810893SQuaker.Fang@Sun.COM 
481910893SQuaker.Fang@Sun.COM /*
482010893SQuaker.Fang@Sun.COM  * translate indirect address in eeprom to direct address
482110893SQuaker.Fang@Sun.COM  * in eeprom and return address of entry whos indirect address
482210893SQuaker.Fang@Sun.COM  * is indi_addr
482310893SQuaker.Fang@Sun.COM  */
482410893SQuaker.Fang@Sun.COM static uint8_t *
iwp_eep_addr_trans(iwp_sc_t * sc,uint32_t indi_addr)482510893SQuaker.Fang@Sun.COM iwp_eep_addr_trans(iwp_sc_t *sc, uint32_t indi_addr)
482610893SQuaker.Fang@Sun.COM {
482710893SQuaker.Fang@Sun.COM 	uint32_t	di_addr;
482810893SQuaker.Fang@Sun.COM 	uint16_t	temp;
482910893SQuaker.Fang@Sun.COM 
483010893SQuaker.Fang@Sun.COM 	if (!(indi_addr & INDIRECT_ADDRESS)) {
483110893SQuaker.Fang@Sun.COM 		di_addr = indi_addr;
483210893SQuaker.Fang@Sun.COM 		return (&sc->sc_eep_map[di_addr]);
483310893SQuaker.Fang@Sun.COM 	}
483410893SQuaker.Fang@Sun.COM 
483510893SQuaker.Fang@Sun.COM 	switch (indi_addr & INDIRECT_TYPE_MSK) {
483610893SQuaker.Fang@Sun.COM 	case INDIRECT_GENERAL:
483710893SQuaker.Fang@Sun.COM 		temp = IWP_READ_EEP_SHORT(sc, EEP_LINK_GENERAL);
483810893SQuaker.Fang@Sun.COM 		break;
483910893SQuaker.Fang@Sun.COM 	case	INDIRECT_HOST:
484010893SQuaker.Fang@Sun.COM 		temp = IWP_READ_EEP_SHORT(sc, EEP_LINK_HOST);
484110893SQuaker.Fang@Sun.COM 		break;
484210893SQuaker.Fang@Sun.COM 	case	INDIRECT_REGULATORY:
484310893SQuaker.Fang@Sun.COM 		temp = IWP_READ_EEP_SHORT(sc, EEP_LINK_REGULATORY);
484410893SQuaker.Fang@Sun.COM 		break;
484510893SQuaker.Fang@Sun.COM 	case	INDIRECT_CALIBRATION:
484610893SQuaker.Fang@Sun.COM 		temp = IWP_READ_EEP_SHORT(sc, EEP_LINK_CALIBRATION);
484710893SQuaker.Fang@Sun.COM 		break;
484810893SQuaker.Fang@Sun.COM 	case	INDIRECT_PROCESS_ADJST:
484910893SQuaker.Fang@Sun.COM 		temp = IWP_READ_EEP_SHORT(sc, EEP_LINK_PROCESS_ADJST);
485010893SQuaker.Fang@Sun.COM 		break;
485110893SQuaker.Fang@Sun.COM 	case	INDIRECT_OTHERS:
485210893SQuaker.Fang@Sun.COM 		temp = IWP_READ_EEP_SHORT(sc, EEP_LINK_OTHERS);
485310893SQuaker.Fang@Sun.COM 		break;
485410893SQuaker.Fang@Sun.COM 	default:
485510893SQuaker.Fang@Sun.COM 		temp = 0;
485610893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_eep_addr_trans(): "
485710893SQuaker.Fang@Sun.COM 		    "incorrect indirect eeprom address.\n");
485810893SQuaker.Fang@Sun.COM 		break;
485910893SQuaker.Fang@Sun.COM 	}
486010893SQuaker.Fang@Sun.COM 
486110893SQuaker.Fang@Sun.COM 	di_addr = (indi_addr & ADDRESS_MSK) + (temp << 1);
486210893SQuaker.Fang@Sun.COM 
486310893SQuaker.Fang@Sun.COM 	return (&sc->sc_eep_map[di_addr]);
486410893SQuaker.Fang@Sun.COM }
486510893SQuaker.Fang@Sun.COM 
486610893SQuaker.Fang@Sun.COM /*
486710893SQuaker.Fang@Sun.COM  * loade a section of ucode into NIC
486810893SQuaker.Fang@Sun.COM  */
486910893SQuaker.Fang@Sun.COM static int
iwp_put_seg_fw(iwp_sc_t * sc,uint32_t addr_s,uint32_t addr_d,uint32_t len)487010893SQuaker.Fang@Sun.COM iwp_put_seg_fw(iwp_sc_t *sc, uint32_t addr_s, uint32_t addr_d, uint32_t len)
487110893SQuaker.Fang@Sun.COM {
487210893SQuaker.Fang@Sun.COM 
487310893SQuaker.Fang@Sun.COM 	iwp_mac_access_enter(sc);
487410893SQuaker.Fang@Sun.COM 
487510893SQuaker.Fang@Sun.COM 	IWP_WRITE(sc, IWP_FH_TCSR_CHNL_TX_CONFIG_REG(IWP_FH_SRVC_CHNL),
487610893SQuaker.Fang@Sun.COM 	    IWP_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE);
487710893SQuaker.Fang@Sun.COM 
487810893SQuaker.Fang@Sun.COM 	IWP_WRITE(sc, IWP_FH_SRVC_CHNL_SRAM_ADDR_REG(IWP_FH_SRVC_CHNL), addr_d);
487910893SQuaker.Fang@Sun.COM 
488010893SQuaker.Fang@Sun.COM 	IWP_WRITE(sc, IWP_FH_TFDIB_CTRL0_REG(IWP_FH_SRVC_CHNL),
488110893SQuaker.Fang@Sun.COM 	    (addr_s & FH_MEM_TFDIB_DRAM_ADDR_LSB_MASK));
488210893SQuaker.Fang@Sun.COM 
488310893SQuaker.Fang@Sun.COM 	IWP_WRITE(sc, IWP_FH_TFDIB_CTRL1_REG(IWP_FH_SRVC_CHNL), len);
488410893SQuaker.Fang@Sun.COM 
488510893SQuaker.Fang@Sun.COM 	IWP_WRITE(sc, IWP_FH_TCSR_CHNL_TX_BUF_STS_REG(IWP_FH_SRVC_CHNL),
488610893SQuaker.Fang@Sun.COM 	    (1 << IWP_FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM) |
488710893SQuaker.Fang@Sun.COM 	    (1 << IWP_FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX) |
488810893SQuaker.Fang@Sun.COM 	    IWP_FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID);
488910893SQuaker.Fang@Sun.COM 
489010893SQuaker.Fang@Sun.COM 	IWP_WRITE(sc, IWP_FH_TCSR_CHNL_TX_CONFIG_REG(IWP_FH_SRVC_CHNL),
489110893SQuaker.Fang@Sun.COM 	    IWP_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
489210893SQuaker.Fang@Sun.COM 	    IWP_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE_VAL |
489310893SQuaker.Fang@Sun.COM 	    IWP_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD);
489410893SQuaker.Fang@Sun.COM 
489510893SQuaker.Fang@Sun.COM 	iwp_mac_access_exit(sc);
489610893SQuaker.Fang@Sun.COM 
489710893SQuaker.Fang@Sun.COM 	return (IWP_SUCCESS);
489810893SQuaker.Fang@Sun.COM }
489910893SQuaker.Fang@Sun.COM 
490010893SQuaker.Fang@Sun.COM /*
490110893SQuaker.Fang@Sun.COM  * necessary setting during alive notification
490210893SQuaker.Fang@Sun.COM  */
490310893SQuaker.Fang@Sun.COM static int
iwp_alive_common(iwp_sc_t * sc)490410893SQuaker.Fang@Sun.COM iwp_alive_common(iwp_sc_t *sc)
490510893SQuaker.Fang@Sun.COM {
490610893SQuaker.Fang@Sun.COM 	uint32_t	base;
490710893SQuaker.Fang@Sun.COM 	uint32_t	i;
490810893SQuaker.Fang@Sun.COM 	iwp_wimax_coex_cmd_t	w_cmd;
490910893SQuaker.Fang@Sun.COM 	iwp_calibration_crystal_cmd_t	c_cmd;
491010893SQuaker.Fang@Sun.COM 	uint32_t	rv = IWP_FAIL;
491110893SQuaker.Fang@Sun.COM 
491210893SQuaker.Fang@Sun.COM 	/*
491310893SQuaker.Fang@Sun.COM 	 * initialize SCD related registers to make TX work.
491410893SQuaker.Fang@Sun.COM 	 */
491510893SQuaker.Fang@Sun.COM 	iwp_mac_access_enter(sc);
491610893SQuaker.Fang@Sun.COM 
491710893SQuaker.Fang@Sun.COM 	/*
491810893SQuaker.Fang@Sun.COM 	 * read sram address of data base.
491910893SQuaker.Fang@Sun.COM 	 */
492010893SQuaker.Fang@Sun.COM 	sc->sc_scd_base = iwp_reg_read(sc, IWP_SCD_SRAM_BASE_ADDR);
492110893SQuaker.Fang@Sun.COM 
492210893SQuaker.Fang@Sun.COM 	for (base = sc->sc_scd_base + IWP_SCD_CONTEXT_DATA_OFFSET;
492310893SQuaker.Fang@Sun.COM 	    base < sc->sc_scd_base + IWP_SCD_TX_STTS_BITMAP_OFFSET;
492410893SQuaker.Fang@Sun.COM 	    base += 4) {
492510893SQuaker.Fang@Sun.COM 		iwp_mem_write(sc, base, 0);
492610893SQuaker.Fang@Sun.COM 	}
492710893SQuaker.Fang@Sun.COM 
492810893SQuaker.Fang@Sun.COM 	for (; base < sc->sc_scd_base + IWP_SCD_TRANSLATE_TBL_OFFSET;
492910893SQuaker.Fang@Sun.COM 	    base += 4) {
493010893SQuaker.Fang@Sun.COM 		iwp_mem_write(sc, base, 0);
493110893SQuaker.Fang@Sun.COM 	}
493210893SQuaker.Fang@Sun.COM 
493310893SQuaker.Fang@Sun.COM 	for (i = 0; i < sizeof (uint16_t) * IWP_NUM_QUEUES; i += 4) {
493410893SQuaker.Fang@Sun.COM 		iwp_mem_write(sc, base + i, 0);
493510893SQuaker.Fang@Sun.COM 	}
493610893SQuaker.Fang@Sun.COM 
493710893SQuaker.Fang@Sun.COM 	iwp_reg_write(sc, IWP_SCD_DRAM_BASE_ADDR,
493810893SQuaker.Fang@Sun.COM 	    sc->sc_dma_sh.cookie.dmac_address >> 10);
493910893SQuaker.Fang@Sun.COM 
494010893SQuaker.Fang@Sun.COM 	iwp_reg_write(sc, IWP_SCD_QUEUECHAIN_SEL,
494110893SQuaker.Fang@Sun.COM 	    IWP_SCD_QUEUECHAIN_SEL_ALL(IWP_NUM_QUEUES));
494210893SQuaker.Fang@Sun.COM 
494310893SQuaker.Fang@Sun.COM 	iwp_reg_write(sc, IWP_SCD_AGGR_SEL, 0);
494410893SQuaker.Fang@Sun.COM 
494510893SQuaker.Fang@Sun.COM 	for (i = 0; i < IWP_NUM_QUEUES; i++) {
494610893SQuaker.Fang@Sun.COM 		iwp_reg_write(sc, IWP_SCD_QUEUE_RDPTR(i), 0);
494710893SQuaker.Fang@Sun.COM 		IWP_WRITE(sc, HBUS_TARG_WRPTR, 0 | (i << 8));
494810893SQuaker.Fang@Sun.COM 		iwp_mem_write(sc, sc->sc_scd_base +
494910893SQuaker.Fang@Sun.COM 		    IWP_SCD_CONTEXT_QUEUE_OFFSET(i), 0);
495010893SQuaker.Fang@Sun.COM 		iwp_mem_write(sc, sc->sc_scd_base +
495110893SQuaker.Fang@Sun.COM 		    IWP_SCD_CONTEXT_QUEUE_OFFSET(i) +
495210893SQuaker.Fang@Sun.COM 		    sizeof (uint32_t),
495310893SQuaker.Fang@Sun.COM 		    ((SCD_WIN_SIZE << IWP_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) &
495410893SQuaker.Fang@Sun.COM 		    IWP_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
495510893SQuaker.Fang@Sun.COM 		    ((SCD_FRAME_LIMIT <<
495610893SQuaker.Fang@Sun.COM 		    IWP_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
495710893SQuaker.Fang@Sun.COM 		    IWP_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));
495810893SQuaker.Fang@Sun.COM 	}
495910893SQuaker.Fang@Sun.COM 
496010893SQuaker.Fang@Sun.COM 	iwp_reg_write(sc, IWP_SCD_INTERRUPT_MASK, (1 << IWP_NUM_QUEUES) - 1);
496110893SQuaker.Fang@Sun.COM 
496210893SQuaker.Fang@Sun.COM 	iwp_reg_write(sc, (IWP_SCD_BASE + 0x10),
496310893SQuaker.Fang@Sun.COM 	    SCD_TXFACT_REG_TXFIFO_MASK(0, 7));
496410893SQuaker.Fang@Sun.COM 
496510893SQuaker.Fang@Sun.COM 	IWP_WRITE(sc, HBUS_TARG_WRPTR, (IWP_CMD_QUEUE_NUM << 8));
496610893SQuaker.Fang@Sun.COM 	iwp_reg_write(sc, IWP_SCD_QUEUE_RDPTR(IWP_CMD_QUEUE_NUM), 0);
496710893SQuaker.Fang@Sun.COM 
496810893SQuaker.Fang@Sun.COM 	/*
496910893SQuaker.Fang@Sun.COM 	 * queue 0-7 map to FIFO 0-7 and
497010893SQuaker.Fang@Sun.COM 	 * all queues work under FIFO mode(none-scheduler_ack)
497110893SQuaker.Fang@Sun.COM 	 */
497210893SQuaker.Fang@Sun.COM 	for (i = 0; i < 4; i++) {
497310893SQuaker.Fang@Sun.COM 		iwp_reg_write(sc, IWP_SCD_QUEUE_STATUS_BITS(i),
497410893SQuaker.Fang@Sun.COM 		    (1 << IWP_SCD_QUEUE_STTS_REG_POS_ACTIVE) |
497510893SQuaker.Fang@Sun.COM 		    ((3-i) << IWP_SCD_QUEUE_STTS_REG_POS_TXF) |
497610893SQuaker.Fang@Sun.COM 		    (1 << IWP_SCD_QUEUE_STTS_REG_POS_WSL) |
497710893SQuaker.Fang@Sun.COM 		    IWP_SCD_QUEUE_STTS_REG_MSK);
497810893SQuaker.Fang@Sun.COM 	}
497910893SQuaker.Fang@Sun.COM 
498010893SQuaker.Fang@Sun.COM 	iwp_reg_write(sc, IWP_SCD_QUEUE_STATUS_BITS(IWP_CMD_QUEUE_NUM),
498110893SQuaker.Fang@Sun.COM 	    (1 << IWP_SCD_QUEUE_STTS_REG_POS_ACTIVE) |
498210893SQuaker.Fang@Sun.COM 	    (IWP_CMD_FIFO_NUM << IWP_SCD_QUEUE_STTS_REG_POS_TXF) |
498310893SQuaker.Fang@Sun.COM 	    (1 << IWP_SCD_QUEUE_STTS_REG_POS_WSL) |
498410893SQuaker.Fang@Sun.COM 	    IWP_SCD_QUEUE_STTS_REG_MSK);
498510893SQuaker.Fang@Sun.COM 
498610893SQuaker.Fang@Sun.COM 	for (i = 5; i < 7; i++) {
498710893SQuaker.Fang@Sun.COM 		iwp_reg_write(sc, IWP_SCD_QUEUE_STATUS_BITS(i),
498810893SQuaker.Fang@Sun.COM 		    (1 << IWP_SCD_QUEUE_STTS_REG_POS_ACTIVE) |
498910893SQuaker.Fang@Sun.COM 		    (i << IWP_SCD_QUEUE_STTS_REG_POS_TXF) |
499010893SQuaker.Fang@Sun.COM 		    (1 << IWP_SCD_QUEUE_STTS_REG_POS_WSL) |
499110893SQuaker.Fang@Sun.COM 		    IWP_SCD_QUEUE_STTS_REG_MSK);
499210893SQuaker.Fang@Sun.COM 	}
499310893SQuaker.Fang@Sun.COM 
499410893SQuaker.Fang@Sun.COM 	iwp_mac_access_exit(sc);
499510893SQuaker.Fang@Sun.COM 
499610893SQuaker.Fang@Sun.COM 	(void) memset(&w_cmd, 0, sizeof (w_cmd));
499710893SQuaker.Fang@Sun.COM 
499810893SQuaker.Fang@Sun.COM 	rv = iwp_cmd(sc, COEX_PRIORITY_TABLE_CMD, &w_cmd, sizeof (w_cmd), 1);
499910893SQuaker.Fang@Sun.COM 	if (rv != IWP_SUCCESS) {
500010893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_alive_common(): "
500110893SQuaker.Fang@Sun.COM 		    "failed to send wimax coexist command.\n");
500210893SQuaker.Fang@Sun.COM 		return (rv);
500310893SQuaker.Fang@Sun.COM 	}
500410893SQuaker.Fang@Sun.COM 
500510893SQuaker.Fang@Sun.COM 	(void) memset(&c_cmd, 0, sizeof (c_cmd));
500610893SQuaker.Fang@Sun.COM 
500710893SQuaker.Fang@Sun.COM 	c_cmd.opCode = PHY_CALIBRATE_CRYSTAL_FRQ_CMD;
500810893SQuaker.Fang@Sun.COM 	c_cmd.data.cap_pin1 = LE_16(sc->sc_eep_calib->xtal_calib[0]);
500910893SQuaker.Fang@Sun.COM 	c_cmd.data.cap_pin2 = LE_16(sc->sc_eep_calib->xtal_calib[1]);
501010893SQuaker.Fang@Sun.COM 
501110893SQuaker.Fang@Sun.COM 	rv = iwp_cmd(sc, REPLY_PHY_CALIBRATION_CMD, &c_cmd, sizeof (c_cmd), 1);
501210893SQuaker.Fang@Sun.COM 	if (rv != IWP_SUCCESS) {
501310893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_alive_common(): "
501410893SQuaker.Fang@Sun.COM 		    "failed to send crystal frq calibration command.\n");
501510893SQuaker.Fang@Sun.COM 		return (rv);
501610893SQuaker.Fang@Sun.COM 	}
501710893SQuaker.Fang@Sun.COM 
501810893SQuaker.Fang@Sun.COM 	/*
501910893SQuaker.Fang@Sun.COM 	 * make sure crystal frequency calibration ready
502010893SQuaker.Fang@Sun.COM 	 * before next operations.
502110893SQuaker.Fang@Sun.COM 	 */
502210893SQuaker.Fang@Sun.COM 	DELAY(1000);
502310893SQuaker.Fang@Sun.COM 
502410893SQuaker.Fang@Sun.COM 	return (IWP_SUCCESS);
502510893SQuaker.Fang@Sun.COM }
502610893SQuaker.Fang@Sun.COM 
502710893SQuaker.Fang@Sun.COM /*
502810893SQuaker.Fang@Sun.COM  * save results of calibration from ucode
502910893SQuaker.Fang@Sun.COM  */
503010893SQuaker.Fang@Sun.COM static void
iwp_save_calib_result(iwp_sc_t * sc,iwp_rx_desc_t * desc)503110893SQuaker.Fang@Sun.COM iwp_save_calib_result(iwp_sc_t *sc, iwp_rx_desc_t *desc)
503210893SQuaker.Fang@Sun.COM {
503310893SQuaker.Fang@Sun.COM 	struct iwp_calib_results *res_p = &sc->sc_calib_results;
503410893SQuaker.Fang@Sun.COM 	struct iwp_calib_hdr *calib_hdr = (struct iwp_calib_hdr *)(desc + 1);
503510893SQuaker.Fang@Sun.COM 	int len = LE_32(desc->len);
503610893SQuaker.Fang@Sun.COM 
503710893SQuaker.Fang@Sun.COM 	/*
503810893SQuaker.Fang@Sun.COM 	 * ensure the size of buffer is not too big
503910893SQuaker.Fang@Sun.COM 	 */
504010893SQuaker.Fang@Sun.COM 	len = (len & FH_RSCSR_FRAME_SIZE_MASK) - 4;
504110893SQuaker.Fang@Sun.COM 
504210893SQuaker.Fang@Sun.COM 	switch (calib_hdr->op_code) {
504310893SQuaker.Fang@Sun.COM 	case PHY_CALIBRATE_LO_CMD:
504410893SQuaker.Fang@Sun.COM 		if (NULL == res_p->lo_res) {
504510893SQuaker.Fang@Sun.COM 			res_p->lo_res = kmem_alloc(len, KM_NOSLEEP);
504610893SQuaker.Fang@Sun.COM 		}
504710893SQuaker.Fang@Sun.COM 
504810893SQuaker.Fang@Sun.COM 		if (NULL == res_p->lo_res) {
504910893SQuaker.Fang@Sun.COM 			cmn_err(CE_WARN, "iwp_save_calib_result(): "
505010893SQuaker.Fang@Sun.COM 			    "failed to allocate memory.\n");
505110893SQuaker.Fang@Sun.COM 			return;
505210893SQuaker.Fang@Sun.COM 		}
505310893SQuaker.Fang@Sun.COM 
505410893SQuaker.Fang@Sun.COM 		res_p->lo_res_len = len;
505510893SQuaker.Fang@Sun.COM 		(void) memcpy(res_p->lo_res, calib_hdr, len);
505610893SQuaker.Fang@Sun.COM 		break;
505710893SQuaker.Fang@Sun.COM 	case PHY_CALIBRATE_TX_IQ_CMD:
505810893SQuaker.Fang@Sun.COM 		if (NULL == res_p->tx_iq_res) {
505910893SQuaker.Fang@Sun.COM 			res_p->tx_iq_res = kmem_alloc(len, KM_NOSLEEP);
506010893SQuaker.Fang@Sun.COM 		}
506110893SQuaker.Fang@Sun.COM 
506210893SQuaker.Fang@Sun.COM 		if (NULL == res_p->tx_iq_res) {
506310893SQuaker.Fang@Sun.COM 			cmn_err(CE_WARN, "iwp_save_calib_result(): "
506410893SQuaker.Fang@Sun.COM 			    "failed to allocate memory.\n");
506510893SQuaker.Fang@Sun.COM 			return;
506610893SQuaker.Fang@Sun.COM 		}
506710893SQuaker.Fang@Sun.COM 
506810893SQuaker.Fang@Sun.COM 		res_p->tx_iq_res_len = len;
506910893SQuaker.Fang@Sun.COM 		(void) memcpy(res_p->tx_iq_res, calib_hdr, len);
507010893SQuaker.Fang@Sun.COM 		break;
507110893SQuaker.Fang@Sun.COM 	case PHY_CALIBRATE_TX_IQ_PERD_CMD:
507210893SQuaker.Fang@Sun.COM 		if (NULL == res_p->tx_iq_perd_res) {
507310893SQuaker.Fang@Sun.COM 			res_p->tx_iq_perd_res = kmem_alloc(len, KM_NOSLEEP);
507410893SQuaker.Fang@Sun.COM 		}
507510893SQuaker.Fang@Sun.COM 
507610893SQuaker.Fang@Sun.COM 		if (NULL == res_p->tx_iq_perd_res) {
507710893SQuaker.Fang@Sun.COM 			cmn_err(CE_WARN, "iwp_save_calib_result(): "
507810893SQuaker.Fang@Sun.COM 			    "failed to allocate memory.\n");
507910893SQuaker.Fang@Sun.COM 		}
508010893SQuaker.Fang@Sun.COM 
508110893SQuaker.Fang@Sun.COM 		res_p->tx_iq_perd_res_len = len;
508210893SQuaker.Fang@Sun.COM 		(void) memcpy(res_p->tx_iq_perd_res, calib_hdr, len);
508310893SQuaker.Fang@Sun.COM 		break;
508410893SQuaker.Fang@Sun.COM 	case PHY_CALIBRATE_BASE_BAND_CMD:
508510893SQuaker.Fang@Sun.COM 		if (NULL == res_p->base_band_res) {
508610893SQuaker.Fang@Sun.COM 			res_p->base_band_res = kmem_alloc(len, KM_NOSLEEP);
508710893SQuaker.Fang@Sun.COM 		}
508810893SQuaker.Fang@Sun.COM 
508910893SQuaker.Fang@Sun.COM 		if (NULL == res_p->base_band_res) {
509010893SQuaker.Fang@Sun.COM 			cmn_err(CE_WARN, "iwp_save_calib_result(): "
509110893SQuaker.Fang@Sun.COM 			    "failed to allocate memory.\n");
509210893SQuaker.Fang@Sun.COM 		}
509310893SQuaker.Fang@Sun.COM 
509410893SQuaker.Fang@Sun.COM 		res_p->base_band_res_len = len;
509510893SQuaker.Fang@Sun.COM 		(void) memcpy(res_p->base_band_res, calib_hdr, len);
509610893SQuaker.Fang@Sun.COM 		break;
509710893SQuaker.Fang@Sun.COM 	default:
509810893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_save_calib_result(): "
509910893SQuaker.Fang@Sun.COM 		    "incorrect calibration type(%d).\n", calib_hdr->op_code);
510010893SQuaker.Fang@Sun.COM 		break;
510110893SQuaker.Fang@Sun.COM 	}
510210893SQuaker.Fang@Sun.COM 
510310893SQuaker.Fang@Sun.COM }
510410893SQuaker.Fang@Sun.COM 
510510893SQuaker.Fang@Sun.COM static void
iwp_release_calib_buffer(iwp_sc_t * sc)510610893SQuaker.Fang@Sun.COM iwp_release_calib_buffer(iwp_sc_t *sc)
510710893SQuaker.Fang@Sun.COM {
510810893SQuaker.Fang@Sun.COM 	if (sc->sc_calib_results.lo_res != NULL) {
510910893SQuaker.Fang@Sun.COM 		kmem_free(sc->sc_calib_results.lo_res,
511010893SQuaker.Fang@Sun.COM 		    sc->sc_calib_results.lo_res_len);
511110893SQuaker.Fang@Sun.COM 		sc->sc_calib_results.lo_res = NULL;
511210893SQuaker.Fang@Sun.COM 	}
511310893SQuaker.Fang@Sun.COM 
511410893SQuaker.Fang@Sun.COM 	if (sc->sc_calib_results.tx_iq_res != NULL) {
511510893SQuaker.Fang@Sun.COM 		kmem_free(sc->sc_calib_results.tx_iq_res,
511610893SQuaker.Fang@Sun.COM 		    sc->sc_calib_results.tx_iq_res_len);
511710893SQuaker.Fang@Sun.COM 		sc->sc_calib_results.tx_iq_res = NULL;
511810893SQuaker.Fang@Sun.COM 	}
511910893SQuaker.Fang@Sun.COM 
512010893SQuaker.Fang@Sun.COM 	if (sc->sc_calib_results.tx_iq_perd_res != NULL) {
512110893SQuaker.Fang@Sun.COM 		kmem_free(sc->sc_calib_results.tx_iq_perd_res,
512210893SQuaker.Fang@Sun.COM 		    sc->sc_calib_results.tx_iq_perd_res_len);
512310893SQuaker.Fang@Sun.COM 		sc->sc_calib_results.tx_iq_perd_res = NULL;
512410893SQuaker.Fang@Sun.COM 	}
512510893SQuaker.Fang@Sun.COM 
512610893SQuaker.Fang@Sun.COM 	if (sc->sc_calib_results.base_band_res != NULL) {
512710893SQuaker.Fang@Sun.COM 		kmem_free(sc->sc_calib_results.base_band_res,
512810893SQuaker.Fang@Sun.COM 		    sc->sc_calib_results.base_band_res_len);
512910893SQuaker.Fang@Sun.COM 		sc->sc_calib_results.base_band_res = NULL;
513010893SQuaker.Fang@Sun.COM 	}
513110893SQuaker.Fang@Sun.COM 
513210893SQuaker.Fang@Sun.COM }
513310893SQuaker.Fang@Sun.COM 
513410893SQuaker.Fang@Sun.COM /*
513510893SQuaker.Fang@Sun.COM  * common section of intialization
513610893SQuaker.Fang@Sun.COM  */
513710893SQuaker.Fang@Sun.COM static int
iwp_init_common(iwp_sc_t * sc)513810893SQuaker.Fang@Sun.COM iwp_init_common(iwp_sc_t *sc)
513910893SQuaker.Fang@Sun.COM {
514010893SQuaker.Fang@Sun.COM 	int32_t	qid;
514110893SQuaker.Fang@Sun.COM 	uint32_t tmp;
514210893SQuaker.Fang@Sun.COM 
514310893SQuaker.Fang@Sun.COM 	(void) iwp_preinit(sc);
514410893SQuaker.Fang@Sun.COM 
514510893SQuaker.Fang@Sun.COM 	tmp = IWP_READ(sc, CSR_GP_CNTRL);
514610893SQuaker.Fang@Sun.COM 	if (!(tmp & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)) {
514710893SQuaker.Fang@Sun.COM 		cmn_err(CE_NOTE, "iwp_init_common(): "
514810893SQuaker.Fang@Sun.COM 		    "radio transmitter is off\n");
514910893SQuaker.Fang@Sun.COM 		return (IWP_FAIL);
515010893SQuaker.Fang@Sun.COM 	}
515110893SQuaker.Fang@Sun.COM 
515210893SQuaker.Fang@Sun.COM 	/*
515310893SQuaker.Fang@Sun.COM 	 * init Rx ring
515410893SQuaker.Fang@Sun.COM 	 */
515510893SQuaker.Fang@Sun.COM 	iwp_mac_access_enter(sc);
515610893SQuaker.Fang@Sun.COM 	IWP_WRITE(sc, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
515710893SQuaker.Fang@Sun.COM 
515810893SQuaker.Fang@Sun.COM 	IWP_WRITE(sc, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0);
515910893SQuaker.Fang@Sun.COM 	IWP_WRITE(sc, FH_RSCSR_CHNL0_RBDCB_BASE_REG,
516010893SQuaker.Fang@Sun.COM 	    sc->sc_rxq.dma_desc.cookie.dmac_address >> 8);
516110893SQuaker.Fang@Sun.COM 
516210893SQuaker.Fang@Sun.COM 	IWP_WRITE(sc, FH_RSCSR_CHNL0_STTS_WPTR_REG,
516310893SQuaker.Fang@Sun.COM 	    ((uint32_t)(sc->sc_dma_sh.cookie.dmac_address +
516410893SQuaker.Fang@Sun.COM 	    offsetof(struct iwp_shared, val0)) >> 4));
516510893SQuaker.Fang@Sun.COM 
516610893SQuaker.Fang@Sun.COM 	IWP_WRITE(sc, FH_MEM_RCSR_CHNL0_CONFIG_REG,
516710893SQuaker.Fang@Sun.COM 	    FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL |
516810893SQuaker.Fang@Sun.COM 	    FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL |
516910893SQuaker.Fang@Sun.COM 	    IWP_FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K |
517010893SQuaker.Fang@Sun.COM 	    (RX_QUEUE_SIZE_LOG <<
517110893SQuaker.Fang@Sun.COM 	    FH_RCSR_RX_CONFIG_RBDCB_SIZE_BITSHIFT));
517210893SQuaker.Fang@Sun.COM 	iwp_mac_access_exit(sc);
517310893SQuaker.Fang@Sun.COM 	IWP_WRITE(sc, FH_RSCSR_CHNL0_RBDCB_WPTR_REG,
517410893SQuaker.Fang@Sun.COM 	    (RX_QUEUE_SIZE - 1) & ~0x7);
517510893SQuaker.Fang@Sun.COM 
517610893SQuaker.Fang@Sun.COM 	/*
517710893SQuaker.Fang@Sun.COM 	 * init Tx rings
517810893SQuaker.Fang@Sun.COM 	 */
517910893SQuaker.Fang@Sun.COM 	iwp_mac_access_enter(sc);
518010893SQuaker.Fang@Sun.COM 	iwp_reg_write(sc, IWP_SCD_TXFACT, 0);
518110893SQuaker.Fang@Sun.COM 
518210893SQuaker.Fang@Sun.COM 	/*
518310893SQuaker.Fang@Sun.COM 	 * keep warm page
518410893SQuaker.Fang@Sun.COM 	 */
518510893SQuaker.Fang@Sun.COM 	IWP_WRITE(sc, IWP_FH_KW_MEM_ADDR_REG,
518610893SQuaker.Fang@Sun.COM 	    sc->sc_dma_kw.cookie.dmac_address >> 4);
518710893SQuaker.Fang@Sun.COM 
518810893SQuaker.Fang@Sun.COM 	for (qid = 0; qid < IWP_NUM_QUEUES; qid++) {
518910893SQuaker.Fang@Sun.COM 		IWP_WRITE(sc, FH_MEM_CBBC_QUEUE(qid),
519010893SQuaker.Fang@Sun.COM 		    sc->sc_txq[qid].dma_desc.cookie.dmac_address >> 8);
519110893SQuaker.Fang@Sun.COM 		IWP_WRITE(sc, IWP_FH_TCSR_CHNL_TX_CONFIG_REG(qid),
519210893SQuaker.Fang@Sun.COM 		    IWP_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
519310893SQuaker.Fang@Sun.COM 		    IWP_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL);
519410893SQuaker.Fang@Sun.COM 	}
519510893SQuaker.Fang@Sun.COM 
519610893SQuaker.Fang@Sun.COM 	iwp_mac_access_exit(sc);
519710893SQuaker.Fang@Sun.COM 
519810893SQuaker.Fang@Sun.COM 	/*
519910893SQuaker.Fang@Sun.COM 	 * clear "radio off" and "disable command" bits
520010893SQuaker.Fang@Sun.COM 	 */
520110893SQuaker.Fang@Sun.COM 	IWP_WRITE(sc, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
520210893SQuaker.Fang@Sun.COM 	IWP_WRITE(sc, CSR_UCODE_DRV_GP1_CLR,
520310893SQuaker.Fang@Sun.COM 	    CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
520410893SQuaker.Fang@Sun.COM 
520510893SQuaker.Fang@Sun.COM 	/*
520610893SQuaker.Fang@Sun.COM 	 * clear any pending interrupts
520710893SQuaker.Fang@Sun.COM 	 */
520810893SQuaker.Fang@Sun.COM 	IWP_WRITE(sc, CSR_INT, 0xffffffff);
520910893SQuaker.Fang@Sun.COM 
521010893SQuaker.Fang@Sun.COM 	/*
521110893SQuaker.Fang@Sun.COM 	 * enable interrupts
521210893SQuaker.Fang@Sun.COM 	 */
521310893SQuaker.Fang@Sun.COM 	IWP_WRITE(sc, CSR_INT_MASK, CSR_INI_SET_MASK);
521410893SQuaker.Fang@Sun.COM 
521510893SQuaker.Fang@Sun.COM 	IWP_WRITE(sc, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
521610893SQuaker.Fang@Sun.COM 	IWP_WRITE(sc, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
521710893SQuaker.Fang@Sun.COM 
521810893SQuaker.Fang@Sun.COM 	return (IWP_SUCCESS);
521910893SQuaker.Fang@Sun.COM }
522010893SQuaker.Fang@Sun.COM 
522110893SQuaker.Fang@Sun.COM static int
iwp_fast_recover(iwp_sc_t * sc)522210893SQuaker.Fang@Sun.COM iwp_fast_recover(iwp_sc_t *sc)
522310893SQuaker.Fang@Sun.COM {
522410893SQuaker.Fang@Sun.COM 	ieee80211com_t *ic = &sc->sc_ic;
522510893SQuaker.Fang@Sun.COM 	int err = IWP_FAIL;
522610893SQuaker.Fang@Sun.COM 
522710893SQuaker.Fang@Sun.COM 	mutex_enter(&sc->sc_glock);
522810893SQuaker.Fang@Sun.COM 
522910893SQuaker.Fang@Sun.COM 	/* restore runtime configuration */
523010893SQuaker.Fang@Sun.COM 	bcopy(&sc->sc_config_save, &sc->sc_config,
523110893SQuaker.Fang@Sun.COM 	    sizeof (sc->sc_config));
523210893SQuaker.Fang@Sun.COM 
523310893SQuaker.Fang@Sun.COM 	sc->sc_config.assoc_id = 0;
523410893SQuaker.Fang@Sun.COM 	sc->sc_config.filter_flags &= ~LE_32(RXON_FILTER_ASSOC_MSK);
523510893SQuaker.Fang@Sun.COM 
523610893SQuaker.Fang@Sun.COM 	if ((err = iwp_hw_set_before_auth(sc)) != IWP_SUCCESS) {
523710893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_fast_recover(): "
523810893SQuaker.Fang@Sun.COM 		    "could not setup authentication\n");
523910893SQuaker.Fang@Sun.COM 		mutex_exit(&sc->sc_glock);
524010893SQuaker.Fang@Sun.COM 		return (err);
524110893SQuaker.Fang@Sun.COM 	}
524210893SQuaker.Fang@Sun.COM 
524310893SQuaker.Fang@Sun.COM 	bcopy(&sc->sc_config_save, &sc->sc_config,
524410893SQuaker.Fang@Sun.COM 	    sizeof (sc->sc_config));
524510893SQuaker.Fang@Sun.COM 
524610893SQuaker.Fang@Sun.COM 	/* update adapter's configuration */
524710893SQuaker.Fang@Sun.COM 	err = iwp_run_state_config(sc);
524810893SQuaker.Fang@Sun.COM 	if (err != IWP_SUCCESS) {
524910893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_fast_recover(): "
525010893SQuaker.Fang@Sun.COM 		    "failed to setup association\n");
525110893SQuaker.Fang@Sun.COM 		mutex_exit(&sc->sc_glock);
525210893SQuaker.Fang@Sun.COM 		return (err);
525310893SQuaker.Fang@Sun.COM 	}
525410893SQuaker.Fang@Sun.COM 	/* set LED on */
525510893SQuaker.Fang@Sun.COM 	iwp_set_led(sc, 2, 0, 1);
525610893SQuaker.Fang@Sun.COM 
525710893SQuaker.Fang@Sun.COM 	mutex_exit(&sc->sc_glock);
525810893SQuaker.Fang@Sun.COM 
525910893SQuaker.Fang@Sun.COM 	atomic_and_32(&sc->sc_flags, ~IWP_F_HW_ERR_RECOVER);
526010893SQuaker.Fang@Sun.COM 
526110893SQuaker.Fang@Sun.COM 	/* start queue */
526210893SQuaker.Fang@Sun.COM 	IWP_DBG((IWP_DEBUG_FW, "iwp_fast_recover(): "
526310893SQuaker.Fang@Sun.COM 	    "resume xmit\n"));
526410893SQuaker.Fang@Sun.COM 	mac_tx_update(ic->ic_mach);
526510893SQuaker.Fang@Sun.COM 
526610893SQuaker.Fang@Sun.COM 	return (IWP_SUCCESS);
526710893SQuaker.Fang@Sun.COM }
526810893SQuaker.Fang@Sun.COM 
526910893SQuaker.Fang@Sun.COM static int
iwp_run_state_config(iwp_sc_t * sc)527010893SQuaker.Fang@Sun.COM iwp_run_state_config(iwp_sc_t *sc)
527110893SQuaker.Fang@Sun.COM {
527210893SQuaker.Fang@Sun.COM 	struct ieee80211com *ic = &sc->sc_ic;
527310893SQuaker.Fang@Sun.COM 	ieee80211_node_t *in = ic->ic_bss;
527410893SQuaker.Fang@Sun.COM 	int err = IWP_FAIL;
527510893SQuaker.Fang@Sun.COM 
527610893SQuaker.Fang@Sun.COM 	/*
527710893SQuaker.Fang@Sun.COM 	 * update adapter's configuration
527810893SQuaker.Fang@Sun.COM 	 */
527910893SQuaker.Fang@Sun.COM 	sc->sc_config.assoc_id = in->in_associd & 0x3fff;
528010893SQuaker.Fang@Sun.COM 
528110893SQuaker.Fang@Sun.COM 	/*
528210893SQuaker.Fang@Sun.COM 	 * short preamble/slot time are
528310893SQuaker.Fang@Sun.COM 	 * negotiated when associating
528410893SQuaker.Fang@Sun.COM 	 */
528510893SQuaker.Fang@Sun.COM 	sc->sc_config.flags &=
528610893SQuaker.Fang@Sun.COM 	    ~LE_32(RXON_FLG_SHORT_PREAMBLE_MSK |
528710893SQuaker.Fang@Sun.COM 	    RXON_FLG_SHORT_SLOT_MSK);
528810893SQuaker.Fang@Sun.COM 
528910893SQuaker.Fang@Sun.COM 	if (ic->ic_flags & IEEE80211_F_SHSLOT) {
529010893SQuaker.Fang@Sun.COM 		sc->sc_config.flags |=
529110893SQuaker.Fang@Sun.COM 		    LE_32(RXON_FLG_SHORT_SLOT_MSK);
529210893SQuaker.Fang@Sun.COM 	}
529310893SQuaker.Fang@Sun.COM 
529410893SQuaker.Fang@Sun.COM 	if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) {
529510893SQuaker.Fang@Sun.COM 		sc->sc_config.flags |=
529610893SQuaker.Fang@Sun.COM 		    LE_32(RXON_FLG_SHORT_PREAMBLE_MSK);
529710893SQuaker.Fang@Sun.COM 	}
529810893SQuaker.Fang@Sun.COM 
529910893SQuaker.Fang@Sun.COM 	sc->sc_config.filter_flags |=
530010893SQuaker.Fang@Sun.COM 	    LE_32(RXON_FILTER_ASSOC_MSK);
530110893SQuaker.Fang@Sun.COM 
530210893SQuaker.Fang@Sun.COM 	if (ic->ic_opmode != IEEE80211_M_STA) {
530310893SQuaker.Fang@Sun.COM 		sc->sc_config.filter_flags |=
530410893SQuaker.Fang@Sun.COM 		    LE_32(RXON_FILTER_BCON_AWARE_MSK);
530510893SQuaker.Fang@Sun.COM 	}
530610893SQuaker.Fang@Sun.COM 
530710893SQuaker.Fang@Sun.COM 	IWP_DBG((IWP_DEBUG_80211, "iwp_run_state_config(): "
530810893SQuaker.Fang@Sun.COM 	    "config chan %d flags %x"
530910893SQuaker.Fang@Sun.COM 	    " filter_flags %x\n",
531010893SQuaker.Fang@Sun.COM 	    sc->sc_config.chan, sc->sc_config.flags,
531110893SQuaker.Fang@Sun.COM 	    sc->sc_config.filter_flags));
531210893SQuaker.Fang@Sun.COM 
531310893SQuaker.Fang@Sun.COM 	err = iwp_cmd(sc, REPLY_RXON, &sc->sc_config,
531410893SQuaker.Fang@Sun.COM 	    sizeof (iwp_rxon_cmd_t), 1);
531510893SQuaker.Fang@Sun.COM 	if (err != IWP_SUCCESS) {
531610893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_run_state_config(): "
531710893SQuaker.Fang@Sun.COM 		    "could not update configuration\n");
531810893SQuaker.Fang@Sun.COM 		return (err);
531910893SQuaker.Fang@Sun.COM 	}
532010893SQuaker.Fang@Sun.COM 
532110893SQuaker.Fang@Sun.COM 	return (err);
532210893SQuaker.Fang@Sun.COM }
532310893SQuaker.Fang@Sun.COM 
532410893SQuaker.Fang@Sun.COM /*
532510893SQuaker.Fang@Sun.COM  * This function overwrites default configurations of
532610893SQuaker.Fang@Sun.COM  * ieee80211com structure in Net80211 module.
532710893SQuaker.Fang@Sun.COM  */
532810893SQuaker.Fang@Sun.COM static void
iwp_overwrite_ic_default(iwp_sc_t * sc)532910893SQuaker.Fang@Sun.COM iwp_overwrite_ic_default(iwp_sc_t *sc)
533010893SQuaker.Fang@Sun.COM {
533110893SQuaker.Fang@Sun.COM 	ieee80211com_t *ic = &sc->sc_ic;
533210893SQuaker.Fang@Sun.COM 
533310893SQuaker.Fang@Sun.COM 	sc->sc_newstate = ic->ic_newstate;
533410893SQuaker.Fang@Sun.COM 	ic->ic_newstate = iwp_newstate;
533510893SQuaker.Fang@Sun.COM 	ic->ic_node_alloc = iwp_node_alloc;
533610893SQuaker.Fang@Sun.COM 	ic->ic_node_free = iwp_node_free;
533710893SQuaker.Fang@Sun.COM }
533810893SQuaker.Fang@Sun.COM 
533910893SQuaker.Fang@Sun.COM 
534010893SQuaker.Fang@Sun.COM /*
534110893SQuaker.Fang@Sun.COM  * This function adds AP station into hardware.
534210893SQuaker.Fang@Sun.COM  */
534310893SQuaker.Fang@Sun.COM static int
iwp_add_ap_sta(iwp_sc_t * sc)534410893SQuaker.Fang@Sun.COM iwp_add_ap_sta(iwp_sc_t *sc)
534510893SQuaker.Fang@Sun.COM {
534610893SQuaker.Fang@Sun.COM 	ieee80211com_t *ic = &sc->sc_ic;
534710893SQuaker.Fang@Sun.COM 	ieee80211_node_t *in = ic->ic_bss;
534810893SQuaker.Fang@Sun.COM 	iwp_add_sta_t node;
534910893SQuaker.Fang@Sun.COM 	int err = IWP_FAIL;
535010893SQuaker.Fang@Sun.COM 
535110893SQuaker.Fang@Sun.COM 	/*
535210893SQuaker.Fang@Sun.COM 	 * Add AP node into hardware.
535310893SQuaker.Fang@Sun.COM 	 */
535410893SQuaker.Fang@Sun.COM 	(void) memset(&node, 0, sizeof (node));
535510893SQuaker.Fang@Sun.COM 	IEEE80211_ADDR_COPY(node.sta.addr, in->in_bssid);
535610893SQuaker.Fang@Sun.COM 	node.mode = STA_MODE_ADD_MSK;
535710893SQuaker.Fang@Sun.COM 	node.sta.sta_id = IWP_AP_ID;
535810893SQuaker.Fang@Sun.COM 
535910893SQuaker.Fang@Sun.COM 	err = iwp_cmd(sc, REPLY_ADD_STA, &node, sizeof (node), 1);
536010893SQuaker.Fang@Sun.COM 	if (err != IWP_SUCCESS) {
536110893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_add_ap_sta(): "
536210893SQuaker.Fang@Sun.COM 		    "failed to add AP node\n");
536310893SQuaker.Fang@Sun.COM 		return (err);
536410893SQuaker.Fang@Sun.COM 	}
536510893SQuaker.Fang@Sun.COM 
536610893SQuaker.Fang@Sun.COM 	return (err);
536710893SQuaker.Fang@Sun.COM }
536810893SQuaker.Fang@Sun.COM 
536910893SQuaker.Fang@Sun.COM /*
537010893SQuaker.Fang@Sun.COM  * Check EEPROM version and Calibration version.
537110893SQuaker.Fang@Sun.COM  */
537210893SQuaker.Fang@Sun.COM static int
iwp_eep_ver_chk(iwp_sc_t * sc)537310893SQuaker.Fang@Sun.COM iwp_eep_ver_chk(iwp_sc_t *sc)
537410893SQuaker.Fang@Sun.COM {
537510893SQuaker.Fang@Sun.COM 	if ((IWP_READ_EEP_SHORT(sc, EEP_VERSION) < 0x011a) ||
537610893SQuaker.Fang@Sun.COM 	    (sc->sc_eep_calib->tx_pow_calib_hdr.calib_version < 4)) {
537710893SQuaker.Fang@Sun.COM 		cmn_err(CE_WARN, "iwp_eep_ver_chk(): "
537810893SQuaker.Fang@Sun.COM 		    "unsupported eeprom detected\n");
537910893SQuaker.Fang@Sun.COM 		return (IWP_FAIL);
538010893SQuaker.Fang@Sun.COM 	}
538110893SQuaker.Fang@Sun.COM 
538210893SQuaker.Fang@Sun.COM 	return (IWP_SUCCESS);
538310893SQuaker.Fang@Sun.COM }
538410893SQuaker.Fang@Sun.COM 
538510893SQuaker.Fang@Sun.COM /*
538610893SQuaker.Fang@Sun.COM  * Determine parameters for all supported chips.
538710893SQuaker.Fang@Sun.COM  */
538810893SQuaker.Fang@Sun.COM static void
iwp_set_chip_param(iwp_sc_t * sc)538910893SQuaker.Fang@Sun.COM iwp_set_chip_param(iwp_sc_t *sc)
539010893SQuaker.Fang@Sun.COM {
539110893SQuaker.Fang@Sun.COM 	if ((0x008d == sc->sc_dev_id) ||
539210893SQuaker.Fang@Sun.COM 	    (0x008e == sc->sc_dev_id)) {
539310893SQuaker.Fang@Sun.COM 		sc->sc_chip_param.phy_mode = PHY_MODE_G |
539410893SQuaker.Fang@Sun.COM 		    PHY_MODE_A | PHY_MODE_N;
539510893SQuaker.Fang@Sun.COM 
539610893SQuaker.Fang@Sun.COM 		sc->sc_chip_param.tx_ant = ANT_A | ANT_B;
539710893SQuaker.Fang@Sun.COM 		sc->sc_chip_param.rx_ant = ANT_A | ANT_B;
539810893SQuaker.Fang@Sun.COM 
539910893SQuaker.Fang@Sun.COM 		sc->sc_chip_param.pa_type = PA_TYPE_MIX;
540010893SQuaker.Fang@Sun.COM 	}
540110893SQuaker.Fang@Sun.COM 
540210893SQuaker.Fang@Sun.COM 	if ((0x422c == sc->sc_dev_id) ||
540310893SQuaker.Fang@Sun.COM 	    (0x4239 == sc->sc_dev_id)) {
540410893SQuaker.Fang@Sun.COM 		sc->sc_chip_param.phy_mode = PHY_MODE_G |
540510893SQuaker.Fang@Sun.COM 		    PHY_MODE_A | PHY_MODE_N;
540610893SQuaker.Fang@Sun.COM 
540710893SQuaker.Fang@Sun.COM 		sc->sc_chip_param.tx_ant = ANT_B | ANT_C;
540810893SQuaker.Fang@Sun.COM 		sc->sc_chip_param.rx_ant = ANT_B | ANT_C;
540910893SQuaker.Fang@Sun.COM 
541010893SQuaker.Fang@Sun.COM 		sc->sc_chip_param.pa_type = PA_TYPE_INTER;
541110893SQuaker.Fang@Sun.COM 	}
541210893SQuaker.Fang@Sun.COM 
541310893SQuaker.Fang@Sun.COM 	if ((0x422b == sc->sc_dev_id) ||
541410893SQuaker.Fang@Sun.COM 	    (0x4238 == sc->sc_dev_id)) {
541510893SQuaker.Fang@Sun.COM 		sc->sc_chip_param.phy_mode = PHY_MODE_G |
541610893SQuaker.Fang@Sun.COM 		    PHY_MODE_A | PHY_MODE_N;
541710893SQuaker.Fang@Sun.COM 
541810893SQuaker.Fang@Sun.COM 		sc->sc_chip_param.tx_ant = ANT_A | ANT_B | ANT_C;
541910893SQuaker.Fang@Sun.COM 		sc->sc_chip_param.rx_ant = ANT_A | ANT_B | ANT_C;
542010893SQuaker.Fang@Sun.COM 
542110893SQuaker.Fang@Sun.COM 		sc->sc_chip_param.pa_type = PA_TYPE_SYSTEM;
542210893SQuaker.Fang@Sun.COM 	}
542310893SQuaker.Fang@Sun.COM }
5424