]> Git Repo - linux.git/blob - drivers/crypto/ccp/sp-dev.c
Linux 6.14-rc3
[linux.git] / drivers / crypto / ccp / sp-dev.c
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 <[email protected]>
8  * Author: Gary R Hook <[email protected]>
9  * Author: Brijesh Singh <[email protected]>
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 "sev-dev.h"
23 #include "ccp-dev.h"
24 #include "sp-dev.h"
25
26 MODULE_AUTHOR("Tom Lendacky <[email protected]>");
27 MODULE_AUTHOR("Gary R Hook <[email protected]>");
28 MODULE_LICENSE("GPL");
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
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
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
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
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
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
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
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  */
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
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
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
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
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
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
254 static int __init sp_mod_init(void)
255 {
256 #ifdef CONFIG_X86
257         static bool initialized;
258         int ret;
259
260         if (initialized)
261                 return 0;
262
263         ret = sp_pci_init();
264         if (ret)
265                 return ret;
266
267 #ifdef CONFIG_CRYPTO_DEV_SP_PSP
268         psp_pci_init();
269 #endif
270
271         initialized = true;
272
273         return 0;
274 #endif
275
276 #ifdef CONFIG_ARM64
277         int ret;
278
279         ret = sp_platform_init();
280         if (ret)
281                 return ret;
282
283         return 0;
284 #endif
285
286         return -ENODEV;
287 }
288
289 #if IS_BUILTIN(CONFIG_KVM_AMD) && IS_ENABLED(CONFIG_KVM_AMD_SEV)
290 int __init sev_module_init(void)
291 {
292         return sp_mod_init();
293 }
294 #endif
295
296 static void __exit sp_mod_exit(void)
297 {
298 #ifdef CONFIG_X86
299
300 #ifdef CONFIG_CRYPTO_DEV_SP_PSP
301         psp_pci_exit();
302 #endif
303
304         sp_pci_exit();
305 #endif
306
307 #ifdef CONFIG_ARM64
308         sp_platform_exit();
309 #endif
310 }
311
312 module_init(sp_mod_init);
313 module_exit(sp_mod_exit);
This page took 0.048497 seconds and 4 git commands to generate.