Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/crypto/ccp/sp-dev.c
26285 views
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);
314
315