at master 313 lines 6.1 kB view raw
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * AMD Secure Processor driver 4 * 5 * Copyright (C) 2017-2018 Advanced Micro Devices, Inc. 6 * 7 * Author: Tom Lendacky <thomas.lendacky@amd.com> 8 * Author: Gary R Hook <gary.hook@amd.com> 9 * Author: Brijesh Singh <brijesh.singh@amd.com> 10 */ 11 12#include <linux/module.h> 13#include <linux/kernel.h> 14#include <linux/kthread.h> 15#include <linux/sched.h> 16#include <linux/interrupt.h> 17#include <linux/spinlock.h> 18#include <linux/spinlock_types.h> 19#include <linux/types.h> 20#include <linux/ccp.h> 21 22#include "sev-dev.h" 23#include "ccp-dev.h" 24#include "sp-dev.h" 25 26MODULE_AUTHOR("Tom Lendacky <thomas.lendacky@amd.com>"); 27MODULE_AUTHOR("Gary R Hook <gary.hook@amd.com>"); 28MODULE_LICENSE("GPL"); 29MODULE_VERSION("1.1.0"); 30MODULE_DESCRIPTION("AMD Secure Processor driver"); 31 32/* List of SPs, SP count, read-write access lock, and access functions 33 * 34 * Lock structure: get sp_unit_lock for reading whenever we need to 35 * examine the SP list. 36 */ 37static DEFINE_RWLOCK(sp_unit_lock); 38static LIST_HEAD(sp_units); 39 40/* Ever-increasing value to produce unique unit numbers */ 41static atomic_t sp_ordinal; 42 43static void sp_add_device(struct sp_device *sp) 44{ 45 unsigned long flags; 46 47 write_lock_irqsave(&sp_unit_lock, flags); 48 49 list_add_tail(&sp->entry, &sp_units); 50 51 write_unlock_irqrestore(&sp_unit_lock, flags); 52} 53 54static void sp_del_device(struct sp_device *sp) 55{ 56 unsigned long flags; 57 58 write_lock_irqsave(&sp_unit_lock, flags); 59 60 list_del(&sp->entry); 61 62 write_unlock_irqrestore(&sp_unit_lock, flags); 63} 64 65static irqreturn_t sp_irq_handler(int irq, void *data) 66{ 67 struct sp_device *sp = data; 68 69 if (sp->ccp_irq_handler) 70 sp->ccp_irq_handler(irq, sp->ccp_irq_data); 71 72 if (sp->psp_irq_handler) 73 sp->psp_irq_handler(irq, sp->psp_irq_data); 74 75 return IRQ_HANDLED; 76} 77 78int sp_request_ccp_irq(struct sp_device *sp, irq_handler_t handler, 79 const char *name, void *data) 80{ 81 int ret; 82 83 if ((sp->psp_irq == sp->ccp_irq) && sp->dev_vdata->psp_vdata) { 84 /* Need a common routine to manage all interrupts */ 85 sp->ccp_irq_data = data; 86 sp->ccp_irq_handler = handler; 87 88 if (!sp->irq_registered) { 89 ret = request_irq(sp->ccp_irq, sp_irq_handler, 0, 90 sp->name, sp); 91 if (ret) 92 return ret; 93 94 sp->irq_registered = true; 95 } 96 } else { 97 /* Each sub-device can manage it's own interrupt */ 98 ret = request_irq(sp->ccp_irq, handler, 0, name, data); 99 if (ret) 100 return ret; 101 } 102 103 return 0; 104} 105 106int sp_request_psp_irq(struct sp_device *sp, irq_handler_t handler, 107 const char *name, void *data) 108{ 109 int ret; 110 111 if ((sp->psp_irq == sp->ccp_irq) && sp->dev_vdata->ccp_vdata) { 112 /* Need a common routine to manage all interrupts */ 113 sp->psp_irq_data = data; 114 sp->psp_irq_handler = handler; 115 116 if (!sp->irq_registered) { 117 ret = request_irq(sp->psp_irq, sp_irq_handler, 0, 118 sp->name, sp); 119 if (ret) 120 return ret; 121 122 sp->irq_registered = true; 123 } 124 } else { 125 /* Each sub-device can manage it's own interrupt */ 126 ret = request_irq(sp->psp_irq, handler, 0, name, data); 127 if (ret) 128 return ret; 129 } 130 131 return 0; 132} 133 134void sp_free_ccp_irq(struct sp_device *sp, void *data) 135{ 136 if ((sp->psp_irq == sp->ccp_irq) && sp->dev_vdata->psp_vdata) { 137 /* Using common routine to manage all interrupts */ 138 if (!sp->psp_irq_handler) { 139 /* Nothing else using it, so free it */ 140 free_irq(sp->ccp_irq, sp); 141 142 sp->irq_registered = false; 143 } 144 145 sp->ccp_irq_handler = NULL; 146 sp->ccp_irq_data = NULL; 147 } else { 148 /* Each sub-device can manage it's own interrupt */ 149 free_irq(sp->ccp_irq, data); 150 } 151} 152 153void sp_free_psp_irq(struct sp_device *sp, void *data) 154{ 155 if ((sp->psp_irq == sp->ccp_irq) && sp->dev_vdata->ccp_vdata) { 156 /* Using common routine to manage all interrupts */ 157 if (!sp->ccp_irq_handler) { 158 /* Nothing else using it, so free it */ 159 free_irq(sp->psp_irq, sp); 160 161 sp->irq_registered = false; 162 } 163 164 sp->psp_irq_handler = NULL; 165 sp->psp_irq_data = NULL; 166 } else { 167 /* Each sub-device can manage it's own interrupt */ 168 free_irq(sp->psp_irq, data); 169 } 170} 171 172/** 173 * sp_alloc_struct - allocate and initialize the sp_device struct 174 * 175 * @dev: device struct of the SP 176 */ 177struct sp_device *sp_alloc_struct(struct device *dev) 178{ 179 struct sp_device *sp; 180 181 sp = devm_kzalloc(dev, sizeof(*sp), GFP_KERNEL); 182 if (!sp) 183 return NULL; 184 185 sp->dev = dev; 186 sp->ord = atomic_inc_return(&sp_ordinal); 187 snprintf(sp->name, SP_MAX_NAME_LEN, "sp-%u", sp->ord); 188 189 return sp; 190} 191 192int sp_init(struct sp_device *sp) 193{ 194 sp_add_device(sp); 195 196 if (sp->dev_vdata->ccp_vdata) 197 ccp_dev_init(sp); 198 199 if (sp->dev_vdata->psp_vdata) 200 psp_dev_init(sp); 201 return 0; 202} 203 204void sp_destroy(struct sp_device *sp) 205{ 206 if (sp->dev_vdata->ccp_vdata) 207 ccp_dev_destroy(sp); 208 209 if (sp->dev_vdata->psp_vdata) 210 psp_dev_destroy(sp); 211 212 sp_del_device(sp); 213} 214 215int sp_suspend(struct sp_device *sp) 216{ 217 if (sp->dev_vdata->ccp_vdata) { 218 ccp_dev_suspend(sp); 219 } 220 221 return 0; 222} 223 224int sp_resume(struct sp_device *sp) 225{ 226 if (sp->dev_vdata->ccp_vdata) { 227 ccp_dev_resume(sp); 228 } 229 230 return 0; 231} 232 233struct sp_device *sp_get_psp_master_device(void) 234{ 235 struct sp_device *i, *ret = NULL; 236 unsigned long flags; 237 238 write_lock_irqsave(&sp_unit_lock, flags); 239 if (list_empty(&sp_units)) 240 goto unlock; 241 242 list_for_each_entry(i, &sp_units, entry) { 243 if (i->psp_data && i->get_psp_master_device) { 244 ret = i->get_psp_master_device(); 245 break; 246 } 247 } 248 249unlock: 250 write_unlock_irqrestore(&sp_unit_lock, flags); 251 return ret; 252} 253 254static int __init sp_mod_init(void) 255{ 256#ifdef CONFIG_X86 257 static bool initialized; 258 int ret; 259 260 if (initialized) 261 return 0; 262 263 ret = sp_pci_init(); 264 if (ret) 265 return ret; 266 267#ifdef CONFIG_CRYPTO_DEV_SP_PSP 268 psp_pci_init(); 269#endif 270 271 initialized = true; 272 273 return 0; 274#endif 275 276#ifdef CONFIG_ARM64 277 int ret; 278 279 ret = sp_platform_init(); 280 if (ret) 281 return ret; 282 283 return 0; 284#endif 285 286 return -ENODEV; 287} 288 289#if IS_BUILTIN(CONFIG_KVM_AMD) && IS_ENABLED(CONFIG_KVM_AMD_SEV) 290int __init sev_module_init(void) 291{ 292 return sp_mod_init(); 293} 294#endif 295 296static void __exit sp_mod_exit(void) 297{ 298#ifdef CONFIG_X86 299 300#ifdef CONFIG_CRYPTO_DEV_SP_PSP 301 psp_pci_exit(); 302#endif 303 304 sp_pci_exit(); 305#endif 306 307#ifdef CONFIG_ARM64 308 sp_platform_exit(); 309#endif 310} 311 312module_init(sp_mod_init); 313module_exit(sp_mod_exit);