Skip to content

Commit

Permalink
Merge tag 'drm-intel-fixes-2019-11-21' of git://anongit.freedesktop.o…
Browse files Browse the repository at this point in the history
…rg/drm/drm-intel into drm-fixes

- Fix kernel oops on dumb_create ioctl on no crtc situation
- Fix bad ugly colored flash on VLV/CHV related to gamma LUT update
- Fix unity of the frequencies reported on PMU
- Fix kernel oops on set_page_dirty using better locks around it
- Protect the request pointer with RCU to prevent it being freed while we might need still
- Make pool objects read-only
- Restore physical addresses for fb_map to avoid corrupted page table

Signed-off-by: Dave Airlie <airlied@redhat.com>

From: Rodrigo Vivi <rodrigo.vivi@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20191121165339.GA23920@intel.com
  • Loading branch information
airlied committed Nov 22, 2019
2 parents f824c1b + 71d1226 commit 51658c0
Show file tree
Hide file tree
Showing 9 changed files with 141 additions and 18 deletions.
1 change: 1 addition & 0 deletions drivers/gpu/drm/i915/display/intel_atomic.c
Expand Up @@ -201,6 +201,7 @@ intel_crtc_duplicate_state(struct drm_crtc *crtc)
crtc_state->update_wm_post = false;
crtc_state->fb_changed = false;
crtc_state->fifo_changed = false;
crtc_state->preload_luts = false;
crtc_state->wm.need_postvbl_update = false;
crtc_state->fb_bits = 0;
crtc_state->update_planes = 0;
Expand Down
61 changes: 61 additions & 0 deletions drivers/gpu/drm/i915/display/intel_color.c
Expand Up @@ -990,6 +990,55 @@ void intel_color_commit(const struct intel_crtc_state *crtc_state)
dev_priv->display.color_commit(crtc_state);
}

static bool intel_can_preload_luts(const struct intel_crtc_state *new_crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->base.crtc);
struct intel_atomic_state *state =
to_intel_atomic_state(new_crtc_state->base.state);
const struct intel_crtc_state *old_crtc_state =
intel_atomic_get_old_crtc_state(state, crtc);

return !old_crtc_state->base.gamma_lut &&
!old_crtc_state->base.degamma_lut;
}

static bool chv_can_preload_luts(const struct intel_crtc_state *new_crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->base.crtc);
struct intel_atomic_state *state =
to_intel_atomic_state(new_crtc_state->base.state);
const struct intel_crtc_state *old_crtc_state =
intel_atomic_get_old_crtc_state(state, crtc);

/*
* CGM_PIPE_MODE is itself single buffered. We'd have to
* somehow split it out from chv_load_luts() if we wanted
* the ability to preload the CGM LUTs/CSC without tearing.
*/
if (old_crtc_state->cgm_mode || new_crtc_state->cgm_mode)
return false;

return !old_crtc_state->base.gamma_lut;
}

static bool glk_can_preload_luts(const struct intel_crtc_state *new_crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->base.crtc);
struct intel_atomic_state *state =
to_intel_atomic_state(new_crtc_state->base.state);
const struct intel_crtc_state *old_crtc_state =
intel_atomic_get_old_crtc_state(state, crtc);

/*
* The hardware degamma is active whenever the pipe
* CSC is active. Thus even if the old state has no
* software degamma we need to avoid clobbering the
* linear hardware degamma mid scanout.
*/
return !old_crtc_state->csc_enable &&
!old_crtc_state->base.gamma_lut;
}

int intel_color_check(struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *dev_priv = to_i915(crtc_state->base.crtc->dev);
Expand Down Expand Up @@ -1133,6 +1182,8 @@ static int i9xx_color_check(struct intel_crtc_state *crtc_state)
if (ret)
return ret;

crtc_state->preload_luts = intel_can_preload_luts(crtc_state);

return 0;
}

Expand Down Expand Up @@ -1185,6 +1236,8 @@ static int chv_color_check(struct intel_crtc_state *crtc_state)
if (ret)
return ret;

crtc_state->preload_luts = chv_can_preload_luts(crtc_state);

return 0;
}

Expand Down Expand Up @@ -1224,6 +1277,8 @@ static int ilk_color_check(struct intel_crtc_state *crtc_state)
if (ret)
return ret;

crtc_state->preload_luts = intel_can_preload_luts(crtc_state);

return 0;
}

Expand Down Expand Up @@ -1281,6 +1336,8 @@ static int ivb_color_check(struct intel_crtc_state *crtc_state)
if (ret)
return ret;

crtc_state->preload_luts = intel_can_preload_luts(crtc_state);

return 0;
}

Expand Down Expand Up @@ -1319,6 +1376,8 @@ static int glk_color_check(struct intel_crtc_state *crtc_state)
if (ret)
return ret;

crtc_state->preload_luts = glk_can_preload_luts(crtc_state);

return 0;
}

Expand Down Expand Up @@ -1368,6 +1427,8 @@ static int icl_color_check(struct intel_crtc_state *crtc_state)

crtc_state->csc_mode = icl_csc_mode(crtc_state);

crtc_state->preload_luts = intel_can_preload_luts(crtc_state);

return 0;
}

Expand Down
9 changes: 9 additions & 0 deletions drivers/gpu/drm/i915/display/intel_display.c
Expand Up @@ -2504,6 +2504,9 @@ u32 intel_plane_fb_max_stride(struct drm_i915_private *dev_priv,
* the highest stride limits of them all.
*/
crtc = intel_get_crtc_for_pipe(dev_priv, PIPE_A);
if (!crtc)
return 0;

plane = to_intel_plane(crtc->base.primary);

return plane->max_stride(plane, pixel_format, modifier,
Expand Down Expand Up @@ -13740,6 +13743,11 @@ static void intel_update_crtc(struct intel_crtc *crtc,
/* vblanks work again, re-enable pipe CRC. */
intel_crtc_enable_pipe_crc(crtc);
} else {
if (new_crtc_state->preload_luts &&
(new_crtc_state->base.color_mgmt_changed ||
new_crtc_state->update_pipe))
intel_color_load_luts(new_crtc_state);

intel_pre_plane_update(old_crtc_state, new_crtc_state);

if (new_crtc_state->update_pipe)
Expand Down Expand Up @@ -14034,6 +14042,7 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state)
for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) {
if (new_crtc_state->base.active &&
!needs_modeset(new_crtc_state) &&
!new_crtc_state->preload_luts &&
(new_crtc_state->base.color_mgmt_changed ||
new_crtc_state->update_pipe))
intel_color_load_luts(new_crtc_state);
Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/i915/display/intel_display_types.h
Expand Up @@ -761,6 +761,7 @@ struct intel_crtc_state {
bool update_wm_pre, update_wm_post; /* watermarks are updated */
bool fb_changed; /* fb on any of the planes is changed */
bool fifo_changed; /* FIFO split is changed */
bool preload_luts;

/* Pipe source size (ie. panel fitter input size)
* All planes will be positioned inside this space,
Expand Down
9 changes: 5 additions & 4 deletions drivers/gpu/drm/i915/display/intel_fbdev.c
Expand Up @@ -235,6 +235,11 @@ static int intelfb_create(struct drm_fb_helper *helper,
info->apertures->ranges[0].base = ggtt->gmadr.start;
info->apertures->ranges[0].size = ggtt->mappable_end;

/* Our framebuffer is the entirety of fbdev's system memory */
info->fix.smem_start =
(unsigned long)(ggtt->gmadr.start + vma->node.start);
info->fix.smem_len = vma->node.size;

vaddr = i915_vma_pin_iomap(vma);
if (IS_ERR(vaddr)) {
DRM_ERROR("Failed to remap framebuffer into virtual memory\n");
Expand All @@ -244,10 +249,6 @@ static int intelfb_create(struct drm_fb_helper *helper,
info->screen_base = vaddr;
info->screen_size = vma->node.size;

/* Our framebuffer is the entirety of fbdev's system memory */
info->fix.smem_start = (unsigned long)info->screen_base;
info->fix.smem_len = info->screen_size;

drm_fb_helper_fill_info(info, &ifbdev->helper, sizes);

/* If the object is shmemfs backed, it will have given us zeroed pages.
Expand Down
22 changes: 21 additions & 1 deletion drivers/gpu/drm/i915/gem/i915_gem_userptr.c
Expand Up @@ -671,8 +671,28 @@ i915_gem_userptr_put_pages(struct drm_i915_gem_object *obj,
obj->mm.dirty = false;

for_each_sgt_page(page, sgt_iter, pages) {
if (obj->mm.dirty)
if (obj->mm.dirty && trylock_page(page)) {
/*
* As this may not be anonymous memory (e.g. shmem)
* but exist on a real mapping, we have to lock
* the page in order to dirty it -- holding
* the page reference is not sufficient to
* prevent the inode from being truncated.
* Play safe and take the lock.
*
* However...!
*
* The mmu-notifier can be invalidated for a
* migrate_page, that is alreadying holding the lock
* on the page. Such a try_to_unmap() will result
* in us calling put_pages() and so recursively try
* to lock the page. We avoid that deadlock with
* a trylock_page() and in exchange we risk missing
* some page dirtying.
*/
set_page_dirty(page);
unlock_page(page);
}

mark_page_accessed(page);
put_page(page);
Expand Down
2 changes: 2 additions & 0 deletions drivers/gpu/drm/i915/gt/intel_engine_pool.c
Expand Up @@ -103,6 +103,8 @@ node_create(struct intel_engine_pool *pool, size_t sz)
return ERR_CAST(obj);
}

i915_gem_object_set_readonly(obj);

node->obj = obj;
return node;
}
Expand Down
4 changes: 2 additions & 2 deletions drivers/gpu/drm/i915/i915_pmu.c
Expand Up @@ -843,8 +843,8 @@ create_event_attributes(struct i915_pmu *pmu)
const char *name;
const char *unit;
} events[] = {
__event(I915_PMU_ACTUAL_FREQUENCY, "actual-frequency", "MHz"),
__event(I915_PMU_REQUESTED_FREQUENCY, "requested-frequency", "MHz"),
__event(I915_PMU_ACTUAL_FREQUENCY, "actual-frequency", "M"),
__event(I915_PMU_REQUESTED_FREQUENCY, "requested-frequency", "M"),
__event(I915_PMU_INTERRUPTS, "interrupts", NULL),
__event(I915_PMU_RC6_RESIDENCY, "rc6-residency", "ns"),
};
Expand Down
50 changes: 39 additions & 11 deletions drivers/gpu/drm/i915/i915_scheduler.c
Expand Up @@ -177,9 +177,37 @@ static inline int rq_prio(const struct i915_request *rq)
return rq->sched.attr.priority | __NO_PREEMPTION;
}

static void kick_submission(struct intel_engine_cs *engine, int prio)
static inline bool need_preempt(int prio, int active)
{
const struct i915_request *inflight = *engine->execlists.active;
/*
* Allow preemption of low -> normal -> high, but we do
* not allow low priority tasks to preempt other low priority
* tasks under the impression that latency for low priority
* tasks does not matter (as much as background throughput),
* so kiss.
*/
return prio >= max(I915_PRIORITY_NORMAL, active);
}

static void kick_submission(struct intel_engine_cs *engine,
const struct i915_request *rq,
int prio)
{
const struct i915_request *inflight;

/*
* We only need to kick the tasklet once for the high priority
* new context we add into the queue.
*/
if (prio <= engine->execlists.queue_priority_hint)
return;

rcu_read_lock();

/* Nothing currently active? We're overdue for a submission! */
inflight = execlists_active(&engine->execlists);
if (!inflight)
goto unlock;

/*
* If we are already the currently executing context, don't
Expand All @@ -188,10 +216,15 @@ static void kick_submission(struct intel_engine_cs *engine, int prio)
* tasklet, i.e. we have not change the priority queue
* sufficiently to oust the running context.
*/
if (!inflight || !i915_scheduler_need_preempt(prio, rq_prio(inflight)))
return;
if (inflight->hw_context == rq->hw_context)
goto unlock;

tasklet_hi_schedule(&engine->execlists.tasklet);
engine->execlists.queue_priority_hint = prio;
if (need_preempt(prio, rq_prio(inflight)))
tasklet_hi_schedule(&engine->execlists.tasklet);

unlock:
rcu_read_unlock();
}

static void __i915_schedule(struct i915_sched_node *node,
Expand Down Expand Up @@ -317,13 +350,8 @@ static void __i915_schedule(struct i915_sched_node *node,
list_move_tail(&node->link, cache.priolist);
}

if (prio <= engine->execlists.queue_priority_hint)
continue;

engine->execlists.queue_priority_hint = prio;

/* Defer (tasklet) submission until after all of our updates. */
kick_submission(engine, prio);
kick_submission(engine, node_to_request(node), prio);
}

spin_unlock(&engine->active.lock);
Expand Down

0 comments on commit 51658c0

Please sign in to comment.