Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

platform/x86/amd/pmf: Fix CnQF and auto-mode after resume

After suspend/resume cycle there is an error message and auto-mode
or CnQF stops working.

[ 5741.447511] amd-pmf AMDI0100:00: SMU cmd failed. err: 0xff
[ 5741.447523] amd-pmf AMDI0100:00: AMD_PMF_REGISTER_RESPONSE:ff
[ 5741.447527] amd-pmf AMDI0100:00: AMD_PMF_REGISTER_ARGUMENT:7
[ 5741.447531] amd-pmf AMDI0100:00: AMD_PMF_REGISTER_MESSAGE:16
[ 5741.447540] amd-pmf AMDI0100:00: [AUTO_MODE] avg power: 0 mW mode: QUIET

This is because the DRAM address used for accessing metrics table
needs to be refreshed after a suspend resume cycle. Add a resume
callback to reset this again.

Fixes: 1a409b35c995 ("platform/x86/amd/pmf: Get performance metrics from PMFW")
Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
Link: https://lore.kernel.org/r/20230513011408.958-1-mario.limonciello@amd.com
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>

authored by

Mario Limonciello and committed by
Hans de Goede
b54147fa 362c1f2e

+26 -8
+26 -8
drivers/platform/x86/amd/pmf/core.c
··· 245 245 { } 246 246 }; 247 247 248 - int amd_pmf_init_metrics_table(struct amd_pmf_dev *dev) 248 + static void amd_pmf_set_dram_addr(struct amd_pmf_dev *dev) 249 249 { 250 250 u64 phys_addr; 251 251 u32 hi, low; 252 - 253 - INIT_DELAYED_WORK(&dev->work_buffer, amd_pmf_get_metrics); 254 - 255 - /* Get Metrics Table Address */ 256 - dev->buf = kzalloc(sizeof(dev->m_table), GFP_KERNEL); 257 - if (!dev->buf) 258 - return -ENOMEM; 259 252 260 253 phys_addr = virt_to_phys(dev->buf); 261 254 hi = phys_addr >> 32; ··· 256 263 257 264 amd_pmf_send_cmd(dev, SET_DRAM_ADDR_HIGH, 0, hi, NULL); 258 265 amd_pmf_send_cmd(dev, SET_DRAM_ADDR_LOW, 0, low, NULL); 266 + } 267 + 268 + int amd_pmf_init_metrics_table(struct amd_pmf_dev *dev) 269 + { 270 + /* Get Metrics Table Address */ 271 + dev->buf = kzalloc(sizeof(dev->m_table), GFP_KERNEL); 272 + if (!dev->buf) 273 + return -ENOMEM; 274 + 275 + INIT_DELAYED_WORK(&dev->work_buffer, amd_pmf_get_metrics); 276 + 277 + amd_pmf_set_dram_addr(dev); 259 278 260 279 /* 261 280 * Start collecting the metrics data after a small delay ··· 277 272 278 273 return 0; 279 274 } 275 + 276 + static int amd_pmf_resume_handler(struct device *dev) 277 + { 278 + struct amd_pmf_dev *pdev = dev_get_drvdata(dev); 279 + 280 + if (pdev->buf) 281 + amd_pmf_set_dram_addr(pdev); 282 + 283 + return 0; 284 + } 285 + 286 + static DEFINE_SIMPLE_DEV_PM_OPS(amd_pmf_pm, NULL, amd_pmf_resume_handler); 280 287 281 288 static void amd_pmf_init_features(struct amd_pmf_dev *dev) 282 289 { ··· 430 413 .name = "amd-pmf", 431 414 .acpi_match_table = amd_pmf_acpi_ids, 432 415 .dev_groups = amd_pmf_driver_groups, 416 + .pm = pm_sleep_ptr(&amd_pmf_pm), 433 417 }, 434 418 .probe = amd_pmf_probe, 435 419 .remove_new = amd_pmf_remove,