From 415754a4837f71d06d8e68e2b8bee31bca26b893 Mon Sep 17 00:00:00 2001 From: Vivian Wang Date: Fri, 23 Jan 2026 14:07:28 +0800 Subject: [PATCH 1/4] FROMLIST: PCI/MSI: Conservatively generalize no_64bit_msi into msi_addr_mask Some PCI devices have PCI_MSI_FLAGS_64BIT in the MSI capability, but implement less than 64 address bits. This breaks on platforms where such a device is assigned an MSI address higher than what's reachable. Currently, we deal with this with a single no_64bit_msi flag, and (notably on powerpc) forces 32-bit MSI address for these devices. However, on some platforms the MSI doorbell address is above 32-bit but within device ability. As a first step to enabling MSI on those combinations of devices and platforms, conservatively generalize the single-bit flag no_64bit_msi into msi_addr_mask. (The name msi_addr_mask is chosen to avoid confusion with msi_mask.) The translation is essentially: - no_64bit_msi = 1 -> msi_addr_mask = DMA_BIT_MASK(32) - no_64bit_msi = 0 -> msi_addr_mask = DMA_BIT_MASK(64) - if (no_64bit_msi) -> if (msi_addr_mask < DMA_BIT_MASK(64)) Since no values other than DMA_BIT_MASK(32) and DMA_BIT_MASK(64) is used, no functional change is intended. Future patches that make use of intermediate values of msi_addr_mask will follow, allowing devices that cannot use full 64-bit addresses for MSI to work on platforms with MSI doorbell above 32-bit address space. Acked-by: Takashi Iwai Signed-off-by: Vivian Wang Link: https://lore.kernel.org/r/20260123-pci-msi-addr-mask-v3-1-9f9baa048524@iscas.ac.cn Signed-off-by: Han Gao --- arch/powerpc/platforms/powernv/pci-ioda.c | 2 +- arch/powerpc/platforms/pseries/msi.c | 4 ++-- drivers/gpu/drm/radeon/radeon_irq_kms.c | 2 +- drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c | 2 +- drivers/pci/msi/msi.c | 2 +- drivers/pci/msi/pcidev_msi.c | 2 +- drivers/pci/probe.c | 7 +++++++ include/linux/pci.h | 8 +++++++- sound/hda/controllers/intel.c | 2 +- 9 files changed, 22 insertions(+), 9 deletions(-) diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c index b0c1d9d16fb52c..1c78fdfb7b0366 100644 --- a/arch/powerpc/platforms/powernv/pci-ioda.c +++ b/arch/powerpc/platforms/powernv/pci-ioda.c @@ -1666,7 +1666,7 @@ static int __pnv_pci_ioda_msi_setup(struct pnv_phb *phb, struct pci_dev *dev, return -ENXIO; /* Force 32-bit MSI on some broken devices */ - if (dev->no_64bit_msi) + if (dev->msi_addr_mask < DMA_BIT_MASK(64)) is_64 = 0; /* Assign XIVE to PE */ diff --git a/arch/powerpc/platforms/pseries/msi.c b/arch/powerpc/platforms/pseries/msi.c index a82aaa786e9e02..7473c7ca1db07e 100644 --- a/arch/powerpc/platforms/pseries/msi.c +++ b/arch/powerpc/platforms/pseries/msi.c @@ -383,7 +383,7 @@ static int rtas_prepare_msi_irqs(struct pci_dev *pdev, int nvec_in, int type, */ again: if (type == PCI_CAP_ID_MSI) { - if (pdev->no_64bit_msi) { + if (pdev->msi_addr_mask < DMA_BIT_MASK(64)) { rc = rtas_change_msi(pdn, RTAS_CHANGE_32MSI_FN, nvec); if (rc < 0) { /* @@ -409,7 +409,7 @@ static int rtas_prepare_msi_irqs(struct pci_dev *pdev, int nvec_in, int type, if (use_32bit_msi_hack && rc > 0) rtas_hack_32bit_msi_gen2(pdev); } else { - if (pdev->no_64bit_msi) + if (pdev->msi_addr_mask < DMA_BIT_MASK(64)) rc = rtas_change_msi(pdn, RTAS_CHANGE_32MSIX_FN, nvec); else rc = rtas_change_msi(pdn, RTAS_CHANGE_MSIX_FN, nvec); diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c index d4ad1fa8264542..ff0e253e56e990 100644 --- a/drivers/gpu/drm/radeon/radeon_irq_kms.c +++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c @@ -253,7 +253,7 @@ static bool radeon_msi_ok(struct radeon_device *rdev) */ if (rdev->family < CHIP_BONAIRE) { dev_info(rdev->dev, "radeon: MSI limited to 32-bit\n"); - rdev->pdev->no_64bit_msi = 1; + rdev->pdev->msi_addr_mask = DMA_BIT_MASK(32); } /* force MSI on */ diff --git a/drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c b/drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c index 70d86c5f52fbb6..0671deae9a2860 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c @@ -331,7 +331,7 @@ static int ionic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) #ifdef CONFIG_PPC64 /* Ensure MSI/MSI-X interrupts lie within addressable physical memory */ - pdev->no_64bit_msi = 1; + pdev->msi_addr_mask = DMA_BIT_MASK(32); #endif err = ionic_setup_one(ionic); diff --git a/drivers/pci/msi/msi.c b/drivers/pci/msi/msi.c index 34d664139f48fc..48f5f03d147982 100644 --- a/drivers/pci/msi/msi.c +++ b/drivers/pci/msi/msi.c @@ -322,7 +322,7 @@ static int msi_verify_entries(struct pci_dev *dev) { struct msi_desc *entry; - if (!dev->no_64bit_msi) + if (dev->msi_addr_mask == DMA_BIT_MASK(64)) return 0; msi_for_each_desc(entry, &dev->dev, MSI_DESC_ALL) { diff --git a/drivers/pci/msi/pcidev_msi.c b/drivers/pci/msi/pcidev_msi.c index 5520aff53b5670..0b034681309265 100644 --- a/drivers/pci/msi/pcidev_msi.c +++ b/drivers/pci/msi/pcidev_msi.c @@ -24,7 +24,7 @@ void pci_msi_init(struct pci_dev *dev) } if (!(ctrl & PCI_MSI_FLAGS_64BIT)) - dev->no_64bit_msi = 1; + dev->msi_addr_mask = DMA_BIT_MASK(32); } void pci_msix_init(struct pci_dev *dev) diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 9cd032dff31e57..44cb3a38a27e09 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -2028,6 +2028,13 @@ int pci_setup_device(struct pci_dev *dev) */ dev->dma_mask = 0xffffffff; + /* + * Assume 64-bit addresses for MSI initially. Will be changed to 32-bit + * if MSI (rather than MSI-X) capability does not have + * PCI_MSI_FLAGS_64BIT. Can also be overridden by driver. + */ + dev->msi_addr_mask = DMA_BIT_MASK(64); + dev_set_name(&dev->dev, "%04x:%02x:%02x.%d", pci_domain_nr(dev->bus), dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); diff --git a/include/linux/pci.h b/include/linux/pci.h index b20d4559421ba5..060baa3b38ed3b 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -378,6 +378,13 @@ struct pci_dev { 0xffffffff. You only need to change this if your device has broken DMA or supports 64-bit transfers. */ + u64 msi_addr_mask; /* Mask of the bits of bus address for + MSI that this device implements. + Normally set based on device + capabilities. You only need to + change this if your device claims + to support 64-bit MSI but implements + fewer than 64 address bits. */ struct device_dma_parameters dma_parms; @@ -442,7 +449,6 @@ struct pci_dev { unsigned int is_busmaster:1; /* Is busmaster */ unsigned int no_msi:1; /* May not use MSI */ - unsigned int no_64bit_msi:1; /* May only use 32-bit MSIs */ unsigned int block_cfg_access:1; /* Config space access blocked */ unsigned int broken_parity_status:1; /* Generates false positive parity */ unsigned int irq_reroute_variant:2; /* Needs IRQ rerouting variant */ diff --git a/sound/hda/controllers/intel.c b/sound/hda/controllers/intel.c index a19258c95886c4..766e42b8a6d8e4 100644 --- a/sound/hda/controllers/intel.c +++ b/sound/hda/controllers/intel.c @@ -1905,7 +1905,7 @@ static int azx_first_init(struct azx *chip) if (chip->msi && chip->driver_caps & AZX_DCAPS_NO_MSI64) { dev_dbg(card->dev, "Disabling 64bit MSI\n"); - pci->no_64bit_msi = true; + pci->msi_addr_mask = DMA_BIT_MASK(32); } pci_set_master(pci); From 21107693960c8eb2445df29e51000ad5a83fcaad Mon Sep 17 00:00:00 2001 From: Vivian Wang Date: Fri, 23 Jan 2026 14:07:29 +0800 Subject: [PATCH 2/4] FROMLIST: PCI/MSI: Check msi_addr_mask in msi_verify_entries() Instead of a 32-bit/64-bit dichotomy, check the MSI address against msi_addr_mask. This allows platforms with MSI doorbell above 32-bit address space to work with devices without full 64-bit MSI address support, as long as the doorbell is within addressable range of MSI of the device. Signed-off-by: Vivian Wang Link: https://lore.kernel.org/r/20260123-pci-msi-addr-mask-v3-2-9f9baa048524@iscas.ac.cn Signed-off-by: Han Gao --- drivers/pci/msi/msi.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/pci/msi/msi.c b/drivers/pci/msi/msi.c index 48f5f03d147982..77713f89a10b7a 100644 --- a/drivers/pci/msi/msi.c +++ b/drivers/pci/msi/msi.c @@ -321,14 +321,17 @@ static int msi_setup_msi_desc(struct pci_dev *dev, int nvec, static int msi_verify_entries(struct pci_dev *dev) { struct msi_desc *entry; + u64 address; if (dev->msi_addr_mask == DMA_BIT_MASK(64)) return 0; msi_for_each_desc(entry, &dev->dev, MSI_DESC_ALL) { - if (entry->msg.address_hi) { - pci_err(dev, "arch assigned 64-bit MSI address %#x%08x but device only supports 32 bits\n", - entry->msg.address_hi, entry->msg.address_lo); + address = (u64)entry->msg.address_hi << 32 | + entry->msg.address_lo; + if (address & ~dev->msi_addr_mask) { + pci_err(dev, "arch assigned 64-bit MSI address %#llx above device MSI address mask %#llx\n", + address, dev->msi_addr_mask); break; } } From 2bd7b498eccb70e853280bd48bb953d7a46f9c0f Mon Sep 17 00:00:00 2001 From: Vivian Wang Date: Fri, 23 Jan 2026 14:07:30 +0800 Subject: [PATCH 3/4] FROMLIST: drm/radeon: Raise msi_addr_mask to dma_bits The code was originally written using no_64bit_msi, which restricts the device to 32-bit MSI addresses. Since msi_addr_mask is introduced, use DMA_BIT_MASK(dma_bits) instead of DMA_BIT_MASK(32) here for msi_addr_mask, describing the restriction more precisely and allowing these devices to work on platforms with MSI doorbell address above 32-bit space, as long as it is within the hardware's addressable space. Signed-off-by: Vivian Wang Link: https://lore.kernel.org/r/20260123-pci-msi-addr-mask-v3-3-9f9baa048524@iscas.ac.cn Signed-off-by: Han Gao --- drivers/gpu/drm/radeon/radeon_device.c | 1 + drivers/gpu/drm/radeon/radeon_irq_kms.c | 10 ---------- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 1ccd4b5d60d689..499a2bdf79bba9 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -1374,6 +1374,7 @@ int radeon_device_init(struct radeon_device *rdev, pr_warn("radeon: No suitable DMA available\n"); return r; } + rdev->pdev->msi_addr_mask = DMA_BIT_MASK(dma_bits); rdev->need_swiotlb = drm_need_swiotlb(dma_bits); /* Registers mapping */ diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c index ff0e253e56e990..a995bf7c9f1e12 100644 --- a/drivers/gpu/drm/radeon/radeon_irq_kms.c +++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c @@ -246,16 +246,6 @@ static bool radeon_msi_ok(struct radeon_device *rdev) if (rdev->flags & RADEON_IS_AGP) return false; - /* - * Older chips have a HW limitation, they can only generate 40 bits - * of address for "64-bit" MSIs which breaks on some platforms, notably - * IBM POWER servers, so we limit them - */ - if (rdev->family < CHIP_BONAIRE) { - dev_info(rdev->dev, "radeon: MSI limited to 32-bit\n"); - rdev->pdev->msi_addr_mask = DMA_BIT_MASK(32); - } - /* force MSI on */ if (radeon_msi == 1) return true; From a88d5d2c2b199d1adc349f53b8edff5b7b1f38aa Mon Sep 17 00:00:00 2001 From: Vivian Wang Date: Fri, 23 Jan 2026 14:07:31 +0800 Subject: [PATCH 4/4] FROMLIST: ALSA: hda/intel: Raise msi_addr_mask to dma_bits The code was originally written using no_64bit_msi, which restricts the device to 32-bit MSI addresses. Since msi_addr_mask is introduced, use DMA_BIT_MASK(dma_bits) instead of DMA_BIT_MASK(32) here for msi_addr_mask, describing the restriction more precisely and allowing these devices to work on platforms with MSI doorbell address above 32-bit space, as long as it is within the hardware's addressable space. Acked-by: Takashi Iwai Signed-off-by: Vivian Wang Link: https://lore.kernel.org/r/20260123-pci-msi-addr-mask-v3-4-9f9baa048524@iscas.ac.cn Signed-off-by: Han Gao --- sound/hda/controllers/intel.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/hda/controllers/intel.c b/sound/hda/controllers/intel.c index 766e42b8a6d8e4..c378237a4cf4fc 100644 --- a/sound/hda/controllers/intel.c +++ b/sound/hda/controllers/intel.c @@ -1903,11 +1903,6 @@ static int azx_first_init(struct azx *chip) chip->gts_present = true; #endif - if (chip->msi && chip->driver_caps & AZX_DCAPS_NO_MSI64) { - dev_dbg(card->dev, "Disabling 64bit MSI\n"); - pci->msi_addr_mask = DMA_BIT_MASK(32); - } - pci_set_master(pci); gcap = azx_readw(chip, GCAP); @@ -1958,6 +1953,11 @@ static int azx_first_init(struct azx *chip) dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(32)); dma_set_max_seg_size(&pci->dev, UINT_MAX); + if (chip->msi && chip->driver_caps & AZX_DCAPS_NO_MSI64) { + dev_dbg(card->dev, "Restricting MSI to %u-bit\n", dma_bits); + pci->msi_addr_mask = DMA_BIT_MASK(dma_bits); + } + /* read number of streams from GCAP register instead of using * hardcoded value */