diff options
Diffstat (limited to 'drivers/gpu/drm/i915/i915_gem_render_state.c')
| -rw-r--r-- | drivers/gpu/drm/i915/i915_gem_render_state.c | 198 | 
1 files changed, 198 insertions, 0 deletions
diff --git a/drivers/gpu/drm/i915/i915_gem_render_state.c b/drivers/gpu/drm/i915/i915_gem_render_state.c new file mode 100644 index 00000000000..34894b57306 --- /dev/null +++ b/drivers/gpu/drm/i915/i915_gem_render_state.c @@ -0,0 +1,198 @@ +/* + * Copyright © 2014 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Authors: + *    Mika Kuoppala <mika.kuoppala@intel.com> + * + */ + +#include "i915_drv.h" +#include "intel_renderstate.h" + +struct i915_render_state { +	struct drm_i915_gem_object *obj; +	unsigned long ggtt_offset; +	u32 *batch; +	u32 size; +	u32 len; +}; + +static struct i915_render_state *render_state_alloc(struct drm_device *dev) +{ +	struct i915_render_state *so; +	struct page *page; +	int ret; + +	so = kzalloc(sizeof(*so), GFP_KERNEL); +	if (!so) +		return ERR_PTR(-ENOMEM); + +	so->obj = i915_gem_alloc_object(dev, 4096); +	if (so->obj == NULL) { +		ret = -ENOMEM; +		goto free; +	} +	so->size = 4096; + +	ret = i915_gem_obj_ggtt_pin(so->obj, 4096, 0); +	if (ret) +		goto free_gem; + +	BUG_ON(so->obj->pages->nents != 1); +	page = sg_page(so->obj->pages->sgl); + +	so->batch = kmap(page); +	if (!so->batch) { +		ret = -ENOMEM; +		goto unpin; +	} + +	so->ggtt_offset = i915_gem_obj_ggtt_offset(so->obj); + +	return so; +unpin: +	i915_gem_object_ggtt_unpin(so->obj); +free_gem: +	drm_gem_object_unreference(&so->obj->base); +free: +	kfree(so); +	return ERR_PTR(ret); +} + +static void render_state_free(struct i915_render_state *so) +{ +	kunmap(kmap_to_page(so->batch)); +	i915_gem_object_ggtt_unpin(so->obj); +	drm_gem_object_unreference(&so->obj->base); +	kfree(so); +} + +static const struct intel_renderstate_rodata * +render_state_get_rodata(struct drm_device *dev, const int gen) +{ +	switch (gen) { +	case 6: +		return &gen6_null_state; +	case 7: +		return &gen7_null_state; +	case 8: +		return &gen8_null_state; +	} + +	return NULL; +} + +static int render_state_setup(const int gen, +			      const struct intel_renderstate_rodata *rodata, +			      struct i915_render_state *so) +{ +	const u64 goffset = i915_gem_obj_ggtt_offset(so->obj); +	u32 reloc_index = 0; +	u32 * const d = so->batch; +	unsigned int i = 0; +	int ret; + +	if (!rodata || rodata->batch_items * 4 > so->size) +		return -EINVAL; + +	ret = i915_gem_object_set_to_cpu_domain(so->obj, true); +	if (ret) +		return ret; + +	while (i < rodata->batch_items) { +		u32 s = rodata->batch[i]; + +		if (reloc_index < rodata->reloc_items && +		    i * 4  == rodata->reloc[reloc_index]) { + +			s += goffset & 0xffffffff; + +			/* We keep batch offsets max 32bit */ +			if (gen >= 8) { +				if (i + 1 >= rodata->batch_items || +				    rodata->batch[i + 1] != 0) +					return -EINVAL; + +				d[i] = s; +				i++; +				s = (goffset & 0xffffffff00000000ull) >> 32; +			} + +			reloc_index++; +		} + +		d[i] = s; +		i++; +	} + +	ret = i915_gem_object_set_to_gtt_domain(so->obj, false); +	if (ret) +		return ret; + +	if (rodata->reloc_items != reloc_index) { +		DRM_ERROR("not all relocs resolved, %d out of %d\n", +			  reloc_index, rodata->reloc_items); +		return -EINVAL; +	} + +	so->len = rodata->batch_items * 4; + +	return 0; +} + +int i915_gem_render_state_init(struct intel_engine_cs *ring) +{ +	const int gen = INTEL_INFO(ring->dev)->gen; +	struct i915_render_state *so; +	const struct intel_renderstate_rodata *rodata; +	int ret; + +	if (WARN_ON(ring->id != RCS)) +		return -ENOENT; + +	rodata = render_state_get_rodata(ring->dev, gen); +	if (rodata == NULL) +		return 0; + +	so = render_state_alloc(ring->dev); +	if (IS_ERR(so)) +		return PTR_ERR(so); + +	ret = render_state_setup(gen, rodata, so); +	if (ret) +		goto out; + +	ret = ring->dispatch_execbuffer(ring, +					i915_gem_obj_ggtt_offset(so->obj), +					so->len, +					I915_DISPATCH_SECURE); +	if (ret) +		goto out; + +	i915_vma_move_to_active(i915_gem_obj_to_ggtt(so->obj), ring); + +	ret = __i915_add_request(ring, NULL, so->obj, NULL); +	/* __i915_add_request moves object to inactive if it fails */ +out: +	render_state_free(so); +	return ret; +}  | 
