Skip to content

Commit f83b94d

Browse files
committed
drm/i915/dsb: Use DEwake to combat PkgC latency
Normally we could be in a deep PkgC state all the way up to the point when DSB starts its execution at the transcoders undelayed vblank. The DSB will then have to wait for the hardware to wake up before it can execute anything. This will waste a huge chunk of the vblank time just waiting, and risks the DSB execution spilling into the vertical active period. That will be very bad, especially when programming the LUTs as the anti-collision logic will cause DSB to corrupt LUT writes during vertical active. To avoid these problems we can instruct the DSB to pre-wake the display engine on a specific scanline so that everything will be 100% ready to go when we hit the transcoder's undelayed vblank. One annoyance is that the scanline is specified as just that, a single scanline. So if we happen to start the DSB execution after passing said scanline no DEwake will happen and we may drop back into some PkgC state before reaching the transcoder's undelayed vblank. To prevent that we'll use the "force DEwake" bit to manually force the display engine to stay awake. We'll then have to clear the force bit again after the DSB is done (the force bit remains effective even when the DSB is otherwise disabled). Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20230606191504.18099-18-ville.syrjala@linux.intel.com Reviewed-by: Uma Shankar <uma.shankar@intel.com>
1 parent 77d8285 commit f83b94d

3 files changed

Lines changed: 82 additions & 14 deletions

File tree

drivers/gpu/drm/i915/display/intel_color.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1905,7 +1905,7 @@ void intel_color_prepare_commit(struct intel_crtc_state *crtc_state)
19051905
if (!crtc_state->pre_csc_lut && !crtc_state->post_csc_lut)
19061906
return;
19071907

1908-
crtc_state->dsb = intel_dsb_prepare(crtc, 1024);
1908+
crtc_state->dsb = intel_dsb_prepare(crtc_state, 1024);
19091909
if (!crtc_state->dsb)
19101910
return;
19111911

drivers/gpu/drm/i915/display/intel_dsb.c

Lines changed: 79 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,16 @@
77
#include "gem/i915_gem_internal.h"
88

99
#include "i915_drv.h"
10+
#include "i915_irq.h"
1011
#include "i915_reg.h"
12+
#include "intel_crtc.h"
1113
#include "intel_de.h"
1214
#include "intel_display_types.h"
1315
#include "intel_dsb.h"
1416
#include "intel_dsb_regs.h"
17+
#include "intel_vblank.h"
18+
#include "intel_vrr.h"
19+
#include "skl_watermark.h"
1520

1621
struct i915_vma;
1722

@@ -47,6 +52,8 @@ struct intel_dsb {
4752
* register.
4853
*/
4954
unsigned int ins_start_offset;
55+
56+
int dewake_scanline;
5057
};
5158

5259
/**
@@ -297,17 +304,40 @@ static void intel_dsb_align_tail(struct intel_dsb *dsb)
297304

298305
void intel_dsb_finish(struct intel_dsb *dsb)
299306
{
307+
struct intel_crtc *crtc = dsb->crtc;
308+
309+
/*
310+
* DSB_FORCE_DEWAKE remains active even after DSB is
311+
* disabled, so make sure to clear it (if set during
312+
* intel_dsb_commit()).
313+
*/
314+
intel_dsb_reg_write_masked(dsb, DSB_PMCTRL_2(crtc->pipe, dsb->id),
315+
DSB_FORCE_DEWAKE, 0);
316+
300317
intel_dsb_align_tail(dsb);
301318
}
302319

303-
/**
304-
* intel_dsb_commit() - Trigger workload execution of DSB.
305-
* @dsb: DSB context
306-
* @wait_for_vblank: wait for vblank before executing
307-
*
308-
* This function is used to do actual write to hardware using DSB.
309-
*/
310-
void intel_dsb_commit(struct intel_dsb *dsb, bool wait_for_vblank)
320+
static int intel_dsb_dewake_scanline(const struct intel_crtc_state *crtc_state)
321+
{
322+
struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
323+
const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode;
324+
unsigned int latency = skl_watermark_max_latency(i915);
325+
int vblank_start;
326+
327+
if (crtc_state->vrr.enable) {
328+
vblank_start = intel_vrr_vmin_vblank_start(crtc_state);
329+
} else {
330+
vblank_start = adjusted_mode->crtc_vblank_start;
331+
332+
if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)
333+
vblank_start = DIV_ROUND_UP(vblank_start, 2);
334+
}
335+
336+
return max(0, vblank_start - intel_usecs_to_scanlines(adjusted_mode, latency));
337+
}
338+
339+
static void _intel_dsb_commit(struct intel_dsb *dsb, u32 ctrl,
340+
unsigned int dewake_scanline)
311341
{
312342
struct intel_crtc *crtc = dsb->crtc;
313343
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
@@ -325,14 +355,49 @@ void intel_dsb_commit(struct intel_dsb *dsb, bool wait_for_vblank)
325355
}
326356

327357
intel_de_write_fw(dev_priv, DSB_CTRL(pipe, dsb->id),
328-
(wait_for_vblank ? DSB_WAIT_FOR_VBLANK : 0) |
329-
DSB_ENABLE);
358+
ctrl | DSB_ENABLE);
359+
330360
intel_de_write_fw(dev_priv, DSB_HEAD(pipe, dsb->id),
331361
i915_ggtt_offset(dsb->vma));
362+
363+
if (dewake_scanline >= 0) {
364+
int diff, hw_dewake_scanline;
365+
366+
hw_dewake_scanline = intel_crtc_scanline_to_hw(crtc, dewake_scanline);
367+
368+
intel_de_write_fw(dev_priv, DSB_PMCTRL(pipe, dsb->id),
369+
DSB_ENABLE_DEWAKE |
370+
DSB_SCANLINE_FOR_DEWAKE(hw_dewake_scanline));
371+
372+
/*
373+
* Force DEwake immediately if we're already past
374+
* or close to racing past the target scanline.
375+
*/
376+
diff = dewake_scanline - intel_get_crtc_scanline(crtc);
377+
intel_de_write_fw(dev_priv, DSB_PMCTRL_2(pipe, dsb->id),
378+
(diff >= 0 && diff < 5 ? DSB_FORCE_DEWAKE : 0) |
379+
DSB_BLOCK_DEWAKE_EXTENSION);
380+
}
381+
332382
intel_de_write_fw(dev_priv, DSB_TAIL(pipe, dsb->id),
333383
i915_ggtt_offset(dsb->vma) + tail);
334384
}
335385

386+
/**
387+
* intel_dsb_commit() - Trigger workload execution of DSB.
388+
* @dsb: DSB context
389+
* @wait_for_vblank: wait for vblank before executing
390+
*
391+
* This function is used to do actual write to hardware using DSB.
392+
*/
393+
void intel_dsb_commit(struct intel_dsb *dsb,
394+
bool wait_for_vblank)
395+
{
396+
_intel_dsb_commit(dsb,
397+
wait_for_vblank ? DSB_WAIT_FOR_VBLANK : 0,
398+
wait_for_vblank ? dsb->dewake_scanline : -1);
399+
}
400+
336401
void intel_dsb_wait(struct intel_dsb *dsb)
337402
{
338403
struct intel_crtc *crtc = dsb->crtc;
@@ -363,7 +428,7 @@ void intel_dsb_wait(struct intel_dsb *dsb)
363428

364429
/**
365430
* intel_dsb_prepare() - Allocate, pin and map the DSB command buffer.
366-
* @crtc: the CRTC
431+
* @crtc_state: the CRTC state
367432
* @max_cmds: number of commands we need to fit into command buffer
368433
*
369434
* This function prepare the command buffer which is used to store dsb
@@ -372,9 +437,10 @@ void intel_dsb_wait(struct intel_dsb *dsb)
372437
* Returns:
373438
* DSB context, NULL on failure
374439
*/
375-
struct intel_dsb *intel_dsb_prepare(struct intel_crtc *crtc,
440+
struct intel_dsb *intel_dsb_prepare(const struct intel_crtc_state *crtc_state,
376441
unsigned int max_cmds)
377442
{
443+
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
378444
struct drm_i915_private *i915 = to_i915(crtc->base.dev);
379445
struct drm_i915_gem_object *obj;
380446
intel_wakeref_t wakeref;
@@ -420,6 +486,7 @@ struct intel_dsb *intel_dsb_prepare(struct intel_crtc *crtc,
420486
dsb->size = size / 4; /* in dwords */
421487
dsb->free_pos = 0;
422488
dsb->ins_start_offset = 0;
489+
dsb->dewake_scanline = intel_dsb_dewake_scanline(crtc_state);
423490

424491
return dsb;
425492

drivers/gpu/drm/i915/display/intel_dsb.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,10 @@
1111
#include "i915_reg_defs.h"
1212

1313
struct intel_crtc;
14+
struct intel_crtc_state;
1415
struct intel_dsb;
1516

16-
struct intel_dsb *intel_dsb_prepare(struct intel_crtc *crtc,
17+
struct intel_dsb *intel_dsb_prepare(const struct intel_crtc_state *crtc_state,
1718
unsigned int max_cmds);
1819
void intel_dsb_finish(struct intel_dsb *dsb);
1920
void intel_dsb_cleanup(struct intel_dsb *dsb);

0 commit comments

Comments
 (0)