linux/drivers/crypto/ccp/sp-dev.c
<<
>>
Prefs
   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
  25MODULE_AUTHOR("Tom Lendacky <thomas.lendacky@amd.com>");
  26MODULE_AUTHOR("Gary R Hook <gary.hook@amd.com>");
  27MODULE_LICENSE("GPL");
  28MODULE_VERSION("1.1.0");
  29MODULE_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 */
  36static DEFINE_RWLOCK(sp_unit_lock);
  37static LIST_HEAD(sp_units);
  38
  39/* Ever-increasing value to produce unique unit numbers */
  40static atomic_t sp_ordinal;
  41
  42static 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
  53static 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
  64static 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
  77int 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
 105int 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
 133void 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
 152void 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 */
 176struct 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
 191int 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
 203void 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
 214int sp_suspend(struct sp_device *sp)
 215{
 216        if (sp->dev_vdata->ccp_vdata) {
 217                ccp_dev_suspend(sp);
 218        }
 219
 220        return 0;
 221}
 222
 223int sp_resume(struct sp_device *sp)
 224{
 225        if (sp->dev_vdata->ccp_vdata) {
 226                ccp_dev_resume(sp);
 227        }
 228
 229        return 0;
 230}
 231
 232struct sp_device *sp_get_psp_master_device(void)
 233{
 234        struct sp_device *i, *ret = NULL;
 235        unsigned long flags;
 236
 237        write_lock_irqsave(&sp_unit_lock, flags);
 238        if (list_empty(&sp_units))
 239                goto unlock;
 240
 241        list_for_each_entry(i, &sp_units, entry) {
 242                if (i->psp_data && i->get_psp_master_device) {
 243                        ret = i->get_psp_master_device();
 244                        break;
 245                }
 246        }
 247
 248unlock:
 249        write_unlock_irqrestore(&sp_unit_lock, flags);
 250        return ret;
 251}
 252
 253static int __init sp_mod_init(void)
 254{
 255#ifdef CONFIG_X86
 256        int ret;
 257
 258        ret = sp_pci_init();
 259        if (ret)
 260                return ret;
 261
 262#ifdef CONFIG_CRYPTO_DEV_SP_PSP
 263        psp_pci_init();
 264#endif
 265
 266        return 0;
 267#endif
 268
 269#ifdef CONFIG_ARM64
 270        int ret;
 271
 272        ret = sp_platform_init();
 273        if (ret)
 274                return ret;
 275
 276        return 0;
 277#endif
 278
 279        return -ENODEV;
 280}
 281
 282static void __exit sp_mod_exit(void)
 283{
 284#ifdef CONFIG_X86
 285
 286#ifdef CONFIG_CRYPTO_DEV_SP_PSP
 287        psp_pci_exit();
 288#endif
 289
 290        sp_pci_exit();
 291#endif
 292
 293#ifdef CONFIG_ARM64
 294        sp_platform_exit();
 295#endif
 296}
 297
 298module_init(sp_mod_init);
 299module_exit(sp_mod_exit);
 300