Files
linux/drivers/pci/msi/pcidev_msi.c
Vivian Wang 386ced19e9 PCI/MSI: Convert the boolean no_64bit_msi flag to a DMA address 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 supported.

Currently, no_64bit_msi bit is set for these devices, meaning that only
32-bit MSI addresses are allowed for them. However, on some platforms the
MSI doorbell address is above the 32-bit limit but within the addressable
range of the device.

As a first step to enable MSI on those combinations of devices and
platforms, convert the boolean no_64bit_msi flag to a DMA mask and fixup
the affected usage sites:

  - 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) are used,
this is functionally equivalent.

This prepares for changing the binary decision between 32 and 64 bit to a
DMA mask based decision which allows to support systems which have a DMA
address space less than 64bit but a MSI doorbell address above the 32-bit
limit.

[ tglx: Massaged changelog ]

Signed-off-by: Vivian Wang <wangruikang@iscas.ac.cn>
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
Reviewed-by: Brett Creeley <brett.creeley@amd.com> # ionic
Reviewed-by: Thomas Gleixner <tglx@kernel.org>
Acked-by: Takashi Iwai <tiwai@suse.de> # sound
Link: https://patch.msgid.link/20260129-pci-msi-addr-mask-v4-1-70da998f2750@iscas.ac.cn
2026-01-31 01:11:48 +01:00

44 lines
1.0 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* MSI[X} related functions which are available unconditionally.
*/
#include "../pci.h"
/*
* Disable the MSI[X] hardware to avoid screaming interrupts during boot.
* This is the power on reset default so usually this should be a noop.
*/
void pci_msi_init(struct pci_dev *dev)
{
u16 ctrl;
dev->msi_cap = pci_find_capability(dev, PCI_CAP_ID_MSI);
if (!dev->msi_cap)
return;
pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &ctrl);
if (ctrl & PCI_MSI_FLAGS_ENABLE) {
pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS,
ctrl & ~PCI_MSI_FLAGS_ENABLE);
}
if (!(ctrl & PCI_MSI_FLAGS_64BIT))
dev->msi_addr_mask = DMA_BIT_MASK(32);
}
void pci_msix_init(struct pci_dev *dev)
{
u16 ctrl;
dev->msix_cap = pci_find_capability(dev, PCI_CAP_ID_MSIX);
if (!dev->msix_cap)
return;
pci_read_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, &ctrl);
if (ctrl & PCI_MSIX_FLAGS_ENABLE) {
pci_write_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS,
ctrl & ~PCI_MSIX_FLAGS_ENABLE);
}
}