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
4444 mutex_init(&suballoc->lock);
4545 init_waitqueue_head(&suballoc->free_event);
4646
47+ BUILD_BUG_ON(ETNAVIV_SOFTPIN_START_ADDRESS < SUBALLOC_SIZE);
4748 suballoc->vaddr = dma_alloc_wc(dev, SUBALLOC_SIZE,
4849 &suballoc->paddr, GFP_KERNEL);
4950 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
529529 .desc = "etnaviv DRM",
530530 .date = "20151214",
531531 .major = 1,
532− .minor = 2,
532+ .minor = 3,
533533 };
534534
535535 /*
drivers/gpu/drm/etnaviv/etnaviv_drv.h+2−0
@@ -24,6 +24,8 @@ struct etnaviv_gem_object; · 23 unmodified lines
2424 struct etnaviv_gem_submit;
2525 struct etnaviv_iommu_global;
2626
27+#define ETNAVIV_SOFTPIN_START_ADDRESS SZ_4M /* must be >= SUBALLOC_SIZE */
28+
2729 struct etnaviv_file_private {
2830 struct etnaviv_iommu_context *mmu;
2931 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
248248 }
249249
250250 struct 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)
252253 {
253254 struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
254255 struct etnaviv_vram_mapping *mapping;
@@ -309,7 +310,7 @@ struct etnaviv_vram_mapping *etnaviv_gem_mapping_get( · 54 unmodified lines
309310
310311 ret = etnaviv_iommu_map_gem(mmu_context, etnaviv_obj,
311312 mmu_context->global->memory_base,
312− mapping, 0);
313+ mapping, va);
313314 if (ret < 0) {
314315 etnaviv_iommu_context_put(mmu_context);
315316 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
7777
7878 struct etnaviv_gem_submit_bo {
7979 u32 flags;
80+ u64 va;
8081 struct etnaviv_gem_object *obj;
8182 struct etnaviv_vram_mapping *mapping;
8283 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
7272 }
7373
7474 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+ }
7583
7684 /* normally use drm_gem_object_lookup(), but for bulk lookup
7785 * 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
224232 struct etnaviv_vram_mapping *mapping;
225233
226234 mapping = etnaviv_gem_mapping_get(&etnaviv_obj->base,
227− submit->mmu_context);
235+ submit->mmu_context,
236+ submit->bos[i].va);
228237 if (IS_ERR(mapping)) {
229238 ret = PTR_ERR(mapping);
230239 break;
231240 }
241+
242+ if ((submit->flags & ETNA_SUBMIT_SOFTPIN) &&
243+ submit->bos[i].va != mapping->iova)
244+ return -EINVAL;
245+
232246 atomic_inc(&etnaviv_obj->gpu_active);
233247
234248 submit->bos[i].flags |= BO_PINNED;
@@ -261,6 +275,10 @@ static int submit_reloc(struct etnaviv_gem_submit *submit, void *stream, · 26 unmodified lines
261275 u32 *ptr = stream;
262276 int ret;
263277
278+ /* Submits using softpin don't blend with relocs */
279+ if ((submit->flags & ETNA_SUBMIT_SOFTPIN) && nr_relocs != 0)
280+ return -EINVAL;
281+
264282 for (i = 0; i < nr_relocs; i++) {
265283 const struct drm_etnaviv_gem_submit_reloc *r = relocs + i;
266284 struct etnaviv_gem_submit_bo *bo;
@@ -445,6 +463,12 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data, · 178 unmodified lines
445463 return -EINVAL;
446464 }
447465
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+
448472 /*
449473 * Copy the command submission and bo array to kernel space in
450474 * 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
4242
4343 int etnaviv_gpu_get_param(struct etnaviv_gpu *gpu, u32 param, u64 *value)
4444 {
45+ struct etnaviv_drm_private *priv = gpu->drm->dev_private;
46+
4547 switch (param) {
4648 case ETNAVIV_PARAM_GPU_MODEL:
4749 *value = gpu->identity.model;
@@ -147,6 +149,13 @@ int etnaviv_gpu_get_param(struct etnaviv_gpu *gpu, u32 param, u64 *value) · 99 unmodified lines
147149 *value = gpu->identity.varyings_count;
148150 break;
149151
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+
150159 default:
151160 DBG("%s: invalid param: %u", dev_name(gpu->dev), param);
152161 return -EINVAL;
include/uapi/drm/etnaviv_drm.h+9−1
@@ -73,6 +73,7 @@ struct drm_etnaviv_timespec { · 72 unmodified lines
7373 #define ETNAVIV_PARAM_GPU_INSTRUCTION_COUNT 0x18
7474 #define ETNAVIV_PARAM_GPU_NUM_CONSTANTS 0x19
7575 #define ETNAVIV_PARAM_GPU_NUM_VARYINGS 0x1a
76+#define ETNAVIV_PARAM_SOFTPIN_START_ADDR 0x1b
7677
7778 #define ETNA_MAX_PIPES 4
7879
@@ -148,6 +149,11 @@ struct drm_etnaviv_gem_submit_reloc { · 69 unmodified lines
148149 * then patching the cmdstream for this entry is skipped. This can
149150 * avoid kernel needing to map/access the cmdstream bo in the common
150151 * 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.
151157 */
152158 #define ETNA_SUBMIT_BO_READ 0x0001
153159 #define ETNA_SUBMIT_BO_WRITE 0x0002
@@ -177,9 +183,11 @@ struct drm_etnaviv_gem_submit_pmr { · 23 unmodified lines
177183 #define ETNA_SUBMIT_NO_IMPLICIT 0x0001
178184 #define ETNA_SUBMIT_FENCE_FD_IN 0x0002
179185 #define ETNA_SUBMIT_FENCE_FD_OUT 0x0004
186+#define ETNA_SUBMIT_SOFTPIN 0x0008
180187 #define ETNA_SUBMIT_FLAGS (ETNA_SUBMIT_NO_IMPLICIT | \
181188 ETNA_SUBMIT_FENCE_FD_IN | \
182− ETNA_SUBMIT_FENCE_FD_OUT)
189+ ETNA_SUBMIT_FENCE_FD_OUT| \
190+ ETNA_SUBMIT_SOFTPIN)
183191 #define ETNA_PIPE_3D 0x00
184192 #define ETNA_PIPE_2D 0x01
185193 #define ETNA_PIPE_VG 0x02