diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2011-04-04 04:44:39 -0400 |
---|---|---|
committer | Keith Packard <keithp@keithp.com> | 2011-06-10 00:51:16 -0400 |
commit | e4ffd173a1c2f96b43127c2537dd99d89e759bba (patch) | |
tree | 932a67f5eebb7884ba6b28a4ebf0893d84a44eec | |
parent | d5bd144959e639443f387c34989cec7c9efff091 (diff) |
drm/i915: Add an interface to dynamically change the cache level
[anholt v2: Don't forget that when going from cached to uncached, we
haven't been tracking the write domain from the CPU perspective, since
we haven't needed it for GPU coherency.]
[ickle v3: We also need to make sure we relinquish any fences on older
chipsets and clear the GTT for sane domain tracking.]
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Eric Anholt <eric@anholt.net>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.h | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem.c | 60 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem_gtt.c | 7 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_ringbuffer.c | 6 |
4 files changed, 71 insertions, 7 deletions
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 4d1a8ae70a33..e552aa6bc859 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h | |||
@@ -1223,9 +1223,14 @@ void i915_gem_release(struct drm_device *dev, struct drm_file *file); | |||
1223 | uint32_t | 1223 | uint32_t |
1224 | i915_gem_get_unfenced_gtt_alignment(struct drm_i915_gem_object *obj); | 1224 | i915_gem_get_unfenced_gtt_alignment(struct drm_i915_gem_object *obj); |
1225 | 1225 | ||
1226 | int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj, | ||
1227 | enum i915_cache_level cache_level); | ||
1228 | |||
1226 | /* i915_gem_gtt.c */ | 1229 | /* i915_gem_gtt.c */ |
1227 | void i915_gem_restore_gtt_mappings(struct drm_device *dev); | 1230 | void i915_gem_restore_gtt_mappings(struct drm_device *dev); |
1228 | int __must_check i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj); | 1231 | int __must_check i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj); |
1232 | void i915_gem_gtt_rebind_object(struct drm_i915_gem_object *obj, | ||
1233 | enum i915_cache_level cache_level); | ||
1229 | void i915_gem_gtt_unbind_object(struct drm_i915_gem_object *obj); | 1234 | void i915_gem_gtt_unbind_object(struct drm_i915_gem_object *obj); |
1230 | 1235 | ||
1231 | /* i915_gem_evict.c */ | 1236 | /* i915_gem_evict.c */ |
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index e78a7ef634d9..e6915072ba72 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c | |||
@@ -3034,6 +3034,66 @@ i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write) | |||
3034 | return 0; | 3034 | return 0; |
3035 | } | 3035 | } |
3036 | 3036 | ||
3037 | int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj, | ||
3038 | enum i915_cache_level cache_level) | ||
3039 | { | ||
3040 | int ret; | ||
3041 | |||
3042 | if (obj->cache_level == cache_level) | ||
3043 | return 0; | ||
3044 | |||
3045 | if (obj->pin_count) { | ||
3046 | DRM_DEBUG("can not change the cache level of pinned objects\n"); | ||
3047 | return -EBUSY; | ||
3048 | } | ||
3049 | |||
3050 | if (obj->gtt_space) { | ||
3051 | ret = i915_gem_object_finish_gpu(obj); | ||
3052 | if (ret) | ||
3053 | return ret; | ||
3054 | |||
3055 | i915_gem_object_finish_gtt(obj); | ||
3056 | |||
3057 | /* Before SandyBridge, you could not use tiling or fence | ||
3058 | * registers with snooped memory, so relinquish any fences | ||
3059 | * currently pointing to our region in the aperture. | ||
3060 | */ | ||
3061 | if (INTEL_INFO(obj->base.dev)->gen < 6) { | ||
3062 | ret = i915_gem_object_put_fence(obj); | ||
3063 | if (ret) | ||
3064 | return ret; | ||
3065 | } | ||
3066 | |||
3067 | i915_gem_gtt_rebind_object(obj, cache_level); | ||
3068 | } | ||
3069 | |||
3070 | if (cache_level == I915_CACHE_NONE) { | ||
3071 | u32 old_read_domains, old_write_domain; | ||
3072 | |||
3073 | /* If we're coming from LLC cached, then we haven't | ||
3074 | * actually been tracking whether the data is in the | ||
3075 | * CPU cache or not, since we only allow one bit set | ||
3076 | * in obj->write_domain and have been skipping the clflushes. | ||
3077 | * Just set it to the CPU cache for now. | ||
3078 | */ | ||
3079 | WARN_ON(obj->base.write_domain & ~I915_GEM_DOMAIN_CPU); | ||
3080 | WARN_ON(obj->base.read_domains & ~I915_GEM_DOMAIN_CPU); | ||
3081 | |||
3082 | old_read_domains = obj->base.read_domains; | ||
3083 | old_write_domain = obj->base.write_domain; | ||
3084 | |||
3085 | obj->base.read_domains = I915_GEM_DOMAIN_CPU; | ||
3086 | obj->base.write_domain = I915_GEM_DOMAIN_CPU; | ||
3087 | |||
3088 | trace_i915_gem_object_change_domain(obj, | ||
3089 | old_read_domains, | ||
3090 | old_write_domain); | ||
3091 | } | ||
3092 | |||
3093 | obj->cache_level = cache_level; | ||
3094 | return 0; | ||
3095 | } | ||
3096 | |||
3037 | /* | 3097 | /* |
3038 | * Prepare buffer for display plane. Use uninterruptible for possible flush | 3098 | * Prepare buffer for display plane. Use uninterruptible for possible flush |
3039 | * wait, as in modesetting process we're not supposed to be interrupted. | 3099 | * wait, as in modesetting process we're not supposed to be interrupted. |
diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 837033cf2ce5..7a709cd8d543 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c | |||
@@ -29,9 +29,6 @@ | |||
29 | #include "i915_trace.h" | 29 | #include "i915_trace.h" |
30 | #include "intel_drv.h" | 30 | #include "intel_drv.h" |
31 | 31 | ||
32 | static void i915_gem_gtt_rebind_object(struct drm_i915_gem_object *obj, | ||
33 | enum i915_cache_level cache_level); | ||
34 | |||
35 | /* XXX kill agp_type! */ | 32 | /* XXX kill agp_type! */ |
36 | static unsigned int cache_level_to_agp_type(struct drm_device *dev, | 33 | static unsigned int cache_level_to_agp_type(struct drm_device *dev, |
37 | enum i915_cache_level cache_level) | 34 | enum i915_cache_level cache_level) |
@@ -97,8 +94,8 @@ int i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj) | |||
97 | return 0; | 94 | return 0; |
98 | } | 95 | } |
99 | 96 | ||
100 | static void i915_gem_gtt_rebind_object(struct drm_i915_gem_object *obj, | 97 | void i915_gem_gtt_rebind_object(struct drm_i915_gem_object *obj, |
101 | enum i915_cache_level cache_level) | 98 | enum i915_cache_level cache_level) |
102 | { | 99 | { |
103 | struct drm_device *dev = obj->base.dev; | 100 | struct drm_device *dev = obj->base.dev; |
104 | struct drm_i915_private *dev_priv = dev->dev_private; | 101 | struct drm_i915_private *dev_priv = dev->dev_private; |
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 95c4b1429935..e9615685a39c 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c | |||
@@ -236,7 +236,8 @@ init_pipe_control(struct intel_ring_buffer *ring) | |||
236 | ret = -ENOMEM; | 236 | ret = -ENOMEM; |
237 | goto err; | 237 | goto err; |
238 | } | 238 | } |
239 | obj->cache_level = I915_CACHE_LLC; | 239 | |
240 | i915_gem_object_set_cache_level(obj, I915_CACHE_LLC); | ||
240 | 241 | ||
241 | ret = i915_gem_object_pin(obj, 4096, true); | 242 | ret = i915_gem_object_pin(obj, 4096, true); |
242 | if (ret) | 243 | if (ret) |
@@ -776,7 +777,8 @@ static int init_status_page(struct intel_ring_buffer *ring) | |||
776 | ret = -ENOMEM; | 777 | ret = -ENOMEM; |
777 | goto err; | 778 | goto err; |
778 | } | 779 | } |
779 | obj->cache_level = I915_CACHE_LLC; | 780 | |
781 | i915_gem_object_set_cache_level(obj, I915_CACHE_LLC); | ||
780 | 782 | ||
781 | ret = i915_gem_object_pin(obj, 4096, true); | 783 | ret = i915_gem_object_pin(obj, 4096, true); |
782 | if (ret != 0) { | 784 | if (ret != 0) { |