From 369971aa0101c4cfb84dacaaaa1b5cc5790c14ff Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 11 Apr 2018 10:34:17 +0200 Subject: [PATCH] drm/nouveau: tegra: Detach from ARM DMA/IOMMU mapping Depending on the kernel configuration, early ARM architecture setup code may have attached the GPU to a DMA/IOMMU mapping that transparently uses the IOMMU to back the DMA API. Tegra requires special handling for IOMMU backed buffers (a special bit in the GPU's MMU page tables indicates the memory path to take: via the SMMU or directly to the memory controller). Transparently backing DMA memory with an IOMMU prevents Nouveau from properly handling such memory accesses and causes memory access faults. As a side-note: buffers other than those allocated in instance memory don't need to be physically contiguous from the GPU's perspective since the GPU can map them into contiguous buffers using its own MMU. Mapping these buffers through the IOMMU is unnecessary and will even lead to performance degradation because of the additional translation. Signed-off-by: Thierry Reding --- drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c index 1f07999aea1d..ac7706f56f6f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c @@ -19,6 +19,11 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ + +#if IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU) +#include +#endif + #include #ifdef CONFIG_NOUVEAU_PLATFORM_DRIVER #include "priv.h" @@ -105,6 +110,20 @@ nvkm_device_tegra_probe_iommu(struct nvkm_device_tegra *tdev) unsigned long pgsize_bitmap; int ret; +#if IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU) + if (dev->archdata.mapping) { + struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev); + + arm_iommu_release_mapping(mapping); + arm_iommu_detach_device(dev); + + if (dev->archdata.dma_coherent) + set_dma_ops(dev, &arm_coherent_dma_ops); + else + set_dma_ops(dev, &arm_dma_ops); + } +#endif + if (!tdev->func->iommu_bit) return; -- 2.16.3