diff options
Diffstat (limited to 'drivers/pci/setup-bus.c')
-rw-r--r-- | drivers/pci/setup-bus.c | 81 |
1 files changed, 60 insertions, 21 deletions
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index fb506137aaee..1e808ca338f8 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c | |||
@@ -697,6 +697,38 @@ static resource_size_t calculate_memsize(resource_size_t size, | |||
697 | return size; | 697 | return size; |
698 | } | 698 | } |
699 | 699 | ||
700 | resource_size_t __weak pcibios_window_alignment(struct pci_bus *bus, | ||
701 | unsigned long type) | ||
702 | { | ||
703 | return 1; | ||
704 | } | ||
705 | |||
706 | #define PCI_P2P_DEFAULT_MEM_ALIGN 0x100000 /* 1MiB */ | ||
707 | #define PCI_P2P_DEFAULT_IO_ALIGN 0x1000 /* 4KiB */ | ||
708 | #define PCI_P2P_DEFAULT_IO_ALIGN_1K 0x400 /* 1KiB */ | ||
709 | |||
710 | static resource_size_t window_alignment(struct pci_bus *bus, | ||
711 | unsigned long type) | ||
712 | { | ||
713 | resource_size_t align = 1, arch_align; | ||
714 | |||
715 | if (type & IORESOURCE_MEM) | ||
716 | align = PCI_P2P_DEFAULT_MEM_ALIGN; | ||
717 | else if (type & IORESOURCE_IO) { | ||
718 | /* | ||
719 | * Per spec, I/O windows are 4K-aligned, but some | ||
720 | * bridges have an extension to support 1K alignment. | ||
721 | */ | ||
722 | if (bus->self->io_window_1k) | ||
723 | align = PCI_P2P_DEFAULT_IO_ALIGN_1K; | ||
724 | else | ||
725 | align = PCI_P2P_DEFAULT_IO_ALIGN; | ||
726 | } | ||
727 | |||
728 | arch_align = pcibios_window_alignment(bus, type); | ||
729 | return max(align, arch_align); | ||
730 | } | ||
731 | |||
700 | /** | 732 | /** |
701 | * pbus_size_io() - size the io window of a given bus | 733 | * pbus_size_io() - size the io window of a given bus |
702 | * | 734 | * |
@@ -717,17 +749,12 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size, | |||
717 | struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO); | 749 | struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO); |
718 | unsigned long size = 0, size0 = 0, size1 = 0; | 750 | unsigned long size = 0, size0 = 0, size1 = 0; |
719 | resource_size_t children_add_size = 0; | 751 | resource_size_t children_add_size = 0; |
720 | resource_size_t min_align = 4096, align; | 752 | resource_size_t min_align, io_align, align; |
721 | 753 | ||
722 | if (!b_res) | 754 | if (!b_res) |
723 | return; | 755 | return; |
724 | 756 | ||
725 | /* | 757 | io_align = min_align = window_alignment(bus, IORESOURCE_IO); |
726 | * Per spec, I/O windows are 4K-aligned, but some bridges have an | ||
727 | * extension to support 1K alignment. | ||
728 | */ | ||
729 | if (bus->self->io_window_1k) | ||
730 | min_align = 1024; | ||
731 | list_for_each_entry(dev, &bus->devices, bus_list) { | 758 | list_for_each_entry(dev, &bus->devices, bus_list) { |
732 | int i; | 759 | int i; |
733 | 760 | ||
@@ -754,8 +781,8 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size, | |||
754 | } | 781 | } |
755 | } | 782 | } |
756 | 783 | ||
757 | if (min_align > 4096) | 784 | if (min_align > io_align) |
758 | min_align = 4096; | 785 | min_align = io_align; |
759 | 786 | ||
760 | size0 = calculate_iosize(size, min_size, size1, | 787 | size0 = calculate_iosize(size, min_size, size1, |
761 | resource_size(b_res), min_align); | 788 | resource_size(b_res), min_align); |
@@ -785,6 +812,28 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size, | |||
785 | } | 812 | } |
786 | } | 813 | } |
787 | 814 | ||
815 | static inline resource_size_t calculate_mem_align(resource_size_t *aligns, | ||
816 | int max_order) | ||
817 | { | ||
818 | resource_size_t align = 0; | ||
819 | resource_size_t min_align = 0; | ||
820 | int order; | ||
821 | |||
822 | for (order = 0; order <= max_order; order++) { | ||
823 | resource_size_t align1 = 1; | ||
824 | |||
825 | align1 <<= (order + 20); | ||
826 | |||
827 | if (!align) | ||
828 | min_align = align1; | ||
829 | else if (ALIGN(align + min_align, min_align) < align1) | ||
830 | min_align = align1 >> 1; | ||
831 | align += aligns[order]; | ||
832 | } | ||
833 | |||
834 | return min_align; | ||
835 | } | ||
836 | |||
788 | /** | 837 | /** |
789 | * pbus_size_mem() - size the memory window of a given bus | 838 | * pbus_size_mem() - size the memory window of a given bus |
790 | * | 839 | * |
@@ -864,19 +913,9 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, | |||
864 | children_add_size += get_res_add_size(realloc_head, r); | 913 | children_add_size += get_res_add_size(realloc_head, r); |
865 | } | 914 | } |
866 | } | 915 | } |
867 | align = 0; | ||
868 | min_align = 0; | ||
869 | for (order = 0; order <= max_order; order++) { | ||
870 | resource_size_t align1 = 1; | ||
871 | 916 | ||
872 | align1 <<= (order + 20); | 917 | min_align = calculate_mem_align(aligns, max_order); |
873 | 918 | min_align = max(min_align, window_alignment(bus, b_res->flags & mask)); | |
874 | if (!align) | ||
875 | min_align = align1; | ||
876 | else if (ALIGN(align + min_align, min_align) < align1) | ||
877 | min_align = align1 >> 1; | ||
878 | align += aligns[order]; | ||
879 | } | ||
880 | size0 = calculate_memsize(size, min_size, 0, resource_size(b_res), min_align); | 919 | size0 = calculate_memsize(size, min_size, 0, resource_size(b_res), min_align); |
881 | if (children_add_size > add_size) | 920 | if (children_add_size > add_size) |
882 | add_size = children_add_size; | 921 | add_size = children_add_size; |