Skip to content

Commit 92c025d

Browse files
sumachidanandij-intel
authored andcommitted
platform/x86/amd/hsmp: Report power via hwmon sensors
Expose power reading and power limits via hwmon power sensors. Signed-off-by: Suma Hegde <[email protected]> Reviewed-by: Naveen Krishna Chatradhi <[email protected]> Link: https://lore.kernel.org/r/[email protected] Reviewed-by: Ilpo Järvinen <[email protected]> Signed-off-by: Ilpo Järvinen <[email protected]>
1 parent cf8dea4 commit 92c025d

File tree

6 files changed

+146
-1
lines changed

6 files changed

+146
-1
lines changed

Documentation/arch/x86/amd_hsmp.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,14 @@ for socket with ID00 is given below::
116116
})
117117
}
118118

119+
HSMP HWMON interface
120+
====================
121+
HSMP power sensors are registered with the hwmon interface. A separate hwmon
122+
directory is created for each socket and the following files are generated
123+
within the hwmon directory.
124+
- power1_input (read only)
125+
- power1_cap_max (read only)
126+
- power1_cap (read, write)
119127

120128
An example
121129
==========

drivers/platform/x86/amd/hsmp/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
obj-$(CONFIG_AMD_HSMP) += hsmp_common.o
88
hsmp_common-y := hsmp.o
9+
hsmp_common-$(CONFIG_HWMON) += hwmon.o
910
obj-$(CONFIG_AMD_HSMP_PLAT) += amd_hsmp.o
1011
amd_hsmp-y := plat.o
1112
obj-$(CONFIG_AMD_HSMP_ACPI) += hsmp_acpi.o

drivers/platform/x86/amd/hsmp/acpi.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,10 @@ static int init_acpi(struct device *dev)
281281
dev_err(dev, "Failed to init metric table\n");
282282
}
283283

284+
ret = hsmp_create_sensor(dev, sock_ind);
285+
if (ret)
286+
dev_err(dev, "Failed to register HSMP sensors with hwmon\n");
287+
284288
return ret;
285289
}
286290

drivers/platform/x86/amd/hsmp/hsmp.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
#include <linux/compiler_types.h>
1414
#include <linux/device.h>
15+
#include <linux/hwmon.h>
1516
#include <linux/miscdevice.h>
1617
#include <linux/pci.h>
1718
#include <linux/semaphore.h>
@@ -25,7 +26,7 @@
2526
#define HSMP_DEVNODE_NAME "hsmp"
2627
#define ACPI_HSMP_DEVICE_HID "AMDI0097"
2728

28-
#define DRIVER_VERSION "2.4"
29+
#define DRIVER_VERSION "2.5"
2930

3031
struct hsmp_mbaddr_info {
3132
u32 base_addr;
@@ -63,4 +64,9 @@ int hsmp_misc_register(struct device *dev);
6364
int hsmp_get_tbl_dram_base(u16 sock_ind);
6465
ssize_t hsmp_metric_tbl_read(struct hsmp_socket *sock, char *buf, size_t size);
6566
struct hsmp_plat_device *get_hsmp_pdev(void);
67+
#if IS_REACHABLE(CONFIG_HWMON)
68+
int hsmp_create_sensor(struct device *dev, u16 sock_ind);
69+
#else
70+
static inline int hsmp_create_sensor(struct device *dev, u16 sock_ind) { return 0; }
71+
#endif
6672
#endif /* HSMP_H */

drivers/platform/x86/amd/hsmp/hwmon.c

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* AMD HSMP hwmon support
4+
* Copyright (c) 2025, AMD.
5+
* All Rights Reserved.
6+
*
7+
* This file provides hwmon implementation for HSMP interface.
8+
*/
9+
10+
#include <asm/amd_hsmp.h>
11+
12+
#include <linux/device.h>
13+
#include <linux/err.h>
14+
#include <linux/hwmon.h>
15+
#include <linux/types.h>
16+
#include <linux/units.h>
17+
18+
#include "hsmp.h"
19+
20+
#define HSMP_HWMON_NAME "amd_hsmp_hwmon"
21+
22+
static int hsmp_hwmon_write(struct device *dev, enum hwmon_sensor_types type,
23+
u32 attr, int channel, long val)
24+
{
25+
u16 sock_ind = (uintptr_t)dev_get_drvdata(dev);
26+
struct hsmp_message msg = {};
27+
28+
if (type != hwmon_power)
29+
return -EOPNOTSUPP;
30+
31+
if (attr != hwmon_power_cap)
32+
return -EOPNOTSUPP;
33+
34+
msg.num_args = 1;
35+
msg.args[0] = val / MICROWATT_PER_MILLIWATT;
36+
msg.msg_id = HSMP_SET_SOCKET_POWER_LIMIT;
37+
msg.sock_ind = sock_ind;
38+
return hsmp_send_message(&msg);
39+
}
40+
41+
static int hsmp_hwmon_read(struct device *dev,
42+
enum hwmon_sensor_types type,
43+
u32 attr, int channel, long *val)
44+
{
45+
u16 sock_ind = (uintptr_t)dev_get_drvdata(dev);
46+
struct hsmp_message msg = {};
47+
int ret;
48+
49+
if (type != hwmon_power)
50+
return -EOPNOTSUPP;
51+
52+
msg.sock_ind = sock_ind;
53+
msg.response_sz = 1;
54+
55+
switch (attr) {
56+
case hwmon_power_input:
57+
msg.msg_id = HSMP_GET_SOCKET_POWER;
58+
break;
59+
case hwmon_power_cap:
60+
msg.msg_id = HSMP_GET_SOCKET_POWER_LIMIT;
61+
break;
62+
case hwmon_power_cap_max:
63+
msg.msg_id = HSMP_GET_SOCKET_POWER_LIMIT_MAX;
64+
break;
65+
default:
66+
return -EOPNOTSUPP;
67+
}
68+
69+
ret = hsmp_send_message(&msg);
70+
if (!ret)
71+
*val = msg.args[0] * MICROWATT_PER_MILLIWATT;
72+
73+
return ret;
74+
}
75+
76+
static umode_t hsmp_hwmon_is_visble(const void *data,
77+
enum hwmon_sensor_types type,
78+
u32 attr, int channel)
79+
{
80+
if (type != hwmon_power)
81+
return 0;
82+
83+
switch (attr) {
84+
case hwmon_power_input:
85+
return 0444;
86+
case hwmon_power_cap:
87+
return 0644;
88+
case hwmon_power_cap_max:
89+
return 0444;
90+
default:
91+
return 0;
92+
}
93+
}
94+
95+
static const struct hwmon_ops hsmp_hwmon_ops = {
96+
.read = hsmp_hwmon_read,
97+
.is_visible = hsmp_hwmon_is_visble,
98+
.write = hsmp_hwmon_write,
99+
};
100+
101+
static const struct hwmon_channel_info * const hsmp_info[] = {
102+
HWMON_CHANNEL_INFO(power, HWMON_P_INPUT | HWMON_P_CAP | HWMON_P_CAP_MAX),
103+
NULL
104+
};
105+
106+
static const struct hwmon_chip_info hsmp_chip_info = {
107+
.ops = &hsmp_hwmon_ops,
108+
.info = hsmp_info,
109+
};
110+
111+
int hsmp_create_sensor(struct device *dev, u16 sock_ind)
112+
{
113+
struct device *hwmon_dev;
114+
115+
hwmon_dev = devm_hwmon_device_register_with_info(dev, HSMP_HWMON_NAME,
116+
(void *)(uintptr_t)sock_ind,
117+
&hsmp_chip_info,
118+
NULL);
119+
return PTR_ERR_OR_ZERO(hwmon_dev);
120+
}
121+
EXPORT_SYMBOL_NS(hsmp_create_sensor, "AMD_HSMP");

drivers/platform/x86/amd/hsmp/plat.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,11 @@ static int init_platform_device(struct device *dev)
189189
if (ret)
190190
dev_err(dev, "Failed to init metric table\n");
191191
}
192+
193+
/* Register with hwmon interface for reporting power */
194+
ret = hsmp_create_sensor(dev, i);
195+
if (ret)
196+
dev_err(dev, "Failed to register HSMP sensors with hwmon\n");
192197
}
193198

194199
return 0;

0 commit comments

Comments
 (0)