Skip to content

Commit dc40515

Browse files
Rakesh PillaiKalle Valo
authored andcommitted
ath10k: handle mgmt tx completion event
WCN3990 transmits management frames via WMI with reference. Currently, with the management tx completion not being handled, these frames are not getting freed even after the transmission status is returned by the firmware. The transmitted management frames should be freed when the firmware sends the over-the-air tx status of the corresponding management frames. Handle the wmi mgmt tx completion event and free the corresponding management frame. Tested HW: WCN3990 Tested FW: WLAN.HL.2.0-01188-QCAHLSWMTPLZ-1 Signed-off-by: Rakesh Pillai <[email protected]> Signed-off-by: Kalle Valo <[email protected]>
1 parent 673bc51 commit dc40515

8 files changed

Lines changed: 186 additions & 2 deletions

File tree

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2095,6 +2095,7 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar)
20952095
ar->fw_stats_req_mask = WMI_STAT_PDEV | WMI_STAT_VDEV |
20962096
WMI_STAT_PEER;
20972097
ar->max_spatial_stream = WMI_MAX_SPATIAL_STREAM;
2098+
ar->wmi.mgmt_max_num_pending_tx = TARGET_TLV_MGMT_NUM_MSDU_DESC;
20982099
break;
20992100
case ATH10K_FW_WMI_OP_VERSION_10_4:
21002101
ar->max_num_peers = TARGET_10_4_NUM_PEERS;

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,11 @@ struct ath10k_wmi {
186186
const struct wmi_ops *ops;
187187
const struct wmi_peer_flags_map *peer_flags;
188188

189+
u32 mgmt_max_num_pending_tx;
190+
191+
/* Protected by data_lock */
192+
struct idr mgmt_pending_tx;
193+
189194
u32 num_mem_chunks;
190195
u32 rx_decap_mode;
191196
struct ath10k_mem_chunk mem_chunks[WMI_MAX_MEM_REQS];

drivers/net/wireless/ath/ath10k/hw.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -699,6 +699,7 @@ ath10k_rx_desc_get_l3_pad_bytes(struct ath10k_hw_params *hw,
699699
#define TARGET_TLV_NUM_TIDS ((TARGET_TLV_NUM_PEERS) * 2)
700700
#define TARGET_TLV_NUM_MSDU_DESC (1024 + 32)
701701
#define TARGET_TLV_NUM_WOW_PATTERNS 22
702+
#define TARGET_TLV_MGMT_NUM_MSDU_DESC (50)
702703

703704
/* Target specific defines for WMI-HL-1.0 firmware */
704705
#define TARGET_HL_10_TLV_NUM_PEERS 14

drivers/net/wireless/ath/ath10k/wmi-ops.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ struct wmi_ops {
3131
struct wmi_scan_ev_arg *arg);
3232
int (*pull_mgmt_rx)(struct ath10k *ar, struct sk_buff *skb,
3333
struct wmi_mgmt_rx_ev_arg *arg);
34+
int (*pull_mgmt_tx_compl)(struct ath10k *ar, struct sk_buff *skb,
35+
struct wmi_tlv_mgmt_tx_compl_ev_arg *arg);
3436
int (*pull_ch_info)(struct ath10k *ar, struct sk_buff *skb,
3537
struct wmi_ch_info_ev_arg *arg);
3638
int (*pull_vdev_start)(struct ath10k *ar, struct sk_buff *skb,
@@ -261,6 +263,16 @@ ath10k_wmi_pull_scan(struct ath10k *ar, struct sk_buff *skb,
261263
return ar->wmi.ops->pull_scan(ar, skb, arg);
262264
}
263265

266+
static inline int
267+
ath10k_wmi_pull_mgmt_tx_compl(struct ath10k *ar, struct sk_buff *skb,
268+
struct wmi_tlv_mgmt_tx_compl_ev_arg *arg)
269+
{
270+
if (!ar->wmi.ops->pull_mgmt_tx_compl)
271+
return -EOPNOTSUPP;
272+
273+
return ar->wmi.ops->pull_mgmt_tx_compl(ar, skb, arg);
274+
}
275+
264276
static inline int
265277
ath10k_wmi_pull_mgmt_rx(struct ath10k *ar, struct sk_buff *skb,
266278
struct wmi_mgmt_rx_ev_arg *arg)

drivers/net/wireless/ath/ath10k/wmi-tlv.c

Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -618,6 +618,9 @@ static void ath10k_wmi_tlv_op_rx(struct ath10k *ar, struct sk_buff *skb)
618618
case WMI_TLV_TDLS_PEER_EVENTID:
619619
ath10k_wmi_event_tdls_peer(ar, skb);
620620
break;
621+
case WMI_TLV_MGMT_TX_COMPLETION_EVENTID:
622+
ath10k_wmi_event_mgmt_tx_compl(ar, skb);
623+
break;
621624
default:
622625
ath10k_warn(ar, "Unknown eventid: %d\n", id);
623626
break;
@@ -659,6 +662,31 @@ static int ath10k_wmi_tlv_op_pull_scan_ev(struct ath10k *ar,
659662
return 0;
660663
}
661664

665+
static int
666+
ath10k_wmi_tlv_op_pull_mgmt_tx_compl_ev(struct ath10k *ar, struct sk_buff *skb,
667+
struct wmi_tlv_mgmt_tx_compl_ev_arg *arg)
668+
{
669+
const void **tb;
670+
const struct wmi_tlv_mgmt_tx_compl_ev *ev;
671+
int ret;
672+
673+
tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC);
674+
if (IS_ERR(tb)) {
675+
ret = PTR_ERR(tb);
676+
ath10k_warn(ar, "failed to parse tlv: %d\n", ret);
677+
return ret;
678+
}
679+
680+
ev = tb[WMI_TLV_TAG_STRUCT_MGMT_TX_COMPL_EVENT];
681+
682+
arg->desc_id = ev->desc_id;
683+
arg->status = ev->status;
684+
arg->pdev_id = ev->pdev_id;
685+
686+
kfree(tb);
687+
return 0;
688+
}
689+
662690
static int ath10k_wmi_tlv_op_pull_mgmt_rx_ev(struct ath10k *ar,
663691
struct sk_buff *skb,
664692
struct wmi_mgmt_rx_ev_arg *arg)
@@ -2612,6 +2640,30 @@ ath10k_wmi_tlv_op_gen_request_stats(struct ath10k *ar, u32 stats_mask)
26122640
return skb;
26132641
}
26142642

2643+
static int
2644+
ath10k_wmi_mgmt_tx_alloc_msdu_id(struct ath10k *ar, struct sk_buff *skb,
2645+
dma_addr_t paddr)
2646+
{
2647+
struct ath10k_wmi *wmi = &ar->wmi;
2648+
struct ath10k_mgmt_tx_pkt_addr *pkt_addr;
2649+
int ret;
2650+
2651+
pkt_addr = kmalloc(sizeof(*pkt_addr), GFP_ATOMIC);
2652+
if (!pkt_addr)
2653+
return -ENOMEM;
2654+
2655+
pkt_addr->vaddr = skb;
2656+
pkt_addr->paddr = paddr;
2657+
2658+
spin_lock_bh(&ar->data_lock);
2659+
ret = idr_alloc(&wmi->mgmt_pending_tx, pkt_addr, 0,
2660+
wmi->mgmt_max_num_pending_tx, GFP_ATOMIC);
2661+
spin_unlock_bh(&ar->data_lock);
2662+
2663+
ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi mgmt tx alloc msdu_id ret %d\n", ret);
2664+
return ret;
2665+
}
2666+
26152667
static struct sk_buff *
26162668
ath10k_wmi_tlv_op_gen_mgmt_tx_send(struct ath10k *ar, struct sk_buff *msdu,
26172669
dma_addr_t paddr)
@@ -2623,9 +2675,9 @@ ath10k_wmi_tlv_op_gen_mgmt_tx_send(struct ath10k *ar, struct sk_buff *msdu,
26232675
u32 buf_len = msdu->len;
26242676
struct wmi_tlv *tlv;
26252677
struct sk_buff *skb;
2678+
int len, desc_id;
26262679
u32 vdev_id;
26272680
void *ptr;
2628-
int len;
26292681

26302682
if (!cb->vif)
26312683
return ERR_PTR(-EINVAL);
@@ -2656,13 +2708,17 @@ ath10k_wmi_tlv_op_gen_mgmt_tx_send(struct ath10k *ar, struct sk_buff *msdu,
26562708
if (!skb)
26572709
return ERR_PTR(-ENOMEM);
26582710

2711+
desc_id = ath10k_wmi_mgmt_tx_alloc_msdu_id(ar, msdu, paddr);
2712+
if (desc_id < 0)
2713+
goto err_free_skb;
2714+
26592715
ptr = (void *)skb->data;
26602716
tlv = ptr;
26612717
tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_MGMT_TX_CMD);
26622718
tlv->len = __cpu_to_le16(sizeof(*cmd));
26632719
cmd = (void *)tlv->value;
26642720
cmd->vdev_id = __cpu_to_le32(vdev_id);
2665-
cmd->desc_id = 0;
2721+
cmd->desc_id = __cpu_to_le32(desc_id);
26662722
cmd->chanfreq = 0;
26672723
cmd->buf_len = __cpu_to_le32(buf_len);
26682724
cmd->frame_len = __cpu_to_le32(msdu->len);
@@ -2679,6 +2735,10 @@ ath10k_wmi_tlv_op_gen_mgmt_tx_send(struct ath10k *ar, struct sk_buff *msdu,
26792735
memcpy(ptr, msdu->data, buf_len);
26802736

26812737
return skb;
2738+
2739+
err_free_skb:
2740+
dev_kfree_skb(skb);
2741+
return ERR_PTR(desc_id);
26822742
}
26832743

26842744
static struct sk_buff *
@@ -3843,6 +3903,7 @@ static const struct wmi_ops wmi_tlv_ops = {
38433903

38443904
.pull_scan = ath10k_wmi_tlv_op_pull_scan_ev,
38453905
.pull_mgmt_rx = ath10k_wmi_tlv_op_pull_mgmt_rx_ev,
3906+
.pull_mgmt_tx_compl = ath10k_wmi_tlv_op_pull_mgmt_tx_compl_ev,
38463907
.pull_ch_info = ath10k_wmi_tlv_op_pull_ch_info_ev,
38473908
.pull_vdev_start = ath10k_wmi_tlv_op_pull_vdev_start_ev,
38483909
.pull_peer_kick = ath10k_wmi_tlv_op_pull_peer_kick_ev,

drivers/net/wireless/ath/ath10k/wmi-tlv.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,7 @@ enum wmi_tlv_event_id {
320320
WMI_TLV_TBTTOFFSET_UPDATE_EVENTID,
321321
WMI_TLV_OFFLOAD_BCN_TX_STATUS_EVENTID,
322322
WMI_TLV_OFFLOAD_PROB_RESP_TX_STATUS_EVENTID,
323+
WMI_TLV_MGMT_TX_COMPLETION_EVENTID,
323324
WMI_TLV_TX_DELBA_COMPLETE_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_BA_NEG),
324325
WMI_TLV_TX_ADDBA_COMPLETE_EVENTID,
325326
WMI_TLV_BA_RSP_SSN_EVENTID,
@@ -1573,6 +1574,17 @@ struct wmi_tlv {
15731574
u8 value[0];
15741575
} __packed;
15751576

1577+
struct ath10k_mgmt_tx_pkt_addr {
1578+
void *vaddr;
1579+
dma_addr_t paddr;
1580+
};
1581+
1582+
struct wmi_tlv_mgmt_tx_compl_ev {
1583+
__le32 desc_id;
1584+
__le32 status;
1585+
__le32 pdev_id;
1586+
};
1587+
15761588
#define WMI_TLV_MGMT_RX_NUM_RSSI 4
15771589

15781590
struct wmi_tlv_mgmt_rx_ev {

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

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2313,6 +2313,59 @@ static bool ath10k_wmi_rx_is_decrypted(struct ath10k *ar,
23132313
return true;
23142314
}
23152315

2316+
static int wmi_process_mgmt_tx_comp(struct ath10k *ar, u32 desc_id,
2317+
u32 status)
2318+
{
2319+
struct ath10k_mgmt_tx_pkt_addr *pkt_addr;
2320+
struct ath10k_wmi *wmi = &ar->wmi;
2321+
struct ieee80211_tx_info *info;
2322+
struct sk_buff *msdu;
2323+
int ret;
2324+
2325+
spin_lock_bh(&ar->data_lock);
2326+
2327+
pkt_addr = idr_find(&wmi->mgmt_pending_tx, desc_id);
2328+
if (!pkt_addr) {
2329+
ath10k_warn(ar, "received mgmt tx completion for invalid msdu_id: %d\n",
2330+
desc_id);
2331+
ret = -ENOENT;
2332+
goto out;
2333+
}
2334+
2335+
msdu = pkt_addr->vaddr;
2336+
dma_unmap_single(ar->dev, pkt_addr->paddr,
2337+
msdu->len, DMA_FROM_DEVICE);
2338+
info = IEEE80211_SKB_CB(msdu);
2339+
info->flags |= status;
2340+
ieee80211_tx_status_irqsafe(ar->hw, msdu);
2341+
2342+
ret = 0;
2343+
2344+
out:
2345+
idr_remove(&wmi->mgmt_pending_tx, desc_id);
2346+
spin_unlock_bh(&ar->data_lock);
2347+
return ret;
2348+
}
2349+
2350+
int ath10k_wmi_event_mgmt_tx_compl(struct ath10k *ar, struct sk_buff *skb)
2351+
{
2352+
struct wmi_tlv_mgmt_tx_compl_ev_arg arg;
2353+
int ret;
2354+
2355+
ret = ath10k_wmi_pull_mgmt_tx_compl(ar, skb, &arg);
2356+
if (ret) {
2357+
ath10k_warn(ar, "failed to parse mgmt comp event: %d\n", ret);
2358+
return ret;
2359+
}
2360+
2361+
wmi_process_mgmt_tx_comp(ar, __le32_to_cpu(arg.desc_id),
2362+
__le32_to_cpu(arg.status));
2363+
2364+
ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv evnt mgmt tx completion\n");
2365+
2366+
return 0;
2367+
}
2368+
23162369
int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
23172370
{
23182371
struct wmi_mgmt_rx_ev_arg arg = {};
@@ -9073,6 +9126,11 @@ int ath10k_wmi_attach(struct ath10k *ar)
90739126
INIT_WORK(&ar->radar_confirmation_work,
90749127
ath10k_radar_confirmation_work);
90759128

9129+
if (test_bit(ATH10K_FW_FEATURE_MGMT_TX_BY_REF,
9130+
ar->running_fw->fw_file.fw_features)) {
9131+
idr_init(&ar->wmi.mgmt_pending_tx);
9132+
}
9133+
90769134
return 0;
90779135
}
90789136

@@ -9091,8 +9149,35 @@ void ath10k_wmi_free_host_mem(struct ath10k *ar)
90919149
ar->wmi.num_mem_chunks = 0;
90929150
}
90939151

9152+
static int ath10k_wmi_mgmt_tx_clean_up_pending(int msdu_id, void *ptr,
9153+
void *ctx)
9154+
{
9155+
struct ath10k_mgmt_tx_pkt_addr *pkt_addr = ptr;
9156+
struct ath10k *ar = ctx;
9157+
struct sk_buff *msdu;
9158+
9159+
ath10k_dbg(ar, ATH10K_DBG_WMI,
9160+
"force cleanup mgmt msdu_id %hu\n", msdu_id);
9161+
9162+
msdu = pkt_addr->vaddr;
9163+
dma_unmap_single(ar->dev, pkt_addr->paddr,
9164+
msdu->len, DMA_FROM_DEVICE);
9165+
ieee80211_free_txskb(ar->hw, msdu);
9166+
9167+
return 0;
9168+
}
9169+
90949170
void ath10k_wmi_detach(struct ath10k *ar)
90959171
{
9172+
if (test_bit(ATH10K_FW_FEATURE_MGMT_TX_BY_REF,
9173+
ar->running_fw->fw_file.fw_features)) {
9174+
spin_lock_bh(&ar->data_lock);
9175+
idr_for_each(&ar->wmi.mgmt_pending_tx,
9176+
ath10k_wmi_mgmt_tx_clean_up_pending, ar);
9177+
idr_destroy(&ar->wmi.mgmt_pending_tx);
9178+
spin_unlock_bh(&ar->data_lock);
9179+
}
9180+
90969181
cancel_work_sync(&ar->svc_rdy_work);
90979182

90989183
if (ar->svc_rdy_skb)

drivers/net/wireless/ath/ath10k/wmi.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6600,6 +6600,12 @@ struct wmi_scan_ev_arg {
66006600
__le32 vdev_id;
66016601
};
66026602

6603+
struct wmi_tlv_mgmt_tx_compl_ev_arg {
6604+
__le32 desc_id;
6605+
__le32 status;
6606+
__le32 pdev_id;
6607+
};
6608+
66036609
struct wmi_mgmt_rx_ev_arg {
66046610
__le32 channel;
66056611
__le32 snr;
@@ -7071,6 +7077,7 @@ int ath10k_wmi_start_scan_verify(const struct wmi_start_scan_arg *arg);
70717077

70727078
int ath10k_wmi_event_scan(struct ath10k *ar, struct sk_buff *skb);
70737079
int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb);
7080+
int ath10k_wmi_event_mgmt_tx_compl(struct ath10k *ar, struct sk_buff *skb);
70747081
void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb);
70757082
void ath10k_wmi_event_echo(struct ath10k *ar, struct sk_buff *skb);
70767083
int ath10k_wmi_event_debug_mesg(struct ath10k *ar, struct sk_buff *skb);

0 commit comments

Comments
 (0)