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) } } -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; @@ -137,8 +137,8 @@ static void msi_set_mask_bit(unsigned int irq, int flag) pos = (long)entry->mask_base; pci_read_config_dword(entry->dev, pos, &mask_bits); - mask_bits &= ~(1); - mask_bits |= flag; + mask_bits &= ~(mask); + mask_bits |= flag & mask; pci_write_config_dword(entry->dev, pos, mask_bits); } else { msi_set_enable(entry->dev, !flag); @@ -241,13 +241,13 @@ void write_msi_msg(unsigned int irq, struct msi_msg *msg) void mask_msi_irq(unsigned int irq) { - msi_set_mask_bit(irq, 1); + msi_set_mask_bits(irq, 1, 1); msix_flush_writes(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); } @@ -291,7 +291,8 @@ static void __pci_restore_msi_state(struct pci_dev *dev) msi_set_enable(dev, 0); write_msi_msg(dev->irq, &entry->msg); 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); control &= ~(PCI_MSI_FLAGS_QSIZE | PCI_MSI_FLAGS_ENABLE); @@ -315,7 +316,7 @@ static void __pci_restore_msix_state(struct pci_dev *dev) list_for_each_entry(entry, &dev->msi_list, list) { 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)); @@ -382,6 +383,7 @@ static int msi_capability_init(struct pci_dev *dev) pci_write_config_dword(dev, msi_mask_bits_reg(pos, is_64bit_address(control)), maskbits); + entry->msi_attrib.maskbits_mask = temp; } list_add_tail(&entry->list, &dev->msi_list); @@ -583,6 +585,11 @@ void pci_disable_msi(struct pci_dev* dev) BUG_ON(list_empty(&dev->msi_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) { return; } 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 { __u8 masked : 1; __u8 is_64 : 1; /* Address size: 0=32bit 1=64bit */ __u8 pos; /* Location of the msi capability */ + __u32 maskbits_mask; /* mask bits mask */ __u16 entry_nr; /* specific enabled entry */ unsigned default_irq; /* default pre-assigned irq */ }msi_attrib;