2 * Host side test driver to test endpoint functionality
4 * Copyright (C) 2017 Texas Instruments
5 * Author: Kishon Vijay Abraham I <kishon@ti.com>
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.
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.
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/>.
20 #include <linux/crc32.h>
21 #include <linux/delay.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>
34 #include <linux/pci_regs.h>
36 #include <uapi/linux/pcitest.h>
38 #define DRV_MODULE_NAME "pci-endpoint-test"
40 #define PCI_ENDPOINT_TEST_MAGIC 0x0
42 #define PCI_ENDPOINT_TEST_COMMAND 0x4
43 #define COMMAND_RAISE_LEGACY_IRQ BIT(0)
44 #define COMMAND_RAISE_MSI_IRQ BIT(1)
45 #define MSI_NUMBER_SHIFT 2
46 /* 6 bits for MSI number */
47 #define COMMAND_READ BIT(8)
48 #define COMMAND_WRITE BIT(9)
49 #define COMMAND_COPY BIT(10)
51 #define PCI_ENDPOINT_TEST_STATUS 0x8
52 #define STATUS_READ_SUCCESS BIT(0)
53 #define STATUS_READ_FAIL BIT(1)
54 #define STATUS_WRITE_SUCCESS BIT(2)
55 #define STATUS_WRITE_FAIL BIT(3)
56 #define STATUS_COPY_SUCCESS BIT(4)
57 #define STATUS_COPY_FAIL BIT(5)
58 #define STATUS_IRQ_RAISED BIT(6)
59 #define STATUS_SRC_ADDR_INVALID BIT(7)
60 #define STATUS_DST_ADDR_INVALID BIT(8)
62 #define PCI_ENDPOINT_TEST_LOWER_SRC_ADDR 0xc
63 #define PCI_ENDPOINT_TEST_UPPER_SRC_ADDR 0x10
65 #define PCI_ENDPOINT_TEST_LOWER_DST_ADDR 0x14
66 #define PCI_ENDPOINT_TEST_UPPER_DST_ADDR 0x18
68 #define PCI_ENDPOINT_TEST_SIZE 0x1c
69 #define PCI_ENDPOINT_TEST_CHECKSUM 0x20
71 static DEFINE_IDA(pci_endpoint_test_ida
);
73 #define to_endpoint_test(priv) container_of((priv), struct pci_endpoint_test, \
77 module_param(no_msi
, bool, 0444);
78 MODULE_PARM_DESC(no_msi
, "Disable MSI interrupt in pci_endpoint_test");
89 struct pci_endpoint_test
{
93 struct completion irq_raised
;
95 /* mutex to protect the ioctls */
97 struct miscdevice miscdev
;
98 enum pci_barno test_reg_bar
;
102 struct pci_endpoint_test_data
{
103 enum pci_barno test_reg_bar
;
108 static inline u32
pci_endpoint_test_readl(struct pci_endpoint_test
*test
,
111 return readl(test
->base
+ offset
);
114 static inline void pci_endpoint_test_writel(struct pci_endpoint_test
*test
,
115 u32 offset
, u32 value
)
117 writel(value
, test
->base
+ offset
);
120 static inline u32
pci_endpoint_test_bar_readl(struct pci_endpoint_test
*test
,
123 return readl(test
->bar
[bar
] + offset
);
126 static inline void pci_endpoint_test_bar_writel(struct pci_endpoint_test
*test
,
127 int bar
, u32 offset
, u32 value
)
129 writel(value
, test
->bar
[bar
] + offset
);
132 static irqreturn_t
pci_endpoint_test_irqhandler(int irq
, void *dev_id
)
134 struct pci_endpoint_test
*test
= dev_id
;
137 reg
= pci_endpoint_test_readl(test
, PCI_ENDPOINT_TEST_STATUS
);
138 if (reg
& STATUS_IRQ_RAISED
) {
139 test
->last_irq
= irq
;
140 complete(&test
->irq_raised
);
141 reg
&= ~STATUS_IRQ_RAISED
;
143 pci_endpoint_test_writel(test
, PCI_ENDPOINT_TEST_STATUS
,
149 static bool pci_endpoint_test_bar(struct pci_endpoint_test
*test
,
150 enum pci_barno barno
)
155 struct pci_dev
*pdev
= test
->pdev
;
157 if (!test
->bar
[barno
])
160 size
= pci_resource_len(pdev
, barno
);
162 if (barno
== test
->test_reg_bar
)
165 for (j
= 0; j
< size
; j
+= 4)
166 pci_endpoint_test_bar_writel(test
, barno
, j
, 0xA0A0A0A0);
168 for (j
= 0; j
< size
; j
+= 4) {
169 val
= pci_endpoint_test_bar_readl(test
, barno
, j
);
170 if (val
!= 0xA0A0A0A0)
177 static bool pci_endpoint_test_legacy_irq(struct pci_endpoint_test
*test
)
181 pci_endpoint_test_writel(test
, PCI_ENDPOINT_TEST_COMMAND
,
182 COMMAND_RAISE_LEGACY_IRQ
);
183 val
= wait_for_completion_timeout(&test
->irq_raised
,
184 msecs_to_jiffies(1000));
191 static bool pci_endpoint_test_msi_irq(struct pci_endpoint_test
*test
,
195 struct pci_dev
*pdev
= test
->pdev
;
197 pci_endpoint_test_writel(test
, PCI_ENDPOINT_TEST_COMMAND
,
198 msi_num
<< MSI_NUMBER_SHIFT
|
199 COMMAND_RAISE_MSI_IRQ
);
200 val
= wait_for_completion_timeout(&test
->irq_raised
,
201 msecs_to_jiffies(1000));
205 if (test
->last_irq
- pdev
->irq
== msi_num
- 1)
211 static bool pci_endpoint_test_copy(struct pci_endpoint_test
*test
, size_t size
)
216 dma_addr_t src_phys_addr
;
217 dma_addr_t dst_phys_addr
;
218 struct pci_dev
*pdev
= test
->pdev
;
219 struct device
*dev
= &pdev
->dev
;
221 dma_addr_t orig_src_phys_addr
;
223 dma_addr_t orig_dst_phys_addr
;
225 size_t alignment
= test
->alignment
;
229 orig_src_addr
= dma_alloc_coherent(dev
, size
+ alignment
,
230 &orig_src_phys_addr
, GFP_KERNEL
);
231 if (!orig_src_addr
) {
232 dev_err(dev
, "failed to allocate source buffer\n");
237 if (alignment
&& !IS_ALIGNED(orig_src_phys_addr
, alignment
)) {
238 src_phys_addr
= PTR_ALIGN(orig_src_phys_addr
, alignment
);
239 offset
= src_phys_addr
- orig_src_phys_addr
;
240 src_addr
= orig_src_addr
+ offset
;
242 src_phys_addr
= orig_src_phys_addr
;
243 src_addr
= orig_src_addr
;
246 pci_endpoint_test_writel(test
, PCI_ENDPOINT_TEST_LOWER_SRC_ADDR
,
247 lower_32_bits(src_phys_addr
));
249 pci_endpoint_test_writel(test
, PCI_ENDPOINT_TEST_UPPER_SRC_ADDR
,
250 upper_32_bits(src_phys_addr
));
252 get_random_bytes(src_addr
, size
);
253 src_crc32
= crc32_le(~0, src_addr
, size
);
255 orig_dst_addr
= dma_alloc_coherent(dev
, size
+ alignment
,
256 &orig_dst_phys_addr
, GFP_KERNEL
);
257 if (!orig_dst_addr
) {
258 dev_err(dev
, "failed to allocate destination address\n");
260 goto err_orig_src_addr
;
263 if (alignment
&& !IS_ALIGNED(orig_dst_phys_addr
, alignment
)) {
264 dst_phys_addr
= PTR_ALIGN(orig_dst_phys_addr
, alignment
);
265 offset
= dst_phys_addr
- orig_dst_phys_addr
;
266 dst_addr
= orig_dst_addr
+ offset
;
268 dst_phys_addr
= orig_dst_phys_addr
;
269 dst_addr
= orig_dst_addr
;
272 pci_endpoint_test_writel(test
, PCI_ENDPOINT_TEST_LOWER_DST_ADDR
,
273 lower_32_bits(dst_phys_addr
));
274 pci_endpoint_test_writel(test
, PCI_ENDPOINT_TEST_UPPER_DST_ADDR
,
275 upper_32_bits(dst_phys_addr
));
277 pci_endpoint_test_writel(test
, PCI_ENDPOINT_TEST_SIZE
,
280 pci_endpoint_test_writel(test
, PCI_ENDPOINT_TEST_COMMAND
,
281 1 << MSI_NUMBER_SHIFT
| COMMAND_COPY
);
283 wait_for_completion(&test
->irq_raised
);
285 dst_crc32
= crc32_le(~0, dst_addr
, size
);
286 if (dst_crc32
== src_crc32
)
289 dma_free_coherent(dev
, size
+ alignment
, orig_dst_addr
,
293 dma_free_coherent(dev
, size
+ alignment
, orig_src_addr
,
300 static bool pci_endpoint_test_write(struct pci_endpoint_test
*test
, size_t size
)
305 dma_addr_t phys_addr
;
306 struct pci_dev
*pdev
= test
->pdev
;
307 struct device
*dev
= &pdev
->dev
;
309 dma_addr_t orig_phys_addr
;
311 size_t alignment
= test
->alignment
;
314 orig_addr
= dma_alloc_coherent(dev
, size
+ alignment
, &orig_phys_addr
,
317 dev_err(dev
, "failed to allocate address\n");
322 if (alignment
&& !IS_ALIGNED(orig_phys_addr
, alignment
)) {
323 phys_addr
= PTR_ALIGN(orig_phys_addr
, alignment
);
324 offset
= phys_addr
- orig_phys_addr
;
325 addr
= orig_addr
+ offset
;
327 phys_addr
= orig_phys_addr
;
331 get_random_bytes(addr
, size
);
333 crc32
= crc32_le(~0, addr
, size
);
334 pci_endpoint_test_writel(test
, PCI_ENDPOINT_TEST_CHECKSUM
,
337 pci_endpoint_test_writel(test
, PCI_ENDPOINT_TEST_LOWER_SRC_ADDR
,
338 lower_32_bits(phys_addr
));
339 pci_endpoint_test_writel(test
, PCI_ENDPOINT_TEST_UPPER_SRC_ADDR
,
340 upper_32_bits(phys_addr
));
342 pci_endpoint_test_writel(test
, PCI_ENDPOINT_TEST_SIZE
, size
);
344 pci_endpoint_test_writel(test
, PCI_ENDPOINT_TEST_COMMAND
,
345 1 << MSI_NUMBER_SHIFT
| COMMAND_READ
);
347 wait_for_completion(&test
->irq_raised
);
349 reg
= pci_endpoint_test_readl(test
, PCI_ENDPOINT_TEST_STATUS
);
350 if (reg
& STATUS_READ_SUCCESS
)
353 dma_free_coherent(dev
, size
+ alignment
, orig_addr
, orig_phys_addr
);
359 static bool pci_endpoint_test_read(struct pci_endpoint_test
*test
, size_t size
)
363 dma_addr_t phys_addr
;
364 struct pci_dev
*pdev
= test
->pdev
;
365 struct device
*dev
= &pdev
->dev
;
367 dma_addr_t orig_phys_addr
;
369 size_t alignment
= test
->alignment
;
372 orig_addr
= dma_alloc_coherent(dev
, size
+ alignment
, &orig_phys_addr
,
375 dev_err(dev
, "failed to allocate destination address\n");
380 if (alignment
&& !IS_ALIGNED(orig_phys_addr
, alignment
)) {
381 phys_addr
= PTR_ALIGN(orig_phys_addr
, alignment
);
382 offset
= phys_addr
- orig_phys_addr
;
383 addr
= orig_addr
+ offset
;
385 phys_addr
= orig_phys_addr
;
389 pci_endpoint_test_writel(test
, PCI_ENDPOINT_TEST_LOWER_DST_ADDR
,
390 lower_32_bits(phys_addr
));
391 pci_endpoint_test_writel(test
, PCI_ENDPOINT_TEST_UPPER_DST_ADDR
,
392 upper_32_bits(phys_addr
));
394 pci_endpoint_test_writel(test
, PCI_ENDPOINT_TEST_SIZE
, size
);
396 pci_endpoint_test_writel(test
, PCI_ENDPOINT_TEST_COMMAND
,
397 1 << MSI_NUMBER_SHIFT
| COMMAND_WRITE
);
399 wait_for_completion(&test
->irq_raised
);
401 crc32
= crc32_le(~0, addr
, size
);
402 if (crc32
== pci_endpoint_test_readl(test
, PCI_ENDPOINT_TEST_CHECKSUM
))
405 dma_free_coherent(dev
, size
+ alignment
, orig_addr
, orig_phys_addr
);
410 static long pci_endpoint_test_ioctl(struct file
*file
, unsigned int cmd
,
415 struct pci_endpoint_test
*test
= to_endpoint_test(file
->private_data
);
417 mutex_lock(&test
->mutex
);
421 if (bar
< 0 || bar
> 5)
423 ret
= pci_endpoint_test_bar(test
, bar
);
425 case PCITEST_LEGACY_IRQ
:
426 ret
= pci_endpoint_test_legacy_irq(test
);
429 ret
= pci_endpoint_test_msi_irq(test
, arg
);
432 ret
= pci_endpoint_test_write(test
, arg
);
435 ret
= pci_endpoint_test_read(test
, arg
);
438 ret
= pci_endpoint_test_copy(test
, arg
);
443 mutex_unlock(&test
->mutex
);
447 static const struct file_operations pci_endpoint_test_fops
= {
448 .owner
= THIS_MODULE
,
449 .unlocked_ioctl
= pci_endpoint_test_ioctl
,
452 static int pci_endpoint_test_probe(struct pci_dev
*pdev
,
453 const struct pci_device_id
*ent
)
462 struct device
*dev
= &pdev
->dev
;
463 struct pci_endpoint_test
*test
;
464 struct pci_endpoint_test_data
*data
;
465 enum pci_barno test_reg_bar
= BAR_0
;
466 struct miscdevice
*misc_device
;
468 if (pci_is_bridge(pdev
))
471 test
= devm_kzalloc(dev
, sizeof(*test
), GFP_KERNEL
);
475 test
->test_reg_bar
= 0;
479 data
= (struct pci_endpoint_test_data
*)ent
->driver_data
;
481 test_reg_bar
= data
->test_reg_bar
;
482 test
->alignment
= data
->alignment
;
483 no_msi
= data
->no_msi
;
486 init_completion(&test
->irq_raised
);
487 mutex_init(&test
->mutex
);
489 err
= pci_enable_device(pdev
);
491 dev_err(dev
, "Cannot enable PCI device\n");
495 err
= pci_request_regions(pdev
, DRV_MODULE_NAME
);
497 dev_err(dev
, "Cannot obtain PCI resources\n");
498 goto err_disable_pdev
;
501 pci_set_master(pdev
);
504 irq
= pci_alloc_irq_vectors(pdev
, 1, 32, PCI_IRQ_MSI
);
506 dev_err(dev
, "failed to get MSI interrupts\n");
509 err
= devm_request_irq(dev
, pdev
->irq
, pci_endpoint_test_irqhandler
,
510 IRQF_SHARED
, DRV_MODULE_NAME
, test
);
512 dev_err(dev
, "failed to request IRQ %d\n", pdev
->irq
);
513 goto err_disable_msi
;
516 for (i
= 1; i
< irq
; i
++) {
517 err
= devm_request_irq(dev
, pdev
->irq
+ i
,
518 pci_endpoint_test_irqhandler
,
519 IRQF_SHARED
, DRV_MODULE_NAME
, test
);
521 dev_err(dev
, "failed to request IRQ %d for MSI %d\n",
522 pdev
->irq
+ i
, i
+ 1);
525 for (bar
= BAR_0
; bar
<= BAR_5
; bar
++) {
526 base
= pci_ioremap_bar(pdev
, bar
);
528 dev_err(dev
, "failed to read BAR%d\n", bar
);
529 WARN_ON(bar
== test_reg_bar
);
531 test
->bar
[bar
] = base
;
534 test
->base
= test
->bar
[test_reg_bar
];
536 dev_err(dev
, "Cannot perform PCI test without BAR%d\n",
541 pci_set_drvdata(pdev
, test
);
543 id
= ida_simple_get(&pci_endpoint_test_ida
, 0, 0, GFP_KERNEL
);
545 dev_err(dev
, "unable to get id\n");
549 snprintf(name
, sizeof(name
), DRV_MODULE_NAME
".%d", id
);
550 misc_device
= &test
->miscdev
;
551 misc_device
->minor
= MISC_DYNAMIC_MINOR
;
552 misc_device
->name
= name
;
553 misc_device
->fops
= &pci_endpoint_test_fops
,
555 err
= misc_register(misc_device
);
557 dev_err(dev
, "failed to register device\n");
564 ida_simple_remove(&pci_endpoint_test_ida
, id
);
567 for (bar
= BAR_0
; bar
<= BAR_5
; bar
++) {
569 pci_iounmap(pdev
, test
->bar
[bar
]);
573 pci_disable_msi(pdev
);
574 pci_release_regions(pdev
);
577 pci_disable_device(pdev
);
582 static void pci_endpoint_test_remove(struct pci_dev
*pdev
)
586 struct pci_endpoint_test
*test
= pci_get_drvdata(pdev
);
587 struct miscdevice
*misc_device
= &test
->miscdev
;
589 if (sscanf(misc_device
->name
, DRV_MODULE_NAME
".%d", &id
) != 1)
592 misc_deregister(&test
->miscdev
);
593 ida_simple_remove(&pci_endpoint_test_ida
, id
);
594 for (bar
= BAR_0
; bar
<= BAR_5
; bar
++) {
596 pci_iounmap(pdev
, test
->bar
[bar
]);
598 pci_disable_msi(pdev
);
599 pci_release_regions(pdev
);
600 pci_disable_device(pdev
);
603 static const struct pci_device_id pci_endpoint_test_tbl
[] = {
604 { PCI_DEVICE(PCI_VENDOR_ID_TI
, PCI_DEVICE_ID_TI_DRA74x
) },
605 { PCI_DEVICE(PCI_VENDOR_ID_TI
, PCI_DEVICE_ID_TI_DRA72x
) },
608 MODULE_DEVICE_TABLE(pci
, pci_endpoint_test_tbl
);
610 static struct pci_driver pci_endpoint_test_driver
= {
611 .name
= DRV_MODULE_NAME
,
612 .id_table
= pci_endpoint_test_tbl
,
613 .probe
= pci_endpoint_test_probe
,
614 .remove
= pci_endpoint_test_remove
,
616 module_pci_driver(pci_endpoint_test_driver
);
618 MODULE_DESCRIPTION("PCI ENDPOINT TEST HOST DRIVER");
619 MODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>");
620 MODULE_LICENSE("GPL v2");