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