| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /** |
|---|
| 2 | 3 | * Host side test driver to test endpoint functionality |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright (C) 2017 Texas Instruments |
|---|
| 5 | 6 | * 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 | 7 | */ |
|---|
| 19 | 8 | |
|---|
| 20 | 9 | #include <linux/crc32.h> |
|---|
| .. | .. |
|---|
| 28 | 17 | #include <linux/mutex.h> |
|---|
| 29 | 18 | #include <linux/random.h> |
|---|
| 30 | 19 | #include <linux/slab.h> |
|---|
| 20 | +#include <linux/uaccess.h> |
|---|
| 31 | 21 | #include <linux/pci.h> |
|---|
| 32 | 22 | #include <linux/pci_ids.h> |
|---|
| 33 | 23 | |
|---|
| .. | .. |
|---|
| 75 | 65 | #define PCI_ENDPOINT_TEST_IRQ_TYPE 0x24 |
|---|
| 76 | 66 | #define PCI_ENDPOINT_TEST_IRQ_NUMBER 0x28 |
|---|
| 77 | 67 | |
|---|
| 68 | +#define PCI_ENDPOINT_TEST_FLAGS 0x2c |
|---|
| 69 | +#define FLAG_USE_DMA BIT(0) |
|---|
| 70 | + |
|---|
| 71 | +#define PCI_DEVICE_ID_TI_J721E 0xb00d |
|---|
| 78 | 72 | #define PCI_DEVICE_ID_TI_AM654 0xb00c |
|---|
| 73 | +#define PCI_DEVICE_ID_LS1088A 0x80c0 |
|---|
| 79 | 74 | |
|---|
| 80 | 75 | #define is_am654_pci_dev(pdev) \ |
|---|
| 81 | 76 | ((pdev)->device == PCI_DEVICE_ID_TI_AM654) |
|---|
| 77 | + |
|---|
| 78 | +#define PCI_DEVICE_ID_RENESAS_R8A774A1 0x0028 |
|---|
| 79 | +#define PCI_DEVICE_ID_RENESAS_R8A774B1 0x002b |
|---|
| 80 | +#define PCI_DEVICE_ID_RENESAS_R8A774C0 0x002d |
|---|
| 81 | +#define PCI_DEVICE_ID_RENESAS_R8A774E1 0x0025 |
|---|
| 82 | 82 | |
|---|
| 83 | 83 | static DEFINE_IDA(pci_endpoint_test_ida); |
|---|
| 84 | 84 | |
|---|
| .. | .. |
|---|
| 105 | 105 | struct pci_endpoint_test { |
|---|
| 106 | 106 | struct pci_dev *pdev; |
|---|
| 107 | 107 | void __iomem *base; |
|---|
| 108 | | - void __iomem *bar[6]; |
|---|
| 108 | + void __iomem *bar[PCI_STD_NUM_BARS]; |
|---|
| 109 | 109 | struct completion irq_raised; |
|---|
| 110 | 110 | int last_irq; |
|---|
| 111 | 111 | int num_irqs; |
|---|
| .. | .. |
|---|
| 115 | 115 | struct miscdevice miscdev; |
|---|
| 116 | 116 | enum pci_barno test_reg_bar; |
|---|
| 117 | 117 | size_t alignment; |
|---|
| 118 | + const char *name; |
|---|
| 118 | 119 | }; |
|---|
| 119 | 120 | |
|---|
| 120 | 121 | struct pci_endpoint_test_data { |
|---|
| .. | .. |
|---|
| 233 | 234 | for (i = 0; i < test->num_irqs; i++) { |
|---|
| 234 | 235 | err = devm_request_irq(dev, pci_irq_vector(pdev, i), |
|---|
| 235 | 236 | pci_endpoint_test_irqhandler, |
|---|
| 236 | | - IRQF_SHARED, DRV_MODULE_NAME, test); |
|---|
| 237 | + IRQF_SHARED, test->name, test); |
|---|
| 237 | 238 | if (err) |
|---|
| 238 | 239 | goto fail; |
|---|
| 239 | 240 | } |
|---|
| .. | .. |
|---|
| 330 | 331 | return false; |
|---|
| 331 | 332 | } |
|---|
| 332 | 333 | |
|---|
| 333 | | -static bool pci_endpoint_test_copy(struct pci_endpoint_test *test, size_t size) |
|---|
| 334 | +static int pci_endpoint_test_validate_xfer_params(struct device *dev, |
|---|
| 335 | + struct pci_endpoint_test_xfer_param *param, size_t alignment) |
|---|
| 334 | 336 | { |
|---|
| 337 | + if (!param->size) { |
|---|
| 338 | + dev_dbg(dev, "Data size is zero\n"); |
|---|
| 339 | + return -EINVAL; |
|---|
| 340 | + } |
|---|
| 341 | + |
|---|
| 342 | + if (param->size > SIZE_MAX - alignment) { |
|---|
| 343 | + dev_dbg(dev, "Maximum transfer data size exceeded\n"); |
|---|
| 344 | + return -EINVAL; |
|---|
| 345 | + } |
|---|
| 346 | + |
|---|
| 347 | + return 0; |
|---|
| 348 | +} |
|---|
| 349 | + |
|---|
| 350 | +static bool pci_endpoint_test_copy(struct pci_endpoint_test *test, |
|---|
| 351 | + unsigned long arg) |
|---|
| 352 | +{ |
|---|
| 353 | + struct pci_endpoint_test_xfer_param param; |
|---|
| 335 | 354 | bool ret = false; |
|---|
| 336 | 355 | void *src_addr; |
|---|
| 337 | 356 | void *dst_addr; |
|---|
| 357 | + u32 flags = 0; |
|---|
| 358 | + bool use_dma; |
|---|
| 359 | + size_t size; |
|---|
| 338 | 360 | dma_addr_t src_phys_addr; |
|---|
| 339 | 361 | dma_addr_t dst_phys_addr; |
|---|
| 340 | 362 | struct pci_dev *pdev = test->pdev; |
|---|
| .. | .. |
|---|
| 348 | 370 | int irq_type = test->irq_type; |
|---|
| 349 | 371 | u32 src_crc32; |
|---|
| 350 | 372 | u32 dst_crc32; |
|---|
| 373 | + int err; |
|---|
| 351 | 374 | |
|---|
| 352 | | - if (size > SIZE_MAX - alignment) |
|---|
| 353 | | - goto err; |
|---|
| 375 | + err = copy_from_user(¶m, (void __user *)arg, sizeof(param)); |
|---|
| 376 | + if (err) { |
|---|
| 377 | + dev_err(dev, "Failed to get transfer param\n"); |
|---|
| 378 | + return false; |
|---|
| 379 | + } |
|---|
| 380 | + |
|---|
| 381 | + err = pci_endpoint_test_validate_xfer_params(dev, ¶m, alignment); |
|---|
| 382 | + if (err) |
|---|
| 383 | + return false; |
|---|
| 384 | + |
|---|
| 385 | + size = param.size; |
|---|
| 386 | + |
|---|
| 387 | + use_dma = !!(param.flags & PCITEST_FLAGS_USE_DMA); |
|---|
| 388 | + if (use_dma) |
|---|
| 389 | + flags |= FLAG_USE_DMA; |
|---|
| 354 | 390 | |
|---|
| 355 | 391 | if (irq_type < IRQ_TYPE_LEGACY || irq_type > IRQ_TYPE_MSIX) { |
|---|
| 356 | 392 | dev_err(dev, "Invalid IRQ type option\n"); |
|---|
| 357 | 393 | goto err; |
|---|
| 358 | 394 | } |
|---|
| 359 | 395 | |
|---|
| 360 | | - orig_src_addr = dma_alloc_coherent(dev, size + alignment, |
|---|
| 361 | | - &orig_src_phys_addr, GFP_KERNEL); |
|---|
| 396 | + orig_src_addr = kzalloc(size + alignment, GFP_KERNEL); |
|---|
| 362 | 397 | if (!orig_src_addr) { |
|---|
| 363 | 398 | dev_err(dev, "Failed to allocate source buffer\n"); |
|---|
| 364 | 399 | ret = false; |
|---|
| 365 | 400 | goto err; |
|---|
| 401 | + } |
|---|
| 402 | + |
|---|
| 403 | + get_random_bytes(orig_src_addr, size + alignment); |
|---|
| 404 | + orig_src_phys_addr = dma_map_single(dev, orig_src_addr, |
|---|
| 405 | + size + alignment, DMA_TO_DEVICE); |
|---|
| 406 | + if (dma_mapping_error(dev, orig_src_phys_addr)) { |
|---|
| 407 | + dev_err(dev, "failed to map source buffer address\n"); |
|---|
| 408 | + ret = false; |
|---|
| 409 | + goto err_src_phys_addr; |
|---|
| 366 | 410 | } |
|---|
| 367 | 411 | |
|---|
| 368 | 412 | if (alignment && !IS_ALIGNED(orig_src_phys_addr, alignment)) { |
|---|
| .. | .. |
|---|
| 380 | 424 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_UPPER_SRC_ADDR, |
|---|
| 381 | 425 | upper_32_bits(src_phys_addr)); |
|---|
| 382 | 426 | |
|---|
| 383 | | - get_random_bytes(src_addr, size); |
|---|
| 384 | 427 | src_crc32 = crc32_le(~0, src_addr, size); |
|---|
| 385 | 428 | |
|---|
| 386 | | - orig_dst_addr = dma_alloc_coherent(dev, size + alignment, |
|---|
| 387 | | - &orig_dst_phys_addr, GFP_KERNEL); |
|---|
| 429 | + orig_dst_addr = kzalloc(size + alignment, GFP_KERNEL); |
|---|
| 388 | 430 | if (!orig_dst_addr) { |
|---|
| 389 | 431 | dev_err(dev, "Failed to allocate destination address\n"); |
|---|
| 390 | 432 | ret = false; |
|---|
| 391 | | - goto err_orig_src_addr; |
|---|
| 433 | + goto err_dst_addr; |
|---|
| 434 | + } |
|---|
| 435 | + |
|---|
| 436 | + orig_dst_phys_addr = dma_map_single(dev, orig_dst_addr, |
|---|
| 437 | + size + alignment, DMA_FROM_DEVICE); |
|---|
| 438 | + if (dma_mapping_error(dev, orig_dst_phys_addr)) { |
|---|
| 439 | + dev_err(dev, "failed to map destination buffer address\n"); |
|---|
| 440 | + ret = false; |
|---|
| 441 | + goto err_dst_phys_addr; |
|---|
| 392 | 442 | } |
|---|
| 393 | 443 | |
|---|
| 394 | 444 | if (alignment && !IS_ALIGNED(orig_dst_phys_addr, alignment)) { |
|---|
| .. | .. |
|---|
| 408 | 458 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_SIZE, |
|---|
| 409 | 459 | size); |
|---|
| 410 | 460 | |
|---|
| 461 | + pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_FLAGS, flags); |
|---|
| 411 | 462 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE, irq_type); |
|---|
| 412 | 463 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, 1); |
|---|
| 413 | 464 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND, |
|---|
| .. | .. |
|---|
| 415 | 466 | |
|---|
| 416 | 467 | wait_for_completion(&test->irq_raised); |
|---|
| 417 | 468 | |
|---|
| 469 | + dma_unmap_single(dev, orig_dst_phys_addr, size + alignment, |
|---|
| 470 | + DMA_FROM_DEVICE); |
|---|
| 471 | + |
|---|
| 418 | 472 | dst_crc32 = crc32_le(~0, dst_addr, size); |
|---|
| 419 | 473 | if (dst_crc32 == src_crc32) |
|---|
| 420 | 474 | ret = true; |
|---|
| 421 | 475 | |
|---|
| 422 | | - dma_free_coherent(dev, size + alignment, orig_dst_addr, |
|---|
| 423 | | - orig_dst_phys_addr); |
|---|
| 476 | +err_dst_phys_addr: |
|---|
| 477 | + kfree(orig_dst_addr); |
|---|
| 424 | 478 | |
|---|
| 425 | | -err_orig_src_addr: |
|---|
| 426 | | - dma_free_coherent(dev, size + alignment, orig_src_addr, |
|---|
| 427 | | - orig_src_phys_addr); |
|---|
| 479 | +err_dst_addr: |
|---|
| 480 | + dma_unmap_single(dev, orig_src_phys_addr, size + alignment, |
|---|
| 481 | + DMA_TO_DEVICE); |
|---|
| 482 | + |
|---|
| 483 | +err_src_phys_addr: |
|---|
| 484 | + kfree(orig_src_addr); |
|---|
| 428 | 485 | |
|---|
| 429 | 486 | err: |
|---|
| 430 | 487 | return ret; |
|---|
| 431 | 488 | } |
|---|
| 432 | 489 | |
|---|
| 433 | | -static bool pci_endpoint_test_write(struct pci_endpoint_test *test, size_t size) |
|---|
| 490 | +static bool pci_endpoint_test_write(struct pci_endpoint_test *test, |
|---|
| 491 | + unsigned long arg) |
|---|
| 434 | 492 | { |
|---|
| 493 | + struct pci_endpoint_test_xfer_param param; |
|---|
| 435 | 494 | bool ret = false; |
|---|
| 495 | + u32 flags = 0; |
|---|
| 496 | + bool use_dma; |
|---|
| 436 | 497 | u32 reg; |
|---|
| 437 | 498 | void *addr; |
|---|
| 438 | 499 | dma_addr_t phys_addr; |
|---|
| .. | .. |
|---|
| 443 | 504 | size_t offset; |
|---|
| 444 | 505 | size_t alignment = test->alignment; |
|---|
| 445 | 506 | int irq_type = test->irq_type; |
|---|
| 507 | + size_t size; |
|---|
| 446 | 508 | u32 crc32; |
|---|
| 509 | + int err; |
|---|
| 447 | 510 | |
|---|
| 448 | | - if (size > SIZE_MAX - alignment) |
|---|
| 449 | | - goto err; |
|---|
| 511 | + err = copy_from_user(¶m, (void __user *)arg, sizeof(param)); |
|---|
| 512 | + if (err != 0) { |
|---|
| 513 | + dev_err(dev, "Failed to get transfer param\n"); |
|---|
| 514 | + return false; |
|---|
| 515 | + } |
|---|
| 516 | + |
|---|
| 517 | + err = pci_endpoint_test_validate_xfer_params(dev, ¶m, alignment); |
|---|
| 518 | + if (err) |
|---|
| 519 | + return false; |
|---|
| 520 | + |
|---|
| 521 | + size = param.size; |
|---|
| 522 | + |
|---|
| 523 | + use_dma = !!(param.flags & PCITEST_FLAGS_USE_DMA); |
|---|
| 524 | + if (use_dma) |
|---|
| 525 | + flags |= FLAG_USE_DMA; |
|---|
| 450 | 526 | |
|---|
| 451 | 527 | if (irq_type < IRQ_TYPE_LEGACY || irq_type > IRQ_TYPE_MSIX) { |
|---|
| 452 | 528 | dev_err(dev, "Invalid IRQ type option\n"); |
|---|
| 453 | 529 | goto err; |
|---|
| 454 | 530 | } |
|---|
| 455 | 531 | |
|---|
| 456 | | - orig_addr = dma_alloc_coherent(dev, size + alignment, &orig_phys_addr, |
|---|
| 457 | | - GFP_KERNEL); |
|---|
| 532 | + orig_addr = kzalloc(size + alignment, GFP_KERNEL); |
|---|
| 458 | 533 | if (!orig_addr) { |
|---|
| 459 | 534 | dev_err(dev, "Failed to allocate address\n"); |
|---|
| 460 | 535 | ret = false; |
|---|
| 461 | 536 | goto err; |
|---|
| 537 | + } |
|---|
| 538 | + |
|---|
| 539 | + get_random_bytes(orig_addr, size + alignment); |
|---|
| 540 | + |
|---|
| 541 | + orig_phys_addr = dma_map_single(dev, orig_addr, size + alignment, |
|---|
| 542 | + DMA_TO_DEVICE); |
|---|
| 543 | + if (dma_mapping_error(dev, orig_phys_addr)) { |
|---|
| 544 | + dev_err(dev, "failed to map source buffer address\n"); |
|---|
| 545 | + ret = false; |
|---|
| 546 | + goto err_phys_addr; |
|---|
| 462 | 547 | } |
|---|
| 463 | 548 | |
|---|
| 464 | 549 | if (alignment && !IS_ALIGNED(orig_phys_addr, alignment)) { |
|---|
| .. | .. |
|---|
| 469 | 554 | phys_addr = orig_phys_addr; |
|---|
| 470 | 555 | addr = orig_addr; |
|---|
| 471 | 556 | } |
|---|
| 472 | | - |
|---|
| 473 | | - get_random_bytes(addr, size); |
|---|
| 474 | 557 | |
|---|
| 475 | 558 | crc32 = crc32_le(~0, addr, size); |
|---|
| 476 | 559 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_CHECKSUM, |
|---|
| .. | .. |
|---|
| 483 | 566 | |
|---|
| 484 | 567 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_SIZE, size); |
|---|
| 485 | 568 | |
|---|
| 569 | + pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_FLAGS, flags); |
|---|
| 486 | 570 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE, irq_type); |
|---|
| 487 | 571 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, 1); |
|---|
| 488 | 572 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND, |
|---|
| .. | .. |
|---|
| 494 | 578 | if (reg & STATUS_READ_SUCCESS) |
|---|
| 495 | 579 | ret = true; |
|---|
| 496 | 580 | |
|---|
| 497 | | - dma_free_coherent(dev, size + alignment, orig_addr, orig_phys_addr); |
|---|
| 581 | + dma_unmap_single(dev, orig_phys_addr, size + alignment, |
|---|
| 582 | + DMA_TO_DEVICE); |
|---|
| 583 | + |
|---|
| 584 | +err_phys_addr: |
|---|
| 585 | + kfree(orig_addr); |
|---|
| 498 | 586 | |
|---|
| 499 | 587 | err: |
|---|
| 500 | 588 | return ret; |
|---|
| 501 | 589 | } |
|---|
| 502 | 590 | |
|---|
| 503 | | -static bool pci_endpoint_test_read(struct pci_endpoint_test *test, size_t size) |
|---|
| 591 | +static bool pci_endpoint_test_read(struct pci_endpoint_test *test, |
|---|
| 592 | + unsigned long arg) |
|---|
| 504 | 593 | { |
|---|
| 594 | + struct pci_endpoint_test_xfer_param param; |
|---|
| 505 | 595 | bool ret = false; |
|---|
| 596 | + u32 flags = 0; |
|---|
| 597 | + bool use_dma; |
|---|
| 598 | + size_t size; |
|---|
| 506 | 599 | void *addr; |
|---|
| 507 | 600 | dma_addr_t phys_addr; |
|---|
| 508 | 601 | struct pci_dev *pdev = test->pdev; |
|---|
| .. | .. |
|---|
| 513 | 606 | size_t alignment = test->alignment; |
|---|
| 514 | 607 | int irq_type = test->irq_type; |
|---|
| 515 | 608 | u32 crc32; |
|---|
| 609 | + int err; |
|---|
| 516 | 610 | |
|---|
| 517 | | - if (size > SIZE_MAX - alignment) |
|---|
| 518 | | - goto err; |
|---|
| 611 | + err = copy_from_user(¶m, (void __user *)arg, sizeof(param)); |
|---|
| 612 | + if (err) { |
|---|
| 613 | + dev_err(dev, "Failed to get transfer param\n"); |
|---|
| 614 | + return false; |
|---|
| 615 | + } |
|---|
| 616 | + |
|---|
| 617 | + err = pci_endpoint_test_validate_xfer_params(dev, ¶m, alignment); |
|---|
| 618 | + if (err) |
|---|
| 619 | + return false; |
|---|
| 620 | + |
|---|
| 621 | + size = param.size; |
|---|
| 622 | + |
|---|
| 623 | + use_dma = !!(param.flags & PCITEST_FLAGS_USE_DMA); |
|---|
| 624 | + if (use_dma) |
|---|
| 625 | + flags |= FLAG_USE_DMA; |
|---|
| 519 | 626 | |
|---|
| 520 | 627 | if (irq_type < IRQ_TYPE_LEGACY || irq_type > IRQ_TYPE_MSIX) { |
|---|
| 521 | 628 | dev_err(dev, "Invalid IRQ type option\n"); |
|---|
| 522 | 629 | goto err; |
|---|
| 523 | 630 | } |
|---|
| 524 | 631 | |
|---|
| 525 | | - orig_addr = dma_alloc_coherent(dev, size + alignment, &orig_phys_addr, |
|---|
| 526 | | - GFP_KERNEL); |
|---|
| 632 | + orig_addr = kzalloc(size + alignment, GFP_KERNEL); |
|---|
| 527 | 633 | if (!orig_addr) { |
|---|
| 528 | 634 | dev_err(dev, "Failed to allocate destination address\n"); |
|---|
| 529 | 635 | ret = false; |
|---|
| 530 | 636 | goto err; |
|---|
| 637 | + } |
|---|
| 638 | + |
|---|
| 639 | + orig_phys_addr = dma_map_single(dev, orig_addr, size + alignment, |
|---|
| 640 | + DMA_FROM_DEVICE); |
|---|
| 641 | + if (dma_mapping_error(dev, orig_phys_addr)) { |
|---|
| 642 | + dev_err(dev, "failed to map source buffer address\n"); |
|---|
| 643 | + ret = false; |
|---|
| 644 | + goto err_phys_addr; |
|---|
| 531 | 645 | } |
|---|
| 532 | 646 | |
|---|
| 533 | 647 | if (alignment && !IS_ALIGNED(orig_phys_addr, alignment)) { |
|---|
| .. | .. |
|---|
| 546 | 660 | |
|---|
| 547 | 661 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_SIZE, size); |
|---|
| 548 | 662 | |
|---|
| 663 | + pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_FLAGS, flags); |
|---|
| 549 | 664 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE, irq_type); |
|---|
| 550 | 665 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, 1); |
|---|
| 551 | 666 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND, |
|---|
| .. | .. |
|---|
| 553 | 668 | |
|---|
| 554 | 669 | wait_for_completion(&test->irq_raised); |
|---|
| 555 | 670 | |
|---|
| 671 | + dma_unmap_single(dev, orig_phys_addr, size + alignment, |
|---|
| 672 | + DMA_FROM_DEVICE); |
|---|
| 673 | + |
|---|
| 556 | 674 | crc32 = crc32_le(~0, addr, size); |
|---|
| 557 | 675 | if (crc32 == pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_CHECKSUM)) |
|---|
| 558 | 676 | ret = true; |
|---|
| 559 | 677 | |
|---|
| 560 | | - dma_free_coherent(dev, size + alignment, orig_addr, orig_phys_addr); |
|---|
| 678 | +err_phys_addr: |
|---|
| 679 | + kfree(orig_addr); |
|---|
| 561 | 680 | err: |
|---|
| 562 | 681 | return ret; |
|---|
| 682 | +} |
|---|
| 683 | + |
|---|
| 684 | +static bool pci_endpoint_test_clear_irq(struct pci_endpoint_test *test) |
|---|
| 685 | +{ |
|---|
| 686 | + pci_endpoint_test_release_irq(test); |
|---|
| 687 | + pci_endpoint_test_free_irq_vectors(test); |
|---|
| 688 | + return true; |
|---|
| 563 | 689 | } |
|---|
| 564 | 690 | |
|---|
| 565 | 691 | static bool pci_endpoint_test_set_irq(struct pci_endpoint_test *test, |
|---|
| .. | .. |
|---|
| 632 | 758 | case PCITEST_GET_IRQTYPE: |
|---|
| 633 | 759 | ret = irq_type; |
|---|
| 634 | 760 | break; |
|---|
| 761 | + case PCITEST_CLEAR_IRQ: |
|---|
| 762 | + ret = pci_endpoint_test_clear_irq(test); |
|---|
| 763 | + break; |
|---|
| 635 | 764 | } |
|---|
| 636 | 765 | |
|---|
| 637 | 766 | ret: |
|---|
| .. | .. |
|---|
| 684 | 813 | init_completion(&test->irq_raised); |
|---|
| 685 | 814 | mutex_init(&test->mutex); |
|---|
| 686 | 815 | |
|---|
| 816 | + if ((dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(48)) != 0) && |
|---|
| 817 | + dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)) != 0) { |
|---|
| 818 | + dev_err(dev, "Cannot set DMA mask\n"); |
|---|
| 819 | + return -EINVAL; |
|---|
| 820 | + } |
|---|
| 821 | + |
|---|
| 687 | 822 | err = pci_enable_device(pdev); |
|---|
| 688 | 823 | if (err) { |
|---|
| 689 | 824 | dev_err(dev, "Cannot enable PCI device\n"); |
|---|
| .. | .. |
|---|
| 698 | 833 | |
|---|
| 699 | 834 | pci_set_master(pdev); |
|---|
| 700 | 835 | |
|---|
| 701 | | - if (!pci_endpoint_test_alloc_irq_vectors(test, irq_type)) |
|---|
| 836 | + if (!pci_endpoint_test_alloc_irq_vectors(test, irq_type)) { |
|---|
| 837 | + err = -EINVAL; |
|---|
| 702 | 838 | goto err_disable_irq; |
|---|
| 839 | + } |
|---|
| 703 | 840 | |
|---|
| 704 | | - if (!pci_endpoint_test_request_irq(test)) |
|---|
| 705 | | - goto err_disable_irq; |
|---|
| 706 | | - |
|---|
| 707 | | - for (bar = BAR_0; bar <= BAR_5; bar++) { |
|---|
| 841 | + for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) { |
|---|
| 708 | 842 | if (pci_resource_flags(pdev, bar) & IORESOURCE_MEM) { |
|---|
| 709 | 843 | base = pci_ioremap_bar(pdev, bar); |
|---|
| 710 | 844 | if (!base) { |
|---|
| .. | .. |
|---|
| 733 | 867 | } |
|---|
| 734 | 868 | |
|---|
| 735 | 869 | snprintf(name, sizeof(name), DRV_MODULE_NAME ".%d", id); |
|---|
| 870 | + test->name = kstrdup(name, GFP_KERNEL); |
|---|
| 871 | + if (!test->name) { |
|---|
| 872 | + err = -ENOMEM; |
|---|
| 873 | + goto err_ida_remove; |
|---|
| 874 | + } |
|---|
| 875 | + |
|---|
| 876 | + if (!pci_endpoint_test_request_irq(test)) { |
|---|
| 877 | + err = -EINVAL; |
|---|
| 878 | + goto err_kfree_test_name; |
|---|
| 879 | + } |
|---|
| 880 | + |
|---|
| 736 | 881 | misc_device = &test->miscdev; |
|---|
| 737 | 882 | misc_device->minor = MISC_DYNAMIC_MINOR; |
|---|
| 738 | 883 | misc_device->name = kstrdup(name, GFP_KERNEL); |
|---|
| 739 | 884 | if (!misc_device->name) { |
|---|
| 740 | 885 | err = -ENOMEM; |
|---|
| 741 | | - goto err_ida_remove; |
|---|
| 886 | + goto err_release_irq; |
|---|
| 742 | 887 | } |
|---|
| 743 | 888 | misc_device->fops = &pci_endpoint_test_fops, |
|---|
| 744 | 889 | |
|---|
| .. | .. |
|---|
| 753 | 898 | err_kfree_name: |
|---|
| 754 | 899 | kfree(misc_device->name); |
|---|
| 755 | 900 | |
|---|
| 901 | +err_release_irq: |
|---|
| 902 | + pci_endpoint_test_release_irq(test); |
|---|
| 903 | + |
|---|
| 904 | +err_kfree_test_name: |
|---|
| 905 | + kfree(test->name); |
|---|
| 906 | + |
|---|
| 756 | 907 | err_ida_remove: |
|---|
| 757 | 908 | ida_simple_remove(&pci_endpoint_test_ida, id); |
|---|
| 758 | 909 | |
|---|
| 759 | 910 | err_iounmap: |
|---|
| 760 | | - for (bar = BAR_0; bar <= BAR_5; bar++) { |
|---|
| 911 | + for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) { |
|---|
| 761 | 912 | if (test->bar[bar]) |
|---|
| 762 | 913 | pci_iounmap(pdev, test->bar[bar]); |
|---|
| 763 | 914 | } |
|---|
| 764 | | - pci_endpoint_test_release_irq(test); |
|---|
| 765 | 915 | |
|---|
| 766 | 916 | err_disable_irq: |
|---|
| 767 | 917 | pci_endpoint_test_free_irq_vectors(test); |
|---|
| .. | .. |
|---|
| 787 | 937 | |
|---|
| 788 | 938 | misc_deregister(&test->miscdev); |
|---|
| 789 | 939 | kfree(misc_device->name); |
|---|
| 940 | + kfree(test->name); |
|---|
| 790 | 941 | ida_simple_remove(&pci_endpoint_test_ida, id); |
|---|
| 791 | | - for (bar = BAR_0; bar <= BAR_5; bar++) { |
|---|
| 942 | + for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) { |
|---|
| 792 | 943 | if (test->bar[bar]) |
|---|
| 793 | 944 | pci_iounmap(pdev, test->bar[bar]); |
|---|
| 794 | 945 | } |
|---|
| .. | .. |
|---|
| 800 | 951 | pci_disable_device(pdev); |
|---|
| 801 | 952 | } |
|---|
| 802 | 953 | |
|---|
| 954 | +static const struct pci_endpoint_test_data default_data = { |
|---|
| 955 | + .test_reg_bar = BAR_0, |
|---|
| 956 | + .alignment = SZ_4K, |
|---|
| 957 | + .irq_type = IRQ_TYPE_MSI, |
|---|
| 958 | +}; |
|---|
| 959 | + |
|---|
| 803 | 960 | static const struct pci_endpoint_test_data am654_data = { |
|---|
| 804 | 961 | .test_reg_bar = BAR_2, |
|---|
| 805 | 962 | .alignment = SZ_64K, |
|---|
| 806 | 963 | .irq_type = IRQ_TYPE_MSI, |
|---|
| 807 | 964 | }; |
|---|
| 808 | 965 | |
|---|
| 966 | +static const struct pci_endpoint_test_data j721e_data = { |
|---|
| 967 | + .alignment = 256, |
|---|
| 968 | + .irq_type = IRQ_TYPE_MSI, |
|---|
| 969 | +}; |
|---|
| 970 | + |
|---|
| 809 | 971 | static const struct pci_device_id pci_endpoint_test_tbl[] = { |
|---|
| 810 | | - { PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_DRA74x) }, |
|---|
| 811 | | - { PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_DRA72x) }, |
|---|
| 812 | | - { PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, 0x81c0) }, |
|---|
| 972 | + { PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_DRA74x), |
|---|
| 973 | + .driver_data = (kernel_ulong_t)&default_data, |
|---|
| 974 | + }, |
|---|
| 975 | + { PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_DRA72x), |
|---|
| 976 | + .driver_data = (kernel_ulong_t)&default_data, |
|---|
| 977 | + }, |
|---|
| 978 | + { PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, 0x81c0), |
|---|
| 979 | + .driver_data = (kernel_ulong_t)&default_data, |
|---|
| 980 | + }, |
|---|
| 981 | + { PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, PCI_DEVICE_ID_LS1088A), |
|---|
| 982 | + .driver_data = (kernel_ulong_t)&default_data, |
|---|
| 983 | + }, |
|---|
| 813 | 984 | { PCI_DEVICE_DATA(SYNOPSYS, EDDA, NULL) }, |
|---|
| 814 | 985 | { PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_AM654), |
|---|
| 815 | 986 | .driver_data = (kernel_ulong_t)&am654_data |
|---|
| 816 | 987 | }, |
|---|
| 988 | + { PCI_DEVICE(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_R8A774A1),}, |
|---|
| 989 | + { PCI_DEVICE(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_R8A774B1),}, |
|---|
| 990 | + { PCI_DEVICE(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_R8A774C0),}, |
|---|
| 991 | + { PCI_DEVICE(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_R8A774E1),}, |
|---|
| 992 | + { PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_J721E), |
|---|
| 993 | + .driver_data = (kernel_ulong_t)&j721e_data, |
|---|
| 994 | + }, |
|---|
| 817 | 995 | { } |
|---|
| 818 | 996 | }; |
|---|
| 819 | 997 | MODULE_DEVICE_TABLE(pci, pci_endpoint_test_tbl); |
|---|