From mboxrd@z Thu Jan  1 00:00:00 1970
Return-Path: <dev-bounces@dpdk.org>
Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124])
	by inbox.dpdk.org (Postfix) with ESMTP id 71E704586C;
	Mon, 26 Aug 2024 15:07:59 +0200 (CEST)
Received: from mails.dpdk.org (localhost [127.0.0.1])
	by mails.dpdk.org (Postfix) with ESMTP id 0EE474065D;
	Mon, 26 Aug 2024 15:07:33 +0200 (CEST)
Received: from NAM11-DM6-obe.outbound.protection.outlook.com
 (mail-dm6nam11on2085.outbound.protection.outlook.com [40.107.223.85])
 by mails.dpdk.org (Postfix) with ESMTP id 53DE340654
 for <dev@dpdk.org>; Mon, 26 Aug 2024 15:07:31 +0200 (CEST)
ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none;
 b=X1vfgE+I9CsfLXCf/HiP4+GXWEgvMCo554FwRyuwWxVukM7yfu2DB4VcMsGkboOvnShmekaFusTR62Qf0NNZMBThfp3PBUTaSLXhE28RsYwgWsgGu8JOUDU4/3iiKYPN/zQyARwzX5CpnsHYK039NgUG2Zv2l1inRNJdz63cuKa+dJJWPDTKR9xaxwgyjGgRjl4iP+jzWOQCHpqATdqehsSh7H0zpoHVulwnVB7B+P1oHDrxrQLzu66AIeIWcwMqvDaXmHE08lGBZ/1lo2e8HOUi7RGJ03gKgM6190JxI49kzy2fjkKrEe/hKOBMIKsMcO6tRcw8f2OnJtq8RPPtRg==
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; 
 s=arcselector10001;
 h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1;
 bh=heY26u+1rPdcnm+3mDIH4I47sEaK611grJab8pIYJXM=;
 b=qiq9koUXsKsHM5X7G5YqqqNiyvh67IZ6KJNSVIyUQylb6mGy9gDyV413jg7jABn4SGAwBaP5rSNTXmGkeAomws52KmOHP6FnDbJVxPAGL1cbTd7zfYz+gqSvu3ZltNCqjc2Uh9xgSi13nfMk9es2krsNLD0Bq8memvb9c8d/J0TMRdqHbHFAZ+jtNFD/71WU/77Cwy7yepWqcMPqseAut0vjK5bNAmFm5aKmKNetIc9mA+gdGZiz0YcjTidFIspL9ROmXo/mTEREbzv2LStX+n10S/aHBKZHpJoJ7sQB6gwql9c+nn08YvLsmemLkNQWxSb+uutsuCOJI7s/cQrE5Q==
ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is
 165.204.84.17) smtp.rcpttodomain=intel.com smtp.mailfrom=amd.com; dmarc=pass
 (p=quarantine sp=quarantine pct=100) action=none header.from=amd.com;
 dkim=none (message not signed); arc=none (0)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amd.com; s=selector1; 
 h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck;
 bh=heY26u+1rPdcnm+3mDIH4I47sEaK611grJab8pIYJXM=;
 b=CGQGvfwSYk+nELBTRiTwjzXvsWpOY3UH27Y7iQpSs8Sk4s4cKwrcgdE9tWbgmPAFBlV9wjA/yJZHs3yLud5u1njo8kbGa/vlH9kcHy+ux65KTvaBIGl4dTO3wkjOAxYQX5zRUjOgQ/GZ9p6W399K6FoBMUiylAdGEocweqN35wA=
Received: from BN9PR03CA0589.namprd03.prod.outlook.com (2603:10b6:408:10d::24)
 by MW3PR12MB4441.namprd12.prod.outlook.com (2603:10b6:303:59::9) with
 Microsoft SMTP Server (version=TLS1_2,
 cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7897.24; Mon, 26 Aug
 2024 13:07:27 +0000
Received: from BL6PEPF0001AB72.namprd02.prod.outlook.com
 (2603:10b6:408:10d:cafe::91) by BN9PR03CA0589.outlook.office365.com
 (2603:10b6:408:10d::24) with Microsoft SMTP Server (version=TLS1_2,
 cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7897.24 via Frontend
 Transport; Mon, 26 Aug 2024 13:07:26 +0000
X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 165.204.84.17)
 smtp.mailfrom=amd.com; dkim=none (message not signed)
 header.d=none;dmarc=pass action=none header.from=amd.com;
Received-SPF: Pass (protection.outlook.com: domain of amd.com designates
 165.204.84.17 as permitted sender) receiver=protection.outlook.com;
 client-ip=165.204.84.17; helo=SATLEXMB04.amd.com; pr=C
Received: from SATLEXMB04.amd.com (165.204.84.17) by
 BL6PEPF0001AB72.mail.protection.outlook.com (10.167.242.165) with Microsoft
 SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id
 15.20.7918.13 via Frontend Transport; Mon, 26 Aug 2024 13:07:26 +0000
Received: from jfw9ny3-os.amd.com (10.180.168.240) by SATLEXMB04.amd.com
 (10.181.40.145) with Microsoft SMTP Server (version=TLS1_2,
 cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.39; Mon, 26 Aug
 2024 08:07:23 -0500
From: Sivaprasad Tummala <sivaprasad.tummala@amd.com>
To: <david.hunt@intel.com>, <anatoly.burakov@intel.com>, <jerinj@marvell.com>, 
 <radu.nicolau@intel.com>, <gakhil@marvell.com>,
 <cristian.dumitrescu@intel.com>, <ferruh.yigit@amd.com>,
 <konstantin.ananyev@huawei.com>
CC: <dev@dpdk.org>
Subject: [PATCH v2 4/4] power/amd_uncore: uncore power management support for
 AMD EPYC processors
Date: Mon, 26 Aug 2024 13:06:49 +0000
Message-ID: <20240826130650.320130-5-sivaprasad.tummala@amd.com>
X-Mailer: git-send-email 2.34.1
In-Reply-To: <20240826130650.320130-1-sivaprasad.tummala@amd.com>
References: <20240720165030.246294-1-sivaprasad.tummala@amd.com>
 <20240826130650.320130-1-sivaprasad.tummala@amd.com>
MIME-Version: 1.0
Content-Transfer-Encoding: 8bit
Content-Type: text/plain
X-Originating-IP: [10.180.168.240]
X-ClientProxiedBy: SATLEXMB04.amd.com (10.181.40.145) To SATLEXMB04.amd.com
 (10.181.40.145)
X-EOPAttributedMessage: 0
X-MS-PublicTrafficType: Email
X-MS-TrafficTypeDiagnostic: BL6PEPF0001AB72:EE_|MW3PR12MB4441:EE_
X-MS-Office365-Filtering-Correlation-Id: 081fff83-6e84-4341-2e38-08dcc5d0087d
X-MS-Exchange-SenderADCheck: 1
X-MS-Exchange-AntiSpam-Relay: 0
X-Microsoft-Antispam: BCL:0;
 ARA:13230040|36860700013|1800799024|376014|82310400026; 
X-Microsoft-Antispam-Message-Info: =?us-ascii?Q?gbU8sXuvlJcnOdqsKjKHMNgGVcYZMwz68lJwNb1ksxt2W67TVi0FZlJxpAu4?=
 =?us-ascii?Q?z+DSVrBpQ8NKtrPZgcEvFDOJnZe2rmndLyv913NS5w6sb6AuzeC4NNJzNShX?=
 =?us-ascii?Q?GGAjmeKxKCtDHXibgLP+rSTH1YBaJiobOQNegL5nDELQpG0jVoPBdI5B3F6n?=
 =?us-ascii?Q?m75o3Iqqg1H1ScRqbQnH4fm1ZV38Ur8gYbIBwn/n+OIj57YVXhz5YrtZKUj8?=
 =?us-ascii?Q?epZbuWiPDlrWe0q5h6+QBa/C9XI5/er0DN/vSW4KP8AM6d+Uapw78HscSGQP?=
 =?us-ascii?Q?OZi4cL/QYYmCvxaJuA01CVe8S7DjX1gypFy6jhSRJf1fWqb7P1WBOMXT48Yv?=
 =?us-ascii?Q?Y6OeV8Ye+HOyYqwzjnNJbUMjD1ZN4OUhuVDewGLYn0+WIlCkOKGJM8pEZoKB?=
 =?us-ascii?Q?bZSleRzEjZwopg1ZV96Ehdj4xP1h6ql0U2B7FwjcnEjW2x4DZO3LaoVFH7XK?=
 =?us-ascii?Q?LIXBsq/q2zcNxRWrtT3XyX/bHSS6AGz7fll5DjYMfaffU9mJxr9cgy4pjP6n?=
 =?us-ascii?Q?6y5CqoxPbQ/+pwpdLZIn+DtonBvX9Wd24KKvRD0utYtf3ay1gXSBqQa+GRnE?=
 =?us-ascii?Q?R9PVLQZ9+8A9leX0LUuZMwEEXze3XYhSK6/DgRTdPG0+/41HPWEuAiRctR+9?=
 =?us-ascii?Q?I2w7CqtMDdD8dmwqxOrEl6pYZ9GqkeqDk3+t6S1k5ijapFyueknBJ3kkfCS8?=
 =?us-ascii?Q?cwpZEG+4MLEv+wMsV3mXKGGIu112tvQdFKQOy92M8JSr6puHV8aeSIXQg5gx?=
 =?us-ascii?Q?UVdjtcftzVtthRn9jBOWUGTjNKQ4EqWsrHR7wUEmQhwRKaRz6kpa3OisRHD6?=
 =?us-ascii?Q?bskBlsqdKZ/79X08kZbKQrXbI69ftWay/RbdrCrJm6nDHDgxqIjBV8+6pRHA?=
 =?us-ascii?Q?0efMTYGbWge5POtZX4jtaMKAMeepB95UlK85kjoLOskqzdPnz+eWcFPrw2KZ?=
 =?us-ascii?Q?fBlQMLRBE/eKDeC4RHqUd/GNKeJ3v5sUMAX3VrY1zrjAIgqE5M/mPEGhTX1z?=
 =?us-ascii?Q?Qzh8YWtZr2Cwx14FJGBB/rxf824ymQ8NdqX3R49mFmZDDb4/UIECDLhcRJV1?=
 =?us-ascii?Q?0Fx99FFIRBh19uHEa9c0FCCqWc6AV3g2EejI/bBe/f9fp/NrcEmWigwiwDAv?=
 =?us-ascii?Q?pHwobPxPVN6JdFQqRhvVI3xa8/iaE60OyVo83b+mzzZ75iT22MPkYMrH7KC9?=
 =?us-ascii?Q?9/qTA5F3ChRNl+F1tVlYI8l9NYQzFBPXKmsP0Q6ZmYEhrzvRG0ZibIodWqQg?=
 =?us-ascii?Q?CDV6wmxEeq4EfBBVdgtXzRQDgTYf1J5PPaN1HHWtqUudJZZRPQ4idljtxh6B?=
 =?us-ascii?Q?OOp/ThS6QqdskkPVlliPPffErLCm+Nf1pjehm95zqqvy/FSfLk2TO87iSd7X?=
 =?us-ascii?Q?Gl8OvPSpM/6qwQrbZHb2TNpvBbdPldTifITEGwOxmX8uJvHOukzXJw+k2AgX?=
 =?us-ascii?Q?86QLpbYCzu4fLuIdnkEyn9pFVFisxPNy?=
X-Forefront-Antispam-Report: CIP:165.204.84.17; CTRY:US; LANG:en; SCL:1; SRV:;
 IPV:CAL; SFV:NSPM; H:SATLEXMB04.amd.com; PTR:InfoDomainNonexistent; CAT:NONE;
 SFS:(13230040)(36860700013)(1800799024)(376014)(82310400026); DIR:OUT;
 SFP:1101; 
X-OriginatorOrg: amd.com
X-MS-Exchange-CrossTenant-OriginalArrivalTime: 26 Aug 2024 13:07:26.5277 (UTC)
X-MS-Exchange-CrossTenant-Network-Message-Id: 081fff83-6e84-4341-2e38-08dcc5d0087d
X-MS-Exchange-CrossTenant-Id: 3dd8961f-e488-4e60-8e11-a82d994e183d
X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=3dd8961f-e488-4e60-8e11-a82d994e183d; Ip=[165.204.84.17];
 Helo=[SATLEXMB04.amd.com]
X-MS-Exchange-CrossTenant-AuthSource: BL6PEPF0001AB72.namprd02.prod.outlook.com
X-MS-Exchange-CrossTenant-AuthAs: Anonymous
X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem
X-MS-Exchange-Transport-CrossTenantHeadersStamped: MW3PR12MB4441
X-BeenThere: dev@dpdk.org
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: DPDK patches and discussions <dev.dpdk.org>
List-Unsubscribe: <https://mails.dpdk.org/options/dev>,
 <mailto:dev-request@dpdk.org?subject=unsubscribe>
List-Archive: <http://mails.dpdk.org/archives/dev/>
List-Post: <mailto:dev@dpdk.org>
List-Help: <mailto:dev-request@dpdk.org?subject=help>
List-Subscribe: <https://mails.dpdk.org/listinfo/dev>,
 <mailto:dev-request@dpdk.org?subject=subscribe>
Errors-To: dev-bounces@dpdk.org

This patch introduces driver support for power management of uncore
components in AMD EPYC processors.

v2:
 - fixed typo in comments section.
 - added fabric frequency get support for legacy platforms.

Signed-off-by: Sivaprasad Tummala <sivaprasad.tummala@amd.com>
---
 drivers/power/amd_uncore/amd_uncore.c | 328 ++++++++++++++++++++++++++
 drivers/power/amd_uncore/amd_uncore.h | 226 ++++++++++++++++++
 drivers/power/amd_uncore/meson.build  |  20 ++
 drivers/power/meson.build             |   1 +
 4 files changed, 575 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..e667a783cd
--- /dev/null
+++ b/drivers/power/amd_uncore/amd_uncore.c
@@ -0,0 +1,328 @@
+/* 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_NUMA_DIE 8
+
+struct  __rte_cache_aligned uncore_power_info {
+	unsigned int die;                  /* Core die id */
+	unsigned int pkg;                  /* Package id */
+	uint32_t freqs[RTE_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 hsmp_proto_ver;
+
+static int
+set_uncore_freq_internal(struct uncore_power_info *ui, uint32_t idx)
+{
+	int ret;
+
+	if (idx >= RTE_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;
+}
+
+static int
+power_init_for_setting_uncore_freq(struct uncore_power_info *ui)
+{
+	switch (hsmp_proto_ver) {
+	case HSMP_PROTO_VER5:
+		ui->max_freq = 1800000; /* Hz */
+		ui->min_freq = 1200000; /* Hz */
+		break;
+	case HSMP_PROTO_VER2:
+	default:
+		ui->max_freq = 1600000; /* Hz */
+		ui->min_freq = 1200000; /* Hz */
+	}
+
+	return 0;
+}
+
+/*
+ * Get the available uncore frequencies of the specific die.
+ */
+static int
+power_get_available_uncore_freqs(struct uncore_power_info *ui)
+{
+	ui->nb_freqs = 3;
+	if (ui->nb_freqs >= RTE_MAX_UNCORE_FREQS) {
+		POWER_LOG(ERR, "Too many available uncore frequencies: %d",
+				num_uncore_freqs);
+		return -1;
+	}
+
+	/* Generate the uncore freq bucket array. */
+	switch (hsmp_proto_ver) {
+	case HSMP_PROTO_VER5:
+		ui->freqs[0] = 1800000;
+		ui->freqs[1] = 1440000;
+		ui->freqs[2] = 1200000;
+	case HSMP_PROTO_VER2:
+	default:
+		ui->freqs[0] = 1600000;
+		ui->freqs[1] = 1333000;
+		ui->freqs[2] = 1200000;
+	}
+
+	POWER_DEBUG_LOG("%d frequency(s) of pkg %02u die %02u are available",
+			ui->num_uncore_freqs, ui->pkg, ui->die);
+
+	return 0;
+}
+
+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) {
+		if (esmi_hsmp_proto_ver_get(&hsmp_proto_ver) ==
+				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 = esmi_hsmp_proto_ver_get(&hsmp_proto_ver);
+		if (ret != ESMI_SUCCESS) {
+			POWER_LOG(DEBUG, "HSMP Proto Version Get failed with "
+					"error %s", esmi_get_err_msg(ret));
+			esmi_exit();
+			return -1;
+		}
+		esmi_initialized = 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);
diff --git a/drivers/power/amd_uncore/amd_uncore.h b/drivers/power/amd_uncore/amd_uncore.h
new file mode 100644
index 0000000000..60e0e64d27
--- /dev/null
+++ b/drivers/power/amd_uncore/amd_uncore.h
@@ -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 */
diff --git a/drivers/power/amd_uncore/meson.build b/drivers/power/amd_uncore/meson.build
new file mode 100644
index 0000000000..8cbab47b01
--- /dev/null
+++ b/drivers/power/amd_uncore/meson.build
@@ -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
+
+ESMI_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']
diff --git a/drivers/power/meson.build b/drivers/power/meson.build
index c83047af94..4ba5954e13 100644
--- a/drivers/power/meson.build
+++ b/drivers/power/meson.build
@@ -7,6 +7,7 @@ drivers = [
         'cppc',
         'kvm_vm',
         'pstate',
+        'amd_uncore',
         'intel_uncore'
 ]
 
-- 
2.34.1