[Freedreno] [DPU PATCH 4/4] drm/msm/dpu: use private obj to track hw resources

Jordan Crouse jcrouse at codeaurora.org
Wed Jun 13 16:44:56 UTC 2018


On Tue, Jun 12, 2018 at 06:17:47PM -0700, Jeykumar Sankaran wrote:
> Switch to state based resource management. This patch
> overhauls the resource manager and HW allocation methods by
> maintaining the global resource pool and allocated hw
> blocks in respective drm component states.
> 
> Global resource manager(RM) is tracked in private object.
> Allocation strategy is switched from single point allocation
> of HW resources for the display pipeline to per component
> based allocation, where each drm component allocates HW
> blocks mapped to it's domain and tracks them in their respective
> state objects.
> 
> Fixes resource contention due to race conditions between
> user space and display thread by reserving resources
> only in atomic check.
> 
> Signed-off-by: Jeykumar Sankaran <jsanka at codeaurora.org>
> ---
>  drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c           | 210 +++---
>  drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h           |  59 +-
>  drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c        | 223 ++----
>  drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h        |   4 -
>  drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h   |   9 +-
>  .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c   |  32 +-
>  .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c   |  86 +--
>  drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c            |  19 +-
>  drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h            |   8 +-
>  drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c             | 805 ++++++---------------
>  drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h             | 149 ++--
>  11 files changed, 534 insertions(+), 1070 deletions(-)
> 
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> index 426e2ad..a484c06 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> @@ -47,6 +47,8 @@
>  #define RIGHT_MIXER 1
>  
>  #define MISR_BUFF_SIZE			256
> +#define MAX_VDISPLAY_SPLIT		1080
> +
>  
>  static inline struct dpu_kms *_dpu_crtc_get_kms(struct drm_crtc *crtc)
>  {
> @@ -142,9 +144,9 @@ static void _dpu_crtc_program_lm_output_roi(struct drm_crtc *crtc)
>  	crtc_state = to_dpu_crtc_state(crtc->state);
>  
>  	lm_horiz_position = 0;
> -	for (lm_idx = 0; lm_idx < dpu_crtc->num_mixers; lm_idx++) {
> +	for (lm_idx = 0; lm_idx < crtc_state->num_mixers; lm_idx++) {
>  		const struct dpu_rect *lm_roi = &crtc_state->lm_bounds[lm_idx];
> -		struct dpu_hw_mixer *hw_lm = dpu_crtc->mixers[lm_idx].hw_lm;
> +		struct dpu_hw_mixer *hw_lm = crtc_state->mixers[lm_idx].hw_lm;
>  		struct dpu_hw_mixer_cfg cfg;
>  
>  		if (dpu_kms_rect_is_null(lm_roi))
> @@ -182,7 +184,7 @@ static void _dpu_crtc_blend_setup_mixer(struct drm_crtc *crtc,
>  		return;
>  	}
>  
> -	ctl = mixer->hw_ctl;
> +	ctl = mixer->lm_ctl;
>  	lm = mixer->hw_lm;
>  	stage_cfg = &dpu_crtc->stage_cfg;
>  	cstate = to_dpu_crtc_state(crtc->state);
> @@ -237,7 +239,7 @@ static void _dpu_crtc_blend_setup_mixer(struct drm_crtc *crtc,
>  			format->base.pixel_format, fb ? fb->modifier : 0);
>  
>  		/* blend config update */
> -		for (lm_idx = 0; lm_idx < dpu_crtc->num_mixers; lm_idx++) {
> +		for (lm_idx = 0; lm_idx < cstate->num_mixers; lm_idx++) {
>  			_dpu_crtc_setup_blend_cfg(mixer + lm_idx, pstate);
>  
>  			mixer[lm_idx].flush_mask |= flush_mask;
> @@ -260,7 +262,7 @@ static void _dpu_crtc_blend_setup_mixer(struct drm_crtc *crtc,
>  static void _dpu_crtc_blend_setup(struct drm_crtc *crtc)
>  {
>  	struct dpu_crtc *dpu_crtc;
> -	struct dpu_crtc_state *dpu_crtc_state;
> +	struct dpu_crtc_state *cstate;
>  	struct dpu_crtc_mixer *mixer;
>  	struct dpu_hw_ctl *ctl;
>  	struct dpu_hw_mixer *lm;
> @@ -271,26 +273,26 @@ static void _dpu_crtc_blend_setup(struct drm_crtc *crtc)
>  		return;
>  
>  	dpu_crtc = to_dpu_crtc(crtc);
> -	dpu_crtc_state = to_dpu_crtc_state(crtc->state);
> -	mixer = dpu_crtc->mixers;
> +	cstate = to_dpu_crtc_state(crtc->state);
> +	mixer = cstate->mixers;
>  
>  	DPU_DEBUG("%s\n", dpu_crtc->name);
>  
> -	if (dpu_crtc->num_mixers > CRTC_DUAL_MIXERS) {
> -		DPU_ERROR("invalid number mixers: %d\n", dpu_crtc->num_mixers);
> +	if (cstate->num_mixers > CRTC_DUAL_MIXERS) {
> +		DPU_ERROR("invalid number mixers: %d\n", cstate->num_mixers);

Nit - this could be worded a bit better - "too many mixers" would be better, but
I have to ask - under what circumstances would the number of mixers be larger
than CRTC_DUAL_MIXERS and/or why don't we support a dynamic number of mixers?

>  		return;
>  	}

<ship>

> +static void _dpu_crtc_setup_mixers(struct drm_crtc_state *crtc_state)
>  {
> -	struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc);
> -	struct dpu_kms *dpu_kms = _dpu_crtc_get_kms(crtc);
> -	struct dpu_rm *rm = &dpu_kms->rm;
> +	struct dpu_crtc_state *cstate = to_dpu_crtc_state(crtc_state);
>  	struct dpu_crtc_mixer *mixer;
> -	struct dpu_hw_ctl *last_valid_ctl = NULL;
>  	int i;
> -	struct dpu_rm_hw_iter lm_iter, ctl_iter;
>  
> -	dpu_rm_init_hw_iter(&lm_iter, enc->base.id, DPU_HW_BLK_LM);
> -	dpu_rm_init_hw_iter(&ctl_iter, enc->base.id, DPU_HW_BLK_CTL);
> +	if (!cstate->num_mixers || !cstate->num_ctls) {
> +		DPU_ERROR("invalid hw count-lm's:%d ctl's:%d\n",
> +			cstate->num_mixers, cstate->num_ctls);

This can also be reworded - I don't know what lm is, and you shouldn't use an
apostrophe - it would just be 'ctls' or 'mixers'.  Instead of invalid, perhaps
using "no mixers defined" and "no controls defined".


> +		return;
> +	}

<snip>

> @@ -1584,6 +1579,23 @@ static int dpu_crtc_atomic_check(struct drm_crtc *crtc,
>  		}
>  	}
>  
> +	/* Resource allocation */
> +	dpu_priv_state = dpu_get_private_state(state->state);
> +

Ah, here is a use of dpu_get_private_state() that assumes dpu_priv_state is
valid - this could use a ERR check but I think it also implies that
dpu_get_private_state() doesn't have a legitimate reason to return NULL.

> +	topology = dpu_crtc_get_topology(cstate, &state->adjusted_mode);
> +	if (!topology.needs_realloc)
> +		goto end;
> +
> +	dpu_rm_release_crtc_res(&dpu_priv_state->rm, cstate);
> +	rc = dpu_rm_reserve_crtc_res(&dpu_priv_state->rm, cstate, &topology);
> +	if (rc) {
> +		DPU_ERROR("failed to allocate resources for crtc: %d\n",
> +				crtc->base.id);
> +		goto end;
> +	}
> +
> +	_dpu_crtc_setup_mixers(state);
> +
>  end:
>  	return rc;
>  }

<snip>

> @@ -657,27 +666,31 @@ static int dpu_encoder_virt_atomic_check(
>  		}
>  	}
>  
> -	topology = dpu_encoder_get_topology(dpu_enc, dpu_kms, adj_mode);
> +	if (ret)
> +		goto end;
>  
> -	/* Reserve dynamic resources now. Indicating AtomicTest phase */
> -	if (!ret) {
> -		/*
> -		 * Avoid reserving resources when mode set is pending. Topology
> -		 * info may not be available to complete reservation.
> -		 */
> -		if (drm_atomic_crtc_needs_modeset(crtc_state)
> -				&& dpu_enc->mode_set_complete) {
> -			ret = dpu_rm_reserve(&dpu_kms->rm, drm_enc, crtc_state,
> -				conn_state, topology, true);
> -			dpu_enc->mode_set_complete = false;
> -		}
> +	/* hw resource allocation */
> +	dpu_encoder_get_hw_resources(drm_enc, &enc_hw_res, conn_state);
> +
> +	dpu_priv_state = dpu_get_private_state(crtc_state->state);

Here is another use of dpu_get_private_state() that assumes a valid pointer.

> +	topology = dpu_encoder_get_topology(dpu_enc, dpu_cstate);
> +	if (!topology.needs_realloc)
> +		goto end;
> +
> +	dpu_rm_release_encoder_res(&dpu_priv_state->rm, dpu_cstate);
> +	ret = dpu_rm_reserve_encoder_res(&dpu_priv_state->rm,
> +						     dpu_cstate, &enc_hw_res);
> +	if (ret) {
> +		DPU_ERROR_ENC(dpu_enc,
> +				"failed to allocate hw resources\n");
> +		goto end;
>  	}
>  
> -	if (!ret)
> -		drm_mode_set_crtcinfo(adj_mode, 0);
> +	drm_mode_set_crtcinfo(adj_mode, 0);
>  
>  	DPU_EVT32(DRMID(drm_enc), adj_mode->flags, adj_mode->private_flags);
> -
> +end:
>  	return ret;
>  }

<snip>

> @@ -1170,35 +1159,48 @@ void dpu_encoder_virt_restore(struct drm_encoder *drm_enc)
>  static void dpu_encoder_virt_enable(struct drm_encoder *drm_enc)
>  {
>  	struct dpu_encoder_virt *dpu_enc = NULL;
> +	struct dpu_encoder_phys *phys  = NULL;
>  	int i, ret = 0;
> -	struct drm_display_mode *cur_mode = NULL;
>  
>  	if (!drm_enc) {
>  		DPU_ERROR("invalid encoder\n");
>  		return;
>  	}
>  	dpu_enc = to_dpu_encoder_virt(drm_enc);
> -	cur_mode = &dpu_enc->base.crtc->state->adjusted_mode;
>  
>  	DPU_DEBUG_ENC(dpu_enc, "\n");
> -	DPU_EVT32(DRMID(drm_enc), cur_mode->hdisplay, cur_mode->vdisplay);
>  
>  	dpu_enc->cur_master = NULL;
> +	dpu_enc->cur_slave = NULL;
>  	for (i = 0; i < dpu_enc->num_phys_encs; i++) {
> -		struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i];
> +		phys = dpu_enc->phys_encs[i];
>  
> -		if (phys && phys->ops.is_master && phys->ops.is_master(phys)) {
> -			DPU_DEBUG_ENC(dpu_enc, "master is now idx %d\n", i);
> +		if (!phys || !phys->ops.is_master)
> +			continue;
> +
> +		if (phys->ops.is_master(phys)) {
> +			DPU_DEBUG_ENC(dpu_enc, "master is at idx %d\n", i);
>  			dpu_enc->cur_master = phys;
> -			break;
> +		} else {
> +			DPU_DEBUG_ENC(dpu_enc, "slave is at idx %d\n", i);
> +			dpu_enc->cur_slave = phys;
>  		}
>  	}
>  
>  	if (!dpu_enc->cur_master) {
> -		DPU_ERROR("virt encoder has no master! num_phys %d\n", i);
> +		DPU_ERROR("virt encoder has no master!\n");

I don't think this rises to the occasion of needing a exclamation point.

<snip>

-- 
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project


More information about the Freedreno mailing list