xref: /linux/drivers/crypto/ccp/sp-pci.c (revision d0ebbc0c407a10485a8672ef370dfe55c666d57f)
1*d0ebbc0cSBrijesh Singh /*
2*d0ebbc0cSBrijesh Singh  * AMD Secure Processor device driver
3*d0ebbc0cSBrijesh Singh  *
4*d0ebbc0cSBrijesh Singh  * Copyright (C) 2013,2016 Advanced Micro Devices, Inc.
5*d0ebbc0cSBrijesh Singh  *
6*d0ebbc0cSBrijesh Singh  * Author: Tom Lendacky <thomas.lendacky@amd.com>
7*d0ebbc0cSBrijesh Singh  * Author: Gary R Hook <gary.hook@amd.com>
8*d0ebbc0cSBrijesh Singh  *
9*d0ebbc0cSBrijesh Singh  * This program is free software; you can redistribute it and/or modify
10*d0ebbc0cSBrijesh Singh  * it under the terms of the GNU General Public License version 2 as
11*d0ebbc0cSBrijesh Singh  * published by the Free Software Foundation.
12*d0ebbc0cSBrijesh Singh  */
13*d0ebbc0cSBrijesh Singh 
14*d0ebbc0cSBrijesh Singh #include <linux/module.h>
15*d0ebbc0cSBrijesh Singh #include <linux/kernel.h>
16*d0ebbc0cSBrijesh Singh #include <linux/device.h>
17*d0ebbc0cSBrijesh Singh #include <linux/pci.h>
18*d0ebbc0cSBrijesh Singh #include <linux/pci_ids.h>
19*d0ebbc0cSBrijesh Singh #include <linux/dma-mapping.h>
20*d0ebbc0cSBrijesh Singh #include <linux/kthread.h>
21*d0ebbc0cSBrijesh Singh #include <linux/sched.h>
22*d0ebbc0cSBrijesh Singh #include <linux/interrupt.h>
23*d0ebbc0cSBrijesh Singh #include <linux/spinlock.h>
24*d0ebbc0cSBrijesh Singh #include <linux/delay.h>
25*d0ebbc0cSBrijesh Singh #include <linux/ccp.h>
26*d0ebbc0cSBrijesh Singh 
27*d0ebbc0cSBrijesh Singh #include "ccp-dev.h"
28*d0ebbc0cSBrijesh Singh 
29*d0ebbc0cSBrijesh Singh #define MSIX_VECTORS			2
30*d0ebbc0cSBrijesh Singh 
31*d0ebbc0cSBrijesh Singh struct sp_pci {
32*d0ebbc0cSBrijesh Singh 	int msix_count;
33*d0ebbc0cSBrijesh Singh 	struct msix_entry msix_entry[MSIX_VECTORS];
34*d0ebbc0cSBrijesh Singh };
35*d0ebbc0cSBrijesh Singh 
36*d0ebbc0cSBrijesh Singh static int sp_get_msix_irqs(struct sp_device *sp)
37*d0ebbc0cSBrijesh Singh {
38*d0ebbc0cSBrijesh Singh 	struct sp_pci *sp_pci = sp->dev_specific;
39*d0ebbc0cSBrijesh Singh 	struct device *dev = sp->dev;
40*d0ebbc0cSBrijesh Singh 	struct pci_dev *pdev = to_pci_dev(dev);
41*d0ebbc0cSBrijesh Singh 	int v, ret;
42*d0ebbc0cSBrijesh Singh 
43*d0ebbc0cSBrijesh Singh 	for (v = 0; v < ARRAY_SIZE(sp_pci->msix_entry); v++)
44*d0ebbc0cSBrijesh Singh 		sp_pci->msix_entry[v].entry = v;
45*d0ebbc0cSBrijesh Singh 
46*d0ebbc0cSBrijesh Singh 	ret = pci_enable_msix_range(pdev, sp_pci->msix_entry, 1, v);
47*d0ebbc0cSBrijesh Singh 	if (ret < 0)
48*d0ebbc0cSBrijesh Singh 		return ret;
49*d0ebbc0cSBrijesh Singh 
50*d0ebbc0cSBrijesh Singh 	sp_pci->msix_count = ret;
51*d0ebbc0cSBrijesh Singh 	sp->use_tasklet = true;
52*d0ebbc0cSBrijesh Singh 
53*d0ebbc0cSBrijesh Singh 	sp->psp_irq = sp_pci->msix_entry[0].vector;
54*d0ebbc0cSBrijesh Singh 	sp->ccp_irq = (sp_pci->msix_count > 1) ? sp_pci->msix_entry[1].vector
55*d0ebbc0cSBrijesh Singh 					       : sp_pci->msix_entry[0].vector;
56*d0ebbc0cSBrijesh Singh 	return 0;
57*d0ebbc0cSBrijesh Singh }
58*d0ebbc0cSBrijesh Singh 
59*d0ebbc0cSBrijesh Singh static int sp_get_msi_irq(struct sp_device *sp)
60*d0ebbc0cSBrijesh Singh {
61*d0ebbc0cSBrijesh Singh 	struct device *dev = sp->dev;
62*d0ebbc0cSBrijesh Singh 	struct pci_dev *pdev = to_pci_dev(dev);
63*d0ebbc0cSBrijesh Singh 	int ret;
64*d0ebbc0cSBrijesh Singh 
65*d0ebbc0cSBrijesh Singh 	ret = pci_enable_msi(pdev);
66*d0ebbc0cSBrijesh Singh 	if (ret)
67*d0ebbc0cSBrijesh Singh 		return ret;
68*d0ebbc0cSBrijesh Singh 
69*d0ebbc0cSBrijesh Singh 	sp->ccp_irq = pdev->irq;
70*d0ebbc0cSBrijesh Singh 	sp->psp_irq = pdev->irq;
71*d0ebbc0cSBrijesh Singh 
72*d0ebbc0cSBrijesh Singh 	return 0;
73*d0ebbc0cSBrijesh Singh }
74*d0ebbc0cSBrijesh Singh 
75*d0ebbc0cSBrijesh Singh static int sp_get_irqs(struct sp_device *sp)
76*d0ebbc0cSBrijesh Singh {
77*d0ebbc0cSBrijesh Singh 	struct device *dev = sp->dev;
78*d0ebbc0cSBrijesh Singh 	int ret;
79*d0ebbc0cSBrijesh Singh 
80*d0ebbc0cSBrijesh Singh 	ret = sp_get_msix_irqs(sp);
81*d0ebbc0cSBrijesh Singh 	if (!ret)
82*d0ebbc0cSBrijesh Singh 		return 0;
83*d0ebbc0cSBrijesh Singh 
84*d0ebbc0cSBrijesh Singh 	/* Couldn't get MSI-X vectors, try MSI */
85*d0ebbc0cSBrijesh Singh 	dev_notice(dev, "could not enable MSI-X (%d), trying MSI\n", ret);
86*d0ebbc0cSBrijesh Singh 	ret = sp_get_msi_irq(sp);
87*d0ebbc0cSBrijesh Singh 	if (!ret)
88*d0ebbc0cSBrijesh Singh 		return 0;
89*d0ebbc0cSBrijesh Singh 
90*d0ebbc0cSBrijesh Singh 	/* Couldn't get MSI interrupt */
91*d0ebbc0cSBrijesh Singh 	dev_notice(dev, "could not enable MSI (%d)\n", ret);
92*d0ebbc0cSBrijesh Singh 
93*d0ebbc0cSBrijesh Singh 	return ret;
94*d0ebbc0cSBrijesh Singh }
95*d0ebbc0cSBrijesh Singh 
96*d0ebbc0cSBrijesh Singh static void sp_free_irqs(struct sp_device *sp)
97*d0ebbc0cSBrijesh Singh {
98*d0ebbc0cSBrijesh Singh 	struct sp_pci *sp_pci = sp->dev_specific;
99*d0ebbc0cSBrijesh Singh 	struct device *dev = sp->dev;
100*d0ebbc0cSBrijesh Singh 	struct pci_dev *pdev = to_pci_dev(dev);
101*d0ebbc0cSBrijesh Singh 
102*d0ebbc0cSBrijesh Singh 	if (sp_pci->msix_count)
103*d0ebbc0cSBrijesh Singh 		pci_disable_msix(pdev);
104*d0ebbc0cSBrijesh Singh 	else if (sp->psp_irq)
105*d0ebbc0cSBrijesh Singh 		pci_disable_msi(pdev);
106*d0ebbc0cSBrijesh Singh 
107*d0ebbc0cSBrijesh Singh 	sp->ccp_irq = 0;
108*d0ebbc0cSBrijesh Singh 	sp->psp_irq = 0;
109*d0ebbc0cSBrijesh Singh }
110*d0ebbc0cSBrijesh Singh 
111*d0ebbc0cSBrijesh Singh static int sp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
112*d0ebbc0cSBrijesh Singh {
113*d0ebbc0cSBrijesh Singh 	struct sp_device *sp;
114*d0ebbc0cSBrijesh Singh 	struct sp_pci *sp_pci;
115*d0ebbc0cSBrijesh Singh 	struct device *dev = &pdev->dev;
116*d0ebbc0cSBrijesh Singh 	void __iomem * const *iomap_table;
117*d0ebbc0cSBrijesh Singh 	int bar_mask;
118*d0ebbc0cSBrijesh Singh 	int ret;
119*d0ebbc0cSBrijesh Singh 
120*d0ebbc0cSBrijesh Singh 	ret = -ENOMEM;
121*d0ebbc0cSBrijesh Singh 	sp = sp_alloc_struct(dev);
122*d0ebbc0cSBrijesh Singh 	if (!sp)
123*d0ebbc0cSBrijesh Singh 		goto e_err;
124*d0ebbc0cSBrijesh Singh 
125*d0ebbc0cSBrijesh Singh 	sp_pci = devm_kzalloc(dev, sizeof(*sp_pci), GFP_KERNEL);
126*d0ebbc0cSBrijesh Singh 	if (!sp_pci)
127*d0ebbc0cSBrijesh Singh 		goto e_err;
128*d0ebbc0cSBrijesh Singh 
129*d0ebbc0cSBrijesh Singh 	sp->dev_specific = sp_pci;
130*d0ebbc0cSBrijesh Singh 	sp->dev_vdata = (struct sp_dev_vdata *)id->driver_data;
131*d0ebbc0cSBrijesh Singh 	if (!sp->dev_vdata) {
132*d0ebbc0cSBrijesh Singh 		ret = -ENODEV;
133*d0ebbc0cSBrijesh Singh 		dev_err(dev, "missing driver data\n");
134*d0ebbc0cSBrijesh Singh 		goto e_err;
135*d0ebbc0cSBrijesh Singh 	}
136*d0ebbc0cSBrijesh Singh 
137*d0ebbc0cSBrijesh Singh 	ret = pcim_enable_device(pdev);
138*d0ebbc0cSBrijesh Singh 	if (ret) {
139*d0ebbc0cSBrijesh Singh 		dev_err(dev, "pcim_enable_device failed (%d)\n", ret);
140*d0ebbc0cSBrijesh Singh 		goto e_err;
141*d0ebbc0cSBrijesh Singh 	}
142*d0ebbc0cSBrijesh Singh 
143*d0ebbc0cSBrijesh Singh 	bar_mask = pci_select_bars(pdev, IORESOURCE_MEM);
144*d0ebbc0cSBrijesh Singh 	ret = pcim_iomap_regions(pdev, bar_mask, "ccp");
145*d0ebbc0cSBrijesh Singh 	if (ret) {
146*d0ebbc0cSBrijesh Singh 		dev_err(dev, "pcim_iomap_regions failed (%d)\n", ret);
147*d0ebbc0cSBrijesh Singh 		goto e_err;
148*d0ebbc0cSBrijesh Singh 	}
149*d0ebbc0cSBrijesh Singh 
150*d0ebbc0cSBrijesh Singh 	iomap_table = pcim_iomap_table(pdev);
151*d0ebbc0cSBrijesh Singh 	if (!iomap_table) {
152*d0ebbc0cSBrijesh Singh 		dev_err(dev, "pcim_iomap_table failed\n");
153*d0ebbc0cSBrijesh Singh 		ret = -ENOMEM;
154*d0ebbc0cSBrijesh Singh 		goto e_err;
155*d0ebbc0cSBrijesh Singh 	}
156*d0ebbc0cSBrijesh Singh 
157*d0ebbc0cSBrijesh Singh 	sp->io_map = iomap_table[sp->dev_vdata->bar];
158*d0ebbc0cSBrijesh Singh 	if (!sp->io_map) {
159*d0ebbc0cSBrijesh Singh 		dev_err(dev, "ioremap failed\n");
160*d0ebbc0cSBrijesh Singh 		ret = -ENOMEM;
161*d0ebbc0cSBrijesh Singh 		goto e_err;
162*d0ebbc0cSBrijesh Singh 	}
163*d0ebbc0cSBrijesh Singh 
164*d0ebbc0cSBrijesh Singh 	ret = sp_get_irqs(sp);
165*d0ebbc0cSBrijesh Singh 	if (ret)
166*d0ebbc0cSBrijesh Singh 		goto e_err;
167*d0ebbc0cSBrijesh Singh 
168*d0ebbc0cSBrijesh Singh 	pci_set_master(pdev);
169*d0ebbc0cSBrijesh Singh 
170*d0ebbc0cSBrijesh Singh 	ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(48));
171*d0ebbc0cSBrijesh Singh 	if (ret) {
172*d0ebbc0cSBrijesh Singh 		ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
173*d0ebbc0cSBrijesh Singh 		if (ret) {
174*d0ebbc0cSBrijesh Singh 			dev_err(dev, "dma_set_mask_and_coherent failed (%d)\n",
175*d0ebbc0cSBrijesh Singh 				ret);
176*d0ebbc0cSBrijesh Singh 			goto e_err;
177*d0ebbc0cSBrijesh Singh 		}
178*d0ebbc0cSBrijesh Singh 	}
179*d0ebbc0cSBrijesh Singh 
180*d0ebbc0cSBrijesh Singh 	dev_set_drvdata(dev, sp);
181*d0ebbc0cSBrijesh Singh 
182*d0ebbc0cSBrijesh Singh 	ret = sp_init(sp);
183*d0ebbc0cSBrijesh Singh 	if (ret)
184*d0ebbc0cSBrijesh Singh 		goto e_err;
185*d0ebbc0cSBrijesh Singh 
186*d0ebbc0cSBrijesh Singh 	dev_notice(dev, "enabled\n");
187*d0ebbc0cSBrijesh Singh 
188*d0ebbc0cSBrijesh Singh 	return 0;
189*d0ebbc0cSBrijesh Singh 
190*d0ebbc0cSBrijesh Singh e_err:
191*d0ebbc0cSBrijesh Singh 	dev_notice(dev, "initialization failed\n");
192*d0ebbc0cSBrijesh Singh 	return ret;
193*d0ebbc0cSBrijesh Singh }
194*d0ebbc0cSBrijesh Singh 
195*d0ebbc0cSBrijesh Singh static void sp_pci_remove(struct pci_dev *pdev)
196*d0ebbc0cSBrijesh Singh {
197*d0ebbc0cSBrijesh Singh 	struct device *dev = &pdev->dev;
198*d0ebbc0cSBrijesh Singh 	struct sp_device *sp = dev_get_drvdata(dev);
199*d0ebbc0cSBrijesh Singh 
200*d0ebbc0cSBrijesh Singh 	if (!sp)
201*d0ebbc0cSBrijesh Singh 		return;
202*d0ebbc0cSBrijesh Singh 
203*d0ebbc0cSBrijesh Singh 	sp_destroy(sp);
204*d0ebbc0cSBrijesh Singh 
205*d0ebbc0cSBrijesh Singh 	sp_free_irqs(sp);
206*d0ebbc0cSBrijesh Singh 
207*d0ebbc0cSBrijesh Singh 	dev_notice(dev, "disabled\n");
208*d0ebbc0cSBrijesh Singh }
209*d0ebbc0cSBrijesh Singh 
210*d0ebbc0cSBrijesh Singh #ifdef CONFIG_PM
211*d0ebbc0cSBrijesh Singh static int sp_pci_suspend(struct pci_dev *pdev, pm_message_t state)
212*d0ebbc0cSBrijesh Singh {
213*d0ebbc0cSBrijesh Singh 	struct device *dev = &pdev->dev;
214*d0ebbc0cSBrijesh Singh 	struct sp_device *sp = dev_get_drvdata(dev);
215*d0ebbc0cSBrijesh Singh 
216*d0ebbc0cSBrijesh Singh 	return sp_suspend(sp, state);
217*d0ebbc0cSBrijesh Singh }
218*d0ebbc0cSBrijesh Singh 
219*d0ebbc0cSBrijesh Singh static int sp_pci_resume(struct pci_dev *pdev)
220*d0ebbc0cSBrijesh Singh {
221*d0ebbc0cSBrijesh Singh 	struct device *dev = &pdev->dev;
222*d0ebbc0cSBrijesh Singh 	struct sp_device *sp = dev_get_drvdata(dev);
223*d0ebbc0cSBrijesh Singh 
224*d0ebbc0cSBrijesh Singh 	return sp_resume(sp);
225*d0ebbc0cSBrijesh Singh }
226*d0ebbc0cSBrijesh Singh #endif
227*d0ebbc0cSBrijesh Singh 
228*d0ebbc0cSBrijesh Singh static const struct sp_dev_vdata dev_vdata[] = {
229*d0ebbc0cSBrijesh Singh 	{
230*d0ebbc0cSBrijesh Singh 		.bar = 2,
231*d0ebbc0cSBrijesh Singh #ifdef CONFIG_CRYPTO_DEV_SP_CCP
232*d0ebbc0cSBrijesh Singh 		.ccp_vdata = &ccpv3,
233*d0ebbc0cSBrijesh Singh #endif
234*d0ebbc0cSBrijesh Singh 	},
235*d0ebbc0cSBrijesh Singh 	{
236*d0ebbc0cSBrijesh Singh 		.bar = 2,
237*d0ebbc0cSBrijesh Singh #ifdef CONFIG_CRYPTO_DEV_SP_CCP
238*d0ebbc0cSBrijesh Singh 		.ccp_vdata = &ccpv5a,
239*d0ebbc0cSBrijesh Singh #endif
240*d0ebbc0cSBrijesh Singh 	},
241*d0ebbc0cSBrijesh Singh 	{
242*d0ebbc0cSBrijesh Singh 		.bar = 2,
243*d0ebbc0cSBrijesh Singh #ifdef CONFIG_CRYPTO_DEV_SP_CCP
244*d0ebbc0cSBrijesh Singh 		.ccp_vdata = &ccpv5b,
245*d0ebbc0cSBrijesh Singh #endif
246*d0ebbc0cSBrijesh Singh 	},
247*d0ebbc0cSBrijesh Singh };
248*d0ebbc0cSBrijesh Singh static const struct pci_device_id sp_pci_table[] = {
249*d0ebbc0cSBrijesh Singh 	{ PCI_VDEVICE(AMD, 0x1537), (kernel_ulong_t)&dev_vdata[0] },
250*d0ebbc0cSBrijesh Singh 	{ PCI_VDEVICE(AMD, 0x1456), (kernel_ulong_t)&dev_vdata[1] },
251*d0ebbc0cSBrijesh Singh 	{ PCI_VDEVICE(AMD, 0x1468), (kernel_ulong_t)&dev_vdata[2] },
252*d0ebbc0cSBrijesh Singh 	/* Last entry must be zero */
253*d0ebbc0cSBrijesh Singh 	{ 0, }
254*d0ebbc0cSBrijesh Singh };
255*d0ebbc0cSBrijesh Singh MODULE_DEVICE_TABLE(pci, sp_pci_table);
256*d0ebbc0cSBrijesh Singh 
257*d0ebbc0cSBrijesh Singh static struct pci_driver sp_pci_driver = {
258*d0ebbc0cSBrijesh Singh 	.name = "ccp",
259*d0ebbc0cSBrijesh Singh 	.id_table = sp_pci_table,
260*d0ebbc0cSBrijesh Singh 	.probe = sp_pci_probe,
261*d0ebbc0cSBrijesh Singh 	.remove = sp_pci_remove,
262*d0ebbc0cSBrijesh Singh #ifdef CONFIG_PM
263*d0ebbc0cSBrijesh Singh 	.suspend = sp_pci_suspend,
264*d0ebbc0cSBrijesh Singh 	.resume = sp_pci_resume,
265*d0ebbc0cSBrijesh Singh #endif
266*d0ebbc0cSBrijesh Singh };
267*d0ebbc0cSBrijesh Singh 
268*d0ebbc0cSBrijesh Singh int sp_pci_init(void)
269*d0ebbc0cSBrijesh Singh {
270*d0ebbc0cSBrijesh Singh 	return pci_register_driver(&sp_pci_driver);
271*d0ebbc0cSBrijesh Singh }
272*d0ebbc0cSBrijesh Singh 
273*d0ebbc0cSBrijesh Singh void sp_pci_exit(void)
274*d0ebbc0cSBrijesh Singh {
275*d0ebbc0cSBrijesh Singh 	pci_unregister_driver(&sp_pci_driver);
276*d0ebbc0cSBrijesh Singh }
277