Due to electrical and mechanical constraints in certain platform designs
there may be likely interference of relatively high-powered harmonics of
the (G-)DDR memory clocks with local radio module frequency bands used
by Wifi 6/6e/7.
To mitigate this, AMD has introduced a mechanism that devices can use to
notify active use of particular frequencies so that other devices can make
relative internal adjustments as necessary to avoid this resonance.
In order for a device to support this, the expected flow for device
driver or subsystems:
Drivers/subsystems contributing frequencies:
1) During probe, check `wbrf_supported_producer` to see if WBRF supported
for the device.
2) If adding frequencies, then call `wbrf_add_exclusion` with the
start and end ranges of the frequencies.
3) If removing frequencies, then call `wbrf_remove_exclusion` with
start and end ranges of the frequencies.
Drivers/subsystems responding to frequencies:
1) During probe, check `wbrf_supported_consumer` to see if WBRF is supported
for the device.
2) Call the `wbrf_register_notifier` to register for notifications of
frequency changes from other devices.
3) Call the `wbrf_retrieve_exclusions` to retrieve the current exclusions
range on receiving a notification and response correspondingly.
Meanwhile a kernel parameter `wbrf` with default setting as "auto" is
introduced to specify what the policy is.
- With `wbrf=on`, the WBRF features will be enabled forcely.
- With `wbrf=off`, the WBRF features will be disabled forcely.
- With `wbrf=auto`, it will be up to the system to do proper checks
to determine the WBRF features should be enabled or not.
Co-developed-by: Mario Limonciello
Signed-off-by: Mario Limonciello
Co-developed-by: Evan Quan
Signed-off-by: Evan Quan
--
v4->v5:
- promote this to be a more generic solution with input argument taking
`struct device` and provide better scalability to support non-ACPI
scenarios(Andrew)
- update the APIs naming and some other minor fixes(Rafael)
v6->v7:
- revised the `struct wbrf_ranges_out` to be naturally aligned(Andrew)
- revised some code comments(Andrew)
---
.../admin-guide/kernel-parameters.txt | 9 +
drivers/base/Makefile | 1 +
drivers/base/wbrf.c | 280 ++
include/linux/wbrf.h | 47 +++
4 files changed, 337 insertions(+)
create mode 100644 drivers/base/wbrf.c
create mode 100644 include/linux/wbrf.h
diff --git a/Documentation/admin-guide/kernel-parameters.txt
b/Documentation/admin-guide/kernel-parameters.txt
index a1457995fd41..21f73a0bbd0b 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -7152,3 +7152,12 @@
xmon commands.
off xmon is disabled.
+ wbrf= [KNL]
+ Format: { on | auto | off }
+ Controls if WBRF features should be enabled or disabled
+ forcely. Default is auto.
+ on Force enable the WBRF features.
+ autoUp to the system to do proper checks to
+ determine the WBRF features should be enabled
+ or not.
+ off Force disable the WBRF features.
diff --git a/drivers/base/Makefile b/drivers/base/Makefile
index 3079bfe53d04..7b3cef898c19 100644
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -26,6 +26,7 @@ obj-$(CONFIG_GENERIC_MSI_IRQ) += platform-msi.o
obj-$(CONFIG_GENERIC_ARCH_TOPOLOGY) += arch_topology.o
obj-$(CONFIG_GENERIC_ARCH_NUMA) += arch_numa.o
obj-$(CONFIG_ACPI) += physical_location.o
+obj-y += wbrf.o
obj-y += test/
diff --git a/drivers/base/wbrf.c b/drivers/base/wbrf.c
new file mode 100644
index ..678f245c12c6
--- /dev/null
+++ b/drivers/base/wbrf.c
@@ -0,0 +1,280 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Wifi Band Exclusion Interface
+ * Copyright (C) 2023 Advanced Micro Devices
+ *
+ */
+
+#include
+
+static BLOCKING_NOTIFIER_HEAD(wbrf_chain_head);
+static DEFINE_MUTEX(wbrf_mutex);
+static enum WBRF_POLICY_MODE {
+ WBRF_POLICY_FORCE_DISABLE,
+ WBRF_POLICY_AUTO,
+ WBRF_POLICY_FORCE_ENABLE,
+} wbrf_policy = WBRF_POLICY_AUTO;
+
+static int __init parse_wbrf_policy_mode(char *p)
+{
+ if (!strncmp(p, "auto", 4))
+ wbrf_policy = WBRF_POLICY_AUTO;
+ else if (!strncmp(p, "on", 2))
+ wbrf_policy = WBRF_POLICY_FORCE_ENABLE;
+ else if (!strncmp(p, "off", 3))
+ wbrf_policy = WBRF_POLICY_FORCE_DISABLE;
+ else
+ return -EINVAL;
+
+ return 0;
+}
+early_param("wbrf", parse_wbrf_policy_mode);
+
+static struct exclusion_range_pool {
+ struct exclusion_range band_list[MAX_NUM_OF_WBRF_RANGES];
+ u64