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