[v2,2/4] power: refactor uncore power management library

Message ID 20240826130650.320130-3-sivaprasad.tummala@amd.com (mailing list archive)
State Superseded
Delegated to: Thomas Monjalon
Headers
Series power: refactor power management library |

Checks

Context Check Description
ci/checkpatch warning coding style issues

Commit Message

Tummala, Sivaprasad Aug. 26, 2024, 1:06 p.m. UTC
This patch refactors the power management library, addressing uncore
power management. The primary changes involve the creation of dedicated
directories for each driver within 'drivers/power/uncore/*'. The
adjustment of meson.build files enables the selective activation
of individual drivers.

This refactor significantly improves code organization, enhances
clarity and boosts maintainability. It lays the foundation for more
focused development on individual drivers and facilitates seamless
integration of future enhancements, particularly the AMD uncore driver.

Signed-off-by: Sivaprasad Tummala <sivaprasad.tummala@amd.com>
---
 .../power/intel_uncore/intel_uncore.c         |  18 +-
 .../power/intel_uncore/intel_uncore.h         |   8 +-
 drivers/power/intel_uncore/meson.build        |   6 +
 drivers/power/meson.build                     |   3 +-
 lib/power/meson.build                         |   2 +-
 lib/power/rte_power_uncore.c                  | 205 ++++++---------
 lib/power/rte_power_uncore.h                  |  87 ++++---
 lib/power/rte_power_uncore_ops.h              | 239 ++++++++++++++++++
 lib/power/version.map                         |   1 +
 9 files changed, 405 insertions(+), 164 deletions(-)
 rename lib/power/power_intel_uncore.c => drivers/power/intel_uncore/intel_uncore.c (95%)
 rename lib/power/power_intel_uncore.h => drivers/power/intel_uncore/intel_uncore.h (97%)
 create mode 100644 drivers/power/intel_uncore/meson.build
 create mode 100644 lib/power/rte_power_uncore_ops.h
  

Comments

lihuisong (C) Aug. 27, 2024, 1:02 p.m. UTC | #1
Hi Sivaprasad,

Suggest to split this patch into two patches for easiler to review:
patch-1: abstract a file for uncore dvfs core level, namely, the 
rte_power_uncore_ops.c you did.
patch-2: move and rename, lib/power/power_intel_uncore.c => 
drivers/power/intel_uncore/intel_uncore.c

patch[1/4] is also too big and not good to review.

In addition, I have some question and am not sure if we can adjust 
uncore init process.

/Huisong


在 2024/8/26 21:06, Sivaprasad Tummala 写道:
> This patch refactors the power management library, addressing uncore
> power management. The primary changes involve the creation of dedicated
> directories for each driver within 'drivers/power/uncore/*'. The
> adjustment of meson.build files enables the selective activation
> of individual drivers.
>
> This refactor significantly improves code organization, enhances
> clarity and boosts maintainability. It lays the foundation for more
> focused development on individual drivers and facilitates seamless
> integration of future enhancements, particularly the AMD uncore driver.
>
> Signed-off-by: Sivaprasad Tummala <sivaprasad.tummala@amd.com>
> ---
>   .../power/intel_uncore/intel_uncore.c         |  18 +-
>   .../power/intel_uncore/intel_uncore.h         |   8 +-
>   drivers/power/intel_uncore/meson.build        |   6 +
>   drivers/power/meson.build                     |   3 +-
>   lib/power/meson.build                         |   2 +-
>   lib/power/rte_power_uncore.c                  | 205 ++++++---------
>   lib/power/rte_power_uncore.h                  |  87 ++++---
>   lib/power/rte_power_uncore_ops.h              | 239 ++++++++++++++++++
>   lib/power/version.map                         |   1 +
>   9 files changed, 405 insertions(+), 164 deletions(-)
>   rename lib/power/power_intel_uncore.c => drivers/power/intel_uncore/intel_uncore.c (95%)
>   rename lib/power/power_intel_uncore.h => drivers/power/intel_uncore/intel_uncore.h (97%)
>   create mode 100644 drivers/power/intel_uncore/meson.build
>   create mode 100644 lib/power/rte_power_uncore_ops.h
>
> diff --git a/lib/power/power_intel_uncore.c b/drivers/power/intel_uncore/intel_uncore.c
> similarity index 95%
> rename from lib/power/power_intel_uncore.c
> rename to drivers/power/intel_uncore/intel_uncore.c
> index 4eb9c5900a..804ad5d755 100644
> --- a/lib/power/power_intel_uncore.c
> +++ b/drivers/power/intel_uncore/intel_uncore.c
> @@ -8,7 +8,7 @@
>   
>   #include <rte_memcpy.h>
>   
> -#include "power_intel_uncore.h"
> +#include "intel_uncore.h"
>   #include "power_common.h"
>   
>   #define MAX_NUMA_DIE 8
> @@ -475,3 +475,19 @@ power_intel_uncore_get_num_dies(unsigned int pkg)
>   
>   	return count;
>   }
<...>
>   
> -#endif /* POWER_INTEL_UNCORE_H */
> +#endif /* INTEL_UNCORE_H */
> diff --git a/drivers/power/intel_uncore/meson.build b/drivers/power/intel_uncore/meson.build
> new file mode 100644
> index 0000000000..876df8ad14
> --- /dev/null
> +++ b/drivers/power/intel_uncore/meson.build
> @@ -0,0 +1,6 @@
> +# SPDX-License-Identifier: BSD-3-Clause
> +# Copyright(c) 2017 Intel Corporation
> +# Copyright(c) 2024 Advanced Micro Devices, Inc.
> +
> +sources = files('intel_uncore.c')
> +deps += ['power']
> diff --git a/drivers/power/meson.build b/drivers/power/meson.build
> index 8c7215c639..c83047af94 100644
> --- a/drivers/power/meson.build
> +++ b/drivers/power/meson.build
> @@ -6,7 +6,8 @@ drivers = [
>           'amd_pstate',
>           'cppc',
>           'kvm_vm',
> -        'pstate'
> +        'pstate',
> +        'intel_uncore'
The cppc, amd_pstate and so on belong to cpufreq scope.
And intel_uncore belongs to uncore dvfs scope.
They are not the same level. So I proposes that we need to create one 
directory called like cpufreq or core.
This 'intel_uncore' name don't seems appropriate. what do you think the 
following directory structure:
drivers/power/uncore/intel_uncore.c
drivers/power/uncore/amd_uncore.c (according to the patch[4/4]).
>   ]
>   std_deps = ['power']
> diff --git a/lib/power/meson.build b/lib/power/meson.build
> index f3e3451cdc..9b13d98810 100644
> --- a/lib/power/meson.build
> +++ b/lib/power/meson.build
> @@ -13,7 +13,6 @@ if not is_linux
>   endif
>   sources = files(
>           'power_common.c',
> -        'power_intel_uncore.c',
>           'rte_power.c',
>           'rte_power_uncore.c',
>           'rte_power_pmd_mgmt.c',
> @@ -24,6 +23,7 @@ headers = files(
>           'rte_power_guest_channel.h',
>           'rte_power_pmd_mgmt.h',
>           'rte_power_uncore.h',
> +        'rte_power_uncore_ops.h',
>   )
>   if cc.has_argument('-Wno-cast-qual')
>       cflags += '-Wno-cast-qual'
> diff --git a/lib/power/rte_power_uncore.c b/lib/power/rte_power_uncore.c
> index 48c75a5da0..9f8771224f 100644
> --- a/lib/power/rte_power_uncore.c
> +++ b/lib/power/rte_power_uncore.c
> @@ -1,6 +1,7 @@
>   /* SPDX-License-Identifier: BSD-3-Clause
>    * Copyright(c) 2010-2014 Intel Corporation
>    * Copyright(c) 2023 AMD Corporation
> + * Copyright(c) 2024 Advanced Micro Devices, Inc.
>    */
>   
>   #include <errno.h>
> @@ -12,98 +13,50 @@
>   #include "rte_power_uncore.h"
>   #include "power_intel_uncore.h"
>   
> -enum rte_uncore_power_mgmt_env default_uncore_env = RTE_UNCORE_PM_ENV_NOT_SET;
> +static enum rte_uncore_power_mgmt_env global_uncore_env = RTE_UNCORE_PM_ENV_NOT_SET;
> +static struct rte_power_uncore_ops *global_uncore_ops;
>   
>   static rte_spinlock_t global_env_cfg_lock = RTE_SPINLOCK_INITIALIZER;
> +static RTE_TAILQ_HEAD(, rte_power_uncore_ops) uncore_ops_list =
> +			TAILQ_HEAD_INITIALIZER(uncore_ops_list);
>   
> -static uint32_t
> -power_get_dummy_uncore_freq(unsigned int pkg __rte_unused,
> -	       unsigned int die __rte_unused)
> -{
> -	return 0;
> -}
> -
> -static int
> -power_set_dummy_uncore_freq(unsigned int pkg __rte_unused,
> -	       unsigned int die __rte_unused, uint32_t index __rte_unused)
> -{
> -	return 0;
> -}
> +const char *uncore_env_str[] = {
> +	"not set",
> +	"auto-detect",
> +	"intel-uncore",
> +	"amd-hsmp"
> +};
Why open the "auto-detect" mode to user?
Why not set this automatically at framework initialization?
After all, the uncore driver is fixed for one platform.
>   
> -static int
> -power_dummy_uncore_freq_max(unsigned int pkg __rte_unused,
> -	       unsigned int die __rte_unused)
> -{
> -	return 0;
> -}
> -
<...>
> -static int
> -power_dummy_uncore_get_num_freqs(unsigned int pkg __rte_unused,
> -	       unsigned int die __rte_unused)
> +/* register the ops struct in rte_power_uncore_ops, return 0 on success. */
> +int
> +rte_power_register_uncore_ops(struct rte_power_uncore_ops *driver_ops)
>   {
> -	return 0;
> -}
> +	if (!driver_ops->init || !driver_ops->exit || !driver_ops->get_num_pkgs ||
> +		!driver_ops->get_num_dies || !driver_ops->get_num_freqs ||
> +		!driver_ops->get_avail_freqs || !driver_ops->get_freq ||
> +		!driver_ops->set_freq || !driver_ops->freq_max ||
> +		!driver_ops->freq_min) {
> +		POWER_LOG(ERR, "Missing callbacks while registering power ops");
> +		return -1;
> +	}
> +	if (driver_ops->cb)
> +		driver_ops->cb();
>   
> -static unsigned int
> -power_dummy_uncore_get_num_pkgs(void)
> -{
> -	return 0;
> -}
> +	TAILQ_INSERT_TAIL(&uncore_ops_list, driver_ops, next);
>   
> -static unsigned int
> -power_dummy_uncore_get_num_dies(unsigned int pkg __rte_unused)
> -{
>   	return 0;
>   }
> -
> -/* function pointers */
> -rte_power_get_uncore_freq_t rte_power_get_uncore_freq = power_get_dummy_uncore_freq;
> -rte_power_set_uncore_freq_t rte_power_set_uncore_freq = power_set_dummy_uncore_freq;
> -rte_power_uncore_freq_change_t rte_power_uncore_freq_max = power_dummy_uncore_freq_max;
> -rte_power_uncore_freq_change_t rte_power_uncore_freq_min = power_dummy_uncore_freq_min;
> -rte_power_uncore_freqs_t rte_power_uncore_freqs = power_dummy_uncore_freqs;
> -rte_power_uncore_get_num_freqs_t rte_power_uncore_get_num_freqs = power_dummy_uncore_get_num_freqs;
> -rte_power_uncore_get_num_pkgs_t rte_power_uncore_get_num_pkgs = power_dummy_uncore_get_num_pkgs;
> -rte_power_uncore_get_num_dies_t rte_power_uncore_get_num_dies = power_dummy_uncore_get_num_dies;
> -
> -static void
> -reset_power_uncore_function_ptrs(void)
> -{
> -	rte_power_get_uncore_freq = power_get_dummy_uncore_freq;
> -	rte_power_set_uncore_freq = power_set_dummy_uncore_freq;
> -	rte_power_uncore_freq_max = power_dummy_uncore_freq_max;
> -	rte_power_uncore_freq_min = power_dummy_uncore_freq_min;
> -	rte_power_uncore_freqs  = power_dummy_uncore_freqs;
> -	rte_power_uncore_get_num_freqs = power_dummy_uncore_get_num_freqs;
> -	rte_power_uncore_get_num_pkgs = power_dummy_uncore_get_num_pkgs;
> -	rte_power_uncore_get_num_dies = power_dummy_uncore_get_num_dies;
> -}
> -
>   int
>   rte_power_set_uncore_env(enum rte_uncore_power_mgmt_env env)
>   {
> -	int ret;
> +	int ret = -1;
> +	struct rte_power_uncore_ops *ops;
>   
>   	rte_spinlock_lock(&global_env_cfg_lock);
>   
> -	if (default_uncore_env != RTE_UNCORE_PM_ENV_NOT_SET) {
> +	if (global_uncore_env != RTE_UNCORE_PM_ENV_NOT_SET) {
>   		POWER_LOG(ERR, "Uncore Power Management Env already set.");
> -		rte_spinlock_unlock(&global_env_cfg_lock);
> -		return -1;
> +		goto out;
>   	}
>   
<...>
> +	if (env <= RTE_DIM(uncore_env_str)) {
> +		RTE_TAILQ_FOREACH(ops, &uncore_ops_list, next)
> +			if (strncmp(ops->name, uncore_env_str[env],
> +				RTE_POWER_UNCORE_DRIVER_NAMESZ) == 0) {
> +				global_uncore_env = env;
> +				global_uncore_ops = ops;
> +				ret = 0;
> +				goto out;
> +			}
> +		POWER_LOG(ERR, "Power Management (%s) not supported",
> +				uncore_env_str[env]);
> +	} else
> +		POWER_LOG(ERR, "Invalid Power Management Environment");
>   
> -	default_uncore_env = env;
>   out:
>   	rte_spinlock_unlock(&global_env_cfg_lock);
>   	return ret;
> @@ -139,15 +89,22 @@ void
>   rte_power_unset_uncore_env(void)
>   {
>   	rte_spinlock_lock(&global_env_cfg_lock);
> -	default_uncore_env = RTE_UNCORE_PM_ENV_NOT_SET;
> -	reset_power_uncore_function_ptrs();
> +	global_uncore_env = RTE_UNCORE_PM_ENV_NOT_SET;
>   	rte_spinlock_unlock(&global_env_cfg_lock);
>   }
>   

How about abstract an ABI interface to intialize or set the uncore 
driver on platform by automatical.

And later do power_intel_uncore_init_on_die() for each die on different 
package.

>   enum rte_uncore_power_mgmt_env
>   rte_power_get_uncore_env(void)
>   {
> -	return default_uncore_env;
> +	return global_uncore_env;
> +}
> +
> +struct rte_power_uncore_ops *
> +rte_power_get_uncore_ops(void)
> +{
> +	RTE_ASSERT(global_uncore_ops != NULL);
> +
> +	return global_uncore_ops;
>   }
>   
>   int
> @@ -155,27 +112,29 @@ rte_power_uncore_init(unsigned int pkg, unsigned int die)
This pkg means the socket id on the platform, right?
If so, I am not sure that the 
uncore_info[RTE_MAX_NUMA_NODES][MAX_NUMA_DIE] used in uncore lib is 
universal for all uncore driver.
For example, uncore driver just support do uncore dvfs based on the 
socket unit.
What shoud we do for this? we may need to think twice.
>   {
>   	int ret = -1;
>   
<...>
  
Tummala, Sivaprasad Oct. 8, 2024, 6:19 a.m. UTC | #2
[AMD Official Use Only - AMD Internal Distribution Only]

Hi Lihuisong,

> -----Original Message-----
> From: lihuisong (C) <lihuisong@huawei.com>
> Sent: Tuesday, August 27, 2024 6:33 PM
> To: Tummala, Sivaprasad <Sivaprasad.Tummala@amd.com>
> Cc: dev@dpdk.org; david.hunt@intel.com; anatoly.burakov@intel.com;
> radu.nicolau@intel.com; jerinj@marvell.com; cristian.dumitrescu@intel.com;
> konstantin.ananyev@huawei.com; Yigit, Ferruh <Ferruh.Yigit@amd.com>;
> gakhil@marvell.com
> Subject: Re: [PATCH v2 2/4] power: refactor uncore power management library
>
> Caution: This message originated from an External Source. Use proper caution
> when opening attachments, clicking links, or responding.
>
>
> Hi Sivaprasad,
>
> Suggest to split this patch into two patches for easiler to review:
> patch-1: abstract a file for uncore dvfs core level, namely, the
> rte_power_uncore_ops.c you did.
> patch-2: move and rename, lib/power/power_intel_uncore.c =>
> drivers/power/intel_uncore/intel_uncore.c
>
> patch[1/4] is also too big and not good to review.
>
> In addition, I have some question and am not sure if we can adjust uncore init
> process.
>
> /Huisong
>
>
> 在 2024/8/26 21:06, Sivaprasad Tummala 写道:
> > This patch refactors the power management library, addressing uncore
> > power management. The primary changes involve the creation of
> > dedicated directories for each driver within 'drivers/power/uncore/*'.
> > The adjustment of meson.build files enables the selective activation
> > of individual drivers.
> >
> > This refactor significantly improves code organization, enhances
> > clarity and boosts maintainability. It lays the foundation for more
> > focused development on individual drivers and facilitates seamless
> > integration of future enhancements, particularly the AMD uncore driver.
> >
> > Signed-off-by: Sivaprasad Tummala <sivaprasad.tummala@amd.com>
> > ---
> >   .../power/intel_uncore/intel_uncore.c         |  18 +-
> >   .../power/intel_uncore/intel_uncore.h         |   8 +-
> >   drivers/power/intel_uncore/meson.build        |   6 +
> >   drivers/power/meson.build                     |   3 +-
> >   lib/power/meson.build                         |   2 +-
> >   lib/power/rte_power_uncore.c                  | 205 ++++++---------
> >   lib/power/rte_power_uncore.h                  |  87 ++++---
> >   lib/power/rte_power_uncore_ops.h              | 239 ++++++++++++++++++
> >   lib/power/version.map                         |   1 +
> >   9 files changed, 405 insertions(+), 164 deletions(-)
> >   rename lib/power/power_intel_uncore.c =>
> drivers/power/intel_uncore/intel_uncore.c (95%)
> >   rename lib/power/power_intel_uncore.h =>
> drivers/power/intel_uncore/intel_uncore.h (97%)
> >   create mode 100644 drivers/power/intel_uncore/meson.build
> >   create mode 100644 lib/power/rte_power_uncore_ops.h
> >
> > diff --git a/lib/power/power_intel_uncore.c
> > b/drivers/power/intel_uncore/intel_uncore.c
> > similarity index 95%
> > rename from lib/power/power_intel_uncore.c rename to
> > drivers/power/intel_uncore/intel_uncore.c
> > index 4eb9c5900a..804ad5d755 100644
> > --- a/lib/power/power_intel_uncore.c
> > +++ b/drivers/power/intel_uncore/intel_uncore.c
> > @@ -8,7 +8,7 @@
> >
> >   #include <rte_memcpy.h>
> >
> > -#include "power_intel_uncore.h"
> > +#include "intel_uncore.h"
> >   #include "power_common.h"
> >
> >   #define MAX_NUMA_DIE 8
> > @@ -475,3 +475,19 @@ power_intel_uncore_get_num_dies(unsigned int pkg)
> >
> >       return count;
> >   }
> <...>
> >
> > -#endif /* POWER_INTEL_UNCORE_H */
> > +#endif /* INTEL_UNCORE_H */
> > diff --git a/drivers/power/intel_uncore/meson.build
> > b/drivers/power/intel_uncore/meson.build
> > new file mode 100644
> > index 0000000000..876df8ad14
> > --- /dev/null
> > +++ b/drivers/power/intel_uncore/meson.build
> > @@ -0,0 +1,6 @@
> > +# SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2017 Intel
> > +Corporation # Copyright(c) 2024 Advanced Micro Devices, Inc.
> > +
> > +sources = files('intel_uncore.c')
> > +deps += ['power']
> > diff --git a/drivers/power/meson.build b/drivers/power/meson.build
> > index 8c7215c639..c83047af94 100644
> > --- a/drivers/power/meson.build
> > +++ b/drivers/power/meson.build
> > @@ -6,7 +6,8 @@ drivers = [
> >           'amd_pstate',
> >           'cppc',
> >           'kvm_vm',
> > -        'pstate'
> > +        'pstate',
> > +        'intel_uncore'
> The cppc, amd_pstate and so on belong to cpufreq scope.
> And intel_uncore belongs to uncore dvfs scope.
> They are not the same level. So I proposes that we need to create one directory
> called like cpufreq or core.
> This 'intel_uncore' name don't seems appropriate. what do you think the following
> directory structure:
> drivers/power/uncore/intel_uncore.c
> drivers/power/uncore/amd_uncore.c (according to the patch[4/4]).
At present, Meson does not support detecting an additional level of subdirectories within drivers/*.
All the drivers maintain a consistent subdirectory structure.
> >   ]
> >   std_deps = ['power']
> > diff --git a/lib/power/meson.build b/lib/power/meson.build index
> > f3e3451cdc..9b13d98810 100644
> > --- a/lib/power/meson.build
> > +++ b/lib/power/meson.build
> > @@ -13,7 +13,6 @@ if not is_linux
> >   endif
> >   sources = files(
> >           'power_common.c',
> > -        'power_intel_uncore.c',
> >           'rte_power.c',
> >           'rte_power_uncore.c',
> >           'rte_power_pmd_mgmt.c',
> > @@ -24,6 +23,7 @@ headers = files(
> >           'rte_power_guest_channel.h',
> >           'rte_power_pmd_mgmt.h',
> >           'rte_power_uncore.h',
> > +        'rte_power_uncore_ops.h',
> >   )
> >   if cc.has_argument('-Wno-cast-qual')
> >       cflags += '-Wno-cast-qual'
> > diff --git a/lib/power/rte_power_uncore.c
> > b/lib/power/rte_power_uncore.c index 48c75a5da0..9f8771224f 100644
> > --- a/lib/power/rte_power_uncore.c
> > +++ b/lib/power/rte_power_uncore.c
> > @@ -1,6 +1,7 @@
> >   /* SPDX-License-Identifier: BSD-3-Clause
> >    * Copyright(c) 2010-2014 Intel Corporation
> >    * Copyright(c) 2023 AMD Corporation
> > + * Copyright(c) 2024 Advanced Micro Devices, Inc.
> >    */
> >
> >   #include <errno.h>
> > @@ -12,98 +13,50 @@
> >   #include "rte_power_uncore.h"
> >   #include "power_intel_uncore.h"
> >
> > -enum rte_uncore_power_mgmt_env default_uncore_env =
> > RTE_UNCORE_PM_ENV_NOT_SET;
> > +static enum rte_uncore_power_mgmt_env global_uncore_env =
> > +RTE_UNCORE_PM_ENV_NOT_SET; static struct rte_power_uncore_ops
> > +*global_uncore_ops;
> >
> >   static rte_spinlock_t global_env_cfg_lock =
> > RTE_SPINLOCK_INITIALIZER;
> > +static RTE_TAILQ_HEAD(, rte_power_uncore_ops) uncore_ops_list =
> > +                     TAILQ_HEAD_INITIALIZER(uncore_ops_list);
> >
> > -static uint32_t
> > -power_get_dummy_uncore_freq(unsigned int pkg __rte_unused,
> > -            unsigned int die __rte_unused)
> > -{
> > -     return 0;
> > -}
> > -
> > -static int
> > -power_set_dummy_uncore_freq(unsigned int pkg __rte_unused,
> > -            unsigned int die __rte_unused, uint32_t index __rte_unused)
> > -{
> > -     return 0;
> > -}
> > +const char *uncore_env_str[] = {
> > +     "not set",
> > +     "auto-detect",
> > +     "intel-uncore",
> > +     "amd-hsmp"
> > +};
> Why open the "auto-detect" mode to user?
> Why not set this automatically at framework initialization?
> After all, the uncore driver is fixed for one platform.
The auto-detection feature has been implemented to enable seamless migration across platforms
without requiring any changes to the application
> >
> > -static int
> > -power_dummy_uncore_freq_max(unsigned int pkg __rte_unused,
> > -            unsigned int die __rte_unused)
> > -{
> > -     return 0;
> > -}
> > -
> <...>
> > -static int
> > -power_dummy_uncore_get_num_freqs(unsigned int pkg __rte_unused,
> > -            unsigned int die __rte_unused)
> > +/* register the ops struct in rte_power_uncore_ops, return 0 on
> > +success. */ int rte_power_register_uncore_ops(struct
> > +rte_power_uncore_ops *driver_ops)
> >   {
> > -     return 0;
> > -}
> > +     if (!driver_ops->init || !driver_ops->exit || !driver_ops->get_num_pkgs ||
> > +             !driver_ops->get_num_dies || !driver_ops->get_num_freqs ||
> > +             !driver_ops->get_avail_freqs || !driver_ops->get_freq ||
> > +             !driver_ops->set_freq || !driver_ops->freq_max ||
> > +             !driver_ops->freq_min) {
> > +             POWER_LOG(ERR, "Missing callbacks while registering power ops");
> > +             return -1;
> > +     }
> > +     if (driver_ops->cb)
> > +             driver_ops->cb();
> >
> > -static unsigned int
> > -power_dummy_uncore_get_num_pkgs(void)
> > -{
> > -     return 0;
> > -}
> > +     TAILQ_INSERT_TAIL(&uncore_ops_list, driver_ops, next);
> >
> > -static unsigned int
> > -power_dummy_uncore_get_num_dies(unsigned int pkg __rte_unused) -{
> >       return 0;
> >   }
> > -
> > -/* function pointers */
> > -rte_power_get_uncore_freq_t rte_power_get_uncore_freq =
> > power_get_dummy_uncore_freq; -rte_power_set_uncore_freq_t
> > rte_power_set_uncore_freq = power_set_dummy_uncore_freq;
> > -rte_power_uncore_freq_change_t rte_power_uncore_freq_max =
> > power_dummy_uncore_freq_max; -rte_power_uncore_freq_change_t
> > rte_power_uncore_freq_min = power_dummy_uncore_freq_min;
> > -rte_power_uncore_freqs_t rte_power_uncore_freqs =
> > power_dummy_uncore_freqs; -rte_power_uncore_get_num_freqs_t
> > rte_power_uncore_get_num_freqs = power_dummy_uncore_get_num_freqs;
> > -rte_power_uncore_get_num_pkgs_t rte_power_uncore_get_num_pkgs =
> > power_dummy_uncore_get_num_pkgs; -rte_power_uncore_get_num_dies_t
> > rte_power_uncore_get_num_dies = power_dummy_uncore_get_num_dies;
> > -
> > -static void
> > -reset_power_uncore_function_ptrs(void)
> > -{
> > -     rte_power_get_uncore_freq = power_get_dummy_uncore_freq;
> > -     rte_power_set_uncore_freq = power_set_dummy_uncore_freq;
> > -     rte_power_uncore_freq_max = power_dummy_uncore_freq_max;
> > -     rte_power_uncore_freq_min = power_dummy_uncore_freq_min;
> > -     rte_power_uncore_freqs  = power_dummy_uncore_freqs;
> > -     rte_power_uncore_get_num_freqs = power_dummy_uncore_get_num_freqs;
> > -     rte_power_uncore_get_num_pkgs = power_dummy_uncore_get_num_pkgs;
> > -     rte_power_uncore_get_num_dies = power_dummy_uncore_get_num_dies;
> > -}
> > -
> >   int
> >   rte_power_set_uncore_env(enum rte_uncore_power_mgmt_env env)
> >   {
> > -     int ret;
> > +     int ret = -1;
> > +     struct rte_power_uncore_ops *ops;
> >
> >       rte_spinlock_lock(&global_env_cfg_lock);
> >
> > -     if (default_uncore_env != RTE_UNCORE_PM_ENV_NOT_SET) {
> > +     if (global_uncore_env != RTE_UNCORE_PM_ENV_NOT_SET) {
> >               POWER_LOG(ERR, "Uncore Power Management Env already set.");
> > -             rte_spinlock_unlock(&global_env_cfg_lock);
> > -             return -1;
> > +             goto out;
> >       }
> >
> <...>
> > +     if (env <= RTE_DIM(uncore_env_str)) {
> > +             RTE_TAILQ_FOREACH(ops, &uncore_ops_list, next)
> > +                     if (strncmp(ops->name, uncore_env_str[env],
> > +                             RTE_POWER_UNCORE_DRIVER_NAMESZ) == 0) {
> > +                             global_uncore_env = env;
> > +                             global_uncore_ops = ops;
> > +                             ret = 0;
> > +                             goto out;
> > +                     }
> > +             POWER_LOG(ERR, "Power Management (%s) not supported",
> > +                             uncore_env_str[env]);
> > +     } else
> > +             POWER_LOG(ERR, "Invalid Power Management Environment");
> >
> > -     default_uncore_env = env;
> >   out:
> >       rte_spinlock_unlock(&global_env_cfg_lock);
> >       return ret;
> > @@ -139,15 +89,22 @@ void
> >   rte_power_unset_uncore_env(void)
> >   {
> >       rte_spinlock_lock(&global_env_cfg_lock);
> > -     default_uncore_env = RTE_UNCORE_PM_ENV_NOT_SET;
> > -     reset_power_uncore_function_ptrs();
> > +     global_uncore_env = RTE_UNCORE_PM_ENV_NOT_SET;
> >       rte_spinlock_unlock(&global_env_cfg_lock);
> >   }
> >
>
> How about abstract an ABI interface to intialize or set the uncore driver on platform
> by automatical.
>
> And later do power_intel_uncore_init_on_die() for each die on different package.

>
> >   enum rte_uncore_power_mgmt_env
> >   rte_power_get_uncore_env(void)
> >   {
> > -     return default_uncore_env;
> > +     return global_uncore_env;
> > +}
> > +
> > +struct rte_power_uncore_ops *
> > +rte_power_get_uncore_ops(void)
> > +{
> > +     RTE_ASSERT(global_uncore_ops != NULL);
> > +
> > +     return global_uncore_ops;
> >   }
> >
> >   int
> > @@ -155,27 +112,29 @@ rte_power_uncore_init(unsigned int pkg, unsigned
> > int die)
> This pkg means the socket id on the platform, right?
> If so, I am not sure that the
> uncore_info[RTE_MAX_NUMA_NODES][MAX_NUMA_DIE] used in uncore lib is
> universal for all uncore driver.
> For example, uncore driver just support do uncore dvfs based on the socket unit.
> What shoud we do for this? we may need to think twice.
Yes, pkg represents a socket id. In platforms with a single uncore controller per socket,
the die ID should be set to '0' for the corresponding socket ID (pkg).
.
> >   {
> >       int ret = -1;
> >
> <...>
  
lihuisong (C) Oct. 22, 2024, 2:05 a.m. UTC | #3
Hi Sivaprasa,

I have a inline question, please take a look.

在 2024/10/8 14:19, Tummala, Sivaprasad 写道:
> [AMD Official Use Only - AMD Internal Distribution Only]
>
> Hi Lihuisong,
>
>> -----Original Message-----
>> From: lihuisong (C) <lihuisong@huawei.com>
>> Sent: Tuesday, August 27, 2024 6:33 PM
>> To: Tummala, Sivaprasad <Sivaprasad.Tummala@amd.com>
>> Cc: dev@dpdk.org; david.hunt@intel.com; anatoly.burakov@intel.com;
>> radu.nicolau@intel.com; jerinj@marvell.com; cristian.dumitrescu@intel.com;
>> konstantin.ananyev@huawei.com; Yigit, Ferruh <Ferruh.Yigit@amd.com>;
>> gakhil@marvell.com
>> Subject: Re: [PATCH v2 2/4] power: refactor uncore power management library
>>
>> Caution: This message originated from an External Source. Use proper caution
>> when opening attachments, clicking links, or responding.
>>
>>
>> Hi Sivaprasad,
>>
>> Suggest to split this patch into two patches for easiler to review:
>> patch-1: abstract a file for uncore dvfs core level, namely, the
>> rte_power_uncore_ops.c you did.
>> patch-2: move and rename, lib/power/power_intel_uncore.c =>
>> drivers/power/intel_uncore/intel_uncore.c
>>
>> patch[1/4] is also too big and not good to review.
>>
>> In addition, I have some question and am not sure if we can adjust uncore init
>> process.
>>
>> /Huisong
>>
>>
>> 在 2024/8/26 21:06, Sivaprasad Tummala 写道:
>>> This patch refactors the power management library, addressing uncore
>>> power management. The primary changes involve the creation of
>>> dedicated directories for each driver within 'drivers/power/uncore/*'.
>>> The adjustment of meson.build files enables the selective activation
>>> of individual drivers.
>>>
>>> This refactor significantly improves code organization, enhances
>>> clarity and boosts maintainability. It lays the foundation for more
>>> focused development on individual drivers and facilitates seamless
>>> integration of future enhancements, particularly the AMD uncore driver.
>>>
>>> Signed-off-by: Sivaprasad Tummala <sivaprasad.tummala@amd.com>
>>> ---
>>>    .../power/intel_uncore/intel_uncore.c         |  18 +-
>>>    .../power/intel_uncore/intel_uncore.h         |   8 +-
>>>    drivers/power/intel_uncore/meson.build        |   6 +
>>>    drivers/power/meson.build                     |   3 +-
>>>    lib/power/meson.build                         |   2 +-
>>>    lib/power/rte_power_uncore.c                  | 205 ++++++---------
>>>    lib/power/rte_power_uncore.h                  |  87 ++++---
>>>    lib/power/rte_power_uncore_ops.h              | 239 ++++++++++++++++++
>>>    lib/power/version.map                         |   1 +
>>>    9 files changed, 405 insertions(+), 164 deletions(-)
>>>    rename lib/power/power_intel_uncore.c =>
>> drivers/power/intel_uncore/intel_uncore.c (95%)
>>>    rename lib/power/power_intel_uncore.h =>
>> drivers/power/intel_uncore/intel_uncore.h (97%)
>>>    create mode 100644 drivers/power/intel_uncore/meson.build
>>>    create mode 100644 lib/power/rte_power_uncore_ops.h
>>>
>>> diff --git a/lib/power/power_intel_uncore.c
>>> b/drivers/power/intel_uncore/intel_uncore.c
>>> similarity index 95%
>>> rename from lib/power/power_intel_uncore.c rename to
>>> drivers/power/intel_uncore/intel_uncore.c
>>> index 4eb9c5900a..804ad5d755 100644
>>> --- a/lib/power/power_intel_uncore.c
>>> +++ b/drivers/power/intel_uncore/intel_uncore.c
>>> @@ -8,7 +8,7 @@
>>>
>>>    #include <rte_memcpy.h>
>>>
>>> -#include "power_intel_uncore.h"
>>> +#include "intel_uncore.h"
>>>    #include "power_common.h"
>>>
>>>    #define MAX_NUMA_DIE 8
>>> @@ -475,3 +475,19 @@ power_intel_uncore_get_num_dies(unsigned int pkg)
>>>
>>>        return count;
>>>    }
>> <...>
>>> -#endif /* POWER_INTEL_UNCORE_H */
>>> +#endif /* INTEL_UNCORE_H */
>>> diff --git a/drivers/power/intel_uncore/meson.build
>>> b/drivers/power/intel_uncore/meson.build
>>> new file mode 100644
>>> index 0000000000..876df8ad14
>>> --- /dev/null
>>> +++ b/drivers/power/intel_uncore/meson.build
>>> @@ -0,0 +1,6 @@
>>> +# SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2017 Intel
>>> +Corporation # Copyright(c) 2024 Advanced Micro Devices, Inc.
>>> +
>>> +sources = files('intel_uncore.c')
>>> +deps += ['power']
>>> diff --git a/drivers/power/meson.build b/drivers/power/meson.build
>>> index 8c7215c639..c83047af94 100644
>>> --- a/drivers/power/meson.build
>>> +++ b/drivers/power/meson.build
>>> @@ -6,7 +6,8 @@ drivers = [
>>>            'amd_pstate',
>>>            'cppc',
>>>            'kvm_vm',
>>> -        'pstate'
>>> +        'pstate',
>>> +        'intel_uncore'
>> The cppc, amd_pstate and so on belong to cpufreq scope.
>> And intel_uncore belongs to uncore dvfs scope.
>> They are not the same level. So I proposes that we need to create one directory
>> called like cpufreq or core.
>> This 'intel_uncore' name don't seems appropriate. what do you think the following
>> directory structure:
>> drivers/power/uncore/intel_uncore.c
>> drivers/power/uncore/amd_uncore.c (according to the patch[4/4]).
> At present, Meson does not support detecting an additional level of subdirectories within drivers/*.
> All the drivers maintain a consistent subdirectory structure.
>>>    ]
>>>    std_deps = ['power']
>>> diff --git a/lib/power/meson.build b/lib/power/meson.build index
>>> f3e3451cdc..9b13d98810 100644
>>> --- a/lib/power/meson.build
>>> +++ b/lib/power/meson.build
>>> @@ -13,7 +13,6 @@ if not is_linux
>>>    endif
>>>    sources = files(
>>>            'power_common.c',
>>> -        'power_intel_uncore.c',
>>>            'rte_power.c',
>>>            'rte_power_uncore.c',
>>>            'rte_power_pmd_mgmt.c',
>>> @@ -24,6 +23,7 @@ headers = files(
>>>            'rte_power_guest_channel.h',
>>>            'rte_power_pmd_mgmt.h',
>>>            'rte_power_uncore.h',
>>> +        'rte_power_uncore_ops.h',
>>>    )
>>>    if cc.has_argument('-Wno-cast-qual')
>>>        cflags += '-Wno-cast-qual'
>>> diff --git a/lib/power/rte_power_uncore.c
>>> b/lib/power/rte_power_uncore.c index 48c75a5da0..9f8771224f 100644
>>> --- a/lib/power/rte_power_uncore.c
>>> +++ b/lib/power/rte_power_uncore.c
>>> @@ -1,6 +1,7 @@
>>>    /* SPDX-License-Identifier: BSD-3-Clause
>>>     * Copyright(c) 2010-2014 Intel Corporation
>>>     * Copyright(c) 2023 AMD Corporation
>>> + * Copyright(c) 2024 Advanced Micro Devices, Inc.
>>>     */
>>>
>>>    #include <errno.h>
>>> @@ -12,98 +13,50 @@
>>>    #include "rte_power_uncore.h"
>>>    #include "power_intel_uncore.h"
>>>
>>> -enum rte_uncore_power_mgmt_env default_uncore_env =
>>> RTE_UNCORE_PM_ENV_NOT_SET;
>>> +static enum rte_uncore_power_mgmt_env global_uncore_env =
>>> +RTE_UNCORE_PM_ENV_NOT_SET; static struct rte_power_uncore_ops
>>> +*global_uncore_ops;
>>>
>>>    static rte_spinlock_t global_env_cfg_lock =
>>> RTE_SPINLOCK_INITIALIZER;
>>> +static RTE_TAILQ_HEAD(, rte_power_uncore_ops) uncore_ops_list =
>>> +                     TAILQ_HEAD_INITIALIZER(uncore_ops_list);
>>>
>>> -static uint32_t
>>> -power_get_dummy_uncore_freq(unsigned int pkg __rte_unused,
>>> -            unsigned int die __rte_unused)
>>> -{
>>> -     return 0;
>>> -}
>>> -
>>> -static int
>>> -power_set_dummy_uncore_freq(unsigned int pkg __rte_unused,
>>> -            unsigned int die __rte_unused, uint32_t index __rte_unused)
>>> -{
>>> -     return 0;
>>> -}
>>> +const char *uncore_env_str[] = {
>>> +     "not set",
>>> +     "auto-detect",
>>> +     "intel-uncore",
>>> +     "amd-hsmp"
>>> +};
>> Why open the "auto-detect" mode to user?
>> Why not set this automatically at framework initialization?
>> After all, the uncore driver is fixed for one platform.
> The auto-detection feature has been implemented to enable seamless migration across platforms
> without requiring any changes to the application
>>> -static int
>>> -power_dummy_uncore_freq_max(unsigned int pkg __rte_unused,
>>> -            unsigned int die __rte_unused)
>>> -{
>>> -     return 0;
>>> -}
>>> -
>> <...>
>>> -static int
>>> -power_dummy_uncore_get_num_freqs(unsigned int pkg __rte_unused,
>>> -            unsigned int die __rte_unused)
>>> +/* register the ops struct in rte_power_uncore_ops, return 0 on
>>> +success. */ int rte_power_register_uncore_ops(struct
>>> +rte_power_uncore_ops *driver_ops)
>>>    {
>>> -     return 0;
>>> -}
>>> +     if (!driver_ops->init || !driver_ops->exit || !driver_ops->get_num_pkgs ||
>>> +             !driver_ops->get_num_dies || !driver_ops->get_num_freqs ||
>>> +             !driver_ops->get_avail_freqs || !driver_ops->get_freq ||
>>> +             !driver_ops->set_freq || !driver_ops->freq_max ||
>>> +             !driver_ops->freq_min) {
>>> +             POWER_LOG(ERR, "Missing callbacks while registering power ops");
>>> +             return -1;
>>> +     }
>>> +     if (driver_ops->cb)
>>> +             driver_ops->cb();
>>>
>>> -static unsigned int
>>> -power_dummy_uncore_get_num_pkgs(void)
>>> -{
>>> -     return 0;
>>> -}
>>> +     TAILQ_INSERT_TAIL(&uncore_ops_list, driver_ops, next);
>>>
>>> -static unsigned int
>>> -power_dummy_uncore_get_num_dies(unsigned int pkg __rte_unused) -{
>>>        return 0;
>>>    }
>>> -
>>> -/* function pointers */
>>> -rte_power_get_uncore_freq_t rte_power_get_uncore_freq =
>>> power_get_dummy_uncore_freq; -rte_power_set_uncore_freq_t
>>> rte_power_set_uncore_freq = power_set_dummy_uncore_freq;
>>> -rte_power_uncore_freq_change_t rte_power_uncore_freq_max =
>>> power_dummy_uncore_freq_max; -rte_power_uncore_freq_change_t
>>> rte_power_uncore_freq_min = power_dummy_uncore_freq_min;
>>> -rte_power_uncore_freqs_t rte_power_uncore_freqs =
>>> power_dummy_uncore_freqs; -rte_power_uncore_get_num_freqs_t
>>> rte_power_uncore_get_num_freqs = power_dummy_uncore_get_num_freqs;
>>> -rte_power_uncore_get_num_pkgs_t rte_power_uncore_get_num_pkgs =
>>> power_dummy_uncore_get_num_pkgs; -rte_power_uncore_get_num_dies_t
>>> rte_power_uncore_get_num_dies = power_dummy_uncore_get_num_dies;
>>> -
>>> -static void
>>> -reset_power_uncore_function_ptrs(void)
>>> -{
>>> -     rte_power_get_uncore_freq = power_get_dummy_uncore_freq;
>>> -     rte_power_set_uncore_freq = power_set_dummy_uncore_freq;
>>> -     rte_power_uncore_freq_max = power_dummy_uncore_freq_max;
>>> -     rte_power_uncore_freq_min = power_dummy_uncore_freq_min;
>>> -     rte_power_uncore_freqs  = power_dummy_uncore_freqs;
>>> -     rte_power_uncore_get_num_freqs = power_dummy_uncore_get_num_freqs;
>>> -     rte_power_uncore_get_num_pkgs = power_dummy_uncore_get_num_pkgs;
>>> -     rte_power_uncore_get_num_dies = power_dummy_uncore_get_num_dies;
>>> -}
>>> -
>>>    int
>>>    rte_power_set_uncore_env(enum rte_uncore_power_mgmt_env env)
>>>    {
>>> -     int ret;
>>> +     int ret = -1;
>>> +     struct rte_power_uncore_ops *ops;
>>>
>>>        rte_spinlock_lock(&global_env_cfg_lock);
>>>
>>> -     if (default_uncore_env != RTE_UNCORE_PM_ENV_NOT_SET) {
>>> +     if (global_uncore_env != RTE_UNCORE_PM_ENV_NOT_SET) {
>>>                POWER_LOG(ERR, "Uncore Power Management Env already set.");
>>> -             rte_spinlock_unlock(&global_env_cfg_lock);
>>> -             return -1;
>>> +             goto out;
>>>        }
>>>
>> <...>
>>> +     if (env <= RTE_DIM(uncore_env_str)) {
>>> +             RTE_TAILQ_FOREACH(ops, &uncore_ops_list, next)
>>> +                     if (strncmp(ops->name, uncore_env_str[env],
>>> +                             RTE_POWER_UNCORE_DRIVER_NAMESZ) == 0) {
>>> +                             global_uncore_env = env;
>>> +                             global_uncore_ops = ops;
>>> +                             ret = 0;
>>> +                             goto out;
>>> +                     }
>>> +             POWER_LOG(ERR, "Power Management (%s) not supported",
>>> +                             uncore_env_str[env]);
>>> +     } else
>>> +             POWER_LOG(ERR, "Invalid Power Management Environment");
>>>
>>> -     default_uncore_env = env;
>>>    out:
>>>        rte_spinlock_unlock(&global_env_cfg_lock);
>>>        return ret;
>>> @@ -139,15 +89,22 @@ void
>>>    rte_power_unset_uncore_env(void)
>>>    {
>>>        rte_spinlock_lock(&global_env_cfg_lock);
>>> -     default_uncore_env = RTE_UNCORE_PM_ENV_NOT_SET;
>>> -     reset_power_uncore_function_ptrs();
>>> +     global_uncore_env = RTE_UNCORE_PM_ENV_NOT_SET;
>>>        rte_spinlock_unlock(&global_env_cfg_lock);
>>>    }
>>>
>> How about abstract an ABI interface to intialize or set the uncore driver on platform
>> by automatical.
>>
>> And later do power_intel_uncore_init_on_die() for each die on different package.
>>>    enum rte_uncore_power_mgmt_env
>>>    rte_power_get_uncore_env(void)
>>>    {
>>> -     return default_uncore_env;
>>> +     return global_uncore_env;
>>> +}
>>> +
>>> +struct rte_power_uncore_ops *
>>> +rte_power_get_uncore_ops(void)
>>> +{
>>> +     RTE_ASSERT(global_uncore_ops != NULL);
>>> +
>>> +     return global_uncore_ops;
>>>    }
>>>
>>>    int
>>> @@ -155,27 +112,29 @@ rte_power_uncore_init(unsigned int pkg, unsigned
>>> int die)
>> This pkg means the socket id on the platform, right?
>> If so, I am not sure that the
>> uncore_info[RTE_MAX_NUMA_NODES][MAX_NUMA_DIE] used in uncore lib is
>> universal for all uncore driver.
>> For example, uncore driver just support do uncore dvfs based on the socket unit.
>> What shoud we do for this? we may need to think twice.
> Yes, pkg represents a socket id. In platforms with a single uncore controller per socket,
> the die ID should be set to '0' for the corresponding socket ID (pkg).
> .
So just use the die ID 0 on one socket ID(namely, uncore_info[0][0], 
uncore_info[1][0]) to initialize the uncore power info on sockets, right?
 From the implement in l3fwd-power, it set all die ID and all sockets.
For the platform with a single uncore controller per socket, their 
uncore driver in DPDK have to ignore other die IDs except die-0 on one 
socket. right?
>>>    {
>>>        int ret = -1;
>>>
>> <...>
  

Patch

diff --git a/lib/power/power_intel_uncore.c b/drivers/power/intel_uncore/intel_uncore.c
similarity index 95%
rename from lib/power/power_intel_uncore.c
rename to drivers/power/intel_uncore/intel_uncore.c
index 4eb9c5900a..804ad5d755 100644
--- a/lib/power/power_intel_uncore.c
+++ b/drivers/power/intel_uncore/intel_uncore.c
@@ -8,7 +8,7 @@ 
 
 #include <rte_memcpy.h>
 
-#include "power_intel_uncore.h"
+#include "intel_uncore.h"
 #include "power_common.h"
 
 #define MAX_NUMA_DIE 8
@@ -475,3 +475,19 @@  power_intel_uncore_get_num_dies(unsigned int pkg)
 
 	return count;
 }
+
+static struct rte_power_uncore_ops intel_uncore_ops = {
+	.name = "intel-uncore",
+	.init = power_intel_uncore_init,
+	.exit = power_intel_uncore_exit,
+	.get_avail_freqs = power_intel_uncore_freqs,
+	.get_num_pkgs = power_intel_uncore_get_num_pkgs,
+	.get_num_dies = power_intel_uncore_get_num_dies,
+	.get_num_freqs = power_intel_uncore_get_num_freqs,
+	.get_freq = power_get_intel_uncore_freq,
+	.set_freq = power_set_intel_uncore_freq,
+	.freq_max = power_intel_uncore_freq_max,
+	.freq_min = power_intel_uncore_freq_min,
+};
+
+RTE_POWER_REGISTER_UNCORE_OPS(intel_uncore_ops);
diff --git a/lib/power/power_intel_uncore.h b/drivers/power/intel_uncore/intel_uncore.h
similarity index 97%
rename from lib/power/power_intel_uncore.h
rename to drivers/power/intel_uncore/intel_uncore.h
index 20a3ba8ebe..f2ce2f0c66 100644
--- a/lib/power/power_intel_uncore.h
+++ b/drivers/power/intel_uncore/intel_uncore.h
@@ -2,8 +2,8 @@ 
  * Copyright(c) 2022 Intel Corporation
  */
 
-#ifndef POWER_INTEL_UNCORE_H
-#define POWER_INTEL_UNCORE_H
+#ifndef INTEL_UNCORE_H
+#define INTEL_UNCORE_H
 
 /**
  * @file
@@ -11,7 +11,7 @@ 
  */
 
 #include "rte_power.h"
-#include "rte_power_uncore.h"
+#include "rte_power_uncore_ops.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -223,4 +223,4 @@  power_intel_uncore_get_num_dies(unsigned int pkg);
 }
 #endif
 
-#endif /* POWER_INTEL_UNCORE_H */
+#endif /* INTEL_UNCORE_H */
diff --git a/drivers/power/intel_uncore/meson.build b/drivers/power/intel_uncore/meson.build
new file mode 100644
index 0000000000..876df8ad14
--- /dev/null
+++ b/drivers/power/intel_uncore/meson.build
@@ -0,0 +1,6 @@ 
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2017 Intel Corporation
+# Copyright(c) 2024 Advanced Micro Devices, Inc.
+
+sources = files('intel_uncore.c')
+deps += ['power']
diff --git a/drivers/power/meson.build b/drivers/power/meson.build
index 8c7215c639..c83047af94 100644
--- a/drivers/power/meson.build
+++ b/drivers/power/meson.build
@@ -6,7 +6,8 @@  drivers = [
         'amd_pstate',
         'cppc',
         'kvm_vm',
-        'pstate'
+        'pstate',
+        'intel_uncore'
 ]
 
 std_deps = ['power']
diff --git a/lib/power/meson.build b/lib/power/meson.build
index f3e3451cdc..9b13d98810 100644
--- a/lib/power/meson.build
+++ b/lib/power/meson.build
@@ -13,7 +13,6 @@  if not is_linux
 endif
 sources = files(
         'power_common.c',
-        'power_intel_uncore.c',
         'rte_power.c',
         'rte_power_uncore.c',
         'rte_power_pmd_mgmt.c',
@@ -24,6 +23,7 @@  headers = files(
         'rte_power_guest_channel.h',
         'rte_power_pmd_mgmt.h',
         'rte_power_uncore.h',
+        'rte_power_uncore_ops.h',
 )
 if cc.has_argument('-Wno-cast-qual')
     cflags += '-Wno-cast-qual'
diff --git a/lib/power/rte_power_uncore.c b/lib/power/rte_power_uncore.c
index 48c75a5da0..9f8771224f 100644
--- a/lib/power/rte_power_uncore.c
+++ b/lib/power/rte_power_uncore.c
@@ -1,6 +1,7 @@ 
 /* SPDX-License-Identifier: BSD-3-Clause
  * Copyright(c) 2010-2014 Intel Corporation
  * Copyright(c) 2023 AMD Corporation
+ * Copyright(c) 2024 Advanced Micro Devices, Inc.
  */
 
 #include <errno.h>
@@ -12,98 +13,50 @@ 
 #include "rte_power_uncore.h"
 #include "power_intel_uncore.h"
 
-enum rte_uncore_power_mgmt_env default_uncore_env = RTE_UNCORE_PM_ENV_NOT_SET;
+static enum rte_uncore_power_mgmt_env global_uncore_env = RTE_UNCORE_PM_ENV_NOT_SET;
+static struct rte_power_uncore_ops *global_uncore_ops;
 
 static rte_spinlock_t global_env_cfg_lock = RTE_SPINLOCK_INITIALIZER;
+static RTE_TAILQ_HEAD(, rte_power_uncore_ops) uncore_ops_list =
+			TAILQ_HEAD_INITIALIZER(uncore_ops_list);
 
-static uint32_t
-power_get_dummy_uncore_freq(unsigned int pkg __rte_unused,
-	       unsigned int die __rte_unused)
-{
-	return 0;
-}
-
-static int
-power_set_dummy_uncore_freq(unsigned int pkg __rte_unused,
-	       unsigned int die __rte_unused, uint32_t index __rte_unused)
-{
-	return 0;
-}
+const char *uncore_env_str[] = {
+	"not set",
+	"auto-detect",
+	"intel-uncore",
+	"amd-hsmp"
+};
 
-static int
-power_dummy_uncore_freq_max(unsigned int pkg __rte_unused,
-	       unsigned int die __rte_unused)
-{
-	return 0;
-}
-
-static int
-power_dummy_uncore_freq_min(unsigned int pkg __rte_unused,
-	       unsigned int die __rte_unused)
-{
-	return 0;
-}
-
-static int
-power_dummy_uncore_freqs(unsigned int pkg __rte_unused, unsigned int die __rte_unused,
-		uint32_t *freqs __rte_unused, uint32_t num __rte_unused)
-{
-	return 0;
-}
-
-static int
-power_dummy_uncore_get_num_freqs(unsigned int pkg __rte_unused,
-	       unsigned int die __rte_unused)
+/* register the ops struct in rte_power_uncore_ops, return 0 on success. */
+int
+rte_power_register_uncore_ops(struct rte_power_uncore_ops *driver_ops)
 {
-	return 0;
-}
+	if (!driver_ops->init || !driver_ops->exit || !driver_ops->get_num_pkgs ||
+		!driver_ops->get_num_dies || !driver_ops->get_num_freqs ||
+		!driver_ops->get_avail_freqs || !driver_ops->get_freq ||
+		!driver_ops->set_freq || !driver_ops->freq_max ||
+		!driver_ops->freq_min) {
+		POWER_LOG(ERR, "Missing callbacks while registering power ops");
+		return -1;
+	}
+	if (driver_ops->cb)
+		driver_ops->cb();
 
-static unsigned int
-power_dummy_uncore_get_num_pkgs(void)
-{
-	return 0;
-}
+	TAILQ_INSERT_TAIL(&uncore_ops_list, driver_ops, next);
 
-static unsigned int
-power_dummy_uncore_get_num_dies(unsigned int pkg __rte_unused)
-{
 	return 0;
 }
-
-/* function pointers */
-rte_power_get_uncore_freq_t rte_power_get_uncore_freq = power_get_dummy_uncore_freq;
-rte_power_set_uncore_freq_t rte_power_set_uncore_freq = power_set_dummy_uncore_freq;
-rte_power_uncore_freq_change_t rte_power_uncore_freq_max = power_dummy_uncore_freq_max;
-rte_power_uncore_freq_change_t rte_power_uncore_freq_min = power_dummy_uncore_freq_min;
-rte_power_uncore_freqs_t rte_power_uncore_freqs = power_dummy_uncore_freqs;
-rte_power_uncore_get_num_freqs_t rte_power_uncore_get_num_freqs = power_dummy_uncore_get_num_freqs;
-rte_power_uncore_get_num_pkgs_t rte_power_uncore_get_num_pkgs = power_dummy_uncore_get_num_pkgs;
-rte_power_uncore_get_num_dies_t rte_power_uncore_get_num_dies = power_dummy_uncore_get_num_dies;
-
-static void
-reset_power_uncore_function_ptrs(void)
-{
-	rte_power_get_uncore_freq = power_get_dummy_uncore_freq;
-	rte_power_set_uncore_freq = power_set_dummy_uncore_freq;
-	rte_power_uncore_freq_max = power_dummy_uncore_freq_max;
-	rte_power_uncore_freq_min = power_dummy_uncore_freq_min;
-	rte_power_uncore_freqs  = power_dummy_uncore_freqs;
-	rte_power_uncore_get_num_freqs = power_dummy_uncore_get_num_freqs;
-	rte_power_uncore_get_num_pkgs = power_dummy_uncore_get_num_pkgs;
-	rte_power_uncore_get_num_dies = power_dummy_uncore_get_num_dies;
-}
-
 int
 rte_power_set_uncore_env(enum rte_uncore_power_mgmt_env env)
 {
-	int ret;
+	int ret = -1;
+	struct rte_power_uncore_ops *ops;
 
 	rte_spinlock_lock(&global_env_cfg_lock);
 
-	if (default_uncore_env != RTE_UNCORE_PM_ENV_NOT_SET) {
+	if (global_uncore_env != RTE_UNCORE_PM_ENV_NOT_SET) {
 		POWER_LOG(ERR, "Uncore Power Management Env already set.");
-		rte_spinlock_unlock(&global_env_cfg_lock);
-		return -1;
+		goto out;
 	}
 
 	if (env == RTE_UNCORE_PM_ENV_AUTO_DETECT)
@@ -113,23 +66,20 @@  rte_power_set_uncore_env(enum rte_uncore_power_mgmt_env env)
 		 */
 		env = RTE_UNCORE_PM_ENV_INTEL_UNCORE;
 
-	ret = 0;
-	if (env == RTE_UNCORE_PM_ENV_INTEL_UNCORE) {
-		rte_power_get_uncore_freq = power_get_intel_uncore_freq;
-		rte_power_set_uncore_freq = power_set_intel_uncore_freq;
-		rte_power_uncore_freq_min  = power_intel_uncore_freq_min;
-		rte_power_uncore_freq_max  = power_intel_uncore_freq_max;
-		rte_power_uncore_freqs = power_intel_uncore_freqs;
-		rte_power_uncore_get_num_freqs = power_intel_uncore_get_num_freqs;
-		rte_power_uncore_get_num_pkgs = power_intel_uncore_get_num_pkgs;
-		rte_power_uncore_get_num_dies = power_intel_uncore_get_num_dies;
-	} else {
-		POWER_LOG(ERR, "Invalid Power Management Environment(%d) set", env);
-		ret = -1;
-		goto out;
-	}
+	if (env <= RTE_DIM(uncore_env_str)) {
+		RTE_TAILQ_FOREACH(ops, &uncore_ops_list, next)
+			if (strncmp(ops->name, uncore_env_str[env],
+				RTE_POWER_UNCORE_DRIVER_NAMESZ) == 0) {
+				global_uncore_env = env;
+				global_uncore_ops = ops;
+				ret = 0;
+				goto out;
+			}
+		POWER_LOG(ERR, "Power Management (%s) not supported",
+				uncore_env_str[env]);
+	} else
+		POWER_LOG(ERR, "Invalid Power Management Environment");
 
-	default_uncore_env = env;
 out:
 	rte_spinlock_unlock(&global_env_cfg_lock);
 	return ret;
@@ -139,15 +89,22 @@  void
 rte_power_unset_uncore_env(void)
 {
 	rte_spinlock_lock(&global_env_cfg_lock);
-	default_uncore_env = RTE_UNCORE_PM_ENV_NOT_SET;
-	reset_power_uncore_function_ptrs();
+	global_uncore_env = RTE_UNCORE_PM_ENV_NOT_SET;
 	rte_spinlock_unlock(&global_env_cfg_lock);
 }
 
 enum rte_uncore_power_mgmt_env
 rte_power_get_uncore_env(void)
 {
-	return default_uncore_env;
+	return global_uncore_env;
+}
+
+struct rte_power_uncore_ops *
+rte_power_get_uncore_ops(void)
+{
+	RTE_ASSERT(global_uncore_ops != NULL);
+
+	return global_uncore_ops;
 }
 
 int
@@ -155,27 +112,29 @@  rte_power_uncore_init(unsigned int pkg, unsigned int die)
 {
 	int ret = -1;
 
-	switch (default_uncore_env) {
-	case RTE_UNCORE_PM_ENV_INTEL_UNCORE:
-		return power_intel_uncore_init(pkg, die);
-	default:
-		POWER_LOG(INFO, "Uncore Env isn't set yet!");
-		break;
-	}
-
-	/* Auto detect Environment */
-	POWER_LOG(INFO, "Attempting to initialise Intel Uncore power mgmt...");
-	ret = power_intel_uncore_init(pkg, die);
-	if (ret == 0) {
-		rte_power_set_uncore_env(RTE_UNCORE_PM_ENV_INTEL_UNCORE);
-		goto out;
-	}
-
-	if (default_uncore_env == RTE_UNCORE_PM_ENV_NOT_SET) {
-		POWER_LOG(ERR, "Unable to set Power Management Environment "
-			"for package %u Die %u", pkg, die);
-		ret = 0;
-	}
+	struct rte_power_uncore_ops *ops;
+	uint8_t env;
+
+	if ((global_uncore_env != RTE_UNCORE_PM_ENV_NOT_SET) &&
+			(global_uncore_env != RTE_UNCORE_PM_ENV_AUTO_DETECT))
+		return global_uncore_ops->init(pkg, die);
+
+	/* Auto Detect Environment */
+	RTE_TAILQ_FOREACH(ops, &uncore_ops_list, next)
+		if (ops) {
+			POWER_LOG(INFO,
+				"Attempting to initialise %s power management...",
+				ops->name);
+			ret = ops->init(pkg, die);
+			if (ret == 0) {
+				for (env = 0; env < RTE_DIM(uncore_env_str); env++)
+					if (strncmp(ops->name, uncore_env_str[env],
+						RTE_POWER_UNCORE_DRIVER_NAMESZ) == 0) {
+						rte_power_set_uncore_env(env);
+						goto out;
+					}
+			}
+		}
 out:
 	return ret;
 }
@@ -183,12 +142,12 @@  rte_power_uncore_init(unsigned int pkg, unsigned int die)
 int
 rte_power_uncore_exit(unsigned int pkg, unsigned int die)
 {
-	switch (default_uncore_env) {
-	case RTE_UNCORE_PM_ENV_INTEL_UNCORE:
-		return power_intel_uncore_exit(pkg, die);
-	default:
-		POWER_LOG(ERR, "Uncore Env has not been set, unable to exit gracefully");
-		break;
-	}
+	if ((global_uncore_env != RTE_UNCORE_PM_ENV_NOT_SET) &&
+			global_uncore_ops)
+		return global_uncore_ops->exit(pkg, die);
+
+	POWER_LOG(ERR,
+		"Uncore Env has not been set, unable to exit gracefully");
+
 	return -1;
 }
diff --git a/lib/power/rte_power_uncore.h b/lib/power/rte_power_uncore.h
index 99859042dd..c9fba02568 100644
--- a/lib/power/rte_power_uncore.h
+++ b/lib/power/rte_power_uncore.h
@@ -1,6 +1,7 @@ 
 /* SPDX-License-Identifier: BSD-3-Clause
  * Copyright(c) 2022 Intel Corporation
  * Copyright(c) 2023 AMD Corporation
+ * Copyright(c) 2024 Advanced Micro Devices, Inc.
  */
 
 #ifndef RTE_POWER_UNCORE_H
@@ -11,8 +12,7 @@ 
  * RTE Uncore Frequency Management
  */
 
-#include <rte_compat.h>
-#include "rte_power.h"
+#include "rte_power_uncore_ops.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -116,9 +116,13 @@  rte_power_uncore_exit(unsigned int pkg, unsigned int die);
  *  The current index of available frequencies.
  *  If error, it will return 'RTE_POWER_INVALID_FREQ_INDEX = (~0)'.
  */
-typedef uint32_t (*rte_power_get_uncore_freq_t)(unsigned int pkg, unsigned int die);
+static inline uint32_t
+rte_power_get_uncore_freq(unsigned int pkg, unsigned int die)
+{
+	struct rte_power_uncore_ops *ops = rte_power_get_uncore_ops();
 
-extern rte_power_get_uncore_freq_t rte_power_get_uncore_freq;
+	return ops->get_freq(pkg, die);
+}
 
 /**
  * Set minimum and maximum uncore frequency for specified die on a package
@@ -141,26 +145,13 @@  extern rte_power_get_uncore_freq_t rte_power_get_uncore_freq;
  *  - 0 on success without frequency changed.
  *  - Negative on error.
  */
-typedef int (*rte_power_set_uncore_freq_t)(unsigned int pkg, unsigned int die, uint32_t index);
-
-extern rte_power_set_uncore_freq_t rte_power_set_uncore_freq;
+static inline uint32_t
+rte_power_set_uncore_freq(unsigned int pkg, unsigned int die, uint32_t index)
+{
+	struct rte_power_uncore_ops *ops = rte_power_get_uncore_ops();
 
-/**
- * Function pointer definition for generic frequency change functions.
- *
- * @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.
- */
-typedef int (*rte_power_uncore_freq_change_t)(unsigned int pkg, unsigned int die);
+	return ops->set_freq(pkg, die, index);
+}
 
 /**
  * Set minimum and maximum uncore frequency for specified die on a package
@@ -169,7 +160,13 @@  typedef int (*rte_power_uncore_freq_change_t)(unsigned int pkg, unsigned int die
  *
  * This function should NOT be called in the fast path.
  */
-extern rte_power_uncore_freq_change_t rte_power_uncore_freq_max;
+static inline uint32_t
+rte_power_uncore_freq_max(unsigned int pkg, unsigned int die)
+{
+	struct rte_power_uncore_ops *ops = rte_power_get_uncore_ops();
+
+	return ops->freq_max(pkg, die);
+}
 
 /**
  * Set minimum and maximum uncore frequency for specified die on a package
@@ -178,7 +175,13 @@  extern rte_power_uncore_freq_change_t rte_power_uncore_freq_max;
  *
  * This function should NOT be called in the fast path.
  */
-extern rte_power_uncore_freq_change_t rte_power_uncore_freq_min;
+static inline uint32_t
+rte_power_uncore_freq_min(unsigned int pkg, unsigned int die)
+{
+	struct rte_power_uncore_ops *ops = rte_power_get_uncore_ops();
+
+	return ops->freq_min(pkg, die);
+}
 
 /**
  * Return the list of available frequencies in the index array.
@@ -200,10 +203,14 @@  extern rte_power_uncore_freq_change_t rte_power_uncore_freq_min;
  *  - The number of available index's in frequency array.
  *  - Negative on error.
  */
-typedef int (*rte_power_uncore_freqs_t)(unsigned int pkg, unsigned int die,
-		uint32_t *freqs, uint32_t num);
+static inline uint32_t
+rte_power_uncore_freqs(unsigned int pkg, unsigned int die,
+			uint32_t *freqs, uint32_t num)
+{
+	struct rte_power_uncore_ops *ops = rte_power_get_uncore_ops();
 
-extern rte_power_uncore_freqs_t rte_power_uncore_freqs;
+	return ops->get_avail_freqs(pkg, die, freqs, num);
+}
 
 /**
  * Return the list length of available frequencies in the index array.
@@ -221,9 +228,13 @@  extern rte_power_uncore_freqs_t rte_power_uncore_freqs;
  *  - The number of available index's in frequency array.
  *  - Negative on error.
  */
-typedef int (*rte_power_uncore_get_num_freqs_t)(unsigned int pkg, unsigned int die);
+static inline int
+rte_power_uncore_get_num_freqs(unsigned int pkg, unsigned int die)
+{
+	struct rte_power_uncore_ops *ops = rte_power_get_uncore_ops();
 
-extern rte_power_uncore_get_num_freqs_t rte_power_uncore_get_num_freqs;
+	return ops->get_num_freqs(pkg, die);
+}
 
 /**
  * Return the number of packages (CPUs) on a system
@@ -235,9 +246,13 @@  extern rte_power_uncore_get_num_freqs_t rte_power_uncore_get_num_freqs;
  *  - Zero on error.
  *  - Number of package on system on success.
  */
-typedef unsigned int (*rte_power_uncore_get_num_pkgs_t)(void);
+static inline unsigned int
+rte_power_uncore_get_num_pkgs(void)
+{
+	struct rte_power_uncore_ops *ops = rte_power_get_uncore_ops();
 
-extern rte_power_uncore_get_num_pkgs_t rte_power_uncore_get_num_pkgs;
+	return ops->get_num_pkgs();
+}
 
 /**
  * Return the number of dies for pakckages (CPUs) specified
@@ -253,9 +268,13 @@  extern rte_power_uncore_get_num_pkgs_t rte_power_uncore_get_num_pkgs;
  *  - Zero on error.
  *  - Number of dies for package on sucecss.
  */
-typedef unsigned int (*rte_power_uncore_get_num_dies_t)(unsigned int pkg);
+static inline unsigned int
+rte_power_uncore_get_num_dies(unsigned int pkg)
+{
+	struct rte_power_uncore_ops *ops = rte_power_get_uncore_ops();
 
-extern rte_power_uncore_get_num_dies_t rte_power_uncore_get_num_dies;
+	return ops->get_num_dies(pkg);
+}
 
 #ifdef __cplusplus
 }
diff --git a/lib/power/rte_power_uncore_ops.h b/lib/power/rte_power_uncore_ops.h
new file mode 100644
index 0000000000..623d63800c
--- /dev/null
+++ b/lib/power/rte_power_uncore_ops.h
@@ -0,0 +1,239 @@ 
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2022 Intel Corporation
+ * Copyright(c) 2024 Advanced Micro Devices, Inc.
+ */
+
+#ifndef RTE_POWER_UNCORE_OPS_H
+#define RTE_POWER_UNCORE_OPS_H
+
+/**
+ * @file
+ * RTE Uncore Frequency Management
+ */
+
+#include <rte_compat.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define RTE_POWER_UNCORE_DRIVER_NAMESZ       24
+
+/**
+ * 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.
+ */
+typedef int (*rte_power_uncore_init_t)(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.
+ */
+typedef int (*rte_power_uncore_exit_t)(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)'.
+ */
+typedef uint32_t (*rte_power_get_uncore_freq_t)(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.
+ */
+typedef int (*rte_power_set_uncore_freq_t)(unsigned int pkg, unsigned int die, uint32_t index);
+
+/**
+ * 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.
+ */
+typedef int (*rte_power_uncore_get_num_freqs_t)(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.
+ */
+typedef int (*rte_power_uncore_freqs_t)(unsigned int pkg, unsigned int die,
+					uint32_t *freqs, uint32_t num);
+/**
+ * Function pointers for generic frequency change functions.
+ *
+ * @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.
+ */
+typedef int (*rte_power_uncore_freq_change_t)(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.
+ */
+typedef unsigned int (*rte_power_uncore_get_num_pkgs_t)(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.
+ */
+typedef unsigned int (*rte_power_uncore_get_num_dies_t)(unsigned int pkg);
+typedef void (*rte_power_uncore_driver_cb_t)(void);
+
+/** Structure defining uncore power operations structure */
+struct rte_power_uncore_ops {
+	RTE_TAILQ_ENTRY(rte_power_uncore_ops) next;     /**< Next in list. */
+	char name[RTE_POWER_UNCORE_DRIVER_NAMESZ];      /**< power mgmt driver. */
+	rte_power_uncore_driver_cb_t cb;                /**< Driver specific callbacks. */
+	rte_power_uncore_init_t init;                   /**< Initialize power management. */
+	rte_power_uncore_exit_t exit;                   /**< Exit power management. */
+	rte_power_uncore_get_num_pkgs_t get_num_pkgs;
+	rte_power_uncore_get_num_dies_t get_num_dies;
+	rte_power_uncore_get_num_freqs_t get_num_freqs; /**< Number of available frequencies. */
+	rte_power_uncore_freqs_t get_avail_freqs;       /**< Get the available frequencies. */
+	rte_power_get_uncore_freq_t get_freq;           /**< Get frequency index. */
+	rte_power_set_uncore_freq_t set_freq;           /**< Set frequency index. */
+	rte_power_uncore_freq_change_t freq_max;        /**< Scale up frequency to highest. */
+	rte_power_uncore_freq_change_t freq_min;        /**< Scale up frequency to lowest. */
+};
+
+/**
+ * Register power uncore frequency operations.
+ * @param ops
+ *   Pointer to an ops structure to register.
+ * @return
+ *   - >=0: Success; return the index of the ops struct in the table.
+ *   - -EINVAL - error while registering ops struct.
+ */
+__rte_internal
+int rte_power_register_uncore_ops(struct rte_power_uncore_ops *ops);
+
+/**
+ * Macro to statically register the ops of an uncore driver.
+ */
+#define RTE_POWER_REGISTER_UNCORE_OPS(ops)             \
+	RTE_INIT(power_hdlr_init_uncore_##ops)         \
+	{                                               \
+		rte_power_register_uncore_ops(&ops);    \
+	}
+
+/**
+ * @internal Get the power uncore ops struct from its index.
+ *
+ * @return
+ *   The pointer to the ops struct in the table if registered.
+ */
+struct rte_power_uncore_ops *
+rte_power_get_uncore_ops(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* RTE_POWER_UNCORE_OPS_H */
diff --git a/lib/power/version.map b/lib/power/version.map
index bd64e0828f..f1eabd7c9a 100644
--- a/lib/power/version.map
+++ b/lib/power/version.map
@@ -59,6 +59,7 @@  INTERNAL {
 	global:
 
 	rte_power_register_ops;
+	rte_power_register_uncore_ops;
 	cpufreq_check_scaling_driver;
 	power_set_governor;
 	open_core_sysfs_file;