diff options
| author | Daniel Vetter <daniel.vetter@ffwll.ch> | 2010-02-19 05:51:58 -0500 |
|---|---|---|
| committer | Eric Anholt <eric@anholt.net> | 2010-02-26 16:23:21 -0500 |
| commit | ae3db24aab398fb5f985696c12362eb12ef65812 (patch) | |
| tree | 6c8c552805855cc42ec9d18773dc026424a0fa9f | |
| parent | 4a87b8ca2185199c5d1b37b570efffd2e46fe813 (diff) | |
drm/i915: extract fence stealing code
The spaghetti logic in there tripped up my brain's code parser for a
few secs. Prevent this from happening again by extracting the fence
stealing code into a seperate functions. IMHO this slightly clears up
the code flow.
v2: Beautified according to ickle's comments.
v3: ickle forgot to flush his comment queue ... Now there's also a
we-are-paranoid BUG_ON in there.
v4: I've forgotten to switch on my brain when doing v3. Now the BUG_ON
actually checks something useful.
v5: Clean up a stale comment as noted by Eric Anholt.
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Eric Anholt <eric@anholt.net>
| -rw-r--r-- | drivers/gpu/drm/i915/i915_gem.c | 107 |
1 files changed, 60 insertions, 47 deletions
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index e6b85cdbc60f..ce1c0262bc63 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c | |||
| @@ -2382,6 +2382,58 @@ static void i830_write_fence_reg(struct drm_i915_fence_reg *reg) | |||
| 2382 | I915_WRITE(FENCE_REG_830_0 + (regnum * 4), val); | 2382 | I915_WRITE(FENCE_REG_830_0 + (regnum * 4), val); |
| 2383 | } | 2383 | } |
| 2384 | 2384 | ||
| 2385 | static int i915_find_fence_reg(struct drm_device *dev) | ||
| 2386 | { | ||
| 2387 | struct drm_i915_fence_reg *reg = NULL; | ||
| 2388 | struct drm_i915_gem_object *obj_priv = NULL; | ||
| 2389 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
| 2390 | struct drm_gem_object *obj = NULL; | ||
| 2391 | int i, avail, ret; | ||
| 2392 | |||
| 2393 | /* First try to find a free reg */ | ||
| 2394 | avail = 0; | ||
| 2395 | for (i = dev_priv->fence_reg_start; i < dev_priv->num_fence_regs; i++) { | ||
| 2396 | reg = &dev_priv->fence_regs[i]; | ||
| 2397 | if (!reg->obj) | ||
| 2398 | return i; | ||
| 2399 | |||
| 2400 | obj_priv = reg->obj->driver_private; | ||
| 2401 | if (!obj_priv->pin_count) | ||
| 2402 | avail++; | ||
| 2403 | } | ||
| 2404 | |||
| 2405 | if (avail == 0) | ||
| 2406 | return -ENOSPC; | ||
| 2407 | |||
| 2408 | /* None available, try to steal one or wait for a user to finish */ | ||
| 2409 | i = I915_FENCE_REG_NONE; | ||
| 2410 | list_for_each_entry(obj_priv, &dev_priv->mm.fence_list, | ||
| 2411 | fence_list) { | ||
| 2412 | obj = obj_priv->obj; | ||
| 2413 | |||
| 2414 | if (obj_priv->pin_count) | ||
| 2415 | continue; | ||
| 2416 | |||
| 2417 | /* found one! */ | ||
| 2418 | i = obj_priv->fence_reg; | ||
| 2419 | break; | ||
| 2420 | } | ||
| 2421 | |||
| 2422 | BUG_ON(i == I915_FENCE_REG_NONE); | ||
| 2423 | |||
| 2424 | /* We only have a reference on obj from the active list. put_fence_reg | ||
| 2425 | * might drop that one, causing a use-after-free in it. So hold a | ||
| 2426 | * private reference to obj like the other callers of put_fence_reg | ||
| 2427 | * (set_tiling ioctl) do. */ | ||
| 2428 | drm_gem_object_reference(obj); | ||
| 2429 | ret = i915_gem_object_put_fence_reg(obj); | ||
| 2430 | drm_gem_object_unreference(obj); | ||
| 2431 | if (ret != 0) | ||
| 2432 | return ret; | ||
| 2433 | |||
| 2434 | return i; | ||
| 2435 | } | ||
| 2436 | |||
| 2385 | /** | 2437 | /** |
| 2386 | * i915_gem_object_get_fence_reg - set up a fence reg for an object | 2438 | * i915_gem_object_get_fence_reg - set up a fence reg for an object |
| 2387 | * @obj: object to map through a fence reg | 2439 | * @obj: object to map through a fence reg |
| @@ -2402,8 +2454,7 @@ i915_gem_object_get_fence_reg(struct drm_gem_object *obj) | |||
| 2402 | struct drm_i915_private *dev_priv = dev->dev_private; | 2454 | struct drm_i915_private *dev_priv = dev->dev_private; |
| 2403 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | 2455 | struct drm_i915_gem_object *obj_priv = obj->driver_private; |
| 2404 | struct drm_i915_fence_reg *reg = NULL; | 2456 | struct drm_i915_fence_reg *reg = NULL; |
| 2405 | struct drm_i915_gem_object *old_obj_priv = NULL; | 2457 | int ret; |
| 2406 | int i, ret, avail; | ||
| 2407 | 2458 | ||
| 2408 | /* Just update our place in the LRU if our fence is getting used. */ | 2459 | /* Just update our place in the LRU if our fence is getting used. */ |
| 2409 | if (obj_priv->fence_reg != I915_FENCE_REG_NONE) { | 2460 | if (obj_priv->fence_reg != I915_FENCE_REG_NONE) { |
| @@ -2431,51 +2482,12 @@ i915_gem_object_get_fence_reg(struct drm_gem_object *obj) | |||
| 2431 | break; | 2482 | break; |
| 2432 | } | 2483 | } |
| 2433 | 2484 | ||
| 2434 | /* First try to find a free reg */ | 2485 | ret = i915_find_fence_reg(dev); |
| 2435 | avail = 0; | 2486 | if (ret < 0) |
| 2436 | for (i = dev_priv->fence_reg_start; i < dev_priv->num_fence_regs; i++) { | 2487 | return ret; |
| 2437 | reg = &dev_priv->fence_regs[i]; | ||
| 2438 | if (!reg->obj) | ||
| 2439 | break; | ||
| 2440 | |||
| 2441 | old_obj_priv = reg->obj->driver_private; | ||
| 2442 | if (!old_obj_priv->pin_count) | ||
| 2443 | avail++; | ||
| 2444 | } | ||
| 2445 | |||
| 2446 | /* None available, try to steal one or wait for a user to finish */ | ||
| 2447 | if (i == dev_priv->num_fence_regs) { | ||
| 2448 | struct drm_gem_object *old_obj = NULL; | ||
| 2449 | |||
| 2450 | if (avail == 0) | ||
| 2451 | return -ENOSPC; | ||
| 2452 | |||
| 2453 | list_for_each_entry(old_obj_priv, &dev_priv->mm.fence_list, | ||
| 2454 | fence_list) { | ||
| 2455 | old_obj = old_obj_priv->obj; | ||
| 2456 | |||
| 2457 | if (old_obj_priv->pin_count) | ||
| 2458 | continue; | ||
| 2459 | |||
| 2460 | /* Take a reference, as otherwise the wait_rendering | ||
| 2461 | * below may cause the object to get freed out from | ||
| 2462 | * under us. | ||
| 2463 | */ | ||
| 2464 | drm_gem_object_reference(old_obj); | ||
| 2465 | |||
| 2466 | break; | ||
| 2467 | } | ||
| 2468 | |||
| 2469 | i = old_obj_priv->fence_reg; | ||
| 2470 | reg = &dev_priv->fence_regs[i]; | ||
| 2471 | |||
| 2472 | ret = i915_gem_object_put_fence_reg(old_obj); | ||
| 2473 | drm_gem_object_unreference(old_obj); | ||
| 2474 | if (ret != 0) | ||
| 2475 | return ret; | ||
| 2476 | } | ||
| 2477 | 2488 | ||
| 2478 | obj_priv->fence_reg = i; | 2489 | obj_priv->fence_reg = ret; |
| 2490 | reg = &dev_priv->fence_regs[obj_priv->fence_reg]; | ||
| 2479 | list_add_tail(&obj_priv->fence_list, &dev_priv->mm.fence_list); | 2491 | list_add_tail(&obj_priv->fence_list, &dev_priv->mm.fence_list); |
| 2480 | 2492 | ||
| 2481 | reg->obj = obj; | 2493 | reg->obj = obj; |
| @@ -2489,7 +2501,8 @@ i915_gem_object_get_fence_reg(struct drm_gem_object *obj) | |||
| 2489 | else | 2501 | else |
| 2490 | i830_write_fence_reg(reg); | 2502 | i830_write_fence_reg(reg); |
| 2491 | 2503 | ||
| 2492 | trace_i915_gem_object_get_fence(obj, i, obj_priv->tiling_mode); | 2504 | trace_i915_gem_object_get_fence(obj, obj_priv->fence_reg, |
| 2505 | obj_priv->tiling_mode); | ||
| 2493 | 2506 | ||
| 2494 | return 0; | 2507 | return 0; |
| 2495 | } | 2508 | } |
