Commit 8e149e09 authored by Yinghai Lu's avatar Yinghai Lu Committed by Jesse Barnes

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 89d694b9
| 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:
|
|    76d21601
|    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: default avatarYinghai Lu <yhlu.kernel@gmail.com>
Signed-off-by: default avatarJesse Barnes <jbarnes@hobbes.lan>
parent 2768f92c
...@@ -123,7 +123,7 @@ static void msix_flush_writes(unsigned int irq) ...@@ -123,7 +123,7 @@ static void msix_flush_writes(unsigned int irq)
} }
} }
static void msi_set_mask_bit(unsigned int irq, int flag) static void msi_set_mask_bits(unsigned int irq, u32 mask, u32 flag)
{ {
struct msi_desc *entry; struct msi_desc *entry;
...@@ -137,8 +137,8 @@ static void msi_set_mask_bit(unsigned int irq, int flag) ...@@ -137,8 +137,8 @@ static void msi_set_mask_bit(unsigned int irq, int flag)
pos = (long)entry->mask_base; pos = (long)entry->mask_base;
pci_read_config_dword(entry->dev, pos, &mask_bits); pci_read_config_dword(entry->dev, pos, &mask_bits);
mask_bits &= ~(1); mask_bits &= ~(mask);
mask_bits |= flag; mask_bits |= flag & mask;
pci_write_config_dword(entry->dev, pos, mask_bits); pci_write_config_dword(entry->dev, pos, mask_bits);
} else { } else {
msi_set_enable(entry->dev, !flag); msi_set_enable(entry->dev, !flag);
...@@ -241,13 +241,13 @@ void write_msi_msg(unsigned int irq, struct msi_msg *msg) ...@@ -241,13 +241,13 @@ void write_msi_msg(unsigned int irq, struct msi_msg *msg)
void mask_msi_irq(unsigned int irq) void mask_msi_irq(unsigned int irq)
{ {
msi_set_mask_bit(irq, 1); msi_set_mask_bits(irq, 1, 1);
msix_flush_writes(irq); msix_flush_writes(irq);
} }
void unmask_msi_irq(unsigned int irq) void unmask_msi_irq(unsigned int irq)
{ {
msi_set_mask_bit(irq, 0); msi_set_mask_bits(irq, 1, 0);
msix_flush_writes(irq); msix_flush_writes(irq);
} }
...@@ -291,7 +291,8 @@ static void __pci_restore_msi_state(struct pci_dev *dev) ...@@ -291,7 +291,8 @@ static void __pci_restore_msi_state(struct pci_dev *dev)
msi_set_enable(dev, 0); msi_set_enable(dev, 0);
write_msi_msg(dev->irq, &entry->msg); write_msi_msg(dev->irq, &entry->msg);
if (entry->msi_attrib.maskbit) if (entry->msi_attrib.maskbit)
msi_set_mask_bit(dev->irq, entry->msi_attrib.masked); msi_set_mask_bits(dev->irq, entry->msi_attrib.maskbits_mask,
entry->msi_attrib.masked);
pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control); pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control);
control &= ~(PCI_MSI_FLAGS_QSIZE | PCI_MSI_FLAGS_ENABLE); control &= ~(PCI_MSI_FLAGS_QSIZE | PCI_MSI_FLAGS_ENABLE);
...@@ -315,7 +316,7 @@ static void __pci_restore_msix_state(struct pci_dev *dev) ...@@ -315,7 +316,7 @@ static void __pci_restore_msix_state(struct pci_dev *dev)
list_for_each_entry(entry, &dev->msi_list, list) { list_for_each_entry(entry, &dev->msi_list, list) {
write_msi_msg(entry->irq, &entry->msg); write_msi_msg(entry->irq, &entry->msg);
msi_set_mask_bit(entry->irq, entry->msi_attrib.masked); msi_set_mask_bits(entry->irq, 1, entry->msi_attrib.masked);
} }
BUG_ON(list_empty(&dev->msi_list)); BUG_ON(list_empty(&dev->msi_list));
...@@ -382,6 +383,7 @@ static int msi_capability_init(struct pci_dev *dev) ...@@ -382,6 +383,7 @@ static int msi_capability_init(struct pci_dev *dev)
pci_write_config_dword(dev, pci_write_config_dword(dev,
msi_mask_bits_reg(pos, is_64bit_address(control)), msi_mask_bits_reg(pos, is_64bit_address(control)),
maskbits); maskbits);
entry->msi_attrib.maskbits_mask = temp;
} }
list_add_tail(&entry->list, &dev->msi_list); list_add_tail(&entry->list, &dev->msi_list);
...@@ -583,6 +585,11 @@ void pci_disable_msi(struct pci_dev* dev) ...@@ -583,6 +585,11 @@ void pci_disable_msi(struct pci_dev* dev)
BUG_ON(list_empty(&dev->msi_list)); BUG_ON(list_empty(&dev->msi_list));
entry = list_entry(dev->msi_list.next, struct msi_desc, list); entry = list_entry(dev->msi_list.next, struct msi_desc, list);
/* Return the the pci reset with msi irqs unmasked */
if (entry->msi_attrib.maskbit) {
u32 mask = entry->msi_attrib.maskbits_mask;
msi_set_mask_bits(dev->irq, mask, ~mask);
}
if (!entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI) { if (!entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI) {
return; return;
} }
......
...@@ -22,6 +22,7 @@ struct msi_desc { ...@@ -22,6 +22,7 @@ struct msi_desc {
__u8 masked : 1; __u8 masked : 1;
__u8 is_64 : 1; /* Address size: 0=32bit 1=64bit */ __u8 is_64 : 1; /* Address size: 0=32bit 1=64bit */
__u8 pos; /* Location of the msi capability */ __u8 pos; /* Location of the msi capability */
__u32 maskbits_mask; /* mask bits mask */
__u16 entry_nr; /* specific enabled entry */ __u16 entry_nr; /* specific enabled entry */
unsigned default_irq; /* default pre-assigned irq */ unsigned default_irq; /* default pre-assigned irq */
}msi_attrib; }msi_attrib;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment