Merge branch 'core-objtool-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-block.git] / drivers / staging / kpc2000 / kpc2000 / core.c
CommitLineData
7dc7967f 1// SPDX-License-Identifier: GPL-2.0+
bdd4a571 2#include <linux/kernel.h>
f7315408 3#include <linux/idr.h>
7dc7967f
GKH
4#include <linux/init.h>
5#include <linux/module.h>
6#include <linux/pci.h>
7#include <linux/types.h>
8#include <linux/export.h>
9#include <linux/slab.h>
bdd4a571
GKH
10#include <linux/fs.h>
11#include <linux/errno.h>
12#include <linux/cdev.h>
13#include <linux/rwsem.h>
14#include <linux/uaccess.h>
7dc7967f
GKH
15#include <linux/io.h>
16#include <linux/mfd/core.h>
17#include <linux/platform_device.h>
18#include <linux/ioport.h>
91b6cb72 19#include <linux/io-64-nonatomic-lo-hi.h>
7dc7967f
GKH
20#include <linux/interrupt.h>
21#include <linux/workqueue.h>
22#include <linux/device.h>
23#include <linux/sched.h>
24#include <linux/jiffies.h>
25#include "pcie.h"
bdd4a571 26#include "uapi.h"
7dc7967f 27
f7315408
JS
28static DEFINE_IDA(card_num_ida);
29
7dc7967f 30/*******************************************************
d8ac3593
JS
31 * SysFS Attributes
32 ******************************************************/
33
80bcd6cc 34static ssize_t ssid_show(struct device *dev, struct device_attribute *attr,
a986d796
JS
35 char *buf)
36{
e416dad1 37 struct kp2000_device *pcard = dev_get_drvdata(dev);
a986d796 38
80bcd6cc
JS
39 return sprintf(buf, "%016llx\n", pcard->ssid);
40}
41static DEVICE_ATTR_RO(ssid);
d8ac3593 42
80bcd6cc
JS
43static ssize_t ddna_show(struct device *dev, struct device_attribute *attr,
44 char *buf)
45{
e416dad1 46 struct kp2000_device *pcard = dev_get_drvdata(dev);
d8ac3593 47
80bcd6cc
JS
48 return sprintf(buf, "%016llx\n", pcard->ddna);
49}
50static DEVICE_ATTR_RO(ddna);
51
52static ssize_t card_id_show(struct device *dev, struct device_attribute *attr,
53 char *buf)
54{
e416dad1 55 struct kp2000_device *pcard = dev_get_drvdata(dev);
d8ac3593 56
80bcd6cc
JS
57 return sprintf(buf, "%08x\n", pcard->card_id);
58}
59static DEVICE_ATTR_RO(card_id);
d8ac3593 60
80bcd6cc
JS
61static ssize_t hw_rev_show(struct device *dev, struct device_attribute *attr,
62 char *buf)
63{
e416dad1 64 struct kp2000_device *pcard = dev_get_drvdata(dev);
d8ac3593 65
80bcd6cc 66 return sprintf(buf, "%08x\n", pcard->hardware_revision);
7dc7967f 67}
80bcd6cc 68static DEVICE_ATTR_RO(hw_rev);
7dc7967f 69
80bcd6cc
JS
70static ssize_t build_show(struct device *dev, struct device_attribute *attr,
71 char *buf)
72{
e416dad1 73 struct kp2000_device *pcard = dev_get_drvdata(dev);
80bcd6cc 74
80bcd6cc
JS
75 return sprintf(buf, "%08x\n", pcard->build_version);
76}
77static DEVICE_ATTR_RO(build);
78
79static ssize_t build_date_show(struct device *dev,
80 struct device_attribute *attr, char *buf)
81{
e416dad1 82 struct kp2000_device *pcard = dev_get_drvdata(dev);
80bcd6cc 83
80bcd6cc
JS
84 return sprintf(buf, "%08x\n", pcard->build_datestamp);
85}
86static DEVICE_ATTR_RO(build_date);
87
88static ssize_t build_time_show(struct device *dev,
89 struct device_attribute *attr, char *buf)
90{
e416dad1 91 struct kp2000_device *pcard = dev_get_drvdata(dev);
80bcd6cc 92
80bcd6cc
JS
93 return sprintf(buf, "%08x\n", pcard->build_timestamp);
94}
95static DEVICE_ATTR_RO(build_time);
96
97static ssize_t cpld_reg_show(struct device *dev, struct device_attribute *attr,
98 char *buf)
7dc7967f 99{
e416dad1 100 struct kp2000_device *pcard = dev_get_drvdata(dev);
7dc7967f
GKH
101 u64 val;
102
7dc7967f 103 val = readq(pcard->sysinfo_regs_base + REG_CPLD_CONFIG);
80bcd6cc 104 return sprintf(buf, "%016llx\n", val);
7dc7967f 105}
80bcd6cc 106static DEVICE_ATTR_RO(cpld_reg);
d8ac3593
JS
107
108static ssize_t cpld_reconfigure(struct device *dev,
109 struct device_attribute *attr,
110 const char *buf, size_t count)
7dc7967f 111{
e416dad1 112 struct kp2000_device *pcard = dev_get_drvdata(dev);
72db61d7 113 unsigned long wr_val;
d8ac3593
JS
114 int rv;
115
72db61d7 116 rv = kstrtoul(buf, 0, &wr_val);
d8ac3593
JS
117 if (rv < 0)
118 return rv;
119 if (wr_val > 7)
120 return -EINVAL;
7dc7967f 121
d8ac3593
JS
122 wr_val = wr_val << 8;
123 wr_val |= 0x1; // Set the "Configure Go" bit
124 writeq(wr_val, pcard->sysinfo_regs_base + REG_CPLD_CONFIG);
125 return count;
126}
80bcd6cc 127static DEVICE_ATTR(cpld_reconfigure, 0220, NULL, cpld_reconfigure);
7dc7967f 128
eb1a5c64
JS
129static ssize_t irq_mask_reg_show(struct device *dev,
130 struct device_attribute *attr, char *buf)
131{
132 struct kp2000_device *pcard = dev_get_drvdata(dev);
133 u64 val;
134
135 val = readq(pcard->sysinfo_regs_base + REG_INTERRUPT_MASK);
136 return sprintf(buf, "%016llx\n", val);
137}
138static DEVICE_ATTR_RO(irq_mask_reg);
139
140static ssize_t irq_active_reg_show(struct device *dev,
141 struct device_attribute *attr, char *buf)
142{
143 struct kp2000_device *pcard = dev_get_drvdata(dev);
144 u64 val;
145
146 val = readq(pcard->sysinfo_regs_base + REG_INTERRUPT_ACTIVE);
147 return sprintf(buf, "%016llx\n", val);
148}
149static DEVICE_ATTR_RO(irq_active_reg);
150
151static ssize_t pcie_error_count_reg_show(struct device *dev,
152 struct device_attribute *attr,
153 char *buf)
154{
155 struct kp2000_device *pcard = dev_get_drvdata(dev);
156 u64 val;
157
158 val = readq(pcard->sysinfo_regs_base + REG_PCIE_ERROR_COUNT);
159 return sprintf(buf, "%016llx\n", val);
160}
161static DEVICE_ATTR_RO(pcie_error_count_reg);
162
163static ssize_t core_table_offset_show(struct device *dev,
164 struct device_attribute *attr, char *buf)
165{
166 struct kp2000_device *pcard = dev_get_drvdata(dev);
167
168 return sprintf(buf, "%08x\n", pcard->core_table_offset);
169}
170static DEVICE_ATTR_RO(core_table_offset);
171
172static ssize_t core_table_length_show(struct device *dev,
173 struct device_attribute *attr, char *buf)
174{
175 struct kp2000_device *pcard = dev_get_drvdata(dev);
176
177 return sprintf(buf, "%08x\n", pcard->core_table_length);
178}
179static DEVICE_ATTR_RO(core_table_length);
180
d8ac3593
JS
181static const struct attribute *kp_attr_list[] = {
182 &dev_attr_ssid.attr,
183 &dev_attr_ddna.attr,
184 &dev_attr_card_id.attr,
185 &dev_attr_hw_rev.attr,
186 &dev_attr_build.attr,
187 &dev_attr_build_date.attr,
188 &dev_attr_build_time.attr,
189 &dev_attr_cpld_reg.attr,
190 &dev_attr_cpld_reconfigure.attr,
eb1a5c64
JS
191 &dev_attr_irq_mask_reg.attr,
192 &dev_attr_irq_active_reg.attr,
193 &dev_attr_pcie_error_count_reg.attr,
194 &dev_attr_core_table_offset.attr,
195 &dev_attr_core_table_length.attr,
d8ac3593 196 NULL,
7dc7967f
GKH
197};
198
7dc7967f 199/*******************************************************
d8ac3593
JS
200 * Functions
201 ******************************************************/
7dc7967f
GKH
202
203static void wait_and_read_ssid(struct kp2000_device *pcard)
204{
d8ac3593
JS
205 u64 read_val = readq(pcard->sysinfo_regs_base + REG_FPGA_SSID);
206 unsigned long timeout;
207
f08ab0ab 208 if (read_val & 0x8000000000000000UL) {
d8ac3593
JS
209 pcard->ssid = read_val;
210 return;
211 }
212
213 timeout = jiffies + (HZ * 2);
214 do {
215 read_val = readq(pcard->sysinfo_regs_base + REG_FPGA_SSID);
f08ab0ab 216 if (read_val & 0x8000000000000000UL) {
d8ac3593
JS
217 pcard->ssid = read_val;
218 return;
219 }
220 cpu_relax();
221 //schedule();
222 } while (time_before(jiffies, timeout));
223
224 dev_notice(&pcard->pdev->dev, "SSID didn't show up!\n");
225
d8ac3593
JS
226 // Timed out waiting for the SSID to show up, stick all zeros in the
227 // value
228 pcard->ssid = 0;
7dc7967f
GKH
229}
230
231static int read_system_regs(struct kp2000_device *pcard)
232{
d8ac3593
JS
233 u64 read_val;
234
235 read_val = readq(pcard->sysinfo_regs_base + REG_MAGIC_NUMBER);
236 if (read_val != KP2000_MAGIC_VALUE) {
237 dev_err(&pcard->pdev->dev,
89a237aa 238 "Invalid magic! Got: 0x%016llx Want: 0x%016llx\n",
d8ac3593
JS
239 read_val, KP2000_MAGIC_VALUE);
240 return -EILSEQ;
241 }
242
243 read_val = readq(pcard->sysinfo_regs_base + REG_CARD_ID_AND_BUILD);
f08ab0ab
HJ
244 pcard->card_id = (read_val & 0xFFFFFFFF00000000UL) >> 32;
245 pcard->build_version = (read_val & 0x00000000FFFFFFFFUL) >> 0;
d8ac3593
JS
246
247 read_val = readq(pcard->sysinfo_regs_base + REG_DATE_AND_TIME_STAMPS);
f08ab0ab
HJ
248 pcard->build_datestamp = (read_val & 0xFFFFFFFF00000000UL) >> 32;
249 pcard->build_timestamp = (read_val & 0x00000000FFFFFFFFUL) >> 0;
d8ac3593
JS
250
251 read_val = readq(pcard->sysinfo_regs_base + REG_CORE_TABLE_OFFSET);
f08ab0ab
HJ
252 pcard->core_table_length = (read_val & 0xFFFFFFFF00000000UL) >> 32;
253 pcard->core_table_offset = (read_val & 0x00000000FFFFFFFFUL) >> 0;
d8ac3593
JS
254
255 wait_and_read_ssid(pcard);
256
257 read_val = readq(pcard->sysinfo_regs_base + REG_FPGA_HW_ID);
258 pcard->core_table_rev = (read_val & 0x0000000000000F00) >> 8;
259 pcard->hardware_revision = (read_val & 0x000000000000001F);
260
261 read_val = readq(pcard->sysinfo_regs_base + REG_FPGA_DDNA);
262 pcard->ddna = read_val;
263
264 dev_info(&pcard->pdev->dev,
265 "system_regs: %08x %08x %08x %08x %02x %d %d %016llx %016llx\n",
266 pcard->card_id,
267 pcard->build_version,
268 pcard->build_datestamp,
269 pcard->build_timestamp,
270 pcard->hardware_revision,
271 pcard->core_table_rev,
272 pcard->core_table_length,
273 pcard->ssid,
274 pcard->ddna);
275
276 if (pcard->core_table_rev > 1) {
277 dev_err(&pcard->pdev->dev,
278 "core table entry revision is higher than we can deal with, cannot continue with this card!\n");
279 return 1;
280 }
281
282 return 0;
7dc7967f
GKH
283}
284
6bcd56b7 285static irqreturn_t kp2000_irq_handler(int irq, void *dev_id)
7dc7967f 286{
6bcd56b7
GKH
287 struct kp2000_device *pcard = dev_id;
288
289 writel(KPC_DMA_CARD_IRQ_ENABLE |
290 KPC_DMA_CARD_USER_INTERRUPT_MODE |
291 KPC_DMA_CARD_USER_INTERRUPT_ACTIVE,
292 pcard->dma_common_regs);
293 return IRQ_HANDLED;
7dc7967f
GKH
294}
295
92642f38
GKH
296static int kp2000_pcie_probe(struct pci_dev *pdev,
297 const struct pci_device_id *id)
7dc7967f 298{
d8ac3593
JS
299 int err = 0;
300 struct kp2000_device *pcard;
d8ac3593
JS
301 int rv;
302 unsigned long reg_bar_phys_addr;
303 unsigned long reg_bar_phys_len;
304 unsigned long dma_bar_phys_addr;
305 unsigned long dma_bar_phys_len;
306 u16 regval;
307
a1ceab8b 308 pcard = kzalloc(sizeof(*pcard), GFP_KERNEL);
5298be48 309 if (!pcard)
d8ac3593 310 return -ENOMEM;
d8ac3593
JS
311 dev_dbg(&pdev->dev, "probe: allocated struct kp2000_device @ %p\n",
312 pcard);
313
f7315408
JS
314 err = ida_simple_get(&card_num_ida, 1, INT_MAX, GFP_KERNEL);
315 if (err < 0) {
316 dev_err(&pdev->dev, "probe: failed to get card number (%d)\n",
317 err);
fd5a82f4 318 goto err_free_pcard;
f7315408
JS
319 }
320 pcard->card_num = err;
321 scnprintf(pcard->name, 16, "kpcard%u", pcard->card_num);
d8ac3593
JS
322
323 mutex_init(&pcard->sem);
276accf2 324 mutex_lock(&pcard->sem);
2f9dcc46 325
d8ac3593
JS
326 pcard->pdev = pdev;
327 pci_set_drvdata(pdev, pcard);
328
d8ac3593
JS
329 err = pci_enable_device(pcard->pdev);
330 if (err) {
331 dev_err(&pcard->pdev->dev,
332 "probe: failed to enable PCIE2000 PCIe device (%d)\n",
333 err);
fd5a82f4 334 goto err_remove_ida;
d8ac3593
JS
335 }
336
eafae15f 337 /* Setup the Register BAR */
d8ac3593
JS
338 reg_bar_phys_addr = pci_resource_start(pcard->pdev, REG_BAR);
339 reg_bar_phys_len = pci_resource_len(pcard->pdev, REG_BAR);
340
4bdc0d67 341 pcard->regs_bar_base = ioremap(reg_bar_phys_addr, PAGE_SIZE);
636928fc 342 if (!pcard->regs_bar_base) {
d8ac3593
JS
343 dev_err(&pcard->pdev->dev,
344 "probe: REG_BAR could not remap memory to virtual space\n");
345 err = -ENODEV;
fd5a82f4 346 goto err_disable_device;
d8ac3593
JS
347 }
348 dev_dbg(&pcard->pdev->dev,
349 "probe: REG_BAR virt hardware address start [%p]\n",
350 pcard->regs_bar_base);
351
352 err = pci_request_region(pcard->pdev, REG_BAR, KP_DRIVER_NAME_KP2000);
353 if (err) {
d8ac3593
JS
354 dev_err(&pcard->pdev->dev,
355 "probe: failed to acquire PCI region (%d)\n",
356 err);
357 err = -ENODEV;
a50185cb 358 goto err_unmap_regs;
d8ac3593
JS
359 }
360
361 pcard->regs_base_resource.start = reg_bar_phys_addr;
362 pcard->regs_base_resource.end = reg_bar_phys_addr +
363 reg_bar_phys_len - 1;
364 pcard->regs_base_resource.flags = IORESOURCE_MEM;
365
eafae15f 366 /* Setup the DMA BAR */
d8ac3593
JS
367 dma_bar_phys_addr = pci_resource_start(pcard->pdev, DMA_BAR);
368 dma_bar_phys_len = pci_resource_len(pcard->pdev, DMA_BAR);
369
4bdc0d67 370 pcard->dma_bar_base = ioremap(dma_bar_phys_addr,
d8ac3593 371 dma_bar_phys_len);
636928fc 372 if (!pcard->dma_bar_base) {
d8ac3593
JS
373 dev_err(&pcard->pdev->dev,
374 "probe: DMA_BAR could not remap memory to virtual space\n");
375 err = -ENODEV;
a50185cb 376 goto err_release_regs;
d8ac3593
JS
377 }
378 dev_dbg(&pcard->pdev->dev,
379 "probe: DMA_BAR virt hardware address start [%p]\n",
380 pcard->dma_bar_base);
381
382 pcard->dma_common_regs = pcard->dma_bar_base + KPC_DMA_COMMON_OFFSET;
383
384 err = pci_request_region(pcard->pdev, DMA_BAR, "kp2000_pcie");
385 if (err) {
d8ac3593
JS
386 dev_err(&pcard->pdev->dev,
387 "probe: failed to acquire PCI region (%d)\n", err);
388 err = -ENODEV;
a50185cb 389 goto err_unmap_dma;
d8ac3593
JS
390 }
391
392 pcard->dma_base_resource.start = dma_bar_phys_addr;
393 pcard->dma_base_resource.end = dma_bar_phys_addr +
394 dma_bar_phys_len - 1;
395 pcard->dma_base_resource.flags = IORESOURCE_MEM;
396
eafae15f 397 /* Read System Regs */
d8ac3593
JS
398 pcard->sysinfo_regs_base = pcard->regs_bar_base;
399 err = read_system_regs(pcard);
400 if (err)
a50185cb 401 goto err_release_dma;
d8ac3593
JS
402
403 // Disable all "user" interrupts because they're not used yet.
f08ab0ab 404 writeq(0xFFFFFFFFFFFFFFFFUL,
d8ac3593
JS
405 pcard->sysinfo_regs_base + REG_INTERRUPT_MASK);
406
d8ac3593
JS
407 // let the card master PCIe
408 pci_set_master(pcard->pdev);
eafae15f 409
d8ac3593
JS
410 // enable IO and mem if not already done
411 pci_read_config_word(pcard->pdev, PCI_COMMAND, &regval);
412 regval |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
413 pci_write_config_word(pcard->pdev, PCI_COMMAND, regval);
414
415 // Clear relaxed ordering bit
416 pcie_capability_clear_and_set_word(pcard->pdev, PCI_EXP_DEVCTL,
417 PCI_EXP_DEVCTL_RELAX_EN, 0);
418
419 // Set Max_Payload_Size and Max_Read_Request_Size
420 regval = (0x0) << 5; // Max_Payload_Size = 128 B
421 pcie_capability_clear_and_set_word(pcard->pdev, PCI_EXP_DEVCTL,
422 PCI_EXP_DEVCTL_PAYLOAD, regval);
423 regval = (0x0) << 12; // Max_Read_Request_Size = 128 B
424 pcie_capability_clear_and_set_word(pcard->pdev, PCI_EXP_DEVCTL,
425 PCI_EXP_DEVCTL_READRQ, regval);
426
427 // Enable error reporting for: Correctable Errors, Non-Fatal Errors,
428 // Fatal Errors, Unsupported Requests
429 pcie_capability_clear_and_set_word(pcard->pdev, PCI_EXP_DEVCTL, 0,
430 PCI_EXP_DEVCTL_CERE |
431 PCI_EXP_DEVCTL_NFERE |
432 PCI_EXP_DEVCTL_FERE |
433 PCI_EXP_DEVCTL_URRE);
434
435 err = dma_set_mask(PCARD_TO_DEV(pcard), DMA_BIT_MASK(64));
436 if (err) {
437 dev_err(&pcard->pdev->dev,
438 "CANNOT use DMA mask %0llx\n", DMA_BIT_MASK(64));
a50185cb 439 goto err_release_dma;
d8ac3593
JS
440 }
441 dev_dbg(&pcard->pdev->dev,
442 "Using DMA mask %0llx\n", dma_get_mask(PCARD_TO_DEV(pcard)));
443
d8ac3593
JS
444 err = pci_enable_msi(pcard->pdev);
445 if (err < 0)
a50185cb 446 goto err_release_dma;
d8ac3593
JS
447
448 rv = request_irq(pcard->pdev->irq, kp2000_irq_handler, IRQF_SHARED,
449 pcard->name, pcard);
450 if (rv) {
451 dev_err(&pcard->pdev->dev,
745cde4e 452 "%s: failed to request_irq: %d\n", __func__, rv);
fd5a82f4 453 goto err_disable_msi;
d8ac3593
JS
454 }
455
1c10f069 456 err = sysfs_create_files(&pdev->dev.kobj, kp_attr_list);
d8ac3593
JS
457 if (err) {
458 dev_err(&pdev->dev, "Failed to add sysfs files: %d\n", err);
fd5a82f4 459 goto err_free_irq;
d8ac3593
JS
460 }
461
d8ac3593
JS
462 err = kp2000_probe_cores(pcard);
463 if (err)
fd5a82f4 464 goto err_remove_sysfs;
d8ac3593 465
eafae15f 466 /* Enable IRQs in HW */
6bcd56b7
GKH
467 writel(KPC_DMA_CARD_IRQ_ENABLE | KPC_DMA_CARD_USER_INTERRUPT_MODE,
468 pcard->dma_common_regs);
2f9dcc46 469
276accf2 470 mutex_unlock(&pcard->sem);
d8ac3593
JS
471 return 0;
472
fd5a82f4 473err_remove_sysfs:
1c10f069 474 sysfs_remove_files(&pdev->dev.kobj, kp_attr_list);
fd5a82f4 475err_free_irq:
d8ac3593 476 free_irq(pcard->pdev->irq, pcard);
fd5a82f4 477err_disable_msi:
d8ac3593 478 pci_disable_msi(pcard->pdev);
a50185cb
SS
479err_release_dma:
480 pci_release_region(pdev, DMA_BAR);
fd5a82f4 481err_unmap_dma:
d8ac3593 482 iounmap(pcard->dma_bar_base);
a50185cb
SS
483err_release_regs:
484 pci_release_region(pdev, REG_BAR);
fd5a82f4 485err_unmap_regs:
d8ac3593 486 iounmap(pcard->regs_bar_base);
fd5a82f4 487err_disable_device:
d8ac3593 488 pci_disable_device(pcard->pdev);
fd5a82f4 489err_remove_ida:
276accf2 490 mutex_unlock(&pcard->sem);
f7315408 491 ida_simple_remove(&card_num_ida, pcard->card_num);
fd5a82f4 492err_free_pcard:
d8ac3593
JS
493 kfree(pcard);
494 return err;
7dc7967f
GKH
495}
496
92642f38 497static void kp2000_pcie_remove(struct pci_dev *pdev)
7dc7967f 498{
d8ac3593 499 struct kp2000_device *pcard = pci_get_drvdata(pdev);
7dc7967f 500
636928fc 501 if (!pcard)
d8ac3593 502 return;
2f9dcc46 503
276accf2 504 mutex_lock(&pcard->sem);
d8ac3593
JS
505 kp2000_remove_cores(pcard);
506 mfd_remove_devices(PCARD_TO_DEV(pcard));
1c10f069 507 sysfs_remove_files(&pdev->dev.kobj, kp_attr_list);
d8ac3593
JS
508 free_irq(pcard->pdev->irq, pcard);
509 pci_disable_msi(pcard->pdev);
636928fc 510 if (pcard->dma_bar_base) {
d8ac3593
JS
511 iounmap(pcard->dma_bar_base);
512 pci_release_region(pdev, DMA_BAR);
513 pcard->dma_bar_base = NULL;
514 }
636928fc 515 if (pcard->regs_bar_base) {
d8ac3593
JS
516 iounmap(pcard->regs_bar_base);
517 pci_release_region(pdev, REG_BAR);
518 pcard->regs_bar_base = NULL;
519 }
520 pci_disable_device(pcard->pdev);
521 pci_set_drvdata(pdev, NULL);
276accf2 522 mutex_unlock(&pcard->sem);
f7315408 523 ida_simple_remove(&card_num_ida, pcard->card_num);
d8ac3593 524 kfree(pcard);
7dc7967f 525}
92642f38
GKH
526
527struct class *kpc_uio_class;
528ATTRIBUTE_GROUPS(kpc_uio_class);
529
530static const struct pci_device_id kp2000_pci_device_ids[] = {
531 { PCI_DEVICE(PCI_VENDOR_ID_DAKTRONICS, PCI_DEVICE_ID_DAKTRONICS) },
532 { PCI_DEVICE(PCI_VENDOR_ID_DAKTRONICS, PCI_DEVICE_ID_DAKTRONICS_KADOKA_P2KR0) },
533 { 0, }
534};
535MODULE_DEVICE_TABLE(pci, kp2000_pci_device_ids);
536
537static struct pci_driver kp2000_driver_inst = {
538 .name = "kp2000_pcie",
539 .id_table = kp2000_pci_device_ids,
540 .probe = kp2000_pcie_probe,
541 .remove = kp2000_pcie_remove,
542};
543
8dd3355a 544static int __init kp2000_pcie_init(void)
92642f38
GKH
545{
546 kpc_uio_class = class_create(THIS_MODULE, "kpc_uio");
547 if (IS_ERR(kpc_uio_class))
548 return PTR_ERR(kpc_uio_class);
549
550 kpc_uio_class->dev_groups = kpc_uio_class_groups;
551 return pci_register_driver(&kp2000_driver_inst);
552}
553module_init(kp2000_pcie_init);
554
8dd3355a 555static void __exit kp2000_pcie_exit(void)
92642f38
GKH
556{
557 pci_unregister_driver(&kp2000_driver_inst);
558 class_destroy(kpc_uio_class);
f7315408 559 ida_destroy(&card_num_ida);
92642f38
GKH
560}
561module_exit(kp2000_pcie_exit);
562
563MODULE_LICENSE("GPL");
564MODULE_AUTHOR("Lee.Brooke@Daktronics.com, Matt.Sickler@Daktronics.com");
565MODULE_SOFTDEP("pre: uio post: kpc_nwl_dma kpc_i2c kpc_spi");