blob: 27c74b7cceb5d86bbaebe3ca2ab450d186ce0d4c [file] [log] [blame]
developer05f3b2b2024-08-19 19:17:34 +08001From 3b007db9f040c663de6308f0cb1b9b603f1811c5 Mon Sep 17 00:00:00 2001
developer66e89bc2024-04-23 14:50:01 +08002From: mtk20656 <chank.chen@mediatek.com>
3Date: Sat, 20 Jan 2024 12:03:24 +0800
developer05f3b2b2024-08-19 19:17:34 +08004Subject: [PATCH 118/199] mtk: mt76: mt7996: Add connac3 csi feature.
developer66e89bc2024-04-23 14:50:01 +08005
61. format align to wifi6.
72. add bw320 support.
83. add active mode.
9
developer05f3b2b2024-08-19 19:17:34 +080010Fix csi bug with single wiphy design.
11
developer66e89bc2024-04-23 14:50:01 +080012Signed-off-by: mtk20656 <chank.chen@mediatek.com>
13---
14 mt76_connac_mcu.h | 2 +
15 mt7996/init.c | 22 +++
16 mt7996/main.c | 3 +
17 mt7996/mcu.c | 465 ++++++++++++++++++++++++++++++++++++++++++++++
18 mt7996/mcu.h | 105 +++++++++++
19 mt7996/mt7996.h | 55 ++++++
developer05f3b2b2024-08-19 19:17:34 +080020 mt7996/vendor.c | 247 ++++++++++++++++++++++++
21 mt7996/vendor.h | 52 ++++++
22 8 files changed, 951 insertions(+)
developer66e89bc2024-04-23 14:50:01 +080023
24diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
developer05f3b2b2024-08-19 19:17:34 +080025index 6e3324f5..1852e512 100644
developer66e89bc2024-04-23 14:50:01 +080026--- a/mt76_connac_mcu.h
27+++ b/mt76_connac_mcu.h
developer05f3b2b2024-08-19 19:17:34 +080028@@ -1061,6 +1061,7 @@ enum {
developer66e89bc2024-04-23 14:50:01 +080029 MCU_UNI_EVENT_THERMAL = 0x35,
30 MCU_UNI_EVENT_NIC_CAPAB = 0x43,
31 MCU_UNI_EVENT_TESTMODE_CTRL = 0x46,
32+ MCU_UNI_EVENT_CSI_REPORT = 0x4A,
33 MCU_UNI_EVENT_WED_RRO = 0x57,
34 MCU_UNI_EVENT_PER_STA_INFO = 0x6d,
35 MCU_UNI_EVENT_ALL_STA_INFO = 0x6e,
developer05f3b2b2024-08-19 19:17:34 +080036@@ -1298,6 +1299,7 @@ enum {
developer66e89bc2024-04-23 14:50:01 +080037 MCU_UNI_CMD_TESTMODE_TRX_PARAM = 0x42,
38 MCU_UNI_CMD_TESTMODE_CTRL = 0x46,
39 MCU_UNI_CMD_PRECAL_RESULT = 0x47,
40+ MCU_UNI_CMD_CSI_CTRL = 0x4A,
41 MCU_UNI_CMD_THERMAL_CAL = 0x4c,
42 MCU_UNI_CMD_RRO = 0x57,
43 MCU_UNI_CMD_OFFCH_SCAN_CTRL = 0x58,
44diff --git a/mt7996/init.c b/mt7996/init.c
developer05f3b2b2024-08-19 19:17:34 +080045index f75aa568..a1941869 100644
developer66e89bc2024-04-23 14:50:01 +080046--- a/mt7996/init.c
47+++ b/mt7996/init.c
developer05f3b2b2024-08-19 19:17:34 +080048@@ -807,6 +807,24 @@ error:
developer66e89bc2024-04-23 14:50:01 +080049 return ret;
50 }
51
52+#ifdef CONFIG_MTK_VENDOR
53+static int mt7996_unregister_csi(struct mt7996_phy *phy)
54+{
55+ struct csi_data *c, *tmp_c;
56+
57+ spin_lock_bh(&phy->csi.lock);
58+ phy->csi.enable = 0;
59+
60+ list_for_each_entry_safe(c, tmp_c, &phy->csi.list, node) {
61+ list_del(&c->node);
62+ kfree(c);
63+ }
64+ spin_unlock_bh(&phy->csi.lock);
65+
66+ return 0;
67+}
68+#endif
69+
70 static void
71 mt7996_unregister_phy(struct mt7996_phy *phy, enum mt76_band_id band)
72 {
developer05f3b2b2024-08-19 19:17:34 +080073@@ -818,6 +836,10 @@ mt7996_unregister_phy(struct mt7996_phy *phy, enum mt76_band_id band)
developer66e89bc2024-04-23 14:50:01 +080074 /* TODO: FIXME: temp for single wiphy support */
75 phy->mt76->hw = phy->mt76->ori_hw;
76
77+#ifdef CONFIG_MTK_VENDOR
78+ mt7996_unregister_csi(phy);
79+#endif
80+
81 mt7996_unregister_thermal(phy);
82
83 mphy = phy->dev->mt76.phys[band];
84diff --git a/mt7996/main.c b/mt7996/main.c
developer05f3b2b2024-08-19 19:17:34 +080085index 7e56f4b0..b94af2f6 100644
developer66e89bc2024-04-23 14:50:01 +080086--- a/mt7996/main.c
87+++ b/mt7996/main.c
developer05f3b2b2024-08-19 19:17:34 +080088@@ -1302,6 +1302,9 @@ void mt7996_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
developer66e89bc2024-04-23 14:50:01 +080089 struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76);
90 unsigned long rem = sta->valid_links ?: BIT(0);
91
92+#ifdef CONFIG_MTK_VENDOR
93+ mt7996_mcu_set_csi(&dev->phy, 2, 8, 1, 0, sta->addr);
94+#endif
95 mt7996_mac_sta_remove_links(dev, vif, sta, rem);
96 }
97
98diff --git a/mt7996/mcu.c b/mt7996/mcu.c
developer05f3b2b2024-08-19 19:17:34 +080099index f97acfb2..c59dbbea 100644
developer66e89bc2024-04-23 14:50:01 +0800100--- a/mt7996/mcu.c
101+++ b/mt7996/mcu.c
102@@ -653,6 +653,263 @@ mt7996_mcu_rx_all_sta_info_event(struct mt7996_dev *dev, struct sk_buff *skb)
103 }
104 }
105
106+static int
107+csi_integrate_segment_data(struct mt7996_phy *phy, struct csi_data *csi)
108+{
109+ struct csi_data *csi_temp = NULL;
110+
111+ if (csi->segment_num == 0 && csi->remain_last == 0)
112+ return CSI_CHAIN_COMPLETE;
113+ else if (csi->segment_num == 0 && csi->remain_last == 1) {
114+ memcpy(&phy->csi.buffered_csi,
115+ csi, sizeof(struct csi_data));
116+
117+ return CSI_CHAIN_SEGMENT_FIRST;
118+ } else if (csi->segment_num != 0) {
119+ csi_temp = &phy->csi.buffered_csi;
120+ if (csi->chain_info != csi_temp->chain_info ||
121+ csi->segment_num != (csi_temp->segment_num + 1))
122+ return CSI_CHAIN_SEGMENT_ERR;
123+
124+ memcpy(&csi_temp->data_i[csi_temp->data_num],
125+ csi->data_i, csi->data_num * sizeof(s16));
126+
127+ memcpy(&csi_temp->data_q[csi_temp->data_num],
128+ csi->data_q, csi->data_num * sizeof(s16));
129+
130+ csi_temp->data_num += csi->data_num;
131+ csi_temp->segment_num = csi->segment_num;
132+ csi_temp->remain_last = csi->remain_last;
133+
134+ if (csi->remain_last == 0)
135+ return CSI_CHAIN_SEGMENT_LAST;
136+ else if (csi->remain_last == 1)
137+ return CSI_CHAIN_SEGMENT_MIDDLE;
138+ }
139+
140+ return CSI_CHAIN_ERR;
141+}
142+
143+static int
144+mt7996_mcu_csi_report_data(struct mt7996_phy *phy, u8 *tlv_buf, u32 len)
145+{
146+ int ret, i;
147+ struct csi_data *current_csi;
148+ struct csi_data *target_csi;
149+ struct csi_tlv *tlv_data;
150+ u8 *buf_tmp;
151+ u32 rx_info, tx_rx_idx;
152+ u32 buf_len_last, offset;
153+
154+ buf_tmp = tlv_buf;
155+ buf_len_last = len;
156+ offset = sizeof(((struct csi_tlv *)0)->basic);
157+
158+ current_csi = kzalloc(sizeof(*current_csi), GFP_KERNEL);
159+ if (!current_csi)
160+ return -ENOMEM;
161+
162+ while (buf_len_last >= offset) {
163+ u32 tag, len;
164+ s16 *data_tmp = NULL;
165+
166+ tlv_data = (struct csi_tlv *)buf_tmp;
167+ tag = le32_to_cpu(tlv_data->basic.tag);
168+ len = le32_to_cpu(tlv_data->basic.len);
169+
170+ switch (tag) {
171+ case CSI_EVENT_FW_VER:
172+ current_csi->fw_ver = le32_to_cpu(tlv_data->info);
173+ break;
174+ case CSI_EVENT_CBW:
175+ current_csi->ch_bw = le32_to_cpu(tlv_data->info);
176+ break;
177+ case CSI_EVENT_RSSI:
178+ current_csi->rssi = le32_to_cpu(tlv_data->info);
179+ break;
180+ case CSI_EVENT_SNR:
181+ current_csi->snr = le32_to_cpu(tlv_data->info);
182+ break;
183+ case CSI_EVENT_BAND:
184+ current_csi->band = le32_to_cpu(tlv_data->info);
185+
186+ if (current_csi->band != phy->mt76->band_idx) {
187+ kfree(current_csi);
188+ return -EINVAL;
189+ }
190+
191+ break;
192+ case CSI_EVENT_CSI_NUM:
193+ current_csi->data_num = le32_to_cpu(tlv_data->info);
194+
195+ if (current_csi->data_num > CSI_BW80_DATA_COUNT) {
196+ kfree(current_csi);
197+ return -EINVAL;
198+ }
199+
200+ break;
201+ case CSI_EVENT_CSI_I_DATA:
202+ if (len != sizeof(s16) * current_csi->data_num) {
203+ kfree(current_csi);
204+ return -EINVAL;
205+ }
206+
207+ data_tmp = tlv_data->data;
208+ for (i = 0; i < current_csi->data_num; i++)
209+ current_csi->data_i[i] = le16_to_cpu(*(data_tmp + i));
210+ break;
211+ case CSI_EVENT_CSI_Q_DATA:
212+ if (len != sizeof(s16) * current_csi->data_num) {
213+ kfree(current_csi);
214+ return -EINVAL;
215+ }
216+
217+ data_tmp = tlv_data->data;
218+ for (i = 0; i < current_csi->data_num; i++)
219+ current_csi->data_q[i] = le16_to_cpu(*(data_tmp + i));
220+ break;
221+ case CSI_EVENT_DBW:
222+ current_csi->data_bw = le32_to_cpu(tlv_data->info);
223+ break;
224+ case CSI_EVENT_CH_IDX:
225+ current_csi->pri_ch_idx = le32_to_cpu(tlv_data->info);
226+ break;
227+ case CSI_EVENT_TA:
228+ memcpy(current_csi->ta, tlv_data->mac, ETH_ALEN);
229+ break;
230+ case CSI_EVENT_EXTRA_INFO:
231+ current_csi->ext_info = le32_to_cpu(tlv_data->info);
232+ break;
233+ case CSI_EVENT_RX_MODE:
234+ rx_info = le32_to_cpu(tlv_data->info);
235+ current_csi->rx_mode = u32_get_bits(rx_info, GENMASK(15, 0));
236+ current_csi->rx_rate = u32_get_bits(rx_info, GENMASK(31, 16));
237+ break;
238+ case CSI_EVENT_H_IDX:
239+ current_csi->chain_info = le32_to_cpu(tlv_data->info);
240+ break;
241+ case CSI_EVENT_TX_RX_IDX:
242+ tx_rx_idx = le32_to_cpu(tlv_data->info);
243+ current_csi->tx_idx = u32_get_bits(tx_rx_idx, GENMASK(31, 16));
244+ current_csi->rx_idx = u32_get_bits(tx_rx_idx, GENMASK(15, 0));
245+ break;
246+ case CSI_EVENT_TS:
247+ current_csi->ts = le32_to_cpu(tlv_data->info);
248+
249+ if (phy->csi.interval &&
250+ current_csi->ts < phy->csi.last_record + phy->csi.interval) {
251+ kfree(current_csi);
252+ return 0;
253+ }
254+
255+ break;
256+ case CSI_EVENT_PKT_SN:
257+ current_csi->pkt_sn = le32_to_cpu(tlv_data->info);
258+ break;
259+ case CSI_EVENT_BW_SEG:
260+ current_csi->segment_num = le32_to_cpu(tlv_data->info);
261+ break;
262+ case CSI_EVENT_REMAIN_LAST:
263+ current_csi->remain_last = le32_to_cpu(tlv_data->info);
264+ break;
265+ case CSI_EVENT_TR_STREAM:
266+ current_csi->tr_stream = le32_to_cpu(tlv_data->info);
267+ break;
268+ default:
269+ break;
270+ };
271+
272+ buf_len_last -= (offset + len);
273+
274+ if (buf_len_last >= offset)
275+ buf_tmp += (offset + len);
276+ }
277+
278+ /* integret the bw80 segment */
279+ if (current_csi->ch_bw >= CSI_BW80) {
280+ ret = csi_integrate_segment_data(phy, current_csi);
281+
282+ switch (ret) {
283+ case CSI_CHAIN_ERR:
284+ case CSI_CHAIN_SEGMENT_ERR:
285+ kfree(current_csi);
286+ return -EINVAL;
287+ break;
288+ case CSI_CHAIN_SEGMENT_FIRST:
289+ case CSI_CHAIN_SEGMENT_MIDDLE:
290+ kfree(current_csi);
291+ return 0;
292+ break;
293+ case CSI_CHAIN_COMPLETE:
294+ target_csi = current_csi;
295+ break;
296+ case CSI_CHAIN_SEGMENT_LAST:
297+ target_csi = current_csi;
298+ memcpy(target_csi, &phy->csi.buffered_csi, sizeof(struct csi_data));
299+ memset(&phy->csi.buffered_csi, 0, sizeof(struct csi_data));
300+ break;
301+ default:
302+ break;
303+ }
304+ } else {
305+ target_csi = current_csi;
306+ }
307+
308+ /* put the csi data into list */
309+ INIT_LIST_HEAD(&target_csi->node);
310+ spin_lock_bh(&phy->csi.lock);
311+
312+ if (!phy->csi.enable) {
313+ kfree(target_csi);
314+ goto out;
315+ }
316+
317+ list_add_tail(&target_csi->node, &phy->csi.list);
318+ phy->csi.count++;
319+
320+ if (phy->csi.count > CSI_MAX_BUF_NUM) {
321+ struct csi_data *old;
322+
323+ old = list_first_entry(&phy->csi.list,
324+ struct csi_data, node);
325+
326+ list_del(&old->node);
327+ kfree(old);
328+ phy->csi.count--;
329+ }
330+
331+ if (target_csi->chain_info & BIT(15)) /* last chain */
332+ phy->csi.last_record = target_csi->ts;
333+
334+out:
335+ spin_unlock_bh(&phy->csi.lock);
336+ return 0;
337+}
338+
339+void
340+mt7996_mcu_csi_report_event(struct mt7996_dev *dev, struct sk_buff *skb)
341+{
342+ struct mt7996_mcu_csi_event *event;
343+ struct mt76_phy *mphy;
344+ struct mt7996_phy *phy;
345+
346+ event = (struct mt7996_mcu_csi_event *)skb->data;
347+
348+ mphy = dev->mt76.phys[event->band_idx];
349+ if (!mphy)
350+ return;
351+
352+ phy = mphy->priv;
353+
354+ switch (le16_to_cpu(event->tag)) {
355+ case UNI_EVENT_CSI_DATA:
356+ mt7996_mcu_csi_report_data(phy, event->tlv_buf, le16_to_cpu(event->len) - 4);
357+ break;
358+ default:
359+ break;
360+ }
361+}
362+
363 static void
364 mt7996_mcu_rx_thermal_notify(struct mt7996_dev *dev, struct sk_buff *skb)
365 {
366@@ -896,6 +1153,11 @@ mt7996_mcu_uni_rx_unsolicited_event(struct mt7996_dev *dev, struct sk_buff *skb)
367 case MCU_UNI_EVENT_BF:
368 mt7996_mcu_rx_bf_event(dev, skb);
369 break;
370+#endif
371+#ifdef CONFIG_MTK_VENDOR
372+ case MCU_UNI_EVENT_CSI_REPORT:
373+ mt7996_mcu_csi_report_event(dev, skb);
374+ break;
375 #endif
376 default:
377 break;
developer05f3b2b2024-08-19 19:17:34 +0800378@@ -5980,4 +6242,207 @@ void mt7996_set_beacon_vif(void *data, u8 *mac, struct ieee80211_vif *vif)
developer66e89bc2024-04-23 14:50:01 +0800379
380 mt7996_mcu_add_beacon(hw, &vif->bss_conf, &mvif->deflink, val);
381 }
382+
383+static int mt7996_mcu_set_csi_enable(struct mt7996_phy *phy, u16 tag)
384+{
385+ struct {
386+ u8 band;
387+ u8 rsv1[3];
388+
389+ __le16 tag;
390+ __le16 len;
391+ } __packed req = {
392+ .band = phy->mt76->band_idx,
393+ .tag = cpu_to_le16(tag),
394+ .len = cpu_to_le16(sizeof(req) - 4),
395+ };
396+
397+ return mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(CSI_CTRL), &req,
398+ sizeof(req), false);
399+}
400+
401+static int mt7996_mcu_set_csi_frame_type(struct mt7996_phy *phy, u16 tag, u8 type_idx, u32 type)
402+{
403+ struct {
404+ u8 band;
405+ u8 rsv1[3];
406+
407+ __le16 tag;
408+ __le16 len;
409+ u8 frame_type_idx;
410+ u8 frame_type;
411+ u8 rsv2[2];
412+ } __packed req = {
413+ .band = phy->mt76->band_idx,
414+ .tag = cpu_to_le16(tag),
415+ .len = cpu_to_le16(sizeof(req) - 4),
416+ .frame_type_idx = type_idx,
417+ .frame_type = type,
418+ };
419+
420+ return mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(CSI_CTRL), &req,
421+ sizeof(req), false);
422+}
423+
424+static int mt7996_mcu_set_csi_chain_filter(struct mt7996_phy *phy, u16 tag, u8 func, u32 value)
425+{
426+ struct {
427+ u8 band;
428+ u8 rsv1[3];
429+
430+ __le16 tag;
431+ __le16 len;
432+ u8 function;
433+ u8 chain_value;
434+ u8 rsv2[2];
435+ } __packed req = {
436+ .band = phy->mt76->band_idx,
437+ .tag = cpu_to_le16(tag),
438+ .len = cpu_to_le16(sizeof(req) - 4),
439+ .function = func,
440+ .chain_value = value,
441+ };
442+
443+ return mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(CSI_CTRL), &req,
444+ sizeof(req), false);
445+}
446+
447+static int mt7996_mcu_set_csi_sta_filter(struct mt7996_phy *phy, u16 tag, u32 op, u8 *sta_mac)
448+{
449+ struct {
450+ u8 band;
451+ u8 rsv1[3];
452+
453+ __le16 tag;
454+ __le16 len;
455+ u8 operation;
456+ u8 rsv2[1];
457+ u8 mac[6];
458+ } __packed req = {
459+ .band = phy->mt76->band_idx,
460+ .tag = cpu_to_le16(tag),
461+ .len = cpu_to_le16(sizeof(req) - 4),
462+ .operation = op,
463+ };
464+
465+ memcpy(req.mac, sta_mac, ETH_ALEN);
466+
467+ return mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(CSI_CTRL), &req,
468+ sizeof(req), false);
469+}
470+
471+static int mt7996_mcu_set_csi_active_mode(struct mt7996_phy *phy, u16 tag,
472+ u32 interval, u8 frame_idx, u8 subframe_idx, u32 bitmap)
473+{
474+ struct {
475+ u8 band;
476+ u8 rsv1[3];
477+
478+ __le16 tag;
479+ __le16 len;
480+ __le16 interval; /* uint: ms */
481+ u8 frame_type_idx;
482+ u8 subframe_type_idx;
483+ __le32 bitmap; /* sta wcid bitmap */
484+ u8 rsv2[4];
485+ } __packed req = {
486+ .band = phy->mt76->band_idx,
487+ .tag = cpu_to_le16(tag),
488+ .len = cpu_to_le16(sizeof(req) - 4),
489+ .interval = cpu_to_le16(interval),
490+ .frame_type_idx = frame_idx,
491+ .subframe_type_idx = subframe_idx,
492+ .bitmap = cpu_to_le32(bitmap),
493+ };
494+
495+ return mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(CSI_CTRL), &req,
496+ sizeof(req), false);
497+}
498+
499+void mt7996_csi_wcid_bitmap_update(void *data, struct ieee80211_sta *sta)
500+{
501+ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
502+ struct mt7996_phy *phy = msta->vif->deflink.phy;
503+ struct csi_bitmap_info_update *sta_info = (struct csi_bitmap_info_update *)data;
504+ u16 wcid = 0;
505+
506+#define CSI_ACTIVE_MODE_ADD 1
507+#define CSI_ACTIVE_MODE_REMOVE 0
508+
509+ if (!memcmp(sta_info->addr, sta->addr, ETH_ALEN)) {
510+ wcid = msta->deflink.wcid.idx;
511+
512+ /* active mode: only support station with wcid less than 32 */
513+ if (wcid > 32)
514+ return;
515+
516+ if (sta_info->action == CSI_ACTIVE_MODE_ADD)
517+ phy->csi.active_bitmap |= BIT(wcid);
518+ else if (sta_info->action == CSI_ACTIVE_MODE_REMOVE)
519+ phy->csi.active_bitmap &= ~(BIT(wcid));
520+ }
521+}
522+
523+int mt7996_mcu_set_csi(struct mt7996_phy *phy, u8 mode,
524+ u8 cfg, u8 v1, u32 v2, u8 *mac_addr)
525+{
526+ switch (mode) {
527+ case CSI_CONTROL_MODE_STOP:
528+ return mt7996_mcu_set_csi_enable(phy, UNI_CMD_CSI_STOP);
529+ case CSI_CONTROL_MODE_START:
530+ return mt7996_mcu_set_csi_enable(phy, UNI_CMD_CSI_START);
531+ case CSI_CONTROL_MODE_SET:
532+ switch (cfg) {
533+ case CSI_CONFIG_FRAME_TYPE:
534+ if (v2 > 255)
535+ return -EINVAL;
536+
537+ return mt7996_mcu_set_csi_frame_type(phy,
538+ UNI_CMD_CSI_SET_FRAME_TYPE, v1, v2);
539+ case CSI_CONFIG_CHAIN_FILTER:
540+ if (v2 > 255)
541+ return -EINVAL;
542+
543+ return mt7996_mcu_set_csi_chain_filter(phy,
544+ UNI_CMD_CSI_SET_CHAIN_FILTER, v1, v2);
545+ case CSI_CONFIG_STA_FILTER:
546+ if (!is_valid_ether_addr(mac_addr))
547+ return -EINVAL;
548+
549+ if (v2 > 255)
550+ return -EINVAL;
551+
552+ return mt7996_mcu_set_csi_sta_filter(phy,
553+ UNI_CMD_CSI_SET_STA_FILTER, v2, mac_addr);
554+ case CSI_CONFIG_ACTIVE_MODE:
555+ if (is_valid_ether_addr(mac_addr)) {
556+ struct csi_bitmap_info_update sta_info;
557+
558+ if (v2 > 255)
559+ return -EINVAL;
560+
561+ memcpy(sta_info.addr, mac_addr, ETH_ALEN);
562+ sta_info.action = v2;
563+
564+ ieee80211_iterate_stations_atomic(phy->mt76->hw,
565+ mt7996_csi_wcid_bitmap_update, &sta_info);
566+ return 0;
567+ } else {
568+ u8 frame_type = v1 & 0x3;
569+ u8 frame_subtype = (v1 & 0x3c) >> 2;
570+
571+ /* active mode: max interval is 3000ms */
572+ if (v2 > 3000)
573+ return -EINVAL;
574+
575+ return mt7996_mcu_set_csi_active_mode(phy, UNI_CMD_CSI_SET_ACTIVE_MODE,
576+ v2, frame_type, frame_subtype, phy->csi.active_bitmap);
577+ }
578+ default:
579+ return -EINVAL;
580+ }
581+ default:
582+ return -EINVAL;
583+ }
584+}
585 #endif
586diff --git a/mt7996/mcu.h b/mt7996/mcu.h
developer05f3b2b2024-08-19 19:17:34 +0800587index f9f04680..42e9f525 100644
developer66e89bc2024-04-23 14:50:01 +0800588--- a/mt7996/mcu.h
589+++ b/mt7996/mcu.h
developer05f3b2b2024-08-19 19:17:34 +0800590@@ -1153,4 +1153,109 @@ struct fixed_rate_table_ctrl {
developer66e89bc2024-04-23 14:50:01 +0800591 u8 _rsv2;
592 } __packed;
593
594+#ifdef CONFIG_MTK_VENDOR
595+struct mt7996_mcu_csi_event {
596+ struct mt7996_mcu_rxd rxd;
597+
598+ u8 band_idx;
599+ u8 _rsv[3];
600+
601+ __le16 tag;
602+ __le16 len;
603+ u8 tlv_buf[0];
604+};
605+
606+enum UNI_EVENT_CSI_TAG_T {
607+ UNI_EVENT_CSI_DATA = 0,
608+ UNI_EVENT_CSI_MAX_NUM
609+};
610+
611+struct csi_tlv {
612+ struct {
613+ __le32 tag;
614+ __le32 len;
615+ } basic;
616+ union {
617+ u8 mac[ETH_ALEN];
618+ __le32 info;
619+ s16 data[0];
620+ };
621+} __packed;
622+
623+struct csi_bitmap_info_update {
624+ u8 action;
625+ u8 addr[ETH_ALEN];
626+};
627+
628+#define CSI_MAX_BUF_NUM 3000
629+
630+enum CSI_EVENT_TLV_TAG {
631+ CSI_EVENT_FW_VER,
632+ CSI_EVENT_CBW,
633+ CSI_EVENT_RSSI,
634+ CSI_EVENT_SNR,
635+ CSI_EVENT_BAND,
636+ CSI_EVENT_CSI_NUM,
637+ CSI_EVENT_CSI_I_DATA,
638+ CSI_EVENT_CSI_Q_DATA,
639+ CSI_EVENT_DBW,
640+ CSI_EVENT_CH_IDX,
641+ CSI_EVENT_TA,
642+ CSI_EVENT_EXTRA_INFO,
643+ CSI_EVENT_RX_MODE,
644+ CSI_EVENT_RSVD1,
645+ CSI_EVENT_RSVD2,
646+ CSI_EVENT_RSVD3,
647+ CSI_EVENT_RSVD4,
648+ CSI_EVENT_H_IDX,
649+ CSI_EVENT_TX_RX_IDX,
650+ CSI_EVENT_TS,
651+ CSI_EVENT_PKT_SN,
652+ CSI_EVENT_BW_SEG,
653+ CSI_EVENT_REMAIN_LAST,
654+ CSI_EVENT_TR_STREAM,
655+ CSI_EVENT_TLV_TAG_NUM,
656+};
657+
658+enum CSI_CHAIN_TYPE {
659+ CSI_CHAIN_ERR,
660+ CSI_CHAIN_COMPLETE,
661+ CSI_CHAIN_SEGMENT_FIRST,
662+ CSI_CHAIN_SEGMENT_MIDDLE,
663+ CSI_CHAIN_SEGMENT_LAST,
664+ CSI_CHAIN_SEGMENT_ERR,
665+};
666+
667+enum CSI_CONTROL_MODE_T {
668+ CSI_CONTROL_MODE_STOP,
669+ CSI_CONTROL_MODE_START,
670+ CSI_CONTROL_MODE_SET,
671+ CSI_CONTROL_MODE_NUM
672+};
673+
674+enum CSI_CONFIG_ITEM_T {
675+ CSI_CONFIG_RSVD1,
676+ CSI_CONFIG_WF,
677+ CSI_CONFIG_RSVD2,
678+ CSI_CONFIG_FRAME_TYPE,
679+ CSI_CONFIG_TX_PATH,
680+ CSI_CONFIG_OUTPUT_FORMAT,
681+ CSI_CONFIG_INFO,
682+ CSI_CONFIG_CHAIN_FILTER,
683+ CSI_CONFIG_STA_FILTER,
684+ CSI_CONFIG_ACTIVE_MODE,
685+ CSI_CONFIG_ITEM_NUM
686+};
687+
688+/* CSI config Tag */
689+enum UNI_CMD_CSI_TAG_T {
690+ UNI_CMD_CSI_STOP = 0,
691+ UNI_CMD_CSI_START = 1,
692+ UNI_CMD_CSI_SET_FRAME_TYPE = 2,
693+ UNI_CMD_CSI_SET_CHAIN_FILTER = 3,
694+ UNI_CMD_CSI_SET_STA_FILTER = 4,
695+ UNI_CMD_CSI_SET_ACTIVE_MODE = 5,
696+};
697+#endif
698+
699 #endif
700diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
developer05f3b2b2024-08-19 19:17:34 +0800701index 40ee8949..f0492078 100644
developer66e89bc2024-04-23 14:50:01 +0800702--- a/mt7996/mt7996.h
703+++ b/mt7996/mt7996.h
developer05f3b2b2024-08-19 19:17:34 +0800704@@ -445,6 +445,47 @@ struct mt7996_air_monitor_ctrl {
developer66e89bc2024-04-23 14:50:01 +0800705 struct mt7996_air_monitor_group group[MT7996_AIR_MONITOR_MAX_GROUP];
706 struct mt7996_air_monitor_entry entry[MT7996_AIR_MONITOR_MAX_ENTRY];
707 };
708+
709+enum {
710+ CSI_BW20,
711+ CSI_BW40,
712+ CSI_BW80,
713+ CSI_BW160,
714+ CSI_BW320
715+};
716+
717+#define CSI_BW20_DATA_COUNT 64
718+#define CSI_BW40_DATA_COUNT 128
719+#define CSI_BW80_DATA_COUNT 256
720+#define CSI_BW160_DATA_COUNT 512
721+#define CSI_BW320_DATA_COUNT 1024
722+
723+struct csi_data {
724+ u8 fw_ver;
725+ u8 ch_bw;
726+ u16 data_num;
727+ s16 data_i[CSI_BW320_DATA_COUNT];
728+ s16 data_q[CSI_BW320_DATA_COUNT];
729+ u8 band;
730+ s8 rssi;
731+ u8 snr;
732+ u32 ts;
733+ u8 data_bw;
734+ u8 pri_ch_idx;
735+ u8 ta[ETH_ALEN];
736+ u32 ext_info;
737+ u16 rx_mode;
738+ u16 rx_rate;
739+ u32 chain_info;
740+ u16 tx_idx;
741+ u16 rx_idx;
742+ u32 segment_num;
743+ u8 remain_last;
744+ u16 pkt_sn;
745+ u8 tr_stream;
746+
747+ struct list_head node;
748+};
749 #endif
750
751 struct mt7996_rro_ba_session {
developer05f3b2b2024-08-19 19:17:34 +0800752@@ -541,6 +582,18 @@ struct mt7996_phy {
developer66e89bc2024-04-23 14:50:01 +0800753 u8 rts_bw_sig;
754 spinlock_t amnt_lock;
755 struct mt7996_air_monitor_ctrl amnt_ctrl;
756+
757+ struct {
758+ struct list_head list;
759+ spinlock_t lock;
760+ u32 count;
761+ bool enable;
762+
763+ struct csi_data buffered_csi;
764+ u32 active_bitmap;
765+ u32 interval;
766+ u32 last_record;
767+ } csi;
768 #endif
769 #ifdef CONFIG_MTK_DEBUG
770 bool sr_enable:1;
developer05f3b2b2024-08-19 19:17:34 +0800771@@ -1176,6 +1229,8 @@ void mt7996_mcu_set_mimo(struct mt7996_phy *phy);
developer66e89bc2024-04-23 14:50:01 +0800772 int mt7996_set_muru_cfg(struct mt7996_phy *phy, u8 action, u8 val);
773 int mt7996_mcu_set_muru_cfg(struct mt7996_phy *phy, void *data);
774 void mt7996_set_beacon_vif(void *data, u8 *mac, struct ieee80211_vif *vif);
775+int mt7996_mcu_set_csi(struct mt7996_phy *phy, u8 mode,
776+ u8 cfg, u8 v1, u32 v2, u8 *mac_addr);
777 #endif
778
779 int mt7996_mcu_edcca_enable(struct mt7996_phy *phy, bool enable);
780diff --git a/mt7996/vendor.c b/mt7996/vendor.c
developer05f3b2b2024-08-19 19:17:34 +0800781index 64ef5515..84b50ab2 100644
developer66e89bc2024-04-23 14:50:01 +0800782--- a/mt7996/vendor.c
783+++ b/mt7996/vendor.c
developer05f3b2b2024-08-19 19:17:34 +0800784@@ -119,6 +119,19 @@ beacon_ctrl_policy[NUM_MTK_VENDOR_ATTRS_BEACON_CTRL] = {
developer66e89bc2024-04-23 14:50:01 +0800785 [MTK_VENDOR_ATTR_BEACON_CTRL_MODE] = { .type = NLA_U8 },
786 };
787
788+static const struct nla_policy
789+csi_ctrl_policy[NUM_MTK_VENDOR_ATTRS_CSI_CTRL] = {
developer05f3b2b2024-08-19 19:17:34 +0800790+ [MTK_VENDOR_ATTR_CSI_CTRL_BAND_IDX] = { .type = NLA_U8 },
developer66e89bc2024-04-23 14:50:01 +0800791+ [MTK_VENDOR_ATTR_CSI_CTRL_CFG] = {.type = NLA_NESTED },
792+ [MTK_VENDOR_ATTR_CSI_CTRL_CFG_MODE] = { .type = NLA_U8 },
793+ [MTK_VENDOR_ATTR_CSI_CTRL_CFG_TYPE] = { .type = NLA_U8 },
794+ [MTK_VENDOR_ATTR_CSI_CTRL_CFG_VAL1] = { .type = NLA_U8 },
795+ [MTK_VENDOR_ATTR_CSI_CTRL_CFG_VAL2] = { .type = NLA_U32 },
796+ [MTK_VENDOR_ATTR_CSI_CTRL_MAC_ADDR] = { .type = NLA_NESTED },
797+ [MTK_VENDOR_ATTR_CSI_CTRL_DUMP_NUM] = { .type = NLA_U16 },
798+ [MTK_VENDOR_ATTR_CSI_CTRL_DATA] = { .type = NLA_NESTED },
799+};
800+
801 struct mt7996_amnt_data {
802 u8 idx;
803 u8 addr[ETH_ALEN];
developer05f3b2b2024-08-19 19:17:34 +0800804@@ -1000,7 +1013,226 @@ static int mt7996_vendor_beacon_ctrl(struct wiphy *wiphy,
developer66e89bc2024-04-23 14:50:01 +0800805
806 return 0;
807 }
808+static int mt7996_vendor_csi_ctrl(struct wiphy *wiphy,
809+ struct wireless_dev *wdev,
810+ const void *data,
811+ int data_len)
812+{
813+ struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
developer05f3b2b2024-08-19 19:17:34 +0800814+ struct mt7996_dev *dev = mt7996_hw_dev(hw);
815+ struct mt7996_phy *phy;
816+ struct mt76_phy *mphy;
developer66e89bc2024-04-23 14:50:01 +0800817+ struct nlattr *tb[NUM_MTK_VENDOR_ATTRS_CSI_CTRL];
developer05f3b2b2024-08-19 19:17:34 +0800818+ u8 band_idx = 0;
developer66e89bc2024-04-23 14:50:01 +0800819+ int err;
820+
821+ err = nla_parse(tb, MTK_VENDOR_ATTR_CSI_CTRL_MAX, data, data_len,
822+ csi_ctrl_policy, NULL);
823+ if (err)
824+ return err;
825+
developer05f3b2b2024-08-19 19:17:34 +0800826+ if (tb[MTK_VENDOR_ATTR_CSI_CTRL_BAND_IDX])
827+ band_idx = nla_get_u8(tb[MTK_VENDOR_ATTR_CSI_CTRL_BAND_IDX]);
828+
829+ if (!mt7996_band_valid(dev, band_idx))
830+ goto error;
831+
832+ mphy = dev->mt76.phys[band_idx];
833+ if (!mphy)
834+ goto error;
835+
836+ phy = (struct mt7996_phy *)mphy->priv;
837+ if (!phy)
838+ goto error;
839+
developer66e89bc2024-04-23 14:50:01 +0800840+ if (tb[MTK_VENDOR_ATTR_CSI_CTRL_CFG]) {
841+ u8 mode = 0, type = 0, v1 = 0;
842+ u32 v2 = 0;
843+ u8 mac_addr[ETH_ALEN] = {};
844+ struct nlattr *cur;
845+ int rem;
846+
847+ nla_for_each_nested(cur, tb[MTK_VENDOR_ATTR_CSI_CTRL_CFG], rem) {
848+ switch (nla_type(cur)) {
849+ case MTK_VENDOR_ATTR_CSI_CTRL_CFG_MODE:
850+ mode = nla_get_u8(cur);
851+ break;
852+ case MTK_VENDOR_ATTR_CSI_CTRL_CFG_TYPE:
853+ type = nla_get_u8(cur);
854+ break;
855+ case MTK_VENDOR_ATTR_CSI_CTRL_CFG_VAL1:
856+ v1 = nla_get_u8(cur);
857+ break;
858+ case MTK_VENDOR_ATTR_CSI_CTRL_CFG_VAL2:
859+ v2 = nla_get_u32(cur);
860+ break;
861+ default:
862+ return -EINVAL;
863+ };
864+ }
865+
866+ if (tb[MTK_VENDOR_ATTR_CSI_CTRL_MAC_ADDR]) {
867+ u8 idx = 0;
868+
869+ nla_for_each_nested(cur, tb[MTK_VENDOR_ATTR_CSI_CTRL_MAC_ADDR], rem) {
870+ mac_addr[idx++] = nla_get_u8(cur);
871+ }
872+ }
873+
874+ err = mt7996_mcu_set_csi(phy, mode, type, v1, v2, mac_addr);
875+ if (err < 0)
876+ return err;
877+
878+ spin_lock_bh(&phy->csi.lock);
developer05f3b2b2024-08-19 19:17:34 +0800879+
developer66e89bc2024-04-23 14:50:01 +0800880+ phy->csi.enable = !!mode;
881+
882+ /* clean up old csi stats */
883+ if ((mode == CSI_CONTROL_MODE_STOP || mode == CSI_CONTROL_MODE_SET)
884+ && !list_empty(&phy->csi.list)) {
885+ struct csi_data *c, *tmp_c;
886+
887+ list_for_each_entry_safe(c, tmp_c, &phy->csi.list, node) {
888+ list_del(&c->node);
889+ kfree(c);
890+ phy->csi.count--;
891+ }
892+ } else if (mode == CSI_CONTROL_MODE_START) {
893+ phy->csi.last_record = 0;
894+ }
895+
896+ spin_unlock_bh(&phy->csi.lock);
897+
898+ if (mode == CSI_CONTROL_MODE_SET && type == CSI_CONFIG_STA_FILTER && v1 == 2)
899+ phy->csi.interval = v2;
900+ }
901+
902+ return 0;
developer05f3b2b2024-08-19 19:17:34 +0800903+
904+error:
905+ dev_err(dev->mt76.dev, "Invalid band idx: %d\n", band_idx);
906+ return -EINVAL;
developer66e89bc2024-04-23 14:50:01 +0800907+}
908+
909+static int
910+mt7996_vendor_csi_ctrl_dump(struct wiphy *wiphy, struct wireless_dev *wdev,
911+ struct sk_buff *skb, const void *data, int data_len,
912+ unsigned long *storage)
913+{
914+#define RESERVED_SET BIT(31)
915+ struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
developer05f3b2b2024-08-19 19:17:34 +0800916+ struct mt7996_dev *dev = mt7996_hw_dev(hw);
917+ struct mt7996_phy *phy;
918+ struct mt76_phy *mphy;
developer66e89bc2024-04-23 14:50:01 +0800919+ struct nlattr *tb[NUM_MTK_VENDOR_ATTRS_CSI_CTRL] = {0};
developer05f3b2b2024-08-19 19:17:34 +0800920+ u8 band_idx = 0;
developer66e89bc2024-04-23 14:50:01 +0800921+ int err = 0;
922+
923+ if (*storage & RESERVED_SET) {
924+ if ((*storage & GENMASK(15, 0)) == 0)
925+ return -ENOENT;
926+ (*storage)--;
927+ }
928+
929+ if (data) {
930+ err = nla_parse(tb, MTK_VENDOR_ATTR_CSI_CTRL_MAX, data, data_len,
931+ csi_ctrl_policy, NULL);
932+ if (err)
933+ return err;
934+ }
935+
developer05f3b2b2024-08-19 19:17:34 +0800936+ if (tb[MTK_VENDOR_ATTR_CSI_CTRL_BAND_IDX])
937+ band_idx = nla_get_u8(tb[MTK_VENDOR_ATTR_CSI_CTRL_BAND_IDX]);
938+
939+ if (!mt7996_band_valid(dev, band_idx))
940+ return -EINVAL;
941
942+ mphy = dev->mt76.phys[band_idx];
943+ if (!mphy)
944+ return -EINVAL;
945+
946+ phy = (struct mt7996_phy *)mphy->priv;
947+ if (!phy)
948+ return -EINVAL;
949+
developer66e89bc2024-04-23 14:50:01 +0800950+ if (!(*storage & RESERVED_SET) && tb[MTK_VENDOR_ATTR_CSI_CTRL_DUMP_NUM]) {
951+ *storage = nla_get_u16(tb[MTK_VENDOR_ATTR_CSI_CTRL_DUMP_NUM]);
952+ *storage |= RESERVED_SET;
953+ }
954+
955+ spin_lock_bh(&phy->csi.lock);
956+
957+ if (!list_empty(&phy->csi.list)) {
958+ struct csi_data *csi;
959+ void *a, *b;
960+ int i;
961+
962+ csi = list_first_entry(&phy->csi.list, struct csi_data, node);
963+
964+ a = nla_nest_start(skb, MTK_VENDOR_ATTR_CSI_CTRL_DATA);
965+ if (!a)
966+ goto out;
967+
968+ if (nla_put_u8(skb, MTK_VENDOR_ATTR_CSI_DATA_VER, 1) ||
969+ nla_put_u8(skb, MTK_VENDOR_ATTR_CSI_DATA_RSSI, csi->rssi) ||
970+ nla_put_u8(skb, MTK_VENDOR_ATTR_CSI_DATA_SNR, csi->snr) ||
971+ nla_put_u8(skb, MTK_VENDOR_ATTR_CSI_DATA_BW, csi->data_bw) ||
972+ nla_put_u8(skb, MTK_VENDOR_ATTR_CSI_DATA_CH_IDX, csi->pri_ch_idx) ||
973+ nla_put_u8(skb, MTK_VENDOR_ATTR_CSI_DATA_MODE, csi->rx_mode))
974+ goto out;
975+
976+ if (nla_put_u16(skb, MTK_VENDOR_ATTR_CSI_DATA_TX_ANT, csi->tx_idx) ||
977+ nla_put_u16(skb, MTK_VENDOR_ATTR_CSI_DATA_RX_ANT, csi->rx_idx))
978+ goto out;
979+
980+ if (nla_put_u32(skb, MTK_VENDOR_ATTR_CSI_DATA_INFO, csi->ext_info) ||
981+ nla_put_u32(skb, MTK_VENDOR_ATTR_CSI_DATA_CHAIN_INFO, csi->chain_info) ||
982+ nla_put_u32(skb, MTK_VENDOR_ATTR_CSI_DATA_TS, csi->ts))
983+ goto out;
984+
985+ b = nla_nest_start(skb, MTK_VENDOR_ATTR_CSI_DATA_TA);
986+ if (!b)
987+ goto out;
988+
989+ for (i = 0; i < ARRAY_SIZE(csi->ta); i++)
990+ if (nla_put_u8(skb, i, csi->ta[i]))
991+ goto out;
992+ nla_nest_end(skb, b);
993+
994+ if (nla_put_u32(skb, MTK_VENDOR_ATTR_CSI_DATA_NUM, csi->data_num))
995+ goto out;
996+
997+ b = nla_nest_start(skb, MTK_VENDOR_ATTR_CSI_DATA_I);
998+ if (!b)
999+ goto out;
1000+
1001+ for (i = 0; i < csi->data_num; i++)
1002+ if (nla_put_u16(skb, i, csi->data_i[i]))
1003+ goto out;
1004+ nla_nest_end(skb, b);
1005+
1006+ b = nla_nest_start(skb, MTK_VENDOR_ATTR_CSI_DATA_Q);
1007+ if (!b)
1008+ goto out;
1009+
1010+ for (i = 0; i < csi->data_num; i++)
1011+ if (nla_put_u16(skb, i, csi->data_q[i]))
1012+ goto out;
1013+ nla_nest_end(skb, b);
1014+
1015+ nla_nest_end(skb, a);
1016+
1017+ list_del(&csi->node);
1018+ kfree(csi);
1019+ phy->csi.count--;
1020+
1021+ err = phy->csi.count;
1022+ }
1023+out:
1024+ spin_unlock_bh(&phy->csi.lock);
1025+
1026+ return err;
1027+}
1028
1029 static const struct wiphy_vendor_command mt7996_vendor_commands[] = {
1030 {
developer05f3b2b2024-08-19 19:17:34 +08001031@@ -1129,6 +1361,18 @@ static const struct wiphy_vendor_command mt7996_vendor_commands[] = {
developer66e89bc2024-04-23 14:50:01 +08001032 .policy = beacon_ctrl_policy,
1033 .maxattr = MTK_VENDOR_ATTR_BEACON_CTRL_MAX,
1034 },
1035+ {
1036+ .info = {
1037+ .vendor_id = MTK_NL80211_VENDOR_ID,
1038+ .subcmd = MTK_NL80211_VENDOR_SUBCMD_CSI_CTRL,
1039+ },
1040+ .flags = WIPHY_VENDOR_CMD_NEED_NETDEV |
1041+ WIPHY_VENDOR_CMD_NEED_RUNNING,
1042+ .doit = mt7996_vendor_csi_ctrl,
1043+ .dumpit = mt7996_vendor_csi_ctrl_dump,
1044+ .policy = csi_ctrl_policy,
1045+ .maxattr = MTK_VENDOR_ATTR_CSI_CTRL_MAX,
1046+ },
1047 };
1048
1049 void mt7996_vendor_register(struct mt7996_phy *phy)
developer05f3b2b2024-08-19 19:17:34 +08001050@@ -1136,6 +1380,9 @@ void mt7996_vendor_register(struct mt7996_phy *phy)
developer66e89bc2024-04-23 14:50:01 +08001051 phy->mt76->hw->wiphy->vendor_commands = mt7996_vendor_commands;
1052 phy->mt76->hw->wiphy->n_vendor_commands = ARRAY_SIZE(mt7996_vendor_commands);
1053
1054+ INIT_LIST_HEAD(&phy->csi.list);
1055+ spin_lock_init(&phy->csi.lock);
1056+
1057 spin_lock_init(&phy->amnt_lock);
1058 }
1059 #endif
1060diff --git a/mt7996/vendor.h b/mt7996/vendor.h
developer05f3b2b2024-08-19 19:17:34 +08001061index 32346775..834b3d08 100644
developer66e89bc2024-04-23 14:50:01 +08001062--- a/mt7996/vendor.h
1063+++ b/mt7996/vendor.h
1064@@ -7,6 +7,7 @@
1065
1066 enum mtk_nl80211_vendor_subcmds {
1067 MTK_NL80211_VENDOR_SUBCMD_AMNT_CTRL = 0xae,
1068+ MTK_NL80211_VENDOR_SUBCMD_CSI_CTRL = 0xc2,
1069 MTK_NL80211_VENDOR_SUBCMD_RFEATURE_CTRL = 0xc3,
1070 MTK_NL80211_VENDOR_SUBCMD_WIRELESS_CTRL = 0xc4,
1071 MTK_NL80211_VENDOR_SUBCMD_MU_CTRL = 0xc5,
developer05f3b2b2024-08-19 19:17:34 +08001072@@ -240,6 +241,57 @@ enum mtk_vendor_attr_beacon_ctrl {
developer66e89bc2024-04-23 14:50:01 +08001073 NUM_MTK_VENDOR_ATTRS_BEACON_CTRL - 1
1074 };
1075
1076+enum mtk_vendor_attr_csi_ctrl {
1077+ MTK_VENDOR_ATTR_CSI_CTRL_UNSPEC,
1078+
1079+ MTK_VENDOR_ATTR_CSI_CTRL_CFG,
1080+ MTK_VENDOR_ATTR_CSI_CTRL_CFG_MODE,
1081+ MTK_VENDOR_ATTR_CSI_CTRL_CFG_TYPE,
1082+ MTK_VENDOR_ATTR_CSI_CTRL_CFG_VAL1,
1083+ MTK_VENDOR_ATTR_CSI_CTRL_CFG_VAL2,
1084+ MTK_VENDOR_ATTR_CSI_CTRL_MAC_ADDR,
1085+
1086+ MTK_VENDOR_ATTR_CSI_CTRL_DUMP_NUM,
1087+
1088+ MTK_VENDOR_ATTR_CSI_CTRL_DATA,
1089+
developer05f3b2b2024-08-19 19:17:34 +08001090+ MTK_VENDOR_ATTR_CSI_CTRL_BAND_IDX,
1091+
developer66e89bc2024-04-23 14:50:01 +08001092+ /* keep last */
1093+ NUM_MTK_VENDOR_ATTRS_CSI_CTRL,
1094+ MTK_VENDOR_ATTR_CSI_CTRL_MAX =
1095+ NUM_MTK_VENDOR_ATTRS_CSI_CTRL - 1
1096+};
1097+
1098+enum mtk_vendor_attr_csi_data {
1099+ MTK_VENDOR_ATTR_CSI_DATA_UNSPEC,
1100+ MTK_VENDOR_ATTR_CSI_DATA_PAD,
1101+
1102+ MTK_VENDOR_ATTR_CSI_DATA_VER,
1103+ MTK_VENDOR_ATTR_CSI_DATA_TS,
1104+ MTK_VENDOR_ATTR_CSI_DATA_RSSI,
1105+ MTK_VENDOR_ATTR_CSI_DATA_SNR,
1106+ MTK_VENDOR_ATTR_CSI_DATA_BW,
1107+ MTK_VENDOR_ATTR_CSI_DATA_CH_IDX,
1108+ MTK_VENDOR_ATTR_CSI_DATA_TA,
1109+ MTK_VENDOR_ATTR_CSI_DATA_NUM,
1110+ MTK_VENDOR_ATTR_CSI_DATA_I,
1111+ MTK_VENDOR_ATTR_CSI_DATA_Q,
1112+ MTK_VENDOR_ATTR_CSI_DATA_INFO,
1113+ MTK_VENDOR_ATTR_CSI_DATA_RSVD1,
1114+ MTK_VENDOR_ATTR_CSI_DATA_RSVD2,
1115+ MTK_VENDOR_ATTR_CSI_DATA_RSVD3,
1116+ MTK_VENDOR_ATTR_CSI_DATA_RSVD4,
1117+ MTK_VENDOR_ATTR_CSI_DATA_TX_ANT,
1118+ MTK_VENDOR_ATTR_CSI_DATA_RX_ANT,
1119+ MTK_VENDOR_ATTR_CSI_DATA_MODE,
1120+ MTK_VENDOR_ATTR_CSI_DATA_CHAIN_INFO,
1121+
1122+ /* keep last */
1123+ NUM_MTK_VENDOR_ATTRS_CSI_DATA,
1124+ MTK_VENDOR_ATTR_CSI_DATA_MAX =
1125+ NUM_MTK_VENDOR_ATTRS_CSI_DATA - 1
1126+};
1127 #endif
1128
1129 #endif
1130--
developer9237f442024-06-14 17:13:04 +080011312.18.0
developer66e89bc2024-04-23 14:50:01 +08001132