diff --git a/drivers/platform/tegra/nvadsp/dev.h b/drivers/platform/tegra/nvadsp/dev.h index ac68a480..dbdcbdbf 100644 --- a/drivers/platform/tegra/nvadsp/dev.h +++ b/drivers/platform/tegra/nvadsp/dev.h @@ -22,7 +22,6 @@ #include #include #include -#include #include #include @@ -215,9 +214,6 @@ struct nvadsp_drv_data { struct tegra_bwmgr_client *bwmgr; u32 evp_base[ADSP_EVP_END]; - /* Used to reserve iova */ - struct iova_domain iovad; - const struct nvadsp_chipdata *chip_data; }; diff --git a/drivers/platform/tegra/nvadsp/os.c b/drivers/platform/tegra/nvadsp/os.c index fd402397..73deff89 100644 --- a/drivers/platform/tegra/nvadsp/os.c +++ b/drivers/platform/tegra/nvadsp/os.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -620,26 +621,35 @@ static void *nvadsp_dma_alloc_and_map_at(struct platform_device *pdev, gfp_t flags) { struct iommu_domain *domain = iommu_get_domain_for_dev(&pdev->dev); - struct nvadsp_drv_data *drv_data = platform_get_drvdata(pdev); + unsigned long align_mask = ~0UL << fls_long(size - 1); unsigned long shift = __ffs(domain->pgsize_bitmap); unsigned long pg_size = 1UL << shift; unsigned long mp_size = pg_size; struct device *dev = &pdev->dev; + dma_addr_t aligned_iova = iova & align_mask; + dma_addr_t end = iova + size; dma_addr_t tmp_iova, offset; phys_addr_t pa, pa_new; - struct iova *iova_pfn; void *cpu_va; int ret; - /* Reserve iova range */ - iova_pfn = alloc_iova(&drv_data->iovad, size >> shift, - (iova + size - pg_size) >> shift, false); - if (!iova_pfn || (iova_pfn->pfn_lo << shift) != iova) { - dev_err(dev, "failed to reserve iova at 0x%llx size 0x%lx\n", - iova, size); + /* + * Reserve iova range using aligned size: adsp memory might not start + * from an aligned address by power of 2, while iommu_dma_alloc_iova() + * would shift the allocation off the target iova so as to align start + * address by power of 2. To prevent this shifting, use aligned size. + * It might allocate an excessive iova region but it would be handled + * by IOMMU core during iommu_dma_free_iova(). + */ + tmp_iova = iommu_dma_alloc_iova(dev, end - aligned_iova, end - pg_size); + if (tmp_iova != aligned_iova) { + dev_err(dev, "failed to reserve iova range [%llx, %llx]\n", + aligned_iova, end); return NULL; } + dev_dbg(dev, "Reserved iova region [%llx, %llx]\n", aligned_iova, end); + /* Allocate a memory first and get a tmp_iova */ cpu_va = dma_alloc_coherent(dev, size, &tmp_iova, flags); if (!cpu_va) @@ -675,8 +685,9 @@ static void *nvadsp_dma_alloc_and_map_at(struct platform_device *pdev, } } - /* Unmap the tmp_iova since target iova is linked */ + /* Unmap and free the tmp_iova since target iova is linked */ iommu_unmap(domain, tmp_iova, size); + iommu_dma_free_iova(dev, tmp_iova, size); return cpu_va; @@ -684,7 +695,7 @@ fail_map: iommu_unmap(domain, iova, offset); dma_free_coherent(dev, size, cpu_va, tmp_iova); fail_dma_alloc: - __free_iova(&drv_data->iovad, iova_pfn); + iommu_dma_free_iova(dev, end - aligned_iova, end - pg_size); return NULL; } @@ -727,13 +738,9 @@ end: static void deallocate_memory_for_adsp_os(struct device *dev) { #if defined(CONFIG_TEGRA_NVADSP_ON_SMMU) - struct nvadsp_drv_data *drv_data = platform_get_drvdata(priv.pdev); - struct iova_domain *iovad = &drv_data->iovad; void *va = nvadsp_da_to_va_mappings(priv.adsp_os_addr, priv.adsp_os_size); dma_free_coherent(dev, priv.adsp_os_size, va, priv.adsp_os_addr); - free_iova(iovad, iova_pfn(iovad, priv.adsp_os_addr)); - put_iova_domain(iovad); #endif } @@ -839,9 +846,6 @@ int nvadsp_os_load(void) struct nvadsp_drv_data *drv_data; struct device *dev; int ret = 0; -#ifdef CONFIG_TEGRA_NVADSP_ON_SMMU - u32 addr, size; -#endif if (!priv.pdev) { pr_err("ADSP Driver is not initialized\n"); @@ -855,18 +859,6 @@ int nvadsp_os_load(void) drv_data = platform_get_drvdata(priv.pdev); dev = &priv.pdev->dev; -#ifdef CONFIG_TEGRA_NVADSP_ON_SMMU - if (drv_data->adsp_os_secload) { - addr = drv_data->adsp_mem[ACSR_ADDR]; - size = drv_data->adsp_mem[ACSR_SIZE]; - } else { - addr = drv_data->adsp_mem[ADSP_OS_ADDR]; - size = drv_data->adsp_mem[ADSP_OS_SIZE]; - } - init_iova_domain(&drv_data->iovad, PAGE_SIZE, - addr >> PAGE_SHIFT, (addr + size) >> PAGE_SHIFT); -#endif - if (drv_data->adsp_os_secload) { dev_info(dev, "ADSP OS firmware already loaded\n"); ret = __nvadsp_os_secload(priv.pdev);