1 // SPDX-License-Identifier: GPL-2.0-only
3 * AMD Secure Processor driver
5 * Copyright (C) 2017-2018 Advanced Micro Devices, Inc.
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>
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>
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");
31 /* List of SPs, SP count, read-write access lock, and access functions
33 * Lock structure: get sp_unit_lock for reading whenever we need to
34 * examine the SP list.
36 static DEFINE_RWLOCK(sp_unit_lock
);
37 static LIST_HEAD(sp_units
);
39 /* Ever-increasing value to produce unique unit numbers */
40 static atomic_t sp_ordinal
;
42 static void sp_add_device(struct sp_device
*sp
)
46 write_lock_irqsave(&sp_unit_lock
, flags
);
48 list_add_tail(&sp
->entry
, &sp_units
);
50 write_unlock_irqrestore(&sp_unit_lock
, flags
);
53 static void sp_del_device(struct sp_device
*sp
)
57 write_lock_irqsave(&sp_unit_lock
, flags
);
61 write_unlock_irqrestore(&sp_unit_lock
, flags
);
64 static irqreturn_t
sp_irq_handler(int irq
, void *data
)
66 struct sp_device
*sp
= data
;
68 if (sp
->ccp_irq_handler
)
69 sp
->ccp_irq_handler(irq
, sp
->ccp_irq_data
);
71 if (sp
->psp_irq_handler
)
72 sp
->psp_irq_handler(irq
, sp
->psp_irq_data
);
77 int sp_request_ccp_irq(struct sp_device
*sp
, irq_handler_t handler
,
78 const char *name
, void *data
)
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
;
87 if (!sp
->irq_registered
) {
88 ret
= request_irq(sp
->ccp_irq
, sp_irq_handler
, 0,
93 sp
->irq_registered
= true;
96 /* Each sub-device can manage it's own interrupt */
97 ret
= request_irq(sp
->ccp_irq
, handler
, 0, name
, data
);
105 int sp_request_psp_irq(struct sp_device
*sp
, irq_handler_t handler
,
106 const char *name
, void *data
)
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
;
115 if (!sp
->irq_registered
) {
116 ret
= request_irq(sp
->psp_irq
, sp_irq_handler
, 0,
121 sp
->irq_registered
= true;
124 /* Each sub-device can manage it's own interrupt */
125 ret
= request_irq(sp
->psp_irq
, handler
, 0, name
, data
);
133 void sp_free_ccp_irq(struct sp_device
*sp
, void *data
)
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
);
141 sp
->irq_registered
= false;
144 sp
->ccp_irq_handler
= NULL
;
145 sp
->ccp_irq_data
= NULL
;
147 /* Each sub-device can manage it's own interrupt */
148 free_irq(sp
->ccp_irq
, data
);
152 void sp_free_psp_irq(struct sp_device
*sp
, void *data
)
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
);
160 sp
->irq_registered
= false;
163 sp
->psp_irq_handler
= NULL
;
164 sp
->psp_irq_data
= NULL
;
166 /* Each sub-device can manage it's own interrupt */
167 free_irq(sp
->psp_irq
, data
);
172 * sp_alloc_struct - allocate and initialize the sp_device struct
174 * @dev: device struct of the SP
176 struct sp_device
*sp_alloc_struct(struct device
*dev
)
178 struct sp_device
*sp
;
180 sp
= devm_kzalloc(dev
, sizeof(*sp
), GFP_KERNEL
);
185 sp
->ord
= atomic_inc_return(&sp_ordinal
);
186 snprintf(sp
->name
, SP_MAX_NAME_LEN
, "sp-%u", sp
->ord
);
191 int sp_init(struct sp_device
*sp
)
195 if (sp
->dev_vdata
->ccp_vdata
)
198 if (sp
->dev_vdata
->psp_vdata
)
203 void sp_destroy(struct sp_device
*sp
)
205 if (sp
->dev_vdata
->ccp_vdata
)
208 if (sp
->dev_vdata
->psp_vdata
)
215 int sp_suspend(struct sp_device
*sp
, pm_message_t state
)
219 if (sp
->dev_vdata
->ccp_vdata
) {
220 ret
= ccp_dev_suspend(sp
, state
);
228 int sp_resume(struct sp_device
*sp
)
232 if (sp
->dev_vdata
->ccp_vdata
) {
233 ret
= ccp_dev_resume(sp
);
242 struct sp_device
*sp_get_psp_master_device(void)
244 struct sp_device
*i
, *ret
= NULL
;
247 write_lock_irqsave(&sp_unit_lock
, flags
);
248 if (list_empty(&sp_units
))
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();
259 write_unlock_irqrestore(&sp_unit_lock
, flags
);
263 static int __init
sp_mod_init(void)
272 #ifdef CONFIG_CRYPTO_DEV_SP_PSP
282 ret
= sp_platform_init();
292 static void __exit
sp_mod_exit(void)
296 #ifdef CONFIG_CRYPTO_DEV_SP_PSP
308 module_init(sp_mod_init
);
309 module_exit(sp_mod_exit
);