diff options
Diffstat (limited to 'drivers/misc/pci_endpoint_test.c')
-rw-r--r-- | drivers/misc/pci_endpoint_test.c | 132 |
1 files changed, 109 insertions, 23 deletions
diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c index 09c10f426b64..deb203026496 100644 --- a/drivers/misc/pci_endpoint_test.c +++ b/drivers/misc/pci_endpoint_test.c | |||
@@ -72,6 +72,11 @@ static DEFINE_IDA(pci_endpoint_test_ida); | |||
72 | 72 | ||
73 | #define to_endpoint_test(priv) container_of((priv), struct pci_endpoint_test, \ | 73 | #define to_endpoint_test(priv) container_of((priv), struct pci_endpoint_test, \ |
74 | miscdev) | 74 | miscdev) |
75 | |||
76 | static bool no_msi; | ||
77 | module_param(no_msi, bool, 0444); | ||
78 | MODULE_PARM_DESC(no_msi, "Disable MSI interrupt in pci_endpoint_test"); | ||
79 | |||
75 | enum pci_barno { | 80 | enum pci_barno { |
76 | BAR_0, | 81 | BAR_0, |
77 | BAR_1, | 82 | BAR_1, |
@@ -90,9 +95,15 @@ struct pci_endpoint_test { | |||
90 | /* mutex to protect the ioctls */ | 95 | /* mutex to protect the ioctls */ |
91 | struct mutex mutex; | 96 | struct mutex mutex; |
92 | struct miscdevice miscdev; | 97 | struct miscdevice miscdev; |
98 | enum pci_barno test_reg_bar; | ||
99 | size_t alignment; | ||
93 | }; | 100 | }; |
94 | 101 | ||
95 | static int bar_size[] = { 4, 512, 1024, 16384, 131072, 1048576 }; | 102 | struct pci_endpoint_test_data { |
103 | enum pci_barno test_reg_bar; | ||
104 | size_t alignment; | ||
105 | bool no_msi; | ||
106 | }; | ||
96 | 107 | ||
97 | static inline u32 pci_endpoint_test_readl(struct pci_endpoint_test *test, | 108 | static inline u32 pci_endpoint_test_readl(struct pci_endpoint_test *test, |
98 | u32 offset) | 109 | u32 offset) |
@@ -141,11 +152,15 @@ static bool pci_endpoint_test_bar(struct pci_endpoint_test *test, | |||
141 | int j; | 152 | int j; |
142 | u32 val; | 153 | u32 val; |
143 | int size; | 154 | int size; |
155 | struct pci_dev *pdev = test->pdev; | ||
144 | 156 | ||
145 | if (!test->bar[barno]) | 157 | if (!test->bar[barno]) |
146 | return false; | 158 | return false; |
147 | 159 | ||
148 | size = bar_size[barno]; | 160 | size = pci_resource_len(pdev, barno); |
161 | |||
162 | if (barno == test->test_reg_bar) | ||
163 | size = 0x4; | ||
149 | 164 | ||
150 | for (j = 0; j < size; j += 4) | 165 | for (j = 0; j < size; j += 4) |
151 | pci_endpoint_test_bar_writel(test, barno, j, 0xA0A0A0A0); | 166 | pci_endpoint_test_bar_writel(test, barno, j, 0xA0A0A0A0); |
@@ -202,16 +217,32 @@ static bool pci_endpoint_test_copy(struct pci_endpoint_test *test, size_t size) | |||
202 | dma_addr_t dst_phys_addr; | 217 | dma_addr_t dst_phys_addr; |
203 | struct pci_dev *pdev = test->pdev; | 218 | struct pci_dev *pdev = test->pdev; |
204 | struct device *dev = &pdev->dev; | 219 | struct device *dev = &pdev->dev; |
220 | void *orig_src_addr; | ||
221 | dma_addr_t orig_src_phys_addr; | ||
222 | void *orig_dst_addr; | ||
223 | dma_addr_t orig_dst_phys_addr; | ||
224 | size_t offset; | ||
225 | size_t alignment = test->alignment; | ||
205 | u32 src_crc32; | 226 | u32 src_crc32; |
206 | u32 dst_crc32; | 227 | u32 dst_crc32; |
207 | 228 | ||
208 | src_addr = dma_alloc_coherent(dev, size, &src_phys_addr, GFP_KERNEL); | 229 | orig_src_addr = dma_alloc_coherent(dev, size + alignment, |
209 | if (!src_addr) { | 230 | &orig_src_phys_addr, GFP_KERNEL); |
231 | if (!orig_src_addr) { | ||
210 | dev_err(dev, "failed to allocate source buffer\n"); | 232 | dev_err(dev, "failed to allocate source buffer\n"); |
211 | ret = false; | 233 | ret = false; |
212 | goto err; | 234 | goto err; |
213 | } | 235 | } |
214 | 236 | ||
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; | ||
241 | } else { | ||
242 | src_phys_addr = orig_src_phys_addr; | ||
243 | src_addr = orig_src_addr; | ||
244 | } | ||
245 | |||
215 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_LOWER_SRC_ADDR, | 246 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_LOWER_SRC_ADDR, |
216 | lower_32_bits(src_phys_addr)); | 247 | lower_32_bits(src_phys_addr)); |
217 | 248 | ||
@@ -221,11 +252,21 @@ static bool pci_endpoint_test_copy(struct pci_endpoint_test *test, size_t size) | |||
221 | get_random_bytes(src_addr, size); | 252 | get_random_bytes(src_addr, size); |
222 | src_crc32 = crc32_le(~0, src_addr, size); | 253 | src_crc32 = crc32_le(~0, src_addr, size); |
223 | 254 | ||
224 | dst_addr = dma_alloc_coherent(dev, size, &dst_phys_addr, GFP_KERNEL); | 255 | orig_dst_addr = dma_alloc_coherent(dev, size + alignment, |
225 | if (!dst_addr) { | 256 | &orig_dst_phys_addr, GFP_KERNEL); |
257 | if (!orig_dst_addr) { | ||
226 | dev_err(dev, "failed to allocate destination address\n"); | 258 | dev_err(dev, "failed to allocate destination address\n"); |
227 | ret = false; | 259 | ret = false; |
228 | goto err_src_addr; | 260 | goto err_orig_src_addr; |
261 | } | ||
262 | |||
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; | ||
267 | } else { | ||
268 | dst_phys_addr = orig_dst_phys_addr; | ||
269 | dst_addr = orig_dst_addr; | ||
229 | } | 270 | } |
230 | 271 | ||
231 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_LOWER_DST_ADDR, | 272 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_LOWER_DST_ADDR, |
@@ -245,10 +286,12 @@ static bool pci_endpoint_test_copy(struct pci_endpoint_test *test, size_t size) | |||
245 | if (dst_crc32 == src_crc32) | 286 | if (dst_crc32 == src_crc32) |
246 | ret = true; | 287 | ret = true; |
247 | 288 | ||
248 | dma_free_coherent(dev, size, dst_addr, dst_phys_addr); | 289 | dma_free_coherent(dev, size + alignment, orig_dst_addr, |
290 | orig_dst_phys_addr); | ||
249 | 291 | ||
250 | err_src_addr: | 292 | err_orig_src_addr: |
251 | dma_free_coherent(dev, size, src_addr, src_phys_addr); | 293 | dma_free_coherent(dev, size + alignment, orig_src_addr, |
294 | orig_src_phys_addr); | ||
252 | 295 | ||
253 | err: | 296 | err: |
254 | return ret; | 297 | return ret; |
@@ -262,15 +305,29 @@ static bool pci_endpoint_test_write(struct pci_endpoint_test *test, size_t size) | |||
262 | dma_addr_t phys_addr; | 305 | dma_addr_t phys_addr; |
263 | struct pci_dev *pdev = test->pdev; | 306 | struct pci_dev *pdev = test->pdev; |
264 | struct device *dev = &pdev->dev; | 307 | struct device *dev = &pdev->dev; |
308 | void *orig_addr; | ||
309 | dma_addr_t orig_phys_addr; | ||
310 | size_t offset; | ||
311 | size_t alignment = test->alignment; | ||
265 | u32 crc32; | 312 | u32 crc32; |
266 | 313 | ||
267 | addr = dma_alloc_coherent(dev, size, &phys_addr, GFP_KERNEL); | 314 | orig_addr = dma_alloc_coherent(dev, size + alignment, &orig_phys_addr, |
268 | if (!addr) { | 315 | GFP_KERNEL); |
316 | if (!orig_addr) { | ||
269 | dev_err(dev, "failed to allocate address\n"); | 317 | dev_err(dev, "failed to allocate address\n"); |
270 | ret = false; | 318 | ret = false; |
271 | goto err; | 319 | goto err; |
272 | } | 320 | } |
273 | 321 | ||
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; | ||
326 | } else { | ||
327 | phys_addr = orig_phys_addr; | ||
328 | addr = orig_addr; | ||
329 | } | ||
330 | |||
274 | get_random_bytes(addr, size); | 331 | get_random_bytes(addr, size); |
275 | 332 | ||
276 | crc32 = crc32_le(~0, addr, size); | 333 | crc32 = crc32_le(~0, addr, size); |
@@ -293,7 +350,7 @@ static bool pci_endpoint_test_write(struct pci_endpoint_test *test, size_t size) | |||
293 | if (reg & STATUS_READ_SUCCESS) | 350 | if (reg & STATUS_READ_SUCCESS) |
294 | ret = true; | 351 | ret = true; |
295 | 352 | ||
296 | dma_free_coherent(dev, size, addr, phys_addr); | 353 | dma_free_coherent(dev, size + alignment, orig_addr, orig_phys_addr); |
297 | 354 | ||
298 | err: | 355 | err: |
299 | return ret; | 356 | return ret; |
@@ -306,15 +363,29 @@ static bool pci_endpoint_test_read(struct pci_endpoint_test *test, size_t size) | |||
306 | dma_addr_t phys_addr; | 363 | dma_addr_t phys_addr; |
307 | struct pci_dev *pdev = test->pdev; | 364 | struct pci_dev *pdev = test->pdev; |
308 | struct device *dev = &pdev->dev; | 365 | struct device *dev = &pdev->dev; |
366 | void *orig_addr; | ||
367 | dma_addr_t orig_phys_addr; | ||
368 | size_t offset; | ||
369 | size_t alignment = test->alignment; | ||
309 | u32 crc32; | 370 | u32 crc32; |
310 | 371 | ||
311 | addr = dma_alloc_coherent(dev, size, &phys_addr, GFP_KERNEL); | 372 | orig_addr = dma_alloc_coherent(dev, size + alignment, &orig_phys_addr, |
312 | if (!addr) { | 373 | GFP_KERNEL); |
374 | if (!orig_addr) { | ||
313 | dev_err(dev, "failed to allocate destination address\n"); | 375 | dev_err(dev, "failed to allocate destination address\n"); |
314 | ret = false; | 376 | ret = false; |
315 | goto err; | 377 | goto err; |
316 | } | 378 | } |
317 | 379 | ||
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; | ||
384 | } else { | ||
385 | phys_addr = orig_phys_addr; | ||
386 | addr = orig_addr; | ||
387 | } | ||
388 | |||
318 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_LOWER_DST_ADDR, | 389 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_LOWER_DST_ADDR, |
319 | lower_32_bits(phys_addr)); | 390 | lower_32_bits(phys_addr)); |
320 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_UPPER_DST_ADDR, | 391 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_UPPER_DST_ADDR, |
@@ -331,7 +402,7 @@ static bool pci_endpoint_test_read(struct pci_endpoint_test *test, size_t size) | |||
331 | if (crc32 == pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_CHECKSUM)) | 402 | if (crc32 == pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_CHECKSUM)) |
332 | ret = true; | 403 | ret = true; |
333 | 404 | ||
334 | dma_free_coherent(dev, size, addr, phys_addr); | 405 | dma_free_coherent(dev, size + alignment, orig_addr, orig_phys_addr); |
335 | err: | 406 | err: |
336 | return ret; | 407 | return ret; |
337 | } | 408 | } |
@@ -383,13 +454,15 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev, | |||
383 | { | 454 | { |
384 | int i; | 455 | int i; |
385 | int err; | 456 | int err; |
386 | int irq; | 457 | int irq = 0; |
387 | int id; | 458 | int id; |
388 | char name[20]; | 459 | char name[20]; |
389 | enum pci_barno bar; | 460 | enum pci_barno bar; |
390 | void __iomem *base; | 461 | void __iomem *base; |
391 | struct device *dev = &pdev->dev; | 462 | struct device *dev = &pdev->dev; |
392 | struct pci_endpoint_test *test; | 463 | struct pci_endpoint_test *test; |
464 | struct pci_endpoint_test_data *data; | ||
465 | enum pci_barno test_reg_bar = BAR_0; | ||
393 | struct miscdevice *misc_device; | 466 | struct miscdevice *misc_device; |
394 | 467 | ||
395 | if (pci_is_bridge(pdev)) | 468 | if (pci_is_bridge(pdev)) |
@@ -399,7 +472,17 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev, | |||
399 | if (!test) | 472 | if (!test) |
400 | return -ENOMEM; | 473 | return -ENOMEM; |
401 | 474 | ||
475 | test->test_reg_bar = 0; | ||
476 | test->alignment = 0; | ||
402 | test->pdev = pdev; | 477 | test->pdev = pdev; |
478 | |||
479 | data = (struct pci_endpoint_test_data *)ent->driver_data; | ||
480 | if (data) { | ||
481 | test_reg_bar = data->test_reg_bar; | ||
482 | test->alignment = data->alignment; | ||
483 | no_msi = data->no_msi; | ||
484 | } | ||
485 | |||
403 | init_completion(&test->irq_raised); | 486 | init_completion(&test->irq_raised); |
404 | mutex_init(&test->mutex); | 487 | mutex_init(&test->mutex); |
405 | 488 | ||
@@ -417,9 +500,11 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev, | |||
417 | 500 | ||
418 | pci_set_master(pdev); | 501 | pci_set_master(pdev); |
419 | 502 | ||
420 | irq = pci_alloc_irq_vectors(pdev, 1, 32, PCI_IRQ_MSI); | 503 | if (!no_msi) { |
421 | if (irq < 0) | 504 | irq = pci_alloc_irq_vectors(pdev, 1, 32, PCI_IRQ_MSI); |
422 | dev_err(dev, "failed to get MSI interrupts\n"); | 505 | if (irq < 0) |
506 | dev_err(dev, "failed to get MSI interrupts\n"); | ||
507 | } | ||
423 | 508 | ||
424 | err = devm_request_irq(dev, pdev->irq, pci_endpoint_test_irqhandler, | 509 | err = devm_request_irq(dev, pdev->irq, pci_endpoint_test_irqhandler, |
425 | IRQF_SHARED, DRV_MODULE_NAME, test); | 510 | IRQF_SHARED, DRV_MODULE_NAME, test); |
@@ -441,14 +526,15 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev, | |||
441 | base = pci_ioremap_bar(pdev, bar); | 526 | base = pci_ioremap_bar(pdev, bar); |
442 | if (!base) { | 527 | if (!base) { |
443 | dev_err(dev, "failed to read BAR%d\n", bar); | 528 | dev_err(dev, "failed to read BAR%d\n", bar); |
444 | WARN_ON(bar == BAR_0); | 529 | WARN_ON(bar == test_reg_bar); |
445 | } | 530 | } |
446 | test->bar[bar] = base; | 531 | test->bar[bar] = base; |
447 | } | 532 | } |
448 | 533 | ||
449 | test->base = test->bar[0]; | 534 | test->base = test->bar[test_reg_bar]; |
450 | if (!test->base) { | 535 | if (!test->base) { |
451 | dev_err(dev, "Cannot perform PCI test without BAR0\n"); | 536 | dev_err(dev, "Cannot perform PCI test without BAR%d\n", |
537 | test_reg_bar); | ||
452 | goto err_iounmap; | 538 | goto err_iounmap; |
453 | } | 539 | } |
454 | 540 | ||