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