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