Commit | Line | Data |
---|---|---|
d34be431 EQ |
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); | |
d34be431 EQ |
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 | } |