Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Yinghai Lu and committed by
Jesse Barnes
8e149e09 2768f92c

+15 -7
+14 -7
drivers/pci/msi.c
··· 123 123 } 124 124 } 125 125 126 - static void msi_set_mask_bit(unsigned int irq, int flag) 126 + static void msi_set_mask_bits(unsigned int irq, u32 mask, u32 flag) 127 127 { 128 128 struct msi_desc *entry; 129 129 ··· 137 137 138 138 pos = (long)entry->mask_base; 139 139 pci_read_config_dword(entry->dev, pos, &mask_bits); 140 - mask_bits &= ~(1); 141 - mask_bits |= flag; 140 + mask_bits &= ~(mask); 141 + mask_bits |= flag & mask; 142 142 pci_write_config_dword(entry->dev, pos, mask_bits); 143 143 } else { 144 144 msi_set_enable(entry->dev, !flag); ··· 241 241 242 242 void mask_msi_irq(unsigned int irq) 243 243 { 244 - msi_set_mask_bit(irq, 1); 244 + msi_set_mask_bits(irq, 1, 1); 245 245 msix_flush_writes(irq); 246 246 } 247 247 248 248 void unmask_msi_irq(unsigned int irq) 249 249 { 250 - msi_set_mask_bit(irq, 0); 250 + msi_set_mask_bits(irq, 1, 0); 251 251 msix_flush_writes(irq); 252 252 } 253 253 ··· 291 291 msi_set_enable(dev, 0); 292 292 write_msi_msg(dev->irq, &entry->msg); 293 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 297 pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control); 297 298 control &= ~(PCI_MSI_FLAGS_QSIZE | PCI_MSI_FLAGS_ENABLE); ··· 316 315 317 316 list_for_each_entry(entry, &dev->msi_list, list) { 318 317 write_msi_msg(entry->irq, &entry->msg); 319 - msi_set_mask_bit(entry->irq, entry->msi_attrib.masked); 318 + msi_set_mask_bits(entry->irq, 1, entry->msi_attrib.masked); 320 319 } 321 320 322 321 BUG_ON(list_empty(&dev->msi_list)); ··· 383 382 pci_write_config_dword(dev, 384 383 msi_mask_bits_reg(pos, is_64bit_address(control)), 385 384 maskbits); 385 + entry->msi_attrib.maskbits_mask = temp; 386 386 } 387 387 list_add_tail(&entry->list, &dev->msi_list); 388 388 ··· 585 583 586 584 BUG_ON(list_empty(&dev->msi_list)); 587 585 entry = list_entry(dev->msi_list.next, struct msi_desc, list); 586 + /* Return the the pci reset with msi irqs unmasked */ 587 + if (entry->msi_attrib.maskbit) { 588 + u32 mask = entry->msi_attrib.maskbits_mask; 589 + msi_set_mask_bits(dev->irq, mask, ~mask); 590 + } 588 591 if (!entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI) { 589 592 return; 590 593 }
+1
include/linux/msi.h
··· 22 22 __u8 masked : 1; 23 23 __u8 is_64 : 1; /* Address size: 0=32bit 1=64bit */ 24 24 __u8 pos; /* Location of the msi capability */ 25 + __u32 maskbits_mask; /* mask bits mask */ 25 26 __u16 entry_nr; /* specific enabled entry */ 26 27 unsigned default_irq; /* default pre-assigned irq */ 27 28 }msi_attrib;