All of lore.kernel.org
 help / color / mirror / Atom feed
From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
To: Ville Syrjala <ville.syrjala@linux.intel.com>,
	intel-gfx@lists.freedesktop.org
Subject: Re: [PATCH 2/2] drm/i915: Make sure we have enough memory bandwidth on ICL
Date: Wed, 27 Mar 2019 15:12:21 +0100	[thread overview]
Message-ID: <3a875644-9cee-637f-4c54-53c57488857c@linux.intel.com> (raw)
In-Reply-To: <20190320214635.27814-2-ville.syrjala@linux.intel.com>

Op 20-03-2019 om 22:46 schreef Ville Syrjala:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
>
> ICL has so many planes that it can easily exceed the maximum
> effective memory bandwidth of the system. We must therefore check
> that we don't exceed that limit.
>
> The algorithm is very magic number heavy and lacks sufficient
> explanation for now. We also have no sane way to query the
> memory clock and timings, so we must rely on a combination of
> raw readout from the memory controller and hardcoded assumptions.
> The memory controller values obviously change as the system
> jumps between the different SAGV points, so we try to stabilize
> it first by disabling SAGV for the duration of the readout.
>
> The utilized bandwidth is tracked via a device wide atomic
> private object. That is actually not robust because we can't
> afford to enforce strict global ordering between the pipes.
> Thus I think I'll need to change this to simply chop up the
> available bandwidth between all the active pipes. Each pipe
> can then do whatever it wants as long as it doesn't exceed
> its budget. That scheme will also require that we assume that
> any number of planes could be active at any time.
>
> TODO: make it robust and deal with all the open questions
>
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>  drivers/gpu/drm/i915/Makefile             |   1 +
>  drivers/gpu/drm/i915/i915_drv.c           | 346 ++++++++++++++++++++++
>  drivers/gpu/drm/i915/i915_drv.h           |  10 +
>  drivers/gpu/drm/i915/intel_atomic_plane.c |  20 ++
>  drivers/gpu/drm/i915/intel_bw.c           | 190 ++++++++++++
>  drivers/gpu/drm/i915/intel_display.c      |  39 ++-
>  drivers/gpu/drm/i915/intel_drv.h          |  32 ++
>  7 files changed, 637 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/gpu/drm/i915/intel_bw.c
>
> diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
> index 68fecf355471..2d24bdd501c4 100644
> --- a/drivers/gpu/drm/i915/Makefile
> +++ b/drivers/gpu/drm/i915/Makefile
> @@ -126,6 +126,7 @@ i915-y += intel_audio.o \
>  	  intel_atomic.o \
>  	  intel_atomic_plane.o \
>  	  intel_bios.o \
> +	  intel_bw.o \
>  	  intel_cdclk.o \
>  	  intel_color.o \
>  	  intel_combo_phy.o \
> diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
> index 8b37ec0e0676..134d1b1a93f1 100644
> --- a/drivers/gpu/drm/i915/i915_drv.c
> +++ b/drivers/gpu/drm/i915/i915_drv.c
> @@ -1451,6 +1451,348 @@ bxt_get_dram_info(struct drm_i915_private *dev_priv)
>  	return 0;
>  }
>  
> +#define SA_PERF_STATUS_0_0_0_MCHBAR_PC _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5918)
> +#define  SKL_QCLK_RATIO_MASK (0x7f << 0)
> +#define  SKL_QCLK_RATIO_SHIT 0
> +#define  SKL_QCLK_REFERENCE (1 << 7)
> +#define  CNL_QCLK_RATIO_MASK (0x7f << 2)
> +#define  CNL_QCLK_RATIO_SHIT 2
> +#define  CNL_QCLK_REFERENCE (1 << 9)
> +#define  ICL_QCLK_RATIO_MASK (0xff << 2)
> +#define  ICL_QCLK_RATIO_SHIT 2
> +#define  ICL_QCLK_REFERENCE (1 << 10)
> +
> +#define MCHBAR_CH0_CR_TC_PRE_0_0_0_MCHBAR _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x4000)
> +#define MCHBAR_CH1_CR_TC_PRE_0_0_0_MCHBAR _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x4400)
> +#define  SKL_DRAM_T_WRPRE_MASK (0x7f << 24)
> +#define  SKL_DRAM_T_WRPRE_SHIFT 24
> +#define  SKL_DRAM_T_RDPRE_MASK (0xf << 16)
> +#define  SKL_DRAM_T_RDPRE_SHIFT 16
> +#define  SKL_DRAM_T_RAS_MASK (0x7f << 8)
> +#define  SKL_DRAM_T_RAS_SHIFT 8
> +#define  SKL_DRAM_T_RPAB_EXT_MASK (0x3 << 6)
> +#define  SKL_DRAM_T_RPAB_EXT_SHIFT 6
> +#define  SKL_DRAM_T_RP_MASK (0x3f << 0)
> +#define  SKL_DRAM_T_RP_SHIFT 0
> +#define  CNL_DRAM_T_WRPRE_MASK (0xff << 24)
> +#define  CNL_DRAM_T_WRPRE_SHIFT 24
> +#define  CNL_DRAM_T_PPD_MASK (0x7 << 21)
> +#define  CNL_DRAM_T_PPD_SHIFT 21
> +#define  CNL_DRAM_T_RDPRE_MASK (0x1f << 16)
> +#define  CNL_DRAM_T_RDPRE_SHIFT 16
> +#define  CNL_DRAM_T_RAS_MASK (0x7f << 9)
> +#define  CNL_DRAM_T_RAS_SHIFT 9
> +#define  CNL_DRAM_T_RPAB_EXT_MASK (0x7 << 6)
> +#define  CNL_DRAM_T_RPAB_EXT_SHIFT 6
> +#define  CNL_DRAM_T_RP_MASK (0x3f << 0)
> +#define  CNL_DRAM_T_RP_SHIFT 0
> +
> +struct intel_dram_timings {
> +	u8 t_rp, t_rdpre, t_ras, t_bl;
> +};
> +
> +static int icl_get_dclk(struct drm_i915_private *dev_priv)
> +{
> +	int ratio, ref;
> +	u32 val;
> +
> +	val = I915_READ(SA_PERF_STATUS_0_0_0_MCHBAR_PC);
> +
> +	DRM_DEBUG_KMS("SA_PERF = 0x%x\n", val);
> +	DRM_DEBUG_KMS("BIOS_DATA = 0x%x\n",
> +		      I915_READ(SKL_MC_BIOS_DATA_0_0_0_MCHBAR_PCU));
> +
> +	ratio = (val & ICL_QCLK_RATIO_MASK) >> ICL_QCLK_RATIO_SHIT;
> +
> +	if (val & ICL_QCLK_REFERENCE)
> +		ref = 6; /* 6 * 16.666 MHz = 100 MHz */
> +	else
> +		ref = 8; /* 8 * 16.666 MHz = 133 MHz */
> +
> +	return ratio * ref;
> +}
> +
> +#if 0
> +static void skl_get_dram_ch_timings(struct intel_dram_timings *t,
> +				    int channel, enum intel_dram_type type,
> +				    u32 val)
> +{
> +	t->t_rp = (val & SKL_DRAM_T_RP_MASK) >> SKL_DRAM_T_RP_SHIFT;
> +	t->t_rdpre = (val & SKL_DRAM_T_RDPRE_MASK) >> SKL_DRAM_T_RDPRE_SHIFT;
> +	t->t_ras = (val & SKL_DRAM_T_RAS_MASK) >> SKL_DRAM_T_RAS_SHIFT;
> +	t->t_bl = type == INTEL_DRAM_DDR4 ? 4 : 8;
> +
> +	DRM_DEBUG_KMS("CH%d tRP=%d tRDPRE=%d tRAS=%d tBL=%d\n",
> +		      channel, t->t_rp, t->t_rdpre, t->t_ras, t->t_bl);
> +}
> +
> +static void skl_get_dram_timings(struct drm_i915_private *dev_priv,
> +				 const struct dram_info *dram,
> +				 struct intel_dram_timings *t)
> +{
> +	if (dram->channels & BIT(0)) {
> +		u32 val = I915_READ(MCHBAR_CH0_CR_TC_PRE_0_0_0_MCHBAR);
> +
> +		skl_get_dram_ch_timings(t, 0, dram->type, val);
> +	} else if (dram->channels & BIT(1)) {
> +		u32 val = I915_READ(MCHBAR_CH1_CR_TC_PRE_0_0_0_MCHBAR);
> +
> +		skl_get_dram_ch_timings(t, 1, dram->type, val);
> +	}
> +}
> +#endif
> +
> +static void cnl_get_dram_ch_timings(struct intel_dram_timings *t,
> +				    int channel, enum intel_dram_type type,
> +				    u32 val)
> +{
> +	t->t_rp = (val & CNL_DRAM_T_RP_MASK) >> CNL_DRAM_T_RP_SHIFT;
> +	t->t_rdpre = (val & CNL_DRAM_T_RDPRE_MASK) >> CNL_DRAM_T_RDPRE_SHIFT;
> +	t->t_ras = (val & CNL_DRAM_T_RAS_MASK) >> CNL_DRAM_T_RAS_SHIFT;
> +	t->t_bl = type == INTEL_DRAM_DDR4 ? 4 : 8;
> +
> +	DRM_DEBUG_KMS("CH%d tRP=%d tRDPRE=%d tRAS=%d tBL=%d\n",
> +		      channel, t->t_rp, t->t_rdpre, t->t_ras, t->t_bl);
> +}
> +
> +static void cnl_get_dram_timings(struct drm_i915_private *dev_priv,
> +				 const struct dram_info *dram,
> +				 struct intel_dram_timings *t)
> +{
> +	u32 val;
> +
> +	if (dram->channels & BIT(0)) {
> +		val = I915_READ(MCHBAR_CH0_CR_TC_PRE_0_0_0_MCHBAR);
> +		cnl_get_dram_ch_timings(t, 0, dram->type, val);
> +	} else if (dram->channels & BIT(1)) {
> +		val = I915_READ(MCHBAR_CH1_CR_TC_PRE_0_0_0_MCHBAR);
> +		cnl_get_dram_ch_timings(t, 1, dram->type, val);
> +	}
> +}
> +
> +struct intel_sagv_point {
> +	u16 dclk, t_rp, t_rdpre, t_rc, t_ras, t_rcd;
> +};
> +
> +struct intel_sagv_info {
> +	struct intel_sagv_point points[3];
> +	int num_points;
> +};
> +
> +static void icl_get_sagv_points(struct drm_i915_private *dev_priv,
> +				struct intel_sagv_info *si,
> +				const struct intel_dram_timings *t)
> +{
> +	int dclk, i;
> +
> +	dclk = icl_get_dclk(dev_priv);
> +
> +	si->num_points = 3;
> +
> +	/*
> +	 * ICL Hardcoded
> +	 * Name  Description         MC clock(MHz)     DDR data rate(MT / s)  Gear
> +	 * Low   Min voltage point   1066              2133                   2
> +	 * Med   Max DDR rate point  Max DDR freq / 2  Max DDR freq           2
> +	 * High  Min latency point   2667              Same as MC clock       1
> +	 */
> +	si->points[0].dclk = min(64, dclk);
> +	si->points[1].dclk = dclk;
> +	si->points[2].dclk = min(80, dclk);
> +
> +	for (i = 0; i < si->num_points; i++) {
> +		struct intel_sagv_point *sp = &si->points[i];
> +
> +		/*
> +		 * We assume these scale linearly.
> +		 * Seems to match observed behaviour.
> +		 */
> +		sp->t_rp = DIV_ROUND_UP(t->t_rp * sp->dclk, dclk);
> +		sp->t_rdpre = DIV_ROUND_UP(t->t_rdpre * sp->dclk, dclk);
> +		sp->t_ras = DIV_ROUND_UP(t->t_ras * sp->dclk, dclk);
> +
> +		sp->t_rcd = sp->t_rp;
> +		sp->t_rc = sp->t_rp + sp->t_ras;
> +
> +		DRM_DEBUG_KMS("SAGV %d DCLK=%d tRP=%d tRDPRE=%d tRAS=%d tRCD=%d tRC=%d\n",
> +			      i, sp->dclk, sp->t_rp, sp->t_rdpre, sp->t_ras,
> +			      sp->t_rcd, sp->t_rc);
> +	}
> +}
> +
> +static int icl_calc_bw(int dclk, int num, int den)
> +{
> +	/* multiples of 2 x 16.666MHz (100/6) */
> +	return DIV_ROUND_CLOSEST(num * dclk * 2 * 100, den * 6);
> +}
> +
> +static int icl_sagv_max_dclk(const struct intel_sagv_info *si)
> +{
> +	u16 dclk = 0;
> +	int i;
> +
> +	for (i = 0; i < si->num_points; i++)
> +		dclk = max(dclk, si->points[i].dclk);
> +
> +	return dclk;
> +}
> +
> +struct intel_sa_info {
> +	u8 deburst, mpagesize, deprogbwlimit, displayrtids;
> +};
> +
> +static const struct intel_sa_info icl_sa_info = {
> +	.deburst = 8,
> +	.mpagesize = 16,
> +	.deprogbwlimit = 25, /* GB/s */
> +	.displayrtids = 128,
> +};
> +
> +static void icl_get_bw_info(struct drm_i915_private *dev_priv)
> +{
> +	const struct dram_info *dram = &dev_priv->dram_info;
> +	struct intel_sagv_info si = {};
> +	struct intel_dram_timings t = {};
> +	const struct intel_sa_info *sa = &icl_sa_info;
> +	bool is_y_tile = true; /* assume y tile may be used */
> +	int num_channels = hweight8(dram->channels);
> +	int deinterleave;
> +#if 0
> +	int clpchpblock;
> +	int pagelimit;
> +#endif
> +	int ipqdepth, ipqdepthpch;
> +	int dclk_max;
> +	int maxdebw;
> +	int i;
> +
> +	/*
> +	 * Try to muzzle SAGV to prevent it from
> +	 * messing up the memory controller readout.
> +	 */
> +	intel_disable_sagv(dev_priv);
> +
> +	/*
> +	 * Magic sleep to avoid observing very high DDR clock.
> +	 * Not sure what's going on but on a system with DDR4-3200
> +	 * clock of 4800 MT/s is often observed here. A short
> +	 * sleep manages to hide that.. Is that actually
> +	 * the "min latency" SAGV point?. Maybe the SA clocks
> +	 * things way up when there is no memory traffic?
> +	 * But polling the register never seems to show this
> +	 * except during i915 unload/load. Sleeping before the
> +	 * SAGV disable usually returns 2133 MT/s.
> +	 *
> +	 * FIXME what is going on?
> +	 */
> +	msleep(5);
> +
> +	cnl_get_dram_timings(dev_priv, dram, &t);
> +
> +	icl_get_sagv_points(dev_priv, &si, &t);
> +
> +	deinterleave = DIV_ROUND_UP(num_channels, is_y_tile ? 4 : 2);
> +	dclk_max = icl_sagv_max_dclk(&si);
> +
> +	ipqdepthpch = 16;
> +
> +	maxdebw = min(sa->deprogbwlimit * 1000,
> +		      icl_calc_bw(dclk_max, 16, 1) * 6 / 10); /* 60% */
> +#if 0
> +	clpchpblock = deinterleave * 8 / num_channels;
> +	pagelimit = sa->mpagesize * deinterleave * 2 / num_channels;
> +#endif
> +	ipqdepth = min(ipqdepthpch, sa->displayrtids / num_channels);
> +
> +	DRM_DEBUG_KMS("maxdebw = %d\n", maxdebw);
> +	DRM_DEBUG_KMS("ipqdepth = %d\n", ipqdepth);
> +	DRM_DEBUG_KMS("deinterleave = %d\n", deinterleave);
> +	DRM_DEBUG_KMS("dclk_max = %d\n", dclk_max);
> +
> +	for (i = 0; i < ARRAY_SIZE(dev_priv->max_bw); i++) {
> +		struct intel_bw_info *bi = &dev_priv->max_bw[i];
> +		int clpchgroup;
> +		int j;
> +
> +		clpchgroup = (sa->deburst * deinterleave / num_channels) << i;
> +		bi->num_planes = (ipqdepth - clpchgroup) / clpchgroup + 1;
> +
> +		DRM_DEBUG_KMS("clpchgroup = %d\n", clpchgroup);
> +		DRM_DEBUG_KMS("num_planes = %d\n", bi->num_planes);
> +
> +		for (j = 0; j < si.num_points; j++) {
> +			const struct intel_sagv_point *sp = &si.points[j];
> +			int ct, bw;
> +
> +			/*
> +			 * Max row cycle time
> +			 *
> +			 * FIXME what is the logic behind the
> +			 * assumed burst length?
> +			 */
> +			ct = max_t(int, sp->t_rc, sp->t_rp + sp->t_rcd +
> +				   (clpchgroup - 1) * t.t_bl + sp->t_rdpre);
> +			bw = icl_calc_bw(sp->dclk, clpchgroup * 32 * num_channels, ct);
> +
> +			DRM_DEBUG_KMS("ct = %d\n", ct);
> +			DRM_DEBUG_KMS("bw = %d\n", bw);
> +
> +			bi->deratedbw[j] = min(maxdebw,
> +					       bw * 9 / 10); /* 90% */
> +		}
> +
> +		if (bi->num_planes == 1)
> +			break;
> +	}
> +}
> +
> +static unsigned int icl_max_bw(struct drm_i915_private *dev_priv,
> +			       int num_planes, int sagv)
> +{
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(dev_priv->max_bw); i++) {
> +		const struct intel_bw_info *bi =
> +			&dev_priv->max_bw[i];
> +
> +		if (num_planes >= bi->num_planes)
> +			return bi->deratedbw[sagv];
> +	}
> +
> +	return 0;
> +}
> +
> +unsigned int intel_max_data_rate(struct drm_i915_private *dev_priv,
> +				 int num_planes)
> +{
> +	if (IS_ICELAKE(dev_priv))
> +		/*
> +		 * FIXME with SAGV disabled maybe we can assume
> +		 * point 1 will always be used? Seems to match
> +		 * the behaviour observed in the wild.
> +		 */
> +		return min3(icl_max_bw(dev_priv, num_planes, 0),
> +			    icl_max_bw(dev_priv, num_planes, 1),
> +			    icl_max_bw(dev_priv, num_planes, 2));
> +	else
> +		return UINT_MAX;
> +}
> +
> +static void icl_dump_max_bw(struct drm_i915_private *dev_priv)
> +{
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(dev_priv->max_bw); i++) {
> +		const struct intel_bw_info *bi = &dev_priv->max_bw[i];
> +		int j;
> +
> +		for (j = 0; j < ARRAY_SIZE(bi->deratedbw); j++) {
> +			DRM_DEBUG_KMS("BW%d SAGV%d: num_planes=%d deratedbw=%d\n",
> +				      i, j, bi->num_planes, bi->deratedbw[j]);
> +		}
> +	}
> +}
> +
>  static void
>  intel_get_dram_info(struct drm_i915_private *dev_priv)
>  {
> @@ -1629,6 +1971,10 @@ static int i915_driver_init_hw(struct drm_i915_private *dev_priv)
>  	 */
>  	intel_get_dram_info(dev_priv);
>  
> +	if (INTEL_GEN(dev_priv) >= 11) {
> +		icl_get_bw_info(dev_priv);
> +		icl_dump_max_bw(dev_priv);
> +	}
>  
>  	return 0;
>  
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index f638c0c74955..825bea3176fc 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -54,6 +54,7 @@
>  #include <drm/drm_cache.h>
>  #include <drm/drm_util.h>
>  #include <drm/drm_dsc.h>
> +#include <drm/drm_atomic.h>
>  #include <drm/drm_connector.h>
>  #include <drm/i915_mei_hdcp_interface.h>
>  
> @@ -1845,6 +1846,13 @@ struct drm_i915_private {
>  		} type;
>  	} dram_info;
>  
> +	struct intel_bw_info {
> +		int num_planes;
> +		int deratedbw[3];
> +	} max_bw[6];
> +
> +	struct drm_private_obj bw_obj;
> +
>  	struct i915_runtime_pm runtime_pm;
>  
>  	struct {
> @@ -2634,6 +2642,8 @@ extern unsigned long i915_mch_val(struct drm_i915_private *dev_priv);
>  extern unsigned long i915_gfx_val(struct drm_i915_private *dev_priv);
>  extern void i915_update_gfx_val(struct drm_i915_private *dev_priv);
>  int vlv_force_gfx_clock(struct drm_i915_private *dev_priv, bool on);
> +unsigned int intel_max_data_rate(struct drm_i915_private *dev_priv,
> +				 int num_planes);
>  
>  int intel_engines_init_mmio(struct drm_i915_private *dev_priv);
>  int intel_engines_init(struct drm_i915_private *dev_priv);
> diff --git a/drivers/gpu/drm/i915/intel_atomic_plane.c b/drivers/gpu/drm/i915/intel_atomic_plane.c
> index 9d32a6fcf840..de6b23ee6306 100644
> --- a/drivers/gpu/drm/i915/intel_atomic_plane.c
> +++ b/drivers/gpu/drm/i915/intel_atomic_plane.c
> @@ -111,6 +111,22 @@ intel_plane_destroy_state(struct drm_plane *plane,
>  	drm_atomic_helper_plane_destroy_state(plane, state);
>  }
>  
> +unsigned int intel_plane_data_rate(const struct intel_crtc_state *crtc_state,
> +				   const struct intel_plane_state *plane_state)
> +{
> +	const struct drm_framebuffer *fb = plane_state->base.fb;
> +	unsigned int cpp = 0;
> +	int i;
> +
> +	if (!plane_state->base.visible)
> +		return 0;
> +
> +	for (i = 0; i < fb->format->num_planes; i++)
> +		cpp += fb->format->cpp[i];
> +
> +	return cpp * crtc_state->pixel_rate;

This doesn't take into account plane width/height? Surely that affects bandwidth as well?

This breaks kms_atomic_transition, which tries to decrease plane size to reduce load when max plane width/height is not supported.

According to this calculation, 6 256x256 overlay planes will take the same bandwidth as 6 planes filled with 4k fb's

~Maarten

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

  parent reply	other threads:[~2019-03-27 14:12 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-03-20 21:46 [PATCH 1/2] drm/i915: Turn dram_info.num_channels into a bitmask Ville Syrjala
2019-03-20 21:46 ` [PATCH 2/2] drm/i915: Make sure we have enough memory bandwidth on ICL Ville Syrjala
2019-03-21  9:34   ` Lisovskiy, Stanislav
2019-03-21 10:32     ` Ville Syrjälä
2019-03-22 17:04   ` Ville Syrjälä
2019-03-27 14:12   ` Maarten Lankhorst [this message]
2019-03-20 23:43 ` ✗ Fi.CI.CHECKPATCH: warning for series starting with [1/2] drm/i915: Turn dram_info.num_channels into a bitmask Patchwork
2019-03-20 23:44 ` ✗ Fi.CI.SPARSE: " Patchwork
2019-03-21  0:12 ` ✗ Fi.CI.BAT: failure " Patchwork
2019-03-21  5:24 ` ✗ Fi.CI.CHECKPATCH: warning for series starting with [1/2] drm/i915: Turn dram_info.num_channels into a bitmask (rev2) Patchwork
2019-03-21  5:25 ` ✗ Fi.CI.SPARSE: " Patchwork
2019-03-21  5:53 ` ✗ Fi.CI.BAT: failure " Patchwork
2019-03-21  6:12 ` ✗ Fi.CI.CHECKPATCH: warning for series starting with [1/2] drm/i915: Turn dram_info.num_channels into a bitmask (rev3) Patchwork
2019-03-21  6:14 ` ✗ Fi.CI.SPARSE: " Patchwork
2019-03-21  6:33 ` ✓ Fi.CI.BAT: success " Patchwork
2019-03-21  7:50   ` Saarinen, Jani
2019-03-21 13:36 ` ✗ Fi.CI.IGT: failure " Patchwork

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=3a875644-9cee-637f-4c54-53c57488857c@linux.intel.com \
    --to=maarten.lankhorst@linux.intel.com \
    --cc=intel-gfx@lists.freedesktop.org \
    --cc=ville.syrjala@linux.intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.