|
@@ -339,11 +339,38 @@ int msi_domain_populate_irqs(struct irq_domain *domain, struct device *dev,
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-static bool msi_check_reservation_mode(struct msi_domain_info *info)
|
|
|
+/*
|
|
|
+ * Carefully check whether the device can use reservation mode. If
|
|
|
+ * reservation mode is enabled then the early activation will assign a
|
|
|
+ * dummy vector to the device. If the PCI/MSI device does not support
|
|
|
+ * masking of the entry then this can result in spurious interrupts when
|
|
|
+ * the device driver is not absolutely careful. But even then a malfunction
|
|
|
+ * of the hardware could result in a spurious interrupt on the dummy vector
|
|
|
+ * and render the device unusable. If the entry can be masked then the core
|
|
|
+ * logic will prevent the spurious interrupt and reservation mode can be
|
|
|
+ * used. For now reservation mode is restricted to PCI/MSI.
|
|
|
+ */
|
|
|
+static bool msi_check_reservation_mode(struct irq_domain *domain,
|
|
|
+ struct msi_domain_info *info,
|
|
|
+ struct device *dev)
|
|
|
{
|
|
|
+ struct msi_desc *desc;
|
|
|
+
|
|
|
+ if (domain->bus_token != DOMAIN_BUS_PCI_MSI)
|
|
|
+ return false;
|
|
|
+
|
|
|
if (!(info->flags & MSI_FLAG_MUST_REACTIVATE))
|
|
|
return false;
|
|
|
- return true;
|
|
|
+
|
|
|
+ if (IS_ENABLED(CONFIG_PCI_MSI) && pci_msi_ignore_mask)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Checking the first MSI descriptor is sufficient. MSIX supports
|
|
|
+ * masking and MSI does so when the maskbit is set.
|
|
|
+ */
|
|
|
+ desc = first_msi_entry(dev);
|
|
|
+ return desc->msi_attrib.is_msix || desc->msi_attrib.maskbit;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -394,7 +421,7 @@ int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
|
|
|
if (ops->msi_finish)
|
|
|
ops->msi_finish(&arg, 0);
|
|
|
|
|
|
- can_reserve = msi_check_reservation_mode(info);
|
|
|
+ can_reserve = msi_check_reservation_mode(domain, info, dev);
|
|
|
|
|
|
for_each_msi_entry(desc, dev) {
|
|
|
virq = desc->irq;
|
|
@@ -412,7 +439,9 @@ int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
|
|
|
continue;
|
|
|
|
|
|
irq_data = irq_domain_get_irq_data(domain, desc->irq);
|
|
|
- ret = irq_domain_activate_irq(irq_data, true);
|
|
|
+ if (!can_reserve)
|
|
|
+ irqd_clr_can_reserve(irq_data);
|
|
|
+ ret = irq_domain_activate_irq(irq_data, can_reserve);
|
|
|
if (ret)
|
|
|
goto cleanup;
|
|
|
}
|