From: Shaohua Li It appears pci_enable_msi doesn't reconfigure msi registers if it successfully look up a msi for a device. It assumes the data and address registers unchanged after calling pci_disable_msi. But this isn't always true, such as in a suspend/resume circle. In my test system, the registers unsurprised become zero after a S3 resume. This patch fixes my problem, please look at it. MSIX might have the same issue, but I haven't taken a close look. Signed-off-by: Andrew Morton --- drivers/pci/msi.c | 72 ++++++++++++++++++++++++++++++++---------------------- 1 files changed, 43 insertions(+), 29 deletions(-) diff -puN drivers/pci/msi.c~reconfigure-msi-registers-after-resume drivers/pci/msi.c --- devel/drivers/pci/msi.c~reconfigure-msi-registers-after-resume 2005-08-17 22:43:19.000000000 -0700 +++ devel-akpm/drivers/pci/msi.c 2005-08-17 22:43:19.000000000 -0700 @@ -495,6 +495,45 @@ void pci_scan_msi_device(struct pci_dev nr_reserved_vectors++; } +static void msi_register_init(struct pci_dev *dev, struct msi_desc *entry) +{ + struct msg_address address; + struct msg_data data; + int pos, vector = dev->irq; + u16 control; + + pos = pci_find_capability(dev, PCI_CAP_ID_MSI); + pci_read_config_word(dev, msi_control_reg(pos), &control); + /* Configure MSI capability structure */ + msi_address_init(&address); + msi_data_init(&data, vector); + entry->msi_attrib.current_cpu = ((address.lo_address.u.dest_id >> + MSI_TARGET_CPU_SHIFT) & MSI_TARGET_CPU_MASK); + pci_write_config_dword(dev, msi_lower_address_reg(pos), + address.lo_address.value); + if (is_64bit_address(control)) { + pci_write_config_dword(dev, + msi_upper_address_reg(pos), address.hi_address); + pci_write_config_word(dev, + msi_data_reg(pos, 1), *((u32*)&data)); + } else + pci_write_config_word(dev, + msi_data_reg(pos, 0), *((u32*)&data)); + if (entry->msi_attrib.maskbit) { + unsigned int maskbits, temp; + /* All MSIs are unmasked by default, Mask them all */ + pci_read_config_dword(dev, + msi_mask_bits_reg(pos, is_64bit_address(control)), + &maskbits); + temp = (1 << multi_msi_capable(control)); + temp = ((temp - 1) & ~temp); + maskbits |= temp; + pci_write_config_dword(dev, + msi_mask_bits_reg(pos, is_64bit_address(control)), + maskbits); + } +} + /** * msi_capability_init - configure device's MSI capability structure * @dev: pointer to the pci_dev data structure of MSI device function @@ -507,8 +546,6 @@ void pci_scan_msi_device(struct pci_dev static int msi_capability_init(struct pci_dev *dev) { struct msi_desc *entry; - struct msg_address address; - struct msg_data data; int pos, vector; u16 control; @@ -538,33 +575,8 @@ static int msi_capability_init(struct pc /* Replace with MSI handler */ irq_handler_init(PCI_CAP_ID_MSI, vector, entry->msi_attrib.maskbit); /* Configure MSI capability structure */ - msi_address_init(&address); - msi_data_init(&data, vector); - entry->msi_attrib.current_cpu = ((address.lo_address.u.dest_id >> - MSI_TARGET_CPU_SHIFT) & MSI_TARGET_CPU_MASK); - pci_write_config_dword(dev, msi_lower_address_reg(pos), - address.lo_address.value); - if (is_64bit_address(control)) { - pci_write_config_dword(dev, - msi_upper_address_reg(pos), address.hi_address); - pci_write_config_word(dev, - msi_data_reg(pos, 1), *((u32*)&data)); - } else - pci_write_config_word(dev, - msi_data_reg(pos, 0), *((u32*)&data)); - if (entry->msi_attrib.maskbit) { - unsigned int maskbits, temp; - /* All MSIs are unmasked by default, Mask them all */ - pci_read_config_dword(dev, - msi_mask_bits_reg(pos, is_64bit_address(control)), - &maskbits); - temp = (1 << multi_msi_capable(control)); - temp = ((temp - 1) & ~temp); - maskbits |= temp; - pci_write_config_dword(dev, - msi_mask_bits_reg(pos, is_64bit_address(control)), - maskbits); - } + msi_register_init(dev, entry); + attach_msi_entry(entry, vector); /* Set MSI enabled bits */ enable_msi_mode(dev, pos, PCI_CAP_ID_MSI); @@ -711,6 +723,8 @@ int pci_enable_msi(struct pci_dev* dev) vector_irq[dev->irq] = -1; nr_released_vectors--; spin_unlock_irqrestore(&msi_lock, flags); + + msi_register_init(dev, msi_desc[dev->irq]); enable_msi_mode(dev, pos, PCI_CAP_ID_MSI); return 0; } _