From 652291601459272d52b6ba12811f0b60b3e6444f Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 28 Nov 2021 14:15:09 +0200 Subject: [PATCH 01/42] iwlwifi: mei: don't rely on the size from the shared area If CSME is compromised, it could report a bigger queue size in the share area and make the host perform an out of bound access. Instead of reading the size of the queue from the shared area, store it in the regular context which is not accessible by CSME. While at it, fix a small typo in an error print. Signed-off-by: Emmanuel Grumbach Link: https://lore.kernel.org/r/20211128121509.3952-1-emmanuel.grumbach@intel.com Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mei/main.c | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mei/main.c b/drivers/net/wireless/intel/iwlwifi/mei/main.c index 112cc362e8e7..4eca333f91b3 100644 --- a/drivers/net/wireless/intel/iwlwifi/mei/main.c +++ b/drivers/net/wireless/intel/iwlwifi/mei/main.c @@ -119,6 +119,7 @@ struct iwl_sap_shared_mem_ctrl_blk { struct iwl_mei_shared_mem_ptrs { struct iwl_sap_shared_mem_ctrl_blk *ctrl; void *q_head[SAP_DIRECTION_MAX][SAP_QUEUE_IDX_MAX]; + size_t q_size[SAP_DIRECTION_MAX][SAP_QUEUE_IDX_MAX]; }; struct iwl_mei_filters { @@ -209,7 +210,7 @@ static void iwl_mei_free_shared_mem(struct mei_cl_device *cldev) struct iwl_mei *mei = mei_cldev_get_drvdata(cldev); if (mei_cldev_dma_unmap(cldev)) - dev_err(&cldev->dev, "Coudln't unmap the shared mem properly\n"); + dev_err(&cldev->dev, "Couldn't unmap the shared mem properly\n"); memset(&mei->shared_mem, 0, sizeof(mei->shared_mem)); } @@ -271,6 +272,8 @@ static void iwl_mei_init_shared_mem(struct iwl_mei *mei) mem->q_head[dir][queue] = q_head; q_head += le32_to_cpu(mem->ctrl->dir[dir].q_ctrl_blk[queue].size); + mem->q_size[dir][queue] = + le32_to_cpu(mem->ctrl->dir[dir].q_ctrl_blk[queue].size); } } @@ -280,11 +283,11 @@ static void iwl_mei_init_shared_mem(struct iwl_mei *mei) static ssize_t iwl_mei_write_cyclic_buf(struct mei_cl_device *cldev, struct iwl_sap_q_ctrl_blk *notif_q, u8 *q_head, - const struct iwl_sap_hdr *hdr) + const struct iwl_sap_hdr *hdr, + u32 q_sz) { u32 rd = le32_to_cpu(READ_ONCE(notif_q->rd_ptr)); u32 wr = le32_to_cpu(READ_ONCE(notif_q->wr_ptr)); - u32 q_sz = le32_to_cpu(notif_q->size); size_t room_in_buf; size_t tx_sz = sizeof(*hdr) + le16_to_cpu(hdr->len); @@ -382,6 +385,7 @@ static int iwl_mei_send_sap_msg_payload(struct mei_cl_device *cldev, struct iwl_sap_q_ctrl_blk *notif_q; struct iwl_sap_dir *dir; void *q_head; + u32 q_sz; int ret; lockdep_assert_held(&iwl_mei_mutex); @@ -404,7 +408,8 @@ static int iwl_mei_send_sap_msg_payload(struct mei_cl_device *cldev, dir = &mei->shared_mem.ctrl->dir[SAP_DIRECTION_HOST_TO_ME]; notif_q = &dir->q_ctrl_blk[SAP_QUEUE_IDX_NOTIF]; q_head = mei->shared_mem.q_head[SAP_DIRECTION_HOST_TO_ME][SAP_QUEUE_IDX_NOTIF]; - ret = iwl_mei_write_cyclic_buf(q_head, notif_q, q_head, hdr); + q_sz = mei->shared_mem.q_size[SAP_DIRECTION_HOST_TO_ME][SAP_QUEUE_IDX_NOTIF]; + ret = iwl_mei_write_cyclic_buf(q_head, notif_q, q_head, hdr, q_sz); if (ret < 0) return ret; @@ -454,10 +459,10 @@ void iwl_mei_add_data_to_ring(struct sk_buff *skb, bool cb_tx) dir = &mei->shared_mem.ctrl->dir[SAP_DIRECTION_HOST_TO_ME]; notif_q = &dir->q_ctrl_blk[SAP_QUEUE_IDX_DATA]; q_head = mei->shared_mem.q_head[SAP_DIRECTION_HOST_TO_ME][SAP_QUEUE_IDX_DATA]; + q_sz = mei->shared_mem.q_size[SAP_DIRECTION_HOST_TO_ME][SAP_QUEUE_IDX_DATA]; rd = le32_to_cpu(READ_ONCE(notif_q->rd_ptr)); wr = le32_to_cpu(READ_ONCE(notif_q->wr_ptr)); - q_sz = le32_to_cpu(notif_q->size); hdr_sz = cb_tx ? sizeof(struct iwl_sap_cb_data) : sizeof(struct iwl_sap_hdr); tx_sz = skb->len + hdr_sz; @@ -1074,11 +1079,11 @@ static void iwl_mei_handle_sap_rx_cmd(struct mei_cl_device *cldev, static void iwl_mei_handle_sap_rx(struct mei_cl_device *cldev, struct iwl_sap_q_ctrl_blk *notif_q, const u8 *q_head, - struct sk_buff_head *skbs) + struct sk_buff_head *skbs, + u32 q_sz) { u32 rd = le32_to_cpu(READ_ONCE(notif_q->rd_ptr)); u32 wr = le32_to_cpu(READ_ONCE(notif_q->wr_ptr)); - u32 q_sz = le32_to_cpu(notif_q->size); ssize_t valid_rx_sz; if (rd > q_sz || wr > q_sz) { @@ -1110,6 +1115,7 @@ static void iwl_mei_handle_check_shared_area(struct mei_cl_device *cldev) struct sk_buff_head tx_skbs; struct iwl_sap_dir *dir; void *q_head; + u32 q_sz; if (!mei->shared_mem.ctrl) return; @@ -1117,22 +1123,24 @@ static void iwl_mei_handle_check_shared_area(struct mei_cl_device *cldev) dir = &mei->shared_mem.ctrl->dir[SAP_DIRECTION_ME_TO_HOST]; notif_q = &dir->q_ctrl_blk[SAP_QUEUE_IDX_NOTIF]; q_head = mei->shared_mem.q_head[SAP_DIRECTION_ME_TO_HOST][SAP_QUEUE_IDX_NOTIF]; + q_sz = mei->shared_mem.q_size[SAP_DIRECTION_ME_TO_HOST][SAP_QUEUE_IDX_NOTIF]; /* * Do not hold the mutex here, but rather each and every message * handler takes it. * This allows message handlers to take it at a certain time. */ - iwl_mei_handle_sap_rx(cldev, notif_q, q_head, NULL); + iwl_mei_handle_sap_rx(cldev, notif_q, q_head, NULL, q_sz); mutex_lock(&iwl_mei_mutex); dir = &mei->shared_mem.ctrl->dir[SAP_DIRECTION_ME_TO_HOST]; notif_q = &dir->q_ctrl_blk[SAP_QUEUE_IDX_DATA]; q_head = mei->shared_mem.q_head[SAP_DIRECTION_ME_TO_HOST][SAP_QUEUE_IDX_DATA]; + q_sz = mei->shared_mem.q_size[SAP_DIRECTION_ME_TO_HOST][SAP_QUEUE_IDX_DATA]; __skb_queue_head_init(&tx_skbs); - iwl_mei_handle_sap_rx(cldev, notif_q, q_head, &tx_skbs); + iwl_mei_handle_sap_rx(cldev, notif_q, q_head, &tx_skbs, q_sz); if (skb_queue_empty(&tx_skbs)) { mutex_unlock(&iwl_mei_mutex); From 1a4d5758692519d6de648803a6d1dbba000bfe74 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 29 Nov 2021 12:49:21 +0000 Subject: [PATCH 02/42] iwlwifi: mei: Fix spelling mistake "req_ownserhip" -> "req_ownership" There is a spelling mistake in a debugfs filename. Fix it. Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20211129124921.11817-1-colin.i.king@gmail.com Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mei/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mei/main.c b/drivers/net/wireless/intel/iwlwifi/mei/main.c index 4eca333f91b3..3435998f0791 100644 --- a/drivers/net/wireless/intel/iwlwifi/mei/main.c +++ b/drivers/net/wireless/intel/iwlwifi/mei/main.c @@ -1762,7 +1762,7 @@ static void iwl_mei_dbgfs_register(struct iwl_mei *mei) mei->dbgfs_dir, &iwl_mei_status); debugfs_create_file("send_start_message", S_IWUSR, mei->dbgfs_dir, mei, &iwl_mei_dbgfs_send_start_message_ops); - debugfs_create_file("req_ownserhip", S_IWUSR, mei->dbgfs_dir, + debugfs_create_file("req_ownership", S_IWUSR, mei->dbgfs_dir, mei, &iwl_mei_dbgfs_req_ownership_ops); } From 46c7b05a4f91f425d429bbe152c0185e9f8a5d18 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 30 Nov 2021 12:59:51 +0200 Subject: [PATCH 03/42] iwlwifi: mvm: fix a possible NULL pointer deference Smatch spot a possible NULL pointer dereference. Fix it. __iwl_mvm_mac_set_key can be called with sta = NULL Also add a NULL pointer check after memory allocation. Reported-by: Dan Carpenter Signed-off-by: Emmanuel Grumbach Link: https://lore.kernel.org/r/20211130105951.85539-1-emmanuel.grumbach@intel.com Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mei/main.c | 2 ++ drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 11 ++++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mei/main.c b/drivers/net/wireless/intel/iwlwifi/mei/main.c index 3435998f0791..4453cd2571c2 100644 --- a/drivers/net/wireless/intel/iwlwifi/mei/main.c +++ b/drivers/net/wireless/intel/iwlwifi/mei/main.c @@ -632,6 +632,8 @@ static void iwl_mei_handle_csme_filters(struct mei_cl_device *cldev, lockdep_is_held(&iwl_mei_mutex)); new_filters = kzalloc(sizeof(*new_filters), GFP_KERNEL); + if (!new_filters) + return; /* Copy the OOB filters */ new_filters->filters = filters->filters; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 20422e640059..aac2c03fbcb3 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -3563,13 +3563,14 @@ static int __iwl_mvm_mac_set_key(struct ieee80211_hw *hw, { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - struct iwl_mvm_sta *mvmsta; + struct iwl_mvm_sta *mvmsta = NULL; struct iwl_mvm_key_pn *ptk_pn; int keyidx = key->keyidx; int ret, i; u8 key_offset; - mvmsta = iwl_mvm_sta_from_mac80211(sta); + if (sta) + mvmsta = iwl_mvm_sta_from_mac80211(sta); switch (key->cipher) { case WLAN_CIPHER_SUITE_TKIP: @@ -3671,7 +3672,7 @@ static int __iwl_mvm_mac_set_key(struct ieee80211_hw *hw, } if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) && - sta && iwl_mvm_has_new_rx_api(mvm) && + mvmsta && iwl_mvm_has_new_rx_api(mvm) && key->flags & IEEE80211_KEY_FLAG_PAIRWISE && (key->cipher == WLAN_CIPHER_SUITE_CCMP || key->cipher == WLAN_CIPHER_SUITE_GCMP || @@ -3705,7 +3706,7 @@ static int __iwl_mvm_mac_set_key(struct ieee80211_hw *hw, else key_offset = STA_KEY_IDX_INVALID; - if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) + if (mvmsta && key->flags & IEEE80211_KEY_FLAG_PAIRWISE) mvmsta->pairwise_cipher = key->cipher; IWL_DEBUG_MAC80211(mvm, "set hwcrypto key\n"); @@ -3748,7 +3749,7 @@ static int __iwl_mvm_mac_set_key(struct ieee80211_hw *hw, break; } - if (sta && iwl_mvm_has_new_rx_api(mvm) && + if (mvmsta && iwl_mvm_has_new_rx_api(mvm) && key->flags & IEEE80211_KEY_FLAG_PAIRWISE && (key->cipher == WLAN_CIPHER_SUITE_CCMP || key->cipher == WLAN_CIPHER_SUITE_GCMP || From f973795a8d19cbf3d03807704eb7c6ff65788d5a Mon Sep 17 00:00:00 2001 From: Lv Yunlong Date: Fri, 2 Apr 2021 22:47:55 -0700 Subject: [PATCH 04/42] wireless: iwlwifi: Fix a double free in iwl_txq_dyn_alloc_dma In iwl_txq_dyn_alloc_dma, txq->tfds is freed at first time by: iwl_txq_alloc()->goto err_free_tfds->dma_free_coherent(). But it forgot to set txq->tfds to NULL. Then the txq->tfds is freed again in iwl_txq_dyn_alloc_dma by: goto error->iwl_txq_gen2_free_memory()->dma_free_coherent(). My patch sets txq->tfds to NULL after the first free to avoid the double free. Fixes: 0cd1ad2d7fd41 ("iwlwifi: move all bus-independent TX functions to common code") Signed-off-by: Lv Yunlong Link: https://lore.kernel.org/r/20210403054755.4781-1-lyl2019@mail.ustc.edu.cn Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/queue/tx.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/intel/iwlwifi/queue/tx.c b/drivers/net/wireless/intel/iwlwifi/queue/tx.c index 451b06069350..0f3526b0c5b0 100644 --- a/drivers/net/wireless/intel/iwlwifi/queue/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/queue/tx.c @@ -1072,6 +1072,7 @@ int iwl_txq_alloc(struct iwl_trans *trans, struct iwl_txq *txq, int slots_num, return 0; err_free_tfds: dma_free_coherent(trans->dev, tfd_sz, txq->tfds, txq->dma_addr); + txq->tfds = NULL; error: if (txq->entries && cmd_queue) for (i = 0; i < slots_num; i++) From 00d667fc457d39adc0798d57af0316e8a461ec37 Mon Sep 17 00:00:00 2001 From: Yang Shen Date: Mon, 17 May 2021 13:01:36 +0800 Subject: [PATCH 05/42] iwlwifi: mvm: demote non-compliant kernel-doc header Fixes the following W=1 kernel build warning: drivers/net/wireless/intel/iwlwifi/mvm/rfi.c:11: warning: This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst Cc: Stanislav Yakovlev Signed-off-by: Yang Shen [removed the static const fix, since it's already done and updated the commit message accordingly.] Link: https://lore.kernel.org/r/20210517050141.61488-7-shenyang39@huawei.com 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 44344216a1a9..f1ed73c9f3dd 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rfi.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rfi.c @@ -7,7 +7,7 @@ #include "fw/api/commands.h" #include "fw/api/phy-ctxt.h" -/** +/* * DDR needs frequency in units of 16.666MHz, so provide FW with the * frequency values in the adjusted format. */ From 2438d430868e1676f5b1e476c8982e88217fe66c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 4 Dec 2021 08:35:44 +0200 Subject: [PATCH 06/42] iwlwifi: mvm: fix delBA vs. NSSN queue sync race If we happen to decide an NSSN queue sync (IWL_MVM_RXQ_NSSN_SYNC) for some remaining packets that are still on the queue, but just after we've decided to do a delBA (which causes its own queues sync with IWL_MVM_RXQ_NOTIF_DEL_BA) we can end up with a sequence of events like this: CPU 1 CPU 2 remove BA session with baid N send IWL_MVM_RXQ_NOTIF_DEL_BA send IWL_MVM_RXQ_NSSN_SYNC get IWL_MVM_RXQ_NOTIF_DEL_BA get IWL_MVM_RXQ_NOTIF_DEL_BA get IWL_MVM_RXQ_NSSN_SYNC complete IWL_MVM_RXQ_NOTIF_DEL_BA remove N from baid_map[] get IWL_MVM_RXQ_NSSN_SYNC WARN_ON(!baid_map[N]) Thus, there's a race that leads in hitting the WARN_ON, but more importantly, it's a race that potentially even results in a new aggregation session getting assigned to baid N. To fix this, remove the WARN_ON() in the NSSN_SYNC case, we can't completely protect against hitting this case, so we shouldn't be warning. However, guard ourselves against BAID reuse by doing yet another round of queue synchronization after the entry is removed from the baid_map, so that it cannot be reused with any in-flight IWL_MVM_RXQ_NSSN_SYNC messages. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20211204083237.44abbbc50f40.I5492600dfe513356555abe2d7df0e2835846e3d8@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 5 ++++- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 10 ++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index e0601f802628..03e90087576c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -766,8 +766,11 @@ static void iwl_mvm_release_frames_from_notif(struct iwl_mvm *mvm, rcu_read_lock(); ba_data = rcu_dereference(mvm->baid_map[baid]); - if (WARN_ON_ONCE(!ba_data)) + if (!ba_data) { + WARN(!(flags & IWL_MVM_RELEASE_FROM_RSS_SYNC), + "BAID %d not found in map\n", baid); goto out; + } sta = rcu_dereference(mvm->fw_id_to_mac_id[ba_data->sta_id]); if (WARN_ON_ONCE(IS_ERR_OR_NULL(sta))) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index a64874c05ced..feab0bfcd7a2 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -2684,6 +2684,16 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, RCU_INIT_POINTER(mvm->baid_map[baid], NULL); kfree_rcu(baid_data, rcu_head); IWL_DEBUG_HT(mvm, "BAID %d is free\n", baid); + + /* + * After we've deleted it, do another queue sync + * so if an IWL_MVM_RXQ_NSSN_SYNC was concurrently + * running it won't find a new session in the old + * BAID. It can find the NULL pointer for the BAID, + * but we must not have it find a different session. + */ + iwl_mvm_sync_rx_queues_internal(mvm, IWL_MVM_RXQ_EMPTY, + true, NULL, 0); } return 0; From db66abeea3aefed481391ecc564fb7b7fb31d742 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 4 Dec 2021 08:35:45 +0200 Subject: [PATCH 07/42] iwlwifi: mvm: synchronize with FW after multicast commands If userspace installs a lot of multicast groups very quickly, then we may run out of command queue space as we send the updates in an asynchronous fashion (due to locking concerns), and the CPU can create them faster than the firmware can process them. This is true even when mac80211 has a work struct that gets scheduled. Fix this by synchronizing with the firmware after sending all those commands - outside of the iteration we can send a synchronous echo command that just has the effect of the CPU waiting for the prior asynchronous commands to finish. This also will cause fewer of the commands to be sent to the firmware overall, because the work will only run once when rescheduled multiple times while it's running. Link: https://bugzilla.kernel.org/show_bug.cgi?id=213649 Suggested-by: Emmanuel Grumbach Reported-by: Maximilian Ernestus Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20211204083238.51aea5b79ea4.I88a44798efda16e9fe480fb3e94224931d311b29@changeid Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/mvm/mac80211.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index aac2c03fbcb3..77569b5afe1a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -1710,6 +1710,7 @@ static void iwl_mvm_recalc_multicast(struct iwl_mvm *mvm) struct iwl_mvm_mc_iter_data iter_data = { .mvm = mvm, }; + int ret; lockdep_assert_held(&mvm->mutex); @@ -1719,6 +1720,22 @@ static void iwl_mvm_recalc_multicast(struct iwl_mvm *mvm) ieee80211_iterate_active_interfaces_atomic( mvm->hw, IEEE80211_IFACE_ITER_NORMAL, iwl_mvm_mc_iface_iterator, &iter_data); + + /* + * Send a (synchronous) ech command so that we wait for the + * multiple asynchronous MCAST_FILTER_CMD commands sent by + * the interface iterator. Otherwise, we might get here over + * and over again (by userspace just sending a lot of these) + * and the CPU can send them faster than the firmware can + * process them. + * Note that the CPU is still faster - but with this we'll + * actually send fewer commands overall because the CPU will + * not schedule the work in mac80211 as frequently if it's + * still running when rescheduled (possibly multiple times). + */ + ret = iwl_mvm_send_cmd_pdu(mvm, ECHO_CMD, 0, 0, NULL); + if (ret) + IWL_ERR(mvm, "Failed to synchronize multicast groups update\n"); } static u64 iwl_mvm_prepare_multicast(struct ieee80211_hw *hw, From 55c6d8f89dab6d9bed0165dd4c134856975bd000 Mon Sep 17 00:00:00 2001 From: Mike Golant Date: Tue, 7 Dec 2021 16:05:51 +0200 Subject: [PATCH 08/42] iwlwifi: support 4-bits in MAC step value We have a MAC component (which is inside the SoC) and it has several different HW steps. 3 bits used to be enough but now we need 4-bits to represent all the different steps. Properly support 4-bits in the MAC step value by refactoring all the current handling of the MAC step/dash. Already from family 8000 and up the dash (bits 0-1) no longer exists and the step (until 8000 bits 2-3) consists of the dash bits as well. To do this remove the CSR_HW_REV_STEP and the CSR_HW_REV_DASH macros, replace them with CSR_HW_REV_STEP_DASH and add hw_rev_step into the trans struct. In addition remove the CSR_HW_IF_CONFIG_REG_MSK_MAC_STEP and CSR_HW_IF_CONFIG_REG_MSK_MAC_DASH macros and create a new macro combining the 2 (this way we don't need shifting or anything else.) Signed-off-by: Matti Gottlieb Signed-off-by: Mike Golant Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20211207160459.2e81a14d1f80.Ia5287e37fb3439d805336837361f6491f958e465@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/dvm/main.c | 8 ++------ drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 4 ++-- drivers/net/wireless/intel/iwlwifi/iwl-csr.h | 14 ++++++-------- drivers/net/wireless/intel/iwlwifi/iwl-drv.c | 4 ++-- drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c | 2 +- drivers/net/wireless/intel/iwlwifi/iwl-trans.h | 2 ++ drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 10 +++------- drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 2 +- drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 5 +++-- 9 files changed, 22 insertions(+), 29 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/main.c b/drivers/net/wireless/intel/iwlwifi/dvm/main.c index fbd57a2b2bd5..90b9becd1673 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/main.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/main.c @@ -1974,12 +1974,8 @@ static void iwl_nic_config(struct iwl_op_mode *op_mode) /* SKU Control */ iwl_trans_set_bits_mask(priv->trans, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_MSK_MAC_DASH | - CSR_HW_IF_CONFIG_REG_MSK_MAC_STEP, - (CSR_HW_REV_STEP(priv->trans->hw_rev) << - CSR_HW_IF_CONFIG_REG_POS_MAC_STEP) | - (CSR_HW_REV_DASH(priv->trans->hw_rev) << - CSR_HW_IF_CONFIG_REG_POS_MAC_DASH)); + CSR_HW_IF_CONFIG_REG_MSK_MAC_STEP_DASH, + CSR_HW_REV_STEP_DASH(priv->trans->hw_rev)); /* write radio config values to register */ if (priv->nvm_data->radio_cfg_type <= EEPROM_RF_CONFIG_TYPE_MAX) { diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index a39013c401c9..c8a08bdfefa4 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -880,7 +880,7 @@ iwl_fw_error_dump_file(struct iwl_fw_runtime *fwrt, dump_info->hw_type = cpu_to_le32(CSR_HW_REV_TYPE(fwrt->trans->hw_rev)); dump_info->hw_step = - cpu_to_le32(CSR_HW_REV_STEP(fwrt->trans->hw_rev)); + cpu_to_le32(fwrt->trans->hw_rev_step); memcpy(dump_info->fw_human_readable, fwrt->fw->human_readable, sizeof(dump_info->fw_human_readable)); strncpy(dump_info->dev_human_readable, fwrt->trans->name, @@ -2099,7 +2099,7 @@ static u32 iwl_dump_ini_info(struct iwl_fw_runtime *fwrt, dump->ver_type = cpu_to_le32(fwrt->dump.fw_ver.type); dump->ver_subtype = cpu_to_le32(fwrt->dump.fw_ver.subtype); - dump->hw_step = cpu_to_le32(CSR_HW_REV_STEP(fwrt->trans->hw_rev)); + dump->hw_step = cpu_to_le32(fwrt->trans->hw_rev_step); /* * Several HWs all have type == 0x42, so we'll override this value diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h index ff79a2ecb242..cfea20e507b3 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h @@ -143,8 +143,7 @@ #define CSR_FUNC_SCRATCH_INIT_VALUE (0x01010101) /* Bits for CSR_HW_IF_CONFIG_REG */ -#define CSR_HW_IF_CONFIG_REG_MSK_MAC_DASH (0x00000003) -#define CSR_HW_IF_CONFIG_REG_MSK_MAC_STEP (0x0000000C) +#define CSR_HW_IF_CONFIG_REG_MSK_MAC_STEP_DASH (0x0000000F) #define CSR_HW_IF_CONFIG_REG_BIT_MONITOR_SRAM (0x00000080) #define CSR_HW_IF_CONFIG_REG_MSK_BOARD_VER (0x000000C0) #define CSR_HW_IF_CONFIG_REG_BIT_MAC_SI (0x00000100) @@ -287,8 +286,7 @@ #define CSR_GP_CNTRL_REG_FLAG_SW_RESET BIT(31) /* HW REV */ -#define CSR_HW_REV_DASH(_val) (((_val) & 0x0000003) >> 0) -#define CSR_HW_REV_STEP(_val) (((_val) & 0x000000C) >> 2) +#define CSR_HW_REV_STEP_DASH(_val) ((_val) & CSR_HW_IF_CONFIG_REG_MSK_MAC_STEP_DASH) #define CSR_HW_REV_TYPE(_val) (((_val) & 0x000FFF0) >> 4) /* HW RFID */ @@ -328,10 +326,10 @@ enum { #define CSR_HW_REV_TYPE_7265D (0x0000210) #define CSR_HW_REV_TYPE_NONE (0x00001F0) #define CSR_HW_REV_TYPE_QNJ (0x0000360) -#define CSR_HW_REV_TYPE_QNJ_B0 (0x0000364) -#define CSR_HW_REV_TYPE_QU_B0 (0x0000334) -#define CSR_HW_REV_TYPE_QU_C0 (0x0000338) -#define CSR_HW_REV_TYPE_QUZ (0x0000354) +#define CSR_HW_REV_TYPE_QNJ_B0 (0x0000361) +#define CSR_HW_REV_TYPE_QU_B0 (0x0000331) +#define CSR_HW_REV_TYPE_QU_C0 (0x0000332) +#define CSR_HW_REV_TYPE_QUZ (0x0000351) #define CSR_HW_REV_TYPE_HR_CDB (0x0000340) #define CSR_HW_REV_TYPE_SO (0x0000370) #define CSR_HW_REV_TYPE_TY (0x0000420) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c index 36196e07b1a0..026116629040 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c @@ -163,8 +163,8 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first) char tag[8]; if (drv->trans->trans_cfg->device_family == IWL_DEVICE_FAMILY_9000 && - (CSR_HW_REV_STEP(drv->trans->hw_rev) != SILICON_B_STEP && - CSR_HW_REV_STEP(drv->trans->hw_rev) != SILICON_C_STEP)) { + (drv->trans->hw_rev_step != SILICON_B_STEP && + drv->trans->hw_rev_step != SILICON_C_STEP)) { IWL_ERR(drv, "Only HW steps B and C are currently supported (0x%0x)\n", drv->trans->hw_rev); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c index 0cd4718372f5..9ef89ff09105 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c @@ -1609,7 +1609,7 @@ int iwl_read_external_nvm(struct iwl_trans *trans, /* nvm file validation, dword_buff[2] holds the file version */ if (trans->trans_cfg->device_family == IWL_DEVICE_FAMILY_8000 && - CSR_HW_REV_STEP(trans->hw_rev) == SILICON_C_STEP && + trans->hw_rev_step == SILICON_C_STEP && le32_to_cpu(dword_buff[2]) < 0xE4A) { ret = -EFAULT; goto out; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index a4060af50201..947ed82b7f19 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -938,6 +938,7 @@ struct iwl_trans_txqs { * @hw_id: a u32 with the ID of the device / sub-device. * Set during transport allocation. * @hw_id_str: a string with info about HW ID. Set during transport allocation. + * @hw_rev_step: The mac step of the HW * @pm_support: set to true in start_hw if link pm is supported * @ltr_enabled: set to true if the LTR is enabled * @wide_cmd_header: true when ucode supports wide command header format @@ -971,6 +972,7 @@ struct iwl_trans { struct device *dev; u32 max_skb_frags; u32 hw_rev; + u32 hw_rev_step; u32 hw_rf_id; u32 hw_id; char hw_id_str[52]; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 3ab0217abeea..cd04f24dd7fa 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -78,7 +78,7 @@ static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode) { struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); u8 radio_cfg_type, radio_cfg_step, radio_cfg_dash; - u32 reg_val = 0; + u32 reg_val; u32 phy_config = iwl_mvm_get_phy_config(mvm); radio_cfg_type = (phy_config & FW_PHY_CFG_RADIO_TYPE) >> @@ -89,10 +89,7 @@ static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode) FW_PHY_CFG_RADIO_DASH_POS; /* SKU control */ - reg_val |= CSR_HW_REV_STEP(mvm->trans->hw_rev) << - CSR_HW_IF_CONFIG_REG_POS_MAC_STEP; - reg_val |= CSR_HW_REV_DASH(mvm->trans->hw_rev) << - CSR_HW_IF_CONFIG_REG_POS_MAC_DASH; + reg_val = CSR_HW_REV_STEP_DASH(mvm->trans->hw_rev); /* radio configuration */ reg_val |= radio_cfg_type << CSR_HW_IF_CONFIG_REG_POS_PHY_TYPE; @@ -117,8 +114,7 @@ static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode) reg_val |= CSR_HW_IF_CONFIG_REG_D3_DEBUG; iwl_trans_set_bits_mask(mvm->trans, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_MSK_MAC_DASH | - CSR_HW_IF_CONFIG_REG_MSK_MAC_STEP | + CSR_HW_IF_CONFIG_REG_MSK_MAC_STEP_DASH | CSR_HW_IF_CONFIG_REG_MSK_PHY_TYPE | CSR_HW_IF_CONFIG_REG_MSK_PHY_STEP | CSR_HW_IF_CONFIG_REG_MSK_PHY_DASH | diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index 5c56da36fc84..db8b62e432eb 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -1450,7 +1450,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) dev_info = iwl_pci_find_dev_info(pdev->device, pdev->subsystem_device, CSR_HW_REV_TYPE(iwl_trans->hw_rev), - CSR_HW_REV_STEP(iwl_trans->hw_rev), + iwl_trans->hw_rev_step, CSR_HW_RFID_TYPE(iwl_trans->hw_rf_id), CSR_HW_RFID_IS_CDB(iwl_trans->hw_rf_id), IWL_SUBDEVICE_RF_ID(pdev->subsystem_device), diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 451b28de1392..f607edd41baa 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -3616,8 +3616,9 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, * in the old format. */ if (cfg_trans->device_family >= IWL_DEVICE_FAMILY_8000) - trans->hw_rev = (trans->hw_rev & 0xfff0) | - (CSR_HW_REV_STEP(trans->hw_rev << 2) << 2); + trans->hw_rev_step = trans->hw_rev & 0xF; + else + trans->hw_rev_step = (trans->hw_rev & 0xC) >> 2; IWL_DEBUG_INFO(trans, "HW REV: 0x%0x\n", trans->hw_rev); From f738e705975f591c2acd5ed79d5c5e496c986773 Mon Sep 17 00:00:00 2001 From: Mike Golant Date: Sat, 4 Dec 2021 08:35:47 +0200 Subject: [PATCH 09/42] iwlwifi: add support for Bz-Z HW Add support for Bz Z step HW with GF RF. Signed-off-by: Mike Golant Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20211204083238.fc8626515758.Ibfeffc8bb071f9773ea189992ebef056f51be1be@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/cfg/22000.c | 10 ++++++++++ drivers/net/wireless/intel/iwlwifi/iwl-config.h | 1 + drivers/net/wireless/intel/iwlwifi/iwl-csr.h | 1 + drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 7 +++++++ 4 files changed, 19 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c index 1572097bccf1..7a06bbae178b 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c @@ -55,6 +55,7 @@ #define IWL_BZ_A_MR_A_FW_PRE "iwlwifi-bz-a0-mr-a0-" #define IWL_BZ_A_FM_A_FW_PRE "iwlwifi-bz-a0-fm-a0-" #define IWL_GL_A_FM_A_FW_PRE "iwlwifi-gl-a0-fm7-a0-" +#define IWL_BZ_Z_GF_A_FW_PRE "iwlwifi-bz-z0-gf-a0-" #define IWL_QU_B_HR_B_MODULE_FIRMWARE(api) \ @@ -113,6 +114,8 @@ IWL_BZ_A_FM_A_FW_PRE __stringify(api) ".ucode" #define IWL_GL_A_FM_A_MODULE_FIRMWARE(api) \ IWL_GL_A_FM_A_FW_PRE __stringify(api) ".ucode" +#define IWL_BZ_Z_GF_A_MODULE_FIRMWARE(api) \ + IWL_BZ_Z_GF_A_FW_PRE __stringify(api) ".ucode" static const struct iwl_base_params iwl_22000_base_params = { .eeprom_size = OTP_LOW_IMAGE_SIZE_32K, @@ -879,6 +882,13 @@ const struct iwl_cfg iwl_cfg_gl_a0_fm_a0 = { .num_rbds = IWL_NUM_RBDS_AX210_HE, }; +const struct iwl_cfg iwl_cfg_bz_z0_gf_a0 = { + .fw_name_pre = IWL_BZ_Z_GF_A_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_BZ, + .num_rbds = IWL_NUM_RBDS_AX210_HE, +}; + MODULE_FIRMWARE(IWL_QU_B_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_QNJ_B_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_QU_C_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index 665167a223f6..d704e278b577 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -634,6 +634,7 @@ extern const struct iwl_cfg iwl_cfg_bz_a0_gf4_a0; extern const struct iwl_cfg iwl_cfg_bz_a0_mr_a0; extern const struct iwl_cfg iwl_cfg_bz_a0_fm_a0; extern const struct iwl_cfg iwl_cfg_gl_a0_fm_a0; +extern const struct iwl_cfg iwl_cfg_bz_z0_gf_a0; #endif /* CONFIG_IWLMVM */ #endif /* __IWL_CONFIG_H__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h index cfea20e507b3..046a01f5988b 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h @@ -304,6 +304,7 @@ enum { SILICON_A_STEP = 0, SILICON_B_STEP, SILICON_C_STEP, + SILICON_Z_STEP = 0xf, }; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index db8b62e432eb..93d789670f89 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -1130,6 +1130,13 @@ static const struct iwl_dev_info iwl_dev_info_table[] = { IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_gl_a0_fm_a0, iwl_bz_name), +/* BZ Z step */ + _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_BZ, SILICON_Z_STEP, + IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, + iwl_cfg_bz_z0_gf_a0, iwl_bz_name), + /* SoF with JF2 */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SOF, IWL_CFG_ANY, From 87209b7fc2c54a5d8b75fca4452012d2e93df3e0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 4 Dec 2021 08:35:48 +0200 Subject: [PATCH 10/42] iwlwifi: mvm: d3: move GTK rekeys condition Move the GTK rekeying condition into iwl_mvm_set_key_rx_seq() so we can modify it in the next patch. In the next firmware API revision we'll properly get data for both active GTKs and will have to install it accordingly. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20211204083238.f309942ddd15.Iaa95c602f3a681dd464e10ce2de047aa86fac19c@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index a19f646a324f..f9b485fcfcdb 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -1651,8 +1651,12 @@ static void iwl_mvm_convert_key_counters(struct iwl_wowlan_status_data *status, static void iwl_mvm_set_key_rx_seq(struct iwl_mvm *mvm, struct ieee80211_key_conf *key, - struct iwl_wowlan_status_data *status) + struct iwl_wowlan_status_data *status, + bool installed) { + if (status->num_of_gtk_rekeys && !installed) + return; + switch (key->cipher) { case WLAN_CIPHER_SUITE_CCMP: case WLAN_CIPHER_SUITE_GCMP: @@ -1740,8 +1744,9 @@ static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw, if (data->status->num_of_gtk_rekeys) ieee80211_remove_key(key); - else if (data->last_gtk == key) - iwl_mvm_set_key_rx_seq(data->mvm, key, data->status); + + if (data->last_gtk == key) + iwl_mvm_set_key_rx_seq(data->mvm, key, data->status, false); } static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm, @@ -1825,7 +1830,7 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm, key = ieee80211_gtk_rekey_add(vif, &conf.conf); if (IS_ERR(key)) return false; - iwl_mvm_set_key_rx_seq(mvm, key, status); + iwl_mvm_set_key_rx_seq(mvm, key, status, true); replay_ctr = cpu_to_be64(status->replay_ctr); From af08571d39254a8ef71422e213f59baf38351d55 Mon Sep 17 00:00:00 2001 From: Haim Dreyfuss Date: Sat, 4 Dec 2021 08:35:49 +0200 Subject: [PATCH 11/42] iwlwifi: pcie: support Bz suspend/resume trigger Instead of using two bits in the doorbell interrupt, the new Bz devices have a new CSR_IPC_SLEEP_CONTROL register to let drivers indicate the desired transition before triggering the doorbell interrupt. Signed-off-by: Haim Dreyfuss Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20211204083238.63f3d150689a.Iaeb6f9b007e81b1a5a02144b0281935e4613cb78@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-csr.h | 4 + drivers/net/wireless/intel/iwlwifi/iwl-prph.h | 7 ++ .../net/wireless/intel/iwlwifi/pcie/trans.c | 75 ++++++++++--------- 3 files changed, 52 insertions(+), 34 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h index 046a01f5988b..21d8249980fa 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h @@ -105,6 +105,10 @@ /* GIO Chicken Bits (PCI Express bus link power management) */ #define CSR_GIO_CHICKEN_BITS (CSR_BASE+0x100) +#define CSR_IPC_SLEEP_CONTROL (CSR_BASE + 0x114) +#define CSR_IPC_SLEEP_CONTROL_SUSPEND 0x3 +#define CSR_IPC_SLEEP_CONTROL_RESUME 0 + /* Doorbell NMI (since Bz) */ #define CSR_DOORBELL_VECTOR (CSR_BASE + 0x130) #define CSR_DOORBELL_VECTOR_NMI BIT(1) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h index a84ab02cf9d7..2ca22e1b8bd9 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h @@ -455,6 +455,13 @@ enum { #define UREG_DOORBELL_TO_ISR6_RESUME BIT(19) #define UREG_DOORBELL_TO_ISR6_PNVM BIT(20) +/* + * From BZ family driver triggers this bit for suspend and resume + * The driver should update CSR_IPC_SLEEP_CONTROL before triggering + * this interrupt with suspend/resume value + */ +#define UREG_DOORBELL_TO_ISR6_SLEEP_CTRL BIT(31) + #define CNVI_MBOX_C 0xA3400C #define FSEQ_ERROR_CODE 0xA340C8 diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index f607edd41baa..0aeab8acc247 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -1499,33 +1499,54 @@ void iwl_pcie_d3_complete_suspend(struct iwl_trans *trans, iwl_pcie_set_pwr(trans, true); } +static int iwl_pcie_d3_handshake(struct iwl_trans *trans, bool suspend) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + int ret; + + if (trans->trans_cfg->device_family == IWL_DEVICE_FAMILY_AX210) { + iwl_write_umac_prph(trans, UREG_DOORBELL_TO_ISR6, + suspend ? UREG_DOORBELL_TO_ISR6_SUSPEND : + UREG_DOORBELL_TO_ISR6_RESUME); + } else if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) { + iwl_write32(trans, CSR_IPC_SLEEP_CONTROL, + suspend ? CSR_IPC_SLEEP_CONTROL_SUSPEND : + CSR_IPC_SLEEP_CONTROL_RESUME); + iwl_write_umac_prph(trans, UREG_DOORBELL_TO_ISR6, + UREG_DOORBELL_TO_ISR6_SLEEP_CTRL); + } else { + return 0; + } + + ret = wait_event_timeout(trans_pcie->sx_waitq, + trans_pcie->sx_complete, 2 * HZ); + + /* Invalidate it toward next suspend or resume */ + trans_pcie->sx_complete = false; + + if (!ret) { + IWL_ERR(trans, "Timeout %s D3\n", + suspend ? "entering" : "exiting"); + return -ETIMEDOUT; + } + + return 0; +} + static int iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test, bool reset) { int ret; - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); if (!reset) /* Enable persistence mode to avoid reset */ iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_PERSIST_MODE); - if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) { - iwl_write_umac_prph(trans, UREG_DOORBELL_TO_ISR6, - UREG_DOORBELL_TO_ISR6_SUSPEND); + ret = iwl_pcie_d3_handshake(trans, true); + if (ret) + return ret; - ret = wait_event_timeout(trans_pcie->sx_waitq, - trans_pcie->sx_complete, 2 * HZ); - /* - * Invalidate it toward resume. - */ - trans_pcie->sx_complete = false; - - if (!ret) { - IWL_ERR(trans, "Timeout entering D3\n"); - return -ETIMEDOUT; - } - } iwl_pcie_d3_complete_suspend(trans, test, reset); return 0; @@ -1542,6 +1563,7 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans, if (test) { iwl_enable_interrupts(trans); *status = IWL_D3_STATUS_ALIVE; + ret = 0; goto out; } @@ -1590,25 +1612,10 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans, *status = IWL_D3_STATUS_ALIVE; out: - if (*status == IWL_D3_STATUS_ALIVE && - trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) { - trans_pcie->sx_complete = false; - iwl_write_umac_prph(trans, UREG_DOORBELL_TO_ISR6, - UREG_DOORBELL_TO_ISR6_RESUME); + if (*status == IWL_D3_STATUS_ALIVE) + ret = iwl_pcie_d3_handshake(trans, false); - ret = wait_event_timeout(trans_pcie->sx_waitq, - trans_pcie->sx_complete, 2 * HZ); - /* - * Invalidate it toward next suspend. - */ - trans_pcie->sx_complete = false; - - if (!ret) { - IWL_ERR(trans, "Timeout exiting D3\n"); - return -ETIMEDOUT; - } - } - return 0; + return ret; } static void From 708d8c5385a4cf63760d0932387f2cce9e8c9d8f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 4 Dec 2021 08:35:50 +0200 Subject: [PATCH 12/42] iwlwifi: mvm: parse firmware alive message version 6 There's a new version with some addition, we'll need to do something with the additional data later, but for now just parse it so we don't fail with the newer firmware. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20211204083238.f856cb190a4e.I77e3ff5a92b1bcc3e81c1344b046dade0a8b6a24@changeid Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/fw/api/alive.h | 17 ++++++++++++++++- .../wireless/intel/iwlwifi/fw/api/commands.h | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 6 ++++-- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/alive.h b/drivers/net/wireless/intel/iwlwifi/fw/api/alive.h index c840a97e6a62..7dd984fbe0f8 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/alive.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/alive.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, 2020-2021 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -97,6 +97,21 @@ struct iwl_alive_ntf_v5 { struct iwl_sku_id sku_id; } __packed; /* UCODE_ALIVE_NTFY_API_S_VER_5 */ +struct iwl_imr_alive_info { + __le64 base_addr; + __le32 size; + __le32 enabled; +} __packed; /* IMR_ALIVE_INFO_API_S_VER_1 */ + +struct iwl_alive_ntf_v6 { + __le16 status; + __le16 flags; + struct iwl_lmac_alive lmac_data[2]; + struct iwl_umac_alive umac_data; + struct iwl_sku_id sku_id; + struct iwl_imr_alive_info imr; +} __packed; /* UCODE_ALIVE_NTFY_API_S_VER_6 */ + /** * enum iwl_extended_cfg_flag - commands driver may send before * finishing init flow diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h b/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h index ee6b5844a871..8a90acbd0db9 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h @@ -51,7 +51,7 @@ enum iwl_legacy_cmds { * @UCODE_ALIVE_NTFY: * Alive data from the firmware, as described in * &struct iwl_alive_ntf_v3 or &struct iwl_alive_ntf_v4 or - * &struct iwl_alive_ntf_v5. + * &struct iwl_alive_ntf_v5 or &struct iwl_alive_ntf_v6. */ UCODE_ALIVE_NTFY = 0x1, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 6ce78c03e51f..7608b1e486c4 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -123,13 +123,15 @@ static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait, struct iwl_lmac_alive *lmac2 = NULL; u16 status; u32 lmac_error_event_table, umac_error_table; + u32 version = iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP, + UCODE_ALIVE_NTFY, 0); /* * For v5 and above, we can check the version, for older * versions we need to check the size. */ - if (iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP, - UCODE_ALIVE_NTFY, 0) == 5) { + if (version == 5 || version == 6) { + /* v5 and v6 are compatible (only IMR addition) */ struct iwl_alive_ntf_v5 *palive; if (pkt_len < sizeof(*palive)) From 2dc977423cbf762bbc6a7237b4294a9099ad10d3 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 4 Dec 2021 08:35:51 +0200 Subject: [PATCH 13/42] iwlwifi: mvm: d3: support v12 wowlan status Newer firmware versions are going to come with a new version of the wowlan status API, which gives us replay counters for both GTKs that might still be in use, as well as unifying the layout of the counters to just be 64-bit quantities. Extend our code to handle this case and be able to install replay counters for both keys, if they're sent up from the firmware. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20211204083238.73637acafe0b.I33e27712a12fff2816edc0a8abda1759259e20d7@changeid Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/fw/api/d3.h | 81 +++++++- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 183 +++++++++++++++--- 2 files changed, 235 insertions(+), 29 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h index 1503119ea910..4cd9ab23954e 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h @@ -554,7 +554,7 @@ struct iwl_wowlan_gtk_status_v1 { } __packed; /* WOWLAN_GTK_MATERIAL_VER_1 */ /** - * struct iwl_wowlan_gtk_status - GTK status + * struct iwl_wowlan_gtk_status_v2 - GTK status * @key: GTK material * @key_len: GTK legth, if set to 0, the key is not available * @key_flags: information about the key: @@ -565,7 +565,7 @@ struct iwl_wowlan_gtk_status_v1 { * @tkip_mic_key: TKIP RX MIC key * @rsc: TSC RSC counters */ -struct iwl_wowlan_gtk_status { +struct iwl_wowlan_gtk_status_v2 { u8 key[WOWLAN_KEY_MAX_SIZE]; u8 key_len; u8 key_flags; @@ -574,6 +574,41 @@ struct iwl_wowlan_gtk_status { struct iwl_wowlan_rsc_tsc_params_cmd_ver_2 rsc; } __packed; /* WOWLAN_GTK_MATERIAL_VER_2 */ +/** + * struct iwl_wowlan_all_rsc_tsc_v5 - key counters + * @ucast_rsc: unicast RSC values + * @mcast_rsc: multicast RSC values (per key map value) + * @sta_id: station ID + * @mcast_key_id_map: map of key id to @mcast_rsc entry + */ +struct iwl_wowlan_all_rsc_tsc_v5 { + __le64 ucast_rsc[IWL_MAX_TID_COUNT]; + __le64 mcast_rsc[2][IWL_MAX_TID_COUNT]; + __le32 sta_id; + u8 mcast_key_id_map[4]; +} __packed; /* ALL_TSC_RSC_API_S_VER_5 */ + +/** + * struct iwl_wowlan_gtk_status_v3 - GTK status + * @key: GTK material + * @key_len: GTK length, if set to 0, the key is not available + * @key_flags: information about the key: + * bits[0:1]: key index assigned by the AP + * bits[2:6]: GTK index of the key in the internal DB + * bit[7]: Set iff this is the currently used GTK + * @reserved: padding + * @tkip_mic_key: TKIP RX MIC key + * @sc: RSC/TSC counters + */ +struct iwl_wowlan_gtk_status_v3 { + u8 key[WOWLAN_KEY_MAX_SIZE]; + u8 key_len; + u8 key_flags; + u8 reserved[2]; + u8 tkip_mic_key[IWL_MIC_KEY_SIZE]; + struct iwl_wowlan_all_rsc_tsc_v5 sc; +} __packed; /* WOWLAN_GTK_MATERIAL_VER_3 */ + #define IWL_WOWLAN_GTK_IDX_MASK (BIT(0) | BIT(1)) /** @@ -640,7 +675,7 @@ struct iwl_wowlan_status_v6 { * @wake_packet: wakeup packet */ struct iwl_wowlan_status_v7 { - struct iwl_wowlan_gtk_status gtk[WOWLAN_GTK_KEYS_NUM]; + struct iwl_wowlan_gtk_status_v2 gtk[WOWLAN_GTK_KEYS_NUM]; struct iwl_wowlan_igtk_status igtk[WOWLAN_IGTK_KEYS_NUM]; __le64 replay_ctr; __le16 pattern_number; @@ -676,7 +711,7 @@ struct iwl_wowlan_status_v7 { * @wake_packet: wakeup packet */ struct iwl_wowlan_status_v9 { - struct iwl_wowlan_gtk_status gtk[WOWLAN_GTK_KEYS_NUM]; + struct iwl_wowlan_gtk_status_v2 gtk[WOWLAN_GTK_KEYS_NUM]; struct iwl_wowlan_igtk_status igtk[WOWLAN_IGTK_KEYS_NUM]; __le64 replay_ctr; __le16 pattern_number; @@ -693,6 +728,44 @@ struct iwl_wowlan_status_v9 { u8 wake_packet[]; /* can be truncated from _length to _bufsize */ } __packed; /* WOWLAN_STATUSES_RSP_API_S_VER_9 */ +/** + * struct iwl_wowlan_status_v12 - WoWLAN status + * @gtk: GTK data + * @igtk: IGTK data + * @replay_ctr: GTK rekey replay counter + * @pattern_number: number of the matched pattern + * @non_qos_seq_ctr: non-QoS sequence counter to use next. + * Reserved if the struct has version >= 10. + * @qos_seq_ctr: QoS sequence counters to use next + * @wakeup_reasons: wakeup reasons, see &enum iwl_wowlan_wakeup_reason + * @num_of_gtk_rekeys: number of GTK rekeys + * @transmitted_ndps: number of transmitted neighbor discovery packets + * @received_beacons: number of received beacons + * @wake_packet_length: wakeup packet length + * @wake_packet_bufsize: wakeup packet buffer size + * @tid_tear_down: bit mask of tids whose BA sessions were closed + * in suspend state + * @reserved: unused + * @wake_packet: wakeup packet + */ +struct iwl_wowlan_status_v12 { + struct iwl_wowlan_gtk_status_v3 gtk[WOWLAN_GTK_KEYS_NUM]; + struct iwl_wowlan_igtk_status igtk[WOWLAN_IGTK_KEYS_NUM]; + __le64 replay_ctr; + __le16 pattern_number; + __le16 non_qos_seq_ctr; + __le16 qos_seq_ctr[8]; + __le32 wakeup_reasons; + __le32 num_of_gtk_rekeys; + __le32 transmitted_ndps; + __le32 received_beacons; + __le32 wake_packet_length; + __le32 wake_packet_bufsize; + u8 tid_tear_down; + u8 reserved[3]; + u8 wake_packet[]; /* can be truncated from _length to _bufsize */ +} __packed; /* WOWLAN_STATUSES_RSP_API_S_VER_12 */ + /* TODO: NetDetect API */ #endif /* __iwl_fw_api_d3_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index f9b485fcfcdb..b400867e94f0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -1390,6 +1390,13 @@ struct iwl_wowlan_status_data { u16 qos_seq_ctr[8]; u8 tid_tear_down; + struct { + /* including RX MIC key for TKIP */ + u8 key[WOWLAN_KEY_MAX_SIZE]; + u8 len; + u8 flags; + } gtk; + struct { /* * We store both the TKIP and AES representations @@ -1400,11 +1407,15 @@ struct iwl_wowlan_status_data { struct { struct ieee80211_key_seq seq[IWL_MAX_TID_COUNT]; } tkip, aes; - /* including RX MIC key for TKIP */ - u8 key[WOWLAN_KEY_MAX_SIZE]; - u8 len; - u8 flags; - } gtk; + + /* + * We use -1 for when we have valid data but don't know + * the key ID from firmware, and thus it needs to be + * installed with the last key (depending on rekeying). + */ + s8 key_id; + bool valid; + } gtk_seq[2]; struct { /* Same as above */ @@ -1556,12 +1567,10 @@ static void iwl_mvm_report_wakeup_reasons(struct iwl_mvm *mvm, kfree_skb(pkt); } -static void iwl_mvm_aes_sc_to_seq(struct aes_sc *sc, - struct ieee80211_key_seq *seq) +static void iwl_mvm_le64_to_aes_seq(__le64 le_pn, struct ieee80211_key_seq *seq) { - u64 pn; + u64 pn = le64_to_cpu(le_pn); - pn = le64_to_cpu(sc->pn); seq->ccmp.pn[0] = pn >> 40; seq->ccmp.pn[1] = pn >> 32; seq->ccmp.pn[2] = pn >> 24; @@ -1570,6 +1579,20 @@ static void iwl_mvm_aes_sc_to_seq(struct aes_sc *sc, seq->ccmp.pn[5] = pn; } +static void iwl_mvm_aes_sc_to_seq(struct aes_sc *sc, + struct ieee80211_key_seq *seq) +{ + iwl_mvm_le64_to_aes_seq(sc->pn, seq); +} + +static void iwl_mvm_le64_to_tkip_seq(__le64 le_pn, struct ieee80211_key_seq *seq) +{ + u64 pn = le64_to_cpu(le_pn); + + seq->tkip.iv16 = (u16)pn; + seq->tkip.iv32 = (u32)(pn >> 16); +} + static void iwl_mvm_tkip_sc_to_seq(struct tkip_sc *sc, struct ieee80211_key_seq *seq) { @@ -1630,10 +1653,12 @@ static void iwl_mvm_convert_key_counters(struct iwl_wowlan_status_data *status, /* GTK RX counters */ for (i = 0; i < IWL_MAX_TID_COUNT; i++) { iwl_mvm_tkip_sc_to_seq(&sc->tkip.multicast_rsc[i], - &status->gtk.tkip.seq[i]); + &status->gtk_seq[0].tkip.seq[i]); iwl_mvm_aes_sc_to_seq(&sc->aes.multicast_rsc[i], - &status->gtk.aes.seq[i]); + &status->gtk_seq[0].aes.seq[i]); } + status->gtk_seq[0].valid = true; + status->gtk_seq[0].key_id = -1; /* PTK TX counter */ status->ptk.tkip.tx_pn = (u64)le16_to_cpu(sc->tkip.tsc.iv16) | @@ -1649,28 +1674,103 @@ static void iwl_mvm_convert_key_counters(struct iwl_wowlan_status_data *status, } } -static void iwl_mvm_set_key_rx_seq(struct iwl_mvm *mvm, - struct ieee80211_key_conf *key, - struct iwl_wowlan_status_data *status, - bool installed) +static void +iwl_mvm_convert_key_counters_v5_gtk_seq(struct iwl_wowlan_status_data *status, + struct iwl_wowlan_all_rsc_tsc_v5 *sc, + unsigned int idx, unsigned int key_id) { - if (status->num_of_gtk_rekeys && !installed) - return; + int tid; + for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) { + iwl_mvm_le64_to_tkip_seq(sc->mcast_rsc[idx][tid], + &status->gtk_seq[idx].tkip.seq[tid]); + iwl_mvm_le64_to_aes_seq(sc->mcast_rsc[idx][tid], + &status->gtk_seq[idx].aes.seq[tid]); + } + + status->gtk_seq[idx].valid = true; + status->gtk_seq[idx].key_id = key_id; +} + +static void +iwl_mvm_convert_key_counters_v5(struct iwl_wowlan_status_data *status, + struct iwl_wowlan_all_rsc_tsc_v5 *sc) +{ + int i, tid; + + BUILD_BUG_ON(IWL_MAX_TID_COUNT > IWL_MAX_TID_COUNT); + BUILD_BUG_ON(IWL_MAX_TID_COUNT > IWL_NUM_RSC); + BUILD_BUG_ON(ARRAY_SIZE(sc->mcast_rsc) != ARRAY_SIZE(status->gtk_seq)); + + /* GTK RX counters */ + for (i = 0; i < ARRAY_SIZE(sc->mcast_key_id_map); i++) { + u8 entry = sc->mcast_key_id_map[i]; + + if (entry < ARRAY_SIZE(sc->mcast_rsc)) + iwl_mvm_convert_key_counters_v5_gtk_seq(status, sc, + entry, i); + } + + /* PTK TX counters not needed, assigned in device */ + + /* PTK RX counters */ + for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) { + iwl_mvm_le64_to_tkip_seq(sc->ucast_rsc[tid], + &status->ptk.tkip.seq[tid]); + iwl_mvm_le64_to_aes_seq(sc->ucast_rsc[tid], + &status->ptk.aes.seq[tid]); + } +} + +static void iwl_mvm_set_key_rx_seq_idx(struct ieee80211_key_conf *key, + struct iwl_wowlan_status_data *status, + int idx) +{ switch (key->cipher) { case WLAN_CIPHER_SUITE_CCMP: case WLAN_CIPHER_SUITE_GCMP: case WLAN_CIPHER_SUITE_GCMP_256: - iwl_mvm_set_key_rx_seq_tids(key, status->gtk.aes.seq); + iwl_mvm_set_key_rx_seq_tids(key, status->gtk_seq[idx].aes.seq); break; case WLAN_CIPHER_SUITE_TKIP: - iwl_mvm_set_key_rx_seq_tids(key, status->gtk.tkip.seq); + iwl_mvm_set_key_rx_seq_tids(key, status->gtk_seq[idx].tkip.seq); break; default: WARN_ON(1); } } +static void iwl_mvm_set_key_rx_seq(struct ieee80211_key_conf *key, + struct iwl_wowlan_status_data *status, + bool installed) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(status->gtk_seq); i++) { + if (!status->gtk_seq[i].valid) + continue; + + /* Handle the case where we know the key ID */ + if (status->gtk_seq[i].key_id == key->keyidx) { + s8 new_key_id = -1; + + if (status->num_of_gtk_rekeys) + new_key_id = status->gtk.flags & + IWL_WOWLAN_GTK_IDX_MASK; + + /* Don't install a new key's value to an old key */ + if (new_key_id != key->keyidx) + iwl_mvm_set_key_rx_seq_idx(key, status, i); + continue; + } + + /* handle the case where we didn't, last key only */ + if (status->gtk_seq[i].key_id == -1 && + (!status->num_of_gtk_rekeys || installed)) + iwl_mvm_set_key_rx_seq_idx(key, status, i); + } +} + struct iwl_mvm_d3_gtk_iter_data { struct iwl_mvm *mvm; struct iwl_wowlan_status_data *status; @@ -1746,7 +1846,7 @@ static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw, ieee80211_remove_key(key); if (data->last_gtk == key) - iwl_mvm_set_key_rx_seq(data->mvm, key, data->status, false); + iwl_mvm_set_key_rx_seq(key, data->status, false); } static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm, @@ -1830,7 +1930,7 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm, key = ieee80211_gtk_rekey_add(vif, &conf.conf); if (IS_ERR(key)) return false; - iwl_mvm_set_key_rx_seq(mvm, key, status, true); + iwl_mvm_set_key_rx_seq(key, status, true); replay_ctr = cpu_to_be64(status->replay_ctr); @@ -1898,9 +1998,10 @@ iwl_mvm_parse_wowlan_status_common_ ## _ver(struct iwl_mvm *mvm, \ iwl_mvm_parse_wowlan_status_common(v6) iwl_mvm_parse_wowlan_status_common(v7) iwl_mvm_parse_wowlan_status_common(v9) +iwl_mvm_parse_wowlan_status_common(v12) -static void iwl_mvm_convert_gtk(struct iwl_wowlan_status_data *status, - struct iwl_wowlan_gtk_status *data) +static void iwl_mvm_convert_gtk_v2(struct iwl_wowlan_status_data *status, + struct iwl_wowlan_gtk_status_v2 *data) { BUILD_BUG_ON(sizeof(status->gtk.key) < sizeof(data->key)); BUILD_BUG_ON(NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY + @@ -1918,6 +2019,26 @@ static void iwl_mvm_convert_gtk(struct iwl_wowlan_status_data *status, data->tkip_mic_key, sizeof(data->tkip_mic_key)); } +static void iwl_mvm_convert_gtk_v3(struct iwl_wowlan_status_data *status, + struct iwl_wowlan_gtk_status_v3 *data) +{ + /* The parts we need are identical in v2 and v3 */ +#define CHECK(_f) do { \ + BUILD_BUG_ON(offsetof(struct iwl_wowlan_gtk_status_v2, _f) != \ + offsetof(struct iwl_wowlan_gtk_status_v3, _f)); \ + BUILD_BUG_ON(offsetofend(struct iwl_wowlan_gtk_status_v2, _f) !=\ + offsetofend(struct iwl_wowlan_gtk_status_v3, _f)); \ +} while (0) + + CHECK(key); + CHECK(key_len); + CHECK(key_flags); + CHECK(tkip_mic_key); +#undef CHECK + + iwl_mvm_convert_gtk_v2(status, (void *)data); +} + static void iwl_mvm_convert_igtk(struct iwl_wowlan_status_data *status, struct iwl_wowlan_igtk_status *data) { @@ -2017,7 +2138,7 @@ iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm, u8 sta_id) goto out_free_resp; iwl_mvm_convert_key_counters(status, &v7->gtk[0].rsc.all_tsc_rsc); - iwl_mvm_convert_gtk(status, &v7->gtk[0]); + iwl_mvm_convert_gtk_v2(status, &v7->gtk[0]); iwl_mvm_convert_igtk(status, &v7->igtk[0]); } else if (notif_ver == 9 || notif_ver == 10 || notif_ver == 11) { struct iwl_wowlan_status_v9 *v9 = (void *)cmd.resp_pkt->data; @@ -2030,10 +2151,22 @@ iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm, u8 sta_id) goto out_free_resp; iwl_mvm_convert_key_counters(status, &v9->gtk[0].rsc.all_tsc_rsc); - iwl_mvm_convert_gtk(status, &v9->gtk[0]); + iwl_mvm_convert_gtk_v2(status, &v9->gtk[0]); iwl_mvm_convert_igtk(status, &v9->igtk[0]); status->tid_tear_down = v9->tid_tear_down; + } else if (notif_ver == 12) { + struct iwl_wowlan_status_v12 *v12 = (void *)cmd.resp_pkt->data; + + status = iwl_mvm_parse_wowlan_status_common_v12(mvm, v12, len); + if (IS_ERR(status)) + goto out_free_resp; + + iwl_mvm_convert_key_counters_v5(status, &v12->gtk[0].sc); + iwl_mvm_convert_gtk_v3(status, &v12->gtk[0]); + iwl_mvm_convert_igtk(status, &v12->igtk[0]); + + status->tid_tear_down = v12->tid_tear_down; } else { IWL_ERR(mvm, "Firmware advertises unknown WoWLAN status response %d!\n", From c48e93a65487aedc9334bcaec4abce63e204241f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 4 Dec 2021 08:35:52 +0200 Subject: [PATCH 14/42] iwlwifi: mvm: support RLC configuration command There's an RLC configuration command in the firmware that's going to replace the chain information in the PHY context. Add support for this command, while leaving the PHY context fields unset when we know the RLC command will be used. Also add support to send only the RLC configuration command if only the # of chains used on the PHY context changes. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20211204083238.55faa3782bb0.I3f9d0071e680cab513c59b093d0827af99d41c51@changeid Signed-off-by: Luca Coelho --- .../wireless/intel/iwlwifi/fw/api/datapath.h | 62 +++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 7 +-- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 1 + .../net/wireless/intel/iwlwifi/mvm/phy-ctxt.c | 60 +++++++++++++++++- 4 files changed, 123 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h b/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h index 985b0dc5b52a..89236f42c5a4 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h @@ -31,6 +31,11 @@ enum iwl_data_path_subcmd_ids { */ STA_HE_CTXT_CMD = 0x7, + /** + * @RLC_CONFIG_CMD: &struct iwl_rlc_config_cmd + */ + RLC_CONFIG_CMD = 0x8, + /** * @RFH_QUEUE_CONFIG_CMD: &struct iwl_rfh_queue_config */ @@ -195,4 +200,61 @@ struct iwl_thermal_dual_chain_request { __le32 event; } __packed; /* THERMAL_DUAL_CHAIN_DISABLE_REQ_NTFY_API_S_VER_1 */ +enum iwl_rlc_chain_info { + IWL_RLC_CHAIN_INFO_DRIVER_FORCE = BIT(0), + IWL_RLC_CHAIN_INFO_VALID = 0x000e, + IWL_RLC_CHAIN_INFO_FORCE = 0x0070, + IWL_RLC_CHAIN_INFO_FORCE_MIMO = 0x0380, + IWL_RLC_CHAIN_INFO_COUNT = 0x0c00, + IWL_RLC_CHAIN_INFO_MIMO_COUNT = 0x3000, +}; + +/** + * struct iwl_rlc_properties - RLC properties + * @rx_chain_info: RX chain info, &enum iwl_rlc_chain_info + * @reserved: reserved + */ +struct iwl_rlc_properties { + __le32 rx_chain_info; + __le32 reserved; +} __packed; /* RLC_PROPERTIES_S_VER_1 */ + +enum iwl_sad_mode { + IWL_SAD_MODE_ENABLED = BIT(0), + IWL_SAD_MODE_DEFAULT_ANT_MSK = 0x6, + IWL_SAD_MODE_DEFAULT_ANT_FW = 0x0, + IWL_SAD_MODE_DEFAULT_ANT_A = 0x2, + IWL_SAD_MODE_DEFAULT_ANT_B = 0x4, +}; + +/** + * struct iwl_sad_properties - SAD properties + * @chain_a_sad_mode: chain A SAD mode, &enum iwl_sad_mode + * @chain_b_sad_mode: chain B SAD mode, &enum iwl_sad_mode + * @mac_id: MAC index + * @reserved: reserved + */ +struct iwl_sad_properties { + __le32 chain_a_sad_mode; + __le32 chain_b_sad_mode; + __le32 mac_id; + __le32 reserved; +} __packed; + +/** + * struct iwl_rlc_config_cmd - RLC configuration + * @phy_id: PHY index + * @rlc: RLC properties, &struct iwl_rlc_properties + * @sad: SAD (single antenna diversity) options, &struct iwl_sad_properties + * @flags: flags, &enum iwl_rlc_flags + * @reserved: reserved + */ +struct iwl_rlc_config_cmd { + __le32 phy_id; + struct iwl_rlc_properties rlc; + struct iwl_sad_properties sad; + u8 flags; + u8 reserved[3]; +} __packed; /* RLC_CONFIG_CMD_API_S_VER_2 */ + #endif /* __iwl_fw_api_datapath_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 64ff2395800c..f7ff7f2e3928 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -94,11 +94,10 @@ struct iwl_mvm_phy_ctxt { enum nl80211_chan_width width; - /* - * TODO: This should probably be removed. Currently here only for rate - * scaling algorithm - */ struct ieee80211_channel *channel; + + /* track for RLC config command */ + u32 center_freq1; }; struct iwl_mvm_time_event_data { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index cd04f24dd7fa..baa1d8c597fa 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -530,6 +530,7 @@ static const struct iwl_hcmd_names iwl_mvm_data_path_names[] = { HCMD_NAME(UPDATE_MU_GROUPS_CMD), HCMD_NAME(TRIGGER_RX_QUEUES_NOTIF_CMD), HCMD_NAME(STA_HE_CTXT_CMD), + HCMD_NAME(RLC_CONFIG_CMD), HCMD_NAME(RFH_QUEUE_CONFIG_CMD), HCMD_NAME(TLC_MNG_CONFIG_CMD), HCMD_NAME(CHEST_COLLECTOR_FILTER_CONFIG_CMD), diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c index 035336a9e755..6feb2f664d2c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c @@ -157,8 +157,43 @@ static void iwl_mvm_phy_ctxt_cmd_data(struct iwl_mvm *mvm, /* Set the channel info data */ iwl_mvm_set_chan_info_chandef(mvm, &cmd->ci, chandef); - iwl_mvm_phy_ctxt_set_rxchain(mvm, ctxt, &cmd->rxchain_info, + /* we only support RLC command version 2 */ + if (iwl_fw_lookup_cmd_ver(mvm->fw, DATA_PATH_GROUP, + RLC_CONFIG_CMD, 0) < 2) + iwl_mvm_phy_ctxt_set_rxchain(mvm, ctxt, &cmd->rxchain_info, + chains_static, chains_dynamic); +} + +static int iwl_mvm_phy_send_rlc(struct iwl_mvm *mvm, + struct iwl_mvm_phy_ctxt *ctxt, + u8 chains_static, u8 chains_dynamic) +{ + struct iwl_rlc_config_cmd cmd = { + .phy_id = cpu_to_le32(ctxt->id), + }; + + if (iwl_fw_lookup_cmd_ver(mvm->fw, DATA_PATH_GROUP, + RLC_CONFIG_CMD, 0) < 2) + return 0; + + BUILD_BUG_ON(IWL_RLC_CHAIN_INFO_DRIVER_FORCE != + PHY_RX_CHAIN_DRIVER_FORCE_MSK); + BUILD_BUG_ON(IWL_RLC_CHAIN_INFO_VALID != + PHY_RX_CHAIN_VALID_MSK); + BUILD_BUG_ON(IWL_RLC_CHAIN_INFO_FORCE != + PHY_RX_CHAIN_FORCE_SEL_MSK); + BUILD_BUG_ON(IWL_RLC_CHAIN_INFO_FORCE_MIMO != + PHY_RX_CHAIN_FORCE_MIMO_SEL_MSK); + BUILD_BUG_ON(IWL_RLC_CHAIN_INFO_COUNT != PHY_RX_CHAIN_CNT_MSK); + BUILD_BUG_ON(IWL_RLC_CHAIN_INFO_MIMO_COUNT != + PHY_RX_CHAIN_MIMO_CNT_MSK); + + iwl_mvm_phy_ctxt_set_rxchain(mvm, ctxt, &cmd.rlc.rx_chain_info, chains_static, chains_dynamic); + + return iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(RLC_CONFIG_CMD, + DATA_PATH_GROUP, 2), + 0, sizeof(cmd), &cmd); } /* @@ -211,9 +246,16 @@ static int iwl_mvm_phy_ctxt_apply(struct iwl_mvm *mvm, } - if (ret) + if (ret) { IWL_ERR(mvm, "PHY ctxt cmd error. ret=%d\n", ret); - return ret; + return ret; + } + + if (action != FW_CTXT_ACTION_REMOVE) + return iwl_mvm_phy_send_rlc(mvm, ctxt, chains_static, + chains_dynamic); + + return 0; } /* @@ -228,6 +270,8 @@ int iwl_mvm_phy_ctxt_add(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, lockdep_assert_held(&mvm->mutex); ctxt->channel = chandef->chan; + ctxt->width = chandef->width; + ctxt->center_freq1 = chandef->center_freq1; return iwl_mvm_phy_ctxt_apply(mvm, ctxt, chandef, chains_static, chains_dynamic, @@ -257,6 +301,14 @@ int iwl_mvm_phy_ctxt_changed(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, lockdep_assert_held(&mvm->mutex); + if (iwl_fw_lookup_cmd_ver(mvm->fw, DATA_PATH_GROUP, + RLC_CONFIG_CMD, 0) >= 2 && + ctxt->channel == chandef->chan && + ctxt->width == chandef->width && + ctxt->center_freq1 == chandef->center_freq1) + return iwl_mvm_phy_send_rlc(mvm, ctxt, chains_static, + chains_dynamic); + if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_BINDING_CDB_SUPPORT) && ctxt->channel->band != chandef->chan->band) { @@ -275,6 +327,8 @@ int iwl_mvm_phy_ctxt_changed(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, ctxt->channel = chandef->chan; ctxt->width = chandef->width; + ctxt->center_freq1 = chandef->center_freq1; + return iwl_mvm_phy_ctxt_apply(mvm, ctxt, chandef, chains_static, chains_dynamic, action); From f4340baff9c23be65e7becf91e2e9bb1b77f92ac Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 4 Dec 2021 08:35:53 +0200 Subject: [PATCH 15/42] iwlwifi: fw: api: add link to PHY context command struct v1 There are two possible versions of this command in use today, add a link to v1 as well in the documentation. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20211204083238.d7c4ed8e85e0.I524a84e03068ecf7c3125ad028f0ca465d41c0f3@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/api/commands.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h b/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h index 8a90acbd0db9..8ce03b08592c 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h @@ -72,7 +72,8 @@ enum iwl_legacy_cmds { /** * @PHY_CONTEXT_CMD: - * Add/modify/remove a PHY context, using &struct iwl_phy_context_cmd. + * Add/modify/remove a PHY context, using &struct iwl_phy_context_cmd + * or &struct iwl_phy_context_cmd_v1. */ PHY_CONTEXT_CMD = 0x8, From 26e9ccb3c800d87828a2bf87a3b6de3a8c069b08 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 4 Dec 2021 08:35:54 +0200 Subject: [PATCH 16/42] iwlwifi: mvm: add support for PHY context command v4 A new version of this command deprecates the rxchain_info field but is otherwise the same, so treat it the same way. We already leave the rxchain_info zeroed since the RLC command is supported. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20211204083238.aca5bd78518e.I2f1b4b38899717851ea9f5b6dd23cde27e10387a@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/api/phy-ctxt.h | 9 +++++---- drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/phy-ctxt.h b/drivers/net/wireless/intel/iwlwifi/fw/api/phy-ctxt.h index 68b788b92b7a..e66f77924f83 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/phy-ctxt.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/phy-ctxt.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, 2020-2021 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -150,11 +150,12 @@ struct iwl_phy_context_cmd { /* COMMON_INDEX_HDR_API_S_VER_1 */ __le32 id_and_color; __le32 action; - /* PHY_CONTEXT_DATA_API_S_VER_3 */ + /* PHY_CONTEXT_DATA_API_S_VER_3, PHY_CONTEXT_DATA_API_S_VER_4 */ struct iwl_fw_channel_info ci; __le32 lmac_id; - __le32 rxchain_info; + __le32 rxchain_info; /* reserved in _VER_4 */ __le32 dsp_cfg_flags; __le32 reserved; -} __packed; /* PHY_CONTEXT_CMD_API_VER_3 */ +} __packed; /* PHY_CONTEXT_CMD_API_VER_3, PHY_CONTEXT_CMD_API_VER_4 */ + #endif /* __iwl_fw_api_phy_ctxt_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c index 6feb2f664d2c..9af40b0fa37a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c @@ -212,7 +212,7 @@ static int iwl_mvm_phy_ctxt_apply(struct iwl_mvm *mvm, int ver = iwl_fw_lookup_cmd_ver(mvm->fw, IWL_ALWAYS_LONG_GROUP, PHY_CONTEXT_CMD, 1); - if (ver == 3) { + if (ver == 3 || ver == 4) { struct iwl_phy_context_cmd cmd = {}; /* Set the command header fields */ From 94cc0b9e12c02954a9f8a560ad703eba6073de38 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Sat, 4 Dec 2021 08:35:55 +0200 Subject: [PATCH 17/42] iwlwifi: remove unused iwlax210_2ax_cfg_so_hr_a0 structure We don't use this structure anymore, except for a check that will never match, so we can remove this structure entirely. Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20211204083238.c41548abd174.I6bb4f6058fd85e1dd92cd056b6eaca1cb4aa74a3@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/cfg/22000.c | 7 ------- drivers/net/wireless/intel/iwlwifi/iwl-config.h | 1 - drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 15 --------------- 3 files changed, 23 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c index 7a06bbae178b..0467c1e9eeb3 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c @@ -699,13 +699,6 @@ const struct iwl_cfg iwlax210_2ax_cfg_so_jf_b0 = { .num_rbds = IWL_NUM_RBDS_NON_HE, }; -const struct iwl_cfg iwlax210_2ax_cfg_so_hr_a0 = { - .name = "Intel(R) Wi-Fi 6 AX210 160MHz", - .fw_name_pre = IWL_SO_A_HR_B_FW_PRE, - IWL_DEVICE_AX210, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - const struct iwl_cfg iwlax211_2ax_cfg_so_gf_a0 = { .name = iwl_ax211_name, .fw_name_pre = IWL_SO_A_GF_A_FW_PRE, diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index d704e278b577..1ecde7c86368 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -610,7 +610,6 @@ extern const struct iwl_cfg killer1650x_2ax_cfg; extern const struct iwl_cfg killer1650w_2ax_cfg; extern const struct iwl_cfg iwl_qnj_b0_hr_b0_cfg; extern const struct iwl_cfg iwlax210_2ax_cfg_so_jf_b0; -extern const struct iwl_cfg iwlax210_2ax_cfg_so_hr_a0; extern const struct iwl_cfg iwlax211_2ax_cfg_so_gf_a0; extern const struct iwl_cfg iwlax211_2ax_cfg_so_gf_a0_long; extern const struct iwl_cfg iwlax210_2ax_cfg_ty_gf_a0; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index 93d789670f89..89f0390963c9 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -1498,21 +1498,6 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) (iwl_trans->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_7265D) iwl_trans->cfg = cfg_7265d; - if (cfg == &iwlax210_2ax_cfg_so_hr_a0) { - if (iwl_trans->hw_rev == CSR_HW_REV_TYPE_TY) { - iwl_trans->cfg = &iwlax210_2ax_cfg_ty_gf_a0; - } else if (CSR_HW_RFID_TYPE(iwl_trans->hw_rf_id) == - CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_JF)) { - iwl_trans->cfg = &iwlax210_2ax_cfg_so_jf_b0; - } else if (CSR_HW_RFID_TYPE(iwl_trans->hw_rf_id) == - CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_GF)) { - iwl_trans->cfg = &iwlax211_2ax_cfg_so_gf_a0; - } else if (CSR_HW_RFID_TYPE(iwl_trans->hw_rf_id) == - CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_GF4)) { - iwl_trans->cfg = &iwlax411_2ax_cfg_so_gf4_a0; - } - } - /* * This is a hack to switch from Qu B0 to Qu C0. We need to * do this for all cfgs that use Qu B0, except for those using From d5d8ee526d1401173ad1261c3b6388a4f947e0a3 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sat, 4 Dec 2021 13:10:42 +0200 Subject: [PATCH 18/42] iwlwifi: mvm: remove session protection upon station removal When the station is removed we need to remove the session protection that may be still running. Note that we need also to remove the session protection upon unassoc in case the station is kept in the AUTH state. Signed-off-by: Emmanuel Grumbach Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20211204130722.483977310ca2.If7eba02594f20dabd22d758e1c917fbca54b2ddd@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 77569b5afe1a..4344f5d94b09 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -3405,16 +3405,16 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, if (vif->type == NL80211_IFTYPE_AP) { mvmvif->ap_assoc_sta_count--; iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL); - } else if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) { - /* remove session protection if still running */ + } else if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) iwl_mvm_stop_session_protection(mvm, vif); - } ret = 0; } else if (old_state == IEEE80211_STA_AUTH && new_state == IEEE80211_STA_NONE) { ret = 0; } else if (old_state == IEEE80211_STA_NONE && new_state == IEEE80211_STA_NOTEXIST) { + if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) + iwl_mvm_stop_session_protection(mvm, vif); ret = iwl_mvm_rm_sta(mvm, vif, sta); if (sta->tdls) { iwl_mvm_recalc_tdls_state(mvm, vif, false); From 4743a72fa5adc3cdcf4a596e99a982725db4e2e5 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Sat, 4 Dec 2021 13:10:43 +0200 Subject: [PATCH 19/42] iwlwifi: add missing entries for Gf4 with So and SoF We need to support platforms with So and SoF together with Gf4 radio modules. The difference is that these devices support CDB, so add the entries accordingly. Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20211204130722.e7fa5b87fbdb.Ib47ff1dc082366b570649dfd8a2b24f0d6c52b5b@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index 89f0390963c9..11b6c5b54683 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -1097,6 +1097,11 @@ static const struct iwl_dev_info iwl_dev_info_table[] = { IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY, IWL_CFG_160, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwlax211_2ax_cfg_so_gf_a0, iwl_ax211_name), + _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_SOF, IWL_CFG_ANY, + IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY, + IWL_CFG_160, IWL_CFG_ANY, IWL_CFG_CDB, + iwlax411_2ax_cfg_so_gf4_a0, iwl_ax411_name), /* Bz */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, @@ -1211,6 +1216,11 @@ static const struct iwl_dev_info iwl_dev_info_table[] = { IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY, IWL_CFG_160, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwlax211_2ax_cfg_so_gf_a0, iwl_ax211_name), + _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_SO, IWL_CFG_ANY, + IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY, + IWL_CFG_160, IWL_CFG_ANY, IWL_CFG_CDB, + iwlax411_2ax_cfg_so_gf4_a0, iwl_ax411_name), /* So with JF2 */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, From 7e32281d07c51fe6dd98ccaf36ccb4d4387972ff Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Sat, 4 Dec 2021 13:10:44 +0200 Subject: [PATCH 20/42] iwlwifi: mvm: Fix wrong documentation for scan request command Signed-off-by: Ilan Peer Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20211204130722.26c8bd826c83.Iefc78689607561573d8afbc7c5d3797abfbe875e@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/api/scan.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h index 8b200379f7c2..37197ef3f22c 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h @@ -942,7 +942,7 @@ struct iwl_scan_channel_params_v6 { /** * struct iwl_scan_general_params_v10 - * @flags: &enum iwl_umac_scan_flags + * @flags: &enum iwl_umac_scan_general_flags_v2 * @reserved: reserved for future * @scan_start_mac_id: report the scan start TSF time according to this mac TSF * @active_dwell: dwell time for active scan per LMAC From ba16c04fab0fac9f31bd44b5c575ab771e38847f Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Sat, 4 Dec 2021 13:10:45 +0200 Subject: [PATCH 21/42] iwlwifi: mvm: Add support for a new version of scan request command The scan request command is identical in binary format to the previous scan request command and the only change is now a previously reserved octet is used to indicate new flags introduced in the command. Align the code to support the new version and the previous one. Later patches would add the specific handling for the new flags. Signed-off-by: Ilan Peer Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20211204130722.392a4af559bc.Ib8f1e3b527453531c10bfd7f4b116d3e257c7f1f@changeid Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/fw/api/scan.h | 46 +++++++++++------ drivers/net/wireless/intel/iwlwifi/mvm/scan.c | 51 ++++++++++++------- 2 files changed, 63 insertions(+), 34 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h index 37197ef3f22c..9aa7d0bbd64e 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h @@ -659,6 +659,19 @@ enum iwl_umac_scan_general_flags_v2 { IWL_UMAC_SCAN_GEN_FLAGS_V2_6GHZ_PASSIVE_SCAN_FILTER_IN = BIT(14), }; +/** + * enum iwl_umac_scan_general_params_flags2 - UMAC scan general flags2 + * + * @IWL_UMAC_SCAN_GEN_PARAMS_FLAGS2_RESPECT_P2P_GO_LB: scan event scheduling + * should be aware of a P2P GO operation on the 2GHz band. + * @IWL_UMAC_SCAN_GEN_PARAMS_FLAGS2_RESPECT_P2P_GO_HB: scan event scheduling + * should be aware of a P2P GO operation on the 5GHz or 6GHz band. + */ +enum iwl_umac_scan_general_params_flags2 { + IWL_UMAC_SCAN_GEN_PARAMS_FLAGS2_RESPECT_P2P_GO_LB = BIT(0), + IWL_UMAC_SCAN_GEN_PARAMS_FLAGS2_RESPECT_P2P_GO_HB = BIT(1), +}; + /** * struct iwl_scan_channel_cfg_umac * @flags: bitmap - 0-19: directed scan to i'th ssid. @@ -941,7 +954,7 @@ struct iwl_scan_channel_params_v6 { } __packed; /* SCAN_CHANNEL_PARAMS_API_S_VER_6 */ /** - * struct iwl_scan_general_params_v10 + * struct iwl_scan_general_params_v11 * @flags: &enum iwl_umac_scan_general_flags_v2 * @reserved: reserved for future * @scan_start_mac_id: report the scan start TSF time according to this mac TSF @@ -952,7 +965,8 @@ struct iwl_scan_channel_params_v6 { * for 5GHz channels * @adwell_default_social_chn: adaptive dwell default number of * APs per social channel - * @reserved1: reserved for future + * @flags2: for version 11 see &enum iwl_umac_scan_general_params_flags2. + * Otherwise reserved. * @adwell_max_budget: the maximal number of TUs that adaptive dwell * can add to the total scan time * @max_out_of_time: max out of serving channel time, per LMAC @@ -963,7 +977,7 @@ struct iwl_scan_channel_params_v6 { * @num_of_fragments: number of fragments needed for full fragmented * scan coverage. */ -struct iwl_scan_general_params_v10 { +struct iwl_scan_general_params_v11 { __le16 flags; u8 reserved; u8 scan_start_mac_id; @@ -971,14 +985,14 @@ struct iwl_scan_general_params_v10 { u8 adwell_default_2g; u8 adwell_default_5g; u8 adwell_default_social_chn; - u8 reserved1; + u8 flags2; __le16 adwell_max_budget; __le32 max_out_of_time[SCAN_TWO_LMACS]; __le32 suspend_time[SCAN_TWO_LMACS]; __le32 scan_priority; u8 passive_dwell[SCAN_TWO_LMACS]; u8 num_of_fragments[SCAN_TWO_LMACS]; -} __packed; /* SCAN_GENERAL_PARAMS_API_S_VER_10 */ +} __packed; /* SCAN_GENERAL_PARAMS_API_S_VER_11 and *_VER_10 */ /** * struct iwl_scan_periodic_parms_v1 @@ -994,31 +1008,31 @@ struct iwl_scan_periodic_parms_v1 { /** * struct iwl_scan_req_params_v12 - * @general_params: &struct iwl_scan_general_params_v10 + * @general_params: &struct iwl_scan_general_params_v11 * @channel_params: &struct iwl_scan_channel_params_v4 * @periodic_params: &struct iwl_scan_periodic_parms_v1 * @probe_params: &struct iwl_scan_probe_params_v3 */ struct iwl_scan_req_params_v12 { - struct iwl_scan_general_params_v10 general_params; + struct iwl_scan_general_params_v11 general_params; struct iwl_scan_channel_params_v4 channel_params; struct iwl_scan_periodic_parms_v1 periodic_params; struct iwl_scan_probe_params_v3 probe_params; } __packed; /* SCAN_REQUEST_PARAMS_API_S_VER_12 */ /** - * struct iwl_scan_req_params_v14 - * @general_params: &struct iwl_scan_general_params_v10 + * struct iwl_scan_req_params_v15 + * @general_params: &struct iwl_scan_general_params_v11 * @channel_params: &struct iwl_scan_channel_params_v6 * @periodic_params: &struct iwl_scan_periodic_parms_v1 * @probe_params: &struct iwl_scan_probe_params_v4 */ -struct iwl_scan_req_params_v14 { - struct iwl_scan_general_params_v10 general_params; +struct iwl_scan_req_params_v15 { + struct iwl_scan_general_params_v11 general_params; struct iwl_scan_channel_params_v6 channel_params; struct iwl_scan_periodic_parms_v1 periodic_params; struct iwl_scan_probe_params_v4 probe_params; -} __packed; /* SCAN_REQUEST_PARAMS_API_S_VER_14 */ +} __packed; /* SCAN_REQUEST_PARAMS_API_S_VER_15 and *_VER_14 */ /** * struct iwl_scan_req_umac_v12 @@ -1033,16 +1047,16 @@ struct iwl_scan_req_umac_v12 { } __packed; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_12 */ /** - * struct iwl_scan_req_umac_v14 + * struct iwl_scan_req_umac_v15 * @uid: scan id, &enum iwl_umac_scan_uid_offsets * @ooc_priority: out of channel priority - &enum iwl_scan_priority * @scan_params: scan parameters */ -struct iwl_scan_req_umac_v14 { +struct iwl_scan_req_umac_v15 { __le32 uid; __le32 ooc_priority; - struct iwl_scan_req_params_v14 scan_params; -} __packed; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_14 */ + struct iwl_scan_req_params_v15 scan_params; +} __packed; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_15 and *_VER_14 */ /** * struct iwl_umac_scan_abort diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index a138b5c4cce8..54ec5eb6c763 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -1394,8 +1394,8 @@ static u32 iwl_mvm_scan_umac_ooc_priority(struct iwl_mvm_scan_params *params) } static void -iwl_mvm_scan_umac_dwell_v10(struct iwl_mvm *mvm, - struct iwl_scan_general_params_v10 *general_params, +iwl_mvm_scan_umac_dwell_v11(struct iwl_mvm *mvm, + struct iwl_scan_general_params_v11 *general_params, struct iwl_mvm_scan_params *params) { struct iwl_mvm_scan_timing_params *timing, *hb_timing; @@ -2238,15 +2238,15 @@ static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, } static void -iwl_mvm_scan_umac_fill_general_p_v10(struct iwl_mvm *mvm, +iwl_mvm_scan_umac_fill_general_p_v11(struct iwl_mvm *mvm, struct iwl_mvm_scan_params *params, struct ieee80211_vif *vif, - struct iwl_scan_general_params_v10 *gp, + struct iwl_scan_general_params_v11 *gp, u16 gen_flags) { struct iwl_mvm_vif *scan_vif = iwl_mvm_vif_from_mac80211(vif); - iwl_mvm_scan_umac_dwell_v10(mvm, gp, params); + iwl_mvm_scan_umac_dwell_v11(mvm, gp, params); gp->flags = cpu_to_le16(gen_flags); @@ -2350,7 +2350,7 @@ static int iwl_mvm_scan_umac_v12(struct iwl_mvm *mvm, struct ieee80211_vif *vif, cmd->uid = cpu_to_le32(uid); gen_flags = iwl_mvm_scan_umac_flags_v2(mvm, params, vif, type); - iwl_mvm_scan_umac_fill_general_p_v10(mvm, params, vif, + iwl_mvm_scan_umac_fill_general_p_v11(mvm, params, vif, &scan_p->general_params, gen_flags); @@ -2367,12 +2367,13 @@ static int iwl_mvm_scan_umac_v12(struct iwl_mvm *mvm, struct ieee80211_vif *vif, return 0; } -static int iwl_mvm_scan_umac_v14(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - struct iwl_mvm_scan_params *params, int type, - int uid) +static int iwl_mvm_scan_umac_v14_and_above(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + struct iwl_mvm_scan_params *params, + int type, int uid, u32 version) { - struct iwl_scan_req_umac_v14 *cmd = mvm->scan_cmd; - struct iwl_scan_req_params_v14 *scan_p = &cmd->scan_params; + struct iwl_scan_req_umac_v15 *cmd = mvm->scan_cmd; + struct iwl_scan_req_params_v15 *scan_p = &cmd->scan_params; struct iwl_scan_channel_params_v6 *cp = &scan_p->channel_params; struct iwl_scan_probe_params_v4 *pb = &scan_p->probe_params; int ret; @@ -2385,7 +2386,7 @@ static int iwl_mvm_scan_umac_v14(struct iwl_mvm *mvm, struct ieee80211_vif *vif, cmd->uid = cpu_to_le32(uid); gen_flags = iwl_mvm_scan_umac_flags_v2(mvm, params, vif, type); - iwl_mvm_scan_umac_fill_general_p_v10(mvm, params, vif, + iwl_mvm_scan_umac_fill_general_p_v11(mvm, params, vif, &scan_p->general_params, gen_flags); @@ -2425,6 +2426,20 @@ static int iwl_mvm_scan_umac_v14(struct iwl_mvm *mvm, struct ieee80211_vif *vif, return 0; } +static int iwl_mvm_scan_umac_v14(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + struct iwl_mvm_scan_params *params, int type, + int uid) +{ + return iwl_mvm_scan_umac_v14_and_above(mvm, vif, params, type, uid, 14); +} + +static int iwl_mvm_scan_umac_v15(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + struct iwl_mvm_scan_params *params, int type, + int uid) +{ + return iwl_mvm_scan_umac_v14_and_above(mvm, vif, params, type, uid, 15); +} + static int iwl_mvm_num_scans(struct iwl_mvm *mvm) { return hweight32(mvm->scan_status & IWL_MVM_SCAN_MASK); @@ -2540,6 +2555,7 @@ struct iwl_scan_umac_handler { static const struct iwl_scan_umac_handler iwl_scan_umac_handlers[] = { /* set the newest version first to shorten the list traverse time */ + IWL_SCAN_UMAC_HANDLER(15), IWL_SCAN_UMAC_HANDLER(14), IWL_SCAN_UMAC_HANDLER(12), }; @@ -2940,15 +2956,14 @@ static int iwl_mvm_scan_stop_wait(struct iwl_mvm *mvm, int type) 1 * HZ); } -#define IWL_SCAN_REQ_UMAC_HANDLE_SIZE(_ver) { \ - case (_ver): return sizeof(struct iwl_scan_req_umac_v##_ver); \ -} - static int iwl_scan_req_umac_get_size(u8 scan_ver) { switch (scan_ver) { - IWL_SCAN_REQ_UMAC_HANDLE_SIZE(14); - IWL_SCAN_REQ_UMAC_HANDLE_SIZE(12); + case 12: + return sizeof(struct iwl_scan_req_umac_v12); + case 14: + case 15: + return sizeof(struct iwl_scan_req_umac_v15); } return 0; From 6324c173ff4af5a0974baca09b168d527205bd19 Mon Sep 17 00:00:00 2001 From: Mordechay Goodstein Date: Sat, 4 Dec 2021 13:10:46 +0200 Subject: [PATCH 22/42] iwlwifi: mvm: add support for statistics update version 15 The main changes are remove the respond from STATISTICS_CMD and sending it with STATISTICS_NOTIFICATION, and updating for all mac id's and phy id's in one notification. Signed-off-by: Mordechay Goodstein Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20211204130722.832c7b599202.If192dce8f51ec13005999c3ff96fe09a73cd8f91@changeid Signed-off-by: Luca Coelho --- .../wireless/intel/iwlwifi/fw/api/commands.h | 3 +- .../net/wireless/intel/iwlwifi/fw/api/stats.h | 92 +++++- drivers/net/wireless/intel/iwlwifi/mvm/rx.c | 261 +++++++++++++----- .../net/wireless/intel/iwlwifi/mvm/utils.c | 51 +++- 4 files changed, 335 insertions(+), 72 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h b/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h index 8ce03b08592c..2792fd5d9c9b 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h @@ -357,7 +357,7 @@ enum iwl_legacy_cmds { * &struct iwl_notif_statistics_v11, * &struct iwl_notif_statistics_v10, * &struct iwl_notif_statistics, - * &struct iwl_statistics_operational_ntfy + * &struct iwl_statistics_operational_ntfy_ver_14 */ STATISTICS_CMD = 0x9c, @@ -366,6 +366,7 @@ enum iwl_legacy_cmds { * one of &struct iwl_notif_statistics_v10, * &struct iwl_notif_statistics_v11, * &struct iwl_notif_statistic, + * &struct iwl_statistics_operational_ntfy_ver_14 * &struct iwl_statistics_operational_ntfy */ STATISTICS_NOTIFICATION = 0x9d, diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/stats.h b/drivers/net/wireless/intel/iwlwifi/fw/api/stats.h index 18cca15caa3a..898e62326e6c 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/stats.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/stats.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, 2020 - 2021 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -432,6 +432,7 @@ enum iwl_fw_statistics_type { FW_STATISTICS_HE, }; /* FW_STATISTICS_TYPE_API_E_VER_1 */ +#define IWL_STATISTICS_TYPE_MSK 0x7f /** * struct iwl_statistics_ntfy_hdr * @@ -445,11 +446,98 @@ struct iwl_statistics_ntfy_hdr { __le16 size; }; /* STATISTICS_NTFY_HDR_API_S_VER_1 */ +/** + * struct iwl_statistics_ntfy_per_mac + * + * @beacon_filter_average_energy: Average energy [-dBm] of the 2 + * antennas. + * @air_time: air time + * @beacon_counter: all beacons (both filtered and not filtered) + * @beacon_average_energy: all beacons (both filtered and not + * filtered) + * @beacon_rssi_a: beacon RSSI on antenna A + * @beacon_rssi_b: beacon RSSI on antenna B + * @rx_bytes: RX byte count + */ +struct iwl_statistics_ntfy_per_mac { + __le32 beacon_filter_average_energy; + __le32 air_time; + __le32 beacon_counter; + __le32 beacon_average_energy; + __le32 beacon_rssi_a; + __le32 beacon_rssi_b; + __le32 rx_bytes; +} __packed; /* STATISTICS_NTFY_PER_MAC_API_S_VER_1 */ + +#define IWL_STATS_MAX_BW_INDEX 5 +/** struct iwl_statistics_ntfy_per_phy + * @channel_load: channel load + * @channel_load_by_us: device contribution to MCLM + * @channel_load_not_by_us: other devices' contribution to MCLM + * @clt: CLT HW timer (TIM_CH_LOAD2) + * @act: active accumulator SW + * @elp: elapsed time accumulator SW + * @rx_detected_per_ch_width: number of deferred TX per channel width, + * 0 - 20, 1/2/3 - 40/80/160 + * @success_per_ch_width: number of frames that got ACK/BACK/CTS + * per channel BW. note, BACK counted as 1 + * @fail_per_ch_width: number of frames that didn't get ACK/BACK/CTS + * per channel BW. note BACK counted as 1 + * @last_tx_ch_width_indx: last txed frame channel width index + */ +struct iwl_statistics_ntfy_per_phy { + __le32 channel_load; + __le32 channel_load_by_us; + __le32 channel_load_not_by_us; + __le32 clt; + __le32 act; + __le32 elp; + __le32 rx_detected_per_ch_width[IWL_STATS_MAX_BW_INDEX]; + __le32 success_per_ch_width[IWL_STATS_MAX_BW_INDEX]; + __le32 fail_per_ch_width[IWL_STATS_MAX_BW_INDEX]; + __le32 last_tx_ch_width_indx; +} __packed; /* STATISTICS_NTFY_PER_PHY_API_S_VER_1 */ + +/** + * struct iwl_statistics_ntfy_per_sta + * + * @average_energy: in fact it is minus the energy.. + */ +struct iwl_statistics_ntfy_per_sta { + __le32 average_energy; +} __packed; /* STATISTICS_NTFY_PER_STA_API_S_VER_1 */ + +#define IWL_STATS_MAX_PHY_OPERTINAL 3 /** * struct iwl_statistics_operational_ntfy * * @hdr: general statistics header * @flags: bitmap of possible notification structures + * @per_mac_stats: per mac statistics, &struct iwl_statistics_ntfy_per_mac + * @per_phy_stats: per phy statistics, &struct iwl_statistics_ntfy_per_phy + * @per_sta_stats: per sta statistics, &struct iwl_statistics_ntfy_per_sta + * @rx_time: rx time + * @tx_time: usec the radio is transmitting. + * @on_time_rf: The total time in usec the RF is awake. + * @on_time_scan: usec the radio is awake due to scan. + */ +struct iwl_statistics_operational_ntfy { + struct iwl_statistics_ntfy_hdr hdr; + __le32 flags; + struct iwl_statistics_ntfy_per_mac per_mac_stats[MAC_INDEX_AUX]; + struct iwl_statistics_ntfy_per_phy per_phy_stats[IWL_STATS_MAX_PHY_OPERTINAL]; + struct iwl_statistics_ntfy_per_sta per_sta_stats[IWL_MVM_STATION_COUNT_MAX]; + __le64 rx_time; + __le64 tx_time; + __le64 on_time_rf; + __le64 on_time_scan; +} __packed; /* STATISTICS_OPERATIONAL_NTFY_API_S_VER_15 */ + +/** + * struct iwl_statistics_operational_ntfy_ver_14 + * + * @hdr: general statistics header + * @flags: bitmap of possible notification structures * @mac_id: mac on which the beacon was received * @beacon_filter_average_energy: Average energy [-dBm] of the 2 * antennas. @@ -469,7 +557,7 @@ struct iwl_statistics_ntfy_hdr { * @average_energy: in fact it is minus the energy.. * @reserved: reserved */ -struct iwl_statistics_operational_ntfy { +struct iwl_statistics_operational_ntfy_ver_14 { struct iwl_statistics_ntfy_hdr hdr; __le32 flags; __le32 mac_id; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c index d22f40a5354d..64446a11ef98 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c @@ -527,40 +527,19 @@ struct iwl_mvm_stat_data { u8 *beacon_average_energy; }; -static void iwl_mvm_stat_iterator(void *_data, u8 *mac, - struct ieee80211_vif *vif) +struct iwl_mvm_stat_data_all_macs { + struct iwl_mvm *mvm; + __le32 flags; + struct iwl_statistics_ntfy_per_mac *per_mac_stats; +}; + +static void iwl_mvm_update_vif_sig(struct ieee80211_vif *vif, int sig) { - struct iwl_mvm_stat_data *data = _data; - struct iwl_mvm *mvm = data->mvm; - int sig = -data->beacon_filter_average_energy; - int last_event; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm *mvm = mvmvif->mvm; int thold = vif->bss_conf.cqm_rssi_thold; int hyst = vif->bss_conf.cqm_rssi_hyst; - u16 id = le32_to_cpu(data->mac_id); - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - u16 vif_id = mvmvif->id; - - /* This doesn't need the MAC ID check since it's not taking the - * data copied into the "data" struct, but rather the data from - * the notification directly. - */ - mvmvif->beacon_stats.num_beacons = - le32_to_cpu(data->beacon_counter[vif_id]); - mvmvif->beacon_stats.avg_signal = - -data->beacon_average_energy[vif_id]; - - /* make sure that beacon statistics don't go backwards with TCM - * request to clear statistics - */ - if (le32_to_cpu(data->flags) & IWL_STATISTICS_REPLY_FLG_CLEAR) - mvmvif->beacon_stats.accu_num_beacons += - mvmvif->beacon_stats.num_beacons; - - if (mvmvif->id != id) - return; - - if (vif->type != NL80211_IFTYPE_STATION) - return; + int last_event; if (sig == 0) { IWL_DEBUG_RX(mvm, "RSSI is 0 - skip signal based decision\n"); @@ -618,6 +597,73 @@ static void iwl_mvm_stat_iterator(void *_data, u8 *mac, } } +static void iwl_mvm_stat_iterator(void *_data, u8 *mac, + struct ieee80211_vif *vif) +{ + struct iwl_mvm_stat_data *data = _data; + int sig = -data->beacon_filter_average_energy; + u16 id = le32_to_cpu(data->mac_id); + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + u16 vif_id = mvmvif->id; + + /* This doesn't need the MAC ID check since it's not taking the + * data copied into the "data" struct, but rather the data from + * the notification directly. + */ + mvmvif->beacon_stats.num_beacons = + le32_to_cpu(data->beacon_counter[vif_id]); + mvmvif->beacon_stats.avg_signal = + -data->beacon_average_energy[vif_id]; + + if (mvmvif->id != id) + return; + + if (vif->type != NL80211_IFTYPE_STATION) + return; + + /* make sure that beacon statistics don't go backwards with TCM + * request to clear statistics + */ + if (le32_to_cpu(data->flags) & IWL_STATISTICS_REPLY_FLG_CLEAR) + mvmvif->beacon_stats.accu_num_beacons += + mvmvif->beacon_stats.num_beacons; + + iwl_mvm_update_vif_sig(vif, sig); +} + +static void iwl_mvm_stat_iterator_all_macs(void *_data, u8 *mac, + struct ieee80211_vif *vif) +{ + struct iwl_mvm_stat_data_all_macs *data = _data; + struct iwl_statistics_ntfy_per_mac *mac_stats; + int sig; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + u16 vif_id = mvmvif->id; + + if (WARN_ONCE(vif_id > MAC_INDEX_AUX, "invalid vif id: %d", vif_id)) + return; + + if (vif->type != NL80211_IFTYPE_STATION) + return; + + mac_stats = &data->per_mac_stats[vif_id]; + + mvmvif->beacon_stats.num_beacons = + le32_to_cpu(mac_stats->beacon_counter); + mvmvif->beacon_stats.avg_signal = + -le32_to_cpu(mac_stats->beacon_average_energy); + + /* make sure that beacon statistics don't go backwards with TCM + * request to clear statistics + */ + if (le32_to_cpu(data->flags) & IWL_STATISTICS_REPLY_FLG_CLEAR) + mvmvif->beacon_stats.accu_num_beacons += + mvmvif->beacon_stats.num_beacons; + + sig = -le32_to_cpu(mac_stats->beacon_filter_average_energy); + iwl_mvm_update_vif_sig(vif, sig); +} + static inline void iwl_mvm_rx_stats_check_trigger(struct iwl_mvm *mvm, struct iwl_rx_packet *pkt) { @@ -684,47 +730,41 @@ iwl_mvm_update_tcm_from_stats(struct iwl_mvm *mvm, __le32 *air_time_le, } static void -iwl_mvm_handle_rx_statistics_tlv(struct iwl_mvm *mvm, - struct iwl_rx_packet *pkt) +iwl_mvm_stats_ver_15(struct iwl_mvm *mvm, + struct iwl_statistics_operational_ntfy *stats) +{ + struct iwl_mvm_stat_data_all_macs data = { + .mvm = mvm, + .flags = stats->flags, + .per_mac_stats = stats->per_mac_stats, + }; + + ieee80211_iterate_active_interfaces(mvm->hw, + IEEE80211_IFACE_ITER_NORMAL, + iwl_mvm_stat_iterator_all_macs, + &data); +} + +static void +iwl_mvm_stats_ver_14(struct iwl_mvm *mvm, + struct iwl_statistics_operational_ntfy_ver_14 *stats) { struct iwl_mvm_stat_data data = { .mvm = mvm, }; + u8 beacon_average_energy[MAC_INDEX_AUX]; - u8 average_energy[IWL_MVM_STATION_COUNT_MAX]; - struct iwl_statistics_operational_ntfy *stats; - int expected_size; __le32 flags; int i; - expected_size = sizeof(*stats); - if (WARN_ONCE(iwl_rx_packet_payload_len(pkt) < expected_size, - "received invalid statistics size (%d)!, expected_size: %d\n", - iwl_rx_packet_payload_len(pkt), expected_size)) - return; - - stats = (void *)&pkt->data; - - if (WARN_ONCE(stats->hdr.type != FW_STATISTICS_OPERATIONAL || - stats->hdr.version != - iwl_fw_lookup_notif_ver(mvm->fw, LONG_GROUP, STATISTICS_CMD, 0), - "received unsupported hdr type %d, version %d\n", - stats->hdr.type, stats->hdr.version)) - return; - flags = stats->flags; - mvm->radio_stats.rx_time = le64_to_cpu(stats->rx_time); - mvm->radio_stats.tx_time = le64_to_cpu(stats->tx_time); - mvm->radio_stats.on_time_rf = le64_to_cpu(stats->on_time_rf); - mvm->radio_stats.on_time_scan = le64_to_cpu(stats->on_time_scan); - - iwl_mvm_rx_stats_check_trigger(mvm, pkt); data.mac_id = stats->mac_id; data.beacon_filter_average_energy = le32_to_cpu(stats->beacon_filter_average_energy); data.flags = flags; data.beacon_counter = stats->beacon_counter; + for (i = 0; i < ARRAY_SIZE(beacon_average_energy); i++) beacon_average_energy[i] = le32_to_cpu(stats->beacon_average_energy[i]); @@ -735,9 +775,105 @@ iwl_mvm_handle_rx_statistics_tlv(struct iwl_mvm *mvm, IEEE80211_IFACE_ITER_NORMAL, iwl_mvm_stat_iterator, &data); +} + +static bool iwl_mvm_verify_stats_len(struct iwl_mvm *mvm, + struct iwl_rx_packet *pkt, + u32 expected_size) +{ + struct iwl_statistics_ntfy_hdr *hdr; + + if (WARN_ONCE(iwl_rx_packet_payload_len(pkt) < expected_size, + "received invalid statistics size (%d)!, expected_size: %d\n", + iwl_rx_packet_payload_len(pkt), expected_size)) + return false; + + hdr = (void *)&pkt->data; + + if (WARN_ONCE((hdr->type & IWL_STATISTICS_TYPE_MSK) != FW_STATISTICS_OPERATIONAL || + hdr->version != + iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP, STATISTICS_NOTIFICATION, 0), + "received unsupported hdr type %d, version %d\n", + hdr->type, hdr->version)) + return false; + + if (WARN_ONCE(le16_to_cpu(hdr->size) != expected_size, + "received invalid statistics size in header (%d)!, expected_size: %d\n", + le16_to_cpu(hdr->size), expected_size)) + return false; + + return true; +} + +static void +iwl_mvm_handle_rx_statistics_tlv(struct iwl_mvm *mvm, + struct iwl_rx_packet *pkt) +{ + u8 average_energy[IWL_MVM_STATION_COUNT_MAX]; + __le32 air_time[MAC_INDEX_AUX]; + __le32 rx_bytes[MAC_INDEX_AUX]; + __le32 flags = 0; + int i; + u32 notif_ver = iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP, + STATISTICS_NOTIFICATION, 0); + + if (WARN_ONCE(notif_ver > 15, + "invalid statistics version id: %d\n", notif_ver)) + return; + + if (notif_ver == 14) { + struct iwl_statistics_operational_ntfy_ver_14 *stats = + (void *)pkt->data; + + if (!iwl_mvm_verify_stats_len(mvm, pkt, sizeof(*stats))) + return; + + iwl_mvm_stats_ver_14(mvm, stats); + + flags = stats->flags; + mvm->radio_stats.rx_time = le64_to_cpu(stats->rx_time); + mvm->radio_stats.tx_time = le64_to_cpu(stats->tx_time); + mvm->radio_stats.on_time_rf = le64_to_cpu(stats->on_time_rf); + mvm->radio_stats.on_time_scan = + le64_to_cpu(stats->on_time_scan); + + for (i = 0; i < ARRAY_SIZE(average_energy); i++) + average_energy[i] = le32_to_cpu(stats->average_energy[i]); + + for (i = 0; i < ARRAY_SIZE(air_time); i++) { + air_time[i] = stats->air_time[i]; + rx_bytes[i] = stats->rx_bytes[i]; + } + } + + if (notif_ver == 15) { + struct iwl_statistics_operational_ntfy *stats = + (void *)pkt->data; + + if (!iwl_mvm_verify_stats_len(mvm, pkt, sizeof(*stats))) + return; + + iwl_mvm_stats_ver_15(mvm, stats); + + flags = stats->flags; + mvm->radio_stats.rx_time = le64_to_cpu(stats->rx_time); + mvm->radio_stats.tx_time = le64_to_cpu(stats->tx_time); + mvm->radio_stats.on_time_rf = le64_to_cpu(stats->on_time_rf); + mvm->radio_stats.on_time_scan = + le64_to_cpu(stats->on_time_scan); + + for (i = 0; i < ARRAY_SIZE(average_energy); i++) + average_energy[i] = + le32_to_cpu(stats->per_sta_stats[i].average_energy); + + for (i = 0; i < ARRAY_SIZE(air_time); i++) { + air_time[i] = stats->per_mac_stats[i].air_time; + rx_bytes[i] = stats->per_mac_stats[i].rx_bytes; + } + } + + iwl_mvm_rx_stats_check_trigger(mvm, pkt); - for (i = 0; i < ARRAY_SIZE(average_energy); i++) - average_energy[i] = le32_to_cpu(stats->average_energy[i]); ieee80211_iterate_stations_atomic(mvm->hw, iwl_mvm_stats_energy_iter, average_energy); /* @@ -746,8 +882,7 @@ iwl_mvm_handle_rx_statistics_tlv(struct iwl_mvm *mvm, * request and once in statistics notification. */ if (le32_to_cpu(flags) & IWL_STATISTICS_REPLY_FLG_CLEAR) - iwl_mvm_update_tcm_from_stats(mvm, stats->air_time, - stats->rx_bytes); + iwl_mvm_update_tcm_from_stats(mvm, air_time, rx_bytes); } void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm, @@ -761,8 +896,8 @@ void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm, u8 *energy; /* From ver 14 and up we use TLV statistics format */ - if (iwl_fw_lookup_notif_ver(mvm->fw, LONG_GROUP, - STATISTICS_CMD, 0) >= 14) + if (iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP, + STATISTICS_NOTIFICATION, 0) >= 14) return iwl_mvm_handle_rx_statistics_tlv(mvm, pkt); if (!iwl_mvm_has_new_rx_stats_api(mvm)) { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index caf1dcf48888..1f3e90e5dbd4 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -340,25 +340,64 @@ void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif, ieee80211_request_smps(vif, smps_mode); } +static bool iwl_wait_stats_complete(struct iwl_notif_wait_data *notif_wait, + struct iwl_rx_packet *pkt, void *data) +{ + WARN_ON(pkt->hdr.cmd != STATISTICS_NOTIFICATION); + + return true; +} + int iwl_mvm_request_statistics(struct iwl_mvm *mvm, bool clear) { struct iwl_statistics_cmd scmd = { .flags = clear ? cpu_to_le32(IWL_STATISTICS_FLG_CLEAR) : 0, }; + struct iwl_host_cmd cmd = { .id = STATISTICS_CMD, .len[0] = sizeof(scmd), .data[0] = &scmd, - .flags = CMD_WANT_SKB, }; int ret; - ret = iwl_mvm_send_cmd(mvm, &cmd); - if (ret) - return ret; + /* From version 15 - STATISTICS_NOTIFICATION, the reply for + * STATISTICS_CMD is empty, and the response is with + * STATISTICS_NOTIFICATION notification + */ + if (iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP, + STATISTICS_NOTIFICATION, 0) < 15) { + cmd.flags = CMD_WANT_SKB; - iwl_mvm_handle_rx_statistics(mvm, cmd.resp_pkt); - iwl_free_resp(&cmd); + ret = iwl_mvm_send_cmd(mvm, &cmd); + if (ret) + return ret; + + iwl_mvm_handle_rx_statistics(mvm, cmd.resp_pkt); + iwl_free_resp(&cmd); + } else { + struct iwl_notification_wait stats_wait; + static const u16 stats_complete[] = { + STATISTICS_NOTIFICATION, + }; + + iwl_init_notification_wait(&mvm->notif_wait, &stats_wait, + stats_complete, ARRAY_SIZE(stats_complete), + iwl_wait_stats_complete, NULL); + + ret = iwl_mvm_send_cmd(mvm, &cmd); + if (ret) { + iwl_remove_notification(&mvm->notif_wait, &stats_wait); + return ret; + } + + /* 200ms should be enough for FW to collect data from all + * LMACs and send STATISTICS_NOTIFICATION to host + */ + ret = iwl_wait_notification(&mvm->notif_wait, &stats_wait, HZ / 5); + if (ret) + return ret; + } if (clear) iwl_mvm_accu_radio_stats(mvm); From 8e967c137df3b236d2075f9538cb888129425d1a Mon Sep 17 00:00:00 2001 From: Shaul Triebitz Date: Sat, 4 Dec 2021 13:10:47 +0200 Subject: [PATCH 23/42] iwlwifi: mvm: avoid clearing a just saved session protection id When scheduling a session protection the id is saved but then it may be cleared when calling iwl_mvm_te_clear_data (if a previous session protection is currently active). Fix it by saving the id after calling iwl_mvm_te_clear_data. Signed-off-by: Shaul Triebitz Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20211204130722.b0743a588d14.I098fef6677d0dab3ef1b6183ed206a10bab01eb2@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/time-event.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c index e91f8e889df7..e6813317edf3 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c @@ -1158,15 +1158,10 @@ void iwl_mvm_schedule_session_protection(struct iwl_mvm *mvm, cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color)), .action = cpu_to_le32(FW_CTXT_ACTION_ADD), + .conf_id = cpu_to_le32(SESSION_PROTECT_CONF_ASSOC), .duration_tu = cpu_to_le32(MSEC_TO_TU(duration)), }; - /* The time_event_data.id field is reused to save session - * protection's configuration. - */ - mvmvif->time_event_data.id = SESSION_PROTECT_CONF_ASSOC; - cmd.conf_id = cpu_to_le32(mvmvif->time_event_data.id); - lockdep_assert_held(&mvm->mutex); spin_lock_bh(&mvm->time_event_lock); @@ -1180,6 +1175,11 @@ void iwl_mvm_schedule_session_protection(struct iwl_mvm *mvm, } iwl_mvm_te_clear_data(mvm, te_data); + /* + * The time_event_data.id field is reused to save session + * protection's configuration. + */ + te_data->id = le32_to_cpu(cmd.conf_id); te_data->duration = le32_to_cpu(cmd.duration_tu); te_data->vif = vif; spin_unlock_bh(&mvm->time_event_lock); From d9e95e35289ff2054c72ca691345bf2c404301be Mon Sep 17 00:00:00 2001 From: Mordechay Goodstein Date: Sat, 4 Dec 2021 13:10:48 +0200 Subject: [PATCH 24/42] iwlwifi: mvm: update rate scale in moving back to assoc state In assoc state we only use narrow bandwidth, due to phy/radio not configured to max bandwidth. Signed-off-by: Mordechay Goodstein Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20211204130722.139d74d2b063.I4cfbb594c110ea9b250e2306c30601f847db2c1a@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 5 +++++ drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c | 8 ++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 4344f5d94b09..82f7c98ea3bf 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -3383,6 +3383,11 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, true); } else if (old_state == IEEE80211_STA_AUTHORIZED && new_state == IEEE80211_STA_ASSOC) { + /* once we move into assoc state, need to update rate scale to + * disable using wide bandwidth + */ + iwl_mvm_rs_rate_init(mvm, sta, mvmvif->phy_ctxt->channel->band, + false); if (!sta->tdls) { /* Multicast data frames are no longer allowed */ iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c index 958702403a45..970b92fd7042 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c @@ -291,8 +291,12 @@ void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm, notif = (void *)pkt->data; sta = rcu_dereference(mvm->fw_id_to_mac_id[notif->sta_id]); if (IS_ERR_OR_NULL(sta)) { - IWL_ERR(mvm, "Invalid sta id (%d) in FW TLC notification\n", - notif->sta_id); + /* can happen in remove station flow where mvm removed internally + * the station before removing from FW + */ + IWL_DEBUG_RATE(mvm, + "Invalid mvm RCU pointer for sta id (%d) in TLC notification\n", + notif->sta_id); goto out; } From 020cde4750c5b20be309e028dec9950520384c1e Mon Sep 17 00:00:00 2001 From: Mukesh Sisodiya Date: Sat, 4 Dec 2021 13:10:49 +0200 Subject: [PATCH 25/42] iwlwifi: yoyo: support for DBGC4 for dram Add DBGC4 memory for debug handling in driver which will be created, freed and collected from the FW in case of crash. Signed-off-by: Mukesh Sisodiya Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20211204130722.488268ffb2a6.I4fd9ee9dc43d04953a640e19ecac7575ad34fe94@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h | 2 ++ 1 file changed, 2 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 3988f5fea33a..b37392719398 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h @@ -306,6 +306,7 @@ enum iwl_fw_ini_config_set_type { * @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_DBGC4: allocation meant for DBGC4 configuration * @IWL_FW_INI_ALLOCATION_NUM: number of allocation ids */ enum iwl_fw_ini_allocation_id { @@ -313,6 +314,7 @@ 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_DBGC4, IWL_FW_INI_ALLOCATION_NUM, }; /* FW_DEBUG_TLV_ALLOCATION_ID_E_VER_1 */ From dc276ffd0754e94080565c10b964f3c211879fdd Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Sat, 4 Dec 2021 13:10:50 +0200 Subject: [PATCH 26/42] iwlwifi: acpi: fix wgds rev 3 size The exact size of WGDS revision 3 was calculated using the wrong parameters. Fix it. Signed-off-by: Miri Korenblit Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20211204130722.12c5b0cffe52.I7f342502f628f43a7e000189a699484bcef0f562@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index bf431fa4fe81..2e4590876bc3 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -789,7 +789,7 @@ int iwl_sar_get_wgds_table(struct iwl_fw_runtime *fwrt) * looking up in ACPI */ if (wifi_pkg->package.count != - min_size + profile_size * num_profiles) { + hdr_size + profile_size * num_profiles) { ret = -EINVAL; goto out_free; } From e5178014f9e20dea4361839f4d9342bb442dc410 Mon Sep 17 00:00:00 2001 From: Yaara Baruch Date: Sat, 4 Dec 2021 13:10:51 +0200 Subject: [PATCH 27/42] iwlwifi: swap 1650i and 1650s killer struct names The names of the killer 1650i and 1650s devices weren't aligned. This patch swap the names in the structs. Signed-off-by: Yaara Baruch Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20211204130722.4e992a115f14.Icacedcc06f33e5457f650290e7deea22bf1ca12d@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/cfg/22000.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c index 0467c1e9eeb3..2a2f236a7de5 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c @@ -629,7 +629,7 @@ const struct iwl_cfg iwl_ax200_cfg_cc = { }; const struct iwl_cfg killer1650s_2ax_cfg_qu_b0_hr_b0 = { - .name = "Killer(R) Wi-Fi 6 AX1650i 160MHz Wireless Network Adapter (201NGW)", + .name = "Killer(R) Wi-Fi 6 AX1650s 160MHz Wireless Network Adapter (201NGW)", .fw_name_pre = IWL_QU_B_HR_B_FW_PRE, IWL_DEVICE_22500, /* @@ -642,7 +642,7 @@ const struct iwl_cfg killer1650s_2ax_cfg_qu_b0_hr_b0 = { }; const struct iwl_cfg killer1650i_2ax_cfg_qu_b0_hr_b0 = { - .name = "Killer(R) Wi-Fi 6 AX1650s 160MHz Wireless Network Adapter (201D2W)", + .name = "Killer(R) Wi-Fi 6 AX1650i 160MHz Wireless Network Adapter (201D2W)", .fw_name_pre = IWL_QU_B_HR_B_FW_PRE, IWL_DEVICE_22500, /* @@ -655,7 +655,7 @@ const struct iwl_cfg killer1650i_2ax_cfg_qu_b0_hr_b0 = { }; const struct iwl_cfg killer1650s_2ax_cfg_qu_c0_hr_b0 = { - .name = "Killer(R) Wi-Fi 6 AX1650i 160MHz Wireless Network Adapter (201NGW)", + .name = "Killer(R) Wi-Fi 6 AX1650s 160MHz Wireless Network Adapter (201NGW)", .fw_name_pre = IWL_QU_C_HR_B_FW_PRE, IWL_DEVICE_22500, /* @@ -668,7 +668,7 @@ const struct iwl_cfg killer1650s_2ax_cfg_qu_c0_hr_b0 = { }; const struct iwl_cfg killer1650i_2ax_cfg_qu_c0_hr_b0 = { - .name = "Killer(R) Wi-Fi 6 AX1650s 160MHz Wireless Network Adapter (201D2W)", + .name = "Killer(R) Wi-Fi 6 AX1650i 160MHz Wireless Network Adapter (201D2W)", .fw_name_pre = IWL_QU_C_HR_B_FW_PRE, IWL_DEVICE_22500, /* From 62ed5d905b70c6508b33bc9470cb5db001460a03 Mon Sep 17 00:00:00 2001 From: Mordechay Goodstein Date: Sat, 4 Dec 2021 13:10:52 +0200 Subject: [PATCH 28/42] iwlwifi: fw: add support for splitting region type bits In next region tlv (3) region type is going to be split into bit mask without affecting the ops for handling region type, so we just mask the type independent of the version due to all versions having the same bits usage. Signed-off-by: Mordechay Goodstein Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20211204130722.083e4b47055e.If7483d854e3d07f81236d314b8155cd5996f306c@changeid Signed-off-by: Luca Coelho --- .../wireless/intel/iwlwifi/fw/api/dbg-tlv.h | 8 +++++++- drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 14 +++++++++----- .../net/wireless/intel/iwlwifi/fw/error-dump.h | 18 ++++++++++++++++++ .../net/wireless/intel/iwlwifi/iwl-dbg-tlv.c | 10 +++++----- 4 files changed, 39 insertions(+), 11 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 b37392719398..1c302cdbde5a 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h @@ -124,6 +124,9 @@ struct iwl_fw_ini_region_internal_buffer { * @hdr: debug header * @id: region id. Max id is &IWL_FW_INI_MAX_REGION_ID * @type: region type. One of &enum iwl_fw_ini_region_type + * @sub_type: region sub type + * @sub_type_ver: region sub type + * @reserved: not in use * @name: region name * @dev_addr: device address configuration. Used by * &IWL_FW_INI_REGION_DEVICE_MEMORY, &IWL_FW_INI_REGION_PERIPHERY_MAC, @@ -146,7 +149,10 @@ struct iwl_fw_ini_region_internal_buffer { struct iwl_fw_ini_region_tlv { struct iwl_fw_ini_header hdr; __le32 id; - __le32 type; + u8 type; + u8 sub_type; + u8 sub_type_ver; + u8 reserved; u8 name[IWL_FW_INI_MAX_NAME]; union { struct iwl_fw_ini_region_dev_addr dev_addr; diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index c8a08bdfefa4..fa3a7a3c3a61 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -1988,17 +1988,18 @@ static u32 iwl_dump_ini_mem(struct iwl_fw_runtime *fwrt, struct list_head *list, { struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data; struct iwl_fw_ini_dump_entry *entry; - struct iwl_fw_error_dump_data *tlv; + struct iwl_fw_ini_error_dump_data *tlv; struct iwl_fw_ini_error_dump_header *header; - u32 type = le32_to_cpu(reg->type), id = le32_to_cpu(reg->id); + u32 type = reg->type; + u32 id = le32_to_cpu(reg->id); u32 num_of_ranges, i, size; void *range; /* - * The higher part of the ID in version 2 is irrelevant for + * The higher part of the ID from 2 is irrelevant for * us, so mask it out. */ - if (le32_to_cpu(reg->hdr.version) == 2) + if (le32_to_cpu(reg->hdr.version) >= 2) id &= IWL_FW_INI_REGION_V2_MASK; if (!ops->get_num_of_ranges || !ops->get_size || !ops->fill_mem_hdr || @@ -2017,6 +2018,9 @@ static u32 iwl_dump_ini_mem(struct iwl_fw_runtime *fwrt, struct list_head *list, tlv = (void *)entry->data; tlv->type = reg->type; + tlv->sub_type = reg->sub_type; + tlv->sub_type_ver = reg->sub_type_ver; + tlv->reserved = reg->reserved; tlv->len = cpu_to_le32(size); IWL_DEBUG_FW(fwrt, "WRT: Collecting region: id=%d, type=%d\n", id, @@ -2291,7 +2295,7 @@ static u32 iwl_dump_ini_trigger(struct iwl_fw_runtime *fwrt, } reg = (void *)reg_data.reg_tlv->data; - reg_type = le32_to_cpu(reg->type); + reg_type = reg->type; if (reg_type >= ARRAY_SIZE(iwl_dump_ini_region_ops)) continue; diff --git a/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h b/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h index 9036b32ec765..079fa0023bd8 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h @@ -231,6 +231,24 @@ struct iwl_fw_error_dump_mem { /* Use bit 31 as dump info type to avoid colliding with region types */ #define IWL_INI_DUMP_INFO_TYPE BIT(31) +/** + * struct iwl_fw_error_dump_data - data for one type + * @type: &enum iwl_fw_ini_region_type + * @sub_type: sub type id + * @sub_type_ver: sub type version + * @reserved: not in use + * @len: the length starting from %data + * @data: the data itself + */ +struct iwl_fw_ini_error_dump_data { + u8 type; + u8 sub_type; + u8 sub_type_ver; + u8 reserved; + __le32 len; + __u8 data[]; +} __packed; + /** * struct iwl_fw_ini_dump_entry * @list: list of dump entries diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c index 7ab98b419cc1..49526fdcf9d2 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c @@ -59,7 +59,7 @@ dbg_ver_table[IWL_DBG_TLV_TYPE_NUM] = { [IWL_DBG_TLV_TYPE_DEBUG_INFO] = {.min_ver = 1, .max_ver = 1,}, [IWL_DBG_TLV_TYPE_BUF_ALLOC] = {.min_ver = 1, .max_ver = 1,}, [IWL_DBG_TLV_TYPE_HCMD] = {.min_ver = 1, .max_ver = 1,}, - [IWL_DBG_TLV_TYPE_REGION] = {.min_ver = 1, .max_ver = 2,}, + [IWL_DBG_TLV_TYPE_REGION] = {.min_ver = 1, .max_ver = 3,}, [IWL_DBG_TLV_TYPE_TRIGGER] = {.min_ver = 1, .max_ver = 1,}, [IWL_DBG_TLV_TYPE_CONF_SET] = {.min_ver = 1, .max_ver = 1,}, }; @@ -177,14 +177,14 @@ static int iwl_dbg_tlv_alloc_region(struct iwl_trans *trans, const struct iwl_fw_ini_region_tlv *reg = (const void *)tlv->data; struct iwl_ucode_tlv **active_reg; u32 id = le32_to_cpu(reg->id); - u32 type = le32_to_cpu(reg->type); + u8 type = reg->type; u32 tlv_len = sizeof(*tlv) + le32_to_cpu(tlv->length); /* - * The higher part of the ID in version 2 is irrelevant for + * The higher part of the ID in from version 2 is irrelevant for * us, so mask it out. */ - if (le32_to_cpu(reg->hdr.version) == 2) + if (le32_to_cpu(reg->hdr.version) >= 2) id &= IWL_FW_INI_REGION_V2_MASK; if (le32_to_cpu(tlv->length) < sizeof(*reg)) @@ -1244,7 +1244,7 @@ static void iwl_dbg_tlv_init_cfg(struct iwl_fw_runtime *fwrt) } reg = (void *)(*active_reg)->data; - reg_type = le32_to_cpu(reg->type); + reg_type = reg->type; if (reg_type != IWL_FW_INI_REGION_DRAM_BUFFER || !(BIT(le32_to_cpu(reg->dram_alloc_id)) & failed_alloc)) From 1e8b7f43774aa15b95d93923a032b0fee1ed1964 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 4 Dec 2021 13:10:53 +0200 Subject: [PATCH 29/42] iwlwifi: mvm: add some missing command strings Some command strings in the system group weren't added for debug, add them now. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20211204130722.5bbda292908e.I53cefd74547a745fd29261a795c94611e7ee8d1d@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index baa1d8c597fa..9e53769b800a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -498,6 +498,8 @@ static const struct iwl_hcmd_names iwl_mvm_system_names[] = { HCMD_NAME(SHARED_MEM_CFG_CMD), HCMD_NAME(INIT_EXTENDED_CFG_CMD), HCMD_NAME(FW_ERROR_RECOVERY_CMD), + HCMD_NAME(RFI_CONFIG_CMD), + HCMD_NAME(RFI_GET_FREQ_TABLE_CMD), }; /* Please keep this array *SORTED* by hex value. From a2263adab8bf722b5a4c981d8fc1b7c821820240 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Sat, 4 Dec 2021 17:49:33 +0200 Subject: [PATCH 30/42] iwlwifi: bump FW API to 68 for AX devices Start supporting API version 68 for AX devices. Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20211204174545.695e3db16cf5.Ie94a3ad1c7a300cff7ecde26a732779159ec919e@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 2a2f236a7de5..c9ccbbe3b92d 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 67 +#define IWL_22000_UCODE_API_MAX 68 /* Lowest firmware API version supported */ #define IWL_22000_UCODE_API_MIN 39 From e93d4aaf4b13963bdd50d11e154ecc251cba4ac7 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 4 Dec 2021 17:49:34 +0200 Subject: [PATCH 31/42] iwlwifi: mvm/api: define system control command The firmware is exposing a new system features control command, define the necessary data structures etc. Rename "soc.h" to "system.h" since the SoC command is also in the system group and adding another file for just one more struct seemed like a waste of files. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20211204174545.94a120687887.I79acffcf0793ea9e4ddec24b06420961bfb4fe94@changeid Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/fw/api/commands.h | 5 +++++ .../intel/iwlwifi/fw/api/{soc.h => system.h} | 16 ++++++++++++---- drivers/net/wireless/intel/iwlwifi/fw/init.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 1 + 5 files changed, 20 insertions(+), 6 deletions(-) rename drivers/net/wireless/intel/iwlwifi/fw/api/{soc.h => system.h} (70%) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h b/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h index 2792fd5d9c9b..dab02a6a2622 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h @@ -614,6 +614,11 @@ enum iwl_system_subcmd_ids { * @RFI_GET_FREQ_TABLE_CMD: &struct iwl_rfi_config_cmd */ RFI_GET_FREQ_TABLE_CMD = 0xc, + + /** + * @SYSTEM_FEATURES_CONTROL_CMD: &struct iwl_system_features_control_cmd + */ + SYSTEM_FEATURES_CONTROL_CMD = 0xd, }; #endif /* __iwl_fw_api_commands_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/soc.h b/drivers/net/wireless/intel/iwlwifi/fw/api/system.h similarity index 70% rename from drivers/net/wireless/intel/iwlwifi/fw/api/soc.h rename to drivers/net/wireless/intel/iwlwifi/fw/api/system.h index c5df1171462b..acf5d4b9a214 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/soc.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/system.h @@ -1,11 +1,11 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2012-2014, 2019-2020 Intel Corporation + * Copyright (C) 2012-2014, 2019-2021 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ -#ifndef __iwl_fw_api_soc_h__ -#define __iwl_fw_api_soc_h__ +#ifndef __iwl_fw_api_system_h__ +#define __iwl_fw_api_system_h__ #define SOC_CONFIG_CMD_FLAGS_DISCRETE BIT(0) #define SOC_CONFIG_CMD_FLAGS_LOW_LATENCY BIT(1) @@ -32,4 +32,12 @@ struct iwl_soc_configuration_cmd { * SOC_CONFIGURATION_CMD_S_VER_2 */ -#endif /* __iwl_fw_api_soc_h__ */ +/** + * struct iwl_system_features_control_cmd - system features control command + * @features: bitmap of features to disable + */ +struct iwl_system_features_control_cmd { + __le32 features[4]; +} __packed; /* SYSTEM_FEATURES_CONTROL_CMD_API_S_VER_1 */ + +#endif /* __iwl_fw_api_system_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/init.c b/drivers/net/wireless/intel/iwlwifi/fw/init.c index 566957ac4539..139ece879fab 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/init.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/init.c @@ -8,7 +8,7 @@ #include "dbg.h" #include "debugfs.h" -#include "fw/api/soc.h" +#include "fw/api/system.h" #include "fw/api/commands.h" #include "fw/api/rx.h" #include "fw/api/datapath.h" diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h index 73a82f07dc59..083f86fa5017 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h @@ -15,7 +15,7 @@ #include "fw/api/datapath.h" #include "fw/api/phy.h" #include "fw/api/config.h" -#include "fw/api/soc.h" +#include "fw/api/system.h" #include "fw/api/alive.h" #include "fw/api/binding.h" #include "fw/api/cmdhdr.h" diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 9e53769b800a..8056018600ad 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -500,6 +500,7 @@ static const struct iwl_hcmd_names iwl_mvm_system_names[] = { HCMD_NAME(FW_ERROR_RECOVERY_CMD), HCMD_NAME(RFI_CONFIG_CMD), HCMD_NAME(RFI_GET_FREQ_TABLE_CMD), + HCMD_NAME(SYSTEM_FEATURES_CONTROL_CMD), }; /* Please keep this array *SORTED* by hex value. From b780c10f1f8c504264dfb7da3c735ce80c586a6b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 4 Dec 2021 17:49:35 +0200 Subject: [PATCH 32/42] iwlwifi: mvm: always use 4K RB size by default When we use 2K RBs, we cannot receive all valid 802.11 frames, including e.g. long beacons, since up to 2304 bytes are valid (plus metadata and also encryption overhead etc.). Increase the RB size to be always 4K to avoid that. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20211204174545.675781ab0da5.I5c653f4c7dd726f8ad40077e4a109b85e7c0cdb1@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 8056018600ad..9c0872b106b6 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -1055,7 +1055,6 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, }; int scan_size; u32 min_backoff; - enum iwl_amsdu_size rb_size_default; struct iwl_mvm_csme_conn_info *csme_conn_info __maybe_unused; /* @@ -1198,14 +1197,9 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, trans_cfg.no_reclaim_cmds = no_reclaim_cmds; trans_cfg.n_no_reclaim_cmds = ARRAY_SIZE(no_reclaim_cmds); - if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) - rb_size_default = IWL_AMSDU_2K; - else - rb_size_default = IWL_AMSDU_4K; - switch (iwlwifi_mod_params.amsdu_size) { case IWL_AMSDU_DEF: - trans_cfg.rx_buf_size = rb_size_default; + trans_cfg.rx_buf_size = IWL_AMSDU_4K; break; case IWL_AMSDU_4K: trans_cfg.rx_buf_size = IWL_AMSDU_4K; @@ -1219,7 +1213,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, default: pr_err("%s: Unsupported amsdu_size: %d\n", KBUILD_MODNAME, iwlwifi_mod_params.amsdu_size); - trans_cfg.rx_buf_size = rb_size_default; + trans_cfg.rx_buf_size = IWL_AMSDU_4K; } trans->wide_cmd_header = true; From 15bf5ac6cd93b655ef82c6bb837cb3c19bce7f36 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 4 Dec 2021 17:49:36 +0200 Subject: [PATCH 33/42] iwlwifi: pcie: retake ownership after reset In most cases, unless shutting down the NIC, we really need to retake ownership after doing a software reset of the NIC. Encode that into the API so we "automatically" do it, even in case of workarounds, and don't keep forgetting it like a few of the places we have did. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20211204174545.458f9d98ac21.I40b9a22df1ab8178cc838fc83d5190e689dfac6a@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/dump.c | 4 ++- .../net/wireless/intel/iwlwifi/iwl-trans.h | 8 +++-- .../wireless/intel/iwlwifi/pcie/trans-gen2.c | 8 ++--- .../net/wireless/intel/iwlwifi/pcie/trans.c | 35 ++++++++++++------- 4 files changed, 33 insertions(+), 22 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dump.c b/drivers/net/wireless/intel/iwlwifi/fw/dump.c index 016b3a4c5f51..358fc2d999d5 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dump.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dump.c @@ -212,7 +212,9 @@ static void iwl_fwrt_dump_lmac_error_log(struct iwl_fw_runtime *fwrt, u8 lmac_nu IWL_ERR(trans, "HW error, resetting before reading\n"); /* reset the device */ - iwl_trans_sw_reset(trans); + err = iwl_trans_sw_reset(trans, true); + if (err) + return; err = iwl_finish_nic_init(trans); if (err) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index 947ed82b7f19..9dea8f9bbcae 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -593,7 +593,7 @@ struct iwl_trans_ops { void (*configure)(struct iwl_trans *trans, const struct iwl_trans_config *trans_cfg); void (*set_pmi)(struct iwl_trans *trans, bool state); - void (*sw_reset)(struct iwl_trans *trans); + int (*sw_reset)(struct iwl_trans *trans, bool retake_ownership); bool (*grab_nic_access)(struct iwl_trans *trans); void (*release_nic_access)(struct iwl_trans *trans); void (*set_bits_mask)(struct iwl_trans *trans, u32 reg, u32 mask, @@ -1386,10 +1386,12 @@ static inline void iwl_trans_set_pmi(struct iwl_trans *trans, bool state) trans->ops->set_pmi(trans, state); } -static inline void iwl_trans_sw_reset(struct iwl_trans *trans) +static inline int iwl_trans_sw_reset(struct iwl_trans *trans, + bool retake_ownership) { if (trans->ops->sw_reset) - trans->ops->sw_reset(trans); + return trans->ops->sw_reset(trans, retake_ownership); + return 0; } static inline void diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c index 645cb4dd4e5a..72b5b69bfe5e 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c @@ -81,7 +81,7 @@ static void iwl_pcie_gen2_apm_stop(struct iwl_trans *trans, bool op_mode_leave) /* Stop device's DMA activity */ iwl_pcie_apm_stop_master(trans); - iwl_trans_sw_reset(trans); + iwl_trans_sw_reset(trans, false); /* * Clear "initialization complete" bit to move adapter from @@ -166,7 +166,8 @@ void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans) /* Stop the device, and put it in low power state */ iwl_pcie_gen2_apm_stop(trans, false); - iwl_trans_sw_reset(trans); + /* re-take ownership to prevent other users from stealing the device */ + iwl_trans_sw_reset(trans, true); /* * Upon stop, the IVAR table gets erased, so msi-x won't @@ -196,9 +197,6 @@ void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans) * interrupt */ iwl_enable_rfkill_int(trans); - - /* re-take ownership to prevent other users from stealing the device */ - iwl_pcie_prepare_card_hw(trans); } void iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 0aeab8acc247..a63386a01232 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -127,7 +127,8 @@ out: kfree(buf); } -static void iwl_trans_pcie_sw_reset(struct iwl_trans *trans) +static int iwl_trans_pcie_sw_reset(struct iwl_trans *trans, + bool retake_ownership) { /* Reset entire device - do controller reset (results in SHRD_HW_RST) */ if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) @@ -137,6 +138,11 @@ static void iwl_trans_pcie_sw_reset(struct iwl_trans *trans) iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); usleep_range(5000, 6000); + + if (retake_ownership) + return iwl_pcie_prepare_card_hw(trans); + + return 0; } static void iwl_pcie_free_fw_monitor(struct iwl_trans *trans) @@ -382,9 +388,11 @@ static void iwl_pcie_apm_lp_xtal_enable(struct iwl_trans *trans) __iwl_trans_pcie_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_XTAL_ON); - iwl_trans_pcie_sw_reset(trans); + ret = iwl_trans_pcie_sw_reset(trans, true); + + if (!ret) + ret = iwl_finish_nic_init(trans); - ret = iwl_finish_nic_init(trans); if (WARN_ON(ret)) { /* Release XTAL ON request */ __iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL, @@ -409,7 +417,10 @@ static void iwl_pcie_apm_lp_xtal_enable(struct iwl_trans *trans) apmg_xtal_cfg_reg | SHR_APMG_XTAL_CFG_XTAL_ON_REQ); - iwl_trans_pcie_sw_reset(trans); + ret = iwl_trans_pcie_sw_reset(trans, true); + if (ret) + IWL_ERR(trans, + "iwl_pcie_apm_lp_xtal_enable: failed to retake NIC ownership\n"); /* Enable LP XTAL by indirect access through CSR */ apmg_gp1_reg = iwl_trans_pcie_read_shr(trans, SHR_APMG_GP1_REG); @@ -515,7 +526,7 @@ static void iwl_pcie_apm_stop(struct iwl_trans *trans, bool op_mode_leave) return; } - iwl_trans_pcie_sw_reset(trans); + iwl_trans_pcie_sw_reset(trans, false); /* * Clear "initialization complete" bit to move adapter from @@ -1261,7 +1272,8 @@ static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans) /* Stop the device, and put it in low power state */ iwl_pcie_apm_stop(trans, false); - iwl_trans_pcie_sw_reset(trans); + /* re-take ownership to prevent other users from stealing the device */ + iwl_trans_pcie_sw_reset(trans, true); /* * Upon stop, the IVAR table gets erased, so msi-x won't @@ -1291,9 +1303,6 @@ static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans) * interrupt */ iwl_enable_rfkill_int(trans); - - /* re-take ownership to prevent other users from stealing the device */ - iwl_pcie_prepare_card_hw(trans); } void iwl_pcie_synchronize_irqs(struct iwl_trans *trans) @@ -1802,9 +1811,7 @@ static int iwl_pcie_gen2_force_power_gating(struct iwl_trans *trans) iwl_clear_bits_prph(trans, HPM_HIPM_GEN_CFG, HPM_HIPM_GEN_CFG_CR_FORCE_ACTIVE); - iwl_trans_pcie_sw_reset(trans); - - return 0; + return iwl_trans_pcie_sw_reset(trans, true); } static int _iwl_trans_pcie_start_hw(struct iwl_trans *trans) @@ -1824,7 +1831,9 @@ static int _iwl_trans_pcie_start_hw(struct iwl_trans *trans) if (err) return err; - iwl_trans_pcie_sw_reset(trans); + err = iwl_trans_pcie_sw_reset(trans, true); + if (err) + return err; if (trans->trans_cfg->device_family == IWL_DEVICE_FAMILY_22000 && trans->trans_cfg->integrated) { From c593d2fae592aefaec86f012e1354400b8ac4715 Mon Sep 17 00:00:00 2001 From: Ayala Barazani Date: Sat, 4 Dec 2021 17:49:37 +0200 Subject: [PATCH 34/42] iwlwifi: support SAR GEO Offset Mapping override via BIOS Support reading the SAR Geographic Offset Mapping (SGOM) table from UEFI to allow OEMs to override the values according to geographical regions. Signed-off-by: Ayala Barazani Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20211204174546.e6dfd8b5dd40.Ibc9a8fe2bfde345f49df5d57ec56663da6a53dc4@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 2 + .../wireless/intel/iwlwifi/fw/api/nvm-reg.h | 5 ++ .../net/wireless/intel/iwlwifi/fw/api/power.h | 14 +++ .../net/wireless/intel/iwlwifi/fw/runtime.h | 4 + drivers/net/wireless/intel/iwlwifi/fw/uefi.c | 88 +++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/fw/uefi.h | 20 +++++ drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 49 ++++++++++- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 2 + 8 files changed, 183 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index 2e4590876bc3..0495316d1fc1 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -852,6 +852,8 @@ read_table: } } + fwrt->geo_num_profiles = num_profiles; + fwrt->geo_enabled = true; ret = 0; out_free: kfree(data); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h index 3551a3f1c1aa..186199100929 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h @@ -33,6 +33,11 @@ enum iwl_regulatory_and_nvm_subcmd_ids { */ TAS_CONFIG = 0x3, + /** + * @SAR_OFFSET_MAPPING_TABLE_CMD: &iwl_sar_offset_mapping_cmd + */ + SAR_OFFSET_MAPPING_TABLE_CMD = 0x4, + /** * @PNVM_INIT_COMPLETE_NTFY: &struct iwl_pnvm_init_complete_ntfy */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/power.h b/drivers/net/wireless/intel/iwlwifi/fw/api/power.h index 4d671c878bb7..631b96cc8ee9 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/power.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/power.h @@ -503,6 +503,20 @@ union iwl_ppag_table_cmd { } v2; } __packed; +#define MCC_TO_SAR_OFFSET_TABLE_ROW_SIZE 26 +#define MCC_TO_SAR_OFFSET_TABLE_COL_SIZE 13 + +/** + * struct iwl_sar_offset_mapping_cmd - struct for SAR_OFFSET_MAPPING_TABLE_CMD + * @offset_map: mapping a mcc to a geo sar group + * @reserved: reserved + */ +struct iwl_sar_offset_mapping_cmd { + u8 offset_map[MCC_TO_SAR_OFFSET_TABLE_ROW_SIZE] + [MCC_TO_SAR_OFFSET_TABLE_COL_SIZE]; + u16 reserved; +} __packed; /*SAR_OFFSET_MAPPING_TABLE_CMD_API_S*/ + /** * struct iwl_beacon_filter_cmd * REPLY_BEACON_FILTERING_CMD = 0xd2 (command) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h index 69799f1ed2c4..cd895b614ddb 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h @@ -156,8 +156,12 @@ struct iwl_fw_runtime { u8 sar_chain_b_profile; struct iwl_geo_profile geo_profiles[ACPI_NUM_GEO_PROFILES_REV3]; u32 geo_rev; + u32 geo_num_profiles; + bool geo_enabled; union iwl_ppag_table_cmd ppag_table; u32 ppag_ver; + struct iwl_sar_offset_mapping_cmd sgom_table; + bool sgom_enabled; #endif }; diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c index c875bf35533c..c4dfc1aa60d5 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c @@ -11,6 +11,7 @@ #include "fw/uefi.h" #include "fw/api/alive.h" #include +#include "fw/runtime.h" #define IWL_EFI_VAR_GUID EFI_GUID(0x92daaf2f, 0xc02b, 0x455b, \ 0xb2, 0xec, 0xf5, 0xa3, \ @@ -260,3 +261,90 @@ out: return data; } + +#ifdef CONFIG_ACPI +static int iwl_uefi_sgom_parse(struct uefi_cnv_wlan_sgom_data *sgom_data, + struct iwl_fw_runtime *fwrt) +{ + int i, j; + + if (sgom_data->revision != 1) + return -EINVAL; + + memcpy(fwrt->sgom_table.offset_map, sgom_data->offset_map, + sizeof(fwrt->sgom_table.offset_map)); + + for (i = 0; i < MCC_TO_SAR_OFFSET_TABLE_ROW_SIZE; i++) { + for (j = 0; j < MCC_TO_SAR_OFFSET_TABLE_COL_SIZE; j++) { + /* since each byte is composed of to values, */ + /* one for each letter, */ + /* extract and check each of them separately */ + u8 value = fwrt->sgom_table.offset_map[i][j]; + u8 low = value & 0xF; + u8 high = (value & 0xF0) >> 4; + + if (high > fwrt->geo_num_profiles) + high = 0; + if (low > fwrt->geo_num_profiles) + low = 0; + fwrt->sgom_table.offset_map[i][j] = (high << 4) | low; + } + } + + fwrt->sgom_enabled = true; + return 0; +} + +void iwl_uefi_get_sgom_table(struct iwl_trans *trans, + struct iwl_fw_runtime *fwrt) +{ + struct efivar_entry *sgom_efivar; + struct uefi_cnv_wlan_sgom_data *data; + unsigned long package_size; + int err, ret; + + if (!fwrt->geo_enabled) + return; + + sgom_efivar = kzalloc(sizeof(*sgom_efivar), GFP_KERNEL); + if (!sgom_efivar) + return; + + memcpy(&sgom_efivar->var.VariableName, IWL_UEFI_SGOM_NAME, + sizeof(IWL_UEFI_SGOM_NAME)); + sgom_efivar->var.VendorGuid = IWL_EFI_VAR_GUID; + + /* TODO: we hardcode a maximum length here, because reading + * from the UEFI is not working. To implement this properly, + * we have to call efivar_entry_size(). + */ + package_size = IWL_HARDCODED_SGOM_SIZE; + + data = kmalloc(package_size, GFP_KERNEL); + if (!data) { + data = ERR_PTR(-ENOMEM); + goto out; + } + + err = efivar_entry_get(sgom_efivar, NULL, &package_size, data); + if (err) { + IWL_DEBUG_FW(trans, + "SGOM UEFI variable not found %d\n", err); + goto out_free; + } + + IWL_DEBUG_FW(trans, "Read SGOM from UEFI with size %lu\n", + package_size); + + ret = iwl_uefi_sgom_parse(data, fwrt); + if (ret < 0) + IWL_DEBUG_FW(trans, "Cannot read SGOM tables. rev is invalid\n"); + +out_free: + kfree(data); + +out: + kfree(sgom_efivar); +} +IWL_EXPORT_SYMBOL(iwl_uefi_get_sgom_table); +#endif /* CONFIG_ACPI */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h index d552c656ac9f..09d2a971b3a0 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h @@ -7,6 +7,7 @@ #define IWL_UEFI_OEM_PNVM_NAME L"UefiCnvWlanOemSignedPnvm" #define IWL_UEFI_REDUCED_POWER_NAME L"UefiCnvWlanReducedPower" +#define IWL_UEFI_SGOM_NAME L"UefiCnvWlanSarGeoOffsetMapping" /* * TODO: we have these hardcoded values that the caller must pass, @@ -16,6 +17,7 @@ */ #define IWL_HARDCODED_PNVM_SIZE 4096 #define IWL_HARDCODED_REDUCE_POWER_SIZE 32768 +#define IWL_HARDCODED_SGOM_SIZE 339 struct pnvm_sku_package { u8 rev; @@ -25,6 +27,16 @@ struct pnvm_sku_package { u8 data[]; } __packed; +struct uefi_cnv_wlan_sgom_data { + u8 revision; + u8 offset_map[IWL_HARDCODED_SGOM_SIZE - 1]; +} __packed; + +/* + * This is known to be broken on v4.19 and to work on v5.4. Until we + * figure out why this is the case and how to make it work, simply + * disable the feature in old kernels. + */ #ifdef CONFIG_EFI void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len); void *iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len); @@ -42,4 +54,12 @@ void *iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len) } #endif /* CONFIG_EFI */ +#if defined(CONFIG_EFI) && defined(CONFIG_ACPI) +void iwl_uefi_get_sgom_table(struct iwl_trans *trans, struct iwl_fw_runtime *fwrt); +#else +static inline +void iwl_uefi_get_sgom_table(struct iwl_trans *trans, struct iwl_fw_runtime *fwrt) +{ +} +#endif #endif /* __iwl_fw_uefi__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 7608b1e486c4..187637c81d1a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -518,7 +518,6 @@ static void iwl_mvm_phy_filter_init(struct iwl_mvm *mvm, cpu_to_le32(IWL_MVM_PHY_FILTER_CHAIN_D); } } - #else /* CONFIG_ACPI */ static void iwl_mvm_phy_filter_init(struct iwl_mvm *mvm, @@ -527,6 +526,49 @@ static void iwl_mvm_phy_filter_init(struct iwl_mvm *mvm, } #endif /* CONFIG_ACPI */ +#if defined(CONFIG_ACPI) && defined(CONFIG_EFI) +static int iwl_mvm_sgom_init(struct iwl_mvm *mvm) +{ + u8 cmd_ver; + int ret; + struct iwl_host_cmd cmd = { + .id = WIDE_ID(REGULATORY_AND_NVM_GROUP, + SAR_OFFSET_MAPPING_TABLE_CMD), + .flags = 0, + .data[0] = &mvm->fwrt.sgom_table, + .len[0] = sizeof(mvm->fwrt.sgom_table), + .dataflags[0] = IWL_HCMD_DFL_NOCOPY, + }; + + if (!mvm->fwrt.sgom_enabled) { + IWL_DEBUG_RADIO(mvm, "SGOM table is disabled\n"); + return 0; + } + + cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, REGULATORY_AND_NVM_GROUP, + SAR_OFFSET_MAPPING_TABLE_CMD, + IWL_FW_CMD_VER_UNKNOWN); + + if (cmd_ver != 2) { + IWL_DEBUG_RADIO(mvm, "command version is unsupported. version = %d\n", + cmd_ver); + return 0; + } + + ret = iwl_mvm_send_cmd(mvm, &cmd); + if (ret < 0) + IWL_ERR(mvm, "failed to send SAR_OFFSET_MAPPING_CMD (%d)\n", ret); + + return ret; +} +#else + +static int iwl_mvm_sgom_init(struct iwl_mvm *mvm) +{ + return 0; +} +#endif + static int iwl_send_phy_cfg_cmd(struct iwl_mvm *mvm) { struct iwl_phy_cfg_cmd_v3 phy_cfg_cmd; @@ -1340,6 +1382,7 @@ static u8 iwl_mvm_eval_dsm_rfi(struct iwl_mvm *mvm) 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) @@ -1634,6 +1677,10 @@ int iwl_mvm_up(struct iwl_mvm *mvm) else if (ret < 0) goto error; + ret = iwl_mvm_sgom_init(mvm); + if (ret) + goto error; + iwl_mvm_tas_init(mvm); iwl_mvm_leds_sync(mvm); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 9c0872b106b6..cc1879e10c65 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -26,6 +26,7 @@ #include "time-event.h" #include "fw-api.h" #include "fw/acpi.h" +#include "fw/uefi.h" #define DRV_DESCRIPTION "The new Intel(R) wireless AGN driver for Linux" MODULE_DESCRIPTION(DRV_DESCRIPTION); @@ -1094,6 +1095,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, &iwl_mvm_sanitize_ops, mvm, dbgfs_dir); iwl_mvm_get_acpi_tables(mvm); + iwl_uefi_get_sgom_table(trans, &mvm->fwrt); mvm->init_status = 0; From 1599a16492336ec47dfbf3780d3e90c2f0df965d Mon Sep 17 00:00:00 2001 From: Mukesh Sisodiya Date: Sat, 4 Dec 2021 17:49:38 +0200 Subject: [PATCH 35/42] iwlwifi: dbg: disable ini debug in 8000 family and below Yoyo based debug is not applicable for 8000 and below old devices. The check added in code has 9000 and below familiy which is corrected. Signed-off-by: Mukesh Sisodiya Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20211204174546.b6176a5bc198.Ib8e4b1e60e0b6c1538cc4f384dcf681b3db097ce@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c | 2 +- 1 file changed, 1 insertion(+), 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 49526fdcf9d2..a8ebc26d1da1 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c @@ -473,7 +473,7 @@ void iwl_dbg_tlv_load_bin(struct device *dev, struct iwl_trans *trans) int res; if (!iwlwifi_mod_params.enable_ini || - trans->trans_cfg->device_family <= IWL_DEVICE_FAMILY_9000) + trans->trans_cfg->device_family <= IWL_DEVICE_FAMILY_8000) return; res = firmware_request_nowarn(&fw, yoyo_bin, dev); From 9c13f21f7c2c645da95c9543785ccd7e4022b6a1 Mon Sep 17 00:00:00 2001 From: Matti Gottlieb Date: Sat, 4 Dec 2021 17:49:39 +0200 Subject: [PATCH 36/42] iwlwifi: Fix FW name for gl Fix FW name for gl use the crf fm and not fm7, since the later no longer exists. Signed-off-by: Matti Gottlieb Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20211204174546.497b2f2c587d.If71fa8cbed043c15f927bb78cb8a695625a362dd@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 c9ccbbe3b92d..b1ad0e1c472a 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c @@ -54,7 +54,7 @@ #define IWL_BZ_A_GF4_A_FW_PRE "iwlwifi-bz-a0-gf4-a0-" #define IWL_BZ_A_MR_A_FW_PRE "iwlwifi-bz-a0-mr-a0-" #define IWL_BZ_A_FM_A_FW_PRE "iwlwifi-bz-a0-fm-a0-" -#define IWL_GL_A_FM_A_FW_PRE "iwlwifi-gl-a0-fm7-a0-" +#define IWL_GL_A_FM_A_FW_PRE "iwlwifi-gl-a0-fm-a0-" #define IWL_BZ_Z_GF_A_FW_PRE "iwlwifi-bz-z0-gf-a0-" From def423ea1d0de18b38ac7c43118a4c328ff70406 Mon Sep 17 00:00:00 2001 From: Yaara Baruch Date: Sat, 4 Dec 2021 17:49:40 +0200 Subject: [PATCH 37/42] iwlwifi: add new Qu-Hr device Add new Qu-Hr device ID. Signed-off-by: Yaara Baruch Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20211204174546.c68af5f8d7ce.I37894e98080161c3bca6f33b99a5b8812166ee41@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index 11b6c5b54683..4bc3837eaacb 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -959,6 +959,11 @@ static const struct iwl_dev_info iwl_dev_info_table[] = { IWL_CFG_RF_TYPE_HR2, IWL_CFG_ANY, IWL_CFG_NO_160, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_qu_c0_hr_b0, iwl_ax203_name), + _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_QU, SILICON_C_STEP, + IWL_CFG_RF_TYPE_HR2, IWL_CFG_ANY, + IWL_CFG_160, IWL_CFG_ANY, IWL_CFG_NO_CDB, + iwl_qu_c0_hr_b0, iwl_ax201_name), /* QuZ */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, From 23a392a44a3cabf43515f7601373a2094ac5f747 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 4 Dec 2021 17:49:41 +0200 Subject: [PATCH 38/42] iwlwifi: implement reset flow for Bz devices On Bz devices, UREG_DOORBELL_TO_ISR6_NMI_BIT no longer actually triggers an NMI. So instead of setting BIT(0) | BIT(1) for the reset flow, we need to just set BIT(1) and then force the NMI in the new way. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20211204174546.6b56e7ee1773.I71cba66e17cc0daabc5ad7abd88763674b625c82@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c index 72b5b69bfe5e..0febdcacbd42 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c @@ -105,9 +105,12 @@ static void iwl_trans_pcie_fw_reset_handshake(struct iwl_trans *trans) 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_RESET_HANDSHAKE); - else + else if (trans->trans_cfg->device_family == IWL_DEVICE_FAMILY_AX210) iwl_write_umac_prph(trans, UREG_DOORBELL_TO_ISR6, UREG_DOORBELL_TO_ISR6_RESET_HANDSHAKE); + else + iwl_write32(trans, CSR_DOORBELL_VECTOR, + UREG_DOORBELL_TO_ISR6_RESET_HANDSHAKE); /* wait 200ms */ ret = wait_event_timeout(trans_pcie->fw_reset_waitq, From 04f1ee24040308baf29a1ffc0831430445d56e7a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 4 Dec 2021 17:49:42 +0200 Subject: [PATCH 39/42] iwlwifi: fw: correctly detect HW-SMEM region subtype This is part of the "device memory" type, but with the subtypes we can now detect it properly, rather than having to make assumptions on the ID. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20211204174546.91d33aa9dd3d.Ifb48e21fbb92ea25360856b5cc2afbb9b485d6b3@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h | 3 ++- drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 3 +-- 2 files changed, 3 insertions(+), 3 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 1c302cdbde5a..224525417424 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h @@ -7,7 +7,6 @@ #include -#define IWL_FW_INI_HW_SMEM_REGION_ID 15 #define IWL_FW_INI_MAX_REGION_ID 64 #define IWL_FW_INI_MAX_NAME 32 #define IWL_FW_INI_MAX_CFG_NAME 64 @@ -387,6 +386,8 @@ enum iwl_fw_ini_region_type { IWL_FW_INI_REGION_NUM }; /* FW_TLV_DEBUG_REGION_TYPE_API_E */ +#define IWL_FW_INI_REGION_DEVICE_MEMORY_SUBTYPE_HW_SMEM 1 + /** * enum iwl_fw_ini_time_point * diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index fa3a7a3c3a61..a373a2bc964a 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -1165,8 +1165,7 @@ static int iwl_dump_ini_dev_mem_iter(struct iwl_fw_runtime *fwrt, iwl_trans_read_mem_bytes(fwrt->trans, addr, range->data, le32_to_cpu(reg->dev_addr.size)); - if ((le32_to_cpu(reg->id) & IWL_FW_INI_REGION_V2_MASK) == - IWL_FW_INI_HW_SMEM_REGION_ID && + if (reg->sub_type == IWL_FW_INI_REGION_DEVICE_MEMORY_SUBTYPE_HW_SMEM && fwrt->sanitize_ops && fwrt->sanitize_ops->frob_txf) fwrt->sanitize_ops->frob_txf(fwrt->sanitize_ctx, range->data, From 953e66a7238b90ba1d0766ce3342bad799f83b52 Mon Sep 17 00:00:00 2001 From: Yaara Baruch Date: Sat, 4 Dec 2021 17:49:43 +0200 Subject: [PATCH 40/42] iwlwifi: add new ax1650 killer device Add new Qu-Hr killer device id. Signed-off-by: Yaara Baruch Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20211204174546.997c250b9edc.Id50730e3e342297432eed47cdf9678ee16cf6d17@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index 4bc3837eaacb..5c6e81a734ac 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -562,6 +562,7 @@ static const struct iwl_dev_info iwl_dev_info_table[] = { IWL_DEV_INFO(0x43F0, 0x1652, killer1650i_2ax_cfg_qu_b0_hr_b0, iwl_ax201_killer_1650i_name), IWL_DEV_INFO(0x43F0, 0x2074, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0x43F0, 0x4070, iwl_ax201_cfg_qu_hr, NULL), + IWL_DEV_INFO(0x43F0, 0x1651, killer1650s_2ax_cfg_qu_b0_hr_b0, iwl_ax201_killer_1650s_name), IWL_DEV_INFO(0xA0F0, 0x0070, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0xA0F0, 0x0074, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0xA0F0, 0x0078, iwl_ax201_cfg_qu_hr, NULL), From 4b992db6ebdaaee244a7931753f5b49d049a760a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 4 Dec 2021 17:49:44 +0200 Subject: [PATCH 41/42] iwlwifi: mvm: optionally suppress assert log Normally, when we hit an assert, we print out all the assert data. However, in certain tests, when we trigger it from debugfs intentionally, that can be useless and confusing. Allow writing the string "nolog\n" to the fw_nmi and fw_restart files suppressing the assert dump as well as - in the case of fw_restart - the iwlwifi 0000:00:00.0: FW error in SYNC CMD REPLY_ERROR message. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20211204174546.75e29a2ab68d.Id3064feda2ce7a77c116c6d6e71ce5ff447c6e86@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-trans.h | 3 +++ drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c | 8 ++++++++ drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 3 +++ drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 4 +++- drivers/net/wireless/intel/iwlwifi/queue/tx.c | 7 +++++-- 5 files changed, 22 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index 9dea8f9bbcae..e7c6e7bc5277 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -296,6 +296,8 @@ enum iwl_d3_status { * are sent * @STATUS_TRANS_IDLE: the trans is idle - general commands are not to be sent * @STATUS_TRANS_DEAD: trans is dead - avoid any read/write operation + * @STATUS_SUPPRESS_CMD_ERROR_ONCE: suppress "FW error in SYNC CMD" once, + * e.g. for testing */ enum iwl_trans_status { STATUS_SYNC_HCMD_ACTIVE, @@ -308,6 +310,7 @@ enum iwl_trans_status { STATUS_TRANS_GOING_IDLE, STATUS_TRANS_IDLE, STATUS_TRANS_DEAD, + STATUS_SUPPRESS_CMD_ERROR_ONCE, }; static inline int diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index ff66001d507e..f1e9d2c99051 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -1022,6 +1022,11 @@ static ssize_t iwl_dbgfs_fw_restart_write(struct iwl_mvm *mvm, char *buf, if (mvm->fw_restart >= 0) mvm->fw_restart++; + if (count == 6 && !strcmp(buf, "nolog\n")) { + set_bit(IWL_MVM_STATUS_SUPPRESS_ERROR_LOG_ONCE, &mvm->status); + set_bit(STATUS_SUPPRESS_CMD_ERROR_ONCE, &mvm->trans->status); + } + /* take the return value to make compiler happy - it will fail anyway */ ret = iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(LONG_GROUP, REPLY_ERROR), @@ -1038,6 +1043,9 @@ static ssize_t iwl_dbgfs_fw_nmi_write(struct iwl_mvm *mvm, char *buf, if (!iwl_mvm_firmware_running(mvm)) return -EIO; + if (count == 6 && !strcmp(buf, "nolog\n")) + set_bit(IWL_MVM_STATUS_SUPPRESS_ERROR_LOG_ONCE, &mvm->status); + iwl_force_nmi(mvm->trans); return count; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index f7ff7f2e3928..92d6e3dbbb62 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1137,6 +1137,8 @@ struct iwl_mvm { * @IWL_MVM_STATUS_FIRMWARE_RUNNING: firmware is running * @IWL_MVM_STATUS_NEED_FLUSH_P2P: need to flush P2P bcast STA * @IWL_MVM_STATUS_IN_D3: in D3 (or at least about to go into it) + * @IWL_MVM_STATUS_SUPPRESS_ERROR_LOG_ONCE: suppress one error log + * if this is set, when intentionally triggered */ enum iwl_mvm_status { IWL_MVM_STATUS_HW_RFKILL, @@ -1148,6 +1150,7 @@ enum iwl_mvm_status { IWL_MVM_STATUS_FIRMWARE_RUNNING, IWL_MVM_STATUS_NEED_FLUSH_P2P, IWL_MVM_STATUS_IN_D3, + IWL_MVM_STATUS_SUPPRESS_ERROR_LOG_ONCE, }; struct iwl_mvm_csme_conn_info { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index cc1879e10c65..6bb4e4d9d95a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -1841,7 +1841,9 @@ 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)) + if (!test_bit(STATUS_TRANS_DEAD, &mvm->trans->status) && + !test_and_clear_bit(IWL_MVM_STATUS_SUPPRESS_ERROR_LOG_ONCE, + &mvm->status)) iwl_mvm_dump_nic_error_log(mvm); if (sync) { diff --git a/drivers/net/wireless/intel/iwlwifi/queue/tx.c b/drivers/net/wireless/intel/iwlwifi/queue/tx.c index 0f3526b0c5b0..0730657d54bf 100644 --- a/drivers/net/wireless/intel/iwlwifi/queue/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/queue/tx.c @@ -1753,8 +1753,11 @@ static int iwl_trans_txq_send_hcmd_sync(struct iwl_trans *trans, } if (test_bit(STATUS_FW_ERROR, &trans->status)) { - IWL_ERR(trans, "FW error in SYNC CMD %s\n", cmd_str); - dump_stack(); + if (!test_and_clear_bit(STATUS_SUPPRESS_CMD_ERROR_ONCE, + &trans->status)) { + IWL_ERR(trans, "FW error in SYNC CMD %s\n", cmd_str); + dump_stack(); + } ret = -EIO; goto cancel; } From 977df8bd5844c9370c26a9477418165b870da27c Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 7 Dec 2021 16:14:36 +0100 Subject: [PATCH 42/42] iwlwifi: work around reverse dependency on MEI If the iwlmei code is a loadable module, the main iwlwifi driver cannot be built-in: x86_64-linux-ld: drivers/net/wireless/intel/iwlwifi/pcie/trans.o: in function `iwl_pcie_prepare_card_hw': trans.c:(.text+0x4158): undefined reference to `iwl_mei_is_connected' Unfortunately, Kconfig enforces the opposite, forcing the MEI driver to not be built-in if iwlwifi is a module. To work around this, decouple iwlmei from iwlwifi and add the dependency in the other direction. Signed-off-by: Arnd Bergmann Link: https://lore.kernel.org/r/20211207151447.3338818-1-arnd@kernel.org Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/Kconfig | 52 +++++++++++----------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/Kconfig b/drivers/net/wireless/intel/iwlwifi/Kconfig index 337428ef2e67..cafdb458b067 100644 --- a/drivers/net/wireless/intel/iwlwifi/Kconfig +++ b/drivers/net/wireless/intel/iwlwifi/Kconfig @@ -2,6 +2,7 @@ config IWLWIFI tristate "Intel Wireless WiFi Next Gen AGN - Wireless-N/Advanced-N/Ultimate-N (iwlwifi) " depends on PCI && HAS_IOMEM && CFG80211 + depends on IWLMEI || !IWLMEI select FW_LOADER help Select to build the driver supporting the: @@ -92,32 +93,6 @@ config IWLWIFI_BCAST_FILTERING If unsure, don't enable this option, as some programs might expect incoming broadcasts for their normal operations. -config IWLMEI - tristate "Intel Management Engine communication over WLAN" - depends on INTEL_MEI - depends on PM - depends on IWLMVM - help - Enables the iwlmei kernel module. - - CSME stands for Converged Security and Management Engine. It is a CPU - on the chipset and runs a dedicated firmware. AMT (Active Management - Technology) is one of the applications that run on that CPU. AMT - allows to control the platform remotely. - - This kernel module allows to communicate with the Intel Management - Engine over Wifi. This is supported starting from Tiger Lake - platforms and has been tested on 9260 devices only. - If AMT is configured not to use the wireless device, this module is - harmless (and useless). - Enabling this option on a platform that has a different device and - has Wireless enabled on AMT can prevent WiFi from working correctly. - - For more information see - - - If unsure, say N. - menu "Debugging Options" config IWLWIFI_DEBUG @@ -172,3 +147,28 @@ config IWLWIFI_DEVICE_TRACING endmenu endif + +config IWLMEI + tristate "Intel Management Engine communication over WLAN" + depends on INTEL_MEI + depends on PM + help + Enables the iwlmei kernel module. + + CSME stands for Converged Security and Management Engine. It is a CPU + on the chipset and runs a dedicated firmware. AMT (Active Management + Technology) is one of the applications that run on that CPU. AMT + allows to control the platform remotely. + + This kernel module allows to communicate with the Intel Management + Engine over Wifi. This is supported starting from Tiger Lake + platforms and has been tested on 9260 devices only. + If AMT is configured not to use the wireless device, this module is + harmless (and useless). + Enabling this option on a platform that has a different device and + has Wireless enabled on AMT can prevent WiFi from working correctly. + + For more information see + + + If unsure, say N.