Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at master 325 lines 6.3 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 233int sp_restore(struct sp_device *sp) 234{ 235 if (sp->psp_data) { 236 int ret = psp_restore(sp); 237 238 if (ret) 239 return ret; 240 } 241 242 return sp_resume(sp); 243} 244 245struct sp_device *sp_get_psp_master_device(void) 246{ 247 struct sp_device *i, *ret = NULL; 248 unsigned long flags; 249 250 write_lock_irqsave(&sp_unit_lock, flags); 251 if (list_empty(&sp_units)) 252 goto unlock; 253 254 list_for_each_entry(i, &sp_units, entry) { 255 if (i->psp_data && i->get_psp_master_device) { 256 ret = i->get_psp_master_device(); 257 break; 258 } 259 } 260 261unlock: 262 write_unlock_irqrestore(&sp_unit_lock, flags); 263 return ret; 264} 265 266static int __init sp_mod_init(void) 267{ 268#ifdef CONFIG_X86 269 static bool initialized; 270 int ret; 271 272 if (initialized) 273 return 0; 274 275 ret = sp_pci_init(); 276 if (ret) 277 return ret; 278 279#ifdef CONFIG_CRYPTO_DEV_SP_PSP 280 psp_pci_init(); 281#endif 282 283 initialized = true; 284 285 return 0; 286#endif 287 288#ifdef CONFIG_ARM64 289 int ret; 290 291 ret = sp_platform_init(); 292 if (ret) 293 return ret; 294 295 return 0; 296#endif 297 298 return -ENODEV; 299} 300 301#if IS_BUILTIN(CONFIG_KVM_AMD) && IS_ENABLED(CONFIG_KVM_AMD_SEV) 302int __init sev_module_init(void) 303{ 304 return sp_mod_init(); 305} 306#endif 307 308static void __exit sp_mod_exit(void) 309{ 310#ifdef CONFIG_X86 311 312#ifdef CONFIG_CRYPTO_DEV_SP_PSP 313 psp_pci_exit(); 314#endif 315 316 sp_pci_exit(); 317#endif 318 319#ifdef CONFIG_ARM64 320 sp_platform_exit(); 321#endif 322} 323 324module_init(sp_mod_init); 325module_exit(sp_mod_exit);