root/drivers/crypto/ccp/sp-dev.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sp_add_device
  2. sp_del_device
  3. sp_irq_handler
  4. sp_request_ccp_irq
  5. sp_request_psp_irq
  6. sp_free_ccp_irq
  7. sp_free_psp_irq
  8. sp_alloc_struct
  9. sp_init
  10. sp_destroy
  11. sp_suspend
  12. sp_resume
  13. sp_get_psp_master_device
  14. sp_mod_init
  15. sp_mod_exit

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

/* [<][>][^][v][top][bottom][index][help] */