[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH v10 5/8] tools/cpufreq: extract CPPC para from cpufreq para


  • To: <xen-devel@xxxxxxxxxxxxxxxxxxxx>
  • From: Penny Zheng <Penny.Zheng@xxxxxxx>
  • Date: Tue, 23 Sep 2025 12:38:23 +0800
  • Arc-authentication-results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 165.204.84.17) smtp.rcpttodomain=lists.xenproject.org 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)
  • 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=UK7p1dxIdAUwnp9/KlnmFuOMlvoXNyC3ltvAs175wZ0=; b=Hc3iSF9AIsX4PMi+eBB1vom6+2epv2fnDYW/Kst4vqHozLg+CrcG9A3V9H5XXwvoR/xIqMe/2ciNlnG+4vSeVgv2QE2OA8dkGhNE80+xbYYS7WKJtiI9xcOUCqBCw90PRK0/0ASPUZcEJu8g19nOfXplYxTSqkKl4DaJvEbefIjVxsqZehk1gm0Jo9AiNxlijrwoIYXIXhiNzdwdG/eia0QIJ+OAEyv5Ju+LzcqTCrs9gZRSdNmp6gaa4fHmOVjtVeZ54biUdETZQNcEZyTqJxz/G6+9VWhaUIQCqR3AFmKpVWkEPCY1iONwvN6T4Vq4RNxfuBjK88LKR1H/pAcJZA==
  • Arc-seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=InkQXB/oYYvDztmGOvNzuq0gdb7wGxCYKAP1vbr33jgjy99yQHsg6ym98vq2uhH03qCwsvclRjgTkxFX+khpKm1c61rM4i5bOuZmUMhZWNVs3o78BrzsdKCdpRwoKzD7EGWwUz3zK99JXjtqdCvE63TgdeQo8Fu0gam3pjJWIfBSwcRLYYCPa0Du+34Ftjhk9goLJT6Pr/DOPnjt3PRLzDwBC+l0zUvONifZxGLPUSqONfB6D8vL8dU27MjAuDJF6CZg95QJFkPU4B0UkbcI54/5QbcDIG2PyJirDkHLex5O3Z0puFt1WmOS+Aj7jYG/debBuN94m8I9XkSWieTKoA==
  • Cc: <ray.huang@xxxxxxx>, Penny Zheng <Penny.Zheng@xxxxxxx>, Anthony PERARD <anthony.perard@xxxxxxxxxx>, Juergen Gross <jgross@xxxxxxxx>, Andrew Cooper <andrew.cooper3@xxxxxxxxxx>, Michal Orzel <michal.orzel@xxxxxxx>, Jan Beulich <jbeulich@xxxxxxxx>, Julien Grall <julien@xxxxxxx>, Roger Pau Monné <roger.pau@xxxxxxxxxx>, "Stefano Stabellini" <sstabellini@xxxxxxxxxx>
  • Delivery-date: Tue, 23 Sep 2025 04:39:21 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>

We extract cppc info from "struct xen_get_cpufreq_para", where it acts as
a member of union, and share the space with governor info.
However, it may fail in amd-cppc passive mode, in which governor info and
CPPC info could co-exist, and both need to be printed together via xenpm tool.
If we tried to still put it in "struct xen_get_cpufreq_para" (e.g. just move
out of union), "struct xen_get_cpufreq_para" will enlarge too much to further
make xen_sysctl.u exceed 128 bytes.

So we introduce a new sub-field GET_CPUFREQ_CPPC to dedicatedly acquire
CPPC-related para, and make get-cpufreq-para invoke GET_CPUFREQ_CPPC
if available.
New helpers print_cppc_para() and get_cpufreq_cppc() are introduced to
extract CPPC-related parameters process from cpufreq para.

Signed-off-by: Penny Zheng <Penny.Zheng@xxxxxxx>
Acked-by: Jan Beulich <jbeulich@xxxxxxxx> # hypervisor
Acked-by: Anthony PERARD <anthony.perard@xxxxxxxxxx>
---
v4 -> v5:
- new commit
---
v5 -> v6:
- remove the changes for get-cpufreq-para
---
v6 -> v7:
- make get-cpufreq-para invoke GET_CPUFREQ_CPPC
---
v7 -> v8:
- use structure assignment as it is a alias
- add errno info to the error print
---
v9 -> v10
- drop the outer union
---
 tools/include/xenctrl.h     |  27 +++++-----
 tools/libs/ctrl/xc_pm.c     |  47 +++++++++++-----
 tools/misc/xenpm.c          | 103 ++++++++++++++++++++++--------------
 xen/drivers/acpi/pm-op.c    |  43 +++++++++------
 xen/include/public/sysctl.h |  31 ++++++-----
 5 files changed, 155 insertions(+), 96 deletions(-)

diff --git a/tools/include/xenctrl.h b/tools/include/xenctrl.h
index 965d3b585a..c14ecd66aa 100644
--- a/tools/include/xenctrl.h
+++ b/tools/include/xenctrl.h
@@ -1924,22 +1924,19 @@ struct xc_get_cpufreq_para {
     uint32_t cpuinfo_cur_freq;
     uint32_t cpuinfo_max_freq;
     uint32_t cpuinfo_min_freq;
-    union {
-        struct {
-            uint32_t scaling_cur_freq;
+    struct {
+        uint32_t scaling_cur_freq;
 
-            char scaling_governor[CPUFREQ_NAME_LEN];
-            uint32_t scaling_max_freq;
-            uint32_t scaling_min_freq;
+        char scaling_governor[CPUFREQ_NAME_LEN];
+        uint32_t scaling_max_freq;
+        uint32_t scaling_min_freq;
 
-            /* for specific governor */
-            union {
-                xc_userspace_t userspace;
-                xc_ondemand_t ondemand;
-            } u;
-        } s;
-        xc_cppc_para_t cppc_para;
-    } u;
+        /* for specific governor */
+        union {
+            xc_userspace_t userspace;
+            xc_ondemand_t ondemand;
+        } u;
+    } s;
 
     int32_t turbo_enabled;
 };
@@ -1953,6 +1950,8 @@ int xc_set_cpufreq_para(xc_interface *xch, int cpuid,
                         int ctrl_type, int ctrl_value);
 int xc_set_cpufreq_cppc(xc_interface *xch, int cpuid,
                         xc_set_cppc_para_t *set_cppc);
+int xc_get_cppc_para(xc_interface *xch, unsigned int cpuid,
+                     xc_cppc_para_t *cppc_para);
 int xc_get_cpufreq_avgfreq(xc_interface *xch, int cpuid, int *avg_freq);
 
 int xc_set_sched_opt_smt(xc_interface *xch, uint32_t value);
diff --git a/tools/libs/ctrl/xc_pm.c b/tools/libs/ctrl/xc_pm.c
index 6fda973f1f..5b4e489acf 100644
--- a/tools/libs/ctrl/xc_pm.c
+++ b/tools/libs/ctrl/xc_pm.c
@@ -274,25 +274,24 @@ int xc_get_cpufreq_para(xc_interface *xch, int cpuid,
         /*
          * Copy to user_para no matter what cpufreq driver/governor.
          *
-         * First sanity check layout of the union subject to memcpy() below.
+         * First sanity check layout of the struct subject to memcpy() below.
          */
-        BUILD_BUG_ON(sizeof(user_para->u) != sizeof(sys_para->u));
+        BUILD_BUG_ON(sizeof(user_para->s) != sizeof(sys_para->s));
 
 #define CHK_FIELD(fld) \
-        BUILD_BUG_ON(offsetof(typeof(user_para->u), fld) != \
-                     offsetof(typeof(sys_para->u),  fld))
+        BUILD_BUG_ON(offsetof(typeof(user_para->s), fld) != \
+                     offsetof(typeof(sys_para->s),  fld))
 
-        CHK_FIELD(s.scaling_cur_freq);
-        CHK_FIELD(s.scaling_governor);
-        CHK_FIELD(s.scaling_max_freq);
-        CHK_FIELD(s.scaling_min_freq);
-        CHK_FIELD(s.u.userspace);
-        CHK_FIELD(s.u.ondemand);
-        CHK_FIELD(cppc_para);
+        CHK_FIELD(scaling_cur_freq);
+        CHK_FIELD(scaling_governor);
+        CHK_FIELD(scaling_max_freq);
+        CHK_FIELD(scaling_min_freq);
+        CHK_FIELD(u.userspace);
+        CHK_FIELD(u.ondemand);
 
 #undef CHK_FIELD
 
-        memcpy(&user_para->u, &sys_para->u, sizeof(sys_para->u));
+        memcpy(&user_para->s, &sys_para->s, sizeof(sys_para->s));
     }
 
 unlock_4:
@@ -366,6 +365,30 @@ int xc_set_cpufreq_cppc(xc_interface *xch, int cpuid,
     return ret;
 }
 
+int xc_get_cppc_para(xc_interface *xch, unsigned int cpuid,
+                     xc_cppc_para_t *cppc_para)
+{
+    int ret;
+    struct xen_sysctl sysctl = {};
+
+    if ( !xch  || !cppc_para )
+    {
+        errno = EINVAL;
+        return -1;
+    }
+
+    sysctl.cmd = XEN_SYSCTL_pm_op;
+    sysctl.u.pm_op.cmd = GET_CPUFREQ_CPPC;
+    sysctl.u.pm_op.cpuid = cpuid;
+
+    ret = xc_sysctl(xch, &sysctl);
+    if ( ret )
+        return ret;
+
+    *cppc_para = sysctl.u.pm_op.u.get_cppc;
+    return ret;
+}
+
 int xc_get_cpufreq_avgfreq(xc_interface *xch, int cpuid, int *avg_freq)
 {
     int ret = 0;
diff --git a/tools/misc/xenpm.c b/tools/misc/xenpm.c
index 6b054b10a4..c7f19cea28 100644
--- a/tools/misc/xenpm.c
+++ b/tools/misc/xenpm.c
@@ -801,6 +801,34 @@ static unsigned int calculate_activity_window(const 
xc_cppc_para_t *cppc,
     return mantissa * multiplier;
 }
 
+/* print out parameters about cpu cppc */
+static void print_cppc_para(unsigned int cpuid,
+                            const xc_cppc_para_t *cppc)
+{
+    printf("cppc variables       :\n");
+    printf("  hardware limits    : lowest [%"PRIu32"] lowest nonlinear 
[%"PRIu32"]\n",
+           cppc->lowest, cppc->lowest_nonlinear);
+    printf("                     : nominal [%"PRIu32"] highest [%"PRIu32"]\n",
+           cppc->nominal, cppc->highest);
+    printf("  configured limits  : min [%"PRIu32"] max [%"PRIu32"] energy perf 
[%"PRIu32"]\n",
+           cppc->minimum, cppc->maximum, cppc->energy_perf);
+
+    if ( cppc->features & XEN_SYSCTL_CPPC_FEAT_ACT_WINDOW )
+    {
+        unsigned int activity_window;
+        const char *units;
+
+        activity_window = calculate_activity_window(cppc, &units);
+        printf("                     : activity_window [%"PRIu32" %s]\n",
+               activity_window, units);
+    }
+
+    printf("                     : desired [%"PRIu32"%s]\n",
+           cppc->desired,
+           cppc->desired ? "" : " hw autonomous");
+    printf("\n");
+}
+
 /* print out parameters about cpu frequency */
 static void print_cpufreq_para(int cpuid, struct xc_get_cpufreq_para 
*p_cpufreq)
 {
@@ -826,71 +854,45 @@ static void print_cpufreq_para(int cpuid, struct 
xc_get_cpufreq_para *p_cpufreq)
 
     printf("scaling_driver       : %s\n", p_cpufreq->scaling_driver);
 
-    if ( hwp )
-    {
-        const xc_cppc_para_t *cppc = &p_cpufreq->u.cppc_para;
-
-        printf("cppc variables       :\n");
-        printf("  hardware limits    : lowest [%"PRIu32"] lowest nonlinear 
[%"PRIu32"]\n",
-               cppc->lowest, cppc->lowest_nonlinear);
-        printf("                     : nominal [%"PRIu32"] highest 
[%"PRIu32"]\n",
-               cppc->nominal, cppc->highest);
-        printf("  configured limits  : min [%"PRIu32"] max [%"PRIu32"] energy 
perf [%"PRIu32"]\n",
-               cppc->minimum, cppc->maximum, cppc->energy_perf);
-
-        if ( cppc->features & XEN_SYSCTL_CPPC_FEAT_ACT_WINDOW )
-        {
-            unsigned int activity_window;
-            const char *units;
-
-            activity_window = calculate_activity_window(cppc, &units);
-            printf("                     : activity_window [%"PRIu32" %s]\n",
-                   activity_window, units);
-        }
-
-        printf("                     : desired [%"PRIu32"%s]\n",
-               cppc->desired,
-               cppc->desired ? "" : " hw autonomous");
-    }
-    else
+    if ( !hwp )
     {
         if ( p_cpufreq->gov_num )
             printf("scaling_avail_gov    : %s\n",
                    p_cpufreq->scaling_available_governors);
 
-        printf("current_governor     : %s\n", p_cpufreq->u.s.scaling_governor);
-        if ( !strncmp(p_cpufreq->u.s.scaling_governor,
+        printf("current_governor     : %s\n", p_cpufreq->s.scaling_governor);
+        if ( !strncmp(p_cpufreq->s.scaling_governor,
                       "userspace", CPUFREQ_NAME_LEN) )
         {
             printf("  userspace specific :\n");
             printf("    scaling_setspeed : %u\n",
-                   p_cpufreq->u.s.u.userspace.scaling_setspeed);
+                   p_cpufreq->s.u.userspace.scaling_setspeed);
         }
-        else if ( !strncmp(p_cpufreq->u.s.scaling_governor,
+        else if ( !strncmp(p_cpufreq->s.scaling_governor,
                            "ondemand", CPUFREQ_NAME_LEN) )
         {
             printf("  ondemand specific  :\n");
             printf("    sampling_rate    : max [%u] min [%u] cur [%u]\n",
-                   p_cpufreq->u.s.u.ondemand.sampling_rate_max,
-                   p_cpufreq->u.s.u.ondemand.sampling_rate_min,
-                   p_cpufreq->u.s.u.ondemand.sampling_rate);
+                   p_cpufreq->s.u.ondemand.sampling_rate_max,
+                   p_cpufreq->s.u.ondemand.sampling_rate_min,
+                   p_cpufreq->s.u.ondemand.sampling_rate);
             printf("    up_threshold     : %u\n",
-                   p_cpufreq->u.s.u.ondemand.up_threshold);
+                   p_cpufreq->s.u.ondemand.up_threshold);
         }
 
         printf("scaling_avail_freq   :");
         for ( i = 0; i < p_cpufreq->freq_num; i++ )
             if ( p_cpufreq->scaling_available_frequencies[i] ==
-                 p_cpufreq->u.s.scaling_cur_freq )
+                 p_cpufreq->s.scaling_cur_freq )
                 printf(" *%d", p_cpufreq->scaling_available_frequencies[i]);
             else
                 printf(" %d", p_cpufreq->scaling_available_frequencies[i]);
         printf("\n");
 
         printf("scaling frequency    : max [%u] min [%u] cur [%u]\n",
-               p_cpufreq->u.s.scaling_max_freq,
-               p_cpufreq->u.s.scaling_min_freq,
-               p_cpufreq->u.s.scaling_cur_freq);
+               p_cpufreq->s.scaling_max_freq,
+               p_cpufreq->s.scaling_min_freq,
+               p_cpufreq->s.scaling_cur_freq);
     }
 
     printf("turbo mode           : %s\n",
@@ -898,6 +900,24 @@ static void print_cpufreq_para(int cpuid, struct 
xc_get_cpufreq_para *p_cpufreq)
     printf("\n");
 }
 
+/* show cpu cppc parameters information on CPU cpuid */
+static int show_cppc_para_by_cpuid(xc_interface *xc_handle, unsigned int cpuid)
+{
+    int ret;
+    xc_cppc_para_t cppc_para;
+
+    ret = xc_get_cppc_para(xc_handle, cpuid, &cppc_para);
+    if ( !ret )
+        print_cppc_para(cpuid, &cppc_para);
+    else if ( errno == ENODEV )
+        ret = 0; /* Ignore unsupported platform */
+    else
+        fprintf(stderr, "[CPU%u] failed to get cppc parameter: %s\n",
+                cpuid, strerror(errno));
+
+    return ret;
+}
+
 /* show cpu frequency parameters information on CPU cpuid */
 static int show_cpufreq_para_by_cpuid(xc_interface *xc_handle, int cpuid)
 {
@@ -957,7 +977,12 @@ static int show_cpufreq_para_by_cpuid(xc_interface 
*xc_handle, int cpuid)
     } while ( ret && errno == EAGAIN );
 
     if ( ret == 0 )
+    {
         print_cpufreq_para(cpuid, p_cpufreq);
+
+        /* Show CPPC parameters if available */
+        ret = show_cppc_para_by_cpuid(xc_handle, cpuid);
+    }
     else if ( errno == ENODEV )
     {
         ret = -ENODEV;
diff --git a/xen/drivers/acpi/pm-op.c b/xen/drivers/acpi/pm-op.c
index a7eaf29c31..f50acd7088 100644
--- a/xen/drivers/acpi/pm-op.c
+++ b/xen/drivers/acpi/pm-op.c
@@ -77,6 +77,17 @@ static int read_scaling_available_governors(char 
*scaling_available_governors,
     return 0;
 }
 
+static int get_cpufreq_cppc(unsigned int cpu,
+                            struct xen_get_cppc_para *cppc_para)
+{
+    int ret = -ENODEV;
+
+    if ( hwp_active() )
+        ret = get_hwp_para(cpu, cppc_para);
+
+    return ret;
+}
+
 static int get_cpufreq_para(struct xen_sysctl_pm_op *op)
 {
     uint32_t ret = 0;
@@ -143,9 +154,7 @@ static int get_cpufreq_para(struct xen_sysctl_pm_op *op)
     else
         strlcpy(op->u.get_para.scaling_driver, "Unknown", CPUFREQ_NAME_LEN);
 
-    if ( hwp_active() )
-        ret = get_hwp_para(policy->cpu, &op->u.get_para.u.cppc_para);
-    else
+    if ( !hwp_active() )
     {
         if ( !(scaling_available_governors =
                xzalloc_array(char, gov_num * CPUFREQ_NAME_LEN)) )
@@ -165,29 +174,29 @@ static int get_cpufreq_para(struct xen_sysctl_pm_op *op)
         if ( ret )
             return -EFAULT;
 
-        op->u.get_para.u.s.scaling_cur_freq = policy->cur;
-        op->u.get_para.u.s.scaling_max_freq = policy->max;
-        op->u.get_para.u.s.scaling_min_freq = policy->min;
+        op->u.get_para.s.scaling_cur_freq = policy->cur;
+        op->u.get_para.s.scaling_max_freq = policy->max;
+        op->u.get_para.s.scaling_min_freq = policy->min;
 
         if ( policy->governor->name[0] )
-            strlcpy(op->u.get_para.u.s.scaling_governor,
+            strlcpy(op->u.get_para.s.scaling_governor,
                     policy->governor->name, CPUFREQ_NAME_LEN);
         else
-            strlcpy(op->u.get_para.u.s.scaling_governor, "Unknown",
+            strlcpy(op->u.get_para.s.scaling_governor, "Unknown",
                     CPUFREQ_NAME_LEN);
 
         /* governor specific para */
-        if ( !strncasecmp(op->u.get_para.u.s.scaling_governor,
+        if ( !strncasecmp(op->u.get_para.s.scaling_governor,
                           "userspace", CPUFREQ_NAME_LEN) )
-            op->u.get_para.u.s.u.userspace.scaling_setspeed = policy->cur;
+            op->u.get_para.s.u.userspace.scaling_setspeed = policy->cur;
 
-        if ( !strncasecmp(op->u.get_para.u.s.scaling_governor,
+        if ( !strncasecmp(op->u.get_para.s.scaling_governor,
                           "ondemand", CPUFREQ_NAME_LEN) )
             ret = get_cpufreq_ondemand_para(
-                &op->u.get_para.u.s.u.ondemand.sampling_rate_max,
-                &op->u.get_para.u.s.u.ondemand.sampling_rate_min,
-                &op->u.get_para.u.s.u.ondemand.sampling_rate,
-                &op->u.get_para.u.s.u.ondemand.up_threshold);
+                &op->u.get_para.s.u.ondemand.sampling_rate_max,
+                &op->u.get_para.s.u.ondemand.sampling_rate_min,
+                &op->u.get_para.s.u.ondemand.sampling_rate,
+                &op->u.get_para.s.u.ondemand.up_threshold);
     }
 
     return ret;
@@ -385,6 +394,10 @@ int do_pm_op(struct xen_sysctl_pm_op *op)
         ret = set_cpufreq_para(op);
         break;
 
+    case GET_CPUFREQ_CPPC:
+        ret = get_cpufreq_cppc(op->cpuid, &op->u.get_cppc);
+        break;
+
     case SET_CPUFREQ_CPPC:
         ret = set_cpufreq_cppc(op);
         break;
diff --git a/xen/include/public/sysctl.h b/xen/include/public/sysctl.h
index eb3a23b038..66c9b65465 100644
--- a/xen/include/public/sysctl.h
+++ b/xen/include/public/sysctl.h
@@ -478,22 +478,19 @@ struct xen_get_cpufreq_para {
     uint32_t cpuinfo_cur_freq;
     uint32_t cpuinfo_max_freq;
     uint32_t cpuinfo_min_freq;
-    union {
-        struct {
-            uint32_t scaling_cur_freq;
-
-            char scaling_governor[CPUFREQ_NAME_LEN];
-            uint32_t scaling_max_freq;
-            uint32_t scaling_min_freq;
-
-            /* for specific governor */
-            union {
-                struct  xen_userspace userspace;
-                struct  xen_ondemand ondemand;
-            } u;
-        } s;
-        struct xen_get_cppc_para cppc_para;
-    } u;
+    struct {
+        uint32_t scaling_cur_freq;
+
+        char scaling_governor[CPUFREQ_NAME_LEN];
+        uint32_t scaling_max_freq;
+        uint32_t scaling_min_freq;
+
+        /* for specific governor */
+        union {
+            struct  xen_userspace userspace;
+            struct  xen_ondemand ondemand;
+        } u;
+    } s;
 
     int32_t turbo_enabled;
 };
@@ -523,6 +520,7 @@ struct xen_sysctl_pm_op {
     #define SET_CPUFREQ_PARA           (CPUFREQ_PARA | 0x03)
     #define GET_CPUFREQ_AVGFREQ        (CPUFREQ_PARA | 0x04)
     #define SET_CPUFREQ_CPPC           (CPUFREQ_PARA | 0x05)
+    #define GET_CPUFREQ_CPPC           (CPUFREQ_PARA | 0x06)
 
     /* set/reset scheduler power saving option */
     #define XEN_SYSCTL_pm_op_set_sched_opt_smt    0x21
@@ -547,6 +545,7 @@ struct xen_sysctl_pm_op {
     uint32_t cpuid;
     union {
         struct xen_get_cpufreq_para get_para;
+        struct xen_get_cppc_para    get_cppc;
         struct xen_set_cpufreq_gov  set_gov;
         struct xen_set_cpufreq_para set_para;
         struct xen_set_cppc_para    set_cppc;
-- 
2.34.1




 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.