From a042994dd377d86bff9446ee76151ceb6267c9ba Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 28 Nov 2011 16:47:15 -0500 Subject: [PATCH 1/7] cfg80211: fix race on init and driver registration There is a theoretical race that if hit will trigger a crash. The race is between when we issue the first regulatory hint, regulatory_hint_core(), gets processed by the workqueue and between when the first device gets registered to the wireless core. This is not easy to reproduce but it was easy to do so through the regulatory simulator I have been working on. This is a port of the fix I implemented there [1]. [1] https://github.com/mcgrof/regsim/commit/a246ccf81f059cb662eee288aa13100f631e4cc8 Cc: stable@vger.kernel.org Cc: Johannes Berg Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- net/wireless/reg.c | 43 +++++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 186b7f2a27b..0ec40715a67 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -55,8 +55,17 @@ #define REG_DBG_PRINT(args...) #endif +static struct regulatory_request core_request_world = { + .initiator = NL80211_REGDOM_SET_BY_CORE, + .alpha2[0] = '0', + .alpha2[1] = '0', + .intersect = false, + .processed = true, + .country_ie_env = ENVIRON_ANY, +}; + /* Receipt of information from last regulatory request */ -static struct regulatory_request *last_request; +static struct regulatory_request *last_request = &core_request_world; /* To trigger userspace events */ static struct platform_device *reg_pdev; @@ -148,7 +157,7 @@ static char user_alpha2[2]; module_param(ieee80211_regdom, charp, 0444); MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code"); -static void reset_regdomains(void) +static void reset_regdomains(bool full_reset) { /* avoid freeing static information or freeing something twice */ if (cfg80211_regdomain == cfg80211_world_regdom) @@ -163,6 +172,13 @@ static void reset_regdomains(void) cfg80211_world_regdom = &world_regdom; cfg80211_regdomain = NULL; + + if (!full_reset) + return; + + if (last_request != &core_request_world) + kfree(last_request); + last_request = &core_request_world; } /* @@ -173,7 +189,7 @@ static void update_world_regdomain(const struct ieee80211_regdomain *rd) { BUG_ON(!last_request); - reset_regdomains(); + reset_regdomains(false); cfg80211_world_regdom = rd; cfg80211_regdomain = rd; @@ -1405,7 +1421,8 @@ static int __regulatory_hint(struct wiphy *wiphy, } new_request: - kfree(last_request); + if (last_request != &core_request_world) + kfree(last_request); last_request = pending_request; last_request->intersect = intersect; @@ -1575,9 +1592,6 @@ static int regulatory_hint_core(const char *alpha2) { struct regulatory_request *request; - kfree(last_request); - last_request = NULL; - request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL); if (!request) @@ -1775,7 +1789,7 @@ static void restore_regulatory_settings(bool reset_user) mutex_lock(&cfg80211_mutex); mutex_lock(®_mutex); - reset_regdomains(); + reset_regdomains(true); restore_alpha2(alpha2, reset_user); /* @@ -2044,7 +2058,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) int r; if (last_request->initiator != NL80211_REGDOM_SET_BY_DRIVER) { - reset_regdomains(); + reset_regdomains(false); cfg80211_regdomain = rd; return 0; } @@ -2065,7 +2079,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) if (r) return r; - reset_regdomains(); + reset_regdomains(false); cfg80211_regdomain = rd; return 0; } @@ -2090,7 +2104,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) rd = NULL; - reset_regdomains(); + reset_regdomains(false); cfg80211_regdomain = intersected_rd; return 0; @@ -2110,7 +2124,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) kfree(rd); rd = NULL; - reset_regdomains(); + reset_regdomains(false); cfg80211_regdomain = intersected_rd; return 0; @@ -2263,11 +2277,8 @@ void /* __init_or_exit */ regulatory_exit(void) mutex_lock(&cfg80211_mutex); mutex_lock(®_mutex); - reset_regdomains(); + reset_regdomains(true); - kfree(last_request); - - last_request = NULL; dev_set_uevent_suppress(®_pdev->dev, true); platform_device_unregister(reg_pdev); From 0bac71af6e66dc798bf07d0c0dd14ee5503362f9 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 28 Nov 2011 16:47:16 -0500 Subject: [PATCH 2/7] cfg80211: amend regulatory NULL dereference fix Johannes' patch for "cfg80211: fix regulatory NULL dereference" broke user regulaotry hints and it did not address the fact that last_request was left populated even if the previous regulatory hint was stale due to the wiphy disappearing. Fix user reguluatory hints by only bailing out if for those regulatory hints where a request_wiphy is expected. The stale last_request considerations are addressed through the previous fixes on last_request where we reset the last_request to a static world regdom request upon reset_regdomains(). In this case though we further enhance the effect by simply restoring reguluatory settings completely. Cc: stable@vger.kernel.org Cc: Johannes Berg Signed-off-by: Luis R. Rodriguez Reviewed-by: Johannes Berg Signed-off-by: John W. Linville --- net/wireless/reg.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 0ec40715a67..074c1122ce4 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -2049,8 +2049,10 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) } request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx); - if (!request_wiphy) { - reg_set_request_processed(); + if (!request_wiphy && + (last_request->initiator == NL80211_REGDOM_SET_BY_DRIVER || + last_request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE)) { + schedule_delayed_work(®_timeout, 0); return -ENODEV; } From c72e8d335e2c6a309b6281f2abcf491f37b8b92b Mon Sep 17 00:00:00 2001 From: Simon Wunderlich Date: Wed, 30 Nov 2011 16:56:30 +0100 Subject: [PATCH 3/7] mac80211: fill rate filter for internal scan requests The rates bitmap for internal scan requests shoud be filled, otherwise there will be probe requests with zero rates supported. Signed-off-by: Simon Wunderlich Signed-off-by: Mathias Kretschmer Cc: stable@vger.kernel.org Signed-off-by: John W. Linville --- net/mac80211/main.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/net/mac80211/main.c b/net/mac80211/main.c index d999bf3b84e..cae443563ec 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -757,6 +757,12 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) if (!local->int_scan_req) return -ENOMEM; + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + if (!local->hw.wiphy->bands[band]) + continue; + local->int_scan_req->rates[band] = (u32) -1; + } + /* if low-level driver supports AP, we also support VLAN */ if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_AP)) { hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP_VLAN); From 03360c5a405999d605ffc7373a7b90f3388db92e Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Thu, 1 Dec 2011 10:44:17 -0500 Subject: [PATCH 4/7] Revert "mac80211: clear sta.drv_priv on reconfiguration" This reverts commit f785d83a19bca326f79d127a413e35769afc0105. This was provoking WARNINGs from the iwlegacy drivers. Signed-off-by: John W. Linville --- net/mac80211/util.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 0c9490722aa..6719bce4a08 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1038,7 +1038,6 @@ int ieee80211_reconfig(struct ieee80211_local *local) struct ieee80211_sub_if_data, u.ap); - memset(&sta->sta.drv_priv, 0, hw->sta_data_size); WARN_ON(drv_sta_add(local, sdata, &sta->sta)); } } From 274b89ca3b006926cb9b45d78ab5906f4c0fc0aa Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 2 Dec 2011 08:19:17 -0800 Subject: [PATCH 5/7] iwlagn: fix HW crypto for TX-only keys Group keys in IBSS or AP mode are not programmed into the device since we give the key to it with every TX packet. However, we do need mac80211 to create the MMIC & PN in all cases. Move the code around to set the key flags all the time. We set them even when the key is removed again but that is obviously harmless. Cc: stable@vger.kernel.org Reported-by: Reinette Chatre Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-sta.c | 5 ----- drivers/net/wireless/iwlwifi/iwl-agn.c | 11 +++++++++++ 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c index ed628362393..4b2aa1da095 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c @@ -1268,9 +1268,6 @@ int iwl_set_dynamic_key(struct iwl_priv *priv, switch (keyconf->cipher) { case WLAN_CIPHER_SUITE_TKIP: - keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; - keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; - if (sta) addr = sta->addr; else /* station mode case only */ @@ -1283,8 +1280,6 @@ int iwl_set_dynamic_key(struct iwl_priv *priv, seq.tkip.iv32, p1k, CMD_SYNC); break; case WLAN_CIPHER_SUITE_CCMP: - keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; - /* fall through */ case WLAN_CIPHER_SUITE_WEP40: case WLAN_CIPHER_SUITE_WEP104: ret = iwlagn_send_sta_key(priv, keyconf, sta_id, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index ccba69b7f8a..6094deab510 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2316,6 +2316,17 @@ static int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, return -EOPNOTSUPP; } + switch (key->cipher) { + case WLAN_CIPHER_SUITE_TKIP: + key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; + /* fall through */ + case WLAN_CIPHER_SUITE_CCMP: + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + break; + default: + break; + } + /* * We could program these keys into the hardware as well, but we * don't expect much multicast traffic in IBSS and having keys From 34a5b4b6af104cf18eb50748509528b9bdbc4036 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 2 Dec 2011 08:19:18 -0800 Subject: [PATCH 6/7] iwlwifi: do not re-configure HT40 after associated The ht40 setting should not change after association unless channel switch This fix a problem we are seeing which cause uCode assert because driver sending invalid information and make uCode confuse Here is the firmware assert message: kernel: iwlagn 0000:03:00.0: Microcode SW error detected. Restarting 0x82000000. kernel: iwlagn 0000:03:00.0: Loaded firmware version: 17.168.5.3 build 42301 kernel: iwlagn 0000:03:00.0: Start IWL Error Log Dump: kernel: iwlagn 0000:03:00.0: Status: 0x000512E4, count: 6 kernel: iwlagn 0000:03:00.0: 0x00002078 | ADVANCED_SYSASSERT kernel: iwlagn 0000:03:00.0: 0x00009514 | uPc kernel: iwlagn 0000:03:00.0: 0x00009496 | branchlink1 kernel: iwlagn 0000:03:00.0: 0x00009496 | branchlink2 kernel: iwlagn 0000:03:00.0: 0x0000D1F2 | interruptlink1 kernel: iwlagn 0000:03:00.0: 0x00000000 | interruptlink2 kernel: iwlagn 0000:03:00.0: 0x01008035 | data1 kernel: iwlagn 0000:03:00.0: 0x0000C90F | data2 kernel: iwlagn 0000:03:00.0: 0x000005A7 | line kernel: iwlagn 0000:03:00.0: 0x5080B520 | beacon time kernel: iwlagn 0000:03:00.0: 0xCC515AE0 | tsf low kernel: iwlagn 0000:03:00.0: 0x00000003 | tsf hi kernel: iwlagn 0000:03:00.0: 0x00000000 | time gp1 kernel: iwlagn 0000:03:00.0: 0x29703BF0 | time gp2 kernel: iwlagn 0000:03:00.0: 0x00000000 | time gp3 kernel: iwlagn 0000:03:00.0: 0x000111A8 | uCode version kernel: iwlagn 0000:03:00.0: 0x000000B0 | hw version kernel: iwlagn 0000:03:00.0: 0x00480303 | board version kernel: iwlagn 0000:03:00.0: 0x09E8004E | hcmd kernel: iwlagn 0000:03:00.0: CSR values: kernel: iwlagn 0000:03:00.0: (2nd byte of CSR_INT_COALESCING is CSR_INT_PERIODIC_REG) kernel: iwlagn 0000:03:00.0: CSR_HW_IF_CONFIG_REG: 0X00480303 kernel: iwlagn 0000:03:00.0: CSR_INT_COALESCING: 0X0000ff40 kernel: iwlagn 0000:03:00.0: CSR_INT: 0X00000000 kernel: iwlagn 0000:03:00.0: CSR_INT_MASK: 0X00000000 kernel: iwlagn 0000:03:00.0: CSR_FH_INT_STATUS: 0X00000000 kernel: iwlagn 0000:03:00.0: CSR_GPIO_IN: 0X00000030 kernel: iwlagn 0000:03:00.0: CSR_RESET: 0X00000000 kernel: iwlagn 0000:03:00.0: CSR_GP_CNTRL: 0X080403c5 kernel: iwlagn 0000:03:00.0: CSR_HW_REV: 0X000000b0 kernel: iwlagn 0000:03:00.0: CSR_EEPROM_REG: 0X07d60ffd kernel: iwlagn 0000:03:00.0: CSR_EEPROM_GP: 0X90000001 kernel: iwlagn 0000:03:00.0: CSR_OTP_GP_REG: 0X00030001 kernel: iwlagn 0000:03:00.0: CSR_GIO_REG: 0X00080044 kernel: iwlagn 0000:03:00.0: CSR_GP_UCODE_REG: 0X000093bb kernel: iwlagn 0000:03:00.0: CSR_GP_DRIVER_REG: 0X00000000 kernel: iwlagn 0000:03:00.0: CSR_UCODE_DRV_GP1: 0X00000000 kernel: iwlagn 0000:03:00.0: CSR_UCODE_DRV_GP2: 0X00000000 kernel: iwlagn 0000:03:00.0: CSR_LED_REG: 0X00000078 kernel: iwlagn 0000:03:00.0: CSR_DRAM_INT_TBL_REG: 0X88214dd2 kernel: iwlagn 0000:03:00.0: CSR_GIO_CHICKEN_BITS: 0X27800200 kernel: iwlagn 0000:03:00.0: CSR_ANA_PLL_CFG: 0X00000000 kernel: iwlagn 0000:03:00.0: CSR_HW_REV_WA_REG: 0X0001001a kernel: iwlagn 0000:03:00.0: CSR_DBG_HPET_MEM_REG: 0Xffff0010 kernel: iwlagn 0000:03:00.0: FH register values: kernel: iwlagn 0000:03:00.0: FH_RSCSR_CHNL0_STTS_WPTR_REG: 0X21316d00 kernel: iwlagn 0000:03:00.0: FH_RSCSR_CHNL0_RBDCB_BASE_REG: 0X021479c0 kernel: iwlagn 0000:03:00.0: FH_RSCSR_CHNL0_WPTR: 0X00000060 kernel: iwlagn 0000:03:00.0: FH_MEM_RCSR_CHNL0_CONFIG_REG: 0X80819104 kernel: iwlagn 0000:03:00.0: FH_MEM_RSSR_SHARED_CTRL_REG: 0X000000fc kernel: iwlagn 0000:03:00.0: FH_MEM_RSSR_RX_STATUS_REG: 0X07030000 kernel: iwlagn 0000:03:00.0: FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV: 0X00000000 kernel: iwlagn 0000:03:00.0: FH_TSSR_TX_STATUS_REG: 0X07ff0001 kernel: iwlagn 0000:03:00.0: FH_TSSR_TX_ERROR_REG: 0X00000000 kernel: iwlagn 0000:03:00.0: Start IWL Event Log Dump: display last 20 entries kernel: ------------[ cut here ]------------ WARNING: at net/mac80211/util.c:1208 ieee80211_reconfig+0x1f1/0x407() kernel: Hardware name: 4290W4H kernel: Pid: 1896, comm: kworker/0:0 Not tainted 3.1.0 #2 kernel: Call Trace: kernel: [] ? warn_slowpath_common+0x73/0x87 kernel: [] ? ieee80211_reconfig+0x1f1/0x407 kernel: [] ? ieee80211_recalc_smps_work+0x32/0x32 kernel: [] ? ieee80211_restart_work+0x7e/0x87 kernel: [] ? process_one_work+0x1c8/0x2e3 kernel: [] ? worker_thread+0x17a/0x23a kernel: [] ? manage_workers.clone.18+0x15b/0x15b kernel: [] ? manage_workers.clone.18+0x15b/0x15b kernel: [] ? kthread+0x7a/0x82 kernel: [] ? kernel_thread_helper+0x4/0x10 kernel: [] ? kthread_flush_work_fn+0x11/0x11 kernel: [] ? gs_change+0xb/0xb Cc: 3.1+ Reported-by: Udo Steinberg Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-rxon.c | 36 +++++++++++++-------- drivers/net/wireless/iwlwifi/iwl-agn.c | 18 ++--------- drivers/net/wireless/iwlwifi/iwl-agn.h | 2 ++ 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c index 58a381c01c8..a7a6def40d0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c @@ -528,6 +528,24 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) return 0; } +void iwlagn_config_ht40(struct ieee80211_conf *conf, + struct iwl_rxon_context *ctx) +{ + if (conf_is_ht40_minus(conf)) { + ctx->ht.extension_chan_offset = + IEEE80211_HT_PARAM_CHA_SEC_BELOW; + ctx->ht.is_40mhz = true; + } else if (conf_is_ht40_plus(conf)) { + ctx->ht.extension_chan_offset = + IEEE80211_HT_PARAM_CHA_SEC_ABOVE; + ctx->ht.is_40mhz = true; + } else { + ctx->ht.extension_chan_offset = + IEEE80211_HT_PARAM_CHA_SEC_NONE; + ctx->ht.is_40mhz = false; + } +} + int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed) { struct iwl_priv *priv = hw->priv; @@ -586,19 +604,11 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed) ctx->ht.enabled = conf_is_ht(conf); if (ctx->ht.enabled) { - if (conf_is_ht40_minus(conf)) { - ctx->ht.extension_chan_offset = - IEEE80211_HT_PARAM_CHA_SEC_BELOW; - ctx->ht.is_40mhz = true; - } else if (conf_is_ht40_plus(conf)) { - ctx->ht.extension_chan_offset = - IEEE80211_HT_PARAM_CHA_SEC_ABOVE; - ctx->ht.is_40mhz = true; - } else { - ctx->ht.extension_chan_offset = - IEEE80211_HT_PARAM_CHA_SEC_NONE; - ctx->ht.is_40mhz = false; - } + /* if HT40 is used, it should not change + * after associated except channel switch */ + if (iwl_is_associated_ctx(ctx) && + !ctx->ht.is_40mhz) + iwlagn_config_ht40(conf, ctx); } else ctx->ht.is_40mhz = false; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 6094deab510..f5564514868 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2610,21 +2610,9 @@ static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, /* Configure HT40 channels */ ctx->ht.enabled = conf_is_ht(conf); - if (ctx->ht.enabled) { - if (conf_is_ht40_minus(conf)) { - ctx->ht.extension_chan_offset = - IEEE80211_HT_PARAM_CHA_SEC_BELOW; - ctx->ht.is_40mhz = true; - } else if (conf_is_ht40_plus(conf)) { - ctx->ht.extension_chan_offset = - IEEE80211_HT_PARAM_CHA_SEC_ABOVE; - ctx->ht.is_40mhz = true; - } else { - ctx->ht.extension_chan_offset = - IEEE80211_HT_PARAM_CHA_SEC_NONE; - ctx->ht.is_40mhz = false; - } - } else + if (ctx->ht.enabled) + iwlagn_config_ht40(conf, ctx); + else ctx->ht.is_40mhz = false; if ((le16_to_cpu(ctx->staging.channel) != ch)) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index 5b936ec1a54..3856abaea50 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h @@ -86,6 +86,8 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, u32 changes); +void iwlagn_config_ht40(struct ieee80211_conf *conf, + struct iwl_rxon_context *ctx); /* uCode */ int iwlagn_rx_calib_result(struct iwl_priv *priv, From 9995ffe5f5fdddcc73e4465cc3f8b38714df8108 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 2 Dec 2011 08:19:19 -0800 Subject: [PATCH 7/7] iwlwifi: change the default behavior of watchdog timer The current default watchdog timer is enabled, but we are seeing issues on legacy devices. So change the default setting of watchdog timer to per device based. But user still can use the "wd_disable" module parameter to overwrite the system setting Cc: stable@vger.kernel.org #3.0+ Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-1000.c | 1 + drivers/net/wireless/iwlwifi/iwl-5000.c | 1 + drivers/net/wireless/iwlwifi/iwl-agn.c | 5 +++-- drivers/net/wireless/iwlwifi/iwl-core.c | 22 +++++++++++++++++----- drivers/net/wireless/iwlwifi/iwl-core.h | 2 ++ drivers/net/wireless/iwlwifi/iwl-shared.h | 4 ++-- 6 files changed, 26 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index e12b48c2cff..dd008b0e641 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -191,6 +191,7 @@ static struct iwl_base_params iwl1000_base_params = { .chain_noise_scale = 1000, .wd_timeout = IWL_DEF_WD_TIMEOUT, .max_event_log_size = 128, + .wd_disable = true, }; static struct iwl_ht_params iwl1000_ht_params = { .ht_greenfield_support = true, diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index c511c98a89a..f55fb2d1af5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -364,6 +364,7 @@ static struct iwl_base_params iwl5000_base_params = { .wd_timeout = IWL_LONG_WD_TIMEOUT, .max_event_log_size = 512, .no_idle_support = true, + .wd_disable = true, }; static struct iwl_ht_params iwl5000_ht_params = { .ht_greenfield_support = true, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index f5564514868..bacc06c95e7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -3498,9 +3498,10 @@ MODULE_PARM_DESC(plcp_check, "Check plcp health (default: 1 [enabled])"); module_param_named(ack_check, iwlagn_mod_params.ack_check, bool, S_IRUGO); MODULE_PARM_DESC(ack_check, "Check ack health (default: 0 [disabled])"); -module_param_named(wd_disable, iwlagn_mod_params.wd_disable, bool, S_IRUGO); +module_param_named(wd_disable, iwlagn_mod_params.wd_disable, int, S_IRUGO); MODULE_PARM_DESC(wd_disable, - "Disable stuck queue watchdog timer (default: 0 [enabled])"); + "Disable stuck queue watchdog timer 0=system default, " + "1=disable, 2=enable (default: 0)"); /* * set bt_coex_active to true, uCode will do kill/defer diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 001fdf140ab..fcf54160e4e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1810,11 +1810,23 @@ void iwl_setup_watchdog(struct iwl_priv *priv) { unsigned int timeout = priv->cfg->base_params->wd_timeout; - if (timeout && !iwlagn_mod_params.wd_disable) - mod_timer(&priv->watchdog, - jiffies + msecs_to_jiffies(IWL_WD_TICK(timeout))); - else - del_timer(&priv->watchdog); + if (!iwlagn_mod_params.wd_disable) { + /* use system default */ + if (timeout && !priv->cfg->base_params->wd_disable) + mod_timer(&priv->watchdog, + jiffies + + msecs_to_jiffies(IWL_WD_TICK(timeout))); + else + del_timer(&priv->watchdog); + } else { + /* module parameter overwrite default configuration */ + if (timeout && iwlagn_mod_params.wd_disable == 2) + mod_timer(&priv->watchdog, + jiffies + + msecs_to_jiffies(IWL_WD_TICK(timeout))); + else + del_timer(&priv->watchdog); + } } /** diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 137da338070..f2fc288f3dd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -113,6 +113,7 @@ struct iwl_lib_ops { * @shadow_reg_enable: HW shadhow register bit * @no_idle_support: do not support idle mode * @hd_v2: v2 of enhanced sensitivity value, used for 2000 series and up + * wd_disable: disable watchdog timer */ struct iwl_base_params { int eeprom_size; @@ -134,6 +135,7 @@ struct iwl_base_params { const bool shadow_reg_enable; const bool no_idle_support; const bool hd_v2; + const bool wd_disable; }; /* * @advanced_bt_coexist: support advanced bt coexist diff --git a/drivers/net/wireless/iwlwifi/iwl-shared.h b/drivers/net/wireless/iwlwifi/iwl-shared.h index 1f7a93c67c4..14eaf37ce3b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-shared.h +++ b/drivers/net/wireless/iwlwifi/iwl-shared.h @@ -120,7 +120,7 @@ extern struct iwl_mod_params iwlagn_mod_params; * @restart_fw: restart firmware, default = 1 * @plcp_check: enable plcp health check, default = true * @ack_check: disable ack health check, default = false - * @wd_disable: enable stuck queue check, default = false + * @wd_disable: enable stuck queue check, default = 0 * @bt_coex_active: enable bt coex, default = true * @led_mode: system default, default = 0 * @no_sleep_autoadjust: disable autoadjust, default = true @@ -141,7 +141,7 @@ struct iwl_mod_params { int restart_fw; bool plcp_check; bool ack_check; - bool wd_disable; + int wd_disable; bool bt_coex_active; int led_mode; bool no_sleep_autoadjust;