| From e045fa29e89383c717e308609edd19d2fd29e1be Mon Sep 17 00:00:00 2001 |
| From: Jian-Hong Pan <jian-hong@endlessm.com> |
| Date: Tue, 8 Oct 2019 11:42:39 +0800 |
| Subject: PCI/MSI: Fix incorrect MSI-X masking on resume |
| |
| From: Jian-Hong Pan <jian-hong@endlessm.com> |
| |
| commit e045fa29e89383c717e308609edd19d2fd29e1be upstream. |
| |
| When a driver enables MSI-X, msix_program_entries() reads the MSI-X Vector |
| Control register for each vector and saves it in desc->masked. Each |
| register is 32 bits and bit 0 is the actual Mask bit. |
| |
| When we restored these registers during resume, we previously set the Mask |
| bit if *any* bit in desc->masked was set instead of when the Mask bit |
| itself was set: |
| |
| pci_restore_state |
| pci_restore_msi_state |
| __pci_restore_msix_state |
| for_each_pci_msi_entry |
| msix_mask_irq(entry, entry->masked) <-- entire u32 word |
| __pci_msix_desc_mask_irq(desc, flag) |
| mask_bits = desc->masked & ~PCI_MSIX_ENTRY_CTRL_MASKBIT |
| if (flag) <-- testing entire u32, not just bit 0 |
| mask_bits |= PCI_MSIX_ENTRY_CTRL_MASKBIT |
| writel(mask_bits, desc_addr + PCI_MSIX_ENTRY_VECTOR_CTRL) |
| |
| This means that after resume, MSI-X vectors were masked when they shouldn't |
| be, which leads to timeouts like this: |
| |
| nvme nvme0: I/O 978 QID 3 timeout, completion polled |
| |
| On resume, set the Mask bit only when the saved Mask bit from suspend was |
| set. |
| |
| This should remove the need for 19ea025e1d28 ("nvme: Add quirk for Kingston |
| NVME SSD running FW E8FK11.T"). |
| |
| [bhelgaas: commit log, move fix to __pci_msix_desc_mask_irq()] |
| Link: https://bugzilla.kernel.org/show_bug.cgi?id=204887 |
| Link: https://lore.kernel.org/r/20191008034238.2503-1-jian-hong@endlessm.com |
| Fixes: f2440d9acbe8 ("PCI MSI: Refactor interrupt masking code") |
| Signed-off-by: Jian-Hong Pan <jian-hong@endlessm.com> |
| Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> |
| Cc: stable@vger.kernel.org |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/pci/msi.c | 2 +- |
| 1 file changed, 1 insertion(+), 1 deletion(-) |
| |
| --- a/drivers/pci/msi.c |
| +++ b/drivers/pci/msi.c |
| @@ -200,7 +200,7 @@ u32 default_msix_mask_irq(struct msi_des |
| unsigned offset = desc->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE + |
| PCI_MSIX_ENTRY_VECTOR_CTRL; |
| mask_bits &= ~PCI_MSIX_ENTRY_CTRL_MASKBIT; |
| - if (flag) |
| + if (flag & PCI_MSIX_ENTRY_CTRL_MASKBIT) |
| mask_bits |= PCI_MSIX_ENTRY_CTRL_MASKBIT; |
| writel(mask_bits, desc->mask_base + offset); |
| |