From 8a03447dd311da2ad2df74dcf730a1a15f673379 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Mon, 6 May 2019 09:39:17 +0200 Subject: rtw88: fix subscript above array bounds compiler warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit My compiler complains about: drivers/net/wireless/realtek/rtw88/phy.c: In function ‘rtw_phy_rf_power_2_rssi’: drivers/net/wireless/realtek/rtw88/phy.c:430:26: warning: array subscript is above array bounds [-Warray-bounds] linear = db_invert_table[i][j]; According to comment power_db should be in range 1 ~ 96 . To fix add check for boundaries before access the array. Signed-off-by: Stanislaw Gruszka Acked-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/phy.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/phy.c b/drivers/net/wireless/realtek/rtw88/phy.c index 4381b360b5b5..8284a7797398 100644 --- a/drivers/net/wireless/realtek/rtw88/phy.c +++ b/drivers/net/wireless/realtek/rtw88/phy.c @@ -423,6 +423,11 @@ static u64 rtw_phy_db_2_linear(u8 power_db) u8 i, j; u64 linear; + if (power_db > 96) + power_db = 96; + else if (power_db < 1) + return 1; + /* 1dB ~ 96dB */ i = (power_db - 1) >> 3; j = (power_db - 1) - (i << 3); -- cgit v1.2.3 From a24bad74737f4c8814e0669d38dba5f2ddb86514 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Tue, 7 May 2019 10:28:18 +0800 Subject: rtw88: fix unassigned rssi_level in rtw_sta_info The new rssi_level should be stored in si, otherwise the rssi_level will never be updated and get a wrong RA mask, which is calculated by the rssi level If a wrong RA mask is chosen, the firmware will pick some *bad rates*. The most hurtful scene will be in *noisy environment*, such as office or public area with many APs and users. The latency would be high and the overall throughput would be only half or less. Tested in 2.4G in office area, with this patch the throughput increased from such as "1x Mbps -> 4x Mbps". Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/phy.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/phy.c b/drivers/net/wireless/realtek/rtw88/phy.c index 8284a7797398..77b8c02b5ac6 100644 --- a/drivers/net/wireless/realtek/rtw88/phy.c +++ b/drivers/net/wireless/realtek/rtw88/phy.c @@ -144,10 +144,10 @@ static void rtw_phy_stat_rssi_iter(void *data, struct ieee80211_sta *sta) struct rtw_phy_stat_iter_data *iter_data = data; struct rtw_dev *rtwdev = iter_data->rtwdev; struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv; - u8 rssi, rssi_level; + u8 rssi; rssi = ewma_rssi_read(&si->avg_rssi); - rssi_level = rtw_phy_get_rssi_level(si->rssi_level, rssi); + si->rssi_level = rtw_phy_get_rssi_level(si->rssi_level, rssi); rtw_fw_send_rssi_info(rtwdev, si); -- cgit v1.2.3 From f57b5d85ed5865f0cd0a6dc4726c995b9e57e28a Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Thu, 23 May 2019 08:30:08 -0700 Subject: rsi: Properly initialize data in rsi_sdio_ta_reset When building with -Wuninitialized, Clang warns: drivers/net/wireless/rsi/rsi_91x_sdio.c:940:43: warning: variable 'data' is uninitialized when used here [-Wuninitialized] put_unaligned_le32(TA_HOLD_THREAD_VALUE, data); ^~~~ drivers/net/wireless/rsi/rsi_91x_sdio.c:930:10: note: initialize the variable 'data' to silence this warning u8 *data; ^ = NULL 1 warning generated. Using Clang's suggestion of initializing data to NULL wouldn't work out because data will be dereferenced by put_unaligned_le32. Use kzalloc to properly initialize data, which matches a couple of other places in this driver. Fixes: e5a1ecc97e5f ("rsi: add firmware loading for 9116 device") Link: https://github.com/ClangBuiltLinux/linux/issues/464 Signed-off-by: Nathan Chancellor Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_sdio.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio.c b/drivers/net/wireless/rsi/rsi_91x_sdio.c index f9c67ed473d1..b42cd50b837e 100644 --- a/drivers/net/wireless/rsi/rsi_91x_sdio.c +++ b/drivers/net/wireless/rsi/rsi_91x_sdio.c @@ -929,11 +929,15 @@ static int rsi_sdio_ta_reset(struct rsi_hw *adapter) u32 addr; u8 *data; + data = kzalloc(RSI_9116_REG_SIZE, GFP_KERNEL); + if (!data) + return -ENOMEM; + status = rsi_sdio_master_access_msword(adapter, TA_BASE_ADDR); if (status < 0) { rsi_dbg(ERR_ZONE, "Unable to set ms word to common reg\n"); - return status; + goto err; } rsi_dbg(INIT_ZONE, "%s: Bring TA out of reset\n", __func__); @@ -944,7 +948,7 @@ static int rsi_sdio_ta_reset(struct rsi_hw *adapter) RSI_9116_REG_SIZE); if (status < 0) { rsi_dbg(ERR_ZONE, "Unable to hold TA threads\n"); - return status; + goto err; } put_unaligned_le32(TA_SOFT_RST_CLR, data); @@ -954,7 +958,7 @@ static int rsi_sdio_ta_reset(struct rsi_hw *adapter) RSI_9116_REG_SIZE); if (status < 0) { rsi_dbg(ERR_ZONE, "Unable to get TA out of reset\n"); - return status; + goto err; } put_unaligned_le32(TA_PC_ZERO, data); @@ -964,7 +968,8 @@ static int rsi_sdio_ta_reset(struct rsi_hw *adapter) RSI_9116_REG_SIZE); if (status < 0) { rsi_dbg(ERR_ZONE, "Unable to Reset TA PC value\n"); - return -EINVAL; + status = -EINVAL; + goto err; } put_unaligned_le32(TA_RELEASE_THREAD_VALUE, data); @@ -974,17 +979,19 @@ static int rsi_sdio_ta_reset(struct rsi_hw *adapter) RSI_9116_REG_SIZE); if (status < 0) { rsi_dbg(ERR_ZONE, "Unable to release TA threads\n"); - return status; + goto err; } status = rsi_sdio_master_access_msword(adapter, MISC_CFG_BASE_ADDR); if (status < 0) { rsi_dbg(ERR_ZONE, "Unable to set ms word to common reg\n"); - return status; + goto err; } rsi_dbg(INIT_ZONE, "***** TA Reset done *****\n"); - return 0; +err: + kfree(data); + return status; } static struct rsi_host_intf_ops sdio_host_intf_ops = { -- cgit v1.2.3 From 5b0efb4d670c8b53b25c166967efd2a02b309e05 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Fri, 3 May 2019 14:29:07 +0200 Subject: rtw88: avoid circular locking between local->iflist_mtx and rtwdev->mutex Remove circular lock dependency by using atomic version of interfaces iterate in watch_dog_work(), hence avoid taking local->iflist_mtx (rtw_vif_watch_dog_iter() only update some data, it can be called from atomic context). Fixes below LOCKDEP warning: [ 1157.219415] ====================================================== [ 1157.225772] [ INFO: possible circular locking dependency detected ] [ 1157.232150] 3.10.0-1043.el7.sgruszka1.x86_64.debug #1 Not tainted [ 1157.238346] ------------------------------------------------------- [ 1157.244635] kworker/u4:2/14490 is trying to acquire lock: [ 1157.250194] (&rtwdev->mutex){+.+.+.}, at: [] rtw_ops_config+0x2b/0x90 [rtw88] [ 1157.259151] but task is already holding lock: [ 1157.265085] (&local->iflist_mtx){+.+...}, at: [] ieee80211_mgd_probe_ap.part.28+0xca/0x160 [mac80211] [ 1157.276169] which lock already depends on the new lock. [ 1157.284488] the existing dependency chain (in reverse order) is: [ 1157.292101] -> #2 (&local->iflist_mtx){+.+...}: [ 1157.296919] [] lock_acquire+0x99/0x1e0 [ 1157.302955] [] mutex_lock_nested+0x93/0x410 [ 1157.309416] [] ieee80211_iterate_interfaces+0x2f/0x60 [mac80211] [ 1157.317730] [] rtw_watch_dog_work+0xcb/0x130 [rtw88] [ 1157.325003] [] process_one_work+0x22c/0x720 [ 1157.331481] [] worker_thread+0x126/0x3b0 [ 1157.337589] [] kthread+0xef/0x100 [ 1157.343260] [] ret_from_fork_nospec_end+0x0/0x39 [ 1157.350091] -> #1 ((&(&rtwdev->watch_dog_work)->work)){+.+...}: [ 1157.356314] [] lock_acquire+0x99/0x1e0 [ 1157.362427] [] flush_work+0x5b/0x310 [ 1157.368287] [] __cancel_work_timer+0xae/0x170 [ 1157.374940] [] cancel_delayed_work_sync+0x13/0x20 [ 1157.381930] [] rtw_core_stop+0x29/0x50 [rtw88] [ 1157.388679] [] rtw_enter_ips+0x16/0x20 [rtw88] [ 1157.395428] [] rtw_ops_config+0x42/0x90 [rtw88] [ 1157.402173] [] ieee80211_hw_config+0xc3/0x680 [mac80211] [ 1157.409854] [] ieee80211_do_open+0x69b/0x9c0 [mac80211] [ 1157.417418] [] ieee80211_open+0x69/0x70 [mac80211] [ 1157.424496] [] __dev_open+0xe2/0x160 [ 1157.430356] [] __dev_change_flags+0xa3/0x180 [ 1157.436922] [] dev_change_flags+0x29/0x60 [ 1157.443224] [] devinet_ioctl+0x794/0x890 [ 1157.449331] [] inet_ioctl+0x75/0xa0 [ 1157.455087] [] sock_do_ioctl+0x2b/0x60 [ 1157.461178] [] sock_ioctl+0x233/0x310 [ 1157.467109] [] do_vfs_ioctl+0x410/0x6c0 [ 1157.473233] [] SyS_ioctl+0xa1/0xc0 [ 1157.478914] [] system_call_fastpath+0x25/0x2a [ 1157.485569] -> #0 (&rtwdev->mutex){+.+.+.}: [ 1157.490022] [] __lock_acquire+0xec1/0x1630 [ 1157.496305] [] lock_acquire+0x99/0x1e0 [ 1157.502413] [] mutex_lock_nested+0x93/0x410 [ 1157.508890] [] rtw_ops_config+0x2b/0x90 [rtw88] [ 1157.515724] [] ieee80211_hw_config+0xc3/0x680 [mac80211] [ 1157.523370] [] ieee80211_recalc_ps.part.27+0x9a/0x180 [mac80211] [ 1157.531685] [] ieee80211_mgd_probe_ap.part.28+0x115/0x160 [mac80211] [ 1157.540353] [] ieee80211_beacon_connection_loss_work+0x4d/0x80 [mac80211] [ 1157.549513] [] process_one_work+0x22c/0x720 [ 1157.555886] [] worker_thread+0x126/0x3b0 [ 1157.562170] [] kthread+0xef/0x100 [ 1157.567765] [] ret_from_fork_nospec_end+0x0/0x39 [ 1157.574579] other info that might help us debug this: [ 1157.582788] Chain exists of: &rtwdev->mutex --> (&(&rtwdev->watch_dog_work)->work) --> &local->iflist_mtx [ 1157.593024] Possible unsafe locking scenario: [ 1157.599046] CPU0 CPU1 [ 1157.603653] ---- ---- [ 1157.608258] lock(&local->iflist_mtx); [ 1157.612180] lock((&(&rtwdev->watch_dog_work)->work)); [ 1157.620074] lock(&local->iflist_mtx); [ 1157.626555] lock(&rtwdev->mutex); [ 1157.630124] *** DEADLOCK *** [ 1157.636148] 4 locks held by kworker/u4:2/14490: [ 1157.640755] #0: (%s#6){.+.+.+}, at: [] process_one_work+0x1ba/0x720 [ 1157.648965] #1: ((&ifmgd->beacon_connection_loss_work)){+.+.+.}, at: [] process_one_work+0x1ba/0x720 [ 1157.659950] #2: (&wdev->mtx){+.+.+.}, at: [] ieee80211_mgd_probe_ap.part.28+0x25/0x160 [mac80211] [ 1157.670901] #3: (&local->iflist_mtx){+.+...}, at: [] ieee80211_mgd_probe_ap.part.28+0xca/0x160 [mac80211] [ 1157.682466] Fixes: e3037485c68e ("rtw88: new Realtek 802.11ac driver") Signed-off-by: Stanislaw Gruszka Acked-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index f447361f7573..b2dac4609138 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -162,7 +162,8 @@ static void rtw_watch_dog_work(struct work_struct *work) rtwdev->stats.tx_cnt = 0; rtwdev->stats.rx_cnt = 0; - rtw_iterate_vifs(rtwdev, rtw_vif_watch_dog_iter, &data); + /* use atomic version to avoid taking local->iflist_mtx mutex */ + rtw_iterate_vifs_atomic(rtwdev, rtw_vif_watch_dog_iter, &data); /* fw supports only one station associated to enter lps, if there are * more than two stations associated to the AP, then we can not enter -- cgit v1.2.3 From 6aca09771db4277a78853d6ac680d8d5f0d915e3 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sat, 4 May 2019 18:32:24 +0800 Subject: rtw88: Make some symbols static Fix sparse warnings: drivers/net/wireless/realtek/rtw88/phy.c:851:4: warning: symbol 'rtw_cck_size' was not declared. Should it be static? drivers/net/wireless/realtek/rtw88/phy.c:852:4: warning: symbol 'rtw_ofdm_size' was not declared. Should it be static? drivers/net/wireless/realtek/rtw88/phy.c:853:4: warning: symbol 'rtw_ht_1s_size' was not declared. Should it be static? drivers/net/wireless/realtek/rtw88/phy.c:854:4: warning: symbol 'rtw_ht_2s_size' was not declared. Should it be static? drivers/net/wireless/realtek/rtw88/phy.c:855:4: warning: symbol 'rtw_vht_1s_size' was not declared. Should it be static? drivers/net/wireless/realtek/rtw88/phy.c:856:4: warning: symbol 'rtw_vht_2s_size' was not declared. Should it be static? drivers/net/wireless/realtek/rtw88/fw.c:11:6: warning: symbol 'rtw_fw_c2h_cmd_handle_ext' was not declared. Should it be static? drivers/net/wireless/realtek/rtw88/fw.c:50:6: warning: symbol 'rtw_fw_send_h2c_command' was not declared. Should it be static? Reported-by: Hulk Robot Signed-off-by: YueHaibing Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/fw.c | 6 ++++-- drivers/net/wireless/realtek/rtw88/phy.c | 13 +++++++------ 2 files changed, 11 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/fw.c b/drivers/net/wireless/realtek/rtw88/fw.c index cf4265cda224..628477971213 100644 --- a/drivers/net/wireless/realtek/rtw88/fw.c +++ b/drivers/net/wireless/realtek/rtw88/fw.c @@ -8,7 +8,8 @@ #include "reg.h" #include "debug.h" -void rtw_fw_c2h_cmd_handle_ext(struct rtw_dev *rtwdev, struct sk_buff *skb) +static void rtw_fw_c2h_cmd_handle_ext(struct rtw_dev *rtwdev, + struct sk_buff *skb) { struct rtw_c2h_cmd *c2h; u8 sub_cmd_id; @@ -47,7 +48,8 @@ void rtw_fw_c2h_cmd_handle(struct rtw_dev *rtwdev, struct sk_buff *skb) } } -void rtw_fw_send_h2c_command(struct rtw_dev *rtwdev, u8 *h2c) +static void rtw_fw_send_h2c_command(struct rtw_dev *rtwdev, + u8 *h2c) { u8 box; u8 box_state; diff --git a/drivers/net/wireless/realtek/rtw88/phy.c b/drivers/net/wireless/realtek/rtw88/phy.c index 77b8c02b5ac6..404d89432c96 100644 --- a/drivers/net/wireless/realtek/rtw88/phy.c +++ b/drivers/net/wireless/realtek/rtw88/phy.c @@ -853,12 +853,13 @@ u8 rtw_vht_2s_rates[] = { DESC_RATEVHT2SS_MCS6, DESC_RATEVHT2SS_MCS7, DESC_RATEVHT2SS_MCS8, DESC_RATEVHT2SS_MCS9 }; -u8 rtw_cck_size = ARRAY_SIZE(rtw_cck_rates); -u8 rtw_ofdm_size = ARRAY_SIZE(rtw_ofdm_rates); -u8 rtw_ht_1s_size = ARRAY_SIZE(rtw_ht_1s_rates); -u8 rtw_ht_2s_size = ARRAY_SIZE(rtw_ht_2s_rates); -u8 rtw_vht_1s_size = ARRAY_SIZE(rtw_vht_1s_rates); -u8 rtw_vht_2s_size = ARRAY_SIZE(rtw_vht_2s_rates); + +static u8 rtw_cck_size = ARRAY_SIZE(rtw_cck_rates); +static u8 rtw_ofdm_size = ARRAY_SIZE(rtw_ofdm_rates); +static u8 rtw_ht_1s_size = ARRAY_SIZE(rtw_ht_1s_rates); +static u8 rtw_ht_2s_size = ARRAY_SIZE(rtw_ht_2s_rates); +static u8 rtw_vht_1s_size = ARRAY_SIZE(rtw_vht_1s_rates); +static u8 rtw_vht_2s_size = ARRAY_SIZE(rtw_vht_2s_rates); u8 *rtw_rate_section[RTW_RATE_SECTION_MAX] = { rtw_cck_rates, rtw_ofdm_rates, rtw_ht_1s_rates, rtw_ht_2s_rates, -- cgit v1.2.3 From 13ec7f10b87f5fc04c4ccbd491c94c7980236a74 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 29 May 2019 14:52:19 +0200 Subject: mwifiex: Fix possible buffer overflows at parsing bss descriptor mwifiex_update_bss_desc_with_ie() calls memcpy() unconditionally in a couple places without checking the destination size. Since the source is given from user-space, this may trigger a heap buffer overflow. Fix it by putting the length check before performing memcpy(). This fix addresses CVE-2019-3846. Reported-by: huangwen Signed-off-by: Takashi Iwai Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/scan.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/marvell/mwifiex/scan.c b/drivers/net/wireless/marvell/mwifiex/scan.c index 935778ec9a1b..64ab6fe78c0d 100644 --- a/drivers/net/wireless/marvell/mwifiex/scan.c +++ b/drivers/net/wireless/marvell/mwifiex/scan.c @@ -1247,6 +1247,8 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter, } switch (element_id) { case WLAN_EID_SSID: + if (element_len > IEEE80211_MAX_SSID_LEN) + return -EINVAL; bss_entry->ssid.ssid_len = element_len; memcpy(bss_entry->ssid.ssid, (current_ptr + 2), element_len); @@ -1256,6 +1258,8 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter, break; case WLAN_EID_SUPP_RATES: + if (element_len > MWIFIEX_SUPPORTED_RATES) + return -EINVAL; memcpy(bss_entry->data_rates, current_ptr + 2, element_len); memcpy(bss_entry->supported_rates, current_ptr + 2, -- cgit v1.2.3 From 685c9b7750bfacd6fc1db50d86579980593b7869 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 29 May 2019 14:52:20 +0200 Subject: mwifiex: Abort at too short BSS descriptor element Currently mwifiex_update_bss_desc_with_ie() implicitly assumes that the source descriptor entries contain the enough size for each type and performs copying without checking the source size. This may lead to read over boundary. Fix this by putting the source size check in appropriate places. Signed-off-by: Takashi Iwai Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/scan.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/marvell/mwifiex/scan.c b/drivers/net/wireless/marvell/mwifiex/scan.c index 64ab6fe78c0d..c269a0de9413 100644 --- a/drivers/net/wireless/marvell/mwifiex/scan.c +++ b/drivers/net/wireless/marvell/mwifiex/scan.c @@ -1269,6 +1269,8 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter, break; case WLAN_EID_FH_PARAMS: + if (element_len + 2 < sizeof(*fh_param_set)) + return -EINVAL; fh_param_set = (struct ieee_types_fh_param_set *) current_ptr; memcpy(&bss_entry->phy_param_set.fh_param_set, @@ -1277,6 +1279,8 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter, break; case WLAN_EID_DS_PARAMS: + if (element_len + 2 < sizeof(*ds_param_set)) + return -EINVAL; ds_param_set = (struct ieee_types_ds_param_set *) current_ptr; @@ -1288,6 +1292,8 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter, break; case WLAN_EID_CF_PARAMS: + if (element_len + 2 < sizeof(*cf_param_set)) + return -EINVAL; cf_param_set = (struct ieee_types_cf_param_set *) current_ptr; memcpy(&bss_entry->ss_param_set.cf_param_set, @@ -1296,6 +1302,8 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter, break; case WLAN_EID_IBSS_PARAMS: + if (element_len + 2 < sizeof(*ibss_param_set)) + return -EINVAL; ibss_param_set = (struct ieee_types_ibss_param_set *) current_ptr; @@ -1305,10 +1313,14 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter, break; case WLAN_EID_ERP_INFO: + if (!element_len) + return -EINVAL; bss_entry->erp_flags = *(current_ptr + 2); break; case WLAN_EID_PWR_CONSTRAINT: + if (!element_len) + return -EINVAL; bss_entry->local_constraint = *(current_ptr + 2); bss_entry->sensed_11h = true; break; @@ -1349,6 +1361,9 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter, break; case WLAN_EID_VENDOR_SPECIFIC: + if (element_len + 2 < sizeof(vendor_ie->vend_hdr)) + return -EINVAL; + vendor_ie = (struct ieee_types_vendor_specific *) current_ptr; -- cgit v1.2.3 From 23f57bfac7c283746ffba5caf4046b152074b2d9 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 29 May 2019 16:39:49 +0300 Subject: iwlwifi: mvm: remove d3_sram debugfs file This debugfs file is really old, and cannot work properly since the unified image support. Rather than trying to make it work, which is difficult now due to multiple images (LMAC/UMAC etc.) just remove it - we no longer need it since we properly do a FW coredump even in D3 cases. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Signed-off-by: Kalle Valo --- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 22 --------- drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c | 57 ------------------------ drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 2 - drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 3 -- 4 files changed, 84 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 60f5d337f16d..e7e68fb2bd29 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -1972,26 +1972,6 @@ out: } } -static void iwl_mvm_read_d3_sram(struct iwl_mvm *mvm) -{ -#ifdef CONFIG_IWLWIFI_DEBUGFS - const struct fw_img *img = &mvm->fw->img[IWL_UCODE_WOWLAN]; - u32 len = img->sec[IWL_UCODE_SECTION_DATA].len; - u32 offs = img->sec[IWL_UCODE_SECTION_DATA].offset; - - if (!mvm->store_d3_resume_sram) - return; - - if (!mvm->d3_resume_sram) { - mvm->d3_resume_sram = kzalloc(len, GFP_KERNEL); - if (!mvm->d3_resume_sram) - return; - } - - iwl_trans_read_mem_bytes(mvm->trans, offs, mvm->d3_resume_sram, len); -#endif -} - static void iwl_mvm_d3_disconnect_iter(void *data, u8 *mac, struct ieee80211_vif *vif) { @@ -2054,8 +2034,6 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) } iwl_fw_dbg_read_d3_debug_data(&mvm->fwrt); - /* query SRAM first in case we want event logging */ - iwl_mvm_read_d3_sram(mvm); if (iwl_mvm_check_rt_status(mvm, vif)) { set_bit(STATUS_FW_ERROR, &mvm->trans->status); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index d4ff6b44de2c..5b1bb76c5d28 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -1557,59 +1557,6 @@ static ssize_t iwl_dbgfs_bcast_filters_macs_write(struct iwl_mvm *mvm, } #endif -#ifdef CONFIG_PM_SLEEP -static ssize_t iwl_dbgfs_d3_sram_write(struct iwl_mvm *mvm, char *buf, - size_t count, loff_t *ppos) -{ - int store; - - if (sscanf(buf, "%d", &store) != 1) - return -EINVAL; - - mvm->store_d3_resume_sram = store; - - return count; -} - -static ssize_t iwl_dbgfs_d3_sram_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_mvm *mvm = file->private_data; - const struct fw_img *img; - int ofs, len, pos = 0; - size_t bufsz, ret; - char *buf; - u8 *ptr = mvm->d3_resume_sram; - - img = &mvm->fw->img[IWL_UCODE_WOWLAN]; - len = img->sec[IWL_UCODE_SECTION_DATA].len; - - bufsz = len * 4 + 256; - buf = kzalloc(bufsz, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - pos += scnprintf(buf, bufsz, "D3 SRAM capture: %sabled\n", - mvm->store_d3_resume_sram ? "en" : "dis"); - - if (ptr) { - for (ofs = 0; ofs < len; ofs += 16) { - pos += scnprintf(buf + pos, bufsz - pos, - "0x%.4x %16ph\n", ofs, ptr + ofs); - } - } else { - pos += scnprintf(buf + pos, bufsz - pos, - "(no data captured)\n"); - } - - ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); - - kfree(buf); - - return ret; -} -#endif - #define PRINT_MVM_REF(ref) do { \ if (mvm->refs[ref]) \ pos += scnprintf(buf + pos, bufsz - pos, \ @@ -1940,9 +1887,6 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters, 256); MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters_macs, 256); #endif -#ifdef CONFIG_PM_SLEEP -MVM_DEBUGFS_READ_WRITE_FILE_OPS(d3_sram, 8); -#endif #ifdef CONFIG_ACPI MVM_DEBUGFS_READ_FILE_OPS(sar_geo_profile); #endif @@ -2159,7 +2103,6 @@ void iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) #endif #ifdef CONFIG_PM_SLEEP - MVM_DEBUGFS_ADD_FILE(d3_sram, mvm->debugfs_dir, 0600); MVM_DEBUGFS_ADD_FILE(d3_test, mvm->debugfs_dir, 0400); debugfs_create_bool("d3_wake_sysassert", 0600, mvm->debugfs_dir, &mvm->d3_wake_sysassert); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 8dc2a9850bc5..7b829a5be773 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1039,8 +1039,6 @@ struct iwl_mvm { #ifdef CONFIG_IWLWIFI_DEBUGFS bool d3_wake_sysassert; bool d3_test_active; - bool store_d3_resume_sram; - void *d3_resume_sram; u32 d3_test_pme_ptr; struct ieee80211_vif *keep_vif; u32 last_netdetect_scans; /* no. of scans in the last net-detect wake */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index acd2fda12466..004de67f9157 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -918,9 +918,6 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode) kfree(mvm->error_recovery_buf); mvm->error_recovery_buf = NULL; -#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_IWLWIFI_DEBUGFS) - kfree(mvm->d3_resume_sram); -#endif iwl_trans_op_mode_leave(mvm->trans); iwl_phy_db_free(mvm->phy_db); -- cgit v1.2.3 From b3500b472c880b5abe90ffd5c4a25aa736f906ad Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 29 May 2019 16:39:50 +0300 Subject: iwlwifi: fix load in rfkill flow for unified firmware When we have a single image (same firmware image for INIT and OPERATIONAL), we couldn't load the driver and register to the stack if we had hardware RF-Kill asserted. Fix this. This required a few changes: 1) Run the firmware as part of the INIT phase even if its ucode_type is not IWL_UCODE_INIT. 2) Send the commands that are sent to the unified image in INIT flow even in RF-Kill. 3) Don't ask the transport to stop the hardware upon RF-Kill interrupt if the RF-Kill is asserted. 4) Allow the RF-Kill interrupt to take us out of L1A so that the RF-Kill interrupt will be received by the host (to enable the radio). Signed-off-by: Emmanuel Grumbach Signed-off-by: Luca Coelho Signed-off-by: Kalle Valo --- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 23 ++++++++++++++++------ drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 17 ++++++++++++---- drivers/net/wireless/intel/iwlwifi/pcie/internal.h | 2 +- 5 files changed, 33 insertions(+), 13 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index ab68b5d53ec9..153717587aeb 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -311,6 +311,8 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, int ret; enum iwl_ucode_type old_type = mvm->fwrt.cur_fw_img; static const u16 alive_cmd[] = { MVM_ALIVE }; + bool run_in_rfkill = + ucode_type == IWL_UCODE_INIT || iwl_mvm_has_unified_ucode(mvm); if (ucode_type == IWL_UCODE_REGULAR && iwl_fw_dbg_conf_usniffer(mvm->fw, FW_DBG_START_FROM_ALIVE) && @@ -328,7 +330,12 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, alive_cmd, ARRAY_SIZE(alive_cmd), iwl_alive_fn, &alive_data); - ret = iwl_trans_start_fw(mvm->trans, fw, ucode_type == IWL_UCODE_INIT); + /* + * We want to load the INIT firmware even in RFKILL + * For the unified firmware case, the ucode_type is not + * INIT, but we still need to run it. + */ + ret = iwl_trans_start_fw(mvm->trans, fw, run_in_rfkill); if (ret) { iwl_fw_set_current_image(&mvm->fwrt, old_type); iwl_remove_notification(&mvm->notif_wait, &alive_wait); @@ -433,7 +440,8 @@ static int iwl_run_unified_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) * commands */ ret = iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(SYSTEM_GROUP, - INIT_EXTENDED_CFG_CMD), 0, + INIT_EXTENDED_CFG_CMD), + CMD_SEND_IN_RFKILL, sizeof(init_cfg), &init_cfg); if (ret) { IWL_ERR(mvm, "Failed to run init config command: %d\n", @@ -457,7 +465,8 @@ static int iwl_run_unified_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) } ret = iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(REGULATORY_AND_NVM_GROUP, - NVM_ACCESS_COMPLETE), 0, + NVM_ACCESS_COMPLETE), + CMD_SEND_IN_RFKILL, sizeof(nvm_complete), &nvm_complete); if (ret) { IWL_ERR(mvm, "Failed to run complete NVM access: %d\n", @@ -482,6 +491,8 @@ static int iwl_run_unified_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) } } + mvm->rfkill_safe_init_done = true; + return 0; error: @@ -526,7 +537,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) lockdep_assert_held(&mvm->mutex); - if (WARN_ON_ONCE(mvm->calibrating)) + if (WARN_ON_ONCE(mvm->rfkill_safe_init_done)) return 0; iwl_init_notification_wait(&mvm->notif_wait, @@ -576,7 +587,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) goto remove_notif; } - mvm->calibrating = true; + mvm->rfkill_safe_init_done = true; /* Send TX valid antennas before triggering calibrations */ ret = iwl_send_tx_ant_cfg(mvm, iwl_mvm_get_valid_tx_ant(mvm)); @@ -612,7 +623,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) remove_notif: iwl_remove_notification(&mvm->notif_wait, &calib_wait); out: - mvm->calibrating = false; + mvm->rfkill_safe_init_done = false; if (iwlmvm_mod_params.init_dbg && !mvm->nvm_data) { /* we want to debug INIT and we have no NVM - fake */ mvm->nvm_data = kzalloc(sizeof(struct iwl_nvm_data) + diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 5c52469288be..fdbabca0280e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -1209,7 +1209,7 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) mvm->scan_status = 0; mvm->ps_disabled = false; - mvm->calibrating = false; + mvm->rfkill_safe_init_done = false; /* just in case one was running */ iwl_mvm_cleanup_roc_te(mvm); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 7b829a5be773..02efcf2189c4 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -880,7 +880,7 @@ struct iwl_mvm { struct iwl_mvm_vif *bf_allowed_vif; bool hw_registered; - bool calibrating; + bool rfkill_safe_init_done; bool support_umac_log; u32 ampdu_ref; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 004de67f9157..fad3bf563712 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -1209,7 +1209,8 @@ void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state) static bool iwl_mvm_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state) { struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); - bool calibrating = READ_ONCE(mvm->calibrating); + bool rfkill_safe_init_done = READ_ONCE(mvm->rfkill_safe_init_done); + bool unified = iwl_mvm_has_unified_ucode(mvm); if (state) set_bit(IWL_MVM_STATUS_HW_RFKILL, &mvm->status); @@ -1218,15 +1219,23 @@ static bool iwl_mvm_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state) iwl_mvm_set_rfkill_state(mvm); - /* iwl_run_init_mvm_ucode is waiting for results, abort it */ - if (calibrating) + /* iwl_run_init_mvm_ucode is waiting for results, abort it. */ + if (rfkill_safe_init_done) iwl_abort_notification_waits(&mvm->notif_wait); + /* + * Don't ask the transport to stop the firmware. We'll do it + * after cfg80211 takes us down. + */ + if (unified) + return false; + /* * Stop the device if we run OPERATIONAL firmware or if we are in the * middle of the calibrations. */ - return state && (mvm->fwrt.cur_fw_img != IWL_UCODE_INIT || calibrating); + return state && (mvm->fwrt.cur_fw_img != IWL_UCODE_INIT || + rfkill_safe_init_done); } static void iwl_mvm_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index b513037dc066..85973dd57234 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -928,7 +928,7 @@ static inline void iwl_enable_rfkill_int(struct iwl_trans *trans) MSIX_HW_INT_CAUSES_REG_RF_KILL); } - if (trans->cfg->device_family == IWL_DEVICE_FAMILY_9000) { + if (trans->cfg->device_family >= IWL_DEVICE_FAMILY_9000) { /* * On 9000-series devices this bit isn't enabled by default, so * when we power down the device we need set the bit to allow it -- cgit v1.2.3 From 44f61b5c832c4085fcf476484efeaeef96dcfb8b Mon Sep 17 00:00:00 2001 From: Shahar S Matityahu Date: Wed, 29 May 2019 16:39:51 +0300 Subject: iwlwifi: clear persistence bit according to device family The driver attempts to clear persistence bit on any device familiy even though only 9000 and 22000 families require it. Clear the bit only on the relevant device families. Each HW has different address to the write protection register. Use the right register for each HW Signed-off-by: Shahar S Matityahu Fixes: 8954e1eb2270 ("iwlwifi: trans: Clear persistence bit when starting the FW") Signed-off-by: Luca Coelho Signed-off-by: Kalle Valo --- drivers/net/wireless/intel/iwlwifi/iwl-prph.h | 7 +++- drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 46 ++++++++++++++++++------- 2 files changed, 39 insertions(+), 14 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h index 8e6a0c363c0d..925f308764bf 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h @@ -408,7 +408,12 @@ enum aux_misc_master1_en { #define AUX_MISC_MASTER1_SMPHR_STATUS 0xA20800 #define RSA_ENABLE 0xA24B08 #define PREG_AUX_BUS_WPROT_0 0xA04CC0 -#define PREG_PRPH_WPROT_0 0xA04CE0 + +/* device family 9000 WPROT register */ +#define PREG_PRPH_WPROT_9000 0xA04CE0 +/* device family 22000 WPROT register */ +#define PREG_PRPH_WPROT_22000 0xA04D00 + #define SB_CPU_1_STATUS 0xA01E30 #define SB_CPU_2_STATUS 0xA01E34 #define UMAG_SB_CPU_1_STATUS 0xA038C0 diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 803fcbac4152..e9d1075d91db 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -1698,26 +1698,26 @@ static int iwl_pcie_init_msix_handler(struct pci_dev *pdev, return 0; } -static int _iwl_trans_pcie_start_hw(struct iwl_trans *trans, bool low_power) +static int iwl_trans_pcie_clear_persistence_bit(struct iwl_trans *trans) { - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - u32 hpm; - int err; - - lockdep_assert_held(&trans_pcie->mutex); + u32 hpm, wprot; - err = iwl_pcie_prepare_card_hw(trans); - if (err) { - IWL_ERR(trans, "Error while preparing HW: %d\n", err); - return err; + switch (trans->cfg->device_family) { + case IWL_DEVICE_FAMILY_9000: + wprot = PREG_PRPH_WPROT_9000; + break; + case IWL_DEVICE_FAMILY_22000: + wprot = PREG_PRPH_WPROT_22000; + break; + default: + return 0; } hpm = iwl_read_umac_prph_no_grab(trans, HPM_DEBUG); if (hpm != 0xa5a5a5a0 && (hpm & PERSISTENCE_BIT)) { - int wfpm_val = iwl_read_umac_prph_no_grab(trans, - PREG_PRPH_WPROT_0); + u32 wprot_val = iwl_read_umac_prph_no_grab(trans, wprot); - if (wfpm_val & PREG_WFPM_ACCESS) { + if (wprot_val & PREG_WFPM_ACCESS) { IWL_ERR(trans, "Error, can not clear persistence bit\n"); return -EPERM; @@ -1726,6 +1726,26 @@ static int _iwl_trans_pcie_start_hw(struct iwl_trans *trans, bool low_power) hpm & ~PERSISTENCE_BIT); } + return 0; +} + +static int _iwl_trans_pcie_start_hw(struct iwl_trans *trans, bool low_power) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + int err; + + lockdep_assert_held(&trans_pcie->mutex); + + err = iwl_pcie_prepare_card_hw(trans); + if (err) { + IWL_ERR(trans, "Error while preparing HW: %d\n", err); + return err; + } + + err = iwl_trans_pcie_clear_persistence_bit(trans); + if (err) + return err; + iwl_trans_pcie_sw_reset(trans); err = iwl_pcie_apm_init(trans); -- cgit v1.2.3 From cc5470df4495049170d49466415680ee3c2a9a42 Mon Sep 17 00:00:00 2001 From: Shahar S Matityahu Date: Wed, 29 May 2019 16:39:52 +0300 Subject: iwlwifi: print fseq info upon fw assert Read fseq info from FW registers and print it upon fw assert. The print is needed since the fseq version coming from the TLV might not be the actual version that is used. Signed-off-by: Shahar S Matityahu Signed-off-by: Luca Coelho Signed-off-by: Kalle Valo --- drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 39 +++++++++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/fw/dbg.h | 2 ++ drivers/net/wireless/intel/iwlwifi/iwl-prph.h | 15 +++++++++- drivers/net/wireless/intel/iwlwifi/mvm/utils.c | 2 ++ drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 3 +- 5 files changed, 59 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index 5f52e40a2903..33d7bc5500db 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -2747,3 +2747,42 @@ void iwl_fw_dbg_periodic_trig_handler(struct timer_list *t) jiffies + msecs_to_jiffies(collect_interval)); } } + +#define FSEQ_REG(x) { .addr = (x), .str = #x, } + +void iwl_fw_error_print_fseq_regs(struct iwl_fw_runtime *fwrt) +{ + struct iwl_trans *trans = fwrt->trans; + unsigned long flags; + int i; + struct { + u32 addr; + const char *str; + } fseq_regs[] = { + FSEQ_REG(FSEQ_ERROR_CODE), + FSEQ_REG(FSEQ_TOP_INIT_VERSION), + FSEQ_REG(FSEQ_CNVIO_INIT_VERSION), + FSEQ_REG(FSEQ_OTP_VERSION), + FSEQ_REG(FSEQ_TOP_CONTENT_VERSION), + FSEQ_REG(FSEQ_ALIVE_TOKEN), + FSEQ_REG(FSEQ_CNVI_ID), + FSEQ_REG(FSEQ_CNVR_ID), + FSEQ_REG(CNVI_AUX_MISC_CHIP), + FSEQ_REG(CNVR_AUX_MISC_CHIP), + FSEQ_REG(CNVR_SCU_SD_REGS_SD_REG_DIG_DCDC_VTRIM), + FSEQ_REG(CNVR_SCU_SD_REGS_SD_REG_ACTIVE_VDIG_MIRROR), + }; + + if (!iwl_trans_grab_nic_access(trans, &flags)) + return; + + IWL_ERR(fwrt, "Fseq Registers:\n"); + + for (i = 0; i < ARRAY_SIZE(fseq_regs); i++) + IWL_ERR(fwrt, "0x%08X | %s\n", + iwl_read_prph_no_grab(trans, fseq_regs[i].addr), + fseq_regs[i].str); + + iwl_trans_release_nic_access(trans, &flags); +} +IWL_EXPORT_SYMBOL(iwl_fw_error_print_fseq_regs); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h index 2a9e560a906b..fd0ad220e961 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h @@ -471,4 +471,6 @@ static inline void iwl_fw_error_collect(struct iwl_fw_runtime *fwrt) } void iwl_fw_dbg_periodic_trig_handler(struct timer_list *t); + +void iwl_fw_error_print_fseq_regs(struct iwl_fw_runtime *fwrt); #endif /* __iwl_fw_dbg_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h index 925f308764bf..8d930bfe0727 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h @@ -395,7 +395,11 @@ enum { WFPM_AUX_CTL_AUX_IF_MAC_OWNER_MSK = 0x80000000, }; -#define AUX_MISC_REG 0xA200B0 +#define CNVI_AUX_MISC_CHIP 0xA200B0 +#define CNVR_AUX_MISC_CHIP 0xA2B800 +#define CNVR_SCU_SD_REGS_SD_REG_DIG_DCDC_VTRIM 0xA29890 +#define CNVR_SCU_SD_REGS_SD_REG_ACTIVE_VDIG_MIRROR 0xA29938 + enum { HW_STEP_LOCATION_BITS = 24, }; @@ -447,4 +451,13 @@ enum { #define UREG_DOORBELL_TO_ISR6 0xA05C04 #define UREG_DOORBELL_TO_ISR6_NMI_BIT BIT(0) + +#define FSEQ_ERROR_CODE 0xA340C8 +#define FSEQ_TOP_INIT_VERSION 0xA34038 +#define FSEQ_CNVIO_INIT_VERSION 0xA3403C +#define FSEQ_OTP_VERSION 0xA340FC +#define FSEQ_TOP_CONTENT_VERSION 0xA340F4 +#define FSEQ_ALIVE_TOKEN 0xA340F0 +#define FSEQ_CNVI_ID 0xA3408C +#define FSEQ_CNVR_ID 0xA34090 #endif /* __iwl_prph_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index b9914efc55c4..cc56ab88fb43 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -596,6 +596,8 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm) iwl_mvm_dump_lmac_error_log(mvm, 1); iwl_mvm_dump_umac_error_log(mvm); + + iwl_fw_error_print_fseq_regs(&mvm->fwrt); } int iwl_mvm_reconfig_scd(struct iwl_mvm *mvm, int queue, int fifo, int sta_id, diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index e9d1075d91db..21da18af0155 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -3546,7 +3546,8 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, hw_step |= ENABLE_WFPM; iwl_write_umac_prph_no_grab(trans, WFPM_CTRL_REG, hw_step); - hw_step = iwl_read_prph_no_grab(trans, AUX_MISC_REG); + hw_step = iwl_read_prph_no_grab(trans, + CNVI_AUX_MISC_CHIP); hw_step = (hw_step >> HW_STEP_LOCATION_BITS) & 0xF; if (hw_step == 0x3) trans->hw_rev = (trans->hw_rev & 0xFFFFFFF3) | -- cgit v1.2.3 From b17dc0632a17fbfe66b34ee7c24e1cc10cfc503e Mon Sep 17 00:00:00 2001 From: Matt Chen Date: Wed, 29 May 2019 16:39:53 +0300 Subject: iwlwifi: fix AX201 killer sku loading firmware issue When try to bring up the AX201 2 killer sku, we run into: [81261.392463] iwlwifi 0000:01:00.0: loaded firmware version 46.8c20f243.0 op_mode iwlmvm [81261.407407] iwlwifi 0000:01:00.0: Detected Intel(R) Dual Band Wireless AX 22000, REV=0x340 [81262.424778] iwlwifi 0000:01:00.0: Collecting data: trigger 16 fired. [81262.673359] iwlwifi 0000:01:00.0: Start IWL Error Log Dump: [81262.673365] iwlwifi 0000:01:00.0: Status: 0x00000000, count: -906373681 [81262.673368] iwlwifi 0000:01:00.0: Loaded firmware version: 46.8c20f243.0 [81262.673371] iwlwifi 0000:01:00.0: 0x507C015D | ADVANCED_SYSASSERT Fix this issue by adding 2 more cfg to avoid modifying the original cfg configuration. Signed-off-by: Matt Chen Signed-off-by: Luca Coelho Signed-off-by: Kalle Valo --- drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 21da18af0155..dfa1bed124aa 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -3598,7 +3598,9 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, } } else if (CSR_HW_RF_ID_TYPE_CHIP_ID(trans->hw_rf_id) == CSR_HW_RF_ID_TYPE_CHIP_ID(CSR_HW_RF_ID_TYPE_HR) && - (trans->cfg != &iwl_ax200_cfg_cc || + ((trans->cfg != &iwl_ax200_cfg_cc && + trans->cfg != &killer1650x_2ax_cfg && + trans->cfg != &killer1650w_2ax_cfg) || trans->hw_rev == CSR_HW_REV_TYPE_QNJ_B0)) { u32 hw_status; -- cgit v1.2.3 From a8627176b0de7ba3f4524f641ddff4abf23ae4e4 Mon Sep 17 00:00:00 2001 From: Jia-Ju Bai Date: Wed, 29 May 2019 16:39:54 +0300 Subject: iwlwifi: Fix double-free problems in iwl_req_fw_callback() In the error handling code of iwl_req_fw_callback(), iwl_dealloc_ucode() is called to free data. In iwl_drv_stop(), iwl_dealloc_ucode() is called again, which can cause double-free problems. To fix this bug, the call to iwl_dealloc_ucode() in iwl_req_fw_callback() is deleted. This bug is found by a runtime fuzzing tool named FIZZER written by us. Signed-off-by: Jia-Ju Bai Signed-off-by: Luca Coelho Signed-off-by: Kalle Valo --- drivers/net/wireless/intel/iwlwifi/iwl-drv.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c index 852d3cbfc719..fba242284507 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c @@ -1597,7 +1597,6 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) goto free; out_free_fw: - iwl_dealloc_ucode(drv); release_firmware(ucode_raw); out_unbind: complete(&drv->request_firmware_complete); -- cgit v1.2.3 From 5f4d55d5791a8b7150dbaba239e92719ae0f94d4 Mon Sep 17 00:00:00 2001 From: Lior Cohen Date: Wed, 29 May 2019 16:39:55 +0300 Subject: iwlwifi: mvm: change TLC config cmd sent by rs to be async The TLC_MNG_CONFIG sync cmd sent by the rs leads to a kernel warning of sleeping while in rcu read-side critical section. The fix is to change the command to be ASYNC (not blocking for the response anymore). Signed-off-by: Lior Cohen Signed-off-by: Luca Coelho Signed-off-by: Kalle Valo --- drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c index 659e21b2d4e7..be62f499c595 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c @@ -441,7 +441,8 @@ void rs_fw_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, */ sta->max_amsdu_len = max_amsdu_len; - ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, sizeof(cfg_cmd), &cfg_cmd); + ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, CMD_ASYNC, sizeof(cfg_cmd), + &cfg_cmd); if (ret) IWL_ERR(mvm, "Failed to send rate scale config (%d)\n", ret); } -- cgit v1.2.3 From 69ae4f6aac1578575126319d3f55550e7e440449 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 31 May 2019 15:18:41 +0200 Subject: mwifiex: Fix heap overflow in mwifiex_uap_parse_tail_ies() A few places in mwifiex_uap_parse_tail_ies() perform memcpy() unconditionally, which may lead to either buffer overflow or read over boundary. This patch addresses the issues by checking the read size and the destination size at each place more properly. Along with the fixes, the patch cleans up the code slightly by introducing a temporary variable for the token size, and unifies the error path with the standard goto statement. Reported-by: huangwen Signed-off-by: Takashi Iwai Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/ie.c | 47 ++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 16 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/marvell/mwifiex/ie.c b/drivers/net/wireless/marvell/mwifiex/ie.c index 6845eb57b39a..653d347a9a19 100644 --- a/drivers/net/wireless/marvell/mwifiex/ie.c +++ b/drivers/net/wireless/marvell/mwifiex/ie.c @@ -329,6 +329,8 @@ static int mwifiex_uap_parse_tail_ies(struct mwifiex_private *priv, struct ieee80211_vendor_ie *vendorhdr; u16 gen_idx = MWIFIEX_AUTO_IDX_MASK, ie_len = 0; int left_len, parsed_len = 0; + unsigned int token_len; + int err = 0; if (!info->tail || !info->tail_len) return 0; @@ -344,6 +346,12 @@ static int mwifiex_uap_parse_tail_ies(struct mwifiex_private *priv, */ while (left_len > sizeof(struct ieee_types_header)) { hdr = (void *)(info->tail + parsed_len); + token_len = hdr->len + sizeof(struct ieee_types_header); + if (token_len > left_len) { + err = -EINVAL; + goto out; + } + switch (hdr->element_id) { case WLAN_EID_SSID: case WLAN_EID_SUPP_RATES: @@ -361,17 +369,20 @@ static int mwifiex_uap_parse_tail_ies(struct mwifiex_private *priv, if (cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT, WLAN_OUI_TYPE_MICROSOFT_WMM, (const u8 *)hdr, - hdr->len + sizeof(struct ieee_types_header))) + token_len)) break; /* fall through */ default: - memcpy(gen_ie->ie_buffer + ie_len, hdr, - hdr->len + sizeof(struct ieee_types_header)); - ie_len += hdr->len + sizeof(struct ieee_types_header); + if (ie_len + token_len > IEEE_MAX_IE_SIZE) { + err = -EINVAL; + goto out; + } + memcpy(gen_ie->ie_buffer + ie_len, hdr, token_len); + ie_len += token_len; break; } - left_len -= hdr->len + sizeof(struct ieee_types_header); - parsed_len += hdr->len + sizeof(struct ieee_types_header); + left_len -= token_len; + parsed_len += token_len; } /* parse only WPA vendor IE from tail, WMM IE is configured by @@ -381,15 +392,17 @@ static int mwifiex_uap_parse_tail_ies(struct mwifiex_private *priv, WLAN_OUI_TYPE_MICROSOFT_WPA, info->tail, info->tail_len); if (vendorhdr) { - memcpy(gen_ie->ie_buffer + ie_len, vendorhdr, - vendorhdr->len + sizeof(struct ieee_types_header)); - ie_len += vendorhdr->len + sizeof(struct ieee_types_header); + token_len = vendorhdr->len + sizeof(struct ieee_types_header); + if (ie_len + token_len > IEEE_MAX_IE_SIZE) { + err = -EINVAL; + goto out; + } + memcpy(gen_ie->ie_buffer + ie_len, vendorhdr, token_len); + ie_len += token_len; } - if (!ie_len) { - kfree(gen_ie); - return 0; - } + if (!ie_len) + goto out; gen_ie->ie_index = cpu_to_le16(gen_idx); gen_ie->mgmt_subtype_mask = cpu_to_le16(MGMT_MASK_BEACON | @@ -399,13 +412,15 @@ static int mwifiex_uap_parse_tail_ies(struct mwifiex_private *priv, if (mwifiex_update_uap_custom_ie(priv, gen_ie, &gen_idx, NULL, NULL, NULL, NULL)) { - kfree(gen_ie); - return -1; + err = -EINVAL; + goto out; } priv->gen_idx = gen_idx; + + out: kfree(gen_ie); - return 0; + return err; } /* This function parses different IEs-head & tail IEs, beacon IEs, -- cgit v1.2.3