]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - drivers/misc/pci_endpoint_test.c
pci-epf-test/pci_endpoint_test: Use irq_type module parameter
[mirror_ubuntu-jammy-kernel.git] / drivers / misc / pci_endpoint_test.c
CommitLineData
2c156ac7
KVA
1/**
2 * Host side test driver to test endpoint functionality
3 *
4 * Copyright (C) 2017 Texas Instruments
5 * Author: Kishon Vijay Abraham I <kishon@ti.com>
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 of
9 * the License as published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include <linux/crc32.h>
21#include <linux/delay.h>
22#include <linux/fs.h>
23#include <linux/io.h>
24#include <linux/interrupt.h>
25#include <linux/irq.h>
26#include <linux/miscdevice.h>
27#include <linux/module.h>
28#include <linux/mutex.h>
29#include <linux/random.h>
30#include <linux/slab.h>
31#include <linux/pci.h>
32#include <linux/pci_ids.h>
33
34#include <linux/pci_regs.h>
35
36#include <uapi/linux/pcitest.h>
37
e8817de7
GP
38#define DRV_MODULE_NAME "pci-endpoint-test"
39
40#define IRQ_TYPE_LEGACY 0
41#define IRQ_TYPE_MSI 1
42
43#define PCI_ENDPOINT_TEST_MAGIC 0x0
44
45#define PCI_ENDPOINT_TEST_COMMAND 0x4
46#define COMMAND_RAISE_LEGACY_IRQ BIT(0)
47#define COMMAND_RAISE_MSI_IRQ BIT(1)
48/* BIT(2) is reserved for raising MSI-X IRQ command */
49#define COMMAND_READ BIT(3)
50#define COMMAND_WRITE BIT(4)
51#define COMMAND_COPY BIT(5)
52
53#define PCI_ENDPOINT_TEST_STATUS 0x8
54#define STATUS_READ_SUCCESS BIT(0)
55#define STATUS_READ_FAIL BIT(1)
56#define STATUS_WRITE_SUCCESS BIT(2)
57#define STATUS_WRITE_FAIL BIT(3)
58#define STATUS_COPY_SUCCESS BIT(4)
59#define STATUS_COPY_FAIL BIT(5)
60#define STATUS_IRQ_RAISED BIT(6)
61#define STATUS_SRC_ADDR_INVALID BIT(7)
62#define STATUS_DST_ADDR_INVALID BIT(8)
63
64#define PCI_ENDPOINT_TEST_LOWER_SRC_ADDR 0x0c
2c156ac7
KVA
65#define PCI_ENDPOINT_TEST_UPPER_SRC_ADDR 0x10
66
67#define PCI_ENDPOINT_TEST_LOWER_DST_ADDR 0x14
68#define PCI_ENDPOINT_TEST_UPPER_DST_ADDR 0x18
69
e8817de7
GP
70#define PCI_ENDPOINT_TEST_SIZE 0x1c
71#define PCI_ENDPOINT_TEST_CHECKSUM 0x20
72
73#define PCI_ENDPOINT_TEST_IRQ_TYPE 0x24
74#define PCI_ENDPOINT_TEST_IRQ_NUMBER 0x28
2c156ac7
KVA
75
76static DEFINE_IDA(pci_endpoint_test_ida);
77
78#define to_endpoint_test(priv) container_of((priv), struct pci_endpoint_test, \
79 miscdev)
0c8a5f9d
KVA
80
81static bool no_msi;
82module_param(no_msi, bool, 0444);
83MODULE_PARM_DESC(no_msi, "Disable MSI interrupt in pci_endpoint_test");
84
9133e394
GP
85static int irq_type = IRQ_TYPE_MSI;
86module_param(irq_type, int, 0444);
87MODULE_PARM_DESC(irq_type, "IRQ mode selection in pci_endpoint_test (0 - Legacy, 1 - MSI)");
88
2c156ac7
KVA
89enum pci_barno {
90 BAR_0,
91 BAR_1,
92 BAR_2,
93 BAR_3,
94 BAR_4,
95 BAR_5,
96};
97
98struct pci_endpoint_test {
99 struct pci_dev *pdev;
100 void __iomem *base;
101 void __iomem *bar[6];
102 struct completion irq_raised;
103 int last_irq;
b7636e81 104 int num_irqs;
2c156ac7
KVA
105 /* mutex to protect the ioctls */
106 struct mutex mutex;
107 struct miscdevice miscdev;
834b9051 108 enum pci_barno test_reg_bar;
13107c60 109 size_t alignment;
2c156ac7
KVA
110};
111
834b9051
KVA
112struct pci_endpoint_test_data {
113 enum pci_barno test_reg_bar;
13107c60 114 size_t alignment;
9133e394 115 int irq_type;
834b9051
KVA
116};
117
2c156ac7
KVA
118static inline u32 pci_endpoint_test_readl(struct pci_endpoint_test *test,
119 u32 offset)
120{
121 return readl(test->base + offset);
122}
123
124static inline void pci_endpoint_test_writel(struct pci_endpoint_test *test,
125 u32 offset, u32 value)
126{
127 writel(value, test->base + offset);
128}
129
130static inline u32 pci_endpoint_test_bar_readl(struct pci_endpoint_test *test,
131 int bar, int offset)
132{
133 return readl(test->bar[bar] + offset);
134}
135
136static inline void pci_endpoint_test_bar_writel(struct pci_endpoint_test *test,
137 int bar, u32 offset, u32 value)
138{
139 writel(value, test->bar[bar] + offset);
140}
141
142static irqreturn_t pci_endpoint_test_irqhandler(int irq, void *dev_id)
143{
144 struct pci_endpoint_test *test = dev_id;
145 u32 reg;
146
147 reg = pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_STATUS);
148 if (reg & STATUS_IRQ_RAISED) {
149 test->last_irq = irq;
150 complete(&test->irq_raised);
151 reg &= ~STATUS_IRQ_RAISED;
152 }
153 pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_STATUS,
154 reg);
155
156 return IRQ_HANDLED;
157}
158
159static bool pci_endpoint_test_bar(struct pci_endpoint_test *test,
160 enum pci_barno barno)
161{
162 int j;
163 u32 val;
164 int size;
cda370ec 165 struct pci_dev *pdev = test->pdev;
2c156ac7
KVA
166
167 if (!test->bar[barno])
168 return false;
169
cda370ec 170 size = pci_resource_len(pdev, barno);
2c156ac7 171
834b9051
KVA
172 if (barno == test->test_reg_bar)
173 size = 0x4;
174
2c156ac7
KVA
175 for (j = 0; j < size; j += 4)
176 pci_endpoint_test_bar_writel(test, barno, j, 0xA0A0A0A0);
177
178 for (j = 0; j < size; j += 4) {
179 val = pci_endpoint_test_bar_readl(test, barno, j);
180 if (val != 0xA0A0A0A0)
181 return false;
182 }
183
184 return true;
185}
186
187static bool pci_endpoint_test_legacy_irq(struct pci_endpoint_test *test)
188{
189 u32 val;
190
e8817de7
GP
191 pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE,
192 IRQ_TYPE_LEGACY);
193 pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, 0);
2c156ac7
KVA
194 pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND,
195 COMMAND_RAISE_LEGACY_IRQ);
196 val = wait_for_completion_timeout(&test->irq_raised,
197 msecs_to_jiffies(1000));
198 if (!val)
199 return false;
200
201 return true;
202}
203
204static bool pci_endpoint_test_msi_irq(struct pci_endpoint_test *test,
205 u8 msi_num)
206{
207 u32 val;
208 struct pci_dev *pdev = test->pdev;
209
e8817de7
GP
210 pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE,
211 IRQ_TYPE_MSI);
212 pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, msi_num);
2c156ac7 213 pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND,
2c156ac7
KVA
214 COMMAND_RAISE_MSI_IRQ);
215 val = wait_for_completion_timeout(&test->irq_raised,
216 msecs_to_jiffies(1000));
217 if (!val)
218 return false;
219
ecc57efe 220 if (pci_irq_vector(pdev, msi_num - 1) == test->last_irq)
2c156ac7
KVA
221 return true;
222
223 return false;
224}
225
226static bool pci_endpoint_test_copy(struct pci_endpoint_test *test, size_t size)
227{
228 bool ret = false;
229 void *src_addr;
230 void *dst_addr;
231 dma_addr_t src_phys_addr;
232 dma_addr_t dst_phys_addr;
233 struct pci_dev *pdev = test->pdev;
234 struct device *dev = &pdev->dev;
13107c60
KVA
235 void *orig_src_addr;
236 dma_addr_t orig_src_phys_addr;
237 void *orig_dst_addr;
238 dma_addr_t orig_dst_phys_addr;
239 size_t offset;
240 size_t alignment = test->alignment;
2c156ac7
KVA
241 u32 src_crc32;
242 u32 dst_crc32;
243
343dc693
DC
244 if (size > SIZE_MAX - alignment)
245 goto err;
246
13107c60
KVA
247 orig_src_addr = dma_alloc_coherent(dev, size + alignment,
248 &orig_src_phys_addr, GFP_KERNEL);
249 if (!orig_src_addr) {
0e52ea61 250 dev_err(dev, "Failed to allocate source buffer\n");
2c156ac7
KVA
251 ret = false;
252 goto err;
253 }
254
13107c60
KVA
255 if (alignment && !IS_ALIGNED(orig_src_phys_addr, alignment)) {
256 src_phys_addr = PTR_ALIGN(orig_src_phys_addr, alignment);
257 offset = src_phys_addr - orig_src_phys_addr;
258 src_addr = orig_src_addr + offset;
259 } else {
260 src_phys_addr = orig_src_phys_addr;
261 src_addr = orig_src_addr;
262 }
263
2c156ac7
KVA
264 pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_LOWER_SRC_ADDR,
265 lower_32_bits(src_phys_addr));
266
267 pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_UPPER_SRC_ADDR,
268 upper_32_bits(src_phys_addr));
269
270 get_random_bytes(src_addr, size);
271 src_crc32 = crc32_le(~0, src_addr, size);
272
13107c60
KVA
273 orig_dst_addr = dma_alloc_coherent(dev, size + alignment,
274 &orig_dst_phys_addr, GFP_KERNEL);
275 if (!orig_dst_addr) {
0e52ea61 276 dev_err(dev, "Failed to allocate destination address\n");
2c156ac7 277 ret = false;
13107c60
KVA
278 goto err_orig_src_addr;
279 }
280
281 if (alignment && !IS_ALIGNED(orig_dst_phys_addr, alignment)) {
282 dst_phys_addr = PTR_ALIGN(orig_dst_phys_addr, alignment);
283 offset = dst_phys_addr - orig_dst_phys_addr;
284 dst_addr = orig_dst_addr + offset;
285 } else {
286 dst_phys_addr = orig_dst_phys_addr;
287 dst_addr = orig_dst_addr;
2c156ac7
KVA
288 }
289
290 pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_LOWER_DST_ADDR,
291 lower_32_bits(dst_phys_addr));
292 pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_UPPER_DST_ADDR,
293 upper_32_bits(dst_phys_addr));
294
295 pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_SIZE,
296 size);
297
9133e394 298 pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE, irq_type);
e8817de7 299 pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, 1);
2c156ac7 300 pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND,
e8817de7 301 COMMAND_COPY);
2c156ac7
KVA
302
303 wait_for_completion(&test->irq_raised);
304
305 dst_crc32 = crc32_le(~0, dst_addr, size);
306 if (dst_crc32 == src_crc32)
307 ret = true;
308
13107c60
KVA
309 dma_free_coherent(dev, size + alignment, orig_dst_addr,
310 orig_dst_phys_addr);
2c156ac7 311
13107c60
KVA
312err_orig_src_addr:
313 dma_free_coherent(dev, size + alignment, orig_src_addr,
314 orig_src_phys_addr);
2c156ac7
KVA
315
316err:
317 return ret;
318}
319
320static bool pci_endpoint_test_write(struct pci_endpoint_test *test, size_t size)
321{
322 bool ret = false;
323 u32 reg;
324 void *addr;
325 dma_addr_t phys_addr;
326 struct pci_dev *pdev = test->pdev;
327 struct device *dev = &pdev->dev;
13107c60
KVA
328 void *orig_addr;
329 dma_addr_t orig_phys_addr;
330 size_t offset;
331 size_t alignment = test->alignment;
2c156ac7
KVA
332 u32 crc32;
333
343dc693
DC
334 if (size > SIZE_MAX - alignment)
335 goto err;
336
13107c60
KVA
337 orig_addr = dma_alloc_coherent(dev, size + alignment, &orig_phys_addr,
338 GFP_KERNEL);
339 if (!orig_addr) {
0e52ea61 340 dev_err(dev, "Failed to allocate address\n");
2c156ac7
KVA
341 ret = false;
342 goto err;
343 }
344
13107c60
KVA
345 if (alignment && !IS_ALIGNED(orig_phys_addr, alignment)) {
346 phys_addr = PTR_ALIGN(orig_phys_addr, alignment);
347 offset = phys_addr - orig_phys_addr;
348 addr = orig_addr + offset;
349 } else {
350 phys_addr = orig_phys_addr;
351 addr = orig_addr;
352 }
353
2c156ac7
KVA
354 get_random_bytes(addr, size);
355
356 crc32 = crc32_le(~0, addr, size);
357 pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_CHECKSUM,
358 crc32);
359
360 pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_LOWER_SRC_ADDR,
361 lower_32_bits(phys_addr));
362 pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_UPPER_SRC_ADDR,
363 upper_32_bits(phys_addr));
364
365 pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_SIZE, size);
366
9133e394 367 pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE, irq_type);
e8817de7 368 pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, 1);
2c156ac7 369 pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND,
e8817de7 370 COMMAND_READ);
2c156ac7
KVA
371
372 wait_for_completion(&test->irq_raised);
373
374 reg = pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_STATUS);
375 if (reg & STATUS_READ_SUCCESS)
376 ret = true;
377
13107c60 378 dma_free_coherent(dev, size + alignment, orig_addr, orig_phys_addr);
2c156ac7
KVA
379
380err:
381 return ret;
382}
383
384static bool pci_endpoint_test_read(struct pci_endpoint_test *test, size_t size)
385{
386 bool ret = false;
387 void *addr;
388 dma_addr_t phys_addr;
389 struct pci_dev *pdev = test->pdev;
390 struct device *dev = &pdev->dev;
13107c60
KVA
391 void *orig_addr;
392 dma_addr_t orig_phys_addr;
393 size_t offset;
394 size_t alignment = test->alignment;
2c156ac7
KVA
395 u32 crc32;
396
343dc693
DC
397 if (size > SIZE_MAX - alignment)
398 goto err;
399
13107c60
KVA
400 orig_addr = dma_alloc_coherent(dev, size + alignment, &orig_phys_addr,
401 GFP_KERNEL);
402 if (!orig_addr) {
0e52ea61 403 dev_err(dev, "Failed to allocate destination address\n");
2c156ac7
KVA
404 ret = false;
405 goto err;
406 }
407
13107c60
KVA
408 if (alignment && !IS_ALIGNED(orig_phys_addr, alignment)) {
409 phys_addr = PTR_ALIGN(orig_phys_addr, alignment);
410 offset = phys_addr - orig_phys_addr;
411 addr = orig_addr + offset;
412 } else {
413 phys_addr = orig_phys_addr;
414 addr = orig_addr;
415 }
416
2c156ac7
KVA
417 pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_LOWER_DST_ADDR,
418 lower_32_bits(phys_addr));
419 pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_UPPER_DST_ADDR,
420 upper_32_bits(phys_addr));
421
422 pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_SIZE, size);
423
9133e394 424 pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE, irq_type);
e8817de7 425 pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, 1);
2c156ac7 426 pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND,
e8817de7 427 COMMAND_WRITE);
2c156ac7
KVA
428
429 wait_for_completion(&test->irq_raised);
430
431 crc32 = crc32_le(~0, addr, size);
432 if (crc32 == pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_CHECKSUM))
433 ret = true;
434
13107c60 435 dma_free_coherent(dev, size + alignment, orig_addr, orig_phys_addr);
2c156ac7
KVA
436err:
437 return ret;
438}
439
440static long pci_endpoint_test_ioctl(struct file *file, unsigned int cmd,
441 unsigned long arg)
442{
443 int ret = -EINVAL;
444 enum pci_barno bar;
445 struct pci_endpoint_test *test = to_endpoint_test(file->private_data);
446
447 mutex_lock(&test->mutex);
448 switch (cmd) {
449 case PCITEST_BAR:
450 bar = arg;
451 if (bar < 0 || bar > 5)
452 goto ret;
453 ret = pci_endpoint_test_bar(test, bar);
454 break;
455 case PCITEST_LEGACY_IRQ:
456 ret = pci_endpoint_test_legacy_irq(test);
457 break;
458 case PCITEST_MSI:
459 ret = pci_endpoint_test_msi_irq(test, arg);
460 break;
461 case PCITEST_WRITE:
462 ret = pci_endpoint_test_write(test, arg);
463 break;
464 case PCITEST_READ:
465 ret = pci_endpoint_test_read(test, arg);
466 break;
467 case PCITEST_COPY:
468 ret = pci_endpoint_test_copy(test, arg);
469 break;
470 }
471
472ret:
473 mutex_unlock(&test->mutex);
474 return ret;
475}
476
477static const struct file_operations pci_endpoint_test_fops = {
478 .owner = THIS_MODULE,
479 .unlocked_ioctl = pci_endpoint_test_ioctl,
480};
481
482static int pci_endpoint_test_probe(struct pci_dev *pdev,
483 const struct pci_device_id *ent)
484{
485 int i;
486 int err;
0b91516a 487 int irq = 0;
2c156ac7
KVA
488 int id;
489 char name[20];
490 enum pci_barno bar;
491 void __iomem *base;
492 struct device *dev = &pdev->dev;
493 struct pci_endpoint_test *test;
834b9051
KVA
494 struct pci_endpoint_test_data *data;
495 enum pci_barno test_reg_bar = BAR_0;
2c156ac7
KVA
496 struct miscdevice *misc_device;
497
498 if (pci_is_bridge(pdev))
499 return -ENODEV;
500
501 test = devm_kzalloc(dev, sizeof(*test), GFP_KERNEL);
502 if (!test)
503 return -ENOMEM;
504
834b9051 505 test->test_reg_bar = 0;
13107c60 506 test->alignment = 0;
2c156ac7 507 test->pdev = pdev;
834b9051 508
9133e394
GP
509 if (no_msi)
510 irq_type = IRQ_TYPE_LEGACY;
511
834b9051 512 data = (struct pci_endpoint_test_data *)ent->driver_data;
13107c60 513 if (data) {
834b9051 514 test_reg_bar = data->test_reg_bar;
13107c60 515 test->alignment = data->alignment;
9133e394 516 irq_type = data->irq_type;
13107c60 517 }
834b9051 518
2c156ac7
KVA
519 init_completion(&test->irq_raised);
520 mutex_init(&test->mutex);
521
522 err = pci_enable_device(pdev);
523 if (err) {
524 dev_err(dev, "Cannot enable PCI device\n");
525 return err;
526 }
527
528 err = pci_request_regions(pdev, DRV_MODULE_NAME);
529 if (err) {
530 dev_err(dev, "Cannot obtain PCI resources\n");
531 goto err_disable_pdev;
532 }
533
534 pci_set_master(pdev);
535
9133e394
GP
536 switch (irq_type) {
537 case IRQ_TYPE_LEGACY:
538 break;
539 case IRQ_TYPE_MSI:
0b91516a
KVA
540 irq = pci_alloc_irq_vectors(pdev, 1, 32, PCI_IRQ_MSI);
541 if (irq < 0)
0e52ea61 542 dev_err(dev, "Failed to get MSI interrupts\n");
b7636e81 543 test->num_irqs = irq;
9133e394
GP
544 break;
545 default:
546 dev_err(dev, "Invalid IRQ type selected\n");
0b91516a 547 }
2c156ac7
KVA
548
549 err = devm_request_irq(dev, pdev->irq, pci_endpoint_test_irqhandler,
550 IRQF_SHARED, DRV_MODULE_NAME, test);
551 if (err) {
0e52ea61 552 dev_err(dev, "Failed to request IRQ %d\n", pdev->irq);
2c156ac7
KVA
553 goto err_disable_msi;
554 }
555
556 for (i = 1; i < irq; i++) {
ecc57efe 557 err = devm_request_irq(dev, pci_irq_vector(pdev, i),
2c156ac7
KVA
558 pci_endpoint_test_irqhandler,
559 IRQF_SHARED, DRV_MODULE_NAME, test);
560 if (err)
561 dev_err(dev, "failed to request IRQ %d for MSI %d\n",
ecc57efe 562 pci_irq_vector(pdev, i), i + 1);
2c156ac7
KVA
563 }
564
565 for (bar = BAR_0; bar <= BAR_5; bar++) {
16b17cad
NC
566 if (pci_resource_flags(pdev, bar) & IORESOURCE_MEM) {
567 base = pci_ioremap_bar(pdev, bar);
568 if (!base) {
0e52ea61 569 dev_err(dev, "Failed to read BAR%d\n", bar);
16b17cad
NC
570 WARN_ON(bar == test_reg_bar);
571 }
572 test->bar[bar] = base;
2c156ac7 573 }
2c156ac7
KVA
574 }
575
834b9051 576 test->base = test->bar[test_reg_bar];
2c156ac7 577 if (!test->base) {
80068c93 578 err = -ENOMEM;
834b9051
KVA
579 dev_err(dev, "Cannot perform PCI test without BAR%d\n",
580 test_reg_bar);
2c156ac7
KVA
581 goto err_iounmap;
582 }
583
584 pci_set_drvdata(pdev, test);
585
586 id = ida_simple_get(&pci_endpoint_test_ida, 0, 0, GFP_KERNEL);
587 if (id < 0) {
80068c93 588 err = id;
0e52ea61 589 dev_err(dev, "Unable to get id\n");
2c156ac7
KVA
590 goto err_iounmap;
591 }
592
593 snprintf(name, sizeof(name), DRV_MODULE_NAME ".%d", id);
594 misc_device = &test->miscdev;
595 misc_device->minor = MISC_DYNAMIC_MINOR;
139838ff
KVA
596 misc_device->name = kstrdup(name, GFP_KERNEL);
597 if (!misc_device->name) {
598 err = -ENOMEM;
599 goto err_ida_remove;
600 }
2c156ac7
KVA
601 misc_device->fops = &pci_endpoint_test_fops,
602
603 err = misc_register(misc_device);
604 if (err) {
0e52ea61 605 dev_err(dev, "Failed to register device\n");
139838ff 606 goto err_kfree_name;
2c156ac7
KVA
607 }
608
609 return 0;
610
139838ff
KVA
611err_kfree_name:
612 kfree(misc_device->name);
613
2c156ac7
KVA
614err_ida_remove:
615 ida_simple_remove(&pci_endpoint_test_ida, id);
616
617err_iounmap:
618 for (bar = BAR_0; bar <= BAR_5; bar++) {
619 if (test->bar[bar])
620 pci_iounmap(pdev, test->bar[bar]);
621 }
622
b7636e81 623 for (i = 0; i < irq; i++)
ecc57efe 624 devm_free_irq(&pdev->dev, pci_irq_vector(pdev, i), test);
b7636e81 625
2c156ac7
KVA
626err_disable_msi:
627 pci_disable_msi(pdev);
628 pci_release_regions(pdev);
629
630err_disable_pdev:
631 pci_disable_device(pdev);
632
633 return err;
634}
635
636static void pci_endpoint_test_remove(struct pci_dev *pdev)
637{
638 int id;
b7636e81 639 int i;
2c156ac7
KVA
640 enum pci_barno bar;
641 struct pci_endpoint_test *test = pci_get_drvdata(pdev);
642 struct miscdevice *misc_device = &test->miscdev;
643
644 if (sscanf(misc_device->name, DRV_MODULE_NAME ".%d", &id) != 1)
645 return;
a2db2663
DC
646 if (id < 0)
647 return;
2c156ac7
KVA
648
649 misc_deregister(&test->miscdev);
139838ff 650 kfree(misc_device->name);
2c156ac7
KVA
651 ida_simple_remove(&pci_endpoint_test_ida, id);
652 for (bar = BAR_0; bar <= BAR_5; bar++) {
653 if (test->bar[bar])
654 pci_iounmap(pdev, test->bar[bar]);
655 }
b7636e81 656 for (i = 0; i < test->num_irqs; i++)
ecc57efe 657 devm_free_irq(&pdev->dev, pci_irq_vector(pdev, i), test);
2c156ac7
KVA
658 pci_disable_msi(pdev);
659 pci_release_regions(pdev);
660 pci_disable_device(pdev);
661}
662
663static const struct pci_device_id pci_endpoint_test_tbl[] = {
664 { PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_DRA74x) },
665 { PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_DRA72x) },
14b06ddd 666 { PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS, 0xedda) },
2c156ac7
KVA
667 { }
668};
669MODULE_DEVICE_TABLE(pci, pci_endpoint_test_tbl);
670
671static struct pci_driver pci_endpoint_test_driver = {
672 .name = DRV_MODULE_NAME,
673 .id_table = pci_endpoint_test_tbl,
674 .probe = pci_endpoint_test_probe,
675 .remove = pci_endpoint_test_remove,
676};
677module_pci_driver(pci_endpoint_test_driver);
678
679MODULE_DESCRIPTION("PCI ENDPOINT TEST HOST DRIVER");
680MODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>");
681MODULE_LICENSE("GPL v2");