From f2d1bdf053d0cafff61a32103b20403958cb5232 Mon Sep 17 00:00:00 2001 From: Mordechay Goodstein Date: Mon, 2 Aug 2021 17:09:33 +0300 Subject: [PATCH 01/95] iwlwifi: iwl-nvm-parse: set STBC flags for HE phy capabilities Our HW supersets STBC for HE but never set it in assoc IE, fix it by setting it and enable using it. Signed-off-by: Mordechay Goodstein Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210802170640.0108f3e322b6.Ib25a91b5c48ff1fb2185b86a9e4bf5eec637df90@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c index 850648ebd61c..2ce4aa26774e 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c @@ -568,7 +568,8 @@ static const struct ieee80211_sband_iftype_data iwl_he_capa[] = { IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD, .phy_cap_info[2] = - IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US, + IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US | + IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ, .phy_cap_info[3] = IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_NO_DCM | IEEE80211_HE_PHY_CAP3_DCM_MAX_TX_NSS_1 | @@ -634,6 +635,7 @@ static const struct ieee80211_sband_iftype_data iwl_he_capa[] = { .phy_cap_info[1] = IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD, .phy_cap_info[2] = + IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ | IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US, .phy_cap_info[3] = IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_NO_DCM | @@ -742,6 +744,8 @@ iwl_nvm_fixup_sband_iftd(struct iwl_trans *trans, IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G; if ((tx_chains & rx_chains) == ANT_AB) { + iftype_data->he_cap.he_cap_elem.phy_cap_info[2] |= + IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ; iftype_data->he_cap.he_cap_elem.phy_cap_info[5] |= IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_2 | IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_2; From 1269ba1ce35d91799a43fc52e9eeb04364f50dfd Mon Sep 17 00:00:00 2001 From: Shaul Triebitz Date: Mon, 2 Aug 2021 17:09:34 +0300 Subject: [PATCH 02/95] iwlwifi: mvm: set BROADCAST_TWT_SUPPORTED in MAC policy If broadcast TWT is supported in the BSS, tell the firmware about it by setting the BROADCAST_TWT_SUPPORTED in the MAC context command. Signed-off-by: Shaul Triebitz Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210802170640.736c3b1bc915.I10583bb6f808aa60954da26106bbc8c26620cbe8@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/api/mac.h | 4 +++- drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 5 ++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h b/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h index 93084bbad534..7be7715b431d 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2012-2014, 2018-2020 Intel Corporation + * Copyright (C) 2012-2014, 2018-2021 Intel Corporation * Copyright (C) 2017 Intel Deutschland GmbH */ #ifndef __iwl_fw_api_mac_h__ @@ -137,12 +137,14 @@ struct iwl_mac_data_ibss { * early termination detection. * @FLEXIBLE_TWT_SUPPORTED: AP supports flexible TWT schedule * @PROTECTED_TWT_SUPPORTED: AP supports protected TWT frames (with 11w) + * @BROADCAST_TWT_SUPPORTED: AP and STA support broadcast TWT */ enum iwl_mac_data_policy { TWT_SUPPORTED = BIT(0), MORE_DATA_ACK_SUPPORTED = BIT(1), FLEXIBLE_TWT_SUPPORTED = BIT(2), PROTECTED_TWT_SUPPORTED = BIT(3), + BROADCAST_TWT_SUPPORTED = BIT(4), }; /** diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index fd5e08961651..76a658cb5493 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2020 Intel Corporation + * Copyright (C) 2012-2014, 2018-2021 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2015-2017 Intel Deutschland GmbH */ @@ -652,6 +652,9 @@ static int iwl_mvm_mac_ctxt_cmd_sta(struct iwl_mvm *mvm, if (vif->bss_conf.twt_protected) ctxt_sta->data_policy |= cpu_to_le32(PROTECTED_TWT_SUPPORTED); + if (vif->bss_conf.twt_broadcast) + ctxt_sta->data_policy |= + cpu_to_le32(BROADCAST_TWT_SUPPORTED); } } From 0eb5a554bb49bf62f929612dd964e4a834b71a81 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 2 Aug 2021 17:09:35 +0300 Subject: [PATCH 03/95] iwlwifi: nvm: enable IEEE80211_HE_PHY_CAP10_HE_MU_M1RU_MAX_LTF The device is capable of receiving MU-MIMO frames with 8 symbols, enable the bit here that says so. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210802170640.90cf2eb42794.I692e6d0fde6e99a1db97d2e678952f043f48f603@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c index 2ce4aa26774e..a6de34358a3f 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c @@ -596,6 +596,8 @@ static const struct ieee80211_sband_iftype_data iwl_he_capa[] = { IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB | IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB | IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_RESERVED, + .phy_cap_info[10] = + IEEE80211_HE_PHY_CAP10_HE_MU_M1RU_MAX_LTF, }, /* * Set default Tx/Rx HE MCS NSS Support field. From 2f308f008f1ccda4dcf9816c7dad0a33fbffdd18 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 2 Aug 2021 17:09:36 +0300 Subject: [PATCH 04/95] iwlwifi: mvm: avoid FW restart while shutting down If the firmware crashes while we're already shutting down the system, there isn't much we can do since the shutdown process is continuing and we wanted to do that. Don't do a FW restart, with the implied debug collection, in this case. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210802170640.43a7351ae6bd.I164d48ce4379accf76ea0637983fd946d52dc6f5@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 20e8d343a950..1f43079f02af 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -1466,6 +1466,14 @@ static void iwl_mvm_nic_error(struct iwl_op_mode *op_mode) if (!test_bit(STATUS_TRANS_DEAD, &mvm->trans->status)) iwl_mvm_dump_nic_error_log(mvm); + /* + * If the firmware crashes while we're already considering it + * to be dead then don't ask for a restart, that cannot do + * anything useful anyway. + */ + if (!test_bit(IWL_MVM_STATUS_FIRMWARE_RUNNING, &mvm->status)) + return; + iwl_mvm_nic_restart(mvm, true); } From 95fe8d89bb8c9c114ca3e46f8b2457f894f55746 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 2 Aug 2021 17:09:37 +0300 Subject: [PATCH 05/95] iwlwifi: pcie: optimise struct iwl_rx_mem_buffer layout On 64-bit machines, struct iwl_rx_mem_buffer has a lot of padding due to the use of pointers after the small items. Move the list entry before them, and while at it also add documentation for it. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210802170640.6a62255b3df0.I47bb36530a3c2cdbd73454c796ce608ee2a32a6c@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/internal.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index cc550f6ef957..10d763fc3d50 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -42,6 +42,7 @@ struct iwl_host_cmd; * struct iwl_rx_mem_buffer * @page_dma: bus address of rxb page * @page: driver's pointer to the rxb page + * @list: list entry for the membuffer * @invalid: rxb is in driver ownership - not owned by HW * @vid: index of this rxb in the global table * @offset: indicates which offset of the page (in bytes) @@ -50,10 +51,10 @@ struct iwl_host_cmd; struct iwl_rx_mem_buffer { dma_addr_t page_dma; struct page *page; - u16 vid; - bool invalid; struct list_head list; u32 offset; + u16 vid; + bool invalid; }; /** From 6ac5720086c8b176794eb74c5cc09f8b79017f38 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 2 Aug 2021 17:09:38 +0300 Subject: [PATCH 06/95] iwlwifi: pcie: free RBs during configure When switching op-modes, or more generally when reconfiguring, we might switch the RB size. In _iwl_pcie_rx_init() we have a comment saying we must free all RBs since we might switch the size, but this is actually too late: the switch has been done and we'll free the buffers with the wrong size. Fix this by always freeing the buffers, if any, at the start of configure, instead of only after the size may have changed. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210802170640.42d7c93279c4.I07f74e65aab0e3d965a81206fcb289dc92d74878@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 5 ++++- drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c index 4f6f4b2720f0..ff7ca3c57f34 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c @@ -487,6 +487,9 @@ void iwl_pcie_free_rbs_pool(struct iwl_trans *trans) struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); int i; + if (!trans_pcie->rx_pool) + return; + for (i = 0; i < RX_POOL_SIZE(trans_pcie->num_rx_bufs); i++) { if (!trans_pcie->rx_pool[i].page) continue; @@ -1062,7 +1065,7 @@ static int _iwl_pcie_rx_init(struct iwl_trans *trans) INIT_LIST_HEAD(&rba->rbd_empty); spin_unlock_bh(&rba->lock); - /* free all first - we might be reconfigured for a different size */ + /* free all first - we overwrite everything here */ iwl_pcie_free_rbs_pool(trans); for (i = 0; i < RX_QUEUE_SIZE; i++) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index bee6b4574226..65cc25cbb9ec 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -1866,6 +1866,9 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans, { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + /* free all first - we might be reconfigured for a different size */ + iwl_pcie_free_rbs_pool(trans); + trans->txqs.cmd.q_id = trans_cfg->cmd_queue; trans->txqs.cmd.fifo = trans_cfg->cmd_fifo; trans->txqs.cmd.wdg_timeout = trans_cfg->cmd_q_wdg_timeout; From b8221b0f750a05a7ae9cbca84932e2a36a3ee658 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 2 Aug 2021 17:09:39 +0300 Subject: [PATCH 07/95] iwlwifi: prepare for synchronous error dumps In some cases it may be necessary to synchronously create a firmware error report, add the necessary infrastructure for this. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210802170640.481b6642f0fc.I7c9c958408a285e3d19aceed2a5a3341cfc08382@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/dvm/main.c | 4 +- drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 97 ++++++++++--------- drivers/net/wireless/intel/iwlwifi/fw/dbg.h | 7 +- .../net/wireless/intel/iwlwifi/iwl-dbg-tlv.c | 25 ++--- .../net/wireless/intel/iwlwifi/iwl-dbg-tlv.h | 24 ++++- drivers/net/wireless/intel/iwlwifi/iwl-io.c | 4 +- .../net/wireless/intel/iwlwifi/iwl-op-mode.h | 8 +- .../net/wireless/intel/iwlwifi/iwl-trans.h | 4 +- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 16 ++- drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 2 +- 10 files changed, 113 insertions(+), 78 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/main.c b/drivers/net/wireless/intel/iwlwifi/dvm/main.c index c01523f64bfc..cc7b69fd14d3 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/main.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/main.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /****************************************************************************** * - * Copyright(c) 2003 - 2014, 2018 - 2020 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2014, 2018 - 2021 Intel Corporation. All rights reserved. * Copyright(c) 2015 Intel Deutschland GmbH * * Portions of this file are derived from the ipw3945 project, as well @@ -1950,7 +1950,7 @@ static void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand) } } -static void iwl_nic_error(struct iwl_op_mode *op_mode) +static void iwl_nic_error(struct iwl_op_mode *op_mode, bool sync) { struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index df7c55e06f54..70e0a3089876 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -2530,51 +2530,6 @@ int iwl_fw_dbg_collect(struct iwl_fw_runtime *fwrt, } IWL_EXPORT_SYMBOL(iwl_fw_dbg_collect); -int iwl_fw_dbg_ini_collect(struct iwl_fw_runtime *fwrt, - struct iwl_fwrt_dump_data *dump_data) -{ - struct iwl_fw_ini_trigger_tlv *trig = dump_data->trig; - enum iwl_fw_ini_time_point tp_id = le32_to_cpu(trig->time_point); - u32 occur, delay; - unsigned long idx; - - if (!iwl_fw_ini_trigger_on(fwrt, trig)) { - IWL_WARN(fwrt, "WRT: Trigger %d is not active, aborting dump\n", - tp_id); - return -EINVAL; - } - - delay = le32_to_cpu(trig->dump_delay); - occur = le32_to_cpu(trig->occurrences); - if (!occur) - return 0; - - trig->occurrences = cpu_to_le32(--occur); - - /* Check there is an available worker. - * ffz return value is undefined if no zero exists, - * so check against ~0UL first. - */ - if (fwrt->dump.active_wks == ~0UL) - return -EBUSY; - - idx = ffz(fwrt->dump.active_wks); - - if (idx >= IWL_FW_RUNTIME_DUMP_WK_NUM || - test_and_set_bit(fwrt->dump.wks[idx].idx, &fwrt->dump.active_wks)) - return -EBUSY; - - fwrt->dump.wks[idx].dump_data = *dump_data; - - IWL_WARN(fwrt, - "WRT: Collecting data: ini trigger %d fired (delay=%dms).\n", - tp_id, (u32)(delay / USEC_PER_MSEC)); - - schedule_delayed_work(&fwrt->dump.wks[idx].wk, usecs_to_jiffies(delay)); - - return 0; -} - int iwl_fw_dbg_collect_trig(struct iwl_fw_runtime *fwrt, struct iwl_fw_dbg_trigger_tlv *trigger, const char *fmt, ...) @@ -2703,6 +2658,58 @@ out: clear_bit(wk_idx, &fwrt->dump.active_wks); } +int iwl_fw_dbg_ini_collect(struct iwl_fw_runtime *fwrt, + struct iwl_fwrt_dump_data *dump_data, + bool sync) +{ + struct iwl_fw_ini_trigger_tlv *trig = dump_data->trig; + enum iwl_fw_ini_time_point tp_id = le32_to_cpu(trig->time_point); + u32 occur, delay; + unsigned long idx; + + if (!iwl_fw_ini_trigger_on(fwrt, trig)) { + IWL_WARN(fwrt, "WRT: Trigger %d is not active, aborting dump\n", + tp_id); + return -EINVAL; + } + + delay = le32_to_cpu(trig->dump_delay); + occur = le32_to_cpu(trig->occurrences); + if (!occur) + return 0; + + trig->occurrences = cpu_to_le32(--occur); + + /* Check there is an available worker. + * ffz return value is undefined if no zero exists, + * so check against ~0UL first. + */ + if (fwrt->dump.active_wks == ~0UL) + return -EBUSY; + + idx = ffz(fwrt->dump.active_wks); + + if (idx >= IWL_FW_RUNTIME_DUMP_WK_NUM || + test_and_set_bit(fwrt->dump.wks[idx].idx, &fwrt->dump.active_wks)) + return -EBUSY; + + fwrt->dump.wks[idx].dump_data = *dump_data; + + if (sync) + delay = 0; + + IWL_WARN(fwrt, + "WRT: Collecting data: ini trigger %d fired (delay=%dms).\n", + tp_id, (u32)(delay / USEC_PER_MSEC)); + + schedule_delayed_work(&fwrt->dump.wks[idx].wk, usecs_to_jiffies(delay)); + + if (sync) + iwl_fw_dbg_collect_sync(fwrt, idx); + + return 0; +} + void iwl_fw_error_dump_wk(struct work_struct *work) { struct iwl_fwrt_wk_data *wks = diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h index c0e84ef84f5d..8c3c890066b0 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h @@ -46,7 +46,8 @@ int iwl_fw_dbg_collect_desc(struct iwl_fw_runtime *fwrt, int iwl_fw_dbg_error_collect(struct iwl_fw_runtime *fwrt, enum iwl_fw_dbg_trigger trig_type); int iwl_fw_dbg_ini_collect(struct iwl_fw_runtime *fwrt, - struct iwl_fwrt_dump_data *dump_data); + struct iwl_fwrt_dump_data *dump_data, + bool sync); int iwl_fw_dbg_collect(struct iwl_fw_runtime *fwrt, enum iwl_fw_dbg_trigger trig, const char *str, size_t len, struct iwl_fw_dbg_trigger_tlv *trigger); @@ -284,7 +285,7 @@ static inline void iwl_fw_umac_set_alive_err_table(struct iwl_trans *trans, trans->dbg.umac_error_event_table = umac_error_event_table; } -static inline void iwl_fw_error_collect(struct iwl_fw_runtime *fwrt) +static inline void iwl_fw_error_collect(struct iwl_fw_runtime *fwrt, bool sync) { enum iwl_fw_ini_time_point tp_id; @@ -300,7 +301,7 @@ static inline void iwl_fw_error_collect(struct iwl_fw_runtime *fwrt) tp_id = IWL_FW_INI_TIME_POINT_FW_ASSERT; } - iwl_dbg_tlv_time_point(fwrt, tp_id, NULL); + _iwl_dbg_tlv_time_point(fwrt, tp_id, NULL, sync); } void iwl_fw_error_print_fseq_regs(struct iwl_fw_runtime *fwrt); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c index 0ddd255a8cc1..cc78fd23c922 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c @@ -683,7 +683,7 @@ static void iwl_dbg_tlv_periodic_trig_handler(struct timer_list *t) }; int ret; - ret = iwl_fw_dbg_ini_collect(timer_node->fwrt, &dump_data); + ret = iwl_fw_dbg_ini_collect(timer_node->fwrt, &dump_data, false); if (!ret || ret == -EBUSY) { u32 occur = le32_to_cpu(dump_data.trig->occurrences); u32 collect_interval = le32_to_cpu(dump_data.trig->data[0]); @@ -927,7 +927,7 @@ static bool iwl_dbg_tlv_check_fw_pkt(struct iwl_fw_runtime *fwrt, } static int -iwl_dbg_tlv_tp_trigger(struct iwl_fw_runtime *fwrt, +iwl_dbg_tlv_tp_trigger(struct iwl_fw_runtime *fwrt, bool sync, struct list_head *active_trig_list, union iwl_dbg_tlv_tp_data *tp_data, bool (*data_check)(struct iwl_fw_runtime *fwrt, @@ -946,7 +946,7 @@ iwl_dbg_tlv_tp_trigger(struct iwl_fw_runtime *fwrt, int ret, i; if (!num_data) { - ret = iwl_fw_dbg_ini_collect(fwrt, &dump_data); + ret = iwl_fw_dbg_ini_collect(fwrt, &dump_data, sync); if (ret) return ret; } @@ -955,7 +955,7 @@ iwl_dbg_tlv_tp_trigger(struct iwl_fw_runtime *fwrt, if (!data_check || data_check(fwrt, &dump_data, tp_data, le32_to_cpu(dump_data.trig->data[i]))) { - ret = iwl_fw_dbg_ini_collect(fwrt, &dump_data); + ret = iwl_fw_dbg_ini_collect(fwrt, &dump_data, sync); if (ret) return ret; @@ -1043,9 +1043,10 @@ static void iwl_dbg_tlv_init_cfg(struct iwl_fw_runtime *fwrt) } } -void iwl_dbg_tlv_time_point(struct iwl_fw_runtime *fwrt, - enum iwl_fw_ini_time_point tp_id, - union iwl_dbg_tlv_tp_data *tp_data) +void _iwl_dbg_tlv_time_point(struct iwl_fw_runtime *fwrt, + enum iwl_fw_ini_time_point tp_id, + union iwl_dbg_tlv_tp_data *tp_data, + bool sync) { struct list_head *hcmd_list, *trig_list; @@ -1060,12 +1061,12 @@ void iwl_dbg_tlv_time_point(struct iwl_fw_runtime *fwrt, switch (tp_id) { case IWL_FW_INI_TIME_POINT_EARLY: iwl_dbg_tlv_init_cfg(fwrt); - iwl_dbg_tlv_tp_trigger(fwrt, trig_list, tp_data, NULL); + iwl_dbg_tlv_tp_trigger(fwrt, sync, trig_list, tp_data, NULL); break; case IWL_FW_INI_TIME_POINT_AFTER_ALIVE: iwl_dbg_tlv_apply_buffers(fwrt); iwl_dbg_tlv_send_hcmds(fwrt, hcmd_list); - iwl_dbg_tlv_tp_trigger(fwrt, trig_list, tp_data, NULL); + iwl_dbg_tlv_tp_trigger(fwrt, sync, trig_list, tp_data, NULL); break; case IWL_FW_INI_TIME_POINT_PERIODIC: iwl_dbg_tlv_set_periodic_trigs(fwrt); @@ -1075,13 +1076,13 @@ void iwl_dbg_tlv_time_point(struct iwl_fw_runtime *fwrt, case IWL_FW_INI_TIME_POINT_MISSED_BEACONS: case IWL_FW_INI_TIME_POINT_FW_DHC_NOTIFICATION: iwl_dbg_tlv_send_hcmds(fwrt, hcmd_list); - iwl_dbg_tlv_tp_trigger(fwrt, trig_list, tp_data, + iwl_dbg_tlv_tp_trigger(fwrt, sync, trig_list, tp_data, iwl_dbg_tlv_check_fw_pkt); break; default: iwl_dbg_tlv_send_hcmds(fwrt, hcmd_list); - iwl_dbg_tlv_tp_trigger(fwrt, trig_list, tp_data, NULL); + iwl_dbg_tlv_tp_trigger(fwrt, sync, trig_list, tp_data, NULL); break; } } -IWL_EXPORT_SYMBOL(iwl_dbg_tlv_time_point); +IWL_EXPORT_SYMBOL(_iwl_dbg_tlv_time_point); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.h b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.h index 92c720527946..c12b1fd3f479 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2018-2020 Intel Corporation + * Copyright (C) 2018-2021 Intel Corporation */ #ifndef __iwl_dbg_tlv_h__ #define __iwl_dbg_tlv_h__ @@ -48,9 +48,25 @@ void iwl_dbg_tlv_free(struct iwl_trans *trans); void iwl_dbg_tlv_alloc(struct iwl_trans *trans, const struct iwl_ucode_tlv *tlv, bool ext); void iwl_dbg_tlv_init(struct iwl_trans *trans); -void iwl_dbg_tlv_time_point(struct iwl_fw_runtime *fwrt, - enum iwl_fw_ini_time_point tp_id, - union iwl_dbg_tlv_tp_data *tp_data); +void _iwl_dbg_tlv_time_point(struct iwl_fw_runtime *fwrt, + enum iwl_fw_ini_time_point tp_id, + union iwl_dbg_tlv_tp_data *tp_data, + bool sync); + +static inline void iwl_dbg_tlv_time_point(struct iwl_fw_runtime *fwrt, + enum iwl_fw_ini_time_point tp_id, + union iwl_dbg_tlv_tp_data *tp_data) +{ + _iwl_dbg_tlv_time_point(fwrt, tp_id, tp_data, false); +} + +static inline void iwl_dbg_tlv_time_point_sync(struct iwl_fw_runtime *fwrt, + enum iwl_fw_ini_time_point tp_id, + union iwl_dbg_tlv_tp_data *tp_data) +{ + _iwl_dbg_tlv_time_point(fwrt, tp_id, tp_data, true); +} + void iwl_dbg_tlv_del_timers(struct iwl_trans *trans); #endif /* __iwl_dbg_tlv_h__*/ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-io.c b/drivers/net/wireless/intel/iwlwifi/iwl-io.c index 33d42e08d5b8..2a0be1fafdf9 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-io.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-io.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2003-2014, 2018-2020 Intel Corporation + * Copyright (C) 2003-2014, 2018-2021 Intel Corporation * Copyright (C) 2015-2016 Intel Deutschland GmbH */ #include @@ -468,5 +468,5 @@ void iwl_trans_sync_nmi_with_addr(struct iwl_trans *trans, u32 inta_addr, if (interrupts_enabled) iwl_trans_interrupts(trans, true); - iwl_trans_fw_error(trans); + iwl_trans_fw_error(trans, false); } diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h b/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h index cf9c64090014..af5f9b210f22 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h @@ -78,7 +78,7 @@ struct iwl_cfg; * there are Tx packets pending in the transport layer. * Must be atomic * @nic_error: error notification. Must be atomic and must be called with BH - * disabled. + * disabled, unless the sync parameter is true. * @cmd_queue_full: Called when the command queue gets full. Must be atomic and * called with BH disabled. * @nic_config: configure NIC, called before firmware is started. @@ -102,7 +102,7 @@ struct iwl_op_mode_ops { void (*queue_not_full)(struct iwl_op_mode *op_mode, int queue); bool (*hw_rf_kill)(struct iwl_op_mode *op_mode, bool state); void (*free_skb)(struct iwl_op_mode *op_mode, struct sk_buff *skb); - void (*nic_error)(struct iwl_op_mode *op_mode); + void (*nic_error)(struct iwl_op_mode *op_mode, bool sync); void (*cmd_queue_full)(struct iwl_op_mode *op_mode); void (*nic_config)(struct iwl_op_mode *op_mode); void (*wimax_active)(struct iwl_op_mode *op_mode); @@ -181,9 +181,9 @@ static inline void iwl_op_mode_free_skb(struct iwl_op_mode *op_mode, op_mode->ops->free_skb(op_mode, skb); } -static inline void iwl_op_mode_nic_error(struct iwl_op_mode *op_mode) +static inline void iwl_op_mode_nic_error(struct iwl_op_mode *op_mode, bool sync) { - op_mode->ops->nic_error(op_mode); + op_mode->ops->nic_error(op_mode, sync); } static inline void iwl_op_mode_cmd_queue_full(struct iwl_op_mode *op_mode) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index 0199d7a5a648..2cbc9ecd688b 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -1385,14 +1385,14 @@ iwl_trans_release_nic_access(struct iwl_trans *trans) __release(nic_access); } -static inline void iwl_trans_fw_error(struct iwl_trans *trans) +static inline void iwl_trans_fw_error(struct iwl_trans *trans, bool sync) { if (WARN_ON_ONCE(!trans->op_mode)) return; /* prevent double restarts due to the same erroneous FW */ if (!test_and_set_bit(STATUS_FW_ERROR, &trans->status)) { - iwl_op_mode_nic_error(trans->op_mode); + iwl_op_mode_nic_error(trans->op_mode, sync); trans->state = IWL_TRANS_NO_FW; } } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 1f43079f02af..880cf2042531 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -1400,7 +1400,7 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error) * can't recover this since we're already half suspended. */ if (!mvm->fw_restart && fw_error) { - iwl_fw_error_collect(&mvm->fwrt); + iwl_fw_error_collect(&mvm->fwrt, false); } else if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { struct iwl_mvm_reprobe *reprobe; @@ -1451,7 +1451,7 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error) } } - iwl_fw_error_collect(&mvm->fwrt); + iwl_fw_error_collect(&mvm->fwrt, false); if (fw_error && mvm->fw_restart > 0) mvm->fw_restart--; @@ -1459,13 +1459,23 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error) } } -static void iwl_mvm_nic_error(struct iwl_op_mode *op_mode) +static void iwl_mvm_nic_error(struct iwl_op_mode *op_mode, bool sync) { struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); if (!test_bit(STATUS_TRANS_DEAD, &mvm->trans->status)) iwl_mvm_dump_nic_error_log(mvm); + if (sync) { + iwl_fw_error_collect(&mvm->fwrt, true); + /* + * Currently, the only case for sync=true is during + * shutdown, so just stop in this case. If/when that + * changes, we need to be a bit smarter here. + */ + return; + } + /* * If the firmware crashes while we're already considering it * to be dead then don't ask for a restart, that cannot do diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c index ff7ca3c57f34..54bfc01ab34c 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c @@ -1656,7 +1656,7 @@ static void iwl_pcie_irq_handle_error(struct iwl_trans *trans) /* The STATUS_FW_ERROR bit is set in this function. This must happen * before we wake up the command caller, to ensure a proper cleanup. */ - iwl_trans_fw_error(trans); + iwl_trans_fw_error(trans, false); clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status); wake_up(&trans->wait_command_queue); From e63aafea74393e6c6ca0dd439e72021830a0fcac Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 2 Aug 2021 17:09:40 +0300 Subject: [PATCH 08/95] iwlwifi: pcie: dump error on FW reset handshake failures If the firmware crashes while we're waiting for the reset handshake then it cannot possibly make progress anymore, and we will just time out the wait. That's pointless, so just stop waiting at that point. Additionally, if it never acknowledges the reset handshake, something went wrong. Dump an error in both of these cases, but we need to do it synchronously here since the device will be turned off. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210802170640.8b6a33544b4b.I55f97f70f8efa64db064a9207177a094c60ac8f1@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/internal.h | 9 ++++++++- drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 10 ++++++++-- drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c | 11 ++++++++--- 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index 10d763fc3d50..6c3b0403b68f 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -254,6 +254,13 @@ struct cont_rec { }; #endif +enum iwl_pcie_fw_reset_state { + FW_RESET_IDLE, + FW_RESET_REQUESTED, + FW_RESET_OK, + FW_RESET_ERROR, +}; + /** * struct iwl_trans_pcie - PCIe transport specific data * @rxq: all the RX queue data @@ -405,7 +412,7 @@ struct iwl_trans_pcie { dma_addr_t base_rb_stts_dma; bool fw_reset_handshake; - bool fw_reset_done; + enum iwl_pcie_fw_reset_state fw_reset_state; wait_queue_head_t fw_reset_waitq; char rf_name[32]; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c index 54bfc01ab34c..8e45eb38304b 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c @@ -2228,7 +2228,13 @@ irqreturn_t iwl_pcie_irq_msix_handler(int irq, void *dev_id) "Microcode SW error detected. Restarting 0x%X.\n", inta_fh); isr_stats->sw++; - iwl_pcie_irq_handle_error(trans); + /* during FW reset flow report errors from there */ + if (trans_pcie->fw_reset_state == FW_RESET_REQUESTED) { + trans_pcie->fw_reset_state = FW_RESET_ERROR; + wake_up(&trans_pcie->fw_reset_waitq); + } else { + iwl_pcie_irq_handle_error(trans); + } } /* After checking FH register check HW register */ @@ -2296,7 +2302,7 @@ irqreturn_t iwl_pcie_irq_msix_handler(int irq, void *dev_id) if (inta_hw & MSIX_HW_INT_CAUSES_REG_RESET_DONE) { IWL_DEBUG_ISR(trans, "Reset flow completed\n"); - trans_pcie->fw_reset_done = true; + trans_pcie->fw_reset_state = FW_RESET_OK; wake_up(&trans_pcie->fw_reset_waitq); } diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c index a34009357227..a266a35ff928 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c @@ -95,7 +95,7 @@ static void iwl_trans_pcie_fw_reset_handshake(struct iwl_trans *trans) struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); int ret; - trans_pcie->fw_reset_done = false; + trans_pcie->fw_reset_state = FW_RESET_REQUESTED; if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210) iwl_write_umac_prph(trans, UREG_NIC_SET_NMI_DRIVER, @@ -106,10 +106,15 @@ static void iwl_trans_pcie_fw_reset_handshake(struct iwl_trans *trans) /* wait 200ms */ ret = wait_event_timeout(trans_pcie->fw_reset_waitq, - trans_pcie->fw_reset_done, FW_RESET_TIMEOUT); - if (!ret) + trans_pcie->fw_reset_state != FW_RESET_REQUESTED, + FW_RESET_TIMEOUT); + if (!ret || trans_pcie->fw_reset_state == FW_RESET_ERROR) { IWL_INFO(trans, "firmware didn't ACK the reset - continue anyway\n"); + iwl_trans_fw_error(trans, true); + } + + trans_pcie->fw_reset_state = FW_RESET_IDLE; } void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans) From 2a1d2fcf2bedd5aef9e7cc638211ffdef062e5dd Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Mon, 2 Aug 2021 17:09:41 +0300 Subject: [PATCH 09/95] iwlwifi: print PNVM complete notification status in hexadecimal This value is not a simple incrementing integer, it contains some flags as well, so reading it in hexadecimal is easier. Change the print to do it in hex instead of decimal. Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210802170640.5e35f930d0ed.I5f94575a835f060bdc8ed3477871256f8a2cbaaa@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/pnvm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c index b4b1f75b9c2a..34e24196c1a3 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c @@ -24,7 +24,7 @@ static bool iwl_pnvm_complete_fn(struct iwl_notif_wait_data *notif_wait, struct iwl_pnvm_init_complete_ntfy *pnvm_ntf = (void *)pkt->data; IWL_DEBUG_FW(trans, - "PNVM complete notification received with status %d\n", + "PNVM complete notification received with status 0x%0x\n", le32_to_cpu(pnvm_ntf->status)); return true; From deedf9b97cd4ef45da476c9bdd2a5f3276053956 Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Mon, 2 Aug 2021 17:09:42 +0300 Subject: [PATCH 10/95] iwlwifi: mvm: Do not use full SSIDs in 6GHz scan The scan request processing populated the direct SSIDs in the FW scan request command also for 6GHz scan, which is not needed and might result in unexpected behavior. Fix the code to add the direct SSIDs only in case the scan is not a 6GHz scan. Signed-off-by: Ilan Peer Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210802170640.f465937c7bbf.Ic11a1659ddda850c3ec1b1afbe9e2b9577ac1800@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/scan.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index 0368b7101222..4899d8f90bab 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -2368,14 +2368,17 @@ static int iwl_mvm_scan_umac_v14(struct iwl_mvm *mvm, struct ieee80211_vif *vif, if (ret) return ret; - iwl_mvm_scan_umac_fill_probe_p_v4(params, &scan_p->probe_params, - &bitmap_ssid); if (!params->scan_6ghz) { + iwl_mvm_scan_umac_fill_probe_p_v4(params, &scan_p->probe_params, + &bitmap_ssid); iwl_mvm_scan_umac_fill_ch_p_v6(mvm, params, vif, - &scan_p->channel_params, bitmap_ssid); + &scan_p->channel_params, bitmap_ssid); return 0; + } else { + pb->preq = params->preq; } + cp->flags = iwl_mvm_scan_umac_chan_flags_v2(mvm, params, vif); cp->n_aps_override[0] = IWL_SCAN_ADWELL_N_APS_GO_FRIENDLY; cp->n_aps_override[1] = IWL_SCAN_ADWELL_N_APS_SOCIAL_CHS; From 16cff731a3a17d30b1e556c474b6dddb09c64b41 Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Mon, 2 Aug 2021 17:09:43 +0300 Subject: [PATCH 11/95] iwlwifi: mvm: Add support for hidden network scan on 6GHz band Add support for discovery of hidden networks on the 6GHz band, by including the scan request direct SSIDs in the FW scan request command: - In case a short SSID matches one of the direct SSIDs in the scan request command, add the matching SSID in the same offset in the 'direct_ssids' array. - Otherwise, add the SSID in one of the available slots. Additionally, as a preparation to handle hidden APs, refactor iwl_mvm_umac_scan_cfg_channels_v6_6g() the function. Signed-off-by: Ilan Peer Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210802170640.ffb540a70212.Ia2bb9bc9435b833820bcc7dc30adcedb5a5a9869@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/file.h | 1 + drivers/net/wireless/intel/iwlwifi/mvm/scan.c | 90 +++++++++++++++---- 2 files changed, 76 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h index 9a8c7b7a0816..6c8e9f3a6af2 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/file.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h @@ -414,6 +414,7 @@ enum iwl_ucode_tlv_capa { IWL_UCODE_TLV_CAPA_PROTECTED_TWT = (__force iwl_ucode_tlv_capa_t)56, IWL_UCODE_TLV_CAPA_FW_RESET_HANDSHAKE = (__force iwl_ucode_tlv_capa_t)57, IWL_UCODE_TLV_CAPA_PASSIVE_6GHZ_SCAN = (__force iwl_ucode_tlv_capa_t)58, + IWL_UCODE_TLV_CAPA_HIDDEN_6GHZ_SCAN = (__force iwl_ucode_tlv_capa_t)59, IWL_UCODE_TLV_CAPA_BROADCAST_TWT = (__force iwl_ucode_tlv_capa_t)60, /* set 2 */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index 4899d8f90bab..82ab08af0e21 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -1724,9 +1724,8 @@ iwl_mvm_umac_scan_fill_6g_chan_list(struct iwl_mvm_scan_params *params, /* TODO: this function can be merged with iwl_mvm_scan_umac_fill_ch_p_v6 */ static void iwl_mvm_umac_scan_cfg_channels_v6_6g(struct iwl_mvm_scan_params *params, - u32 n_channels, __le32 *cmd_short_ssid, - u8 *cmd_bssid, u8 scan_ssid_num, - u8 bssid_num, + u32 n_channels, + struct iwl_scan_probe_params_v4 *pp, struct iwl_scan_channel_params_v6 *cp, enum nl80211_iftype vif_type) { @@ -1741,7 +1740,7 @@ iwl_mvm_umac_scan_cfg_channels_v6_6g(struct iwl_mvm_scan_params *params, u32 s_ssid_bitmap = 0, bssid_bitmap = 0, flags = 0; u8 j, k, s_max = 0, b_max = 0, n_used_bssid_entries; - bool force_passive, found = false, + bool force_passive, found = false, allow_passive = true, unsolicited_probe_on_chan = false, psc_no_listen = false; cfg->v1.channel_num = params->channels[i]->hw_value; @@ -1766,9 +1765,9 @@ iwl_mvm_umac_scan_cfg_channels_v6_6g(struct iwl_mvm_scan_params *params, scan_6ghz_params[j].unsolicited_probe; psc_no_listen |= scan_6ghz_params[j].psc_no_listen; - for (k = 0; k < scan_ssid_num; k++) { + for (k = 0; k < pp->short_ssid_num; k++) { if (!scan_6ghz_params[j].unsolicited_probe && - le32_to_cpu(cmd_short_ssid[k]) == + le32_to_cpu(pp->short_ssid[k]) == scan_6ghz_params[j].short_ssid) { /* Relevant short SSID bit set */ if (s_ssid_bitmap & BIT(k)) { @@ -1778,7 +1777,10 @@ iwl_mvm_umac_scan_cfg_channels_v6_6g(struct iwl_mvm_scan_params *params, /* * Use short SSID only to create a new - * iteration during channel dwell. + * iteration during channel dwell or in + * case that the short SSID has a + * matching SSID, i.e., scan for hidden + * APs. */ if (n_used_bssid_entries >= 3) { s_ssid_bitmap |= BIT(k); @@ -1786,6 +1788,12 @@ iwl_mvm_umac_scan_cfg_channels_v6_6g(struct iwl_mvm_scan_params *params, n_used_bssid_entries -= 3; found = true; break; + } else if (pp->direct_scan[k].len) { + s_ssid_bitmap |= BIT(k); + s_max++; + found = true; + allow_passive = false; + break; } } } @@ -1793,8 +1801,8 @@ iwl_mvm_umac_scan_cfg_channels_v6_6g(struct iwl_mvm_scan_params *params, if (found) continue; - for (k = 0; k < bssid_num; k++) { - if (!memcmp(&cmd_bssid[ETH_ALEN * k], + for (k = 0; k < pp->bssid_num; k++) { + if (!memcmp(&pp->bssid_array[k], scan_6ghz_params[j].bssid, ETH_ALEN)) { if (!(bssid_bitmap & BIT(k))) { @@ -1849,7 +1857,7 @@ iwl_mvm_umac_scan_cfg_channels_v6_6g(struct iwl_mvm_scan_params *params, force_passive |= (unsolicited_probe_on_chan && (s_max > 1 || b_max > 3)); } - if (force_passive || + if ((allow_passive && force_passive) || (!flags && !cfg80211_channel_is_psc(params->channels[i]))) flags |= IWL_UHB_CHAN_CFG_FLAG_FORCE_PASSIVE; @@ -1857,6 +1865,60 @@ iwl_mvm_umac_scan_cfg_channels_v6_6g(struct iwl_mvm_scan_params *params, } } +static void +iwl_mvm_umac_scan_cfg_6g_direct_ssids(struct iwl_mvm *mvm, + struct iwl_mvm_scan_params *params, + struct iwl_scan_probe_params_v4 *pp) +{ + u8 next_free_idx = pp->short_ssid_num; + int i; + + if (!fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_HIDDEN_6GHZ_SCAN)) { + IWL_DEBUG_SCAN(mvm, + "6GHz hidden scan: Not supported by FW\n"); + return; + } + + for (i = params->n_ssids - 1; i >= 0; i--) { + __le32 short_ssid; + u8 ssid_idx, j; + + if (!params->ssids[i].ssid_len) + continue; + + short_ssid = cpu_to_le32(~crc32_le(~0, params->ssids[i].ssid, + params->ssids[i].ssid_len)); + + for (j = 0; j < pp->short_ssid_num; j++) + if (short_ssid == pp->short_ssid[j]) + break; + + if (j == pp->short_ssid_num) { + /* + * If there are no available slots for the short SSID, do not + * place it. + */ + if (next_free_idx < SCAN_SHORT_SSID_MAX_SIZE) + ssid_idx = next_free_idx++; + else + continue; + } else { + ssid_idx = j; + } + + if (ssid_idx >= PROBE_OPTION_MAX) + continue; + + pp->direct_scan[ssid_idx].id = WLAN_EID_SSID; + pp->direct_scan[ssid_idx].len = params->ssids[i].ssid_len; + memcpy(pp->direct_scan[ssid_idx].ssid, params->ssids[i].ssid, + params->ssids[i].ssid_len); + } + + pp->short_ssid_num = next_free_idx; +} + static u8 iwl_mvm_scan_umac_chan_flags_v2(struct iwl_mvm *mvm, struct iwl_mvm_scan_params *params, struct ieee80211_vif *vif) @@ -2390,13 +2452,11 @@ static int iwl_mvm_scan_umac_v14(struct iwl_mvm *mvm, struct ieee80211_vif *vif, if (ret) return ret; + iwl_mvm_umac_scan_cfg_6g_direct_ssids(mvm, params, pb); + iwl_mvm_umac_scan_cfg_channels_v6_6g(params, params->n_channels, - pb->short_ssid, - pb->bssid_array[0], - pb->short_ssid_num, - pb->bssid_num, cp, - vif->type); + pb, cp, vif->type); cp->count = params->n_channels; if (!params->n_ssids || (params->n_ssids == 1 && !params->ssids[0].ssid_len)) From 8fc3015d0d35f42ee57c04bfe3c17f112afce5fe Mon Sep 17 00:00:00 2001 From: Mordechay Goodstein Date: Mon, 2 Aug 2021 17:09:44 +0300 Subject: [PATCH 12/95] iwlwifi: iwl-dbg-tlv: add info about loading external dbg bin This helps understand why and what debug capabilities are running. Signed-off-by: Mordechay Goodstein Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210802170640.98980f8bd17f.Ifcedf415a545a87cb341a4142085b5723d8cac4d@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c index cc78fd23c922..c89db7b9585a 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c @@ -435,13 +435,16 @@ static int iwl_dbg_tlv_parse_bin(struct iwl_trans *trans, const u8 *data, void iwl_dbg_tlv_load_bin(struct device *dev, struct iwl_trans *trans) { const struct firmware *fw; + const char *yoyo_bin = "iwl-debug-yoyo.bin"; int res; if (!iwlwifi_mod_params.enable_ini || trans->trans_cfg->device_family <= IWL_DEVICE_FAMILY_9000) return; - res = firmware_request_nowarn(&fw, "iwl-debug-yoyo.bin", dev); + res = firmware_request_nowarn(&fw, yoyo_bin, dev); + IWL_DEBUG_FW(trans, "%s %s\n", res ? "didn't load" : "loaded", yoyo_bin); + if (res) return; From 1a81bddf7f47443240b7703bf9e5ffb12c4261cf Mon Sep 17 00:00:00 2001 From: Mordechay Goodstein Date: Mon, 2 Aug 2021 17:28:18 +0300 Subject: [PATCH 13/95] iwlwifi: mvm: remove trigger EAPOL time event EAPOL failure results in deauthentication with various reasons, not related to AUTH failure specifically, so we just merge AUTH failure with failed to assoc to AP. Signed-off-by: Mordechay Goodstein Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210802172232.2ff350d85eab.I02c5b5d29c0d5c2e014bd1081b07ed33772ae04d@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 70ebecb73c24..3a7f756c4545 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -5035,22 +5035,14 @@ static void iwl_mvm_event_mlme_callback_ini(struct iwl_mvm *mvm, struct ieee80211_vif *vif, const struct ieee80211_mlme_event *mlme) { - if (mlme->data == ASSOC_EVENT && (mlme->status == MLME_DENIED || - mlme->status == MLME_TIMEOUT)) { + if ((mlme->data == ASSOC_EVENT || mlme->data == AUTH_EVENT) && + (mlme->status == MLME_DENIED || mlme->status == MLME_TIMEOUT)) { iwl_dbg_tlv_time_point(&mvm->fwrt, IWL_FW_INI_TIME_POINT_ASSOC_FAILED, NULL); return; } - if (mlme->data == AUTH_EVENT && (mlme->status == MLME_DENIED || - mlme->status == MLME_TIMEOUT)) { - iwl_dbg_tlv_time_point(&mvm->fwrt, - IWL_FW_INI_TIME_POINT_EAPOL_FAILED, - NULL); - return; - } - if (mlme->data == DEAUTH_RX_EVENT || mlme->data == DEAUTH_TX_EVENT) { iwl_dbg_tlv_time_point(&mvm->fwrt, IWL_FW_INI_TIME_POINT_DEASSOC, From a6dfbd040e26d0fa429545d37ca9d3dc8a80cf3b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 2 Aug 2021 17:28:19 +0300 Subject: [PATCH 14/95] iwlwifi: mvm: set replay counter on key install When installing a (new) key, set the replay counter so that after FW restart the firmware has the correct value of the replay counters. This doesn't have a large effect - for frames that reach the driver, it will do a replay check, and when installing a new key, the counter is normally zero to start with (not for GTK though, if joining the BSS for the first time). Since this only affects frames handled entirely by the FW, and that's restricted to a few unicast management frames, the only affect here is for those after a firmware restart. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210802172232.1cedf2ca7bb6.I2e609c28eaa301436e6740f4f1beca838f69a96a@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 53 ++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 9c45a64c5009..0ec84d8ff9e6 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -3190,6 +3190,20 @@ static struct iwl_mvm_sta *iwl_mvm_get_key_sta(struct iwl_mvm *mvm, return NULL; } +static int iwl_mvm_pn_cmp(const u8 *pn1, const u8 *pn2, int len) +{ + int i; + + for (i = len - 1; i >= 0; i--) { + if (pn1[i] > pn2[i]) + return 1; + if (pn1[i] < pn2[i]) + return -1; + } + + return 0; +} + static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm, u32 sta_id, struct ieee80211_key_conf *key, bool mcast, @@ -3274,6 +3288,45 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm, u.cmd.common.key_flags = key_flags; u.cmd.common.sta_id = sta_id; + if (key->cipher == WLAN_CIPHER_SUITE_TKIP) + i = 0; + else + i = -1; + + for (; i < IEEE80211_NUM_TIDS; i++) { + struct ieee80211_key_seq seq = {}; + u8 _rx_pn[IEEE80211_MAX_PN_LEN] = {}, *rx_pn = _rx_pn; + int rx_pn_len = 8; + + ieee80211_get_key_rx_seq(key, i, &seq); + + if (key->cipher == WLAN_CIPHER_SUITE_TKIP) { + rx_pn[0] = seq.tkip.iv16; + rx_pn[1] = seq.tkip.iv16 >> 8; + /* hole at 2/3 in FW format */ + rx_pn[4] = seq.tkip.iv32; + rx_pn[5] = seq.tkip.iv32 >> 8; + rx_pn[6] = seq.tkip.iv32 >> 16; + rx_pn[7] = seq.tkip.iv32 >> 24; + } else if (key_flags & cpu_to_le16(STA_KEY_FLG_EXT)) { + rx_pn = seq.hw.seq; + rx_pn_len = seq.hw.seq_len; + } else { + rx_pn[0] = seq.ccmp.pn[0]; + rx_pn[1] = seq.ccmp.pn[1]; + /* hole at 2/3 in FW format */ + rx_pn[4] = seq.ccmp.pn[2]; + rx_pn[5] = seq.ccmp.pn[3]; + rx_pn[6] = seq.ccmp.pn[4]; + rx_pn[7] = seq.ccmp.pn[5]; + } + + if (iwl_mvm_pn_cmp(rx_pn, (u8 *)&u.cmd.common.rx_secur_seq_cnt, + rx_pn_len) > 0) + memcpy(&u.cmd.common.rx_secur_seq_cnt, rx_pn, + rx_pn_len); + } + if (new_api) { u.cmd.transmit_seq_cnt = cpu_to_le64(pn); size = sizeof(u.cmd); From de34d1c1d30d6d9373f536522c04b86b54711c3b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 2 Aug 2021 17:28:20 +0300 Subject: [PATCH 15/95] iwlwifi: mvm: restrict FW SMPS request The firmware SMPS request should only be honoured if the connection is currently with HE and on 160 MHz, so check that and then potentially reapply any request if the BW changes. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210802172232.0cdcac5660da.I9ee7956fd4f48399855d1f97728bc58b36caf112@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 3 +++ drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 11 +++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 3a7f756c4545..b2072e19b5dc 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -2440,6 +2440,9 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, IWL_DEBUG_MAC80211(mvm, "arp filter changed\n"); iwl_mvm_configure_bcast_filter(mvm); } + + if (changes & BSS_CHANGED_BANDWIDTH) + iwl_mvm_apply_fw_smps_request(vif); } static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 880cf2042531..564ccfbd15bd 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -214,11 +214,14 @@ void iwl_mvm_apply_fw_smps_request(struct ieee80211_vif *vif) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm *mvm = mvmvif->mvm; + enum ieee80211_smps_mode mode = IEEE80211_SMPS_AUTOMATIC; - iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_FW, - mvm->fw_static_smps_request ? - IEEE80211_SMPS_STATIC : - IEEE80211_SMPS_AUTOMATIC); + if (mvm->fw_static_smps_request && + vif->bss_conf.chandef.width == NL80211_CHAN_WIDTH_160 && + vif->bss_conf.he_support) + mode = IEEE80211_SMPS_STATIC; + + iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_FW, mode); } static void iwl_mvm_intf_dual_chain_req(void *data, u8 *mac, From 02289645a085eedb55b185da2766b5c6f9492577 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Mon, 2 Aug 2021 17:28:21 +0300 Subject: [PATCH 16/95] iwlwifi: pcie: remove spaces from queue names If we use spaces in the queue names, we get files with spaces in their name in procfs, which is ugly. Remove the spaces. Reported-by: Joe Perches Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210802172232.0ef8aedd4f9b.If527b9ae5bf8de8c6877d4b6a21ed8d81b0f877e@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/internal.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index 6c3b0403b68f..a43e56c7689f 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -678,19 +678,19 @@ static inline const char *queue_name(struct device *dev, IWL_SHARED_IRQ_FIRST_RSS ? 1 : 0; if (i == 0) - return DRV_NAME ": shared IRQ"; + return DRV_NAME ":shared_IRQ"; return devm_kasprintf(dev, GFP_KERNEL, - DRV_NAME ": queue %d", i + vec); + DRV_NAME ":queue_%d", i + vec); } if (i == 0) - return DRV_NAME ": default queue"; + return DRV_NAME ":default_queue"; if (i == trans_p->alloc_vecs - 1) - return DRV_NAME ": exception"; + return DRV_NAME ":exception"; return devm_kasprintf(dev, GFP_KERNEL, - DRV_NAME ": queue %d", i); + DRV_NAME ":queue_%d", i); } static inline void iwl_enable_rfkill_int(struct iwl_trans *trans) From c1868c0b78892a8b2329dae835786a8a7f643fe2 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Mon, 2 Aug 2021 17:28:22 +0300 Subject: [PATCH 17/95] iwlwifi: mvm: remove check for vif in iwl_mvm_vif_from_mac80211() This check is useless, because we would return NULL in that case and none of the callers actually check that the return value was not NULL before accessing it. Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210802172232.f1c4844a2650.If4dc009e22cda51099a1dc4237d04bf4313055d6@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index b50942f28bb7..82a53cbf4342 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -431,8 +431,6 @@ struct iwl_mvm_vif { static inline struct iwl_mvm_vif * iwl_mvm_vif_from_mac80211(struct ieee80211_vif *vif) { - if (!vif) - return NULL; return (void *)vif->drv_priv; } From cd7ae5493448e12183e0b01070f060d617dd1edd Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Mon, 2 Aug 2021 17:28:23 +0300 Subject: [PATCH 18/95] iwlwifi: mvm: fix old-style static const declaration GCC reports warning as follows: drivers/net/wireless/intel/iwlwifi/mvm/rfi.c:14:1: warning: 'static' is not at beginning of declaration [-Wold-style-declaration] 14 | const static struct iwl_rfi_lut_entry iwl_rfi_table[IWL_RFI_LUT_SIZE] = { | ^~~~~ Move static to the beginning of declaration. Fixes: 21254908cbe9 ("iwlwifi: mvm: add RFI-M support") Reported-by: Hulk Robot Signed-off-by: Wei Yongjun Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210802172232.f60b39bbb0c0.I8b0ad9105003d13cc4aa64fc957aec9582e8b26d@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/rfi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rfi.c b/drivers/net/wireless/intel/iwlwifi/mvm/rfi.c index 0b818067067c..44344216a1a9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rfi.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rfi.c @@ -11,7 +11,7 @@ * DDR needs frequency in units of 16.666MHz, so provide FW with the * frequency values in the adjusted format. */ -const static struct iwl_rfi_lut_entry iwl_rfi_table[IWL_RFI_LUT_SIZE] = { +static const struct iwl_rfi_lut_entry iwl_rfi_table[IWL_RFI_LUT_SIZE] = { /* LPDDR4 */ /* frequency 3733MHz */ From 0f5d44ac6e55551798dd3da0ff847c8df5990822 Mon Sep 17 00:00:00 2001 From: Zhang Qilong Date: Mon, 2 Aug 2021 17:28:24 +0300 Subject: [PATCH 19/95] iwlwifi: mvm: fix a memory leak in iwl_mvm_mac_ctxt_beacon_changed If beacon_inject_active is true, we will return without freeing beacon. Fid that by freeing it before returning. Signed-off-by: Zhang Qilong [reworded the commit message] Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210802172232.d16206ca60fc.I9984a9b442c84814c307cee3213044e24d26f38a@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index 76a658cb5493..2fbc1a3bbdca 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -1008,8 +1008,10 @@ int iwl_mvm_mac_ctxt_beacon_changed(struct iwl_mvm *mvm, return -ENOMEM; #ifdef CONFIG_IWLWIFI_DEBUGFS - if (mvm->beacon_inject_active) + if (mvm->beacon_inject_active) { + dev_kfree_skb(beacon); return -EBUSY; + } #endif ret = iwl_mvm_mac_ctxt_send_beacon(mvm, vif, beacon); From 2b06127df02fbca66d0098e9a1d3eaf62bb5e9c8 Mon Sep 17 00:00:00 2001 From: Tom Rix Date: Mon, 2 Aug 2021 17:28:25 +0300 Subject: [PATCH 20/95] iwlwifi: remove trailing semicolon in macro definition The macro use will already have a semicolon. Signed-off-by: Tom Rix Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210802172232.3db450ebbb3c.Ic63f85b85a043256318da49d7b5a63f7dddf3986@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/dvm/rx.c | 2 +- drivers/net/wireless/intel/iwlwifi/fw/api/coex.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/rx.c b/drivers/net/wireless/intel/iwlwifi/dvm/rx.c index 80475c7a6fba..3cd7b423c588 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/rx.c @@ -318,7 +318,7 @@ iwlagn_accumulative_statistics(struct iwl_priv *priv, (__le32 *)&priv->delta_stats._name, \ (__le32 *)&priv->max_delta_stats._name, \ (__le32 *)&priv->accum_stats._name, \ - sizeof(*_name)); + sizeof(*_name)) ACCUM(common); ACCUM(rx_non_phy); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/coex.h b/drivers/net/wireless/intel/iwlwifi/fw/api/coex.h index 01580c9175f3..3e81e9369224 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/coex.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/coex.h @@ -142,7 +142,7 @@ enum iwl_bt_mxbox_dw3 { "\t%s: %d%s", \ #_field, \ BT_MBOX_MSG(notif, _num, _field), \ - true ? "\n" : ", "); + true ? "\n" : ", ") enum iwl_bt_activity_grading { BT_OFF = 0, BT_ON_NO_CONNECTION = 1, From 5993c90ccb56b34aaedfd77a1c67c7a2039090ee Mon Sep 17 00:00:00 2001 From: Zheng Yongjun Date: Mon, 2 Aug 2021 17:28:26 +0300 Subject: [PATCH 21/95] iwlwifi: use DEFINE_MUTEX() for mutex lock mutex lock can be initialized automatically with DEFINE_MUTEX() rather than explicitly calling mutex_init(). Signed-off-by: Zheng Yongjun Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210802172232.2a583d006739.Ia782c08525397b6430b1c877a870d688a7f3f494@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-drv.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c index 977dce686bdb..77124b8b235e 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c @@ -78,7 +78,7 @@ enum { }; /* Protects the table contents, i.e. the ops pointer & drv list */ -static struct mutex iwlwifi_opmode_table_mtx; +static DEFINE_MUTEX(iwlwifi_opmode_table_mtx); static struct iwlwifi_opmode_table { const char *name; /* name: iwldvm, iwlmvm, etc */ const struct iwl_op_mode_ops *ops; /* pointer to op_mode ops */ @@ -1754,8 +1754,6 @@ static int __init iwl_drv_init(void) { int i, err; - mutex_init(&iwlwifi_opmode_table_mtx); - for (i = 0; i < ARRAY_SIZE(iwlwifi_opmode_table); i++) INIT_LIST_HEAD(&iwlwifi_opmode_table[i].drv); From c6ce1c74ef2923b8ffd85f7f8b486f804f343b39 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 2 Aug 2021 17:28:27 +0300 Subject: [PATCH 22/95] iwlwifi: mvm: avoid static queue number aliasing When TVQM is enabled (iwl_mvm_has_new_tx_api() is true), then queue numbers are just sequentially assigned 0, 1, 2, ... Prior to TVQM, in DQA, there were some statically allocated queue numbers: * IWL_MVM_DQA_AUX_QUEUE == 1, * both IWL_MVM_DQA_INJECT_MONITOR_QUEUE and IWL_MVM_DQA_P2P_DEVICE_QUEUE == 2, and * IWL_MVM_DQA_AP_PROBE_RESP_QUEUE == 9. Now, these values are assigned to the members mvm->aux_queue, mvm->snif_queue, mvm->probe_queue and mvm->p2p_dev_queue by default. Normally, this doesn't really matter, and if TVQM is in fact available we override them to the real values after allocating a queue for use there. However, this allocation doesn't always happen. For example, for mvm->p2p_dev_queue (== 2) it only happens when the P2P Device interface is started, if any. If it's not started, the value in mvm->p2p_dev_queue remains 2. This wouldn't really matter all that much if it weren't for iwl_mvm_is_static_queue() which checks a queue number against one of those four static numbers. Now, if no P2P Device or monitor interface is added then queue 2 may be dynamically allocated, yet alias mvm->p2p_dev_queue or mvm->snif_queue, and thus iwl_mvm_is_static_queue() erroneously returns true for it. If it then gets full, all interface queues are stopped, instead of just backpressuring against the one TXQ that's really the only affected one. This clearly can lead to issues, as everything is stopped even if just a single TXQ filled its corresponding HW queue, if it happens to have an appropriate number (2 or 9, AUX is always reassigned.) Due to a mac80211 bug, this also led to a situation in which the queues remained stopped across a deauthentication and then attempts to connect to a new AP started failing, but that's fixed separately. Fix all of this by simply initializing the queue numbers to the invalid value until they're used, if TVQM is enabled, and also setting them back to that value when the queues are later freed again. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210802172232.2e47e623f9e2.I9b0830dafbb68ef35b7b8f0f46160abec02ac7d0@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 24 +++++++++++++--- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 30 ++++++++++++-------- 2 files changed, 38 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 564ccfbd15bd..f1aa31150318 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -795,10 +795,26 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, mvm->fw_restart = iwlwifi_mod_params.fw_restart ? -1 : 0; - mvm->aux_queue = IWL_MVM_DQA_AUX_QUEUE; - mvm->snif_queue = IWL_MVM_DQA_INJECT_MONITOR_QUEUE; - mvm->probe_queue = IWL_MVM_DQA_AP_PROBE_RESP_QUEUE; - mvm->p2p_dev_queue = IWL_MVM_DQA_P2P_DEVICE_QUEUE; + if (iwl_mvm_has_new_tx_api(mvm)) { + /* + * If we have the new TX/queue allocation API initialize them + * all to invalid numbers. We'll rewrite the ones that we need + * later, but that doesn't happen for all of them all of the + * time (e.g. P2P Device is optional), and if a dynamic queue + * ends up getting number 2 (IWL_MVM_DQA_P2P_DEVICE_QUEUE) then + * iwl_mvm_is_static_queue() erroneously returns true, and we + * might have things getting stuck. + */ + mvm->aux_queue = IWL_MVM_INVALID_QUEUE; + mvm->snif_queue = IWL_MVM_INVALID_QUEUE; + mvm->probe_queue = IWL_MVM_INVALID_QUEUE; + mvm->p2p_dev_queue = IWL_MVM_INVALID_QUEUE; + } else { + mvm->aux_queue = IWL_MVM_DQA_AUX_QUEUE; + mvm->snif_queue = IWL_MVM_DQA_INJECT_MONITOR_QUEUE; + mvm->probe_queue = IWL_MVM_DQA_AP_PROBE_RESP_QUEUE; + mvm->p2p_dev_queue = IWL_MVM_DQA_P2P_DEVICE_QUEUE; + } mvm->sf_state = SF_UNINIT; if (iwl_mvm_has_unified_ucode(mvm)) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 0ec84d8ff9e6..84953d7e5f09 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -316,8 +316,9 @@ static int iwl_mvm_invalidate_sta_queue(struct iwl_mvm *mvm, int queue, } static int iwl_mvm_disable_txq(struct iwl_mvm *mvm, struct ieee80211_sta *sta, - int queue, u8 tid, u8 flags) + u16 *queueptr, u8 tid, u8 flags) { + int queue = *queueptr; struct iwl_scd_txq_cfg_cmd cmd = { .scd_queue = queue, .action = SCD_CFG_DISABLE_QUEUE, @@ -326,6 +327,7 @@ static int iwl_mvm_disable_txq(struct iwl_mvm *mvm, struct ieee80211_sta *sta, if (iwl_mvm_has_new_tx_api(mvm)) { iwl_trans_txq_free(mvm->trans, queue); + *queueptr = IWL_MVM_INVALID_QUEUE; return 0; } @@ -487,6 +489,7 @@ static int iwl_mvm_free_inactive_queue(struct iwl_mvm *mvm, int queue, u8 sta_id, tid; unsigned long disable_agg_tids = 0; bool same_sta; + u16 queue_tmp = queue; int ret; lockdep_assert_held(&mvm->mutex); @@ -509,7 +512,7 @@ static int iwl_mvm_free_inactive_queue(struct iwl_mvm *mvm, int queue, iwl_mvm_invalidate_sta_queue(mvm, queue, disable_agg_tids, false); - ret = iwl_mvm_disable_txq(mvm, old_sta, queue, tid, 0); + ret = iwl_mvm_disable_txq(mvm, old_sta, &queue_tmp, tid, 0); if (ret) { IWL_ERR(mvm, "Failed to free inactive queue %d (ret=%d)\n", @@ -1184,6 +1187,7 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm, unsigned int wdg_timeout = iwl_mvm_get_wd_timeout(mvm, mvmsta->vif, false, false); int queue = -1; + u16 queue_tmp; unsigned long disable_agg_tids = 0; enum iwl_mvm_agg_state queue_state; bool shared_queue = false, inc_ssn; @@ -1332,7 +1336,8 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm, return 0; out_err: - iwl_mvm_disable_txq(mvm, sta, queue, tid, 0); + queue_tmp = queue; + iwl_mvm_disable_txq(mvm, sta, &queue_tmp, tid, 0); return ret; } @@ -1779,7 +1784,7 @@ static void iwl_mvm_disable_sta_queues(struct iwl_mvm *mvm, if (mvm_sta->tid_data[i].txq_id == IWL_MVM_INVALID_QUEUE) continue; - iwl_mvm_disable_txq(mvm, sta, mvm_sta->tid_data[i].txq_id, i, + iwl_mvm_disable_txq(mvm, sta, &mvm_sta->tid_data[i].txq_id, i, 0); mvm_sta->tid_data[i].txq_id = IWL_MVM_INVALID_QUEUE; } @@ -1987,7 +1992,7 @@ static int iwl_mvm_add_int_sta_with_queue(struct iwl_mvm *mvm, int macidx, ret = iwl_mvm_add_int_sta_common(mvm, sta, addr, macidx, maccolor); if (ret) { if (!iwl_mvm_has_new_tx_api(mvm)) - iwl_mvm_disable_txq(mvm, NULL, *queue, + iwl_mvm_disable_txq(mvm, NULL, queue, IWL_MAX_TID_COUNT, 0); return ret; } @@ -2060,7 +2065,7 @@ int iwl_mvm_rm_snif_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) if (WARN_ON_ONCE(mvm->snif_sta.sta_id == IWL_MVM_INVALID_STA)) return -EINVAL; - iwl_mvm_disable_txq(mvm, NULL, mvm->snif_queue, IWL_MAX_TID_COUNT, 0); + iwl_mvm_disable_txq(mvm, NULL, &mvm->snif_queue, IWL_MAX_TID_COUNT, 0); ret = iwl_mvm_rm_sta_common(mvm, mvm->snif_sta.sta_id); if (ret) IWL_WARN(mvm, "Failed sending remove station\n"); @@ -2077,7 +2082,7 @@ int iwl_mvm_rm_aux_sta(struct iwl_mvm *mvm) if (WARN_ON_ONCE(mvm->aux_sta.sta_id == IWL_MVM_INVALID_STA)) return -EINVAL; - iwl_mvm_disable_txq(mvm, NULL, mvm->aux_queue, IWL_MAX_TID_COUNT, 0); + iwl_mvm_disable_txq(mvm, NULL, &mvm->aux_queue, IWL_MAX_TID_COUNT, 0); ret = iwl_mvm_rm_sta_common(mvm, mvm->aux_sta.sta_id); if (ret) IWL_WARN(mvm, "Failed sending remove station\n"); @@ -2173,7 +2178,7 @@ static void iwl_mvm_free_bcast_sta_queues(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - int queue; + u16 *queueptr, queue; lockdep_assert_held(&mvm->mutex); @@ -2182,10 +2187,10 @@ static void iwl_mvm_free_bcast_sta_queues(struct iwl_mvm *mvm, switch (vif->type) { case NL80211_IFTYPE_AP: case NL80211_IFTYPE_ADHOC: - queue = mvm->probe_queue; + queueptr = &mvm->probe_queue; break; case NL80211_IFTYPE_P2P_DEVICE: - queue = mvm->p2p_dev_queue; + queueptr = &mvm->p2p_dev_queue; break; default: WARN(1, "Can't free bcast queue on vif type %d\n", @@ -2193,7 +2198,8 @@ static void iwl_mvm_free_bcast_sta_queues(struct iwl_mvm *mvm, return; } - iwl_mvm_disable_txq(mvm, NULL, queue, IWL_MAX_TID_COUNT, 0); + queue = *queueptr; + iwl_mvm_disable_txq(mvm, NULL, queueptr, IWL_MAX_TID_COUNT, 0); if (iwl_mvm_has_new_tx_api(mvm)) return; @@ -2428,7 +2434,7 @@ int iwl_mvm_rm_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) iwl_mvm_flush_sta(mvm, &mvmvif->mcast_sta, true); - iwl_mvm_disable_txq(mvm, NULL, mvmvif->cab_queue, 0, 0); + iwl_mvm_disable_txq(mvm, NULL, &mvmvif->cab_queue, 0, 0); ret = iwl_mvm_rm_sta_common(mvm, mvmvif->mcast_sta.sta_id); if (ret) From 366fc672d6250bd747b745111b6a0d16b62aa60b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 2 Aug 2021 17:28:28 +0300 Subject: [PATCH 23/95] iwlwifi: mvm: clean up number of HW queues Since switching to mac80211 TXQs, we no longer need to advertise more hardware queues than ACs, since we don't even set QUEUE_CONTROL anyway, so the vif->hw_queue[] mapping array won't be used. All we need (at least for now) is for hw->queues to indicate that we have enough queues to handle QoS. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210802172232.80611a3c1ee7.I8a3d2b269421b6d8bada8c12cce3e095e6cfaeed@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index b2072e19b5dc..f38d2476d5a3 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -390,7 +390,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) if (mvm->trans->max_skb_frags) hw->netdev_features = NETIF_F_HIGHDMA | NETIF_F_SG; - hw->queues = IEEE80211_MAX_QUEUES; + hw->queues = IEEE80211_NUM_ACS; hw->offchannel_tx_hw_queue = IWL_MVM_OFFCHANNEL_QUEUE; hw->radiotap_mcs_details |= IEEE80211_RADIOTAP_MCS_HAVE_FEC | IEEE80211_RADIOTAP_MCS_HAVE_STBC; From 105167830d5fa7ca39d764c28e8f72bef5a16528 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 2 Aug 2021 17:28:29 +0300 Subject: [PATCH 24/95] iwlwifi: mvm: treat MMPDUs in iwl_mvm_mac_tx() as bcast There's no need for all the complicated conditions here, any bufferable MMPDUs or MMPDUs for client interfaces are already coming through the TXQ interface, not iwl_mvm_mac_tx(). Simplify the logic. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210802172232.3939f7c5c43a.I1d5cb5262e31a000023d79acbb897b8db50adf0d@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index f38d2476d5a3..c60c0b49d7f7 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -762,11 +762,11 @@ static void iwl_mvm_mac_tx(struct ieee80211_hw *hw, !test_bit(IWL_MVM_STATUS_ROC_AUX_RUNNING, &mvm->status)) goto drop; - /* treat non-bufferable MMPDUs on AP interfaces as broadcast */ - if ((info->control.vif->type == NL80211_IFTYPE_AP || - info->control.vif->type == NL80211_IFTYPE_ADHOC) && - ieee80211_is_mgmt(hdr->frame_control) && - !ieee80211_is_bufferable_mmpdu(hdr->frame_control)) + /* + * bufferable MMPDUs or MMPDUs on STA interfaces come via TXQs + * so we treat the others as broadcast + */ + if (ieee80211_is_mgmt(hdr->frame_control)) sta = NULL; /* If there is no sta, and it's not offchannel - send through AP */ From e75bc5f3f110aa6c4c372e574bd2c37a8cad495f Mon Sep 17 00:00:00 2001 From: Mukesh Sisodiya Date: Mon, 2 Aug 2021 21:58:47 +0300 Subject: [PATCH 25/95] iwlwifi: yoyo: cleanup internal buffer allocation in D3 With recent changes in the firmware SRAM debug during D3 is enabled by default and need not be enabled by driver. cleaning the code to align the same. Signed-off-by: Mukesh Sisodiya Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210802215208.8535203d0ef7.Ib1695ce5de921b0472d0b1052e729e071573b863@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h | 2 -- drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c | 3 +-- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 6 +----- 3 files changed, 2 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h b/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h index 5a2d9a1f7e73..15a6b3eb999a 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h @@ -249,7 +249,6 @@ struct iwl_fw_ini_hcmd_tlv { * @IWL_FW_INI_ALLOCATION_ID_DBGC1: allocation meant for DBGC1 configuration * @IWL_FW_INI_ALLOCATION_ID_DBGC2: allocation meant for DBGC2 configuration * @IWL_FW_INI_ALLOCATION_ID_DBGC3: allocation meant for DBGC3 configuration - * @IWL_FW_INI_ALLOCATION_ID_INTERNAL: allocation meant for Intreanl SMEM in D3 * @IWL_FW_INI_ALLOCATION_NUM: number of allocation ids */ enum iwl_fw_ini_allocation_id { @@ -257,7 +256,6 @@ enum iwl_fw_ini_allocation_id { IWL_FW_INI_ALLOCATION_ID_DBGC1, IWL_FW_INI_ALLOCATION_ID_DBGC2, IWL_FW_INI_ALLOCATION_ID_DBGC3, - IWL_FW_INI_ALLOCATION_ID_INTERNAL, IWL_FW_INI_ALLOCATION_NUM, }; /* FW_DEBUG_TLV_ALLOCATION_ID_E_VER_1 */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c index c89db7b9585a..dc4bff681e52 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c @@ -131,8 +131,7 @@ static int iwl_dbg_tlv_alloc_buf_alloc(struct iwl_trans *trans, goto err; if (buf_location == IWL_FW_INI_LOCATION_SRAM_PATH && - alloc_id != IWL_FW_INI_ALLOCATION_ID_DBGC1 && - alloc_id != IWL_FW_INI_ALLOCATION_ID_INTERNAL) + alloc_id != IWL_FW_INI_ALLOCATION_ID_DBGC1) goto err; trans->dbg.fw_mon_cfg[alloc_id] = *alloc; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index f1aa31150318..f57d2643135b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -78,7 +78,6 @@ module_exit(iwl_mvm_exit); static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode) { struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); - struct iwl_trans_debug *dbg = &mvm->trans->dbg; u8 radio_cfg_type, radio_cfg_step, radio_cfg_dash; u32 reg_val = 0; u32 phy_config = iwl_mvm_get_phy_config(mvm); @@ -115,10 +114,7 @@ static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode) if (mvm->trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_8000) reg_val |= CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI; - if (iwl_fw_dbg_is_d3_debug_enabled(&mvm->fwrt) || - (iwl_trans_dbg_ini_valid(mvm->trans) && - dbg->fw_mon_cfg[IWL_FW_INI_ALLOCATION_ID_INTERNAL].buf_location) - ) + if (iwl_fw_dbg_is_d3_debug_enabled(&mvm->fwrt)) reg_val |= CSR_HW_IF_CONFIG_REG_D3_DEBUG; iwl_trans_set_bits_mask(mvm->trans, CSR_HW_IF_CONFIG_REG, From d98cee05e3fdc7499583deb224eda52af577eae8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 2 Aug 2021 21:58:48 +0300 Subject: [PATCH 26/95] iwlwifi: split off Bz devices into their own family These devices have some places with different behaviour required, so split them off into their own family as they should be. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210802215208.90257303559f.I4c4342229dcb9513099a3152605f0947423e86dc@changeid Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/cfg/22000.c | 33 ++++++++++++++++--- .../net/wireless/intel/iwlwifi/iwl-config.h | 1 + 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c index 7f1faa9d97b4..fb0ad4e19cc4 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c @@ -215,6 +215,29 @@ static const struct iwl_ht_params iwl_22000_ht_params = { }, \ } +#define IWL_DEVICE_BZ \ + IWL_DEVICE_22000_COMMON, \ + .trans.umac_prph_offset = 0x300000, \ + .trans.device_family = IWL_DEVICE_FAMILY_BZ, \ + .trans.base_params = &iwl_ax210_base_params, \ + .min_txq_size = 128, \ + .gp2_reg_addr = 0xd02c68, \ + .min_256_ba_txq_size = 1024, \ + .mon_dram_regs = { \ + .write_ptr = { \ + .addr = DBGC_CUR_DBGBUF_STATUS, \ + .mask = DBGC_CUR_DBGBUF_STATUS_OFFSET_MSK, \ + }, \ + .cycle_cnt = { \ + .addr = DBGC_DBGBUF_WRAP_AROUND, \ + .mask = 0xffffffff, \ + }, \ + .cur_frag = { \ + .addr = DBGC_CUR_DBGBUF_STATUS, \ + .mask = DBGC_CUR_DBGBUF_STATUS_IDX_MSK, \ + }, \ + } + const struct iwl_cfg_trans_params iwl_qnj_trans_cfg = { .mq_rx_supported = true, .use_tfh = true, @@ -373,7 +396,7 @@ const struct iwl_cfg_trans_params iwl_ma_trans_cfg = { }; const struct iwl_cfg_trans_params iwl_bz_trans_cfg = { - .device_family = IWL_DEVICE_FAMILY_AX210, + .device_family = IWL_DEVICE_FAMILY_BZ, .base_params = &iwl_ax210_base_params, .mq_rx_supported = true, .use_tfh = true, @@ -763,28 +786,28 @@ const struct iwl_cfg iwl_cfg_quz_a0_hr_b0 = { const struct iwl_cfg iwl_cfg_bz_a0_hr_b0 = { .fw_name_pre = IWL_BZ_A_HR_B_FW_PRE, .uhb_supported = true, - IWL_DEVICE_AX210, + IWL_DEVICE_BZ, .num_rbds = IWL_NUM_RBDS_AX210_HE, }; const struct iwl_cfg iwl_cfg_bz_a0_gf_a0 = { .fw_name_pre = IWL_BZ_A_GF_A_FW_PRE, .uhb_supported = true, - IWL_DEVICE_AX210, + IWL_DEVICE_BZ, .num_rbds = IWL_NUM_RBDS_AX210_HE, }; const struct iwl_cfg iwl_cfg_bz_a0_gf4_a0 = { .fw_name_pre = IWL_BZ_A_GF4_A_FW_PRE, .uhb_supported = true, - IWL_DEVICE_AX210, + IWL_DEVICE_BZ, .num_rbds = IWL_NUM_RBDS_AX210_HE, }; const struct iwl_cfg iwl_cfg_bz_a0_mr_a0 = { .fw_name_pre = IWL_BZ_A_MR_A_FW_PRE, .uhb_supported = true, - IWL_DEVICE_AX210, + IWL_DEVICE_BZ, .num_rbds = IWL_NUM_RBDS_AX210_HE, }; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index bf6ee56d4d96..999c6a4ab60e 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -33,6 +33,7 @@ enum iwl_device_family { IWL_DEVICE_FAMILY_9000, IWL_DEVICE_FAMILY_22000, IWL_DEVICE_FAMILY_AX210, + IWL_DEVICE_FAMILY_BZ, }; /* From d01408ee3a2bdfb1a6e0ae086c628dccf27ab811 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 2 Aug 2021 21:58:49 +0300 Subject: [PATCH 27/95] iwlwifi: give Bz devices their own name The real name isn't determined yet, but give them a new name that isn't clashing with older devices. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210802215208.46b86c8074b2.I94d58b8e622ca87658dc05b05483fb954d526eab@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/cfg/22000.c | 1 + drivers/net/wireless/intel/iwlwifi/iwl-config.h | 1 + drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 8 ++++---- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c index fb0ad4e19cc4..a3ff7001e1c3 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c @@ -417,6 +417,7 @@ const char iwl_ax211_name[] = "Intel(R) Wi-Fi 6E AX211 160MHz"; const char iwl_ax221_name[] = "Intel(R) Wi-Fi 6E AX221 160MHz"; const char iwl_ax231_name[] = "Intel(R) Wi-Fi 6E AX231 160MHz"; const char iwl_ax411_name[] = "Intel(R) Wi-Fi 6E AX411 160MHz"; +const char iwl_bz_name[] = "Intel(R) TBD Bz device"; const char iwl_ax200_killer_1650w_name[] = "Killer(R) Wi-Fi 6 AX1650w 160MHz Wireless Network Adapter (200D2W)"; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index 999c6a4ab60e..82e49ead3a44 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -513,6 +513,7 @@ extern const char iwl_ax211_name[]; extern const char iwl_ax221_name[]; extern const char iwl_ax231_name[]; extern const char iwl_ax411_name[]; +extern const char iwl_bz_name[]; #if IS_ENABLED(CONFIG_IWLDVM) extern const struct iwl_cfg iwl5300_agn_cfg; extern const struct iwl_cfg iwl5100_agn_cfg; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index 0b8a0cd3b652..8dc1b8eecb86 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -1093,22 +1093,22 @@ static const struct iwl_dev_info iwl_dev_info_table[] = { IWL_CFG_MAC_TYPE_BZ, IWL_CFG_ANY, IWL_CFG_RF_TYPE_HR2, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, - iwl_cfg_bz_a0_hr_b0, iwl_ax201_name), + iwl_cfg_bz_a0_hr_b0, iwl_bz_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_BZ, IWL_CFG_ANY, IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, - iwl_cfg_bz_a0_gf_a0, iwl_ax211_name), + iwl_cfg_bz_a0_gf_a0, iwl_bz_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_BZ, IWL_CFG_ANY, IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_CDB, - iwl_cfg_bz_a0_gf4_a0, iwl_ax211_name), + iwl_cfg_bz_a0_gf4_a0, iwl_bz_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_BZ, IWL_CFG_ANY, IWL_CFG_RF_TYPE_MR, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, - iwl_cfg_bz_a0_mr_a0, iwl_ax211_name), + iwl_cfg_bz_a0_mr_a0, iwl_bz_name), /* SoF with JF2 */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, From 7e6dffda95d09bf008db0a35aee9045cb78b191f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 2 Aug 2021 21:58:50 +0300 Subject: [PATCH 28/95] iwlwifi: read MAC address from correct place on Bz On Bz devices, the MAC address CSRs changed from 0x380 to 0x30. Change the boolean configuration "mac_addr_from_csr" to hold the base address instead, and set it correctly for the different devices using this feature. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210802215208.928c7983f014.Ic5ba92d98946c1b4640280a05dcfd75119c0f0c0@changeid Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/cfg/22000.c | 42 ++++++++++++++++++- drivers/net/wireless/intel/iwlwifi/cfg/9000.c | 2 +- .../net/wireless/intel/iwlwifi/iwl-config.h | 6 ++- drivers/net/wireless/intel/iwlwifi/iwl-csr.h | 10 ++--- .../wireless/intel/iwlwifi/iwl-nvm-parse.c | 10 +++-- 5 files changed, 56 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c index a3ff7001e1c3..cb4c1d23fc92 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c @@ -154,7 +154,7 @@ static const struct iwl_ht_params iwl_22000_ht_params = { .apmg_not_supported = true, \ .trans.mq_rx_supported = true, \ .vht_mu_mimo_supported = true, \ - .mac_addr_from_csr = true, \ + .mac_addr_from_csr = 0x380, \ .ht_params = &iwl_22000_ht_params, \ .nvm_ver = IWL_22000_NVM_VERSION, \ .trans.use_tfh = true, \ @@ -215,8 +215,46 @@ static const struct iwl_ht_params iwl_22000_ht_params = { }, \ } +#define IWL_DEVICE_BZ_COMMON \ + .ucode_api_max = IWL_22000_UCODE_API_MAX, \ + .ucode_api_min = IWL_22000_UCODE_API_MIN, \ + .led_mode = IWL_LED_RF_STATE, \ + .nvm_hw_section_num = 10, \ + .non_shared_ant = ANT_B, \ + .dccm_offset = IWL_22000_DCCM_OFFSET, \ + .dccm_len = IWL_22000_DCCM_LEN, \ + .dccm2_offset = IWL_22000_DCCM2_OFFSET, \ + .dccm2_len = IWL_22000_DCCM2_LEN, \ + .smem_offset = IWL_22000_SMEM_OFFSET, \ + .smem_len = IWL_22000_SMEM_LEN, \ + .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, \ + .apmg_not_supported = true, \ + .trans.mq_rx_supported = true, \ + .vht_mu_mimo_supported = true, \ + .mac_addr_from_csr = 0x30, \ + .ht_params = &iwl_22000_ht_params, \ + .nvm_ver = IWL_22000_NVM_VERSION, \ + .trans.use_tfh = true, \ + .trans.rf_id = true, \ + .trans.gen2 = true, \ + .nvm_type = IWL_NVM_EXT, \ + .dbgc_supported = true, \ + .min_umac_error_event_table = 0x400000, \ + .d3_debug_data_base_addr = 0x401000, \ + .d3_debug_data_length = 60 * 1024, \ + .mon_smem_regs = { \ + .write_ptr = { \ + .addr = LDBG_M2S_BUF_WPTR, \ + .mask = LDBG_M2S_BUF_WPTR_VAL_MSK, \ + }, \ + .cycle_cnt = { \ + .addr = LDBG_M2S_BUF_WRAP_CNT, \ + .mask = LDBG_M2S_BUF_WRAP_CNT_VAL_MSK, \ + }, \ + } + #define IWL_DEVICE_BZ \ - IWL_DEVICE_22000_COMMON, \ + IWL_DEVICE_BZ_COMMON, \ .trans.umac_prph_offset = 0x300000, \ .trans.device_family = IWL_DEVICE_FAMILY_BZ, \ .trans.base_params = &iwl_ax210_base_params, \ diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/9000.c b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c index 871533beff30..7a7ca06d46c1 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/9000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c @@ -89,7 +89,7 @@ static const struct iwl_tt_params iwl9000_tt_params = { .apmg_not_supported = true, \ .num_rbds = 512, \ .vht_mu_mimo_supported = true, \ - .mac_addr_from_csr = true, \ + .mac_addr_from_csr = 0x380, \ .nvm_type = IWL_NVM_EXT, \ .dbgc_supported = true, \ .min_umac_error_event_table = 0x800000, \ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index 82e49ead3a44..7eb534df5331 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -322,7 +322,7 @@ struct iwl_fw_mon_regs { * @host_interrupt_operation_mode: device needs host interrupt operation * mode set * @nvm_hw_section_num: the ID of the HW NVM section - * @mac_addr_from_csr: read HW address from CSR registers + * @mac_addr_from_csr: read HW address from CSR registers at this offset * @features: hw features, any combination of feature_passlist * @pwr_tx_backoffs: translation table between power limits and backoffs * @max_tx_agg_size: max TX aggregation size of the ADDBA request/response @@ -344,6 +344,8 @@ struct iwl_fw_mon_regs { * supports 256 BA aggregation * @num_rbds: number of receive buffer descriptors to use * (only used for multi-queue capable devices) + * @mac_addr_csr_base: CSR base register for MAC address access, if not set + * assume 0x380 * * We enable the driver to be backward compatible wrt. hardware features. * API differences in uCode shouldn't be handled here but through TLVs @@ -379,7 +381,7 @@ struct iwl_cfg { internal_wimax_coex:1, host_interrupt_operation_mode:1, high_temp:1, - mac_addr_from_csr:1, + mac_addr_from_csr:10, lp_xtal_workaround:1, disable_dummy_notification:1, apmg_not_supported:1, diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h index 47e5a17c0f48..004a1b02bea8 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h @@ -604,10 +604,10 @@ enum msix_hw_int_causes { * HW address related registers * *****************************************************************************/ -#define CSR_ADDR_BASE (0x380) -#define CSR_MAC_ADDR0_OTP (CSR_ADDR_BASE) -#define CSR_MAC_ADDR1_OTP (CSR_ADDR_BASE + 4) -#define CSR_MAC_ADDR0_STRAP (CSR_ADDR_BASE + 8) -#define CSR_MAC_ADDR1_STRAP (CSR_ADDR_BASE + 0xC) +#define CSR_ADDR_BASE(trans) ((trans)->cfg->mac_addr_from_csr) +#define CSR_MAC_ADDR0_OTP(trans) (CSR_ADDR_BASE(trans) + 0x00) +#define CSR_MAC_ADDR1_OTP(trans) (CSR_ADDR_BASE(trans) + 0x04) +#define CSR_MAC_ADDR0_STRAP(trans) (CSR_ADDR_BASE(trans) + 0x08) +#define CSR_MAC_ADDR1_STRAP(trans) (CSR_ADDR_BASE(trans) + 0x0c) #endif /* !__iwl_csr_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c index a6de34358a3f..2fbb7cdf00a4 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c @@ -964,8 +964,10 @@ static void iwl_flip_hw_address(__le32 mac_addr0, __le32 mac_addr1, u8 *dest) static void iwl_set_hw_address_from_csr(struct iwl_trans *trans, struct iwl_nvm_data *data) { - __le32 mac_addr0 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR0_STRAP)); - __le32 mac_addr1 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR1_STRAP)); + __le32 mac_addr0 = cpu_to_le32(iwl_read32(trans, + CSR_MAC_ADDR0_STRAP(trans))); + __le32 mac_addr1 = cpu_to_le32(iwl_read32(trans, + CSR_MAC_ADDR1_STRAP(trans))); iwl_flip_hw_address(mac_addr0, mac_addr1, data->hw_addr); /* @@ -975,8 +977,8 @@ static void iwl_set_hw_address_from_csr(struct iwl_trans *trans, if (is_valid_ether_addr(data->hw_addr)) return; - mac_addr0 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR0_OTP)); - mac_addr1 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR1_OTP)); + mac_addr0 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR0_OTP(trans))); + mac_addr1 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR1_OTP(trans))); iwl_flip_hw_address(mac_addr0, mac_addr1, data->hw_addr); } From 9ce041f5966fd07a4326b81add4ae472400351cd Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 2 Aug 2021 21:58:51 +0300 Subject: [PATCH 29/95] iwlwifi: pcie: implement Bz device startup Device startup changed in Bz, some register bits moved around. Change the code accordingly. The new Bz hardware changes also the way we wake it (grab NIC access) and the way we disable bus mastering, update the driver code accordingly. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210802215208.00a137364a95.I059a2abac948965458862941ee7db6a2e1076fa6@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-csr.h | 8 ++++ drivers/net/wireless/intel/iwlwifi/iwl-io.c | 17 ++++++--- .../wireless/intel/iwlwifi/pcie/trans-gen2.c | 24 ++++++++++-- .../net/wireless/intel/iwlwifi/pcie/trans.c | 38 ++++++++++++++----- 4 files changed, 68 insertions(+), 19 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h index 004a1b02bea8..704ff2ada122 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h @@ -266,6 +266,14 @@ #define CSR_GP_CNTRL_REG_FLAG_RFKILL_WAKE_L1A_EN (0x04000000) #define CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW (0x08000000) +/* From Bz we use these instead during init/reset flow */ +#define CSR_GP_CNTRL_REG_FLAG_MAC_INIT BIT(6) +#define CSR_GP_CNTRL_REG_FLAG_ROM_START BIT(7) +#define CSR_GP_CNTRL_REG_FLAG_MAC_STATUS BIT(20) +#define CSR_GP_CNTRL_REG_FLAG_BZ_MAC_ACCESS_REQ BIT(21) +#define CSR_GP_CNTRL_REG_FLAG_BUS_MASTER_DISABLE_STATUS BIT(28) +#define CSR_GP_CNTRL_REG_FLAG_BUS_MASTER_DISABLE_REQ BIT(29) +#define CSR_GP_CNTRL_REG_FLAG_SW_RESET BIT(31) /* HW REV */ #define CSR_HW_REV_DASH(_val) (((_val) & 0x0000003) >> 0) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-io.c b/drivers/net/wireless/intel/iwlwifi/iwl-io.c index 2a0be1fafdf9..dba54b3297d1 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-io.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-io.c @@ -398,6 +398,7 @@ int iwl_dump_fh(struct iwl_trans *trans, char **buf) int iwl_finish_nic_init(struct iwl_trans *trans, const struct iwl_cfg_trans_params *cfg_trans) { + u32 poll_ready; int err; if (cfg_trans->bisr_workaround) { @@ -409,7 +410,16 @@ int iwl_finish_nic_init(struct iwl_trans *trans, * Set "initialization complete" bit to move adapter from * D0U* --> D0A* (powered-up active) state. */ - iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + if (cfg_trans->device_family >= IWL_DEVICE_FAMILY_BZ) { + iwl_set_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY | + CSR_GP_CNTRL_REG_FLAG_MAC_INIT); + poll_ready = CSR_GP_CNTRL_REG_FLAG_MAC_STATUS; + } else { + iwl_set_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + poll_ready = CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY; + } if (cfg_trans->device_family == IWL_DEVICE_FAMILY_8000) udelay(2); @@ -419,10 +429,7 @@ int iwl_finish_nic_init(struct iwl_trans *trans, * device-internal resources is supported, e.g. iwl_write_prph() * and accesses to uCode SRAM. */ - err = iwl_poll_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - 25000); + err = iwl_poll_bit(trans, CSR_GP_CNTRL, poll_ready, poll_ready, 25000); if (err < 0) IWL_DEBUG_INFO(trans, "Failed to wake NIC\n"); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c index a266a35ff928..fa416b42bd9d 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c @@ -87,7 +87,12 @@ static void iwl_pcie_gen2_apm_stop(struct iwl_trans *trans, bool op_mode_leave) * Clear "initialization complete" bit to move adapter from * D0A* (powered-up Active) --> D0U* (Uninitialized) state. */ - iwl_clear_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) + iwl_clear_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_INIT); + else + iwl_clear_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_INIT_DONE); } static void iwl_trans_pcie_fw_reset_handshake(struct iwl_trans *trans) @@ -159,9 +164,17 @@ void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans) iwl_pcie_ctxt_info_free(trans); /* Make sure (redundant) we've released our request to stay awake */ - iwl_clear_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) + iwl_clear_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_BZ_MAC_ACCESS_REQ); + else + iwl_clear_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) { + iwl_set_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_SW_RESET); + } /* Stop the device, and put it in low power state */ iwl_pcie_gen2_apm_stop(trans, false); @@ -441,7 +454,10 @@ int iwl_trans_pcie_gen2_start_fw(struct iwl_trans *trans, iwl_pcie_set_ltr(trans); - if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) + if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) + iwl_set_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_ROM_START); + else if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) iwl_write_umac_prph(trans, UREG_CPU_INIT_RUN, 1); else iwl_write_prph(trans, UREG_CPU_INIT_RUN, 1); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 65cc25cbb9ec..86a949440486 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -449,11 +449,23 @@ void iwl_pcie_apm_stop_master(struct iwl_trans *trans) int ret; /* stop device's busmaster DMA activity */ - iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER); - ret = iwl_poll_bit(trans, CSR_RESET, - CSR_RESET_REG_FLAG_MASTER_DISABLED, - CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); + if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) { + iwl_set_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_BUS_MASTER_DISABLE_REQ); + + ret = iwl_poll_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_BUS_MASTER_DISABLE_STATUS, + CSR_GP_CNTRL_REG_FLAG_BUS_MASTER_DISABLE_STATUS, + 100); + } else { + iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER); + + ret = iwl_poll_bit(trans, CSR_RESET, + CSR_RESET_REG_FLAG_MASTER_DISABLED, + CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); + } + if (ret < 0) IWL_WARN(trans, "Master Disable Timed Out, 100 usec\n"); @@ -1995,15 +2007,24 @@ bool __iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans) { int ret; struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + u32 write = CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ; + u32 mask = CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY | + CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP; + u32 poll = CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN; spin_lock(&trans_pcie->reg_lock); if (trans_pcie->cmd_hold_nic_awake) goto out; + if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) { + write = CSR_GP_CNTRL_REG_FLAG_BZ_MAC_ACCESS_REQ; + mask = CSR_GP_CNTRL_REG_FLAG_MAC_STATUS; + poll = CSR_GP_CNTRL_REG_FLAG_MAC_STATUS; + } + /* this bit wakes up the NIC */ - __iwl_trans_pcie_set_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + __iwl_trans_pcie_set_bit(trans, CSR_GP_CNTRL, write); if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_8000) udelay(2); @@ -2027,10 +2048,7 @@ bool __iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans) * 5000 series and later (including 1000 series) have non-volatile SRAM, * and do not save/restore SRAM when power cycling. */ - ret = iwl_poll_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN, - (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY | - CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 15000); + ret = iwl_poll_bit(trans, CSR_GP_CNTRL, poll, mask, 15000); if (unlikely(ret < 0)) { u32 cntrl = iwl_read32(trans, CSR_GP_CNTRL); From 6c0795f1a52410f2dccc63cd0993ae1a38856c77 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 2 Aug 2021 21:58:52 +0300 Subject: [PATCH 30/95] iwlwifi: implement Bz NMI behaviour The method to NMI the firmware also changed in Bz devices, implement the new logic. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210802215208.c9bd2034dc05.I983c25caa09c3776c7640fff73fe739362ecc5b6@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-csr.h | 4 ++++ drivers/net/wireless/intel/iwlwifi/iwl-io.c | 5 ++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h index 704ff2ada122..cf796403c45c 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h @@ -104,6 +104,10 @@ /* GIO Chicken Bits (PCI Express bus link power management) */ #define CSR_GIO_CHICKEN_BITS (CSR_BASE+0x100) +/* Doorbell NMI (since Bz) */ +#define CSR_DOORBELL_VECTOR (CSR_BASE + 0x130) +#define CSR_DOORBELL_VECTOR_NMI BIT(1) + /* host chicken bits */ #define CSR_HOST_CHICKEN (CSR_BASE + 0x204) #define CSR_HOST_CHICKEN_PM_IDLE_SRC_DIS_SB_PME BIT(19) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-io.c b/drivers/net/wireless/intel/iwlwifi/iwl-io.c index dba54b3297d1..2517c4ae07ab 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-io.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-io.c @@ -213,9 +213,12 @@ void iwl_force_nmi(struct iwl_trans *trans) else if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210) iwl_write_umac_prph(trans, UREG_NIC_SET_NMI_DRIVER, UREG_NIC_SET_NMI_DRIVER_NMI_FROM_DRIVER); - else + else if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_BZ) iwl_write_umac_prph(trans, UREG_DOORBELL_TO_ISR6, UREG_DOORBELL_TO_ISR6_NMI_BIT); + else + iwl_write32(trans, CSR_DOORBELL_VECTOR, + CSR_DOORBELL_VECTOR_NMI); } IWL_EXPORT_SYMBOL(iwl_force_nmi); From 9de168a01279db655052a19b56662656bc94ea89 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 2 Aug 2021 21:58:53 +0300 Subject: [PATCH 31/95] iwlwifi: pcie: implement Bz reset flow Bz device reset flow changed, now the hardware (instead of firmware) will reset the PCI bus etc., this can take up to 100ms. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210802215208.df30875c6ff9.I962ed0f2c3358903dc6ba1abb65726ce5acbbd48@changeid Signed-off-by: Luca Coelho --- .../wireless/intel/iwlwifi/pcie/trans-gen2.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c index fa416b42bd9d..bf0c32a74ca4 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c @@ -131,9 +131,21 @@ void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans) if (trans_pcie->is_down) return; - if (trans_pcie->fw_reset_handshake && - trans->state >= IWL_TRANS_FW_STARTED) - iwl_trans_pcie_fw_reset_handshake(trans); + if (trans->state >= IWL_TRANS_FW_STARTED) { + if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) { + iwl_set_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_BUS_MASTER_DISABLE_REQ); + iwl_poll_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_BUS_MASTER_DISABLE_STATUS, + CSR_GP_CNTRL_REG_FLAG_BUS_MASTER_DISABLE_STATUS, + 5000); + msleep(100); + iwl_set_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_SW_RESET); + } else if (trans_pcie->fw_reset_handshake) { + iwl_trans_pcie_fw_reset_handshake(trans); + } + } trans_pcie->is_down = true; From 35fc5feca7b24b97e828e6e6a4243b4b9b0131f8 Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Mon, 2 Aug 2021 21:58:54 +0300 Subject: [PATCH 32/95] iwlwifi: mvm: Fix umac scan request probe parameters Both 'iwl_scan_probe_params_v3' and 'iwl_scan_probe_params_v4' wrongly addressed the 'bssid_array' field which should supposed to be any array of BSSIDs each of size ETH_ALEN and not the opposite. Fix it. Signed-off-by: Ilan Peer Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210802215208.04146f24794f.I90726440ddff75013e9fecbe9fa1a05c69e3f17b@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/api/scan.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h index b2605aefc290..8b200379f7c2 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2012-2014, 2018-2020 Intel Corporation + * Copyright (C) 2012-2014, 2018-2021 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -874,7 +874,7 @@ struct iwl_scan_probe_params_v3 { u8 reserved; struct iwl_ssid_ie direct_scan[PROBE_OPTION_MAX]; __le32 short_ssid[SCAN_SHORT_SSID_MAX_SIZE]; - u8 bssid_array[ETH_ALEN][SCAN_BSSID_MAX_SIZE]; + u8 bssid_array[SCAN_BSSID_MAX_SIZE][ETH_ALEN]; } __packed; /* SCAN_PROBE_PARAMS_API_S_VER_3 */ /** @@ -894,7 +894,7 @@ struct iwl_scan_probe_params_v4 { __le16 reserved; struct iwl_ssid_ie direct_scan[PROBE_OPTION_MAX]; __le32 short_ssid[SCAN_SHORT_SSID_MAX_SIZE]; - u8 bssid_array[ETH_ALEN][SCAN_BSSID_MAX_SIZE]; + u8 bssid_array[SCAN_BSSID_MAX_SIZE][ETH_ALEN]; } __packed; /* SCAN_PROBE_PARAMS_API_S_VER_4 */ #define SCAN_MAX_NUM_CHANS_V3 67 From 199d895f47601fcd2c24d484e5ce1f5d283b5d4f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 2 Aug 2021 21:58:55 +0300 Subject: [PATCH 33/95] iwlwifi: mvm: support new station key API The new version 3 of the station key API has gotten rid of the strange hole in the sequence counter values, support that. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210802215208.39a00ca1a1a6.Ifb4adeb4edd2b72232046dd2d59c0b3732f497c2@changeid Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/fw/api/sta.h | 8 +++-- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 31 ++++++++++--------- 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/sta.h b/drivers/net/wireless/intel/iwlwifi/fw/api/sta.h index 12b2f2c48387..f1a3e14880e7 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/sta.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/sta.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2012-2014, 2018-2020 Intel Corporation + * Copyright (C) 2012-2014, 2018-2021 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -384,13 +384,17 @@ struct iwl_mvm_add_sta_key_cmd_v1 { * @rx_mic_key: TKIP RX unicast or multicast key * @tx_mic_key: TKIP TX key * @transmit_seq_cnt: TSC, transmit packet number + * + * Note: This is used for both v2 and v3, the difference being + * in the way the common.rx_secur_seq_cnt is used, in v2 that's + * the strange hole format, in v3 it's just a u64. */ struct iwl_mvm_add_sta_key_cmd { struct iwl_mvm_add_sta_key_common common; __le64 rx_mic_key; __le64 tx_mic_key; __le64 transmit_seq_cnt; -} __packed; /* ADD_MODIFY_STA_KEY_API_S_VER_2 */ +} __packed; /* ADD_MODIFY_STA_KEY_API_S_VER_2, ADD_MODIFY_STA_KEY_API_S_VER_3 */ /** * enum iwl_mvm_add_sta_rsp_status - status in the response to ADD_STA command diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 84953d7e5f09..7e9951993af8 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -3228,6 +3228,9 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm, int i, size; bool new_api = fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_TKIP_MIC_KEYS); + int api_ver = iwl_fw_lookup_cmd_ver(mvm->fw, LONG_GROUP, + ADD_STA_KEY, + new_api ? 2 : 1); if (sta_id == IWL_MVM_INVALID_STA) return -EINVAL; @@ -3240,7 +3243,7 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm, switch (key->cipher) { case WLAN_CIPHER_SUITE_TKIP: key_flags |= cpu_to_le16(STA_KEY_FLG_TKIP); - if (new_api) { + if (api_ver >= 2) { memcpy((void *)&u.cmd.tx_mic_key, &key->key[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY], IWL_MIC_KEY_SIZE); @@ -3261,7 +3264,7 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm, case WLAN_CIPHER_SUITE_CCMP: key_flags |= cpu_to_le16(STA_KEY_FLG_CCM); memcpy(u.cmd.common.key, key->key, key->keylen); - if (new_api) + if (api_ver >= 2) pn = atomic64_read(&key->tx_pn); break; case WLAN_CIPHER_SUITE_WEP104: @@ -3277,7 +3280,7 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm, case WLAN_CIPHER_SUITE_GCMP: key_flags |= cpu_to_le16(STA_KEY_FLG_GCMP); memcpy(u.cmd.common.key, key->key, key->keylen); - if (new_api) + if (api_ver >= 2) pn = atomic64_read(&key->tx_pn); break; default: @@ -3303,28 +3306,28 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm, struct ieee80211_key_seq seq = {}; u8 _rx_pn[IEEE80211_MAX_PN_LEN] = {}, *rx_pn = _rx_pn; int rx_pn_len = 8; + /* there's a hole at 2/3 in FW format depending on version */ + int hole = api_ver >= 3 ? 0 : 2; ieee80211_get_key_rx_seq(key, i, &seq); if (key->cipher == WLAN_CIPHER_SUITE_TKIP) { rx_pn[0] = seq.tkip.iv16; rx_pn[1] = seq.tkip.iv16 >> 8; - /* hole at 2/3 in FW format */ - rx_pn[4] = seq.tkip.iv32; - rx_pn[5] = seq.tkip.iv32 >> 8; - rx_pn[6] = seq.tkip.iv32 >> 16; - rx_pn[7] = seq.tkip.iv32 >> 24; + rx_pn[2 + hole] = seq.tkip.iv32; + rx_pn[3 + hole] = seq.tkip.iv32 >> 8; + rx_pn[4 + hole] = seq.tkip.iv32 >> 16; + rx_pn[5 + hole] = seq.tkip.iv32 >> 24; } else if (key_flags & cpu_to_le16(STA_KEY_FLG_EXT)) { rx_pn = seq.hw.seq; rx_pn_len = seq.hw.seq_len; } else { rx_pn[0] = seq.ccmp.pn[0]; rx_pn[1] = seq.ccmp.pn[1]; - /* hole at 2/3 in FW format */ - rx_pn[4] = seq.ccmp.pn[2]; - rx_pn[5] = seq.ccmp.pn[3]; - rx_pn[6] = seq.ccmp.pn[4]; - rx_pn[7] = seq.ccmp.pn[5]; + rx_pn[2 + hole] = seq.ccmp.pn[2]; + rx_pn[3 + hole] = seq.ccmp.pn[3]; + rx_pn[4 + hole] = seq.ccmp.pn[4]; + rx_pn[5 + hole] = seq.ccmp.pn[5]; } if (iwl_mvm_pn_cmp(rx_pn, (u8 *)&u.cmd.common.rx_secur_seq_cnt, @@ -3333,7 +3336,7 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm, rx_pn_len); } - if (new_api) { + if (api_ver >= 2) { u.cmd.transmit_seq_cnt = cpu_to_le64(pn); size = sizeof(u.cmd); } else { From 95a62c331f6ac38bd22b0353cab9d719d031c892 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 2 Aug 2021 21:58:56 +0300 Subject: [PATCH 34/95] iwlwifi: mvm: simplify __iwl_mvm_set_sta_key() There's no need to differentiate identical default and cipher type cases, nor do we really need to have a 'ret' variable. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210802215208.e89178b22fbf.I4d62baad9a9fdfd5c645a3cc5dbffb22feab5033@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 26 ++++++-------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 7e9951993af8..a64874c05ced 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -3473,7 +3473,6 @@ static int __iwl_mvm_set_sta_key(struct iwl_mvm *mvm, u8 key_offset, bool mcast) { - int ret; const u8 *addr; struct ieee80211_key_seq seq; u16 p1k[5]; @@ -3495,30 +3494,19 @@ static int __iwl_mvm_set_sta_key(struct iwl_mvm *mvm, return -EINVAL; } - switch (keyconf->cipher) { - case WLAN_CIPHER_SUITE_TKIP: + if (keyconf->cipher == WLAN_CIPHER_SUITE_TKIP) { addr = iwl_mvm_get_mac_addr(mvm, vif, sta); /* get phase 1 key from mac80211 */ ieee80211_get_key_rx_seq(keyconf, 0, &seq); ieee80211_get_tkip_rx_p1k(keyconf, addr, seq.tkip.iv32, p1k); - ret = iwl_mvm_send_sta_key(mvm, sta_id, keyconf, mcast, - seq.tkip.iv32, p1k, 0, key_offset, - mfp); - break; - case WLAN_CIPHER_SUITE_CCMP: - case WLAN_CIPHER_SUITE_WEP40: - case WLAN_CIPHER_SUITE_WEP104: - case WLAN_CIPHER_SUITE_GCMP: - case WLAN_CIPHER_SUITE_GCMP_256: - ret = iwl_mvm_send_sta_key(mvm, sta_id, keyconf, mcast, - 0, NULL, 0, key_offset, mfp); - break; - default: - ret = iwl_mvm_send_sta_key(mvm, sta_id, keyconf, mcast, - 0, NULL, 0, key_offset, mfp); + + return iwl_mvm_send_sta_key(mvm, sta_id, keyconf, mcast, + seq.tkip.iv32, p1k, 0, key_offset, + mfp); } - return ret; + return iwl_mvm_send_sta_key(mvm, sta_id, keyconf, mcast, + 0, NULL, 0, key_offset, mfp); } int iwl_mvm_set_sta_key(struct iwl_mvm *mvm, From 0419e5e672d6d931fcaa83f7a715364ab4dc1ac9 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 5 Aug 2021 13:19:23 +0300 Subject: [PATCH 35/95] iwlwifi: mvm: d3: separate TKIP data from key iteration We do a key iteration to program the keys, and while at it we also collect the data necessary for TKIP. This code has all kinds of dependencies on the firmware API though, so take out the TKIP phase 1 key generation and do that in a separate key iteration only if necessary. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210805130823.80721fc0fd61.I5a8fbba4e3a9606f700ee41c7a4244dd5e2af935@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 132 ++++++++++++-------- 1 file changed, 83 insertions(+), 49 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 6a259d867d90..14c24f3e0717 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -103,9 +103,8 @@ static const u8 *iwl_mvm_find_max_pn(struct ieee80211_key_conf *key, struct wowlan_key_data { struct iwl_wowlan_rsc_tsc_params_cmd *rsc_tsc; - struct iwl_wowlan_tkip_params_cmd *tkip; struct iwl_wowlan_kek_kck_material_cmd_v4 *kek_kck_cmd; - bool error, use_rsc_tsc, use_tkip, configure_keys; + bool error, use_rsc_tsc, configure_keys; int wep_key_idx; }; @@ -120,11 +119,7 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw, struct wowlan_key_data *data = _data; struct aes_sc *aes_sc, *aes_tx_sc = NULL; struct tkip_sc *tkip_sc, *tkip_tx_sc = NULL; - struct iwl_p1k_cache *rx_p1ks; - u8 *rx_mic_key; struct ieee80211_key_seq seq; - u32 cur_rx_iv32 = 0; - u16 p1k[IWL_P1K_SIZE]; int ret, i; switch (key->cipher) { @@ -204,26 +199,12 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw, tkip_tx_sc = &data->rsc_tsc->params.all_tsc_rsc.tkip.tsc; - rx_p1ks = data->tkip->rx_uni; - pn64 = atomic64_read(&key->tx_pn); tkip_tx_sc->iv16 = cpu_to_le16(TKIP_PN_TO_IV16(pn64)); tkip_tx_sc->iv32 = cpu_to_le32(TKIP_PN_TO_IV32(pn64)); - - ieee80211_get_tkip_p1k_iv(key, TKIP_PN_TO_IV32(pn64), - p1k); - iwl_mvm_convert_p1k(p1k, data->tkip->tx.p1k); - - memcpy(data->tkip->mic_keys.tx, - &key->key[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY], - IWL_MIC_KEY_SIZE); - - rx_mic_key = data->tkip->mic_keys.rx_unicast; } else { tkip_sc = data->rsc_tsc->params.all_tsc_rsc.tkip.multicast_rsc; - rx_p1ks = data->tkip->rx_multi; - rx_mic_key = data->tkip->mic_keys.rx_mcast; data->kek_kck_cmd->gtk_cipher = cpu_to_le32(STA_KEY_FLG_TKIP); } @@ -237,23 +218,8 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw, ieee80211_get_key_rx_seq(key, i, &seq); tkip_sc[i].iv16 = cpu_to_le16(seq.tkip.iv16); tkip_sc[i].iv32 = cpu_to_le32(seq.tkip.iv32); - /* wrapping isn't allowed, AP must rekey */ - if (seq.tkip.iv32 > cur_rx_iv32) - cur_rx_iv32 = seq.tkip.iv32; } - ieee80211_get_tkip_rx_p1k(key, vif->bss_conf.bssid, - cur_rx_iv32, p1k); - iwl_mvm_convert_p1k(p1k, rx_p1ks[0].p1k); - ieee80211_get_tkip_rx_p1k(key, vif->bss_conf.bssid, - cur_rx_iv32 + 1, p1k); - iwl_mvm_convert_p1k(p1k, rx_p1ks[1].p1k); - - memcpy(rx_mic_key, - &key->key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY], - IWL_MIC_KEY_SIZE); - - data->use_tkip = true; data->use_rsc_tsc = true; break; case WLAN_CIPHER_SUITE_CCMP: @@ -352,6 +318,72 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw, } } +struct wowlan_key_tkip_data { + struct iwl_wowlan_tkip_params_cmd tkip; + bool have_tkip_keys; +}; + +static void iwl_mvm_wowlan_get_tkip_data(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *key, + void *_data) +{ + struct wowlan_key_tkip_data *data = _data; + struct iwl_p1k_cache *rx_p1ks; + u8 *rx_mic_key; + struct ieee80211_key_seq seq; + u32 cur_rx_iv32 = 0; + u16 p1k[IWL_P1K_SIZE]; + int i; + + switch (key->cipher) { + default: + break; + case WLAN_CIPHER_SUITE_TKIP: + if (sta) { + u64 pn64; + + rx_p1ks = data->tkip.rx_uni; + + pn64 = atomic64_read(&key->tx_pn); + + ieee80211_get_tkip_p1k_iv(key, TKIP_PN_TO_IV32(pn64), + p1k); + iwl_mvm_convert_p1k(p1k, data->tkip.tx.p1k); + + memcpy(data->tkip.mic_keys.tx, + &key->key[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY], + IWL_MIC_KEY_SIZE); + + rx_mic_key = data->tkip.mic_keys.rx_unicast; + } else { + rx_p1ks = data->tkip.rx_multi; + rx_mic_key = data->tkip.mic_keys.rx_mcast; + } + + for (i = 0; i < IWL_NUM_RSC; i++) { + /* wrapping isn't allowed, AP must rekey */ + if (seq.tkip.iv32 > cur_rx_iv32) + cur_rx_iv32 = seq.tkip.iv32; + } + + ieee80211_get_tkip_rx_p1k(key, vif->bss_conf.bssid, + cur_rx_iv32, p1k); + iwl_mvm_convert_p1k(p1k, rx_p1ks[0].p1k); + ieee80211_get_tkip_rx_p1k(key, vif->bss_conf.bssid, + cur_rx_iv32 + 1, p1k); + iwl_mvm_convert_p1k(p1k, rx_p1ks[1].p1k); + + memcpy(rx_mic_key, + &key->key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY], + IWL_MIC_KEY_SIZE); + + data->have_tkip_keys = true; + break; + } +} + static int iwl_mvm_send_patterns_v1(struct iwl_mvm *mvm, struct cfg80211_wowlan *wowlan) { @@ -718,14 +750,11 @@ static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm, { struct iwl_wowlan_kek_kck_material_cmd_v4 kek_kck_cmd = {}; struct iwl_wowlan_kek_kck_material_cmd_v4 *_kek_kck_cmd = &kek_kck_cmd; - struct iwl_wowlan_tkip_params_cmd tkip_cmd = {}; bool unified = fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG); struct wowlan_key_data key_data = { .configure_keys = !unified, .use_rsc_tsc = false, - .tkip = &tkip_cmd, - .use_tkip = false, .kek_kck_cmd = _kek_kck_cmd, }; struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); @@ -785,17 +814,17 @@ static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm, goto out; } - if (key_data.use_tkip && - !fw_has_api(&mvm->fw->ucode_capa, + if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_TKIP_MIC_KEYS)) { int ver = iwl_fw_lookup_cmd_ver(mvm->fw, LONG_GROUP, WOWLAN_TKIP_PARAM, IWL_FW_CMD_VER_UNKNOWN); + struct wowlan_key_tkip_data tkip_data = {}; int size; if (ver == 2) { - size = sizeof(tkip_cmd); - key_data.tkip->sta_id = + size = sizeof(tkip_data.tkip); + tkip_data.tkip.sta_id = cpu_to_le32(mvmvif->ap_sta_id); } else if (ver == 1 || ver == IWL_FW_CMD_VER_UNKNOWN) { size = sizeof(struct iwl_wowlan_tkip_params_cmd_ver_1); @@ -805,13 +834,18 @@ static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm, goto out; } - /* send relevant data according to CMD version */ - ret = iwl_mvm_send_cmd_pdu(mvm, - WOWLAN_TKIP_PARAM, - cmd_flags, size, - &tkip_cmd); - if (ret) - goto out; + ieee80211_iter_keys(mvm->hw, vif, iwl_mvm_wowlan_get_tkip_data, + &tkip_data); + + if (tkip_data.have_tkip_keys) { + /* send relevant data according to CMD version */ + ret = iwl_mvm_send_cmd_pdu(mvm, + WOWLAN_TKIP_PARAM, + cmd_flags, size, + &tkip_data.tkip); + if (ret) + goto out; + } } /* configure rekey data only if offloaded rekey is supported (d3) */ From 398760aa9679bbf985e00e1502f1d63d7fd25a67 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 5 Aug 2021 13:19:24 +0300 Subject: [PATCH 36/95] iwlwifi: mvm: d3: remove fixed cmd_flags argument We only ever pass cmd_flags == CMD_ASYNC, so might as well not have the argument. Remove it. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210805130823.9130db608b77.I352cbc35fefd98cc00aa0c69ea43863942aa62f5@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 23 ++++++++------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 14c24f3e0717..0d87de66bf8d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -745,8 +745,7 @@ iwl_mvm_get_wowlan_config(struct iwl_mvm *mvm, } static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - u32 cmd_flags) + struct ieee80211_vif *vif) { struct iwl_wowlan_kek_kck_material_cmd_v4 kek_kck_cmd = {}; struct iwl_wowlan_kek_kck_material_cmd_v4 *_kek_kck_cmd = &kek_kck_cmd; @@ -772,10 +771,9 @@ static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm, * required locks. */ /* - * Note that currently we don't propagate cmd_flags - * to the iterator. In case of key_data.configure_keys, - * all the configured commands are SYNC, and - * iwl_mvm_wowlan_program_keys() will take care of + * Note that currently we don't use CMD_ASYNC in the iterator. + * In case of key_data.configure_keys, all the configured commands + * are SYNC, and iwl_mvm_wowlan_program_keys() will take care of * locking/unlocking mvm->mutex. */ ieee80211_iter_keys(mvm->hw, vif, iwl_mvm_wowlan_program_keys, @@ -806,8 +804,7 @@ static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm, } ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_TSC_RSC_PARAM, - cmd_flags, - size, + CMD_ASYNC, size, key_data.rsc_tsc); if (ret) @@ -841,7 +838,7 @@ static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm, /* send relevant data according to CMD version */ ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_TKIP_PARAM, - cmd_flags, size, + CMD_ASYNC, size, &tkip_data.tkip); if (ret) goto out; @@ -885,10 +882,8 @@ static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm, IWL_DEBUG_WOWLAN(mvm, "setting akm %d\n", mvmvif->rekey_data.akm); - ret = iwl_mvm_send_cmd_pdu(mvm, - WOWLAN_KEK_KCK_MATERIAL, cmd_flags, - cmd_size, - _kek_kck_cmd); + ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_KEK_KCK_MATERIAL, + CMD_ASYNC, cmd_size, _kek_kck_cmd); if (ret) goto out; } @@ -927,7 +922,7 @@ iwl_mvm_wowlan_config(struct iwl_mvm *mvm, * that isn't really a problem though. */ mutex_unlock(&mvm->mutex); - ret = iwl_mvm_wowlan_config_key_params(mvm, vif, CMD_ASYNC); + ret = iwl_mvm_wowlan_config_key_params(mvm, vif); mutex_lock(&mvm->mutex); if (ret) return ret; From 631ee512028589835b48fdfa104654d0f563e27a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 5 Aug 2021 13:19:25 +0300 Subject: [PATCH 37/95] iwlwifi: mvm: d3: refactor TSC/RSC configuration Refactor the TSC/RSC configuration out from the normal wowlan key iteration so we can replace it later with a different one adapted to a different firmware API. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210805130823.78e431c9aaeb.I5b83b8b30e3e7c04706a1f99b3970e4e5f36af9e@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 197 ++++++++++++-------- 1 file changed, 116 insertions(+), 81 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 0d87de66bf8d..0979fc18d4fb 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -102,9 +102,8 @@ static const u8 *iwl_mvm_find_max_pn(struct ieee80211_key_conf *key, } struct wowlan_key_data { - struct iwl_wowlan_rsc_tsc_params_cmd *rsc_tsc; struct iwl_wowlan_kek_kck_material_cmd_v4 *kek_kck_cmd; - bool error, use_rsc_tsc, configure_keys; + bool error, configure_keys; int wep_key_idx; }; @@ -117,10 +116,7 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw, struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct wowlan_key_data *data = _data; - struct aes_sc *aes_sc, *aes_tx_sc = NULL; - struct tkip_sc *tkip_sc, *tkip_tx_sc = NULL; - struct ieee80211_key_seq seq; - int ret, i; + int ret; switch (key->cipher) { case WLAN_CIPHER_SUITE_WEP40: @@ -190,6 +186,71 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw, * be deauthenticated, but that was considered acceptable. */ return; + case WLAN_CIPHER_SUITE_TKIP: + if (!sta) + data->kek_kck_cmd->gtk_cipher = + cpu_to_le32(STA_KEY_FLG_TKIP); + break; + case WLAN_CIPHER_SUITE_CCMP: + case WLAN_CIPHER_SUITE_GCMP: + case WLAN_CIPHER_SUITE_GCMP_256: + if (!sta) + data->kek_kck_cmd->gtk_cipher = + key->cipher == WLAN_CIPHER_SUITE_CCMP ? + cpu_to_le32(STA_KEY_FLG_CCM) : + cpu_to_le32(STA_KEY_FLG_GCMP); + break; + } + + IWL_DEBUG_WOWLAN(mvm, "GTK cipher %d\n", data->kek_kck_cmd->gtk_cipher); + + if (data->configure_keys) { + mutex_lock(&mvm->mutex); + /* + * The D3 firmware hardcodes the key offset 0 as the key it + * uses to transmit packets to the AP, i.e. the PTK. + */ + if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) { + mvm->ptk_ivlen = key->iv_len; + mvm->ptk_icvlen = key->icv_len; + ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, 0); + } else { + /* + * firmware only supports TSC/RSC for a single key, + * so if there are multiple keep overwriting them + * with new ones -- this relies on mac80211 doing + * list_add_tail(). + */ + mvm->gtk_ivlen = key->iv_len; + mvm->gtk_icvlen = key->icv_len; + ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, 1); + } + mutex_unlock(&mvm->mutex); + data->error = ret != 0; + } +} + +struct wowlan_key_rsc_tsc_data { + struct iwl_wowlan_rsc_tsc_params_cmd *rsc_tsc; + bool have_rsc_tsc; +}; + +static void iwl_mvm_wowlan_get_rsc_tsc_data(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *key, + void *_data) +{ + struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + struct wowlan_key_rsc_tsc_data *data = _data; + struct aes_sc *aes_sc; + struct tkip_sc *tkip_sc, *tkip_tx_sc = NULL; + struct ieee80211_key_seq seq; + int i; + + switch (key->cipher) { + default: + break; case WLAN_CIPHER_SUITE_TKIP: if (sta) { u64 pn64; @@ -205,8 +266,6 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw, } else { tkip_sc = data->rsc_tsc->params.all_tsc_rsc.tkip.multicast_rsc; - data->kek_kck_cmd->gtk_cipher = - cpu_to_le32(STA_KEY_FLG_TKIP); } /* @@ -220,12 +279,13 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw, tkip_sc[i].iv32 = cpu_to_le32(seq.tkip.iv32); } - data->use_rsc_tsc = true; + data->have_rsc_tsc = true; break; case WLAN_CIPHER_SUITE_CCMP: case WLAN_CIPHER_SUITE_GCMP: case WLAN_CIPHER_SUITE_GCMP_256: if (sta) { + struct aes_sc *aes_tx_sc; u64 pn64; aes_sc = @@ -238,10 +298,6 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw, } else { aes_sc = data->rsc_tsc->params.all_tsc_rsc.aes.multicast_rsc; - data->kek_kck_cmd->gtk_cipher = - key->cipher == WLAN_CIPHER_SUITE_CCMP ? - cpu_to_le32(STA_KEY_FLG_CCM) : - cpu_to_le32(STA_KEY_FLG_GCMP); } /* @@ -286,36 +342,48 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw, ((u64)pn[0] << 40)); } } - data->use_rsc_tsc = true; + data->have_rsc_tsc = true; break; } +} - IWL_DEBUG_WOWLAN(mvm, "GTK cipher %d\n", data->kek_kck_cmd->gtk_cipher); +static int iwl_mvm_wowlan_config_rsc_tsc(struct iwl_mvm *mvm, + struct ieee80211_vif *vif) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + int ver = iwl_fw_lookup_cmd_ver(mvm->fw, LONG_GROUP, + WOWLAN_TSC_RSC_PARAM, + IWL_FW_CMD_VER_UNKNOWN); + struct wowlan_key_rsc_tsc_data data = {}; + int size; + int ret; - if (data->configure_keys) { - mutex_lock(&mvm->mutex); - /* - * The D3 firmware hardcodes the key offset 0 as the key it - * uses to transmit packets to the AP, i.e. the PTK. - */ - if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) { - mvm->ptk_ivlen = key->iv_len; - mvm->ptk_icvlen = key->icv_len; - ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, 0); - } else { - /* - * firmware only supports TSC/RSC for a single key, - * so if there are multiple keep overwriting them - * with new ones -- this relies on mac80211 doing - * list_add_tail(). - */ - mvm->gtk_ivlen = key->iv_len; - mvm->gtk_icvlen = key->icv_len; - ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, 1); - } - mutex_unlock(&mvm->mutex); - data->error = ret != 0; + data.rsc_tsc = kzalloc(sizeof(*data.rsc_tsc), GFP_KERNEL); + if (!data.rsc_tsc) + return -ENOMEM; + + if (ver == 4) { + size = sizeof(*data.rsc_tsc); + data.rsc_tsc->sta_id = cpu_to_le32(mvmvif->ap_sta_id); + } else if (ver == 2 || ver == IWL_FW_CMD_VER_UNKNOWN) { + size = sizeof(data.rsc_tsc->params); + } else { + ret = 0; + WARN_ON_ONCE(1); + goto out; } + + ieee80211_iter_keys(mvm->hw, vif, iwl_mvm_wowlan_get_rsc_tsc_data, + &data); + + if (data.have_rsc_tsc) + ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_TSC_RSC_PARAM, + CMD_ASYNC, size, data.rsc_tsc); + else + ret = 0; +out: + kfree(data.rsc_tsc); + return ret; } struct wowlan_key_tkip_data { @@ -753,7 +821,6 @@ static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm, IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG); struct wowlan_key_data key_data = { .configure_keys = !unified, - .use_rsc_tsc = false, .kek_kck_cmd = _kek_kck_cmd, }; struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); @@ -761,10 +828,6 @@ static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm, u8 cmd_ver; size_t cmd_size; - key_data.rsc_tsc = kzalloc(sizeof(*key_data.rsc_tsc), GFP_KERNEL); - if (!key_data.rsc_tsc) - return -ENOMEM; - /* * if we have to configure keys, call ieee80211_iter_keys(), * as we need non-atomic context in order to take the @@ -779,37 +842,12 @@ static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm, ieee80211_iter_keys(mvm->hw, vif, iwl_mvm_wowlan_program_keys, &key_data); - if (key_data.error) { - ret = -EIO; - goto out; - } + if (key_data.error) + return -EIO; - if (key_data.use_rsc_tsc) { - int ver = iwl_fw_lookup_cmd_ver(mvm->fw, LONG_GROUP, - WOWLAN_TSC_RSC_PARAM, - IWL_FW_CMD_VER_UNKNOWN); - int size; - - if (ver == 4) { - size = sizeof(*key_data.rsc_tsc); - key_data.rsc_tsc->sta_id = - cpu_to_le32(mvmvif->ap_sta_id); - - } else if (ver == 2 || ver == IWL_FW_CMD_VER_UNKNOWN) { - size = sizeof(key_data.rsc_tsc->params); - } else { - ret = 0; - WARN_ON_ONCE(1); - goto out; - } - - ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_TSC_RSC_PARAM, - CMD_ASYNC, size, - key_data.rsc_tsc); - - if (ret) - goto out; - } + ret = iwl_mvm_wowlan_config_rsc_tsc(mvm, vif); + if (ret) + return ret; if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_TKIP_MIC_KEYS)) { @@ -826,9 +864,8 @@ static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm, } else if (ver == 1 || ver == IWL_FW_CMD_VER_UNKNOWN) { size = sizeof(struct iwl_wowlan_tkip_params_cmd_ver_1); } else { - ret = -EINVAL; WARN_ON_ONCE(1); - goto out; + return -EINVAL; } ieee80211_iter_keys(mvm->hw, vif, iwl_mvm_wowlan_get_tkip_data, @@ -841,7 +878,7 @@ static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm, CMD_ASYNC, size, &tkip_data.tkip); if (ret) - goto out; + return ret; } } @@ -885,12 +922,10 @@ static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm, ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_KEK_KCK_MATERIAL, CMD_ASYNC, cmd_size, _kek_kck_cmd); if (ret) - goto out; + return ret; } - ret = 0; -out: - kfree(key_data.rsc_tsc); - return ret; + + return 0; } static int From be05fae23d03a228b2b10b18e1a3e7dbaa363b0f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 5 Aug 2021 13:19:26 +0300 Subject: [PATCH 38/95] iwlwifi: mvm: d3: add separate key iteration for GTK type If we're sending the KEK/KCK data we also need the GTK and IGTK type, add a separate key iteration for that so we can make the configure_key iteration optional later. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210805130823.c99f86423702.Icf7d4e93be77ea05a80235d01851ad0155593de9@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 63 +++++++++++++++------ 1 file changed, 46 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 0979fc18d4fb..61490f17a1fa 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -102,7 +102,6 @@ static const u8 *iwl_mvm_find_max_pn(struct ieee80211_key_conf *key, } struct wowlan_key_data { - struct iwl_wowlan_kek_kck_material_cmd_v4 *kek_kck_cmd; bool error, configure_keys; int wep_key_idx; }; @@ -174,10 +173,8 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw, return; case WLAN_CIPHER_SUITE_BIP_GMAC_256: case WLAN_CIPHER_SUITE_BIP_GMAC_128: - data->kek_kck_cmd->igtk_cipher = cpu_to_le32(STA_KEY_FLG_GCMP); return; case WLAN_CIPHER_SUITE_AES_CMAC: - data->kek_kck_cmd->igtk_cipher = cpu_to_le32(STA_KEY_FLG_CCM); /* * Ignore CMAC keys -- the WoWLAN firmware doesn't support them * but we also shouldn't abort suspend due to that. It does have @@ -187,23 +184,12 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw, */ return; case WLAN_CIPHER_SUITE_TKIP: - if (!sta) - data->kek_kck_cmd->gtk_cipher = - cpu_to_le32(STA_KEY_FLG_TKIP); - break; case WLAN_CIPHER_SUITE_CCMP: case WLAN_CIPHER_SUITE_GCMP: case WLAN_CIPHER_SUITE_GCMP_256: - if (!sta) - data->kek_kck_cmd->gtk_cipher = - key->cipher == WLAN_CIPHER_SUITE_CCMP ? - cpu_to_le32(STA_KEY_FLG_CCM) : - cpu_to_le32(STA_KEY_FLG_GCMP); break; } - IWL_DEBUG_WOWLAN(mvm, "GTK cipher %d\n", data->kek_kck_cmd->gtk_cipher); - if (data->configure_keys) { mutex_lock(&mvm->mutex); /* @@ -452,6 +438,42 @@ static void iwl_mvm_wowlan_get_tkip_data(struct ieee80211_hw *hw, } } +struct wowlan_key_gtk_type_iter { + struct iwl_wowlan_kek_kck_material_cmd_v4 *kek_kck_cmd; +}; + +static void iwl_mvm_wowlan_gtk_type_iter(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *key, + void *_data) +{ + struct wowlan_key_gtk_type_iter *data = _data; + + switch (key->cipher) { + default: + return; + case WLAN_CIPHER_SUITE_BIP_GMAC_256: + case WLAN_CIPHER_SUITE_BIP_GMAC_128: + data->kek_kck_cmd->igtk_cipher = cpu_to_le32(STA_KEY_FLG_GCMP); + return; + case WLAN_CIPHER_SUITE_AES_CMAC: + data->kek_kck_cmd->igtk_cipher = cpu_to_le32(STA_KEY_FLG_CCM); + return; + case WLAN_CIPHER_SUITE_CCMP: + if (!sta) + data->kek_kck_cmd->gtk_cipher = + cpu_to_le32(STA_KEY_FLG_CCM); + break; + case WLAN_CIPHER_SUITE_GCMP: + case WLAN_CIPHER_SUITE_GCMP_256: + if (!sta) + data->kek_kck_cmd->gtk_cipher = + cpu_to_le32(STA_KEY_FLG_GCMP); + break; + } +} + static int iwl_mvm_send_patterns_v1(struct iwl_mvm *mvm, struct cfg80211_wowlan *wowlan) { @@ -815,13 +837,10 @@ iwl_mvm_get_wowlan_config(struct iwl_mvm *mvm, static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { - struct iwl_wowlan_kek_kck_material_cmd_v4 kek_kck_cmd = {}; - struct iwl_wowlan_kek_kck_material_cmd_v4 *_kek_kck_cmd = &kek_kck_cmd; bool unified = fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG); struct wowlan_key_data key_data = { .configure_keys = !unified, - .kek_kck_cmd = _kek_kck_cmd, }; struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); int ret; @@ -884,6 +903,13 @@ static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm, /* configure rekey data only if offloaded rekey is supported (d3) */ if (mvmvif->rekey_data.valid) { + struct iwl_wowlan_kek_kck_material_cmd_v4 kek_kck_cmd = {}; + struct iwl_wowlan_kek_kck_material_cmd_v4 *_kek_kck_cmd = + &kek_kck_cmd; + struct wowlan_key_gtk_type_iter gtk_type_data = { + .kek_kck_cmd = _kek_kck_cmd, + }; + cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, IWL_ALWAYS_LONG_GROUP, WOWLAN_KEK_KCK_MATERIAL, @@ -892,6 +918,9 @@ static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm, cmd_ver != IWL_FW_CMD_VER_UNKNOWN)) return -EINVAL; + ieee80211_iter_keys(mvm->hw, vif, iwl_mvm_wowlan_gtk_type_iter, + >k_type_data); + memcpy(kek_kck_cmd.kck, mvmvif->rekey_data.kck, mvmvif->rekey_data.kck_len); kek_kck_cmd.kck_len = cpu_to_le16(mvmvif->rekey_data.kck_len); From af3aab9ce2989d7378e468c4d6a4eb39e0479c9b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 5 Aug 2021 13:19:27 +0300 Subject: [PATCH 39/95] iwlwifi: mvm: d3: make key reprogramming iteration optional Now that only reprogramming is left in the initial key iteration, skip it entirely on unified firmware images instead of skipping only the command sending inside of it. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210805130823.c6f77325c430.I798ce9d757492a9e3d223c1de5d4e62ebbc00b2c@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 100 +++++++++----------- 1 file changed, 47 insertions(+), 53 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 61490f17a1fa..ad7308cc4b7f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -101,8 +101,8 @@ static const u8 *iwl_mvm_find_max_pn(struct ieee80211_key_conf *key, return ret; } -struct wowlan_key_data { - bool error, configure_keys; +struct wowlan_key_reprogram_data { + bool error; int wep_key_idx; }; @@ -114,7 +114,7 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw, { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct wowlan_key_data *data = _data; + struct wowlan_key_reprogram_data *data = _data; int ret; switch (key->cipher) { @@ -152,18 +152,14 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw, wkc.wep_key.key_offset = data->wep_key_idx; } - if (data->configure_keys) { - mutex_lock(&mvm->mutex); - ret = iwl_mvm_send_cmd_pdu(mvm, WEP_KEY, 0, - sizeof(wkc), &wkc); - data->error = ret != 0; + mutex_lock(&mvm->mutex); + ret = iwl_mvm_send_cmd_pdu(mvm, WEP_KEY, 0, sizeof(wkc), &wkc); + data->error = ret != 0; - mvm->ptk_ivlen = key->iv_len; - mvm->ptk_icvlen = key->icv_len; - mvm->gtk_ivlen = key->iv_len; - mvm->gtk_icvlen = key->icv_len; - mutex_unlock(&mvm->mutex); - } + mvm->ptk_ivlen = key->iv_len; + mvm->ptk_icvlen = key->icv_len; + mvm->gtk_ivlen = key->iv_len; + mvm->gtk_icvlen = key->icv_len; /* don't upload key again */ return; @@ -190,30 +186,28 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw, break; } - if (data->configure_keys) { - mutex_lock(&mvm->mutex); + mutex_lock(&mvm->mutex); + /* + * The D3 firmware hardcodes the key offset 0 as the key it + * uses to transmit packets to the AP, i.e. the PTK. + */ + if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) { + mvm->ptk_ivlen = key->iv_len; + mvm->ptk_icvlen = key->icv_len; + ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, 0); + } else { /* - * The D3 firmware hardcodes the key offset 0 as the key it - * uses to transmit packets to the AP, i.e. the PTK. + * firmware only supports TSC/RSC for a single key, + * so if there are multiple keep overwriting them + * with new ones -- this relies on mac80211 doing + * list_add_tail(). */ - if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) { - mvm->ptk_ivlen = key->iv_len; - mvm->ptk_icvlen = key->icv_len; - ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, 0); - } else { - /* - * firmware only supports TSC/RSC for a single key, - * so if there are multiple keep overwriting them - * with new ones -- this relies on mac80211 doing - * list_add_tail(). - */ - mvm->gtk_ivlen = key->iv_len; - mvm->gtk_icvlen = key->icv_len; - ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, 1); - } - mutex_unlock(&mvm->mutex); - data->error = ret != 0; + mvm->gtk_ivlen = key->iv_len; + mvm->gtk_icvlen = key->icv_len; + ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, 1); } + mutex_unlock(&mvm->mutex); + data->error = ret != 0; } struct wowlan_key_rsc_tsc_data { @@ -839,30 +833,30 @@ static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm, { bool unified = fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG); - struct wowlan_key_data key_data = { - .configure_keys = !unified, - }; + struct wowlan_key_reprogram_data key_data = {}; struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); int ret; u8 cmd_ver; size_t cmd_size; - /* - * if we have to configure keys, call ieee80211_iter_keys(), - * as we need non-atomic context in order to take the - * required locks. - */ - /* - * Note that currently we don't use CMD_ASYNC in the iterator. - * In case of key_data.configure_keys, all the configured commands - * are SYNC, and iwl_mvm_wowlan_program_keys() will take care of - * locking/unlocking mvm->mutex. - */ - ieee80211_iter_keys(mvm->hw, vif, iwl_mvm_wowlan_program_keys, - &key_data); + if (!unified) { + /* + * if we have to configure keys, call ieee80211_iter_keys(), + * as we need non-atomic context in order to take the + * required locks. + */ + /* + * Note that currently we don't use CMD_ASYNC in the iterator. + * In case of key_data.configure_keys, all the configured + * commands are SYNC, and iwl_mvm_wowlan_program_keys() will + * take care of locking/unlocking mvm->mutex. + */ + ieee80211_iter_keys(mvm->hw, vif, iwl_mvm_wowlan_program_keys, + &key_data); - if (key_data.error) - return -EIO; + if (key_data.error) + return -EIO; + } ret = iwl_mvm_wowlan_config_rsc_tsc(mvm, vif); if (ret) From 79e561f0f05afaa10b8d9bd18f89ec7d7168126d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 5 Aug 2021 13:19:28 +0300 Subject: [PATCH 40/95] iwlwifi: mvm: d3: implement RSC command version 5 In later firmware we haven't needed the TSC anyway since we have it already (and firmware image doesn't change), but the new version adds the ability to send down replay counters for more than one GTK. Implement that. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210805130823.28cd065e8c4a.Ic8406a78ee46b07e0ca1b8199522ef08ec6eef53@changeid Signed-off-by: Luca Coelho --- .../wireless/intel/iwlwifi/fw/api/commands.h | 3 +- .../net/wireless/intel/iwlwifi/fw/api/d3.h | 22 +- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 196 ++++++++++++++++-- 3 files changed, 191 insertions(+), 30 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h b/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h index ce060c3dfd7b..ee6b5844a871 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h @@ -550,7 +550,8 @@ enum iwl_legacy_cmds { WOWLAN_CONFIGURATION = 0xe1, /** - * @WOWLAN_TSC_RSC_PARAM: &struct iwl_wowlan_rsc_tsc_params_cmd + * @WOWLAN_TSC_RSC_PARAM: &struct iwl_wowlan_rsc_tsc_params_cmd_v4, + * &struct iwl_wowlan_rsc_tsc_params_cmd */ WOWLAN_TSC_RSC_PARAM = 0xe2, diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h index b2e7ef3ddc88..3ec82cae3981 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h @@ -6,6 +6,7 @@ */ #ifndef __iwl_fw_api_d3_h__ #define __iwl_fw_api_d3_h__ +#include /** * enum iwl_d0i3_flags - d0i3 flags @@ -389,11 +390,14 @@ struct iwl_wowlan_config_cmd { u8 reserved; } __packed; /* WOWLAN_CONFIG_API_S_VER_5 */ +#define IWL_NUM_RSC 16 +#define WOWLAN_KEY_MAX_SIZE 32 +#define WOWLAN_GTK_KEYS_NUM 2 +#define WOWLAN_IGTK_KEYS_NUM 2 + /* * WOWLAN_TSC_RSC_PARAMS */ -#define IWL_NUM_RSC 16 - struct tkip_sc { __le16 iv16; __le16 pad; @@ -425,11 +429,19 @@ struct iwl_wowlan_rsc_tsc_params_cmd_ver_2 { union iwl_all_tsc_rsc all_tsc_rsc; } __packed; /* ALL_TSC_RSC_API_S_VER_2 */ -struct iwl_wowlan_rsc_tsc_params_cmd { +struct iwl_wowlan_rsc_tsc_params_cmd_v4 { struct iwl_wowlan_rsc_tsc_params_cmd_ver_2 params; __le32 sta_id; } __packed; /* ALL_TSC_RSC_API_S_VER_4 */ +struct iwl_wowlan_rsc_tsc_params_cmd { + __le64 ucast_rsc[IWL_MAX_TID_COUNT]; + __le64 mcast_rsc[WOWLAN_GTK_KEYS_NUM][IWL_MAX_TID_COUNT]; + __le32 sta_id; +#define IWL_MCAST_KEY_MAP_INVALID 0xff + u8 mcast_key_id_map[4]; +} __packed; /* ALL_TSC_RSC_API_S_VER_5 */ + #define IWL_MIC_KEY_SIZE 8 struct iwl_mic_keys { u8 tx[IWL_MIC_KEY_SIZE]; @@ -541,10 +553,6 @@ struct iwl_wowlan_gtk_status_v1 { struct iwl_wowlan_rsc_tsc_params_cmd_ver_2 rsc; } __packed; /* WOWLAN_GTK_MATERIAL_VER_1 */ -#define WOWLAN_KEY_MAX_SIZE 32 -#define WOWLAN_GTK_KEYS_NUM 2 -#define WOWLAN_IGTK_KEYS_NUM 2 - /** * struct iwl_wowlan_gtk_status - GTK status * @key: GTK material diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index ad7308cc4b7f..00403b337060 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -211,7 +211,7 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw, } struct wowlan_key_rsc_tsc_data { - struct iwl_wowlan_rsc_tsc_params_cmd *rsc_tsc; + struct iwl_wowlan_rsc_tsc_params_cmd_v4 *rsc_tsc; bool have_rsc_tsc; }; @@ -327,6 +327,127 @@ static void iwl_mvm_wowlan_get_rsc_tsc_data(struct ieee80211_hw *hw, } } +struct wowlan_key_rsc_v5_data { + struct iwl_wowlan_rsc_tsc_params_cmd *rsc; + bool have_rsc; + int gtks; + int gtk_ids[4]; +}; + +static void iwl_mvm_wowlan_get_rsc_v5_data(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *key, + void *_data) +{ + struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + struct wowlan_key_rsc_v5_data *data = _data; + struct ieee80211_key_seq seq; + __le64 *rsc; + int i; + + /* only for ciphers that can be PTK/GTK */ + switch (key->cipher) { + default: + return; + case WLAN_CIPHER_SUITE_TKIP: + case WLAN_CIPHER_SUITE_CCMP: + case WLAN_CIPHER_SUITE_GCMP: + case WLAN_CIPHER_SUITE_GCMP_256: + break; + } + + if (sta) { + rsc = data->rsc->ucast_rsc; + } else { + if (WARN_ON(data->gtks > ARRAY_SIZE(data->gtk_ids))) + return; + data->gtk_ids[data->gtks] = key->keyidx; + rsc = data->rsc->mcast_rsc[data->gtks % 2]; + if (WARN_ON(key->keyidx > + ARRAY_SIZE(data->rsc->mcast_key_id_map))) + return; + data->rsc->mcast_key_id_map[key->keyidx] = data->gtks % 2; + if (data->gtks >= 2) { + int prev = data->gtks - 2; + int prev_idx = data->gtk_ids[prev]; + + data->rsc->mcast_key_id_map[prev_idx] = + IWL_MCAST_KEY_MAP_INVALID; + } + data->gtks++; + } + + switch (key->cipher) { + default: + WARN_ON(1); + break; + case WLAN_CIPHER_SUITE_TKIP: + + /* + * For non-QoS this relies on the fact that both the uCode and + * mac80211 use TID 0 (as they need to to avoid replay attacks) + * for checking the IV in the frames. + */ + for (i = 0; i < IWL_MAX_TID_COUNT; i++) { + ieee80211_get_key_rx_seq(key, i, &seq); + + rsc[i] = cpu_to_le64(((u64)seq.tkip.iv32 << 16) | + seq.tkip.iv16); + } + + data->have_rsc = true; + break; + case WLAN_CIPHER_SUITE_CCMP: + case WLAN_CIPHER_SUITE_GCMP: + case WLAN_CIPHER_SUITE_GCMP_256: + /* + * For non-QoS this relies on the fact that both the uCode and + * mac80211/our RX code use TID 0 for checking the PN. + */ + if (sta) { + struct iwl_mvm_sta *mvmsta; + struct iwl_mvm_key_pn *ptk_pn; + const u8 *pn; + + mvmsta = iwl_mvm_sta_from_mac80211(sta); + rcu_read_lock(); + ptk_pn = rcu_dereference(mvmsta->ptk_pn[key->keyidx]); + if (WARN_ON(!ptk_pn)) { + rcu_read_unlock(); + break; + } + + for (i = 0; i < IWL_MAX_TID_COUNT; i++) { + pn = iwl_mvm_find_max_pn(key, ptk_pn, &seq, i, + mvm->trans->num_rx_queues); + rsc[i] = cpu_to_le64((u64)pn[5] | + ((u64)pn[4] << 8) | + ((u64)pn[3] << 16) | + ((u64)pn[2] << 24) | + ((u64)pn[1] << 32) | + ((u64)pn[0] << 40)); + } + + rcu_read_unlock(); + } else { + for (i = 0; i < IWL_MAX_TID_COUNT; i++) { + u8 *pn = seq.ccmp.pn; + + ieee80211_get_key_rx_seq(key, i, &seq); + rsc[i] = cpu_to_le64((u64)pn[5] | + ((u64)pn[4] << 8) | + ((u64)pn[3] << 16) | + ((u64)pn[2] << 24) | + ((u64)pn[1] << 32) | + ((u64)pn[0] << 40)); + } + } + data->have_rsc = true; + break; + } +} + static int iwl_mvm_wowlan_config_rsc_tsc(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { @@ -334,35 +455,66 @@ static int iwl_mvm_wowlan_config_rsc_tsc(struct iwl_mvm *mvm, int ver = iwl_fw_lookup_cmd_ver(mvm->fw, LONG_GROUP, WOWLAN_TSC_RSC_PARAM, IWL_FW_CMD_VER_UNKNOWN); - struct wowlan_key_rsc_tsc_data data = {}; - int size; int ret; - data.rsc_tsc = kzalloc(sizeof(*data.rsc_tsc), GFP_KERNEL); - if (!data.rsc_tsc) - return -ENOMEM; + if (ver == 5) { + struct wowlan_key_rsc_v5_data data = {}; + int i; - if (ver == 4) { - size = sizeof(*data.rsc_tsc); - data.rsc_tsc->sta_id = cpu_to_le32(mvmvif->ap_sta_id); - } else if (ver == 2 || ver == IWL_FW_CMD_VER_UNKNOWN) { - size = sizeof(data.rsc_tsc->params); + data.rsc = kmalloc(sizeof(*data.rsc), GFP_KERNEL); + if (!data.rsc) + return -ENOMEM; + + memset(data.rsc, 0xff, sizeof(*data.rsc)); + + for (i = 0; i < ARRAY_SIZE(data.rsc->mcast_key_id_map); i++) + data.rsc->mcast_key_id_map[i] = + IWL_MCAST_KEY_MAP_INVALID; + data.rsc->sta_id = cpu_to_le32(mvmvif->ap_sta_id); + + ieee80211_iter_keys(mvm->hw, vif, + iwl_mvm_wowlan_get_rsc_v5_data, + &data); + + if (data.have_rsc) + ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_TSC_RSC_PARAM, + CMD_ASYNC, sizeof(*data.rsc), + data.rsc); + else + ret = 0; + kfree(data.rsc); + } else if (ver == 4 || ver == 2 || ver == IWL_FW_CMD_VER_UNKNOWN) { + struct wowlan_key_rsc_tsc_data data = {}; + int size; + + data.rsc_tsc = kzalloc(sizeof(*data.rsc_tsc), GFP_KERNEL); + if (!data.rsc_tsc) + return -ENOMEM; + + if (ver == 4) { + size = sizeof(*data.rsc_tsc); + data.rsc_tsc->sta_id = cpu_to_le32(mvmvif->ap_sta_id); + } else { + /* ver == 2 || ver == IWL_FW_CMD_VER_UNKNOWN */ + size = sizeof(data.rsc_tsc->params); + } + + ieee80211_iter_keys(mvm->hw, vif, + iwl_mvm_wowlan_get_rsc_tsc_data, + &data); + + if (data.have_rsc_tsc) + ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_TSC_RSC_PARAM, + CMD_ASYNC, size, + data.rsc_tsc); + else + ret = 0; + kfree(data.rsc_tsc); } else { ret = 0; WARN_ON_ONCE(1); - goto out; } - ieee80211_iter_keys(mvm->hw, vif, iwl_mvm_wowlan_get_rsc_tsc_data, - &data); - - if (data.have_rsc_tsc) - ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_TSC_RSC_PARAM, - CMD_ASYNC, size, data.rsc_tsc); - else - ret = 0; -out: - kfree(data.rsc_tsc); return ret; } From 3df5c0ddcf81f2fe2d6a5e48efc3a37aa0feda5b Mon Sep 17 00:00:00 2001 From: Avraham Stern Date: Thu, 5 Aug 2021 13:19:29 +0300 Subject: [PATCH 41/95] iwlwifi: mvm: silently drop encrypted frames for unknown station When a station is removed, the driver-mac80211 station mapping is removed before the station is actually deleted from the FW. As a result, it is reasonable that the FW will continue to pass frames although the driver doesn't have a station for them anymore. Thus change the message severity level from ERR to DEBUG_DROP. Signed-off-by: Avraham Stern Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210805130823.a751177743c6.I5607504dade88ba461508643f58390dd661c05ba@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index c0babb8d5b5c..06cc03820dd5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -69,8 +69,8 @@ static inline int iwl_mvm_check_pn(struct iwl_mvm *mvm, struct sk_buff *skb, /* if we are here - this for sure is either CCMP or GCMP */ if (IS_ERR_OR_NULL(sta)) { - IWL_ERR(mvm, - "expected hw-decrypted unicast frame for station\n"); + IWL_DEBUG_DROP(mvm, + "expected hw-decrypted unicast frame for station\n"); return -1; } From 967a39832ebe72e7b3826368e26ca1adda66814d Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Thu, 5 Aug 2021 13:19:30 +0300 Subject: [PATCH 42/95] iwlwifi: mvm: Refactor setting of SSIDs for 6GHz scan - Short SSIDs should always be added for direct SSIDs included in the scan request. However, this was not done in case that information for collocated APs was included. Fix this. - With the above fix, if the FW also supports discovery of hidden APs over the 6GHz band, also set the corresponding full SSID information. Signed-off-by: Ilan Peer Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210805130823.02512b7a1443.Ibb023b09b86179ed049a195f4e32e887c2f4971d@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/scan.c | 104 +++++------------- 1 file changed, 28 insertions(+), 76 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index 82ab08af0e21..e1b436e805b1 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -1661,22 +1661,32 @@ iwl_mvm_umac_scan_cfg_channels_v6(struct iwl_mvm *mvm, } static int -iwl_mvm_umac_scan_fill_6g_chan_list(struct iwl_mvm_scan_params *params, - __le32 *cmd_short_ssid, u8 *cmd_bssid, - u8 *scan_ssid_num, u8 *bssid_num) +iwl_mvm_umac_scan_fill_6g_chan_list(struct iwl_mvm *mvm, + struct iwl_mvm_scan_params *params, + struct iwl_scan_probe_params_v4 *pp) { int j, idex_s = 0, idex_b = 0; struct cfg80211_scan_6ghz_params *scan_6ghz_params = params->scan_6ghz_params; + bool hidden_supported = fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_HIDDEN_6GHZ_SCAN); - if (!params->n_6ghz_params) { - for (j = 0; j < params->n_ssids; j++) { - cmd_short_ssid[idex_s++] = - cpu_to_le32(~crc32_le(~0, params->ssids[j].ssid, - params->ssids[j].ssid_len)); - (*scan_ssid_num)++; + for (j = 0; j < params->n_ssids && idex_s < SCAN_SHORT_SSID_MAX_SIZE; + j++) { + if (!params->ssids[j].ssid_len) + continue; + + pp->short_ssid[idex_s] = + cpu_to_le32(~crc32_le(~0, params->ssids[j].ssid, + params->ssids[j].ssid_len)); + + if (hidden_supported) { + pp->direct_scan[idex_s].id = WLAN_EID_SSID; + pp->direct_scan[idex_s].len = params->ssids[j].ssid_len; + memcpy(pp->direct_scan[idex_s].ssid, params->ssids[j].ssid, + params->ssids[j].ssid_len); } - return 0; + idex_s++; } /* @@ -1693,31 +1703,32 @@ iwl_mvm_umac_scan_fill_6g_chan_list(struct iwl_mvm_scan_params *params, /* First, try to place the short SSID */ if (scan_6ghz_params[j].short_ssid_valid) { for (k = 0; k < idex_s; k++) { - if (cmd_short_ssid[k] == + if (pp->short_ssid[k] == cpu_to_le32(scan_6ghz_params[j].short_ssid)) break; } if (k == idex_s && idex_s < SCAN_SHORT_SSID_MAX_SIZE) { - cmd_short_ssid[idex_s++] = + pp->short_ssid[idex_s++] = cpu_to_le32(scan_6ghz_params[j].short_ssid); - (*scan_ssid_num)++; } } /* try to place BSSID for the same entry */ for (k = 0; k < idex_b; k++) { - if (!memcmp(&cmd_bssid[ETH_ALEN * k], + if (!memcmp(&pp->bssid_array[k], scan_6ghz_params[j].bssid, ETH_ALEN)) break; } if (k == idex_b && idex_b < SCAN_BSSID_MAX_SIZE) { - memcpy(&cmd_bssid[ETH_ALEN * idex_b++], + memcpy(&pp->bssid_array[idex_b++], scan_6ghz_params[j].bssid, ETH_ALEN); - (*bssid_num)++; } } + + pp->short_ssid_num = idex_s; + pp->bssid_num = idex_b; return 0; } @@ -1865,60 +1876,6 @@ iwl_mvm_umac_scan_cfg_channels_v6_6g(struct iwl_mvm_scan_params *params, } } -static void -iwl_mvm_umac_scan_cfg_6g_direct_ssids(struct iwl_mvm *mvm, - struct iwl_mvm_scan_params *params, - struct iwl_scan_probe_params_v4 *pp) -{ - u8 next_free_idx = pp->short_ssid_num; - int i; - - if (!fw_has_capa(&mvm->fw->ucode_capa, - IWL_UCODE_TLV_CAPA_HIDDEN_6GHZ_SCAN)) { - IWL_DEBUG_SCAN(mvm, - "6GHz hidden scan: Not supported by FW\n"); - return; - } - - for (i = params->n_ssids - 1; i >= 0; i--) { - __le32 short_ssid; - u8 ssid_idx, j; - - if (!params->ssids[i].ssid_len) - continue; - - short_ssid = cpu_to_le32(~crc32_le(~0, params->ssids[i].ssid, - params->ssids[i].ssid_len)); - - for (j = 0; j < pp->short_ssid_num; j++) - if (short_ssid == pp->short_ssid[j]) - break; - - if (j == pp->short_ssid_num) { - /* - * If there are no available slots for the short SSID, do not - * place it. - */ - if (next_free_idx < SCAN_SHORT_SSID_MAX_SIZE) - ssid_idx = next_free_idx++; - else - continue; - } else { - ssid_idx = j; - } - - if (ssid_idx >= PROBE_OPTION_MAX) - continue; - - pp->direct_scan[ssid_idx].id = WLAN_EID_SSID; - pp->direct_scan[ssid_idx].len = params->ssids[i].ssid_len; - memcpy(pp->direct_scan[ssid_idx].ssid, params->ssids[i].ssid, - params->ssids[i].ssid_len); - } - - pp->short_ssid_num = next_free_idx; -} - static u8 iwl_mvm_scan_umac_chan_flags_v2(struct iwl_mvm *mvm, struct iwl_mvm_scan_params *params, struct ieee80211_vif *vif) @@ -2445,15 +2402,10 @@ static int iwl_mvm_scan_umac_v14(struct iwl_mvm *mvm, struct ieee80211_vif *vif, cp->n_aps_override[0] = IWL_SCAN_ADWELL_N_APS_GO_FRIENDLY; cp->n_aps_override[1] = IWL_SCAN_ADWELL_N_APS_SOCIAL_CHS; - ret = iwl_mvm_umac_scan_fill_6g_chan_list(params, pb->short_ssid, - pb->bssid_array[0], - &pb->short_ssid_num, - &pb->bssid_num); + ret = iwl_mvm_umac_scan_fill_6g_chan_list(mvm, params, pb); if (ret) return ret; - iwl_mvm_umac_scan_cfg_6g_direct_ssids(mvm, params, pb); - iwl_mvm_umac_scan_cfg_channels_v6_6g(params, params->n_channels, pb, cp, vif->type); From 6c608cd6962ebdf84fd3de6d42f88ed64d2f4e1b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 5 Aug 2021 13:19:31 +0300 Subject: [PATCH 43/95] iwlwifi: mvm: fix access to BSS elements BSS elements are protected using RCU, so we need to use RCU properly to access them, fix that. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210805130823.fd8b5791ab44.Iba26800a6301078d3782fb249c476dd8ac2bf3c6@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index c60c0b49d7f7..3a4585222d6d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -2990,16 +2990,20 @@ static void iwl_mvm_check_he_obss_narrow_bw_ru_iter(struct wiphy *wiphy, void *_data) { struct iwl_mvm_he_obss_narrow_bw_ru_data *data = _data; + const struct cfg80211_bss_ies *ies; const struct element *elem; - elem = cfg80211_find_elem(WLAN_EID_EXT_CAPABILITY, bss->ies->data, - bss->ies->len); + rcu_read_lock(); + ies = rcu_dereference(bss->ies); + elem = cfg80211_find_elem(WLAN_EID_EXT_CAPABILITY, ies->data, + ies->len); if (!elem || elem->datalen < 10 || !(elem->data[10] & WLAN_EXT_CAPA10_OBSS_NARROW_BW_RU_TOLERANCE_SUPPORT)) { data->tolerated = false; } + rcu_read_unlock(); } static void iwl_mvm_check_he_obss_narrow_bw_ru(struct ieee80211_hw *hw, From 248e7e2a1d8d1140f0d5cc507812987c33c7b020 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Thu, 5 Aug 2021 13:19:32 +0300 Subject: [PATCH 44/95] iwlwifi: rename ACPI_SAR_NUM_CHAIN_LIMITS to ACPI_SAR_NUM_CHAINS The "LIMITS" in the macro name don't have much meaning, so remove it to make the macro shorter and better reflect that this is the number of chains that we have limits for. Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210805130823.65591c9fa2af.Ie7e4ba94c903ef444cb07df61891394c11c7c864@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 6 +++--- drivers/net/wireless/intel/iwlwifi/fw/acpi.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index 34933f133a0a..dff792653a24 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -433,10 +433,10 @@ static int iwl_sar_fill_table(struct iwl_fw_runtime *fwrt, __le16 *per_chain, u32 n_subbands, int prof_a, int prof_b) { - int profs[ACPI_SAR_NUM_CHAIN_LIMITS] = { prof_a, prof_b }; + int profs[ACPI_SAR_NUM_CHAINS] = { prof_a, prof_b }; int i, j, idx; - for (i = 0; i < ACPI_SAR_NUM_CHAIN_LIMITS; i++) { + for (i = 0; i < ACPI_SAR_NUM_CHAINS; i++) { struct iwl_sar_profile *prof; /* don't allow SAR to be disabled (profile 0 means disable) */ @@ -486,7 +486,7 @@ int iwl_sar_select_profile(struct iwl_fw_runtime *fwrt, for (i = 0; i < n_tables; i++) { ret = iwl_sar_fill_table(fwrt, - &per_chain[i * n_subbands * ACPI_SAR_NUM_CHAIN_LIMITS], + &per_chain[i * n_subbands * ACPI_SAR_NUM_CHAINS], n_subbands, prof_a, prof_b); if (ret) break; diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h index b858e998999c..24e94430e5d9 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h @@ -33,7 +33,7 @@ #define ACPI_NUM_GEO_PROFILES 3 #define ACPI_GEO_PER_CHAIN_SIZE 3 -#define ACPI_SAR_NUM_CHAIN_LIMITS 2 +#define ACPI_SAR_NUM_CHAINS 2 #define ACPI_SAR_NUM_SUB_BANDS 5 #define ACPI_SAR_NUM_TABLES 1 From 81870d138dfe9450d99411113c57258449f250b3 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Thu, 5 Aug 2021 13:19:33 +0300 Subject: [PATCH 45/95] iwlwifi: convert flat SAR profile table to a struct version The SAR profiles have been stored in single-dimension arrays and the access has been done via a single index. We will soon need to support different revisions of this table, which will make the flat array even harder to handle. To prepare for that, convert the single-dimension array to a struct with substructures. Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210805130823.01530088097f.I903c236a574c7e4c0fc4db101fc39c0f5415ca43@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 30 +++++++++++++------- drivers/net/wireless/intel/iwlwifi/fw/acpi.h | 13 ++++++--- 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index dff792653a24..f20f0150f407 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -414,16 +414,25 @@ static int iwl_sar_set_profile(union acpi_object *table, struct iwl_sar_profile *profile, bool enabled) { - int i; + int i, j, idx = 0; profile->enabled = enabled; - for (i = 0; i < ACPI_SAR_TABLE_SIZE; i++) { - if (table[i].type != ACPI_TYPE_INTEGER || - table[i].integer.value > U8_MAX) - return -EINVAL; + /* + * The table from ACPI is flat, but we store it in a + * structured array. + */ + for (i = 0; i < ACPI_SAR_NUM_CHAINS; i++) { + for (j = 0; j < ACPI_SAR_NUM_SUB_BANDS; j++) { + if (table[idx].type != ACPI_TYPE_INTEGER || + table[idx].integer.value > U8_MAX) + return -EINVAL; - profile->table[i] = table[i].integer.value; + profile->chains[i].subbands[j] = + table[idx].integer.value; + + idx++; + } } return 0; @@ -434,7 +443,7 @@ static int iwl_sar_fill_table(struct iwl_fw_runtime *fwrt, int prof_a, int prof_b) { int profs[ACPI_SAR_NUM_CHAINS] = { prof_a, prof_b }; - int i, j, idx; + int i, j; for (i = 0; i < ACPI_SAR_NUM_CHAINS; i++) { struct iwl_sar_profile *prof; @@ -467,11 +476,10 @@ static int iwl_sar_fill_table(struct iwl_fw_runtime *fwrt, i, profs[i]); IWL_DEBUG_RADIO(fwrt, " Chain[%d]:\n", i); for (j = 0; j < n_subbands; j++) { - idx = i * ACPI_SAR_NUM_SUB_BANDS + j; per_chain[i * n_subbands + j] = - cpu_to_le16(prof->table[idx]); + cpu_to_le16(prof->chains[i].subbands[j]); IWL_DEBUG_RADIO(fwrt, " Band[%d] = %d * .125dBm\n", - j, prof->table[idx]); + j, prof->chains[i].subbands[j]); } } @@ -595,7 +603,7 @@ int iwl_sar_get_ewrd_table(struct iwl_fw_runtime *fwrt) break; /* go to the next table */ - pos += ACPI_SAR_TABLE_SIZE; + pos += ACPI_SAR_NUM_CHAINS * ACPI_SAR_NUM_SUB_BANDS; } out_free: diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h index 24e94430e5d9..cd26a155baf7 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h @@ -26,7 +26,6 @@ #define ACPI_WIFI_DOMAIN (0x07) -#define ACPI_SAR_TABLE_SIZE 10 #define ACPI_SAR_PROFILE_NUM 4 #define ACPI_GEO_TABLE_SIZE 6 @@ -37,9 +36,11 @@ #define ACPI_SAR_NUM_SUB_BANDS 5 #define ACPI_SAR_NUM_TABLES 1 -#define ACPI_WRDS_WIFI_DATA_SIZE (ACPI_SAR_TABLE_SIZE + 2) +#define ACPI_WRDS_WIFI_DATA_SIZE (ACPI_SAR_NUM_CHAINS * \ + ACPI_SAR_NUM_SUB_BANDS + 2) #define ACPI_EWRD_WIFI_DATA_SIZE ((ACPI_SAR_PROFILE_NUM - 1) * \ - ACPI_SAR_TABLE_SIZE + 3) + ACPI_SAR_NUM_CHAINS * \ + ACPI_SAR_NUM_SUB_BANDS + 3) #define ACPI_WGDS_WIFI_DATA_SIZE 19 #define ACPI_WRDD_WIFI_DATA_SIZE 2 #define ACPI_SPLC_WIFI_DATA_SIZE 2 @@ -64,9 +65,13 @@ #define ACPI_PPAG_MIN_HB -16 #define ACPI_PPAG_MAX_HB 40 +struct iwl_sar_profile_chain { + u8 subbands[ACPI_SAR_NUM_SUB_BANDS]; +}; + struct iwl_sar_profile { bool enabled; - u8 table[ACPI_SAR_TABLE_SIZE]; + struct iwl_sar_profile_chain chains[ACPI_SAR_NUM_CHAINS]; }; struct iwl_geo_profile { From dac7171c81323afa3a8c4fa1c08719ff9fd033cb Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Thu, 5 Aug 2021 13:19:34 +0300 Subject: [PATCH 46/95] iwlwifi: remove ACPI_SAR_NUM_TABLES definition This definition was only used to pass the size of the tables in the FW API to the iwl_sar_select_profile() function, but we should actually pass the definition from the FW API file. We don't have the concept of tables in the ACPI definition, so we can remove it. Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210805130823.00b5084be918.I18efb3c45bffacfa9a356c2c8d34e5ffbb3eb423@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/acpi.h | 1 - drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h index cd26a155baf7..245f0646c8f8 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h @@ -34,7 +34,6 @@ #define ACPI_SAR_NUM_CHAINS 2 #define ACPI_SAR_NUM_SUB_BANDS 5 -#define ACPI_SAR_NUM_TABLES 1 #define ACPI_WRDS_WIFI_DATA_SIZE (ACPI_SAR_NUM_CHAINS * \ ACPI_SAR_NUM_SUB_BANDS + 2) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 38fd5886af2d..0b769aac0b02 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -743,7 +743,8 @@ int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b) /* all structs have the same common part, add it */ len += sizeof(cmd.common); - ret = iwl_sar_select_profile(&mvm->fwrt, per_chain, ACPI_SAR_NUM_TABLES, + ret = iwl_sar_select_profile(&mvm->fwrt, per_chain, + IWL_NUM_CHAIN_TABLES, n_subbands, prof_a, prof_b); /* return on error or if the profile is disabled (positive number) */ From 8ecf0477b990791949752578e7706908682db6e5 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Thu, 5 Aug 2021 14:21:47 +0300 Subject: [PATCH 47/95] iwlwifi: pass number of chains and sub-bands to iwl_sar_set_profile() The number of chains and sub-bands read from the ACPI tables varies depending on the revision. Pass these numbers to the iwl_sar_set_profile() function in order to make using different revisions easier. Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210805141826.905b54c398f8.I9bac8c3bc3b1b6bbe813de53746daee33e53fc86@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index f20f0150f407..9175f53806bf 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -412,7 +412,7 @@ IWL_EXPORT_SYMBOL(iwl_acpi_get_eckv); static int iwl_sar_set_profile(union acpi_object *table, struct iwl_sar_profile *profile, - bool enabled) + bool enabled, u8 num_chains, u8 num_sub_bands) { int i, j, idx = 0; @@ -422,8 +422,8 @@ static int iwl_sar_set_profile(union acpi_object *table, * The table from ACPI is flat, but we store it in a * structured array. */ - for (i = 0; i < ACPI_SAR_NUM_CHAINS; i++) { - for (j = 0; j < ACPI_SAR_NUM_SUB_BANDS; j++) { + for (i = 0; i < num_chains; i++) { + for (j = 0; j < num_sub_bands; j++) { if (table[idx].type != ACPI_TYPE_INTEGER || table[idx].integer.value > U8_MAX) return -EINVAL; @@ -539,7 +539,8 @@ int iwl_sar_get_wrds_table(struct iwl_fw_runtime *fwrt) /* The profile from WRDS is officially profile 1, but goes * into sar_profiles[0] (because we don't have a profile 0). */ - ret = iwl_sar_set_profile(table, &fwrt->sar_profiles[0], enabled); + ret = iwl_sar_set_profile(table, &fwrt->sar_profiles[0], enabled, + ACPI_SAR_NUM_CHAINS, ACPI_SAR_NUM_SUB_BANDS); out_free: kfree(data); return ret; @@ -598,7 +599,9 @@ int iwl_sar_get_ewrd_table(struct iwl_fw_runtime *fwrt) */ ret = iwl_sar_set_profile(&wifi_pkg->package.elements[pos], &fwrt->sar_profiles[i + 1], - enabled); + enabled, + ACPI_SAR_NUM_CHAINS, + ACPI_SAR_NUM_SUB_BANDS); if (ret < 0) break; From 2a8084147bff7a1fe9f567ed39c340a6a3fc27ef Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Thu, 5 Aug 2021 14:21:48 +0300 Subject: [PATCH 48/95] iwlwifi: acpi: support reading and storing WRDS revision 1 and 2 Change the SAR profile tables storage to revision 2 regardless of the revision we read from ACPI. Revision 2 is a superset of revision 1, which is in turn a superset of revision 0, so they can all be stored inside revision 2. Add support for reading and storing also revisions 1 and 2, whose only difference is the number of chains and number of sub-bands. So most of the code revolves around passing different chain and sub-band sizes. With this patch we still pass only revision 0 to the firmware, but that will be changed in a separate patch. Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210805141826.2edad09415c8.I36297aef90a9ec6a3ea1bf1a151a62f272826d59@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 74 +++++++++++++++----- drivers/net/wireless/intel/iwlwifi/fw/acpi.h | 29 +++++--- 2 files changed, 79 insertions(+), 24 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index 9175f53806bf..d4e7e303b190 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -442,10 +442,10 @@ static int iwl_sar_fill_table(struct iwl_fw_runtime *fwrt, __le16 *per_chain, u32 n_subbands, int prof_a, int prof_b) { - int profs[ACPI_SAR_NUM_CHAINS] = { prof_a, prof_b }; + int profs[ACPI_SAR_NUM_CHAINS_REV0] = { prof_a, prof_b }; int i, j; - for (i = 0; i < ACPI_SAR_NUM_CHAINS; i++) { + for (i = 0; i < ACPI_SAR_NUM_CHAINS_REV0; i++) { struct iwl_sar_profile *prof; /* don't allow SAR to be disabled (profile 0 means disable) */ @@ -494,7 +494,7 @@ int iwl_sar_select_profile(struct iwl_fw_runtime *fwrt, for (i = 0; i < n_tables; i++) { ret = iwl_sar_fill_table(fwrt, - &per_chain[i * n_subbands * ACPI_SAR_NUM_CHAINS], + &per_chain[i * n_subbands * ACPI_SAR_NUM_CHAINS_REV0], n_subbands, prof_a, prof_b); if (ret) break; @@ -509,28 +509,71 @@ int iwl_sar_get_wrds_table(struct iwl_fw_runtime *fwrt) union acpi_object *wifi_pkg, *table, *data; bool enabled; int ret, tbl_rev; + u8 num_chains, num_sub_bands; data = iwl_acpi_get_object(fwrt->dev, ACPI_WRDS_METHOD); if (IS_ERR(data)) return PTR_ERR(data); + /* start by trying to read revision 2 */ wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, - ACPI_WRDS_WIFI_DATA_SIZE, &tbl_rev); - if (IS_ERR(wifi_pkg)) { - ret = PTR_ERR(wifi_pkg); - goto out_free; + ACPI_WRDS_WIFI_DATA_SIZE_REV2, + &tbl_rev); + if (!IS_ERR(wifi_pkg)) { + if (tbl_rev != 2) { + ret = PTR_ERR(wifi_pkg); + goto out_free; + } + + num_chains = ACPI_SAR_NUM_CHAINS_REV2; + num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV2; + + goto read_table; } - if (tbl_rev != 0) { - ret = -EINVAL; - goto out_free; + /* then try revision 1 */ + wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, + ACPI_WRDS_WIFI_DATA_SIZE_REV1, + &tbl_rev); + if (!IS_ERR(wifi_pkg)) { + if (tbl_rev != 1) { + ret = PTR_ERR(wifi_pkg); + goto out_free; + } + + num_chains = ACPI_SAR_NUM_CHAINS_REV1; + num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV1; + + goto read_table; } + /* then finally revision 0 */ + wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, + ACPI_WRDS_WIFI_DATA_SIZE_REV0, + &tbl_rev); + if (!IS_ERR(wifi_pkg)) { + if (tbl_rev != 0) { + ret = PTR_ERR(wifi_pkg); + goto out_free; + } + + num_chains = ACPI_SAR_NUM_CHAINS_REV0; + num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV0; + + goto read_table; + } + + ret = PTR_ERR(wifi_pkg); + goto out_free; + +read_table: if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER) { ret = -EINVAL; goto out_free; } + IWL_DEBUG_RADIO(fwrt, "Reading WRDS tbl_rev=%d\n", tbl_rev); + enabled = !!(wifi_pkg->package.elements[1].integer.value); /* position of the actual table */ @@ -540,7 +583,7 @@ int iwl_sar_get_wrds_table(struct iwl_fw_runtime *fwrt) * into sar_profiles[0] (because we don't have a profile 0). */ ret = iwl_sar_set_profile(table, &fwrt->sar_profiles[0], enabled, - ACPI_SAR_NUM_CHAINS, ACPI_SAR_NUM_SUB_BANDS); + num_chains, num_sub_bands); out_free: kfree(data); return ret; @@ -598,15 +641,14 @@ int iwl_sar_get_ewrd_table(struct iwl_fw_runtime *fwrt) * have profile 0). So in the array we start from 1. */ ret = iwl_sar_set_profile(&wifi_pkg->package.elements[pos], - &fwrt->sar_profiles[i + 1], - enabled, - ACPI_SAR_NUM_CHAINS, - ACPI_SAR_NUM_SUB_BANDS); + &fwrt->sar_profiles[i + 1], enabled, + ACPI_SAR_NUM_CHAINS_REV0, + ACPI_SAR_NUM_SUB_BANDS_REV0); if (ret < 0) break; /* go to the next table */ - pos += ACPI_SAR_NUM_CHAINS * ACPI_SAR_NUM_SUB_BANDS; + pos += ACPI_SAR_NUM_CHAINS_REV0 * ACPI_SAR_NUM_SUB_BANDS_REV0; } out_free: diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h index 245f0646c8f8..e49aec8e3946 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h @@ -32,14 +32,22 @@ #define ACPI_NUM_GEO_PROFILES 3 #define ACPI_GEO_PER_CHAIN_SIZE 3 -#define ACPI_SAR_NUM_CHAINS 2 -#define ACPI_SAR_NUM_SUB_BANDS 5 +#define ACPI_SAR_NUM_CHAINS_REV0 2 +#define ACPI_SAR_NUM_CHAINS_REV1 2 +#define ACPI_SAR_NUM_CHAINS_REV2 4 +#define ACPI_SAR_NUM_SUB_BANDS_REV0 5 +#define ACPI_SAR_NUM_SUB_BANDS_REV1 11 +#define ACPI_SAR_NUM_SUB_BANDS_REV2 11 -#define ACPI_WRDS_WIFI_DATA_SIZE (ACPI_SAR_NUM_CHAINS * \ - ACPI_SAR_NUM_SUB_BANDS + 2) +#define ACPI_WRDS_WIFI_DATA_SIZE_REV0 (ACPI_SAR_NUM_CHAINS_REV0 * \ + ACPI_SAR_NUM_SUB_BANDS_REV0 + 2) +#define ACPI_WRDS_WIFI_DATA_SIZE_REV1 (ACPI_SAR_NUM_CHAINS_REV1 * \ + ACPI_SAR_NUM_SUB_BANDS_REV1 + 2) +#define ACPI_WRDS_WIFI_DATA_SIZE_REV2 (ACPI_SAR_NUM_CHAINS_REV2 * \ + ACPI_SAR_NUM_SUB_BANDS_REV2 + 2) #define ACPI_EWRD_WIFI_DATA_SIZE ((ACPI_SAR_PROFILE_NUM - 1) * \ - ACPI_SAR_NUM_CHAINS * \ - ACPI_SAR_NUM_SUB_BANDS + 3) + ACPI_SAR_NUM_CHAINS_REV0 * \ + ACPI_SAR_NUM_SUB_BANDS_REV0 + 3) #define ACPI_WGDS_WIFI_DATA_SIZE 19 #define ACPI_WRDD_WIFI_DATA_SIZE 2 #define ACPI_SPLC_WIFI_DATA_SIZE 2 @@ -64,13 +72,18 @@ #define ACPI_PPAG_MIN_HB -16 #define ACPI_PPAG_MAX_HB 40 +/* + * The profile for revision 2 is a superset of revision 1, which is in + * turn a superset of revision 0. So we can store all revisions + * inside revision 2, which is what we represent here. + */ struct iwl_sar_profile_chain { - u8 subbands[ACPI_SAR_NUM_SUB_BANDS]; + u8 subbands[ACPI_SAR_NUM_SUB_BANDS_REV2]; }; struct iwl_sar_profile { bool enabled; - struct iwl_sar_profile_chain chains[ACPI_SAR_NUM_CHAINS]; + struct iwl_sar_profile_chain chains[ACPI_SAR_NUM_CHAINS_REV2]; }; struct iwl_geo_profile { From 51266c11ceccbe95a5abe98e4c4b0f4932b5b023 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Thu, 5 Aug 2021 14:21:49 +0300 Subject: [PATCH 49/95] iwlwifi: support reading and storing EWRD revisions 1 and 2 As an extension to the WRDS support for revisions 1 and 2, do the same for the EWRD tables. These tables have a very similar format to the WRDS table, so most of the code is similar. Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210805141826.2d5494de683c.Ia024b1368873d488906a639e29454cbbdc788d03@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 60 ++++++++++++++++---- drivers/net/wireless/intel/iwlwifi/fw/acpi.h | 8 ++- 2 files changed, 57 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index d4e7e303b190..c31c212996fa 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -596,23 +596,64 @@ int iwl_sar_get_ewrd_table(struct iwl_fw_runtime *fwrt) bool enabled; int i, n_profiles, tbl_rev, pos; int ret = 0; + u8 num_chains, num_sub_bands; data = iwl_acpi_get_object(fwrt->dev, ACPI_EWRD_METHOD); if (IS_ERR(data)) return PTR_ERR(data); + /* start by trying to read revision 2 */ wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, - ACPI_EWRD_WIFI_DATA_SIZE, &tbl_rev); - if (IS_ERR(wifi_pkg)) { - ret = PTR_ERR(wifi_pkg); - goto out_free; + ACPI_EWRD_WIFI_DATA_SIZE_REV2, + &tbl_rev); + if (!IS_ERR(wifi_pkg)) { + if (tbl_rev != 2) { + ret = PTR_ERR(wifi_pkg); + goto out_free; + } + + num_chains = ACPI_SAR_NUM_CHAINS_REV2; + num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV2; + + goto read_table; } - if (tbl_rev != 0) { - ret = -EINVAL; - goto out_free; + /* then try revision 1 */ + wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, + ACPI_EWRD_WIFI_DATA_SIZE_REV1, + &tbl_rev); + if (!IS_ERR(wifi_pkg)) { + if (tbl_rev != 1) { + ret = PTR_ERR(wifi_pkg); + goto out_free; + } + + num_chains = ACPI_SAR_NUM_CHAINS_REV1; + num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV1; + + goto read_table; } + /* then finally revision 0 */ + wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, + ACPI_EWRD_WIFI_DATA_SIZE_REV0, + &tbl_rev); + if (!IS_ERR(wifi_pkg)) { + if (tbl_rev != 0) { + ret = PTR_ERR(wifi_pkg); + goto out_free; + } + + num_chains = ACPI_SAR_NUM_CHAINS_REV0; + num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV0; + + goto read_table; + } + + ret = PTR_ERR(wifi_pkg); + goto out_free; + +read_table: if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER || wifi_pkg->package.elements[2].type != ACPI_TYPE_INTEGER) { ret = -EINVAL; @@ -642,13 +683,12 @@ int iwl_sar_get_ewrd_table(struct iwl_fw_runtime *fwrt) */ ret = iwl_sar_set_profile(&wifi_pkg->package.elements[pos], &fwrt->sar_profiles[i + 1], enabled, - ACPI_SAR_NUM_CHAINS_REV0, - ACPI_SAR_NUM_SUB_BANDS_REV0); + num_chains, num_sub_bands); if (ret < 0) break; /* go to the next table */ - pos += ACPI_SAR_NUM_CHAINS_REV0 * ACPI_SAR_NUM_SUB_BANDS_REV0; + pos += num_chains * num_sub_bands; } out_free: diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h index e49aec8e3946..2d98f7e903e7 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h @@ -45,9 +45,15 @@ ACPI_SAR_NUM_SUB_BANDS_REV1 + 2) #define ACPI_WRDS_WIFI_DATA_SIZE_REV2 (ACPI_SAR_NUM_CHAINS_REV2 * \ ACPI_SAR_NUM_SUB_BANDS_REV2 + 2) -#define ACPI_EWRD_WIFI_DATA_SIZE ((ACPI_SAR_PROFILE_NUM - 1) * \ +#define ACPI_EWRD_WIFI_DATA_SIZE_REV0 ((ACPI_SAR_PROFILE_NUM - 1) * \ ACPI_SAR_NUM_CHAINS_REV0 * \ ACPI_SAR_NUM_SUB_BANDS_REV0 + 3) +#define ACPI_EWRD_WIFI_DATA_SIZE_REV1 ((ACPI_SAR_PROFILE_NUM - 1) * \ + ACPI_SAR_NUM_CHAINS_REV1 * \ + ACPI_SAR_NUM_SUB_BANDS_REV1 + 3) +#define ACPI_EWRD_WIFI_DATA_SIZE_REV2 ((ACPI_SAR_PROFILE_NUM - 1) * \ + ACPI_SAR_NUM_CHAINS_REV2 * \ + ACPI_SAR_NUM_SUB_BANDS_REV2 + 3) #define ACPI_WGDS_WIFI_DATA_SIZE 19 #define ACPI_WRDD_WIFI_DATA_SIZE 2 #define ACPI_SPLC_WIFI_DATA_SIZE 2 From de95c9288ae15b53be63e52097fe0d5b374e6a13 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Thu, 5 Aug 2021 14:21:50 +0300 Subject: [PATCH 50/95] iwlwifi: remove unused ACPI_WGDS_TABLE_SIZE definition When we started supporting the new FW API for the geo profiles, we stopped using this definition, but left it there. Remove it now. Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210805141826.91dec6fad3e8.Ica42d5538d83b1407efe0c441c61aa8830e7496d@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/acpi.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h index 2d98f7e903e7..85cf4cb1336e 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h @@ -65,8 +65,6 @@ #define APCI_WTAS_BLACK_LIST_MAX 16 #define ACPI_WTAS_WIFI_DATA_SIZE (3 + APCI_WTAS_BLACK_LIST_MAX) -#define ACPI_WGDS_TABLE_SIZE 3 - #define ACPI_PPAG_WIFI_DATA_SIZE_V1 ((IWL_NUM_CHAIN_LIMITS * \ IWL_NUM_SUB_BANDS_V1) + 2) #define ACPI_PPAG_WIFI_DATA_SIZE_V2 ((IWL_NUM_CHAIN_LIMITS * \ From 5bf7a9edddbb9d7c7deae58663aedd4dbc731a9e Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Thu, 5 Aug 2021 14:21:51 +0300 Subject: [PATCH 51/95] iwlwifi: convert flat GEO profile table to a struct version The GEO profiles have been stored in single-dimension arrays and the access has been done via a single index. We will soon need to support different revisions of this table, which will make the flat array even harder to handle. To prepare for that, convert the single-dimension array to a struct with substructures. Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210805141826.56f3506411a2.I600ed3708d19f2263a5a8d143f6711d08499bbb0@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 46 +++++++++++-------- drivers/net/wireless/intel/iwlwifi/fw/acpi.h | 14 +++++- .../net/wireless/intel/iwlwifi/mvm/debugfs.c | 11 +++-- 3 files changed, 44 insertions(+), 27 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index c31c212996fa..3d2962260665 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -700,8 +700,8 @@ IWL_EXPORT_SYMBOL(iwl_sar_get_ewrd_table); int iwl_sar_get_wgds_table(struct iwl_fw_runtime *fwrt) { union acpi_object *wifi_pkg, *data; - int i, j, ret, tbl_rev; - int idx = 1; + int i, j, k, ret, tbl_rev; + int idx = 1; /* start from one to skip the domain */ data = iwl_acpi_get_object(fwrt->dev, ACPI_WGDS_METHOD); if (IS_ERR(data)) @@ -722,7 +722,7 @@ int iwl_sar_get_wgds_table(struct iwl_fw_runtime *fwrt) fwrt->geo_rev = tbl_rev; for (i = 0; i < ACPI_NUM_GEO_PROFILES; i++) { - for (j = 0; j < ACPI_GEO_TABLE_SIZE; j++) { + for (j = 0; j < ACPI_GEO_NUM_BANDS_REV0; j++) { union acpi_object *entry; entry = &wifi_pkg->package.elements[idx++]; @@ -732,9 +732,23 @@ int iwl_sar_get_wgds_table(struct iwl_fw_runtime *fwrt) goto out_free; } - fwrt->geo_profiles[i].values[j] = entry->integer.value; + fwrt->geo_profiles[i].bands[j].max = + entry->integer.value; + + for (k = 0; k < ACPI_GEO_NUM_CHAINS; k++) { + entry = &wifi_pkg->package.elements[idx++]; + if (entry->type != ACPI_TYPE_INTEGER || + entry->integer.value > U8_MAX) { + ret = -EINVAL; + goto out_free; + } + + fwrt->geo_profiles[i].bands[j].chains[k] = + entry->integer.value; + } } } + ret = 0; out_free: kfree(data); @@ -784,25 +798,17 @@ int iwl_sar_geo_init(struct iwl_fw_runtime *fwrt, for (j = 0; j < n_bands; j++) { struct iwl_per_chain_offset *chain = &table[i * n_bands + j]; - u8 *value; - if (j * ACPI_GEO_PER_CHAIN_SIZE >= - ARRAY_SIZE(fwrt->geo_profiles[0].values)) - /* - * Currently we only store lb an hb values, and - * don't have any special ones for uhb. So leave - * those empty for the time being - */ - break; - - value = &fwrt->geo_profiles[i].values[j * - ACPI_GEO_PER_CHAIN_SIZE]; - chain->max_tx_power = cpu_to_le16(value[0]); - chain->chain_a = value[1]; - chain->chain_b = value[2]; + chain->max_tx_power = + cpu_to_le16(fwrt->geo_profiles[i].bands[j].max); + chain->chain_a = fwrt->geo_profiles[i].bands[j].chains[0]; + chain->chain_b = fwrt->geo_profiles[i].bands[j].chains[1]; IWL_DEBUG_RADIO(fwrt, "SAR geographic profile[%d] Band[%d]: chain A = %d chain B = %d max_tx_power = %d\n", - i, j, value[1], value[2], value[0]); + i, j, + fwrt->geo_profiles[i].bands[j].chains[0], + fwrt->geo_profiles[i].bands[j].chains[1], + fwrt->geo_profiles[i].bands[j].max); } } diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h index 85cf4cb1336e..030ea3efcc87 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h @@ -28,7 +28,6 @@ #define ACPI_SAR_PROFILE_NUM 4 -#define ACPI_GEO_TABLE_SIZE 6 #define ACPI_NUM_GEO_PROFILES 3 #define ACPI_GEO_PER_CHAIN_SIZE 3 @@ -39,6 +38,11 @@ #define ACPI_SAR_NUM_SUB_BANDS_REV1 11 #define ACPI_SAR_NUM_SUB_BANDS_REV2 11 +#define ACPI_GEO_NUM_CHAINS 2 +#define ACPI_GEO_NUM_BANDS_REV0 2 +#define ACPI_GEO_NUM_BANDS_REV1 2 +#define ACPI_GEO_NUM_BANDS_REV2 3 + #define ACPI_WRDS_WIFI_DATA_SIZE_REV0 (ACPI_SAR_NUM_CHAINS_REV0 * \ ACPI_SAR_NUM_SUB_BANDS_REV0 + 2) #define ACPI_WRDS_WIFI_DATA_SIZE_REV1 (ACPI_SAR_NUM_CHAINS_REV1 * \ @@ -90,8 +94,14 @@ struct iwl_sar_profile { struct iwl_sar_profile_chain chains[ACPI_SAR_NUM_CHAINS_REV2]; }; +/* Same thing as with SAR, all revisions fit in revision 2 */ +struct iwl_geo_profile_band { + u8 max; + u8 chains[ACPI_GEO_NUM_CHAINS]; +}; + struct iwl_geo_profile { - u8 values[ACPI_GEO_TABLE_SIZE]; + struct iwl_geo_profile_band bands[ACPI_GEO_NUM_BANDS_REV2]; }; enum iwl_dsm_funcs_rev_0 { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index 95f883aba148..5dc39fbb74d6 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -305,7 +305,6 @@ static ssize_t iwl_dbgfs_sar_geo_profile_read(struct file *file, int pos = 0; int bufsz = sizeof(buf); int tbl_idx; - u8 *value; if (!iwl_mvm_firmware_running(mvm)) return -EIO; @@ -321,16 +320,18 @@ static ssize_t iwl_dbgfs_sar_geo_profile_read(struct file *file, pos = scnprintf(buf, bufsz, "SAR geographic profile disabled\n"); } else { - value = &mvm->fwrt.geo_profiles[tbl_idx - 1].values[0]; - pos += scnprintf(buf + pos, bufsz - pos, "Use geographic profile %d\n", tbl_idx); pos += scnprintf(buf + pos, bufsz - pos, "2.4GHz:\n\tChain A offset: %hhu dBm\n\tChain B offset: %hhu dBm\n\tmax tx power: %hhu dBm\n", - value[1], value[2], value[0]); + mvm->fwrt.geo_profiles[tbl_idx - 1].bands[0].chains[0], + mvm->fwrt.geo_profiles[tbl_idx - 1].bands[0].chains[1], + mvm->fwrt.geo_profiles[tbl_idx - 1].bands[0].max); pos += scnprintf(buf + pos, bufsz - pos, "5.2GHz:\n\tChain A offset: %hhu dBm\n\tChain B offset: %hhu dBm\n\tmax tx power: %hhu dBm\n", - value[4], value[5], value[3]); + mvm->fwrt.geo_profiles[tbl_idx - 1].bands[1].chains[0], + mvm->fwrt.geo_profiles[tbl_idx - 1].bands[1].chains[1], + mvm->fwrt.geo_profiles[tbl_idx - 1].bands[1].max); } mutex_unlock(&mvm->mutex); From 058b94dc9bf8310b93da864f9fe5bee5b50b0cf4 Mon Sep 17 00:00:00 2001 From: Gregory Greenman Date: Thu, 5 Aug 2021 14:21:52 +0300 Subject: [PATCH 52/95] iwlwifi: mvm: support version 11 of wowlan statuses notification The new version of the command has same size and layout as version 10. It just sends corresponding station id in one of the reserved fields. It's not used in the driver, so just be ready to accept version 11. Signed-off-by: Gregory Greenman Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210805141826.0a387598eef1.I3be0bbf603ef95c644218be8a12b329411f11646@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 00403b337060..0e97d5e6c644 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -1933,9 +1933,12 @@ iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm, u8 sta_id) status->gtk[0] = v7->gtk[0]; status->igtk[0] = v7->igtk[0]; - } else if (notif_ver == 9 || notif_ver == 10) { + } else if (notif_ver == 9 || notif_ver == 10 || notif_ver == 11) { struct iwl_wowlan_status_v9 *v9 = (void *)cmd.resp_pkt->data; + /* these three command versions have same layout and size, the + * difference is only in a few not used (reserved) fields. + */ status = iwl_mvm_parse_wowlan_status_common_v9(mvm, cmd.resp_pkt->data, len); From 19426d54302e199b3fd2d575f926a13af66be2b9 Mon Sep 17 00:00:00 2001 From: Abhishek Naik Date: Thu, 5 Aug 2021 14:21:53 +0300 Subject: [PATCH 53/95] iwlwifi: skip first element in the WTAS ACPI table By mistake we were considering the first element of the WTAS wifi package as part of the data we want to rid, but that element is the wifi package signature (always 0x07), so it should be skipped. Change the code to read the data starting from element 1 instead. Signed-off-by: Abhishek Naik Fixes: 28dd7ccdc56f ("iwlwifi: acpi: read TAS table from ACPI and send it to the FW") Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210805141826.ff8148197b15.I70636c04e37b2b57a5df3ce611511f62203d27a7@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index 3d2962260665..78f0f2032c59 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -264,7 +264,7 @@ int iwl_acpi_get_tas(struct iwl_fw_runtime *fwrt, goto out_free; } - enabled = !!wifi_pkg->package.elements[0].integer.value; + enabled = !!wifi_pkg->package.elements[1].integer.value; if (!enabled) { *block_list_size = -1; @@ -273,15 +273,15 @@ int iwl_acpi_get_tas(struct iwl_fw_runtime *fwrt, goto out_free; } - if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER || - wifi_pkg->package.elements[1].integer.value > + if (wifi_pkg->package.elements[2].type != ACPI_TYPE_INTEGER || + wifi_pkg->package.elements[2].integer.value > APCI_WTAS_BLACK_LIST_MAX) { IWL_DEBUG_RADIO(fwrt, "TAS invalid array size %llu\n", wifi_pkg->package.elements[1].integer.value); ret = -EINVAL; goto out_free; } - *block_list_size = wifi_pkg->package.elements[1].integer.value; + *block_list_size = wifi_pkg->package.elements[2].integer.value; IWL_DEBUG_RADIO(fwrt, "TAS array size %d\n", *block_list_size); if (*block_list_size > APCI_WTAS_BLACK_LIST_MAX) { @@ -294,15 +294,15 @@ int iwl_acpi_get_tas(struct iwl_fw_runtime *fwrt, for (i = 0; i < *block_list_size; i++) { u32 country; - if (wifi_pkg->package.elements[2 + i].type != + if (wifi_pkg->package.elements[3 + i].type != ACPI_TYPE_INTEGER) { IWL_DEBUG_RADIO(fwrt, - "TAS invalid array elem %d\n", 2 + i); + "TAS invalid array elem %d\n", 3 + i); ret = -EINVAL; goto out_free; } - country = wifi_pkg->package.elements[2 + i].integer.value; + country = wifi_pkg->package.elements[3 + i].integer.value; block_list_array[i] = cpu_to_le32(country); IWL_DEBUG_RADIO(fwrt, "TAS block list country %d\n", country); } From e6344c060209ef4e970cac18adeac1676a2a73cd Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 5 Aug 2021 14:21:54 +0300 Subject: [PATCH 54/95] iwlwifi: fw: correctly limit to monitor dump In commit 79f033f6f229 ("iwlwifi: dbg: don't limit dump decisions to all or monitor") we changed the code to pass around a bitmap, but in the monitor_only case, one place accidentally used the bit number, not the bit mask, resulting in CSR and FW_INFO getting dumped instead of monitor data. Fix that. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210805141826.774fd8729a33.Ic985a787071d1c0b127ef0ba8367da896ee11f57@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index 70e0a3089876..c1537a9515f7 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -2321,7 +2321,7 @@ static void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt, return; if (dump_data->monitor_only) - dump_mask &= IWL_FW_ERROR_DUMP_FW_MONITOR; + dump_mask &= BIT(IWL_FW_ERROR_DUMP_FW_MONITOR); fw_error_dump.trans_ptr = iwl_trans_dump_data(fwrt->trans, dump_mask); file_len = le32_to_cpu(dump_file->file_len); From b537ffb6ea16b803b5ab5ef73c3bccc68a104af9 Mon Sep 17 00:00:00 2001 From: Shaul Triebitz Date: Thu, 5 Aug 2021 14:21:55 +0300 Subject: [PATCH 55/95] iwlwifi: mvm: trigger WRT when no beacon heard If the session protection ends but no beacon was heard, the driver triggers a disconnection. Trigger WRT in that case so it can be debugged. Signed-off-by: Shaul Triebitz Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210805141826.7bf71939826b.Id73f1a466929670f5ec54301227d68883afd9207@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/time-event.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c index d3307a11fcac..788fd2b84ed2 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c @@ -168,6 +168,16 @@ static bool iwl_mvm_te_check_disconnect(struct iwl_mvm *mvm, rcu_read_unlock(); } + if (vif->bss_conf.assoc) { + /* + * When not associated, this will be called from + * iwl_mvm_event_mlme_callback_ini() + */ + iwl_dbg_tlv_time_point(&mvm->fwrt, + IWL_FW_INI_TIME_POINT_ASSOC_FAILED, + NULL); + } + iwl_mvm_connection_loss(mvm, vif, errmsg); return true; } From 78a19d5285d93e281b40c3b8d5a959fbbd2fe006 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Thu, 5 Aug 2021 14:21:56 +0300 Subject: [PATCH 56/95] iwlwifi: mvm: Read the PPAG and SAR tables at INIT stage We used to read the PPAG, WRDS, EWRD, WGDS tables from ACPI in the load stage only. This prevented vendor commands from being executed before bringing the interface up. Move reading those tables to INIT stage. Signed-off-by: Miri Korenblit Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210805141826.ce3b60f0b426.I3643bf00e714aae930880cc7d6cf390b142eaccb@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 16 +-- drivers/net/wireless/intel/iwlwifi/fw/acpi.h | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 105 +++++++++++-------- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 1 + drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 2 + 5 files changed, 69 insertions(+), 57 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index 78f0f2032c59..1802a451c450 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -416,8 +416,6 @@ static int iwl_sar_set_profile(union acpi_object *table, { int i, j, idx = 0; - profile->enabled = enabled; - /* * The table from ACPI is flat, but we store it in a * structured array. @@ -435,6 +433,9 @@ static int iwl_sar_set_profile(union acpi_object *table, } } + /* Only if all values were valid can the profile be enabled */ + profile->enabled = enabled; + return 0; } @@ -780,20 +781,11 @@ IWL_EXPORT_SYMBOL(iwl_sar_geo_support); int iwl_sar_geo_init(struct iwl_fw_runtime *fwrt, struct iwl_per_chain_offset *table, u32 n_bands) { - int ret, i, j; + int i, j; if (!iwl_sar_geo_support(fwrt)) return -EOPNOTSUPP; - ret = iwl_sar_get_wgds_table(fwrt); - if (ret < 0) { - IWL_DEBUG_RADIO(fwrt, - "Geo SAR BIOS table invalid or unavailable. (%d)\n", - ret); - /* we don't fail if the table is not available */ - return -ENOENT; - } - for (i = 0; i < ACPI_NUM_GEO_PROFILES; i++) { for (j = 0; j < n_bands; j++) { struct iwl_per_chain_offset *chain = diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h index 030ea3efcc87..a424186af3c8 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h @@ -265,7 +265,7 @@ static inline int iwl_sar_get_ewrd_table(struct iwl_fw_runtime *fwrt) static inline int iwl_sar_get_wgds_table(struct iwl_fw_runtime *fwrt) { - return -ENOENT; + return 1; } static inline bool iwl_sar_geo_support(struct iwl_fw_runtime *fwrt) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 0b769aac0b02..74404c96063b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -1058,16 +1058,7 @@ static const struct dmi_system_id dmi_ppag_approved_list[] = { static int iwl_mvm_ppag_init(struct iwl_mvm *mvm) { - int ret; - - ret = iwl_mvm_get_ppag_table(mvm); - if (ret < 0) { - IWL_DEBUG_RADIO(mvm, - "PPAG BIOS table invalid or unavailable. (%d)\n", - ret); - return 0; - } - + /* no need to read the table, done in INIT stage */ if (!dmi_check_system(dmi_ppag_approved_list)) { IWL_DEBUG_RADIO(mvm, "System vendor '%s' is not in the approved list, disabling PPAG.\n", @@ -1192,12 +1183,65 @@ static void iwl_mvm_lari_cfg(struct iwl_mvm *mvm) ret); } } + +void iwl_mvm_get_acpi_tables(struct iwl_mvm *mvm) +{ + int ret; + + /* read PPAG table */ + ret = iwl_mvm_get_ppag_table(mvm); + if (ret < 0) { + IWL_DEBUG_RADIO(mvm, + "PPAG BIOS table invalid or unavailable. (%d)\n", + ret); + } + + /* read SAR tables */ + ret = iwl_sar_get_wrds_table(&mvm->fwrt); + if (ret < 0) { + IWL_DEBUG_RADIO(mvm, + "WRDS SAR BIOS table invalid or unavailable. (%d)\n", + ret); + /* + * If not available, don't fail and don't bother with EWRD and + * WGDS */ + + if (!iwl_sar_get_wgds_table(&mvm->fwrt)) { + /* + * If basic SAR is not available, we check for WGDS, + * which should *not* be available either. If it is + * available, issue an error, because we can't use SAR + * Geo without basic SAR. + */ + IWL_ERR(mvm, "BIOS contains WGDS but no WRDS\n"); + } + + } else { + ret = iwl_sar_get_ewrd_table(&mvm->fwrt); + /* if EWRD is not available, we can still use + * WRDS, so don't fail */ + if (ret < 0) + IWL_DEBUG_RADIO(mvm, + "EWRD SAR BIOS table invalid or unavailable. (%d)\n", + ret); + + /* read geo SAR table */ + if (iwl_sar_geo_support(&mvm->fwrt)) { + ret = iwl_sar_get_wgds_table(&mvm->fwrt); + if (ret < 0) + IWL_DEBUG_RADIO(mvm, + "Geo SAR BIOS table invalid or unavailable. (%d)\n", + ret); + /* we don't fail if the table is not available */ + } + } +} #else /* CONFIG_ACPI */ inline int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b) { - return -ENOENT; + return 1; } inline int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm) @@ -1232,6 +1276,10 @@ static u8 iwl_mvm_eval_dsm_rfi(struct iwl_mvm *mvm) { return DSM_VALUE_RFI_DISABLE; } + +void iwl_mvm_get_acpi_tables(struct iwl_mvm *mvm) +{ +} #endif /* CONFIG_ACPI */ void iwl_mvm_send_recovery_cmd(struct iwl_mvm *mvm, u32 flags) @@ -1287,27 +1335,6 @@ void iwl_mvm_send_recovery_cmd(struct iwl_mvm *mvm, u32 flags) static int iwl_mvm_sar_init(struct iwl_mvm *mvm) { - int ret; - - ret = iwl_sar_get_wrds_table(&mvm->fwrt); - if (ret < 0) { - IWL_DEBUG_RADIO(mvm, - "WRDS SAR BIOS table invalid or unavailable. (%d)\n", - ret); - /* - * If not available, don't fail and don't bother with EWRD. - * Return 1 to tell that we can't use WGDS either. - */ - return 1; - } - - ret = iwl_sar_get_ewrd_table(&mvm->fwrt); - /* if EWRD is not available, we can still use WRDS, so don't fail */ - if (ret < 0) - IWL_DEBUG_RADIO(mvm, - "EWRD SAR BIOS table invalid or unavailable. (%d)\n", - ret); - return iwl_mvm_sar_select_profile(mvm, 1, 1); } @@ -1543,19 +1570,9 @@ int iwl_mvm_up(struct iwl_mvm *mvm) goto error; ret = iwl_mvm_sar_init(mvm); - if (ret == 0) { + if (ret == 0) ret = iwl_mvm_sar_geo_init(mvm); - } else if (ret == -ENOENT && !iwl_sar_get_wgds_table(&mvm->fwrt)) { - /* - * If basic SAR is not available, we check for WGDS, - * which should *not* be available either. If it is - * available, issue an error, because we can't use SAR - * Geo without basic SAR. - */ - IWL_ERR(mvm, "BIOS contains WGDS but no WRDS\n"); - } - - if (ret < 0) + else if (ret < 0) goto error; iwl_mvm_tas_init(mvm); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 82a53cbf4342..f877d86b038e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -2043,6 +2043,7 @@ void iwl_mvm_event_frame_timeout_callback(struct iwl_mvm *mvm, int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b); int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm); int iwl_mvm_ppag_send_cmd(struct iwl_mvm *mvm); +void iwl_mvm_get_acpi_tables(struct iwl_mvm *mvm); #ifdef CONFIG_IWLWIFI_DEBUGFS void iwl_mvm_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index f57d2643135b..edff2cd3a30e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -771,6 +771,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, iwl_fw_runtime_init(&mvm->fwrt, trans, fw, &iwl_mvm_fwrt_ops, mvm, dbgfs_dir); + iwl_mvm_get_acpi_tables(mvm); + mvm->init_status = 0; if (iwl_mvm_has_new_rx_api(mvm)) { From eb09ae93dabfd0980f5226dfd0bd531eb87902f5 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Thu, 5 Aug 2021 14:21:57 +0300 Subject: [PATCH 57/95] iwlwifi: mvm: load regdomain at INIT stage We used to load the regdomain only in the load stage, this caused the 'iw phy phy0 reg get' command to fail if we booted a machine with wifi off. Therefor we should load it in INIT stage already. Signed-off-by: Miri Korenblit Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210805141826.a6077801d7d5.I7d8d5c895bc467efbf81ea055dde366ea01cced1@changeid Signed-off-by: Luca Coelho --- .../wireless/intel/iwlwifi/iwl-nvm-parse.c | 19 +++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/mvm/nvm.c | 4 ++-- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 5 +++++ 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c index 2fbb7cdf00a4..03387a5f8cbc 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c @@ -1381,6 +1381,25 @@ iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg, reg_query_regdb_wmm(regd->alpha2, center_freq, rule); } + /* + * Certain firmware versions might report no valid channels + * if booted in RF-kill, i.e. not all calibrations etc. are + * running. We'll get out of this situation later when the + * rfkill is removed and we update the regdomain again, but + * since cfg80211 doesn't accept an empty regdomain, add a + * dummy (unusable) rule here in this case so we can init. + */ + if (!valid_rules) { + valid_rules = 1; + rule = ®d->reg_rules[valid_rules - 1]; + rule->freq_range.start_freq_khz = MHZ_TO_KHZ(2412); + rule->freq_range.end_freq_khz = MHZ_TO_KHZ(2413); + rule->freq_range.max_bandwidth_khz = MHZ_TO_KHZ(1); + rule->power_rule.max_antenna_gain = DBI_TO_MBI(6); + rule->power_rule.max_eirp = + DBM_TO_MBM(IWL_DEFAULT_MAX_TX_POWER); + } + regd->n_reg_rules = valid_rules; /* diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c index 7fb4e618f76e..da705fcaf0fc 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2019 Intel Corporation + * Copyright (C) 2012-2014, 2018-2019, 2021 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -416,7 +416,7 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, struct iwl_rx_packet *pkt; struct iwl_host_cmd cmd = { .id = MCC_UPDATE_CMD, - .flags = CMD_WANT_SKB, + .flags = CMD_WANT_SKB | CMD_SEND_IN_RFKILL, .data = { &mcc_update_cmd }, }; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index edff2cd3a30e..8ce937f8445a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -692,11 +692,16 @@ static int iwl_mvm_start_get_nvm(struct iwl_mvm *mvm) if (ret && ret != -ERFKILL) iwl_fw_dbg_error_collect(&mvm->fwrt, FW_DBG_TRIGGER_DRIVER); + if (!ret && iwl_mvm_is_lar_supported(mvm)) { + mvm->hw->wiphy->regulatory_flags |= REGULATORY_WIPHY_SELF_MANAGED; + ret = iwl_mvm_init_mcc(mvm); + } if (!iwlmvm_mod_params.init_dbg || !ret) iwl_mvm_stop_device(mvm); mutex_unlock(&mvm->mutex); + rtnl_unlock(); if (ret < 0) IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", ret); From 664c011b763e437cbe2662432ec8e09128515700 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Thu, 5 Aug 2021 14:21:58 +0300 Subject: [PATCH 58/95] iwlwifi: acpi: support reading and storing WGDS revision 2 Revisions 0 and 1 are identical, so we were already supporting that. But revision 2 has a different size, so we have to try to read them separately. Add support for this new revision. Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210805141826.78e441b16f9c.I2d79492f05624ddd02c533c673811a36eaf8a396@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 38 +++++++++++++++----- drivers/net/wireless/intel/iwlwifi/fw/acpi.h | 19 ++++++---- 2 files changed, 43 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index 1802a451c450..de1e9271dcd2 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -703,27 +703,49 @@ int iwl_sar_get_wgds_table(struct iwl_fw_runtime *fwrt) union acpi_object *wifi_pkg, *data; int i, j, k, ret, tbl_rev; int idx = 1; /* start from one to skip the domain */ + u8 num_bands; data = iwl_acpi_get_object(fwrt->dev, ACPI_WGDS_METHOD); if (IS_ERR(data)) return PTR_ERR(data); + /* start by trying to read revision 2 */ wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, - ACPI_WGDS_WIFI_DATA_SIZE, &tbl_rev); + ACPI_WGDS_WIFI_DATA_SIZE_REV2, + &tbl_rev); + if (!IS_ERR(wifi_pkg)) { + if (tbl_rev != 2) { + ret = PTR_ERR(wifi_pkg); + goto out_free; + } - if (IS_ERR(wifi_pkg)) { - ret = PTR_ERR(wifi_pkg); - goto out_free; + num_bands = ACPI_GEO_NUM_BANDS_REV2; + + goto read_table; } - if (tbl_rev > 1) { - ret = -EINVAL; - goto out_free; + /* then try revision 0 (which is the same as 1) */ + wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, + ACPI_WGDS_WIFI_DATA_SIZE_REV0, + &tbl_rev); + if (!IS_ERR(wifi_pkg)) { + if (tbl_rev != 0 && tbl_rev != 1) { + ret = PTR_ERR(wifi_pkg); + goto out_free; + } + + num_bands = ACPI_GEO_NUM_BANDS_REV0; + + goto read_table; } + ret = PTR_ERR(wifi_pkg); + goto out_free; + +read_table: fwrt->geo_rev = tbl_rev; for (i = 0; i < ACPI_NUM_GEO_PROFILES; i++) { - for (j = 0; j < ACPI_GEO_NUM_BANDS_REV0; j++) { + for (j = 0; j < num_bands; j++) { union acpi_object *entry; entry = &wifi_pkg->package.elements[idx++]; diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h index a424186af3c8..16ed0995b51e 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h @@ -38,11 +38,6 @@ #define ACPI_SAR_NUM_SUB_BANDS_REV1 11 #define ACPI_SAR_NUM_SUB_BANDS_REV2 11 -#define ACPI_GEO_NUM_CHAINS 2 -#define ACPI_GEO_NUM_BANDS_REV0 2 -#define ACPI_GEO_NUM_BANDS_REV1 2 -#define ACPI_GEO_NUM_BANDS_REV2 3 - #define ACPI_WRDS_WIFI_DATA_SIZE_REV0 (ACPI_SAR_NUM_CHAINS_REV0 * \ ACPI_SAR_NUM_SUB_BANDS_REV0 + 2) #define ACPI_WRDS_WIFI_DATA_SIZE_REV1 (ACPI_SAR_NUM_CHAINS_REV1 * \ @@ -58,7 +53,19 @@ #define ACPI_EWRD_WIFI_DATA_SIZE_REV2 ((ACPI_SAR_PROFILE_NUM - 1) * \ ACPI_SAR_NUM_CHAINS_REV2 * \ ACPI_SAR_NUM_SUB_BANDS_REV2 + 3) -#define ACPI_WGDS_WIFI_DATA_SIZE 19 + +/* revision 0 and 1 are identical, except for the semantics in the FW */ +#define ACPI_GEO_NUM_BANDS_REV0 2 +#define ACPI_GEO_NUM_BANDS_REV2 3 +#define ACPI_GEO_NUM_CHAINS 2 + +#define ACPI_WGDS_WIFI_DATA_SIZE_REV0 (ACPI_NUM_GEO_PROFILES * \ + ACPI_GEO_NUM_BANDS_REV0 * \ + ACPI_GEO_PER_CHAIN_SIZE + 1) +#define ACPI_WGDS_WIFI_DATA_SIZE_REV2 (ACPI_NUM_GEO_PROFILES * \ + ACPI_GEO_NUM_BANDS_REV2 * \ + ACPI_GEO_PER_CHAIN_SIZE + 1) + #define ACPI_WRDD_WIFI_DATA_SIZE 2 #define ACPI_SPLC_WIFI_DATA_SIZE 2 #define ACPI_ECKV_WIFI_DATA_SIZE 2 From a6a39ab2645c696d5ed203a0d40300276da99f99 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Thu, 19 Aug 2021 18:40:25 +0300 Subject: [PATCH 59/95] iwlwifi: bump FW API to 65 for AX devices Start supporting API version 65 for AX devices. Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210819183728.1cb15b015485.I2818924b772d7518f4d9fc38b4caab3494ab11f9@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/cfg/22000.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c index cb4c1d23fc92..52d1d391f4c6 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c @@ -9,7 +9,7 @@ #include "iwl-prph.h" /* Highest firmware API version supported */ -#define IWL_22000_UCODE_API_MAX 64 +#define IWL_22000_UCODE_API_MAX 65 /* Lowest firmware API version supported */ #define IWL_22000_UCODE_API_MIN 39 From c5b42c674ad88643c8a7d31611114bda62425fcf Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Thu, 19 Aug 2021 18:40:26 +0300 Subject: [PATCH 60/95] iwlwifi: acpi: fill in WGDS table with defaults The tables we store are the larger of all the revisions, so we need to fill in the values that we don't get from ACPI when using older revisions. Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210819183728.01b12461a30b.I08d1f9154f26eca25c44616efdb5223bcc1935f3@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 42 ++++++++++++++------ 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index de1e9271dcd2..37da836a8c08 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -745,20 +745,18 @@ int iwl_sar_get_wgds_table(struct iwl_fw_runtime *fwrt) read_table: fwrt->geo_rev = tbl_rev; for (i = 0; i < ACPI_NUM_GEO_PROFILES; i++) { - for (j = 0; j < num_bands; j++) { + for (j = 0; j < ACPI_GEO_NUM_BANDS_REV2; j++) { union acpi_object *entry; - entry = &wifi_pkg->package.elements[idx++]; - if (entry->type != ACPI_TYPE_INTEGER || - entry->integer.value > U8_MAX) { - ret = -EINVAL; - goto out_free; - } - - fwrt->geo_profiles[i].bands[j].max = - entry->integer.value; - - for (k = 0; k < ACPI_GEO_NUM_CHAINS; k++) { + /* + * num_bands is either 2 or 3, if it's only 2 then + * fill the third band (6 GHz) with the values from + * 5 GHz (second band) + */ + if (j >= num_bands) { + fwrt->geo_profiles[i].bands[j].max = + fwrt->geo_profiles[i].bands[1].max; + } else { entry = &wifi_pkg->package.elements[idx++]; if (entry->type != ACPI_TYPE_INTEGER || entry->integer.value > U8_MAX) { @@ -766,9 +764,27 @@ read_table: goto out_free; } - fwrt->geo_profiles[i].bands[j].chains[k] = + fwrt->geo_profiles[i].bands[j].max = entry->integer.value; } + + for (k = 0; k < ACPI_GEO_NUM_CHAINS; k++) { + /* same here as above */ + if (j >= num_bands) { + fwrt->geo_profiles[i].bands[j].chains[k] = + fwrt->geo_profiles[i].bands[1].chains[k]; + } else { + entry = &wifi_pkg->package.elements[idx++]; + if (entry->type != ACPI_TYPE_INTEGER || + entry->integer.value > U8_MAX) { + ret = -EINVAL; + goto out_free; + } + + fwrt->geo_profiles[i].bands[j].chains[k] = + entry->integer.value; + } + } } } From 40063f602868aaeab5afe7f84237e3d95801680f Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Thu, 19 Aug 2021 18:40:27 +0300 Subject: [PATCH 61/95] iwlwifi: acpi: fill in SAR tables with defaults If the tables we get in the iwl_sar_set_profile() is smaller than the revision we support, we need to fill the values with 0. Make sure that's the case. Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210819183728.7fb9716db7ba.I75541846e0720f80695186ba39398133c8758280@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 21 ++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index 37da836a8c08..1efac0b2a94d 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -420,16 +420,21 @@ static int iwl_sar_set_profile(union acpi_object *table, * The table from ACPI is flat, but we store it in a * structured array. */ - for (i = 0; i < num_chains; i++) { - for (j = 0; j < num_sub_bands; j++) { - if (table[idx].type != ACPI_TYPE_INTEGER || - table[idx].integer.value > U8_MAX) - return -EINVAL; + for (i = 0; i < ACPI_SAR_NUM_CHAINS_REV2; i++) { + for (j = 0; j < ACPI_SAR_NUM_SUB_BANDS_REV2; j++) { + /* if we don't have the values, use the default */ + if (i >= num_chains || j >= num_sub_bands) { + profile->chains[i].subbands[j] = 0; + } else { + if (table[idx].type != ACPI_TYPE_INTEGER || + table[idx].integer.value > U8_MAX) + return -EINVAL; - profile->chains[i].subbands[j] = - table[idx].integer.value; + profile->chains[i].subbands[j] = + table[idx].integer.value; - idx++; + idx++; + } } } From 59a6ee97e0d4d8f9f3f47df1b82d850ce8e0f0b1 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 19 Aug 2021 18:40:28 +0300 Subject: [PATCH 62/95] iwlwifi: pcie: avoid dma unmap/remap in crash dump DMA-API debug code pointed out that in this code path we never check the return value of dma_map_page(), which could fail. However, we don't really even want to unmap/remap, we just want to ensure that we can actually access the last version of the data that the (now-dead) device may have written, so only need to dma_sync_single_for_cpu() instead. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210819183728.5987f35883a2.I2d9ea5ecc69a5e5947b546fb15f33363a0595651@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 86a949440486..1e6af3cbe026 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -2968,8 +2968,8 @@ static u32 iwl_trans_pcie_dump_rbs(struct iwl_trans *trans, struct iwl_rx_mem_buffer *rxb = rxq->queue[i]; struct iwl_fw_error_dump_rb *rb; - dma_unmap_page(trans->dev, rxb->page_dma, max_len, - DMA_FROM_DEVICE); + dma_sync_single_for_cpu(trans->dev, rxb->page_dma, + max_len, DMA_FROM_DEVICE); rb_len += sizeof(**data) + sizeof(*rb) + max_len; @@ -2978,10 +2978,6 @@ static u32 iwl_trans_pcie_dump_rbs(struct iwl_trans *trans, rb = (void *)(*data)->data; rb->index = cpu_to_le32(i); memcpy(rb->data, page_address(rxb->page), max_len); - /* remap the page for the free benefit */ - rxb->page_dma = dma_map_page(trans->dev, rxb->page, - rxb->offset, max_len, - DMA_FROM_DEVICE); *data = iwl_fw_error_next_data(*data); } From 4246465edb16e493be2f2f1523866b589a234ec5 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 19 Aug 2021 18:40:29 +0300 Subject: [PATCH 63/95] iwlwifi: fix __percpu annotation Sparse warns about some type mismatches, which really is just because of the strangely placed __percpu annotation. Put it into the correct place. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210819183728.0a292b05fcf4.I7e89dfa6495143585021cb628ebb17d52e4588e5@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-trans.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index 2cbc9ecd688b..8f0ff540f439 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -887,7 +887,7 @@ struct iwl_trans_txqs { bool bc_table_dword; u8 page_offs; u8 dev_cmd_offs; - struct __percpu iwl_tso_hdr_page * tso_hdr_page; + struct iwl_tso_hdr_page __percpu *tso_hdr_page; struct { u8 fifo; From 394f419296727cb614494c74b233d9bd3b24e271 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 19 Aug 2021 18:40:30 +0300 Subject: [PATCH 64/95] iwlwifi: api: remove datamember from struct We don't use this, but we embed this struct elsewhere and having structs with flexible arrays embedded isn't quite right, with sparse (for example) complaining. Remove the data[] member in this case. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210819183728.72ca1232b27c.I6ec766691b89670e1683f9fc0fbd12648309a574@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h b/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h index 15a6b3eb999a..9d34c96c1692 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h @@ -33,12 +33,11 @@ struct iwl_fw_ini_hcmd { * * @version: TLV version * @domain: domain of the TLV. One of &enum iwl_fw_ini_dbg_domain - * @data: TLV data */ struct iwl_fw_ini_header { __le32 version; __le32 domain; - u8 data[]; + /* followed by the data */ } __packed; /* FW_TLV_DEBUG_HEADER_S_VER_1 */ /** From 8a433cb64ec5494571f313ba04f28ff58490c8c4 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 19 Aug 2021 18:40:31 +0300 Subject: [PATCH 65/95] iwlwifi: fw: fix debug dump data declarations The debug dump ranges aren't just an array of such ranges since each range has a variable size. Therefore, the use of a struct array is misleading at best. Change it to be a u8 data[] instead of the struct array, the code doesn't significantly change since it's actually doing things correctly now. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210819183728.693c9891097d.Idcaab1fd659e8be2f56be647b2534befd61a4460@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 8 +++---- .../wireless/intel/iwlwifi/fw/error-dump.h | 22 +++++++++++-------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index c1537a9515f7..f826e6c96095 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -1547,7 +1547,7 @@ iwl_dump_ini_mem_fill_header(struct iwl_fw_runtime *fwrt, dump->header.version = cpu_to_le32(IWL_INI_DUMP_VER); - return dump->ranges; + return dump->data; } /** @@ -1611,7 +1611,7 @@ iwl_dump_ini_mon_fill_header(struct iwl_fw_runtime *fwrt, data->header.version = cpu_to_le32(IWL_INI_DUMP_VER); - return data->ranges; + return data->data; } static void * @@ -1647,7 +1647,7 @@ iwl_dump_ini_err_table_fill_header(struct iwl_fw_runtime *fwrt, dump->header.version = cpu_to_le32(IWL_INI_DUMP_VER); dump->version = reg->err_table.version; - return dump->ranges; + return dump->data; } static void * @@ -1662,7 +1662,7 @@ iwl_dump_ini_special_mem_fill_header(struct iwl_fw_runtime *fwrt, dump->type = reg->special_mem.type; dump->version = reg->special_mem.version; - return dump->ranges; + return dump->data; } static u32 iwl_dump_ini_mem_ranges(struct iwl_fw_runtime *fwrt, diff --git a/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h b/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h index 9fffac903b93..521ca2bb0e92 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2014, 2018-2020 Intel Corporation + * Copyright (C) 2014, 2018-2021 Intel Corporation * Copyright (C) 2014-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -305,11 +305,12 @@ struct iwl_fw_ini_error_dump_header { /** * struct iwl_fw_ini_error_dump - ini region dump * @header: the header of this region - * @ranges: the memory ranges of this region + * @data: data of memory ranges in this region, + * see &struct iwl_fw_ini_error_dump_range */ struct iwl_fw_ini_error_dump { struct iwl_fw_ini_error_dump_header header; - struct iwl_fw_ini_error_dump_range ranges[]; + u8 data[]; } __packed; /* This bit is used to differentiate between lmac and umac rxf */ @@ -399,12 +400,13 @@ struct iwl_fw_ini_dump_info { * struct iwl_fw_ini_err_table_dump - ini error table dump * @header: header of the region * @version: error table version - * @ranges: the memory ranges of this this region + * @data: data of memory ranges in this region, + * see &struct iwl_fw_ini_error_dump_range */ struct iwl_fw_ini_err_table_dump { struct iwl_fw_ini_error_dump_header header; __le32 version; - struct iwl_fw_ini_error_dump_range ranges[]; + u8 data[]; } __packed; /** @@ -427,14 +429,15 @@ struct iwl_fw_error_dump_rb { * @write_ptr: write pointer position in the buffer * @cycle_cnt: cycles count * @cur_frag: current fragment in use - * @ranges: the memory ranges of this this region + * @data: data of memory ranges in this region, + * see &struct iwl_fw_ini_error_dump_range */ struct iwl_fw_ini_monitor_dump { struct iwl_fw_ini_error_dump_header header; __le32 write_ptr; __le32 cycle_cnt; __le32 cur_frag; - struct iwl_fw_ini_error_dump_range ranges[]; + u8 data[]; } __packed; /** @@ -442,13 +445,14 @@ struct iwl_fw_ini_monitor_dump { * @header: header of the region * @type: type of special memory * @version: struct special memory version - * @ranges: the memory ranges of this this region + * @data: data of memory ranges in this region, + * see &struct iwl_fw_ini_error_dump_range */ struct iwl_fw_ini_special_device_memory { struct iwl_fw_ini_error_dump_header header; __le16 type; __le16 version; - struct iwl_fw_ini_error_dump_range ranges[]; + u8 data[]; } __packed; /** From 4e110e799cb50dcbf6b57254fd41b595479c91b9 Mon Sep 17 00:00:00 2001 From: Shaul Triebitz Date: Thu, 19 Aug 2021 18:40:32 +0300 Subject: [PATCH 66/95] iwlwifi: add 'Rx control frame to MBSSID' HE capability 'Rx control frame to MBSSID' is supported by HW and FW. Add the capability to the HE mac capabilities. Signed-off-by: Shaul Triebitz Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210819183728.f3d6561dd8ee.I193d5331b43a1ecdae59eaedb37f0190a6d2311d@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c index 03387a5f8cbc..475f951d4b1e 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c @@ -549,7 +549,8 @@ static const struct ieee80211_sband_iftype_data iwl_he_capa[] = { .mac_cap_info[2] = IEEE80211_HE_MAC_CAP2_32BIT_BA_BITMAP, .mac_cap_info[3] = - IEEE80211_HE_MAC_CAP3_OMI_CONTROL, + IEEE80211_HE_MAC_CAP3_OMI_CONTROL | + IEEE80211_HE_MAC_CAP3_RX_CTRL_FRAME_TO_MULTIBSS, .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU | IEEE80211_HE_MAC_CAP4_MULTI_TID_AGG_TX_QOS_B39, From 89639e06d0f35625db506f43971d08b0489cd2ce Mon Sep 17 00:00:00 2001 From: Mukesh Sisodiya Date: Thu, 19 Aug 2021 18:40:33 +0300 Subject: [PATCH 67/95] iwlwifi: yoyo: support for new DBGI_SRAM region new region handling is added for dump collection. Signed-off-by: Mukesh Sisodiya Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210819183728.af9a24b82396.I53c5f82bd2d0f56fd699e3841c922082d99f1c90@changeid Signed-off-by: Luca Coelho --- .../wireless/intel/iwlwifi/fw/api/dbg-tlv.h | 3 ++ drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 37 +++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/iwl-prph.h | 7 ++++ 3 files changed, 47 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h b/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h index 9d34c96c1692..d8b5870d6e9a 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h @@ -129,6 +129,7 @@ struct iwl_fw_ini_region_internal_buffer { * &IWL_FW_INI_REGION_PERIPHERY_PHY, &IWL_FW_INI_REGION_PERIPHERY_AUX, * &IWL_FW_INI_REGION_PAGING, &IWL_FW_INI_REGION_CSR, * &IWL_FW_INI_REGION_DRAM_IMR and &IWL_FW_INI_REGION_PCI_IOSF_CONFIG + * &IWL_FW_INI_REGION_DBGI_SRAM, &FW_TLV_DEBUG_REGION_TYPE_DBGI_SRAM, * @fifos: fifos configuration. Used by &IWL_FW_INI_REGION_TXF and * &IWL_FW_INI_REGION_RXF * @err_table: error table configuration. Used by @@ -295,6 +296,7 @@ enum iwl_fw_ini_buffer_location { * @IWL_FW_INI_REGION_DRAM_IMR: IMR memory * @IWL_FW_INI_REGION_PCI_IOSF_CONFIG: PCI/IOSF config * @IWL_FW_INI_REGION_SPECIAL_DEVICE_MEMORY: special device memory + * @IWL_FW_INI_REGION_DBGI_SRAM: periphery registers of DBGI SRAM * @IWL_FW_INI_REGION_NUM: number of region types */ enum iwl_fw_ini_region_type { @@ -316,6 +318,7 @@ enum iwl_fw_ini_region_type { IWL_FW_INI_REGION_DRAM_IMR, IWL_FW_INI_REGION_PCI_IOSF_CONFIG, IWL_FW_INI_REGION_SPECIAL_DEVICE_MEMORY, + IWL_FW_INI_REGION_DBGI_SRAM, IWL_FW_INI_REGION_NUM }; /* FW_TLV_DEBUG_REGION_TYPE_API_E */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index f826e6c96095..6dcafd0a3d4b 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -1517,6 +1517,37 @@ iwl_dump_ini_special_mem_iter(struct iwl_fw_runtime *fwrt, return sizeof(*range) + le32_to_cpu(range->range_data_size); } +static int +iwl_dump_ini_dbgi_sram_iter(struct iwl_fw_runtime *fwrt, + struct iwl_dump_ini_region_data *reg_data, + void *range_ptr, int idx) +{ + struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data; + struct iwl_fw_ini_error_dump_range *range = range_ptr; + __le32 *val = range->data; + u32 prph_data; + int i; + + if (!iwl_trans_grab_nic_access(fwrt->trans)) + return -EBUSY; + + range->range_data_size = reg->dev_addr.size; + iwl_write_prph_no_grab(fwrt->trans, DBGI_SRAM_TARGET_ACCESS_CFG, + DBGI_SRAM_TARGET_ACCESS_CFG_RESET_ADDRESS_MSK); + for (i = 0; i < (le32_to_cpu(reg->dev_addr.size) / 4); i++) { + prph_data = iwl_read_prph(fwrt->trans, (i % 2) ? + DBGI_SRAM_TARGET_ACCESS_RDATA_MSB : + DBGI_SRAM_TARGET_ACCESS_RDATA_LSB); + if (prph_data == 0x5a5a5a5a) { + iwl_trans_release_nic_access(fwrt->trans); + return -EBUSY; + } + *val++ = cpu_to_le32(prph_data); + } + iwl_trans_release_nic_access(fwrt->trans); + return sizeof(*range) + le32_to_cpu(range->range_data_size); +} + static int iwl_dump_ini_fw_pkt_iter(struct iwl_fw_runtime *fwrt, struct iwl_dump_ini_region_data *reg_data, void *range_ptr, int idx) @@ -2189,6 +2220,12 @@ static const struct iwl_dump_ini_mem_ops iwl_dump_ini_region_ops[] = { .fill_mem_hdr = iwl_dump_ini_special_mem_fill_header, .fill_range = iwl_dump_ini_special_mem_iter, }, + [IWL_FW_INI_REGION_DBGI_SRAM] = { + .get_num_of_ranges = iwl_dump_ini_mem_ranges, + .get_size = iwl_dump_ini_mem_get_size, + .fill_mem_hdr = iwl_dump_ini_mem_fill_header, + .fill_range = iwl_dump_ini_dbgi_sram_iter, + }, }; static u32 iwl_dump_ini_trigger(struct iwl_fw_runtime *fwrt, diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h index 9a9e714bf9af..d0a7d58336a9 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h @@ -348,6 +348,13 @@ #define RFIC_REG_RD 0xAD0470 #define WFPM_CTRL_REG 0xA03030 #define WFPM_GP2 0xA030B4 + +/* DBGI SRAM Register details */ +#define DBGI_SRAM_TARGET_ACCESS_CFG 0x00A2E14C +#define DBGI_SRAM_TARGET_ACCESS_CFG_RESET_ADDRESS_MSK 0x10000 +#define DBGI_SRAM_TARGET_ACCESS_RDATA_LSB 0x00A2E154 +#define DBGI_SRAM_TARGET_ACCESS_RDATA_MSB 0x00A2E158 + enum { ENABLE_WFPM = BIT(31), WFPM_AUX_CTL_AUX_IF_MAC_OWNER_MSK = 0x80000000, From a76b57311b1a247e31b055872d021c38707dc3a8 Mon Sep 17 00:00:00 2001 From: Avraham Stern Date: Thu, 19 Aug 2021 18:40:34 +0300 Subject: [PATCH 68/95] iwlwifi: mvm: don't schedule the roc_done_wk if it is already running When P2P roc is removed, the IWL_MVM_STATUS_NEED_FLUSH_P2P bit is set to indicate to iwl_mvm_roc_done_wk() that the removed roc is a P2P one, so it will flush the broadcast station and not the aux station. However, since setting this bit and scheduling the worker is done in roc ended flow as well as in case the roc is removed, there is a race where the worker has already started running (but did not test this bit yet) and then it is scheduled again. In this case, the first run of the worker will clear this bit, and thus the second run will find it already cleared and will try to flush and remove the aux station by mistake. Fix it by scheduling the worker only if this bit is not yet set. In case this bit is already set, the worker is either running or scheduled, so there is no need to re-schedule it. Signed-off-by: Avraham Stern Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210819183728.8c147659b331.If5924375e9bfd46214ab8ab81cb9d0f5c82fbcbc@changeid Signed-off-by: Luca Coelho --- .../wireless/intel/iwlwifi/mvm/time-event.c | 31 ++++++++++++------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c index 788fd2b84ed2..25af88a3edce 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c @@ -256,6 +256,18 @@ static void iwl_mvm_te_check_trigger(struct iwl_mvm *mvm, } } +static void iwl_mvm_p2p_roc_finished(struct iwl_mvm *mvm) +{ + /* + * If the IWL_MVM_STATUS_NEED_FLUSH_P2P is already set, then the + * roc_done_wk is already scheduled or running, so don't schedule it + * again to avoid a race where the roc_done_wk clears this bit after + * it is set here, affecting the next run of the roc_done_wk. + */ + if (!test_and_set_bit(IWL_MVM_STATUS_NEED_FLUSH_P2P, &mvm->status)) + iwl_mvm_roc_finished(mvm); +} + /* * Handles a FW notification for an event that is known to the driver. * @@ -307,8 +319,7 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm, switch (te_data->vif->type) { case NL80211_IFTYPE_P2P_DEVICE: ieee80211_remain_on_channel_expired(mvm->hw); - set_bit(IWL_MVM_STATUS_NEED_FLUSH_P2P, &mvm->status); - iwl_mvm_roc_finished(mvm); + iwl_mvm_p2p_roc_finished(mvm); break; case NL80211_IFTYPE_STATION: /* @@ -684,8 +695,7 @@ static bool __iwl_mvm_remove_time_event(struct iwl_mvm *mvm, /* Session protection is still ongoing. Cancel it */ iwl_mvm_cancel_session_protection(mvm, mvmvif, id); if (iftype == NL80211_IFTYPE_P2P_DEVICE) { - set_bit(IWL_MVM_STATUS_NEED_FLUSH_P2P, &mvm->status); - iwl_mvm_roc_finished(mvm); + iwl_mvm_p2p_roc_finished(mvm); } } return false; @@ -852,8 +862,7 @@ void iwl_mvm_rx_session_protect_notif(struct iwl_mvm *mvm, /* End TE, notify mac80211 */ mvmvif->time_event_data.id = SESSION_PROTECT_CONF_MAX_ID; ieee80211_remain_on_channel_expired(mvm->hw); - set_bit(IWL_MVM_STATUS_NEED_FLUSH_P2P, &mvm->status); - iwl_mvm_roc_finished(mvm); + iwl_mvm_p2p_roc_finished(mvm); } else if (le32_to_cpu(notif->start)) { if (WARN_ON(mvmvif->time_event_data.id != le32_to_cpu(notif->conf_id))) @@ -1014,14 +1023,13 @@ void iwl_mvm_stop_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif) if (vif->type == NL80211_IFTYPE_P2P_DEVICE) { iwl_mvm_cancel_session_protection(mvm, mvmvif, mvmvif->time_event_data.id); - set_bit(IWL_MVM_STATUS_NEED_FLUSH_P2P, &mvm->status); + iwl_mvm_p2p_roc_finished(mvm); } else { iwl_mvm_remove_aux_roc_te(mvm, mvmvif, &mvmvif->time_event_data); + iwl_mvm_roc_finished(mvm); } - iwl_mvm_roc_finished(mvm); - return; } @@ -1035,12 +1043,11 @@ void iwl_mvm_stop_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif) if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) { iwl_mvm_remove_time_event(mvm, mvmvif, te_data); - set_bit(IWL_MVM_STATUS_NEED_FLUSH_P2P, &mvm->status); + iwl_mvm_p2p_roc_finished(mvm); } else { iwl_mvm_remove_aux_roc_te(mvm, mvmvif, te_data); + iwl_mvm_roc_finished(mvm); } - - iwl_mvm_roc_finished(mvm); } void iwl_mvm_remove_csa_period(struct iwl_mvm *mvm, From 7e47f41648b215d458f2e0f35e26fe4157b9eb98 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 19 Aug 2021 18:40:35 +0300 Subject: [PATCH 69/95] iwlwifi: allow debug init in RF-kill We can send this even if initializing in RF-kill, thus suppressing a bunch of error messages about it. In fact, we _want_ to, since we might still want to debug the firmware even if in RF-kill. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210819183728.bcdb076609e2.I2d177c00772510b5338d8aa45af7558138b08448@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c index dc4bff681e52..125479b5c0d6 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c @@ -623,6 +623,7 @@ static int iwl_dbg_tlv_apply_buffer(struct iwl_fw_runtime *fwrt, .id = WIDE_ID(DEBUG_GROUP, BUFFER_ALLOCATION), .data[0] = &data, .len[0] = sizeof(data), + .flags = CMD_SEND_IN_RFKILL, }; int ret, j; From 830aa3e7d1ca1a7c8b6f414ac5bf8da561a45867 Mon Sep 17 00:00:00 2001 From: Avraham Stern Date: Thu, 26 Aug 2021 22:47:37 +0300 Subject: [PATCH 70/95] iwlwifi: mvm: add support for range request command version 13 This version adds the following configuration options: 1. Set the BSS color for NDP ranging 2. Set the minimum and maximum time between measurements for non trigger based NDP ranging. 3. Terminate the session in case the responder requests LMR feedback. Signed-off-by: Avraham Stern Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210826224715.9dcd5210b7e5.I76f6977cde852de0f251344e279ad85076eef8d6@changeid Signed-off-by: Luca Coelho --- .../wireless/intel/iwlwifi/fw/api/location.h | 119 +++++++++++++++++- .../wireless/intel/iwlwifi/mvm/constants.h | 5 +- .../intel/iwlwifi/mvm/ftm-initiator.c | 83 ++++++++++-- 3 files changed, 193 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/location.h b/drivers/net/wireless/intel/iwlwifi/fw/api/location.h index 0e38eb1cd75d..0a8681d9687c 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/location.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/location.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* * Copyright (C) 2015-2017 Intel Deutschland GmbH - * Copyright (C) 2018-2020 Intel Corporation + * Copyright (C) 2018-2021 Intel Corporation */ #ifndef __iwl_fw_api_location_h__ #define __iwl_fw_api_location_h__ @@ -489,6 +489,10 @@ struct iwl_tof_range_req_ap_entry_v2 { * instead of fw internal values. * @IWL_INITIATOR_AP_FLAGS_PMF: request to protect the negotiation and LMR * frames with protected management frames. + * @IWL_INITIATOR_AP_FLAGS_TERMINATE_ON_LMR_FEEDBACK: terminate the session if + * the responder asked for LMR feedback although the initiator did not set + * the LMR feedback bit in the FTM request. If not set, the initiator will + * continue with the session and will provide the LMR feedback. */ enum iwl_initiator_ap_flags { IWL_INITIATOR_AP_FLAGS_ASAP = BIT(1), @@ -504,6 +508,7 @@ enum iwl_initiator_ap_flags { IWL_INITIATOR_AP_FLAGS_LMR_FEEDBACK = BIT(12), IWL_INITIATOR_AP_FLAGS_USE_CALIB = BIT(13), IWL_INITIATOR_AP_FLAGS_PMF = BIT(14), + IWL_INITIATOR_AP_FLAGS_TERMINATE_ON_LMR_FEEDBACK = BIT(15), }; /** @@ -794,6 +799,90 @@ struct iwl_tof_range_req_ap_entry_v8 { u8 i2r_max_total_ltf; } __packed; /* LOCATION_RANGE_REQ_AP_ENTRY_CMD_API_S_VER_8 */ +/** + * struct iwl_tof_range_req_ap_entry_v9 - AP configuration parameters + * @initiator_ap_flags: see &enum iwl_initiator_ap_flags. + * @channel_num: AP Channel number + * @format_bw: bits 0 - 3: &enum iwl_location_frame_format. + * bits 4 - 7: &enum iwl_location_bw. + * @ctrl_ch_position: Coding of the control channel position relative to the + * center frequency, see iwl_mvm_get_ctrl_pos(). + * @ftmr_max_retries: Max number of retries to send the FTMR in case of no + * reply from the AP. + * @bssid: AP's BSSID + * @burst_period: For EDCA based ranging: Recommended value to be sent to the + * AP. Measurement periodicity In units of 100ms. ignored if + * num_of_bursts_exp = 0. + * For non trigger based NDP ranging, the maximum time between + * measurements in units of milliseconds. + * @samples_per_burst: the number of FTMs pairs in single Burst (1-31); + * @num_of_bursts: Recommended value to be sent to the AP. 2s Exponent of + * the number of measurement iterations (min 2^0 = 1, max 2^14) + * @sta_id: the station id of the AP. Only relevant when associated to the AP, + * otherwise should be set to &IWL_MVM_INVALID_STA. + * @cipher: pairwise cipher suite for secured measurement. + * &enum iwl_location_cipher. + * @hltk: HLTK to be used for secured 11az measurement + * @tk: TK to be used for secured 11az measurement + * @calib: An array of calibration values per FTM rx bandwidth. + * If &IWL_INITIATOR_AP_FLAGS_USE_CALIB is set, the fw will use the + * calibration value that corresponds to the rx bandwidth of the FTM + * frame. + * @beacon_interval: beacon interval of the AP in TUs. Only required if + * &IWL_INITIATOR_AP_FLAGS_TB is set. + * @bss_color: the BSS color of the responder. Only valid if + * &IWL_INITIATOR_AP_FLAGS_TB or &IWL_INITIATOR_AP_FLAGS_NON_TB is set. + * @rx_pn: the next expected PN for protected management frames Rx. LE byte + * order. Only valid if &IWL_INITIATOR_AP_FLAGS_SECURED is set and sta_id + * is set to &IWL_MVM_INVALID_STA. + * @tx_pn: the next PN to use for protected management frames Tx. LE byte + * order. Only valid if &IWL_INITIATOR_AP_FLAGS_SECURED is set and sta_id + * is set to &IWL_MVM_INVALID_STA. + * @r2i_ndp_params: parameters for R2I NDP ranging negotiation. + * bits 0 - 2: max LTF repetitions + * bits 3 - 5: max number of spatial streams + * bits 6 - 7: reserved + * @i2r_ndp_params: parameters for I2R NDP ranging negotiation. + * bits 0 - 2: max LTF repetitions + * bits 3 - 5: max number of spatial streams (supported values are < 2) + * bits 6 - 7: reserved + * @r2i_max_total_ltf: R2I Max Total LTFs for NDP ranging negotiation. + * One of &enum ieee80211_range_params_max_total_ltf. + * @i2r_max_total_ltf: I2R Max Total LTFs for NDP ranging negotiation. + * One of &enum ieee80211_range_params_max_total_ltf. + * @bss_color: the BSS color of the responder. Only valid if + * &IWL_INITIATOR_AP_FLAGS_NON_TB or &IWL_INITIATOR_AP_FLAGS_TB is set. + * @band: 0 for 5.2 GHz, 1 for 2.4 GHz, 2 for 6GHz + * @min_time_between_msr: For non trigger based NDP ranging, the minimum time + * between measurements in units of milliseconds + */ +struct iwl_tof_range_req_ap_entry_v9 { + __le32 initiator_ap_flags; + u8 channel_num; + u8 format_bw; + u8 ctrl_ch_position; + u8 ftmr_max_retries; + u8 bssid[ETH_ALEN]; + __le16 burst_period; + u8 samples_per_burst; + u8 num_of_bursts; + u8 sta_id; + u8 cipher; + u8 hltk[HLTK_11AZ_LEN]; + u8 tk[TK_11AZ_LEN]; + __le16 calib[IWL_TOF_BW_NUM]; + u16 beacon_interval; + u8 rx_pn[IEEE80211_CCMP_PN_LEN]; + u8 tx_pn[IEEE80211_CCMP_PN_LEN]; + u8 r2i_ndp_params; + u8 i2r_ndp_params; + u8 r2i_max_total_ltf; + u8 i2r_max_total_ltf; + u8 bss_color; + u8 band; + __le16 min_time_between_msr; +} __packed; /* LOCATION_RANGE_REQ_AP_ENTRY_CMD_API_S_VER_9 */ + /** * enum iwl_tof_response_mode * @IWL_MVM_TOF_RESPONSE_ASAP: report each AP measurement separately as soon as @@ -1043,6 +1132,34 @@ struct iwl_tof_range_req_cmd_v12 { struct iwl_tof_range_req_ap_entry_v8 ap[IWL_MVM_TOF_MAX_APS]; } __packed; /* LOCATION_RANGE_REQ_CMD_API_S_VER_12 */ +/** + * struct iwl_tof_range_req_cmd_v13 - start measurement cmd + * @initiator_flags: see flags @ iwl_tof_initiator_flags + * @request_id: A Token incremented per request. The same Token will be + * sent back in the range response + * @num_of_ap: Number of APs to measure (error if > IWL_MVM_TOF_MAX_APS) + * @range_req_bssid: ranging request BSSID + * @macaddr_mask: Bits set to 0 shall be copied from the MAC address template. + * Bits set to 1 shall be randomized by the UMAC + * @macaddr_template: MAC address template to use for non-randomized bits + * @req_timeout_ms: Requested timeout of the response in units of milliseconds. + * This is the session time for completing the measurement. + * @tsf_mac_id: report the measurement start time for each ap in terms of the + * TSF of this mac id. 0xff to disable TSF reporting. + * @ap: per-AP request data, see &struct iwl_tof_range_req_ap_entry_v9. + */ +struct iwl_tof_range_req_cmd_v13 { + __le32 initiator_flags; + u8 request_id; + u8 num_of_ap; + u8 range_req_bssid[ETH_ALEN]; + u8 macaddr_mask[ETH_ALEN]; + u8 macaddr_template[ETH_ALEN]; + __le32 req_timeout_ms; + __le32 tsf_mac_id; + struct iwl_tof_range_req_ap_entry_v9 ap[IWL_MVM_TOF_MAX_APS]; +} __packed; /* LOCATION_RANGE_REQ_CMD_API_S_VER_13 */ + /* * enum iwl_tof_range_request_status - status of the sent request * @IWL_TOF_RANGE_REQUEST_STATUS_SUCCESSFUL - FW successfully received the diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/constants.h b/drivers/net/wireless/intel/iwlwifi/mvm/constants.h index 1343f25f1090..9d0d01f27d92 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/constants.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/constants.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* * Copyright (C) 2013-2015 Intel Mobile Communications GmbH - * Copyright (C) 2013-2014, 2018-2020 Intel Corporation + * Copyright (C) 2013-2014, 2018-2021 Intel Corporation * Copyright (C) 2015 Intel Deutschland GmbH */ #ifndef __MVM_CONSTANTS_H @@ -93,6 +93,7 @@ #define IWL_MVM_ENABLE_EBS 1 #define IWL_MVM_FTM_INITIATOR_ALGO IWL_TOF_ALGO_TYPE_MAX_LIKE #define IWL_MVM_FTM_INITIATOR_DYNACK true +#define IWL_MVM_FTM_LMR_FEEDBACK_TERMINATE false #define IWL_MVM_FTM_R2I_MAX_REP 7 #define IWL_MVM_FTM_I2R_MAX_REP 7 #define IWL_MVM_FTM_R2I_MAX_STS 1 @@ -102,6 +103,8 @@ #define IWL_MVM_FTM_INITIATOR_SECURE_LTF false #define IWL_MVM_FTM_RESP_NDP_SUPPORT true #define IWL_MVM_FTM_RESP_LMR_FEEDBACK_SUPPORT true +#define IWL_MVM_FTM_NON_TB_MIN_TIME_BETWEEN_MSR 5 +#define IWL_MVM_FTM_NON_TB_MAX_TIME_BETWEEN_MSR 1000 #define IWL_MVM_D3_DEBUG false #define IWL_MVM_USE_TWT true #define IWL_MVM_AMPDU_CONSEC_DROPS_DELBA 10 diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c index 59cef0d89a6d..03e5bf5cb909 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c @@ -754,6 +754,33 @@ iwl_mvm_ftm_set_ndp_params(struct iwl_mvm *mvm, target->i2r_max_total_ltf = IWL_MVM_FTM_I2R_MAX_TOTAL_LTF; } +static int +iwl_mvm_ftm_put_target_v8(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + struct cfg80211_pmsr_request_peer *peer, + struct iwl_tof_range_req_ap_entry_v8 *target) +{ + u32 flags; + int ret = iwl_mvm_ftm_put_target_v7(mvm, vif, peer, (void *)target); + + if (ret) + return ret; + + iwl_mvm_ftm_set_ndp_params(mvm, target); + + /* + * If secure LTF is turned off, replace the flag with PMF only + */ + flags = le32_to_cpu(target->initiator_ap_flags); + if ((flags & IWL_INITIATOR_AP_FLAGS_SECURED) && + !IWL_MVM_FTM_INITIATOR_SECURE_LTF) { + flags &= ~IWL_INITIATOR_AP_FLAGS_SECURED; + flags |= IWL_INITIATOR_AP_FLAGS_PMF; + target->initiator_ap_flags = cpu_to_le32(flags); + } + + return 0; +} + static int iwl_mvm_ftm_start_v12(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct cfg80211_pmsr_request *req) @@ -773,24 +800,53 @@ static int iwl_mvm_ftm_start_v12(struct iwl_mvm *mvm, for (i = 0; i < cmd.num_of_ap; i++) { struct cfg80211_pmsr_request_peer *peer = &req->peers[i]; struct iwl_tof_range_req_ap_entry_v8 *target = &cmd.ap[i]; - u32 flags; - err = iwl_mvm_ftm_put_target_v7(mvm, vif, peer, (void *)target); + err = iwl_mvm_ftm_put_target_v8(mvm, vif, peer, target); + if (err) + return err; + } + + return iwl_mvm_ftm_send_cmd(mvm, &hcmd); +} + +static int iwl_mvm_ftm_start_v13(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + struct cfg80211_pmsr_request *req) +{ + struct iwl_tof_range_req_cmd_v13 cmd; + struct iwl_host_cmd hcmd = { + .id = iwl_cmd_id(TOF_RANGE_REQ_CMD, LOCATION_GROUP, 0), + .dataflags[0] = IWL_HCMD_DFL_DUP, + .data[0] = &cmd, + .len[0] = sizeof(cmd), + }; + u8 i; + int err; + + iwl_mvm_ftm_cmd_common(mvm, vif, (void *)&cmd, req); + + for (i = 0; i < cmd.num_of_ap; i++) { + struct cfg80211_pmsr_request_peer *peer = &req->peers[i]; + struct iwl_tof_range_req_ap_entry_v9 *target = &cmd.ap[i]; + + err = iwl_mvm_ftm_put_target_v8(mvm, vif, peer, (void *)target); if (err) return err; - iwl_mvm_ftm_set_ndp_params(mvm, target); + if (peer->ftm.trigger_based || peer->ftm.non_trigger_based) + target->bss_color = peer->ftm.bss_color; - /* - * If secure LTF is turned off, replace the flag with PMF only - */ - flags = le32_to_cpu(target->initiator_ap_flags); - if ((flags & IWL_INITIATOR_AP_FLAGS_SECURED) && - !IWL_MVM_FTM_INITIATOR_SECURE_LTF) { - flags &= ~IWL_INITIATOR_AP_FLAGS_SECURED; - flags |= IWL_INITIATOR_AP_FLAGS_PMF; - target->initiator_ap_flags = cpu_to_le32(flags); + if (peer->ftm.non_trigger_based) { + target->min_time_between_msr = + cpu_to_le16(IWL_MVM_FTM_NON_TB_MIN_TIME_BETWEEN_MSR); + target->burst_period = + cpu_to_le16(IWL_MVM_FTM_NON_TB_MAX_TIME_BETWEEN_MSR); + } else { + target->min_time_between_msr = cpu_to_le16(0); } + + target->band = + iwl_mvm_phy_band_from_nl80211(peer->chandef.chan->band); } return iwl_mvm_ftm_send_cmd(mvm, &hcmd); @@ -814,6 +870,9 @@ int iwl_mvm_ftm_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, IWL_FW_CMD_VER_UNKNOWN); switch (cmd_ver) { + case 13: + err = iwl_mvm_ftm_start_v13(mvm, vif, req); + break; case 12: err = iwl_mvm_ftm_start_v12(mvm, vif, req); break; From bd34ff380e783d129bf3fc6b8762967ee8eab14f Mon Sep 17 00:00:00 2001 From: Avraham Stern Date: Thu, 26 Aug 2021 22:47:38 +0300 Subject: [PATCH 71/95] iwlwifi: mvm: add support for responder config command version 9 This version adds the following configuration options: 1. Enable/disable setting the session id in the FTM frame 2. Set the BSS color for the responder 3. Set the minimum and maximum time between measurements for non trigger based NDP ranging. Signed-off-by: Avraham Stern Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210826224715.0a10d43f3d7f.Ice4112c1910cf94babd1c2d492a3a3de9f7ee6cb@changeid Signed-off-by: Luca Coelho --- .../wireless/intel/iwlwifi/fw/api/location.h | 70 +++++++++++++++++-- .../intel/iwlwifi/mvm/ftm-responder.c | 27 +++++-- 2 files changed, 88 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/location.h b/drivers/net/wireless/intel/iwlwifi/fw/api/location.h index 0a8681d9687c..6bbb8b8c91cd 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/location.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/location.h @@ -151,6 +151,10 @@ enum iwl_tof_mcsi_enable { * is valid * @IWL_TOF_RESPONDER_CMD_VALID_NDP_PARAMS: NDP parameters are valid * @IWL_TOF_RESPONDER_CMD_VALID_LMR_FEEDBACK: LMR feedback support is valid + * @IWL_TOF_RESPONDER_CMD_VALID_SESSION_ID: session id flag is valid + * @IWL_TOF_RESPONDER_CMD_VALID_BSS_COLOR: the bss_color field is valid + * @IWL_TOF_RESPONDER_CMD_VALID_MIN_MAX_TIME_BETWEEN_MSR: the + * min_time_between_msr and max_time_between_msr fields are valid */ enum iwl_tof_responder_cmd_valid_field { IWL_TOF_RESPONDER_CMD_VALID_CHAN_INFO = BIT(0), @@ -169,6 +173,9 @@ enum iwl_tof_responder_cmd_valid_field { IWL_TOF_RESPONDER_CMD_VALID_NDP_SUPPORT = BIT(22), IWL_TOF_RESPONDER_CMD_VALID_NDP_PARAMS = BIT(23), IWL_TOF_RESPONDER_CMD_VALID_LMR_FEEDBACK = BIT(24), + IWL_TOF_RESPONDER_CMD_VALID_SESSION_ID = BIT(25), + IWL_TOF_RESPONDER_CMD_VALID_BSS_COLOR = BIT(26), + IWL_TOF_RESPONDER_CMD_VALID_MIN_MAX_TIME_BETWEEN_MSR = BIT(27), }; /** @@ -186,6 +193,8 @@ enum iwl_tof_responder_cmd_valid_field { * @IWL_TOF_RESPONDER_FLAGS_NDP_SUPPORT: support NDP ranging * @IWL_TOF_RESPONDER_FLAGS_LMR_FEEDBACK: request for LMR feedback if the * initiator supports it + * @IWL_TOF_RESPONDER_FLAGS_SESSION_ID: send the session id in the initial FTM + * frame. */ enum iwl_tof_responder_cfg_flags { IWL_TOF_RESPONDER_FLAGS_NON_ASAP_SUPPORT = BIT(0), @@ -200,6 +209,7 @@ enum iwl_tof_responder_cfg_flags { IWL_TOF_RESPONDER_FLAGS_FTM_TX_ANT = RATE_MCS_ANT_ABC_MSK, IWL_TOF_RESPONDER_FLAGS_NDP_SUPPORT = BIT(24), IWL_TOF_RESPONDER_FLAGS_LMR_FEEDBACK = BIT(25), + IWL_TOF_RESPONDER_FLAGS_SESSION_ID = BIT(27), }; /** @@ -297,13 +307,13 @@ struct iwl_tof_responder_config_cmd_v7 { * @r2i_ndp_params: parameters for R2I NDP. * bits 0 - 2: max number of LTF repetitions * bits 3 - 5: max number of spatial streams (supported values are < 2) - * bits 6 - 7: max number of total LTFs - * (&enum ieee80211_range_params_max_total_ltf) + * bits 6 - 7: max number of total LTFs see + * &enum ieee80211_range_params_max_total_ltf * @i2r_ndp_params: parameters for I2R NDP. * bits 0 - 2: max number of LTF repetitions * bits 3 - 5: max number of spatial streams - * bits 6 - 7: max number of total LTFs - * (&enum ieee80211_range_params_max_total_ltf) + * bits 6 - 7: max number of total LTFs see + * &enum ieee80211_range_params_max_total_ltf */ struct iwl_tof_responder_config_cmd_v8 { __le32 cmd_valid_fields; @@ -322,6 +332,58 @@ struct iwl_tof_responder_config_cmd_v8 { u8 i2r_ndp_params; } __packed; /* TOF_RESPONDER_CONFIG_CMD_API_S_VER_8 */ +/** + * struct iwl_tof_responder_config_cmd_v9 - ToF AP mode (for debug) + * @cmd_valid_fields: &iwl_tof_responder_cmd_valid_field + * @responder_cfg_flags: &iwl_tof_responder_cfg_flags + * @format_bw: bits 0 - 3: &enum iwl_location_frame_format. + * bits 4 - 7: &enum iwl_location_bw. + * @bss_color: current AP bss_color + * @channel_num: current AP Channel + * @ctrl_ch_position: coding of the control channel position relative to + * the center frequency, see iwl_mvm_get_ctrl_pos() + * @sta_id: index of the AP STA when in AP mode + * @reserved1: reserved + * @toa_offset: Artificial addition [pSec] for the ToA - to be used for debug + * purposes, simulating station movement by adding various values + * to this field + * @common_calib: XVT: common calibration value + * @specific_calib: XVT: specific calibration value + * @bssid: Current AP BSSID + * @r2i_ndp_params: parameters for R2I NDP. + * bits 0 - 2: max number of LTF repetitions + * bits 3 - 5: max number of spatial streams (supported values are < 2) + * bits 6 - 7: max number of total LTFs see + * &enum ieee80211_range_params_max_total_ltf + * @i2r_ndp_params: parameters for I2R NDP. + * bits 0 - 2: max number of LTF repetitions + * bits 3 - 5: max number of spatial streams + * bits 6 - 7: max number of total LTFs see + * &enum ieee80211_range_params_max_total_ltf + * @min_time_between_msr: for non trigger based NDP ranging, minimum time + * between measurements in milliseconds. + * @max_time_between_msr: for non trigger based NDP ranging, maximum time + * between measurements in milliseconds. + */ +struct iwl_tof_responder_config_cmd_v9 { + __le32 cmd_valid_fields; + __le32 responder_cfg_flags; + u8 format_bw; + u8 bss_color; + u8 channel_num; + u8 ctrl_ch_position; + u8 sta_id; + u8 reserved1; + __le16 toa_offset; + __le16 common_calib; + __le16 specific_calib; + u8 bssid[ETH_ALEN]; + u8 r2i_ndp_params; + u8 i2r_ndp_params; + __le16 min_time_between_msr; + __le16 max_time_between_msr; +} __packed; /* TOF_RESPONDER_CONFIG_CMD_API_S_VER_8 */ + #define IWL_LCI_CIVIC_IE_MAX_SIZE 400 /** diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c index 5a249ea97eb2..eba5433c2626 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* * Copyright (C) 2015-2017 Intel Deutschland GmbH - * Copyright (C) 2018-2020 Intel Corporation + * Copyright (C) 2018-2021 Intel Corporation */ #include #include @@ -77,7 +77,7 @@ static int iwl_mvm_ftm_responder_set_bw_v2(struct cfg80211_chan_def *chandef, static void iwl_mvm_ftm_responder_set_ndp(struct iwl_mvm *mvm, - struct iwl_tof_responder_config_cmd_v8 *cmd) + struct iwl_tof_responder_config_cmd_v9 *cmd) { /* Up to 2 R2I STS are allowed on the responder */ u32 r2i_max_sts = IWL_MVM_FTM_R2I_MAX_STS < 2 ? @@ -104,7 +104,7 @@ iwl_mvm_ftm_responder_cmd(struct iwl_mvm *mvm, * field interpretation is different), so the same struct can be use * for all cases. */ - struct iwl_tof_responder_config_cmd_v8 cmd = { + struct iwl_tof_responder_config_cmd_v9 cmd = { .channel_num = chandef->chan->hw_value, .cmd_valid_fields = cpu_to_le32(IWL_TOF_RESPONDER_CMD_VALID_CHAN_INFO | @@ -115,10 +115,27 @@ iwl_mvm_ftm_responder_cmd(struct iwl_mvm *mvm, u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, LOCATION_GROUP, TOF_RESPONDER_CONFIG_CMD, 6); int err; + int cmd_size; lockdep_assert_held(&mvm->mutex); -if (cmd_ver == 8) + /* Use a default of bss_color=1 for now */ + if (cmd_ver == 9) { + cmd.cmd_valid_fields |= + cpu_to_le32(IWL_TOF_RESPONDER_CMD_VALID_BSS_COLOR | + IWL_TOF_RESPONDER_CMD_VALID_MIN_MAX_TIME_BETWEEN_MSR); + cmd.bss_color = 1; + cmd.min_time_between_msr = + cpu_to_le16(IWL_MVM_FTM_NON_TB_MIN_TIME_BETWEEN_MSR); + cmd.max_time_between_msr = + cpu_to_le16(IWL_MVM_FTM_NON_TB_MAX_TIME_BETWEEN_MSR); + cmd_size = sizeof(struct iwl_tof_responder_config_cmd_v9); + } else { + /* All versions up to version 8 have the same size */ + cmd_size = sizeof(struct iwl_tof_responder_config_cmd_v8); + } + + if (cmd_ver >= 8) iwl_mvm_ftm_responder_set_ndp(mvm, &cmd); if (cmd_ver >= 7) @@ -137,7 +154,7 @@ if (cmd_ver == 8) return iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(TOF_RESPONDER_CONFIG_CMD, LOCATION_GROUP, 0), - 0, sizeof(cmd), &cmd); + 0, cmd_size, &cmd); } static int From b05c1d14a177eaffe3aa7fa18b39df3a3e1f3a47 Mon Sep 17 00:00:00 2001 From: Dror Moshe Date: Thu, 26 Aug 2021 22:47:39 +0300 Subject: [PATCH 72/95] iwlwifi: move get pnvm file name to a separate function Move code that generates the pnvm file name to a separate function, so that it can be reused. Signed-off-by: Dror Moshe Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210826224715.7d2dd18c75a2.I3652584755b9ab44909ddcd09ff4d80c6690a1ad@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/pnvm.c | 13 ++----------- drivers/net/wireless/intel/iwlwifi/fw/pnvm.h | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c index 34e24196c1a3..314ed90c23dd 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c @@ -230,19 +230,10 @@ static int iwl_pnvm_parse(struct iwl_trans *trans, const u8 *data, static int iwl_pnvm_get_from_fs(struct iwl_trans *trans, u8 **data, size_t *len) { const struct firmware *pnvm; - char pnvm_name[64]; + char pnvm_name[MAX_PNVM_NAME]; int ret; - /* - * The prefix unfortunately includes a hyphen at the end, so - * don't add the dot here... - */ - snprintf(pnvm_name, sizeof(pnvm_name), "%spnvm", - trans->cfg->fw_name_pre); - - /* ...but replace the hyphen with the dot here. */ - if (strlen(trans->cfg->fw_name_pre) < sizeof(pnvm_name)) - pnvm_name[strlen(trans->cfg->fw_name_pre) - 1] = '.'; + iwl_pnvm_get_fs_name(trans, pnvm_name, sizeof(pnvm_name)); ret = firmware_request_nowarn(&pnvm, pnvm_name, trans->dev); if (ret) { diff --git a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.h b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.h index 61d3d4e0b7d9..203c367dd4de 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.h @@ -12,7 +12,27 @@ #define MVM_UCODE_PNVM_TIMEOUT (HZ / 4) +#define MAX_PNVM_NAME 64 + int iwl_pnvm_load(struct iwl_trans *trans, struct iwl_notif_wait_data *notif_wait); +static inline +void iwl_pnvm_get_fs_name(struct iwl_trans *trans, + u8 *pnvm_name, size_t max_len) +{ + int pre_len; + + /* + * The prefix unfortunately includes a hyphen at the end, so + * don't add the dot here... + */ + snprintf(pnvm_name, max_len, "%spnvm", trans->cfg->fw_name_pre); + + /* ...but replace the hyphen with the dot here. */ + pre_len = strlen(trans->cfg->fw_name_pre); + if (pre_len < max_len && pre_len > 0) + pnvm_name[pre_len - 1] = '.'; +} + #endif /* __IWL_PNVM_H__ */ From fb3fac5fafa8a6d45853b183c36cda4c13e1c279 Mon Sep 17 00:00:00 2001 From: Gregory Greenman Date: Thu, 26 Aug 2021 22:47:40 +0300 Subject: [PATCH 73/95] iwlwifi: mvm: introduce iwl_stored_beacon_notif_v3 The new version sends station id in the notification. It's still not used, but need to adjust the code since the offset of the data was changed. Signed-off-by: Gregory Greenman Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210826224715.87bc9e45c40b.I770493dc4a293ed8bdf059518e94dccf5dd1b3a7@changeid Signed-off-by: Luca Coelho --- .../wireless/intel/iwlwifi/fw/api/offload.h | 31 +++++++++++++++++-- .../net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 26 ++++++++++++++-- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 2 +- 3 files changed, 52 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/offload.h b/drivers/net/wireless/intel/iwlwifi/fw/api/offload.h index f06214d418aa..5204aa94e72a 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/offload.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/offload.h @@ -3,6 +3,7 @@ * Copyright (C) 2012-2014 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH + * Copyright (C) 2021 Intel Corporation */ #ifndef __iwl_fw_api_offload_h__ #define __iwl_fw_api_offload_h__ @@ -20,7 +21,7 @@ enum iwl_prot_offload_subcmd_ids { #define MAX_STORED_BEACON_SIZE 600 /** - * struct iwl_stored_beacon_notif - Stored beacon notification + * struct iwl_stored_beacon_notif_common - Stored beacon notif common fields * * @system_time: system time on air rise * @tsf: TSF on air rise @@ -29,9 +30,8 @@ enum iwl_prot_offload_subcmd_ids { * @channel: channel this beacon was received on * @rates: rate in ucode internal format * @byte_count: frame's byte count - * @data: beacon data, length in @byte_count */ -struct iwl_stored_beacon_notif { +struct iwl_stored_beacon_notif_common { __le32 system_time; __le64 tsf; __le32 beacon_timestamp; @@ -39,7 +39,32 @@ struct iwl_stored_beacon_notif { __le16 channel; __le32 rates; __le32 byte_count; +} __packed; + +/** + * struct iwl_stored_beacon_notif - Stored beacon notification + * + * @common: fields common for all versions + * @data: beacon data, length in @byte_count + */ +struct iwl_stored_beacon_notif_v2 { + struct iwl_stored_beacon_notif_common common; u8 data[MAX_STORED_BEACON_SIZE]; } __packed; /* WOWLAN_STROED_BEACON_INFO_S_VER_2 */ +/** + * struct iwl_stored_beacon_notif_v3 - Stored beacon notification + * + * @common: fields common for all versions + * @sta_id: station for which the beacon was received + * @reserved: reserved for alignment + * @data: beacon data, length in @byte_count + */ +struct iwl_stored_beacon_notif_v3 { + struct iwl_stored_beacon_notif_common common; + u8 sta_id; + u8 reserved[3]; + u8 data[MAX_STORED_BEACON_SIZE]; +} __packed; /* WOWLAN_STROED_BEACON_INFO_S_VER_3 */ + #endif /* __iwl_fw_api_offload_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index 2fbc1a3bbdca..1ebd4654d18e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -1432,14 +1432,34 @@ void iwl_mvm_rx_stored_beacon_notif(struct iwl_mvm *mvm, { struct iwl_rx_packet *pkt = rxb_addr(rxb); unsigned int pkt_len = iwl_rx_packet_payload_len(pkt); - struct iwl_stored_beacon_notif *sb = (void *)pkt->data; + struct iwl_stored_beacon_notif_common *sb = (void *)pkt->data; struct ieee80211_rx_status rx_status; struct sk_buff *skb; + u8 *data; u32 size = le32_to_cpu(sb->byte_count); + int ver = iwl_fw_lookup_cmd_ver(mvm->fw, PROT_OFFLOAD_GROUP, + STORED_BEACON_NTF, 0); - if (size == 0 || pkt_len < struct_size(sb, data, size)) + if (size == 0) return; + /* handle per-version differences */ + if (ver <= 2) { + struct iwl_stored_beacon_notif_v2 *sb_v2 = (void *)pkt->data; + + if (pkt_len < struct_size(sb_v2, data, size)) + return; + + data = sb_v2->data; + } else { + struct iwl_stored_beacon_notif_v3 *sb_v3 = (void *)pkt->data; + + if (pkt_len < struct_size(sb_v3, data, size)) + return; + + data = sb_v3->data; + } + skb = alloc_skb(size, GFP_ATOMIC); if (!skb) { IWL_ERR(mvm, "alloc_skb failed\n"); @@ -1460,7 +1480,7 @@ void iwl_mvm_rx_stored_beacon_notif(struct iwl_mvm *mvm, rx_status.band); /* copy the data */ - skb_put_data(skb, sb->data, size); + skb_put_data(skb, data, size); memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); /* pass it as regular rx to mac80211 */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 8ce937f8445a..6f60018feed1 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -373,7 +373,7 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { struct iwl_mfu_assert_dump_notif), RX_HANDLER_GRP(PROT_OFFLOAD_GROUP, STORED_BEACON_NTF, iwl_mvm_rx_stored_beacon_notif, RX_HANDLER_SYNC, - struct iwl_stored_beacon_notif), + struct iwl_stored_beacon_notif_v2), RX_HANDLER_GRP(DATA_PATH_GROUP, MU_GROUP_MGMT_NOTIF, iwl_mvm_mu_mimo_grp_notif, RX_HANDLER_SYNC, struct iwl_mu_group_mgmt_notif), From cde5dbaa35edbf4467cd6ac5b3588861257685a1 Mon Sep 17 00:00:00 2001 From: Shaul Triebitz Date: Thu, 26 Aug 2021 22:47:41 +0300 Subject: [PATCH 74/95] iwlwifi: mvm: support broadcast TWT alone Tell the firmware about broadcast TWT support even if individual TWT is not supported. In that case the firmware will negotiate only a broadcast TWT session. Signed-off-by: Shaul Triebitz Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210826224715.556934ed023a.I843677252be64f4732e434ab9ef72f487625e49e@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index 1ebd4654d18e..fd352b2624a6 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -647,15 +647,14 @@ static int iwl_mvm_mac_ctxt_cmd_sta(struct iwl_mvm *mvm, if (vif->bss_conf.he_support && !iwlwifi_mod_params.disable_11ax) { cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_11AX); - if (vif->bss_conf.twt_requester && IWL_MVM_USE_TWT) { + if (vif->bss_conf.twt_requester && IWL_MVM_USE_TWT) ctxt_sta->data_policy |= cpu_to_le32(TWT_SUPPORTED); - if (vif->bss_conf.twt_protected) - ctxt_sta->data_policy |= - cpu_to_le32(PROTECTED_TWT_SUPPORTED); - if (vif->bss_conf.twt_broadcast) - ctxt_sta->data_policy |= - cpu_to_le32(BROADCAST_TWT_SUPPORTED); - } + if (vif->bss_conf.twt_protected) + ctxt_sta->data_policy |= + cpu_to_le32(PROTECTED_TWT_SUPPORTED); + if (vif->bss_conf.twt_broadcast) + ctxt_sta->data_policy |= + cpu_to_le32(BROADCAST_TWT_SUPPORTED); } From 090f1be3abf3069ef856b29761f181808bf55917 Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Thu, 26 Aug 2021 22:47:42 +0300 Subject: [PATCH 75/95] iwlwifi: mvm: Fix scan channel flags settings The iwl_mvm_scan_ch_n_aps_flag() is called with a variable before the value of the variable is set. Fix it. Signed-off-by: Ilan Peer Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210826224715.f6f188980a5e.Ie7331a8b94004d308f6cbde44e519155a5be91dd@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/scan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index e1b436e805b1..d78e436fa8b5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -1648,7 +1648,7 @@ iwl_mvm_umac_scan_cfg_channels_v6(struct iwl_mvm *mvm, struct iwl_scan_channel_cfg_umac *cfg = &cp->channel_config[i]; u32 n_aps_flag = iwl_mvm_scan_ch_n_aps_flag(vif_type, - cfg->v2.channel_num); + channels[i]->hw_value); cfg->flags = cpu_to_le32(flags | n_aps_flag); cfg->v2.channel_num = channels[i]->hw_value; From e257d969f36503b8eb1240f32653a1afb3109f86 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 26 Aug 2021 22:47:43 +0300 Subject: [PATCH 76/95] iwlwifi: mvm: don't use FW key ID in beacon protection To check beacon protection had a mismatch of the key ID we currently use the key ID from the firmware, but firmware side we want to clean up the API to stop reporting this. Instead, check the IWL_RX_MPDU_STATUS_KEY_VALID bit that indicates that the firmware used the correct key, and if that's set but we get invalid MIC/replay use the key ID from the frame to look up the key and notify mac80211 of MIC error or replay. Since both keys must have the same cipher and thus MIC length, we can use either of them to look up the MIC length. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210826224715.30e665d39b07.I78bf7d304ef5a80cecf5fa1c1fca0b51b956cceb@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 41 ++++++++++++------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 06cc03820dd5..c12f303cf652 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -279,7 +279,6 @@ static int iwl_mvm_rx_mgmt_prot(struct ieee80211_sta *sta, { struct iwl_mvm_sta *mvmsta; struct iwl_mvm_vif *mvmvif; - u8 fwkeyid = u32_get_bits(status, IWL_RX_MPDU_STATUS_KEY); u8 keyid; struct ieee80211_key_conf *key; u32 len = le16_to_cpu(desc->mpdu_len); @@ -299,6 +298,10 @@ static int iwl_mvm_rx_mgmt_prot(struct ieee80211_sta *sta, if (!ieee80211_is_beacon(hdr->frame_control)) return 0; + /* key mismatch - will also report !MIC_OK but we shouldn't count it */ + if (!(status & IWL_RX_MPDU_STATUS_KEY_VALID)) + return -1; + /* good cases */ if (likely(status & IWL_RX_MPDU_STATUS_MIC_OK && !(status & IWL_RX_MPDU_STATUS_REPLAY_ERROR))) @@ -309,26 +312,36 @@ static int iwl_mvm_rx_mgmt_prot(struct ieee80211_sta *sta, mvmsta = iwl_mvm_sta_from_mac80211(sta); - /* what? */ - if (fwkeyid != 6 && fwkeyid != 7) - return -1; - mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif); - key = rcu_dereference(mvmvif->bcn_prot.keys[fwkeyid - 6]); - if (!key) - return -1; + /* + * both keys will have the same cipher and MIC length, use + * whichever one is available + */ + key = rcu_dereference(mvmvif->bcn_prot.keys[0]); + if (!key) { + key = rcu_dereference(mvmvif->bcn_prot.keys[1]); + if (!key) + return -1; + } if (len < key->icv_len + IEEE80211_GMAC_PN_LEN + 2) return -1; - /* - * See if the key ID matches - if not this may be due to a - * switch and the firmware may erroneously report !MIC_OK. - */ + /* get the real key ID */ keyid = frame[len - key->icv_len - IEEE80211_GMAC_PN_LEN - 2]; - if (keyid != fwkeyid) - return -1; + /* and if that's the other key, look it up */ + if (keyid != key->keyidx) { + /* + * shouldn't happen since firmware checked, but be safe + * in case the MIC length is wrong too, for example + */ + if (keyid != 6 && keyid != 7) + return -1; + key = rcu_dereference(mvmvif->bcn_prot.keys[keyid - 6]); + if (!key) + return -1; + } /* Report status to mac80211 */ if (!(status & IWL_RX_MPDU_STATUS_MIC_OK)) From d195d7aac09bddabc2c8326fb02fcec2b0a2de02 Mon Sep 17 00:00:00 2001 From: Joseph Gates Date: Wed, 18 Aug 2021 13:31:43 +0200 Subject: [PATCH 77/95] wcn36xx: Ensure finish scan is not requested before start scan If the operating channel is the first in the scan list, it was seen that a finish scan request would be sent before a start scan request was sent, causing the firmware to fail all future scans. Track the current channel being scanned to avoid requesting the scan finish before it starts. Cc: Fixes: 5973a2947430 ("wcn36xx: Fix software-driven scan") Signed-off-by: Joseph Gates Signed-off-by: Loic Poulain Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1629286303-13179-1-git-send-email-loic.poulain@linaro.org --- drivers/net/wireless/ath/wcn36xx/main.c | 5 ++++- drivers/net/wireless/ath/wcn36xx/wcn36xx.h | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index d202f2128df2..67f4db662402 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c @@ -408,13 +408,14 @@ static int wcn36xx_config(struct ieee80211_hw *hw, u32 changed) wcn36xx_dbg(WCN36XX_DBG_MAC, "wcn36xx_config channel switch=%d\n", ch); - if (wcn->sw_scan_opchannel == ch) { + if (wcn->sw_scan_opchannel == ch && wcn->sw_scan_channel) { /* If channel is the initial operating channel, we may * want to receive/transmit regular data packets, then * simply stop the scan session and exit PS mode. */ wcn36xx_smd_finish_scan(wcn, HAL_SYS_MODE_SCAN, wcn->sw_scan_vif); + wcn->sw_scan_channel = 0; } else if (wcn->sw_scan) { /* A scan is ongoing, do not change the operating * channel, but start a scan session on the channel. @@ -422,6 +423,7 @@ static int wcn36xx_config(struct ieee80211_hw *hw, u32 changed) wcn36xx_smd_init_scan(wcn, HAL_SYS_MODE_SCAN, wcn->sw_scan_vif); wcn36xx_smd_start_scan(wcn, ch); + wcn->sw_scan_channel = ch; } else { wcn36xx_change_opchannel(wcn, ch); } @@ -702,6 +704,7 @@ static void wcn36xx_sw_scan_start(struct ieee80211_hw *hw, wcn->sw_scan = true; wcn->sw_scan_vif = vif; + wcn->sw_scan_channel = 0; if (vif_priv->sta_assoc) wcn->sw_scan_opchannel = WCN36XX_HW_CHANNEL(wcn); else diff --git a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h index 6121d8a5641a..0feb235b5a42 100644 --- a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h +++ b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h @@ -246,6 +246,7 @@ struct wcn36xx { struct cfg80211_scan_request *scan_req; bool sw_scan; u8 sw_scan_opchannel; + u8 sw_scan_channel; struct ieee80211_vif *sw_scan_vif; struct mutex scan_lock; bool scan_aborted; From b7f96d5c79cd9584bb1193a3c9008bd1e2683906 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Tue, 24 Aug 2021 10:12:25 -0700 Subject: [PATCH 78/95] wcn36xx: Allow firmware name to be overridden by DT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The WLAN NV firmware blob differs between platforms, and possibly devices, so add support in the wcn36xx driver for reading the path of this file from DT in order to allow these files to live in a generic file system (or linux-firmware). For some reason the parent (wcnss_ctrl) also needs to upload this blob, so rather than specifying the same information in both nodes wcn36xx reads the string from the parent's of_node. Signed-off-by: Bjorn Andersson Tested-by: Bryan O'Donoghue Tested-by: Aníbal Limón Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20210824171225.686683-1-bjorn.andersson@linaro.org --- drivers/net/wireless/ath/wcn36xx/main.c | 7 +++++++ drivers/net/wireless/ath/wcn36xx/smd.c | 4 ++-- drivers/net/wireless/ath/wcn36xx/wcn36xx.h | 1 + 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index 67f4db662402..ec913ec991f3 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c @@ -1503,6 +1503,13 @@ static int wcn36xx_probe(struct platform_device *pdev) goto out_wq; } + wcn->nv_file = WLAN_NV_FILE; + ret = of_property_read_string(wcn->dev->parent->of_node, "firmware-name", &wcn->nv_file); + if (ret < 0 && ret != -EINVAL) { + wcn36xx_err("failed to read \"firmware-name\" property: %d\n", ret); + goto out_wq; + } + wcn->smd_channel = qcom_wcnss_open_channel(wcnss, "WLAN_CTRL", wcn36xx_smd_rsp_process, hw); if (IS_ERR(wcn->smd_channel)) { wcn36xx_err("failed to open WLAN_CTRL channel\n"); diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c index 0e3be17d8cea..57fa857b290b 100644 --- a/drivers/net/wireless/ath/wcn36xx/smd.c +++ b/drivers/net/wireless/ath/wcn36xx/smd.c @@ -504,10 +504,10 @@ int wcn36xx_smd_load_nv(struct wcn36xx *wcn) u16 fm_offset = 0; if (!wcn->nv) { - ret = request_firmware(&wcn->nv, WLAN_NV_FILE, wcn->dev); + ret = request_firmware(&wcn->nv, wcn->nv_file, wcn->dev); if (ret) { wcn36xx_err("Failed to load nv file %s: %d\n", - WLAN_NV_FILE, ret); + wcn->nv_file, ret); goto out; } } diff --git a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h index 0feb235b5a42..add6e527e833 100644 --- a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h +++ b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h @@ -199,6 +199,7 @@ struct wcn36xx { struct device *dev; struct list_head vif_list; + const char *nv_file; const struct firmware *nv; u8 fw_revision; From 8678fd31f2d3eb14f2b8b39c9bc266f16fa24b22 Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Thu, 26 Aug 2021 17:46:08 +0200 Subject: [PATCH 79/95] wcn36xx: Fix missing frame timestamp for beacon/probe-resp When receiving a beacon or probe response, we should update the boottime_ns field which is the timestamp the frame was received at. (cf mac80211.h) This fixes a scanning issue with Android since it relies on this timestamp to determine when the AP has been seen for the last time (via the nl80211 BSS_LAST_SEEN_BOOTTIME parameter). Signed-off-by: Loic Poulain Reviewed-by: Bryan O'Donoghue Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1629992768-23785-1-git-send-email-loic.poulain@linaro.org --- drivers/net/wireless/ath/wcn36xx/txrx.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/ath/wcn36xx/txrx.c b/drivers/net/wireless/ath/wcn36xx/txrx.c index 1b831157ede1..cab196bb38cd 100644 --- a/drivers/net/wireless/ath/wcn36xx/txrx.c +++ b/drivers/net/wireless/ath/wcn36xx/txrx.c @@ -287,6 +287,10 @@ int wcn36xx_rx_skb(struct wcn36xx *wcn, struct sk_buff *skb) status.rate_idx = 0; } + if (ieee80211_is_beacon(hdr->frame_control) || + ieee80211_is_probe_resp(hdr->frame_control)) + status.boottime_ns = ktime_get_boottime_ns(); + memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); if (ieee80211_is_beacon(hdr->frame_control)) { From 23151b9ae79e3bc4f6a0c4cd3a7f355f68dad128 Mon Sep 17 00:00:00 2001 From: Zekun Shen Date: Sat, 19 Jun 2021 09:29:14 -0400 Subject: [PATCH 80/95] ath9k: fix OOB read ar9300_eeprom_restore_internal Bad header can have large length field which can cause OOB. cptr is the last bytes for read, and the eeprom is parsed from high to low address. The OOB, triggered by the condition length > cptr could cause memory error with a read on negative index. There are some sanity check around length, but it is not compared with cptr (the remaining bytes). Here, the corrupted/bad EEPROM can cause panic. I was able to reproduce the crash, but I cannot find the log and the reproducer now. After I applied the patch, the bug is no longer reproducible. Signed-off-by: Zekun Shen Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/YM3xKsQJ0Hw2hjrc@Zekuns-MBP-16.fios-router.home --- drivers/net/wireless/ath/ath9k/ar9003_eeprom.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index b4885a700296..b0a4ca3559fd 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -3351,7 +3351,8 @@ found: "Found block at %x: code=%d ref=%d length=%d major=%d minor=%d\n", cptr, code, reference, length, major, minor); if ((!AR_SREV_9485(ah) && length >= 1024) || - (AR_SREV_9485(ah) && length > EEPROM_DATA_LEN_9485)) { + (AR_SREV_9485(ah) && length > EEPROM_DATA_LEN_9485) || + (length > cptr)) { ath_dbg(common, EEPROM, "Skipping bad header\n"); cptr -= COMP_HDR_LEN; continue; From 7c48662b9d56666219f526a71ace8c15e6e12f1f Mon Sep 17 00:00:00 2001 From: Miaoqing Pan Date: Mon, 9 Aug 2021 12:05:16 +0800 Subject: [PATCH 81/95] ath9k: fix sleeping in atomic context The problem is that gpio_free() can sleep and the cfg_soc() can be called with spinlocks held. One problematic call tree is: --> ath_reset_internal() takes &sc->sc_pcu_lock spin lock --> ath9k_hw_reset() --> ath9k_hw_gpio_request_in() --> ath9k_hw_gpio_request() --> ath9k_hw_gpio_cfg_soc() Remove gpio_free(), use error message instead, so we should make sure there is no GPIO conflict. Also remove ath9k_hw_gpio_free() from ath9k_hw_apply_gpio_override(), as gpio_mask will never be set for SOC chips. Signed-off-by: Miaoqing Pan Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1628481916-15030-1-git-send-email-miaoqing@codeaurora.org --- drivers/net/wireless/ath/ath9k/hw.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 2ca3b86714a9..172081ffe477 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1621,7 +1621,6 @@ static void ath9k_hw_apply_gpio_override(struct ath_hw *ah) ath9k_hw_gpio_request_out(ah, i, NULL, AR_GPIO_OUTPUT_MUX_AS_OUTPUT); ath9k_hw_set_gpio(ah, i, !!(ah->gpio_val & BIT(i))); - ath9k_hw_gpio_free(ah, i); } } @@ -2728,14 +2727,17 @@ static void ath9k_hw_gpio_cfg_output_mux(struct ath_hw *ah, u32 gpio, u32 type) static void ath9k_hw_gpio_cfg_soc(struct ath_hw *ah, u32 gpio, bool out, const char *label) { + int err; + if (ah->caps.gpio_requested & BIT(gpio)) return; - /* may be requested by BSP, free anyway */ - gpio_free(gpio); - - if (gpio_request_one(gpio, out ? GPIOF_OUT_INIT_LOW : GPIOF_IN, label)) + err = gpio_request_one(gpio, out ? GPIOF_OUT_INIT_LOW : GPIOF_IN, label); + if (err) { + ath_err(ath9k_hw_common(ah), "request GPIO%d failed:%d\n", + gpio, err); return; + } ah->caps.gpio_requested |= BIT(gpio); } From fd6729ec534cffbbeb3917761e6d1fe6a412d3fe Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 13 Aug 2021 14:34:38 +0300 Subject: [PATCH 82/95] ath6kl: wmi: fix an error code in ath6kl_wmi_sync_point() This error path is unlikely because of it checked for NULL and returned -ENOMEM earlier in the function. But it should return an error code here as well if we ever do hit it because of a race condition or something. Fixes: bdcd81707973 ("Add ath6kl cleaned up driver") Signed-off-by: Dan Carpenter Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20210813113438.GB30697@kili --- drivers/net/wireless/ath/ath6kl/wmi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index b137e7f34397..bd1ef6334997 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -2504,8 +2504,10 @@ static int ath6kl_wmi_sync_point(struct wmi *wmi, u8 if_idx) goto free_data_skb; for (index = 0; index < num_pri_streams; index++) { - if (WARN_ON(!data_sync_bufs[index].skb)) + if (WARN_ON(!data_sync_bufs[index].skb)) { + ret = -ENOMEM; goto free_data_skb; + } ep_id = ath6kl_ac2_endpoint_id(wmi->parent_dev, data_sync_bufs[index]. From 1d4dcaf3db9bd073cebf709d081957068de88bdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ugo=20R=C3=A9mery?= Date: Sun, 22 Aug 2021 14:49:32 -0500 Subject: [PATCH 83/95] rtw88: add quirk to disable pci caps on HP Pavilion 14-ce0xxx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 8821CE causes random freezes on HP Pavilion 14-ce0019nf. Add a quirk to disable pci ASPM capability. Signed-off-by: Ugo Rémery Signed-off-by: Larry Finger Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20210822194932.29630-1-Larry.Finger@lwfinger.net --- drivers/net/wireless/realtek/rtw88/pci.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw88/pci.c b/drivers/net/wireless/realtek/rtw88/pci.c index cfb9f1ea30a0..a7a6ebfaa203 100644 --- a/drivers/net/wireless/realtek/rtw88/pci.c +++ b/drivers/net/wireless/realtek/rtw88/pci.c @@ -1729,6 +1729,15 @@ static const struct dmi_system_id rtw88_pci_quirks[] = { }, .driver_data = (void *)BIT(QUIRK_DIS_PCI_CAP_ASPM), }, + { + .callback = disable_pci_caps, + .ident = "HP HP Pavilion Laptop 14-ce0xxx", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HP"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion Laptop 14-ce0xxx"), + }, + .driver_data = (void *)BIT(QUIRK_DIS_PCI_CAP_ASPM), + }, {} }; From 533ccdae76faa6fd8e0857ec494b264a5d87a191 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Mon, 23 Aug 2021 15:20:14 -0700 Subject: [PATCH 84/95] rtlwifi: rtl8192de: Fix initialization of place in _rtl92c_phy_get_rightchnlplace() Clang warns: drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c:901:6: warning: variable 'place' is used uninitialized whenever 'if' condition is false [-Wsometimes-uninitialized] if (chnl > 14) { ^~~~~~~~~ drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c:909:9: note: uninitialized use occurs here return place; ^~~~~ drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c:901:2: note: remove the 'if' if its condition is always true if (chnl > 14) { ^~~~~~~~~~~~~~~ drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c:899:10: note: initialize the variable 'place' to silence this warning u8 place; ^ = '\0' 1 warning generated. Commit 369956ae5720 ("rtlwifi: rtl8192de: Remove redundant variable initializations") removed the initialization of place but it appears that this removal was in the wrong function. _rtl92c_phy_get_rightchnlplace() returns place's value at the end of the function so now if the if statement is false, place never gets initialized. Add that initialization back to address the warning. place's initialization is not necessary in rtl92d_get_rightchnlplace_for_iqk() as place is only used within the if statement so it can be removed, which is likely what was intended in the first place. Fixes: 369956ae5720 ("rtlwifi: rtl8192de: Remove redundant variable initializations") Signed-off-by: Nathan Chancellor Acked-by: Ping-Ke Shih Reviewed-by: Kees Cook Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20210823222014.764557-1-nathan@kernel.org --- drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c index 8ae69d914312..9b83c710c9b8 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c @@ -896,7 +896,7 @@ static void _rtl92d_ccxpower_index_check(struct ieee80211_hw *hw, static u8 _rtl92c_phy_get_rightchnlplace(u8 chnl) { - u8 place; + u8 place = chnl; if (chnl > 14) { for (place = 14; place < sizeof(channel5g); place++) { @@ -1363,7 +1363,7 @@ static void _rtl92d_phy_switch_rf_setting(struct ieee80211_hw *hw, u8 channel) u8 rtl92d_get_rightchnlplace_for_iqk(u8 chnl) { - u8 place = chnl; + u8 place; if (chnl > 14) { for (place = 14; place < sizeof(channel_all); place++) { From f4c813641897cfb43b3b99edd8c8851a1c98c70f Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 19 Aug 2021 13:50:18 +0100 Subject: [PATCH 85/95] rsi: make array fsm_state static const, makes object smaller Don't populate the array fsm_state on the stack but instead it static const. Makes the object code smaller by 154 bytes: Before: text data bss dec hex filename 9213 3904 0 13117 333d .../wireless/rsi/rsi_91x_debugfs.o After: text data bss dec hex filename 8995 3968 0 12963 32a3 .../wireless/rsi/rsi_91x_debugfs.o (gcc version 10.3.0) Signed-off-by: Colin Ian King Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20210819125018.8577-1-colin.king@canonical.com --- drivers/net/wireless/rsi/rsi_91x_debugfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/rsi/rsi_91x_debugfs.c b/drivers/net/wireless/rsi/rsi_91x_debugfs.c index 24a417ea2ae7..bf22fd948276 100644 --- a/drivers/net/wireless/rsi/rsi_91x_debugfs.c +++ b/drivers/net/wireless/rsi/rsi_91x_debugfs.c @@ -117,7 +117,7 @@ static int rsi_stats_read(struct seq_file *seq, void *data) { struct rsi_common *common = seq->private; - unsigned char fsm_state[][32] = { + static const unsigned char fsm_state[][32] = { "FSM_FW_NOT_LOADED", "FSM_CARD_NOT_READY", "FSM_COMMON_DEV_PARAMS_SENT", From 81f9ebd43659320a88cae8ed5124c50b4d47ab66 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sun, 22 Aug 2021 01:58:00 +0200 Subject: [PATCH 86/95] ssb: Drop legacy header include The SSB header only uses the legacy header to get struct gpio_chip so inluce which is the right include to deal with gpio_chip. Cc: Michael Buesch Cc: Kalle Valo Signed-off-by: Linus Walleij Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20210821235800.138817-1-linus.walleij@linaro.org --- include/linux/ssb/ssb.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h index 0d5a2691e7e9..f9b53acb4e02 100644 --- a/include/linux/ssb/ssb.h +++ b/include/linux/ssb/ssb.h @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include #include From 4b51de063d5310f1fb297388b7955926e63e45c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Drewniak?= Date: Tue, 24 Aug 2021 23:13:30 +0100 Subject: [PATCH 87/95] brcmfmac: Add WPA3 Personal with FT to supported cipher suites MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows the driver to connect to BSSIDs supporting SAE with 802.11r. Tested on Raspberry Pi 4 Model B (STA) and UniFi 6LR/OpenWRT 21.02.0-rc2. AP was set to 'sae-mixed' (WPA2/3 Personal). Signed-off-by: Paweł Drewniak Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20210824221330.3847139-1-czajernia@gmail.com --- .../net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index cedba56fc448..f7b96cd69242 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -1829,6 +1829,14 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme) profile->use_fwsup = BRCMF_PROFILE_FWSUP_SAE; } break; + case WLAN_AKM_SUITE_FT_OVER_SAE: + val = WPA3_AUTH_SAE_PSK | WPA2_AUTH_FT; + profile->is_ft = true; + if (sme->crypto.sae_pwd) { + brcmf_dbg(INFO, "using SAE offload\n"); + profile->use_fwsup = BRCMF_PROFILE_FWSUP_SAE; + } + break; default: bphy_err(drvr, "invalid cipher group (%d)\n", sme->crypto.cipher_group); From 50cbbfd41e9f7716baa976ae2d60309a088a246e Mon Sep 17 00:00:00 2001 From: David Mosberger-Tang Date: Sat, 28 Aug 2021 15:19:11 +0000 Subject: [PATCH 88/95] wilc1000: Convert module-global "isinit" to device-specific variable Move static "isinit" variable to wilc_spi structure to allow multiple WILC1000 devices per machine. Signed-off-by: David Mosberger-Tang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20210828151346.3012697-1-davidm@egauge.net --- drivers/net/wireless/microchip/wilc1000/spi.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/microchip/wilc1000/spi.c b/drivers/net/wireless/microchip/wilc1000/spi.c index 8b180c29d682..dd481dc0b5ce 100644 --- a/drivers/net/wireless/microchip/wilc1000/spi.c +++ b/drivers/net/wireless/microchip/wilc1000/spi.c @@ -39,6 +39,7 @@ MODULE_PARM_DESC(enable_crc16, #define WILC_SPI_RSP_HDR_EXTRA_DATA 8 struct wilc_spi { + bool isinit; /* true if SPI protocol has been configured */ bool probing_crc; /* true if we're probing chip's CRC config */ bool crc7_enabled; /* true if crc7 is currently enabled */ bool crc16_enabled; /* true if crc16 is currently enabled */ @@ -908,15 +909,15 @@ static int wilc_spi_init(struct wilc *wilc, bool resume) struct wilc_spi *spi_priv = wilc->bus_data; u32 reg; u32 chipid; - static int isinit; int ret, i; - if (isinit) { + if (spi_priv->isinit) { + /* Confirm we can read chipid register without error: */ ret = wilc_spi_read_reg(wilc, WILC_CHIPID, &chipid); - if (ret) - dev_err(&spi->dev, "Fail cmd read chip id...\n"); + if (ret == 0) + return 0; - return ret; + dev_err(&spi->dev, "Fail cmd read chip id...\n"); } /* @@ -974,7 +975,7 @@ static int wilc_spi_init(struct wilc *wilc, bool resume) spi_priv->probing_crc = false; /* - * make sure can read back chip id correctly + * make sure can read chip id without protocol error */ ret = wilc_spi_read_reg(wilc, WILC_CHIPID, &chipid); if (ret) { @@ -982,7 +983,7 @@ static int wilc_spi_init(struct wilc *wilc, bool resume) return ret; } - isinit = 1; + spi_priv->isinit = true; return 0; } From b63aed3ff195130fef12e0af590f4838cf0201d8 Mon Sep 17 00:00:00 2001 From: Zenghui Yu Date: Tue, 27 Jul 2021 10:52:31 +0800 Subject: [PATCH 89/95] bcma: Fix memory leak for internally-handled cores kmemleak reported that dev_name() of internally-handled cores were leaked on driver unbinding. Let's use device_initialize() to take refcounts for them and put_device() to properly free the related stuff. While looking at it, there's another potential issue for those which should be *registered* into driver core. If device_register() failed, we put device once and freed bcma_device structures. In bcma_unregister_cores(), they're treated as unregistered and we hit both UAF and double-free. That smells not good and has also been fixed now. Fixes: ab54bc8460b5 ("bcma: fill core details for every device") Signed-off-by: Zenghui Yu Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20210727025232.663-2-yuzenghui@huawei.com --- drivers/bcma/main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c index 6535614a7dc1..1df2b5801c3b 100644 --- a/drivers/bcma/main.c +++ b/drivers/bcma/main.c @@ -236,6 +236,7 @@ EXPORT_SYMBOL(bcma_core_irq); void bcma_prepare_core(struct bcma_bus *bus, struct bcma_device *core) { + device_initialize(&core->dev); core->dev.release = bcma_release_core_dev; core->dev.bus = &bcma_bus_type; dev_set_name(&core->dev, "bcma%d:%d", bus->num, core->core_index); @@ -277,11 +278,10 @@ static void bcma_register_core(struct bcma_bus *bus, struct bcma_device *core) { int err; - err = device_register(&core->dev); + err = device_add(&core->dev); if (err) { bcma_err(bus, "Could not register dev for core 0x%03X\n", core->id.id); - put_device(&core->dev); return; } core->dev_registered = true; @@ -372,7 +372,7 @@ void bcma_unregister_cores(struct bcma_bus *bus) /* Now noone uses internally-handled cores, we can free them */ list_for_each_entry_safe(core, tmp, &bus->cores, list) { list_del(&core->list); - kfree(core); + put_device(&core->dev); } } From 9fc8048c56f33e0e969844a2f1b1e89cf30ee5ba Mon Sep 17 00:00:00 2001 From: Zenghui Yu Date: Tue, 27 Jul 2021 10:52:32 +0800 Subject: [PATCH 90/95] bcma: Drop the unused parameter of bcma_scan_read32() As it had never been used since the initial commit 8369ae33b705 ("bcma: add Broadcom specific AMBA bus driver"). Signed-off-by: Zenghui Yu Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20210727025232.663-3-yuzenghui@huawei.com --- drivers/bcma/scan.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/bcma/scan.c b/drivers/bcma/scan.c index d49e7c0de2b6..26d12a7e6ca0 100644 --- a/drivers/bcma/scan.c +++ b/drivers/bcma/scan.c @@ -141,8 +141,7 @@ static const char *bcma_device_name(const struct bcma_device_id *id) return "UNKNOWN"; } -static u32 bcma_scan_read32(struct bcma_bus *bus, u8 current_coreidx, - u16 offset) +static u32 bcma_scan_read32(struct bcma_bus *bus, u16 offset) { return readl(bus->mmio + offset); } @@ -443,7 +442,7 @@ void bcma_detect_chip(struct bcma_bus *bus) bcma_scan_switch_core(bus, BCMA_ADDR_BASE); - tmp = bcma_scan_read32(bus, 0, BCMA_CC_ID); + tmp = bcma_scan_read32(bus, BCMA_CC_ID); chipinfo->id = (tmp & BCMA_CC_ID_ID) >> BCMA_CC_ID_ID_SHIFT; chipinfo->rev = (tmp & BCMA_CC_ID_REV) >> BCMA_CC_ID_REV_SHIFT; chipinfo->pkg = (tmp & BCMA_CC_ID_PKG) >> BCMA_CC_ID_PKG_SHIFT; @@ -465,7 +464,7 @@ int bcma_bus_scan(struct bcma_bus *bus) if (bus->nr_cores) return 0; - erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM); + erombase = bcma_scan_read32(bus, BCMA_CC_EROM); if (bus->hosttype == BCMA_HOSTTYPE_SOC) { eromptr = ioremap(erombase, BCMA_CORE_SIZE); if (!eromptr) From d745ca4f2c4ae9f1bd8cf7d8ac6e22d739bffd19 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Tue, 17 Aug 2021 08:35:22 +0200 Subject: [PATCH 91/95] brcmfmac: pcie: fix oops on failure to resume and reprobe When resuming from suspend, brcmf_pcie_pm_leave_D3 will first attempt a hot resume and then fall back to removing the PCI device and then reprobing. If this probe fails, the kernel will oops, because brcmf_err, which is called to report the failure will dereference the stale bus pointer. Open code and use the default bus-less brcmf_err to avoid this. Fixes: 8602e62441ab ("brcmfmac: pass bus to the __brcmf_err() in pcie.c") Signed-off-by: Ahmad Fatoum Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20210817063521.22450-1-a.fatoum@pengutronix.de --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c index 5f6a418fbbb1..8b149996fc00 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c @@ -2076,7 +2076,7 @@ cleanup: err = brcmf_pcie_probe(pdev, NULL); if (err) - brcmf_err(bus, "probe after resume failed, err=%d\n", err); + __brcmf_err(NULL, __func__, "probe after resume failed, err=%d\n", err); return err; } From 5448bc2a426c2199db9b8bd87ae2b5c06b77ef92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Fri, 20 Aug 2021 16:20:49 +0200 Subject: [PATCH 92/95] mwifiex: pcie: add DMI-based quirk implementation for Surface devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds the ability to apply device-specific quirks to the mwifiex driver. It uses DMI matching similar to the quirks brcmfmac uses with dmi.c. We'll add identifiers to match various MS Surface devices, which this is primarily meant for, later. This commit is a slightly modified version of a previous patch sent in by Tsuchiya Yuto. Co-developed-by: Tsuchiya Yuto Signed-off-by: Tsuchiya Yuto Signed-off-by: Jonas Dreßler Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20210820142050.35741-2-verdre@v0yd.nl --- drivers/net/wireless/marvell/mwifiex/Makefile | 1 + drivers/net/wireless/marvell/mwifiex/pcie.c | 4 ++ drivers/net/wireless/marvell/mwifiex/pcie.h | 1 + .../wireless/marvell/mwifiex/pcie_quirks.c | 38 +++++++++++++++++++ .../wireless/marvell/mwifiex/pcie_quirks.h | 20 ++++++++++ 5 files changed, 64 insertions(+) create mode 100644 drivers/net/wireless/marvell/mwifiex/pcie_quirks.c create mode 100644 drivers/net/wireless/marvell/mwifiex/pcie_quirks.h diff --git a/drivers/net/wireless/marvell/mwifiex/Makefile b/drivers/net/wireless/marvell/mwifiex/Makefile index 162d557b78af..2bd00f40958e 100644 --- a/drivers/net/wireless/marvell/mwifiex/Makefile +++ b/drivers/net/wireless/marvell/mwifiex/Makefile @@ -49,6 +49,7 @@ mwifiex_sdio-y += sdio.o obj-$(CONFIG_MWIFIEX_SDIO) += mwifiex_sdio.o mwifiex_pcie-y += pcie.o +mwifiex_pcie-y += pcie_quirks.o obj-$(CONFIG_MWIFIEX_PCIE) += mwifiex_pcie.o mwifiex_usb-y += usb.o diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c index 46517515ba72..a530832c9421 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -27,6 +27,7 @@ #include "wmm.h" #include "11n.h" #include "pcie.h" +#include "pcie_quirks.h" #define PCIE_VERSION "1.0" #define DRV_NAME "Marvell mwifiex PCIe" @@ -410,6 +411,9 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, return ret; } + /* check quirks */ + mwifiex_initialize_quirks(card); + if (mwifiex_add_card(card, &card->fw_done, &pcie_ops, MWIFIEX_PCIE, &pdev->dev)) { pr_err("%s failed\n", __func__); diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.h b/drivers/net/wireless/marvell/mwifiex/pcie.h index 5ed613d65709..981e330c77d7 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.h +++ b/drivers/net/wireless/marvell/mwifiex/pcie.h @@ -244,6 +244,7 @@ struct pcie_service_card { unsigned long work_flags; bool pci_reset_ongoing; + unsigned long quirks; }; static inline int diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c new file mode 100644 index 000000000000..c1665ac5c5d9 --- /dev/null +++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c @@ -0,0 +1,38 @@ +/* + * NXP Wireless LAN device driver: PCIE and platform specific quirks + * + * This software file (the "File") is distributed by NXP + * under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#include + +#include "pcie_quirks.h" + +/* quirk table based on DMI matching */ +static const struct dmi_system_id mwifiex_quirk_table[] = { + {} +}; + +void mwifiex_initialize_quirks(struct pcie_service_card *card) +{ + struct pci_dev *pdev = card->dev; + const struct dmi_system_id *dmi_id; + + dmi_id = dmi_first_match(mwifiex_quirk_table); + if (dmi_id) + card->quirks = (uintptr_t)dmi_id->driver_data; + + if (!card->quirks) + dev_info(&pdev->dev, "no quirks enabled\n"); +} diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h new file mode 100644 index 000000000000..18eacc8c2d3a --- /dev/null +++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h @@ -0,0 +1,20 @@ +/* + * NXP Wireless LAN device driver: PCIE and platform specific quirks + * + * This software file (the "File") is distributed by NXP + * under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#include "pcie.h" + +void mwifiex_initialize_quirks(struct pcie_service_card *card); From a847666accf2c1d4f4ed6c50be43dbc30ebc3a11 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Fri, 20 Aug 2021 16:20:50 +0200 Subject: [PATCH 93/95] mwifiex: pcie: add reset_d3cold quirk for Surface gen4+ devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To reset mwifiex on Surface gen4+ (Pro 4 or later gen) devices, it seems that putting the wifi device into D3cold is required according to errata.inf file on Windows installation (Windows/INF/errata.inf). This patch adds a function that performs power-cycle (put into D3cold then D0) and call the function at the end of reset_prepare(). Note: Need to also reset the parent device (bridge) of wifi on SB1; it might be because the bridge of wifi always reports it's in D3hot. When I tried to reset only the wifi device (not touching parent), it gave the following error and the reset failed: acpi device:4b: Cannot transition to power state D0 for parent in D3hot mwifiex_pcie 0000:03:00.0: can't change power state from D3cold to D0 (config space inaccessible) Signed-off-by: Tsuchiya Yuto Signed-off-by: Jonas Dreßler Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20210820142050.35741-3-verdre@v0yd.nl --- drivers/net/wireless/marvell/mwifiex/pcie.c | 7 + .../wireless/marvell/mwifiex/pcie_quirks.c | 123 ++++++++++++++++++ .../wireless/marvell/mwifiex/pcie_quirks.h | 3 + 3 files changed, 133 insertions(+) diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c index a530832c9421..c6ccce426b49 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -528,6 +528,13 @@ static void mwifiex_pcie_reset_prepare(struct pci_dev *pdev) mwifiex_shutdown_sw(adapter); clear_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, &card->work_flags); clear_bit(MWIFIEX_IFACE_WORK_CARD_RESET, &card->work_flags); + + /* On MS Surface gen4+ devices FLR isn't effective to recover from + * hangups, so we power-cycle the card instead. + */ + if (card->quirks & QUIRK_FW_RST_D3COLD) + mwifiex_pcie_reset_d3cold_quirk(pdev); + mwifiex_dbg(adapter, INFO, "%s, successful\n", __func__); card->pci_reset_ongoing = true; diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c index c1665ac5c5d9..0234cf3c2974 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c @@ -21,6 +21,72 @@ /* quirk table based on DMI matching */ static const struct dmi_system_id mwifiex_quirk_table[] = { + { + .ident = "Surface Pro 4", + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 4"), + }, + .driver_data = (void *)QUIRK_FW_RST_D3COLD, + }, + { + .ident = "Surface Pro 5", + .matches = { + /* match for SKU here due to generic product name "Surface Pro" */ + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1796"), + }, + .driver_data = (void *)QUIRK_FW_RST_D3COLD, + }, + { + .ident = "Surface Pro 5 (LTE)", + .matches = { + /* match for SKU here due to generic product name "Surface Pro" */ + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1807"), + }, + .driver_data = (void *)QUIRK_FW_RST_D3COLD, + }, + { + .ident = "Surface Pro 6", + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 6"), + }, + .driver_data = (void *)QUIRK_FW_RST_D3COLD, + }, + { + .ident = "Surface Book 1", + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book"), + }, + .driver_data = (void *)QUIRK_FW_RST_D3COLD, + }, + { + .ident = "Surface Book 2", + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book 2"), + }, + .driver_data = (void *)QUIRK_FW_RST_D3COLD, + }, + { + .ident = "Surface Laptop 1", + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop"), + }, + .driver_data = (void *)QUIRK_FW_RST_D3COLD, + }, + { + .ident = "Surface Laptop 2", + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 2"), + }, + .driver_data = (void *)QUIRK_FW_RST_D3COLD, + }, {} }; @@ -35,4 +101,61 @@ void mwifiex_initialize_quirks(struct pcie_service_card *card) if (!card->quirks) dev_info(&pdev->dev, "no quirks enabled\n"); + if (card->quirks & QUIRK_FW_RST_D3COLD) + dev_info(&pdev->dev, "quirk reset_d3cold enabled\n"); +} + +static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev) +{ + dev_info(&pdev->dev, "putting into D3cold...\n"); + + pci_save_state(pdev); + if (pci_is_enabled(pdev)) + pci_disable_device(pdev); + pci_set_power_state(pdev, PCI_D3cold); +} + +static int mwifiex_pcie_set_power_d0(struct pci_dev *pdev) +{ + int ret; + + dev_info(&pdev->dev, "putting into D0...\n"); + + pci_set_power_state(pdev, PCI_D0); + ret = pci_enable_device(pdev); + if (ret) { + dev_err(&pdev->dev, "pci_enable_device failed\n"); + return ret; + } + pci_restore_state(pdev); + + return 0; +} + +int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev) +{ + struct pci_dev *parent_pdev = pci_upstream_bridge(pdev); + int ret; + + /* Power-cycle (put into D3cold then D0) */ + dev_info(&pdev->dev, "Using reset_d3cold quirk to perform FW reset\n"); + + /* We need to perform power-cycle also for bridge of wifi because + * on some devices (e.g. Surface Book 1), the OS for some reasons + * can't know the real power state of the bridge. + * When tried to power-cycle only wifi, the reset failed with the + * following dmesg log: + * "Cannot transition to power state D0 for parent in D3hot". + */ + mwifiex_pcie_set_power_d3cold(pdev); + mwifiex_pcie_set_power_d3cold(parent_pdev); + + ret = mwifiex_pcie_set_power_d0(parent_pdev); + if (ret) + return ret; + ret = mwifiex_pcie_set_power_d0(pdev); + if (ret) + return ret; + + return 0; } diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h index 18eacc8c2d3a..8ec4176d698f 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h @@ -17,4 +17,7 @@ #include "pcie.h" +#define QUIRK_FW_RST_D3COLD BIT(0) + void mwifiex_initialize_quirks(struct pcie_service_card *card); +int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); From ebe9e6514b40f8aac7387466b898541b84c4ef1f Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sun, 22 Aug 2021 10:03:50 +0200 Subject: [PATCH 94/95] intel: switch from 'pci_' to 'dma_' API The wrappers in include/linux/pci-dma-compat.h should go away. The patch has been generated with the coccinelle script below. It has been hand modified to use 'dma_set_mask_and_coherent()' instead of 'pci_set_dma_mask()/pci_set_consistent_dma_mask()' when applicable. This is less verbose. It has been compile tested. @@ @@ - PCI_DMA_BIDIRECTIONAL + DMA_BIDIRECTIONAL @@ @@ - PCI_DMA_TODEVICE + DMA_TO_DEVICE @@ @@ - PCI_DMA_FROMDEVICE + DMA_FROM_DEVICE @@ @@ - PCI_DMA_NONE + DMA_NONE @@ expression e1, e2, e3; @@ - pci_alloc_consistent(e1, e2, e3) + dma_alloc_coherent(&e1->dev, e2, e3, GFP_) @@ expression e1, e2, e3; @@ - pci_zalloc_consistent(e1, e2, e3) + dma_alloc_coherent(&e1->dev, e2, e3, GFP_) @@ expression e1, e2, e3, e4; @@ - pci_free_consistent(e1, e2, e3, e4) + dma_free_coherent(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_map_single(e1, e2, e3, e4) + dma_map_single(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_unmap_single(e1, e2, e3, e4) + dma_unmap_single(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4, e5; @@ - pci_map_page(e1, e2, e3, e4, e5) + dma_map_page(&e1->dev, e2, e3, e4, e5) @@ expression e1, e2, e3, e4; @@ - pci_unmap_page(e1, e2, e3, e4) + dma_unmap_page(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_map_sg(e1, e2, e3, e4) + dma_map_sg(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_unmap_sg(e1, e2, e3, e4) + dma_unmap_sg(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_single_for_cpu(e1, e2, e3, e4) + dma_sync_single_for_cpu(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_single_for_device(e1, e2, e3, e4) + dma_sync_single_for_device(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_sg_for_cpu(e1, e2, e3, e4) + dma_sync_sg_for_cpu(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_sg_for_device(e1, e2, e3, e4) + dma_sync_sg_for_device(&e1->dev, e2, e3, e4) @@ expression e1, e2; @@ - pci_dma_mapping_error(e1, e2) + dma_mapping_error(&e1->dev, e2) @@ expression e1, e2; @@ - pci_set_dma_mask(e1, e2) + dma_set_mask(&e1->dev, e2) @@ expression e1, e2; @@ - pci_set_consistent_dma_mask(e1, e2) + dma_set_coherent_mask(&e1->dev, e2) Signed-off-by: Christophe JAILLET Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/f55043d0c847bfae60087707778563cf732a7bf9.1629619229.git.christophe.jaillet@wanadoo.fr --- .../net/wireless/intel/iwlegacy/3945-mac.c | 52 ++++++------- drivers/net/wireless/intel/iwlegacy/3945.c | 10 +-- .../net/wireless/intel/iwlegacy/4965-mac.c | 78 +++++++++---------- drivers/net/wireless/intel/iwlegacy/common.c | 19 +++-- .../net/wireless/intel/iwlwifi/pcie/trans.c | 10 +-- 5 files changed, 77 insertions(+), 92 deletions(-) diff --git a/drivers/net/wireless/intel/iwlegacy/3945-mac.c b/drivers/net/wireless/intel/iwlegacy/3945-mac.c index 6ff2674f8466..45abb25b65a9 100644 --- a/drivers/net/wireless/intel/iwlegacy/3945-mac.c +++ b/drivers/net/wireless/intel/iwlegacy/3945-mac.c @@ -571,20 +571,18 @@ il3945_tx_skb(struct il_priv *il, /* Physical address of this Tx command's header (not MAC header!), * within command buffer array. */ - txcmd_phys = - pci_map_single(il->pci_dev, &out_cmd->hdr, firstlen, - PCI_DMA_TODEVICE); - if (unlikely(pci_dma_mapping_error(il->pci_dev, txcmd_phys))) + txcmd_phys = dma_map_single(&il->pci_dev->dev, &out_cmd->hdr, firstlen, + DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(&il->pci_dev->dev, txcmd_phys))) goto drop_unlock; /* Set up TFD's 2nd entry to point directly to remainder of skb, * if any (802.11 null frames have no payload). */ secondlen = skb->len - hdr_len; if (secondlen > 0) { - phys_addr = - pci_map_single(il->pci_dev, skb->data + hdr_len, secondlen, - PCI_DMA_TODEVICE); - if (unlikely(pci_dma_mapping_error(il->pci_dev, phys_addr))) + phys_addr = dma_map_single(&il->pci_dev->dev, skb->data + hdr_len, + secondlen, DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(&il->pci_dev->dev, phys_addr))) goto drop_unlock; } @@ -1015,11 +1013,11 @@ il3945_rx_allocate(struct il_priv *il, gfp_t priority) /* Get physical address of RB/SKB */ page_dma = - pci_map_page(il->pci_dev, page, 0, + dma_map_page(&il->pci_dev->dev, page, 0, PAGE_SIZE << il->hw_params.rx_page_order, - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); - if (unlikely(pci_dma_mapping_error(il->pci_dev, page_dma))) { + if (unlikely(dma_mapping_error(&il->pci_dev->dev, page_dma))) { __free_pages(page, il->hw_params.rx_page_order); break; } @@ -1028,9 +1026,9 @@ il3945_rx_allocate(struct il_priv *il, gfp_t priority) if (list_empty(&rxq->rx_used)) { spin_unlock_irqrestore(&rxq->lock, flags); - pci_unmap_page(il->pci_dev, page_dma, + dma_unmap_page(&il->pci_dev->dev, page_dma, PAGE_SIZE << il->hw_params.rx_page_order, - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); __free_pages(page, il->hw_params.rx_page_order); return; } @@ -1062,9 +1060,10 @@ il3945_rx_queue_reset(struct il_priv *il, struct il_rx_queue *rxq) /* In the reset function, these buffers may have been allocated * to an SKB, so we need to unmap and free potential storage */ if (rxq->pool[i].page != NULL) { - pci_unmap_page(il->pci_dev, rxq->pool[i].page_dma, + dma_unmap_page(&il->pci_dev->dev, + rxq->pool[i].page_dma, PAGE_SIZE << il->hw_params.rx_page_order, - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); __il_free_pages(il, rxq->pool[i].page); rxq->pool[i].page = NULL; } @@ -1111,9 +1110,10 @@ il3945_rx_queue_free(struct il_priv *il, struct il_rx_queue *rxq) int i; for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) { if (rxq->pool[i].page != NULL) { - pci_unmap_page(il->pci_dev, rxq->pool[i].page_dma, + dma_unmap_page(&il->pci_dev->dev, + rxq->pool[i].page_dma, PAGE_SIZE << il->hw_params.rx_page_order, - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); __il_free_pages(il, rxq->pool[i].page); rxq->pool[i].page = NULL; } @@ -1213,9 +1213,9 @@ il3945_rx_handle(struct il_priv *il) rxq->queue[i] = NULL; - pci_unmap_page(il->pci_dev, rxb->page_dma, + dma_unmap_page(&il->pci_dev->dev, rxb->page_dma, PAGE_SIZE << il->hw_params.rx_page_order, - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); pkt = rxb_addr(rxb); len = le32_to_cpu(pkt->len_n_flags) & IL_RX_FRAME_SIZE_MSK; @@ -1260,11 +1260,11 @@ il3945_rx_handle(struct il_priv *il) spin_lock_irqsave(&rxq->lock, flags); if (rxb->page != NULL) { rxb->page_dma = - pci_map_page(il->pci_dev, rxb->page, 0, - PAGE_SIZE << il->hw_params. - rx_page_order, PCI_DMA_FROMDEVICE); - if (unlikely(pci_dma_mapping_error(il->pci_dev, - rxb->page_dma))) { + dma_map_page(&il->pci_dev->dev, rxb->page, 0, + PAGE_SIZE << il->hw_params.rx_page_order, + DMA_FROM_DEVICE); + if (unlikely(dma_mapping_error(&il->pci_dev->dev, + rxb->page_dma))) { __il_free_pages(il, rxb->page); rxb->page = NULL; list_add_tail(&rxb->list, &rxq->rx_used); @@ -3616,9 +3616,7 @@ il3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_master(pdev); - err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - if (!err) - err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); + err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); if (err) { IL_WARN("No suitable DMA available.\n"); goto out_pci_disable_device; diff --git a/drivers/net/wireless/intel/iwlegacy/3945.c b/drivers/net/wireless/intel/iwlegacy/3945.c index 0597d828bee1..a773939b8c2a 100644 --- a/drivers/net/wireless/intel/iwlegacy/3945.c +++ b/drivers/net/wireless/intel/iwlegacy/3945.c @@ -652,16 +652,16 @@ il3945_hw_txq_free_tfd(struct il_priv *il, struct il_tx_queue *txq) /* Unmap tx_cmd */ if (counter) - pci_unmap_single(dev, dma_unmap_addr(&txq->meta[idx], mapping), + dma_unmap_single(&dev->dev, + dma_unmap_addr(&txq->meta[idx], mapping), dma_unmap_len(&txq->meta[idx], len), - PCI_DMA_TODEVICE); + DMA_TO_DEVICE); /* unmap chunks if any */ for (i = 1; i < counter; i++) - pci_unmap_single(dev, le32_to_cpu(tfd->tbs[i].addr), - le32_to_cpu(tfd->tbs[i].len), - PCI_DMA_TODEVICE); + dma_unmap_single(&dev->dev, le32_to_cpu(tfd->tbs[i].addr), + le32_to_cpu(tfd->tbs[i].len), DMA_TO_DEVICE); /* free SKB */ if (txq->skbs) { diff --git a/drivers/net/wireless/intel/iwlegacy/4965-mac.c b/drivers/net/wireless/intel/iwlegacy/4965-mac.c index 341d6a2bc690..0223532fd56a 100644 --- a/drivers/net/wireless/intel/iwlegacy/4965-mac.c +++ b/drivers/net/wireless/intel/iwlegacy/4965-mac.c @@ -94,9 +94,10 @@ il4965_rx_queue_reset(struct il_priv *il, struct il_rx_queue *rxq) /* In the reset function, these buffers may have been allocated * to an SKB, so we need to unmap and free potential storage */ if (rxq->pool[i].page != NULL) { - pci_unmap_page(il->pci_dev, rxq->pool[i].page_dma, + dma_unmap_page(&il->pci_dev->dev, + rxq->pool[i].page_dma, PAGE_SIZE << il->hw_params.rx_page_order, - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); __il_free_pages(il, rxq->pool[i].page); rxq->pool[i].page = NULL; } @@ -342,11 +343,10 @@ il4965_rx_allocate(struct il_priv *il, gfp_t priority) } /* Get physical address of the RB */ - page_dma = - pci_map_page(il->pci_dev, page, 0, - PAGE_SIZE << il->hw_params.rx_page_order, - PCI_DMA_FROMDEVICE); - if (unlikely(pci_dma_mapping_error(il->pci_dev, page_dma))) { + page_dma = dma_map_page(&il->pci_dev->dev, page, 0, + PAGE_SIZE << il->hw_params.rx_page_order, + DMA_FROM_DEVICE); + if (unlikely(dma_mapping_error(&il->pci_dev->dev, page_dma))) { __free_pages(page, il->hw_params.rx_page_order); break; } @@ -355,9 +355,9 @@ il4965_rx_allocate(struct il_priv *il, gfp_t priority) if (list_empty(&rxq->rx_used)) { spin_unlock_irqrestore(&rxq->lock, flags); - pci_unmap_page(il->pci_dev, page_dma, + dma_unmap_page(&il->pci_dev->dev, page_dma, PAGE_SIZE << il->hw_params.rx_page_order, - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); __free_pages(page, il->hw_params.rx_page_order); return; } @@ -409,9 +409,10 @@ il4965_rx_queue_free(struct il_priv *il, struct il_rx_queue *rxq) int i; for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) { if (rxq->pool[i].page != NULL) { - pci_unmap_page(il->pci_dev, rxq->pool[i].page_dma, + dma_unmap_page(&il->pci_dev->dev, + rxq->pool[i].page_dma, PAGE_SIZE << il->hw_params.rx_page_order, - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); __il_free_pages(il, rxq->pool[i].page); rxq->pool[i].page = NULL; } @@ -1815,20 +1816,18 @@ il4965_tx_skb(struct il_priv *il, /* Physical address of this Tx command's header (not MAC header!), * within command buffer array. */ - txcmd_phys = - pci_map_single(il->pci_dev, &out_cmd->hdr, firstlen, - PCI_DMA_BIDIRECTIONAL); - if (unlikely(pci_dma_mapping_error(il->pci_dev, txcmd_phys))) + txcmd_phys = dma_map_single(&il->pci_dev->dev, &out_cmd->hdr, firstlen, + DMA_BIDIRECTIONAL); + if (unlikely(dma_mapping_error(&il->pci_dev->dev, txcmd_phys))) goto drop_unlock; /* Set up TFD's 2nd entry to point directly to remainder of skb, * if any (802.11 null frames have no payload). */ secondlen = skb->len - hdr_len; if (secondlen > 0) { - phys_addr = - pci_map_single(il->pci_dev, skb->data + hdr_len, secondlen, - PCI_DMA_TODEVICE); - if (unlikely(pci_dma_mapping_error(il->pci_dev, phys_addr))) + phys_addr = dma_map_single(&il->pci_dev->dev, skb->data + hdr_len, + secondlen, DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(&il->pci_dev->dev, phys_addr))) goto drop_unlock; } @@ -1853,8 +1852,8 @@ il4965_tx_skb(struct il_priv *il, offsetof(struct il_tx_cmd, scratch); /* take back ownership of DMA buffer to enable update */ - pci_dma_sync_single_for_cpu(il->pci_dev, txcmd_phys, firstlen, - PCI_DMA_BIDIRECTIONAL); + dma_sync_single_for_cpu(&il->pci_dev->dev, txcmd_phys, firstlen, + DMA_BIDIRECTIONAL); tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys); tx_cmd->dram_msb_ptr = il_get_dma_hi_addr(scratch_phys); @@ -1869,8 +1868,8 @@ il4965_tx_skb(struct il_priv *il, if (info->flags & IEEE80211_TX_CTL_AMPDU) il->ops->txq_update_byte_cnt_tbl(il, txq, le16_to_cpu(tx_cmd->len)); - pci_dma_sync_single_for_device(il->pci_dev, txcmd_phys, firstlen, - PCI_DMA_BIDIRECTIONAL); + dma_sync_single_for_device(&il->pci_dev->dev, txcmd_phys, firstlen, + DMA_BIDIRECTIONAL); /* Tell device the write idx *just past* this latest filled TFD */ q->write_ptr = il_queue_inc_wrap(q->write_ptr, q->n_bd); @@ -3929,15 +3928,15 @@ il4965_hw_txq_free_tfd(struct il_priv *il, struct il_tx_queue *txq) /* Unmap tx_cmd */ if (num_tbs) - pci_unmap_single(dev, dma_unmap_addr(&txq->meta[idx], mapping), + dma_unmap_single(&dev->dev, + dma_unmap_addr(&txq->meta[idx], mapping), dma_unmap_len(&txq->meta[idx], len), - PCI_DMA_BIDIRECTIONAL); + DMA_BIDIRECTIONAL); /* Unmap chunks, if any. */ for (i = 1; i < num_tbs; i++) - pci_unmap_single(dev, il4965_tfd_tb_get_addr(tfd, i), - il4965_tfd_tb_get_len(tfd, i), - PCI_DMA_TODEVICE); + dma_unmap_single(&dev->dev, il4965_tfd_tb_get_addr(tfd, i), + il4965_tfd_tb_get_len(tfd, i), DMA_TO_DEVICE); /* free SKB */ if (txq->skbs) { @@ -4243,9 +4242,9 @@ il4965_rx_handle(struct il_priv *il) rxq->queue[i] = NULL; - pci_unmap_page(il->pci_dev, rxb->page_dma, + dma_unmap_page(&il->pci_dev->dev, rxb->page_dma, PAGE_SIZE << il->hw_params.rx_page_order, - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); pkt = rxb_addr(rxb); len = le32_to_cpu(pkt->len_n_flags) & IL_RX_FRAME_SIZE_MSK; @@ -4290,12 +4289,12 @@ il4965_rx_handle(struct il_priv *il) spin_lock_irqsave(&rxq->lock, flags); if (rxb->page != NULL) { rxb->page_dma = - pci_map_page(il->pci_dev, rxb->page, 0, - PAGE_SIZE << il->hw_params. - rx_page_order, PCI_DMA_FROMDEVICE); + dma_map_page(&il->pci_dev->dev, rxb->page, 0, + PAGE_SIZE << il->hw_params.rx_page_order, + DMA_FROM_DEVICE); - if (unlikely(pci_dma_mapping_error(il->pci_dev, - rxb->page_dma))) { + if (unlikely(dma_mapping_error(&il->pci_dev->dev, + rxb->page_dma))) { __il_free_pages(il, rxb->page); rxb->page = NULL; list_add_tail(&rxb->list, &rxq->rx_used); @@ -6514,14 +6513,9 @@ il4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_master(pdev); - err = pci_set_dma_mask(pdev, DMA_BIT_MASK(36)); - if (!err) - err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(36)); + err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(36)); if (err) { - err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - if (!err) - err = - pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); + err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); /* both attempts failed: */ if (err) { IL_WARN("No suitable DMA available.\n"); diff --git a/drivers/net/wireless/intel/iwlegacy/common.c b/drivers/net/wireless/intel/iwlegacy/common.c index 219fed91cac5..683b632981ed 100644 --- a/drivers/net/wireless/intel/iwlegacy/common.c +++ b/drivers/net/wireless/intel/iwlegacy/common.c @@ -2819,10 +2819,10 @@ il_cmd_queue_unmap(struct il_priv *il) i = il_get_cmd_idx(q, q->read_ptr, 0); if (txq->meta[i].flags & CMD_MAPPED) { - pci_unmap_single(il->pci_dev, + dma_unmap_single(&il->pci_dev->dev, dma_unmap_addr(&txq->meta[i], mapping), dma_unmap_len(&txq->meta[i], len), - PCI_DMA_BIDIRECTIONAL); + DMA_BIDIRECTIONAL); txq->meta[i].flags = 0; } @@ -2831,10 +2831,10 @@ il_cmd_queue_unmap(struct il_priv *il) i = q->n_win; if (txq->meta[i].flags & CMD_MAPPED) { - pci_unmap_single(il->pci_dev, + dma_unmap_single(&il->pci_dev->dev, dma_unmap_addr(&txq->meta[i], mapping), dma_unmap_len(&txq->meta[i], len), - PCI_DMA_BIDIRECTIONAL); + DMA_BIDIRECTIONAL); txq->meta[i].flags = 0; } } @@ -3197,10 +3197,9 @@ il_enqueue_hcmd(struct il_priv *il, struct il_host_cmd *cmd) } #endif - phys_addr = - pci_map_single(il->pci_dev, &out_cmd->hdr, fix_size, - PCI_DMA_BIDIRECTIONAL); - if (unlikely(pci_dma_mapping_error(il->pci_dev, phys_addr))) { + phys_addr = dma_map_single(&il->pci_dev->dev, &out_cmd->hdr, fix_size, + DMA_BIDIRECTIONAL); + if (unlikely(dma_mapping_error(&il->pci_dev->dev, phys_addr))) { idx = -ENOMEM; goto out; } @@ -3298,8 +3297,8 @@ il_tx_cmd_complete(struct il_priv *il, struct il_rx_buf *rxb) txq->time_stamp = jiffies; - pci_unmap_single(il->pci_dev, dma_unmap_addr(meta, mapping), - dma_unmap_len(meta, len), PCI_DMA_BIDIRECTIONAL); + dma_unmap_single(&il->pci_dev->dev, dma_unmap_addr(meta, mapping), + dma_unmap_len(meta, len), DMA_BIDIRECTIONAL); /* Input error checking is done when commands are added to queue. */ if (meta->flags & CMD_WANT_SKB) { diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 1e6af3cbe026..f252680f18e8 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -3506,15 +3506,9 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, pci_set_master(pdev); addr_size = trans->txqs.tfd.addr_size; - ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(addr_size)); - if (!ret) - ret = pci_set_consistent_dma_mask(pdev, - DMA_BIT_MASK(addr_size)); + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(addr_size)); if (ret) { - ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - if (!ret) - ret = pci_set_consistent_dma_mask(pdev, - DMA_BIT_MASK(32)); + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); /* both attempts failed: */ if (ret) { dev_err(&pdev->dev, "No suitable DMA available\n"); From 8d4be124062bddbb2bcb887702a0601b790b9a83 Mon Sep 17 00:00:00 2001 From: Jing Yangyang Date: Mon, 23 Aug 2021 23:13:41 -0700 Subject: [PATCH 95/95] ssb: fix boolreturn.cocci warning ./include/linux/ssb/ssb_driver_extif.h:200:8-9:WARNING: return of 0/1 in function 'ssb_extif_available' with return type bool Return statements in functions returning bool should use true/false instead of 1/0. Generated by: scripts/coccinelle/misc/boolreturn.cocci Reported-by: Zeal Robot Signed-off-by: Jing Yangyang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20210824061341.59255-1-deng.changcheng@zte.com.cn --- include/linux/ssb/ssb_driver_extif.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/ssb/ssb_driver_extif.h b/include/linux/ssb/ssb_driver_extif.h index 3f8bc973d67d..19253bfacd1a 100644 --- a/include/linux/ssb/ssb_driver_extif.h +++ b/include/linux/ssb/ssb_driver_extif.h @@ -197,7 +197,7 @@ struct ssb_extif { static inline bool ssb_extif_available(struct ssb_extif *extif) { - return 0; + return false; } static inline