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