Commit 1a409b35 authored by Shyam Sundar S K's avatar Shyam Sundar S K Committed by Hans de Goede

platform/x86/amd/pmf: Get performance metrics from PMFW

PMF driver polls for metrics information from PMFW to understand the system
behavior, power consumption etc.

This metrics table information will be used the PMF features to tweak the
thermal heuristics. The poll duration can also be changed by the user
by changing the poll duration time.
Reviewed-by: default avatarHans de Goede <hdegoede@redhat.com>
Signed-off-by: default avatarShyam Sundar S K <Shyam-sundar.S-k@amd.com>
Link: https://lore.kernel.org/r/20220802151149.2123699-8-Shyam-sundar.S-k@amd.comSigned-off-by: default avatarHans de Goede <hdegoede@redhat.com>
parent a3281ec5
...@@ -47,6 +47,11 @@ ...@@ -47,6 +47,11 @@
#define DELAY_MIN_US 2000 #define DELAY_MIN_US 2000
#define DELAY_MAX_US 3000 #define DELAY_MAX_US 3000
/* override Metrics Table sample size time (in ms) */
static int metrics_table_loop_ms = 1000;
module_param(metrics_table_loop_ms, int, 0644);
MODULE_PARM_DESC(metrics_table_loop_ms, "Metrics Table sample size time (default = 1000ms)");
static int current_power_limits_show(struct seq_file *seq, void *unused) static int current_power_limits_show(struct seq_file *seq, void *unused)
{ {
struct amd_pmf_dev *dev = seq->private; struct amd_pmf_dev *dev = seq->private;
...@@ -88,6 +93,25 @@ int amd_pmf_get_power_source(void) ...@@ -88,6 +93,25 @@ int amd_pmf_get_power_source(void)
return POWER_SOURCE_DC; return POWER_SOURCE_DC;
} }
static void amd_pmf_get_metrics(struct work_struct *work)
{
struct amd_pmf_dev *dev = container_of(work, struct amd_pmf_dev, work_buffer.work);
ktime_t time_elapsed_ms;
int socket_power;
/* Transfer table contents */
memset(dev->buf, 0, sizeof(dev->m_table));
amd_pmf_send_cmd(dev, SET_TRANSFER_TABLE, 0, 7, NULL);
memcpy(&dev->m_table, dev->buf, sizeof(dev->m_table));
time_elapsed_ms = ktime_to_ms(ktime_get()) - dev->start_time;
/* Calculate the avg SoC power consumption */
socket_power = dev->m_table.apu_power + dev->m_table.dgpu_power;
dev->start_time = ktime_to_ms(ktime_get());
schedule_delayed_work(&dev->work_buffer, msecs_to_jiffies(metrics_table_loop_ms));
}
static inline u32 amd_pmf_reg_read(struct amd_pmf_dev *dev, int reg_offset) static inline u32 amd_pmf_reg_read(struct amd_pmf_dev *dev, int reg_offset)
{ {
return ioread32(dev->regbase + reg_offset); return ioread32(dev->regbase + reg_offset);
...@@ -181,6 +205,34 @@ static const struct pci_device_id pmf_pci_ids[] = { ...@@ -181,6 +205,34 @@ static const struct pci_device_id pmf_pci_ids[] = {
{ } { }
}; };
int amd_pmf_init_metrics_table(struct amd_pmf_dev *dev)
{
u64 phys_addr;
u32 hi, low;
INIT_DELAYED_WORK(&dev->work_buffer, amd_pmf_get_metrics);
/* Get Metrics Table Address */
dev->buf = kzalloc(sizeof(dev->m_table), GFP_KERNEL);
if (!dev->buf)
return -ENOMEM;
phys_addr = virt_to_phys(dev->buf);
hi = phys_addr >> 32;
low = phys_addr & GENMASK(31, 0);
amd_pmf_send_cmd(dev, SET_DRAM_ADDR_HIGH, 0, hi, NULL);
amd_pmf_send_cmd(dev, SET_DRAM_ADDR_LOW, 0, low, NULL);
/*
* Start collecting the metrics data after a small delay
* or else, we might end up getting stale values from PMFW.
*/
schedule_delayed_work(&dev->work_buffer, msecs_to_jiffies(metrics_table_loop_ms * 3));
return 0;
}
static void amd_pmf_init_features(struct amd_pmf_dev *dev) static void amd_pmf_init_features(struct amd_pmf_dev *dev)
{ {
/* Enable Static Slider */ /* Enable Static Slider */
......
...@@ -67,6 +67,41 @@ struct apmf_fan_idx { ...@@ -67,6 +67,41 @@ struct apmf_fan_idx {
u32 fan_ctl_idx; u32 fan_ctl_idx;
} __packed; } __packed;
struct smu_pmf_metrics {
u16 gfxclk_freq; /* in MHz */
u16 socclk_freq; /* in MHz */
u16 vclk_freq; /* in MHz */
u16 dclk_freq; /* in MHz */
u16 memclk_freq; /* in MHz */
u16 spare;
u16 gfx_activity; /* in Centi */
u16 uvd_activity; /* in Centi */
u16 voltage[2]; /* in mV */
u16 currents[2]; /* in mA */
u16 power[2];/* in mW */
u16 core_freq[8]; /* in MHz */
u16 core_power[8]; /* in mW */
u16 core_temp[8]; /* in centi-Celsius */
u16 l3_freq; /* in MHz */
u16 l3_temp; /* in centi-Celsius */
u16 gfx_temp; /* in centi-Celsius */
u16 soc_temp; /* in centi-Celsius */
u16 throttler_status;
u16 current_socketpower; /* in mW */
u16 stapm_orig_limit; /* in W */
u16 stapm_cur_limit; /* in W */
u32 apu_power; /* in mW */
u32 dgpu_power; /* in mW */
u16 vdd_tdc_val; /* in mA */
u16 soc_tdc_val; /* in mA */
u16 vdd_edc_val; /* in mA */
u16 soc_edcv_al; /* in mA */
u16 infra_cpu_maxfreq; /* in MHz */
u16 infra_gfx_maxfreq; /* in MHz */
u16 skin_temp; /* in centi-Celsius */
u16 device_state;
} __packed;
enum amd_stt_skin_temp { enum amd_stt_skin_temp {
STT_TEMP_APU, STT_TEMP_APU,
STT_TEMP_HS2, STT_TEMP_HS2,
...@@ -105,6 +140,9 @@ struct amd_pmf_dev { ...@@ -105,6 +140,9 @@ struct amd_pmf_dev {
struct dentry *dbgfs_dir; struct dentry *dbgfs_dir;
int hb_interval; /* SBIOS heartbeat interval */ int hb_interval; /* SBIOS heartbeat interval */
struct delayed_work heart_beat; struct delayed_work heart_beat;
struct smu_pmf_metrics m_table;
struct delayed_work work_buffer;
ktime_t start_time;
}; };
struct apmf_sps_prop_granular { struct apmf_sps_prop_granular {
...@@ -138,6 +176,7 @@ int apmf_acpi_init(struct amd_pmf_dev *pmf_dev); ...@@ -138,6 +176,7 @@ int apmf_acpi_init(struct amd_pmf_dev *pmf_dev);
void apmf_acpi_deinit(struct amd_pmf_dev *pmf_dev); void apmf_acpi_deinit(struct amd_pmf_dev *pmf_dev);
int is_apmf_func_supported(struct amd_pmf_dev *pdev, unsigned long index); int is_apmf_func_supported(struct amd_pmf_dev *pdev, unsigned long index);
int amd_pmf_send_cmd(struct amd_pmf_dev *dev, u8 message, bool get, u32 arg, u32 *data); int amd_pmf_send_cmd(struct amd_pmf_dev *dev, u8 message, bool get, u32 arg, u32 *data);
int amd_pmf_init_metrics_table(struct amd_pmf_dev *dev);
int amd_pmf_get_power_source(void); int amd_pmf_get_power_source(void);
/* SPS Layer */ /* SPS Layer */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment