diff options
author | Mark Kettenis <kettenis@openbsd.org> | 2013-03-10 20:33:10 +0100 |
---|---|---|
committer | Mark Kettenis <kettenis@openbsd.org> | 2013-03-10 20:33:10 +0100 |
commit | 1251b11c93a9ab8eda018c9a6750ee989e6b9ed3 (patch) | |
tree | 88b3d4489ea38b670efdeeff3f786d7aa74dcd8f | |
parent | 13686416801499eac0955c28e46c461eaa652619 (diff) |
bring i915_gem_object_bind_to_gtt closer to Linux 3.8.2
-rw-r--r-- | sys/dev/pci/drm/i915_drv.h | 9 | ||||
-rw-r--r-- | sys/dev/pci/drm/i915_gem.c | 212 |
2 files changed, 152 insertions, 69 deletions
diff --git a/sys/dev/pci/drm/i915_drv.h b/sys/dev/pci/drm/i915_drv.h index c4c52feaeb4..2eaf075a67b 100644 --- a/sys/dev/pci/drm/i915_drv.h +++ b/sys/dev/pci/drm/i915_drv.h @@ -1068,8 +1068,6 @@ void i915_dispatch_gem_execbuffer(struct intel_ring_buffer *, int i915_gem_object_pin_and_relocate(struct drm_obj *, struct drm_file *, struct drm_i915_gem_exec_object2 *, struct drm_i915_gem_relocation_entry *); -int i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *, - bus_size_t); struct drm_obj *i915_gem_find_inactive_object(struct inteldrm_softc *, size_t); @@ -1084,7 +1082,6 @@ int i915_gem_object_set_to_cpu_domain(struct drm_i915_gem_object *, bool); int i915_gem_object_flush_gpu_write_domain(struct drm_i915_gem_object *); int i915_gem_object_wait_rendering(struct drm_i915_gem_object *, bool); -bus_size_t i915_gem_get_gtt_alignment(struct drm_obj *); int i915_gem_init(struct drm_device *); int i915_gem_mmap_gtt(struct drm_file *, struct drm_device *, @@ -1208,6 +1205,12 @@ int i915_gem_object_put_fence(struct drm_i915_gem_object *); void i915_gem_reset(struct drm_device *); void i915_gem_clflush_object(struct drm_i915_gem_object *); void i915_gem_release(struct drm_device *, struct drm_file *); + +uint32_t +i915_gem_get_unfenced_gtt_alignment(struct drm_device *dev, + uint32_t size, + int tiling_mode); + int i915_gem_object_sync(struct drm_i915_gem_object *, struct intel_ring_buffer *); diff --git a/sys/dev/pci/drm/i915_gem.c b/sys/dev/pci/drm/i915_gem.c index 938908c78e3..1dc1f4c2e2d 100644 --- a/sys/dev/pci/drm/i915_gem.c +++ b/sys/dev/pci/drm/i915_gem.c @@ -57,6 +57,10 @@ #include <sys/workq.h> void i915_gem_release_mmap(struct drm_i915_gem_object *); +uint32_t i915_gem_get_gtt_size(struct drm_device *dev, uint32_t size, + int tiling_mode); +uint32_t i915_gem_get_gtt_alignment(struct drm_device *dev, + uint32_t size, int tiling_mode); void i915_gem_object_finish_gtt(struct drm_i915_gem_object *); void i915_gem_object_flush_cpu_write_domain(struct drm_i915_gem_object *); int i915_gem_init_phys_object(struct drm_device *, int, int, int); @@ -75,6 +79,8 @@ void i915_gem_request_remove_from_client(struct drm_i915_gem_request *); int i915_gem_object_flush_active(struct drm_i915_gem_object *); int i915_gem_check_olr(struct intel_ring_buffer *, u32); void i915_gem_object_truncate(struct drm_i915_gem_object *obj); +int i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, + unsigned alignment, bool map_and_fenceable); extern int ticks; @@ -640,20 +646,15 @@ i915_gem_fault(struct drm_obj *gem_obj, struct uvm_faultinfo *ufi, */ drm_unlock_obj(&obj->base); - if (obj->dmamap != NULL && - (obj->gtt_offset & (i915_gem_get_gtt_alignment(&obj->base) - 1) || - (!i915_gem_object_fence_ok(obj, obj->tiling_mode)))) { - /* - * pinned objects are defined to have a sane alignment which can - * not change. - */ - KASSERT(obj->pin_count == 0); - if ((ret = i915_gem_object_unbind(obj))) + /* Now bind into the GTT if needed */ + if (!obj->map_and_fenceable) { + ret = i915_gem_object_unbind(obj); + if (ret) goto error; } if (obj->dmamap == NULL) { - ret = i915_gem_object_bind_to_gtt(obj, 0); + ret = i915_gem_object_bind_to_gtt(obj, 0, true); if (ret) goto error; @@ -760,43 +761,83 @@ i915_gem_release_mmap(struct drm_i915_gem_object *obj) obj->fault_mappable = false; } -// i915_gem_get_gtt_size +uint32_t +i915_gem_get_gtt_size(struct drm_device *dev, uint32_t size, int tiling_mode) +{ + uint32_t gtt_size; -/* - * return required GTT alignment for an object, taking into account potential - * fence register needs + if (INTEL_INFO(dev)->gen >= 4 || + tiling_mode == I915_TILING_NONE) + return size; + + /* Previous chips need a power-of-two fence region when tiling */ + if (INTEL_INFO(dev)->gen == 3) + gtt_size = 1024*1024; + else + gtt_size = 512*1024; + + while (gtt_size < size) + gtt_size <<= 1; + + return gtt_size; +} + +/** + * i915_gem_get_gtt_alignment - return required GTT alignment for an object + * @obj: object to check + * + * Return the required GTT alignment for an object, taking into account + * potential fence register mapping. */ -bus_size_t -i915_gem_get_gtt_alignment(struct drm_obj *obj) +uint32_t +i915_gem_get_gtt_alignment(struct drm_device *dev, + uint32_t size, + int tiling_mode) { - struct drm_device *dev = obj->dev; - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); - bus_size_t start, i; - /* - * Minimum alignment is 4k (GTT page size), but fence registers may - * modify this + * Minimum alignment is 4k (GTT page size), but might be greater + * if a fence register is needed for the object. */ if (INTEL_INFO(dev)->gen >= 4 || - obj_priv->tiling_mode == I915_TILING_NONE) - return (4096); + tiling_mode == I915_TILING_NONE) + return 4096; /* - * Older chips need to be aligned to the size of the smallest fence - * register that can contain the object. + * Previous chips need to be aligned to the size of the smallest + * fence register that can contain the object. */ - if (IS_I9XX(dev)) - start = 1024 * 1024; - else - start = 512 * 1024; + return i915_gem_get_gtt_size(dev, size, tiling_mode); +} - for (i = start; i < obj->size; i <<= 1) - ; +/** + * i915_gem_get_unfenced_gtt_alignment - return required GTT alignment for an + * unfenced object + * @dev: the device + * @size: size of the object + * @tiling_mode: tiling mode of the object + * + * Return the required GTT alignment for an object, only taking into account + * unfenced tiled surface requirements. + */ +uint32_t +i915_gem_get_unfenced_gtt_alignment(struct drm_device *dev, + uint32_t size, + int tiling_mode) +{ + /* + * Minimum alignment is 4k (GTT page size) for sane hw. + */ + if (INTEL_INFO(dev)->gen >= 4 || IS_G33(dev) || + tiling_mode == I915_TILING_NONE) + return 4096; - return (i); + /* Previous hardware however needs to be aligned to a power-of-two + * tile height. The simplest method for determining this is to reuse + * the power-of-tile object size. + */ + return i915_gem_get_gtt_size(dev, size, tiling_mode); } -// i915_gem_get_unfenced_gtt_alignment // i915_gem_object_create_mmap_offset // i915_gem_object_free_mmap_offset @@ -832,7 +873,7 @@ i915_gem_mmap_gtt(struct drm_file *file, struct drm_device *dev, goto done; } - ret = i915_gem_object_bind_to_gtt(obj, 0); + ret = i915_gem_object_bind_to_gtt(obj, 0, true); if (ret) { printf("%s: failed to bind\n", __func__); goto done; @@ -1481,7 +1522,7 @@ sandybridge_write_fence_reg(struct drm_device *dev, int reg, uint64_t val; if (obj) { - u32 size = obj->base.size; + u32 size = obj->dmamap->dm_segs[0].ds_len; val = (uint64_t)((obj->gtt_offset + size - 4096) & 0xfffff000) << 32; @@ -1507,7 +1548,7 @@ i965_write_fence_reg(struct drm_device *dev, int reg, uint64_t val; if (obj) { - u32 size = obj->base.size; + u32 size = obj->dmamap->dm_segs[0].ds_len; val = (uint64_t)((obj->gtt_offset + size - 4096) & 0xfffff000) << 32; @@ -1531,7 +1572,7 @@ i915_write_fence_reg(struct drm_device *dev, int reg, u32 val; if (obj) { - u32 size = obj->base.size; + u32 size = obj->dmamap->dm_segs[0].ds_len; int pitch_val; int tile_width; @@ -1576,7 +1617,7 @@ i830_write_fence_reg(struct drm_device *dev, int reg, uint32_t val; if (obj) { - u32 size = obj->base.size; + u32 size = obj->dmamap->dm_segs[0].ds_len; uint32_t pitch_val; WARN((obj->gtt_offset & ~I830_FENCE_START_MASK) || @@ -1789,12 +1830,14 @@ i915_gem_object_get_fence(struct drm_i915_gem_object *obj) */ int i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, - bus_size_t alignment) + unsigned alignment, bool map_and_fenceable) { struct drm_device *dev = obj->base.dev; drm_i915_private_t *dev_priv = dev->dev_private; + u32 size, fence_size, fence_alignment, unfenced_alignment; + bool mappable, fenceable; int ret; - uint32_t flags; + int flags; DRM_ASSERT_HELD(&obj->base); @@ -1803,15 +1846,40 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, return EINVAL; } - if (alignment == 0) { - alignment = i915_gem_get_gtt_alignment(&obj->base); - } else if (alignment & (i915_gem_get_gtt_alignment(&obj->base) - 1)) { + fence_size = i915_gem_get_gtt_size(dev, + obj->base.size, + obj->tiling_mode); + fence_alignment = i915_gem_get_gtt_alignment(dev, + obj->base.size, + obj->tiling_mode); + unfenced_alignment = + i915_gem_get_unfenced_gtt_alignment(dev, + obj->base.size, + obj->tiling_mode); + + if (alignment == 0) + alignment = map_and_fenceable ? fence_alignment : + unfenced_alignment; + if (map_and_fenceable && alignment & (fence_alignment - 1)) { DRM_ERROR("Invalid object alignment requested %u\n", alignment); - return (EINVAL); + return EINVAL; + } + + size = map_and_fenceable ? fence_size : obj->base.size; + +#ifdef notyet + /* If the object is bigger than the entire aperture, reject it early + * before evicting everything in a vain attempt to find space. + */ + if (obj->base.size > + (map_and_fenceable ? dev_priv->mm.gtt_mappable_end : dev_priv->mm.gtt_total)) { + DRM_ERROR("Attempting to bind an object larger than the aperture\n"); + return -E2BIG; } +#endif - if ((ret = bus_dmamap_create(dev_priv->agpdmat, obj->base.size, 1, - obj->base.size, 0, BUS_DMA_WAITOK, &obj->dmamap)) != 0) { + if ((ret = bus_dmamap_create(dev_priv->agpdmat, size, 1, + size, 0, BUS_DMA_WAITOK, &obj->dmamap)) != 0) { DRM_ERROR("Failed to create dmamap\n"); return (ret); } @@ -1868,6 +1936,19 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, obj->gtt_offset = obj->dmamap->dm_segs[0].ds_addr - dev->agp->base; + fenceable = + obj->dmamap->dm_segs[0].ds_len == fence_size && + (obj->dmamap->dm_segs[0].ds_addr & (fence_alignment - 1)) == 0; + +#ifdef notyet + mappable = + obj->gtt_offset + obj->base.size <= dev_priv->mm.gtt_mappable_end; +#else + mappable = true; +#endif + + obj->map_and_fenceable = mappable && fenceable; + atomic_inc(&dev->gtt_count); atomic_add(obj->base.size, &dev->gtt_memory); @@ -2290,28 +2371,27 @@ i915_gem_object_pin(struct drm_i915_gem_object *obj, DRM_ASSERT_HELD(&obj->base); inteldrm_verify_inactive(dev_priv, __FILE__, __LINE__); - /* - * if already bound, but alignment is unsuitable, unbind so we can - * fix it. Similarly if we have constraints due to fence registers, - * adjust if needed. Note that if we are already pinned we may as well - * fail because whatever depends on this alignment will render poorly - * otherwise, so just fail the pin (with a printf so we can fix a - * wrong userland). - */ - if (obj->dmamap != NULL && - ((alignment && obj->gtt_offset & (alignment - 1)) || - obj->gtt_offset & (i915_gem_get_gtt_alignment(&obj->base) - 1) || - !i915_gem_object_fence_ok(obj, obj->tiling_mode))) { - /* if it is already pinned we sanitised the alignment then */ - KASSERT(obj->pin_count == 0); - if ((ret = i915_gem_object_unbind(obj))) - return (ret); + if (obj->dmamap != NULL) { + if ((alignment && obj->gtt_offset & (alignment - 1)) || + (map_and_fenceable && !obj->map_and_fenceable)) { + WARN(obj->pin_count, + "bo is already pinned with incorrect alignment:" + " offset=%x, req.alignment=%x, req.map_and_fenceable=%d," + " obj->map_and_fenceable=%d\n", + obj->gtt_offset, alignment, + map_and_fenceable, + obj->map_and_fenceable); + ret = i915_gem_object_unbind(obj); + if (ret) + return ret; + } } if (obj->dmamap == NULL) { - ret = i915_gem_object_bind_to_gtt(obj, alignment); - if (ret != 0) - return (ret); + ret = i915_gem_object_bind_to_gtt(obj, alignment, + map_and_fenceable); + if (ret) + return ret; } /* |