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_hsmp.h> 13 #include <asm/amd_nb.h> 14 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> 24 25 #include <uapi/asm-generic/errno-base.h> 26 27 #include "hsmp.h" 28 29 #define DRIVER_NAME "amd_hsmp" 30 #define DRIVER_VERSION "2.3" 31 #define ACPI_HSMP_DEVICE_HID "AMDI0097" 32 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" 37 38 static struct hsmp_plat_device *hsmp_pdev; 39 40 static int amd_hsmp_acpi_rdwr(struct hsmp_socket *sock, u32 offset, 41 u32 *value, bool write) 42 { 43 if (write) 44 iowrite32(*value, sock->virt_base_addr + offset); 45 else 46 *value = ioread32(sock->virt_base_addr + offset); 47 48 return 0; 49 } 50 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); 55 56 static inline bool is_acpi_hsmp_uuid(union acpi_object *obj) 57 { 58 if (obj->type == ACPI_TYPE_BUFFER && obj->buffer.length == UUID_SIZE) 59 return guid_equal((guid_t *)obj->buffer.pointer, &acpi_hsmp_uuid); 60 61 return false; 62 } 63 64 static inline int hsmp_get_uid(struct device *dev, u16 *sock_ind) 65 { 66 char *uid; 67 68 /* 69 * UID (ID00, ID01..IDXX) is used for differentiating sockets, 70 * read it and strip the "ID" part of it and convert the remaining 71 * bytes to integer. 72 */ 73 uid = acpi_device_uid(ACPI_COMPANION(dev)); 74 75 return kstrtou16(uid + 2, 10, sock_ind); 76 } 77 78 static acpi_status hsmp_resource(struct acpi_resource *res, void *data) 79 { 80 struct hsmp_socket *sock = data; 81 struct resource r; 82 83 switch (res->type) { 84 case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: 85 if (!acpi_dev_resource_memory(res, &r)) 86 return AE_ERROR; 87 if (!r.start || r.end < r.start || !(r.flags & IORESOURCE_MEM_WRITEABLE)) 88 return AE_ERROR; 89 sock->mbinfo.base_addr = r.start; 90 sock->mbinfo.size = resource_size(&r); 91 break; 92 case ACPI_RESOURCE_TYPE_END_TAG: 93 break; 94 default: 95 return AE_ERROR; 96 } 97 98 return AE_OK; 99 } 100 101 static int hsmp_read_acpi_dsd(struct hsmp_socket *sock) 102 { 103 struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL }; 104 union acpi_object *guid, *mailbox_package; 105 union acpi_object *dsd; 106 acpi_status status; 107 int ret = 0; 108 int j; 109 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)); 115 return -ENODEV; 116 } 117 118 dsd = buf.pointer; 119 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 127 */ 128 if (!dsd || dsd->type != ACPI_TYPE_PACKAGE || dsd->package.count != 2) { 129 ret = -EINVAL; 130 goto free_buf; 131 } 132 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"); 137 ret = -EINVAL; 138 goto free_buf; 139 } 140 141 for (j = 0; j < mailbox_package->package.count; j++) { 142 union acpi_object *msgobj, *msgstr, *msgint; 143 144 msgobj = &mailbox_package->package.elements[j]; 145 msgstr = &msgobj->package.elements[0]; 146 msgint = &msgobj->package.elements[1]; 147 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) { 152 ret = -EINVAL; 153 goto free_buf; 154 } 155 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; 165 } else { 166 ret = -ENOENT; 167 goto free_buf; 168 } 169 } 170 171 if (!sock->mbinfo.msg_id_off || !sock->mbinfo.msg_resp_off || 172 !sock->mbinfo.msg_arg_off) 173 ret = -EINVAL; 174 175 free_buf: 176 ACPI_FREE(buf.pointer); 177 return ret; 178 } 179 180 static int hsmp_read_acpi_crs(struct hsmp_socket *sock) 181 { 182 acpi_status status; 183 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)); 189 return -EINVAL; 190 } 191 if (!sock->mbinfo.base_addr || !sock->mbinfo.size) 192 return -EINVAL; 193 194 /* The mapped region should be un-cached */ 195 sock->virt_base_addr = devm_ioremap_uc(sock->dev, sock->mbinfo.base_addr, 196 sock->mbinfo.size); 197 if (!sock->virt_base_addr) { 198 dev_err(sock->dev, "Failed to ioremap MP1 base address\n"); 199 return -ENOMEM; 200 } 201 202 return 0; 203 } 204 205 /* Parse the ACPI table to read the data */ 206 static int hsmp_parse_acpi_table(struct device *dev, u16 sock_ind) 207 { 208 struct hsmp_socket *sock = &hsmp_pdev->sock[sock_ind]; 209 int ret; 210 211 sock->sock_ind = sock_ind; 212 sock->dev = dev; 213 sock->amd_hsmp_rdwr = amd_hsmp_acpi_rdwr; 214 215 sema_init(&sock->hsmp_sem, 1); 216 217 dev_set_drvdata(dev, sock); 218 219 /* Read MP1 base address from CRS method */ 220 ret = hsmp_read_acpi_crs(sock); 221 if (ret) 222 return ret; 223 224 /* Read mailbox offsets from DSD table */ 225 return hsmp_read_acpi_dsd(sock); 226 } 227 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) 231 { 232 struct device *dev = container_of(kobj, struct device, kobj); 233 struct hsmp_socket *sock = dev_get_drvdata(dev); 234 235 return hsmp_metric_tbl_read(sock, buf, count); 236 } 237 238 static umode_t hsmp_is_sock_attr_visible(struct kobject *kobj, 239 const struct bin_attribute *battr, int id) 240 { 241 if (hsmp_pdev->proto_ver == HSMP_PROTO_VER6) 242 return battr->attr.mode; 243 244 return 0; 245 } 246 247 static int init_acpi(struct device *dev) 248 { 249 u16 sock_ind; 250 int ret; 251 252 ret = hsmp_get_uid(dev, &sock_ind); 253 if (ret) 254 return ret; 255 if (sock_ind >= hsmp_pdev->num_sockets) 256 return -EINVAL; 257 258 ret = hsmp_parse_acpi_table(dev, sock_ind); 259 if (ret) { 260 dev_err(dev, "Failed to parse ACPI table\n"); 261 return ret; 262 } 263 264 /* Test the hsmp interface */ 265 ret = hsmp_test(sock_ind, 0xDEADBEEF); 266 if (ret) { 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"); 270 return ret; 271 } 272 273 ret = hsmp_cache_proto_ver(sock_ind); 274 if (ret) { 275 dev_err(dev, "Failed to read HSMP protocol version\n"); 276 return ret; 277 } 278 279 if (hsmp_pdev->proto_ver == HSMP_PROTO_VER6) { 280 ret = hsmp_get_tbl_dram_base(sock_ind); 281 if (ret) 282 dev_err(dev, "Failed to init metric table\n"); 283 } 284 285 return ret; 286 } 287 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), 292 }; 293 294 static struct bin_attribute *hsmp_attr_list[] = { 295 &hsmp_metric_tbl_attr, 296 NULL 297 }; 298 299 static struct attribute_group hsmp_attr_grp = { 300 .bin_attrs = hsmp_attr_list, 301 .is_bin_visible = hsmp_is_sock_attr_visible, 302 }; 303 304 static const struct attribute_group *hsmp_groups[] = { 305 &hsmp_attr_grp, 306 NULL 307 }; 308 309 static const struct acpi_device_id amd_hsmp_acpi_ids[] = { 310 {ACPI_HSMP_DEVICE_HID, 0}, 311 {} 312 }; 313 MODULE_DEVICE_TABLE(acpi, amd_hsmp_acpi_ids); 314 315 static int hsmp_acpi_probe(struct platform_device *pdev) 316 { 317 int ret; 318 319 hsmp_pdev = get_hsmp_pdev(); 320 if (!hsmp_pdev) 321 return -ENOMEM; 322 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) 326 return -ENODEV; 327 328 hsmp_pdev->sock = devm_kcalloc(&pdev->dev, hsmp_pdev->num_sockets, 329 sizeof(*hsmp_pdev->sock), 330 GFP_KERNEL); 331 if (!hsmp_pdev->sock) 332 return -ENOMEM; 333 } 334 335 ret = init_acpi(&pdev->dev); 336 if (ret) { 337 dev_err(&pdev->dev, "Failed to initialize HSMP interface.\n"); 338 return ret; 339 } 340 341 if (!hsmp_pdev->is_probed) { 342 ret = hsmp_misc_register(&pdev->dev); 343 if (ret) 344 return ret; 345 hsmp_pdev->is_probed = true; 346 } 347 348 return 0; 349 } 350 351 static void hsmp_acpi_remove(struct platform_device *pdev) 352 { 353 /* 354 * We register only one misc_device even on multi-socket system. 355 * So, deregister should happen only once. 356 */ 357 if (hsmp_pdev->is_probed) { 358 hsmp_misc_deregister(); 359 hsmp_pdev->is_probed = false; 360 } 361 } 362 363 static struct platform_driver amd_hsmp_driver = { 364 .probe = hsmp_acpi_probe, 365 .remove = hsmp_acpi_remove, 366 .driver = { 367 .name = DRIVER_NAME, 368 .acpi_match_table = amd_hsmp_acpi_ids, 369 .dev_groups = hsmp_groups, 370 }, 371 }; 372 373 module_platform_driver(amd_hsmp_driver); 374 375 MODULE_IMPORT_NS(AMD_HSMP); 376 MODULE_DESCRIPTION("AMD HSMP Platform Interface Driver"); 377 MODULE_VERSION(DRIVER_VERSION); 378 MODULE_LICENSE("GPL"); 379