@@ -259,6 +259,8 @@ enum {
MSI_FLAG_MULTI_PCI_MSI = (1 << 3),
/* Support PCI MSIX interrupts */
MSI_FLAG_PCI_MSIX = (1 << 4),
+ /* Require exact match for PCI domain */
+ MSI_FLAG_PCI_DOMAIN_MATCH = (1 << 5),
};
int msi_domain_set_affinity(struct irq_data *data, const struct cpumask *mask,
@@ -141,11 +141,35 @@ static void msi_domain_free(struct irq_domain *domain, unsigned int virq,
irq_domain_free_irqs_top(domain, virq, nr_irqs);
}
+/*
+ * Return a higher rank for exact matches against PCI domain (segment)
+ * so that generic MSI IRQ domains can be overridden by more specific
+ * implementations.
+ */
+static int msi_domain_match(struct irq_domain *d, struct device_node *node,
+ enum irq_domain_bus_token bus_token,
+ void *bus_data)
+{
+ struct msi_domain_info *info = d->host_data;
+
+ if (bus_token != d->bus_token)
+ return 0;
+
+ if (bus_token == DOMAIN_BUS_PCI_MSI) {
+ if (!(info->flags & MSI_FLAG_PCI_DOMAIN_MATCH))
+ return 1;
+ if (bus_data && (info->pci_domain == *(int *)bus_data))
+ return 2;
+ }
+ return 0;
+}
+
static const struct irq_domain_ops msi_domain_ops = {
.alloc = msi_domain_alloc,
.free = msi_domain_free,
.activate = msi_domain_activate,
.deactivate = msi_domain_deactivate,
+ .match = msi_domain_match,
};
#ifdef GENERIC_MSI_DOMAIN_OPS