1 // SPDX-License-Identifier: GPL-2.0
3 * AMD HSMP Platform Driver
4 * Copyright (c) 2024, AMD.
7 * This file provides an ACPI based driver implementation for HSMP interface.
10 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
12 #include <asm/amd_hsmp.h>
13 #include <asm/amd_nb.h>
15 #include <linux/acpi.h>
16 #include <linux/device.h>
17 #include <linux/dev_printk.h>
18 #include <linux/ioport.h>
19 #include <linux/kstrtox.h>
20 #include <linux/module.h>
21 #include <linux/platform_device.h>
22 #include <linux/sysfs.h>
23 #include <linux/uuid.h>
25 #include <uapi/asm-generic/errno-base.h>
29 #define DRIVER_NAME "amd_hsmp"
30 #define DRIVER_VERSION "2.3"
31 #define ACPI_HSMP_DEVICE_HID "AMDI0097"
33 /* These are the strings specified in ACPI table */
34 #define MSG_IDOFF_STR "MsgIdOffset"
35 #define MSG_ARGOFF_STR "MsgArgOffset"
36 #define MSG_RESPOFF_STR "MsgRspOffset"
38 static struct hsmp_plat_device
*hsmp_pdev
;
40 static int amd_hsmp_acpi_rdwr(struct hsmp_socket
*sock
, u32 offset
,
41 u32
*value
, bool write
)
44 iowrite32(*value
, sock
->virt_base_addr
+ offset
);
46 *value
= ioread32(sock
->virt_base_addr
+ offset
);
51 /* This is the UUID used for HSMP */
52 static const guid_t acpi_hsmp_uuid
= GUID_INIT(0xb74d619d, 0x5707, 0x48bd,
53 0xa6, 0x9f, 0x4e, 0xa2,
54 0x87, 0x1f, 0xc2, 0xf6);
56 static inline bool is_acpi_hsmp_uuid(union acpi_object
*obj
)
58 if (obj
->type
== ACPI_TYPE_BUFFER
&& obj
->buffer
.length
== UUID_SIZE
)
59 return guid_equal((guid_t
*)obj
->buffer
.pointer
, &acpi_hsmp_uuid
);
64 static inline int hsmp_get_uid(struct device
*dev
, u16
*sock_ind
)
69 * UID (ID00, ID01..IDXX) is used for differentiating sockets,
70 * read it and strip the "ID" part of it and convert the remaining
73 uid
= acpi_device_uid(ACPI_COMPANION(dev
));
75 return kstrtou16(uid
+ 2, 10, sock_ind
);
78 static acpi_status
hsmp_resource(struct acpi_resource
*res
, void *data
)
80 struct hsmp_socket
*sock
= data
;
84 case ACPI_RESOURCE_TYPE_FIXED_MEMORY32
:
85 if (!acpi_dev_resource_memory(res
, &r
))
87 if (!r
.start
|| r
.end
< r
.start
|| !(r
.flags
& IORESOURCE_MEM_WRITEABLE
))
89 sock
->mbinfo
.base_addr
= r
.start
;
90 sock
->mbinfo
.size
= resource_size(&r
);
92 case ACPI_RESOURCE_TYPE_END_TAG
:
101 static int hsmp_read_acpi_dsd(struct hsmp_socket
*sock
)
103 struct acpi_buffer buf
= { ACPI_ALLOCATE_BUFFER
, NULL
};
104 union acpi_object
*guid
, *mailbox_package
;
105 union acpi_object
*dsd
;
110 status
= acpi_evaluate_object_typed(ACPI_HANDLE(sock
->dev
), "_DSD", NULL
,
111 &buf
, ACPI_TYPE_PACKAGE
);
112 if (ACPI_FAILURE(status
)) {
113 dev_err(sock
->dev
, "Failed to read mailbox reg offsets from DSD table, err: %s\n",
114 acpi_format_exception(status
));
120 /* HSMP _DSD property should contain 2 objects.
121 * 1. guid which is an acpi object of type ACPI_TYPE_BUFFER
122 * 2. mailbox which is an acpi object of type ACPI_TYPE_PACKAGE
123 * This mailbox object contains 3 more acpi objects of type
124 * ACPI_TYPE_PACKAGE for holding msgid, msgresp, msgarg offsets
125 * these packages inturn contain 2 acpi objects of type
126 * ACPI_TYPE_STRING and ACPI_TYPE_INTEGER
128 if (!dsd
|| dsd
->type
!= ACPI_TYPE_PACKAGE
|| dsd
->package
.count
!= 2) {
133 guid
= &dsd
->package
.elements
[0];
134 mailbox_package
= &dsd
->package
.elements
[1];
135 if (!is_acpi_hsmp_uuid(guid
) || mailbox_package
->type
!= ACPI_TYPE_PACKAGE
) {
136 dev_err(sock
->dev
, "Invalid hsmp _DSD table data\n");
141 for (j
= 0; j
< mailbox_package
->package
.count
; j
++) {
142 union acpi_object
*msgobj
, *msgstr
, *msgint
;
144 msgobj
= &mailbox_package
->package
.elements
[j
];
145 msgstr
= &msgobj
->package
.elements
[0];
146 msgint
= &msgobj
->package
.elements
[1];
148 /* package should have 1 string and 1 integer object */
149 if (msgobj
->type
!= ACPI_TYPE_PACKAGE
||
150 msgstr
->type
!= ACPI_TYPE_STRING
||
151 msgint
->type
!= ACPI_TYPE_INTEGER
) {
156 if (!strncmp(msgstr
->string
.pointer
, MSG_IDOFF_STR
,
157 msgstr
->string
.length
)) {
158 sock
->mbinfo
.msg_id_off
= msgint
->integer
.value
;
159 } else if (!strncmp(msgstr
->string
.pointer
, MSG_RESPOFF_STR
,
160 msgstr
->string
.length
)) {
161 sock
->mbinfo
.msg_resp_off
= msgint
->integer
.value
;
162 } else if (!strncmp(msgstr
->string
.pointer
, MSG_ARGOFF_STR
,
163 msgstr
->string
.length
)) {
164 sock
->mbinfo
.msg_arg_off
= msgint
->integer
.value
;
171 if (!sock
->mbinfo
.msg_id_off
|| !sock
->mbinfo
.msg_resp_off
||
172 !sock
->mbinfo
.msg_arg_off
)
176 ACPI_FREE(buf
.pointer
);
180 static int hsmp_read_acpi_crs(struct hsmp_socket
*sock
)
184 status
= acpi_walk_resources(ACPI_HANDLE(sock
->dev
), METHOD_NAME__CRS
,
185 hsmp_resource
, sock
);
186 if (ACPI_FAILURE(status
)) {
187 dev_err(sock
->dev
, "Failed to look up MP1 base address from CRS method, err: %s\n",
188 acpi_format_exception(status
));
191 if (!sock
->mbinfo
.base_addr
|| !sock
->mbinfo
.size
)
194 /* The mapped region should be un-cached */
195 sock
->virt_base_addr
= devm_ioremap_uc(sock
->dev
, sock
->mbinfo
.base_addr
,
197 if (!sock
->virt_base_addr
) {
198 dev_err(sock
->dev
, "Failed to ioremap MP1 base address\n");
205 /* Parse the ACPI table to read the data */
206 static int hsmp_parse_acpi_table(struct device
*dev
, u16 sock_ind
)
208 struct hsmp_socket
*sock
= &hsmp_pdev
->sock
[sock_ind
];
211 sock
->sock_ind
= sock_ind
;
213 sock
->amd_hsmp_rdwr
= amd_hsmp_acpi_rdwr
;
215 sema_init(&sock
->hsmp_sem
, 1);
217 dev_set_drvdata(dev
, sock
);
219 /* Read MP1 base address from CRS method */
220 ret
= hsmp_read_acpi_crs(sock
);
224 /* Read mailbox offsets from DSD table */
225 return hsmp_read_acpi_dsd(sock
);
228 static ssize_t
hsmp_metric_tbl_acpi_read(struct file
*filp
, struct kobject
*kobj
,
229 struct bin_attribute
*bin_attr
, char *buf
,
230 loff_t off
, size_t count
)
232 struct device
*dev
= container_of(kobj
, struct device
, kobj
);
233 struct hsmp_socket
*sock
= dev_get_drvdata(dev
);
235 return hsmp_metric_tbl_read(sock
, buf
, count
);
238 static umode_t
hsmp_is_sock_attr_visible(struct kobject
*kobj
,
239 const struct bin_attribute
*battr
, int id
)
241 if (hsmp_pdev
->proto_ver
== HSMP_PROTO_VER6
)
242 return battr
->attr
.mode
;
247 static int init_acpi(struct device
*dev
)
252 ret
= hsmp_get_uid(dev
, &sock_ind
);
255 if (sock_ind
>= hsmp_pdev
->num_sockets
)
258 ret
= hsmp_parse_acpi_table(dev
, sock_ind
);
260 dev_err(dev
, "Failed to parse ACPI table\n");
264 /* Test the hsmp interface */
265 ret
= hsmp_test(sock_ind
, 0xDEADBEEF);
267 dev_err(dev
, "HSMP test message failed on Fam:%x model:%x\n",
268 boot_cpu_data
.x86
, boot_cpu_data
.x86_model
);
269 dev_err(dev
, "Is HSMP disabled in BIOS ?\n");
273 ret
= hsmp_cache_proto_ver(sock_ind
);
275 dev_err(dev
, "Failed to read HSMP protocol version\n");
279 if (hsmp_pdev
->proto_ver
== HSMP_PROTO_VER6
) {
280 ret
= hsmp_get_tbl_dram_base(sock_ind
);
282 dev_err(dev
, "Failed to init metric table\n");
288 static struct bin_attribute hsmp_metric_tbl_attr
= {
289 .attr
= { .name
= HSMP_METRICS_TABLE_NAME
, .mode
= 0444},
290 .read
= hsmp_metric_tbl_acpi_read
,
291 .size
= sizeof(struct hsmp_metric_table
),
294 static struct bin_attribute
*hsmp_attr_list
[] = {
295 &hsmp_metric_tbl_attr
,
299 static struct attribute_group hsmp_attr_grp
= {
300 .bin_attrs
= hsmp_attr_list
,
301 .is_bin_visible
= hsmp_is_sock_attr_visible
,
304 static const struct attribute_group
*hsmp_groups
[] = {
309 static const struct acpi_device_id amd_hsmp_acpi_ids
[] = {
310 {ACPI_HSMP_DEVICE_HID
, 0},
313 MODULE_DEVICE_TABLE(acpi
, amd_hsmp_acpi_ids
);
315 static int hsmp_acpi_probe(struct platform_device
*pdev
)
319 hsmp_pdev
= get_hsmp_pdev();
323 if (!hsmp_pdev
->is_probed
) {
324 hsmp_pdev
->num_sockets
= amd_nb_num();
325 if (hsmp_pdev
->num_sockets
== 0 || hsmp_pdev
->num_sockets
> MAX_AMD_SOCKETS
)
328 hsmp_pdev
->sock
= devm_kcalloc(&pdev
->dev
, hsmp_pdev
->num_sockets
,
329 sizeof(*hsmp_pdev
->sock
),
331 if (!hsmp_pdev
->sock
)
335 ret
= init_acpi(&pdev
->dev
);
337 dev_err(&pdev
->dev
, "Failed to initialize HSMP interface.\n");
341 if (!hsmp_pdev
->is_probed
) {
342 ret
= hsmp_misc_register(&pdev
->dev
);
345 hsmp_pdev
->is_probed
= true;
351 static void hsmp_acpi_remove(struct platform_device
*pdev
)
354 * We register only one misc_device even on multi-socket system.
355 * So, deregister should happen only once.
357 if (hsmp_pdev
->is_probed
) {
358 hsmp_misc_deregister();
359 hsmp_pdev
->is_probed
= false;
363 static struct platform_driver amd_hsmp_driver
= {
364 .probe
= hsmp_acpi_probe
,
365 .remove
= hsmp_acpi_remove
,
368 .acpi_match_table
= amd_hsmp_acpi_ids
,
369 .dev_groups
= hsmp_groups
,
373 module_platform_driver(amd_hsmp_driver
);
375 MODULE_IMPORT_NS("AMD_HSMP");
376 MODULE_DESCRIPTION("AMD HSMP Platform Interface Driver");
377 MODULE_VERSION(DRIVER_VERSION
);
378 MODULE_LICENSE("GPL");