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 | ||
