|
|
@@ -28,6 +28,40 @@ int pci_msi_ignore_mask;
|
|
|
|
|
|
#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 */
|
|
|
|
|
|
@@ -348,7 +382,7 @@ static void free_msi_irqs(struct pci_dev *dev)
|
|
|
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) {
|
|
|
@@ -600,7 +634,7 @@ static int msi_capability_init(struct pci_dev *dev, int nvec)
|
|
|
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);
|
|
|
@@ -715,7 +749,7 @@ static int msix_capability_init(struct pci_dev *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;
|
|
|
|
|
|
@@ -1258,4 +1292,31 @@ void pci_msi_domain_free_irqs(struct irq_domain *domain, struct pci_dev *dev)
|
|
|
{
|
|
|
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 */
|