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

drm/tegra: Implement correct DMA-BUF semantics

DMA-BUF requires that each device that accesses a DMA-BUF attaches to it
separately. To do so the host1x_bo_pin() and host1x_bo_unpin() functions
need to be reimplemented so that they can return a mapping, which either
represents an attachment or a map of the driver's own GEM object.

Signed-off-by: Thierry Reding <treding@nvidia.com>

+272 -292
+104 -63
drivers/gpu/drm/tegra/gem.c
··· 23 23 24 24 MODULE_IMPORT_NS(DMA_BUF); 25 25 26 + static unsigned int sg_dma_count_chunks(struct scatterlist *sgl, unsigned int nents) 27 + { 28 + dma_addr_t next = ~(dma_addr_t)0; 29 + unsigned int count = 0, i; 30 + struct scatterlist *s; 31 + 32 + for_each_sg(sgl, s, nents, i) { 33 + /* sg_dma_address(s) is only valid for entries that have sg_dma_len(s) != 0. */ 34 + if (!sg_dma_len(s)) 35 + continue; 36 + 37 + if (sg_dma_address(s) != next) { 38 + next = sg_dma_address(s) + sg_dma_len(s); 39 + count++; 40 + } 41 + } 42 + 43 + return count; 44 + } 45 + 46 + static inline unsigned int sgt_dma_count_chunks(struct sg_table *sgt) 47 + { 48 + return sg_dma_count_chunks(sgt->sgl, sgt->nents); 49 + } 50 + 26 51 static void tegra_bo_put(struct host1x_bo *bo) 27 52 { 28 53 struct tegra_bo *obj = host1x_to_tegra_bo(bo); ··· 55 30 drm_gem_object_put(&obj->gem); 56 31 } 57 32 58 - /* XXX move this into lib/scatterlist.c? */ 59 - static int sg_alloc_table_from_sg(struct sg_table *sgt, struct scatterlist *sg, 60 - unsigned int nents, gfp_t gfp_mask) 61 - { 62 - struct scatterlist *dst; 63 - unsigned int i; 64 - int err; 65 - 66 - err = sg_alloc_table(sgt, nents, gfp_mask); 67 - if (err < 0) 68 - return err; 69 - 70 - dst = sgt->sgl; 71 - 72 - for (i = 0; i < nents; i++) { 73 - sg_set_page(dst, sg_page(sg), sg->length, 0); 74 - dst = sg_next(dst); 75 - sg = sg_next(sg); 76 - } 77 - 78 - return 0; 79 - } 80 - 81 - static struct sg_table *tegra_bo_pin(struct device *dev, struct host1x_bo *bo, 82 - dma_addr_t *phys) 33 + static struct host1x_bo_mapping *tegra_bo_pin(struct device *dev, struct host1x_bo *bo, 34 + enum dma_data_direction direction) 83 35 { 84 36 struct tegra_bo *obj = host1x_to_tegra_bo(bo); 85 - struct sg_table *sgt; 37 + struct drm_gem_object *gem = &obj->gem; 38 + struct host1x_bo_mapping *map; 86 39 int err; 87 40 41 + map = kzalloc(sizeof(*map), GFP_KERNEL); 42 + if (!map) 43 + return ERR_PTR(-ENOMEM); 44 + 45 + map->bo = host1x_bo_get(bo); 46 + map->direction = direction; 47 + map->dev = dev; 48 + 88 49 /* 89 - * If we've manually mapped the buffer object through the IOMMU, make 90 - * sure to return the IOVA address of our mapping. 91 - * 92 - * Similarly, for buffers that have been allocated by the DMA API the 93 - * physical address can be used for devices that are not attached to 94 - * an IOMMU. For these devices, callers must pass a valid pointer via 95 - * the @phys argument. 96 - * 97 - * Imported buffers were also already mapped at import time, so the 98 - * existing mapping can be reused. 50 + * Imported buffers need special treatment to satisfy the semantics of DMA-BUF. 99 51 */ 100 - if (phys) { 101 - *phys = obj->iova; 102 - return NULL; 52 + if (gem->import_attach) { 53 + struct dma_buf *buf = gem->import_attach->dmabuf; 54 + 55 + map->attach = dma_buf_attach(buf, dev); 56 + if (IS_ERR(map->attach)) { 57 + err = PTR_ERR(map->attach); 58 + goto free; 59 + } 60 + 61 + map->sgt = dma_buf_map_attachment(map->attach, direction); 62 + if (IS_ERR(map->sgt)) { 63 + dma_buf_detach(buf, map->attach); 64 + err = PTR_ERR(map->sgt); 65 + goto free; 66 + } 67 + 68 + err = sgt_dma_count_chunks(map->sgt); 69 + map->size = gem->size; 70 + 71 + goto out; 103 72 } 104 73 105 74 /* 106 75 * If we don't have a mapping for this buffer yet, return an SG table 107 76 * so that host1x can do the mapping for us via the DMA API. 108 77 */ 109 - sgt = kzalloc(sizeof(*sgt), GFP_KERNEL); 110 - if (!sgt) 111 - return ERR_PTR(-ENOMEM); 78 + map->sgt = kzalloc(sizeof(*map->sgt), GFP_KERNEL); 79 + if (!map->sgt) { 80 + err = -ENOMEM; 81 + goto free; 82 + } 112 83 113 84 if (obj->pages) { 114 85 /* 115 86 * If the buffer object was allocated from the explicit IOMMU 116 87 * API code paths, construct an SG table from the pages. 117 88 */ 118 - err = sg_alloc_table_from_pages(sgt, obj->pages, obj->num_pages, 119 - 0, obj->gem.size, GFP_KERNEL); 120 - if (err < 0) 121 - goto free; 122 - } else if (obj->sgt) { 123 - /* 124 - * If the buffer object already has an SG table but no pages 125 - * were allocated for it, it means the buffer was imported and 126 - * the SG table needs to be copied to avoid overwriting any 127 - * other potential users of the original SG table. 128 - */ 129 - err = sg_alloc_table_from_sg(sgt, obj->sgt->sgl, 130 - obj->sgt->orig_nents, GFP_KERNEL); 89 + err = sg_alloc_table_from_pages(map->sgt, obj->pages, obj->num_pages, 0, gem->size, 90 + GFP_KERNEL); 131 91 if (err < 0) 132 92 goto free; 133 93 } else { ··· 121 111 * not imported, it had to be allocated with the DMA API, so 122 112 * the DMA API helper can be used. 123 113 */ 124 - err = dma_get_sgtable(dev, sgt, obj->vaddr, obj->iova, 125 - obj->gem.size); 114 + err = dma_get_sgtable(dev, map->sgt, obj->vaddr, obj->iova, gem->size); 126 115 if (err < 0) 127 116 goto free; 128 117 } 129 118 130 - return sgt; 119 + err = dma_map_sgtable(dev, map->sgt, direction, 0); 120 + if (err) 121 + goto free_sgt; 131 122 123 + out: 124 + /* 125 + * If we've manually mapped the buffer object through the IOMMU, make sure to return the 126 + * existing IOVA address of our mapping. 127 + */ 128 + if (!obj->mm) { 129 + map->phys = sg_dma_address(map->sgt->sgl); 130 + map->chunks = err; 131 + } else { 132 + map->phys = obj->iova; 133 + map->chunks = 1; 134 + } 135 + 136 + map->size = gem->size; 137 + 138 + return map; 139 + 140 + free_sgt: 141 + sg_free_table(map->sgt); 132 142 free: 133 - kfree(sgt); 143 + kfree(map->sgt); 144 + kfree(map); 134 145 return ERR_PTR(err); 135 146 } 136 147 137 - static void tegra_bo_unpin(struct device *dev, struct sg_table *sgt) 148 + static void tegra_bo_unpin(struct host1x_bo_mapping *map) 138 149 { 139 - if (sgt) { 140 - sg_free_table(sgt); 141 - kfree(sgt); 150 + if (!map) 151 + return; 152 + 153 + if (map->attach) { 154 + dma_buf_unmap_attachment(map->attach, map->sgt, map->direction); 155 + dma_buf_detach(map->attach->dmabuf, map->attach); 156 + } else { 157 + dma_unmap_sgtable(map->dev, map->sgt, map->direction, 0); 158 + sg_free_table(map->sgt); 159 + kfree(map->sgt); 142 160 } 161 + 162 + host1x_bo_put(map->bo); 163 + kfree(map); 143 164 } 144 165 145 166 static void *tegra_bo_mmap(struct host1x_bo *bo)
+15 -45
drivers/gpu/drm/tegra/plane.c
··· 74 74 75 75 for (i = 0; i < 3; i++) { 76 76 copy->iova[i] = DMA_MAPPING_ERROR; 77 - copy->sgt[i] = NULL; 77 + copy->map[i] = NULL; 78 78 } 79 79 80 80 return &copy->base; ··· 138 138 139 139 static int tegra_dc_pin(struct tegra_dc *dc, struct tegra_plane_state *state) 140 140 { 141 - struct iommu_domain *domain = iommu_get_domain_for_dev(dc->dev); 142 141 unsigned int i; 143 142 int err; 144 143 145 144 for (i = 0; i < state->base.fb->format->num_planes; i++) { 146 145 struct tegra_bo *bo = tegra_fb_get_plane(state->base.fb, i); 147 - dma_addr_t phys_addr, *phys; 148 - struct sg_table *sgt; 146 + struct host1x_bo_mapping *map; 149 147 150 - /* 151 - * If we're not attached to a domain, we already stored the 152 - * physical address when the buffer was allocated. If we're 153 - * part of a group that's shared between all display 154 - * controllers, we've also already mapped the framebuffer 155 - * through the SMMU. In both cases we can short-circuit the 156 - * code below and retrieve the stored IOV address. 157 - */ 158 - if (!domain || dc->client.group) 159 - phys = &phys_addr; 160 - else 161 - phys = NULL; 162 - 163 - sgt = host1x_bo_pin(dc->dev, &bo->base, phys); 164 - if (IS_ERR(sgt)) { 165 - err = PTR_ERR(sgt); 148 + map = host1x_bo_pin(dc->dev, &bo->base, DMA_TO_DEVICE); 149 + if (IS_ERR(map)) { 150 + err = PTR_ERR(map); 166 151 goto unpin; 167 152 } 168 153 169 - if (sgt) { 170 - err = dma_map_sgtable(dc->dev, sgt, DMA_TO_DEVICE, 0); 171 - if (err) 172 - goto unpin; 173 - 154 + if (!dc->client.group) { 174 155 /* 175 156 * The display controller needs contiguous memory, so 176 157 * fail if the buffer is discontiguous and we fail to 177 158 * map its SG table to a single contiguous chunk of 178 159 * I/O virtual memory. 179 160 */ 180 - if (sgt->nents > 1) { 161 + if (map->chunks > 1) { 181 162 err = -EINVAL; 182 163 goto unpin; 183 164 } 184 165 185 - state->iova[i] = sg_dma_address(sgt->sgl); 186 - state->sgt[i] = sgt; 166 + state->iova[i] = map->phys; 187 167 } else { 188 - state->iova[i] = phys_addr; 168 + state->iova[i] = bo->iova; 189 169 } 170 + 171 + state->map[i] = map; 190 172 } 191 173 192 174 return 0; ··· 177 195 dev_err(dc->dev, "failed to map plane %u: %d\n", i, err); 178 196 179 197 while (i--) { 180 - struct tegra_bo *bo = tegra_fb_get_plane(state->base.fb, i); 181 - struct sg_table *sgt = state->sgt[i]; 182 - 183 - if (sgt) 184 - dma_unmap_sgtable(dc->dev, sgt, DMA_TO_DEVICE, 0); 185 - 186 - host1x_bo_unpin(dc->dev, &bo->base, sgt); 198 + host1x_bo_unpin(state->map[i]); 187 199 state->iova[i] = DMA_MAPPING_ERROR; 188 - state->sgt[i] = NULL; 200 + state->map[i] = NULL; 189 201 } 190 202 191 203 return err; ··· 190 214 unsigned int i; 191 215 192 216 for (i = 0; i < state->base.fb->format->num_planes; i++) { 193 - struct tegra_bo *bo = tegra_fb_get_plane(state->base.fb, i); 194 - struct sg_table *sgt = state->sgt[i]; 195 - 196 - if (sgt) 197 - dma_unmap_sgtable(dc->dev, sgt, DMA_TO_DEVICE, 0); 198 - 199 - host1x_bo_unpin(dc->dev, &bo->base, sgt); 217 + host1x_bo_unpin(state->map[i]); 200 218 state->iova[i] = DMA_MAPPING_ERROR; 201 - state->sgt[i] = NULL; 219 + state->map[i] = NULL; 202 220 } 203 221 } 204 222
+1 -1
drivers/gpu/drm/tegra/plane.h
··· 43 43 struct tegra_plane_state { 44 44 struct drm_plane_state base; 45 45 46 - struct sg_table *sgt[3]; 46 + struct host1x_bo_mapping *map[3]; 47 47 dma_addr_t iova[3]; 48 48 49 49 struct tegra_bo_tiling tiling;
+45 -17
drivers/gpu/drm/tegra/submit.c
··· 64 64 kref_put(&bo->ref, gather_bo_release); 65 65 } 66 66 67 - static struct sg_table * 68 - gather_bo_pin(struct device *dev, struct host1x_bo *host_bo, dma_addr_t *phys) 67 + static struct host1x_bo_mapping * 68 + gather_bo_pin(struct device *dev, struct host1x_bo *bo, enum dma_data_direction direction) 69 69 { 70 - struct gather_bo *bo = container_of(host_bo, struct gather_bo, base); 71 - struct sg_table *sgt; 70 + struct gather_bo *gather = container_of(bo, struct gather_bo, base); 71 + struct host1x_bo_mapping *map; 72 72 int err; 73 73 74 - sgt = kzalloc(sizeof(*sgt), GFP_KERNEL); 75 - if (!sgt) 74 + map = kzalloc(sizeof(*map), GFP_KERNEL); 75 + if (!map) 76 76 return ERR_PTR(-ENOMEM); 77 77 78 - err = dma_get_sgtable(bo->dev, sgt, bo->gather_data, bo->gather_data_dma, 79 - bo->gather_data_words * 4); 80 - if (err) { 81 - kfree(sgt); 82 - return ERR_PTR(err); 78 + map->bo = host1x_bo_get(bo); 79 + map->direction = direction; 80 + map->dev = dev; 81 + 82 + map->sgt = kzalloc(sizeof(*map->sgt), GFP_KERNEL); 83 + if (!map->sgt) { 84 + err = -ENOMEM; 85 + goto free; 83 86 } 84 87 85 - return sgt; 88 + err = dma_get_sgtable(gather->dev, map->sgt, gather->gather_data, gather->gather_data_dma, 89 + gather->gather_data_words * 4); 90 + if (err) 91 + goto free_sgt; 92 + 93 + err = dma_map_sgtable(dev, map->sgt, direction, 0); 94 + if (err) 95 + goto free_sgt; 96 + 97 + map->phys = sg_dma_address(map->sgt->sgl); 98 + map->size = gather->gather_data_words * 4; 99 + map->chunks = err; 100 + 101 + return map; 102 + 103 + free_sgt: 104 + sg_free_table(map->sgt); 105 + kfree(map->sgt); 106 + free: 107 + kfree(map); 108 + return ERR_PTR(err); 86 109 } 87 110 88 - static void gather_bo_unpin(struct device *dev, struct sg_table *sgt) 111 + static void gather_bo_unpin(struct host1x_bo_mapping *map) 89 112 { 90 - if (sgt) { 91 - sg_free_table(sgt); 92 - kfree(sgt); 93 - } 113 + if (!map) 114 + return; 115 + 116 + dma_unmap_sgtable(map->dev, map->sgt, map->direction, 0); 117 + sg_free_table(map->sgt); 118 + kfree(map->sgt); 119 + host1x_bo_put(map->bo); 120 + 121 + kfree(map); 94 122 } 95 123 96 124 static void *gather_bo_mmap(struct host1x_bo *host_bo)
+26 -44
drivers/gpu/drm/tegra/uapi.c
··· 17 17 struct tegra_drm_mapping *mapping = 18 18 container_of(ref, struct tegra_drm_mapping, ref); 19 19 20 - if (mapping->sgt) 21 - dma_unmap_sgtable(mapping->dev, mapping->sgt, mapping->direction, 22 - DMA_ATTR_SKIP_CPU_SYNC); 23 - 24 - host1x_bo_unpin(mapping->dev, mapping->bo, mapping->sgt); 20 + host1x_bo_unpin(mapping->map); 25 21 host1x_bo_put(mapping->bo); 26 22 27 23 kfree(mapping); ··· 155 159 struct drm_tegra_channel_map *args = data; 156 160 struct tegra_drm_mapping *mapping; 157 161 struct tegra_drm_context *context; 162 + enum dma_data_direction direction; 158 163 int err = 0; 159 164 160 165 if (args->flags & ~DRM_TEGRA_CHANNEL_MAP_READ_WRITE) ··· 177 180 178 181 kref_init(&mapping->ref); 179 182 180 - mapping->dev = context->client->base.dev; 181 183 mapping->bo = tegra_gem_lookup(file, args->handle); 182 184 if (!mapping->bo) { 183 185 err = -EINVAL; 184 - goto unlock; 186 + goto free; 185 187 } 186 188 187 - if (context->client->base.group) { 188 - /* IOMMU domain managed directly using IOMMU API */ 189 - host1x_bo_pin(mapping->dev, mapping->bo, &mapping->iova); 190 - } else { 191 - switch (args->flags & DRM_TEGRA_CHANNEL_MAP_READ_WRITE) { 192 - case DRM_TEGRA_CHANNEL_MAP_READ_WRITE: 193 - mapping->direction = DMA_BIDIRECTIONAL; 194 - break; 189 + switch (args->flags & DRM_TEGRA_CHANNEL_MAP_READ_WRITE) { 190 + case DRM_TEGRA_CHANNEL_MAP_READ_WRITE: 191 + direction = DMA_BIDIRECTIONAL; 192 + break; 195 193 196 - case DRM_TEGRA_CHANNEL_MAP_WRITE: 197 - mapping->direction = DMA_FROM_DEVICE; 198 - break; 194 + case DRM_TEGRA_CHANNEL_MAP_WRITE: 195 + direction = DMA_FROM_DEVICE; 196 + break; 199 197 200 - case DRM_TEGRA_CHANNEL_MAP_READ: 201 - mapping->direction = DMA_TO_DEVICE; 202 - break; 198 + case DRM_TEGRA_CHANNEL_MAP_READ: 199 + direction = DMA_TO_DEVICE; 200 + break; 203 201 204 - default: 205 - return -EINVAL; 206 - } 207 - 208 - mapping->sgt = host1x_bo_pin(mapping->dev, mapping->bo, NULL); 209 - if (IS_ERR(mapping->sgt)) { 210 - err = PTR_ERR(mapping->sgt); 211 - goto put_gem; 212 - } 213 - 214 - err = dma_map_sgtable(mapping->dev, mapping->sgt, mapping->direction, 215 - DMA_ATTR_SKIP_CPU_SYNC); 216 - if (err) 217 - goto unpin; 218 - 219 - mapping->iova = sg_dma_address(mapping->sgt->sgl); 202 + default: 203 + err = -EINVAL; 204 + goto put_gem; 220 205 } 221 206 207 + mapping->map = host1x_bo_pin(context->client->base.dev, mapping->bo, direction); 208 + if (IS_ERR(mapping->map)) { 209 + err = PTR_ERR(mapping->map); 210 + goto put_gem; 211 + } 212 + 213 + mapping->iova = mapping->map->phys; 222 214 mapping->iova_end = mapping->iova + host1x_to_tegra_bo(mapping->bo)->gem.size; 223 215 224 216 err = xa_alloc(&context->mappings, &args->mapping, mapping, XA_LIMIT(1, U32_MAX), 225 217 GFP_KERNEL); 226 218 if (err < 0) 227 - goto unmap; 219 + goto unpin; 228 220 229 221 mutex_unlock(&fpriv->lock); 230 222 231 223 return 0; 232 224 233 - unmap: 234 - if (mapping->sgt) { 235 - dma_unmap_sgtable(mapping->dev, mapping->sgt, mapping->direction, 236 - DMA_ATTR_SKIP_CPU_SYNC); 237 - } 238 225 unpin: 239 - host1x_bo_unpin(mapping->dev, mapping->bo, mapping->sgt); 226 + host1x_bo_unpin(mapping->map); 240 227 put_gem: 241 228 host1x_bo_put(mapping->bo); 229 + free: 242 230 kfree(mapping); 243 231 unlock: 244 232 mutex_unlock(&fpriv->lock);
+2 -3
drivers/gpu/drm/tegra/uapi.h
··· 27 27 struct tegra_drm_mapping { 28 28 struct kref ref; 29 29 30 - struct device *dev; 30 + struct host1x_bo_mapping *map; 31 31 struct host1x_bo *bo; 32 - struct sg_table *sgt; 33 - enum dma_data_direction direction; 32 + 34 33 dma_addr_t iova; 35 34 dma_addr_t iova_end; 36 35 };
+58 -104
drivers/gpu/host1x/job.c
··· 134 134 135 135 static unsigned int pin_job(struct host1x *host, struct host1x_job *job) 136 136 { 137 + unsigned long mask = HOST1X_RELOC_READ | HOST1X_RELOC_WRITE; 137 138 struct host1x_client *client = job->client; 138 139 struct device *dev = client->dev; 139 140 struct host1x_job_gather *g; 140 - struct iommu_domain *domain; 141 - struct sg_table *sgt; 142 141 unsigned int i; 143 142 int err; 144 143 145 - domain = iommu_get_domain_for_dev(dev); 146 144 job->num_unpins = 0; 147 145 148 146 for (i = 0; i < job->num_relocs; i++) { 149 147 struct host1x_reloc *reloc = &job->relocs[i]; 150 - dma_addr_t phys_addr, *phys; 148 + enum dma_data_direction direction; 149 + struct host1x_bo_mapping *map; 150 + struct host1x_bo *bo; 151 151 152 152 reloc->target.bo = host1x_bo_get(reloc->target.bo); 153 153 if (!reloc->target.bo) { ··· 155 155 goto unpin; 156 156 } 157 157 158 - /* 159 - * If the client device is not attached to an IOMMU, the 160 - * physical address of the buffer object can be used. 161 - * 162 - * Similarly, when an IOMMU domain is shared between all 163 - * host1x clients, the IOVA is already available, so no 164 - * need to map the buffer object again. 165 - * 166 - * XXX Note that this isn't always safe to do because it 167 - * relies on an assumption that no cache maintenance is 168 - * needed on the buffer objects. 169 - */ 170 - if (!domain || client->group) 171 - phys = &phys_addr; 172 - else 173 - phys = NULL; 158 + bo = reloc->target.bo; 174 159 175 - sgt = host1x_bo_pin(dev, reloc->target.bo, phys); 176 - if (IS_ERR(sgt)) { 177 - err = PTR_ERR(sgt); 160 + switch (reloc->flags & mask) { 161 + case HOST1X_RELOC_READ: 162 + direction = DMA_TO_DEVICE; 163 + break; 164 + 165 + case HOST1X_RELOC_WRITE: 166 + direction = DMA_FROM_DEVICE; 167 + break; 168 + 169 + case HOST1X_RELOC_READ | HOST1X_RELOC_WRITE: 170 + direction = DMA_BIDIRECTIONAL; 171 + break; 172 + 173 + default: 174 + err = -EINVAL; 178 175 goto unpin; 179 176 } 180 177 181 - if (sgt) { 182 - unsigned long mask = HOST1X_RELOC_READ | 183 - HOST1X_RELOC_WRITE; 184 - enum dma_data_direction dir; 185 - 186 - switch (reloc->flags & mask) { 187 - case HOST1X_RELOC_READ: 188 - dir = DMA_TO_DEVICE; 189 - break; 190 - 191 - case HOST1X_RELOC_WRITE: 192 - dir = DMA_FROM_DEVICE; 193 - break; 194 - 195 - case HOST1X_RELOC_READ | HOST1X_RELOC_WRITE: 196 - dir = DMA_BIDIRECTIONAL; 197 - break; 198 - 199 - default: 200 - err = -EINVAL; 201 - goto unpin; 202 - } 203 - 204 - err = dma_map_sgtable(dev, sgt, dir, 0); 205 - if (err) 206 - goto unpin; 207 - 208 - job->unpins[job->num_unpins].dev = dev; 209 - job->unpins[job->num_unpins].dir = dir; 210 - phys_addr = sg_dma_address(sgt->sgl); 178 + map = host1x_bo_pin(dev, bo, direction); 179 + if (IS_ERR(map)) { 180 + err = PTR_ERR(map); 181 + goto unpin; 211 182 } 212 183 213 - job->addr_phys[job->num_unpins] = phys_addr; 214 - job->unpins[job->num_unpins].bo = reloc->target.bo; 215 - job->unpins[job->num_unpins].sgt = sgt; 184 + /* 185 + * host1x clients are generally not able to do scatter-gather themselves, so fail 186 + * if the buffer is discontiguous and we fail to map its SG table to a single 187 + * contiguous chunk of I/O virtual memory. 188 + */ 189 + if (map->chunks > 1) { 190 + err = -EINVAL; 191 + goto unpin; 192 + } 193 + 194 + job->addr_phys[job->num_unpins] = map->phys; 195 + job->unpins[job->num_unpins].map = map; 216 196 job->num_unpins++; 217 197 } 218 198 ··· 204 224 return 0; 205 225 206 226 for (i = 0; i < job->num_cmds; i++) { 227 + struct host1x_bo_mapping *map; 207 228 size_t gather_size = 0; 208 229 struct scatterlist *sg; 209 - dma_addr_t phys_addr; 210 230 unsigned long shift; 211 231 struct iova *alloc; 212 - dma_addr_t *phys; 213 232 unsigned int j; 214 233 215 234 if (job->cmds[i].is_wait) ··· 222 243 goto unpin; 223 244 } 224 245 225 - /** 226 - * If the host1x is not attached to an IOMMU, there is no need 227 - * to map the buffer object for the host1x, since the physical 228 - * address can simply be used. 229 - */ 230 - if (!iommu_get_domain_for_dev(host->dev)) 231 - phys = &phys_addr; 232 - else 233 - phys = NULL; 234 - 235 - sgt = host1x_bo_pin(host->dev, g->bo, phys); 236 - if (IS_ERR(sgt)) { 237 - err = PTR_ERR(sgt); 238 - goto put; 246 + map = host1x_bo_pin(host->dev, g->bo, DMA_TO_DEVICE); 247 + if (IS_ERR(map)) { 248 + err = PTR_ERR(map); 249 + goto unpin; 239 250 } 240 251 241 252 if (host->domain) { 242 - for_each_sgtable_sg(sgt, sg, j) 253 + for_each_sgtable_sg(map->sgt, sg, j) 243 254 gather_size += sg->length; 255 + 244 256 gather_size = iova_align(&host->iova, gather_size); 245 257 246 258 shift = iova_shift(&host->iova); ··· 242 272 goto put; 243 273 } 244 274 245 - err = iommu_map_sgtable(host->domain, 246 - iova_dma_addr(&host->iova, alloc), 247 - sgt, IOMMU_READ); 275 + err = iommu_map_sgtable(host->domain, iova_dma_addr(&host->iova, alloc), 276 + map->sgt, IOMMU_READ); 248 277 if (err == 0) { 249 278 __free_iova(&host->iova, alloc); 250 279 err = -EINVAL; 251 280 goto put; 252 281 } 253 282 254 - job->unpins[job->num_unpins].size = gather_size; 255 - phys_addr = iova_dma_addr(&host->iova, alloc); 256 - } else if (sgt) { 257 - err = dma_map_sgtable(host->dev, sgt, DMA_TO_DEVICE, 0); 258 - if (err) 259 - goto put; 260 - 261 - job->unpins[job->num_unpins].dir = DMA_TO_DEVICE; 262 - job->unpins[job->num_unpins].dev = host->dev; 263 - phys_addr = sg_dma_address(sgt->sgl); 283 + map->phys = iova_dma_addr(&host->iova, alloc); 284 + map->size = gather_size; 264 285 } 265 286 266 - job->addr_phys[job->num_unpins] = phys_addr; 267 - job->gather_addr_phys[i] = phys_addr; 268 - 269 - job->unpins[job->num_unpins].bo = g->bo; 270 - job->unpins[job->num_unpins].sgt = sgt; 287 + job->addr_phys[job->num_unpins] = map->phys; 288 + job->unpins[job->num_unpins].map = map; 271 289 job->num_unpins++; 290 + 291 + job->gather_addr_phys[i] = map->phys; 272 292 } 273 293 274 294 return 0; ··· 650 690 unsigned int i; 651 691 652 692 for (i = 0; i < job->num_unpins; i++) { 653 - struct host1x_job_unpin_data *unpin = &job->unpins[i]; 654 - struct device *dev = unpin->dev ?: host->dev; 655 - struct sg_table *sgt = unpin->sgt; 693 + struct host1x_bo_mapping *map = job->unpins[i].map; 694 + struct host1x_bo *bo = map->bo; 656 695 657 - if (!job->enable_firewall && unpin->size && host->domain) { 658 - iommu_unmap(host->domain, job->addr_phys[i], 659 - unpin->size); 660 - free_iova(&host->iova, 661 - iova_pfn(&host->iova, job->addr_phys[i])); 696 + if (!job->enable_firewall && map->size && host->domain) { 697 + iommu_unmap(host->domain, job->addr_phys[i], map->size); 698 + free_iova(&host->iova, iova_pfn(&host->iova, job->addr_phys[i])); 662 699 } 663 700 664 - if (unpin->dev && sgt) 665 - dma_unmap_sgtable(unpin->dev, sgt, unpin->dir, 0); 666 - 667 - host1x_bo_unpin(dev, unpin->bo, sgt); 668 - host1x_bo_put(unpin->bo); 701 + host1x_bo_unpin(map); 702 + host1x_bo_put(bo); 669 703 } 670 704 671 705 job->num_unpins = 0;
+1 -5
drivers/gpu/host1x/job.h
··· 35 35 }; 36 36 37 37 struct host1x_job_unpin_data { 38 - struct host1x_bo *bo; 39 - struct sg_table *sgt; 40 - struct device *dev; 41 - size_t size; 42 - enum dma_data_direction dir; 38 + struct host1x_bo_mapping *map; 43 39 }; 44 40 45 41 /*
+20 -10
include/linux/host1x.h
··· 7 7 #define __LINUX_HOST1X_H 8 8 9 9 #include <linux/device.h> 10 + #include <linux/dma-direction.h> 10 11 #include <linux/types.h> 11 12 12 13 enum host1x_class { ··· 83 82 struct host1x_bo; 84 83 struct sg_table; 85 84 85 + struct host1x_bo_mapping { 86 + struct dma_buf_attachment *attach; 87 + enum dma_data_direction direction; 88 + struct host1x_bo *bo; 89 + struct sg_table *sgt; 90 + unsigned int chunks; 91 + struct device *dev; 92 + dma_addr_t phys; 93 + size_t size; 94 + }; 95 + 86 96 struct host1x_bo_ops { 87 97 struct host1x_bo *(*get)(struct host1x_bo *bo); 88 98 void (*put)(struct host1x_bo *bo); 89 - struct sg_table *(*pin)(struct device *dev, struct host1x_bo *bo, 90 - dma_addr_t *phys); 91 - void (*unpin)(struct device *dev, struct sg_table *sgt); 99 + struct host1x_bo_mapping *(*pin)(struct device *dev, struct host1x_bo *bo, 100 + enum dma_data_direction dir); 101 + void (*unpin)(struct host1x_bo_mapping *map); 92 102 void *(*mmap)(struct host1x_bo *bo); 93 103 void (*munmap)(struct host1x_bo *bo, void *addr); 94 104 }; ··· 124 112 bo->ops->put(bo); 125 113 } 126 114 127 - static inline struct sg_table *host1x_bo_pin(struct device *dev, 128 - struct host1x_bo *bo, 129 - dma_addr_t *phys) 115 + static inline struct host1x_bo_mapping *host1x_bo_pin(struct device *dev, struct host1x_bo *bo, 116 + enum dma_data_direction dir) 130 117 { 131 - return bo->ops->pin(dev, bo, phys); 118 + return bo->ops->pin(dev, bo, dir); 132 119 } 133 120 134 - static inline void host1x_bo_unpin(struct device *dev, struct host1x_bo *bo, 135 - struct sg_table *sgt) 121 + static inline void host1x_bo_unpin(struct host1x_bo_mapping *map) 136 122 { 137 - bo->ops->unpin(dev, sgt); 123 + map->bo->ops->unpin(map); 138 124 } 139 125 140 126 static inline void *host1x_bo_mmap(struct host1x_bo *bo)