History

drm/etnaviv: implement softpin

With softpin we allow the userspace to take control over the GPU virtual address space. The new capability is relected by a bump of the minor DRM version. There are a few restrictions for userspace to take into account: 1. The kernel reserves a bit of the address space to implement zero page faulting and mapping of the kernel internal ring buffer. Userspace can query the kernel for the first usable GPU VM address via ETNAVIV_PARAM_SOFTPIN_START_ADDR. 2. We only allow softpin on GPUs, which implement proper process separation via PPAS. If softpin is not available the softpin start address will be set to ~0. 3. Softpin is all or nothing. A submit using softpin must not use any address fixups via relocs.

Lucas Stach committed 7 years ago

Commit 088880d1 parent 17eae238 files · +51 −5Browse files

Unified · Split

8 files
  1. drivers/gpu/drm/etnaviv/etnaviv_cmdbuf.c +1 −0
  2. drivers/gpu/drm/etnaviv/etnaviv_drv.c +1 −1
  3. drivers/gpu/drm/etnaviv/etnaviv_drv.h +2 −0
  4. drivers/gpu/drm/etnaviv/etnaviv_gem.c +3 −2
  5. drivers/gpu/drm/etnaviv/etnaviv_gem.h +1 −0
  6. drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c +25 −1
  7. drivers/gpu/drm/etnaviv/etnaviv_gpu.c +9 −0
  8. include/uapi/drm/etnaviv_drm.h +9 −1
drivers/gpu/drm/etnaviv/etnaviv_cmdbuf.c+1−0
@@ -44,6 +44,7 @@ etnaviv_cmdbuf_suballoc_new(struct device *dev) · 43 unmodified lines
44 mutex_init(&suballoc->lock);44 mutex_init(&suballoc->lock);
45 init_waitqueue_head(&suballoc->free_event);45 init_waitqueue_head(&suballoc->free_event);
46 46
47 BUILD_BUG_ON(ETNAVIV_SOFTPIN_START_ADDRESS < SUBALLOC_SIZE);
47 suballoc->vaddr = dma_alloc_wc(dev, SUBALLOC_SIZE,48 suballoc->vaddr = dma_alloc_wc(dev, SUBALLOC_SIZE,
48 &suballoc->paddr, GFP_KERNEL);49 &suballoc->paddr, GFP_KERNEL);
49 if (!suballoc->vaddr) {50 if (!suballoc->vaddr) {
drivers/gpu/drm/etnaviv/etnaviv_drv.c+1−1
@@ -529,7 +529,7 @@ static struct drm_driver etnaviv_drm_driver = { · 528 unmodified lines
529 .desc = "etnaviv DRM",529 .desc = "etnaviv DRM",
530 .date = "20151214",530 .date = "20151214",
531 .major = 1,531 .major = 1,
532 .minor = 2,532 .minor = 3,
533};533};
534 534
535/*535/*
drivers/gpu/drm/etnaviv/etnaviv_drv.h+2−0
@@ -24,6 +24,8 @@ struct etnaviv_gem_object; · 23 unmodified lines
24struct etnaviv_gem_submit;24struct etnaviv_gem_submit;
25struct etnaviv_iommu_global;25struct etnaviv_iommu_global;
26 26
27#define ETNAVIV_SOFTPIN_START_ADDRESS SZ_4M /* must be >= SUBALLOC_SIZE */
28
27struct etnaviv_file_private {29struct etnaviv_file_private {
28 struct etnaviv_iommu_context *mmu;30 struct etnaviv_iommu_context *mmu;
29 struct drm_sched_entity sched_entity[ETNA_MAX_PIPES];31 struct drm_sched_entity sched_entity[ETNA_MAX_PIPES];
drivers/gpu/drm/etnaviv/etnaviv_gem.c+3−2
@@ -248,7 +248,8 @@ void etnaviv_gem_mapping_unreference(struct etnaviv_vram_mapping *mapping) · 247 unmodified lines
248}248}
249 249
250struct etnaviv_vram_mapping *etnaviv_gem_mapping_get(250struct etnaviv_vram_mapping *etnaviv_gem_mapping_get(
251 struct drm_gem_object *obj, struct etnaviv_iommu_context *mmu_context)251 struct drm_gem_object *obj, struct etnaviv_iommu_context *mmu_context,
252 u64 va)
252{253{
253 struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);254 struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
254 struct etnaviv_vram_mapping *mapping;255 struct etnaviv_vram_mapping *mapping;
@@ -309,7 +310,7 @@ struct etnaviv_vram_mapping *etnaviv_gem_mapping_get( · 54 unmodified lines
309 310
310 ret = etnaviv_iommu_map_gem(mmu_context, etnaviv_obj,311 ret = etnaviv_iommu_map_gem(mmu_context, etnaviv_obj,
311 mmu_context->global->memory_base,312 mmu_context->global->memory_base,
312 mapping, 0);313 mapping, va);
313 if (ret < 0) {314 if (ret < 0) {
314 etnaviv_iommu_context_put(mmu_context);315 etnaviv_iommu_context_put(mmu_context);
315 kfree(mapping);316 kfree(mapping);
drivers/gpu/drm/etnaviv/etnaviv_gem.h+1−0
@@ -77,6 +77,7 @@ static inline bool is_active(struct etnaviv_gem_object *etnaviv_obj) · 76 unmodified lines
77 77
78struct etnaviv_gem_submit_bo {78struct etnaviv_gem_submit_bo {
79 u32 flags;79 u32 flags;
80 u64 va;
80 struct etnaviv_gem_object *obj;81 struct etnaviv_gem_object *obj;
81 struct etnaviv_vram_mapping *mapping;82 struct etnaviv_vram_mapping *mapping;
82 struct dma_fence *excl;83 struct dma_fence *excl;
drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c+25−1
@@ -72,6 +72,14 @@ static int submit_lookup_objects(struct etnaviv_gem_submit *submit, · 71 unmodified lines
72 }72 }
73 73
74 submit->bos[i].flags = bo->flags;74 submit->bos[i].flags = bo->flags;
75 if (submit->flags & ETNA_SUBMIT_SOFTPIN) {
76 if (bo->presumed < ETNAVIV_SOFTPIN_START_ADDRESS) {
77 DRM_ERROR("invalid softpin address\n");
78 ret = -EINVAL;
79 goto out_unlock;
80 }
81 submit->bos[i].va = bo->presumed;
82 }
75 83
76 /* normally use drm_gem_object_lookup(), but for bulk lookup84 /* normally use drm_gem_object_lookup(), but for bulk lookup
77 * all under single table_lock just hit object_idr directly:85 * all under single table_lock just hit object_idr directly:
@@ -224,11 +232,17 @@ static int submit_pin_objects(struct etnaviv_gem_submit *submit) · 146 unmodified lines
224 struct etnaviv_vram_mapping *mapping;232 struct etnaviv_vram_mapping *mapping;
225 233
226 mapping = etnaviv_gem_mapping_get(&etnaviv_obj->base,234 mapping = etnaviv_gem_mapping_get(&etnaviv_obj->base,
227 submit->mmu_context);235 submit->mmu_context,
236 submit->bos[i].va);
228 if (IS_ERR(mapping)) {237 if (IS_ERR(mapping)) {
229 ret = PTR_ERR(mapping);238 ret = PTR_ERR(mapping);
230 break;239 break;
231 }240 }
241
242 if ((submit->flags & ETNA_SUBMIT_SOFTPIN) &&
243 submit->bos[i].va != mapping->iova)
244 return -EINVAL;
245
232 atomic_inc(&etnaviv_obj->gpu_active);246 atomic_inc(&etnaviv_obj->gpu_active);
233 247
234 submit->bos[i].flags |= BO_PINNED;248 submit->bos[i].flags |= BO_PINNED;
@@ -261,6 +275,10 @@ static int submit_reloc(struct etnaviv_gem_submit *submit, void *stream, · 26 unmodified lines
261 u32 *ptr = stream;275 u32 *ptr = stream;
262 int ret;276 int ret;
263 277
278 /* Submits using softpin don't blend with relocs */
279 if ((submit->flags & ETNA_SUBMIT_SOFTPIN) && nr_relocs != 0)
280 return -EINVAL;
281
264 for (i = 0; i < nr_relocs; i++) {282 for (i = 0; i < nr_relocs; i++) {
265 const struct drm_etnaviv_gem_submit_reloc *r = relocs + i;283 const struct drm_etnaviv_gem_submit_reloc *r = relocs + i;
266 struct etnaviv_gem_submit_bo *bo;284 struct etnaviv_gem_submit_bo *bo;
@@ -445,6 +463,12 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data, · 178 unmodified lines
445 return -EINVAL;463 return -EINVAL;
446 }464 }
447 465
466 if ((args->flags & ETNA_SUBMIT_SOFTPIN) &&
467 priv->mmu_global->version != ETNAVIV_IOMMU_V2) {
468 DRM_ERROR("softpin requested on incompatible MMU\n");
469 return -EINVAL;
470 }
471
448 /*472 /*
449 * Copy the command submission and bo array to kernel space in473 * Copy the command submission and bo array to kernel space in
450 * one go, and do this outside of any locks.474 * one go, and do this outside of any locks.
drivers/gpu/drm/etnaviv/etnaviv_gpu.c+9−0
@@ -42,6 +42,8 @@ static const struct platform_device_id gpu_ids[] = { · 41 unmodified lines
42 42
43int etnaviv_gpu_get_param(struct etnaviv_gpu *gpu, u32 param, u64 *value)43int etnaviv_gpu_get_param(struct etnaviv_gpu *gpu, u32 param, u64 *value)
44{44{
45 struct etnaviv_drm_private *priv = gpu->drm->dev_private;
46
45 switch (param) {47 switch (param) {
46 case ETNAVIV_PARAM_GPU_MODEL:48 case ETNAVIV_PARAM_GPU_MODEL:
47 *value = gpu->identity.model;49 *value = gpu->identity.model;
@@ -147,6 +149,13 @@ int etnaviv_gpu_get_param(struct etnaviv_gpu *gpu, u32 param, u64 *value) · 99 unmodified lines
147 *value = gpu->identity.varyings_count;149 *value = gpu->identity.varyings_count;
148 break;150 break;
149 151
152 case ETNAVIV_PARAM_SOFTPIN_START_ADDR:
153 if (priv->mmu_global->version == ETNAVIV_IOMMU_V2)
154 *value = ETNAVIV_SOFTPIN_START_ADDRESS;
155 else
156 *value = ~0ULL;
157 break;
158
150 default:159 default:
151 DBG("%s: invalid param: %u", dev_name(gpu->dev), param);160 DBG("%s: invalid param: %u", dev_name(gpu->dev), param);
152 return -EINVAL;161 return -EINVAL;
include/uapi/drm/etnaviv_drm.h+9−1
@@ -73,6 +73,7 @@ struct drm_etnaviv_timespec { · 72 unmodified lines
73#define ETNAVIV_PARAM_GPU_INSTRUCTION_COUNT 0x1873#define ETNAVIV_PARAM_GPU_INSTRUCTION_COUNT 0x18
74#define ETNAVIV_PARAM_GPU_NUM_CONSTANTS 0x1974#define ETNAVIV_PARAM_GPU_NUM_CONSTANTS 0x19
75#define ETNAVIV_PARAM_GPU_NUM_VARYINGS 0x1a75#define ETNAVIV_PARAM_GPU_NUM_VARYINGS 0x1a
76#define ETNAVIV_PARAM_SOFTPIN_START_ADDR 0x1b
76 77
77#define ETNA_MAX_PIPES 478#define ETNA_MAX_PIPES 4
78 79
@@ -148,6 +149,11 @@ struct drm_etnaviv_gem_submit_reloc { · 69 unmodified lines
148 * then patching the cmdstream for this entry is skipped. This can149 * then patching the cmdstream for this entry is skipped. This can
149 * avoid kernel needing to map/access the cmdstream bo in the common150 * avoid kernel needing to map/access the cmdstream bo in the common
150 * case.151 * case.
152 * If the submit is a softpin submit (ETNA_SUBMIT_SOFTPIN) the 'presumed'
153 * field is interpreted as the fixed location to map the bo into the gpu
154 * virtual address space. If the kernel is unable to map the buffer at
155 * this location the submit will fail. This means userspace is responsible
156 * for the whole gpu virtual address management.
151 */157 */
152#define ETNA_SUBMIT_BO_READ 0x0001158#define ETNA_SUBMIT_BO_READ 0x0001
153#define ETNA_SUBMIT_BO_WRITE 0x0002159#define ETNA_SUBMIT_BO_WRITE 0x0002
@@ -177,9 +183,11 @@ struct drm_etnaviv_gem_submit_pmr { · 23 unmodified lines
177#define ETNA_SUBMIT_NO_IMPLICIT 0x0001183#define ETNA_SUBMIT_NO_IMPLICIT 0x0001
178#define ETNA_SUBMIT_FENCE_FD_IN 0x0002184#define ETNA_SUBMIT_FENCE_FD_IN 0x0002
179#define ETNA_SUBMIT_FENCE_FD_OUT 0x0004185#define ETNA_SUBMIT_FENCE_FD_OUT 0x0004
186#define ETNA_SUBMIT_SOFTPIN 0x0008
180#define ETNA_SUBMIT_FLAGS (ETNA_SUBMIT_NO_IMPLICIT | \187#define ETNA_SUBMIT_FLAGS (ETNA_SUBMIT_NO_IMPLICIT | \
181 ETNA_SUBMIT_FENCE_FD_IN | \188 ETNA_SUBMIT_FENCE_FD_IN | \
182 ETNA_SUBMIT_FENCE_FD_OUT)189 ETNA_SUBMIT_FENCE_FD_OUT| \
190 ETNA_SUBMIT_SOFTPIN)
183#define ETNA_PIPE_3D 0x00191#define ETNA_PIPE_3D 0x00
184#define ETNA_PIPE_2D 0x01192#define ETNA_PIPE_2D 0x01
185#define ETNA_PIPE_VG 0x02193#define ETNA_PIPE_VG 0x02