wbrf.c 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  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. #include <linux/acpi_amd_wbrf.h>
  8. #include <linux/units.h>
  9. #include <net/cfg80211.h>
  10. #include "ieee80211_i.h"
  11. void ieee80211_check_wbrf_support(struct ieee80211_local *local)
  12. {
  13. struct wiphy *wiphy = local->hw.wiphy;
  14. struct device *dev;
  15. if (!wiphy)
  16. return;
  17. dev = wiphy->dev.parent;
  18. if (!dev)
  19. return;
  20. local->wbrf_supported = acpi_amd_wbrf_supported_producer(dev);
  21. }
  22. static void get_chan_freq_boundary(u32 center_freq, u32 bandwidth, u64 *start, u64 *end)
  23. {
  24. bandwidth *= KHZ_PER_MHZ;
  25. center_freq *= KHZ_PER_MHZ;
  26. *start = center_freq - bandwidth / 2;
  27. *end = center_freq + bandwidth / 2;
  28. /* Frequency in Hz is expected */
  29. *start = *start * HZ_PER_KHZ;
  30. *end = *end * HZ_PER_KHZ;
  31. }
  32. static void get_ranges_from_chandef(struct cfg80211_chan_def *chandef,
  33. struct wbrf_ranges_in_out *ranges_in)
  34. {
  35. u64 start_freq1, end_freq1;
  36. u64 start_freq2, end_freq2;
  37. int bandwidth;
  38. bandwidth = nl80211_chan_width_to_mhz(chandef->width);
  39. get_chan_freq_boundary(chandef->center_freq1, bandwidth, &start_freq1, &end_freq1);
  40. ranges_in->band_list[0].start = start_freq1;
  41. ranges_in->band_list[0].end = end_freq1;
  42. ranges_in->num_of_ranges = 1;
  43. if (chandef->width == NL80211_CHAN_WIDTH_80P80) {
  44. get_chan_freq_boundary(chandef->center_freq2, bandwidth, &start_freq2, &end_freq2);
  45. ranges_in->band_list[1].start = start_freq2;
  46. ranges_in->band_list[1].end = end_freq2;
  47. ranges_in->num_of_ranges++;
  48. }
  49. }
  50. void ieee80211_add_wbrf(struct ieee80211_local *local, struct cfg80211_chan_def *chandef)
  51. {
  52. struct wbrf_ranges_in_out ranges_in = {0};
  53. struct device *dev;
  54. if (!local->wbrf_supported)
  55. return;
  56. dev = local->hw.wiphy->dev.parent;
  57. get_ranges_from_chandef(chandef, &ranges_in);
  58. acpi_amd_wbrf_add_remove(dev, WBRF_RECORD_ADD, &ranges_in);
  59. }
  60. void ieee80211_remove_wbrf(struct ieee80211_local *local, struct cfg80211_chan_def *chandef)
  61. {
  62. struct wbrf_ranges_in_out ranges_in = {0};
  63. struct device *dev;
  64. if (!local->wbrf_supported)
  65. return;
  66. dev = local->hw.wiphy->dev.parent;
  67. get_ranges_from_chandef(chandef, &ranges_in);
  68. acpi_amd_wbrf_add_remove(dev, WBRF_RECORD_REMOVE, &ranges_in);
  69. }