powerpc/pci: Fix MODPOST warning
[safe/jmp/linux-2.6] / arch / powerpc / kernel / pci-common.c
index 7d0afd4..e8dfdbd 100644 (file)
@@ -16,8 +16,6 @@
  * 2 of the License, or (at your option) any later version.
  */
 
-#undef DEBUG
-
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/string.h>
 #include <asm/machdep.h>
 #include <asm/ppc-pci.h>
 #include <asm/firmware.h>
-
-#ifdef DEBUG
-#include <asm/udbg.h>
-#define DBG(fmt...) printk(fmt)
-#else
-#define DBG(fmt...)
-#endif
+#include <asm/eeh.h>
 
 static DEFINE_SPINLOCK(hose_spinlock);
+LIST_HEAD(hose_list);
 
 /* XXX kill that some day ... */
 static int global_phb_number;          /* Global phb counter */
@@ -53,8 +46,37 @@ static int global_phb_number;                /* Global phb counter */
 /* ISA Memory physical address */
 resource_size_t isa_mem_base;
 
-/* Default PCI flags is 0 */
-unsigned int ppc_pci_flags;
+/* Default PCI flags is 0 on ppc32, modified at boot on ppc64 */
+unsigned int ppc_pci_flags = 0;
+
+
+static struct dma_map_ops *pci_dma_ops = &dma_direct_ops;
+
+void set_pci_dma_ops(struct dma_map_ops *dma_ops)
+{
+       pci_dma_ops = dma_ops;
+}
+
+struct dma_map_ops *get_pci_dma_ops(void)
+{
+       return pci_dma_ops;
+}
+EXPORT_SYMBOL(get_pci_dma_ops);
+
+int pci_set_dma_mask(struct pci_dev *dev, u64 mask)
+{
+       return dma_set_mask(&dev->dev, mask);
+}
+
+int pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask)
+{
+       int rc;
+
+       rc = dma_set_mask(&dev->dev, mask);
+       dev->dev.coherent_dma_mask = dev->dma_mask;
+
+       return rc;
+}
 
 struct pci_controller *pcibios_alloc_controller(struct device_node *dev)
 {
@@ -92,19 +114,24 @@ void pcibios_free_controller(struct pci_controller *phb)
                kfree(phb);
 }
 
+static resource_size_t pcibios_io_size(const struct pci_controller *hose)
+{
+#ifdef CONFIG_PPC64
+       return hose->pci_io_size;
+#else
+       return hose->io_resource.end - hose->io_resource.start + 1;
+#endif
+}
+
 int pcibios_vaddr_is_ioport(void __iomem *address)
 {
        int ret = 0;
        struct pci_controller *hose;
-       unsigned long size;
+       resource_size_t size;
 
        spin_lock(&hose_spinlock);
        list_for_each_entry(hose, &hose_list, list_node) {
-#ifdef CONFIG_PPC64
-               size = hose->pci_io_size;
-#else
-               size = hose->io_resource.end - hose->io_resource.start + 1;
-#endif
+               size = pcibios_io_size(hose);
                if (address >= hose->io_base_virt &&
                    address < (hose->io_base_virt + size)) {
                        ret = 1;
@@ -115,6 +142,29 @@ int pcibios_vaddr_is_ioport(void __iomem *address)
        return ret;
 }
 
+unsigned long pci_address_to_pio(phys_addr_t address)
+{
+       struct pci_controller *hose;
+       resource_size_t size;
+       unsigned long ret = ~0;
+
+       spin_lock(&hose_spinlock);
+       list_for_each_entry(hose, &hose_list, list_node) {
+               size = pcibios_io_size(hose);
+               if (address >= hose->io_base_phys &&
+                   address < (hose->io_base_phys + size)) {
+                       unsigned long base =
+                               (unsigned long)hose->io_base_virt - _IO_BASE;
+                       ret = base + (address - hose->io_base_phys);
+                       break;
+               }
+       }
+       spin_unlock(&hose_spinlock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(pci_address_to_pio);
+
 /*
  * Return the domain number for this bus.
  */
@@ -126,8 +176,6 @@ int pci_domain_nr(struct pci_bus *bus)
 }
 EXPORT_SYMBOL(pci_domain_nr);
 
-#ifdef CONFIG_PPC_OF
-
 /* This routine is meant to be used early during boot, when the
  * PCI bus numbers have not yet been assigned, and you need to
  * issue PCI config cycles to an OF device.
@@ -137,8 +185,6 @@ EXPORT_SYMBOL(pci_domain_nr);
  */
 struct pci_controller* pci_find_hose_for_OF_device(struct device_node* node)
 {
-       if (!have_of)
-               return NULL;
        while(node) {
                struct pci_controller *hose, *tmp;
                list_for_each_entry_safe(hose, tmp, &hose_list, list_node)
@@ -162,17 +208,11 @@ static ssize_t pci_show_devspec(struct device *dev,
        return sprintf(buf, "%s", np->full_name);
 }
 static DEVICE_ATTR(devspec, S_IRUGO, pci_show_devspec, NULL);
-#endif /* CONFIG_PPC_OF */
 
 /* Add sysfs properties */
 int pcibios_add_platform_entries(struct pci_dev *pdev)
 {
-#ifdef CONFIG_PPC_OF
        return device_create_file(&pdev->dev, &dev_attr_devspec);
-#else
-       return 0;
-#endif /* CONFIG_PPC_OF */
-
 }
 
 char __devinit *pcibios_setup(char *str)
@@ -204,7 +244,7 @@ int pci_read_irq_line(struct pci_dev *pci_dev)
                return -1;
 #endif
 
-       DBG("Try to map irq for %s...\n", pci_name(pci_dev));
+       pr_debug("PCI: Try to map irq for %s...\n", pci_name(pci_dev));
 
 #ifdef DEBUG
        memset(&oirq, 0xff, sizeof(oirq));
@@ -228,26 +268,27 @@ int pci_read_irq_line(struct pci_dev *pci_dev)
                    line == 0xff || line == 0) {
                        return -1;
                }
-               DBG(" -> no map ! Using line %d (pin %d) from PCI config\n",
-                   line, pin);
+               pr_debug(" No map ! Using line %d (pin %d) from PCI config\n",
+                        line, pin);
 
                virq = irq_create_mapping(NULL, line);
                if (virq != NO_IRQ)
                        set_irq_type(virq, IRQ_TYPE_LEVEL_LOW);
        } else {
-               DBG(" -> got one, spec %d cells (0x%08x 0x%08x...) on %s\n",
-                   oirq.size, oirq.specifier[0], oirq.specifier[1],
-                   oirq.controller->full_name);
+               pr_debug(" Got one, spec %d cells (0x%08x 0x%08x...) on %s\n",
+                        oirq.size, oirq.specifier[0], oirq.specifier[1],
+                        oirq.controller ? oirq.controller->full_name :
+                        "<default>");
 
                virq = irq_create_of_mapping(oirq.controller, oirq.specifier,
                                             oirq.size);
        }
        if(virq == NO_IRQ) {
-               DBG(" -> failed to map !\n");
+               pr_debug(" Failed to map !\n");
                return -1;
        }
 
-       DBG(" -> mapped to linux irq %d\n", virq);
+       pr_debug(" Mapped to linux irq %d\n", virq);
 
        pci_dev->irq = virq;
 
@@ -349,13 +390,10 @@ static pgprot_t __pci_mmap_set_pgprot(struct pci_dev *dev, struct resource *rp,
        }
 
        /* XXX would be nice to have a way to ask for write-through */
-       prot |= _PAGE_NO_CACHE;
        if (write_combine)
-               prot &= ~_PAGE_GUARDED;
+               return pgprot_noncached_wc(prot);
        else
-               prot |= _PAGE_GUARDED;
-
-       return __pgprot(prot);
+               return pgprot_noncached(prot);
 }
 
 /*
@@ -366,19 +404,17 @@ static pgprot_t __pci_mmap_set_pgprot(struct pci_dev *dev, struct resource *rp,
 pgprot_t pci_phys_mem_access_prot(struct file *file,
                                  unsigned long pfn,
                                  unsigned long size,
-                                 pgprot_t protection)
+                                 pgprot_t prot)
 {
        struct pci_dev *pdev = NULL;
        struct resource *found = NULL;
-       unsigned long prot = pgprot_val(protection);
-       unsigned long offset = pfn << PAGE_SHIFT;
+       resource_size_t offset = ((resource_size_t)pfn) << PAGE_SHIFT;
        int i;
 
        if (page_is_ram(pfn))
-               return __pgprot(prot);
-
-       prot |= _PAGE_NO_CACHE | _PAGE_GUARDED;
+               return prot;
 
+       prot = pgprot_noncached(prot);
        for_each_pci_dev(pdev) {
                for (i = 0; i <= PCI_ROM_RESOURCE; i++) {
                        struct resource *rp = &pdev->resource[i];
@@ -399,13 +435,14 @@ pgprot_t pci_phys_mem_access_prot(struct file *file,
        }
        if (found) {
                if (found->flags & IORESOURCE_PREFETCH)
-                       prot &= ~_PAGE_GUARDED;
+                       prot = pgprot_noncached_wc(prot);
                pci_dev_put(pdev);
        }
 
-       DBG("non-PCI map for %lx, prot: %lx\n", offset, prot);
+       pr_debug("PCI: Non-PCI map for %llx, prot: %lx\n",
+                (unsigned long long)offset, pgprot_val(prot));
 
-       return __pgprot(prot);
+       return prot;
 }
 
 
@@ -422,7 +459,8 @@ pgprot_t pci_phys_mem_access_prot(struct file *file,
 int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
                        enum pci_mmap_state mmap_state, int write_combine)
 {
-       resource_size_t offset = vma->vm_pgoff << PAGE_SHIFT;
+       resource_size_t offset =
+               ((resource_size_t)vma->vm_pgoff) << PAGE_SHIFT;
        struct resource *rp;
        int ret;
 
@@ -441,6 +479,144 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
        return ret;
 }
 
+/* This provides legacy IO read access on a bus */
+int pci_legacy_read(struct pci_bus *bus, loff_t port, u32 *val, size_t size)
+{
+       unsigned long offset;
+       struct pci_controller *hose = pci_bus_to_host(bus);
+       struct resource *rp = &hose->io_resource;
+       void __iomem *addr;
+
+       /* Check if port can be supported by that bus. We only check
+        * the ranges of the PHB though, not the bus itself as the rules
+        * for forwarding legacy cycles down bridges are not our problem
+        * here. So if the host bridge supports it, we do it.
+        */
+       offset = (unsigned long)hose->io_base_virt - _IO_BASE;
+       offset += port;
+
+       if (!(rp->flags & IORESOURCE_IO))
+               return -ENXIO;
+       if (offset < rp->start || (offset + size) > rp->end)
+               return -ENXIO;
+       addr = hose->io_base_virt + port;
+
+       switch(size) {
+       case 1:
+               *((u8 *)val) = in_8(addr);
+               return 1;
+       case 2:
+               if (port & 1)
+                       return -EINVAL;
+               *((u16 *)val) = in_le16(addr);
+               return 2;
+       case 4:
+               if (port & 3)
+                       return -EINVAL;
+               *((u32 *)val) = in_le32(addr);
+               return 4;
+       }
+       return -EINVAL;
+}
+
+/* This provides legacy IO write access on a bus */
+int pci_legacy_write(struct pci_bus *bus, loff_t port, u32 val, size_t size)
+{
+       unsigned long offset;
+       struct pci_controller *hose = pci_bus_to_host(bus);
+       struct resource *rp = &hose->io_resource;
+       void __iomem *addr;
+
+       /* Check if port can be supported by that bus. We only check
+        * the ranges of the PHB though, not the bus itself as the rules
+        * for forwarding legacy cycles down bridges are not our problem
+        * here. So if the host bridge supports it, we do it.
+        */
+       offset = (unsigned long)hose->io_base_virt - _IO_BASE;
+       offset += port;
+
+       if (!(rp->flags & IORESOURCE_IO))
+               return -ENXIO;
+       if (offset < rp->start || (offset + size) > rp->end)
+               return -ENXIO;
+       addr = hose->io_base_virt + port;
+
+       /* WARNING: The generic code is idiotic. It gets passed a pointer
+        * to what can be a 1, 2 or 4 byte quantity and always reads that
+        * as a u32, which means that we have to correct the location of
+        * the data read within those 32 bits for size 1 and 2
+        */
+       switch(size) {
+       case 1:
+               out_8(addr, val >> 24);
+               return 1;
+       case 2:
+               if (port & 1)
+                       return -EINVAL;
+               out_le16(addr, val >> 16);
+               return 2;
+       case 4:
+               if (port & 3)
+                       return -EINVAL;
+               out_le32(addr, val);
+               return 4;
+       }
+       return -EINVAL;
+}
+
+/* This provides legacy IO or memory mmap access on a bus */
+int pci_mmap_legacy_page_range(struct pci_bus *bus,
+                              struct vm_area_struct *vma,
+                              enum pci_mmap_state mmap_state)
+{
+       struct pci_controller *hose = pci_bus_to_host(bus);
+       resource_size_t offset =
+               ((resource_size_t)vma->vm_pgoff) << PAGE_SHIFT;
+       resource_size_t size = vma->vm_end - vma->vm_start;
+       struct resource *rp;
+
+       pr_debug("pci_mmap_legacy_page_range(%04x:%02x, %s @%llx..%llx)\n",
+                pci_domain_nr(bus), bus->number,
+                mmap_state == pci_mmap_mem ? "MEM" : "IO",
+                (unsigned long long)offset,
+                (unsigned long long)(offset + size - 1));
+
+       if (mmap_state == pci_mmap_mem) {
+               /* Hack alert !
+                *
+                * Because X is lame and can fail starting if it gets an error trying
+                * to mmap legacy_mem (instead of just moving on without legacy memory
+                * access) we fake it here by giving it anonymous memory, effectively
+                * behaving just like /dev/zero
+                */
+               if ((offset + size) > hose->isa_mem_size) {
+                       printk(KERN_DEBUG
+                              "Process %s (pid:%d) mapped non-existing PCI legacy memory for 0%04x:%02x\n",
+                              current->comm, current->pid, pci_domain_nr(bus), bus->number);
+                       if (vma->vm_flags & VM_SHARED)
+                               return shmem_zero_setup(vma);
+                       return 0;
+               }
+               offset += hose->isa_mem_phys;
+       } else {
+               unsigned long io_offset = (unsigned long)hose->io_base_virt - _IO_BASE;
+               unsigned long roffset = offset + io_offset;
+               rp = &hose->io_resource;
+               if (!(rp->flags & IORESOURCE_IO))
+                       return -ENXIO;
+               if (roffset < rp->start || (roffset + size) > rp->end)
+                       return -ENXIO;
+               offset += hose->io_base_phys;
+       }
+       pr_debug(" -> mapping phys %llx\n", (unsigned long long)offset);
+
+       vma->vm_pgoff = offset >> PAGE_SHIFT;
+       vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+       return remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
+                              vma->vm_end - vma->vm_start,
+                              vma->vm_page_prot);
+}
+
 void pci_resource_to_user(const struct pci_dev *dev, int bar,
                          const struct resource *rsrc,
                          resource_size_t *start, resource_size_t *end)
@@ -543,6 +719,12 @@ void __devinit pci_process_bridge_OF_ranges(struct pci_controller *hose,
                cpu_addr = of_translate_address(dev, ranges + 3);
                size = of_read_number(ranges + pna + 3, 2);
                ranges += np;
+
+               /* If we failed translation or got a zero-sized region
+                * (some FW try to feed us with non sensical zero sized regions
+                * such as power3 which look like some kind of attempt at exposing
+                * the VGA memory hole)
+                */
                if (cpu_addr == OF_BAD_ADDR || size == 0)
                        continue;
 
@@ -598,6 +780,7 @@ void __devinit pci_process_bridge_OF_ranges(struct pci_controller *hose,
                        res->start = pci_addr;
                        break;
                case 2:         /* PCI Memory space */
+               case 3:         /* PCI 64 bits Memory space */
                        printk(KERN_INFO
                               " MEM 0x%016llx..0x%016llx -> 0x%016llx %s\n",
                               cpu_addr, cpu_addr + size - 1, pci_addr,
@@ -615,6 +798,8 @@ void __devinit pci_process_bridge_OF_ranges(struct pci_controller *hose,
                                isa_hole = memno;
                                if (primary || isa_mem_base == 0)
                                        isa_mem_base = cpu_addr;
+                               hose->isa_mem_phys = cpu_addr;
+                               hose->isa_mem_size = size;
                        }
 
                        /* We get the PCI/Mem offset from the first range or
@@ -649,11 +834,18 @@ void __devinit pci_process_bridge_OF_ranges(struct pci_controller *hose,
                }
        }
 
-       /* Out of paranoia, let's put the ISA hole last if any */
-       if (isa_hole >= 0 && memno > 0 && isa_hole != (memno-1)) {
-               struct resource tmp = hose->mem_resources[isa_hole];
-               hose->mem_resources[isa_hole] = hose->mem_resources[memno-1];
-               hose->mem_resources[memno-1] = tmp;
+       /* If there's an ISA hole and the pci_mem_offset is -not- matching
+        * the ISA hole offset, then we need to remove the ISA hole from
+        * the resource list for that brige
+        */
+       if (isa_hole >= 0 && hose->pci_mem_offset != isa_mb) {
+               unsigned int next = isa_hole + 1;
+               printk(KERN_INFO " Removing ISA hole at 0x%016llx\n", isa_mb);
+               if (next < memno)
+                       memmove(&hose->mem_resources[isa_hole],
+                               &hose->mem_resources[next],
+                               sizeof(struct resource) * (memno - next));
+               hose->mem_resources[--memno].flags = 0;
        }
 }
 
@@ -661,15 +853,12 @@ void __devinit pci_process_bridge_OF_ranges(struct pci_controller *hose,
 int pci_proc_domain(struct pci_bus *bus)
 {
        struct pci_controller *hose = pci_bus_to_host(bus);
-#ifdef CONFIG_PPC64
-       return hose->buid != 0;
-#else
+
        if (!(ppc_pci_flags & PPC_PCI_ENABLE_PROC_DOMAINS))
                return 0;
        if (ppc_pci_flags & PPC_PCI_COMPAT_DOMAIN_0)
                return hose->global_number != 0;
        return 1;
-#endif
 }
 
 void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
@@ -723,11 +912,6 @@ static void __devinit fixup_resource(struct resource *res, struct pci_dev *dev)
 
        res->start = (res->start + offset) & mask;
        res->end = (res->end + offset) & mask;
-
-       pr_debug("PCI:%s            %016llx-%016llx\n",
-                pci_name(dev),
-                (unsigned long long)res->start,
-                (unsigned long long)res->end);
 }
 
 
@@ -748,7 +932,13 @@ static void __devinit pcibios_fixup_resources(struct pci_dev *dev)
                struct resource *res = dev->resource + i;
                if (!res->flags)
                        continue;
-               if (res->end == 0xffffffff) {
+               /* On platforms that have PPC_PCI_PROBE_ONLY set, we don't
+                * consider 0 as an unassigned BAR value. It's technically
+                * a valid value, but linux doesn't like it... so when we can
+                * re-assign things, we do so, but if we can't, we keep it
+                * around and hope for the best...
+                */
+               if (res->start == 0 && !(ppc_pci_flags & PPC_PCI_PROBE_ONLY)) {
                        pr_debug("PCI:%s Resource %d %016llx-%016llx [%x] is unassigned\n",
                                 pci_name(dev), i,
                                 (unsigned long long)res->start,
@@ -767,6 +957,11 @@ static void __devinit pcibios_fixup_resources(struct pci_dev *dev)
                         (unsigned int)res->flags);
 
                fixup_resource(res, dev);
+
+               pr_debug("PCI:%s            %016llx-%016llx\n",
+                        pci_name(dev),
+                        (unsigned long long)res->start,
+                        (unsigned long long)res->end);
        }
 
        /* Call machine specific resource fixup */
@@ -775,67 +970,160 @@ static void __devinit pcibios_fixup_resources(struct pci_dev *dev)
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pcibios_fixup_resources);
 
-static void __devinit __pcibios_fixup_bus(struct pci_bus *bus)
+/* This function tries to figure out if a bridge resource has been initialized
+ * by the firmware or not. It doesn't have to be absolutely bullet proof, but
+ * things go more smoothly when it gets it right. It should covers cases such
+ * as Apple "closed" bridge resources and bare-metal pSeries unassigned bridges
+ */
+static int __devinit pcibios_uninitialized_bridge_resource(struct pci_bus *bus,
+                                                          struct resource *res)
 {
        struct pci_controller *hose = pci_bus_to_host(bus);
        struct pci_dev *dev = bus->self;
+       resource_size_t offset;
+       u16 command;
+       int i;
 
-       pr_debug("PCI: Fixup bus %d (%s)\n", bus->number, dev ? pci_name(dev) : "PHB");
+       /* We don't do anything if PCI_PROBE_ONLY is set */
+       if (ppc_pci_flags & PPC_PCI_PROBE_ONLY)
+               return 0;
 
-       /* Fixup PCI<->PCI bridges. Host bridges are handled separately, for
-        * now differently between 32 and 64 bits.
-        */
-       if (dev != NULL) {
-               struct resource *res;
-               int i;
+       /* Job is a bit different between memory and IO */
+       if (res->flags & IORESOURCE_MEM) {
+               /* If the BAR is non-0 (res != pci_mem_offset) then it's probably been
+                * initialized by somebody
+                */
+               if (res->start != hose->pci_mem_offset)
+                       return 0;
 
-               for (i = 0; i < PCI_BUS_NUM_RESOURCES; ++i) {
-                       if ((res = bus->resource[i]) == NULL)
-                               continue;
-                       if (!res->flags || bus->self->transparent)
-                               continue;
+               /* The BAR is 0, let's check if memory decoding is enabled on
+                * the bridge. If not, we consider it unassigned
+                */
+               pci_read_config_word(dev, PCI_COMMAND, &command);
+               if ((command & PCI_COMMAND_MEMORY) == 0)
+                       return 1;
 
-                       /* On PowerMac, Apple leaves bridge windows open over
-                        * an inaccessible region of memory space (0...fffff)
-                        * which is somewhat bogus, but that's what they think
-                        * means disabled...
-                        *
-                        * We clear those to force them to be reallocated later
-                        *
-                        * We detect such regions by the fact that the base is
-                        * equal to the pci_mem_offset of the host bridge and
-                        * their size is smaller than 1M.
-                        */
-                       if (res->flags & IORESOURCE_MEM &&
-                           res->start == hose->pci_mem_offset &&
-                           res->end < 0x100000) {
-                               printk(KERN_INFO
-                                      "PCI: Closing bogus Apple Firmware"
-                                      " region %d on bus 0x%02x\n",
-                                      i, bus->number);
-                               res->flags = 0;
-                               continue;
-                       }
+               /* Memory decoding is enabled and the BAR is 0. If any of the bridge
+                * resources covers that starting address (0 then it's good enough for
+                * us for memory
+                */
+               for (i = 0; i < 3; i++) {
+                       if ((hose->mem_resources[i].flags & IORESOURCE_MEM) &&
+                           hose->mem_resources[i].start == hose->pci_mem_offset)
+                               return 0;
+               }
 
-                       pr_debug("PCI:%s Bus rsrc %d %016llx-%016llx [%x] fixup...\n",
-                                pci_name(dev), i,
-                                (unsigned long long)res->start,\
-                                (unsigned long long)res->end,
-                                (unsigned int)res->flags);
+               /* Well, it starts at 0 and we know it will collide so we may as
+                * well consider it as unassigned. That covers the Apple case.
+                */
+               return 1;
+       } else {
+               /* If the BAR is non-0, then we consider it assigned */
+               offset = (unsigned long)hose->io_base_virt - _IO_BASE;
+               if (((res->start - offset) & 0xfffffffful) != 0)
+                       return 0;
+
+               /* Here, we are a bit different than memory as typically IO space
+                * starting at low addresses -is- valid. What we do instead if that
+                * we consider as unassigned anything that doesn't have IO enabled
+                * in the PCI command register, and that's it.
+                */
+               pci_read_config_word(dev, PCI_COMMAND, &command);
+               if (command & PCI_COMMAND_IO)
+                       return 0;
+
+               /* It's starting at 0 and IO is disabled in the bridge, consider
+                * it unassigned
+                */
+               return 1;
+       }
+}
+
+/* Fixup resources of a PCI<->PCI bridge */
+static void __devinit pcibios_fixup_bridge(struct pci_bus *bus)
+{
+       struct resource *res;
+       int i;
+
+       struct pci_dev *dev = bus->self;
 
-                       fixup_resource(res, dev);
+       for (i = 0; i < PCI_BUS_NUM_RESOURCES; ++i) {
+               if ((res = bus->resource[i]) == NULL)
+                       continue;
+               if (!res->flags)
+                       continue;
+               if (i >= 3 && bus->self->transparent)
+                       continue;
+
+               pr_debug("PCI:%s Bus rsrc %d %016llx-%016llx [%x] fixup...\n",
+                        pci_name(dev), i,
+                        (unsigned long long)res->start,\
+                        (unsigned long long)res->end,
+                        (unsigned int)res->flags);
+
+               /* Perform fixup */
+               fixup_resource(res, dev);
+
+               /* Try to detect uninitialized P2P bridge resources,
+                * and clear them out so they get re-assigned later
+                */
+               if (pcibios_uninitialized_bridge_resource(bus, res)) {
+                       res->flags = 0;
+                       pr_debug("PCI:%s            (unassigned)\n", pci_name(dev));
+               } else {
+
+                       pr_debug("PCI:%s            %016llx-%016llx\n",
+                                pci_name(dev),
+                                (unsigned long long)res->start,
+                                (unsigned long long)res->end);
                }
        }
+}
 
-       /* Additional setup that is different between 32 and 64 bits for now */
-       pcibios_do_bus_setup(bus);
+void __devinit pcibios_setup_bus_self(struct pci_bus *bus)
+{
+       /* Fix up the bus resources for P2P bridges */
+       if (bus->self != NULL)
+               pcibios_fixup_bridge(bus);
 
-       /* Platform specific bus fixups */
+       /* Platform specific bus fixups. This is currently only used
+        * by fsl_pci and I'm hoping to get rid of it at some point
+        */
        if (ppc_md.pcibios_fixup_bus)
                ppc_md.pcibios_fixup_bus(bus);
 
-       /* Read default IRQs and fixup if necessary */
+       /* Setup bus DMA mappings */
+       if (ppc_md.pci_dma_bus_setup)
+               ppc_md.pci_dma_bus_setup(bus);
+}
+
+void __devinit pcibios_setup_bus_devices(struct pci_bus *bus)
+{
+       struct pci_dev *dev;
+
+       pr_debug("PCI: Fixup bus devices %d (%s)\n",
+                bus->number, bus->self ? pci_name(bus->self) : "PHB");
+
        list_for_each_entry(dev, &bus->devices, bus_list) {
+               struct dev_archdata *sd = &dev->dev.archdata;
+
+               /* Setup OF node pointer in archdata */
+               sd->of_node = pci_device_to_OF_node(dev);
+
+               /* Fixup NUMA node as it may not be setup yet by the generic
+                * code and is needed by the DMA init
+                */
+               set_dev_node(&dev->dev, pcibus_to_node(dev->bus));
+
+               /* Hook up default DMA ops */
+               sd->dma_ops = pci_dma_ops;
+               set_dma_offset(&dev->dev, PCI_DRAM_OFFSET);
+
+               /* Additional platform DMA/iommu setup */
+               if (ppc_md.pci_dma_dev_setup)
+                       ppc_md.pci_dma_dev_setup(dev);
+
+               /* Read default IRQs and fixup if necessary */
                pci_read_irq_line(dev);
                if (ppc_md.pci_irq_fixup)
                        ppc_md.pci_irq_fixup(dev);
@@ -845,22 +1133,19 @@ static void __devinit __pcibios_fixup_bus(struct pci_bus *bus)
 void __devinit pcibios_fixup_bus(struct pci_bus *bus)
 {
        /* When called from the generic PCI probe, read PCI<->PCI bridge
-        * bases before proceeding
+        * bases. This is -not- called when generating the PCI tree from
+        * the OF device-tree.
         */
        if (bus->self != NULL)
                pci_read_bridge_bases(bus);
-       __pcibios_fixup_bus(bus);
-}
-EXPORT_SYMBOL(pcibios_fixup_bus);
 
-/* When building a bus from the OF tree rather than probing, we need a
- * slightly different version of the fixup which doesn't read the
- * bridge bases using config space accesses
- */
-void __devinit pcibios_fixup_of_probed_bus(struct pci_bus *bus)
-{
-       __pcibios_fixup_bus(bus);
+       /* Now fixup the bus bus */
+       pcibios_setup_bus_self(bus);
+
+       /* Now fixup devices on that bus */
+       pcibios_setup_bus_devices(bus);
 }
+EXPORT_SYMBOL(pcibios_fixup_bus);
 
 static int skip_isa_ioresource_align(struct pci_dev *dev)
 {
@@ -905,7 +1190,7 @@ EXPORT_SYMBOL(pcibios_align_resource);
  * Reparent resource children of pr that conflict with res
  * under res, and make res replace those children.
  */
-static int __init reparent_resources(struct resource *parent,
+static int reparent_resources(struct resource *parent,
                                     struct resource *res)
 {
        struct resource *p, **pp;
@@ -930,10 +1215,10 @@ static int __init reparent_resources(struct resource *parent,
        *pp = NULL;
        for (p = res->child; p != NULL; p = p->sibling) {
                p->parent = res;
-               DBG(KERN_INFO "PCI: reparented %s [%llx..%llx] under %s\n",
-                   p->name,
-                   (unsigned long long)p->start,
-                   (unsigned long long)p->end, res->name);
+               pr_debug("PCI: Reparented %s [%llx..%llx] under %s\n",
+                        p->name,
+                        (unsigned long long)p->start,
+                        (unsigned long long)p->end, res->name);
        }
        return 0;
 }
@@ -971,80 +1256,80 @@ static int __init reparent_resources(struct resource *parent,
  *         as well.
  */
 
-static void __init pcibios_allocate_bus_resources(struct list_head *bus_list)
+void pcibios_allocate_bus_resources(struct pci_bus *bus)
 {
-       struct pci_bus *bus;
+       struct pci_bus *b;
        int i;
        struct resource *res, *pr;
 
-       /* Depth-First Search on bus tree */
-       list_for_each_entry(bus, bus_list, node) {
-               for (i = 0; i < PCI_BUS_NUM_RESOURCES; ++i) {
-                       if ((res = bus->resource[i]) == NULL || !res->flags
-                           || res->start > res->end)
-                               continue;
-                       if (bus->parent == NULL)
-                               pr = (res->flags & IORESOURCE_IO) ?
-                                       &ioport_resource : &iomem_resource;
-                       else {
-                               /* Don't bother with non-root busses when
-                                * re-assigning all resources. We clear the
-                                * resource flags as if they were colliding
-                                * and as such ensure proper re-allocation
-                                * later.
-                                */
-                               if (ppc_pci_flags & PPC_PCI_REASSIGN_ALL_RSRC)
-                                       goto clear_resource;
-                               pr = pci_find_parent_resource(bus->self, res);
-                               if (pr == res) {
-                                       /* this happens when the generic PCI
-                                        * code (wrongly) decides that this
-                                        * bridge is transparent  -- paulus
-                                        */
-                                       continue;
-                               }
-                       }
+       pr_debug("PCI: Allocating bus resources for %04x:%02x...\n",
+                pci_domain_nr(bus), bus->number);
 
-                       DBG("PCI: %s (bus %d) bridge rsrc %d: %016llx-%016llx "
-                           "[0x%x], parent %p (%s)\n",
-                           bus->self ? pci_name(bus->self) : "PHB",
-                           bus->number, i,
-                           (unsigned long long)res->start,
-                           (unsigned long long)res->end,
-                           (unsigned int)res->flags,
-                           pr, (pr && pr->name) ? pr->name : "nil");
-
-                       if (pr && !(pr->flags & IORESOURCE_UNSET)) {
-                               if (request_resource(pr, res) == 0)
-                                       continue;
-                               /*
-                                * Must be a conflict with an existing entry.
-                                * Move that entry (or entries) under the
-                                * bridge resource and try again.
+       for (i = 0; i < PCI_BUS_NUM_RESOURCES; ++i) {
+               if ((res = bus->resource[i]) == NULL || !res->flags
+                   || res->start > res->end || res->parent)
+                       continue;
+               if (bus->parent == NULL)
+                       pr = (res->flags & IORESOURCE_IO) ?
+                               &ioport_resource : &iomem_resource;
+               else {
+                       /* Don't bother with non-root busses when
+                        * re-assigning all resources. We clear the
+                        * resource flags as if they were colliding
+                        * and as such ensure proper re-allocation
+                        * later.
+                        */
+                       if (ppc_pci_flags & PPC_PCI_REASSIGN_ALL_RSRC)
+                               goto clear_resource;
+                       pr = pci_find_parent_resource(bus->self, res);
+                       if (pr == res) {
+                               /* this happens when the generic PCI
+                                * code (wrongly) decides that this
+                                * bridge is transparent  -- paulus
                                 */
-                               if (reparent_resources(pr, res) == 0)
-                                       continue;
+                               continue;
                        }
-                       printk(KERN_WARNING
-                              "PCI: Cannot allocate resource region "
-                              "%d of PCI bridge %d, will remap\n",
-                              i, bus->number);
-clear_resource:
-                       res->flags = 0;
                }
-               pcibios_allocate_bus_resources(&bus->children);
+
+               pr_debug("PCI: %s (bus %d) bridge rsrc %d: %016llx-%016llx "
+                        "[0x%x], parent %p (%s)\n",
+                        bus->self ? pci_name(bus->self) : "PHB",
+                        bus->number, i,
+                        (unsigned long long)res->start,
+                        (unsigned long long)res->end,
+                        (unsigned int)res->flags,
+                        pr, (pr && pr->name) ? pr->name : "nil");
+
+               if (pr && !(pr->flags & IORESOURCE_UNSET)) {
+                       if (request_resource(pr, res) == 0)
+                               continue;
+                       /*
+                        * Must be a conflict with an existing entry.
+                        * Move that entry (or entries) under the
+                        * bridge resource and try again.
+                        */
+                       if (reparent_resources(pr, res) == 0)
+                               continue;
+               }
+               printk(KERN_WARNING "PCI: Cannot allocate resource region "
+                      "%d of PCI bridge %d, will remap\n", i, bus->number);
+clear_resource:
+               res->flags = 0;
        }
+
+       list_for_each_entry(b, &bus->children, node)
+               pcibios_allocate_bus_resources(b);
 }
 
 static inline void __devinit alloc_resource(struct pci_dev *dev, int idx)
 {
        struct resource *pr, *r = &dev->resource[idx];
 
-       DBG("PCI: Allocating %s: Resource %d: %016llx..%016llx [%x]\n",
-           pci_name(dev), idx,
-           (unsigned long long)r->start,
-           (unsigned long long)r->end,
-           (unsigned int)r->flags);
+       pr_debug("PCI: Allocating %s: Resource %d: %016llx..%016llx [%x]\n",
+                pci_name(dev), idx,
+                (unsigned long long)r->start,
+                (unsigned long long)r->end,
+                (unsigned int)r->flags);
 
        pr = pci_find_parent_resource(dev, r);
        if (!pr || (pr->flags & IORESOURCE_UNSET) ||
@@ -1052,10 +1337,11 @@ static inline void __devinit alloc_resource(struct pci_dev *dev, int idx)
                printk(KERN_WARNING "PCI: Cannot allocate resource region %d"
                       " of device %s, will remap\n", idx, pci_name(dev));
                if (pr)
-                       DBG("PCI:  parent is %p: %016llx-%016llx [%x]\n", pr,
-                           (unsigned long long)pr->start,
-                           (unsigned long long)pr->end,
-                           (unsigned int)pr->flags);
+                       pr_debug("PCI:  parent is %p: %016llx-%016llx [%x]\n",
+                                pr,
+                                (unsigned long long)pr->start,
+                                (unsigned long long)pr->end,
+                                (unsigned int)pr->flags);
                /* We'll assign a new address later */
                r->flags |= IORESOURCE_UNSET;
                r->end -= r->start;
@@ -1072,12 +1358,17 @@ static void __init pcibios_allocate_resources(int pass)
 
        for_each_pci_dev(dev) {
                pci_read_config_word(dev, PCI_COMMAND, &command);
-               for (idx = 0; idx < 6; idx++) {
+               for (idx = 0; idx <= PCI_ROM_RESOURCE; idx++) {
                        r = &dev->resource[idx];
                        if (r->parent)          /* Already allocated */
                                continue;
                        if (!r->flags || (r->flags & IORESOURCE_UNSET))
                                continue;       /* Not assigned at all */
+                       /* We only allocate ROMs on pass 1 just in case they
+                        * have been screwed up by firmware
+                        */
+                       if (idx == PCI_ROM_RESOURCE )
+                               disabled = 1;
                        if (r->flags & IORESOURCE_IO)
                                disabled = !(command & PCI_COMMAND_IO);
                        else
@@ -1088,34 +1379,109 @@ static void __init pcibios_allocate_resources(int pass)
                if (pass)
                        continue;
                r = &dev->resource[PCI_ROM_RESOURCE];
-               if (r->flags & IORESOURCE_ROM_ENABLE) {
+               if (r->flags) {
                        /* Turn the ROM off, leave the resource region,
                         * but keep it unregistered.
                         */
                        u32 reg;
-                       DBG("PCI: Switching off ROM of %s\n", pci_name(dev));
-                       r->flags &= ~IORESOURCE_ROM_ENABLE;
                        pci_read_config_dword(dev, dev->rom_base_reg, &reg);
-                       pci_write_config_dword(dev, dev->rom_base_reg,
-                                              reg & ~PCI_ROM_ADDRESS_ENABLE);
+                       if (reg & PCI_ROM_ADDRESS_ENABLE) {
+                               pr_debug("PCI: Switching off ROM of %s\n",
+                                        pci_name(dev));
+                               r->flags &= ~IORESOURCE_ROM_ENABLE;
+                               pci_write_config_dword(dev, dev->rom_base_reg,
+                                                      reg & ~PCI_ROM_ADDRESS_ENABLE);
+                       }
                }
        }
 }
 
+static void __init pcibios_reserve_legacy_regions(struct pci_bus *bus)
+{
+       struct pci_controller *hose = pci_bus_to_host(bus);
+       resource_size_t offset;
+       struct resource *res, *pres;
+       int i;
+
+       pr_debug("Reserving legacy ranges for domain %04x\n", pci_domain_nr(bus));
+
+       /* Check for IO */
+       if (!(hose->io_resource.flags & IORESOURCE_IO))
+               goto no_io;
+       offset = (unsigned long)hose->io_base_virt - _IO_BASE;
+       res = kzalloc(sizeof(struct resource), GFP_KERNEL);
+       BUG_ON(res == NULL);
+       res->name = "Legacy IO";
+       res->flags = IORESOURCE_IO;
+       res->start = offset;
+       res->end = (offset + 0xfff) & 0xfffffffful;
+       pr_debug("Candidate legacy IO: %pR\n", res);
+       if (request_resource(&hose->io_resource, res)) {
+               printk(KERN_DEBUG
+                      "PCI %04x:%02x Cannot reserve Legacy IO %pR\n",
+                      pci_domain_nr(bus), bus->number, res);
+               kfree(res);
+       }
+
+ no_io:
+       /* Check for memory */
+       offset = hose->pci_mem_offset;
+       pr_debug("hose mem offset: %016llx\n", (unsigned long long)offset);
+       for (i = 0; i < 3; i++) {
+               pres = &hose->mem_resources[i];
+               if (!(pres->flags & IORESOURCE_MEM))
+                       continue;
+               pr_debug("hose mem res: %pR\n", pres);
+               if ((pres->start - offset) <= 0xa0000 &&
+                   (pres->end - offset) >= 0xbffff)
+                       break;
+       }
+       if (i >= 3)
+               return;
+       res = kzalloc(sizeof(struct resource), GFP_KERNEL);
+       BUG_ON(res == NULL);
+       res->name = "Legacy VGA memory";
+       res->flags = IORESOURCE_MEM;
+       res->start = 0xa0000 + offset;
+       res->end = 0xbffff + offset;
+       pr_debug("Candidate VGA memory: %pR\n", res);
+       if (request_resource(pres, res)) {
+               printk(KERN_DEBUG
+                      "PCI %04x:%02x Cannot reserve VGA memory %pR\n",
+                      pci_domain_nr(bus), bus->number, res);
+               kfree(res);
+       }
+}
+
 void __init pcibios_resource_survey(void)
 {
+       struct pci_bus *b;
+
        /* Allocate and assign resources. If we re-assign everything, then
         * we skip the allocate phase
         */
-       pcibios_allocate_bus_resources(&pci_root_buses);
+       list_for_each_entry(b, &pci_root_buses, node)
+               pcibios_allocate_bus_resources(b);
 
        if (!(ppc_pci_flags & PPC_PCI_REASSIGN_ALL_RSRC)) {
                pcibios_allocate_resources(0);
                pcibios_allocate_resources(1);
        }
 
+       /* Before we start assigning unassigned resource, we try to reserve
+        * the low IO area and the VGA memory area if they intersect the
+        * bus available resources to avoid allocating things on top of them
+        */
+       if (!(ppc_pci_flags & PPC_PCI_PROBE_ONLY)) {
+               list_for_each_entry(b, &pci_root_buses, node)
+                       pcibios_reserve_legacy_regions(b);
+       }
+
+       /* Now, if the platform didn't decide to blindly trust the firmware,
+        * we proceed to assigning things that were left unassigned
+        */
        if (!(ppc_pci_flags & PPC_PCI_PROBE_ONLY)) {
-               DBG("PCI: Assigning unassigned resouces...\n");
+               pr_debug("PCI: Assigning unassigned resources...\n");
                pci_assign_unassigned_resources();
        }
 
@@ -1125,11 +1491,13 @@ void __init pcibios_resource_survey(void)
 }
 
 #ifdef CONFIG_HOTPLUG
-/* This is used by the pSeries hotplug driver to allocate resource
+
+/* This is used by the PCI hotplug driver to allocate resource
  * of newly plugged busses. We can try to consolidate with the
- * rest of the code later, for now, keep it as-is
+ * rest of the code later, for now, keep it as-is as our main
+ * resource allocation function doesn't deal with sub-trees yet.
  */
-void __devinit pcibios_claim_one_bus(struct pci_bus *bus)
+void pcibios_claim_one_bus(struct pci_bus *bus)
 {
        struct pci_dev *dev;
        struct pci_bus *child_bus;
@@ -1142,6 +1510,14 @@ void __devinit pcibios_claim_one_bus(struct pci_bus *bus)
 
                        if (r->parent || !r->start || !r->flags)
                                continue;
+
+                       pr_debug("PCI: Claiming %s: "
+                                "Resource %d: %016llx..%016llx [%x]\n",
+                                pci_name(dev), i,
+                                (unsigned long long)r->start,
+                                (unsigned long long)r->end,
+                                (unsigned int)r->flags);
+
                        pci_claim_resource(dev, i);
                }
        }
@@ -1149,46 +1525,215 @@ void __devinit pcibios_claim_one_bus(struct pci_bus *bus)
        list_for_each_entry(child_bus, &bus->children, node)
                pcibios_claim_one_bus(child_bus);
 }
-EXPORT_SYMBOL_GPL(pcibios_claim_one_bus);
+
+
+/* pcibios_finish_adding_to_bus
+ *
+ * This is to be called by the hotplug code after devices have been
+ * added to a bus, this include calling it for a PHB that is just
+ * being added
+ */
+void pcibios_finish_adding_to_bus(struct pci_bus *bus)
+{
+       pr_debug("PCI: Finishing adding to hotplug bus %04x:%02x\n",
+                pci_domain_nr(bus), bus->number);
+
+       /* Allocate bus and devices resources */
+       pcibios_allocate_bus_resources(bus);
+       pcibios_claim_one_bus(bus);
+
+       /* Add new devices to global lists.  Register in proc, sysfs. */
+       pci_bus_add_devices(bus);
+
+       /* Fixup EEH */
+       eeh_add_device_tree_late(bus);
+}
+EXPORT_SYMBOL_GPL(pcibios_finish_adding_to_bus);
+
 #endif /* CONFIG_HOTPLUG */
 
 int pcibios_enable_device(struct pci_dev *dev, int mask)
 {
-       u16 cmd, old_cmd;
-       int idx;
-       struct resource *r;
-
        if (ppc_md.pcibios_enable_device_hook)
                if (ppc_md.pcibios_enable_device_hook(dev))
                        return -EINVAL;
 
-       pci_read_config_word(dev, PCI_COMMAND, &cmd);
-       old_cmd = cmd;
-       for (idx = 0; idx < PCI_NUM_RESOURCES; idx++) {
-               /* Only set up the requested stuff */
-               if (!(mask & (1 << idx)))
-                       continue;
-               r = &dev->resource[idx];
-               if (!(r->flags & (IORESOURCE_IO | IORESOURCE_MEM)))
-                       continue;
-               if ((idx == PCI_ROM_RESOURCE) &&
-                               (!(r->flags & IORESOURCE_ROM_ENABLE)))
-                       continue;
-               if (r->parent == NULL) {
-                       printk(KERN_ERR "PCI: Device %s not available because"
-                              " of resource collisions\n", pci_name(dev));
-                       return -EINVAL;
+       return pci_enable_resources(dev, mask);
+}
+
+void __devinit pcibios_setup_phb_resources(struct pci_controller *hose)
+{
+       struct pci_bus *bus = hose->bus;
+       struct resource *res;
+       int i;
+
+       /* Hookup PHB IO resource */
+       bus->resource[0] = res = &hose->io_resource;
+
+       if (!res->flags) {
+               printk(KERN_WARNING "PCI: I/O resource not set for host"
+                      " bridge %s (domain %d)\n",
+                      hose->dn->full_name, hose->global_number);
+#ifdef CONFIG_PPC32
+               /* Workaround for lack of IO resource only on 32-bit */
+               res->start = (unsigned long)hose->io_base_virt - isa_io_base;
+               res->end = res->start + IO_SPACE_LIMIT;
+               res->flags = IORESOURCE_IO;
+#endif /* CONFIG_PPC32 */
+       }
+
+       pr_debug("PCI: PHB IO resource    = %016llx-%016llx [%lx]\n",
+                (unsigned long long)res->start,
+                (unsigned long long)res->end,
+                (unsigned long)res->flags);
+
+       /* Hookup PHB Memory resources */
+       for (i = 0; i < 3; ++i) {
+               res = &hose->mem_resources[i];
+               if (!res->flags) {
+                       if (i > 0)
+                               continue;
+                       printk(KERN_ERR "PCI: Memory resource 0 not set for "
+                              "host bridge %s (domain %d)\n",
+                              hose->dn->full_name, hose->global_number);
+#ifdef CONFIG_PPC32
+                       /* Workaround for lack of MEM resource only on 32-bit */
+                       res->start = hose->pci_mem_offset;
+                       res->end = (resource_size_t)-1LL;
+                       res->flags = IORESOURCE_MEM;
+#endif /* CONFIG_PPC32 */
                }
-               if (r->flags & IORESOURCE_IO)
-                       cmd |= PCI_COMMAND_IO;
-               if (r->flags & IORESOURCE_MEM)
-                       cmd |= PCI_COMMAND_MEMORY;
+               bus->resource[i+1] = res;
+
+               pr_debug("PCI: PHB MEM resource %d = %016llx-%016llx [%lx]\n", i,
+                        (unsigned long long)res->start,
+                        (unsigned long long)res->end,
+                        (unsigned long)res->flags);
        }
-       if (cmd != old_cmd) {
-               printk("PCI: Enabling device %s (%04x -> %04x)\n",
-                      pci_name(dev), old_cmd, cmd);
-               pci_write_config_word(dev, PCI_COMMAND, cmd);
+
+       pr_debug("PCI: PHB MEM offset     = %016llx\n",
+                (unsigned long long)hose->pci_mem_offset);
+       pr_debug("PCI: PHB IO  offset     = %08lx\n",
+                (unsigned long)hose->io_base_virt - _IO_BASE);
+
+}
+
+/*
+ * Null PCI config access functions, for the case when we can't
+ * find a hose.
+ */
+#define NULL_PCI_OP(rw, size, type)                                    \
+static int                                                             \
+null_##rw##_config_##size(struct pci_dev *dev, int offset, type val)   \
+{                                                                      \
+       return PCIBIOS_DEVICE_NOT_FOUND;                                \
+}
+
+static int
+null_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
+                int len, u32 *val)
+{
+       return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
+static int
+null_write_config(struct pci_bus *bus, unsigned int devfn, int offset,
+                 int len, u32 val)
+{
+       return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
+static struct pci_ops null_pci_ops =
+{
+       .read = null_read_config,
+       .write = null_write_config,
+};
+
+/*
+ * These functions are used early on before PCI scanning is done
+ * and all of the pci_dev and pci_bus structures have been created.
+ */
+static struct pci_bus *
+fake_pci_bus(struct pci_controller *hose, int busnr)
+{
+       static struct pci_bus bus;
+
+       if (hose == 0) {
+               printk(KERN_ERR "Can't find hose for PCI bus %d!\n", busnr);
        }
-       return 0;
+       bus.number = busnr;
+       bus.sysdata = hose;
+       bus.ops = hose? hose->ops: &null_pci_ops;
+       return &bus;
+}
+
+#define EARLY_PCI_OP(rw, size, type)                                   \
+int early_##rw##_config_##size(struct pci_controller *hose, int bus,   \
+                              int devfn, int offset, type value)       \
+{                                                                      \
+       return pci_bus_##rw##_config_##size(fake_pci_bus(hose, bus),    \
+                                           devfn, offset, value);      \
 }
 
+EARLY_PCI_OP(read, byte, u8 *)
+EARLY_PCI_OP(read, word, u16 *)
+EARLY_PCI_OP(read, dword, u32 *)
+EARLY_PCI_OP(write, byte, u8)
+EARLY_PCI_OP(write, word, u16)
+EARLY_PCI_OP(write, dword, u32)
+
+extern int pci_bus_find_capability (struct pci_bus *bus, unsigned int devfn, int cap);
+int early_find_capability(struct pci_controller *hose, int bus, int devfn,
+                         int cap)
+{
+       return pci_bus_find_capability(fake_pci_bus(hose, bus), devfn, cap);
+}
+
+/**
+ * pci_scan_phb - Given a pci_controller, setup and scan the PCI bus
+ * @hose: Pointer to the PCI host controller instance structure
+ * @sysdata: value to use for sysdata pointer.  ppc32 and ppc64 differ here
+ *
+ * Note: the 'data' pointer is a temporary measure.  As 32 and 64 bit
+ * pci code gets merged, this parameter should become unnecessary because
+ * both will use the same value.
+ */
+void __devinit pcibios_scan_phb(struct pci_controller *hose, void *sysdata)
+{
+       struct pci_bus *bus;
+       struct device_node *node = hose->dn;
+       int mode;
+
+       pr_debug("PCI: Scanning PHB %s\n",
+                node ? node->full_name : "<NO NAME>");
+
+       /* Create an empty bus for the toplevel */
+       bus = pci_create_bus(hose->parent, hose->first_busno, hose->ops,
+                            sysdata);
+       if (bus == NULL) {
+               pr_err("Failed to create bus for PCI domain %04x\n",
+                       hose->global_number);
+               return;
+       }
+       bus->secondary = hose->first_busno;
+       hose->bus = bus;
+
+       /* Get some IO space for the new PHB */
+       pcibios_setup_phb_io_space(hose);
+
+       /* Wire up PHB bus resources */
+       pcibios_setup_phb_resources(hose);
+
+       /* Get probe mode and perform scan */
+       mode = PCI_PROBE_NORMAL;
+       if (node && ppc_md.pci_probe_mode)
+               mode = ppc_md.pci_probe_mode(bus);
+       pr_debug("    probe mode: %d\n", mode);
+       if (mode == PCI_PROBE_DEVTREE) {
+               bus->subordinate = hose->last_busno;
+               of_scan_bus(node, bus);
+       }
+
+       if (mode == PCI_PROBE_NORMAL)
+               hose->last_busno = bus->subordinate = pci_scan_child_bus(bus);
+}