Skip to content

Commit c3164d2

Browse files
roygerjgross1
authored andcommitted
PCI/MSI: Convert pci_msi_ignore_mask to per MSI domain flag
Setting pci_msi_ignore_mask inhibits the toggling of the mask bit for both MSI and MSI-X entries globally, regardless of the IRQ chip they are using. Only Xen sets the pci_msi_ignore_mask when routing physical interrupts over event channels, to prevent PCI code from attempting to toggle the maskbit, as it's Xen that controls the bit. However, the pci_msi_ignore_mask being global will affect devices that use MSI interrupts but are not routing those interrupts over event channels (not using the Xen pIRQ chip). One example is devices behind a VMD PCI bridge. In that scenario the VMD bridge configures MSI(-X) using the normal IRQ chip (the pIRQ one in the Xen case), and devices behind the bridge configure the MSI entries using indexes into the VMD bridge MSI table. The VMD bridge then demultiplexes such interrupts and delivers to the destination device(s). Having pci_msi_ignore_mask set in that scenario prevents (un)masking of MSI entries for devices behind the VMD bridge. Move the signaling of no entry masking into the MSI domain flags, as that allows setting it on a per-domain basis. Set it for the Xen MSI domain that uses the pIRQ chip, while leaving it unset for the rest of the cases. Remove pci_msi_ignore_mask at once, since it was only used by Xen code, and with Xen dropping usage the variable is unneeded. This fixes using devices behind a VMD bridge on Xen PV hardware domains. Albeit Devices behind a VMD bridge are not known to Xen, that doesn't mean Linux cannot use them. By inhibiting the usage of VMD_FEAT_CAN_BYPASS_MSI_REMAP and the removal of the pci_msi_ignore_mask bodge devices behind a VMD bridge do work fine when use from a Linux Xen hardware domain. That's the whole point of the series. Signed-off-by: Roger Pau Monné <roger.pau@citrix.com> Reviewed-by: Thomas Gleixner <tglx@linutronix.de> Acked-by: Juergen Gross <jgross@suse.com> Acked-by: Bjorn Helgaas <bhelgaas@google.com> Message-ID: <20250219092059.90850-4-roger.pau@citrix.com> Signed-off-by: Juergen Gross <jgross@suse.com>
1 parent 6c4d5aa commit c3164d2

File tree

4 files changed

+26
-24
lines changed

4 files changed

+26
-24
lines changed

arch/x86/pci/xen.c

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -436,7 +436,8 @@ static struct msi_domain_ops xen_pci_msi_domain_ops = {
436436
};
437437

438438
static struct msi_domain_info xen_pci_msi_domain_info = {
439-
.flags = MSI_FLAG_PCI_MSIX | MSI_FLAG_FREE_MSI_DESCS | MSI_FLAG_DEV_SYSFS,
439+
.flags = MSI_FLAG_PCI_MSIX | MSI_FLAG_FREE_MSI_DESCS |
440+
MSI_FLAG_DEV_SYSFS | MSI_FLAG_NO_MASK,
440441
.ops = &xen_pci_msi_domain_ops,
441442
};
442443

@@ -484,11 +485,6 @@ static __init void xen_setup_pci_msi(void)
484485
* in allocating the native domain and never use it.
485486
*/
486487
x86_init.irqs.create_pci_msi_domain = xen_create_pci_msi_domain;
487-
/*
488-
* With XEN PIRQ/Eventchannels in use PCI/MSI[-X] masking is solely
489-
* controlled by the hypervisor.
490-
*/
491-
pci_msi_ignore_mask = 1;
492488
}
493489

494490
#else /* CONFIG_PCI_MSI */

drivers/pci/msi/msi.c

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,12 @@
1010
#include <linux/err.h>
1111
#include <linux/export.h>
1212
#include <linux/irq.h>
13+
#include <linux/irqdomain.h>
1314

1415
#include "../pci.h"
1516
#include "msi.h"
1617

1718
int pci_msi_enable = 1;
18-
int pci_msi_ignore_mask;
1919

2020
/**
2121
* pci_msi_supported - check whether MSI may be enabled on a device
@@ -285,6 +285,8 @@ static void pci_msi_set_enable(struct pci_dev *dev, int enable)
285285
static int msi_setup_msi_desc(struct pci_dev *dev, int nvec,
286286
struct irq_affinity_desc *masks)
287287
{
288+
const struct irq_domain *d = dev_get_msi_domain(&dev->dev);
289+
const struct msi_domain_info *info = d->host_data;
288290
struct msi_desc desc;
289291
u16 control;
290292

@@ -295,8 +297,7 @@ static int msi_setup_msi_desc(struct pci_dev *dev, int nvec,
295297
/* Lies, damned lies, and MSIs */
296298
if (dev->dev_flags & PCI_DEV_FLAGS_HAS_MSI_MASKING)
297299
control |= PCI_MSI_FLAGS_MASKBIT;
298-
/* Respect XEN's mask disabling */
299-
if (pci_msi_ignore_mask)
300+
if (info->flags & MSI_FLAG_NO_MASK)
300301
control &= ~PCI_MSI_FLAGS_MASKBIT;
301302

302303
desc.nvec_used = nvec;
@@ -604,12 +605,15 @@ static void __iomem *msix_map_region(struct pci_dev *dev,
604605
*/
605606
void msix_prepare_msi_desc(struct pci_dev *dev, struct msi_desc *desc)
606607
{
608+
const struct irq_domain *d = dev_get_msi_domain(&dev->dev);
609+
const struct msi_domain_info *info = d->host_data;
610+
607611
desc->nvec_used = 1;
608612
desc->pci.msi_attrib.is_msix = 1;
609613
desc->pci.msi_attrib.is_64 = 1;
610614
desc->pci.msi_attrib.default_irq = dev->irq;
611615
desc->pci.mask_base = dev->msix_base;
612-
desc->pci.msi_attrib.can_mask = !pci_msi_ignore_mask &&
616+
desc->pci.msi_attrib.can_mask = !(info->flags & MSI_FLAG_NO_MASK) &&
613617
!desc->pci.msi_attrib.is_virtual;
614618

615619
if (desc->pci.msi_attrib.can_mask) {
@@ -659,9 +663,6 @@ static void msix_mask_all(void __iomem *base, int tsize)
659663
u32 ctrl = PCI_MSIX_ENTRY_CTRL_MASKBIT;
660664
int i;
661665

662-
if (pci_msi_ignore_mask)
663-
return;
664-
665666
for (i = 0; i < tsize; i++, base += PCI_MSIX_ENTRY_SIZE)
666667
writel(ctrl, base + PCI_MSIX_ENTRY_VECTOR_CTRL);
667668
}
@@ -714,6 +715,8 @@ static int msix_setup_interrupts(struct pci_dev *dev, struct msix_entry *entries
714715
static int msix_capability_init(struct pci_dev *dev, struct msix_entry *entries,
715716
int nvec, struct irq_affinity *affd)
716717
{
718+
const struct irq_domain *d = dev_get_msi_domain(&dev->dev);
719+
const struct msi_domain_info *info = d->host_data;
717720
int ret, tsize;
718721
u16 control;
719722

@@ -744,15 +747,17 @@ static int msix_capability_init(struct pci_dev *dev, struct msix_entry *entries,
744747
/* Disable INTX */
745748
pci_intx_for_msi(dev, 0);
746749

747-
/*
748-
* Ensure that all table entries are masked to prevent
749-
* stale entries from firing in a crash kernel.
750-
*
751-
* Done late to deal with a broken Marvell NVME device
752-
* which takes the MSI-X mask bits into account even
753-
* when MSI-X is disabled, which prevents MSI delivery.
754-
*/
755-
msix_mask_all(dev->msix_base, tsize);
750+
if (!(info->flags & MSI_FLAG_NO_MASK)) {
751+
/*
752+
* Ensure that all table entries are masked to prevent
753+
* stale entries from firing in a crash kernel.
754+
*
755+
* Done late to deal with a broken Marvell NVME device
756+
* which takes the MSI-X mask bits into account even
757+
* when MSI-X is disabled, which prevents MSI delivery.
758+
*/
759+
msix_mask_all(dev->msix_base, tsize);
760+
}
756761
pci_msix_clear_and_set_ctrl(dev, PCI_MSIX_FLAGS_MASKALL, 0);
757762

758763
pcibios_free_irq(dev);

include/linux/msi.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,6 @@ struct msi_msg {
7373
};
7474
};
7575

76-
extern int pci_msi_ignore_mask;
7776
/* Helper functions */
7877
struct msi_desc;
7978
struct pci_dev;
@@ -556,6 +555,8 @@ enum {
556555
MSI_FLAG_PCI_MSIX_ALLOC_DYN = (1 << 20),
557556
/* PCI MSIs cannot be steered separately to CPU cores */
558557
MSI_FLAG_NO_AFFINITY = (1 << 21),
558+
/* Inhibit usage of entry masking */
559+
MSI_FLAG_NO_MASK = (1 << 22),
559560
};
560561

561562
/**

kernel/irq/msi.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1143,7 +1143,7 @@ static bool msi_check_reservation_mode(struct irq_domain *domain,
11431143
if (!(info->flags & MSI_FLAG_MUST_REACTIVATE))
11441144
return false;
11451145

1146-
if (IS_ENABLED(CONFIG_PCI_MSI) && pci_msi_ignore_mask)
1146+
if (info->flags & MSI_FLAG_NO_MASK)
11471147
return false;
11481148

11491149
/*

0 commit comments

Comments
 (0)