aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/dma/ioat.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/dma/ioat.c')
-rw-r--r--drivers/dma/ioat.c196
1 files changed, 196 insertions, 0 deletions
diff --git a/drivers/dma/ioat.c b/drivers/dma/ioat.c
new file mode 100644
index 000000000000..ae5817bfc015
--- /dev/null
+++ b/drivers/dma/ioat.c
@@ -0,0 +1,196 @@
1/*
2 * Intel I/OAT DMA Linux driver
3 * Copyright(c) 2004 - 2007 Intel Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
17 *
18 * The full GNU General Public License is included in this distribution in
19 * the file called "COPYING".
20 *
21 */
22
23/*
24 * This driver supports an Intel I/OAT DMA engine, which does asynchronous
25 * copy operations.
26 */
27
28#include <linux/init.h>
29#include <linux/module.h>
30#include <linux/pci.h>
31#include <linux/interrupt.h>
32#include "ioatdma.h"
33#include "ioatdma_registers.h"
34#include "ioatdma_hw.h"
35
36MODULE_VERSION("1.24");
37MODULE_LICENSE("GPL");
38MODULE_AUTHOR("Intel Corporation");
39
40static struct pci_device_id ioat_pci_tbl[] = {
41 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT) },
42 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_CNB) },
43 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_SCNB) },
44 { PCI_DEVICE(PCI_VENDOR_ID_UNISYS, PCI_DEVICE_ID_UNISYS_DMA_DIRECTOR) },
45 { 0, }
46};
47
48struct ioat_device {
49 struct pci_dev *pdev;
50 void __iomem *iobase;
51 struct ioatdma_device *dma;
52};
53
54static int __devinit ioat_probe(struct pci_dev *pdev,
55 const struct pci_device_id *id);
56#ifdef IOAT_DMA_REMOVE
57static void __devexit ioat_remove(struct pci_dev *pdev);
58#endif
59
60static int ioat_setup_functionality(struct pci_dev *pdev, void __iomem *iobase)
61{
62 struct ioat_device *device = pci_get_drvdata(pdev);
63 u8 version;
64 int err = 0;
65
66 version = readb(iobase + IOAT_VER_OFFSET);
67 switch (version) {
68 case IOAT_VER_1_2:
69 device->dma = ioat_dma_probe(pdev, iobase);
70 break;
71 default:
72 err = -ENODEV;
73 break;
74 }
75 return err;
76}
77
78static void ioat_shutdown_functionality(struct pci_dev *pdev)
79{
80 struct ioat_device *device = pci_get_drvdata(pdev);
81
82 if (device->dma) {
83 ioat_dma_remove(device->dma);
84 device->dma = NULL;
85 }
86}
87
88static struct pci_driver ioat_pci_drv = {
89 .name = "ioatdma",
90 .id_table = ioat_pci_tbl,
91 .probe = ioat_probe,
92 .shutdown = ioat_shutdown_functionality,
93#ifdef IOAT_DMA_REMOVE
94 .remove = __devexit_p(ioat_remove),
95#endif
96};
97
98static int __devinit ioat_probe(struct pci_dev *pdev,
99 const struct pci_device_id *id)
100{
101 void __iomem *iobase;
102 struct ioat_device *device;
103 unsigned long mmio_start, mmio_len;
104 int err;
105
106 err = pci_enable_device(pdev);
107 if (err)
108 goto err_enable_device;
109
110 err = pci_request_regions(pdev, ioat_pci_drv.name);
111 if (err)
112 goto err_request_regions;
113
114 err = pci_set_dma_mask(pdev, DMA_64BIT_MASK);
115 if (err)
116 err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
117 if (err)
118 goto err_set_dma_mask;
119
120 err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
121 if (err)
122 err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
123 if (err)
124 goto err_set_dma_mask;
125
126 mmio_start = pci_resource_start(pdev, 0);
127 mmio_len = pci_resource_len(pdev, 0);
128 iobase = ioremap(mmio_start, mmio_len);
129 if (!iobase) {
130 err = -ENOMEM;
131 goto err_ioremap;
132 }
133
134 device = kzalloc(sizeof(*device), GFP_KERNEL);
135 if (!device) {
136 err = -ENOMEM;
137 goto err_kzalloc;
138 }
139 device->pdev = pdev;
140 pci_set_drvdata(pdev, device);
141 device->iobase = iobase;
142
143 pci_set_master(pdev);
144
145 err = ioat_setup_functionality(pdev, iobase);
146 if (err)
147 goto err_version;
148
149 return 0;
150
151err_version:
152 kfree(device);
153err_kzalloc:
154 iounmap(iobase);
155err_ioremap:
156err_set_dma_mask:
157 pci_release_regions(pdev);
158 pci_disable_device(pdev);
159err_request_regions:
160err_enable_device:
161 return err;
162}
163
164#ifdef IOAT_DMA_REMOVE
165/*
166 * It is unsafe to remove this module: if removed while a requested
167 * dma is outstanding, esp. from tcp, it is possible to hang while
168 * waiting for something that will never finish, thus hanging at
169 * least one cpu. However, if you're feeling lucky and need to do
170 * some testing, this usually works just fine.
171 */
172static void __devexit ioat_remove(struct pci_dev *pdev)
173{
174 struct ioat_device *device = pci_get_drvdata(pdev);
175
176 ioat_shutdown_functionality(pdev);
177
178 kfree(device);
179
180 iounmap(device->iobase);
181 pci_release_regions(pdev);
182 pci_disable_device(pdev);
183}
184#endif
185
186static int __init ioat_init_module(void)
187{
188 return pci_register_driver(&ioat_pci_drv);
189}
190module_init(ioat_init_module);
191
192static void __exit ioat_exit_module(void)
193{
194 pci_unregister_driver(&ioat_pci_drv);
195}
196module_exit(ioat_exit_module);