2023-10-17 02:55:46

by Ma Jun

[permalink] [raw]
Subject: [PATCH v12 0/9] Enable Wifi RFI interference mitigation feature support

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 possible RFI interference we introuduced WBRF(Wifi Band RFI mitigation Feature).
Producers can advertise the frequencies in use and consumers can use this information
to avoid using these frequencies for sensitive features.

The whole patch set is based on Linux 6.5.0. With some brief introductions
as below:
Patch1: Document about WBRF
Patch2: Core functionality setup for WBRF feature support
Patch3 - 4: Bring WBRF support to wifi subsystem.
Patch5 - 9: Bring WBRF support to AMD graphics driver.

Evan Quan (7):
cfg80211: expose nl80211_chan_width_to_mhz for wide sharing
wifi: mac80211: Add support for WBRF features
drm/amd/pm: update driver_if and ppsmc headers for coming wbrf feature
drm/amd/pm: setup the framework to support Wifi RFI mitigation feature
drm/amd/pm: add flood detection for wbrf events
drm/amd/pm: enable Wifi RFI mitigation feature support for SMU13.0.0
drm/amd/pm: enable Wifi RFI mitigation feature support for SMU13.0.7

Ma Jun (2):
Documentation/driver-api: Add document about WBRF mechanism
platform/x86/amd: Add support for AMD ACPI based Wifi band RFI
mitigation feature

Documentation/driver-api/wbrf.rst | 71 +++
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 | 214 +++++++++
drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 33 ++
.../inc/pmfw_if/smu13_driver_if_v13_0_0.h | 14 +-
.../inc/pmfw_if/smu13_driver_if_v13_0_7.h | 14 +-
.../pm/swsmu/inc/pmfw_if/smu_v13_0_0_ppsmc.h | 3 +-
.../pm/swsmu/inc/pmfw_if/smu_v13_0_7_ppsmc.h | 3 +-
drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h | 3 +-
drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h | 3 +
.../gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c | 9 +
.../drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c | 60 +++
.../drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c | 59 +++
drivers/gpu/drm/amd/pm/swsmu/smu_internal.h | 3 +
drivers/platform/x86/amd/Kconfig | 15 +
drivers/platform/x86/amd/Makefile | 1 +
drivers/platform/x86/amd/wbrf.c | 422 ++++++++++++++++++
include/linux/acpi_amd_wbrf.h | 101 +++++
include/linux/ieee80211.h | 1 +
include/net/cfg80211.h | 8 +
net/mac80211/Makefile | 2 +
net/mac80211/chan.c | 9 +
net/mac80211/ieee80211_i.h | 9 +
net/mac80211/main.c | 2 +
net/mac80211/wbrf.c | 105 +++++
net/wireless/chan.c | 3 +-
27 files changed, 1180 insertions(+), 6 deletions(-)
create mode 100644 Documentation/driver-api/wbrf.rst
create mode 100644 drivers/platform/x86/amd/wbrf.c
create mode 100644 include/linux/acpi_amd_wbrf.h
create mode 100644 net/mac80211/wbrf.c

--
2.34.1


2023-10-17 02:56:18

by Ma Jun

[permalink] [raw]
Subject: [PATCH v12 5/9] drm/amd/pm: update driver_if and ppsmc headers for coming wbrf feature

From: Evan Quan <[email protected]>

Add those data structures to support Wifi RFI mitigation feature.

Signed-off-by: Evan Quan <[email protected]>
Reviewed-by: Mario Limonciello <[email protected]>
Signed-off-by: Ma Jun <[email protected]>
---
.../pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_0.h | 14 +++++++++++++-
.../pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_7.h | 14 +++++++++++++-
.../amd/pm/swsmu/inc/pmfw_if/smu_v13_0_0_ppsmc.h | 3 ++-
.../amd/pm/swsmu/inc/pmfw_if/smu_v13_0_7_ppsmc.h | 3 ++-
4 files changed, 30 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_0.h
index 9dd1ed5b8940..e481407b6584 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_0.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_0.h
@@ -391,6 +391,17 @@ typedef struct {
EccInfo_t EccInfo[24];
} EccInfoTable_t;

+typedef struct {
+ uint16_t LowFreq;
+ uint16_t HighFreq;
+} WifiOneBand_t;
+
+typedef struct {
+ uint32_t WifiBandEntryNum;
+ WifiOneBand_t WifiBandEntry[11];
+ uint32_t MmHubPadding[8];
+} WifiBandEntryTable_t;
+
//D3HOT sequences
typedef enum {
BACO_SEQUENCE,
@@ -1615,7 +1626,8 @@ typedef struct {
#define TABLE_I2C_COMMANDS 9
#define TABLE_DRIVER_INFO 10
#define TABLE_ECCINFO 11
-#define TABLE_COUNT 12
+#define TABLE_WIFIBAND 12
+#define TABLE_COUNT 13

//IH Interupt ID
#define IH_INTERRUPT_ID_TO_DRIVER 0xFE
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_7.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_7.h
index 62b7c0daff68..1530ca002c6c 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_7.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_7.h
@@ -392,6 +392,17 @@ typedef struct {
EccInfo_t EccInfo[24];
} EccInfoTable_t;

+typedef struct {
+ uint16_t LowFreq;
+ uint16_t HighFreq;
+} WifiOneBand_t;
+
+typedef struct {
+ uint32_t WifiBandEntryNum;
+ WifiOneBand_t WifiBandEntry[11];
+ uint32_t MmHubPadding[8];
+} WifiBandEntryTable_t;
+
//D3HOT sequences
typedef enum {
BACO_SEQUENCE,
@@ -1605,7 +1616,8 @@ typedef struct {
#define TABLE_I2C_COMMANDS 9
#define TABLE_DRIVER_INFO 10
#define TABLE_ECCINFO 11
-#define TABLE_COUNT 12
+#define TABLE_WIFIBAND 12
+#define TABLE_COUNT 13

//IH Interupt ID
#define IH_INTERRUPT_ID_TO_DRIVER 0xFE
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_0_ppsmc.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_0_ppsmc.h
index 10cff75b44d5..c98cc32d11bd 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_0_ppsmc.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_0_ppsmc.h
@@ -138,7 +138,8 @@
#define PPSMC_MSG_SetBadMemoryPagesRetiredFlagsPerChannel 0x4A
#define PPSMC_MSG_SetPriorityDeltaGain 0x4B
#define PPSMC_MSG_AllowIHHostInterrupt 0x4C
-#define PPSMC_Message_Count 0x4D
+#define PPSMC_MSG_EnableUCLKShadow 0x51
+#define PPSMC_Message_Count 0x52

//Debug Dump Message
#define DEBUGSMC_MSG_TestMessage 0x1
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_7_ppsmc.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_7_ppsmc.h
index 6aaefca9b595..a6bf9cdd130e 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_7_ppsmc.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_7_ppsmc.h
@@ -134,6 +134,7 @@
#define PPSMC_MSG_SetBadMemoryPagesRetiredFlagsPerChannel 0x4A
#define PPSMC_MSG_SetPriorityDeltaGain 0x4B
#define PPSMC_MSG_AllowIHHostInterrupt 0x4C
-#define PPSMC_Message_Count 0x4D
+#define PPSMC_MSG_EnableUCLKShadow 0x51
+#define PPSMC_Message_Count 0x52

#endif
--
2.34.1

2023-10-17 02:56:23

by Ma Jun

[permalink] [raw]
Subject: [PATCH v12 6/9] drm/amd/pm: setup the framework to support Wifi RFI mitigation feature

From: Evan Quan <[email protected]>

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 <[email protected]>
Reviewed-by: Mario Limonciello <[email protected]>
Signed-off-by: Ma Jun <[email protected]>
--
v1->v2:
- update the prompt for feature support(Lijo)
v8->v9:
- update parameter document for smu_wbrf_event_handler(Simon)
v9->v10:
v10->v11:
- correct the logics for wbrf range sorting(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 | 195 ++++++++++++++++++
drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 23 +++
drivers/gpu/drm/amd/pm/swsmu/smu_internal.h | 3 +
5 files changed, 240 insertions(+)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
index 6dc950c1b689..11a19384df56 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 222af2fae745..d52cd7ed2868 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
@@ -1228,6 +1228,174 @@ 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_in_out wbrf_exclusion = {0};
+ struct freq_band_range *wifi_bands = wbrf_exclusion.band_list;
+ struct amdgpu_device *adev = smu->adev;
+ uint32_t num_of_wbrf_ranges = MAX_NUM_OF_WBRF_RANGES;
+ uint64_t start, end;
+ int ret, i, j;
+
+ ret = amd_wbrf_retrieve_freq_band(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 < 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 = num_of_wbrf_ranges - 1; j > i; j--)
+ if (wifi_bands[j].start &&
+ wifi_bands[j].end)
+ break;
+
+ /* no valid entry left */
+ if (j <= i)
+ break;
+
+ start = wifi_bands[i].start = wifi_bands[j].start;
+ end = wifi_bands[i].end = wifi_bands[j].end;
+ wifi_bands[j].start = 0;
+ wifi_bands[j].end = 0;
+ num_of_wbrf_ranges = j;
+ }
+
+ /* eliminate duplicate entries */
+ for (j = i + 1; j < num_of_wbrf_ranges; j++) {
+ if ((wifi_bands[j].start == start) &&
+ (wifi_bands[j].end == end)) {
+ wifi_bands[j].start = 0;
+ wifi_bands[j].end = 0;
+ }
+ }
+ }
+
+ /* Send the sorted wifi_bands to PMFW */
+ ret = smu_set_wbrf_exclusion_ranges(smu, wifi_bands);
+ /* Give it another chance */
+ if (unlikely(ret == -EBUSY)) {
+ mdelay(5);
+ ret = smu_set_wbrf_exclusion_ranges(smu, wifi_bands);
+ }
+
+ return ret;
+}
+
+/**
+ * smu_wbrf_event_handler - handle notify events
+ *
+ * @nb: notifier block
+ * @action: event type
+ * @_arg: event data
+ *
+ * Calls relevant amdgpu function in response to wbrf event
+ * notification from kernel.
+ */
+static int smu_wbrf_event_handler(struct notifier_block *nb,
+ unsigned long action, void *_arg)
+{
+ struct smu_context *smu = container_of(nb, struct smu_context,
+ wbrf_notifier);
+
+ switch (action) {
+ case WBRF_CHANGED:
+ smu_wbrf_handle_exclusion_ranges(smu);
+ break;
+ default:
+ return NOTIFY_DONE;
+ };
+
+ return NOTIFY_OK;
+}
+
+/**
+ * smu_wbrf_support_check - check wbrf support
+ *
+ * @smu: smu_context pointer
+ *
+ * Verifies the ACPI interface whether wbrf is supported.
+ */
+static void smu_wbrf_support_check(struct smu_context *smu)
+{
+ struct amdgpu_device *adev = smu->adev;
+
+ smu->wbrf_supported = smu_is_asic_wbrf_supported(smu) &&
+ !!amdgpu_wbrf &&
+ acpi_amd_wbrf_supported_consumer(adev->dev);
+
+ if (smu->wbrf_supported)
+ dev_info(adev->dev, "RF interference mitigation is supported\n");
+}
+
+/**
+ * smu_wbrf_init - init driver wbrf support
+ *
+ * @smu: smu_context pointer
+ *
+ * Verifies the AMD ACPI interfaces and registers with the wbrf
+ * notifier chain if wbrf feature is supported.
+ * Returns 0 on success, error on failure.
+ */
+static int smu_wbrf_init(struct smu_context *smu)
+{
+ struct amdgpu_device *adev = smu->adev;
+ int ret;
+
+ if (!smu->wbrf_supported)
+ return 0;
+
+ smu->wbrf_notifier.notifier_call = smu_wbrf_event_handler;
+ ret = amd_wbrf_register_notifier(&smu->wbrf_notifier);
+ if (ret)
+ return ret;
+
+ /*
+ * Some wifiband exclusion ranges may be already there
+ * before our driver loaded. To make sure our driver
+ * is awared of those exclusion ranges.
+ */
+ ret = smu_wbrf_handle_exclusion_ranges(smu);
+ if (ret)
+ dev_err(adev->dev, "Failed to handle wbrf exclusion ranges\n");
+
+ return ret;
+}
+
+/**
+ * smu_wbrf_fini - tear down driver wbrf support
+ *
+ * @smu: smu_context pointer
+ *
+ * Unregisters with the wbrf notifier chain.
+ */
+static void smu_wbrf_fini(struct smu_context *smu)
+{
+ if (!smu->wbrf_supported)
+ return;
+
+ amd_wbrf_unregister_notifier(&smu->wbrf_notifier);
+}
+
static int smu_smc_hw_setup(struct smu_context *smu)
{
struct smu_feature *feature = &smu->smu_feature;
@@ -1320,6 +1488,15 @@ static int smu_smc_hw_setup(struct smu_context *smu)
if (ret)
return ret;

+ /* Enable UclkShadow on wbrf supported */
+ if (smu->wbrf_supported) {
+ ret = smu_enable_uclk_shadow(smu, true);
+ if (ret) {
+ dev_err(adev->dev, "Failed to enable UclkShadow feature to support wbrf!\n");
+ return ret;
+ }
+ }
+
/*
* With SCPM enabled, these actions(and relevant messages) are
* not needed and permitted.
@@ -1416,6 +1593,15 @@ static int smu_smc_hw_setup(struct smu_context *smu)
*/
ret = smu_set_min_dcef_deep_sleep(smu,
smu->smu_table.boot_values.dcefclk / 100);
+ if (ret) {
+ dev_err(adev->dev, "Error setting min deepsleep dcefclk\n");
+ return ret;
+ }
+
+ /* Init wbrf support. Properly setup the notifier */
+ ret = smu_wbrf_init(smu);
+ if (ret)
+ dev_err(adev->dev, "Error during wbrf init call\n");

return ret;
}
@@ -1471,6 +1657,13 @@ static int smu_hw_init(void *handle)
return ret;
}

+ /*
+ * Check whether wbrf is supported. This needs to be done
+ * before SMU setup starts since part of SMU configuration
+ * relies on this.
+ */
+ smu_wbrf_support_check(smu);
+
if (smu->is_apu) {
ret = smu_set_gfx_imu_enable(smu);
if (ret)
@@ -1623,6 +1816,8 @@ static int smu_smc_hw_cleanup(struct smu_context *smu)
struct amdgpu_device *adev = smu->adev;
int ret = 0;

+ smu_wbrf_fini(smu);
+
cancel_work_sync(&smu->throttling_logging_work);
cancel_work_sync(&smu->interrupt_work);

diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
index 6e2069dcb6b9..39c1620d68c9 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
@@ -22,6 +22,8 @@
#ifndef __AMDGPU_SMU_H__
#define __AMDGPU_SMU_H__

+#include <linux/acpi_amd_wbrf.h>
+
#include "amdgpu.h"
#include "kgd_pp_interface.h"
#include "dm_pp_interface.h"
@@ -575,6 +577,10 @@ struct smu_context
u32 debug_resp_reg;

struct delayed_work swctf_delayed_work;
+
+ /* data structures for wbrf feature support */
+ bool wbrf_supported;
+ struct notifier_block wbrf_notifier;
};

struct i2c_adapter;
@@ -1356,6 +1362,23 @@ struct pptable_funcs {
* @init_pptable_microcode: Prepare the pptable microcode to upload via PSP
*/
int (*init_pptable_microcode)(struct smu_context *smu);
+
+ /**
+ * @is_asic_wbrf_supported: check whether PMFW supports the wbrf feature
+ */
+ bool (*is_asic_wbrf_supported)(struct smu_context *smu);
+
+ /**
+ * @enable_uclk_shadow: Enable the uclk shadow feature on wbrf supported
+ */
+ int (*enable_uclk_shadow)(struct smu_context *smu,
+ bool enablement);
+
+ /**
+ * @set_wbrf_exclusion_ranges: notify SMU the wifi bands occupied
+ */
+ int (*set_wbrf_exclusion_ranges)(struct smu_context *smu,
+ struct freq_band_range *exclusion_ranges);
};

typedef enum {
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_internal.h b/drivers/gpu/drm/amd/pm/swsmu/smu_internal.h
index ceb13c838067..aa64c7cdf3c9 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu_internal.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu_internal.h
@@ -97,6 +97,9 @@
#define smu_get_default_config_table_settings(smu, config_table) smu_ppt_funcs(get_default_config_table_settings, -EOPNOTSUPP, smu, config_table)
#define smu_set_config_table(smu, config_table) smu_ppt_funcs(set_config_table, -EOPNOTSUPP, smu, config_table)
#define smu_init_pptable_microcode(smu) smu_ppt_funcs(init_pptable_microcode, 0, smu)
+#define smu_is_asic_wbrf_supported(smu) smu_ppt_funcs(is_asic_wbrf_supported, false, smu)
+#define smu_enable_uclk_shadow(smu, enablement) smu_ppt_funcs(enable_uclk_shadow, 0, smu, enablement)
+#define smu_set_wbrf_exclusion_ranges(smu, freq_band_range) smu_ppt_funcs(set_wbrf_exclusion_ranges, -EOPNOTSUPP, smu, freq_band_range)

#endif
#endif
--
2.34.1

2023-10-17 02:56:32

by Ma Jun

[permalink] [raw]
Subject: [PATCH v12 3/9] cfg80211: expose nl80211_chan_width_to_mhz for wide sharing

From: Evan Quan <[email protected]>

The newly added WBRF feature needs this interface for channel
width calculation.

Signed-off-by: Ma Jun <[email protected]>
Signed-off-by: Evan Quan <[email protected]>

--
v8->v9:
- correct typo(Mhz -> MHz) (Johnson)
---
include/net/cfg80211.h | 8 ++++++++
net/wireless/chan.c | 3 ++-
2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index d6fa7c8767ad..026d91083f37 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -923,6 +923,14 @@ const struct cfg80211_chan_def *
cfg80211_chandef_compatible(const struct cfg80211_chan_def *chandef1,
const struct cfg80211_chan_def *chandef2);

+/**
+ * nl80211_chan_width_to_mhz - get the channel width in MHz
+ * @chan_width: the channel width from &enum nl80211_chan_width
+ * Return: channel width in MHz if the chan_width from &enum nl80211_chan_width
+ * is valid. -1 otherwise.
+ */
+int nl80211_chan_width_to_mhz(enum nl80211_chan_width chan_width);
+
/**
* cfg80211_chandef_valid - check if a channel definition is valid
* @chandef: the channel definition to check
diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index 0b7e81db383d..227db04eac42 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -141,7 +141,7 @@ static bool cfg80211_edmg_chandef_valid(const struct cfg80211_chan_def *chandef)
return true;
}

-static int nl80211_chan_width_to_mhz(enum nl80211_chan_width chan_width)
+int nl80211_chan_width_to_mhz(enum nl80211_chan_width chan_width)
{
int mhz;

@@ -190,6 +190,7 @@ static int nl80211_chan_width_to_mhz(enum nl80211_chan_width chan_width)
}
return mhz;
}
+EXPORT_SYMBOL(nl80211_chan_width_to_mhz);

static int cfg80211_chandef_get_width(const struct cfg80211_chan_def *c)
{
--
2.34.1

2023-10-17 02:56:33

by Ma Jun

[permalink] [raw]
Subject: [PATCH v12 4/9] wifi: mac80211: Add support for WBRF features

From: Evan Quan <[email protected]>

To support the WBRF mechanism, Wifi adapters utilized in the system must
register the frequencies in use(or unregister those frequencies no longer
used) via the dedicated calls. So that, other drivers responding to the
frequencies can take proper actions to mitigate possible interference.

Co-developed-by: Mario Limonciello <[email protected]>
Signed-off-by: Mario Limonciello <[email protected]>
Co-developed-by: Evan Quan <[email protected]>
Signed-off-by: Evan Quan <[email protected]>
Signed-off-by: Ma Jun <[email protected]>
--
v1->v2:
- place the new added member(`wbrf_supported`) in
ieee80211_local(Johannes)
- handle chandefs change scenario properly(Johannes)
- some minor fixes around code sharing and possible invalid input
checks(Johannes)
v2->v3:
- drop unnecessary input checks and intermediate APIs(Mario)
- Separate some mac80211 common code(Mario, Johannes)
v3->v4:
- some minor fixes around return values(Johannes)
v9->v10:
- get ranges_in->num_of_ranges set and passed in(Johannes)
v12:
- use acpi_amd_wbrf_add_remove to replace the acpi_amd_wbrf_add_exclusion
acpi_amd_wbrf_remove_exclusion
---
include/linux/ieee80211.h | 1 +
net/mac80211/Makefile | 2 +
net/mac80211/chan.c | 9 ++++
net/mac80211/ieee80211_i.h | 9 ++++
net/mac80211/main.c | 2 +
net/mac80211/wbrf.c | 105 +++++++++++++++++++++++++++++++++++++
6 files changed, 128 insertions(+)
create mode 100644 net/mac80211/wbrf.c

diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 4b998090898e..f995d06da87f 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -4335,6 +4335,7 @@ static inline int ieee80211_get_tdls_action(struct sk_buff *skb, u32 hdr_size)
/* convert frequencies */
#define MHZ_TO_KHZ(freq) ((freq) * 1000)
#define KHZ_TO_MHZ(freq) ((freq) / 1000)
+#define KHZ_TO_HZ(freq) ((freq) * 1000)
#define PR_KHZ(f) KHZ_TO_MHZ(f), f % 1000
#define KHZ_F "%d.%03d"

diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile
index b8de44da1fb8..d46c36f55fd3 100644
--- a/net/mac80211/Makefile
+++ b/net/mac80211/Makefile
@@ -65,4 +65,6 @@ rc80211_minstrel-$(CONFIG_MAC80211_DEBUGFS) += \

mac80211-$(CONFIG_MAC80211_RC_MINSTREL) += $(rc80211_minstrel-y)

+mac80211-y += wbrf.o
+
ccflags-y += -DDEBUG
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 68952752b599..458469c224ae 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -506,11 +506,16 @@ static void _ieee80211_change_chanctx(struct ieee80211_local *local,

WARN_ON(!cfg80211_chandef_compatible(&ctx->conf.def, chandef));

+ ieee80211_remove_wbrf(local, &ctx->conf.def);
+
ctx->conf.def = *chandef;

/* check if min chanctx also changed */
changed = IEEE80211_CHANCTX_CHANGE_WIDTH |
_ieee80211_recalc_chanctx_min_def(local, ctx, rsvd_for);
+
+ ieee80211_add_wbrf(local, &ctx->conf.def);
+
drv_change_chanctx(local, ctx, changed);

if (!local->use_chanctx) {
@@ -668,6 +673,8 @@ static int ieee80211_add_chanctx(struct ieee80211_local *local,
lockdep_assert_held(&local->mtx);
lockdep_assert_held(&local->chanctx_mtx);

+ ieee80211_add_wbrf(local, &ctx->conf.def);
+
if (!local->use_chanctx)
local->hw.conf.radar_enabled = ctx->conf.radar_enabled;

@@ -748,6 +755,8 @@ static void ieee80211_del_chanctx(struct ieee80211_local *local,
}

ieee80211_recalc_idle(local);
+
+ ieee80211_remove_wbrf(local, &ctx->conf.def);
}

static void ieee80211_free_chanctx(struct ieee80211_local *local,
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 91633a0b723e..719f2c892132 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1600,6 +1600,8 @@ struct ieee80211_local {

/* extended capabilities provided by mac80211 */
u8 ext_capa[8];
+
+ bool wbrf_supported;
};

static inline struct ieee80211_sub_if_data *
@@ -2638,4 +2640,11 @@ ieee80211_eht_cap_ie_to_sta_eht_cap(struct ieee80211_sub_if_data *sdata,
const struct ieee80211_eht_cap_elem *eht_cap_ie_elem,
u8 eht_cap_len,
struct link_sta_info *link_sta);
+
+void ieee80211_check_wbrf_support(struct ieee80211_local *local);
+void ieee80211_add_wbrf(struct ieee80211_local *local,
+ struct cfg80211_chan_def *chandef);
+void ieee80211_remove_wbrf(struct ieee80211_local *local,
+ struct cfg80211_chan_def *chandef);
+
#endif /* IEEE80211_I_H */
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 24315d7b3126..b20bdaac84db 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -1396,6 +1396,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
debugfs_hw_add(local);
rate_control_add_debugfs(local);

+ ieee80211_check_wbrf_support(local);
+
rtnl_lock();
wiphy_lock(hw->wiphy);

diff --git a/net/mac80211/wbrf.c b/net/mac80211/wbrf.c
new file mode 100644
index 000000000000..7329f554c7af
--- /dev/null
+++ b/net/mac80211/wbrf.c
@@ -0,0 +1,105 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Wifi Band Exclusion Interface for WLAN
+ * Copyright (C) 2023 Advanced Micro Devices
+ *
+ */
+
+#include <linux/acpi_amd_wbrf.h>
+#include <net/cfg80211.h>
+#include "ieee80211_i.h"
+
+void ieee80211_check_wbrf_support(struct ieee80211_local *local)
+{
+ struct wiphy *wiphy = local->hw.wiphy;
+ struct device *dev;
+
+ if (!wiphy)
+ return;
+
+ dev = wiphy->dev.parent;
+ if (!dev)
+ return;
+
+ local->wbrf_supported = acpi_amd_wbrf_supported_producer(dev);
+ dev_dbg(dev, "WBRF is %s supported\n",
+ local->wbrf_supported ? "" : "not");
+}
+
+static void get_chan_freq_boundary(u32 center_freq,
+ u32 bandwidth,
+ u64 *start,
+ u64 *end)
+{
+ bandwidth = MHZ_TO_KHZ(bandwidth);
+ center_freq = MHZ_TO_KHZ(center_freq);
+
+ *start = center_freq - bandwidth / 2;
+ *end = center_freq + bandwidth / 2;
+
+ /* Frequency in HZ is expected */
+ *start = KHZ_TO_HZ(*start);
+ *end = KHZ_TO_HZ(*end);
+}
+
+static void get_ranges_from_chandef(struct cfg80211_chan_def *chandef,
+ struct wbrf_ranges_in_out *ranges_in)
+{
+ u64 start_freq1, end_freq1;
+ u64 start_freq2, end_freq2;
+ int bandwidth;
+
+ bandwidth = nl80211_chan_width_to_mhz(chandef->width);
+
+ get_chan_freq_boundary(chandef->center_freq1,
+ bandwidth,
+ &start_freq1,
+ &end_freq1);
+
+ ranges_in->band_list[0].start = start_freq1;
+ ranges_in->band_list[0].end = end_freq1;
+ ranges_in->num_of_ranges = 1;
+
+ if (chandef->width == NL80211_CHAN_WIDTH_80P80) {
+ get_chan_freq_boundary(chandef->center_freq2,
+ bandwidth,
+ &start_freq2,
+ &end_freq2);
+
+ ranges_in->band_list[1].start = start_freq2;
+ ranges_in->band_list[1].end = end_freq2;
+ ranges_in->num_of_ranges++;
+ }
+}
+
+void ieee80211_add_wbrf(struct ieee80211_local *local,
+ struct cfg80211_chan_def *chandef)
+{
+ struct wbrf_ranges_in_out ranges_in = {0};
+ struct device *dev;
+
+ if (!local->wbrf_supported)
+ return;
+
+ dev = local->hw.wiphy->dev.parent;
+
+ get_ranges_from_chandef(chandef, &ranges_in);
+
+ acpi_amd_wbrf_add_remove(dev, WBRF_RECORD_ADD, &ranges_in);
+}
+
+void ieee80211_remove_wbrf(struct ieee80211_local *local,
+ struct cfg80211_chan_def *chandef)
+{
+ struct wbrf_ranges_in_out ranges_in = {0};
+ struct device *dev;
+
+ if (!local->wbrf_supported)
+ return;
+
+ dev = local->hw.wiphy->dev.parent;
+
+ get_ranges_from_chandef(chandef, &ranges_in);
+
+ acpi_amd_wbrf_add_remove(dev, WBRF_RECORD_REMOVE, &ranges_in);
+}
--
2.34.1

2023-10-17 02:56:35

by Ma Jun

[permalink] [raw]
Subject: [PATCH v12 7/9] drm/amd/pm: add flood detection for wbrf events

From: Evan Quan <[email protected]>

To protect PMFW from being overloaded.

Signed-off-by: Evan Quan <[email protected]>
Reviewed-by: Mario Limonciello <[email protected]>
Signed-off-by: Ma Jun <[email protected]>
---
drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 31 +++++++++++++++----
drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 7 +++++
2 files changed, 32 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
index d52cd7ed2868..b470f7b7c91d 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
@@ -1319,7 +1319,8 @@ static int smu_wbrf_event_handler(struct notifier_block *nb,

switch (action) {
case WBRF_CHANGED:
- smu_wbrf_handle_exclusion_ranges(smu);
+ schedule_delayed_work(&smu->wbrf_delayed_work,
+ msecs_to_jiffies(SMU_WBRF_EVENT_HANDLING_PACE));
break;
default:
return NOTIFY_DONE;
@@ -1328,6 +1329,21 @@ static int smu_wbrf_event_handler(struct notifier_block *nb,
return NOTIFY_OK;
}

+/**
+ * smu_wbrf_delayed_work_handler - callback on delayed work timer expired
+ *
+ * @work: struct work_struct pointer
+ *
+ * Flood is over and driver will consume the latest exclusion ranges.
+ */
+static void smu_wbrf_delayed_work_handler(struct work_struct *work)
+{
+ struct smu_context *smu =
+ container_of(work, struct smu_context, wbrf_delayed_work.work);
+
+ smu_wbrf_handle_exclusion_ranges(smu);
+}
+
/**
* smu_wbrf_support_check - check wbrf support
*
@@ -1358,12 +1374,14 @@ static void smu_wbrf_support_check(struct smu_context *smu)
*/
static int smu_wbrf_init(struct smu_context *smu)
{
- struct amdgpu_device *adev = smu->adev;
int ret;

if (!smu->wbrf_supported)
return 0;

+ INIT_DELAYED_WORK(&smu->wbrf_delayed_work,
+ smu_wbrf_delayed_work_handler);
+
smu->wbrf_notifier.notifier_call = smu_wbrf_event_handler;
ret = amd_wbrf_register_notifier(&smu->wbrf_notifier);
if (ret)
@@ -1374,11 +1392,10 @@ static int smu_wbrf_init(struct smu_context *smu)
* before our driver loaded. To make sure our driver
* is awared of those exclusion ranges.
*/
- ret = smu_wbrf_handle_exclusion_ranges(smu);
- if (ret)
- dev_err(adev->dev, "Failed to handle wbrf exclusion ranges\n");
+ schedule_delayed_work(&smu->wbrf_delayed_work,
+ msecs_to_jiffies(SMU_WBRF_EVENT_HANDLING_PACE));

- return ret;
+ return 0;
}

/**
@@ -1394,6 +1411,8 @@ static void smu_wbrf_fini(struct smu_context *smu)
return;

amd_wbrf_unregister_notifier(&smu->wbrf_notifier);
+
+ cancel_delayed_work_sync(&smu->wbrf_delayed_work);
}

static int smu_smc_hw_setup(struct smu_context *smu)
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
index 39c1620d68c9..d396a18fe0f3 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
@@ -480,6 +480,12 @@ struct stb_context {

#define WORKLOAD_POLICY_MAX 7

+/*
+ * Configure wbrf event handling pace as there can be only one
+ * event processed every SMU_WBRF_EVENT_HANDLING_PACE ms.
+ */
+#define SMU_WBRF_EVENT_HANDLING_PACE 10
+
struct smu_context
{
struct amdgpu_device *adev;
@@ -581,6 +587,7 @@ struct smu_context
/* data structures for wbrf feature support */
bool wbrf_supported;
struct notifier_block wbrf_notifier;
+ struct delayed_work wbrf_delayed_work;
};

struct i2c_adapter;
--
2.34.1

2023-10-17 02:56:47

by Ma Jun

[permalink] [raw]
Subject: [PATCH v12 8/9] drm/amd/pm: enable Wifi RFI mitigation feature support for SMU13.0.0

From: Evan Quan <[email protected]>

Fulfill the SMU13.0.0 support for Wifi RFI mitigation feature.

Signed-off-by: Evan Quan <[email protected]>
Reviewed-by: Mario Limonciello <[email protected]>
Signed-off-by: Ma Jun <[email protected]>
--
v10->v11:
- downgrade the prompt level on message failure(Lijo)
---
drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 3 +
drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h | 3 +-
drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h | 3 +
.../gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c | 9 +++
.../drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c | 60 +++++++++++++++++++
5 files changed, 77 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
index d396a18fe0f3..6f88c352b53e 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
@@ -325,6 +325,7 @@ enum smu_table_id
SMU_TABLE_PACE,
SMU_TABLE_ECCINFO,
SMU_TABLE_COMBO_PPTABLE,
+ SMU_TABLE_WIFIBAND,
SMU_TABLE_COUNT,
};

@@ -1501,6 +1502,8 @@ enum smu_baco_seq {
__dst_size); \
})

+#define HZ_IN_MHZ 1000000U
+
#if !defined(SWSMU_CODE_LAYER_L2) && !defined(SWSMU_CODE_LAYER_L3) && !defined(SWSMU_CODE_LAYER_L4)
int smu_get_power_limit(void *handle,
uint32_t *limit,
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h
index 297b70b9388f..5bbb60289a79 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h
@@ -245,7 +245,8 @@
__SMU_DUMMY_MAP(AllowGpo), \
__SMU_DUMMY_MAP(Mode2Reset), \
__SMU_DUMMY_MAP(RequestI2cTransaction), \
- __SMU_DUMMY_MAP(GetMetricsTable),
+ __SMU_DUMMY_MAP(GetMetricsTable), \
+ __SMU_DUMMY_MAP(EnableUCLKShadow),

#undef __SMU_DUMMY_MAP
#define __SMU_DUMMY_MAP(type) SMU_MSG_##type
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h
index 355c156d871a..dd70b56aa71e 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h
@@ -299,5 +299,8 @@ int smu_v13_0_update_pcie_parameters(struct smu_context *smu,
uint32_t pcie_gen_cap,
uint32_t pcie_width_cap);

+int smu_v13_0_enable_uclk_shadow(struct smu_context *smu,
+ bool enablement);
+
#endif
#endif
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c
index 9b62b45ebb7f..6a5cb582aa92 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c
@@ -2472,3 +2472,12 @@ int smu_v13_0_update_pcie_parameters(struct smu_context *smu,

return 0;
}
+
+int smu_v13_0_enable_uclk_shadow(struct smu_context *smu,
+ bool enablement)
+{
+ return smu_cmn_send_smc_msg_with_param(smu,
+ SMU_MSG_EnableUCLKShadow,
+ enablement,
+ NULL);
+}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
index 0fb6be11a0cc..08ab19559c7b 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
@@ -154,6 +154,7 @@ static struct cmn2asic_msg_mapping smu_v13_0_0_message_map[SMU_MSG_MAX_COUNT] =
MSG_MAP(AllowGpo, PPSMC_MSG_SetGpoAllow, 0),
MSG_MAP(AllowIHHostInterrupt, PPSMC_MSG_AllowIHHostInterrupt, 0),
MSG_MAP(ReenableAcDcInterrupt, PPSMC_MSG_ReenableAcDcInterrupt, 0),
+ MSG_MAP(EnableUCLKShadow, PPSMC_MSG_EnableUCLKShadow, 0),
};

static struct cmn2asic_mapping smu_v13_0_0_clk_map[SMU_CLK_COUNT] = {
@@ -237,6 +238,7 @@ static struct cmn2asic_mapping smu_v13_0_0_table_map[SMU_TABLE_COUNT] = {
TAB_MAP(I2C_COMMANDS),
TAB_MAP(ECCINFO),
TAB_MAP(OVERDRIVE),
+ TAB_MAP(WIFIBAND),
};

static struct cmn2asic_mapping smu_v13_0_0_pwr_src_map[SMU_POWER_SOURCE_COUNT] = {
@@ -496,6 +498,9 @@ static int smu_v13_0_0_tables_init(struct smu_context *smu)
PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
SMU_TABLE_INIT(tables, SMU_TABLE_ECCINFO, sizeof(EccInfoTable_t),
PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
+ SMU_TABLE_INIT(tables, SMU_TABLE_WIFIBAND,
+ sizeof(WifiBandEntryTable_t), PAGE_SIZE,
+ AMDGPU_GEM_DOMAIN_VRAM);

smu_table->metrics_table = kzalloc(sizeof(SmuMetricsExternal_t), GFP_KERNEL);
if (!smu_table->metrics_table)
@@ -2607,6 +2612,58 @@ static ssize_t smu_v13_0_0_get_ecc_info(struct smu_context *smu,
return ret;
}

+static bool smu_v13_0_0_wbrf_support_check(struct smu_context *smu)
+{
+ struct amdgpu_device *adev = smu->adev;
+
+ switch (adev->ip_versions[MP1_HWIP][0]) {
+ case IP_VERSION(13, 0, 0):
+ return smu->smc_fw_version >= 0x004e6300;
+ case IP_VERSION(13, 0, 10):
+ return smu->smc_fw_version >= 0x00503300;
+ default:
+ return false;
+ }
+}
+
+static int smu_v13_0_0_set_wbrf_exclusion_ranges(struct smu_context *smu,
+ struct freq_band_range *exclusion_ranges)
+{
+ WifiBandEntryTable_t wifi_bands;
+ int valid_entries = 0;
+ int ret, i;
+
+ memset(&wifi_bands, 0, sizeof(wifi_bands));
+ for (i = 0; i < ARRAY_SIZE(wifi_bands.WifiBandEntry); i++) {
+ if (!exclusion_ranges[i].start &&
+ !exclusion_ranges[i].end)
+ break;
+
+ /* PMFW expects the inputs to be in Mhz unit */
+ wifi_bands.WifiBandEntry[valid_entries].LowFreq =
+ DIV_ROUND_DOWN_ULL(exclusion_ranges[i].start, HZ_IN_MHZ);
+ wifi_bands.WifiBandEntry[valid_entries++].HighFreq =
+ DIV_ROUND_UP_ULL(exclusion_ranges[i].end, HZ_IN_MHZ);
+ }
+ wifi_bands.WifiBandEntryNum = valid_entries;
+
+ /*
+ * Per confirm with PMFW team, WifiBandEntryNum = 0
+ * is a valid setting. So, there should be no direct
+ * return on that.
+ */
+
+ ret = smu_cmn_update_table(smu,
+ SMU_TABLE_WIFIBAND,
+ 0,
+ (void *)(&wifi_bands),
+ true);
+ if (ret)
+ dev_warn(smu->adev->dev, "Failed to set wifiband!");
+
+ return ret;
+}
+
static const struct pptable_funcs smu_v13_0_0_ppt_funcs = {
.get_allowed_feature_mask = smu_v13_0_0_get_allowed_feature_mask,
.set_default_dpm_table = smu_v13_0_0_set_default_dpm_table,
@@ -2686,6 +2743,9 @@ static const struct pptable_funcs smu_v13_0_0_ppt_funcs = {
.send_hbm_bad_channel_flag = smu_v13_0_0_send_bad_mem_channel_flag,
.gpo_control = smu_v13_0_gpo_control,
.get_ecc_info = smu_v13_0_0_get_ecc_info,
+ .is_asic_wbrf_supported = smu_v13_0_0_wbrf_support_check,
+ .enable_uclk_shadow = smu_v13_0_enable_uclk_shadow,
+ .set_wbrf_exclusion_ranges = smu_v13_0_0_set_wbrf_exclusion_ranges,
};

void smu_v13_0_0_set_ppt_funcs(struct smu_context *smu)
--
2.34.1

2023-10-17 02:56:48

by Ma Jun

[permalink] [raw]
Subject: [PATCH v12 9/9] drm/amd/pm: enable Wifi RFI mitigation feature support for SMU13.0.7

From: Evan Quan <[email protected]>

Fulfill the SMU13.0.7 support for Wifi RFI mitigation feature.

Signed-off-by: Evan Quan <[email protected]>
Reviewed-by: Mario Limonciello <[email protected]>
Signed-off-by: Ma Jun <[email protected]>
--
v10->v11:
- downgrade the prompt level on message failure(Lijo)
---
.../drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c | 59 +++++++++++++++++++
1 file changed, 59 insertions(+)

diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
index 62f2886ab4df..c5736fb3cf6d 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
@@ -126,6 +126,7 @@ static struct cmn2asic_msg_mapping smu_v13_0_7_message_map[SMU_MSG_MAX_COUNT] =
MSG_MAP(AllowGpo, PPSMC_MSG_SetGpoAllow, 0),
MSG_MAP(GetPptLimit, PPSMC_MSG_GetPptLimit, 0),
MSG_MAP(NotifyPowerSource, PPSMC_MSG_NotifyPowerSource, 0),
+ MSG_MAP(EnableUCLKShadow, PPSMC_MSG_EnableUCLKShadow, 0),
};

static struct cmn2asic_mapping smu_v13_0_7_clk_map[SMU_CLK_COUNT] = {
@@ -207,6 +208,7 @@ static struct cmn2asic_mapping smu_v13_0_7_table_map[SMU_TABLE_COUNT] = {
TAB_MAP(ACTIVITY_MONITOR_COEFF),
[SMU_TABLE_COMBO_PPTABLE] = {1, TABLE_COMBO_PPTABLE},
TAB_MAP(OVERDRIVE),
+ TAB_MAP(WIFIBAND),
};

static struct cmn2asic_mapping smu_v13_0_7_pwr_src_map[SMU_POWER_SOURCE_COUNT] = {
@@ -503,6 +505,9 @@ static int smu_v13_0_7_tables_init(struct smu_context *smu)
AMDGPU_GEM_DOMAIN_VRAM);
SMU_TABLE_INIT(tables, SMU_TABLE_COMBO_PPTABLE, MP0_MP1_DATA_REGION_SIZE_COMBOPPTABLE,
PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
+ SMU_TABLE_INIT(tables, SMU_TABLE_WIFIBAND,
+ sizeof(WifiBandEntryTable_t), PAGE_SIZE,
+ AMDGPU_GEM_DOMAIN_VRAM);

smu_table->metrics_table = kzalloc(sizeof(SmuMetricsExternal_t), GFP_KERNEL);
if (!smu_table->metrics_table)
@@ -2179,6 +2184,57 @@ static int smu_v13_0_7_set_df_cstate(struct smu_context *smu,
NULL);
}

+static bool smu_v13_0_7_wbrf_support_check(struct smu_context *smu)
+{
+ return smu->smc_fw_version > 0x00524600;
+}
+
+static int smu_v13_0_7_set_wbrf_exclusion_ranges(struct smu_context *smu,
+ struct freq_band_range *exclusion_ranges)
+{
+ WifiBandEntryTable_t wifi_bands;
+ int valid_entries = 0;
+ int ret, i;
+
+ memset(&wifi_bands, 0, sizeof(wifi_bands));
+ for (i = 0; i < ARRAY_SIZE(wifi_bands.WifiBandEntry); i++) {
+ if (!exclusion_ranges[i].start &&
+ !exclusion_ranges[i].end)
+ break;
+
+ /* PMFW expects the inputs to be in Mhz unit */
+ wifi_bands.WifiBandEntry[valid_entries].LowFreq =
+ DIV_ROUND_DOWN_ULL(exclusion_ranges[i].start, HZ_IN_MHZ);
+ wifi_bands.WifiBandEntry[valid_entries++].HighFreq =
+ DIV_ROUND_UP_ULL(exclusion_ranges[i].end, HZ_IN_MHZ);
+ }
+ wifi_bands.WifiBandEntryNum = valid_entries;
+
+ /*
+ * Per confirm with PMFW team, WifiBandEntryNum = 0 is a valid setting.
+ * Considering the scenarios below:
+ * - At first the wifi device adds an exclusion range e.g. (2400,2500) to
+ * BIOS and our driver gets notified. We will set WifiBandEntryNum = 1
+ * and pass the WifiBandEntry (2400, 2500) to PMFW.
+ *
+ * - Later the wifi device removes the wifiband list added above and
+ * our driver gets notified again. At this time, driver will set
+ * WifiBandEntryNum = 0 and pass an empty WifiBandEntry list to PMFW.
+ * - PMFW may still need to do some uclk shadow update(e.g. switching
+ * from shadow clock back to primary clock) on receiving this.
+ */
+
+ ret = smu_cmn_update_table(smu,
+ SMU_TABLE_WIFIBAND,
+ 0,
+ (void *)(&wifi_bands),
+ true);
+ if (ret)
+ dev_warn(smu->adev->dev, "Failed to set wifiband!");
+
+ return ret;
+}
+
static const struct pptable_funcs smu_v13_0_7_ppt_funcs = {
.get_allowed_feature_mask = smu_v13_0_7_get_allowed_feature_mask,
.set_default_dpm_table = smu_v13_0_7_set_default_dpm_table,
@@ -2247,6 +2303,9 @@ static const struct pptable_funcs smu_v13_0_7_ppt_funcs = {
.set_mp1_state = smu_v13_0_7_set_mp1_state,
.set_df_cstate = smu_v13_0_7_set_df_cstate,
.gpo_control = smu_v13_0_gpo_control,
+ .is_asic_wbrf_supported = smu_v13_0_7_wbrf_support_check,
+ .enable_uclk_shadow = smu_v13_0_enable_uclk_shadow,
+ .set_wbrf_exclusion_ranges = smu_v13_0_7_set_wbrf_exclusion_ranges,
};

void smu_v13_0_7_set_ppt_funcs(struct smu_context *smu)
--
2.34.1

2023-10-17 08:51:44

by Ilpo Järvinen

[permalink] [raw]
Subject: Re: [PATCH v12 6/9] drm/amd/pm: setup the framework to support Wifi RFI mitigation feature

On Tue, 17 Oct 2023, Ma Jun wrote:

> From: Evan Quan <[email protected]>
>
> 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 <[email protected]>
> Reviewed-by: Mario Limonciello <[email protected]>
> Signed-off-by: Ma Jun <[email protected]>
> --
> v1->v2:
> - update the prompt for feature support(Lijo)
> v8->v9:
> - update parameter document for smu_wbrf_event_handler(Simon)
> v9->v10:
> v10->v11:
> - correct the logics for wbrf range sorting(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 | 195 ++++++++++++++++++
> drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 23 +++
> drivers/gpu/drm/amd/pm/swsmu/smu_internal.h | 3 +
> 5 files changed, 240 insertions(+)
>
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> index 6dc950c1b689..11a19384df56 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 222af2fae745..d52cd7ed2868 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
> @@ -1228,6 +1228,174 @@ 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_in_out wbrf_exclusion = {0};
> + struct freq_band_range *wifi_bands = wbrf_exclusion.band_list;
> + struct amdgpu_device *adev = smu->adev;
> + uint32_t num_of_wbrf_ranges = MAX_NUM_OF_WBRF_RANGES;
> + uint64_t start, end;
> + int ret, i, j;
> +
> + ret = amd_wbrf_retrieve_freq_band(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 < 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 = num_of_wbrf_ranges - 1; j > i; j--)
> + if (wifi_bands[j].start &&
> + wifi_bands[j].end)
> + break;
> +
> + /* no valid entry left */
> + if (j <= i)
> + break;
> +
> + start = wifi_bands[i].start = wifi_bands[j].start;
> + end = wifi_bands[i].end = wifi_bands[j].end;
> + wifi_bands[j].start = 0;
> + wifi_bands[j].end = 0;
> + num_of_wbrf_ranges = j;
> + }

Wouldn't it be easier and less error-prone to just sort them and then do
the duplicate removal after that?

> + /* eliminate duplicate entries */
> + for (j = i + 1; j < num_of_wbrf_ranges; j++) {
> + if ((wifi_bands[j].start == start) &&
> + (wifi_bands[j].end == end)) {
> + wifi_bands[j].start = 0;
> + wifi_bands[j].end = 0;
> + }
> + }
> + }
> +
> + /* Send the sorted wifi_bands to PMFW */
> + ret = smu_set_wbrf_exclusion_ranges(smu, wifi_bands);
> + /* Give it another chance */

This sounds very vague comment. What "it", what "another chance" ??

> + if (unlikely(ret == -EBUSY)) {
> + mdelay(5);

Magic delay without name, please add a define for it.

> + ret = smu_set_wbrf_exclusion_ranges(smu, wifi_bands);
> + }
> +
> + return ret;
> +}
> +
> +/**
> + * smu_wbrf_event_handler - handle notify events
> + *
> + * @nb: notifier block
> + * @action: event type
> + * @_arg: event data
> + *
> + * Calls relevant amdgpu function in response to wbrf event
> + * notification from kernel.
> + */
> +static int smu_wbrf_event_handler(struct notifier_block *nb,
> + unsigned long action, void *_arg)
> +{
> + struct smu_context *smu = container_of(nb, struct smu_context,
> + wbrf_notifier);
> +
> + switch (action) {
> + case WBRF_CHANGED:
> + smu_wbrf_handle_exclusion_ranges(smu);
> + break;
> + default:
> + return NOTIFY_DONE;
> + };
> +
> + return NOTIFY_OK;
> +}
> +
> +/**
> + * smu_wbrf_support_check - check wbrf support
> + *
> + * @smu: smu_context pointer
> + *
> + * Verifies the ACPI interface whether wbrf is supported.
> + */
> +static void smu_wbrf_support_check(struct smu_context *smu)
> +{
> + struct amdgpu_device *adev = smu->adev;
> +
> + smu->wbrf_supported = smu_is_asic_wbrf_supported(smu) &&
> + !!amdgpu_wbrf &&

Unnecessary !!.

> + acpi_amd_wbrf_supported_consumer(adev->dev);
> +
> + if (smu->wbrf_supported)
> + dev_info(adev->dev, "RF interference mitigation is supported\n");
> +}
> +
> +/**
> + * smu_wbrf_init - init driver wbrf support
> + *
> + * @smu: smu_context pointer
> + *
> + * Verifies the AMD ACPI interfaces and registers with the wbrf
> + * notifier chain if wbrf feature is supported.
> + * Returns 0 on success, error on failure.
> + */
> +static int smu_wbrf_init(struct smu_context *smu)
> +{
> + struct amdgpu_device *adev = smu->adev;
> + int ret;
> +
> + if (!smu->wbrf_supported)
> + return 0;
> +
> + smu->wbrf_notifier.notifier_call = smu_wbrf_event_handler;
> + ret = amd_wbrf_register_notifier(&smu->wbrf_notifier);
> + if (ret)
> + return ret;
> +
> + /*
> + * Some wifiband exclusion ranges may be already there
> + * before our driver loaded. To make sure our driver
> + * is awared of those exclusion ranges.
> + */
> + ret = smu_wbrf_handle_exclusion_ranges(smu);
> + if (ret)
> + dev_err(adev->dev, "Failed to handle wbrf exclusion ranges\n");
> +
> + return ret;
> +}
> +
> +/**
> + * smu_wbrf_fini - tear down driver wbrf support
> + *
> + * @smu: smu_context pointer
> + *
> + * Unregisters with the wbrf notifier chain.
> + */
> +static void smu_wbrf_fini(struct smu_context *smu)
> +{
> + if (!smu->wbrf_supported)
> + return;
> +
> + amd_wbrf_unregister_notifier(&smu->wbrf_notifier);
> +}
> +
> static int smu_smc_hw_setup(struct smu_context *smu)
> {
> struct smu_feature *feature = &smu->smu_feature;
> @@ -1320,6 +1488,15 @@ static int smu_smc_hw_setup(struct smu_context *smu)
> if (ret)
> return ret;
>
> + /* Enable UclkShadow on wbrf supported */
> + if (smu->wbrf_supported) {
> + ret = smu_enable_uclk_shadow(smu, true);
> + if (ret) {
> + dev_err(adev->dev, "Failed to enable UclkShadow feature to support wbrf!\n");
> + return ret;
> + }
> + }
> +
> /*
> * With SCPM enabled, these actions(and relevant messages) are
> * not needed and permitted.
> @@ -1416,6 +1593,15 @@ static int smu_smc_hw_setup(struct smu_context *smu)
> */
> ret = smu_set_min_dcef_deep_sleep(smu,
> smu->smu_table.boot_values.dcefclk / 100);
> + if (ret) {
> + dev_err(adev->dev, "Error setting min deepsleep dcefclk\n");
> + return ret;
> + }
> +
> + /* Init wbrf support. Properly setup the notifier */
> + ret = smu_wbrf_init(smu);
> + if (ret)
> + dev_err(adev->dev, "Error during wbrf init call\n");
>
> return ret;
> }
> @@ -1471,6 +1657,13 @@ static int smu_hw_init(void *handle)
> return ret;
> }
>
> + /*
> + * Check whether wbrf is supported. This needs to be done
> + * before SMU setup starts since part of SMU configuration
> + * relies on this.
> + */
> + smu_wbrf_support_check(smu);
> +
> if (smu->is_apu) {
> ret = smu_set_gfx_imu_enable(smu);
> if (ret)
> @@ -1623,6 +1816,8 @@ static int smu_smc_hw_cleanup(struct smu_context *smu)
> struct amdgpu_device *adev = smu->adev;
> int ret = 0;
>
> + smu_wbrf_fini(smu);
> +
> cancel_work_sync(&smu->throttling_logging_work);
> cancel_work_sync(&smu->interrupt_work);
>
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
> index 6e2069dcb6b9..39c1620d68c9 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
> +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
> @@ -22,6 +22,8 @@
> #ifndef __AMDGPU_SMU_H__
> #define __AMDGPU_SMU_H__
>
> +#include <linux/acpi_amd_wbrf.h>
> +
> #include "amdgpu.h"
> #include "kgd_pp_interface.h"
> #include "dm_pp_interface.h"
> @@ -575,6 +577,10 @@ struct smu_context
> u32 debug_resp_reg;
>
> struct delayed_work swctf_delayed_work;
> +
> + /* data structures for wbrf feature support */
> + bool wbrf_supported;
> + struct notifier_block wbrf_notifier;
> };
>
> struct i2c_adapter;
> @@ -1356,6 +1362,23 @@ struct pptable_funcs {
> * @init_pptable_microcode: Prepare the pptable microcode to upload via PSP
> */
> int (*init_pptable_microcode)(struct smu_context *smu);
> +
> + /**
> + * @is_asic_wbrf_supported: check whether PMFW supports the wbrf feature
> + */
> + bool (*is_asic_wbrf_supported)(struct smu_context *smu);
> +
> + /**
> + * @enable_uclk_shadow: Enable the uclk shadow feature on wbrf supported
> + */
> + int (*enable_uclk_shadow)(struct smu_context *smu,
> + bool enablement);

Fit to one line. Please go through all your patches and fix all
prematurely split lines.

Perhaps "enable" is enough, I don't know why you use "enablement".

> +
> + /**
> + * @set_wbrf_exclusion_ranges: notify SMU the wifi bands occupied
> + */
> + int (*set_wbrf_exclusion_ranges)(struct smu_context *smu,
> + struct freq_band_range *exclusion_ranges);
> };
>
> typedef enum {
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_internal.h b/drivers/gpu/drm/amd/pm/swsmu/smu_internal.h
> index ceb13c838067..aa64c7cdf3c9 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu_internal.h
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_internal.h
> @@ -97,6 +97,9 @@
> #define smu_get_default_config_table_settings(smu, config_table) smu_ppt_funcs(get_default_config_table_settings, -EOPNOTSUPP, smu, config_table)
> #define smu_set_config_table(smu, config_table) smu_ppt_funcs(set_config_table, -EOPNOTSUPP, smu, config_table)
> #define smu_init_pptable_microcode(smu) smu_ppt_funcs(init_pptable_microcode, 0, smu)
> +#define smu_is_asic_wbrf_supported(smu) smu_ppt_funcs(is_asic_wbrf_supported, false, smu)
> +#define smu_enable_uclk_shadow(smu, enablement) smu_ppt_funcs(enable_uclk_shadow, 0, smu, enablement)
> +#define smu_set_wbrf_exclusion_ranges(smu, freq_band_range) smu_ppt_funcs(set_wbrf_exclusion_ranges, -EOPNOTSUPP, smu, freq_band_range)
>
> #endif
> #endif
>

--
i.

2023-10-17 08:57:48

by Ilpo Järvinen

[permalink] [raw]
Subject: Re: [PATCH v12 8/9] drm/amd/pm: enable Wifi RFI mitigation feature support for SMU13.0.0

On Tue, 17 Oct 2023, Ma Jun wrote:

> From: Evan Quan <[email protected]>
>
> Fulfill the SMU13.0.0 support for Wifi RFI mitigation feature.
>
> Signed-off-by: Evan Quan <[email protected]>
> Reviewed-by: Mario Limonciello <[email protected]>
> Signed-off-by: Ma Jun <[email protected]>
> --
> v10->v11:
> - downgrade the prompt level on message failure(Lijo)
> ---
> drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 3 +
> drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h | 3 +-
> drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h | 3 +
> .../gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c | 9 +++
> .../drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c | 60 +++++++++++++++++++
> 5 files changed, 77 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
> index d396a18fe0f3..6f88c352b53e 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
> +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
> @@ -325,6 +325,7 @@ enum smu_table_id
> SMU_TABLE_PACE,
> SMU_TABLE_ECCINFO,
> SMU_TABLE_COMBO_PPTABLE,
> + SMU_TABLE_WIFIBAND,
> SMU_TABLE_COUNT,
> };
>
> @@ -1501,6 +1502,8 @@ enum smu_baco_seq {
> __dst_size); \
> })
>
> +#define HZ_IN_MHZ 1000000U

Don't add generic conversion constants like this into driver specific
code. Use the one from include/linux/units.h,

> +
> #if !defined(SWSMU_CODE_LAYER_L2) && !defined(SWSMU_CODE_LAYER_L3) && !defined(SWSMU_CODE_LAYER_L4)
> int smu_get_power_limit(void *handle,
> uint32_t *limit,
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h
> index 297b70b9388f..5bbb60289a79 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h
> +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h
> @@ -245,7 +245,8 @@
> __SMU_DUMMY_MAP(AllowGpo), \
> __SMU_DUMMY_MAP(Mode2Reset), \
> __SMU_DUMMY_MAP(RequestI2cTransaction), \
> - __SMU_DUMMY_MAP(GetMetricsTable),
> + __SMU_DUMMY_MAP(GetMetricsTable), \
> + __SMU_DUMMY_MAP(EnableUCLKShadow),
>
> #undef __SMU_DUMMY_MAP
> #define __SMU_DUMMY_MAP(type) SMU_MSG_##type
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h
> index 355c156d871a..dd70b56aa71e 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h
> +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h
> @@ -299,5 +299,8 @@ int smu_v13_0_update_pcie_parameters(struct smu_context *smu,
> uint32_t pcie_gen_cap,
> uint32_t pcie_width_cap);
>
> +int smu_v13_0_enable_uclk_shadow(struct smu_context *smu,
> + bool enablement);
> +
> #endif
> #endif
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c
> index 9b62b45ebb7f..6a5cb582aa92 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c
> @@ -2472,3 +2472,12 @@ int smu_v13_0_update_pcie_parameters(struct smu_context *smu,
>
> return 0;
> }
> +
> +int smu_v13_0_enable_uclk_shadow(struct smu_context *smu,
> + bool enablement)
> +{
> + return smu_cmn_send_smc_msg_with_param(smu,
> + SMU_MSG_EnableUCLKShadow,
> + enablement,
> + NULL);
> +}
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
> index 0fb6be11a0cc..08ab19559c7b 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
> @@ -154,6 +154,7 @@ static struct cmn2asic_msg_mapping smu_v13_0_0_message_map[SMU_MSG_MAX_COUNT] =
> MSG_MAP(AllowGpo, PPSMC_MSG_SetGpoAllow, 0),
> MSG_MAP(AllowIHHostInterrupt, PPSMC_MSG_AllowIHHostInterrupt, 0),
> MSG_MAP(ReenableAcDcInterrupt, PPSMC_MSG_ReenableAcDcInterrupt, 0),
> + MSG_MAP(EnableUCLKShadow, PPSMC_MSG_EnableUCLKShadow, 0),
> };
>
> static struct cmn2asic_mapping smu_v13_0_0_clk_map[SMU_CLK_COUNT] = {
> @@ -237,6 +238,7 @@ static struct cmn2asic_mapping smu_v13_0_0_table_map[SMU_TABLE_COUNT] = {
> TAB_MAP(I2C_COMMANDS),
> TAB_MAP(ECCINFO),
> TAB_MAP(OVERDRIVE),
> + TAB_MAP(WIFIBAND),
> };
>
> static struct cmn2asic_mapping smu_v13_0_0_pwr_src_map[SMU_POWER_SOURCE_COUNT] = {
> @@ -496,6 +498,9 @@ static int smu_v13_0_0_tables_init(struct smu_context *smu)
> PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
> SMU_TABLE_INIT(tables, SMU_TABLE_ECCINFO, sizeof(EccInfoTable_t),
> PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
> + SMU_TABLE_INIT(tables, SMU_TABLE_WIFIBAND,
> + sizeof(WifiBandEntryTable_t), PAGE_SIZE,
> + AMDGPU_GEM_DOMAIN_VRAM);
>
> smu_table->metrics_table = kzalloc(sizeof(SmuMetricsExternal_t), GFP_KERNEL);
> if (!smu_table->metrics_table)
> @@ -2607,6 +2612,58 @@ static ssize_t smu_v13_0_0_get_ecc_info(struct smu_context *smu,
> return ret;
> }
>
> +static bool smu_v13_0_0_wbrf_support_check(struct smu_context *smu)
> +{
> + struct amdgpu_device *adev = smu->adev;
> +
> + switch (adev->ip_versions[MP1_HWIP][0]) {
> + case IP_VERSION(13, 0, 0):
> + return smu->smc_fw_version >= 0x004e6300;
> + case IP_VERSION(13, 0, 10):
> + return smu->smc_fw_version >= 0x00503300;
> + default:
> + return false;
> + }
> +}
> +
> +static int smu_v13_0_0_set_wbrf_exclusion_ranges(struct smu_context *smu,
> + struct freq_band_range *exclusion_ranges)
> +{
> + WifiBandEntryTable_t wifi_bands;
> + int valid_entries = 0;
> + int ret, i;
> +
> + memset(&wifi_bands, 0, sizeof(wifi_bands));
> + for (i = 0; i < ARRAY_SIZE(wifi_bands.WifiBandEntry); i++) {
> + if (!exclusion_ranges[i].start &&
> + !exclusion_ranges[i].end)
> + break;
> +
> + /* PMFW expects the inputs to be in Mhz unit */
> + wifi_bands.WifiBandEntry[valid_entries].LowFreq =
> + DIV_ROUND_DOWN_ULL(exclusion_ranges[i].start, HZ_IN_MHZ);
> + wifi_bands.WifiBandEntry[valid_entries++].HighFreq =
> + DIV_ROUND_UP_ULL(exclusion_ranges[i].end, HZ_IN_MHZ);
> + }
> + wifi_bands.WifiBandEntryNum = valid_entries;
> +
> + /*
> + * Per confirm with PMFW team, WifiBandEntryNum = 0
> + * is a valid setting. So, there should be no direct
> + * return on that.
> + */
> +
> + ret = smu_cmn_update_table(smu,
> + SMU_TABLE_WIFIBAND,
> + 0,
> + (void *)(&wifi_bands),

Explicit casting to void * is never needed, drop it and the parenthesis.

This probably fits to one line after that and certainly to less lines than
now.

> + true);
> + if (ret)
> + dev_warn(smu->adev->dev, "Failed to set wifiband!");
> +
> + return ret;
> +}
> +
> static const struct pptable_funcs smu_v13_0_0_ppt_funcs = {
> .get_allowed_feature_mask = smu_v13_0_0_get_allowed_feature_mask,
> .set_default_dpm_table = smu_v13_0_0_set_default_dpm_table,
> @@ -2686,6 +2743,9 @@ static const struct pptable_funcs smu_v13_0_0_ppt_funcs = {
> .send_hbm_bad_channel_flag = smu_v13_0_0_send_bad_mem_channel_flag,
> .gpo_control = smu_v13_0_gpo_control,
> .get_ecc_info = smu_v13_0_0_get_ecc_info,
> + .is_asic_wbrf_supported = smu_v13_0_0_wbrf_support_check,
> + .enable_uclk_shadow = smu_v13_0_enable_uclk_shadow,
> + .set_wbrf_exclusion_ranges = smu_v13_0_0_set_wbrf_exclusion_ranges,
> };
>
> void smu_v13_0_0_set_ppt_funcs(struct smu_context *smu)
>

--
i.

2023-10-17 09:04:01

by Ilpo Järvinen

[permalink] [raw]
Subject: Re: [PATCH v12 9/9] drm/amd/pm: enable Wifi RFI mitigation feature support for SMU13.0.7

On Tue, 17 Oct 2023, Ma Jun wrote:

> From: Evan Quan <[email protected]>
>
> Fulfill the SMU13.0.7 support for Wifi RFI mitigation feature.
>
> Signed-off-by: Evan Quan <[email protected]>
> Reviewed-by: Mario Limonciello <[email protected]>
> Signed-off-by: Ma Jun <[email protected]>
> --
> v10->v11:
> - downgrade the prompt level on message failure(Lijo)
> ---
> .../drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c | 59 +++++++++++++++++++
> 1 file changed, 59 insertions(+)
>
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
> index 62f2886ab4df..c5736fb3cf6d 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
> @@ -126,6 +126,7 @@ static struct cmn2asic_msg_mapping smu_v13_0_7_message_map[SMU_MSG_MAX_COUNT] =
> MSG_MAP(AllowGpo, PPSMC_MSG_SetGpoAllow, 0),
> MSG_MAP(GetPptLimit, PPSMC_MSG_GetPptLimit, 0),
> MSG_MAP(NotifyPowerSource, PPSMC_MSG_NotifyPowerSource, 0),
> + MSG_MAP(EnableUCLKShadow, PPSMC_MSG_EnableUCLKShadow, 0),
> };
>
> static struct cmn2asic_mapping smu_v13_0_7_clk_map[SMU_CLK_COUNT] = {
> @@ -207,6 +208,7 @@ static struct cmn2asic_mapping smu_v13_0_7_table_map[SMU_TABLE_COUNT] = {
> TAB_MAP(ACTIVITY_MONITOR_COEFF),
> [SMU_TABLE_COMBO_PPTABLE] = {1, TABLE_COMBO_PPTABLE},
> TAB_MAP(OVERDRIVE),
> + TAB_MAP(WIFIBAND),
> };
>
> static struct cmn2asic_mapping smu_v13_0_7_pwr_src_map[SMU_POWER_SOURCE_COUNT] = {
> @@ -503,6 +505,9 @@ static int smu_v13_0_7_tables_init(struct smu_context *smu)
> AMDGPU_GEM_DOMAIN_VRAM);
> SMU_TABLE_INIT(tables, SMU_TABLE_COMBO_PPTABLE, MP0_MP1_DATA_REGION_SIZE_COMBOPPTABLE,
> PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
> + SMU_TABLE_INIT(tables, SMU_TABLE_WIFIBAND,
> + sizeof(WifiBandEntryTable_t), PAGE_SIZE,
> + AMDGPU_GEM_DOMAIN_VRAM);
>
> smu_table->metrics_table = kzalloc(sizeof(SmuMetricsExternal_t), GFP_KERNEL);
> if (!smu_table->metrics_table)
> @@ -2179,6 +2184,57 @@ static int smu_v13_0_7_set_df_cstate(struct smu_context *smu,
> NULL);
> }
>
> +static bool smu_v13_0_7_wbrf_support_check(struct smu_context *smu)
> +{
> + return smu->smc_fw_version > 0x00524600;
> +}
> +
> +static int smu_v13_0_7_set_wbrf_exclusion_ranges(struct smu_context *smu,
> + struct freq_band_range *exclusion_ranges)
> +{
> + WifiBandEntryTable_t wifi_bands;
> + int valid_entries = 0;
> + int ret, i;
> +
> + memset(&wifi_bands, 0, sizeof(wifi_bands));
> + for (i = 0; i < ARRAY_SIZE(wifi_bands.WifiBandEntry); i++) {
> + if (!exclusion_ranges[i].start &&
> + !exclusion_ranges[i].end)

After having seen this construct nth time, I think you should have a
static inline function for this check with a proper name.

> + break;
> +
> + /* PMFW expects the inputs to be in Mhz unit */
> + wifi_bands.WifiBandEntry[valid_entries].LowFreq =
> + DIV_ROUND_DOWN_ULL(exclusion_ranges[i].start, HZ_IN_MHZ);
> + wifi_bands.WifiBandEntry[valid_entries++].HighFreq =
> + DIV_ROUND_UP_ULL(exclusion_ranges[i].end, HZ_IN_MHZ);
> + }
> + wifi_bands.WifiBandEntryNum = valid_entries;
> +
> + /*
> + * Per confirm with PMFW team, WifiBandEntryNum = 0 is a valid setting.
> + * Considering the scenarios below:
> + * - At first the wifi device adds an exclusion range e.g. (2400,2500) to
> + * BIOS and our driver gets notified. We will set WifiBandEntryNum = 1
> + * and pass the WifiBandEntry (2400, 2500) to PMFW.
> + *
> + * - Later the wifi device removes the wifiband list added above and
> + * our driver gets notified again. At this time, driver will set
> + * WifiBandEntryNum = 0 and pass an empty WifiBandEntry list to PMFW.
> + * - PMFW may still need to do some uclk shadow update(e.g. switching
> + * from shadow clock back to primary clock) on receiving this.
> + */
> +
> + ret = smu_cmn_update_table(smu,
> + SMU_TABLE_WIFIBAND,
> + 0,
> + (void *)(&wifi_bands),
> + true);
> + if (ret)
> + dev_warn(smu->adev->dev, "Failed to set wifiband!");
> +
> + return ret;
> +}

Is this whole function duplicate of the one in the other file? Don't
duplicate code like this but create reusable functions properly.

--
i.

> +
> static const struct pptable_funcs smu_v13_0_7_ppt_funcs = {
> .get_allowed_feature_mask = smu_v13_0_7_get_allowed_feature_mask,
> .set_default_dpm_table = smu_v13_0_7_set_default_dpm_table,
> @@ -2247,6 +2303,9 @@ static const struct pptable_funcs smu_v13_0_7_ppt_funcs = {
> .set_mp1_state = smu_v13_0_7_set_mp1_state,
> .set_df_cstate = smu_v13_0_7_set_df_cstate,
> .gpo_control = smu_v13_0_gpo_control,
> + .is_asic_wbrf_supported = smu_v13_0_7_wbrf_support_check,
> + .enable_uclk_shadow = smu_v13_0_enable_uclk_shadow,
> + .set_wbrf_exclusion_ranges = smu_v13_0_7_set_wbrf_exclusion_ranges,
> };
>
> void smu_v13_0_7_set_ppt_funcs(struct smu_context *smu)
>

2023-10-17 09:12:01

by Ilpo Järvinen

[permalink] [raw]
Subject: Re: [PATCH v12 4/9] wifi: mac80211: Add support for WBRF features

On Tue, 17 Oct 2023, Ma Jun wrote:

> From: Evan Quan <[email protected]>
>
> To support the WBRF mechanism, Wifi adapters utilized in the system must
> register the frequencies in use(or unregister those frequencies no longer
> used) via the dedicated calls. So that, other drivers responding to the
> frequencies can take proper actions to mitigate possible interference.
>
> Co-developed-by: Mario Limonciello <[email protected]>
> Signed-off-by: Mario Limonciello <[email protected]>
> Co-developed-by: Evan Quan <[email protected]>
> Signed-off-by: Evan Quan <[email protected]>
> Signed-off-by: Ma Jun <[email protected]>
> --
> v1->v2:
> - place the new added member(`wbrf_supported`) in
> ieee80211_local(Johannes)
> - handle chandefs change scenario properly(Johannes)
> - some minor fixes around code sharing and possible invalid input
> checks(Johannes)
> v2->v3:
> - drop unnecessary input checks and intermediate APIs(Mario)
> - Separate some mac80211 common code(Mario, Johannes)
> v3->v4:
> - some minor fixes around return values(Johannes)
> v9->v10:
> - get ranges_in->num_of_ranges set and passed in(Johannes)
> v12:
> - use acpi_amd_wbrf_add_remove to replace the acpi_amd_wbrf_add_exclusion
> acpi_amd_wbrf_remove_exclusion
> ---
> include/linux/ieee80211.h | 1 +
> net/mac80211/Makefile | 2 +
> net/mac80211/chan.c | 9 ++++
> net/mac80211/ieee80211_i.h | 9 ++++
> net/mac80211/main.c | 2 +
> net/mac80211/wbrf.c | 105 +++++++++++++++++++++++++++++++++++++
> 6 files changed, 128 insertions(+)
> create mode 100644 net/mac80211/wbrf.c
>
> diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
> index 4b998090898e..f995d06da87f 100644
> --- a/include/linux/ieee80211.h
> +++ b/include/linux/ieee80211.h
> @@ -4335,6 +4335,7 @@ static inline int ieee80211_get_tdls_action(struct sk_buff *skb, u32 hdr_size)
> /* convert frequencies */
> #define MHZ_TO_KHZ(freq) ((freq) * 1000)
> #define KHZ_TO_MHZ(freq) ((freq) / 1000)
> +#define KHZ_TO_HZ(freq) ((freq) * 1000)

It would be better to not add more of these per subsystem but use the
generic include/linux/units.h constants instead.

> #define PR_KHZ(f) KHZ_TO_MHZ(f), f % 1000
> #define KHZ_F "%d.%03d"
>
> diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile
> index b8de44da1fb8..d46c36f55fd3 100644
> --- a/net/mac80211/Makefile
> +++ b/net/mac80211/Makefile
> @@ -65,4 +65,6 @@ rc80211_minstrel-$(CONFIG_MAC80211_DEBUGFS) += \
>
> mac80211-$(CONFIG_MAC80211_RC_MINSTREL) += $(rc80211_minstrel-y)
>
> +mac80211-y += wbrf.o
> +
> ccflags-y += -DDEBUG
> diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
> index 68952752b599..458469c224ae 100644
> --- a/net/mac80211/chan.c
> +++ b/net/mac80211/chan.c
> @@ -506,11 +506,16 @@ static void _ieee80211_change_chanctx(struct ieee80211_local *local,
>
> WARN_ON(!cfg80211_chandef_compatible(&ctx->conf.def, chandef));
>
> + ieee80211_remove_wbrf(local, &ctx->conf.def);
> +
> ctx->conf.def = *chandef;
>
> /* check if min chanctx also changed */
> changed = IEEE80211_CHANCTX_CHANGE_WIDTH |
> _ieee80211_recalc_chanctx_min_def(local, ctx, rsvd_for);
> +
> + ieee80211_add_wbrf(local, &ctx->conf.def);
> +
> drv_change_chanctx(local, ctx, changed);
>
> if (!local->use_chanctx) {
> @@ -668,6 +673,8 @@ static int ieee80211_add_chanctx(struct ieee80211_local *local,
> lockdep_assert_held(&local->mtx);
> lockdep_assert_held(&local->chanctx_mtx);
>
> + ieee80211_add_wbrf(local, &ctx->conf.def);
> +
> if (!local->use_chanctx)
> local->hw.conf.radar_enabled = ctx->conf.radar_enabled;
>
> @@ -748,6 +755,8 @@ static void ieee80211_del_chanctx(struct ieee80211_local *local,
> }
>
> ieee80211_recalc_idle(local);
> +
> + ieee80211_remove_wbrf(local, &ctx->conf.def);
> }
>
> static void ieee80211_free_chanctx(struct ieee80211_local *local,
> diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
> index 91633a0b723e..719f2c892132 100644
> --- a/net/mac80211/ieee80211_i.h
> +++ b/net/mac80211/ieee80211_i.h
> @@ -1600,6 +1600,8 @@ struct ieee80211_local {
>
> /* extended capabilities provided by mac80211 */
> u8 ext_capa[8];
> +
> + bool wbrf_supported;
> };
>
> static inline struct ieee80211_sub_if_data *
> @@ -2638,4 +2640,11 @@ ieee80211_eht_cap_ie_to_sta_eht_cap(struct ieee80211_sub_if_data *sdata,
> const struct ieee80211_eht_cap_elem *eht_cap_ie_elem,
> u8 eht_cap_len,
> struct link_sta_info *link_sta);
> +
> +void ieee80211_check_wbrf_support(struct ieee80211_local *local);
> +void ieee80211_add_wbrf(struct ieee80211_local *local,
> + struct cfg80211_chan_def *chandef);
> +void ieee80211_remove_wbrf(struct ieee80211_local *local,
> + struct cfg80211_chan_def *chandef);
> +
> #endif /* IEEE80211_I_H */
> diff --git a/net/mac80211/main.c b/net/mac80211/main.c
> index 24315d7b3126..b20bdaac84db 100644
> --- a/net/mac80211/main.c
> +++ b/net/mac80211/main.c
> @@ -1396,6 +1396,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
> debugfs_hw_add(local);
> rate_control_add_debugfs(local);
>
> + ieee80211_check_wbrf_support(local);
> +
> rtnl_lock();
> wiphy_lock(hw->wiphy);
>
> diff --git a/net/mac80211/wbrf.c b/net/mac80211/wbrf.c
> new file mode 100644
> index 000000000000..7329f554c7af
> --- /dev/null
> +++ b/net/mac80211/wbrf.c
> @@ -0,0 +1,105 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Wifi Band Exclusion Interface for WLAN
> + * Copyright (C) 2023 Advanced Micro Devices
> + *
> + */
> +
> +#include <linux/acpi_amd_wbrf.h>
> +#include <net/cfg80211.h>
> +#include "ieee80211_i.h"
> +
> +void ieee80211_check_wbrf_support(struct ieee80211_local *local)
> +{
> + struct wiphy *wiphy = local->hw.wiphy;
> + struct device *dev;
> +
> + if (!wiphy)
> + return;
> +
> + dev = wiphy->dev.parent;
> + if (!dev)
> + return;
> +
> + local->wbrf_supported = acpi_amd_wbrf_supported_producer(dev);
> + dev_dbg(dev, "WBRF is %s supported\n",
> + local->wbrf_supported ? "" : "not");

Add a new static inline into include/linux/string_choices.h for
"supported" / "not supported" and use it here.

> +}
> +
> +static void get_chan_freq_boundary(u32 center_freq,
> + u32 bandwidth,
> + u64 *start,
> + u64 *end)

Use less lines.

> +{
> + bandwidth = MHZ_TO_KHZ(bandwidth);
> + center_freq = MHZ_TO_KHZ(center_freq);
> +
> + *start = center_freq - bandwidth / 2;
> + *end = center_freq + bandwidth / 2;
> +
> + /* Frequency in HZ is expected */

No, it's not in HZ but Hz. HZ has a special meaning in kernel.

--
i.

> + *start = KHZ_TO_HZ(*start);
> + *end = KHZ_TO_HZ(*end);
> +}
> +
> +static void get_ranges_from_chandef(struct cfg80211_chan_def *chandef,
> + struct wbrf_ranges_in_out *ranges_in)
> +{
> + u64 start_freq1, end_freq1;
> + u64 start_freq2, end_freq2;
> + int bandwidth;
> +
> + bandwidth = nl80211_chan_width_to_mhz(chandef->width);
> +
> + get_chan_freq_boundary(chandef->center_freq1,
> + bandwidth,
> + &start_freq1,
> + &end_freq1);
> +
> + ranges_in->band_list[0].start = start_freq1;
> + ranges_in->band_list[0].end = end_freq1;
> + ranges_in->num_of_ranges = 1;
> +
> + if (chandef->width == NL80211_CHAN_WIDTH_80P80) {
> + get_chan_freq_boundary(chandef->center_freq2,
> + bandwidth,
> + &start_freq2,
> + &end_freq2);
> +
> + ranges_in->band_list[1].start = start_freq2;
> + ranges_in->band_list[1].end = end_freq2;
> + ranges_in->num_of_ranges++;
> + }
> +}
> +
> +void ieee80211_add_wbrf(struct ieee80211_local *local,
> + struct cfg80211_chan_def *chandef)
> +{
> + struct wbrf_ranges_in_out ranges_in = {0};
> + struct device *dev;
> +
> + if (!local->wbrf_supported)
> + return;
> +
> + dev = local->hw.wiphy->dev.parent;
> +
> + get_ranges_from_chandef(chandef, &ranges_in);
> +
> + acpi_amd_wbrf_add_remove(dev, WBRF_RECORD_ADD, &ranges_in);
> +}
> +
> +void ieee80211_remove_wbrf(struct ieee80211_local *local,
> + struct cfg80211_chan_def *chandef)
> +{
> + struct wbrf_ranges_in_out ranges_in = {0};
> + struct device *dev;
> +
> + if (!local->wbrf_supported)
> + return;
> +
> + dev = local->hw.wiphy->dev.parent;
> +
> + get_ranges_from_chandef(chandef, &ranges_in);
> +
> + acpi_amd_wbrf_add_remove(dev, WBRF_RECORD_REMOVE, &ranges_in);
> +}
>

2023-10-17 09:12:40

by Ilpo Järvinen

[permalink] [raw]
Subject: Re: [PATCH v12 4/9] wifi: mac80211: Add support for WBRF features

On Tue, 17 Oct 2023, Ma Jun wrote:

> From: Evan Quan <[email protected]>
>
> To support the WBRF mechanism, Wifi adapters utilized in the system must
> register the frequencies in use(or unregister those frequencies no longer

Space is missing.

--
i.

2023-10-17 09:14:57

by Ilpo Järvinen

[permalink] [raw]
Subject: Re: [PATCH v12 3/9] cfg80211: expose nl80211_chan_width_to_mhz for wide sharing

On Tue, 17 Oct 2023, Ma Jun wrote:

> From: Evan Quan <[email protected]>
>
> The newly added WBRF feature needs this interface for channel
> width calculation.
>
> Signed-off-by: Ma Jun <[email protected]>
> Signed-off-by: Evan Quan <[email protected]>
>
> --
> v8->v9:
> - correct typo(Mhz -> MHz) (Johnson)
> ---
> include/net/cfg80211.h | 8 ++++++++
> net/wireless/chan.c | 3 ++-
> 2 files changed, 10 insertions(+), 1 deletion(-)
>
> diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
> index d6fa7c8767ad..026d91083f37 100644
> --- a/include/net/cfg80211.h
> +++ b/include/net/cfg80211.h
> @@ -923,6 +923,14 @@ const struct cfg80211_chan_def *
> cfg80211_chandef_compatible(const struct cfg80211_chan_def *chandef1,
> const struct cfg80211_chan_def *chandef2);
>
> +/**
> + * nl80211_chan_width_to_mhz - get the channel width in MHz
> + * @chan_width: the channel width from &enum nl80211_chan_width
> + * Return: channel width in MHz if the chan_width from &enum nl80211_chan_width
> + * is valid. -1 otherwise.

Add empty line before Return:

> + */
> +int nl80211_chan_width_to_mhz(enum nl80211_chan_width chan_width);
> +
> /**
> * cfg80211_chandef_valid - check if a channel definition is valid
> * @chandef: the channel definition to check
> diff --git a/net/wireless/chan.c b/net/wireless/chan.c
> index 0b7e81db383d..227db04eac42 100644
> --- a/net/wireless/chan.c
> +++ b/net/wireless/chan.c
> @@ -141,7 +141,7 @@ static bool cfg80211_edmg_chandef_valid(const struct cfg80211_chan_def *chandef)
> return true;
> }
>
> -static int nl80211_chan_width_to_mhz(enum nl80211_chan_width chan_width)
> +int nl80211_chan_width_to_mhz(enum nl80211_chan_width chan_width)
> {
> int mhz;
>
> @@ -190,6 +190,7 @@ static int nl80211_chan_width_to_mhz(enum nl80211_chan_width chan_width)
> }
> return mhz;
> }
> +EXPORT_SYMBOL(nl80211_chan_width_to_mhz);
>
> static int cfg80211_chandef_get_width(const struct cfg80211_chan_def *c)
> {
>

--
i.

2023-10-19 06:17:38

by Ma, Jun

[permalink] [raw]
Subject: Re: [PATCH v12 0/9] Enable Wifi RFI interference mitigation feature support

ping...
Any other comments?

Regards,
Ma Jun

On 10/17/2023 10:53 AM, Ma Jun wrote:
> 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 possible RFI interference we introuduced WBRF(Wifi Band RFI mitigation Feature).
> Producers can advertise the frequencies in use and consumers can use this information
> to avoid using these frequencies for sensitive features.
>
> The whole patch set is based on Linux 6.5.0. With some brief introductions
> as below:
> Patch1: Document about WBRF
> Patch2: Core functionality setup for WBRF feature support
> Patch3 - 4: Bring WBRF support to wifi subsystem.
> Patch5 - 9: Bring WBRF support to AMD graphics driver.
>
> Evan Quan (7):
> cfg80211: expose nl80211_chan_width_to_mhz for wide sharing
> wifi: mac80211: Add support for WBRF features
> drm/amd/pm: update driver_if and ppsmc headers for coming wbrf feature
> drm/amd/pm: setup the framework to support Wifi RFI mitigation feature
> drm/amd/pm: add flood detection for wbrf events
> drm/amd/pm: enable Wifi RFI mitigation feature support for SMU13.0.0
> drm/amd/pm: enable Wifi RFI mitigation feature support for SMU13.0.7
>
> Ma Jun (2):
> Documentation/driver-api: Add document about WBRF mechanism
> platform/x86/amd: Add support for AMD ACPI based Wifi band RFI
> mitigation feature
>
> Documentation/driver-api/wbrf.rst | 71 +++
> 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 | 214 +++++++++
> drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 33 ++
> .../inc/pmfw_if/smu13_driver_if_v13_0_0.h | 14 +-
> .../inc/pmfw_if/smu13_driver_if_v13_0_7.h | 14 +-
> .../pm/swsmu/inc/pmfw_if/smu_v13_0_0_ppsmc.h | 3 +-
> .../pm/swsmu/inc/pmfw_if/smu_v13_0_7_ppsmc.h | 3 +-
> drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h | 3 +-
> drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h | 3 +
> .../gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c | 9 +
> .../drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c | 60 +++
> .../drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c | 59 +++
> drivers/gpu/drm/amd/pm/swsmu/smu_internal.h | 3 +
> drivers/platform/x86/amd/Kconfig | 15 +
> drivers/platform/x86/amd/Makefile | 1 +
> drivers/platform/x86/amd/wbrf.c | 422 ++++++++++++++++++
> include/linux/acpi_amd_wbrf.h | 101 +++++
> include/linux/ieee80211.h | 1 +
> include/net/cfg80211.h | 8 +
> net/mac80211/Makefile | 2 +
> net/mac80211/chan.c | 9 +
> net/mac80211/ieee80211_i.h | 9 +
> net/mac80211/main.c | 2 +
> net/mac80211/wbrf.c | 105 +++++
> net/wireless/chan.c | 3 +-
> 27 files changed, 1180 insertions(+), 6 deletions(-)
> create mode 100644 Documentation/driver-api/wbrf.rst
> create mode 100644 drivers/platform/x86/amd/wbrf.c
> create mode 100644 include/linux/acpi_amd_wbrf.h
> create mode 100644 net/mac80211/wbrf.c
>