return NULL;
 }
 
+/*
+ * Assumption is made on the interrupt parent. All interrupt-map
+ * entries are considered to have the same parent.
+ */
+static int pcibios_irq_map_count(struct pci_controller *phb)
+{
+       const __be32 *imap;
+       int imaplen;
+       struct device_node *parent;
+       u32 intsize, addrsize, parintsize, paraddrsize;
+
+       if (of_property_read_u32(phb->dn, "#interrupt-cells", &intsize))
+               return 0;
+       if (of_property_read_u32(phb->dn, "#address-cells", &addrsize))
+               return 0;
+
+       imap = of_get_property(phb->dn, "interrupt-map", &imaplen);
+       if (!imap) {
+               pr_debug("%pOF : no interrupt-map\n", phb->dn);
+               return 0;
+       }
+       imaplen /= sizeof(u32);
+       pr_debug("%pOF : imaplen=%d\n", phb->dn, imaplen);
+
+       if (imaplen < (addrsize + intsize + 1))
+               return 0;
+
+       imap += intsize + addrsize;
+       parent = of_find_node_by_phandle(be32_to_cpup(imap));
+       if (!parent) {
+               pr_debug("%pOF : no imap parent found !\n", phb->dn);
+               return 0;
+       }
+
+       if (of_property_read_u32(parent, "#interrupt-cells", &parintsize)) {
+               pr_debug("%pOF : parent lacks #interrupt-cells!\n", phb->dn);
+               return 0;
+       }
+
+       if (of_property_read_u32(parent, "#address-cells", ¶ddrsize))
+               paraddrsize = 0;
+
+       return imaplen / (addrsize + intsize + 1 + paraddrsize + parintsize);
+}
+
+static void pcibios_irq_map_init(struct pci_controller *phb)
+{
+       phb->irq_count = pcibios_irq_map_count(phb);
+       if (phb->irq_count < PCI_NUM_INTX)
+               phb->irq_count = PCI_NUM_INTX;
+
+       pr_debug("%pOF : interrupt map #%d\n", phb->dn, phb->irq_count);
+
+       phb->irq_map = kcalloc(phb->irq_count, sizeof(unsigned int),
+                              GFP_KERNEL);
+}
+
+static void pci_irq_map_register(struct pci_dev *pdev, unsigned int virq)
+{
+       struct pci_controller *phb = pci_bus_to_host(pdev->bus);
+       int i;
+
+       if (!phb->irq_map)
+               return;
+
+       for (i = 0; i < phb->irq_count; i++) {
+               /*
+                * Look for an empty or an equivalent slot, as INTx
+                * interrupts can be shared between adapters.
+                */
+               if (phb->irq_map[i] == virq || !phb->irq_map[i]) {
+                       phb->irq_map[i] = virq;
+                       break;
+               }
+       }
+
+       if (i == phb->irq_count)
+               pr_err("PCI:%s all platform interrupts mapped\n",
+                      pci_name(pdev));
+}
+
+/*
+ * Clearing the mapped interrupts will also clear the underlying
+ * mappings of the ESB pages of the interrupts when under XIVE. It is
+ * a requirement of PowerVM to clear all memory mappings before
+ * removing a PHB.
+ */
+static void pci_irq_map_dispose(struct pci_bus *bus)
+{
+       struct pci_controller *phb = pci_bus_to_host(bus);
+       int i;
+
+       if (!phb->irq_map)
+               return;
+
+       pr_debug("PCI: Clearing interrupt mappings for PHB %04x:%02x...\n",
+                pci_domain_nr(bus), bus->number);
+       for (i = 0; i < phb->irq_count; i++)
+               irq_dispose_mapping(phb->irq_map[i]);
+
+       kfree(phb->irq_map);
+}
+
+void pcibios_remove_bus(struct pci_bus *bus)
+{
+       pci_irq_map_dispose(bus);
+}
+EXPORT_SYMBOL_GPL(pcibios_remove_bus);
+
 /*
  * Reads the interrupt pin to determine if interrupt is use by card.
  * If the interrupt is used, then gets the interrupt line from the
 
        pci_dev->irq = virq;
 
+       /* Record all interrut mappings for later removal of a PHB */
+       pci_irq_map_register(pci_dev, virq);
        return 0;
 }
 
 
        pr_debug("PCI: Scanning PHB %pOF\n", node);
 
+       /* Allocate interrupt mappings array */
+       pcibios_irq_map_init(hose);
+
        /* Get some IO space for the new PHB */
        pcibios_setup_phb_io_space(hose);