Skip to content

Commit 704c132

Browse files
Venkateswara NaralasettyRealzhq
authored andcommitted
FROMGIT: wifi: ath11k: Register DBR event handler for CFR data
Add handler for WMI_PDEV_DMA_RING_BUF_RELEASE_EVENT which indicates CFR data availability in the DB ring. Add CFR data processing from DB ring buffers. Use correlate_and_relay API to match CFR data with metadata from WMI_PEER_CFR_CAPTURE_EVENT. Release buffer to userspace through relayfs on successful correlation, otherwise hold buffer waiting for matching WMI event from firmware. Add new debug masks: - ATH11K_DBG_CFR: Enables CFR-related debug logs. - ATH11K_DBG_CFR_DUMP: Enables detailed CFR data dump for analysis. Tested-on: IPQ8074 hw2.0 PCI IPQ8074 WLAN.HK.2.5.0.1-00991-QCAHKSWPL_SILICONZ-1 Tested-on: WCN6855 hw2.1 PCI WLAN.HSP.1.1-04685-QCAHSPSWPL_V1_V2_SILICONZ_IOE-1 Signed-off-by: Venkateswara Naralasetty <quic_vnaralas@quicinc.com> Co-developed-by: Yu Zhang (Yuriy) <yu.zhang@oss.qualcomm.com> Signed-off-by: Yu Zhang (Yuriy) <yu.zhang@oss.qualcomm.com> Reviewed-by: Vasanthakumar Thiagarajan <vasanthakumar.thiagarajan@oss.qualcomm.com> Reviewed-by: Baochen Qiang <baochen.qiang@oss.qualcomm.com> Signed-off-by: Qian Zhang <qian.zhang@oss.qualcomm.com> Link: https://patch.msgid.link/20251230082520.3401007-3-qian.zhang@oss.qualcomm.com Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
1 parent c6db66f commit 704c132

5 files changed

Lines changed: 339 additions & 3 deletions

File tree

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

Lines changed: 239 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,248 @@
88
#include "core.h"
99
#include "debug.h"
1010

11+
struct ath11k_dbring *ath11k_cfr_get_dbring(struct ath11k *ar)
12+
{
13+
if (ar->cfr_enabled)
14+
return &ar->cfr.rx_ring;
15+
16+
return NULL;
17+
}
18+
19+
static int ath11k_cfr_calculate_tones_from_dma_hdr(struct ath11k_cfr_dma_hdr *hdr)
20+
{
21+
u8 bw = FIELD_GET(CFIR_DMA_HDR_INFO1_UPLOAD_PKT_BW, hdr->info1);
22+
u8 preamble = FIELD_GET(CFIR_DMA_HDR_INFO1_PREAMBLE_TYPE, hdr->info1);
23+
24+
switch (preamble) {
25+
case ATH11K_CFR_PREAMBLE_TYPE_LEGACY:
26+
fallthrough;
27+
case ATH11K_CFR_PREAMBLE_TYPE_VHT:
28+
switch (bw) {
29+
case 0:
30+
return TONES_IN_20MHZ;
31+
case 1: /* DUP40/VHT40 */
32+
return TONES_IN_40MHZ;
33+
case 2: /* DUP80/VHT80 */
34+
return TONES_IN_80MHZ;
35+
case 3: /* DUP160/VHT160 */
36+
return TONES_IN_160MHZ;
37+
default:
38+
return TONES_INVALID;
39+
}
40+
case ATH11K_CFR_PREAMBLE_TYPE_HT:
41+
switch (bw) {
42+
case 0:
43+
return TONES_IN_20MHZ;
44+
case 1:
45+
return TONES_IN_40MHZ;
46+
default:
47+
return TONES_INVALID;
48+
}
49+
default:
50+
return TONES_INVALID;
51+
}
52+
}
53+
54+
void ath11k_cfr_release_lut_entry(struct ath11k_look_up_table *lut)
55+
{
56+
memset(lut, 0, sizeof(*lut));
57+
}
58+
59+
static void ath11k_cfr_rfs_write(struct ath11k *ar, const void *head,
60+
u32 head_len, const void *data, u32 data_len,
61+
const void *tail, int tail_data)
62+
{
63+
struct ath11k_cfr *cfr = &ar->cfr;
64+
65+
if (!cfr->rfs_cfr_capture)
66+
return;
67+
68+
relay_write(cfr->rfs_cfr_capture, head, head_len);
69+
relay_write(cfr->rfs_cfr_capture, data, data_len);
70+
relay_write(cfr->rfs_cfr_capture, tail, tail_data);
71+
relay_flush(cfr->rfs_cfr_capture);
72+
}
73+
74+
static void ath11k_cfr_free_pending_dbr_events(struct ath11k *ar)
75+
{
76+
struct ath11k_cfr *cfr = &ar->cfr;
77+
struct ath11k_look_up_table *lut;
78+
int i;
79+
80+
if (!cfr->lut)
81+
return;
82+
83+
for (i = 0; i < cfr->lut_num; i++) {
84+
lut = &cfr->lut[i];
85+
if (lut->dbr_recv && !lut->tx_recv &&
86+
lut->dbr_tstamp < cfr->last_success_tstamp) {
87+
ath11k_dbring_bufs_replenish(ar, &cfr->rx_ring, lut->buff,
88+
WMI_DIRECT_BUF_CFR);
89+
ath11k_cfr_release_lut_entry(lut);
90+
cfr->flush_dbr_cnt++;
91+
}
92+
}
93+
}
94+
95+
/**
96+
* ath11k_cfr_correlate_and_relay() - Correlate and relay CFR events
97+
* @ar: Pointer to ath11k structure
98+
* @lut: Lookup table for correlation
99+
* @event_type: Type of event received (TX or DBR)
100+
*
101+
* Correlates WMI_PDEV_DMA_RING_BUF_RELEASE_EVENT (DBR) and
102+
* WMI_PEER_CFR_CAPTURE_EVENT (TX capture) by PPDU ID. If both events
103+
* are present and the PPDU IDs match, returns CORRELATE_STATUS_RELEASE
104+
* to relay thecorrelated data to userspace. Otherwise returns
105+
* CORRELATE_STATUS_HOLD to wait for the other event.
106+
*
107+
* Also checks pending DBR events and clears them when no corresponding TX
108+
* capture event is received for the PPDU.
109+
*
110+
* Return: CORRELATE_STATUS_RELEASE or CORRELATE_STATUS_HOLD
111+
*/
112+
113+
static enum ath11k_cfr_correlate_status
114+
ath11k_cfr_correlate_and_relay(struct ath11k *ar,
115+
struct ath11k_look_up_table *lut,
116+
u8 event_type)
117+
{
118+
enum ath11k_cfr_correlate_status status;
119+
struct ath11k_cfr *cfr = &ar->cfr;
120+
u64 diff;
121+
122+
if (event_type == ATH11K_CORRELATE_TX_EVENT) {
123+
if (lut->tx_recv)
124+
cfr->cfr_dma_aborts++;
125+
cfr->tx_evt_cnt++;
126+
lut->tx_recv = true;
127+
} else if (event_type == ATH11K_CORRELATE_DBR_EVENT) {
128+
cfr->dbr_evt_cnt++;
129+
lut->dbr_recv = true;
130+
}
131+
132+
if (lut->dbr_recv && lut->tx_recv) {
133+
if (lut->dbr_ppdu_id == lut->tx_ppdu_id) {
134+
/*
135+
* 64-bit counters make wraparound highly improbable,
136+
* wraparound handling is omitted.
137+
*/
138+
cfr->last_success_tstamp = lut->dbr_tstamp;
139+
if (lut->dbr_tstamp > lut->txrx_tstamp) {
140+
diff = lut->dbr_tstamp - lut->txrx_tstamp;
141+
ath11k_dbg(ar->ab, ATH11K_DBG_CFR,
142+
"txrx event -> dbr event delay = %u ms",
143+
jiffies_to_msecs(diff));
144+
} else if (lut->txrx_tstamp > lut->dbr_tstamp) {
145+
diff = lut->txrx_tstamp - lut->dbr_tstamp;
146+
ath11k_dbg(ar->ab, ATH11K_DBG_CFR,
147+
"dbr event -> txrx event delay = %u ms",
148+
jiffies_to_msecs(diff));
149+
}
150+
151+
ath11k_cfr_free_pending_dbr_events(ar);
152+
153+
cfr->release_cnt++;
154+
status = ATH11K_CORRELATE_STATUS_RELEASE;
155+
} else {
156+
/*
157+
* Discard TXRX event on PPDU ID mismatch because multiple PPDUs
158+
* may share the same DMA address due to ucode aborts.
159+
*/
160+
161+
ath11k_dbg(ar->ab, ATH11K_DBG_CFR,
162+
"Received dbr event twice for the same lut entry");
163+
lut->tx_recv = false;
164+
lut->tx_ppdu_id = 0;
165+
cfr->clear_txrx_event++;
166+
cfr->cfr_dma_aborts++;
167+
status = ATH11K_CORRELATE_STATUS_HOLD;
168+
}
169+
} else {
170+
status = ATH11K_CORRELATE_STATUS_HOLD;
171+
}
172+
173+
return status;
174+
}
175+
11176
static int ath11k_cfr_process_data(struct ath11k *ar,
12177
struct ath11k_dbring_data *param)
13178
{
14-
return 0;
179+
u32 end_magic = ATH11K_CFR_END_MAGIC;
180+
struct ath11k_csi_cfr_header *header;
181+
struct ath11k_cfr_dma_hdr *dma_hdr;
182+
struct ath11k_cfr *cfr = &ar->cfr;
183+
struct ath11k_look_up_table *lut;
184+
struct ath11k_base *ab = ar->ab;
185+
u32 buf_id, tones, length;
186+
u8 num_chains;
187+
int status;
188+
u8 *data;
189+
190+
data = param->data;
191+
buf_id = param->buf_id;
192+
193+
if (param->data_sz < sizeof(*dma_hdr))
194+
return -EINVAL;
195+
196+
dma_hdr = (struct ath11k_cfr_dma_hdr *)data;
197+
198+
tones = ath11k_cfr_calculate_tones_from_dma_hdr(dma_hdr);
199+
if (tones == TONES_INVALID) {
200+
ath11k_warn(ar->ab, "Number of tones received is invalid\n");
201+
return -EINVAL;
202+
}
203+
204+
num_chains = FIELD_GET(CFIR_DMA_HDR_INFO1_NUM_CHAINS,
205+
dma_hdr->info1);
206+
207+
length = sizeof(*dma_hdr);
208+
length += tones * (num_chains + 1);
209+
210+
spin_lock_bh(&cfr->lut_lock);
211+
212+
if (!cfr->lut) {
213+
spin_unlock_bh(&cfr->lut_lock);
214+
return -EINVAL;
215+
}
216+
217+
lut = &cfr->lut[buf_id];
218+
219+
ath11k_dbg_dump(ab, ATH11K_DBG_CFR_DUMP, "data_from_buf_rel:", "",
220+
data, length);
221+
222+
lut->buff = param->buff;
223+
lut->data = data;
224+
lut->data_len = length;
225+
lut->dbr_ppdu_id = dma_hdr->phy_ppdu_id;
226+
lut->dbr_tstamp = jiffies;
227+
228+
memcpy(&lut->hdr, dma_hdr, sizeof(*dma_hdr));
229+
230+
header = &lut->header;
231+
header->meta_data.channel_bw = FIELD_GET(CFIR_DMA_HDR_INFO1_UPLOAD_PKT_BW,
232+
dma_hdr->info1);
233+
header->meta_data.length = length;
234+
235+
status = ath11k_cfr_correlate_and_relay(ar, lut,
236+
ATH11K_CORRELATE_DBR_EVENT);
237+
if (status == ATH11K_CORRELATE_STATUS_RELEASE) {
238+
ath11k_dbg(ab, ATH11K_DBG_CFR,
239+
"releasing CFR data to user space");
240+
ath11k_cfr_rfs_write(ar, &lut->header,
241+
sizeof(struct ath11k_csi_cfr_header),
242+
lut->data, lut->data_len,
243+
&end_magic, sizeof(u32));
244+
ath11k_cfr_release_lut_entry(lut);
245+
} else if (status == ATH11K_CORRELATE_STATUS_HOLD) {
246+
ath11k_dbg(ab, ATH11K_DBG_CFR,
247+
"tx event is not yet received holding the buf");
248+
}
249+
250+
spin_unlock_bh(&cfr->lut_lock);
251+
252+
return status;
15253
}
16254

17255
/* Helper function to check whether the given peer mac address

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

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,78 @@
1919

2020
#define HOST_MAX_CHAINS 8
2121

22+
enum ath11k_cfr_correlate_event_type {
23+
ATH11K_CORRELATE_DBR_EVENT,
24+
ATH11K_CORRELATE_TX_EVENT,
25+
};
26+
2227
struct ath11k_sta;
2328
struct ath11k_per_peer_cfr_capture;
2429

30+
#define ATH11K_CFR_END_MAGIC 0xBEAFDEAD
31+
32+
enum ath11k_cfr_correlate_status {
33+
ATH11K_CORRELATE_STATUS_RELEASE,
34+
ATH11K_CORRELATE_STATUS_HOLD,
35+
ATH11K_CORRELATE_STATUS_ERR,
36+
};
37+
38+
enum ath11k_cfr_preamble_type {
39+
ATH11K_CFR_PREAMBLE_TYPE_LEGACY,
40+
ATH11K_CFR_PREAMBLE_TYPE_HT,
41+
ATH11K_CFR_PREAMBLE_TYPE_VHT,
42+
};
43+
44+
struct cfr_metadata {
45+
u8 peer_addr[ETH_ALEN];
46+
u8 status;
47+
u8 capture_bw;
48+
u8 channel_bw;
49+
u8 phy_mode;
50+
u16 prim20_chan;
51+
u16 center_freq1;
52+
u16 center_freq2;
53+
u8 capture_mode;
54+
u8 capture_type;
55+
u8 sts_count;
56+
u8 num_rx_chain;
57+
u32 timestamp;
58+
u32 length;
59+
u32 chain_rssi[HOST_MAX_CHAINS];
60+
u16 chain_phase[HOST_MAX_CHAINS];
61+
u32 cfo_measurement;
62+
u8 agc_gain[HOST_MAX_CHAINS];
63+
u32 rx_start_ts;
64+
} __packed;
65+
66+
struct ath11k_csi_cfr_header {
67+
u32 start_magic_num;
68+
u32 vendorid;
69+
u8 cfr_metadata_version;
70+
u8 cfr_data_version;
71+
u8 chip_type;
72+
u8 platform_type;
73+
u32 reserved;
74+
struct cfr_metadata meta_data;
75+
} __packed;
76+
77+
#define TONES_IN_20MHZ 256
78+
#define TONES_IN_40MHZ 512
79+
#define TONES_IN_80MHZ 1024
80+
#define TONES_IN_160MHZ 2048 /* 160 MHz isn't supported yet */
81+
#define TONES_INVALID 0
82+
83+
#define CFIR_DMA_HDR_INFO0_TAG GENMASK(7, 0)
84+
#define CFIR_DMA_HDR_INFO0_LEN GENMASK(13, 8)
85+
86+
#define CFIR_DMA_HDR_INFO1_UPLOAD_DONE GENMASK(0, 0)
87+
#define CFIR_DMA_HDR_INFO1_CAPTURE_TYPE GENMASK(3, 1)
88+
#define CFIR_DMA_HDR_INFO1_PREAMBLE_TYPE GENMASK(5, 4)
89+
#define CFIR_DMA_HDR_INFO1_NSS GENMASK(8, 6)
90+
#define CFIR_DMA_HDR_INFO1_NUM_CHAINS GENMASK(11, 9)
91+
#define CFIR_DMA_HDR_INFO1_UPLOAD_PKT_BW GENMASK(14, 12)
92+
#define CFIR_DMA_HDR_INFO1_SW_PEER_ID_VALID GENMASK(15, 15)
93+
2594
struct ath11k_cfr_dma_hdr {
2695
u16 info0;
2796
u16 info1;
@@ -37,6 +106,7 @@ struct ath11k_look_up_table {
37106
u16 dbr_ppdu_id;
38107
u16 tx_ppdu_id;
39108
dma_addr_t dbr_address;
109+
struct ath11k_csi_cfr_header header;
40110
struct ath11k_cfr_dma_hdr hdr;
41111
u64 txrx_tstamp;
42112
u64 dbr_tstamp;
@@ -109,6 +179,8 @@ int ath11k_cfr_send_peer_cfr_capture_cmd(struct ath11k *ar,
109179
struct ath11k_sta *arsta,
110180
struct ath11k_per_peer_cfr_capture *params,
111181
const u8 *peer_mac);
182+
struct ath11k_dbring *ath11k_cfr_get_dbring(struct ath11k *ar);
183+
void ath11k_cfr_release_lut_entry(struct ath11k_look_up_table *lut);
112184

113185
#else
114186
static inline int ath11k_cfr_init(struct ath11k_base *ab)
@@ -156,5 +228,15 @@ ath11k_cfr_send_peer_cfr_capture_cmd(struct ath11k *ar,
156228
{
157229
return 0;
158230
}
231+
232+
static inline void ath11k_cfr_release_lut_entry(struct ath11k_look_up_table *lut)
233+
{
234+
}
235+
236+
static inline
237+
struct ath11k_dbring *ath11k_cfr_get_dbring(struct ath11k *ar)
238+
{
239+
return NULL;
240+
}
159241
#endif /* CONFIG_ATH11K_CFR */
160242
#endif /* ATH11K_CFR_H */

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,7 @@ int ath11k_dbring_buffer_release_event(struct ath11k_base *ab,
295295
int size;
296296
dma_addr_t paddr;
297297
int ret = 0;
298+
int status;
298299

299300
pdev_idx = ev->fixed.pdev_id;
300301
module_id = ev->fixed.module_id;
@@ -328,6 +329,9 @@ int ath11k_dbring_buffer_release_event(struct ath11k_base *ab,
328329
case WMI_DIRECT_BUF_SPECTRAL:
329330
ring = ath11k_spectral_get_dbring(ar);
330331
break;
332+
case WMI_DIRECT_BUF_CFR:
333+
ring = ath11k_cfr_get_dbring(ar);
334+
break;
331335
default:
332336
ring = NULL;
333337
ath11k_warn(ab, "Recv dma buffer release ev on unsupp module %d\n",
@@ -378,8 +382,12 @@ int ath11k_dbring_buffer_release_event(struct ath11k_base *ab,
378382
handler_data.data = PTR_ALIGN(vaddr_unalign,
379383
ring->buf_align);
380384
handler_data.data_sz = ring->buf_sz;
385+
handler_data.buff = buff;
386+
handler_data.buf_id = buf_id;
381387

382-
ring->handler(ar, &handler_data);
388+
status = ring->handler(ar, &handler_data);
389+
if (status == ATH11K_CORRELATE_STATUS_HOLD)
390+
continue;
383391
}
384392

385393
buff->paddr = 0;

0 commit comments

Comments
 (0)