Skip to content

Commit cd19154

Browse files
StanFox1984Manasi Navare
authored andcommitted
drm/i915: Adjust CDCLK accordingly to our DBuf bw needs
According to BSpec max BW per slice is calculated using formula Max BW = CDCLK * 64. Currently when calculating min CDCLK we account only per plane requirements, however in order to avoid FIFO underruns we need to estimate accumulated BW consumed by all planes(ddb entries basically) residing on that particular DBuf slice. This will allow us to put CDCLK lower and save power when we don't need that much bandwidth or gain additional performance once plane consumption grows. v2: - Fix long line warning - Limited new DBuf bw checks to only gens >= 11 v3: - Lets track used Dbuf bw per slice and per crtc in bw state (or may be in DBuf state in future), that way we don't need to have all crtcs in state and those only if we detect if are actually going to change cdclk, just same way as we do with other stuff, i.e intel_atomic_serialize_global_state and co. Just as per Ville's paradigm. - Made dbuf bw calculation procedure look nicer by introducing for_each_dbuf_slice_in_mask - we often will now need to iterate slices using mask. - According to experimental results CDCLK * 64 accounts for overall bandwidth across all dbufs, not per dbuf. v4: - Fixed missing const(Ville) - Removed spurious whitespaces(Ville) - Fixed local variable init(reduced scope where not needed) - Added some comments about data rate for planar formats - Changed struct intel_crtc_bw to intel_dbuf_bw - Moved dbuf bw calculation to intel_compute_min_cdclk(Ville) v5: - Removed unneeded macro v6: - Prevent too frequent CDCLK switching back and forth: Always switch to higher CDCLK when needed to prevent bandwidth issues, however don't switch to lower CDCLK earlier than once in 30 minutes in order to prevent constant modeset blinking. We could of course not switch back at all, however this is bad from power consumption point of view. v7: - Fixed to track cdclk using bw_state, modeset will be now triggered only when CDCLK change is really needed. v8: - Lock global state if bw_state->min_cdclk is changed. - Try getting bw_state only if there are crtcs in the commit (need to have read-locked global state) v9: - Do not do Dbuf bw check for gens < 9 - triggers WARN as ddb_size is 0. v10: - Lock global state for older gens as well. v11: - Define new bw_calc_min_cdclk hook, instead of using a condition(Manasi Navare) v12: - Fixed rebase conflict v13: - Added spaces after declarations to make checkpatch happy. Signed-off-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> Reviewed-by: Manasi Navare <manasi.d.navare@intel.com> Signed-off-by: Manasi Navare <manasi.d.navare@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20200520150058.16123-1-stanislav.lisovskiy@intel.com
1 parent 8435576 commit cd19154

File tree

8 files changed

+220
-15
lines changed

8 files changed

+220
-15
lines changed

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

Lines changed: 119 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,12 @@
66
#include <drm/drm_atomic_state_helper.h>
77

88
#include "intel_bw.h"
9+
#include "intel_pm.h"
910
#include "intel_display_types.h"
1011
#include "intel_sideband.h"
1112
#include "intel_atomic.h"
1213
#include "intel_pm.h"
13-
14+
#include "intel_cdclk.h"
1415

1516
/* Parameters for Qclk Geyserville (QGV) */
1617
struct intel_qgv_point {
@@ -351,7 +352,6 @@ static unsigned int intel_bw_crtc_data_rate(const struct intel_crtc_state *crtc_
351352

352353
return data_rate;
353354
}
354-
355355
void intel_bw_crtc_update(struct intel_bw_state *bw_state,
356356
const struct intel_crtc_state *crtc_state)
357357
{
@@ -428,6 +428,123 @@ intel_atomic_get_bw_state(struct intel_atomic_state *state)
428428
return to_intel_bw_state(bw_state);
429429
}
430430

431+
int skl_bw_calc_min_cdclk(struct intel_atomic_state *state)
432+
{
433+
struct drm_i915_private *dev_priv = to_i915(state->base.dev);
434+
int i;
435+
const struct intel_crtc_state *crtc_state;
436+
struct intel_crtc *crtc;
437+
int max_bw = 0;
438+
int slice_id;
439+
struct intel_bw_state *new_bw_state = NULL;
440+
struct intel_bw_state *old_bw_state = NULL;
441+
442+
for_each_new_intel_crtc_in_state(state, crtc, crtc_state, i) {
443+
enum plane_id plane_id;
444+
struct intel_dbuf_bw *crtc_bw;
445+
446+
new_bw_state = intel_atomic_get_bw_state(state);
447+
if (IS_ERR(new_bw_state))
448+
return PTR_ERR(new_bw_state);
449+
450+
crtc_bw = &new_bw_state->dbuf_bw[crtc->pipe];
451+
452+
memset(&crtc_bw->used_bw, 0, sizeof(crtc_bw->used_bw));
453+
454+
for_each_plane_id_on_crtc(crtc, plane_id) {
455+
const struct skl_ddb_entry *plane_alloc =
456+
&crtc_state->wm.skl.plane_ddb_y[plane_id];
457+
const struct skl_ddb_entry *uv_plane_alloc =
458+
&crtc_state->wm.skl.plane_ddb_uv[plane_id];
459+
unsigned int data_rate = crtc_state->data_rate[plane_id];
460+
unsigned int dbuf_mask = 0;
461+
462+
dbuf_mask |= skl_ddb_dbuf_slice_mask(dev_priv, plane_alloc);
463+
dbuf_mask |= skl_ddb_dbuf_slice_mask(dev_priv, uv_plane_alloc);
464+
465+
/*
466+
* FIXME: To calculate that more properly we probably need to
467+
* to split per plane data_rate into data_rate_y and data_rate_uv
468+
* for multiplanar formats in order not to get accounted those twice
469+
* if they happen to reside on different slices.
470+
* However for pre-icl this would work anyway because we have only single
471+
* slice and for icl+ uv plane has non-zero data rate.
472+
* So in worst case those calculation are a bit pessimistic, which
473+
* shouldn't pose any significant problem anyway.
474+
*/
475+
for_each_dbuf_slice_in_mask(slice_id, dbuf_mask)
476+
crtc_bw->used_bw[slice_id] += data_rate;
477+
}
478+
479+
for_each_dbuf_slice(slice_id) {
480+
/*
481+
* Current experimental observations show that contrary to BSpec
482+
* we get underruns once we exceed 64 * CDCLK for slices in total.
483+
* As a temporary measure in order not to keep CDCLK bumped up all the
484+
* time we calculate CDCLK according to this formula for overall bw
485+
* consumed by slices.
486+
*/
487+
max_bw += crtc_bw->used_bw[slice_id];
488+
}
489+
490+
new_bw_state->min_cdclk = max_bw / 64;
491+
492+
old_bw_state = intel_atomic_get_old_bw_state(state);
493+
}
494+
495+
if (!old_bw_state)
496+
return 0;
497+
498+
if (new_bw_state->min_cdclk != old_bw_state->min_cdclk) {
499+
int ret = intel_atomic_lock_global_state(&new_bw_state->base);
500+
501+
if (ret)
502+
return ret;
503+
}
504+
505+
return 0;
506+
}
507+
508+
int intel_bw_calc_min_cdclk(struct intel_atomic_state *state)
509+
{
510+
int i;
511+
const struct intel_crtc_state *crtc_state;
512+
struct intel_crtc *crtc;
513+
int min_cdclk = 0;
514+
struct intel_bw_state *new_bw_state = NULL;
515+
struct intel_bw_state *old_bw_state = NULL;
516+
517+
for_each_new_intel_crtc_in_state(state, crtc, crtc_state, i) {
518+
struct intel_cdclk_state *cdclk_state;
519+
520+
new_bw_state = intel_atomic_get_bw_state(state);
521+
if (IS_ERR(new_bw_state))
522+
return PTR_ERR(new_bw_state);
523+
524+
cdclk_state = intel_atomic_get_cdclk_state(state);
525+
if (IS_ERR(cdclk_state))
526+
return PTR_ERR(cdclk_state);
527+
528+
min_cdclk = max(cdclk_state->min_cdclk[crtc->pipe], min_cdclk);
529+
530+
new_bw_state->min_cdclk = min_cdclk;
531+
532+
old_bw_state = intel_atomic_get_old_bw_state(state);
533+
}
534+
535+
if (!old_bw_state)
536+
return 0;
537+
538+
if (new_bw_state->min_cdclk != old_bw_state->min_cdclk) {
539+
int ret = intel_atomic_lock_global_state(&new_bw_state->base);
540+
541+
if (ret)
542+
return ret;
543+
}
544+
545+
return 0;
546+
}
547+
431548
int intel_bw_atomic_check(struct intel_atomic_state *state)
432549
{
433550
struct drm_i915_private *dev_priv = to_i915(state->base.dev);

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,19 @@
1010

1111
#include "intel_display.h"
1212
#include "intel_global_state.h"
13+
#include "intel_display_power.h"
1314

1415
struct drm_i915_private;
1516
struct intel_atomic_state;
1617
struct intel_crtc_state;
1718

19+
struct intel_dbuf_bw {
20+
int used_bw[I915_MAX_DBUF_SLICES];
21+
};
22+
1823
struct intel_bw_state {
1924
struct intel_global_state base;
25+
struct intel_dbuf_bw dbuf_bw[I915_MAX_PIPES];
2026

2127
/*
2228
* Contains a bit mask, used to determine, whether correspondent
@@ -36,6 +42,8 @@ struct intel_bw_state {
3642

3743
/* bitmask of active pipes */
3844
u8 active_pipes;
45+
46+
int min_cdclk;
3947
};
4048

4149
#define to_intel_bw_state(x) container_of((x), struct intel_bw_state, base)
@@ -56,5 +64,7 @@ void intel_bw_crtc_update(struct intel_bw_state *bw_state,
5664
const struct intel_crtc_state *crtc_state);
5765
int icl_pcode_restrict_qgv_points(struct drm_i915_private *dev_priv,
5866
u32 points_mask);
67+
int intel_bw_calc_min_cdclk(struct intel_atomic_state *state);
68+
int skl_bw_calc_min_cdclk(struct intel_atomic_state *state);
5969

6070
#endif /* __INTEL_BW_H__ */

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

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,12 @@
2121
* DEALINGS IN THE SOFTWARE.
2222
*/
2323

24+
#include <linux/time.h>
2425
#include "intel_atomic.h"
2526
#include "intel_cdclk.h"
2627
#include "intel_display_types.h"
2728
#include "intel_sideband.h"
29+
#include "intel_bw.h"
2830

2931
/**
3032
* DOC: CDCLK / RAWCLK
@@ -2093,11 +2095,9 @@ int intel_crtc_compute_min_cdclk(const struct intel_crtc_state *crtc_state)
20932095
static int intel_compute_min_cdclk(struct intel_cdclk_state *cdclk_state)
20942096
{
20952097
struct intel_atomic_state *state = cdclk_state->base.state;
2096-
struct drm_i915_private *dev_priv = to_i915(state->base.dev);
20972098
struct intel_crtc *crtc;
20982099
struct intel_crtc_state *crtc_state;
20992100
int min_cdclk, i;
2100-
enum pipe pipe;
21012101

21022102
for_each_new_intel_crtc_in_state(state, crtc, crtc_state, i) {
21032103
int ret;
@@ -2117,8 +2117,18 @@ static int intel_compute_min_cdclk(struct intel_cdclk_state *cdclk_state)
21172117
}
21182118

21192119
min_cdclk = cdclk_state->force_min_cdclk;
2120-
for_each_pipe(dev_priv, pipe)
2121-
min_cdclk = max(cdclk_state->min_cdclk[pipe], min_cdclk);
2120+
2121+
for_each_new_intel_crtc_in_state(state, crtc, crtc_state, i) {
2122+
struct intel_bw_state *bw_state;
2123+
2124+
min_cdclk = max(cdclk_state->min_cdclk[crtc->pipe], min_cdclk);
2125+
2126+
bw_state = intel_atomic_get_bw_state(state);
2127+
if (IS_ERR(bw_state))
2128+
return PTR_ERR(bw_state);
2129+
2130+
min_cdclk = max(bw_state->min_cdclk, min_cdclk);
2131+
}
21222132

21232133
return min_cdclk;
21242134
}
@@ -2790,25 +2800,30 @@ void intel_init_cdclk_hooks(struct drm_i915_private *dev_priv)
27902800
{
27912801
if (INTEL_GEN(dev_priv) >= 12) {
27922802
dev_priv->display.set_cdclk = bxt_set_cdclk;
2803+
dev_priv->display.bw_calc_min_cdclk = skl_bw_calc_min_cdclk;
27932804
dev_priv->display.modeset_calc_cdclk = bxt_modeset_calc_cdclk;
27942805
dev_priv->display.calc_voltage_level = tgl_calc_voltage_level;
27952806
dev_priv->cdclk.table = icl_cdclk_table;
27962807
} else if (IS_ELKHARTLAKE(dev_priv)) {
27972808
dev_priv->display.set_cdclk = bxt_set_cdclk;
2809+
dev_priv->display.bw_calc_min_cdclk = skl_bw_calc_min_cdclk;
27982810
dev_priv->display.modeset_calc_cdclk = bxt_modeset_calc_cdclk;
27992811
dev_priv->display.calc_voltage_level = ehl_calc_voltage_level;
28002812
dev_priv->cdclk.table = icl_cdclk_table;
28012813
} else if (INTEL_GEN(dev_priv) >= 11) {
28022814
dev_priv->display.set_cdclk = bxt_set_cdclk;
2815+
dev_priv->display.bw_calc_min_cdclk = skl_bw_calc_min_cdclk;
28032816
dev_priv->display.modeset_calc_cdclk = bxt_modeset_calc_cdclk;
28042817
dev_priv->display.calc_voltage_level = icl_calc_voltage_level;
28052818
dev_priv->cdclk.table = icl_cdclk_table;
28062819
} else if (IS_CANNONLAKE(dev_priv)) {
2820+
dev_priv->display.bw_calc_min_cdclk = skl_bw_calc_min_cdclk;
28072821
dev_priv->display.set_cdclk = bxt_set_cdclk;
28082822
dev_priv->display.modeset_calc_cdclk = bxt_modeset_calc_cdclk;
28092823
dev_priv->display.calc_voltage_level = cnl_calc_voltage_level;
28102824
dev_priv->cdclk.table = cnl_cdclk_table;
28112825
} else if (IS_GEN9_LP(dev_priv)) {
2826+
dev_priv->display.bw_calc_min_cdclk = skl_bw_calc_min_cdclk;
28122827
dev_priv->display.set_cdclk = bxt_set_cdclk;
28132828
dev_priv->display.modeset_calc_cdclk = bxt_modeset_calc_cdclk;
28142829
dev_priv->display.calc_voltage_level = bxt_calc_voltage_level;
@@ -2817,18 +2832,23 @@ void intel_init_cdclk_hooks(struct drm_i915_private *dev_priv)
28172832
else
28182833
dev_priv->cdclk.table = bxt_cdclk_table;
28192834
} else if (IS_GEN9_BC(dev_priv)) {
2835+
dev_priv->display.bw_calc_min_cdclk = skl_bw_calc_min_cdclk;
28202836
dev_priv->display.set_cdclk = skl_set_cdclk;
28212837
dev_priv->display.modeset_calc_cdclk = skl_modeset_calc_cdclk;
28222838
} else if (IS_BROADWELL(dev_priv)) {
2839+
dev_priv->display.bw_calc_min_cdclk = intel_bw_calc_min_cdclk;
28232840
dev_priv->display.set_cdclk = bdw_set_cdclk;
28242841
dev_priv->display.modeset_calc_cdclk = bdw_modeset_calc_cdclk;
28252842
} else if (IS_CHERRYVIEW(dev_priv)) {
2843+
dev_priv->display.bw_calc_min_cdclk = intel_bw_calc_min_cdclk;
28262844
dev_priv->display.set_cdclk = chv_set_cdclk;
28272845
dev_priv->display.modeset_calc_cdclk = vlv_modeset_calc_cdclk;
28282846
} else if (IS_VALLEYVIEW(dev_priv)) {
2847+
dev_priv->display.bw_calc_min_cdclk = intel_bw_calc_min_cdclk;
28292848
dev_priv->display.set_cdclk = vlv_set_cdclk;
28302849
dev_priv->display.modeset_calc_cdclk = vlv_modeset_calc_cdclk;
28312850
} else {
2851+
dev_priv->display.bw_calc_min_cdclk = intel_bw_calc_min_cdclk;
28322852
dev_priv->display.modeset_calc_cdclk = fixed_modeset_calc_cdclk;
28332853
}
28342854

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
#define __INTEL_CDCLK_H__
88

99
#include <linux/types.h>
10-
1110
#include "i915_drv.h"
1211
#include "intel_display.h"
1312
#include "intel_global_state.h"

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

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14708,16 +14708,14 @@ static int intel_atomic_check_planes(struct intel_atomic_state *state)
1470814708
static int intel_atomic_check_cdclk(struct intel_atomic_state *state,
1470914709
bool *need_cdclk_calc)
1471014710
{
14711-
struct intel_cdclk_state *new_cdclk_state;
14711+
struct drm_i915_private *dev_priv = to_i915(state->base.dev);
1471214712
int i;
1471314713
struct intel_plane_state *plane_state;
1471414714
struct intel_plane *plane;
1471514715
int ret;
14716-
14717-
new_cdclk_state = intel_atomic_get_new_cdclk_state(state);
14718-
if (new_cdclk_state && new_cdclk_state->force_min_cdclk_changed)
14719-
*need_cdclk_calc = true;
14720-
14716+
struct intel_cdclk_state *new_cdclk_state;
14717+
struct intel_crtc_state *new_crtc_state;
14718+
struct intel_crtc *crtc;
1472114719
/*
1472214720
* active_planes bitmask has been updated, and potentially
1472314721
* affected planes are part of the state. We can now
@@ -14729,6 +14727,35 @@ static int intel_atomic_check_cdclk(struct intel_atomic_state *state,
1472914727
return ret;
1473014728
}
1473114729

14730+
new_cdclk_state = intel_atomic_get_new_cdclk_state(state);
14731+
14732+
if (new_cdclk_state && new_cdclk_state->force_min_cdclk_changed)
14733+
*need_cdclk_calc = true;
14734+
14735+
ret = dev_priv->display.bw_calc_min_cdclk(state);
14736+
if (ret)
14737+
return ret;
14738+
14739+
if (!new_cdclk_state)
14740+
return 0;
14741+
14742+
for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) {
14743+
struct intel_bw_state *bw_state;
14744+
int min_cdclk = 0;
14745+
14746+
min_cdclk = max(new_cdclk_state->min_cdclk[crtc->pipe], min_cdclk);
14747+
14748+
bw_state = intel_atomic_get_bw_state(state);
14749+
if (IS_ERR(bw_state))
14750+
return PTR_ERR(bw_state);
14751+
14752+
/*
14753+
* Currently do this change only if we need to increase
14754+
*/
14755+
if (bw_state->min_cdclk > min_cdclk)
14756+
*need_cdclk_calc = true;
14757+
}
14758+
1473214759
return 0;
1473314760
}
1473414761

drivers/gpu/drm/i915/i915_drv.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,7 @@ struct drm_i915_display_funcs {
273273
void (*set_cdclk)(struct drm_i915_private *dev_priv,
274274
const struct intel_cdclk_config *cdclk_config,
275275
enum pipe pipe);
276+
int (*bw_calc_min_cdclk)(struct intel_atomic_state *state);
276277
int (*get_fifo_size)(struct drm_i915_private *dev_priv,
277278
enum i9xx_plane_id i9xx_plane);
278279
int (*compute_pipe_wm)(struct intel_crtc_state *crtc_state);

0 commit comments

Comments
 (0)