aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>2013-11-06 16:16:56 -0500
committerBjorn Helgaas <bhelgaas@google.com>2013-11-06 18:32:19 -0500
commit0e4ccb1505a9e29c50170742ce26ac4655baab2d (patch)
tree59712adb4f49a554fb68178a2a6b1894ffbd1c42
parentf92d74c1f5afaff7cd1ea14ade8f1ba6b519e422 (diff)
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=64581 Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> CC: Sucheta Chakraborty <sucheta.chakraborty@qlogic.com> CC: Zhenzhong Duan <zhenzhong.duan@oracle.com>
-rw-r--r--arch/x86/include/asm/x86_init.h3
-rw-r--r--arch/x86/kernel/x86_init.c10
-rw-r--r--arch/x86/pci/xen.c13
-rw-r--r--drivers/pci/msi.c22
-rw-r--r--include/linux/msi.h2
5 files changed, 43 insertions, 7 deletions
diff --git a/arch/x86/include/asm/x86_init.h b/arch/x86/include/asm/x86_init.h
index 828a1565ba57..0f1be11e43d2 100644
--- a/arch/x86/include/asm/x86_init.h
+++ b/arch/x86/include/asm/x86_init.h
@@ -172,6 +172,7 @@ struct x86_platform_ops {
172 172
173struct pci_dev; 173struct pci_dev;
174struct msi_msg; 174struct msi_msg;
175struct msi_desc;
175 176
176struct x86_msi_ops { 177struct x86_msi_ops {
177 int (*setup_msi_irqs)(struct pci_dev *dev, int nvec, int type); 178 int (*setup_msi_irqs)(struct pci_dev *dev, int nvec, int type);
@@ -182,6 +183,8 @@ struct x86_msi_ops {
182 void (*teardown_msi_irqs)(struct pci_dev *dev); 183 void (*teardown_msi_irqs)(struct pci_dev *dev);
183 void (*restore_msi_irqs)(struct pci_dev *dev, int irq); 184 void (*restore_msi_irqs)(struct pci_dev *dev, int irq);
184 int (*setup_hpet_msi)(unsigned int irq, unsigned int id); 185 int (*setup_hpet_msi)(unsigned int irq, unsigned int id);
186 u32 (*msi_mask_irq)(struct msi_desc *desc, u32 mask, u32 flag);
187 u32 (*msix_mask_irq)(struct msi_desc *desc, u32 flag);
185}; 188};
186 189
187struct IO_APIC_route_entry; 190struct IO_APIC_route_entry;
diff --git a/arch/x86/kernel/x86_init.c b/arch/x86/kernel/x86_init.c
index 8ce0072cd700..021783b1f46a 100644
--- a/arch/x86/kernel/x86_init.c
+++ b/arch/x86/kernel/x86_init.c
@@ -116,6 +116,8 @@ struct x86_msi_ops x86_msi = {
116 .teardown_msi_irqs = default_teardown_msi_irqs, 116 .teardown_msi_irqs = default_teardown_msi_irqs,
117 .restore_msi_irqs = default_restore_msi_irqs, 117 .restore_msi_irqs = default_restore_msi_irqs,
118 .setup_hpet_msi = default_setup_hpet_msi, 118 .setup_hpet_msi = default_setup_hpet_msi,
119 .msi_mask_irq = default_msi_mask_irq,
120 .msix_mask_irq = default_msix_mask_irq,
119}; 121};
120 122
121/* MSI arch specific hooks */ 123/* MSI arch specific hooks */
@@ -138,6 +140,14 @@ void arch_restore_msi_irqs(struct pci_dev *dev, int irq)
138{ 140{
139 x86_msi.restore_msi_irqs(dev, irq); 141 x86_msi.restore_msi_irqs(dev, irq);
140} 142}
143u32 arch_msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag)
144{
145 return x86_msi.msi_mask_irq(desc, mask, flag);
146}
147u32 arch_msix_mask_irq(struct msi_desc *desc, u32 flag)
148{
149 return x86_msi.msix_mask_irq(desc, flag);
150}
141#endif 151#endif
142 152
143struct x86_io_apic_ops x86_io_apic_ops = { 153struct x86_io_apic_ops x86_io_apic_ops = {
diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c
index 48e8461057ba..5eee4959785d 100644
--- a/arch/x86/pci/xen.c
+++ b/arch/x86/pci/xen.c
@@ -382,7 +382,14 @@ static void xen_teardown_msi_irq(unsigned int irq)
382{ 382{
383 xen_destroy_irq(irq); 383 xen_destroy_irq(irq);
384} 384}
385 385static u32 xen_nop_msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag)
386{
387 return 0;
388}
389static u32 xen_nop_msix_mask_irq(struct msi_desc *desc, u32 flag)
390{
391 return 0;
392}
386#endif 393#endif
387 394
388int __init pci_xen_init(void) 395int __init pci_xen_init(void)
@@ -406,6 +413,8 @@ int __init pci_xen_init(void)
406 x86_msi.setup_msi_irqs = xen_setup_msi_irqs; 413 x86_msi.setup_msi_irqs = xen_setup_msi_irqs;
407 x86_msi.teardown_msi_irq = xen_teardown_msi_irq; 414 x86_msi.teardown_msi_irq = xen_teardown_msi_irq;
408 x86_msi.teardown_msi_irqs = xen_teardown_msi_irqs; 415 x86_msi.teardown_msi_irqs = xen_teardown_msi_irqs;
416 x86_msi.msi_mask_irq = xen_nop_msi_mask_irq;
417 x86_msi.msix_mask_irq = xen_nop_msix_mask_irq;
409#endif 418#endif
410 return 0; 419 return 0;
411} 420}
@@ -485,6 +494,8 @@ int __init pci_xen_initial_domain(void)
485 x86_msi.setup_msi_irqs = xen_initdom_setup_msi_irqs; 494 x86_msi.setup_msi_irqs = xen_initdom_setup_msi_irqs;
486 x86_msi.teardown_msi_irq = xen_teardown_msi_irq; 495 x86_msi.teardown_msi_irq = xen_teardown_msi_irq;
487 x86_msi.restore_msi_irqs = xen_initdom_restore_msi_irqs; 496 x86_msi.restore_msi_irqs = xen_initdom_restore_msi_irqs;
497 x86_msi.msi_mask_irq = xen_nop_msi_mask_irq;
498 x86_msi.msix_mask_irq = xen_nop_msix_mask_irq;
488#endif 499#endif
489 xen_setup_acpi_sci(); 500 xen_setup_acpi_sci();
490 __acpi_register_gsi = acpi_register_gsi_xen; 501 __acpi_register_gsi = acpi_register_gsi_xen;
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index 604265c40853..5e63645a7abe 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -185,7 +185,7 @@ static inline __attribute_const__ u32 msi_enabled_mask(u16 control)
185 * reliably as devices without an INTx disable bit will then generate a 185 * reliably as devices without an INTx disable bit will then generate a
186 * level IRQ which will never be cleared. 186 * level IRQ which will never be cleared.
187 */ 187 */
188static u32 __msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag) 188u32 default_msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag)
189{ 189{
190 u32 mask_bits = desc->masked; 190 u32 mask_bits = desc->masked;
191 191
@@ -199,9 +199,14 @@ static u32 __msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag)
199 return mask_bits; 199 return mask_bits;
200} 200}
201 201
202__weak u32 arch_msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag)
203{
204 return default_msi_mask_irq(desc, mask, flag);
205}
206
202static void msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag) 207static void msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag)
203{ 208{
204 desc->masked = __msi_mask_irq(desc, mask, flag); 209 desc->masked = arch_msi_mask_irq(desc, mask, flag);
205} 210}
206 211
207/* 212/*
@@ -211,7 +216,7 @@ static void msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag)
211 * file. This saves a few milliseconds when initialising devices with lots 216 * file. This saves a few milliseconds when initialising devices with lots
212 * of MSI-X interrupts. 217 * of MSI-X interrupts.
213 */ 218 */
214static u32 __msix_mask_irq(struct msi_desc *desc, u32 flag) 219u32 default_msix_mask_irq(struct msi_desc *desc, u32 flag)
215{ 220{
216 u32 mask_bits = desc->masked; 221 u32 mask_bits = desc->masked;
217 unsigned offset = desc->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE + 222 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 return mask_bits; 229 return mask_bits;
225} 230}
226 231
232__weak u32 arch_msix_mask_irq(struct msi_desc *desc, u32 flag)
233{
234 return default_msix_mask_irq(desc, flag);
235}
236
227static void msix_mask_irq(struct msi_desc *desc, u32 flag) 237static void msix_mask_irq(struct msi_desc *desc, u32 flag)
228{ 238{
229 desc->masked = __msix_mask_irq(desc, flag); 239 desc->masked = arch_msix_mask_irq(desc, flag);
230} 240}
231 241
232static void msi_set_mask_bit(struct irq_data *data, u32 flag) 242static void msi_set_mask_bit(struct irq_data *data, u32 flag)
@@ -902,7 +912,7 @@ void pci_msi_shutdown(struct pci_dev *dev)
902 pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &ctrl); 912 pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &ctrl);
903 mask = msi_capable_mask(ctrl); 913 mask = msi_capable_mask(ctrl);
904 /* Keep cached state to be restored */ 914 /* Keep cached state to be restored */
905 __msi_mask_irq(desc, mask, ~mask); 915 arch_msi_mask_irq(desc, mask, ~mask);
906 916
907 /* Restore dev->irq to its default pin-assertion irq */ 917 /* Restore dev->irq to its default pin-assertion irq */
908 dev->irq = desc->msi_attrib.default_irq; 918 dev->irq = desc->msi_attrib.default_irq;
@@ -998,7 +1008,7 @@ void pci_msix_shutdown(struct pci_dev *dev)
998 /* Return the device with MSI-X masked as initial states */ 1008 /* Return the device with MSI-X masked as initial states */
999 list_for_each_entry(entry, &dev->msi_list, list) { 1009 list_for_each_entry(entry, &dev->msi_list, list) {
1000 /* Keep cached states to be restored */ 1010 /* Keep cached states to be restored */
1001 __msix_mask_irq(entry, 1); 1011 arch_msix_mask_irq(entry, 1);
1002 } 1012 }
1003 1013
1004 msix_set_enable(dev, 0); 1014 msix_set_enable(dev, 0);
diff --git a/include/linux/msi.h b/include/linux/msi.h
index b17ead818aec..87cce50bd121 100644
--- a/include/linux/msi.h
+++ b/include/linux/msi.h
@@ -64,6 +64,8 @@ void arch_restore_msi_irqs(struct pci_dev *dev, int irq);
64 64
65void default_teardown_msi_irqs(struct pci_dev *dev); 65void default_teardown_msi_irqs(struct pci_dev *dev);
66void default_restore_msi_irqs(struct pci_dev *dev, int irq); 66void default_restore_msi_irqs(struct pci_dev *dev, int irq);
67u32 default_msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag);
68u32 default_msix_mask_irq(struct msi_desc *desc, u32 flag);
67 69
68struct msi_chip { 70struct msi_chip {
69 struct module *owner; 71 struct module *owner;