diff options
Diffstat (limited to 'drivers/gpu/drm/i915/i915_cmd_parser.c')
| -rw-r--r-- | drivers/gpu/drm/i915/i915_cmd_parser.c | 130 | 
1 files changed, 71 insertions, 59 deletions
diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index 3992c25a191d..a3b4d99d64b9 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c @@ -1145,19 +1145,41 @@ find_reg(const struct intel_engine_cs *engine, u32 addr)  static u32 *copy_batch(struct drm_i915_gem_object *dst_obj,  		       struct drm_i915_gem_object *src_obj,  		       unsigned long offset, unsigned long length, -		       void *dst, const void *src) +		       bool *needs_clflush_after)  { -	bool needs_clflush = -		!(src_obj->cache_coherent & I915_BO_CACHE_COHERENT_FOR_READ); +	unsigned int src_needs_clflush; +	unsigned int dst_needs_clflush; +	void *dst, *src; +	int ret; + +	ret = i915_gem_object_prepare_write(dst_obj, &dst_needs_clflush); +	if (ret) +		return ERR_PTR(ret); -	if (src) { -		GEM_BUG_ON(!needs_clflush); -		i915_unaligned_memcpy_from_wc(dst, src + offset, length); -	} else { -		struct scatterlist *sg; +	dst = i915_gem_object_pin_map(dst_obj, I915_MAP_WB); +	i915_gem_object_finish_access(dst_obj); +	if (IS_ERR(dst)) +		return dst; + +	ret = i915_gem_object_prepare_read(src_obj, &src_needs_clflush); +	if (ret) { +		i915_gem_object_unpin_map(dst_obj); +		return ERR_PTR(ret); +	} + +	src = ERR_PTR(-ENODEV); +	if (src_needs_clflush && i915_has_memcpy_from_wc()) { +		src = i915_gem_object_pin_map(src_obj, I915_MAP_WC); +		if (!IS_ERR(src)) { +			i915_unaligned_memcpy_from_wc(dst, +						      src + offset, +						      length); +			i915_gem_object_unpin_map(src_obj); +		} +	} +	if (IS_ERR(src)) { +		unsigned long x, n, remain;  		void *ptr; -		unsigned int x, sg_ofs; -		unsigned long remain;  		/*  		 * We can avoid clflushing partial cachelines before the write @@ -1168,40 +1190,34 @@ static u32 *copy_batch(struct drm_i915_gem_object *dst_obj,  		 * validate up to the end of the batch.  		 */  		remain = length; -		if (!(dst_obj->cache_coherent & I915_BO_CACHE_COHERENT_FOR_READ)) +		if (dst_needs_clflush & CLFLUSH_BEFORE)  			remain = round_up(remain,  					  boot_cpu_data.x86_clflush_size);  		ptr = dst;  		x = offset_in_page(offset); -		sg = i915_gem_object_get_sg(src_obj, offset >> PAGE_SHIFT, &sg_ofs, false); - -		while (remain) { -			unsigned long sg_max = sg->length >> PAGE_SHIFT; - -			for (; remain && sg_ofs < sg_max; sg_ofs++) { -				unsigned long len = min(remain, PAGE_SIZE - x); -				void *map; +		for (n = offset >> PAGE_SHIFT; remain; n++) { +			int len = min(remain, PAGE_SIZE - x); -				map = kmap_atomic(nth_page(sg_page(sg), sg_ofs)); -				if (needs_clflush) -					drm_clflush_virt_range(map + x, len); -				memcpy(ptr, map + x, len); -				kunmap_atomic(map); +			src = kmap_atomic(i915_gem_object_get_page(src_obj, n)); +			if (src_needs_clflush) +				drm_clflush_virt_range(src + x, len); +			memcpy(ptr, src + x, len); +			kunmap_atomic(src); -				ptr += len; -				remain -= len; -				x = 0; -			} - -			sg_ofs = 0; -			sg = sg_next(sg); +			ptr += len; +			remain -= len; +			x = 0;  		}  	} +	i915_gem_object_finish_access(src_obj); +  	memset32(dst + length, 0, (dst_obj->base.size - length) / sizeof(u32));  	/* dst_obj is returned with vmap pinned */ +	*needs_clflush_after = dst_needs_clflush & CLFLUSH_AFTER; +  	return dst;  } @@ -1360,6 +1376,9 @@ static int check_bbstart(u32 *cmd, u32 offset, u32 length,  	if (target_cmd_index == offset)  		return 0; +	if (IS_ERR(jump_whitelist)) +		return PTR_ERR(jump_whitelist); +  	if (!test_bit(target_cmd_index, jump_whitelist)) {  		DRM_DEBUG("CMD: BB_START to 0x%llx not a previously executed cmd\n",  			  jump_target); @@ -1369,28 +1388,10 @@ static int check_bbstart(u32 *cmd, u32 offset, u32 length,  	return 0;  } -/** - * intel_engine_cmd_parser_alloc_jump_whitelist() - preallocate jump whitelist for intel_engine_cmd_parser() - * @batch_length: length of the commands in batch_obj - * @trampoline: Whether jump trampolines are used. - * - * Preallocates a jump whitelist for parsing the cmd buffer in intel_engine_cmd_parser(). - * This has to be preallocated, because the command parser runs in signaling context, - * and may not allocate any memory. - * - * Return: NULL or pointer to a jump whitelist, or ERR_PTR() on failure. Use - * IS_ERR() to check for errors. Must bre freed() with kfree(). - * - * NULL is a valid value, meaning no allocation was required. - */ -unsigned long *intel_engine_cmd_parser_alloc_jump_whitelist(u32 batch_length, -							    bool trampoline) +static unsigned long *alloc_whitelist(u32 batch_length)  {  	unsigned long *jmp; -	if (trampoline) -		return NULL; -  	/*  	 * We expect batch_length to be less than 256KiB for known users,  	 * i.e. we need at most an 8KiB bitmap allocation which should be @@ -1415,9 +1416,7 @@ unsigned long *intel_engine_cmd_parser_alloc_jump_whitelist(u32 batch_length,   * @batch_offset: byte offset in the batch at which execution starts   * @batch_length: length of the commands in batch_obj   * @shadow: validated copy of the batch buffer in question - * @jump_whitelist: buffer preallocated with intel_engine_cmd_parser_alloc_jump_whitelist() - * @shadow_map: mapping to @shadow vma - * @batch_map: mapping to @batch vma + * @trampoline: true if we need to trampoline into privileged execution   *   * Parses the specified batch buffer looking for privilege violations as   * described in the overview. @@ -1425,21 +1424,21 @@ unsigned long *intel_engine_cmd_parser_alloc_jump_whitelist(u32 batch_length,   * Return: non-zero if the parser finds violations or otherwise fails; -EACCES   * if the batch appears legal but should use hardware parsing   */ +  int intel_engine_cmd_parser(struct intel_engine_cs *engine,  			    struct i915_vma *batch,  			    unsigned long batch_offset,  			    unsigned long batch_length,  			    struct i915_vma *shadow, -			    unsigned long *jump_whitelist, -			    void *shadow_map, -			    const void *batch_map) +			    bool trampoline)  {  	u32 *cmd, *batch_end, offset = 0;  	struct drm_i915_cmd_descriptor default_desc = noop_desc;  	const struct drm_i915_cmd_descriptor *desc = &default_desc; +	bool needs_clflush_after = false; +	unsigned long *jump_whitelist;  	u64 batch_addr, shadow_addr;  	int ret = 0; -	bool trampoline = !jump_whitelist;  	GEM_BUG_ON(!IS_ALIGNED(batch_offset, sizeof(*cmd)));  	GEM_BUG_ON(!IS_ALIGNED(batch_length, sizeof(*cmd))); @@ -1447,8 +1446,18 @@ int intel_engine_cmd_parser(struct intel_engine_cs *engine,  				     batch->size));  	GEM_BUG_ON(!batch_length); -	cmd = copy_batch(shadow->obj, batch->obj, batch_offset, batch_length, -			 shadow_map, batch_map); +	cmd = copy_batch(shadow->obj, batch->obj, +			 batch_offset, batch_length, +			 &needs_clflush_after); +	if (IS_ERR(cmd)) { +		DRM_DEBUG("CMD: Failed to copy batch\n"); +		return PTR_ERR(cmd); +	} + +	jump_whitelist = NULL; +	if (!trampoline) +		/* Defer failure until attempted use */ +		jump_whitelist = alloc_whitelist(batch_length);  	shadow_addr = gen8_canonical_addr(shadow->node.start);  	batch_addr = gen8_canonical_addr(batch->node.start + batch_offset); @@ -1549,6 +1558,9 @@ int intel_engine_cmd_parser(struct intel_engine_cs *engine,  	i915_gem_object_flush_map(shadow->obj); +	if (!IS_ERR_OR_NULL(jump_whitelist)) +		kfree(jump_whitelist); +	i915_gem_object_unpin_map(shadow->obj);  	return ret;  }  | 
