118,14 → 118,12 |
} |
|
static int |
i915_gem_wait_for_error(struct drm_device *dev) |
i915_gem_wait_for_error(struct i915_gpu_error *error) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct completion *x = &dev_priv->error_completion; |
unsigned long flags; |
int ret; |
|
if (!atomic_read(&dev_priv->mm.wedged)) |
#define EXIT_COND (!i915_reset_in_progress(error)) |
if (EXIT_COND) |
return 0; |
#if 0 |
/* |
133,7 → 131,9 |
* userspace. If it takes that long something really bad is going on and |
* we should simply try to bail out and fail as gracefully as possible. |
*/ |
ret = wait_for_completion_interruptible_timeout(x, 10*HZ); |
ret = wait_event_interruptible_timeout(error->reset_queue, |
EXIT_COND, |
10*HZ); |
if (ret == 0) { |
DRM_ERROR("Timed out waiting for the gpu reset to complete\n"); |
return -EIO; |
141,17 → 141,8 |
return ret; |
} |
|
if (atomic_read(&dev_priv->mm.wedged)) { |
/* GPU is hung, bump the completion count to account for |
* the token we just consumed so that we never hit zero and |
* end up waiting upon a subsequent completion event that |
* will never happen. |
*/ |
spin_lock_irqsave(&x->wait.lock, flags); |
x->done++; |
spin_unlock_irqrestore(&x->wait.lock, flags); |
} |
#endif |
#undef EXIT_COND |
|
return 0; |
} |
158,13 → 149,16 |
|
int i915_mutex_lock_interruptible(struct drm_device *dev) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
int ret; |
|
ret = i915_gem_wait_for_error(dev); |
ret = i915_gem_wait_for_error(&dev_priv->gpu_error); |
if (ret) |
return ret; |
|
mutex_lock(&dev->struct_mutex); |
ret = mutex_lock_interruptible(&dev->struct_mutex); |
if (ret) |
return ret; |
|
WARN_ON(i915_verify_lists(dev)); |
return 0; |
183,6 → 177,7 |
i915_gem_init_ioctl(struct drm_device *dev, void *data, |
struct drm_file *file) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct drm_i915_gem_init *args = data; |
|
if (drm_core_check_feature(dev, DRIVER_MODESET)) |
197,8 → 192,9 |
return -ENODEV; |
|
mutex_lock(&dev->struct_mutex); |
i915_gem_init_global_gtt(dev, args->gtt_start, |
args->gtt_end, args->gtt_end); |
i915_gem_setup_global_gtt(dev, args->gtt_start, args->gtt_end, |
args->gtt_end); |
dev_priv->gtt.mappable_end = args->gtt_end; |
mutex_unlock(&dev->struct_mutex); |
|
return 0; |
221,12 → 217,24 |
pinned += obj->gtt_space->size; |
mutex_unlock(&dev->struct_mutex); |
|
args->aper_size = dev_priv->mm.gtt_total; |
args->aper_size = dev_priv->gtt.total; |
args->aper_available_size = args->aper_size - pinned; |
|
return 0; |
} |
|
void *i915_gem_object_alloc(struct drm_device *dev) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
return kmalloc(sizeof(struct drm_i915_gem_object), 0); |
} |
|
void i915_gem_object_free(struct drm_i915_gem_object *obj) |
{ |
struct drm_i915_private *dev_priv = obj->base.dev->dev_private; |
kfree(obj); |
} |
|
static int |
i915_gem_create(struct drm_file *file, |
struct drm_device *dev, |
297,13 → 305,7 |
args->size, &args->handle); |
} |
|
static int i915_gem_object_needs_bit17_swizzle(struct drm_i915_gem_object *obj) |
{ |
drm_i915_private_t *dev_priv = obj->base.dev->dev_private; |
|
return dev_priv->mm.bit_6_swizzle_x == I915_BIT_6_SWIZZLE_9_10_17 && |
obj->tiling_mode != I915_TILING_NONE; |
} |
#if 0 |
|
static inline int |
446,7 → 448,6 |
loff_t offset; |
int shmem_page_offset, page_length, ret = 0; |
int obj_do_bit17_swizzling, page_do_bit17_swizzling; |
int hit_slowpath = 0; |
int prefaulted = 0; |
int needs_clflush = 0; |
struct scatterlist *sg; |
508,7 → 509,6 |
if (ret == 0) |
goto next_page; |
|
hit_slowpath = 1; |
mutex_unlock(&dev->struct_mutex); |
|
if (!prefaulted) { |
541,12 → 541,6 |
out: |
i915_gem_object_unpin_pages(obj); |
|
if (hit_slowpath) { |
/* Fixup: Kill any reinstated backing storage pages */ |
if (obj->madv == __I915_MADV_PURGED) |
i915_gem_object_truncate(obj); |
} |
|
return ret; |
} |
|
888,12 → 882,13 |
i915_gem_object_unpin_pages(obj); |
|
if (hit_slowpath) { |
/* Fixup: Kill any reinstated backing storage pages */ |
if (obj->madv == __I915_MADV_PURGED) |
i915_gem_object_truncate(obj); |
/* and flush dirty cachelines in case the object isn't in the cpu write |
* domain anymore. */ |
if (obj->base.write_domain != I915_GEM_DOMAIN_CPU) { |
/* |
* Fixup: Flush cpu caches in case we didn't flush the dirty |
* cachelines in-line while writing and the object moved |
* out of the cpu write domain while we've dropped the lock. |
*/ |
if (!needs_clflush_after && |
obj->base.write_domain != I915_GEM_DOMAIN_CPU) { |
i915_gem_clflush_object(obj); |
i915_gem_chipset_flush(dev); |
} |
918,6 → 913,12 |
struct drm_i915_gem_object *obj; |
int ret; |
|
if(args->handle == -2) |
{ |
printf("%s handle %d\n", __FUNCTION__, args->handle); |
return 0; |
} |
|
if (args->size == 0) |
return 0; |
|
980,26 → 981,17 |
} |
|
int |
i915_gem_check_wedge(struct drm_i915_private *dev_priv, |
i915_gem_check_wedge(struct i915_gpu_error *error, |
bool interruptible) |
{ |
if (atomic_read(&dev_priv->mm.wedged)) { |
struct completion *x = &dev_priv->error_completion; |
bool recovery_complete; |
unsigned long flags; |
|
/* Give the error handler a chance to run. */ |
spin_lock_irqsave(&x->wait.lock, flags); |
recovery_complete = x->done > 0; |
spin_unlock_irqrestore(&x->wait.lock, flags); |
|
if (i915_reset_in_progress(error)) { |
/* Non-interruptible callers can't handle -EAGAIN, hence return |
* -EIO unconditionally for these. */ |
if (!interruptible) |
return -EIO; |
|
/* Recovery complete, but still wedged means reset failure. */ |
if (recovery_complete) |
/* Recovery complete, but the reset failed ... */ |
if (i915_terminally_wedged(error)) |
return -EIO; |
|
return -EAGAIN; |
1030,13 → 1022,22 |
* __wait_seqno - wait until execution of seqno has finished |
* @ring: the ring expected to report seqno |
* @seqno: duh! |
* @reset_counter: reset sequence associated with the given seqno |
* @interruptible: do an interruptible wait (normally yes) |
* @timeout: in - how long to wait (NULL forever); out - how much time remaining |
* |
* Note: It is of utmost importance that the passed in seqno and reset_counter |
* values have been read by the caller in an smp safe manner. Where read-side |
* locks are involved, it is sufficient to read the reset_counter before |
* unlocking the lock that protects the seqno. For lockless tricks, the |
* reset_counter _must_ be read before, and an appropriate smp_rmb must be |
* inserted. |
* |
* Returns 0 if the seqno was found within the alloted time. Else returns the |
* errno with remaining time filled in timeout argument. |
*/ |
static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno, |
unsigned reset_counter, |
bool interruptible, struct timespec *timeout) |
{ |
drm_i915_private_t *dev_priv = ring->dev->dev_private; |
1066,7 → 1067,8 |
|
#define EXIT_COND \ |
(i915_seqno_passed(ring->get_seqno(ring, false), seqno) || \ |
atomic_read(&dev_priv->mm.wedged)) |
i915_reset_in_progress(&dev_priv->gpu_error) || \ |
reset_counter != atomic_read(&dev_priv->gpu_error.reset_counter)) |
do { |
if (interruptible) |
end = wait_event_interruptible_timeout(ring->irq_queue, |
1076,7 → 1078,14 |
end = wait_event_timeout(ring->irq_queue, EXIT_COND, |
timeout_jiffies); |
|
ret = i915_gem_check_wedge(dev_priv, interruptible); |
/* We need to check whether any gpu reset happened in between |
* the caller grabbing the seqno and now ... */ |
if (reset_counter != atomic_read(&dev_priv->gpu_error.reset_counter)) |
end = -EAGAIN; |
|
/* ... but upgrade the -EGAIN to an -EIO if the gpu is truely |
* gone. */ |
ret = i915_gem_check_wedge(&dev_priv->gpu_error, interruptible); |
if (ret) |
end = ret; |
} while (end == 0 && wait_forever); |
1122,7 → 1131,7 |
BUG_ON(!mutex_is_locked(&dev->struct_mutex)); |
BUG_ON(seqno == 0); |
|
ret = i915_gem_check_wedge(dev_priv, interruptible); |
ret = i915_gem_check_wedge(&dev_priv->gpu_error, interruptible); |
if (ret) |
return ret; |
|
1130,7 → 1139,9 |
if (ret) |
return ret; |
|
return __wait_seqno(ring, seqno, interruptible, NULL); |
return __wait_seqno(ring, seqno, |
atomic_read(&dev_priv->gpu_error.reset_counter), |
interruptible, NULL); |
} |
|
/** |
1177,6 → 1188,7 |
struct drm_device *dev = obj->base.dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct intel_ring_buffer *ring = obj->ring; |
unsigned reset_counter; |
u32 seqno; |
int ret; |
|
1187,7 → 1199,7 |
if (seqno == 0) |
return 0; |
|
ret = i915_gem_check_wedge(dev_priv, true); |
ret = i915_gem_check_wedge(&dev_priv->gpu_error, true); |
if (ret) |
return ret; |
|
1195,8 → 1207,9 |
if (ret) |
return ret; |
|
reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter); |
mutex_unlock(&dev->struct_mutex); |
ret = __wait_seqno(ring, seqno, true, NULL); |
ret = __wait_seqno(ring, seqno, reset_counter, true, NULL); |
mutex_lock(&dev->struct_mutex); |
|
i915_gem_retire_requests_ring(ring); |
1227,6 → 1240,13 |
uint32_t write_domain = args->write_domain; |
int ret; |
|
|
if(args->handle == -2) |
{ |
printf("%s handle %d\n", __FUNCTION__, args->handle); |
return 0; |
} |
|
/* Only handle setting domains to types used by the CPU. */ |
if (write_domain & I915_GEM_GPU_DOMAINS) |
return -EINVAL; |
1298,6 → 1318,12 |
struct drm_gem_object *obj; |
unsigned long addr = 0; |
|
if(args->handle == -2) |
{ |
printf("%s handle %d\n", __FUNCTION__, args->handle); |
return 0; |
} |
|
obj = drm_gem_object_lookup(dev, file, args->handle); |
if (obj == NULL) |
return -ENOENT; |
1364,7 → 1390,7 |
obj->fault_mappable = false; |
} |
|
static uint32_t |
uint32_t |
i915_gem_get_gtt_size(struct drm_device *dev, uint32_t size, int tiling_mode) |
{ |
uint32_t gtt_size; |
1392,16 → 1418,15 |
* Return the required GTT alignment for an object, taking into account |
* potential fence register mapping. |
*/ |
static uint32_t |
i915_gem_get_gtt_alignment(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, bool fenced) |
{ |
/* |
* 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 || |
if (INTEL_INFO(dev)->gen >= 4 || (!fenced && IS_G33(dev)) || |
tiling_mode == I915_TILING_NONE) |
return 4096; |
|
1441,6 → 1466,104 |
return i915_gem_get_gtt_size(dev, size, tiling_mode); |
} |
|
int |
i915_gem_mmap_gtt(struct drm_file *file, |
struct drm_device *dev, |
uint32_t handle, |
uint64_t *offset) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct drm_i915_gem_object *obj; |
unsigned long pfn; |
char *mem, *ptr; |
int ret; |
|
ret = i915_mutex_lock_interruptible(dev); |
if (ret) |
return ret; |
|
obj = to_intel_bo(drm_gem_object_lookup(dev, file, handle)); |
if (&obj->base == NULL) { |
ret = -ENOENT; |
goto unlock; |
} |
|
if (obj->base.size > dev_priv->gtt.mappable_end) { |
ret = -E2BIG; |
goto out; |
} |
|
if (obj->madv != I915_MADV_WILLNEED) { |
DRM_ERROR("Attempting to mmap a purgeable buffer\n"); |
ret = -EINVAL; |
goto out; |
} |
/* Now bind it into the GTT if needed */ |
ret = i915_gem_object_pin(obj, 0, true, false); |
if (ret) |
goto out; |
|
ret = i915_gem_object_set_to_gtt_domain(obj, 1); |
if (ret) |
goto unpin; |
|
ret = i915_gem_object_get_fence(obj); |
if (ret) |
goto unpin; |
|
obj->fault_mappable = true; |
|
pfn = dev_priv->gtt.mappable_base + obj->gtt_offset; |
|
/* Finally, remap it using the new GTT offset */ |
|
mem = UserAlloc(obj->base.size); |
if(unlikely(mem == NULL)) |
{ |
ret = -ENOMEM; |
goto unpin; |
} |
|
for(ptr = mem; ptr < mem + obj->base.size; ptr+= 4096, pfn+= 4096) |
MapPage(ptr, pfn, PG_SHARED|PG_UW); |
|
unpin: |
i915_gem_object_unpin(obj); |
|
|
*offset = (u64)mem; |
|
out: |
drm_gem_object_unreference(&obj->base); |
unlock: |
mutex_unlock(&dev->struct_mutex); |
return ret; |
} |
|
/** |
* i915_gem_mmap_gtt_ioctl - prepare an object for GTT mmap'ing |
* @dev: DRM device |
* @data: GTT mapping ioctl data |
* @file: GEM object info |
* |
* Simply returns the fake offset to userspace so it can mmap it. |
* The mmap call will end up in drm_gem_mmap(), which will set things |
* up so we can get faults in the handler above. |
* |
* The fault handler will take care of binding the object into the GTT |
* (since it may have been evicted to make room for something), allocating |
* a fence register, and mapping the appropriate aperture address into |
* userspace. |
*/ |
int |
i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data, |
struct drm_file *file) |
{ |
struct drm_i915_gem_mmap_gtt *args = data; |
|
return i915_gem_mmap_gtt(file, dev, args->handle, &args->offset); |
} |
|
/* Immediately discard the backing storage */ |
static void |
i915_gem_object_truncate(struct drm_i915_gem_object *obj) |
1504,7 → 1627,7 |
kfree(obj->pages); |
} |
|
static int |
int |
i915_gem_object_put_pages(struct drm_i915_gem_object *obj) |
{ |
const struct drm_i915_gem_object_ops *ops = obj->ops; |
1669,9 → 1792,6 |
BUG_ON(obj->base.write_domain & ~I915_GEM_GPU_DOMAINS); |
BUG_ON(!obj->active); |
|
if (obj->pin_count) /* are we a framebuffer? */ |
intel_mark_fb_idle(obj); |
|
list_move_tail(&obj->mm_list, &dev_priv->mm.inactive_list); |
|
list_del_init(&obj->ring_list); |
1691,30 → 1811,24 |
} |
|
static int |
i915_gem_handle_seqno_wrap(struct drm_device *dev) |
i915_gem_init_seqno(struct drm_device *dev, u32 seqno) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct intel_ring_buffer *ring; |
int ret, i, j; |
|
/* The hardware uses various monotonic 32-bit counters, if we |
* detect that they will wraparound we need to idle the GPU |
* and reset those counters. |
*/ |
ret = 0; |
/* Carefully retire all requests without writing to the rings */ |
for_each_ring(ring, dev_priv, i) { |
for (j = 0; j < ARRAY_SIZE(ring->sync_seqno); j++) |
ret |= ring->sync_seqno[j] != 0; |
} |
if (ret == 0) |
return ret; |
|
ret = i915_gpu_idle(dev); |
ret = intel_ring_idle(ring); |
if (ret) |
return ret; |
} |
i915_gem_retire_requests(dev); |
|
i915_gem_retire_requests(dev); |
/* Finally reset hw state */ |
for_each_ring(ring, dev_priv, i) { |
intel_ring_init_seqno(ring, seqno); |
|
for (j = 0; j < ARRAY_SIZE(ring->sync_seqno); j++) |
ring->sync_seqno[j] = 0; |
} |
1722,6 → 1836,32 |
return 0; |
} |
|
int i915_gem_set_seqno(struct drm_device *dev, u32 seqno) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
int ret; |
|
if (seqno == 0) |
return -EINVAL; |
|
/* HWS page needs to be set less than what we |
* will inject to ring |
*/ |
ret = i915_gem_init_seqno(dev, seqno - 1); |
if (ret) |
return ret; |
|
/* Carefully set the last_seqno value so that wrap |
* detection still works |
*/ |
dev_priv->next_seqno = seqno; |
dev_priv->last_seqno = seqno - 1; |
if (dev_priv->last_seqno == 0) |
dev_priv->last_seqno--; |
|
return 0; |
} |
|
int |
i915_gem_get_seqno(struct drm_device *dev, u32 *seqno) |
{ |
1729,7 → 1869,7 |
|
/* reserve 0 for non-seqno */ |
if (dev_priv->next_seqno == 0) { |
int ret = i915_gem_handle_seqno_wrap(dev); |
int ret = i915_gem_init_seqno(dev, 0); |
if (ret) |
return ret; |
|
1736,7 → 1876,7 |
dev_priv->next_seqno = 1; |
} |
|
*seqno = dev_priv->next_seqno++; |
*seqno = dev_priv->last_seqno = dev_priv->next_seqno++; |
return 0; |
} |
|
2126,9 → 2266,6 |
{ |
u32 old_write_domain, old_read_domains; |
|
/* Act a barrier for all accesses through the GTT */ |
mb(); |
|
/* Force a pagefault for domain tracking on next user access */ |
// i915_gem_release_mmap(obj); |
|
2135,6 → 2272,9 |
if ((obj->base.read_domains & I915_GEM_DOMAIN_GTT) == 0) |
return; |
|
/* Wait for any direct GTT access to complete */ |
mb(); |
|
old_read_domains = obj->base.read_domains; |
old_write_domain = obj->base.write_domain; |
|
2153,7 → 2293,7 |
i915_gem_object_unbind(struct drm_i915_gem_object *obj) |
{ |
drm_i915_private_t *dev_priv = obj->base.dev->dev_private; |
int ret = 0; |
int ret; |
|
if(obj == get_fb_obj()) |
return 0; |
2223,37 → 2363,22 |
return 0; |
} |
|
static void sandybridge_write_fence_reg(struct drm_device *dev, int reg, |
static void i965_write_fence_reg(struct drm_device *dev, int reg, |
struct drm_i915_gem_object *obj) |
{ |
drm_i915_private_t *dev_priv = dev->dev_private; |
int fence_reg; |
int fence_pitch_shift; |
uint64_t val; |
|
if (obj) { |
u32 size = obj->gtt_space->size; |
|
val = (uint64_t)((obj->gtt_offset + size - 4096) & |
0xfffff000) << 32; |
val |= obj->gtt_offset & 0xfffff000; |
val |= (uint64_t)((obj->stride / 128) - 1) << |
SANDYBRIDGE_FENCE_PITCH_SHIFT; |
|
if (obj->tiling_mode == I915_TILING_Y) |
val |= 1 << I965_FENCE_TILING_Y_SHIFT; |
val |= I965_FENCE_REG_VALID; |
} else |
val = 0; |
|
I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + reg * 8, val); |
POSTING_READ(FENCE_REG_SANDYBRIDGE_0 + reg * 8); |
if (INTEL_INFO(dev)->gen >= 6) { |
fence_reg = FENCE_REG_SANDYBRIDGE_0; |
fence_pitch_shift = SANDYBRIDGE_FENCE_PITCH_SHIFT; |
} else { |
fence_reg = FENCE_REG_965_0; |
fence_pitch_shift = I965_FENCE_PITCH_SHIFT; |
} |
|
static void i965_write_fence_reg(struct drm_device *dev, int reg, |
struct drm_i915_gem_object *obj) |
{ |
drm_i915_private_t *dev_priv = dev->dev_private; |
uint64_t val; |
|
if (obj) { |
u32 size = obj->gtt_space->size; |
|
2260,7 → 2385,7 |
val = (uint64_t)((obj->gtt_offset + size - 4096) & |
0xfffff000) << 32; |
val |= obj->gtt_offset & 0xfffff000; |
val |= ((obj->stride / 128) - 1) << I965_FENCE_PITCH_SHIFT; |
val |= (uint64_t)((obj->stride / 128) - 1) << fence_pitch_shift; |
if (obj->tiling_mode == I915_TILING_Y) |
val |= 1 << I965_FENCE_TILING_Y_SHIFT; |
val |= I965_FENCE_REG_VALID; |
2267,8 → 2392,9 |
} else |
val = 0; |
|
I915_WRITE64(FENCE_REG_965_0 + reg * 8, val); |
POSTING_READ(FENCE_REG_965_0 + reg * 8); |
fence_reg += reg * 8; |
I915_WRITE64(fence_reg, val); |
POSTING_READ(fence_reg); |
} |
|
static void i915_write_fence_reg(struct drm_device *dev, int reg, |
2347,18 → 2473,37 |
POSTING_READ(FENCE_REG_830_0 + reg * 4); |
} |
|
inline static bool i915_gem_object_needs_mb(struct drm_i915_gem_object *obj) |
{ |
return obj && obj->base.read_domains & I915_GEM_DOMAIN_GTT; |
} |
|
static void i915_gem_write_fence(struct drm_device *dev, int reg, |
struct drm_i915_gem_object *obj) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
|
/* Ensure that all CPU reads are completed before installing a fence |
* and all writes before removing the fence. |
*/ |
if (i915_gem_object_needs_mb(dev_priv->fence_regs[reg].obj)) |
mb(); |
|
switch (INTEL_INFO(dev)->gen) { |
case 7: |
case 6: sandybridge_write_fence_reg(dev, reg, obj); break; |
case 6: |
case 5: |
case 4: i965_write_fence_reg(dev, reg, obj); break; |
case 3: i915_write_fence_reg(dev, reg, obj); break; |
case 2: i830_write_fence_reg(dev, reg, obj); break; |
default: break; |
default: BUG(); |
} |
|
/* And similarly be paranoid that no direct access to this region |
* is reordered to before the fence is installed. |
*/ |
if (i915_gem_object_needs_mb(obj)) |
mb(); |
} |
|
static inline int fence_number(struct drm_i915_private *dev_priv, |
2388,7 → 2533,7 |
} |
|
static int |
i915_gem_object_flush_fence(struct drm_i915_gem_object *obj) |
i915_gem_object_wait_fence(struct drm_i915_gem_object *obj) |
{ |
if (obj->last_fenced_seqno) { |
int ret = i915_wait_seqno(obj->ring, obj->last_fenced_seqno); |
2398,12 → 2543,6 |
obj->last_fenced_seqno = 0; |
} |
|
/* Ensure that all CPU reads are completed before installing a fence |
* and all writes before removing the fence. |
*/ |
if (obj->base.read_domains & I915_GEM_DOMAIN_GTT) |
mb(); |
|
obj->fenced_gpu_access = false; |
return 0; |
} |
2414,7 → 2553,7 |
struct drm_i915_private *dev_priv = obj->base.dev->dev_private; |
int ret; |
|
ret = i915_gem_object_flush_fence(obj); |
ret = i915_gem_object_wait_fence(obj); |
if (ret) |
return ret; |
|
2488,7 → 2627,7 |
* will need to serialise the write to the associated fence register? |
*/ |
if (obj->fence_dirty) { |
ret = i915_gem_object_flush_fence(obj); |
ret = i915_gem_object_wait_fence(obj); |
if (ret) |
return ret; |
} |
2509,7 → 2648,7 |
if (reg->obj) { |
struct drm_i915_gem_object *old = reg->obj; |
|
ret = i915_gem_object_flush_fence(old); |
ret = i915_gem_object_wait_fence(old); |
if (ret) |
return ret; |
|
2532,7 → 2671,7 |
|
/* On non-LLC machines we have to be careful when putting differing |
* types of snoopable memory together to avoid the prefetcher |
* crossing memory domains and dieing. |
* crossing memory domains and dying. |
*/ |
if (HAS_LLC(dev)) |
return true; |
2610,21 → 2749,16 |
bool mappable, fenceable; |
int ret; |
|
if (obj->madv != I915_MADV_WILLNEED) { |
DRM_ERROR("Attempting to bind a purgeable object\n"); |
return -EINVAL; |
} |
|
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); |
obj->tiling_mode, true); |
unfenced_alignment = |
i915_gem_get_unfenced_gtt_alignment(dev, |
i915_gem_get_gtt_alignment(dev, |
obj->base.size, |
obj->tiling_mode); |
obj->tiling_mode, false); |
|
if (alignment == 0) |
alignment = map_and_fenceable ? fence_alignment : |
2640,7 → 2774,7 |
* 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)) { |
(map_and_fenceable ? dev_priv->gtt.mappable_end : dev_priv->gtt.total)) { |
DRM_ERROR("Attempting to bind an object larger than the aperture\n"); |
return -E2BIG; |
} |
2661,7 → 2795,7 |
if (map_and_fenceable) |
ret = drm_mm_insert_node_in_range_generic(&dev_priv->mm.gtt_space, node, |
size, alignment, obj->cache_level, |
0, dev_priv->mm.gtt_mappable_end); |
0, dev_priv->gtt.mappable_end); |
else |
ret = drm_mm_insert_node_generic(&dev_priv->mm.gtt_space, node, |
size, alignment, obj->cache_level); |
2695,7 → 2829,7 |
(node->start & (fence_alignment - 1)) == 0; |
|
mappable = |
obj->gtt_offset + obj->base.size <= dev_priv->mm.gtt_mappable_end; |
obj->gtt_offset + obj->base.size <= dev_priv->gtt.mappable_end; |
|
obj->map_and_fenceable = mappable && fenceable; |
|
2715,6 → 2849,13 |
if (obj->pages == NULL) |
return; |
|
/* |
* Stolen memory is always coherent with the GPU as it is explicitly |
* marked as wc by the system, or the system is cache-coherent. |
*/ |
if (obj->stolen) |
return; |
|
/* If the GPU is snooping the contents of the CPU cache, |
* we do not need to manually clear the CPU cache lines. However, |
* the caches are only snooped when the render cache is |
2848,6 → 2989,13 |
|
i915_gem_object_flush_cpu_write_domain(obj); |
|
/* Serialise direct access to this object with the barriers for |
* coherent writes from the GPU, by effectively invalidating the |
* GTT domain upon first access. |
*/ |
if ((obj->base.read_domains & I915_GEM_DOMAIN_GTT) == 0) |
mb(); |
|
old_write_domain = obj->base.write_domain; |
old_read_domains = obj->base.read_domains; |
|
2955,6 → 3103,12 |
struct drm_i915_gem_object *obj; |
int ret; |
|
if(args->handle == -2) |
{ |
printf("%s handle %d\n", __FUNCTION__, args->handle); |
return 0; |
} |
|
ret = i915_mutex_lock_interruptible(dev); |
if (ret) |
return ret; |
2981,6 → 3135,12 |
enum i915_cache_level level; |
int ret; |
|
if(args->handle == -2) |
{ |
printf("%s handle %d\n", __FUNCTION__, args->handle); |
return 0; |
} |
|
switch (args->caching) { |
case I915_CACHING_NONE: |
level = I915_CACHE_NONE; |
3154,12 → 3314,18 |
unsigned long recent_enough = GetTimerTicks() - msecs_to_jiffies(20); |
struct drm_i915_gem_request *request; |
struct intel_ring_buffer *ring = NULL; |
unsigned reset_counter; |
u32 seqno = 0; |
int ret; |
|
if (atomic_read(&dev_priv->mm.wedged)) |
return -EIO; |
ret = i915_gem_wait_for_error(&dev_priv->gpu_error); |
if (ret) |
return ret; |
|
ret = i915_gem_check_wedge(&dev_priv->gpu_error, false); |
if (ret) |
return ret; |
|
spin_lock(&file_priv->mm.lock); |
list_for_each_entry(request, &file_priv->mm.request_list, client_list) { |
if (time_after_eq(request->emitted_jiffies, recent_enough)) |
3168,12 → 3334,13 |
ring = request->ring; |
seqno = request->seqno; |
} |
reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter); |
spin_unlock(&file_priv->mm.lock); |
|
if (seqno == 0) |
return 0; |
|
ret = __wait_seqno(ring, seqno, true, NULL); |
ret = __wait_seqno(ring, seqno, reset_counter, true, NULL); |
if (ret == 0) |
queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, 0); |
|
3247,6 → 3414,12 |
struct drm_i915_gem_object *obj; |
int ret; |
|
if(args->handle == -2) |
{ |
printf("%s handle %d\n", __FUNCTION__, args->handle); |
return 0; |
} |
|
ret = i915_mutex_lock_interruptible(dev); |
if (ret) |
return ret; |
3344,6 → 3517,12 |
if (ret) |
return ret; |
|
if(args->handle == -2) |
{ |
obj = get_fb_obj(); |
drm_gem_object_reference(&obj->base); |
} |
else |
obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle)); |
if (&obj->base == NULL) { |
ret = -ENOENT; |
3454,7 → 3633,7 |
{ |
struct drm_i915_gem_object *obj; |
struct address_space *mapping; |
u32 mask; |
gfp_t mask; |
|
obj = kzalloc(sizeof(*obj), GFP_KERNEL); |
if (obj == NULL) |
3565,6 → 3744,10 |
} |
i915_gem_retire_requests(dev); |
|
/* Under UMS, be paranoid and evict. */ |
if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
i915_gem_evict_everything(dev); |
|
i915_gem_reset_fences(dev); |
|
/* Hack! Don't let anybody do execbuf while we don't control the chip. |
3572,7 → 3755,7 |
* And not confound mm.suspended! |
*/ |
dev_priv->mm.suspended = 1; |
del_timer_sync(&dev_priv->hangcheck_timer); |
del_timer_sync(&dev_priv->gpu_error.hangcheck_timer); |
|
i915_kernel_lost_context(dev); |
i915_gem_cleanup_ringbuffer(dev); |
3592,7 → 3775,7 |
u32 misccpctl; |
int i; |
|
if (!IS_IVYBRIDGE(dev)) |
if (!HAS_L3_GPU_CACHE(dev)) |
return; |
|
if (!dev_priv->l3_parity.remap_info) |
3635,8 → 3818,10 |
I915_WRITE(TILECTL, I915_READ(TILECTL) | TILECTL_SWZCTL); |
if (IS_GEN6(dev)) |
I915_WRITE(ARB_MODE, _MASKED_BIT_ENABLE(ARB_MODE_SWIZZLE_SNB)); |
else if (IS_GEN7(dev)) |
I915_WRITE(ARB_MODE, _MASKED_BIT_ENABLE(ARB_MODE_SWIZZLE_IVB)); |
else |
I915_WRITE(ARB_MODE, _MASKED_BIT_ENABLE(ARB_MODE_SWIZZLE_IVB)); |
BUG(); |
} |
|
static bool |
3655,22 → 3840,11 |
return true; |
} |
|
int |
i915_gem_init_hw(struct drm_device *dev) |
static int i915_gem_init_rings(struct drm_device *dev) |
{ |
drm_i915_private_t *dev_priv = dev->dev_private; |
struct drm_i915_private *dev_priv = dev->dev_private; |
int ret; |
|
if (INTEL_INFO(dev)->gen < 6 && !intel_enable_gtt()) |
return -EIO; |
|
if (IS_HASWELL(dev) && (I915_READ(0x120010) == 1)) |
I915_WRITE(0x9008, I915_READ(0x9008) | 0xf0000); |
|
i915_gem_l3_remap(dev); |
|
i915_gem_init_swizzling(dev); |
|
ret = intel_init_render_ring_buffer(dev); |
if (ret) |
return ret; |
3687,37 → 3861,50 |
goto cleanup_bsd_ring; |
} |
|
dev_priv->next_seqno = 1; |
ret = i915_gem_set_seqno(dev, ((u32)~0 - 0x1000)); |
if (ret) |
goto cleanup_blt_ring; |
|
/* |
* XXX: There was some w/a described somewhere suggesting loading |
* contexts before PPGTT. |
*/ |
i915_gem_context_init(dev); |
i915_gem_init_ppgtt(dev); |
|
return 0; |
|
cleanup_blt_ring: |
intel_cleanup_ring_buffer(&dev_priv->ring[BCS]); |
cleanup_bsd_ring: |
intel_cleanup_ring_buffer(&dev_priv->ring[VCS]); |
cleanup_render_ring: |
intel_cleanup_ring_buffer(&dev_priv->ring[RCS]); |
|
return ret; |
} |
|
static bool |
intel_enable_ppgtt(struct drm_device *dev) |
int |
i915_gem_init_hw(struct drm_device *dev) |
{ |
if (i915_enable_ppgtt >= 0) |
return i915_enable_ppgtt; |
drm_i915_private_t *dev_priv = dev->dev_private; |
int ret; |
|
#ifdef CONFIG_INTEL_IOMMU |
/* Disable ppgtt on SNB if VT-d is on. */ |
if (INTEL_INFO(dev)->gen == 6 && intel_iommu_gfx_mapped) |
return false; |
#endif |
if (INTEL_INFO(dev)->gen < 6 && !intel_enable_gtt()) |
return -EIO; |
|
return true; |
if (IS_HASWELL(dev) && (I915_READ(0x120010) == 1)) |
I915_WRITE(0x9008, I915_READ(0x9008) | 0xf0000); |
|
i915_gem_l3_remap(dev); |
|
i915_gem_init_swizzling(dev); |
|
ret = i915_gem_init_rings(dev); |
if (ret) |
return ret; |
|
/* |
* XXX: There was some w/a described somewhere suggesting loading |
* contexts before PPGTT. |
*/ |
i915_gem_context_init(dev); |
i915_gem_init_ppgtt(dev); |
|
return 0; |
} |
|
#define LFB_SIZE 0xC00000 |
3725,39 → 3912,10 |
int i915_gem_init(struct drm_device *dev) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
unsigned long gtt_size, mappable_size; |
int ret; |
|
gtt_size = dev_priv->mm.gtt->gtt_total_entries << PAGE_SHIFT; |
mappable_size = dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT; |
|
mutex_lock(&dev->struct_mutex); |
if (intel_enable_ppgtt(dev) && HAS_ALIASING_PPGTT(dev)) { |
/* PPGTT pdes are stolen from global gtt ptes, so shrink the |
* aperture accordingly when using aliasing ppgtt. */ |
gtt_size -= I915_PPGTT_PD_ENTRIES*PAGE_SIZE; |
|
i915_gem_init_global_gtt(dev, LFB_SIZE, mappable_size, gtt_size - LFB_SIZE); |
|
ret = i915_gem_init_aliasing_ppgtt(dev); |
if (ret) { |
mutex_unlock(&dev->struct_mutex); |
return ret; |
} |
} else { |
/* Let GEM Manage all of the aperture. |
* |
* However, leave one page at the end still bound to the scratch |
* page. There are a number of places where the hardware |
* apparently prefetches past the end of the object, and we've |
* seen multiple hangs with the GPU head pointer stuck in a |
* batchbuffer bound at the last page of the aperture. One page |
* should be enough to keep any prefetching inside of the |
* aperture. |
*/ |
i915_gem_init_global_gtt(dev, LFB_SIZE, mappable_size, gtt_size - LFB_SIZE); |
} |
|
i915_gem_init_global_gtt(dev); |
ret = i915_gem_init_hw(dev); |
mutex_unlock(&dev->struct_mutex); |
if (ret) { |
3791,9 → 3949,9 |
if (drm_core_check_feature(dev, DRIVER_MODESET)) |
return 0; |
|
if (atomic_read(&dev_priv->mm.wedged)) { |
if (i915_reset_in_progress(&dev_priv->gpu_error)) { |
DRM_ERROR("Reenabling wedged hardware, good luck\n"); |
atomic_set(&dev_priv->mm.wedged, 0); |
atomic_set(&dev_priv->gpu_error.reset_counter, 0); |
} |
|
mutex_lock(&dev->struct_mutex); |
3858,8 → 4016,8 |
void |
i915_gem_load(struct drm_device *dev) |
{ |
drm_i915_private_t *dev_priv = dev->dev_private; |
int i; |
drm_i915_private_t *dev_priv = dev->dev_private; |
|
INIT_LIST_HEAD(&dev_priv->mm.active_list); |
INIT_LIST_HEAD(&dev_priv->mm.inactive_list); |
3872,6 → 4030,7 |
INIT_LIST_HEAD(&dev_priv->fence_regs[i].lru_list); |
INIT_DELAYED_WORK(&dev_priv->mm.retire_work, |
i915_gem_retire_work_handler); |
init_waitqueue_head(&dev_priv->gpu_error.reset_queue); |
|
/* On GEN3 we really need to make sure the ARB C3 LP bit is set */ |
if (IS_GEN3(dev)) { |