diff options
Diffstat (limited to 'drivers/gpu/drm/i915/i915_gem.c')
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem.c | 430 |
1 files changed, 208 insertions, 222 deletions
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index ec8a0d7ffa39..fba37e9f775d 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c | |||
@@ -128,9 +128,7 @@ i915_gem_create_ioctl(struct drm_device *dev, void *data, | |||
128 | return -ENOMEM; | 128 | return -ENOMEM; |
129 | 129 | ||
130 | ret = drm_gem_handle_create(file_priv, obj, &handle); | 130 | ret = drm_gem_handle_create(file_priv, obj, &handle); |
131 | mutex_lock(&dev->struct_mutex); | 131 | drm_gem_object_handle_unreference_unlocked(obj); |
132 | drm_gem_object_handle_unreference(obj); | ||
133 | mutex_unlock(&dev->struct_mutex); | ||
134 | 132 | ||
135 | if (ret) | 133 | if (ret) |
136 | return ret; | 134 | return ret; |
@@ -488,7 +486,7 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data, | |||
488 | */ | 486 | */ |
489 | if (args->offset > obj->size || args->size > obj->size || | 487 | if (args->offset > obj->size || args->size > obj->size || |
490 | args->offset + args->size > obj->size) { | 488 | args->offset + args->size > obj->size) { |
491 | drm_gem_object_unreference(obj); | 489 | drm_gem_object_unreference_unlocked(obj); |
492 | return -EINVAL; | 490 | return -EINVAL; |
493 | } | 491 | } |
494 | 492 | ||
@@ -501,7 +499,7 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data, | |||
501 | file_priv); | 499 | file_priv); |
502 | } | 500 | } |
503 | 501 | ||
504 | drm_gem_object_unreference(obj); | 502 | drm_gem_object_unreference_unlocked(obj); |
505 | 503 | ||
506 | return ret; | 504 | return ret; |
507 | } | 505 | } |
@@ -961,7 +959,7 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, | |||
961 | */ | 959 | */ |
962 | if (args->offset > obj->size || args->size > obj->size || | 960 | if (args->offset > obj->size || args->size > obj->size || |
963 | args->offset + args->size > obj->size) { | 961 | args->offset + args->size > obj->size) { |
964 | drm_gem_object_unreference(obj); | 962 | drm_gem_object_unreference_unlocked(obj); |
965 | return -EINVAL; | 963 | return -EINVAL; |
966 | } | 964 | } |
967 | 965 | ||
@@ -995,7 +993,7 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, | |||
995 | DRM_INFO("pwrite failed %d\n", ret); | 993 | DRM_INFO("pwrite failed %d\n", ret); |
996 | #endif | 994 | #endif |
997 | 995 | ||
998 | drm_gem_object_unreference(obj); | 996 | drm_gem_object_unreference_unlocked(obj); |
999 | 997 | ||
1000 | return ret; | 998 | return ret; |
1001 | } | 999 | } |
@@ -1138,9 +1136,7 @@ i915_gem_mmap_ioctl(struct drm_device *dev, void *data, | |||
1138 | PROT_READ | PROT_WRITE, MAP_SHARED, | 1136 | PROT_READ | PROT_WRITE, MAP_SHARED, |
1139 | args->offset); | 1137 | args->offset); |
1140 | up_write(¤t->mm->mmap_sem); | 1138 | up_write(¤t->mm->mmap_sem); |
1141 | mutex_lock(&dev->struct_mutex); | 1139 | drm_gem_object_unreference_unlocked(obj); |
1142 | drm_gem_object_unreference(obj); | ||
1143 | mutex_unlock(&dev->struct_mutex); | ||
1144 | if (IS_ERR((void *)addr)) | 1140 | if (IS_ERR((void *)addr)) |
1145 | return addr; | 1141 | return addr; |
1146 | 1142 | ||
@@ -1562,6 +1558,38 @@ i915_gem_object_move_to_inactive(struct drm_gem_object *obj) | |||
1562 | i915_verify_inactive(dev, __FILE__, __LINE__); | 1558 | i915_verify_inactive(dev, __FILE__, __LINE__); |
1563 | } | 1559 | } |
1564 | 1560 | ||
1561 | static void | ||
1562 | i915_gem_process_flushing_list(struct drm_device *dev, | ||
1563 | uint32_t flush_domains, uint32_t seqno) | ||
1564 | { | ||
1565 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
1566 | struct drm_i915_gem_object *obj_priv, *next; | ||
1567 | |||
1568 | list_for_each_entry_safe(obj_priv, next, | ||
1569 | &dev_priv->mm.gpu_write_list, | ||
1570 | gpu_write_list) { | ||
1571 | struct drm_gem_object *obj = obj_priv->obj; | ||
1572 | |||
1573 | if ((obj->write_domain & flush_domains) == | ||
1574 | obj->write_domain) { | ||
1575 | uint32_t old_write_domain = obj->write_domain; | ||
1576 | |||
1577 | obj->write_domain = 0; | ||
1578 | list_del_init(&obj_priv->gpu_write_list); | ||
1579 | i915_gem_object_move_to_active(obj, seqno); | ||
1580 | |||
1581 | /* update the fence lru list */ | ||
1582 | if (obj_priv->fence_reg != I915_FENCE_REG_NONE) | ||
1583 | list_move_tail(&obj_priv->fence_list, | ||
1584 | &dev_priv->mm.fence_list); | ||
1585 | |||
1586 | trace_i915_gem_object_change_domain(obj, | ||
1587 | obj->read_domains, | ||
1588 | old_write_domain); | ||
1589 | } | ||
1590 | } | ||
1591 | } | ||
1592 | |||
1565 | /** | 1593 | /** |
1566 | * Creates a new sequence number, emitting a write of it to the status page | 1594 | * Creates a new sequence number, emitting a write of it to the status page |
1567 | * plus an interrupt, which will trigger i915_user_interrupt_handler. | 1595 | * plus an interrupt, which will trigger i915_user_interrupt_handler. |
@@ -1620,29 +1648,8 @@ i915_add_request(struct drm_device *dev, struct drm_file *file_priv, | |||
1620 | /* Associate any objects on the flushing list matching the write | 1648 | /* Associate any objects on the flushing list matching the write |
1621 | * domain we're flushing with our flush. | 1649 | * domain we're flushing with our flush. |
1622 | */ | 1650 | */ |
1623 | if (flush_domains != 0) { | 1651 | if (flush_domains != 0) |
1624 | struct drm_i915_gem_object *obj_priv, *next; | 1652 | i915_gem_process_flushing_list(dev, flush_domains, seqno); |
1625 | |||
1626 | list_for_each_entry_safe(obj_priv, next, | ||
1627 | &dev_priv->mm.gpu_write_list, | ||
1628 | gpu_write_list) { | ||
1629 | struct drm_gem_object *obj = obj_priv->obj; | ||
1630 | |||
1631 | if ((obj->write_domain & flush_domains) == | ||
1632 | obj->write_domain) { | ||
1633 | uint32_t old_write_domain = obj->write_domain; | ||
1634 | |||
1635 | obj->write_domain = 0; | ||
1636 | list_del_init(&obj_priv->gpu_write_list); | ||
1637 | i915_gem_object_move_to_active(obj, seqno); | ||
1638 | |||
1639 | trace_i915_gem_object_change_domain(obj, | ||
1640 | obj->read_domains, | ||
1641 | old_write_domain); | ||
1642 | } | ||
1643 | } | ||
1644 | |||
1645 | } | ||
1646 | 1653 | ||
1647 | if (!dev_priv->mm.suspended) { | 1654 | if (!dev_priv->mm.suspended) { |
1648 | mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD); | 1655 | mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD); |
@@ -1822,7 +1829,7 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno, int interruptible) | |||
1822 | return -EIO; | 1829 | return -EIO; |
1823 | 1830 | ||
1824 | if (!i915_seqno_passed(i915_get_gem_seqno(dev), seqno)) { | 1831 | if (!i915_seqno_passed(i915_get_gem_seqno(dev), seqno)) { |
1825 | if (IS_IRONLAKE(dev)) | 1832 | if (HAS_PCH_SPLIT(dev)) |
1826 | ier = I915_READ(DEIER) | I915_READ(GTIER); | 1833 | ier = I915_READ(DEIER) | I915_READ(GTIER); |
1827 | else | 1834 | else |
1828 | ier = I915_READ(IER); | 1835 | ier = I915_READ(IER); |
@@ -1991,6 +1998,7 @@ int | |||
1991 | i915_gem_object_unbind(struct drm_gem_object *obj) | 1998 | i915_gem_object_unbind(struct drm_gem_object *obj) |
1992 | { | 1999 | { |
1993 | struct drm_device *dev = obj->dev; | 2000 | struct drm_device *dev = obj->dev; |
2001 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
1994 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | 2002 | struct drm_i915_gem_object *obj_priv = obj->driver_private; |
1995 | int ret = 0; | 2003 | int ret = 0; |
1996 | 2004 | ||
@@ -2046,8 +2054,10 @@ i915_gem_object_unbind(struct drm_gem_object *obj) | |||
2046 | } | 2054 | } |
2047 | 2055 | ||
2048 | /* Remove ourselves from the LRU list if present. */ | 2056 | /* Remove ourselves from the LRU list if present. */ |
2057 | spin_lock(&dev_priv->mm.active_list_lock); | ||
2049 | if (!list_empty(&obj_priv->list)) | 2058 | if (!list_empty(&obj_priv->list)) |
2050 | list_del_init(&obj_priv->list); | 2059 | list_del_init(&obj_priv->list); |
2060 | spin_unlock(&dev_priv->mm.active_list_lock); | ||
2051 | 2061 | ||
2052 | if (i915_gem_object_is_purgeable(obj_priv)) | 2062 | if (i915_gem_object_is_purgeable(obj_priv)) |
2053 | i915_gem_object_truncate(obj); | 2063 | i915_gem_object_truncate(obj); |
@@ -2085,11 +2095,34 @@ i915_gem_find_inactive_object(struct drm_device *dev, int min_size) | |||
2085 | } | 2095 | } |
2086 | 2096 | ||
2087 | static int | 2097 | static int |
2098 | i915_gpu_idle(struct drm_device *dev) | ||
2099 | { | ||
2100 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
2101 | bool lists_empty; | ||
2102 | uint32_t seqno; | ||
2103 | |||
2104 | spin_lock(&dev_priv->mm.active_list_lock); | ||
2105 | lists_empty = list_empty(&dev_priv->mm.flushing_list) && | ||
2106 | list_empty(&dev_priv->mm.active_list); | ||
2107 | spin_unlock(&dev_priv->mm.active_list_lock); | ||
2108 | |||
2109 | if (lists_empty) | ||
2110 | return 0; | ||
2111 | |||
2112 | /* Flush everything onto the inactive list. */ | ||
2113 | i915_gem_flush(dev, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS); | ||
2114 | seqno = i915_add_request(dev, NULL, I915_GEM_GPU_DOMAINS); | ||
2115 | if (seqno == 0) | ||
2116 | return -ENOMEM; | ||
2117 | |||
2118 | return i915_wait_request(dev, seqno); | ||
2119 | } | ||
2120 | |||
2121 | static int | ||
2088 | i915_gem_evict_everything(struct drm_device *dev) | 2122 | i915_gem_evict_everything(struct drm_device *dev) |
2089 | { | 2123 | { |
2090 | drm_i915_private_t *dev_priv = dev->dev_private; | 2124 | drm_i915_private_t *dev_priv = dev->dev_private; |
2091 | int ret; | 2125 | int ret; |
2092 | uint32_t seqno; | ||
2093 | bool lists_empty; | 2126 | bool lists_empty; |
2094 | 2127 | ||
2095 | spin_lock(&dev_priv->mm.active_list_lock); | 2128 | spin_lock(&dev_priv->mm.active_list_lock); |
@@ -2102,12 +2135,7 @@ i915_gem_evict_everything(struct drm_device *dev) | |||
2102 | return -ENOSPC; | 2135 | return -ENOSPC; |
2103 | 2136 | ||
2104 | /* Flush everything (on to the inactive lists) and evict */ | 2137 | /* Flush everything (on to the inactive lists) and evict */ |
2105 | i915_gem_flush(dev, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS); | 2138 | ret = i915_gpu_idle(dev); |
2106 | seqno = i915_add_request(dev, NULL, I915_GEM_GPU_DOMAINS); | ||
2107 | if (seqno == 0) | ||
2108 | return -ENOMEM; | ||
2109 | |||
2110 | ret = i915_wait_request(dev, seqno); | ||
2111 | if (ret) | 2139 | if (ret) |
2112 | return ret; | 2140 | return ret; |
2113 | 2141 | ||
@@ -2265,6 +2293,28 @@ i915_gem_object_get_pages(struct drm_gem_object *obj, | |||
2265 | return 0; | 2293 | return 0; |
2266 | } | 2294 | } |
2267 | 2295 | ||
2296 | static void sandybridge_write_fence_reg(struct drm_i915_fence_reg *reg) | ||
2297 | { | ||
2298 | struct drm_gem_object *obj = reg->obj; | ||
2299 | struct drm_device *dev = obj->dev; | ||
2300 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
2301 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | ||
2302 | int regnum = obj_priv->fence_reg; | ||
2303 | uint64_t val; | ||
2304 | |||
2305 | val = (uint64_t)((obj_priv->gtt_offset + obj->size - 4096) & | ||
2306 | 0xfffff000) << 32; | ||
2307 | val |= obj_priv->gtt_offset & 0xfffff000; | ||
2308 | val |= (uint64_t)((obj_priv->stride / 128) - 1) << | ||
2309 | SANDYBRIDGE_FENCE_PITCH_SHIFT; | ||
2310 | |||
2311 | if (obj_priv->tiling_mode == I915_TILING_Y) | ||
2312 | val |= 1 << I965_FENCE_TILING_Y_SHIFT; | ||
2313 | val |= I965_FENCE_REG_VALID; | ||
2314 | |||
2315 | I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + (regnum * 8), val); | ||
2316 | } | ||
2317 | |||
2268 | static void i965_write_fence_reg(struct drm_i915_fence_reg *reg) | 2318 | static void i965_write_fence_reg(struct drm_i915_fence_reg *reg) |
2269 | { | 2319 | { |
2270 | struct drm_gem_object *obj = reg->obj; | 2320 | struct drm_gem_object *obj = reg->obj; |
@@ -2361,6 +2411,58 @@ static void i830_write_fence_reg(struct drm_i915_fence_reg *reg) | |||
2361 | I915_WRITE(FENCE_REG_830_0 + (regnum * 4), val); | 2411 | I915_WRITE(FENCE_REG_830_0 + (regnum * 4), val); |
2362 | } | 2412 | } |
2363 | 2413 | ||
2414 | static int i915_find_fence_reg(struct drm_device *dev) | ||
2415 | { | ||
2416 | struct drm_i915_fence_reg *reg = NULL; | ||
2417 | struct drm_i915_gem_object *obj_priv = NULL; | ||
2418 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
2419 | struct drm_gem_object *obj = NULL; | ||
2420 | int i, avail, ret; | ||
2421 | |||
2422 | /* First try to find a free reg */ | ||
2423 | avail = 0; | ||
2424 | for (i = dev_priv->fence_reg_start; i < dev_priv->num_fence_regs; i++) { | ||
2425 | reg = &dev_priv->fence_regs[i]; | ||
2426 | if (!reg->obj) | ||
2427 | return i; | ||
2428 | |||
2429 | obj_priv = reg->obj->driver_private; | ||
2430 | if (!obj_priv->pin_count) | ||
2431 | avail++; | ||
2432 | } | ||
2433 | |||
2434 | if (avail == 0) | ||
2435 | return -ENOSPC; | ||
2436 | |||
2437 | /* None available, try to steal one or wait for a user to finish */ | ||
2438 | i = I915_FENCE_REG_NONE; | ||
2439 | list_for_each_entry(obj_priv, &dev_priv->mm.fence_list, | ||
2440 | fence_list) { | ||
2441 | obj = obj_priv->obj; | ||
2442 | |||
2443 | if (obj_priv->pin_count) | ||
2444 | continue; | ||
2445 | |||
2446 | /* found one! */ | ||
2447 | i = obj_priv->fence_reg; | ||
2448 | break; | ||
2449 | } | ||
2450 | |||
2451 | BUG_ON(i == I915_FENCE_REG_NONE); | ||
2452 | |||
2453 | /* We only have a reference on obj from the active list. put_fence_reg | ||
2454 | * might drop that one, causing a use-after-free in it. So hold a | ||
2455 | * private reference to obj like the other callers of put_fence_reg | ||
2456 | * (set_tiling ioctl) do. */ | ||
2457 | drm_gem_object_reference(obj); | ||
2458 | ret = i915_gem_object_put_fence_reg(obj); | ||
2459 | drm_gem_object_unreference(obj); | ||
2460 | if (ret != 0) | ||
2461 | return ret; | ||
2462 | |||
2463 | return i; | ||
2464 | } | ||
2465 | |||
2364 | /** | 2466 | /** |
2365 | * i915_gem_object_get_fence_reg - set up a fence reg for an object | 2467 | * i915_gem_object_get_fence_reg - set up a fence reg for an object |
2366 | * @obj: object to map through a fence reg | 2468 | * @obj: object to map through a fence reg |
@@ -2381,8 +2483,7 @@ i915_gem_object_get_fence_reg(struct drm_gem_object *obj) | |||
2381 | struct drm_i915_private *dev_priv = dev->dev_private; | 2483 | struct drm_i915_private *dev_priv = dev->dev_private; |
2382 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | 2484 | struct drm_i915_gem_object *obj_priv = obj->driver_private; |
2383 | struct drm_i915_fence_reg *reg = NULL; | 2485 | struct drm_i915_fence_reg *reg = NULL; |
2384 | struct drm_i915_gem_object *old_obj_priv = NULL; | 2486 | int ret; |
2385 | int i, ret, avail; | ||
2386 | 2487 | ||
2387 | /* Just update our place in the LRU if our fence is getting used. */ | 2488 | /* Just update our place in the LRU if our fence is getting used. */ |
2388 | if (obj_priv->fence_reg != I915_FENCE_REG_NONE) { | 2489 | if (obj_priv->fence_reg != I915_FENCE_REG_NONE) { |
@@ -2410,86 +2511,27 @@ i915_gem_object_get_fence_reg(struct drm_gem_object *obj) | |||
2410 | break; | 2511 | break; |
2411 | } | 2512 | } |
2412 | 2513 | ||
2413 | /* First try to find a free reg */ | 2514 | ret = i915_find_fence_reg(dev); |
2414 | avail = 0; | 2515 | if (ret < 0) |
2415 | for (i = dev_priv->fence_reg_start; i < dev_priv->num_fence_regs; i++) { | 2516 | return ret; |
2416 | reg = &dev_priv->fence_regs[i]; | ||
2417 | if (!reg->obj) | ||
2418 | break; | ||
2419 | |||
2420 | old_obj_priv = reg->obj->driver_private; | ||
2421 | if (!old_obj_priv->pin_count) | ||
2422 | avail++; | ||
2423 | } | ||
2424 | |||
2425 | /* None available, try to steal one or wait for a user to finish */ | ||
2426 | if (i == dev_priv->num_fence_regs) { | ||
2427 | struct drm_gem_object *old_obj = NULL; | ||
2428 | |||
2429 | if (avail == 0) | ||
2430 | return -ENOSPC; | ||
2431 | |||
2432 | list_for_each_entry(old_obj_priv, &dev_priv->mm.fence_list, | ||
2433 | fence_list) { | ||
2434 | old_obj = old_obj_priv->obj; | ||
2435 | |||
2436 | if (old_obj_priv->pin_count) | ||
2437 | continue; | ||
2438 | |||
2439 | /* Take a reference, as otherwise the wait_rendering | ||
2440 | * below may cause the object to get freed out from | ||
2441 | * under us. | ||
2442 | */ | ||
2443 | drm_gem_object_reference(old_obj); | ||
2444 | |||
2445 | /* i915 uses fences for GPU access to tiled buffers */ | ||
2446 | if (IS_I965G(dev) || !old_obj_priv->active) | ||
2447 | break; | ||
2448 | |||
2449 | /* This brings the object to the head of the LRU if it | ||
2450 | * had been written to. The only way this should | ||
2451 | * result in us waiting longer than the expected | ||
2452 | * optimal amount of time is if there was a | ||
2453 | * fence-using buffer later that was read-only. | ||
2454 | */ | ||
2455 | i915_gem_object_flush_gpu_write_domain(old_obj); | ||
2456 | ret = i915_gem_object_wait_rendering(old_obj); | ||
2457 | if (ret != 0) { | ||
2458 | drm_gem_object_unreference(old_obj); | ||
2459 | return ret; | ||
2460 | } | ||
2461 | |||
2462 | break; | ||
2463 | } | ||
2464 | |||
2465 | /* | ||
2466 | * Zap this virtual mapping so we can set up a fence again | ||
2467 | * for this object next time we need it. | ||
2468 | */ | ||
2469 | i915_gem_release_mmap(old_obj); | ||
2470 | |||
2471 | i = old_obj_priv->fence_reg; | ||
2472 | reg = &dev_priv->fence_regs[i]; | ||
2473 | |||
2474 | old_obj_priv->fence_reg = I915_FENCE_REG_NONE; | ||
2475 | list_del_init(&old_obj_priv->fence_list); | ||
2476 | |||
2477 | drm_gem_object_unreference(old_obj); | ||
2478 | } | ||
2479 | 2517 | ||
2480 | obj_priv->fence_reg = i; | 2518 | obj_priv->fence_reg = ret; |
2519 | reg = &dev_priv->fence_regs[obj_priv->fence_reg]; | ||
2481 | list_add_tail(&obj_priv->fence_list, &dev_priv->mm.fence_list); | 2520 | list_add_tail(&obj_priv->fence_list, &dev_priv->mm.fence_list); |
2482 | 2521 | ||
2483 | reg->obj = obj; | 2522 | reg->obj = obj; |
2484 | 2523 | ||
2485 | if (IS_I965G(dev)) | 2524 | if (IS_GEN6(dev)) |
2525 | sandybridge_write_fence_reg(reg); | ||
2526 | else if (IS_I965G(dev)) | ||
2486 | i965_write_fence_reg(reg); | 2527 | i965_write_fence_reg(reg); |
2487 | else if (IS_I9XX(dev)) | 2528 | else if (IS_I9XX(dev)) |
2488 | i915_write_fence_reg(reg); | 2529 | i915_write_fence_reg(reg); |
2489 | else | 2530 | else |
2490 | i830_write_fence_reg(reg); | 2531 | i830_write_fence_reg(reg); |
2491 | 2532 | ||
2492 | trace_i915_gem_object_get_fence(obj, i, obj_priv->tiling_mode); | 2533 | trace_i915_gem_object_get_fence(obj, obj_priv->fence_reg, |
2534 | obj_priv->tiling_mode); | ||
2493 | 2535 | ||
2494 | return 0; | 2536 | return 0; |
2495 | } | 2537 | } |
@@ -2508,9 +2550,12 @@ i915_gem_clear_fence_reg(struct drm_gem_object *obj) | |||
2508 | drm_i915_private_t *dev_priv = dev->dev_private; | 2550 | drm_i915_private_t *dev_priv = dev->dev_private; |
2509 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | 2551 | struct drm_i915_gem_object *obj_priv = obj->driver_private; |
2510 | 2552 | ||
2511 | if (IS_I965G(dev)) | 2553 | if (IS_GEN6(dev)) { |
2554 | I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + | ||
2555 | (obj_priv->fence_reg * 8), 0); | ||
2556 | } else if (IS_I965G(dev)) { | ||
2512 | I915_WRITE64(FENCE_REG_965_0 + (obj_priv->fence_reg * 8), 0); | 2557 | I915_WRITE64(FENCE_REG_965_0 + (obj_priv->fence_reg * 8), 0); |
2513 | else { | 2558 | } else { |
2514 | uint32_t fence_reg; | 2559 | uint32_t fence_reg; |
2515 | 2560 | ||
2516 | if (obj_priv->fence_reg < 8) | 2561 | if (obj_priv->fence_reg < 8) |
@@ -2544,6 +2589,12 @@ i915_gem_object_put_fence_reg(struct drm_gem_object *obj) | |||
2544 | if (obj_priv->fence_reg == I915_FENCE_REG_NONE) | 2589 | if (obj_priv->fence_reg == I915_FENCE_REG_NONE) |
2545 | return 0; | 2590 | return 0; |
2546 | 2591 | ||
2592 | /* If we've changed tiling, GTT-mappings of the object | ||
2593 | * need to re-fault to ensure that the correct fence register | ||
2594 | * setup is in place. | ||
2595 | */ | ||
2596 | i915_gem_release_mmap(obj); | ||
2597 | |||
2547 | /* On the i915, GPU access to tiled buffers is via a fence, | 2598 | /* On the i915, GPU access to tiled buffers is via a fence, |
2548 | * therefore we must wait for any outstanding access to complete | 2599 | * therefore we must wait for any outstanding access to complete |
2549 | * before clearing the fence. | 2600 | * before clearing the fence. |
@@ -2552,12 +2603,12 @@ i915_gem_object_put_fence_reg(struct drm_gem_object *obj) | |||
2552 | int ret; | 2603 | int ret; |
2553 | 2604 | ||
2554 | i915_gem_object_flush_gpu_write_domain(obj); | 2605 | i915_gem_object_flush_gpu_write_domain(obj); |
2555 | i915_gem_object_flush_gtt_write_domain(obj); | ||
2556 | ret = i915_gem_object_wait_rendering(obj); | 2606 | ret = i915_gem_object_wait_rendering(obj); |
2557 | if (ret != 0) | 2607 | if (ret != 0) |
2558 | return ret; | 2608 | return ret; |
2559 | } | 2609 | } |
2560 | 2610 | ||
2611 | i915_gem_object_flush_gtt_write_domain(obj); | ||
2561 | i915_gem_clear_fence_reg (obj); | 2612 | i915_gem_clear_fence_reg (obj); |
2562 | 2613 | ||
2563 | return 0; | 2614 | return 0; |
@@ -2697,7 +2748,6 @@ static void | |||
2697 | i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj) | 2748 | i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj) |
2698 | { | 2749 | { |
2699 | struct drm_device *dev = obj->dev; | 2750 | struct drm_device *dev = obj->dev; |
2700 | uint32_t seqno; | ||
2701 | uint32_t old_write_domain; | 2751 | uint32_t old_write_domain; |
2702 | 2752 | ||
2703 | if ((obj->write_domain & I915_GEM_GPU_DOMAINS) == 0) | 2753 | if ((obj->write_domain & I915_GEM_GPU_DOMAINS) == 0) |
@@ -2706,9 +2756,8 @@ i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj) | |||
2706 | /* Queue the GPU write cache flushing we need. */ | 2756 | /* Queue the GPU write cache flushing we need. */ |
2707 | old_write_domain = obj->write_domain; | 2757 | old_write_domain = obj->write_domain; |
2708 | i915_gem_flush(dev, 0, obj->write_domain); | 2758 | i915_gem_flush(dev, 0, obj->write_domain); |
2709 | seqno = i915_add_request(dev, NULL, obj->write_domain); | 2759 | (void) i915_add_request(dev, NULL, obj->write_domain); |
2710 | BUG_ON(obj->write_domain); | 2760 | BUG_ON(obj->write_domain); |
2711 | i915_gem_object_move_to_active(obj, seqno); | ||
2712 | 2761 | ||
2713 | trace_i915_gem_object_change_domain(obj, | 2762 | trace_i915_gem_object_change_domain(obj, |
2714 | obj->read_domains, | 2763 | obj->read_domains, |
@@ -3247,7 +3296,8 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj, | |||
3247 | obj_priv->tiling_mode != I915_TILING_NONE; | 3296 | obj_priv->tiling_mode != I915_TILING_NONE; |
3248 | 3297 | ||
3249 | /* Check fence reg constraints and rebind if necessary */ | 3298 | /* Check fence reg constraints and rebind if necessary */ |
3250 | if (need_fence && !i915_obj_fenceable(dev, obj)) | 3299 | if (need_fence && !i915_gem_object_fence_offset_ok(obj, |
3300 | obj_priv->tiling_mode)) | ||
3251 | i915_gem_object_unbind(obj); | 3301 | i915_gem_object_unbind(obj); |
3252 | 3302 | ||
3253 | /* Choose the GTT offset for our buffer and put it there. */ | 3303 | /* Choose the GTT offset for our buffer and put it there. */ |
@@ -3317,6 +3367,16 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj, | |||
3317 | } | 3367 | } |
3318 | 3368 | ||
3319 | /* Validate that the target is in a valid r/w GPU domain */ | 3369 | /* Validate that the target is in a valid r/w GPU domain */ |
3370 | if (reloc->write_domain & (reloc->write_domain - 1)) { | ||
3371 | DRM_ERROR("reloc with multiple write domains: " | ||
3372 | "obj %p target %d offset %d " | ||
3373 | "read %08x write %08x", | ||
3374 | obj, reloc->target_handle, | ||
3375 | (int) reloc->offset, | ||
3376 | reloc->read_domains, | ||
3377 | reloc->write_domain); | ||
3378 | return -EINVAL; | ||
3379 | } | ||
3320 | if (reloc->write_domain & I915_GEM_DOMAIN_CPU || | 3380 | if (reloc->write_domain & I915_GEM_DOMAIN_CPU || |
3321 | reloc->read_domains & I915_GEM_DOMAIN_CPU) { | 3381 | reloc->read_domains & I915_GEM_DOMAIN_CPU) { |
3322 | DRM_ERROR("reloc with read/write CPU domains: " | 3382 | DRM_ERROR("reloc with read/write CPU domains: " |
@@ -4445,8 +4505,7 @@ int | |||
4445 | i915_gem_idle(struct drm_device *dev) | 4505 | i915_gem_idle(struct drm_device *dev) |
4446 | { | 4506 | { |
4447 | drm_i915_private_t *dev_priv = dev->dev_private; | 4507 | drm_i915_private_t *dev_priv = dev->dev_private; |
4448 | uint32_t seqno, cur_seqno, last_seqno; | 4508 | int ret; |
4449 | int stuck, ret; | ||
4450 | 4509 | ||
4451 | mutex_lock(&dev->struct_mutex); | 4510 | mutex_lock(&dev->struct_mutex); |
4452 | 4511 | ||
@@ -4455,115 +4514,36 @@ i915_gem_idle(struct drm_device *dev) | |||
4455 | return 0; | 4514 | return 0; |
4456 | } | 4515 | } |
4457 | 4516 | ||
4458 | /* Hack! Don't let anybody do execbuf while we don't control the chip. | 4517 | ret = i915_gpu_idle(dev); |
4459 | * We need to replace this with a semaphore, or something. | 4518 | if (ret) { |
4460 | */ | ||
4461 | dev_priv->mm.suspended = 1; | ||
4462 | del_timer(&dev_priv->hangcheck_timer); | ||
4463 | |||
4464 | /* Cancel the retire work handler, wait for it to finish if running | ||
4465 | */ | ||
4466 | mutex_unlock(&dev->struct_mutex); | ||
4467 | cancel_delayed_work_sync(&dev_priv->mm.retire_work); | ||
4468 | mutex_lock(&dev->struct_mutex); | ||
4469 | |||
4470 | i915_kernel_lost_context(dev); | ||
4471 | |||
4472 | /* Flush the GPU along with all non-CPU write domains | ||
4473 | */ | ||
4474 | i915_gem_flush(dev, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS); | ||
4475 | seqno = i915_add_request(dev, NULL, I915_GEM_GPU_DOMAINS); | ||
4476 | |||
4477 | if (seqno == 0) { | ||
4478 | mutex_unlock(&dev->struct_mutex); | 4519 | mutex_unlock(&dev->struct_mutex); |
4479 | return -ENOMEM; | 4520 | return ret; |
4480 | } | 4521 | } |
4481 | 4522 | ||
4482 | dev_priv->mm.waiting_gem_seqno = seqno; | 4523 | /* Under UMS, be paranoid and evict. */ |
4483 | last_seqno = 0; | 4524 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) { |
4484 | stuck = 0; | 4525 | ret = i915_gem_evict_from_inactive_list(dev); |
4485 | for (;;) { | 4526 | if (ret) { |
4486 | cur_seqno = i915_get_gem_seqno(dev); | 4527 | mutex_unlock(&dev->struct_mutex); |
4487 | if (i915_seqno_passed(cur_seqno, seqno)) | 4528 | return ret; |
4488 | break; | ||
4489 | if (last_seqno == cur_seqno) { | ||
4490 | if (stuck++ > 100) { | ||
4491 | DRM_ERROR("hardware wedged\n"); | ||
4492 | atomic_set(&dev_priv->mm.wedged, 1); | ||
4493 | DRM_WAKEUP(&dev_priv->irq_queue); | ||
4494 | break; | ||
4495 | } | ||
4496 | } | 4529 | } |
4497 | msleep(10); | ||
4498 | last_seqno = cur_seqno; | ||
4499 | } | ||
4500 | dev_priv->mm.waiting_gem_seqno = 0; | ||
4501 | |||
4502 | i915_gem_retire_requests(dev); | ||
4503 | |||
4504 | spin_lock(&dev_priv->mm.active_list_lock); | ||
4505 | if (!atomic_read(&dev_priv->mm.wedged)) { | ||
4506 | /* Active and flushing should now be empty as we've | ||
4507 | * waited for a sequence higher than any pending execbuffer | ||
4508 | */ | ||
4509 | WARN_ON(!list_empty(&dev_priv->mm.active_list)); | ||
4510 | WARN_ON(!list_empty(&dev_priv->mm.flushing_list)); | ||
4511 | /* Request should now be empty as we've also waited | ||
4512 | * for the last request in the list | ||
4513 | */ | ||
4514 | WARN_ON(!list_empty(&dev_priv->mm.request_list)); | ||
4515 | } | 4530 | } |
4516 | 4531 | ||
4517 | /* Empty the active and flushing lists to inactive. If there's | 4532 | /* Hack! Don't let anybody do execbuf while we don't control the chip. |
4518 | * anything left at this point, it means that we're wedged and | 4533 | * We need to replace this with a semaphore, or something. |
4519 | * nothing good's going to happen by leaving them there. So strip | 4534 | * And not confound mm.suspended! |
4520 | * the GPU domains and just stuff them onto inactive. | ||
4521 | */ | 4535 | */ |
4522 | while (!list_empty(&dev_priv->mm.active_list)) { | 4536 | dev_priv->mm.suspended = 1; |
4523 | struct drm_gem_object *obj; | 4537 | del_timer(&dev_priv->hangcheck_timer); |
4524 | uint32_t old_write_domain; | ||
4525 | |||
4526 | obj = list_first_entry(&dev_priv->mm.active_list, | ||
4527 | struct drm_i915_gem_object, | ||
4528 | list)->obj; | ||
4529 | old_write_domain = obj->write_domain; | ||
4530 | obj->write_domain &= ~I915_GEM_GPU_DOMAINS; | ||
4531 | i915_gem_object_move_to_inactive(obj); | ||
4532 | |||
4533 | trace_i915_gem_object_change_domain(obj, | ||
4534 | obj->read_domains, | ||
4535 | old_write_domain); | ||
4536 | } | ||
4537 | spin_unlock(&dev_priv->mm.active_list_lock); | ||
4538 | |||
4539 | while (!list_empty(&dev_priv->mm.flushing_list)) { | ||
4540 | struct drm_gem_object *obj; | ||
4541 | uint32_t old_write_domain; | ||
4542 | |||
4543 | obj = list_first_entry(&dev_priv->mm.flushing_list, | ||
4544 | struct drm_i915_gem_object, | ||
4545 | list)->obj; | ||
4546 | old_write_domain = obj->write_domain; | ||
4547 | obj->write_domain &= ~I915_GEM_GPU_DOMAINS; | ||
4548 | i915_gem_object_move_to_inactive(obj); | ||
4549 | |||
4550 | trace_i915_gem_object_change_domain(obj, | ||
4551 | obj->read_domains, | ||
4552 | old_write_domain); | ||
4553 | } | ||
4554 | |||
4555 | |||
4556 | /* Move all inactive buffers out of the GTT. */ | ||
4557 | ret = i915_gem_evict_from_inactive_list(dev); | ||
4558 | WARN_ON(!list_empty(&dev_priv->mm.inactive_list)); | ||
4559 | if (ret) { | ||
4560 | mutex_unlock(&dev->struct_mutex); | ||
4561 | return ret; | ||
4562 | } | ||
4563 | 4538 | ||
4539 | i915_kernel_lost_context(dev); | ||
4564 | i915_gem_cleanup_ringbuffer(dev); | 4540 | i915_gem_cleanup_ringbuffer(dev); |
4541 | |||
4565 | mutex_unlock(&dev->struct_mutex); | 4542 | mutex_unlock(&dev->struct_mutex); |
4566 | 4543 | ||
4544 | /* Cancel the retire work handler, which should be idle now. */ | ||
4545 | cancel_delayed_work_sync(&dev_priv->mm.retire_work); | ||
4546 | |||
4567 | return 0; | 4547 | return 0; |
4568 | } | 4548 | } |
4569 | 4549 | ||
@@ -4607,8 +4587,13 @@ i915_gem_init_hws(struct drm_device *dev) | |||
4607 | } | 4587 | } |
4608 | dev_priv->hws_obj = obj; | 4588 | dev_priv->hws_obj = obj; |
4609 | memset(dev_priv->hw_status_page, 0, PAGE_SIZE); | 4589 | memset(dev_priv->hw_status_page, 0, PAGE_SIZE); |
4610 | I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr); | 4590 | if (IS_GEN6(dev)) { |
4611 | I915_READ(HWS_PGA); /* posting read */ | 4591 | I915_WRITE(HWS_PGA_GEN6, dev_priv->status_gfx_addr); |
4592 | I915_READ(HWS_PGA_GEN6); /* posting read */ | ||
4593 | } else { | ||
4594 | I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr); | ||
4595 | I915_READ(HWS_PGA); /* posting read */ | ||
4596 | } | ||
4612 | DRM_DEBUG_DRIVER("hws offset: 0x%08x\n", dev_priv->status_gfx_addr); | 4597 | DRM_DEBUG_DRIVER("hws offset: 0x%08x\n", dev_priv->status_gfx_addr); |
4613 | 4598 | ||
4614 | return 0; | 4599 | return 0; |
@@ -4850,7 +4835,8 @@ i915_gem_load(struct drm_device *dev) | |||
4850 | spin_unlock(&shrink_list_lock); | 4835 | spin_unlock(&shrink_list_lock); |
4851 | 4836 | ||
4852 | /* Old X drivers will take 0-2 for front, back, depth buffers */ | 4837 | /* Old X drivers will take 0-2 for front, back, depth buffers */ |
4853 | dev_priv->fence_reg_start = 3; | 4838 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
4839 | dev_priv->fence_reg_start = 3; | ||
4854 | 4840 | ||
4855 | if (IS_I965G(dev) || IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) | 4841 | if (IS_I965G(dev) || IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) |
4856 | dev_priv->num_fence_regs = 16; | 4842 | dev_priv->num_fence_regs = 16; |