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 platform device implementations. 8 */ 9 10 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 11 12 #include <asm/amd_nb.h> 13 14 #include <linux/device.h> 15 #include <linux/module.h> 16 #include <linux/pci.h> 17 #include <linux/platform_device.h> 18 #include <linux/sysfs.h> 19 20 #include "hsmp.h" 21 22 #define DRIVER_NAME "amd_hsmp" 23 #define DRIVER_VERSION "2.3" 24 25 /* 26 * To access specific HSMP mailbox register, s/w writes the SMN address of HSMP mailbox 27 * register into the SMN_INDEX register, and reads/writes the SMN_DATA reg. 28 * Below are required SMN address for HSMP Mailbox register offsets in SMU address space 29 */ 30 #define SMN_HSMP_BASE 0x3B00000 31 #define SMN_HSMP_MSG_ID 0x0010534 32 #define SMN_HSMP_MSG_ID_F1A_M0H 0x0010934 33 #define SMN_HSMP_MSG_RESP 0x0010980 34 #define SMN_HSMP_MSG_DATA 0x00109E0 35 36 #define HSMP_INDEX_REG 0xc4 37 #define HSMP_DATA_REG 0xc8 38 39 static int amd_hsmp_pci_rdwr(struct hsmp_socket *sock, u32 offset, 40 u32 *value, bool write) 41 { 42 int ret; 43 44 if (!sock->root) 45 return -ENODEV; 46 47 ret = pci_write_config_dword(sock->root, HSMP_INDEX_REG, 48 sock->mbinfo.base_addr + offset); 49 if (ret) 50 return ret; 51 52 ret = (write ? pci_write_config_dword(sock->root, HSMP_DATA_REG, *value) 53 : pci_read_config_dword(sock->root, HSMP_DATA_REG, value)); 54 55 return ret; 56 } 57 58 static int hsmp_create_non_acpi_sysfs_if(struct device *dev) 59 { 60 const struct attribute_group **hsmp_attr_grps; 61 struct attribute_group *attr_grp; 62 u16 i; 63 64 hsmp_attr_grps = devm_kcalloc(dev, hsmp_pdev.num_sockets + 1, 65 sizeof(*hsmp_attr_grps), 66 GFP_KERNEL); 67 if (!hsmp_attr_grps) 68 return -ENOMEM; 69 70 /* Create a sysfs directory for each socket */ 71 for (i = 0; i < hsmp_pdev.num_sockets; i++) { 72 attr_grp = devm_kzalloc(dev, sizeof(struct attribute_group), 73 GFP_KERNEL); 74 if (!attr_grp) 75 return -ENOMEM; 76 77 snprintf(hsmp_pdev.sock[i].name, HSMP_ATTR_GRP_NAME_SIZE, "socket%u", (u8)i); 78 attr_grp->name = hsmp_pdev.sock[i].name; 79 attr_grp->is_bin_visible = hsmp_is_sock_attr_visible; 80 hsmp_attr_grps[i] = attr_grp; 81 82 hsmp_create_attr_list(attr_grp, dev, i); 83 } 84 85 return device_add_groups(dev, hsmp_attr_grps); 86 } 87 88 static inline bool is_f1a_m0h(void) 89 { 90 if (boot_cpu_data.x86 == 0x1A && boot_cpu_data.x86_model <= 0x0F) 91 return true; 92 93 return false; 94 } 95 96 static int init_platform_device(struct device *dev) 97 { 98 struct hsmp_socket *sock; 99 int ret, i; 100 101 for (i = 0; i < hsmp_pdev.num_sockets; i++) { 102 if (!node_to_amd_nb(i)) 103 return -ENODEV; 104 sock = &hsmp_pdev.sock[i]; 105 sock->root = node_to_amd_nb(i)->root; 106 sock->sock_ind = i; 107 sock->dev = dev; 108 sock->mbinfo.base_addr = SMN_HSMP_BASE; 109 sock->amd_hsmp_rdwr = amd_hsmp_pci_rdwr; 110 111 /* 112 * This is a transitional change from non-ACPI to ACPI, only 113 * family 0x1A, model 0x00 platform is supported for both ACPI and non-ACPI. 114 */ 115 if (is_f1a_m0h()) 116 sock->mbinfo.msg_id_off = SMN_HSMP_MSG_ID_F1A_M0H; 117 else 118 sock->mbinfo.msg_id_off = SMN_HSMP_MSG_ID; 119 120 sock->mbinfo.msg_resp_off = SMN_HSMP_MSG_RESP; 121 sock->mbinfo.msg_arg_off = SMN_HSMP_MSG_DATA; 122 sema_init(&sock->hsmp_sem, 1); 123 124 /* Test the hsmp interface on each socket */ 125 ret = hsmp_test(i, 0xDEADBEEF); 126 if (ret) { 127 dev_err(dev, "HSMP test message failed on Fam:%x model:%x\n", 128 boot_cpu_data.x86, boot_cpu_data.x86_model); 129 dev_err(dev, "Is HSMP disabled in BIOS ?\n"); 130 return ret; 131 } 132 133 ret = hsmp_cache_proto_ver(i); 134 if (ret) { 135 dev_err(dev, "Failed to read HSMP protocol version\n"); 136 return ret; 137 } 138 } 139 140 return 0; 141 } 142 143 static int hsmp_pltdrv_probe(struct platform_device *pdev) 144 { 145 int ret; 146 147 hsmp_pdev.sock = devm_kcalloc(&pdev->dev, hsmp_pdev.num_sockets, 148 sizeof(*hsmp_pdev.sock), 149 GFP_KERNEL); 150 if (!hsmp_pdev.sock) 151 return -ENOMEM; 152 153 ret = init_platform_device(&pdev->dev); 154 if (ret) { 155 dev_err(&pdev->dev, "Failed to init HSMP mailbox\n"); 156 return ret; 157 } 158 159 ret = hsmp_create_non_acpi_sysfs_if(&pdev->dev); 160 if (ret) 161 dev_err(&pdev->dev, "Failed to create HSMP sysfs interface\n"); 162 163 return hsmp_misc_register(&pdev->dev); 164 } 165 166 static void hsmp_pltdrv_remove(struct platform_device *pdev) 167 { 168 hsmp_misc_deregister(); 169 } 170 171 static struct platform_driver amd_hsmp_driver = { 172 .probe = hsmp_pltdrv_probe, 173 .remove = hsmp_pltdrv_remove, 174 .driver = { 175 .name = DRIVER_NAME, 176 }, 177 }; 178 179 static struct platform_device *amd_hsmp_platdev; 180 181 static int hsmp_plat_dev_register(void) 182 { 183 int ret; 184 185 amd_hsmp_platdev = platform_device_alloc(DRIVER_NAME, PLATFORM_DEVID_NONE); 186 if (!amd_hsmp_platdev) 187 return -ENOMEM; 188 189 ret = platform_device_add(amd_hsmp_platdev); 190 if (ret) 191 platform_device_put(amd_hsmp_platdev); 192 193 return ret; 194 } 195 196 /* 197 * This check is only needed for backward compatibility of previous platforms. 198 * All new platforms are expected to support ACPI based probing. 199 */ 200 static bool legacy_hsmp_support(void) 201 { 202 if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD) 203 return false; 204 205 switch (boot_cpu_data.x86) { 206 case 0x19: 207 switch (boot_cpu_data.x86_model) { 208 case 0x00 ... 0x1F: 209 case 0x30 ... 0x3F: 210 case 0x90 ... 0x9F: 211 case 0xA0 ... 0xAF: 212 return true; 213 default: 214 return false; 215 } 216 case 0x1A: 217 switch (boot_cpu_data.x86_model) { 218 case 0x00 ... 0x1F: 219 return true; 220 default: 221 return false; 222 } 223 default: 224 return false; 225 } 226 227 return false; 228 } 229 230 static int __init hsmp_plt_init(void) 231 { 232 int ret = -ENODEV; 233 234 if (!legacy_hsmp_support()) { 235 pr_info("HSMP is not supported on Family:%x model:%x\n", 236 boot_cpu_data.x86, boot_cpu_data.x86_model); 237 return ret; 238 } 239 240 /* 241 * amd_nb_num() returns number of SMN/DF interfaces present in the system 242 * if we have N SMN/DF interfaces that ideally means N sockets 243 */ 244 hsmp_pdev.num_sockets = amd_nb_num(); 245 if (hsmp_pdev.num_sockets == 0 || hsmp_pdev.num_sockets > MAX_AMD_SOCKETS) 246 return ret; 247 248 ret = platform_driver_register(&amd_hsmp_driver); 249 if (ret) 250 return ret; 251 252 ret = hsmp_plat_dev_register(); 253 if (ret) 254 platform_driver_unregister(&amd_hsmp_driver); 255 256 return ret; 257 } 258 259 static void __exit hsmp_plt_exit(void) 260 { 261 platform_device_unregister(amd_hsmp_platdev); 262 platform_driver_unregister(&amd_hsmp_driver); 263 } 264 265 device_initcall(hsmp_plt_init); 266 module_exit(hsmp_plt_exit); 267 268 MODULE_DESCRIPTION("AMD HSMP Platform Interface Driver"); 269 MODULE_VERSION(DRIVER_VERSION); 270 MODULE_LICENSE("GPL"); 271