xref: /illumos-gate/usr/src/uts/common/io/iwk/iwk2.c (revision ae5a8bed)
1c533a883Shx /*
20dc2366fSVenugopal Iyer  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
3c533a883Shx  * Use is subject to license terms.
4c533a883Shx  */
5c533a883Shx 
6c533a883Shx /*
7c533a883Shx  * Copyright (c) 2007, Intel Corporation
8c533a883Shx  * All rights reserved.
9c533a883Shx  */
10c533a883Shx 
11c533a883Shx /*
12c533a883Shx  * Copyright (c) 2006
13c533a883Shx  * Copyright (c) 2007
14c533a883Shx  *	Damien Bergamini <damien.bergamini@free.fr>
15c533a883Shx  *
16c533a883Shx  * Permission to use, copy, modify, and distribute this software for any
17c533a883Shx  * purpose with or without fee is hereby granted, provided that the above
18c533a883Shx  * copyright notice and this permission notice appear in all copies.
19c533a883Shx  *
20c533a883Shx  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
21c533a883Shx  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
22c533a883Shx  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
23c533a883Shx  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
24c533a883Shx  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
25c533a883Shx  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
26c533a883Shx  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
27c533a883Shx  */
28c533a883Shx 
29c533a883Shx /*
30c533a883Shx  * Driver for Intel PRO/Wireless 4965AGN(kedron) 802.11 network adapters.
31c533a883Shx  */
32c533a883Shx 
33c533a883Shx #include <sys/types.h>
34c533a883Shx #include <sys/byteorder.h>
35c533a883Shx #include <sys/conf.h>
36c533a883Shx #include <sys/cmn_err.h>
37c533a883Shx #include <sys/stat.h>
38c533a883Shx #include <sys/ddi.h>
39c533a883Shx #include <sys/sunddi.h>
40c533a883Shx #include <sys/strsubr.h>
41c533a883Shx #include <sys/ethernet.h>
42c533a883Shx #include <inet/common.h>
43c533a883Shx #include <inet/nd.h>
44c533a883Shx #include <inet/mi.h>
45c533a883Shx #include <sys/note.h>
46c533a883Shx #include <sys/stream.h>
47c533a883Shx #include <sys/strsun.h>
48c533a883Shx #include <sys/modctl.h>
49c533a883Shx #include <sys/devops.h>
50c533a883Shx #include <sys/dlpi.h>
51da14cebeSEric Cheng #include <sys/mac_provider.h>
52c533a883Shx #include <sys/mac_wifi.h>
53c533a883Shx #include <sys/net80211.h>
54c533a883Shx #include <sys/net80211_proto.h>
55c533a883Shx #include <sys/varargs.h>
56c533a883Shx #include <sys/policy.h>
57c533a883Shx #include <sys/pci.h>
58c533a883Shx 
59cdc64593Sxinghua wen - Sun Microsystems - Beijing China #include "iwk_calibration.h"
60c533a883Shx #include "iwk_hw.h"
61c533a883Shx #include "iwk_eeprom.h"
62c533a883Shx #include "iwk2_var.h"
63c533a883Shx #include <inet/wifi_ioctl.h>
64c533a883Shx 
65c533a883Shx #ifdef DEBUG
66c533a883Shx #define	IWK_DEBUG_80211		(1 << 0)
67c533a883Shx #define	IWK_DEBUG_CMD		(1 << 1)
68c533a883Shx #define	IWK_DEBUG_DMA		(1 << 2)
69c533a883Shx #define	IWK_DEBUG_EEPROM	(1 << 3)
70c533a883Shx #define	IWK_DEBUG_FW		(1 << 4)
71c533a883Shx #define	IWK_DEBUG_HW		(1 << 5)
72c533a883Shx #define	IWK_DEBUG_INTR		(1 << 6)
73c533a883Shx #define	IWK_DEBUG_MRR		(1 << 7)
74c533a883Shx #define	IWK_DEBUG_PIO		(1 << 8)
75c533a883Shx #define	IWK_DEBUG_RX		(1 << 9)
76c533a883Shx #define	IWK_DEBUG_SCAN		(1 << 10)
77c533a883Shx #define	IWK_DEBUG_TX		(1 << 11)
78c533a883Shx #define	IWK_DEBUG_RATECTL	(1 << 12)
79c533a883Shx #define	IWK_DEBUG_RADIO		(1 << 13)
8043439c96Shx #define	IWK_DEBUG_RESUME	(1 << 14)
81cdc64593Sxinghua wen - Sun Microsystems - Beijing China #define	IWK_DEBUG_CALIBRATION	(1 << 15)
82c533a883Shx uint32_t iwk_dbg_flags = 0;
83c533a883Shx #define	IWK_DBG(x) \
84c533a883Shx 	iwk_dbg x
85c533a883Shx #else
86c533a883Shx #define	IWK_DBG(x)
87c533a883Shx #endif
88c533a883Shx 
89c533a883Shx static void	*iwk_soft_state_p = NULL;
90c533a883Shx static uint8_t iwk_fw_bin [] = {
91c533a883Shx #include "fw-iw/iw4965.ucode.hex"
92c533a883Shx };
93c533a883Shx 
94c533a883Shx /* DMA attributes for a shared page */
95c533a883Shx static ddi_dma_attr_t sh_dma_attr = {
96c533a883Shx 	DMA_ATTR_V0,	/* version of this structure */
97c533a883Shx 	0,		/* lowest usable address */
98c533a883Shx 	0xffffffffU,	/* highest usable address */
99c533a883Shx 	0xffffffffU,	/* maximum DMAable byte count */
100c533a883Shx 	0x1000,		/* alignment in bytes */
101c533a883Shx 	0x1000,		/* burst sizes (any?) */
102c533a883Shx 	1,		/* minimum transfer */
103c533a883Shx 	0xffffffffU,	/* maximum transfer */
104c533a883Shx 	0xffffffffU,	/* maximum segment length */
105c533a883Shx 	1,		/* maximum number of segments */
106c533a883Shx 	1,		/* granularity */
107c533a883Shx 	0,		/* flags (reserved) */
108c533a883Shx };
109c533a883Shx 
110c533a883Shx /* DMA attributes for a keep warm DRAM descriptor */
111c533a883Shx static ddi_dma_attr_t kw_dma_attr = {
112c533a883Shx 	DMA_ATTR_V0,	/* version of this structure */
113c533a883Shx 	0,		/* lowest usable address */
114c533a883Shx 	0xffffffffU,	/* highest usable address */
115c533a883Shx 	0xffffffffU,	/* maximum DMAable byte count */
116c533a883Shx 	0x1000,		/* alignment in bytes */
117c533a883Shx 	0x1000,		/* burst sizes (any?) */
118c533a883Shx 	1,		/* minimum transfer */
119c533a883Shx 	0xffffffffU,	/* maximum transfer */
120c533a883Shx 	0xffffffffU,	/* maximum segment length */
121c533a883Shx 	1,		/* maximum number of segments */
122c533a883Shx 	1,		/* granularity */
123c533a883Shx 	0,		/* flags (reserved) */
124c533a883Shx };
125c533a883Shx 
126c533a883Shx /* DMA attributes for a ring descriptor */
127c533a883Shx static ddi_dma_attr_t ring_desc_dma_attr = {
128c533a883Shx 	DMA_ATTR_V0,	/* version of this structure */
129c533a883Shx 	0,		/* lowest usable address */
130c533a883Shx 	0xffffffffU,	/* highest usable address */
131c533a883Shx 	0xffffffffU,	/* maximum DMAable byte count */
132c533a883Shx 	0x100,		/* alignment in bytes */
133c533a883Shx 	0x100,		/* burst sizes (any?) */
134c533a883Shx 	1,		/* minimum transfer */
135c533a883Shx 	0xffffffffU,	/* maximum transfer */
136c533a883Shx 	0xffffffffU,	/* maximum segment length */
137c533a883Shx 	1,		/* maximum number of segments */
138c533a883Shx 	1,		/* granularity */
139c533a883Shx 	0,		/* flags (reserved) */
140c533a883Shx };
141c533a883Shx 
142c533a883Shx /* DMA attributes for a cmd */
143c533a883Shx static ddi_dma_attr_t cmd_dma_attr = {
144c533a883Shx 	DMA_ATTR_V0,	/* version of this structure */
145c533a883Shx 	0,		/* lowest usable address */
146c533a883Shx 	0xffffffffU,	/* highest usable address */
147c533a883Shx 	0xffffffffU,	/* maximum DMAable byte count */
148c533a883Shx 	4,		/* alignment in bytes */
149c533a883Shx 	0x100,		/* burst sizes (any?) */
150c533a883Shx 	1,		/* minimum transfer */
151c533a883Shx 	0xffffffffU,	/* maximum transfer */
152c533a883Shx 	0xffffffffU,	/* maximum segment length */
153c533a883Shx 	1,		/* maximum number of segments */
154c533a883Shx 	1,		/* granularity */
155c533a883Shx 	0,		/* flags (reserved) */
156c533a883Shx };
157c533a883Shx 
158c533a883Shx /* DMA attributes for a rx buffer */
159c533a883Shx static ddi_dma_attr_t rx_buffer_dma_attr = {
160c533a883Shx 	DMA_ATTR_V0,	/* version of this structure */
161c533a883Shx 	0,		/* lowest usable address */
162c533a883Shx 	0xffffffffU,	/* highest usable address */
163c533a883Shx 	0xffffffffU,	/* maximum DMAable byte count */
164c533a883Shx 	0x100,		/* alignment in bytes */
165c533a883Shx 	0x100,		/* burst sizes (any?) */
166c533a883Shx 	1,		/* minimum transfer */
167c533a883Shx 	0xffffffffU,	/* maximum transfer */
168c533a883Shx 	0xffffffffU,	/* maximum segment length */
169c533a883Shx 	1,		/* maximum number of segments */
170c533a883Shx 	1,		/* granularity */
171c533a883Shx 	0,		/* flags (reserved) */
172c533a883Shx };
173c533a883Shx 
174c533a883Shx /*
175c533a883Shx  * DMA attributes for a tx buffer.
176c533a883Shx  * the maximum number of segments is 4 for the hardware.
177c533a883Shx  * now all the wifi drivers put the whole frame in a single
178c533a883Shx  * descriptor, so we define the maximum  number of segments 1,
179c533a883Shx  * just the same as the rx_buffer. we consider leverage the HW
180c533a883Shx  * ability in the future, that is why we don't define rx and tx
181c533a883Shx  * buffer_dma_attr as the same.
182c533a883Shx  */
183c533a883Shx static ddi_dma_attr_t tx_buffer_dma_attr = {
184c533a883Shx 	DMA_ATTR_V0,	/* version of this structure */
185c533a883Shx 	0,		/* lowest usable address */
186c533a883Shx 	0xffffffffU,	/* highest usable address */
187c533a883Shx 	0xffffffffU,	/* maximum DMAable byte count */
188c533a883Shx 	4,		/* alignment in bytes */
189c533a883Shx 	0x100,		/* burst sizes (any?) */
190c533a883Shx 	1,		/* minimum transfer */
191c533a883Shx 	0xffffffffU,	/* maximum transfer */
192c533a883Shx 	0xffffffffU,	/* maximum segment length */
193c533a883Shx 	1,		/* maximum number of segments */
194c533a883Shx 	1,		/* granularity */
195c533a883Shx 	0,		/* flags (reserved) */
196c533a883Shx };
197c533a883Shx 
198c533a883Shx /* DMA attributes for text and data part in the firmware */
199c533a883Shx static ddi_dma_attr_t fw_dma_attr = {
200c533a883Shx 	DMA_ATTR_V0,	/* version of this structure */
201c533a883Shx 	0,		/* lowest usable address */
202c533a883Shx 	0xffffffffU,	/* highest usable address */
203c533a883Shx 	0x7fffffff,	/* maximum DMAable byte count */
204c533a883Shx 	0x10,		/* alignment in bytes */
205c533a883Shx 	0x100,		/* burst sizes (any?) */
206c533a883Shx 	1,		/* minimum transfer */
207c533a883Shx 	0xffffffffU,	/* maximum transfer */
208c533a883Shx 	0xffffffffU,	/* maximum segment length */
209c533a883Shx 	1,		/* maximum number of segments */
210c533a883Shx 	1,		/* granularity */
211c533a883Shx 	0,		/* flags (reserved) */
212c533a883Shx };
213c533a883Shx 
214c533a883Shx 
215c533a883Shx /* regs access attributes */
216c533a883Shx static ddi_device_acc_attr_t iwk_reg_accattr = {
217c533a883Shx 	DDI_DEVICE_ATTR_V0,
218c533a883Shx 	DDI_STRUCTURE_LE_ACC,
219c533a883Shx 	DDI_STRICTORDER_ACC,
220c533a883Shx 	DDI_DEFAULT_ACC
221c533a883Shx };
222c533a883Shx 
223b510adaeSfei feng - Sun Microsystems - Beijing China /* DMA access attributes for Descriptor */
224b510adaeSfei feng - Sun Microsystems - Beijing China static ddi_device_acc_attr_t iwk_dma_descattr = {
225b510adaeSfei feng - Sun Microsystems - Beijing China 	DDI_DEVICE_ATTR_V0,
226b510adaeSfei feng - Sun Microsystems - Beijing China 	DDI_STRUCTURE_LE_ACC,
227b510adaeSfei feng - Sun Microsystems - Beijing China 	DDI_STRICTORDER_ACC,
228b510adaeSfei feng - Sun Microsystems - Beijing China 	DDI_DEFAULT_ACC
229b510adaeSfei feng - Sun Microsystems - Beijing China };
230b510adaeSfei feng - Sun Microsystems - Beijing China 
231c533a883Shx /* DMA access attributes */
232c533a883Shx static ddi_device_acc_attr_t iwk_dma_accattr = {
233c533a883Shx 	DDI_DEVICE_ATTR_V0,
234c533a883Shx 	DDI_NEVERSWAP_ACC,
235c533a883Shx 	DDI_STRICTORDER_ACC,
236c533a883Shx 	DDI_DEFAULT_ACC
237c533a883Shx };
238c533a883Shx 
239c533a883Shx static int	iwk_ring_init(iwk_sc_t *);
240c533a883Shx static void	iwk_ring_free(iwk_sc_t *);
241c533a883Shx static int	iwk_alloc_shared(iwk_sc_t *);
242c533a883Shx static void	iwk_free_shared(iwk_sc_t *);
243c533a883Shx static int	iwk_alloc_kw(iwk_sc_t *);
244c533a883Shx static void	iwk_free_kw(iwk_sc_t *);
245c533a883Shx static int	iwk_alloc_fw_dma(iwk_sc_t *);
246c533a883Shx static void	iwk_free_fw_dma(iwk_sc_t *);
247c533a883Shx static int	iwk_alloc_rx_ring(iwk_sc_t *);
248c533a883Shx static void	iwk_reset_rx_ring(iwk_sc_t *);
249c533a883Shx static void	iwk_free_rx_ring(iwk_sc_t *);
250c533a883Shx static int	iwk_alloc_tx_ring(iwk_sc_t *, iwk_tx_ring_t *,
251c533a883Shx     int, int);
252c533a883Shx static void	iwk_reset_tx_ring(iwk_sc_t *, iwk_tx_ring_t *);
253c533a883Shx static void	iwk_free_tx_ring(iwk_sc_t *, iwk_tx_ring_t *);
254c533a883Shx 
25543439c96Shx static ieee80211_node_t *iwk_node_alloc(ieee80211com_t *);
25643439c96Shx static void	iwk_node_free(ieee80211_node_t *);
257c533a883Shx static int	iwk_newstate(ieee80211com_t *, enum ieee80211_state, int);
258c533a883Shx static int	iwk_key_set(ieee80211com_t *, const struct ieee80211_key *,
259c533a883Shx     const uint8_t mac[IEEE80211_ADDR_LEN]);
260c533a883Shx static void	iwk_mac_access_enter(iwk_sc_t *);
261c533a883Shx static void	iwk_mac_access_exit(iwk_sc_t *);
262c533a883Shx static uint32_t	iwk_reg_read(iwk_sc_t *, uint32_t);
263c533a883Shx static void	iwk_reg_write(iwk_sc_t *, uint32_t, uint32_t);
264c533a883Shx static void	iwk_reg_write_region_4(iwk_sc_t *, uint32_t,
265c533a883Shx 		    uint32_t *, int);
266c533a883Shx static int	iwk_load_firmware(iwk_sc_t *);
267c533a883Shx static void	iwk_rx_intr(iwk_sc_t *, iwk_rx_desc_t *,
268c533a883Shx 		    iwk_rx_data_t *);
269c533a883Shx static void	iwk_tx_intr(iwk_sc_t *, iwk_rx_desc_t *,
270c533a883Shx 		    iwk_rx_data_t *);
271c533a883Shx static void	iwk_cmd_intr(iwk_sc_t *, iwk_rx_desc_t *);
272cdc64593Sxinghua wen - Sun Microsystems - Beijing China static uint_t   iwk_intr(caddr_t, caddr_t);
273c533a883Shx static int	iwk_eep_load(iwk_sc_t *sc);
274c533a883Shx static void	iwk_get_mac_from_eep(iwk_sc_t *sc);
275c533a883Shx static int	iwk_eep_sem_down(iwk_sc_t *sc);
276c533a883Shx static void	iwk_eep_sem_up(iwk_sc_t *sc);
277cdc64593Sxinghua wen - Sun Microsystems - Beijing China static uint_t   iwk_rx_softintr(caddr_t, caddr_t);
278c533a883Shx static uint8_t	iwk_rate_to_plcp(int);
279c533a883Shx static int	iwk_cmd(iwk_sc_t *, int, const void *, int, int);
280c533a883Shx static void	iwk_set_led(iwk_sc_t *, uint8_t, uint8_t, uint8_t);
281c533a883Shx static int	iwk_hw_set_before_auth(iwk_sc_t *);
282c533a883Shx static int	iwk_scan(iwk_sc_t *);
283c533a883Shx static int	iwk_config(iwk_sc_t *);
284c533a883Shx static void	iwk_stop_master(iwk_sc_t *);
285c533a883Shx static int	iwk_power_up(iwk_sc_t *);
286c533a883Shx static int	iwk_preinit(iwk_sc_t *);
287c533a883Shx static int	iwk_init(iwk_sc_t *);
288c533a883Shx static void	iwk_stop(iwk_sc_t *);
28943439c96Shx static void	iwk_amrr_init(iwk_amrr_t *);
29043439c96Shx static void	iwk_amrr_timeout(iwk_sc_t *);
29143439c96Shx static void	iwk_amrr_ratectl(void *, ieee80211_node_t *);
292cdc64593Sxinghua wen - Sun Microsystems - Beijing China static int32_t	iwk_curr_tempera(iwk_sc_t *sc);
293cdc64593Sxinghua wen - Sun Microsystems - Beijing China static int	iwk_tx_power_calibration(iwk_sc_t *sc);
294cdc64593Sxinghua wen - Sun Microsystems - Beijing China static inline int	iwk_is_24G_band(iwk_sc_t *sc);
295cdc64593Sxinghua wen - Sun Microsystems - Beijing China static inline int	iwk_is_fat_channel(iwk_sc_t *sc);
296cdc64593Sxinghua wen - Sun Microsystems - Beijing China static int	iwk_txpower_grp(uint16_t channel);
297cdc64593Sxinghua wen - Sun Microsystems - Beijing China static struct	iwk_eep_channel *iwk_get_eep_channel(iwk_sc_t *sc,
298cdc64593Sxinghua wen - Sun Microsystems - Beijing China     uint16_t channel,
299cdc64593Sxinghua wen - Sun Microsystems - Beijing China     int is_24G, int is_fat, int is_hi_chan);
300cdc64593Sxinghua wen - Sun Microsystems - Beijing China static int32_t	iwk_band_number(iwk_sc_t *sc, uint16_t channel);
301cdc64593Sxinghua wen - Sun Microsystems - Beijing China static int	iwk_division(int32_t num, int32_t denom, int32_t *res);
302cdc64593Sxinghua wen - Sun Microsystems - Beijing China static int32_t	iwk_interpolate_value(int32_t x, int32_t x1, int32_t y1,
303cdc64593Sxinghua wen - Sun Microsystems - Beijing China     int32_t x2, int32_t y2);
304cdc64593Sxinghua wen - Sun Microsystems - Beijing China static int	iwk_channel_interpolate(iwk_sc_t *sc, uint16_t channel,
305cdc64593Sxinghua wen - Sun Microsystems - Beijing China     struct iwk_eep_calib_channel_info *chan_info);
306cdc64593Sxinghua wen - Sun Microsystems - Beijing China static int32_t	iwk_voltage_compensation(int32_t eep_voltage,
307cdc64593Sxinghua wen - Sun Microsystems - Beijing China     int32_t curr_voltage);
308cdc64593Sxinghua wen - Sun Microsystems - Beijing China static int32_t	iwk_min_power_index(int32_t rate_pow_idx, int32_t is_24G);
309cdc64593Sxinghua wen - Sun Microsystems - Beijing China static int	iwk_txpower_table_cmd_init(iwk_sc_t *sc,
310cdc64593Sxinghua wen - Sun Microsystems - Beijing China     struct iwk_tx_power_db *tp_db);
311cdc64593Sxinghua wen - Sun Microsystems - Beijing China static void	iwk_statistics_notify(iwk_sc_t *sc, iwk_rx_desc_t *desc);
312cdc64593Sxinghua wen - Sun Microsystems - Beijing China static int	iwk_is_associated(iwk_sc_t *sc);
313cdc64593Sxinghua wen - Sun Microsystems - Beijing China static int	iwk_rxgain_diff_init(iwk_sc_t *sc);
314cdc64593Sxinghua wen - Sun Microsystems - Beijing China static int	iwk_rxgain_diff(iwk_sc_t *sc);
315cdc64593Sxinghua wen - Sun Microsystems - Beijing China static int	iwk_rx_sens_init(iwk_sc_t *sc);
316cdc64593Sxinghua wen - Sun Microsystems - Beijing China static int	iwk_rx_sens(iwk_sc_t *sc);
317cdc64593Sxinghua wen - Sun Microsystems - Beijing China static int	iwk_cck_sens(iwk_sc_t *sc, uint32_t actual_rx_time);
318cdc64593Sxinghua wen - Sun Microsystems - Beijing China static int	iwk_ofdm_sens(iwk_sc_t *sc, uint32_t actual_rx_time);
31919d332feSfei feng - Sun Microsystems - Beijing China static void	iwk_recv_mgmt(struct ieee80211com *ic, mblk_t *mp,
32019d332feSfei feng - Sun Microsystems - Beijing China     struct ieee80211_node *in, int subtype, int rssi, uint32_t rstamp);
321cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
322cdc64593Sxinghua wen - Sun Microsystems - Beijing China static void	iwk_write_event_log(iwk_sc_t *);
323cdc64593Sxinghua wen - Sun Microsystems - Beijing China static void	iwk_write_error_log(iwk_sc_t *);
324cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
325cdc64593Sxinghua wen - Sun Microsystems - Beijing China static int	iwk_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
326cdc64593Sxinghua wen - Sun Microsystems - Beijing China static int	iwk_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
327d2a61391Spengcheng chen - Sun Microsystems - Beijing China static int	iwk_quiesce(dev_info_t *dip);
328c533a883Shx 
329c533a883Shx /*
330c533a883Shx  * GLD specific operations
331c533a883Shx  */
332c533a883Shx static int	iwk_m_stat(void *arg, uint_t stat, uint64_t *val);
333c533a883Shx static int	iwk_m_start(void *arg);
334c533a883Shx static void	iwk_m_stop(void *arg);
335c533a883Shx static int	iwk_m_unicst(void *arg, const uint8_t *macaddr);
336c533a883Shx static int	iwk_m_multicst(void *arg, boolean_t add, const uint8_t *m);
337c533a883Shx static int	iwk_m_promisc(void *arg, boolean_t on);
338*ae5a8bedSAndy Fiddaman static mblk_t	*iwk_m_tx(void *arg, mblk_t *mp);
339c533a883Shx static void	iwk_m_ioctl(void *arg, queue_t *wq, mblk_t *mp);
340bcb5c89dSSowmini Varadhan static int	iwk_m_setprop(void *arg, const char *pr_name,
341bcb5c89dSSowmini Varadhan 	mac_prop_id_t wldp_pr_name, uint_t wldp_length, const void *wldp_buf);
342bcb5c89dSSowmini Varadhan static int	iwk_m_getprop(void *arg, const char *pr_name,
3430dc2366fSVenugopal Iyer 	mac_prop_id_t wldp_pr_name, uint_t wldp_length, void *wldp_buf);
3440dc2366fSVenugopal Iyer static void	iwk_m_propinfo(void *arg, const char *pr_name,
3450dc2366fSVenugopal Iyer     mac_prop_id_t wldp_pr_num, mac_prop_info_handle_t mph);
346c533a883Shx static void	iwk_destroy_locks(iwk_sc_t *sc);
347c533a883Shx static int	iwk_send(ieee80211com_t *ic, mblk_t *mp, uint8_t type);
348c533a883Shx static void	iwk_thread(iwk_sc_t *sc);
349f3c4902cSpengcheng chen - Sun Microsystems - Beijing China static void	iwk_watchdog(void *arg);
35019d332feSfei feng - Sun Microsystems - Beijing China static int	iwk_run_state_config_ibss(ieee80211com_t *ic);
35119d332feSfei feng - Sun Microsystems - Beijing China static int	iwk_run_state_config_sta(ieee80211com_t *ic);
3526f12def4Spengcheng chen - Sun Microsystems - Beijing China static int	iwk_fast_recover(iwk_sc_t *sc);
35319d332feSfei feng - Sun Microsystems - Beijing China static int	iwk_start_tx_beacon(ieee80211com_t *ic);
35419d332feSfei feng - Sun Microsystems - Beijing China static int	iwk_clean_add_node_ibss(struct ieee80211com *ic,
35519d332feSfei feng - Sun Microsystems - Beijing China     uint8_t addr[IEEE80211_ADDR_LEN], uint8_t *index2);
356c533a883Shx 
357c533a883Shx /*
358c533a883Shx  * Supported rates for 802.11b/g modes (in 500Kbps unit).
359c533a883Shx  * 11a and 11n support will be added later.
360c533a883Shx  */
361c533a883Shx static const struct ieee80211_rateset iwk_rateset_11b =
362c533a883Shx 	{ 4, { 2, 4, 11, 22 } };
363c533a883Shx 
364c533a883Shx static const struct ieee80211_rateset iwk_rateset_11g =
365c533a883Shx 	{ 12, { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 } };
366c533a883Shx 
367c533a883Shx /*
368c533a883Shx  * For mfthread only
369c533a883Shx  */
370c533a883Shx extern pri_t minclsyspri;
371c533a883Shx 
372c533a883Shx #define	DRV_NAME_4965	"iwk"
373c533a883Shx 
374c533a883Shx /*
375c533a883Shx  * Module Loading Data & Entry Points
376c533a883Shx  */
377c533a883Shx DDI_DEFINE_STREAM_OPS(iwk_devops, nulldev, nulldev, iwk_attach,
378d2a61391Spengcheng chen - Sun Microsystems - Beijing China     iwk_detach, nodev, NULL, D_MP, NULL, iwk_quiesce);
379c533a883Shx 
380c533a883Shx static struct modldrv iwk_modldrv = {
381c533a883Shx 	&mod_driverops,
382c533a883Shx 	"Intel(R) 4965AGN driver(N)",
383c533a883Shx 	&iwk_devops
384c533a883Shx };
385c533a883Shx 
386c533a883Shx static struct modlinkage iwk_modlinkage = {
387c533a883Shx 	MODREV_1,
388c533a883Shx 	&iwk_modldrv,
389c533a883Shx 	NULL
390c533a883Shx };
391c533a883Shx 
392c533a883Shx int
_init(void)393c533a883Shx _init(void)
394c533a883Shx {
395c533a883Shx 	int	status;
396c533a883Shx 
397c533a883Shx 	status = ddi_soft_state_init(&iwk_soft_state_p,
398c533a883Shx 	    sizeof (iwk_sc_t), 1);
399c533a883Shx 	if (status != DDI_SUCCESS)
400c533a883Shx 		return (status);
401c533a883Shx 
402c533a883Shx 	mac_init_ops(&iwk_devops, DRV_NAME_4965);
403c533a883Shx 	status = mod_install(&iwk_modlinkage);
404c533a883Shx 	if (status != DDI_SUCCESS) {
405c533a883Shx 		mac_fini_ops(&iwk_devops);
406c533a883Shx 		ddi_soft_state_fini(&iwk_soft_state_p);
407c533a883Shx 	}
408c533a883Shx 
409c533a883Shx 	return (status);
410c533a883Shx }
411c533a883Shx 
412c533a883Shx int
_fini(void)413c533a883Shx _fini(void)
414c533a883Shx {
415c533a883Shx 	int status;
416c533a883Shx 
417c533a883Shx 	status = mod_remove(&iwk_modlinkage);
418c533a883Shx 	if (status == DDI_SUCCESS) {
419c533a883Shx 		mac_fini_ops(&iwk_devops);
420c533a883Shx 		ddi_soft_state_fini(&iwk_soft_state_p);
421c533a883Shx 	}
422c533a883Shx 
423c533a883Shx 	return (status);
424c533a883Shx }
425c533a883Shx 
426c533a883Shx int
_info(struct modinfo * mip)427c533a883Shx _info(struct modinfo *mip)
428c533a883Shx {
429c533a883Shx 	return (mod_info(&iwk_modlinkage, mip));
430c533a883Shx }
431c533a883Shx 
432c533a883Shx /*
433c533a883Shx  * Mac Call Back entries
434c533a883Shx  */
435c533a883Shx mac_callbacks_t	iwk_m_callbacks = {
4360dc2366fSVenugopal Iyer 	MC_IOCTL | MC_SETPROP | MC_GETPROP | MC_PROPINFO,
437c533a883Shx 	iwk_m_stat,
438c533a883Shx 	iwk_m_start,
439c533a883Shx 	iwk_m_stop,
440c533a883Shx 	iwk_m_promisc,
441c533a883Shx 	iwk_m_multicst,
442c533a883Shx 	iwk_m_unicst,
443c533a883Shx 	iwk_m_tx,
4440dc2366fSVenugopal Iyer 	NULL,
445bcb5c89dSSowmini Varadhan 	iwk_m_ioctl,
446bcb5c89dSSowmini Varadhan 	NULL,
447bcb5c89dSSowmini Varadhan 	NULL,
448bcb5c89dSSowmini Varadhan 	NULL,
449bcb5c89dSSowmini Varadhan 	iwk_m_setprop,
4500dc2366fSVenugopal Iyer 	iwk_m_getprop,
4510dc2366fSVenugopal Iyer 	iwk_m_propinfo
452c533a883Shx };
453c533a883Shx 
454c533a883Shx #ifdef DEBUG
455c533a883Shx void
iwk_dbg(uint32_t flags,const char * fmt,...)456c533a883Shx iwk_dbg(uint32_t flags, const char *fmt, ...)
457c533a883Shx {
458c533a883Shx 	va_list	ap;
459c533a883Shx 
460c533a883Shx 	if (flags & iwk_dbg_flags) {
461c533a883Shx 		va_start(ap, fmt);
462c533a883Shx 		vcmn_err(CE_NOTE, fmt, ap);
463c533a883Shx 		va_end(ap);
464c533a883Shx 	}
465c533a883Shx }
466c533a883Shx #endif
467c533a883Shx 
468c533a883Shx /*
469c533a883Shx  * device operations
470c533a883Shx  */
471c533a883Shx int
iwk_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)472c533a883Shx iwk_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
473c533a883Shx {
474c533a883Shx 	iwk_sc_t		*sc;
475c533a883Shx 	ieee80211com_t	*ic;
476c533a883Shx 	int			instance, err, i;
477c533a883Shx 	char			strbuf[32];
478c533a883Shx 	wifi_data_t		wd = { 0 };
479c533a883Shx 	mac_register_t		*macp;
480c533a883Shx 
481cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	int			intr_type;
482cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	int			intr_count;
483cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	int			intr_actual;
484cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
485d62cb7ffShx 	switch (cmd) {
486d62cb7ffShx 	case DDI_ATTACH:
487d62cb7ffShx 		break;
488d62cb7ffShx 	case DDI_RESUME:
489d62cb7ffShx 		sc = ddi_get_soft_state(iwk_soft_state_p,
490d62cb7ffShx 		    ddi_get_instance(dip));
491d62cb7ffShx 		ASSERT(sc != NULL);
49209539a3cSpengcheng chen - Sun Microsystems - Beijing China 
49309539a3cSpengcheng chen - Sun Microsystems - Beijing China 		mutex_enter(&sc->sc_glock);
49409539a3cSpengcheng chen - Sun Microsystems - Beijing China 		sc->sc_flags &= ~IWK_F_SUSPEND;
49509539a3cSpengcheng chen - Sun Microsystems - Beijing China 		mutex_exit(&sc->sc_glock);
49609539a3cSpengcheng chen - Sun Microsystems - Beijing China 
497d40f4da4Spengcheng chen - Sun Microsystems - Beijing China 		if (sc->sc_flags & IWK_F_RUNNING)
498d40f4da4Spengcheng chen - Sun Microsystems - Beijing China 			(void) iwk_init(sc);
499d40f4da4Spengcheng chen - Sun Microsystems - Beijing China 
500d62cb7ffShx 		mutex_enter(&sc->sc_glock);
501d40f4da4Spengcheng chen - Sun Microsystems - Beijing China 		sc->sc_flags |= IWK_F_LAZY_RESUME;
502d62cb7ffShx 		mutex_exit(&sc->sc_glock);
503d40f4da4Spengcheng chen - Sun Microsystems - Beijing China 
504d62cb7ffShx 		IWK_DBG((IWK_DEBUG_RESUME, "iwk: resume\n"));
505d62cb7ffShx 		return (DDI_SUCCESS);
506d62cb7ffShx 	default:
507c533a883Shx 		err = DDI_FAILURE;
508c533a883Shx 		goto attach_fail1;
509c533a883Shx 	}
510c533a883Shx 
511c533a883Shx 	instance = ddi_get_instance(dip);
512c533a883Shx 	err = ddi_soft_state_zalloc(iwk_soft_state_p, instance);
513c533a883Shx 	if (err != DDI_SUCCESS) {
514c533a883Shx 		cmn_err(CE_WARN,
515c533a883Shx 		    "iwk_attach(): failed to allocate soft state\n");
516c533a883Shx 		goto attach_fail1;
517c533a883Shx 	}
518c533a883Shx 	sc = ddi_get_soft_state(iwk_soft_state_p, instance);
519c533a883Shx 	sc->sc_dip = dip;
520c533a883Shx 
521c533a883Shx 	err = ddi_regs_map_setup(dip, 0, &sc->sc_cfg_base, 0, 0,
522c533a883Shx 	    &iwk_reg_accattr, &sc->sc_cfg_handle);
523c533a883Shx 	if (err != DDI_SUCCESS) {
524c533a883Shx 		cmn_err(CE_WARN,
525c533a883Shx 		    "iwk_attach(): failed to map config spaces regs\n");
526c533a883Shx 		goto attach_fail2;
527c533a883Shx 	}
528c533a883Shx 	sc->sc_rev = ddi_get8(sc->sc_cfg_handle,
529c533a883Shx 	    (uint8_t *)(sc->sc_cfg_base + PCI_CONF_REVID));
530c533a883Shx 	ddi_put8(sc->sc_cfg_handle, (uint8_t *)(sc->sc_cfg_base + 0x41), 0);
531c533a883Shx 	sc->sc_clsz = ddi_get16(sc->sc_cfg_handle,
532c533a883Shx 	    (uint16_t *)(sc->sc_cfg_base + PCI_CONF_CACHE_LINESZ));
533c533a883Shx 	if (!sc->sc_clsz)
534c533a883Shx 		sc->sc_clsz = 16;
535c533a883Shx 	sc->sc_clsz = (sc->sc_clsz << 2);
536c533a883Shx 	sc->sc_dmabuf_sz = roundup(0x1000 + sizeof (struct ieee80211_frame) +
537c533a883Shx 	    IEEE80211_MTU + IEEE80211_CRC_LEN +
538c533a883Shx 	    (IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN +
539c533a883Shx 	    IEEE80211_WEP_CRCLEN), sc->sc_clsz);
540c533a883Shx 	/*
541c533a883Shx 	 * Map operating registers
542c533a883Shx 	 */
543c533a883Shx 	err = ddi_regs_map_setup(dip, 1, &sc->sc_base,
544c533a883Shx 	    0, 0, &iwk_reg_accattr, &sc->sc_handle);
545c533a883Shx 	if (err != DDI_SUCCESS) {
546c533a883Shx 		cmn_err(CE_WARN,
547c533a883Shx 		    "iwk_attach(): failed to map device regs\n");
548c533a883Shx 		goto attach_fail2a;
549c533a883Shx 	}
550c533a883Shx 
551cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	err = ddi_intr_get_supported_types(dip, &intr_type);
552cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if ((err != DDI_SUCCESS) || (!(intr_type & DDI_INTR_TYPE_FIXED))) {
553cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		cmn_err(CE_WARN, "iwk_attach(): "
554cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		    "Fixed type interrupt is not supported\n");
555cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		goto attach_fail_intr_a;
556cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
557cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
558cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	err = ddi_intr_get_nintrs(dip, DDI_INTR_TYPE_FIXED, &intr_count);
559cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if ((err != DDI_SUCCESS) || (intr_count != 1)) {
560cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		cmn_err(CE_WARN, "iwk_attach(): "
561cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		    "No fixed interrupts\n");
562cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		goto attach_fail_intr_a;
563cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
564cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
565cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	sc->sc_intr_htable = kmem_zalloc(sizeof (ddi_intr_handle_t), KM_SLEEP);
566cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
567cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	err = ddi_intr_alloc(dip, sc->sc_intr_htable, DDI_INTR_TYPE_FIXED, 0,
568cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	    intr_count, &intr_actual, 0);
569cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if ((err != DDI_SUCCESS) || (intr_actual != 1)) {
570cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		cmn_err(CE_WARN, "iwk_attach(): "
571cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		    "ddi_intr_alloc() failed 0x%x\n", err);
572cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		goto attach_fail_intr_b;
573cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
574cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
575cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	err = ddi_intr_get_pri(sc->sc_intr_htable[0], &sc->sc_intr_pri);
576c533a883Shx 	if (err != DDI_SUCCESS) {
577cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		cmn_err(CE_WARN, "iwk_attach(): "
578cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		    "ddi_intr_get_pri() failed 0x%x\n", err);
579cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		goto attach_fail_intr_c;
580c533a883Shx 	}
581cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
582cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	mutex_init(&sc->sc_glock, NULL, MUTEX_DRIVER,
583cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	    DDI_INTR_PRI(sc->sc_intr_pri));
584cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	mutex_init(&sc->sc_tx_lock, NULL, MUTEX_DRIVER,
585cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	    DDI_INTR_PRI(sc->sc_intr_pri));
586cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	mutex_init(&sc->sc_mt_lock, NULL, MUTEX_DRIVER,
587cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	    DDI_INTR_PRI(sc->sc_intr_pri));
58819d332feSfei feng - Sun Microsystems - Beijing China 	mutex_init(&sc->sc_ibss.node_tb_lock, NULL, MUTEX_DRIVER,
58919d332feSfei feng - Sun Microsystems - Beijing China 	    DDI_INTR_PRI(sc->sc_intr_pri));
590cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
591c533a883Shx 	cv_init(&sc->sc_fw_cv, NULL, CV_DRIVER, NULL);
592c533a883Shx 	cv_init(&sc->sc_cmd_cv, NULL, CV_DRIVER, NULL);
593c533a883Shx 	cv_init(&sc->sc_tx_cv, "tx-ring", CV_DRIVER, NULL);
594c533a883Shx 	/*
595c533a883Shx 	 * initialize the mfthread
596c533a883Shx 	 */
597c533a883Shx 	cv_init(&sc->sc_mt_cv, NULL, CV_DRIVER, NULL);
598c533a883Shx 	sc->sc_mf_thread = NULL;
599c533a883Shx 	sc->sc_mf_thread_switch = 0;
600c533a883Shx 
601c533a883Shx 	/*
602c533a883Shx 	 * Allocate shared page.
603c533a883Shx 	 */
604c533a883Shx 	err = iwk_alloc_shared(sc);
605c533a883Shx 	if (err != DDI_SUCCESS) {
606cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		cmn_err(CE_WARN, "iwk_attach(): "
607cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		    "failed to allocate shared page\n");
608c533a883Shx 		goto attach_fail3;
609c533a883Shx 	}
610c533a883Shx 
611c533a883Shx 	/*
612c533a883Shx 	 * Allocate keep warm page.
613c533a883Shx 	 */
614c533a883Shx 	err = iwk_alloc_kw(sc);
615c533a883Shx 	if (err != DDI_SUCCESS) {
616cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		cmn_err(CE_WARN, "iwk_attach(): "
617cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		    "failed to allocate keep warm page\n");
618c533a883Shx 		goto attach_fail3a;
619c533a883Shx 	}
620c533a883Shx 
621c533a883Shx 	/*
622c533a883Shx 	 * Do some necessary hardware initializations.
623c533a883Shx 	 */
624c533a883Shx 	err = iwk_preinit(sc);
625c533a883Shx 	if (err != DDI_SUCCESS) {
626cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		cmn_err(CE_WARN, "iwk_attach(): "
627cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		    "failed to init hardware\n");
628c533a883Shx 		goto attach_fail4;
629c533a883Shx 	}
630c533a883Shx 
631c533a883Shx 	/* initialize EEPROM */
632c533a883Shx 	err = iwk_eep_load(sc);  /* get hardware configurations from eeprom */
633c533a883Shx 	if (err != 0) {
634c533a883Shx 		cmn_err(CE_WARN, "iwk_attach(): failed to load eeprom\n");
635c533a883Shx 		goto attach_fail4;
636c533a883Shx 	}
637c533a883Shx 
638b510adaeSfei feng - Sun Microsystems - Beijing China 	if (LE_16(sc->sc_eep_map.calib_version) < EEP_TX_POWER_VERSION_NEW) {
639c50ced99Spengcheng chen - Sun Microsystems - Beijing China 		cmn_err(CE_WARN, "older EEPROM detected\n");
640c533a883Shx 		goto attach_fail4;
641c533a883Shx 	}
642c533a883Shx 
643c533a883Shx 	iwk_get_mac_from_eep(sc);
644c533a883Shx 
645c533a883Shx 	err = iwk_ring_init(sc);
646c533a883Shx 	if (err != DDI_SUCCESS) {
647c533a883Shx 		cmn_err(CE_WARN, "iwk_attach(): "
648c533a883Shx 		    "failed to allocate and initialize ring\n");
649c533a883Shx 		goto attach_fail4;
650c533a883Shx 	}
651c533a883Shx 
652c533a883Shx 	sc->sc_hdr = (iwk_firmware_hdr_t *)iwk_fw_bin;
653c533a883Shx 
654c533a883Shx 	err = iwk_alloc_fw_dma(sc);
655c533a883Shx 	if (err != DDI_SUCCESS) {
656c533a883Shx 		cmn_err(CE_WARN, "iwk_attach(): "
657c533a883Shx 		    "failed to allocate firmware dma\n");
658c533a883Shx 		goto attach_fail5;
659c533a883Shx 	}
660c533a883Shx 
661c533a883Shx 	/*
662c533a883Shx 	 * Initialize the wifi part, which will be used by
663c533a883Shx 	 * generic layer
664c533a883Shx 	 */
665c533a883Shx 	ic = &sc->sc_ic;
666c533a883Shx 	ic->ic_phytype  = IEEE80211_T_OFDM;
667c533a883Shx 	ic->ic_opmode   = IEEE80211_M_STA; /* default to BSS mode */
668c533a883Shx 	ic->ic_state    = IEEE80211_S_INIT;
669c533a883Shx 	ic->ic_maxrssi  = 100; /* experimental number */
670c533a883Shx 	ic->ic_caps = IEEE80211_C_SHPREAMBLE | IEEE80211_C_TXPMGT |
671c533a883Shx 	    IEEE80211_C_PMGT | IEEE80211_C_SHSLOT;
672c533a883Shx 	/*
673c533a883Shx 	 * use software WEP and TKIP, hardware CCMP;
674c533a883Shx 	 */
675c533a883Shx 	ic->ic_caps |= IEEE80211_C_AES_CCM;
676c533a883Shx 	/*
677c533a883Shx 	 * Support WPA/WPA2
678c533a883Shx 	 */
679c533a883Shx 	ic->ic_caps |= IEEE80211_C_WPA;
68019d332feSfei feng - Sun Microsystems - Beijing China 	/*
68119d332feSfei feng - Sun Microsystems - Beijing China 	 * support Adhoc mode
68219d332feSfei feng - Sun Microsystems - Beijing China 	 */
68319d332feSfei feng - Sun Microsystems - Beijing China 	ic->ic_caps |= IEEE80211_C_IBSS;
684cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
685c533a883Shx 	/* set supported .11b and .11g rates */
686c533a883Shx 	ic->ic_sup_rates[IEEE80211_MODE_11B] = iwk_rateset_11b;
687c533a883Shx 	ic->ic_sup_rates[IEEE80211_MODE_11G] = iwk_rateset_11g;
688c533a883Shx 
689c50ced99Spengcheng chen - Sun Microsystems - Beijing China 	/* set supported .11b and .11g channels (1 through 11) */
690c50ced99Spengcheng chen - Sun Microsystems - Beijing China 	for (i = 1; i <= 11; i++) {
691c533a883Shx 		ic->ic_sup_channels[i].ich_freq =
692c533a883Shx 		    ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ);
693c533a883Shx 		ic->ic_sup_channels[i].ich_flags =
694c533a883Shx 		    IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM |
695c50ced99Spengcheng chen - Sun Microsystems - Beijing China 		    IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ |
696c50ced99Spengcheng chen - Sun Microsystems - Beijing China 		    IEEE80211_CHAN_PASSIVE;
697c533a883Shx 	}
69819d332feSfei feng - Sun Microsystems - Beijing China 	ic->ic_ibss_chan = &ic->ic_sup_channels[0];
699cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
700c533a883Shx 	ic->ic_xmit = iwk_send;
701c533a883Shx 	/*
702c533a883Shx 	 * init Wifi layer
703c533a883Shx 	 */
704c533a883Shx 	ieee80211_attach(ic);
705c533a883Shx 
706c533a883Shx 	/*
707c533a883Shx 	 * different instance has different WPA door
708c533a883Shx 	 */
709c533a883Shx 	(void) snprintf(ic->ic_wpadoor, MAX_IEEE80211STR, "%s_%s%d", WPA_DOOR,
710c533a883Shx 	    ddi_driver_name(dip),
711c533a883Shx 	    ddi_get_instance(dip));
712c533a883Shx 
713c533a883Shx 	/*
714c533a883Shx 	 * Override 80211 default routines
715c533a883Shx 	 */
716c533a883Shx 	sc->sc_newstate = ic->ic_newstate;
717c533a883Shx 	ic->ic_newstate = iwk_newstate;
718f3c4902cSpengcheng chen - Sun Microsystems - Beijing China 	ic->ic_watchdog = iwk_watchdog;
719cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	sc->sc_recv_mgmt = ic->ic_recv_mgmt;
72019d332feSfei feng - Sun Microsystems - Beijing China 	ic->ic_recv_mgmt = iwk_recv_mgmt;
72143439c96Shx 	ic->ic_node_alloc = iwk_node_alloc;
72243439c96Shx 	ic->ic_node_free = iwk_node_free;
723c533a883Shx 	ic->ic_crypto.cs_key_set = iwk_key_set;
724c533a883Shx 	ieee80211_media_init(ic);
725c533a883Shx 	/*
726c533a883Shx 	 * initialize default tx key
727c533a883Shx 	 */
728c533a883Shx 	ic->ic_def_txkey = 0;
729cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	err = ddi_intr_add_softint(dip, &sc->sc_soft_hdl, DDI_INTR_SOFTPRI_MAX,
730cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	    iwk_rx_softintr, (caddr_t)sc);
731c533a883Shx 	if (err != DDI_SUCCESS) {
732cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		cmn_err(CE_WARN, "iwk_attach(): "
733cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		    "add soft interrupt failed\n");
734c533a883Shx 		goto attach_fail7;
735c533a883Shx 	}
736c533a883Shx 
737c533a883Shx 	/*
738c533a883Shx 	 * Add the interrupt handler
739c533a883Shx 	 */
740cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	err = ddi_intr_add_handler(sc->sc_intr_htable[0], iwk_intr,
741cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	    (caddr_t)sc, NULL);
742c533a883Shx 	if (err != DDI_SUCCESS) {
743cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		cmn_err(CE_WARN, "iwk_attach(): "
744cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		    "ddi_intr_add_handle() failed\n");
745c533a883Shx 		goto attach_fail8;
746c533a883Shx 	}
747c533a883Shx 
748cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	err = ddi_intr_enable(sc->sc_intr_htable[0]);
749cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (err != DDI_SUCCESS) {
750cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		cmn_err(CE_WARN, "iwk_attach(): "
751cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		    "ddi_intr_enable() failed\n");
752cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		goto attach_fail_intr_d;
753cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
754cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
755c533a883Shx 	/*
756c533a883Shx 	 * Initialize pointer to device specific functions
757c533a883Shx 	 */
758c533a883Shx 	wd.wd_secalloc = WIFI_SEC_NONE;
759c533a883Shx 	wd.wd_opmode = ic->ic_opmode;
760c533a883Shx 	IEEE80211_ADDR_COPY(wd.wd_bssid, ic->ic_macaddr);
761c533a883Shx 
762c533a883Shx 	macp = mac_alloc(MAC_VERSION);
76319d332feSfei feng - Sun Microsystems - Beijing China 	if (macp == NULL) {
764c533a883Shx 		cmn_err(CE_WARN,
765c533a883Shx 		    "iwk_attach(): failed to do mac_alloc()\n");
766c533a883Shx 		goto attach_fail9;
767c533a883Shx 	}
768c533a883Shx 
769c533a883Shx 	macp->m_type_ident	= MAC_PLUGIN_IDENT_WIFI;
770c533a883Shx 	macp->m_driver		= sc;
771c533a883Shx 	macp->m_dip		= dip;
772c533a883Shx 	macp->m_src_addr	= ic->ic_macaddr;
773c533a883Shx 	macp->m_callbacks	= &iwk_m_callbacks;
774c533a883Shx 	macp->m_min_sdu		= 0;
775c533a883Shx 	macp->m_max_sdu		= IEEE80211_MTU;
776c533a883Shx 	macp->m_pdata		= &wd;
777c533a883Shx 	macp->m_pdata_size	= sizeof (wd);
778c533a883Shx 
779c533a883Shx 	/*
780c533a883Shx 	 * Register the macp to mac
781c533a883Shx 	 */
782c533a883Shx 	err = mac_register(macp, &ic->ic_mach);
783c533a883Shx 	mac_free(macp);
784c533a883Shx 	if (err != DDI_SUCCESS) {
785c533a883Shx 		cmn_err(CE_WARN,
786c533a883Shx 		    "iwk_attach(): failed to do mac_register()\n");
787c533a883Shx 		goto attach_fail9;
788c533a883Shx 	}
789c533a883Shx 
790c533a883Shx 	/*
791c533a883Shx 	 * Create minor node of type DDI_NT_NET_WIFI
792c533a883Shx 	 */
793c533a883Shx 	(void) snprintf(strbuf, sizeof (strbuf), DRV_NAME_4965"%d", instance);
794c533a883Shx 	err = ddi_create_minor_node(dip, strbuf, S_IFCHR,
795c533a883Shx 	    instance + 1, DDI_NT_NET_WIFI, 0);
796c533a883Shx 	if (err != DDI_SUCCESS)
797c533a883Shx 		cmn_err(CE_WARN,
798c533a883Shx 		    "iwk_attach(): failed to do ddi_create_minor_node()\n");
799c533a883Shx 
800c533a883Shx 	/*
801c533a883Shx 	 * Notify link is down now
802c533a883Shx 	 */
803c533a883Shx 	mac_link_update(ic->ic_mach, LINK_STATE_DOWN);
804c533a883Shx 
805c533a883Shx 	/*
806c533a883Shx 	 * create the mf thread to handle the link status,
807c533a883Shx 	 * recovery fatal error, etc.
808c533a883Shx 	 */
809c533a883Shx 	sc->sc_mf_thread_switch = 1;
810c533a883Shx 	if (sc->sc_mf_thread == NULL)
811c533a883Shx 		sc->sc_mf_thread = thread_create((caddr_t)NULL, 0,
812c533a883Shx 		    iwk_thread, sc, 0, &p0, TS_RUN, minclsyspri);
813c533a883Shx 
814c533a883Shx 	sc->sc_flags |= IWK_F_ATTACHED;
815c533a883Shx 
816c533a883Shx 	return (DDI_SUCCESS);
817c533a883Shx attach_fail9:
818cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	(void) ddi_intr_disable(sc->sc_intr_htable[0]);
819cdc64593Sxinghua wen - Sun Microsystems - Beijing China attach_fail_intr_d:
820cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	(void) ddi_intr_remove_handler(sc->sc_intr_htable[0]);
821cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
822c533a883Shx attach_fail8:
823cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	(void) ddi_intr_remove_softint(sc->sc_soft_hdl);
824cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	sc->sc_soft_hdl = NULL;
825c533a883Shx attach_fail7:
826c533a883Shx 	ieee80211_detach(ic);
827c533a883Shx attach_fail6:
828c533a883Shx 	iwk_free_fw_dma(sc);
829c533a883Shx attach_fail5:
830c533a883Shx 	iwk_ring_free(sc);
831c533a883Shx attach_fail4:
832c533a883Shx 	iwk_free_kw(sc);
833c533a883Shx attach_fail3a:
834c533a883Shx 	iwk_free_shared(sc);
835c533a883Shx attach_fail3:
836c533a883Shx 	iwk_destroy_locks(sc);
837cdc64593Sxinghua wen - Sun Microsystems - Beijing China attach_fail_intr_c:
838cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	(void) ddi_intr_free(sc->sc_intr_htable[0]);
839cdc64593Sxinghua wen - Sun Microsystems - Beijing China attach_fail_intr_b:
840cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	kmem_free(sc->sc_intr_htable, sizeof (ddi_intr_handle_t));
841cdc64593Sxinghua wen - Sun Microsystems - Beijing China attach_fail_intr_a:
842c533a883Shx 	ddi_regs_map_free(&sc->sc_handle);
843c533a883Shx attach_fail2a:
844c533a883Shx 	ddi_regs_map_free(&sc->sc_cfg_handle);
845c533a883Shx attach_fail2:
846c533a883Shx 	ddi_soft_state_free(iwk_soft_state_p, instance);
847c533a883Shx attach_fail1:
848c533a883Shx 	return (err);
849c533a883Shx }
850c533a883Shx 
851c533a883Shx int
iwk_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)852c533a883Shx iwk_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
853c533a883Shx {
854c533a883Shx 	iwk_sc_t	*sc;
855c533a883Shx 	int err;
856c533a883Shx 
857c533a883Shx 	sc = ddi_get_soft_state(iwk_soft_state_p, ddi_get_instance(dip));
858c533a883Shx 	ASSERT(sc != NULL);
859c533a883Shx 
860d62cb7ffShx 	switch (cmd) {
861d62cb7ffShx 	case DDI_DETACH:
862d62cb7ffShx 		break;
863d62cb7ffShx 	case DDI_SUSPEND:
864d62cb7ffShx 		mutex_enter(&sc->sc_glock);
865d62cb7ffShx 		sc->sc_flags |= IWK_F_SUSPEND;
866d62cb7ffShx 		mutex_exit(&sc->sc_glock);
867d40f4da4Spengcheng chen - Sun Microsystems - Beijing China 		if (sc->sc_flags & IWK_F_RUNNING) {
868d40f4da4Spengcheng chen - Sun Microsystems - Beijing China 			iwk_stop(sc);
869d40f4da4Spengcheng chen - Sun Microsystems - Beijing China 		}
870d40f4da4Spengcheng chen - Sun Microsystems - Beijing China 
871d62cb7ffShx 		IWK_DBG((IWK_DEBUG_RESUME, "iwk: suspend\n"));
872d62cb7ffShx 		return (DDI_SUCCESS);
873d62cb7ffShx 	default:
874c533a883Shx 		return (DDI_FAILURE);
875d62cb7ffShx 	}
87643439c96Shx 
877c533a883Shx 	if (!(sc->sc_flags & IWK_F_ATTACHED))
878c533a883Shx 		return (DDI_FAILURE);
879c533a883Shx 
880cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	err = mac_disable(sc->sc_ic.ic_mach);
881cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (err != DDI_SUCCESS)
882cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		return (err);
883cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
884c533a883Shx 	/*
885c533a883Shx 	 * Destroy the mf_thread
886c533a883Shx 	 */
887c533a883Shx 	mutex_enter(&sc->sc_mt_lock);
888c533a883Shx 	sc->sc_mf_thread_switch = 0;
889c533a883Shx 	while (sc->sc_mf_thread != NULL) {
890c533a883Shx 		if (cv_wait_sig(&sc->sc_mt_cv, &sc->sc_mt_lock) == 0)
891c533a883Shx 			break;
892c533a883Shx 	}
893c533a883Shx 	mutex_exit(&sc->sc_mt_lock);
894c533a883Shx 
895c533a883Shx 	iwk_stop(sc);
896c533a883Shx 	DELAY(500000);
897c533a883Shx 
898c533a883Shx 	/*
899c533a883Shx 	 * Unregiste from the MAC layer subsystem
900c533a883Shx 	 */
901cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	(void) mac_unregister(sc->sc_ic.ic_mach);
902c533a883Shx 
903c533a883Shx 	mutex_enter(&sc->sc_glock);
904c533a883Shx 	iwk_free_fw_dma(sc);
905c533a883Shx 	iwk_ring_free(sc);
906c533a883Shx 	iwk_free_kw(sc);
907c533a883Shx 	iwk_free_shared(sc);
908c533a883Shx 	mutex_exit(&sc->sc_glock);
909c533a883Shx 
910cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	(void) ddi_intr_disable(sc->sc_intr_htable[0]);
911cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	(void) ddi_intr_remove_handler(sc->sc_intr_htable[0]);
912cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	(void) ddi_intr_free(sc->sc_intr_htable[0]);
913cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	kmem_free(sc->sc_intr_htable, sizeof (ddi_intr_handle_t));
914cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
915cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	(void) ddi_intr_remove_softint(sc->sc_soft_hdl);
916cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	sc->sc_soft_hdl = NULL;
917c533a883Shx 
918c533a883Shx 	/*
919c533a883Shx 	 * detach ieee80211
920c533a883Shx 	 */
921c533a883Shx 	ieee80211_detach(&sc->sc_ic);
922c533a883Shx 
923c533a883Shx 	iwk_destroy_locks(sc);
924c533a883Shx 
925c533a883Shx 	ddi_regs_map_free(&sc->sc_handle);
926c533a883Shx 	ddi_regs_map_free(&sc->sc_cfg_handle);
927c533a883Shx 	ddi_remove_minor_node(dip, NULL);
928c533a883Shx 	ddi_soft_state_free(iwk_soft_state_p, ddi_get_instance(dip));
929c533a883Shx 
930c533a883Shx 	return (DDI_SUCCESS);
931c533a883Shx }
932c533a883Shx 
933d2a61391Spengcheng chen - Sun Microsystems - Beijing China /*
934d2a61391Spengcheng chen - Sun Microsystems - Beijing China  * quiesce(9E) entry point.
935d2a61391Spengcheng chen - Sun Microsystems - Beijing China  *
936d2a61391Spengcheng chen - Sun Microsystems - Beijing China  * This function is called when the system is single-threaded at high
937d2a61391Spengcheng chen - Sun Microsystems - Beijing China  * PIL with preemption disabled. Therefore, this function must not be
938d2a61391Spengcheng chen - Sun Microsystems - Beijing China  * blocked.
939d2a61391Spengcheng chen - Sun Microsystems - Beijing China  *
940d2a61391Spengcheng chen - Sun Microsystems - Beijing China  * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
941d2a61391Spengcheng chen - Sun Microsystems - Beijing China  * DDI_FAILURE indicates an error condition and should almost never happen.
942d2a61391Spengcheng chen - Sun Microsystems - Beijing China  */
943d2a61391Spengcheng chen - Sun Microsystems - Beijing China int
iwk_quiesce(dev_info_t * dip)944d2a61391Spengcheng chen - Sun Microsystems - Beijing China iwk_quiesce(dev_info_t *dip)
945d2a61391Spengcheng chen - Sun Microsystems - Beijing China {
946d2a61391Spengcheng chen - Sun Microsystems - Beijing China 	iwk_sc_t	*sc;
947d2a61391Spengcheng chen - Sun Microsystems - Beijing China 
948d2a61391Spengcheng chen - Sun Microsystems - Beijing China 	sc = ddi_get_soft_state(iwk_soft_state_p, ddi_get_instance(dip));
949d2a61391Spengcheng chen - Sun Microsystems - Beijing China 	ASSERT(sc != NULL);
950d2a61391Spengcheng chen - Sun Microsystems - Beijing China 
951d2a61391Spengcheng chen - Sun Microsystems - Beijing China 	/* no message prints and no lock accquisition */
952d2a61391Spengcheng chen - Sun Microsystems - Beijing China #ifdef DEBUG
953d2a61391Spengcheng chen - Sun Microsystems - Beijing China 	iwk_dbg_flags = 0;
954d2a61391Spengcheng chen - Sun Microsystems - Beijing China #endif
955d2a61391Spengcheng chen - Sun Microsystems - Beijing China 	sc->sc_flags |= IWK_F_QUIESCED;
956d2a61391Spengcheng chen - Sun Microsystems - Beijing China 
957d2a61391Spengcheng chen - Sun Microsystems - Beijing China 	iwk_stop(sc);
958d2a61391Spengcheng chen - Sun Microsystems - Beijing China 
959d2a61391Spengcheng chen - Sun Microsystems - Beijing China 	return (DDI_SUCCESS);
960d2a61391Spengcheng chen - Sun Microsystems - Beijing China }
961d2a61391Spengcheng chen - Sun Microsystems - Beijing China 
962c533a883Shx static void
iwk_destroy_locks(iwk_sc_t * sc)963c533a883Shx iwk_destroy_locks(iwk_sc_t *sc)
964c533a883Shx {
965c533a883Shx 	cv_destroy(&sc->sc_mt_cv);
966c533a883Shx 	mutex_destroy(&sc->sc_mt_lock);
967c533a883Shx 	cv_destroy(&sc->sc_tx_cv);
968c533a883Shx 	cv_destroy(&sc->sc_cmd_cv);
969c533a883Shx 	cv_destroy(&sc->sc_fw_cv);
970c533a883Shx 	mutex_destroy(&sc->sc_tx_lock);
971c533a883Shx 	mutex_destroy(&sc->sc_glock);
972c533a883Shx }
973c533a883Shx 
974c533a883Shx /*
975c533a883Shx  * Allocate an area of memory and a DMA handle for accessing it
976c533a883Shx  */
977c533a883Shx static int
iwk_alloc_dma_mem(iwk_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,iwk_dma_t * dma_p)978c533a883Shx iwk_alloc_dma_mem(iwk_sc_t *sc, size_t memsize,
979c533a883Shx     ddi_dma_attr_t *dma_attr_p, ddi_device_acc_attr_t *acc_attr_p,
980c533a883Shx     uint_t dma_flags, iwk_dma_t *dma_p)
981c533a883Shx {
982c533a883Shx 	caddr_t vaddr;
983c533a883Shx 	int err;
984c533a883Shx 
985c533a883Shx 	/*
986c533a883Shx 	 * Allocate handle
987c533a883Shx 	 */
988c533a883Shx 	err = ddi_dma_alloc_handle(sc->sc_dip, dma_attr_p,
989c533a883Shx 	    DDI_DMA_SLEEP, NULL, &dma_p->dma_hdl);
990c533a883Shx 	if (err != DDI_SUCCESS) {
991c533a883Shx 		dma_p->dma_hdl = NULL;
992c533a883Shx 		return (DDI_FAILURE);
993c533a883Shx 	}
994c533a883Shx 
995c533a883Shx 	/*
996c533a883Shx 	 * Allocate memory
997c533a883Shx 	 */
998c533a883Shx 	err = ddi_dma_mem_alloc(dma_p->dma_hdl, memsize, acc_attr_p,
999c533a883Shx 	    dma_flags & (DDI_DMA_CONSISTENT | DDI_DMA_STREAMING),
1000c533a883Shx 	    DDI_DMA_SLEEP, NULL, &vaddr, &dma_p->alength, &dma_p->acc_hdl);
1001c533a883Shx 	if (err != DDI_SUCCESS) {
1002c533a883Shx 		ddi_dma_free_handle(&dma_p->dma_hdl);
1003c533a883Shx 		dma_p->dma_hdl = NULL;
1004c533a883Shx 		dma_p->acc_hdl = NULL;
1005c533a883Shx 		return (DDI_FAILURE);
1006c533a883Shx 	}
1007c533a883Shx 
1008c533a883Shx 	/*
1009c533a883Shx 	 * Bind the two together
1010c533a883Shx 	 */
1011c533a883Shx 	dma_p->mem_va = vaddr;
1012c533a883Shx 	err = ddi_dma_addr_bind_handle(dma_p->dma_hdl, NULL,
1013c533a883Shx 	    vaddr, dma_p->alength, dma_flags, DDI_DMA_SLEEP, NULL,
1014c533a883Shx 	    &dma_p->cookie, &dma_p->ncookies);
1015c533a883Shx 	if (err != DDI_DMA_MAPPED) {
1016c533a883Shx 		ddi_dma_mem_free(&dma_p->acc_hdl);
1017c533a883Shx 		ddi_dma_free_handle(&dma_p->dma_hdl);
1018c533a883Shx 		dma_p->acc_hdl = NULL;
1019c533a883Shx 		dma_p->dma_hdl = NULL;
1020c533a883Shx 		return (DDI_FAILURE);
1021c533a883Shx 	}
1022c533a883Shx 
1023c533a883Shx 	dma_p->nslots = ~0U;
1024c533a883Shx 	dma_p->size = ~0U;
1025c533a883Shx 	dma_p->token = ~0U;
1026c533a883Shx 	dma_p->offset = 0;
1027c533a883Shx 	return (DDI_SUCCESS);
1028c533a883Shx }
1029c533a883Shx 
1030c533a883Shx /*
1031c533a883Shx  * Free one allocated area of DMAable memory
1032c533a883Shx  */
1033c533a883Shx static void
iwk_free_dma_mem(iwk_dma_t * dma_p)1034c533a883Shx iwk_free_dma_mem(iwk_dma_t *dma_p)
1035c533a883Shx {
1036c533a883Shx 	if (dma_p->dma_hdl != NULL) {
1037c533a883Shx 		if (dma_p->ncookies) {
1038c533a883Shx 			(void) ddi_dma_unbind_handle(dma_p->dma_hdl);
1039c533a883Shx 			dma_p->ncookies = 0;
1040c533a883Shx 		}
1041c533a883Shx 		ddi_dma_free_handle(&dma_p->dma_hdl);
1042c533a883Shx 		dma_p->dma_hdl = NULL;
1043c533a883Shx 	}
1044c533a883Shx 
1045c533a883Shx 	if (dma_p->acc_hdl != NULL) {
1046c533a883Shx 		ddi_dma_mem_free(&dma_p->acc_hdl);
1047c533a883Shx 		dma_p->acc_hdl = NULL;
1048c533a883Shx 	}
1049c533a883Shx }
1050c533a883Shx 
1051c533a883Shx /*
1052c533a883Shx  *
1053c533a883Shx  */
1054c533a883Shx static int
iwk_alloc_fw_dma(iwk_sc_t * sc)1055c533a883Shx iwk_alloc_fw_dma(iwk_sc_t *sc)
1056c533a883Shx {
1057c533a883Shx 	int err = DDI_SUCCESS;
1058c533a883Shx 	iwk_dma_t *dma_p;
1059c533a883Shx 	char *t;
1060c533a883Shx 
1061c533a883Shx 	/*
1062c533a883Shx 	 * firmware image layout:
1063c533a883Shx 	 * |HDR|<-TEXT->|<-DATA->|<-INIT_TEXT->|<-INIT_DATA->|<-BOOT->|
1064c533a883Shx 	 */
1065c533a883Shx 	t = (char *)(sc->sc_hdr + 1);
1066c533a883Shx 	err = iwk_alloc_dma_mem(sc, LE_32(sc->sc_hdr->textsz),
1067c533a883Shx 	    &fw_dma_attr, &iwk_dma_accattr,
1068c533a883Shx 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1069c533a883Shx 	    &sc->sc_dma_fw_text);
1070c533a883Shx 	dma_p = &sc->sc_dma_fw_text;
1071c533a883Shx 	IWK_DBG((IWK_DEBUG_DMA, "text[ncookies:%d addr:%lx size:%lx]\n",
1072c533a883Shx 	    dma_p->ncookies, dma_p->cookie.dmac_address,
1073c533a883Shx 	    dma_p->cookie.dmac_size));
1074c533a883Shx 	if (err != DDI_SUCCESS) {
1075c533a883Shx 		cmn_err(CE_WARN, "iwk_alloc_fw_dma(): failed to alloc"
1076c533a883Shx 		    " text dma memory");
1077c533a883Shx 		goto fail;
1078c533a883Shx 	}
1079c533a883Shx 	(void) memcpy(dma_p->mem_va, t, LE_32(sc->sc_hdr->textsz));
1080c533a883Shx 
1081c533a883Shx 	t += LE_32(sc->sc_hdr->textsz);
1082c533a883Shx 	err = iwk_alloc_dma_mem(sc, LE_32(sc->sc_hdr->datasz),
1083c533a883Shx 	    &fw_dma_attr, &iwk_dma_accattr,
1084c533a883Shx 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1085c533a883Shx 	    &sc->sc_dma_fw_data);
1086c533a883Shx 	dma_p = &sc->sc_dma_fw_data;
1087c533a883Shx 	IWK_DBG((IWK_DEBUG_DMA, "data[ncookies:%d addr:%lx size:%lx]\n",
1088c533a883Shx 	    dma_p->ncookies, dma_p->cookie.dmac_address,
1089c533a883Shx 	    dma_p->cookie.dmac_size));
1090c533a883Shx 	if (err != DDI_SUCCESS) {
1091c533a883Shx 		cmn_err(CE_WARN, "iwk_alloc_fw_dma(): failed to alloc"
1092c533a883Shx 		    " data dma memory");
1093c533a883Shx 		goto fail;
1094c533a883Shx 	}
1095c533a883Shx 	(void) memcpy(dma_p->mem_va, t, LE_32(sc->sc_hdr->datasz));
1096c533a883Shx 
1097c533a883Shx 	err = iwk_alloc_dma_mem(sc, LE_32(sc->sc_hdr->datasz),
1098c533a883Shx 	    &fw_dma_attr, &iwk_dma_accattr,
1099c533a883Shx 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1100c533a883Shx 	    &sc->sc_dma_fw_data_bak);
1101c533a883Shx 	dma_p = &sc->sc_dma_fw_data_bak;
1102c533a883Shx 	IWK_DBG((IWK_DEBUG_DMA, "data_bak[ncookies:%d addr:%lx "
1103c533a883Shx 	    "size:%lx]\n",
1104c533a883Shx 	    dma_p->ncookies, dma_p->cookie.dmac_address,
1105c533a883Shx 	    dma_p->cookie.dmac_size));
1106c533a883Shx 	if (err != DDI_SUCCESS) {
1107c533a883Shx 		cmn_err(CE_WARN, "iwk_alloc_fw_dma(): failed to alloc"
1108c533a883Shx 		    " data bakeup dma memory");
1109c533a883Shx 		goto fail;
1110c533a883Shx 	}
1111c533a883Shx 	(void) memcpy(dma_p->mem_va, t, LE_32(sc->sc_hdr->datasz));
1112c533a883Shx 
1113c533a883Shx 	t += LE_32(sc->sc_hdr->datasz);
1114c533a883Shx 	err = iwk_alloc_dma_mem(sc, LE_32(sc->sc_hdr->init_textsz),
1115c533a883Shx 	    &fw_dma_attr, &iwk_dma_accattr,
1116c533a883Shx 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1117c533a883Shx 	    &sc->sc_dma_fw_init_text);
1118c533a883Shx 	dma_p = &sc->sc_dma_fw_init_text;
1119c533a883Shx 	IWK_DBG((IWK_DEBUG_DMA, "init_text[ncookies:%d addr:%lx "
1120c533a883Shx 	    "size:%lx]\n",
1121c533a883Shx 	    dma_p->ncookies, dma_p->cookie.dmac_address,
1122c533a883Shx 	    dma_p->cookie.dmac_size));
1123c533a883Shx 	if (err != DDI_SUCCESS) {
1124c533a883Shx 		cmn_err(CE_WARN, "iwk_alloc_fw_dma(): failed to alloc"
1125c533a883Shx 		    "init text dma memory");
1126c533a883Shx 		goto fail;
1127c533a883Shx 	}
1128c533a883Shx 	(void) memcpy(dma_p->mem_va, t, LE_32(sc->sc_hdr->init_textsz));
1129c533a883Shx 
1130c533a883Shx 	t += LE_32(sc->sc_hdr->init_textsz);
1131c533a883Shx 	err = iwk_alloc_dma_mem(sc, LE_32(sc->sc_hdr->init_datasz),
1132c533a883Shx 	    &fw_dma_attr, &iwk_dma_accattr,
1133c533a883Shx 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1134c533a883Shx 	    &sc->sc_dma_fw_init_data);
1135c533a883Shx 	dma_p = &sc->sc_dma_fw_init_data;
1136c533a883Shx 	IWK_DBG((IWK_DEBUG_DMA, "init_data[ncookies:%d addr:%lx "
1137c533a883Shx 	    "size:%lx]\n",
1138c533a883Shx 	    dma_p->ncookies, dma_p->cookie.dmac_address,
1139c533a883Shx 	    dma_p->cookie.dmac_size));
1140c533a883Shx 	if (err != DDI_SUCCESS) {
1141c533a883Shx 		cmn_err(CE_WARN, "iwk_alloc_fw_dma(): failed to alloc"
1142c533a883Shx 		    "init data dma memory");
1143c533a883Shx 		goto fail;
1144c533a883Shx 	}
1145c533a883Shx 	(void) memcpy(dma_p->mem_va, t, LE_32(sc->sc_hdr->init_datasz));
1146c533a883Shx 
1147c533a883Shx 	sc->sc_boot = t + LE_32(sc->sc_hdr->init_datasz);
1148c533a883Shx fail:
1149c533a883Shx 	return (err);
1150c533a883Shx }
1151c533a883Shx 
1152c533a883Shx static void
iwk_free_fw_dma(iwk_sc_t * sc)1153c533a883Shx iwk_free_fw_dma(iwk_sc_t *sc)
1154c533a883Shx {
1155c533a883Shx 	iwk_free_dma_mem(&sc->sc_dma_fw_text);
1156c533a883Shx 	iwk_free_dma_mem(&sc->sc_dma_fw_data);
1157c533a883Shx 	iwk_free_dma_mem(&sc->sc_dma_fw_data_bak);
1158c533a883Shx 	iwk_free_dma_mem(&sc->sc_dma_fw_init_text);
1159c533a883Shx 	iwk_free_dma_mem(&sc->sc_dma_fw_init_data);
1160c533a883Shx }
1161c533a883Shx 
1162c533a883Shx /*
1163c533a883Shx  * Allocate a shared page between host and NIC.
1164c533a883Shx  */
1165c533a883Shx static int
iwk_alloc_shared(iwk_sc_t * sc)1166c533a883Shx iwk_alloc_shared(iwk_sc_t *sc)
1167c533a883Shx {
1168c533a883Shx 	iwk_dma_t *dma_p;
1169c533a883Shx 	int err = DDI_SUCCESS;
1170c533a883Shx 
1171c533a883Shx 	/* must be aligned on a 4K-page boundary */
1172c533a883Shx 	err = iwk_alloc_dma_mem(sc, sizeof (iwk_shared_t),
1173b510adaeSfei feng - Sun Microsystems - Beijing China 	    &sh_dma_attr, &iwk_dma_descattr,
1174c533a883Shx 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1175c533a883Shx 	    &sc->sc_dma_sh);
1176c533a883Shx 	if (err != DDI_SUCCESS)
1177c533a883Shx 		goto fail;
1178c533a883Shx 	sc->sc_shared = (iwk_shared_t *)sc->sc_dma_sh.mem_va;
1179c533a883Shx 
1180c533a883Shx 	dma_p = &sc->sc_dma_sh;
1181c533a883Shx 	IWK_DBG((IWK_DEBUG_DMA, "sh[ncookies:%d addr:%lx size:%lx]\n",
1182c533a883Shx 	    dma_p->ncookies, dma_p->cookie.dmac_address,
1183c533a883Shx 	    dma_p->cookie.dmac_size));
1184c533a883Shx 
1185c533a883Shx 	return (err);
1186c533a883Shx fail:
1187c533a883Shx 	iwk_free_shared(sc);
1188c533a883Shx 	return (err);
1189c533a883Shx }
1190c533a883Shx 
1191c533a883Shx static void
iwk_free_shared(iwk_sc_t * sc)1192c533a883Shx iwk_free_shared(iwk_sc_t *sc)
1193c533a883Shx {
1194c533a883Shx 	iwk_free_dma_mem(&sc->sc_dma_sh);
1195c533a883Shx }
1196c533a883Shx 
1197c533a883Shx /*
1198c533a883Shx  * Allocate a keep warm page.
1199c533a883Shx  */
1200c533a883Shx static int
iwk_alloc_kw(iwk_sc_t * sc)1201c533a883Shx iwk_alloc_kw(iwk_sc_t *sc)
1202c533a883Shx {
1203c533a883Shx 	iwk_dma_t *dma_p;
1204c533a883Shx 	int err = DDI_SUCCESS;
1205c533a883Shx 
1206c533a883Shx 	/* must be aligned on a 4K-page boundary */
1207c533a883Shx 	err = iwk_alloc_dma_mem(sc, IWK_KW_SIZE,
1208c533a883Shx 	    &kw_dma_attr, &iwk_dma_accattr,
1209c533a883Shx 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1210c533a883Shx 	    &sc->sc_dma_kw);
1211c533a883Shx 	if (err != DDI_SUCCESS)
1212c533a883Shx 		goto fail;
1213c533a883Shx 
1214c533a883Shx 	dma_p = &sc->sc_dma_kw;
1215c533a883Shx 	IWK_DBG((IWK_DEBUG_DMA, "kw[ncookies:%d addr:%lx size:%lx]\n",
1216c533a883Shx 	    dma_p->ncookies, dma_p->cookie.dmac_address,
1217c533a883Shx 	    dma_p->cookie.dmac_size));
1218c533a883Shx 
1219c533a883Shx 	return (err);
1220c533a883Shx fail:
1221c533a883Shx 	iwk_free_kw(sc);
1222c533a883Shx 	return (err);
1223c533a883Shx }
1224c533a883Shx 
1225c533a883Shx static void
iwk_free_kw(iwk_sc_t * sc)1226c533a883Shx iwk_free_kw(iwk_sc_t *sc)
1227c533a883Shx {
1228c533a883Shx 	iwk_free_dma_mem(&sc->sc_dma_kw);
1229c533a883Shx }
1230c533a883Shx 
1231c533a883Shx static int
iwk_alloc_rx_ring(iwk_sc_t * sc)1232c533a883Shx iwk_alloc_rx_ring(iwk_sc_t *sc)
1233c533a883Shx {
1234c533a883Shx 	iwk_rx_ring_t *ring;
1235c533a883Shx 	iwk_rx_data_t *data;
1236c533a883Shx 	iwk_dma_t *dma_p;
1237c533a883Shx 	int i, err = DDI_SUCCESS;
1238c533a883Shx 
1239c533a883Shx 	ring = &sc->sc_rxq;
1240c533a883Shx 	ring->cur = 0;
1241c533a883Shx 
1242c533a883Shx 	err = iwk_alloc_dma_mem(sc, RX_QUEUE_SIZE * sizeof (uint32_t),
1243b510adaeSfei feng - Sun Microsystems - Beijing China 	    &ring_desc_dma_attr, &iwk_dma_descattr,
1244c533a883Shx 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1245c533a883Shx 	    &ring->dma_desc);
1246c533a883Shx 	if (err != DDI_SUCCESS) {
1247c50ced99Spengcheng chen - Sun Microsystems - Beijing China 		cmn_err(CE_WARN, "dma alloc rx ring desc failed\n");
1248c533a883Shx 		goto fail;
1249c533a883Shx 	}
1250c533a883Shx 	ring->desc = (uint32_t *)ring->dma_desc.mem_va;
1251c533a883Shx 	dma_p = &ring->dma_desc;
1252c533a883Shx 	IWK_DBG((IWK_DEBUG_DMA, "rx bd[ncookies:%d addr:%lx size:%lx]\n",
1253c533a883Shx 	    dma_p->ncookies, dma_p->cookie.dmac_address,
1254c533a883Shx 	    dma_p->cookie.dmac_size));
1255c533a883Shx 
1256c533a883Shx 	/*
1257c533a883Shx 	 * Allocate Rx buffers.
1258c533a883Shx 	 */
1259c533a883Shx 	for (i = 0; i < RX_QUEUE_SIZE; i++) {
1260c533a883Shx 		data = &ring->data[i];
1261c533a883Shx 		err = iwk_alloc_dma_mem(sc, sc->sc_dmabuf_sz,
1262c533a883Shx 		    &rx_buffer_dma_attr, &iwk_dma_accattr,
1263c533a883Shx 		    DDI_DMA_READ | DDI_DMA_STREAMING,
1264c533a883Shx 		    &data->dma_data);
1265c533a883Shx 		if (err != DDI_SUCCESS) {
1266c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			cmn_err(CE_WARN, "dma alloc rx ring buf[%d] "
1267c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			    "failed\n", i);
1268c533a883Shx 			goto fail;
1269c533a883Shx 		}
1270c533a883Shx 		/*
1271c533a883Shx 		 * the physical address bit [8-36] are used,
1272c533a883Shx 		 * instead of bit [0-31] in 3945.
1273c533a883Shx 		 */
1274b510adaeSfei feng - Sun Microsystems - Beijing China 		ring->desc[i] = (uint32_t)
1275b510adaeSfei feng - Sun Microsystems - Beijing China 		    (data->dma_data.cookie.dmac_address >> 8);
1276c533a883Shx 	}
1277c533a883Shx 	dma_p = &ring->data[0].dma_data;
1278c533a883Shx 	IWK_DBG((IWK_DEBUG_DMA, "rx buffer[0][ncookies:%d addr:%lx "
1279c533a883Shx 	    "size:%lx]\n",
1280c533a883Shx 	    dma_p->ncookies, dma_p->cookie.dmac_address,
1281c533a883Shx 	    dma_p->cookie.dmac_size));
1282c533a883Shx 
1283c533a883Shx 	IWK_DMA_SYNC(ring->dma_desc, DDI_DMA_SYNC_FORDEV);
1284c533a883Shx 
1285c533a883Shx 	return (err);
1286c533a883Shx 
1287c533a883Shx fail:
1288c533a883Shx 	iwk_free_rx_ring(sc);
1289c533a883Shx 	return (err);
1290c533a883Shx }
1291c533a883Shx 
1292c533a883Shx static void
iwk_reset_rx_ring(iwk_sc_t * sc)1293c533a883Shx iwk_reset_rx_ring(iwk_sc_t *sc)
1294c533a883Shx {
1295c533a883Shx 	int n;
1296c533a883Shx 
1297c533a883Shx 	iwk_mac_access_enter(sc);
1298c533a883Shx 	IWK_WRITE(sc, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
1299c533a883Shx 	for (n = 0; n < 2000; n++) {
1300c533a883Shx 		if (IWK_READ(sc, FH_MEM_RSSR_RX_STATUS_REG) & (1 << 24))
1301c533a883Shx 			break;
1302c533a883Shx 		DELAY(1000);
1303c533a883Shx 	}
1304d2a61391Spengcheng chen - Sun Microsystems - Beijing China 
1305c533a883Shx 	if (n == 2000)
1306c533a883Shx 		IWK_DBG((IWK_DEBUG_DMA, "timeout resetting Rx ring\n"));
1307d2a61391Spengcheng chen - Sun Microsystems - Beijing China 
1308c533a883Shx 	iwk_mac_access_exit(sc);
1309c533a883Shx 
1310c533a883Shx 	sc->sc_rxq.cur = 0;
1311c533a883Shx }
1312c533a883Shx 
1313c533a883Shx static void
iwk_free_rx_ring(iwk_sc_t * sc)1314c533a883Shx iwk_free_rx_ring(iwk_sc_t *sc)
1315c533a883Shx {
1316c533a883Shx 	int i;
1317c533a883Shx 
1318c533a883Shx 	for (i = 0; i < RX_QUEUE_SIZE; i++) {
1319c533a883Shx 		if (sc->sc_rxq.data[i].dma_data.dma_hdl)
1320c533a883Shx 			IWK_DMA_SYNC(sc->sc_rxq.data[i].dma_data,
1321c533a883Shx 			    DDI_DMA_SYNC_FORCPU);
1322c533a883Shx 		iwk_free_dma_mem(&sc->sc_rxq.data[i].dma_data);
1323c533a883Shx 	}
1324c533a883Shx 
1325c533a883Shx 	if (sc->sc_rxq.dma_desc.dma_hdl)
1326c533a883Shx 		IWK_DMA_SYNC(sc->sc_rxq.dma_desc, DDI_DMA_SYNC_FORDEV);
1327c533a883Shx 	iwk_free_dma_mem(&sc->sc_rxq.dma_desc);
1328c533a883Shx }
1329c533a883Shx 
1330c533a883Shx static int
iwk_alloc_tx_ring(iwk_sc_t * sc,iwk_tx_ring_t * ring,int slots,int qid)1331c533a883Shx iwk_alloc_tx_ring(iwk_sc_t *sc, iwk_tx_ring_t *ring,
1332c533a883Shx     int slots, int qid)
1333c533a883Shx {
1334c533a883Shx 	iwk_tx_data_t *data;
1335c533a883Shx 	iwk_tx_desc_t *desc_h;
1336c533a883Shx 	uint32_t paddr_desc_h;
1337c533a883Shx 	iwk_cmd_t *cmd_h;
1338c533a883Shx 	uint32_t paddr_cmd_h;
1339c533a883Shx 	iwk_dma_t *dma_p;
1340c533a883Shx 	int i, err = DDI_SUCCESS;
1341c533a883Shx 
1342c533a883Shx 	ring->qid = qid;
1343c533a883Shx 	ring->count = TFD_QUEUE_SIZE_MAX;
1344c533a883Shx 	ring->window = slots;
1345c533a883Shx 	ring->queued = 0;
1346c533a883Shx 	ring->cur = 0;
1347c533a883Shx 
1348c533a883Shx 	err = iwk_alloc_dma_mem(sc,
1349c533a883Shx 	    TFD_QUEUE_SIZE_MAX * sizeof (iwk_tx_desc_t),
1350b510adaeSfei feng - Sun Microsystems - Beijing China 	    &ring_desc_dma_attr, &iwk_dma_descattr,
1351c533a883Shx 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1352c533a883Shx 	    &ring->dma_desc);
1353c533a883Shx 	if (err != DDI_SUCCESS) {
1354c50ced99Spengcheng chen - Sun Microsystems - Beijing China 		cmn_err(CE_WARN, "dma alloc tx ring desc[%d] "
1355c50ced99Spengcheng chen - Sun Microsystems - Beijing China 		    "failed\n", qid);
1356c533a883Shx 		goto fail;
1357c533a883Shx 	}
1358c533a883Shx 	dma_p = &ring->dma_desc;
1359c533a883Shx 	IWK_DBG((IWK_DEBUG_DMA, "tx bd[ncookies:%d addr:%lx size:%lx]\n",
1360c533a883Shx 	    dma_p->ncookies, dma_p->cookie.dmac_address,
1361c533a883Shx 	    dma_p->cookie.dmac_size));
1362c533a883Shx 
1363c533a883Shx 	desc_h = (iwk_tx_desc_t *)ring->dma_desc.mem_va;
1364c533a883Shx 	paddr_desc_h = ring->dma_desc.cookie.dmac_address;
1365c533a883Shx 
1366c533a883Shx 	err = iwk_alloc_dma_mem(sc,
1367c533a883Shx 	    TFD_QUEUE_SIZE_MAX * sizeof (iwk_cmd_t),
1368c533a883Shx 	    &cmd_dma_attr, &iwk_dma_accattr,
1369c533a883Shx 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1370c533a883Shx 	    &ring->dma_cmd);
1371c533a883Shx 	if (err != DDI_SUCCESS) {
1372c50ced99Spengcheng chen - Sun Microsystems - Beijing China 		cmn_err(CE_WARN, "dma alloc tx ring cmd[%d] "
1373c50ced99Spengcheng chen - Sun Microsystems - Beijing China 		    "failed\n", qid);
1374c533a883Shx 		goto fail;
1375c533a883Shx 	}
1376c533a883Shx 	dma_p = &ring->dma_cmd;
1377c533a883Shx 	IWK_DBG((IWK_DEBUG_DMA, "tx cmd[ncookies:%d addr:%lx size:%lx]\n",
1378c533a883Shx 	    dma_p->ncookies, dma_p->cookie.dmac_address,
1379c533a883Shx 	    dma_p->cookie.dmac_size));
1380c533a883Shx 
1381c533a883Shx 	cmd_h = (iwk_cmd_t *)ring->dma_cmd.mem_va;
1382c533a883Shx 	paddr_cmd_h = ring->dma_cmd.cookie.dmac_address;
1383c533a883Shx 
1384c533a883Shx 	/*
1385c533a883Shx 	 * Allocate Tx buffers.
1386c533a883Shx 	 */
1387c533a883Shx 	ring->data = kmem_zalloc(sizeof (iwk_tx_data_t) * TFD_QUEUE_SIZE_MAX,
1388c533a883Shx 	    KM_NOSLEEP);
1389c533a883Shx 	if (ring->data == NULL) {
1390c50ced99Spengcheng chen - Sun Microsystems - Beijing China 		cmn_err(CE_WARN, "could not allocate tx data slots\n");
1391c533a883Shx 		goto fail;
1392c533a883Shx 	}
1393c533a883Shx 
1394c533a883Shx 	for (i = 0; i < TFD_QUEUE_SIZE_MAX; i++) {
1395c533a883Shx 		data = &ring->data[i];
1396c533a883Shx 		err = iwk_alloc_dma_mem(sc, sc->sc_dmabuf_sz,
1397c533a883Shx 		    &tx_buffer_dma_attr, &iwk_dma_accattr,
1398c533a883Shx 		    DDI_DMA_WRITE | DDI_DMA_STREAMING,
1399c533a883Shx 		    &data->dma_data);
1400c533a883Shx 		if (err != DDI_SUCCESS) {
1401c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			cmn_err(CE_WARN, "dma alloc tx ring "
1402c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			    "buf[%d] failed\n", i);
1403c533a883Shx 			goto fail;
1404c533a883Shx 		}
1405c533a883Shx 
1406c533a883Shx 		data->desc = desc_h + i;
1407c533a883Shx 		data->paddr_desc = paddr_desc_h +
1408ff3124efSff 		    _PTRDIFF(data->desc, desc_h);
1409c533a883Shx 		data->cmd = cmd_h +  i; /* (i % slots); */
1410cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		/* ((i % slots) * sizeof (iwk_cmd_t)); */
1411c533a883Shx 		data->paddr_cmd = paddr_cmd_h +
1412ff3124efSff 		    _PTRDIFF(data->cmd, cmd_h);
1413c533a883Shx 	}
1414c533a883Shx 	dma_p = &ring->data[0].dma_data;
1415c533a883Shx 	IWK_DBG((IWK_DEBUG_DMA, "tx buffer[0][ncookies:%d addr:%lx "
1416c533a883Shx 	    "size:%lx]\n",
1417c533a883Shx 	    dma_p->ncookies, dma_p->cookie.dmac_address,
1418c533a883Shx 	    dma_p->cookie.dmac_size));
1419c533a883Shx 
1420c533a883Shx 	return (err);
1421c533a883Shx 
1422c533a883Shx fail:
1423c533a883Shx 	if (ring->data)
1424c533a883Shx 		kmem_free(ring->data,
1425c533a883Shx 		    sizeof (iwk_tx_data_t) * TFD_QUEUE_SIZE_MAX);
1426c533a883Shx 	iwk_free_tx_ring(sc, ring);
1427c533a883Shx 	return (err);
1428c533a883Shx }
1429c533a883Shx 
1430c533a883Shx static void
iwk_reset_tx_ring(iwk_sc_t * sc,iwk_tx_ring_t * ring)1431c533a883Shx iwk_reset_tx_ring(iwk_sc_t *sc, iwk_tx_ring_t *ring)
1432c533a883Shx {
1433c533a883Shx 	iwk_tx_data_t *data;
1434c533a883Shx 	int i, n;
1435c533a883Shx 
1436c533a883Shx 	iwk_mac_access_enter(sc);
1437c533a883Shx 
1438c533a883Shx 	IWK_WRITE(sc, IWK_FH_TCSR_CHNL_TX_CONFIG_REG(ring->qid), 0);
1439c533a883Shx 	for (n = 0; n < 200; n++) {
1440c533a883Shx 		if (IWK_READ(sc, IWK_FH_TSSR_TX_STATUS_REG) &
1441c533a883Shx 		    IWK_FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ring->qid))
1442c533a883Shx 			break;
1443c533a883Shx 		DELAY(10);
1444c533a883Shx 	}
1445c50ced99Spengcheng chen - Sun Microsystems - Beijing China 	if (n == 200) {
1446c533a883Shx 		IWK_DBG((IWK_DEBUG_DMA, "timeout reset tx ring %d\n",
1447c533a883Shx 		    ring->qid));
1448c533a883Shx 	}
1449c533a883Shx 	iwk_mac_access_exit(sc);
1450c533a883Shx 
1451c533a883Shx 	for (i = 0; i < ring->count; i++) {
1452c533a883Shx 		data = &ring->data[i];
1453c533a883Shx 		IWK_DMA_SYNC(data->dma_data, DDI_DMA_SYNC_FORDEV);
1454c533a883Shx 	}
1455c533a883Shx 
1456c533a883Shx 	ring->queued = 0;
1457c533a883Shx 	ring->cur = 0;
1458c533a883Shx }
1459c533a883Shx 
1460c533a883Shx /*ARGSUSED*/
1461c533a883Shx static void
iwk_free_tx_ring(iwk_sc_t * sc,iwk_tx_ring_t * ring)1462c533a883Shx iwk_free_tx_ring(iwk_sc_t *sc, iwk_tx_ring_t *ring)
1463c533a883Shx {
1464c533a883Shx 	int i;
1465c533a883Shx 
1466c533a883Shx 	if (ring->dma_desc.dma_hdl != NULL)
1467c533a883Shx 		IWK_DMA_SYNC(ring->dma_desc, DDI_DMA_SYNC_FORDEV);
1468c533a883Shx 	iwk_free_dma_mem(&ring->dma_desc);
1469c533a883Shx 
1470c533a883Shx 	if (ring->dma_cmd.dma_hdl != NULL)
1471c533a883Shx 		IWK_DMA_SYNC(ring->dma_cmd, DDI_DMA_SYNC_FORDEV);
1472c533a883Shx 	iwk_free_dma_mem(&ring->dma_cmd);
1473c533a883Shx 
1474c533a883Shx 	if (ring->data != NULL) {
1475c533a883Shx 		for (i = 0; i < ring->count; i++) {
1476c533a883Shx 			if (ring->data[i].dma_data.dma_hdl)
1477c533a883Shx 				IWK_DMA_SYNC(ring->data[i].dma_data,
1478c533a883Shx 				    DDI_DMA_SYNC_FORDEV);
1479c533a883Shx 			iwk_free_dma_mem(&ring->data[i].dma_data);
1480c533a883Shx 		}
1481c533a883Shx 		kmem_free(ring->data, ring->count * sizeof (iwk_tx_data_t));
1482c533a883Shx 	}
1483c533a883Shx }
1484c533a883Shx 
1485c533a883Shx static int
iwk_ring_init(iwk_sc_t * sc)1486c533a883Shx iwk_ring_init(iwk_sc_t *sc)
1487c533a883Shx {
1488c533a883Shx 	int i, err = DDI_SUCCESS;
1489c533a883Shx 
1490c533a883Shx 	for (i = 0; i < IWK_NUM_QUEUES; i++) {
1491c533a883Shx 		if (i == IWK_CMD_QUEUE_NUM)
1492c533a883Shx 			continue;
1493c533a883Shx 		err = iwk_alloc_tx_ring(sc, &sc->sc_txq[i], TFD_TX_CMD_SLOTS,
1494c533a883Shx 		    i);
1495c533a883Shx 		if (err != DDI_SUCCESS)
1496c533a883Shx 			goto fail;
1497c533a883Shx 	}
1498c533a883Shx 	err = iwk_alloc_tx_ring(sc, &sc->sc_txq[IWK_CMD_QUEUE_NUM],
1499c533a883Shx 	    TFD_CMD_SLOTS, IWK_CMD_QUEUE_NUM);
1500c533a883Shx 	if (err != DDI_SUCCESS)
1501c533a883Shx 		goto fail;
1502c533a883Shx 	err = iwk_alloc_rx_ring(sc);
1503c533a883Shx 	if (err != DDI_SUCCESS)
1504c533a883Shx 		goto fail;
1505c533a883Shx 	return (err);
1506c533a883Shx 
1507c533a883Shx fail:
1508c533a883Shx 	return (err);
1509c533a883Shx }
1510c533a883Shx 
1511c533a883Shx static void
iwk_ring_free(iwk_sc_t * sc)1512c533a883Shx iwk_ring_free(iwk_sc_t *sc)
1513c533a883Shx {
1514c533a883Shx 	int i = IWK_NUM_QUEUES;
1515c533a883Shx 
1516c533a883Shx 	iwk_free_rx_ring(sc);
1517c533a883Shx 	while (--i >= 0) {
1518c533a883Shx 		iwk_free_tx_ring(sc, &sc->sc_txq[i]);
1519c533a883Shx 	}
1520c533a883Shx }
1521c533a883Shx 
152243439c96Shx /* ARGSUSED */
152343439c96Shx static ieee80211_node_t *
iwk_node_alloc(ieee80211com_t * ic)152443439c96Shx iwk_node_alloc(ieee80211com_t *ic)
152543439c96Shx {
152643439c96Shx 	iwk_amrr_t *amrr;
152743439c96Shx 
152843439c96Shx 	amrr = kmem_zalloc(sizeof (iwk_amrr_t), KM_SLEEP);
152943439c96Shx 	if (amrr != NULL)
153043439c96Shx 		iwk_amrr_init(amrr);
153143439c96Shx 	return (&amrr->in);
153243439c96Shx }
153343439c96Shx 
153443439c96Shx static void
iwk_node_free(ieee80211_node_t * in)153543439c96Shx iwk_node_free(ieee80211_node_t *in)
153643439c96Shx {
153743439c96Shx 	ieee80211com_t *ic = in->in_ic;
153843439c96Shx 
153943439c96Shx 	ic->ic_node_cleanup(in);
154043439c96Shx 	if (in->in_wpa_ie != NULL)
154143439c96Shx 		ieee80211_free(in->in_wpa_ie);
154243439c96Shx 	kmem_free(in, sizeof (iwk_amrr_t));
154343439c96Shx }
154443439c96Shx 
1545c533a883Shx /*ARGSUSED*/
1546c533a883Shx static int
iwk_newstate(ieee80211com_t * ic,enum ieee80211_state nstate,int arg)1547c533a883Shx iwk_newstate(ieee80211com_t *ic, enum ieee80211_state nstate, int arg)
1548c533a883Shx {
1549c533a883Shx 	iwk_sc_t *sc = (iwk_sc_t *)ic;
155043439c96Shx 	ieee80211_node_t *in = ic->ic_bss;
1551c533a883Shx 	enum ieee80211_state ostate = ic->ic_state;
1552c533a883Shx 	int i, err = IWK_SUCCESS;
1553c533a883Shx 
1554c533a883Shx 	mutex_enter(&sc->sc_glock);
1555c533a883Shx 	switch (nstate) {
1556c533a883Shx 	case IEEE80211_S_SCAN:
1557c50ced99Spengcheng chen - Sun Microsystems - Beijing China 		switch (ostate) {
1558c50ced99Spengcheng chen - Sun Microsystems - Beijing China 		case IEEE80211_S_INIT:
1559c50ced99Spengcheng chen - Sun Microsystems - Beijing China 		{
1560c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			iwk_add_sta_t node;
1561c50ced99Spengcheng chen - Sun Microsystems - Beijing China 
1562c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			sc->sc_flags |= IWK_F_SCANNING;
1563f3c4902cSpengcheng chen - Sun Microsystems - Beijing China 			sc->sc_scan_pending = 0;
1564c533a883Shx 			iwk_set_led(sc, 2, 10, 2);
1565c533a883Shx 
1566c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			/*
1567c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			 * clear association to receive beacons from
1568c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			 * all BSS'es
1569c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			 */
1570c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			sc->sc_config.assoc_id = 0;
1571c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			sc->sc_config.filter_flags &=
1572c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			    ~LE_32(RXON_FILTER_ASSOC_MSK);
1573c50ced99Spengcheng chen - Sun Microsystems - Beijing China 
1574c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			IWK_DBG((IWK_DEBUG_80211, "config chan %d "
1575c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			    "flags %x filter_flags %x\n", sc->sc_config.chan,
1576c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			    sc->sc_config.flags, sc->sc_config.filter_flags));
1577c50ced99Spengcheng chen - Sun Microsystems - Beijing China 
1578c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			err = iwk_cmd(sc, REPLY_RXON, &sc->sc_config,
1579c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			    sizeof (iwk_rxon_cmd_t), 1);
1580c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			if (err != IWK_SUCCESS) {
1581c50ced99Spengcheng chen - Sun Microsystems - Beijing China 				cmn_err(CE_WARN,
1582c50ced99Spengcheng chen - Sun Microsystems - Beijing China 				    "could not clear association\n");
1583c50ced99Spengcheng chen - Sun Microsystems - Beijing China 				sc->sc_flags &= ~IWK_F_SCANNING;
1584c50ced99Spengcheng chen - Sun Microsystems - Beijing China 				mutex_exit(&sc->sc_glock);
1585c50ced99Spengcheng chen - Sun Microsystems - Beijing China 				return (err);
1586c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			}
1587c50ced99Spengcheng chen - Sun Microsystems - Beijing China 
1588c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			/* add broadcast node to send probe request */
1589c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			(void) memset(&node, 0, sizeof (node));
1590c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			(void) memset(&node.bssid, 0xff, IEEE80211_ADDR_LEN);
1591c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			node.id = IWK_BROADCAST_ID;
1592c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			err = iwk_cmd(sc, REPLY_ADD_STA, &node,
1593c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			    sizeof (node), 1);
1594c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			if (err != IWK_SUCCESS) {
1595c50ced99Spengcheng chen - Sun Microsystems - Beijing China 				cmn_err(CE_WARN, "could not add "
1596c50ced99Spengcheng chen - Sun Microsystems - Beijing China 				    "broadcast node\n");
1597c50ced99Spengcheng chen - Sun Microsystems - Beijing China 				sc->sc_flags &= ~IWK_F_SCANNING;
1598c533a883Shx 				mutex_exit(&sc->sc_glock);
1599c533a883Shx 				return (err);
1600c533a883Shx 			}
1601c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			break;
1602c50ced99Spengcheng chen - Sun Microsystems - Beijing China 		}
1603f3c4902cSpengcheng chen - Sun Microsystems - Beijing China 
1604f3c4902cSpengcheng chen - Sun Microsystems - Beijing China 		case IEEE80211_S_AUTH:
1605f3c4902cSpengcheng chen - Sun Microsystems - Beijing China 		case IEEE80211_S_ASSOC:
1606f3c4902cSpengcheng chen - Sun Microsystems - Beijing China 		case IEEE80211_S_RUN:
1607f3c4902cSpengcheng chen - Sun Microsystems - Beijing China 			sc->sc_flags |= IWK_F_SCANNING;
1608f3c4902cSpengcheng chen - Sun Microsystems - Beijing China 			sc->sc_scan_pending = 0;
1609f3c4902cSpengcheng chen - Sun Microsystems - Beijing China 
1610f3c4902cSpengcheng chen - Sun Microsystems - Beijing China 			iwk_set_led(sc, 2, 10, 2);
1611f3c4902cSpengcheng chen - Sun Microsystems - Beijing China 			/* FALLTHRU */
1612c50ced99Spengcheng chen - Sun Microsystems - Beijing China 		case IEEE80211_S_SCAN:
1613c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			mutex_exit(&sc->sc_glock);
1614c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			/* step to next channel before actual FW scan */
1615c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			err = sc->sc_newstate(ic, nstate, arg);
1616c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			mutex_enter(&sc->sc_glock);
1617c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			if ((err != 0) || ((err = iwk_scan(sc)) != 0)) {
1618c50ced99Spengcheng chen - Sun Microsystems - Beijing China 				cmn_err(CE_WARN,
1619c50ced99Spengcheng chen - Sun Microsystems - Beijing China 				    "could not initiate scan\n");
1620c50ced99Spengcheng chen - Sun Microsystems - Beijing China 				sc->sc_flags &= ~IWK_F_SCANNING;
1621c50ced99Spengcheng chen - Sun Microsystems - Beijing China 				ieee80211_cancel_scan(ic);
1622c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			}
1623c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			mutex_exit(&sc->sc_glock);
1624c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			return (err);
1625c50ced99Spengcheng chen - Sun Microsystems - Beijing China 		default:
1626c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			break;
1627c50ced99Spengcheng chen - Sun Microsystems - Beijing China 
1628c533a883Shx 		}
162943439c96Shx 		sc->sc_clk = 0;
1630c50ced99Spengcheng chen - Sun Microsystems - Beijing China 		break;
1631c533a883Shx 
1632c533a883Shx 	case IEEE80211_S_AUTH:
1633c50ced99Spengcheng chen - Sun Microsystems - Beijing China 		if (ostate == IEEE80211_S_SCAN) {
1634c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			sc->sc_flags &= ~IWK_F_SCANNING;
1635c50ced99Spengcheng chen - Sun Microsystems - Beijing China 		}
1636c50ced99Spengcheng chen - Sun Microsystems - Beijing China 
1637c533a883Shx 		/* reset state to handle reassociations correctly */
1638c533a883Shx 		sc->sc_config.assoc_id = 0;
1639c533a883Shx 		sc->sc_config.filter_flags &= ~LE_32(RXON_FILTER_ASSOC_MSK);
1640c533a883Shx 
1641c533a883Shx 		/*
1642c533a883Shx 		 * before sending authentication and association request frame,
1643c533a883Shx 		 * we need do something in the hardware, such as setting the
1644c533a883Shx 		 * channel same to the target AP...
1645c533a883Shx 		 */
1646c533a883Shx 		if ((err = iwk_hw_set_before_auth(sc)) != 0) {
1647c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			cmn_err(CE_WARN, "could not setup firmware for "
1648c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			    "authentication\n");
1649c533a883Shx 			mutex_exit(&sc->sc_glock);
1650c533a883Shx 			return (err);
1651c533a883Shx 		}
1652c533a883Shx 		break;
1653c533a883Shx 
1654c533a883Shx 	case IEEE80211_S_RUN:
1655c50ced99Spengcheng chen - Sun Microsystems - Beijing China 		if (ostate == IEEE80211_S_SCAN) {
1656c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			sc->sc_flags &= ~IWK_F_SCANNING;
1657c50ced99Spengcheng chen - Sun Microsystems - Beijing China 		}
1658c50ced99Spengcheng chen - Sun Microsystems - Beijing China 
1659c533a883Shx 		if (ic->ic_opmode == IEEE80211_M_MONITOR) {
1660c533a883Shx 			/* let LED blink when monitoring */
1661c533a883Shx 			iwk_set_led(sc, 2, 10, 10);
1662c533a883Shx 			break;
1663c533a883Shx 		}
1664c533a883Shx 		IWK_DBG((IWK_DEBUG_80211, "iwk: associated."));
1665c533a883Shx 
166619d332feSfei feng - Sun Microsystems - Beijing China 		/* IBSS mode */
166719d332feSfei feng - Sun Microsystems - Beijing China 		if (ic->ic_opmode == IEEE80211_M_IBSS) {
1668cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			/*
166919d332feSfei feng - Sun Microsystems - Beijing China 			 * clean all nodes in ibss node table
167019d332feSfei feng - Sun Microsystems - Beijing China 			 * in order to be consistent with hardware
1671cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			 */
167219d332feSfei feng - Sun Microsystems - Beijing China 			err = iwk_run_state_config_ibss(ic);
167319d332feSfei feng - Sun Microsystems - Beijing China 			if (err != IWK_SUCCESS) {
167419d332feSfei feng - Sun Microsystems - Beijing China 				cmn_err(CE_WARN, "iwk_newstate(): "
167519d332feSfei feng - Sun Microsystems - Beijing China 				    "failed to update configuration "
167619d332feSfei feng - Sun Microsystems - Beijing China 				    "in IBSS mode\n");
167719d332feSfei feng - Sun Microsystems - Beijing China 				mutex_exit(&sc->sc_glock);
167819d332feSfei feng - Sun Microsystems - Beijing China 				return (err);
167919d332feSfei feng - Sun Microsystems - Beijing China 			}
168019d332feSfei feng - Sun Microsystems - Beijing China 		}
1681cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
168219d332feSfei feng - Sun Microsystems - Beijing China 		/* none IBSS mode */
168319d332feSfei feng - Sun Microsystems - Beijing China 		if (ic->ic_opmode != IEEE80211_M_IBSS) {
168419d332feSfei feng - Sun Microsystems - Beijing China 			/* update adapter's configuration */
168519d332feSfei feng - Sun Microsystems - Beijing China 			err = iwk_run_state_config_sta(ic);
1686cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			if (err != IWK_SUCCESS) {
168719d332feSfei feng - Sun Microsystems - Beijing China 				cmn_err(CE_WARN, "iwk_newstate(): "
168819d332feSfei feng - Sun Microsystems - Beijing China 				    "failed to update configuration "
168919d332feSfei feng - Sun Microsystems - Beijing China 				    "in none IBSS mode\n");
1690cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				mutex_exit(&sc->sc_glock);
1691cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				return (err);
1692cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			}
1693c533a883Shx 		}
1694c533a883Shx 
1695cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		/* obtain current temperature of chipset */
1696cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		sc->sc_tempera = iwk_curr_tempera(sc);
1697cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
1698c533a883Shx 		/*
1699cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		 * make Tx power calibration to determine
1700cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		 * the gains of DSP and radio
1701c533a883Shx 		 */
1702cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		err = iwk_tx_power_calibration(sc);
1703cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		if (err) {
1704cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			cmn_err(CE_WARN, "iwk_newstate(): "
1705cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			    "failed to set tx power table\n");
170619d332feSfei feng - Sun Microsystems - Beijing China 			mutex_exit(&sc->sc_glock);
1707c533a883Shx 			return (err);
1708c533a883Shx 		}
1709c533a883Shx 
171019d332feSfei feng - Sun Microsystems - Beijing China 		if (ic->ic_opmode == IEEE80211_M_IBSS) {
171119d332feSfei feng - Sun Microsystems - Beijing China 
171219d332feSfei feng - Sun Microsystems - Beijing China 			/*
171319d332feSfei feng - Sun Microsystems - Beijing China 			 * allocate and transmit beacon frames
171419d332feSfei feng - Sun Microsystems - Beijing China 			 */
171519d332feSfei feng - Sun Microsystems - Beijing China 			err = iwk_start_tx_beacon(ic);
171619d332feSfei feng - Sun Microsystems - Beijing China 			if (err != IWK_SUCCESS) {
171719d332feSfei feng - Sun Microsystems - Beijing China 				cmn_err(CE_WARN, "iwk_newstate(): "
171819d332feSfei feng - Sun Microsystems - Beijing China 				    "can't transmit beacon frames\n");
171919d332feSfei feng - Sun Microsystems - Beijing China 				mutex_exit(&sc->sc_glock);
172019d332feSfei feng - Sun Microsystems - Beijing China 				return (err);
172119d332feSfei feng - Sun Microsystems - Beijing China 			}
172219d332feSfei feng - Sun Microsystems - Beijing China 		}
172319d332feSfei feng - Sun Microsystems - Beijing China 
172443439c96Shx 		/* start automatic rate control */
172543439c96Shx 		mutex_enter(&sc->sc_mt_lock);
172643439c96Shx 		if (ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE) {
172743439c96Shx 			sc->sc_flags |= IWK_F_RATE_AUTO_CTL;
172843439c96Shx 			/* set rate to some reasonable initial value */
172943439c96Shx 			i = in->in_rates.ir_nrates - 1;
173043439c96Shx 			while (i > 0 && IEEE80211_RATE(i) > 72)
173143439c96Shx 				i--;
173243439c96Shx 			in->in_txrate = i;
173343439c96Shx 		} else {
173443439c96Shx 			sc->sc_flags &= ~IWK_F_RATE_AUTO_CTL;
173543439c96Shx 		}
173643439c96Shx 		mutex_exit(&sc->sc_mt_lock);
173743439c96Shx 
1738c533a883Shx 		/* set LED on after associated */
1739c533a883Shx 		iwk_set_led(sc, 2, 0, 1);
1740c533a883Shx 		break;
1741c533a883Shx 
1742c533a883Shx 	case IEEE80211_S_INIT:
1743c50ced99Spengcheng chen - Sun Microsystems - Beijing China 		if (ostate == IEEE80211_S_SCAN) {
1744c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			sc->sc_flags &= ~IWK_F_SCANNING;
1745c50ced99Spengcheng chen - Sun Microsystems - Beijing China 		}
1746c50ced99Spengcheng chen - Sun Microsystems - Beijing China 
1747c533a883Shx 		/* set LED off after init */
1748c533a883Shx 		iwk_set_led(sc, 2, 1, 0);
1749c533a883Shx 		break;
1750c533a883Shx 	case IEEE80211_S_ASSOC:
1751c50ced99Spengcheng chen - Sun Microsystems - Beijing China 		if (ostate == IEEE80211_S_SCAN) {
1752c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			sc->sc_flags &= ~IWK_F_SCANNING;
1753c50ced99Spengcheng chen - Sun Microsystems - Beijing China 		}
1754c50ced99Spengcheng chen - Sun Microsystems - Beijing China 
1755c533a883Shx 		break;
1756c533a883Shx 	}
1757c533a883Shx 
1758c533a883Shx 	mutex_exit(&sc->sc_glock);
1759cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
1760cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	err = sc->sc_newstate(ic, nstate, arg);
1761cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
1762cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (nstate == IEEE80211_S_RUN) {
1763cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
1764cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		mutex_enter(&sc->sc_glock);
1765cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
1766cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		/*
1767cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		 * make initialization for Receiver
1768cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		 * sensitivity calibration
1769cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		 */
1770cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		err = iwk_rx_sens_init(sc);
1771cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		if (err) {
1772cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			cmn_err(CE_WARN, "iwk_newstate(): "
1773cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			    "failed to init RX sensitivity\n");
1774c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			mutex_exit(&sc->sc_glock);
1775cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			return (err);
1776cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		}
1777cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
1778cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		/* make initialization for Receiver gain balance */
1779cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		err = iwk_rxgain_diff_init(sc);
1780cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		if (err) {
1781cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			cmn_err(CE_WARN, "iwk_newstate(): "
1782cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			    "failed to init phy calibration\n");
1783c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			mutex_exit(&sc->sc_glock);
1784cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			return (err);
1785cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		}
1786cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
1787cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		mutex_exit(&sc->sc_glock);
1788cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
1789cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
1790cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
1791cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	return (err);
1792c533a883Shx }
1793c533a883Shx 
1794f3c4902cSpengcheng chen - Sun Microsystems - Beijing China static void
iwk_watchdog(void * arg)1795f3c4902cSpengcheng chen - Sun Microsystems - Beijing China iwk_watchdog(void *arg)
1796f3c4902cSpengcheng chen - Sun Microsystems - Beijing China {
1797f3c4902cSpengcheng chen - Sun Microsystems - Beijing China 	iwk_sc_t *sc = arg;
1798f3c4902cSpengcheng chen - Sun Microsystems - Beijing China 	struct ieee80211com *ic = &sc->sc_ic;
1799f3c4902cSpengcheng chen - Sun Microsystems - Beijing China #ifdef DEBUG
1800f3c4902cSpengcheng chen - Sun Microsystems - Beijing China 	timeout_id_t timeout_id = ic->ic_watchdog_timer;
1801f3c4902cSpengcheng chen - Sun Microsystems - Beijing China #endif
1802f3c4902cSpengcheng chen - Sun Microsystems - Beijing China 
1803f3c4902cSpengcheng chen - Sun Microsystems - Beijing China 	ieee80211_stop_watchdog(ic);
1804f3c4902cSpengcheng chen - Sun Microsystems - Beijing China 
1805f3c4902cSpengcheng chen - Sun Microsystems - Beijing China 	if ((ic->ic_state != IEEE80211_S_AUTH) &&
1806f3c4902cSpengcheng chen - Sun Microsystems - Beijing China 	    (ic->ic_state != IEEE80211_S_ASSOC))
1807f3c4902cSpengcheng chen - Sun Microsystems - Beijing China 		return;
1808f3c4902cSpengcheng chen - Sun Microsystems - Beijing China 
1809f3c4902cSpengcheng chen - Sun Microsystems - Beijing China 	if (ic->ic_bss->in_fails > 0) {
1810f3c4902cSpengcheng chen - Sun Microsystems - Beijing China 		IWK_DBG((IWK_DEBUG_80211, "watchdog (0x%x) reset: "
1811f3c4902cSpengcheng chen - Sun Microsystems - Beijing China 		    "node (0x%x)\n", timeout_id, &ic->ic_bss));
1812f3c4902cSpengcheng chen - Sun Microsystems - Beijing China 		ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
1813f3c4902cSpengcheng chen - Sun Microsystems - Beijing China 	} else {
1814f3c4902cSpengcheng chen - Sun Microsystems - Beijing China 		IWK_DBG((IWK_DEBUG_80211, "watchdog (0x%x) timeout: "
1815f3c4902cSpengcheng chen - Sun Microsystems - Beijing China 		    "node (0x%x), retry (%d)\n",
1816f3c4902cSpengcheng chen - Sun Microsystems - Beijing China 		    timeout_id, &ic->ic_bss, ic->ic_bss->in_fails + 1));
1817f3c4902cSpengcheng chen - Sun Microsystems - Beijing China 		ieee80211_watchdog(ic);
1818f3c4902cSpengcheng chen - Sun Microsystems - Beijing China 	}
1819f3c4902cSpengcheng chen - Sun Microsystems - Beijing China }
1820f3c4902cSpengcheng chen - Sun Microsystems - Beijing China 
1821c533a883Shx /*ARGSUSED*/
iwk_key_set(ieee80211com_t * ic,const struct ieee80211_key * k,const uint8_t mac[IEEE80211_ADDR_LEN])1822c533a883Shx static int iwk_key_set(ieee80211com_t *ic, const struct ieee80211_key *k,
1823c533a883Shx     const uint8_t mac[IEEE80211_ADDR_LEN])
1824c533a883Shx {
1825c533a883Shx 	iwk_sc_t *sc = (iwk_sc_t *)ic;
1826c533a883Shx 	iwk_add_sta_t node;
1827c533a883Shx 	int err;
182819d332feSfei feng - Sun Microsystems - Beijing China 	uint8_t index1;
1829c533a883Shx 
1830c533a883Shx 	switch (k->wk_cipher->ic_cipher) {
1831c533a883Shx 	case IEEE80211_CIPHER_WEP:
1832c533a883Shx 	case IEEE80211_CIPHER_TKIP:
1833c533a883Shx 		return (1); /* sofeware do it. */
1834c533a883Shx 	case IEEE80211_CIPHER_AES_CCM:
1835c533a883Shx 		break;
1836c533a883Shx 	default:
1837c533a883Shx 		return (0);
1838c533a883Shx 	}
1839b510adaeSfei feng - Sun Microsystems - Beijing China 	sc->sc_config.filter_flags &= ~LE_32(RXON_FILTER_DIS_DECRYPT_MSK |
1840cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	    RXON_FILTER_DIS_GRP_DECRYPT_MSK);
1841c533a883Shx 
1842c533a883Shx 	mutex_enter(&sc->sc_glock);
1843c533a883Shx 
1844c533a883Shx 	/* update ap/multicast node */
1845c533a883Shx 	(void) memset(&node, 0, sizeof (node));
1846c533a883Shx 	if (IEEE80211_IS_MULTICAST(mac)) {
1847c533a883Shx 		(void) memset(node.bssid, 0xff, 6);
1848c533a883Shx 		node.id = IWK_BROADCAST_ID;
184919d332feSfei feng - Sun Microsystems - Beijing China 	} else if (ic->ic_opmode == IEEE80211_M_IBSS) {
185019d332feSfei feng - Sun Microsystems - Beijing China 		mutex_exit(&sc->sc_glock);
185119d332feSfei feng - Sun Microsystems - Beijing China 		mutex_enter(&sc->sc_ibss.node_tb_lock);
185219d332feSfei feng - Sun Microsystems - Beijing China 
185319d332feSfei feng - Sun Microsystems - Beijing China 		/*
185419d332feSfei feng - Sun Microsystems - Beijing China 		 * search for node in ibss node table
185519d332feSfei feng - Sun Microsystems - Beijing China 		 */
185619d332feSfei feng - Sun Microsystems - Beijing China 		for (index1 = IWK_STA_ID; index1 < IWK_STATION_COUNT;
185719d332feSfei feng - Sun Microsystems - Beijing China 		    index1++) {
185819d332feSfei feng - Sun Microsystems - Beijing China 			if (sc->sc_ibss.ibss_node_tb[index1].used &&
185919d332feSfei feng - Sun Microsystems - Beijing China 			    IEEE80211_ADDR_EQ(sc->sc_ibss.
186019d332feSfei feng - Sun Microsystems - Beijing China 			    ibss_node_tb[index1].node.bssid,
186119d332feSfei feng - Sun Microsystems - Beijing China 			    mac)) {
186219d332feSfei feng - Sun Microsystems - Beijing China 				break;
186319d332feSfei feng - Sun Microsystems - Beijing China 			}
186419d332feSfei feng - Sun Microsystems - Beijing China 		}
186519d332feSfei feng - Sun Microsystems - Beijing China 		if (index1 >= IWK_BROADCAST_ID) {
186619d332feSfei feng - Sun Microsystems - Beijing China 			cmn_err(CE_WARN, "iwk_key_set(): "
186719d332feSfei feng - Sun Microsystems - Beijing China 			    "have no this node in hardware node table\n");
186819d332feSfei feng - Sun Microsystems - Beijing China 			mutex_exit(&sc->sc_ibss.node_tb_lock);
186919d332feSfei feng - Sun Microsystems - Beijing China 			return (0);
187019d332feSfei feng - Sun Microsystems - Beijing China 		} else {
187119d332feSfei feng - Sun Microsystems - Beijing China 			/*
187219d332feSfei feng - Sun Microsystems - Beijing China 			 * configure key for given node in hardware
187319d332feSfei feng - Sun Microsystems - Beijing China 			 */
187419d332feSfei feng - Sun Microsystems - Beijing China 			if (k->wk_flags & IEEE80211_KEY_XMIT) {
187519d332feSfei feng - Sun Microsystems - Beijing China 				sc->sc_ibss.ibss_node_tb[index1].
187619d332feSfei feng - Sun Microsystems - Beijing China 				    node.key_flags = 0;
187719d332feSfei feng - Sun Microsystems - Beijing China 				sc->sc_ibss.ibss_node_tb[index1].
187819d332feSfei feng - Sun Microsystems - Beijing China 				    node.keyp = k->wk_keyix;
187919d332feSfei feng - Sun Microsystems - Beijing China 			} else {
188019d332feSfei feng - Sun Microsystems - Beijing China 				sc->sc_ibss.ibss_node_tb[index1].
188119d332feSfei feng - Sun Microsystems - Beijing China 				    node.key_flags = (1 << 14);
188219d332feSfei feng - Sun Microsystems - Beijing China 				sc->sc_ibss.ibss_node_tb[index1].
188319d332feSfei feng - Sun Microsystems - Beijing China 				    node.keyp = k->wk_keyix + 4;
188419d332feSfei feng - Sun Microsystems - Beijing China 			}
188519d332feSfei feng - Sun Microsystems - Beijing China 
188619d332feSfei feng - Sun Microsystems - Beijing China 			(void) memcpy(sc->sc_ibss.ibss_node_tb[index1].node.key,
188719d332feSfei feng - Sun Microsystems - Beijing China 			    k->wk_key, k->wk_keylen);
188819d332feSfei feng - Sun Microsystems - Beijing China 			sc->sc_ibss.ibss_node_tb[index1].node.key_flags |=
188919d332feSfei feng - Sun Microsystems - Beijing China 			    (STA_KEY_FLG_CCMP | (1 << 3) | (k->wk_keyix << 8));
1890b510adaeSfei feng - Sun Microsystems - Beijing China 			sc->sc_ibss.ibss_node_tb[index1].node.key_flags =
1891b510adaeSfei feng - Sun Microsystems - Beijing China 			    LE_16(sc->sc_ibss.ibss_node_tb[index1].
1892b510adaeSfei feng - Sun Microsystems - Beijing China 			    node.key_flags);
189319d332feSfei feng - Sun Microsystems - Beijing China 			sc->sc_ibss.ibss_node_tb[index1].node.sta_mask =
189419d332feSfei feng - Sun Microsystems - Beijing China 			    STA_MODIFY_KEY_MASK;
189519d332feSfei feng - Sun Microsystems - Beijing China 			sc->sc_ibss.ibss_node_tb[index1].node.control = 1;
189619d332feSfei feng - Sun Microsystems - Beijing China 
189719d332feSfei feng - Sun Microsystems - Beijing China 			mutex_enter(&sc->sc_glock);
189819d332feSfei feng - Sun Microsystems - Beijing China 			err = iwk_cmd(sc, REPLY_ADD_STA,
189919d332feSfei feng - Sun Microsystems - Beijing China 			    &sc->sc_ibss.ibss_node_tb[index1].node,
190019d332feSfei feng - Sun Microsystems - Beijing China 			    sizeof (iwk_add_sta_t), 1);
190119d332feSfei feng - Sun Microsystems - Beijing China 			if (err != IWK_SUCCESS) {
190219d332feSfei feng - Sun Microsystems - Beijing China 				cmn_err(CE_WARN, "iwk_key_set(): "
190319d332feSfei feng - Sun Microsystems - Beijing China 				    "failed to update IBSS node in hardware\n");
190419d332feSfei feng - Sun Microsystems - Beijing China 				mutex_exit(&sc->sc_glock);
190519d332feSfei feng - Sun Microsystems - Beijing China 				mutex_exit(&sc->sc_ibss.node_tb_lock);
190619d332feSfei feng - Sun Microsystems - Beijing China 				return (0);
190719d332feSfei feng - Sun Microsystems - Beijing China 			}
190819d332feSfei feng - Sun Microsystems - Beijing China 			mutex_exit(&sc->sc_glock);
190919d332feSfei feng - Sun Microsystems - Beijing China 		}
191019d332feSfei feng - Sun Microsystems - Beijing China 		mutex_exit(&sc->sc_ibss.node_tb_lock);
191119d332feSfei feng - Sun Microsystems - Beijing China 		return (1);
1912c533a883Shx 	} else {
1913c533a883Shx 		IEEE80211_ADDR_COPY(node.bssid, ic->ic_bss->in_bssid);
1914c533a883Shx 		node.id = IWK_AP_ID;
1915c533a883Shx 	}
1916c533a883Shx 	if (k->wk_flags & IEEE80211_KEY_XMIT) {
1917c533a883Shx 		node.key_flags = 0;
1918c533a883Shx 		node.keyp = k->wk_keyix;
1919c533a883Shx 	} else {
1920c533a883Shx 		node.key_flags = (1 << 14);
1921c533a883Shx 		node.keyp = k->wk_keyix + 4;
1922c533a883Shx 	}
1923c533a883Shx 	(void) memcpy(node.key, k->wk_key, k->wk_keylen);
1924c533a883Shx 	node.key_flags |= (STA_KEY_FLG_CCMP | (1 << 3) | (k->wk_keyix << 8));
1925b510adaeSfei feng - Sun Microsystems - Beijing China 	node.key_flags = LE_16(node.key_flags);
1926c533a883Shx 	node.sta_mask = STA_MODIFY_KEY_MASK;
1927c533a883Shx 	node.control = 1;
1928c533a883Shx 	err = iwk_cmd(sc, REPLY_ADD_STA, &node, sizeof (node), 1);
1929c533a883Shx 	if (err != IWK_SUCCESS) {
1930c533a883Shx 		cmn_err(CE_WARN, "iwk_key_set():"
1931c533a883Shx 		    "failed to update ap node\n");
1932c533a883Shx 		mutex_exit(&sc->sc_glock);
1933c533a883Shx 		return (0);
1934c533a883Shx 	}
1935c533a883Shx 	mutex_exit(&sc->sc_glock);
1936c533a883Shx 	return (1);
1937c533a883Shx }
1938c533a883Shx 
1939c533a883Shx /*
1940c533a883Shx  * exclusive access to mac begin.
1941c533a883Shx  */
1942c533a883Shx static void
iwk_mac_access_enter(iwk_sc_t * sc)1943c533a883Shx iwk_mac_access_enter(iwk_sc_t *sc)
1944c533a883Shx {
1945c533a883Shx 	uint32_t tmp;
1946c533a883Shx 	int n;
1947c533a883Shx 
1948c533a883Shx 	tmp = IWK_READ(sc, CSR_GP_CNTRL);
1949c533a883Shx 	IWK_WRITE(sc, CSR_GP_CNTRL,
1950c533a883Shx 	    tmp | CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
1951c533a883Shx 
1952c533a883Shx 	/* wait until we succeed */
1953c533a883Shx 	for (n = 0; n < 1000; n++) {
1954c533a883Shx 		if ((IWK_READ(sc, CSR_GP_CNTRL) &
1955c533a883Shx 		    (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY |
1956c533a883Shx 		    CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP)) ==
1957c533a883Shx 		    CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN)
1958c533a883Shx 			break;
1959c533a883Shx 		DELAY(10);
1960c533a883Shx 	}
1961c533a883Shx 	if (n == 1000)
1962c533a883Shx 		IWK_DBG((IWK_DEBUG_PIO, "could not lock memory\n"));
1963c533a883Shx }
1964c533a883Shx 
1965c533a883Shx /*
1966c533a883Shx  * exclusive access to mac end.
1967c533a883Shx  */
1968c533a883Shx static void
iwk_mac_access_exit(iwk_sc_t * sc)1969c533a883Shx iwk_mac_access_exit(iwk_sc_t *sc)
1970c533a883Shx {
1971c533a883Shx 	uint32_t tmp = IWK_READ(sc, CSR_GP_CNTRL);
1972c533a883Shx 	IWK_WRITE(sc, CSR_GP_CNTRL,
1973c533a883Shx 	    tmp & ~CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
1974c533a883Shx }
1975c533a883Shx 
1976cdc64593Sxinghua wen - Sun Microsystems - Beijing China static uint32_t
iwk_mem_read(iwk_sc_t * sc,uint32_t addr)1977cdc64593Sxinghua wen - Sun Microsystems - Beijing China iwk_mem_read(iwk_sc_t *sc, uint32_t addr)
1978cdc64593Sxinghua wen - Sun Microsystems - Beijing China {
1979cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	IWK_WRITE(sc, HBUS_TARG_MEM_RADDR, addr);
1980cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	return (IWK_READ(sc, HBUS_TARG_MEM_RDAT));
1981cdc64593Sxinghua wen - Sun Microsystems - Beijing China }
1982c533a883Shx 
1983c533a883Shx static void
iwk_mem_write(iwk_sc_t * sc,uint32_t addr,uint32_t data)1984c533a883Shx iwk_mem_write(iwk_sc_t *sc, uint32_t addr, uint32_t data)
1985c533a883Shx {
1986c533a883Shx 	IWK_WRITE(sc, HBUS_TARG_MEM_WADDR, addr);
1987c533a883Shx 	IWK_WRITE(sc, HBUS_TARG_MEM_WDAT, data);
1988c533a883Shx }
1989c533a883Shx 
1990c533a883Shx static uint32_t
iwk_reg_read(iwk_sc_t * sc,uint32_t addr)1991c533a883Shx iwk_reg_read(iwk_sc_t *sc, uint32_t addr)
1992c533a883Shx {
1993c533a883Shx 	IWK_WRITE(sc, HBUS_TARG_PRPH_RADDR, addr | (3 << 24));
1994c533a883Shx 	return (IWK_READ(sc, HBUS_TARG_PRPH_RDAT));
1995c533a883Shx }
1996c533a883Shx 
1997c533a883Shx static void
iwk_reg_write(iwk_sc_t * sc,uint32_t addr,uint32_t data)1998c533a883Shx iwk_reg_write(iwk_sc_t *sc, uint32_t addr, uint32_t data)
1999c533a883Shx {
2000c533a883Shx 	IWK_WRITE(sc, HBUS_TARG_PRPH_WADDR, addr | (3 << 24));
2001c533a883Shx 	IWK_WRITE(sc, HBUS_TARG_PRPH_WDAT, data);
2002c533a883Shx }
2003c533a883Shx 
2004c533a883Shx static void
iwk_reg_write_region_4(iwk_sc_t * sc,uint32_t addr,uint32_t * data,int wlen)2005c533a883Shx iwk_reg_write_region_4(iwk_sc_t *sc, uint32_t addr,
2006c533a883Shx     uint32_t *data, int wlen)
2007c533a883Shx {
2008c533a883Shx 	for (; wlen > 0; wlen--, data++, addr += 4)
2009b510adaeSfei feng - Sun Microsystems - Beijing China 		iwk_reg_write(sc, addr, LE_32(*data));
2010c533a883Shx }
2011c533a883Shx 
2012c533a883Shx 
2013c533a883Shx /*
2014c533a883Shx  * ucode load/initialization steps:
2015c533a883Shx  * 1)  load Bootstrap State Machine (BSM) with "bootstrap" uCode image.
2016c533a883Shx  * BSM contains a small memory that *always* stays powered up, so it can
2017c533a883Shx  * retain the bootstrap program even when the card is in a power-saving
2018c533a883Shx  * power-down state.  The BSM loads the small program into ARC processor's
2019c533a883Shx  * instruction memory when triggered by power-up.
2020c533a883Shx  * 2)  load Initialize image via bootstrap program.
2021c533a883Shx  * The Initialize image sets up regulatory and calibration data for the
2022c533a883Shx  * Runtime/Protocol uCode. This sends a REPLY_ALIVE notification when completed.
2023c533a883Shx  * The 4965 reply contains calibration data for temperature, voltage and tx gain
2024c533a883Shx  * correction.
2025c533a883Shx  */
2026c533a883Shx static int
iwk_load_firmware(iwk_sc_t * sc)2027c533a883Shx iwk_load_firmware(iwk_sc_t *sc)
2028c533a883Shx {
2029c533a883Shx 	uint32_t *boot_fw = (uint32_t *)sc->sc_boot;
2030b510adaeSfei feng - Sun Microsystems - Beijing China 	uint32_t size = LE_32(sc->sc_hdr->bootsz);
2031c533a883Shx 	int n, err = IWK_SUCCESS;
2032c533a883Shx 
2033c533a883Shx 	/*
2034c533a883Shx 	 * The physical address bit [4-35] of the initialize uCode.
2035c533a883Shx 	 * In the initialize alive notify interrupt the physical address of
2036c533a883Shx 	 * the runtime ucode will be set for loading.
2037c533a883Shx 	 */
2038c533a883Shx 	iwk_mac_access_enter(sc);
2039c533a883Shx 
2040c533a883Shx 	iwk_reg_write(sc, BSM_DRAM_INST_PTR_REG,
2041c533a883Shx 	    sc->sc_dma_fw_init_text.cookie.dmac_address >> 4);
2042c533a883Shx 	iwk_reg_write(sc, BSM_DRAM_DATA_PTR_REG,
2043c533a883Shx 	    sc->sc_dma_fw_init_data.cookie.dmac_address >> 4);
2044c533a883Shx 	iwk_reg_write(sc, BSM_DRAM_INST_BYTECOUNT_REG,
2045c533a883Shx 	    sc->sc_dma_fw_init_text.cookie.dmac_size);
2046c533a883Shx 	iwk_reg_write(sc, BSM_DRAM_DATA_BYTECOUNT_REG,
2047c533a883Shx 	    sc->sc_dma_fw_init_data.cookie.dmac_size);
2048c533a883Shx 
2049c533a883Shx 	/* load bootstrap code into BSM memory */
2050c533a883Shx 	iwk_reg_write_region_4(sc, BSM_SRAM_LOWER_BOUND, boot_fw,
2051c533a883Shx 	    size / sizeof (uint32_t));
2052c533a883Shx 
2053c533a883Shx 	iwk_reg_write(sc, BSM_WR_MEM_SRC_REG, 0);
2054c533a883Shx 	iwk_reg_write(sc, BSM_WR_MEM_DST_REG, RTC_INST_LOWER_BOUND);
2055c533a883Shx 	iwk_reg_write(sc, BSM_WR_DWCOUNT_REG, size / sizeof (uint32_t));
2056c533a883Shx 
2057c533a883Shx 	/*
2058c533a883Shx 	 * prepare to load initialize uCode
2059c533a883Shx 	 */
2060c533a883Shx 	iwk_reg_write(sc, BSM_WR_CTRL_REG, BSM_WR_CTRL_REG_BIT_START);
2061c533a883Shx 
2062c533a883Shx 	/* wait while the adapter is busy loading the firmware */
2063c533a883Shx 	for (n = 0; n < 1000; n++) {
2064c533a883Shx 		if (!(iwk_reg_read(sc, BSM_WR_CTRL_REG) &
2065c533a883Shx 		    BSM_WR_CTRL_REG_BIT_START))
2066c533a883Shx 			break;
2067c533a883Shx 		DELAY(10);
2068c533a883Shx 	}
2069c533a883Shx 	if (n == 1000) {
2070c50ced99Spengcheng chen - Sun Microsystems - Beijing China 		cmn_err(CE_WARN, "timeout transferring firmware\n");
2071c533a883Shx 		err = ETIMEDOUT;
2072c533a883Shx 		return (err);
2073c533a883Shx 	}
2074c533a883Shx 
2075c533a883Shx 	/* for future power-save mode use */
2076c533a883Shx 	iwk_reg_write(sc, BSM_WR_CTRL_REG, BSM_WR_CTRL_REG_BIT_START_EN);
2077c533a883Shx 
2078c533a883Shx 	iwk_mac_access_exit(sc);
2079c533a883Shx 
2080c533a883Shx 	return (err);
2081c533a883Shx }
2082c533a883Shx 
2083c533a883Shx /*ARGSUSED*/
2084c533a883Shx static void
iwk_rx_intr(iwk_sc_t * sc,iwk_rx_desc_t * desc,iwk_rx_data_t * data)2085c533a883Shx iwk_rx_intr(iwk_sc_t *sc, iwk_rx_desc_t *desc, iwk_rx_data_t *data)
2086c533a883Shx {
2087c533a883Shx 	ieee80211com_t *ic = &sc->sc_ic;
2088c533a883Shx 	iwk_rx_ring_t *ring = &sc->sc_rxq;
2089c533a883Shx 	iwk_rx_phy_res_t *stat;
2090c533a883Shx 	ieee80211_node_t *in;
2091c533a883Shx 	uint32_t *tail;
2092c533a883Shx 	struct ieee80211_frame *wh;
2093c533a883Shx 	mblk_t *mp;
2094c533a883Shx 	uint16_t len, rssi, mrssi, agc;
2095c533a883Shx 	int16_t t;
2096c533a883Shx 	uint32_t ants, i;
2097c533a883Shx 	struct iwk_rx_non_cfg_phy *phyinfo;
2098b510adaeSfei feng - Sun Microsystems - Beijing China 	uint32_t crc;
2099c533a883Shx 
2100c533a883Shx 	/* assuming not 11n here. cope with 11n in phase-II */
2101c533a883Shx 	stat = (iwk_rx_phy_res_t *)(desc + 1);
2102c533a883Shx 	if (stat->cfg_phy_cnt > 20) {
2103c533a883Shx 		return;
2104c533a883Shx 	}
2105c533a883Shx 
2106b510adaeSfei feng - Sun Microsystems - Beijing China 	for (i = 0; i < RX_RES_PHY_CNT; i++)
2107b510adaeSfei feng - Sun Microsystems - Beijing China 		stat->non_cfg_phy[i] = LE_16(stat->non_cfg_phy[i]);
2108b510adaeSfei feng - Sun Microsystems - Beijing China 
2109c533a883Shx 	phyinfo = (struct iwk_rx_non_cfg_phy *)stat->non_cfg_phy;
2110c533a883Shx 	agc = (phyinfo->agc_info & IWK_AGC_DB_MASK) >> IWK_AGC_DB_POS;
2111c533a883Shx 	mrssi = 0;
2112b510adaeSfei feng - Sun Microsystems - Beijing China 	ants = (LE_16(stat->phy_flags) & RX_PHY_FLAGS_ANTENNAE_MASK) >>
2113cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	    RX_PHY_FLAGS_ANTENNAE_OFFSET;
2114c533a883Shx 	for (i = 0; i < 3; i++) {
2115c533a883Shx 		if (ants & (1 << i))
2116c533a883Shx 			mrssi = MAX(mrssi, phyinfo->rssi_info[i << 1]);
2117c533a883Shx 	}
2118c533a883Shx 	t = mrssi - agc - 44; /* t is the dBM value */
2119c533a883Shx 	/*
2120c533a883Shx 	 * convert dBm to percentage ???
2121c533a883Shx 	 */
2122cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	rssi = (100 * 75 * 75 - (-20 - t) * (15 * 75 + 62 * (-20 - t))) /
2123cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	    (75 * 75);
2124c533a883Shx 	if (rssi > 100)
2125c533a883Shx 		rssi = 100;
2126c533a883Shx 	if (rssi < 1)
2127c533a883Shx 		rssi = 1;
2128b510adaeSfei feng - Sun Microsystems - Beijing China 	len = LE_16(stat->byte_count);
2129b510adaeSfei feng - Sun Microsystems - Beijing China 	tail = (uint32_t *)((caddr_t)(stat + 1) + stat->cfg_phy_cnt + len);
2130b510adaeSfei feng - Sun Microsystems - Beijing China 	bcopy(tail, &crc, 4);
2131c533a883Shx 
2132c533a883Shx 	IWK_DBG((IWK_DEBUG_RX, "rx intr: idx=%d phy_len=%x len=%d "
2133c533a883Shx 	    "rate=%x chan=%d tstamp=%x non_cfg_phy_count=%x "
2134c533a883Shx 	    "cfg_phy_count=%x tail=%x", ring->cur, sizeof (*stat),
2135b510adaeSfei feng - Sun Microsystems - Beijing China 	    len, stat->rate.r.s.rate, LE_16(stat->channel),
2136c533a883Shx 	    LE_32(stat->timestampl), stat->non_cfg_phy_cnt,
2137b510adaeSfei feng - Sun Microsystems - Beijing China 	    stat->cfg_phy_cnt, LE_32(crc)));
2138c533a883Shx 
2139c533a883Shx 	if ((len < 16) || (len > sc->sc_dmabuf_sz)) {
2140c533a883Shx 		IWK_DBG((IWK_DEBUG_RX, "rx frame oversize\n"));
2141c533a883Shx 		return;
2142c533a883Shx 	}
2143c533a883Shx 
2144c533a883Shx 	/*
2145c533a883Shx 	 * discard Rx frames with bad CRC
2146c533a883Shx 	 */
2147b510adaeSfei feng - Sun Microsystems - Beijing China 	if ((LE_32(crc) &
2148c533a883Shx 	    (RX_RES_STATUS_NO_CRC32_ERROR | RX_RES_STATUS_NO_RXE_OVERFLOW)) !=
2149c533a883Shx 	    (RX_RES_STATUS_NO_CRC32_ERROR | RX_RES_STATUS_NO_RXE_OVERFLOW)) {
2150c533a883Shx 		IWK_DBG((IWK_DEBUG_RX, "rx crc error tail: %x\n",
2151b510adaeSfei feng - Sun Microsystems - Beijing China 		    LE_32(crc)));
2152c533a883Shx 		sc->sc_rx_err++;
2153c533a883Shx 		return;
2154c533a883Shx 	}
2155c533a883Shx 
2156c533a883Shx 	wh = (struct ieee80211_frame *)
2157c533a883Shx 	    ((uint8_t *)(stat + 1)+ stat->cfg_phy_cnt);
2158c533a883Shx 	if (*(uint8_t *)wh == IEEE80211_FC0_SUBTYPE_ASSOC_RESP) {
2159c533a883Shx 		sc->sc_assoc_id = *((uint16_t *)(wh + 1) + 2);
2160c533a883Shx 		IWK_DBG((IWK_DEBUG_RX, "rx : association id = %x\n",
2161c533a883Shx 		    sc->sc_assoc_id));
2162c533a883Shx 	}
2163c533a883Shx #ifdef DEBUG
2164c533a883Shx 	if (iwk_dbg_flags & IWK_DEBUG_RX)
2165c533a883Shx 		ieee80211_dump_pkt((uint8_t *)wh, len, 0, 0);
2166c533a883Shx #endif
2167c533a883Shx 	in = ieee80211_find_rxnode(ic, wh);
2168c533a883Shx 	mp = allocb(len, BPRI_MED);
2169c533a883Shx 	if (mp) {
2170c533a883Shx 		(void) memcpy(mp->b_wptr, wh, len);
2171c533a883Shx 		mp->b_wptr += len;
2172c533a883Shx 
2173c533a883Shx 		/* send the frame to the 802.11 layer */
2174c533a883Shx 		(void) ieee80211_input(ic, mp, in, rssi, 0);
2175c533a883Shx 	} else {
2176c533a883Shx 		sc->sc_rx_nobuf++;
2177c533a883Shx 		IWK_DBG((IWK_DEBUG_RX,
2178c533a883Shx 		    "iwk_rx_intr(): alloc rx buf failed\n"));
2179c533a883Shx 	}
2180c533a883Shx 	/* release node reference */
2181c533a883Shx 	ieee80211_free_node(in);
2182c533a883Shx }
2183c533a883Shx 
2184c533a883Shx /*ARGSUSED*/
2185c533a883Shx static void
iwk_tx_intr(iwk_sc_t * sc,iwk_rx_desc_t * desc,iwk_rx_data_t * data)2186c533a883Shx iwk_tx_intr(iwk_sc_t *sc, iwk_rx_desc_t *desc, iwk_rx_data_t *data)
2187c533a883Shx {
2188c533a883Shx 	ieee80211com_t *ic = &sc->sc_ic;
2189c533a883Shx 	iwk_tx_ring_t *ring = &sc->sc_txq[desc->hdr.qid & 0x3];
2190c533a883Shx 	iwk_tx_stat_t *stat = (iwk_tx_stat_t *)(desc + 1);
219143439c96Shx 	iwk_amrr_t *amrr = (iwk_amrr_t *)ic->ic_bss;
2192c533a883Shx 
2193c533a883Shx 	IWK_DBG((IWK_DEBUG_TX, "tx done: qid=%d idx=%d"
2194c533a883Shx 	    " retries=%d frame_count=%x nkill=%d "
2195c533a883Shx 	    "rate=%x duration=%d status=%x\n",
2196c533a883Shx 	    desc->hdr.qid, desc->hdr.idx, stat->ntries, stat->frame_count,
2197c533a883Shx 	    stat->bt_kill_count, stat->rate.r.s.rate,
2198b510adaeSfei feng - Sun Microsystems - Beijing China 	    LE_16(stat->duration), LE_32(stat->status)));
2199c533a883Shx 
220043439c96Shx 	amrr->txcnt++;
220143439c96Shx 	IWK_DBG((IWK_DEBUG_RATECTL, "tx: %d cnt\n", amrr->txcnt));
2202c533a883Shx 	if (stat->ntries > 0) {
220343439c96Shx 		amrr->retrycnt++;
2204c533a883Shx 		sc->sc_tx_retries++;
2205c533a883Shx 		IWK_DBG((IWK_DEBUG_TX, "tx: %d retries\n",
2206c533a883Shx 		    sc->sc_tx_retries));
2207c533a883Shx 	}
2208c533a883Shx 
2209c533a883Shx 	sc->sc_tx_timer = 0;
2210c533a883Shx 
2211c533a883Shx 	mutex_enter(&sc->sc_tx_lock);
2212c533a883Shx 	ring->queued--;
2213c533a883Shx 	if (ring->queued < 0)
2214c533a883Shx 		ring->queued = 0;
2215c533a883Shx 	if ((sc->sc_need_reschedule) && (ring->queued <= (ring->count << 3))) {
2216c533a883Shx 		sc->sc_need_reschedule = 0;
2217c533a883Shx 		mutex_exit(&sc->sc_tx_lock);
2218c533a883Shx 		mac_tx_update(ic->ic_mach);
2219c533a883Shx 		mutex_enter(&sc->sc_tx_lock);
2220c533a883Shx 	}
2221c533a883Shx 	mutex_exit(&sc->sc_tx_lock);
2222c533a883Shx }
2223c533a883Shx 
2224c533a883Shx static void
iwk_cmd_intr(iwk_sc_t * sc,iwk_rx_desc_t * desc)2225c533a883Shx iwk_cmd_intr(iwk_sc_t *sc, iwk_rx_desc_t *desc)
2226c533a883Shx {
2227c533a883Shx 	if ((desc->hdr.qid & 7) != 4) {
2228c533a883Shx 		return;
2229c533a883Shx 	}
2230c533a883Shx 	mutex_enter(&sc->sc_glock);
2231c533a883Shx 	sc->sc_flags |= IWK_F_CMD_DONE;
2232c533a883Shx 	cv_signal(&sc->sc_cmd_cv);
2233c533a883Shx 	mutex_exit(&sc->sc_glock);
2234c533a883Shx 	IWK_DBG((IWK_DEBUG_CMD, "rx cmd: "
2235c533a883Shx 	    "qid=%x idx=%d flags=%x type=0x%x\n",
2236c533a883Shx 	    desc->hdr.qid, desc->hdr.idx, desc->hdr.flags,
2237c533a883Shx 	    desc->hdr.type));
2238c533a883Shx }
2239c533a883Shx 
2240c533a883Shx static void
iwk_ucode_alive(iwk_sc_t * sc,iwk_rx_desc_t * desc)2241c533a883Shx iwk_ucode_alive(iwk_sc_t *sc, iwk_rx_desc_t *desc)
2242c533a883Shx {
2243c533a883Shx 	uint32_t base, i;
2244c533a883Shx 	struct iwk_alive_resp *ar =
2245c533a883Shx 	    (struct iwk_alive_resp *)(desc + 1);
2246c533a883Shx 
2247c533a883Shx 	/* the microcontroller is ready */
2248c533a883Shx 	IWK_DBG((IWK_DEBUG_FW,
2249c533a883Shx 	    "microcode alive notification minor: %x major: %x type:"
2250c533a883Shx 	    " %x subtype: %x\n",
2251c533a883Shx 	    ar->ucode_minor, ar->ucode_minor, ar->ver_type, ar->ver_subtype));
2252c533a883Shx 
2253c533a883Shx 	if (LE_32(ar->is_valid) != UCODE_VALID_OK) {
2254c533a883Shx 		IWK_DBG((IWK_DEBUG_FW,
2255c533a883Shx 		    "microcontroller initialization failed\n"));
2256c533a883Shx 	}
2257c533a883Shx 	if (ar->ver_subtype == INITIALIZE_SUBTYPE) {
2258c533a883Shx 		IWK_DBG((IWK_DEBUG_FW,
2259c533a883Shx 		    "initialization alive received.\n"));
2260c533a883Shx 		(void) memcpy(&sc->sc_card_alive_init, ar,
2261c533a883Shx 		    sizeof (struct iwk_init_alive_resp));
2262c533a883Shx 		/* XXX get temperature */
2263c533a883Shx 		iwk_mac_access_enter(sc);
2264c533a883Shx 		iwk_reg_write(sc, BSM_DRAM_INST_PTR_REG,
2265c533a883Shx 		    sc->sc_dma_fw_text.cookie.dmac_address >> 4);
2266c533a883Shx 		iwk_reg_write(sc, BSM_DRAM_DATA_PTR_REG,
2267c533a883Shx 		    sc->sc_dma_fw_data_bak.cookie.dmac_address >> 4);
2268c533a883Shx 		iwk_reg_write(sc, BSM_DRAM_DATA_BYTECOUNT_REG,
2269c533a883Shx 		    sc->sc_dma_fw_data.cookie.dmac_size);
2270c533a883Shx 		iwk_reg_write(sc, BSM_DRAM_INST_BYTECOUNT_REG,
2271c533a883Shx 		    sc->sc_dma_fw_text.cookie.dmac_size | 0x80000000);
2272c533a883Shx 		iwk_mac_access_exit(sc);
2273c533a883Shx 	} else {
2274c533a883Shx 		IWK_DBG((IWK_DEBUG_FW, "runtime alive received.\n"));
2275c533a883Shx 		(void) memcpy(&sc->sc_card_alive_run, ar,
2276c533a883Shx 		    sizeof (struct iwk_alive_resp));
2277c533a883Shx 
2278c533a883Shx 		/*
2279c533a883Shx 		 * Init SCD related registers to make Tx work. XXX
2280c533a883Shx 		 */
2281c533a883Shx 		iwk_mac_access_enter(sc);
2282c533a883Shx 
2283c533a883Shx 		/* read sram address of data base */
2284c533a883Shx 		sc->sc_scd_base = iwk_reg_read(sc, SCD_SRAM_BASE_ADDR);
2285c533a883Shx 
2286c533a883Shx 		/* clear and init SCD_CONTEXT_DATA_OFFSET area. 128 bytes */
2287c533a883Shx 		for (base = sc->sc_scd_base + SCD_CONTEXT_DATA_OFFSET, i = 0;
2288c533a883Shx 		    i < 128; i += 4)
2289c533a883Shx 			iwk_mem_write(sc, base + i, 0);
2290c533a883Shx 
2291c533a883Shx 		/* clear and init SCD_TX_STTS_BITMAP_OFFSET area. 256 bytes */
2292c533a883Shx 		for (base = sc->sc_scd_base + SCD_TX_STTS_BITMAP_OFFSET;
2293c533a883Shx 		    i < 256; i += 4)
2294c533a883Shx 			iwk_mem_write(sc, base + i, 0);
2295c533a883Shx 
2296c533a883Shx 		/* clear and init SCD_TRANSLATE_TBL_OFFSET area. 32 bytes */
2297c533a883Shx 		for (base = sc->sc_scd_base + SCD_TRANSLATE_TBL_OFFSET;
2298c533a883Shx 		    i < sizeof (uint16_t) * IWK_NUM_QUEUES; i += 4)
2299c533a883Shx 			iwk_mem_write(sc, base + i, 0);
2300c533a883Shx 
2301c533a883Shx 		iwk_reg_write(sc, SCD_DRAM_BASE_ADDR,
2302c533a883Shx 		    sc->sc_dma_sh.cookie.dmac_address >> 10);
2303c533a883Shx 		iwk_reg_write(sc, SCD_QUEUECHAIN_SEL, 0);
2304c533a883Shx 
2305c533a883Shx 		/* initiate the tx queues */
2306c533a883Shx 		for (i = 0; i < IWK_NUM_QUEUES; i++) {
2307c533a883Shx 			iwk_reg_write(sc, SCD_QUEUE_RDPTR(i), 0);
2308c533a883Shx 			IWK_WRITE(sc, HBUS_TARG_WRPTR, (i << 8));
2309c533a883Shx 			iwk_mem_write(sc, sc->sc_scd_base +
2310c533a883Shx 			    SCD_CONTEXT_QUEUE_OFFSET(i),
2311c533a883Shx 			    (SCD_WIN_SIZE & 0x7f));
2312c533a883Shx 			iwk_mem_write(sc, sc->sc_scd_base +
2313c533a883Shx 			    SCD_CONTEXT_QUEUE_OFFSET(i) + sizeof (uint32_t),
2314c533a883Shx 			    (SCD_FRAME_LIMIT & 0x7f) << 16);
2315c533a883Shx 		}
2316c533a883Shx 		/* interrupt enable on each queue0-7 */
2317c533a883Shx 		iwk_reg_write(sc, SCD_INTERRUPT_MASK,
2318c533a883Shx 		    (1 << IWK_NUM_QUEUES) - 1);
2319c533a883Shx 		/* enable  each channel 0-7 */
2320c533a883Shx 		iwk_reg_write(sc, SCD_TXFACT,
2321c533a883Shx 		    SCD_TXFACT_REG_TXFIFO_MASK(0, 7));
2322c533a883Shx 		/*
2323c533a883Shx 		 * queue 0-7 maps to FIFO 0-7 and
2324c533a883Shx 		 * all queues work under FIFO mode (none-scheduler-ack)
2325c533a883Shx 		 */
2326c533a883Shx 		for (i = 0; i < 7; i++) {
2327c533a883Shx 			iwk_reg_write(sc,
2328c533a883Shx 			    SCD_QUEUE_STATUS_BITS(i),
2329c533a883Shx 			    (1 << SCD_QUEUE_STTS_REG_POS_ACTIVE)|
2330c533a883Shx 			    (i << SCD_QUEUE_STTS_REG_POS_TXF)|
2331c533a883Shx 			    SCD_QUEUE_STTS_REG_MSK);
2332c533a883Shx 		}
2333c533a883Shx 		iwk_mac_access_exit(sc);
2334c533a883Shx 
2335c533a883Shx 		sc->sc_flags |= IWK_F_FW_INIT;
2336c533a883Shx 		cv_signal(&sc->sc_fw_cv);
2337c533a883Shx 	}
2338c533a883Shx 
2339c533a883Shx }
2340c533a883Shx 
2341c533a883Shx static uint_t
2342cdc64593Sxinghua wen - Sun Microsystems - Beijing China /* LINTED: argument unused in function: unused */
iwk_rx_softintr(caddr_t arg,caddr_t unused)2343cdc64593Sxinghua wen - Sun Microsystems - Beijing China iwk_rx_softintr(caddr_t arg, caddr_t unused)
2344c533a883Shx {
2345c533a883Shx 	iwk_sc_t *sc = (iwk_sc_t *)arg;
2346c533a883Shx 	ieee80211com_t *ic = &sc->sc_ic;
2347c533a883Shx 	iwk_rx_desc_t *desc;
2348c533a883Shx 	iwk_rx_data_t *data;
2349c533a883Shx 	uint32_t index;
2350c533a883Shx 
2351c533a883Shx 	mutex_enter(&sc->sc_glock);
2352c533a883Shx 	if (sc->sc_rx_softint_pending != 1) {
2353c533a883Shx 		mutex_exit(&sc->sc_glock);
2354c533a883Shx 		return (DDI_INTR_UNCLAIMED);
2355c533a883Shx 	}
2356c533a883Shx 	/* disable interrupts */
2357c533a883Shx 	IWK_WRITE(sc, CSR_INT_MASK, 0);
2358c533a883Shx 	mutex_exit(&sc->sc_glock);
2359c533a883Shx 
2360c533a883Shx 	/*
2361c533a883Shx 	 * firmware has moved the index of the rx queue, driver get it,
2362c533a883Shx 	 * and deal with it.
2363c533a883Shx 	 */
2364b510adaeSfei feng - Sun Microsystems - Beijing China 	index = sc->sc_shared->val0 & 0xfff;
2365c533a883Shx 
2366c533a883Shx 	while (sc->sc_rxq.cur != index) {
2367c533a883Shx 		data = &sc->sc_rxq.data[sc->sc_rxq.cur];
2368c533a883Shx 		desc = (iwk_rx_desc_t *)data->dma_data.mem_va;
2369c533a883Shx 
2370c533a883Shx 		IWK_DBG((IWK_DEBUG_INTR, "rx notification index = %d"
2371c533a883Shx 		    " cur = %d qid=%x idx=%d flags=%x type=%x len=%d\n",
2372c533a883Shx 		    index, sc->sc_rxq.cur, desc->hdr.qid, desc->hdr.idx,
2373c533a883Shx 		    desc->hdr.flags, desc->hdr.type, LE_32(desc->len)));
2374c533a883Shx 
2375c533a883Shx 		/* a command other than a tx need to be replied */
2376c533a883Shx 		if (!(desc->hdr.qid & 0x80) &&
2377c533a883Shx 		    (desc->hdr.type != REPLY_RX_PHY_CMD) &&
2378cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		    (desc->hdr.type != REPLY_TX) &&
2379cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		    (desc->hdr.type != REPLY_TX_PWR_TABLE_CMD) &&
2380cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		    (desc->hdr.type != REPLY_PHY_CALIBRATION_CMD) &&
2381cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		    (desc->hdr.type != SENSITIVITY_CMD))
2382c533a883Shx 			iwk_cmd_intr(sc, desc);
2383c533a883Shx 
2384c533a883Shx 		switch (desc->hdr.type) {
2385c533a883Shx 		case REPLY_4965_RX:
2386c533a883Shx 			iwk_rx_intr(sc, desc, data);
2387c533a883Shx 			break;
2388c533a883Shx 
2389c533a883Shx 		case REPLY_TX:
2390c533a883Shx 			iwk_tx_intr(sc, desc, data);
2391c533a883Shx 			break;
2392c533a883Shx 
2393c533a883Shx 		case REPLY_ALIVE:
2394c533a883Shx 			iwk_ucode_alive(sc, desc);
2395c533a883Shx 			break;
2396c533a883Shx 
2397c533a883Shx 		case CARD_STATE_NOTIFICATION:
2398c533a883Shx 		{
2399c533a883Shx 			uint32_t *status = (uint32_t *)(desc + 1);
2400c533a883Shx 
2401c533a883Shx 			IWK_DBG((IWK_DEBUG_RADIO, "state changed to %x\n",
2402c533a883Shx 			    LE_32(*status)));
2403c533a883Shx 
2404c533a883Shx 			if (LE_32(*status) & 1) {
240543439c96Shx 				/*
240643439c96Shx 				 * the radio button has to be pushed(OFF). It
240743439c96Shx 				 * is considered as a hw error, the
240843439c96Shx 				 * iwk_thread() tries to recover it after the
240943439c96Shx 				 * button is pushed again(ON)
241043439c96Shx 				 */
2411c533a883Shx 				cmn_err(CE_NOTE,
2412cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				    "iwk_rx_softintr(): "
2413cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				    "Radio transmitter is off\n");
241443439c96Shx 				sc->sc_ostate = sc->sc_ic.ic_state;
241543439c96Shx 				ieee80211_new_state(&sc->sc_ic,
241643439c96Shx 				    IEEE80211_S_INIT, -1);
241743439c96Shx 				sc->sc_flags |=
241843439c96Shx 				    (IWK_F_HW_ERR_RECOVER | IWK_F_RADIO_OFF);
2419c533a883Shx 			}
2420c533a883Shx 			break;
2421c533a883Shx 		}
2422c533a883Shx 		case SCAN_START_NOTIFICATION:
2423c533a883Shx 		{
2424c533a883Shx 			iwk_start_scan_t *scan =
2425c533a883Shx 			    (iwk_start_scan_t *)(desc + 1);
2426c533a883Shx 
2427c533a883Shx 			IWK_DBG((IWK_DEBUG_SCAN,
2428c533a883Shx 			    "scanning channel %d status %x\n",
2429c533a883Shx 			    scan->chan, LE_32(scan->status)));
2430c533a883Shx 
2431c533a883Shx 			ic->ic_curchan = &ic->ic_sup_channels[scan->chan];
2432c533a883Shx 			break;
2433c533a883Shx 		}
2434c533a883Shx 		case SCAN_COMPLETE_NOTIFICATION:
2435c50ced99Spengcheng chen - Sun Microsystems - Beijing China 		{
2436c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			iwk_stop_scan_t *scan =
2437c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			    (iwk_stop_scan_t *)(desc + 1);
2438c50ced99Spengcheng chen - Sun Microsystems - Beijing China 
2439c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			IWK_DBG((IWK_DEBUG_SCAN,
2440c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			    "completed channel %d (burst of %d) status %02x\n",
2441c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			    scan->chan, scan->nchan, scan->status));
2442c50ced99Spengcheng chen - Sun Microsystems - Beijing China 
2443c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			sc->sc_scan_pending++;
2444c533a883Shx 			break;
2445c50ced99Spengcheng chen - Sun Microsystems - Beijing China 		}
2446cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		case STATISTICS_NOTIFICATION:
2447cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			/* handle statistics notification */
2448cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			iwk_statistics_notify(sc, desc);
2449cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			break;
2450cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		}
2451cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
2452c533a883Shx 		sc->sc_rxq.cur = (sc->sc_rxq.cur + 1) % RX_QUEUE_SIZE;
2453c533a883Shx 	}
2454c533a883Shx 
2455c533a883Shx 	/*
2456c533a883Shx 	 * driver dealt with what reveived in rx queue and tell the information
2457c533a883Shx 	 * to the firmware.
2458c533a883Shx 	 */
2459c533a883Shx 	index = (index == 0) ? RX_QUEUE_SIZE - 1 : index - 1;
2460c533a883Shx 	IWK_WRITE(sc, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, index & (~7));
2461c533a883Shx 
2462c533a883Shx 	mutex_enter(&sc->sc_glock);
2463c533a883Shx 	/* re-enable interrupts */
2464c533a883Shx 	IWK_WRITE(sc, CSR_INT_MASK, CSR_INI_SET_MASK);
2465c533a883Shx 	sc->sc_rx_softint_pending = 0;
2466c533a883Shx 	mutex_exit(&sc->sc_glock);
2467c533a883Shx 
2468c533a883Shx 	return (DDI_INTR_CLAIMED);
2469c533a883Shx }
2470c533a883Shx 
2471c533a883Shx static uint_t
2472cdc64593Sxinghua wen - Sun Microsystems - Beijing China /* LINTED: argument unused in function: unused */
iwk_intr(caddr_t arg,caddr_t unused)2473cdc64593Sxinghua wen - Sun Microsystems - Beijing China iwk_intr(caddr_t arg, caddr_t unused)
2474c533a883Shx {
2475c533a883Shx 	iwk_sc_t *sc = (iwk_sc_t *)arg;
2476c533a883Shx 	uint32_t r, rfh;
2477c533a883Shx 
2478c533a883Shx 	mutex_enter(&sc->sc_glock);
2479d62cb7ffShx 
2480d62cb7ffShx 	if (sc->sc_flags & IWK_F_SUSPEND) {
2481d62cb7ffShx 		mutex_exit(&sc->sc_glock);
2482d62cb7ffShx 		return (DDI_INTR_UNCLAIMED);
2483d62cb7ffShx 	}
2484d62cb7ffShx 
2485c533a883Shx 	r = IWK_READ(sc, CSR_INT);
2486c533a883Shx 	if (r == 0 || r == 0xffffffff) {
2487c533a883Shx 		mutex_exit(&sc->sc_glock);
2488c533a883Shx 		return (DDI_INTR_UNCLAIMED);
2489c533a883Shx 	}
2490c533a883Shx 
2491c533a883Shx 	IWK_DBG((IWK_DEBUG_INTR, "interrupt reg %x\n", r));
2492c533a883Shx 
2493c533a883Shx 	rfh = IWK_READ(sc, CSR_FH_INT_STATUS);
2494c533a883Shx 	IWK_DBG((IWK_DEBUG_INTR, "FH interrupt reg %x\n", rfh));
2495c533a883Shx 	/* disable interrupts */
2496c533a883Shx 	IWK_WRITE(sc, CSR_INT_MASK, 0);
2497c533a883Shx 	/* ack interrupts */
2498c533a883Shx 	IWK_WRITE(sc, CSR_INT, r);
2499c533a883Shx 	IWK_WRITE(sc, CSR_FH_INT_STATUS, rfh);
2500c533a883Shx 
2501cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (sc->sc_soft_hdl == NULL) {
2502c533a883Shx 		mutex_exit(&sc->sc_glock);
2503c533a883Shx 		return (DDI_INTR_CLAIMED);
2504c533a883Shx 	}
2505c533a883Shx 	if (r & (BIT_INT_SWERROR | BIT_INT_ERR)) {
2506c50ced99Spengcheng chen - Sun Microsystems - Beijing China 		cmn_err(CE_WARN, "fatal firmware error\n");
2507c533a883Shx 		mutex_exit(&sc->sc_glock);
2508cdc64593Sxinghua wen - Sun Microsystems - Beijing China #ifdef DEBUG
2509cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		/* dump event and error logs to dmesg */
2510cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		iwk_write_error_log(sc);
2511cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		iwk_write_event_log(sc);
2512cdc64593Sxinghua wen - Sun Microsystems - Beijing China #endif /* DEBUG */
2513c533a883Shx 		iwk_stop(sc);
2514c533a883Shx 		sc->sc_ostate = sc->sc_ic.ic_state;
25156f12def4Spengcheng chen - Sun Microsystems - Beijing China 
25166f12def4Spengcheng chen - Sun Microsystems - Beijing China 		/* not capable of fast recovery */
25176f12def4Spengcheng chen - Sun Microsystems - Beijing China 		if (!IWK_CHK_FAST_RECOVER(sc))
25186f12def4Spengcheng chen - Sun Microsystems - Beijing China 			ieee80211_new_state(&sc->sc_ic, IEEE80211_S_INIT, -1);
25196f12def4Spengcheng chen - Sun Microsystems - Beijing China 
2520c533a883Shx 		sc->sc_flags |= IWK_F_HW_ERR_RECOVER;
2521c533a883Shx 		return (DDI_INTR_CLAIMED);
2522c533a883Shx 	}
2523c533a883Shx 
2524c533a883Shx 	if (r & BIT_INT_RF_KILL) {
2525b510adaeSfei feng - Sun Microsystems - Beijing China 		uint32_t tmp = IWK_READ(sc, CSR_GP_CNTRL);
2526b510adaeSfei feng - Sun Microsystems - Beijing China 		if (tmp & (1 << 27))
2527b510adaeSfei feng - Sun Microsystems - Beijing China 			cmn_err(CE_NOTE, "RF switch: radio on\n");
2528c533a883Shx 	}
2529c533a883Shx 
2530c533a883Shx 	if ((r & (BIT_INT_FH_RX | BIT_INT_SW_RX)) ||
2531c533a883Shx 	    (rfh & FH_INT_RX_MASK)) {
2532c533a883Shx 		sc->sc_rx_softint_pending = 1;
2533cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		(void) ddi_intr_trigger_softint(sc->sc_soft_hdl, NULL);
2534c533a883Shx 	}
2535c533a883Shx 
2536c533a883Shx 	if (r & BIT_INT_ALIVE)	{
2537c533a883Shx 		IWK_DBG((IWK_DEBUG_FW, "firmware initialized.\n"));
2538c533a883Shx 	}
2539c533a883Shx 
2540c533a883Shx 	/* re-enable interrupts */
2541c533a883Shx 	IWK_WRITE(sc, CSR_INT_MASK, CSR_INI_SET_MASK);
2542c533a883Shx 	mutex_exit(&sc->sc_glock);
2543c533a883Shx 
2544c533a883Shx 	return (DDI_INTR_CLAIMED);
2545c533a883Shx }
2546c533a883Shx 
2547c533a883Shx static uint8_t
iwk_rate_to_plcp(int rate)2548c533a883Shx iwk_rate_to_plcp(int rate)
2549c533a883Shx {
2550c533a883Shx 	uint8_t ret;
2551c533a883Shx 
2552c533a883Shx 	switch (rate) {
2553c533a883Shx 	/* CCK rates */
2554c533a883Shx 	case 2:
2555c533a883Shx 		ret = 0xa;
2556c533a883Shx 		break;
2557c533a883Shx 	case 4:
2558c533a883Shx 		ret = 0x14;
2559c533a883Shx 		break;
2560c533a883Shx 	case 11:
2561c533a883Shx 		ret = 0x37;
2562c533a883Shx 		break;
2563c533a883Shx 	case 22:
2564c533a883Shx 		ret = 0x6e;
2565c533a883Shx 		break;
2566c533a883Shx 	/* OFDM rates */
2567c533a883Shx 	case 12:
2568c533a883Shx 		ret = 0xd;
2569c533a883Shx 		break;
2570c533a883Shx 	case 18:
2571c533a883Shx 		ret = 0xf;
2572c533a883Shx 		break;
2573c533a883Shx 	case 24:
2574c533a883Shx 		ret = 0x5;
2575c533a883Shx 		break;
2576c533a883Shx 	case 36:
2577c533a883Shx 		ret = 0x7;
2578c533a883Shx 		break;
2579c533a883Shx 	case 48:
2580c533a883Shx 		ret = 0x9;
2581c533a883Shx 		break;
2582c533a883Shx 	case 72:
2583c533a883Shx 		ret = 0xb;
2584c533a883Shx 		break;
2585c533a883Shx 	case 96:
2586c533a883Shx 		ret = 0x1;
2587c533a883Shx 		break;
2588c533a883Shx 	case 108:
2589c533a883Shx 		ret = 0x3;
2590c533a883Shx 		break;
2591c533a883Shx 	default:
2592c533a883Shx 		ret = 0;
2593c533a883Shx 		break;
2594c533a883Shx 	}
2595c533a883Shx 	return (ret);
2596c533a883Shx }
2597c533a883Shx 
2598c533a883Shx static mblk_t *
iwk_m_tx(void * arg,mblk_t * mp)2599c533a883Shx iwk_m_tx(void *arg, mblk_t *mp)
2600c533a883Shx {
2601c533a883Shx 	iwk_sc_t	*sc = (iwk_sc_t *)arg;
2602c533a883Shx 	ieee80211com_t	*ic = &sc->sc_ic;
2603c533a883Shx 	mblk_t			*next;
2604c533a883Shx 
2605d62cb7ffShx 	if (sc->sc_flags & IWK_F_SUSPEND) {
2606d62cb7ffShx 		freemsgchain(mp);
2607d62cb7ffShx 		return (NULL);
2608d62cb7ffShx 	}
2609d62cb7ffShx 
2610c533a883Shx 	if (ic->ic_state != IEEE80211_S_RUN) {
2611c533a883Shx 		freemsgchain(mp);
2612c533a883Shx 		return (NULL);
2613c533a883Shx 	}
2614c533a883Shx 
26156f12def4Spengcheng chen - Sun Microsystems - Beijing China 	if ((sc->sc_flags & IWK_F_HW_ERR_RECOVER) &&
26166f12def4Spengcheng chen - Sun Microsystems - Beijing China 	    IWK_CHK_FAST_RECOVER(sc)) {
26176f12def4Spengcheng chen - Sun Microsystems - Beijing China 		IWK_DBG((IWK_DEBUG_FW, "iwk_m_tx(): hold queue\n"));
26186f12def4Spengcheng chen - Sun Microsystems - Beijing China 		return (mp);
26196f12def4Spengcheng chen - Sun Microsystems - Beijing China 	}
26206f12def4Spengcheng chen - Sun Microsystems - Beijing China 
2621c533a883Shx 	while (mp != NULL) {
2622c533a883Shx 		next = mp->b_next;
2623c533a883Shx 		mp->b_next = NULL;
2624c533a883Shx 		if (iwk_send(ic, mp, IEEE80211_FC0_TYPE_DATA) != 0) {
2625c533a883Shx 			mp->b_next = next;
2626c533a883Shx 			break;
2627c533a883Shx 		}
2628c533a883Shx 		mp = next;
2629c533a883Shx 	}
2630c533a883Shx 	return (mp);
2631c533a883Shx }
2632c533a883Shx 
2633c533a883Shx /* ARGSUSED */
2634c533a883Shx static int
iwk_send(ieee80211com_t * ic,mblk_t * mp,uint8_t type)2635c533a883Shx iwk_send(ieee80211com_t *ic, mblk_t *mp, uint8_t type)
2636c533a883Shx {
2637c533a883Shx 	iwk_sc_t *sc = (iwk_sc_t *)ic;
2638c533a883Shx 	iwk_tx_ring_t *ring;
2639c533a883Shx 	iwk_tx_desc_t *desc;
2640c533a883Shx 	iwk_tx_data_t *data;
2641c533a883Shx 	iwk_cmd_t *cmd;
2642c533a883Shx 	iwk_tx_cmd_t *tx;
2643c533a883Shx 	ieee80211_node_t *in;
2644c533a883Shx 	struct ieee80211_frame *wh;
2645c533a883Shx 	struct ieee80211_key *k = NULL;
2646c533a883Shx 	mblk_t *m, *m0;
2647c533a883Shx 	int rate, hdrlen, len, len0, mblen, off, err = IWK_SUCCESS;
2648c533a883Shx 	uint16_t masks = 0;
264919d332feSfei feng - Sun Microsystems - Beijing China 	uint8_t index, index1, index2;
2650c533a883Shx 
2651c533a883Shx 	ring = &sc->sc_txq[0];
2652c533a883Shx 	data = &ring->data[ring->cur];
2653c533a883Shx 	desc = data->desc;
2654c533a883Shx 	cmd = data->cmd;
2655c533a883Shx 	bzero(desc, sizeof (*desc));
2656c533a883Shx 	bzero(cmd, sizeof (*cmd));
2657c533a883Shx 
2658c533a883Shx 	mutex_enter(&sc->sc_tx_lock);
2659d62cb7ffShx 	if (sc->sc_flags & IWK_F_SUSPEND) {
2660d62cb7ffShx 		mutex_exit(&sc->sc_tx_lock);
2661d62cb7ffShx 		if ((type & IEEE80211_FC0_TYPE_MASK) !=
2662d62cb7ffShx 		    IEEE80211_FC0_TYPE_DATA) {
2663d62cb7ffShx 			freemsg(mp);
2664d62cb7ffShx 		}
2665d62cb7ffShx 		err = IWK_FAIL;
2666d62cb7ffShx 		goto exit;
2667d62cb7ffShx 	}
2668d62cb7ffShx 
2669c533a883Shx 	if (ring->queued > ring->count - 64) {
2670c533a883Shx 		IWK_DBG((IWK_DEBUG_TX, "iwk_send(): no txbuf\n"));
2671c533a883Shx 		sc->sc_need_reschedule = 1;
2672c533a883Shx 		mutex_exit(&sc->sc_tx_lock);
2673c533a883Shx 		if ((type & IEEE80211_FC0_TYPE_MASK) !=
2674c533a883Shx 		    IEEE80211_FC0_TYPE_DATA) {
2675c533a883Shx 			freemsg(mp);
2676c533a883Shx 		}
2677c533a883Shx 		sc->sc_tx_nobuf++;
2678c533a883Shx 		err = IWK_FAIL;
2679c533a883Shx 		goto exit;
2680c533a883Shx 	}
2681c533a883Shx 	mutex_exit(&sc->sc_tx_lock);
2682c533a883Shx 
2683c533a883Shx 	hdrlen = sizeof (struct ieee80211_frame);
2684c533a883Shx 
2685c533a883Shx 	m = allocb(msgdsize(mp) + 32, BPRI_MED);
2686c533a883Shx 	if (m == NULL) { /* can not alloc buf, drop this package */
2687c533a883Shx 		cmn_err(CE_WARN,
2688c533a883Shx 		    "iwk_send(): failed to allocate msgbuf\n");
2689c533a883Shx 		freemsg(mp);
2690c533a883Shx 		err = IWK_SUCCESS;
2691c533a883Shx 		goto exit;
2692c533a883Shx 	}
2693c533a883Shx 	for (off = 0, m0 = mp; m0 != NULL; m0 = m0->b_cont) {
2694c533a883Shx 		mblen = MBLKL(m0);
2695c533a883Shx 		(void) memcpy(m->b_rptr + off, m0->b_rptr, mblen);
2696c533a883Shx 		off += mblen;
2697c533a883Shx 	}
2698c533a883Shx 	m->b_wptr += off;
2699c533a883Shx 	freemsg(mp);
2700c533a883Shx 
2701c533a883Shx 	wh = (struct ieee80211_frame *)m->b_rptr;
2702c533a883Shx 
270319d332feSfei feng - Sun Microsystems - Beijing China 	if (ic->ic_opmode == IEEE80211_M_IBSS &&
270419d332feSfei feng - Sun Microsystems - Beijing China 	    (!(IEEE80211_IS_MULTICAST(wh->i_addr1)))) {
270519d332feSfei feng - Sun Microsystems - Beijing China 		mutex_enter(&sc->sc_glock);
270619d332feSfei feng - Sun Microsystems - Beijing China 		mutex_enter(&sc->sc_ibss.node_tb_lock);
270719d332feSfei feng - Sun Microsystems - Beijing China 
270819d332feSfei feng - Sun Microsystems - Beijing China 		/*
270919d332feSfei feng - Sun Microsystems - Beijing China 		 * search for node in ibss node table
271019d332feSfei feng - Sun Microsystems - Beijing China 		 */
271119d332feSfei feng - Sun Microsystems - Beijing China 		for (index1 = IWK_STA_ID;
271219d332feSfei feng - Sun Microsystems - Beijing China 		    index1 < IWK_STATION_COUNT; index1++) {
271319d332feSfei feng - Sun Microsystems - Beijing China 			if (sc->sc_ibss.ibss_node_tb[index1].used &&
271419d332feSfei feng - Sun Microsystems - Beijing China 			    IEEE80211_ADDR_EQ(sc->sc_ibss.
271519d332feSfei feng - Sun Microsystems - Beijing China 			    ibss_node_tb[index1].node.bssid,
271619d332feSfei feng - Sun Microsystems - Beijing China 			    wh->i_addr1)) {
271719d332feSfei feng - Sun Microsystems - Beijing China 				break;
271819d332feSfei feng - Sun Microsystems - Beijing China 			}
271919d332feSfei feng - Sun Microsystems - Beijing China 		}
272019d332feSfei feng - Sun Microsystems - Beijing China 
272119d332feSfei feng - Sun Microsystems - Beijing China 		/*
272219d332feSfei feng - Sun Microsystems - Beijing China 		 * if don't find in ibss node table
272319d332feSfei feng - Sun Microsystems - Beijing China 		 */
272419d332feSfei feng - Sun Microsystems - Beijing China 		if (index1 >= IWK_BROADCAST_ID) {
272519d332feSfei feng - Sun Microsystems - Beijing China 			err = iwk_clean_add_node_ibss(ic,
272619d332feSfei feng - Sun Microsystems - Beijing China 			    wh->i_addr1, &index2);
272719d332feSfei feng - Sun Microsystems - Beijing China 			if (err != IWK_SUCCESS) {
272819d332feSfei feng - Sun Microsystems - Beijing China 				cmn_err(CE_WARN, "iwk_send(): "
272919d332feSfei feng - Sun Microsystems - Beijing China 				    "failed to clean all nodes "
273019d332feSfei feng - Sun Microsystems - Beijing China 				    "and add one node\n");
273119d332feSfei feng - Sun Microsystems - Beijing China 				mutex_exit(&sc->sc_ibss.node_tb_lock);
273219d332feSfei feng - Sun Microsystems - Beijing China 				mutex_exit(&sc->sc_glock);
273319d332feSfei feng - Sun Microsystems - Beijing China 				freemsg(m);
273419d332feSfei feng - Sun Microsystems - Beijing China 				sc->sc_tx_err++;
273519d332feSfei feng - Sun Microsystems - Beijing China 				err = IWK_SUCCESS;
273619d332feSfei feng - Sun Microsystems - Beijing China 				goto exit;
273719d332feSfei feng - Sun Microsystems - Beijing China 			}
273819d332feSfei feng - Sun Microsystems - Beijing China 			index = index2;
273919d332feSfei feng - Sun Microsystems - Beijing China 		} else {
274019d332feSfei feng - Sun Microsystems - Beijing China 			index = index1;
274119d332feSfei feng - Sun Microsystems - Beijing China 		}
274219d332feSfei feng - Sun Microsystems - Beijing China 		mutex_exit(&sc->sc_ibss.node_tb_lock);
274319d332feSfei feng - Sun Microsystems - Beijing China 		mutex_exit(&sc->sc_glock);
274419d332feSfei feng - Sun Microsystems - Beijing China 	}
274519d332feSfei feng - Sun Microsystems - Beijing China 
2746c533a883Shx 	in = ieee80211_find_txnode(ic, wh->i_addr1);
2747c533a883Shx 	if (in == NULL) {
2748c533a883Shx 		cmn_err(CE_WARN, "iwk_send(): failed to find tx node\n");
2749c533a883Shx 		freemsg(m);
2750c533a883Shx 		sc->sc_tx_err++;
2751c533a883Shx 		err = IWK_SUCCESS;
2752c533a883Shx 		goto exit;
2753c533a883Shx 	}
2754c533a883Shx 	(void) ieee80211_encap(ic, m, in);
2755c533a883Shx 
2756c533a883Shx 	cmd->hdr.type = REPLY_TX;
2757c533a883Shx 	cmd->hdr.flags = 0;
2758c533a883Shx 	cmd->hdr.qid = ring->qid;
2759c533a883Shx 	cmd->hdr.idx = ring->cur;
2760c533a883Shx 
2761c533a883Shx 	tx = (iwk_tx_cmd_t *)cmd->data;
2762c533a883Shx 	tx->tx_flags = 0;
2763c533a883Shx 
2764c533a883Shx 	if (IEEE80211_IS_MULTICAST(wh->i_addr1)) {
2765c533a883Shx 		tx->tx_flags &= ~(LE_32(TX_CMD_FLG_ACK_MSK));
2766c533a883Shx 	} else {
2767c533a883Shx 		tx->tx_flags |= LE_32(TX_CMD_FLG_ACK_MSK);
2768c533a883Shx 	}
2769c533a883Shx 
2770c533a883Shx 	if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
2771c533a883Shx 		k = ieee80211_crypto_encap(ic, m);
2772c533a883Shx 		if (k == NULL) {
2773c533a883Shx 			freemsg(m);
2774c533a883Shx 			sc->sc_tx_err++;
2775c533a883Shx 			err = IWK_SUCCESS;
2776c533a883Shx 			goto exit;
2777c533a883Shx 		}
2778c533a883Shx 
2779c533a883Shx 		if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_AES_CCM) {
2780c533a883Shx 			tx->sec_ctl = 2; /* for CCMP */
2781c533a883Shx 			tx->tx_flags |= LE_32(TX_CMD_FLG_ACK_MSK);
2782c533a883Shx 			(void) memcpy(&tx->key, k->wk_key, k->wk_keylen);
2783c533a883Shx 		}
2784c533a883Shx 
2785c533a883Shx 		/* packet header may have moved, reset our local pointer */
2786c533a883Shx 		wh = (struct ieee80211_frame *)m->b_rptr;
2787c533a883Shx 	}
2788c533a883Shx 
2789c533a883Shx 	len = msgdsize(m);
2790c533a883Shx 
2791c533a883Shx #ifdef DEBUG
2792c533a883Shx 	if (iwk_dbg_flags & IWK_DEBUG_TX)
2793c533a883Shx 		ieee80211_dump_pkt((uint8_t *)wh, hdrlen, 0, 0);
2794c533a883Shx #endif
2795c533a883Shx 
2796c533a883Shx 	/* pickup a rate */
2797c533a883Shx 	if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
2798c533a883Shx 	    IEEE80211_FC0_TYPE_MGT) {
2799c533a883Shx 		/* mgmt frames are sent at 1M */
2800c533a883Shx 		rate = in->in_rates.ir_rates[0];
2801c533a883Shx 	} else {
2802c533a883Shx 		/*
280343439c96Shx 		 * do it here for the software way rate control.
280443439c96Shx 		 * later for rate scaling in hardware.
2805c533a883Shx 		 * maybe like the following, for management frame:
2806c533a883Shx 		 * tx->initial_rate_index = LINK_QUAL_MAX_RETRY_NUM - 1;
2807c533a883Shx 		 * for data frame:
2808c533a883Shx 		 * tx->tx_flags |= (LE_32(TX_CMD_FLG_STA_RATE_MSK));
2809c533a883Shx 		 * rate = in->in_rates.ir_rates[in->in_txrate];
2810c533a883Shx 		 * tx->initial_rate_index = 1;
2811c533a883Shx 		 *
2812c533a883Shx 		 * now the txrate is determined in tx cmd flags, set to the
2813c533a883Shx 		 * max value 54M for 11g and 11M for 11b.
2814c533a883Shx 		 */
2815c533a883Shx 
2816c533a883Shx 		if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE) {
2817c533a883Shx 			rate = ic->ic_fixed_rate;
2818c533a883Shx 		} else {
2819c533a883Shx 			rate = in->in_rates.ir_rates[in->in_txrate];
2820c533a883Shx 		}
2821c533a883Shx 	}
2822c533a883Shx 	rate &= IEEE80211_RATE_VAL;
2823c533a883Shx 	IWK_DBG((IWK_DEBUG_TX, "tx rate[%d of %d] = %x",
2824c533a883Shx 	    in->in_txrate, in->in_rates.ir_nrates, rate));
2825c533a883Shx 
2826c533a883Shx 	tx->tx_flags |= (LE_32(TX_CMD_FLG_SEQ_CTL_MSK));
2827c533a883Shx 
2828c533a883Shx 	len0 = roundup(4 + sizeof (iwk_tx_cmd_t) + hdrlen, 4);
2829c533a883Shx 	if (len0 != (4 + sizeof (iwk_tx_cmd_t) + hdrlen))
2830b510adaeSfei feng - Sun Microsystems - Beijing China 		tx->tx_flags |= LE_32(TX_CMD_FLG_MH_PAD_MSK);
2831c533a883Shx 
2832c533a883Shx 	/* retrieve destination node's id */
2833c533a883Shx 	if (IEEE80211_IS_MULTICAST(wh->i_addr1)) {
2834c533a883Shx 		tx->sta_id = IWK_BROADCAST_ID;
2835c533a883Shx 	} else {
283619d332feSfei feng - Sun Microsystems - Beijing China 		if (ic->ic_opmode == IEEE80211_M_IBSS)
283719d332feSfei feng - Sun Microsystems - Beijing China 			tx->sta_id = index;
283819d332feSfei feng - Sun Microsystems - Beijing China 		else
2839cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			tx->sta_id = IWK_AP_ID;
2840c533a883Shx 	}
2841c533a883Shx 
2842c533a883Shx 	if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
2843c533a883Shx 	    IEEE80211_FC0_TYPE_MGT) {
2844c533a883Shx 		/* tell h/w to set timestamp in probe responses */
2845c533a883Shx 		if ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) ==
2846c533a883Shx 		    IEEE80211_FC0_SUBTYPE_PROBE_RESP)
2847c533a883Shx 			tx->tx_flags |= LE_32(TX_CMD_FLG_TSF_MSK);
2848c533a883Shx 
2849c533a883Shx 		if (((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) ==
2850c533a883Shx 		    IEEE80211_FC0_SUBTYPE_ASSOC_REQ) ||
2851c533a883Shx 		    ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) ==
2852c533a883Shx 		    IEEE80211_FC0_SUBTYPE_REASSOC_REQ))
2853b510adaeSfei feng - Sun Microsystems - Beijing China 			tx->timeout.pm_frame_timeout = LE_16(3);
2854c533a883Shx 		else
2855b510adaeSfei feng - Sun Microsystems - Beijing China 			tx->timeout.pm_frame_timeout = LE_16(2);
2856c533a883Shx 	} else
2857c533a883Shx 		tx->timeout.pm_frame_timeout = 0;
2858c533a883Shx 	if (rate == 2 || rate == 4 || rate == 11 || rate == 22)
2859c533a883Shx 		masks |= RATE_MCS_CCK_MSK;
2860c533a883Shx 
2861c533a883Shx 	masks |= RATE_MCS_ANT_B_MSK;
2862b510adaeSfei feng - Sun Microsystems - Beijing China 	tx->rate.r.rate_n_flags = LE_32(iwk_rate_to_plcp(rate) | masks);
2863c533a883Shx 
2864c533a883Shx 	IWK_DBG((IWK_DEBUG_TX, "tx flag = %x",
2865b510adaeSfei feng - Sun Microsystems - Beijing China 	    LE_32(tx->tx_flags)));
2866c533a883Shx 
2867c533a883Shx 	tx->rts_retry_limit = 60;
2868c533a883Shx 	tx->data_retry_limit = 15;
2869c533a883Shx 
2870c533a883Shx 	tx->stop_time.life_time  = LE_32(0xffffffff);
2871c533a883Shx 
2872c533a883Shx 	tx->len = LE_16(len);
2873c533a883Shx 
2874c533a883Shx 	tx->dram_lsb_ptr =
2875b510adaeSfei feng - Sun Microsystems - Beijing China 	    LE_32(data->paddr_cmd + 4 + offsetof(iwk_tx_cmd_t, scratch));
2876c533a883Shx 	tx->dram_msb_ptr = 0;
2877c533a883Shx 	tx->driver_txop = 0;
2878c533a883Shx 	tx->next_frame_len = 0;
2879c533a883Shx 
2880c533a883Shx 	(void) memcpy(tx + 1, m->b_rptr, hdrlen);
2881c533a883Shx 	m->b_rptr += hdrlen;
2882c533a883Shx 	(void) memcpy(data->dma_data.mem_va, m->b_rptr, len - hdrlen);
2883c533a883Shx 
2884c533a883Shx 	IWK_DBG((IWK_DEBUG_TX, "sending data: qid=%d idx=%d len=%d",
2885c533a883Shx 	    ring->qid, ring->cur, len));
2886c533a883Shx 
2887c533a883Shx 	/*
2888c533a883Shx 	 * first segment includes the tx cmd plus the 802.11 header,
2889c533a883Shx 	 * the second includes the remaining of the 802.11 frame.
2890c533a883Shx 	 */
2891b510adaeSfei feng - Sun Microsystems - Beijing China 	desc->val0 = 2 << 24;
2892b510adaeSfei feng - Sun Microsystems - Beijing China 	desc->pa[0].tb1_addr = data->paddr_cmd;
2893c533a883Shx 	desc->pa[0].val1 = ((len0 << 4) & 0xfff0) |
2894c533a883Shx 	    ((data->dma_data.cookie.dmac_address & 0xffff) << 16);
2895c533a883Shx 	desc->pa[0].val2 =
2896c533a883Shx 	    ((data->dma_data.cookie.dmac_address & 0xffff0000) >> 16) |
2897c533a883Shx 	    ((len - hdrlen) << 20);
2898c533a883Shx 	IWK_DBG((IWK_DEBUG_TX, "phy addr1 = 0x%x phy addr2 = 0x%x "
2899c533a883Shx 	    "len1 = 0x%x, len2 = 0x%x val1 = 0x%x val2 = 0x%x",
2900c533a883Shx 	    data->paddr_cmd, data->dma_data.cookie.dmac_address,
2901b510adaeSfei feng - Sun Microsystems - Beijing China 	    len0, len - hdrlen, LE_32(desc->pa[0].val1),
2902b510adaeSfei feng - Sun Microsystems - Beijing China 	    LE_32(desc->pa[0].val2)));
2903c533a883Shx 
2904c533a883Shx 	mutex_enter(&sc->sc_tx_lock);
2905c533a883Shx 	ring->queued++;
2906c533a883Shx 	mutex_exit(&sc->sc_tx_lock);
2907c533a883Shx 
2908c533a883Shx 	/* kick ring */
2909cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	sc->sc_shared->queues_byte_cnt_tbls[ring->qid].
2910cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	    tfd_offset[ring->cur].val = 8 + len;
2911c533a883Shx 	if (ring->cur < IWK_MAX_WIN_SIZE) {
2912c533a883Shx 		sc->sc_shared->queues_byte_cnt_tbls[ring->qid].
2913c533a883Shx 		    tfd_offset[IWK_QUEUE_SIZE + ring->cur].val = 8 + len;
2914c533a883Shx 	}
2915c533a883Shx 
2916c533a883Shx 	IWK_DMA_SYNC(data->dma_data, DDI_DMA_SYNC_FORDEV);
2917c533a883Shx 	IWK_DMA_SYNC(ring->dma_desc, DDI_DMA_SYNC_FORDEV);
2918c533a883Shx 
2919c533a883Shx 	ring->cur = (ring->cur + 1) % ring->count;
2920c533a883Shx 	IWK_WRITE(sc, HBUS_TARG_WRPTR, ring->qid << 8 | ring->cur);
2921c533a883Shx 	freemsg(m);
2922c533a883Shx 	/* release node reference */
2923c533a883Shx 	ieee80211_free_node(in);
2924c533a883Shx 
2925c533a883Shx 	ic->ic_stats.is_tx_bytes += len;
2926c533a883Shx 	ic->ic_stats.is_tx_frags++;
2927c533a883Shx 
2928c533a883Shx 	if (sc->sc_tx_timer == 0)
29296f12def4Spengcheng chen - Sun Microsystems - Beijing China 		sc->sc_tx_timer = 4;
29306f12def4Spengcheng chen - Sun Microsystems - Beijing China 
2931c533a883Shx exit:
2932c533a883Shx 	return (err);
2933c533a883Shx }
2934c533a883Shx 
2935c533a883Shx static void
iwk_m_ioctl(void * arg,queue_t * wq,mblk_t * mp)2936c533a883Shx iwk_m_ioctl(void* arg, queue_t *wq, mblk_t *mp)
2937c533a883Shx {
2938c533a883Shx 	iwk_sc_t	*sc  = (iwk_sc_t *)arg;
2939c533a883Shx 	ieee80211com_t	*ic = &sc->sc_ic;
294019d332feSfei feng - Sun Microsystems - Beijing China 
294119d332feSfei feng - Sun Microsystems - Beijing China 	enum ieee80211_opmode		oldmod;
294219d332feSfei feng - Sun Microsystems - Beijing China 	iwk_tx_power_table_cmd_t	txpower;
294319d332feSfei feng - Sun Microsystems - Beijing China 	iwk_add_sta_t			node;
294419d332feSfei feng - Sun Microsystems - Beijing China 	iwk_link_quality_cmd_t		link_quality;
294519d332feSfei feng - Sun Microsystems - Beijing China 	uint16_t			masks = 0;
294619d332feSfei feng - Sun Microsystems - Beijing China 	int				i, err, err1;
294719d332feSfei feng - Sun Microsystems - Beijing China 
294819d332feSfei feng - Sun Microsystems - Beijing China 	oldmod = ic->ic_opmode;
2949c533a883Shx 
2950c533a883Shx 	err = ieee80211_ioctl(ic, wq, mp);
2951cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
295219d332feSfei feng - Sun Microsystems - Beijing China 	/*
295319d332feSfei feng - Sun Microsystems - Beijing China 	 * return to STA mode
295419d332feSfei feng - Sun Microsystems - Beijing China 	 */
295519d332feSfei feng - Sun Microsystems - Beijing China 	if ((0 == err || ENETRESET == err) && (oldmod != ic->ic_opmode) &&
295619d332feSfei feng - Sun Microsystems - Beijing China 	    (ic->ic_opmode == IEEE80211_M_STA)) {
295719d332feSfei feng - Sun Microsystems - Beijing China 		/* configure rxon */
295819d332feSfei feng - Sun Microsystems - Beijing China 		(void) memset(&sc->sc_config, 0, sizeof (iwk_rxon_cmd_t));
295919d332feSfei feng - Sun Microsystems - Beijing China 		IEEE80211_ADDR_COPY(sc->sc_config.node_addr, ic->ic_macaddr);
296019d332feSfei feng - Sun Microsystems - Beijing China 		IEEE80211_ADDR_COPY(sc->sc_config.wlap_bssid, ic->ic_macaddr);
2961b510adaeSfei feng - Sun Microsystems - Beijing China 		sc->sc_config.chan =
2962b510adaeSfei feng - Sun Microsystems - Beijing China 		    LE_16(ieee80211_chan2ieee(ic, ic->ic_curchan));
2963b510adaeSfei feng - Sun Microsystems - Beijing China 		sc->sc_config.flags = LE_32(RXON_FLG_TSF2HOST_MSK |
296419d332feSfei feng - Sun Microsystems - Beijing China 		    RXON_FLG_AUTO_DETECT_MSK |
296519d332feSfei feng - Sun Microsystems - Beijing China 		    RXON_FLG_BAND_24G_MSK);
2966b510adaeSfei feng - Sun Microsystems - Beijing China 		sc->sc_config.flags &= LE_32(~RXON_FLG_CCK_MSK);
296719d332feSfei feng - Sun Microsystems - Beijing China 		switch (ic->ic_opmode) {
296819d332feSfei feng - Sun Microsystems - Beijing China 		case IEEE80211_M_STA:
296919d332feSfei feng - Sun Microsystems - Beijing China 			sc->sc_config.dev_type = RXON_DEV_TYPE_ESS;
297019d332feSfei feng - Sun Microsystems - Beijing China 			sc->sc_config.filter_flags |=
297119d332feSfei feng - Sun Microsystems - Beijing China 			    LE_32(RXON_FILTER_ACCEPT_GRP_MSK |
297219d332feSfei feng - Sun Microsystems - Beijing China 			    RXON_FILTER_DIS_DECRYPT_MSK |
297319d332feSfei feng - Sun Microsystems - Beijing China 			    RXON_FILTER_DIS_GRP_DECRYPT_MSK);
297419d332feSfei feng - Sun Microsystems - Beijing China 			break;
297519d332feSfei feng - Sun Microsystems - Beijing China 		case IEEE80211_M_IBSS:
297619d332feSfei feng - Sun Microsystems - Beijing China 		case IEEE80211_M_AHDEMO:
297719d332feSfei feng - Sun Microsystems - Beijing China 			sc->sc_config.dev_type = RXON_DEV_TYPE_IBSS;
2978b510adaeSfei feng - Sun Microsystems - Beijing China 			sc->sc_config.flags |=
2979b510adaeSfei feng - Sun Microsystems - Beijing China 			    LE_32(RXON_FLG_SHORT_PREAMBLE_MSK);
298019d332feSfei feng - Sun Microsystems - Beijing China 			sc->sc_config.filter_flags =
298119d332feSfei feng - Sun Microsystems - Beijing China 			    LE_32(RXON_FILTER_ACCEPT_GRP_MSK |
298219d332feSfei feng - Sun Microsystems - Beijing China 			    RXON_FILTER_DIS_DECRYPT_MSK |
298319d332feSfei feng - Sun Microsystems - Beijing China 			    RXON_FILTER_DIS_GRP_DECRYPT_MSK);
298419d332feSfei feng - Sun Microsystems - Beijing China 			break;
298519d332feSfei feng - Sun Microsystems - Beijing China 		case IEEE80211_M_HOSTAP:
298619d332feSfei feng - Sun Microsystems - Beijing China 			sc->sc_config.dev_type = RXON_DEV_TYPE_AP;
298719d332feSfei feng - Sun Microsystems - Beijing China 			break;
298819d332feSfei feng - Sun Microsystems - Beijing China 		case IEEE80211_M_MONITOR:
298919d332feSfei feng - Sun Microsystems - Beijing China 			sc->sc_config.dev_type = RXON_DEV_TYPE_SNIFFER;
299019d332feSfei feng - Sun Microsystems - Beijing China 			sc->sc_config.filter_flags |=
299119d332feSfei feng - Sun Microsystems - Beijing China 			    LE_32(RXON_FILTER_ACCEPT_GRP_MSK |
299219d332feSfei feng - Sun Microsystems - Beijing China 			    RXON_FILTER_CTL2HOST_MSK |
299319d332feSfei feng - Sun Microsystems - Beijing China 			    RXON_FILTER_PROMISC_MSK);
299419d332feSfei feng - Sun Microsystems - Beijing China 			break;
299519d332feSfei feng - Sun Microsystems - Beijing China 		}
299619d332feSfei feng - Sun Microsystems - Beijing China 		sc->sc_config.cck_basic_rates  = 0x0f;
299719d332feSfei feng - Sun Microsystems - Beijing China 		sc->sc_config.ofdm_basic_rates = 0xff;
299819d332feSfei feng - Sun Microsystems - Beijing China 		sc->sc_config.ofdm_ht_single_stream_basic_rates = 0xff;
299919d332feSfei feng - Sun Microsystems - Beijing China 		sc->sc_config.ofdm_ht_dual_stream_basic_rates = 0xff;
300019d332feSfei feng - Sun Microsystems - Beijing China 		/* set antenna */
300119d332feSfei feng - Sun Microsystems - Beijing China 		mutex_enter(&sc->sc_glock);
3002b510adaeSfei feng - Sun Microsystems - Beijing China 		sc->sc_config.rx_chain = LE_16(RXON_RX_CHAIN_DRIVER_FORCE_MSK |
3003b510adaeSfei feng - Sun Microsystems - Beijing China 		    (0x7 << RXON_RX_CHAIN_VALID_POS) |
300419d332feSfei feng - Sun Microsystems - Beijing China 		    (0x6 << RXON_RX_CHAIN_FORCE_SEL_POS) |
300519d332feSfei feng - Sun Microsystems - Beijing China 		    (0x7 << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS));
300619d332feSfei feng - Sun Microsystems - Beijing China 		err1 = iwk_cmd(sc, REPLY_RXON, &sc->sc_config,
300719d332feSfei feng - Sun Microsystems - Beijing China 		    sizeof (iwk_rxon_cmd_t), 1);
300819d332feSfei feng - Sun Microsystems - Beijing China 		if (err1 != IWK_SUCCESS) {
300919d332feSfei feng - Sun Microsystems - Beijing China 			cmn_err(CE_WARN, "iwk_m_ioctl(): "
301019d332feSfei feng - Sun Microsystems - Beijing China 			    "failed to set configure command"
301119d332feSfei feng - Sun Microsystems - Beijing China 			    " please run (ifconfig unplumb and"
301219d332feSfei feng - Sun Microsystems - Beijing China 			    " ifconfig plumb)\n");
301319d332feSfei feng - Sun Microsystems - Beijing China 		}
301419d332feSfei feng - Sun Microsystems - Beijing China 		/*
301519d332feSfei feng - Sun Microsystems - Beijing China 		 * set Tx power for 2.4GHz channels
301619d332feSfei feng - Sun Microsystems - Beijing China 		 * (need further investigation. fix tx power at present)
301719d332feSfei feng - Sun Microsystems - Beijing China 		 */
301819d332feSfei feng - Sun Microsystems - Beijing China 		(void) memset(&txpower, 0, sizeof (txpower));
301919d332feSfei feng - Sun Microsystems - Beijing China 		txpower.band = 1; /* for 2.4G */
302019d332feSfei feng - Sun Microsystems - Beijing China 		txpower.channel = sc->sc_config.chan;
302119d332feSfei feng - Sun Microsystems - Beijing China 		txpower.channel_normal_width = 0;
302219d332feSfei feng - Sun Microsystems - Beijing China 		for (i = 0; i < POWER_TABLE_NUM_HT_OFDM_ENTRIES; i++) {
302319d332feSfei feng - Sun Microsystems - Beijing China 			txpower.tx_power.ht_ofdm_power[i].
3024b510adaeSfei feng - Sun Microsystems - Beijing China 			    s.ramon_tx_gain = LE_16(0x3f3f);
302519d332feSfei feng - Sun Microsystems - Beijing China 			txpower.tx_power.ht_ofdm_power[i].
3026b510adaeSfei feng - Sun Microsystems - Beijing China 			    s.dsp_predis_atten = LE_16(110 | (110 << 8));
302719d332feSfei feng - Sun Microsystems - Beijing China 		}
3028b510adaeSfei feng - Sun Microsystems - Beijing China 		txpower.tx_power.legacy_cck_power.s.
3029b510adaeSfei feng - Sun Microsystems - Beijing China 		    ramon_tx_gain = LE_16(0x3f3f);
3030b510adaeSfei feng - Sun Microsystems - Beijing China 		txpower.tx_power.legacy_cck_power.s.
3031b510adaeSfei feng - Sun Microsystems - Beijing China 		    dsp_predis_atten = LE_16(110 | (110 << 8));
303219d332feSfei feng - Sun Microsystems - Beijing China 		err1 = iwk_cmd(sc, REPLY_TX_PWR_TABLE_CMD, &txpower,
303319d332feSfei feng - Sun Microsystems - Beijing China 		    sizeof (txpower), 1);
303419d332feSfei feng - Sun Microsystems - Beijing China 		if (err1 != IWK_SUCCESS) {
303519d332feSfei feng - Sun Microsystems - Beijing China 			cmn_err(CE_WARN, "iwk_m_ioctl(): failed to set txpower"
303619d332feSfei feng - Sun Microsystems - Beijing China 			    " please run (ifconfig unplumb "
303719d332feSfei feng - Sun Microsystems - Beijing China 			    "and ifconfig plumb)\n");
303819d332feSfei feng - Sun Microsystems - Beijing China 		}
303919d332feSfei feng - Sun Microsystems - Beijing China 		/* add broadcast node so that we can send broadcast frame */
304019d332feSfei feng - Sun Microsystems - Beijing China 		(void) memset(&node, 0, sizeof (node));
304119d332feSfei feng - Sun Microsystems - Beijing China 		(void) memset(node.bssid, 0xff, 6);
304219d332feSfei feng - Sun Microsystems - Beijing China 		node.id = IWK_BROADCAST_ID;
304319d332feSfei feng - Sun Microsystems - Beijing China 		err1 = iwk_cmd(sc, REPLY_ADD_STA, &node, sizeof (node), 1);
304419d332feSfei feng - Sun Microsystems - Beijing China 		if (err1 != IWK_SUCCESS) {
304519d332feSfei feng - Sun Microsystems - Beijing China 			cmn_err(CE_WARN, "iwk_m_ioctl(): "
304619d332feSfei feng - Sun Microsystems - Beijing China 			    "failed to add broadcast node\n");
304719d332feSfei feng - Sun Microsystems - Beijing China 		}
304819d332feSfei feng - Sun Microsystems - Beijing China 
304919d332feSfei feng - Sun Microsystems - Beijing China 		/* TX_LINK_QUALITY cmd */
305019d332feSfei feng - Sun Microsystems - Beijing China 		(void) memset(&link_quality, 0, sizeof (link_quality));
305119d332feSfei feng - Sun Microsystems - Beijing China 		for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) {
305219d332feSfei feng - Sun Microsystems - Beijing China 			masks |= RATE_MCS_CCK_MSK;
305319d332feSfei feng - Sun Microsystems - Beijing China 			masks |= RATE_MCS_ANT_B_MSK;
305419d332feSfei feng - Sun Microsystems - Beijing China 			masks &= ~RATE_MCS_ANT_A_MSK;
305519d332feSfei feng - Sun Microsystems - Beijing China 			link_quality.rate_n_flags[i] =
3056b510adaeSfei feng - Sun Microsystems - Beijing China 			    LE_32(iwk_rate_to_plcp(2) | masks);
305719d332feSfei feng - Sun Microsystems - Beijing China 		}
305819d332feSfei feng - Sun Microsystems - Beijing China 		link_quality.general_params.single_stream_ant_msk = 2;
305919d332feSfei feng - Sun Microsystems - Beijing China 		link_quality.general_params.dual_stream_ant_msk = 3;
306019d332feSfei feng - Sun Microsystems - Beijing China 		link_quality.agg_params.agg_dis_start_th = 3;
306119d332feSfei feng - Sun Microsystems - Beijing China 		link_quality.agg_params.agg_time_limit = LE_16(4000);
306219d332feSfei feng - Sun Microsystems - Beijing China 		link_quality.sta_id = IWK_BROADCAST_ID;
306319d332feSfei feng - Sun Microsystems - Beijing China 		err1 = iwk_cmd(sc, REPLY_TX_LINK_QUALITY_CMD, &link_quality,
306419d332feSfei feng - Sun Microsystems - Beijing China 		    sizeof (link_quality), 1);
306519d332feSfei feng - Sun Microsystems - Beijing China 		if (err1 != IWK_SUCCESS) {
306619d332feSfei feng - Sun Microsystems - Beijing China 			cmn_err(CE_WARN, "iwk_m_ioctl(): "
306719d332feSfei feng - Sun Microsystems - Beijing China 			    "failed to config link quality table\n");
306819d332feSfei feng - Sun Microsystems - Beijing China 		}
306919d332feSfei feng - Sun Microsystems - Beijing China 		mutex_exit(&sc->sc_glock);
307019d332feSfei feng - Sun Microsystems - Beijing China 		ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
307119d332feSfei feng - Sun Microsystems - Beijing China 	}
307219d332feSfei feng - Sun Microsystems - Beijing China 
3073c533a883Shx 	if (err == ENETRESET) {
307443439c96Shx 		/*
307543439c96Shx 		 * This is special for the hidden AP connection.
307643439c96Shx 		 * In any case, we should make sure only one 'scan'
307743439c96Shx 		 * in the driver for a 'connect' CLI command. So
307843439c96Shx 		 * when connecting to a hidden AP, the scan is just
307943439c96Shx 		 * sent out to the air when we know the desired
308043439c96Shx 		 * essid of the AP we want to connect.
308143439c96Shx 		 */
308243439c96Shx 		if (ic->ic_des_esslen) {
3083c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			if (sc->sc_flags & IWK_F_RUNNING) {
3084c50ced99Spengcheng chen - Sun Microsystems - Beijing China 				iwk_m_stop(sc);
3085c50ced99Spengcheng chen - Sun Microsystems - Beijing China 				(void) iwk_m_start(sc);
3086c50ced99Spengcheng chen - Sun Microsystems - Beijing China 				(void) ieee80211_new_state(ic,
3087c50ced99Spengcheng chen - Sun Microsystems - Beijing China 				    IEEE80211_S_SCAN, -1);
3088c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			}
308943439c96Shx 		}
3090c533a883Shx 	}
3091c533a883Shx }
3092c533a883Shx 
3093bcb5c89dSSowmini Varadhan /*
3094bcb5c89dSSowmini Varadhan  * callback functions for set/get properties
3095bcb5c89dSSowmini Varadhan  */
30960dc2366fSVenugopal Iyer 
3097bcb5c89dSSowmini Varadhan static int
iwk_m_getprop(void * arg,const char * pr_name,mac_prop_id_t wldp_pr_num,uint_t wldp_length,void * wldp_buf)3098bcb5c89dSSowmini Varadhan iwk_m_getprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
30990dc2366fSVenugopal Iyer     uint_t wldp_length, void *wldp_buf)
3100bcb5c89dSSowmini Varadhan {
3101bcb5c89dSSowmini Varadhan 	int		err = 0;
3102bcb5c89dSSowmini Varadhan 	iwk_sc_t	*sc = (iwk_sc_t *)arg;
3103bcb5c89dSSowmini Varadhan 
3104bcb5c89dSSowmini Varadhan 	err = ieee80211_getprop(&sc->sc_ic, pr_name, wldp_pr_num,
31050dc2366fSVenugopal Iyer 	    wldp_length, wldp_buf);
3106bcb5c89dSSowmini Varadhan 
3107bcb5c89dSSowmini Varadhan 	return (err);
3108bcb5c89dSSowmini Varadhan }
31090dc2366fSVenugopal Iyer 
3110bcb5c89dSSowmini Varadhan static int
iwk_m_setprop(void * arg,const char * pr_name,mac_prop_id_t wldp_pr_num,uint_t wldp_length,const void * wldp_buf)3111bcb5c89dSSowmini Varadhan iwk_m_setprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
3112bcb5c89dSSowmini Varadhan     uint_t wldp_length, const void *wldp_buf)
3113bcb5c89dSSowmini Varadhan {
3114bcb5c89dSSowmini Varadhan 	int		err;
3115bcb5c89dSSowmini Varadhan 	iwk_sc_t	*sc = (iwk_sc_t *)arg;
3116bcb5c89dSSowmini Varadhan 	ieee80211com_t	*ic = &sc->sc_ic;
3117bcb5c89dSSowmini Varadhan 
3118bcb5c89dSSowmini Varadhan 	err = ieee80211_setprop(ic, pr_name, wldp_pr_num, wldp_length,
3119bcb5c89dSSowmini Varadhan 	    wldp_buf);
3120bcb5c89dSSowmini Varadhan 
3121bcb5c89dSSowmini Varadhan 	if (err == ENETRESET) {
3122bcb5c89dSSowmini Varadhan 		if (ic->ic_des_esslen) {
3123c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			if (sc->sc_flags & IWK_F_RUNNING) {
3124c50ced99Spengcheng chen - Sun Microsystems - Beijing China 				iwk_m_stop(sc);
3125c50ced99Spengcheng chen - Sun Microsystems - Beijing China 				(void) iwk_m_start(sc);
3126c50ced99Spengcheng chen - Sun Microsystems - Beijing China 				(void) ieee80211_new_state(ic,
3127c50ced99Spengcheng chen - Sun Microsystems - Beijing China 				    IEEE80211_S_SCAN, -1);
3128c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			}
3129bcb5c89dSSowmini Varadhan 		}
3130bcb5c89dSSowmini Varadhan 		err = 0;
3131bcb5c89dSSowmini Varadhan 	}
3132bcb5c89dSSowmini Varadhan 
3133bcb5c89dSSowmini Varadhan 	return (err);
3134bcb5c89dSSowmini Varadhan }
3135bcb5c89dSSowmini Varadhan 
31360dc2366fSVenugopal Iyer static void
iwk_m_propinfo(void * arg,const char * pr_name,mac_prop_id_t wldp_pr_num,mac_prop_info_handle_t mph)31370dc2366fSVenugopal Iyer iwk_m_propinfo(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
31380dc2366fSVenugopal Iyer     mac_prop_info_handle_t mph)
31390dc2366fSVenugopal Iyer {
31400dc2366fSVenugopal Iyer 	iwk_sc_t	*sc = (iwk_sc_t *)arg;
31410dc2366fSVenugopal Iyer 	ieee80211com_t	*ic = &sc->sc_ic;
31420dc2366fSVenugopal Iyer 
31430dc2366fSVenugopal Iyer 	ieee80211_propinfo(ic, pr_name, wldp_pr_num, mph);
31440dc2366fSVenugopal Iyer }
31450dc2366fSVenugopal Iyer 
3146c533a883Shx /*ARGSUSED*/
3147c533a883Shx static int
iwk_m_stat(void * arg,uint_t stat,uint64_t * val)3148c533a883Shx iwk_m_stat(void *arg, uint_t stat, uint64_t *val)
3149c533a883Shx {
3150c533a883Shx 	iwk_sc_t	*sc  = (iwk_sc_t *)arg;
3151c533a883Shx 	ieee80211com_t	*ic = &sc->sc_ic;
3152503bf41cSpengcheng chen - Sun Microsystems - Beijing China 	ieee80211_node_t *in;
3153c533a883Shx 
3154c533a883Shx 	mutex_enter(&sc->sc_glock);
3155c533a883Shx 	switch (stat) {
3156c533a883Shx 	case MAC_STAT_IFSPEED:
3157503bf41cSpengcheng chen - Sun Microsystems - Beijing China 		in = ic->ic_bss;
3158c533a883Shx 		*val = ((ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE) ?
3159503bf41cSpengcheng chen - Sun Microsystems - Beijing China 		    IEEE80211_RATE(in->in_txrate) :
3160503bf41cSpengcheng chen - Sun Microsystems - Beijing China 		    ic->ic_fixed_rate) / 2 * 1000000;
3161c533a883Shx 		break;
3162c533a883Shx 	case MAC_STAT_NOXMTBUF:
3163c533a883Shx 		*val = sc->sc_tx_nobuf;
3164c533a883Shx 		break;
3165c533a883Shx 	case MAC_STAT_NORCVBUF:
3166c533a883Shx 		*val = sc->sc_rx_nobuf;
3167c533a883Shx 		break;
3168c533a883Shx 	case MAC_STAT_IERRORS:
3169c533a883Shx 		*val = sc->sc_rx_err;
3170c533a883Shx 		break;
3171c533a883Shx 	case MAC_STAT_RBYTES:
3172c533a883Shx 		*val = ic->ic_stats.is_rx_bytes;
3173c533a883Shx 		break;
3174c533a883Shx 	case MAC_STAT_IPACKETS:
3175c533a883Shx 		*val = ic->ic_stats.is_rx_frags;
3176c533a883Shx 		break;
3177c533a883Shx 	case MAC_STAT_OBYTES:
3178c533a883Shx 		*val = ic->ic_stats.is_tx_bytes;
3179c533a883Shx 		break;
3180c533a883Shx 	case MAC_STAT_OPACKETS:
3181c533a883Shx 		*val = ic->ic_stats.is_tx_frags;
3182c533a883Shx 		break;
3183c533a883Shx 	case MAC_STAT_OERRORS:
3184c533a883Shx 	case WIFI_STAT_TX_FAILED:
3185c533a883Shx 		*val = sc->sc_tx_err;
3186c533a883Shx 		break;
3187c533a883Shx 	case WIFI_STAT_TX_RETRANS:
3188c533a883Shx 		*val = sc->sc_tx_retries;
3189c533a883Shx 		break;
3190c533a883Shx 	case WIFI_STAT_FCS_ERRORS:
3191c533a883Shx 	case WIFI_STAT_WEP_ERRORS:
3192c533a883Shx 	case WIFI_STAT_TX_FRAGS:
3193c533a883Shx 	case WIFI_STAT_MCAST_TX:
3194c533a883Shx 	case WIFI_STAT_RTS_SUCCESS:
3195c533a883Shx 	case WIFI_STAT_RTS_FAILURE:
3196c533a883Shx 	case WIFI_STAT_ACK_FAILURE:
3197c533a883Shx 	case WIFI_STAT_RX_FRAGS:
3198c533a883Shx 	case WIFI_STAT_MCAST_RX:
3199c533a883Shx 	case WIFI_STAT_RX_DUPS:
3200c533a883Shx 		mutex_exit(&sc->sc_glock);
3201c533a883Shx 		return (ieee80211_stat(ic, stat, val));
3202c533a883Shx 	default:
3203c533a883Shx 		mutex_exit(&sc->sc_glock);
3204c533a883Shx 		return (ENOTSUP);
3205c533a883Shx 	}
3206c533a883Shx 	mutex_exit(&sc->sc_glock);
3207c533a883Shx 
3208c533a883Shx 	return (IWK_SUCCESS);
3209c533a883Shx 
3210c533a883Shx }
3211c533a883Shx 
3212c533a883Shx static int
iwk_m_start(void * arg)3213c533a883Shx iwk_m_start(void *arg)
3214c533a883Shx {
3215c533a883Shx 	iwk_sc_t *sc = (iwk_sc_t *)arg;
3216c533a883Shx 	ieee80211com_t	*ic = &sc->sc_ic;
3217c533a883Shx 	int err;
3218c533a883Shx 
3219c533a883Shx 	err = iwk_init(sc);
3220c533a883Shx 
3221c533a883Shx 	if (err != IWK_SUCCESS) {
322243439c96Shx 		/*
322343439c96Shx 		 * The hw init err(eg. RF is OFF). Return Success to make
322443439c96Shx 		 * the 'plumb' succeed. The iwk_thread() tries to re-init
322543439c96Shx 		 * background.
322643439c96Shx 		 */
322743439c96Shx 		mutex_enter(&sc->sc_glock);
322843439c96Shx 		sc->sc_flags |= IWK_F_HW_ERR_RECOVER;
322943439c96Shx 		mutex_exit(&sc->sc_glock);
323043439c96Shx 		return (IWK_SUCCESS);
3231c533a883Shx 	}
323243439c96Shx 
3233c533a883Shx 	ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
3234c533a883Shx 
323543439c96Shx 	mutex_enter(&sc->sc_glock);
323643439c96Shx 	sc->sc_flags |= IWK_F_RUNNING;
323743439c96Shx 	mutex_exit(&sc->sc_glock);
323843439c96Shx 
323943439c96Shx 	return (IWK_SUCCESS);
3240c533a883Shx }
3241c533a883Shx 
3242c533a883Shx static void
iwk_m_stop(void * arg)3243c533a883Shx iwk_m_stop(void *arg)
3244c533a883Shx {
3245c533a883Shx 	iwk_sc_t *sc = (iwk_sc_t *)arg;
3246c533a883Shx 	ieee80211com_t	*ic = &sc->sc_ic;
3247c533a883Shx 
3248c533a883Shx 	iwk_stop(sc);
3249c533a883Shx 	ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
3250f3c4902cSpengcheng chen - Sun Microsystems - Beijing China 	ieee80211_stop_watchdog(ic);
3251c533a883Shx 	mutex_enter(&sc->sc_mt_lock);
3252c533a883Shx 	sc->sc_flags &= ~IWK_F_HW_ERR_RECOVER;
325343439c96Shx 	sc->sc_flags &= ~IWK_F_RATE_AUTO_CTL;
3254c533a883Shx 	mutex_exit(&sc->sc_mt_lock);
325543439c96Shx 	mutex_enter(&sc->sc_glock);
325643439c96Shx 	sc->sc_flags &= ~IWK_F_RUNNING;
325743439c96Shx 	mutex_exit(&sc->sc_glock);
3258c533a883Shx }
3259c533a883Shx 
3260c533a883Shx /*ARGSUSED*/
3261c533a883Shx static int
iwk_m_unicst(void * arg,const uint8_t * macaddr)3262c533a883Shx iwk_m_unicst(void *arg, const uint8_t *macaddr)
3263c533a883Shx {
3264c533a883Shx 	iwk_sc_t *sc = (iwk_sc_t *)arg;
3265c533a883Shx 	ieee80211com_t	*ic = &sc->sc_ic;
3266c533a883Shx 	int err;
3267c533a883Shx 
3268c533a883Shx 	if (!IEEE80211_ADDR_EQ(ic->ic_macaddr, macaddr)) {
3269c533a883Shx 		IEEE80211_ADDR_COPY(ic->ic_macaddr, macaddr);
3270c533a883Shx 		mutex_enter(&sc->sc_glock);
3271c533a883Shx 		err = iwk_config(sc);
3272c533a883Shx 		mutex_exit(&sc->sc_glock);
3273c533a883Shx 		if (err != IWK_SUCCESS) {
3274c533a883Shx 			cmn_err(CE_WARN,
3275c533a883Shx 			    "iwk_m_unicst(): "
3276c533a883Shx 			    "failed to configure device\n");
3277c533a883Shx 			goto fail;
3278c533a883Shx 		}
3279c533a883Shx 	}
3280c533a883Shx 	return (IWK_SUCCESS);
3281c533a883Shx fail:
3282c533a883Shx 	return (err);
3283c533a883Shx }
3284c533a883Shx 
3285c533a883Shx /*ARGSUSED*/
3286c533a883Shx static int
iwk_m_multicst(void * arg,boolean_t add,const uint8_t * m)3287c533a883Shx iwk_m_multicst(void *arg, boolean_t add, const uint8_t *m)
3288c533a883Shx {
3289c533a883Shx 	return (IWK_SUCCESS);
3290c533a883Shx }
3291c533a883Shx 
3292c533a883Shx /*ARGSUSED*/
3293c533a883Shx static int
iwk_m_promisc(void * arg,boolean_t on)3294c533a883Shx iwk_m_promisc(void *arg, boolean_t on)
3295c533a883Shx {
3296c533a883Shx 	return (IWK_SUCCESS);
3297c533a883Shx }
3298c533a883Shx 
3299c533a883Shx static void
iwk_thread(iwk_sc_t * sc)3300c533a883Shx iwk_thread(iwk_sc_t *sc)
3301c533a883Shx {
3302c533a883Shx 	ieee80211com_t	*ic = &sc->sc_ic;
330343439c96Shx 	clock_t clk;
3304c533a883Shx 	int times = 0, err, n = 0, timeout = 0;
330543439c96Shx 	uint32_t tmp;
3306c533a883Shx 
3307c533a883Shx 	mutex_enter(&sc->sc_mt_lock);
3308c533a883Shx 	while (sc->sc_mf_thread_switch) {
330943439c96Shx 		tmp = IWK_READ(sc, CSR_GP_CNTRL);
331043439c96Shx 		if (tmp & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) {
331143439c96Shx 			sc->sc_flags &= ~IWK_F_RADIO_OFF;
331243439c96Shx 		} else {
331343439c96Shx 			sc->sc_flags |= IWK_F_RADIO_OFF;
331443439c96Shx 		}
331543439c96Shx 		/*
3316d62cb7ffShx 		 * If in SUSPEND or the RF is OFF, do nothing
331743439c96Shx 		 */
3318d62cb7ffShx 		if ((sc->sc_flags & IWK_F_SUSPEND) ||
3319d62cb7ffShx 		    (sc->sc_flags & IWK_F_RADIO_OFF)) {
332043439c96Shx 			mutex_exit(&sc->sc_mt_lock);
332143439c96Shx 			delay(drv_usectohz(100000));
332243439c96Shx 			mutex_enter(&sc->sc_mt_lock);
332343439c96Shx 			continue;
332443439c96Shx 		}
332543439c96Shx 
3326c533a883Shx 		/*
3327c533a883Shx 		 * recovery fatal error
3328c533a883Shx 		 */
3329c533a883Shx 		if (ic->ic_mach &&
3330c533a883Shx 		    (sc->sc_flags & IWK_F_HW_ERR_RECOVER)) {
3331c533a883Shx 
3332c533a883Shx 			IWK_DBG((IWK_DEBUG_FW,
3333c533a883Shx 			    "iwk_thread(): "
3334c533a883Shx 			    "try to recover fatal hw error: %d\n", times++));
3335c533a883Shx 
3336c533a883Shx 			iwk_stop(sc);
3337c533a883Shx 
33386f12def4Spengcheng chen - Sun Microsystems - Beijing China 			if (IWK_CHK_FAST_RECOVER(sc)) {
33396f12def4Spengcheng chen - Sun Microsystems - Beijing China 				/* save runtime configuration */
33406f12def4Spengcheng chen - Sun Microsystems - Beijing China 				bcopy(&sc->sc_config, &sc->sc_config_save,
33416f12def4Spengcheng chen - Sun Microsystems - Beijing China 				    sizeof (sc->sc_config));
33426f12def4Spengcheng chen - Sun Microsystems - Beijing China 			} else {
33436f12def4Spengcheng chen - Sun Microsystems - Beijing China 				mutex_exit(&sc->sc_mt_lock);
33446f12def4Spengcheng chen - Sun Microsystems - Beijing China 				ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
33456f12def4Spengcheng chen - Sun Microsystems - Beijing China 				delay(drv_usectohz(2000000 + n*500000));
33466f12def4Spengcheng chen - Sun Microsystems - Beijing China 				mutex_enter(&sc->sc_mt_lock);
33476f12def4Spengcheng chen - Sun Microsystems - Beijing China 			}
3348c50ced99Spengcheng chen - Sun Microsystems - Beijing China 
3349c533a883Shx 			err = iwk_init(sc);
3350c533a883Shx 			if (err != IWK_SUCCESS) {
3351c533a883Shx 				n++;
3352c533a883Shx 				if (n < 20)
3353c533a883Shx 					continue;
3354c533a883Shx 			}
3355c533a883Shx 			n = 0;
335643439c96Shx 			if (!err)
335743439c96Shx 				sc->sc_flags |= IWK_F_RUNNING;
33586f12def4Spengcheng chen - Sun Microsystems - Beijing China 
33596f12def4Spengcheng chen - Sun Microsystems - Beijing China 			if (!IWK_CHK_FAST_RECOVER(sc) ||
33606f12def4Spengcheng chen - Sun Microsystems - Beijing China 			    iwk_fast_recover(sc) != IWK_SUCCESS) {
33616f12def4Spengcheng chen - Sun Microsystems - Beijing China 				sc->sc_flags &= ~IWK_F_HW_ERR_RECOVER;
33626f12def4Spengcheng chen - Sun Microsystems - Beijing China 
33636f12def4Spengcheng chen - Sun Microsystems - Beijing China 				mutex_exit(&sc->sc_mt_lock);
33646f12def4Spengcheng chen - Sun Microsystems - Beijing China 				delay(drv_usectohz(2000000));
33656f12def4Spengcheng chen - Sun Microsystems - Beijing China 				if (sc->sc_ostate != IEEE80211_S_INIT)
33666f12def4Spengcheng chen - Sun Microsystems - Beijing China 					ieee80211_new_state(ic,
33676f12def4Spengcheng chen - Sun Microsystems - Beijing China 					    IEEE80211_S_SCAN, 0);
33686f12def4Spengcheng chen - Sun Microsystems - Beijing China 				mutex_enter(&sc->sc_mt_lock);
33696f12def4Spengcheng chen - Sun Microsystems - Beijing China 			}
3370c533a883Shx 		}
3371c533a883Shx 
3372d40f4da4Spengcheng chen - Sun Microsystems - Beijing China 		if (ic->ic_mach && (sc->sc_flags & IWK_F_LAZY_RESUME)) {
3373d40f4da4Spengcheng chen - Sun Microsystems - Beijing China 			IWK_DBG((IWK_DEBUG_RESUME,
33746f12def4Spengcheng chen - Sun Microsystems - Beijing China 			    "iwk_thread(): lazy resume\n"));
33756f12def4Spengcheng chen - Sun Microsystems - Beijing China 
3376d40f4da4Spengcheng chen - Sun Microsystems - Beijing China 			sc->sc_flags &= ~IWK_F_LAZY_RESUME;
3377d40f4da4Spengcheng chen - Sun Microsystems - Beijing China 			mutex_exit(&sc->sc_mt_lock);
3378d40f4da4Spengcheng chen - Sun Microsystems - Beijing China 			/*
3379d40f4da4Spengcheng chen - Sun Microsystems - Beijing China 			 * NB: under WPA mode, this call hangs (door problem?)
3380d40f4da4Spengcheng chen - Sun Microsystems - Beijing China 			 * when called in iwk_attach() and iwk_detach() while
3381d40f4da4Spengcheng chen - Sun Microsystems - Beijing China 			 * system is in the procedure of CPR. To be safe, let
3382d40f4da4Spengcheng chen - Sun Microsystems - Beijing China 			 * the thread do this.
3383d40f4da4Spengcheng chen - Sun Microsystems - Beijing China 			 */
3384d40f4da4Spengcheng chen - Sun Microsystems - Beijing China 			ieee80211_new_state(&sc->sc_ic, IEEE80211_S_INIT, -1);
3385d40f4da4Spengcheng chen - Sun Microsystems - Beijing China 			mutex_enter(&sc->sc_mt_lock);
3386d40f4da4Spengcheng chen - Sun Microsystems - Beijing China 		}
3387d40f4da4Spengcheng chen - Sun Microsystems - Beijing China 
3388c50ced99Spengcheng chen - Sun Microsystems - Beijing China 		if (ic->ic_mach &&
3389c50ced99Spengcheng chen - Sun Microsystems - Beijing China 		    (sc->sc_flags & IWK_F_SCANNING) && sc->sc_scan_pending) {
3390c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			IWK_DBG((IWK_DEBUG_SCAN,
3391c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			    "iwk_thread(): "
3392c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			    "wait for probe response\n"));
3393c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			sc->sc_scan_pending--;
3394c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			mutex_exit(&sc->sc_mt_lock);
3395c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			delay(drv_usectohz(200000));
3396d40f4da4Spengcheng chen - Sun Microsystems - Beijing China 			if (sc->sc_flags & IWK_F_SCANNING)
3397d40f4da4Spengcheng chen - Sun Microsystems - Beijing China 				ieee80211_next_scan(ic);
3398c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			mutex_enter(&sc->sc_mt_lock);
3399c50ced99Spengcheng chen - Sun Microsystems - Beijing China 		}
3400c50ced99Spengcheng chen - Sun Microsystems - Beijing China 
340143439c96Shx 		/*
340243439c96Shx 		 * rate ctl
340343439c96Shx 		 */
340443439c96Shx 		if (ic->ic_mach &&
340543439c96Shx 		    (sc->sc_flags & IWK_F_RATE_AUTO_CTL)) {
340643439c96Shx 			clk = ddi_get_lbolt();
340743439c96Shx 			if (clk > sc->sc_clk + drv_usectohz(500000)) {
340843439c96Shx 				iwk_amrr_timeout(sc);
340943439c96Shx 			}
341043439c96Shx 		}
341143439c96Shx 
3412216e0daaSQuaker Fang 		if ((ic->ic_state == IEEE80211_S_RUN) &&
3413216e0daaSQuaker Fang 		    (ic->ic_beaconmiss++ > 50)) {	/* 5 seconds */
3414216e0daaSQuaker Fang 			cmn_err(CE_WARN, "iwk: beacon missed for 5 seconds\n");
3415216e0daaSQuaker Fang 			(void) ieee80211_new_state(ic,
3416216e0daaSQuaker Fang 			    IEEE80211_S_INIT, -1);
3417216e0daaSQuaker Fang 		}
3418216e0daaSQuaker Fang 
3419c533a883Shx 		mutex_exit(&sc->sc_mt_lock);
3420c533a883Shx 		delay(drv_usectohz(100000));
3421c533a883Shx 		mutex_enter(&sc->sc_mt_lock);
3422c533a883Shx 
3423c533a883Shx 		if (sc->sc_tx_timer) {
3424c533a883Shx 			timeout++;
3425c533a883Shx 			if (timeout == 10) {
3426c533a883Shx 				sc->sc_tx_timer--;
3427c533a883Shx 				if (sc->sc_tx_timer == 0) {
3428c533a883Shx 					sc->sc_flags |= IWK_F_HW_ERR_RECOVER;
3429c533a883Shx 					sc->sc_ostate = IEEE80211_S_RUN;
3430c533a883Shx 					IWK_DBG((IWK_DEBUG_FW,
3431c533a883Shx 					    "iwk_thread(): try to recover from"
3432c533a883Shx 					    " 'send fail\n"));
3433c533a883Shx 				}
3434c533a883Shx 				timeout = 0;
3435c533a883Shx 			}
3436c533a883Shx 		}
3437c533a883Shx 
3438c533a883Shx 	}
3439c533a883Shx 	sc->sc_mf_thread = NULL;
3440c533a883Shx 	cv_signal(&sc->sc_mt_cv);
3441c533a883Shx 	mutex_exit(&sc->sc_mt_lock);
3442c533a883Shx }
3443c533a883Shx 
3444c533a883Shx 
3445c533a883Shx /*
3446c533a883Shx  * Send a command to the firmware.
3447c533a883Shx  */
3448c533a883Shx static int
iwk_cmd(iwk_sc_t * sc,int code,const void * buf,int size,int async)3449c533a883Shx iwk_cmd(iwk_sc_t *sc, int code, const void *buf, int size, int async)
3450c533a883Shx {
3451c533a883Shx 	iwk_tx_ring_t *ring = &sc->sc_txq[IWK_CMD_QUEUE_NUM];
3452c533a883Shx 	iwk_tx_desc_t *desc;
3453c533a883Shx 	iwk_cmd_t *cmd;
3454cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	clock_t clk;
3455c533a883Shx 
3456c533a883Shx 	ASSERT(size <= sizeof (cmd->data));
3457c533a883Shx 	ASSERT(mutex_owned(&sc->sc_glock));
3458c533a883Shx 
3459c533a883Shx 	IWK_DBG((IWK_DEBUG_CMD, "iwk_cmd() code[%d]", code));
3460c533a883Shx 	desc = ring->data[ring->cur].desc;
3461c533a883Shx 	cmd = ring->data[ring->cur].cmd;
3462c533a883Shx 
3463c533a883Shx 	cmd->hdr.type = (uint8_t)code;
3464c533a883Shx 	cmd->hdr.flags = 0;
3465c533a883Shx 	cmd->hdr.qid = ring->qid;
3466c533a883Shx 	cmd->hdr.idx = ring->cur;
3467c533a883Shx 	(void) memcpy(cmd->data, buf, size);
3468c533a883Shx 	(void) memset(desc, 0, sizeof (*desc));
3469c533a883Shx 
3470b510adaeSfei feng - Sun Microsystems - Beijing China 	desc->val0 = 1 << 24;
3471c533a883Shx 	desc->pa[0].tb1_addr =
3472c533a883Shx 	    (uint32_t)(ring->data[ring->cur].paddr_cmd & 0xffffffff);
3473c533a883Shx 	desc->pa[0].val1 = ((4 + size) << 4) & 0xfff0;
3474c533a883Shx 
3475c533a883Shx 	/* kick cmd ring XXX */
3476cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	sc->sc_shared->queues_byte_cnt_tbls[ring->qid].
3477cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	    tfd_offset[ring->cur].val = 8;
3478c533a883Shx 	if (ring->cur < IWK_MAX_WIN_SIZE) {
3479cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		sc->sc_shared->queues_byte_cnt_tbls[ring->qid].
3480cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		    tfd_offset[IWK_QUEUE_SIZE + ring->cur].val = 8;
3481c533a883Shx 	}
3482c533a883Shx 	ring->cur = (ring->cur + 1) % ring->count;
3483c533a883Shx 	IWK_WRITE(sc, HBUS_TARG_WRPTR, ring->qid << 8 | ring->cur);
3484c533a883Shx 
3485c533a883Shx 	if (async)
3486c533a883Shx 		return (IWK_SUCCESS);
3487c533a883Shx 	else {
3488c533a883Shx 		sc->sc_flags &= ~IWK_F_CMD_DONE;
3489c533a883Shx 		clk = ddi_get_lbolt() + drv_usectohz(2000000);
3490c533a883Shx 		while (!(sc->sc_flags & IWK_F_CMD_DONE)) {
3491cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			if (cv_timedwait(&sc->sc_cmd_cv, &sc->sc_glock, clk) <
3492cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			    0)
3493c533a883Shx 				break;
3494c533a883Shx 		}
3495c533a883Shx 		if (sc->sc_flags & IWK_F_CMD_DONE)
3496c533a883Shx 			return (IWK_SUCCESS);
3497c533a883Shx 		else
3498c533a883Shx 			return (IWK_FAIL);
3499c533a883Shx 	}
3500c533a883Shx }
3501c533a883Shx 
3502c533a883Shx static void
iwk_set_led(iwk_sc_t * sc,uint8_t id,uint8_t off,uint8_t on)3503c533a883Shx iwk_set_led(iwk_sc_t *sc, uint8_t id, uint8_t off, uint8_t on)
3504c533a883Shx {
3505c533a883Shx 	iwk_led_cmd_t led;
3506c533a883Shx 
3507c533a883Shx 	led.interval = LE_32(100000);	/* unit: 100ms */
3508c533a883Shx 	led.id = id;
3509c533a883Shx 	led.off = off;
3510c533a883Shx 	led.on = on;
3511c533a883Shx 
3512c533a883Shx 	(void) iwk_cmd(sc, REPLY_LEDS_CMD, &led, sizeof (led), 1);
3513c533a883Shx }
3514c533a883Shx 
3515c533a883Shx static int
iwk_hw_set_before_auth(iwk_sc_t * sc)3516c533a883Shx iwk_hw_set_before_auth(iwk_sc_t *sc)
3517c533a883Shx {
3518c533a883Shx 	ieee80211com_t *ic = &sc->sc_ic;
3519c533a883Shx 	ieee80211_node_t *in = ic->ic_bss;
3520c533a883Shx 	iwk_add_sta_t node;
3521c533a883Shx 	iwk_link_quality_cmd_t link_quality;
3522c533a883Shx 	struct ieee80211_rateset rs;
3523c533a883Shx 	uint16_t masks = 0, rate;
3524c533a883Shx 	int i, err;
3525c533a883Shx 
3526f3c4902cSpengcheng chen - Sun Microsystems - Beijing China 	if (in->in_chan == IEEE80211_CHAN_ANYC) {
3527f3c4902cSpengcheng chen - Sun Microsystems - Beijing China 		cmn_err(CE_WARN, "iwk_hw_set_before_auth():"
3528f3c4902cSpengcheng chen - Sun Microsystems - Beijing China 		    "channel (%d) isn't in proper range\n",
3529b510adaeSfei feng - Sun Microsystems - Beijing China 		    LE_16(ieee80211_chan2ieee(ic, in->in_chan)));
3530f3c4902cSpengcheng chen - Sun Microsystems - Beijing China 		return (IWK_FAIL);
3531f3c4902cSpengcheng chen - Sun Microsystems - Beijing China 	}
3532f3c4902cSpengcheng chen - Sun Microsystems - Beijing China 
3533c533a883Shx 	/* update adapter's configuration according the info of target AP */
3534c533a883Shx 	IEEE80211_ADDR_COPY(sc->sc_config.bssid, in->in_bssid);
3535b510adaeSfei feng - Sun Microsystems - Beijing China 	sc->sc_config.chan = LE_16(ieee80211_chan2ieee(ic, in->in_chan));
3536c533a883Shx 	if (ic->ic_curmode == IEEE80211_MODE_11B) {
3537c533a883Shx 		sc->sc_config.cck_basic_rates  = 0x03;
3538c533a883Shx 		sc->sc_config.ofdm_basic_rates = 0;
3539c533a883Shx 	} else if ((in->in_chan != IEEE80211_CHAN_ANYC) &&
3540c533a883Shx 	    (IEEE80211_IS_CHAN_5GHZ(in->in_chan))) {
3541c533a883Shx 		sc->sc_config.cck_basic_rates  = 0;
3542c533a883Shx 		sc->sc_config.ofdm_basic_rates = 0x15;
3543c533a883Shx 	} else { /* assume 802.11b/g */
3544c533a883Shx 		sc->sc_config.cck_basic_rates  = 0x0f;
3545c533a883Shx 		sc->sc_config.ofdm_basic_rates = 0xff;
3546c533a883Shx 	}
3547c533a883Shx 
3548c533a883Shx 	sc->sc_config.flags &= ~LE_32(RXON_FLG_SHORT_PREAMBLE_MSK |
3549c533a883Shx 	    RXON_FLG_SHORT_SLOT_MSK);
3550c533a883Shx 
3551c533a883Shx 	if (ic->ic_flags & IEEE80211_F_SHSLOT)
3552c533a883Shx 		sc->sc_config.flags |= LE_32(RXON_FLG_SHORT_SLOT_MSK);
3553c533a883Shx 	else
3554c533a883Shx 		sc->sc_config.flags &= LE_32(~RXON_FLG_SHORT_SLOT_MSK);
3555c533a883Shx 
3556c533a883Shx 	if (ic->ic_flags & IEEE80211_F_SHPREAMBLE)
3557c533a883Shx 		sc->sc_config.flags |= LE_32(RXON_FLG_SHORT_PREAMBLE_MSK);
3558c533a883Shx 	else
3559c533a883Shx 		sc->sc_config.flags &= LE_32(~RXON_FLG_SHORT_PREAMBLE_MSK);
3560c533a883Shx 
3561c533a883Shx 	IWK_DBG((IWK_DEBUG_80211, "config chan %d flags %x "
3562c533a883Shx 	    "filter_flags %x  cck %x ofdm %x"
3563c533a883Shx 	    " bssid:%02x:%02x:%02x:%02x:%02x:%2x\n",
3564b510adaeSfei feng - Sun Microsystems - Beijing China 	    LE_16(sc->sc_config.chan), LE_32(sc->sc_config.flags),
3565b510adaeSfei feng - Sun Microsystems - Beijing China 	    LE_32(sc->sc_config.filter_flags),
3566c533a883Shx 	    sc->sc_config.cck_basic_rates, sc->sc_config.ofdm_basic_rates,
3567c533a883Shx 	    sc->sc_config.bssid[0], sc->sc_config.bssid[1],
3568c533a883Shx 	    sc->sc_config.bssid[2], sc->sc_config.bssid[3],
3569c533a883Shx 	    sc->sc_config.bssid[4], sc->sc_config.bssid[5]));
3570c533a883Shx 	err = iwk_cmd(sc, REPLY_RXON, &sc->sc_config,
3571c533a883Shx 	    sizeof (iwk_rxon_cmd_t), 1);
3572c533a883Shx 	if (err != IWK_SUCCESS) {
3573c533a883Shx 		cmn_err(CE_WARN, "iwk_hw_set_before_auth():"
3574c533a883Shx 		    " failed to config chan%d\n",
3575c533a883Shx 		    sc->sc_config.chan);
3576c533a883Shx 		return (err);
3577c533a883Shx 	}
3578c533a883Shx 
3579cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	/* obtain current temperature of chipset */
3580cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	sc->sc_tempera = iwk_curr_tempera(sc);
3581cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
3582cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	/* make Tx power calibration to determine the gains of DSP and radio */
3583cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	err = iwk_tx_power_calibration(sc);
3584cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (err) {
3585c533a883Shx 		cmn_err(CE_WARN, "iwk_hw_set_before_auth():"
3586cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		    "failed to set tx power table\n");
3587c533a883Shx 		return (err);
3588c533a883Shx 	}
3589c533a883Shx 
3590c533a883Shx 	/* add default AP node */
3591c533a883Shx 	(void) memset(&node, 0, sizeof (node));
3592c533a883Shx 	IEEE80211_ADDR_COPY(node.bssid, in->in_bssid);
3593c533a883Shx 	node.id = IWK_AP_ID;
3594c533a883Shx 	err = iwk_cmd(sc, REPLY_ADD_STA, &node, sizeof (node), 1);
3595c533a883Shx 	if (err != IWK_SUCCESS) {
3596cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		cmn_err(CE_WARN, "iwk_hw_set_before_auth(): "
3597cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		    "failed to add BSS node\n");
3598c533a883Shx 		return (err);
3599c533a883Shx 	}
3600c533a883Shx 
360119d332feSfei feng - Sun Microsystems - Beijing China 	/* TX_LINK_QUALITY cmd */
3602c533a883Shx 	(void) memset(&link_quality, 0, sizeof (link_quality));
3603c533a883Shx 	rs = ic->ic_sup_rates[ieee80211_chan2mode(ic, ic->ic_curchan)];
3604c533a883Shx 	for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) {
3605c533a883Shx 		if (i < rs.ir_nrates)
3606c533a883Shx 			rate = rs.ir_rates[rs.ir_nrates - i];
3607c533a883Shx 		else
3608c533a883Shx 			rate = 2;
3609c533a883Shx 		if (rate == 2 || rate == 4 || rate == 11 || rate == 22)
3610c533a883Shx 			masks |= RATE_MCS_CCK_MSK;
3611c533a883Shx 		masks |= RATE_MCS_ANT_B_MSK;
3612c533a883Shx 		masks &= ~RATE_MCS_ANT_A_MSK;
3613c533a883Shx 		link_quality.rate_n_flags[i] =
3614b510adaeSfei feng - Sun Microsystems - Beijing China 		    LE_32(iwk_rate_to_plcp(rate) | masks);
3615c533a883Shx 	}
3616c533a883Shx 
3617c533a883Shx 	link_quality.general_params.single_stream_ant_msk = 2;
3618c533a883Shx 	link_quality.general_params.dual_stream_ant_msk = 3;
3619c533a883Shx 	link_quality.agg_params.agg_dis_start_th = 3;
3620c533a883Shx 	link_quality.agg_params.agg_time_limit = LE_16(4000);
3621c533a883Shx 	link_quality.sta_id = IWK_AP_ID;
3622c533a883Shx 	err = iwk_cmd(sc, REPLY_TX_LINK_QUALITY_CMD, &link_quality,
3623c533a883Shx 	    sizeof (link_quality), 1);
3624c533a883Shx 	if (err != IWK_SUCCESS) {
3625c533a883Shx 		cmn_err(CE_WARN, "iwk_hw_set_before_auth(): "
3626c533a883Shx 		    "failed to config link quality table\n");
3627c533a883Shx 		return (err);
3628c533a883Shx 	}
3629c533a883Shx 
3630c533a883Shx 	return (IWK_SUCCESS);
3631c533a883Shx }
3632c533a883Shx 
3633c533a883Shx /*
3634c533a883Shx  * Send a scan request(assembly scan cmd) to the firmware.
3635c533a883Shx  */
3636c533a883Shx static int
iwk_scan(iwk_sc_t * sc)3637c533a883Shx iwk_scan(iwk_sc_t *sc)
3638c533a883Shx {
3639c533a883Shx 	ieee80211com_t *ic = &sc->sc_ic;
3640c533a883Shx 	iwk_tx_ring_t *ring = &sc->sc_txq[IWK_CMD_QUEUE_NUM];
3641c533a883Shx 	iwk_tx_desc_t *desc;
3642c533a883Shx 	iwk_tx_data_t *data;
3643c533a883Shx 	iwk_cmd_t *cmd;
3644c533a883Shx 	iwk_scan_hdr_t *hdr;
3645c533a883Shx 	iwk_scan_chan_t *chan;
3646c533a883Shx 	struct ieee80211_frame *wh;
3647c533a883Shx 	ieee80211_node_t *in = ic->ic_bss;
3648c50ced99Spengcheng chen - Sun Microsystems - Beijing China 	uint8_t essid[IEEE80211_NWID_LEN+1];
3649c533a883Shx 	struct ieee80211_rateset *rs;
3650c533a883Shx 	enum ieee80211_phymode mode;
3651c533a883Shx 	uint8_t *frm;
3652c533a883Shx 	int i, pktlen, nrates;
3653c533a883Shx 
3654c533a883Shx 	data = &ring->data[ring->cur];
3655c533a883Shx 	desc = data->desc;
3656c533a883Shx 	cmd = (iwk_cmd_t *)data->dma_data.mem_va;
3657c533a883Shx 
3658c533a883Shx 	cmd->hdr.type = REPLY_SCAN_CMD;
3659c533a883Shx 	cmd->hdr.flags = 0;
3660c533a883Shx 	cmd->hdr.qid = ring->qid;
3661c533a883Shx 	cmd->hdr.idx = ring->cur | 0x40;
3662c533a883Shx 
3663c533a883Shx 	hdr = (iwk_scan_hdr_t *)cmd->data;
3664c533a883Shx 	(void) memset(hdr, 0, sizeof (iwk_scan_hdr_t));
3665c50ced99Spengcheng chen - Sun Microsystems - Beijing China 	hdr->nchan = 1;
3666c50ced99Spengcheng chen - Sun Microsystems - Beijing China 	hdr->quiet_time = LE_16(50);
3667c533a883Shx 	hdr->quiet_plcp_th = LE_16(1);
3668c533a883Shx 
3669b510adaeSfei feng - Sun Microsystems - Beijing China 	hdr->flags = LE_32(RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK);
3670b510adaeSfei feng - Sun Microsystems - Beijing China 	hdr->rx_chain = LE_16(RXON_RX_CHAIN_DRIVER_FORCE_MSK |
3671b510adaeSfei feng - Sun Microsystems - Beijing China 	    (0x7 << RXON_RX_CHAIN_VALID_POS) |
3672c533a883Shx 	    (0x6 << RXON_RX_CHAIN_FORCE_SEL_POS) |
3673c533a883Shx 	    (0x7 << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS));
3674c533a883Shx 
3675b510adaeSfei feng - Sun Microsystems - Beijing China 	hdr->tx_cmd.tx_flags = LE_32(TX_CMD_FLG_SEQ_CTL_MSK);
3676c533a883Shx 	hdr->tx_cmd.sta_id = IWK_BROADCAST_ID;
3677b510adaeSfei feng - Sun Microsystems - Beijing China 	hdr->tx_cmd.stop_time.life_time = LE_32(0xffffffff);
3678b510adaeSfei feng - Sun Microsystems - Beijing China 	hdr->tx_cmd.tx_flags |= LE_32(0x200);
3679b510adaeSfei feng - Sun Microsystems - Beijing China 	hdr->tx_cmd.rate.r.rate_n_flags = LE_32(iwk_rate_to_plcp(2));
3680c533a883Shx 	hdr->tx_cmd.rate.r.rate_n_flags |=
3681b510adaeSfei feng - Sun Microsystems - Beijing China 	    LE_32(RATE_MCS_ANT_B_MSK|RATE_MCS_CCK_MSK);
3682c533a883Shx 	hdr->direct_scan[0].len = ic->ic_des_esslen;
3683c533a883Shx 	hdr->direct_scan[0].id  = IEEE80211_ELEMID_SSID;
3684c533a883Shx 
3685c50ced99Spengcheng chen - Sun Microsystems - Beijing China 	if (ic->ic_des_esslen) {
3686c50ced99Spengcheng chen - Sun Microsystems - Beijing China 		bcopy(ic->ic_des_essid, essid, ic->ic_des_esslen);
3687c50ced99Spengcheng chen - Sun Microsystems - Beijing China 		essid[ic->ic_des_esslen] = '\0';
3688c50ced99Spengcheng chen - Sun Microsystems - Beijing China 		IWK_DBG((IWK_DEBUG_SCAN, "directed scan %s\n", essid));
3689c50ced99Spengcheng chen - Sun Microsystems - Beijing China 
3690c533a883Shx 		bcopy(ic->ic_des_essid, hdr->direct_scan[0].ssid,
3691c533a883Shx 		    ic->ic_des_esslen);
3692c50ced99Spengcheng chen - Sun Microsystems - Beijing China 	} else {
3693c533a883Shx 		bzero(hdr->direct_scan[0].ssid,
3694c533a883Shx 		    sizeof (hdr->direct_scan[0].ssid));
3695c50ced99Spengcheng chen - Sun Microsystems - Beijing China 	}
3696c533a883Shx 	/*
3697c533a883Shx 	 * a probe request frame is required after the REPLY_SCAN_CMD
3698c533a883Shx 	 */
3699c533a883Shx 	wh = (struct ieee80211_frame *)(hdr + 1);
3700c533a883Shx 	wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT |
3701c533a883Shx 	    IEEE80211_FC0_SUBTYPE_PROBE_REQ;
3702c533a883Shx 	wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
3703c533a883Shx 	(void) memset(wh->i_addr1, 0xff, 6);
3704c533a883Shx 	IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_macaddr);
3705c533a883Shx 	(void) memset(wh->i_addr3, 0xff, 6);
3706c533a883Shx 	*(uint16_t *)&wh->i_dur[0] = 0;
3707c533a883Shx 	*(uint16_t *)&wh->i_seq[0] = 0;
3708c533a883Shx 
3709c533a883Shx 	frm = (uint8_t *)(wh + 1);
3710c533a883Shx 
3711c533a883Shx 	/* essid IE */
3712c50ced99Spengcheng chen - Sun Microsystems - Beijing China 	if (in->in_esslen) {
3713c50ced99Spengcheng chen - Sun Microsystems - Beijing China 		bcopy(in->in_essid, essid, in->in_esslen);
3714c50ced99Spengcheng chen - Sun Microsystems - Beijing China 		essid[in->in_esslen] = '\0';
3715c50ced99Spengcheng chen - Sun Microsystems - Beijing China 		IWK_DBG((IWK_DEBUG_SCAN, "probe with ESSID %s\n",
3716c50ced99Spengcheng chen - Sun Microsystems - Beijing China 		    essid));
3717c50ced99Spengcheng chen - Sun Microsystems - Beijing China 	}
3718c533a883Shx 	*frm++ = IEEE80211_ELEMID_SSID;
3719c533a883Shx 	*frm++ = in->in_esslen;
3720c533a883Shx 	(void) memcpy(frm, in->in_essid, in->in_esslen);
3721c533a883Shx 	frm += in->in_esslen;
3722c533a883Shx 
3723c533a883Shx 	mode = ieee80211_chan2mode(ic, ic->ic_curchan);
3724c533a883Shx 	rs = &ic->ic_sup_rates[mode];
3725c533a883Shx 
3726c533a883Shx 	/* supported rates IE */
3727c533a883Shx 	*frm++ = IEEE80211_ELEMID_RATES;
3728c533a883Shx 	nrates = rs->ir_nrates;
3729c533a883Shx 	if (nrates > IEEE80211_RATE_SIZE)
3730c533a883Shx 		nrates = IEEE80211_RATE_SIZE;
3731c533a883Shx 	*frm++ = (uint8_t)nrates;
3732c533a883Shx 	(void) memcpy(frm, rs->ir_rates, nrates);
3733c533a883Shx 	frm += nrates;
3734c533a883Shx 
3735c533a883Shx 	/* supported xrates IE */
3736c533a883Shx 	if (rs->ir_nrates > IEEE80211_RATE_SIZE) {
3737c533a883Shx 		nrates = rs->ir_nrates - IEEE80211_RATE_SIZE;
3738c533a883Shx 		*frm++ = IEEE80211_ELEMID_XRATES;
3739c533a883Shx 		*frm++ = (uint8_t)nrates;
3740c533a883Shx 		(void) memcpy(frm, rs->ir_rates + IEEE80211_RATE_SIZE, nrates);
3741c533a883Shx 		frm += nrates;
3742c533a883Shx 	}
3743c533a883Shx 
3744c533a883Shx 	/* optionnal IE (usually for wpa) */
3745c533a883Shx 	if (ic->ic_opt_ie != NULL) {
3746c533a883Shx 		(void) memcpy(frm, ic->ic_opt_ie, ic->ic_opt_ie_len);
3747c533a883Shx 		frm += ic->ic_opt_ie_len;
3748c533a883Shx 	}
3749c533a883Shx 
3750c533a883Shx 	/* setup length of probe request */
3751ff3124efSff 	hdr->tx_cmd.len = LE_16(_PTRDIFF(frm, wh));
3752b510adaeSfei feng - Sun Microsystems - Beijing China 	hdr->len = LE_16(hdr->nchan * sizeof (iwk_scan_chan_t) +
3753b510adaeSfei feng - Sun Microsystems - Beijing China 	    LE_16(hdr->tx_cmd.len) + sizeof (iwk_scan_hdr_t));
3754c533a883Shx 
3755c533a883Shx 	/*
3756c533a883Shx 	 * the attribute of the scan channels are required after the probe
3757c533a883Shx 	 * request frame.
3758c533a883Shx 	 */
3759c533a883Shx 	chan = (iwk_scan_chan_t *)frm;
3760c533a883Shx 	for (i = 1; i <= hdr->nchan; i++, chan++) {
3761c50ced99Spengcheng chen - Sun Microsystems - Beijing China 		if (ic->ic_des_esslen) {
3762c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			chan->type = 3;
3763c50ced99Spengcheng chen - Sun Microsystems - Beijing China 		} else {
3764c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			chan->type = 1;
3765c50ced99Spengcheng chen - Sun Microsystems - Beijing China 		}
3766c50ced99Spengcheng chen - Sun Microsystems - Beijing China 
3767c50ced99Spengcheng chen - Sun Microsystems - Beijing China 		chan->chan = ieee80211_chan2ieee(ic, ic->ic_curchan);
3768c533a883Shx 		chan->tpc.tx_gain = 0x3f;
3769c533a883Shx 		chan->tpc.dsp_atten = 110;
3770c50ced99Spengcheng chen - Sun Microsystems - Beijing China 		chan->active_dwell = LE_16(50);
3771c533a883Shx 		chan->passive_dwell = LE_16(120);
3772c533a883Shx 
3773c533a883Shx 		frm += sizeof (iwk_scan_chan_t);
3774c533a883Shx 	}
3775c533a883Shx 
3776ff3124efSff 	pktlen = _PTRDIFF(frm, cmd);
3777c533a883Shx 
3778c533a883Shx 	(void) memset(desc, 0, sizeof (*desc));
3779b510adaeSfei feng - Sun Microsystems - Beijing China 	desc->val0 = 1 << 24;
3780c533a883Shx 	desc->pa[0].tb1_addr =
3781c533a883Shx 	    (uint32_t)(data->dma_data.cookie.dmac_address & 0xffffffff);
3782c533a883Shx 	desc->pa[0].val1 = (pktlen << 4) & 0xfff0;
3783c533a883Shx 
3784c533a883Shx 	/*
3785c533a883Shx 	 * maybe for cmd, filling the byte cnt table is not necessary.
3786c533a883Shx 	 * anyway, we fill it here.
3787c533a883Shx 	 */
3788cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	sc->sc_shared->queues_byte_cnt_tbls[ring->qid].
3789cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	    tfd_offset[ring->cur].val = 8;
3790c533a883Shx 	if (ring->cur < IWK_MAX_WIN_SIZE) {
3791cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		sc->sc_shared->queues_byte_cnt_tbls[ring->qid].
3792cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		    tfd_offset[IWK_QUEUE_SIZE + ring->cur].val = 8;
3793c533a883Shx 	}
379443439c96Shx 
3795c533a883Shx 	/* kick cmd ring */
3796c533a883Shx 	ring->cur = (ring->cur + 1) % ring->count;
3797c533a883Shx 	IWK_WRITE(sc, HBUS_TARG_WRPTR, ring->qid << 8 | ring->cur);
3798c533a883Shx 
3799c533a883Shx 	return (IWK_SUCCESS);
3800c533a883Shx }
3801c533a883Shx 
3802c533a883Shx static int
iwk_config(iwk_sc_t * sc)3803c533a883Shx iwk_config(iwk_sc_t *sc)
3804c533a883Shx {
3805c533a883Shx 	ieee80211com_t *ic = &sc->sc_ic;
3806c533a883Shx 	iwk_powertable_cmd_t powertable;
3807c533a883Shx 	iwk_bt_cmd_t bt;
3808c533a883Shx 	iwk_add_sta_t node;
3809c533a883Shx 	iwk_link_quality_cmd_t link_quality;
3810c533a883Shx 	int i, err;
3811c533a883Shx 	uint16_t masks = 0;
3812c533a883Shx 
3813c533a883Shx 	/*
3814c533a883Shx 	 * set power mode. Disable power management at present, do it later
3815c533a883Shx 	 */
3816c533a883Shx 	(void) memset(&powertable, 0, sizeof (powertable));
3817c533a883Shx 	powertable.flags = LE_16(0x8);
3818c533a883Shx 	err = iwk_cmd(sc, POWER_TABLE_CMD, &powertable,
3819c533a883Shx 	    sizeof (powertable), 0);
3820c533a883Shx 	if (err != IWK_SUCCESS) {
3821c533a883Shx 		cmn_err(CE_WARN, "iwk_config(): failed to set power mode\n");
3822c533a883Shx 		return (err);
3823c533a883Shx 	}
3824c533a883Shx 
3825c533a883Shx 	/* configure bt coexistence */
3826c533a883Shx 	(void) memset(&bt, 0, sizeof (bt));
3827c533a883Shx 	bt.flags = 3;
3828c533a883Shx 	bt.lead_time = 0xaa;
3829c533a883Shx 	bt.max_kill = 1;
3830c533a883Shx 	err = iwk_cmd(sc, REPLY_BT_CONFIG, &bt,
3831c533a883Shx 	    sizeof (bt), 0);
3832c533a883Shx 	if (err != IWK_SUCCESS) {
3833c533a883Shx 		cmn_err(CE_WARN,
3834c533a883Shx 		    "iwk_config(): "
3835c533a883Shx 		    "failed to configurate bt coexistence\n");
3836c533a883Shx 		return (err);
3837c533a883Shx 	}
3838c533a883Shx 
3839c533a883Shx 	/* configure rxon */
3840c533a883Shx 	(void) memset(&sc->sc_config, 0, sizeof (iwk_rxon_cmd_t));
3841c533a883Shx 	IEEE80211_ADDR_COPY(sc->sc_config.node_addr, ic->ic_macaddr);
3842c533a883Shx 	IEEE80211_ADDR_COPY(sc->sc_config.wlap_bssid, ic->ic_macaddr);
3843b510adaeSfei feng - Sun Microsystems - Beijing China 	sc->sc_config.chan = LE_16(ieee80211_chan2ieee(ic, ic->ic_curchan));
3844b510adaeSfei feng - Sun Microsystems - Beijing China 	sc->sc_config.flags = LE_32(RXON_FLG_TSF2HOST_MSK |
3845cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	    RXON_FLG_AUTO_DETECT_MSK | RXON_FLG_BAND_24G_MSK);
3846b510adaeSfei feng - Sun Microsystems - Beijing China 	sc->sc_config.flags &= LE_32(~RXON_FLG_CCK_MSK);
3847c533a883Shx 	switch (ic->ic_opmode) {
3848c533a883Shx 	case IEEE80211_M_STA:
3849c533a883Shx 		sc->sc_config.dev_type = RXON_DEV_TYPE_ESS;
3850c533a883Shx 		sc->sc_config.filter_flags |= LE_32(RXON_FILTER_ACCEPT_GRP_MSK |
3851c533a883Shx 		    RXON_FILTER_DIS_DECRYPT_MSK |
3852c533a883Shx 		    RXON_FILTER_DIS_GRP_DECRYPT_MSK);
3853c533a883Shx 		break;
385419d332feSfei feng - Sun Microsystems - Beijing China 	case IEEE80211_M_IBSS:
3855c533a883Shx 	case IEEE80211_M_AHDEMO:
3856c533a883Shx 		sc->sc_config.dev_type = RXON_DEV_TYPE_IBSS;
3857b510adaeSfei feng - Sun Microsystems - Beijing China 		sc->sc_config.flags |= LE_32(RXON_FLG_SHORT_PREAMBLE_MSK);
3858cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		sc->sc_config.filter_flags = LE_32(RXON_FILTER_ACCEPT_GRP_MSK |
3859cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		    RXON_FILTER_DIS_DECRYPT_MSK |
3860cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		    RXON_FILTER_DIS_GRP_DECRYPT_MSK);
3861c533a883Shx 		break;
3862c533a883Shx 	case IEEE80211_M_HOSTAP:
3863c533a883Shx 		sc->sc_config.dev_type = RXON_DEV_TYPE_AP;
3864c533a883Shx 		break;
3865c533a883Shx 	case IEEE80211_M_MONITOR:
3866c533a883Shx 		sc->sc_config.dev_type = RXON_DEV_TYPE_SNIFFER;
3867c533a883Shx 		sc->sc_config.filter_flags |= LE_32(RXON_FILTER_ACCEPT_GRP_MSK |
3868c533a883Shx 		    RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_PROMISC_MSK);
3869c533a883Shx 		break;
3870c533a883Shx 	}
3871c533a883Shx 	sc->sc_config.cck_basic_rates  = 0x0f;
3872c533a883Shx 	sc->sc_config.ofdm_basic_rates = 0xff;
3873c533a883Shx 
3874c533a883Shx 	sc->sc_config.ofdm_ht_single_stream_basic_rates = 0xff;
3875c533a883Shx 	sc->sc_config.ofdm_ht_dual_stream_basic_rates = 0xff;
3876c533a883Shx 
3877c533a883Shx 	/* set antenna */
3878c533a883Shx 
3879b510adaeSfei feng - Sun Microsystems - Beijing China 	sc->sc_config.rx_chain = LE_16(RXON_RX_CHAIN_DRIVER_FORCE_MSK |
3880b510adaeSfei feng - Sun Microsystems - Beijing China 	    (0x7 << RXON_RX_CHAIN_VALID_POS) |
3881c533a883Shx 	    (0x6 << RXON_RX_CHAIN_FORCE_SEL_POS) |
3882c533a883Shx 	    (0x7 << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS));
3883c533a883Shx 
3884c533a883Shx 	err = iwk_cmd(sc, REPLY_RXON, &sc->sc_config,
3885c533a883Shx 	    sizeof (iwk_rxon_cmd_t), 0);
3886c533a883Shx 	if (err != IWK_SUCCESS) {
3887c533a883Shx 		cmn_err(CE_WARN, "iwk_config(): "
3888c533a883Shx 		    "failed to set configure command\n");
3889c533a883Shx 		return (err);
3890c533a883Shx 	}
3891cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	/* obtain current temperature of chipset */
3892cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	sc->sc_tempera = iwk_curr_tempera(sc);
3893c533a883Shx 
3894cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	/* make Tx power calibration to determine the gains of DSP and radio */
3895cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	err = iwk_tx_power_calibration(sc);
3896cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (err) {
3897cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		cmn_err(CE_WARN, "iwk_config(): "
3898cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		    "failed to set tx power table\n");
3899c533a883Shx 		return (err);
3900c533a883Shx 	}
3901c533a883Shx 
3902c533a883Shx 	/* add broadcast node so that we can send broadcast frame */
3903c533a883Shx 	(void) memset(&node, 0, sizeof (node));
3904c533a883Shx 	(void) memset(node.bssid, 0xff, 6);
3905c533a883Shx 	node.id = IWK_BROADCAST_ID;
3906c533a883Shx 	err = iwk_cmd(sc, REPLY_ADD_STA, &node, sizeof (node), 0);
3907c533a883Shx 	if (err != IWK_SUCCESS) {
3908c533a883Shx 		cmn_err(CE_WARN, "iwk_config(): "
3909c533a883Shx 		    "failed to add broadcast node\n");
3910c533a883Shx 		return (err);
3911c533a883Shx 	}
3912c533a883Shx 
3913c533a883Shx 	/* TX_LINK_QUALITY cmd ? */
3914c533a883Shx 	(void) memset(&link_quality, 0, sizeof (link_quality));
3915c533a883Shx 	for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) {
3916c533a883Shx 		masks |= RATE_MCS_CCK_MSK;
3917c533a883Shx 		masks |= RATE_MCS_ANT_B_MSK;
3918c533a883Shx 		masks &= ~RATE_MCS_ANT_A_MSK;
3919b510adaeSfei feng - Sun Microsystems - Beijing China 		link_quality.rate_n_flags[i] =
3920b510adaeSfei feng - Sun Microsystems - Beijing China 		    LE_32(iwk_rate_to_plcp(2) | masks);
3921c533a883Shx 	}
3922c533a883Shx 
3923c533a883Shx 	link_quality.general_params.single_stream_ant_msk = 2;
3924c533a883Shx 	link_quality.general_params.dual_stream_ant_msk = 3;
3925c533a883Shx 	link_quality.agg_params.agg_dis_start_th = 3;
3926c533a883Shx 	link_quality.agg_params.agg_time_limit = LE_16(4000);
3927c533a883Shx 	link_quality.sta_id = IWK_BROADCAST_ID;
3928c533a883Shx 	err = iwk_cmd(sc, REPLY_TX_LINK_QUALITY_CMD, &link_quality,
3929c533a883Shx 	    sizeof (link_quality), 0);
3930c533a883Shx 	if (err != IWK_SUCCESS) {
3931c533a883Shx 		cmn_err(CE_WARN, "iwk_config(): "
3932c533a883Shx 		    "failed to config link quality table\n");
3933c533a883Shx 		return (err);
3934c533a883Shx 	}
3935c533a883Shx 
3936c533a883Shx 	return (IWK_SUCCESS);
3937c533a883Shx }
3938c533a883Shx 
3939c533a883Shx static void
iwk_stop_master(iwk_sc_t * sc)3940c533a883Shx iwk_stop_master(iwk_sc_t *sc)
3941c533a883Shx {
3942c533a883Shx 	uint32_t tmp;
3943c533a883Shx 	int n;
3944c533a883Shx 
3945c533a883Shx 	tmp = IWK_READ(sc, CSR_RESET);
3946c533a883Shx 	IWK_WRITE(sc, CSR_RESET, tmp | CSR_RESET_REG_FLAG_STOP_MASTER);
3947c533a883Shx 
3948c533a883Shx 	tmp = IWK_READ(sc, CSR_GP_CNTRL);
3949c533a883Shx 	if ((tmp & CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE) ==
3950c533a883Shx 	    CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE)
3951c533a883Shx 		return;
3952c533a883Shx 
3953c533a883Shx 	for (n = 0; n < 2000; n++) {
3954c533a883Shx 		if (IWK_READ(sc, CSR_RESET) &
3955c533a883Shx 		    CSR_RESET_REG_FLAG_MASTER_DISABLED)
3956c533a883Shx 			break;
3957c533a883Shx 		DELAY(1000);
3958c533a883Shx 	}
3959c533a883Shx 	if (n == 2000)
3960c533a883Shx 		IWK_DBG((IWK_DEBUG_HW,
3961c533a883Shx 		    "timeout waiting for master stop\n"));
3962c533a883Shx }
3963c533a883Shx 
3964c533a883Shx static int
iwk_power_up(iwk_sc_t * sc)3965c533a883Shx iwk_power_up(iwk_sc_t *sc)
3966c533a883Shx {
3967c533a883Shx 	uint32_t tmp;
3968c533a883Shx 
3969c533a883Shx 	iwk_mac_access_enter(sc);
3970c533a883Shx 	tmp = iwk_reg_read(sc, ALM_APMG_PS_CTL);
3971c533a883Shx 	tmp &= ~APMG_PS_CTRL_REG_MSK_POWER_SRC;
3972c533a883Shx 	tmp |= APMG_PS_CTRL_REG_VAL_POWER_SRC_VMAIN;
3973c533a883Shx 	iwk_reg_write(sc, ALM_APMG_PS_CTL, tmp);
3974c533a883Shx 	iwk_mac_access_exit(sc);
3975c533a883Shx 
3976c533a883Shx 	DELAY(5000);
3977c533a883Shx 	return (IWK_SUCCESS);
3978c533a883Shx }
3979c533a883Shx 
3980c533a883Shx static int
iwk_preinit(iwk_sc_t * sc)3981c533a883Shx iwk_preinit(iwk_sc_t *sc)
3982c533a883Shx {
3983c533a883Shx 	uint32_t tmp;
3984c533a883Shx 	int n;
3985c533a883Shx 	uint8_t vlink;
3986c533a883Shx 
3987c533a883Shx 	/* clear any pending interrupts */
3988c533a883Shx 	IWK_WRITE(sc, CSR_INT, 0xffffffff);
3989c533a883Shx 
3990c533a883Shx 	tmp = IWK_READ(sc, CSR_GIO_CHICKEN_BITS);
3991c533a883Shx 	IWK_WRITE(sc, CSR_GIO_CHICKEN_BITS,
3992c533a883Shx 	    tmp | CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
3993c533a883Shx 
3994c533a883Shx 	tmp = IWK_READ(sc, CSR_GP_CNTRL);
3995c533a883Shx 	IWK_WRITE(sc, CSR_GP_CNTRL, tmp | CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
3996c533a883Shx 
3997c533a883Shx 	/* wait for clock ready */
3998c533a883Shx 	for (n = 0; n < 1000; n++) {
3999c533a883Shx 		if (IWK_READ(sc, CSR_GP_CNTRL) &
4000c533a883Shx 		    CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY)
4001c533a883Shx 			break;
4002c533a883Shx 		DELAY(10);
4003c533a883Shx 	}
4004c533a883Shx 	if (n == 1000) {
4005c50ced99Spengcheng chen - Sun Microsystems - Beijing China 		cmn_err(CE_WARN,
4006c50ced99Spengcheng chen - Sun Microsystems - Beijing China 		    "iwk_preinit(): timeout waiting for clock ready\n");
4007c533a883Shx 		return (ETIMEDOUT);
4008c533a883Shx 	}
4009c533a883Shx 	iwk_mac_access_enter(sc);
4010c533a883Shx 	tmp = iwk_reg_read(sc, APMG_CLK_CTRL_REG);
4011c533a883Shx 	iwk_reg_write(sc, APMG_CLK_CTRL_REG, tmp |
4012c533a883Shx 	    APMG_CLK_REG_VAL_DMA_CLK_RQT | APMG_CLK_REG_VAL_BSM_CLK_RQT);
4013c533a883Shx 
4014c533a883Shx 	DELAY(20);
4015c533a883Shx 	tmp = iwk_reg_read(sc, ALM_APMG_PCIDEV_STT);
4016c533a883Shx 	iwk_reg_write(sc, ALM_APMG_PCIDEV_STT, tmp |
4017c533a883Shx 	    APMG_DEV_STATE_REG_VAL_L1_ACTIVE_DISABLE);
4018c533a883Shx 	iwk_mac_access_exit(sc);
4019c533a883Shx 
4020c533a883Shx 	IWK_WRITE(sc, CSR_INT_COALESCING, 512 / 32); /* ??? */
4021c533a883Shx 
4022c533a883Shx 	(void) iwk_power_up(sc);
4023c533a883Shx 
4024c533a883Shx 	if ((sc->sc_rev & 0x80) == 0x80 && (sc->sc_rev & 0x7f) < 8) {
4025c533a883Shx 		tmp = ddi_get32(sc->sc_cfg_handle,
4026c533a883Shx 		    (uint32_t *)(sc->sc_cfg_base + 0xe8));
4027c533a883Shx 		ddi_put32(sc->sc_cfg_handle,
4028c533a883Shx 		    (uint32_t *)(sc->sc_cfg_base + 0xe8),
4029c533a883Shx 		    tmp & ~(1 << 11));
4030c533a883Shx 	}
4031c533a883Shx 
4032c533a883Shx 
4033c533a883Shx 	vlink = ddi_get8(sc->sc_cfg_handle,
4034c533a883Shx 	    (uint8_t *)(sc->sc_cfg_base + 0xf0));
4035c533a883Shx 	ddi_put8(sc->sc_cfg_handle, (uint8_t *)(sc->sc_cfg_base + 0xf0),
4036c533a883Shx 	    vlink & ~2);
4037c533a883Shx 
4038c533a883Shx 	tmp = IWK_READ(sc, CSR_SW_VER);
4039c533a883Shx 	tmp |= CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI |
4040cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	    CSR_HW_IF_CONFIG_REG_BIT_MAC_SI |
4041cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	    CSR_HW_IF_CONFIG_REG_BIT_KEDRON_R;
4042c533a883Shx 	IWK_WRITE(sc, CSR_SW_VER, tmp);
4043c533a883Shx 
4044c533a883Shx 	/* make sure power supply on each part of the hardware */
4045c533a883Shx 	iwk_mac_access_enter(sc);
4046c533a883Shx 	tmp = iwk_reg_read(sc, ALM_APMG_PS_CTL);
4047c533a883Shx 	tmp |= APMG_PS_CTRL_REG_VAL_ALM_R_RESET_REQ;
4048c533a883Shx 	iwk_reg_write(sc, ALM_APMG_PS_CTL, tmp);
4049c533a883Shx 	DELAY(5);
4050c533a883Shx 	tmp = iwk_reg_read(sc, ALM_APMG_PS_CTL);
4051c533a883Shx 	tmp &= ~APMG_PS_CTRL_REG_VAL_ALM_R_RESET_REQ;
4052c533a883Shx 	iwk_reg_write(sc, ALM_APMG_PS_CTL, tmp);
4053c533a883Shx 	iwk_mac_access_exit(sc);
4054c533a883Shx 	return (IWK_SUCCESS);
4055c533a883Shx }
4056c533a883Shx 
4057c533a883Shx /*
4058c533a883Shx  * set up semphore flag to own EEPROM
4059c533a883Shx  */
iwk_eep_sem_down(iwk_sc_t * sc)4060c533a883Shx static int iwk_eep_sem_down(iwk_sc_t *sc)
4061c533a883Shx {
4062c533a883Shx 	int count1, count2;
4063c533a883Shx 	uint32_t tmp;
4064c533a883Shx 
4065c533a883Shx 	for (count1 = 0; count1 < 1000; count1++) {
4066c533a883Shx 		tmp = IWK_READ(sc, CSR_HW_IF_CONFIG_REG);
4067c533a883Shx 		IWK_WRITE(sc, CSR_HW_IF_CONFIG_REG,
4068c533a883Shx 		    tmp | CSR_HW_IF_CONFIG_REG_EEP_SEM);
4069c533a883Shx 
4070c533a883Shx 		for (count2 = 0; count2 < 2; count2++) {
4071c533a883Shx 			if (IWK_READ(sc, CSR_HW_IF_CONFIG_REG) &
4072c533a883Shx 			    CSR_HW_IF_CONFIG_REG_EEP_SEM)
4073c533a883Shx 				return (IWK_SUCCESS);
4074c533a883Shx 			DELAY(10000);
4075c533a883Shx 		}
4076c533a883Shx 	}
4077c533a883Shx 	return (IWK_FAIL);
4078c533a883Shx }
4079c533a883Shx 
4080c533a883Shx /*
4081c533a883Shx  * reset semphore flag to release EEPROM
4082c533a883Shx  */
iwk_eep_sem_up(iwk_sc_t * sc)4083c533a883Shx static void iwk_eep_sem_up(iwk_sc_t *sc)
4084c533a883Shx {
4085c533a883Shx 	uint32_t tmp;
4086c533a883Shx 
4087c533a883Shx 	tmp = IWK_READ(sc, CSR_HW_IF_CONFIG_REG);
4088c533a883Shx 	IWK_WRITE(sc, CSR_HW_IF_CONFIG_REG,
4089c533a883Shx 	    tmp & (~CSR_HW_IF_CONFIG_REG_EEP_SEM));
4090c533a883Shx }
4091c533a883Shx 
4092c533a883Shx /*
4093c533a883Shx  * This function load all infomation in eeprom into iwk_eep
4094c533a883Shx  * structure in iwk_sc_t structure
4095c533a883Shx  */
iwk_eep_load(iwk_sc_t * sc)4096c533a883Shx static int iwk_eep_load(iwk_sc_t *sc)
4097c533a883Shx {
4098c533a883Shx 	int i, rr;
4099c533a883Shx 	uint32_t rv, tmp, eep_gp;
4100c533a883Shx 	uint16_t addr, eep_sz = sizeof (sc->sc_eep_map);
4101c533a883Shx 	uint16_t *eep_p = (uint16_t *)&sc->sc_eep_map;
4102c533a883Shx 
4103c533a883Shx 	/* read eeprom gp register in CSR */
4104c533a883Shx 	eep_gp = IWK_READ(sc, CSR_EEPROM_GP);
4105c533a883Shx 	if ((eep_gp & CSR_EEPROM_GP_VALID_MSK) ==
4106c533a883Shx 	    CSR_EEPROM_GP_BAD_SIGNATURE) {
4107c50ced99Spengcheng chen - Sun Microsystems - Beijing China 		cmn_err(CE_WARN, "EEPROM not found\n");
4108c533a883Shx 		return (IWK_FAIL);
4109c533a883Shx 	}
4110c533a883Shx 
4111c533a883Shx 	rr = iwk_eep_sem_down(sc);
4112c533a883Shx 	if (rr != 0) {
4113c50ced99Spengcheng chen - Sun Microsystems - Beijing China 		cmn_err(CE_WARN, "failed to own EEPROM\n");
4114c533a883Shx 		return (IWK_FAIL);
4115c533a883Shx 	}
4116c533a883Shx 
4117c533a883Shx 	for (addr = 0; addr < eep_sz; addr += 2) {
4118c533a883Shx 		IWK_WRITE(sc, CSR_EEPROM_REG, addr<<1);
4119c533a883Shx 		tmp = IWK_READ(sc, CSR_EEPROM_REG);
4120c533a883Shx 		IWK_WRITE(sc, CSR_EEPROM_REG, tmp & ~(0x2));
4121c533a883Shx 
4122c533a883Shx 		for (i = 0; i < 10; i++) {
4123c533a883Shx 			rv = IWK_READ(sc, CSR_EEPROM_REG);
4124c533a883Shx 			if (rv & 1)
4125c533a883Shx 				break;
4126c533a883Shx 			DELAY(10);
4127c533a883Shx 		}
4128c533a883Shx 
4129c533a883Shx 		if (!(rv & 1)) {
4130c50ced99Spengcheng chen - Sun Microsystems - Beijing China 			cmn_err(CE_WARN, "time out when read EEPROM\n");
4131c533a883Shx 			iwk_eep_sem_up(sc);
4132c533a883Shx 			return (IWK_FAIL);
4133c533a883Shx 		}
4134c533a883Shx 
4135b510adaeSfei feng - Sun Microsystems - Beijing China 		eep_p[addr/2] = LE_16(rv >> 16);
4136c533a883Shx 	}
4137c533a883Shx 
4138c533a883Shx 	iwk_eep_sem_up(sc);
4139c533a883Shx 	return (IWK_SUCCESS);
4140c533a883Shx }
4141c533a883Shx 
4142c533a883Shx /*
4143c533a883Shx  * init mac address in ieee80211com_t struct
4144c533a883Shx  */
iwk_get_mac_from_eep(iwk_sc_t * sc)4145c533a883Shx static void iwk_get_mac_from_eep(iwk_sc_t *sc)
4146c533a883Shx {
4147c533a883Shx 	ieee80211com_t *ic = &sc->sc_ic;
4148c533a883Shx 	struct iwk_eep *ep = &sc->sc_eep_map;
4149c533a883Shx 
4150c533a883Shx 	IEEE80211_ADDR_COPY(ic->ic_macaddr, ep->mac_address);
4151c533a883Shx 
4152c533a883Shx 	IWK_DBG((IWK_DEBUG_EEPROM, "mac:%2x:%2x:%2x:%2x:%2x:%2x\n",
4153c533a883Shx 	    ic->ic_macaddr[0], ic->ic_macaddr[1], ic->ic_macaddr[2],
4154c533a883Shx 	    ic->ic_macaddr[3], ic->ic_macaddr[4], ic->ic_macaddr[5]));
4155c533a883Shx }
4156c533a883Shx 
4157c533a883Shx static int
iwk_init(iwk_sc_t * sc)4158c533a883Shx iwk_init(iwk_sc_t *sc)
4159c533a883Shx {
4160c533a883Shx 	int qid, n, err;
4161c533a883Shx 	clock_t clk;
416243439c96Shx 	uint32_t tmp;
4163c533a883Shx 
4164c533a883Shx 	mutex_enter(&sc->sc_glock);
4165c533a883Shx 	sc->sc_flags &= ~IWK_F_FW_INIT;
4166c533a883Shx 
4167c533a883Shx 	(void) iwk_preinit(sc);
4168c533a883Shx 
416943439c96Shx 	tmp = IWK_READ(sc, CSR_GP_CNTRL);
417043439c96Shx 	if (!(tmp & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)) {
4171b510adaeSfei feng - Sun Microsystems - Beijing China 		cmn_err(CE_NOTE, "iwk_init(): Radio transmitter is off\n");
417243439c96Shx 		goto fail1;
417343439c96Shx 	}
417443439c96Shx 
4175c533a883Shx 	/* init Rx ring */
4176c533a883Shx 	iwk_mac_access_enter(sc);
4177c533a883Shx 	IWK_WRITE(sc, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
4178c533a883Shx 
4179c533a883Shx 	IWK_WRITE(sc, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0);
4180c533a883Shx 	IWK_WRITE(sc, FH_RSCSR_CHNL0_RBDCB_BASE_REG,
4181c533a883Shx 	    sc->sc_rxq.dma_desc.cookie.dmac_address >> 8);
4182c533a883Shx 
4183c533a883Shx 	IWK_WRITE(sc, FH_RSCSR_CHNL0_STTS_WPTR_REG,
4184c533a883Shx 	    ((uint32_t)(sc->sc_dma_sh.cookie.dmac_address +
4185c533a883Shx 	    offsetof(struct iwk_shared, val0)) >> 4));
4186c533a883Shx 
4187c533a883Shx 	IWK_WRITE(sc, FH_MEM_RCSR_CHNL0_CONFIG_REG,
4188c533a883Shx 	    FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL |
4189c533a883Shx 	    FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL |
4190c533a883Shx 	    IWK_FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K |
4191c533a883Shx 	    (RX_QUEUE_SIZE_LOG <<
4192c533a883Shx 	    FH_RCSR_RX_CONFIG_RBDCB_SIZE_BITSHIFT));
4193c533a883Shx 	iwk_mac_access_exit(sc);
4194c533a883Shx 	IWK_WRITE(sc, FH_RSCSR_CHNL0_RBDCB_WPTR_REG,
4195c533a883Shx 	    (RX_QUEUE_SIZE - 1) & ~0x7);
4196c533a883Shx 
4197c533a883Shx 	/* init Tx rings */
4198c533a883Shx 	iwk_mac_access_enter(sc);
4199c533a883Shx 	iwk_reg_write(sc, SCD_TXFACT, 0);
4200c533a883Shx 
4201d62cb7ffShx 	/* keep warm page */
4202c533a883Shx 	iwk_reg_write(sc, IWK_FH_KW_MEM_ADDR_REG,
4203c533a883Shx 	    sc->sc_dma_kw.cookie.dmac_address >> 4);
4204c533a883Shx 
4205c533a883Shx 	for (qid = 0; qid < IWK_NUM_QUEUES; qid++) {
4206c533a883Shx 		IWK_WRITE(sc, FH_MEM_CBBC_QUEUE(qid),
4207c533a883Shx 		    sc->sc_txq[qid].dma_desc.cookie.dmac_address >> 8);
4208c533a883Shx 		IWK_WRITE(sc, IWK_FH_TCSR_CHNL_TX_CONFIG_REG(qid),
4209c533a883Shx 		    IWK_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
4210c533a883Shx 		    IWK_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL);
4211c533a883Shx 	}
4212c533a883Shx 	iwk_mac_access_exit(sc);
4213c533a883Shx 
4214c533a883Shx 	/* clear "radio off" and "disable command" bits */
4215c533a883Shx 	IWK_WRITE(sc, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
4216c533a883Shx 	IWK_WRITE(sc, CSR_UCODE_DRV_GP1_CLR,
4217c533a883Shx 	    CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
4218c533a883Shx 
4219c533a883Shx 	/* clear any pending interrupts */
4220c533a883Shx 	IWK_WRITE(sc, CSR_INT, 0xffffffff);
4221c533a883Shx 
4222c533a883Shx 	/* enable interrupts */
4223c533a883Shx 	IWK_WRITE(sc, CSR_INT_MASK, CSR_INI_SET_MASK);
4224c533a883Shx 
4225c533a883Shx 	IWK_WRITE(sc, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
4226c533a883Shx 	IWK_WRITE(sc, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
4227c533a883Shx 
4228c533a883Shx 	/*
4229c533a883Shx 	 * backup ucode data part for future use.
4230c533a883Shx 	 */
4231c533a883Shx 	(void) memcpy(sc->sc_dma_fw_data_bak.mem_va,
4232c533a883Shx 	    sc->sc_dma_fw_data.mem_va,
4233c533a883Shx 	    sc->sc_dma_fw_data.alength);
4234c533a883Shx 
4235c533a883Shx 	for (n = 0; n < 2; n++) {
4236c533a883Shx 		/* load firmware init segment into NIC */
4237c533a883Shx 		err = iwk_load_firmware(sc);
4238c533a883Shx 		if (err != IWK_SUCCESS) {
4239c533a883Shx 			cmn_err(CE_WARN, "iwk_init(): "
4240c533a883Shx 			    "failed to setup boot firmware\n");
4241c533a883Shx 			continue;
4242c533a883Shx 		}
4243c533a883Shx 
4244c533a883Shx 		/* now press "execute" start running */
4245c533a883Shx 		IWK_WRITE(sc, CSR_RESET, 0);
4246c533a883Shx 		break;
4247c533a883Shx 	}
4248c533a883Shx 	if (n == 2) {
4249cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		cmn_err(CE_WARN, "iwk_init(): failed to load firmware\n");
4250c533a883Shx 		goto fail1;
4251c533a883Shx 	}
4252c533a883Shx 	/* ..and wait at most one second for adapter to initialize */
4253c533a883Shx 	clk = ddi_get_lbolt() + drv_usectohz(2000000);
4254c533a883Shx 	while (!(sc->sc_flags & IWK_F_FW_INIT)) {
4255c533a883Shx 		if (cv_timedwait(&sc->sc_fw_cv, &sc->sc_glock, clk) < 0)
4256c533a883Shx 			break;
4257c533a883Shx 	}
4258c533a883Shx 	if (!(sc->sc_flags & IWK_F_FW_INIT)) {
4259c533a883Shx 		cmn_err(CE_WARN,
4260c533a883Shx 		    "iwk_init(): timeout waiting for firmware init\n");
4261c533a883Shx 		goto fail1;
4262c533a883Shx 	}
4263c533a883Shx 
4264c533a883Shx 	/*
4265c533a883Shx 	 * at this point, the firmware is loaded OK, then config the hardware
4266c533a883Shx 	 * with the ucode API, including rxon, txpower, etc.
4267c533a883Shx 	 */
4268c533a883Shx 	err = iwk_config(sc);
4269c533a883Shx 	if (err) {
4270c533a883Shx 		cmn_err(CE_WARN, "iwk_init(): failed to configure device\n");
4271c533a883Shx 		goto fail1;
4272c533a883Shx 	}
4273c533a883Shx 
4274c533a883Shx 	/* at this point, hardware may receive beacons :) */
4275c533a883Shx 	mutex_exit(&sc->sc_glock);
4276c533a883Shx 	return (IWK_SUCCESS);
4277c533a883Shx 
4278c533a883Shx fail1:
4279c533a883Shx 	err = IWK_FAIL;
4280c533a883Shx 	mutex_exit(&sc->sc_glock);
4281c533a883Shx 	return (err);
4282c533a883Shx }
4283c533a883Shx 
4284c533a883Shx static void
iwk_stop(iwk_sc_t * sc)4285c533a883Shx iwk_stop(iwk_sc_t *sc)
4286c533a883Shx {
4287c533a883Shx 	uint32_t tmp;
4288c533a883Shx 	int i;
4289c533a883Shx 
4290d2a61391Spengcheng chen - Sun Microsystems - Beijing China 	if (!(sc->sc_flags & IWK_F_QUIESCED))
4291d2a61391Spengcheng chen - Sun Microsystems - Beijing China 		mutex_enter(&sc->sc_glock);
4292c533a883Shx 
4293c533a883Shx 	IWK_WRITE(sc, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
4294c533a883Shx 	/* disable interrupts */
4295c533a883Shx 	IWK_WRITE(sc, CSR_INT_MASK, 0);
4296c533a883Shx 	IWK_WRITE(sc, CSR_INT, CSR_INI_SET_MASK);
4297c533a883Shx 	IWK_WRITE(sc, CSR_FH_INT_STATUS, 0xffffffff);
4298c533a883Shx 
4299c533a883Shx 	/* reset all Tx rings */
4300c533a883Shx 	for (i = 0; i < IWK_NUM_QUEUES; i++)
4301c533a883Shx 		iwk_reset_tx_ring(sc, &sc->sc_txq[i]);
4302c533a883Shx 
4303c533a883Shx 	/* reset Rx ring */
4304c533a883Shx 	iwk_reset_rx_ring(sc);
4305c533a883Shx 
4306c533a883Shx 	iwk_mac_access_enter(sc);
4307c533a883Shx 	iwk_reg_write(sc, ALM_APMG_CLK_DIS, APMG_CLK_REG_VAL_DMA_CLK_RQT);
4308c533a883Shx 	iwk_mac_access_exit(sc);
4309c533a883Shx 
4310c533a883Shx 	DELAY(5);
4311c533a883Shx 
4312c533a883Shx 	iwk_stop_master(sc);
4313c533a883Shx 
4314c533a883Shx 	sc->sc_tx_timer = 0;
4315f3c4902cSpengcheng chen - Sun Microsystems - Beijing China 	sc->sc_flags &= ~IWK_F_SCANNING;
4316f3c4902cSpengcheng chen - Sun Microsystems - Beijing China 	sc->sc_scan_pending = 0;
4317f3c4902cSpengcheng chen - Sun Microsystems - Beijing China 
4318c533a883Shx 	tmp = IWK_READ(sc, CSR_RESET);
4319c533a883Shx 	IWK_WRITE(sc, CSR_RESET, tmp | CSR_RESET_REG_FLAG_SW_RESET);
4320d2a61391Spengcheng chen - Sun Microsystems - Beijing China 
4321d2a61391Spengcheng chen - Sun Microsystems - Beijing China 	if (!(sc->sc_flags & IWK_F_QUIESCED))
4322d2a61391Spengcheng chen - Sun Microsystems - Beijing China 		mutex_exit(&sc->sc_glock);
4323c533a883Shx }
432443439c96Shx 
432543439c96Shx /*
432643439c96Shx  * Naive implementation of the Adaptive Multi Rate Retry algorithm:
432743439c96Shx  * "IEEE 802.11 Rate Adaptation: A Practical Approach"
432843439c96Shx  * Mathieu Lacage, Hossein Manshaei, Thierry Turletti
432943439c96Shx  * INRIA Sophia - Projet Planete
433043439c96Shx  * http://www-sop.inria.fr/rapports/sophia/RR-5208.html
433143439c96Shx  */
433243439c96Shx #define	is_success(amrr)	\
433343439c96Shx 	((amrr)->retrycnt < (amrr)->txcnt / 10)
433443439c96Shx #define	is_failure(amrr)	\
433543439c96Shx 	((amrr)->retrycnt > (amrr)->txcnt / 3)
433643439c96Shx #define	is_enough(amrr)		\
433743439c96Shx 	((amrr)->txcnt > 100)
433843439c96Shx #define	is_min_rate(in)		\
433943439c96Shx 	((in)->in_txrate == 0)
434043439c96Shx #define	is_max_rate(in)		\
434143439c96Shx 	((in)->in_txrate == (in)->in_rates.ir_nrates - 1)
434243439c96Shx #define	increase_rate(in)	\
434343439c96Shx 	((in)->in_txrate++)
434443439c96Shx #define	decrease_rate(in)	\
434543439c96Shx 	((in)->in_txrate--)
434643439c96Shx #define	reset_cnt(amrr)		\
434743439c96Shx 	{ (amrr)->txcnt = (amrr)->retrycnt = 0; }
434843439c96Shx 
434943439c96Shx #define	IWK_AMRR_MIN_SUCCESS_THRESHOLD	 1
435043439c96Shx #define	IWK_AMRR_MAX_SUCCESS_THRESHOLD	15
435143439c96Shx 
435243439c96Shx static void
iwk_amrr_init(iwk_amrr_t * amrr)435343439c96Shx iwk_amrr_init(iwk_amrr_t *amrr)
435443439c96Shx {
435543439c96Shx 	amrr->success = 0;
435643439c96Shx 	amrr->recovery = 0;
435743439c96Shx 	amrr->txcnt = amrr->retrycnt = 0;
435843439c96Shx 	amrr->success_threshold = IWK_AMRR_MIN_SUCCESS_THRESHOLD;
435943439c96Shx }
436043439c96Shx 
436143439c96Shx static void
iwk_amrr_timeout(iwk_sc_t * sc)436243439c96Shx iwk_amrr_timeout(iwk_sc_t *sc)
436343439c96Shx {
436443439c96Shx 	ieee80211com_t *ic = &sc->sc_ic;
436543439c96Shx 
436643439c96Shx 	IWK_DBG((IWK_DEBUG_RATECTL, "iwk_amrr_timeout() enter\n"));
436743439c96Shx 	if (ic->ic_opmode == IEEE80211_M_STA)
436843439c96Shx 		iwk_amrr_ratectl(NULL, ic->ic_bss);
436943439c96Shx 	else
437043439c96Shx 		ieee80211_iterate_nodes(&ic->ic_sta, iwk_amrr_ratectl, NULL);
437143439c96Shx 	sc->sc_clk = ddi_get_lbolt();
437243439c96Shx }
437343439c96Shx 
437443439c96Shx /* ARGSUSED */
437543439c96Shx static void
iwk_amrr_ratectl(void * arg,ieee80211_node_t * in)437643439c96Shx iwk_amrr_ratectl(void *arg, ieee80211_node_t *in)
437743439c96Shx {
437843439c96Shx 	iwk_amrr_t *amrr = (iwk_amrr_t *)in;
437943439c96Shx 	int need_change = 0;
438043439c96Shx 
438143439c96Shx 	if (is_success(amrr) && is_enough(amrr)) {
438243439c96Shx 		amrr->success++;
438343439c96Shx 		if (amrr->success >= amrr->success_threshold &&
438443439c96Shx 		    !is_max_rate(in)) {
438543439c96Shx 			amrr->recovery = 1;
438643439c96Shx 			amrr->success = 0;
438743439c96Shx 			increase_rate(in);
438843439c96Shx 			IWK_DBG((IWK_DEBUG_RATECTL,
438943439c96Shx 			    "AMRR increasing rate %d (txcnt=%d retrycnt=%d)\n",
439043439c96Shx 			    in->in_txrate, amrr->txcnt, amrr->retrycnt));
439143439c96Shx 			need_change = 1;
439243439c96Shx 		} else {
439343439c96Shx 			amrr->recovery = 0;
439443439c96Shx 		}
439543439c96Shx 	} else if (is_failure(amrr)) {
439643439c96Shx 		amrr->success = 0;
439743439c96Shx 		if (!is_min_rate(in)) {
439843439c96Shx 			if (amrr->recovery) {
439943439c96Shx 				amrr->success_threshold++;
440043439c96Shx 				if (amrr->success_threshold >
440143439c96Shx 				    IWK_AMRR_MAX_SUCCESS_THRESHOLD)
440243439c96Shx 					amrr->success_threshold =
440343439c96Shx 					    IWK_AMRR_MAX_SUCCESS_THRESHOLD;
440443439c96Shx 			} else {
440543439c96Shx 				amrr->success_threshold =
440643439c96Shx 				    IWK_AMRR_MIN_SUCCESS_THRESHOLD;
440743439c96Shx 			}
440843439c96Shx 			decrease_rate(in);
440943439c96Shx 			IWK_DBG((IWK_DEBUG_RATECTL,
441043439c96Shx 			    "AMRR decreasing rate %d (txcnt=%d retrycnt=%d)\n",
441143439c96Shx 			    in->in_txrate, amrr->txcnt, amrr->retrycnt));
441243439c96Shx 			need_change = 1;
441343439c96Shx 		}
441443439c96Shx 		amrr->recovery = 0;	/* paper is incorrect */
441543439c96Shx 	}
441643439c96Shx 
441743439c96Shx 	if (is_enough(amrr) || need_change)
441843439c96Shx 		reset_cnt(amrr);
441943439c96Shx }
4420cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4421cdc64593Sxinghua wen - Sun Microsystems - Beijing China /*
4422cdc64593Sxinghua wen - Sun Microsystems - Beijing China  * calculate 4965 chipset's kelvin temperature according to
4423cdc64593Sxinghua wen - Sun Microsystems - Beijing China  * the data of init alive and satistics notification.
4424cdc64593Sxinghua wen - Sun Microsystems - Beijing China  * The details is described in iwk_calibration.h file
4425cdc64593Sxinghua wen - Sun Microsystems - Beijing China  */
iwk_curr_tempera(iwk_sc_t * sc)4426cdc64593Sxinghua wen - Sun Microsystems - Beijing China static int32_t iwk_curr_tempera(iwk_sc_t *sc)
4427cdc64593Sxinghua wen - Sun Microsystems - Beijing China {
4428cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	int32_t  tempera;
4429cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	int32_t  r1, r2, r3;
4430cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	uint32_t  r4_u;
4431cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	int32_t   r4_s;
4432cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4433cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (iwk_is_fat_channel(sc)) {
4434b510adaeSfei feng - Sun Microsystems - Beijing China 		r1 = (int32_t)LE_32(sc->sc_card_alive_init.therm_r1[1]);
4435b510adaeSfei feng - Sun Microsystems - Beijing China 		r2 = (int32_t)LE_32(sc->sc_card_alive_init.therm_r2[1]);
4436b510adaeSfei feng - Sun Microsystems - Beijing China 		r3 = (int32_t)LE_32(sc->sc_card_alive_init.therm_r3[1]);
4437b510adaeSfei feng - Sun Microsystems - Beijing China 		r4_u = LE_32(sc->sc_card_alive_init.therm_r4[1]);
4438cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	} else {
4439b510adaeSfei feng - Sun Microsystems - Beijing China 		r1 = (int32_t)LE_32(sc->sc_card_alive_init.therm_r1[0]);
4440b510adaeSfei feng - Sun Microsystems - Beijing China 		r2 = (int32_t)LE_32(sc->sc_card_alive_init.therm_r2[0]);
4441b510adaeSfei feng - Sun Microsystems - Beijing China 		r3 = (int32_t)LE_32(sc->sc_card_alive_init.therm_r3[0]);
4442b510adaeSfei feng - Sun Microsystems - Beijing China 		r4_u = LE_32(sc->sc_card_alive_init.therm_r4[0]);
4443cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
4444cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4445cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (sc->sc_flags & IWK_F_STATISTICS) {
4446b510adaeSfei feng - Sun Microsystems - Beijing China 		r4_s = (int32_t)(LE_32(sc->sc_statistics.general.temperature) <<
4447cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		    (31-23)) >> (31-23);
4448cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	} else {
4449cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		r4_s = (int32_t)(r4_u << (31-23)) >> (31-23);
4450cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
4451cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4452cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	IWK_DBG((IWK_DEBUG_CALIBRATION, "temperature R[1-4]: %d %d %d %d\n",
4453cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	    r1, r2, r3, r4_s));
4454cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4455cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (r3 == r1) {
4456cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		cmn_err(CE_WARN, "iwk_curr_tempera(): "
4457cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		    "failed to calculate temperature"
4458cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		    "because r3 = r1\n");
4459cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		return (DDI_FAILURE);
4460cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
4461cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4462cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	tempera = TEMPERATURE_CALIB_A_VAL * (r4_s - r2);
4463cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	tempera /= (r3 - r1);
4464cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	tempera = (tempera*97) / 100 + TEMPERATURE_CALIB_KELVIN_OFFSET;
4465cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4466cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	IWK_DBG((IWK_DEBUG_CALIBRATION, "calculated temperature: %dK, %dC\n",
4467cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	    tempera, KELVIN_TO_CELSIUS(tempera)));
4468cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4469cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	return (tempera);
4470cdc64593Sxinghua wen - Sun Microsystems - Beijing China }
4471cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4472cdc64593Sxinghua wen - Sun Microsystems - Beijing China /* Determine whether 4965 is using 2.4 GHz band */
iwk_is_24G_band(iwk_sc_t * sc)4473cdc64593Sxinghua wen - Sun Microsystems - Beijing China static inline int iwk_is_24G_band(iwk_sc_t *sc)
4474cdc64593Sxinghua wen - Sun Microsystems - Beijing China {
4475b510adaeSfei feng - Sun Microsystems - Beijing China 	return (LE_32(sc->sc_config.flags) & RXON_FLG_BAND_24G_MSK);
4476cdc64593Sxinghua wen - Sun Microsystems - Beijing China }
4477cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4478cdc64593Sxinghua wen - Sun Microsystems - Beijing China /* Determine whether 4965 is using fat channel */
iwk_is_fat_channel(iwk_sc_t * sc)4479cdc64593Sxinghua wen - Sun Microsystems - Beijing China static inline int iwk_is_fat_channel(iwk_sc_t *sc)
4480cdc64593Sxinghua wen - Sun Microsystems - Beijing China {
4481b510adaeSfei feng - Sun Microsystems - Beijing China 	return ((LE_32(sc->sc_config.flags) &
4482b510adaeSfei feng - Sun Microsystems - Beijing China 	    RXON_FLG_CHANNEL_MODE_PURE_40_MSK) ||
4483b510adaeSfei feng - Sun Microsystems - Beijing China 	    (LE_32(sc->sc_config.flags) & RXON_FLG_CHANNEL_MODE_MIXED_MSK));
4484cdc64593Sxinghua wen - Sun Microsystems - Beijing China }
4485cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4486cdc64593Sxinghua wen - Sun Microsystems - Beijing China /*
4487cdc64593Sxinghua wen - Sun Microsystems - Beijing China  * In MIMO mode, determine which group 4965's current channel belong to.
4488cdc64593Sxinghua wen - Sun Microsystems - Beijing China  * For more infomation about "channel group",
4489cdc64593Sxinghua wen - Sun Microsystems - Beijing China  * please refer to iwk_calibration.h file
4490cdc64593Sxinghua wen - Sun Microsystems - Beijing China  */
iwk_txpower_grp(uint16_t channel)4491cdc64593Sxinghua wen - Sun Microsystems - Beijing China static int iwk_txpower_grp(uint16_t channel)
4492cdc64593Sxinghua wen - Sun Microsystems - Beijing China {
4493cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (channel >= CALIB_IWK_TX_ATTEN_GR5_FCH &&
4494cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	    channel <= CALIB_IWK_TX_ATTEN_GR5_LCH) {
4495cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		return (CALIB_CH_GROUP_5);
4496cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
4497cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4498cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (channel >= CALIB_IWK_TX_ATTEN_GR1_FCH &&
4499cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	    channel <= CALIB_IWK_TX_ATTEN_GR1_LCH) {
4500cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		return (CALIB_CH_GROUP_1);
4501cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
4502cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4503cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (channel >= CALIB_IWK_TX_ATTEN_GR2_FCH &&
4504cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	    channel <= CALIB_IWK_TX_ATTEN_GR2_LCH) {
4505cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		return (CALIB_CH_GROUP_2);
4506cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
4507cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4508cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (channel >= CALIB_IWK_TX_ATTEN_GR3_FCH &&
4509cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	    channel <= CALIB_IWK_TX_ATTEN_GR3_LCH) {
4510cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		return (CALIB_CH_GROUP_3);
4511cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
4512cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4513cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (channel >= CALIB_IWK_TX_ATTEN_GR4_FCH &&
4514cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	    channel <= CALIB_IWK_TX_ATTEN_GR4_LCH) {
4515cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		return (CALIB_CH_GROUP_4);
4516cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
4517cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4518cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	cmn_err(CE_WARN, "iwk_txpower_grp(): "
4519cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	    "can't find txpower group for channel %d.\n", channel);
4520cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4521cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	return (DDI_FAILURE);
4522cdc64593Sxinghua wen - Sun Microsystems - Beijing China }
4523cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4524cdc64593Sxinghua wen - Sun Microsystems - Beijing China /* 2.4 GHz */
4525cdc64593Sxinghua wen - Sun Microsystems - Beijing China static uint16_t iwk_eep_band_1[14] = {
4526cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
4527cdc64593Sxinghua wen - Sun Microsystems - Beijing China };
4528cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4529cdc64593Sxinghua wen - Sun Microsystems - Beijing China /* 5.2 GHz bands */
4530cdc64593Sxinghua wen - Sun Microsystems - Beijing China static uint16_t iwk_eep_band_2[13] = {
4531cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	183, 184, 185, 187, 188, 189, 192, 196, 7, 8, 11, 12, 16
4532cdc64593Sxinghua wen - Sun Microsystems - Beijing China };
4533cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4534cdc64593Sxinghua wen - Sun Microsystems - Beijing China static uint16_t iwk_eep_band_3[12] = {
4535cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64
4536cdc64593Sxinghua wen - Sun Microsystems - Beijing China };
4537cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4538cdc64593Sxinghua wen - Sun Microsystems - Beijing China static uint16_t iwk_eep_band_4[11] = {
4539cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140
4540cdc64593Sxinghua wen - Sun Microsystems - Beijing China };
4541cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4542cdc64593Sxinghua wen - Sun Microsystems - Beijing China static uint16_t iwk_eep_band_5[6] = {
4543cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	145, 149, 153, 157, 161, 165
4544cdc64593Sxinghua wen - Sun Microsystems - Beijing China };
4545cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4546cdc64593Sxinghua wen - Sun Microsystems - Beijing China static uint16_t iwk_eep_band_6[7] = {
4547cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	1, 2, 3, 4, 5, 6, 7
4548cdc64593Sxinghua wen - Sun Microsystems - Beijing China };
4549cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4550cdc64593Sxinghua wen - Sun Microsystems - Beijing China static uint16_t iwk_eep_band_7[11] = {
4551cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157
4552cdc64593Sxinghua wen - Sun Microsystems - Beijing China };
4553cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4554cdc64593Sxinghua wen - Sun Microsystems - Beijing China /* Get regulatory data from eeprom for a given channel */
iwk_get_eep_channel(iwk_sc_t * sc,uint16_t channel,int is_24G,int is_fat,int is_hi_chan)4555cdc64593Sxinghua wen - Sun Microsystems - Beijing China static struct iwk_eep_channel *iwk_get_eep_channel(iwk_sc_t *sc,
4556cdc64593Sxinghua wen - Sun Microsystems - Beijing China     uint16_t channel,
4557cdc64593Sxinghua wen - Sun Microsystems - Beijing China     int is_24G, int is_fat, int is_hi_chan)
4558cdc64593Sxinghua wen - Sun Microsystems - Beijing China {
4559cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	int32_t i;
4560cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	uint16_t chan;
4561cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4562cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (is_fat) {  /* 11n mode */
4563cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4564cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		if (is_hi_chan) {
4565cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			chan = channel - 4;
4566cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		} else {
4567cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			chan = channel;
4568cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		}
4569cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4570cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		for (i = 0; i < 7; i++) {
4571cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			if (iwk_eep_band_6[i] == chan) {
4572cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				return (&sc->sc_eep_map.band_24_channels[i]);
4573cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			}
4574cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		}
4575cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		for (i = 0; i < 11; i++) {
4576cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			if (iwk_eep_band_7[i] == chan) {
4577cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				return (&sc->sc_eep_map.band_52_channels[i]);
4578cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			}
4579cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		}
4580cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	} else if (is_24G) {  /* 2.4 GHz band */
4581cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		for (i = 0; i < 14; i++) {
4582cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			if (iwk_eep_band_1[i] == channel) {
4583cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				return (&sc->sc_eep_map.band_1_channels[i]);
4584cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			}
4585cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		}
4586cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	} else {  /* 5 GHz band */
4587cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		for (i = 0; i < 13; i++) {
4588cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			if (iwk_eep_band_2[i] == channel) {
4589cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				return (&sc->sc_eep_map.band_2_channels[i]);
4590cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			}
4591cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		}
4592cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		for (i = 0; i < 12; i++) {
4593cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			if (iwk_eep_band_3[i] == channel) {
4594cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				return (&sc->sc_eep_map.band_3_channels[i]);
4595cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			}
4596cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		}
4597cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		for (i = 0; i < 11; i++) {
4598cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			if (iwk_eep_band_4[i] == channel) {
4599cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				return (&sc->sc_eep_map.band_4_channels[i]);
4600cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			}
4601cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		}
4602cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		for (i = 0; i < 6; i++) {
4603cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			if (iwk_eep_band_5[i] == channel) {
4604cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				return (&sc->sc_eep_map.band_5_channels[i]);
4605cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			}
4606cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		}
4607cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
4608cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4609cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	return (NULL);
4610cdc64593Sxinghua wen - Sun Microsystems - Beijing China }
4611cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4612cdc64593Sxinghua wen - Sun Microsystems - Beijing China /*
4613cdc64593Sxinghua wen - Sun Microsystems - Beijing China  * Determine which subband a given channel belongs
4614cdc64593Sxinghua wen - Sun Microsystems - Beijing China  * to in 2.4 GHz or 5 GHz band
4615cdc64593Sxinghua wen - Sun Microsystems - Beijing China  */
iwk_band_number(iwk_sc_t * sc,uint16_t channel)4616cdc64593Sxinghua wen - Sun Microsystems - Beijing China static int32_t iwk_band_number(iwk_sc_t *sc, uint16_t channel)
4617cdc64593Sxinghua wen - Sun Microsystems - Beijing China {
4618cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	int32_t b_n = -1;
4619cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4620cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	for (b_n = 0; b_n < EEP_TX_POWER_BANDS; b_n++) {
4621cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		if (0 == sc->sc_eep_map.calib_info.band_info_tbl[b_n].ch_from) {
4622cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			continue;
4623cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		}
4624cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4625cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		if ((channel >=
4626cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		    (uint16_t)sc->sc_eep_map.calib_info.
4627cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		    band_info_tbl[b_n].ch_from) &&
4628cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		    (channel <=
4629cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		    (uint16_t)sc->sc_eep_map.calib_info.
4630cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		    band_info_tbl[b_n].ch_to)) {
4631cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			break;
4632cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		}
4633cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
4634cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4635cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	return (b_n);
4636cdc64593Sxinghua wen - Sun Microsystems - Beijing China }
4637cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4638cdc64593Sxinghua wen - Sun Microsystems - Beijing China /* Make a special division for interpolation operation */
iwk_division(int32_t num,int32_t denom,int32_t * res)4639cdc64593Sxinghua wen - Sun Microsystems - Beijing China static int iwk_division(int32_t num, int32_t denom, int32_t *res)
4640cdc64593Sxinghua wen - Sun Microsystems - Beijing China {
4641cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	int32_t sign = 1;
4642cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4643cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (num < 0) {
4644cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		sign = -sign;
4645cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		num = -num;
4646cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
4647cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4648cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (denom < 0) {
4649cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		sign = -sign;
4650cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		denom = -denom;
4651cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
4652cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4653cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	*res = ((num*2 + denom) / (denom*2)) * sign;
4654cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4655cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	return (IWK_SUCCESS);
4656cdc64593Sxinghua wen - Sun Microsystems - Beijing China }
4657cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4658cdc64593Sxinghua wen - Sun Microsystems - Beijing China /* Make interpolation operation */
iwk_interpolate_value(int32_t x,int32_t x1,int32_t y1,int32_t x2,int32_t y2)4659cdc64593Sxinghua wen - Sun Microsystems - Beijing China static int32_t iwk_interpolate_value(int32_t x, int32_t x1, int32_t y1,
4660cdc64593Sxinghua wen - Sun Microsystems - Beijing China     int32_t x2, int32_t y2)
4661cdc64593Sxinghua wen - Sun Microsystems - Beijing China {
4662cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	int32_t val;
4663cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4664cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (x2 == x1) {
4665cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		return (y1);
4666cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	} else {
4667cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		(void) iwk_division((x2-x)*(y1-y2), (x2-x1), &val);
4668cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		return (val + y2);
4669cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
4670cdc64593Sxinghua wen - Sun Microsystems - Beijing China }
4671cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4672cdc64593Sxinghua wen - Sun Microsystems - Beijing China /* Get interpolation measurement data of a given channel for all chains. */
iwk_channel_interpolate(iwk_sc_t * sc,uint16_t channel,struct iwk_eep_calib_channel_info * chan_info)4673cdc64593Sxinghua wen - Sun Microsystems - Beijing China static int iwk_channel_interpolate(iwk_sc_t *sc, uint16_t channel,
4674cdc64593Sxinghua wen - Sun Microsystems - Beijing China     struct iwk_eep_calib_channel_info *chan_info)
4675cdc64593Sxinghua wen - Sun Microsystems - Beijing China {
4676cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	int32_t ban_n;
4677cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	uint32_t ch1_n, ch2_n;
4678cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	int32_t c, m;
4679cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	struct iwk_eep_calib_measure *m1_p, *m2_p, *m_p;
4680cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4681cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	/* determine subband number */
4682cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	ban_n = iwk_band_number(sc, channel);
4683cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (ban_n >= EEP_TX_POWER_BANDS) {
4684cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		return (DDI_FAILURE);
4685cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
4686cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4687cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	ch1_n =
4688cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	    (uint32_t)sc->sc_eep_map.calib_info.band_info_tbl[ban_n].ch1.ch_num;
4689cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	ch2_n =
4690cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	    (uint32_t)sc->sc_eep_map.calib_info.band_info_tbl[ban_n].ch2.ch_num;
4691cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4692cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	chan_info->ch_num = (uint8_t)channel;  /* given channel number */
4693cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4694cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	/*
4695cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	 * go through all chains on chipset
4696cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	 */
4697cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	for (c = 0; c < EEP_TX_POWER_TX_CHAINS; c++) {
4698cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		/*
4699cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		 * go through all factory measurements
4700cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		 */
4701cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		for (m = 0; m < EEP_TX_POWER_MEASUREMENTS; m++) {
4702cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			m1_p =
4703cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			    &(sc->sc_eep_map.calib_info.
4704cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			    band_info_tbl[ban_n].ch1.measure[c][m]);
4705cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			m2_p =
4706cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			    &(sc->sc_eep_map.calib_info.band_info_tbl[ban_n].
4707cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			    ch2.measure[c][m]);
4708cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			m_p = &(chan_info->measure[c][m]);
4709cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4710cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			/*
4711cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			 * make interpolation to get actual
4712cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			 * Tx power for given channel
4713cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			 */
4714cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			m_p->actual_pow = iwk_interpolate_value(channel,
4715cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			    ch1_n, m1_p->actual_pow,
4716cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			    ch2_n, m2_p->actual_pow);
4717cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4718cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			/* make interpolation to get index into gain table */
4719cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			m_p->gain_idx = iwk_interpolate_value(channel,
4720cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			    ch1_n, m1_p->gain_idx,
4721cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			    ch2_n, m2_p->gain_idx);
4722cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4723cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			/* make interpolation to get chipset temperature */
4724cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			m_p->temperature = iwk_interpolate_value(channel,
4725cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			    ch1_n, m1_p->temperature,
4726cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			    ch2_n, m2_p->temperature);
4727cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4728cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			/*
4729cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			 * make interpolation to get power
4730cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			 * amp detector level
4731cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			 */
4732cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			m_p->pa_det = iwk_interpolate_value(channel, ch1_n,
4733cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			    m1_p->pa_det,
4734cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			    ch2_n, m2_p->pa_det);
4735cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		}
4736cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
4737cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4738cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	return (IWK_SUCCESS);
4739cdc64593Sxinghua wen - Sun Microsystems - Beijing China }
4740cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4741cdc64593Sxinghua wen - Sun Microsystems - Beijing China /*
4742cdc64593Sxinghua wen - Sun Microsystems - Beijing China  * Calculate voltage compensation for Tx power. For more infomation,
4743cdc64593Sxinghua wen - Sun Microsystems - Beijing China  * please refer to iwk_calibration.h file
4744cdc64593Sxinghua wen - Sun Microsystems - Beijing China  */
iwk_voltage_compensation(int32_t eep_voltage,int32_t curr_voltage)4745cdc64593Sxinghua wen - Sun Microsystems - Beijing China static int32_t iwk_voltage_compensation(int32_t eep_voltage,
4746cdc64593Sxinghua wen - Sun Microsystems - Beijing China     int32_t curr_voltage)
4747cdc64593Sxinghua wen - Sun Microsystems - Beijing China {
4748cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	int32_t vol_comp = 0;
4749cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4750cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if ((TX_POWER_IWK_ILLEGAL_VOLTAGE == eep_voltage) ||
4751cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	    (TX_POWER_IWK_ILLEGAL_VOLTAGE == curr_voltage)) {
4752cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		return (vol_comp);
4753cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
4754cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4755cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	(void) iwk_division(curr_voltage-eep_voltage,
4756cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	    TX_POWER_IWK_VOLTAGE_CODES_PER_03V, &vol_comp);
4757cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4758cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (curr_voltage > eep_voltage) {
4759cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		vol_comp *= 2;
4760cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
4761cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if ((vol_comp < -2) || (vol_comp > 2)) {
4762cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		vol_comp = 0;
4763cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
4764cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4765cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	return (vol_comp);
4766cdc64593Sxinghua wen - Sun Microsystems - Beijing China }
4767cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4768cdc64593Sxinghua wen - Sun Microsystems - Beijing China /*
4769cdc64593Sxinghua wen - Sun Microsystems - Beijing China  * Thermal compensation values for txpower for various frequency ranges ...
4770cdc64593Sxinghua wen - Sun Microsystems - Beijing China  * ratios from 3:1 to 4.5:1 of degrees (Celsius) per half-dB gain adjust
4771cdc64593Sxinghua wen - Sun Microsystems - Beijing China  */
4772cdc64593Sxinghua wen - Sun Microsystems - Beijing China static struct iwk_txpower_tempera_comp {
4773cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	int32_t degrees_per_05db_a;
4774cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	int32_t degrees_per_05db_a_denom;
4775cdc64593Sxinghua wen - Sun Microsystems - Beijing China } txpower_tempera_comp_table[CALIB_CH_GROUP_MAX] = {
4776cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	{9, 2},			/* group 0 5.2, ch  34-43 */
4777cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	{4, 1},			/* group 1 5.2, ch  44-70 */
4778cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	{4, 1},			/* group 2 5.2, ch  71-124 */
4779cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	{4, 1},			/* group 3 5.2, ch 125-200 */
4780cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	{3, 1}			/* group 4 2.4, ch   all */
4781cdc64593Sxinghua wen - Sun Microsystems - Beijing China };
4782cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4783cdc64593Sxinghua wen - Sun Microsystems - Beijing China /*
4784cdc64593Sxinghua wen - Sun Microsystems - Beijing China  * bit-rate-dependent table to prevent Tx distortion, in half-dB units,
4785cdc64593Sxinghua wen - Sun Microsystems - Beijing China  * for OFDM 6, 12, 18, 24, 36, 48, 54, 60 MBit, and CCK all rates.
4786cdc64593Sxinghua wen - Sun Microsystems - Beijing China  */
4787cdc64593Sxinghua wen - Sun Microsystems - Beijing China static int32_t back_off_table[] = {
4788cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	10, 10, 10, 10, 10, 15, 17, 20, /* OFDM SISO 20 MHz */
4789cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	10, 10, 10, 10, 10, 15, 17, 20, /* OFDM MIMO 20 MHz */
4790cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	10, 10, 10, 10, 10, 15, 17, 20, /* OFDM SISO 40 MHz */
4791cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	10, 10, 10, 10, 10, 15, 17, 20, /* OFDM MIMO 40 MHz */
4792cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	10			/* CCK */
4793cdc64593Sxinghua wen - Sun Microsystems - Beijing China };
4794cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4795cdc64593Sxinghua wen - Sun Microsystems - Beijing China /* determine minimum Tx power index in gain table */
iwk_min_power_index(int32_t rate_pow_idx,int32_t is_24G)4796cdc64593Sxinghua wen - Sun Microsystems - Beijing China static int32_t iwk_min_power_index(int32_t rate_pow_idx, int32_t is_24G)
4797cdc64593Sxinghua wen - Sun Microsystems - Beijing China {
4798cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if ((!is_24G) && ((rate_pow_idx & 7) <= 4)) {
4799cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		return (MIN_TX_GAIN_INDEX_52GHZ_EXT);
4800cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
4801cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4802cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	return (MIN_TX_GAIN_INDEX);
4803cdc64593Sxinghua wen - Sun Microsystems - Beijing China }
4804cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4805cdc64593Sxinghua wen - Sun Microsystems - Beijing China /*
4806cdc64593Sxinghua wen - Sun Microsystems - Beijing China  * Determine DSP and radio gain according to temperature and other factors.
4807cdc64593Sxinghua wen - Sun Microsystems - Beijing China  * This function is the majority of Tx power calibration
4808cdc64593Sxinghua wen - Sun Microsystems - Beijing China  */
iwk_txpower_table_cmd_init(iwk_sc_t * sc,struct iwk_tx_power_db * tp_db)4809cdc64593Sxinghua wen - Sun Microsystems - Beijing China static int iwk_txpower_table_cmd_init(iwk_sc_t *sc,
4810cdc64593Sxinghua wen - Sun Microsystems - Beijing China     struct iwk_tx_power_db *tp_db)
4811cdc64593Sxinghua wen - Sun Microsystems - Beijing China {
4812cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	int is_24G, is_fat, is_high_chan, is_mimo;
4813cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	int c, r;
4814cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	int32_t target_power;
4815cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	int32_t tx_grp = CALIB_CH_GROUP_MAX;
4816cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	uint16_t channel;
4817cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	uint8_t saturation_power;
4818cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	int32_t regu_power;
4819cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	int32_t curr_regu_power;
4820cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	struct iwk_eep_channel *eep_chan_p;
4821cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	struct iwk_eep_calib_channel_info eep_chan_calib;
4822cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	int32_t eep_voltage, init_voltage;
4823cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	int32_t voltage_compensation;
4824cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	int32_t temperature;
4825cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	int32_t degrees_per_05db_num;
4826cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	int32_t degrees_per_05db_denom;
4827cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	struct iwk_eep_calib_measure *measure_p;
4828cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	int32_t interpo_temp;
4829cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	int32_t power_limit;
4830cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	int32_t atten_value;
4831cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	int32_t tempera_comp[2];
4832cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	int32_t interpo_gain_idx[2];
4833cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	int32_t interpo_actual_pow[2];
4834cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	union iwk_tx_power_dual_stream txpower_gains;
4835cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	int32_t txpower_gains_idx;
4836cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4837b510adaeSfei feng - Sun Microsystems - Beijing China 	channel = LE_16(sc->sc_config.chan);
4838cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4839cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	/* 2.4 GHz or 5 GHz band */
4840cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	is_24G = iwk_is_24G_band(sc);
4841cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4842cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	/* fat channel or not */
4843cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	is_fat = iwk_is_fat_channel(sc);
4844cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4845cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	/*
4846cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	 * using low half channel number or high half channel number
4847cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	 * identify fat channel
4848cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	 */
4849b510adaeSfei feng - Sun Microsystems - Beijing China 	if (is_fat && (LE_32(sc->sc_config.flags) &
4850cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	    RXON_FLG_CONTROL_CHANNEL_LOC_HIGH_MSK)) {
4851cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		is_high_chan = 1;
4852cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
4853cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4854cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if ((channel > 0) && (channel < 200)) {
4855cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		/* get regulatory channel data from eeprom */
4856cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		eep_chan_p = iwk_get_eep_channel(sc, channel, is_24G,
4857cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		    is_fat, is_high_chan);
4858cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		if (NULL == eep_chan_p) {
4859cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			cmn_err(CE_WARN,
4860cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			    "iwk_txpower_table_cmd_init(): "
4861cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			    "can't get channel infomation\n");
4862cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			return (DDI_FAILURE);
4863cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		}
4864cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	} else {
4865cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		cmn_err(CE_WARN, "iwk_txpower_table_cmd_init(): "
4866cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		    "channel(%d) isn't in proper range\n",
4867cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		    channel);
4868cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		return (DDI_FAILURE);
4869cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
4870cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4871cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	/* initial value of Tx power */
4872cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	sc->sc_user_txpower = (int32_t)eep_chan_p->max_power_avg;
4873cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (sc->sc_user_txpower < IWK_TX_POWER_TARGET_POWER_MIN) {
4874cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		cmn_err(CE_WARN, "iwk_txpower_table_cmd_init(): "
4875cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		    "user TX power is too weak\n");
4876cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		return (DDI_FAILURE);
4877cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	} else if (sc->sc_user_txpower > IWK_TX_POWER_TARGET_POWER_MAX) {
4878cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		cmn_err(CE_WARN, "iwk_txpower_table_cmd_init(): "
4879cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		    "user TX power is too strong\n");
4880cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		return (DDI_FAILURE);
4881cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
4882cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4883cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	target_power = 2 * sc->sc_user_txpower;
4884cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4885cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	/* determine which group current channel belongs to */
4886cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	tx_grp = iwk_txpower_grp(channel);
4887cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (tx_grp < 0) {
4888cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		return (tx_grp);
4889cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
4890cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4891cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4892cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (is_fat) {
4893cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		if (is_high_chan) {
4894cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			channel -= 2;
4895cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		} else {
4896cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			channel += 2;
4897cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		}
4898cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
4899cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4900cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	/* determine saturation power */
4901cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (is_24G) {
4902cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		saturation_power =
4903cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		    sc->sc_eep_map.calib_info.saturation_power24;
4904cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	} else {
4905cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		saturation_power =
4906cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		    sc->sc_eep_map.calib_info.saturation_power52;
4907cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
4908cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4909cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (saturation_power < IWK_TX_POWER_SATURATION_MIN ||
4910cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	    saturation_power > IWK_TX_POWER_SATURATION_MAX) {
4911cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		if (is_24G) {
4912cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			saturation_power = IWK_TX_POWER_DEFAULT_SATURATION_24;
4913cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		} else {
4914cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			saturation_power = IWK_TX_POWER_DEFAULT_SATURATION_52;
4915cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		}
4916cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
4917cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4918cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	/* determine regulatory power */
4919cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	regu_power = (int32_t)eep_chan_p->max_power_avg * 2;
4920cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if ((regu_power < IWK_TX_POWER_REGULATORY_MIN) ||
4921cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	    (regu_power > IWK_TX_POWER_REGULATORY_MAX)) {
4922cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		if (is_24G) {
4923cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			regu_power = IWK_TX_POWER_DEFAULT_REGULATORY_24;
4924cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		} else {
4925cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			regu_power = IWK_TX_POWER_DEFAULT_REGULATORY_52;
4926cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		}
4927cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
4928cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4929cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	/*
4930cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	 * get measurement data for current channel
4931cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	 * suach as temperature,index to gain table,actual Tx power
4932cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	 */
4933cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	(void) iwk_channel_interpolate(sc, channel, &eep_chan_calib);
4934cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4935b510adaeSfei feng - Sun Microsystems - Beijing China 	eep_voltage = (int32_t)LE_16(sc->sc_eep_map.calib_info.voltage);
4936b510adaeSfei feng - Sun Microsystems - Beijing China 	init_voltage = (int32_t)LE_32(sc->sc_card_alive_init.voltage);
4937cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4938cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	/* calculate voltage compensation to Tx power */
4939cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	voltage_compensation =
4940cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	    iwk_voltage_compensation(eep_voltage, init_voltage);
4941cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4942cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (sc->sc_tempera >= IWK_TX_POWER_TEMPERATURE_MIN) {
4943cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		temperature = sc->sc_tempera;
4944cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	} else {
4945cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		temperature = IWK_TX_POWER_TEMPERATURE_MIN;
4946cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
4947cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (sc->sc_tempera <= IWK_TX_POWER_TEMPERATURE_MAX) {
4948cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		temperature = sc->sc_tempera;
4949cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	} else {
4950cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		temperature = IWK_TX_POWER_TEMPERATURE_MAX;
4951cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
4952cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	temperature = KELVIN_TO_CELSIUS(temperature);
4953cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4954cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	degrees_per_05db_num =
4955cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	    txpower_tempera_comp_table[tx_grp].degrees_per_05db_a;
4956cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	degrees_per_05db_denom =
4957cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	    txpower_tempera_comp_table[tx_grp].degrees_per_05db_a_denom;
4958cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4959cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	for (c = 0; c < 2; c++) {  /* go through all chains */
4960cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		measure_p = &eep_chan_calib.measure[c][1];
4961cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		interpo_temp = measure_p->temperature;
4962cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4963cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		/* determine temperature compensation to Tx power */
4964cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		(void) iwk_division(
4965cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		    (temperature-interpo_temp)*degrees_per_05db_denom,
4966cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		    degrees_per_05db_num, &tempera_comp[c]);
4967cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4968cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		interpo_gain_idx[c] = measure_p->gain_idx;
4969cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		interpo_actual_pow[c] = measure_p->actual_pow;
4970cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
4971cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4972cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	/*
4973cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	 * go through all rate entries in Tx power table
4974cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	 */
4975cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	for (r = 0; r < POWER_TABLE_NUM_ENTRIES; r++) {
4976cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		if (r & 0x8) {
4977cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			/* need to lower regulatory power for MIMO mode */
4978cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			curr_regu_power = regu_power -
4979cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			    IWK_TX_POWER_MIMO_REGULATORY_COMPENSATION;
4980cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			is_mimo = 1;
4981cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		} else {
4982cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			curr_regu_power = regu_power;
4983cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			is_mimo = 0;
4984cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		}
4985cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4986cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		power_limit = saturation_power - back_off_table[r];
4987cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		if (power_limit > curr_regu_power) {
4988cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			/* final Tx power limit */
4989cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			power_limit = curr_regu_power;
4990cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		}
4991cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4992cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		if (target_power > power_limit) {
4993cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			target_power = power_limit; /* final target Tx power */
4994cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		}
4995cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
4996cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		for (c = 0; c < 2; c++) {	  /* go through all Tx chains */
4997cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			if (is_mimo) {
4998cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				atten_value =
4999b510adaeSfei feng - Sun Microsystems - Beijing China 				    LE_32(sc->sc_card_alive_init.
5000b510adaeSfei feng - Sun Microsystems - Beijing China 				    tx_atten[tx_grp][c]);
5001cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			} else {
5002cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				atten_value = 0;
5003cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			}
5004cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5005cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			/*
5006cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			 * calculate index in gain table
5007cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			 * this step is very important
5008cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			 */
5009cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			txpower_gains_idx = interpo_gain_idx[c] -
5010cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			    (target_power - interpo_actual_pow[c]) -
5011cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			    tempera_comp[c] - voltage_compensation +
5012cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			    atten_value;
5013cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5014cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			if (txpower_gains_idx <
5015cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			    iwk_min_power_index(r, is_24G)) {
5016cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				txpower_gains_idx =
5017cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				    iwk_min_power_index(r, is_24G);
5018cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			}
5019cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5020cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			if (!is_24G) {
5021cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				/*
5022cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				 * support negative index for 5 GHz
5023cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				 * band
5024cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				 */
5025cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				txpower_gains_idx += 9;
5026cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			}
5027cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5028cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			if (POWER_TABLE_CCK_ENTRY == r) {
5029cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				/* for CCK mode, make necessary attenuaton */
5030cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				txpower_gains_idx +=
5031cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				    IWK_TX_POWER_CCK_COMPENSATION_C_STEP;
5032cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			}
5033cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5034cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			if (txpower_gains_idx > 107) {
5035cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				txpower_gains_idx = 107;
5036cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			} else if (txpower_gains_idx < 0) {
5037cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				txpower_gains_idx = 0;
5038cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			}
5039cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5040cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			/* search DSP and radio gains in gain table */
5041cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			txpower_gains.s.radio_tx_gain[c] =
5042cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			    gains_table[is_24G][txpower_gains_idx].radio;
5043cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			txpower_gains.s.dsp_predis_atten[c] =
5044cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			    gains_table[is_24G][txpower_gains_idx].dsp;
5045cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5046cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			IWK_DBG((IWK_DEBUG_CALIBRATION,
5047cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			    "rate_index: %d, "
5048cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			    "gain_index %d, c: %d,is_mimo: %d\n",
5049cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			    r, txpower_gains_idx, c, is_mimo));
5050cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		}
5051cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5052cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		/* initialize Tx power table */
5053cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		if (r < POWER_TABLE_NUM_HT_OFDM_ENTRIES) {
5054b510adaeSfei feng - Sun Microsystems - Beijing China 			tp_db->ht_ofdm_power[r].dw = LE_32(txpower_gains.dw);
5055cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		} else {
5056b510adaeSfei feng - Sun Microsystems - Beijing China 			tp_db->legacy_cck_power.dw = LE_32(txpower_gains.dw);
5057cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		}
5058cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
5059cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5060cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	return (IWK_SUCCESS);
5061cdc64593Sxinghua wen - Sun Microsystems - Beijing China }
5062cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5063cdc64593Sxinghua wen - Sun Microsystems - Beijing China /*
5064cdc64593Sxinghua wen - Sun Microsystems - Beijing China  * make Tx power calibration to adjust Tx power.
5065cdc64593Sxinghua wen - Sun Microsystems - Beijing China  * This is completed by sending out Tx power table command.
5066cdc64593Sxinghua wen - Sun Microsystems - Beijing China  */
iwk_tx_power_calibration(iwk_sc_t * sc)5067cdc64593Sxinghua wen - Sun Microsystems - Beijing China static int iwk_tx_power_calibration(iwk_sc_t *sc)
5068cdc64593Sxinghua wen - Sun Microsystems - Beijing China {
5069cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	iwk_tx_power_table_cmd_t cmd;
5070cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	int rv;
5071cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5072cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (sc->sc_flags & IWK_F_SCANNING) {
5073cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		return (IWK_SUCCESS);
5074cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
5075cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5076cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	/* necessary initialization to Tx power table command */
5077cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	cmd.band = (uint8_t)iwk_is_24G_band(sc);
5078cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	cmd.channel = sc->sc_config.chan;
5079cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	cmd.channel_normal_width = 0;
5080cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5081cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	/* initialize Tx power table */
5082cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	rv = iwk_txpower_table_cmd_init(sc, &cmd.tx_power);
5083cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (rv) {
5084cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		cmn_err(CE_NOTE, "rv= %d\n", rv);
5085cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		return (rv);
5086cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
5087cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5088cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	/* send out Tx power table command */
5089cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	rv = iwk_cmd(sc, REPLY_TX_PWR_TABLE_CMD, &cmd, sizeof (cmd), 1);
5090cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (rv) {
5091cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		return (rv);
5092cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
5093cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5094cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	/* record current temperature */
5095cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	sc->sc_last_tempera = sc->sc_tempera;
5096cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5097cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	return (IWK_SUCCESS);
5098cdc64593Sxinghua wen - Sun Microsystems - Beijing China }
5099cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5100cdc64593Sxinghua wen - Sun Microsystems - Beijing China /* This function is the handler of statistics notification from uCode */
iwk_statistics_notify(iwk_sc_t * sc,iwk_rx_desc_t * desc)5101cdc64593Sxinghua wen - Sun Microsystems - Beijing China static void iwk_statistics_notify(iwk_sc_t *sc, iwk_rx_desc_t *desc)
5102cdc64593Sxinghua wen - Sun Microsystems - Beijing China {
5103cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	int is_diff;
5104cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	struct iwk_notif_statistics *statistics_p =
5105cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	    (struct iwk_notif_statistics *)(desc + 1);
5106cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5107cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	mutex_enter(&sc->sc_glock);
5108cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5109cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	is_diff = (sc->sc_statistics.general.temperature !=
5110cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	    statistics_p->general.temperature) ||
5111b510adaeSfei feng - Sun Microsystems - Beijing China 	    (LE_32(sc->sc_statistics.flag) &
5112b510adaeSfei feng - Sun Microsystems - Beijing China 	    STATISTICS_REPLY_FLG_FAT_MODE_MSK) !=
5113b510adaeSfei feng - Sun Microsystems - Beijing China 	    (LE_32(statistics_p->flag) & STATISTICS_REPLY_FLG_FAT_MODE_MSK);
5114cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5115cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	/* update statistics data */
5116cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	(void) memcpy(&sc->sc_statistics, statistics_p,
5117cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	    sizeof (struct iwk_notif_statistics));
5118cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5119cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	sc->sc_flags |= IWK_F_STATISTICS;
5120cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5121cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (!(sc->sc_flags & IWK_F_SCANNING)) {
5122cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		/* make Receiver gain balance calibration */
5123cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		(void) iwk_rxgain_diff(sc);
5124cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5125cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		/* make Receiver sensitivity calibration */
5126cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		(void) iwk_rx_sens(sc);
5127cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
5128cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5129cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5130cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (!is_diff) {
5131cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		mutex_exit(&sc->sc_glock);
5132cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		return;
5133cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
5134cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5135cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	/* calibration current temperature of 4965 chipset */
5136cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	sc->sc_tempera = iwk_curr_tempera(sc);
5137cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5138cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	/* distinct temperature change will trigger Tx power calibration */
5139cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (((sc->sc_tempera - sc->sc_last_tempera) >= 3) ||
5140cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	    ((sc->sc_last_tempera - sc->sc_tempera) >= 3)) {
5141cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		/* make Tx power calibration */
5142cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		(void) iwk_tx_power_calibration(sc);
5143cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
5144cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5145cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	mutex_exit(&sc->sc_glock);
5146cdc64593Sxinghua wen - Sun Microsystems - Beijing China }
5147cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5148cdc64593Sxinghua wen - Sun Microsystems - Beijing China /* Determine this station is in associated state or not */
iwk_is_associated(iwk_sc_t * sc)5149cdc64593Sxinghua wen - Sun Microsystems - Beijing China static int iwk_is_associated(iwk_sc_t *sc)
5150cdc64593Sxinghua wen - Sun Microsystems - Beijing China {
5151b510adaeSfei feng - Sun Microsystems - Beijing China 	return (LE_32(sc->sc_config.filter_flags) & RXON_FILTER_ASSOC_MSK);
5152cdc64593Sxinghua wen - Sun Microsystems - Beijing China }
5153cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5154cdc64593Sxinghua wen - Sun Microsystems - Beijing China /* Make necessary preparation for Receiver gain balance calibration */
iwk_rxgain_diff_init(iwk_sc_t * sc)5155cdc64593Sxinghua wen - Sun Microsystems - Beijing China static int iwk_rxgain_diff_init(iwk_sc_t *sc)
5156cdc64593Sxinghua wen - Sun Microsystems - Beijing China {
5157cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	int i, rv;
5158cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	struct iwk_calibration_cmd cmd;
5159cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	struct iwk_rx_gain_diff *gain_diff_p;
5160cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5161cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	gain_diff_p = &sc->sc_rxgain_diff;
5162cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5163cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	(void) memset(gain_diff_p, 0, sizeof (struct iwk_rx_gain_diff));
5164cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	(void) memset(&cmd, 0, sizeof (struct iwk_calibration_cmd));
5165cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5166cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	for (i = 0; i < RX_CHAINS_NUM; i++) {
5167cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		gain_diff_p->gain_diff_chain[i] = CHAIN_GAIN_DIFF_INIT_VAL;
5168cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
5169cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5170cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (iwk_is_associated(sc)) {
5171cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		cmd.opCode = PHY_CALIBRATE_DIFF_GAIN_CMD;
5172cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		cmd.diff_gain_a = 0;
5173cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		cmd.diff_gain_b = 0;
5174cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		cmd.diff_gain_c = 0;
5175cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5176cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		/* assume the gains of every Rx chains is balanceable */
5177cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		rv = iwk_cmd(sc, REPLY_PHY_CALIBRATION_CMD, &cmd,
5178cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		    sizeof (cmd), 1);
5179cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		if (rv) {
5180cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			return (rv);
5181cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		}
5182cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5183cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		gain_diff_p->state = IWK_GAIN_DIFF_ACCUMULATE;
5184cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
5185cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5186cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	return (IWK_SUCCESS);
5187cdc64593Sxinghua wen - Sun Microsystems - Beijing China }
5188cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5189cdc64593Sxinghua wen - Sun Microsystems - Beijing China /*
5190cdc64593Sxinghua wen - Sun Microsystems - Beijing China  * make Receiver gain balance to balance Rx gain between Rx chains
5191cdc64593Sxinghua wen - Sun Microsystems - Beijing China  * and determine which chain is disconnected
5192cdc64593Sxinghua wen - Sun Microsystems - Beijing China  */
iwk_rxgain_diff(iwk_sc_t * sc)5193cdc64593Sxinghua wen - Sun Microsystems - Beijing China static int iwk_rxgain_diff(iwk_sc_t *sc)
5194cdc64593Sxinghua wen - Sun Microsystems - Beijing China {
5195cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	int i, is_24G, rv;
5196cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	int max_beacon_chain_n;
5197cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	int min_noise_chain_n;
5198cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	uint16_t channel_n;
5199cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	int32_t beacon_diff;
5200cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	int32_t noise_diff;
5201cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	uint32_t noise_chain_a, noise_chain_b, noise_chain_c;
5202cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	uint32_t beacon_chain_a, beacon_chain_b, beacon_chain_c;
5203cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	struct iwk_calibration_cmd cmd;
5204cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	uint32_t beacon_aver[RX_CHAINS_NUM] = {0xFFFFFFFF};
5205cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	uint32_t noise_aver[RX_CHAINS_NUM] = {0xFFFFFFFF};
5206cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	struct statistics_rx_non_phy *rx_general_p =
5207cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	    &sc->sc_statistics.rx.general;
5208cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	struct iwk_rx_gain_diff *gain_diff_p = &sc->sc_rxgain_diff;
5209cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5210cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (INTERFERENCE_DATA_AVAILABLE !=
5211b510adaeSfei feng - Sun Microsystems - Beijing China 	    LE_32(rx_general_p->interference_data_flag)) {
5212cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		return (IWK_SUCCESS);
5213cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
5214cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5215cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (IWK_GAIN_DIFF_ACCUMULATE != gain_diff_p->state) {
5216cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		return (IWK_SUCCESS);
5217cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
5218cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5219cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	is_24G = iwk_is_24G_band(sc);
5220cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	channel_n = sc->sc_config.chan;	 /* channel number */
5221cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5222b510adaeSfei feng - Sun Microsystems - Beijing China 	if ((channel_n != (LE_32(sc->sc_statistics.flag) >> 16)) ||
5223cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	    ((STATISTICS_REPLY_FLG_BAND_24G_MSK ==
5224b510adaeSfei feng - Sun Microsystems - Beijing China 	    (LE_32(sc->sc_statistics.flag) &
5225b510adaeSfei feng - Sun Microsystems - Beijing China 	    STATISTICS_REPLY_FLG_BAND_24G_MSK)) &&
5226cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	    !is_24G)) {
5227cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		return (IWK_SUCCESS);
5228cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
5229cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5230cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	/* Rx chain's noise strength from statistics notification */
5231b510adaeSfei feng - Sun Microsystems - Beijing China 	noise_chain_a = LE_32(rx_general_p->beacon_silence_rssi_a) & 0xFF;
5232b510adaeSfei feng - Sun Microsystems - Beijing China 	noise_chain_b = LE_32(rx_general_p->beacon_silence_rssi_b) & 0xFF;
5233b510adaeSfei feng - Sun Microsystems - Beijing China 	noise_chain_c = LE_32(rx_general_p->beacon_silence_rssi_c) & 0xFF;
5234cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5235cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	/* Rx chain's beacon strength from statistics notification */
5236b510adaeSfei feng - Sun Microsystems - Beijing China 	beacon_chain_a = LE_32(rx_general_p->beacon_rssi_a) & 0xFF;
5237b510adaeSfei feng - Sun Microsystems - Beijing China 	beacon_chain_b = LE_32(rx_general_p->beacon_rssi_b) & 0xFF;
5238b510adaeSfei feng - Sun Microsystems - Beijing China 	beacon_chain_c = LE_32(rx_general_p->beacon_rssi_c) & 0xFF;
5239cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5240cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	gain_diff_p->beacon_count++;
5241cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5242cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	/* accumulate chain's noise strength */
5243cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	gain_diff_p->noise_stren_a += noise_chain_a;
5244cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	gain_diff_p->noise_stren_b += noise_chain_b;
5245cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	gain_diff_p->noise_stren_c += noise_chain_c;
5246cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5247cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	/* accumulate chain's beacon strength */
5248cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	gain_diff_p->beacon_stren_a += beacon_chain_a;
5249cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	gain_diff_p->beacon_stren_b += beacon_chain_b;
5250cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	gain_diff_p->beacon_stren_c += beacon_chain_c;
5251cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5252cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (BEACON_NUM_20 == gain_diff_p->beacon_count) {
5253cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		/* calculate average beacon strength */
5254cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		beacon_aver[0] = (gain_diff_p->beacon_stren_a) / BEACON_NUM_20;
5255cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		beacon_aver[1] = (gain_diff_p->beacon_stren_b) / BEACON_NUM_20;
5256cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		beacon_aver[2] = (gain_diff_p->beacon_stren_c) / BEACON_NUM_20;
5257cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5258cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		/* calculate average noise strength */
5259cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		noise_aver[0] = (gain_diff_p->noise_stren_a) / BEACON_NUM_20;
5260cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		noise_aver[1] = (gain_diff_p->noise_stren_b) / BEACON_NUM_20;
5261cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		noise_aver[2] = (gain_diff_p->noise_stren_b) / BEACON_NUM_20;
5262cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5263cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		/* determine maximum beacon strength among 3 chains */
5264cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		if ((beacon_aver[0] >= beacon_aver[1]) &&
5265cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		    (beacon_aver[0] >= beacon_aver[2])) {
5266cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			max_beacon_chain_n = 0;
5267cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			gain_diff_p->connected_chains = 1 << 0;
5268cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		} else if (beacon_aver[1] >= beacon_aver[2]) {
5269cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			max_beacon_chain_n = 1;
5270cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			gain_diff_p->connected_chains = 1 << 1;
5271cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		} else {
5272cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			max_beacon_chain_n = 2;
5273cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			gain_diff_p->connected_chains = 1 << 2;
5274cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		}
5275cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5276cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		/* determine which chain is disconnected */
5277cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		for (i = 0; i < RX_CHAINS_NUM; i++) {
5278cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			if (i != max_beacon_chain_n) {
5279cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				beacon_diff = beacon_aver[max_beacon_chain_n] -
5280cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				    beacon_aver[i];
5281cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				if (beacon_diff > MAX_ALLOWED_DIFF) {
5282cdc64593Sxinghua wen - Sun Microsystems - Beijing China 					gain_diff_p->disconnect_chain[i] = 1;
5283cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				} else {
5284cdc64593Sxinghua wen - Sun Microsystems - Beijing China 					gain_diff_p->connected_chains |=
5285cdc64593Sxinghua wen - Sun Microsystems - Beijing China 					    (1 << i);
5286cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				}
5287cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			}
5288cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		}
5289cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5290cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		/*
5291cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		 * if chain A and B are both disconnected,
5292cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		 * assume the stronger in beacon strength is connected
5293cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		 */
5294cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		if (gain_diff_p->disconnect_chain[0] &&
5295cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		    gain_diff_p->disconnect_chain[1]) {
5296cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			if (beacon_aver[0] >= beacon_aver[1]) {
5297cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				gain_diff_p->disconnect_chain[0] = 0;
5298cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				gain_diff_p->connected_chains |= (1 << 0);
5299cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			} else {
5300cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				gain_diff_p->disconnect_chain[1] = 0;
5301cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				gain_diff_p->connected_chains |= (1 << 1);
5302cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			}
5303cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		}
5304cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5305cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		/* determine minimum noise strength among 3 chains */
5306cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		if (!gain_diff_p->disconnect_chain[0]) {
5307cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			min_noise_chain_n = 0;
5308cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5309cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			for (i = 0; i < RX_CHAINS_NUM; i++) {
5310cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				if (!gain_diff_p->disconnect_chain[i] &&
5311cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				    (noise_aver[i] <=
5312cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				    noise_aver[min_noise_chain_n])) {
5313cdc64593Sxinghua wen - Sun Microsystems - Beijing China 					min_noise_chain_n = i;
5314cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				}
5315cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5316cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			}
5317cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		} else {
5318cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			min_noise_chain_n = 1;
5319cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5320cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			for (i = 0; i < RX_CHAINS_NUM; i++) {
5321cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				if (!gain_diff_p->disconnect_chain[i] &&
5322cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				    (noise_aver[i] <=
5323cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				    noise_aver[min_noise_chain_n])) {
5324cdc64593Sxinghua wen - Sun Microsystems - Beijing China 					min_noise_chain_n = i;
5325cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				}
5326cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			}
5327cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		}
5328cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5329cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		gain_diff_p->gain_diff_chain[min_noise_chain_n] = 0;
5330cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5331cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		/* determine gain difference between chains */
5332cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		for (i = 0; i < RX_CHAINS_NUM; i++) {
5333cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			if (!gain_diff_p->disconnect_chain[i] &&
5334cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			    (CHAIN_GAIN_DIFF_INIT_VAL ==
5335cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			    gain_diff_p->gain_diff_chain[i])) {
5336cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5337cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				noise_diff = noise_aver[i] -
5338cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				    noise_aver[min_noise_chain_n];
5339cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				gain_diff_p->gain_diff_chain[i] =
5340cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				    (uint8_t)((noise_diff * 10) / 15);
5341cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5342cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				if (gain_diff_p->gain_diff_chain[i] > 3) {
5343cdc64593Sxinghua wen - Sun Microsystems - Beijing China 					gain_diff_p->gain_diff_chain[i] = 3;
5344cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				}
5345cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5346cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				gain_diff_p->gain_diff_chain[i] |= (1 << 2);
5347cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			} else {
5348cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				gain_diff_p->gain_diff_chain[i] = 0;
5349cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			}
5350cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		}
5351cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5352cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		if (!gain_diff_p->gain_diff_send) {
5353cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			gain_diff_p->gain_diff_send = 1;
5354cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5355cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			(void) memset(&cmd, 0, sizeof (cmd));
5356cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5357cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			cmd.opCode = PHY_CALIBRATE_DIFF_GAIN_CMD;
5358cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			cmd.diff_gain_a = gain_diff_p->gain_diff_chain[0];
5359cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			cmd.diff_gain_b = gain_diff_p->gain_diff_chain[1];
5360cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			cmd.diff_gain_c = gain_diff_p->gain_diff_chain[2];
5361cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5362cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			/*
5363cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			 * send out PHY calibration command to
5364cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			 * adjust every chain's Rx gain
5365cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			 */
5366cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			rv = iwk_cmd(sc, REPLY_PHY_CALIBRATION_CMD,
5367cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			    &cmd, sizeof (cmd), 1);
5368cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			if (rv) {
5369cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				return (rv);
5370cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			}
5371cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5372cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			gain_diff_p->state = IWK_GAIN_DIFF_CALIBRATED;
5373cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		}
5374cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5375cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		gain_diff_p->beacon_stren_a = 0;
5376cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		gain_diff_p->beacon_stren_b = 0;
5377cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		gain_diff_p->beacon_stren_c = 0;
5378cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5379cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		gain_diff_p->noise_stren_a = 0;
5380cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		gain_diff_p->noise_stren_b = 0;
5381cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		gain_diff_p->noise_stren_c = 0;
5382cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
5383cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5384cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	return (IWK_SUCCESS);
5385cdc64593Sxinghua wen - Sun Microsystems - Beijing China }
5386cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5387cdc64593Sxinghua wen - Sun Microsystems - Beijing China /* Make necessary preparation for Receiver sensitivity calibration */
iwk_rx_sens_init(iwk_sc_t * sc)5388cdc64593Sxinghua wen - Sun Microsystems - Beijing China static int iwk_rx_sens_init(iwk_sc_t *sc)
5389cdc64593Sxinghua wen - Sun Microsystems - Beijing China {
5390cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	int i, rv;
5391cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	struct iwk_rx_sensitivity_cmd cmd;
5392cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	struct iwk_rx_sensitivity *rx_sens_p = &sc->sc_rx_sens;
5393cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5394cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	(void) memset(&cmd, 0, sizeof (struct iwk_rx_sensitivity_cmd));
5395cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	(void) memset(rx_sens_p, 0, sizeof (struct iwk_rx_sensitivity));
5396cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5397cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	rx_sens_p->auto_corr_ofdm_x4 = 90;
5398cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	rx_sens_p->auto_corr_mrc_ofdm_x4 = 170;
5399cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	rx_sens_p->auto_corr_ofdm_x1 = 105;
5400cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	rx_sens_p->auto_corr_mrc_ofdm_x1 = 220;
5401cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5402cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	rx_sens_p->auto_corr_cck_x4 = 125;
5403cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	rx_sens_p->auto_corr_mrc_cck_x4 = 200;
5404cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	rx_sens_p->min_energy_det_cck = 100;
5405cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5406cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	rx_sens_p->flags &= (~IWK_SENSITIVITY_CALIB_ALLOW_MSK);
5407cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	rx_sens_p->flags &= (~IWK_SENSITIVITY_OFDM_UPDATE_MSK);
5408cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	rx_sens_p->flags &= (~IWK_SENSITIVITY_CCK_UPDATE_MSK);
5409cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5410cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	rx_sens_p->last_bad_plcp_cnt_ofdm = 0;
5411cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	rx_sens_p->last_false_alarm_cnt_ofdm = 0;
5412cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	rx_sens_p->last_bad_plcp_cnt_cck = 0;
5413cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	rx_sens_p->last_false_alarm_cnt_cck = 0;
5414cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5415cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	rx_sens_p->cck_curr_state = IWK_TOO_MANY_FALSE_ALARM;
5416cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	rx_sens_p->cck_prev_state = IWK_TOO_MANY_FALSE_ALARM;
5417cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	rx_sens_p->cck_no_false_alarm_num = 0;
5418cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	rx_sens_p->cck_beacon_idx = 0;
5419cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5420cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	for (i = 0; i < 10; i++) {
5421cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		rx_sens_p->cck_beacon_min[i] = 0;
5422cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
5423cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5424cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	rx_sens_p->cck_noise_idx = 0;
5425cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	rx_sens_p->cck_noise_ref = 0;
5426cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5427cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	for (i = 0; i < 20; i++) {
5428cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		rx_sens_p->cck_noise_max[i] = 0;
5429cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
5430cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5431cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	rx_sens_p->cck_noise_diff = 0;
5432cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	rx_sens_p->cck_no_false_alarm_num = 0;
5433cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5434b510adaeSfei feng - Sun Microsystems - Beijing China 	cmd.control = LE_16(IWK_SENSITIVITY_CONTROL_WORK_TABLE);
5435cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5436cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	cmd.table[AUTO_CORR32_X4_TH_ADD_MIN_IDX] =
5437b510adaeSfei feng - Sun Microsystems - Beijing China 	    LE_16(rx_sens_p->auto_corr_ofdm_x4);
5438cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	cmd.table[AUTO_CORR32_X4_TH_ADD_MIN_MRC_IDX] =
5439b510adaeSfei feng - Sun Microsystems - Beijing China 	    LE_16(rx_sens_p->auto_corr_mrc_ofdm_x4);
5440cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	cmd.table[AUTO_CORR32_X1_TH_ADD_MIN_IDX] =
5441b510adaeSfei feng - Sun Microsystems - Beijing China 	    LE_16(rx_sens_p->auto_corr_ofdm_x1);
5442cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	cmd.table[AUTO_CORR32_X1_TH_ADD_MIN_MRC_IDX] =
5443b510adaeSfei feng - Sun Microsystems - Beijing China 	    LE_16(rx_sens_p->auto_corr_mrc_ofdm_x1);
5444cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5445cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	cmd.table[AUTO_CORR40_X4_TH_ADD_MIN_IDX] =
5446b510adaeSfei feng - Sun Microsystems - Beijing China 	    LE_16(rx_sens_p->auto_corr_cck_x4);
5447cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	cmd.table[AUTO_CORR40_X4_TH_ADD_MIN_MRC_IDX] =
5448b510adaeSfei feng - Sun Microsystems - Beijing China 	    LE_16(rx_sens_p->auto_corr_mrc_cck_x4);
5449b510adaeSfei feng - Sun Microsystems - Beijing China 	cmd.table[MIN_ENERGY_CCK_DET_IDX] =
5450b510adaeSfei feng - Sun Microsystems - Beijing China 	    LE_16(rx_sens_p->min_energy_det_cck);
5451cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5452b510adaeSfei feng - Sun Microsystems - Beijing China 	cmd.table[MIN_ENERGY_OFDM_DET_IDX] = LE_16(100);
5453b510adaeSfei feng - Sun Microsystems - Beijing China 	cmd.table[BARKER_CORR_TH_ADD_MIN_IDX] = LE_16(190);
5454b510adaeSfei feng - Sun Microsystems - Beijing China 	cmd.table[BARKER_CORR_TH_ADD_MIN_MRC_IDX] = LE_16(390);
5455b510adaeSfei feng - Sun Microsystems - Beijing China 	cmd.table[PTAM_ENERGY_TH_IDX] = LE_16(62);
5456cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5457cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	/* at first, set up Rx to maximum sensitivity */
5458cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	rv = iwk_cmd(sc, SENSITIVITY_CMD, &cmd, sizeof (cmd), 1);
5459cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (rv) {
5460cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		cmn_err(CE_WARN, "iwk_rx_sens_init(): "
5461cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		    "in the process of initialization, "
5462cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		    "failed to send rx sensitivity command\n");
5463cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		return (rv);
5464cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
5465cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5466cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	rx_sens_p->flags |= IWK_SENSITIVITY_CALIB_ALLOW_MSK;
5467cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5468cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	return (IWK_SUCCESS);
5469cdc64593Sxinghua wen - Sun Microsystems - Beijing China }
5470cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5471cdc64593Sxinghua wen - Sun Microsystems - Beijing China /*
5472cdc64593Sxinghua wen - Sun Microsystems - Beijing China  * make Receiver sensitivity calibration to adjust every chain's Rx sensitivity.
5473cdc64593Sxinghua wen - Sun Microsystems - Beijing China  * for more infomation, please refer to iwk_calibration.h file
5474cdc64593Sxinghua wen - Sun Microsystems - Beijing China  */
iwk_rx_sens(iwk_sc_t * sc)5475cdc64593Sxinghua wen - Sun Microsystems - Beijing China static int iwk_rx_sens(iwk_sc_t *sc)
5476cdc64593Sxinghua wen - Sun Microsystems - Beijing China {
5477cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	int rv;
5478cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	uint32_t actual_rx_time;
5479cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	struct statistics_rx_non_phy *rx_general_p =
5480cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	    &sc->sc_statistics.rx.general;
5481cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	struct iwk_rx_sensitivity *rx_sens_p = &sc->sc_rx_sens;
5482cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	struct iwk_rx_sensitivity_cmd cmd;
5483cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5484cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (!(rx_sens_p->flags & IWK_SENSITIVITY_CALIB_ALLOW_MSK)) {
5485cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		cmn_err(CE_WARN, "iwk_rx_sens(): "
5486cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		    "sensitivity initialization has not finished.\n");
5487cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		return (DDI_FAILURE);
5488cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
5489cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5490cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (INTERFERENCE_DATA_AVAILABLE !=
5491b510adaeSfei feng - Sun Microsystems - Beijing China 	    LE_32(rx_general_p->interference_data_flag)) {
5492cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		cmn_err(CE_WARN, "iwk_rx_sens(): "
5493cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		    "can't make rx sensitivity calibration,"
5494cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		    "because of invalid statistics\n");
5495cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		return (DDI_FAILURE);
5496cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
5497cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5498b510adaeSfei feng - Sun Microsystems - Beijing China 	actual_rx_time = LE_32(rx_general_p->channel_load);
5499cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (!actual_rx_time) {
5500d2a61391Spengcheng chen - Sun Microsystems - Beijing China 		IWK_DBG((IWK_DEBUG_CALIBRATION, "iwk_rx_sens(): "
5501cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		    "can't make rx sensitivity calibration,"
5502d2a61391Spengcheng chen - Sun Microsystems - Beijing China 		    "because has not enough rx time\n"));
5503cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		return (DDI_FAILURE);
5504cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
5505cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5506cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	/* make Rx sensitivity calibration for OFDM mode */
5507cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	rv = iwk_ofdm_sens(sc, actual_rx_time);
5508cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (rv) {
5509cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		return (rv);
5510cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
5511cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5512cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	/* make Rx sensitivity calibration for CCK mode */
5513cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	rv = iwk_cck_sens(sc, actual_rx_time);
5514cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (rv) {
5515cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		return (rv);
5516cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
5517cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5518cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	/*
5519cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	 * if the sum of false alarm had not changed, nothing will be done
5520cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	 */
5521cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if ((!(rx_sens_p->flags & IWK_SENSITIVITY_OFDM_UPDATE_MSK)) &&
5522cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	    (!(rx_sens_p->flags & IWK_SENSITIVITY_CCK_UPDATE_MSK))) {
5523cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		return (IWK_SUCCESS);
5524cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
5525cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5526cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	cmd.control = IWK_SENSITIVITY_CONTROL_WORK_TABLE;
5527cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5528cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	cmd.table[AUTO_CORR32_X4_TH_ADD_MIN_IDX] =
5529cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	    rx_sens_p->auto_corr_ofdm_x4;
5530cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	cmd.table[AUTO_CORR32_X4_TH_ADD_MIN_MRC_IDX] =
5531cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	    rx_sens_p->auto_corr_mrc_ofdm_x4;
5532cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	cmd.table[AUTO_CORR32_X1_TH_ADD_MIN_IDX] =
5533cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	    rx_sens_p->auto_corr_ofdm_x1;
5534cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	cmd.table[AUTO_CORR32_X1_TH_ADD_MIN_MRC_IDX] =
5535cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	    rx_sens_p->auto_corr_mrc_ofdm_x1;
5536cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5537cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	cmd.table[AUTO_CORR40_X4_TH_ADD_MIN_IDX] =
5538cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	    rx_sens_p->auto_corr_cck_x4;
5539cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	cmd.table[AUTO_CORR40_X4_TH_ADD_MIN_MRC_IDX] =
5540cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	    rx_sens_p->auto_corr_mrc_cck_x4;
5541cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	cmd.table[MIN_ENERGY_CCK_DET_IDX] =
5542cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	    rx_sens_p->min_energy_det_cck;
5543cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5544cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	cmd.table[MIN_ENERGY_OFDM_DET_IDX] = 100;
5545cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	cmd.table[BARKER_CORR_TH_ADD_MIN_IDX] = 190;
5546cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	cmd.table[BARKER_CORR_TH_ADD_MIN_MRC_IDX] = 390;
5547cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	cmd.table[PTAM_ENERGY_TH_IDX] = 62;
5548cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5549cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	/*
5550cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	 * send sensitivity command to complete actual sensitivity calibration
5551cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	 */
5552cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	rv = iwk_cmd(sc, SENSITIVITY_CMD, &cmd, sizeof (cmd), 1);
5553cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (rv) {
5554cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		cmn_err(CE_WARN, "iwk_rx_sens(): "
5555cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		    "fail to send rx sensitivity command\n");
5556cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		return (rv);
5557cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
5558cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5559cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	return (IWK_SUCCESS);
5560cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5561cdc64593Sxinghua wen - Sun Microsystems - Beijing China }
5562cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5563cdc64593Sxinghua wen - Sun Microsystems - Beijing China /*
5564cdc64593Sxinghua wen - Sun Microsystems - Beijing China  * make Rx sensitivity calibration for CCK mode.
5565cdc64593Sxinghua wen - Sun Microsystems - Beijing China  * This is preparing parameters for Sensitivity command
5566cdc64593Sxinghua wen - Sun Microsystems - Beijing China  */
iwk_cck_sens(iwk_sc_t * sc,uint32_t actual_rx_time)5567cdc64593Sxinghua wen - Sun Microsystems - Beijing China static int iwk_cck_sens(iwk_sc_t *sc, uint32_t actual_rx_time)
5568cdc64593Sxinghua wen - Sun Microsystems - Beijing China {
5569cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	int i;
5570cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	uint8_t noise_a, noise_b, noise_c;
5571cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	uint8_t max_noise_abc, max_noise_20;
5572cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	uint32_t beacon_a, beacon_b, beacon_c;
5573cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	uint32_t min_beacon_abc, max_beacon_10;
5574cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	uint32_t cck_fa, cck_bp;
5575cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	uint32_t cck_sum_fa_bp;
5576cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	uint32_t temp;
5577cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	struct statistics_rx_non_phy *rx_general_p =
5578cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	    &sc->sc_statistics.rx.general;
5579cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	struct iwk_rx_sensitivity *rx_sens_p = &sc->sc_rx_sens;
5580cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5581b510adaeSfei feng - Sun Microsystems - Beijing China 	cck_fa = LE_32(sc->sc_statistics.rx.cck.false_alarm_cnt);
5582b510adaeSfei feng - Sun Microsystems - Beijing China 	cck_bp = LE_32(sc->sc_statistics.rx.cck.plcp_err);
5583cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5584cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	/* accumulate false alarm */
5585cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (rx_sens_p->last_false_alarm_cnt_cck > cck_fa) {
5586cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		temp = rx_sens_p->last_false_alarm_cnt_cck;
5587cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		rx_sens_p->last_false_alarm_cnt_cck = cck_fa;
5588cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		cck_fa += (0xFFFFFFFF - temp);
5589cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	} else {
5590cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		cck_fa -= rx_sens_p->last_false_alarm_cnt_cck;
5591cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		rx_sens_p->last_false_alarm_cnt_cck += cck_fa;
5592cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
5593cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5594cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	/* accumulate bad plcp */
5595cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (rx_sens_p->last_bad_plcp_cnt_cck > cck_bp) {
5596cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		temp = rx_sens_p->last_bad_plcp_cnt_cck;
5597cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		rx_sens_p->last_bad_plcp_cnt_cck = cck_bp;
5598cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		cck_bp += (0xFFFFFFFF - temp);
5599cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	} else {
5600cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		cck_bp -= rx_sens_p->last_bad_plcp_cnt_cck;
5601cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		rx_sens_p->last_bad_plcp_cnt_cck += cck_bp;
5602cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
5603cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5604cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	/*
5605cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	 * calculate relative value
5606cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	 */
5607cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	cck_sum_fa_bp = (cck_fa + cck_bp) * 200 * 1024;
5608cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	rx_sens_p->cck_noise_diff = 0;
5609cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5610cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	noise_a =
5611b510adaeSfei feng - Sun Microsystems - Beijing China 	    (uint8_t)((LE_32(rx_general_p->beacon_silence_rssi_a) & 0xFF00) >>
5612b510adaeSfei feng - Sun Microsystems - Beijing China 	    8);
5613cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	noise_b =
5614b510adaeSfei feng - Sun Microsystems - Beijing China 	    (uint8_t)((LE_32(rx_general_p->beacon_silence_rssi_b) & 0xFF00) >>
5615b510adaeSfei feng - Sun Microsystems - Beijing China 	    8);
5616cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	noise_c =
5617b510adaeSfei feng - Sun Microsystems - Beijing China 	    (uint8_t)((LE_32(rx_general_p->beacon_silence_rssi_c) & 0xFF00) >>
5618b510adaeSfei feng - Sun Microsystems - Beijing China 	    8);
5619cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5620b510adaeSfei feng - Sun Microsystems - Beijing China 	beacon_a = LE_32(rx_general_p->beacon_energy_a);
5621b510adaeSfei feng - Sun Microsystems - Beijing China 	beacon_b = LE_32(rx_general_p->beacon_energy_b);
5622b510adaeSfei feng - Sun Microsystems - Beijing China 	beacon_c = LE_32(rx_general_p->beacon_energy_c);
5623cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5624cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	/* determine maximum noise among 3 chains */
5625cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if ((noise_a >= noise_b) && (noise_a >= noise_c)) {
5626cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		max_noise_abc = noise_a;
5627cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	} else if (noise_b >= noise_c) {
5628cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		max_noise_abc = noise_b;
5629cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	} else {
5630cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		max_noise_abc = noise_c;
5631cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
5632cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5633cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	/* record maximum noise among 3 chains */
5634cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	rx_sens_p->cck_noise_max[rx_sens_p->cck_noise_idx] = max_noise_abc;
5635cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	rx_sens_p->cck_noise_idx++;
5636cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (rx_sens_p->cck_noise_idx >= 20) {
5637cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		rx_sens_p->cck_noise_idx = 0;
5638cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
5639cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5640cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	/* determine maximum noise among 20 max noise */
5641cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	max_noise_20 = rx_sens_p->cck_noise_max[0];
5642cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	for (i = 0; i < 20; i++) {
5643cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		if (rx_sens_p->cck_noise_max[i] >= max_noise_20) {
5644cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			max_noise_20 = rx_sens_p->cck_noise_max[i];
5645cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		}
5646cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
5647cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5648cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	/* determine minimum beacon among 3 chains */
5649cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if ((beacon_a <= beacon_b) && (beacon_a <= beacon_c)) {
5650cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		min_beacon_abc = beacon_a;
5651cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	} else if (beacon_b <= beacon_c) {
5652cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		min_beacon_abc = beacon_b;
5653cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	} else {
5654cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		min_beacon_abc = beacon_c;
5655cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
5656cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5657cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	/* record miminum beacon among 3 chains */
5658cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	rx_sens_p->cck_beacon_min[rx_sens_p->cck_beacon_idx] = min_beacon_abc;
5659cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	rx_sens_p->cck_beacon_idx++;
5660cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (rx_sens_p->cck_beacon_idx >= 10) {
5661cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		rx_sens_p->cck_beacon_idx = 0;
5662cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
5663cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5664cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	/* determine maximum beacon among 10 miminum beacon among 3 chains */
5665cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	max_beacon_10 = rx_sens_p->cck_beacon_min[0];
5666cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	for (i = 0; i < 10; i++) {
5667cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		if (rx_sens_p->cck_beacon_min[i] >= max_beacon_10) {
5668cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			max_beacon_10 = rx_sens_p->cck_beacon_min[i];
5669cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		}
5670cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
5671cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5672cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	/* add a little margin */
5673cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	max_beacon_10 += 6;
5674cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5675cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	/* record the count of having no false alarms */
5676cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (cck_sum_fa_bp < (5 * actual_rx_time)) {
5677cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		rx_sens_p->cck_no_false_alarm_num++;
5678cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	} else {
5679cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		rx_sens_p->cck_no_false_alarm_num = 0;
5680cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
5681cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5682cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	/*
5683cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	 * adjust parameters in sensitivity command
5684cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	 * according to different status.
5685cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	 * for more infomation, please refer to iwk_calibration.h file
5686cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	 */
5687cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (cck_sum_fa_bp > (50 * actual_rx_time)) {
5688cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		rx_sens_p->cck_curr_state = IWK_TOO_MANY_FALSE_ALARM;
5689cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5690cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		if (rx_sens_p->auto_corr_cck_x4 > 160) {
5691cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			rx_sens_p->cck_noise_ref = max_noise_20;
5692cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5693cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			if (rx_sens_p->min_energy_det_cck > 2) {
5694cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				rx_sens_p->min_energy_det_cck -= 2;
5695cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			}
5696cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		}
5697cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5698cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		if (rx_sens_p->auto_corr_cck_x4 < 160) {
5699cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			rx_sens_p->auto_corr_cck_x4 = 160 + 1;
5700cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		} else {
5701cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			if ((rx_sens_p->auto_corr_cck_x4 + 3) < 200) {
5702cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				rx_sens_p->auto_corr_cck_x4 += 3;
5703cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			} else {
5704cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				rx_sens_p->auto_corr_cck_x4 = 200;
5705cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			}
5706cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		}
5707cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5708cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		if ((rx_sens_p->auto_corr_mrc_cck_x4 + 3) < 400) {
5709cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			rx_sens_p->auto_corr_mrc_cck_x4 += 3;
5710cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		} else {
5711cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			rx_sens_p->auto_corr_mrc_cck_x4 = 400;
5712cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		}
5713cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5714cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		rx_sens_p->flags |= IWK_SENSITIVITY_CCK_UPDATE_MSK;
5715cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5716cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	} else if (cck_sum_fa_bp < (5 * actual_rx_time)) {
5717cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		rx_sens_p->cck_curr_state = IWK_TOO_FEW_FALSE_ALARM;
5718cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5719cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		rx_sens_p->cck_noise_diff = (int32_t)rx_sens_p->cck_noise_ref -
5720cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		    (int32_t)max_noise_20;
5721cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5722cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		if ((rx_sens_p->cck_prev_state != IWK_TOO_MANY_FALSE_ALARM) &&
5723cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		    ((rx_sens_p->cck_noise_diff > 2) ||
5724cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		    (rx_sens_p->cck_no_false_alarm_num > 100))) {
5725cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			if ((rx_sens_p->min_energy_det_cck + 2) < 97) {
5726cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				rx_sens_p->min_energy_det_cck += 2;
5727cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			} else {
5728cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				rx_sens_p->min_energy_det_cck = 97;
5729cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			}
5730cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5731cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			if ((rx_sens_p->auto_corr_cck_x4 - 3) > 125) {
5732cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				rx_sens_p->auto_corr_cck_x4 -= 3;
5733cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			} else {
5734cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				rx_sens_p->auto_corr_cck_x4 = 125;
5735cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			}
5736cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5737cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			if ((rx_sens_p->auto_corr_mrc_cck_x4 -3) > 200) {
5738cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				rx_sens_p->auto_corr_mrc_cck_x4 -= 3;
5739cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			} else {
5740cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				rx_sens_p->auto_corr_mrc_cck_x4 = 200;
5741cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			}
5742cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5743cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			rx_sens_p->flags |= IWK_SENSITIVITY_CCK_UPDATE_MSK;
5744cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		} else {
5745cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			rx_sens_p->flags &= (~IWK_SENSITIVITY_CCK_UPDATE_MSK);
5746cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		}
5747cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	} else {
5748cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		rx_sens_p->cck_curr_state = IWK_GOOD_RANGE_FALSE_ALARM;
5749cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5750cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		rx_sens_p->cck_noise_ref = max_noise_20;
5751cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5752cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		if (IWK_TOO_MANY_FALSE_ALARM == rx_sens_p->cck_prev_state) {
5753cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			rx_sens_p->min_energy_det_cck -= 8;
5754cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		}
5755cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5756cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		rx_sens_p->flags &= (~IWK_SENSITIVITY_CCK_UPDATE_MSK);
5757cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
5758cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5759cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (rx_sens_p->min_energy_det_cck < max_beacon_10) {
5760cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		rx_sens_p->min_energy_det_cck = (uint16_t)max_beacon_10;
5761cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
5762cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5763cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	rx_sens_p->cck_prev_state = rx_sens_p->cck_curr_state;
5764cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5765cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	return (IWK_SUCCESS);
5766cdc64593Sxinghua wen - Sun Microsystems - Beijing China }
5767cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5768cdc64593Sxinghua wen - Sun Microsystems - Beijing China /*
5769cdc64593Sxinghua wen - Sun Microsystems - Beijing China  * make Rx sensitivity calibration for OFDM mode.
5770cdc64593Sxinghua wen - Sun Microsystems - Beijing China  * This is preparing parameters for Sensitivity command
5771cdc64593Sxinghua wen - Sun Microsystems - Beijing China  */
iwk_ofdm_sens(iwk_sc_t * sc,uint32_t actual_rx_time)5772cdc64593Sxinghua wen - Sun Microsystems - Beijing China static int iwk_ofdm_sens(iwk_sc_t *sc, uint32_t actual_rx_time)
5773cdc64593Sxinghua wen - Sun Microsystems - Beijing China {
5774cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	uint32_t temp;
5775cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	uint16_t temp1;
5776cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	uint32_t ofdm_fa, ofdm_bp;
5777cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	uint32_t ofdm_sum_fa_bp;
5778cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	struct iwk_rx_sensitivity *rx_sens_p = &sc->sc_rx_sens;
5779cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5780b510adaeSfei feng - Sun Microsystems - Beijing China 	ofdm_fa = LE_32(sc->sc_statistics.rx.ofdm.false_alarm_cnt);
5781b510adaeSfei feng - Sun Microsystems - Beijing China 	ofdm_bp = LE_32(sc->sc_statistics.rx.ofdm.plcp_err);
5782cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5783cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	/* accumulate false alarm */
5784cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (rx_sens_p->last_false_alarm_cnt_ofdm > ofdm_fa) {
5785cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		temp = rx_sens_p->last_false_alarm_cnt_ofdm;
5786cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		rx_sens_p->last_false_alarm_cnt_ofdm = ofdm_fa;
5787cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		ofdm_fa += (0xFFFFFFFF - temp);
5788cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	} else {
5789cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		ofdm_fa -= rx_sens_p->last_false_alarm_cnt_ofdm;
5790cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		rx_sens_p->last_false_alarm_cnt_ofdm += ofdm_fa;
5791cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
5792cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5793cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	/* accumulate bad plcp */
5794cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (rx_sens_p->last_bad_plcp_cnt_ofdm > ofdm_bp) {
5795cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		temp = rx_sens_p->last_bad_plcp_cnt_ofdm;
5796cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		rx_sens_p->last_bad_plcp_cnt_ofdm = ofdm_bp;
5797cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		ofdm_bp += (0xFFFFFFFF - temp);
5798cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	} else {
5799cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		ofdm_bp -= rx_sens_p->last_bad_plcp_cnt_ofdm;
5800cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		rx_sens_p->last_bad_plcp_cnt_ofdm += ofdm_bp;
5801cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
5802cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5803cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	ofdm_sum_fa_bp = (ofdm_fa + ofdm_bp) * 200 * 1024; /* relative value */
5804cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5805cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	/*
5806cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	 * adjust parameter in sensitivity command according to different status
5807cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	 */
5808cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (ofdm_sum_fa_bp > (50 * actual_rx_time)) {
5809cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		temp1 = rx_sens_p->auto_corr_ofdm_x4 + 1;
5810cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		rx_sens_p->auto_corr_ofdm_x4 = (temp1 <= 120) ? temp1 : 120;
5811cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5812cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		temp1 = rx_sens_p->auto_corr_mrc_ofdm_x4 + 1;
5813cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		rx_sens_p->auto_corr_mrc_ofdm_x4 =
5814cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		    (temp1 <= 210) ? temp1 : 210;
5815cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5816cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		temp1 = rx_sens_p->auto_corr_ofdm_x1 + 1;
5817cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		rx_sens_p->auto_corr_ofdm_x1 = (temp1 <= 140) ? temp1 : 140;
5818cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5819cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		temp1 = rx_sens_p->auto_corr_mrc_ofdm_x1 + 1;
5820cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		rx_sens_p->auto_corr_mrc_ofdm_x1 =
5821cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		    (temp1 <= 270) ? temp1 : 270;
5822cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5823cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		rx_sens_p->flags |= IWK_SENSITIVITY_OFDM_UPDATE_MSK;
5824cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5825cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	} else if (ofdm_sum_fa_bp < (5 * actual_rx_time)) {
5826cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		temp1 = rx_sens_p->auto_corr_ofdm_x4 - 1;
5827cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		rx_sens_p->auto_corr_ofdm_x4 = (temp1 >= 85) ? temp1 : 85;
5828cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5829cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		temp1 = rx_sens_p->auto_corr_mrc_ofdm_x4 - 1;
5830cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		rx_sens_p->auto_corr_mrc_ofdm_x4 =
5831cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		    (temp1 >= 170) ? temp1 : 170;
5832cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5833cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		temp1 = rx_sens_p->auto_corr_ofdm_x1 - 1;
5834cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		rx_sens_p->auto_corr_ofdm_x1 = (temp1 >= 105) ? temp1 : 105;
5835cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5836cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		temp1 = rx_sens_p->auto_corr_mrc_ofdm_x1 - 1;
5837cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		rx_sens_p->auto_corr_mrc_ofdm_x1 =
5838cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		    (temp1 >= 220) ? temp1 : 220;
5839cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5840cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		rx_sens_p->flags |= IWK_SENSITIVITY_OFDM_UPDATE_MSK;
5841cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5842cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	} else {
5843cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		rx_sens_p->flags &= (~IWK_SENSITIVITY_OFDM_UPDATE_MSK);
5844cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
5845cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5846cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	return (IWK_SUCCESS);
5847cdc64593Sxinghua wen - Sun Microsystems - Beijing China }
5848cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
584919d332feSfei feng - Sun Microsystems - Beijing China /*
585019d332feSfei feng - Sun Microsystems - Beijing China  * additional process to management frames
585119d332feSfei feng - Sun Microsystems - Beijing China  */
iwk_recv_mgmt(struct ieee80211com * ic,mblk_t * mp,struct ieee80211_node * in,int subtype,int rssi,uint32_t rstamp)585219d332feSfei feng - Sun Microsystems - Beijing China static void iwk_recv_mgmt(struct ieee80211com *ic, mblk_t *mp,
585319d332feSfei feng - Sun Microsystems - Beijing China     struct ieee80211_node *in,
585419d332feSfei feng - Sun Microsystems - Beijing China     int subtype, int rssi, uint32_t rstamp)
585519d332feSfei feng - Sun Microsystems - Beijing China {
585619d332feSfei feng - Sun Microsystems - Beijing China 	iwk_sc_t *sc = (iwk_sc_t *)ic;
585719d332feSfei feng - Sun Microsystems - Beijing China 	struct ieee80211_frame *wh;
585819d332feSfei feng - Sun Microsystems - Beijing China 	uint8_t index1, index2;
585919d332feSfei feng - Sun Microsystems - Beijing China 	int err;
586019d332feSfei feng - Sun Microsystems - Beijing China 
586119d332feSfei feng - Sun Microsystems - Beijing China 	sc->sc_recv_mgmt(ic, mp, in, subtype, rssi, rstamp);
586219d332feSfei feng - Sun Microsystems - Beijing China 
586319d332feSfei feng - Sun Microsystems - Beijing China 	mutex_enter(&sc->sc_glock);
586419d332feSfei feng - Sun Microsystems - Beijing China 	switch (subtype) {
586519d332feSfei feng - Sun Microsystems - Beijing China 	case IEEE80211_FC0_SUBTYPE_BEACON:
586619d332feSfei feng - Sun Microsystems - Beijing China 		if (sc->sc_ibss.ibss_beacon.syncbeacon && in == ic->ic_bss &&
586719d332feSfei feng - Sun Microsystems - Beijing China 		    ic->ic_state == IEEE80211_S_RUN) {
586819d332feSfei feng - Sun Microsystems - Beijing China 			if (ieee80211_beacon_update(ic, in,
586919d332feSfei feng - Sun Microsystems - Beijing China 			    &sc->sc_ibss.ibss_beacon.iwk_boff,
587019d332feSfei feng - Sun Microsystems - Beijing China 			    sc->sc_ibss.ibss_beacon.mp, 0)) {
587119d332feSfei feng - Sun Microsystems - Beijing China 				bcopy(sc->sc_ibss.ibss_beacon.mp->b_rptr,
587219d332feSfei feng - Sun Microsystems - Beijing China 				    sc->sc_ibss.ibss_beacon.beacon_cmd.
587319d332feSfei feng - Sun Microsystems - Beijing China 				    bcon_frame,
587419d332feSfei feng - Sun Microsystems - Beijing China 				    MBLKL(sc->sc_ibss.ibss_beacon.mp));
587519d332feSfei feng - Sun Microsystems - Beijing China 			}
587619d332feSfei feng - Sun Microsystems - Beijing China 			err = iwk_cmd(sc, REPLY_TX_BEACON,
587719d332feSfei feng - Sun Microsystems - Beijing China 			    &sc->sc_ibss.ibss_beacon.beacon_cmd,
587819d332feSfei feng - Sun Microsystems - Beijing China 			    sc->sc_ibss.ibss_beacon.beacon_cmd_len, 1);
587919d332feSfei feng - Sun Microsystems - Beijing China 			if (err != IWK_SUCCESS) {
588019d332feSfei feng - Sun Microsystems - Beijing China 				cmn_err(CE_WARN, "iwk_recv_mgmt(): "
588119d332feSfei feng - Sun Microsystems - Beijing China 				    "failed to TX beacon.\n");
588219d332feSfei feng - Sun Microsystems - Beijing China 			}
588319d332feSfei feng - Sun Microsystems - Beijing China 			sc->sc_ibss.ibss_beacon.syncbeacon = 0;
588419d332feSfei feng - Sun Microsystems - Beijing China 		}
588519d332feSfei feng - Sun Microsystems - Beijing China 		if (ic->ic_opmode == IEEE80211_M_IBSS &&
588619d332feSfei feng - Sun Microsystems - Beijing China 		    ic->ic_state == IEEE80211_S_RUN) {
588719d332feSfei feng - Sun Microsystems - Beijing China 			wh = (struct ieee80211_frame *)mp->b_rptr;
588819d332feSfei feng - Sun Microsystems - Beijing China 			mutex_enter(&sc->sc_ibss.node_tb_lock);
588919d332feSfei feng - Sun Microsystems - Beijing China 			/*
589019d332feSfei feng - Sun Microsystems - Beijing China 			 * search for node in ibss node table
589119d332feSfei feng - Sun Microsystems - Beijing China 			 */
589219d332feSfei feng - Sun Microsystems - Beijing China 			for (index1 = IWK_STA_ID; index1 < IWK_STATION_COUNT;
589319d332feSfei feng - Sun Microsystems - Beijing China 			    index1++) {
589419d332feSfei feng - Sun Microsystems - Beijing China 				if (sc->sc_ibss.ibss_node_tb[index1].used &&
589519d332feSfei feng - Sun Microsystems - Beijing China 				    IEEE80211_ADDR_EQ(sc->sc_ibss.
589619d332feSfei feng - Sun Microsystems - Beijing China 				    ibss_node_tb[index1].node.bssid,
589719d332feSfei feng - Sun Microsystems - Beijing China 				    wh->i_addr2)) {
589819d332feSfei feng - Sun Microsystems - Beijing China 					break;
589919d332feSfei feng - Sun Microsystems - Beijing China 				}
590019d332feSfei feng - Sun Microsystems - Beijing China 			}
590119d332feSfei feng - Sun Microsystems - Beijing China 			/*
590219d332feSfei feng - Sun Microsystems - Beijing China 			 * if don't find in ibss node table
590319d332feSfei feng - Sun Microsystems - Beijing China 			 */
590419d332feSfei feng - Sun Microsystems - Beijing China 			if (index1 >= IWK_BROADCAST_ID) {
590519d332feSfei feng - Sun Microsystems - Beijing China 				err = iwk_clean_add_node_ibss(ic,
590619d332feSfei feng - Sun Microsystems - Beijing China 				    wh->i_addr2, &index2);
590719d332feSfei feng - Sun Microsystems - Beijing China 				if (err != IWK_SUCCESS) {
590819d332feSfei feng - Sun Microsystems - Beijing China 					cmn_err(CE_WARN, "iwk_recv_mgmt(): "
590919d332feSfei feng - Sun Microsystems - Beijing China 					    "failed to clean all nodes "
591019d332feSfei feng - Sun Microsystems - Beijing China 					    "and add one node\n");
591119d332feSfei feng - Sun Microsystems - Beijing China 				}
591219d332feSfei feng - Sun Microsystems - Beijing China 			}
591319d332feSfei feng - Sun Microsystems - Beijing China 			mutex_exit(&sc->sc_ibss.node_tb_lock);
591419d332feSfei feng - Sun Microsystems - Beijing China 		}
591519d332feSfei feng - Sun Microsystems - Beijing China 		break;
591619d332feSfei feng - Sun Microsystems - Beijing China 	case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
591719d332feSfei feng - Sun Microsystems - Beijing China 		break;
591819d332feSfei feng - Sun Microsystems - Beijing China 	}
591919d332feSfei feng - Sun Microsystems - Beijing China 	mutex_exit(&sc->sc_glock);
592019d332feSfei feng - Sun Microsystems - Beijing China }
592119d332feSfei feng - Sun Microsystems - Beijing China 
5922*ae5a8bedSAndy Fiddaman #ifdef DEBUG
5923cdc64593Sxinghua wen - Sun Microsystems - Beijing China /*
5924cdc64593Sxinghua wen - Sun Microsystems - Beijing China  * 1)  log_event_table_ptr indicates base of the event log.  This traces
5925cdc64593Sxinghua wen - Sun Microsystems - Beijing China  *     a 256-entry history of uCode execution within a circular buffer.
5926cdc64593Sxinghua wen - Sun Microsystems - Beijing China  *     Its header format is:
5927cdc64593Sxinghua wen - Sun Microsystems - Beijing China  *
5928cdc64593Sxinghua wen - Sun Microsystems - Beijing China  *	uint32_t log_size;	log capacity (in number of entries)
5929cdc64593Sxinghua wen - Sun Microsystems - Beijing China  *	uint32_t type;	(1) timestamp with each entry, (0) no timestamp
5930cdc64593Sxinghua wen - Sun Microsystems - Beijing China  *	uint32_t wraps;	# times uCode has wrapped to top of circular buffer
5931cdc64593Sxinghua wen - Sun Microsystems - Beijing China  *      uint32_t write_index;	next circular buffer entry that uCode would fill
5932cdc64593Sxinghua wen - Sun Microsystems - Beijing China  *
5933cdc64593Sxinghua wen - Sun Microsystems - Beijing China  *     The header is followed by the circular buffer of log entries.  Entries
5934cdc64593Sxinghua wen - Sun Microsystems - Beijing China  *     with timestamps have the following format:
5935cdc64593Sxinghua wen - Sun Microsystems - Beijing China  *
5936cdc64593Sxinghua wen - Sun Microsystems - Beijing China  *	uint32_t event_id;     range 0 - 1500
5937cdc64593Sxinghua wen - Sun Microsystems - Beijing China  *	uint32_t timestamp;    low 32 bits of TSF (of network, if associated)
5938cdc64593Sxinghua wen - Sun Microsystems - Beijing China  *	uint32_t data;         event_id-specific data value
5939cdc64593Sxinghua wen - Sun Microsystems - Beijing China  *
5940cdc64593Sxinghua wen - Sun Microsystems - Beijing China  *     Entries without timestamps contain only event_id and data.
5941cdc64593Sxinghua wen - Sun Microsystems - Beijing China  */
5942cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5943cdc64593Sxinghua wen - Sun Microsystems - Beijing China /*
5944cdc64593Sxinghua wen - Sun Microsystems - Beijing China  * iwk_write_event_log - Write event log to dmesg
5945cdc64593Sxinghua wen - Sun Microsystems - Beijing China  */
iwk_write_event_log(iwk_sc_t * sc)5946cdc64593Sxinghua wen - Sun Microsystems - Beijing China static void iwk_write_event_log(iwk_sc_t *sc)
5947cdc64593Sxinghua wen - Sun Microsystems - Beijing China {
5948cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	uint32_t log_event_table_ptr;	/* Start address of event table */
5949cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	uint32_t startptr;	/* Start address of log data */
5950cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	uint32_t logptr;	/* address of log data entry */
5951cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	uint32_t i, n, num_events;
5952cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	uint32_t event_id, data1, data2; /* log data */
5953cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5954cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	uint32_t log_size;   /* log capacity (in number of entries) */
5955cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	uint32_t type;	/* (1)timestamp with each entry,(0) no timestamp */
5956cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	uint32_t wraps;	/* # times uCode has wrapped to */
5957cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			/* the top of circular buffer */
5958cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	uint32_t idx; /* index of entry to be filled in next */
5959cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5960b510adaeSfei feng - Sun Microsystems - Beijing China 	log_event_table_ptr = LE_32(sc->sc_card_alive_run.log_event_table_ptr);
5961cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (!(log_event_table_ptr)) {
5962cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		IWK_DBG((IWK_DEBUG_EEPROM, "NULL event table pointer\n"));
5963cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		return;
5964cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
5965cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5966cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	iwk_mac_access_enter(sc);
5967cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5968cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	/* Read log header */
5969cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	log_size = iwk_mem_read(sc, log_event_table_ptr);
5970cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	log_event_table_ptr += sizeof (uint32_t); /* addr of "type" */
5971cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	type = iwk_mem_read(sc, log_event_table_ptr);
5972cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	log_event_table_ptr += sizeof (uint32_t); /* addr of "wraps" */
5973cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	wraps = iwk_mem_read(sc, log_event_table_ptr);
5974cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	log_event_table_ptr += sizeof (uint32_t); /* addr of "idx" */
5975cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	idx = iwk_mem_read(sc, log_event_table_ptr);
5976cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	startptr = log_event_table_ptr +
5977cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	    sizeof (uint32_t); /* addr of start of log data */
5978cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (!log_size & !wraps) {
5979cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		IWK_DBG((IWK_DEBUG_EEPROM, "Empty log\n"));
5980cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		iwk_mac_access_exit(sc);
5981cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		return;
5982cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
5983cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5984cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (!wraps) {
5985cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		num_events = idx;
5986cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		logptr = startptr;
5987cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	} else {
5988cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		num_events = log_size - idx;
5989cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		n = type ? 2 : 3;
5990cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		logptr = startptr + (idx * n * sizeof (uint32_t));
5991cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
5992cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
5993cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	for (i = 0; i < num_events; i++) {
5994cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		event_id = iwk_mem_read(sc, logptr);
5995cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		logptr += sizeof (uint32_t);
5996cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		data1 = iwk_mem_read(sc, logptr);
5997cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		logptr += sizeof (uint32_t);
5998cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		if (type == 0) { /* no timestamp */
5999cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			IWK_DBG((IWK_DEBUG_EEPROM, "Event ID=%d, Data=%x0x",
6000cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			    event_id, data1));
6001cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		} else { /* timestamp */
6002cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			data2 = iwk_mem_read(sc, logptr);
6003cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			IWK_DBG((IWK_DEBUG_EEPROM,
6004cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			    "Time=%d, Event ID=%d, Data=0x%x\n",
6005cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			    data1, event_id, data2));
6006cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			logptr += sizeof (uint32_t);
6007cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		}
6008cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
6009cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
6010cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	/*
6011cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	 * Print the wrapped around entries, if any
6012cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	 */
6013cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (wraps) {
6014cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		logptr = startptr;
6015cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		for (i = 0; i < idx; i++) {
6016cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			event_id = iwk_mem_read(sc, logptr);
6017cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			logptr += sizeof (uint32_t);
6018cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			data1 = iwk_mem_read(sc, logptr);
6019cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			logptr += sizeof (uint32_t);
6020cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			if (type == 0) { /* no timestamp */
6021cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				IWK_DBG((IWK_DEBUG_EEPROM,
6022cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				    "Event ID=%d, Data=%x0x", event_id, data1));
6023cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			} else { /* timestamp */
6024cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				data2 = iwk_mem_read(sc, logptr);
6025cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				IWK_DBG((IWK_DEBUG_EEPROM,
6026cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				    "Time = %d, Event ID=%d, Data=0x%x\n",
6027cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				    data1, event_id, data2));
6028cdc64593Sxinghua wen - Sun Microsystems - Beijing China 				logptr += sizeof (uint32_t);
6029cdc64593Sxinghua wen - Sun Microsystems - Beijing China 			}
6030cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		}
6031cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
6032cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
6033cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	iwk_mac_access_exit(sc);
6034cdc64593Sxinghua wen - Sun Microsystems - Beijing China }
6035cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
6036cdc64593Sxinghua wen - Sun Microsystems - Beijing China /*
6037cdc64593Sxinghua wen - Sun Microsystems - Beijing China  * error_event_table_ptr indicates base of the error log.  This contains
6038cdc64593Sxinghua wen - Sun Microsystems - Beijing China  * information about any uCode error that occurs.  For 4965, the format is:
6039cdc64593Sxinghua wen - Sun Microsystems - Beijing China  *
6040cdc64593Sxinghua wen - Sun Microsystems - Beijing China  * uint32_t valid;        (nonzero) valid, (0) log is empty
6041cdc64593Sxinghua wen - Sun Microsystems - Beijing China  * uint32_t error_id;     type of error
6042cdc64593Sxinghua wen - Sun Microsystems - Beijing China  * uint32_t pc;           program counter
6043cdc64593Sxinghua wen - Sun Microsystems - Beijing China  * uint32_t blink1;       branch link
6044cdc64593Sxinghua wen - Sun Microsystems - Beijing China  * uint32_t blink2;       branch link
6045cdc64593Sxinghua wen - Sun Microsystems - Beijing China  * uint32_t ilink1;       interrupt link
6046cdc64593Sxinghua wen - Sun Microsystems - Beijing China  * uint32_t ilink2;       interrupt link
6047cdc64593Sxinghua wen - Sun Microsystems - Beijing China  * uint32_t data1;        error-specific data
6048cdc64593Sxinghua wen - Sun Microsystems - Beijing China  * uint32_t data2;        error-specific data
6049cdc64593Sxinghua wen - Sun Microsystems - Beijing China  * uint32_t line;         source code line of error
6050cdc64593Sxinghua wen - Sun Microsystems - Beijing China  * uint32_t bcon_time;    beacon timer
6051cdc64593Sxinghua wen - Sun Microsystems - Beijing China  * uint32_t tsf_low;      network timestamp function timer
6052cdc64593Sxinghua wen - Sun Microsystems - Beijing China  * uint32_t tsf_hi;       network timestamp function timer
6053cdc64593Sxinghua wen - Sun Microsystems - Beijing China  */
6054cdc64593Sxinghua wen - Sun Microsystems - Beijing China /*
6055cdc64593Sxinghua wen - Sun Microsystems - Beijing China  * iwk_write_error_log - Write error log to dmesg
6056cdc64593Sxinghua wen - Sun Microsystems - Beijing China  */
iwk_write_error_log(iwk_sc_t * sc)6057cdc64593Sxinghua wen - Sun Microsystems - Beijing China static void iwk_write_error_log(iwk_sc_t *sc)
6058cdc64593Sxinghua wen - Sun Microsystems - Beijing China {
6059cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	uint32_t err_ptr;	/* Start address of error log */
6060cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	uint32_t valid;		/* is error log valid */
6061cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
6062b510adaeSfei feng - Sun Microsystems - Beijing China 	err_ptr = LE_32(sc->sc_card_alive_run.error_event_table_ptr);
6063cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (!(err_ptr)) {
6064cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		IWK_DBG((IWK_DEBUG_EEPROM, "NULL error table pointer\n"));
6065cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		return;
6066cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
6067cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
6068cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	iwk_mac_access_enter(sc);
6069cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
6070cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	valid = iwk_mem_read(sc, err_ptr);
6071cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	if (!(valid)) {
6072cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		IWK_DBG((IWK_DEBUG_EEPROM, "Error data not valid\n"));
6073cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		iwk_mac_access_exit(sc);
6074cdc64593Sxinghua wen - Sun Microsystems - Beijing China 		return;
6075cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	}
6076cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	err_ptr += sizeof (uint32_t);
6077cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	IWK_DBG((IWK_DEBUG_EEPROM, "err=%d ", iwk_mem_read(sc, err_ptr)));
6078cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	err_ptr += sizeof (uint32_t);
6079cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	IWK_DBG((IWK_DEBUG_EEPROM, "pc=0x%X ", iwk_mem_read(sc, err_ptr)));
6080cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	err_ptr += sizeof (uint32_t);
6081cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	IWK_DBG((IWK_DEBUG_EEPROM,
6082cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	    "branch link1=0x%X ", iwk_mem_read(sc, err_ptr)));
6083cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	err_ptr += sizeof (uint32_t);
6084cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	IWK_DBG((IWK_DEBUG_EEPROM,
6085cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	    "branch link2=0x%X ", iwk_mem_read(sc, err_ptr)));
6086cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	err_ptr += sizeof (uint32_t);
6087cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	IWK_DBG((IWK_DEBUG_EEPROM,
6088cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	    "interrupt link1=0x%X ", iwk_mem_read(sc, err_ptr)));
6089cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	err_ptr += sizeof (uint32_t);
6090cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	IWK_DBG((IWK_DEBUG_EEPROM,
6091cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	    "interrupt link2=0x%X ", iwk_mem_read(sc, err_ptr)));
6092cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	err_ptr += sizeof (uint32_t);
6093cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	IWK_DBG((IWK_DEBUG_EEPROM, "data1=0x%X ", iwk_mem_read(sc, err_ptr)));
6094cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	err_ptr += sizeof (uint32_t);
6095cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	IWK_DBG((IWK_DEBUG_EEPROM, "data2=0x%X ", iwk_mem_read(sc, err_ptr)));
6096cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	err_ptr += sizeof (uint32_t);
6097cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	IWK_DBG((IWK_DEBUG_EEPROM, "line=%d ", iwk_mem_read(sc, err_ptr)));
6098cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	err_ptr += sizeof (uint32_t);
6099cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	IWK_DBG((IWK_DEBUG_EEPROM, "bcon_time=%d ", iwk_mem_read(sc, err_ptr)));
6100cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	err_ptr += sizeof (uint32_t);
6101cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	IWK_DBG((IWK_DEBUG_EEPROM, "tsf_low=%d ", iwk_mem_read(sc, err_ptr)));
6102cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	err_ptr += sizeof (uint32_t);
6103cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	IWK_DBG((IWK_DEBUG_EEPROM, "tsf_hi=%d\n", iwk_mem_read(sc, err_ptr)));
6104cdc64593Sxinghua wen - Sun Microsystems - Beijing China 
6105cdc64593Sxinghua wen - Sun Microsystems - Beijing China 	iwk_mac_access_exit(sc);
6106cdc64593Sxinghua wen - Sun Microsystems - Beijing China }
6107*ae5a8bedSAndy Fiddaman #endif /* DEBUG */
610819d332feSfei feng - Sun Microsystems - Beijing China 
610919d332feSfei feng - Sun Microsystems - Beijing China static int
iwk_run_state_config_ibss(ieee80211com_t * ic)611019d332feSfei feng - Sun Microsystems - Beijing China iwk_run_state_config_ibss(ieee80211com_t *ic)
611119d332feSfei feng - Sun Microsystems - Beijing China {
611219d332feSfei feng - Sun Microsystems - Beijing China 	iwk_sc_t *sc = (iwk_sc_t *)ic;
611319d332feSfei feng - Sun Microsystems - Beijing China 	ieee80211_node_t *in = ic->ic_bss;
611419d332feSfei feng - Sun Microsystems - Beijing China 	int i, err = IWK_SUCCESS;
611519d332feSfei feng - Sun Microsystems - Beijing China 
611619d332feSfei feng - Sun Microsystems - Beijing China 	mutex_enter(&sc->sc_ibss.node_tb_lock);
611719d332feSfei feng - Sun Microsystems - Beijing China 
611819d332feSfei feng - Sun Microsystems - Beijing China 	/*
611919d332feSfei feng - Sun Microsystems - Beijing China 	 * clean all nodes in ibss node table assure be
612019d332feSfei feng - Sun Microsystems - Beijing China 	 * consistent with hardware
612119d332feSfei feng - Sun Microsystems - Beijing China 	 */
612219d332feSfei feng - Sun Microsystems - Beijing China 	for (i = IWK_STA_ID; i < IWK_STATION_COUNT; i++) {
612319d332feSfei feng - Sun Microsystems - Beijing China 		sc->sc_ibss.ibss_node_tb[i].used = 0;
612419d332feSfei feng - Sun Microsystems - Beijing China 		(void) memset(&sc->sc_ibss.ibss_node_tb[i].node,
612519d332feSfei feng - Sun Microsystems - Beijing China 		    0,
612619d332feSfei feng - Sun Microsystems - Beijing China 		    sizeof (iwk_add_sta_t));
612719d332feSfei feng - Sun Microsystems - Beijing China 	}
612819d332feSfei feng - Sun Microsystems - Beijing China 
612919d332feSfei feng - Sun Microsystems - Beijing China 	sc->sc_ibss.node_number = 0;
613019d332feSfei feng - Sun Microsystems - Beijing China 
613119d332feSfei feng - Sun Microsystems - Beijing China 	mutex_exit(&sc->sc_ibss.node_tb_lock);
613219d332feSfei feng - Sun Microsystems - Beijing China 
613319d332feSfei feng - Sun Microsystems - Beijing China 	/*
613419d332feSfei feng - Sun Microsystems - Beijing China 	 * configure RX and TX
613519d332feSfei feng - Sun Microsystems - Beijing China 	 */
613619d332feSfei feng - Sun Microsystems - Beijing China 	sc->sc_config.dev_type = RXON_DEV_TYPE_IBSS;
613719d332feSfei feng - Sun Microsystems - Beijing China 
6138b510adaeSfei feng - Sun Microsystems - Beijing China 	sc->sc_config.flags |= LE_32(RXON_FLG_SHORT_PREAMBLE_MSK);
613919d332feSfei feng - Sun Microsystems - Beijing China 	sc->sc_config.filter_flags =
614019d332feSfei feng - Sun Microsystems - Beijing China 	    LE_32(RXON_FILTER_ACCEPT_GRP_MSK |
614119d332feSfei feng - Sun Microsystems - Beijing China 	    RXON_FILTER_DIS_DECRYPT_MSK |
614219d332feSfei feng - Sun Microsystems - Beijing China 	    RXON_FILTER_DIS_GRP_DECRYPT_MSK);
614319d332feSfei feng - Sun Microsystems - Beijing China 
614419d332feSfei feng - Sun Microsystems - Beijing China 	sc->sc_config.assoc_id = 0;
614519d332feSfei feng - Sun Microsystems - Beijing China 
614619d332feSfei feng - Sun Microsystems - Beijing China 	IEEE80211_ADDR_COPY(sc->sc_config.bssid, in->in_bssid);
6147b510adaeSfei feng - Sun Microsystems - Beijing China 	sc->sc_config.chan = LE_16(ieee80211_chan2ieee(ic,
6148b510adaeSfei feng - Sun Microsystems - Beijing China 	    in->in_chan));
614919d332feSfei feng - Sun Microsystems - Beijing China 
615019d332feSfei feng - Sun Microsystems - Beijing China 	if (ic->ic_curmode == IEEE80211_MODE_11B) {
615119d332feSfei feng - Sun Microsystems - Beijing China 		sc->sc_config.cck_basic_rates = 0x03;
615219d332feSfei feng - Sun Microsystems - Beijing China 		sc->sc_config.ofdm_basic_rates = 0;
615319d332feSfei feng - Sun Microsystems - Beijing China 	} else if ((in->in_chan != IEEE80211_CHAN_ANYC) &&
615419d332feSfei feng - Sun Microsystems - Beijing China 	    (IEEE80211_IS_CHAN_5GHZ(in->in_chan))) {
615519d332feSfei feng - Sun Microsystems - Beijing China 		sc->sc_config.cck_basic_rates = 0;
615619d332feSfei feng - Sun Microsystems - Beijing China 		sc->sc_config.ofdm_basic_rates = 0x15;
615719d332feSfei feng - Sun Microsystems - Beijing China 
615819d332feSfei feng - Sun Microsystems - Beijing China 	} else {
615919d332feSfei feng - Sun Microsystems - Beijing China 		sc->sc_config.cck_basic_rates = 0x0f;
616019d332feSfei feng - Sun Microsystems - Beijing China 		sc->sc_config.ofdm_basic_rates = 0xff;
616119d332feSfei feng - Sun Microsystems - Beijing China 	}
616219d332feSfei feng - Sun Microsystems - Beijing China 
616319d332feSfei feng - Sun Microsystems - Beijing China 	sc->sc_config.flags &=
616419d332feSfei feng - Sun Microsystems - Beijing China 	    ~LE_32(RXON_FLG_SHORT_PREAMBLE_MSK |
616519d332feSfei feng - Sun Microsystems - Beijing China 	    RXON_FLG_SHORT_SLOT_MSK);
616619d332feSfei feng - Sun Microsystems - Beijing China 
616719d332feSfei feng - Sun Microsystems - Beijing China 	if (ic->ic_flags & IEEE80211_F_SHSLOT) {
616819d332feSfei feng - Sun Microsystems - Beijing China 		sc->sc_config.flags |=
616919d332feSfei feng - Sun Microsystems - Beijing China 		    LE_32(RXON_FLG_SHORT_SLOT_MSK);
617019d332feSfei feng - Sun Microsystems - Beijing China 	}
617119d332feSfei feng - Sun Microsystems - Beijing China 
617219d332feSfei feng - Sun Microsystems - Beijing China 	if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) {
617319d332feSfei feng - Sun Microsystems - Beijing China 		sc->sc_config.flags |=
617419d332feSfei feng - Sun Microsystems - Beijing China 		    LE_32(RXON_FLG_SHORT_PREAMBLE_MSK);
617519d332feSfei feng - Sun Microsystems - Beijing China 	}
617619d332feSfei feng - Sun Microsystems - Beijing China 
617719d332feSfei feng - Sun Microsystems - Beijing China 	sc->sc_config.filter_flags |=
617819d332feSfei feng - Sun Microsystems - Beijing China 	    LE_32(RXON_FILTER_ASSOC_MSK);
617919d332feSfei feng - Sun Microsystems - Beijing China 
618019d332feSfei feng - Sun Microsystems - Beijing China 	err = iwk_cmd(sc, REPLY_RXON, &sc->sc_config,
618119d332feSfei feng - Sun Microsystems - Beijing China 	    sizeof (iwk_rxon_cmd_t), 1);
618219d332feSfei feng - Sun Microsystems - Beijing China 	if (err != IWK_SUCCESS) {
618319d332feSfei feng - Sun Microsystems - Beijing China 		cmn_err(CE_WARN, "iwk_run_state_config_ibss(): "
618419d332feSfei feng - Sun Microsystems - Beijing China 		    "failed to update configuration.\n");
618519d332feSfei feng - Sun Microsystems - Beijing China 		return (err);
618619d332feSfei feng - Sun Microsystems - Beijing China 	}
618719d332feSfei feng - Sun Microsystems - Beijing China 
618819d332feSfei feng - Sun Microsystems - Beijing China 	return (err);
618919d332feSfei feng - Sun Microsystems - Beijing China 
619019d332feSfei feng - Sun Microsystems - Beijing China }
619119d332feSfei feng - Sun Microsystems - Beijing China 
619219d332feSfei feng - Sun Microsystems - Beijing China static int
iwk_run_state_config_sta(ieee80211com_t * ic)619319d332feSfei feng - Sun Microsystems - Beijing China iwk_run_state_config_sta(ieee80211com_t *ic)
619419d332feSfei feng - Sun Microsystems - Beijing China {
619519d332feSfei feng - Sun Microsystems - Beijing China 	iwk_sc_t *sc = (iwk_sc_t *)ic;
619619d332feSfei feng - Sun Microsystems - Beijing China 	ieee80211_node_t *in = ic->ic_bss;
619719d332feSfei feng - Sun Microsystems - Beijing China 	int err = IWK_SUCCESS;
619819d332feSfei feng - Sun Microsystems - Beijing China 
619919d332feSfei feng - Sun Microsystems - Beijing China 	/* update adapter's configuration */
620019d332feSfei feng - Sun Microsystems - Beijing China 	if (sc->sc_assoc_id != in->in_associd) {
620119d332feSfei feng - Sun Microsystems - Beijing China 		cmn_err(CE_WARN, "iwk_run_state_config_sta(): "
620219d332feSfei feng - Sun Microsystems - Beijing China 		    "associate ID mismatch: expected %d, "
620319d332feSfei feng - Sun Microsystems - Beijing China 		    "got %d\n",
620419d332feSfei feng - Sun Microsystems - Beijing China 		    in->in_associd, sc->sc_assoc_id);
620519d332feSfei feng - Sun Microsystems - Beijing China 	}
6206b510adaeSfei feng - Sun Microsystems - Beijing China 	sc->sc_config.assoc_id = LE_16(in->in_associd & 0x3fff);
620719d332feSfei feng - Sun Microsystems - Beijing China 
620819d332feSfei feng - Sun Microsystems - Beijing China 	/*
620919d332feSfei feng - Sun Microsystems - Beijing China 	 * short preamble/slot time are
621019d332feSfei feng - Sun Microsystems - Beijing China 	 * negotiated when associating
621119d332feSfei feng - Sun Microsystems - Beijing China 	 */
621219d332feSfei feng - Sun Microsystems - Beijing China 	sc->sc_config.flags &=
621319d332feSfei feng - Sun Microsystems - Beijing China 	    ~LE_32(RXON_FLG_SHORT_PREAMBLE_MSK |
621419d332feSfei feng - Sun Microsystems - Beijing China 	    RXON_FLG_SHORT_SLOT_MSK);
621519d332feSfei feng - Sun Microsystems - Beijing China 
621619d332feSfei feng - Sun Microsystems - Beijing China 	if (ic->ic_flags & IEEE80211_F_SHSLOT)
621719d332feSfei feng - Sun Microsystems - Beijing China 		sc->sc_config.flags |=
621819d332feSfei feng - Sun Microsystems - Beijing China 		    LE_32(RXON_FLG_SHORT_SLOT_MSK);
621919d332feSfei feng - Sun Microsystems - Beijing China 
622019d332feSfei feng - Sun Microsystems - Beijing China 	if (ic->ic_flags & IEEE80211_F_SHPREAMBLE)
622119d332feSfei feng - Sun Microsystems - Beijing China 		sc->sc_config.flags |=
622219d332feSfei feng - Sun Microsystems - Beijing China 		    LE_32(RXON_FLG_SHORT_PREAMBLE_MSK);
622319d332feSfei feng - Sun Microsystems - Beijing China 
622419d332feSfei feng - Sun Microsystems - Beijing China 	sc->sc_config.filter_flags |=
622519d332feSfei feng - Sun Microsystems - Beijing China 	    LE_32(RXON_FILTER_ASSOC_MSK);
622619d332feSfei feng - Sun Microsystems - Beijing China 
622719d332feSfei feng - Sun Microsystems - Beijing China 	if (ic->ic_opmode != IEEE80211_M_STA)
622819d332feSfei feng - Sun Microsystems - Beijing China 		sc->sc_config.filter_flags |=
622919d332feSfei feng - Sun Microsystems - Beijing China 		    LE_32(RXON_FILTER_BCON_AWARE_MSK);
623019d332feSfei feng - Sun Microsystems - Beijing China 
623119d332feSfei feng - Sun Microsystems - Beijing China 	IWK_DBG((IWK_DEBUG_80211, "config chan %d flags %x"
623219d332feSfei feng - Sun Microsystems - Beijing China 	    " filter_flags %x\n",
623319d332feSfei feng - Sun Microsystems - Beijing China 	    sc->sc_config.chan, sc->sc_config.flags,
623419d332feSfei feng - Sun Microsystems - Beijing China 	    sc->sc_config.filter_flags));
623519d332feSfei feng - Sun Microsystems - Beijing China 
623619d332feSfei feng - Sun Microsystems - Beijing China 	err = iwk_cmd(sc, REPLY_RXON, &sc->sc_config,
623719d332feSfei feng - Sun Microsystems - Beijing China 	    sizeof (iwk_rxon_cmd_t), 1);
623819d332feSfei feng - Sun Microsystems - Beijing China 	if (err != IWK_SUCCESS) {
623919d332feSfei feng - Sun Microsystems - Beijing China 		cmn_err(CE_WARN, "iwk_run_state_config_sta(): "
624019d332feSfei feng - Sun Microsystems - Beijing China 		    "failed to update configuration\n");
624119d332feSfei feng - Sun Microsystems - Beijing China 		return (err);
624219d332feSfei feng - Sun Microsystems - Beijing China 	}
624319d332feSfei feng - Sun Microsystems - Beijing China 
624419d332feSfei feng - Sun Microsystems - Beijing China 	return (err);
624519d332feSfei feng - Sun Microsystems - Beijing China }
624619d332feSfei feng - Sun Microsystems - Beijing China 
62476f12def4Spengcheng chen - Sun Microsystems - Beijing China static int
iwk_fast_recover(iwk_sc_t * sc)62486f12def4Spengcheng chen - Sun Microsystems - Beijing China iwk_fast_recover(iwk_sc_t *sc)
62496f12def4Spengcheng chen - Sun Microsystems - Beijing China {
62506f12def4Spengcheng chen - Sun Microsystems - Beijing China 	ieee80211com_t *ic = &sc->sc_ic;
62516f12def4Spengcheng chen - Sun Microsystems - Beijing China 	int err;
62526f12def4Spengcheng chen - Sun Microsystems - Beijing China 
62536f12def4Spengcheng chen - Sun Microsystems - Beijing China 	mutex_enter(&sc->sc_glock);
62546f12def4Spengcheng chen - Sun Microsystems - Beijing China 
62556f12def4Spengcheng chen - Sun Microsystems - Beijing China 	/* restore runtime configuration */
62566f12def4Spengcheng chen - Sun Microsystems - Beijing China 	bcopy(&sc->sc_config_save, &sc->sc_config,
62576f12def4Spengcheng chen - Sun Microsystems - Beijing China 	    sizeof (sc->sc_config));
62586f12def4Spengcheng chen - Sun Microsystems - Beijing China 
62596f12def4Spengcheng chen - Sun Microsystems - Beijing China 	/* reset state to handle reassociations correctly */
62606f12def4Spengcheng chen - Sun Microsystems - Beijing China 	sc->sc_config.assoc_id = 0;
62616f12def4Spengcheng chen - Sun Microsystems - Beijing China 	sc->sc_config.filter_flags &=
62626f12def4Spengcheng chen - Sun Microsystems - Beijing China 	    ~LE_32(RXON_FILTER_ASSOC_MSK);
62636f12def4Spengcheng chen - Sun Microsystems - Beijing China 
62646f12def4Spengcheng chen - Sun Microsystems - Beijing China 	if ((err = iwk_hw_set_before_auth(sc)) != 0) {
62656f12def4Spengcheng chen - Sun Microsystems - Beijing China 		cmn_err(CE_WARN, "iwk_fast_recover(): "
62666f12def4Spengcheng chen - Sun Microsystems - Beijing China 		    "failed to setup authentication\n");
62676f12def4Spengcheng chen - Sun Microsystems - Beijing China 		mutex_exit(&sc->sc_glock);
62686f12def4Spengcheng chen - Sun Microsystems - Beijing China 		return (err);
62696f12def4Spengcheng chen - Sun Microsystems - Beijing China 	}
62706f12def4Spengcheng chen - Sun Microsystems - Beijing China 
62716f12def4Spengcheng chen - Sun Microsystems - Beijing China 	bcopy(&sc->sc_config_save, &sc->sc_config,
62726f12def4Spengcheng chen - Sun Microsystems - Beijing China 	    sizeof (sc->sc_config));
62736f12def4Spengcheng chen - Sun Microsystems - Beijing China 
62746f12def4Spengcheng chen - Sun Microsystems - Beijing China 	/* update adapter's configuration */
62756f12def4Spengcheng chen - Sun Microsystems - Beijing China 	err = iwk_run_state_config_sta(ic);
62766f12def4Spengcheng chen - Sun Microsystems - Beijing China 	if (err != IWK_SUCCESS) {
62776f12def4Spengcheng chen - Sun Microsystems - Beijing China 		cmn_err(CE_WARN, "iwk_fast_recover(): "
62786f12def4Spengcheng chen - Sun Microsystems - Beijing China 		    "failed to setup association\n");
62796f12def4Spengcheng chen - Sun Microsystems - Beijing China 		mutex_exit(&sc->sc_glock);
62806f12def4Spengcheng chen - Sun Microsystems - Beijing China 		return (err);
62816f12def4Spengcheng chen - Sun Microsystems - Beijing China 	}
62826f12def4Spengcheng chen - Sun Microsystems - Beijing China 
62836f12def4Spengcheng chen - Sun Microsystems - Beijing China 	/* obtain current temperature of chipset */
62846f12def4Spengcheng chen - Sun Microsystems - Beijing China 	sc->sc_tempera = iwk_curr_tempera(sc);
62856f12def4Spengcheng chen - Sun Microsystems - Beijing China 
62866f12def4Spengcheng chen - Sun Microsystems - Beijing China 	/*
62876f12def4Spengcheng chen - Sun Microsystems - Beijing China 	 * make Tx power calibration to determine
62886f12def4Spengcheng chen - Sun Microsystems - Beijing China 	 * the gains of DSP and radio
62896f12def4Spengcheng chen - Sun Microsystems - Beijing China 	 */
62906f12def4Spengcheng chen - Sun Microsystems - Beijing China 	err = iwk_tx_power_calibration(sc);
62916f12def4Spengcheng chen - Sun Microsystems - Beijing China 	if (err) {
62926f12def4Spengcheng chen - Sun Microsystems - Beijing China 		cmn_err(CE_WARN, "iwk_fast_recover(): "
62936f12def4Spengcheng chen - Sun Microsystems - Beijing China 		    "failed to set tx power table\n");
62946f12def4Spengcheng chen - Sun Microsystems - Beijing China 		mutex_exit(&sc->sc_glock);
62956f12def4Spengcheng chen - Sun Microsystems - Beijing China 		return (err);
62966f12def4Spengcheng chen - Sun Microsystems - Beijing China 	}
62976f12def4Spengcheng chen - Sun Microsystems - Beijing China 
62986f12def4Spengcheng chen - Sun Microsystems - Beijing China 	/*
62996f12def4Spengcheng chen - Sun Microsystems - Beijing China 	 * make initialization for Receiver
63006f12def4Spengcheng chen - Sun Microsystems - Beijing China 	 * sensitivity calibration
63016f12def4Spengcheng chen - Sun Microsystems - Beijing China 	 */
63026f12def4Spengcheng chen - Sun Microsystems - Beijing China 	err = iwk_rx_sens_init(sc);
63036f12def4Spengcheng chen - Sun Microsystems - Beijing China 	if (err) {
63046f12def4Spengcheng chen - Sun Microsystems - Beijing China 		cmn_err(CE_WARN, "iwk_fast_recover(): "
63056f12def4Spengcheng chen - Sun Microsystems - Beijing China 		    "failed to init RX sensitivity\n");
63066f12def4Spengcheng chen - Sun Microsystems - Beijing China 		mutex_exit(&sc->sc_glock);
63076f12def4Spengcheng chen - Sun Microsystems - Beijing China 		return (err);
63086f12def4Spengcheng chen - Sun Microsystems - Beijing China 	}
63096f12def4Spengcheng chen - Sun Microsystems - Beijing China 
63106f12def4Spengcheng chen - Sun Microsystems - Beijing China 	/* make initialization for Receiver gain balance */
63116f12def4Spengcheng chen - Sun Microsystems - Beijing China 	err = iwk_rxgain_diff_init(sc);
63126f12def4Spengcheng chen - Sun Microsystems - Beijing China 	if (err) {
63136f12def4Spengcheng chen - Sun Microsystems - Beijing China 		cmn_err(CE_WARN, "iwk_fast_recover(): "
63146f12def4Spengcheng chen - Sun Microsystems - Beijing China 		    "failed to init phy calibration\n");
63156f12def4Spengcheng chen - Sun Microsystems - Beijing China 		mutex_exit(&sc->sc_glock);
63166f12def4Spengcheng chen - Sun Microsystems - Beijing China 		return (err);
63176f12def4Spengcheng chen - Sun Microsystems - Beijing China 
63186f12def4Spengcheng chen - Sun Microsystems - Beijing China 	}
63196f12def4Spengcheng chen - Sun Microsystems - Beijing China 	/* set LED on */
63206f12def4Spengcheng chen - Sun Microsystems - Beijing China 	iwk_set_led(sc, 2, 0, 1);
63216f12def4Spengcheng chen - Sun Microsystems - Beijing China 
63226f12def4Spengcheng chen - Sun Microsystems - Beijing China 	mutex_exit(&sc->sc_glock);
63236f12def4Spengcheng chen - Sun Microsystems - Beijing China 
63246f12def4Spengcheng chen - Sun Microsystems - Beijing China 	/* update keys */
63256f12def4Spengcheng chen - Sun Microsystems - Beijing China 	if (ic->ic_flags & IEEE80211_F_PRIVACY) {
63266f12def4Spengcheng chen - Sun Microsystems - Beijing China 		for (int i = 0; i < IEEE80211_KEY_MAX; i++) {
63276f12def4Spengcheng chen - Sun Microsystems - Beijing China 			if (ic->ic_nw_keys[i].wk_keyix == IEEE80211_KEYIX_NONE)
63286f12def4Spengcheng chen - Sun Microsystems - Beijing China 				continue;
63296f12def4Spengcheng chen - Sun Microsystems - Beijing China 			err = iwk_key_set(ic, &ic->ic_nw_keys[i],
63306f12def4Spengcheng chen - Sun Microsystems - Beijing China 			    ic->ic_bss->in_macaddr);
63316f12def4Spengcheng chen - Sun Microsystems - Beijing China 			/* failure */
63326f12def4Spengcheng chen - Sun Microsystems - Beijing China 			if (err == 0) {
63336f12def4Spengcheng chen - Sun Microsystems - Beijing China 				cmn_err(CE_WARN, "iwk_fast_recover(): "
63346f12def4Spengcheng chen - Sun Microsystems - Beijing China 				    "failed to setup hardware keys\n");
63356f12def4Spengcheng chen - Sun Microsystems - Beijing China 				return (IWK_FAIL);
63366f12def4Spengcheng chen - Sun Microsystems - Beijing China 			}
63376f12def4Spengcheng chen - Sun Microsystems - Beijing China 		}
63386f12def4Spengcheng chen - Sun Microsystems - Beijing China 	}
63396f12def4Spengcheng chen - Sun Microsystems - Beijing China 
63406f12def4Spengcheng chen - Sun Microsystems - Beijing China 	sc->sc_flags &= ~IWK_F_HW_ERR_RECOVER;
63416f12def4Spengcheng chen - Sun Microsystems - Beijing China 
63426f12def4Spengcheng chen - Sun Microsystems - Beijing China 	/* start queue */
63436f12def4Spengcheng chen - Sun Microsystems - Beijing China 	IWK_DBG((IWK_DEBUG_FW, "iwk_fast_recover(): resume xmit\n"));
63446f12def4Spengcheng chen - Sun Microsystems - Beijing China 	mac_tx_update(ic->ic_mach);
63456f12def4Spengcheng chen - Sun Microsystems - Beijing China 
63466f12def4Spengcheng chen - Sun Microsystems - Beijing China 
63476f12def4Spengcheng chen - Sun Microsystems - Beijing China 	return (IWK_SUCCESS);
63486f12def4Spengcheng chen - Sun Microsystems - Beijing China }
63496f12def4Spengcheng chen - Sun Microsystems - Beijing China 
635019d332feSfei feng - Sun Microsystems - Beijing China static int
iwk_start_tx_beacon(ieee80211com_t * ic)635119d332feSfei feng - Sun Microsystems - Beijing China iwk_start_tx_beacon(ieee80211com_t *ic)
635219d332feSfei feng - Sun Microsystems - Beijing China {
635319d332feSfei feng - Sun Microsystems - Beijing China 	iwk_sc_t *sc = (iwk_sc_t *)ic;
635419d332feSfei feng - Sun Microsystems - Beijing China 	ieee80211_node_t *in = ic->ic_bss;
635519d332feSfei feng - Sun Microsystems - Beijing China 	int err = IWK_SUCCESS;
635619d332feSfei feng - Sun Microsystems - Beijing China 	iwk_tx_beacon_cmd_t  *tx_beacon_p;
635719d332feSfei feng - Sun Microsystems - Beijing China 	uint16_t  masks = 0;
635819d332feSfei feng - Sun Microsystems - Beijing China 	mblk_t *mp;
635919d332feSfei feng - Sun Microsystems - Beijing China 	int rate;
636019d332feSfei feng - Sun Microsystems - Beijing China 
636119d332feSfei feng - Sun Microsystems - Beijing China 	/*
636219d332feSfei feng - Sun Microsystems - Beijing China 	 * allocate and transmit beacon frames
636319d332feSfei feng - Sun Microsystems - Beijing China 	 */
636419d332feSfei feng - Sun Microsystems - Beijing China 	tx_beacon_p = &sc->sc_ibss.ibss_beacon.beacon_cmd;
636519d332feSfei feng - Sun Microsystems - Beijing China 
636619d332feSfei feng - Sun Microsystems - Beijing China 	(void) memset(tx_beacon_p, 0,
636719d332feSfei feng - Sun Microsystems - Beijing China 	    sizeof (iwk_tx_beacon_cmd_t));
636819d332feSfei feng - Sun Microsystems - Beijing China 	rate = 0;
636919d332feSfei feng - Sun Microsystems - Beijing China 	masks = 0;
637019d332feSfei feng - Sun Microsystems - Beijing China 
637119d332feSfei feng - Sun Microsystems - Beijing China 	tx_beacon_p->config.sta_id = IWK_BROADCAST_ID;
637219d332feSfei feng - Sun Microsystems - Beijing China 	tx_beacon_p->config.stop_time.life_time =
637319d332feSfei feng - Sun Microsystems - Beijing China 	    LE_32(0xffffffff);
637419d332feSfei feng - Sun Microsystems - Beijing China 
637519d332feSfei feng - Sun Microsystems - Beijing China 	if (sc->sc_ibss.ibss_beacon.mp != NULL) {
637619d332feSfei feng - Sun Microsystems - Beijing China 		freemsg(sc->sc_ibss.ibss_beacon.mp);
637719d332feSfei feng - Sun Microsystems - Beijing China 		sc->sc_ibss.ibss_beacon.mp = NULL;
637819d332feSfei feng - Sun Microsystems - Beijing China 	}
637919d332feSfei feng - Sun Microsystems - Beijing China 
638019d332feSfei feng - Sun Microsystems - Beijing China 	sc->sc_ibss.ibss_beacon.mp =
638119d332feSfei feng - Sun Microsystems - Beijing China 	    ieee80211_beacon_alloc(ic, in,
638219d332feSfei feng - Sun Microsystems - Beijing China 	    &sc->sc_ibss.ibss_beacon.iwk_boff);
638319d332feSfei feng - Sun Microsystems - Beijing China 	if (sc->sc_ibss.ibss_beacon.mp == NULL) {
638419d332feSfei feng - Sun Microsystems - Beijing China 		cmn_err(CE_WARN, "iwk_start_tx_beacon(): "
638519d332feSfei feng - Sun Microsystems - Beijing China 		    "failed to get beacon frame.\n");
638619d332feSfei feng - Sun Microsystems - Beijing China 		return (IWK_FAIL);
638719d332feSfei feng - Sun Microsystems - Beijing China 	}
638819d332feSfei feng - Sun Microsystems - Beijing China 
638919d332feSfei feng - Sun Microsystems - Beijing China 	mp = sc->sc_ibss.ibss_beacon.mp;
639019d332feSfei feng - Sun Microsystems - Beijing China 
639119d332feSfei feng - Sun Microsystems - Beijing China 	ASSERT(mp->b_cont == NULL);
639219d332feSfei feng - Sun Microsystems - Beijing China 
639319d332feSfei feng - Sun Microsystems - Beijing China 	bcopy(mp->b_rptr, tx_beacon_p->bcon_frame, MBLKL(mp));
639419d332feSfei feng - Sun Microsystems - Beijing China 
6395b510adaeSfei feng - Sun Microsystems - Beijing China 	tx_beacon_p->config.len = LE_16((uint16_t)(MBLKL(mp)));
639619d332feSfei feng - Sun Microsystems - Beijing China 	sc->sc_ibss.ibss_beacon.beacon_cmd_len =
639719d332feSfei feng - Sun Microsystems - Beijing China 	    sizeof (iwk_tx_cmd_t) +
6398b510adaeSfei feng - Sun Microsystems - Beijing China 	    4 + LE_16(tx_beacon_p->config.len);
639919d332feSfei feng - Sun Microsystems - Beijing China 
640019d332feSfei feng - Sun Microsystems - Beijing China 	/*
640119d332feSfei feng - Sun Microsystems - Beijing China 	 * beacons are sent at 1M
640219d332feSfei feng - Sun Microsystems - Beijing China 	 */
640319d332feSfei feng - Sun Microsystems - Beijing China 	rate = in->in_rates.ir_rates[0];
640419d332feSfei feng - Sun Microsystems - Beijing China 	rate &= IEEE80211_RATE_VAL;
640519d332feSfei feng - Sun Microsystems - Beijing China 
640619d332feSfei feng - Sun Microsystems - Beijing China 	if (2 == rate || 4 == rate || 11 == rate ||
640719d332feSfei feng - Sun Microsystems - Beijing China 	    22 == rate) {
640819d332feSfei feng - Sun Microsystems - Beijing China 		masks |= RATE_MCS_CCK_MSK;
640919d332feSfei feng - Sun Microsystems - Beijing China 	}
641019d332feSfei feng - Sun Microsystems - Beijing China 
641119d332feSfei feng - Sun Microsystems - Beijing China 	masks |= RATE_MCS_ANT_B_MSK;
641219d332feSfei feng - Sun Microsystems - Beijing China 
641319d332feSfei feng - Sun Microsystems - Beijing China 	tx_beacon_p->config.rate.r.rate_n_flags =
6414b510adaeSfei feng - Sun Microsystems - Beijing China 	    LE_32(iwk_rate_to_plcp(rate) | masks);
641519d332feSfei feng - Sun Microsystems - Beijing China 
641619d332feSfei feng - Sun Microsystems - Beijing China 
641719d332feSfei feng - Sun Microsystems - Beijing China 	tx_beacon_p->config.tx_flags =
6418b510adaeSfei feng - Sun Microsystems - Beijing China 	    LE_32(TX_CMD_FLG_SEQ_CTL_MSK | TX_CMD_FLG_TSF_MSK);
641919d332feSfei feng - Sun Microsystems - Beijing China 
642019d332feSfei feng - Sun Microsystems - Beijing China 	if (ic->ic_bss->in_tstamp.tsf != 0) {
642119d332feSfei feng - Sun Microsystems - Beijing China 		sc->sc_ibss.ibss_beacon.syncbeacon = 1;
642219d332feSfei feng - Sun Microsystems - Beijing China 	} else {
642319d332feSfei feng - Sun Microsystems - Beijing China 		if (ieee80211_beacon_update(ic, in,
642419d332feSfei feng - Sun Microsystems - Beijing China 		    &sc->sc_ibss.ibss_beacon.iwk_boff,
642519d332feSfei feng - Sun Microsystems - Beijing China 		    mp, 0)) {
642619d332feSfei feng - Sun Microsystems - Beijing China 			bcopy(mp->b_rptr,
642719d332feSfei feng - Sun Microsystems - Beijing China 			    tx_beacon_p->bcon_frame,
642819d332feSfei feng - Sun Microsystems - Beijing China 			    MBLKL(mp));
642919d332feSfei feng - Sun Microsystems - Beijing China 		}
643019d332feSfei feng - Sun Microsystems - Beijing China 
643119d332feSfei feng - Sun Microsystems - Beijing China 		err = iwk_cmd(sc, REPLY_TX_BEACON,
643219d332feSfei feng - Sun Microsystems - Beijing China 		    tx_beacon_p,
643319d332feSfei feng - Sun Microsystems - Beijing China 		    sc->sc_ibss.ibss_beacon.beacon_cmd_len,
643419d332feSfei feng - Sun Microsystems - Beijing China 		    1);
643519d332feSfei feng - Sun Microsystems - Beijing China 		if (err != IWK_SUCCESS) {
643619d332feSfei feng - Sun Microsystems - Beijing China 			cmn_err(CE_WARN, "iwk_start_tx_beacon(): "
643719d332feSfei feng - Sun Microsystems - Beijing China 			    "failed to TX beacon.\n");
643819d332feSfei feng - Sun Microsystems - Beijing China 			return (err);
643919d332feSfei feng - Sun Microsystems - Beijing China 		}
644019d332feSfei feng - Sun Microsystems - Beijing China 
644119d332feSfei feng - Sun Microsystems - Beijing China 		sc->sc_ibss.ibss_beacon.syncbeacon = 0;
644219d332feSfei feng - Sun Microsystems - Beijing China 	}
644319d332feSfei feng - Sun Microsystems - Beijing China 
644419d332feSfei feng - Sun Microsystems - Beijing China 	return (err);
644519d332feSfei feng - Sun Microsystems - Beijing China }
644619d332feSfei feng - Sun Microsystems - Beijing China 
644719d332feSfei feng - Sun Microsystems - Beijing China static int
iwk_clean_add_node_ibss(struct ieee80211com * ic,uint8_t addr[IEEE80211_ADDR_LEN],uint8_t * index2)644819d332feSfei feng - Sun Microsystems - Beijing China iwk_clean_add_node_ibss(struct ieee80211com *ic,
644919d332feSfei feng - Sun Microsystems - Beijing China     uint8_t addr[IEEE80211_ADDR_LEN], uint8_t *index2)
645019d332feSfei feng - Sun Microsystems - Beijing China {
645119d332feSfei feng - Sun Microsystems - Beijing China 	iwk_sc_t *sc = (iwk_sc_t *)ic;
645219d332feSfei feng - Sun Microsystems - Beijing China 	uint8_t	index;
645319d332feSfei feng - Sun Microsystems - Beijing China 	iwk_add_sta_t bc_node;
645419d332feSfei feng - Sun Microsystems - Beijing China 	iwk_link_quality_cmd_t bc_link_quality;
645519d332feSfei feng - Sun Microsystems - Beijing China 	iwk_link_quality_cmd_t link_quality;
645619d332feSfei feng - Sun Microsystems - Beijing China 	uint16_t  bc_masks = 0;
645719d332feSfei feng - Sun Microsystems - Beijing China 	uint16_t  masks = 0;
645819d332feSfei feng - Sun Microsystems - Beijing China 	int i, rate;
645919d332feSfei feng - Sun Microsystems - Beijing China 	struct ieee80211_rateset rs;
646019d332feSfei feng - Sun Microsystems - Beijing China 	iwk_ibss_node_t *ibss_node_p;
646119d332feSfei feng - Sun Microsystems - Beijing China 	int err = IWK_SUCCESS;
646219d332feSfei feng - Sun Microsystems - Beijing China 
646319d332feSfei feng - Sun Microsystems - Beijing China 	/*
646419d332feSfei feng - Sun Microsystems - Beijing China 	 * find a location that is not
646519d332feSfei feng - Sun Microsystems - Beijing China 	 * used in ibss node table
646619d332feSfei feng - Sun Microsystems - Beijing China 	 */
646719d332feSfei feng - Sun Microsystems - Beijing China 	for (index = IWK_STA_ID;
646819d332feSfei feng - Sun Microsystems - Beijing China 	    index < IWK_STATION_COUNT; index++) {
646919d332feSfei feng - Sun Microsystems - Beijing China 		if (!sc->sc_ibss.ibss_node_tb[index].used) {
647019d332feSfei feng - Sun Microsystems - Beijing China 			break;
647119d332feSfei feng - Sun Microsystems - Beijing China 		}
647219d332feSfei feng - Sun Microsystems - Beijing China 	}
647319d332feSfei feng - Sun Microsystems - Beijing China 
647419d332feSfei feng - Sun Microsystems - Beijing China 	/*
647519d332feSfei feng - Sun Microsystems - Beijing China 	 * if have too many nodes in hardware, clean up
647619d332feSfei feng - Sun Microsystems - Beijing China 	 */
647719d332feSfei feng - Sun Microsystems - Beijing China 	if (index < IWK_BROADCAST_ID &&
647819d332feSfei feng - Sun Microsystems - Beijing China 	    sc->sc_ibss.node_number >= 25) {
647919d332feSfei feng - Sun Microsystems - Beijing China 		if (iwk_cmd(sc, REPLY_REMOVE_ALL_STA,
648019d332feSfei feng - Sun Microsystems - Beijing China 		    NULL, 0, 1) != IWK_SUCCESS) {
648119d332feSfei feng - Sun Microsystems - Beijing China 			cmn_err(CE_WARN, "iwk_clean_add_node_ibss(): "
648219d332feSfei feng - Sun Microsystems - Beijing China 			    "failed to remove all nodes in hardware\n");
648319d332feSfei feng - Sun Microsystems - Beijing China 			return (IWK_FAIL);
648419d332feSfei feng - Sun Microsystems - Beijing China 		}
648519d332feSfei feng - Sun Microsystems - Beijing China 
648619d332feSfei feng - Sun Microsystems - Beijing China 		for (i = IWK_STA_ID; i < IWK_STATION_COUNT; i++) {
648719d332feSfei feng - Sun Microsystems - Beijing China 			sc->sc_ibss.ibss_node_tb[i].used = 0;
648819d332feSfei feng - Sun Microsystems - Beijing China 			(void) memset(&sc->sc_ibss.ibss_node_tb[i].node,
648919d332feSfei feng - Sun Microsystems - Beijing China 			    0, sizeof (iwk_add_sta_t));
649019d332feSfei feng - Sun Microsystems - Beijing China 		}
649119d332feSfei feng - Sun Microsystems - Beijing China 
649219d332feSfei feng - Sun Microsystems - Beijing China 		sc->sc_ibss.node_number = 0;
649319d332feSfei feng - Sun Microsystems - Beijing China 
649419d332feSfei feng - Sun Microsystems - Beijing China 		/*
649519d332feSfei feng - Sun Microsystems - Beijing China 		 * add broadcast node so that we
649619d332feSfei feng - Sun Microsystems - Beijing China 		 * can send broadcast frame
649719d332feSfei feng - Sun Microsystems - Beijing China 		 */
649819d332feSfei feng - Sun Microsystems - Beijing China 		(void) memset(&bc_node, 0, sizeof (bc_node));
649919d332feSfei feng - Sun Microsystems - Beijing China 		(void) memset(bc_node.bssid, 0xff, 6);
650019d332feSfei feng - Sun Microsystems - Beijing China 		bc_node.id = IWK_BROADCAST_ID;
650119d332feSfei feng - Sun Microsystems - Beijing China 
650219d332feSfei feng - Sun Microsystems - Beijing China 		err = iwk_cmd(sc, REPLY_ADD_STA, &bc_node, sizeof (bc_node), 1);
650319d332feSfei feng - Sun Microsystems - Beijing China 		if (err != IWK_SUCCESS) {
650419d332feSfei feng - Sun Microsystems - Beijing China 		cmn_err(CE_WARN, "iwk_clean_add_node_ibss(): "
650519d332feSfei feng - Sun Microsystems - Beijing China 		    "failed to add broadcast node\n");
650619d332feSfei feng - Sun Microsystems - Beijing China 		return (err);
650719d332feSfei feng - Sun Microsystems - Beijing China 		}
650819d332feSfei feng - Sun Microsystems - Beijing China 
650919d332feSfei feng - Sun Microsystems - Beijing China 		/* TX_LINK_QUALITY cmd */
651019d332feSfei feng - Sun Microsystems - Beijing China 		(void) memset(&bc_link_quality, 0, sizeof (bc_link_quality));
651119d332feSfei feng - Sun Microsystems - Beijing China 		for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) {
651219d332feSfei feng - Sun Microsystems - Beijing China 			bc_masks |= RATE_MCS_CCK_MSK;
651319d332feSfei feng - Sun Microsystems - Beijing China 			bc_masks |= RATE_MCS_ANT_B_MSK;
651419d332feSfei feng - Sun Microsystems - Beijing China 			bc_masks &= ~RATE_MCS_ANT_A_MSK;
651519d332feSfei feng - Sun Microsystems - Beijing China 			bc_link_quality.rate_n_flags[i] =
6516b510adaeSfei feng - Sun Microsystems - Beijing China 			    LE_32(iwk_rate_to_plcp(2) | bc_masks);
651719d332feSfei feng - Sun Microsystems - Beijing China 		}
651819d332feSfei feng - Sun Microsystems - Beijing China 
651919d332feSfei feng - Sun Microsystems - Beijing China 		bc_link_quality.general_params.single_stream_ant_msk = 2;
652019d332feSfei feng - Sun Microsystems - Beijing China 		bc_link_quality.general_params.dual_stream_ant_msk = 3;
652119d332feSfei feng - Sun Microsystems - Beijing China 		bc_link_quality.agg_params.agg_dis_start_th = 3;
652219d332feSfei feng - Sun Microsystems - Beijing China 		bc_link_quality.agg_params.agg_time_limit = LE_16(4000);
652319d332feSfei feng - Sun Microsystems - Beijing China 		bc_link_quality.sta_id = IWK_BROADCAST_ID;
652419d332feSfei feng - Sun Microsystems - Beijing China 
652519d332feSfei feng - Sun Microsystems - Beijing China 		err = iwk_cmd(sc, REPLY_TX_LINK_QUALITY_CMD,
652619d332feSfei feng - Sun Microsystems - Beijing China 		    &bc_link_quality, sizeof (bc_link_quality), 1);
652719d332feSfei feng - Sun Microsystems - Beijing China 		if (err != IWK_SUCCESS) {
652819d332feSfei feng - Sun Microsystems - Beijing China 			cmn_err(CE_WARN, "iwk_clean_add_node_ibss(): "
652919d332feSfei feng - Sun Microsystems - Beijing China 			    "failed to config link quality table\n");
653019d332feSfei feng - Sun Microsystems - Beijing China 			return (err);
653119d332feSfei feng - Sun Microsystems - Beijing China 		}
653219d332feSfei feng - Sun Microsystems - Beijing China 	}
653319d332feSfei feng - Sun Microsystems - Beijing China 
653419d332feSfei feng - Sun Microsystems - Beijing China 	if (index >= IWK_BROADCAST_ID) {
653519d332feSfei feng - Sun Microsystems - Beijing China 		cmn_err(CE_WARN, "iwk_clean_add_node_ibss(): "
653619d332feSfei feng - Sun Microsystems - Beijing China 		    "the count of node in hardware is too much\n");
653719d332feSfei feng - Sun Microsystems - Beijing China 		return (IWK_FAIL);
653819d332feSfei feng - Sun Microsystems - Beijing China 	}
653919d332feSfei feng - Sun Microsystems - Beijing China 
654019d332feSfei feng - Sun Microsystems - Beijing China 	/*
654119d332feSfei feng - Sun Microsystems - Beijing China 	 * add a node into hardware
654219d332feSfei feng - Sun Microsystems - Beijing China 	 */
654319d332feSfei feng - Sun Microsystems - Beijing China 	ibss_node_p = &sc->sc_ibss.ibss_node_tb[index];
654419d332feSfei feng - Sun Microsystems - Beijing China 
654519d332feSfei feng - Sun Microsystems - Beijing China 	ibss_node_p->used = 1;
654619d332feSfei feng - Sun Microsystems - Beijing China 
654719d332feSfei feng - Sun Microsystems - Beijing China 	(void) memset(&ibss_node_p->node, 0,
654819d332feSfei feng - Sun Microsystems - Beijing China 	    sizeof (iwk_add_sta_t));
654919d332feSfei feng - Sun Microsystems - Beijing China 
655019d332feSfei feng - Sun Microsystems - Beijing China 	IEEE80211_ADDR_COPY(ibss_node_p->node.bssid, addr);
655119d332feSfei feng - Sun Microsystems - Beijing China 	ibss_node_p->node.id = index;
655219d332feSfei feng - Sun Microsystems - Beijing China 	ibss_node_p->node.control = 0;
655319d332feSfei feng - Sun Microsystems - Beijing China 	ibss_node_p->node.flags = 0;
655419d332feSfei feng - Sun Microsystems - Beijing China 
655519d332feSfei feng - Sun Microsystems - Beijing China 	err = iwk_cmd(sc, REPLY_ADD_STA, &ibss_node_p->node,
655619d332feSfei feng - Sun Microsystems - Beijing China 	    sizeof (iwk_add_sta_t), 1);
655719d332feSfei feng - Sun Microsystems - Beijing China 	if (err != IWK_SUCCESS) {
655819d332feSfei feng - Sun Microsystems - Beijing China 		cmn_err(CE_WARN, "iwk_clean_add_node_ibss(): "
655919d332feSfei feng - Sun Microsystems - Beijing China 		    "failed to add IBSS node\n");
656019d332feSfei feng - Sun Microsystems - Beijing China 		ibss_node_p->used = 0;
656119d332feSfei feng - Sun Microsystems - Beijing China 		(void) memset(&ibss_node_p->node, 0,
656219d332feSfei feng - Sun Microsystems - Beijing China 		    sizeof (iwk_add_sta_t));
656319d332feSfei feng - Sun Microsystems - Beijing China 		return (err);
656419d332feSfei feng - Sun Microsystems - Beijing China 	}
656519d332feSfei feng - Sun Microsystems - Beijing China 
656619d332feSfei feng - Sun Microsystems - Beijing China 	sc->sc_ibss.node_number++;
656719d332feSfei feng - Sun Microsystems - Beijing China 
656819d332feSfei feng - Sun Microsystems - Beijing China 	(void) memset(&link_quality, 0, sizeof (link_quality));
656919d332feSfei feng - Sun Microsystems - Beijing China 
657019d332feSfei feng - Sun Microsystems - Beijing China 	rs = ic->ic_sup_rates[ieee80211_chan2mode(ic,
657119d332feSfei feng - Sun Microsystems - Beijing China 	    ic->ic_curchan)];
657219d332feSfei feng - Sun Microsystems - Beijing China 
657319d332feSfei feng - Sun Microsystems - Beijing China 	for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) {
657419d332feSfei feng - Sun Microsystems - Beijing China 		if (i < rs.ir_nrates) {
657519d332feSfei feng - Sun Microsystems - Beijing China 			rate = rs.
657619d332feSfei feng - Sun Microsystems - Beijing China 			    ir_rates[rs.ir_nrates - i];
657719d332feSfei feng - Sun Microsystems - Beijing China 		} else {
657819d332feSfei feng - Sun Microsystems - Beijing China 			rate = 2;
657919d332feSfei feng - Sun Microsystems - Beijing China 		}
658019d332feSfei feng - Sun Microsystems - Beijing China 
658119d332feSfei feng - Sun Microsystems - Beijing China 		if (2 == rate || 4 == rate ||
658219d332feSfei feng - Sun Microsystems - Beijing China 		    11 == rate || 22 == rate) {
658319d332feSfei feng - Sun Microsystems - Beijing China 			masks |= RATE_MCS_CCK_MSK;
658419d332feSfei feng - Sun Microsystems - Beijing China 		}
658519d332feSfei feng - Sun Microsystems - Beijing China 
658619d332feSfei feng - Sun Microsystems - Beijing China 		masks |= RATE_MCS_ANT_B_MSK;
658719d332feSfei feng - Sun Microsystems - Beijing China 		masks &= ~RATE_MCS_ANT_A_MSK;
658819d332feSfei feng - Sun Microsystems - Beijing China 
658919d332feSfei feng - Sun Microsystems - Beijing China 		link_quality.rate_n_flags[i] =
6590b510adaeSfei feng - Sun Microsystems - Beijing China 		    LE_32(iwk_rate_to_plcp(rate) | masks);
659119d332feSfei feng - Sun Microsystems - Beijing China 	}
659219d332feSfei feng - Sun Microsystems - Beijing China 
659319d332feSfei feng - Sun Microsystems - Beijing China 	link_quality.general_params.single_stream_ant_msk = 2;
659419d332feSfei feng - Sun Microsystems - Beijing China 	link_quality.general_params.dual_stream_ant_msk = 3;
659519d332feSfei feng - Sun Microsystems - Beijing China 	link_quality.agg_params.agg_dis_start_th = 3;
659619d332feSfei feng - Sun Microsystems - Beijing China 	link_quality.agg_params.agg_time_limit = LE_16(4000);
659719d332feSfei feng - Sun Microsystems - Beijing China 	link_quality.sta_id = ibss_node_p->node.id;
659819d332feSfei feng - Sun Microsystems - Beijing China 
659919d332feSfei feng - Sun Microsystems - Beijing China 	err = iwk_cmd(sc, REPLY_TX_LINK_QUALITY_CMD,
660019d332feSfei feng - Sun Microsystems - Beijing China 	    &link_quality, sizeof (link_quality), 1);
660119d332feSfei feng - Sun Microsystems - Beijing China 	if (err != IWK_SUCCESS) {
660219d332feSfei feng - Sun Microsystems - Beijing China 		cmn_err(CE_WARN, "iwk_clean_add_node_ibss(): "
660319d332feSfei feng - Sun Microsystems - Beijing China 		    "failed to set up TX link quality\n");
660419d332feSfei feng - Sun Microsystems - Beijing China 		ibss_node_p->used = 0;
660519d332feSfei feng - Sun Microsystems - Beijing China 		(void) memset(ibss_node_p->node.bssid, 0, 6);
660619d332feSfei feng - Sun Microsystems - Beijing China 		return (err);
660719d332feSfei feng - Sun Microsystems - Beijing China 	}
660819d332feSfei feng - Sun Microsystems - Beijing China 
660919d332feSfei feng - Sun Microsystems - Beijing China 	*index2 = index;
661019d332feSfei feng - Sun Microsystems - Beijing China 
661119d332feSfei feng - Sun Microsystems - Beijing China 	return (err);
661219d332feSfei feng - Sun Microsystems - Beijing China }
6613