aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYinghai Lu <yhlu.kernel.send@gmail.com>2008-04-23 17:56:30 -0400
committerJesse Barnes <jbarnes@hobbes.lan>2008-04-29 12:11:12 -0400
commit8e149e09f91098fd72bf9ac5b4a77a693abf721e (patch)
treee0aae800a75a478820494ddce42291f896014012
parent2768f92c06a59c3ebf17a6b86002c3f33ab61a28 (diff)
pci/irq: restore mask_bits in msi shutdown -v3
[PATCH 1/2] pci/irq: restore mask_bits in msi shutdown -v3 Yinghai found that kexec'ing a RHEL 5.1 kernel with 2.6.25-rc3+ kernels prevents his NIC from working. He bisected to | commit 89d694b9dbe769ca1004e01db0ca43964806a611 | Author: Thomas Gleixner <tglx@linutronix.de> | Date: Mon Feb 18 18:25:17 2008 +0100 | | genirq: do not leave interupts enabled on free_irq | | The default_disable() function was changed in commit: | | 76d2160147f43f982dfe881404cfde9fd0a9da21 | genirq: do not mask interrupts by default | For MSI, default_shutdown will call mask_bit for msi device. All mask bits will left disabled after free_irq. Then in the kexec case, the next kernel can only use msi_enable bit, so all device's MSI can not be used. So lets to restore the mask bit to its pci reset defined value (enabled) when we disable the kernels use of msi to be a little friendlier to kexec'd kernels. Extend msi_set_mask_bit to msi_set_mask_bits to take mask, so we can fully restore that to 0x00 instead of 0xfe. Signed-off-by: Yinghai Lu <yhlu.kernel@gmail.com> Signed-off-by: Jesse Barnes <jbarnes@hobbes.lan>
-rw-r--r--drivers/pci/msi.c21
-rw-r--r--include/linux/msi.h1
2 files changed, 15 insertions, 7 deletions
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index 26938da8f438..e3a05cc9a595 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -123,7 +123,7 @@ static void msix_flush_writes(unsigned int irq)
123 } 123 }
124} 124}
125 125
126static void msi_set_mask_bit(unsigned int irq, int flag) 126static void msi_set_mask_bits(unsigned int irq, u32 mask, u32 flag)
127{ 127{
128 struct msi_desc *entry; 128 struct msi_desc *entry;
129 129
@@ -137,8 +137,8 @@ static void msi_set_mask_bit(unsigned int irq, int flag)
137 137
138 pos = (long)entry->mask_base; 138 pos = (long)entry->mask_base;
139 pci_read_config_dword(entry->dev, pos, &mask_bits); 139 pci_read_config_dword(entry->dev, pos, &mask_bits);
140 mask_bits &= ~(1); 140 mask_bits &= ~(mask);
141 mask_bits |= flag; 141 mask_bits |= flag & mask;
142 pci_write_config_dword(entry->dev, pos, mask_bits); 142 pci_write_config_dword(entry->dev, pos, mask_bits);
143 } else { 143 } else {
144 msi_set_enable(entry->dev, !flag); 144 msi_set_enable(entry->dev, !flag);
@@ -241,13 +241,13 @@ void write_msi_msg(unsigned int irq, struct msi_msg *msg)
241 241
242void mask_msi_irq(unsigned int irq) 242void mask_msi_irq(unsigned int irq)
243{ 243{
244 msi_set_mask_bit(irq, 1); 244 msi_set_mask_bits(irq, 1, 1);
245 msix_flush_writes(irq); 245 msix_flush_writes(irq);
246} 246}
247 247
248void unmask_msi_irq(unsigned int irq) 248void unmask_msi_irq(unsigned int irq)
249{ 249{
250 msi_set_mask_bit(irq, 0); 250 msi_set_mask_bits(irq, 1, 0);
251 msix_flush_writes(irq); 251 msix_flush_writes(irq);
252} 252}
253 253
@@ -291,7 +291,8 @@ static void __pci_restore_msi_state(struct pci_dev *dev)
291 msi_set_enable(dev, 0); 291 msi_set_enable(dev, 0);
292 write_msi_msg(dev->irq, &entry->msg); 292 write_msi_msg(dev->irq, &entry->msg);
293 if (entry->msi_attrib.maskbit) 293 if (entry->msi_attrib.maskbit)
294 msi_set_mask_bit(dev->irq, entry->msi_attrib.masked); 294 msi_set_mask_bits(dev->irq, entry->msi_attrib.maskbits_mask,
295 entry->msi_attrib.masked);
295 296
296 pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control); 297 pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control);
297 control &= ~(PCI_MSI_FLAGS_QSIZE | PCI_MSI_FLAGS_ENABLE); 298 control &= ~(PCI_MSI_FLAGS_QSIZE | PCI_MSI_FLAGS_ENABLE);
@@ -315,7 +316,7 @@ static void __pci_restore_msix_state(struct pci_dev *dev)
315 316
316 list_for_each_entry(entry, &dev->msi_list, list) { 317 list_for_each_entry(entry, &dev->msi_list, list) {
317 write_msi_msg(entry->irq, &entry->msg); 318 write_msi_msg(entry->irq, &entry->msg);
318 msi_set_mask_bit(entry->irq, entry->msi_attrib.masked); 319 msi_set_mask_bits(entry->irq, 1, entry->msi_attrib.masked);
319 } 320 }
320 321
321 BUG_ON(list_empty(&dev->msi_list)); 322 BUG_ON(list_empty(&dev->msi_list));
@@ -382,6 +383,7 @@ static int msi_capability_init(struct pci_dev *dev)
382 pci_write_config_dword(dev, 383 pci_write_config_dword(dev,
383 msi_mask_bits_reg(pos, is_64bit_address(control)), 384 msi_mask_bits_reg(pos, is_64bit_address(control)),
384 maskbits); 385 maskbits);
386 entry->msi_attrib.maskbits_mask = temp;
385 } 387 }
386 list_add_tail(&entry->list, &dev->msi_list); 388 list_add_tail(&entry->list, &dev->msi_list);
387 389
@@ -583,6 +585,11 @@ void pci_disable_msi(struct pci_dev* dev)
583 585
584 BUG_ON(list_empty(&dev->msi_list)); 586 BUG_ON(list_empty(&dev->msi_list));
585 entry = list_entry(dev->msi_list.next, struct msi_desc, list); 587 entry = list_entry(dev->msi_list.next, struct msi_desc, list);
588 /* Return the the pci reset with msi irqs unmasked */
589 if (entry->msi_attrib.maskbit) {
590 u32 mask = entry->msi_attrib.maskbits_mask;
591 msi_set_mask_bits(dev->irq, mask, ~mask);
592 }
586 if (!entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI) { 593 if (!entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI) {
587 return; 594 return;
588 } 595 }
diff --git a/include/linux/msi.h b/include/linux/msi.h
index 94bb46d82efd..8f2939227207 100644
--- a/include/linux/msi.h
+++ b/include/linux/msi.h
@@ -22,6 +22,7 @@ struct msi_desc {
22 __u8 masked : 1; 22 __u8 masked : 1;
23 __u8 is_64 : 1; /* Address size: 0=32bit 1=64bit */ 23 __u8 is_64 : 1; /* Address size: 0=32bit 1=64bit */
24 __u8 pos; /* Location of the msi capability */ 24 __u8 pos; /* Location of the msi capability */
25 __u32 maskbits_mask; /* mask bits mask */
25 __u16 entry_nr; /* specific enabled entry */ 26 __u16 entry_nr; /* specific enabled entry */
26 unsigned default_irq; /* default pre-assigned irq */ 27 unsigned default_irq; /* default pre-assigned irq */
27 }msi_attrib; 28 }msi_attrib;