]>
Commit | Line | Data |
---|---|---|
d2912cb1 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
63b94509 | 2 | /* |
d0ebbc0c | 3 | * AMD Secure Processor device driver |
63b94509 | 4 | * |
33960acc | 5 | * Copyright (C) 2013,2019 Advanced Micro Devices, Inc. |
63b94509 TL |
6 | * |
7 | * Author: Tom Lendacky <thomas.lendacky@amd.com> | |
fba8855c | 8 | * Author: Gary R Hook <gary.hook@amd.com> |
63b94509 TL |
9 | */ |
10 | ||
11 | #include <linux/module.h> | |
12 | #include <linux/kernel.h> | |
3d77565b | 13 | #include <linux/device.h> |
63b94509 TL |
14 | #include <linux/pci.h> |
15 | #include <linux/pci_ids.h> | |
3d77565b | 16 | #include <linux/dma-mapping.h> |
63b94509 TL |
17 | #include <linux/kthread.h> |
18 | #include <linux/sched.h> | |
19 | #include <linux/interrupt.h> | |
20 | #include <linux/spinlock.h> | |
21 | #include <linux/delay.h> | |
22 | #include <linux/ccp.h> | |
23 | ||
24 | #include "ccp-dev.h" | |
b93566f1 | 25 | #include "psp-dev.h" |
63b94509 | 26 | |
63b94509 TL |
27 | #define MSIX_VECTORS 2 |
28 | ||
d0ebbc0c | 29 | struct sp_pci { |
63b94509 | 30 | int msix_count; |
f4d18d65 | 31 | struct msix_entry msix_entry[MSIX_VECTORS]; |
63b94509 | 32 | }; |
2a6170df | 33 | static struct sp_device *sp_dev_master; |
63b94509 | 34 | |
d0ebbc0c | 35 | static int sp_get_msix_irqs(struct sp_device *sp) |
63b94509 | 36 | { |
d0ebbc0c | 37 | struct sp_pci *sp_pci = sp->dev_specific; |
f4d18d65 | 38 | struct device *dev = sp->dev; |
c6c59bf2 | 39 | struct pci_dev *pdev = to_pci_dev(dev); |
63b94509 TL |
40 | int v, ret; |
41 | ||
d0ebbc0c BS |
42 | for (v = 0; v < ARRAY_SIZE(sp_pci->msix_entry); v++) |
43 | sp_pci->msix_entry[v].entry = v; | |
63b94509 | 44 | |
d0ebbc0c | 45 | ret = pci_enable_msix_range(pdev, sp_pci->msix_entry, 1, v); |
5347ee8e | 46 | if (ret < 0) |
63b94509 TL |
47 | return ret; |
48 | ||
d0ebbc0c | 49 | sp_pci->msix_count = ret; |
f4d18d65 | 50 | sp->use_tasklet = true; |
63b94509 | 51 | |
d0ebbc0c BS |
52 | sp->psp_irq = sp_pci->msix_entry[0].vector; |
53 | sp->ccp_irq = (sp_pci->msix_count > 1) ? sp_pci->msix_entry[1].vector | |
54 | : sp_pci->msix_entry[0].vector; | |
63b94509 | 55 | return 0; |
63b94509 TL |
56 | } |
57 | ||
d0ebbc0c | 58 | static int sp_get_msi_irq(struct sp_device *sp) |
63b94509 | 59 | { |
f4d18d65 | 60 | struct device *dev = sp->dev; |
c6c59bf2 | 61 | struct pci_dev *pdev = to_pci_dev(dev); |
63b94509 TL |
62 | int ret; |
63 | ||
64 | ret = pci_enable_msi(pdev); | |
65 | if (ret) | |
66 | return ret; | |
67 | ||
f4d18d65 BS |
68 | sp->ccp_irq = pdev->irq; |
69 | sp->psp_irq = pdev->irq; | |
63b94509 TL |
70 | |
71 | return 0; | |
63b94509 TL |
72 | } |
73 | ||
d0ebbc0c | 74 | static int sp_get_irqs(struct sp_device *sp) |
63b94509 | 75 | { |
f4d18d65 | 76 | struct device *dev = sp->dev; |
63b94509 TL |
77 | int ret; |
78 | ||
d0ebbc0c | 79 | ret = sp_get_msix_irqs(sp); |
63b94509 TL |
80 | if (!ret) |
81 | return 0; | |
82 | ||
83 | /* Couldn't get MSI-X vectors, try MSI */ | |
84 | dev_notice(dev, "could not enable MSI-X (%d), trying MSI\n", ret); | |
d0ebbc0c | 85 | ret = sp_get_msi_irq(sp); |
63b94509 TL |
86 | if (!ret) |
87 | return 0; | |
88 | ||
89 | /* Couldn't get MSI interrupt */ | |
90 | dev_notice(dev, "could not enable MSI (%d)\n", ret); | |
91 | ||
92 | return ret; | |
93 | } | |
94 | ||
d0ebbc0c | 95 | static void sp_free_irqs(struct sp_device *sp) |
63b94509 | 96 | { |
d0ebbc0c | 97 | struct sp_pci *sp_pci = sp->dev_specific; |
f4d18d65 | 98 | struct device *dev = sp->dev; |
c6c59bf2 | 99 | struct pci_dev *pdev = to_pci_dev(dev); |
63b94509 | 100 | |
d0ebbc0c | 101 | if (sp_pci->msix_count) |
63b94509 | 102 | pci_disable_msix(pdev); |
f4d18d65 | 103 | else if (sp->psp_irq) |
63b94509 | 104 | pci_disable_msi(pdev); |
f4d18d65 BS |
105 | |
106 | sp->ccp_irq = 0; | |
107 | sp->psp_irq = 0; | |
63b94509 TL |
108 | } |
109 | ||
2a6170df BS |
110 | static bool sp_pci_is_master(struct sp_device *sp) |
111 | { | |
112 | struct device *dev_cur, *dev_new; | |
113 | struct pci_dev *pdev_cur, *pdev_new; | |
114 | ||
115 | dev_new = sp->dev; | |
116 | dev_cur = sp_dev_master->dev; | |
117 | ||
118 | pdev_new = to_pci_dev(dev_new); | |
119 | pdev_cur = to_pci_dev(dev_cur); | |
120 | ||
121 | if (pdev_new->bus->number < pdev_cur->bus->number) | |
122 | return true; | |
123 | ||
124 | if (PCI_SLOT(pdev_new->devfn) < PCI_SLOT(pdev_cur->devfn)) | |
125 | return true; | |
126 | ||
127 | if (PCI_FUNC(pdev_new->devfn) < PCI_FUNC(pdev_cur->devfn)) | |
128 | return true; | |
129 | ||
130 | return false; | |
131 | } | |
132 | ||
133 | static void psp_set_master(struct sp_device *sp) | |
134 | { | |
135 | if (!sp_dev_master) { | |
136 | sp_dev_master = sp; | |
137 | return; | |
138 | } | |
139 | ||
140 | if (sp_pci_is_master(sp)) | |
141 | sp_dev_master = sp; | |
142 | } | |
143 | ||
144 | static struct sp_device *psp_get_master(void) | |
145 | { | |
146 | return sp_dev_master; | |
147 | } | |
148 | ||
d0ebbc0c | 149 | static int sp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) |
63b94509 | 150 | { |
720419f0 | 151 | struct sp_device *sp; |
d0ebbc0c | 152 | struct sp_pci *sp_pci; |
63b94509 | 153 | struct device *dev = &pdev->dev; |
970e8303 BS |
154 | void __iomem * const *iomap_table; |
155 | int bar_mask; | |
63b94509 TL |
156 | int ret; |
157 | ||
158 | ret = -ENOMEM; | |
720419f0 BS |
159 | sp = sp_alloc_struct(dev); |
160 | if (!sp) | |
63b94509 TL |
161 | goto e_err; |
162 | ||
d0ebbc0c BS |
163 | sp_pci = devm_kzalloc(dev, sizeof(*sp_pci), GFP_KERNEL); |
164 | if (!sp_pci) | |
be03a3a0 TL |
165 | goto e_err; |
166 | ||
d0ebbc0c | 167 | sp->dev_specific = sp_pci; |
720419f0 BS |
168 | sp->dev_vdata = (struct sp_dev_vdata *)id->driver_data; |
169 | if (!sp->dev_vdata) { | |
c7019c4d GH |
170 | ret = -ENODEV; |
171 | dev_err(dev, "missing driver data\n"); | |
172 | goto e_err; | |
173 | } | |
63b94509 | 174 | |
970e8303 | 175 | ret = pcim_enable_device(pdev); |
63b94509 | 176 | if (ret) { |
970e8303 | 177 | dev_err(dev, "pcim_enable_device failed (%d)\n", ret); |
be03a3a0 | 178 | goto e_err; |
63b94509 TL |
179 | } |
180 | ||
970e8303 BS |
181 | bar_mask = pci_select_bars(pdev, IORESOURCE_MEM); |
182 | ret = pcim_iomap_regions(pdev, bar_mask, "ccp"); | |
63b94509 | 183 | if (ret) { |
970e8303 BS |
184 | dev_err(dev, "pcim_iomap_regions failed (%d)\n", ret); |
185 | goto e_err; | |
63b94509 TL |
186 | } |
187 | ||
970e8303 BS |
188 | iomap_table = pcim_iomap_table(pdev); |
189 | if (!iomap_table) { | |
190 | dev_err(dev, "pcim_iomap_table failed\n"); | |
191 | ret = -ENOMEM; | |
192 | goto e_err; | |
193 | } | |
63b94509 | 194 | |
720419f0 BS |
195 | sp->io_map = iomap_table[sp->dev_vdata->bar]; |
196 | if (!sp->io_map) { | |
970e8303 BS |
197 | dev_err(dev, "ioremap failed\n"); |
198 | ret = -ENOMEM; | |
199 | goto e_err; | |
63b94509 | 200 | } |
970e8303 | 201 | |
d0ebbc0c | 202 | ret = sp_get_irqs(sp); |
f4d18d65 BS |
203 | if (ret) |
204 | goto e_err; | |
205 | ||
970e8303 | 206 | pci_set_master(pdev); |
2a6170df BS |
207 | sp->set_psp_master_device = psp_set_master; |
208 | sp->get_psp_master_device = psp_get_master; | |
63b94509 | 209 | |
3d77565b TL |
210 | ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(48)); |
211 | if (ret) { | |
212 | ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); | |
63b94509 | 213 | if (ret) { |
3d77565b | 214 | dev_err(dev, "dma_set_mask_and_coherent failed (%d)\n", |
63b94509 | 215 | ret); |
970e8303 | 216 | goto e_err; |
63b94509 TL |
217 | } |
218 | } | |
219 | ||
720419f0 | 220 | dev_set_drvdata(dev, sp); |
63b94509 | 221 | |
720419f0 | 222 | ret = sp_init(sp); |
63b94509 | 223 | if (ret) |
970e8303 | 224 | goto e_err; |
63b94509 | 225 | |
63b94509 TL |
226 | return 0; |
227 | ||
63b94509 TL |
228 | e_err: |
229 | dev_notice(dev, "initialization failed\n"); | |
230 | return ret; | |
231 | } | |
232 | ||
d0ebbc0c | 233 | static void sp_pci_remove(struct pci_dev *pdev) |
63b94509 TL |
234 | { |
235 | struct device *dev = &pdev->dev; | |
720419f0 | 236 | struct sp_device *sp = dev_get_drvdata(dev); |
63b94509 | 237 | |
720419f0 | 238 | if (!sp) |
db34cf91 TL |
239 | return; |
240 | ||
720419f0 | 241 | sp_destroy(sp); |
63b94509 | 242 | |
d0ebbc0c | 243 | sp_free_irqs(sp); |
63b94509 TL |
244 | } |
245 | ||
246 | #ifdef CONFIG_PM | |
d0ebbc0c | 247 | static int sp_pci_suspend(struct pci_dev *pdev, pm_message_t state) |
63b94509 TL |
248 | { |
249 | struct device *dev = &pdev->dev; | |
720419f0 | 250 | struct sp_device *sp = dev_get_drvdata(dev); |
63b94509 | 251 | |
720419f0 | 252 | return sp_suspend(sp, state); |
63b94509 TL |
253 | } |
254 | ||
d0ebbc0c | 255 | static int sp_pci_resume(struct pci_dev *pdev) |
63b94509 TL |
256 | { |
257 | struct device *dev = &pdev->dev; | |
720419f0 | 258 | struct sp_device *sp = dev_get_drvdata(dev); |
63b94509 | 259 | |
720419f0 | 260 | return sp_resume(sp); |
63b94509 TL |
261 | } |
262 | #endif | |
263 | ||
2a6170df | 264 | #ifdef CONFIG_CRYPTO_DEV_SP_PSP |
6eb0cc72 | 265 | static const struct sev_vdata sevv1 = { |
ad01a984 TL |
266 | .cmdresp_reg = 0x10580, |
267 | .cmdbuff_addr_lo_reg = 0x105e0, | |
268 | .cmdbuff_addr_hi_reg = 0x105e4, | |
6eb0cc72 RT |
269 | }; |
270 | ||
271 | static const struct sev_vdata sevv2 = { | |
272 | .cmdresp_reg = 0x10980, | |
273 | .cmdbuff_addr_lo_reg = 0x109e0, | |
274 | .cmdbuff_addr_hi_reg = 0x109e4, | |
275 | }; | |
276 | ||
33960acc RT |
277 | static const struct tee_vdata teev1 = { |
278 | .cmdresp_reg = 0x10544, | |
279 | .cmdbuff_addr_lo_reg = 0x10548, | |
280 | .cmdbuff_addr_hi_reg = 0x1054c, | |
281 | .ring_wptr_reg = 0x10550, | |
282 | .ring_rptr_reg = 0x10554, | |
283 | }; | |
284 | ||
6eb0cc72 RT |
285 | static const struct psp_vdata pspv1 = { |
286 | .sev = &sevv1, | |
ad01a984 TL |
287 | .feature_reg = 0x105fc, |
288 | .inten_reg = 0x10610, | |
289 | .intsts_reg = 0x10614, | |
2a6170df | 290 | }; |
dcbc0c6e TL |
291 | |
292 | static const struct psp_vdata pspv2 = { | |
6eb0cc72 | 293 | .sev = &sevv2, |
dcbc0c6e TL |
294 | .feature_reg = 0x109fc, |
295 | .inten_reg = 0x10690, | |
296 | .intsts_reg = 0x10694, | |
297 | }; | |
33960acc RT |
298 | |
299 | static const struct psp_vdata pspv3 = { | |
300 | .tee = &teev1, | |
301 | .feature_reg = 0x109fc, | |
302 | .inten_reg = 0x10690, | |
303 | .intsts_reg = 0x10694, | |
304 | }; | |
2a6170df BS |
305 | #endif |
306 | ||
720419f0 | 307 | static const struct sp_dev_vdata dev_vdata[] = { |
dcbc0c6e | 308 | { /* 0 */ |
720419f0 BS |
309 | .bar = 2, |
310 | #ifdef CONFIG_CRYPTO_DEV_SP_CCP | |
311 | .ccp_vdata = &ccpv3, | |
312 | #endif | |
313 | }, | |
dcbc0c6e | 314 | { /* 1 */ |
720419f0 BS |
315 | .bar = 2, |
316 | #ifdef CONFIG_CRYPTO_DEV_SP_CCP | |
317 | .ccp_vdata = &ccpv5a, | |
2a6170df BS |
318 | #endif |
319 | #ifdef CONFIG_CRYPTO_DEV_SP_PSP | |
dcbc0c6e | 320 | .psp_vdata = &pspv1, |
720419f0 BS |
321 | #endif |
322 | }, | |
dcbc0c6e | 323 | { /* 2 */ |
720419f0 BS |
324 | .bar = 2, |
325 | #ifdef CONFIG_CRYPTO_DEV_SP_CCP | |
326 | .ccp_vdata = &ccpv5b, | |
dcbc0c6e TL |
327 | #endif |
328 | }, | |
329 | { /* 3 */ | |
330 | .bar = 2, | |
331 | #ifdef CONFIG_CRYPTO_DEV_SP_CCP | |
332 | .ccp_vdata = &ccpv5a, | |
333 | #endif | |
334 | #ifdef CONFIG_CRYPTO_DEV_SP_PSP | |
335 | .psp_vdata = &pspv2, | |
33960acc RT |
336 | #endif |
337 | }, | |
338 | { /* 4 */ | |
339 | .bar = 2, | |
340 | #ifdef CONFIG_CRYPTO_DEV_SP_CCP | |
341 | .ccp_vdata = &ccpv5a, | |
342 | #endif | |
343 | #ifdef CONFIG_CRYPTO_DEV_SP_PSP | |
344 | .psp_vdata = &pspv3, | |
720419f0 BS |
345 | #endif |
346 | }, | |
347 | }; | |
d0ebbc0c | 348 | static const struct pci_device_id sp_pci_table[] = { |
720419f0 BS |
349 | { PCI_VDEVICE(AMD, 0x1537), (kernel_ulong_t)&dev_vdata[0] }, |
350 | { PCI_VDEVICE(AMD, 0x1456), (kernel_ulong_t)&dev_vdata[1] }, | |
351 | { PCI_VDEVICE(AMD, 0x1468), (kernel_ulong_t)&dev_vdata[2] }, | |
dcbc0c6e | 352 | { PCI_VDEVICE(AMD, 0x1486), (kernel_ulong_t)&dev_vdata[3] }, |
33960acc | 353 | { PCI_VDEVICE(AMD, 0x15DF), (kernel_ulong_t)&dev_vdata[4] }, |
63b94509 TL |
354 | /* Last entry must be zero */ |
355 | { 0, } | |
356 | }; | |
d0ebbc0c | 357 | MODULE_DEVICE_TABLE(pci, sp_pci_table); |
63b94509 | 358 | |
d0ebbc0c | 359 | static struct pci_driver sp_pci_driver = { |
166db195 | 360 | .name = "ccp", |
d0ebbc0c BS |
361 | .id_table = sp_pci_table, |
362 | .probe = sp_pci_probe, | |
363 | .remove = sp_pci_remove, | |
63b94509 | 364 | #ifdef CONFIG_PM |
d0ebbc0c BS |
365 | .suspend = sp_pci_suspend, |
366 | .resume = sp_pci_resume, | |
63b94509 TL |
367 | #endif |
368 | }; | |
369 | ||
d0ebbc0c | 370 | int sp_pci_init(void) |
63b94509 | 371 | { |
d0ebbc0c | 372 | return pci_register_driver(&sp_pci_driver); |
63b94509 TL |
373 | } |
374 | ||
d0ebbc0c | 375 | void sp_pci_exit(void) |
63b94509 | 376 | { |
d0ebbc0c | 377 | pci_unregister_driver(&sp_pci_driver); |
63b94509 | 378 | } |