From 3ec72b5768e32b3651209a7f936d9406ed520c08 Mon Sep 17 00:00:00 2001 From: Vivian Wang Date: Wed, 24 Dec 2025 11:10:49 +0800 Subject: [PATCH 1/7] 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) use 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, 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. Signed-off-by: Vivian Wang Link: https://lore.kernel.org/r/20251224-pci-msi-addr-mask-v1-1-05a6fcb4b4c0@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 7a432c7428c10d79f10b472d2429134891e5e50e Mon Sep 17 00:00:00 2001 From: Vivian Wang Date: Wed, 24 Dec 2025 11:10:50 +0800 Subject: [PATCH 2/7] 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/20251224-pci-msi-addr-mask-v1-2-05a6fcb4b4c0@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..2ecbcd6c436adc 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 16b480e0d5eacdd091bb734a64daa4a7bd554498 Mon Sep 17 00:00:00 2001 From: Vivian Wang Date: Wed, 24 Dec 2025 11:10:51 +0800 Subject: [PATCH 3/7] FROMLIST: drm/radeon: Raise msi_addr_mask to 40 bits for pre-Bonaire 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(40) 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 restriction of 40-bit space. Signed-off-by: Vivian Wang Link: https://lore.kernel.org/r/20251224-pci-msi-addr-mask-v1-3-05a6fcb4b4c0@iscas.ac.cn Signed-off-by: Han Gao --- drivers/gpu/drm/radeon/radeon_irq_kms.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c index ff0e253e56e990..e0fe5df75551ea 100644 --- a/drivers/gpu/drm/radeon/radeon_irq_kms.c +++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c @@ -252,8 +252,8 @@ static bool radeon_msi_ok(struct radeon_device *rdev) * 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); + dev_info(rdev->dev, "radeon: MSI limited to 40-bit\n"); + rdev->pdev->msi_addr_mask = DMA_BIT_MASK(40); } /* force MSI on */ From e48ca6a348f1b026c8bfa50dbfa5f61a8759de9b Mon Sep 17 00:00:00 2001 From: Vivian Wang Date: Wed, 24 Dec 2025 11:10:52 +0800 Subject: [PATCH 4/7] 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. Signed-off-by: Vivian Wang Link: https://lore.kernel.org/r/20251224-pci-msi-addr-mask-v1-4-05a6fcb4b4c0@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 */ From 9b6f7bd78bd76464ec0210e43c21d37b5057e7cb Mon Sep 17 00:00:00 2001 From: Inochi Amaoto Date: Thu, 25 Dec 2025 18:05:28 +0800 Subject: [PATCH 5/7] FROMLIST: PCI/ASPM: Avoid L0s and L1 on Sophgo 2042 PCIe [1f1c:2042] Root Ports Since commit f3ac2ff14834 ("PCI/ASPM: Enable all ClockPM and ASPM states for devicetree platforms") force enable ASPM on all device tree platform, the SG2042 root port breaks as it advertises L0s and L1 capabilities without supporting it. Override the L0s and L1 Support advertised in Link Capabilities by the SG2042 Root Ports ([1f1c:2042]), so we don't try to enable those states. Fixes: 4e27aca4881a ("riscv: sophgo: dts: add PCIe controllers for SG2042") Signed-off-by: Inochi Amaoto Tested-by: Han Gao Link: https://lore.kernel.org/r/20251225100530.1301625-2-inochiama@gmail.com Signed-off-by: Han Gao --- drivers/pci/quirks.c | 1 + include/linux/pci_ids.h | 2 ++ 2 files changed, 3 insertions(+) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 167bb94f6ad6fe..5f10fc2ce7556b 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -2556,6 +2556,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ASMEDIA, 0x1080, quirk_disable_aspm_l0s_l DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_FREESCALE, 0x0451, quirk_disable_aspm_l0s_l1); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_PASEMI, 0xa002, quirk_disable_aspm_l0s_l1); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_HUAWEI, 0x1105, quirk_disable_aspm_l0s_l1); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SOPHGO, 0x2042, quirk_disable_aspm_l0s_l1); /* * Some Pericom PCIe-to-PCI bridges in reverse mode need the PCIe Retrain diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index ce78dabfbf67f6..1bfd3e29c41efb 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2632,6 +2632,8 @@ #define PCI_VENDOR_ID_CXL 0x1e98 +#define PCI_VENDOR_ID_SOPHGO 0x1f1c + #define PCI_VENDOR_ID_CIX 0x1f6c #define PCI_DEVICE_ID_CIX_SKY1 0x0001 From 42b510e08f613981ace70c1ec8df663d3904617f Mon Sep 17 00:00:00 2001 From: Inochi Amaoto Date: Thu, 25 Dec 2025 18:05:29 +0800 Subject: [PATCH 6/7] FROMLIST: PCI/ASPM: Avoid L0s and L1 on Sophgo 2044 PCIe [1f1c:2044] Root Ports Since commit f3ac2ff14834 ("PCI/ASPM: Enable all ClockPM and ASPM states for devicetree platforms") force enable ASPM on all device tree platform, the SG2044 root port breaks as it advertises L0s and L1 capabilities without supporting it. Override the L0s and L1 Support advertised in Link Capabilities by the SG2044 Root Ports ([1f1c:2044]), so we don't try to enable those states. Fixes: 3309df45e6b5 ("riscv: dts: sophgo: sg2044: add PCIe device support for SG2044") Signed-off-by: Inochi Amaoto Tested-by: Han Gao Link: https://lore.kernel.org/r/20251225100530.1301625-3-inochiama@gmail.com Signed-off-by: Han Gao --- drivers/pci/quirks.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 5f10fc2ce7556b..a5b526e6abc9b4 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -2557,6 +2557,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_FREESCALE, 0x0451, quirk_disable_aspm_l0s DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_PASEMI, 0xa002, quirk_disable_aspm_l0s_l1); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_HUAWEI, 0x1105, quirk_disable_aspm_l0s_l1); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SOPHGO, 0x2042, quirk_disable_aspm_l0s_l1); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SOPHGO, 0x2044, quirk_disable_aspm_l0s_l1); /* * Some Pericom PCIe-to-PCI bridges in reverse mode need the PCIe Retrain From 13b4028c0ff5b7188d6caa47d9dc465ce55206c0 Mon Sep 17 00:00:00 2001 From: Vivian Wang Date: Tue, 30 Dec 2025 21:39:17 +0800 Subject: [PATCH 7/7] FROMLIST: riscv: boot: Always make Image from vmlinux, not vmlinux.unstripped Since commit 4b47a3aefb29 ("kbuild: Restore pattern to avoid stripping .rela.dyn from vmlinux") vmlinux has .rel*.dyn preserved. Therefore, use vmlinux to produce Image, not vmlinux.unstripped. Doing so fixes booting a RELOCATABLE=y Image with kexec. The problem is caused by this chain of events: - Since commit 3e86e4d74c04 ("kbuild: keep .modinfo section in vmlinux.unstripped"), vmlinux.unstripped gets a .modinfo section. - The .modinfo section has SHF_ALLOC, so it ends up in Image, at the end of it. - The Image header's image_size field does not expect to include .modinfo and does not account for it, since it should not be in Image. - If .modinfo is large enough, the file size of Image ends up larger than image_size, which eventually leads to it failing sanity_check_segment_list(). Using vmlinux instead of vmlinux.unstripped means that the unexpected .modinfo section is gone from Image, fixing the file size problem. Cc: stable@vger.kernel.org Fixes: 3e86e4d74c04 ("kbuild: keep .modinfo section in vmlinux.unstripped") Signed-off-by: Vivian Wang Link: https://lore.kernel.org/r/20251230-riscv-vmlinux-not-unstripped-v1-1-15f49df880df@iscas.ac.cn Signed-off-by: Han Gao --- arch/riscv/boot/Makefile | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/riscv/boot/Makefile b/arch/riscv/boot/Makefile index bfc3d0b75b9b2b..5301adf5f3f5d2 100644 --- a/arch/riscv/boot/Makefile +++ b/arch/riscv/boot/Makefile @@ -31,11 +31,7 @@ $(obj)/xipImage: vmlinux FORCE endif -ifdef CONFIG_RELOCATABLE -$(obj)/Image: vmlinux.unstripped FORCE -else $(obj)/Image: vmlinux FORCE -endif $(call if_changed,objcopy) $(obj)/Image.gz: $(obj)/Image FORCE