Skip to content

Commit dddaa64

Browse files
Wen Gongkvalo
authored andcommitted
ath11k: add wait operation for tx management packets for flush from mac80211
In ath11k, tx of management packet is doing in a work queue. Sometimes the workqueue does not finish tx immediately, then it lead after the next step of vdev delete finished, it start to send the management packet to firmware and lead firmware crash. ieee80211_set_disassoc() have logic of ieee80211_flush_queues() after it send_deauth_disassoc() to ath11k, its purpose is make sure the deauth was actually sent, so it need to change ath11k to match the purpose of mac80211. To address these issue wait for tx mgmt as well as tx data packets. dmesg log of connect/disconnect to AP: [ 307.522226] wls1: authenticate with 62:66:e4:e9:6a:a9 [ 307.586565] wls1: send auth to 62:66:e4:e9:6a:a9 (try 1/3) [ 307.586581] ath11k_pci 0000:05:00.0: mac tx mgmt frame, buf id 0 [ 307.586922] ath11k_pci 0000:05:00.0: mac tx mgmt frame, vdev_id 0 [ 307.590179] ath11k_pci 0000:05:00.0: wmi mgmt tx comp pending 0 desc id 0 [ 307.590181] ath11k_pci 0000:05:00.0: mgmt tx compl ev pdev_id 2, desc_id 0, status 0 [ 307.598699] wls1: authenticated [ 307.599483] wls1: associate with 62:66:e4:e9:6a:a9 (try 1/3) [ 307.599506] ath11k_pci 0000:05:00.0: mac tx mgmt frame, buf id 0 [ 307.599519] ath11k_pci 0000:05:00.0: mac tx mgmt frame, vdev_id 0 [ 307.603059] ath11k_pci 0000:05:00.0: wmi mgmt tx comp pending 0 desc id 0 [ 307.603063] ath11k_pci 0000:05:00.0: mgmt tx compl ev pdev_id 2, desc_id 0, status 0 [ 307.637105] wls1: associated [ 317.365239] wls1: deauthenticating from 62:66:e4:e9:6a:a9 by local choice (Reason: 3=DEAUTH_LEAVING) [ 317.368104] ath11k_pci 0000:05:00.0: mac tx mgmt frame, buf id 0 [ 317.372622] ath11k_pci 0000:05:00.0: mac tx mgmt frame, vdev_id 0 [ 317.378320] ath11k_pci 0000:05:00.0: wmi mgmt tx comp pending 0 desc id 0 [ 317.378330] ath11k_pci 0000:05:00.0: mgmt tx compl ev pdev_id 2, desc_id 0, status 0 [ 317.378359] ath11k_pci 0000:05:00.0: mac mgmt tx flush mgmt pending 0 [ 317.421066] ath11k_pci 0000:05:00.0: mac mgmt tx flush mgmt pending 0 [ 317.421427] ath11k_pci 0000:05:00.0: mac remove interface (vdev 0) Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01230-QCAHSTSWPLZ_V2_TO_X86-1 Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 Signed-off-by: Wen Gong <[email protected]> Signed-off-by: Kalle Valo <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 6273c97 commit dddaa64

File tree

4 files changed

+55
-10
lines changed

4 files changed

+55
-10
lines changed

drivers/net/wireless/ath/ath11k/core.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1165,6 +1165,7 @@ static void ath11k_core_restart(struct work_struct *work)
11651165
idr_for_each(&ar->txmgmt_idr,
11661166
ath11k_mac_tx_mgmt_pending_free, ar);
11671167
idr_destroy(&ar->txmgmt_idr);
1168+
wake_up(&ar->txmgmt_empty_waitq);
11681169
}
11691170

11701171
wake_up(&ab->wmi_ab.tx_credits_wq);

drivers/net/wireless/ath/ath11k/core.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,7 @@ struct ath11k {
550550
/* protects txmgmt_idr data */
551551
spinlock_t txmgmt_idr_lock;
552552
atomic_t num_pending_mgmt_tx;
553+
wait_queue_head_t txmgmt_empty_waitq;
553554

554555
/* cycle count is reported twice for each visited channel during scan.
555556
* access protected by data_lock

drivers/net/wireless/ath/ath11k/mac.c

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5265,6 +5265,21 @@ static int __ath11k_set_antenna(struct ath11k *ar, u32 tx_ant, u32 rx_ant)
52655265
return 0;
52665266
}
52675267

5268+
static void ath11k_mgmt_over_wmi_tx_drop(struct ath11k *ar, struct sk_buff *skb)
5269+
{
5270+
int num_mgmt;
5271+
5272+
ieee80211_free_txskb(ar->hw, skb);
5273+
5274+
num_mgmt = atomic_dec_if_positive(&ar->num_pending_mgmt_tx);
5275+
5276+
if (num_mgmt < 0)
5277+
WARN_ON_ONCE(1);
5278+
5279+
if (!num_mgmt)
5280+
wake_up(&ar->txmgmt_empty_waitq);
5281+
}
5282+
52685283
static void ath11k_mac_tx_mgmt_free(struct ath11k *ar, int buf_id)
52695284
{
52705285
struct sk_buff *msdu;
@@ -5283,7 +5298,7 @@ static void ath11k_mac_tx_mgmt_free(struct ath11k *ar, int buf_id)
52835298
info = IEEE80211_SKB_CB(msdu);
52845299
memset(&info->status, 0, sizeof(info->status));
52855300

5286-
ieee80211_free_txskb(ar->hw, msdu);
5301+
ath11k_mgmt_over_wmi_tx_drop(ar, msdu);
52875302
}
52885303

52895304
int ath11k_mac_tx_mgmt_pending_free(int buf_id, void *skb, void *ctx)
@@ -5323,6 +5338,10 @@ static int ath11k_mac_mgmt_tx_wmi(struct ath11k *ar, struct ath11k_vif *arvif,
53235338
buf_id = idr_alloc(&ar->txmgmt_idr, skb, 0,
53245339
ATH11K_TX_MGMT_NUM_PENDING_MAX, GFP_ATOMIC);
53255340
spin_unlock_bh(&ar->txmgmt_idr_lock);
5341+
5342+
ath11k_dbg(ar->ab, ATH11K_DBG_MAC,
5343+
"mac tx mgmt frame, buf id %d\n", buf_id);
5344+
53265345
if (buf_id < 0)
53275346
return -ENOSPC;
53285347

@@ -5369,7 +5388,7 @@ static void ath11k_mgmt_over_wmi_tx_purge(struct ath11k *ar)
53695388
struct sk_buff *skb;
53705389

53715390
while ((skb = skb_dequeue(&ar->wmi_mgmt_tx_queue)) != NULL)
5372-
ieee80211_free_txskb(ar->hw, skb);
5391+
ath11k_mgmt_over_wmi_tx_drop(ar, skb);
53735392
}
53745393

53755394
static void ath11k_mgmt_over_wmi_tx_work(struct work_struct *work)
@@ -5384,29 +5403,29 @@ static void ath11k_mgmt_over_wmi_tx_work(struct work_struct *work)
53845403
skb_cb = ATH11K_SKB_CB(skb);
53855404
if (!skb_cb->vif) {
53865405
ath11k_warn(ar->ab, "no vif found for mgmt frame\n");
5387-
ieee80211_free_txskb(ar->hw, skb);
5406+
ath11k_mgmt_over_wmi_tx_drop(ar, skb);
53885407
continue;
53895408
}
53905409

53915410
arvif = ath11k_vif_to_arvif(skb_cb->vif);
53925411
if (ar->allocated_vdev_map & (1LL << arvif->vdev_id) &&
53935412
arvif->is_started) {
5394-
atomic_inc(&ar->num_pending_mgmt_tx);
53955413
ret = ath11k_mac_mgmt_tx_wmi(ar, arvif, skb);
53965414
if (ret) {
5397-
if (atomic_dec_if_positive(&ar->num_pending_mgmt_tx) < 0)
5398-
WARN_ON_ONCE(1);
5399-
54005415
ath11k_warn(ar->ab, "failed to tx mgmt frame, vdev_id %d :%d\n",
54015416
arvif->vdev_id, ret);
5402-
ieee80211_free_txskb(ar->hw, skb);
5417+
ath11k_mgmt_over_wmi_tx_drop(ar, skb);
5418+
} else {
5419+
ath11k_dbg(ar->ab, ATH11K_DBG_MAC,
5420+
"mac tx mgmt frame, vdev_id %d\n",
5421+
arvif->vdev_id);
54035422
}
54045423
} else {
54055424
ath11k_warn(ar->ab,
54065425
"dropping mgmt frame for vdev %d, is_started %d\n",
54075426
arvif->vdev_id,
54085427
arvif->is_started);
5409-
ieee80211_free_txskb(ar->hw, skb);
5428+
ath11k_mgmt_over_wmi_tx_drop(ar, skb);
54105429
}
54115430
}
54125431
}
@@ -5437,6 +5456,7 @@ static int ath11k_mac_mgmt_tx(struct ath11k *ar, struct sk_buff *skb,
54375456
}
54385457

54395458
skb_queue_tail(q, skb);
5459+
atomic_inc(&ar->num_pending_mgmt_tx);
54405460
ieee80211_queue_work(ar->hw, &ar->wmi_mgmt_tx_work);
54415461

54425462
return 0;
@@ -7023,6 +7043,17 @@ static void ath11k_mac_op_flush(struct ieee80211_hw *hw, struct ieee80211_vif *v
70237043
ATH11K_FLUSH_TIMEOUT);
70247044
if (time_left == 0)
70257045
ath11k_warn(ar->ab, "failed to flush transmit queue %ld\n", time_left);
7046+
7047+
time_left = wait_event_timeout(ar->txmgmt_empty_waitq,
7048+
(atomic_read(&ar->num_pending_mgmt_tx) == 0),
7049+
ATH11K_FLUSH_TIMEOUT);
7050+
if (time_left == 0)
7051+
ath11k_warn(ar->ab, "failed to flush mgmt transmit queue %ld\n",
7052+
time_left);
7053+
7054+
ath11k_dbg(ar->ab, ATH11K_DBG_MAC,
7055+
"mac mgmt tx flush mgmt pending %d\n",
7056+
atomic_read(&ar->num_pending_mgmt_tx));
70267057
}
70277058

70287059
static int
@@ -8261,6 +8292,8 @@ int ath11k_mac_register(struct ath11k_base *ab)
82618292
ret = __ath11k_mac_register(ar);
82628293
if (ret)
82638294
goto err_cleanup;
8295+
8296+
init_waitqueue_head(&ar->txmgmt_empty_waitq);
82648297
}
82658298

82668299
return 0;

drivers/net/wireless/ath/ath11k/wmi.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4980,6 +4980,7 @@ static int wmi_process_mgmt_tx_comp(struct ath11k *ar, u32 desc_id,
49804980
struct sk_buff *msdu;
49814981
struct ieee80211_tx_info *info;
49824982
struct ath11k_skb_cb *skb_cb;
4983+
int num_mgmt;
49834984

49844985
spin_lock_bh(&ar->txmgmt_idr_lock);
49854986
msdu = idr_find(&ar->txmgmt_idr, desc_id);
@@ -5003,10 +5004,19 @@ static int wmi_process_mgmt_tx_comp(struct ath11k *ar, u32 desc_id,
50035004

50045005
ieee80211_tx_status_irqsafe(ar->hw, msdu);
50055006

5007+
num_mgmt = atomic_dec_if_positive(&ar->num_pending_mgmt_tx);
5008+
50065009
/* WARN when we received this event without doing any mgmt tx */
5007-
if (atomic_dec_if_positive(&ar->num_pending_mgmt_tx) < 0)
5010+
if (num_mgmt < 0)
50085011
WARN_ON_ONCE(1);
50095012

5013+
ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
5014+
"wmi mgmt tx comp pending %d desc id %d\n",
5015+
num_mgmt, desc_id);
5016+
5017+
if (!num_mgmt)
5018+
wake_up(&ar->txmgmt_empty_waitq);
5019+
50105020
return 0;
50115021
}
50125022

0 commit comments

Comments
 (0)