PCI: dwc: Strengthen the MSI address allocation logic
authorAjay Agarwal <ajayagarwal@google.com>
Wed, 21 Feb 2024 15:38:40 +0000 (21:08 +0530)
committerKrzysztof Wilczyński <kwilczynski@kernel.org>
Sun, 10 Mar 2024 18:08:04 +0000 (18:08 +0000)
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>
drivers/pci/controller/dwc/pcie-designware-host.c

index d5fc31f..d15a5c2 100644 (file)
@@ -328,7 +328,7 @@ static int dw_pcie_msi_host_init(struct dw_pcie_rp *pp)
        struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
        struct device *dev = pci->dev;
        struct platform_device *pdev = to_platform_device(dev);
-       u64 *msi_vaddr;
+       u64 *msi_vaddr = NULL;
        int ret;
        u32 ctrl, num_ctrls;
 
@@ -379,15 +379,20 @@ static int dw_pcie_msi_host_init(struct dw_pcie_rp *pp)
         * memory.
         */
        ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
-       if (ret)
-               dev_warn(dev, "Failed to set DMA mask to 32-bit. Devices with only 32-bit MSI support may not work properly\n");
+       if (!ret)
+               msi_vaddr = dmam_alloc_coherent(dev, sizeof(u64), &pp->msi_data,
+                                               GFP_KERNEL);
 
-       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");
-               dw_pcie_free_msi(pp);
-               return -ENOMEM;
+               dev_warn(dev, "Failed to allocate 32-bit MSI address\n");
+               dma_set_coherent_mask(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 allocate MSI address\n");
+                       dw_pcie_free_msi(pp);
+                       return -ENOMEM;
+               }
        }
 
        return 0;