diff options
Diffstat (limited to 'drivers/gpu/drm/i915/i915_cmd_parser.c')
-rw-r--r-- | drivers/gpu/drm/i915/i915_cmd_parser.c | 79 |
1 files changed, 62 insertions, 17 deletions
diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index b882bf2a2388..2a4ccac66b5a 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c @@ -848,6 +848,56 @@ finish: return (u32*)addr; } +/* Returns a vmap'd pointer to dest_obj, which the caller must unmap */ +static u32 *copy_batch(struct drm_i915_gem_object *dest_obj, + struct drm_i915_gem_object *src_obj) +{ + int ret = 0; + int needs_clflush = 0; + u32 *src_addr, *dest_addr = NULL; + + ret = i915_gem_obj_prepare_shmem_read(src_obj, &needs_clflush); + if (ret) { + DRM_DEBUG_DRIVER("CMD: failed to prep read\n"); + return ERR_PTR(ret); + } + + src_addr = vmap_batch(src_obj); + if (!src_addr) { + DRM_DEBUG_DRIVER("CMD: Failed to vmap batch\n"); + ret = -ENOMEM; + goto unpin_src; + } + + if (needs_clflush) + drm_clflush_virt_range((char *)src_addr, src_obj->base.size); + + ret = i915_gem_object_set_to_cpu_domain(dest_obj, true); + if (ret) { + DRM_DEBUG_DRIVER("CMD: Failed to set batch CPU domain\n"); + goto unmap_src; + } + + dest_addr = vmap_batch(dest_obj); + if (!dest_addr) { + DRM_DEBUG_DRIVER("CMD: Failed to vmap shadow batch\n"); + ret = -ENOMEM; + goto unmap_src; + } + + memcpy(dest_addr, src_addr, src_obj->base.size); + if (dest_obj->base.size > src_obj->base.size) + memset((u8 *)dest_addr + src_obj->base.size, 0, + dest_obj->base.size - src_obj->base.size); + +unmap_src: + vunmap(src_addr); +unpin_src: + i915_gem_object_unpin_pages(src_obj); + + return ret ? ERR_PTR(ret) : dest_addr; +} + /** * i915_needs_cmd_parser() - should a given ring use software command parsing? * @ring: the ring in question @@ -964,6 +1014,7 @@ static bool check_cmd(const struct intel_engine_cs *ring, * i915_parse_cmds() - parse a submitted batch buffer for privilege violations * @ring: the ring on which the batch is to execute * @batch_obj: the batch buffer in question + * @shadow_batch_obj: copy of the batch buffer in question * @batch_start_offset: byte offset in the batch at which execution starts * @is_master: is the submitting process the drm master? * @@ -975,32 +1026,28 @@ static bool check_cmd(const struct intel_engine_cs *ring, */ int i915_parse_cmds(struct intel_engine_cs *ring, struct drm_i915_gem_object *batch_obj, + struct drm_i915_gem_object *shadow_batch_obj, u32 batch_start_offset, bool is_master) { int ret = 0; u32 *cmd, *batch_base, *batch_end; struct drm_i915_cmd_descriptor default_desc = { 0 }; - int needs_clflush = 0; bool oacontrol_set = false; /* OACONTROL tracking. See check_cmd() */ - ret = i915_gem_obj_prepare_shmem_read(batch_obj, &needs_clflush); - if (ret) { - DRM_DEBUG_DRIVER("CMD: failed to prep read\n"); - return ret; + batch_base = copy_batch(shadow_batch_obj, batch_obj); + if (IS_ERR(batch_base)) { + DRM_DEBUG_DRIVER("CMD: Failed to copy batch\n"); + return PTR_ERR(batch_base); } - batch_base = vmap_batch(batch_obj); - if (!batch_base) { - DRM_DEBUG_DRIVER("CMD: Failed to vmap batch\n"); - i915_gem_object_unpin_pages(batch_obj); - return -ENOMEM; - } - - if (needs_clflush) - drm_clflush_virt_range((char *)batch_base, batch_obj->base.size); - cmd = batch_base + (batch_start_offset / sizeof(*cmd)); + + /* + * We use the source object's size because the shadow object is as + * large or larger and copy_batch() will write MI_NOPs to the extra + * space. Parsing should be faster in some cases this way. + */ batch_end = cmd + (batch_obj->base.size / sizeof(*batch_end)); while (cmd < batch_end) { @@ -1062,8 +1109,6 @@ int i915_parse_cmds(struct intel_engine_cs *ring, vunmap(batch_base); - i915_gem_object_unpin_pages(batch_obj); - return ret; } |