root/drivers/staging/media/tegra-vde/iommu.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. tegra_vde_iommu_map
  2. tegra_vde_iommu_unmap
  3. tegra_vde_iommu_init
  4. tegra_vde_iommu_deinit

   1 // SPDX-License-Identifier: GPL-2.0+
   2 /*
   3  * NVIDIA Tegra Video decoder driver
   4  *
   5  * Copyright (C) 2016-2019 GRATE-DRIVER project
   6  */
   7 
   8 #include <linux/iommu.h>
   9 #include <linux/iova.h>
  10 #include <linux/kernel.h>
  11 #include <linux/platform_device.h>
  12 
  13 #if IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU)
  14 #include <asm/dma-iommu.h>
  15 #endif
  16 
  17 #include "vde.h"
  18 
  19 int tegra_vde_iommu_map(struct tegra_vde *vde,
  20                         struct sg_table *sgt,
  21                         struct iova **iovap,
  22                         size_t size)
  23 {
  24         struct iova *iova;
  25         unsigned long shift;
  26         unsigned long end;
  27         dma_addr_t addr;
  28 
  29         end = vde->domain->geometry.aperture_end;
  30         size = iova_align(&vde->iova, size);
  31         shift = iova_shift(&vde->iova);
  32 
  33         iova = alloc_iova(&vde->iova, size >> shift, end >> shift, true);
  34         if (!iova)
  35                 return -ENOMEM;
  36 
  37         addr = iova_dma_addr(&vde->iova, iova);
  38 
  39         size = iommu_map_sg(vde->domain, addr, sgt->sgl, sgt->nents,
  40                             IOMMU_READ | IOMMU_WRITE);
  41         if (!size) {
  42                 __free_iova(&vde->iova, iova);
  43                 return -ENXIO;
  44         }
  45 
  46         *iovap = iova;
  47 
  48         return 0;
  49 }
  50 
  51 void tegra_vde_iommu_unmap(struct tegra_vde *vde, struct iova *iova)
  52 {
  53         unsigned long shift = iova_shift(&vde->iova);
  54         unsigned long size = iova_size(iova) << shift;
  55         dma_addr_t addr = iova_dma_addr(&vde->iova, iova);
  56 
  57         iommu_unmap(vde->domain, addr, size);
  58         __free_iova(&vde->iova, iova);
  59 }
  60 
  61 int tegra_vde_iommu_init(struct tegra_vde *vde)
  62 {
  63         struct device *dev = vde->miscdev.parent;
  64         struct iova *iova;
  65         unsigned long order;
  66         unsigned long shift;
  67         int err;
  68 
  69         vde->group = iommu_group_get(dev);
  70         if (!vde->group)
  71                 return 0;
  72 
  73 #if IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU)
  74         if (dev->archdata.mapping) {
  75                 struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev);
  76 
  77                 arm_iommu_detach_device(dev);
  78                 arm_iommu_release_mapping(mapping);
  79         }
  80 #endif
  81         vde->domain = iommu_domain_alloc(&platform_bus_type);
  82         if (!vde->domain) {
  83                 err = -ENOMEM;
  84                 goto put_group;
  85         }
  86 
  87         err = iova_cache_get();
  88         if (err)
  89                 goto free_domain;
  90 
  91         order = __ffs(vde->domain->pgsize_bitmap);
  92         init_iova_domain(&vde->iova, 1UL << order, 0);
  93 
  94         err = iommu_attach_group(vde->domain, vde->group);
  95         if (err)
  96                 goto put_iova;
  97 
  98         /*
  99          * We're using some static addresses that are not accessible by VDE
 100          * to trap invalid memory accesses.
 101          */
 102         shift = iova_shift(&vde->iova);
 103         iova = reserve_iova(&vde->iova, 0x60000000 >> shift,
 104                             0x70000000 >> shift);
 105         if (!iova) {
 106                 err = -ENOMEM;
 107                 goto detach_group;
 108         }
 109 
 110         vde->iova_resv_static_addresses = iova;
 111 
 112         /*
 113          * BSEV's end-address wraps around due to integer overflow during
 114          * of hardware context preparation if IOVA is allocated at the end
 115          * of address space and VDE can't handle that. Hence simply reserve
 116          * the last page to avoid the problem.
 117          */
 118         iova = reserve_iova(&vde->iova, 0xffffffff >> shift,
 119                             (0xffffffff >> shift) + 1);
 120         if (!iova) {
 121                 err = -ENOMEM;
 122                 goto unreserve_iova;
 123         }
 124 
 125         vde->iova_resv_last_page = iova;
 126 
 127         return 0;
 128 
 129 unreserve_iova:
 130         __free_iova(&vde->iova, vde->iova_resv_static_addresses);
 131 detach_group:
 132         iommu_detach_group(vde->domain, vde->group);
 133 put_iova:
 134         put_iova_domain(&vde->iova);
 135         iova_cache_put();
 136 free_domain:
 137         iommu_domain_free(vde->domain);
 138 put_group:
 139         iommu_group_put(vde->group);
 140 
 141         return err;
 142 }
 143 
 144 void tegra_vde_iommu_deinit(struct tegra_vde *vde)
 145 {
 146         if (vde->domain) {
 147                 __free_iova(&vde->iova, vde->iova_resv_last_page);
 148                 __free_iova(&vde->iova, vde->iova_resv_static_addresses);
 149                 iommu_detach_group(vde->domain, vde->group);
 150                 put_iova_domain(&vde->iova);
 151                 iova_cache_put();
 152                 iommu_domain_free(vde->domain);
 153                 iommu_group_put(vde->group);
 154 
 155                 vde->domain = NULL;
 156         }
 157 }

/* [<][>][^][v][top][bottom][index][help] */