linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Sasha Levin <sashal@kernel.org>
To: linux-kernel@vger.kernel.org, stable@vger.kernel.org
Cc: Thomas Gleixner <tglx@linutronix.de>,
	Marc Zyngier <maz@kernel.org>,
	Bjorn Helgaas <bhelgaas@google.com>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Subject: [PATCH 4.4 11/31] PCI/MSI: Mask all unused MSI-X entries
Date: Tue, 24 Aug 2021 13:07:23 -0400	[thread overview]
Message-ID: <20210824170743.710957-12-sashal@kernel.org> (raw)
In-Reply-To: <20210824170743.710957-1-sashal@kernel.org>

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 | 45 +++++++++++++++++++++++++++++++--------------
 1 file changed, 31 insertions(+), 14 deletions(-)

diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index dffa5c5bcc76..9cc4a598c652 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -208,6 +208,12 @@ static void msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag)
 	__pci_msi_desc_mask_irq(desc, mask, flag);
 }
 
+static void __iomem *pci_msix_desc_addr(struct msi_desc *desc)
+{
+	return desc->mask_base +
+		desc->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE;
+}
+
 /*
  * This internal function does not flush PCI writes to the device.
  * All users must ensure that they read from the device before either
@@ -678,6 +684,7 @@ static int msix_setup_entries(struct pci_dev *dev, void __iomem *base,
 			      struct msix_entry *entries, int nvec)
 {
 	struct msi_desc *entry;
+	void __iomem *addr;
 	int i;
 
 	for (i = 0; i < nvec; i++) {
@@ -698,29 +705,35 @@ static int msix_setup_entries(struct pci_dev *dev, void __iomem *base,
 		entry->mask_base		= base;
 		entry->nvec_used		= 1;
 
+		addr = pci_msix_desc_addr(entry);
+		entry->masked = readl(addr + PCI_MSIX_ENTRY_VECTOR_CTRL);
 		list_add_tail(&entry->list, dev_to_msi_list(&dev->dev));
 	}
 
 	return 0;
 }
 
-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) {
-		int offset = entries[i].entry * PCI_MSIX_ENTRY_SIZE +
-						PCI_MSIX_ENTRY_VECTOR_CTRL;
-
-		entries[i].vector = entry->irq;
-		entry->masked = readl(entry->mask_base + offset);
-		msix_mask_irq(entry, 1);
-		i++;
+		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
@@ -734,9 +747,9 @@ static void msix_program_entries(struct pci_dev *dev,
 static int msix_capability_init(struct pci_dev *dev,
 				struct msix_entry *entries, int nvec)
 {
-	int ret;
-	u16 control;
 	void __iomem *base;
+	int ret, tsize;
+	u16 control;
 
 	/*
 	 * Some devices require MSI-X to be enabled before the MSI-X
@@ -748,12 +761,16 @@ static int msix_capability_init(struct pci_dev *dev,
 
 	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);
 	if (ret)
 		goto out_disable;
@@ -767,7 +784,7 @@ static int msix_capability_init(struct pci_dev *dev,
 	if (ret)
 		goto out_free;
 
-	msix_program_entries(dev, entries);
+	msix_update_entries(dev, entries);
 
 	ret = populate_msi_sysfs(dev);
 	if (ret)
-- 
2.30.2


  parent reply	other threads:[~2021-08-24 17:39 UTC|newest]

Thread overview: 38+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-08-24 17:07 [PATCH 4.4 00/31] 4.4.282-rc1 review Sasha Levin
2021-08-24 17:07 ` [PATCH 4.4 01/31] ASoC: intel: atom: Fix reference to PCM buffer address Sasha Levin
2021-08-24 17:07 ` [PATCH 4.4 02/31] i2c: dev: zero out array used for i2c reads from userspace Sasha Levin
2021-08-24 17:07 ` [PATCH 4.4 03/31] net: Fix memory leak in ieee802154_raw_deliver Sasha Levin
2021-08-24 17:07 ` [PATCH 4.4 04/31] xen/events: Fix race in set_evtchn_to_irq Sasha Levin
2021-08-24 17:07 ` [PATCH 4.4 05/31] x86/tools: Fix objdump version check again Sasha Levin
2021-08-24 17:07 ` [PATCH 4.4 06/31] PCI/MSI: Enable and mask MSI-X early Sasha Levin
2021-08-24 17:07 ` [PATCH 4.4 07/31] PCI/MSI: Do not set invalid bits in MSI mask Sasha Levin
2021-08-24 17:07 ` [PATCH 4.4 08/31] PCI/MSI: Correct misleading comments Sasha Levin
2021-08-24 17:07 ` [PATCH 4.4 09/31] PCI/MSI: Use msi_mask_irq() in pci_msi_shutdown() Sasha Levin
2021-08-24 17:07 ` [PATCH 4.4 10/31] PCI/MSI: Protect msi_desc::masked for multi-MSI Sasha Levin
2021-08-24 17:07 ` Sasha Levin [this message]
2021-08-24 17:07 ` [PATCH 4.4 12/31] PCI/MSI: Enforce that MSI-X table entry is masked for update Sasha Levin
2021-08-24 17:07 ` [PATCH 4.4 13/31] PCI/MSI: Enforce MSI[X] entry updates to be visible Sasha Levin
2021-08-24 17:07 ` [PATCH 4.4 14/31] vmlinux.lds.h: Handle clang's module.{c,d}tor sections Sasha Levin
2021-08-24 17:07 ` [PATCH 4.4 15/31] KVM: nSVM: avoid picking up unsupported bits from L2 in int_ctl (CVE-2021-3653) Sasha Levin
2021-08-24 17:07 ` [PATCH 4.4 16/31] dmaengine: usb-dmac: Fix PM reference leak in usb_dmac_probe() Sasha Levin
2021-08-24 17:07 ` [PATCH 4.4 17/31] ARM: dts: am43x-epos-evm: Reduce i2c0 bus speed for tps65218 Sasha Levin
2021-08-24 17:07 ` [PATCH 4.4 18/31] dmaengine: of-dma: router_xlate to return -EPROBE_DEFER if controller is not yet available Sasha Levin
2021-08-24 17:07 ` [PATCH 4.4 19/31] scsi: megaraid_mm: Fix end of loop tests for list_for_each_entry() Sasha Levin
2021-08-24 17:07 ` [PATCH 4.4 20/31] scsi: core: Avoid printing an error if target_alloc() returns -ENXIO Sasha Levin
2021-08-24 17:07 ` [PATCH 4.4 21/31] Bluetooth: hidp: use correct wait queue when removing ctrl_wait Sasha Levin
2021-08-24 17:07 ` [PATCH 4.4 22/31] dccp: add do-while-0 stubs for dccp_pr_debug macros Sasha Levin
2021-08-24 17:07 ` [PATCH 4.4 23/31] net: 6pack: fix slab-out-of-bounds in decode_data Sasha Levin
2021-08-24 17:07 ` [PATCH 4.4 24/31] net: qlcnic: add missed unlock in qlcnic_83xx_flash_read32 Sasha Levin
2021-08-24 17:07 ` [PATCH 4.4 25/31] mmc: dw_mmc: Wait for data transfer after response errors Sasha Levin
2021-08-26 11:59   ` Nobuhiro Iwamatsu
2021-08-26 12:31     ` Sasha Levin
2021-08-24 17:07 ` [PATCH 4.4 26/31] mmc: dw_mmc: call the dw_mci_prep_stop_abort() by default Sasha Levin
2021-08-24 17:07 ` [PATCH 4.4 27/31] mmc: dw_mmc: Fix hang on data CRC error Sasha Levin
2021-08-24 17:07 ` [PATCH 4.4 28/31] ALSA: hda - fix the 'Capture Switch' value change notifications Sasha Levin
2021-08-24 17:07 ` [PATCH 4.4 29/31] ipack: tpci200: fix many double free issues in tpci200_pci_probe Sasha Levin
2021-08-24 17:07 ` [PATCH 4.4 30/31] ASoC: intel: atom: Fix breakage for PCM buffer address setup Sasha Levin
2021-08-24 17:07 ` [PATCH 4.4 31/31] Linux 4.4.282-rc1 Sasha Levin
2021-08-25  7:33 ` [PATCH 4.4 00/31] 4.4.282-rc1 review Pavel Machek
2021-08-25 20:27 ` Guenter Roeck
2021-08-25 21:18 ` Daniel Díaz
2021-08-25 22:38 ` Shuah Khan

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210824170743.710957-12-sashal@kernel.org \
    --to=sashal@kernel.org \
    --cc=bhelgaas@google.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=maz@kernel.org \
    --cc=stable@vger.kernel.org \
    --cc=tglx@linutronix.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).