--- /dev/null
+From b9255a7cb51754e8d2645b65dd31805e282b4f3e Mon Sep 17 00:00:00 2001
+From: Thomas Gleixner <tglx@linutronix.de>
+Date: Thu, 29 Jul 2021 23:51:43 +0200
+Subject: PCI/MSI: Enforce MSI[X] entry updates to be visible
+
+From: Thomas Gleixner <tglx@linutronix.de>
+
+commit b9255a7cb51754e8d2645b65dd31805e282b4f3e upstream.
+
+Nothing enforces the posted writes to be visible when the function
+returns. Flush them even if the flush might be redundant when the entry is
+masked already as the unmask will flush as well. This is either setup or a
+rare affinity change event so the extra flush is not the end of the world.
+
+While this is more a theoretical issue especially the logic in the X86
+specific msi_set_affinity() function relies on the assumption that the
+update has reached the hardware when the function returns.
+
+Again, as this never has been enforced the Fixes tag refers to a commit in:
+ git://git.kernel.org/pub/scm/linux/kernel/git/tglx/history.git
+
+Fixes: f036d4ea5fa7 ("[PATCH] ia32 Message Signalled Interrupt support")
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Tested-by: Marc Zyngier <maz@kernel.org>
+Reviewed-by: Marc Zyngier <maz@kernel.org>
+Acked-by: Bjorn Helgaas <bhelgaas@google.com>
+Cc: stable@vger.kernel.org
+Link: https://lore.kernel.org/r/20210729222542.515188147@linutronix.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/pci/msi.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/drivers/pci/msi.c
++++ b/drivers/pci/msi.c
+@@ -322,6 +322,9 @@ void __pci_write_msi_msg(struct msi_desc
+
+ if (unmasked)
+ __pci_msix_desc_mask_irq(entry, 0);
++
++ /* Ensure that the writes are visible in the device */
++ readl(base + PCI_MSIX_ENTRY_DATA);
+ } else {
+ int pos = dev->msi_cap;
+ u16 msgctl;
+@@ -342,6 +345,8 @@ void __pci_write_msi_msg(struct msi_desc
+ pci_write_config_word(dev, pos + PCI_MSI_DATA_32,
+ msg->data);
+ }
++ /* Ensure that the writes are visible in the device */
++ pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &msgctl);
+ }
+ entry->msg = *msg;
+ }
--- /dev/null
+From da181dc974ad667579baece33c2c8d2d1e4558d5 Mon Sep 17 00:00:00 2001
+From: Thomas Gleixner <tglx@linutronix.de>
+Date: Thu, 29 Jul 2021 23:51:42 +0200
+Subject: PCI/MSI: Enforce that MSI-X table entry is masked for update
+
+From: Thomas Gleixner <tglx@linutronix.de>
+
+commit da181dc974ad667579baece33c2c8d2d1e4558d5 upstream.
+
+The specification (PCIe r5.0, sec 6.1.4.5) states:
+
+ For MSI-X, a function is permitted to cache Address and Data values
+ from unmasked MSI-X Table entries. However, anytime software unmasks a
+ currently masked MSI-X Table entry either by clearing its Mask bit or
+ by clearing the Function Mask bit, the function must update any Address
+ or Data values that it cached from that entry. If software changes the
+ Address or Data value of an entry while the entry is unmasked, the
+ result is undefined.
+
+The Linux kernel's MSI-X support never enforced that the entry is masked
+before the entry is modified hence the Fixes tag refers to a commit in:
+ git://git.kernel.org/pub/scm/linux/kernel/git/tglx/history.git
+
+Enforce the entry to be masked across the update.
+
+There is no point in enforcing this to be handled at all possible call
+sites as this is just pointless code duplication and the common update
+function is the obvious place to enforce this.
+
+Fixes: f036d4ea5fa7 ("[PATCH] ia32 Message Signalled Interrupt support")
+Reported-by: Kevin Tian <kevin.tian@intel.com>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Tested-by: Marc Zyngier <maz@kernel.org>
+Reviewed-by: Marc Zyngier <maz@kernel.org>
+Acked-by: Bjorn Helgaas <bhelgaas@google.com>
+Cc: stable@vger.kernel.org
+Link: https://lore.kernel.org/r/20210729222542.462096385@linutronix.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/pci/msi.c | 15 +++++++++++++++
+ 1 file changed, 15 insertions(+)
+
+--- a/drivers/pci/msi.c
++++ b/drivers/pci/msi.c
+@@ -303,10 +303,25 @@ void __pci_write_msi_msg(struct msi_desc
+ /* Don't touch the hardware now */
+ } else if (entry->msi_attrib.is_msix) {
+ void __iomem *base = pci_msix_desc_addr(entry);
++ bool unmasked = !(entry->masked & PCI_MSIX_ENTRY_CTRL_MASKBIT);
++
++ /*
++ * The specification mandates that the entry is masked
++ * when the message is modified:
++ *
++ * "If software changes the Address or Data value of an
++ * entry while the entry is unmasked, the result is
++ * undefined."
++ */
++ if (unmasked)
++ __pci_msix_desc_mask_irq(entry, PCI_MSIX_ENTRY_CTRL_MASKBIT);
+
+ writel(msg->address_lo, base + PCI_MSIX_ENTRY_LOWER_ADDR);
+ writel(msg->address_hi, base + PCI_MSIX_ENTRY_UPPER_ADDR);
+ writel(msg->data, base + PCI_MSIX_ENTRY_DATA);
++
++ if (unmasked)
++ __pci_msix_desc_mask_irq(entry, 0);
+ } else {
+ int pos = dev->msi_cap;
+ u16 msgctl;
--- /dev/null
+From 7d5ec3d3612396dc6d4b76366d20ab9fc06f399f Mon Sep 17 00:00:00 2001
+From: Thomas Gleixner <tglx@linutronix.de>
+Date: Thu, 29 Jul 2021 23:51:41 +0200
+Subject: PCI/MSI: Mask all unused MSI-X entries
+
+From: Thomas Gleixner <tglx@linutronix.de>
+
+commit 7d5ec3d3612396dc6d4b76366d20ab9fc06f399f upstream.
+
+When MSI-X is enabled the ordering of calls is:
+
+ msix_map_region();
+ msix_setup_entries();
+ pci_msi_setup_msi_irqs();
+ msix_program_entries();
+
+This has a few interesting issues:
+
+ 1) msix_setup_entries() allocates the MSI descriptors and initializes them
+ except for the msi_desc:masked member which is left zero initialized.
+
+ 2) pci_msi_setup_msi_irqs() allocates the interrupt descriptors and sets
+ up the MSI interrupts which ends up in pci_write_msi_msg() unless the
+ interrupt chip provides its own irq_write_msi_msg() function.
+
+ 3) msix_program_entries() does not do what the name suggests. It solely
+ updates the entries array (if not NULL) and initializes the masked
+ member for each MSI descriptor by reading the hardware state and then
+ masks the entry.
+
+Obviously this has some issues:
+
+ 1) The uninitialized masked member of msi_desc prevents the enforcement
+ of masking the entry in pci_write_msi_msg() depending on the cached
+ masked bit. Aside of that half initialized data is a NONO in general
+
+ 2) msix_program_entries() only ensures that the actually allocated entries
+ are masked. This is wrong as experimentation with crash testing and
+ crash kernel kexec has shown.
+
+ This limited testing unearthed that when the production kernel had more
+ entries in use and unmasked when it crashed and the crash kernel
+ allocated a smaller amount of entries, then a full scan of all entries
+ found unmasked entries which were in use in the production kernel.
+
+ This is obviously a device or emulation issue as the device reset
+ should mask all MSI-X table entries, but obviously that's just part
+ of the paper specification.
+
+Cure this by:
+
+ 1) Masking all table entries in hardware
+ 2) Initializing msi_desc::masked in msix_setup_entries()
+ 3) Removing the mask dance in msix_program_entries()
+ 4) Renaming msix_program_entries() to msix_update_entries() to
+ reflect the purpose of that function.
+
+As the masking of unused entries has never been done the Fixes tag refers
+to a commit in:
+ git://git.kernel.org/pub/scm/linux/kernel/git/tglx/history.git
+
+Fixes: f036d4ea5fa7 ("[PATCH] ia32 Message Signalled Interrupt support")
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Tested-by: Marc Zyngier <maz@kernel.org>
+Reviewed-by: Marc Zyngier <maz@kernel.org>
+Acked-by: Bjorn Helgaas <bhelgaas@google.com>
+Cc: stable@vger.kernel.org
+Link: https://lore.kernel.org/r/20210729222542.403833459@linutronix.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/pci/msi.c | 40 ++++++++++++++++++++++++++++------------
+ 1 file changed, 28 insertions(+), 12 deletions(-)
+
+--- a/drivers/pci/msi.c
++++ b/drivers/pci/msi.c
+@@ -675,6 +675,7 @@ static int msix_setup_entries(struct pci
+ {
+ struct cpumask *curmsk, *masks = NULL;
+ struct msi_desc *entry;
++ void __iomem *addr;
+ int ret, i;
+
+ if (affd)
+@@ -694,6 +695,7 @@ static int msix_setup_entries(struct pci
+
+ entry->msi_attrib.is_msix = 1;
+ entry->msi_attrib.is_64 = 1;
++
+ if (entries)
+ entry->msi_attrib.entry_nr = entries[i].entry;
+ else
+@@ -701,6 +703,10 @@ static int msix_setup_entries(struct pci
+ entry->msi_attrib.default_irq = dev->irq;
+ entry->mask_base = base;
+
++ addr = pci_msix_desc_addr(entry);
++ if (addr)
++ entry->masked = readl(addr + PCI_MSIX_ENTRY_VECTOR_CTRL);
++
+ list_add_tail(&entry->list, dev_to_msi_list(&dev->dev));
+ if (masks)
+ curmsk++;
+@@ -711,21 +717,27 @@ out:
+ return ret;
+ }
+
+-static void msix_program_entries(struct pci_dev *dev,
+- struct msix_entry *entries)
++static void msix_update_entries(struct pci_dev *dev, struct msix_entry *entries)
+ {
+ struct msi_desc *entry;
+- int i = 0;
+
+ for_each_pci_msi_entry(entry, dev) {
+- if (entries)
+- entries[i++].vector = entry->irq;
+- entry->masked = readl(pci_msix_desc_addr(entry) +
+- PCI_MSIX_ENTRY_VECTOR_CTRL);
+- msix_mask_irq(entry, 1);
++ if (entries) {
++ entries->vector = entry->irq;
++ entries++;
++ }
+ }
+ }
+
++static void msix_mask_all(void __iomem *base, int tsize)
++{
++ u32 ctrl = PCI_MSIX_ENTRY_CTRL_MASKBIT;
++ int i;
++
++ for (i = 0; i < tsize; i++, base += PCI_MSIX_ENTRY_SIZE)
++ writel(ctrl, base + PCI_MSIX_ENTRY_VECTOR_CTRL);
++}
++
+ /**
+ * msix_capability_init - configure device's MSI-X capability
+ * @dev: pointer to the pci_dev data structure of MSI-X device function
+@@ -740,9 +752,9 @@ static void msix_program_entries(struct
+ static int msix_capability_init(struct pci_dev *dev, struct msix_entry *entries,
+ int nvec, const struct irq_affinity *affd)
+ {
+- int ret;
+- u16 control;
+ void __iomem *base;
++ int ret, tsize;
++ u16 control;
+
+ /*
+ * Some devices require MSI-X to be enabled before the MSI-X
+@@ -754,12 +766,16 @@ static int msix_capability_init(struct p
+
+ pci_read_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, &control);
+ /* Request & Map MSI-X table region */
+- base = msix_map_region(dev, msix_table_size(control));
++ tsize = msix_table_size(control);
++ base = msix_map_region(dev, tsize);
+ if (!base) {
+ ret = -ENOMEM;
+ goto out_disable;
+ }
+
++ /* Ensure that all table entries are masked. */
++ msix_mask_all(base, tsize);
++
+ ret = msix_setup_entries(dev, base, entries, nvec, affd);
+ if (ret)
+ goto out_disable;
+@@ -773,7 +789,7 @@ static int msix_capability_init(struct p
+ if (ret)
+ goto out_free;
+
+- msix_program_entries(dev, entries);
++ msix_update_entries(dev, entries);
+
+ ret = populate_msi_sysfs(dev);
+ if (ret)