提交 0e4ccb15 编写于 作者: K Konrad Rzeszutek Wilk 提交者: Bjorn Helgaas

PCI: Add x86_msi.msi_mask_irq() and msix_mask_irq()

Certain platforms do not allow writes in the MSI-X BARs to setup or tear
down vector values.  To combat against the generic code trying to write to
that and either silently being ignored or crashing due to the pagetables
being marked R/O this patch introduces a platform override.

Note that we keep two separate, non-weak, functions default_mask_msi_irqs()
and default_mask_msix_irqs() for the behavior of the arch_mask_msi_irqs()
and arch_mask_msix_irqs(), as the default behavior is needed by x86 PCI
code.

For Xen, which does not allow the guest to write to MSI-X tables - as the
hypervisor is solely responsible for setting the vector values - we
implement two nops.

This fixes a Xen guest crash when passing a PCI device with MSI-X to the
guest.  See the bugzilla for more details.

[bhelgaas: add bugzilla info]
Reference: https://bugzilla.kernel.org/show_bug.cgi?id=64581Signed-off-by: NKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Signed-off-by: NBjorn Helgaas <bhelgaas@google.com>
CC: Sucheta Chakraborty <sucheta.chakraborty@qlogic.com>
CC: Zhenzhong Duan <zhenzhong.duan@oracle.com>
上级 f92d74c1
...@@ -172,6 +172,7 @@ struct x86_platform_ops { ...@@ -172,6 +172,7 @@ struct x86_platform_ops {
struct pci_dev; struct pci_dev;
struct msi_msg; struct msi_msg;
struct msi_desc;
struct x86_msi_ops { struct x86_msi_ops {
int (*setup_msi_irqs)(struct pci_dev *dev, int nvec, int type); int (*setup_msi_irqs)(struct pci_dev *dev, int nvec, int type);
...@@ -182,6 +183,8 @@ struct x86_msi_ops { ...@@ -182,6 +183,8 @@ struct x86_msi_ops {
void (*teardown_msi_irqs)(struct pci_dev *dev); void (*teardown_msi_irqs)(struct pci_dev *dev);
void (*restore_msi_irqs)(struct pci_dev *dev, int irq); void (*restore_msi_irqs)(struct pci_dev *dev, int irq);
int (*setup_hpet_msi)(unsigned int irq, unsigned int id); int (*setup_hpet_msi)(unsigned int irq, unsigned int id);
u32 (*msi_mask_irq)(struct msi_desc *desc, u32 mask, u32 flag);
u32 (*msix_mask_irq)(struct msi_desc *desc, u32 flag);
}; };
struct IO_APIC_route_entry; struct IO_APIC_route_entry;
......
...@@ -116,6 +116,8 @@ struct x86_msi_ops x86_msi = { ...@@ -116,6 +116,8 @@ struct x86_msi_ops x86_msi = {
.teardown_msi_irqs = default_teardown_msi_irqs, .teardown_msi_irqs = default_teardown_msi_irqs,
.restore_msi_irqs = default_restore_msi_irqs, .restore_msi_irqs = default_restore_msi_irqs,
.setup_hpet_msi = default_setup_hpet_msi, .setup_hpet_msi = default_setup_hpet_msi,
.msi_mask_irq = default_msi_mask_irq,
.msix_mask_irq = default_msix_mask_irq,
}; };
/* MSI arch specific hooks */ /* MSI arch specific hooks */
...@@ -138,6 +140,14 @@ void arch_restore_msi_irqs(struct pci_dev *dev, int irq) ...@@ -138,6 +140,14 @@ void arch_restore_msi_irqs(struct pci_dev *dev, int irq)
{ {
x86_msi.restore_msi_irqs(dev, irq); x86_msi.restore_msi_irqs(dev, irq);
} }
u32 arch_msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag)
{
return x86_msi.msi_mask_irq(desc, mask, flag);
}
u32 arch_msix_mask_irq(struct msi_desc *desc, u32 flag)
{
return x86_msi.msix_mask_irq(desc, flag);
}
#endif #endif
struct x86_io_apic_ops x86_io_apic_ops = { struct x86_io_apic_ops x86_io_apic_ops = {
......
...@@ -382,7 +382,14 @@ static void xen_teardown_msi_irq(unsigned int irq) ...@@ -382,7 +382,14 @@ static void xen_teardown_msi_irq(unsigned int irq)
{ {
xen_destroy_irq(irq); xen_destroy_irq(irq);
} }
static u32 xen_nop_msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag)
{
return 0;
}
static u32 xen_nop_msix_mask_irq(struct msi_desc *desc, u32 flag)
{
return 0;
}
#endif #endif
int __init pci_xen_init(void) int __init pci_xen_init(void)
...@@ -406,6 +413,8 @@ int __init pci_xen_init(void) ...@@ -406,6 +413,8 @@ int __init pci_xen_init(void)
x86_msi.setup_msi_irqs = xen_setup_msi_irqs; x86_msi.setup_msi_irqs = xen_setup_msi_irqs;
x86_msi.teardown_msi_irq = xen_teardown_msi_irq; x86_msi.teardown_msi_irq = xen_teardown_msi_irq;
x86_msi.teardown_msi_irqs = xen_teardown_msi_irqs; x86_msi.teardown_msi_irqs = xen_teardown_msi_irqs;
x86_msi.msi_mask_irq = xen_nop_msi_mask_irq;
x86_msi.msix_mask_irq = xen_nop_msix_mask_irq;
#endif #endif
return 0; return 0;
} }
...@@ -485,6 +494,8 @@ int __init pci_xen_initial_domain(void) ...@@ -485,6 +494,8 @@ int __init pci_xen_initial_domain(void)
x86_msi.setup_msi_irqs = xen_initdom_setup_msi_irqs; x86_msi.setup_msi_irqs = xen_initdom_setup_msi_irqs;
x86_msi.teardown_msi_irq = xen_teardown_msi_irq; x86_msi.teardown_msi_irq = xen_teardown_msi_irq;
x86_msi.restore_msi_irqs = xen_initdom_restore_msi_irqs; x86_msi.restore_msi_irqs = xen_initdom_restore_msi_irqs;
x86_msi.msi_mask_irq = xen_nop_msi_mask_irq;
x86_msi.msix_mask_irq = xen_nop_msix_mask_irq;
#endif #endif
xen_setup_acpi_sci(); xen_setup_acpi_sci();
__acpi_register_gsi = acpi_register_gsi_xen; __acpi_register_gsi = acpi_register_gsi_xen;
......
...@@ -185,7 +185,7 @@ static inline __attribute_const__ u32 msi_enabled_mask(u16 control) ...@@ -185,7 +185,7 @@ static inline __attribute_const__ u32 msi_enabled_mask(u16 control)
* reliably as devices without an INTx disable bit will then generate a * reliably as devices without an INTx disable bit will then generate a
* level IRQ which will never be cleared. * level IRQ which will never be cleared.
*/ */
static u32 __msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag) u32 default_msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag)
{ {
u32 mask_bits = desc->masked; u32 mask_bits = desc->masked;
...@@ -199,9 +199,14 @@ static u32 __msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag) ...@@ -199,9 +199,14 @@ static u32 __msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag)
return mask_bits; return mask_bits;
} }
__weak u32 arch_msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag)
{
return default_msi_mask_irq(desc, mask, flag);
}
static void msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag) static void msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag)
{ {
desc->masked = __msi_mask_irq(desc, mask, flag); desc->masked = arch_msi_mask_irq(desc, mask, flag);
} }
/* /*
...@@ -211,7 +216,7 @@ static void msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag) ...@@ -211,7 +216,7 @@ static void msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag)
* file. This saves a few milliseconds when initialising devices with lots * file. This saves a few milliseconds when initialising devices with lots
* of MSI-X interrupts. * of MSI-X interrupts.
*/ */
static u32 __msix_mask_irq(struct msi_desc *desc, u32 flag) u32 default_msix_mask_irq(struct msi_desc *desc, u32 flag)
{ {
u32 mask_bits = desc->masked; u32 mask_bits = desc->masked;
unsigned offset = desc->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE + unsigned offset = desc->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
...@@ -224,9 +229,14 @@ static u32 __msix_mask_irq(struct msi_desc *desc, u32 flag) ...@@ -224,9 +229,14 @@ static u32 __msix_mask_irq(struct msi_desc *desc, u32 flag)
return mask_bits; return mask_bits;
} }
__weak u32 arch_msix_mask_irq(struct msi_desc *desc, u32 flag)
{
return default_msix_mask_irq(desc, flag);
}
static void msix_mask_irq(struct msi_desc *desc, u32 flag) static void msix_mask_irq(struct msi_desc *desc, u32 flag)
{ {
desc->masked = __msix_mask_irq(desc, flag); desc->masked = arch_msix_mask_irq(desc, flag);
} }
static void msi_set_mask_bit(struct irq_data *data, u32 flag) static void msi_set_mask_bit(struct irq_data *data, u32 flag)
...@@ -902,7 +912,7 @@ void pci_msi_shutdown(struct pci_dev *dev) ...@@ -902,7 +912,7 @@ void pci_msi_shutdown(struct pci_dev *dev)
pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &ctrl); pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &ctrl);
mask = msi_capable_mask(ctrl); mask = msi_capable_mask(ctrl);
/* Keep cached state to be restored */ /* Keep cached state to be restored */
__msi_mask_irq(desc, mask, ~mask); arch_msi_mask_irq(desc, mask, ~mask);
/* Restore dev->irq to its default pin-assertion irq */ /* Restore dev->irq to its default pin-assertion irq */
dev->irq = desc->msi_attrib.default_irq; dev->irq = desc->msi_attrib.default_irq;
...@@ -998,7 +1008,7 @@ void pci_msix_shutdown(struct pci_dev *dev) ...@@ -998,7 +1008,7 @@ void pci_msix_shutdown(struct pci_dev *dev)
/* Return the device with MSI-X masked as initial states */ /* Return the device with MSI-X masked as initial states */
list_for_each_entry(entry, &dev->msi_list, list) { list_for_each_entry(entry, &dev->msi_list, list) {
/* Keep cached states to be restored */ /* Keep cached states to be restored */
__msix_mask_irq(entry, 1); arch_msix_mask_irq(entry, 1);
} }
msix_set_enable(dev, 0); msix_set_enable(dev, 0);
......
...@@ -64,6 +64,8 @@ void arch_restore_msi_irqs(struct pci_dev *dev, int irq); ...@@ -64,6 +64,8 @@ void arch_restore_msi_irqs(struct pci_dev *dev, int irq);
void default_teardown_msi_irqs(struct pci_dev *dev); void default_teardown_msi_irqs(struct pci_dev *dev);
void default_restore_msi_irqs(struct pci_dev *dev, int irq); void default_restore_msi_irqs(struct pci_dev *dev, int irq);
u32 default_msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag);
u32 default_msix_mask_irq(struct msi_desc *desc, u32 flag);
struct msi_chip { struct msi_chip {
struct module *owner; struct module *owner;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册