brintos

brintos / linux-shallow public Read only

0
0
Text · 5.8 KiB · 7eb3e46 Raw
300 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * AMD Secure Processor driver4 *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 functions32 *33 * Lock structure: get sp_unit_lock for reading whenever we need to34 * 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 struct173 *174 * @dev: device struct of the SP175 */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_X86256	int ret;257 258	ret = sp_pci_init();259	if (ret)260		return ret;261 262#ifdef CONFIG_CRYPTO_DEV_SP_PSP263	psp_pci_init();264#endif265 266	return 0;267#endif268 269#ifdef CONFIG_ARM64270	int ret;271 272	ret = sp_platform_init();273	if (ret)274		return ret;275 276	return 0;277#endif278 279	return -ENODEV;280}281 282static void __exit sp_mod_exit(void)283{284#ifdef CONFIG_X86285 286#ifdef CONFIG_CRYPTO_DEV_SP_PSP287	psp_pci_exit();288#endif289 290	sp_pci_exit();291#endif292 293#ifdef CONFIG_ARM64294	sp_platform_exit();295#endif296}297 298module_init(sp_mod_init);299module_exit(sp_mod_exit);300