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