[v1,4/4] power/amd_uncore: uncore power management support for AMD EPYC processors
Checks
Commit Message
This patch introduces driver support for power management of uncore
components in AMD EPYC processors.
Signed-off-by: Sivaprasad Tummala <sivaprasad.tummala@amd.com>
---
drivers/power/amd_uncore/amd_uncore.c | 321 ++++++++++++++++++++++++++
drivers/power/amd_uncore/amd_uncore.h | 226 ++++++++++++++++++
drivers/power/amd_uncore/meson.build | 20 ++
drivers/power/meson.build | 1 +
4 files changed, 568 insertions(+)
create mode 100644 drivers/power/amd_uncore/amd_uncore.c
create mode 100644 drivers/power/amd_uncore/amd_uncore.h
create mode 100644 drivers/power/amd_uncore/meson.build
Comments
On 20/07/2024 17:50, Sivaprasad Tummala wrote:
> This patch introduces driver support for power management of uncore
> components in AMD EPYC processors.
>
> Signed-off-by: Sivaprasad Tummala <sivaprasad.tummala@amd.com>
> ---
> drivers/power/amd_uncore/amd_uncore.c | 321 ++++++++++++++++++++++++++
> drivers/power/amd_uncore/amd_uncore.h | 226 ++++++++++++++++++
> drivers/power/amd_uncore/meson.build | 20 ++
> drivers/power/meson.build | 1 +
> 4 files changed, 568 insertions(+)
> create mode 100644 drivers/power/amd_uncore/amd_uncore.c
> create mode 100644 drivers/power/amd_uncore/amd_uncore.h
> create mode 100644 drivers/power/amd_uncore/meson.build
>
> diff --git a/drivers/power/amd_uncore/amd_uncore.c b/drivers/power/amd_uncore/amd_uncore.c
> new file mode 100644
> index 0000000000..f15eaaa307
> --- /dev/null
> +++ b/drivers/power/amd_uncore/amd_uncore.c
> @@ -0,0 +1,321 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2024 Advanced Micro Devices, Inc.
> + */
> +
> +#include <errno.h>
> +#include <dirent.h>
> +#include <fnmatch.h>
> +
> +#include <rte_memcpy.h>
> +
> +#include "amd_uncore.h"
> +#include "power_common.h"
> +#include "e_smi/e_smi.h"
> +
> +#define MAX_UNCORE_FREQS 8
> +#define MAX_NUMA_DIE 8
> +
> +#define BUS_FREQ 1000
> +
> +struct __rte_cache_aligned uncore_power_info {
> + unsigned int die; /* Core die id */
> + unsigned int pkg; /* Package id */
> + uint32_t freqs[MAX_UNCORE_FREQS]; /* Frequency array */
> + uint32_t nb_freqs; /* Number of available freqs */
> + uint32_t curr_idx; /* Freq index in freqs array */
> + uint32_t max_freq; /* System max uncore freq */
> + uint32_t min_freq; /* System min uncore freq */
> +};
> +
> +static struct uncore_power_info uncore_info[RTE_MAX_NUMA_NODES][MAX_NUMA_DIE];
> +static int esmi_initialized;
> +
> +static int
> +set_uncore_freq_internal(struct uncore_power_info *ui, uint32_t idx)
> +{
> + int ret;
> +
> + if (idx >= MAX_UNCORE_FREQS || idx >= ui->nb_freqs) {
> + POWER_LOG(DEBUG, "Invalid uncore frequency index %u, which "
> + "should be less than %u", idx, ui->nb_freqs);
> + return -1;
> + }
> +
> + ret = esmi_apb_disable(ui->pkg, idx);
> + if (ret != ESMI_SUCCESS) {
> + POWER_LOG(ERR, "DF P-state '%u' set failed for pkg %02u",
> + idx, ui->pkg);
> + return -1;
> + }
> +
> + POWER_DEBUG_LOG("DF P-state '%u' to be set for pkg %02u die %02u",
> + idx, ui->pkg, ui->die);
> +
> + /* write the minimum value first if the target freq is less than current max */
> + ui->curr_idx = idx;
> +
> + return 0;
> +}
> +
> +/*
> + * Fopen the sys file for the future setting of the uncore die frequency.
> + */
Comment may need updating, as function is not reading any sysfs files
(for the moment, at least).
> +static int
> +power_init_for_setting_uncore_freq(struct uncore_power_info *ui)
> +{
> + /* open and read all uncore sys files */
Comment may need updating, as function is not reading any sysfs files
(for the moment, at least).
> + /* Base max */
> + ui->max_freq = 1800000;
> + ui->min_freq = 1200000;
> +
> + return 0;
> +}
> +
> +/*
> + * Get the available uncore frequencies of the specific die by reading the
> + * sys file.
> + */
Comment may need updating, as function is not reading any sysfs files. 3
uncore frequencies hard-coded for the moment, may get via esmi or sysfs
in the future.
> +static int
> +power_get_available_uncore_freqs(struct uncore_power_info *ui)
> +{
> + int ret = -1;
> + uint32_t i, num_uncore_freqs = 3;
> + uint32_t fabric_freqs[] = {
> + /* to be extended for probing support in future */
> + 1800,
> + 1444,
> + 1200
> + };
> +
> + if (num_uncore_freqs >= MAX_UNCORE_FREQS) {
> + POWER_LOG(ERR, "Too many available uncore frequencies: %d",
> + num_uncore_freqs);
> + goto out;
> + }
> +
> + /* Generate the uncore freq bucket array. */
> + for (i = 0; i < num_uncore_freqs; i++)
> + ui->freqs[i] = fabric_freqs[i] * BUS_FREQ;
> +
> + ui->nb_freqs = num_uncore_freqs;
> +
> + ret = 0;
> +
> + POWER_DEBUG_LOG("%d frequency(s) of pkg %02u die %02u are available",
> + num_uncore_freqs, ui->pkg, ui->die);
> +
> +out:
> + return ret;
> +}
> +
--snip--
>
[AMD Official Use Only - AMD Internal Distribution Only]
Hi Dave,
> -----Original Message-----
> From: Hunt, David <david.hunt@intel.com>
> Sent: Tuesday, July 23, 2024 4:03 PM
> To: Tummala, Sivaprasad <Sivaprasad.Tummala@amd.com>;
> anatoly.burakov@intel.com; jerinj@marvell.com; lihuisong@huawei.com;
> david.marchand@redhat.com; Yigit, Ferruh <Ferruh.Yigit@amd.com>;
> konstantin.ananyev@huawei.com
> Cc: dev@dpdk.org
> Subject: Re: [PATCH v1 4/4] power/amd_uncore: uncore power management
> support for AMD EPYC processors
>
> Caution: This message originated from an External Source. Use proper caution
> when opening attachments, clicking links, or responding.
>
>
> On 20/07/2024 17:50, Sivaprasad Tummala wrote:
> > This patch introduces driver support for power management of uncore
> > components in AMD EPYC processors.
> >
> > Signed-off-by: Sivaprasad Tummala <sivaprasad.tummala@amd.com>
> > ---
> > drivers/power/amd_uncore/amd_uncore.c | 321
> ++++++++++++++++++++++++++
> > drivers/power/amd_uncore/amd_uncore.h | 226 ++++++++++++++++++
> > drivers/power/amd_uncore/meson.build | 20 ++
> > drivers/power/meson.build | 1 +
> > 4 files changed, 568 insertions(+)
> > create mode 100644 drivers/power/amd_uncore/amd_uncore.c
> > create mode 100644 drivers/power/amd_uncore/amd_uncore.h
> > create mode 100644 drivers/power/amd_uncore/meson.build
> >
> > diff --git a/drivers/power/amd_uncore/amd_uncore.c
> > b/drivers/power/amd_uncore/amd_uncore.c
> > new file mode 100644
> > index 0000000000..f15eaaa307
> > --- /dev/null
> > +++ b/drivers/power/amd_uncore/amd_uncore.c
> > @@ -0,0 +1,321 @@
> > +/* SPDX-License-Identifier: BSD-3-Clause
> > + * Copyright(c) 2024 Advanced Micro Devices, Inc.
> > + */
> > +
> > +#include <errno.h>
> > +#include <dirent.h>
> > +#include <fnmatch.h>
> > +
> > +#include <rte_memcpy.h>
> > +
> > +#include "amd_uncore.h"
> > +#include "power_common.h"
> > +#include "e_smi/e_smi.h"
> > +
> > +#define MAX_UNCORE_FREQS 8
> > +#define MAX_NUMA_DIE 8
> > +
> > +#define BUS_FREQ 1000
> > +
> > +struct __rte_cache_aligned uncore_power_info {
> > + unsigned int die; /* Core die id */
> > + unsigned int pkg; /* Package id */
> > + uint32_t freqs[MAX_UNCORE_FREQS]; /* Frequency array */
> > + uint32_t nb_freqs; /* Number of available freqs */
> > + uint32_t curr_idx; /* Freq index in freqs array */
> > + uint32_t max_freq; /* System max uncore freq */
> > + uint32_t min_freq; /* System min uncore freq */
> > +};
> > +
> > +static struct uncore_power_info
> > +uncore_info[RTE_MAX_NUMA_NODES][MAX_NUMA_DIE];
> > +static int esmi_initialized;
> > +
> > +static int
> > +set_uncore_freq_internal(struct uncore_power_info *ui, uint32_t idx)
> > +{
> > + int ret;
> > +
> > + if (idx >= MAX_UNCORE_FREQS || idx >= ui->nb_freqs) {
> > + POWER_LOG(DEBUG, "Invalid uncore frequency index %u, which "
> > + "should be less than %u", idx, ui->nb_freqs);
> > + return -1;
> > + }
> > +
> > + ret = esmi_apb_disable(ui->pkg, idx);
> > + if (ret != ESMI_SUCCESS) {
> > + POWER_LOG(ERR, "DF P-state '%u' set failed for pkg %02u",
> > + idx, ui->pkg);
> > + return -1;
> > + }
> > +
> > + POWER_DEBUG_LOG("DF P-state '%u' to be set for pkg %02u die %02u",
> > + idx, ui->pkg, ui->die);
> > +
> > + /* write the minimum value first if the target freq is less than current max
> */
> > + ui->curr_idx = idx;
> > +
> > + return 0;
> > +}
> > +
> > +/*
> > + * Fopen the sys file for the future setting of the uncore die frequency.
> > + */
>
>
> Comment may need updating, as function is not reading any sysfs files (for the
> moment, at least).
ACK! Will address this in next version.
>
>
> > +static int
> > +power_init_for_setting_uncore_freq(struct uncore_power_info *ui) {
> > + /* open and read all uncore sys files */
>
>
> Comment may need updating, as function is not reading any sysfs files (for the
> moment, at least).
ACK! Will address this in next version.
>
>
>
> > + /* Base max */
> > + ui->max_freq = 1800000;
> > + ui->min_freq = 1200000;
> > +
> > + return 0;
> > +}
> > +
> > +/*
> > + * Get the available uncore frequencies of the specific die by
> > +reading the
> > + * sys file.
> > + */
>
>
> Comment may need updating, as function is not reading any sysfs files. 3
> uncore frequencies hard-coded for the moment, may get via esmi or sysfs in
> the future.
ACK! Will address this in next version.
>
>
> > +static int
> > +power_get_available_uncore_freqs(struct uncore_power_info *ui) {
> > + int ret = -1;
> > + uint32_t i, num_uncore_freqs = 3;
> > + uint32_t fabric_freqs[] = {
> > + /* to be extended for probing support in future */
> > + 1800,
> > + 1444,
> > + 1200
> > + };
> > +
> > + if (num_uncore_freqs >= MAX_UNCORE_FREQS) {
> > + POWER_LOG(ERR, "Too many available uncore frequencies: %d",
> > + num_uncore_freqs);
> > + goto out;
> > + }
> > +
> > + /* Generate the uncore freq bucket array. */
> > + for (i = 0; i < num_uncore_freqs; i++)
> > + ui->freqs[i] = fabric_freqs[i] * BUS_FREQ;
> > +
> > + ui->nb_freqs = num_uncore_freqs;
> > +
> > + ret = 0;
> > +
> > + POWER_DEBUG_LOG("%d frequency(s) of pkg %02u die %02u are
> available",
> > + num_uncore_freqs, ui->pkg, ui->die);
> > +
> > +out:
> > + return ret;
> > +}
> > +
>
>
> --snip--
>
> >
new file mode 100644
@@ -0,0 +1,321 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2024 Advanced Micro Devices, Inc.
+ */
+
+#include <errno.h>
+#include <dirent.h>
+#include <fnmatch.h>
+
+#include <rte_memcpy.h>
+
+#include "amd_uncore.h"
+#include "power_common.h"
+#include "e_smi/e_smi.h"
+
+#define MAX_UNCORE_FREQS 8
+#define MAX_NUMA_DIE 8
+
+#define BUS_FREQ 1000
+
+struct __rte_cache_aligned uncore_power_info {
+ unsigned int die; /* Core die id */
+ unsigned int pkg; /* Package id */
+ uint32_t freqs[MAX_UNCORE_FREQS]; /* Frequency array */
+ uint32_t nb_freqs; /* Number of available freqs */
+ uint32_t curr_idx; /* Freq index in freqs array */
+ uint32_t max_freq; /* System max uncore freq */
+ uint32_t min_freq; /* System min uncore freq */
+};
+
+static struct uncore_power_info uncore_info[RTE_MAX_NUMA_NODES][MAX_NUMA_DIE];
+static int esmi_initialized;
+
+static int
+set_uncore_freq_internal(struct uncore_power_info *ui, uint32_t idx)
+{
+ int ret;
+
+ if (idx >= MAX_UNCORE_FREQS || idx >= ui->nb_freqs) {
+ POWER_LOG(DEBUG, "Invalid uncore frequency index %u, which "
+ "should be less than %u", idx, ui->nb_freqs);
+ return -1;
+ }
+
+ ret = esmi_apb_disable(ui->pkg, idx);
+ if (ret != ESMI_SUCCESS) {
+ POWER_LOG(ERR, "DF P-state '%u' set failed for pkg %02u",
+ idx, ui->pkg);
+ return -1;
+ }
+
+ POWER_DEBUG_LOG("DF P-state '%u' to be set for pkg %02u die %02u",
+ idx, ui->pkg, ui->die);
+
+ /* write the minimum value first if the target freq is less than current max */
+ ui->curr_idx = idx;
+
+ return 0;
+}
+
+/*
+ * Fopen the sys file for the future setting of the uncore die frequency.
+ */
+static int
+power_init_for_setting_uncore_freq(struct uncore_power_info *ui)
+{
+ /* open and read all uncore sys files */
+ /* Base max */
+ ui->max_freq = 1800000;
+ ui->min_freq = 1200000;
+
+ return 0;
+}
+
+/*
+ * Get the available uncore frequencies of the specific die by reading the
+ * sys file.
+ */
+static int
+power_get_available_uncore_freqs(struct uncore_power_info *ui)
+{
+ int ret = -1;
+ uint32_t i, num_uncore_freqs = 3;
+ uint32_t fabric_freqs[] = {
+ /* to be extended for probing support in future */
+ 1800,
+ 1444,
+ 1200
+ };
+
+ if (num_uncore_freqs >= MAX_UNCORE_FREQS) {
+ POWER_LOG(ERR, "Too many available uncore frequencies: %d",
+ num_uncore_freqs);
+ goto out;
+ }
+
+ /* Generate the uncore freq bucket array. */
+ for (i = 0; i < num_uncore_freqs; i++)
+ ui->freqs[i] = fabric_freqs[i] * BUS_FREQ;
+
+ ui->nb_freqs = num_uncore_freqs;
+
+ ret = 0;
+
+ POWER_DEBUG_LOG("%d frequency(s) of pkg %02u die %02u are available",
+ num_uncore_freqs, ui->pkg, ui->die);
+
+out:
+ return ret;
+}
+
+static int
+check_pkg_die_values(unsigned int pkg, unsigned int die)
+{
+ unsigned int max_pkgs, max_dies;
+ max_pkgs = power_amd_uncore_get_num_pkgs();
+ if (max_pkgs == 0)
+ return -1;
+ if (pkg >= max_pkgs) {
+ POWER_LOG(DEBUG, "Package number %02u can not exceed %u",
+ pkg, max_pkgs);
+ return -1;
+ }
+
+ max_dies = power_amd_uncore_get_num_dies(pkg);
+ if (max_dies == 0)
+ return -1;
+ if (die >= max_dies) {
+ POWER_LOG(DEBUG, "Die number %02u can not exceed %u",
+ die, max_dies);
+ return -1;
+ }
+
+ return 0;
+}
+
+static void
+power_amd_uncore_esmi_init(void)
+{
+ if (esmi_init() == ESMI_SUCCESS)
+ esmi_initialized = 1;
+}
+
+int
+power_amd_uncore_init(unsigned int pkg, unsigned int die)
+{
+ struct uncore_power_info *ui;
+ int ret;
+
+ if (!esmi_initialized) {
+ ret = esmi_init();
+ if (ret != ESMI_SUCCESS) {
+ POWER_LOG(DEBUG, "ESMI Not initialized, drivers not found");
+ return -1;
+ }
+ }
+
+ ret = check_pkg_die_values(pkg, die);
+ if (ret < 0)
+ return -1;
+
+ ui = &uncore_info[pkg][die];
+ ui->die = die;
+ ui->pkg = pkg;
+
+ /* Init for setting uncore die frequency */
+ if (power_init_for_setting_uncore_freq(ui) < 0) {
+ POWER_LOG(DEBUG, "Cannot init for setting uncore frequency for "
+ "pkg %02u die %02u", pkg, die);
+ return -1;
+ }
+
+ /* Get the available frequencies */
+ if (power_get_available_uncore_freqs(ui) < 0) {
+ POWER_LOG(DEBUG, "Cannot get available uncore frequencies of "
+ "pkg %02u die %02u", pkg, die);
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+power_amd_uncore_exit(unsigned int pkg, unsigned int die)
+{
+ struct uncore_power_info *ui;
+
+ int ret = check_pkg_die_values(pkg, die);
+ if (ret < 0)
+ return -1;
+
+ ui = &uncore_info[pkg][die];
+ ui->nb_freqs = 0;
+
+ if (esmi_initialized) {
+ esmi_exit();
+ esmi_initialized = 0;
+ }
+
+ return 0;
+}
+
+uint32_t
+power_get_amd_uncore_freq(unsigned int pkg, unsigned int die)
+{
+ int ret = check_pkg_die_values(pkg, die);
+ if (ret < 0)
+ return -1;
+
+ return uncore_info[pkg][die].curr_idx;
+}
+
+int
+power_set_amd_uncore_freq(unsigned int pkg, unsigned int die, uint32_t index)
+{
+ int ret = check_pkg_die_values(pkg, die);
+ if (ret < 0)
+ return -1;
+
+ return set_uncore_freq_internal(&(uncore_info[pkg][die]), index);
+}
+
+int
+power_amd_uncore_freq_max(unsigned int pkg, unsigned int die)
+{
+ int ret = check_pkg_die_values(pkg, die);
+ if (ret < 0)
+ return -1;
+
+ return set_uncore_freq_internal(&(uncore_info[pkg][die]), 0);
+}
+
+
+int
+power_amd_uncore_freq_min(unsigned int pkg, unsigned int die)
+{
+ int ret = check_pkg_die_values(pkg, die);
+ if (ret < 0)
+ return -1;
+
+ struct uncore_power_info *ui = &uncore_info[pkg][die];
+
+ return set_uncore_freq_internal(&(uncore_info[pkg][die]), ui->nb_freqs - 1);
+}
+
+int
+power_amd_uncore_freqs(unsigned int pkg, unsigned int die, uint32_t *freqs, uint32_t num)
+{
+ struct uncore_power_info *ui;
+
+ int ret = check_pkg_die_values(pkg, die);
+ if (ret < 0)
+ return -1;
+
+ if (freqs == NULL) {
+ POWER_LOG(ERR, "NULL buffer supplied");
+ return 0;
+ }
+
+ ui = &uncore_info[pkg][die];
+ if (num < ui->nb_freqs) {
+ POWER_LOG(ERR, "Buffer size is not enough");
+ return 0;
+ }
+ rte_memcpy(freqs, ui->freqs, ui->nb_freqs * sizeof(uint32_t));
+
+ return ui->nb_freqs;
+}
+
+int
+power_amd_uncore_get_num_freqs(unsigned int pkg, unsigned int die)
+{
+ int ret = check_pkg_die_values(pkg, die);
+ if (ret < 0)
+ return -1;
+
+ return uncore_info[pkg][die].nb_freqs;
+}
+
+unsigned int
+power_amd_uncore_get_num_pkgs(void)
+{
+ uint32_t num_pkgs = 0;
+ int ret;
+
+ if (esmi_initialized) {
+ ret = esmi_number_of_sockets_get(&num_pkgs);
+ if (ret != ESMI_SUCCESS) {
+ POWER_LOG(ERR, "Failed to get number of sockets");
+ num_pkgs = 0;
+ }
+ }
+ return num_pkgs;
+}
+
+unsigned int
+power_amd_uncore_get_num_dies(unsigned int pkg)
+{
+ if (pkg >= power_amd_uncore_get_num_pkgs()) {
+ POWER_LOG(ERR, "Invalid package ID");
+ return 0;
+ }
+
+ return 1;
+}
+
+static struct rte_power_uncore_ops amd_uncore_ops = {
+ .name = "amd-hsmp",
+ .cb = power_amd_uncore_esmi_init,
+ .init = power_amd_uncore_init,
+ .exit = power_amd_uncore_exit,
+ .get_avail_freqs = power_amd_uncore_freqs,
+ .get_num_pkgs = power_amd_uncore_get_num_pkgs,
+ .get_num_dies = power_amd_uncore_get_num_dies,
+ .get_num_freqs = power_amd_uncore_get_num_freqs,
+ .get_freq = power_get_amd_uncore_freq,
+ .set_freq = power_set_amd_uncore_freq,
+ .freq_max = power_amd_uncore_freq_max,
+ .freq_min = power_amd_uncore_freq_min,
+};
+
+RTE_POWER_REGISTER_UNCORE_OPS(amd_uncore_ops);
new file mode 100644
@@ -0,0 +1,226 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2024 Advanced Micro Devices, Inc.
+ */
+
+#ifndef POWER_AMD_UNCORE_H
+#define POWER_AMD_UNCORE_H
+
+/**
+ * @file
+ * RTE AMD Uncore Frequency Management
+ */
+
+#include "rte_power.h"
+#include "rte_power_uncore.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Initialize uncore frequency management for specific die on a package.
+ * It will get the available frequencies and prepare to set new die frequencies.
+ *
+ * This function should NOT be called in the fast path.
+ *
+ * @param pkg
+ * Package number.
+ * Each physical CPU in a system is referred to as a package.
+ * @param die
+ * Die number.
+ * Each package can have several dies connected together via the uncore mesh.
+ *
+ * @return
+ * - 0 on success.
+ * - Negative on error.
+ */
+int
+power_amd_uncore_init(unsigned int pkg, unsigned int die);
+
+/**
+ * Exit uncore frequency management on a specific die on a package.
+ * It will restore uncore min and* max values to previous values
+ * before initialization of API.
+ *
+ * This function should NOT be called in the fast path.
+ *
+ * @param pkg
+ * Package number.
+ * Each physical CPU in a system is referred to as a package.
+ * @param die
+ * Die number.
+ * Each package can have several dies connected together via the uncore mesh.
+ *
+ * @return
+ * - 0 on success.
+ * - Negative on error.
+ */
+int
+power_amd_uncore_exit(unsigned int pkg, unsigned int die);
+
+/**
+ * Return the current index of available frequencies of a specific die on a package.
+ * It should be protected outside of this function for threadsafe.
+ *
+ * This function should NOT be called in the fast path.
+ *
+ * @param pkg
+ * Package number.
+ * Each physical CPU in a system is referred to as a package.
+ * @param die
+ * Die number.
+ * Each package can have several dies connected together via the uncore mesh.
+ *
+ * @return
+ * The current index of available frequencies.
+ * If error, it will return 'RTE_POWER_INVALID_FREQ_INDEX = (~0)'.
+ */
+uint32_t
+power_get_amd_uncore_freq(unsigned int pkg, unsigned int die);
+
+/**
+ * Set minimum and maximum uncore frequency for specified die on a package
+ * to specified index value.
+ * It should be protected outside of this function for threadsafe.
+ *
+ * This function should NOT be called in the fast path.
+ *
+ * @param pkg
+ * Package number.
+ * Each physical CPU in a system is referred to as a package.
+ * @param die
+ * Die number.
+ * Each package can have several dies connected together via the uncore mesh.
+ * @param index
+ * The index of available frequencies.
+ *
+ * @return
+ * - 1 on success with frequency changed.
+ * - 0 on success without frequency changed.
+ * - Negative on error.
+ */
+int
+power_set_amd_uncore_freq(unsigned int pkg, unsigned int die, uint32_t index);
+
+/**
+ * Set minimum and maximum uncore frequency for specified die on a package
+ * to maximum value according to the available frequencies.
+ * It should be protected outside of this function for threadsafe.
+ *
+ * This function should NOT be called in the fast path.
+ *
+ * @param pkg
+ * Package number.
+ * Each physical CPU in a system is referred to as a package.
+ * @param die
+ * Die number.
+ * Each package can have several dies connected together via the uncore mesh.
+ *
+ * @return
+ * - 1 on success with frequency changed.
+ * - 0 on success without frequency changed.
+ * - Negative on error.
+ */
+int
+power_amd_uncore_freq_max(unsigned int pkg, unsigned int die);
+
+/**
+ * Set minimum and maximum uncore frequency for specified die on a package
+ * to minimum value according to the available frequencies.
+ * It should be protected outside of this function for threadsafe.
+ *
+ * This function should NOT be called in the fast path.
+ *
+ * @param pkg
+ * Package number.
+ * Each physical CPU in a system is referred to as a package.
+ * @param die
+ * Die number.
+ * Each package can have several dies connected together via the uncore mesh.
+ *
+ * @return
+ * - 1 on success with frequency changed.
+ * - 0 on success without frequency changed.
+ * - Negative on error.
+ */
+int
+power_amd_uncore_freq_min(unsigned int pkg, unsigned int die);
+
+/**
+ * Return the list of available frequencies in the index array.
+ *
+ * This function should NOT be called in the fast path.
+ *
+ * @param pkg
+ * Package number.
+ * Each physical CPU in a system is referred to as a package.
+ * @param die
+ * Die number.
+ * Each package can have several dies connected together via the uncore mesh.
+ * @param freqs
+ * The buffer array to save the frequencies.
+ * @param num
+ * The number of frequencies to get.
+ *
+ * @return
+ * - The number of available index's in frequency array.
+ * - Negative on error.
+ */
+int
+power_amd_uncore_freqs(unsigned int pkg, unsigned int die,
+ unsigned int *freqs, unsigned int num);
+
+/**
+ * Return the list length of available frequencies in the index array.
+ *
+ * This function should NOT be called in the fast path.
+ *
+ * @param pkg
+ * Package number.
+ * Each physical CPU in a system is referred to as a package.
+ * @param die
+ * Die number.
+ * Each package can have several dies connected together via the uncore mesh.
+ *
+ * @return
+ * - The number of available index's in frequency array.
+ * - Negative on error.
+ */
+int
+power_amd_uncore_get_num_freqs(unsigned int pkg, unsigned int die);
+
+/**
+ * Return the number of packages (CPUs) on a system
+ * by parsing the uncore sysfs directory.
+ *
+ * This function should NOT be called in the fast path.
+ *
+ * @return
+ * - Zero on error.
+ * - Number of package on system on success.
+ */
+unsigned int
+power_amd_uncore_get_num_pkgs(void);
+
+/**
+ * Return the number of dies for pakckages (CPUs) specified
+ * from parsing the uncore sysfs directory.
+ *
+ * This function should NOT be called in the fast path.
+ *
+ * @param pkg
+ * Package number.
+ * Each physical CPU in a system is referred to as a package.
+ *
+ * @return
+ * - Zero on error.
+ * - Number of dies for package on sucecss.
+ */
+unsigned int
+power_amd_uncore_get_num_dies(unsigned int pkg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* POWER_INTEL_UNCORE_H */
new file mode 100644
@@ -0,0 +1,20 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2024 Advanced Micro Devices, Inc.
+
+if not is_linux
+ build = false
+ reason = 'only supported on Linux'
+ subdir_done()
+endif
+
+IMB_header = '#include<e_smi/e_smi.h>'
+lib = cc.find_library('e_smi64', required: false)
+if not lib.found()
+ build = false
+ reason = 'missing dependency, "libe_smi"'
+else
+ ext_deps += lib
+endif
+
+sources = files('amd_uncore.c')
+deps += ['power']
@@ -7,6 +7,7 @@ drivers = [
'cppc',
'kvm_vm',
'pstate',
+ 'amd_uncore',
'intel_uncore'
]