summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRakesh Pillai <pillair@codeaurora.org>2020-05-08 05:55:18 +0300
committerKalle Valo <kvalo@codeaurora.org>2020-05-11 15:32:28 +0300
commitc730c477176ad4af86d9aae4d360a7ad840b073a (patch)
tree4998513557983da1edc48a7396a834114007f2b8
parent7c6d67b136ceb0aebc7a3153b300e925ed915daf (diff)
ath10k: Remove msdu from idr when management pkt send fails
Currently when the sending of any management pkt via wmi command fails, the packet is being unmapped freed in the error handling. But the idr entry added, which is used to track these packet is not getting removed. Hence, during unload, in wmi cleanup, all the entries in IDR are removed and the corresponding buffer is attempted to be freed. This can cause a situation where one packet is attempted to be freed twice. Fix this error by rmeoving the msdu from the idr list when the sending of a management packet over wmi fails. Tested HW: WCN3990 Tested FW: WLAN.HL.3.1-01040-QCAHLSWMTPLZ-1 Fixes: 1807da49733e ("ath10k: wmi: add management tx by reference support over wmi") Signed-off-by: Rakesh Pillai <pillair@codeaurora.org> Signed-off-by: Kalle Valo <kvalo@codeaurora.org> Link: https://lore.kernel.org/r/1588667015-25490-1-git-send-email-pillair@codeaurora.org
-rw-r--r--drivers/net/wireless/ath/ath10k/mac.c3
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi-ops.h10
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi-tlv.c15
3 files changed, 28 insertions, 0 deletions
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 91f5444ecedb..919d15584d4a 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -3967,6 +3967,9 @@ void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work)
if (ret) {
ath10k_warn(ar, "failed to transmit management frame by ref via WMI: %d\n",
ret);
+ /* remove this msdu from idr tracking */
+ ath10k_wmi_cleanup_mgmt_tx_send(ar, skb);
+
dma_unmap_single(ar->dev, paddr, skb->len,
DMA_TO_DEVICE);
ieee80211_free_txskb(ar->hw, skb);
diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h
index 6b730f59fd5b..0dd484f85082 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-ops.h
+++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h
@@ -140,6 +140,7 @@ struct wmi_ops {
struct sk_buff *(*gen_mgmt_tx_send)(struct ath10k *ar,
struct sk_buff *skb,
dma_addr_t paddr);
+ int (*cleanup_mgmt_tx_send)(struct ath10k *ar, struct sk_buff *msdu);
struct sk_buff *(*gen_dbglog_cfg)(struct ath10k *ar, u64 module_enable,
u32 log_level);
struct sk_buff *(*gen_pktlog_enable)(struct ath10k *ar, u32 filter);
@@ -449,6 +450,15 @@ ath10k_wmi_get_txbf_conf_scheme(struct ath10k *ar)
}
static inline int
+ath10k_wmi_cleanup_mgmt_tx_send(struct ath10k *ar, struct sk_buff *msdu)
+{
+ if (!ar->wmi.ops->cleanup_mgmt_tx_send)
+ return -EOPNOTSUPP;
+
+ return ar->wmi.ops->cleanup_mgmt_tx_send(ar, msdu);
+}
+
+static inline int
ath10k_wmi_mgmt_tx_send(struct ath10k *ar, struct sk_buff *msdu,
dma_addr_t paddr)
{
diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
index 9187b62b331c..afa03cb3aaf5 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
@@ -3016,6 +3016,18 @@ ath10k_wmi_tlv_op_gen_request_peer_stats_info(struct ath10k *ar,
}
static int
+ath10k_wmi_tlv_op_cleanup_mgmt_tx_send(struct ath10k *ar,
+ struct sk_buff *msdu)
+{
+ struct ath10k_skb_cb *cb = ATH10K_SKB_CB(msdu);
+ struct ath10k_wmi *wmi = &ar->wmi;
+
+ idr_remove(&wmi->mgmt_pending_tx, cb->msdu_id);
+
+ return 0;
+}
+
+static int
ath10k_wmi_mgmt_tx_alloc_msdu_id(struct ath10k *ar, struct sk_buff *skb,
dma_addr_t paddr)
{
@@ -3089,6 +3101,8 @@ ath10k_wmi_tlv_op_gen_mgmt_tx_send(struct ath10k *ar, struct sk_buff *msdu,
if (desc_id < 0)
goto err_free_skb;
+ cb->msdu_id = desc_id;
+
ptr = (void *)skb->data;
tlv = ptr;
tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_MGMT_TX_CMD);
@@ -4540,6 +4554,7 @@ static const struct wmi_ops wmi_tlv_ops = {
.gen_force_fw_hang = ath10k_wmi_tlv_op_gen_force_fw_hang,
/* .gen_mgmt_tx = not implemented; HTT is used */
.gen_mgmt_tx_send = ath10k_wmi_tlv_op_gen_mgmt_tx_send,
+ .cleanup_mgmt_tx_send = ath10k_wmi_tlv_op_cleanup_mgmt_tx_send,
.gen_dbglog_cfg = ath10k_wmi_tlv_op_gen_dbglog_cfg,
.gen_pktlog_enable = ath10k_wmi_tlv_op_gen_pktlog_enable,
.gen_pktlog_disable = ath10k_wmi_tlv_op_gen_pktlog_disable,