blob: ae7b4459991448a662fe63a3094d770840517081 [file] [log] [blame]
David Brazdil0f672f62019-12-10 10:32:29 +00001// SPDX-License-Identifier: GPL-2.0-only
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00002/*
3 * AMD Platform Security Processor (PSP) interface
4 *
Olivier Deprez157378f2022-04-04 15:47:50 +02005 * Copyright (C) 2016,2019 Advanced Micro Devices, Inc.
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00006 *
7 * Author: Brijesh Singh <brijesh.singh@amd.com>
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00008 */
9
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000010#include <linux/kernel.h>
Olivier Deprez157378f2022-04-04 15:47:50 +020011#include <linux/irqreturn.h>
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000012
13#include "sp-dev.h"
14#include "psp-dev.h"
Olivier Deprez157378f2022-04-04 15:47:50 +020015#include "sev-dev.h"
16#include "tee-dev.h"
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000017
Olivier Deprez157378f2022-04-04 15:47:50 +020018struct psp_device *psp_master;
David Brazdil0f672f62019-12-10 10:32:29 +000019
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000020static struct psp_device *psp_alloc_struct(struct sp_device *sp)
21{
22 struct device *dev = sp->dev;
23 struct psp_device *psp;
24
25 psp = devm_kzalloc(dev, sizeof(*psp), GFP_KERNEL);
26 if (!psp)
27 return NULL;
28
29 psp->dev = dev;
30 psp->sp = sp;
31
32 snprintf(psp->name, sizeof(psp->name), "psp-%u", sp->ord);
33
34 return psp;
35}
36
37static irqreturn_t psp_irq_handler(int irq, void *data)
38{
39 struct psp_device *psp = data;
40 unsigned int status;
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000041
42 /* Read the interrupt status: */
43 status = ioread32(psp->io_regs + psp->vdata->intsts_reg);
44
Olivier Deprez157378f2022-04-04 15:47:50 +020045 /* invoke subdevice interrupt handlers */
46 if (status) {
47 if (psp->sev_irq_handler)
48 psp->sev_irq_handler(irq, psp->sev_irq_data, status);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000049
Olivier Deprez157378f2022-04-04 15:47:50 +020050 if (psp->tee_irq_handler)
51 psp->tee_irq_handler(irq, psp->tee_irq_data, status);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000052 }
53
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000054 /* Clear the interrupt status by writing the same value we read. */
55 iowrite32(status, psp->io_regs + psp->vdata->intsts_reg);
56
57 return IRQ_HANDLED;
58}
59
Olivier Deprez157378f2022-04-04 15:47:50 +020060static unsigned int psp_get_capability(struct psp_device *psp)
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000061{
Olivier Deprez157378f2022-04-04 15:47:50 +020062 unsigned int val = ioread32(psp->io_regs + psp->vdata->feature_reg);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000063
Olivier Deprez157378f2022-04-04 15:47:50 +020064 /*
65 * Check for a access to the registers. If this read returns
66 * 0xffffffff, it's likely that the system is running a broken
67 * BIOS which disallows access to the device. Stop here and
68 * fail the PSP initialization (but not the load, as the CCP
69 * could get properly initialized).
70 */
71 if (val == 0xffffffff) {
72 dev_notice(psp->dev, "psp: unable to access the device: you might be running a broken BIOS.\n");
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000073 return 0;
Olivier Deprez157378f2022-04-04 15:47:50 +020074 }
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000075
Olivier Deprez157378f2022-04-04 15:47:50 +020076 return val;
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000077}
78
Olivier Deprez157378f2022-04-04 15:47:50 +020079static int psp_check_sev_support(struct psp_device *psp,
80 unsigned int capability)
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000081{
82 /* Check if device supports SEV feature */
Olivier Deprez157378f2022-04-04 15:47:50 +020083 if (!(capability & 1)) {
David Brazdil0f672f62019-12-10 10:32:29 +000084 dev_dbg(psp->dev, "psp does not support SEV\n");
85 return -ENODEV;
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000086 }
87
David Brazdil0f672f62019-12-10 10:32:29 +000088 return 0;
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000089}
90
Olivier Deprez157378f2022-04-04 15:47:50 +020091static int psp_check_tee_support(struct psp_device *psp,
92 unsigned int capability)
93{
94 /* Check if device supports TEE feature */
95 if (!(capability & 2)) {
96 dev_dbg(psp->dev, "psp does not support TEE\n");
97 return -ENODEV;
98 }
99
100 return 0;
101}
102
103static int psp_check_support(struct psp_device *psp,
104 unsigned int capability)
105{
106 int sev_support = psp_check_sev_support(psp, capability);
107 int tee_support = psp_check_tee_support(psp, capability);
108
109 /* Return error if device neither supports SEV nor TEE */
110 if (sev_support && tee_support)
111 return -ENODEV;
112
113 return 0;
114}
115
116static int psp_init(struct psp_device *psp, unsigned int capability)
117{
118 int ret;
119
120 if (!psp_check_sev_support(psp, capability)) {
121 ret = sev_dev_init(psp);
122 if (ret)
123 return ret;
124 }
125
126 if (!psp_check_tee_support(psp, capability)) {
127 ret = tee_dev_init(psp);
128 if (ret)
129 return ret;
130 }
131
132 return 0;
133}
134
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000135int psp_dev_init(struct sp_device *sp)
136{
137 struct device *dev = sp->dev;
138 struct psp_device *psp;
Olivier Deprez157378f2022-04-04 15:47:50 +0200139 unsigned int capability;
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000140 int ret;
141
142 ret = -ENOMEM;
143 psp = psp_alloc_struct(sp);
144 if (!psp)
145 goto e_err;
146
147 sp->psp_data = psp;
148
149 psp->vdata = (struct psp_vdata *)sp->dev_vdata->psp_vdata;
150 if (!psp->vdata) {
151 ret = -ENODEV;
152 dev_err(dev, "missing driver data\n");
153 goto e_err;
154 }
155
156 psp->io_regs = sp->io_map;
157
Olivier Deprez157378f2022-04-04 15:47:50 +0200158 capability = psp_get_capability(psp);
159 if (!capability)
160 goto e_disable;
161
162 ret = psp_check_support(psp, capability);
David Brazdil0f672f62019-12-10 10:32:29 +0000163 if (ret)
164 goto e_disable;
165
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000166 /* Disable and clear interrupts until ready */
167 iowrite32(0, psp->io_regs + psp->vdata->inten_reg);
168 iowrite32(-1, psp->io_regs + psp->vdata->intsts_reg);
169
170 /* Request an irq */
171 ret = sp_request_psp_irq(psp->sp, psp_irq_handler, psp->name, psp);
172 if (ret) {
173 dev_err(dev, "psp: unable to allocate an IRQ\n");
174 goto e_err;
175 }
176
Olivier Deprez157378f2022-04-04 15:47:50 +0200177 ret = psp_init(psp, capability);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000178 if (ret)
179 goto e_irq;
180
181 if (sp->set_psp_master_device)
182 sp->set_psp_master_device(sp);
183
184 /* Enable interrupt */
185 iowrite32(-1, psp->io_regs + psp->vdata->inten_reg);
186
187 dev_notice(dev, "psp enabled\n");
188
189 return 0;
190
191e_irq:
192 sp_free_psp_irq(psp->sp, psp);
193e_err:
194 sp->psp_data = NULL;
195
196 dev_notice(dev, "psp initialization failed\n");
197
198 return ret;
David Brazdil0f672f62019-12-10 10:32:29 +0000199
200e_disable:
201 sp->psp_data = NULL;
202
203 return ret;
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000204}
205
206void psp_dev_destroy(struct sp_device *sp)
207{
208 struct psp_device *psp = sp->psp_data;
209
210 if (!psp)
211 return;
212
Olivier Deprez157378f2022-04-04 15:47:50 +0200213 sev_dev_destroy(psp);
214
215 tee_dev_destroy(psp);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000216
217 sp_free_psp_irq(sp, psp);
Olivier Deprez157378f2022-04-04 15:47:50 +0200218
219 if (sp->clear_psp_master_device)
220 sp->clear_psp_master_device(sp);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000221}
222
Olivier Deprez157378f2022-04-04 15:47:50 +0200223void psp_set_sev_irq_handler(struct psp_device *psp, psp_irq_handler_t handler,
224 void *data)
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000225{
Olivier Deprez157378f2022-04-04 15:47:50 +0200226 psp->sev_irq_data = data;
227 psp->sev_irq_handler = handler;
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000228}
Olivier Deprez157378f2022-04-04 15:47:50 +0200229
230void psp_clear_sev_irq_handler(struct psp_device *psp)
231{
232 psp_set_sev_irq_handler(psp, NULL, NULL);
233}
234
235void psp_set_tee_irq_handler(struct psp_device *psp, psp_irq_handler_t handler,
236 void *data)
237{
238 psp->tee_irq_data = data;
239 psp->tee_irq_handler = handler;
240}
241
242void psp_clear_tee_irq_handler(struct psp_device *psp)
243{
244 psp_set_tee_irq_handler(psp, NULL, NULL);
245}
246
247struct psp_device *psp_get_master_device(void)
248{
249 struct sp_device *sp = sp_get_psp_master_device();
250
251 return sp ? sp->psp_data : NULL;
252}
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000253
254void psp_pci_init(void)
255{
Olivier Deprez157378f2022-04-04 15:47:50 +0200256 psp_master = psp_get_master_device();
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000257
Olivier Deprez157378f2022-04-04 15:47:50 +0200258 if (!psp_master)
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000259 return;
260
Olivier Deprez157378f2022-04-04 15:47:50 +0200261 sev_pci_init();
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000262}
263
264void psp_pci_exit(void)
265{
266 if (!psp_master)
267 return;
268
Olivier Deprez157378f2022-04-04 15:47:50 +0200269 sev_pci_exit();
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000270}