2 * AMD Secure Processor driver
4 * Copyright (C) 2017 Advanced Micro Devices, Inc.
6 * Author: Tom Lendacky <thomas.lendacky@amd.com>
7 * Author: Gary R Hook <gary.hook@amd.com>
8 * Author: Brijesh Singh <brijesh.singh@amd.com>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
15 #include <linux/module.h>
16 #include <linux/kernel.h>
17 #include <linux/kthread.h>
18 #include <linux/sched.h>
19 #include <linux/interrupt.h>
20 #include <linux/spinlock.h>
21 #include <linux/spinlock_types.h>
22 #include <linux/types.h>
23 #include <linux/ccp.h>
28 MODULE_AUTHOR("Tom Lendacky <thomas.lendacky@amd.com>");
29 MODULE_AUTHOR("Gary R Hook <gary.hook@amd.com>");
30 MODULE_LICENSE("GPL");
31 MODULE_VERSION("1.1.0");
32 MODULE_DESCRIPTION("AMD Secure Processor driver");
34 /* List of SPs, SP count, read-write access lock, and access functions
36 * Lock structure: get sp_unit_lock for reading whenever we need to
37 * examine the SP list.
39 static DEFINE_RWLOCK(sp_unit_lock
);
40 static LIST_HEAD(sp_units
);
42 /* Ever-increasing value to produce unique unit numbers */
43 static atomic_t sp_ordinal
;
45 static void sp_add_device(struct sp_device
*sp
)
49 write_lock_irqsave(&sp_unit_lock
, flags
);
51 list_add_tail(&sp
->entry
, &sp_units
);
53 write_unlock_irqrestore(&sp_unit_lock
, flags
);
56 static void sp_del_device(struct sp_device
*sp
)
60 write_lock_irqsave(&sp_unit_lock
, flags
);
64 write_unlock_irqrestore(&sp_unit_lock
, flags
);
67 static irqreturn_t
sp_irq_handler(int irq
, void *data
)
69 struct sp_device
*sp
= data
;
71 if (sp
->ccp_irq_handler
)
72 sp
->ccp_irq_handler(irq
, sp
->ccp_irq_data
);
74 if (sp
->psp_irq_handler
)
75 sp
->psp_irq_handler(irq
, sp
->psp_irq_data
);
80 int sp_request_ccp_irq(struct sp_device
*sp
, irq_handler_t handler
,
81 const char *name
, void *data
)
85 if ((sp
->psp_irq
== sp
->ccp_irq
) && sp
->dev_vdata
->psp_vdata
) {
86 /* Need a common routine to manage all interrupts */
87 sp
->ccp_irq_data
= data
;
88 sp
->ccp_irq_handler
= handler
;
90 if (!sp
->irq_registered
) {
91 ret
= request_irq(sp
->ccp_irq
, sp_irq_handler
, 0,
96 sp
->irq_registered
= true;
99 /* Each sub-device can manage it's own interrupt */
100 ret
= request_irq(sp
->ccp_irq
, handler
, 0, name
, data
);
108 int sp_request_psp_irq(struct sp_device
*sp
, irq_handler_t handler
,
109 const char *name
, void *data
)
113 if ((sp
->psp_irq
== sp
->ccp_irq
) && sp
->dev_vdata
->ccp_vdata
) {
114 /* Need a common routine to manage all interrupts */
115 sp
->psp_irq_data
= data
;
116 sp
->psp_irq_handler
= handler
;
118 if (!sp
->irq_registered
) {
119 ret
= request_irq(sp
->psp_irq
, sp_irq_handler
, 0,
124 sp
->irq_registered
= true;
127 /* Each sub-device can manage it's own interrupt */
128 ret
= request_irq(sp
->psp_irq
, handler
, 0, name
, data
);
136 void sp_free_ccp_irq(struct sp_device
*sp
, void *data
)
138 if ((sp
->psp_irq
== sp
->ccp_irq
) && sp
->dev_vdata
->psp_vdata
) {
139 /* Using common routine to manage all interrupts */
140 if (!sp
->psp_irq_handler
) {
141 /* Nothing else using it, so free it */
142 free_irq(sp
->ccp_irq
, sp
);
144 sp
->irq_registered
= false;
147 sp
->ccp_irq_handler
= NULL
;
148 sp
->ccp_irq_data
= NULL
;
150 /* Each sub-device can manage it's own interrupt */
151 free_irq(sp
->ccp_irq
, data
);
155 void sp_free_psp_irq(struct sp_device
*sp
, void *data
)
157 if ((sp
->psp_irq
== sp
->ccp_irq
) && sp
->dev_vdata
->ccp_vdata
) {
158 /* Using common routine to manage all interrupts */
159 if (!sp
->ccp_irq_handler
) {
160 /* Nothing else using it, so free it */
161 free_irq(sp
->psp_irq
, sp
);
163 sp
->irq_registered
= false;
166 sp
->psp_irq_handler
= NULL
;
167 sp
->psp_irq_data
= NULL
;
169 /* Each sub-device can manage it's own interrupt */
170 free_irq(sp
->psp_irq
, data
);
175 * sp_alloc_struct - allocate and initialize the sp_device struct
177 * @dev: device struct of the SP
179 struct sp_device
*sp_alloc_struct(struct device
*dev
)
181 struct sp_device
*sp
;
183 sp
= devm_kzalloc(dev
, sizeof(*sp
), GFP_KERNEL
);
188 sp
->ord
= atomic_inc_return(&sp_ordinal
);
189 snprintf(sp
->name
, SP_MAX_NAME_LEN
, "sp-%u", sp
->ord
);
194 int sp_init(struct sp_device
*sp
)
198 if (sp
->dev_vdata
->ccp_vdata
)
201 if (sp
->dev_vdata
->psp_vdata
)
206 void sp_destroy(struct sp_device
*sp
)
208 if (sp
->dev_vdata
->ccp_vdata
)
211 if (sp
->dev_vdata
->psp_vdata
)
218 int sp_suspend(struct sp_device
*sp
, pm_message_t state
)
222 if (sp
->dev_vdata
->ccp_vdata
) {
223 ret
= ccp_dev_suspend(sp
, state
);
231 int sp_resume(struct sp_device
*sp
)
235 if (sp
->dev_vdata
->ccp_vdata
) {
236 ret
= ccp_dev_resume(sp
);
245 struct sp_device
*sp_get_psp_master_device(void)
247 struct sp_device
*i
, *ret
= NULL
;
250 write_lock_irqsave(&sp_unit_lock
, flags
);
251 if (list_empty(&sp_units
))
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();
262 write_unlock_irqrestore(&sp_unit_lock
, flags
);
266 static int __init
sp_mod_init(void)
275 #ifdef CONFIG_CRYPTO_DEV_SP_PSP
285 ret
= sp_platform_init();
295 static void __exit
sp_mod_exit(void)
299 #ifdef CONFIG_CRYPTO_DEV_SP_PSP
311 module_init(sp_mod_init
);
312 module_exit(sp_mod_exit
);