blob: be103d343b390d6fcb45866052672563140d1f92 [file] [log] [blame]
developer66e89bc2024-04-23 14:50:01 +08001From 60adbabe8df3bdbab9bd3c2146f19b4c83b69def Mon Sep 17 00:00:00 2001
2From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
3Date: Thu, 22 Sep 2022 14:27:41 +0800
4Subject: [PATCH 11/61] mtk: cfg80211: implement DFS status show, cac and nop
5 skip command via debugfs
6
7Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
8
9Refactor DFS debugfs command for MLO
10
developer66e89bc2024-04-23 14:50:01 +080011Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
developer66e89bc2024-04-23 14:50:01 +080012---
13 include/net/cfg80211.h | 1 +
14 net/mac80211/cfg.c | 25 +++
15 net/wireless/core.h | 3 +
16 net/wireless/debugfs.c | 326 +++++++++++++++++++++++++++++++++++++++-
17 net/wireless/mlme.c | 6 +
18 net/wireless/rdev-ops.h | 14 ++
19 net/wireless/trace.h | 13 ++
20 7 files changed, 381 insertions(+), 7 deletions(-)
21
22diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
23index d987b62..c55028f 100644
24--- a/include/net/cfg80211.h
25+++ b/include/net/cfg80211.h
26@@ -4965,6 +4965,7 @@ struct cfg80211_ops {
27 struct cfg80211_set_hw_timestamp *hwts);
28 int (*set_ttlm)(struct wiphy *wiphy, struct net_device *dev,
29 struct cfg80211_ttlm_params *params);
30+ void (*skip_cac)(struct wireless_dev *wdev, unsigned int link_id);
31 };
32
33 /*
34diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
35index 72e64be..3f4c129 100644
36--- a/net/mac80211/cfg.c
37+++ b/net/mac80211/cfg.c
38@@ -5055,6 +5055,30 @@ ieee80211_set_ttlm(struct wiphy *wiphy, struct net_device *dev,
39 return ieee80211_req_neg_ttlm(sdata, params);
40 }
41
42+static void
43+ieee80211_skip_cac(struct wireless_dev *wdev, unsigned int link_id)
44+{
45+ struct net_device *dev = wdev->netdev;
46+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
47+ struct ieee80211_link_data *link;
48+ unsigned int cac_time_ms;
49+
50+ link = sdata_dereference(sdata->link[link_id], sdata);
51+ if (!link)
52+ return;
53+
54+ wiphy_delayed_work_cancel(sdata->local->hw.wiphy,
55+ &link->dfs_cac_timer_work);
56+ if (wdev->cac_started) {
57+ ieee80211_link_release_channel(link);
58+ cac_time_ms = wdev->cac_time_ms;
59+ wdev->cac_start_time = jiffies -
60+ msecs_to_jiffies(cac_time_ms + 1);
61+ cfg80211_cac_event(wdev->netdev, &link->conf->chanreq.oper,
62+ NL80211_RADAR_CAC_FINISHED, GFP_KERNEL);
63+ }
64+}
65+
66 const struct cfg80211_ops mac80211_config_ops = {
67 .add_virtual_intf = ieee80211_add_iface,
68 .del_virtual_intf = ieee80211_del_iface,
69@@ -5168,4 +5192,5 @@ const struct cfg80211_ops mac80211_config_ops = {
70 .del_link_station = ieee80211_del_link_station,
71 .set_hw_timestamp = ieee80211_set_hw_timestamp,
72 .set_ttlm = ieee80211_set_ttlm,
73+ .skip_cac = ieee80211_skip_cac,
74 };
75diff --git a/net/wireless/core.h b/net/wireless/core.h
76index 7bef6b0..ae6b7fa 100644
77--- a/net/wireless/core.h
78+++ b/net/wireless/core.h
79@@ -86,6 +86,9 @@ struct cfg80211_registered_device {
80
81 struct wireless_dev *background_radar_wdev;
82 struct cfg80211_chan_def background_radar_chandef;
83+ bool background_cac_started;
84+ unsigned long background_cac_start_time;
85+ unsigned int background_cac_time_ms;
86 struct delayed_work background_cac_done_wk;
87 struct work_struct background_cac_abort_wk;
88
89diff --git a/net/wireless/debugfs.c b/net/wireless/debugfs.c
90index 7c59a25..a246b2c 100644
91--- a/net/wireless/debugfs.c
92+++ b/net/wireless/debugfs.c
93@@ -10,6 +10,7 @@
94 #include <linux/slab.h>
95 #include "core.h"
96 #include "debugfs.h"
97+#include "rdev-ops.h"
98
99 #define DEBUGFS_READONLY_FILE(name, buflen, fmt, value...) \
100 static ssize_t name## _read(struct file *file, char __user *userbuf, \
101@@ -97,18 +98,329 @@ static const struct file_operations ht40allow_map_ops = {
102 .llseek = default_llseek,
103 };
104
105-#define DEBUGFS_ADD(name) \
106- debugfs_create_file(#name, 0444, phyd, &rdev->wiphy, &name## _ops)
107+static int dfs_print_chan(struct ieee80211_channel *chan, int remain_time, int wait_time,
108+ char *buf, int buf_size, int offset, bool is_background)
109+{
110+ if (WARN_ON(offset > buf_size))
111+ return 0;
112+
113+ if (chan->dfs_state == NL80211_DFS_UNAVAILABLE) {
114+ offset += scnprintf(buf + offset, buf_size - offset,
115+ " Channel = %d, DFS_state = Unavailable",
116+ chan->hw_value);
117+ if (remain_time > 0)
118+ offset += scnprintf(buf + offset, buf_size - offset,
119+ ", Non-occupancy Remain Time = %d / %d [sec]",
120+ remain_time, wait_time);
121+ else
122+ offset += scnprintf(buf + offset, buf_size - offset,
123+ ", Changing state...");
124+ } else if (chan->dfs_state == NL80211_DFS_USABLE) {
125+ offset += scnprintf(buf + offset, buf_size - offset,
126+ " Channel = %d, DFS_state = Usable",
127+ chan->hw_value);
128+ if (remain_time > 0)
129+ offset += scnprintf(buf + offset, buf_size - offset,
130+ ", CAC Remain Time = %d / %d [sec]",
131+ remain_time, wait_time);
132+ } else if (chan->dfs_state == NL80211_DFS_AVAILABLE) {
133+ offset += scnprintf(buf + offset, buf_size - offset,
134+ " Channel = %d, DFS_state = Available",
135+ chan->hw_value);
136+ } else {
137+ offset += scnprintf(buf + offset, buf_size - offset,
138+ " Channel = %d, DFS_state = Unknown",
139+ chan->hw_value);
140+ }
141+
142+ if (is_background)
143+ offset += scnprintf(buf + offset, buf_size - offset,
144+ " (background chain)");
145+ offset += scnprintf(buf + offset, buf_size - offset, "\n");
146+
147+ return offset;
148+}
149+
150+static int dfs_status_read_wdev(struct wiphy *wiphy, struct wireless_dev *wdev, char *buf,
151+ unsigned int buf_size, unsigned int offset)
152+{
153+ struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
154+ struct cfg80211_chan_def *chandef;
155+ struct cfg80211_chan_def *background_chandef = &rdev->background_radar_chandef;
156+ enum nl80211_band band;
157+ struct ieee80211_supported_band *sband;
158+ struct ieee80211_channel *chan;
159+ unsigned long jiffies_passed;
160+ unsigned int link_id;
161+ int i, remain_time = 0, wait_time_ms = 0;
162+ bool is_background;
163+
164+ for (band = 0; band < NUM_NL80211_BANDS; band++)
165+ if (wiphy->bands[band] &&
166+ wiphy->bands[band]->band == NL80211_BAND_5GHZ)
167+ sband = wiphy->bands[band];
168+
169+ if (!sband) {
170+ offset += scnprintf(buf + offset, buf_size - offset, "No 5G band\n");
171+ return offset;
172+ }
173+
174+ for_each_valid_link(wdev, link_id) {
175+ chandef = wdev_chandef(wdev, link_id);
176+ if (!chandef || !chandef->chan ||
177+ chandef->chan->band != NL80211_BAND_5GHZ)
178+ continue;
179+
180+ offset += scnprintf(buf + offset, buf_size - offset,
181+ "Link %d DFS channel:\n", link_id);
182+ for (i = 0; i < sband->n_channels; i++) {
183+ is_background = false;
184+ chan = &sband->channels[i];
185+
186+ if (!(chan->flags & IEEE80211_CHAN_RADAR))
187+ continue;
188+
189+ if (chan->dfs_state == NL80211_DFS_UNAVAILABLE) {
190+ jiffies_passed = jiffies - chan->dfs_state_entered;
191+ wait_time_ms = IEEE80211_DFS_MIN_NOP_TIME_MS;
192+ remain_time = (wait_time_ms - jiffies_to_msecs(jiffies_passed));
193+ if (remain_time > wait_time_ms)
194+ remain_time = 0;
195+ } else if (chan->dfs_state == NL80211_DFS_USABLE) {
196+ if (wdev->cac_started &&
197+ cfg80211_is_sub_chan(chandef, chan, false)) {
198+ jiffies_passed = jiffies - wdev->cac_start_time;
199+ wait_time_ms = wdev->cac_time_ms;
200+ remain_time = (wait_time_ms -
201+ jiffies_to_msecs(jiffies_passed));
202+ }
203+
204+ if (rdev->background_radar_wdev == wdev &&
205+ rdev->background_cac_started &&
206+ cfg80211_is_sub_chan(background_chandef, chan, false)) {
207+ jiffies_passed = jiffies - rdev->background_cac_start_time;
208+ wait_time_ms = rdev->background_cac_time_ms;
209+ remain_time = (wait_time_ms -
210+ jiffies_to_msecs(jiffies_passed));
211+ is_background = true;
212+ }
213+
214+ if (remain_time > wait_time_ms)
215+ remain_time = 0;
216+
217+ } else {
218+ if (rdev->background_radar_wdev == wdev &&
219+ cfg80211_is_sub_chan(background_chandef, chan, false))
220+ is_background = true;
221+ }
222+
223+ offset = dfs_print_chan(chan, remain_time / 1000, wait_time_ms / 1000,
224+ buf, buf_size, offset, is_background);
225+ remain_time = 0;
226+ }
227+ }
228+
229+ return offset;
230+}
231+
232+static ssize_t dfs_status_read(struct file *file, char __user *user_buf,
233+ size_t count, loff_t *ppos)
234+{
235+ struct wiphy *wiphy = file->private_data;
236+ struct wireless_dev *wdev;
237+ char *buf;
238+ unsigned int offset = 0, buf_size = PAGE_SIZE, r;
239+ const char * const iftype_str[] = {
240+ [NL80211_IFTYPE_UNSPECIFIED] = "unspecified",
241+ [NL80211_IFTYPE_ADHOC] = "adhoc",
242+ [NL80211_IFTYPE_STATION] = "station",
243+ [NL80211_IFTYPE_AP] = "ap",
244+ [NL80211_IFTYPE_AP_VLAN] = "ap vlan",
245+ [NL80211_IFTYPE_WDS] = "wds",
246+ [NL80211_IFTYPE_MONITOR] = "monitor",
247+ [NL80211_IFTYPE_MESH_POINT] = "mesh point",
248+ [NL80211_IFTYPE_P2P_CLIENT] = "p2p client",
249+ [NL80211_IFTYPE_P2P_GO] = "p2p go",
250+ [NL80211_IFTYPE_P2P_DEVICE] = "p2p device",
251+ [NL80211_IFTYPE_OCB] = "ocb",
252+ [NL80211_IFTYPE_NAN] = "nan",
253+ };
254+
255+ buf = kzalloc(buf_size, GFP_KERNEL);
256+ if (!buf)
257+ return -ENOMEM;
258+
259+ list_for_each_entry(wdev, &wiphy->wdev_list, list) {
260+ offset += scnprintf(buf + offset, buf_size - offset,
261+ "wdev 0x%x\n"
262+ "interface type %s\n",
263+ wdev->identifier, iftype_str[wdev->iftype]);
264+ offset = dfs_status_read_wdev(wiphy, wdev, buf, buf_size, offset);
265+ }
266+
267+ r = simple_read_from_buffer(user_buf, count, ppos, buf, offset);
268+
269+ kfree(buf);
270+
271+ return r;
272+}
273+
274+static const struct file_operations dfs_status_ops = {
275+ .read = dfs_status_read,
276+ .open = simple_open,
277+ .llseek = default_llseek,
278+};
279+
280+static int
281+dfs_nop_skip(void *data, u64 val)
282+{
283+ struct wiphy *wiphy = data;
284+ struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
285+ bool en = !!val;
286+ enum nl80211_band band;
287+ struct ieee80211_supported_band *sband;
288+ struct ieee80211_channel *chan;
289+ u32 nop_time = IEEE80211_DFS_MIN_NOP_TIME_MS;
290+ int i;
291+
292+ if (!en)
293+ return 0;
294+
295+ for (band = 0; band < NUM_NL80211_BANDS; band++) {
296+ sband = wiphy->bands[band];
297+ if (!sband)
298+ continue;
299+ for (i = 0; i < sband->n_channels; i++) {
300+ chan = &sband->channels[i];
301+
302+ if (!(chan->flags & IEEE80211_CHAN_RADAR))
303+ continue;
304+
305+ if (chan->dfs_state == NL80211_DFS_UNAVAILABLE) {
306+ // Let current jiffies > dfs_state_entered_jiffies + NOP time
307+ chan->dfs_state_entered = jiffies -
308+ msecs_to_jiffies(nop_time + 1);
309+ }
310+ }
311+ }
312+
313+ cfg80211_sched_dfs_chan_update(rdev);
314+
315+ return 0;
316+}
317+
318+DEFINE_DEBUGFS_ATTRIBUTE(dfs_skip_nop_ops, NULL,
319+ dfs_nop_skip, "0x%08llx\n");
320+
321+static int
322+dfs_cac_skip(void *data, u64 val)
323+{
324+#define CAC_SKIP_MASK BIT(0)
325+#define CAC_SKIP_BACKGROUND_MASK BIT(1)
326+ struct wiphy *wiphy = data;
327+ struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
328+ struct wireless_dev *wdev;
329+ struct cfg80211_chan_def *c;
330+ unsigned int link_id, skip_mode = val;
331+ unsigned long cac_time;
332+
333+ if (!skip_mode || skip_mode > (CAC_SKIP_MASK | CAC_SKIP_BACKGROUND_MASK))
334+ return 0;
335+
336+ list_for_each_entry(wdev, &wiphy->wdev_list, list) {
337+ if (skip_mode & CAC_SKIP_MASK) {
338+ for_each_valid_link(wdev, link_id) {
339+ c = wdev_chandef(wdev, link_id);
340+ if (!c || !c->chan ||
341+ c->chan->band != NL80211_BAND_5GHZ)
342+ continue;
343+
344+ if (cfg80211_chandef_dfs_required(wiphy, c, wdev->iftype) > 0 &&
345+ cfg80211_chandef_dfs_usable(wiphy, c) && wdev->cac_started) {
346+ rdev_skip_cac(rdev, wdev, link_id);
347+ }
348+ }
349+ }
350+
351+ if ((skip_mode & CAC_SKIP_BACKGROUND_MASK) &&
352+ rdev->background_radar_wdev == wdev &&
353+ rdev->background_radar_chandef.chan) {
354+ c = &rdev->background_radar_chandef;
355+
356+ if ((cfg80211_chandef_dfs_required(wiphy, c, wdev->iftype) > 0) &&
357+ cfg80211_chandef_dfs_usable(wiphy, c) &&
358+ rdev->background_cac_started) {
359+ // Let current jiffies > dfs_state_entered_jiffies + CAC time
360+ cac_time = rdev->background_cac_time_ms;
361+ rdev->background_cac_start_time = jiffies -
362+ msecs_to_jiffies(cac_time + 1);
363+ cancel_delayed_work(&rdev->background_cac_done_wk);
364+ queue_delayed_work(cfg80211_wq, &rdev->background_cac_done_wk, 0);
365+ }
366+ }
367+ }
368+
369+ return 0;
370+}
371+
372+DEFINE_DEBUGFS_ATTRIBUTE(dfs_skip_cac_ops, NULL,
373+ dfs_cac_skip, "0x%08llx\n");
374+
375+static int
376+dfs_available_reset(void *data, u64 val)
377+{
378+ struct wiphy *wiphy = data;
379+ struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
380+ bool en = !!val;
381+ enum nl80211_band band;
382+ struct ieee80211_supported_band *sband;
383+ struct ieee80211_channel *chan;
384+ int i;
385+
386+ if (!en)
387+ return 0;
388+
389+ for (band = 0; band < NUM_NL80211_BANDS; band++) {
390+ sband = wiphy->bands[band];
391+ if (!sband)
392+ continue;
393+ for (i = 0; i < sband->n_channels; i++) {
394+ chan = &sband->channels[i];
395+
396+ if (!(chan->flags & IEEE80211_CHAN_RADAR))
397+ continue;
398+
399+ if (chan->dfs_state == NL80211_DFS_AVAILABLE) {
400+ chan->dfs_state = NL80211_DFS_USABLE;
401+ chan->dfs_state_entered = jiffies;
402+ }
403+ }
404+ }
405+
406+ cfg80211_sched_dfs_chan_update(rdev);
407+
408+ return 0;
409+}
410+
411+DEFINE_DEBUGFS_ATTRIBUTE(dfs_available_reset_ops, NULL,
412+ dfs_available_reset, "0x%08llx\n");
413+
414+#define DEBUGFS_ADD(name, chmod) \
415+ debugfs_create_file(#name, chmod, phyd, &rdev->wiphy, &name## _ops)
416
417 void cfg80211_debugfs_rdev_add(struct cfg80211_registered_device *rdev)
418 {
419 struct dentry *phyd = rdev->wiphy.debugfsdir;
420
421- DEBUGFS_ADD(rts_threshold);
422- DEBUGFS_ADD(fragmentation_threshold);
423- DEBUGFS_ADD(short_retry_limit);
424- DEBUGFS_ADD(long_retry_limit);
425- DEBUGFS_ADD(ht40allow_map);
426+ DEBUGFS_ADD(rts_threshold, 0444);
427+ DEBUGFS_ADD(fragmentation_threshold, 0444);
428+ DEBUGFS_ADD(short_retry_limit, 0444);
429+ DEBUGFS_ADD(long_retry_limit, 0444);
430+ DEBUGFS_ADD(ht40allow_map, 0444);
431+ DEBUGFS_ADD(dfs_status, 0444);
432+ DEBUGFS_ADD(dfs_skip_nop, 0600);
433+ DEBUGFS_ADD(dfs_skip_cac, 0600);
434+ DEBUGFS_ADD(dfs_available_reset, 0600);
435 }
436
437 struct debugfs_read_work {
438diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
439index c7e62eb..d42b65b 100644
440--- a/net/wireless/mlme.c
441+++ b/net/wireless/mlme.c
442@@ -1177,13 +1177,16 @@ __cfg80211_background_cac_event(struct cfg80211_registered_device *rdev,
443 queue_work(cfg80211_wq, &rdev->propagate_cac_done_wk);
444 cfg80211_sched_dfs_chan_update(rdev);
445 wdev = rdev->background_radar_wdev;
446+ rdev->background_cac_started = false;
447 break;
448 case NL80211_RADAR_CAC_ABORTED:
449 if (!cancel_delayed_work(&rdev->background_cac_done_wk))
450 return;
451 wdev = rdev->background_radar_wdev;
452+ rdev->background_cac_started = false;
453 break;
454 case NL80211_RADAR_CAC_STARTED:
455+ rdev->background_cac_started = true;
456 break;
457 default:
458 return;
459@@ -1203,6 +1206,7 @@ cfg80211_background_cac_event(struct cfg80211_registered_device *rdev,
460 chandef, event);
461 wiphy_unlock(&rdev->wiphy);
462 }
463+EXPORT_SYMBOL(cfg80211_background_cac_event);
464
465 void cfg80211_background_cac_done_wk(struct work_struct *work)
466 {
467@@ -1264,8 +1268,10 @@ cfg80211_start_background_radar_detection(struct cfg80211_registered_device *rde
468 if (!cac_time_ms)
469 cac_time_ms = IEEE80211_DFS_MIN_CAC_TIME_MS;
470
471+ rdev->background_cac_time_ms = cac_time_ms;
472 rdev->background_radar_chandef = *chandef;
473 rdev->background_radar_wdev = wdev; /* Get offchain ownership */
474+ rdev->background_cac_start_time = jiffies;
475
476 __cfg80211_background_cac_event(rdev, wdev, chandef,
477 NL80211_RADAR_CAC_STARTED);
478diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
479index 466828f..2ae7fc5 100644
480--- a/net/wireless/rdev-ops.h
481+++ b/net/wireless/rdev-ops.h
482@@ -1542,4 +1542,18 @@ rdev_set_ttlm(struct cfg80211_registered_device *rdev,
483
484 return ret;
485 }
486+
487+static inline int
488+rdev_skip_cac(struct cfg80211_registered_device *rdev,
489+ struct wireless_dev *wdev, unsigned int link_id)
490+{
491+ if (!rdev->ops->skip_cac)
492+ return -EOPNOTSUPP;
493+
494+ trace_rdev_skip_cac(wdev, link_id);
495+ rdev->ops->skip_cac(wdev, link_id);
496+ trace_rdev_return_void(&rdev->wiphy);
497+
498+ return 0;
499+}
500 #endif /* __CFG80211_RDEV_OPS */
501diff --git a/net/wireless/trace.h b/net/wireless/trace.h
502index 7073a70..aa3284f 100644
503--- a/net/wireless/trace.h
504+++ b/net/wireless/trace.h
505@@ -4005,6 +4005,19 @@ TRACE_EVENT(rdev_set_ttlm,
506 WIPHY_PR_ARG, NETDEV_PR_ARG)
507 );
508
509+TRACE_EVENT(rdev_skip_cac,
510+ TP_PROTO(struct wireless_dev *wdev, unsigned int link_id),
511+ TP_ARGS(wdev, link_id),
512+ TP_STRUCT__entry(
513+ WDEV_ENTRY
514+ __field(unsigned int, link_id)
515+ ),
516+ TP_fast_assign(
517+ WDEV_ASSIGN;
518+ __entry->link_id = link_id;
519+ ),
520+ TP_printk(WDEV_PR_FMT ", link_id: %d", WDEV_PR_ARG, __entry->link_id)
521+);
522 #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */
523
524 #undef TRACE_INCLUDE_PATH
525--
5262.39.2
527