aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/pci-common.c
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2008-10-13 09:56:31 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2008-10-14 19:13:29 -0400
commitb556151110ff003ce77d84597400c84824690ccf (patch)
tree2c19b6c484c1930801bf194dab5d047e404c64d3 /arch/powerpc/kernel/pci-common.c
parenteef2622a9fcfa964073333ea72c7c9cd20ad45e6 (diff)
powerpc/pci: Improve detection of unassigned bridge resources
When the powerpc PCI layer is not configured to re-assign everything, it currently fails to detect that a PCI to PCI bridge has been left unassigned by the firmware and tries to allocate resource for the default window values in the bridge (0...X) (with the notable exception of a hack we have in there that detects some Apple firmware unassigned bridge resources). This results in resource allocation failures, which are generally fixed up later on but it causes scary warnings in the logs and we have seen the fixup code fall over in some circumstances (a different issue to fix as well). This code improves that by providing a more complete & useful function to intuit that a bridge was left unassigned by the firmware, and thus force a full re-allocation by the PCI code without trying to allocate the existing useless resources first. The algorithm we use basically considers unassigned a window that starts at 0 (PCI address) if the corresponding address space enable bit is not set. In addition, for memory space, it considers such a resource unassigned also if the host bridge isn't configured to forward cycles to address 0 (ie, the resource basically overlaps main memory). This fixes a range of problems with things like Bare-Metal support on pSeries machines, or attempt to use partial firmware PCI setup. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/kernel/pci-common.c')
-rw-r--r--arch/powerpc/kernel/pci-common.c163
1 files changed, 116 insertions, 47 deletions
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
index 8c0270929cc0..01ce8c38bae6 100644
--- a/arch/powerpc/kernel/pci-common.c
+++ b/arch/powerpc/kernel/pci-common.c
@@ -780,11 +780,6 @@ static void __devinit fixup_resource(struct resource *res, struct pci_dev *dev)
780 780
781 res->start = (res->start + offset) & mask; 781 res->start = (res->start + offset) & mask;
782 res->end = (res->end + offset) & mask; 782 res->end = (res->end + offset) & mask;
783
784 pr_debug("PCI:%s %016llx-%016llx\n",
785 pci_name(dev),
786 (unsigned long long)res->start,
787 (unsigned long long)res->end);
788} 783}
789 784
790 785
@@ -830,6 +825,11 @@ static void __devinit pcibios_fixup_resources(struct pci_dev *dev)
830 (unsigned int)res->flags); 825 (unsigned int)res->flags);
831 826
832 fixup_resource(res, dev); 827 fixup_resource(res, dev);
828
829 pr_debug("PCI:%s %016llx-%016llx\n",
830 pci_name(dev),
831 (unsigned long long)res->start,
832 (unsigned long long)res->end);
833 } 833 }
834 834
835 /* Call machine specific resource fixup */ 835 /* Call machine specific resource fixup */
@@ -838,58 +838,127 @@ static void __devinit pcibios_fixup_resources(struct pci_dev *dev)
838} 838}
839DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pcibios_fixup_resources); 839DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pcibios_fixup_resources);
840 840
841static void __devinit __pcibios_fixup_bus(struct pci_bus *bus) 841/* This function tries to figure out if a bridge resource has been initialized
842 * by the firmware or not. It doesn't have to be absolutely bullet proof, but
843 * things go more smoothly when it gets it right. It should covers cases such
844 * as Apple "closed" bridge resources and bare-metal pSeries unassigned bridges
845 */
846static int __devinit pcibios_uninitialized_bridge_resource(struct pci_bus *bus,
847 struct resource *res)
842{ 848{
843 struct pci_controller *hose = pci_bus_to_host(bus); 849 struct pci_controller *hose = pci_bus_to_host(bus);
844 struct pci_dev *dev = bus->self; 850 struct pci_dev *dev = bus->self;
851 resource_size_t offset;
852 u16 command;
853 int i;
845 854
846 pr_debug("PCI: Fixup bus %d (%s)\n", bus->number, dev ? pci_name(dev) : "PHB"); 855 /* We don't do anything if PCI_PROBE_ONLY is set */
856 if (ppc_pci_flags & PPC_PCI_PROBE_ONLY)
857 return 0;
847 858
848 /* Fixup PCI<->PCI bridges. Host bridges are handled separately, for 859 /* Job is a bit different between memory and IO */
849 * now differently between 32 and 64 bits. 860 if (res->flags & IORESOURCE_MEM) {
850 */ 861 /* If the BAR is non-0 (res != pci_mem_offset) then it's probably been
851 if (dev != NULL) { 862 * initialized by somebody
852 struct resource *res; 863 */
853 int i; 864 if (res->start != hose->pci_mem_offset)
865 return 0;
854 866
855 for (i = 0; i < PCI_BUS_NUM_RESOURCES; ++i) { 867 /* The BAR is 0, let's check if memory decoding is enabled on
856 if ((res = bus->resource[i]) == NULL) 868 * the bridge. If not, we consider it unassigned
857 continue; 869 */
858 if (!res->flags) 870 pci_read_config_word(dev, PCI_COMMAND, &command);
859 continue; 871 if ((command & PCI_COMMAND_MEMORY) == 0)
860 if (i >= 3 && bus->self->transparent) 872 return 1;
861 continue;
862 /* On PowerMac, Apple leaves bridge windows open over
863 * an inaccessible region of memory space (0...fffff)
864 * which is somewhat bogus, but that's what they think
865 * means disabled...
866 *
867 * We clear those to force them to be reallocated later
868 *
869 * We detect such regions by the fact that the base is
870 * equal to the pci_mem_offset of the host bridge and
871 * their size is smaller than 1M.
872 */
873 if (res->flags & IORESOURCE_MEM &&
874 res->start == hose->pci_mem_offset &&
875 res->end < 0x100000) {
876 printk(KERN_INFO
877 "PCI: Closing bogus Apple Firmware"
878 " region %d on bus 0x%02x\n",
879 i, bus->number);
880 res->flags = 0;
881 continue;
882 }
883 873
884 pr_debug("PCI:%s Bus rsrc %d %016llx-%016llx [%x] fixup...\n", 874 /* Memory decoding is enabled and the BAR is 0. If any of the bridge
885 pci_name(dev), i, 875 * resources covers that starting address (0 then it's good enough for
886 (unsigned long long)res->start,\ 876 * us for memory
887 (unsigned long long)res->end, 877 */
888 (unsigned int)res->flags); 878 for (i = 0; i < 3; i++) {
879 if ((hose->mem_resources[i].flags & IORESOURCE_MEM) &&
880 hose->mem_resources[i].start == hose->pci_mem_offset)
881 return 0;
882 }
883
884 /* Well, it starts at 0 and we know it will collide so we may as
885 * well consider it as unassigned. That covers the Apple case.
886 */
887 return 1;
888 } else {
889 /* If the BAR is non-0, then we consider it assigned */
890 offset = (unsigned long)hose->io_base_virt - _IO_BASE;
891 if (((res->start - offset) & 0xfffffffful) != 0)
892 return 0;
893
894 /* Here, we are a bit different than memory as typically IO space
895 * starting at low addresses -is- valid. What we do instead if that
896 * we consider as unassigned anything that doesn't have IO enabled
897 * in the PCI command register, and that's it.
898 */
899 pci_read_config_word(dev, PCI_COMMAND, &command);
900 if (command & PCI_COMMAND_IO)
901 return 0;
902
903 /* It's starting at 0 and IO is disabled in the bridge, consider
904 * it unassigned
905 */
906 return 1;
907 }
908}
909
910/* Fixup resources of a PCI<->PCI bridge */
911static void __devinit pcibios_fixup_bridge(struct pci_bus *bus)
912{
913 struct resource *res;
914 int i;
915
916 struct pci_dev *dev = bus->self;
889 917
890 fixup_resource(res, dev); 918 for (i = 0; i < PCI_BUS_NUM_RESOURCES; ++i) {
919 if ((res = bus->resource[i]) == NULL)
920 continue;
921 if (!res->flags)
922 continue;
923 if (i >= 3 && bus->self->transparent)
924 continue;
925
926 pr_debug("PCI:%s Bus rsrc %d %016llx-%016llx [%x] fixup...\n",
927 pci_name(dev), i,
928 (unsigned long long)res->start,\
929 (unsigned long long)res->end,
930 (unsigned int)res->flags);
931
932 /* Perform fixup */
933 fixup_resource(res, dev);
934
935 /* Try to detect uninitialized P2P bridge resources,
936 * and clear them out so they get re-assigned later
937 */
938 if (pcibios_uninitialized_bridge_resource(bus, res)) {
939 res->flags = 0;
940 pr_debug("PCI:%s (unassigned)\n", pci_name(dev));
941 } else {
942
943 pr_debug("PCI:%s %016llx-%016llx\n",
944 pci_name(dev),
945 (unsigned long long)res->start,
946 (unsigned long long)res->end);
891 } 947 }
892 } 948 }
949}
950
951static void __devinit __pcibios_fixup_bus(struct pci_bus *bus)
952{
953 struct pci_dev *dev = bus->self;
954
955 pr_debug("PCI: Fixup bus %d (%s)\n", bus->number, dev ? pci_name(dev) : "PHB");
956
957 /* Fixup PCI<->PCI bridges. Host bridges are handled separately, for
958 * now differently between 32 and 64 bits.
959 */
960 if (dev != NULL)
961 pcibios_fixup_bridge(bus);
893 962
894 /* Additional setup that is different between 32 and 64 bits for now */ 963 /* Additional setup that is different between 32 and 64 bits for now */
895 pcibios_do_bus_setup(bus); 964 pcibios_do_bus_setup(bus);