From: Gregory Greenman <[email protected]>
Hi,
Here's the first set of patches intended for v6.2. It contains
some fixes for IWLMEI. There will be more fixes, so it still depends
on BROKEN.
As usual, I'm pushing this to a pending branch, for kbuild bot,
and will send a pull-request later.
Please review.
Thanks,
Gregory
Avraham Stern (3):
wifi: iwlwifi: mvm: send TKIP connection status to csme
wifi: iwlwifi: mei: make sure ownership confirmed message is sent
wifi: iwlwifi: mei: avoid blocking sap messages handling due to rtnl
lock
Emmanuel Grumbach (2):
wifi: iwlwifi: mei: don't send SAP commands if AMT is disabled
wifi: iwlwifi: mei: fix tx DHCP packet for devices with new Tx API
Johannes Berg (1):
wifi: iwlwifi: mei: fix potential NULL-ptr deref after clone
.../net/wireless/intel/iwlwifi/mei/iwl-mei.h | 9 +-
drivers/net/wireless/intel/iwlwifi/mei/main.c | 172 ++++++++++--------
drivers/net/wireless/intel/iwlwifi/mei/net.c | 10 +-
drivers/net/wireless/intel/iwlwifi/mei/sap.h | 4 +-
drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 2 +
.../net/wireless/intel/iwlwifi/mvm/mac80211.c | 3 +
drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 4 +-
drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 2 +-
drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 8 +-
9 files changed, 132 insertions(+), 82 deletions(-)
--
2.35.3
From: Avraham Stern <[email protected]>
Notify csme when associated with TKIP cipher. TKIP is supported
by csme.
Signed-off-by: Avraham Stern <[email protected]>
Signed-off-by: Gregory Greenman <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/mei/iwl-mei.h | 2 ++
drivers/net/wireless/intel/iwlwifi/mei/sap.h | 4 +++-
drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 3 +++
3 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/mei/iwl-mei.h b/drivers/net/wireless/intel/iwlwifi/mei/iwl-mei.h
index 67122cfa2292..bea61c8fb526 100644
--- a/drivers/net/wireless/intel/iwlwifi/mei/iwl-mei.h
+++ b/drivers/net/wireless/intel/iwlwifi/mei/iwl-mei.h
@@ -220,6 +220,7 @@ struct iwl_mei_nvm {
/**
* enum iwl_mei_pairwise_cipher - cipher for UCAST key
* @IWL_MEI_CIPHER_NONE: none
+ * @IWL_MEI_CIPHER_TKIP: tkip
* @IWL_MEI_CIPHER_CCMP: ccmp
* @IWL_MEI_CIPHER_GCMP: gcmp
* @IWL_MEI_CIPHER_GCMP_256: gcmp 256
@@ -228,6 +229,7 @@ struct iwl_mei_nvm {
*/
enum iwl_mei_pairwise_cipher {
IWL_MEI_CIPHER_NONE = 0,
+ IWL_MEI_CIPHER_TKIP = 2,
IWL_MEI_CIPHER_CCMP = 4,
IWL_MEI_CIPHER_GCMP = 8,
IWL_MEI_CIPHER_GCMP_256 = 9,
diff --git a/drivers/net/wireless/intel/iwlwifi/mei/sap.h b/drivers/net/wireless/intel/iwlwifi/mei/sap.h
index be1456dea484..ef2664589fc1 100644
--- a/drivers/net/wireless/intel/iwlwifi/mei/sap.h
+++ b/drivers/net/wireless/intel/iwlwifi/mei/sap.h
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (C) 2021 Intel Corporation
+ * Copyright (C) 2021 - 2022 Intel Corporation
*/
#ifndef __sap_h__
@@ -334,12 +334,14 @@ enum iwl_sap_wifi_auth_type {
/**
* enum iwl_sap_wifi_cipher_alg
* @SAP_WIFI_CIPHER_ALG_NONE: TBD
+ * @SAP_WIFI_CIPHER_ALG_TKIP: TBD
* @SAP_WIFI_CIPHER_ALG_CCMP: TBD
* @SAP_WIFI_CIPHER_ALG_GCMP: TBD
* @SAP_WIFI_CIPHER_ALG_GCMP_256: TBD
*/
enum iwl_sap_wifi_cipher_alg {
SAP_WIFI_CIPHER_ALG_NONE = IWL_MEI_CIPHER_NONE,
+ SAP_WIFI_CIPHER_ALG_TKIP = IWL_MEI_CIPHER_TKIP,
SAP_WIFI_CIPHER_ALG_CCMP = IWL_MEI_CIPHER_CCMP,
SAP_WIFI_CIPHER_ALG_GCMP = IWL_MEI_CIPHER_GCMP,
SAP_WIFI_CIPHER_ALG_GCMP_256 = IWL_MEI_CIPHER_GCMP_256,
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
index 8464c9b7baf1..156283237e2a 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
@@ -3059,6 +3059,9 @@ static void iwl_mvm_mei_host_associated(struct iwl_mvm *mvm,
return;
switch (mvm_sta->pairwise_cipher) {
+ case WLAN_CIPHER_SUITE_TKIP:
+ conn_info.pairwise_cipher = IWL_MEI_CIPHER_TKIP;
+ break;
case WLAN_CIPHER_SUITE_CCMP:
conn_info.pairwise_cipher = IWL_MEI_CIPHER_CCMP;
break;
--
2.35.3
From: Avraham Stern <[email protected]>
It is possible that CSME will try to take ownership while the driver
is stopping. In this case, if the CSME takes ownership message arrives
after the driver started unregistering, the iwl_mei_cache->ops is
already invalid, so the host will not answer with the ownership
confirmed message.
Similarly, if the take ownership message arrived after the mac was
stopped or when iwl_mvm_up() failed, setting rfkill will not trigger
sending the confirm message. As a result, CSME will not take
ownership, which will result in a disconnection.
Fix it by sending the ownership confirmed message immediately in such
cases.
Fixes: 2da4366f9e2c ("iwlwifi: mei: add the driver to allow cooperation with CSME")
Signed-off-by: Avraham Stern <[email protected]>
Signed-off-by: Gregory Greenman <[email protected]>
---
.../net/wireless/intel/iwlwifi/mei/iwl-mei.h | 7 +++--
drivers/net/wireless/intel/iwlwifi/mei/main.c | 30 ++++++++++++-------
drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 2 ++
drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 4 +--
drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 2 +-
5 files changed, 29 insertions(+), 16 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/mei/iwl-mei.h b/drivers/net/wireless/intel/iwlwifi/mei/iwl-mei.h
index bea61c8fb526..2e57438a70f0 100644
--- a/drivers/net/wireless/intel/iwlwifi/mei/iwl-mei.h
+++ b/drivers/net/wireless/intel/iwlwifi/mei/iwl-mei.h
@@ -448,9 +448,10 @@ void iwl_mei_host_associated(const struct iwl_mei_conn_info *conn_info,
void iwl_mei_host_disassociated(void);
/**
- * iwl_mei_device_down() - must be called when the device is down
+ * iwl_mei_device_state() - must be called when the device changes up/down state
+ * @up: true if the device is up, false otherwise.
*/
-void iwl_mei_device_down(void);
+void iwl_mei_device_state(bool up);
#else
@@ -499,7 +500,7 @@ static inline void iwl_mei_host_associated(const struct iwl_mei_conn_info *conn_
static inline void iwl_mei_host_disassociated(void)
{}
-static inline void iwl_mei_device_down(void)
+static inline void iwl_mei_device_state(bool up)
{}
#endif /* CONFIG_IWLMEI */
diff --git a/drivers/net/wireless/intel/iwlwifi/mei/main.c b/drivers/net/wireless/intel/iwlwifi/mei/main.c
index 357f14626cf4..90646c54a3c5 100644
--- a/drivers/net/wireless/intel/iwlwifi/mei/main.c
+++ b/drivers/net/wireless/intel/iwlwifi/mei/main.c
@@ -147,6 +147,8 @@ struct iwl_mei_filters {
* to send CSME_OWNERSHIP_CONFIRMED when the driver completes its down
* flow.
* @link_prot_state: true when we are in link protection PASSIVE
+ * @device_down: true if the device is down. Used to remember to send
+ * CSME_OWNERSHIP_CONFIRMED when the driver is already down.
* @csa_throttle_end_wk: used when &csa_throttled is true
* @data_q_lock: protects the access to the data queues which are
* accessed without the mutex.
@@ -167,6 +169,7 @@ struct iwl_mei {
bool csa_throttled;
bool csme_taking_ownership;
bool link_prot_state;
+ bool device_down;
struct delayed_work csa_throttle_end_wk;
spinlock_t data_q_lock;
@@ -798,14 +801,18 @@ static void iwl_mei_handle_csme_taking_ownership(struct mei_cl_device *cldev,
mei->got_ownership = false;
- /*
- * Remember to send CSME_OWNERSHIP_CONFIRMED when the wifi driver
- * is finished taking the device down.
- */
- mei->csme_taking_ownership = true;
+ if (iwl_mei_cache.ops && !mei->device_down) {
+ /*
+ * Remember to send CSME_OWNERSHIP_CONFIRMED when the wifi
+ * driver is finished taking the device down.
+ */
+ mei->csme_taking_ownership = true;
- if (iwl_mei_cache.ops)
- iwl_mei_cache.ops->rfkill(iwl_mei_cache.priv, true);
+ iwl_mei_cache.ops->rfkill(iwl_mei_cache.priv, true, true);
+ } else {
+ iwl_mei_send_sap_msg(cldev,
+ SAP_MSG_NOTIF_CSME_OWNERSHIP_CONFIRMED);
+ }
}
static void iwl_mei_handle_nvm(struct mei_cl_device *cldev,
@@ -1616,7 +1623,7 @@ void iwl_mei_set_netdev(struct net_device *netdev)
}
EXPORT_SYMBOL_GPL(iwl_mei_set_netdev);
-void iwl_mei_device_down(void)
+void iwl_mei_device_state(bool up)
{
struct iwl_mei *mei;
@@ -1630,7 +1637,9 @@ void iwl_mei_device_down(void)
if (!mei)
goto out;
- if (!mei->csme_taking_ownership)
+ mei->device_down = !up;
+
+ if (up || !mei->csme_taking_ownership)
goto out;
iwl_mei_send_sap_msg(mei->cldev,
@@ -1639,7 +1648,7 @@ void iwl_mei_device_down(void)
out:
mutex_unlock(&iwl_mei_mutex);
}
-EXPORT_SYMBOL_GPL(iwl_mei_device_down);
+EXPORT_SYMBOL_GPL(iwl_mei_device_state);
int iwl_mei_register(void *priv, const struct iwl_mei_ops *ops)
{
@@ -1821,6 +1830,7 @@ static int iwl_mei_probe(struct mei_cl_device *cldev,
mei_cldev_set_drvdata(cldev, mei);
mei->cldev = cldev;
+ mei->device_down = true;
do {
ret = iwl_mei_alloc_shared_mem(cldev);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
index f041e77af059..5de34edc51fe 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
@@ -1665,6 +1665,8 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
iwl_rfi_send_config_cmd(mvm, NULL);
}
+ iwl_mvm_mei_device_state(mvm, true);
+
IWL_DEBUG_INFO(mvm, "RT uCode started.\n");
return 0;
error:
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
index 97cba526e465..1ccb3cad7cdc 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
@@ -2201,10 +2201,10 @@ static inline void iwl_mvm_mei_host_disassociated(struct iwl_mvm *mvm)
iwl_mei_host_disassociated();
}
-static inline void iwl_mvm_mei_device_down(struct iwl_mvm *mvm)
+static inline void iwl_mvm_mei_device_state(struct iwl_mvm *mvm, bool up)
{
if (mvm->mei_registered)
- iwl_mei_device_down();
+ iwl_mei_device_state(up);
}
static inline void iwl_mvm_mei_set_sw_rfkill_state(struct iwl_mvm *mvm)
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
index d2d42cd48af2..5b8e9a06f6d4 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
@@ -1375,7 +1375,7 @@ void iwl_mvm_stop_device(struct iwl_mvm *mvm)
iwl_trans_stop_device(mvm->trans);
iwl_free_fw_paging(&mvm->fwrt);
iwl_fw_dump_conf_clear(&mvm->fwrt);
- iwl_mvm_mei_device_down(mvm);
+ iwl_mvm_mei_device_state(mvm, false);
}
static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode)
--
2.35.3
From: Emmanuel Grumbach <[email protected]>
Devices with new Tx API have the IV introduced by the HW and it is not
present in the skb at all. Hence we don't need to tell
iwl_mvm_mei_tx_copy_to_csme to jump over 8 bytes to get to the ethernet
header.
Fixes: 2da4366f9e2c ("iwlwifi: mei: add the driver to allow cooperation with CSME")
Signed-off-by: Emmanuel Grumbach <[email protected]>
Signed-off-by: Gregory Greenman <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
index 86d20e13bf47..ba335f57771c 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
@@ -1171,9 +1171,15 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb,
/* From now on, we cannot access info->control */
iwl_mvm_skb_prepare_status(skb, dev_cmd);
+ /*
+ * The IV is introduced by the HW for new tx api, and it is not present
+ * in the skb, hence, don't tell iwl_mvm_mei_tx_copy_to_csme about the
+ * IV for those devices.
+ */
if (ieee80211_is_data(fc))
iwl_mvm_mei_tx_copy_to_csme(mvm, skb,
- info->control.hw_key ?
+ info->control.hw_key &&
+ !iwl_mvm_has_new_tx_api(mvm) ?
info->control.hw_key->iv_len : 0);
if (iwl_trans_tx(mvm->trans, skb, dev_cmd, txq_id))
--
2.35.3
From: Emmanuel Grumbach <[email protected]>
We should not send any SAP command to CSME if AMT is disabled.
Reported-by: Toke Høiland-Jørgensen <[email protected]>
Fixes: 2da4366f9e2c ("iwlwifi: mei: add the driver to allow cooperation with CSME")
Signed-off-by: Emmanuel Grumbach <[email protected]>
Signed-off-by: Gregory Greenman <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/mei/main.c | 85 ++++++++++---------
1 file changed, 44 insertions(+), 41 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/mei/main.c b/drivers/net/wireless/intel/iwlwifi/mei/main.c
index 90646c54a3c5..64a637ef199c 100644
--- a/drivers/net/wireless/intel/iwlwifi/mei/main.c
+++ b/drivers/net/wireless/intel/iwlwifi/mei/main.c
@@ -596,8 +596,6 @@ iwl_mei_handle_rx_start_ok(struct mei_cl_device *cldev,
const struct iwl_sap_me_msg_start_ok *rsp,
ssize_t len)
{
- struct iwl_mei *mei = mei_cldev_get_drvdata(cldev);
-
if (len != sizeof(*rsp)) {
dev_err(&cldev->dev,
"got invalid SAP_ME_MSG_START_OK from CSME firmware\n");
@@ -616,13 +614,10 @@ iwl_mei_handle_rx_start_ok(struct mei_cl_device *cldev,
mutex_lock(&iwl_mei_mutex);
set_bit(IWL_MEI_STATUS_SAP_CONNECTED, &iwl_mei_status);
- /* wifi driver has registered already */
- if (iwl_mei_cache.ops) {
- iwl_mei_send_sap_msg(mei->cldev,
- SAP_MSG_NOTIF_WIFIDR_UP);
- iwl_mei_cache.ops->sap_connected(iwl_mei_cache.priv);
- }
-
+ /*
+ * We'll receive AMT_STATE SAP message in a bit and
+ * that will continue the flow
+ */
mutex_unlock(&iwl_mei_mutex);
}
@@ -715,6 +710,13 @@ static void iwl_mei_set_init_conf(struct iwl_mei *mei)
.val = cpu_to_le32(iwl_mei_cache.rf_kill),
};
+ /* wifi driver has registered already */
+ if (iwl_mei_cache.ops) {
+ iwl_mei_send_sap_msg(mei->cldev,
+ SAP_MSG_NOTIF_WIFIDR_UP);
+ iwl_mei_cache.ops->sap_connected(iwl_mei_cache.priv);
+ }
+
iwl_mei_send_sap_msg(mei->cldev, SAP_MSG_NOTIF_WHO_OWNS_NIC);
if (iwl_mei_cache.conn_info) {
@@ -1420,10 +1422,7 @@ void iwl_mei_host_associated(const struct iwl_mei_conn_info *conn_info,
mei = mei_cldev_get_drvdata(iwl_mei_global_cldev);
- if (!mei)
- goto out;
-
- if (!mei->amt_enabled)
+ if (!mei && !mei->amt_enabled)
goto out;
iwl_mei_send_sap_msg_payload(mei->cldev, &msg.hdr);
@@ -1452,7 +1451,7 @@ void iwl_mei_host_disassociated(void)
mei = mei_cldev_get_drvdata(iwl_mei_global_cldev);
- if (!mei)
+ if (!mei && !mei->amt_enabled)
goto out;
iwl_mei_send_sap_msg_payload(mei->cldev, &msg.hdr);
@@ -1488,7 +1487,7 @@ void iwl_mei_set_rfkill_state(bool hw_rfkill, bool sw_rfkill)
mei = mei_cldev_get_drvdata(iwl_mei_global_cldev);
- if (!mei)
+ if (!mei && !mei->amt_enabled)
goto out;
iwl_mei_send_sap_msg_payload(mei->cldev, &msg.hdr);
@@ -1517,7 +1516,7 @@ void iwl_mei_set_nic_info(const u8 *mac_address, const u8 *nvm_address)
mei = mei_cldev_get_drvdata(iwl_mei_global_cldev);
- if (!mei)
+ if (!mei && !mei->amt_enabled)
goto out;
iwl_mei_send_sap_msg_payload(mei->cldev, &msg.hdr);
@@ -1545,7 +1544,7 @@ void iwl_mei_set_country_code(u16 mcc)
mei = mei_cldev_get_drvdata(iwl_mei_global_cldev);
- if (!mei)
+ if (!mei && !mei->amt_enabled)
goto out;
iwl_mei_send_sap_msg_payload(mei->cldev, &msg.hdr);
@@ -1571,7 +1570,7 @@ void iwl_mei_set_power_limit(const __le16 *power_limit)
mei = mei_cldev_get_drvdata(iwl_mei_global_cldev);
- if (!mei)
+ if (!mei && !mei->amt_enabled)
goto out;
memcpy(msg.sar_chain_info_table, power_limit, sizeof(msg.sar_chain_info_table));
@@ -1678,9 +1677,10 @@ int iwl_mei_register(void *priv, const struct iwl_mei_ops *ops)
/* we have already a SAP connection */
if (iwl_mei_is_connected()) {
- iwl_mei_send_sap_msg(mei->cldev,
- SAP_MSG_NOTIF_WIFIDR_UP);
- ops->rfkill(priv, mei->link_prot_state);
+ if (mei->amt_enabled)
+ iwl_mei_send_sap_msg(mei->cldev,
+ SAP_MSG_NOTIF_WIFIDR_UP);
+ ops->rfkill(priv, mei->link_prot_state, false);
}
}
ret = 0;
@@ -1931,29 +1931,32 @@ static void iwl_mei_remove(struct mei_cl_device *cldev)
mutex_lock(&iwl_mei_mutex);
- /*
- * Tell CSME that we are going down so that it won't access the
- * memory anymore, make sure this message goes through immediately.
- */
- mei->csa_throttled = false;
- iwl_mei_send_sap_msg(mei->cldev,
- SAP_MSG_NOTIF_HOST_GOES_DOWN);
+ if (mei->amt_enabled) {
+ /*
+ * Tell CSME that we are going down so that it won't access the
+ * memory anymore, make sure this message goes through immediately.
+ */
+ mei->csa_throttled = false;
+ iwl_mei_send_sap_msg(mei->cldev,
+ SAP_MSG_NOTIF_HOST_GOES_DOWN);
- for (i = 0; i < SEND_SAP_MAX_WAIT_ITERATION; i++) {
- if (!iwl_mei_host_to_me_data_pending(mei))
- break;
+ for (i = 0; i < SEND_SAP_MAX_WAIT_ITERATION; i++) {
+ if (!iwl_mei_host_to_me_data_pending(mei))
+ break;
- msleep(5);
- }
+ msleep(20);
+ }
- /*
- * If we couldn't make sure that CSME saw the HOST_GOES_DOWN message,
- * it means that it will probably keep reading memory that we are going
- * to unmap and free, expect IOMMU error messages.
- */
- if (i == SEND_SAP_MAX_WAIT_ITERATION)
- dev_err(&mei->cldev->dev,
- "Couldn't get ACK from CSME on HOST_GOES_DOWN message\n");
+ /*
+ * If we couldn't make sure that CSME saw the HOST_GOES_DOWN
+ * message, it means that it will probably keep reading memory
+ * that we are going to unmap and free, expect IOMMU error
+ * messages.
+ */
+ if (i == SEND_SAP_MAX_WAIT_ITERATION)
+ dev_err(&mei->cldev->dev,
+ "Couldn't get ACK from CSME on HOST_GOES_DOWN message\n");
+ }
mutex_unlock(&iwl_mei_mutex);
--
2.35.3
From: Johannes Berg <[email protected]>
If cloning the SKB fails, don't try to use it, but rather return
as if we should pass it.
Coverity CID: 1503456
Fixes: 2da4366f9e2c ("iwlwifi: mei: add the driver to allow cooperation with CSME")
Signed-off-by: Johannes Berg <[email protected]>
Signed-off-by: Gregory Greenman <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/mei/net.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/mei/net.c b/drivers/net/wireless/intel/iwlwifi/mei/net.c
index 3472167c8370..eac46d1a397a 100644
--- a/drivers/net/wireless/intel/iwlwifi/mei/net.c
+++ b/drivers/net/wireless/intel/iwlwifi/mei/net.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (C) 2021 Intel Corporation
+ * Copyright (C) 2021-2022 Intel Corporation
*/
#include <uapi/linux/if_ether.h>
@@ -337,10 +337,14 @@ rx_handler_result_t iwl_mei_rx_filter(struct sk_buff *orig_skb,
if (!*pass_to_csme)
return RX_HANDLER_PASS;
- if (ret == RX_HANDLER_PASS)
+ if (ret == RX_HANDLER_PASS) {
skb = skb_copy(orig_skb, GFP_ATOMIC);
- else
+
+ if (!skb)
+ return RX_HANDLER_PASS;
+ } else {
skb = orig_skb;
+ }
/* CSME wants the MAC header as well, push it back */
skb_push(skb, skb->data - skb_mac_header(skb));
--
2.35.3
From: Avraham Stern <[email protected]>
The AMT_STATE sap message handler tries to take the rtnl lock.
This means that in case the rtnl lock is already taken, sap messages
will not be processed.
When an interface is brought up, the host requests ownership from
csme. However, since the rtnl lock is already held, if there is a
pending amt state message, the host will not be able to read the
ownership confirm message because the amt state message handler
is pending. As a result, the host fails to get ownership although
csme granted it.
Fix it by moving the part that needs the rtnl lock into a dedicated
worker, so handling sap messages can continue.
Fixes: 2da4366f9e2c ("iwlwifi: mei: add the driver to allow cooperation with CSME")
Signed-off-by: Avraham Stern <[email protected]>
Signed-off-by: Gregory Greenman <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/mei/main.c | 57 ++++++++++++-------
1 file changed, 37 insertions(+), 20 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/mei/main.c b/drivers/net/wireless/intel/iwlwifi/mei/main.c
index 64a637ef199c..c0142093c768 100644
--- a/drivers/net/wireless/intel/iwlwifi/mei/main.c
+++ b/drivers/net/wireless/intel/iwlwifi/mei/main.c
@@ -152,6 +152,8 @@ struct iwl_mei_filters {
* @csa_throttle_end_wk: used when &csa_throttled is true
* @data_q_lock: protects the access to the data queues which are
* accessed without the mutex.
+ * @netdev_work: used to defer registering and unregistering of the netdev to
+ * avoid taking the rtnl lock in the SAP messages handlers.
* @sap_seq_no: the sequence number for the SAP messages
* @seq_no: the sequence number for the SAP messages
* @dbgfs_dir: the debugfs dir entry
@@ -172,6 +174,7 @@ struct iwl_mei {
bool device_down;
struct delayed_work csa_throttle_end_wk;
spinlock_t data_q_lock;
+ struct work_struct netdev_work;
atomic_t sap_seq_no;
atomic_t seq_no;
@@ -591,6 +594,33 @@ static rx_handler_result_t iwl_mei_rx_handler(struct sk_buff **pskb)
return res;
}
+static void iwl_mei_netdev_work(struct work_struct *wk)
+{
+ struct iwl_mei *mei =
+ container_of(wk, struct iwl_mei, netdev_work);
+ struct net_device *netdev;
+
+ /*
+ * First take rtnl and only then the mutex to avoid an ABBA
+ * with iwl_mei_set_netdev()
+ */
+ rtnl_lock();
+ mutex_lock(&iwl_mei_mutex);
+
+ netdev = rcu_dereference_protected(iwl_mei_cache.netdev,
+ lockdep_is_held(&iwl_mei_mutex));
+ if (netdev) {
+ if (mei->amt_enabled)
+ netdev_rx_handler_register(netdev, iwl_mei_rx_handler,
+ mei);
+ else
+ netdev_rx_handler_unregister(netdev);
+ }
+
+ mutex_unlock(&iwl_mei_mutex);
+ rtnl_unlock();
+}
+
static void
iwl_mei_handle_rx_start_ok(struct mei_cl_device *cldev,
const struct iwl_sap_me_msg_start_ok *rsp,
@@ -743,38 +773,23 @@ static void iwl_mei_handle_amt_state(struct mei_cl_device *cldev,
const struct iwl_sap_msg_dw *dw)
{
struct iwl_mei *mei = mei_cldev_get_drvdata(cldev);
- struct net_device *netdev;
- /*
- * First take rtnl and only then the mutex to avoid an ABBA
- * with iwl_mei_set_netdev()
- */
- rtnl_lock();
mutex_lock(&iwl_mei_mutex);
- netdev = rcu_dereference_protected(iwl_mei_cache.netdev,
- lockdep_is_held(&iwl_mei_mutex));
-
if (mei->amt_enabled == !!le32_to_cpu(dw->val))
goto out;
mei->amt_enabled = dw->val;
- if (mei->amt_enabled) {
- if (netdev)
- netdev_rx_handler_register(netdev, iwl_mei_rx_handler, mei);
-
+ if (mei->amt_enabled)
iwl_mei_set_init_conf(mei);
- } else {
- if (iwl_mei_cache.ops)
- iwl_mei_cache.ops->rfkill(iwl_mei_cache.priv, false);
- if (netdev)
- netdev_rx_handler_unregister(netdev);
- }
+ else if (iwl_mei_cache.ops)
+ iwl_mei_cache.ops->rfkill(iwl_mei_cache.priv, false, false);
+
+ schedule_work(&mei->netdev_work);
out:
mutex_unlock(&iwl_mei_mutex);
- rtnl_unlock();
}
static void iwl_mei_handle_nic_owner(struct mei_cl_device *cldev,
@@ -1827,6 +1842,7 @@ static int iwl_mei_probe(struct mei_cl_device *cldev,
iwl_mei_csa_throttle_end_wk);
init_waitqueue_head(&mei->get_ownership_wq);
spin_lock_init(&mei->data_q_lock);
+ INIT_WORK(&mei->netdev_work, iwl_mei_netdev_work);
mei_cldev_set_drvdata(cldev, mei);
mei->cldev = cldev;
@@ -1989,6 +2005,7 @@ static void iwl_mei_remove(struct mei_cl_device *cldev)
*/
cancel_work_sync(&mei->send_csa_msg_wk);
cancel_delayed_work_sync(&mei->csa_throttle_end_wk);
+ cancel_work_sync(&mei->netdev_work);
/*
* If someone waits for the ownership, let him know that we are going
--
2.35.3