Merge branch 'drm-next' of git://people.freedesktop.org/~airlied/linux
Pull drm merge from Dave Airlie:
"Highlights:
- TI LCD controller KMS driver
- TI OMAP KMS driver merged from staging
- drop gma500 stub driver
- the fbcon locking fixes
- the vgacon dirty like zebra fix.
- open firmware videomode and hdmi common code helpers
- major locking rework for kms object handling - pageflip/cursor
won't block on polling anymore!
- fbcon helper and prime helper cleanups
- i915: all over the map, haswell power well enhancements, valleyview
macro horrors cleaned up, killing lots of legacy GTT code,
- radeon: CS ioctl unification, deprecated UMS support, gpu reset
rework, VM fixes
- nouveau: reworked thermal code, external dp/tmds encoder support
(anx9805), fences sleep instead of polling,
- exynos: all over the driver fixes."
Lovely conflict in radeon/evergreen_cs.c between commit de0babd60d
("drm/radeon: enforce use of radeon_get_ib_value when reading user cmd")
and the new changes that modified that evergreen_dma_cs_parse()
function.
* 'drm-next' of git://people.freedesktop.org/~airlied/linux: (508 commits)
drm/tilcdc: only build on arm
drm/i915: Revert hdmi HDP pin checks
drm/tegra: Add list of framebuffers to debugfs
drm/tegra: Fix color expansion
drm/tegra: Split DC_CMD_STATE_CONTROL register write
drm/tegra: Implement page-flipping support
drm/tegra: Implement VBLANK support
drm/tegra: Implement .mode_set_base()
drm/tegra: Add plane support
drm/tegra: Remove bogus tegra_framebuffer structure
drm: Add consistency check for page-flipping
drm/radeon: Use generic HDMI infoframe helpers
drm/tegra: Use generic HDMI infoframe helpers
drm: Add EDID helper documentation
drm: Add HDMI infoframe helpers
video: Add generic HDMI infoframe helpers
drm: Add some missing forward declarations
drm: Move mode tables to drm_edid.c
drm: Remove duplicate drm_mode_cea_vic()
gma500: Fix n, m1 and m2 clock limits for sdvo and lvds
...
Цей коміт міститься в:
@@ -158,7 +158,8 @@ static void ttm_bo_release_list(struct kref *list_kref)
|
||||
ttm_mem_global_free(bdev->glob->mem_glob, acc_size);
|
||||
}
|
||||
|
||||
int ttm_bo_wait_unreserved(struct ttm_buffer_object *bo, bool interruptible)
|
||||
static int ttm_bo_wait_unreserved(struct ttm_buffer_object *bo,
|
||||
bool interruptible)
|
||||
{
|
||||
if (interruptible) {
|
||||
return wait_event_interruptible(bo->event_queue,
|
||||
@@ -168,7 +169,6 @@ int ttm_bo_wait_unreserved(struct ttm_buffer_object *bo, bool interruptible)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(ttm_bo_wait_unreserved);
|
||||
|
||||
void ttm_bo_add_to_lru(struct ttm_buffer_object *bo)
|
||||
{
|
||||
@@ -213,14 +213,13 @@ int ttm_bo_del_from_lru(struct ttm_buffer_object *bo)
|
||||
return put_count;
|
||||
}
|
||||
|
||||
int ttm_bo_reserve_locked(struct ttm_buffer_object *bo,
|
||||
int ttm_bo_reserve_nolru(struct ttm_buffer_object *bo,
|
||||
bool interruptible,
|
||||
bool no_wait, bool use_sequence, uint32_t sequence)
|
||||
{
|
||||
struct ttm_bo_global *glob = bo->glob;
|
||||
int ret;
|
||||
|
||||
while (unlikely(atomic_read(&bo->reserved) != 0)) {
|
||||
while (unlikely(atomic_xchg(&bo->reserved, 1) != 0)) {
|
||||
/**
|
||||
* Deadlock avoidance for multi-bo reserving.
|
||||
*/
|
||||
@@ -241,26 +240,36 @@ int ttm_bo_reserve_locked(struct ttm_buffer_object *bo,
|
||||
if (no_wait)
|
||||
return -EBUSY;
|
||||
|
||||
spin_unlock(&glob->lru_lock);
|
||||
ret = ttm_bo_wait_unreserved(bo, interruptible);
|
||||
spin_lock(&glob->lru_lock);
|
||||
|
||||
if (unlikely(ret))
|
||||
return ret;
|
||||
}
|
||||
|
||||
atomic_set(&bo->reserved, 1);
|
||||
if (use_sequence) {
|
||||
bool wake_up = false;
|
||||
/**
|
||||
* Wake up waiters that may need to recheck for deadlock,
|
||||
* if we decreased the sequence number.
|
||||
*/
|
||||
if (unlikely((bo->val_seq - sequence < (1 << 31))
|
||||
|| !bo->seq_valid))
|
||||
wake_up_all(&bo->event_queue);
|
||||
wake_up = true;
|
||||
|
||||
/*
|
||||
* In the worst case with memory ordering these values can be
|
||||
* seen in the wrong order. However since we call wake_up_all
|
||||
* in that case, this will hopefully not pose a problem,
|
||||
* and the worst case would only cause someone to accidentally
|
||||
* hit -EAGAIN in ttm_bo_reserve when they see old value of
|
||||
* val_seq. However this would only happen if seq_valid was
|
||||
* written before val_seq was, and just means some slightly
|
||||
* increased cpu usage
|
||||
*/
|
||||
bo->val_seq = sequence;
|
||||
bo->seq_valid = true;
|
||||
if (wake_up)
|
||||
wake_up_all(&bo->event_queue);
|
||||
} else {
|
||||
bo->seq_valid = false;
|
||||
}
|
||||
@@ -289,18 +298,65 @@ int ttm_bo_reserve(struct ttm_buffer_object *bo,
|
||||
int put_count = 0;
|
||||
int ret;
|
||||
|
||||
spin_lock(&glob->lru_lock);
|
||||
ret = ttm_bo_reserve_locked(bo, interruptible, no_wait, use_sequence,
|
||||
sequence);
|
||||
if (likely(ret == 0))
|
||||
ret = ttm_bo_reserve_nolru(bo, interruptible, no_wait, use_sequence,
|
||||
sequence);
|
||||
if (likely(ret == 0)) {
|
||||
spin_lock(&glob->lru_lock);
|
||||
put_count = ttm_bo_del_from_lru(bo);
|
||||
spin_unlock(&glob->lru_lock);
|
||||
|
||||
ttm_bo_list_ref_sub(bo, put_count, true);
|
||||
spin_unlock(&glob->lru_lock);
|
||||
ttm_bo_list_ref_sub(bo, put_count, true);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ttm_bo_reserve_slowpath_nolru(struct ttm_buffer_object *bo,
|
||||
bool interruptible, uint32_t sequence)
|
||||
{
|
||||
bool wake_up = false;
|
||||
int ret;
|
||||
|
||||
while (unlikely(atomic_xchg(&bo->reserved, 1) != 0)) {
|
||||
WARN_ON(bo->seq_valid && sequence == bo->val_seq);
|
||||
|
||||
ret = ttm_bo_wait_unreserved(bo, interruptible);
|
||||
|
||||
if (unlikely(ret))
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ((bo->val_seq - sequence < (1 << 31)) || !bo->seq_valid)
|
||||
wake_up = true;
|
||||
|
||||
/**
|
||||
* Wake up waiters that may need to recheck for deadlock,
|
||||
* if we decreased the sequence number.
|
||||
*/
|
||||
bo->val_seq = sequence;
|
||||
bo->seq_valid = true;
|
||||
if (wake_up)
|
||||
wake_up_all(&bo->event_queue);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ttm_bo_reserve_slowpath(struct ttm_buffer_object *bo,
|
||||
bool interruptible, uint32_t sequence)
|
||||
{
|
||||
struct ttm_bo_global *glob = bo->glob;
|
||||
int put_count, ret;
|
||||
|
||||
ret = ttm_bo_reserve_slowpath_nolru(bo, interruptible, sequence);
|
||||
if (likely(!ret)) {
|
||||
spin_lock(&glob->lru_lock);
|
||||
put_count = ttm_bo_del_from_lru(bo);
|
||||
spin_unlock(&glob->lru_lock);
|
||||
ttm_bo_list_ref_sub(bo, put_count, true);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(ttm_bo_reserve_slowpath);
|
||||
|
||||
void ttm_bo_unreserve_locked(struct ttm_buffer_object *bo)
|
||||
{
|
||||
ttm_bo_add_to_lru(bo);
|
||||
@@ -511,7 +567,7 @@ static void ttm_bo_cleanup_refs_or_queue(struct ttm_buffer_object *bo)
|
||||
int ret;
|
||||
|
||||
spin_lock(&glob->lru_lock);
|
||||
ret = ttm_bo_reserve_locked(bo, false, true, false, 0);
|
||||
ret = ttm_bo_reserve_nolru(bo, false, true, false, 0);
|
||||
|
||||
spin_lock(&bdev->fence_lock);
|
||||
(void) ttm_bo_wait(bo, false, false, true);
|
||||
@@ -604,7 +660,7 @@ static int ttm_bo_cleanup_refs_and_unlock(struct ttm_buffer_object *bo,
|
||||
return ret;
|
||||
|
||||
spin_lock(&glob->lru_lock);
|
||||
ret = ttm_bo_reserve_locked(bo, false, true, false, 0);
|
||||
ret = ttm_bo_reserve_nolru(bo, false, true, false, 0);
|
||||
|
||||
/*
|
||||
* We raced, and lost, someone else holds the reservation now,
|
||||
@@ -668,7 +724,14 @@ static int ttm_bo_delayed_delete(struct ttm_bo_device *bdev, bool remove_all)
|
||||
kref_get(&nentry->list_kref);
|
||||
}
|
||||
|
||||
ret = ttm_bo_reserve_locked(entry, false, !remove_all, false, 0);
|
||||
ret = ttm_bo_reserve_nolru(entry, false, true, false, 0);
|
||||
if (remove_all && ret) {
|
||||
spin_unlock(&glob->lru_lock);
|
||||
ret = ttm_bo_reserve_nolru(entry, false, false,
|
||||
false, 0);
|
||||
spin_lock(&glob->lru_lock);
|
||||
}
|
||||
|
||||
if (!ret)
|
||||
ret = ttm_bo_cleanup_refs_and_unlock(entry, false,
|
||||
!remove_all);
|
||||
@@ -816,7 +879,7 @@ static int ttm_mem_evict_first(struct ttm_bo_device *bdev,
|
||||
|
||||
spin_lock(&glob->lru_lock);
|
||||
list_for_each_entry(bo, &man->lru, lru) {
|
||||
ret = ttm_bo_reserve_locked(bo, false, true, false, 0);
|
||||
ret = ttm_bo_reserve_nolru(bo, false, true, false, 0);
|
||||
if (!ret)
|
||||
break;
|
||||
}
|
||||
@@ -1797,7 +1860,7 @@ static int ttm_bo_swapout(struct ttm_mem_shrink *shrink)
|
||||
|
||||
spin_lock(&glob->lru_lock);
|
||||
list_for_each_entry(bo, &glob->swap_lru, swap) {
|
||||
ret = ttm_bo_reserve_locked(bo, false, true, false, 0);
|
||||
ret = ttm_bo_reserve_nolru(bo, false, true, false, 0);
|
||||
if (!ret)
|
||||
break;
|
||||
}
|
||||
|
@@ -82,22 +82,6 @@ static void ttm_eu_list_ref_sub(struct list_head *list)
|
||||
}
|
||||
}
|
||||
|
||||
static int ttm_eu_wait_unreserved_locked(struct list_head *list,
|
||||
struct ttm_buffer_object *bo)
|
||||
{
|
||||
struct ttm_bo_global *glob = bo->glob;
|
||||
int ret;
|
||||
|
||||
ttm_eu_del_from_lru_locked(list);
|
||||
spin_unlock(&glob->lru_lock);
|
||||
ret = ttm_bo_wait_unreserved(bo, true);
|
||||
spin_lock(&glob->lru_lock);
|
||||
if (unlikely(ret != 0))
|
||||
ttm_eu_backoff_reservation_locked(list);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void ttm_eu_backoff_reservation(struct list_head *list)
|
||||
{
|
||||
struct ttm_validate_buffer *entry;
|
||||
@@ -145,47 +129,65 @@ int ttm_eu_reserve_buffers(struct list_head *list)
|
||||
entry = list_first_entry(list, struct ttm_validate_buffer, head);
|
||||
glob = entry->bo->glob;
|
||||
|
||||
retry:
|
||||
spin_lock(&glob->lru_lock);
|
||||
val_seq = entry->bo->bdev->val_seq++;
|
||||
|
||||
retry:
|
||||
list_for_each_entry(entry, list, head) {
|
||||
struct ttm_buffer_object *bo = entry->bo;
|
||||
|
||||
retry_this_bo:
|
||||
ret = ttm_bo_reserve_locked(bo, true, true, true, val_seq);
|
||||
/* already slowpath reserved? */
|
||||
if (entry->reserved)
|
||||
continue;
|
||||
|
||||
ret = ttm_bo_reserve_nolru(bo, true, true, true, val_seq);
|
||||
switch (ret) {
|
||||
case 0:
|
||||
break;
|
||||
case -EBUSY:
|
||||
ret = ttm_eu_wait_unreserved_locked(list, bo);
|
||||
if (unlikely(ret != 0)) {
|
||||
spin_unlock(&glob->lru_lock);
|
||||
ttm_eu_list_ref_sub(list);
|
||||
return ret;
|
||||
}
|
||||
goto retry_this_bo;
|
||||
ttm_eu_del_from_lru_locked(list);
|
||||
spin_unlock(&glob->lru_lock);
|
||||
ret = ttm_bo_reserve_nolru(bo, true, false,
|
||||
true, val_seq);
|
||||
spin_lock(&glob->lru_lock);
|
||||
if (!ret)
|
||||
break;
|
||||
|
||||
if (unlikely(ret != -EAGAIN))
|
||||
goto err;
|
||||
|
||||
/* fallthrough */
|
||||
case -EAGAIN:
|
||||
ttm_eu_backoff_reservation_locked(list);
|
||||
|
||||
/*
|
||||
* temporarily increase sequence number every retry,
|
||||
* to prevent us from seeing our old reservation
|
||||
* sequence when someone else reserved the buffer,
|
||||
* but hasn't updated the seq_valid/seqno members yet.
|
||||
*/
|
||||
val_seq = entry->bo->bdev->val_seq++;
|
||||
|
||||
spin_unlock(&glob->lru_lock);
|
||||
ttm_eu_list_ref_sub(list);
|
||||
ret = ttm_bo_wait_unreserved(bo, true);
|
||||
ret = ttm_bo_reserve_slowpath_nolru(bo, true, val_seq);
|
||||
if (unlikely(ret != 0))
|
||||
return ret;
|
||||
spin_lock(&glob->lru_lock);
|
||||
entry->reserved = true;
|
||||
if (unlikely(atomic_read(&bo->cpu_writers) > 0)) {
|
||||
ret = -EBUSY;
|
||||
goto err;
|
||||
}
|
||||
goto retry;
|
||||
default:
|
||||
ttm_eu_backoff_reservation_locked(list);
|
||||
spin_unlock(&glob->lru_lock);
|
||||
ttm_eu_list_ref_sub(list);
|
||||
return ret;
|
||||
goto err;
|
||||
}
|
||||
|
||||
entry->reserved = true;
|
||||
if (unlikely(atomic_read(&bo->cpu_writers) > 0)) {
|
||||
ttm_eu_backoff_reservation_locked(list);
|
||||
spin_unlock(&glob->lru_lock);
|
||||
ttm_eu_list_ref_sub(list);
|
||||
return -EBUSY;
|
||||
ret = -EBUSY;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,6 +196,12 @@ retry_this_bo:
|
||||
ttm_eu_list_ref_sub(list);
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
ttm_eu_backoff_reservation_locked(list);
|
||||
spin_unlock(&glob->lru_lock);
|
||||
ttm_eu_list_ref_sub(list);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(ttm_eu_reserve_buffers);
|
||||
|
||||
|
Посилання в новій задачі
Заблокувати користувача