aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/iwlwifi')
-rw-r--r--drivers/net/wireless/iwlwifi/Kconfig2
-rw-r--r--drivers/net/wireless/iwlwifi/Makefile29
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-hw.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965-commands.h50
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965-hw.h22
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965-rs.c65
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965.c373
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965.h41
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.c13
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.h32
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debugfs.c73
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-hcmd.c1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-rfkill.c3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-rfkill.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-sta.c355
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-sta.h49
-rw-r--r--drivers/net/wireless/iwlwifi/iwl3945-base.c6
-rw-r--r--drivers/net/wireless/iwlwifi/iwl4965-base.c575
19 files changed, 1008 insertions, 687 deletions
diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig
index bcaa61b7c563..f844b738d34e 100644
--- a/drivers/net/wireless/iwlwifi/Kconfig
+++ b/drivers/net/wireless/iwlwifi/Kconfig
@@ -6,7 +6,7 @@ config IWLWIFI_LEDS
bool
default n
-config IWLCORE_RFKILL
+config IWLWIFI_RFKILL
boolean "IWLWIFI RF kill support"
depends on IWLCORE
select RFKILL
diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile
index 2751e8aa97d7..4f3e88b12e3a 100644
--- a/drivers/net/wireless/iwlwifi/Makefile
+++ b/drivers/net/wireless/iwlwifi/Makefile
@@ -1,26 +1,13 @@
-obj-$(CONFIG_IWLCORE) += iwlcore.o
-iwlcore-objs = iwl-core.o iwl-eeprom.o iwl-hcmd.o
-
-ifeq ($(CONFIG_IWLWIFI_DEBUGFS),y)
- iwlcore-objs += iwl-debugfs.o
-endif
-
-ifeq ($(CONFIG_IWLWIFI_LEDS),y)
- iwlcore-objs += iwl-led.o
-endif
-
-ifeq ($(CONFIG_IWLCORE_RFKILL),y)
- iwlcore-objs += iwl-rfkill.o
-endif
+obj-$(CONFIG_IWLCORE) := iwlcore.o
+iwlcore-objs := iwl-core.o iwl-eeprom.o iwl-hcmd.o
+iwlcore-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o
+iwlcore-$(CONFIG_IWLWIFI_LEDS) += iwl-led.o
+iwlcore-$(CONFIG_IWLWIFI_RFKILL) += iwl-rfkill.o
obj-$(CONFIG_IWL3945) += iwl3945.o
-iwl3945-objs = iwl3945-base.o iwl-3945.o iwl-3945-rs.o
-
-ifeq ($(CONFIG_IWL3945_LEDS),y)
- iwl3945-objs += iwl-3945-led.o
-endif
-
+iwl3945-objs := iwl3945-base.o iwl-3945.o iwl-3945-rs.o
+iwl3945-$(CONFIG_IWL3945_LEDS) += iwl-3945-led.o
obj-$(CONFIG_IWL4965) += iwl4965.o
-iwl4965-objs = iwl4965-base.o iwl-4965.o iwl-4965-rs.o
+iwl4965-objs := iwl4965-base.o iwl-4965.o iwl-4965-rs.o iwl-sta.o
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
index 368da9852aab..ad612a8719f4 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
@@ -456,7 +456,7 @@ struct iwl3945_eeprom {
/* Size of uCode instruction memory in bootstrap state machine */
#define IWL_MAX_BSM_SIZE ALM_RTC_INST_SIZE
-#define IWL_MAX_NUM_QUEUES 8
+#define IWL39_MAX_NUM_QUEUES 8
static inline int iwl3945_hw_valid_rtc_data_addr(u32 addr)
{
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h
index 3dc7f0fbf02f..45c1c5533bf0 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.h
@@ -687,6 +687,8 @@ enum {
#endif
+#define IWL_MAX_NUM_QUEUES IWL39_MAX_NUM_QUEUES
+
struct iwl3945_priv {
/* ieee device used by generic ieee processing code */
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-commands.h b/drivers/net/wireless/iwlwifi/iwl-4965-commands.h
index 7e36ecb27575..3bcd107e2d71 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965-commands.h
+++ b/drivers/net/wireless/iwlwifi/iwl-4965-commands.h
@@ -84,6 +84,9 @@ enum {
REPLY_REMOVE_STA = 0x19, /* not used */
REPLY_REMOVE_ALL_STA = 0x1a, /* not used */
+ /* Security */
+ REPLY_WEPKEY = 0x20,
+
/* RX, TX, LEDs */
REPLY_TX = 0x1c,
REPLY_RATE_SCALE = 0x47, /* 3945 only */
@@ -266,11 +269,10 @@ struct iwl_cmd_header {
* 10 B active, A inactive
* 11 Both active
*/
-#define RATE_MCS_ANT_A_POS 14
-#define RATE_MCS_ANT_B_POS 15
-#define RATE_MCS_ANT_A_MSK 0x4000
-#define RATE_MCS_ANT_B_MSK 0x8000
-#define RATE_MCS_ANT_AB_MSK 0xc000
+#define RATE_MCS_ANT_POS 14
+#define RATE_MCS_ANT_A_MSK 0x04000
+#define RATE_MCS_ANT_B_MSK 0x08000
+#define RATE_MCS_ANT_AB_MSK 0x0C000
/**
@@ -850,6 +852,30 @@ struct iwl4965_add_sta_resp {
u8 status; /* ADD_STA_* */
} __attribute__ ((packed));
+/*
+ * REPLY_WEP_KEY = 0x20
+ */
+struct iwl_wep_key {
+ u8 key_index;
+ u8 key_offset;
+ u8 reserved1[2];
+ u8 key_size;
+ u8 reserved2[3];
+ u8 key[16];
+} __attribute__ ((packed));
+
+struct iwl_wep_cmd {
+ u8 num_keys;
+ u8 global_key_type;
+ u8 flags;
+ u8 reserved;
+ struct iwl_wep_key key[0];
+} __attribute__ ((packed));
+
+#define WEP_KEY_WEP_TYPE 1
+#define WEP_KEYS_MAX 4
+#define WEP_INVALID_OFFSET 0xff
+#define WEP_KEY_LEN_128 13
/******************************************************************************
* (4)
@@ -1387,11 +1413,11 @@ struct iwl4965_txpowertable_cmd {
/**
- * struct iwl4965_link_qual_general_params
+ * struct iwl_link_qual_general_params
*
* Used in REPLY_TX_LINK_QUALITY_CMD
*/
-struct iwl4965_link_qual_general_params {
+struct iwl_link_qual_general_params {
u8 flags;
/* No entries at or above this (driver chosen) index contain MIMO */
@@ -1418,11 +1444,11 @@ struct iwl4965_link_qual_general_params {
} __attribute__ ((packed));
/**
- * struct iwl4965_link_qual_agg_params
+ * struct iwl_link_qual_agg_params
*
* Used in REPLY_TX_LINK_QUALITY_CMD
*/
-struct iwl4965_link_qual_agg_params {
+struct iwl_link_qual_agg_params {
/* Maximum number of uSec in aggregation.
* Driver should set this to 4000 (4 milliseconds). */
@@ -1632,14 +1658,14 @@ struct iwl4965_link_qual_agg_params {
* legacy), and then repeat the search process.
*
*/
-struct iwl4965_link_quality_cmd {
+struct iwl_link_quality_cmd {
/* Index of destination/recipient station in uCode's station table */
u8 sta_id;
u8 reserved1;
__le16 control; /* not used */
- struct iwl4965_link_qual_general_params general_params;
- struct iwl4965_link_qual_agg_params agg_params;
+ struct iwl_link_qual_general_params general_params;
+ struct iwl_link_qual_agg_params agg_params;
/*
* Rate info; when using rate-scaling, Tx command's initial_rate_index
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
index de7bac149723..1a66b508a8ea 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
@@ -1385,10 +1385,10 @@ static inline __le32 iwl4965_hw_set_rate_n_flags(u8 rate, u16 flags)
* up to 7 DMA channels (FIFOs). Each Tx queue is supported by a circular array
* in DRAM containing 256 Transmit Frame Descriptors (TFDs).
*/
-#define IWL4965_MAX_WIN_SIZE 64
-#define IWL4965_QUEUE_SIZE 256
-#define IWL4965_NUM_FIFOS 7
-#define IWL_MAX_NUM_QUEUES 16
+#define IWL4965_MAX_WIN_SIZE 64
+#define IWL4965_QUEUE_SIZE 256
+#define IWL4965_NUM_FIFOS 7
+#define IWL4965_MAX_NUM_QUEUES 16
/**
@@ -1553,30 +1553,30 @@ struct iwl4965_sched_queue_byte_cnt_tbl {
*/
struct iwl4965_shared {
struct iwl4965_sched_queue_byte_cnt_tbl
- queues_byte_cnt_tbls[IWL_MAX_NUM_QUEUES];
- __le32 val0;
+ queues_byte_cnt_tbls[IWL4965_MAX_NUM_QUEUES];
+ __le32 rb_closed;
/* __le32 rb_closed_stts_rb_num:12; */
#define IWL_rb_closed_stts_rb_num_POS 0
#define IWL_rb_closed_stts_rb_num_LEN 12
-#define IWL_rb_closed_stts_rb_num_SYM val0
+#define IWL_rb_closed_stts_rb_num_SYM rb_closed
/* __le32 rsrv1:4; */
/* __le32 rb_closed_stts_rx_frame_num:12; */
#define IWL_rb_closed_stts_rx_frame_num_POS 16
#define IWL_rb_closed_stts_rx_frame_num_LEN 12
-#define IWL_rb_closed_stts_rx_frame_num_SYM val0
+#define IWL_rb_closed_stts_rx_frame_num_SYM rb_closed
/* __le32 rsrv2:4; */
- __le32 val1;
+ __le32 frm_finished;
/* __le32 frame_finished_stts_rb_num:12; */
#define IWL_frame_finished_stts_rb_num_POS 0
#define IWL_frame_finished_stts_rb_num_LEN 12
-#define IWL_frame_finished_stts_rb_num_SYM val1
+#define IWL_frame_finished_stts_rb_num_SYM frm_finished
/* __le32 rsrv3:4; */
/* __le32 frame_finished_stts_rx_frame_num:12; */
#define IWL_frame_finished_stts_rx_frame_num_POS 16
#define IWL_frame_finished_stts_rx_frame_num_LEN 12
-#define IWL_frame_finished_stts_rx_frame_num_SYM val1
+#define IWL_frame_finished_stts_rx_frame_num_SYM frm_finished
/* __le32 rsrv4:4; */
__le32 padding1; /* so that allocation will be aligned to 16B */
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c
index 315b0433801e..b608e1ca8b40 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c
@@ -150,7 +150,7 @@ struct iwl4965_lq_sta {
u16 active_mimo_rate;
u16 active_rate_basic;
- struct iwl4965_link_quality_cmd lq;
+ struct iwl_link_quality_cmd lq;
struct iwl4965_scale_tbl_info lq_info[LQ_SIZE]; /* "active", "search" */
#ifdef CONFIG_IWL4965_HT
struct iwl4965_traffic_load load[TID_MAX_LOAD_COUNT];
@@ -173,7 +173,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
struct sta_info *sta);
static void rs_fill_link_cmd(struct iwl4965_lq_sta *lq_sta,
struct iwl4965_rate *tx_mcs,
- struct iwl4965_link_quality_cmd *tbl);
+ struct iwl_link_quality_cmd *tbl);
#ifdef CONFIG_MAC80211_DEBUGFS
@@ -230,58 +230,11 @@ static s32 expected_tpt_mimo40MHzSGI[IWL_RATE_COUNT] = {
0, 0, 0, 0, 131, 131, 191, 222, 242, 270, 284, 289, 293
};
-static int iwl4965_lq_sync_callback(struct iwl_priv *priv,
- struct iwl_cmd *cmd, struct sk_buff *skb)
-{
- /*We didn't cache the SKB; let the caller free it */
- return 1;
-}
-
static inline u8 iwl4965_rate_get_rate(u32 rate_n_flags)
{
return (u8)(rate_n_flags & 0xFF);
}
-static int rs_send_lq_cmd(struct iwl_priv *priv,
- struct iwl4965_link_quality_cmd *lq, u8 flags)
-{
-#ifdef CONFIG_IWLWIFI_DEBUG
- int i;
-#endif
- struct iwl_host_cmd cmd = {
- .id = REPLY_TX_LINK_QUALITY_CMD,
- .len = sizeof(struct iwl4965_link_quality_cmd),
- .meta.flags = flags,
- .data = lq,
- };
-
- if ((lq->sta_id == 0xFF) &&
- (priv->iw_mode == IEEE80211_IF_TYPE_IBSS))
- return -EINVAL;
-
- if (lq->sta_id == 0xFF)
- lq->sta_id = IWL_AP_ID;
-
- IWL_DEBUG_RATE("lq station id 0x%x\n", lq->sta_id);
- IWL_DEBUG_RATE("lq dta 0x%X 0x%X\n",
- lq->general_params.single_stream_ant_msk,
- lq->general_params.dual_stream_ant_msk);
-#ifdef CONFIG_IWLWIFI_DEBUG
- for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++)
- IWL_DEBUG_RATE("lq index %d 0x%X\n",
- i, lq->rs_table[i].rate_n_flags);
-#endif
-
- if (flags & CMD_ASYNC)
- cmd.meta.u.callback = iwl4965_lq_sync_callback;
-
- if (iwl_is_associated(priv) && priv->assoc_station_added &&
- priv->lq_mngr.lq_ready)
- return iwl_send_cmd(priv, &cmd);
-
- return 0;
-}
-
static void rs_rate_scale_clear_window(struct iwl4965_rate_scale_data *window)
{
window->data = 0;
@@ -819,7 +772,7 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev,
u8 retries;
int rs_index, index = 0;
struct iwl4965_lq_sta *lq_sta;
- struct iwl4965_link_quality_cmd *table;
+ struct iwl_link_quality_cmd *table;
struct sta_info *sta;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct iwl_priv *priv = (struct iwl_priv *)priv_rate;
@@ -1879,7 +1832,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
if (update_lq) {
rs_mcs_from_tbl(&mcs_rate, tbl, index, is_green);
rs_fill_link_cmd(lq_sta, &mcs_rate, &lq_sta->lq);
- rs_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC);
+ iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC);
}
goto out;
@@ -2044,7 +1997,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
if (update_lq) {
rs_mcs_from_tbl(&mcs_rate, tbl, index, is_green);
rs_fill_link_cmd(lq_sta, &mcs_rate, &lq_sta->lq);
- rs_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC);
+ iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC);
}
/* Should we stay with this modulation mode, or search for a new one? */
@@ -2084,7 +2037,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
tbl->current_rate.rate_n_flags, index);
rs_fill_link_cmd(lq_sta, &tbl->current_rate,
&lq_sta->lq);
- rs_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC);
+ iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC);
}
/* If the "active" (non-search) mode was legacy,
@@ -2197,7 +2150,7 @@ static void rs_initialize_lq(struct iwl_priv *priv,
tbl->current_rate.rate_n_flags = mcs_rate.rate_n_flags;
rs_get_expected_tpt_table(lq_sta, tbl);
rs_fill_link_cmd(lq_sta, &mcs_rate, &lq_sta->lq);
- rs_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC);
+ iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC);
out:
return;
}
@@ -2392,7 +2345,7 @@ static void rs_rate_init(void *priv_rate, void *priv_sta,
static void rs_fill_link_cmd(struct iwl4965_lq_sta *lq_sta,
struct iwl4965_rate *tx_mcs,
- struct iwl4965_link_quality_cmd *lq_cmd)
+ struct iwl_link_quality_cmd *lq_cmd)
{
int index = 0;
int rate_idx;
@@ -2591,7 +2544,7 @@ static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file,
if (lq_sta->dbg_fixed.rate_n_flags) {
rs_fill_link_cmd(lq_sta, &lq_sta->dbg_fixed, &lq_sta->lq);
- rs_send_lq_cmd(lq_sta->drv, &lq_sta->lq, CMD_ASYNC);
+ iwl_send_lq_cmd(lq_sta->drv, &lq_sta->lq, CMD_ASYNC);
}
return count;
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index 472ca3d7e034..17f629fb96ff 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -46,7 +46,7 @@
/* module parameters */
static struct iwl_mod_params iwl4965_mod_params = {
- .num_of_queues = IWL_MAX_NUM_QUEUES,
+ .num_of_queues = IWL4965_MAX_NUM_QUEUES,
.enable_qos = 1,
.amsdu_size_8K = 1,
/* the rest are 0 by default */
@@ -114,6 +114,151 @@ static const u16 default_tid_to_tx_fifo[] = {
#endif /*CONFIG_IWL4965_HT */
+/* check contents of special bootstrap uCode SRAM */
+static int iwl4965_verify_bsm(struct iwl_priv *priv)
+{
+ __le32 *image = priv->ucode_boot.v_addr;
+ u32 len = priv->ucode_boot.len;
+ u32 reg;
+ u32 val;
+
+ IWL_DEBUG_INFO("Begin verify bsm\n");
+
+ /* verify BSM SRAM contents */
+ val = iwl_read_prph(priv, BSM_WR_DWCOUNT_REG);
+ for (reg = BSM_SRAM_LOWER_BOUND;
+ reg < BSM_SRAM_LOWER_BOUND + len;
+ reg += sizeof(u32), image++) {
+ val = iwl_read_prph(priv, reg);
+ if (val != le32_to_cpu(*image)) {
+ IWL_ERROR("BSM uCode verification failed at "
+ "addr 0x%08X+%u (of %u), is 0x%x, s/b 0x%x\n",
+ BSM_SRAM_LOWER_BOUND,
+ reg - BSM_SRAM_LOWER_BOUND, len,
+ val, le32_to_cpu(*image));
+ return -EIO;
+ }
+ }
+
+ IWL_DEBUG_INFO("BSM bootstrap uCode image OK\n");
+
+ return 0;
+}
+
+/**
+ * iwl4965_load_bsm - Load bootstrap instructions
+ *
+ * BSM operation:
+ *
+ * The Bootstrap State Machine (BSM) stores a short bootstrap uCode program
+ * in special SRAM that does not power down during RFKILL. When powering back
+ * up after power-saving sleeps (or during initial uCode load), the BSM loads
+ * the bootstrap program into the on-board processor, and starts it.
+ *
+ * The bootstrap program loads (via DMA) instructions and data for a new
+ * program from host DRAM locations indicated by the host driver in the
+ * BSM_DRAM_* registers. Once the new program is loaded, it starts
+ * automatically.
+ *
+ * When initializing the NIC, the host driver points the BSM to the
+ * "initialize" uCode image. This uCode sets up some internal data, then
+ * notifies host via "initialize alive" that it is complete.
+ *
+ * The host then replaces the BSM_DRAM_* pointer values to point to the
+ * normal runtime uCode instructions and a backup uCode data cache buffer
+ * (filled initially with starting data values for the on-board processor),
+ * then triggers the "initialize" uCode to load and launch the runtime uCode,
+ * which begins normal operation.
+ *
+ * When doing a power-save shutdown, runtime uCode saves data SRAM into
+ * the backup data cache in DRAM before SRAM is powered down.
+ *
+ * When powering back up, the BSM loads the bootstrap program. This reloads
+ * the runtime uCode instructions and the backup data cache into SRAM,
+ * and re-launches the runtime uCode from where it left off.
+ */
+static int iwl4965_load_bsm(struct iwl_priv *priv)
+{
+ __le32 *image = priv->ucode_boot.v_addr;
+ u32 len = priv->ucode_boot.len;
+ dma_addr_t pinst;
+ dma_addr_t pdata;
+ u32 inst_len;
+ u32 data_len;
+ int i;
+ u32 done;
+ u32 reg_offset;
+ int ret;
+
+ IWL_DEBUG_INFO("Begin load bsm\n");
+
+ /* make sure bootstrap program is no larger than BSM's SRAM size */
+ if (len > IWL_MAX_BSM_SIZE)
+ return -EINVAL;
+
+ /* Tell bootstrap uCode where to find the "Initialize" uCode
+ * in host DRAM ... host DRAM physical address bits 35:4 for 4965.
+ * NOTE: iwl4965_initialize_alive_start() will replace these values,
+ * after the "initialize" uCode has run, to point to
+ * runtime/protocol instructions and backup data cache. */
+ pinst = priv->ucode_init.p_addr >> 4;
+ pdata = priv->ucode_init_data.p_addr >> 4;
+ inst_len = priv->ucode_init.len;
+ data_len = priv->ucode_init_data.len;
+
+ ret = iwl_grab_nic_access(priv);
+ if (ret)
+ return ret;
+
+ iwl_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst);
+ iwl_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata);
+ iwl_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG, inst_len);
+ iwl_write_prph(priv, BSM_DRAM_DATA_BYTECOUNT_REG, data_len);
+
+ /* Fill BSM memory with bootstrap instructions */
+ for (reg_offset = BSM_SRAM_LOWER_BOUND;
+ reg_offset < BSM_SRAM_LOWER_BOUND + len;
+ reg_offset += sizeof(u32), image++)
+ _iwl_write_prph(priv, reg_offset, le32_to_cpu(*image));
+
+ ret = iwl4965_verify_bsm(priv);
+ if (ret) {
+ iwl_release_nic_access(priv);
+ return ret;
+ }
+
+ /* Tell BSM to copy from BSM SRAM into instruction SRAM, when asked */
+ iwl_write_prph(priv, BSM_WR_MEM_SRC_REG, 0x0);
+ iwl_write_prph(priv, BSM_WR_MEM_DST_REG, RTC_INST_LOWER_BOUND);
+ iwl_write_prph(priv, BSM_WR_DWCOUNT_REG, len / sizeof(u32));
+
+ /* Load bootstrap code into instruction SRAM now,
+ * to prepare to load "initialize" uCode */
+ iwl_write_prph(priv, BSM_WR_CTRL_REG, BSM_WR_CTRL_REG_BIT_START);
+
+ /* Wait for load of bootstrap uCode to finish */
+ for (i = 0; i < 100; i++) {
+ done = iwl_read_prph(priv, BSM_WR_CTRL_REG);
+ if (!(done & BSM_WR_CTRL_REG_BIT_START))
+ break;
+ udelay(10);
+ }
+ if (i < 100)
+ IWL_DEBUG_INFO("BSM write complete, poll %d iterations\n", i);
+ else {
+ IWL_ERROR("BSM write did not complete!\n");
+ return -EIO;
+ }
+
+ /* Enable future boot loads whenever power management unit triggers it
+ * (e.g. when powering back up after power-save shutdown) */
+ iwl_write_prph(priv, BSM_WR_CTRL_REG, BSM_WR_CTRL_REG_BIT_START_EN);
+
+ iwl_release_nic_access(priv);
+
+ return 0;
+}
+
static int iwl4965_init_drv(struct iwl_priv *priv)
{
int ret;
@@ -129,6 +274,18 @@ static int iwl4965_init_drv(struct iwl_priv *priv)
spin_lock_init(&priv->hcmd_lock);
spin_lock_init(&priv->lq_mngr.lock);
+ priv->shared_virt = pci_alloc_consistent(priv->pci_dev,
+ sizeof(struct iwl4965_shared),
+ &priv->shared_phys);
+
+ if (!priv->shared_virt) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ memset(priv->shared_virt, 0, sizeof(struct iwl4965_shared));
+
+
for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++)
INIT_LIST_HEAD(&priv->ibss_mac_hash[i]);
@@ -253,7 +410,7 @@ void iwl4965_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags,
int rate_index;
control->antenna_sel_tx =
- ((rate_n_flags & RATE_MCS_ANT_AB_MSK) >> RATE_MCS_ANT_A_POS);
+ ((rate_n_flags & RATE_MCS_ANT_AB_MSK) >> RATE_MCS_ANT_POS);
if (rate_n_flags & RATE_MCS_HT_MSK)
control->flags |= IEEE80211_TXCTL_OFDM_HT;
if (rate_n_flags & RATE_MCS_GF_MSK)
@@ -347,10 +504,10 @@ u8 iwl4965_hw_find_station(struct iwl_priv *priv, const u8 *addr)
start = IWL_STA_ID;
if (is_broadcast_ether_addr(addr))
- return priv->hw_setting.bcast_sta_id;
+ return priv->hw_params.bcast_sta_id;
spin_lock_irqsave(&priv->sta_lock, flags);
- for (i = start; i < priv->hw_setting.max_stations; i++)
+ for (i = start; i < priv->hw_params.max_stations; i++)
if ((priv->stations[i].used) &&
(!compare_ether_addr
(priv->stations[i].sta.sta.addr, addr))) {
@@ -401,15 +558,15 @@ static int iwl4965_nic_set_pwr_src(struct iwl_priv *priv, int pwr_max)
static int iwl4965_rx_init(struct iwl_priv *priv, struct iwl4965_rx_queue *rxq)
{
- int rc;
+ int ret;
unsigned long flags;
unsigned int rb_size;
spin_lock_irqsave(&priv->lock, flags);
- rc = iwl_grab_nic_access(priv);
- if (rc) {
+ ret = iwl_grab_nic_access(priv);
+ if (ret) {
spin_unlock_irqrestore(&priv->lock, flags);
- return rc;
+ return ret;
}
if (priv->cfg->mod_params->amsdu_size_8K)
@@ -429,15 +586,15 @@ static int iwl4965_rx_init(struct iwl_priv *priv, struct iwl4965_rx_queue *rxq)
/* Tell device where in DRAM to update its Rx status */
iwl_write_direct32(priv, FH_RSCSR_CHNL0_STTS_WPTR_REG,
- (priv->hw_setting.shared_phys +
- offsetof(struct iwl4965_shared, val0)) >> 4);
+ (priv->shared_phys +
+ offsetof(struct iwl4965_shared, rb_closed)) >> 4);
/* Enable Rx DMA, enable host interrupt, Rx buffer size 4k, 256 RBDs */
iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG,
FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL |
FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL |
rb_size |
- /*0x10 << 4 | */
+ /* 0x10 << 4 | */
(RX_QUEUE_SIZE_LOG <<
FH_RCSR_RX_CONFIG_RBDCB_SIZE_BITSHIFT));
@@ -545,7 +702,7 @@ static int iwl4965_txq_ctx_reset(struct iwl_priv *priv)
/* Alloc and init all (default 16) Tx queues,
* including the command queue (#4) */
- for (txq_id = 0; txq_id < priv->hw_setting.max_txq_num; txq_id++) {
+ for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ?
TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
rc = iwl4965_tx_queue_init(priv, &priv->txq[txq_id], slots_num,
@@ -751,7 +908,7 @@ void iwl4965_hw_txq_ctx_stop(struct iwl_priv *priv)
unsigned long flags;
/* Stop each Tx DMA channel, and wait for it to be idle */
- for (txq_id = 0; txq_id < priv->hw_setting.max_txq_num; txq_id++) {
+ for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
spin_lock_irqsave(&priv->lock, flags);
if (iwl_grab_nic_access(priv)) {
spin_unlock_irqrestore(&priv->lock, flags);
@@ -819,40 +976,21 @@ int iwl4965_hw_nic_reset(struct iwl_priv *priv)
/**
* iwl4965_bg_statistics_periodic - Timer callback to queue statistics
*
- * This callback is provided in order to queue the statistics_work
- * in work_queue context (v. softirq)
+ * This callback is provided in order to send a statistics request.
*
* This timer function is continually reset to execute within
* REG_RECALIB_PERIOD seconds since the last STATISTICS_NOTIFICATION
* was received. We need to ensure we receive the statistics in order
- * to update the temperature used for calibrating the TXPOWER. However,
- * we can't send the statistics command from softirq context (which
- * is the context which timers run at) so we have to queue off the
- * statistics_work to actually send the command to the hardware.
+ * to update the temperature used for calibrating the TXPOWER.
*/
static void iwl4965_bg_statistics_periodic(unsigned long data)
{
struct iwl_priv *priv = (struct iwl_priv *)data;
- queue_work(priv->workqueue, &priv->statistics_work);
-}
-
-/**
- * iwl4965_bg_statistics_work - Send the statistics request to the hardware.
- *
- * This is queued by iwl4965_bg_statistics_periodic.
- */
-static void iwl4965_bg_statistics_work(struct work_struct *work)
-{
- struct iwl_priv *priv = container_of(work, struct iwl_priv,
- statistics_work);
-
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
return;
- mutex_lock(&priv->mutex);
- iwl4965_send_statistics_request(priv);
- mutex_unlock(&priv->mutex);
+ iwl_send_statistics_request(priv, CMD_ASYNC);
}
#define CT_LIMIT_CONST 259
@@ -1816,19 +1954,19 @@ int iwl4965_alive_notify(struct iwl_priv *priv)
iwl_write_targ_mem(priv, a, 0);
for (; a < priv->scd_base_addr + SCD_TRANSLATE_TBL_OFFSET; a += 4)
iwl_write_targ_mem(priv, a, 0);
- for (; a < sizeof(u16) * priv->hw_setting.max_txq_num; a += 4)
+ for (; a < sizeof(u16) * priv->hw_params.max_txq_num; a += 4)
iwl_write_targ_mem(priv, a, 0);
/* Tel 4965 where to find Tx byte count tables */
iwl_write_prph(priv, IWL49_SCD_DRAM_BASE_ADDR,
- (priv->hw_setting.shared_phys +
+ (priv->shared_phys +
offsetof(struct iwl4965_shared, queues_byte_cnt_tbls)) >> 10);
/* Disable chain mode for all queues */
iwl_write_prph(priv, IWL49_SCD_QUEUECHAIN_SEL, 0);
/* Initialize each Tx queue (including the command queue) */
- for (i = 0; i < priv->hw_setting.max_txq_num; i++) {
+ for (i = 0; i < priv->hw_params.max_txq_num; i++) {
/* TFD circular buffer read/write indexes */
iwl_write_prph(priv, IWL49_SCD_QUEUE_RDPTR(i), 0);
@@ -1851,7 +1989,7 @@ int iwl4965_alive_notify(struct iwl_priv *priv)
}
iwl_write_prph(priv, IWL49_SCD_INTERRUPT_MASK,
- (1 << priv->hw_setting.max_txq_num) - 1);
+ (1 << priv->hw_params.max_txq_num) - 1);
/* Activate all Tx DMA/FIFO channels */
iwl_write_prph(priv, IWL49_SCD_TXFACT,
@@ -1869,55 +2007,45 @@ int iwl4965_alive_notify(struct iwl_priv *priv)
iwl_release_nic_access(priv);
spin_unlock_irqrestore(&priv->lock, flags);
+ /* Ask for statistics now, the uCode will send statistics notification
+ * periodically after association */
+ iwl_send_statistics_request(priv, CMD_ASYNC);
return ret;
}
/**
- * iwl4965_hw_set_hw_setting
+ * iwl4965_hw_set_hw_params
*
* Called when initializing driver
*/
-int iwl4965_hw_set_hw_setting(struct iwl_priv *priv)
+int iwl4965_hw_set_hw_params(struct iwl_priv *priv)
{
- int ret = 0;
- if ((priv->cfg->mod_params->num_of_queues > IWL_MAX_NUM_QUEUES) ||
+ if ((priv->cfg->mod_params->num_of_queues > IWL4965_MAX_NUM_QUEUES) ||
(priv->cfg->mod_params->num_of_queues < IWL_MIN_NUM_QUEUES)) {
IWL_ERROR("invalid queues_num, should be between %d and %d\n",
- IWL_MIN_NUM_QUEUES, IWL_MAX_NUM_QUEUES);
- ret = -EINVAL;
- goto out;
- }
-
- /* Allocate area for Tx byte count tables and Rx queue status */
- priv->hw_setting.shared_virt =
- pci_alloc_consistent(priv->pci_dev,
- sizeof(struct iwl4965_shared),
- &priv->hw_setting.shared_phys);
-
- if (!priv->hw_setting.shared_virt) {
- ret = -ENOMEM;
- goto out;
+ IWL_MIN_NUM_QUEUES, IWL4965_MAX_NUM_QUEUES);
+ return -EINVAL;
}
- memset(priv->hw_setting.shared_virt, 0, sizeof(struct iwl4965_shared));
-
- priv->hw_setting.max_txq_num = priv->cfg->mod_params->num_of_queues;
- priv->hw_setting.tx_cmd_len = sizeof(struct iwl4965_tx_cmd);
- priv->hw_setting.max_rxq_size = RX_QUEUE_SIZE;
- priv->hw_setting.max_rxq_log = RX_QUEUE_SIZE_LOG;
+ priv->hw_params.max_txq_num = priv->cfg->mod_params->num_of_queues;
+ priv->hw_params.tx_cmd_len = sizeof(struct iwl4965_tx_cmd);
+ priv->hw_params.max_rxq_size = RX_QUEUE_SIZE;
+ priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG;
if (priv->cfg->mod_params->amsdu_size_8K)
- priv->hw_setting.rx_buf_size = IWL_RX_BUF_SIZE_8K;
+ priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_8K;
else
- priv->hw_setting.rx_buf_size = IWL_RX_BUF_SIZE_4K;
- priv->hw_setting.max_pkt_size = priv->hw_setting.rx_buf_size - 256;
- priv->hw_setting.max_stations = IWL4965_STATION_COUNT;
- priv->hw_setting.bcast_sta_id = IWL4965_BROADCAST_ID;
+ priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_4K;
+ priv->hw_params.max_pkt_size = priv->hw_params.rx_buf_size - 256;
+ priv->hw_params.max_stations = IWL4965_STATION_COUNT;
+ priv->hw_params.bcast_sta_id = IWL4965_BROADCAST_ID;
- priv->hw_setting.tx_ant_num = 2;
+ priv->hw_params.tx_chains_num = 2;
+ priv->hw_params.rx_chains_num = 2;
+ priv->hw_params.valid_tx_ant = (IWL_ANTENNA_MAIN | IWL_ANTENNA_AUX);
+ priv->hw_params.valid_rx_ant = (IWL_ANTENNA_MAIN | IWL_ANTENNA_AUX);
-out:
- return ret;
+ return 0;
}
/**
@@ -1930,7 +2058,7 @@ void iwl4965_hw_txq_ctx_free(struct iwl_priv *priv)
int txq_id;
/* Tx queues */
- for (txq_id = 0; txq_id < priv->hw_setting.max_txq_num; txq_id++)
+ for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)
iwl4965_tx_queue_free(priv, &priv->txq[txq_id]);
/* Keep-warm buffer */
@@ -2756,6 +2884,46 @@ out:
return ret;
}
+static int iwl4965_send_rxon_assoc(struct iwl_priv *priv)
+{
+ int ret = 0;
+ struct iwl4965_rxon_assoc_cmd rxon_assoc;
+ const struct iwl4965_rxon_cmd *rxon1 = &priv->staging_rxon;
+ const struct iwl4965_rxon_cmd *rxon2 = &priv->active_rxon;
+
+ if ((rxon1->flags == rxon2->flags) &&
+ (rxon1->filter_flags == rxon2->filter_flags) &&
+ (rxon1->cck_basic_rates == rxon2->cck_basic_rates) &&
+ (rxon1->ofdm_ht_single_stream_basic_rates ==
+ rxon2->ofdm_ht_single_stream_basic_rates) &&
+ (rxon1->ofdm_ht_dual_stream_basic_rates ==
+ rxon2->ofdm_ht_dual_stream_basic_rates) &&
+ (rxon1->rx_chain == rxon2->rx_chain) &&
+ (rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates)) {
+ IWL_DEBUG_INFO("Using current RXON_ASSOC. Not resending.\n");
+ return 0;
+ }
+
+ rxon_assoc.flags = priv->staging_rxon.flags;
+ rxon_assoc.filter_flags = priv->staging_rxon.filter_flags;
+ rxon_assoc.ofdm_basic_rates = priv->staging_rxon.ofdm_basic_rates;
+ rxon_assoc.cck_basic_rates = priv->staging_rxon.cck_basic_rates;
+ rxon_assoc.reserved = 0;
+ rxon_assoc.ofdm_ht_single_stream_basic_rates =
+ priv->staging_rxon.ofdm_ht_single_stream_basic_rates;
+ rxon_assoc.ofdm_ht_dual_stream_basic_rates =
+ priv->staging_rxon.ofdm_ht_dual_stream_basic_rates;
+ rxon_assoc.rx_chain_select_flags = priv->staging_rxon.rx_chain;
+
+ ret = iwl_send_cmd_pdu_async(priv, REPLY_RXON_ASSOC,
+ sizeof(rxon_assoc), &rxon_assoc, NULL);
+ if (ret)
+ return ret;
+
+ return ret;
+}
+
+
int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel)
{
int rc;
@@ -2869,9 +3037,8 @@ void iwl4965_hw_build_tx_cmd_rate(struct iwl_priv *priv,
int iwl4965_hw_get_rx_read(struct iwl_priv *priv)
{
- struct iwl4965_shared *shared_data = priv->hw_setting.shared_virt;
-
- return IWL_GET_BITS(*shared_data, rb_closed_stts_rb_num);
+ struct iwl4965_shared *s = priv->shared_virt;
+ return le32_to_cpu(s->rb_closed) & 0xFFF;
}
int iwl4965_hw_get_temperature(struct iwl_priv *priv)
@@ -2888,7 +3055,7 @@ unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv,
tx_beacon_cmd = &frame->u.beacon;
memset(tx_beacon_cmd, 0, sizeof(*tx_beacon_cmd));
- tx_beacon_cmd->tx.sta_id = priv->hw_setting.bcast_sta_id;
+ tx_beacon_cmd->tx.sta_id = priv->hw_params.bcast_sta_id;
tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
frame_size = iwl4965_fill_beacon_frame(priv,
@@ -2996,17 +3163,15 @@ static void iwl4965_hw_card_show_info(struct iwl_priv *priv)
#define IWL_TX_DELIMITER_SIZE 4
/**
- * iwl4965_tx_queue_update_wr_ptr - Set up entry in Tx byte-count array
+ * iwl4965_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array
*/
-int iwl4965_tx_queue_update_wr_ptr(struct iwl_priv *priv,
- struct iwl4965_tx_queue *txq, u16 byte_cnt)
+static void iwl4965_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
+ struct iwl4965_tx_queue *txq,
+ u16 byte_cnt)
{
int len;
int txq_id = txq->q.id;
- struct iwl4965_shared *shared_data = priv->hw_setting.shared_virt;
-
- if (txq->need_update == 0)
- return 0;
+ struct iwl4965_shared *shared_data = priv->shared_virt;
len = byte_cnt + IWL_TX_CRC_SIZE + IWL_TX_DELIMITER_SIZE;
@@ -3019,8 +3184,6 @@ int iwl4965_tx_queue_update_wr_ptr(struct iwl_priv *priv,
IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id].
tfd_offset[IWL4965_QUEUE_SIZE + txq->q.write_ptr],
byte_cnt, len);
-
- return 0;
}
/**
@@ -3500,7 +3663,7 @@ static void iwl4965_handle_data_packet(struct iwl_priv *priv, int is_data,
rx_start->byte_count = amsdu->byte_count;
rx_end = (__le32 *) (((u8 *) hdr) + len);
}
- if (len > priv->hw_setting.max_pkt_size || len < 16) {
+ if (len > priv->hw_params.max_pkt_size || len < 16) {
IWL_WARNING("byte count out of range [16,4K] : %d\n", len);
return;
}
@@ -3528,7 +3691,7 @@ static void iwl4965_handle_data_packet(struct iwl_priv *priv, int is_data,
stats->flag = 0;
hdr = (struct ieee80211_hdr *)rxb->skb->data;
- if (priv->cfg->mod_params->hw_crypto)
+ if (!priv->cfg->mod_params->sw_crypto)
iwl4965_set_decrypted_flag(priv, rxb->skb, ampdu_status, stats);
if (priv->add_radiotap)
@@ -4199,7 +4362,7 @@ static void iwl4965_rx_reply_compressed_ba(struct iwl_priv *priv,
* (in Tx queue's circular buffer) of first TFD/frame in window */
u16 ba_resp_scd_ssn = le16_to_cpu(ba_resp->scd_ssn);
- if (scd_flow >= ARRAY_SIZE(priv->txq)) {
+ if (scd_flow >= priv->hw_params.max_txq_num) {
IWL_ERROR("BUG_ON scd_flow is bigger than number of queues");
return;
}
@@ -4361,7 +4524,7 @@ static int iwl4965_tx_queue_agg_enable(struct iwl_priv *priv, int txq_id,
void iwl4965_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap)
{
int i, r;
- struct iwl4965_link_quality_cmd link_cmd = {
+ struct iwl_link_quality_cmd link_cmd = {
.reserved1 = 0,
};
u16 rate_flags;
@@ -4395,7 +4558,7 @@ void iwl4965_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap)
link_cmd.agg_params.agg_time_limit = cpu_to_le16(4000);
/* Update the rate scaling for control frame Tx to AP */
- link_cmd.sta_id = is_ap ? IWL_AP_ID : priv->hw_setting.bcast_sta_id;
+ link_cmd.sta_id = is_ap ? IWL_AP_ID : priv->hw_params.bcast_sta_id;
iwl_send_cmd_pdu_async(priv, REPLY_TX_LINK_QUALITY_CMD,
sizeof(link_cmd), &link_cmd, NULL);
@@ -4584,7 +4747,7 @@ static int iwl4965_txq_ctx_activate_free(struct iwl_priv *priv)
{
int txq_id;
- for (txq_id = 0; txq_id < priv->hw_setting.max_txq_num; txq_id++)
+ for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)
if (!test_and_set_bit(txq_id, &priv->txq_ctx_active_msk))
return txq_id;
return -1;
@@ -4767,7 +4930,6 @@ void iwl4965_hw_rx_handler_setup(struct iwl_priv *priv)
void iwl4965_hw_setup_deferred_work(struct iwl_priv *priv)
{
INIT_WORK(&priv->txpower_work, iwl4965_bg_txpower_work);
- INIT_WORK(&priv->statistics_work, iwl4965_bg_statistics_work);
#ifdef CONFIG_IWL4965_SENSITIVITY
INIT_WORK(&priv->sensitivity_work, iwl4965_bg_sensitivity_work);
#endif
@@ -4783,12 +4945,23 @@ void iwl4965_hw_cancel_deferred_work(struct iwl_priv *priv)
cancel_delayed_work(&priv->init_alive_start);
}
+
+static struct iwl_hcmd_ops iwl4965_hcmd = {
+ .rxon_assoc = iwl4965_send_rxon_assoc,
+};
+
static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = {
.enqueue_hcmd = iwl4965_enqueue_hcmd,
};
static struct iwl_lib_ops iwl4965_lib = {
.init_drv = iwl4965_init_drv,
+ .set_hw_params = iwl4965_hw_set_hw_params,
+ .txq_update_byte_cnt_tbl = iwl4965_txq_update_byte_cnt_tbl,
+ .hw_nic_init = iwl4965_hw_nic_init,
+ .is_valid_rtc_data_addr = iwl4965_hw_valid_rtc_data_addr,
+ .alive_notify = iwl4965_alive_notify,
+ .load_ucode = iwl4965_load_bsm,
.eeprom_ops = {
.verify_signature = iwlcore_eeprom_verify_signature,
.acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
@@ -4799,10 +4972,11 @@ static struct iwl_lib_ops iwl4965_lib = {
static struct iwl_ops iwl4965_ops = {
.lib = &iwl4965_lib,
+ .hcmd = &iwl4965_hcmd,
.utils = &iwl4965_hcmd_utils,
};
-static struct iwl_cfg iwl4965_agn_cfg = {
+struct iwl_cfg iwl4965_agn_cfg = {
.name = "4965AGN",
.fw_name = "iwlwifi-4965" IWL4965_UCODE_API ".ucode",
.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
@@ -4810,21 +4984,12 @@ static struct iwl_cfg iwl4965_agn_cfg = {
.mod_params = &iwl4965_mod_params,
};
-struct pci_device_id iwl4965_hw_card_ids[] = {
- {IWL_PCI_DEVICE(0x4229, PCI_ANY_ID, iwl4965_agn_cfg)},
- {IWL_PCI_DEVICE(0x4230, PCI_ANY_ID, iwl4965_agn_cfg)},
- {0}
-};
-
-MODULE_DEVICE_TABLE(pci, iwl4965_hw_card_ids);
-
module_param_named(antenna, iwl4965_mod_params.antenna, int, 0444);
MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])");
module_param_named(disable, iwl4965_mod_params.disable, int, 0444);
MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])");
-module_param_named(hwcrypto, iwl4965_mod_params.hw_crypto, int, 0444);
-MODULE_PARM_DESC(hwcrypto,
- "using hardware crypto engine (default 0 [software])\n");
+module_param_named(swcrypto, iwl4965_mod_params.sw_crypto, int, 0444);
+MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])\n");
module_param_named(debug, iwl4965_mod_params.debug, int, 0444);
MODULE_PARM_DESC(debug, "debug output mask");
module_param_named(
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.h b/drivers/net/wireless/iwlwifi/iwl-4965.h
index 65e536782706..9ed13cb0a2a9 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.h
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.h
@@ -36,9 +36,6 @@
#include <linux/kernel.h>
#include <net/ieee80211_radiotap.h>
-/* Hardware specific file defines the PCI IDs table for that hardware module */
-extern struct pci_device_id iwl4965_hw_card_ids[];
-
#define DRV_NAME "iwl4965"
#include "iwl-rfkill.h"
#include "iwl-eeprom.h"
@@ -48,6 +45,9 @@ extern struct pci_device_id iwl4965_hw_card_ids[];
#include "iwl-debug.h"
#include "iwl-led.h"
+/* configuration for the iwl4965 */
+extern struct iwl_cfg iwl4965_agn_cfg;
+
/* Change firmware file name, using "-" and incrementing number,
* *only* when uCode interface or architecture changes so that it
* is not compatible with earlier drivers.
@@ -461,6 +461,7 @@ struct iwl4965_tid_data {
struct iwl4965_hw_key {
enum ieee80211_key_alg alg;
int keylen;
+ u8 keyidx;
struct ieee80211_key_conf *conf;
u8 key[32];
};
@@ -566,7 +567,7 @@ struct iwl4965_ibss_seq {
};
/**
- * struct iwl4965_driver_hw_info
+ * struct iwl_hw_params
* @max_txq_num: Max # Tx queues supported
* @tx_cmd_len: Size of Tx command (but not including frame itself)
* @tx_ant_num: Number of TX antennas
@@ -575,21 +576,20 @@ struct iwl4965_ibss_seq {
* @max_rxq_log: Log-base-2 of max_rxq_size
* @max_stations:
* @bcast_sta_id:
- * @shared_virt: Pointer to driver/uCode shared Tx Byte Counts and Rx status
- * @shared_phys: Physical Pointer to Tx Byte Counts and Rx status
*/
-struct iwl4965_driver_hw_info {
+struct iwl_hw_params {
u16 max_txq_num;
u16 tx_cmd_len;
- u16 tx_ant_num;
+ u8 tx_chains_num;
+ u8 rx_chains_num;
+ u8 valid_tx_ant;
+ u8 valid_rx_ant;
u16 max_rxq_size;
+ u16 max_rxq_log;
u32 rx_buf_size;
u32 max_pkt_size;
- u16 max_rxq_log;
u8 max_stations;
u8 bcast_sta_id;
- void *shared_virt;
- dma_addr_t shared_phys;
};
#define HT_SHORT_GI_20MHZ_ONLY (1 << 0)
@@ -641,7 +641,6 @@ extern unsigned int iwl4965_fill_beacon_frame(struct iwl_priv *priv,
const u8 *dest, int left);
extern int iwl4965_rx_queue_update_write_ptr(struct iwl_priv *priv,
struct iwl4965_rx_queue *q);
-extern int iwl4965_send_statistics_request(struct iwl_priv *priv);
extern void iwl4965_set_decrypted_flag(struct iwl_priv *priv, struct sk_buff *skb,
u32 decrypt_res,
struct ieee80211_rx_status *stats);
@@ -679,7 +678,7 @@ extern void iwl4965_hw_rx_handler_setup(struct iwl_priv *priv);
extern void iwl4965_hw_setup_deferred_work(struct iwl_priv *priv);
extern void iwl4965_hw_cancel_deferred_work(struct iwl_priv *priv);
extern int iwl4965_hw_rxq_stop(struct iwl_priv *priv);
-extern int iwl4965_hw_set_hw_setting(struct iwl_priv *priv);
+extern int iwl4965_hw_set_hw_params(struct iwl_priv *priv);
extern int iwl4965_hw_nic_init(struct iwl_priv *priv);
extern int iwl4965_hw_nic_stop_master(struct iwl_priv *priv);
extern void iwl4965_hw_txq_ctx_free(struct iwl_priv *priv);
@@ -942,6 +941,8 @@ enum {
#endif
+#define IWL_MAX_NUM_QUEUES 20 /* FIXME: do dynamic allocation */
+
struct iwl_priv {
/* ieee device used by generic ieee processing code */
@@ -1033,7 +1034,7 @@ struct iwl_priv {
* 4965's initialize alive response contains some calibration data. */
struct iwl4965_init_alive_resp card_alive_init;
struct iwl4965_alive_resp card_alive;
-#ifdef CONFIG_IWLCORE_RFKILL
+#ifdef CONFIG_IWLWIFI_RFKILL
struct iwl_rfkill_mngr rfkill_mngr;
#endif
@@ -1112,6 +1113,10 @@ struct iwl_priv {
spinlock_t sta_lock;
int num_stations;
struct iwl4965_station_entry stations[IWL_STATION_COUNT];
+ struct iwl_wep_key wep_keys[WEP_KEYS_MAX];
+ u8 default_wep_key;
+ u8 key_mapping_key;
+ unsigned long ucode_key_table;
/* Indication if ieee80211_ops->open has been called */
u8 is_open;
@@ -1142,9 +1147,14 @@ struct iwl_priv {
/* Last Rx'd beacon timestamp */
u64 timestamp;
u16 beacon_int;
- struct iwl4965_driver_hw_info hw_setting;
struct ieee80211_vif *vif;
+ struct iwl_hw_params hw_params;
+ /* driver/uCode shared Tx Byte Counts and Rx status */
+ void *shared_virt;
+ /* Physical Pointer to Tx Byte Counts and Rx status */
+ dma_addr_t shared_phys;
+
/* Current association information needed to configure the
* hardware */
u16 assoc_id;
@@ -1200,7 +1210,6 @@ struct iwl_priv {
#ifdef CONFIG_IWL4965_SENSITIVITY
struct work_struct sensitivity_work;
#endif
- struct work_struct statistics_work;
struct timer_list statistics_periodic;
}; /*iwl_priv */
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index d8a226e68ed1..2dfd982d7d1f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -277,3 +277,16 @@ int iwlcore_low_level_notify(struct iwl_priv *priv,
}
EXPORT_SYMBOL(iwlcore_low_level_notify);
+int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags)
+{
+ u32 stat_flags = 0;
+ struct iwl_host_cmd cmd = {
+ .id = REPLY_STATISTICS_CMD,
+ .meta.flags = flags,
+ .len = sizeof(stat_flags),
+ .data = (u8 *) &stat_flags,
+ };
+ return iwl_send_cmd(priv, &cmd);
+}
+EXPORT_SYMBOL(iwl_send_statistics_request);
+
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index 6d82376f43f9..7193d97630dc 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -82,6 +82,9 @@ struct iwl_cmd;
#define IWL_SKU_A 0x2
#define IWL_SKU_N 0x8
+struct iwl_hcmd_ops {
+ int (*rxon_assoc)(struct iwl_priv *priv);
+};
struct iwl_hcmd_utils_ops {
int (*enqueue_hcmd)(struct iwl_priv *priv, struct iwl_host_cmd *cmd);
};
@@ -89,19 +92,35 @@ struct iwl_hcmd_utils_ops {
struct iwl_lib_ops {
/* iwlwifi driver (priv) init */
int (*init_drv)(struct iwl_priv *priv);
+ /* set hw dependant perameters */
+ int (*set_hw_params)(struct iwl_priv *priv);
+
+ void (*txq_update_byte_cnt_tbl)(struct iwl_priv *priv,
+ struct iwl4965_tx_queue *txq,
+ u16 byte_cnt);
+ /* nic init */
+ int (*hw_nic_init)(struct iwl_priv *priv);
+ /* alive notification */
+ int (*alive_notify)(struct iwl_priv *priv);
+ /* check validity of rtc data address */
+ int (*is_valid_rtc_data_addr)(u32 addr);
+ /* 1st ucode load */
+ int (*load_ucode)(struct iwl_priv *priv);
+ /* rfkill */
+ void (*radio_kill_sw)(struct iwl_priv *priv, int disable_radio);
/* eeprom operations (as defined in iwl-eeprom.h) */
struct iwl_eeprom_ops eeprom_ops;
- void (*radio_kill_sw)(struct iwl_priv *priv, int disable_radio);
};
struct iwl_ops {
const struct iwl_lib_ops *lib;
+ const struct iwl_hcmd_ops *hcmd;
const struct iwl_hcmd_utils_ops *utils;
};
struct iwl_mod_params {
int disable; /* def: 0 = enable radio */
- int hw_crypto; /* def: 0 = using software encryption */
+ int sw_crypto; /* def: 0 = using hardware encryption */
int debug; /* def: 0 = minimal debug log messages */
int disable_hw_scan; /* def: 0 = use h/w scan */
int num_of_queues; /* def: HW dependent */
@@ -215,4 +234,13 @@ enum iwlcore_card_notify {
int iwlcore_low_level_notify(struct iwl_priv *priv,
enum iwlcore_card_notify notify);
+extern int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags);
+int iwl_send_lq_cmd(struct iwl_priv *priv,
+ struct iwl_link_quality_cmd *lq, u8 flags);
+
+static inline int iwl_send_rxon_assoc(struct iwl_priv *priv)
+{
+ return priv->cfg->ops->hcmd->rxon_assoc(priv);
+}
+
#endif /* __iwl_core_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
index 23632e54aab2..0f16f2606f29 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
@@ -102,10 +102,14 @@ static ssize_t iwl_dbgfs_tx_statistics_read(struct file *file,
struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
char buf[256];
int pos = 0;
+ const size_t bufsz = sizeof(buf);
- pos += sprintf(buf+pos, "mgmt: %u\n", priv->tx_stats[0].cnt);
- pos += sprintf(buf+pos, "ctrl: %u\n", priv->tx_stats[1].cnt);
- pos += sprintf(buf+pos, "data: %u\n", priv->tx_stats[2].cnt);
+ pos += scnprintf(buf + pos, bufsz - pos, "mgmt: %u\n",
+ priv->tx_stats[0].cnt);
+ pos += scnprintf(buf + pos, bufsz - pos, "ctrl: %u\n",
+ priv->tx_stats[1].cnt);
+ pos += scnprintf(buf + pos, bufsz - pos, "data: %u\n",
+ priv->tx_stats[2].cnt);
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
}
@@ -117,10 +121,14 @@ static ssize_t iwl_dbgfs_rx_statistics_read(struct file *file,
struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
char buf[256];
int pos = 0;
+ const size_t bufsz = sizeof(buf);
- pos += sprintf(buf+pos, "mgmt: %u\n", priv->rx_stats[0].cnt);
- pos += sprintf(buf+pos, "ctrl: %u\n", priv->rx_stats[1].cnt);
- pos += sprintf(buf+pos, "data: %u\n", priv->rx_stats[2].cnt);
+ pos += scnprintf(buf + pos, bufsz - pos, "mgmt: %u\n",
+ priv->rx_stats[0].cnt);
+ pos += scnprintf(buf + pos, bufsz - pos, "ctrl: %u\n",
+ priv->rx_stats[1].cnt);
+ pos += scnprintf(buf + pos, bufsz - pos, "data: %u\n",
+ priv->rx_stats[2].cnt);
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
}
@@ -138,6 +146,7 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file,
int i;
int pos = 0;
struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ const size_t bufsz = sizeof(buf);
printk(KERN_DEBUG "offset is: 0x%x\tlen is: 0x%x\n",
priv->dbgfs->sram_offset, priv->dbgfs->sram_len);
@@ -159,9 +168,9 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file,
break;
}
}
- pos += sprintf(buf+pos, "0x%08x ", val);
+ pos += scnprintf(buf + pos, bufsz - pos, "0x%08x ", val);
}
- pos += sprintf(buf+pos, "\n");
+ pos += scnprintf(buf + pos, bufsz - pos, "\n");
iwl_release_nic_access(priv);
ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
@@ -198,7 +207,7 @@ static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf,
{
struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
struct iwl4965_station_entry *station;
- int max_sta = priv->hw_setting.max_stations;
+ int max_sta = priv->hw_params.max_stations;
char *buf;
int i, j, pos = 0;
ssize_t ret;
@@ -210,44 +219,50 @@ static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf,
if(!buf)
return -ENOMEM;
- pos += sprintf(buf+pos, "num of stations: %d\n\n",
+ pos += scnprintf(buf + pos, bufsz - pos, "num of stations: %d\n\n",
priv->num_stations);
for (i = 0; i < max_sta; i++) {
station = &priv->stations[i];
if (station->used) {
- pos += sprintf(buf+pos, "station %d:\ngeneral data:\n",
- i+1);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "station %d:\ngeneral data:\n", i+1);
print_mac(mac, station->sta.sta.addr);
- pos += sprintf(buf+pos, "id: %u\n",
+ pos += scnprintf(buf + pos, bufsz - pos, "id: %u\n",
station->sta.sta.sta_id);
- pos += sprintf(buf+pos, "mode: %u\n",
+ pos += scnprintf(buf + pos, bufsz - pos, "mode: %u\n",
station->sta.mode);
- pos += sprintf(buf+pos, "flags: 0x%x\n",
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "flags: 0x%x\n",
station->sta.station_flags_msk);
- pos += sprintf(buf+pos, "ps_status: %u\n",
- station->ps_status);
-
- pos += sprintf(buf+pos, "tid data:\n");
-
- pos += sprintf(buf+pos, "seq_num\t\ttxq_id\t");
- pos += sprintf(buf+pos, "frame_count\twait_for_ba\t");
- pos += sprintf(buf+pos, "start_idx\tbitmap0\t");
- pos += sprintf(buf+pos, "bitmap1\trate_n_flags\n");
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "ps_status: %u\n", station->ps_status);
+ pos += scnprintf(buf + pos, bufsz - pos, "tid data:\n");
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "seq_num\t\ttxq_id\t");
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "frame_count\twait_for_ba\t");
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "start_idx\tbitmap0\t");
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "bitmap1\trate_n_flags\n");
for (j = 0; j < MAX_TID_COUNT; j++) {
- pos += sprintf(buf+pos, "[%d]:\t\t%u\t",
- j, station->tid[j].seq_number);
- pos += sprintf(buf+pos, "%u\t\t%u\t\t%u\t\t",
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "[%d]:\t\t%u\t", j,
+ station->tid[j].seq_number);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "%u\t\t%u\t\t%u\t\t",
station->tid[j].agg.txq_id,
station->tid[j].agg.frame_count,
station->tid[j].agg.wait_for_ba);
- pos += sprintf(buf+pos, "%u\t%llu\t%u\n",
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "%u\t%llu\t%u\n",
station->tid[j].agg.start_idx,
(unsigned long long)station->tid[j].agg.bitmap,
station->tid[j].agg.rate_n_flags);
}
- pos += sprintf(buf+pos, "\n");
+ pos += scnprintf(buf + pos, bufsz - pos, "\n");
}
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c
index 1f8c2999805b..fdb27f1cdc08 100644
--- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c
+++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c
@@ -51,6 +51,7 @@ const char *get_cmd_string(u8 cmd)
IWL_CMD(REPLY_ADD_STA);
IWL_CMD(REPLY_REMOVE_STA);
IWL_CMD(REPLY_REMOVE_ALL_STA);
+ IWL_CMD(REPLY_WEPKEY);
IWL_CMD(REPLY_TX);
IWL_CMD(REPLY_RATE_SCALE);
IWL_CMD(REPLY_LEDS_CMD);
diff --git a/drivers/net/wireless/iwlwifi/iwl-rfkill.c b/drivers/net/wireless/iwlwifi/iwl-rfkill.c
index 8f38c24491cd..5980a5621cb8 100644
--- a/drivers/net/wireless/iwlwifi/iwl-rfkill.c
+++ b/drivers/net/wireless/iwlwifi/iwl-rfkill.c
@@ -47,6 +47,9 @@ static int iwl_rfkill_soft_rf_kill(void *data, enum rfkill_state state)
if (!priv->rfkill_mngr.rfkill)
return 0;
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return 0;
+
IWL_DEBUG_RF_KILL("we recieved soft RFKILL set to state %d\n", state);
mutex_lock(&priv->mutex);
diff --git a/drivers/net/wireless/iwlwifi/iwl-rfkill.h b/drivers/net/wireless/iwlwifi/iwl-rfkill.h
index e7aa51a1db18..a7f04b855403 100644
--- a/drivers/net/wireless/iwlwifi/iwl-rfkill.h
+++ b/drivers/net/wireless/iwlwifi/iwl-rfkill.h
@@ -34,7 +34,7 @@ struct iwl_priv;
#include <linux/input.h>
-#ifdef CONFIG_IWLCORE_RFKILL
+#ifdef CONFIG_IWLWIFI_RFKILL
struct iwl_rfkill_mngr {
struct rfkill *rfkill;
struct input_dev *input_dev;
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c
new file mode 100644
index 000000000000..e4fdfaa2b9b2
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-sta.c
@@ -0,0 +1,355 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project, as well
+ * as portions of the ieee80211 subsystem header files.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#include <net/mac80211.h>
+
+#include "iwl-eeprom.h"
+#include "iwl-4965.h"
+#include "iwl-core.h"
+#include "iwl-sta.h"
+#include "iwl-io.h"
+#include "iwl-helpers.h"
+#include "iwl-4965.h"
+#include "iwl-sta.h"
+
+int iwl_get_free_ucode_key_index(struct iwl_priv *priv)
+{
+ int i;
+
+ for (i = 0; i < STA_KEY_MAX_NUM; i++)
+ if (!test_and_set_bit(i, &priv->ucode_key_table))
+ return i;
+
+ return -1;
+}
+
+int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty)
+{
+ int i, not_empty = 0;
+ u8 buff[sizeof(struct iwl_wep_cmd) +
+ sizeof(struct iwl_wep_key) * WEP_KEYS_MAX];
+ struct iwl_wep_cmd *wep_cmd = (struct iwl_wep_cmd *)buff;
+ size_t cmd_size = sizeof(struct iwl_wep_cmd);
+ struct iwl_host_cmd cmd = {
+ .id = REPLY_WEPKEY,
+ .data = wep_cmd,
+ .meta.flags = CMD_ASYNC,
+ };
+
+ memset(wep_cmd, 0, cmd_size +
+ (sizeof(struct iwl_wep_key) * WEP_KEYS_MAX));
+
+ for (i = 0; i < WEP_KEYS_MAX ; i++) {
+ wep_cmd->key[i].key_index = i;
+ if (priv->wep_keys[i].key_size) {
+ wep_cmd->key[i].key_offset = i;
+ not_empty = 1;
+ } else {
+ wep_cmd->key[i].key_offset = WEP_INVALID_OFFSET;
+ }
+
+ wep_cmd->key[i].key_size = priv->wep_keys[i].key_size;
+ memcpy(&wep_cmd->key[i].key[3], priv->wep_keys[i].key,
+ priv->wep_keys[i].key_size);
+ }
+
+ wep_cmd->global_key_type = WEP_KEY_WEP_TYPE;
+ wep_cmd->num_keys = WEP_KEYS_MAX;
+
+ cmd_size += sizeof(struct iwl_wep_key) * WEP_KEYS_MAX;
+
+ cmd.len = cmd_size;
+
+ if (not_empty || send_if_empty)
+ return iwl_send_cmd(priv, &cmd);
+ else
+ return 0;
+}
+
+int iwl_remove_default_wep_key(struct iwl_priv *priv,
+ struct ieee80211_key_conf *keyconf)
+{
+ int ret;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+
+ if (!test_and_clear_bit(keyconf->keyidx, &priv->ucode_key_table))
+ IWL_ERROR("index %d not used in uCode key table.\n",
+ keyconf->keyidx);
+
+ priv->default_wep_key--;
+ memset(&priv->wep_keys[keyconf->keyidx], 0, sizeof(priv->wep_keys[0]));
+ ret = iwl_send_static_wepkey_cmd(priv, 1);
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+ return ret;
+}
+
+int iwl_set_default_wep_key(struct iwl_priv *priv,
+ struct ieee80211_key_conf *keyconf)
+{
+ int ret;
+ unsigned long flags;
+
+ keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV;
+ keyconf->hw_key_idx = keyconf->keyidx;
+ priv->stations[IWL_AP_ID].keyinfo.alg = ALG_WEP;
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+ priv->default_wep_key++;
+
+ if (test_and_set_bit(keyconf->keyidx, &priv->ucode_key_table))
+ IWL_ERROR("index %d already used in uCode key table.\n",
+ keyconf->keyidx);
+
+ priv->wep_keys[keyconf->keyidx].key_size = keyconf->keylen;
+ memcpy(&priv->wep_keys[keyconf->keyidx].key, &keyconf->key,
+ keyconf->keylen);
+
+ ret = iwl_send_static_wepkey_cmd(priv, 0);
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+ return ret;
+}
+
+static int iwl_set_wep_dynamic_key_info(struct iwl_priv *priv,
+ struct ieee80211_key_conf *keyconf,
+ u8 sta_id)
+{
+ unsigned long flags;
+ __le16 key_flags = 0;
+ int ret;
+
+ keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV;
+ keyconf->hw_key_idx = keyconf->keyidx;
+
+ key_flags |= (STA_KEY_FLG_WEP | STA_KEY_FLG_MAP_KEY_MSK);
+ key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
+ key_flags &= ~STA_KEY_FLG_INVALID;
+
+ if (keyconf->keylen == WEP_KEY_LEN_128)
+ key_flags |= STA_KEY_FLG_KEY_SIZE_MSK;
+
+ if (sta_id == priv->hw_params.bcast_sta_id)
+ key_flags |= STA_KEY_MULTICAST_MSK;
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+
+ priv->stations[sta_id].keyinfo.alg = keyconf->alg;
+ priv->stations[sta_id].keyinfo.keylen = keyconf->keylen;
+ priv->stations[sta_id].keyinfo.keyidx = keyconf->keyidx;
+
+ memcpy(priv->stations[sta_id].keyinfo.key,
+ keyconf->key, keyconf->keylen);
+
+ memcpy(&priv->stations[sta_id].sta.key.key[3],
+ keyconf->key, keyconf->keylen);
+
+ priv->stations[sta_id].sta.key.key_offset =
+ iwl_get_free_ucode_key_index(priv);
+ priv->stations[sta_id].sta.key.key_flags = key_flags;
+
+ priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
+ priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+
+ ret = iwl4965_send_add_station(priv,
+ &priv->stations[sta_id].sta, CMD_ASYNC);
+
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+ return ret;
+}
+
+static int iwl_set_ccmp_dynamic_key_info(struct iwl_priv *priv,
+ struct ieee80211_key_conf *keyconf,
+ u8 sta_id)
+{
+ unsigned long flags;
+ __le16 key_flags = 0;
+
+ key_flags |= (STA_KEY_FLG_CCMP | STA_KEY_FLG_MAP_KEY_MSK);
+ key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
+ key_flags &= ~STA_KEY_FLG_INVALID;
+
+ if (sta_id == priv->hw_params.bcast_sta_id)
+ key_flags |= STA_KEY_MULTICAST_MSK;
+
+ keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+ keyconf->hw_key_idx = keyconf->keyidx;
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+ priv->stations[sta_id].keyinfo.alg = keyconf->alg;
+ priv->stations[sta_id].keyinfo.keylen = keyconf->keylen;
+
+ memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key,
+ keyconf->keylen);
+
+ memcpy(priv->stations[sta_id].sta.key.key, keyconf->key,
+ keyconf->keylen);
+
+ priv->stations[sta_id].sta.key.key_offset =
+ iwl_get_free_ucode_key_index(priv);
+ priv->stations[sta_id].sta.key.key_flags = key_flags;
+ priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
+ priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+ IWL_DEBUG_INFO("hwcrypto: modify ucode station key info\n");
+ return iwl4965_send_add_station(priv,
+ &priv->stations[sta_id].sta, CMD_ASYNC);
+}
+
+static int iwl_set_tkip_dynamic_key_info(struct iwl_priv *priv,
+ struct ieee80211_key_conf *keyconf,
+ u8 sta_id)
+{
+ unsigned long flags;
+ int ret = 0;
+
+ keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+ keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
+ keyconf->hw_key_idx = keyconf->keyidx;
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+
+ priv->stations[sta_id].keyinfo.alg = keyconf->alg;
+ priv->stations[sta_id].keyinfo.conf = keyconf;
+ priv->stations[sta_id].keyinfo.keylen = 16;
+ priv->stations[sta_id].sta.key.key_offset =
+ iwl_get_free_ucode_key_index(priv);
+
+ /* This copy is acutally not needed: we get the key with each TX */
+ memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key, 16);
+
+ memcpy(priv->stations[sta_id].sta.key.key, keyconf->key, 16);
+
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+ return ret;
+}
+
+int iwl_remove_dynamic_key(struct iwl_priv *priv, u8 sta_id)
+{
+ unsigned long flags;
+
+ priv->key_mapping_key = 0;
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+ if (!test_and_clear_bit(priv->stations[sta_id].sta.key.key_offset,
+ &priv->ucode_key_table))
+ IWL_ERROR("index %d not used in uCode key table.\n",
+ priv->stations[sta_id].sta.key.key_offset);
+ memset(&priv->stations[sta_id].keyinfo, 0,
+ sizeof(struct iwl4965_hw_key));
+ memset(&priv->stations[sta_id].sta.key, 0,
+ sizeof(struct iwl4965_keyinfo));
+ priv->stations[sta_id].sta.key.key_flags = STA_KEY_FLG_NO_ENC;
+ priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
+ priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+ IWL_DEBUG_INFO("hwcrypto: clear ucode station key info\n");
+ return iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, 0);
+}
+
+int iwl_set_dynamic_key(struct iwl_priv *priv,
+ struct ieee80211_key_conf *key, u8 sta_id)
+{
+ int ret;
+
+ priv->key_mapping_key = 1;
+
+ switch (key->alg) {
+ case ALG_CCMP:
+ ret = iwl_set_ccmp_dynamic_key_info(priv, key, sta_id);
+ break;
+ case ALG_TKIP:
+ ret = iwl_set_tkip_dynamic_key_info(priv, key, sta_id);
+ break;
+ case ALG_WEP:
+ ret = iwl_set_wep_dynamic_key_info(priv, key, sta_id);
+ break;
+ default:
+ IWL_ERROR("Unknown alg: %s alg = %d\n", __func__, key->alg);
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+static void iwl_dump_lq_cmd(struct iwl_priv *priv,
+ struct iwl_link_quality_cmd *lq)
+{
+ int i;
+ IWL_DEBUG_RATE("lq station id 0x%x\n", lq->sta_id);
+ IWL_DEBUG_RATE("lq dta 0x%X 0x%X\n",
+ lq->general_params.single_stream_ant_msk,
+ lq->general_params.dual_stream_ant_msk);
+
+ for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++)
+ IWL_DEBUG_RATE("lq index %d 0x%X\n",
+ i, lq->rs_table[i].rate_n_flags);
+}
+#else
+static inline void iwl_dump_lq_cmd(struct iwl_priv *priv,
+ struct iwl_link_quality_cmd *lq)
+{
+}
+#endif
+
+int iwl_send_lq_cmd(struct iwl_priv *priv,
+ struct iwl_link_quality_cmd *lq, u8 flags)
+{
+ struct iwl_host_cmd cmd = {
+ .id = REPLY_TX_LINK_QUALITY_CMD,
+ .len = sizeof(struct iwl_link_quality_cmd),
+ .meta.flags = flags,
+ .data = lq,
+ };
+
+ if ((lq->sta_id == 0xFF) &&
+ (priv->iw_mode == IEEE80211_IF_TYPE_IBSS))
+ return -EINVAL;
+
+ if (lq->sta_id == 0xFF)
+ lq->sta_id = IWL_AP_ID;
+
+ iwl_dump_lq_cmd(priv,lq);
+
+ if (iwl_is_associated(priv) && priv->assoc_station_added &&
+ priv->lq_mngr.lq_ready)
+ return iwl_send_cmd(priv, &cmd);
+
+ return 0;
+}
+EXPORT_SYMBOL(iwl_send_lq_cmd);
+
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.h b/drivers/net/wireless/iwlwifi/iwl-sta.h
new file mode 100644
index 000000000000..44f272ecc827
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-sta.h
@@ -0,0 +1,49 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project, as well
+ * as portions of the ieee80211 subsystem header files.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+#ifndef __iwl_sta_h__
+#define __iwl_sta_h__
+
+#include <net/mac80211.h>
+
+#include "iwl-eeprom.h"
+#include "iwl-core.h"
+#include "iwl-4965.h"
+#include "iwl-io.h"
+#include "iwl-helpers.h"
+
+int iwl_get_free_ucode_key_index(struct iwl_priv *priv);
+int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty);
+int iwl_remove_default_wep_key(struct iwl_priv *priv,
+ struct ieee80211_key_conf *key);
+int iwl_set_default_wep_key(struct iwl_priv *priv,
+ struct ieee80211_key_conf *key);
+int iwl_remove_dynamic_key(struct iwl_priv *priv, u8 sta_id);
+int iwl_set_dynamic_key(struct iwl_priv *priv,
+ struct ieee80211_key_conf *key, u8 sta_id);
+#endif /* __iwl_sta_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index 29a9ecdcbf35..1a5678fe4224 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -70,7 +70,7 @@ static int iwl3945_param_disable; /* def: 0 = enable radio */
static int iwl3945_param_antenna; /* def: 0 = both antennas (use diversity) */
int iwl3945_param_hwcrypto; /* def: 0 = use software encryption */
static int iwl3945_param_qos_enable = 1; /* def: 1 = use quality of service */
-int iwl3945_param_queues_num = IWL_MAX_NUM_QUEUES; /* def: 8 Tx queues */
+int iwl3945_param_queues_num = IWL39_MAX_NUM_QUEUES; /* def: 8 Tx queues */
/*
* module name, copyright, version, etc.
@@ -7974,10 +7974,10 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
iwl3945_hw_ops.hw_scan = NULL;
}
- if ((iwl3945_param_queues_num > IWL_MAX_NUM_QUEUES) ||
+ if ((iwl3945_param_queues_num > IWL39_MAX_NUM_QUEUES) ||
(iwl3945_param_queues_num < IWL_MIN_NUM_QUEUES)) {
IWL_ERROR("invalid queues_num, should be between %d and %d\n",
- IWL_MIN_NUM_QUEUES, IWL_MAX_NUM_QUEUES);
+ IWL_MIN_NUM_QUEUES, IWL39_MAX_NUM_QUEUES);
err = -EINVAL;
goto out;
}
diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c
index 06e44dad5f02..d7e2358a213a 100644
--- a/drivers/net/wireless/iwlwifi/iwl4965-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c
@@ -50,6 +50,7 @@
#include "iwl-core.h"
#include "iwl-io.h"
#include "iwl-helpers.h"
+#include "iwl-sta.h"
static int iwl4965_tx_queue_update_write_ptr(struct iwl_priv *priv,
struct iwl4965_tx_queue *txq);
@@ -397,9 +398,9 @@ static u8 iwl4965_remove_station(struct iwl_priv *priv, const u8 *addr, int is_a
if (is_ap)
index = IWL_AP_ID;
else if (is_broadcast_ether_addr(addr))
- index = priv->hw_setting.bcast_sta_id;
+ index = priv->hw_params.bcast_sta_id;
else
- for (i = IWL_STA_ID; i < priv->hw_setting.max_stations; i++)
+ for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++)
if (priv->stations[i].used &&
!compare_ether_addr(priv->stations[i].sta.sta.addr,
addr)) {
@@ -439,9 +440,9 @@ u8 iwl4965_add_station_flags(struct iwl_priv *priv, const u8 *addr,
if (is_ap)
index = IWL_AP_ID;
else if (is_broadcast_ether_addr(addr))
- index = priv->hw_setting.bcast_sta_id;
+ index = priv->hw_params.bcast_sta_id;
else
- for (i = IWL_STA_ID; i < priv->hw_setting.max_stations; i++) {
+ for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++) {
if (!compare_ether_addr(priv->stations[i].sta.sta.addr,
addr)) {
index = i;
@@ -482,7 +483,7 @@ u8 iwl4965_add_station_flags(struct iwl_priv *priv, const u8 *addr,
#ifdef CONFIG_IWL4965_HT
/* BCAST station and IBSS stations do not work in HT mode */
- if (index != priv->hw_setting.bcast_sta_id &&
+ if (index != priv->hw_params.bcast_sta_id &&
priv->iw_mode != IEEE80211_IF_TYPE_IBSS)
iwl4965_set_ht_add_station(priv, index,
(struct ieee80211_ht_info *) ht_data);
@@ -574,11 +575,11 @@ int iwl4965_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
txq->need_update = 1;
/* Set up entry in queue's byte count circular buffer */
- ret = iwl4965_tx_queue_update_wr_ptr(priv, txq, 0);
+ priv->cfg->ops->lib->txq_update_byte_cnt_tbl(priv, txq, 0);
/* Increment and update queue's write index */
q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
- iwl4965_tx_queue_update_write_ptr(priv, txq);
+ ret = iwl4965_tx_queue_update_write_ptr(priv, txq);
spin_unlock_irqrestore(&priv->hcmd_lock, flags);
return ret ? ret : idx;
@@ -595,13 +596,6 @@ static void iwl4965_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt)
}
-int iwl4965_send_statistics_request(struct iwl_priv *priv)
-{
- u32 flags = 0;
- return iwl_send_cmd_pdu(priv, REPLY_STATISTICS_CMD,
- sizeof(flags), &flags);
-}
-
/**
* iwl4965_rxon_add_station - add station into station table.
*
@@ -755,60 +749,6 @@ static int iwl4965_full_rxon_required(struct iwl_priv *priv)
return 0;
}
-static int iwl4965_send_rxon_assoc(struct iwl_priv *priv)
-{
- int rc = 0;
- struct iwl4965_rx_packet *res = NULL;
- struct iwl4965_rxon_assoc_cmd rxon_assoc;
- struct iwl_host_cmd cmd = {
- .id = REPLY_RXON_ASSOC,
- .len = sizeof(rxon_assoc),
- .meta.flags = CMD_WANT_SKB,
- .data = &rxon_assoc,
- };
- const struct iwl4965_rxon_cmd *rxon1 = &priv->staging_rxon;
- const struct iwl4965_rxon_cmd *rxon2 = &priv->active_rxon;
-
- if ((rxon1->flags == rxon2->flags) &&
- (rxon1->filter_flags == rxon2->filter_flags) &&
- (rxon1->cck_basic_rates == rxon2->cck_basic_rates) &&
- (rxon1->ofdm_ht_single_stream_basic_rates ==
- rxon2->ofdm_ht_single_stream_basic_rates) &&
- (rxon1->ofdm_ht_dual_stream_basic_rates ==
- rxon2->ofdm_ht_dual_stream_basic_rates) &&
- (rxon1->rx_chain == rxon2->rx_chain) &&
- (rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates)) {
- IWL_DEBUG_INFO("Using current RXON_ASSOC. Not resending.\n");
- return 0;
- }
-
- rxon_assoc.flags = priv->staging_rxon.flags;
- rxon_assoc.filter_flags = priv->staging_rxon.filter_flags;
- rxon_assoc.ofdm_basic_rates = priv->staging_rxon.ofdm_basic_rates;
- rxon_assoc.cck_basic_rates = priv->staging_rxon.cck_basic_rates;
- rxon_assoc.reserved = 0;
- rxon_assoc.ofdm_ht_single_stream_basic_rates =
- priv->staging_rxon.ofdm_ht_single_stream_basic_rates;
- rxon_assoc.ofdm_ht_dual_stream_basic_rates =
- priv->staging_rxon.ofdm_ht_dual_stream_basic_rates;
- rxon_assoc.rx_chain_select_flags = priv->staging_rxon.rx_chain;
-
- rc = iwl_send_cmd_sync(priv, &cmd);
- if (rc)
- return rc;
-
- res = (struct iwl4965_rx_packet *)cmd.meta.u.skb->data;
- if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
- IWL_ERROR("Bad return from REPLY_RXON_ASSOC command\n");
- rc = -EIO;
- }
-
- priv->alloc_rxb_skb--;
- dev_kfree_skb_any(cmd.meta.u.skb);
-
- return rc;
-}
-
/**
* iwl4965_commit_rxon - commit staging_rxon to hardware
*
@@ -840,7 +780,7 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv)
* iwl4965_rxon_assoc_cmd which is used to reconfigure filter
* and other flags for the current radio configuration. */
if (!iwl4965_full_rxon_required(priv)) {
- rc = iwl4965_send_rxon_assoc(priv);
+ rc = iwl_send_rxon_assoc(priv);
if (rc) {
IWL_ERROR("Error setting RXON_ASSOC "
"configuration (%d).\n", rc);
@@ -895,7 +835,7 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv)
le16_to_cpu(priv->staging_rxon.channel),
print_mac(mac, priv->staging_rxon.bssid_addr));
- iwl4965_set_rxon_hwcrypto(priv, priv->cfg->mod_params->hw_crypto);
+ iwl4965_set_rxon_hwcrypto(priv, !priv->cfg->mod_params->sw_crypto);
/* Apply the new configuration */
rc = iwl_send_cmd_pdu(priv, REPLY_RXON,
sizeof(struct iwl4965_rxon_cmd), &priv->staging_rxon);
@@ -941,6 +881,9 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv)
return -EIO;
}
priv->assoc_station_added = 1;
+ if (priv->default_wep_key &&
+ iwl_send_static_wepkey_cmd(priv, 0))
+ IWL_ERROR("Could not send WEP static key.\n");
}
return 0;
@@ -1108,131 +1051,6 @@ int iwl4965_send_add_station(struct iwl_priv *priv,
return rc;
}
-static int iwl4965_set_ccmp_dynamic_key_info(struct iwl_priv *priv,
- struct ieee80211_key_conf *keyconf,
- u8 sta_id)
-{
- unsigned long flags;
- __le16 key_flags = 0;
-
- key_flags |= (STA_KEY_FLG_CCMP | STA_KEY_FLG_MAP_KEY_MSK);
- key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
-
- if (sta_id == priv->hw_setting.bcast_sta_id)
- key_flags |= STA_KEY_MULTICAST_MSK;
-
- keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
- keyconf->hw_key_idx = keyconf->keyidx;
-
- key_flags &= ~STA_KEY_FLG_INVALID;
-
- spin_lock_irqsave(&priv->sta_lock, flags);
- priv->stations[sta_id].keyinfo.alg = keyconf->alg;
- priv->stations[sta_id].keyinfo.keylen = keyconf->keylen;
-
- memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key,
- keyconf->keylen);
-
- memcpy(priv->stations[sta_id].sta.key.key, keyconf->key,
- keyconf->keylen);
-
- priv->stations[sta_id].sta.key.key_offset
- = (sta_id % STA_KEY_MAX_NUM);/*FIXME*/
- priv->stations[sta_id].sta.key.key_flags = key_flags;
- priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
- priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
-
- spin_unlock_irqrestore(&priv->sta_lock, flags);
-
- IWL_DEBUG_INFO("hwcrypto: modify ucode station key info\n");
- return iwl4965_send_add_station(priv,
- &priv->stations[sta_id].sta, CMD_ASYNC);
-}
-
-static int iwl4965_set_tkip_dynamic_key_info(struct iwl_priv *priv,
- struct ieee80211_key_conf *keyconf,
- u8 sta_id)
-{
- unsigned long flags;
- int ret = 0;
-
- keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
- keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
- keyconf->hw_key_idx = keyconf->keyidx;
-
- spin_lock_irqsave(&priv->sta_lock, flags);
-
- priv->stations[sta_id].keyinfo.alg = keyconf->alg;
- priv->stations[sta_id].keyinfo.conf = keyconf;
- priv->stations[sta_id].keyinfo.keylen = 16;
-
- /* This copy is acutally not needed: we get the key with each TX */
- memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key, 16);
-
- memcpy(priv->stations[sta_id].sta.key.key, keyconf->key, 16);
-
- spin_unlock_irqrestore(&priv->sta_lock, flags);
-
- return ret;
-}
-
-static int iwl4965_clear_sta_key_info(struct iwl_priv *priv, u8 sta_id)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&priv->sta_lock, flags);
- memset(&priv->stations[sta_id].keyinfo, 0, sizeof(struct iwl4965_hw_key));
- memset(&priv->stations[sta_id].sta.key, 0, sizeof(struct iwl4965_keyinfo));
- priv->stations[sta_id].sta.key.key_flags = STA_KEY_FLG_NO_ENC;
- priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
- priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
- spin_unlock_irqrestore(&priv->sta_lock, flags);
-
- IWL_DEBUG_INFO("hwcrypto: clear ucode station key info\n");
- iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, 0);
- return 0;
-}
-
-static int iwl4965_set_dynamic_key(struct iwl_priv *priv,
- struct ieee80211_key_conf *key, u8 sta_id)
-{
- int ret;
-
- switch (key->alg) {
- case ALG_CCMP:
- ret = iwl4965_set_ccmp_dynamic_key_info(priv, key, sta_id);
- break;
- case ALG_TKIP:
- ret = iwl4965_set_tkip_dynamic_key_info(priv, key, sta_id);
- break;
- case ALG_WEP:
- ret = -EOPNOTSUPP;
- break;
- default:
- IWL_ERROR("Unknown alg: %s alg = %d\n", __func__, key->alg);
- ret = -EINVAL;
- }
-
- return ret;
-}
-
-static int iwl4965_remove_static_key(struct iwl_priv *priv)
-{
- int ret = -EOPNOTSUPP;
-
- return ret;
-}
-
-static int iwl4965_set_static_key(struct iwl_priv *priv,
- struct ieee80211_key_conf *key)
-{
- if (key->alg == ALG_WEP)
- return -EOPNOTSUPP;
-
- IWL_ERROR("Static key invalid: alg %d\n", key->alg);
- return -EINVAL;
-}
-
static void iwl4965_clear_free_frames(struct iwl_priv *priv)
{
struct list_head *element;
@@ -1353,13 +1171,13 @@ static int iwl4965_send_beacon_cmd(struct iwl_priv *priv)
*
******************************************************************************/
-static void iwl4965_unset_hw_setting(struct iwl_priv *priv)
+static void iwl4965_unset_hw_params(struct iwl_priv *priv)
{
- if (priv->hw_setting.shared_virt)
+ if (priv->shared_virt)
pci_free_consistent(priv->pci_dev,
sizeof(struct iwl4965_shared),
- priv->hw_setting.shared_virt,
- priv->hw_setting.shared_phys);
+ priv->shared_virt,
+ priv->shared_phys);
}
/**
@@ -1976,7 +1794,7 @@ static void iwl4965_set_flags_for_phymode(struct iwl_priv *priv,
| RXON_FLG_CCK_MSK);
priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
} else {
- /* Copied from iwl4965_bg_post_associate() */
+ /* Copied from iwl4965_post_associate() */
if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
else
@@ -2115,6 +1933,10 @@ static void iwl4965_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
int sta_id)
{
struct iwl4965_hw_key *keyinfo = &priv->stations[sta_id].keyinfo;
+ struct iwl_wep_key *wepkey;
+ int keyidx = 0;
+
+ BUG_ON(ctl->key_idx > 3);
switch (keyinfo->alg) {
case ALG_CCMP:
@@ -2133,16 +1955,29 @@ static void iwl4965_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
break;
case ALG_WEP:
- cmd->cmd.tx.sec_ctl = TX_CMD_SEC_WEP |
- (ctl->key_idx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT;
-
- if (keyinfo->keylen == 13)
- cmd->cmd.tx.sec_ctl |= TX_CMD_SEC_KEY128;
+ wepkey = &priv->wep_keys[ctl->key_idx];
+ cmd->cmd.tx.sec_ctl = 0;
+ if (priv->default_wep_key) {
+ /* the WEP key was sent as static */
+ keyidx = ctl->key_idx;
+ memcpy(&cmd->cmd.tx.key[3], wepkey->key,
+ wepkey->key_size);
+ if (wepkey->key_size == WEP_KEY_LEN_128)
+ cmd->cmd.tx.sec_ctl |= TX_CMD_SEC_KEY128;
+ } else {
+ /* the WEP key was sent as dynamic */
+ keyidx = keyinfo->keyidx;
+ memcpy(&cmd->cmd.tx.key[3], keyinfo->key,
+ keyinfo->keylen);
+ if (keyinfo->keylen == WEP_KEY_LEN_128)
+ cmd->cmd.tx.sec_ctl |= TX_CMD_SEC_KEY128;
+ }
- memcpy(&cmd->cmd.tx.key[3], keyinfo->key, keyinfo->keylen);
+ cmd->cmd.tx.sec_ctl |= (TX_CMD_SEC_WEP |
+ (keyidx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT);
IWL_DEBUG_TX("Configuring packet for WEP encryption "
- "with key %d\n", ctl->key_idx);
+ "with key %d\n", keyidx);
break;
default:
@@ -2240,7 +2075,7 @@ static int iwl4965_get_sta_id(struct iwl_priv *priv,
/* If this frame is broadcast or management, use broadcast station id */
if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) ||
is_multicast_ether_addr(hdr->addr1))
- return priv->hw_setting.bcast_sta_id;
+ return priv->hw_params.bcast_sta_id;
switch (priv->iw_mode) {
@@ -2254,7 +2089,7 @@ static int iwl4965_get_sta_id(struct iwl_priv *priv,
sta_id = iwl4965_hw_find_station(priv, hdr->addr1);
if (sta_id != IWL_INVALID_STATION)
return sta_id;
- return priv->hw_setting.bcast_sta_id;
+ return priv->hw_params.bcast_sta_id;
/* If this frame is going out to an IBSS network, find the station,
* or create a new station table entry */
@@ -2274,11 +2109,11 @@ static int iwl4965_get_sta_id(struct iwl_priv *priv,
"Defaulting to broadcast...\n",
print_mac(mac, hdr->addr1));
iwl_print_hex_dump(IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr));
- return priv->hw_setting.bcast_sta_id;
+ return priv->hw_params.bcast_sta_id;
default:
IWL_WARNING("Unknown mode of operation: %d", priv->iw_mode);
- return priv->hw_setting.bcast_sta_id;
+ return priv->hw_params.bcast_sta_id;
}
}
@@ -2425,7 +2260,7 @@ static int iwl4965_tx_skb(struct iwl_priv *priv,
* of the MAC header (device reads on dword boundaries).
* We'll tell device about this padding later.
*/
- len = priv->hw_setting.tx_cmd_len +
+ len = priv->hw_params.tx_cmd_len +
sizeof(struct iwl_cmd_header) + hdr_len;
len_org = len;
@@ -2496,7 +2331,7 @@ static int iwl4965_tx_skb(struct iwl_priv *priv,
ieee80211_get_hdrlen(fc));
/* Set up entry for this TFD in Tx byte-count array */
- iwl4965_tx_queue_update_wr_ptr(priv, txq, len);
+ priv->cfg->ops->lib->txq_update_byte_cnt_tbl(priv, txq, len);
/* Tell device the write index *just past* this latest filled TFD */
q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
@@ -2592,7 +2427,8 @@ void iwl4965_radio_kill_sw(struct iwl_priv *priv, int disable_radio)
CSR_UCODE_SW_BIT_RFKILL);
spin_unlock_irqrestore(&priv->lock, flags);
/* call the host command only if no hw rf-kill set */
- if (!test_bit(STATUS_RF_KILL_HW, &priv->status))
+ if (!test_bit(STATUS_RF_KILL_HW, &priv->status) &&
+ iwl_is_ready(priv))
iwl4965_send_card_state(priv,
CARD_STATE_CMD_DISABLE,
0);
@@ -3852,7 +3688,7 @@ static void iwl4965_rx_allocate(struct iwl_priv *priv)
/* Alloc a new receive buffer */
rxb->skb =
- alloc_skb(priv->hw_setting.rx_buf_size,
+ alloc_skb(priv->hw_params.rx_buf_size,
__GFP_NOWARN | GFP_ATOMIC);
if (!rxb->skb) {
if (net_ratelimit())
@@ -3869,7 +3705,7 @@ static void iwl4965_rx_allocate(struct iwl_priv *priv)
/* Get physical address of RB/SKB */
rxb->dma_addr =
pci_map_single(priv->pci_dev, rxb->skb->data,
- priv->hw_setting.rx_buf_size, PCI_DMA_FROMDEVICE);
+ priv->hw_params.rx_buf_size, PCI_DMA_FROMDEVICE);
list_add_tail(&rxb->list, &rxq->rx_free);
rxq->free_count++;
}
@@ -3912,7 +3748,7 @@ static void iwl4965_rx_queue_free(struct iwl_priv *priv, struct iwl4965_rx_queue
if (rxq->pool[i].skb != NULL) {
pci_unmap_single(priv->pci_dev,
rxq->pool[i].dma_addr,
- priv->hw_setting.rx_buf_size,
+ priv->hw_params.rx_buf_size,
PCI_DMA_FROMDEVICE);
dev_kfree_skb(rxq->pool[i].skb);
}
@@ -3964,7 +3800,7 @@ void iwl4965_rx_queue_reset(struct iwl_priv *priv, struct iwl4965_rx_queue *rxq)
if (rxq->pool[i].skb != NULL) {
pci_unmap_single(priv->pci_dev,
rxq->pool[i].dma_addr,
- priv->hw_setting.rx_buf_size,
+ priv->hw_params.rx_buf_size,
PCI_DMA_FROMDEVICE);
priv->alloc_rxb_skb--;
dev_kfree_skb(rxq->pool[i].skb);
@@ -4099,7 +3935,7 @@ static void iwl4965_rx_handle(struct iwl_priv *priv)
rxq->queue[i] = NULL;
pci_dma_sync_single_for_cpu(priv->pci_dev, rxb->dma_addr,
- priv->hw_setting.rx_buf_size,
+ priv->hw_params.rx_buf_size,
PCI_DMA_FROMDEVICE);
pkt = (struct iwl4965_rx_packet *)rxb->skb->data;
@@ -4152,7 +3988,7 @@ static void iwl4965_rx_handle(struct iwl_priv *priv)
}
pci_unmap_single(priv->pci_dev, rxb->dma_addr,
- priv->hw_setting.rx_buf_size,
+ priv->hw_params.rx_buf_size,
PCI_DMA_FROMDEVICE);
spin_lock_irqsave(&rxq->lock, flags);
list_add_tail(&rxb->list, &priv->rxq.rx_used);
@@ -4305,7 +4141,7 @@ static void iwl4965_dump_nic_error_log(struct iwl_priv *priv)
base = le32_to_cpu(priv->card_alive.error_event_table_ptr);
- if (!iwl4965_hw_valid_rtc_data_addr(base)) {
+ if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
IWL_ERROR("Not valid error log pointer 0x%08X\n", base);
return;
}
@@ -4400,7 +4236,7 @@ static void iwl4965_dump_nic_event_log(struct iwl_priv *priv)
u32 size; /* # entries that we'll print */
base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
- if (!iwl4965_hw_valid_rtc_data_addr(base)) {
+ if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
IWL_ERROR("Invalid event log pointer 0x%08X\n", base);
return;
}
@@ -5175,156 +5011,6 @@ static int iwl4965_verify_ucode(struct iwl_priv *priv)
return rc;
}
-
-/* check contents of special bootstrap uCode SRAM */
-static int iwl4965_verify_bsm(struct iwl_priv *priv)
-{
- __le32 *image = priv->ucode_boot.v_addr;
- u32 len = priv->ucode_boot.len;
- u32 reg;
- u32 val;
-
- IWL_DEBUG_INFO("Begin verify bsm\n");
-
- /* verify BSM SRAM contents */
- val = iwl_read_prph(priv, BSM_WR_DWCOUNT_REG);
- for (reg = BSM_SRAM_LOWER_BOUND;
- reg < BSM_SRAM_LOWER_BOUND + len;
- reg += sizeof(u32), image ++) {
- val = iwl_read_prph(priv, reg);
- if (val != le32_to_cpu(*image)) {
- IWL_ERROR("BSM uCode verification failed at "
- "addr 0x%08X+%u (of %u), is 0x%x, s/b 0x%x\n",
- BSM_SRAM_LOWER_BOUND,
- reg - BSM_SRAM_LOWER_BOUND, len,
- val, le32_to_cpu(*image));
- return -EIO;
- }
- }
-
- IWL_DEBUG_INFO("BSM bootstrap uCode image OK\n");
-
- return 0;
-}
-
-/**
- * iwl4965_load_bsm - Load bootstrap instructions
- *
- * BSM operation:
- *
- * The Bootstrap State Machine (BSM) stores a short bootstrap uCode program
- * in special SRAM that does not power down during RFKILL. When powering back
- * up after power-saving sleeps (or during initial uCode load), the BSM loads
- * the bootstrap program into the on-board processor, and starts it.
- *
- * The bootstrap program loads (via DMA) instructions and data for a new
- * program from host DRAM locations indicated by the host driver in the
- * BSM_DRAM_* registers. Once the new program is loaded, it starts
- * automatically.
- *
- * When initializing the NIC, the host driver points the BSM to the
- * "initialize" uCode image. This uCode sets up some internal data, then
- * notifies host via "initialize alive" that it is complete.
- *
- * The host then replaces the BSM_DRAM_* pointer values to point to the
- * normal runtime uCode instructions and a backup uCode data cache buffer
- * (filled initially with starting data values for the on-board processor),
- * then triggers the "initialize" uCode to load and launch the runtime uCode,
- * which begins normal operation.
- *
- * When doing a power-save shutdown, runtime uCode saves data SRAM into
- * the backup data cache in DRAM before SRAM is powered down.
- *
- * When powering back up, the BSM loads the bootstrap program. This reloads
- * the runtime uCode instructions and the backup data cache into SRAM,
- * and re-launches the runtime uCode from where it left off.
- */
-static int iwl4965_load_bsm(struct iwl_priv *priv)
-{
- __le32 *image = priv->ucode_boot.v_addr;
- u32 len = priv->ucode_boot.len;
- dma_addr_t pinst;
- dma_addr_t pdata;
- u32 inst_len;
- u32 data_len;
- int rc;
- int i;
- u32 done;
- u32 reg_offset;
-
- IWL_DEBUG_INFO("Begin load bsm\n");
-
- /* make sure bootstrap program is no larger than BSM's SRAM size */
- if (len > IWL_MAX_BSM_SIZE)
- return -EINVAL;
-
- /* Tell bootstrap uCode where to find the "Initialize" uCode
- * in host DRAM ... host DRAM physical address bits 35:4 for 4965.
- * NOTE: iwl4965_initialize_alive_start() will replace these values,
- * after the "initialize" uCode has run, to point to
- * runtime/protocol instructions and backup data cache. */
- pinst = priv->ucode_init.p_addr >> 4;
- pdata = priv->ucode_init_data.p_addr >> 4;
- inst_len = priv->ucode_init.len;
- data_len = priv->ucode_init_data.len;
-
- rc = iwl_grab_nic_access(priv);
- if (rc)
- return rc;
-
- iwl_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst);
- iwl_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata);
- iwl_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG, inst_len);
- iwl_write_prph(priv, BSM_DRAM_DATA_BYTECOUNT_REG, data_len);
-
- /* Fill BSM memory with bootstrap instructions */
- for (reg_offset = BSM_SRAM_LOWER_BOUND;
- reg_offset < BSM_SRAM_LOWER_BOUND + len;
- reg_offset += sizeof(u32), image++)
- _iwl_write_prph(priv, reg_offset,
- le32_to_cpu(*image));
-
- rc = iwl4965_verify_bsm(priv);
- if (rc) {
- iwl_release_nic_access(priv);
- return rc;
- }
-
- /* Tell BSM to copy from BSM SRAM into instruction SRAM, when asked */
- iwl_write_prph(priv, BSM_WR_MEM_SRC_REG, 0x0);
- iwl_write_prph(priv, BSM_WR_MEM_DST_REG,
- RTC_INST_LOWER_BOUND);
- iwl_write_prph(priv, BSM_WR_DWCOUNT_REG, len / sizeof(u32));
-
- /* Load bootstrap code into instruction SRAM now,
- * to prepare to load "initialize" uCode */
- iwl_write_prph(priv, BSM_WR_CTRL_REG,
- BSM_WR_CTRL_REG_BIT_START);
-
- /* Wait for load of bootstrap uCode to finish */
- for (i = 0; i < 100; i++) {
- done = iwl_read_prph(priv, BSM_WR_CTRL_REG);
- if (!(done & BSM_WR_CTRL_REG_BIT_START))
- break;
- udelay(10);
- }
- if (i < 100)
- IWL_DEBUG_INFO("BSM write complete, poll %d iterations\n", i);
- else {
- IWL_ERROR("BSM write did not complete!\n");
- return -EIO;
- }
-
- /* Enable future boot loads whenever power management unit triggers it
- * (e.g. when powering back up after power-save shutdown) */
- iwl_write_prph(priv, BSM_WR_CTRL_REG,
- BSM_WR_CTRL_REG_BIT_START_EN);
-
- iwl_release_nic_access(priv);
-
- return 0;
-}
-
static void iwl4965_nic_start(struct iwl_priv *priv)
{
/* Remove all resets to allow NIC to operate */
@@ -5634,7 +5320,7 @@ static void iwl4965_init_alive_start(struct iwl_priv *priv)
*/
static void iwl4965_alive_start(struct iwl_priv *priv)
{
- int rc = 0;
+ int ret = 0;
IWL_DEBUG_INFO("Runtime Alive received.\n");
@@ -5657,10 +5343,10 @@ static void iwl4965_alive_start(struct iwl_priv *priv)
iwlcore_clear_stations_table(priv);
- rc = iwl4965_alive_notify(priv);
- if (rc) {
+ ret = priv->cfg->ops->lib->alive_notify(priv);
+ if (ret) {
IWL_WARNING("Could not complete ALIVE transition [ntf]: %d\n",
- rc);
+ ret);
goto restart;
}
@@ -5835,7 +5521,8 @@ static void iwl4965_down(struct iwl_priv *priv)
static int __iwl4965_up(struct iwl_priv *priv)
{
- int rc, i;
+ int i;
+ int ret;
if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
IWL_WARNING("Exit pending; will not bring the NIC up\n");
@@ -5870,10 +5557,10 @@ static int __iwl4965_up(struct iwl_priv *priv)
iwl_rfkill_set_hw_state(priv);
iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
- rc = iwl4965_hw_nic_init(priv);
- if (rc) {
- IWL_ERROR("Unable to int nic\n");
- return rc;
+ ret = priv->cfg->ops->lib->hw_nic_init(priv);
+ if (ret) {
+ IWL_ERROR("Unable to init nic\n");
+ return ret;
}
/* make sure rfkill handshake bits are cleared */
@@ -5906,10 +5593,10 @@ static int __iwl4965_up(struct iwl_priv *priv)
/* load bootstrap state machine,
* load bootstrap program into processor's memory,
* prepare to load the "initialize" uCode */
- rc = iwl4965_load_bsm(priv);
+ ret = priv->cfg->ops->lib->load_ucode(priv);
- if (rc) {
- IWL_ERROR("Unable to set up bootstrap uCode: %d\n", rc);
+ if (ret) {
+ IWL_ERROR("Unable to set up bootstrap uCode: %d\n", ret);
continue;
}
@@ -6146,7 +5833,7 @@ static void iwl4965_bg_request_scan(struct work_struct *data)
}
scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK;
- scan->tx_cmd.sta_id = priv->hw_setting.bcast_sta_id;
+ scan->tx_cmd.sta_id = priv->hw_params.bcast_sta_id;
scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
@@ -6272,10 +5959,8 @@ static void iwl4965_bg_rx_replenish(struct work_struct *data)
#define IWL_DELAY_NEXT_SCAN (HZ*2)
-static void iwl4965_bg_post_associate(struct work_struct *data)
+static void iwl4965_post_associate(struct iwl_priv *priv)
{
- struct iwl_priv *priv = container_of(data, struct iwl_priv,
- post_associate.work);
struct ieee80211_conf *conf = NULL;
int ret = 0;
DECLARE_MAC_BUF(mac);
@@ -6293,12 +5978,10 @@ static void iwl4965_bg_post_associate(struct work_struct *data)
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
return;
- mutex_lock(&priv->mutex);
- if (!priv->vif || !priv->is_open) {
- mutex_unlock(&priv->mutex);
+ if (!priv->vif || !priv->is_open)
return;
- }
+
iwl4965_scan_cancel_timeout(priv, 200);
conf = ieee80211_get_hw_conf(priv->hw);
@@ -6382,7 +6065,18 @@ static void iwl4965_bg_post_associate(struct work_struct *data)
/* we have just associated, don't start scan too early */
priv->next_scan_jiffies = jiffies + IWL_DELAY_NEXT_SCAN;
+}
+
+
+static void iwl4965_bg_post_associate(struct work_struct *data)
+{
+ struct iwl_priv *priv = container_of(data, struct iwl_priv,
+ post_associate.work);
+
+ mutex_lock(&priv->mutex);
+ iwl4965_post_associate(priv);
mutex_unlock(&priv->mutex);
+
}
static void iwl4965_bg_abort_scan(struct work_struct *work)
@@ -7004,6 +6698,10 @@ static void iwl4965_bss_info_changed(struct ieee80211_hw *hw,
if (changes & BSS_CHANGED_ASSOC) {
IWL_DEBUG_MAC80211("ASSOC %d\n", bss_conf->assoc);
+ /* This should never happen as this function should
+ * never be called from interrupt context. */
+ if (WARN_ON_ONCE(in_interrupt()))
+ return;
if (bss_conf->assoc) {
priv->assoc_id = bss_conf->aid;
priv->beacon_int = bss_conf->beacon_int;
@@ -7011,14 +6709,16 @@ static void iwl4965_bss_info_changed(struct ieee80211_hw *hw,
priv->assoc_capability = bss_conf->assoc_capability;
priv->next_scan_jiffies = jiffies +
IWL_DELAY_NEXT_SCAN_AFTER_ASSOC;
- queue_work(priv->workqueue, &priv->post_associate.work);
+ mutex_lock(&priv->mutex);
+ iwl4965_post_associate(priv);
+ mutex_unlock(&priv->mutex);
} else {
priv->assoc_id = 0;
IWL_DEBUG_MAC80211("DISASSOC %d\n", bss_conf->assoc);
}
} else if (changes && iwl_is_associated(priv) && priv->assoc_id) {
IWL_DEBUG_MAC80211("Associated Changes %d\n", changes);
- iwl4965_send_rxon_assoc(priv);
+ iwl_send_rxon_assoc(priv);
}
}
@@ -7106,13 +6806,11 @@ static void iwl4965_mac_update_tkip_key(struct ieee80211_hw *hw,
key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
key_flags &= ~STA_KEY_FLG_INVALID;
- if (sta_id == priv->hw_setting.bcast_sta_id)
+ if (sta_id == priv->hw_params.bcast_sta_id)
key_flags |= STA_KEY_MULTICAST_MSK;
spin_lock_irqsave(&priv->sta_lock, flags);
- priv->stations[sta_id].sta.key.key_offset =
- (sta_id % STA_KEY_MAX_NUM);/* FIXME */
priv->stations[sta_id].sta.key.key_flags = key_flags;
priv->stations[sta_id].sta.key.tkip_rx_tsc_byte2 = (u8) iv32;
@@ -7138,11 +6836,11 @@ static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
DECLARE_MAC_BUF(mac);
int ret = 0;
u8 sta_id = IWL_INVALID_STATION;
- u8 static_key;
+ u8 is_default_wep_key = 0;
IWL_DEBUG_MAC80211("enter\n");
- if (!priv->cfg->mod_params->hw_crypto) {
+ if (priv->cfg->mod_params->sw_crypto) {
IWL_DEBUG_MAC80211("leave - hwcrypto disabled\n");
return -EOPNOTSUPP;
}
@@ -7151,35 +6849,44 @@ static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
/* only support pairwise keys */
return -EOPNOTSUPP;
- /* FIXME: need to differenciate between static and dynamic key
- * in the level of mac80211 */
- static_key = !iwl_is_associated(priv);
+ sta_id = iwl4965_hw_find_station(priv, addr);
+ if (sta_id == IWL_INVALID_STATION) {
+ IWL_DEBUG_MAC80211("leave - %s not in station map.\n",
+ print_mac(mac, addr));
+ return -EINVAL;
- if (!static_key) {
- sta_id = iwl4965_hw_find_station(priv, addr);
- if (sta_id == IWL_INVALID_STATION) {
- IWL_DEBUG_MAC80211("leave - %s not in station map.\n",
- print_mac(mac, addr));
- return -EINVAL;
- }
}
+ mutex_lock(&priv->mutex);
iwl4965_scan_cancel_timeout(priv, 100);
+ mutex_unlock(&priv->mutex);
+
+ /* If we are getting WEP group key and we didn't receive any key mapping
+ * so far, we are in legacy wep mode (group key only), otherwise we are
+ * in 1X mode.
+ * In legacy wep mode, we use another host command to the uCode */
+ if (key->alg == ALG_WEP && sta_id == priv->hw_params.bcast_sta_id &&
+ priv->iw_mode != IEEE80211_IF_TYPE_AP) {
+ if (cmd == SET_KEY)
+ is_default_wep_key = !priv->key_mapping_key;
+ else
+ is_default_wep_key = priv->default_wep_key;
+ }
switch (cmd) {
case SET_KEY:
- if (static_key)
- ret = iwl4965_set_static_key(priv, key);
+ if (is_default_wep_key)
+ ret = iwl_set_default_wep_key(priv, key);
else
- ret = iwl4965_set_dynamic_key(priv, key, sta_id);
+ ret = iwl_set_dynamic_key(priv, key, sta_id);
IWL_DEBUG_MAC80211("enable hwcrypto key\n");
break;
case DISABLE_KEY:
- if (static_key)
- ret = iwl4965_remove_static_key(priv);
+ if (is_default_wep_key)
+ ret = iwl_remove_default_wep_key(priv, key);
else
- ret = iwl4965_clear_sta_key_info(priv, sta_id);
+ ret = iwl_remove_dynamic_key(priv, sta_id);
IWL_DEBUG_MAC80211("disable hwcrypto key\n");
break;
@@ -7776,7 +7483,7 @@ static ssize_t show_statistics(struct device *d,
return -EAGAIN;
mutex_lock(&priv->mutex);
- rc = iwl4965_send_statistics_request(priv);
+ rc = iwl_send_statistics_request(priv, 0);
mutex_unlock(&priv->mutex);
if (rc) {
@@ -8084,8 +7791,8 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
* 5. Setup HW constants
************************/
/* Device-specific setup */
- if (iwl4965_hw_set_hw_setting(priv)) {
- IWL_ERROR("failed to set hw settings\n");
+ if (priv->cfg->ops->lib->set_hw_params(priv)) {
+ IWL_ERROR("failed to set hw parameters\n");
goto out_iounmap;
}
@@ -8095,7 +7802,7 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
err = iwl_setup(priv);
if (err)
- goto out_unset_hw_settings;
+ goto out_unset_hw_params;
/* At this point both hw and priv are initialized. */
/**********************************
@@ -8121,7 +7828,7 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
err = sysfs_create_group(&pdev->dev.kobj, &iwl4965_attribute_group);
if (err) {
IWL_ERROR("failed to create sysfs device attributes\n");
- goto out_unset_hw_settings;
+ goto out_unset_hw_params;
}
err = iwl_dbgfs_register(priv, DRV_NAME);
@@ -8145,8 +7852,8 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
out_remove_sysfs:
sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group);
- out_unset_hw_settings:
- iwl4965_unset_hw_setting(priv);
+ out_unset_hw_params:
+ iwl4965_unset_hw_params(priv);
out_iounmap:
pci_iounmap(pdev, priv->hw_base);
out_pci_release_regions:
@@ -8208,7 +7915,7 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev)
iwl4965_rx_queue_free(priv, &priv->rxq);
iwl4965_hw_txq_ctx_free(priv);
- iwl4965_unset_hw_setting(priv);
+ iwl4965_unset_hw_params(priv);
iwlcore_clear_stations_table(priv);
@@ -8273,9 +7980,17 @@ static int iwl4965_pci_resume(struct pci_dev *pdev)
*
*****************************************************************************/
-static struct pci_driver iwl4965_driver = {
+/* Hardware specific file defines the PCI IDs table for that hardware module */
+static struct pci_device_id iwl_hw_card_ids[] = {
+ {IWL_PCI_DEVICE(0x4229, PCI_ANY_ID, iwl4965_agn_cfg)},
+ {IWL_PCI_DEVICE(0x4230, PCI_ANY_ID, iwl4965_agn_cfg)},
+ {0}
+};
+MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids);
+
+static struct pci_driver iwl_driver = {
.name = DRV_NAME,
- .id_table = iwl4965_hw_card_ids,
+ .id_table = iwl_hw_card_ids,
.probe = iwl4965_pci_probe,
.remove = __devexit_p(iwl4965_pci_remove),
#ifdef CONFIG_PM
@@ -8297,13 +8012,13 @@ static int __init iwl4965_init(void)
return ret;
}
- ret = pci_register_driver(&iwl4965_driver);
+ ret = pci_register_driver(&iwl_driver);
if (ret) {
IWL_ERROR("Unable to initialize PCI module\n");
goto error_register;
}
#ifdef CONFIG_IWLWIFI_DEBUG
- ret = driver_create_file(&iwl4965_driver.driver, &driver_attr_debug_level);
+ ret = driver_create_file(&iwl_driver.driver, &driver_attr_debug_level);
if (ret) {
IWL_ERROR("Unable to create driver sysfs file\n");
goto error_debug;
@@ -8314,7 +8029,7 @@ static int __init iwl4965_init(void)
#ifdef CONFIG_IWLWIFI_DEBUG
error_debug:
- pci_unregister_driver(&iwl4965_driver);
+ pci_unregister_driver(&iwl_driver);
#endif
error_register:
iwl4965_rate_control_unregister();
@@ -8324,9 +8039,9 @@ error_register:
static void __exit iwl4965_exit(void)
{
#ifdef CONFIG_IWLWIFI_DEBUG
- driver_remove_file(&iwl4965_driver.driver, &driver_attr_debug_level);
+ driver_remove_file(&iwl_driver.driver, &driver_attr_debug_level);
#endif
- pci_unregister_driver(&iwl4965_driver);
+ pci_unregister_driver(&iwl_driver);
iwl4965_rate_control_unregister();
}