GNU Linux-libre 6.8.7-gnu
[releases.git] / net / mac80211 / wbrf.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Wifi Band Exclusion Interface for WLAN
4  * Copyright (C) 2023 Advanced Micro Devices
5  *
6  */
7
8 #include <linux/acpi_amd_wbrf.h>
9 #include <linux/units.h>
10 #include <net/cfg80211.h>
11 #include "ieee80211_i.h"
12
13 void ieee80211_check_wbrf_support(struct ieee80211_local *local)
14 {
15         struct wiphy *wiphy = local->hw.wiphy;
16         struct device *dev;
17
18         if (!wiphy)
19                 return;
20
21         dev = wiphy->dev.parent;
22         if (!dev)
23                 return;
24
25         local->wbrf_supported = acpi_amd_wbrf_supported_producer(dev);
26 }
27
28 static void get_chan_freq_boundary(u32 center_freq, u32 bandwidth, u64 *start, u64 *end)
29 {
30         bandwidth *= KHZ_PER_MHZ;
31         center_freq *= KHZ_PER_MHZ;
32
33         *start = center_freq - bandwidth / 2;
34         *end = center_freq + bandwidth / 2;
35
36         /* Frequency in Hz is expected */
37         *start = *start * HZ_PER_KHZ;
38         *end = *end * HZ_PER_KHZ;
39 }
40
41 static void get_ranges_from_chandef(struct cfg80211_chan_def *chandef,
42                                     struct wbrf_ranges_in_out *ranges_in)
43 {
44         u64 start_freq1, end_freq1;
45         u64 start_freq2, end_freq2;
46         int bandwidth;
47
48         bandwidth = nl80211_chan_width_to_mhz(chandef->width);
49
50         get_chan_freq_boundary(chandef->center_freq1, bandwidth, &start_freq1, &end_freq1);
51
52         ranges_in->band_list[0].start = start_freq1;
53         ranges_in->band_list[0].end = end_freq1;
54         ranges_in->num_of_ranges = 1;
55
56         if (chandef->width == NL80211_CHAN_WIDTH_80P80) {
57                 get_chan_freq_boundary(chandef->center_freq2, bandwidth, &start_freq2, &end_freq2);
58
59                 ranges_in->band_list[1].start = start_freq2;
60                 ranges_in->band_list[1].end = end_freq2;
61                 ranges_in->num_of_ranges++;
62         }
63 }
64
65 void ieee80211_add_wbrf(struct ieee80211_local *local, struct cfg80211_chan_def *chandef)
66 {
67         struct wbrf_ranges_in_out ranges_in = {0};
68         struct device *dev;
69
70         if (!local->wbrf_supported)
71                 return;
72
73         dev = local->hw.wiphy->dev.parent;
74
75         get_ranges_from_chandef(chandef, &ranges_in);
76
77         acpi_amd_wbrf_add_remove(dev, WBRF_RECORD_ADD, &ranges_in);
78 }
79
80 void ieee80211_remove_wbrf(struct ieee80211_local *local, struct cfg80211_chan_def *chandef)
81 {
82         struct wbrf_ranges_in_out ranges_in = {0};
83         struct device *dev;
84
85         if (!local->wbrf_supported)
86                 return;
87
88         dev = local->hw.wiphy->dev.parent;
89
90         get_ranges_from_chandef(chandef, &ranges_in);
91
92         acpi_amd_wbrf_add_remove(dev, WBRF_RECORD_REMOVE, &ranges_in);
93 }