2 * AMD Cryptographic Coprocessor (CCP) driver
4 * Copyright (C) 2013 Advanced Micro Devices, Inc.
6 * Author: Tom Lendacky <thomas.lendacky@amd.com>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
13 #include <linux/module.h>
14 #include <linux/kernel.h>
15 #include <linux/pci.h>
16 #include <linux/pci_ids.h>
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>
27 #define MSIX_VECTORS 2
36 struct ccp_msix msix[MSIX_VECTORS];
39 static int ccp_get_msix_irqs(struct ccp_device *ccp)
41 struct ccp_pci *ccp_pci = ccp->dev_specific;
42 struct device *dev = ccp->dev;
43 struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
44 struct msix_entry msix_entry[MSIX_VECTORS];
45 unsigned int name_len = sizeof(ccp_pci->msix[0].name) - 1;
48 for (v = 0; v < ARRAY_SIZE(msix_entry); v++)
49 msix_entry[v].entry = v;
51 while ((ret = pci_enable_msix(pdev, msix_entry, v)) > 0)
56 ccp_pci->msix_count = v;
57 for (v = 0; v < ccp_pci->msix_count; v++) {
58 /* Set the interrupt names and request the irqs */
59 snprintf(ccp_pci->msix[v].name, name_len, "ccp-%u", v);
60 ccp_pci->msix[v].vector = msix_entry[v].vector;
61 ret = request_irq(ccp_pci->msix[v].vector, ccp_irq_handler,
62 0, ccp_pci->msix[v].name, dev);
64 dev_notice(dev, "unable to allocate MSI-X IRQ (%d)\n",
74 free_irq(ccp_pci->msix[v].vector, dev);
76 pci_disable_msix(pdev);
78 ccp_pci->msix_count = 0;
83 static int ccp_get_msi_irq(struct ccp_device *ccp)
85 struct device *dev = ccp->dev;
86 struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
89 ret = pci_enable_msi(pdev);
93 ret = request_irq(pdev->irq, ccp_irq_handler, 0, "ccp", dev);
95 dev_notice(dev, "unable to allocate MSI IRQ (%d)\n", ret);
102 pci_disable_msi(pdev);
107 static int ccp_get_irqs(struct ccp_device *ccp)
109 struct device *dev = ccp->dev;
112 ret = ccp_get_msix_irqs(ccp);
116 /* Couldn't get MSI-X vectors, try MSI */
117 dev_notice(dev, "could not enable MSI-X (%d), trying MSI\n", ret);
118 ret = ccp_get_msi_irq(ccp);
122 /* Couldn't get MSI interrupt */
123 dev_notice(dev, "could not enable MSI (%d)\n", ret);
128 static void ccp_free_irqs(struct ccp_device *ccp)
130 struct ccp_pci *ccp_pci = ccp->dev_specific;
131 struct device *dev = ccp->dev;
132 struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
134 if (ccp_pci->msix_count) {
135 while (ccp_pci->msix_count--)
136 free_irq(ccp_pci->msix[ccp_pci->msix_count].vector,
138 pci_disable_msix(pdev);
140 free_irq(pdev->irq, dev);
141 pci_disable_msi(pdev);
145 static int ccp_find_mmio_area(struct ccp_device *ccp)
147 struct device *dev = ccp->dev;
148 struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
149 resource_size_t io_len;
150 unsigned long io_flags;
153 io_flags = pci_resource_flags(pdev, IO_BAR);
154 io_len = pci_resource_len(pdev, IO_BAR);
155 if ((io_flags & IORESOURCE_MEM) && (io_len >= (IO_OFFSET + 0x800)))
158 for (bar = 0; bar < PCI_STD_RESOURCE_END; bar++) {
159 io_flags = pci_resource_flags(pdev, bar);
160 io_len = pci_resource_len(pdev, bar);
161 if ((io_flags & IORESOURCE_MEM) &&
162 (io_len >= (IO_OFFSET + 0x800)))
169 static int ccp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
171 struct ccp_device *ccp;
172 struct ccp_pci *ccp_pci;
173 struct device *dev = &pdev->dev;
178 ccp = ccp_alloc_struct(dev);
182 ccp_pci = kzalloc(sizeof(*ccp_pci), GFP_KERNEL);
187 ccp->dev_specific = ccp_pci;
188 ccp->get_irq = ccp_get_irqs;
189 ccp->free_irq = ccp_free_irqs;
191 ret = pci_request_regions(pdev, "ccp");
193 dev_err(dev, "pci_request_regions failed (%d)\n", ret);
197 ret = pci_enable_device(pdev);
199 dev_err(dev, "pci_enable_device failed (%d)\n", ret);
203 pci_set_master(pdev);
205 ret = ccp_find_mmio_area(ccp);
211 ccp->io_map = pci_iomap(pdev, bar, 0);
212 if (ccp->io_map == NULL) {
213 dev_err(dev, "pci_iomap failed\n");
216 ccp->io_regs = ccp->io_map + IO_OFFSET;
218 ret = dma_set_mask(dev, DMA_BIT_MASK(48));
220 ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(48));
223 "pci_set_consistent_dma_mask failed (%d)\n",
228 ret = dma_set_mask(dev, DMA_BIT_MASK(32));
230 dev_err(dev, "pci_set_dma_mask failed (%d)\n", ret);
235 dev_set_drvdata(dev, ccp);
241 dev_notice(dev, "enabled\n");
246 pci_iounmap(pdev, ccp->io_map);
249 pci_disable_device(pdev);
252 pci_release_regions(pdev);
261 dev_notice(dev, "initialization failed\n");
265 static void ccp_pci_remove(struct pci_dev *pdev)
267 struct device *dev = &pdev->dev;
268 struct ccp_device *ccp = dev_get_drvdata(dev);
275 pci_iounmap(pdev, ccp->io_map);
277 pci_disable_device(pdev);
279 pci_release_regions(pdev);
283 dev_notice(dev, "disabled\n");
287 static int ccp_pci_suspend(struct pci_dev *pdev, pm_message_t state)
289 struct device *dev = &pdev->dev;
290 struct ccp_device *ccp = dev_get_drvdata(dev);
294 spin_lock_irqsave(&ccp->cmd_lock, flags);
298 /* Wake all the queue kthreads to prepare for suspend */
299 for (i = 0; i < ccp->cmd_q_count; i++)
300 wake_up_process(ccp->cmd_q[i].kthread);
302 spin_unlock_irqrestore(&ccp->cmd_lock, flags);
304 /* Wait for all queue kthreads to say they're done */
305 while (!ccp_queues_suspended(ccp))
306 wait_event_interruptible(ccp->suspend_queue,
307 ccp_queues_suspended(ccp));
312 static int ccp_pci_resume(struct pci_dev *pdev)
314 struct device *dev = &pdev->dev;
315 struct ccp_device *ccp = dev_get_drvdata(dev);
319 spin_lock_irqsave(&ccp->cmd_lock, flags);
323 /* Wake up all the kthreads */
324 for (i = 0; i < ccp->cmd_q_count; i++) {
325 ccp->cmd_q[i].suspended = 0;
326 wake_up_process(ccp->cmd_q[i].kthread);
329 spin_unlock_irqrestore(&ccp->cmd_lock, flags);
335 static DEFINE_PCI_DEVICE_TABLE(ccp_pci_table) = {
336 { PCI_VDEVICE(AMD, 0x1537), },
337 /* Last entry must be zero */
340 MODULE_DEVICE_TABLE(pci, ccp_pci_table);
342 static struct pci_driver ccp_pci_driver = {
343 .name = "AMD Cryptographic Coprocessor",
344 .id_table = ccp_pci_table,
345 .probe = ccp_pci_probe,
346 .remove = ccp_pci_remove,
348 .suspend = ccp_pci_suspend,
349 .resume = ccp_pci_resume,
353 int ccp_pci_init(void)
355 return pci_register_driver(&ccp_pci_driver);
358 void ccp_pci_exit(void)
360 pci_unregister_driver(&ccp_pci_driver);