|
5 | 5 | #include <linux/module.h>
|
6 | 6 | #include <linux/of_address.h>
|
7 | 7 | #include <linux/pci_regs.h>
|
| 8 | +#include <linux/sizes.h> |
| 9 | +#include <linux/slab.h> |
8 | 10 | #include <linux/string.h>
|
9 | 11 |
|
10 | 12 | /* Max address size we deal with */
|
@@ -601,12 +603,119 @@ const __be32 *of_get_address(struct device_node *dev, int index, u64 *size,
|
601 | 603 | }
|
602 | 604 | EXPORT_SYMBOL(of_get_address);
|
603 | 605 |
|
| 606 | +#ifdef PCI_IOBASE |
| 607 | +struct io_range { |
| 608 | + struct list_head list; |
| 609 | + phys_addr_t start; |
| 610 | + resource_size_t size; |
| 611 | +}; |
| 612 | + |
| 613 | +static LIST_HEAD(io_range_list); |
| 614 | +static DEFINE_SPINLOCK(io_range_lock); |
| 615 | +#endif |
| 616 | + |
| 617 | +/* |
| 618 | + * Record the PCI IO range (expressed as CPU physical address + size). |
| 619 | + * Return a negative value if an error has occured, zero otherwise |
| 620 | + */ |
| 621 | +int __weak pci_register_io_range(phys_addr_t addr, resource_size_t size) |
| 622 | +{ |
| 623 | + int err = 0; |
| 624 | + |
| 625 | +#ifdef PCI_IOBASE |
| 626 | + struct io_range *range; |
| 627 | + resource_size_t allocated_size = 0; |
| 628 | + |
| 629 | + /* check if the range hasn't been previously recorded */ |
| 630 | + spin_lock(&io_range_lock); |
| 631 | + list_for_each_entry(range, &io_range_list, list) { |
| 632 | + if (addr >= range->start && addr + size <= range->start + size) { |
| 633 | + /* range already registered, bail out */ |
| 634 | + goto end_register; |
| 635 | + } |
| 636 | + allocated_size += range->size; |
| 637 | + } |
| 638 | + |
| 639 | + /* range not registed yet, check for available space */ |
| 640 | + if (allocated_size + size - 1 > IO_SPACE_LIMIT) { |
| 641 | + /* if it's too big check if 64K space can be reserved */ |
| 642 | + if (allocated_size + SZ_64K - 1 > IO_SPACE_LIMIT) { |
| 643 | + err = -E2BIG; |
| 644 | + goto end_register; |
| 645 | + } |
| 646 | + |
| 647 | + size = SZ_64K; |
| 648 | + pr_warn("Requested IO range too big, new size set to 64K\n"); |
| 649 | + } |
| 650 | + |
| 651 | + /* add the range to the list */ |
| 652 | + range = kzalloc(sizeof(*range), GFP_KERNEL); |
| 653 | + if (!range) { |
| 654 | + err = -ENOMEM; |
| 655 | + goto end_register; |
| 656 | + } |
| 657 | + |
| 658 | + range->start = addr; |
| 659 | + range->size = size; |
| 660 | + |
| 661 | + list_add_tail(&range->list, &io_range_list); |
| 662 | + |
| 663 | +end_register: |
| 664 | + spin_unlock(&io_range_lock); |
| 665 | +#endif |
| 666 | + |
| 667 | + return err; |
| 668 | +} |
| 669 | + |
| 670 | +phys_addr_t pci_pio_to_address(unsigned long pio) |
| 671 | +{ |
| 672 | + phys_addr_t address = (phys_addr_t)OF_BAD_ADDR; |
| 673 | + |
| 674 | +#ifdef PCI_IOBASE |
| 675 | + struct io_range *range; |
| 676 | + resource_size_t allocated_size = 0; |
| 677 | + |
| 678 | + if (pio > IO_SPACE_LIMIT) |
| 679 | + return address; |
| 680 | + |
| 681 | + spin_lock(&io_range_lock); |
| 682 | + list_for_each_entry(range, &io_range_list, list) { |
| 683 | + if (pio >= allocated_size && pio < allocated_size + range->size) { |
| 684 | + address = range->start + pio - allocated_size; |
| 685 | + break; |
| 686 | + } |
| 687 | + allocated_size += range->size; |
| 688 | + } |
| 689 | + spin_unlock(&io_range_lock); |
| 690 | +#endif |
| 691 | + |
| 692 | + return address; |
| 693 | +} |
| 694 | + |
604 | 695 | unsigned long __weak pci_address_to_pio(phys_addr_t address)
|
605 | 696 | {
|
| 697 | +#ifdef PCI_IOBASE |
| 698 | + struct io_range *res; |
| 699 | + resource_size_t offset = 0; |
| 700 | + unsigned long addr = -1; |
| 701 | + |
| 702 | + spin_lock(&io_range_lock); |
| 703 | + list_for_each_entry(res, &io_range_list, list) { |
| 704 | + if (address >= res->start && address < res->start + res->size) { |
| 705 | + addr = res->start - address + offset; |
| 706 | + break; |
| 707 | + } |
| 708 | + offset += res->size; |
| 709 | + } |
| 710 | + spin_unlock(&io_range_lock); |
| 711 | + |
| 712 | + return addr; |
| 713 | +#else |
606 | 714 | if (address > IO_SPACE_LIMIT)
|
607 | 715 | return (unsigned long)-1;
|
608 | 716 |
|
609 | 717 | return (unsigned long) address;
|
| 718 | +#endif |
610 | 719 | }
|
611 | 720 |
|
612 | 721 | static int __of_address_to_resource(struct device_node *dev,
|
|
0 commit comments