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