#define msix_table_size(flags) ((flags & PCI_MSIX_FLAGS_QSIZE) + 1)
 
+#ifdef CONFIG_PCI_MSI_IRQ_DOMAIN
+static struct irq_domain *pci_msi_default_domain;
+static DEFINE_MUTEX(pci_msi_domain_lock);
+
+struct irq_domain * __weak arch_get_pci_msi_domain(struct pci_dev *dev)
+{
+       return pci_msi_default_domain;
+}
+
+static int pci_msi_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
+{
+       struct irq_domain *domain;
+
+       domain = arch_get_pci_msi_domain(dev);
+       if (domain)
+               return pci_msi_domain_alloc_irqs(domain, dev, nvec, type);
+
+       return arch_setup_msi_irqs(dev, nvec, type);
+}
+
+static void pci_msi_teardown_msi_irqs(struct pci_dev *dev)
+{
+       struct irq_domain *domain;
+
+       domain = arch_get_pci_msi_domain(dev);
+       if (domain)
+               pci_msi_domain_free_irqs(domain, dev);
+       else
+               arch_teardown_msi_irqs(dev);
+}
+#else
+#define pci_msi_setup_msi_irqs         arch_setup_msi_irqs
+#define pci_msi_teardown_msi_irqs      arch_teardown_msi_irqs
+#endif
 
 /* Arch hooks */
 
                        for (i = 0; i < entry->nvec_used; i++)
                                BUG_ON(irq_has_action(entry->irq + i));
 
-       arch_teardown_msi_irqs(dev);
+       pci_msi_teardown_msi_irqs(dev);
 
        list_for_each_entry_safe(entry, tmp, &dev->msi_list, list) {
                if (entry->msi_attrib.is_msix) {
        list_add_tail(&entry->list, &dev->msi_list);
 
        /* Configure MSI capability structure */
-       ret = arch_setup_msi_irqs(dev, nvec, PCI_CAP_ID_MSI);
+       ret = pci_msi_setup_msi_irqs(dev, nvec, PCI_CAP_ID_MSI);
        if (ret) {
                msi_mask_irq(entry, mask, ~mask);
                free_msi_irqs(dev);
        if (ret)
                return ret;
 
-       ret = arch_setup_msi_irqs(dev, nvec, PCI_CAP_ID_MSIX);
+       ret = pci_msi_setup_msi_irqs(dev, nvec, PCI_CAP_ID_MSIX);
        if (ret)
                goto out_avail;
 
 {
        msi_domain_free_irqs(domain, &dev->dev);
 }
+
+/**
+ * pci_msi_create_default_irq_domain - Create a default MSI interrupt domain
+ * @node:      Optional device-tree node of the interrupt controller
+ * @info:      MSI domain info
+ * @parent:    Parent irq domain
+ *
+ * Returns: A domain pointer or NULL in case of failure. If successful
+ * the default PCI/MSI irqdomain pointer is updated.
+ */
+struct irq_domain *pci_msi_create_default_irq_domain(struct device_node *node,
+               struct msi_domain_info *info, struct irq_domain *parent)
+{
+       struct irq_domain *domain;
+
+       mutex_lock(&pci_msi_domain_lock);
+       if (pci_msi_default_domain) {
+               pr_err("PCI: default irq domain for PCI MSI has already been created.\n");
+               domain = NULL;
+       } else {
+               domain = pci_msi_create_irq_domain(node, info, parent);
+               pci_msi_default_domain = domain;
+       }
+       mutex_unlock(&pci_msi_domain_lock);
+
+       return domain;
+}
 #endif /* CONFIG_PCI_MSI_IRQ_DOMAIN */