From 2f73d7c2b1f92e34aceee21740ec5fb9b8262ecb Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 3 Feb 2012 13:06:57 -0800 Subject: [PATCH 01/26] iwlwifi: log as error when error detected A lot of error conditions in testmode log as IWL_DEBUG_INFO which is not logged by default. Change it Signed-off-by: Wey-Yi Guy --- drivers/net/wireless/iwlwifi/iwl-testmode.c | 122 ++++++++------------ 1 file changed, 51 insertions(+), 71 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-testmode.c b/drivers/net/wireless/iwlwifi/iwl-testmode.c index df7ab332c833..e42e0768880b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-testmode.c +++ b/drivers/net/wireless/iwlwifi/iwl-testmode.c @@ -172,7 +172,7 @@ static void iwl_testmode_ucode_rx_pkt(struct iwl_priv *priv, skb = cfg80211_testmode_alloc_event_skb(hw->wiphy, 20 + length, GFP_ATOMIC); if (skb == NULL) { - IWL_DEBUG_INFO(priv, + IWL_ERR(priv, "Run out of memory for messages to user space ?\n"); return; } @@ -183,7 +183,7 @@ static void iwl_testmode_ucode_rx_pkt(struct iwl_priv *priv, nla_put_failure: kfree_skb(skb); - IWL_DEBUG_INFO(priv, "Ouch, overran buffer, check allocation!\n"); + IWL_ERR(priv, "Ouch, overran buffer, check allocation!\n"); } void iwl_testmode_init(struct iwl_priv *priv) @@ -252,8 +252,7 @@ static int iwl_testmode_ucode(struct ieee80211_hw *hw, struct nlattr **tb) if (!tb[IWL_TM_ATTR_UCODE_CMD_ID] || !tb[IWL_TM_ATTR_UCODE_CMD_DATA]) { - IWL_DEBUG_INFO(priv, - "Error finding ucode command mandatory fields\n"); + IWL_ERR(priv, "Missing ucode command mandatory fields\n"); return -ENOMSG; } @@ -295,7 +294,7 @@ static int iwl_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb) int status = 0; if (!tb[IWL_TM_ATTR_REG_OFFSET]) { - IWL_DEBUG_INFO(priv, "Error finding register offset\n"); + IWL_ERR(priv, "Missing register offset\n"); return -ENOMSG; } ofs = nla_get_u32(tb[IWL_TM_ATTR_REG_OFFSET]); @@ -309,7 +308,7 @@ static int iwl_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb) cmd == IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE32 || cmd == IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE8) && (ofs >= FH_MEM_UPPER_BOUND)) { - IWL_DEBUG_INFO(priv, "offset out of segment (0x0 - 0x%x)\n", + IWL_ERR(priv, "offset out of segment (0x0 - 0x%x)\n", FH_MEM_UPPER_BOUND); return -EINVAL; } @@ -321,19 +320,17 @@ static int iwl_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb) skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20); if (!skb) { - IWL_DEBUG_INFO(priv, "Error allocating memory\n"); + IWL_ERR(priv, "Memory allocation fail\n"); return -ENOMEM; } NLA_PUT_U32(skb, IWL_TM_ATTR_REG_VALUE32, val32); status = cfg80211_testmode_reply(skb); if (status < 0) - IWL_DEBUG_INFO(priv, - "Error sending msg : %d\n", status); + IWL_ERR(priv, "Error sending msg : %d\n", status); break; case IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE32: if (!tb[IWL_TM_ATTR_REG_VALUE32]) { - IWL_DEBUG_INFO(priv, - "Error finding value to write\n"); + IWL_ERR(priv, "Missing value to write\n"); return -ENOMSG; } else { val32 = nla_get_u32(tb[IWL_TM_ATTR_REG_VALUE32]); @@ -343,7 +340,7 @@ static int iwl_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb) break; case IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE8: if (!tb[IWL_TM_ATTR_REG_VALUE8]) { - IWL_DEBUG_INFO(priv, "Error finding value to write\n"); + IWL_ERR(priv, "Missing value to write\n"); return -ENOMSG; } else { val8 = nla_get_u8(tb[IWL_TM_ATTR_REG_VALUE8]); @@ -357,19 +354,17 @@ static int iwl_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb) skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20); if (!skb) { - IWL_DEBUG_INFO(priv, "Error allocating memory\n"); + IWL_ERR(priv, "Memory allocation fail\n"); return -ENOMEM; } NLA_PUT_U32(skb, IWL_TM_ATTR_REG_VALUE32, val32); status = cfg80211_testmode_reply(skb); if (status < 0) - IWL_DEBUG_INFO(priv, - "Error sending msg : %d\n", status); + IWL_ERR(priv, "Error sending msg : %d\n", status); break; case IWL_TM_CMD_APP2DEV_INDIRECT_REG_WRITE32: if (!tb[IWL_TM_ATTR_REG_VALUE32]) { - IWL_DEBUG_INFO(priv, - "Error finding value to write\n"); + IWL_ERR(priv, "Missing value to write\n"); return -ENOMSG; } else { val32 = nla_get_u32(tb[IWL_TM_ATTR_REG_VALUE32]); @@ -378,7 +373,7 @@ static int iwl_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb) } break; default: - IWL_DEBUG_INFO(priv, "Unknown testmode register command ID\n"); + IWL_ERR(priv, "Unknown testmode register command ID\n"); return -ENOSYS; } @@ -400,14 +395,13 @@ static int iwl_testmode_cfg_init_calib(struct iwl_priv *priv) NULL, NULL); ret = iwl_init_alive_start(trans(priv)); if (ret) { - IWL_DEBUG_INFO(priv, - "Error configuring init calibration: %d\n", ret); + IWL_ERR(priv, "Fail init calibration: %d\n", ret); goto cfg_init_calib_error; } ret = iwl_wait_notification(priv->shrd, &calib_wait, 2 * HZ); if (ret) - IWL_DEBUG_INFO(priv, "Error detecting" + IWL_ERR(priv, "Error detecting" " CALIBRATION_COMPLETE_NOTIFICATION: %d\n", ret); return ret; @@ -448,8 +442,7 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb) skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, rsp_data_len + 20); if (!skb) { - IWL_DEBUG_INFO(priv, - "Error allocating memory\n"); + IWL_ERR(priv, "Memory allocation fail\n"); return -ENOMEM; } NLA_PUT_U32(skb, IWL_TM_ATTR_COMMAND, @@ -458,15 +451,13 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb) rsp_data_len, rsp_data_ptr); status = cfg80211_testmode_reply(skb); if (status < 0) - IWL_DEBUG_INFO(priv, "Error sending msg : %d\n", - status); + IWL_ERR(priv, "Error sending msg : %d\n", status); break; case IWL_TM_CMD_APP2DEV_LOAD_INIT_FW: status = iwl_load_ucode_wait_alive(trans, IWL_UCODE_INIT); if (status) - IWL_DEBUG_INFO(priv, - "Error loading init ucode: %d\n", status); + IWL_ERR(priv, "Error loading init ucode: %d\n", status); break; case IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB: @@ -477,13 +468,13 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb) case IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW: status = iwl_load_ucode_wait_alive(trans, IWL_UCODE_REGULAR); if (status) { - IWL_DEBUG_INFO(priv, + IWL_ERR(priv, "Error loading runtime ucode: %d\n", status); break; } status = iwl_alive_start(priv); if (status) - IWL_DEBUG_INFO(priv, + IWL_ERR(priv, "Error starting the device: %d\n", status); break; @@ -492,13 +483,13 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb) iwl_trans_stop_device(trans); status = iwl_load_ucode_wait_alive(trans, IWL_UCODE_WOWLAN); if (status) { - IWL_DEBUG_INFO(priv, + IWL_ERR(priv, "Error loading WOWLAN ucode: %d\n", status); break; } status = iwl_alive_start(priv); if (status) - IWL_DEBUG_INFO(priv, + IWL_ERR(priv, "Error starting the device: %d\n", status); break; @@ -507,8 +498,7 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb) skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, cfg(priv)->base_params->eeprom_size + 20); if (!skb) { - IWL_DEBUG_INFO(priv, - "Error allocating memory\n"); + IWL_ERR(priv, "Memory allocation fail\n"); return -ENOMEM; } NLA_PUT_U32(skb, IWL_TM_ATTR_COMMAND, @@ -518,17 +508,15 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb) priv->shrd->eeprom); status = cfg80211_testmode_reply(skb); if (status < 0) - IWL_DEBUG_INFO(priv, - "Error sending msg : %d\n", - status); + IWL_ERR(priv, "Error sending msg : %d\n", + status); } else return -EFAULT; break; case IWL_TM_CMD_APP2DEV_FIXRATE_REQ: if (!tb[IWL_TM_ATTR_FIXRATE]) { - IWL_DEBUG_INFO(priv, - "Error finding fixrate setting\n"); + IWL_ERR(priv, "Missing fixrate setting\n"); return -ENOMSG; } priv->tm_fixed_rate = nla_get_u32(tb[IWL_TM_ATTR_FIXRATE]); @@ -539,14 +527,13 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb) skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20); if (!skb) { - IWL_DEBUG_INFO(priv, "Error allocating memory\n"); + IWL_ERR(priv, "Memory allocation fail\n"); return -ENOMEM; } NLA_PUT_U32(skb, IWL_TM_ATTR_FW_VERSION, priv->ucode_ver); status = cfg80211_testmode_reply(skb); if (status < 0) - IWL_DEBUG_INFO(priv, - "Error sending msg : %d\n", status); + IWL_ERR(priv, "Error sending msg : %d\n", status); break; case IWL_TM_CMD_APP2DEV_GET_DEVICE_ID: @@ -555,20 +542,19 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb) skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20); if (!skb) { - IWL_DEBUG_INFO(priv, "Error allocating memory\n"); + IWL_ERR(priv, "Memory allocation fail\n"); return -ENOMEM; } NLA_PUT_U32(skb, IWL_TM_ATTR_DEVICE_ID, devid); status = cfg80211_testmode_reply(skb); if (status < 0) - IWL_DEBUG_INFO(priv, - "Error sending msg : %d\n", status); + IWL_ERR(priv, "Error sending msg : %d\n", status); break; case IWL_TM_CMD_APP2DEV_GET_FW_INFO: skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20 + 8); if (!skb) { - IWL_DEBUG_INFO(priv, "Error allocating memory\n"); + IWL_ERR(priv, "Memory allocation fail\n"); return -ENOMEM; } switch (priv->shrd->ucode_type) { @@ -585,10 +571,10 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb) data_size = trans(priv)->ucode_wowlan.data.len; break; case IWL_UCODE_NONE: - IWL_DEBUG_INFO(priv, "The uCode has not been loaded\n"); + IWL_ERR(priv, "No uCode has not been loaded\n"); break; default: - IWL_DEBUG_INFO(priv, "Unsupported uCode type\n"); + IWL_ERR(priv, "Unsupported uCode type\n"); break; } NLA_PUT_U32(skb, IWL_TM_ATTR_FW_TYPE, priv->shrd->ucode_type); @@ -596,12 +582,11 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb) NLA_PUT_U32(skb, IWL_TM_ATTR_FW_DATA_SIZE, data_size); status = cfg80211_testmode_reply(skb); if (status < 0) - IWL_DEBUG_INFO(priv, - "Error sending msg : %d\n", status); + IWL_ERR(priv, "Error sending msg : %d\n", status); break; default: - IWL_DEBUG_INFO(priv, "Unknown testmode driver command ID\n"); + IWL_ERR(priv, "Unknown testmode driver command ID\n"); return -ENOSYS; } return status; @@ -664,8 +649,7 @@ static int iwl_testmode_trace(struct ieee80211_hw *hw, struct nlattr **tb) skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, sizeof(priv->testmode_trace.dma_addr) + 20); if (!skb) { - IWL_DEBUG_INFO(priv, - "Error allocating memory\n"); + IWL_ERR(priv, "Memory allocation fail\n"); iwl_trace_cleanup(priv); return -ENOMEM; } @@ -674,9 +658,7 @@ static int iwl_testmode_trace(struct ieee80211_hw *hw, struct nlattr **tb) (u64 *)&priv->testmode_trace.dma_addr); status = cfg80211_testmode_reply(skb); if (status < 0) { - IWL_DEBUG_INFO(priv, - "Error sending msg : %d\n", - status); + IWL_ERR(priv, "Error sending msg : %d\n", status); } priv->testmode_trace.num_chunks = DIV_ROUND_UP(priv->testmode_trace.buff_size, @@ -687,7 +669,7 @@ static int iwl_testmode_trace(struct ieee80211_hw *hw, struct nlattr **tb) iwl_trace_cleanup(priv); break; default: - IWL_DEBUG_INFO(priv, "Unknown testmode mem command ID\n"); + IWL_ERR(priv, "Unknown testmode mem command ID\n"); return -ENOSYS; } return status; @@ -752,7 +734,7 @@ static int iwl_testmode_ownership(struct ieee80211_hw *hw, struct nlattr **tb) u8 owner; if (!tb[IWL_TM_ATTR_UCODE_OWNER]) { - IWL_DEBUG_INFO(priv, "Error finding ucode owner\n"); + IWL_ERR(priv, "Missing ucode owner\n"); return -ENOMSG; } @@ -760,7 +742,7 @@ static int iwl_testmode_ownership(struct ieee80211_hw *hw, struct nlattr **tb) if ((owner == IWL_OWNERSHIP_DRIVER) || (owner == IWL_OWNERSHIP_TM)) priv->shrd->ucode_owner = owner; else { - IWL_DEBUG_INFO(priv, "Invalid owner\n"); + IWL_ERR(priv, "Invalid owner\n"); return -EINVAL; } return 0; @@ -791,12 +773,12 @@ static int iwl_testmode_sram(struct ieee80211_hw *hw, struct nlattr **tb) return -EBUSY; if (!tb[IWL_TM_ATTR_SRAM_ADDR]) { - IWL_DEBUG_INFO(priv, "Error finding SRAM offset address\n"); + IWL_ERR(priv, "Missing SRAM offset address\n"); return -ENOMSG; } ofs = nla_get_u32(tb[IWL_TM_ATTR_SRAM_ADDR]); if (!tb[IWL_TM_ATTR_SRAM_SIZE]) { - IWL_DEBUG_INFO(priv, "Error finding size for SRAM reading\n"); + IWL_ERR(priv, "Missing size for SRAM reading\n"); return -ENOMSG; } size = nla_get_u32(tb[IWL_TM_ATTR_SRAM_SIZE]); @@ -811,10 +793,10 @@ static int iwl_testmode_sram(struct ieee80211_hw *hw, struct nlattr **tb) maxsize = trans(priv)->ucode_wowlan.data.len; break; case IWL_UCODE_NONE: - IWL_ERR(priv, "Error, uCode does not been loaded\n"); + IWL_ERR(priv, "uCode does not been loaded\n"); return -ENOSYS; default: - IWL_ERR(priv, "Error, unsupported uCode type\n"); + IWL_ERR(priv, "unsupported uCode type\n"); return -ENOSYS; } if ((ofs + size) > (maxsize + SRAM_DATA_SEG_OFFSET)) { @@ -825,7 +807,7 @@ static int iwl_testmode_sram(struct ieee80211_hw *hw, struct nlattr **tb) priv->testmode_sram.buff_addr = kmalloc(priv->testmode_sram.buff_size, GFP_KERNEL); if (priv->testmode_sram.buff_addr == NULL) { - IWL_ERR(priv, "Error allocating memory\n"); + IWL_ERR(priv, "Memory allocation fail\n"); return -ENOMEM; } _iwl_read_targ_mem_words(trans(priv), ofs, @@ -898,14 +880,13 @@ int iwlagn_mac_testmode_cmd(struct ieee80211_hw *hw, void *data, int len) result = nla_parse(tb, IWL_TM_ATTR_MAX - 1, data, len, iwl_testmode_gnl_msg_policy); if (result != 0) { - IWL_DEBUG_INFO(priv, - "Error parsing the gnl message : %d\n", result); + IWL_ERR(priv, "Error parsing the gnl message : %d\n", result); return result; } /* IWL_TM_ATTR_COMMAND is absolutely mandatory */ if (!tb[IWL_TM_ATTR_COMMAND]) { - IWL_DEBUG_INFO(priv, "Error finding testmode command type\n"); + IWL_ERR(priv, "Missing testmode command type\n"); return -ENOMSG; } /* in case multiple accesses to the device happens */ @@ -956,7 +937,7 @@ int iwlagn_mac_testmode_cmd(struct ieee80211_hw *hw, void *data, int len) break; default: - IWL_DEBUG_INFO(priv, "Unknown testmode command\n"); + IWL_ERR(priv, "Unknown testmode command\n"); result = -ENOSYS; break; } @@ -981,15 +962,14 @@ int iwlagn_mac_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *skb, result = nla_parse(tb, IWL_TM_ATTR_MAX - 1, data, len, iwl_testmode_gnl_msg_policy); if (result) { - IWL_DEBUG_INFO(priv, - "Error parsing the gnl message : %d\n", result); + IWL_ERR(priv, + "Error parsing the gnl message : %d\n", result); return result; } /* IWL_TM_ATTR_COMMAND is absolutely mandatory */ if (!tb[IWL_TM_ATTR_COMMAND]) { - IWL_DEBUG_INFO(priv, - "Error finding testmode command type\n"); + IWL_ERR(priv, "Missing testmode command type\n"); return -ENOMSG; } cmd = nla_get_u32(tb[IWL_TM_ATTR_COMMAND]); From 6c55f5ed3a23ba60a0e7809a39ad7361ae00a764 Mon Sep 17 00:00:00 2001 From: Amit Beka Date: Wed, 25 Jan 2012 13:30:27 +0200 Subject: [PATCH 02/26] iwlwifi: testmode new indirect RW API Replaced the old SRAM and periphery indirect access functions with a unified indirect memory access functions. These include new IWL_TM_CMDs for buffer read/write/dump which replace the SRAM read/dump commands, but the API for IWL_TM_CMD_INDIRECT_REG read/write will now not be supported (returns error). This also handles writing to periphery registers in 1-3 bytes. Requires the corresponding patch in the library for the API change. Signed-off-by: Amit Beka Signed-off-by: Wey-Yi Guy --- drivers/net/wireless/iwlwifi/iwl-dev.h | 6 +- drivers/net/wireless/iwlwifi/iwl-testmode.c | 226 ++++++++++++-------- drivers/net/wireless/iwlwifi/iwl-testmode.h | 53 ++--- 3 files changed, 163 insertions(+), 122 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index aa99457c3a52..0e8f13705dbe 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -696,11 +696,11 @@ struct iwl_testmode_trace { dma_addr_t dma_addr; bool trace_enabled; }; -struct iwl_testmode_sram { +struct iwl_testmode_mem { u32 buff_size; u32 num_chunks; u8 *buff_addr; - bool sram_readed; + bool read_in_progress; }; #endif @@ -964,7 +964,7 @@ struct iwl_priv { bool led_registered; #ifdef CONFIG_IWLWIFI_DEVICE_TESTMODE struct iwl_testmode_trace testmode_trace; - struct iwl_testmode_sram testmode_sram; + struct iwl_testmode_mem testmode_mem; u32 tm_fixed_rate; #endif diff --git a/drivers/net/wireless/iwlwifi/iwl-testmode.c b/drivers/net/wireless/iwlwifi/iwl-testmode.c index e42e0768880b..debc9ababbfa 100644 --- a/drivers/net/wireless/iwlwifi/iwl-testmode.c +++ b/drivers/net/wireless/iwlwifi/iwl-testmode.c @@ -81,6 +81,13 @@ #include "iwl-bus.h" #include "iwl-fh.h" + +/* Periphery registers absolute lower bound. This is used in order to + * differentiate registery access through HBUS_TARG_PRPH_* and + * HBUS_TARG_MEM_* accesses. + */ +#define IWL_TM_ABS_PRPH_START (0xA00000) + /* The TLVs used in the gnl message policy between the kernel module and * user space application. iwl_testmode_gnl_msg_policy is to be carried * through the NL80211_CMD_TESTMODE channel regulated by nl80211. @@ -110,9 +117,9 @@ struct nla_policy iwl_testmode_gnl_msg_policy[IWL_TM_ATTR_MAX] = { [IWL_TM_ATTR_UCODE_OWNER] = { .type = NLA_U8, }, - [IWL_TM_ATTR_SRAM_ADDR] = { .type = NLA_U32, }, - [IWL_TM_ATTR_SRAM_SIZE] = { .type = NLA_U32, }, - [IWL_TM_ATTR_SRAM_DUMP] = { .type = NLA_UNSPEC, }, + [IWL_TM_ATTR_MEM_ADDR] = { .type = NLA_U32, }, + [IWL_TM_ATTR_BUFFER_SIZE] = { .type = NLA_U32, }, + [IWL_TM_ATTR_BUFFER_DUMP] = { .type = NLA_UNSPEC, }, [IWL_TM_ATTR_FW_VERSION] = { .type = NLA_U32, }, [IWL_TM_ATTR_DEVICE_ID] = { .type = NLA_U32, }, @@ -190,17 +197,17 @@ void iwl_testmode_init(struct iwl_priv *priv) { priv->pre_rx_handler = iwl_testmode_ucode_rx_pkt; priv->testmode_trace.trace_enabled = false; - priv->testmode_sram.sram_readed = false; + priv->testmode_mem.read_in_progress = false; } -static void iwl_sram_cleanup(struct iwl_priv *priv) +static void iwl_mem_cleanup(struct iwl_priv *priv) { - if (priv->testmode_sram.sram_readed) { - kfree(priv->testmode_sram.buff_addr); - priv->testmode_sram.buff_addr = NULL; - priv->testmode_sram.buff_size = 0; - priv->testmode_sram.num_chunks = 0; - priv->testmode_sram.sram_readed = false; + if (priv->testmode_mem.read_in_progress) { + kfree(priv->testmode_mem.buff_addr); + priv->testmode_mem.buff_addr = NULL; + priv->testmode_mem.buff_size = 0; + priv->testmode_mem.num_chunks = 0; + priv->testmode_mem.read_in_progress = false; } } @@ -226,7 +233,7 @@ static void iwl_trace_cleanup(struct iwl_priv *priv) void iwl_testmode_cleanup(struct iwl_priv *priv) { iwl_trace_cleanup(priv); - iwl_sram_cleanup(priv); + iwl_mem_cleanup(priv); } /* @@ -348,30 +355,6 @@ static int iwl_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb) iwl_write8(trans(priv), ofs, val8); } break; - case IWL_TM_CMD_APP2DEV_INDIRECT_REG_READ32: - val32 = iwl_read_prph(trans(priv), ofs); - IWL_INFO(priv, "32bit value to read 0x%x\n", val32); - - skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20); - if (!skb) { - IWL_ERR(priv, "Memory allocation fail\n"); - return -ENOMEM; - } - NLA_PUT_U32(skb, IWL_TM_ATTR_REG_VALUE32, val32); - status = cfg80211_testmode_reply(skb); - if (status < 0) - IWL_ERR(priv, "Error sending msg : %d\n", status); - break; - case IWL_TM_CMD_APP2DEV_INDIRECT_REG_WRITE32: - if (!tb[IWL_TM_ATTR_REG_VALUE32]) { - IWL_ERR(priv, "Missing value to write\n"); - return -ENOMSG; - } else { - val32 = nla_get_u32(tb[IWL_TM_ATTR_REG_VALUE32]); - IWL_INFO(priv, "32bit value to write 0x%x\n", val32); - iwl_write_prph(trans(priv), ofs, val32); - } - break; default: IWL_ERR(priv, "Unknown testmode register command ID\n"); return -ENOSYS; @@ -748,6 +731,81 @@ static int iwl_testmode_ownership(struct ieee80211_hw *hw, struct nlattr **tb) return 0; } +static int iwl_testmode_indirect_read(struct iwl_priv *priv, u32 addr, u32 size) +{ + struct iwl_trans *trans = trans(priv); + unsigned long flags; + int i; + + if (size & 0x3) + return -EINVAL; + priv->testmode_mem.buff_size = size; + priv->testmode_mem.buff_addr = + kmalloc(priv->testmode_mem.buff_size, GFP_KERNEL); + if (priv->testmode_mem.buff_addr == NULL) + return -ENOMEM; + + /* Hard-coded periphery absolute address */ + if (IWL_TM_ABS_PRPH_START <= addr && + addr < IWL_TM_ABS_PRPH_START + PRPH_END) { + spin_lock_irqsave(&trans->reg_lock, flags); + iwl_grab_nic_access(trans); + iwl_write32(trans, HBUS_TARG_PRPH_RADDR, addr); + for (i = 0; i < size; i += 4) + priv->testmode_mem.buff_addr[i] = + iwl_read32(trans, HBUS_TARG_PRPH_RDAT); + iwl_release_nic_access(trans); + spin_unlock_irqrestore(&trans->reg_lock, flags); + } else { /* target memory (SRAM) */ + _iwl_read_targ_mem_words(trans, addr, + priv->testmode_mem.buff_addr, + priv->testmode_mem.buff_size / 4); + } + + priv->testmode_mem.num_chunks = + DIV_ROUND_UP(priv->testmode_mem.buff_size, DUMP_CHUNK_SIZE); + priv->testmode_mem.read_in_progress = true; + return 0; + +} + +static int iwl_testmode_indirect_write(struct iwl_priv *priv, u32 addr, + u32 size, unsigned char *buf) +{ + struct iwl_trans *trans = trans(priv); + u32 val, i; + unsigned long flags; + + if (IWL_TM_ABS_PRPH_START <= addr && + addr < IWL_TM_ABS_PRPH_START + PRPH_END) { + /* Periphery writes can be 1-3 bytes long, or DWORDs */ + if (size < 4) { + memcpy(&val, buf, size); + spin_lock_irqsave(&trans->reg_lock, flags); + iwl_grab_nic_access(trans); + iwl_write32(trans, HBUS_TARG_PRPH_WADDR, + (addr & 0x0000FFFF) | (size << 24)); + iwl_write32(trans, HBUS_TARG_PRPH_WDAT, val); + iwl_release_nic_access(trans); + /* needed after consecutive writes w/o read */ + mmiowb(); + spin_unlock_irqrestore(&trans->reg_lock, flags); + } else { + if (size % 4) + return -EINVAL; + for (i = 0; i < size; i += 4) + iwl_write_prph(trans, addr+i, + *(u32 *)buf+i); + } + } else if (iwlagn_hw_valid_rtc_data_addr(addr) || + (IWLAGN_RTC_INST_LOWER_BOUND <= addr && + addr < IWLAGN_RTC_INST_UPPER_BOUND)) { + _iwl_write_targ_mem_words(trans, addr, buf, size/4); + } else + return -EINVAL; + return 0; +} + /* * This function handles the user application commands for SRAM data dump * @@ -764,82 +822,60 @@ static int iwl_testmode_ownership(struct ieee80211_hw *hw, struct nlattr **tb) * @hw: ieee80211_hw object that represents the device * @tb: gnl message fields from the user space */ -static int iwl_testmode_sram(struct ieee80211_hw *hw, struct nlattr **tb) +static int iwl_testmode_indirect_mem(struct ieee80211_hw *hw, + struct nlattr **tb) { struct iwl_priv *priv = hw->priv; - u32 ofs, size, maxsize; + u32 addr, size, cmd; + unsigned char *buf; - if (priv->testmode_sram.sram_readed) + /* Both read and write should be blocked, for atomicity */ + if (priv->testmode_mem.read_in_progress) return -EBUSY; - if (!tb[IWL_TM_ATTR_SRAM_ADDR]) { - IWL_ERR(priv, "Missing SRAM offset address\n"); + cmd = nla_get_u32(tb[IWL_TM_ATTR_COMMAND]); + if (!tb[IWL_TM_ATTR_MEM_ADDR]) { + IWL_ERR(priv, "Error finding memory offset address\n"); return -ENOMSG; } - ofs = nla_get_u32(tb[IWL_TM_ATTR_SRAM_ADDR]); - if (!tb[IWL_TM_ATTR_SRAM_SIZE]) { - IWL_ERR(priv, "Missing size for SRAM reading\n"); + addr = nla_get_u32(tb[IWL_TM_ATTR_MEM_ADDR]); + if (!tb[IWL_TM_ATTR_BUFFER_SIZE]) { + IWL_ERR(priv, "Error finding size for memory reading\n"); return -ENOMSG; } - size = nla_get_u32(tb[IWL_TM_ATTR_SRAM_SIZE]); - switch (priv->shrd->ucode_type) { - case IWL_UCODE_REGULAR: - maxsize = trans(priv)->ucode_rt.data.len; - break; - case IWL_UCODE_INIT: - maxsize = trans(priv)->ucode_init.data.len; - break; - case IWL_UCODE_WOWLAN: - maxsize = trans(priv)->ucode_wowlan.data.len; - break; - case IWL_UCODE_NONE: - IWL_ERR(priv, "uCode does not been loaded\n"); - return -ENOSYS; - default: - IWL_ERR(priv, "unsupported uCode type\n"); - return -ENOSYS; + size = nla_get_u32(tb[IWL_TM_ATTR_BUFFER_SIZE]); + + if (cmd == IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_READ) + return iwl_testmode_indirect_read(priv, addr, size); + else { + if (!tb[IWL_TM_ATTR_BUFFER_DUMP]) + return -EINVAL; + buf = (unsigned char *) nla_data(tb[IWL_TM_ATTR_BUFFER_DUMP]); + return iwl_testmode_indirect_write(priv, addr, size, buf); } - if ((ofs + size) > (maxsize + SRAM_DATA_SEG_OFFSET)) { - IWL_ERR(priv, "Invalid offset/size: out of range\n"); - return -EINVAL; - } - priv->testmode_sram.buff_size = (size / 4) * 4; - priv->testmode_sram.buff_addr = - kmalloc(priv->testmode_sram.buff_size, GFP_KERNEL); - if (priv->testmode_sram.buff_addr == NULL) { - IWL_ERR(priv, "Memory allocation fail\n"); - return -ENOMEM; - } - _iwl_read_targ_mem_words(trans(priv), ofs, - priv->testmode_sram.buff_addr, - priv->testmode_sram.buff_size / 4); - priv->testmode_sram.num_chunks = - DIV_ROUND_UP(priv->testmode_sram.buff_size, DUMP_CHUNK_SIZE); - priv->testmode_sram.sram_readed = true; - return 0; } -static int iwl_testmode_sram_dump(struct ieee80211_hw *hw, struct nlattr **tb, +static int iwl_testmode_buffer_dump(struct ieee80211_hw *hw, struct nlattr **tb, struct sk_buff *skb, struct netlink_callback *cb) { struct iwl_priv *priv = hw->priv; int idx, length; - if (priv->testmode_sram.sram_readed) { + if (priv->testmode_mem.read_in_progress) { idx = cb->args[4]; - if (idx >= priv->testmode_sram.num_chunks) { - iwl_sram_cleanup(priv); + if (idx >= priv->testmode_mem.num_chunks) { + iwl_mem_cleanup(priv); return -ENOENT; } length = DUMP_CHUNK_SIZE; - if (((idx + 1) == priv->testmode_sram.num_chunks) && - (priv->testmode_sram.buff_size % DUMP_CHUNK_SIZE)) - length = priv->testmode_sram.buff_size % + if (((idx + 1) == priv->testmode_mem.num_chunks) && + (priv->testmode_mem.buff_size % DUMP_CHUNK_SIZE)) + length = priv->testmode_mem.buff_size % DUMP_CHUNK_SIZE; - NLA_PUT(skb, IWL_TM_ATTR_SRAM_DUMP, length, - priv->testmode_sram.buff_addr + + NLA_PUT(skb, IWL_TM_ATTR_BUFFER_DUMP, length, + priv->testmode_mem.buff_addr + (DUMP_CHUNK_SIZE * idx)); idx++; cb->args[4] = idx; @@ -900,8 +936,6 @@ int iwlagn_mac_testmode_cmd(struct ieee80211_hw *hw, void *data, int len) case IWL_TM_CMD_APP2DEV_DIRECT_REG_READ32: case IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE32: case IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE8: - case IWL_TM_CMD_APP2DEV_INDIRECT_REG_READ32: - case IWL_TM_CMD_APP2DEV_INDIRECT_REG_WRITE32: IWL_DEBUG_INFO(priv, "testmode cmd to register\n"); result = iwl_testmode_reg(hw, tb); break; @@ -931,9 +965,11 @@ int iwlagn_mac_testmode_cmd(struct ieee80211_hw *hw, void *data, int len) result = iwl_testmode_ownership(hw, tb); break; - case IWL_TM_CMD_APP2DEV_READ_SRAM: - IWL_DEBUG_INFO(priv, "testmode sram read cmd to driver\n"); - result = iwl_testmode_sram(hw, tb); + case IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_READ: + case IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_WRITE: + IWL_DEBUG_INFO(priv, "testmode indirect memory cmd " + "to driver\n"); + result = iwl_testmode_indirect_mem(hw, tb); break; default: @@ -983,9 +1019,9 @@ int iwlagn_mac_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *skb, IWL_DEBUG_INFO(priv, "uCode trace cmd to driver\n"); result = iwl_testmode_trace_dump(hw, tb, skb, cb); break; - case IWL_TM_CMD_APP2DEV_DUMP_SRAM: + case IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_DUMP: IWL_DEBUG_INFO(priv, "testmode sram dump cmd to driver\n"); - result = iwl_testmode_sram_dump(hw, tb, skb, cb); + result = iwl_testmode_buffer_dump(hw, tb, skb, cb); break; default: result = -EINVAL; diff --git a/drivers/net/wireless/iwlwifi/iwl-testmode.h b/drivers/net/wireless/iwlwifi/iwl-testmode.h index f97d06169b45..3815cf372f2b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-testmode.h +++ b/drivers/net/wireless/iwlwifi/iwl-testmode.h @@ -109,20 +109,19 @@ * if application has the ownership, the only host command from * testmode will deliver to uCode. Default owner is driver * - * @IWL_TM_CMD_APP2DEV_INDIRECT_REG_READ32: - * @IWL_TM_CMD_APP2DEV_INDIRECT_REG_WRITE32: - * commands from user application to indirectly access peripheral register - * - * @IWL_TM_CMD_APP2DEV_READ_SRAM: - * @IWL_TM_CMD_APP2DEV_DUMP_SRAM: - * commands from user application to read data in sram - * * @IWL_TM_CMD_APP2DEV_LOAD_WOWLAN_FW: load Wake On Wireless LAN uCode image * @IWL_TM_CMD_APP2DEV_GET_FW_VERSION: retrieve uCode version * @IWL_TM_CMD_APP2DEV_GET_DEVICE_ID: retrieve ID information in device * @IWL_TM_CMD_APP2DEV_GET_FW_INFO: * retrieve information of existing loaded uCode image * + * @IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_READ: + * @IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_DUMP: + * @IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_WRITE: + * Commands to read/write data from periphery or SRAM memory ranges. + * Fore reading, a READ command is sent from the userspace and the data + * is returned when the user calls a DUMP command. + * For writing, only a WRITE command is used. */ enum iwl_tm_cmd_t { IWL_TM_CMD_APP2DEV_UCODE = 1, @@ -142,15 +141,18 @@ enum iwl_tm_cmd_t { IWL_TM_CMD_DEV2APP_UCODE_RX_PKT = 15, IWL_TM_CMD_DEV2APP_EEPROM_RSP = 16, IWL_TM_CMD_APP2DEV_OWNERSHIP = 17, - IWL_TM_CMD_APP2DEV_INDIRECT_REG_READ32 = 18, - IWL_TM_CMD_APP2DEV_INDIRECT_REG_WRITE32 = 19, - IWL_TM_CMD_APP2DEV_READ_SRAM = 20, - IWL_TM_CMD_APP2DEV_DUMP_SRAM = 21, + RESERVED_18 = 18, + RESERVED_19 = 19, + RESERVED_20 = 20, + RESERVED_21 = 21, IWL_TM_CMD_APP2DEV_LOAD_WOWLAN_FW = 22, IWL_TM_CMD_APP2DEV_GET_FW_VERSION = 23, IWL_TM_CMD_APP2DEV_GET_DEVICE_ID = 24, IWL_TM_CMD_APP2DEV_GET_FW_INFO = 25, - IWL_TM_CMD_MAX = 26, + IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_READ = 26, + IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_DUMP = 27, + IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_WRITE = 28, + IWL_TM_CMD_MAX = 29, }; /* @@ -221,16 +223,19 @@ enum iwl_tm_cmd_t { * The mandatory fields are: * IWL_TM_ATTR_UCODE_OWNER for the new owner * - * @IWL_TM_ATTR_SRAM_ADDR: - * @IWL_TM_ATTR_SRAM_SIZE: - * When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_READ_SRAM, + * @IWL_TM_ATTR_MEM_ADDR: + * @IWL_TM_ATTR_BUFFER_SIZE: + * When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_READ + * or IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_WRITE. * The mandatory fields are: - * IWL_TM_ATTR_SRAM_ADDR for the address in sram - * IWL_TM_ATTR_SRAM_SIZE for the buffer size of data reading + * IWL_TM_ATTR_MEM_ADDR for the address in SRAM/periphery to read/write + * IWL_TM_ATTR_BUFFER_SIZE for the buffer size of data to read/write. * - * @IWL_TM_ATTR_SRAM_DUMP: - * When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_DUMP_SRAM, - * IWL_TM_ATTR_SRAM_DUMP for the data in sram + * @IWL_TM_ATTR_BUFFER_DUMP: + * When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_DUMP, + * IWL_TM_ATTR_BUFFER_DUMP is used for the data that was read. + * When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_WRITE, + * this attribute contains the data to write. * * @IWL_TM_ATTR_FW_VERSION: * When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_GET_FW_VERSION, @@ -266,9 +271,9 @@ enum iwl_tm_attr_t { IWL_TM_ATTR_TRACE_DUMP = 12, IWL_TM_ATTR_FIXRATE = 13, IWL_TM_ATTR_UCODE_OWNER = 14, - IWL_TM_ATTR_SRAM_ADDR = 15, - IWL_TM_ATTR_SRAM_SIZE = 16, - IWL_TM_ATTR_SRAM_DUMP = 17, + IWL_TM_ATTR_MEM_ADDR = 15, + IWL_TM_ATTR_BUFFER_SIZE = 16, + IWL_TM_ATTR_BUFFER_DUMP = 17, IWL_TM_ATTR_FW_VERSION = 18, IWL_TM_ATTR_DEVICE_ID = 19, IWL_TM_ATTR_FW_TYPE = 20, From cdfef6c224f9490215cadd91b34c579757a6e59d Mon Sep 17 00:00:00 2001 From: Amit Beka Date: Tue, 31 Jan 2012 15:30:39 +0200 Subject: [PATCH 03/26] iwlwifi: added reply data to testmode HCMD send The testmode command for host command send now replies with a nl80211 message and the response it recieved from the device. This does not change the API directly, but adds a reply to the testmode call. Signed-off-by: Amit Beka Signed-off-by: Wey-Yi Guy --- drivers/net/wireless/iwlwifi/iwl-testmode.c | 59 ++++++++++++++++++--- drivers/net/wireless/iwlwifi/iwl-testmode.h | 11 ++-- 2 files changed, 60 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-testmode.c b/drivers/net/wireless/iwlwifi/iwl-testmode.c index debc9ababbfa..e54a1dd7014a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-testmode.c +++ b/drivers/net/wireless/iwlwifi/iwl-testmode.c @@ -236,6 +236,7 @@ void iwl_testmode_cleanup(struct iwl_priv *priv) iwl_mem_cleanup(priv); } + /* * This function handles the user application commands to the ucode. * @@ -244,8 +245,10 @@ void iwl_testmode_cleanup(struct iwl_priv *priv) * host command to the ucode. * * If any mandatory field is missing, -ENOMSG is replied to the user space - * application; otherwise, the actual execution result of the host command to - * ucode is replied. + * application; otherwise, waits for the host command to be sent and checks + * the return code. In case or error, it is returned, otherwise a reply is + * allocated and the reply RX packet + * is returned. * * @hw: ieee80211_hw object that represents the device * @tb: gnl message fields from the user space @@ -254,6 +257,12 @@ static int iwl_testmode_ucode(struct ieee80211_hw *hw, struct nlattr **tb) { struct iwl_priv *priv = hw->priv; struct iwl_host_cmd cmd; + struct iwl_rx_packet *pkt; + struct sk_buff *skb; + void *reply_buf; + u32 reply_len; + int ret; + bool cmd_want_skb; memset(&cmd, 0, sizeof(struct iwl_host_cmd)); @@ -263,15 +272,53 @@ static int iwl_testmode_ucode(struct ieee80211_hw *hw, struct nlattr **tb) return -ENOMSG; } - cmd.flags = CMD_ON_DEMAND; + cmd.flags = CMD_ON_DEMAND | CMD_SYNC; + cmd_want_skb = nla_get_flag(tb[IWL_TM_ATTR_UCODE_CMD_SKB]); + if (cmd_want_skb) + cmd.flags |= CMD_WANT_SKB; + cmd.id = nla_get_u8(tb[IWL_TM_ATTR_UCODE_CMD_ID]); cmd.data[0] = nla_data(tb[IWL_TM_ATTR_UCODE_CMD_DATA]); cmd.len[0] = nla_len(tb[IWL_TM_ATTR_UCODE_CMD_DATA]); cmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY; - IWL_INFO(priv, "testmode ucode command ID 0x%x, flags 0x%x," + IWL_DEBUG_INFO(priv, "testmode ucode command ID 0x%x, flags 0x%x," " len %d\n", cmd.id, cmd.flags, cmd.len[0]); - /* ok, let's submit the command to ucode */ - return iwl_trans_send_cmd(trans(priv), &cmd); + + ret = iwl_trans_send_cmd(trans(priv), &cmd); + if (ret) { + IWL_ERR(priv, "Failed to send hcmd\n"); + return ret; + } + if (!cmd_want_skb) + return ret; + + /* Handling return of SKB to the user */ + pkt = (struct iwl_rx_packet *)cmd.reply_page; + if (!pkt) { + IWL_ERR(priv, "HCMD received a null response packet\n"); + return ret; + } + + reply_len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; + skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, reply_len + 20); + reply_buf = kmalloc(reply_len, GFP_KERNEL); + if (!skb || !reply_buf) { + kfree_skb(skb); + kfree(reply_buf); + return -ENOMEM; + } + + /* The reply is in a page, that we cannot send to user space. */ + memcpy(reply_buf, &(pkt->u), reply_len); + iwl_free_pages(priv->shrd, cmd.reply_page); + + NLA_PUT_U32(skb, IWL_TM_ATTR_COMMAND, IWL_TM_CMD_DEV2APP_UCODE_RX_PKT); + NLA_PUT(skb, IWL_TM_ATTR_UCODE_RX_PKT, reply_len, reply_buf); + return cfg80211_testmode_reply(skb); + +nla_put_failure: + IWL_DEBUG_INFO(priv, "Failed creating NL attributes\n"); + return -ENOMSG; } diff --git a/drivers/net/wireless/iwlwifi/iwl-testmode.h b/drivers/net/wireless/iwlwifi/iwl-testmode.h index 3815cf372f2b..69b2e80f4071 100644 --- a/drivers/net/wireless/iwlwifi/iwl-testmode.h +++ b/drivers/net/wireless/iwlwifi/iwl-testmode.h @@ -99,7 +99,7 @@ * to user application * @IWL_TM_CMD_DEV2APP_UCODE_RX_PKT: * commands from kernel space to multicast the spontaneous messages - * to user application + * to user application, or reply of host commands * @IWL_TM_CMD_DEV2APP_EEPROM_RSP: * commands from kernel space to carry the eeprom response * to user application @@ -173,8 +173,6 @@ enum iwl_tm_cmd_t { * When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_UCODE, * The mandatory fields are : * IWL_TM_ATTR_UCODE_CMD_ID for recognizable command ID; - * IWL_TM_ATTR_COMMAND_FLAG for the flags of the commands; - * The optional fields are: * IWL_TM_ATTR_UCODE_CMD_DATA for the actual command payload * to the ucode * @@ -254,6 +252,10 @@ enum iwl_tm_cmd_t { * IWL_TM_ATTR_FW_INST_SIZE for the size of instruction section * IWL_TM_ATTR_FW_DATA_SIZE for the size of data section * + * @IWL_TM_ATTR_UCODE_CMD_SKB: + * When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_UCODE this flag + * indicates that the user wants to receive the response of the command + * in a reply SKB. If it's not present, the response is not returned. */ enum iwl_tm_attr_t { IWL_TM_ATTR_NOT_APPLICABLE = 0, @@ -279,7 +281,8 @@ enum iwl_tm_attr_t { IWL_TM_ATTR_FW_TYPE = 20, IWL_TM_ATTR_FW_INST_SIZE = 21, IWL_TM_ATTR_FW_DATA_SIZE = 22, - IWL_TM_ATTR_MAX = 23, + IWL_TM_ATTR_UCODE_CMD_SKB = 23, + IWL_TM_ATTR_MAX = 24, }; /* uCode trace buffer */ From 2655e314c4b204966008689eaf3e87ba1f38d55c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 31 Jan 2012 21:08:37 -0800 Subject: [PATCH 04/26] iwlwifi: trace debug messages Make iwlwifi record all debug messages into tracing, even if debug_level is not enabled. Due to the lack of APIs, the debug messages are now recorded up to a max length of 100, the only one above that is the RXON which is not needed if you trace the commands as well as it only dumps the command contents. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi W Guy --- drivers/net/wireless/iwlwifi/Makefile | 2 +- drivers/net/wireless/iwlwifi/iwl-debug.c | 127 ++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-debug.h | 83 ++++++------- drivers/net/wireless/iwlwifi/iwl-devtrace.h | 65 ++++++++++ 4 files changed, 235 insertions(+), 42 deletions(-) create mode 100644 drivers/net/wireless/iwlwifi/iwl-debug.c diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index 9dc84a7354db..46622a0f017b 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -1,7 +1,7 @@ # WIFI obj-$(CONFIG_IWLWIFI) += iwlwifi.o iwlwifi-objs := iwl-agn.o iwl-agn-rs.o iwl-mac80211.o -iwlwifi-objs += iwl-ucode.o iwl-agn-tx.o +iwlwifi-objs += iwl-ucode.o iwl-agn-tx.o iwl-debug.o iwlwifi-objs += iwl-agn-lib.o iwl-agn-calib.o iwl-io.o iwlwifi-objs += iwl-agn-tt.o iwl-agn-sta.o iwl-agn-rx.o diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.c b/drivers/net/wireless/iwlwifi/iwl-debug.c new file mode 100644 index 000000000000..4bc2e70051d6 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-debug.c @@ -0,0 +1,127 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved. + * + * 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.GPL. + * + * Contact Information: + * Intel Linux Wireless + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ + +#include +#include "iwl-debug.h" + +#define __iwl_fn(fn) \ +void __iwl_ ##fn(struct device *dev, const char *fmt, ...) \ +{ \ + struct va_format vaf = { \ + .fmt = fmt, \ + }; \ + va_list args; \ + \ + va_start(args, fmt); \ + vaf.va = &args; \ + dev_ ##fn(dev, "%pV", &vaf); \ + trace_iwlwifi_ ##fn(&vaf); \ + va_end(args); \ +} + +__iwl_fn(warn) +__iwl_fn(info) +__iwl_fn(crit) + +void __iwl_err(struct device *dev, bool rfkill_prefix, bool trace_only, + const char *fmt, ...) +{ + struct va_format vaf = { + .fmt = fmt, + }; + va_list args; + + va_start(args, fmt); + vaf.va = &args; + if (!trace_only) { + if (rfkill_prefix) + dev_err(dev, "(RFKILL) %pV", &vaf); + else + dev_err(dev, "%pV", &vaf); + } + trace_iwlwifi_err(&vaf); + va_end(args); +} + +#if defined(CONFIG_IWLWIFI_DEBUG) || defined(CONFIG_IWLWIFI_DEVICE_TRACING) +void __iwl_dbg(struct iwl_shared *shared, struct device *dev, + u32 level, bool limit, const char *function, + const char *fmt, ...) +{ + struct va_format vaf = { + .fmt = fmt, + }; + va_list args; + + va_start(args, fmt); + vaf.va = &args; +#ifdef CONFIG_IWLWIFI_DEBUG + if (iwl_get_debug_level(shared) & level && + (!limit || net_ratelimit())) + dev_err(dev, "%c %s %pV", in_interrupt() ? 'I' : 'U', + function, &vaf); +#endif + trace_iwlwifi_dbg(level, in_interrupt(), function, &vaf); + va_end(args); +} +#endif diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index 351b41d7f4fd..bfc08494ed22 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -31,14 +31,33 @@ #include "iwl-bus.h" #include "iwl-shared.h" +#include "iwl-devtrace.h" struct iwl_priv; -/*No matter what is m (priv, bus, trans), this will work */ -#define IWL_ERR(m, f, a...) dev_err(trans(m)->dev, f, ## a) -#define IWL_WARN(m, f, a...) dev_warn(trans(m)->dev, f, ## a) -#define IWL_INFO(m, f, a...) dev_info(trans(m)->dev, f, ## a) -#define IWL_CRIT(m, f, a...) dev_crit(trans(m)->dev, f, ## a) +void __iwl_err(struct device *dev, bool rfkill_prefix, bool only_trace, + const char *fmt, ...); +void __iwl_warn(struct device *dev, const char *fmt, ...); +void __iwl_info(struct device *dev, const char *fmt, ...); +void __iwl_crit(struct device *dev, const char *fmt, ...); + +/* No matter what is m (priv, bus, trans), this will work */ +#define IWL_ERR(m, f, a...) __iwl_err(trans(m)->dev, false, false, f, ## a) +#define IWL_WARN(m, f, a...) __iwl_warn(trans(m)->dev, f, ## a) +#define IWL_INFO(m, f, a...) __iwl_info(trans(m)->dev, f, ## a) +#define IWL_CRIT(m, f, a...) __iwl_crit(trans(m)->dev, f, ## a) + +#if defined(CONFIG_IWLWIFI_DEBUG) || defined(CONFIG_IWLWIFI_DEVICE_TRACING) +void __iwl_dbg(struct iwl_shared *shared, struct device *dev, + u32 level, bool limit, const char *function, + const char *fmt, ...); +#else +static inline void +__iwl_dbg(struct iwl_shared *shared, struct device *dev, + u32 level, bool limit, const char *function, + const char *fmt, ...) +{} +#endif #define iwl_print_hex_error(m, p, len) \ do { \ @@ -46,53 +65,35 @@ do { \ DUMP_PREFIX_OFFSET, 16, 1, p, len, 1); \ } while (0) +#define IWL_DEBUG(m, level, fmt, args...) \ + __iwl_dbg((m)->shrd, trans(m)->dev, level, false, __func__, fmt, ##args) +#define IWL_DEBUG_LIMIT(m, level, fmt, args...) \ + __iwl_dbg((m)->shrd, trans(m)->dev, level, true, __func__, fmt, ##args) + #ifdef CONFIG_IWLWIFI_DEBUG -#define IWL_DEBUG(m, level, fmt, ...) \ -do { \ - if (iwl_get_debug_level((m)->shrd) & (level)) \ - dev_err(trans(m)->dev, "%c %s " fmt, \ - in_interrupt() ? 'I' : 'U', __func__, \ - ##__VA_ARGS__); \ -} while (0) - -#define IWL_DEBUG_LIMIT(m, level, fmt, ...) \ -do { \ - if (iwl_get_debug_level((m)->shrd) & (level) && \ - net_ratelimit()) \ - dev_err(trans(m)->dev, "%c %s " fmt, \ - in_interrupt() ? 'I' : 'U', __func__, \ - ##__VA_ARGS__); \ -} while (0) - #define iwl_print_hex_dump(m, level, p, len) \ do { \ if (iwl_get_debug_level((m)->shrd) & level) \ print_hex_dump(KERN_DEBUG, "iwl data: ", \ DUMP_PREFIX_OFFSET, 16, 1, p, len, 1); \ } while (0) - -#define IWL_DEBUG_QUIET_RFKILL(p, fmt, ...) \ +#define IWL_DEBUG_QUIET_RFKILL(m, fmt, args...) \ do { \ - if (!iwl_is_rfkill(p->shrd)) \ - dev_err(trans(p)->dev, "%s%c %s " fmt, \ - "", \ - in_interrupt() ? 'I' : 'U', __func__, \ - ##__VA_ARGS__); \ - else if (iwl_get_debug_level(p->shrd) & IWL_DL_RADIO) \ - dev_err(trans(p)->dev, "%s%c %s " fmt, \ - "(RFKILL) ", \ - in_interrupt() ? 'I' : 'U', __func__, \ - ##__VA_ARGS__); \ + if (!iwl_is_rfkill((m)->shrd)) \ + IWL_ERR(m, fmt, ##args); \ + else \ + __iwl_err(trans(m)->dev, true, \ + !(iwl_get_debug_level((m)->shrd) & IWL_DL_RADIO),\ + fmt, ##args); \ } while (0) - #else -#define IWL_DEBUG(m, level, fmt, args...) -#define IWL_DEBUG_LIMIT(m, level, fmt, args...) #define iwl_print_hex_dump(m, level, p, len) -#define IWL_DEBUG_QUIET_RFKILL(p, fmt, args...) \ -do { \ - if (!iwl_is_rfkill(p->shrd)) \ - IWL_ERR(p, fmt, ##args); \ +#define IWL_DEBUG_QUIET_RFKILL(m, fmt, args...) \ +do { \ + if (!iwl_is_rfkill((m)->shrd)) \ + IWL_ERR(m, fmt, ##args); \ + else \ + __iwl_err(trans(m)->dev, true, true, fmt, ##args); \ } while (0) #endif /* CONFIG_IWLWIFI_DEBUG */ diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.h b/drivers/net/wireless/iwlwifi/iwl-devtrace.h index 4d892211ce4c..96e62338cec0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-devtrace.h +++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.h @@ -34,6 +34,11 @@ #undef TRACE_EVENT #define TRACE_EVENT(name, proto, ...) \ static inline void trace_ ## name(proto) {} +#undef DECLARE_EVENT_CLASS +#define DECLARE_EVENT_CLASS(...) +#undef DEFINE_EVENT +#define DEFINE_EVENT(evt_class, name, proto, ...) \ +static inline void trace_ ## name(proto) {} #endif #define PRIV_ENTRY __field(void *, priv) @@ -163,6 +168,66 @@ TRACE_EVENT(iwlwifi_dev_ucode_wrap_event, __entry->p_entry) ); +#undef TRACE_SYSTEM +#define TRACE_SYSTEM iwlwifi_msg + +#define MAX_MSG_LEN 100 + +DECLARE_EVENT_CLASS(iwlwifi_msg_event, + TP_PROTO(struct va_format *vaf), + TP_ARGS(vaf), + TP_STRUCT__entry( + __dynamic_array(char, msg, MAX_MSG_LEN) + ), + TP_fast_assign( + WARN_ON_ONCE(vsnprintf(__get_dynamic_array(msg), + MAX_MSG_LEN, vaf->fmt, + *vaf->va) >= MAX_MSG_LEN); + ), + TP_printk("%s", (char *)__get_dynamic_array(msg)) +); + +DEFINE_EVENT(iwlwifi_msg_event, iwlwifi_err, + TP_PROTO(struct va_format *vaf), + TP_ARGS(vaf) +); + +DEFINE_EVENT(iwlwifi_msg_event, iwlwifi_warn, + TP_PROTO(struct va_format *vaf), + TP_ARGS(vaf) +); + +DEFINE_EVENT(iwlwifi_msg_event, iwlwifi_info, + TP_PROTO(struct va_format *vaf), + TP_ARGS(vaf) +); + +DEFINE_EVENT(iwlwifi_msg_event, iwlwifi_crit, + TP_PROTO(struct va_format *vaf), + TP_ARGS(vaf) +); + +TRACE_EVENT(iwlwifi_dbg, + TP_PROTO(u32 level, bool in_interrupt, const char *function, + struct va_format *vaf), + TP_ARGS(level, in_interrupt, function, vaf), + TP_STRUCT__entry( + __field(u32, level) + __field(u8, in_interrupt) + __string(function, function) + __dynamic_array(char, msg, MAX_MSG_LEN) + ), + TP_fast_assign( + __entry->level = level; + __entry->in_interrupt = in_interrupt; + __assign_str(function, function); + WARN_ON_ONCE(vsnprintf(__get_dynamic_array(msg), + MAX_MSG_LEN, vaf->fmt, + *vaf->va) >= MAX_MSG_LEN); + ), + TP_printk("%s", (char *)__get_dynamic_array(msg)) +); + #undef TRACE_SYSTEM #define TRACE_SYSTEM iwlwifi From 1ee158d83853a9f5c1465be56d56ff56e6698e92 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 17 Feb 2012 10:07:44 -0800 Subject: [PATCH 05/26] iwlwifi: move workqueue to priv In order to separate the different parts of the driver better, we are reducing the shared data. This moves the workqueue to "priv", and removes it from the transport. To do this, simply use schedule_work() in the transport. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy --- drivers/net/wireless/iwlwifi/iwl-agn-lib.c | 4 ++-- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 2 +- drivers/net/wireless/iwlwifi/iwl-agn-rx.c | 2 +- drivers/net/wireless/iwlwifi/iwl-agn-tt.c | 6 +++--- drivers/net/wireless/iwlwifi/iwl-agn-tx.c | 2 +- drivers/net/wireless/iwlwifi/iwl-agn.c | 14 +++++++------- drivers/net/wireless/iwlwifi/iwl-core.c | 2 +- drivers/net/wireless/iwlwifi/iwl-dev.h | 2 ++ drivers/net/wireless/iwlwifi/iwl-mac80211.c | 4 ++-- drivers/net/wireless/iwlwifi/iwl-scan.c | 10 +++++----- drivers/net/wireless/iwlwifi/iwl-shared.h | 2 -- drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c | 10 ++-------- drivers/net/wireless/iwlwifi/iwl-trans-pcie.c | 2 ++ 13 files changed, 29 insertions(+), 33 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index a8f7689aaacf..30b99b9abf7f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -700,7 +700,7 @@ static void iwlagn_set_kill_msk(struct iwl_priv *priv, priv->kill_cts_mask = bt_kill_cts_msg[kill_msk]; /* schedule to send runtime bt_config */ - queue_work(priv->shrd->workqueue, &priv->bt_runtime_config); + queue_work(priv->workqueue, &priv->bt_runtime_config); } } @@ -745,7 +745,7 @@ int iwlagn_bt_coex_profile_notif(struct iwl_priv *priv, IWL_BT_COEX_TRAFFIC_LOAD_NONE; } priv->bt_status = coex->bt_status; - queue_work(priv->shrd->workqueue, + queue_work(priv->workqueue, &priv->bt_traffic_change_work); } } diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index b9ba404d15c1..f88e2e33e2e8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -892,7 +892,7 @@ static void rs_bt_update_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx, rs_fill_link_cmd(priv, lq_sta, tbl->current_rate); iwl_send_lq_cmd(priv, ctx, &lq_sta->lq, CMD_ASYNC, false); - queue_work(priv->shrd->workqueue, &priv->bt_full_concurrency); + queue_work(priv->workqueue, &priv->bt_full_concurrency); } } diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rx.c b/drivers/net/wireless/iwlwifi/iwl-agn-rx.c index a14ddab783ea..aee7d060d317 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rx.c @@ -581,7 +581,7 @@ static int iwlagn_rx_statistics(struct iwl_priv *priv, if (unlikely(!test_bit(STATUS_SCANNING, &priv->shrd->status)) && (pkt->hdr.cmd == STATISTICS_NOTIFICATION)) { iwlagn_rx_calc_noise(priv); - queue_work(priv->shrd->workqueue, &priv->run_time_calib_work); + queue_work(priv->workqueue, &priv->run_time_calib_work); } if (cfg(priv)->lib->temperature && change) cfg(priv)->lib->temperature(priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tt.c b/drivers/net/wireless/iwlwifi/iwl-agn-tt.c index c728ed75584e..56d7c0e38163 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tt.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tt.c @@ -568,7 +568,7 @@ void iwl_tt_enter_ct_kill(struct iwl_priv *priv) return; IWL_DEBUG_TEMP(priv, "Queueing critical temperature enter.\n"); - queue_work(priv->shrd->workqueue, &priv->ct_enter); + queue_work(priv->workqueue, &priv->ct_enter); } void iwl_tt_exit_ct_kill(struct iwl_priv *priv) @@ -577,7 +577,7 @@ void iwl_tt_exit_ct_kill(struct iwl_priv *priv) return; IWL_DEBUG_TEMP(priv, "Queueing critical temperature exit.\n"); - queue_work(priv->shrd->workqueue, &priv->ct_exit); + queue_work(priv->workqueue, &priv->ct_exit); } static void iwl_bg_tt_work(struct work_struct *work) @@ -600,7 +600,7 @@ void iwl_tt_handler(struct iwl_priv *priv) return; IWL_DEBUG_TEMP(priv, "Queueing thermal throttling work.\n"); - queue_work(priv->shrd->workqueue, &priv->tt_work); + queue_work(priv->workqueue, &priv->tt_work); } /* Thermal throttling initialization diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c index 64f8db685dc5..da18a8fc9af7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c @@ -983,7 +983,7 @@ static void iwl_check_abort_status(struct iwl_priv *priv, if (frame_count == 1 && status == TX_STATUS_FAIL_RFKILL_FLUSH) { IWL_ERR(priv, "Tx flush command to flush out all frames\n"); if (!test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) - queue_work(priv->shrd->workqueue, &priv->tx_flush); + queue_work(priv->workqueue, &priv->tx_flush); } } diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 8837171ad553..1cf99a586ec9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -939,7 +939,7 @@ static void iwlagn_disable_roc_work(struct work_struct *work) static void iwl_setup_deferred_work(struct iwl_priv *priv) { - priv->shrd->workqueue = create_singlethread_workqueue(DRV_NAME); + priv->workqueue = create_singlethread_workqueue(DRV_NAME); init_waitqueue_head(&priv->shrd->wait_command_queue); @@ -1282,8 +1282,8 @@ int iwl_probe(struct iwl_bus *bus, const struct iwl_trans_ops *trans_ops, return 0; out_destroy_workqueue: - destroy_workqueue(priv->shrd->workqueue); - priv->shrd->workqueue = NULL; + destroy_workqueue(priv->workqueue); + priv->workqueue = NULL; iwl_uninit_drv(priv); out_free_eeprom: iwl_eeprom_free(priv->shrd); @@ -1321,13 +1321,13 @@ void __devexit iwl_remove(struct iwl_priv * priv) iwl_eeprom_free(priv->shrd); /*netif_stop_queue(dev); */ - flush_workqueue(priv->shrd->workqueue); + flush_workqueue(priv->workqueue); /* ieee80211_unregister_hw calls iwlagn_mac_stop, which flushes - * priv->shrd->workqueue... so we can't take down the workqueue + * priv->workqueue... so we can't take down the workqueue * until now... */ - destroy_workqueue(priv->shrd->workqueue); - priv->shrd->workqueue = NULL; + destroy_workqueue(priv->workqueue); + priv->workqueue = NULL; iwl_free_traffic_mem(priv); iwl_uninit_drv(priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 0677b3dfbfb2..6dff9c41c555 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -875,7 +875,7 @@ void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand) if (iwlagn_mod_params.restart_fw) { IWL_DEBUG_FW_ERRORS(priv, "Restarting adapter due to uCode error.\n"); - queue_work(priv->shrd->workqueue, &priv->restart); + queue_work(priv->workqueue, &priv->restart); } else IWL_DEBUG_FW_ERRORS(priv, "Detected FW error, but not restarting\n"); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 0e8f13705dbe..db37877eed77 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -721,6 +721,8 @@ struct iwl_priv { struct ieee80211_rate *ieee_rates; struct kmem_cache *tx_cmd_pool; + struct workqueue_struct *workqueue; + enum ieee80211_band band; void (*pre_rx_handler)(struct iwl_priv *priv, diff --git a/drivers/net/wireless/iwlwifi/iwl-mac80211.c b/drivers/net/wireless/iwlwifi/iwl-mac80211.c index d8025fee7e0d..17358cfb68a9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-mac80211.c +++ b/drivers/net/wireless/iwlwifi/iwl-mac80211.c @@ -343,7 +343,7 @@ static void iwlagn_mac_stop(struct ieee80211_hw *hw) iwl_down(priv); - flush_workqueue(priv->shrd->workqueue); + flush_workqueue(priv->workqueue); /* User space software may expect getting rfkill changes * even if interface is down, trans->down will leave the RF @@ -1117,7 +1117,7 @@ static int iwlagn_mac_set_tim(struct ieee80211_hw *hw, { struct iwl_priv *priv = hw->priv; - queue_work(priv->shrd->workqueue, &priv->beacon_update); + queue_work(priv->workqueue, &priv->beacon_update); return 0; } diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index 7f2e3a1c80ef..42ee1c410efd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -218,7 +218,7 @@ static void iwl_do_scan_abort(struct iwl_priv *priv) int iwl_scan_cancel(struct iwl_priv *priv) { IWL_DEBUG_SCAN(priv, "Queuing abort scan\n"); - queue_work(priv->shrd->workqueue, &priv->abort_scan); + queue_work(priv->workqueue, &priv->abort_scan); return 0; } @@ -354,7 +354,7 @@ static int iwl_rx_scan_complete_notif(struct iwl_priv *priv, */ set_bit(STATUS_SCAN_COMPLETE, &priv->shrd->status); clear_bit(STATUS_SCAN_HW, &priv->shrd->status); - queue_work(priv->shrd->workqueue, &priv->scan_completed); + queue_work(priv->workqueue, &priv->scan_completed); if (priv->iw_mode != NL80211_IFTYPE_ADHOC && iwl_advanced_bt_coexist(priv) && @@ -374,7 +374,7 @@ static int iwl_rx_scan_complete_notif(struct iwl_priv *priv, IWL_BT_COEX_TRAFFIC_LOAD_NONE; } priv->bt_status = scan_notif->bt_status; - queue_work(priv->shrd->workqueue, + queue_work(priv->workqueue, &priv->bt_traffic_change_work); } return 0; @@ -950,7 +950,7 @@ int __must_check iwl_scan_initiate(struct iwl_priv *priv, return ret; } - queue_delayed_work(priv->shrd->workqueue, &priv->scan_check, + queue_delayed_work(priv->workqueue, &priv->scan_check, IWL_SCAN_CHECK_WATCHDOG); return 0; @@ -963,7 +963,7 @@ int __must_check iwl_scan_initiate(struct iwl_priv *priv, */ void iwl_internal_short_hw_scan(struct iwl_priv *priv) { - queue_work(priv->shrd->workqueue, &priv->start_internal_scan); + queue_work(priv->workqueue, &priv->start_internal_scan); } static void iwl_bg_start_internal_scan(struct work_struct *work) diff --git a/drivers/net/wireless/iwlwifi/iwl-shared.h b/drivers/net/wireless/iwlwifi/iwl-shared.h index 63d4a4fc5b9e..42bf43b9c406 100644 --- a/drivers/net/wireless/iwlwifi/iwl-shared.h +++ b/drivers/net/wireless/iwlwifi/iwl-shared.h @@ -359,7 +359,6 @@ struct iwl_cfg { * @priv: pointer to the upper layer data * @trans: pointer to the transport layer data * @hw_params: see struct iwl_hw_params - * @workqueue: the workqueue used by all the layers of the driver * @lock: protect general shared data * @sta_lock: protects the station table. * If lock and sta_lock are needed, lock must be acquired first. @@ -391,7 +390,6 @@ struct iwl_shared { struct iwl_trans *trans; struct iwl_hw_params hw_params; - struct workqueue_struct *workqueue; spinlock_t lock; spinlock_t sta_lock; struct mutex mutex; diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c index 3826852ec5f0..1b11cfec5da6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c @@ -227,7 +227,7 @@ static void iwlagn_rx_queue_restock(struct iwl_trans *trans) /* If the pre-allocated buffer pool is dropping low, schedule to * refill it */ if (rxq->free_count <= RX_LOW_WATERMARK) - queue_work(trans->shrd->workqueue, &trans_pcie->rx_replenish); + schedule_work(&trans_pcie->rx_replenish); /* If we've added more space for the firmware to place data, tell it. @@ -351,14 +351,8 @@ void iwl_bg_rx_replenish(struct work_struct *data) { struct iwl_trans_pcie *trans_pcie = container_of(data, struct iwl_trans_pcie, rx_replenish); - struct iwl_trans *trans = trans_pcie->trans; - if (test_bit(STATUS_EXIT_PENDING, &trans->shrd->status)) - return; - - mutex_lock(&trans->shrd->mutex); - iwlagn_rx_replenish(trans); - mutex_unlock(&trans->shrd->mutex); + iwlagn_rx_replenish(trans_pcie->trans); } /** diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c index f5cb5d3cd926..e8d1dbfa1aea 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c +++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c @@ -1293,6 +1293,8 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) synchronize_irq(trans->irq); tasklet_kill(&trans_pcie->irq_tasklet); + cancel_work_sync(&trans_pcie->rx_replenish); + /* stop and reset the on-board processor */ iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); } From 7b11488fbbbe06ada39a396dec16532db8c933e6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 5 Feb 2012 13:55:11 -0800 Subject: [PATCH 06/26] iwlwifi: give PCIe its own lock Instead of using a global lock, the PCIe transport can use an own lock for its IRQ. This will make it possible to not disable IRQs for the shared lock. The lock is currently used throughout the code but this can be improved even further by splitting up the locking for the queues. Signed-off-by: Johannes Berg Reviewed-by: Wey-Yi W Guy --- .../net/wireless/iwlwifi/iwl-trans-pcie-int.h | 1 + .../net/wireless/iwlwifi/iwl-trans-pcie-rx.c | 29 ++++++++------- .../net/wireless/iwlwifi/iwl-trans-pcie-tx.c | 4 +- drivers/net/wireless/iwlwifi/iwl-trans-pcie.c | 37 +++++++++++-------- 4 files changed, 40 insertions(+), 31 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h index 561865f29d56..8c30fea8c2b3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h @@ -230,6 +230,7 @@ struct iwl_trans_pcie { struct tasklet_struct irq_tasklet; struct isr_statistics isr_stats; + spinlock_t irq_lock; u32 inta_mask; u32 scd_base_addr; struct iwl_dma_ptr scd_bc_tbls; diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c index 1b11cfec5da6..e06342656cea 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c @@ -331,13 +331,14 @@ static void iwlagn_rx_allocate(struct iwl_trans *trans, gfp_t priority) void iwlagn_rx_replenish(struct iwl_trans *trans) { + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); unsigned long flags; iwlagn_rx_allocate(trans, GFP_KERNEL); - spin_lock_irqsave(&trans->shrd->lock, flags); + spin_lock_irqsave(&trans_pcie->irq_lock, flags); iwlagn_rx_queue_restock(trans); - spin_unlock_irqrestore(&trans->shrd->lock, flags); + spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); } static void iwlagn_rx_replenish_now(struct iwl_trans *trans) @@ -943,7 +944,7 @@ void iwl_irq_tasklet(struct iwl_trans *trans) struct isr_statistics *isr_stats = &trans_pcie->isr_stats; - spin_lock_irqsave(&trans->shrd->lock, flags); + spin_lock_irqsave(&trans_pcie->irq_lock, flags); /* Ack/clear/reset pending uCode interrupts. * Note: Some bits in CSR_INT are "OR" of bits in CSR_FH_INT_STATUS, @@ -973,7 +974,7 @@ void iwl_irq_tasklet(struct iwl_trans *trans) /* saved interrupt in inta variable now we can reset trans_pcie->inta */ trans_pcie->inta = 0; - spin_unlock_irqrestore(&trans->shrd->lock, flags); + spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); /* Now service all interrupt bits discovered above. */ if (inta & CSR_INT_BIT_HW_ERR) { @@ -1226,7 +1227,7 @@ void iwl_reset_ict(struct iwl_trans *trans) if (!trans_pcie->ict_tbl) return; - spin_lock_irqsave(&trans->shrd->lock, flags); + spin_lock_irqsave(&trans_pcie->irq_lock, flags); iwl_disable_interrupts(trans); memset(trans_pcie->ict_tbl, 0, ICT_SIZE); @@ -1243,7 +1244,7 @@ void iwl_reset_ict(struct iwl_trans *trans) trans_pcie->ict_index = 0; iwl_write32(trans, CSR_INT, trans_pcie->inta_mask); iwl_enable_interrupts(trans); - spin_unlock_irqrestore(&trans->shrd->lock, flags); + spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); } /* Device is going down disable ict interrupt usage */ @@ -1254,9 +1255,9 @@ void iwl_disable_ict(struct iwl_trans *trans) unsigned long flags; - spin_lock_irqsave(&trans->shrd->lock, flags); + spin_lock_irqsave(&trans_pcie->irq_lock, flags); trans_pcie->use_ict = false; - spin_unlock_irqrestore(&trans->shrd->lock, flags); + spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); } static irqreturn_t iwl_isr(int irq, void *data) @@ -1275,7 +1276,7 @@ static irqreturn_t iwl_isr(int irq, void *data) trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - spin_lock_irqsave(&trans->shrd->lock, flags); + spin_lock_irqsave(&trans_pcie->irq_lock, flags); /* Disable (but don't clear!) interrupts here to avoid * back-to-back ISRs and sporadic interrupts from our NIC. @@ -1319,7 +1320,7 @@ static irqreturn_t iwl_isr(int irq, void *data) iwl_enable_interrupts(trans); unplugged: - spin_unlock_irqrestore(&trans->shrd->lock, flags); + spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); return IRQ_HANDLED; none: @@ -1329,7 +1330,7 @@ static irqreturn_t iwl_isr(int irq, void *data) !trans_pcie->inta) iwl_enable_interrupts(trans); - spin_unlock_irqrestore(&trans->shrd->lock, flags); + spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); return IRQ_NONE; } @@ -1363,7 +1364,7 @@ irqreturn_t iwl_isr_ict(int irq, void *data) trace_iwlwifi_dev_irq(priv(trans)); - spin_lock_irqsave(&trans->shrd->lock, flags); + spin_lock_irqsave(&trans_pcie->irq_lock, flags); /* Disable (but don't clear!) interrupts here to avoid * back-to-back ISRs and sporadic interrupts from our NIC. @@ -1434,7 +1435,7 @@ irqreturn_t iwl_isr_ict(int irq, void *data) iwl_enable_interrupts(trans); } - spin_unlock_irqrestore(&trans->shrd->lock, flags); + spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); return IRQ_HANDLED; none: @@ -1445,6 +1446,6 @@ irqreturn_t iwl_isr_ict(int irq, void *data) !trans_pcie->inta) iwl_enable_interrupts(trans); - spin_unlock_irqrestore(&trans->shrd->lock, flags); + spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); return IRQ_NONE; } diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c index 08e0a7da48a9..a3cebd76dc0c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c @@ -492,7 +492,7 @@ void iwl_trans_pcie_tx_agg_setup(struct iwl_trans *trans, ra_tid = BUILD_RAxTID(sta_id, tid); - spin_lock_irqsave(&trans->shrd->lock, flags); + spin_lock_irqsave(&trans_pcie->irq_lock, flags); /* Stop this Tx queue before configuring it */ iwlagn_tx_queue_stop_scheduler(trans, txq_id); @@ -532,7 +532,7 @@ void iwl_trans_pcie_tx_agg_setup(struct iwl_trans *trans, trans_pcie->txq[txq_id].sta_id = sta_id; trans_pcie->txq[txq_id].tid = tid; - spin_unlock_irqrestore(&trans->shrd->lock, flags); + spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); } /* diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c index e8d1dbfa1aea..176063c4f781 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c +++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c @@ -219,10 +219,10 @@ static int iwl_rx_init(struct iwl_trans *trans) iwl_trans_rx_hw_init(trans, rxq); - spin_lock_irqsave(&trans->shrd->lock, flags); + spin_lock_irqsave(&trans_pcie->irq_lock, flags); rxq->need_update = 1; iwl_rx_queue_update_write_ptr(trans, rxq); - spin_unlock_irqrestore(&trans->shrd->lock, flags); + spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); return 0; } @@ -585,7 +585,7 @@ static int iwl_tx_init(struct iwl_trans *trans) alloc = true; } - spin_lock_irqsave(&trans->shrd->lock, flags); + spin_lock_irqsave(&trans_pcie->irq_lock, flags); /* Turn off all Tx DMA fifos */ iwl_write_prph(trans, SCD_TXFACT, 0); @@ -594,7 +594,7 @@ static int iwl_tx_init(struct iwl_trans *trans) iwl_write_direct32(trans, FH_KW_MEM_ADDR_REG, trans_pcie->kw.dma >> 4); - spin_unlock_irqrestore(&trans->shrd->lock, flags); + spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); /* Alloc and init all Tx queues, including the command queue (#4/#9) */ for (txq_id = 0; txq_id < hw_params(trans).max_txq_num; txq_id++) { @@ -803,17 +803,18 @@ static void iwl_apm_stop(struct iwl_trans *trans) static int iwl_nic_init(struct iwl_trans *trans) { + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); unsigned long flags; /* nic_init */ - spin_lock_irqsave(&trans->shrd->lock, flags); + spin_lock_irqsave(&trans_pcie->irq_lock, flags); iwl_apm_init(trans); /* Set interrupt coalescing calibration timer to default (512 usecs) */ iwl_write8(trans, CSR_INT_COALESCING, IWL_HOST_INT_CALIB_TIMEOUT_DEF); - spin_unlock_irqrestore(&trans->shrd->lock, flags); + spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); iwl_set_pwr_vmain(trans); @@ -1078,10 +1079,15 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans, struct fw_img *fw) /* * Activate/Deactivate Tx DMA/FIFO channels according tx fifos mask - * must be called under priv->shrd->lock and mac access + * must be called under the irq lock and with MAC access */ static void iwl_trans_txq_set_sched(struct iwl_trans *trans, u32 mask) { + struct iwl_trans_pcie __maybe_unused *trans_pcie = + IWL_TRANS_GET_PCIE_TRANS(trans); + + lockdep_assert_held(&trans_pcie->irq_lock); + iwl_write_prph(trans, SCD_TXFACT, mask); } @@ -1095,7 +1101,7 @@ static void iwl_tx_start(struct iwl_trans *trans) int i, chan; u32 reg_val; - spin_lock_irqsave(&trans->shrd->lock, flags); + spin_lock_irqsave(&trans_pcie->irq_lock, flags); trans_pcie->scd_base_addr = iwl_read_prph(trans, SCD_SRAM_BASE_ADDR); @@ -1191,7 +1197,7 @@ static void iwl_tx_start(struct iwl_trans *trans) fifo, 0); } - spin_unlock_irqrestore(&trans->shrd->lock, flags); + spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); /* Enable L1-Active */ iwl_clear_bits_prph(trans, APMG_PCIDEV_STT_REG, @@ -1214,7 +1220,7 @@ static int iwl_trans_tx_stop(struct iwl_trans *trans) struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); /* Turn off all Tx DMA fifos */ - spin_lock_irqsave(&trans->shrd->lock, flags); + spin_lock_irqsave(&trans_pcie->irq_lock, flags); iwl_trans_txq_set_sched(trans, 0); @@ -1230,7 +1236,7 @@ static int iwl_trans_tx_stop(struct iwl_trans *trans) iwl_read_direct32(trans, FH_TSSR_TX_STATUS_REG)); } - spin_unlock_irqrestore(&trans->shrd->lock, flags); + spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); if (!trans_pcie->txq) { IWL_WARN(trans, "Stopping tx queues that aren't allocated..."); @@ -1250,9 +1256,9 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); /* tell the device to stop sending interrupts */ - spin_lock_irqsave(&trans->shrd->lock, flags); + spin_lock_irqsave(&trans_pcie->irq_lock, flags); iwl_disable_interrupts(trans); - spin_unlock_irqrestore(&trans->shrd->lock, flags); + spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); /* device going down, Stop using ICT table */ iwl_disable_ict(trans); @@ -1285,9 +1291,9 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) /* Upon stop, the APM issues an interrupt if HW RF kill is set. * Clean again the interrupt here */ - spin_lock_irqsave(&trans->shrd->lock, flags); + spin_lock_irqsave(&trans_pcie->irq_lock, flags); iwl_disable_interrupts(trans); - spin_unlock_irqrestore(&trans->shrd->lock, flags); + spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); /* wait to make sure we flush pending tasklet*/ synchronize_irq(trans->irq); @@ -2261,6 +2267,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct iwl_shared *shrd, trans->shrd = shrd; trans_pcie->trans = trans; spin_lock_init(&trans->hcmd_lock); + spin_lock_init(&trans_pcie->irq_lock); /* W/A - seems to solve weird behavior. We need to remove this if we * don't want to stay in L1 all the time. This wastes a lot of power */ From b1c23d9ec3afb85bd299e4f3859dce555fd55c8a Mon Sep 17 00:00:00 2001 From: Don Fry Date: Tue, 7 Feb 2012 14:45:58 -0800 Subject: [PATCH 07/26] iwlwifi: create iwl_nic structure Create iwl_nic structure and link it together. Signed-off-by: Don Fry Signed-off-by: Wey-Yi Guy --- drivers/net/wireless/iwlwifi/iwl-pci.c | 18 +++++++++-- drivers/net/wireless/iwlwifi/iwl-shared.h | 3 ++ drivers/net/wireless/iwlwifi/iwl-ucode.h | 37 +++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-wifi.h | 30 ++++++++++++++++++ 4 files changed, 86 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-pci.c b/drivers/net/wireless/iwlwifi/iwl-pci.c index 3e2fce4ce00c..519067020534 100644 --- a/drivers/net/wireless/iwlwifi/iwl-pci.c +++ b/drivers/net/wireless/iwlwifi/iwl-pci.c @@ -70,6 +70,7 @@ #include "iwl-trans.h" #include "iwl-csr.h" #include "iwl-cfg.h" +#include "iwl-wifi.h" #define IWL_PCI_DEVICE(dev, subdev, cfg) \ .vendor = PCI_VENDOR_ID_INTEL, .device = (dev), \ @@ -282,13 +283,23 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) bus->shrd->bus = bus; + /* temporarily create this here */ + bus->shrd->nic = kzalloc(sizeof(*bus->shrd->nic), GFP_KERNEL); + if (!bus->shrd->nic) { + dev_printk(KERN_ERR, &pdev->dev, + "Couldn't allocate iwl_nic"); + err = -ENOMEM; + goto out_free_bus; + } + /* and initialize it as well, temporarily */ + bus->shrd->nic->shrd = bus->shrd; pci_set_drvdata(pdev, bus); #ifdef CONFIG_IWLWIFI_IDI trans(bus) = iwl_trans_idi_alloc(bus->shrd, pdev, ent); if (trans(bus) == NULL) { err = -ENOMEM; - goto out_free_bus; + goto out_free_nic; } err = iwl_probe(bus, &trans_ops_idi, cfg); @@ -296,7 +307,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) trans(bus) = iwl_trans_pcie_alloc(bus->shrd, pdev, ent); if (trans(bus) == NULL) { err = -ENOMEM; - goto out_free_bus; + goto out_free_nic; } err = iwl_probe(bus, &trans_ops_pcie, cfg); @@ -309,6 +320,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) out_free_trans: iwl_trans_free(trans(bus)); pci_set_drvdata(pdev, NULL); +out_free_nic: + kfree(bus->shrd->nic); out_free_bus: kfree(bus->shrd); kfree(bus); @@ -325,6 +338,7 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev) pci_set_drvdata(pdev, NULL); + kfree(bus->shrd->nic); kfree(bus->shrd); kfree(bus); } diff --git a/drivers/net/wireless/iwlwifi/iwl-shared.h b/drivers/net/wireless/iwlwifi/iwl-shared.h index 42bf43b9c406..8c6fc6e20768 100644 --- a/drivers/net/wireless/iwlwifi/iwl-shared.h +++ b/drivers/net/wireless/iwlwifi/iwl-shared.h @@ -358,6 +358,7 @@ struct iwl_cfg { * @cfg: see struct iwl_cfg * @priv: pointer to the upper layer data * @trans: pointer to the transport layer data + * @nic: pointer to the nic data * @hw_params: see struct iwl_hw_params * @lock: protect general shared data * @sta_lock: protects the station table. @@ -388,6 +389,7 @@ struct iwl_shared { struct iwl_cfg *cfg; struct iwl_priv *priv; struct iwl_trans *trans; + struct iwl_nic *nic; struct iwl_hw_params hw_params; spinlock_t lock; @@ -418,6 +420,7 @@ struct iwl_shared { #define priv(_m) ((_m)->shrd->priv) #define cfg(_m) ((_m)->shrd->cfg) #define bus(_m) ((_m)->shrd->bus) +#define nic(_m) ((_m)->shrd->nic) #define trans(_m) ((_m)->shrd->trans) #define hw_params(_m) ((_m)->shrd->hw_params) diff --git a/drivers/net/wireless/iwlwifi/iwl-ucode.h b/drivers/net/wireless/iwlwifi/iwl-ucode.h index eccf92519a84..18c77e9bb9b0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-ucode.h +++ b/drivers/net/wireless/iwlwifi/iwl-ucode.h @@ -63,6 +63,10 @@ #ifndef __iwl_ucode_h__ #define __iwl_ucode_h__ +#include "iwl-trans.h" + +#include + /* v1/v2 uCode file layout */ struct iwl_ucode_header { __le32 ver; /* major/minor/API/serial */ @@ -171,6 +175,39 @@ struct iwl_tlv_ucode_header { u8 data[0]; }; +struct iwl_ucode_capabilities { + u32 max_probe_length; + u32 standard_phy_calibration_size; + u32 flags; +}; + +/** + * struct iwl_fw - variables associated with the firmware + * + * @ucode_ver: ucode version from the ucode file + * @fw_version: firmware version string + * @ucode_rt: run time ucode image + * @ucode_init: init ucode image + * @ucode_wowlan: wake on wireless ucode image (optional) + * @ucode_capa: capabilities parsed from the ucode file. + * @enhance_sensitivity_table: device can do enhanced sensitivity. + */ +struct iwl_fw { + + /* ucode image and variables */ + u32 ucode_ver; /* version of ucode, copy of + iwl_ucode.ver */ + char fw_version[ETHTOOL_BUSINFO_LEN]; + + /* ucode images */ + struct fw_img ucode_rt; + struct fw_img ucode_init; + struct fw_img ucode_wowlan; + + struct iwl_ucode_capabilities ucode_capa; + bool enhance_sensitivity_table; +}; + struct iwl_priv; int __must_check iwl_request_firmware(struct iwl_priv *priv, bool first); diff --git a/drivers/net/wireless/iwlwifi/iwl-wifi.h b/drivers/net/wireless/iwlwifi/iwl-wifi.h index 7e6eb20823cf..a34708d19380 100644 --- a/drivers/net/wireless/iwlwifi/iwl-wifi.h +++ b/drivers/net/wireless/iwlwifi/iwl-wifi.h @@ -64,6 +64,36 @@ #define __iwl_wifi_h__ #include "iwl-shared.h" +#include "iwl-ucode.h" + +/** + * struct iwl_nic - nic common data + * @fw: the iwl_fw structure + * @shrd: pointer to common shared structure + * @fw_index: firmware revision to try loading + * @firmware_name: composite filename of ucode file to load + * @init_evtlog_ptr: event log offset for init ucode. + * @init_evtlog_size: event log size for init ucode. + * @init_errlog_ptr: error log offfset for init ucode. + * @inst_evtlog_ptr: event log offset for runtime ucode. + * @inst_evtlog_size: event log size for runtime ucode. + * @inst_errlog_ptr: error log offfset for runtime ucode. + * @request_firmware_complete: the firmware has been obtained from user space + */ +struct iwl_nic { + struct iwl_fw fw; + + struct iwl_shared *shrd; + + int fw_index; /* firmware we're trying to load */ + char firmware_name[25]; /* name of firmware file to load */ + + u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr; + u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr; + + struct completion request_firmware_complete; +}; + int iwl_send_bt_env(struct iwl_trans *trans, u8 action, u8 type); void iwl_send_prio_tbl(struct iwl_trans *trans); From d359667767e845d86f60a4ea6374ccb6b8fe0ce5 Mon Sep 17 00:00:00 2001 From: Don Fry Date: Mon, 6 Feb 2012 15:51:15 -0800 Subject: [PATCH 08/26] iwlwifi: move ucode_ver to iwl_nic Delete ucode_ver from iwl_priv and use iwl_nic instead. Signed-off-by: Don Fry Signed-off-by: Wey-Yi Guy --- drivers/net/wireless/iwlwifi/iwl-agn-lib.c | 2 +- drivers/net/wireless/iwlwifi/iwl-agn.c | 2 +- drivers/net/wireless/iwlwifi/iwl-dev.h | 3 --- drivers/net/wireless/iwlwifi/iwl-testmode.c | 6 +++-- drivers/net/wireless/iwlwifi/iwl-ucode.c | 29 ++++++++++++--------- 5 files changed, 22 insertions(+), 20 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index 30b99b9abf7f..c368433f8bc8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -77,7 +77,7 @@ int iwlagn_send_tx_power(struct iwl_priv *priv) tx_power_cmd.flags = IWLAGN_TX_POWER_NO_CLOSED; tx_power_cmd.srv_chan_lmt = IWLAGN_TX_POWER_AUTO; - if (IWL_UCODE_API(priv->ucode_ver) == 1) + if (IWL_UCODE_API(nic(priv)->fw.ucode_ver) == 1) tx_ant_cfg_cmd = REPLY_TX_POWER_DBM_CMD_V1; else tx_ant_cfg_cmd = REPLY_TX_POWER_DBM_CMD; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 1cf99a586ec9..9e902f7e9d35 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -618,7 +618,7 @@ static int iwlagn_send_tx_ant_config(struct iwl_priv *priv, u8 valid_tx_ant) .valid = cpu_to_le32(valid_tx_ant), }; - if (IWL_UCODE_API(priv->ucode_ver) > 1) { + if (IWL_UCODE_API(nic(priv)->fw.ucode_ver) > 1) { IWL_DEBUG_HC(priv, "select valid tx ant: %u\n", valid_tx_ant); return iwl_trans_send_cmd_pdu(trans(priv), TX_ANT_CONFIGURATION_CMD, diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index db37877eed77..f3dc67c8b3eb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -789,9 +789,6 @@ struct iwl_priv { /* uCode images, save to reload in case of failure */ int fw_index; /* firmware we're trying to load */ - u32 ucode_ver; /* version of ucode, copy of - iwl_ucode.ver */ - char firmware_name[25]; struct iwl_rxon_context contexts[NUM_IWL_RXON_CTX]; diff --git a/drivers/net/wireless/iwlwifi/iwl-testmode.c b/drivers/net/wireless/iwlwifi/iwl-testmode.c index e54a1dd7014a..963cc6c89a46 100644 --- a/drivers/net/wireless/iwlwifi/iwl-testmode.c +++ b/drivers/net/wireless/iwlwifi/iwl-testmode.c @@ -553,14 +553,16 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb) break; case IWL_TM_CMD_APP2DEV_GET_FW_VERSION: - IWL_INFO(priv, "uCode version raw: 0x%x\n", priv->ucode_ver); + IWL_INFO(priv, "uCode version raw: 0x%x\n", + nic(priv)->fw.ucode_ver); skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20); if (!skb) { IWL_ERR(priv, "Memory allocation fail\n"); return -ENOMEM; } - NLA_PUT_U32(skb, IWL_TM_ATTR_FW_VERSION, priv->ucode_ver); + NLA_PUT_U32(skb, IWL_TM_ATTR_FW_VERSION, + nic(priv)->fw.ucode_ver); status = cfg80211_testmode_reply(skb); if (status < 0) IWL_ERR(priv, "Error sending msg : %d\n", status); diff --git a/drivers/net/wireless/iwlwifi/iwl-ucode.c b/drivers/net/wireless/iwlwifi/iwl-ucode.c index 11b659ab261d..ca3cd8a9046f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-ucode.c +++ b/drivers/net/wireless/iwlwifi/iwl-ucode.c @@ -738,12 +738,13 @@ static int iwlagn_load_legacy_firmware(struct iwl_priv *priv, const struct firmware *ucode_raw, struct iwlagn_firmware_pieces *pieces) { + struct iwl_nic *nic = nic(priv); struct iwl_ucode_header *ucode = (void *)ucode_raw->data; u32 api_ver, hdr_size; const u8 *src; - priv->ucode_ver = le32_to_cpu(ucode->ver); - api_ver = IWL_UCODE_API(priv->ucode_ver); + nic->fw.ucode_ver = le32_to_cpu(ucode->ver); + api_ver = IWL_UCODE_API(nic->fw.ucode_ver); switch (api_ver) { default: @@ -804,6 +805,7 @@ static int iwlagn_load_firmware(struct iwl_priv *priv, struct iwlagn_firmware_pieces *pieces, struct iwlagn_ucode_capabilities *capa) { + struct iwl_nic *nic = nic(priv); struct iwl_tlv_ucode_header *ucode = (void *)ucode_raw->data; struct iwl_ucode_tlv *tlv; size_t len = ucode_raw->size; @@ -843,7 +845,7 @@ static int iwlagn_load_firmware(struct iwl_priv *priv, "uCode alternative %d not available, choosing %d\n", tmp, wanted_alternative); - priv->ucode_ver = le32_to_cpu(ucode->ver); + nic->fw.ucode_ver = le32_to_cpu(ucode->ver); pieces->build = le32_to_cpu(ucode->build); data = ucode->data; @@ -1008,6 +1010,7 @@ static int iwlagn_load_firmware(struct iwl_priv *priv, static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) { struct iwl_priv *priv = context; + struct iwl_nic *nic = nic(priv); struct iwl_ucode_header *ucode; int err; struct iwlagn_firmware_pieces pieces; @@ -1057,7 +1060,7 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) if (err) goto try_again; - api_ver = IWL_UCODE_API(priv->ucode_ver); + api_ver = IWL_UCODE_API(nic->fw.ucode_ver); build = pieces.build; /* @@ -1097,19 +1100,19 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) buildstr[0] = '\0'; IWL_INFO(priv, "loaded firmware version %u.%u.%u.%u%s\n", - IWL_UCODE_MAJOR(priv->ucode_ver), - IWL_UCODE_MINOR(priv->ucode_ver), - IWL_UCODE_API(priv->ucode_ver), - IWL_UCODE_SERIAL(priv->ucode_ver), + IWL_UCODE_MAJOR(nic->fw.ucode_ver), + IWL_UCODE_MINOR(nic->fw.ucode_ver), + IWL_UCODE_API(nic->fw.ucode_ver), + IWL_UCODE_SERIAL(nic->fw.ucode_ver), buildstr); snprintf(priv->hw->wiphy->fw_version, sizeof(priv->hw->wiphy->fw_version), "%u.%u.%u.%u%s", - IWL_UCODE_MAJOR(priv->ucode_ver), - IWL_UCODE_MINOR(priv->ucode_ver), - IWL_UCODE_API(priv->ucode_ver), - IWL_UCODE_SERIAL(priv->ucode_ver), + IWL_UCODE_MAJOR(nic->fw.ucode_ver), + IWL_UCODE_MINOR(nic->fw.ucode_ver), + IWL_UCODE_API(nic->fw.ucode_ver), + IWL_UCODE_SERIAL(nic->fw.ucode_ver), buildstr); /* @@ -1119,7 +1122,7 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) */ IWL_DEBUG_INFO(priv, "f/w package hdr ucode version raw = 0x%x\n", - priv->ucode_ver); + nic->fw.ucode_ver); IWL_DEBUG_INFO(priv, "f/w package hdr runtime inst size = %Zd\n", pieces.inst_size); IWL_DEBUG_INFO(priv, "f/w package hdr runtime data size = %Zd\n", From f6fd51d9a5abc9aa90246ddc82bbca376c06462e Mon Sep 17 00:00:00 2001 From: Don Fry Date: Mon, 6 Feb 2012 15:54:31 -0800 Subject: [PATCH 09/26] iwlwifi: move fw_index from iwl_priv to iwl_nic Delete fw_index from iwl_priv and use iwl_nic instead. Signed-off-by: Don Fry Signed-off-by: Wey-Yi Guy --- drivers/net/wireless/iwlwifi/iwl-dev.h | 1 - drivers/net/wireless/iwlwifi/iwl-ucode.c | 23 ++++++++++++----------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index f3dc67c8b3eb..008287f08d75 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -788,7 +788,6 @@ struct iwl_priv { struct mac_address addresses[2]; /* uCode images, save to reload in case of failure */ - int fw_index; /* firmware we're trying to load */ char firmware_name[25]; struct iwl_rxon_context contexts[NUM_IWL_RXON_CTX]; diff --git a/drivers/net/wireless/iwlwifi/iwl-ucode.c b/drivers/net/wireless/iwlwifi/iwl-ucode.c index ca3cd8a9046f..c3ac2cc7a795 100644 --- a/drivers/net/wireless/iwlwifi/iwl-ucode.c +++ b/drivers/net/wireless/iwlwifi/iwl-ucode.c @@ -690,23 +690,24 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context); int __must_check iwl_request_firmware(struct iwl_priv *priv, bool first) { + struct iwl_nic *nic = nic(priv); const char *name_pre = cfg(priv)->fw_name_pre; char tag[8]; if (first) { #ifdef CONFIG_IWLWIFI_DEBUG_EXPERIMENTAL_UCODE - priv->fw_index = UCODE_EXPERIMENTAL_INDEX; + nic->fw_index = UCODE_EXPERIMENTAL_INDEX; strcpy(tag, UCODE_EXPERIMENTAL_TAG); - } else if (priv->fw_index == UCODE_EXPERIMENTAL_INDEX) { + } else if (nic->fw_index == UCODE_EXPERIMENTAL_INDEX) { #endif - priv->fw_index = cfg(priv)->ucode_api_max; - sprintf(tag, "%d", priv->fw_index); + nic->fw_index = cfg(priv)->ucode_api_max; + sprintf(tag, "%d", nic->fw_index); } else { - priv->fw_index--; - sprintf(tag, "%d", priv->fw_index); + nic->fw_index--; + sprintf(tag, "%d", nic->fw_index); } - if (priv->fw_index < cfg(priv)->ucode_api_min) { + if (nic->fw_index < cfg(priv)->ucode_api_min) { IWL_ERR(priv, "no suitable firmware found!\n"); return -ENOENT; } @@ -714,7 +715,7 @@ int __must_check iwl_request_firmware(struct iwl_priv *priv, bool first) sprintf(priv->firmware_name, "%s%s%s", name_pre, tag, ".ucode"); IWL_DEBUG_INFO(priv, "attempting to load firmware %s'%s'\n", - (priv->fw_index == UCODE_EXPERIMENTAL_INDEX) + (nic->fw_index == UCODE_EXPERIMENTAL_INDEX) ? "EXPERIMENTAL " : "", priv->firmware_name); @@ -1032,7 +1033,7 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) memset(&pieces, 0, sizeof(pieces)); if (!ucode_raw) { - if (priv->fw_index <= api_ok) + if (nic->fw_index <= api_ok) IWL_ERR(priv, "request for firmware file '%s' failed.\n", priv->firmware_name); @@ -1069,7 +1070,7 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) * on the API version read from firmware header from here on forward */ /* no api version check required for experimental uCode */ - if (priv->fw_index != UCODE_EXPERIMENTAL_INDEX) { + if (nic->fw_index != UCODE_EXPERIMENTAL_INDEX) { if (api_ver < api_min || api_ver > api_max) { IWL_ERR(priv, "Driver unable to support your firmware API. " @@ -1094,7 +1095,7 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) if (build) sprintf(buildstr, " build %u%s", build, - (priv->fw_index == UCODE_EXPERIMENTAL_INDEX) + (nic->fw_index == UCODE_EXPERIMENTAL_INDEX) ? " (EXP)" : ""); else buildstr[0] = '\0'; From 737805ff7a15105b77d83c7c3b17fa0868cb864e Mon Sep 17 00:00:00 2001 From: Don Fry Date: Mon, 6 Feb 2012 15:57:40 -0800 Subject: [PATCH 10/26] iwlwifi: move firmware_name to iwl_nic Delete firmware_name from iwl_priv and use iwl_nic instead. Signed-off-by: Don Fry Signed-off-by: Wey-Yi Guy --- drivers/net/wireless/iwlwifi/iwl-dev.h | 3 --- drivers/net/wireless/iwlwifi/iwl-ucode.c | 10 +++++----- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 008287f08d75..332101006353 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -787,9 +787,6 @@ struct iwl_priv { /* EEPROM MAC addresses */ struct mac_address addresses[2]; - /* uCode images, save to reload in case of failure */ - char firmware_name[25]; - struct iwl_rxon_context contexts[NUM_IWL_RXON_CTX]; __le16 switch_channel; diff --git a/drivers/net/wireless/iwlwifi/iwl-ucode.c b/drivers/net/wireless/iwlwifi/iwl-ucode.c index c3ac2cc7a795..0ba8ea910274 100644 --- a/drivers/net/wireless/iwlwifi/iwl-ucode.c +++ b/drivers/net/wireless/iwlwifi/iwl-ucode.c @@ -712,14 +712,14 @@ int __must_check iwl_request_firmware(struct iwl_priv *priv, bool first) return -ENOENT; } - sprintf(priv->firmware_name, "%s%s%s", name_pre, tag, ".ucode"); + sprintf(nic->firmware_name, "%s%s%s", name_pre, tag, ".ucode"); IWL_DEBUG_INFO(priv, "attempting to load firmware %s'%s'\n", (nic->fw_index == UCODE_EXPERIMENTAL_INDEX) ? "EXPERIMENTAL " : "", - priv->firmware_name); + nic->firmware_name); - return request_firmware_nowait(THIS_MODULE, 1, priv->firmware_name, + return request_firmware_nowait(THIS_MODULE, 1, nic->firmware_name, trans(priv)->dev, GFP_KERNEL, priv, iwl_ucode_callback); } @@ -1036,12 +1036,12 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) if (nic->fw_index <= api_ok) IWL_ERR(priv, "request for firmware file '%s' failed.\n", - priv->firmware_name); + nic->firmware_name); goto try_again; } IWL_DEBUG_INFO(priv, "Loaded firmware file '%s' (%zd bytes).\n", - priv->firmware_name, ucode_raw->size); + nic->firmware_name, ucode_raw->size); /* Make sure that we got at least the API version number */ if (ucode_raw->size < 4) { From 96502ceb1c122cf5496c9176bb690a52b3fab362 Mon Sep 17 00:00:00 2001 From: Don Fry Date: Mon, 6 Feb 2012 16:00:14 -0800 Subject: [PATCH 11/26] iwlwifi: move firmware_loading_complete to iwl_nic Move firmware_loading_complete from iwl_priv to iwl_nic and rename it to more accurately reflect what it does. Signed-off-by: Don Fry Signed-off-by: Wey-Yi Guy --- drivers/net/wireless/iwlwifi/iwl-agn.c | 4 ++-- drivers/net/wireless/iwlwifi/iwl-dev.h | 2 -- drivers/net/wireless/iwlwifi/iwl-ucode.c | 4 ++-- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 9e902f7e9d35..12803d3fb2f9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1273,7 +1273,7 @@ int iwl_probe(struct iwl_bus *bus, const struct iwl_trans_ops *trans_ops, iwl_power_initialize(priv); iwl_tt_initialize(priv); - init_completion(&priv->firmware_loading_complete); + init_completion(&nic(priv)->request_firmware_complete); err = iwl_request_firmware(priv, true); if (err) @@ -1296,7 +1296,7 @@ out: void __devexit iwl_remove(struct iwl_priv * priv) { - wait_for_completion(&priv->firmware_loading_complete); + wait_for_completion(&nic(priv)->request_firmware_complete); IWL_DEBUG_INFO(priv, "*** UNLOAD DRIVER ***\n"); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 332101006353..0d0b4bb9dc63 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -864,8 +864,6 @@ struct iwl_priv { struct iwl_rx_phy_res last_phy_res; bool last_phy_res_valid; - struct completion firmware_loading_complete; - u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr; u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr; diff --git a/drivers/net/wireless/iwlwifi/iwl-ucode.c b/drivers/net/wireless/iwlwifi/iwl-ucode.c index 0ba8ea910274..51a8fb353a6e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-ucode.c +++ b/drivers/net/wireless/iwlwifi/iwl-ucode.c @@ -1273,7 +1273,7 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) /* We have our copies now, allow OS release its copies */ release_firmware(ucode_raw); - complete(&priv->firmware_loading_complete); + complete(&nic->request_firmware_complete); return; try_again: @@ -1287,7 +1287,7 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) IWL_ERR(priv, "failed to allocate pci memory\n"); iwl_dealloc_ucode(trans(priv)); out_unbind: - complete(&priv->firmware_loading_complete); + complete(&nic->request_firmware_complete); device_release_driver(trans(priv)->dev); release_firmware(ucode_raw); } From 6516174d1a42c1b1b2861360bf44fe9992fb0f7e Mon Sep 17 00:00:00 2001 From: Don Fry Date: Tue, 7 Feb 2012 15:00:12 -0800 Subject: [PATCH 12/26] iwlwifi: Move ucode pointers to iwl_fw The ucode image is a ucode related thing not a transport one. Move them. Signed-off-by: Don Fry Signed-off-by: Wey-Yi Guy --- drivers/net/wireless/iwlwifi/iwl-debugfs.c | 11 +++---- drivers/net/wireless/iwlwifi/iwl-mac80211.c | 8 ++--- drivers/net/wireless/iwlwifi/iwl-testmode.c | 12 ++++---- drivers/net/wireless/iwlwifi/iwl-trans.h | 16 +--------- drivers/net/wireless/iwlwifi/iwl-ucode.c | 33 +++++++++++---------- drivers/net/wireless/iwlwifi/iwl-ucode.h | 14 +++++++-- 6 files changed, 46 insertions(+), 48 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 136de6fb3fa4..ad74138e1c70 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -40,6 +40,7 @@ #include "iwl-core.h" #include "iwl-io.h" #include "iwl-agn.h" +#include "iwl-wifi.h" /* create and remove of files */ #define DEBUGFS_ADD_FILE(name, parent, mode) do { \ @@ -234,12 +235,12 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file, /* default is to dump the entire data segment */ if (!priv->dbgfs_sram_offset && !priv->dbgfs_sram_len) { - struct iwl_trans *trans = trans(priv); + struct iwl_nic *nic = nic(priv); priv->dbgfs_sram_offset = 0x800000; - if (trans->shrd->ucode_type == IWL_UCODE_INIT) - priv->dbgfs_sram_len = trans->ucode_init.data.len; + if (nic->shrd->ucode_type == IWL_UCODE_INIT) + priv->dbgfs_sram_len = nic->fw.ucode_init.data.len; else - priv->dbgfs_sram_len = trans->ucode_rt.data.len; + priv->dbgfs_sram_len = nic->fw.ucode_rt.data.len; } len = priv->dbgfs_sram_len; @@ -342,7 +343,7 @@ static ssize_t iwl_dbgfs_wowlan_sram_read(struct file *file, return simple_read_from_buffer(user_buf, count, ppos, priv->wowlan_sram, - trans(priv)->ucode_wowlan.data.len); + nic(priv)->fw.ucode_wowlan.data.len); } static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) diff --git a/drivers/net/wireless/iwlwifi/iwl-mac80211.c b/drivers/net/wireless/iwlwifi/iwl-mac80211.c index 17358cfb68a9..ca0c46506674 100644 --- a/drivers/net/wireless/iwlwifi/iwl-mac80211.c +++ b/drivers/net/wireless/iwlwifi/iwl-mac80211.c @@ -195,7 +195,7 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv, WIPHY_FLAG_DISABLE_BEACON_HINTS | WIPHY_FLAG_IBSS_RSN; - if (trans(priv)->ucode_wowlan.code.len && + if (nic(priv)->fw.ucode_wowlan.code.len && device_can_wakeup(trans(priv)->dev)) { hw->wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT | @@ -453,17 +453,17 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw) #ifdef CONFIG_IWLWIFI_DEBUGFS if (ret == 0) { - struct iwl_trans *trans = trans(priv); + struct iwl_nic *nic = nic(priv); if (!priv->wowlan_sram) priv->wowlan_sram = - kzalloc(trans->ucode_wowlan.data.len, + kzalloc(nic->fw.ucode_wowlan.data.len, GFP_KERNEL); if (priv->wowlan_sram) _iwl_read_targ_mem_words( trans(priv), 0x800000, priv->wowlan_sram, - trans->ucode_wowlan.data.len / 4); + nic->fw.ucode_wowlan.data.len / 4); } #endif } diff --git a/drivers/net/wireless/iwlwifi/iwl-testmode.c b/drivers/net/wireless/iwlwifi/iwl-testmode.c index 963cc6c89a46..5f00a3712707 100644 --- a/drivers/net/wireless/iwlwifi/iwl-testmode.c +++ b/drivers/net/wireless/iwlwifi/iwl-testmode.c @@ -591,16 +591,16 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb) } switch (priv->shrd->ucode_type) { case IWL_UCODE_REGULAR: - inst_size = trans(priv)->ucode_rt.code.len; - data_size = trans(priv)->ucode_rt.data.len; + inst_size = nic(priv)->fw.ucode_rt.code.len; + data_size = nic(priv)->fw.ucode_rt.data.len; break; case IWL_UCODE_INIT: - inst_size = trans(priv)->ucode_init.code.len; - data_size = trans(priv)->ucode_init.data.len; + inst_size = nic(priv)->fw.ucode_init.code.len; + data_size = nic(priv)->fw.ucode_init.data.len; break; case IWL_UCODE_WOWLAN: - inst_size = trans(priv)->ucode_wowlan.code.len; - data_size = trans(priv)->ucode_wowlan.data.len; + inst_size = nic(priv)->fw.ucode_wowlan.code.len; + data_size = nic(priv)->fw.ucode_wowlan.data.len; break; case IWL_UCODE_NONE: IWL_ERR(priv, "No uCode has not been loaded\n"); diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index ae68c51e5327..913df937c964 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -68,6 +68,7 @@ #include "iwl-shared.h" #include "iwl-commands.h" +#include "iwl-ucode.h" /*This file includes the declaration that are exported from the transport * layer */ @@ -131,18 +132,6 @@ struct iwl_host_cmd { u8 id; }; -/* one for each uCode image (inst/data, boot/init/runtime) */ -struct fw_desc { - dma_addr_t p_addr; /* hardware address */ - void *v_addr; /* software address */ - u32 len; /* size in bytes */ -}; - -struct fw_img { - struct fw_desc code; /* firmware code image */ - struct fw_desc data; /* firmware data image */ -}; - /** * struct iwl_trans_ops - transport specific operations * @start_hw: starts the HW- from that point on, the HW can send interrupts @@ -258,9 +247,6 @@ struct iwl_trans { char hw_id_str[52]; u8 ucode_write_complete; /* the image write is complete */ - struct fw_img ucode_rt; - struct fw_img ucode_init; - struct fw_img ucode_wowlan; /* eeprom related variables */ int nvm_device_type; diff --git a/drivers/net/wireless/iwlwifi/iwl-ucode.c b/drivers/net/wireless/iwlwifi/iwl-ucode.c index 51a8fb353a6e..36039eb54dd4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-ucode.c +++ b/drivers/net/wireless/iwlwifi/iwl-ucode.c @@ -99,9 +99,10 @@ static void iwl_free_fw_img(struct iwl_trans *trans, struct fw_img *img) void iwl_dealloc_ucode(struct iwl_trans *trans) { - iwl_free_fw_img(trans, &trans->ucode_rt); - iwl_free_fw_img(trans, &trans->ucode_init); - iwl_free_fw_img(trans, &trans->ucode_wowlan); + struct iwl_nic *nic = nic(trans); + iwl_free_fw_img(trans, &nic->fw.ucode_rt); + iwl_free_fw_img(trans, &nic->fw.ucode_init); + iwl_free_fw_img(trans, &nic->fw.ucode_wowlan); } static int iwl_alloc_fw_desc(struct iwl_trans *trans, struct fw_desc *desc, @@ -122,16 +123,16 @@ static int iwl_alloc_fw_desc(struct iwl_trans *trans, struct fw_desc *desc, return 0; } -static inline struct fw_img *iwl_get_ucode_image(struct iwl_trans *trans, +static inline struct fw_img *iwl_get_ucode_image(struct iwl_nic *nic, enum iwl_ucode_type ucode_type) { switch (ucode_type) { case IWL_UCODE_INIT: - return &trans->ucode_init; + return &nic->fw.ucode_init; case IWL_UCODE_WOWLAN: - return &trans->ucode_wowlan; + return &nic->fw.ucode_wowlan; case IWL_UCODE_REGULAR: - return &trans->ucode_rt; + return &nic->fw.ucode_rt; case IWL_UCODE_NONE: break; } @@ -456,7 +457,7 @@ static void iwl_print_mismatch_inst(struct iwl_trans *trans, static int iwl_verify_ucode(struct iwl_trans *trans, enum iwl_ucode_type ucode_type) { - struct fw_img *img = iwl_get_ucode_image(trans, ucode_type); + struct fw_img *img = iwl_get_ucode_image(nic(trans), ucode_type); if (!img) { IWL_ERR(trans, "Invalid ucode requested (%d)\n", ucode_type); @@ -583,7 +584,7 @@ int iwl_load_ucode_wait_alive(struct iwl_trans *trans, old_type = trans->shrd->ucode_type; trans->shrd->ucode_type = ucode_type; - fw = iwl_get_ucode_image(trans, ucode_type); + fw = iwl_get_ucode_image(nic(trans), ucode_type); if (!fw) return -EINVAL; @@ -647,7 +648,7 @@ int iwl_run_init_ucode(struct iwl_trans *trans) lockdep_assert_held(&trans->shrd->mutex); /* No init ucode required? Curious, but maybe ok */ - if (!trans->ucode_init.code.len) + if (!nic(trans)->fw.ucode_init.code.len) return 0; if (trans->shrd->ucode_type != IWL_UCODE_NONE) @@ -1163,21 +1164,21 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) /* Runtime instructions and 2 copies of data: * 1) unmodified from disk * 2) backup cache for save/restore during power-downs */ - if (iwl_alloc_fw_desc(trans(priv), &trans(priv)->ucode_rt.code, + if (iwl_alloc_fw_desc(trans(priv), &nic(priv)->fw.ucode_rt.code, pieces.inst, pieces.inst_size)) goto err_pci_alloc; - if (iwl_alloc_fw_desc(trans(priv), &trans(priv)->ucode_rt.data, + if (iwl_alloc_fw_desc(trans(priv), &nic(priv)->fw.ucode_rt.data, pieces.data, pieces.data_size)) goto err_pci_alloc; /* Initialization instructions and data */ if (pieces.init_size && pieces.init_data_size) { if (iwl_alloc_fw_desc(trans(priv), - &trans(priv)->ucode_init.code, + &nic(priv)->fw.ucode_init.code, pieces.init, pieces.init_size)) goto err_pci_alloc; if (iwl_alloc_fw_desc(trans(priv), - &trans(priv)->ucode_init.data, + &nic(priv)->fw.ucode_init.data, pieces.init_data, pieces.init_data_size)) goto err_pci_alloc; } @@ -1185,12 +1186,12 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) /* WoWLAN instructions and data */ if (pieces.wowlan_inst_size && pieces.wowlan_data_size) { if (iwl_alloc_fw_desc(trans(priv), - &trans(priv)->ucode_wowlan.code, + &nic(priv)->fw.ucode_wowlan.code, pieces.wowlan_inst, pieces.wowlan_inst_size)) goto err_pci_alloc; if (iwl_alloc_fw_desc(trans(priv), - &trans(priv)->ucode_wowlan.data, + &nic(priv)->fw.ucode_wowlan.data, pieces.wowlan_data, pieces.wowlan_data_size)) goto err_pci_alloc; diff --git a/drivers/net/wireless/iwlwifi/iwl-ucode.h b/drivers/net/wireless/iwlwifi/iwl-ucode.h index 18c77e9bb9b0..5e4b88e05c62 100644 --- a/drivers/net/wireless/iwlwifi/iwl-ucode.h +++ b/drivers/net/wireless/iwlwifi/iwl-ucode.h @@ -63,8 +63,6 @@ #ifndef __iwl_ucode_h__ #define __iwl_ucode_h__ -#include "iwl-trans.h" - #include /* v1/v2 uCode file layout */ @@ -181,6 +179,18 @@ struct iwl_ucode_capabilities { u32 flags; }; +/* one for each uCode image (inst/data, boot/init/runtime) */ +struct fw_desc { + dma_addr_t p_addr; /* hardware address */ + void *v_addr; /* software address */ + u32 len; /* size in bytes */ +}; + +struct fw_img { + struct fw_desc code; /* firmware code image */ + struct fw_desc data; /* firmware data image */ +}; + /** * struct iwl_fw - variables associated with the firmware * From 655ccceb59f8fbffc2ed151d07d03eb88f27adb6 Mon Sep 17 00:00:00 2001 From: Don Fry Date: Mon, 6 Feb 2012 16:37:46 -0800 Subject: [PATCH 13/26] iwlwifi: change args to ucode routines Change the prameters to the ucode (de)allocate routines to iwl_nic as they are not transport operations. Signed-off-by: Don Fry Signed-off-by: Wey-Yi Guy --- drivers/net/wireless/iwlwifi/iwl-agn.c | 2 +- drivers/net/wireless/iwlwifi/iwl-trans.h | 2 - drivers/net/wireless/iwlwifi/iwl-ucode.c | 65 ++++++++++++------------ drivers/net/wireless/iwlwifi/iwl-wifi.h | 2 + 4 files changed, 36 insertions(+), 35 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 12803d3fb2f9..ff22c4ae13b1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1316,7 +1316,7 @@ void __devexit iwl_remove(struct iwl_priv * priv) /*This will stop the queues, move the device to low power state */ iwl_trans_stop_device(trans(priv)); - iwl_dealloc_ucode(trans(priv)); + iwl_dealloc_ucode(nic(priv)); iwl_eeprom_free(priv->shrd); diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 913df937c964..7ea5f7733d2b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -396,8 +396,6 @@ static inline u32 iwl_trans_read32(struct iwl_trans *trans, u32 ofs) /***************************************************** * Utils functions ******************************************************/ -void iwl_dealloc_ucode(struct iwl_trans *trans); - int iwl_send_calib_results(struct iwl_trans *trans); int iwl_calib_set(struct iwl_trans *trans, const struct iwl_calib_hdr *cmd, int len); diff --git a/drivers/net/wireless/iwlwifi/iwl-ucode.c b/drivers/net/wireless/iwlwifi/iwl-ucode.c index 36039eb54dd4..26ead61d1f5c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-ucode.c +++ b/drivers/net/wireless/iwlwifi/iwl-ucode.c @@ -82,30 +82,29 @@ static struct iwl_wimax_coex_event_entry cu_priorities[COEX_NUM_OF_EVENTS] = { * ******************************************************************************/ -static void iwl_free_fw_desc(struct iwl_trans *trans, struct fw_desc *desc) +static void iwl_free_fw_desc(struct iwl_nic *nic, struct fw_desc *desc) { if (desc->v_addr) - dma_free_coherent(trans->dev, desc->len, + dma_free_coherent(trans(nic)->dev, desc->len, desc->v_addr, desc->p_addr); desc->v_addr = NULL; desc->len = 0; } -static void iwl_free_fw_img(struct iwl_trans *trans, struct fw_img *img) +static void iwl_free_fw_img(struct iwl_nic *nic, struct fw_img *img) { - iwl_free_fw_desc(trans, &img->code); - iwl_free_fw_desc(trans, &img->data); + iwl_free_fw_desc(nic, &img->code); + iwl_free_fw_desc(nic, &img->data); } -void iwl_dealloc_ucode(struct iwl_trans *trans) +void iwl_dealloc_ucode(struct iwl_nic *nic) { - struct iwl_nic *nic = nic(trans); - iwl_free_fw_img(trans, &nic->fw.ucode_rt); - iwl_free_fw_img(trans, &nic->fw.ucode_init); - iwl_free_fw_img(trans, &nic->fw.ucode_wowlan); + iwl_free_fw_img(nic, &nic->fw.ucode_rt); + iwl_free_fw_img(nic, &nic->fw.ucode_init); + iwl_free_fw_img(nic, &nic->fw.ucode_wowlan); } -static int iwl_alloc_fw_desc(struct iwl_trans *trans, struct fw_desc *desc, +static int iwl_alloc_fw_desc(struct iwl_nic *nic, struct fw_desc *desc, const void *data, size_t len) { if (!len) { @@ -113,7 +112,7 @@ static int iwl_alloc_fw_desc(struct iwl_trans *trans, struct fw_desc *desc, return -EINVAL; } - desc->v_addr = dma_alloc_coherent(trans->dev, len, + desc->v_addr = dma_alloc_coherent(trans(nic)->dev, len, &desc->p_addr, GFP_KERNEL); if (!desc->v_addr) return -ENOMEM; @@ -398,15 +397,16 @@ static int iwl_alive_notify(struct iwl_trans *trans) * using sample data 100 bytes apart. If these sample points are good, * it's a pretty good bet that everything between them is good, too. */ -static int iwl_verify_inst_sparse(struct iwl_trans *trans, +static int iwl_verify_inst_sparse(struct iwl_nic *nic, struct fw_desc *fw_desc) { + struct iwl_trans *trans = trans(nic); __le32 *image = (__le32 *)fw_desc->v_addr; u32 len = fw_desc->len; u32 val; u32 i; - IWL_DEBUG_FW(trans, "ucode inst image size is %u\n", len); + IWL_DEBUG_FW(nic, "ucode inst image size is %u\n", len); for (i = 0; i < len; i += 100, image += 100/sizeof(u32)) { /* read data comes through single port, auto-incr addr */ @@ -422,16 +422,17 @@ static int iwl_verify_inst_sparse(struct iwl_trans *trans, return 0; } -static void iwl_print_mismatch_inst(struct iwl_trans *trans, +static void iwl_print_mismatch_inst(struct iwl_nic *nic, struct fw_desc *fw_desc) { + struct iwl_trans *trans = trans(nic); __le32 *image = (__le32 *)fw_desc->v_addr; u32 len = fw_desc->len; u32 val; u32 offs; int errors = 0; - IWL_DEBUG_FW(trans, "ucode inst image size is %u\n", len); + IWL_DEBUG_FW(nic, "ucode inst image size is %u\n", len); iwl_write_direct32(trans, HBUS_TARG_MEM_RADDR, IWLAGN_RTC_INST_LOWER_BOUND); @@ -442,7 +443,7 @@ static void iwl_print_mismatch_inst(struct iwl_trans *trans, /* read data comes through single port, auto-incr addr */ val = iwl_read32(trans, HBUS_TARG_MEM_RDAT); if (val != le32_to_cpu(*image)) { - IWL_ERR(trans, "uCode INST section at " + IWL_ERR(nic, "uCode INST section at " "offset 0x%x, is 0x%x, s/b 0x%x\n", offs, val, le32_to_cpu(*image)); errors++; @@ -454,24 +455,24 @@ static void iwl_print_mismatch_inst(struct iwl_trans *trans, * iwl_verify_ucode - determine which instruction image is in SRAM, * and verify its contents */ -static int iwl_verify_ucode(struct iwl_trans *trans, +static int iwl_verify_ucode(struct iwl_nic *nic, enum iwl_ucode_type ucode_type) { - struct fw_img *img = iwl_get_ucode_image(nic(trans), ucode_type); + struct fw_img *img = iwl_get_ucode_image(nic, ucode_type); if (!img) { - IWL_ERR(trans, "Invalid ucode requested (%d)\n", ucode_type); + IWL_ERR(nic, "Invalid ucode requested (%d)\n", ucode_type); return -EINVAL; } - if (!iwl_verify_inst_sparse(trans, &img->code)) { - IWL_DEBUG_FW(trans, "uCode is good in inst SRAM\n"); + if (!iwl_verify_inst_sparse(nic, &img->code)) { + IWL_DEBUG_FW(nic, "uCode is good in inst SRAM\n"); return 0; } - IWL_ERR(trans, "UCODE IMAGE IN INSTRUCTION SRAM NOT VALID!!\n"); + IWL_ERR(nic, "UCODE IMAGE IN INSTRUCTION SRAM NOT VALID!!\n"); - iwl_print_mismatch_inst(trans, &img->code); + iwl_print_mismatch_inst(nic, &img->code); return -EIO; } @@ -619,7 +620,7 @@ int iwl_load_ucode_wait_alive(struct iwl_trans *trans, * skip it for WoWLAN. */ if (ucode_type != IWL_UCODE_WOWLAN) { - ret = iwl_verify_ucode(trans, ucode_type); + ret = iwl_verify_ucode(nic(trans), ucode_type); if (ret) { trans->shrd->ucode_type = old_type; return ret; @@ -1164,20 +1165,20 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) /* Runtime instructions and 2 copies of data: * 1) unmodified from disk * 2) backup cache for save/restore during power-downs */ - if (iwl_alloc_fw_desc(trans(priv), &nic(priv)->fw.ucode_rt.code, + if (iwl_alloc_fw_desc(nic(priv), &nic(priv)->fw.ucode_rt.code, pieces.inst, pieces.inst_size)) goto err_pci_alloc; - if (iwl_alloc_fw_desc(trans(priv), &nic(priv)->fw.ucode_rt.data, + if (iwl_alloc_fw_desc(nic(priv), &nic(priv)->fw.ucode_rt.data, pieces.data, pieces.data_size)) goto err_pci_alloc; /* Initialization instructions and data */ if (pieces.init_size && pieces.init_data_size) { - if (iwl_alloc_fw_desc(trans(priv), + if (iwl_alloc_fw_desc(nic(priv), &nic(priv)->fw.ucode_init.code, pieces.init, pieces.init_size)) goto err_pci_alloc; - if (iwl_alloc_fw_desc(trans(priv), + if (iwl_alloc_fw_desc(nic(priv), &nic(priv)->fw.ucode_init.data, pieces.init_data, pieces.init_data_size)) goto err_pci_alloc; @@ -1185,12 +1186,12 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) /* WoWLAN instructions and data */ if (pieces.wowlan_inst_size && pieces.wowlan_data_size) { - if (iwl_alloc_fw_desc(trans(priv), + if (iwl_alloc_fw_desc(nic(priv), &nic(priv)->fw.ucode_wowlan.code, pieces.wowlan_inst, pieces.wowlan_inst_size)) goto err_pci_alloc; - if (iwl_alloc_fw_desc(trans(priv), + if (iwl_alloc_fw_desc(nic(priv), &nic(priv)->fw.ucode_wowlan.data, pieces.wowlan_data, pieces.wowlan_data_size)) @@ -1286,7 +1287,7 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) err_pci_alloc: IWL_ERR(priv, "failed to allocate pci memory\n"); - iwl_dealloc_ucode(trans(priv)); + iwl_dealloc_ucode(nic(priv)); out_unbind: complete(&nic->request_firmware_complete); device_release_driver(trans(priv)->dev); diff --git a/drivers/net/wireless/iwlwifi/iwl-wifi.h b/drivers/net/wireless/iwlwifi/iwl-wifi.h index a34708d19380..392f1113d954 100644 --- a/drivers/net/wireless/iwlwifi/iwl-wifi.h +++ b/drivers/net/wireless/iwlwifi/iwl-wifi.h @@ -95,6 +95,8 @@ struct iwl_nic { }; +void iwl_dealloc_ucode(struct iwl_nic *nic); + int iwl_send_bt_env(struct iwl_trans *trans, u8 action, u8 type); void iwl_send_prio_tbl(struct iwl_trans *trans); int iwl_init_alive_start(struct iwl_trans *trans); From 78e5a464320338a90b0367ab9cc58029393a9824 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Fri, 17 Feb 2012 10:34:53 -0800 Subject: [PATCH 14/26] iwlwifi: kill iwl_down and s/__iwl_down/iwl_down iwl_down was just a wrapper around __iwl_down which was called from one place only. Replace it to direct call to iwl_down. Add lockdep warning in iwl_down to ensure it was called with the mutex held. Signed-off-by: Emmanuel Grumbach Signed-off-by: Wey-Yi Guy --- drivers/net/wireless/iwlwifi/iwl-agn.c | 19 +++++-------------- drivers/net/wireless/iwlwifi/iwl-agn.h | 2 +- drivers/net/wireless/iwlwifi/iwl-mac80211.c | 6 +++++- 3 files changed, 11 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index ff22c4ae13b1..cf1a353c20bb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -738,14 +738,14 @@ int iwl_alive_start(struct iwl_priv *priv) return iwl_power_update_mode(priv, true); } -static void iwl_cancel_deferred_work(struct iwl_priv *priv); - -void __iwl_down(struct iwl_priv *priv) +void iwl_down(struct iwl_priv *priv) { int exit_pending; IWL_DEBUG_INFO(priv, DRV_NAME " is going down\n"); + lockdep_assert_held(&priv->shrd->mutex); + iwl_scan_cancel_timeout(priv, 200); /* @@ -803,15 +803,6 @@ void __iwl_down(struct iwl_priv *priv) priv->beacon_skb = NULL; } -void iwl_down(struct iwl_priv *priv) -{ - mutex_lock(&priv->shrd->mutex); - __iwl_down(priv); - mutex_unlock(&priv->shrd->mutex); - - iwl_cancel_deferred_work(priv); -} - /***************************************************************************** * * Workqueue callbacks @@ -869,7 +860,7 @@ void iwlagn_prepare_restart(struct iwl_priv *priv) bt_status = priv->bt_status; bt_is_sco = priv->bt_is_sco; - __iwl_down(priv); + iwl_down(priv); priv->bt_full_concurrent = bt_full_concurrent; priv->bt_ci_compliance = bt_ci_compliance; @@ -970,7 +961,7 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv) priv->watchdog.function = iwl_bg_watchdog; } -static void iwl_cancel_deferred_work(struct iwl_priv *priv) +void iwl_cancel_deferred_work(struct iwl_priv *priv) { if (cfg(priv)->lib->cancel_deferred_work) cfg(priv)->lib->cancel_deferred_work(priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index 37c325ff6e8c..8a170b7f1e17 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h @@ -81,8 +81,8 @@ static inline void iwl_set_calib_hdr(struct iwl_calib_hdr *hdr, u8 cmd) hdr->data_valid = 1; } -void __iwl_down(struct iwl_priv *priv); void iwl_down(struct iwl_priv *priv); +void iwl_cancel_deferred_work(struct iwl_priv *priv); void iwlagn_prepare_restart(struct iwl_priv *priv); /* MAC80211 */ diff --git a/drivers/net/wireless/iwlwifi/iwl-mac80211.c b/drivers/net/wireless/iwlwifi/iwl-mac80211.c index ca0c46506674..90d8081426f6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-mac80211.c +++ b/drivers/net/wireless/iwlwifi/iwl-mac80211.c @@ -296,7 +296,7 @@ static int __iwl_up(struct iwl_priv *priv) error: set_bit(STATUS_EXIT_PENDING, &priv->shrd->status); - __iwl_down(priv); + iwl_down(priv); clear_bit(STATUS_EXIT_PENDING, &priv->shrd->status); IWL_ERR(priv, "Unable to initialize device.\n"); @@ -341,7 +341,11 @@ static void iwlagn_mac_stop(struct ieee80211_hw *hw) priv->is_open = 0; + mutex_lock(&priv->shrd->mutex); iwl_down(priv); + mutex_unlock(&priv->shrd->mutex); + + iwl_cancel_deferred_work(priv); flush_workqueue(priv->workqueue); From 6d4dec7ba4b0275c97c39b694cfe60e9aeafdf60 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Fri, 17 Feb 2012 10:52:03 -0800 Subject: [PATCH 15/26] iwlwifi: iwl_set_hw_params returns always 0 Remove the return value. Signed-off-by: Emmanuel Grumbach Signed-off-by: Wey-Yi Guy --- drivers/net/wireless/iwlwifi/iwl-1000.c | 4 +--- drivers/net/wireless/iwlwifi/iwl-2000.c | 4 +--- drivers/net/wireless/iwlwifi/iwl-5000.c | 8 ++------ drivers/net/wireless/iwlwifi/iwl-6000.c | 3 +-- drivers/net/wireless/iwlwifi/iwl-agn.c | 10 +++------- drivers/net/wireless/iwlwifi/iwl-core.h | 2 +- 6 files changed, 9 insertions(+), 22 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 8c1466c907ff..91c4a72da8d7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -120,7 +120,7 @@ static struct iwl_sensitivity_ranges iwl1000_sensitivity = { .nrg_th_cca = 62, }; -static int iwl1000_hw_set_hw_params(struct iwl_priv *priv) +static void iwl1000_hw_set_hw_params(struct iwl_priv *priv) { if (iwlagn_mod_params.num_of_queues >= IWL_MIN_NUM_QUEUES && iwlagn_mod_params.num_of_queues <= IWLAGN_NUM_QUEUES) @@ -146,8 +146,6 @@ static int iwl1000_hw_set_hw_params(struct iwl_priv *priv) /* Set initial sensitivity parameters */ hw_params(priv).sens = &iwl1000_sensitivity; - - return 0; } static struct iwl_lib_ops iwl1000_lib = { diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c index d4f5f3b87578..75f0e5088662 100644 --- a/drivers/net/wireless/iwlwifi/iwl-2000.c +++ b/drivers/net/wireless/iwlwifi/iwl-2000.c @@ -116,7 +116,7 @@ static struct iwl_sensitivity_ranges iwl2000_sensitivity = { .nrg_th_cca = 62, }; -static int iwl2000_hw_set_hw_params(struct iwl_priv *priv) +static void iwl2000_hw_set_hw_params(struct iwl_priv *priv) { if (iwlagn_mod_params.num_of_queues >= IWL_MIN_NUM_QUEUES && iwlagn_mod_params.num_of_queues <= IWLAGN_NUM_QUEUES) @@ -142,8 +142,6 @@ static int iwl2000_hw_set_hw_params(struct iwl_priv *priv) /* Set initial sensitivity parameters */ hw_params(priv).sens = &iwl2000_sensitivity; - - return 0; } static struct iwl_lib_ops iwl2000_lib = { diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index dc9317d0343e..458e6778c72f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -162,7 +162,7 @@ static void iwl5000_set_ct_threshold(struct iwl_priv *priv) hw_params(priv).ct_kill_threshold = CT_KILL_THRESHOLD_LEGACY; } -static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) +static void iwl5000_hw_set_hw_params(struct iwl_priv *priv) { if (iwlagn_mod_params.num_of_queues >= IWL_MIN_NUM_QUEUES && iwlagn_mod_params.num_of_queues <= IWLAGN_NUM_QUEUES) @@ -185,11 +185,9 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) /* Set initial sensitivity parameters */ hw_params(priv).sens = &iwl5000_sensitivity; - - return 0; } -static int iwl5150_hw_set_hw_params(struct iwl_priv *priv) +static void iwl5150_hw_set_hw_params(struct iwl_priv *priv) { if (iwlagn_mod_params.num_of_queues >= IWL_MIN_NUM_QUEUES && iwlagn_mod_params.num_of_queues <= IWLAGN_NUM_QUEUES) @@ -212,8 +210,6 @@ static int iwl5150_hw_set_hw_params(struct iwl_priv *priv) /* Set initial sensitivity parameters */ hw_params(priv).sens = &iwl5150_sensitivity; - - return 0; } static void iwl5150_temperature(struct iwl_priv *priv) diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index c36fb858a45b..19e41037f61e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -137,7 +137,7 @@ static struct iwl_sensitivity_ranges iwl6000_sensitivity = { .nrg_th_cca = 62, }; -static int iwl6000_hw_set_hw_params(struct iwl_priv *priv) +static void iwl6000_hw_set_hw_params(struct iwl_priv *priv) { if (iwlagn_mod_params.num_of_queues >= IWL_MIN_NUM_QUEUES && iwlagn_mod_params.num_of_queues <= IWLAGN_NUM_QUEUES) @@ -165,7 +165,6 @@ static int iwl6000_hw_set_hw_params(struct iwl_priv *priv) /* Set initial sensitivity parameters */ hw_params(priv).sens = &iwl6000_sensitivity; - return 0; } static int iwl6000_hw_channel_switch(struct iwl_priv *priv, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index cf1a353c20bb..68b9e5e5da78 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1082,7 +1082,7 @@ static void iwl_uninit_drv(struct iwl_priv *priv) #define IWL_RX_BUF_SIZE_4K (4 * 1024) #define IWL_RX_BUF_SIZE_8K (8 * 1024) -static int iwl_set_hw_params(struct iwl_priv *priv) +static void iwl_set_hw_params(struct iwl_priv *priv) { if (iwlagn_mod_params.amsdu_size_8K) hw_params(priv).rx_page_order = @@ -1102,7 +1102,7 @@ static int iwl_set_hw_params(struct iwl_priv *priv) hw_params(priv).wd_timeout = cfg(priv)->base_params->wd_timeout; /* Device-specific setup */ - return cfg(priv)->lib->set_hw_params(priv); + cfg(priv)->lib->set_hw_params(priv); } @@ -1239,11 +1239,7 @@ int iwl_probe(struct iwl_bus *bus, const struct iwl_trans_ops *trans_ops, /************************ * 5. Setup HW constants ************************/ - if (iwl_set_hw_params(priv)) { - err = -ENOENT; - IWL_ERR(priv, "failed to set hw parameters\n"); - goto out_free_eeprom; - } + iwl_set_hw_params(priv); /******************* * 6. Setup priv diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 8d60dcf6f2eb..49370dd37768 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -76,7 +76,7 @@ struct iwl_cmd; struct iwl_lib_ops { /* set hw dependent parameters */ - int (*set_hw_params)(struct iwl_priv *priv); + void (*set_hw_params)(struct iwl_priv *priv); /* setup BT Rx handler */ void (*bt_rx_handler_setup)(struct iwl_priv *priv); /* setup BT related deferred work */ From 637d7925910df46bb29a0260dd2fec68b50a811b Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 7 Feb 2012 10:55:46 +0200 Subject: [PATCH 16/26] iwlwifi: use enhance_sensitivity from iwl_fw Remove another dependency between the nic layer and the iwl_priv struct. Signed-off-by: Emmanuel Grumbach Signed-off-by: Wey-Yi Guy --- drivers/net/wireless/iwlwifi/iwl-agn-calib.c | 6 ++++-- drivers/net/wireless/iwlwifi/iwl-dev.h | 1 - drivers/net/wireless/iwlwifi/iwl-ucode.c | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c index 6aa009827865..988ee454a944 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c @@ -68,6 +68,8 @@ #include "iwl-agn-calib.h" #include "iwl-trans.h" #include "iwl-agn.h" +#include "iwl-wifi.h" +#include "iwl-ucode.h" /***************************************************************************** * INIT calibrations framework @@ -634,7 +636,7 @@ void iwl_init_sensitivity(struct iwl_priv *priv) data->last_bad_plcp_cnt_cck = 0; data->last_fa_cnt_cck = 0; - if (priv->enhance_sensitivity_table) + if (nic(priv)->fw.enhance_sensitivity_table) ret |= iwl_enhance_sensitivity_write(priv); else ret |= iwl_sensitivity_write(priv); @@ -745,7 +747,7 @@ void iwl_sensitivity_calibration(struct iwl_priv *priv) iwl_sens_auto_corr_ofdm(priv, norm_fa_ofdm, rx_enable_time); iwl_sens_energy_cck(priv, norm_fa_cck, rx_enable_time, &statis); - if (priv->enhance_sensitivity_table) + if (nic(priv)->fw.enhance_sensitivity_table) iwl_enhance_sensitivity_write(priv); else iwl_sensitivity_write(priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 0d0b4bb9dc63..8a72940aa805 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -796,7 +796,6 @@ struct iwl_priv { u8 start_calib; struct iwl_sensitivity_data sensitivity_data; struct iwl_chain_noise_data chain_noise_data; - bool enhance_sensitivity_table; __le16 sensitivity_tbl[HD_TABLE_SIZE]; __le16 enhance_sensitivity_tbl[ENHANCE_HD_TABLE_ENTRIES]; diff --git a/drivers/net/wireless/iwlwifi/iwl-ucode.c b/drivers/net/wireless/iwlwifi/iwl-ucode.c index 26ead61d1f5c..a2695c27f663 100644 --- a/drivers/net/wireless/iwlwifi/iwl-ucode.c +++ b/drivers/net/wireless/iwlwifi/iwl-ucode.c @@ -967,7 +967,7 @@ static int iwlagn_load_firmware(struct iwl_priv *priv, case IWL_UCODE_TLV_ENHANCE_SENS_TBL: if (tlv_len) goto invalid_tlv_len; - priv->enhance_sensitivity_table = true; + nic->fw.enhance_sensitivity_table = true; break; case IWL_UCODE_TLV_WOWLAN_INST: pieces->wowlan_inst = tlv_data; From 858b7c74dda1d748a687a523e83cf7d1449c70f3 Mon Sep 17 00:00:00 2001 From: Amit Beka Date: Mon, 6 Feb 2012 00:40:47 +0200 Subject: [PATCH 17/26] iwlwifi: fixes to testmode indirect access Fixed casting of buffer addressing, and added size to the read method, like in __iwl_read_prph. Signed-off-by: Amit Beka Signed-off-by: Wey-Yi Guy --- drivers/net/wireless/iwlwifi/iwl-testmode.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-testmode.c b/drivers/net/wireless/iwlwifi/iwl-testmode.c index 5f00a3712707..ba5c63a023a2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-testmode.c +++ b/drivers/net/wireless/iwlwifi/iwl-testmode.c @@ -799,9 +799,10 @@ static int iwl_testmode_indirect_read(struct iwl_priv *priv, u32 addr, u32 size) addr < IWL_TM_ABS_PRPH_START + PRPH_END) { spin_lock_irqsave(&trans->reg_lock, flags); iwl_grab_nic_access(trans); - iwl_write32(trans, HBUS_TARG_PRPH_RADDR, addr); + iwl_write32(trans, HBUS_TARG_PRPH_RADDR, + addr | (3 << 24)); for (i = 0; i < size; i += 4) - priv->testmode_mem.buff_addr[i] = + *(u32 *)(priv->testmode_mem.buff_addr + i) = iwl_read32(trans, HBUS_TARG_PRPH_RDAT); iwl_release_nic_access(trans); spin_unlock_irqrestore(&trans->reg_lock, flags); @@ -833,7 +834,8 @@ static int iwl_testmode_indirect_write(struct iwl_priv *priv, u32 addr, spin_lock_irqsave(&trans->reg_lock, flags); iwl_grab_nic_access(trans); iwl_write32(trans, HBUS_TARG_PRPH_WADDR, - (addr & 0x0000FFFF) | (size << 24)); + (addr & 0x0000FFFF) | + ((size - 1) << 24)); iwl_write32(trans, HBUS_TARG_PRPH_WDAT, val); iwl_release_nic_access(trans); /* needed after consecutive writes w/o read */ @@ -844,7 +846,7 @@ static int iwl_testmode_indirect_write(struct iwl_priv *priv, u32 addr, return -EINVAL; for (i = 0; i < size; i += 4) iwl_write_prph(trans, addr+i, - *(u32 *)buf+i); + *(u32 *)(buf+i)); } } else if (iwlagn_hw_valid_rtc_data_addr(addr) || (IWLAGN_RTC_INST_LOWER_BOUND <= addr && From edabfa914d52daf8c01511109144fe5af3c4389e Mon Sep 17 00:00:00 2001 From: Amit Beka Date: Wed, 8 Feb 2012 10:01:35 +0200 Subject: [PATCH 18/26] iwlwifi: send testmode hcmd reply with rx header When a host command is sent through testmode, the whole reply (including rx header) is returned to the user, and not only the payload of the rx. Before this commit the length was buggy - the reply contained 4 bytes after the end of the payload. Signed-off-by: Amit Beka Signed-off-by: Wey-Yi Guy --- drivers/net/wireless/iwlwifi/iwl-testmode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-testmode.c b/drivers/net/wireless/iwlwifi/iwl-testmode.c index ba5c63a023a2..80955ed06e82 100644 --- a/drivers/net/wireless/iwlwifi/iwl-testmode.c +++ b/drivers/net/wireless/iwlwifi/iwl-testmode.c @@ -309,7 +309,7 @@ static int iwl_testmode_ucode(struct ieee80211_hw *hw, struct nlattr **tb) } /* The reply is in a page, that we cannot send to user space. */ - memcpy(reply_buf, &(pkt->u), reply_len); + memcpy(reply_buf, &(pkt->hdr), reply_len); iwl_free_pages(priv->shrd, cmd.reply_page); NLA_PUT_U32(skb, IWL_TM_ATTR_COMMAND, IWL_TM_CMD_DEV2APP_UCODE_RX_PKT); From 60396183a4e7adce7aa71f801e47b063fe1f70a8 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 6 Feb 2012 16:41:58 +0200 Subject: [PATCH 19/26] iwlwifi: document the transport layer Fix a few typos in the existing comments too. Enforce the comments with might_sleep. Signed-off-by: Emmanuel Grumbach Signed-off-by: Wey-Yi Guy --- drivers/net/wireless/iwlwifi/iwl-trans.h | 120 ++++++++++++++++++++--- 1 file changed, 107 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 7ea5f7733d2b..2a2941f9fd21 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -70,17 +70,72 @@ #include "iwl-commands.h" #include "iwl-ucode.h" - /*This file includes the declaration that are exported from the transport - * layer */ +/** + * DOC: Transport layer - what is it ? + * + * The tranport layer is the layer that deals with the HW directly. It provides + * an abstraction of the underlying HW to the upper layer. The transport layer + * doesn't provide any policy, algorithm or anything of this kind, but only + * mechanisms to make the HW do something.It is not completely stateless but + * close to it. + * We will have an implementation for each different supported bus. + */ + +/** + * DOC: Life cycle of the transport layer + * + * The transport layer has a very precise life cycle. + * + * 1) A helper function is called during the module initialization and + * registers the bus driver's ops with the transport's alloc function. + * 2) Bus's probe calls to the transport layer's allocation functions. + * Of course this function is bus specific. + * 3) This allocation functions will spawn the upper layer which will + * register mac80211. + * + * 4) At some point (i.e. mac80211's start call), the op_mode will call + * the following sequence: + * start_hw + * start_fw + * + * 5) Then when finished (or reset): + * stop_fw (a.k.a. stop device for the moment) + * stop_hw + * + * 6) Eventually, the free function will be called. + */ + +/** + * DOC: API needed by the transport layer from the op_mode + * + * TODO + */ struct iwl_priv; struct iwl_shared; +/** + * DOC: Host command section + * + * A host command is a commaned issued by the upper layer to the fw. There are + * several versions of fw that have several APIs. The transport layer is + * completely agnostic to these differences. + * The transport does provide helper functionnality (i.e. SYNC / ASYNC mode), + */ #define SEQ_TO_SN(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4) #define SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ) #define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4) -enum { +/** + * enum CMD_MODE - how to send the host commands ? + * + * @CMD_SYNC: The caller will be stalled until the fw responds to the command + * @CMD_ASYNC: Return right away and don't want for the response + * @CMD_WANT_SKB: valid only with CMD_SYNC. The caller needs the buffer of the + * response. + * @CMD_ON_DEMAND: This command is sent by the test mode pipe. + */ +enum CMD_MODE { CMD_SYNC = 0, CMD_ASYNC = BIT(0), CMD_WANT_SKB = BIT(1), @@ -105,20 +160,29 @@ struct iwl_device_cmd { #define IWL_MAX_CMD_TFDS 2 +/** + * struct iwl_hcmd_dataflag - flag for each one of the chunks of the command + * + * IWL_HCMD_DFL_NOCOPY: By default, the command is copied to the host command's + * ring. The transport layer doesn't map the command's buffer to DMA, but + * rather copies it to an previously allocated DMA buffer. This flag tells + * the transport layer not to copy the command, but to map the existing + * buffer. This can save memcpy and is worth with very big comamnds. + */ enum iwl_hcmd_dataflag { IWL_HCMD_DFL_NOCOPY = BIT(0), }; /** * struct iwl_host_cmd - Host command to the uCode + * * @data: array of chunks that composes the data of the host command * @reply_page: pointer to the page that holds the response to the host command * @handler_status: return value of the handler of the command * (put in setup_rx_handlers) - valid for SYNC mode only - * @callback: - * @flags: can be CMD_* note CMD_WANT_SKB is incompatible withe CMD_ASYNC + * @flags: can be CMD_* * @len: array of the lenths of the chunks in data - * @dataflags: + * @dataflags: IWL_HCMD_DFL_* * @id: id of the host command */ struct iwl_host_cmd { @@ -134,26 +198,43 @@ struct iwl_host_cmd { /** * struct iwl_trans_ops - transport specific operations + * + * All the handlers MUST be implemented + * * @start_hw: starts the HW- from that point on, the HW can send interrupts + * May sleep * @stop_hw: stops the HW- from that point on, the HW will be in low power but * will still issue interrupt if the HW RF kill is triggered. + * May sleep * @start_fw: allocates and inits all the resources for the transport - * layer. Also kick a fw image. This handler may sleep. + * layer. Also kick a fw image. + * May sleep * @fw_alive: called when the fw sends alive notification + * May sleep * @wake_any_queue: wake all the queues of a specfic context IWL_RXON_CTX_* * @stop_device:stops the whole device (embedded CPU put to reset) + * May sleep * @send_cmd:send a host command + * May sleep only if CMD_SYNC is set * @tx: send an skb + * Must be atomic * @reclaim: free packet until ssn. Returns a list of freed packets. + * Must be atomic * @tx_agg_alloc: allocate resources for a TX BA session + * May sleep * @tx_agg_setup: setup a tx queue for AMPDU - will be called once the HW is - * ready and a successful ADDBA response has been received. + * ready and a successful ADDBA response has been received. + * May sleep * @tx_agg_disable: de-configure a Tx queue to send AMPDUs + * May sleep * @free: release all the ressource for the transport layer itself such as - * irq, tasklet etc... + * irq, tasklet etc... From this point on, the device may not issue + * any interrupt (incl. RFKILL). + * May sleep * @stop_queue: stop a specific queue * @check_stuck_queue: check if a specific queue is stuck * @wait_tx_queue_empty: wait until all tx queues are empty + * May sleep * @dbgfs_register: add the dbgfs files under this directory. Files will be * automatically deleted. * @suspend: stop the device unless WoWLAN is configured @@ -217,6 +298,7 @@ struct iwl_calib_result { /** * struct iwl_trans - transport common data + * * @ops - pointer to iwl_trans_ops * @shrd - pointer to iwl_shared which holds shared data from the upper layer * @hcmd_lock: protects HCMD @@ -224,7 +306,7 @@ struct iwl_calib_result { * @dev - pointer to struct device * that represents the device * @irq - the irq number for the device * @hw_id: a u32 with the ID of the device / subdevice. - * Set during transport alloaction. + * Set during transport allocation. * @hw_id_str: a string with info about HW ID. Set during transport allocation. * @ucode_write_complete: indicates that the ucode has been copied. * @ucode_rt: run time ucode image @@ -246,13 +328,11 @@ struct iwl_trans { u32 hw_id; char hw_id_str[52]; - u8 ucode_write_complete; /* the image write is complete */ + u8 ucode_write_complete; - /* eeprom related variables */ int nvm_device_type; bool pm_support; - /* init calibration results */ struct list_head calib_results; /* pointer to trans specific struct */ @@ -262,16 +342,22 @@ struct iwl_trans { static inline int iwl_trans_start_hw(struct iwl_trans *trans) { + might_sleep(); + return trans->ops->start_hw(trans); } static inline void iwl_trans_stop_hw(struct iwl_trans *trans) { + might_sleep(); + trans->ops->stop_hw(trans); } static inline void iwl_trans_fw_alive(struct iwl_trans *trans) { + might_sleep(); + trans->ops->fw_alive(trans); } @@ -284,6 +370,8 @@ static inline int iwl_trans_start_fw(struct iwl_trans *trans, struct fw_img *fw) static inline void iwl_trans_stop_device(struct iwl_trans *trans) { + might_sleep(); + trans->ops->stop_device(trans); } @@ -322,12 +410,16 @@ static inline int iwl_trans_reclaim(struct iwl_trans *trans, int sta_id, static inline int iwl_trans_tx_agg_disable(struct iwl_trans *trans, int sta_id, int tid) { + might_sleep(); + return trans->ops->tx_agg_disable(trans, sta_id, tid); } static inline int iwl_trans_tx_agg_alloc(struct iwl_trans *trans, int sta_id, int tid) { + might_sleep(); + return trans->ops->tx_agg_alloc(trans, sta_id, tid); } @@ -337,6 +429,8 @@ static inline void iwl_trans_tx_agg_setup(struct iwl_trans *trans, int sta_id, int tid, int frame_limit, u16 ssn) { + might_sleep(); + trans->ops->tx_agg_setup(trans, ctx, sta_id, tid, frame_limit, ssn); } From 8655112d91f247f6b96c9b1285658c141238ce90 Mon Sep 17 00:00:00 2001 From: Don Fry Date: Tue, 7 Feb 2012 14:03:55 -0800 Subject: [PATCH 20/26] iwlwifi: move event and err pointers to iwl_nic Move the ucode offset pointers to the iwl_nic as they are nic related. Signed-off-by: Don Fry Signed-off-by: Wey-Yi Guy --- drivers/net/wireless/iwlwifi/iwl-dev.h | 3 -- .../net/wireless/iwlwifi/iwl-trans-pcie-rx.c | 31 ++++++++++--------- drivers/net/wireless/iwlwifi/iwl-ucode.c | 16 +++++----- 3 files changed, 24 insertions(+), 26 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 8a72940aa805..494c696dc177 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -863,9 +863,6 @@ struct iwl_priv { struct iwl_rx_phy_res last_phy_res; bool last_phy_res_valid; - u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr; - u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr; - /* * chain noise reset and gain commands are the * two extra calibration commands follows the standard diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c index e06342656cea..6715d04b72f4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c @@ -34,6 +34,7 @@ #include "iwl-core.h" #include "iwl-io.h" #include "iwl-trans-pcie-int.h" +#include "iwl-wifi.h" #ifdef CONFIG_IWLWIFI_IDI #include "iwl-amfh.h" @@ -589,17 +590,17 @@ static void iwl_dump_nic_error_log(struct iwl_trans *trans) { u32 base; struct iwl_error_event_table table; - struct iwl_priv *priv = priv(trans); + struct iwl_nic *nic = nic(trans); struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); base = trans->shrd->device_pointers.error_event_table; if (trans->shrd->ucode_type == IWL_UCODE_INIT) { if (!base) - base = priv->init_errlog_ptr; + base = nic->init_errlog_ptr; } else { if (!base) - base = priv->inst_errlog_ptr; + base = nic->inst_errlog_ptr; } if (!iwlagn_hw_valid_rtc_data_addr(base)) { @@ -611,7 +612,7 @@ static void iwl_dump_nic_error_log(struct iwl_trans *trans) return; } - iwl_read_targ_mem_words(trans(priv), base, &table, sizeof(table)); + iwl_read_targ_mem_words(trans, base, &table, sizeof(table)); if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) { IWL_ERR(trans, "Start IWL Error Log Dump:\n"); @@ -621,7 +622,7 @@ static void iwl_dump_nic_error_log(struct iwl_trans *trans) trans_pcie->isr_stats.err_code = table.error_id; - trace_iwlwifi_dev_ucode_error(priv, table.error_id, table.tsf_low, + trace_iwlwifi_dev_ucode_error(priv(nic), table.error_id, table.tsf_low, table.data1, table.data2, table.line, table.blink1, table.blink2, table.ilink1, table.ilink2, table.bcon_time, table.gp1, @@ -718,7 +719,7 @@ static int iwl_print_event_log(struct iwl_trans *trans, u32 start_idx, u32 ptr; /* SRAM byte address of log data */ u32 ev, time, data; /* event log data */ unsigned long reg_flags; - struct iwl_priv *priv = priv(trans); + struct iwl_nic *nic = nic(trans); if (num_events == 0) return pos; @@ -726,10 +727,10 @@ static int iwl_print_event_log(struct iwl_trans *trans, u32 start_idx, base = trans->shrd->device_pointers.log_event_table; if (trans->shrd->ucode_type == IWL_UCODE_INIT) { if (!base) - base = priv->init_evtlog_ptr; + base = nic->init_evtlog_ptr; } else { if (!base) - base = priv->inst_evtlog_ptr; + base = nic->inst_evtlog_ptr; } if (mode == 0) @@ -759,7 +760,7 @@ static int iwl_print_event_log(struct iwl_trans *trans, u32 start_idx, "EVT_LOG:0x%08x:%04u\n", time, ev); } else { - trace_iwlwifi_dev_ucode_event(priv, 0, + trace_iwlwifi_dev_ucode_event(priv(trans), 0, time, ev); IWL_ERR(trans, "EVT_LOG:0x%08x:%04u\n", time, ev); @@ -773,7 +774,7 @@ static int iwl_print_event_log(struct iwl_trans *trans, u32 start_idx, } else { IWL_ERR(trans, "EVT_LOGT:%010u:0x%08x:%04u\n", time, data, ev); - trace_iwlwifi_dev_ucode_event(priv, time, + trace_iwlwifi_dev_ucode_event(priv(trans), time, data, ev); } } @@ -835,17 +836,17 @@ int iwl_dump_nic_event_log(struct iwl_trans *trans, bool full_log, u32 logsize; int pos = 0; size_t bufsz = 0; - struct iwl_priv *priv = priv(trans); + struct iwl_nic *nic = nic(trans); base = trans->shrd->device_pointers.log_event_table; if (trans->shrd->ucode_type == IWL_UCODE_INIT) { - logsize = priv->init_evtlog_size; + logsize = nic->init_evtlog_size; if (!base) - base = priv->init_evtlog_ptr; + base = nic->init_evtlog_ptr; } else { - logsize = priv->inst_evtlog_size; + logsize = nic->inst_evtlog_size; if (!base) - base = priv->inst_evtlog_ptr; + base = nic->inst_evtlog_ptr; } if (!iwlagn_hw_valid_rtc_data_addr(base)) { diff --git a/drivers/net/wireless/iwlwifi/iwl-ucode.c b/drivers/net/wireless/iwlwifi/iwl-ucode.c index a2695c27f663..0d04a4d7dc84 100644 --- a/drivers/net/wireless/iwlwifi/iwl-ucode.c +++ b/drivers/net/wireless/iwlwifi/iwl-ucode.c @@ -1205,20 +1205,20 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) * for each event, which is of mode 1 (including timestamp) for all * new microcodes that include this information. */ - priv->init_evtlog_ptr = pieces.init_evtlog_ptr; + nic->init_evtlog_ptr = pieces.init_evtlog_ptr; if (pieces.init_evtlog_size) - priv->init_evtlog_size = (pieces.init_evtlog_size - 16)/12; + nic->init_evtlog_size = (pieces.init_evtlog_size - 16)/12; else - priv->init_evtlog_size = + nic->init_evtlog_size = cfg(priv)->base_params->max_event_log_size; - priv->init_errlog_ptr = pieces.init_errlog_ptr; - priv->inst_evtlog_ptr = pieces.inst_evtlog_ptr; + nic->init_errlog_ptr = pieces.init_errlog_ptr; + nic->inst_evtlog_ptr = pieces.inst_evtlog_ptr; if (pieces.inst_evtlog_size) - priv->inst_evtlog_size = (pieces.inst_evtlog_size - 16)/12; + nic->inst_evtlog_size = (pieces.inst_evtlog_size - 16)/12; else - priv->inst_evtlog_size = + nic->inst_evtlog_size = cfg(priv)->base_params->max_event_log_size; - priv->inst_errlog_ptr = pieces.inst_errlog_ptr; + nic->inst_errlog_ptr = pieces.inst_errlog_ptr; #ifndef CONFIG_IWLWIFI_P2P ucode_capa.flags &= ~IWL_UCODE_TLV_FLAGS_PAN; #endif From 69655ebf1a64eb922e2ed94ed62898e3c47dd492 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 6 Feb 2012 14:30:54 +0200 Subject: [PATCH 21/26] iwlwifi: the transport knows its state This allows to handle races such as Tx packets on their way to be sent although the transport has been stopped already. Signed-off-by: Emmanuel Grumbach Signed-off-by: Wey-Yi Guy --- drivers/net/wireless/iwlwifi/iwl-trans.h | 49 ++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 2a2941f9fd21..20b50a0e0a86 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -69,6 +69,7 @@ #include "iwl-shared.h" #include "iwl-commands.h" #include "iwl-ucode.h" +#include "iwl-debug.h" /** * DOC: Transport layer - what is it ? @@ -296,6 +297,17 @@ struct iwl_calib_result { /* data follows */ }; +/** + * enum iwl_trans_state - state of the transport layer + * + * @IWL_TRANS_NO_FW: no fw has sent an alive response + * @IWL_TRANS_FW_ALIVE: a fw has sent an alive response + */ +enum iwl_trans_state { + IWL_TRANS_NO_FW = 0, + IWL_TRANS_FW_ALIVE = 1, +}; + /** * struct iwl_trans - transport common data * @@ -319,6 +331,7 @@ struct iwl_calib_result { struct iwl_trans { const struct iwl_trans_ops *ops; struct iwl_shared *shrd; + enum iwl_trans_state state; spinlock_t hcmd_lock; spinlock_t reg_lock; @@ -352,6 +365,8 @@ static inline void iwl_trans_stop_hw(struct iwl_trans *trans) might_sleep(); trans->ops->stop_hw(trans); + + trans->state = IWL_TRANS_NO_FW; } static inline void iwl_trans_fw_alive(struct iwl_trans *trans) @@ -359,6 +374,8 @@ static inline void iwl_trans_fw_alive(struct iwl_trans *trans) might_sleep(); trans->ops->fw_alive(trans); + + trans->state = IWL_TRANS_FW_ALIVE; } static inline int iwl_trans_start_fw(struct iwl_trans *trans, struct fw_img *fw) @@ -373,12 +390,17 @@ static inline void iwl_trans_stop_device(struct iwl_trans *trans) might_sleep(); trans->ops->stop_device(trans); + + trans->state = IWL_TRANS_NO_FW; } static inline void iwl_trans_wake_any_queue(struct iwl_trans *trans, enum iwl_rxon_context_id ctx, const char *msg) { + if (trans->state != IWL_TRANS_FW_ALIVE) + IWL_ERR(trans, "%s bad state = %d", __func__, trans->state); + trans->ops->wake_any_queue(trans, ctx, msg); } @@ -386,6 +408,9 @@ static inline void iwl_trans_wake_any_queue(struct iwl_trans *trans, static inline int iwl_trans_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) { + if (trans->state != IWL_TRANS_FW_ALIVE) + IWL_ERR(trans, "%s bad state = %d", __func__, trans->state); + return trans->ops->send_cmd(trans, cmd); } @@ -396,6 +421,9 @@ static inline int iwl_trans_tx(struct iwl_trans *trans, struct sk_buff *skb, struct iwl_device_cmd *dev_cmd, enum iwl_rxon_context_id ctx, u8 sta_id, u8 tid) { + if (trans->state != IWL_TRANS_FW_ALIVE) + IWL_ERR(trans, "%s bad state = %d", __func__, trans->state); + return trans->ops->tx(trans, skb, dev_cmd, ctx, sta_id, tid); } @@ -403,6 +431,9 @@ static inline int iwl_trans_reclaim(struct iwl_trans *trans, int sta_id, int tid, int txq_id, int ssn, u32 status, struct sk_buff_head *skbs) { + if (trans->state != IWL_TRANS_FW_ALIVE) + IWL_ERR(trans, "%s bad state = %d", __func__, trans->state); + return trans->ops->reclaim(trans, sta_id, tid, txq_id, ssn, status, skbs); } @@ -412,6 +443,9 @@ static inline int iwl_trans_tx_agg_disable(struct iwl_trans *trans, { might_sleep(); + if (trans->state != IWL_TRANS_FW_ALIVE) + IWL_ERR(trans, "%s bad state = %d", __func__, trans->state); + return trans->ops->tx_agg_disable(trans, sta_id, tid); } @@ -420,6 +454,9 @@ static inline int iwl_trans_tx_agg_alloc(struct iwl_trans *trans, { might_sleep(); + if (trans->state != IWL_TRANS_FW_ALIVE) + IWL_ERR(trans, "%s bad state = %d", __func__, trans->state); + return trans->ops->tx_agg_alloc(trans, sta_id, tid); } @@ -431,6 +468,9 @@ static inline void iwl_trans_tx_agg_setup(struct iwl_trans *trans, { might_sleep(); + if (trans->state != IWL_TRANS_FW_ALIVE) + IWL_ERR(trans, "%s bad state = %d", __func__, trans->state); + trans->ops->tx_agg_setup(trans, ctx, sta_id, tid, frame_limit, ssn); } @@ -442,16 +482,25 @@ static inline void iwl_trans_free(struct iwl_trans *trans) static inline void iwl_trans_stop_queue(struct iwl_trans *trans, int q, const char *msg) { + if (trans->state != IWL_TRANS_FW_ALIVE) + IWL_ERR(trans, "%s bad state = %d", __func__, trans->state); + trans->ops->stop_queue(trans, q, msg); } static inline int iwl_trans_wait_tx_queue_empty(struct iwl_trans *trans) { + if (trans->state != IWL_TRANS_FW_ALIVE) + IWL_ERR(trans, "%s bad state = %d", __func__, trans->state); + return trans->ops->wait_tx_queue_empty(trans); } static inline int iwl_trans_check_stuck_queue(struct iwl_trans *trans, int q) { + if (trans->state != IWL_TRANS_FW_ALIVE) + IWL_ERR(trans, "%s bad state = %d", __func__, trans->state); + return trans->ops->check_stuck_queue(trans, q); } static inline int iwl_trans_dbgfs_register(struct iwl_trans *trans, From 06e03f8ce91b71c6ce4134c8bf9ed801aed0382c Mon Sep 17 00:00:00 2001 From: Don Fry Date: Tue, 7 Feb 2012 14:21:32 -0800 Subject: [PATCH 22/26] iwlwifi: changes args to iwl_nic for firmware operations Remove the references to iwl_priv from the firmware request and parsing routines. They are generic to the nic. Signed-off-by: Don Fry Signed-off-by: Wey-Yi Guy --- drivers/net/wireless/iwlwifi/iwl-agn.c | 2 +- drivers/net/wireless/iwlwifi/iwl-ucode.c | 149 ++++++++++++----------- drivers/net/wireless/iwlwifi/iwl-ucode.h | 4 - drivers/net/wireless/iwlwifi/iwl-wifi.h | 1 + 4 files changed, 77 insertions(+), 79 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 68b9e5e5da78..e8fed167f97e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1262,7 +1262,7 @@ int iwl_probe(struct iwl_bus *bus, const struct iwl_trans_ops *trans_ops, init_completion(&nic(priv)->request_firmware_complete); - err = iwl_request_firmware(priv, true); + err = iwl_request_firmware(nic(priv), true); if (err) goto out_destroy_workqueue; diff --git a/drivers/net/wireless/iwlwifi/iwl-ucode.c b/drivers/net/wireless/iwlwifi/iwl-ucode.c index 0d04a4d7dc84..01768f709a76 100644 --- a/drivers/net/wireless/iwlwifi/iwl-ucode.c +++ b/drivers/net/wireless/iwlwifi/iwl-ucode.c @@ -690,10 +690,10 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context); #define UCODE_EXPERIMENTAL_INDEX 100 #define UCODE_EXPERIMENTAL_TAG "exp" -int __must_check iwl_request_firmware(struct iwl_priv *priv, bool first) +int __must_check iwl_request_firmware(struct iwl_nic *nic, bool first) { - struct iwl_nic *nic = nic(priv); - const char *name_pre = cfg(priv)->fw_name_pre; + struct iwl_cfg *cfg = cfg(nic); + const char *name_pre = cfg->fw_name_pre; char tag[8]; if (first) { @@ -702,28 +702,28 @@ int __must_check iwl_request_firmware(struct iwl_priv *priv, bool first) strcpy(tag, UCODE_EXPERIMENTAL_TAG); } else if (nic->fw_index == UCODE_EXPERIMENTAL_INDEX) { #endif - nic->fw_index = cfg(priv)->ucode_api_max; + nic->fw_index = cfg->ucode_api_max; sprintf(tag, "%d", nic->fw_index); } else { nic->fw_index--; sprintf(tag, "%d", nic->fw_index); } - if (nic->fw_index < cfg(priv)->ucode_api_min) { - IWL_ERR(priv, "no suitable firmware found!\n"); + if (nic->fw_index < cfg->ucode_api_min) { + IWL_ERR(nic, "no suitable firmware found!\n"); return -ENOENT; } sprintf(nic->firmware_name, "%s%s%s", name_pre, tag, ".ucode"); - IWL_DEBUG_INFO(priv, "attempting to load firmware %s'%s'\n", + IWL_DEBUG_INFO(nic, "attempting to load firmware %s'%s'\n", (nic->fw_index == UCODE_EXPERIMENTAL_INDEX) ? "EXPERIMENTAL " : "", nic->firmware_name); return request_firmware_nowait(THIS_MODULE, 1, nic->firmware_name, - trans(priv)->dev, - GFP_KERNEL, priv, iwl_ucode_callback); + trans(nic)->dev, + GFP_KERNEL, nic, iwl_ucode_callback); } struct iwlagn_firmware_pieces { @@ -737,11 +737,10 @@ struct iwlagn_firmware_pieces { u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr; }; -static int iwlagn_load_legacy_firmware(struct iwl_priv *priv, +static int iwl_parse_v1_v2_firmware(struct iwl_nic *nic, const struct firmware *ucode_raw, struct iwlagn_firmware_pieces *pieces) { - struct iwl_nic *nic = nic(priv); struct iwl_ucode_header *ucode = (void *)ucode_raw->data; u32 api_ver, hdr_size; const u8 *src; @@ -753,7 +752,7 @@ static int iwlagn_load_legacy_firmware(struct iwl_priv *priv, default: hdr_size = 28; if (ucode_raw->size < hdr_size) { - IWL_ERR(priv, "File size too small!\n"); + IWL_ERR(nic, "File size too small!\n"); return -EINVAL; } pieces->build = le32_to_cpu(ucode->u.v2.build); @@ -768,7 +767,7 @@ static int iwlagn_load_legacy_firmware(struct iwl_priv *priv, case 2: hdr_size = 24; if (ucode_raw->size < hdr_size) { - IWL_ERR(priv, "File size too small!\n"); + IWL_ERR(nic, "File size too small!\n"); return -EINVAL; } pieces->build = 0; @@ -785,7 +784,7 @@ static int iwlagn_load_legacy_firmware(struct iwl_priv *priv, pieces->data_size + pieces->init_size + pieces->init_data_size) { - IWL_ERR(priv, + IWL_ERR(nic, "uCode file size %d does not match expected size\n", (int)ucode_raw->size); return -EINVAL; @@ -803,12 +802,11 @@ static int iwlagn_load_legacy_firmware(struct iwl_priv *priv, return 0; } -static int iwlagn_load_firmware(struct iwl_priv *priv, +static int iwl_parse_tlv_firmware(struct iwl_nic *nic, const struct firmware *ucode_raw, struct iwlagn_firmware_pieces *pieces, struct iwlagn_ucode_capabilities *capa) { - struct iwl_nic *nic = nic(priv); struct iwl_tlv_ucode_header *ucode = (void *)ucode_raw->data; struct iwl_ucode_tlv *tlv; size_t len = ucode_raw->size; @@ -821,12 +819,12 @@ static int iwlagn_load_firmware(struct iwl_priv *priv, const u8 *tlv_data; if (len < sizeof(*ucode)) { - IWL_ERR(priv, "uCode has invalid length: %zd\n", len); + IWL_ERR(nic, "uCode has invalid length: %zd\n", len); return -EINVAL; } if (ucode->magic != cpu_to_le32(IWL_TLV_UCODE_MAGIC)) { - IWL_ERR(priv, "invalid uCode magic: 0X%x\n", + IWL_ERR(nic, "invalid uCode magic: 0X%x\n", le32_to_cpu(ucode->magic)); return -EINVAL; } @@ -844,7 +842,7 @@ static int iwlagn_load_firmware(struct iwl_priv *priv, while (wanted_alternative && !(alternatives & BIT(wanted_alternative))) wanted_alternative--; if (wanted_alternative && wanted_alternative != tmp) - IWL_WARN(priv, + IWL_WARN(nic, "uCode alternative %d not available, choosing %d\n", tmp, wanted_alternative); @@ -866,7 +864,7 @@ static int iwlagn_load_firmware(struct iwl_priv *priv, tlv_data = tlv->data; if (len < tlv_len) { - IWL_ERR(priv, "invalid TLV len: %zd/%u\n", + IWL_ERR(nic, "invalid TLV len: %zd/%u\n", len, tlv_len); return -EINVAL; } @@ -899,7 +897,7 @@ static int iwlagn_load_firmware(struct iwl_priv *priv, pieces->init_data_size = tlv_len; break; case IWL_UCODE_TLV_BOOT: - IWL_ERR(priv, "Found unexpected BOOT ucode\n"); + IWL_ERR(nic, "Found unexpected BOOT ucode\n"); break; case IWL_UCODE_TLV_PROBE_MAX_LEN: if (tlv_len != sizeof(u32)) @@ -984,22 +982,22 @@ static int iwlagn_load_firmware(struct iwl_priv *priv, le32_to_cpup((__le32 *)tlv_data); break; default: - IWL_DEBUG_INFO(priv, "unknown TLV: %d\n", tlv_type); + IWL_DEBUG_INFO(nic, "unknown TLV: %d\n", tlv_type); break; } } if (len) { - IWL_ERR(priv, "invalid TLV after parsing: %zd\n", len); - iwl_print_hex_dump(priv, IWL_DL_FW, (u8 *)data, len); + IWL_ERR(nic, "invalid TLV after parsing: %zd\n", len); + iwl_print_hex_dump(nic, IWL_DL_FW, (u8 *)data, len); return -EINVAL; } return 0; invalid_tlv_len: - IWL_ERR(priv, "TLV %d has invalid size: %u\n", tlv_type, tlv_len); - iwl_print_hex_dump(priv, IWL_DL_FW, tlv_data, tlv_len); + IWL_ERR(nic, "TLV %d has invalid size: %u\n", tlv_type, tlv_len); + iwl_print_hex_dump(nic, IWL_DL_FW, tlv_data, tlv_len); return -EINVAL; } @@ -1012,14 +1010,15 @@ static int iwlagn_load_firmware(struct iwl_priv *priv, */ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) { - struct iwl_priv *priv = context; - struct iwl_nic *nic = nic(priv); + struct iwl_nic *nic = context; + struct iwl_cfg *cfg = cfg(nic); + struct iwl_priv *priv = priv(nic); /* temporary */ struct iwl_ucode_header *ucode; int err; struct iwlagn_firmware_pieces pieces; - const unsigned int api_max = cfg(priv)->ucode_api_max; - unsigned int api_ok = cfg(priv)->ucode_api_ok; - const unsigned int api_min = cfg(priv)->ucode_api_min; + const unsigned int api_max = cfg->ucode_api_max; + unsigned int api_ok = cfg->ucode_api_ok; + const unsigned int api_min = cfg->ucode_api_min; u32 api_ver; char buildstr[25]; u32 build; @@ -1036,18 +1035,18 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) if (!ucode_raw) { if (nic->fw_index <= api_ok) - IWL_ERR(priv, + IWL_ERR(nic, "request for firmware file '%s' failed.\n", nic->firmware_name); goto try_again; } - IWL_DEBUG_INFO(priv, "Loaded firmware file '%s' (%zd bytes).\n", + IWL_DEBUG_INFO(nic, "Loaded firmware file '%s' (%zd bytes).\n", nic->firmware_name, ucode_raw->size); /* Make sure that we got at least the API version number */ if (ucode_raw->size < 4) { - IWL_ERR(priv, "File size way too small!\n"); + IWL_ERR(nic, "File size way too small!\n"); goto try_again; } @@ -1055,9 +1054,9 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) ucode = (struct iwl_ucode_header *)ucode_raw->data; if (ucode->ver) - err = iwlagn_load_legacy_firmware(priv, ucode_raw, &pieces); + err = iwl_parse_v1_v2_firmware(nic, ucode_raw, &pieces); else - err = iwlagn_load_firmware(priv, ucode_raw, &pieces, + err = iwl_parse_tlv_firmware(nic, ucode_raw, &pieces, &ucode_capa); if (err) @@ -1074,7 +1073,7 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) /* no api version check required for experimental uCode */ if (nic->fw_index != UCODE_EXPERIMENTAL_INDEX) { if (api_ver < api_min || api_ver > api_max) { - IWL_ERR(priv, + IWL_ERR(nic, "Driver unable to support your firmware API. " "Driver supports v%u, firmware is v%u.\n", api_max, api_ver); @@ -1083,14 +1082,14 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) if (api_ver < api_ok) { if (api_ok != api_max) - IWL_ERR(priv, "Firmware has old API version, " + IWL_ERR(nic, "Firmware has old API version, " "expected v%u through v%u, got v%u.\n", api_ok, api_max, api_ver); else - IWL_ERR(priv, "Firmware has old API version, " + IWL_ERR(nic, "Firmware has old API version, " "expected v%u, got v%u.\n", api_max, api_ver); - IWL_ERR(priv, "New firmware can be obtained from " + IWL_ERR(nic, "New firmware can be obtained from " "http://www.intellinuxwireless.org/.\n"); } } @@ -1102,7 +1101,7 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) else buildstr[0] = '\0'; - IWL_INFO(priv, "loaded firmware version %u.%u.%u.%u%s\n", + IWL_INFO(nic, "loaded firmware version %u.%u.%u.%u%s\n", IWL_UCODE_MAJOR(nic->fw.ucode_ver), IWL_UCODE_MINOR(nic->fw.ucode_ver), IWL_UCODE_API(nic->fw.ucode_ver), @@ -1124,38 +1123,38 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) * user just got a corrupted version of the latest API. */ - IWL_DEBUG_INFO(priv, "f/w package hdr ucode version raw = 0x%x\n", + IWL_DEBUG_INFO(nic, "f/w package hdr ucode version raw = 0x%x\n", nic->fw.ucode_ver); - IWL_DEBUG_INFO(priv, "f/w package hdr runtime inst size = %Zd\n", + IWL_DEBUG_INFO(nic, "f/w package hdr runtime inst size = %Zd\n", pieces.inst_size); - IWL_DEBUG_INFO(priv, "f/w package hdr runtime data size = %Zd\n", + IWL_DEBUG_INFO(nic, "f/w package hdr runtime data size = %Zd\n", pieces.data_size); - IWL_DEBUG_INFO(priv, "f/w package hdr init inst size = %Zd\n", + IWL_DEBUG_INFO(nic, "f/w package hdr init inst size = %Zd\n", pieces.init_size); - IWL_DEBUG_INFO(priv, "f/w package hdr init data size = %Zd\n", + IWL_DEBUG_INFO(nic, "f/w package hdr init data size = %Zd\n", pieces.init_data_size); /* Verify that uCode images will fit in card's SRAM */ - if (pieces.inst_size > hw_params(priv).max_inst_size) { - IWL_ERR(priv, "uCode instr len %Zd too large to fit in\n", + if (pieces.inst_size > hw_params(nic).max_inst_size) { + IWL_ERR(nic, "uCode instr len %Zd too large to fit in\n", pieces.inst_size); goto try_again; } - if (pieces.data_size > hw_params(priv).max_data_size) { - IWL_ERR(priv, "uCode data len %Zd too large to fit in\n", + if (pieces.data_size > hw_params(nic).max_data_size) { + IWL_ERR(nic, "uCode data len %Zd too large to fit in\n", pieces.data_size); goto try_again; } - if (pieces.init_size > hw_params(priv).max_inst_size) { - IWL_ERR(priv, "uCode init instr len %Zd too large to fit in\n", + if (pieces.init_size > hw_params(nic).max_inst_size) { + IWL_ERR(nic, "uCode init instr len %Zd too large to fit in\n", pieces.init_size); goto try_again; } - if (pieces.init_data_size > hw_params(priv).max_data_size) { - IWL_ERR(priv, "uCode init data len %Zd too large to fit in\n", + if (pieces.init_data_size > hw_params(nic).max_data_size) { + IWL_ERR(nic, "uCode init data len %Zd too large to fit in\n", pieces.init_data_size); goto try_again; } @@ -1165,34 +1164,34 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) /* Runtime instructions and 2 copies of data: * 1) unmodified from disk * 2) backup cache for save/restore during power-downs */ - if (iwl_alloc_fw_desc(nic(priv), &nic(priv)->fw.ucode_rt.code, + if (iwl_alloc_fw_desc(nic, &nic->fw.ucode_rt.code, pieces.inst, pieces.inst_size)) goto err_pci_alloc; - if (iwl_alloc_fw_desc(nic(priv), &nic(priv)->fw.ucode_rt.data, + if (iwl_alloc_fw_desc(nic, &nic->fw.ucode_rt.data, pieces.data, pieces.data_size)) goto err_pci_alloc; /* Initialization instructions and data */ if (pieces.init_size && pieces.init_data_size) { - if (iwl_alloc_fw_desc(nic(priv), - &nic(priv)->fw.ucode_init.code, + if (iwl_alloc_fw_desc(nic, + &nic->fw.ucode_init.code, pieces.init, pieces.init_size)) goto err_pci_alloc; - if (iwl_alloc_fw_desc(nic(priv), - &nic(priv)->fw.ucode_init.data, + if (iwl_alloc_fw_desc(nic, + &nic->fw.ucode_init.data, pieces.init_data, pieces.init_data_size)) goto err_pci_alloc; } /* WoWLAN instructions and data */ if (pieces.wowlan_inst_size && pieces.wowlan_data_size) { - if (iwl_alloc_fw_desc(nic(priv), - &nic(priv)->fw.ucode_wowlan.code, + if (iwl_alloc_fw_desc(nic, + &nic->fw.ucode_wowlan.code, pieces.wowlan_inst, pieces.wowlan_inst_size)) goto err_pci_alloc; - if (iwl_alloc_fw_desc(nic(priv), - &nic(priv)->fw.ucode_wowlan.data, + if (iwl_alloc_fw_desc(nic, + &nic->fw.ucode_wowlan.data, pieces.wowlan_data, pieces.wowlan_data_size)) goto err_pci_alloc; @@ -1210,14 +1209,14 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) nic->init_evtlog_size = (pieces.init_evtlog_size - 16)/12; else nic->init_evtlog_size = - cfg(priv)->base_params->max_event_log_size; + cfg->base_params->max_event_log_size; nic->init_errlog_ptr = pieces.init_errlog_ptr; nic->inst_evtlog_ptr = pieces.inst_evtlog_ptr; if (pieces.inst_evtlog_size) nic->inst_evtlog_size = (pieces.inst_evtlog_size - 16)/12; else nic->inst_evtlog_size = - cfg(priv)->base_params->max_event_log_size; + cfg->base_params->max_event_log_size; nic->inst_errlog_ptr = pieces.inst_errlog_ptr; #ifndef CONFIG_IWLWIFI_P2P ucode_capa.flags &= ~IWL_UCODE_TLV_FLAGS_PAN; @@ -1226,7 +1225,7 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) priv->new_scan_threshold_behaviour = !!(ucode_capa.flags & IWL_UCODE_TLV_FLAGS_NEWSCAN); - if (!(cfg(priv)->sku & EEPROM_SKU_CAP_IPAN_ENABLE)) + if (!(cfg->sku & EEPROM_SKU_CAP_IPAN_ENABLE)) ucode_capa.flags &= ~IWL_UCODE_TLV_FLAGS_PAN; /* @@ -1238,10 +1237,10 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) if (ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PAN) { priv->sta_key_max_num = STA_KEY_MAX_NUM_PAN; - priv->shrd->cmd_queue = IWL_IPAN_CMD_QUEUE_NUM; + nic->shrd->cmd_queue = IWL_IPAN_CMD_QUEUE_NUM; } else { priv->sta_key_max_num = STA_KEY_MAX_NUM; - priv->shrd->cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM; + nic->shrd->cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM; } /* * figure out the offset of chain noise reset and gain commands @@ -1271,7 +1270,9 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) err = iwl_dbgfs_register(priv, DRV_NAME); if (err) - IWL_ERR(priv, "failed to create debugfs files. Ignoring error: %d\n", err); + IWL_ERR(nic, + "failed to create debugfs files. Ignoring error: %d\n", + err); /* We have our copies now, allow OS release its copies */ release_firmware(ucode_raw); @@ -1280,17 +1281,17 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) try_again: /* try next, if any */ - if (iwl_request_firmware(priv, false)) + if (iwl_request_firmware(nic, false)) goto out_unbind; release_firmware(ucode_raw); return; err_pci_alloc: - IWL_ERR(priv, "failed to allocate pci memory\n"); - iwl_dealloc_ucode(nic(priv)); + IWL_ERR(nic, "failed to allocate pci memory\n"); + iwl_dealloc_ucode(nic); out_unbind: complete(&nic->request_firmware_complete); - device_release_driver(trans(priv)->dev); + device_release_driver(trans(nic)->dev); release_firmware(ucode_raw); } diff --git a/drivers/net/wireless/iwlwifi/iwl-ucode.h b/drivers/net/wireless/iwlwifi/iwl-ucode.h index 5e4b88e05c62..d13e6241f126 100644 --- a/drivers/net/wireless/iwlwifi/iwl-ucode.h +++ b/drivers/net/wireless/iwlwifi/iwl-ucode.h @@ -218,8 +218,4 @@ struct iwl_fw { bool enhance_sensitivity_table; }; -struct iwl_priv; - -int __must_check iwl_request_firmware(struct iwl_priv *priv, bool first); - #endif /* __iwl_ucode_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-wifi.h b/drivers/net/wireless/iwlwifi/iwl-wifi.h index 392f1113d954..84172f6de4bb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-wifi.h +++ b/drivers/net/wireless/iwlwifi/iwl-wifi.h @@ -95,6 +95,7 @@ struct iwl_nic { }; +int __must_check iwl_request_firmware(struct iwl_nic *nic, bool first); void iwl_dealloc_ucode(struct iwl_nic *nic); int iwl_send_bt_env(struct iwl_trans *trans, u8 action, u8 type); From 4a986777a53d5fe8fd92ef30e0e8eedd0ff800b1 Mon Sep 17 00:00:00 2001 From: Don Fry Date: Mon, 6 Feb 2012 17:06:07 -0800 Subject: [PATCH 23/26] iwlwifi: save ucode capabilities in iwl_fw The capabilities parsed from the ucode file are never saved. Save them in the iwl_fw structure. Signed-off-by: Don Fry Signed-off-by: Wey-Yi Guy --- drivers/net/wireless/iwlwifi/iwl-agn.h | 8 ++--- drivers/net/wireless/iwlwifi/iwl-mac80211.c | 2 +- drivers/net/wireless/iwlwifi/iwl-trans.h | 3 -- drivers/net/wireless/iwlwifi/iwl-ucode.c | 38 ++++++++++----------- 4 files changed, 22 insertions(+), 29 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index 8a170b7f1e17..79894aca9644 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h @@ -65,11 +65,7 @@ #include "iwl-dev.h" -struct iwlagn_ucode_capabilities { - u32 max_probe_length; - u32 standard_phy_calibration_size; - u32 flags; -}; +struct iwl_ucode_capabilities; extern struct ieee80211_ops iwlagn_hw_ops; @@ -88,7 +84,7 @@ void iwlagn_prepare_restart(struct iwl_priv *priv); /* MAC80211 */ struct ieee80211_hw *iwl_alloc_all(void); int iwlagn_mac_setup_register(struct iwl_priv *priv, - struct iwlagn_ucode_capabilities *capa); + struct iwl_ucode_capabilities *capa); void iwlagn_mac_unregister(struct iwl_priv *priv); /* RXON */ diff --git a/drivers/net/wireless/iwlwifi/iwl-mac80211.c b/drivers/net/wireless/iwlwifi/iwl-mac80211.c index 90d8081426f6..9c29234221fd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-mac80211.c +++ b/drivers/net/wireless/iwlwifi/iwl-mac80211.c @@ -136,7 +136,7 @@ iwlagn_iface_combinations_p2p[] = { * other mac80211 functions grouped here. */ int iwlagn_mac_setup_register(struct iwl_priv *priv, - struct iwlagn_ucode_capabilities *capa) + struct iwl_ucode_capabilities *capa) { int ret; struct ieee80211_hw *hw = priv->hw; diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 20b50a0e0a86..cc7a3cfb5f24 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -321,9 +321,6 @@ enum iwl_trans_state { * Set during transport allocation. * @hw_id_str: a string with info about HW ID. Set during transport allocation. * @ucode_write_complete: indicates that the ucode has been copied. - * @ucode_rt: run time ucode image - * @ucode_init: init ucode image - * @ucode_wowlan: wake on wireless ucode image (optional) * @nvm_device_type: indicates OTP or eeprom * @pm_support: set to true in start_hw if link pm is supported * @calib_results: list head for init calibration results diff --git a/drivers/net/wireless/iwlwifi/iwl-ucode.c b/drivers/net/wireless/iwlwifi/iwl-ucode.c index 01768f709a76..9e21fc15c5f8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-ucode.c +++ b/drivers/net/wireless/iwlwifi/iwl-ucode.c @@ -805,7 +805,7 @@ static int iwl_parse_v1_v2_firmware(struct iwl_nic *nic, static int iwl_parse_tlv_firmware(struct iwl_nic *nic, const struct firmware *ucode_raw, struct iwlagn_firmware_pieces *pieces, - struct iwlagn_ucode_capabilities *capa) + struct iwl_ucode_capabilities *capa) { struct iwl_tlv_ucode_header *ucode = (void *)ucode_raw->data; struct iwl_ucode_tlv *tlv; @@ -1012,6 +1012,7 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) { struct iwl_nic *nic = context; struct iwl_cfg *cfg = cfg(nic); + struct iwl_fw *fw = &nic->fw; struct iwl_priv *priv = priv(nic); /* temporary */ struct iwl_ucode_header *ucode; int err; @@ -1022,11 +1023,10 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) u32 api_ver; char buildstr[25]; u32 build; - struct iwlagn_ucode_capabilities ucode_capa = { - .max_probe_length = 200, - .standard_phy_calibration_size = - IWL_DEFAULT_STANDARD_PHY_CALIBRATE_TBL_SIZE, - }; + + fw->ucode_capa.max_probe_length = 200; + fw->ucode_capa.standard_phy_calibration_size = + IWL_DEFAULT_STANDARD_PHY_CALIBRATE_TBL_SIZE; if (!api_ok) api_ok = api_max; @@ -1057,7 +1057,7 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) err = iwl_parse_v1_v2_firmware(nic, ucode_raw, &pieces); else err = iwl_parse_tlv_firmware(nic, ucode_raw, &pieces, - &ucode_capa); + &fw->ucode_capa); if (err) goto try_again; @@ -1219,23 +1219,23 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) cfg->base_params->max_event_log_size; nic->inst_errlog_ptr = pieces.inst_errlog_ptr; #ifndef CONFIG_IWLWIFI_P2P - ucode_capa.flags &= ~IWL_UCODE_TLV_FLAGS_PAN; + fw->ucode_capa.flags &= ~IWL_UCODE_TLV_FLAGS_PAN; #endif priv->new_scan_threshold_behaviour = - !!(ucode_capa.flags & IWL_UCODE_TLV_FLAGS_NEWSCAN); + !!(fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_NEWSCAN); if (!(cfg->sku & EEPROM_SKU_CAP_IPAN_ENABLE)) - ucode_capa.flags &= ~IWL_UCODE_TLV_FLAGS_PAN; + fw->ucode_capa.flags &= ~IWL_UCODE_TLV_FLAGS_PAN; /* * if not PAN, then don't support P2P -- might be a uCode * packaging bug or due to the eeprom check above */ - if (!(ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PAN)) - ucode_capa.flags &= ~IWL_UCODE_TLV_FLAGS_P2P; + if (!(fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PAN)) + fw->ucode_capa.flags &= ~IWL_UCODE_TLV_FLAGS_P2P; - if (ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PAN) { + if (fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PAN) { priv->sta_key_max_num = STA_KEY_MAX_NUM_PAN; nic->shrd->cmd_queue = IWL_IPAN_CMD_QUEUE_NUM; } else { @@ -1246,25 +1246,25 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) * figure out the offset of chain noise reset and gain commands * base on the size of standard phy calibration commands table size */ - if (ucode_capa.standard_phy_calibration_size > + if (fw->ucode_capa.standard_phy_calibration_size > IWL_MAX_PHY_CALIBRATE_TBL_SIZE) - ucode_capa.standard_phy_calibration_size = + fw->ucode_capa.standard_phy_calibration_size = IWL_MAX_STANDARD_PHY_CALIBRATE_TBL_SIZE; priv->phy_calib_chain_noise_reset_cmd = - ucode_capa.standard_phy_calibration_size; + fw->ucode_capa.standard_phy_calibration_size; priv->phy_calib_chain_noise_gain_cmd = - ucode_capa.standard_phy_calibration_size + 1; + fw->ucode_capa.standard_phy_calibration_size + 1; /* initialize all valid contexts */ - iwl_init_context(priv, ucode_capa.flags); + iwl_init_context(priv, fw->ucode_capa.flags); /************************************************** * This is still part of probe() in a sense... * * 9. Setup and register with mac80211 and debugfs **************************************************/ - err = iwlagn_mac_setup_register(priv, &ucode_capa); + err = iwlagn_mac_setup_register(priv, &fw->ucode_capa); if (err) goto out_unbind; From dae66d0d2ee1a188fcfd437c4e6b2bf32dc7a1b2 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 7 Feb 2012 12:56:26 +0200 Subject: [PATCH 24/26] iwlwifi: SRAM size moves from hw_params to cfg This will allow to set the hw_params after we fetch the uCode. Signed-off-by: Emmanuel Grumbach Signed-off-by: Wey-Yi Guy --- drivers/net/wireless/iwlwifi/iwl-1000.c | 6 ++++-- drivers/net/wireless/iwlwifi/iwl-2000.c | 10 ++++++++-- drivers/net/wireless/iwlwifi/iwl-5000.c | 10 ++++++---- drivers/net/wireless/iwlwifi/iwl-6000.c | 14 ++++++++++++-- drivers/net/wireless/iwlwifi/iwl-shared.h | 8 ++++---- drivers/net/wireless/iwlwifi/iwl-ucode.c | 8 ++++---- 6 files changed, 38 insertions(+), 18 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 91c4a72da8d7..605ee3df1d82 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -128,8 +128,6 @@ static void iwl1000_hw_set_hw_params(struct iwl_priv *priv) iwlagn_mod_params.num_of_queues; hw_params(priv).max_txq_num = cfg(priv)->base_params->num_of_queues; - hw_params(priv).max_data_size = IWLAGN_RTC_DATA_SIZE; - hw_params(priv).max_inst_size = IWLAGN_RTC_INST_SIZE; hw_params(priv).ht40_channel = BIT(IEEE80211_BAND_2GHZ); @@ -191,6 +189,8 @@ static struct iwl_ht_params iwl1000_ht_params = { .ucode_api_max = IWL1000_UCODE_API_MAX, \ .ucode_api_ok = IWL1000_UCODE_API_OK, \ .ucode_api_min = IWL1000_UCODE_API_MIN, \ + .max_inst_size = IWLAGN_RTC_INST_SIZE, \ + .max_data_size = IWLAGN_RTC_DATA_SIZE, \ .eeprom_ver = EEPROM_1000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION, \ .lib = &iwl1000_lib, \ @@ -213,6 +213,8 @@ struct iwl_cfg iwl1000_bg_cfg = { .ucode_api_max = IWL100_UCODE_API_MAX, \ .ucode_api_ok = IWL100_UCODE_API_OK, \ .ucode_api_min = IWL100_UCODE_API_MIN, \ + .max_inst_size = IWLAGN_RTC_INST_SIZE, \ + .max_data_size = IWLAGN_RTC_DATA_SIZE, \ .eeprom_ver = EEPROM_1000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION, \ .lib = &iwl1000_lib, \ diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c index 75f0e5088662..e6e8c79a80d8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-2000.c +++ b/drivers/net/wireless/iwlwifi/iwl-2000.c @@ -124,8 +124,6 @@ static void iwl2000_hw_set_hw_params(struct iwl_priv *priv) iwlagn_mod_params.num_of_queues; hw_params(priv).max_txq_num = cfg(priv)->base_params->num_of_queues; - hw_params(priv).max_data_size = IWL60_RTC_DATA_SIZE; - hw_params(priv).max_inst_size = IWL60_RTC_INST_SIZE; hw_params(priv).ht40_channel = BIT(IEEE80211_BAND_2GHZ); @@ -240,6 +238,8 @@ static struct iwl_bt_params iwl2030_bt_params = { .ucode_api_max = IWL2000_UCODE_API_MAX, \ .ucode_api_ok = IWL2000_UCODE_API_OK, \ .ucode_api_min = IWL2000_UCODE_API_MIN, \ + .max_inst_size = IWL60_RTC_INST_SIZE, \ + .max_data_size = IWL60_RTC_DATA_SIZE, \ .eeprom_ver = EEPROM_2000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ .lib = &iwl2000_lib, \ @@ -266,6 +266,8 @@ struct iwl_cfg iwl2000_2bgn_d_cfg = { .ucode_api_max = IWL2030_UCODE_API_MAX, \ .ucode_api_ok = IWL2030_UCODE_API_OK, \ .ucode_api_min = IWL2030_UCODE_API_MIN, \ + .max_inst_size = IWL60_RTC_INST_SIZE, \ + .max_data_size = IWL60_RTC_DATA_SIZE, \ .eeprom_ver = EEPROM_2000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ .lib = &iwl2030_lib, \ @@ -288,6 +290,8 @@ struct iwl_cfg iwl2030_2bgn_cfg = { .ucode_api_max = IWL105_UCODE_API_MAX, \ .ucode_api_ok = IWL105_UCODE_API_OK, \ .ucode_api_min = IWL105_UCODE_API_MIN, \ + .max_inst_size = IWL60_RTC_INST_SIZE, \ + .max_data_size = IWL60_RTC_DATA_SIZE, \ .eeprom_ver = EEPROM_2000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ .lib = &iwl2000_lib, \ @@ -316,6 +320,8 @@ struct iwl_cfg iwl105_bgn_d_cfg = { .ucode_api_max = IWL135_UCODE_API_MAX, \ .ucode_api_ok = IWL135_UCODE_API_OK, \ .ucode_api_min = IWL135_UCODE_API_MIN, \ + .max_inst_size = IWL60_RTC_INST_SIZE, \ + .max_data_size = IWL60_RTC_DATA_SIZE, \ .eeprom_ver = EEPROM_2000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ .lib = &iwl2030_lib, \ diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 458e6778c72f..1527dec7a267 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -170,8 +170,6 @@ static void iwl5000_hw_set_hw_params(struct iwl_priv *priv) iwlagn_mod_params.num_of_queues; hw_params(priv).max_txq_num = cfg(priv)->base_params->num_of_queues; - hw_params(priv).max_data_size = IWLAGN_RTC_DATA_SIZE; - hw_params(priv).max_inst_size = IWLAGN_RTC_INST_SIZE; hw_params(priv).ht40_channel = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ); @@ -195,8 +193,6 @@ static void iwl5150_hw_set_hw_params(struct iwl_priv *priv) iwlagn_mod_params.num_of_queues; hw_params(priv).max_txq_num = cfg(priv)->base_params->num_of_queues; - hw_params(priv).max_data_size = IWLAGN_RTC_DATA_SIZE; - hw_params(priv).max_inst_size = IWLAGN_RTC_INST_SIZE; hw_params(priv).ht40_channel = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ); @@ -352,6 +348,8 @@ static struct iwl_ht_params iwl5000_ht_params = { .fw_name_pre = IWL5000_FW_PRE, \ .ucode_api_max = IWL5000_UCODE_API_MAX, \ .ucode_api_min = IWL5000_UCODE_API_MIN, \ + .max_inst_size = IWLAGN_RTC_INST_SIZE, \ + .max_data_size = IWLAGN_RTC_DATA_SIZE, \ .eeprom_ver = EEPROM_5000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, \ .lib = &iwl5000_lib, \ @@ -395,6 +393,8 @@ struct iwl_cfg iwl5350_agn_cfg = { .fw_name_pre = IWL5000_FW_PRE, .ucode_api_max = IWL5000_UCODE_API_MAX, .ucode_api_min = IWL5000_UCODE_API_MIN, + .max_inst_size = IWLAGN_RTC_INST_SIZE, + .max_data_size = IWLAGN_RTC_DATA_SIZE, .eeprom_ver = EEPROM_5050_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION, .lib = &iwl5000_lib, @@ -408,6 +408,8 @@ struct iwl_cfg iwl5350_agn_cfg = { .fw_name_pre = IWL5150_FW_PRE, \ .ucode_api_max = IWL5150_UCODE_API_MAX, \ .ucode_api_min = IWL5150_UCODE_API_MIN, \ + .max_inst_size = IWLAGN_RTC_INST_SIZE, \ + .max_data_size = IWLAGN_RTC_DATA_SIZE, \ .eeprom_ver = EEPROM_5050_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION, \ .lib = &iwl5150_lib, \ diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 19e41037f61e..1e6fbf4fcb46 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -145,8 +145,6 @@ static void iwl6000_hw_set_hw_params(struct iwl_priv *priv) iwlagn_mod_params.num_of_queues; hw_params(priv).max_txq_num = cfg(priv)->base_params->num_of_queues; - hw_params(priv).max_data_size = IWL60_RTC_DATA_SIZE; - hw_params(priv).max_inst_size = IWL60_RTC_INST_SIZE; hw_params(priv).ht40_channel = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ); @@ -348,6 +346,8 @@ static struct iwl_bt_params iwl6000_bt_params = { .ucode_api_max = IWL6000G2_UCODE_API_MAX, \ .ucode_api_ok = IWL6000G2_UCODE_API_OK, \ .ucode_api_min = IWL6000G2_UCODE_API_MIN, \ + .max_inst_size = IWL60_RTC_INST_SIZE, \ + .max_data_size = IWL60_RTC_DATA_SIZE, \ .eeprom_ver = EEPROM_6005_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_6005_TX_POWER_VERSION, \ .lib = &iwl6000_lib, \ @@ -388,6 +388,8 @@ struct iwl_cfg iwl6005_2agn_d_cfg = { .ucode_api_max = IWL6000G2_UCODE_API_MAX, \ .ucode_api_ok = IWL6000G2_UCODE_API_OK, \ .ucode_api_min = IWL6000G2_UCODE_API_MIN, \ + .max_inst_size = IWL60_RTC_INST_SIZE, \ + .max_data_size = IWL60_RTC_DATA_SIZE, \ .eeprom_ver = EEPROM_6030_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_6030_TX_POWER_VERSION, \ .lib = &iwl6030_lib, \ @@ -457,6 +459,8 @@ struct iwl_cfg iwl130_bg_cfg = { .ucode_api_max = IWL6000_UCODE_API_MAX, \ .ucode_api_ok = IWL6000_UCODE_API_OK, \ .ucode_api_min = IWL6000_UCODE_API_MIN, \ + .max_inst_size = IWL60_RTC_INST_SIZE, \ + .max_data_size = IWL60_RTC_DATA_SIZE, \ .valid_tx_ant = ANT_BC, /* .cfg overwrite */ \ .valid_rx_ant = ANT_BC, /* .cfg overwrite */ \ .eeprom_ver = EEPROM_6000_EEPROM_VERSION, \ @@ -486,6 +490,8 @@ struct iwl_cfg iwl6000i_2bg_cfg = { .fw_name_pre = IWL6050_FW_PRE, \ .ucode_api_max = IWL6050_UCODE_API_MAX, \ .ucode_api_min = IWL6050_UCODE_API_MIN, \ + .max_inst_size = IWL60_RTC_INST_SIZE, \ + .max_data_size = IWL60_RTC_DATA_SIZE, \ .valid_tx_ant = ANT_AB, /* .cfg overwrite */ \ .valid_rx_ant = ANT_AB, /* .cfg overwrite */ \ .lib = &iwl6000_lib, \ @@ -511,6 +517,8 @@ struct iwl_cfg iwl6050_2abg_cfg = { .fw_name_pre = IWL6050_FW_PRE, \ .ucode_api_max = IWL6050_UCODE_API_MAX, \ .ucode_api_min = IWL6050_UCODE_API_MIN, \ + .max_inst_size = IWL60_RTC_INST_SIZE, \ + .max_data_size = IWL60_RTC_DATA_SIZE, \ .lib = &iwl6000_lib, \ .additional_nic_config = iwl6150_additional_nic_config, \ .eeprom_ver = EEPROM_6150_EEPROM_VERSION, \ @@ -536,6 +544,8 @@ struct iwl_cfg iwl6000_3agn_cfg = { .ucode_api_max = IWL6000_UCODE_API_MAX, .ucode_api_ok = IWL6000_UCODE_API_OK, .ucode_api_min = IWL6000_UCODE_API_MIN, + .max_inst_size = IWL60_RTC_INST_SIZE, + .max_data_size = IWL60_RTC_DATA_SIZE, .eeprom_ver = EEPROM_6000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION, .lib = &iwl6000_lib, diff --git a/drivers/net/wireless/iwlwifi/iwl-shared.h b/drivers/net/wireless/iwlwifi/iwl-shared.h index 8c6fc6e20768..f810b41db9df 100644 --- a/drivers/net/wireless/iwlwifi/iwl-shared.h +++ b/drivers/net/wireless/iwlwifi/iwl-shared.h @@ -173,8 +173,6 @@ struct iwl_mod_params { * @ht40_channel: is 40MHz width possible: BIT(IEEE80211_BAND_XXX) * @sku: sku read from EEPROM * @rx_page_order: Rx buffer page order - * @max_inst_size: for ucode use - * @max_data_size: for ucode use * @ct_kill_threshold: temperature threshold - in hw dependent unit * @ct_kill_exit_threshold: when to reeable the device - in hw dependent unit * relevant for 1000, 6000 and up @@ -192,8 +190,6 @@ struct iwl_hw_params { bool shadow_reg_enable; u16 sku; u32 rx_page_order; - u32 max_inst_size; - u32 max_data_size; u32 ct_kill_threshold; u32 ct_kill_exit_threshold; unsigned int wd_timeout; @@ -283,6 +279,8 @@ enum iwl_led_mode { * @ucode_api_ok: oldest version of the uCode API that is OK to load * without a warning, for use in transitions * @ucode_api_min: Lowest version of uCode API supported by driver. + * @max_inst_size: The maximal length of the fw inst section + * @max_data_size: The maximal length of the fw data section * @valid_tx_ant: valid transmit antenna * @valid_rx_ant: valid receive antenna * @sku: sku information from EEPROM @@ -320,6 +318,8 @@ struct iwl_cfg { const unsigned int ucode_api_max; const unsigned int ucode_api_ok; const unsigned int ucode_api_min; + const u32 max_data_size; + const u32 max_inst_size; u8 valid_tx_ant; u8 valid_rx_ant; u16 sku; diff --git a/drivers/net/wireless/iwlwifi/iwl-ucode.c b/drivers/net/wireless/iwlwifi/iwl-ucode.c index 9e21fc15c5f8..61c6c0568c11 100644 --- a/drivers/net/wireless/iwlwifi/iwl-ucode.c +++ b/drivers/net/wireless/iwlwifi/iwl-ucode.c @@ -1135,25 +1135,25 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) pieces.init_data_size); /* Verify that uCode images will fit in card's SRAM */ - if (pieces.inst_size > hw_params(nic).max_inst_size) { + if (pieces.inst_size > cfg->max_inst_size) { IWL_ERR(nic, "uCode instr len %Zd too large to fit in\n", pieces.inst_size); goto try_again; } - if (pieces.data_size > hw_params(nic).max_data_size) { + if (pieces.data_size > cfg->max_data_size) { IWL_ERR(nic, "uCode data len %Zd too large to fit in\n", pieces.data_size); goto try_again; } - if (pieces.init_size > hw_params(nic).max_inst_size) { + if (pieces.init_size > cfg->max_inst_size) { IWL_ERR(nic, "uCode init instr len %Zd too large to fit in\n", pieces.init_size); goto try_again; } - if (pieces.init_data_size > hw_params(nic).max_data_size) { + if (pieces.init_data_size > cfg->max_data_size) { IWL_ERR(nic, "uCode init data len %Zd too large to fit in\n", pieces.init_data_size); goto try_again; From dd63b84eb44ba4e34daa83cf535a8bb79bc7f2e2 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Wed, 8 Feb 2012 15:57:39 -0800 Subject: [PATCH 25/26] iwlwifi: remove un-necessary return Already return 0, change to void Signed-off-by: Wey-Yi Guy --- drivers/net/wireless/iwlwifi/iwl-core.c | 5 ++--- drivers/net/wireless/iwlwifi/iwl-core.h | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 6dff9c41c555..f3b72bc84d25 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -643,7 +643,7 @@ u8 iwl_get_single_channel_number(struct iwl_priv *priv, * NOTE: Does not commit to the hardware; it sets appropriate bit fields * in the staging RXON flag structure based on the ch->band */ -int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch, +void iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch, struct iwl_rxon_context *ctx) { enum ieee80211_band band = ch->band; @@ -651,7 +651,7 @@ int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch, if ((le16_to_cpu(ctx->staging.channel) == channel) && (priv->band == band)) - return 0; + return; ctx->staging.channel = cpu_to_le16(channel); if (band == IEEE80211_BAND_5GHZ) @@ -663,7 +663,6 @@ int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch, IWL_DEBUG_INFO(priv, "Staging channel set to %d [%d]\n", channel, band); - return 0; } void iwl_set_flags_for_band(struct iwl_priv *priv, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 49370dd37768..930e247bbae6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -169,7 +169,7 @@ void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, struct iwl_rxon_context *ctx, int hw_decrypt); int iwl_check_rxon_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx); int iwl_full_rxon_required(struct iwl_priv *priv, struct iwl_rxon_context *ctx); -int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch, +void iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch, struct iwl_rxon_context *ctx); void iwl_set_flags_for_band(struct iwl_priv *priv, struct iwl_rxon_context *ctx, From 758f555f5e69bb44fc85edb90b3d15e68a29bc0c Mon Sep 17 00:00:00 2001 From: Meenakshi Venkataraman Date: Wed, 8 Feb 2012 12:04:41 -0800 Subject: [PATCH 26/26] iwlwifi: enable receiving beacons when not associated If the firmware implements beacon filtering, beacons are filtered when not associated. This causes association failures on channels marked passive. Enabling this flag indicates to the firmware to allow the beacons to pass through when not associated only. Signed-off-by: Meenakshi Venkataraman Signed-off-by: Wey-Yi Guy --- drivers/net/wireless/iwlwifi/iwl-agn-rxon.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c index 8ca9570ec365..35dd7e364b46 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c @@ -900,6 +900,22 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw, } } + /* + * If the ucode decides to do beacon filtering before + * association, it will lose beacons that are needed + * before sending frames out on passive channels. This + * causes association failures on those channels. Enable + * receiving beacons in such cases. + */ + + if (vif->type == NL80211_IFTYPE_STATION) { + if (!bss_conf->assoc) + ctx->staging.filter_flags |= RXON_FILTER_BCON_AWARE_MSK; + else + ctx->staging.filter_flags &= + ~RXON_FILTER_BCON_AWARE_MSK; + } + if (force || memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging))) iwlagn_commit_rxon(priv, ctx);