Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

PCI: dwc: Strengthen the MSI address allocation logic

There can be platforms that do not use/have 32-bit DMA addresses.
The current implementation of 32-bit IOVA allocation can fail for
such platforms, eventually leading to the probe failure.

Try to allocate a 32-bit msi_data. If this allocation fails,
attempt a 64-bit address allocation. Please note that if the
64-bit MSI address is allocated, then the EPs supporting 32-bit
MSI address only will not work.

Link: https://lore.kernel.org/linux-pci/20240221153840.1789979-1-ajayagarwal@google.com
Tested-by: Will McVicker <willmcvicker@google.com>
Signed-off-by: Ajay Agarwal <ajayagarwal@google.com>
Signed-off-by: Krzysztof Wilczyński <kwilczynski@kernel.org>
Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Reviewed-by: Serge Semin <fancer.lancer@gmail.com>
Reviewed-by: Will McVicker <willmcvicker@google.com>

authored by

Ajay Agarwal and committed by
Krzysztof Wilczyński
f3a29640 6613476e

+13 -8
+13 -8
drivers/pci/controller/dwc/pcie-designware-host.c
··· 328 328 struct dw_pcie *pci = to_dw_pcie_from_pp(pp); 329 329 struct device *dev = pci->dev; 330 330 struct platform_device *pdev = to_platform_device(dev); 331 - u64 *msi_vaddr; 331 + u64 *msi_vaddr = NULL; 332 332 int ret; 333 333 u32 ctrl, num_ctrls; 334 334 ··· 379 379 * memory. 380 380 */ 381 381 ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32)); 382 - if (ret) 383 - dev_warn(dev, "Failed to set DMA mask to 32-bit. Devices with only 32-bit MSI support may not work properly\n"); 382 + if (!ret) 383 + msi_vaddr = dmam_alloc_coherent(dev, sizeof(u64), &pp->msi_data, 384 + GFP_KERNEL); 384 385 385 - msi_vaddr = dmam_alloc_coherent(dev, sizeof(u64), &pp->msi_data, 386 - GFP_KERNEL); 387 386 if (!msi_vaddr) { 388 - dev_err(dev, "Failed to alloc and map MSI data\n"); 389 - dw_pcie_free_msi(pp); 390 - return -ENOMEM; 387 + dev_warn(dev, "Failed to allocate 32-bit MSI address\n"); 388 + dma_set_coherent_mask(dev, DMA_BIT_MASK(64)); 389 + msi_vaddr = dmam_alloc_coherent(dev, sizeof(u64), &pp->msi_data, 390 + GFP_KERNEL); 391 + if (!msi_vaddr) { 392 + dev_err(dev, "Failed to allocate MSI address\n"); 393 + dw_pcie_free_msi(pp); 394 + return -ENOMEM; 395 + } 391 396 } 392 397 393 398 return 0;