[PATCH] drm/msm/mdp5: release SMB(shared memory blocks) in various cases

Archit Taneja architt at codeaurora.org
Mon Jun 22 03:34:31 PDT 2015


On 06/19/2015 11:33 PM, Wentao Xu wrote:
> Release all blocks after the pipe is disabled, even when vsync
> didn't happen in some error cases. Allow requesting SMB multiple
> times before configuring to hardware, by releasing blocks not
> programmed to hardware yet for shrinking case.

Tested-by: Archit Taneja <architt at codeaurora.org>

>
> Signed-off-by: Wentao Xu <wentaox at codeaurora.org>
> ---
>   drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c   | 13 +++++
>   drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h   |  2 +
>   drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c | 33 +++++-------
>   drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c   | 87 ++++++++++++++++++++++++++-----
>   drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.h   |  1 +
>   5 files changed, 104 insertions(+), 32 deletions(-)
>
> diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
> index 97226a1..db49ee8 100644
> --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
> +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
> @@ -78,7 +78,20 @@ static void mdp5_prepare_commit(struct msm_kms *kms, struct drm_atomic_state *st
>
>   static void mdp5_complete_commit(struct msm_kms *kms, struct drm_atomic_state *state)
>   {
> +	int i;
>   	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
> +	int nplanes = mdp5_kms->dev->mode_config.num_total_plane;
> +
> +	for (i = 0; i < nplanes; i++) {
> +		struct drm_plane *plane = state->planes[i];
> +		struct drm_plane_state *plane_state = state->plane_states[i];
> +
> +		if (!plane)
> +			continue;
> +
> +		mdp5_plane_complete_commit(plane, plane_state);
> +	}
> +
>   	mdp5_disable(mdp5_kms);
>   }
>
> diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h
> index 2c0de17..42f270b 100644
> --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h
> +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h
> @@ -227,6 +227,8 @@ void mdp5_plane_install_properties(struct drm_plane *plane,
>   		struct drm_mode_object *obj);
>   uint32_t mdp5_plane_get_flush(struct drm_plane *plane);
>   void mdp5_plane_complete_flip(struct drm_plane *plane);
> +void mdp5_plane_complete_commit(struct drm_plane *plane,
> +	struct drm_plane_state *state);
>   enum mdp5_pipe mdp5_plane_pipe(struct drm_plane *plane);
>   struct drm_plane *mdp5_plane_init(struct drm_device *dev,
>   		enum mdp5_pipe pipe, bool private_plane, uint32_t reg_offset);
> diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
> index 18a3d20..05b2634 100644
> --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
> +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
> @@ -31,8 +31,6 @@ struct mdp5_plane {
>
>   	uint32_t nformats;
>   	uint32_t formats[32];
> -
> -	bool enabled;
>   };
>   #define to_mdp5_plane(x) container_of(x, struct mdp5_plane, base)
>
> @@ -56,22 +54,6 @@ static bool plane_enabled(struct drm_plane_state *state)
>   	return state->fb && state->crtc;
>   }
>
> -static int mdp5_plane_disable(struct drm_plane *plane)
> -{
> -	struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
> -	struct mdp5_kms *mdp5_kms = get_kms(plane);
> -	enum mdp5_pipe pipe = mdp5_plane->pipe;
> -
> -	DBG("%s: disable", mdp5_plane->name);
> -
> -	if (mdp5_kms) {
> -		/* Release the memory we requested earlier from the SMP: */
> -		mdp5_smp_release(mdp5_kms->smp, pipe);
> -	}
> -
> -	return 0;
> -}
> -
>   static void mdp5_plane_destroy(struct drm_plane *plane)
>   {
>   	struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
> @@ -224,7 +206,6 @@ static void mdp5_plane_atomic_update(struct drm_plane *plane,
>
>   	if (!plane_enabled(state)) {
>   		to_mdp5_plane_state(state)->pending = true;
> -		mdp5_plane_disable(plane);
>   	} else if (to_mdp5_plane_state(state)->mode_changed) {
>   		int ret;
>   		to_mdp5_plane_state(state)->pending = true;
> @@ -602,6 +583,20 @@ uint32_t mdp5_plane_get_flush(struct drm_plane *plane)
>   	return mdp5_plane->flush_mask;
>   }
>
> +/* called after vsync in thread context */
> +void mdp5_plane_complete_commit(struct drm_plane *plane,
> +	struct drm_plane_state *state)
> +{
> +	struct mdp5_kms *mdp5_kms = get_kms(plane);
> +	struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
> +	enum mdp5_pipe pipe = mdp5_plane->pipe;
> +
> +	if (!plane_enabled(plane->state)) {
> +		DBG("%s: free SMP", mdp5_plane->name);
> +		mdp5_smp_release(mdp5_kms->smp, pipe);
> +	}
> +}
> +
>   /* initialize plane */
>   struct drm_plane *mdp5_plane_init(struct drm_device *dev,
>   		enum mdp5_pipe pipe, bool private_plane, uint32_t reg_offset)
> diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c
> index 16702ae..64a27d8 100644
> --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c
> +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c
> @@ -34,22 +34,44 @@
>    * and CANNOT be re-allocated (eg: MMB0 and MMB1 both tied to RGB0).
>    *
>    * For each block that can be dynamically allocated, it can be either
> - * free, or pending/in-use by a client. The updates happen in three steps:
> + *     free:
> + *     The block is free.
> + *
> + *     pending:
> + *     The block is allocated to some client and not free.
> + *
> + *     configured:
> + *     The block is allocated to some client, and assigned to that
> + *     client in MDP5_MDP_SMP_ALLOC registers.
> + *
> + *     inuse:
> + *     The block is being actively used by a client.
> + *
> + * The updates happen in the following steps:
>    *
>    *  1) mdp5_smp_request():
>    *     When plane scanout is setup, calculate required number of
> - *     blocks needed per client, and request.  Blocks not inuse or
> - *     pending by any other client are added to client's pending
> - *     set.
> + *     blocks needed per client, and request. Blocks neither inuse nor
> + *     configured nor pending by any other client are added to client's
> + *     pending set.
> + *     For shrinking, blocks in pending but not in configured can be freed
> + *     directly, but those already in configured will be freed later by
> + *     mdp5_smp_commit.
>    *
>    *  2) mdp5_smp_configure():
>    *     As hw is programmed, before FLUSH, MDP5_MDP_SMP_ALLOC registers
>    *     are configured for the union(pending, inuse)
> + *     Current pending is copied to configured.
> + *     It is assumed that mdp5_smp_request and mdp5_smp_configure not run
> + *     concurrently for the same pipe.
>    *
>    *  3) mdp5_smp_commit():
> - *     After next vblank, copy pending -> inuse.  Optionally update
> + *     After next vblank, copy configured -> inuse.  Optionally update
>    *     MDP5_SMP_ALLOC registers if there are newly unused blocks
>    *
> + *  4) mdp5_smp_release():
> + *     Must be called after the pipe is disabled and no longer uses any SMB
> + *
>    * On the next vblank after changes have been committed to hw, the
>    * client's pending blocks become it's in-use blocks (and no-longer
>    * in-use blocks become available to other clients).
> @@ -77,6 +99,9 @@ struct mdp5_smp {
>   	struct mdp5_client_smp_state client_state[MAX_CLIENTS];
>   };
>
> +static void update_smp_state(struct mdp5_smp *smp,
> +		u32 cid, mdp5_smp_state_t *assigned);
> +
>   static inline
>   struct mdp5_kms *get_kms(struct mdp5_smp *smp)
>   {
> @@ -149,7 +174,12 @@ static int smp_request_block(struct mdp5_smp *smp,
>   		for (i = cur_nblks; i > nblks; i--) {
>   			int blk = find_first_bit(ps->pending, cnt);
>   			clear_bit(blk, ps->pending);
> -			/* don't clear in global smp_state until _commit() */
> +
> +			/* clear in global smp_state if not in configured
> +			 * otherwise until _commit()
> +			 */
> +			if (!test_bit(blk, ps->configured))
> +				clear_bit(blk, smp->state);
>   		}
>   	}
>
> @@ -223,10 +253,33 @@ int mdp5_smp_request(struct mdp5_smp *smp, enum mdp5_pipe pipe, u32 fmt, u32 wid
>   /* Release SMP blocks for all clients of the pipe */
>   void mdp5_smp_release(struct mdp5_smp *smp, enum mdp5_pipe pipe)
>   {
> -	int i, nblks;
> +	int i;
> +	unsigned long flags;
> +	int cnt = smp->blk_cnt;
> +
> +	for (i = 0; i < pipe2nclients(pipe); i++) {
> +		mdp5_smp_state_t assigned;
> +		u32 cid = pipe2client(pipe, i);
> +		struct mdp5_client_smp_state *ps = &smp->client_state[cid];
> +
> +		spin_lock_irqsave(&smp->state_lock, flags);
> +
> +		/* clear hw assignment */
> +		bitmap_or(assigned, ps->inuse, ps->configured, cnt);
> +		update_smp_state(smp, CID_UNUSED, &assigned);
> +
> +		/* free to global pool */
> +		bitmap_andnot(smp->state, smp->state, ps->pending, cnt);
> +		bitmap_andnot(smp->state, smp->state, assigned, cnt);
> +
> +		/* clear client's infor */
> +		bitmap_zero(ps->pending, cnt);
> +		bitmap_zero(ps->configured, cnt);
> +		bitmap_zero(ps->inuse, cnt);
> +
> +		spin_unlock_irqrestore(&smp->state_lock, flags);
> +	}
>
> -	for (i = 0, nblks = 0; i < pipe2nclients(pipe); i++)
> -		smp_request_block(smp, pipe2client(pipe, i), 0);
>   	set_fifo_thresholds(smp, pipe, 0);
>   }
>
> @@ -274,12 +327,20 @@ void mdp5_smp_configure(struct mdp5_smp *smp, enum mdp5_pipe pipe)
>   		u32 cid = pipe2client(pipe, i);
>   		struct mdp5_client_smp_state *ps = &smp->client_state[cid];
>
> -		bitmap_or(assigned, ps->inuse, ps->pending, cnt);
> +		/*
> +		 * if vblank has not happened since last smp_configure
> +		 * skip the configure for now
> +		 */
> +		if (!bitmap_equal(ps->inuse, ps->configured, cnt))
> +			continue;
> +
> +		bitmap_copy(ps->configured, ps->pending, cnt);
> +		bitmap_or(assigned, ps->inuse, ps->configured, cnt);
>   		update_smp_state(smp, cid, &assigned);
>   	}
>   }
>
> -/* step #3: after vblank, copy pending -> inuse: */
> +/* step #3: after vblank, copy configured -> inuse: */
>   void mdp5_smp_commit(struct mdp5_smp *smp, enum mdp5_pipe pipe)
>   {
>   	int cnt = smp->blk_cnt;
> @@ -295,7 +356,7 @@ void mdp5_smp_commit(struct mdp5_smp *smp, enum mdp5_pipe pipe)
>   		 * using, which can be released and made available to other
>   		 * clients:
>   		 */
> -		if (bitmap_andnot(released, ps->inuse, ps->pending, cnt)) {
> +		if (bitmap_andnot(released, ps->inuse, ps->configured, cnt)) {
>   			unsigned long flags;
>
>   			spin_lock_irqsave(&smp->state_lock, flags);
> @@ -306,7 +367,7 @@ void mdp5_smp_commit(struct mdp5_smp *smp, enum mdp5_pipe pipe)
>   			update_smp_state(smp, CID_UNUSED, &released);
>   		}
>
> -		bitmap_copy(ps->inuse, ps->pending, cnt);
> +		bitmap_copy(ps->inuse, ps->configured, cnt);
>   	}
>   }
>
> diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.h
> index e47179f..5b6c236 100644
> --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.h
> +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.h
> @@ -23,6 +23,7 @@
>
>   struct mdp5_client_smp_state {
>   	mdp5_smp_state_t inuse;
> +	mdp5_smp_state_t configured;
>   	mdp5_smp_state_t pending;
>   };
>
>

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


More information about the dri-devel mailing list