xref: /linux/drivers/platform/x86/amd/hsmp/acpi.c (revision 4fc0366ef83f493c63ecf732cbb7ed49edd62072)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * AMD HSMP Platform Driver
4  * Copyright (c) 2024, AMD.
5  * All Rights Reserved.
6  *
7  * This file provides an ACPI based driver implementation for HSMP interface.
8  */
9 
10 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
11 
12 #include <asm/amd_nb.h>
13 
14 #include <linux/acpi.h>
15 #include <linux/device.h>
16 #include <linux/dev_printk.h>
17 #include <linux/ioport.h>
18 #include <linux/kstrtox.h>
19 #include <linux/module.h>
20 #include <linux/platform_device.h>
21 #include <linux/sysfs.h>
22 #include <linux/uuid.h>
23 
24 #include <uapi/asm-generic/errno-base.h>
25 
26 #include "hsmp.h"
27 
28 #define DRIVER_NAME		"amd_hsmp"
29 #define DRIVER_VERSION		"2.3"
30 #define ACPI_HSMP_DEVICE_HID	"AMDI0097"
31 
32 /* These are the strings specified in ACPI table */
33 #define MSG_IDOFF_STR		"MsgIdOffset"
34 #define MSG_ARGOFF_STR		"MsgArgOffset"
35 #define MSG_RESPOFF_STR		"MsgRspOffset"
36 
37 static int amd_hsmp_acpi_rdwr(struct hsmp_socket *sock, u32 offset,
38 			      u32 *value, bool write)
39 {
40 	if (write)
41 		iowrite32(*value, sock->virt_base_addr + offset);
42 	else
43 		*value = ioread32(sock->virt_base_addr + offset);
44 
45 	return 0;
46 }
47 
48 /* This is the UUID used for HSMP */
49 static const guid_t acpi_hsmp_uuid = GUID_INIT(0xb74d619d, 0x5707, 0x48bd,
50 						0xa6, 0x9f, 0x4e, 0xa2,
51 						0x87, 0x1f, 0xc2, 0xf6);
52 
53 static inline bool is_acpi_hsmp_uuid(union acpi_object *obj)
54 {
55 	if (obj->type == ACPI_TYPE_BUFFER && obj->buffer.length == UUID_SIZE)
56 		return guid_equal((guid_t *)obj->buffer.pointer, &acpi_hsmp_uuid);
57 
58 	return false;
59 }
60 
61 static inline int hsmp_get_uid(struct device *dev, u16 *sock_ind)
62 {
63 	char *uid;
64 
65 	/*
66 	 * UID (ID00, ID01..IDXX) is used for differentiating sockets,
67 	 * read it and strip the "ID" part of it and convert the remaining
68 	 * bytes to integer.
69 	 */
70 	uid = acpi_device_uid(ACPI_COMPANION(dev));
71 
72 	return kstrtou16(uid + 2, 10, sock_ind);
73 }
74 
75 static acpi_status hsmp_resource(struct acpi_resource *res, void *data)
76 {
77 	struct hsmp_socket *sock = data;
78 	struct resource r;
79 
80 	switch (res->type) {
81 	case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
82 		if (!acpi_dev_resource_memory(res, &r))
83 			return AE_ERROR;
84 		if (!r.start || r.end < r.start || !(r.flags & IORESOURCE_MEM_WRITEABLE))
85 			return AE_ERROR;
86 		sock->mbinfo.base_addr = r.start;
87 		sock->mbinfo.size = resource_size(&r);
88 		break;
89 	case ACPI_RESOURCE_TYPE_END_TAG:
90 		break;
91 	default:
92 		return AE_ERROR;
93 	}
94 
95 	return AE_OK;
96 }
97 
98 static int hsmp_read_acpi_dsd(struct hsmp_socket *sock)
99 {
100 	struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
101 	union acpi_object *guid, *mailbox_package;
102 	union acpi_object *dsd;
103 	acpi_status status;
104 	int ret = 0;
105 	int j;
106 
107 	status = acpi_evaluate_object_typed(ACPI_HANDLE(sock->dev), "_DSD", NULL,
108 					    &buf, ACPI_TYPE_PACKAGE);
109 	if (ACPI_FAILURE(status)) {
110 		dev_err(sock->dev, "Failed to read mailbox reg offsets from DSD table, err: %s\n",
111 			acpi_format_exception(status));
112 		return -ENODEV;
113 	}
114 
115 	dsd = buf.pointer;
116 
117 	/* HSMP _DSD property should contain 2 objects.
118 	 * 1. guid which is an acpi object of type ACPI_TYPE_BUFFER
119 	 * 2. mailbox which is an acpi object of type ACPI_TYPE_PACKAGE
120 	 *    This mailbox object contains 3 more acpi objects of type
121 	 *    ACPI_TYPE_PACKAGE for holding msgid, msgresp, msgarg offsets
122 	 *    these packages inturn contain 2 acpi objects of type
123 	 *    ACPI_TYPE_STRING and ACPI_TYPE_INTEGER
124 	 */
125 	if (!dsd || dsd->type != ACPI_TYPE_PACKAGE || dsd->package.count != 2) {
126 		ret = -EINVAL;
127 		goto free_buf;
128 	}
129 
130 	guid = &dsd->package.elements[0];
131 	mailbox_package = &dsd->package.elements[1];
132 	if (!is_acpi_hsmp_uuid(guid) || mailbox_package->type != ACPI_TYPE_PACKAGE) {
133 		dev_err(sock->dev, "Invalid hsmp _DSD table data\n");
134 		ret = -EINVAL;
135 		goto free_buf;
136 	}
137 
138 	for (j = 0; j < mailbox_package->package.count; j++) {
139 		union acpi_object *msgobj, *msgstr, *msgint;
140 
141 		msgobj	= &mailbox_package->package.elements[j];
142 		msgstr	= &msgobj->package.elements[0];
143 		msgint	= &msgobj->package.elements[1];
144 
145 		/* package should have 1 string and 1 integer object */
146 		if (msgobj->type != ACPI_TYPE_PACKAGE ||
147 		    msgstr->type != ACPI_TYPE_STRING ||
148 		    msgint->type != ACPI_TYPE_INTEGER) {
149 			ret = -EINVAL;
150 			goto free_buf;
151 		}
152 
153 		if (!strncmp(msgstr->string.pointer, MSG_IDOFF_STR,
154 			     msgstr->string.length)) {
155 			sock->mbinfo.msg_id_off = msgint->integer.value;
156 		} else if (!strncmp(msgstr->string.pointer, MSG_RESPOFF_STR,
157 				    msgstr->string.length)) {
158 			sock->mbinfo.msg_resp_off =  msgint->integer.value;
159 		} else if (!strncmp(msgstr->string.pointer, MSG_ARGOFF_STR,
160 				    msgstr->string.length)) {
161 			sock->mbinfo.msg_arg_off = msgint->integer.value;
162 		} else {
163 			ret = -ENOENT;
164 			goto free_buf;
165 		}
166 	}
167 
168 	if (!sock->mbinfo.msg_id_off || !sock->mbinfo.msg_resp_off ||
169 	    !sock->mbinfo.msg_arg_off)
170 		ret = -EINVAL;
171 
172 free_buf:
173 	ACPI_FREE(buf.pointer);
174 	return ret;
175 }
176 
177 static int hsmp_read_acpi_crs(struct hsmp_socket *sock)
178 {
179 	acpi_status status;
180 
181 	status = acpi_walk_resources(ACPI_HANDLE(sock->dev), METHOD_NAME__CRS,
182 				     hsmp_resource, sock);
183 	if (ACPI_FAILURE(status)) {
184 		dev_err(sock->dev, "Failed to look up MP1 base address from CRS method, err: %s\n",
185 			acpi_format_exception(status));
186 		return -EINVAL;
187 	}
188 	if (!sock->mbinfo.base_addr || !sock->mbinfo.size)
189 		return -EINVAL;
190 
191 	/* The mapped region should be un-cached */
192 	sock->virt_base_addr = devm_ioremap_uc(sock->dev, sock->mbinfo.base_addr,
193 					       sock->mbinfo.size);
194 	if (!sock->virt_base_addr) {
195 		dev_err(sock->dev, "Failed to ioremap MP1 base address\n");
196 		return -ENOMEM;
197 	}
198 
199 	return 0;
200 }
201 
202 /* Parse the ACPI table to read the data */
203 static int hsmp_parse_acpi_table(struct device *dev, u16 sock_ind)
204 {
205 	struct hsmp_socket *sock = &hsmp_pdev.sock[sock_ind];
206 	int ret;
207 
208 	sock->sock_ind		= sock_ind;
209 	sock->dev		= dev;
210 	sock->amd_hsmp_rdwr	= amd_hsmp_acpi_rdwr;
211 
212 	sema_init(&sock->hsmp_sem, 1);
213 
214 	/* Read MP1 base address from CRS method */
215 	ret = hsmp_read_acpi_crs(sock);
216 	if (ret)
217 		return ret;
218 
219 	/* Read mailbox offsets from DSD table */
220 	return hsmp_read_acpi_dsd(sock);
221 }
222 
223 static int hsmp_create_acpi_sysfs_if(struct device *dev)
224 {
225 	struct attribute_group *attr_grp;
226 	u16 sock_ind;
227 	int ret;
228 
229 	attr_grp = devm_kzalloc(dev, sizeof(struct attribute_group), GFP_KERNEL);
230 	if (!attr_grp)
231 		return -ENOMEM;
232 
233 	attr_grp->is_bin_visible = hsmp_is_sock_attr_visible;
234 
235 	ret = hsmp_get_uid(dev, &sock_ind);
236 	if (ret)
237 		return ret;
238 
239 	ret = hsmp_create_attr_list(attr_grp, dev, sock_ind);
240 	if (ret)
241 		return ret;
242 
243 	return devm_device_add_group(dev, attr_grp);
244 }
245 
246 static int init_acpi(struct device *dev)
247 {
248 	u16 sock_ind;
249 	int ret;
250 
251 	ret = hsmp_get_uid(dev, &sock_ind);
252 	if (ret)
253 		return ret;
254 	if (sock_ind >= hsmp_pdev.num_sockets)
255 		return -EINVAL;
256 
257 	ret = hsmp_parse_acpi_table(dev, sock_ind);
258 	if (ret) {
259 		dev_err(dev, "Failed to parse ACPI table\n");
260 		return ret;
261 	}
262 
263 	/* Test the hsmp interface */
264 	ret = hsmp_test(sock_ind, 0xDEADBEEF);
265 	if (ret) {
266 		dev_err(dev, "HSMP test message failed on Fam:%x model:%x\n",
267 			boot_cpu_data.x86, boot_cpu_data.x86_model);
268 		dev_err(dev, "Is HSMP disabled in BIOS ?\n");
269 		return ret;
270 	}
271 
272 	ret = hsmp_cache_proto_ver(sock_ind);
273 	if (ret) {
274 		dev_err(dev, "Failed to read HSMP protocol version\n");
275 		return ret;
276 	}
277 
278 	return ret;
279 }
280 
281 static const struct acpi_device_id amd_hsmp_acpi_ids[] = {
282 	{ACPI_HSMP_DEVICE_HID, 0},
283 	{}
284 };
285 MODULE_DEVICE_TABLE(acpi, amd_hsmp_acpi_ids);
286 
287 static int hsmp_acpi_probe(struct platform_device *pdev)
288 {
289 	int ret;
290 
291 	if (!hsmp_pdev.is_probed) {
292 		hsmp_pdev.num_sockets = amd_nb_num();
293 		if (hsmp_pdev.num_sockets == 0 || hsmp_pdev.num_sockets > MAX_AMD_SOCKETS)
294 			return -ENODEV;
295 
296 		hsmp_pdev.sock = devm_kcalloc(&pdev->dev, hsmp_pdev.num_sockets,
297 					      sizeof(*hsmp_pdev.sock),
298 					      GFP_KERNEL);
299 		if (!hsmp_pdev.sock)
300 			return -ENOMEM;
301 	}
302 
303 	ret = init_acpi(&pdev->dev);
304 	if (ret) {
305 		dev_err(&pdev->dev, "Failed to initialize HSMP interface.\n");
306 		return ret;
307 	}
308 
309 	ret = hsmp_create_acpi_sysfs_if(&pdev->dev);
310 	if (ret)
311 		dev_err(&pdev->dev, "Failed to create HSMP sysfs interface\n");
312 
313 	if (!hsmp_pdev.is_probed) {
314 		ret = hsmp_misc_register(&pdev->dev);
315 		if (ret)
316 			return ret;
317 		hsmp_pdev.is_probed = true;
318 	}
319 
320 	return 0;
321 }
322 
323 static void hsmp_acpi_remove(struct platform_device *pdev)
324 {
325 	/*
326 	 * We register only one misc_device even on multi-socket system.
327 	 * So, deregister should happen only once.
328 	 */
329 	if (hsmp_pdev.is_probed) {
330 		hsmp_misc_deregister();
331 		hsmp_pdev.is_probed = false;
332 	}
333 }
334 
335 static struct platform_driver amd_hsmp_driver = {
336 	.probe		= hsmp_acpi_probe,
337 	.remove		= hsmp_acpi_remove,
338 	.driver		= {
339 		.name	= DRIVER_NAME,
340 		.acpi_match_table = amd_hsmp_acpi_ids,
341 	},
342 };
343 
344 module_platform_driver(amd_hsmp_driver);
345 
346 MODULE_IMPORT_NS(AMD_HSMP);
347 MODULE_DESCRIPTION("AMD HSMP Platform Interface Driver");
348 MODULE_VERSION(DRIVER_VERSION);
349 MODULE_LICENSE("GPL");
350