blob: d83c3f98e62abfa935eeb7d4b0082530ddbf97ba [file] [log] [blame]
developer064da3c2023-06-13 15:57:26 +08001From 2637da59e92d101889cf3680e57f0594c6b349ec Mon Sep 17 00:00:00 2001
2From: Evelyn Tsai <evelyn.tsai@mediatek.com>
3Date: Wed, 26 Apr 2023 04:40:05 +0800
4Subject: [PATCH 1003/1015] wifi: mt76: mt7996: Add air monitor support
5
6---
7 mt76_connac_mcu.h | 1 +
8 mt7996/mac.c | 4 +
9 mt7996/main.c | 4 +
10 mt7996/mt7996.h | 35 +++++
11 mt7996/vendor.c | 362 ++++++++++++++++++++++++++++++++++++++++++++++
12 mt7996/vendor.h | 39 +++++
13 6 files changed, 445 insertions(+)
14
15diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
16index 4bb9508a..e62f17ad 100644
17--- a/mt76_connac_mcu.h
18+++ b/mt76_connac_mcu.h
19@@ -1206,6 +1206,7 @@ enum {
20 MCU_UNI_CMD_REG_ACCESS = 0x0d,
21 MCU_UNI_CMD_CHIP_CONFIG = 0x0e,
22 MCU_UNI_CMD_POWER_CTRL = 0x0f,
23+ MCU_UNI_CMD_CFG_SMESH = 0x10,
24 MCU_UNI_CMD_RX_HDR_TRANS = 0x12,
25 MCU_UNI_CMD_SER = 0x13,
26 MCU_UNI_CMD_TWT = 0x14,
27diff --git a/mt7996/mac.c b/mt7996/mac.c
28index 05269e7f..3dc5cdae 100644
29--- a/mt7996/mac.c
30+++ b/mt7996/mac.c
31@@ -865,6 +865,10 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb)
32 if (ieee80211_has_a4(fc) && is_mesh && status->amsdu)
33 *qos &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT;
34 }
35+#ifdef CONFIG_MTK_VENDOR
36+ if (phy->amnt_ctrl.enable && !ieee80211_is_beacon(fc))
37+ mt7996_vendor_amnt_fill_rx(phy, skb);
38+#endif
39 } else {
40 status->flag |= RX_FLAG_8023;
41 }
42diff --git a/mt7996/main.c b/mt7996/main.c
43index 2ed66e6c..e5627c96 100644
44--- a/mt7996/main.c
45+++ b/mt7996/main.c
46@@ -672,6 +672,10 @@ int mt7996_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
47 mt7996_mac_wtbl_update(dev, idx,
48 MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
49
50+#ifdef CONFIG_MTK_VENDOR
51+ mt7996_vendor_amnt_sta_remove(mvif->phy, sta);
52+#endif
53+
54 ret = mt7996_mcu_add_sta(dev, vif, sta, true);
55 if (ret)
56 return ret;
57diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
58index b9f3dd8e..dc44edc1 100644
59--- a/mt7996/mt7996.h
60+++ b/mt7996/mt7996.h
61@@ -235,6 +235,34 @@ enum {
62 SCS_ENABLE,
63 };
64
65+#ifdef CONFIG_MTK_VENDOR
66+#define MT7996_AIR_MONITOR_MAX_ENTRY 16
67+#define MT7996_AIR_MONITOR_MAX_GROUP (MT7996_AIR_MONITOR_MAX_ENTRY >> 1)
68+
69+struct mt7996_air_monitor_group {
70+ bool enable;
71+ bool used[2];
72+};
73+
74+struct mt7996_air_monitor_entry {
75+ bool enable;
76+
77+ u8 group_idx;
78+ u8 group_used_idx;
79+ u8 muar_idx;
80+ u8 addr[ETH_ALEN];
81+ u32 last_seen;
82+ s8 rssi[4];
83+ struct ieee80211_sta *sta;
84+};
85+
86+struct mt7996_air_monitor_ctrl {
87+ u8 enable;
88+ struct mt7996_air_monitor_group group[MT7996_AIR_MONITOR_MAX_GROUP];
89+ struct mt7996_air_monitor_entry entry[MT7996_AIR_MONITOR_MAX_ENTRY];
90+};
91+#endif
92+
93 struct mt7996_phy {
94 struct mt76_phy *mt76;
95 struct mt7996_dev *dev;
96@@ -285,6 +313,10 @@ struct mt7996_phy {
97 u8 spe_idx;
98 } test;
99 #endif
100+#ifdef CONFIG_MTK_VENDOR
101+ spinlock_t amnt_lock;
102+ struct mt7996_air_monitor_ctrl amnt_ctrl;
103+#endif
104 };
105
106 struct mt7996_dev {
107@@ -677,6 +709,9 @@ void mt7996_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
108 #ifdef CONFIG_MTK_VENDOR
109 void mt7996_set_wireless_vif(void *data, u8 *mac, struct ieee80211_vif *vif);
110 void mt7996_vendor_register(struct mt7996_phy *phy);
111+void mt7996_vendor_amnt_fill_rx(struct mt7996_phy *phy, struct sk_buff *skb);
112+int mt7996_vendor_amnt_sta_remove(struct mt7996_phy *phy,
113+ struct ieee80211_sta *sta);
114 #endif
115
116 #ifdef CONFIG_MTK_DEBUG
117diff --git a/mt7996/vendor.c b/mt7996/vendor.c
118index 08ecc2b3..8a021324 100644
119--- a/mt7996/vendor.c
120+++ b/mt7996/vendor.c
121@@ -15,6 +15,32 @@ mu_ctrl_policy[NUM_MTK_VENDOR_ATTRS_MU_CTRL] = {
122 [MTK_VENDOR_ATTR_MU_CTRL_DUMP] = {.type = NLA_U8 },
123 };
124
125+static const struct nla_policy
126+amnt_ctrl_policy[NUM_MTK_VENDOR_ATTRS_AMNT_CTRL] = {
127+ [MTK_VENDOR_ATTR_AMNT_CTRL_SET] = {.type = NLA_NESTED },
128+ [MTK_VENDOR_ATTR_AMNT_CTRL_DUMP] = { .type = NLA_NESTED },
129+};
130+
131+static const struct nla_policy
132+amnt_set_policy[NUM_MTK_VENDOR_ATTRS_AMNT_SET] = {
133+ [MTK_VENDOR_ATTR_AMNT_SET_INDEX] = {.type = NLA_U8 },
134+ [MTK_VENDOR_ATTR_AMNT_SET_MACADDR] = NLA_POLICY_EXACT_LEN_WARN(ETH_ALEN),
135+};
136+
137+static const struct nla_policy
138+amnt_dump_policy[NUM_MTK_VENDOR_ATTRS_AMNT_DUMP] = {
139+ [MTK_VENDOR_ATTR_AMNT_DUMP_INDEX] = {.type = NLA_U8 },
140+ [MTK_VENDOR_ATTR_AMNT_DUMP_LEN] = { .type = NLA_U8 },
141+ [MTK_VENDOR_ATTR_AMNT_DUMP_RESULT] = { .type = NLA_NESTED },
142+};
143+
144+struct mt7996_amnt_data {
145+ u8 idx;
146+ u8 addr[ETH_ALEN];
147+ s8 rssi[4];
148+ u32 last_seen;
149+};
150+
151 static int mt7996_vendor_mu_ctrl(struct wiphy *wiphy,
152 struct wireless_dev *wdev,
153 const void *data,
154@@ -62,6 +88,328 @@ mt7996_vendor_mu_ctrl_dump(struct wiphy *wiphy, struct wireless_dev *wdev,
155 return len;
156 }
157
158+void mt7996_vendor_amnt_fill_rx(struct mt7996_phy *phy, struct sk_buff *skb)
159+{
160+ struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
161+ struct mt7996_air_monitor_ctrl *ctrl = &phy->amnt_ctrl;
162+ struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
163+ __le16 fc = hdr->frame_control;
164+ u8 addr[ETH_ALEN];
165+ int i;
166+
167+ if (!ieee80211_has_fromds(fc))
168+ ether_addr_copy(addr, hdr->addr2);
169+ else if (ieee80211_has_tods(fc))
170+ ether_addr_copy(addr, hdr->addr4);
171+ else
172+ ether_addr_copy(addr, hdr->addr3);
173+
174+ spin_lock_bh(&phy->amnt_lock);
175+ for (i = 0; i < MT7996_AIR_MONITOR_MAX_ENTRY; i++) {
176+ struct mt7996_air_monitor_entry *entry;
177+
178+ if (ether_addr_equal(addr, ctrl->entry[i].addr)) {
179+ entry = &ctrl->entry[i];
180+ entry->rssi[0] = status->chain_signal[0];
181+ entry->rssi[1] = status->chain_signal[1];
182+ entry->rssi[2] = status->chain_signal[2];
183+ entry->rssi[3] = status->chain_signal[3];
184+ entry->last_seen = jiffies;
185+ break;
186+ }
187+ }
188+ spin_unlock_bh(&phy->amnt_lock);
189+}
190+
191+static int
192+mt7996_vendor_smesh_ctrl(struct mt7996_phy *phy, u8 write,
193+ u8 enable, u8 *value)
194+{
195+#define UNI_CMD_SMESH_PARAM 0
196+ struct mt7996_dev *dev = phy->dev;
197+ struct smesh_param {
198+ __le16 tag;
199+ __le16 length;
200+
201+ u8 enable;
202+ bool a2;
203+ bool a1;
204+ bool data;
205+ bool mgnt;
206+ bool ctrl;
207+ u8 padding[2];
208+ } req = {
209+ .tag = cpu_to_le16(UNI_CMD_SMESH_PARAM),
210+ .length = cpu_to_le16(sizeof(req) - 4),
211+
212+ .enable = enable,
213+ .a2 = true,
214+ .a1 = true,
215+ .data = true,
216+ .mgnt = false,
217+ .ctrl = false,
218+ };
219+ struct smesh_param *res;
220+ struct sk_buff *skb;
221+ int ret = 0;
222+
223+ if (!value)
224+ return -EINVAL;
225+
226+ ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_WM_UNI_CMD(CFG_SMESH),
227+ &req, sizeof(req), !write, &skb);
228+
229+ if (ret || write)
230+ return ret;
231+
232+ res = (struct smesh_param *) skb->data;
233+
234+ *value = res->enable;
235+
236+ dev_kfree_skb(skb);
237+
238+ return 0;
239+}
240+
241+static int
242+mt7996_vendor_amnt_muar(struct mt7996_phy *phy, u8 muar_idx, u8 *addr)
243+{
244+#define UNI_CMD_MUAR_ENTRY 2
245+ struct mt7996_dev *dev = phy->dev;
246+ struct muar_entry {
247+ __le16 tag;
248+ __le16 length;
249+
250+ bool smesh;
251+ u8 hw_bss_index;
252+ u8 muar_idx;
253+ u8 entry_add;
254+ u8 mac_addr[6];
255+ u8 padding[2];
256+ } __packed req = {
257+ .tag = cpu_to_le16(UNI_CMD_MUAR_ENTRY),
258+ .length = cpu_to_le16(sizeof(req) - 4),
259+
260+ .smesh = true,
261+ .hw_bss_index = phy != &dev->phy,
262+ .muar_idx = muar_idx,
263+ .entry_add = 1,
264+ };
265+
266+ ether_addr_copy(req.mac_addr, addr);
267+ return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(REPT_MUAR), &req,
268+ sizeof(req), true);
269+}
270+
271+static int
272+mt7996_vendor_amnt_set_en(struct mt7996_phy *phy, u8 enable)
273+{
274+ u8 status;
275+ int ret;
276+
277+ ret = mt7996_vendor_smesh_ctrl(phy, 0, enable, &status);
278+ if (ret)
279+ return ret;
280+
281+ if (status == enable)
282+ return 0;
283+
284+ ret = mt7996_vendor_smesh_ctrl(phy, 1, enable, &status);
285+ if (ret)
286+ return ret;
287+
288+ return 0;
289+}
290+
291+static int
292+mt7996_vendor_amnt_set_addr(struct mt7996_phy *phy, u8 index, u8 *addr)
293+{
294+ struct mt7996_air_monitor_ctrl *amnt_ctrl = &phy->amnt_ctrl;
295+ struct mt7996_air_monitor_group *group;
296+ struct mt7996_air_monitor_entry *entry;
297+ int ret, i, j;
298+
299+ if (index >= MT7996_AIR_MONITOR_MAX_ENTRY)
300+ return -1;
301+
302+ spin_lock_bh(&phy->amnt_lock);
303+ entry = &amnt_ctrl->entry[index];
304+ if (!is_zero_ether_addr(addr)) {
305+ if (entry->enable == false) {
306+ for (i = 0; i < MT7996_AIR_MONITOR_MAX_GROUP; i++) {
307+ group = &(amnt_ctrl->group[i]);
308+ if (group->used[0] == false)
309+ j = 0;
310+ else if (group->used[1] == false)
311+ j = 1;
312+ else
313+ continue;
314+
315+ group->enable = true;
316+ group->used[j] = true;
317+ entry->enable = true;
318+ entry->group_idx = i;
319+ entry->group_used_idx = j;
320+ entry->muar_idx = 32 + 4 * i + 2 * j;
321+ break;
322+ }
323+ }
324+ } else {
325+ group = &(amnt_ctrl->group[entry->group_idx]);
326+
327+ group->used[entry->group_used_idx] = false;
328+ if (group->used[0] == false && group->used[1] == false)
329+ group->enable = false;
330+
331+ entry->enable = false;
332+ }
333+ ether_addr_copy(entry->addr, addr);
334+ amnt_ctrl->enable &= ~(1 << entry->group_idx);
335+ amnt_ctrl->enable |= entry->enable << entry->group_idx;
336+ spin_unlock_bh(&phy->amnt_lock);
337+
338+ ret = mt7996_vendor_amnt_muar(phy, entry->muar_idx, addr);
339+ if (ret)
340+ return ret;
341+
342+ return mt7996_vendor_amnt_set_en(phy, amnt_ctrl->enable);
343+}
344+
345+static int
346+mt7966_vendor_amnt_ctrl(struct wiphy *wiphy, struct wireless_dev *wdev,
347+ const void *data, int data_len)
348+{
349+ struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
350+ struct mt7996_phy *phy = mt7996_hw_phy(hw);
351+ struct nlattr *tb1[NUM_MTK_VENDOR_ATTRS_AMNT_CTRL];
352+ struct nlattr *tb2[NUM_MTK_VENDOR_ATTRS_AMNT_SET];
353+ u8 index = 0;
354+ u8 mac_addr[ETH_ALEN];
355+ int err;
356+
357+ err = nla_parse(tb1, MTK_VENDOR_ATTR_AMNT_CTRL_MAX, data, data_len,
358+ amnt_ctrl_policy, NULL);
359+ if (err)
360+ return err;
361+
362+ if (!tb1[MTK_VENDOR_ATTR_AMNT_CTRL_SET])
363+ return -EINVAL;
364+
365+ err = nla_parse_nested(tb2, MTK_VENDOR_ATTR_AMNT_SET_MAX,
366+ tb1[MTK_VENDOR_ATTR_AMNT_CTRL_SET], amnt_set_policy, NULL);
367+
368+ if (!tb2[MTK_VENDOR_ATTR_AMNT_SET_INDEX] ||
369+ !tb2[MTK_VENDOR_ATTR_AMNT_SET_MACADDR])
370+ return -EINVAL;
371+
372+ index = nla_get_u8(tb2[MTK_VENDOR_ATTR_AMNT_SET_INDEX]);
373+ memcpy(mac_addr, nla_data(tb2[MTK_VENDOR_ATTR_AMNT_SET_MACADDR]), ETH_ALEN);
374+
375+ return mt7996_vendor_amnt_set_addr(phy, index, mac_addr);
376+}
377+
378+int mt7996_vendor_amnt_sta_remove(struct mt7996_phy *phy,
379+ struct ieee80211_sta *sta)
380+{
381+ u8 zero[ETH_ALEN] = {};
382+ int i;
383+
384+ if (!phy->amnt_ctrl.enable)
385+ return 0;
386+
387+ for (i = 0; i < MT7996_AIR_MONITOR_MAX_ENTRY; i++)
388+ if (ether_addr_equal(sta->addr, phy->amnt_ctrl.entry[i].addr))
389+ return mt7996_vendor_amnt_set_addr(phy, i, zero);
390+ return 0;
391+}
392+
393+static int
394+mt7996_amnt_dump(struct mt7996_phy *phy, struct sk_buff *skb,
395+ u8 amnt_idx, int *attrtype)
396+{
397+ struct mt7996_air_monitor_entry *entry;
398+ struct mt7996_amnt_data data;
399+ u32 last_seen = 0;
400+
401+ spin_lock_bh(&phy->amnt_lock);
402+ entry = &phy->amnt_ctrl.entry[amnt_idx];
403+ if (entry->enable == 0) {
404+ spin_unlock_bh(&phy->amnt_lock);
405+ return 0;
406+ }
407+
408+ last_seen = jiffies_to_msecs(jiffies - entry->last_seen);
409+ ether_addr_copy(data.addr, entry->addr);
410+ data.rssi[0] = entry->rssi[0];
411+ data.rssi[1] = entry->rssi[1];
412+ data.rssi[2] = entry->rssi[2];
413+ data.rssi[3] = entry->rssi[3];
414+ spin_unlock_bh(&phy->amnt_lock);
415+
416+ data.idx = amnt_idx;
417+ data.last_seen = last_seen;
418+
419+ nla_put(skb, (*attrtype)++, sizeof(struct mt7996_amnt_data), &data);
420+
421+ return 1;
422+}
423+
424+static int
425+mt7966_vendor_amnt_ctrl_dump(struct wiphy *wiphy, struct wireless_dev *wdev,
426+ struct sk_buff *skb, const void *data, int data_len,
427+ unsigned long *storage)
428+{
429+ struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
430+ struct mt7996_phy *phy = mt7996_hw_phy(hw);
431+ struct nlattr *tb1[NUM_MTK_VENDOR_ATTRS_AMNT_CTRL];
432+ struct nlattr *tb2[NUM_MTK_VENDOR_ATTRS_AMNT_DUMP];
433+ void *a, *b;
434+ int err = 0, attrtype = 0, i, len = 0;
435+ u8 amnt_idx;
436+
437+ if (*storage == 1)
438+ return -ENOENT;
439+ *storage = 1;
440+
441+ err = nla_parse(tb1, MTK_VENDOR_ATTR_AMNT_CTRL_MAX, data, data_len,
442+ amnt_ctrl_policy, NULL);
443+ if (err)
444+ return err;
445+
446+ if (!tb1[MTK_VENDOR_ATTR_AMNT_CTRL_DUMP])
447+ return -EINVAL;
448+
449+ err = nla_parse_nested(tb2, MTK_VENDOR_ATTR_AMNT_DUMP_MAX,
450+ tb1[MTK_VENDOR_ATTR_AMNT_CTRL_DUMP],
451+ amnt_dump_policy, NULL);
452+ if (err)
453+ return err;
454+
455+ if (!tb2[MTK_VENDOR_ATTR_AMNT_DUMP_INDEX])
456+ return -EINVAL;
457+
458+ amnt_idx = nla_get_u8(tb2[MTK_VENDOR_ATTR_AMNT_DUMP_INDEX]);
459+
460+ a = nla_nest_start(skb, MTK_VENDOR_ATTR_AMNT_CTRL_DUMP);
461+ b = nla_nest_start(skb, MTK_VENDOR_ATTR_AMNT_DUMP_RESULT);
462+
463+ if (amnt_idx != 0xff) {
464+ len += mt7996_amnt_dump(phy, skb, amnt_idx, &attrtype);
465+ } else {
466+ for (i = 0; i < MT7996_AIR_MONITOR_MAX_ENTRY; i++)
467+ len += mt7996_amnt_dump(phy, skb, i, &attrtype);
468+ }
469+
470+ nla_nest_end(skb, b);
471+
472+ nla_put_u8(skb, MTK_VENDOR_ATTR_AMNT_DUMP_LEN, len);
473+
474+ nla_nest_end(skb, a);
475+
476+ return len + 1;
477+}
478+
479+
480 static const struct wiphy_vendor_command mt7996_vendor_commands[] = {
481 {
482 .info = {
483@@ -75,10 +423,24 @@ static const struct wiphy_vendor_command mt7996_vendor_commands[] = {
484 .policy = mu_ctrl_policy,
485 .maxattr = MTK_VENDOR_ATTR_MU_CTRL_MAX,
486 },
487+ {
488+ .info = {
489+ .vendor_id = MTK_NL80211_VENDOR_ID,
490+ .subcmd = MTK_NL80211_VENDOR_SUBCMD_AMNT_CTRL,
491+ },
492+ .flags = WIPHY_VENDOR_CMD_NEED_NETDEV |
493+ WIPHY_VENDOR_CMD_NEED_RUNNING,
494+ .doit = mt7966_vendor_amnt_ctrl,
495+ .dumpit = mt7966_vendor_amnt_ctrl_dump,
496+ .policy = amnt_ctrl_policy,
497+ .maxattr = MTK_VENDOR_ATTR_AMNT_CTRL_MAX,
498+ },
499 };
500
501 void mt7996_vendor_register(struct mt7996_phy *phy)
502 {
503 phy->mt76->hw->wiphy->vendor_commands = mt7996_vendor_commands;
504 phy->mt76->hw->wiphy->n_vendor_commands = ARRAY_SIZE(mt7996_vendor_commands);
505+
506+ spin_lock_init(&phy->amnt_lock);
507 }
508diff --git a/mt7996/vendor.h b/mt7996/vendor.h
509index 8ac3ba8e..2078cafa 100644
510--- a/mt7996/vendor.h
511+++ b/mt7996/vendor.h
512@@ -4,6 +4,7 @@
513 #define MTK_NL80211_VENDOR_ID 0x0ce7
514
515 enum mtk_nl80211_vendor_subcmds {
516+ MTK_NL80211_VENDOR_SUBCMD_AMNT_CTRL = 0xae,
517 MTK_NL80211_VENDOR_SUBCMD_MU_CTRL = 0xc5,
518 };
519
520@@ -19,4 +20,42 @@ enum mtk_vendor_attr_mu_ctrl {
521 NUM_MTK_VENDOR_ATTRS_MU_CTRL - 1
522 };
523
524+enum mtk_vendor_attr_mnt_ctrl {
525+ MTK_VENDOR_ATTR_AMNT_CTRL_UNSPEC,
526+
527+ MTK_VENDOR_ATTR_AMNT_CTRL_SET,
528+ MTK_VENDOR_ATTR_AMNT_CTRL_DUMP,
529+
530+ /* keep last */
531+ NUM_MTK_VENDOR_ATTRS_AMNT_CTRL,
532+ MTK_VENDOR_ATTR_AMNT_CTRL_MAX =
533+ NUM_MTK_VENDOR_ATTRS_AMNT_CTRL - 1
534+};
535+
536+enum mtk_vendor_attr_mnt_set {
537+ MTK_VENDOR_ATTR_AMNT_SET_UNSPEC,
538+
539+ MTK_VENDOR_ATTR_AMNT_SET_INDEX,
540+ MTK_VENDOR_ATTR_AMNT_SET_MACADDR,
541+
542+ /* keep last */
543+ NUM_MTK_VENDOR_ATTRS_AMNT_SET,
544+ MTK_VENDOR_ATTR_AMNT_SET_MAX =
545+ NUM_MTK_VENDOR_ATTRS_AMNT_SET - 1
546+};
547+
548+enum mtk_vendor_attr_mnt_dump {
549+ MTK_VENDOR_ATTR_AMNT_DUMP_UNSPEC,
550+
551+ MTK_VENDOR_ATTR_AMNT_DUMP_INDEX,
552+ MTK_VENDOR_ATTR_AMNT_DUMP_LEN,
553+ MTK_VENDOR_ATTR_AMNT_DUMP_RESULT,
554+
555+ /* keep last */
556+ NUM_MTK_VENDOR_ATTRS_AMNT_DUMP,
557+ MTK_VENDOR_ATTR_AMNT_DUMP_MAX =
558+ NUM_MTK_VENDOR_ATTRS_AMNT_DUMP - 1
559+};
560+
561+
562 #endif
563--
5642.39.2
565