1a5487a68SSean Wang // SPDX-License-Identifier: BSD-3-Clause-Clear
2a5487a68SSean Wang /* Copyright (C) 2025-2026 MediaTek Inc. */
3a5487a68SSean Wang
4a5487a68SSean Wang #include <asm/byteorder.h>
5a5487a68SSean Wang #include <linux/bitfield.h>
6a5487a68SSean Wang #include <linux/errno.h>
7a5487a68SSean Wang #include <linux/kernel.h>
8a5487a68SSean Wang #include <linux/stddef.h>
9a5487a68SSean Wang #include <linux/string.h>
10a5487a68SSean Wang #include <linux/types.h>
11a5487a68SSean Wang #include <linux/ieee80211.h>
12a5487a68SSean Wang #include <net/cfg80211.h>
13a5487a68SSean Wang #include <net/mac80211.h>
14a5487a68SSean Wang
15a5487a68SSean Wang #include "mt7925.h"
16a5487a68SSean Wang #include "mcu.h"
17a5487a68SSean Wang #include "nan.h"
18a5487a68SSean Wang #include "regd.h"
19a5487a68SSean Wang
mt7925_nan_set_5g_channel(struct mt792x_dev * dev,struct mt7925_nan_enable_req_tlv * req,struct cfg80211_nan_conf * conf)20a5487a68SSean Wang static void mt7925_nan_set_5g_channel(struct mt792x_dev *dev,
21a5487a68SSean Wang struct mt7925_nan_enable_req_tlv *req,
22a5487a68SSean Wang struct cfg80211_nan_conf *conf)
23a5487a68SSean Wang {
24a5487a68SSean Wang struct ieee80211_channel *chan;
25a5487a68SSean Wang u32 ch5g = 0;
26a5487a68SSean Wang
27a5487a68SSean Wang chan = conf->band_cfgs[NL80211_BAND_5GHZ].chan;
28a5487a68SSean Wang
29a5487a68SSean Wang if (!chan)
30a5487a68SSean Wang return;
31a5487a68SSean Wang
32a5487a68SSean Wang if (!mt7925_regd_is_valid_channel(dev, NL80211_BAND_5GHZ, chan))
33a5487a68SSean Wang return;
34a5487a68SSean Wang
35*0f3605e4SSean Wang req->config_support_5g = 1;
36*0f3605e4SSean Wang req->support_5g_val = 1;
37a5487a68SSean Wang req->config_5g_channel = 1;
38a5487a68SSean Wang
39a5487a68SSean Wang if (chan->hw_value == NAN_5G_LOW_DISC_CHANNEL)
40a5487a68SSean Wang ch5g |= BIT(0);
41a5487a68SSean Wang else if (chan->hw_value == NAN_5G_HIGH_DISC_CHANNEL)
42a5487a68SSean Wang ch5g |= BIT(1);
43a5487a68SSean Wang
44a5487a68SSean Wang req->channel_5g_val = cpu_to_le32(ch5g);
45a5487a68SSean Wang }
46a5487a68SSean Wang
mt7925_nan_set_2g_support(struct mt7925_nan_enable_req_tlv * req,struct cfg80211_nan_conf * conf)47*0f3605e4SSean Wang static void mt7925_nan_set_2g_support(struct mt7925_nan_enable_req_tlv *req,
48*0f3605e4SSean Wang struct cfg80211_nan_conf *conf)
49*0f3605e4SSean Wang {
50*0f3605e4SSean Wang if (!conf->band_cfgs[NL80211_BAND_2GHZ].chan)
51*0f3605e4SSean Wang return;
52*0f3605e4SSean Wang
53*0f3605e4SSean Wang req->config_2dot4g_support = 1;
54*0f3605e4SSean Wang req->support_2dot4g_val = 1;
55*0f3605e4SSean Wang }
56*0f3605e4SSean Wang
mt7925_nan_set_cluster_id(struct mt7925_nan_enable_req_tlv * req,const u8 * cluster_id)57a5487a68SSean Wang static void mt7925_nan_set_cluster_id(struct mt7925_nan_enable_req_tlv *req,
58a5487a68SSean Wang const u8 *cluster_id)
59a5487a68SSean Wang {
60a5487a68SSean Wang if (!cluster_id)
61a5487a68SSean Wang return;
62a5487a68SSean Wang
63a5487a68SSean Wang req->cluster_high = cpu_to_le16(cluster_id[4] | cluster_id[5] << 8);
64a5487a68SSean Wang req->cluster_low = cpu_to_le16((u16)cluster_id[3]);
65a5487a68SSean Wang }
66a5487a68SSean Wang
mt7925_nan_set_dw_interval(struct mt7925_nan_enable_req_tlv * req,struct cfg80211_nan_conf * conf)67a5487a68SSean Wang static void mt7925_nan_set_dw_interval(struct mt7925_nan_enable_req_tlv *req,
68a5487a68SSean Wang struct cfg80211_nan_conf *conf)
69a5487a68SSean Wang {
70a5487a68SSean Wang if (conf->band_cfgs[NL80211_BAND_2GHZ].awake_dw_interval > 0) {
71a5487a68SSean Wang req->config_dw.config_2dot4g_dw_band = 1;
72a5487a68SSean Wang req->config_dw.dw_2dot4g_interval_val =
73a5487a68SSean Wang cpu_to_le32(conf->band_cfgs[NL80211_BAND_2GHZ].awake_dw_interval);
74a5487a68SSean Wang }
75a5487a68SSean Wang
76a5487a68SSean Wang if (conf->band_cfgs[NL80211_BAND_5GHZ].awake_dw_interval > 0) {
77a5487a68SSean Wang req->config_dw.config_5g_dw_band = 1;
78a5487a68SSean Wang req->config_dw.dw_5g_interval_val =
79a5487a68SSean Wang cpu_to_le32(conf->band_cfgs[NL80211_BAND_5GHZ].awake_dw_interval);
80a5487a68SSean Wang }
81a5487a68SSean Wang }
82a5487a68SSean Wang
mt7925_nan_set_disc_beacon(struct mt7925_nan_enable_req_tlv * req,struct cfg80211_nan_conf * conf)83a5487a68SSean Wang static void mt7925_nan_set_disc_beacon(struct mt7925_nan_enable_req_tlv *req,
84a5487a68SSean Wang struct cfg80211_nan_conf *conf)
85a5487a68SSean Wang {
86a5487a68SSean Wang if (conf->discovery_beacon_interval > 0) {
87a5487a68SSean Wang req->config_2dot4g_beacons = true;
88a5487a68SSean Wang req->beacon_2dot4g_val = conf->discovery_beacon_interval;
89a5487a68SSean Wang }
90a5487a68SSean Wang }
91a5487a68SSean Wang
mt7925_nan_set_rssi_thresholds(struct mt7925_nan_enable_req_tlv * req,struct cfg80211_nan_conf * conf)92a5487a68SSean Wang static void mt7925_nan_set_rssi_thresholds(struct mt7925_nan_enable_req_tlv *req,
93a5487a68SSean Wang struct cfg80211_nan_conf *conf)
94a5487a68SSean Wang {
95a5487a68SSean Wang if (conf->band_cfgs[NL80211_BAND_2GHZ].chan) {
96a5487a68SSean Wang req->config_2dot4g_rssi_close = 1;
97a5487a68SSean Wang req->rssi_close_2dot4g_val =
98a5487a68SSean Wang abs(conf->band_cfgs[NL80211_BAND_2GHZ].rssi_close);
99a5487a68SSean Wang req->config_2dot4g_rssi_middle = 1;
100a5487a68SSean Wang req->rssi_middle_2dot4g_val =
101a5487a68SSean Wang abs(conf->band_cfgs[NL80211_BAND_2GHZ].rssi_middle);
102a5487a68SSean Wang }
103a5487a68SSean Wang
104a5487a68SSean Wang if (conf->band_cfgs[NL80211_BAND_5GHZ].chan) {
105a5487a68SSean Wang req->config_5g_rssi_close = 1;
106a5487a68SSean Wang req->rssi_close_5g_val =
107a5487a68SSean Wang abs(conf->band_cfgs[NL80211_BAND_5GHZ].rssi_close);
108a5487a68SSean Wang req->config_5g_rssi_middle = 1;
109a5487a68SSean Wang req->rssi_middle_5g_val =
110a5487a68SSean Wang abs(conf->band_cfgs[NL80211_BAND_5GHZ].rssi_middle);
111a5487a68SSean Wang }
112a5487a68SSean Wang }
113a5487a68SSean Wang
mt7925_nan_set_scan_params(struct mt7925_nan_enable_req_tlv * req,struct cfg80211_nan_conf * conf)114a5487a68SSean Wang static void mt7925_nan_set_scan_params(struct mt7925_nan_enable_req_tlv *req,
115a5487a68SSean Wang struct cfg80211_nan_conf *conf)
116a5487a68SSean Wang {
117a5487a68SSean Wang req->scan_params_val.scan_period[0] =
118a5487a68SSean Wang cpu_to_le16(conf->scan_period < 255 ? conf->scan_period : 255);
119a5487a68SSean Wang req->scan_params_val.dwell_time[0] =
120a5487a68SSean Wang conf->scan_dwell_time < 255 ? conf->scan_dwell_time : 255;
121a5487a68SSean Wang }
122a5487a68SSean Wang
123a5487a68SSean Wang static u16
mt7925_nan_avail_attr_ctrl(const struct ieee80211_nan_sched_cfg * sched)124a5487a68SSean Wang mt7925_nan_avail_attr_ctrl(const struct ieee80211_nan_sched_cfg *sched)
125a5487a68SSean Wang {
126a5487a68SSean Wang if (sched->avail_blob_len < NAN_AVAIL_ATTR_CTRL_OFFSET + 2)
127a5487a68SSean Wang return 0;
128a5487a68SSean Wang
129a5487a68SSean Wang return sched->avail_blob[NAN_AVAIL_ATTR_CTRL_OFFSET] |
130a5487a68SSean Wang sched->avail_blob[NAN_AVAIL_ATTR_CTRL_OFFSET + 1] << 8;
131a5487a68SSean Wang }
132a5487a68SSean Wang
133a5487a68SSean Wang static void
mt7925_nan_update_conf(struct mt792x_vif * mvif,const struct cfg80211_nan_conf * conf)134a5487a68SSean Wang mt7925_nan_update_conf(struct mt792x_vif *mvif,
135a5487a68SSean Wang const struct cfg80211_nan_conf *conf)
136a5487a68SSean Wang {
137a5487a68SSean Wang mvif->nan.conf.master_pref = conf->master_pref;
138a5487a68SSean Wang mvif->nan.conf.bands = conf->bands;
139a5487a68SSean Wang mvif->nan.conf.discovery_beacon_interval =
140a5487a68SSean Wang conf->discovery_beacon_interval;
141a5487a68SSean Wang mvif->nan.conf.enable_dw_notification =
142a5487a68SSean Wang conf->enable_dw_notification;
143a5487a68SSean Wang
144a5487a68SSean Wang memcpy(mvif->nan.conf.cluster_id, conf->cluster_id, ETH_ALEN);
145a5487a68SSean Wang }
146a5487a68SSean Wang
mt7925_nan_set_nmi_addr(struct mt792x_dev * dev,const u8 * addr)147*0f3605e4SSean Wang int mt7925_nan_set_nmi_addr(struct mt792x_dev *dev, const u8 *addr)
148*0f3605e4SSean Wang {
149*0f3605e4SSean Wang struct mt76_dev *mdev;
150*0f3605e4SSean Wang struct {
151*0f3605e4SSean Wang u8 rsv[4];
152*0f3605e4SSean Wang struct mt7925_nan_nmi_addr_tlv nmi_addr_tlv;
153*0f3605e4SSean Wang } nmi_cmd = {
154*0f3605e4SSean Wang .rsv = { 0 },
155*0f3605e4SSean Wang .nmi_addr_tlv = {
156*0f3605e4SSean Wang .tag = cpu_to_le16(NAN_UNI_CMD_CHANGE_NMI_ADDRESS),
157*0f3605e4SSean Wang .len = cpu_to_le16(sizeof(struct mt7925_nan_nmi_addr_tlv)),
158*0f3605e4SSean Wang },
159*0f3605e4SSean Wang };
160*0f3605e4SSean Wang int ret;
161*0f3605e4SSean Wang
162*0f3605e4SSean Wang if (!dev || !addr)
163*0f3605e4SSean Wang return -EINVAL;
164*0f3605e4SSean Wang
165*0f3605e4SSean Wang if (is_zero_ether_addr(addr) || is_multicast_ether_addr(addr)) {
166*0f3605e4SSean Wang dev_err(dev->mt76.dev, "NAN: invalid NMI address %pM\n", addr);
167*0f3605e4SSean Wang return -EINVAL;
168*0f3605e4SSean Wang }
169*0f3605e4SSean Wang
170*0f3605e4SSean Wang mdev = &dev->mt76;
171*0f3605e4SSean Wang memcpy(nmi_cmd.nmi_addr_tlv.nmi_addr, addr, ETH_ALEN);
172*0f3605e4SSean Wang
173*0f3605e4SSean Wang ret = mt76_mcu_send_msg(mdev, MCU_UNI_CMD(NAN), &nmi_cmd,
174*0f3605e4SSean Wang sizeof(nmi_cmd), true);
175*0f3605e4SSean Wang
176*0f3605e4SSean Wang return ret;
177*0f3605e4SSean Wang }
178*0f3605e4SSean Wang
mt7925_nan_enable(struct ieee80211_vif * vif,struct mt792x_dev * dev,struct cfg80211_nan_conf * conf)179a5487a68SSean Wang int mt7925_nan_enable(struct ieee80211_vif *vif,
180a5487a68SSean Wang struct mt792x_dev *dev,
181a5487a68SSean Wang struct cfg80211_nan_conf *conf)
182a5487a68SSean Wang {
183a5487a68SSean Wang struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
184a5487a68SSean Wang struct mt76_dev *mdev = &dev->mt76;
185a5487a68SSean Wang struct {
186a5487a68SSean Wang u8 rsv[4];
187a5487a68SSean Wang struct mt7925_nan_enable_req_tlv nan_req_tlv;
188a5487a68SSean Wang } nan_cmd = {
189a5487a68SSean Wang .rsv = { 0 },
190a5487a68SSean Wang .nan_req_tlv = {
191a5487a68SSean Wang .tag = cpu_to_le16(NAN_UNI_CMD_ENABLE_REQUEST),
192a5487a68SSean Wang .len = cpu_to_le16(sizeof(struct mt7925_nan_enable_req_tlv)),
193a5487a68SSean Wang .config_random_factor_force = 0,
194a5487a68SSean Wang .random_factor_force_val = 0,
195a5487a68SSean Wang .config_hop_count_force = 0,
196a5487a68SSean Wang .hop_count_force_val = 0,
197a5487a68SSean Wang },
198a5487a68SSean Wang };
199a5487a68SSean Wang struct mt7925_nan_enable_req_tlv *p_nan_req_tlv = &nan_cmd.nan_req_tlv;
200*0f3605e4SSean Wang int ret;
201a5487a68SSean Wang
202a5487a68SSean Wang if (!vif || !dev || !conf)
203a5487a68SSean Wang return -EINVAL;
204a5487a68SSean Wang
205a5487a68SSean Wang p_nan_req_tlv->master_pref = conf->master_pref;
206a5487a68SSean Wang
207*0f3605e4SSean Wang mt7925_nan_set_2g_support(p_nan_req_tlv, conf);
208a5487a68SSean Wang mt7925_nan_set_5g_channel(dev, p_nan_req_tlv, conf);
209a5487a68SSean Wang mt7925_nan_set_cluster_id(p_nan_req_tlv, conf->cluster_id);
210a5487a68SSean Wang mt7925_nan_set_dw_interval(p_nan_req_tlv, conf);
211a5487a68SSean Wang mt7925_nan_set_disc_beacon(p_nan_req_tlv, conf);
212a5487a68SSean Wang mt7925_nan_set_rssi_thresholds(p_nan_req_tlv, conf);
213a5487a68SSean Wang mt7925_nan_set_scan_params(p_nan_req_tlv, conf);
214a5487a68SSean Wang
215a5487a68SSean Wang mt7925_nan_update_conf(mvif, conf);
216a5487a68SSean Wang
217*0f3605e4SSean Wang ret = mt76_mcu_send_msg(mdev, MCU_UNI_CMD(NAN), &nan_cmd, sizeof(nan_cmd), true);
218*0f3605e4SSean Wang
219*0f3605e4SSean Wang return ret;
220a5487a68SSean Wang }
221a5487a68SSean Wang
mt7925_nan_disable(struct ieee80211_vif * vif,struct mt792x_dev * dev)222a5487a68SSean Wang int mt7925_nan_disable(struct ieee80211_vif *vif, struct mt792x_dev *dev)
223a5487a68SSean Wang {
224a5487a68SSean Wang struct mt76_dev *mdev = &dev->mt76;
225a5487a68SSean Wang struct {
226a5487a68SSean Wang u8 rsv[4];
227a5487a68SSean Wang struct tlv nan_dis_tlv;
228a5487a68SSean Wang } nan_cmd = {
229a5487a68SSean Wang .rsv = { 0 },
230a5487a68SSean Wang .nan_dis_tlv = {
231a5487a68SSean Wang .tag = cpu_to_le16(NAN_UNI_CMD_DISABLE_REQUEST),
232a5487a68SSean Wang .len = cpu_to_le16(sizeof(struct tlv)),
233a5487a68SSean Wang },
234a5487a68SSean Wang };
235a5487a68SSean Wang
236a5487a68SSean Wang if (!dev)
237a5487a68SSean Wang return -EINVAL;
238a5487a68SSean Wang
239a5487a68SSean Wang return mt76_mcu_send_msg(mdev, MCU_UNI_CMD(NAN), &nan_cmd, sizeof(nan_cmd), true);
240a5487a68SSean Wang }
241a5487a68SSean Wang
242a5487a68SSean Wang static int
mt7925_nan_mp_tlv(struct sk_buff * skb,u8 master_pref)243a5487a68SSean Wang mt7925_nan_mp_tlv(struct sk_buff *skb, u8 master_pref)
244a5487a68SSean Wang {
245a5487a68SSean Wang struct mt7925_nan_master_preference_tlv *mp_tlv = NULL;
246a5487a68SSean Wang struct tlv *tlv = NULL;
247a5487a68SSean Wang
248a5487a68SSean Wang if (!skb)
249a5487a68SSean Wang return -EINVAL;
250a5487a68SSean Wang
251a5487a68SSean Wang tlv = mt76_connac_mcu_add_tlv(skb, NAN_UNI_CMD_SET_MASTER_PREFERENCE,
252a5487a68SSean Wang sizeof(struct mt7925_nan_master_preference_tlv));
253a5487a68SSean Wang if (!tlv)
254a5487a68SSean Wang return -ENOMEM;
255a5487a68SSean Wang
256a5487a68SSean Wang mp_tlv = (struct mt7925_nan_master_preference_tlv *)tlv;
257a5487a68SSean Wang
258a5487a68SSean Wang if (master_pref > NAN_MAX_MASTER_PREFERENCE)
259a5487a68SSean Wang return 0;
260a5487a68SSean Wang
261a5487a68SSean Wang mp_tlv->master_preference = master_pref;
262a5487a68SSean Wang
263a5487a68SSean Wang return 0;
264a5487a68SSean Wang }
265a5487a68SSean Wang
266a5487a68SSean Wang static int
mt7925_nan_dw_tlv(struct sk_buff * skb,struct cfg80211_nan_conf * conf)267a5487a68SSean Wang mt7925_nan_dw_tlv(struct sk_buff *skb, struct cfg80211_nan_conf *conf)
268a5487a68SSean Wang {
269a5487a68SSean Wang struct mt7925_nan_dw_interval_tlv *dw_tlv = NULL;
270a5487a68SSean Wang struct tlv *tlv = NULL;
271a5487a68SSean Wang u16 interval;
272a5487a68SSean Wang
273a5487a68SSean Wang if (!skb || !conf)
274a5487a68SSean Wang return -EINVAL;
275a5487a68SSean Wang
276a5487a68SSean Wang tlv = mt76_connac_mcu_add_tlv(skb, NAN_UNI_CMD_SET_DW_INTERVAL,
277a5487a68SSean Wang sizeof(struct mt7925_nan_dw_interval_tlv));
278a5487a68SSean Wang
279a5487a68SSean Wang if (!tlv)
280a5487a68SSean Wang return -ENOMEM;
281a5487a68SSean Wang
282a5487a68SSean Wang dw_tlv = (struct mt7925_nan_dw_interval_tlv *)tlv;
283a5487a68SSean Wang
284a5487a68SSean Wang /* Set DW interval for 2.4GHz and 5GHz bands if available */
285a5487a68SSean Wang if (conf->band_cfgs[NL80211_BAND_2GHZ].awake_dw_interval > 0) {
286a5487a68SSean Wang dw_tlv->dw_interval = conf->band_cfgs[NL80211_BAND_2GHZ].awake_dw_interval;
287a5487a68SSean Wang } else if (conf->band_cfgs[NL80211_BAND_5GHZ].awake_dw_interval > 0) {
288a5487a68SSean Wang dw_tlv->dw_interval = conf->band_cfgs[NL80211_BAND_5GHZ].awake_dw_interval;
289a5487a68SSean Wang } else {
290a5487a68SSean Wang /* Fallback to a default value or log a warning */
291a5487a68SSean Wang dw_tlv->dw_interval = NAN_DEFAULT_DW_INTERVAL;
292a5487a68SSean Wang }
293a5487a68SSean Wang
294a5487a68SSean Wang /* Validate and set NAN Discovery Beacon Interval */
295a5487a68SSean Wang interval = conf->discovery_beacon_interval > 0 ?
296a5487a68SSean Wang conf->discovery_beacon_interval :
297a5487a68SSean Wang NAN_DEFAULT_DISC_BCN_INTERVAL;
298a5487a68SSean Wang
299a5487a68SSean Wang dw_tlv->disc_bcn_interval = cpu_to_le16(interval);
300a5487a68SSean Wang
301a5487a68SSean Wang return 0;
302a5487a68SSean Wang }
303a5487a68SSean Wang
304a5487a68SSean Wang static int
mt7925_nan_cluster_id_tlv(struct sk_buff * skb,const u8 * cluster_id)305a5487a68SSean Wang mt7925_nan_cluster_id_tlv(struct sk_buff *skb, const u8 *cluster_id)
306a5487a68SSean Wang {
307a5487a68SSean Wang struct mt7925_nan_cluster_id_tlv *cluster_tlv = NULL;
308a5487a68SSean Wang struct tlv *tlv = NULL;
309a5487a68SSean Wang
310a5487a68SSean Wang if (!skb || !cluster_id)
311a5487a68SSean Wang return -EINVAL;
312a5487a68SSean Wang
313a5487a68SSean Wang tlv = mt76_connac_mcu_add_tlv(skb, NAN_UNI_CMD_SET_CLUSTER_ID,
314a5487a68SSean Wang sizeof(struct mt7925_nan_cluster_id_tlv));
315a5487a68SSean Wang
316a5487a68SSean Wang if (!tlv)
317a5487a68SSean Wang return -ENOMEM;
318a5487a68SSean Wang
319a5487a68SSean Wang cluster_tlv = (struct mt7925_nan_cluster_id_tlv *)tlv;
320a5487a68SSean Wang
321a5487a68SSean Wang memcpy(cluster_tlv->cluster_id, cluster_id, ETH_ALEN);
322a5487a68SSean Wang
323a5487a68SSean Wang return 0;
324a5487a68SSean Wang }
325a5487a68SSean Wang
326a5487a68SSean Wang static int
mt7925_nan_sync_rssi_tlv(struct sk_buff * skb,struct cfg80211_nan_conf * conf)327a5487a68SSean Wang mt7925_nan_sync_rssi_tlv(struct sk_buff *skb, struct cfg80211_nan_conf *conf)
328a5487a68SSean Wang {
329a5487a68SSean Wang struct mt7925_nan_sync_rssi_tlv *rssi_tlv = NULL;
330a5487a68SSean Wang struct tlv *tlv = NULL;
331a5487a68SSean Wang
332a5487a68SSean Wang if (!skb || !conf)
333a5487a68SSean Wang return -EINVAL;
334a5487a68SSean Wang
335a5487a68SSean Wang tlv = mt76_connac_mcu_add_tlv(skb, NAN_UNI_CMD_SET_SYNC_RSSI,
336a5487a68SSean Wang sizeof(struct mt7925_nan_sync_rssi_tlv));
337a5487a68SSean Wang
338a5487a68SSean Wang if (!tlv)
339a5487a68SSean Wang return -ENOMEM;
340a5487a68SSean Wang
341a5487a68SSean Wang rssi_tlv = (struct mt7925_nan_sync_rssi_tlv *)tlv;
342a5487a68SSean Wang
343a5487a68SSean Wang if (conf->band_cfgs[NL80211_BAND_2GHZ].chan) {
344a5487a68SSean Wang rssi_tlv->rssi_close_2g =
345a5487a68SSean Wang conf->band_cfgs[NL80211_BAND_2GHZ].rssi_close;
346a5487a68SSean Wang rssi_tlv->rssi_middle_2g =
347a5487a68SSean Wang conf->band_cfgs[NL80211_BAND_2GHZ].rssi_middle;
348a5487a68SSean Wang }
349a5487a68SSean Wang
350a5487a68SSean Wang if (conf->band_cfgs[NL80211_BAND_5GHZ].chan) {
351a5487a68SSean Wang rssi_tlv->rssi_close_5g =
352a5487a68SSean Wang conf->band_cfgs[NL80211_BAND_5GHZ].rssi_close;
353a5487a68SSean Wang rssi_tlv->rssi_middle_5g =
354a5487a68SSean Wang conf->band_cfgs[NL80211_BAND_5GHZ].rssi_middle;
355a5487a68SSean Wang }
356a5487a68SSean Wang
357a5487a68SSean Wang return 0;
358a5487a68SSean Wang }
359a5487a68SSean Wang
mt7925_nan_change_configure(struct ieee80211_vif * vif,struct mt792x_dev * dev,struct cfg80211_nan_conf * conf)360a5487a68SSean Wang int mt7925_nan_change_configure(struct ieee80211_vif *vif,
361a5487a68SSean Wang struct mt792x_dev *dev,
362a5487a68SSean Wang struct cfg80211_nan_conf *conf)
363a5487a68SSean Wang {
364a5487a68SSean Wang struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
365a5487a68SSean Wang struct mt7925_nan_common_hdr *hdr = NULL;
366a5487a68SSean Wang struct mt76_dev *mdev = &dev->mt76;
367a5487a68SSean Wang struct sk_buff *skb = NULL;
368a5487a68SSean Wang
369a5487a68SSean Wang if (!vif || !dev || !conf)
370a5487a68SSean Wang return -EINVAL;
371a5487a68SSean Wang
372a5487a68SSean Wang skb = mt76_mcu_msg_alloc(mdev, NULL, MT7925_NAN_CONF_MAX_SIZE);
373a5487a68SSean Wang if (!skb)
374a5487a68SSean Wang return -ENOMEM;
375a5487a68SSean Wang
376a5487a68SSean Wang hdr = (struct mt7925_nan_common_hdr *)skb_put(skb, sizeof(*hdr));
377a5487a68SSean Wang memset(hdr, 0, sizeof(*hdr));
378a5487a68SSean Wang
379a5487a68SSean Wang if (mt7925_nan_mp_tlv(skb, conf->master_pref) ||
380a5487a68SSean Wang mt7925_nan_dw_tlv(skb, conf) ||
381a5487a68SSean Wang mt7925_nan_cluster_id_tlv(skb, conf->cluster_id) ||
382a5487a68SSean Wang mt7925_nan_sync_rssi_tlv(skb, conf)) {
383a5487a68SSean Wang dev_kfree_skb(skb);
384a5487a68SSean Wang return -ENOMEM;
385a5487a68SSean Wang }
386a5487a68SSean Wang
387a5487a68SSean Wang mt7925_nan_update_conf(mvif, conf);
388a5487a68SSean Wang
389a5487a68SSean Wang return mt76_mcu_skb_send_msg(mdev, skb,
390a5487a68SSean Wang MCU_UNI_CMD(NAN), true);
391a5487a68SSean Wang }
392a5487a68SSean Wang
393a5487a68SSean Wang static void
mt7925_nan_handle_dw_ind(struct mt792x_dev * dev,struct tlv * tlv)394a5487a68SSean Wang mt7925_nan_handle_dw_ind(struct mt792x_dev *dev, struct tlv *tlv)
395a5487a68SSean Wang {
396a5487a68SSean Wang struct ieee80211_channel *chan;
397a5487a68SSean Wang struct nan_rpt_dw_evt *evt;
398a5487a68SSean Wang struct wireless_dev *wdev;
399a5487a68SSean Wang u16 len, channel, dw_num;
400a5487a68SSean Wang struct mt792x_vif *mvif;
401a5487a68SSean Wang enum nl80211_band band;
402a5487a68SSean Wang int freq;
403a5487a68SSean Wang
404a5487a68SSean Wang if (!dev || !tlv)
405a5487a68SSean Wang return;
406a5487a68SSean Wang
407a5487a68SSean Wang len = le16_to_cpu(tlv->len);
408a5487a68SSean Wang if (len < sizeof(*tlv) + sizeof(*evt)) {
409a5487a68SSean Wang dev_warn(dev->mt76.dev,
410a5487a68SSean Wang "nan: short dw event tlv len=%u\n", len);
411a5487a68SSean Wang return;
412a5487a68SSean Wang }
413a5487a68SSean Wang
414a5487a68SSean Wang if (!dev->nan_vif || !ieee80211_vif_nan_started(dev->nan_vif))
415a5487a68SSean Wang return;
416a5487a68SSean Wang
417a5487a68SSean Wang wdev = ieee80211_vif_to_wdev(dev->nan_vif);
418a5487a68SSean Wang if (!wdev)
419a5487a68SSean Wang return;
420a5487a68SSean Wang
421a5487a68SSean Wang mvif = (struct mt792x_vif *)dev->nan_vif->drv_priv;
422a5487a68SSean Wang if (!mvif->nan.conf.enable_dw_notification)
423a5487a68SSean Wang return;
424a5487a68SSean Wang
425a5487a68SSean Wang evt = (struct nan_rpt_dw_evt *)tlv->data;
426a5487a68SSean Wang channel = le16_to_cpu(evt->channel);
427a5487a68SSean Wang dw_num = le16_to_cpu(evt->dw_num);
428a5487a68SSean Wang
429a5487a68SSean Wang band = channel > 13 ? NL80211_BAND_5GHZ : NL80211_BAND_2GHZ;
430a5487a68SSean Wang freq = ieee80211_channel_to_frequency(channel, band);
431a5487a68SSean Wang chan = ieee80211_get_channel(dev->mt76.hw->wiphy, freq);
432a5487a68SSean Wang if (!chan) {
433a5487a68SSean Wang dev_dbg(dev->mt76.dev,
434a5487a68SSean Wang "nan: no channel for dw end event ch=%u dw=%u\n",
435a5487a68SSean Wang channel, dw_num);
436a5487a68SSean Wang return;
437a5487a68SSean Wang }
438a5487a68SSean Wang
439a5487a68SSean Wang cfg80211_next_nan_dw_notif(wdev, chan, GFP_KERNEL);
440a5487a68SSean Wang }
441a5487a68SSean Wang
442a5487a68SSean Wang static void
mt7925_nan_mcu_handle_de_event(struct mt792x_dev * dev,struct tlv * tlv)443a5487a68SSean Wang mt7925_nan_mcu_handle_de_event(struct mt792x_dev *dev, struct tlv *tlv)
444a5487a68SSean Wang {
445a5487a68SSean Wang u8 cluster_id[ETH_ALEN] __aligned(2) = {0x50, 0x6f, 0x9a, 0x01, 0x00, 0x00};
446a5487a68SSean Wang struct mt7925_nan_de_event *de_evt = NULL;
447a5487a68SSean Wang u16 len;
448a5487a68SSean Wang
449a5487a68SSean Wang if (!dev || !tlv) {
450a5487a68SSean Wang if (dev)
451a5487a68SSean Wang dev_warn(dev->mt76.dev, "nan: failed to parse TLV\n");
452a5487a68SSean Wang return;
453a5487a68SSean Wang }
454a5487a68SSean Wang
455a5487a68SSean Wang len = le16_to_cpu(tlv->len);
456a5487a68SSean Wang if (len < sizeof(*tlv) + sizeof(*de_evt)) {
457a5487a68SSean Wang dev_warn(dev->mt76.dev,
458a5487a68SSean Wang "nan: short de_event tlv len=%u\n", len);
459a5487a68SSean Wang return;
460a5487a68SSean Wang }
461a5487a68SSean Wang
462a5487a68SSean Wang de_evt = (struct mt7925_nan_de_event *)tlv->data;
463a5487a68SSean Wang if (!de_evt) {
464a5487a68SSean Wang dev_warn(dev->mt76.dev, "nan: missing DE event payload\n");
465a5487a68SSean Wang return;
466a5487a68SSean Wang }
467a5487a68SSean Wang
468a5487a68SSean Wang if (de_evt->event_type == NAN_EVENT_ID_DISC_MAC_ADDR)
469a5487a68SSean Wang return;
470a5487a68SSean Wang
471a5487a68SSean Wang memcpy(cluster_id, de_evt->cluster_id, ETH_ALEN);
472a5487a68SSean Wang
473a5487a68SSean Wang dev_dbg(dev->mt76.dev, "nan: evt=%u cluster=%pM\n",
474a5487a68SSean Wang de_evt->event_type, de_evt->cluster_id);
475a5487a68SSean Wang
476a5487a68SSean Wang if (de_evt->event_type != NAN_EVENT_ID_JOINED_CLUSTER)
477a5487a68SSean Wang return;
478a5487a68SSean Wang
479*0f3605e4SSean Wang if (!dev->nan_vif || !ieee80211_vif_nan_started(dev->nan_vif)) {
480a5487a68SSean Wang dev_warn(dev->mt76.dev, "nan: joined-cluster event but NAN not started\n");
481a5487a68SSean Wang return;
482a5487a68SSean Wang }
483a5487a68SSean Wang
484a5487a68SSean Wang dev_dbg(dev->mt76.dev, "nan: anchor_master_rank=%*phN\n",
485a5487a68SSean Wang NAN_ANCHOR_MASTER_RANK_NUM, de_evt->anchor_master_rank);
486a5487a68SSean Wang
487a5487a68SSean Wang dev_dbg(dev->mt76.dev, "nan: own_nmi=%pM master_nmi=%pM\n",
488a5487a68SSean Wang de_evt->own_nmi, de_evt->master_nmi);
489a5487a68SSean Wang
490a5487a68SSean Wang ieee80211_nan_cluster_joined(dev->nan_vif, cluster_id, true, GFP_KERNEL);
491a5487a68SSean Wang }
492a5487a68SSean Wang
mt7925_nan_mcu_event(struct mt792x_dev * dev,struct sk_buff * skb)493a5487a68SSean Wang void mt7925_nan_mcu_event(struct mt792x_dev *dev, struct sk_buff *skb)
494a5487a68SSean Wang {
495a5487a68SSean Wang struct tlv *tlv;
496a5487a68SSean Wang u32 tlv_len;
497a5487a68SSean Wang
498a5487a68SSean Wang if (!dev || !skb)
499a5487a68SSean Wang return;
500a5487a68SSean Wang
501a5487a68SSean Wang if (skb->len < sizeof(struct mt7925_mcu_rxd) + 4)
502a5487a68SSean Wang return;
503a5487a68SSean Wang
504a5487a68SSean Wang skb_pull(skb, sizeof(struct mt7925_mcu_rxd) + 4);
505a5487a68SSean Wang tlv = (struct tlv *)skb->data;
506a5487a68SSean Wang tlv_len = skb->len;
507a5487a68SSean Wang
508a5487a68SSean Wang while (tlv_len >= sizeof(*tlv)) {
509a5487a68SSean Wang u16 len = le16_to_cpu(tlv->len);
510a5487a68SSean Wang
511a5487a68SSean Wang if (len < sizeof(*tlv) || len > tlv_len)
512a5487a68SSean Wang break;
513a5487a68SSean Wang
514a5487a68SSean Wang switch (le16_to_cpu(tlv->tag)) {
515a5487a68SSean Wang case NAN_UNI_EVENT_ID_DE_EVENT_IND:
516a5487a68SSean Wang mt7925_nan_mcu_handle_de_event(dev, tlv);
517a5487a68SSean Wang break;
518a5487a68SSean Wang case NAN_UNI_EVENT_REPORT_DW_END:
519a5487a68SSean Wang mt7925_nan_handle_dw_ind(dev, tlv);
520a5487a68SSean Wang break;
521a5487a68SSean Wang default:
522a5487a68SSean Wang break;
523a5487a68SSean Wang }
524a5487a68SSean Wang
525a5487a68SSean Wang tlv_len -= len;
526a5487a68SSean Wang tlv = (struct tlv *)((u8 *)tlv + len);
527a5487a68SSean Wang }
528a5487a68SSean Wang }
529a5487a68SSean Wang
mt7925_nan_avail_ctrl_tlv(struct sk_buff * skb,struct ieee80211_vif * vif)530a5487a68SSean Wang static int mt7925_nan_avail_ctrl_tlv(struct sk_buff *skb,
531a5487a68SSean Wang struct ieee80211_vif *vif)
532a5487a68SSean Wang {
533a5487a68SSean Wang struct mt7925_nan_avail_ctrl_tlv *avail_ctrl_tlv;
534a5487a68SSean Wang struct ieee80211_nan_sched_cfg *sched;
535a5487a68SSean Wang struct tlv *tlv;
536a5487a68SSean Wang u8 seq_id = 0;
537a5487a68SSean Wang u16 ctrl = 0;
538a5487a68SSean Wang
539a5487a68SSean Wang if (!skb || !vif)
540a5487a68SSean Wang return -EINVAL;
541a5487a68SSean Wang
542a5487a68SSean Wang tlv = mt76_connac_mcu_add_tlv(skb, NAN_UNI_CMD_UPDATE_AVAILABILITY_CTRL,
543a5487a68SSean Wang sizeof(struct mt7925_nan_avail_ctrl_tlv));
544a5487a68SSean Wang
545a5487a68SSean Wang if (!tlv)
546a5487a68SSean Wang return -ENOMEM;
547a5487a68SSean Wang
548a5487a68SSean Wang sched = &vif->cfg.nan_sched;
549a5487a68SSean Wang
550a5487a68SSean Wang ctrl = mt7925_nan_avail_attr_ctrl(sched);
551a5487a68SSean Wang if (sched->avail_blob_len >= NAN_AVAIL_ATTR_CTRL_OFFSET + 2)
552a5487a68SSean Wang seq_id = sched->avail_blob[NAN_AVAIL_SEQ_ID_OFFSET];
553a5487a68SSean Wang
554a5487a68SSean Wang avail_ctrl_tlv = (struct mt7925_nan_avail_ctrl_tlv *)tlv;
555a5487a68SSean Wang avail_ctrl_tlv->avail_ctrl =
556a5487a68SSean Wang cpu_to_le16(ctrl & NAN_AVAIL_CTRL_CHECK_FOR_CHANGED);
557a5487a68SSean Wang avail_ctrl_tlv->seq_id = seq_id;
558a5487a68SSean Wang
559a5487a68SSean Wang return 0;
560a5487a68SSean Wang }
561a5487a68SSean Wang
mt7925_nan_slot_to_bitmap(struct ieee80211_vif * vif,struct mt7925_nan_ch_timeline * ch_list)562a5487a68SSean Wang static u32 mt7925_nan_slot_to_bitmap(struct ieee80211_vif *vif,
563a5487a68SSean Wang struct mt7925_nan_ch_timeline *ch_list)
564a5487a68SSean Wang {
565a5487a68SSean Wang struct ieee80211_nan_channel **slots = vif->cfg.nan_sched.schedule;
566a5487a68SSean Wang struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
567a5487a68SSean Wang u32 num_channels = 0;
568a5487a68SSean Wang u32 i, j;
569a5487a68SSean Wang
570a5487a68SSean Wang for (i = 0; i < ARRAY_SIZE(mvif->nan.local_sched); i++) {
571a5487a68SSean Wang struct cfg80211_chan_def *slot_chan = &mvif->nan.local_sched[i];
572a5487a68SSean Wang struct ieee80211_nan_channel *slot = slots[i];
573a5487a68SSean Wang bool is_found = false;
574a5487a68SSean Wang
575a5487a68SSean Wang if (slot && !IS_ERR(slot) && slot->chanctx_conf) {
576a5487a68SSean Wang *slot_chan = slot->chanctx_conf->def;
577a5487a68SSean Wang } else {
578a5487a68SSean Wang memset(slot_chan, 0, sizeof(*slot_chan));
579a5487a68SSean Wang continue;
580a5487a68SSean Wang }
581a5487a68SSean Wang
582a5487a68SSean Wang for (j = 0; j < num_channels; j++) {
583a5487a68SSean Wang u32 raw = le32_to_cpu(ch_list[j].ch_info);
584a5487a68SSean Wang
585a5487a68SSean Wang if (FIELD_GET(NAN_CH_CTRL_PRIMARY_CH, raw) ==
586a5487a68SSean Wang slot_chan->chan->hw_value) {
587a5487a68SSean Wang u32 map = le32_to_cpu(ch_list[j].avail_map[0]);
588a5487a68SSean Wang
589a5487a68SSean Wang ch_list[j].avail_map[0] = cpu_to_le32(map | BIT(i));
590a5487a68SSean Wang le32_add_cpu(&ch_list[j].num, 1);
591a5487a68SSean Wang is_found = true;
592a5487a68SSean Wang break;
593a5487a68SSean Wang }
594a5487a68SSean Wang }
595a5487a68SSean Wang
596a5487a68SSean Wang if (!is_found && num_channels < NAN_TIMELINE_MGMT_CHNL_LIST_NUM) {
597a5487a68SSean Wang ch_list[num_channels].ch_info =
598a5487a68SSean Wang cpu_to_le32(FIELD_PREP(NAN_CH_CTRL_OP_CLASS,
599a5487a68SSean Wang slot->channel_entry[0]) |
600a5487a68SSean Wang FIELD_PREP(NAN_CH_CTRL_PRIMARY_CH,
601a5487a68SSean Wang slot_chan->chan->hw_value));
602a5487a68SSean Wang ch_list[num_channels].avail_map[0] = cpu_to_le32(BIT(i));
603a5487a68SSean Wang le32_add_cpu(&ch_list[num_channels].num, 1);
604a5487a68SSean Wang ch_list[num_channels].is_valid++;
605a5487a68SSean Wang num_channels++;
606a5487a68SSean Wang }
607a5487a68SSean Wang }
608a5487a68SSean Wang
609a5487a68SSean Wang return num_channels;
610a5487a68SSean Wang }
611a5487a68SSean Wang
mt7925_nan_avail_tlv(struct sk_buff * skb,struct ieee80211_vif * vif)612a5487a68SSean Wang static int mt7925_nan_avail_tlv(struct sk_buff *skb,
613a5487a68SSean Wang struct ieee80211_vif *vif)
614a5487a68SSean Wang {
615a5487a68SSean Wang struct mt7925_nan_avail_entry_tlv *avail_tlv;
616a5487a68SSean Wang struct ieee80211_nan_sched_cfg *sched;
617a5487a68SSean Wang struct tlv *tlv;
618a5487a68SSean Wang u16 ctrl = 0;
619a5487a68SSean Wang
620a5487a68SSean Wang if (!skb || !vif)
621a5487a68SSean Wang return -EINVAL;
622a5487a68SSean Wang
623a5487a68SSean Wang tlv = mt76_connac_mcu_add_tlv(skb, NAN_UNI_CMD_UPDATE_AVAILABILITY,
624a5487a68SSean Wang sizeof(struct mt7925_nan_avail_entry_tlv));
625a5487a68SSean Wang
626a5487a68SSean Wang if (!tlv)
627a5487a68SSean Wang return -ENOMEM;
628a5487a68SSean Wang
629a5487a68SSean Wang sched = &vif->cfg.nan_sched;
630a5487a68SSean Wang
631a5487a68SSean Wang ctrl = mt7925_nan_avail_attr_ctrl(sched);
632a5487a68SSean Wang
633a5487a68SSean Wang avail_tlv = (struct mt7925_nan_avail_entry_tlv *)tlv;
634a5487a68SSean Wang avail_tlv->map_id = ctrl & NAN_AVAIL_CTRL_MAPID;
635a5487a68SSean Wang avail_tlv->is_cond_avail = false;
636a5487a68SSean Wang avail_tlv->timeline_idx = 0;
637a5487a68SSean Wang
638a5487a68SSean Wang mt7925_nan_slot_to_bitmap(vif, avail_tlv->ch_list);
639a5487a68SSean Wang
640a5487a68SSean Wang avail_tlv->is_multi_map = false;
641a5487a68SSean Wang
642a5487a68SSean Wang return 0;
643a5487a68SSean Wang }
644a5487a68SSean Wang
mt7925_nan_local_sched_changed(struct mt792x_dev * dev,struct ieee80211_vif * vif)645a5487a68SSean Wang void mt7925_nan_local_sched_changed(struct mt792x_dev *dev,
646a5487a68SSean Wang struct ieee80211_vif *vif)
647a5487a68SSean Wang {
648a5487a68SSean Wang struct mt7925_nan_common_hdr *hdr;
649a5487a68SSean Wang struct mt76_dev *mdev;
650*0f3605e4SSean Wang bool deferred;
651a5487a68SSean Wang struct sk_buff *skb;
652*0f3605e4SSean Wang int ret = -ENOMEM;
653a5487a68SSean Wang
654a5487a68SSean Wang if (!dev || !vif)
655a5487a68SSean Wang return;
656a5487a68SSean Wang
657a5487a68SSean Wang mdev = &dev->mt76;
658*0f3605e4SSean Wang deferred = vif->cfg.nan_sched.deferred;
659*0f3605e4SSean Wang
660*0f3605e4SSean Wang mt792x_mutex_acquire(dev);
661a5487a68SSean Wang
662a5487a68SSean Wang skb = mt76_mcu_msg_alloc(mdev, NULL, MT7925_NAN_AVAIL_MAX_SIZE);
663a5487a68SSean Wang if (!skb)
664*0f3605e4SSean Wang goto out;
665a5487a68SSean Wang
666a5487a68SSean Wang hdr = (struct mt7925_nan_common_hdr *)skb_put(skb, sizeof(*hdr));
667a5487a68SSean Wang memset(hdr, 0, sizeof(*hdr));
668a5487a68SSean Wang
669a5487a68SSean Wang if (mt7925_nan_avail_ctrl_tlv(skb, vif) ||
670a5487a68SSean Wang mt7925_nan_avail_tlv(skb, vif)) {
671a5487a68SSean Wang dev_kfree_skb(skb);
672*0f3605e4SSean Wang goto out;
673a5487a68SSean Wang }
674a5487a68SSean Wang
675*0f3605e4SSean Wang ret = mt76_mcu_skb_send_msg(mdev, skb,
676a5487a68SSean Wang MCU_UNI_CMD(NAN), true);
677*0f3605e4SSean Wang out:
678*0f3605e4SSean Wang mt792x_mutex_release(dev);
679*0f3605e4SSean Wang
680*0f3605e4SSean Wang if (deferred) {
681*0f3605e4SSean Wang if (ret)
682*0f3605e4SSean Wang dev_err(mdev->dev,
683*0f3605e4SSean Wang "NAN: local schedule update failed: %d\n",
684*0f3605e4SSean Wang ret);
685*0f3605e4SSean Wang
686*0f3605e4SSean Wang ieee80211_nan_sched_update_done(vif);
687*0f3605e4SSean Wang }
688a5487a68SSean Wang }
689a5487a68SSean Wang
mt7925_nan_peer_rec_tlv(struct sk_buff * skb,struct ieee80211_sta * sta,struct mt792x_sta * msta,u8 is_activate)690a5487a68SSean Wang static int mt7925_nan_peer_rec_tlv(struct sk_buff *skb,
691a5487a68SSean Wang struct ieee80211_sta *sta,
692a5487a68SSean Wang struct mt792x_sta *msta,
693a5487a68SSean Wang u8 is_activate)
694a5487a68SSean Wang {
695a5487a68SSean Wang struct mt7925_nan_sched_manage_peer_rec_tlv *peer_rec_tlv;
696a5487a68SSean Wang struct tlv *tlv;
697a5487a68SSean Wang
698a5487a68SSean Wang if (!skb || !sta || !msta)
699a5487a68SSean Wang return -EINVAL;
700a5487a68SSean Wang
701a5487a68SSean Wang tlv = mt76_connac_mcu_add_tlv(skb, NAN_UNI_CMD_MANAGE_PEER_SCH_RECORD,
702a5487a68SSean Wang sizeof(struct mt7925_nan_sched_manage_peer_rec_tlv));
703a5487a68SSean Wang
704a5487a68SSean Wang if (!tlv)
705a5487a68SSean Wang return -ENOMEM;
706a5487a68SSean Wang
707a5487a68SSean Wang peer_rec_tlv = (struct mt7925_nan_sched_manage_peer_rec_tlv *)tlv;
708a5487a68SSean Wang peer_rec_tlv->sch_idx = cpu_to_le32(msta->nan_sched.sch_idx);
709a5487a68SSean Wang peer_rec_tlv->is_activate = is_activate;
710a5487a68SSean Wang memcpy(peer_rec_tlv->nmi_addr, sta->addr, ETH_ALEN);
711a5487a68SSean Wang
712a5487a68SSean Wang return 0;
713a5487a68SSean Wang }
714a5487a68SSean Wang
mt7925_nan_get_supported_bands(struct mt792x_vif * mvif)715*0f3605e4SSean Wang static u8 mt7925_nan_get_supported_bands(struct mt792x_vif *mvif)
716*0f3605e4SSean Wang {
717*0f3605e4SSean Wang struct wiphy *wiphy;
718*0f3605e4SSean Wang u8 bands = 0;
719*0f3605e4SSean Wang
720*0f3605e4SSean Wang if (!mvif || !mvif->phy)
721*0f3605e4SSean Wang return BIT(NAN_SUPPORTED_BAND_ID_2P4G);
722*0f3605e4SSean Wang
723*0f3605e4SSean Wang wiphy = mvif->phy->mt76->hw->wiphy;
724*0f3605e4SSean Wang if (wiphy->nan_supported_bands & BIT(NL80211_BAND_2GHZ))
725*0f3605e4SSean Wang bands |= BIT(NAN_SUPPORTED_BAND_ID_2P4G);
726*0f3605e4SSean Wang if (wiphy->nan_supported_bands & BIT(NL80211_BAND_5GHZ))
727*0f3605e4SSean Wang bands |= BIT(NAN_SUPPORTED_BAND_ID_5G);
728*0f3605e4SSean Wang
729*0f3605e4SSean Wang return bands ?: BIT(NAN_SUPPORTED_BAND_ID_2P4G);
730*0f3605e4SSean Wang }
731*0f3605e4SSean Wang
mt7925_nan_peer_cap_tlv(struct sk_buff * skb,struct ieee80211_sta * sta,struct mt792x_sta * msta)732a5487a68SSean Wang static int mt7925_nan_peer_cap_tlv(struct sk_buff *skb,
733a5487a68SSean Wang struct ieee80211_sta *sta,
734a5487a68SSean Wang struct mt792x_sta *msta)
735a5487a68SSean Wang {
736a5487a68SSean Wang struct mt7925_nan_sched_update_peer_cap_tlv *peer_cap_tlv;
737a5487a68SSean Wang struct ieee80211_nan_peer_sched *sched;
738a5487a68SSean Wang enum nl80211_band band;
739a5487a68SSean Wang struct tlv *tlv;
740a5487a68SSean Wang u16 primary_ch;
741a5487a68SSean Wang u32 i;
742a5487a68SSean Wang
743a5487a68SSean Wang if (!skb || !sta || !msta)
744a5487a68SSean Wang return -EINVAL;
745a5487a68SSean Wang
746a5487a68SSean Wang sched = sta->nan_sched;
747a5487a68SSean Wang if (!sched)
748a5487a68SSean Wang return -EINVAL;
749a5487a68SSean Wang
750a5487a68SSean Wang tlv = mt76_connac_mcu_add_tlv(skb, NAN_UNI_CMD_UPDATE_PEER_CAPABILITY,
751a5487a68SSean Wang sizeof(struct mt7925_nan_sched_update_peer_cap_tlv));
752a5487a68SSean Wang
753a5487a68SSean Wang if (!tlv)
754a5487a68SSean Wang return -ENOMEM;
755a5487a68SSean Wang
756a5487a68SSean Wang peer_cap_tlv = (struct mt7925_nan_sched_update_peer_cap_tlv *)tlv;
757a5487a68SSean Wang peer_cap_tlv->sch_idx = cpu_to_le32(msta->nan_sched.sch_idx);
758*0f3605e4SSean Wang peer_cap_tlv->supported_bands =
759*0f3605e4SSean Wang mt7925_nan_get_supported_bands(msta->vif);
760a5487a68SSean Wang peer_cap_tlv->max_chnl_switch_time = cpu_to_le16(sched->max_chan_switch);
761a5487a68SSean Wang
762a5487a68SSean Wang for (i = 0; i < sched->n_channels; i++) {
763a5487a68SSean Wang if (!sched->channels[i].chanctx_conf)
764a5487a68SSean Wang continue;
765a5487a68SSean Wang
766a5487a68SSean Wang band = sched->channels[i].chanctx_conf->def.chan->band;
767a5487a68SSean Wang primary_ch =
768a5487a68SSean Wang sched->channels[i].chanctx_conf->def.chan->hw_value;
769a5487a68SSean Wang
770a5487a68SSean Wang if (band == NL80211_BAND_2GHZ)
771a5487a68SSean Wang peer_cap_tlv->peer_supported_bands |=
772a5487a68SSean Wang BIT(NAN_SUPPORTED_BN_2G);
773a5487a68SSean Wang else if (primary_ch >= UNII1_LOWER_BOUND &&
774a5487a68SSean Wang primary_ch <= UNII1_UPPER_BOUND)
775a5487a68SSean Wang peer_cap_tlv->peer_supported_bands |=
776a5487a68SSean Wang BIT(NAN_SUPPORTED_BN_5G_LOW);
777a5487a68SSean Wang else if (primary_ch >= UNII3_LOWER_BOUND &&
778a5487a68SSean Wang primary_ch <= UNII3_UPPER_BOUND)
779a5487a68SSean Wang peer_cap_tlv->peer_supported_bands |=
780a5487a68SSean Wang BIT(NAN_SUPPORTED_BN_5G_HIGH);
781a5487a68SSean Wang }
782a5487a68SSean Wang
783a5487a68SSean Wang return 0;
784a5487a68SSean Wang }
785a5487a68SSean Wang
786a5487a68SSean Wang static void
mt7925_nan_fill_crb_committed(struct mt7925_nan_sched_update_crb_tlv * crb_tlv,struct ieee80211_vif * vif,struct ieee80211_nan_peer_sched * sched)787a5487a68SSean Wang mt7925_nan_fill_crb_committed(struct mt7925_nan_sched_update_crb_tlv *crb_tlv,
788*0f3605e4SSean Wang struct ieee80211_vif *vif,
789a5487a68SSean Wang struct ieee80211_nan_peer_sched *sched)
790a5487a68SSean Wang {
791*0f3605e4SSean Wang struct ieee80211_nan_sched_cfg *local_sched;
792*0f3605e4SSean Wang u8 local_map_id;
793a5487a68SSean Wang u32 m, slot;
794a5487a68SSean Wang
795*0f3605e4SSean Wang if (!vif || !sched)
796a5487a68SSean Wang return;
797a5487a68SSean Wang
798*0f3605e4SSean Wang local_sched = &vif->cfg.nan_sched;
799*0f3605e4SSean Wang local_map_id = mt7925_nan_avail_attr_ctrl(local_sched) &
800*0f3605e4SSean Wang NAN_AVAIL_CTRL_MAPID;
801*0f3605e4SSean Wang
802a5487a68SSean Wang for (m = 0; m < CFG80211_NAN_MAX_PEER_MAPS &&
803a5487a68SSean Wang m < NAN_TIMELINE_MGMT_SIZE; m++) {
804a5487a68SSean Wang struct mt7925_nan_sched_timeline *tl =
805a5487a68SSean Wang &crb_tlv->comm_faw_timeline[m];
806a5487a68SSean Wang struct ieee80211_nan_peer_map *map = &sched->maps[m];
807*0f3605e4SSean Wang u32 avail_map = 0;
808a5487a68SSean Wang
809a5487a68SSean Wang if (map->map_id == CFG80211_NAN_INVALID_MAP_ID)
810a5487a68SSean Wang continue;
811a5487a68SSean Wang
812a5487a68SSean Wang tl->map_id = map->map_id;
813*0f3605e4SSean Wang tl->local_map_id = local_map_id;
814a5487a68SSean Wang
815a5487a68SSean Wang for (slot = 0; slot < CFG80211_NAN_SCHED_NUM_TIME_SLOTS;
816a5487a68SSean Wang slot++) {
817*0f3605e4SSean Wang struct ieee80211_nan_channel *local_ch;
818*0f3605e4SSean Wang struct ieee80211_nan_channel *peer_ch;
819a5487a68SSean Wang
820*0f3605e4SSean Wang local_ch = local_sched->schedule[slot];
821*0f3605e4SSean Wang peer_ch = map->slots[slot];
822*0f3605e4SSean Wang
823*0f3605e4SSean Wang if (!local_ch || !local_ch->chanctx_conf ||
824*0f3605e4SSean Wang !peer_ch || !peer_ch->chanctx_conf)
825a5487a68SSean Wang continue;
826a5487a68SSean Wang
827*0f3605e4SSean Wang if (local_ch->chanctx_conf != peer_ch->chanctx_conf)
828*0f3605e4SSean Wang continue;
829*0f3605e4SSean Wang
830*0f3605e4SSean Wang avail_map |= BIT(slot);
831a5487a68SSean Wang }
832*0f3605e4SSean Wang
833*0f3605e4SSean Wang tl->avail_map[0] = cpu_to_le32(avail_map);
834a5487a68SSean Wang }
835a5487a68SSean Wang }
836a5487a68SSean Wang
mt7925_nan_update_crb_tlv(struct sk_buff * skb,struct ieee80211_sta * sta,struct mt792x_sta * msta)837a5487a68SSean Wang static int mt7925_nan_update_crb_tlv(struct sk_buff *skb,
838a5487a68SSean Wang struct ieee80211_sta *sta,
839a5487a68SSean Wang struct mt792x_sta *msta)
840a5487a68SSean Wang {
841a5487a68SSean Wang struct mt7925_nan_sched_update_crb_tlv *crb_tlv;
842a5487a68SSean Wang struct tlv *tlv;
843a5487a68SSean Wang
844a5487a68SSean Wang if (!skb || !sta || !msta)
845a5487a68SSean Wang return -EINVAL;
846a5487a68SSean Wang
847a5487a68SSean Wang tlv = mt76_connac_mcu_add_tlv(skb, NAN_UNI_CMD_UPDATE_CRB,
848a5487a68SSean Wang sizeof(struct mt7925_nan_sched_update_crb_tlv));
849a5487a68SSean Wang
850a5487a68SSean Wang if (!tlv)
851a5487a68SSean Wang return -ENOMEM;
852a5487a68SSean Wang
853a5487a68SSean Wang crb_tlv = (struct mt7925_nan_sched_update_crb_tlv *)tlv;
854a5487a68SSean Wang crb_tlv->sch_idx = cpu_to_le32(msta->nan_sched.sch_idx);
855a5487a68SSean Wang crb_tlv->flags = NAN_CRB_USE_DATA_PATH;
856a5487a68SSean Wang crb_tlv->is_use_ranging = false;
857a5487a68SSean Wang crb_tlv->comm_ndc_ctrl.is_valid = false;
858a5487a68SSean Wang
859*0f3605e4SSean Wang mt7925_nan_fill_crb_committed(crb_tlv, msta->vif->phy->dev->nan_vif,
860*0f3605e4SSean Wang sta->nan_sched);
861a5487a68SSean Wang
862a5487a68SSean Wang return 0;
863a5487a68SSean Wang }
864a5487a68SSean Wang
mt792x_nan_set_peer_schedule(struct mt792x_dev * dev,struct ieee80211_sta * sta)865a5487a68SSean Wang int mt792x_nan_set_peer_schedule(struct mt792x_dev *dev,
866a5487a68SSean Wang struct ieee80211_sta *sta)
867a5487a68SSean Wang {
868a5487a68SSean Wang struct mt7925_nan_common_hdr *hdr;
869*0f3605e4SSean Wang bool idx_allocated = false;
870a5487a68SSean Wang struct mt792x_sta *msta;
871a5487a68SSean Wang struct mt792x_nan *nan;
872a5487a68SSean Wang struct mt76_dev *mdev;
873a5487a68SSean Wang struct sk_buff *skb;
874*0f3605e4SSean Wang int ret;
875a5487a68SSean Wang
876a5487a68SSean Wang if (!dev || !sta)
877a5487a68SSean Wang return -EINVAL;
878a5487a68SSean Wang
879a5487a68SSean Wang mdev = &dev->mt76;
880a5487a68SSean Wang
881a5487a68SSean Wang skb = mt76_mcu_msg_alloc(mdev, NULL, MT7925_NAN_PEER_MAX_SIZE);
882a5487a68SSean Wang if (!skb)
883a5487a68SSean Wang return -ENOMEM;
884a5487a68SSean Wang
885a5487a68SSean Wang hdr = (struct mt7925_nan_common_hdr *)skb_put(skb, sizeof(*hdr));
886a5487a68SSean Wang memset(hdr, 0, sizeof(*hdr));
887a5487a68SSean Wang
888a5487a68SSean Wang msta = (struct mt792x_sta *)sta->drv_priv;
889a5487a68SSean Wang nan = &msta->vif->nan;
890a5487a68SSean Wang
891a5487a68SSean Wang /* Allocate connection index on first call for this peer */
892a5487a68SSean Wang if (!msta->nan_sched.idx_assigned) {
893a5487a68SSean Wang int idx = find_first_zero_bit(&nan->conn_bitmap,
894a5487a68SSean Wang NAN_MAX_CONN_CFG);
895a5487a68SSean Wang if (idx >= NAN_MAX_CONN_CFG) {
896a5487a68SSean Wang dev_kfree_skb(skb);
897a5487a68SSean Wang return -ENOSPC;
898a5487a68SSean Wang }
899a5487a68SSean Wang
900a5487a68SSean Wang set_bit(idx, &nan->conn_bitmap);
901a5487a68SSean Wang msta->nan_sched.sch_idx = idx;
902a5487a68SSean Wang msta->nan_sched.idx_assigned = true;
903*0f3605e4SSean Wang idx_allocated = true;
904a5487a68SSean Wang
905a5487a68SSean Wang if (mt7925_nan_peer_rec_tlv(skb, sta, msta, true) ||
906a5487a68SSean Wang mt7925_nan_peer_cap_tlv(skb, sta, msta)) {
907*0f3605e4SSean Wang ret = -ENOMEM;
908*0f3605e4SSean Wang goto free_skb;
909a5487a68SSean Wang }
910a5487a68SSean Wang }
911a5487a68SSean Wang
912a5487a68SSean Wang if (mt7925_nan_update_crb_tlv(skb, sta, msta)) {
913*0f3605e4SSean Wang ret = -ENOMEM;
914*0f3605e4SSean Wang goto free_skb;
915a5487a68SSean Wang }
916a5487a68SSean Wang
917*0f3605e4SSean Wang ret = mt76_mcu_skb_send_msg(mdev, skb, MCU_UNI_CMD(NAN), true);
918*0f3605e4SSean Wang if (ret && idx_allocated)
919*0f3605e4SSean Wang goto clear_idx;
920*0f3605e4SSean Wang
921*0f3605e4SSean Wang return ret;
922*0f3605e4SSean Wang
923*0f3605e4SSean Wang free_skb:
924*0f3605e4SSean Wang dev_kfree_skb(skb);
925*0f3605e4SSean Wang if (!idx_allocated)
926*0f3605e4SSean Wang return ret;
927*0f3605e4SSean Wang
928*0f3605e4SSean Wang clear_idx:
929*0f3605e4SSean Wang clear_bit(msta->nan_sched.sch_idx, &nan->conn_bitmap);
930*0f3605e4SSean Wang msta->nan_sched.idx_assigned = false;
931*0f3605e4SSean Wang
932*0f3605e4SSean Wang return ret;
933a5487a68SSean Wang }
934a5487a68SSean Wang
mt792x_nan_set_peer_rec(struct mt76_dev * mdev,struct ieee80211_sta * sta)935a5487a68SSean Wang int mt792x_nan_set_peer_rec(struct mt76_dev *mdev,
936a5487a68SSean Wang struct ieee80211_sta *sta)
937a5487a68SSean Wang {
938a5487a68SSean Wang struct mt7925_nan_common_hdr *hdr;
939a5487a68SSean Wang struct mt792x_sta *msta;
940a5487a68SSean Wang struct mt792x_nan *nan;
941a5487a68SSean Wang struct sk_buff *skb;
942*0f3605e4SSean Wang int ret;
943a5487a68SSean Wang
944a5487a68SSean Wang if (!mdev || !sta)
945a5487a68SSean Wang return -EINVAL;
946a5487a68SSean Wang
947a5487a68SSean Wang skb = mt76_mcu_msg_alloc(mdev, NULL,
948a5487a68SSean Wang sizeof(struct mt7925_nan_common_hdr) +
949a5487a68SSean Wang sizeof(struct mt7925_nan_sched_manage_peer_rec_tlv));
950a5487a68SSean Wang if (!skb)
951a5487a68SSean Wang return -ENOMEM;
952a5487a68SSean Wang
953a5487a68SSean Wang hdr = (struct mt7925_nan_common_hdr *)skb_put(skb, sizeof(*hdr));
954a5487a68SSean Wang memset(hdr, 0, sizeof(*hdr));
955a5487a68SSean Wang
956a5487a68SSean Wang msta = (struct mt792x_sta *)sta->drv_priv;
957a5487a68SSean Wang nan = &msta->vif->nan;
958a5487a68SSean Wang
959a5487a68SSean Wang if (!msta->nan_sched.idx_assigned) {
960a5487a68SSean Wang dev_kfree_skb(skb);
961a5487a68SSean Wang return 0;
962a5487a68SSean Wang }
963a5487a68SSean Wang
964a5487a68SSean Wang if (mt7925_nan_peer_rec_tlv(skb, sta, msta, false)) {
965a5487a68SSean Wang dev_kfree_skb(skb);
966a5487a68SSean Wang return -ENOMEM;
967a5487a68SSean Wang }
968a5487a68SSean Wang
969*0f3605e4SSean Wang ret = mt76_mcu_skb_send_msg(mdev, skb, MCU_UNI_CMD(NAN), true);
970*0f3605e4SSean Wang if (ret)
971*0f3605e4SSean Wang return ret;
972*0f3605e4SSean Wang
973a5487a68SSean Wang clear_bit(msta->nan_sched.sch_idx, &nan->conn_bitmap);
974a5487a68SSean Wang msta->nan_sched.idx_assigned = false;
975a5487a68SSean Wang
976*0f3605e4SSean Wang return 0;
977a5487a68SSean Wang }
978a5487a68SSean Wang
mt792x_nan_map_sta_rec(struct mt76_dev * mdev,struct ieee80211_vif * vif,struct ieee80211_sta * sta)979a5487a68SSean Wang int mt792x_nan_map_sta_rec(struct mt76_dev *mdev,
980a5487a68SSean Wang struct ieee80211_vif *vif,
981a5487a68SSean Wang struct ieee80211_sta *sta)
982a5487a68SSean Wang {
983a5487a68SSean Wang struct mt7925_nan_sched_map_sta_rec_tlv *map_tlv;
984a5487a68SSean Wang struct mt7925_nan_common_hdr *hdr;
985a5487a68SSean Wang struct ieee80211_sta *nmi_sta;
986a5487a68SSean Wang struct mt792x_sta *nmi_msta;
987*0f3605e4SSean Wang struct mt792x_vif *mvif;
988a5487a68SSean Wang struct mt792x_sta *msta;
989a5487a68SSean Wang u8 nmi_addr[ETH_ALEN];
990a5487a68SSean Wang struct sk_buff *skb;
991a5487a68SSean Wang int ndp_ctx_id = 0;
992*0f3605e4SSean Wang int ret = -ENOMEM;
993*0f3605e4SSean Wang struct mt792x_dev *dev;
994a5487a68SSean Wang struct tlv *tlv;
995a5487a68SSean Wang
996a5487a68SSean Wang if (!mdev || !vif || !sta)
997a5487a68SSean Wang return -EINVAL;
998a5487a68SSean Wang
999*0f3605e4SSean Wang dev = container_of(mdev, struct mt792x_dev, mt76);
1000a5487a68SSean Wang msta = (struct mt792x_sta *)sta->drv_priv;
1001*0f3605e4SSean Wang mvif = (struct mt792x_vif *)vif->drv_priv;
1002a5487a68SSean Wang
1003a5487a68SSean Wang rcu_read_lock();
1004a5487a68SSean Wang nmi_sta = rcu_dereference(sta->nmi);
1005a5487a68SSean Wang if (!nmi_sta) {
1006a5487a68SSean Wang rcu_read_unlock();
1007a5487a68SSean Wang dev_err(mdev->dev, "NAN: NMI sta not found for NDI sta %pM\n",
1008a5487a68SSean Wang sta->addr);
1009a5487a68SSean Wang return -EINVAL;
1010a5487a68SSean Wang }
1011a5487a68SSean Wang
1012a5487a68SSean Wang memcpy(nmi_addr, nmi_sta->addr, ETH_ALEN);
1013a5487a68SSean Wang nmi_msta = (struct mt792x_sta *)nmi_sta->drv_priv;
1014a5487a68SSean Wang
1015*0f3605e4SSean Wang if (!nmi_msta->nan_sched.idx_assigned) {
1016*0f3605e4SSean Wang if (!nmi_sta->nan_sched) {
1017*0f3605e4SSean Wang rcu_read_unlock();
1018*0f3605e4SSean Wang dev_err(mdev->dev,
1019*0f3605e4SSean Wang "NAN: peer schedule missing for NDI sta %pM\n",
1020*0f3605e4SSean Wang sta->addr);
1021*0f3605e4SSean Wang return -EAGAIN;
1022*0f3605e4SSean Wang }
1023*0f3605e4SSean Wang
1024*0f3605e4SSean Wang rcu_read_unlock();
1025*0f3605e4SSean Wang ret = mt792x_nan_set_peer_schedule(dev, nmi_sta);
1026*0f3605e4SSean Wang if (ret)
1027*0f3605e4SSean Wang return ret;
1028*0f3605e4SSean Wang
1029*0f3605e4SSean Wang rcu_read_lock();
1030*0f3605e4SSean Wang nmi_sta = rcu_dereference(sta->nmi);
1031*0f3605e4SSean Wang if (!nmi_sta) {
1032*0f3605e4SSean Wang rcu_read_unlock();
1033*0f3605e4SSean Wang dev_err(mdev->dev,
1034*0f3605e4SSean Wang "NAN: NMI sta not found for NDI sta %pM\n",
1035*0f3605e4SSean Wang sta->addr);
1036*0f3605e4SSean Wang return -EINVAL;
1037*0f3605e4SSean Wang }
1038*0f3605e4SSean Wang
1039*0f3605e4SSean Wang nmi_msta = (struct mt792x_sta *)nmi_sta->drv_priv;
1040*0f3605e4SSean Wang }
1041*0f3605e4SSean Wang
1042a5487a68SSean Wang ndp_ctx_id = find_first_zero_bit(&nmi_msta->nan_sched.ndp_ctx_bitmap,
1043a5487a68SSean Wang NAN_MAX_NDP_CXT);
1044*0f3605e4SSean Wang if (ndp_ctx_id >= NAN_MAX_NDP_CXT) {
1045*0f3605e4SSean Wang rcu_read_unlock();
1046*0f3605e4SSean Wang return -ENOSPC;
1047*0f3605e4SSean Wang }
1048*0f3605e4SSean Wang
1049a5487a68SSean Wang set_bit(ndp_ctx_id, &nmi_msta->nan_sched.ndp_ctx_bitmap);
1050a5487a68SSean Wang rcu_read_unlock();
1051a5487a68SSean Wang
1052a5487a68SSean Wang msta->nan_sched.ndp_ctx_id = ndp_ctx_id;
1053*0f3605e4SSean Wang msta->nan_sched.ndp_ctx_assigned = true;
1054a5487a68SSean Wang
1055a5487a68SSean Wang skb = mt76_mcu_msg_alloc(mdev, NULL,
1056a5487a68SSean Wang sizeof(struct mt7925_nan_common_hdr) +
1057a5487a68SSean Wang sizeof(struct mt7925_nan_sched_map_sta_rec_tlv));
1058a5487a68SSean Wang if (!skb)
1059*0f3605e4SSean Wang goto clear_ndp_ctx;
1060a5487a68SSean Wang
1061a5487a68SSean Wang hdr = (struct mt7925_nan_common_hdr *)skb_put(skb, sizeof(*hdr));
1062a5487a68SSean Wang memset(hdr, 0, sizeof(*hdr));
1063a5487a68SSean Wang
1064a5487a68SSean Wang tlv = mt76_connac_mcu_add_tlv(skb, NAN_UNI_CMD_MAP_STA_RECORD,
1065a5487a68SSean Wang sizeof(struct mt7925_nan_sched_map_sta_rec_tlv));
1066a5487a68SSean Wang if (!tlv) {
1067a5487a68SSean Wang dev_kfree_skb(skb);
1068*0f3605e4SSean Wang ret = -ENOMEM;
1069*0f3605e4SSean Wang goto clear_ndp_ctx;
1070a5487a68SSean Wang }
1071a5487a68SSean Wang
1072a5487a68SSean Wang map_tlv = (struct mt7925_nan_sched_map_sta_rec_tlv *)tlv;
1073a5487a68SSean Wang memcpy(map_tlv->nmi_addr, nmi_addr, ETH_ALEN);
1074a5487a68SSean Wang map_tlv->sta_rec_idx = msta->deflink.wcid.idx;
1075a5487a68SSean Wang map_tlv->ndp_ctx_id = ndp_ctx_id;
1076*0f3605e4SSean Wang map_tlv->role_idx = cpu_to_le32(mvif->bss_conf.mt76.idx);
1077a5487a68SSean Wang memcpy(map_tlv->ndi_addr, vif->addr, ETH_ALEN);
1078a5487a68SSean Wang
1079*0f3605e4SSean Wang ret = mt76_mcu_skb_send_msg(mdev, skb,
1080a5487a68SSean Wang MCU_UNI_CMD(NAN), true);
1081*0f3605e4SSean Wang if (ret)
1082*0f3605e4SSean Wang goto clear_ndp_ctx;
1083*0f3605e4SSean Wang
1084*0f3605e4SSean Wang return 0;
1085*0f3605e4SSean Wang
1086*0f3605e4SSean Wang clear_ndp_ctx:
1087*0f3605e4SSean Wang rcu_read_lock();
1088*0f3605e4SSean Wang nmi_sta = rcu_dereference(sta->nmi);
1089*0f3605e4SSean Wang if (nmi_sta) {
1090*0f3605e4SSean Wang nmi_msta = (struct mt792x_sta *)nmi_sta->drv_priv;
1091*0f3605e4SSean Wang clear_bit(msta->nan_sched.ndp_ctx_id,
1092*0f3605e4SSean Wang &nmi_msta->nan_sched.ndp_ctx_bitmap);
1093*0f3605e4SSean Wang }
1094*0f3605e4SSean Wang rcu_read_unlock();
1095*0f3605e4SSean Wang msta->nan_sched.ndp_ctx_assigned = false;
1096*0f3605e4SSean Wang
1097*0f3605e4SSean Wang return ret ?: -ENOMEM;
1098a5487a68SSean Wang }
1099