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 dev_dbg(dev, "WBRF is %s supported\n", 27 local->wbrf_supported ? "" : "not"); 28 } 29 30 static void get_chan_freq_boundary(u32 center_freq, u32 bandwidth, u64 *start, u64 *end) 31 { 32 bandwidth *= KHZ_PER_MHZ; 33 center_freq *= KHZ_PER_MHZ; 34 35 *start = center_freq - bandwidth / 2; 36 *end = center_freq + bandwidth / 2; 37 38 /* Frequency in Hz is expected */ 39 *start = *start * HZ_PER_KHZ; 40 *end = *end * HZ_PER_KHZ; 41 } 42 43 static void get_ranges_from_chandef(struct cfg80211_chan_def *chandef, 44 struct wbrf_ranges_in_out *ranges_in) 45 { 46 u64 start_freq1, end_freq1; 47 u64 start_freq2, end_freq2; 48 int bandwidth; 49 50 bandwidth = nl80211_chan_width_to_mhz(chandef->width); 51 52 get_chan_freq_boundary(chandef->center_freq1, bandwidth, &start_freq1, &end_freq1); 53 54 ranges_in->band_list[0].start = start_freq1; 55 ranges_in->band_list[0].end = end_freq1; 56 ranges_in->num_of_ranges = 1; 57 58 if (chandef->width == NL80211_CHAN_WIDTH_80P80) { 59 get_chan_freq_boundary(chandef->center_freq2, bandwidth, &start_freq2, &end_freq2); 60 61 ranges_in->band_list[1].start = start_freq2; 62 ranges_in->band_list[1].end = end_freq2; 63 ranges_in->num_of_ranges++; 64 } 65 } 66 67 void ieee80211_add_wbrf(struct ieee80211_local *local, struct cfg80211_chan_def *chandef) 68 { 69 struct wbrf_ranges_in_out ranges_in = {0}; 70 struct device *dev; 71 72 if (!local->wbrf_supported) 73 return; 74 75 dev = local->hw.wiphy->dev.parent; 76 77 get_ranges_from_chandef(chandef, &ranges_in); 78 79 acpi_amd_wbrf_add_remove(dev, WBRF_RECORD_ADD, &ranges_in); 80 } 81 82 void ieee80211_remove_wbrf(struct ieee80211_local *local, struct cfg80211_chan_def *chandef) 83 { 84 struct wbrf_ranges_in_out ranges_in = {0}; 85 struct device *dev; 86 87 if (!local->wbrf_supported) 88 return; 89 90 dev = local->hw.wiphy->dev.parent; 91 92 get_ranges_from_chandef(chandef, &ranges_in); 93 94 acpi_amd_wbrf_add_remove(dev, WBRF_RECORD_REMOVE, &ranges_in); 95 } 96