From: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
The PMF driver retrieves NPU metrics data from the PMFW. Introduce a new
interface to make NPU metrics accessible to other drivers like AMDXDNA
driver, which can access and utilize this information as needed.
Reviewed-by: Mario Limonciello <mario.limonciello@amd.com>
Co-developed-by: Patil Rajesh Reddy <Patil.Reddy@amd.com>
Signed-off-by: Patil Rajesh Reddy <Patil.Reddy@amd.com>
Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
[lizhi: save return value of is_npu_metrics_supported() and return it]
Signed-off-by: Lizhi Hou <lizhi.hou@amd.com>
---
drivers/platform/x86/amd/pmf/core.c | 76 +++++++++++++++++++++++++++++
drivers/platform/x86/amd/pmf/pmf.h | 2 +
include/linux/amd-pmf-io.h | 21 ++++++++
3 files changed, 99 insertions(+)
diff --git a/drivers/platform/x86/amd/pmf/core.c b/drivers/platform/x86/amd/pmf/core.c
index 8fc293c9c538..d180a39e03bf 100644
--- a/drivers/platform/x86/amd/pmf/core.c
+++ b/drivers/platform/x86/amd/pmf/core.c
@@ -8,12 +8,15 @@
* Author: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
*/
+#include <linux/array_size.h>
+#include <linux/cleanup.h>
#include <linux/debugfs.h>
#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/power_supply.h>
+#include <linux/string.h>
#include <asm/amd/node.h>
#include "pmf.h"
@@ -53,6 +56,8 @@ static bool force_load;
module_param(force_load, bool, 0444);
MODULE_PARM_DESC(force_load, "Force load this driver on supported older platforms (experimental)");
+static struct device *pmf_device;
+
static int amd_pmf_pwr_src_notify_call(struct notifier_block *nb, unsigned long event, void *data)
{
struct amd_pmf_dev *pmf = container_of(nb, struct amd_pmf_dev, pwr_src_notifier);
@@ -314,6 +319,71 @@ int amd_pmf_init_metrics_table(struct amd_pmf_dev *dev)
return 0;
}
+static int is_npu_metrics_supported(struct amd_pmf_dev *pdev)
+{
+ switch (pdev->cpu_id) {
+ case PCI_DEVICE_ID_AMD_1AH_M20H_ROOT:
+ case PCI_DEVICE_ID_AMD_1AH_M60H_ROOT:
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int amd_pmf_get_smu_metrics(struct amd_pmf_dev *dev, struct amd_pmf_npu_metrics *data)
+{
+ int ret, i;
+
+ guard(mutex)(&dev->metrics_mutex);
+
+ ret = is_npu_metrics_supported(dev);
+ if (ret)
+ return ret;
+
+ ret = amd_pmf_set_dram_addr(dev, true);
+ if (ret)
+ return ret;
+
+ memset(dev->buf, 0, dev->mtable_size);
+
+ /* Send SMU command to get NPU metrics */
+ ret = amd_pmf_send_cmd(dev, SET_TRANSFER_TABLE, SET_CMD, METRICS_TABLE_ID, NULL);
+ if (ret) {
+ dev_err(dev->dev, "SMU command failed to get NPU metrics: %d\n", ret);
+ return ret;
+ }
+
+ memcpy(&dev->m_table_v2, dev->buf, dev->mtable_size);
+
+ data->npuclk_freq = dev->m_table_v2.npuclk_freq;
+ for (i = 0; i < ARRAY_SIZE(data->npu_busy); i++)
+ data->npu_busy[i] = dev->m_table_v2.npu_busy[i];
+ data->npu_power = dev->m_table_v2.npu_power;
+ data->mpnpuclk_freq = dev->m_table_v2.mpnpuclk_freq;
+ data->npu_reads = dev->m_table_v2.npu_reads;
+ data->npu_writes = dev->m_table_v2.npu_writes;
+
+ return 0;
+}
+
+int amd_pmf_get_npu_data(struct amd_pmf_npu_metrics *info)
+{
+ struct amd_pmf_dev *pdev;
+
+ if (!info)
+ return -EINVAL;
+
+ if (!pmf_device)
+ return -ENODEV;
+
+ pdev = dev_get_drvdata(pmf_device);
+ if (!pdev)
+ return -ENODEV;
+
+ return amd_pmf_get_smu_metrics(pdev, info);
+}
+EXPORT_SYMBOL_GPL(amd_pmf_get_npu_data);
+
static int amd_pmf_suspend_handler(struct device *dev)
{
struct amd_pmf_dev *pdev = dev_get_drvdata(dev);
@@ -477,6 +547,10 @@ static int amd_pmf_probe(struct platform_device *pdev)
if (err)
return err;
+ err = devm_mutex_init(dev->dev, &dev->metrics_mutex);
+ if (err)
+ return err;
+
apmf_acpi_init(dev);
platform_set_drvdata(pdev, dev);
amd_pmf_dbgfs_register(dev);
@@ -485,6 +559,8 @@ static int amd_pmf_probe(struct platform_device *pdev)
if (is_apmf_func_supported(dev, APMF_FUNC_SBIOS_HEARTBEAT_V2))
amd_pmf_notify_sbios_heartbeat_event_v2(dev, ON_LOAD);
+ pmf_device = dev->dev;
+
dev_info(dev->dev, "registered PMF device successfully\n");
return 0;
diff --git a/drivers/platform/x86/amd/pmf/pmf.h b/drivers/platform/x86/amd/pmf/pmf.h
index 9144c8c3bbaf..1bf896c5b92c 100644
--- a/drivers/platform/x86/amd/pmf/pmf.h
+++ b/drivers/platform/x86/amd/pmf/pmf.h
@@ -12,6 +12,7 @@
#define PMF_H
#include <linux/acpi.h>
+#include <linux/amd-pmf-io.h>
#include <linux/input.h>
#include <linux/platform_device.h>
#include <linux/platform_profile.h>
@@ -413,6 +414,7 @@ struct amd_pmf_dev {
struct apmf_sbios_req_v1 req1;
struct pmf_bios_inputs_prev cb_prev; /* To preserve custom BIOS inputs */
bool cb_flag; /* To handle first custom BIOS input */
+ struct mutex metrics_mutex;
};
struct apmf_sps_prop_granular_v2 {
diff --git a/include/linux/amd-pmf-io.h b/include/linux/amd-pmf-io.h
index 6fa510f419c0..55198d2875cc 100644
--- a/include/linux/amd-pmf-io.h
+++ b/include/linux/amd-pmf-io.h
@@ -61,5 +61,26 @@ enum laptop_placement {
LP_UNDEFINED,
};
+/**
+ * struct amd_pmf_npu_metrics: Get NPU metrics data from PMF driver
+ * @npuclk_freq: NPU clock frequency [MHz]
+ * @npu_busy: NPU busy % [0-100]
+ * @npu_power: NPU power [mW]
+ * @mpnpuclk_freq: MPNPU [MHz]
+ * @npu_reads: NPU read bandwidth [MB/sec]
+ * @npu_writes: NPU write bandwidth [MB/sec]
+ */
+struct amd_pmf_npu_metrics {
+ u16 npuclk_freq;
+ u16 npu_busy[8];
+ u16 npu_power;
+ u16 mpnpuclk_freq;
+ u16 npu_reads;
+ u16 npu_writes;
+};
+
int amd_get_sfh_info(struct amd_sfh_info *sfh_info, enum sfh_message_type op);
+
+/* AMD PMF and NPU interface */
+int amd_pmf_get_npu_data(struct amd_pmf_npu_metrics *info);
#endif
--
2.34.1
On Mon, 5 Jan 2026, Lizhi Hou wrote:
> From: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
>
> The PMF driver retrieves NPU metrics data from the PMFW. Introduce a new
> interface to make NPU metrics accessible to other drivers like AMDXDNA
> driver, which can access and utilize this information as needed.
>
> Reviewed-by: Mario Limonciello <mario.limonciello@amd.com>
> Co-developed-by: Patil Rajesh Reddy <Patil.Reddy@amd.com>
> Signed-off-by: Patil Rajesh Reddy <Patil.Reddy@amd.com>
> Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
> [lizhi: save return value of is_npu_metrics_supported() and return it]
> Signed-off-by: Lizhi Hou <lizhi.hou@amd.com>
> ---
> drivers/platform/x86/amd/pmf/core.c | 76 +++++++++++++++++++++++++++++
> drivers/platform/x86/amd/pmf/pmf.h | 2 +
> include/linux/amd-pmf-io.h | 21 ++++++++
> 3 files changed, 99 insertions(+)
>
> diff --git a/drivers/platform/x86/amd/pmf/core.c b/drivers/platform/x86/amd/pmf/core.c
> index 8fc293c9c538..d180a39e03bf 100644
> --- a/drivers/platform/x86/amd/pmf/core.c
> +++ b/drivers/platform/x86/amd/pmf/core.c
> @@ -8,12 +8,15 @@
> * Author: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
> */
>
> +#include <linux/array_size.h>
> +#include <linux/cleanup.h>
> #include <linux/debugfs.h>
> #include <linux/iopoll.h>
> #include <linux/module.h>
> #include <linux/pci.h>
> #include <linux/platform_device.h>
> #include <linux/power_supply.h>
> +#include <linux/string.h>
> #include <asm/amd/node.h>
> #include "pmf.h"
>
> @@ -53,6 +56,8 @@ static bool force_load;
> module_param(force_load, bool, 0444);
> MODULE_PARM_DESC(force_load, "Force load this driver on supported older platforms (experimental)");
>
> +static struct device *pmf_device;
> +
> static int amd_pmf_pwr_src_notify_call(struct notifier_block *nb, unsigned long event, void *data)
> {
> struct amd_pmf_dev *pmf = container_of(nb, struct amd_pmf_dev, pwr_src_notifier);
> @@ -314,6 +319,71 @@ int amd_pmf_init_metrics_table(struct amd_pmf_dev *dev)
> return 0;
> }
>
> +static int is_npu_metrics_supported(struct amd_pmf_dev *pdev)
> +{
> + switch (pdev->cpu_id) {
> + case PCI_DEVICE_ID_AMD_1AH_M20H_ROOT:
> + case PCI_DEVICE_ID_AMD_1AH_M60H_ROOT:
> + return 0;
> + default:
> + return -EOPNOTSUPP;
> + }
> +}
> +
> +static int amd_pmf_get_smu_metrics(struct amd_pmf_dev *dev, struct amd_pmf_npu_metrics *data)
> +{
> + int ret, i;
> +
> + guard(mutex)(&dev->metrics_mutex);
> +
> + ret = is_npu_metrics_supported(dev);
> + if (ret)
> + return ret;
> +
> + ret = amd_pmf_set_dram_addr(dev, true);
> + if (ret)
> + return ret;
> +
> + memset(dev->buf, 0, dev->mtable_size);
> +
> + /* Send SMU command to get NPU metrics */
> + ret = amd_pmf_send_cmd(dev, SET_TRANSFER_TABLE, SET_CMD, METRICS_TABLE_ID, NULL);
> + if (ret) {
> + dev_err(dev->dev, "SMU command failed to get NPU metrics: %d\n", ret);
> + return ret;
> + }
> +
> + memcpy(&dev->m_table_v2, dev->buf, dev->mtable_size);
> +
> + data->npuclk_freq = dev->m_table_v2.npuclk_freq;
> + for (i = 0; i < ARRAY_SIZE(data->npu_busy); i++)
> + data->npu_busy[i] = dev->m_table_v2.npu_busy[i];
> + data->npu_power = dev->m_table_v2.npu_power;
> + data->mpnpuclk_freq = dev->m_table_v2.mpnpuclk_freq;
> + data->npu_reads = dev->m_table_v2.npu_reads;
> + data->npu_writes = dev->m_table_v2.npu_writes;
> +
> + return 0;
> +}
> +
> +int amd_pmf_get_npu_data(struct amd_pmf_npu_metrics *info)
> +{
> + struct amd_pmf_dev *pdev;
> +
> + if (!info)
> + return -EINVAL;
> +
> + if (!pmf_device)
> + return -ENODEV;
> +
> + pdev = dev_get_drvdata(pmf_device);
> + if (!pdev)
> + return -ENODEV;
> +
> + return amd_pmf_get_smu_metrics(pdev, info);
> +}
> +EXPORT_SYMBOL_GPL(amd_pmf_get_npu_data);
One more thing, the export should be namespaced.
And since I'll be applying only this patch and not do an IB, can you also
rebase it on top for the for-next branch.
--
i.
On 1/15/26 07:18, Ilpo Järvinen wrote:
> On Mon, 5 Jan 2026, Lizhi Hou wrote:
>
>> From: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
>>
>> The PMF driver retrieves NPU metrics data from the PMFW. Introduce a new
>> interface to make NPU metrics accessible to other drivers like AMDXDNA
>> driver, which can access and utilize this information as needed.
>>
>> Reviewed-by: Mario Limonciello <mario.limonciello@amd.com>
>> Co-developed-by: Patil Rajesh Reddy <Patil.Reddy@amd.com>
>> Signed-off-by: Patil Rajesh Reddy <Patil.Reddy@amd.com>
>> Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
>> [lizhi: save return value of is_npu_metrics_supported() and return it]
>> Signed-off-by: Lizhi Hou <lizhi.hou@amd.com>
>> ---
>> drivers/platform/x86/amd/pmf/core.c | 76 +++++++++++++++++++++++++++++
>> drivers/platform/x86/amd/pmf/pmf.h | 2 +
>> include/linux/amd-pmf-io.h | 21 ++++++++
>> 3 files changed, 99 insertions(+)
>>
>> diff --git a/drivers/platform/x86/amd/pmf/core.c b/drivers/platform/x86/amd/pmf/core.c
>> index 8fc293c9c538..d180a39e03bf 100644
>> --- a/drivers/platform/x86/amd/pmf/core.c
>> +++ b/drivers/platform/x86/amd/pmf/core.c
>> @@ -8,12 +8,15 @@
>> * Author: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
>> */
>>
>> +#include <linux/array_size.h>
>> +#include <linux/cleanup.h>
>> #include <linux/debugfs.h>
>> #include <linux/iopoll.h>
>> #include <linux/module.h>
>> #include <linux/pci.h>
>> #include <linux/platform_device.h>
>> #include <linux/power_supply.h>
>> +#include <linux/string.h>
>> #include <asm/amd/node.h>
>> #include "pmf.h"
>>
>> @@ -53,6 +56,8 @@ static bool force_load;
>> module_param(force_load, bool, 0444);
>> MODULE_PARM_DESC(force_load, "Force load this driver on supported older platforms (experimental)");
>>
>> +static struct device *pmf_device;
>> +
>> static int amd_pmf_pwr_src_notify_call(struct notifier_block *nb, unsigned long event, void *data)
>> {
>> struct amd_pmf_dev *pmf = container_of(nb, struct amd_pmf_dev, pwr_src_notifier);
>> @@ -314,6 +319,71 @@ int amd_pmf_init_metrics_table(struct amd_pmf_dev *dev)
>> return 0;
>> }
>>
>> +static int is_npu_metrics_supported(struct amd_pmf_dev *pdev)
>> +{
>> + switch (pdev->cpu_id) {
>> + case PCI_DEVICE_ID_AMD_1AH_M20H_ROOT:
>> + case PCI_DEVICE_ID_AMD_1AH_M60H_ROOT:
>> + return 0;
>> + default:
>> + return -EOPNOTSUPP;
>> + }
>> +}
>> +
>> +static int amd_pmf_get_smu_metrics(struct amd_pmf_dev *dev, struct amd_pmf_npu_metrics *data)
>> +{
>> + int ret, i;
>> +
>> + guard(mutex)(&dev->metrics_mutex);
>> +
>> + ret = is_npu_metrics_supported(dev);
>> + if (ret)
>> + return ret;
>> +
>> + ret = amd_pmf_set_dram_addr(dev, true);
>> + if (ret)
>> + return ret;
>> +
>> + memset(dev->buf, 0, dev->mtable_size);
>> +
>> + /* Send SMU command to get NPU metrics */
>> + ret = amd_pmf_send_cmd(dev, SET_TRANSFER_TABLE, SET_CMD, METRICS_TABLE_ID, NULL);
>> + if (ret) {
>> + dev_err(dev->dev, "SMU command failed to get NPU metrics: %d\n", ret);
>> + return ret;
>> + }
>> +
>> + memcpy(&dev->m_table_v2, dev->buf, dev->mtable_size);
>> +
>> + data->npuclk_freq = dev->m_table_v2.npuclk_freq;
>> + for (i = 0; i < ARRAY_SIZE(data->npu_busy); i++)
>> + data->npu_busy[i] = dev->m_table_v2.npu_busy[i];
>> + data->npu_power = dev->m_table_v2.npu_power;
>> + data->mpnpuclk_freq = dev->m_table_v2.mpnpuclk_freq;
>> + data->npu_reads = dev->m_table_v2.npu_reads;
>> + data->npu_writes = dev->m_table_v2.npu_writes;
>> +
>> + return 0;
>> +}
>> +
>> +int amd_pmf_get_npu_data(struct amd_pmf_npu_metrics *info)
>> +{
>> + struct amd_pmf_dev *pdev;
>> +
>> + if (!info)
>> + return -EINVAL;
>> +
>> + if (!pmf_device)
>> + return -ENODEV;
>> +
>> + pdev = dev_get_drvdata(pmf_device);
>> + if (!pdev)
>> + return -ENODEV;
>> +
>> + return amd_pmf_get_smu_metrics(pdev, info);
>> +}
>> +EXPORT_SYMBOL_GPL(amd_pmf_get_npu_data);
> One more thing, the export should be namespaced.
>
> And since I'll be applying only this patch and not do an IB, can you also
> rebase it on top for the for-next branch.
Sure, I will send a V4 patch.
Lizhi
>
On 1/5/2026 22:59, Lizhi Hou wrote:
> From: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
>
> The PMF driver retrieves NPU metrics data from the PMFW. Introduce a new
> interface to make NPU metrics accessible to other drivers like AMDXDNA
> driver, which can access and utilize this information as needed.
>
> Reviewed-by: Mario Limonciello <mario.limonciello@amd.com>
> Co-developed-by: Patil Rajesh Reddy <Patil.Reddy@amd.com>
> Signed-off-by: Patil Rajesh Reddy <Patil.Reddy@amd.com>
> Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
> [lizhi: save return value of is_npu_metrics_supported() and return it]
> Signed-off-by: Lizhi Hou <lizhi.hou@amd.com>
Lizhi, just noticied that this patch may not apply cleanly on
Ilpo-next (which tree does this change land? drm-misc or
platform-x86)? If platform-x86, I can share you a rebased version
offline so that you can wrap into XDNA series.
Thanks,
Shyam
> ---
> drivers/platform/x86/amd/pmf/core.c | 76 +++++++++++++++++++++++++++++
> drivers/platform/x86/amd/pmf/pmf.h | 2 +
> include/linux/amd-pmf-io.h | 21 ++++++++
> 3 files changed, 99 insertions(+)
>
> diff --git a/drivers/platform/x86/amd/pmf/core.c b/drivers/platform/x86/amd/pmf/core.c
> index 8fc293c9c538..d180a39e03bf 100644
> --- a/drivers/platform/x86/amd/pmf/core.c
> +++ b/drivers/platform/x86/amd/pmf/core.c
> @@ -8,12 +8,15 @@
> * Author: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
> */
>
> +#include <linux/array_size.h>
> +#include <linux/cleanup.h>
> #include <linux/debugfs.h>
> #include <linux/iopoll.h>
> #include <linux/module.h>
> #include <linux/pci.h>
> #include <linux/platform_device.h>
> #include <linux/power_supply.h>
> +#include <linux/string.h>
> #include <asm/amd/node.h>
> #include "pmf.h"
>
> @@ -53,6 +56,8 @@ static bool force_load;
> module_param(force_load, bool, 0444);
> MODULE_PARM_DESC(force_load, "Force load this driver on supported older platforms (experimental)");
>
> +static struct device *pmf_device;
> +
> static int amd_pmf_pwr_src_notify_call(struct notifier_block *nb, unsigned long event, void *data)
> {
> struct amd_pmf_dev *pmf = container_of(nb, struct amd_pmf_dev, pwr_src_notifier);
> @@ -314,6 +319,71 @@ int amd_pmf_init_metrics_table(struct amd_pmf_dev *dev)
> return 0;
> }
>
> +static int is_npu_metrics_supported(struct amd_pmf_dev *pdev)
> +{
> + switch (pdev->cpu_id) {
> + case PCI_DEVICE_ID_AMD_1AH_M20H_ROOT:
> + case PCI_DEVICE_ID_AMD_1AH_M60H_ROOT:
> + return 0;
> + default:
> + return -EOPNOTSUPP;
> + }
> +}
> +
> +static int amd_pmf_get_smu_metrics(struct amd_pmf_dev *dev, struct amd_pmf_npu_metrics *data)
> +{
> + int ret, i;
> +
> + guard(mutex)(&dev->metrics_mutex);
> +
> + ret = is_npu_metrics_supported(dev);
> + if (ret)
> + return ret;
> +
> + ret = amd_pmf_set_dram_addr(dev, true);
> + if (ret)
> + return ret;
> +
> + memset(dev->buf, 0, dev->mtable_size);
> +
> + /* Send SMU command to get NPU metrics */
> + ret = amd_pmf_send_cmd(dev, SET_TRANSFER_TABLE, SET_CMD, METRICS_TABLE_ID, NULL);
> + if (ret) {
> + dev_err(dev->dev, "SMU command failed to get NPU metrics: %d\n", ret);
> + return ret;
> + }
> +
> + memcpy(&dev->m_table_v2, dev->buf, dev->mtable_size);
> +
> + data->npuclk_freq = dev->m_table_v2.npuclk_freq;
> + for (i = 0; i < ARRAY_SIZE(data->npu_busy); i++)
> + data->npu_busy[i] = dev->m_table_v2.npu_busy[i];
> + data->npu_power = dev->m_table_v2.npu_power;
> + data->mpnpuclk_freq = dev->m_table_v2.mpnpuclk_freq;
> + data->npu_reads = dev->m_table_v2.npu_reads;
> + data->npu_writes = dev->m_table_v2.npu_writes;
> +
> + return 0;
> +}
> +
> +int amd_pmf_get_npu_data(struct amd_pmf_npu_metrics *info)
> +{
> + struct amd_pmf_dev *pdev;
> +
> + if (!info)
> + return -EINVAL;
> +
> + if (!pmf_device)
> + return -ENODEV;
> +
> + pdev = dev_get_drvdata(pmf_device);
> + if (!pdev)
> + return -ENODEV;
> +
> + return amd_pmf_get_smu_metrics(pdev, info);
> +}
> +EXPORT_SYMBOL_GPL(amd_pmf_get_npu_data);
> +
> static int amd_pmf_suspend_handler(struct device *dev)
> {
> struct amd_pmf_dev *pdev = dev_get_drvdata(dev);
> @@ -477,6 +547,10 @@ static int amd_pmf_probe(struct platform_device *pdev)
> if (err)
> return err;
>
> + err = devm_mutex_init(dev->dev, &dev->metrics_mutex);
> + if (err)
> + return err;
> +
> apmf_acpi_init(dev);
> platform_set_drvdata(pdev, dev);
> amd_pmf_dbgfs_register(dev);
> @@ -485,6 +559,8 @@ static int amd_pmf_probe(struct platform_device *pdev)
> if (is_apmf_func_supported(dev, APMF_FUNC_SBIOS_HEARTBEAT_V2))
> amd_pmf_notify_sbios_heartbeat_event_v2(dev, ON_LOAD);
>
> + pmf_device = dev->dev;
> +
> dev_info(dev->dev, "registered PMF device successfully\n");
>
> return 0;
> diff --git a/drivers/platform/x86/amd/pmf/pmf.h b/drivers/platform/x86/amd/pmf/pmf.h
> index 9144c8c3bbaf..1bf896c5b92c 100644
> --- a/drivers/platform/x86/amd/pmf/pmf.h
> +++ b/drivers/platform/x86/amd/pmf/pmf.h
> @@ -12,6 +12,7 @@
> #define PMF_H
>
> #include <linux/acpi.h>
> +#include <linux/amd-pmf-io.h>
> #include <linux/input.h>
> #include <linux/platform_device.h>
> #include <linux/platform_profile.h>
> @@ -413,6 +414,7 @@ struct amd_pmf_dev {
> struct apmf_sbios_req_v1 req1;
> struct pmf_bios_inputs_prev cb_prev; /* To preserve custom BIOS inputs */
> bool cb_flag; /* To handle first custom BIOS input */
> + struct mutex metrics_mutex;
> };
>
> struct apmf_sps_prop_granular_v2 {
> diff --git a/include/linux/amd-pmf-io.h b/include/linux/amd-pmf-io.h
> index 6fa510f419c0..55198d2875cc 100644
> --- a/include/linux/amd-pmf-io.h
> +++ b/include/linux/amd-pmf-io.h
> @@ -61,5 +61,26 @@ enum laptop_placement {
> LP_UNDEFINED,
> };
>
> +/**
> + * struct amd_pmf_npu_metrics: Get NPU metrics data from PMF driver
> + * @npuclk_freq: NPU clock frequency [MHz]
> + * @npu_busy: NPU busy % [0-100]
> + * @npu_power: NPU power [mW]
> + * @mpnpuclk_freq: MPNPU [MHz]
> + * @npu_reads: NPU read bandwidth [MB/sec]
> + * @npu_writes: NPU write bandwidth [MB/sec]
> + */
> +struct amd_pmf_npu_metrics {
> + u16 npuclk_freq;
> + u16 npu_busy[8];
> + u16 npu_power;
> + u16 mpnpuclk_freq;
> + u16 npu_reads;
> + u16 npu_writes;
> +};
> +
> int amd_get_sfh_info(struct amd_sfh_info *sfh_info, enum sfh_message_type op);
> +
> +/* AMD PMF and NPU interface */
> +int amd_pmf_get_npu_data(struct amd_pmf_npu_metrics *info);
> #endif
On 1/6/26 05:19, Shyam Sundar S K wrote:
>
> On 1/5/2026 22:59, Lizhi Hou wrote:
>> From: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
>>
>> The PMF driver retrieves NPU metrics data from the PMFW. Introduce a new
>> interface to make NPU metrics accessible to other drivers like AMDXDNA
>> driver, which can access and utilize this information as needed.
>>
>> Reviewed-by: Mario Limonciello <mario.limonciello@amd.com>
>> Co-developed-by: Patil Rajesh Reddy <Patil.Reddy@amd.com>
>> Signed-off-by: Patil Rajesh Reddy <Patil.Reddy@amd.com>
>> Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
>> [lizhi: save return value of is_npu_metrics_supported() and return it]
>> Signed-off-by: Lizhi Hou <lizhi.hou@amd.com>
> Lizhi, just noticied that this patch may not apply cleanly on
> Ilpo-next (which tree does this change land? drm-misc or
> platform-x86)? If platform-x86, I can share you a rebased version
I used drm-misc.
Lizhi
> offline so that you can wrap into XDNA series.
>
> Thanks,
> Shyam
>
>> ---
>> drivers/platform/x86/amd/pmf/core.c | 76 +++++++++++++++++++++++++++++
>> drivers/platform/x86/amd/pmf/pmf.h | 2 +
>> include/linux/amd-pmf-io.h | 21 ++++++++
>> 3 files changed, 99 insertions(+)
>>
>> diff --git a/drivers/platform/x86/amd/pmf/core.c b/drivers/platform/x86/amd/pmf/core.c
>> index 8fc293c9c538..d180a39e03bf 100644
>> --- a/drivers/platform/x86/amd/pmf/core.c
>> +++ b/drivers/platform/x86/amd/pmf/core.c
>> @@ -8,12 +8,15 @@
>> * Author: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
>> */
>>
>> +#include <linux/array_size.h>
>> +#include <linux/cleanup.h>
>> #include <linux/debugfs.h>
>> #include <linux/iopoll.h>
>> #include <linux/module.h>
>> #include <linux/pci.h>
>> #include <linux/platform_device.h>
>> #include <linux/power_supply.h>
>> +#include <linux/string.h>
>> #include <asm/amd/node.h>
>> #include "pmf.h"
>>
>> @@ -53,6 +56,8 @@ static bool force_load;
>> module_param(force_load, bool, 0444);
>> MODULE_PARM_DESC(force_load, "Force load this driver on supported older platforms (experimental)");
>>
>> +static struct device *pmf_device;
>> +
>> static int amd_pmf_pwr_src_notify_call(struct notifier_block *nb, unsigned long event, void *data)
>> {
>> struct amd_pmf_dev *pmf = container_of(nb, struct amd_pmf_dev, pwr_src_notifier);
>> @@ -314,6 +319,71 @@ int amd_pmf_init_metrics_table(struct amd_pmf_dev *dev)
>> return 0;
>> }
>>
>> +static int is_npu_metrics_supported(struct amd_pmf_dev *pdev)
>> +{
>> + switch (pdev->cpu_id) {
>> + case PCI_DEVICE_ID_AMD_1AH_M20H_ROOT:
>> + case PCI_DEVICE_ID_AMD_1AH_M60H_ROOT:
>> + return 0;
>> + default:
>> + return -EOPNOTSUPP;
>> + }
>> +}
>> +
>> +static int amd_pmf_get_smu_metrics(struct amd_pmf_dev *dev, struct amd_pmf_npu_metrics *data)
>> +{
>> + int ret, i;
>> +
>> + guard(mutex)(&dev->metrics_mutex);
>> +
>> + ret = is_npu_metrics_supported(dev);
>> + if (ret)
>> + return ret;
>> +
>> + ret = amd_pmf_set_dram_addr(dev, true);
>> + if (ret)
>> + return ret;
>> +
>> + memset(dev->buf, 0, dev->mtable_size);
>> +
>> + /* Send SMU command to get NPU metrics */
>> + ret = amd_pmf_send_cmd(dev, SET_TRANSFER_TABLE, SET_CMD, METRICS_TABLE_ID, NULL);
>> + if (ret) {
>> + dev_err(dev->dev, "SMU command failed to get NPU metrics: %d\n", ret);
>> + return ret;
>> + }
>> +
>> + memcpy(&dev->m_table_v2, dev->buf, dev->mtable_size);
>> +
>> + data->npuclk_freq = dev->m_table_v2.npuclk_freq;
>> + for (i = 0; i < ARRAY_SIZE(data->npu_busy); i++)
>> + data->npu_busy[i] = dev->m_table_v2.npu_busy[i];
>> + data->npu_power = dev->m_table_v2.npu_power;
>> + data->mpnpuclk_freq = dev->m_table_v2.mpnpuclk_freq;
>> + data->npu_reads = dev->m_table_v2.npu_reads;
>> + data->npu_writes = dev->m_table_v2.npu_writes;
>> +
>> + return 0;
>> +}
>> +
>> +int amd_pmf_get_npu_data(struct amd_pmf_npu_metrics *info)
>> +{
>> + struct amd_pmf_dev *pdev;
>> +
>> + if (!info)
>> + return -EINVAL;
>> +
>> + if (!pmf_device)
>> + return -ENODEV;
>> +
>> + pdev = dev_get_drvdata(pmf_device);
>> + if (!pdev)
>> + return -ENODEV;
>> +
>> + return amd_pmf_get_smu_metrics(pdev, info);
>> +}
>> +EXPORT_SYMBOL_GPL(amd_pmf_get_npu_data);
>> +
>> static int amd_pmf_suspend_handler(struct device *dev)
>> {
>> struct amd_pmf_dev *pdev = dev_get_drvdata(dev);
>> @@ -477,6 +547,10 @@ static int amd_pmf_probe(struct platform_device *pdev)
>> if (err)
>> return err;
>>
>> + err = devm_mutex_init(dev->dev, &dev->metrics_mutex);
>> + if (err)
>> + return err;
>> +
>> apmf_acpi_init(dev);
>> platform_set_drvdata(pdev, dev);
>> amd_pmf_dbgfs_register(dev);
>> @@ -485,6 +559,8 @@ static int amd_pmf_probe(struct platform_device *pdev)
>> if (is_apmf_func_supported(dev, APMF_FUNC_SBIOS_HEARTBEAT_V2))
>> amd_pmf_notify_sbios_heartbeat_event_v2(dev, ON_LOAD);
>>
>> + pmf_device = dev->dev;
>> +
>> dev_info(dev->dev, "registered PMF device successfully\n");
>>
>> return 0;
>> diff --git a/drivers/platform/x86/amd/pmf/pmf.h b/drivers/platform/x86/amd/pmf/pmf.h
>> index 9144c8c3bbaf..1bf896c5b92c 100644
>> --- a/drivers/platform/x86/amd/pmf/pmf.h
>> +++ b/drivers/platform/x86/amd/pmf/pmf.h
>> @@ -12,6 +12,7 @@
>> #define PMF_H
>>
>> #include <linux/acpi.h>
>> +#include <linux/amd-pmf-io.h>
>> #include <linux/input.h>
>> #include <linux/platform_device.h>
>> #include <linux/platform_profile.h>
>> @@ -413,6 +414,7 @@ struct amd_pmf_dev {
>> struct apmf_sbios_req_v1 req1;
>> struct pmf_bios_inputs_prev cb_prev; /* To preserve custom BIOS inputs */
>> bool cb_flag; /* To handle first custom BIOS input */
>> + struct mutex metrics_mutex;
>> };
>>
>> struct apmf_sps_prop_granular_v2 {
>> diff --git a/include/linux/amd-pmf-io.h b/include/linux/amd-pmf-io.h
>> index 6fa510f419c0..55198d2875cc 100644
>> --- a/include/linux/amd-pmf-io.h
>> +++ b/include/linux/amd-pmf-io.h
>> @@ -61,5 +61,26 @@ enum laptop_placement {
>> LP_UNDEFINED,
>> };
>>
>> +/**
>> + * struct amd_pmf_npu_metrics: Get NPU metrics data from PMF driver
>> + * @npuclk_freq: NPU clock frequency [MHz]
>> + * @npu_busy: NPU busy % [0-100]
>> + * @npu_power: NPU power [mW]
>> + * @mpnpuclk_freq: MPNPU [MHz]
>> + * @npu_reads: NPU read bandwidth [MB/sec]
>> + * @npu_writes: NPU write bandwidth [MB/sec]
>> + */
>> +struct amd_pmf_npu_metrics {
>> + u16 npuclk_freq;
>> + u16 npu_busy[8];
>> + u16 npu_power;
>> + u16 mpnpuclk_freq;
>> + u16 npu_reads;
>> + u16 npu_writes;
>> +};
>> +
>> int amd_get_sfh_info(struct amd_sfh_info *sfh_info, enum sfh_message_type op);
>> +
>> +/* AMD PMF and NPU interface */
>> +int amd_pmf_get_npu_data(struct amd_pmf_npu_metrics *info);
>> #endif
Hi Ilpo,
What should be the next step? Should I generate both patches based on
review-ilpo-next? Will the amdxdna change upstream through platform-x86
tree?
Thanks,
Lizhi
On 1/6/26 08:16, Lizhi Hou wrote:
>
> On 1/6/26 05:19, Shyam Sundar S K wrote:
>>
>> On 1/5/2026 22:59, Lizhi Hou wrote:
>>> From: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
>>>
>>> The PMF driver retrieves NPU metrics data from the PMFW. Introduce a
>>> new
>>> interface to make NPU metrics accessible to other drivers like AMDXDNA
>>> driver, which can access and utilize this information as needed.
>>>
>>> Reviewed-by: Mario Limonciello <mario.limonciello@amd.com>
>>> Co-developed-by: Patil Rajesh Reddy <Patil.Reddy@amd.com>
>>> Signed-off-by: Patil Rajesh Reddy <Patil.Reddy@amd.com>
>>> Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
>>> [lizhi: save return value of is_npu_metrics_supported() and return it]
>>> Signed-off-by: Lizhi Hou <lizhi.hou@amd.com>
>> Lizhi, just noticied that this patch may not apply cleanly on
>> Ilpo-next (which tree does this change land? drm-misc or
>> platform-x86)? If platform-x86, I can share you a rebased version
>
> I used drm-misc.
>
> Lizhi
>
>> offline so that you can wrap into XDNA series.
>>
>> Thanks,
>> Shyam
>>
>>> ---
>>> drivers/platform/x86/amd/pmf/core.c | 76
>>> +++++++++++++++++++++++++++++
>>> drivers/platform/x86/amd/pmf/pmf.h | 2 +
>>> include/linux/amd-pmf-io.h | 21 ++++++++
>>> 3 files changed, 99 insertions(+)
>>>
>>> diff --git a/drivers/platform/x86/amd/pmf/core.c
>>> b/drivers/platform/x86/amd/pmf/core.c
>>> index 8fc293c9c538..d180a39e03bf 100644
>>> --- a/drivers/platform/x86/amd/pmf/core.c
>>> +++ b/drivers/platform/x86/amd/pmf/core.c
>>> @@ -8,12 +8,15 @@
>>> * Author: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
>>> */
>>> +#include <linux/array_size.h>
>>> +#include <linux/cleanup.h>
>>> #include <linux/debugfs.h>
>>> #include <linux/iopoll.h>
>>> #include <linux/module.h>
>>> #include <linux/pci.h>
>>> #include <linux/platform_device.h>
>>> #include <linux/power_supply.h>
>>> +#include <linux/string.h>
>>> #include <asm/amd/node.h>
>>> #include "pmf.h"
>>> @@ -53,6 +56,8 @@ static bool force_load;
>>> module_param(force_load, bool, 0444);
>>> MODULE_PARM_DESC(force_load, "Force load this driver on supported
>>> older platforms (experimental)");
>>> +static struct device *pmf_device;
>>> +
>>> static int amd_pmf_pwr_src_notify_call(struct notifier_block *nb,
>>> unsigned long event, void *data)
>>> {
>>> struct amd_pmf_dev *pmf = container_of(nb, struct amd_pmf_dev,
>>> pwr_src_notifier);
>>> @@ -314,6 +319,71 @@ int amd_pmf_init_metrics_table(struct
>>> amd_pmf_dev *dev)
>>> return 0;
>>> }
>>> +static int is_npu_metrics_supported(struct amd_pmf_dev *pdev)
>>> +{
>>> + switch (pdev->cpu_id) {
>>> + case PCI_DEVICE_ID_AMD_1AH_M20H_ROOT:
>>> + case PCI_DEVICE_ID_AMD_1AH_M60H_ROOT:
>>> + return 0;
>>> + default:
>>> + return -EOPNOTSUPP;
>>> + }
>>> +}
>>> +
>>> +static int amd_pmf_get_smu_metrics(struct amd_pmf_dev *dev, struct
>>> amd_pmf_npu_metrics *data)
>>> +{
>>> + int ret, i;
>>> +
>>> + guard(mutex)(&dev->metrics_mutex);
>>> +
>>> + ret = is_npu_metrics_supported(dev);
>>> + if (ret)
>>> + return ret;
>>> +
>>> + ret = amd_pmf_set_dram_addr(dev, true);
>>> + if (ret)
>>> + return ret;
>>> +
>>> + memset(dev->buf, 0, dev->mtable_size);
>>> +
>>> + /* Send SMU command to get NPU metrics */
>>> + ret = amd_pmf_send_cmd(dev, SET_TRANSFER_TABLE, SET_CMD,
>>> METRICS_TABLE_ID, NULL);
>>> + if (ret) {
>>> + dev_err(dev->dev, "SMU command failed to get NPU metrics:
>>> %d\n", ret);
>>> + return ret;
>>> + }
>>> +
>>> + memcpy(&dev->m_table_v2, dev->buf, dev->mtable_size);
>>> +
>>> + data->npuclk_freq = dev->m_table_v2.npuclk_freq;
>>> + for (i = 0; i < ARRAY_SIZE(data->npu_busy); i++)
>>> + data->npu_busy[i] = dev->m_table_v2.npu_busy[i];
>>> + data->npu_power = dev->m_table_v2.npu_power;
>>> + data->mpnpuclk_freq = dev->m_table_v2.mpnpuclk_freq;
>>> + data->npu_reads = dev->m_table_v2.npu_reads;
>>> + data->npu_writes = dev->m_table_v2.npu_writes;
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +int amd_pmf_get_npu_data(struct amd_pmf_npu_metrics *info)
>>> +{
>>> + struct amd_pmf_dev *pdev;
>>> +
>>> + if (!info)
>>> + return -EINVAL;
>>> +
>>> + if (!pmf_device)
>>> + return -ENODEV;
>>> +
>>> + pdev = dev_get_drvdata(pmf_device);
>>> + if (!pdev)
>>> + return -ENODEV;
>>> +
>>> + return amd_pmf_get_smu_metrics(pdev, info);
>>> +}
>>> +EXPORT_SYMBOL_GPL(amd_pmf_get_npu_data);
>>> +
>>> static int amd_pmf_suspend_handler(struct device *dev)
>>> {
>>> struct amd_pmf_dev *pdev = dev_get_drvdata(dev);
>>> @@ -477,6 +547,10 @@ static int amd_pmf_probe(struct platform_device
>>> *pdev)
>>> if (err)
>>> return err;
>>> + err = devm_mutex_init(dev->dev, &dev->metrics_mutex);
>>> + if (err)
>>> + return err;
>>> +
>>> apmf_acpi_init(dev);
>>> platform_set_drvdata(pdev, dev);
>>> amd_pmf_dbgfs_register(dev);
>>> @@ -485,6 +559,8 @@ static int amd_pmf_probe(struct platform_device
>>> *pdev)
>>> if (is_apmf_func_supported(dev, APMF_FUNC_SBIOS_HEARTBEAT_V2))
>>> amd_pmf_notify_sbios_heartbeat_event_v2(dev, ON_LOAD);
>>> + pmf_device = dev->dev;
>>> +
>>> dev_info(dev->dev, "registered PMF device successfully\n");
>>> return 0;
>>> diff --git a/drivers/platform/x86/amd/pmf/pmf.h
>>> b/drivers/platform/x86/amd/pmf/pmf.h
>>> index 9144c8c3bbaf..1bf896c5b92c 100644
>>> --- a/drivers/platform/x86/amd/pmf/pmf.h
>>> +++ b/drivers/platform/x86/amd/pmf/pmf.h
>>> @@ -12,6 +12,7 @@
>>> #define PMF_H
>>> #include <linux/acpi.h>
>>> +#include <linux/amd-pmf-io.h>
>>> #include <linux/input.h>
>>> #include <linux/platform_device.h>
>>> #include <linux/platform_profile.h>
>>> @@ -413,6 +414,7 @@ struct amd_pmf_dev {
>>> struct apmf_sbios_req_v1 req1;
>>> struct pmf_bios_inputs_prev cb_prev; /* To preserve custom
>>> BIOS inputs */
>>> bool cb_flag; /* To handle first custom BIOS
>>> input */
>>> + struct mutex metrics_mutex;
>>> };
>>> struct apmf_sps_prop_granular_v2 {
>>> diff --git a/include/linux/amd-pmf-io.h b/include/linux/amd-pmf-io.h
>>> index 6fa510f419c0..55198d2875cc 100644
>>> --- a/include/linux/amd-pmf-io.h
>>> +++ b/include/linux/amd-pmf-io.h
>>> @@ -61,5 +61,26 @@ enum laptop_placement {
>>> LP_UNDEFINED,
>>> };
>>> +/**
>>> + * struct amd_pmf_npu_metrics: Get NPU metrics data from PMF driver
>>> + * @npuclk_freq: NPU clock frequency [MHz]
>>> + * @npu_busy: NPU busy % [0-100]
>>> + * @npu_power: NPU power [mW]
>>> + * @mpnpuclk_freq: MPNPU [MHz]
>>> + * @npu_reads: NPU read bandwidth [MB/sec]
>>> + * @npu_writes: NPU write bandwidth [MB/sec]
>>> + */
>>> +struct amd_pmf_npu_metrics {
>>> + u16 npuclk_freq;
>>> + u16 npu_busy[8];
>>> + u16 npu_power;
>>> + u16 mpnpuclk_freq;
>>> + u16 npu_reads;
>>> + u16 npu_writes;
>>> +};
>>> +
>>> int amd_get_sfh_info(struct amd_sfh_info *sfh_info, enum
>>> sfh_message_type op);
>>> +
>>> +/* AMD PMF and NPU interface */
>>> +int amd_pmf_get_npu_data(struct amd_pmf_npu_metrics *info);
>>> #endif
On Tue, 6 Jan 2026, Lizhi Hou wrote:
> What should be the next step? Should I generate both patches based on
> review-ilpo-next? Will the amdxdna change upstream through platform-x86 tree?
(We seemed to have crossed emails.)
That would work for me too, but I thought it was wanted that patch 2 to
go through accel?
--
i.
> On 1/6/26 08:16, Lizhi Hou wrote:
> >
> > On 1/6/26 05:19, Shyam Sundar S K wrote:
> > >
> > > On 1/5/2026 22:59, Lizhi Hou wrote:
> > > > From: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
> > > >
> > > > The PMF driver retrieves NPU metrics data from the PMFW. Introduce a new
> > > > interface to make NPU metrics accessible to other drivers like AMDXDNA
> > > > driver, which can access and utilize this information as needed.
> > > >
> > > > Reviewed-by: Mario Limonciello <mario.limonciello@amd.com>
> > > > Co-developed-by: Patil Rajesh Reddy <Patil.Reddy@amd.com>
> > > > Signed-off-by: Patil Rajesh Reddy <Patil.Reddy@amd.com>
> > > > Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
> > > > [lizhi: save return value of is_npu_metrics_supported() and return it]
> > > > Signed-off-by: Lizhi Hou <lizhi.hou@amd.com>
> > > Lizhi, just noticied that this patch may not apply cleanly on
> > > Ilpo-next (which tree does this change land? drm-misc or
> > > platform-x86)? If platform-x86, I can share you a rebased version
> >
> > I used drm-misc.
> >
> > Lizhi
> >
> > > offline so that you can wrap into XDNA series.
> > >
> > > Thanks,
> > > Shyam
> > >
> > > > ---
> > > > drivers/platform/x86/amd/pmf/core.c | 76 +++++++++++++++++++++++++++++
> > > > drivers/platform/x86/amd/pmf/pmf.h | 2 +
> > > > include/linux/amd-pmf-io.h | 21 ++++++++
> > > > 3 files changed, 99 insertions(+)
> > > >
> > > > diff --git a/drivers/platform/x86/amd/pmf/core.c
> > > > b/drivers/platform/x86/amd/pmf/core.c
> > > > index 8fc293c9c538..d180a39e03bf 100644
> > > > --- a/drivers/platform/x86/amd/pmf/core.c
> > > > +++ b/drivers/platform/x86/amd/pmf/core.c
> > > > @@ -8,12 +8,15 @@
> > > > * Author: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
> > > > */
> > > > +#include <linux/array_size.h>
> > > > +#include <linux/cleanup.h>
> > > > #include <linux/debugfs.h>
> > > > #include <linux/iopoll.h>
> > > > #include <linux/module.h>
> > > > #include <linux/pci.h>
> > > > #include <linux/platform_device.h>
> > > > #include <linux/power_supply.h>
> > > > +#include <linux/string.h>
> > > > #include <asm/amd/node.h>
> > > > #include "pmf.h"
> > > > @@ -53,6 +56,8 @@ static bool force_load;
> > > > module_param(force_load, bool, 0444);
> > > > MODULE_PARM_DESC(force_load, "Force load this driver on supported
> > > > older platforms (experimental)");
> > > > +static struct device *pmf_device;
> > > > +
> > > > static int amd_pmf_pwr_src_notify_call(struct notifier_block *nb,
> > > > unsigned long event, void *data)
> > > > {
> > > > struct amd_pmf_dev *pmf = container_of(nb, struct amd_pmf_dev,
> > > > pwr_src_notifier);
> > > > @@ -314,6 +319,71 @@ int amd_pmf_init_metrics_table(struct amd_pmf_dev
> > > > *dev)
> > > > return 0;
> > > > }
> > > > +static int is_npu_metrics_supported(struct amd_pmf_dev *pdev)
> > > > +{
> > > > + switch (pdev->cpu_id) {
> > > > + case PCI_DEVICE_ID_AMD_1AH_M20H_ROOT:
> > > > + case PCI_DEVICE_ID_AMD_1AH_M60H_ROOT:
> > > > + return 0;
> > > > + default:
> > > > + return -EOPNOTSUPP;
> > > > + }
> > > > +}
> > > > +
> > > > +static int amd_pmf_get_smu_metrics(struct amd_pmf_dev *dev, struct
> > > > amd_pmf_npu_metrics *data)
> > > > +{
> > > > + int ret, i;
> > > > +
> > > > + guard(mutex)(&dev->metrics_mutex);
> > > > +
> > > > + ret = is_npu_metrics_supported(dev);
> > > > + if (ret)
> > > > + return ret;
> > > > +
> > > > + ret = amd_pmf_set_dram_addr(dev, true);
> > > > + if (ret)
> > > > + return ret;
> > > > +
> > > > + memset(dev->buf, 0, dev->mtable_size);
> > > > +
> > > > + /* Send SMU command to get NPU metrics */
> > > > + ret = amd_pmf_send_cmd(dev, SET_TRANSFER_TABLE, SET_CMD,
> > > > METRICS_TABLE_ID, NULL);
> > > > + if (ret) {
> > > > + dev_err(dev->dev, "SMU command failed to get NPU metrics:
> > > > %d\n", ret);
> > > > + return ret;
> > > > + }
> > > > +
> > > > + memcpy(&dev->m_table_v2, dev->buf, dev->mtable_size);
> > > > +
> > > > + data->npuclk_freq = dev->m_table_v2.npuclk_freq;
> > > > + for (i = 0; i < ARRAY_SIZE(data->npu_busy); i++)
> > > > + data->npu_busy[i] = dev->m_table_v2.npu_busy[i];
> > > > + data->npu_power = dev->m_table_v2.npu_power;
> > > > + data->mpnpuclk_freq = dev->m_table_v2.mpnpuclk_freq;
> > > > + data->npu_reads = dev->m_table_v2.npu_reads;
> > > > + data->npu_writes = dev->m_table_v2.npu_writes;
> > > > +
> > > > + return 0;
> > > > +}
> > > > +
> > > > +int amd_pmf_get_npu_data(struct amd_pmf_npu_metrics *info)
> > > > +{
> > > > + struct amd_pmf_dev *pdev;
> > > > +
> > > > + if (!info)
> > > > + return -EINVAL;
> > > > +
> > > > + if (!pmf_device)
> > > > + return -ENODEV;
> > > > +
> > > > + pdev = dev_get_drvdata(pmf_device);
> > > > + if (!pdev)
> > > > + return -ENODEV;
> > > > +
> > > > + return amd_pmf_get_smu_metrics(pdev, info);
> > > > +}
> > > > +EXPORT_SYMBOL_GPL(amd_pmf_get_npu_data);
> > > > +
> > > > static int amd_pmf_suspend_handler(struct device *dev)
> > > > {
> > > > struct amd_pmf_dev *pdev = dev_get_drvdata(dev);
> > > > @@ -477,6 +547,10 @@ static int amd_pmf_probe(struct platform_device
> > > > *pdev)
> > > > if (err)
> > > > return err;
> > > > + err = devm_mutex_init(dev->dev, &dev->metrics_mutex);
> > > > + if (err)
> > > > + return err;
> > > > +
> > > > apmf_acpi_init(dev);
> > > > platform_set_drvdata(pdev, dev);
> > > > amd_pmf_dbgfs_register(dev);
> > > > @@ -485,6 +559,8 @@ static int amd_pmf_probe(struct platform_device
> > > > *pdev)
> > > > if (is_apmf_func_supported(dev, APMF_FUNC_SBIOS_HEARTBEAT_V2))
> > > > amd_pmf_notify_sbios_heartbeat_event_v2(dev, ON_LOAD);
> > > > + pmf_device = dev->dev;
> > > > +
> > > > dev_info(dev->dev, "registered PMF device successfully\n");
> > > > return 0;
> > > > diff --git a/drivers/platform/x86/amd/pmf/pmf.h
> > > > b/drivers/platform/x86/amd/pmf/pmf.h
> > > > index 9144c8c3bbaf..1bf896c5b92c 100644
> > > > --- a/drivers/platform/x86/amd/pmf/pmf.h
> > > > +++ b/drivers/platform/x86/amd/pmf/pmf.h
> > > > @@ -12,6 +12,7 @@
> > > > #define PMF_H
> > > > #include <linux/acpi.h>
> > > > +#include <linux/amd-pmf-io.h>
> > > > #include <linux/input.h>
> > > > #include <linux/platform_device.h>
> > > > #include <linux/platform_profile.h>
> > > > @@ -413,6 +414,7 @@ struct amd_pmf_dev {
> > > > struct apmf_sbios_req_v1 req1;
> > > > struct pmf_bios_inputs_prev cb_prev; /* To preserve custom BIOS
> > > > inputs */
> > > > bool cb_flag; /* To handle first custom BIOS input
> > > > */
> > > > + struct mutex metrics_mutex;
> > > > };
> > > > struct apmf_sps_prop_granular_v2 {
> > > > diff --git a/include/linux/amd-pmf-io.h b/include/linux/amd-pmf-io.h
> > > > index 6fa510f419c0..55198d2875cc 100644
> > > > --- a/include/linux/amd-pmf-io.h
> > > > +++ b/include/linux/amd-pmf-io.h
> > > > @@ -61,5 +61,26 @@ enum laptop_placement {
> > > > LP_UNDEFINED,
> > > > };
> > > > +/**
> > > > + * struct amd_pmf_npu_metrics: Get NPU metrics data from PMF driver
> > > > + * @npuclk_freq: NPU clock frequency [MHz]
> > > > + * @npu_busy: NPU busy % [0-100]
> > > > + * @npu_power: NPU power [mW]
> > > > + * @mpnpuclk_freq: MPNPU [MHz]
> > > > + * @npu_reads: NPU read bandwidth [MB/sec]
> > > > + * @npu_writes: NPU write bandwidth [MB/sec]
> > > > + */
> > > > +struct amd_pmf_npu_metrics {
> > > > + u16 npuclk_freq;
> > > > + u16 npu_busy[8];
> > > > + u16 npu_power;
> > > > + u16 mpnpuclk_freq;
> > > > + u16 npu_reads;
> > > > + u16 npu_writes;
> > > > +};
> > > > +
> > > > int amd_get_sfh_info(struct amd_sfh_info *sfh_info, enum
> > > > sfh_message_type op);
> > > > +
> > > > +/* AMD PMF and NPU interface */
> > > > +int amd_pmf_get_npu_data(struct amd_pmf_npu_metrics *info);
> > > > #endif
>
On 1/6/26 09:09, Ilpo Järvinen wrote: > On Tue, 6 Jan 2026, Lizhi Hou wrote: > >> What should be the next step? Should I generate both patches based on >> review-ilpo-next? Will the amdxdna change upstream through platform-x86 tree? > (We seemed to have crossed emails.) > > That would work for me too, but I thought it was wanted that patch 2 to > go through accel? Thanks a lot. Glad to know patch 1 is good and I will not post another one. :) The patch 2 depends on patch1. I agree that patch 2 to go through accel which can avoid conflict with other recent amdxdna driver changes. So I can wait the patch 1 to be upstream and reach to drm-misc, then submit patch 2 there. Does it sound a right plan? Thanks, Lizhi >
On Tue, 6 Jan 2026, Lizhi Hou wrote:
>
> On 1/6/26 05:19, Shyam Sundar S K wrote:
> >
> > On 1/5/2026 22:59, Lizhi Hou wrote:
> > > From: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
> > >
> > > The PMF driver retrieves NPU metrics data from the PMFW. Introduce a new
> > > interface to make NPU metrics accessible to other drivers like AMDXDNA
> > > driver, which can access and utilize this information as needed.
> > >
> > > Reviewed-by: Mario Limonciello <mario.limonciello@amd.com>
> > > Co-developed-by: Patil Rajesh Reddy <Patil.Reddy@amd.com>
> > > Signed-off-by: Patil Rajesh Reddy <Patil.Reddy@amd.com>
> > > Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
> > > [lizhi: save return value of is_npu_metrics_supported() and return it]
> > > Signed-off-by: Lizhi Hou <lizhi.hou@amd.com>
> > Lizhi, just noticied that this patch may not apply cleanly on
> > Ilpo-next (which tree does this change land? drm-misc or
> > platform-x86)? If platform-x86, I can share you a rebased version
>
> I used drm-misc.
Hi,
I'm not expecting you to rebase it as I'll need to do an IB to handle the
conflict cleanly.
--
i.
>
> Lizhi
>
> > offline so that you can wrap into XDNA series.
> >
> > Thanks,
> > Shyam
> >
> > > ---
> > > drivers/platform/x86/amd/pmf/core.c | 76 +++++++++++++++++++++++++++++
> > > drivers/platform/x86/amd/pmf/pmf.h | 2 +
> > > include/linux/amd-pmf-io.h | 21 ++++++++
> > > 3 files changed, 99 insertions(+)
> > >
> > > diff --git a/drivers/platform/x86/amd/pmf/core.c
> > > b/drivers/platform/x86/amd/pmf/core.c
> > > index 8fc293c9c538..d180a39e03bf 100644
> > > --- a/drivers/platform/x86/amd/pmf/core.c
> > > +++ b/drivers/platform/x86/amd/pmf/core.c
> > > @@ -8,12 +8,15 @@
> > > * Author: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
> > > */
> > > +#include <linux/array_size.h>
> > > +#include <linux/cleanup.h>
> > > #include <linux/debugfs.h>
> > > #include <linux/iopoll.h>
> > > #include <linux/module.h>
> > > #include <linux/pci.h>
> > > #include <linux/platform_device.h>
> > > #include <linux/power_supply.h>
> > > +#include <linux/string.h>
> > > #include <asm/amd/node.h>
> > > #include "pmf.h"
> > > @@ -53,6 +56,8 @@ static bool force_load;
> > > module_param(force_load, bool, 0444);
> > > MODULE_PARM_DESC(force_load, "Force load this driver on supported older
> > > platforms (experimental)");
> > > +static struct device *pmf_device;
> > > +
> > > static int amd_pmf_pwr_src_notify_call(struct notifier_block *nb,
> > > unsigned long event, void *data)
> > > {
> > > struct amd_pmf_dev *pmf = container_of(nb, struct amd_pmf_dev,
> > > pwr_src_notifier);
> > > @@ -314,6 +319,71 @@ int amd_pmf_init_metrics_table(struct amd_pmf_dev
> > > *dev)
> > > return 0;
> > > }
> > > +static int is_npu_metrics_supported(struct amd_pmf_dev *pdev)
> > > +{
> > > + switch (pdev->cpu_id) {
> > > + case PCI_DEVICE_ID_AMD_1AH_M20H_ROOT:
> > > + case PCI_DEVICE_ID_AMD_1AH_M60H_ROOT:
> > > + return 0;
> > > + default:
> > > + return -EOPNOTSUPP;
> > > + }
> > > +}
> > > +
> > > +static int amd_pmf_get_smu_metrics(struct amd_pmf_dev *dev, struct
> > > amd_pmf_npu_metrics *data)
> > > +{
> > > + int ret, i;
> > > +
> > > + guard(mutex)(&dev->metrics_mutex);
> > > +
> > > + ret = is_npu_metrics_supported(dev);
> > > + if (ret)
> > > + return ret;
> > > +
> > > + ret = amd_pmf_set_dram_addr(dev, true);
> > > + if (ret)
> > > + return ret;
> > > +
> > > + memset(dev->buf, 0, dev->mtable_size);
> > > +
> > > + /* Send SMU command to get NPU metrics */
> > > + ret = amd_pmf_send_cmd(dev, SET_TRANSFER_TABLE, SET_CMD,
> > > METRICS_TABLE_ID, NULL);
> > > + if (ret) {
> > > + dev_err(dev->dev, "SMU command failed to get NPU metrics:
> > > %d\n", ret);
> > > + return ret;
> > > + }
> > > +
> > > + memcpy(&dev->m_table_v2, dev->buf, dev->mtable_size);
> > > +
> > > + data->npuclk_freq = dev->m_table_v2.npuclk_freq;
> > > + for (i = 0; i < ARRAY_SIZE(data->npu_busy); i++)
> > > + data->npu_busy[i] = dev->m_table_v2.npu_busy[i];
> > > + data->npu_power = dev->m_table_v2.npu_power;
> > > + data->mpnpuclk_freq = dev->m_table_v2.mpnpuclk_freq;
> > > + data->npu_reads = dev->m_table_v2.npu_reads;
> > > + data->npu_writes = dev->m_table_v2.npu_writes;
> > > +
> > > + return 0;
> > > +}
> > > +
> > > +int amd_pmf_get_npu_data(struct amd_pmf_npu_metrics *info)
> > > +{
> > > + struct amd_pmf_dev *pdev;
> > > +
> > > + if (!info)
> > > + return -EINVAL;
> > > +
> > > + if (!pmf_device)
> > > + return -ENODEV;
> > > +
> > > + pdev = dev_get_drvdata(pmf_device);
> > > + if (!pdev)
> > > + return -ENODEV;
> > > +
> > > + return amd_pmf_get_smu_metrics(pdev, info);
> > > +}
> > > +EXPORT_SYMBOL_GPL(amd_pmf_get_npu_data);
> > > +
> > > static int amd_pmf_suspend_handler(struct device *dev)
> > > {
> > > struct amd_pmf_dev *pdev = dev_get_drvdata(dev);
> > > @@ -477,6 +547,10 @@ static int amd_pmf_probe(struct platform_device
> > > *pdev)
> > > if (err)
> > > return err;
> > > + err = devm_mutex_init(dev->dev, &dev->metrics_mutex);
> > > + if (err)
> > > + return err;
> > > +
> > > apmf_acpi_init(dev);
> > > platform_set_drvdata(pdev, dev);
> > > amd_pmf_dbgfs_register(dev);
> > > @@ -485,6 +559,8 @@ static int amd_pmf_probe(struct platform_device *pdev)
> > > if (is_apmf_func_supported(dev, APMF_FUNC_SBIOS_HEARTBEAT_V2))
> > > amd_pmf_notify_sbios_heartbeat_event_v2(dev, ON_LOAD);
> > > + pmf_device = dev->dev;
> > > +
> > > dev_info(dev->dev, "registered PMF device successfully\n");
> > > return 0;
> > > diff --git a/drivers/platform/x86/amd/pmf/pmf.h
> > > b/drivers/platform/x86/amd/pmf/pmf.h
> > > index 9144c8c3bbaf..1bf896c5b92c 100644
> > > --- a/drivers/platform/x86/amd/pmf/pmf.h
> > > +++ b/drivers/platform/x86/amd/pmf/pmf.h
> > > @@ -12,6 +12,7 @@
> > > #define PMF_H
> > > #include <linux/acpi.h>
> > > +#include <linux/amd-pmf-io.h>
> > > #include <linux/input.h>
> > > #include <linux/platform_device.h>
> > > #include <linux/platform_profile.h>
> > > @@ -413,6 +414,7 @@ struct amd_pmf_dev {
> > > struct apmf_sbios_req_v1 req1;
> > > struct pmf_bios_inputs_prev cb_prev; /* To preserve custom BIOS inputs
> > > */
> > > bool cb_flag; /* To handle first custom BIOS
> > > input */
> > > + struct mutex metrics_mutex;
> > > };
> > > struct apmf_sps_prop_granular_v2 {
> > > diff --git a/include/linux/amd-pmf-io.h b/include/linux/amd-pmf-io.h
> > > index 6fa510f419c0..55198d2875cc 100644
> > > --- a/include/linux/amd-pmf-io.h
> > > +++ b/include/linux/amd-pmf-io.h
> > > @@ -61,5 +61,26 @@ enum laptop_placement {
> > > LP_UNDEFINED,
> > > };
> > > +/**
> > > + * struct amd_pmf_npu_metrics: Get NPU metrics data from PMF driver
> > > + * @npuclk_freq: NPU clock frequency [MHz]
> > > + * @npu_busy: NPU busy % [0-100]
> > > + * @npu_power: NPU power [mW]
> > > + * @mpnpuclk_freq: MPNPU [MHz]
> > > + * @npu_reads: NPU read bandwidth [MB/sec]
> > > + * @npu_writes: NPU write bandwidth [MB/sec]
> > > + */
> > > +struct amd_pmf_npu_metrics {
> > > + u16 npuclk_freq;
> > > + u16 npu_busy[8];
> > > + u16 npu_power;
> > > + u16 mpnpuclk_freq;
> > > + u16 npu_reads;
> > > + u16 npu_writes;
> > > +};
> > > +
> > > int amd_get_sfh_info(struct amd_sfh_info *sfh_info, enum
> > > sfh_message_type op);
> > > +
> > > +/* AMD PMF and NPU interface */
> > > +int amd_pmf_get_npu_data(struct amd_pmf_npu_metrics *info);
> > > #endif
>
--
i.
© 2016 - 2026 Red Hat, Inc.