diff options
| -rw-r--r-- | drivers/gpu/drm/i915/i915_drv.h | 6 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/i915_gem.c | 86 |
2 files changed, 54 insertions, 38 deletions
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 7537f57d8a87..11fc4b66c889 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h | |||
| @@ -384,6 +384,9 @@ typedef struct drm_i915_private { | |||
| 384 | */ | 384 | */ |
| 385 | struct list_head inactive_list; | 385 | struct list_head inactive_list; |
| 386 | 386 | ||
| 387 | /** LRU list of objects with fence regs on them. */ | ||
| 388 | struct list_head fence_list; | ||
| 389 | |||
| 387 | /** | 390 | /** |
| 388 | * List of breadcrumbs associated with GPU requests currently | 391 | * List of breadcrumbs associated with GPU requests currently |
| 389 | * outstanding. | 392 | * outstanding. |
| @@ -451,6 +454,9 @@ struct drm_i915_gem_object { | |||
| 451 | /** This object's place on the active/flushing/inactive lists */ | 454 | /** This object's place on the active/flushing/inactive lists */ |
| 452 | struct list_head list; | 455 | struct list_head list; |
| 453 | 456 | ||
| 457 | /** This object's place on the fenced object LRU */ | ||
| 458 | struct list_head fence_list; | ||
| 459 | |||
| 454 | /** | 460 | /** |
| 455 | * This is set if the object is on the active or flushing lists | 461 | * This is set if the object is on the active or flushing lists |
| 456 | * (has pending rendering), and is not set if it's on inactive (ready | 462 | * (has pending rendering), and is not set if it's on inactive (ready |
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 140bee142fc2..0c07a755b3a3 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c | |||
| @@ -978,6 +978,7 @@ int | |||
| 978 | i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, | 978 | i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, |
| 979 | struct drm_file *file_priv) | 979 | struct drm_file *file_priv) |
| 980 | { | 980 | { |
| 981 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
| 981 | struct drm_i915_gem_set_domain *args = data; | 982 | struct drm_i915_gem_set_domain *args = data; |
| 982 | struct drm_gem_object *obj; | 983 | struct drm_gem_object *obj; |
| 983 | uint32_t read_domains = args->read_domains; | 984 | uint32_t read_domains = args->read_domains; |
| @@ -1010,8 +1011,18 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, | |||
| 1010 | obj, obj->size, read_domains, write_domain); | 1011 | obj, obj->size, read_domains, write_domain); |
| 1011 | #endif | 1012 | #endif |
| 1012 | if (read_domains & I915_GEM_DOMAIN_GTT) { | 1013 | if (read_domains & I915_GEM_DOMAIN_GTT) { |
| 1014 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | ||
| 1015 | |||
| 1013 | ret = i915_gem_object_set_to_gtt_domain(obj, write_domain != 0); | 1016 | ret = i915_gem_object_set_to_gtt_domain(obj, write_domain != 0); |
| 1014 | 1017 | ||
| 1018 | /* Update the LRU on the fence for the CPU access that's | ||
| 1019 | * about to occur. | ||
| 1020 | */ | ||
| 1021 | if (obj_priv->fence_reg != I915_FENCE_REG_NONE) { | ||
| 1022 | list_move_tail(&obj_priv->fence_list, | ||
| 1023 | &dev_priv->mm.fence_list); | ||
| 1024 | } | ||
| 1025 | |||
| 1015 | /* Silently promote "you're not bound, there was nothing to do" | 1026 | /* Silently promote "you're not bound, there was nothing to do" |
| 1016 | * to success, since the client was just asking us to | 1027 | * to success, since the client was just asking us to |
| 1017 | * make sure everything was done. | 1028 | * make sure everything was done. |
| @@ -1155,8 +1166,7 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | |||
| 1155 | } | 1166 | } |
| 1156 | 1167 | ||
| 1157 | /* Need a new fence register? */ | 1168 | /* Need a new fence register? */ |
| 1158 | if (obj_priv->fence_reg == I915_FENCE_REG_NONE && | 1169 | if (obj_priv->tiling_mode != I915_TILING_NONE) { |
| 1159 | obj_priv->tiling_mode != I915_TILING_NONE) { | ||
| 1160 | ret = i915_gem_object_get_fence_reg(obj); | 1170 | ret = i915_gem_object_get_fence_reg(obj); |
| 1161 | if (ret) { | 1171 | if (ret) { |
| 1162 | mutex_unlock(&dev->struct_mutex); | 1172 | mutex_unlock(&dev->struct_mutex); |
| @@ -2208,6 +2218,12 @@ i915_gem_object_get_fence_reg(struct drm_gem_object *obj) | |||
| 2208 | struct drm_i915_gem_object *old_obj_priv = NULL; | 2218 | struct drm_i915_gem_object *old_obj_priv = NULL; |
| 2209 | int i, ret, avail; | 2219 | int i, ret, avail; |
| 2210 | 2220 | ||
| 2221 | /* Just update our place in the LRU if our fence is getting used. */ | ||
| 2222 | if (obj_priv->fence_reg != I915_FENCE_REG_NONE) { | ||
| 2223 | list_move_tail(&obj_priv->fence_list, &dev_priv->mm.fence_list); | ||
| 2224 | return 0; | ||
| 2225 | } | ||
| 2226 | |||
| 2211 | switch (obj_priv->tiling_mode) { | 2227 | switch (obj_priv->tiling_mode) { |
| 2212 | case I915_TILING_NONE: | 2228 | case I915_TILING_NONE: |
| 2213 | WARN(1, "allocating a fence for non-tiled object?\n"); | 2229 | WARN(1, "allocating a fence for non-tiled object?\n"); |
| @@ -2229,7 +2245,6 @@ i915_gem_object_get_fence_reg(struct drm_gem_object *obj) | |||
| 2229 | } | 2245 | } |
| 2230 | 2246 | ||
| 2231 | /* First try to find a free reg */ | 2247 | /* First try to find a free reg */ |
| 2232 | try_again: | ||
| 2233 | avail = 0; | 2248 | avail = 0; |
| 2234 | for (i = dev_priv->fence_reg_start; i < dev_priv->num_fence_regs; i++) { | 2249 | for (i = dev_priv->fence_reg_start; i < dev_priv->num_fence_regs; i++) { |
| 2235 | reg = &dev_priv->fence_regs[i]; | 2250 | reg = &dev_priv->fence_regs[i]; |
| @@ -2243,52 +2258,41 @@ try_again: | |||
| 2243 | 2258 | ||
| 2244 | /* None available, try to steal one or wait for a user to finish */ | 2259 | /* None available, try to steal one or wait for a user to finish */ |
| 2245 | if (i == dev_priv->num_fence_regs) { | 2260 | if (i == dev_priv->num_fence_regs) { |
| 2246 | uint32_t seqno = dev_priv->mm.next_gem_seqno; | 2261 | struct drm_gem_object *old_obj = NULL; |
| 2247 | 2262 | ||
| 2248 | if (avail == 0) | 2263 | if (avail == 0) |
| 2249 | return -ENOSPC; | 2264 | return -ENOSPC; |
| 2250 | 2265 | ||
| 2251 | for (i = dev_priv->fence_reg_start; | 2266 | list_for_each_entry(old_obj_priv, &dev_priv->mm.fence_list, |
| 2252 | i < dev_priv->num_fence_regs; i++) { | 2267 | fence_list) { |
| 2253 | uint32_t this_seqno; | 2268 | old_obj = old_obj_priv->obj; |
| 2254 | 2269 | ||
| 2255 | reg = &dev_priv->fence_regs[i]; | 2270 | reg = &dev_priv->fence_regs[old_obj_priv->fence_reg]; |
| 2256 | old_obj_priv = reg->obj->driver_private; | ||
| 2257 | 2271 | ||
| 2258 | if (old_obj_priv->pin_count) | 2272 | if (old_obj_priv->pin_count) |
| 2259 | continue; | 2273 | continue; |
| 2260 | 2274 | ||
| 2275 | /* Take a reference, as otherwise the wait_rendering | ||
| 2276 | * below may cause the object to get freed out from | ||
| 2277 | * under us. | ||
| 2278 | */ | ||
| 2279 | drm_gem_object_reference(old_obj); | ||
| 2280 | |||
| 2261 | /* i915 uses fences for GPU access to tiled buffers */ | 2281 | /* i915 uses fences for GPU access to tiled buffers */ |
| 2262 | if (IS_I965G(dev) || !old_obj_priv->active) | 2282 | if (IS_I965G(dev) || !old_obj_priv->active) |
| 2263 | break; | 2283 | break; |
| 2264 | 2284 | ||
| 2265 | /* find the seqno of the first available fence */ | 2285 | /* This brings the object to the head of the LRU if it |
| 2266 | this_seqno = old_obj_priv->last_rendering_seqno; | 2286 | * had been written to. The only way this should |
| 2267 | if (this_seqno != 0 && | 2287 | * result in us waiting longer than the expected |
| 2268 | reg->obj->write_domain == 0 && | 2288 | * optimal amount of time is if there was a |
| 2269 | i915_seqno_passed(seqno, this_seqno)) | 2289 | * fence-using buffer later that was read-only. |
| 2270 | seqno = this_seqno; | 2290 | */ |
| 2271 | } | 2291 | i915_gem_object_flush_gpu_write_domain(old_obj); |
| 2272 | 2292 | ret = i915_gem_object_wait_rendering(old_obj); | |
| 2273 | /* | 2293 | if (ret != 0) |
| 2274 | * Now things get ugly... we have to wait for one of the | ||
| 2275 | * objects to finish before trying again. | ||
| 2276 | */ | ||
| 2277 | if (i == dev_priv->num_fence_regs) { | ||
| 2278 | if (seqno == dev_priv->mm.next_gem_seqno) { | ||
| 2279 | i915_gem_flush(dev, | ||
| 2280 | I915_GEM_GPU_DOMAINS, | ||
| 2281 | I915_GEM_GPU_DOMAINS); | ||
| 2282 | seqno = i915_add_request(dev, NULL, | ||
| 2283 | I915_GEM_GPU_DOMAINS); | ||
| 2284 | if (seqno == 0) | ||
| 2285 | return -ENOMEM; | ||
| 2286 | } | ||
| 2287 | |||
| 2288 | ret = i915_wait_request(dev, seqno); | ||
| 2289 | if (ret) | ||
| 2290 | return ret; | 2294 | return ret; |
| 2291 | goto try_again; | 2295 | break; |
| 2292 | } | 2296 | } |
| 2293 | 2297 | ||
| 2294 | /* | 2298 | /* |
| @@ -2296,10 +2300,15 @@ try_again: | |||
| 2296 | * for this object next time we need it. | 2300 | * for this object next time we need it. |
| 2297 | */ | 2301 | */ |
| 2298 | i915_gem_release_mmap(reg->obj); | 2302 | i915_gem_release_mmap(reg->obj); |
| 2303 | i = old_obj_priv->fence_reg; | ||
| 2299 | old_obj_priv->fence_reg = I915_FENCE_REG_NONE; | 2304 | old_obj_priv->fence_reg = I915_FENCE_REG_NONE; |
| 2305 | list_del_init(&old_obj_priv->fence_list); | ||
| 2306 | drm_gem_object_unreference(old_obj); | ||
| 2300 | } | 2307 | } |
| 2301 | 2308 | ||
| 2302 | obj_priv->fence_reg = i; | 2309 | obj_priv->fence_reg = i; |
| 2310 | list_add_tail(&obj_priv->fence_list, &dev_priv->mm.fence_list); | ||
| 2311 | |||
| 2303 | reg->obj = obj; | 2312 | reg->obj = obj; |
| 2304 | 2313 | ||
| 2305 | if (IS_I965G(dev)) | 2314 | if (IS_I965G(dev)) |
| @@ -2342,6 +2351,7 @@ i915_gem_clear_fence_reg(struct drm_gem_object *obj) | |||
| 2342 | 2351 | ||
| 2343 | dev_priv->fence_regs[obj_priv->fence_reg].obj = NULL; | 2352 | dev_priv->fence_regs[obj_priv->fence_reg].obj = NULL; |
| 2344 | obj_priv->fence_reg = I915_FENCE_REG_NONE; | 2353 | obj_priv->fence_reg = I915_FENCE_REG_NONE; |
| 2354 | list_del_init(&obj_priv->fence_list); | ||
| 2345 | } | 2355 | } |
| 2346 | 2356 | ||
| 2347 | /** | 2357 | /** |
| @@ -3595,9 +3605,7 @@ i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment) | |||
| 3595 | * Pre-965 chips need a fence register set up in order to | 3605 | * Pre-965 chips need a fence register set up in order to |
| 3596 | * properly handle tiled surfaces. | 3606 | * properly handle tiled surfaces. |
| 3597 | */ | 3607 | */ |
| 3598 | if (!IS_I965G(dev) && | 3608 | if (!IS_I965G(dev) && obj_priv->tiling_mode != I915_TILING_NONE) { |
| 3599 | obj_priv->fence_reg == I915_FENCE_REG_NONE && | ||
| 3600 | obj_priv->tiling_mode != I915_TILING_NONE) { | ||
| 3601 | ret = i915_gem_object_get_fence_reg(obj); | 3609 | ret = i915_gem_object_get_fence_reg(obj); |
| 3602 | if (ret != 0) { | 3610 | if (ret != 0) { |
| 3603 | if (ret != -EBUSY && ret != -ERESTARTSYS) | 3611 | if (ret != -EBUSY && ret != -ERESTARTSYS) |
| @@ -3806,6 +3814,7 @@ int i915_gem_init_object(struct drm_gem_object *obj) | |||
| 3806 | obj_priv->obj = obj; | 3814 | obj_priv->obj = obj; |
| 3807 | obj_priv->fence_reg = I915_FENCE_REG_NONE; | 3815 | obj_priv->fence_reg = I915_FENCE_REG_NONE; |
| 3808 | INIT_LIST_HEAD(&obj_priv->list); | 3816 | INIT_LIST_HEAD(&obj_priv->list); |
| 3817 | INIT_LIST_HEAD(&obj_priv->fence_list); | ||
| 3809 | 3818 | ||
| 3810 | return 0; | 3819 | return 0; |
| 3811 | } | 3820 | } |
| @@ -4253,6 +4262,7 @@ i915_gem_load(struct drm_device *dev) | |||
| 4253 | INIT_LIST_HEAD(&dev_priv->mm.flushing_list); | 4262 | INIT_LIST_HEAD(&dev_priv->mm.flushing_list); |
| 4254 | INIT_LIST_HEAD(&dev_priv->mm.inactive_list); | 4263 | INIT_LIST_HEAD(&dev_priv->mm.inactive_list); |
| 4255 | INIT_LIST_HEAD(&dev_priv->mm.request_list); | 4264 | INIT_LIST_HEAD(&dev_priv->mm.request_list); |
| 4265 | INIT_LIST_HEAD(&dev_priv->mm.fence_list); | ||
| 4256 | INIT_DELAYED_WORK(&dev_priv->mm.retire_work, | 4266 | INIT_DELAYED_WORK(&dev_priv->mm.retire_work, |
| 4257 | i915_gem_retire_work_handler); | 4267 | i915_gem_retire_work_handler); |
| 4258 | dev_priv->mm.next_gem_seqno = 1; | 4268 | dev_priv->mm.next_gem_seqno = 1; |
