BACKPORT: FROMGIT: PCI: dwc: Add support for 64-bit MSI target address
Since not all devices require a 32-bit MSI address, add support to the PCIe host driver to allow setting the DMA mask to 64-bits if the 32-bit allocation fails. This allows kernels to disable ZONE_DMA32 and bounce buffering (swiotlb) without risking not being able to get a 32-bit address during DMA allocation. Basically, in the slim chance that there are no 32-bit allocations available, the current PCIe host driver will fail to allocate the msi_msg page due to a DMA address overflow (seen in [1]). With this patch, the PCIe host can retry the allocation with a 64-bit DMA mask if the current PCIe device advertises 64-bit support via its MSI capabilities. [1] https://lore.kernel.org/all/Yo0soniFborDl7+C@google.com/ Bug: 241473543 Link: https://lore.kernel.org/r/20220825235404.4132818-3-willmcvicker@google.com Reported-by: kernel test robot <lkp@intel.com> Signed-off-by: Will McVicker <willmcvicker@google.com> Signed-off-by: Lorenzo Pieralisi <lpieralisi@kernel.org> Reviewed-by: Rob Herring <robh@kernel.org> Acked-by: Jingoo Han <jingoohan1@gmail.com> Change-Id: I8936717b26f3dec453b0a944b26a0bb891905100 (cherry picked from commit e99d8c5e803b9a9f0b5a84165dad3b8895446147 https://git.kernel.org/pub/scm/linux/kernel/git/lpieralisi/pci.git pci/dwc)
This commit is contained in:
committed by
Treehugger Robot
parent
8181ea8d96
commit
8de5430cb7
@@ -373,9 +373,22 @@ int dw_pcie_host_init(struct pcie_port *pp)
|
||||
msi_vaddr = dmam_alloc_coherent(dev, sizeof(u64), &pp->msi_data,
|
||||
GFP_KERNEL);
|
||||
if (!msi_vaddr) {
|
||||
dev_err(dev, "Failed to alloc and map MSI data\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_free_msi;
|
||||
u16 msi_capabilities;
|
||||
|
||||
/* Retry the allocation with a 64-bit mask if supported. */
|
||||
msi_capabilities = dw_pcie_msi_capabilities(pci);
|
||||
if ((msi_capabilities & PCI_MSI_FLAGS_ENABLE) &&
|
||||
(msi_capabilities & PCI_MSI_FLAGS_64BIT)) {
|
||||
dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
|
||||
msi_vaddr = dmam_alloc_coherent(dev, sizeof(u64),
|
||||
&pp->msi_data,
|
||||
GFP_KERNEL);
|
||||
}
|
||||
if (!msi_vaddr) {
|
||||
dev_err(dev, "Failed to alloc and map MSI data\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_free_msi;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,6 +55,14 @@ u8 dw_pcie_find_capability(struct dw_pcie *pci, u8 cap)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_pcie_find_capability);
|
||||
|
||||
u16 dw_pcie_msi_capabilities(struct dw_pcie *pci)
|
||||
{
|
||||
u8 offset;
|
||||
|
||||
offset = dw_pcie_find_capability(pci, PCI_CAP_ID_MSI);
|
||||
return dw_pcie_readw_dbi(pci, offset + PCI_MSI_FLAGS);
|
||||
}
|
||||
|
||||
static u16 dw_pcie_find_next_ext_capability(struct dw_pcie *pci, u16 start,
|
||||
u8 cap)
|
||||
{
|
||||
|
||||
@@ -285,6 +285,7 @@ struct dw_pcie {
|
||||
|
||||
u8 dw_pcie_find_capability(struct dw_pcie *pci, u8 cap);
|
||||
u16 dw_pcie_find_ext_capability(struct dw_pcie *pci, u8 cap);
|
||||
u16 dw_pcie_msi_capabilities(struct dw_pcie *pci);
|
||||
|
||||
int dw_pcie_read(void __iomem *addr, int size, u32 *val);
|
||||
int dw_pcie_write(void __iomem *addr, int size, u32 val);
|
||||
|
||||
Reference in New Issue
Block a user