Merge tag 'drm-intel-next-2015-12-18' of git://anongit.freedesktop.org/drm-intel into drm-next
- fix atomic watermark recomputation logic (Maarten) - modeset sequence fixes for LPT (Ville) - more kbl enabling&prep work (Rodrigo, Wayne) - first bits for mst audio - page dirty tracking fixes from Dave Gordon - new get_eld hook from Takashi, also included in the sound tree - fixup cursor handling when placed at address 0 (Ville) - refactor VBT parsing code (Jani) - rpm wakelock debug infrastructure ( Imre) - fbdev is pinned again (Chris) - tune the busywait logic to avoid wasting cpu cycles (Chris) * tag 'drm-intel-next-2015-12-18' of git://anongit.freedesktop.org/drm-intel: (81 commits) drm/i915: Update DRIVER_DATE to 20151218 drm/i915/skl: Default to noncoherent access up to F0 drm/i915: Only spin whilst waiting on the current request drm/i915: Limit the busy wait on requests to 5us not 10ms! drm/i915: Break busywaiting for requests on pending signals drm/i915: don't enable autosuspend on platforms without RPM support drm/i915/backlight: prefer dev_priv over dev pointer drm/i915: Disable primary plane if we fail to reconstruct BIOS fb (v2) drm/i915: Pin the ifbdev for the info->system_base GGTT mmapping drm/i915: Set the map-and-fenceable flag for preallocated objects drm/i915: mdelay(10) considered harmful drm/i915: check that we are in an RPM atomic section in GGTT PTE updaters drm/i915: add support for checking RPM atomic sections drm/i915: check that we hold an RPM wakelock ref before we put it drm/i915: add support for checking if we hold an RPM reference drm/i915: use assert_rpm_wakelock_held instead of opencoding it drm/i915: add assert_rpm_wakelock_held helper drm/i915: remove HAS_RUNTIME_PM check from RPM get/put/assert helpers drm/i915: get a permanent RPM reference on platforms w/o RPM support drm/i915: refactor RPM disabling due to RC6 being disabled ...
This commit is contained in:
@@ -1146,23 +1146,74 @@ static bool missed_irq(struct drm_i915_private *dev_priv,
|
||||
return test_bit(ring->id, &dev_priv->gpu_error.missed_irq_rings);
|
||||
}
|
||||
|
||||
static int __i915_spin_request(struct drm_i915_gem_request *req)
|
||||
static unsigned long local_clock_us(unsigned *cpu)
|
||||
{
|
||||
unsigned long t;
|
||||
|
||||
/* Cheaply and approximately convert from nanoseconds to microseconds.
|
||||
* The result and subsequent calculations are also defined in the same
|
||||
* approximate microseconds units. The principal source of timing
|
||||
* error here is from the simple truncation.
|
||||
*
|
||||
* Note that local_clock() is only defined wrt to the current CPU;
|
||||
* the comparisons are no longer valid if we switch CPUs. Instead of
|
||||
* blocking preemption for the entire busywait, we can detect the CPU
|
||||
* switch and use that as indicator of system load and a reason to
|
||||
* stop busywaiting, see busywait_stop().
|
||||
*/
|
||||
*cpu = get_cpu();
|
||||
t = local_clock() >> 10;
|
||||
put_cpu();
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
static bool busywait_stop(unsigned long timeout, unsigned cpu)
|
||||
{
|
||||
unsigned this_cpu;
|
||||
|
||||
if (time_after(local_clock_us(&this_cpu), timeout))
|
||||
return true;
|
||||
|
||||
return this_cpu != cpu;
|
||||
}
|
||||
|
||||
static int __i915_spin_request(struct drm_i915_gem_request *req, int state)
|
||||
{
|
||||
unsigned long timeout;
|
||||
unsigned cpu;
|
||||
|
||||
if (i915_gem_request_get_ring(req)->irq_refcount)
|
||||
/* When waiting for high frequency requests, e.g. during synchronous
|
||||
* rendering split between the CPU and GPU, the finite amount of time
|
||||
* required to set up the irq and wait upon it limits the response
|
||||
* rate. By busywaiting on the request completion for a short while we
|
||||
* can service the high frequency waits as quick as possible. However,
|
||||
* if it is a slow request, we want to sleep as quickly as possible.
|
||||
* The tradeoff between waiting and sleeping is roughly the time it
|
||||
* takes to sleep on a request, on the order of a microsecond.
|
||||
*/
|
||||
|
||||
if (req->ring->irq_refcount)
|
||||
return -EBUSY;
|
||||
|
||||
timeout = jiffies + 1;
|
||||
/* Only spin if we know the GPU is processing this request */
|
||||
if (!i915_gem_request_started(req, true))
|
||||
return -EAGAIN;
|
||||
|
||||
timeout = local_clock_us(&cpu) + 5;
|
||||
while (!need_resched()) {
|
||||
if (i915_gem_request_completed(req, true))
|
||||
return 0;
|
||||
|
||||
if (time_after_eq(jiffies, timeout))
|
||||
if (signal_pending_state(state, current))
|
||||
break;
|
||||
|
||||
if (busywait_stop(timeout, cpu))
|
||||
break;
|
||||
|
||||
cpu_relax_lowlatency();
|
||||
}
|
||||
|
||||
if (i915_gem_request_completed(req, false))
|
||||
return 0;
|
||||
|
||||
@@ -1197,6 +1248,7 @@ int __i915_wait_request(struct drm_i915_gem_request *req,
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
const bool irq_test_in_progress =
|
||||
ACCESS_ONCE(dev_priv->gpu_error.test_irq_rings) & intel_ring_flag(ring);
|
||||
int state = interruptible ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE;
|
||||
DEFINE_WAIT(wait);
|
||||
unsigned long timeout_expire;
|
||||
s64 before, now;
|
||||
@@ -1229,7 +1281,7 @@ int __i915_wait_request(struct drm_i915_gem_request *req,
|
||||
before = ktime_get_raw_ns();
|
||||
|
||||
/* Optimistic spin for the next jiffie before touching IRQs */
|
||||
ret = __i915_spin_request(req);
|
||||
ret = __i915_spin_request(req, state);
|
||||
if (ret == 0)
|
||||
goto out;
|
||||
|
||||
@@ -1241,8 +1293,7 @@ int __i915_wait_request(struct drm_i915_gem_request *req,
|
||||
for (;;) {
|
||||
struct timer_list timer;
|
||||
|
||||
prepare_to_wait(&ring->irq_queue, &wait,
|
||||
interruptible ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
|
||||
prepare_to_wait(&ring->irq_queue, &wait, state);
|
||||
|
||||
/* We need to check whether any gpu reset happened in between
|
||||
* the caller grabbing the seqno and now ... */
|
||||
@@ -1260,7 +1311,7 @@ int __i915_wait_request(struct drm_i915_gem_request *req,
|
||||
break;
|
||||
}
|
||||
|
||||
if (interruptible && signal_pending(current)) {
|
||||
if (signal_pending_state(state, current)) {
|
||||
ret = -ERESTARTSYS;
|
||||
break;
|
||||
}
|
||||
@@ -2554,6 +2605,7 @@ void __i915_add_request(struct drm_i915_gem_request *request,
|
||||
request->batch_obj = obj;
|
||||
|
||||
request->emitted_jiffies = jiffies;
|
||||
request->previous_seqno = ring->last_submitted_seqno;
|
||||
ring->last_submitted_seqno = request->seqno;
|
||||
list_add_tail(&request->list, &ring->request_list);
|
||||
|
||||
@@ -2765,20 +2817,13 @@ static void i915_gem_reset_ring_cleanup(struct drm_i915_private *dev_priv,
|
||||
|
||||
if (i915.enable_execlists) {
|
||||
spin_lock_irq(&ring->execlist_lock);
|
||||
while (!list_empty(&ring->execlist_queue)) {
|
||||
struct drm_i915_gem_request *submit_req;
|
||||
|
||||
submit_req = list_first_entry(&ring->execlist_queue,
|
||||
struct drm_i915_gem_request,
|
||||
execlist_link);
|
||||
list_del(&submit_req->execlist_link);
|
||||
/* list_splice_tail_init checks for empty lists */
|
||||
list_splice_tail_init(&ring->execlist_queue,
|
||||
&ring->execlist_retired_req_list);
|
||||
|
||||
if (submit_req->ctx != ring->default_context)
|
||||
intel_lr_context_unpin(submit_req);
|
||||
|
||||
i915_gem_request_unreference(submit_req);
|
||||
}
|
||||
spin_unlock_irq(&ring->execlist_lock);
|
||||
intel_execlists_retire_requests(ring);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3480,30 +3525,50 @@ i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj,
|
||||
if (IS_ERR(vma))
|
||||
goto err_unpin;
|
||||
|
||||
if (flags & PIN_HIGH) {
|
||||
search_flag = DRM_MM_SEARCH_BELOW;
|
||||
alloc_flag = DRM_MM_CREATE_TOP;
|
||||
if (flags & PIN_OFFSET_FIXED) {
|
||||
uint64_t offset = flags & PIN_OFFSET_MASK;
|
||||
|
||||
if (offset & (alignment - 1) || offset + size > end) {
|
||||
ret = -EINVAL;
|
||||
goto err_free_vma;
|
||||
}
|
||||
vma->node.start = offset;
|
||||
vma->node.size = size;
|
||||
vma->node.color = obj->cache_level;
|
||||
ret = drm_mm_reserve_node(&vm->mm, &vma->node);
|
||||
if (ret) {
|
||||
ret = i915_gem_evict_for_vma(vma);
|
||||
if (ret == 0)
|
||||
ret = drm_mm_reserve_node(&vm->mm, &vma->node);
|
||||
}
|
||||
if (ret)
|
||||
goto err_free_vma;
|
||||
} else {
|
||||
search_flag = DRM_MM_SEARCH_DEFAULT;
|
||||
alloc_flag = DRM_MM_CREATE_DEFAULT;
|
||||
}
|
||||
if (flags & PIN_HIGH) {
|
||||
search_flag = DRM_MM_SEARCH_BELOW;
|
||||
alloc_flag = DRM_MM_CREATE_TOP;
|
||||
} else {
|
||||
search_flag = DRM_MM_SEARCH_DEFAULT;
|
||||
alloc_flag = DRM_MM_CREATE_DEFAULT;
|
||||
}
|
||||
|
||||
search_free:
|
||||
ret = drm_mm_insert_node_in_range_generic(&vm->mm, &vma->node,
|
||||
size, alignment,
|
||||
obj->cache_level,
|
||||
start, end,
|
||||
search_flag,
|
||||
alloc_flag);
|
||||
if (ret) {
|
||||
ret = i915_gem_evict_something(dev, vm, size, alignment,
|
||||
obj->cache_level,
|
||||
start, end,
|
||||
flags);
|
||||
if (ret == 0)
|
||||
goto search_free;
|
||||
ret = drm_mm_insert_node_in_range_generic(&vm->mm, &vma->node,
|
||||
size, alignment,
|
||||
obj->cache_level,
|
||||
start, end,
|
||||
search_flag,
|
||||
alloc_flag);
|
||||
if (ret) {
|
||||
ret = i915_gem_evict_something(dev, vm, size, alignment,
|
||||
obj->cache_level,
|
||||
start, end,
|
||||
flags);
|
||||
if (ret == 0)
|
||||
goto search_free;
|
||||
|
||||
goto err_free_vma;
|
||||
goto err_free_vma;
|
||||
}
|
||||
}
|
||||
if (WARN_ON(!i915_gem_valid_gtt_space(vma, obj->cache_level))) {
|
||||
ret = -EINVAL;
|
||||
@@ -4094,9 +4159,36 @@ i915_vma_misplaced(struct i915_vma *vma, uint32_t alignment, uint64_t flags)
|
||||
vma->node.start < (flags & PIN_OFFSET_MASK))
|
||||
return true;
|
||||
|
||||
if (flags & PIN_OFFSET_FIXED &&
|
||||
vma->node.start != (flags & PIN_OFFSET_MASK))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void __i915_vma_set_map_and_fenceable(struct i915_vma *vma)
|
||||
{
|
||||
struct drm_i915_gem_object *obj = vma->obj;
|
||||
bool mappable, fenceable;
|
||||
u32 fence_size, fence_alignment;
|
||||
|
||||
fence_size = i915_gem_get_gtt_size(obj->base.dev,
|
||||
obj->base.size,
|
||||
obj->tiling_mode);
|
||||
fence_alignment = i915_gem_get_gtt_alignment(obj->base.dev,
|
||||
obj->base.size,
|
||||
obj->tiling_mode,
|
||||
true);
|
||||
|
||||
fenceable = (vma->node.size == fence_size &&
|
||||
(vma->node.start & (fence_alignment - 1)) == 0);
|
||||
|
||||
mappable = (vma->node.start + fence_size <=
|
||||
to_i915(obj->base.dev)->gtt.mappable_end);
|
||||
|
||||
obj->map_and_fenceable = mappable && fenceable;
|
||||
}
|
||||
|
||||
static int
|
||||
i915_gem_object_do_pin(struct drm_i915_gem_object *obj,
|
||||
struct i915_address_space *vm,
|
||||
@@ -4164,25 +4256,7 @@ i915_gem_object_do_pin(struct drm_i915_gem_object *obj,
|
||||
|
||||
if (ggtt_view && ggtt_view->type == I915_GGTT_VIEW_NORMAL &&
|
||||
(bound ^ vma->bound) & GLOBAL_BIND) {
|
||||
bool mappable, fenceable;
|
||||
u32 fence_size, fence_alignment;
|
||||
|
||||
fence_size = i915_gem_get_gtt_size(obj->base.dev,
|
||||
obj->base.size,
|
||||
obj->tiling_mode);
|
||||
fence_alignment = i915_gem_get_gtt_alignment(obj->base.dev,
|
||||
obj->base.size,
|
||||
obj->tiling_mode,
|
||||
true);
|
||||
|
||||
fenceable = (vma->node.size == fence_size &&
|
||||
(vma->node.start & (fence_alignment - 1)) == 0);
|
||||
|
||||
mappable = (vma->node.start + fence_size <=
|
||||
dev_priv->gtt.mappable_end);
|
||||
|
||||
obj->map_and_fenceable = mappable && fenceable;
|
||||
|
||||
__i915_vma_set_map_and_fenceable(vma);
|
||||
WARN_ON(flags & PIN_MAPPABLE && !obj->map_and_fenceable);
|
||||
}
|
||||
|
||||
@@ -4842,14 +4916,6 @@ int i915_gem_init(struct drm_device *dev)
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
|
||||
if (IS_VALLEYVIEW(dev)) {
|
||||
/* VLVA0 (potential hack), BIOS isn't actually waking us */
|
||||
I915_WRITE(VLV_GTLC_WAKE_CTRL, VLV_GTLC_ALLOWWAKEREQ);
|
||||
if (wait_for((I915_READ(VLV_GTLC_PW_STATUS) &
|
||||
VLV_GTLC_ALLOWWAKEACK), 10))
|
||||
DRM_DEBUG_DRIVER("allow wake ack timed out\n");
|
||||
}
|
||||
|
||||
if (!i915.enable_execlists) {
|
||||
dev_priv->gt.execbuf_submit = i915_gem_ringbuffer_submission;
|
||||
dev_priv->gt.init_rings = i915_gem_init_rings;
|
||||
@@ -4967,7 +5033,7 @@ i915_gem_load(struct drm_device *dev)
|
||||
|
||||
dev_priv->relative_constants_mode = I915_EXEC_CONSTANTS_REL_GENERAL;
|
||||
|
||||
if (INTEL_INFO(dev)->gen >= 7 && !IS_VALLEYVIEW(dev))
|
||||
if (INTEL_INFO(dev)->gen >= 7 && !IS_VALLEYVIEW(dev) && !IS_CHERRYVIEW(dev))
|
||||
dev_priv->num_fence_regs = 32;
|
||||
else if (INTEL_INFO(dev)->gen >= 4 || IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
|
||||
dev_priv->num_fence_regs = 16;
|
||||
@@ -5188,6 +5254,21 @@ bool i915_gem_obj_is_pinned(struct drm_i915_gem_object *obj)
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Like i915_gem_object_get_page(), but mark the returned page dirty */
|
||||
struct page *
|
||||
i915_gem_object_get_dirty_page(struct drm_i915_gem_object *obj, int n)
|
||||
{
|
||||
struct page *page;
|
||||
|
||||
/* Only default objects have per-page dirty tracking */
|
||||
if (WARN_ON(obj->ops != &i915_gem_object_ops))
|
||||
return NULL;
|
||||
|
||||
page = i915_gem_object_get_page(obj, n);
|
||||
set_page_dirty(page);
|
||||
return page;
|
||||
}
|
||||
|
||||
/* Allocate a new GEM object and fill it with the supplied data */
|
||||
struct drm_i915_gem_object *
|
||||
i915_gem_object_create_from_data(struct drm_device *dev,
|
||||
@@ -5213,6 +5294,7 @@ i915_gem_object_create_from_data(struct drm_device *dev,
|
||||
i915_gem_object_pin_pages(obj);
|
||||
sg = obj->pages;
|
||||
bytes = sg_copy_from_buffer(sg->sgl, sg->nents, (void *)data, size);
|
||||
obj->dirty = 1; /* Backing store is now out of date */
|
||||
i915_gem_object_unpin_pages(obj);
|
||||
|
||||
if (WARN_ON(bytes != size)) {
|
||||
|
Reference in New Issue
Block a user