Skip to content

Commit da181dc

Browse files
committed
PCI/MSI: Enforce that MSI-X table entry is masked for update
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: f036d4e ("[PATCH] ia32 Message Signalled Interrupt support") Reported-by: Kevin Tian <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Tested-by: Marc Zyngier <[email protected]> Reviewed-by: Marc Zyngier <[email protected]> Acked-by: Bjorn Helgaas <[email protected]> Cc: [email protected] Link: https://lore.kernel.org/r/[email protected]
1 parent 7d5ec3d commit da181dc

File tree

1 file changed

+15
-0
lines changed

1 file changed

+15
-0
lines changed

drivers/pci/msi.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,13 +289,28 @@ void __pci_write_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
289289
/* Don't touch the hardware now */
290290
} else if (entry->msi_attrib.is_msix) {
291291
void __iomem *base = pci_msix_desc_addr(entry);
292+
bool unmasked = !(entry->masked & PCI_MSIX_ENTRY_CTRL_MASKBIT);
292293

293294
if (!base)
294295
goto skip;
295296

297+
/*
298+
* The specification mandates that the entry is masked
299+
* when the message is modified:
300+
*
301+
* "If software changes the Address or Data value of an
302+
* entry while the entry is unmasked, the result is
303+
* undefined."
304+
*/
305+
if (unmasked)
306+
__pci_msix_desc_mask_irq(entry, PCI_MSIX_ENTRY_CTRL_MASKBIT);
307+
296308
writel(msg->address_lo, base + PCI_MSIX_ENTRY_LOWER_ADDR);
297309
writel(msg->address_hi, base + PCI_MSIX_ENTRY_UPPER_ADDR);
298310
writel(msg->data, base + PCI_MSIX_ENTRY_DATA);
311+
312+
if (unmasked)
313+
__pci_msix_desc_mask_irq(entry, 0);
299314
} else {
300315
int pos = dev->msi_cap;
301316
u16 msgctl;

0 commit comments

Comments
 (0)