With WBRF feature supported, as a driver responding to the frequencies,
amdgpu driver is able to do shadow pstate switching to mitigate possible
interference(between its (G-)DDR memory clocks and local radio module
frequency bands used by Wifi 6/6e/7).
Signed-off-by: Evan Quan
Reviewed-by: Mario Limonciello
--
v1->v2:
- update the prompt for feature support(Lijo)
---
drivers/gpu/drm/amd/amdgpu/amdgpu.h | 2 +
drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 17 ++
drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 194 ++
drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 23 +++
drivers/gpu/drm/amd/pm/swsmu/smu_internal.h | 3 +
5 files changed, 239 insertions(+)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
index a3b86b86dc47..2bfc9111ab00 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -247,6 +247,8 @@ extern int amdgpu_sg_display;
extern int amdgpu_user_partt_mode;
+extern int amdgpu_wbrf;
+
#define AMDGPU_VM_MAX_NUM_CTX 4096
#define AMDGPU_SG_THRESHOLD(256*1024*1024)
#define AMDGPU_WAIT_IDLE_TIMEOUT_IN_MS 3000
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
index 0593ef8fe0a6..1c574bd3b60d 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
@@ -195,6 +195,7 @@ int amdgpu_use_xgmi_p2p = 1;
int amdgpu_vcnfw_log;
int amdgpu_sg_display = -1; /* auto */
int amdgpu_user_partt_mode = AMDGPU_AUTO_COMPUTE_PARTITION_MODE;
+int amdgpu_wbrf = -1;
static void amdgpu_drv_delayed_reset_work_handler(struct work_struct *work);
@@ -981,6 +982,22 @@ module_param_named(user_partt_mode,
amdgpu_user_partt_mode, uint, 0444);
module_param(enforce_isolation, bool, 0444);
MODULE_PARM_DESC(enforce_isolation, "enforce process isolation between
graphics and compute . enforce_isolation = on");
+/**
+ * DOC: wbrf (int)
+ * Enable Wifi RFI interference mitigation feature.
+ * Due to electrical and mechanical constraints 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 the possible RFI
interference,
+ * with this feature enabled, PMFW will use either “shadowed P-State” or
“P-State” based
+ * on active list of frequencies in-use (to be avoided) as part of initial
setting or
+ * P-state transition. However, there may be potential performance impact with
this
+ * feature enabled.
+ * (0 = disabled, 1 = enabled, -1 = auto (default setting, will be enabled if
supported))
+ */
+MODULE_PARM_DESC(wbrf,
+ "Enable Wifi RFI interference mitigation (0 = disabled, 1 = enabled, -1
= auto(default)");
+module_param_named(wbrf, amdgpu_wbrf, int, 0444);
+
/* These devices are not supported by amdgpu.
* They are supported by the mach64, r128, radeon drivers
*/
diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
index ce41a8309582..163037bd6d16 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
@@ -1228,6 +1228,173 @@ static int smu_get_thermal_temperature_range(struct
smu_context *smu)
return ret;
}
+/**
+ * smu_wbrf_handle_exclusion_ranges - consume the wbrf exclusion ranges
+ *
+ * @smu: smu_context pointer
+ *
+ * Retrieve the wbrf exclusion ranges and send them to PMFW for proper
handling.
+ * Returns 0 on success, error on failure.
+ */
+static int smu_wbrf_handle_exclusion_ranges(struct smu_context *smu)
+{
+ struct wbrf_ranges_out wbrf_exclusion = {0};
+ struct exclusion_range *wifi_bands = wbrf_exclusion.band_list;
+ struct amdgpu_device *adev = smu->adev;
+ uint64_t start, end;
+ int ret, i, j;
+
+ ret = wbrf_retrieve_exclusions(adev->dev, &wbrf_exclusion);
+ if (ret) {
+ dev_err(adev->dev, "Failed to retrieve exclusion ranges!\n");
+ return ret;
+ }
+
+ /*
+* The exclusion ranges array we got might be filled with holes and
duplicate
+* entries. For example:
+* {(2400, 2500), (0, 0), (6882, 6962), (2400, 2500), (0, 0), (6117,
6189), (0, 0)...}
+* We need to do some sortups to eliminate those holes and duplicate
entries.
+* Expected output: {(2400, 2500), (6117, 6189), (6882, 6962), (0,
0)...}
+*/
+ for (i = 0; i < MAX_NUM_OF_WBRF_RANGES; i++) {
+ start = wifi_bands[i].start;
+ end = wifi_bands[i].end;
+
+ /* get the last valid entry to fill the intermediate hole */
+ if (!start && !end) {
+ for (j = MAX_NUM_OF_WBRF_RANGES - 1; j > i; j--)
+ if (wifi_bands[j].start &&
+ wifi_bands[j].end)
+ bre