Commit b54147fa authored by Mario Limonciello's avatar Mario Limonciello Committed by Hans de Goede
Browse files

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: 1a409b35 ("platform/x86/amd/pmf: Get performance metrics from PMFW")
Signed-off-by: default avatarMario Limonciello <mario.limonciello@amd.com>
Link: https://lore.kernel.org/r/20230513011408.958-1-mario.limonciello@amd.com


Reviewed-by: default avatarHans de Goede <hdegoede@redhat.com>
Signed-off-by: default avatarHans de Goede <hdegoede@redhat.com>
parent 362c1f2e
Loading
Loading
Loading
Loading
+25 −7
Original line number Diff line number Diff line
@@ -245,24 +245,29 @@ static const struct pci_device_id pmf_pci_ids[] = {
	{ }
};

int amd_pmf_init_metrics_table(struct amd_pmf_dev *dev)
static void amd_pmf_set_dram_addr(struct amd_pmf_dev *dev)
{
	u64 phys_addr;
	u32 hi, low;

	INIT_DELAYED_WORK(&dev->work_buffer, amd_pmf_get_metrics);
	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);
}

int amd_pmf_init_metrics_table(struct amd_pmf_dev *dev)
{
	/* 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);
	INIT_DELAYED_WORK(&dev->work_buffer, amd_pmf_get_metrics);

	amd_pmf_send_cmd(dev, SET_DRAM_ADDR_HIGH, 0, hi, NULL);
	amd_pmf_send_cmd(dev, SET_DRAM_ADDR_LOW, 0, low, NULL);
	amd_pmf_set_dram_addr(dev);

	/*
	 * Start collecting the metrics data after a small delay
@@ -273,6 +278,18 @@ int amd_pmf_init_metrics_table(struct amd_pmf_dev *dev)
	return 0;
}

static int amd_pmf_resume_handler(struct device *dev)
{
	struct amd_pmf_dev *pdev = dev_get_drvdata(dev);

	if (pdev->buf)
		amd_pmf_set_dram_addr(pdev);

	return 0;
}

static DEFINE_SIMPLE_DEV_PM_OPS(amd_pmf_pm, NULL, amd_pmf_resume_handler);

static void amd_pmf_init_features(struct amd_pmf_dev *dev)
{
	int ret;
@@ -413,6 +430,7 @@ static struct platform_driver amd_pmf_driver = {
		.name = "amd-pmf",
		.acpi_match_table = amd_pmf_acpi_ids,
		.dev_groups = amd_pmf_driver_groups,
		.pm = pm_sleep_ptr(&amd_pmf_pm),
	},
	.probe = amd_pmf_probe,
	.remove_new = amd_pmf_remove,