Re: [Freedreno] [PATCH v2 20/24] drm/msm: dpu: Use atomic_disable for dpu_crtc_disable
On 2018-11-16 10:42, Sean Paul wrote: From: Sean Paul Matches dpu_crtc_enable and we'll need the old state in a future patch Changes in v2: - None Signed-off-by: Sean Paul Reviewed-by: Jeykumar Sankaran --- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index 4d7f9ff1e9f4..9efb41c7973b 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -815,7 +815,8 @@ static struct drm_crtc_state *dpu_crtc_duplicate_state(struct drm_crtc *crtc) return >base; } -static void dpu_crtc_disable(struct drm_crtc *crtc) +static void dpu_crtc_disable(struct drm_crtc *crtc, +struct drm_crtc_state *old_crtc_state) { struct dpu_crtc *dpu_crtc; struct dpu_crtc_state *cstate; @@ -1407,7 +1408,7 @@ static const struct drm_crtc_funcs dpu_crtc_funcs = { }; static const struct drm_crtc_helper_funcs dpu_crtc_helper_funcs = { - .disable = dpu_crtc_disable, + .atomic_disable = dpu_crtc_disable, .atomic_enable = dpu_crtc_enable, .atomic_check = dpu_crtc_atomic_check, .atomic_begin = dpu_crtc_atomic_begin, -- Jeykumar S ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
Re: [Freedreno] [PATCH v2 19/24] drm/msm: dpu: Remove vblank_callback from encoder
On 2018-11-16 10:42, Sean Paul wrote: From: Sean Paul The indirection of registering a callback and opaque pointer isn't reall useful when there's only one callsite. So instead of having the vblank_cb registration, just give encoder a crtc and let it directly call the vblank handler. In a later patch, we'll make use of this further. Changes in v2: - None Cc: Jeykumar Sankaran Signed-off-by: Sean Paul Reviewed-by: Jeykumar Sankaran --- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c| 8 +++ drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h| 6 + drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 25 +++-- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h | 10 - 4 files changed, 26 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index 141ed1b0e90a..4d7f9ff1e9f4 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -293,9 +293,8 @@ enum dpu_intf_mode dpu_crtc_get_intf_mode(struct drm_crtc *crtc) return INTF_MODE_NONE; } -static void dpu_crtc_vblank_cb(void *data) +void dpu_crtc_vblank_callback(struct drm_crtc *crtc) { - struct drm_crtc *crtc = (struct drm_crtc *)data; struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); /* keep statistics on vblank callback - with auto reset via debugfs */ @@ -771,8 +770,7 @@ static void _dpu_crtc_vblank_enable_no_lock( DRMID(enc), enable, dpu_crtc); - dpu_encoder_register_vblank_callback(enc, - dpu_crtc_vblank_cb, (void *)crtc); + dpu_encoder_assign_crtc(enc, crtc); } } else { list_for_each_entry(enc, >mode_config.encoder_list, head) { @@ -783,7 +781,7 @@ static void _dpu_crtc_vblank_enable_no_lock( DRMID(enc), enable, dpu_crtc); - dpu_encoder_register_vblank_callback(enc, NULL, NULL); + dpu_encoder_assign_crtc(enc, NULL); } } } diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h index 93d21a61a040..54595cc29be5 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h @@ -270,6 +270,12 @@ static inline int dpu_crtc_frame_pending(struct drm_crtc *crtc) */ int dpu_crtc_vblank(struct drm_crtc *crtc, bool en); +/** + * dpu_crtc_vblank_callback - called on vblank irq, issues completion events + * @crtc: Pointer to drm crtc object + */ +void dpu_crtc_vblank_callback(struct drm_crtc *crtc); + /** * dpu_crtc_commit_kickoff - trigger kickoff of the commit for this crtc * @crtc: Pointer to drm crtc object diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index d89ac520f7e6..fd6514f681ae 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -142,9 +142,11 @@ enum dpu_enc_rc_states { * @intfs_swapped Whether or not the phys_enc interfaces have been swapped * for partial update right-only cases, such as pingpong * split where virtual pingpong does not generate IRQs - * @crtc_vblank_cb:Callback into the upper layer / CRTC for - * notification of the VBLANK - * @crtc_vblank_cb_data: Data from upper layer for VBLANK notification + * @crtc: Pointer to the currently assigned crtc. Normally you + * would use crtc->state->encoder_mask to determine the + * link between encoder/crtc. However in this case we need + * to track crtc in the disable() hook which is called + * _after_ encoder_mask is cleared. * @crtc_kickoff_cb: Callback into CRTC that will flush & start * all CTL paths * @crtc_kickoff_cb_data: Opaque user data given to crtc_kickoff_cb @@ -186,8 +188,7 @@ struct dpu_encoder_virt { bool intfs_swapped; - void (*crtc_vblank_cb)(void *); - void *crtc_vblank_cb_data; + struct drm_crtc *crtc; struct dentry *debugfs_root; struct mutex enc_lock; @@ -1241,8 +1242,8 @@ static void dpu_encoder_vblank_callback(struct drm_encoder *drm_enc, dpu_enc = to_dpu_encoder_virt(drm_enc); spin_lock_irqsave(_enc->enc_spinlock, lock_flags); - if (dpu_enc->crtc_vblank_cb) - dpu_enc->crtc_vblank_cb(dpu_enc->crtc_vblank_cb_data); + if (dpu_enc->crtc) + dpu_crtc_vblank_callback(dpu_enc->crtc); spin_unlock_irqrestore(_enc->enc_spinlock, lock_flags);
Re: [Freedreno] [PATCH v2 18/24] drm/msm: dpu: Remove crtc_lock from setup_mixers
On 2018-11-16 10:42, Sean Paul wrote: From: Sean Paul I think the intention here was to protect the enc->crtc access, but that's insufficient to avoid enc->crtc changing. Fortunately we're already holding the modeset lock when this is called (from atomic_check), so remove the crtc_lock and add a modeset lock check. While we're at it, use the encoder mask from crtc state instead of legacy pointer. Changes in v2: - None Signed-off-by: Sean Paul Reviewed-by: Jeykumar Sankaran --- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 12 +++- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index c49aaf412b6e..141ed1b0e90a 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -474,19 +474,13 @@ static void _dpu_crtc_setup_mixer_for_encoder( static void _dpu_crtc_setup_mixers(struct drm_crtc *crtc) { - struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); struct drm_encoder *enc; - mutex_lock(_crtc->crtc_lock); - /* Check for mixers on all encoders attached to this crtc */ - list_for_each_entry(enc, >dev->mode_config.encoder_list, head) { - if (enc->crtc != crtc) - continue; + WARN_ON(!drm_modeset_is_locked(>mutex)); + /* Check for mixers on all encoders attached to this crtc */ + drm_for_each_encoder_mask(enc, crtc->dev, crtc->state->encoder_mask) _dpu_crtc_setup_mixer_for_encoder(crtc, enc); - } - - mutex_unlock(_crtc->crtc_lock); } static void _dpu_crtc_setup_lm_bounds(struct drm_crtc *crtc, -- Jeykumar S ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
Re: [Freedreno] [PATCH v2 13/24] drm/msm: dpu: Don't drop locks in crtc_vblank_enable
On 2018-11-16 10:42, Sean Paul wrote: From: Sean Paul Now that runtime resume is handled in encoder, we don't need to worry about crtc_lock recursion when calling pm_runtime_(get|put). So drop the lock drops in _dpu_crtc_vblank_enable_no_lock(). Changes in v2: - None Signed-off-by: Sean Paul Reviewed-by: Jeykumar Sankaran --- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 6 -- 1 file changed, 6 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index 9be24907f8c1..80de5289ada3 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -777,10 +777,7 @@ static void _dpu_crtc_vblank_enable_no_lock( struct drm_encoder *enc; if (enable) { - /* drop lock since power crtc cb may try to re-acquire lock */ - mutex_unlock(_crtc->crtc_lock); pm_runtime_get_sync(dev->dev); - mutex_lock(_crtc->crtc_lock); list_for_each_entry(enc, >mode_config.encoder_list, head) { if (enc->crtc != crtc) @@ -805,10 +802,7 @@ static void _dpu_crtc_vblank_enable_no_lock( dpu_encoder_register_vblank_callback(enc, NULL, NULL); } - /* drop lock since power crtc cb may try to re-acquire lock */ - mutex_unlock(_crtc->crtc_lock); pm_runtime_put_sync(dev->dev); - mutex_lock(_crtc->crtc_lock); } } -- Jeykumar S ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
Re: [Freedreno] [PATCH v2 05/24] drm/msm: dpu: Handle crtc pm_runtime_resume() directly
On 2018-11-16 10:42, Sean Paul wrote: From: Sean Paul Instead of registering through dpu_power_handle just to get a call on runtime_resume, call the crtc function directly. Changes in v2: - None Signed-off-by: Sean Paul Reviewed-by: Jeykumar Sankaran --- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 23 ++- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h | 10 ++ drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 4 drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h | 8 4 files changed, 20 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index e09209d6c469..c55cb751e2b4 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -33,7 +33,6 @@ #include "dpu_plane.h" #include "dpu_encoder.h" #include "dpu_vbif.h" -#include "dpu_power_handle.h" #include "dpu_core_perf.h" #include "dpu_trace.h" @@ -69,8 +68,6 @@ static void dpu_crtc_destroy(struct drm_crtc *crtc) if (!crtc) return; - dpu_crtc->phandle = NULL; - drm_crtc_cleanup(crtc); mutex_destroy(_crtc->crtc_lock); kfree(dpu_crtc); @@ -844,15 +841,17 @@ static struct drm_crtc_state *dpu_crtc_duplicate_state(struct drm_crtc *crtc) return >base; } -static void dpu_crtc_handle_power_event(u32 event_type, void *arg) +void dpu_crtc_runtime_resume(struct drm_crtc *crtc) { - struct drm_crtc *crtc = arg; struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); struct drm_encoder *encoder; mutex_lock(_crtc->crtc_lock); - trace_dpu_crtc_handle_power_event(DRMID(crtc), event_type); + if (!dpu_crtc->enabled) + goto end; + + trace_dpu_crtc_runtime_resume(DRMID(crtc)); /* restore encoder; crtc will be programmed during commit */ drm_for_each_encoder(encoder, crtc->dev) { @@ -862,6 +861,7 @@ static void dpu_crtc_handle_power_event(u32 event_type, void *arg) dpu_encoder_virt_restore(encoder); } +end: mutex_unlock(_crtc->crtc_lock); } @@ -917,10 +917,6 @@ static void dpu_crtc_disable(struct drm_crtc *crtc) dpu_encoder_register_frame_event_callback(encoder, NULL, NULL); } - if (dpu_crtc->power_event) - dpu_power_handle_unregister_event(dpu_crtc->phandle, - dpu_crtc->power_event); - memset(cstate->mixers, 0, sizeof(cstate->mixers)); cstate->num_mixers = 0; @@ -972,11 +968,6 @@ static void dpu_crtc_enable(struct drm_crtc *crtc, /* Enable/restore vblank irq handling */ drm_crtc_vblank_on(crtc); - - dpu_crtc->power_event = dpu_power_handle_register_event( - dpu_crtc->phandle, DPU_POWER_EVENT_ENABLE, - dpu_crtc_handle_power_event, crtc, dpu_crtc->name); - } struct plane_state { @@ -1522,8 +1513,6 @@ struct drm_crtc *dpu_crtc_init(struct drm_device *dev, struct drm_plane *plane, /* initialize event handling */ spin_lock_init(_crtc->event_lock); - dpu_crtc->phandle = >phandle; - DPU_DEBUG("%s: successfully initialized crtc\n", dpu_crtc->name); return crtc; } diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h index 4822602402f9..1dca91d1210f 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h @@ -151,7 +151,6 @@ struct dpu_crtc_frame_event { * @event_worker : Event worker queue * @event_lock: Spinlock around event handling code * @phandle: Pointer to power handler - * @power_event : registered power event handle * @cur_perf : current performance committed to clock/bandwidth driver */ struct dpu_crtc { @@ -187,9 +186,6 @@ struct dpu_crtc { /* for handling internal event thread */ spinlock_t event_lock; - struct dpu_power_handle *phandle; - struct dpu_power_event *power_event; - struct dpu_core_perf_params cur_perf; struct dpu_crtc_smmu_state_data smmu_state; @@ -333,4 +329,10 @@ static inline bool dpu_crtc_is_enabled(struct drm_crtc *crtc) return crtc ? crtc->enabled : false; } +/** + * dpu_crtc_runtime_resume - called by the top-level on pm_runtime_resume + * @crtc: CRTC to resume + */ +void dpu_crtc_runtime_resume(struct drm_crtc *crtc); + #endif /* _DPU_CRTC_H_ */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index ab8574ab8327..654ea5060e02 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -1137,6 +1137,7 @@ static int __maybe_unused dpu_runtime_resume(struct device *dev) int rc = -1; struct platform_device *pdev = to_platform_devi
Re: [Freedreno] [PATCH 1/2] drm/msm/dpu: add dpu encoder uninit
On 2018-11-16 13:37, Sean Paul wrote: On Fri, Nov 16, 2018 at 04:35:26PM -0500, Sean Paul wrote: On Fri, Nov 16, 2018 at 11:22:21AM -0800, Jeykumar Sankaran wrote: > Add encoder interface to release dpu encoder > on mode_init failures in kms. > > Signed-off-by: Jeykumar Sankaran > --- > drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 12 ++-- > drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h | 6 ++ > 2 files changed, 16 insertions(+), 2 deletions(-) > > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c > index dd7ab85..b253165 100644 > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c > @@ -422,6 +422,15 @@ void dpu_encoder_get_hw_resources(struct drm_encoder *drm_enc, >} > } > > +void dpu_encoder_uninit(struct drm_encoder *drm_enc) > +{ > + struct dpu_encoder_virt *dpu_enc = to_dpu_encoder_virt(drm_enc); > + > + drm_encoder_cleanup(drm_enc); > + > + kfree(dpu_enc); > +} > + > static void dpu_encoder_destroy(struct drm_encoder *drm_enc) > { >struct dpu_encoder_virt *dpu_enc = NULL; > @@ -453,10 +462,9 @@ static void dpu_encoder_destroy(struct drm_encoder *drm_enc) >dpu_enc->num_phys_encs = 0; >mutex_unlock(_enc->enc_lock); > > - drm_encoder_cleanup(drm_enc); >mutex_destroy(_enc->enc_lock); > > - kfree(dpu_enc); > + dpu_encoder_uninit(drm_enc); > } > > void dpu_encoder_helper_split_config( > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h > index 9dbf38f..60b88bd 100644 > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h > @@ -142,6 +142,12 @@ struct drm_encoder *dpu_encoder_init( >int drm_enc_mode); > > /** > + * dpu_encoder_uninit - uninitialize virtual encoder object > + * @drm_enc: Pointer to drm encoder > + */ > +void dpu_encoder_uninit(struct drm_encoder *drm_enc); Just make it static? I just saw YueHaibing's patch to remove the kfree entirely since dpu_enc is devm_* managed. IMO, that'd be a better solution than this. Sean I still need the unint here to call drm_encoder_cleanup if the display mode_init fails. I will rebase the patch on top of https://lkml.org/lkml/2018/11/17/87 Thanks, Jeykumar S. > + > +/** > * dpu_encoder_setup - setup dpu_encoder for the display probed > * @dev: Pointer to drm device structure > * @enc: Pointer to the drm_encoder > -- > The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, > a Linux Foundation Collaborative Project > -- Sean Paul, Software Engineer, Google / Chromium OS -- Jeykumar S ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
Re: [Freedreno] [PATCH 1/2] drm/msm/dpu: add dpu encoder uninit
On 2018-11-16 13:35, Sean Paul wrote: On Fri, Nov 16, 2018 at 11:22:21AM -0800, Jeykumar Sankaran wrote: Add encoder interface to release dpu encoder on mode_init failures in kms. Signed-off-by: Jeykumar Sankaran --- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 12 ++-- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h | 6 ++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index dd7ab85..b253165 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -422,6 +422,15 @@ void dpu_encoder_get_hw_resources(struct drm_encoder *drm_enc, } } +void dpu_encoder_uninit(struct drm_encoder *drm_enc) +{ + struct dpu_encoder_virt *dpu_enc = to_dpu_encoder_virt(drm_enc); + + drm_encoder_cleanup(drm_enc); + + kfree(dpu_enc); +} + static void dpu_encoder_destroy(struct drm_encoder *drm_enc) { struct dpu_encoder_virt *dpu_enc = NULL; @@ -453,10 +462,9 @@ static void dpu_encoder_destroy(struct drm_encoder *drm_enc) dpu_enc->num_phys_encs = 0; mutex_unlock(_enc->enc_lock); - drm_encoder_cleanup(drm_enc); mutex_destroy(_enc->enc_lock); - kfree(dpu_enc); + dpu_encoder_uninit(drm_enc); } void dpu_encoder_helper_split_config( diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h index 9dbf38f..60b88bd 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h @@ -142,6 +142,12 @@ struct drm_encoder *dpu_encoder_init( int drm_enc_mode); /** + * dpu_encoder_uninit - uninitialize virtual encoder object + * @drm_enc: Pointer to drm encoder + */ +void dpu_encoder_uninit(struct drm_encoder *drm_enc); Just make it static? encoder_uninit will be called by dpu_kms in patch 2/2 in case of mode_init failures. Thanks and Regards, Jeykumar S. + +/** * dpu_encoder_setup - setup dpu_encoder for the display probed * @dev: Pointer to drm device structure * @enc: Pointer to the drm_encoder -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project -- Jeykumar S ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
Re: [Freedreno] [PATCH v2 3/3] drm/msm: dpu: Make legacy cursor updates asynchronous
On 2018-11-16 12:02, Sean Paul wrote: On Thu, Nov 08, 2018 at 02:00:51PM -0800, Jeykumar Sankaran wrote: On 2018-10-30 09:00, Sean Paul wrote: > From: Sean Paul > > This patch sprinkles a few async/legacy_cursor_update checks > through commit to ensure that cursor updates aren't blocked on vsync. > There are 2 main components to this, the first is that we don't want to > wait_for_commit_done in msm_atomic before returning from > atomic_complete. > The second is that in dpu we don't want to wait for frame_done events > when > updating the cursor. > > Changes in v2: > - None > > Signed-off-by: Sean Paul > --- > drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c| 44 +++-- > drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h| 3 +- > drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 22 +++ > drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h | 6 ++- > drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 5 ++- > drivers/gpu/drm/msm/msm_atomic.c| 3 +- > 6 files changed, 49 insertions(+), 34 deletions(-) > > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c > b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c > index ed84cf44a222..1e3e57817b72 100644 > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c > @@ -702,7 +702,7 @@ static int _dpu_crtc_wait_for_frame_done(struct > drm_crtc *crtc) >return rc; > } > > -void dpu_crtc_commit_kickoff(struct drm_crtc *crtc) > +void dpu_crtc_commit_kickoff(struct drm_crtc *crtc, bool async) > { >struct drm_encoder *encoder; >struct drm_device *dev = crtc->dev; > @@ -731,27 +731,30 @@ void dpu_crtc_commit_kickoff(struct drm_crtc > *crtc) > * Encoder will flush/start now, unless it has a tx > pending. > * If so, it may delay and flush at an irq event (e.g. > ppdone) > */ > - dpu_encoder_prepare_for_kickoff(encoder, ); > + dpu_encoder_prepare_for_kickoff(encoder, , async); >} > > - /* wait for frame_event_done completion */ > - DPU_ATRACE_BEGIN("wait_for_frame_done_event"); > - ret = _dpu_crtc_wait_for_frame_done(crtc); > - DPU_ATRACE_END("wait_for_frame_done_event"); > - if (ret) { > - DPU_ERROR("crtc%d wait for frame done > failed;frame_pending%d\n", > - crtc->base.id, > - atomic_read(_crtc->frame_pending)); > - goto end; > - } > > - if (atomic_inc_return(_crtc->frame_pending) == 1) { > - /* acquire bandwidth and other resources */ > - DPU_DEBUG("crtc%d first commit\n", crtc->base.id); > - } else > - DPU_DEBUG("crtc%d commit\n", crtc->base.id); > + if (!async) { > + /* wait for frame_event_done completion */ > + DPU_ATRACE_BEGIN("wait_for_frame_done_event"); > + ret = _dpu_crtc_wait_for_frame_done(crtc); > + DPU_ATRACE_END("wait_for_frame_done_event"); > + if (ret) { > + DPU_ERROR("crtc%d wait for frame done > failed;frame_pending%d\n", > + crtc->base.id, > + > atomic_read(_crtc->frame_pending)); > + goto end; > + } > + > + if (atomic_inc_return(_crtc->frame_pending) == 1) { > + /* acquire bandwidth and other resources */ > + DPU_DEBUG("crtc%d first commit\n", crtc->base.id); > + } else > + DPU_DEBUG("crtc%d commit\n", crtc->base.id); > > - dpu_crtc->play_count++; > + dpu_crtc->play_count++; > + } > >dpu_vbif_clear_errors(dpu_kms); > > @@ -759,11 +762,12 @@ void dpu_crtc_commit_kickoff(struct drm_crtc > *crtc) >if (encoder->crtc != crtc) >continue; > > - dpu_encoder_kickoff(encoder); > + dpu_encoder_kickoff(encoder, async); >} > > end: > - reinit_completion(_crtc->frame_done_comp); > + if (!async) > + reinit_completion(_crtc->frame_done_comp); >DPU_ATRACE_END("crtc_commit"); > } > > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h > b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h > index 4822602402f9..ec633ce3ee6c 100644 > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h > @@ -277,8 +277,9 @@ int dpu_crtc_vblank(struct drm_crtc *crtc, bool en); > /** > * dpu_crtc_commit_kickoff - trigger kickoff of the commit for this > crtc > * @crtc: Pointer to drm crtc object > + * @async: true if the commit is asy
Re: [Freedreno] [PATCH v2 16/24] drm/msm: dpu: Add modeset lock checks where applicable
On 2018-11-16 10:42, Sean Paul wrote: From: Sean Paul Add modeset lock checks to functions that could be called outside the core atomic stack. Changes in v2: - None Signed-off-by: Sean Paul --- Reviewed-by: Jeykumar Sankaran drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 2 ++ drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 1 + 2 files changed, 3 insertions(+) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index a008a87a8113..cd0a0bea4335 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -284,6 +284,8 @@ enum dpu_intf_mode dpu_crtc_get_intf_mode(struct drm_crtc *crtc) return INTF_MODE_NONE; } + WARN_ON(!drm_modeset_is_locked(>mutex)); + /* TODO: Returns the first INTF_MODE, could there be multiple values? */ drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask) return dpu_encoder_get_intf_mode(encoder); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index 64134d619748..5104fc01147e 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -358,6 +358,7 @@ void dpu_kms_encoder_enable(struct drm_encoder *encoder) if (funcs && funcs->commit) funcs->commit(encoder); + WARN_ON(!drm_modeset_is_locked(>mode_config.connection_mutex)); drm_for_each_crtc(crtc, dev) { if (!(crtc->state->encoder_mask & drm_encoder_mask(encoder))) continue; -- Jeykumar S ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
Re: [Freedreno] [PATCH v2 15/24] drm/msm: dpu: Stop using encoder->crtc pointer
On 2018-11-16 10:42, Sean Paul wrote: From: Sean Paul It's for legacy drivers, for atomic drivers crtc->state->encoder_mask should be used to map encoder to crtc. Changes in v2: - None Signed-off-by: Sean Paul --- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 46 drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 19 +++--- 2 files changed, 29 insertions(+), 36 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index 156f4c77ca44..a008a87a8113 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -284,9 +284,9 @@ enum dpu_intf_mode dpu_crtc_get_intf_mode(struct drm_crtc *crtc) return INTF_MODE_NONE; } - drm_for_each_encoder(encoder, crtc->dev) - if (encoder->crtc == crtc) - return dpu_encoder_get_intf_mode(encoder); + /* TODO: Returns the first INTF_MODE, could there be multiple values? */ + drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask) + return dpu_encoder_get_intf_mode(encoder); return INTF_MODE_NONE; } @@ -551,13 +551,9 @@ static void dpu_crtc_atomic_begin(struct drm_crtc *crtc, spin_unlock_irqrestore(>event_lock, flags); } - list_for_each_entry(encoder, >mode_config.encoder_list, head) { - if (encoder->crtc != crtc) - continue; - - /* encoder will trigger pending mask now */ + /* encoder will trigger pending mask now */ + drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask) dpu_encoder_trigger_kickoff_pending(encoder); - } /* * If no mixers have been allocated in dpu_crtc_atomic_check(), @@ -704,7 +700,6 @@ static int _dpu_crtc_wait_for_frame_done(struct drm_crtc *crtc) void dpu_crtc_commit_kickoff(struct drm_crtc *crtc) { struct drm_encoder *encoder; - struct drm_device *dev = crtc->dev; struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); struct dpu_kms *dpu_kms = _dpu_crtc_get_kms(crtc); struct dpu_crtc_state *cstate = to_dpu_crtc_state(crtc->state); @@ -720,16 +715,13 @@ void dpu_crtc_commit_kickoff(struct drm_crtc *crtc) DPU_ATRACE_BEGIN("crtc_commit"); - list_for_each_entry(encoder, >mode_config.encoder_list, head) { + /* +* Encoder will flush/start now, unless it has a tx pending. If so, it +* may delay and flush at an irq event (e.g. ppdone) +*/ + drm_for_each_encoder_mask(encoder, crtc->dev, + crtc->state->encoder_mask) { struct dpu_encoder_kickoff_params params = { 0 }; - - if (encoder->crtc != crtc) - continue; - - /* -* Encoder will flush/start now, unless it has a tx pending. -* If so, it may delay and flush at an irq event (e.g. ppdone) -*/ dpu_encoder_prepare_for_kickoff(encoder, ); } @@ -754,12 +746,8 @@ void dpu_crtc_commit_kickoff(struct drm_crtc *crtc) dpu_vbif_clear_errors(dpu_kms); - list_for_each_entry(encoder, >mode_config.encoder_list, head) { - if (encoder->crtc != crtc) - continue; - + drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask) dpu_encoder_kickoff(encoder); - } We wont be holding the modeset locks here (and in crtc_atomic_begin) in the display thread. Is it safe to iterate over encoder_mask? end: reinit_completion(_crtc->frame_done_comp); @@ -883,11 +871,8 @@ static void dpu_crtc_disable(struct drm_crtc *crtc) dpu_core_perf_crtc_update(crtc, 0, true); - drm_for_each_encoder(encoder, crtc->dev) { - if (encoder->crtc != crtc) - continue; + drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask) dpu_encoder_register_frame_event_callback(encoder, NULL, NULL); - } memset(cstate->mixers, 0, sizeof(cstate->mixers)); cstate->num_mixers = 0; @@ -922,12 +907,9 @@ static void dpu_crtc_enable(struct drm_crtc *crtc, DRM_DEBUG_KMS("crtc%d\n", crtc->base.id); dpu_crtc = to_dpu_crtc(crtc); - drm_for_each_encoder(encoder, crtc->dev) { - if (encoder->crtc != crtc) - continue; + drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask) dpu_encoder_register_frame_event_callback(encoder, dpu_crtc_frame_event_cb, (void *)crtc); - } mutex_lock(_crtc->crtc_lock); trace_dpu_crtc_enable(DRMID(crtc), true, dpu_crtc); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index 1bec4540f3e1..64134d619748 100644 ---
Re: [Freedreno] [PATCH v2 14/24] drm/msm: dpu: Grab the modeset locks in frame_event
On 2018-11-16 10:42, Sean Paul wrote: From: Sean Paul This patch wraps dpu_core_perf_crtc_release_bw() with modeset locks since it digs into the state objects. Changes in v2: - None Signed-off-by: Sean Paul --- Reviewed-by: Jeykumar Sankaran drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index 80de5289ada3..156f4c77ca44 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -335,7 +335,9 @@ static void dpu_crtc_frame_event_work(struct kthread_work *work) /* release bandwidth and other resources */ trace_dpu_crtc_frame_event_done(DRMID(crtc), fevent->event); + drm_modeset_lock_all(crtc->dev); dpu_core_perf_crtc_release_bw(crtc); + drm_modeset_unlock_all(crtc->dev); We might need to revisit this locking when we measure for performance as it could block the incoming frame locking. } else { trace_dpu_crtc_frame_event_more_pending(DRMID(crtc), fevent->event); -- Jeykumar S ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
[Freedreno] [PATCH 2/2] drm/msm/dpu: add display port support in DPU
Add display port support in DPU by creating hooks for DP encoder enumeration and encoder mode initialization. This change is based on the SDM845 Display port driver changes[1]. [1] https://lwn.net/Articles/768265/ Signed-off-by: Jeykumar Sankaran --- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 3 ++ drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 49 + 2 files changed, 46 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index b253165..e9c7edc6 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -2048,6 +2048,9 @@ static int dpu_encoder_setup_display(struct dpu_encoder_virt *dpu_enc, case DRM_MODE_ENCODER_DSI: intf_type = INTF_DSI; break; + case DRM_MODE_ENCODER_TMDS: + intf_type = INTF_DP; + break; default: DPU_ERROR_ENC(dpu_enc, "unsupported display interface type\n"); return -EINVAL; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index 985c855..b823a37 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -473,6 +473,31 @@ static void _dpu_kms_initialize_dsi(struct drm_device *dev, } } +static void _dpu_kms_initialize_displayport(struct drm_device *dev, + struct msm_drm_private *priv, + struct dpu_kms *dpu_kms) +{ + struct drm_encoder *encoder = NULL; + int rc; + + if (!priv->dp) + return; + + encoder = dpu_encoder_init(dev, DRM_MODE_ENCODER_TMDS); + if (IS_ERR_OR_NULL(encoder)) { + DPU_ERROR("encoder init failed for dsi display\n"); + return; + } + + priv->encoders[priv->num_encoders++] = encoder; + + rc = msm_dp_modeset_init(priv->dp, dev, encoder); + if (rc) { + DPU_ERROR("modeset_init failed for DP, rc = %d\n", rc); + dpu_encoder_uninit(encoder); + } +} + /** * _dpu_kms_setup_displays - create encoders, bridges and connectors * for underlying displays @@ -487,6 +512,8 @@ static void _dpu_kms_setup_displays(struct drm_device *dev, { _dpu_kms_initialize_dsi(dev, priv, dpu_kms); + _dpu_kms_initialize_displayport(dev, priv, dpu_kms); + /** * Extend this function to initialize other * types of displays @@ -723,13 +750,23 @@ static void _dpu_kms_set_encoder_mode(struct msm_kms *kms, info.capabilities = cmd_mode ? MSM_DISPLAY_CAP_CMD_MODE : MSM_DISPLAY_CAP_VID_MODE; - /* TODO: No support for DSI swap */ - for (i = 0; i < ARRAY_SIZE(priv->dsi); i++) { - if (priv->dsi[i]) { - info.h_tile_instance[info.num_of_h_tiles] = i; - info.num_of_h_tiles++; + switch (info.intf_type) { + case DRM_MODE_ENCODER_DSI: + /* TODO: No support for DSI swap */ + for (i = 0; i < ARRAY_SIZE(priv->dsi); i++) { + if (priv->dsi[i]) { + info.h_tile_instance[info.num_of_h_tiles] = i; + info.num_of_h_tiles++; + } } - } + break; + case DRM_MODE_ENCODER_TMDS: + info.num_of_h_tiles = 1; + break; + default: + DPU_ERROR("Invalid connector type\n"); + return; + }; rc = dpu_encoder_setup(encoder->dev, encoder, ); if (rc) -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
[Freedreno] [PATCH 1/2] drm/msm/dpu: add dpu encoder uninit
Add encoder interface to release dpu encoder on mode_init failures in kms. Signed-off-by: Jeykumar Sankaran --- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 12 ++-- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h | 6 ++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index dd7ab85..b253165 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -422,6 +422,15 @@ void dpu_encoder_get_hw_resources(struct drm_encoder *drm_enc, } } +void dpu_encoder_uninit(struct drm_encoder *drm_enc) +{ + struct dpu_encoder_virt *dpu_enc = to_dpu_encoder_virt(drm_enc); + + drm_encoder_cleanup(drm_enc); + + kfree(dpu_enc); +} + static void dpu_encoder_destroy(struct drm_encoder *drm_enc) { struct dpu_encoder_virt *dpu_enc = NULL; @@ -453,10 +462,9 @@ static void dpu_encoder_destroy(struct drm_encoder *drm_enc) dpu_enc->num_phys_encs = 0; mutex_unlock(_enc->enc_lock); - drm_encoder_cleanup(drm_enc); mutex_destroy(_enc->enc_lock); - kfree(dpu_enc); + dpu_encoder_uninit(drm_enc); } void dpu_encoder_helper_split_config( diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h index 9dbf38f..60b88bd 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h @@ -142,6 +142,12 @@ struct drm_encoder *dpu_encoder_init( int drm_enc_mode); /** + * dpu_encoder_uninit - uninitialize virtual encoder object + * @drm_enc: Pointer to drm encoder + */ +void dpu_encoder_uninit(struct drm_encoder *drm_enc); + +/** * dpu_encoder_setup - setup dpu_encoder for the display probed * @dev: Pointer to drm device structure * @enc: Pointer to the drm_encoder -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
[Freedreno] [PATCH v3 5/5] drm/msm: subclass work object for vblank events
msm maintains a separate structure to define vblank work definitions and a list to track events submitted to the workqueue. We can avoid this redundant list and its protection mechanism, if we subclass the work object to encapsulate vblank event parameters. changes in v2: - subclass optimization on system wq (Sean Paul) changes in v3: - none Signed-off-by: Jeykumar Sankaran --- drivers/gpu/drm/msm/msm_drv.c | 65 +-- drivers/gpu/drm/msm/msm_drv.h | 7 - 2 files changed, 19 insertions(+), 53 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 478c14c..3f9064d 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -203,61 +203,44 @@ u32 msm_readl(const void __iomem *addr) return val; } -struct vblank_event { - struct list_head node; +struct msm_vblank_work { + struct work_struct work; int crtc_id; bool enable; + struct msm_drm_private *priv; }; static void vblank_ctrl_worker(struct work_struct *work) { - struct msm_vblank_ctrl *vbl_ctrl = container_of(work, - struct msm_vblank_ctrl, work); - struct msm_drm_private *priv = container_of(vbl_ctrl, - struct msm_drm_private, vblank_ctrl); + struct msm_vblank_work *vbl_work = container_of(work, + struct msm_vblank_work, work); + struct msm_drm_private *priv = vbl_work->priv; struct msm_kms *kms = priv->kms; - struct vblank_event *vbl_ev, *tmp; - unsigned long flags; - - spin_lock_irqsave(_ctrl->lock, flags); - list_for_each_entry_safe(vbl_ev, tmp, _ctrl->event_list, node) { - list_del(_ev->node); - spin_unlock_irqrestore(_ctrl->lock, flags); - - if (vbl_ev->enable) - kms->funcs->enable_vblank(kms, - priv->crtcs[vbl_ev->crtc_id]); - else - kms->funcs->disable_vblank(kms, - priv->crtcs[vbl_ev->crtc_id]); - - kfree(vbl_ev); - spin_lock_irqsave(_ctrl->lock, flags); - } + if (vbl_work->enable) + kms->funcs->enable_vblank(kms, priv->crtcs[vbl_work->crtc_id]); + else + kms->funcs->disable_vblank(kms, priv->crtcs[vbl_work->crtc_id]); - spin_unlock_irqrestore(_ctrl->lock, flags); + kfree(vbl_work); } static int vblank_ctrl_queue_work(struct msm_drm_private *priv, int crtc_id, bool enable) { - struct msm_vblank_ctrl *vbl_ctrl = >vblank_ctrl; - struct vblank_event *vbl_ev; - unsigned long flags; + struct msm_vblank_work *vbl_work; - vbl_ev = kzalloc(sizeof(*vbl_ev), GFP_ATOMIC); - if (!vbl_ev) + vbl_work = kzalloc(sizeof(*vbl_work), GFP_ATOMIC); + if (!vbl_work) return -ENOMEM; - vbl_ev->crtc_id = crtc_id; - vbl_ev->enable = enable; + INIT_WORK(_work->work, vblank_ctrl_worker); - spin_lock_irqsave(_ctrl->lock, flags); - list_add_tail(_ev->node, _ctrl->event_list); - spin_unlock_irqrestore(_ctrl->lock, flags); + vbl_work->crtc_id = crtc_id; + vbl_work->enable = enable; + vbl_work->priv = priv; - schedule_work(_ctrl->work); + schedule_work(_work->work); return 0; } @@ -269,19 +252,12 @@ static int msm_drm_uninit(struct device *dev) struct msm_drm_private *priv = ddev->dev_private; struct msm_kms *kms = priv->kms; struct msm_mdss *mdss = priv->mdss; - struct msm_vblank_ctrl *vbl_ctrl = >vblank_ctrl; - struct vblank_event *vbl_ev, *tmp; int i; /* We must cancel and cleanup any pending vblank enable/disable * work before drm_irq_uninstall() to avoid work re-enabling an * irq after uninstall has disabled it. */ - flush_work(_ctrl->work); - list_for_each_entry_safe(vbl_ev, tmp, _ctrl->event_list, node) { - list_del(_ev->node); - kfree(vbl_ev); - } /* clean up event worker threads */ for (i = 0; i < priv->num_crtcs; i++) { @@ -469,9 +445,6 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) priv->wq = alloc_ordered_workqueue("msm", 0); INIT_LIST_HEAD(>inactive_list); - INIT_LIST_HEAD(>vblank_ctrl.event_list); - INIT_WORK(>vblank_ctrl.work, vblank_ctrl_worker); - spin_lock_init(>vblank_ctrl.lock); drm_mode_config_init(ddev); diff --git a/drivers/gpu/drm/ms
[Freedreno] [PATCH v3 2/5] drm/msm/dpu: use system wq for vblank events
DPU was using one thread per display to dispatch async commits and vblank requests. Since clean up already happened in msm to use the common thread for all the display commits, display threads are only used to cater vblank requests. Since a single thread is sufficient to do the job without any performance hits, use system workqueue to queue requests. A separate patch is submitted later in this series to remove the display threads altogether. changes in v2: - switch to system wq before removing disp threads (Sean Paul) changes in v3: - none Signed-off-by: Jeykumar Sankaran --- drivers/gpu/drm/msm/msm_drv.c | 9 - drivers/gpu/drm/msm/msm_drv.h | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 1ab9ead..90447f3 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -209,7 +209,7 @@ struct vblank_event { bool enable; }; -static void vblank_ctrl_worker(struct kthread_work *work) +static void vblank_ctrl_worker(struct work_struct *work) { struct msm_vblank_ctrl *vbl_ctrl = container_of(work, struct msm_vblank_ctrl, work); @@ -257,8 +257,7 @@ static int vblank_ctrl_queue_work(struct msm_drm_private *priv, list_add_tail(_ev->node, _ctrl->event_list); spin_unlock_irqrestore(_ctrl->lock, flags); - kthread_queue_work(>disp_thread[crtc_id].worker, - _ctrl->work); + schedule_work(_ctrl->work); return 0; } @@ -278,7 +277,7 @@ static int msm_drm_uninit(struct device *dev) * work before drm_irq_uninstall() to avoid work re-enabling an * irq after uninstall has disabled it. */ - kthread_flush_work(_ctrl->work); + flush_work(_ctrl->work); list_for_each_entry_safe(vbl_ev, tmp, _ctrl->event_list, node) { list_del(_ev->node); kfree(vbl_ev); @@ -476,7 +475,7 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) INIT_LIST_HEAD(>inactive_list); INIT_LIST_HEAD(>vblank_ctrl.event_list); - kthread_init_work(>vblank_ctrl.work, vblank_ctrl_worker); + INIT_WORK(>vblank_ctrl.work, vblank_ctrl_worker); spin_lock_init(>vblank_ctrl.lock); drm_mode_config_init(ddev); diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index 9d11f32..126345c4 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -78,7 +78,7 @@ enum msm_mdp_plane_property { }; struct msm_vblank_ctrl { - struct kthread_work work; + struct work_struct work; struct list_head event_list; spinlock_t lock; }; -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
[Freedreno] [PATCH v3 3/5] drm/msm/dpu: use system wq for idle power collapse
msm is using system wq for dispatching commit and vblank events. Switch idle power collapse feature also to use system wq to handle delayed work handlers so that msm can get rid of redundant display threads. changes in v2: - patch introduced in v2 changes in v3: - none Signed-off-by: Jeykumar Sankaran --- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 22 ++ 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index 82c55ef..dd7ab85 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -201,7 +201,7 @@ struct dpu_encoder_virt { bool idle_pc_supported; struct mutex rc_lock; enum dpu_enc_rc_states rc_state; - struct kthread_delayed_work delayed_off_work; + struct delayed_work delayed_off_work; struct kthread_work vsync_event_work; struct msm_display_topology topology; bool mode_set_complete; @@ -740,7 +740,6 @@ static int dpu_encoder_resource_control(struct drm_encoder *drm_enc, { struct dpu_encoder_virt *dpu_enc; struct msm_drm_private *priv; - struct msm_drm_thread *disp_thread; bool is_vid_mode = false; if (!drm_enc || !drm_enc->dev || !drm_enc->dev->dev_private || @@ -753,12 +752,6 @@ static int dpu_encoder_resource_control(struct drm_encoder *drm_enc, is_vid_mode = dpu_enc->disp_info.capabilities & MSM_DISPLAY_CAP_VID_MODE; - if (drm_enc->crtc->index >= ARRAY_SIZE(priv->disp_thread)) { - DPU_ERROR("invalid crtc index\n"); - return -EINVAL; - } - disp_thread = >disp_thread[drm_enc->crtc->index]; - /* * when idle_pc is not supported, process only KICKOFF, STOP and MODESET * events and return early for other events (ie wb display). @@ -775,8 +768,7 @@ static int dpu_encoder_resource_control(struct drm_encoder *drm_enc, switch (sw_event) { case DPU_ENC_RC_EVENT_KICKOFF: /* cancel delayed off work, if any */ - if (kthread_cancel_delayed_work_sync( - _enc->delayed_off_work)) + if (cancel_delayed_work_sync(_enc->delayed_off_work)) DPU_DEBUG_ENC(dpu_enc, "sw_event:%d, work cancelled\n", sw_event); @@ -835,8 +827,7 @@ static int dpu_encoder_resource_control(struct drm_encoder *drm_enc, return 0; } - kthread_queue_delayed_work( - _thread->worker, + schedule_delayed_work( _enc->delayed_off_work, msecs_to_jiffies(dpu_enc->idle_timeout)); @@ -847,8 +838,7 @@ static int dpu_encoder_resource_control(struct drm_encoder *drm_enc, case DPU_ENC_RC_EVENT_PRE_STOP: /* cancel delayed off work, if any */ - if (kthread_cancel_delayed_work_sync( - _enc->delayed_off_work)) + if (cancel_delayed_work_sync(_enc->delayed_off_work)) DPU_DEBUG_ENC(dpu_enc, "sw_event:%d, work cancelled\n", sw_event); @@ -1351,7 +1341,7 @@ static void dpu_encoder_frame_done_callback( } } -static void dpu_encoder_off_work(struct kthread_work *work) +static void dpu_encoder_off_work(struct work_struct *work) { struct dpu_encoder_virt *dpu_enc = container_of(work, struct dpu_encoder_virt, delayed_off_work.work); @@ -2191,7 +2181,7 @@ int dpu_encoder_setup(struct drm_device *dev, struct drm_encoder *enc, mutex_init(_enc->rc_lock); - kthread_init_delayed_work(_enc->delayed_off_work, + INIT_DELAYED_WORK(_enc->delayed_off_work, dpu_encoder_off_work); dpu_enc->idle_timeout = IDLE_TIMEOUT; -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
[Freedreno] [PATCH v3 1/5] drm/msm/dpu: use kthread_destroy_worker to release msm workers
use kthread_destroy_worker to destroy workers and release their associated kthreads. changes in v3: - introduced in the series Signed-off-by: Jeykumar Sankaran --- drivers/gpu/drm/msm/msm_drv.c | 6 ++ 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 9c9f7ff..1ab9ead 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -287,14 +287,12 @@ static int msm_drm_uninit(struct device *dev) /* clean up display commit/event worker threads */ for (i = 0; i < priv->num_crtcs; i++) { if (priv->disp_thread[i].thread) { - kthread_flush_worker(>disp_thread[i].worker); - kthread_stop(priv->disp_thread[i].thread); + kthread_destroy_worker(>disp_thread[i].worker); priv->disp_thread[i].thread = NULL; } if (priv->event_thread[i].thread) { - kthread_flush_worker(>event_thread[i].worker); - kthread_stop(priv->event_thread[i].thread); + kthread_destroy_worker(>event_thread[i].worker); priv->event_thread[i].thread = NULL; } } -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
[Freedreno] [PATCH v3 4/5] drm/msm: clean up display thread
Since there are no clients using these threads, cleaning it up. changes in v2: - switch all the dependent clients to use system wq before removing the disp_threads (Sean Paul) changes in v3: - none Signed-off-by: Jeykumar Sankaran --- drivers/gpu/drm/msm/msm_drv.c | 35 +-- drivers/gpu/drm/msm/msm_drv.h | 1 - 2 files changed, 1 insertion(+), 35 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 90447f3..478c14c 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -283,13 +283,8 @@ static int msm_drm_uninit(struct device *dev) kfree(vbl_ev); } - /* clean up display commit/event worker threads */ + /* clean up event worker threads */ for (i = 0; i < priv->num_crtcs; i++) { - if (priv->disp_thread[i].thread) { - kthread_destroy_worker(>disp_thread[i].worker); - priv->disp_thread[i].thread = NULL; - } - if (priv->event_thread[i].thread) { kthread_destroy_worker(>event_thread[i].worker); priv->event_thread[i].thread = NULL; @@ -541,27 +536,6 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) */ param.sched_priority = 16; for (i = 0; i < priv->num_crtcs; i++) { - - /* initialize display thread */ - priv->disp_thread[i].crtc_id = priv->crtcs[i]->base.id; - kthread_init_worker(>disp_thread[i].worker); - priv->disp_thread[i].dev = ddev; - priv->disp_thread[i].thread = - kthread_run(kthread_worker_fn, - >disp_thread[i].worker, - "crtc_commit:%d", priv->disp_thread[i].crtc_id); - if (IS_ERR(priv->disp_thread[i].thread)) { - DRM_DEV_ERROR(dev, "failed to create crtc_commit kthread\n"); - priv->disp_thread[i].thread = NULL; - goto err_msm_uninit; - } - - ret = sched_setscheduler(priv->disp_thread[i].thread, -SCHED_FIFO, ); - if (ret) - dev_warn(dev, "disp_thread set priority failed: %d\n", -ret); - /* initialize event thread */ priv->event_thread[i].crtc_id = priv->crtcs[i]->base.id; kthread_init_worker(>event_thread[i].worker); @@ -576,13 +550,6 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) goto err_msm_uninit; } - /** -* event thread should also run at same priority as disp_thread -* because it is handling frame_done events. A lower priority -* event thread and higher priority disp_thread can causes -* frame_pending counters beyond 2. This can lead to commit -* failure at crtc commit level. -*/ ret = sched_setscheduler(priv->event_thread[i].thread, SCHED_FIFO, ); if (ret) diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index 126345c4..05d33a7 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -197,7 +197,6 @@ struct msm_drm_private { unsigned int num_crtcs; struct drm_crtc *crtcs[MAX_CRTCS]; - struct msm_drm_thread disp_thread[MAX_CRTCS]; struct msm_drm_thread event_thread[MAX_CRTCS]; unsigned int num_encoders; -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
Re: [Freedreno] [PATCH 6/8] drm/msm: dpu: Separate crtc assignment from vblank enable
On 2018-11-14 12:52, Sean Paul wrote: On Wed, Nov 14, 2018 at 12:46:32PM -0800, Jeykumar Sankaran wrote: On 2018-11-14 11:57, Ville Syrjälä wrote: > On Wed, Nov 14, 2018 at 11:43:51AM -0800, Jeykumar Sankaran wrote: > > On 2018-11-14 07:16, Sean Paul wrote: > > > On Tue, Nov 13, 2018 at 04:48:12PM -0800, Jeykumar Sankaran wrote: > > >> On 2018-11-13 12:52, Sean Paul wrote: > > >> > From: Sean Paul > > >> > > > >> > Instead of assigning/clearing the crtc on vblank enable/disable, we > > > can > > >> > just assign and clear the crtc on modeset. That allows us to just > > > toggle > > >> > the encoder's vblank interrupts on vblank_enable. > > >> > > > >> > So why is this important? Previously the driver was using the > legacy > > >> > pointers to assign/clear the crtc. Legacy pointers are cleared > _after_ > > >> Which pointers are you referring here as legacy pointers? CRTC? > > > > > > encoder->crtc in this case. The loop in vblank_enable_no_lock relies > on > > > enc->crtc == crtc > > > > > >> > disabling the hardware, so the legacy pointer was valid during > > >> > vblank_disable, but that's not something we should rely on. > > >> > > > >> > Instead of relying on the core ordering the legacy pointer > assignments > > >> > just so, we'll assign the crtc in dpu_crtc enable/disable. This is > the > > >> > only place that mapping can change, so we're covered there. > > >> > > > >> > We're also taking advantage of drm_crtc_vblank_on/off. By using > this, > > > we > > >> > ensure that vblank_enable/disable can never be called while the > crtc > > > is > > >> > off (which means the assigned crtc will always be valid). As such, > we > > >> > > >> What about the drm_vblank_enable/disable triggered by drm_vblank_get > > > when > > >> crtc > > >> is disabled? What is the expected behavior there? the > vblank_requested > > >> variable removed by the next patch was introduced to cache the > > >> request. > > > > > > That case is covered by the modeset locks held when calling disable(). > > > > > I am sure it will take care of drm_crtc_vblank_on/off triggered within > > crtc_disable. > > My question was what was the expected behaviour when > > DRM_IOCTL_WAIT_VBLANK is > > called when crtc is disabled? the ioctl will try to call > > drm_vblank_get > > and I > > don't see the patch checking for crtc being enabled in the path. > > drm_vblank_off() > // .enable_vblank/.disable_vblank will never be called here > drm_vblank_on() > > So if you use drm_vblank_on/off judiciously you will never > have to deal with this particular problem. > Thanks ville for clarifying that. We can make sure to avoid that sequence if we have control over it. In DPU, CRTC calls dpu_vblank_off in crtc_disable. After disabling, no one stopping userspace clients to call into DRM_IOCTL_WAIT_VBLANK on the crtc. This ioctl calls enable_vblank when it sees the vblank is disabled [1]. That's prevented by this bit in drm_vblank.c: /* * Prevent subsequent drm_vblank_get() from re-enabling * the vblank interrupt by bumping the refcount. */ if (!vblank->inmodeset) { atomic_inc(>refcount); vblank->inmodeset = 1; } Basically it turns off the hw and then takes a reference such that drm_vblank_get will never call drm_vblank_enable. Sean That explains it! Thanks Sean! So far, the dpu_crtc_vblank was failing when it finds that the crtc is disabled. With this patch, the condition was removed, so I was wondering what is the expected behavior with this patch. [1] https://gitlab.freedesktop.org/seanpaul/dpu-staging/blob/for-next/drivers/ gpu/drm/drm_vblank.c#L956 Thanks and Regards, Jeykumar S. > -- > Ville Syrjälä > Intel -- Jeykumar S -- Sean Paul, Software Engineer, Google / Chromium OS -- Jeykumar S ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
Re: [Freedreno] [PATCH 6/8] drm/msm: dpu: Separate crtc assignment from vblank enable
On 2018-11-14 11:57, Ville Syrjälä wrote: On Wed, Nov 14, 2018 at 11:43:51AM -0800, Jeykumar Sankaran wrote: On 2018-11-14 07:16, Sean Paul wrote: > On Tue, Nov 13, 2018 at 04:48:12PM -0800, Jeykumar Sankaran wrote: >> On 2018-11-13 12:52, Sean Paul wrote: >> > From: Sean Paul >> > >> > Instead of assigning/clearing the crtc on vblank enable/disable, we > can >> > just assign and clear the crtc on modeset. That allows us to just > toggle >> > the encoder's vblank interrupts on vblank_enable. >> > >> > So why is this important? Previously the driver was using the legacy >> > pointers to assign/clear the crtc. Legacy pointers are cleared _after_ >> Which pointers are you referring here as legacy pointers? CRTC? > > encoder->crtc in this case. The loop in vblank_enable_no_lock relies on > enc->crtc == crtc > >> > disabling the hardware, so the legacy pointer was valid during >> > vblank_disable, but that's not something we should rely on. >> > >> > Instead of relying on the core ordering the legacy pointer assignments >> > just so, we'll assign the crtc in dpu_crtc enable/disable. This is the >> > only place that mapping can change, so we're covered there. >> > >> > We're also taking advantage of drm_crtc_vblank_on/off. By using this, > we >> > ensure that vblank_enable/disable can never be called while the crtc > is >> > off (which means the assigned crtc will always be valid). As such, we >> >> What about the drm_vblank_enable/disable triggered by drm_vblank_get > when >> crtc >> is disabled? What is the expected behavior there? the vblank_requested >> variable removed by the next patch was introduced to cache the >> request. > > That case is covered by the modeset locks held when calling disable(). > I am sure it will take care of drm_crtc_vblank_on/off triggered within crtc_disable. My question was what was the expected behaviour when DRM_IOCTL_WAIT_VBLANK is called when crtc is disabled? the ioctl will try to call drm_vblank_get and I don't see the patch checking for crtc being enabled in the path. drm_vblank_off() // .enable_vblank/.disable_vblank will never be called here drm_vblank_on() So if you use drm_vblank_on/off judiciously you will never have to deal with this particular problem. Thanks ville for clarifying that. We can make sure to avoid that sequence if we have control over it. In DPU, CRTC calls dpu_vblank_off in crtc_disable. After disabling, no one stopping userspace clients to call into DRM_IOCTL_WAIT_VBLANK on the crtc. This ioctl calls enable_vblank when it sees the vblank is disabled [1]. So far, the dpu_crtc_vblank was failing when it finds that the crtc is disabled. With this patch, the condition was removed, so I was wondering what is the expected behavior with this patch. [1] https://gitlab.freedesktop.org/seanpaul/dpu-staging/blob/for-next/drivers/gpu/drm/drm_vblank.c#L956 Thanks and Regards, Jeykumar S. -- Ville Syrjälä Intel -- Jeykumar S ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
Re: [Freedreno] [PATCH 6/8] drm/msm: dpu: Separate crtc assignment from vblank enable
On 2018-11-14 07:16, Sean Paul wrote: On Tue, Nov 13, 2018 at 04:48:12PM -0800, Jeykumar Sankaran wrote: On 2018-11-13 12:52, Sean Paul wrote: > From: Sean Paul > > Instead of assigning/clearing the crtc on vblank enable/disable, we can > just assign and clear the crtc on modeset. That allows us to just toggle > the encoder's vblank interrupts on vblank_enable. > > So why is this important? Previously the driver was using the legacy > pointers to assign/clear the crtc. Legacy pointers are cleared _after_ Which pointers are you referring here as legacy pointers? CRTC? encoder->crtc in this case. The loop in vblank_enable_no_lock relies on enc->crtc == crtc > disabling the hardware, so the legacy pointer was valid during > vblank_disable, but that's not something we should rely on. > > Instead of relying on the core ordering the legacy pointer assignments > just so, we'll assign the crtc in dpu_crtc enable/disable. This is the > only place that mapping can change, so we're covered there. > > We're also taking advantage of drm_crtc_vblank_on/off. By using this, we > ensure that vblank_enable/disable can never be called while the crtc is > off (which means the assigned crtc will always be valid). As such, we What about the drm_vblank_enable/disable triggered by drm_vblank_get when crtc is disabled? What is the expected behavior there? the vblank_requested variable removed by the next patch was introduced to cache the request. That case is covered by the modeset locks held when calling disable(). I am sure it will take care of drm_crtc_vblank_on/off triggered within crtc_disable. My question was what was the expected behaviour when DRM_IOCTL_WAIT_VBLANK is called when crtc is disabled? the ioctl will try to call drm_vblank_get and I don't see the patch checking for crtc being enabled in the path. Thanks and Regards, Jeykumar S. > don't need to use modeset locks or the crtc_lock in the > vblank_enable/disable routine to be sure state is consistent. > > ...I think. > > Signed-off-by: Sean Paul > --- > drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c| 77 + > drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 27 +--- > drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h | 10 +++ > 3 files changed, 59 insertions(+), 55 deletions(-) > > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c > b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c > index 4b7f98a6ab60..59e823281fdf 100644 > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c > @@ -757,43 +757,6 @@ void dpu_crtc_commit_kickoff(struct drm_crtc *crtc) >DPU_ATRACE_END("crtc_commit"); > } > > -/** > - * _dpu_crtc_vblank_enable_no_lock - update power resource and vblank > request > - * @dpu_crtc: Pointer to dpu crtc structure > - * @enable: Whether to enable/disable vblanks > - */ > -static void _dpu_crtc_vblank_enable_no_lock( > - struct dpu_crtc *dpu_crtc, bool enable) > -{ > - struct drm_crtc *crtc = _crtc->base; > - struct drm_device *dev = crtc->dev; > - struct drm_encoder *enc; > - > - if (enable) { > - list_for_each_entry(enc, >mode_config.encoder_list, > head) { > - if (enc->crtc != crtc) > - continue; > - > - > trace_dpu_crtc_vblank_enable(DRMID(_crtc->base), > - DRMID(enc), enable, > - dpu_crtc); > - > - dpu_encoder_assign_crtc(enc, crtc); > - } > - } else { > - list_for_each_entry(enc, >mode_config.encoder_list, > head) { > - if (enc->crtc != crtc) > - continue; > - > - > trace_dpu_crtc_vblank_enable(DRMID(_crtc->base), > - DRMID(enc), enable, > - dpu_crtc); > - > - dpu_encoder_assign_crtc(enc, NULL); > - } > - } > -} > - > /** > * dpu_crtc_duplicate_state - state duplicate hook > * @crtc: Pointer to drm crtc structure > @@ -847,6 +810,10 @@ static void dpu_crtc_disable(struct drm_crtc *crtc, >/* Disable/save vblank irq handling */ >drm_crtc_vblank_off(crtc); > > + drm_for_each_encoder_mask(encoder, crtc->dev, > +old_crtc_state->encoder_mask) > + dpu_encoder_assign_crtc(encoder, NULL); > + >mutex_lock(_crtc->crtc_lock); > >/* wait for frame_event_done completion */ > @@ -856,9 +823,6 @@ static void dpu_crtc_disable(struct drm_crtc *crtc, >atomic_read(_crtc->frame_pending)); &g
Re: [Freedreno] [PATCH 3/8] drm/msm: dpu: Remove vblank_callback from encoder
On 2018-11-14 07:13, Sean Paul wrote: On Tue, Nov 13, 2018 at 04:47:22PM -0800, Jeykumar Sankaran wrote: On 2018-11-13 12:52, Sean Paul wrote: > From: Sean Paul > > The indirection of registering a callback and opaque pointer isn't real > useful when there's only one callsite. So instead of having the > vblank_cb registration, just give encoder a crtc and let it directly > call the vblank handler. > > In a later patch, we'll make use of this further. > > Signed-off-by: Sean Paul > --- > drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c| 8 +++ > drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h| 6 + > drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 25 +++-- > drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h | 10 - > 4 files changed, 26 insertions(+), 23 deletions(-) > > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c > b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c > index adda0aa0cbaa..38119b4d4a80 100644 > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c > @@ -291,9 +291,8 @@ enum dpu_intf_mode dpu_crtc_get_intf_mode(struct > drm_crtc *crtc) >return INTF_MODE_NONE; > } > > -static void dpu_crtc_vblank_cb(void *data) > +void dpu_crtc_vblank_callback(struct drm_crtc *crtc) > { > - struct drm_crtc *crtc = (struct drm_crtc *)data; >struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); Since we are calling into a locally stored CRTC and not tracking disable. Should we check for crtc->enable before processing the callback? I see vblank_on/off cant be called when CRTC is disabled with the rest of the patches in the series. But this callback is triggered by IRQ's context. Hmm, yeah, I had assumed that we wouldn't have any interrupts after irq disable. However it doesn't seem like that's the case. That said, I don't think checking crtc->enable is quite what we want. In the case of disable, the crtc is cleared from the encoder, so checking for crtc != NULL would be better here. SGTY? That would still cause a race as crtc assignment will be protected by modeset locks and crtc != NULL check isn't. Now that I've dug into the vblank irq handling a bit in the encoder, it seems like that could be moved to the crtc and a bunch of the encoder->crtc->encoder bouncing around could be avoided. Off the top of your head, is there any reason we couldn't move the vblank irq handling into crtc from encoder? vblank irq handlers are only needed for video mode. As with all the other IRQ's, the handlers are implemented in phys_encoder level and the events are forwarded as and when needed. BTW, the vblank irq flows from phys_enc->virtual_enc->crtc. Thanks, Jeykumar S. Sean > >/* keep statistics on vblank callback - with auto reset via > debugfs */ > @@ -779,8 +778,7 @@ static void _dpu_crtc_vblank_enable_no_lock( > DRMID(enc), enable, > dpu_crtc); > > - dpu_encoder_register_vblank_callback(enc, > - dpu_crtc_vblank_cb, (void *)crtc); > + dpu_encoder_assign_crtc(enc, crtc); >} >} else { >list_for_each_entry(enc, >mode_config.encoder_list, > head) { > @@ -791,7 +789,7 @@ static void _dpu_crtc_vblank_enable_no_lock( > DRMID(enc), enable, > dpu_crtc); > > - dpu_encoder_register_vblank_callback(enc, NULL, > NULL); > + dpu_encoder_assign_crtc(enc, NULL); >} >} > } > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h > b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h > index 93d21a61a040..54595cc29be5 100644 > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h > @@ -270,6 +270,12 @@ static inline int dpu_crtc_frame_pending(struct > drm_crtc *crtc) > */ > int dpu_crtc_vblank(struct drm_crtc *crtc, bool en); > > +/** > + * dpu_crtc_vblank_callback - called on vblank irq, issues completion > events > + * @crtc: Pointer to drm crtc object > + */ > +void dpu_crtc_vblank_callback(struct drm_crtc *crtc); > + > /** > * dpu_crtc_commit_kickoff - trigger kickoff of the commit for this > crtc > * @crtc: Pointer to drm crtc object > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c > b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c > index d89ac520f7e6..fd6514f681ae 100644 > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c > @@ -142,9 +142,11 @@ enum dpu_enc_rc_states { > * @intfs_swapped Whether or not the
Re: [Freedreno] [PATCH 6/8] drm/msm: dpu: Separate crtc assignment from vblank enable
On 2018-11-13 12:52, Sean Paul wrote: From: Sean Paul Instead of assigning/clearing the crtc on vblank enable/disable, we can just assign and clear the crtc on modeset. That allows us to just toggle the encoder's vblank interrupts on vblank_enable. So why is this important? Previously the driver was using the legacy pointers to assign/clear the crtc. Legacy pointers are cleared _after_ Which pointers are you referring here as legacy pointers? CRTC? disabling the hardware, so the legacy pointer was valid during vblank_disable, but that's not something we should rely on. Instead of relying on the core ordering the legacy pointer assignments just so, we'll assign the crtc in dpu_crtc enable/disable. This is the only place that mapping can change, so we're covered there. We're also taking advantage of drm_crtc_vblank_on/off. By using this, we ensure that vblank_enable/disable can never be called while the crtc is off (which means the assigned crtc will always be valid). As such, we What about the drm_vblank_enable/disable triggered by drm_vblank_get when crtc is disabled? What is the expected behavior there? the vblank_requested variable removed by the next patch was introduced to cache the request. don't need to use modeset locks or the crtc_lock in the vblank_enable/disable routine to be sure state is consistent. ...I think. Signed-off-by: Sean Paul --- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c| 77 + drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 27 +--- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h | 10 +++ 3 files changed, 59 insertions(+), 55 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index 4b7f98a6ab60..59e823281fdf 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -757,43 +757,6 @@ void dpu_crtc_commit_kickoff(struct drm_crtc *crtc) DPU_ATRACE_END("crtc_commit"); } -/** - * _dpu_crtc_vblank_enable_no_lock - update power resource and vblank request - * @dpu_crtc: Pointer to dpu crtc structure - * @enable: Whether to enable/disable vblanks - */ -static void _dpu_crtc_vblank_enable_no_lock( - struct dpu_crtc *dpu_crtc, bool enable) -{ - struct drm_crtc *crtc = _crtc->base; - struct drm_device *dev = crtc->dev; - struct drm_encoder *enc; - - if (enable) { - list_for_each_entry(enc, >mode_config.encoder_list, head) { - if (enc->crtc != crtc) - continue; - - trace_dpu_crtc_vblank_enable(DRMID(_crtc->base), -DRMID(enc), enable, -dpu_crtc); - - dpu_encoder_assign_crtc(enc, crtc); - } - } else { - list_for_each_entry(enc, >mode_config.encoder_list, head) { - if (enc->crtc != crtc) - continue; - - trace_dpu_crtc_vblank_enable(DRMID(_crtc->base), -DRMID(enc), enable, -dpu_crtc); - - dpu_encoder_assign_crtc(enc, NULL); - } - } -} - /** * dpu_crtc_duplicate_state - state duplicate hook * @crtc: Pointer to drm crtc structure @@ -847,6 +810,10 @@ static void dpu_crtc_disable(struct drm_crtc *crtc, /* Disable/save vblank irq handling */ drm_crtc_vblank_off(crtc); + drm_for_each_encoder_mask(encoder, crtc->dev, + old_crtc_state->encoder_mask) + dpu_encoder_assign_crtc(encoder, NULL); + mutex_lock(_crtc->crtc_lock); /* wait for frame_event_done completion */ @@ -856,9 +823,6 @@ static void dpu_crtc_disable(struct drm_crtc *crtc, atomic_read(_crtc->frame_pending)); trace_dpu_crtc_disable(DRMID(crtc), false, dpu_crtc); - if (dpu_crtc->enabled && dpu_crtc->vblank_requested) { - _dpu_crtc_vblank_enable_no_lock(dpu_crtc, false); - } dpu_crtc->enabled = false; if (atomic_read(_crtc->frame_pending)) { @@ -922,13 +886,13 @@ static void dpu_crtc_enable(struct drm_crtc *crtc, mutex_lock(_crtc->crtc_lock); trace_dpu_crtc_enable(DRMID(crtc), true, dpu_crtc); - if (!dpu_crtc->enabled && dpu_crtc->vblank_requested) { - _dpu_crtc_vblank_enable_no_lock(dpu_crtc, true); - } dpu_crtc->enabled = true; mutex_unlock(_crtc->crtc_lock); + drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask) + dpu_encoder_assign_crtc(encoder, crtc); + /* Enable/restore vblank irq handling */ drm_crtc_vblank_on(crtc); } @@ -1173,10 +1137,33 @@ static int dpu_crtc_atomic_check(struct drm_crtc *crtc, int dpu_crtc_vblank(struct drm_crtc
Re: [Freedreno] [PATCH 7/8] drm/msm: dpu: Remove vblank_requested flag from dpu_crtc
On 2018-11-13 12:52, Sean Paul wrote: From: Sean Paul It's just for debug output, we don't need it Signed-off-by: Sean Paul --- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 6 -- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h | 2 -- drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h | 14 -- 3 files changed, 4 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index 59e823281fdf..ab96a2e69efa 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -1163,10 +1163,6 @@ int dpu_crtc_vblank(struct drm_crtc *crtc, bool en) dpu_encoder_toggle_vblank_for_crtc(enc, crtc, en); } - mutex_lock(_crtc->crtc_lock); - dpu_crtc->vblank_requested = en; - mutex_unlock(_crtc->crtc_lock); - return 0; } @@ -1282,8 +1278,6 @@ static int _dpu_debugfs_status_show(struct seq_file *s, void *data) dpu_crtc->vblank_cb_time = ktime_set(0, 0); } - seq_printf(s, "vblank_enable:%d\n", dpu_crtc->vblank_requested); - mutex_unlock(_crtc->crtc_lock); drm_modeset_unlock_all(crtc->dev); I see few more references @ https://gitlab.freedesktop.org/seanpaul/dpu-staging/blob/for-next/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c#L900 Which change is removing them? diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h index 54595cc29be5..2b358546af49 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h @@ -132,7 +132,6 @@ struct dpu_crtc_frame_event { * @vblank_cb_count : count of vblank callback since last reset * @play_count: frame count between crtc enable and disable * @vblank_cb_time : ktime at vblank count reset - * @vblank_requested : whether the user has requested vblank events * @enabled : whether the DPU CRTC is currently enabled. updated in the * commit-thread, not state-swap time which is earlier, so * safe to make decisions on during VBLANK on/off work @@ -166,7 +165,6 @@ struct dpu_crtc { u32 vblank_cb_count; u64 play_count; ktime_t vblank_cb_time; - bool vblank_requested; bool enabled; struct list_head feature_list; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h index 328df37d7580..c78b521ceda1 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h @@ -728,20 +728,17 @@ TRACE_EVENT(dpu_crtc_vblank_enable, __field(uint32_t, enc_id ) __field(bool, enable ) __field(bool, enabled ) - __field(bool, vblank_requested ) ), TP_fast_assign( __entry->drm_id = drm_id; __entry->enc_id = enc_id; __entry->enable = enable; __entry->enabled = crtc->enabled; - __entry->vblank_requested = crtc->vblank_requested; ), - TP_printk("id:%u encoder:%u enable:%s state{enabled:%s vblank_req:%s}", + TP_printk("id:%u encoder:%u enable:%s state{enabled:%s}", __entry->drm_id, __entry->enc_id, __entry->enable ? "true" : "false", - __entry->enabled ? "true" : "false", - __entry->vblank_requested ? "true" : "false") + __entry->enabled ? "true" : "false") ); DECLARE_EVENT_CLASS(dpu_crtc_enable_template, @@ -751,18 +748,15 @@ DECLARE_EVENT_CLASS(dpu_crtc_enable_template, __field(uint32_t, drm_id ) __field(bool, enable ) __field(bool, enabled ) - __field(bool, vblank_requested ) ), TP_fast_assign( __entry->drm_id = drm_id; __entry->enable = enable; __entry->enabled = crtc->enabled; - __entry->vblank_requested = crtc->vblank_requested; ), - TP_printk("id:%u enable:%s state{enabled:%s vblank_req:%s}", + TP_printk("id:%u enable:%s state{enabled:%s}", __entry->drm_id, __entry->enable ? "true" : "false", - __entry->enabled ? "true" : "false", - __entry->vblank_requested ? "true" : "false") + __entry->enabled ? "true" : "false") ); DEFINE_EVENT(dpu_crtc_enable_template, dpu_crtc_enable, TP_PROTO(uint32_t drm_id, bool enable, struct dpu_crtc *crtc), -- Jeykumar S ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
Re: [Freedreno] [PATCH 3/8] drm/msm: dpu: Remove vblank_callback from encoder
On 2018-11-13 12:52, Sean Paul wrote: From: Sean Paul The indirection of registering a callback and opaque pointer isn't real useful when there's only one callsite. So instead of having the vblank_cb registration, just give encoder a crtc and let it directly call the vblank handler. In a later patch, we'll make use of this further. Signed-off-by: Sean Paul --- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c| 8 +++ drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h| 6 + drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 25 +++-- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h | 10 - 4 files changed, 26 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index adda0aa0cbaa..38119b4d4a80 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -291,9 +291,8 @@ enum dpu_intf_mode dpu_crtc_get_intf_mode(struct drm_crtc *crtc) return INTF_MODE_NONE; } -static void dpu_crtc_vblank_cb(void *data) +void dpu_crtc_vblank_callback(struct drm_crtc *crtc) { - struct drm_crtc *crtc = (struct drm_crtc *)data; struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); Since we are calling into a locally stored CRTC and not tracking disable. Should we check for crtc->enable before processing the callback? I see vblank_on/off cant be called when CRTC is disabled with the rest of the patches in the series. But this callback is triggered by IRQ's context. /* keep statistics on vblank callback - with auto reset via debugfs */ @@ -779,8 +778,7 @@ static void _dpu_crtc_vblank_enable_no_lock( DRMID(enc), enable, dpu_crtc); - dpu_encoder_register_vblank_callback(enc, - dpu_crtc_vblank_cb, (void *)crtc); + dpu_encoder_assign_crtc(enc, crtc); } } else { list_for_each_entry(enc, >mode_config.encoder_list, head) { @@ -791,7 +789,7 @@ static void _dpu_crtc_vblank_enable_no_lock( DRMID(enc), enable, dpu_crtc); - dpu_encoder_register_vblank_callback(enc, NULL, NULL); + dpu_encoder_assign_crtc(enc, NULL); } } } diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h index 93d21a61a040..54595cc29be5 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h @@ -270,6 +270,12 @@ static inline int dpu_crtc_frame_pending(struct drm_crtc *crtc) */ int dpu_crtc_vblank(struct drm_crtc *crtc, bool en); +/** + * dpu_crtc_vblank_callback - called on vblank irq, issues completion events + * @crtc: Pointer to drm crtc object + */ +void dpu_crtc_vblank_callback(struct drm_crtc *crtc); + /** * dpu_crtc_commit_kickoff - trigger kickoff of the commit for this crtc * @crtc: Pointer to drm crtc object diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index d89ac520f7e6..fd6514f681ae 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -142,9 +142,11 @@ enum dpu_enc_rc_states { * @intfs_swapped Whether or not the phys_enc interfaces have been swapped * for partial update right-only cases, such as pingpong * split where virtual pingpong does not generate IRQs - * @crtc_vblank_cb:Callback into the upper layer / CRTC for - * notification of the VBLANK - * @crtc_vblank_cb_data: Data from upper layer for VBLANK notification + * @crtc: Pointer to the currently assigned crtc. Normally you + * would use crtc->state->encoder_mask to determine the + * link between encoder/crtc. However in this case we need + * to track crtc in the disable() hook which is called + * _after_ encoder_mask is cleared. * @crtc_kickoff_cb: Callback into CRTC that will flush & start * all CTL paths * @crtc_kickoff_cb_data: Opaque user data given to crtc_kickoff_cb @@ -186,8 +188,7 @@ struct dpu_encoder_virt { bool intfs_swapped; - void (*crtc_vblank_cb)(void *); - void *crtc_vblank_cb_data; + struct drm_crtc *crtc; struct dentry *debugfs_root; struct mutex enc_lock; @@ -1241,8 +1242,8 @@ static void dpu_encoder_vblank_callback(struct drm_encoder *drm_enc, dpu_enc = to_dpu_encoder_virt(drm_enc); spin_lock_irqsave(_enc->enc_spinlock, lock_flags); - if (dpu_enc->crtc_vblank_cb) -
Re: [Freedreno] [PATCH 12/12] drm/msm: dpu: Move crtc runtime resume to encoder
On 2018-11-12 11:42, Sean Paul wrote: From: Sean Paul The crtc runtime resume doesn't actually operate on the crtc, but rather its encoders. The problem with this is that we need to inspect the crtc state to get the currently connected encoders. Since runtime resume isn't guaranteed to be called while holding the modeset locks (although it sometimes is), this presents a race condition. Now that we have ->enabled on the virtual encoders, and a lock to protect it, just call resume on each encoder and only restore the ones that are enabled. Signed-off-by: Sean Paul --- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c| 24 - drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h| 6 -- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 24 + drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h | 4 ++-- drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 6 +++--- 5 files changed, 15 insertions(+), 49 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index d8f58caf2772..9be24907f8c1 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -841,30 +841,6 @@ static struct drm_crtc_state *dpu_crtc_duplicate_state(struct drm_crtc *crtc) return >base; } -void dpu_crtc_runtime_resume(struct drm_crtc *crtc) -{ - struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); - struct drm_encoder *encoder; - - mutex_lock(_crtc->crtc_lock); - - if (!dpu_crtc->enabled) - goto end; - - trace_dpu_crtc_runtime_resume(DRMID(crtc)); - - /* restore encoder; crtc will be programmed during commit */ - drm_for_each_encoder(encoder, crtc->dev) { - if (encoder->crtc != crtc) - continue; - - dpu_encoder_virt_restore(encoder); - } I agree the patch provides a cleaner solution. Just for the understanding, won't the race condition be addressed if we acquire the modeset lock here and iterate through crtc->state->encoder_mask? Thanks and Regards, Jeykumar S. - -end: - mutex_unlock(_crtc->crtc_lock); -} - static void dpu_crtc_disable(struct drm_crtc *crtc) { struct dpu_crtc *dpu_crtc; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h index 1dca91d1210f..93d21a61a040 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h @@ -329,10 +329,4 @@ static inline bool dpu_crtc_is_enabled(struct drm_crtc *crtc) return crtc ? crtc->enabled : false; } -/** - * dpu_crtc_runtime_resume - called by the top-level on pm_runtime_resume - * @crtc: CRTC to resume - */ -void dpu_crtc_runtime_resume(struct drm_crtc *crtc); - #endif /* _DPU_CRTC_H_ */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index 3daa86220d47..d89ac520f7e6 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -1089,28 +1089,24 @@ static void _dpu_encoder_virt_enable_helper(struct drm_encoder *drm_enc) _dpu_encoder_update_vsync_source(dpu_enc, _enc->disp_info); } -void dpu_encoder_virt_restore(struct drm_encoder *drm_enc) +void dpu_encoder_virt_runtime_resume(struct drm_encoder *drm_enc) { - struct dpu_encoder_virt *dpu_enc = NULL; - int i; - - if (!drm_enc) { - DPU_ERROR("invalid encoder\n"); - return; - } - dpu_enc = to_dpu_encoder_virt(drm_enc); + struct dpu_encoder_virt *dpu_enc = to_dpu_encoder_virt(drm_enc); - for (i = 0; i < dpu_enc->num_phys_encs; i++) { - struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; + mutex_lock(_enc->enc_lock); - if (phys && (phys != dpu_enc->cur_master) && phys->ops.restore) - phys->ops.restore(phys); - } + if (!dpu_enc->enabled) + goto out; + if (dpu_enc->cur_slave && dpu_enc->cur_slave->ops.restore) + dpu_enc->cur_slave->ops.restore(dpu_enc->cur_slave); if (dpu_enc->cur_master && dpu_enc->cur_master->ops.restore) dpu_enc->cur_master->ops.restore(dpu_enc->cur_master); _dpu_encoder_virt_enable_helper(drm_enc); + +out: + mutex_unlock(_enc->enc_lock); } static void dpu_encoder_virt_enable(struct drm_encoder *drm_enc) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h index 9dbf38f446d9..aa4f135218fa 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h @@ -126,10 +126,10 @@ int dpu_encoder_wait_for_event(struct drm_encoder *drm_encoder, enum dpu_intf_mode dpu_encoder_get_intf_mode(struct drm_encoder *encoder); /** - * dpu_encoder_virt_restore - restore the encoder configs + * dpu_encoder_virt_runtime_resume - pm runtime resume the encoder configs *
Re: [Freedreno] [PATCH 11/12] drm/msm: dpu: Add ->enabled to dpu_encoder_virt
On 2018-11-12 11:42, Sean Paul wrote: From: Sean Paul Add a bool to dpu_encoder_virt to track whether the encoder is enabled or not. Repurpose the enc_lock mutex to ensure that it is consistent with the hw state. Signed-off-by: Sean Paul --- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 27 + 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index 10a0676d1dcf..3daa86220d47 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -132,6 +132,7 @@ enum dpu_enc_rc_states { * @base: drm_encoder base class for registration with DRM * @enc_spinlock: Virtual-Encoder-Wide Spin Lock for IRQ purposes * @bus_scaling_client:Client handle to the bus scaling interface + * @enabled: True if the encoder is active, protected by enc_lock * @num_phys_encs: Actual number of physical encoders contained. * @phys_encs: Container of physical encoders managed. * @cur_master:Pointer to the current master in this mode. Optimization @@ -148,8 +149,8 @@ enum dpu_enc_rc_states { * all CTL paths * @crtc_kickoff_cb_data: Opaque user data given to crtc_kickoff_cb * @debugfs_root: Debug file system root file node - * @enc_lock: Lock around physical encoder create/destroy and - access. + * @enc_lock: Lock around physical encoder + * create/destroy/enable/disable * @frame_busy_mask: Bitmask tracking which phys_enc we are still * busy processing current command. * Bit0 = phys_encs[0] etc. @@ -175,6 +176,8 @@ struct dpu_encoder_virt { spinlock_t enc_spinlock; uint32_t bus_scaling_client; + bool enabled; + unsigned int num_phys_encs; struct dpu_encoder_phys *phys_encs[MAX_PHYS_ENCODERS_PER_VIRTUAL]; struct dpu_encoder_phys *cur_master; @@ -1121,6 +1124,8 @@ static void dpu_encoder_virt_enable(struct drm_encoder *drm_enc) return; } dpu_enc = to_dpu_encoder_virt(drm_enc); + + mutex_lock(_enc->enc_lock); cur_mode = _enc->base.crtc->state->adjusted_mode; trace_dpu_enc_enable(DRMID(drm_enc), cur_mode->hdisplay, @@ -1137,10 +1142,15 @@ static void dpu_encoder_virt_enable(struct drm_encoder *drm_enc) if (ret) { DPU_ERROR_ENC(dpu_enc, "dpu resource control failed: %d\n", ret); - return; + goto out; } _dpu_encoder_virt_enable_helper(drm_enc); + + dpu_enc->enabled = true; + +out: + mutex_unlock(_enc->enc_lock); } static void dpu_encoder_virt_disable(struct drm_encoder *drm_enc) @@ -1162,11 +1172,14 @@ static void dpu_encoder_virt_disable(struct drm_encoder *drm_enc) return; } - mode = _enc->crtc->state->adjusted_mode; - dpu_enc = to_dpu_encoder_virt(drm_enc); DPU_DEBUG_ENC(dpu_enc, "\n"); + mutex_lock(_enc->enc_lock); Where do you expect it to go wrong if enable/disable is not protected using enc_lock? Thanks and Regards, Jeykumar S. + dpu_enc->enabled = false; + + mode = _enc->crtc->state->adjusted_mode; + priv = drm_enc->dev->dev_private; dpu_kms = to_dpu_kms(priv->kms); @@ -1200,6 +1213,8 @@ static void dpu_encoder_virt_disable(struct drm_encoder *drm_enc) DPU_DEBUG_ENC(dpu_enc, "encoder disabled\n"); dpu_rm_release(_kms->rm, drm_enc); + + mutex_unlock(_enc->enc_lock); } static enum dpu_intf dpu_encoder_get_intf(struct dpu_mdss_cfg *catalog, @@ -2233,6 +2248,8 @@ struct drm_encoder *dpu_encoder_init(struct drm_device *dev, drm_encoder_helper_add(_enc->base, _encoder_helper_funcs); + dpu_enc->enabled = false; + return _enc->base; } -- Jeykumar S ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
Re: [Freedreno] [PATCH 10/12] drm/msm: dpu: Fix typo in dpu_encoder
On 2018-11-12 11:42, Sean Paul wrote: From: Sean Paul enc_spinlock instead of enc_spin_lock. Signed-off-by: Sean Paul --- Reviewed-by: Jeykumar Sankaran drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index 82c55efb500f..10a0676d1dcf 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -130,7 +130,7 @@ enum dpu_enc_rc_states { * Virtual encoder defers as much as possible to the physical encoders. * Virtual encoder registers itself with the DRM Framework as the encoder. * @base: drm_encoder base class for registration with DRM - * @enc_spin_lock: Virtual-Encoder-Wide Spin Lock for IRQ purposes + * @enc_spinlock: Virtual-Encoder-Wide Spin Lock for IRQ purposes * @bus_scaling_client:Client handle to the bus scaling interface * @num_phys_encs: Actual number of physical encoders contained. * @phys_encs: Container of physical encoders managed. -- Jeykumar S ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
Re: [Freedreno] [PATCH 04/12] drm/msm: dpu: Don't use power_event for vbif_init_memtypes
On 2018-11-12 17:06, Jeykumar Sankaran wrote: On 2018-11-12 11:42, Sean Paul wrote: From: Sean Paul power_events are only used for pm_runtime, and that's all handled in dpu_kms. So just call vbif_init_memtypes at the correct times. Signed-off-by: Sean Paul --- drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 21 +++-- drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h | 1 - 2 files changed, 3 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index 23094d108e81..ae2bbaae923d 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -651,10 +651,6 @@ static void _dpu_kms_hw_destroy(struct dpu_kms *dpu_kms) dpu_hw_intr_destroy(dpu_kms->hw_intr); dpu_kms->hw_intr = NULL; - if (dpu_kms->power_event) - dpu_power_handle_unregister_event( - _kms->phandle, dpu_kms->power_event); - /* safe to call these more than once during shutdown */ _dpu_debugfs_destroy(dpu_kms); _dpu_kms_mmu_destroy(dpu_kms); @@ -832,16 +828,6 @@ u64 dpu_kms_get_clk_rate(struct dpu_kms *dpu_kms, char *clock_name) return clk_get_rate(clk->clk); } -static void dpu_kms_handle_power_event(u32 event_type, void *usr) -{ - struct dpu_kms *dpu_kms = usr; - - if (!dpu_kms) - return; - - dpu_vbif_init_memtypes(dpu_kms); -} - static int dpu_kms_hw_init(struct msm_kms *kms) { struct dpu_kms *dpu_kms; @@ -1015,10 +1001,7 @@ static int dpu_kms_hw_init(struct msm_kms *kms) /* * Handle (re)initializations during power enable */ - dpu_kms_handle_power_event(DPU_POWER_EVENT_ENABLE, dpu_kms); - dpu_kms->power_event = dpu_power_handle_register_event( - _kms->phandle, DPU_POWER_EVENT_ENABLE, - dpu_kms_handle_power_event, dpu_kms, "kms"); + dpu_vbif_init_memtypes(dpu_kms); pm_runtime_put_sync(_kms->pdev->dev); @@ -1172,6 +1155,8 @@ static int __maybe_unused dpu_runtime_resume(struct device *dev) return rc; } + dpu_vbif_init_memtypes(dpu_kms); + rc = dpu_power_resource_enable(_kms->phandle, true); if (rc) DPU_ERROR("resource enable failed: %d\n", rc); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h index f2c78deb0854..5f08be187c86 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h @@ -114,7 +114,6 @@ struct dpu_kms { struct dpu_mdss_cfg *catalog; struct dpu_power_handle phandle; You can get rid of the handle and header inclusions here itself to clean up KMS from power_handle stuff! nvm. I see you are taking care of this in patch 9/12. - struct dpu_power_event *power_event; /* directory entry for debugfs */ struct dentry *debugfs_root; -- Jeykumar S ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
Re: [Freedreno] [PATCH 09/12] drm/msm: dpu: Remove dpu_power_handle
On 2018-11-12 11:42, Sean Paul wrote: From: Sean Paul Now that we don't have any event handlers, remove dpu_power_handle! Signed-off-by: Sean Paul Reviewed-by: Jeykumar Sankaran --- drivers/gpu/drm/msm/Makefile | 1 - drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 11 -- drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h | 3 - .../gpu/drm/msm/disp/dpu1/dpu_power_handle.c | 136 -- .../gpu/drm/msm/disp/dpu1/dpu_power_handle.h | 113 --- 5 files changed, 264 deletions(-) delete mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_power_handle.c delete mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_power_handle.h diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile index 19ab521d4c3a..7d02ef3655b5 100644 --- a/drivers/gpu/drm/msm/Makefile +++ b/drivers/gpu/drm/msm/Makefile @@ -72,7 +72,6 @@ msm-y := \ disp/dpu1/dpu_kms.o \ disp/dpu1/dpu_mdss.o \ disp/dpu1/dpu_plane.o \ - disp/dpu1/dpu_power_handle.o \ disp/dpu1/dpu_rm.o \ disp/dpu1/dpu_vbif.o \ msm_atomic.o \ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index bae7e86b2913..e42685a1d928 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -1063,8 +1063,6 @@ static int dpu_bind(struct device *dev, struct device *master, void *data) return ret; } - dpu_power_resource_init(pdev, _kms->phandle); - platform_set_drvdata(pdev, dpu_kms); msm_kms_init(_kms->base, _funcs); @@ -1084,7 +1082,6 @@ static void dpu_unbind(struct device *dev, struct device *master, void *data) struct dpu_kms *dpu_kms = platform_get_drvdata(pdev); struct dss_module_power *mp = _kms->mp; - dpu_power_resource_deinit(pdev, _kms->phandle); msm_dss_put_clk(mp->clk_config, mp->num_clk); devm_kfree(>dev, mp->clk_config); mp->num_clk = 0; @@ -1123,10 +1120,6 @@ static int __maybe_unused dpu_runtime_suspend(struct device *dev) return rc; } - rc = dpu_power_resource_enable(_kms->phandle, false); - if (rc) - DPU_ERROR("resource disable failed: %d\n", rc); - rc = msm_dss_enable_clk(mp->clk_config, mp->num_clk, false); if (rc) DPU_ERROR("clock disable failed rc:%d\n", rc); @@ -1160,10 +1153,6 @@ static int __maybe_unused dpu_runtime_resume(struct device *dev) drm_for_each_crtc(crtc, ddev) dpu_crtc_runtime_resume(crtc); - rc = dpu_power_resource_enable(_kms->phandle, true); - if (rc) - DPU_ERROR("resource enable failed: %d\n", rc); - return rc; } diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h index 4e5acacb3065..59e18e2d3c59 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h @@ -31,7 +31,6 @@ #include "dpu_hw_top.h" #include "dpu_io_util.h" #include "dpu_rm.h" -#include "dpu_power_handle.h" #include "dpu_irq.h" #include "dpu_core_perf.h" @@ -114,8 +113,6 @@ struct dpu_kms { int core_rev; struct dpu_mdss_cfg *catalog; - struct dpu_power_handle phandle; - /* directory entry for debugfs */ struct dentry *debugfs_root; struct dentry *debugfs_danger; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_power_handle.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_power_handle.c deleted file mode 100644 index 8e64f0a52147.. --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_power_handle.c +++ /dev/null @@ -1,136 +0,0 @@ -/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#define pr_fmt(fmt)"[drm:%s:%d]: " fmt, __func__, __LINE__ - -#include -#include -#include -#include -#include -#include -#include - -#include "dpu_power_handle.h" -#include "dpu_trace.h" - -static void dpu_power_event_trigger_locked(struct dpu_power_handle *phandle, - u32 event_type) -{ - struct dpu_power_event *event; - - list_for_each_entry(event, >event_list, list) { - if (event->event_type & event_type) - event->cb_fnc(event_type, event->usr); - } -} - -void dpu_power_resource_init(struct platform
Re: [Freedreno] [PATCH 08/12] drm/msm: dpu: Move DPU_POWER_HANDLE_DBUS_ID to core_perf
On 2018-11-12 11:42, Sean Paul wrote: From: Sean Paul It's only used in core_perf, so stick it there (and change the name to reflect that). Signed-off-by: Sean Paul --- Reviewed-by: Jeykumar Sankaran drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c | 34 +-- drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.h | 17 -- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 4 +-- .../gpu/drm/msm/disp/dpu1/dpu_power_handle.h | 13 --- 4 files changed, 34 insertions(+), 34 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c index ef6dd43f8bec..bffc51e496e7 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c @@ -95,20 +95,20 @@ static void _dpu_core_perf_calc_crtc(struct dpu_kms *kms, memset(perf, 0, sizeof(struct dpu_core_perf_params)); if (!dpu_cstate->bw_control) { - for (i = 0; i < DPU_POWER_HANDLE_DBUS_ID_MAX; i++) { + for (i = 0; i < DPU_CORE_PERF_DATA_BUS_ID_MAX; i++) { perf->bw_ctl[i] = kms->catalog->perf.max_bw_high * 1000ULL; perf->max_per_pipe_ib[i] = perf->bw_ctl[i]; } perf->core_clk_rate = kms->perf.max_core_clk_rate; } else if (kms->perf.perf_tune.mode == DPU_PERF_MODE_MINIMUM) { - for (i = 0; i < DPU_POWER_HANDLE_DBUS_ID_MAX; i++) { + for (i = 0; i < DPU_CORE_PERF_DATA_BUS_ID_MAX; i++) { perf->bw_ctl[i] = 0; perf->max_per_pipe_ib[i] = 0; } perf->core_clk_rate = 0; } else if (kms->perf.perf_tune.mode == DPU_PERF_MODE_FIXED) { - for (i = 0; i < DPU_POWER_HANDLE_DBUS_ID_MAX; i++) { + for (i = 0; i < DPU_CORE_PERF_DATA_BUS_ID_MAX; i++) { perf->bw_ctl[i] = kms->perf.fix_core_ab_vote; perf->max_per_pipe_ib[i] = kms->perf.fix_core_ib_vote; } @@ -118,12 +118,12 @@ static void _dpu_core_perf_calc_crtc(struct dpu_kms *kms, DPU_DEBUG( "crtc=%d clk_rate=%llu core_ib=%llu core_ab=%llu llcc_ib=%llu llcc_ab=%llu mem_ib=%llu mem_ab=%llu\n", crtc->base.id, perf->core_clk_rate, - perf->max_per_pipe_ib[DPU_POWER_HANDLE_DBUS_ID_MNOC], - perf->bw_ctl[DPU_POWER_HANDLE_DBUS_ID_MNOC], - perf->max_per_pipe_ib[DPU_POWER_HANDLE_DBUS_ID_LLCC], - perf->bw_ctl[DPU_POWER_HANDLE_DBUS_ID_LLCC], - perf->max_per_pipe_ib[DPU_POWER_HANDLE_DBUS_ID_EBI], - perf->bw_ctl[DPU_POWER_HANDLE_DBUS_ID_EBI]); + perf->max_per_pipe_ib[DPU_CORE_PERF_DATA_BUS_ID_MNOC], + perf->bw_ctl[DPU_CORE_PERF_DATA_BUS_ID_MNOC], + perf->max_per_pipe_ib[DPU_CORE_PERF_DATA_BUS_ID_LLCC], + perf->bw_ctl[DPU_CORE_PERF_DATA_BUS_ID_LLCC], + perf->max_per_pipe_ib[DPU_CORE_PERF_DATA_BUS_ID_EBI], + perf->bw_ctl[DPU_CORE_PERF_DATA_BUS_ID_EBI]); } int dpu_core_perf_crtc_check(struct drm_crtc *crtc, @@ -158,8 +158,8 @@ int dpu_core_perf_crtc_check(struct drm_crtc *crtc, /* obtain new values */ _dpu_core_perf_calc_crtc(kms, crtc, state, _cstate->new_perf); - for (i = DPU_POWER_HANDLE_DBUS_ID_MNOC; - i < DPU_POWER_HANDLE_DBUS_ID_MAX; i++) { + for (i = DPU_CORE_PERF_DATA_BUS_ID_MNOC; + i < DPU_CORE_PERF_DATA_BUS_ID_MAX; i++) { bw_sum_of_intfs = dpu_cstate->new_perf.bw_ctl[i]; curr_client_type = dpu_crtc_get_client_type(crtc); @@ -290,7 +290,7 @@ void dpu_core_perf_crtc_release_bw(struct drm_crtc *crtc) if (kms->perf.enable_bw_release) { trace_dpu_cmd_release_bw(crtc->base.id); DPU_DEBUG("Release BW crtc=%d\n", crtc->base.id); - for (i = 0; i < DPU_POWER_HANDLE_DBUS_ID_MAX; i++) { + for (i = 0; i < DPU_CORE_PERF_DATA_BUS_ID_MAX; i++) { dpu_crtc->cur_perf.bw_ctl[i] = 0; _dpu_core_perf_crtc_update_bus(kms, crtc, i); } @@ -367,7 +367,7 @@ int dpu_core_perf_crtc_update(struct drm_crtc *crtc, new = _cstate->new_perf; if (_dpu_core_perf_crtc_is_power_on(crtc) && !stop_req) { - for (i = 0; i < DPU_POWER_HANDLE_DBUS_ID_MAX; i++) { + for (i = 0; i < DPU_CORE_PERF_DATA_BUS_ID_MAX; i++) { /* * cases for bus bandwidth update. * 1. new bandwidth vote - "ab or ib vote" is higher @@ -409,13 +409,13 @@ int dpu_core_perf_
Re: [Freedreno] [PATCH 07/12] drm/msm: dpu: Include dpu_io_util.h directly in dpu_kms.h
On 2018-11-12 11:42, Sean Paul wrote: From: Sean Paul It's needed for struct dss_module_power, and is currently being pulled in by dpu_power_handle.h Signed-off-by: Sean Paul --- Reviewed-by: Jeykumar Sankaran drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h index 5f08be187c86..4e5acacb3065 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h @@ -29,6 +29,7 @@ #include "dpu_hw_lm.h" #include "dpu_hw_interrupts.h" #include "dpu_hw_top.h" +#include "dpu_io_util.h" #include "dpu_rm.h" #include "dpu_power_handle.h" #include "dpu_irq.h" -- Jeykumar S ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
Re: [Freedreno] [PATCH 06/12] drm/msm: dpu: Remove power_handle from core_perf
On 2018-11-12 11:42, Sean Paul wrote: From: Sean Paul It's unused Signed-off-by: Sean Paul --- Reviewed-by: Jeykumar Sankaran drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c | 3 --- drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.h | 5 - drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 1 - 3 files changed, 9 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c index 22e84b3d7f98..ef6dd43f8bec 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c @@ -605,7 +605,6 @@ void dpu_core_perf_destroy(struct dpu_core_perf *perf) dpu_core_perf_debugfs_destroy(perf); perf->max_core_clk_rate = 0; perf->core_clk = NULL; - perf->phandle = NULL; perf->catalog = NULL; perf->dev = NULL; } @@ -613,12 +612,10 @@ void dpu_core_perf_destroy(struct dpu_core_perf *perf) int dpu_core_perf_init(struct dpu_core_perf *perf, struct drm_device *dev, struct dpu_mdss_cfg *catalog, - struct dpu_power_handle *phandle, struct dss_clk *core_clk) { perf->dev = dev; perf->catalog = catalog; - perf->phandle = phandle; perf->core_clk = core_clk; perf->max_core_clk_rate = core_clk->max_rate; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.h index fbcbe0c7527a..68b84d85eb8f 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.h @@ -19,7 +19,6 @@ #include #include "dpu_hw_catalog.h" -#include "dpu_power_handle.h" #defineDPU_PERF_DEFAULT_MAX_CORE_CLK_RATE 41250 @@ -52,7 +51,6 @@ struct dpu_core_perf_tune { * @dev: Pointer to drm device * @debugfs_root: top level debug folder * @catalog: Pointer to catalog configuration - * @phandle: Pointer to power handler * @core_clk: Pointer to core clock structure * @core_clk_rate: current core clock rate * @max_core_clk_rate: maximum allowable core clock rate @@ -66,7 +64,6 @@ struct dpu_core_perf { struct drm_device *dev; struct dentry *debugfs_root; struct dpu_mdss_cfg *catalog; - struct dpu_power_handle *phandle; struct dss_clk *core_clk; u64 core_clk_rate; u64 max_core_clk_rate; @@ -113,13 +110,11 @@ void dpu_core_perf_destroy(struct dpu_core_perf *perf); * @perf: Pointer to core performance context * @dev: Pointer to drm device * @catalog: Pointer to catalog - * @phandle: Pointer to power handle * @core_clk: pointer to core clock */ int dpu_core_perf_init(struct dpu_core_perf *perf, struct drm_device *dev, struct dpu_mdss_cfg *catalog, - struct dpu_power_handle *phandle, struct dss_clk *core_clk); /** diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index 62a02c606811..bae7e86b2913 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -957,7 +957,6 @@ static int dpu_kms_hw_init(struct msm_kms *kms) } rc = dpu_core_perf_init(_kms->perf, dev, dpu_kms->catalog, - _kms->phandle, _dpu_kms_get_clk(dpu_kms, "core")); if (rc) { DPU_ERROR("failed to init perf %d\n", rc); -- Jeykumar S ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
Re: [Freedreno] [PATCH 05/12] drm/msm: dpu: Handle crtc pm_runtime_resume() directly
On 2018-11-12 11:42, Sean Paul wrote: From: Sean Paul Instead of registering through dpu_power_handle just to get a call on runtime_resume, call the crtc function directly. Signed-off-by: Sean Paul --- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 23 ++- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h | 10 ++ drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 4 drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h | 8 4 files changed, 20 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index e09209d6c469..c55cb751e2b4 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -33,7 +33,6 @@ #include "dpu_plane.h" #include "dpu_encoder.h" #include "dpu_vbif.h" -#include "dpu_power_handle.h" #include "dpu_core_perf.h" #include "dpu_trace.h" @@ -69,8 +68,6 @@ static void dpu_crtc_destroy(struct drm_crtc *crtc) if (!crtc) return; - dpu_crtc->phandle = NULL; - drm_crtc_cleanup(crtc); mutex_destroy(_crtc->crtc_lock); kfree(dpu_crtc); @@ -844,15 +841,17 @@ static struct drm_crtc_state *dpu_crtc_duplicate_state(struct drm_crtc *crtc) return >base; } -static void dpu_crtc_handle_power_event(u32 event_type, void *arg) +void dpu_crtc_runtime_resume(struct drm_crtc *crtc) { - struct drm_crtc *crtc = arg; struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); struct drm_encoder *encoder; mutex_lock(_crtc->crtc_lock); - trace_dpu_crtc_handle_power_event(DRMID(crtc), event_type); + if (!dpu_crtc->enabled) + goto end; + + trace_dpu_crtc_runtime_resume(DRMID(crtc)); /* restore encoder; crtc will be programmed during commit */ drm_for_each_encoder(encoder, crtc->dev) { @@ -862,6 +861,7 @@ static void dpu_crtc_handle_power_event(u32 event_type, void *arg) dpu_encoder_virt_restore(encoder); } +end: mutex_unlock(_crtc->crtc_lock); } @@ -917,10 +917,6 @@ static void dpu_crtc_disable(struct drm_crtc *crtc) dpu_encoder_register_frame_event_callback(encoder, NULL, NULL); } - if (dpu_crtc->power_event) - dpu_power_handle_unregister_event(dpu_crtc->phandle, - dpu_crtc->power_event); - memset(cstate->mixers, 0, sizeof(cstate->mixers)); cstate->num_mixers = 0; @@ -972,11 +968,6 @@ static void dpu_crtc_enable(struct drm_crtc *crtc, /* Enable/restore vblank irq handling */ drm_crtc_vblank_on(crtc); - - dpu_crtc->power_event = dpu_power_handle_register_event( - dpu_crtc->phandle, DPU_POWER_EVENT_ENABLE, - dpu_crtc_handle_power_event, crtc, dpu_crtc->name); - } struct plane_state { @@ -1522,8 +1513,6 @@ struct drm_crtc *dpu_crtc_init(struct drm_device *dev, struct drm_plane *plane, /* initialize event handling */ spin_lock_init(_crtc->event_lock); If this is for synchronizing power events, we can get rid of this too. Thanks, Jeykumar S. - dpu_crtc->phandle = >phandle; - DPU_DEBUG("%s: successfully initialized crtc\n", dpu_crtc->name); return crtc; } diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h index 4822602402f9..1dca91d1210f 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h @@ -151,7 +151,6 @@ struct dpu_crtc_frame_event { * @event_worker : Event worker queue * @event_lock: Spinlock around event handling code * @phandle: Pointer to power handler - * @power_event : registered power event handle * @cur_perf : current performance committed to clock/bandwidth driver */ struct dpu_crtc { @@ -187,9 +186,6 @@ struct dpu_crtc { /* for handling internal event thread */ spinlock_t event_lock; - struct dpu_power_handle *phandle; - struct dpu_power_event *power_event; - struct dpu_core_perf_params cur_perf; struct dpu_crtc_smmu_state_data smmu_state; @@ -333,4 +329,10 @@ static inline bool dpu_crtc_is_enabled(struct drm_crtc *crtc) return crtc ? crtc->enabled : false; } +/** + * dpu_crtc_runtime_resume - called by the top-level on pm_runtime_resume + * @crtc: CRTC to resume + */ +void dpu_crtc_runtime_resume(struct drm_crtc *crtc); + #endif /* _DPU_CRTC_H_ */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index ae2bbaae923d..62a02c606811 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -1140,6 +1140,7 @@ static int __maybe_unused dpu_runtime_resume(struct device *dev) int rc = -1; struct platform_device *pdev = to_platform_device(dev); struct dpu_kms *dpu_kms = platform_get_drvdata(pdev); + struct drm_crtc *crtc;
Re: [Freedreno] [PATCH 04/12] drm/msm: dpu: Don't use power_event for vbif_init_memtypes
On 2018-11-12 11:42, Sean Paul wrote: From: Sean Paul power_events are only used for pm_runtime, and that's all handled in dpu_kms. So just call vbif_init_memtypes at the correct times. Signed-off-by: Sean Paul --- drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 21 +++-- drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h | 1 - 2 files changed, 3 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index 23094d108e81..ae2bbaae923d 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -651,10 +651,6 @@ static void _dpu_kms_hw_destroy(struct dpu_kms *dpu_kms) dpu_hw_intr_destroy(dpu_kms->hw_intr); dpu_kms->hw_intr = NULL; - if (dpu_kms->power_event) - dpu_power_handle_unregister_event( - _kms->phandle, dpu_kms->power_event); - /* safe to call these more than once during shutdown */ _dpu_debugfs_destroy(dpu_kms); _dpu_kms_mmu_destroy(dpu_kms); @@ -832,16 +828,6 @@ u64 dpu_kms_get_clk_rate(struct dpu_kms *dpu_kms, char *clock_name) return clk_get_rate(clk->clk); } -static void dpu_kms_handle_power_event(u32 event_type, void *usr) -{ - struct dpu_kms *dpu_kms = usr; - - if (!dpu_kms) - return; - - dpu_vbif_init_memtypes(dpu_kms); -} - static int dpu_kms_hw_init(struct msm_kms *kms) { struct dpu_kms *dpu_kms; @@ -1015,10 +1001,7 @@ static int dpu_kms_hw_init(struct msm_kms *kms) /* * Handle (re)initializations during power enable */ - dpu_kms_handle_power_event(DPU_POWER_EVENT_ENABLE, dpu_kms); - dpu_kms->power_event = dpu_power_handle_register_event( - _kms->phandle, DPU_POWER_EVENT_ENABLE, - dpu_kms_handle_power_event, dpu_kms, "kms"); + dpu_vbif_init_memtypes(dpu_kms); pm_runtime_put_sync(_kms->pdev->dev); @@ -1172,6 +1155,8 @@ static int __maybe_unused dpu_runtime_resume(struct device *dev) return rc; } + dpu_vbif_init_memtypes(dpu_kms); + rc = dpu_power_resource_enable(_kms->phandle, true); if (rc) DPU_ERROR("resource enable failed: %d\n", rc); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h index f2c78deb0854..5f08be187c86 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h @@ -114,7 +114,6 @@ struct dpu_kms { struct dpu_mdss_cfg *catalog; struct dpu_power_handle phandle; You can get rid of the handle and header inclusions here itself to clean up KMS from power_handle stuff! - struct dpu_power_event *power_event; /* directory entry for debugfs */ struct dentry *debugfs_root; -- Jeykumar S ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
Re: [Freedreno] [PATCH 04/12] drm/msm: dpu: Don't use power_event for vbif_init_memtypes
On 2018-11-12 11:42, Sean Paul wrote: From: Sean Paul power_events are only used for pm_runtime, and that's all handled in dpu_kms. So just call vbif_init_memtypes at the correct times. Signed-off-by: Sean Paul --- drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 21 +++-- drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h | 1 - 2 files changed, 3 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index 23094d108e81..ae2bbaae923d 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -651,10 +651,6 @@ static void _dpu_kms_hw_destroy(struct dpu_kms *dpu_kms) dpu_hw_intr_destroy(dpu_kms->hw_intr); dpu_kms->hw_intr = NULL; - if (dpu_kms->power_event) - dpu_power_handle_unregister_event( - _kms->phandle, dpu_kms->power_event); - /* safe to call these more than once during shutdown */ _dpu_debugfs_destroy(dpu_kms); _dpu_kms_mmu_destroy(dpu_kms); @@ -832,16 +828,6 @@ u64 dpu_kms_get_clk_rate(struct dpu_kms *dpu_kms, char *clock_name) return clk_get_rate(clk->clk); } -static void dpu_kms_handle_power_event(u32 event_type, void *usr) -{ - struct dpu_kms *dpu_kms = usr; - - if (!dpu_kms) - return; - - dpu_vbif_init_memtypes(dpu_kms); -} - static int dpu_kms_hw_init(struct msm_kms *kms) { struct dpu_kms *dpu_kms; @@ -1015,10 +1001,7 @@ static int dpu_kms_hw_init(struct msm_kms *kms) /* * Handle (re)initializations during power enable */ Is this comment valid anymore? - dpu_kms_handle_power_event(DPU_POWER_EVENT_ENABLE, dpu_kms); - dpu_kms->power_event = dpu_power_handle_register_event( - _kms->phandle, DPU_POWER_EVENT_ENABLE, - dpu_kms_handle_power_event, dpu_kms, "kms"); + dpu_vbif_init_memtypes(dpu_kms); pm_runtime_put_sync(_kms->pdev->dev); @@ -1172,6 +1155,8 @@ static int __maybe_unused dpu_runtime_resume(struct device *dev) return rc; } + dpu_vbif_init_memtypes(dpu_kms); + rc = dpu_power_resource_enable(_kms->phandle, true); if (rc) DPU_ERROR("resource enable failed: %d\n", rc); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h index f2c78deb0854..5f08be187c86 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h @@ -114,7 +114,6 @@ struct dpu_kms { struct dpu_mdss_cfg *catalog; struct dpu_power_handle phandle; - struct dpu_power_event *power_event; /* directory entry for debugfs */ struct dentry *debugfs_root; -- Jeykumar S ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
Re: [Freedreno] [PATCH 03/12] drm/msm: dpu: Remove dpu_power_client
On 2018-11-12 11:42, Sean Paul wrote: From: Sean Paul There's only one client -- core, and it's only used for runtime pm which is already refcounted. Signed-off-by: Sean Paul Reviewed-by: Jeykumar Sankaran --- drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 22 + drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h | 1 - .../gpu/drm/msm/disp/dpu1/dpu_power_handle.c | 96 +-- .../gpu/drm/msm/disp/dpu1/dpu_power_handle.h | 86 + 4 files changed, 6 insertions(+), 199 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index 985c855796ae..23094d108e81 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -676,11 +676,6 @@ static void _dpu_kms_hw_destroy(struct dpu_kms *dpu_kms) dpu_hw_catalog_deinit(dpu_kms->catalog); dpu_kms->catalog = NULL; - if (dpu_kms->core_client) - dpu_power_client_destroy(_kms->phandle, - dpu_kms->core_client); - dpu_kms->core_client = NULL; - if (dpu_kms->vbif[VBIF_NRT]) devm_iounmap(_kms->pdev->dev, dpu_kms->vbif[VBIF_NRT]); dpu_kms->vbif[VBIF_NRT] = NULL; @@ -913,17 +908,6 @@ static int dpu_kms_hw_init(struct msm_kms *kms) dpu_kms->reg_dma_len = dpu_iomap_size(dpu_kms->pdev, "regdma"); } - dpu_kms->core_client = dpu_power_client_create(_kms->phandle, - "core"); - if (IS_ERR_OR_NULL(dpu_kms->core_client)) { - rc = PTR_ERR(dpu_kms->core_client); - if (!dpu_kms->core_client) - rc = -EINVAL; - DPU_ERROR("dpu power client create failed: %d\n", rc); - dpu_kms->core_client = NULL; - goto error; - } - pm_runtime_get_sync(_kms->pdev->dev); _dpu_kms_core_hw_rev_init(dpu_kms); @@ -1157,8 +1141,7 @@ static int __maybe_unused dpu_runtime_suspend(struct device *dev) return rc; } - rc = dpu_power_resource_enable(_kms->phandle, - dpu_kms->core_client, false); + rc = dpu_power_resource_enable(_kms->phandle, false); if (rc) DPU_ERROR("resource disable failed: %d\n", rc); @@ -1189,8 +1172,7 @@ static int __maybe_unused dpu_runtime_resume(struct device *dev) return rc; } - rc = dpu_power_resource_enable(_kms->phandle, - dpu_kms->core_client, true); + rc = dpu_power_resource_enable(_kms->phandle, true); if (rc) DPU_ERROR("resource enable failed: %d\n", rc); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h index 2a3625eef6d3..f2c78deb0854 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h @@ -114,7 +114,6 @@ struct dpu_kms { struct dpu_mdss_cfg *catalog; struct dpu_power_handle phandle; - struct dpu_power_client *core_client; struct dpu_power_event *power_event; /* directory entry for debugfs */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_power_handle.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_power_handle.c index 8c6f92aaaf87..8e64f0a52147 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_power_handle.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_power_handle.c @@ -35,59 +35,11 @@ static void dpu_power_event_trigger_locked(struct dpu_power_handle *phandle, } } -struct dpu_power_client *dpu_power_client_create( - struct dpu_power_handle *phandle, char *client_name) -{ - struct dpu_power_client *client; - static u32 id; - - if (!client_name || !phandle) { - pr_err("client name is null or invalid power data\n"); - return ERR_PTR(-EINVAL); - } - - client = kzalloc(sizeof(struct dpu_power_client), GFP_KERNEL); - if (!client) - return ERR_PTR(-ENOMEM); - - mutex_lock(>phandle_lock); - strlcpy(client->name, client_name, MAX_CLIENT_NAME_LEN); - client->usecase_ndx = VOTE_INDEX_DISABLE; - client->id = id; - client->active = true; - pr_debug("client %s created:%pK id :%d\n", client_name, - client, id); - id++; - list_add(>list, >power_client_clist); - mutex_unlock(>phandle_lock); - - return client; -} - -void dpu_power_client_destroy(struct dpu_power_handle *phandle, - struct dpu_power_client *client) -{ - if (!client || !phandle) { - pr_err("reg bus vote: invalid client handle\n"); - } else if (!client->active) { - pr_err("dpu power deinit already done\n"); - kf
Re: [Freedreno] [PATCH 02/12] drm/msm: dpu: Remove unused trace_dpu_perf_update_bus()
On 2018-11-12 11:42, Sean Paul wrote: From: Sean Paul Signed-off-by: Sean Paul --- Reviewed-by: Jeykumar Sankaran drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h | 21 - 1 file changed, 21 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h index 0c122e173892..7ab0ba8224f6 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h @@ -99,27 +99,6 @@ TRACE_EVENT(dpu_perf_set_ot, __entry->vbif_idx) ) -TRACE_EVENT(dpu_perf_update_bus, - TP_PROTO(int client, unsigned long long ab_quota, - unsigned long long ib_quota), - TP_ARGS(client, ab_quota, ib_quota), - TP_STRUCT__entry( - __field(int, client) - __field(u64, ab_quota) - __field(u64, ib_quota) - ), - TP_fast_assign( - __entry->client = client; - __entry->ab_quota = ab_quota; - __entry->ib_quota = ib_quota; - ), - TP_printk("Request client:%d ab=%llu ib=%llu", - __entry->client, - __entry->ab_quota, - __entry->ib_quota) -) - - TRACE_EVENT(dpu_cmd_release_bw, TP_PROTO(u32 crtc_id), TP_ARGS(crtc_id), -- Jeykumar S ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
Re: [Freedreno] [PATCH 01/12] drm/msm: dpu: Remove dpu_power_handle_get_dbus_name()
On 2018-11-12 11:42, Sean Paul wrote: From: Sean Paul It's only used for debugfs, so just output the enum value instead. Signed-off-by: Sean Paul --- Reviewed-by: Jeykumar Sankaran drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 6 ++ drivers/gpu/drm/msm/disp/dpu1/dpu_power_handle.c | 14 -- drivers/gpu/drm/msm/disp/dpu1/dpu_power_handle.h | 7 --- 3 files changed, 2 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index ed84cf44a222..e09209d6c469 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -1381,11 +1381,9 @@ static int dpu_crtc_debugfs_state_show(struct seq_file *s, void *v) dpu_crtc->cur_perf.core_clk_rate); for (i = DPU_POWER_HANDLE_DBUS_ID_MNOC; i < DPU_POWER_HANDLE_DBUS_ID_MAX; i++) { - seq_printf(s, "bw_ctl[%s]: %llu\n", - dpu_power_handle_get_dbus_name(i), + seq_printf(s, "bw_ctl[%d]: %llu\n", i, dpu_crtc->cur_perf.bw_ctl[i]); - seq_printf(s, "max_per_pipe_ib[%s]: %llu\n", - dpu_power_handle_get_dbus_name(i), + seq_printf(s, "max_per_pipe_ib[%d]: %llu\n", i, dpu_crtc->cur_perf.max_per_pipe_ib[i]); } diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_power_handle.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_power_handle.c index fc14116789f2..8c6f92aaaf87 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_power_handle.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_power_handle.c @@ -24,20 +24,6 @@ #include "dpu_power_handle.h" #include "dpu_trace.h" -static const char *data_bus_name[DPU_POWER_HANDLE_DBUS_ID_MAX] = { - [DPU_POWER_HANDLE_DBUS_ID_MNOC] = "qcom,dpu-data-bus", - [DPU_POWER_HANDLE_DBUS_ID_LLCC] = "qcom,dpu-llcc-bus", - [DPU_POWER_HANDLE_DBUS_ID_EBI] = "qcom,dpu-ebi-bus", -}; - -const char *dpu_power_handle_get_dbus_name(u32 bus_id) -{ - if (bus_id < DPU_POWER_HANDLE_DBUS_ID_MAX) - return data_bus_name[bus_id]; - - return NULL; -} - static void dpu_power_event_trigger_locked(struct dpu_power_handle *phandle, u32 event_type) { diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_power_handle.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_power_handle.h index a65b7a297f21..f627ae28ec68 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_power_handle.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_power_handle.h @@ -207,11 +207,4 @@ struct dpu_power_event *dpu_power_handle_register_event( void dpu_power_handle_unregister_event(struct dpu_power_handle *phandle, struct dpu_power_event *event); -/** - * dpu_power_handle_get_dbus_name - get name of given data bus identifier - * @bus_id:data bus identifier - * Return: Pointer to name string if success; NULL otherwise - */ -const char *dpu_power_handle_get_dbus_name(u32 bus_id); - #endif /* _DPU_POWER_HANDLE_H_ */ -- Jeykumar S ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
Re: [Freedreno] [PATCH v2 1/3] drm/msm: dpu: Mask inactive pending flushes
On 2018-11-08 13:40, Sean Paul wrote: On Thu, Nov 08, 2018 at 01:03:03PM -0800, Jeykumar Sankaran wrote: On 2018-10-30 09:00, Sean Paul wrote: > From: Sean Paul > > This patch masks any pending flushes which have not been latched for a > commit. This will catch the case where an asynchronous update is > nullified by a disable in the same frame. > > Changes in v2: > - Added to the set > > Signed-off-by: Sean Paul > --- > drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c | 7 +++ > 1 file changed, 7 insertions(+) > > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c > b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c > index 8fa601a9abbf..d7a7fedc09f7 100644 > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c > @@ -28,6 +28,7 @@ > #define CTL_TOP 0x014 > #define CTL_FLUSH 0x018 > #define CTL_START 0x01C > +#define CTL_FLUSH_MASK0x090 > #define CTL_PREPARE 0x0d0 > #define CTL_SW_RESET 0x030 > #define CTL_LAYER_EXTN_OFFSET 0x40 > @@ -121,6 +122,12 @@ static inline void dpu_hw_ctl_trigger_flush(struct > dpu_hw_ctl *ctx) > { >trace_dpu_hw_ctl_trigger_pending_flush(ctx->pending_flush_mask, > dpu_hw_ctl_get_flush_register(ctx)); > + > + /* > + * Async updates could have changed CTL_FLUSH since it was last > latched. > + * Mask anything not involved in this latest commit. > + */ > + DPU_REG_WRITE(>hw, CTL_FLUSH_MASK, ~ctx->pending_flush_mask); Do we need this change for adding the current async cursor support? Hmm, I think you asked me to implement this at the weekly meeting a little while ago. Apparently HW team requested that we mask off the bits for planes which have been disabled-but-not-flushed? OK. If you want to implement the HW team recommendation, you should block the FLUSH writes until both FLUSH and FLUSH_MASK writes goes through. We can do that by writing 0x to the FLUSH_MASK indicating "hardware is not ready" at the beginnging of the new vsync window. Since async updates dont wait for commit_done (vsync), we can do that only for sync commits. Once we are done programming all the registers and the final flush bits are ready, the order of writing has to be reversed by writing FLUSH first and then FLUSH_MASK to the inverse of FLUSH to unblock the hardware programming on vsync. Still, there is a small window of error where vsync can happen between FLUSH and FLUSH_MASK writes where we will end up missing the vsync but no partial frame registers will be programmed. I believe we have decided to try out this approach with a fresh set of patches and let the current cursor support get in as such. In that case, we can drop this patch from this series. Thanks, Jeykumar S. Sean We are not masking any bit by default. So there is no need for updating it here. The usage of flush_mask is not completely explored yet. Maybe we can add this register support when we revisit this async logic as we discussed. Thanks and Regards, Jeykumar S. >DPU_REG_WRITE(>hw, CTL_FLUSH, ctx->pending_flush_mask); > } -- Jeykumar S -- Jeykumar S ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
Re: [Freedreno] [PATCH 1/2] drm/msm: use common display thread for dispatching vblank events
On 2018-11-01 12:09, Sean Paul wrote: On Wed, Oct 31, 2018 at 05:19:04PM -0700, Jeykumar Sankaran wrote: DPU was using one thread per display to dispatch async commits and vblank requests. Since clean up already happened in msm to use the common thread for all the display commits, display threads are only used to cater vblank requests. Single thread is sufficient to do the job without any performance hits. Signed-off-by: Jeykumar Sankaran --- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 6 +--- drivers/gpu/drm/msm/msm_drv.c | 50 - drivers/gpu/drm/msm/msm_drv.h | 2 +- 3 files changed, 23 insertions(+), 35 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index 82c55ef..aff20f5 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -753,11 +753,7 @@ static int dpu_encoder_resource_control(struct drm_encoder *drm_enc, is_vid_mode = dpu_enc->disp_info.capabilities & MSM_DISPLAY_CAP_VID_MODE; - if (drm_enc->crtc->index >= ARRAY_SIZE(priv->disp_thread)) { - DPU_ERROR("invalid crtc index\n"); - return -EINVAL; - } - disp_thread = >disp_thread[drm_enc->crtc->index]; + disp_thread = >disp_thread; /* * when idle_pc is not supported, process only KICKOFF, STOP and MODESET diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 9c9f7ff..1f384b3 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -257,8 +257,7 @@ static int vblank_ctrl_queue_work(struct msm_drm_private *priv, list_add_tail(_ev->node, _ctrl->event_list); spin_unlock_irqrestore(_ctrl->lock, flags); - kthread_queue_work(>disp_thread[crtc_id].worker, - _ctrl->work); + kthread_queue_work(>disp_thread.worker, _ctrl->work); return 0; } @@ -284,14 +283,12 @@ static int msm_drm_uninit(struct device *dev) kfree(vbl_ev); } + kthread_flush_worker(>disp_thread.worker); + kthread_stop(priv->disp_thread.thread); I realize this is moving existing code, but is there a race here? You can't have work enqueued in between the flush and stop? I looked further into this comment. Ideally, we call into msm_unbind only when the device is released and we release the device only on the last close of the drm device. So the userspace doesn't have any device handle to make ioctl calls, which could queue jobs to this queue. Since we are making sure to flush out the last job already on the queue, we can safely call the kthread_stop here. Thanks and Regards, Jeykumar S. You might also want to use kthread_destroy_worker to do this work (in a follow-up patch including the event threads too). + priv->disp_thread.thread = NULL; + /* clean up display commit/event worker threads */ This comment needs updating now for (i = 0; i < priv->num_crtcs; i++) { - if (priv->disp_thread[i].thread) { - kthread_flush_worker(>disp_thread[i].worker); - kthread_stop(priv->disp_thread[i].thread); - priv->disp_thread[i].thread = NULL; - } - if (priv->event_thread[i].thread) { kthread_flush_worker(>event_thread[i].worker); kthread_stop(priv->event_thread[i].thread); @@ -537,6 +534,22 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) ddev->mode_config.funcs = _config_funcs; ddev->mode_config.helper_private = _config_helper_funcs; + /* initialize display thread */ + kthread_init_worker(>disp_thread.worker); + priv->disp_thread.dev = ddev; + priv->disp_thread.thread = kthread_run(kthread_worker_fn, + >disp_thread.worker, + "disp_thread"); + if (IS_ERR(priv->disp_thread.thread)) { + DRM_DEV_ERROR(dev, "failed to create crtc_commit kthread\n"); + priv->disp_thread.thread = NULL; + goto err_msm_uninit; + } + + ret = sched_setscheduler(priv->disp_thread.thread, SCHED_FIFO, ); + if (ret) + pr_warn("display thread priority update failed: %d\n", ret); + /** * this priority was found during empiric testing to have appropriate * realtime scheduling to process display updates and interact with @@ -544,27 +557,6 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) */ param.sched_priority = 16; for (i = 0; i < priv->num_crtcs; i++
Re: [Freedreno] [PATCH v2 3/3] drm/msm: dpu: Make legacy cursor updates asynchronous
On 2018-10-30 09:00, Sean Paul wrote: From: Sean Paul This patch sprinkles a few async/legacy_cursor_update checks through commit to ensure that cursor updates aren't blocked on vsync. There are 2 main components to this, the first is that we don't want to wait_for_commit_done in msm_atomic before returning from atomic_complete. The second is that in dpu we don't want to wait for frame_done events when updating the cursor. Changes in v2: - None Signed-off-by: Sean Paul --- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c| 44 +++-- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h| 3 +- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 22 +++ drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h | 6 ++- drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 5 ++- drivers/gpu/drm/msm/msm_atomic.c| 3 +- 6 files changed, 49 insertions(+), 34 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index ed84cf44a222..1e3e57817b72 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -702,7 +702,7 @@ static int _dpu_crtc_wait_for_frame_done(struct drm_crtc *crtc) return rc; } -void dpu_crtc_commit_kickoff(struct drm_crtc *crtc) +void dpu_crtc_commit_kickoff(struct drm_crtc *crtc, bool async) { struct drm_encoder *encoder; struct drm_device *dev = crtc->dev; @@ -731,27 +731,30 @@ void dpu_crtc_commit_kickoff(struct drm_crtc *crtc) * Encoder will flush/start now, unless it has a tx pending. * If so, it may delay and flush at an irq event (e.g. ppdone) */ - dpu_encoder_prepare_for_kickoff(encoder, ); + dpu_encoder_prepare_for_kickoff(encoder, , async); } - /* wait for frame_event_done completion */ - DPU_ATRACE_BEGIN("wait_for_frame_done_event"); - ret = _dpu_crtc_wait_for_frame_done(crtc); - DPU_ATRACE_END("wait_for_frame_done_event"); - if (ret) { - DPU_ERROR("crtc%d wait for frame done failed;frame_pending%d\n", - crtc->base.id, - atomic_read(_crtc->frame_pending)); - goto end; - } - if (atomic_inc_return(_crtc->frame_pending) == 1) { - /* acquire bandwidth and other resources */ - DPU_DEBUG("crtc%d first commit\n", crtc->base.id); - } else - DPU_DEBUG("crtc%d commit\n", crtc->base.id); + if (!async) { + /* wait for frame_event_done completion */ + DPU_ATRACE_BEGIN("wait_for_frame_done_event"); + ret = _dpu_crtc_wait_for_frame_done(crtc); + DPU_ATRACE_END("wait_for_frame_done_event"); + if (ret) { + DPU_ERROR("crtc%d wait for frame done failed;frame_pending%d\n", + crtc->base.id, + atomic_read(_crtc->frame_pending)); + goto end; + } + + if (atomic_inc_return(_crtc->frame_pending) == 1) { + /* acquire bandwidth and other resources */ + DPU_DEBUG("crtc%d first commit\n", crtc->base.id); + } else + DPU_DEBUG("crtc%d commit\n", crtc->base.id); - dpu_crtc->play_count++; + dpu_crtc->play_count++; + } dpu_vbif_clear_errors(dpu_kms); @@ -759,11 +762,12 @@ void dpu_crtc_commit_kickoff(struct drm_crtc *crtc) if (encoder->crtc != crtc) continue; - dpu_encoder_kickoff(encoder); + dpu_encoder_kickoff(encoder, async); } end: - reinit_completion(_crtc->frame_done_comp); + if (!async) + reinit_completion(_crtc->frame_done_comp); DPU_ATRACE_END("crtc_commit"); } diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h index 4822602402f9..ec633ce3ee6c 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h @@ -277,8 +277,9 @@ int dpu_crtc_vblank(struct drm_crtc *crtc, bool en); /** * dpu_crtc_commit_kickoff - trigger kickoff of the commit for this crtc * @crtc: Pointer to drm crtc object + * @async: true if the commit is asynchronous, false otherwise */ -void dpu_crtc_commit_kickoff(struct drm_crtc *crtc); +void dpu_crtc_commit_kickoff(struct drm_crtc *crtc, bool async); /** * dpu_crtc_complete_commit - callback signalling completion of current commit diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index 82c55efb500f..a8ba10ceaacf 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -1375,7 +1375,8 @@ static void dpu_encoder_off_work(struct kthread_work *work) * extra_flush_bits:
Re: [Freedreno] [PATCH v2 1/3] drm/msm: dpu: Mask inactive pending flushes
On 2018-10-30 09:00, Sean Paul wrote: From: Sean Paul This patch masks any pending flushes which have not been latched for a commit. This will catch the case where an asynchronous update is nullified by a disable in the same frame. Changes in v2: - Added to the set Signed-off-by: Sean Paul --- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c | 7 +++ 1 file changed, 7 insertions(+) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c index 8fa601a9abbf..d7a7fedc09f7 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c @@ -28,6 +28,7 @@ #define CTL_TOP 0x014 #define CTL_FLUSH 0x018 #define CTL_START 0x01C +#define CTL_FLUSH_MASK0x090 #define CTL_PREPARE 0x0d0 #define CTL_SW_RESET 0x030 #define CTL_LAYER_EXTN_OFFSET 0x40 @@ -121,6 +122,12 @@ static inline void dpu_hw_ctl_trigger_flush(struct dpu_hw_ctl *ctx) { trace_dpu_hw_ctl_trigger_pending_flush(ctx->pending_flush_mask, dpu_hw_ctl_get_flush_register(ctx)); + + /* +* Async updates could have changed CTL_FLUSH since it was last latched. +* Mask anything not involved in this latest commit. +*/ + DPU_REG_WRITE(>hw, CTL_FLUSH_MASK, ~ctx->pending_flush_mask); Do we need this change for adding the current async cursor support? We are not masking any bit by default. So there is no need for updating it here. The usage of flush_mask is not completely explored yet. Maybe we can add this register support when we revisit this async logic as we discussed. Thanks and Regards, Jeykumar S. DPU_REG_WRITE(>hw, CTL_FLUSH, ctx->pending_flush_mask); } -- Jeykumar S ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
Re: [Freedreno] [PATCH v2 2/3] drm/msm: dpu: Only check flush register against pending flushes
On 2018-10-30 09:00, Sean Paul wrote: From: Sean Paul There exists a case where a flush of a plane/dma may have been triggered & started from an async commit. If that plane/dma is subsequently disabled by the next commit, the flush register will continue to hold the flush bit for the disabled plane. Since the bit remains active, pending_kickoff_cnt will never decrement and we'll miss frame_done events. This patch limits the check of flush_register to include only those bits which have been updated with the latest commit. Changes in v2: - None Reviewed-by: Jeykumar Sankaran Signed-off-by: Sean Paul --- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c index b3c68c4fcc8e..667f304c92ea 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c @@ -331,7 +331,7 @@ static void dpu_encoder_phys_vid_vblank_irq(void *arg, int irq_idx) if (hw_ctl && hw_ctl->ops.get_flush_register) flush_register = hw_ctl->ops.get_flush_register(hw_ctl); - if (flush_register == 0) + if (!(flush_register & hw_ctl->ops.get_pending_flush(hw_ctl))) new_cnt = atomic_add_unless(_enc->pending_kickoff_cnt, -1, 0); spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags); -- Jeykumar S ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
[Freedreno] [PATCH v2 3/5] drm/msm/dpu: use system wq for idle power collapse
msm is using system wq for dispatching commit and vblank events. Switch idle power collapse feature also to use system wq to handle delayed work handlers so that msm can get rid of redundant display threads. changes in v2: - patch introduced in v2 Signed-off-by: Jeykumar Sankaran --- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 26 +++--- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index 82c55ef..9b3d1f2 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -201,7 +201,7 @@ struct dpu_encoder_virt { bool idle_pc_supported; struct mutex rc_lock; enum dpu_enc_rc_states rc_state; - struct kthread_delayed_work delayed_off_work; + struct delayed_work delayed_off_work; struct kthread_work vsync_event_work; struct msm_display_topology topology; bool mode_set_complete; @@ -740,7 +740,6 @@ static int dpu_encoder_resource_control(struct drm_encoder *drm_enc, { struct dpu_encoder_virt *dpu_enc; struct msm_drm_private *priv; - struct msm_drm_thread *disp_thread; bool is_vid_mode = false; if (!drm_enc || !drm_enc->dev || !drm_enc->dev->dev_private || @@ -753,12 +752,6 @@ static int dpu_encoder_resource_control(struct drm_encoder *drm_enc, is_vid_mode = dpu_enc->disp_info.capabilities & MSM_DISPLAY_CAP_VID_MODE; - if (drm_enc->crtc->index >= ARRAY_SIZE(priv->disp_thread)) { - DPU_ERROR("invalid crtc index\n"); - return -EINVAL; - } - disp_thread = >disp_thread[drm_enc->crtc->index]; - /* * when idle_pc is not supported, process only KICKOFF, STOP and MODESET * events and return early for other events (ie wb display). @@ -775,8 +768,7 @@ static int dpu_encoder_resource_control(struct drm_encoder *drm_enc, switch (sw_event) { case DPU_ENC_RC_EVENT_KICKOFF: /* cancel delayed off work, if any */ - if (kthread_cancel_delayed_work_sync( - _enc->delayed_off_work)) + if (cancel_delayed_work_sync(_enc->delayed_off_work)) DPU_DEBUG_ENC(dpu_enc, "sw_event:%d, work cancelled\n", sw_event); @@ -835,10 +827,8 @@ static int dpu_encoder_resource_control(struct drm_encoder *drm_enc, return 0; } - kthread_queue_delayed_work( - _thread->worker, - _enc->delayed_off_work, - msecs_to_jiffies(dpu_enc->idle_timeout)); + schedule_delayed_work(_enc->delayed_off_work, + msecs_to_jiffies(dpu_enc->idle_timeout)); trace_dpu_enc_rc(DRMID(drm_enc), sw_event, dpu_enc->idle_pc_supported, dpu_enc->rc_state, @@ -847,8 +837,7 @@ static int dpu_encoder_resource_control(struct drm_encoder *drm_enc, case DPU_ENC_RC_EVENT_PRE_STOP: /* cancel delayed off work, if any */ - if (kthread_cancel_delayed_work_sync( - _enc->delayed_off_work)) + if (cancel_delayed_work_sync(_enc->delayed_off_work)) DPU_DEBUG_ENC(dpu_enc, "sw_event:%d, work cancelled\n", sw_event); @@ -1351,7 +1340,7 @@ static void dpu_encoder_frame_done_callback( } } -static void dpu_encoder_off_work(struct kthread_work *work) +static void dpu_encoder_off_work(struct work_struct *work) { struct dpu_encoder_virt *dpu_enc = container_of(work, struct dpu_encoder_virt, delayed_off_work.work); @@ -2191,8 +2180,7 @@ int dpu_encoder_setup(struct drm_device *dev, struct drm_encoder *enc, mutex_init(_enc->rc_lock); - kthread_init_delayed_work(_enc->delayed_off_work, - dpu_encoder_off_work); + INIT_DELAYED_WORK(_enc->delayed_off_work, dpu_encoder_off_work); dpu_enc->idle_timeout = IDLE_TIMEOUT; kthread_init_work(_enc->vsync_event_work, -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
[Freedreno] [PATCH v2 4/5] drm/msm: clean up display thread
Since there are no clients using these threads, cleaning it up. changes in v2: - switch all the dependent clients to use system wq before removing the disp_threads (Sean Paul) Signed-off-by: Jeykumar Sankaran --- drivers/gpu/drm/msm/msm_drv.c | 35 +-- drivers/gpu/drm/msm/msm_drv.h | 1 - 2 files changed, 1 insertion(+), 35 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 7d3ca99..6d6c73b 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -298,13 +298,8 @@ static int msm_drm_uninit(struct device *dev) kfree(vbl_ev); } - /* clean up display commit/event worker threads */ + /* clean up event worker threads */ for (i = 0; i < priv->num_crtcs; i++) { - if (priv->disp_thread[i].thread) { - kthread_destroy_worker(>disp_thread[i].worker); - priv->disp_thread[i].thread = NULL; - } - if (priv->event_thread[i].thread) { kthread_destroy_worker(>event_thread[i].worker); priv->event_thread[i].thread = NULL; @@ -541,27 +536,6 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) */ param.sched_priority = 16; for (i = 0; i < priv->num_crtcs; i++) { - - /* initialize display thread */ - priv->disp_thread[i].crtc_id = priv->crtcs[i]->base.id; - kthread_init_worker(>disp_thread[i].worker); - priv->disp_thread[i].dev = ddev; - priv->disp_thread[i].thread = - kthread_run(kthread_worker_fn, - >disp_thread[i].worker, - "crtc_commit:%d", priv->disp_thread[i].crtc_id); - if (IS_ERR(priv->disp_thread[i].thread)) { - DRM_DEV_ERROR(dev, "failed to create crtc_commit kthread\n"); - priv->disp_thread[i].thread = NULL; - goto err_msm_uninit; - } - - ret = sched_setscheduler(priv->disp_thread[i].thread, -SCHED_FIFO, ); - if (ret) - dev_warn(dev, "disp_thread set priority failed: %d\n", -ret); - /* initialize event thread */ priv->event_thread[i].crtc_id = priv->crtcs[i]->base.id; kthread_init_worker(>event_thread[i].worker); @@ -576,13 +550,6 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) goto err_msm_uninit; } - /** -* event thread should also run at same priority as disp_thread -* because it is handling frame_done events. A lower priority -* event thread and higher priority disp_thread can causes -* frame_pending counters beyond 2. This can lead to commit -* failure at crtc commit level. -*/ ret = sched_setscheduler(priv->event_thread[i].thread, SCHED_FIFO, ); if (ret) diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index 126345c4..05d33a7 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -197,7 +197,6 @@ struct msm_drm_private { unsigned int num_crtcs; struct drm_crtc *crtcs[MAX_CRTCS]; - struct msm_drm_thread disp_thread[MAX_CRTCS]; struct msm_drm_thread event_thread[MAX_CRTCS]; unsigned int num_encoders; -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
[Freedreno] [PATCH v2 1/5] drm/msm: destroy msm threads after config cleanup
To avoid any possible work queues to msm threads, clean up the threads after the CRTC objects are released in config cleanup. changes in v2: - fix race condition before kthread flush and stop (Sean Paul) - use kthread_destroy_worker for cleaning up kthread (Sean Paul) Signed-off-by: Jeykumar Sankaran --- drivers/gpu/drm/msm/msm_drv.c | 36 +--- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 9c9f7ff..e913059 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -278,6 +278,21 @@ static int msm_drm_uninit(struct device *dev) * work before drm_irq_uninstall() to avoid work re-enabling an * irq after uninstall has disabled it. */ + msm_gem_shrinker_cleanup(ddev); + + drm_kms_helper_poll_fini(ddev); + + drm_dev_unregister(ddev); + + msm_perf_debugfs_cleanup(priv); + msm_rd_debugfs_cleanup(priv); + +#ifdef CONFIG_DRM_FBDEV_EMULATION + if (fbdev && priv->fbdev) + msm_fbdev_free(ddev); +#endif + drm_mode_config_cleanup(ddev); + kthread_flush_work(_ctrl->work); list_for_each_entry_safe(vbl_ev, tmp, _ctrl->event_list, node) { list_del(_ev->node); @@ -287,33 +302,16 @@ static int msm_drm_uninit(struct device *dev) /* clean up display commit/event worker threads */ for (i = 0; i < priv->num_crtcs; i++) { if (priv->disp_thread[i].thread) { - kthread_flush_worker(>disp_thread[i].worker); - kthread_stop(priv->disp_thread[i].thread); + kthread_destroy_worker(>disp_thread[i].worker); priv->disp_thread[i].thread = NULL; } if (priv->event_thread[i].thread) { - kthread_flush_worker(>event_thread[i].worker); - kthread_stop(priv->event_thread[i].thread); + kthread_destroy_worker(>event_thread[i].worker); priv->event_thread[i].thread = NULL; } } - msm_gem_shrinker_cleanup(ddev); - - drm_kms_helper_poll_fini(ddev); - - drm_dev_unregister(ddev); - - msm_perf_debugfs_cleanup(priv); - msm_rd_debugfs_cleanup(priv); - -#ifdef CONFIG_DRM_FBDEV_EMULATION - if (fbdev && priv->fbdev) - msm_fbdev_free(ddev); -#endif - drm_mode_config_cleanup(ddev); - pm_runtime_get_sync(dev); drm_irq_uninstall(ddev); pm_runtime_put_sync(dev); -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
[Freedreno] [PATCH v2 2/5] drm/msm/dpu: use system wq for vblank events
DPU was using one thread per display to dispatch async commits and vblank requests. Since clean up already happened in msm to use the common thread for all the display commits, display threads are only used to cater vblank requests. Since a single thread is sufficient to do the job without any performance hits, use system workqueue to queue requests. A separate patch is submitted later in this series to remove the display threads altogether. changes in v2: - switch to system wq before removing disp threads (Sean Paul) Signed-off-by: Jeykumar Sankaran --- drivers/gpu/drm/msm/msm_drv.c | 9 - drivers/gpu/drm/msm/msm_drv.h | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index e913059..7d3ca99 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -209,7 +209,7 @@ struct vblank_event { bool enable; }; -static void vblank_ctrl_worker(struct kthread_work *work) +static void vblank_ctrl_worker(struct work_struct *work) { struct msm_vblank_ctrl *vbl_ctrl = container_of(work, struct msm_vblank_ctrl, work); @@ -257,8 +257,7 @@ static int vblank_ctrl_queue_work(struct msm_drm_private *priv, list_add_tail(_ev->node, _ctrl->event_list); spin_unlock_irqrestore(_ctrl->lock, flags); - kthread_queue_work(>disp_thread[crtc_id].worker, - _ctrl->work); + schedule_work(_ctrl->work); return 0; } @@ -293,7 +292,7 @@ static int msm_drm_uninit(struct device *dev) #endif drm_mode_config_cleanup(ddev); - kthread_flush_work(_ctrl->work); + flush_work(_ctrl->work); list_for_each_entry_safe(vbl_ev, tmp, _ctrl->event_list, node) { list_del(_ev->node); kfree(vbl_ev); @@ -476,7 +475,7 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) INIT_LIST_HEAD(>inactive_list); INIT_LIST_HEAD(>vblank_ctrl.event_list); - kthread_init_work(>vblank_ctrl.work, vblank_ctrl_worker); + INIT_WORK(>vblank_ctrl.work, vblank_ctrl_worker); spin_lock_init(>vblank_ctrl.lock); drm_mode_config_init(ddev); diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index 9d11f32..126345c4 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -78,7 +78,7 @@ enum msm_mdp_plane_property { }; struct msm_vblank_ctrl { - struct kthread_work work; + struct work_struct work; struct list_head event_list; spinlock_t lock; }; -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
[Freedreno] [PATCH v2 5/5] drm/msm: subclass work object for vblank events
msm maintains a separate structure to define vblank work definitions and a list to track events submitted to the workqueue. We can avoid this redundant list and its protection mechanism, if we subclass the work object to encapsulate vblank event parameters. changes in v2: - subclass optimization on system wq (Sean Paul) Signed-off-by: Jeykumar Sankaran --- drivers/gpu/drm/msm/msm_drv.c | 67 +-- drivers/gpu/drm/msm/msm_drv.h | 7 - 2 files changed, 20 insertions(+), 54 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 6d6c73b..8da5be2 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -203,61 +203,44 @@ u32 msm_readl(const void __iomem *addr) return val; } -struct vblank_event { - struct list_head node; +struct msm_vblank_work { + struct work_struct work; int crtc_id; bool enable; + struct msm_drm_private *priv; }; static void vblank_ctrl_worker(struct work_struct *work) { - struct msm_vblank_ctrl *vbl_ctrl = container_of(work, - struct msm_vblank_ctrl, work); - struct msm_drm_private *priv = container_of(vbl_ctrl, - struct msm_drm_private, vblank_ctrl); + struct msm_vblank_work *vbl_work = container_of(work, + struct msm_vblank_work, work); + struct msm_drm_private *priv = vbl_work->priv; struct msm_kms *kms = priv->kms; - struct vblank_event *vbl_ev, *tmp; - unsigned long flags; - - spin_lock_irqsave(_ctrl->lock, flags); - list_for_each_entry_safe(vbl_ev, tmp, _ctrl->event_list, node) { - list_del(_ev->node); - spin_unlock_irqrestore(_ctrl->lock, flags); - - if (vbl_ev->enable) - kms->funcs->enable_vblank(kms, - priv->crtcs[vbl_ev->crtc_id]); - else - kms->funcs->disable_vblank(kms, - priv->crtcs[vbl_ev->crtc_id]); - kfree(vbl_ev); - - spin_lock_irqsave(_ctrl->lock, flags); - } + if (vbl_work->enable) + kms->funcs->enable_vblank(kms, priv->crtcs[vbl_work->crtc_id]); + else + kms->funcs->disable_vblank(kms, priv->crtcs[vbl_work->crtc_id]); - spin_unlock_irqrestore(_ctrl->lock, flags); + kfree(vbl_work); } static int vblank_ctrl_queue_work(struct msm_drm_private *priv, int crtc_id, bool enable) { - struct msm_vblank_ctrl *vbl_ctrl = >vblank_ctrl; - struct vblank_event *vbl_ev; - unsigned long flags; + struct msm_vblank_work *vbl_work; - vbl_ev = kzalloc(sizeof(*vbl_ev), GFP_ATOMIC); - if (!vbl_ev) + vbl_work = kzalloc(sizeof(*vbl_work), GFP_ATOMIC); + if (!vbl_work) return -ENOMEM; - vbl_ev->crtc_id = crtc_id; - vbl_ev->enable = enable; + INIT_WORK(_work->work, vblank_ctrl_worker); - spin_lock_irqsave(_ctrl->lock, flags); - list_add_tail(_ev->node, _ctrl->event_list); - spin_unlock_irqrestore(_ctrl->lock, flags); + vbl_work->crtc_id = crtc_id; + vbl_work->enable = enable; + vbl_work->priv = priv; - schedule_work(_ctrl->work); + schedule_work(_work->work); return 0; } @@ -269,14 +252,13 @@ static int msm_drm_uninit(struct device *dev) struct msm_drm_private *priv = ddev->dev_private; struct msm_kms *kms = priv->kms; struct msm_mdss *mdss = priv->mdss; - struct msm_vblank_ctrl *vbl_ctrl = >vblank_ctrl; - struct vblank_event *vbl_ev, *tmp; int i; /* We must cancel and cleanup any pending vblank enable/disable * work before drm_irq_uninstall() to avoid work re-enabling an * irq after uninstall has disabled it. */ + msm_gem_shrinker_cleanup(ddev); drm_kms_helper_poll_fini(ddev); @@ -292,12 +274,6 @@ static int msm_drm_uninit(struct device *dev) #endif drm_mode_config_cleanup(ddev); - flush_work(_ctrl->work); - list_for_each_entry_safe(vbl_ev, tmp, _ctrl->event_list, node) { - list_del(_ev->node); - kfree(vbl_ev); - } - /* clean up event worker threads */ for (i = 0; i < priv->num_crtcs; i++) { if (priv->event_thread[i].thread) { @@ -469,9 +445,6 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) priv->wq = alloc_ordered_workqueue("msm", 0); INIT_LIST_HEAD(>inactive_list); - INIT_LIST_HEAD
Re: [Freedreno] [PATCH 2/2] drm/msm: subclass work object for vblank events
On 2018-11-05 09:24, Sean Paul wrote: On Fri, Nov 02, 2018 at 04:38:48PM -0700, Jeykumar Sankaran wrote: On 2018-11-01 12:18, Sean Paul wrote: > On Wed, Oct 31, 2018 at 05:19:05PM -0700, Jeykumar Sankaran wrote: > > msm maintains a separate structure to define vblank > > work definitions and a list to track events submitted > > to the display worker thread. We can avoid these > > redundant list and its protection mechanism, if we > > subclass the work object to encapsulate vblank > > event parameters. > > > > Signed-off-by: Jeykumar Sankaran > > --- > > drivers/gpu/drm/msm/msm_drv.c | 70 > --- > > drivers/gpu/drm/msm/msm_drv.h | 7 - > > 2 files changed, 19 insertions(+), 58 deletions(-) > > > > diff --git a/drivers/gpu/drm/msm/msm_drv.c > b/drivers/gpu/drm/msm/msm_drv.c > > index 1f384b3..67a96ee 100644 > > --- a/drivers/gpu/drm/msm/msm_drv.c > > +++ b/drivers/gpu/drm/msm/msm_drv.c /snip > > static int vblank_ctrl_queue_work(struct msm_drm_private *priv, > > int crtc_id, bool enable) > > { > > - struct msm_vblank_ctrl *vbl_ctrl = >vblank_ctrl; > > - struct vblank_event *vbl_ev; > > - unsigned long flags; > > + struct msm_vblank_work *vbl_work; > > > > - vbl_ev = kzalloc(sizeof(*vbl_ev), GFP_ATOMIC); > > - if (!vbl_ev) > > + vbl_work = kzalloc(sizeof(*vbl_work), GFP_ATOMIC); > > + if (!vbl_work) > > return -ENOMEM; > > > > - vbl_ev->crtc_id = crtc_id; > > - vbl_ev->enable = enable; > > + kthread_init_work(_work->work, vblank_ctrl_worker); > > > > - spin_lock_irqsave(_ctrl->lock, flags); > > - list_add_tail(_ev->node, _ctrl->event_list); > > - spin_unlock_irqrestore(_ctrl->lock, flags); > > + vbl_work->crtc_id = crtc_id; > > + vbl_work->enable = enable; > > + vbl_work->priv = priv; > > > > - kthread_queue_work(>disp_thread.worker, _ctrl->work); > > + kthread_queue_work(>disp_thread.worker, _work->work); > > So I think this can get even more simplified. In the short term, you can > just > use the systemwq to do the enable and disable. you mean priv->wq? I meant the system workqueue, we probably don't need our own for this. > > In the long term, the enable_vblank/disable_vblank functions should be > optimized so they don't sleep. I took a quick look at them perhaps this > is > all because of the crtc_lock mutex? That lock seems a bit suspicious to > me, > especially being dropped around the pm_runtime calls in > _dpu_crtc_vblank_enable_no_lock(). I think we could probably rely on the > modeset > locks for some of these functions, and perhaps convert it to a spinlock > if > we > can't get rid of it entirely. crtc_lock has a history of usage in the downstream driver. It was introduced to protect vblank variables when vblank requests were handled in the user thread (not the display thread). When event threads were introduced to receive encoder events, the lock was further expanded to protect few more vars. It was also needed to synchronize CRTC accesses between debugfs dump calls and display thread. The debugfs case can be solved pretty easily by using the modeset locks. I haven't looked closely at the event threads, could we convert crtc_lock to a spinlock and then make vblank enable/disable synchronous? Did a little digging into the reason why vblank enable/disable was made asynchronous in the first place. Looks like Rob was also using priv->wq to queue vblank requests before display threads were introduced by the DPU driver. The only reason I can think of was to support smart panels, where we wait for CTL_START interrupt instead of PING_PONG_DONE which is needed for fence releases. Need to confirm with Rob for MDP5 behaviour before switcing to sync. For now, I submit a patch to use system wq. Sean Would like to deal with this cleanup bit later once we lose these extra threads. Thanks and Regards, Jeykumar S. > > Sean > > > > > return 0; > > } > > @@ -269,20 +252,8 @@ static int msm_drm_uninit(struct device *dev) > > struct msm_drm_private *priv = ddev->dev_private; > > struct msm_kms *kms = priv->kms; > > struct msm_mdss *mdss = priv->mdss; > > - struct msm_vblank_ctrl *vbl_ctrl = >vblank_ctrl; > > - struct vblank_event *vbl_ev, *tmp; > > int i; > > > > - /* We must cancel and cleanup any pending vblank enable/disable > > - * work before drm_irq_uninstall() to avoid
Re: [Freedreno] [PATCH 2/2] drm/msm: subclass work object for vblank events
On 2018-11-01 12:18, Sean Paul wrote: On Wed, Oct 31, 2018 at 05:19:05PM -0700, Jeykumar Sankaran wrote: msm maintains a separate structure to define vblank work definitions and a list to track events submitted to the display worker thread. We can avoid these redundant list and its protection mechanism, if we subclass the work object to encapsulate vblank event parameters. Signed-off-by: Jeykumar Sankaran --- drivers/gpu/drm/msm/msm_drv.c | 70 --- drivers/gpu/drm/msm/msm_drv.h | 7 - 2 files changed, 19 insertions(+), 58 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 1f384b3..67a96ee 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -203,61 +203,44 @@ u32 msm_readl(const void __iomem *addr) return val; } -struct vblank_event { - struct list_head node; +struct msm_vblank_work { + struct kthread_work work; int crtc_id; bool enable; + struct msm_drm_private *priv; }; static void vblank_ctrl_worker(struct kthread_work *work) { - struct msm_vblank_ctrl *vbl_ctrl = container_of(work, - struct msm_vblank_ctrl, work); - struct msm_drm_private *priv = container_of(vbl_ctrl, - struct msm_drm_private, vblank_ctrl); + struct msm_vblank_work *vbl_work = container_of(work, + struct msm_vblank_work, work); + struct msm_drm_private *priv = vbl_work->priv; struct msm_kms *kms = priv->kms; - struct vblank_event *vbl_ev, *tmp; - unsigned long flags; - - spin_lock_irqsave(_ctrl->lock, flags); - list_for_each_entry_safe(vbl_ev, tmp, _ctrl->event_list, node) { - list_del(_ev->node); - spin_unlock_irqrestore(_ctrl->lock, flags); - - if (vbl_ev->enable) - kms->funcs->enable_vblank(kms, - priv->crtcs[vbl_ev->crtc_id]); - else - kms->funcs->disable_vblank(kms, - priv->crtcs[vbl_ev->crtc_id]); - kfree(vbl_ev); - - spin_lock_irqsave(_ctrl->lock, flags); - } + if (vbl_work->enable) + kms->funcs->enable_vblank(kms, priv->crtcs[vbl_work->crtc_id]); + else + kms->funcs->disable_vblank(kms, priv->crtcs[vbl_work->crtc_id]); - spin_unlock_irqrestore(_ctrl->lock, flags); + kfree(vbl_work); } static int vblank_ctrl_queue_work(struct msm_drm_private *priv, int crtc_id, bool enable) { - struct msm_vblank_ctrl *vbl_ctrl = >vblank_ctrl; - struct vblank_event *vbl_ev; - unsigned long flags; + struct msm_vblank_work *vbl_work; - vbl_ev = kzalloc(sizeof(*vbl_ev), GFP_ATOMIC); - if (!vbl_ev) + vbl_work = kzalloc(sizeof(*vbl_work), GFP_ATOMIC); + if (!vbl_work) return -ENOMEM; - vbl_ev->crtc_id = crtc_id; - vbl_ev->enable = enable; + kthread_init_work(_work->work, vblank_ctrl_worker); - spin_lock_irqsave(_ctrl->lock, flags); - list_add_tail(_ev->node, _ctrl->event_list); - spin_unlock_irqrestore(_ctrl->lock, flags); + vbl_work->crtc_id = crtc_id; + vbl_work->enable = enable; + vbl_work->priv = priv; - kthread_queue_work(>disp_thread.worker, _ctrl->work); + kthread_queue_work(>disp_thread.worker, _work->work); So I think this can get even more simplified. In the short term, you can just use the systemwq to do the enable and disable. you mean priv->wq? In the long term, the enable_vblank/disable_vblank functions should be optimized so they don't sleep. I took a quick look at them perhaps this is all because of the crtc_lock mutex? That lock seems a bit suspicious to me, especially being dropped around the pm_runtime calls in _dpu_crtc_vblank_enable_no_lock(). I think we could probably rely on the modeset locks for some of these functions, and perhaps convert it to a spinlock if we can't get rid of it entirely. crtc_lock has a history of usage in the downstream driver. It was introduced to protect vblank variables when vblank requests were handled in the user thread (not the display thread). When event threads were introduced to receive encoder events, the lock was further expanded to protect few more vars. It was also needed to synchronize CRTC accesses between debugfs dump calls and display thread. Would like to deal with this cleanup bit later once we lose these extra threads. Thanks and Regards, Jeykumar S. Sean return 0; } @@ -269,20 +252,8 @@ static int msm_drm_uninit(struct device *dev) struct msm_drm_private *priv = ddev->dev_priva
Re: [Freedreno] [PATCH 1/2] drm/msm: use common display thread for dispatching vblank events
On 2018-11-01 12:09, Sean Paul wrote: On Wed, Oct 31, 2018 at 05:19:04PM -0700, Jeykumar Sankaran wrote: DPU was using one thread per display to dispatch async commits and vblank requests. Since clean up already happened in msm to use the common thread for all the display commits, display threads are only used to cater vblank requests. Single thread is sufficient to do the job without any performance hits. Signed-off-by: Jeykumar Sankaran --- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 6 +--- drivers/gpu/drm/msm/msm_drv.c | 50 - drivers/gpu/drm/msm/msm_drv.h | 2 +- 3 files changed, 23 insertions(+), 35 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index 82c55ef..aff20f5 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -753,11 +753,7 @@ static int dpu_encoder_resource_control(struct drm_encoder *drm_enc, is_vid_mode = dpu_enc->disp_info.capabilities & MSM_DISPLAY_CAP_VID_MODE; - if (drm_enc->crtc->index >= ARRAY_SIZE(priv->disp_thread)) { - DPU_ERROR("invalid crtc index\n"); - return -EINVAL; - } - disp_thread = >disp_thread[drm_enc->crtc->index]; + disp_thread = >disp_thread; /* * when idle_pc is not supported, process only KICKOFF, STOP and MODESET diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 9c9f7ff..1f384b3 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -257,8 +257,7 @@ static int vblank_ctrl_queue_work(struct msm_drm_private *priv, list_add_tail(_ev->node, _ctrl->event_list); spin_unlock_irqrestore(_ctrl->lock, flags); - kthread_queue_work(>disp_thread[crtc_id].worker, - _ctrl->work); + kthread_queue_work(>disp_thread.worker, _ctrl->work); return 0; } @@ -284,14 +283,12 @@ static int msm_drm_uninit(struct device *dev) kfree(vbl_ev); } + kthread_flush_worker(>disp_thread.worker); + kthread_stop(priv->disp_thread.thread); I realize this is moving existing code, but is there a race here? You can't have work enqueued in between the flush and stop? Yes. I see only priv->kms is checked before queuing the work. I can move the thread cleanup after the drm_mode_config_cleanup which releases the CRTC objects. This way no one can make any further vblank requests. Thanks and Regards, Jeykumar S. You might also want to use kthread_destroy_worker to do this work (in a follow-up patch including the event threads too). + priv->disp_thread.thread = NULL; + /* clean up display commit/event worker threads */ This comment needs updating now for (i = 0; i < priv->num_crtcs; i++) { - if (priv->disp_thread[i].thread) { - kthread_flush_worker(>disp_thread[i].worker); - kthread_stop(priv->disp_thread[i].thread); - priv->disp_thread[i].thread = NULL; - } - if (priv->event_thread[i].thread) { kthread_flush_worker(>event_thread[i].worker); kthread_stop(priv->event_thread[i].thread); @@ -537,6 +534,22 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) ddev->mode_config.funcs = _config_funcs; ddev->mode_config.helper_private = _config_helper_funcs; + /* initialize display thread */ + kthread_init_worker(>disp_thread.worker); + priv->disp_thread.dev = ddev; + priv->disp_thread.thread = kthread_run(kthread_worker_fn, + >disp_thread.worker, + "disp_thread"); + if (IS_ERR(priv->disp_thread.thread)) { + DRM_DEV_ERROR(dev, "failed to create crtc_commit kthread\n"); + priv->disp_thread.thread = NULL; + goto err_msm_uninit; + } + + ret = sched_setscheduler(priv->disp_thread.thread, SCHED_FIFO, ); + if (ret) + pr_warn("display thread priority update failed: %d\n", ret); + /** * this priority was found during empiric testing to have appropriate * realtime scheduling to process display updates and interact with @@ -544,27 +557,6 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) */ param.sched_priority = 16; for (i = 0; i < priv->num_crtcs; i++) { - - /* initialize display thread */ - priv->disp_thread[i].crtc_id = priv->crtcs[i]->base.id; - kthread_init_worker(
[Freedreno] [PATCH v4 3/3] arm64: dts: sdm845: Add display nodes to MTP dts
Add mdss, dsi, dsi_phy, dsi pinctrl and truly nt35597 panel nodes to sdm845 MTP board dtsi. Changes in v4: - patch introduced in the series - move around added nodes to preserve alphabetical order (Doug Anderson) Signed-off-by: Jeykumar Sankaran --- arch/arm64/boot/dts/qcom/sdm845-mtp.dts | 124 1 file changed, 124 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm845-mtp.dts b/arch/arm64/boot/dts/qcom/sdm845-mtp.dts index eedfaf8..eb2a05b 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-mtp.dts +++ b/arch/arm64/boot/dts/qcom/sdm845-mtp.dts @@ -7,6 +7,7 @@ /dts-v1/; +#include #include #include "sdm845.dtsi" @@ -343,11 +344,118 @@ }; }; + { + status = "okay"; + qcom,dual-dsi-mode; + qcom,master-dsi; + qcom,sync-dual-dsi; + + vdda-supply = <_mipi_dsi0_1p2>; + + panel@0 { + compatible = "truly,nt35597-2K-display"; + reg = <0>; + + vdda-supply = <_l14a_1p88>; + vdispp-supply = <_regulator>; + vdispn-supply = <_regulator>; + + pinctrl-names = "default", "suspend"; + pinctrl-0 = <_dsi_active>; + pinctrl-1 = <_dsi_suspend>; + + reset-gpios = < 6 GPIO_ACTIVE_HIGH>; + mode-gpios = < 52 GPIO_ACTIVE_HIGH>; + + display-timings { + timing0: timing-0 { + /* originally +* 268316160 Mhz, +* but value below fits +* better w/ downstream +*/ + clock-frequency = <268316138>; + hactive = <1440>; + vactive = <2560>; + hfront-porch = <200>; + hback-porch = <64>; + hsync-len = <32>; + vfront-porch = <8>; + vback-porch = <7>; + vsync-len = <1>; + }; + }; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + panel0_in: endpoint { + remote-endpoint = <_out>; + }; + }; + + port@1 { + reg = <1>; + panel1_in: endpoint { + remote-endpoint = <_out>; + }; + }; + }; + }; + + ports { + port@1 { + endpoint { + remote-endpoint = <_in>; + data-lanes = <0 1 2 3>; + }; + }; + }; +}; + +_phy { + status = "okay"; + vdds-supply = <_mipi_dsi0_pll>; +}; + + { + status = "okay"; + + qcom,dual-dsi-mode; + qcom,sync-dual-dsi; + + vdda-supply = <_mipi_dsi1_1p2>; + + ports { + port@1 { + endpoint { + remote-endpoint = <_in>; + data-lanes = <0 1 2 3>; + }; + }; + }; +}; + +_phy { + status = "okay"; + vdds-supply = <_mipi_dsi1_pll>; +}; + { status = "okay"; clock-frequency = <40>; }; + { + status = "okay"; +}; + +_mdp { + status = "okay"; +}; + _id_1 { status = "okay"; }; @@ -419,6 +527,22 @@ /* PINCTRL - additions to nodes defined in sdm845.dtsi */ +_dsi_active { + pinconf { + pins = "gpio6", "gpio52"; + drive-strength = <8>; + bias-disable; + }; +}; + +_dsi_suspend { + pinconf { + pins = "gpio6", "gpio52"; + drive-strength = <2>; + bias-pull-down; + }; +}; + _i2c10_default { pinconf { pins = "gpio55", "gpio56"; -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
[Freedreno] [PATCH v4 0/3]
Reviving the patch posted by Sean initially. This patch set adds MDSS and DSI nodes to SDM845 dtsi to enable display. The patches are tested on SDM845 MTP platform using the kernel based on [1]. Part of the dependent drivers are already posted on list. Rest of the dependencies are met using using downstream version of the driver(s) which are yet to make it to the list. References to the driver patches used for testing: display controller: https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/commit/arch/arm64/boot/dts/qcom/sdm845.dtsi?id=40019e8452fe76867bdb2e7 WLED: https://patchwork.kernel.org/project/linux-arm-msm/list/?series=11023=both=* Panel: https://patchwork.freedesktop.org/series/50657/ iommu: https://patchwork.kernel.org/patch/10534999/ [1] https://git.linaro.org/landing-teams/working/qualcomm/kernel.git/log/?h=integration-linux-qcomlt Thanks and Regards, Jeykumar S. Changes in v4: - changes to add pinctrl nodes to SoC dts and display nodes to MTP are included in the series - clock name clean up in dsi nodes - move around added nodes to maintain naming orders Jeykumar Sankaran (3): arm64: dts: qcom: sdm845: Add dpu to sdm845 dts file arm64: dts: sdm845: Add dsi pinctrl nodes arm64: dts: sdm845: Add display nodes to MTP dts arch/arm64/boot/dts/qcom/sdm845-mtp.dts | 124 +++ arch/arm64/boot/dts/qcom/sdm845.dtsi| 205 2 files changed, 329 insertions(+) -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
[Freedreno] [PATCH v4 2/3] arm64: dts: sdm845: Add dsi pinctrl nodes
Add dsi active/suspend pinctrl nodes to sdm845 SoC dts. Changes in v4: - patch introduced in the series Signed-off-by: Jeykumar Sankaran --- arch/arm64/boot/dts/qcom/sdm845.dtsi | 14 ++ 1 file changed, 14 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index 5728b4c..35df5d2 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -822,6 +822,20 @@ interrupt-controller; #interrupt-cells = <2>; + dpu_dsi_active: dpu-dsi-active { + pinmux { + pins = "gpio6", "gpio52"; + function = "gpio"; + }; + }; + + dpu_dsi_suspend: dpu-dsi-suspend { + pinmux { + pins = "gpio6", "gpio52"; + function = "gpio"; + }; + }; + qup_i2c0_default: qup-i2c0-default { pinmux { pins = "gpio0", "gpio1"; -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
[Freedreno] [PATCH v4 1/3] arm64: dts: qcom: sdm845: Add dpu to sdm845 dts file
DPU is short for the Display Processing Unit. It is the display controller on Qualcomm SDM845 chips. This change adds MDSS and DSI nodes to enable display on the target device. Changes in v2: - Beefed up commit message - Use SoC specific compatibles for mdss and dpu (Rob H) - Use assigned-clocks to set initial clock frequency(Rob H) Changes in v3: - added IOMMU node - Fix device naming (remove _phys) - Use correct IRQ_TYPE in interrupt specifiers Changes in v4: - move mdss node to preserve the unit address sort order - remove _clk suffix from dsi clocks (both the comments are from Doug Anderson) Signed-off-by: Jeykumar Sankaran Signed-off-by: Sean Paul --- arch/arm64/boot/dts/qcom/sdm845.dtsi | 191 +++ 1 file changed, 191 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index b72bdb0..5728b4c 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -1248,6 +1248,197 @@ }; }; + mdss: mdss@ae0 { + compatible = "qcom,sdm845-mdss"; + reg = <0xae0 0x1000>; + reg-names = "mdss"; + + power-domains = < 0>; + + clocks = < GCC_DISP_AHB_CLK>, +< GCC_DISP_AXI_CLK>, +< DISP_CC_MDSS_MDP_CLK>; + clock-names = "iface", "bus", "core"; + + assigned-clocks = < DISP_CC_MDSS_MDP_CLK>; + assigned-clock-rates = <3>; + + interrupts = ; + interrupt-controller; + #interrupt-cells = <1>; + + iommus = <_smmu 0x880 0x8>, +<_smmu 0xc80 0x8>; + + #address-cells = <1>; + #size-cells = <1>; + ranges; + + mdss_mdp: mdp@ae01000 { + compatible = "qcom,sdm845-dpu"; + reg = <0x0ae01000 0x8f000>, + <0x0aeb 0x2008>; + reg-names = "mdp", "vbif"; + + clocks = < DISP_CC_MDSS_AHB_CLK>, +< DISP_CC_MDSS_AXI_CLK>, +< DISP_CC_MDSS_MDP_CLK>, +< DISP_CC_MDSS_VSYNC_CLK>; + clock-names = "iface", "bus", "core", "vsync"; + + assigned-clocks = < DISP_CC_MDSS_MDP_CLK>, + < DISP_CC_MDSS_VSYNC_CLK>; + assigned-clock-rates = <3>, + <1920>; + + interrupt-parent = <>; + interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dpu_intf1_out: endpoint { + remote-endpoint = <_in>; + }; + }; + + port@1 { + reg = <1>; + dpu_intf2_out: endpoint { + remote-endpoint = <_in>; + }; + }; + }; + }; + + dsi0: dsi@ae94000 { + compatible = "qcom,mdss-dsi-ctrl"; + reg = <0xae94000 0x400>; + reg-names = "dsi_ctrl"; + + interrupt-parent = <>; + interrupts = <4 IRQ_TYPE_LEVEL_HIGH>; + + clocks = < DISP_CC_MDSS_BYTE0_CLK>, +< DISP_CC_MDSS_BYTE0_INTF_CLK>, +
[Freedreno] [PATCH] arm64: dts: sdm845: Add display nodes to MTP dts
Add mdss, dsi, dsi_phy, dsi pinctrl and truly nt35597 panel nodes to sdm845 MTP board dtsi. Signed-off-by: Jeykumar Sankaran --- arch/arm64/boot/dts/qcom/sdm845-mtp.dts | 124 1 file changed, 124 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm845-mtp.dts b/arch/arm64/boot/dts/qcom/sdm845-mtp.dts index 6d651f3..6e98ae8 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-mtp.dts +++ b/arch/arm64/boot/dts/qcom/sdm845-mtp.dts @@ -8,6 +8,7 @@ /dts-v1/; #include "sdm845.dtsi" +#include / { model = "Qualcomm Technologies, Inc. SDM845 MTP"; @@ -22,6 +23,113 @@ }; }; + { + status = "okay"; + qcom,dual-dsi-mode; + qcom,master-dsi; + qcom,sync-dual-dsi; + + vdda-supply = <_mipi_dsi0_1p2>; + + panel@0 { + compatible = "truly,nt35597-2K-display"; + reg = <0>; + + vdda-supply = <_l14a_1p88>; + vdispp-supply = <_regulator>; + vdispn-supply = <_regulator>; + + pinctrl-names = "default", "suspend"; + pinctrl-0 = <_dsi_active>; + pinctrl-1 = <_dsi_suspend>; + + reset-gpios = < 6 GPIO_ACTIVE_HIGH>; + mode-gpios = < 52 GPIO_ACTIVE_HIGH>; + + display-timings { + timing0: timing-0 { + /* originally +* 268316160 Mhz, +* but value below fits +* better w/ downstream +*/ + clock-frequency = <268316138>; + hactive = <1440>; + vactive = <2560>; + hfront-porch = <200>; + hback-porch = <64>; + hsync-len = <32>; + vfront-porch = <8>; + vback-porch = <7>; + vsync-len = <1>; + }; + }; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + panel0_in: endpoint { + remote-endpoint = <_out>; + }; + }; + + port@1 { + reg = <1>; + panel1_in: endpoint { + remote-endpoint = <_out>; + }; + }; + }; + }; + + ports { + port@1 { + endpoint { + remote-endpoint = <_in>; + data-lanes = <0 1 2 3>; + }; + }; + }; +}; + +_phy { + status = "okay"; + vdds-supply = <_mipi_dsi0_pll>; +}; + + { + status = "okay"; + + qcom,dual-dsi-mode; + qcom,sync-dual-dsi; + + vdda-supply = <_mipi_dsi1_1p2>; + + ports { + port@1 { + endpoint { + remote-endpoint = <_in>; + data-lanes = <0 1 2 3>; + }; + }; + }; +}; + +_phy { + status = "okay"; + vdds-supply = <_mipi_dsi1_pll>; +}; + + { + status = "okay"; +}; + +_mdp { + status = "okay"; +}; + { status = "okay"; clock-frequency = <40>; @@ -58,3 +166,19 @@ bias-pull-up; }; }; + +_dsi_active { + pinconf { + pins = "gpio6", "gpio52"; + drive-strength = <8>; + bias-disable; + }; +}; + +_dsi_suspend { + pinconf { + pins = "gpio6", "gpio52"; + drive-strength = <2>; + bias-pull-down; + }; +}; -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
[Freedreno] [PATCH] arm64: dts: sdm845: Add dsi pinctrl nodes
Add dsi active/suspend pinctrl nodes to sdm845 SoC dts. Signed-off-by: Jeykumar Sankaran --- arch/arm64/boot/dts/qcom/sdm845.dtsi | 14 ++ 1 file changed, 14 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index dd612ac..e6a64f6 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -714,6 +714,20 @@ interrupt-controller; #interrupt-cells = <2>; + dpu_dsi_active: dpu-dsi-active { + pinmux { + pins = "gpio6", "gpio52"; + function = "gpio"; + }; + }; + + dpu_dsi_suspend: dpu-dsi-suspend { + pinmux { + pins = "gpio6", "gpio52"; + function = "gpio"; + }; + }; + qup_i2c0_default: qup-i2c0-default { pinmux { pins = "gpio0", "gpio1"; -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
Re: [Freedreno] [PATCH] drm/msm/dpu: Don't use devm for component devices
On 2018-11-02 07:30, Jordan Crouse wrote: Devices that are bound as components should not use devm since device managed memory is not freed when the component is unbound. In particular this is an issue if the component bind fails due to an -EPROBE_DEFER. In this case the bind would try again Isn't this the only case where using devm would be a problem? Even in this case do you expect any leaks if devm_kfree is called before DEFERing due to errors and in unbounds? Thanks, Jeykumar S. later and any devm managed memory allocated during the former aborted attempt would be leaked until the device itself was destroyed. Since all the memory allocated during a bind should be freed during an unbind (or bind error case) there isn't any reason to use devm for resources that have a explicit teardown step. This doesn't remove devm for all resources - in particular msm_ioremap() still uses devm_ioremap() but thats a generic issue that can easily be addressed as a cleanup later and the unbind code already does the requisite devm calls to unmap it. Signed-off-by: Jordan Crouse --- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 4 ++-- drivers/gpu/drm/msm/disp/dpu1/dpu_io_util.c | 4 +--- drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 10 ++ drivers/gpu/drm/msm/disp/dpu1/dpu_mdss.c| 8 +--- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index 82c55efb500f..287d4c3e58c3 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -2220,14 +2220,14 @@ struct drm_encoder *dpu_encoder_init(struct drm_device *dev, struct dpu_encoder_virt *dpu_enc = NULL; int rc = 0; - dpu_enc = devm_kzalloc(dev->dev, sizeof(*dpu_enc), GFP_KERNEL); + dpu_enc = kzalloc(sizeof(*dpu_enc), GFP_KERNEL); if (!dpu_enc) return ERR_PTR(ENOMEM); rc = drm_encoder_init(dev, _enc->base, _encoder_funcs, drm_enc_mode, NULL); if (rc) { - devm_kfree(dev->dev, dpu_enc); + kfree(dpu_enc); return ERR_PTR(rc); } diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_io_util.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_io_util.c index 89ee4b36beff..90b53e9508f2 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_io_util.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_io_util.c @@ -155,9 +155,7 @@ int msm_dss_parse_clock(struct platform_device *pdev, return 0; } - mp->clk_config = devm_kzalloc(>dev, - sizeof(struct dss_clk) * num_clk, - GFP_KERNEL); + mp->clk_config = kcalloc(num_clk, sizeof(struct dss_clk), GFP_KERNEL); if (!mp->clk_config) return -ENOMEM; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index 985c855796ae..5ac3c3f3b08d 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -1086,13 +1086,14 @@ static int dpu_bind(struct device *dev, struct device *master, void *data) struct dss_module_power *mp; int ret = 0; - dpu_kms = devm_kzalloc(>dev, sizeof(*dpu_kms), GFP_KERNEL); + dpu_kms = kzalloc(sizeof(*dpu_kms), GFP_KERNEL); if (!dpu_kms) return -ENOMEM; mp = _kms->mp; ret = msm_dss_parse_clock(pdev, mp); if (ret) { + kfree(dpu_kms); DPU_ERROR("failed to parse clocks, ret=%d\n", ret); return ret; } @@ -1109,7 +1110,7 @@ static int dpu_bind(struct device *dev, struct device *master, void *data) dpu_kms->rpm_enabled = true; priv->kms = _kms->base; - return ret; + return 0; } static void dpu_unbind(struct device *dev, struct device *master, void *data) @@ -1120,11 +1121,12 @@ static void dpu_unbind(struct device *dev, struct device *master, void *data) dpu_power_resource_deinit(pdev, _kms->phandle); msm_dss_put_clk(mp->clk_config, mp->num_clk); - devm_kfree(>dev, mp->clk_config); - mp->num_clk = 0; + kfree(mp->clk_config); if (dpu_kms->rpm_enabled) pm_runtime_disable(>dev); + + kfree(dpu_kms); } static const struct component_ops dpu_ops = { diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_mdss.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_mdss.c index 2235ef8129f4..34ab489b1a5b 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_mdss.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_mdss.c @@ -161,7 +161,7 @@ static void dpu_mdss_destroy(struct drm_device *dev) free_irq(platform_get_irq(pdev, 0), dpu_mdss); msm_dss_put_clk(mp->clk_config, mp->num_clk); - devm_kfree(>dev, mp->clk_config); + kfree(mp->clk_config); if (dpu_mdss->mmio) devm_iounmap(>dev, dpu_mdss->mmio);
Re: [Freedreno] [[DPU PATCH]] drm/msm/dpu: Correct dpu destroy and disable order
On 2018-11-01 23:17, Jayant Shekhar wrote: In case of msm drm bind failure, dpu_mdss_destroy is triggered. In this function, resources are freed and pm runtime disable is called, which triggers dpu_mdss_disable. Now in dpu_mdss_disable, driver tries to access a memory which is already freed. This results in kernel panic. Fix this by ensuring proper sequence of dpu destroy and disable calls. Change-Id: Id6e01a537ae9c40789c5752dc28c397391ab7dfe Please strip down Change-Id before posting the patch. Signed-off-by: Jayant Shekhar --- drivers/gpu/drm/msm/disp/dpu1/dpu_mdss.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_mdss.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_mdss.c index fd9c893..cd9a6bd 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_mdss.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_mdss.c @@ -156,6 +156,8 @@ static void dpu_mdss_destroy(struct drm_device *dev) struct dpu_mdss *dpu_mdss = to_dpu_mdss(priv->mdss); struct dss_module_power *mp = _mdss->mp; + pm_runtime_disable(dev->dev); + _dpu_mdss_irq_domain_fini(dpu_mdss); free_irq(platform_get_irq(pdev, 0), dpu_mdss); @@ -167,7 +169,6 @@ static void dpu_mdss_destroy(struct drm_device *dev) devm_iounmap(>dev, dpu_mdss->mmio); dpu_mdss->mmio = NULL; Lots of double line spacing. Get rid of them. - pm_runtime_disable(dev->dev); priv->mdss = NULL; } Also drop "DPU PATCH" prefix. -- Jeykumar s ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
[Freedreno] [PATCH v3] Add display nodes to SDM845 dtsi
Reviving the patch posted by Sean initially. This patch set adds MDSS and DSI nodes to SDM845 dtsi to enable display. The patches are tested on SDM845 MTP platform using the kernel based on [1]. Part of the dependent drivers are already posted on list. Rest of the dependencies are met using using downstream version of the driver(s) which are yet to make it to the list. References to the driver patches used for testing: display controller: https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/commit/arch/arm64/boot/dts/qcom/sdm845.dtsi?id=40019e8452fe76867bdb2e7 WLED: https://patchwork.kernel.org/project/linux-arm-msm/list/?series=11023=both=* Panel: https://patchwork.freedesktop.org/series/50657/ iommu: https://patchwork.kernel.org/patch/10534999/ [1] https://git.linaro.org/landing-teams/working/qualcomm/kernel.git/log/?h=integration-linux-qcomlt Thanks and Regards, Jeykumar S. Jeykumar Sankaran (1): arm64: dts: qcom: sdm845: Add dpu to sdm845 dts file arch/arm64/boot/dts/qcom/sdm845.dtsi | 191 +++ 1 file changed, 191 insertions(+) -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
[Freedreno] [PATCH v3] arm64: dts: qcom: sdm845: Add dpu to sdm845 dts file
DPU is short for the Display Processing Unit. It is the display controller on Qualcomm SDM845 chips. This change adds MDSS and DSI nodes to enable display on the target device. Changes in v2: - Beefed up commit message - Use SoC specific compatibles for mdss and dpu (Rob H) - Use assigned-clocks to set initial clock frequency(Rob H) Changes in v3: - added IOMMU node - Fix device naming (remove _phys) - Use correct IRQ_TYPE in interrupt specifiers Signed-off-by: Jeykumar Sankaran Signed-off-by: Sean Paul --- arch/arm64/boot/dts/qcom/sdm845.dtsi | 191 +++ 1 file changed, 191 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index 0c9a2aa..dd612ac 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -978,6 +978,197 @@ #thermal-sensor-cells = <1>; }; + mdss: mdss@ae0 { + compatible = "qcom,sdm845-mdss"; + reg = <0xae0 0x1000>; + reg-names = "mdss"; + + power-domains = < 0>; + + clocks = < GCC_DISP_AHB_CLK>, +< GCC_DISP_AXI_CLK>, +< DISP_CC_MDSS_MDP_CLK>; + clock-names = "iface", "bus", "core"; + + assigned-clocks = < DISP_CC_MDSS_MDP_CLK>; + assigned-clock-rates = <3>; + + interrupts = ; + interrupt-controller; + #interrupt-cells = <1>; + + iommus = <_smmu 0x880 0x8>, +<_smmu 0xc80 0x8>; + + #address-cells = <1>; + #size-cells = <1>; + ranges; + + mdss_mdp: mdp@ae01000 { + compatible = "qcom,sdm845-dpu"; + reg = <0x0ae01000 0x8f000>, + <0x0aeb 0x2008>; + reg-names = "mdp", "vbif"; + + clocks = < DISP_CC_MDSS_AHB_CLK>, +< DISP_CC_MDSS_AXI_CLK>, +< DISP_CC_MDSS_MDP_CLK>, +< DISP_CC_MDSS_VSYNC_CLK>; + clock-names = "iface", "bus", "core", "vsync"; + + assigned-clocks = < DISP_CC_MDSS_MDP_CLK>, + < DISP_CC_MDSS_VSYNC_CLK>; + assigned-clock-rates = <3>, + <1920>; + + interrupt-parent = <>; + interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dpu_intf1_out: endpoint { + remote-endpoint = <_in>; + }; + }; + + port@1 { + reg = <1>; + dpu_intf2_out: endpoint { + remote-endpoint = <_in>; + }; + }; + }; + }; + + dsi0: dsi@ae94000 { + compatible = "qcom,mdss-dsi-ctrl"; + reg = <0xae94000 0x400>; + reg-names = "dsi_ctrl"; + + interrupt-parent = <>; + interrupts = <4 IRQ_TYPE_LEVEL_HIGH>; + + clocks = < DISP_CC_MDSS_BYTE0_CLK>, +< DISP_CC_MDSS_BYTE0_INTF_CLK>, +< DISP_CC_MDSS_PCLK0_CLK>, +< DISP_CC_MDSS_ESC0_CLK>,
[Freedreno] [PATCH 2/2] drm/msm: subclass work object for vblank events
msm maintains a separate structure to define vblank work definitions and a list to track events submitted to the display worker thread. We can avoid these redundant list and its protection mechanism, if we subclass the work object to encapsulate vblank event parameters. Signed-off-by: Jeykumar Sankaran --- drivers/gpu/drm/msm/msm_drv.c | 70 --- drivers/gpu/drm/msm/msm_drv.h | 7 - 2 files changed, 19 insertions(+), 58 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 1f384b3..67a96ee 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -203,61 +203,44 @@ u32 msm_readl(const void __iomem *addr) return val; } -struct vblank_event { - struct list_head node; +struct msm_vblank_work { + struct kthread_work work; int crtc_id; bool enable; + struct msm_drm_private *priv; }; static void vblank_ctrl_worker(struct kthread_work *work) { - struct msm_vblank_ctrl *vbl_ctrl = container_of(work, - struct msm_vblank_ctrl, work); - struct msm_drm_private *priv = container_of(vbl_ctrl, - struct msm_drm_private, vblank_ctrl); + struct msm_vblank_work *vbl_work = container_of(work, + struct msm_vblank_work, work); + struct msm_drm_private *priv = vbl_work->priv; struct msm_kms *kms = priv->kms; - struct vblank_event *vbl_ev, *tmp; - unsigned long flags; - - spin_lock_irqsave(_ctrl->lock, flags); - list_for_each_entry_safe(vbl_ev, tmp, _ctrl->event_list, node) { - list_del(_ev->node); - spin_unlock_irqrestore(_ctrl->lock, flags); - - if (vbl_ev->enable) - kms->funcs->enable_vblank(kms, - priv->crtcs[vbl_ev->crtc_id]); - else - kms->funcs->disable_vblank(kms, - priv->crtcs[vbl_ev->crtc_id]); - kfree(vbl_ev); - - spin_lock_irqsave(_ctrl->lock, flags); - } + if (vbl_work->enable) + kms->funcs->enable_vblank(kms, priv->crtcs[vbl_work->crtc_id]); + else + kms->funcs->disable_vblank(kms, priv->crtcs[vbl_work->crtc_id]); - spin_unlock_irqrestore(_ctrl->lock, flags); + kfree(vbl_work); } static int vblank_ctrl_queue_work(struct msm_drm_private *priv, int crtc_id, bool enable) { - struct msm_vblank_ctrl *vbl_ctrl = >vblank_ctrl; - struct vblank_event *vbl_ev; - unsigned long flags; + struct msm_vblank_work *vbl_work; - vbl_ev = kzalloc(sizeof(*vbl_ev), GFP_ATOMIC); - if (!vbl_ev) + vbl_work = kzalloc(sizeof(*vbl_work), GFP_ATOMIC); + if (!vbl_work) return -ENOMEM; - vbl_ev->crtc_id = crtc_id; - vbl_ev->enable = enable; + kthread_init_work(_work->work, vblank_ctrl_worker); - spin_lock_irqsave(_ctrl->lock, flags); - list_add_tail(_ev->node, _ctrl->event_list); - spin_unlock_irqrestore(_ctrl->lock, flags); + vbl_work->crtc_id = crtc_id; + vbl_work->enable = enable; + vbl_work->priv = priv; - kthread_queue_work(>disp_thread.worker, _ctrl->work); + kthread_queue_work(>disp_thread.worker, _work->work); return 0; } @@ -269,20 +252,8 @@ static int msm_drm_uninit(struct device *dev) struct msm_drm_private *priv = ddev->dev_private; struct msm_kms *kms = priv->kms; struct msm_mdss *mdss = priv->mdss; - struct msm_vblank_ctrl *vbl_ctrl = >vblank_ctrl; - struct vblank_event *vbl_ev, *tmp; int i; - /* We must cancel and cleanup any pending vblank enable/disable -* work before drm_irq_uninstall() to avoid work re-enabling an -* irq after uninstall has disabled it. -*/ - kthread_flush_work(_ctrl->work); - list_for_each_entry_safe(vbl_ev, tmp, _ctrl->event_list, node) { - list_del(_ev->node); - kfree(vbl_ev); - } - kthread_flush_worker(>disp_thread.worker); kthread_stop(priv->disp_thread.thread); priv->disp_thread.thread = NULL; @@ -474,9 +445,6 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) priv->wq = alloc_ordered_workqueue("msm", 0); INIT_LIST_HEAD(>inactive_list); - INIT_LIST_HEAD(>vblank_ctrl.event_list); - kthread_init_work(>vblank_ctrl.work, vblank_ctrl_worker); - spin_lock_init(>vblank_ctrl.lock); drm_mode_config_init(ddev); diff --g
[Freedreno] [PATCH 1/2] drm/msm: use common display thread for dispatching vblank events
DPU was using one thread per display to dispatch async commits and vblank requests. Since clean up already happened in msm to use the common thread for all the display commits, display threads are only used to cater vblank requests. Single thread is sufficient to do the job without any performance hits. Signed-off-by: Jeykumar Sankaran --- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 6 +--- drivers/gpu/drm/msm/msm_drv.c | 50 - drivers/gpu/drm/msm/msm_drv.h | 2 +- 3 files changed, 23 insertions(+), 35 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index 82c55ef..aff20f5 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -753,11 +753,7 @@ static int dpu_encoder_resource_control(struct drm_encoder *drm_enc, is_vid_mode = dpu_enc->disp_info.capabilities & MSM_DISPLAY_CAP_VID_MODE; - if (drm_enc->crtc->index >= ARRAY_SIZE(priv->disp_thread)) { - DPU_ERROR("invalid crtc index\n"); - return -EINVAL; - } - disp_thread = >disp_thread[drm_enc->crtc->index]; + disp_thread = >disp_thread; /* * when idle_pc is not supported, process only KICKOFF, STOP and MODESET diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 9c9f7ff..1f384b3 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -257,8 +257,7 @@ static int vblank_ctrl_queue_work(struct msm_drm_private *priv, list_add_tail(_ev->node, _ctrl->event_list); spin_unlock_irqrestore(_ctrl->lock, flags); - kthread_queue_work(>disp_thread[crtc_id].worker, - _ctrl->work); + kthread_queue_work(>disp_thread.worker, _ctrl->work); return 0; } @@ -284,14 +283,12 @@ static int msm_drm_uninit(struct device *dev) kfree(vbl_ev); } + kthread_flush_worker(>disp_thread.worker); + kthread_stop(priv->disp_thread.thread); + priv->disp_thread.thread = NULL; + /* clean up display commit/event worker threads */ for (i = 0; i < priv->num_crtcs; i++) { - if (priv->disp_thread[i].thread) { - kthread_flush_worker(>disp_thread[i].worker); - kthread_stop(priv->disp_thread[i].thread); - priv->disp_thread[i].thread = NULL; - } - if (priv->event_thread[i].thread) { kthread_flush_worker(>event_thread[i].worker); kthread_stop(priv->event_thread[i].thread); @@ -537,6 +534,22 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) ddev->mode_config.funcs = _config_funcs; ddev->mode_config.helper_private = _config_helper_funcs; + /* initialize display thread */ + kthread_init_worker(>disp_thread.worker); + priv->disp_thread.dev = ddev; + priv->disp_thread.thread = kthread_run(kthread_worker_fn, + >disp_thread.worker, + "disp_thread"); + if (IS_ERR(priv->disp_thread.thread)) { + DRM_DEV_ERROR(dev, "failed to create crtc_commit kthread\n"); + priv->disp_thread.thread = NULL; + goto err_msm_uninit; + } + + ret = sched_setscheduler(priv->disp_thread.thread, SCHED_FIFO, ); + if (ret) + pr_warn("display thread priority update failed: %d\n", ret); + /** * this priority was found during empiric testing to have appropriate * realtime scheduling to process display updates and interact with @@ -544,27 +557,6 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) */ param.sched_priority = 16; for (i = 0; i < priv->num_crtcs; i++) { - - /* initialize display thread */ - priv->disp_thread[i].crtc_id = priv->crtcs[i]->base.id; - kthread_init_worker(>disp_thread[i].worker); - priv->disp_thread[i].dev = ddev; - priv->disp_thread[i].thread = - kthread_run(kthread_worker_fn, - >disp_thread[i].worker, - "crtc_commit:%d", priv->disp_thread[i].crtc_id); - if (IS_ERR(priv->disp_thread[i].thread)) { - DRM_DEV_ERROR(dev, "failed to create crtc_commit kthread\n"); - priv->disp_thread[i].thread = NULL; - goto err_msm_uninit; - } - -
Re: [Freedreno] [PATCH 07/25] drm/msm/dpu: reserve using crtc state
On 2018-10-09 23:28, Jeykumar Sankaran wrote: On 2018-10-09 14:06, Sean Paul wrote: On Mon, Oct 08, 2018 at 09:27:24PM -0700, Jeykumar Sankaran wrote: DPU maintained reservation lists to cache assigned HW blocks for the display and a retrieval mechanism for the individual DRM components to query their respective HW blocks. This patch uses the sub-classed CRTC state to store and track HW blocks assigned for different components of the display pipeline. It helps the driver: - to get rid of unwanted store and retrieval RM API's - to preserve HW resources assigned in atomic_check through atomic swap/duplicate. Separate patch is submitted to remove resource reservation in atomic_commit path. Signed-off-by: Jeykumar Sankaran --- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 65 +++--- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h | 14 + drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c| 28 +++--- .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c | 20 ++- drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 58 --- 5 files changed, 72 insertions(+), 113 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index 4960641..0625f56 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -421,69 +421,20 @@ void dpu_crtc_complete_commit(struct drm_crtc *crtc, trace_dpu_crtc_complete_commit(DRMID(crtc)); } -static void _dpu_crtc_setup_mixer_for_encoder( - struct drm_crtc *crtc, - struct drm_encoder *enc) +static void _dpu_crtc_setup_mixers(struct drm_crtc *crtc) { struct dpu_crtc_state *cstate = to_dpu_crtc_state(crtc->state); - struct dpu_kms *dpu_kms = _dpu_crtc_get_kms(crtc); - struct dpu_rm *rm = _kms->rm; 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(_iter, enc->base.id, DPU_HW_BLK_LM); - dpu_rm_init_hw_iter(_iter, enc->base.id, DPU_HW_BLK_CTL); + int i, ctl_index; /* Set up all the mixers and ctls reserved by this encoder */ - for (i = cstate->num_mixers; i < ARRAY_SIZE(cstate->mixers); i++) { + for (i = 0; i < cstate->num_mixers; i++) { mixer = >mixers[i]; - if (!dpu_rm_get_hw(rm, _iter)) - break; - mixer->hw_lm = (struct dpu_hw_mixer *)lm_iter.hw; - /* CTL may be <= LMs, if <, multiple LMs controlled by 1 CTL */ - if (!dpu_rm_get_hw(rm, _iter)) { - DPU_DEBUG("no ctl assigned to lm %d, using previous\n", - mixer->hw_lm->idx - LM_0); - mixer->lm_ctl = last_valid_ctl; - } else { - mixer->lm_ctl = (struct dpu_hw_ctl *)ctl_iter.hw; - last_valid_ctl = mixer->lm_ctl; - } - - /* Shouldn't happen, mixers are always >= ctls */ - if (!mixer->lm_ctl) { - DPU_ERROR("no valid ctls found for lm %d\n", - mixer->hw_lm->idx - LM_0); - return; - } - - cstate->num_mixers++; - DPU_DEBUG("setup mixer %d: lm %d\n", - i, mixer->hw_lm->idx - LM_0); - DPU_DEBUG("setup mixer %d: ctl %d\n", - i, mixer->lm_ctl->idx - CTL_0); - } -} - -static void _dpu_crtc_setup_mixers(struct drm_crtc *crtc) -{ - struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); - struct drm_encoder *enc; - - mutex_lock(_crtc->crtc_lock); - /* Check for mixers on all encoders attached to this crtc */ - list_for_each_entry(enc, >dev->mode_config.encoder_list, head) { - if (enc->crtc != crtc) - continue; - - _dpu_crtc_setup_mixer_for_encoder(crtc, enc); + ctl_index = min(i, cstate->num_ctls - 1); This is another one of those places I mentioned where we're just assuming a value is going to be in a certain range. If num_ctls/num_intfs/num_phys_encs (all the same value afaict) is 0, we end up in a bad place. Even though all these variables have the same value, they are representing the sizes of logically seperate components. At a minimum, there should be a WARN_ON/BUG_ON somewhere ensuring this can never drop below 0. Isn't RM guaranteeing that? I can add the WARN_ON checks on these num_xxx when the HW blocks are allocated. Thanks, Jeykumar S. + mixer->lm_ctl = cstate->hw_ctls[ctl_index]; } - - mutex_unlock(_crt
[Freedreno] [PATCH v4] drm/msm: validate display and event threads
While creating display and event threads per crtc, validate them before setting their priorities. changes in v2: - use dev_warn (Abhinav Kumar) changes in v3: - fix compilation error changes in v4: - Remove Change-Id (Sean Paul) - Keep logging within 80 char limit (Sean Paul) Signed-off-by: Jeykumar Sankaran --- drivers/gpu/drm/msm/msm_drv.c | 49 ++- 1 file changed, 16 insertions(+), 33 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 4904d0d..dcff812 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -553,17 +553,18 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) kthread_run(kthread_worker_fn, >disp_thread[i].worker, "crtc_commit:%d", priv->disp_thread[i].crtc_id); - ret = sched_setscheduler(priv->disp_thread[i].thread, - SCHED_FIFO, ); - if (ret) - pr_warn("display thread priority update failed: %d\n", - ret); - if (IS_ERR(priv->disp_thread[i].thread)) { dev_err(dev, "failed to create crtc_commit kthread\n"); priv->disp_thread[i].thread = NULL; + goto err_msm_uninit; } + ret = sched_setscheduler(priv->disp_thread[i].thread, +SCHED_FIFO, ); + if (ret) + dev_warn(dev, "disp_thread set priority failed: %d\n", +ret); + /* initialize event thread */ priv->event_thread[i].crtc_id = priv->crtcs[i]->base.id; kthread_init_worker(>event_thread[i].worker); @@ -572,6 +573,12 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) kthread_run(kthread_worker_fn, >event_thread[i].worker, "crtc_event:%d", priv->event_thread[i].crtc_id); + if (IS_ERR(priv->event_thread[i].thread)) { + dev_err(dev, "failed to create crtc_event kthread\n"); + priv->event_thread[i].thread = NULL; + goto err_msm_uninit; + } + /** * event thread should also run at same priority as disp_thread * because it is handling frame_done events. A lower priority @@ -580,34 +587,10 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) * failure at crtc commit level. */ ret = sched_setscheduler(priv->event_thread[i].thread, - SCHED_FIFO, ); +SCHED_FIFO, ); if (ret) - pr_warn("display event thread priority update failed: %d\n", - ret); - - if (IS_ERR(priv->event_thread[i].thread)) { - dev_err(dev, "failed to create crtc_event kthread\n"); - priv->event_thread[i].thread = NULL; - } - - if ((!priv->disp_thread[i].thread) || - !priv->event_thread[i].thread) { - /* clean up previously created threads if any */ - for ( ; i >= 0; i--) { - if (priv->disp_thread[i].thread) { - kthread_stop( - priv->disp_thread[i].thread); - priv->disp_thread[i].thread = NULL; - } - - if (priv->event_thread[i].thread) { - kthread_stop( - priv->event_thread[i].thread); - priv->event_thread[i].thread = NULL; - } - } - goto err_msm_uninit; - } + dev_warn(dev, "event_thread set priority failed:%d\n", +ret); } ret = drm_vblank_init(ddev, priv->num_crtcs); -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
Re: [Freedreno] [PATCH 14/25] drm/msm/dpu: remove enc_id tagging for hw blocks
On 2018-10-10 08:06, Sean Paul wrote: On Mon, Oct 08, 2018 at 09:27:31PM -0700, Jeykumar Sankaran wrote: RM was using encoder id's to tag HW block's to reserve and retrieve later for display pipeline. Now that all the reserved HW blocks for a display are maintained in its crtc state, no retrieval is needed. This patch cleans up RM of encoder id tagging. Signed-off-by: Jeykumar Sankaran --- drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c| 90 +-- drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h | 28 -- 2 files changed, 36 insertions(+), 82 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c index 303f1b3..a8461b8 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c @@ -21,9 +21,6 @@ #include "dpu_encoder.h" #include "dpu_trace.h" -#define RESERVED_BY_OTHER(h, r) \ - ((h)->enc_id && (h)->enc_id != r) - /** * struct dpu_rm_requirements - Reservation requirements parameter bundle * @topology: selected topology for the display @@ -38,12 +35,13 @@ struct dpu_rm_requirements { /** * struct dpu_rm_hw_blk - hardware block tracking list member * @list: List head for list of all hardware blocks tracking items - * @enc_id:Encoder id to which this blk is binded + * @in_use: True, if the hw block is assigned to a display pipeline. + * False, otherwise * @hw:Pointer to the hardware register access object for this block */ struct dpu_rm_hw_blk { struct list_head list; - uint32_t enc_id; + bool in_use; How do the reservations work for TEST_ONLY commits? At a quick glance it looks like they might be marked in_use? Yes. We have a bug. I guess I should be releasing them in drm_crtc_destroy_state. Thanks and Regards, Jeykumar S. Sean struct dpu_hw_blk *hw; }; @@ -51,23 +49,19 @@ struct dpu_rm_hw_blk { * struct dpu_rm_hw_iter - iterator for use with dpu_rm * @hw: dpu_hw object requested, or NULL on failure * @blk: dpu_rm internal block representation. Clients ignore. Used as iterator. - * @enc_id: DRM ID of Encoder client wishes to search for, or 0 for Any Encoder * @type: Hardware Block Type client wishes to search for. */ struct dpu_rm_hw_iter { struct dpu_hw_blk *hw; struct dpu_rm_hw_blk *blk; - uint32_t enc_id; enum dpu_hw_blk_type type; }; static void _dpu_rm_init_hw_iter( struct dpu_rm_hw_iter *iter, - uint32_t enc_id, enum dpu_hw_blk_type type) { memset(iter, 0, sizeof(*iter)); - iter->enc_id = enc_id; iter->type = type; } @@ -91,16 +85,12 @@ static bool _dpu_rm_get_hw_locked(struct dpu_rm *rm, struct dpu_rm_hw_iter *i) i->blk = list_prepare_entry(i->blk, blk_list, list); list_for_each_entry_continue(i->blk, blk_list, list) { - if (i->enc_id == i->blk->enc_id) { + if (!i->blk->in_use) { i->hw = i->blk->hw; - DPU_DEBUG("found type %d id %d for enc %d\n", - i->type, i->blk->hw->id, i->enc_id); return true; } } - DPU_DEBUG("no match, type %d for enc %d\n", i->type, i->enc_id); - return false; } @@ -196,7 +186,6 @@ static int _dpu_rm_hw_blk_create( } blk->hw = hw; - blk->enc_id = 0; list_add_tail(>list, >hw_blks[type]); return 0; @@ -301,7 +290,6 @@ static bool _dpu_rm_needs_split_display(const struct msm_display_topology *top) * proposed use case requirements, incl. hardwired dependent blocks like * pingpong * @rm: dpu resource manager handle - * @enc_id: encoder id requesting for allocation * @reqs: proposed use case requirements * @lm: proposed layer mixer, function checks if lm, and all other hardwired * blocks connected to the lm (pp) is available and appropriate @@ -313,7 +301,6 @@ static bool _dpu_rm_needs_split_display(const struct msm_display_topology *top) */ static bool _dpu_rm_check_lm_and_get_connected_blks( struct dpu_rm *rm, - uint32_t enc_id, struct dpu_rm_requirements *reqs, struct dpu_rm_hw_blk *lm, struct dpu_rm_hw_blk **pp, @@ -339,13 +326,7 @@ static bool _dpu_rm_check_lm_and_get_connected_blks( } } - /* Already reserved? */ - if (RESERVED_BY_OTHER(lm, enc_id)) { - DPU_DEBUG("lm %d already reserved\n", lm_cfg->id); - return false; - } - - _dpu_rm_init_hw_iter(, 0, DPU_HW_BLK_PINGPONG); + _dpu_rm_init_hw_iter(, DPU_HW_BLK_PINGPONG); while (_dpu_rm_ge
Re: [Freedreno] [PATCH 24/25] drm/msm/dpu: remove mutex locking for RM interfaces
On 2018-10-10 07:36, Sean Paul wrote: On Tue, Oct 09, 2018 at 11:03:24PM -0700, Jeykumar Sankaran wrote: On 2018-10-09 12:57, Sean Paul wrote: > On Mon, Oct 08, 2018 at 09:27:41PM -0700, Jeykumar Sankaran wrote: > > Since HW reservations are happening through atomic_check > > and all the display commits are catered by a single commit thread, > > it is not necessary to protect the interfaces by a separate > > mutex. > > > > Signed-off-by: Jeykumar Sankaran > > --- > > drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 24 > > drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h | 2 -- > > 2 files changed, 26 deletions(-) > > > > /snip > > > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h > b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h > > index 8676fa5..9acbeba 100644 > > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h > > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h > > @@ -24,11 +24,9 @@ > > * struct dpu_rm - DPU dynamic hardware resource manager > > * @hw_blks: array of lists of hardware resources present in the > system, one > > * list per type of hardware block > > - * @rm_lock: resource manager mutex > > */ > > struct dpu_rm { > > struct list_head hw_blks[DPU_HW_BLK_MAX]; > > At this point, there's really not much point to even having the rm. It's > just > another level of indirection that IMO complicates the code. If you look > at the usage of hw_blks, the code is always looking at a specific type > of > hw_blk, so the array is unnecessary. > > dpu_kms could just keep a few arrays/lists of the hw types, and the crtc > and encoder > reserve functions can just go in crtc/encoder. > > Sean > RM has been reduced to its current form to manage only LM/PP, CTL and interfaces. Our eventual plan is to support all the advanced HW blocks and its features in an upstream friendly way. When RM grows to manage all its subblocks, iteration logic may get heavy since the chipset have HW chain restrictions on various hw blocks. To provide room for the growth, I suggest keeping the allocation helpers in a separate file. But I can see why you want to maintain the HW block lists in the KMS. At least for the blocks that exist, using the RM is unnecessary, does that change for the current blocks when you add more? I'm guessing their code will remain unchanged. Yes. But to seperate out the allocation logics, I prefered the separate file. I guess we can hold off the discussion until we need those enhancements. I can get rid of the RM files for now and move the allocation functions to the respective files (CRTC / Encoder). Thanks, Jeykumar S. If the new blocks you're adding have a lot of commonality, perhaps it makes sense to re-introduce the RM, but IMO it doesn't make sense for lm/ctl/pp. Sean Thanks, Jeykumar S. > > - struct mutex rm_lock; > > }; > > > > /** > > -- > > The Qualcomm Innovation Center, Inc. is a member of the Code Aurora > Forum, > > a Linux Foundation Collaborative Project > > > > ___ > > Freedreno mailing list > > Freedreno@lists.freedesktop.org > > https://lists.freedesktop.org/mailman/listinfo/freedreno -- Jeykumar S -- Jeykumar S ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
Re: [Freedreno] [PATCH 01/25] drm/msm/dpu: fix hw ctl retrieval for mixer muxing
On 2018-10-10 07:29, Sean Paul wrote: On Tue, Oct 09, 2018 at 10:46:41PM -0700, Jeykumar Sankaran wrote: On 2018-10-09 11:07, Sean Paul wrote: > On Mon, Oct 08, 2018 at 09:27:18PM -0700, Jeykumar Sankaran wrote: > > Layer mixer/pingpong block counts and hw ctl block counts > > will not be same for all the topologies (e.g. layer > > mixer muxing to single interface) > > > > Use the encoder's split_role info to retrieve the > > respective control path for programming. > > > > Signed-off-by: Jeykumar Sankaran > > --- > > drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 9 ++--- > > 1 file changed, 6 insertions(+), 3 deletions(-) > > > > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c > b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c > > index 96cdf06..d12f896 100644 > > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c > > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c > > @@ -1060,6 +1060,7 @@ static void dpu_encoder_virt_mode_set(struct > drm_encoder *drm_enc, > > > > for (i = 0; i < dpu_enc->num_phys_encs; i++) { > > struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; > > + int ctl_index; > > > > if (phys) { > > if (!dpu_enc->hw_pp[i]) { > > @@ -1068,14 +1069,16 @@ static void dpu_encoder_virt_mode_set(struct > drm_encoder *drm_enc, > > return; > > } > > > > - if (!hw_ctl[i]) { > > + ctl_index = phys->split_role == ENC_ROLE_SLAVE ? 1 > : 0; > > + > > What if MAX_CHANNELS_PER_ENC isn't 2? Similarly, what if num_phys_encs > MAX_CHANNELS_PER_ENC? It seems like there should be a more formal > relationship > between all of these verious values (num_of_h_tiles assumed to be <= 2 > as > well). > If one of them changes beyond the assumed bound, the rest of the driver > falls > over pretty hard. > MAX_CHANNELS_PER_ENC is set to 2 to represent HW limitation on the chipset as we cannot gang up more than 2 LM chain to an interface. Supporting more than 2 might demand much larger changes than validating for boundaries. num_phys_enc is the max no of phys encoders we create as we are looping through num_of_h_tiles which cannot be more than priv->dsi array size. So its very unlikely we would expect these loops to go out of bound! For now, sure. However a new revision of hardware will be a pain to add support for if we add more assumptions, and secondly it makes it _really_ hard to understand the code if you don't have Qualcomm employee-level access to the hardware design :). I am having a hard time understanding why you have to see these counts as "assumptions". Except for MAX_CHANNELS_PER_ENC, all the other counts are either calculated or derived from the other modules linked to the topology. h_tiles is the drm_connector terminology which represents the number of panels the display is driving. We use this information to determine the HW block chains in the MDP. HW blocks counts (pp or ctl) need not be same as the h_tile count to replace them with. I believe maintaining the counts independently at each layer allows us to have more flexibility to support independent HW chaining for future revisions. Would it be more convincing if I get the MAX_CHANNELS_PER_ENC value from catalog.c? So this is why I'm advocating for the reduction of the number of "num_of_" values we assume are all in the same range. It's a lot easier to understand the hardware when you can see that a phys encoder is needed per h tile, and that a ctl/pp is needed per phys encoder. This is exactly the idea I don't want to convey to the reader. For the LM merge path, each phys encoder will not be having its own control. Based on the topology we are supporting, HW block counts can vary. We can even drive: - 2 interfaces with 1 ctl and 1 ping pong - 1 interface with 1 ctl and 2 ping pongs - 1 interface with 1 ctl and 1 ping pong Thanks, Jeykumar S. Anyways, just my $0.02. Sean Thanks, Jeykumar S. > > > + if (!hw_ctl[ctl_index]) { > > DPU_ERROR_ENC(dpu_enc, "no ctl block > assigned" > > - "at idx: %d\n", i); > > + "at idx: %d\n", ctl_index); > > return; > > When you return on error here, should you give back the resources that > you've > already provisioned? > > > } > > > > phys->hw_pp = dpu_enc->hw_pp[i]; > > - phys->hw_ctl = hw_ctl
Re: [Freedreno] [DPU PATCH 0/3] Add support for DisplayPort driver on SnapDragon 845
On 2018-10-10 10:15, Chandan Uddaraju wrote: These patches add support for Display-Port driver on SnapDragon 845 hardware. It adds DP driver and DP PLL driver files along with the needed device-tree bindings. The block diagram of DP driver is shown below: +-+ |DRM FRAMEWORK| +--+--+ | +v+ | DP DRM | +++ | +v+ ++| DP+--++--+ ++---+| DISPLAY |+---+ | | |++-+-+-+| | | || | | | | | || | | | | | || | | | | | vv v v v v v +--+ +--+ +---+ ++ ++ +---+ +-+ | DP | | DP | |DP | | DP | | DP | |DP | | DP | |PARSER| |EXTCON| |AUX| |LINK| |CTRL| |PHY| |POWER| +--+---+ +---+--+ +---+ ++ +--+-+ +-+-+ +-+ | || | +--v---+ +---v-+ +v-v+ |DEVICE| |EXTCON | | DP | | TREE | |INTERFACE| |CATALOG| +--+ +-+ +---+---+ | +---v+ |CTRL/PHY| | HW | ++ It will be more helpful to have this block diagram in [DPU PATCH 2/3] drm/msm/dp: add displayPort driver support Thanks, Jeykumar S. These patches have dependency on clock driver changes mentioned below: https://patchwork.kernel.org/patch/10632753/ https://patchwork.kernel.org/patch/10632757/ Chandan Uddaraju (3): dt-bindings: msm/dp: add bindings of DP/DP-PLL driver for Snapdragon 845 drm/msm/dp: add displayPort driver support drm/msm/dp: add support for DP PLL driver .../devicetree/bindings/display/msm/dp.txt | 249 .../devicetree/bindings/display/msm/dpu.txt| 16 +- drivers/gpu/drm/msm/Kconfig| 25 + drivers/gpu/drm/msm/Makefile | 21 +- drivers/gpu/drm/msm/disp/dpu1/dpu_io_util.c| 206 +++ drivers/gpu/drm/msm/disp/dpu1/dpu_io_util.h| 44 + drivers/gpu/drm/msm/dp/dp_aux.c| 570 +++ drivers/gpu/drm/msm/dp/dp_aux.h| 44 + drivers/gpu/drm/msm/dp/dp_catalog.c| 1188 +++ drivers/gpu/drm/msm/dp/dp_catalog.h| 144 ++ drivers/gpu/drm/msm/dp/dp_ctrl.c | 1476 +++ drivers/gpu/drm/msm/dp/dp_ctrl.h | 50 + drivers/gpu/drm/msm/dp/dp_debug.c | 507 +++ drivers/gpu/drm/msm/dp/dp_debug.h | 81 + drivers/gpu/drm/msm/dp/dp_display.c| 1027 + drivers/gpu/drm/msm/dp/dp_display.h| 58 + drivers/gpu/drm/msm/dp/dp_drm.c| 542 +++ drivers/gpu/drm/msm/dp/dp_drm.h| 52 + drivers/gpu/drm/msm/dp/dp_extcon.c | 400 + drivers/gpu/drm/msm/dp/dp_extcon.h | 111 ++ drivers/gpu/drm/msm/dp/dp_link.c | 1549 drivers/gpu/drm/msm/dp/dp_link.h | 184 +++ drivers/gpu/drm/msm/dp/dp_panel.c | 624 drivers/gpu/drm/msm/dp/dp_panel.h | 121 ++ drivers/gpu/drm/msm/dp/dp_parser.c | 679 + drivers/gpu/drm/msm/dp/dp_parser.h | 208 +++ drivers/gpu/drm/msm/dp/dp_power.c | 652 drivers/gpu/drm/msm/dp/dp_power.h | 59 + drivers/gpu/drm/msm/dp/dp_reg.h| 357 + drivers/gpu/drm/msm/dp/pll/dp_pll.c| 153 ++ drivers/gpu/drm/msm/dp/pll/dp_pll.h| 64 + drivers/gpu/drm/msm/dp/pll/dp_pll_10nm.c | 401 + drivers/gpu/drm/msm/dp/pll/dp_pll_10nm.h | 94 ++ drivers/gpu/drm/msm/dp/pll/dp_pll_10nm_util.c | 531 +++ drivers/gpu/drm/msm/msm_drv.c |2 + drivers/gpu/drm/msm/msm_drv.h | 22 + include/drm/drm_dp_helper.h| 19 + 37 files changed, 12525 insertions(+), 5 deletions(-) create mode 100644 Documentation/devicetree/bindings/display/msm/dp.txt create mode 100644 drivers/gpu/drm/msm/dp/dp_aux.c create mode 100644 drivers/gpu/drm/msm/dp/dp_aux.h create mode 100644 drivers/gpu/drm/msm/dp/dp_catalog.c create mode 100644 drivers/gpu/drm/msm/dp/dp_catalog.h create mode 100644 drivers/gpu/drm/msm/dp/dp_ctrl.c create mode 100644 drivers/gpu/drm/msm/dp/dp_ctrl.h create mode 100644 drivers/gpu/drm/msm/dp/dp_debug.c create mode 100644 drivers/gpu/drm/msm/dp/dp_debug.h create
Re: [Freedreno] [PATCH 07/25] drm/msm/dpu: reserve using crtc state
On 2018-10-09 14:06, Sean Paul wrote: On Mon, Oct 08, 2018 at 09:27:24PM -0700, Jeykumar Sankaran wrote: DPU maintained reservation lists to cache assigned HW blocks for the display and a retrieval mechanism for the individual DRM components to query their respective HW blocks. This patch uses the sub-classed CRTC state to store and track HW blocks assigned for different components of the display pipeline. It helps the driver: - to get rid of unwanted store and retrieval RM API's - to preserve HW resources assigned in atomic_check through atomic swap/duplicate. Separate patch is submitted to remove resource reservation in atomic_commit path. Signed-off-by: Jeykumar Sankaran --- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 65 +++--- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h | 14 + drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c| 28 +++--- .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c | 20 ++- drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 58 --- 5 files changed, 72 insertions(+), 113 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index 4960641..0625f56 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -421,69 +421,20 @@ void dpu_crtc_complete_commit(struct drm_crtc *crtc, trace_dpu_crtc_complete_commit(DRMID(crtc)); } -static void _dpu_crtc_setup_mixer_for_encoder( - struct drm_crtc *crtc, - struct drm_encoder *enc) +static void _dpu_crtc_setup_mixers(struct drm_crtc *crtc) { struct dpu_crtc_state *cstate = to_dpu_crtc_state(crtc->state); - struct dpu_kms *dpu_kms = _dpu_crtc_get_kms(crtc); - struct dpu_rm *rm = _kms->rm; 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(_iter, enc->base.id, DPU_HW_BLK_LM); - dpu_rm_init_hw_iter(_iter, enc->base.id, DPU_HW_BLK_CTL); + int i, ctl_index; /* Set up all the mixers and ctls reserved by this encoder */ - for (i = cstate->num_mixers; i < ARRAY_SIZE(cstate->mixers); i++) { + for (i = 0; i < cstate->num_mixers; i++) { mixer = >mixers[i]; - if (!dpu_rm_get_hw(rm, _iter)) - break; - mixer->hw_lm = (struct dpu_hw_mixer *)lm_iter.hw; - /* CTL may be <= LMs, if <, multiple LMs controlled by 1 CTL */ - if (!dpu_rm_get_hw(rm, _iter)) { - DPU_DEBUG("no ctl assigned to lm %d, using previous\n", - mixer->hw_lm->idx - LM_0); - mixer->lm_ctl = last_valid_ctl; - } else { - mixer->lm_ctl = (struct dpu_hw_ctl *)ctl_iter.hw; - last_valid_ctl = mixer->lm_ctl; - } - - /* Shouldn't happen, mixers are always >= ctls */ - if (!mixer->lm_ctl) { - DPU_ERROR("no valid ctls found for lm %d\n", - mixer->hw_lm->idx - LM_0); - return; - } - - cstate->num_mixers++; - DPU_DEBUG("setup mixer %d: lm %d\n", - i, mixer->hw_lm->idx - LM_0); - DPU_DEBUG("setup mixer %d: ctl %d\n", - i, mixer->lm_ctl->idx - CTL_0); - } -} - -static void _dpu_crtc_setup_mixers(struct drm_crtc *crtc) -{ - struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); - struct drm_encoder *enc; - - mutex_lock(_crtc->crtc_lock); - /* Check for mixers on all encoders attached to this crtc */ - list_for_each_entry(enc, >dev->mode_config.encoder_list, head) { - if (enc->crtc != crtc) - continue; - - _dpu_crtc_setup_mixer_for_encoder(crtc, enc); + ctl_index = min(i, cstate->num_ctls - 1); This is another one of those places I mentioned where we're just assuming a value is going to be in a certain range. If num_ctls/num_intfs/num_phys_encs (all the same value afaict) is 0, we end up in a bad place. Even though all these variables have the same value, they are representing the sizes of logically seperate components. At a minimum, there should be a WARN_ON/BUG_ON somewhere ensuring this can never drop below 0. Isn't RM guaranteeing that? I can add the WARN_ON checks on these num_xxx when the HW blocks are allocated. Thanks, Jeykumar S. + mixer->lm_ctl = cstate->hw_ctls[ctl_index]; } - - mutex_unlock(_crtc->crtc_lock); } static void _dpu_cr
Re: [Freedreno] [PATCH 22/25] drm/msm/dpu: make crtc and encoder specific HW reservation
On 2018-10-09 13:41, Sean Paul wrote: On Mon, Oct 08, 2018 at 09:27:39PM -0700, Jeykumar Sankaran wrote: Instead of letting encoder make a centralized reservation for all of its display DRM components, this path splits the responsibility between CRTC and Encoder, each requesting RM for the HW mapping of its own domain. Signed-off-by: Jeykumar Sankaran --- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c| 31 + drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 14 ++ drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 69 - drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h | 36 +++ 4 files changed, 119 insertions(+), 31 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index 0625f56..0536b8a 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 LEFT_MIXER 0 #define RIGHT_MIXER 1 +#define MAX_VDISPLAY_SPLIT 1080 + static inline int _dpu_crtc_get_mixer_width(struct dpu_crtc_state *cstate, struct drm_display_mode *mode) { @@ -448,6 +450,7 @@ static void _dpu_crtc_setup_lm_bounds(struct drm_crtc *crtc, for (i = 0; i < cstate->num_mixers; i++) { struct drm_rect *r = >lm_bounds[i]; + r->x1 = crtc_split_width * i; r->y1 = 0; r->x2 = r->x1 + crtc_split_width; @@ -885,6 +888,7 @@ static void dpu_crtc_disable(struct drm_crtc *crtc) struct drm_display_mode *mode; struct drm_encoder *encoder; struct msm_drm_private *priv; + struct dpu_kms *dpu_kms; unsigned long flags; if (!crtc || !crtc->dev || !crtc->dev->dev_private || !crtc->state) { @@ -895,6 +899,7 @@ static void dpu_crtc_disable(struct drm_crtc *crtc) cstate = to_dpu_crtc_state(crtc->state); mode = >base.adjusted_mode; priv = crtc->dev->dev_private; + dpu_kms = to_dpu_kms(priv->kms); DRM_DEBUG_KMS("crtc%d\n", crtc->base.id); @@ -953,6 +958,8 @@ static void dpu_crtc_disable(struct drm_crtc *crtc) crtc->state->event = NULL; spin_unlock_irqrestore(>dev->event_lock, flags); } + + dpu_rm_crtc_release(_kms->rm, crtc->state); } static void dpu_crtc_enable(struct drm_crtc *crtc, @@ -1004,6 +1011,21 @@ struct plane_state { u32 pipe_id; }; +static void _dpu_crtc_get_topology( + struct drm_crtc_state *crtc_state, + struct drm_display_mode *mode) +{ + struct dpu_crtc_state *dpu_cstate = to_dpu_crtc_state(crtc_state); + + dpu_cstate->num_mixers = (mode->vdisplay > MAX_VDISPLAY_SPLIT) ? 2 : 1; + + /** +* encoder->atomic_check is invoked before crtc->atomic_check. +* so dpu_cstate->num_intfs should have a non-zero value. +*/ + dpu_cstate->num_ctls = dpu_cstate->num_intfs; Why do we need num_ctls? Can't we just use dpu_cstate->num_intfs directly? Also, you don't really need these in their own function, especially if num_ctls goes away. Yes. I can live with just that. But since dpu_cstate maintains HW arrays for each type, I thought it would be more readable if I could use separate variables to track their counts instead of iterating over ctl arrays over dpu_cstate->num_intfs and leaving comments that both will be same for this version of hardware. Also, the counts need not be the same for all the Snapdragon variants. Thanks, Jeykumar S. +} + static int dpu_crtc_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *state) { @@ -1014,6 +1036,8 @@ static int dpu_crtc_atomic_check(struct drm_crtc *crtc, const struct drm_plane_state *pstate; struct drm_plane *plane; struct drm_display_mode *mode; + struct msm_drm_private *priv; + struct dpu_kms *dpu_kms; int cnt = 0, rc = 0, mixer_width, i, z_pos; @@ -1039,6 +1063,9 @@ static int dpu_crtc_atomic_check(struct drm_crtc *crtc, goto end; } + priv = crtc->dev->dev_private; + dpu_kms = to_dpu_kms(priv->kms); + mode = >adjusted_mode; DPU_DEBUG("%s: check", dpu_crtc->name); @@ -1229,6 +1256,10 @@ static int dpu_crtc_atomic_check(struct drm_crtc *crtc, } } + _dpu_crtc_get_topology(state, mode); + if (drm_atomic_crtc_needs_modeset(state)) + rc = dpu_rm_crtc_reserve(_kms->rm, state); + end: kfree(pstates); return rc; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index 5d501c8..ce66309 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -6
Re: [Freedreno] [PATCH 24/25] drm/msm/dpu: remove mutex locking for RM interfaces
On 2018-10-09 12:57, Sean Paul wrote: On Mon, Oct 08, 2018 at 09:27:41PM -0700, Jeykumar Sankaran wrote: Since HW reservations are happening through atomic_check and all the display commits are catered by a single commit thread, it is not necessary to protect the interfaces by a separate mutex. Signed-off-by: Jeykumar Sankaran --- drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 24 drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h | 2 -- 2 files changed, 26 deletions(-) /snip diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h index 8676fa5..9acbeba 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h @@ -24,11 +24,9 @@ * struct dpu_rm - DPU dynamic hardware resource manager * @hw_blks: array of lists of hardware resources present in the system, one * list per type of hardware block - * @rm_lock: resource manager mutex */ struct dpu_rm { struct list_head hw_blks[DPU_HW_BLK_MAX]; At this point, there's really not much point to even having the rm. It's just another level of indirection that IMO complicates the code. If you look at the usage of hw_blks, the code is always looking at a specific type of hw_blk, so the array is unnecessary. dpu_kms could just keep a few arrays/lists of the hw types, and the crtc and encoder reserve functions can just go in crtc/encoder. Sean RM has been reduced to its current form to manage only LM/PP, CTL and interfaces. Our eventual plan is to support all the advanced HW blocks and its features in an upstream friendly way. When RM grows to manage all its subblocks, iteration logic may get heavy since the chipset have HW chain restrictions on various hw blocks. To provide room for the growth, I suggest keeping the allocation helpers in a separate file. But I can see why you want to maintain the HW block lists in the KMS. Thanks, Jeykumar S. - struct mutex rm_lock; }; /** -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno -- Jeykumar S ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
Re: [Freedreno] [PATCH 01/25] drm/msm/dpu: fix hw ctl retrieval for mixer muxing
On 2018-10-09 11:07, Sean Paul wrote: On Mon, Oct 08, 2018 at 09:27:18PM -0700, Jeykumar Sankaran wrote: Layer mixer/pingpong block counts and hw ctl block counts will not be same for all the topologies (e.g. layer mixer muxing to single interface) Use the encoder's split_role info to retrieve the respective control path for programming. Signed-off-by: Jeykumar Sankaran --- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 9 ++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index 96cdf06..d12f896 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -1060,6 +1060,7 @@ static void dpu_encoder_virt_mode_set(struct drm_encoder *drm_enc, for (i = 0; i < dpu_enc->num_phys_encs; i++) { struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; + int ctl_index; if (phys) { if (!dpu_enc->hw_pp[i]) { @@ -1068,14 +1069,16 @@ static void dpu_encoder_virt_mode_set(struct drm_encoder *drm_enc, return; } - if (!hw_ctl[i]) { + ctl_index = phys->split_role == ENC_ROLE_SLAVE ? 1 : 0; + What if MAX_CHANNELS_PER_ENC isn't 2? Similarly, what if num_phys_encs > MAX_CHANNELS_PER_ENC? It seems like there should be a more formal relationship between all of these verious values (num_of_h_tiles assumed to be <= 2 as well). If one of them changes beyond the assumed bound, the rest of the driver falls over pretty hard. MAX_CHANNELS_PER_ENC is set to 2 to represent HW limitation on the chipset as we cannot gang up more than 2 LM chain to an interface. Supporting more than 2 might demand much larger changes than validating for boundaries. num_phys_enc is the max no of phys encoders we create as we are looping through num_of_h_tiles which cannot be more than priv->dsi array size. So its very unlikely we would expect these loops to go out of bound! Thanks, Jeykumar S. + if (!hw_ctl[ctl_index]) { DPU_ERROR_ENC(dpu_enc, "no ctl block assigned" -"at idx: %d\n", i); +"at idx: %d\n", ctl_index); return; When you return on error here, should you give back the resources that you've already provisioned? } phys->hw_pp = dpu_enc->hw_pp[i]; - phys->hw_ctl = hw_ctl[i]; + phys->hw_ctl = hw_ctl[ctl_index]; phys->connector = conn->state->connector; if (phys->ops.mode_set) -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno -- Jeykumar S ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
Re: [Freedreno] [PATCH 2/2] drm/msm: dpu: Remove checks from dpu_plane_destroy_state()
On 2018-10-04 11:09, Sean Paul wrote: From: Sean Paul They're not needed. Signed-off-by: Sean Paul --- Reviewed-by: Jeykumar Sankaran drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 13 + 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c index f549daf30fe6..4213e7a8e525 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c @@ -1193,19 +1193,8 @@ static void dpu_plane_destroy(struct drm_plane *plane) static void dpu_plane_destroy_state(struct drm_plane *plane, struct drm_plane_state *state) { - struct dpu_plane_state *pstate; - - if (!plane || !state) { - DPU_ERROR("invalid arg(s), plane %d state %d\n", - plane != 0, state != 0); - return; - } - - pstate = to_dpu_plane_state(state); - __drm_atomic_helper_plane_destroy_state(state); - - kfree(pstate); + kfree(to_dpu_plane_state(state)); } static struct drm_plane_state * -- Jeykumar S ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
Re: [Freedreno] [PATCH 1/2] drm/msm: dpu: Fix memory leak caused by dropped reference
On 2018-10-04 11:09, Sean Paul wrote: From: Sean Paul We are currently leaking a drm_crtc_commit struct for every atomic commit containing plane state. The dpu plane destroy function cleans up dpu plane destroy -> dpu_plane_destroy_state the fb reference manually, but fails to release the commit ref. As a result, we just keep allocating drm_crtc_commits without ever freeing them. Fortunately there's a helper function which will clean up all of our mess at once, so use that. Thanks to Doug Anderson for reporting the memory leak (and leaving breadcrumbs from kmemleak!). Reported-by: Doug Anderson Signed-off-by: Sean Paul --- With the nit addressed: Reviewed-by: Jeykumar Sankaran drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c index fc59a69aa832..f549daf30fe6 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c @@ -1203,9 +1203,7 @@ static void dpu_plane_destroy_state(struct drm_plane *plane, pstate = to_dpu_plane_state(state); - /* remove ref count for frame buffers */ - if (state->fb) - drm_framebuffer_put(state->fb); + __drm_atomic_helper_plane_destroy_state(state); kfree(pstate); } -- Jeykumar S ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
Re: [Freedreno] [PATCH 18/25] drm/msm/dpu: merge RM interface reservation helpers
On 2018-10-09 09:50, Jordan Crouse wrote: On Mon, Oct 08, 2018 at 09:27:35PM -0700, Jeykumar Sankaran wrote: we don't have enough reasons why the HW block looping's cannot happen in the same function. So merge them. looping's -> looping. So there are reasons one might break them out but not interesting ones? Not just yet. Once we start supporting different type of connectors such as writeback & DP and the parsing logic for the respective type of INTF grows up, we *may* want to split this up. Thanks Jeykumar S. Signed-off-by: Jeykumar Sankaran --- drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 63 ++ 1 file changed, 26 insertions(+), 37 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c index a79456c..bb59250 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c @@ -435,52 +435,39 @@ static int _dpu_rm_reserve_ctls( return 0; } -static struct dpu_rm_hw_blk *_dpu_rm_reserve_intf( - struct dpu_rm *rm, - uint32_t id, - enum dpu_hw_blk_type type) -{ - struct dpu_rm_hw_blk *iter; - struct list_head *blk_list = >hw_blks[DPU_HW_BLK_INTF]; - - /* Find the block entry in the rm, and note the reservation */ - list_for_each_entry(iter, blk_list, list) { - if (iter->hw->id != id || iter->in_use) - continue; - - trace_dpu_rm_reserve_intf(iter->hw->id, DPU_HW_BLK_INTF); - - break; - } - - /* Shouldn't happen since intfs are fixed at probe */ - if (!iter) { - DPU_ERROR("couldn't find type %d id %d\n", type, id); - return NULL; - } - - return iter; -} - -static int _dpu_rm_reserve_intf_related_hw( +static int _dpu_rm_reserve_intfs( struct dpu_rm *rm, struct dpu_crtc_state *dpu_cstate, struct dpu_encoder_hw_resources *hw_res) { - struct dpu_rm_hw_blk *blk; + struct dpu_rm_hw_blk *iter; + struct list_head *blk_list = >hw_blks[DPU_HW_BLK_INTF]; int i, num_intfs = 0; for (i = 0; i < ARRAY_SIZE(hw_res->intfs); i++) { + struct dpu_rm_hw_blk *intf_blk = NULL; + if (hw_res->intfs[i] == INTF_MODE_NONE) continue; - blk = _dpu_rm_reserve_intf(rm, i + INTF_0, - DPU_HW_BLK_INTF); - if (!blk) - return -ENAVAIL; + list_for_each_entry(iter, blk_list, list) { + if (iter->in_use) + continue; + + if (iter->hw->id == (INTF_0 + i)) { + intf_blk = iter; + break; + } + } + + if (!intf_blk) + return -EINVAL; - blk->in_use = true; - dpu_cstate->hw_intfs[num_intfs++] = to_dpu_hw_intf(blk->hw); + intf_blk->in_use = true; + dpu_cstate->hw_intfs[num_intfs++] = + to_dpu_hw_intf(intf_blk->hw); + + trace_dpu_rm_reserve_intf(intf_blk->hw->id, DPU_HW_BLK_INTF); } dpu_cstate->num_intfs = num_intfs; @@ -507,9 +494,11 @@ static int _dpu_rm_make_reservation( return ret; } - ret = _dpu_rm_reserve_intf_related_hw(rm, dpu_cstate, >hw_res); - if (ret) + ret = _dpu_rm_reserve_intfs(rm, dpu_cstate, >hw_res); + if (ret) { + DPU_ERROR("unable to find appropriate INTF\n"); Since there is only once consumer of this function, I would move this error message down into the sub-function and provide more debug information - like which INTF wasn't found. return ret; + } And you don't need to return ret in this block - you can just drop out to the bottom. return ret; } -- Jeykumar S ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
Re: [Freedreno] [PATCH v3] drm/msm: validate display and event threads
On 2018-10-09 07:24, Sean Paul wrote: On Mon, Oct 08, 2018 at 04:55:45PM -0700, Jeykumar Sankaran wrote: While creating display and event threads per crtc, validate them before setting their priorities. changes in v2: - use dev_warn (Abhinav Kumar) changes in v3: - fix compilation error Change-Id: I1dda805286df981c0f0e2b26507d089d3a21ff6c No Change-Id's please! FWIW, checkpatch.pl would have caught this and the nits I found below. It might be worth running patches through it before sending. Signed-off-by: Jeykumar Sankaran --- drivers/gpu/drm/msm/msm_drv.c | 49 ++- 1 file changed, 16 insertions(+), 33 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 4904d0d..ab1b0a9 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -553,17 +553,18 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) kthread_run(kthread_worker_fn, >disp_thread[i].worker, "crtc_commit:%d", priv->disp_thread[i].crtc_id); - ret = sched_setscheduler(priv->disp_thread[i].thread, - SCHED_FIFO, ); - if (ret) - pr_warn("display thread priority update failed: %d\n", - ret); - if (IS_ERR(priv->disp_thread[i].thread)) { dev_err(dev, "failed to create crtc_commit kthread\n"); priv->disp_thread[i].thread = NULL; + goto err_msm_uninit; } + ret = sched_setscheduler(priv->disp_thread[i].thread, +SCHED_FIFO, ); + if (ret) + dev_warn(dev, "display thread priority update failed: %d\n", Although this is wrapped, the line still exceeds 80 chars. Perhaps: dev_warn(dev, "disp_thread set priority failed %d\n", ret); I did run the checkpath.pl on this patch. Check patch usually will not complain if the >80 exceeding line is the logging string. https://01.org/linuxgraphics/gfx-docs/drm/process/coding-style.html#breaking-long-lines-and-strings https://gitlab.freedesktop.org/seanpaul/dpu-staging/blob/for-next/scripts/checkpatch.pl#L3058 Anyway, rewording will be a good idea to avoid nits! + ret); + /* initialize event thread */ priv->event_thread[i].crtc_id = priv->crtcs[i]->base.id; kthread_init_worker(>event_thread[i].worker); @@ -572,6 +573,12 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) kthread_run(kthread_worker_fn, >event_thread[i].worker, "crtc_event:%d", priv->event_thread[i].crtc_id); + if (IS_ERR(priv->event_thread[i].thread)) { + dev_err(dev, "failed to create crtc_event kthread\n"); + priv->event_thread[i].thread = NULL; + goto err_msm_uninit; + } + /** * event thread should also run at same priority as disp_thread * because it is handling frame_done events. A lower priority @@ -580,34 +587,10 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) * failure at crtc commit level. */ ret = sched_setscheduler(priv->event_thread[i].thread, - SCHED_FIFO, ); +SCHED_FIFO, ); if (ret) - pr_warn("display event thread priority update failed: %d\n", - ret); - - if (IS_ERR(priv->event_thread[i].thread)) { - dev_err(dev, "failed to create crtc_event kthread\n"); - priv->event_thread[i].thread = NULL; - } - - if ((!priv->disp_thread[i].thread) || - !priv->event_thread[i].thread) { - /* clean up previously created threads if any */ - for ( ; i >= 0; i--) { - if (priv->disp_thread[i].thread) { - kthread_stop( - priv->disp_thread[i].thread); - priv->disp_thread[i].thread = NULL; - } - - if (priv->event_thread[i].thread) { - kthread_stop( - priv->event_thread[i].thread);
[Freedreno] [PATCH 25/25] drm/msm/dpu: maintain RM init check internally
Move and maintain RM initialization flag checks from KMS to RM. Signed-off-by: Jeykumar Sankaran --- drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 6 +- drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h | 1 - drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 12 drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h | 3 +++ 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index fdc89a8..59ccc46 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -668,9 +668,7 @@ static void _dpu_kms_hw_destroy(struct dpu_kms *dpu_kms) } } - if (dpu_kms->rm_init) - dpu_rm_destroy(_kms->rm); - dpu_kms->rm_init = false; + dpu_rm_destroy(_kms->rm); if (dpu_kms->catalog) dpu_hw_catalog_deinit(dpu_kms->catalog); @@ -1085,8 +1083,6 @@ static int dpu_kms_hw_init(struct msm_kms *kms) goto power_error; } - dpu_kms->rm_init = true; - dpu_kms->hw_mdp = dpu_hw_mdptop_init(MDP_TOP, dpu_kms->mmio, dpu_kms->catalog); if (IS_ERR_OR_NULL(dpu_kms->hw_mdp)) { diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h index 66d4666..1fff795 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h @@ -140,7 +140,6 @@ struct dpu_kms { bool suspend_block; struct dpu_rm rm; - bool rm_init; struct dpu_hw_vbif *hw_vbif[VBIF_MAX]; struct dpu_hw_mdp *hw_mdp; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c index 9a63128..3452fb9 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c @@ -65,6 +65,9 @@ int dpu_rm_destroy(struct dpu_rm *rm) struct dpu_rm_hw_blk *hw_cur, *hw_nxt; enum dpu_hw_blk_type type; + if (!rm->initialized) + return 0; + for (type = 0; type < DPU_HW_BLK_MAX; type++) { list_for_each_entry_safe(hw_cur, hw_nxt, >hw_blks[type], list) { @@ -74,6 +77,8 @@ int dpu_rm_destroy(struct dpu_rm *rm) } } + rm->initialized = false; + return 0; } @@ -141,6 +146,11 @@ int dpu_rm_init(struct dpu_rm *rm, return -EINVAL; } + if (rm->initialized) { + DPU_DEBUG("RM is already initialized\n"); + return 0; + } + /* Clear, setup lists */ memset(rm, 0, sizeof(*rm)); @@ -196,6 +206,8 @@ int dpu_rm_init(struct dpu_rm *rm, } } + rm->initialized = true; + return 0; fail: diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h index 9acbeba..74e5d58 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h @@ -24,9 +24,12 @@ * struct dpu_rm - DPU dynamic hardware resource manager * @hw_blks: array of lists of hardware resources present in the system, one * list per type of hardware block + * @initialized: True, when RM is initialized with hw block list. + * False, otherwise */ struct dpu_rm { struct list_head hw_blks[DPU_HW_BLK_MAX]; + bool initialized; }; /** -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
[Freedreno] [PATCH 14/25] drm/msm/dpu: remove enc_id tagging for hw blocks
RM was using encoder id's to tag HW block's to reserve and retrieve later for display pipeline. Now that all the reserved HW blocks for a display are maintained in its crtc state, no retrieval is needed. This patch cleans up RM of encoder id tagging. Signed-off-by: Jeykumar Sankaran --- drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c| 90 +-- drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h | 28 -- 2 files changed, 36 insertions(+), 82 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c index 303f1b3..a8461b8 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c @@ -21,9 +21,6 @@ #include "dpu_encoder.h" #include "dpu_trace.h" -#define RESERVED_BY_OTHER(h, r) \ - ((h)->enc_id && (h)->enc_id != r) - /** * struct dpu_rm_requirements - Reservation requirements parameter bundle * @topology: selected topology for the display @@ -38,12 +35,13 @@ struct dpu_rm_requirements { /** * struct dpu_rm_hw_blk - hardware block tracking list member * @list: List head for list of all hardware blocks tracking items - * @enc_id:Encoder id to which this blk is binded + * @in_use: True, if the hw block is assigned to a display pipeline. + * False, otherwise * @hw:Pointer to the hardware register access object for this block */ struct dpu_rm_hw_blk { struct list_head list; - uint32_t enc_id; + bool in_use; struct dpu_hw_blk *hw; }; @@ -51,23 +49,19 @@ struct dpu_rm_hw_blk { * struct dpu_rm_hw_iter - iterator for use with dpu_rm * @hw: dpu_hw object requested, or NULL on failure * @blk: dpu_rm internal block representation. Clients ignore. Used as iterator. - * @enc_id: DRM ID of Encoder client wishes to search for, or 0 for Any Encoder * @type: Hardware Block Type client wishes to search for. */ struct dpu_rm_hw_iter { struct dpu_hw_blk *hw; struct dpu_rm_hw_blk *blk; - uint32_t enc_id; enum dpu_hw_blk_type type; }; static void _dpu_rm_init_hw_iter( struct dpu_rm_hw_iter *iter, - uint32_t enc_id, enum dpu_hw_blk_type type) { memset(iter, 0, sizeof(*iter)); - iter->enc_id = enc_id; iter->type = type; } @@ -91,16 +85,12 @@ static bool _dpu_rm_get_hw_locked(struct dpu_rm *rm, struct dpu_rm_hw_iter *i) i->blk = list_prepare_entry(i->blk, blk_list, list); list_for_each_entry_continue(i->blk, blk_list, list) { - if (i->enc_id == i->blk->enc_id) { + if (!i->blk->in_use) { i->hw = i->blk->hw; - DPU_DEBUG("found type %d id %d for enc %d\n", - i->type, i->blk->hw->id, i->enc_id); return true; } } - DPU_DEBUG("no match, type %d for enc %d\n", i->type, i->enc_id); - return false; } @@ -196,7 +186,6 @@ static int _dpu_rm_hw_blk_create( } blk->hw = hw; - blk->enc_id = 0; list_add_tail(>list, >hw_blks[type]); return 0; @@ -301,7 +290,6 @@ static bool _dpu_rm_needs_split_display(const struct msm_display_topology *top) * proposed use case requirements, incl. hardwired dependent blocks like * pingpong * @rm: dpu resource manager handle - * @enc_id: encoder id requesting for allocation * @reqs: proposed use case requirements * @lm: proposed layer mixer, function checks if lm, and all other hardwired * blocks connected to the lm (pp) is available and appropriate @@ -313,7 +301,6 @@ static bool _dpu_rm_needs_split_display(const struct msm_display_topology *top) */ static bool _dpu_rm_check_lm_and_get_connected_blks( struct dpu_rm *rm, - uint32_t enc_id, struct dpu_rm_requirements *reqs, struct dpu_rm_hw_blk *lm, struct dpu_rm_hw_blk **pp, @@ -339,13 +326,7 @@ static bool _dpu_rm_check_lm_and_get_connected_blks( } } - /* Already reserved? */ - if (RESERVED_BY_OTHER(lm, enc_id)) { - DPU_DEBUG("lm %d already reserved\n", lm_cfg->id); - return false; - } - - _dpu_rm_init_hw_iter(, 0, DPU_HW_BLK_PINGPONG); + _dpu_rm_init_hw_iter(, DPU_HW_BLK_PINGPONG); while (_dpu_rm_get_hw_locked(rm, )) { if (iter.blk->hw->id == lm_cfg->pingpong) { *pp = iter.blk; @@ -358,16 +339,10 @@ static bool _dpu_rm_check_lm_and_get_connected_blks( return false; } - if (RESERVED_BY_OTHER(*pp, enc_id)) { - DPU_DEBUG("lm %d pp %d already reserved\n", lm->h
[Freedreno] [PATCH 17/25] drm/msm/dpu: remove RM HW block list iterator
Replacing with simpler linked list helper iterators. Signed-off-by: Jeykumar Sankaran --- drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 120 + 1 file changed, 46 insertions(+), 74 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c index 1234991..a79456c 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c @@ -45,49 +45,6 @@ struct dpu_rm_hw_blk { struct dpu_hw_blk *hw; }; -/** - * struct dpu_rm_hw_iter - iterator for use with dpu_rm - * @blk: dpu_rm internal block representation. Clients ignore. Used as iterator. - * @type: Hardware Block Type client wishes to search for. - */ -struct dpu_rm_hw_iter { - struct dpu_rm_hw_blk *blk; - enum dpu_hw_blk_type type; -}; - -static void _dpu_rm_init_hw_iter( - struct dpu_rm_hw_iter *iter, - enum dpu_hw_blk_type type) -{ - memset(iter, 0, sizeof(*iter)); - iter->type = type; -} - -static bool _dpu_rm_get_hw_locked(struct dpu_rm *rm, struct dpu_rm_hw_iter *i) -{ - struct list_head *blk_list; - - if (!rm || !i || i->type >= DPU_HW_BLK_MAX) { - DPU_ERROR("invalid rm\n"); - return false; - } - - blk_list = >hw_blks[i->type]; - - if (i->blk && (>blk->list == blk_list)) { - DPU_DEBUG("attempt resume iteration past last\n"); - return false; - } - - i->blk = list_prepare_entry(i->blk, blk_list, list); - - list_for_each_entry_continue(i->blk, blk_list, list) - if (!i->blk->in_use) - return true; - - return false; -} - static void _dpu_rm_hw_destroy(enum dpu_hw_blk_type type, void *hw) { switch (type) { @@ -301,7 +258,8 @@ static bool _dpu_rm_check_lm_and_get_connected_blks( struct dpu_rm_hw_blk *primary_lm) { const struct dpu_lm_cfg *lm_cfg = to_dpu_hw_mixer(lm->hw)->cap; - struct dpu_rm_hw_iter iter; + struct dpu_rm_hw_blk *iter; + struct list_head *blk_list = >hw_blks[DPU_HW_BLK_PINGPONG]; *pp = NULL; @@ -320,10 +278,12 @@ static bool _dpu_rm_check_lm_and_get_connected_blks( } } - _dpu_rm_init_hw_iter(, DPU_HW_BLK_PINGPONG); - while (_dpu_rm_get_hw_locked(rm, )) { - if (iter.blk->hw->id == lm_cfg->pingpong) { - *pp = iter.blk; + list_for_each_entry(iter, blk_list, list) { + if (iter->in_use) + continue; + + if (iter->hw->id == lm_cfg->pingpong) { + *pp = iter; break; } } @@ -343,7 +303,8 @@ static int _dpu_rm_reserve_lms(struct dpu_rm *rm, { struct dpu_rm_hw_blk *lm[MAX_BLOCKS]; struct dpu_rm_hw_blk *pp[MAX_BLOCKS]; - struct dpu_rm_hw_iter iter_i, iter_j; + struct dpu_rm_hw_blk *iter_i, *iter_j; + struct list_head *blk_list = >hw_blks[DPU_HW_BLK_LM]; int lm_count = 0; int i, rc = 0; @@ -353,14 +314,18 @@ static int _dpu_rm_reserve_lms(struct dpu_rm *rm, } /* Find a primary mixer */ - _dpu_rm_init_hw_iter(_i, DPU_HW_BLK_LM); - while (lm_count != reqs->topology.num_lm && - _dpu_rm_get_hw_locked(rm, _i)) { + list_for_each_entry(iter_i, blk_list, list) { + if (iter_i->in_use) + continue; + + if (lm_count == reqs->topology.num_lm) + break; + memset(, 0, sizeof(lm)); memset(, 0, sizeof(pp)); lm_count = 0; - lm[lm_count] = iter_i.blk; + lm[lm_count] = iter_i; if (!_dpu_rm_check_lm_and_get_connected_blks( rm, reqs, lm[lm_count], @@ -370,19 +335,22 @@ static int _dpu_rm_reserve_lms(struct dpu_rm *rm, ++lm_count; /* Valid primary mixer found, find matching peers */ - _dpu_rm_init_hw_iter(_j, DPU_HW_BLK_LM); + list_for_each_entry(iter_j, blk_list, list) { + if (iter_j->in_use) + continue; - while (lm_count != reqs->topology.num_lm && - _dpu_rm_get_hw_locked(rm, _j)) { - if (iter_i.blk == iter_j.blk) + if (lm_count == reqs->topology.num_lm) + break; + + if (iter_i == iter_j) continue; if (!_dpu_rm_check_lm_and_get_connected_blks( - rm, reqs, iter_j.blk, - [lm_cou
[Freedreno] [PATCH 24/25] drm/msm/dpu: remove mutex locking for RM interfaces
Since HW reservations are happening through atomic_check and all the display commits are catered by a single commit thread, it is not necessary to protect the interfaces by a separate mutex. Signed-off-by: Jeykumar Sankaran --- drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 24 drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h | 2 -- 2 files changed, 26 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c index 34e09aa..9a63128 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c @@ -74,8 +74,6 @@ int dpu_rm_destroy(struct dpu_rm *rm) } } - mutex_destroy(>rm_lock); - return 0; } @@ -146,8 +144,6 @@ int dpu_rm_init(struct dpu_rm *rm, /* Clear, setup lists */ memset(rm, 0, sizeof(*rm)); - mutex_init(>rm_lock); - for (type = 0; type < DPU_HW_BLK_MAX; type++) INIT_LIST_HEAD(>hw_blks[type]); @@ -473,11 +469,7 @@ void dpu_rm_crtc_release(struct dpu_rm *rm, struct drm_crtc_state *crtc_state) { struct dpu_crtc_state *dpu_cstate = to_dpu_crtc_state(crtc_state); - mutex_lock(>rm_lock); - _dpu_rm_crtc_release_reservation(rm, dpu_cstate); - - mutex_unlock(>rm_lock); } void dpu_rm_encoder_release(struct dpu_rm *rm, @@ -485,11 +477,7 @@ void dpu_rm_encoder_release(struct dpu_rm *rm, { struct dpu_crtc_state *dpu_cstate = to_dpu_crtc_state(crtc_state); - mutex_lock(>rm_lock); - _dpu_rm_encoder_release_reservation(rm, dpu_cstate); - - mutex_unlock(>rm_lock); } int dpu_rm_crtc_reserve( @@ -506,8 +494,6 @@ int dpu_rm_crtc_reserve( DRM_DEBUG_KMS("reserving hw for crtc %d\n", crtc_state->crtc->base.id); - mutex_lock(>rm_lock); - ret = _dpu_rm_reserve_lms(rm, dpu_cstate); if (ret) { DPU_ERROR("unable to find appropriate mixers\n"); @@ -520,15 +506,11 @@ int dpu_rm_crtc_reserve( goto cleanup_on_fail; } - mutex_unlock(>rm_lock); - return ret; cleanup_on_fail: _dpu_rm_crtc_release_reservation(rm, dpu_cstate); - mutex_unlock(>rm_lock); - return ret; } @@ -547,8 +529,6 @@ int dpu_rm_encoder_reserve( DRM_DEBUG_KMS("reserving hw for enc %d\n", enc->base.id); - mutex_lock(>rm_lock); - dpu_encoder_get_hw_resources(enc, _res); ret = _dpu_rm_reserve_intfs(rm, dpu_cstate, _res); @@ -557,14 +537,10 @@ int dpu_rm_encoder_reserve( goto cleanup_on_fail; } - mutex_unlock(>rm_lock); - return ret; cleanup_on_fail: _dpu_rm_encoder_release_reservation(rm, dpu_cstate); - mutex_unlock(>rm_lock); - return ret; } diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h index 8676fa5..9acbeba 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h @@ -24,11 +24,9 @@ * struct dpu_rm - DPU dynamic hardware resource manager * @hw_blks: array of lists of hardware resources present in the system, one * list per type of hardware block - * @rm_lock: resource manager mutex */ struct dpu_rm { struct list_head hw_blks[DPU_HW_BLK_MAX]; - struct mutex rm_lock; }; /** -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
[Freedreno] [PATCH 18/25] drm/msm/dpu: merge RM interface reservation helpers
we don't have enough reasons why the HW block looping's cannot happen in the same function. So merge them. Signed-off-by: Jeykumar Sankaran --- drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 63 ++ 1 file changed, 26 insertions(+), 37 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c index a79456c..bb59250 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c @@ -435,52 +435,39 @@ static int _dpu_rm_reserve_ctls( return 0; } -static struct dpu_rm_hw_blk *_dpu_rm_reserve_intf( - struct dpu_rm *rm, - uint32_t id, - enum dpu_hw_blk_type type) -{ - struct dpu_rm_hw_blk *iter; - struct list_head *blk_list = >hw_blks[DPU_HW_BLK_INTF]; - - /* Find the block entry in the rm, and note the reservation */ - list_for_each_entry(iter, blk_list, list) { - if (iter->hw->id != id || iter->in_use) - continue; - - trace_dpu_rm_reserve_intf(iter->hw->id, DPU_HW_BLK_INTF); - - break; - } - - /* Shouldn't happen since intfs are fixed at probe */ - if (!iter) { - DPU_ERROR("couldn't find type %d id %d\n", type, id); - return NULL; - } - - return iter; -} - -static int _dpu_rm_reserve_intf_related_hw( +static int _dpu_rm_reserve_intfs( struct dpu_rm *rm, struct dpu_crtc_state *dpu_cstate, struct dpu_encoder_hw_resources *hw_res) { - struct dpu_rm_hw_blk *blk; + struct dpu_rm_hw_blk *iter; + struct list_head *blk_list = >hw_blks[DPU_HW_BLK_INTF]; int i, num_intfs = 0; for (i = 0; i < ARRAY_SIZE(hw_res->intfs); i++) { + struct dpu_rm_hw_blk *intf_blk = NULL; + if (hw_res->intfs[i] == INTF_MODE_NONE) continue; - blk = _dpu_rm_reserve_intf(rm, i + INTF_0, - DPU_HW_BLK_INTF); - if (!blk) - return -ENAVAIL; + list_for_each_entry(iter, blk_list, list) { + if (iter->in_use) + continue; + + if (iter->hw->id == (INTF_0 + i)) { + intf_blk = iter; + break; + } + } + + if (!intf_blk) + return -EINVAL; - blk->in_use = true; - dpu_cstate->hw_intfs[num_intfs++] = to_dpu_hw_intf(blk->hw); + intf_blk->in_use = true; + dpu_cstate->hw_intfs[num_intfs++] = + to_dpu_hw_intf(intf_blk->hw); + + trace_dpu_rm_reserve_intf(intf_blk->hw->id, DPU_HW_BLK_INTF); } dpu_cstate->num_intfs = num_intfs; @@ -507,9 +494,11 @@ static int _dpu_rm_make_reservation( return ret; } - ret = _dpu_rm_reserve_intf_related_hw(rm, dpu_cstate, >hw_res); - if (ret) + ret = _dpu_rm_reserve_intfs(rm, dpu_cstate, >hw_res); + if (ret) { + DPU_ERROR("unable to find appropriate INTF\n"); return ret; + } return ret; } -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
[Freedreno] [PATCH 15/25] drm/msm/dpu: avoid redundant hw blk reference
Get rid of hw block pointer in RM iter as we can access the same through dpu_hw_blk. Signed-off-by: Jeykumar Sankaran --- drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 10 ++ 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c index a8461b8..3a92a3e 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c @@ -47,12 +47,10 @@ struct dpu_rm_hw_blk { /** * struct dpu_rm_hw_iter - iterator for use with dpu_rm - * @hw: dpu_hw object requested, or NULL on failure * @blk: dpu_rm internal block representation. Clients ignore. Used as iterator. * @type: Hardware Block Type client wishes to search for. */ struct dpu_rm_hw_iter { - struct dpu_hw_blk *hw; struct dpu_rm_hw_blk *blk; enum dpu_hw_blk_type type; }; @@ -74,7 +72,6 @@ static bool _dpu_rm_get_hw_locked(struct dpu_rm *rm, struct dpu_rm_hw_iter *i) return false; } - i->hw = NULL; blk_list = >hw_blks[i->type]; if (i->blk && (>blk->list == blk_list)) { @@ -84,12 +81,9 @@ static bool _dpu_rm_get_hw_locked(struct dpu_rm *rm, struct dpu_rm_hw_iter *i) i->blk = list_prepare_entry(i->blk, blk_list, list); - list_for_each_entry_continue(i->blk, blk_list, list) { - if (!i->blk->in_use) { - i->hw = i->blk->hw; + list_for_each_entry_continue(i->blk, blk_list, list) + if (!i->blk->in_use) return true; - } - } return false; } -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
[Freedreno] [PATCH 12/25] drm/msm/dpu: remove mode_set_complete
This flag was introduced as a fix to notify modeset complete when hw reservations were happening in both atomic_check and atomic_commit paths. Now that we are reserving only in atomic_check, we can get rid of this flag. Signed-off-by: Jeykumar Sankaran --- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 19 +++ 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index dd482ca..468b8fd0 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -167,7 +167,6 @@ enum dpu_enc_rc_states { * clks and resources after IDLE_TIMEOUT time. * @vsync_event_work: worker to handle vsync event for autorefresh * @topology: topology of the display - * @mode_set_complete: flag to indicate modeset completion * @idle_timeout: idle timeout duration in milliseconds */ struct dpu_encoder_virt { @@ -204,7 +203,6 @@ struct dpu_encoder_virt { struct kthread_delayed_work delayed_off_work; struct kthread_work vsync_event_work; struct msm_display_topology topology; - bool mode_set_complete; u32 idle_timeout; }; @@ -636,18 +634,9 @@ static int dpu_encoder_virt_atomic_check( topology = dpu_encoder_get_topology(dpu_enc, dpu_kms, adj_mode); - 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(_kms->rm, drm_enc, crtc_state, -topology, false); - dpu_enc->mode_set_complete = false; - } - } + if (!ret && drm_atomic_crtc_needs_modeset(crtc_state)) + ret = dpu_rm_reserve(_kms->rm, drm_enc, crtc_state, +topology, false); if (!ret) drm_mode_set_crtcinfo(adj_mode, 0); @@ -1060,8 +1049,6 @@ static void dpu_encoder_virt_mode_set(struct drm_encoder *drm_enc, phys->ops.mode_set(phys, mode, adj_mode); } } - - dpu_enc->mode_set_complete = true; } static void _dpu_encoder_virt_enable_helper(struct drm_encoder *drm_enc) -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
[Freedreno] [PATCH 20/25] drm/msm/dpu: refine layer mixer reservations
Validate layer mixer pairs for compatibility before retrieving the connected pingpong blocks. Signed-off-by: Jeykumar Sankaran --- drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 61 ++ 1 file changed, 17 insertions(+), 44 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c index 85a0fe2..f794d13 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c @@ -235,61 +235,32 @@ static bool _dpu_rm_needs_split_display(const struct dpu_crtc_state *dpu_cstate) } /** - * _dpu_rm_check_lm_and_get_connected_blks - check if proposed layer mixer meets - * proposed use case requirements, incl. hardwired dependent blocks like - * pingpong + * _dpu_rm_get_connected_pp - retrieve hardwired pingpong block * @rm: dpu resource manager handle * @lm: proposed layer mixer, function checks if lm, and all other hardwired - * blocks connected to the lm (pp) is available and appropriate - * @pp: output parameter, pingpong block attached to the layer mixer. - * NULL if pp was not available, or not matching requirements. - * @primary_lm: if non-null, this function check if lm is compatible primary_lm - * as well as satisfying all other requirements - * @Return: true if lm matches all requirements, false otherwise + * @Return: handle to ping pong rm block */ -static bool _dpu_rm_check_lm_and_get_connected_blks( - struct dpu_rm *rm, - struct dpu_rm_hw_blk *lm, - struct dpu_rm_hw_blk **pp, - struct dpu_rm_hw_blk *primary_lm) +static struct dpu_rm_hw_blk * +_dpu_rm_get_connected_pp(struct dpu_rm *rm, struct dpu_rm_hw_blk *lm) { const struct dpu_lm_cfg *lm_cfg = to_dpu_hw_mixer(lm->hw)->cap; - struct dpu_rm_hw_blk *iter; struct list_head *blk_list = >hw_blks[DPU_HW_BLK_PINGPONG]; - - *pp = NULL; - - DPU_DEBUG("check lm %d pp %d\n", - lm_cfg->id, lm_cfg->pingpong); - - /* Check if this layer mixer is a peer of the proposed primary LM */ - if (primary_lm) { - const struct dpu_lm_cfg *prim_lm_cfg = - to_dpu_hw_mixer(primary_lm->hw)->cap; - - if (!test_bit(lm_cfg->id, _lm_cfg->lm_pair_mask)) { - DPU_DEBUG("lm %d not peer of lm %d\n", lm_cfg->id, - prim_lm_cfg->id); - return false; - } - } + struct dpu_rm_hw_blk *iter, *pp = NULL; list_for_each_entry(iter, blk_list, list) { if (iter->in_use) continue; if (iter->hw->id == lm_cfg->pingpong) { - *pp = iter; + pp = iter; break; } } - if (!*pp) { - DPU_ERROR("failed to get pp on lm %d\n", lm_cfg->pingpong); - return false; - } + if (!pp) + DPU_ERROR("failed to get pp on lm %d\n", lm->hw->id); - return true; + return pp; } static int _dpu_rm_reserve_lms(struct dpu_rm *rm, @@ -315,15 +286,15 @@ static int _dpu_rm_reserve_lms(struct dpu_rm *rm, lm_count = 0; lm[lm_count] = iter_i; - - if (!_dpu_rm_check_lm_and_get_connected_blks( - rm, lm[lm_count], [lm_count], NULL)) - continue; + pp[lm_count] = _dpu_rm_get_connected_pp(rm, iter_i); ++lm_count; /* Valid primary mixer found, find matching peers */ list_for_each_entry(iter_j, blk_list, list) { + const struct dpu_lm_cfg *prim_lm_cfg = + to_dpu_hw_mixer(iter_i->hw)->cap; + if (iter_j->in_use) continue; @@ -333,11 +304,13 @@ static int _dpu_rm_reserve_lms(struct dpu_rm *rm, if (iter_i == iter_j) continue; - if (!_dpu_rm_check_lm_and_get_connected_blks( - rm, iter_j, [lm_count], iter_i)) + if (!test_bit(iter_j->hw->id, + _lm_cfg->lm_pair_mask)) continue; lm[lm_count] = iter_j; + pp[lm_count] = _dpu_rm_get_connected_pp(rm, iter_j); + ++lm_count; } } -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
[Freedreno] [PATCH 19/25] drm/msm/dpu: remove msm_display_topology
msm_display_topology was used for providing HW block layout of the pipeline for a specific display topology. We already got rid of its usage from DSI driver. In DPU, it was used to provide the details on HW blocks while reserving resources. Since we can use the crtc state used for storing the assigned HW blocks for providing the info, we can conveniently get rid of this structure. Signed-off-by: Jeykumar Sankaran --- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 29 -- drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 82 - drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h | 4 +- drivers/gpu/drm/msm/msm_drv.h | 12 - 4 files changed, 33 insertions(+), 94 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index dd17528..5d501c8 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -166,7 +166,6 @@ enum dpu_enc_rc_states { * @delayed_off_work: delayed worker to schedule disabling of * clks and resources after IDLE_TIMEOUT time. * @vsync_event_work: worker to handle vsync event for autorefresh - * @topology: topology of the display * @idle_timeout: idle timeout duration in milliseconds */ struct dpu_encoder_virt { @@ -202,7 +201,6 @@ struct dpu_encoder_virt { enum dpu_enc_rc_states rc_state; struct kthread_delayed_work delayed_off_work; struct kthread_work vsync_event_work; - struct msm_display_topology topology; u32 idle_timeout; }; @@ -557,25 +555,19 @@ static void _dpu_encoder_adjust_mode(struct drm_connector *connector, } } -static struct msm_display_topology dpu_encoder_get_topology( +static void _dpu_encoder_get_topology( struct dpu_encoder_virt *dpu_enc, - struct dpu_kms *dpu_kms, + struct drm_crtc_state *crtc_state, struct drm_display_mode *mode) { - struct msm_display_topology topology; - int i, intf_count = 0; - - for (i = 0; i < MAX_PHYS_ENCODERS_PER_VIRTUAL; i++) - if (dpu_enc->phys_encs[i]) - intf_count++; + struct dpu_crtc_state *dpu_cstate = to_dpu_crtc_state(crtc_state); /* User split topology for width > 1080 */ - topology.num_lm = (mode->vdisplay > MAX_VDISPLAY_SPLIT) ? 2 : 1; - topology.num_enc = 0; - topology.num_intf = intf_count; - - return topology; + dpu_cstate->num_mixers = (mode->vdisplay > MAX_VDISPLAY_SPLIT) ? 2 : 1; + dpu_cstate->num_ctls = dpu_enc->num_phys_encs; + dpu_cstate->num_intfs = dpu_enc->num_phys_encs; } + static int dpu_encoder_virt_atomic_check( struct drm_encoder *drm_enc, struct drm_crtc_state *crtc_state, @@ -586,7 +578,6 @@ static int dpu_encoder_virt_atomic_check( struct dpu_kms *dpu_kms; const struct drm_display_mode *mode; struct drm_display_mode *adj_mode; - struct msm_display_topology topology; int i = 0; int ret = 0; @@ -632,11 +623,9 @@ static int dpu_encoder_virt_atomic_check( } } - topology = dpu_encoder_get_topology(dpu_enc, dpu_kms, adj_mode); - + _dpu_encoder_get_topology(dpu_enc, crtc_state, adj_mode); if (!ret && drm_atomic_crtc_needs_modeset(crtc_state)) - ret = dpu_rm_reserve(_kms->rm, drm_enc, crtc_state, -topology); + ret = dpu_rm_reserve(_kms->rm, drm_enc, crtc_state); if (!ret) drm_mode_set_crtcinfo(adj_mode, 0); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c index bb59250..85a0fe2 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c @@ -23,11 +23,9 @@ /** * struct dpu_rm_requirements - Reservation requirements parameter bundle - * @topology: selected topology for the display * @hw_res: Hardware resources required as reported by the encoders */ struct dpu_rm_requirements { - struct msm_display_topology topology; struct dpu_encoder_hw_resources hw_res; }; @@ -231,9 +229,9 @@ int dpu_rm_init(struct dpu_rm *rm, return rc; } -static bool _dpu_rm_needs_split_display(const struct msm_display_topology *top) +static bool _dpu_rm_needs_split_display(const struct dpu_crtc_state *dpu_cstate) { - return top->num_intf > 1; + return dpu_cstate->num_intfs > 1; } /** @@ -241,7 +239,6 @@ static bool _dpu_rm_needs_split_display(const struct msm_display_topology *top) * proposed use case requirements, incl. hardwired dependent blocks like * pingpong * @rm: dpu resource manager handle - * @reqs: proposed use ca
[Freedreno] [PATCH 22/25] drm/msm/dpu: make crtc and encoder specific HW reservation
Instead of letting encoder make a centralized reservation for all of its display DRM components, this path splits the responsibility between CRTC and Encoder, each requesting RM for the HW mapping of its own domain. Signed-off-by: Jeykumar Sankaran --- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c| 31 + drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 14 ++ drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 69 - drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h | 36 +++ 4 files changed, 119 insertions(+), 31 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index 0625f56..0536b8a 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 LEFT_MIXER 0 #define RIGHT_MIXER 1 +#define MAX_VDISPLAY_SPLIT 1080 + static inline int _dpu_crtc_get_mixer_width(struct dpu_crtc_state *cstate, struct drm_display_mode *mode) { @@ -448,6 +450,7 @@ static void _dpu_crtc_setup_lm_bounds(struct drm_crtc *crtc, for (i = 0; i < cstate->num_mixers; i++) { struct drm_rect *r = >lm_bounds[i]; + r->x1 = crtc_split_width * i; r->y1 = 0; r->x2 = r->x1 + crtc_split_width; @@ -885,6 +888,7 @@ static void dpu_crtc_disable(struct drm_crtc *crtc) struct drm_display_mode *mode; struct drm_encoder *encoder; struct msm_drm_private *priv; + struct dpu_kms *dpu_kms; unsigned long flags; if (!crtc || !crtc->dev || !crtc->dev->dev_private || !crtc->state) { @@ -895,6 +899,7 @@ static void dpu_crtc_disable(struct drm_crtc *crtc) cstate = to_dpu_crtc_state(crtc->state); mode = >base.adjusted_mode; priv = crtc->dev->dev_private; + dpu_kms = to_dpu_kms(priv->kms); DRM_DEBUG_KMS("crtc%d\n", crtc->base.id); @@ -953,6 +958,8 @@ static void dpu_crtc_disable(struct drm_crtc *crtc) crtc->state->event = NULL; spin_unlock_irqrestore(>dev->event_lock, flags); } + + dpu_rm_crtc_release(_kms->rm, crtc->state); } static void dpu_crtc_enable(struct drm_crtc *crtc, @@ -1004,6 +1011,21 @@ struct plane_state { u32 pipe_id; }; +static void _dpu_crtc_get_topology( + struct drm_crtc_state *crtc_state, + struct drm_display_mode *mode) +{ + struct dpu_crtc_state *dpu_cstate = to_dpu_crtc_state(crtc_state); + + dpu_cstate->num_mixers = (mode->vdisplay > MAX_VDISPLAY_SPLIT) ? 2 : 1; + + /** +* encoder->atomic_check is invoked before crtc->atomic_check. +* so dpu_cstate->num_intfs should have a non-zero value. +*/ + dpu_cstate->num_ctls = dpu_cstate->num_intfs; +} + static int dpu_crtc_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *state) { @@ -1014,6 +1036,8 @@ static int dpu_crtc_atomic_check(struct drm_crtc *crtc, const struct drm_plane_state *pstate; struct drm_plane *plane; struct drm_display_mode *mode; + struct msm_drm_private *priv; + struct dpu_kms *dpu_kms; int cnt = 0, rc = 0, mixer_width, i, z_pos; @@ -1039,6 +1063,9 @@ static int dpu_crtc_atomic_check(struct drm_crtc *crtc, goto end; } + priv = crtc->dev->dev_private; + dpu_kms = to_dpu_kms(priv->kms); + mode = >adjusted_mode; DPU_DEBUG("%s: check", dpu_crtc->name); @@ -1229,6 +1256,10 @@ static int dpu_crtc_atomic_check(struct drm_crtc *crtc, } } + _dpu_crtc_get_topology(state, mode); + if (drm_atomic_crtc_needs_modeset(state)) + rc = dpu_rm_crtc_reserve(_kms->rm, state); + end: kfree(pstates); return rc; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index 5d501c8..ce66309 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -67,8 +67,6 @@ #define IDLE_SHORT_TIMEOUT 1 -#define MAX_VDISPLAY_SPLIT 1080 - /** * enum dpu_enc_rc_events - events for resource control state machine * @DPU_ENC_RC_EVENT_KICKOFF: @@ -557,14 +555,10 @@ static void _dpu_encoder_adjust_mode(struct drm_connector *connector, static void _dpu_encoder_get_topology( struct dpu_encoder_virt *dpu_enc, - struct drm_crtc_state *crtc_state, - struct drm_display_mode *mode) + struct drm_crtc_state *crtc_state) { struct dpu_crtc_state *dpu_cstate = to_dpu_crtc_state(crtc_state); - /* User split topology for width > 1080 */ - dpu_cstate-
[Freedreno] [PATCH 21/25] drm/msm/dpu: merge RM reservation helpers
We cleaned up RM reserve api's enough to get rid of most of its unwanted checks and release handlers. To improve further the readability of the function, merging down the individual HW type allocators into one function. Signed-off-by: Jeykumar Sankaran --- drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 73 +++--- 1 file changed, 24 insertions(+), 49 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c index f794d13..5304597 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c @@ -22,15 +22,6 @@ #include "dpu_trace.h" /** - * struct dpu_rm_requirements - Reservation requirements parameter bundle - * @hw_res: Hardware resources required as reported by the encoders - */ -struct dpu_rm_requirements { - struct dpu_encoder_hw_resources hw_res; -}; - - -/** * struct dpu_rm_hw_blk - hardware block tracking list member * @list: List head for list of all hardware blocks tracking items * @in_use: True, if the hw block is assigned to a display pipeline. @@ -427,41 +418,6 @@ static int _dpu_rm_reserve_intfs( return 0; } -static int _dpu_rm_make_reservation( - struct dpu_rm *rm, - struct dpu_crtc_state *dpu_cstate, - struct dpu_rm_requirements *reqs) -{ - int ret; - - ret = _dpu_rm_reserve_lms(rm, dpu_cstate); - if (ret) { - DPU_ERROR("unable to find appropriate mixers\n"); - return ret; - } - - ret = _dpu_rm_reserve_ctls(rm, dpu_cstate); - if (ret) { - DPU_ERROR("unable to find appropriate CTL\n"); - return ret; - } - - ret = _dpu_rm_reserve_intfs(rm, dpu_cstate, >hw_res); - if (ret) { - DPU_ERROR("unable to find appropriate INTF\n"); - return ret; - } - - return ret; -} - -static void _dpu_rm_populate_requirements( - struct drm_encoder *enc, - struct dpu_rm_requirements *reqs) -{ - dpu_encoder_get_hw_resources(enc, >hw_res); -} - static int _dpu_rm_release_hw(struct dpu_rm *rm, enum dpu_hw_blk_type type, int id) { @@ -535,7 +491,7 @@ int dpu_rm_reserve( struct drm_encoder *enc, struct drm_crtc_state *crtc_state) { - struct dpu_rm_requirements reqs; + struct dpu_encoder_hw_resources hw_res; struct dpu_crtc_state *dpu_cstate = to_dpu_crtc_state(crtc_state); int ret; @@ -548,14 +504,33 @@ int dpu_rm_reserve( mutex_lock(>rm_lock); - _dpu_rm_populate_requirements(enc, ); + dpu_encoder_get_hw_resources(enc, _res); - ret = _dpu_rm_make_reservation(rm, dpu_cstate, ); + ret = _dpu_rm_reserve_lms(rm, dpu_cstate); if (ret) { - DPU_ERROR("failed to reserve hw resources: %d\n", ret); - _dpu_rm_release_reservation(rm, dpu_cstate); + DPU_ERROR("unable to find appropriate mixers\n"); + goto cleanup_on_fail; } + ret = _dpu_rm_reserve_ctls(rm, dpu_cstate); + if (ret) { + DPU_ERROR("unable to find appropriate CTL\n"); + goto cleanup_on_fail; + } + + ret = _dpu_rm_reserve_intfs(rm, dpu_cstate, _res); + if (ret) { + DPU_ERROR("unable to find appropriate INTF\n"); + goto cleanup_on_fail; + } + + mutex_unlock(>rm_lock); + + return ret; + +cleanup_on_fail: + _dpu_rm_release_reservation(rm, dpu_cstate); + mutex_unlock(>rm_lock); return ret; -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
[Freedreno] [PATCH 16/25] drm/msm/dpu: clean up test_only flag for RM reservation
Encoder uses test_only flag to differentiate RM reservations invoked from atomic check and atomic_commit phases. After reserving the HW blocks, if test_only was set, RM releases the reservation. Retains them if not. Since we got rid of RM reserve call from atomic_commit path, get rid of this flag. Signed-off-by: Jeykumar Sankaran --- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 2 +- drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 13 +++-- drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h | 4 +--- 3 files changed, 5 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index 468b8fd0..dd17528 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -636,7 +636,7 @@ static int dpu_encoder_virt_atomic_check( if (!ret && drm_atomic_crtc_needs_modeset(crtc_state)) ret = dpu_rm_reserve(_kms->rm, drm_enc, crtc_state, -topology, false); +topology); if (!ret) drm_mode_set_crtcinfo(adj_mode, 0); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c index 3a92a3e..1234991 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c @@ -631,8 +631,7 @@ int dpu_rm_reserve( struct dpu_rm *rm, struct drm_encoder *enc, struct drm_crtc_state *crtc_state, - struct msm_display_topology topology, - bool test_only) + struct msm_display_topology topology) { struct dpu_rm_requirements reqs; struct dpu_crtc_state *dpu_cstate = to_dpu_crtc_state(crtc_state); @@ -642,8 +641,8 @@ int dpu_rm_reserve( if (!drm_atomic_crtc_needs_modeset(crtc_state)) return 0; - DRM_DEBUG_KMS("reserving hw for enc %d crtc %d test_only %d\n", - enc->base.id, crtc_state->crtc->base.id, test_only); + DRM_DEBUG_KMS("reserving hw for enc %d crtc %d\n", + enc->base.id, crtc_state->crtc->base.id); mutex_lock(>rm_lock); @@ -657,13 +656,7 @@ int dpu_rm_reserve( if (ret) { DPU_ERROR("failed to reserve hw resources: %d\n", ret); _dpu_rm_release_reservation(rm, dpu_cstate); - } else if (test_only) { -/* test_only: test the reservation and then undo */ - DPU_DEBUG("test_only: discard test [enc: %d]\n", - enc->base.id); - _dpu_rm_release_reservation(rm, dpu_cstate); } - end: mutex_unlock(>rm_lock); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h index 7ac1553..415eeec 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h @@ -63,14 +63,12 @@ int dpu_rm_init(struct dpu_rm *rm, * @drm_enc: DRM Encoder handle * @crtc_state: Proposed Atomic DRM CRTC State handle * @topology: Pointer to topology info for the display - * @test_only: Atomic-Test phase, discard results (unless property overrides) * @Return: 0 on Success otherwise -ERROR */ int dpu_rm_reserve(struct dpu_rm *rm, struct drm_encoder *drm_enc, struct drm_crtc_state *crtc_state, - struct msm_display_topology topology, - bool test_only); + struct msm_display_topology topology); /** * dpu_rm_release - Given the encoder for the display chain, release any -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
[Freedreno] [PATCH 10/25] drm/msm/dpu: maintain hw_mdp in kms
hw_mdp block is common for displays. No need to reserve per display. Signed-off-by: Jeykumar Sankaran --- drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 7 ++- drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 20 drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h | 10 -- 3 files changed, 6 insertions(+), 31 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index 8309850..fdc89a8 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -689,6 +689,10 @@ static void _dpu_kms_hw_destroy(struct dpu_kms *dpu_kms) devm_iounmap(_kms->pdev->dev, dpu_kms->vbif[VBIF_RT]); dpu_kms->vbif[VBIF_RT] = NULL; + if (dpu_kms->hw_mdp) + dpu_hw_mdp_destroy(dpu_kms->hw_mdp); + dpu_kms->hw_mdp = NULL; + if (dpu_kms->mmio) devm_iounmap(_kms->pdev->dev, dpu_kms->mmio); dpu_kms->mmio = NULL; @@ -1083,7 +1087,8 @@ static int dpu_kms_hw_init(struct msm_kms *kms) dpu_kms->rm_init = true; - dpu_kms->hw_mdp = dpu_rm_get_mdp(_kms->rm); + dpu_kms->hw_mdp = dpu_hw_mdptop_init(MDP_TOP, dpu_kms->mmio, +dpu_kms->catalog); if (IS_ERR_OR_NULL(dpu_kms->hw_mdp)) { rc = PTR_ERR(dpu_kms->hw_mdp); if (!dpu_kms->hw_mdp) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c index 24fc1c7..561120d 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c @@ -63,11 +63,6 @@ struct dpu_rm_hw_iter { enum dpu_hw_blk_type type; }; -struct dpu_hw_mdp *dpu_rm_get_mdp(struct dpu_rm *rm) -{ - return rm->hw_mdp; -} - static void _dpu_rm_init_hw_iter( struct dpu_rm_hw_iter *iter, uint32_t enc_id, @@ -151,9 +146,6 @@ int dpu_rm_destroy(struct dpu_rm *rm) } } - dpu_hw_mdp_destroy(rm->hw_mdp); - rm->hw_mdp = NULL; - mutex_destroy(>rm_lock); return 0; @@ -168,11 +160,8 @@ static int _dpu_rm_hw_blk_create( void *hw_catalog_info) { struct dpu_rm_hw_blk *blk; - struct dpu_hw_mdp *hw_mdp; void *hw; - hw_mdp = rm->hw_mdp; - switch (type) { case DPU_HW_BLK_LM: hw = dpu_hw_lm_init(id, mmio, cat); @@ -236,15 +225,6 @@ int dpu_rm_init(struct dpu_rm *rm, for (type = 0; type < DPU_HW_BLK_MAX; type++) INIT_LIST_HEAD(>hw_blks[type]); - /* Some of the sub-blocks require an mdptop to be created */ - rm->hw_mdp = dpu_hw_mdptop_init(MDP_TOP, mmio, cat); - if (IS_ERR_OR_NULL(rm->hw_mdp)) { - rc = PTR_ERR(rm->hw_mdp); - rm->hw_mdp = NULL; - DPU_ERROR("failed: mdp hw not available\n"); - goto fail; - } - /* Interrogate HW catalog and create tracking items for hw blocks */ for (i = 0; i < cat->mixer_count; i++) { struct dpu_lm_cfg *lm = >mixer[i]; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h index c7e3b2b..7ac1553 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h @@ -24,13 +24,11 @@ * struct dpu_rm - DPU dynamic hardware resource manager * @hw_blks: array of lists of hardware resources present in the system, one * list per type of hardware block - * @hw_mdp: hardware object for mdp_top * @lm_max_width: cached layer mixer maximum width * @rm_lock: resource manager mutex */ struct dpu_rm { struct list_head hw_blks[DPU_HW_BLK_MAX]; - struct dpu_hw_mdp *hw_mdp; uint32_t lm_max_width; struct mutex rm_lock; }; @@ -82,12 +80,4 @@ int dpu_rm_reserve(struct dpu_rm *rm, * @Return: 0 on Success otherwise -ERROR */ void dpu_rm_release(struct dpu_rm *rm, struct drm_crtc_state *crtc_state); - -/** - * dpu_rm_get_mdp - Retrieve HW block for MDP TOP. - * This is never reserved, and is usable by any display. - * @rm: DPU Resource Manager handle - * @Return: Pointer to hw block or NULL - */ -struct dpu_hw_mdp *dpu_rm_get_mdp(struct dpu_rm *rm); #endif /* __DPU_RM_H__ */ -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
[Freedreno] [PATCH 03/25] drm/msm/dpu: remove dev from RM
Not used. Remove from RM. Signed-off-by: Jeykumar Sankaran --- drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 3 +-- drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 7 ++- drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h | 6 +- 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index 0a683e6..8309850 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -1075,8 +1075,7 @@ static int dpu_kms_hw_init(struct msm_kms *kms) goto power_error; } - rc = dpu_rm_init(_kms->rm, dpu_kms->catalog, dpu_kms->mmio, - dpu_kms->dev); + rc = dpu_rm_init(_kms->rm, dpu_kms->catalog, dpu_kms->mmio); if (rc) { DPU_ERROR("rm init failed: %d\n", rc); goto power_error; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c index 36a929b..5ce89b9 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c @@ -224,13 +224,12 @@ static int _dpu_rm_hw_blk_create( int dpu_rm_init(struct dpu_rm *rm, struct dpu_mdss_cfg *cat, - void __iomem *mmio, - struct drm_device *dev) + void __iomem *mmio) { int rc, i; enum dpu_hw_blk_type type; - if (!rm || !cat || !mmio || !dev) { + if (!rm || !cat || !mmio) { DPU_ERROR("invalid kms\n"); return -EINVAL; } @@ -243,8 +242,6 @@ int dpu_rm_init(struct dpu_rm *rm, for (type = 0; type < DPU_HW_BLK_MAX; type++) INIT_LIST_HEAD(>hw_blks[type]); - rm->dev = dev; - /* Some of the sub-blocks require an mdptop to be created */ rm->hw_mdp = dpu_hw_mdptop_init(MDP_TOP, mmio, cat); if (IS_ERR_OR_NULL(rm->hw_mdp)) { diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h index 0dd3c21..f41fd19 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h @@ -22,7 +22,6 @@ /** * struct dpu_rm - DPU dynamic hardware resource manager - * @dev: device handle for event logging purposes * @hw_blks: array of lists of hardware resources present in the system, one * list per type of hardware block * @hw_mdp: hardware object for mdp_top @@ -30,7 +29,6 @@ * @rm_lock: resource manager mutex */ struct dpu_rm { - struct drm_device *dev; struct list_head hw_blks[DPU_HW_BLK_MAX]; struct dpu_hw_mdp *hw_mdp; uint32_t lm_max_width; @@ -63,13 +61,11 @@ struct dpu_rm_hw_iter { * @rm: DPU Resource Manager handle * @cat: Pointer to hardware catalog * @mmio: mapped register io address of MDP - * @dev: device handle for event logging purposes * @Return: 0 on Success otherwise -ERROR */ int dpu_rm_init(struct dpu_rm *rm, struct dpu_mdss_cfg *cat, - void __iomem *mmio, - struct drm_device *dev); + void __iomem *mmio); /** * dpu_rm_destroy - Free all memory allocated by dpu_rm_init -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
[Freedreno] [PATCH 23/25] drm/msm/dpu: remove max_width from RM
Unused variable in the driver. Signed-off-by: Jeykumar Sankaran --- drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 12 drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h | 2 -- 2 files changed, 14 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c index 901b1fc..34e09aa 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c @@ -166,18 +166,6 @@ int dpu_rm_init(struct dpu_rm *rm, DPU_ERROR("failed: lm hw not available\n"); goto fail; } - - if (!rm->lm_max_width) { - rm->lm_max_width = lm->sblk->maxwidth; - } else if (rm->lm_max_width != lm->sblk->maxwidth) { - /* -* Don't expect to have hw where lm max widths differ. -* If found, take the min. -*/ - DPU_ERROR("unsupported: lm maxwidth differs\n"); - if (rm->lm_max_width > lm->sblk->maxwidth) - rm->lm_max_width = lm->sblk->maxwidth; - } } for (i = 0; i < cat->pingpong_count; i++) { diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h index 0b1deb0..8676fa5 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h @@ -24,12 +24,10 @@ * struct dpu_rm - DPU dynamic hardware resource manager * @hw_blks: array of lists of hardware resources present in the system, one * list per type of hardware block - * @lm_max_width: cached layer mixer maximum width * @rm_lock: resource manager mutex */ struct dpu_rm { struct list_head hw_blks[DPU_HW_BLK_MAX]; - uint32_t lm_max_width; struct mutex rm_lock; }; -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
[Freedreno] [PATCH 04/25] drm/msm/dpu: clean up dpu_rm_check_property_topctl declaration
Definition was removed already. Clean up header declaration. Signed-off-by: Jeykumar Sankaran --- drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h | 8 1 file changed, 8 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h index f41fd19..eb6a6ac 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h @@ -136,12 +136,4 @@ void dpu_rm_init_hw_iter( * @Return: true on match found, false on no match found */ bool dpu_rm_get_hw(struct dpu_rm *rm, struct dpu_rm_hw_iter *iter); - -/** - * dpu_rm_check_property_topctl - validate property bitmask before it is set - * @val: user's proposed topology control bitmask - * @Return: 0 on success or error - */ -int dpu_rm_check_property_topctl(uint64_t val); - #endif /* __DPU_RM_H__ */ -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
[Freedreno] [PATCH 02/25] drm/msm/dpu: avoid tracking reservations in RM
RM was equipped with reservation tracking structure RSVP to cache HW reservation of displays for certain clients where atomic_checks (atomic commit with TEST_ONLY) for all the displays are called before their respective atomic_commits. Since DPU doesn't support the sequence anymore, clean up the support from RM. Replace rsvp with the corresponding encoder id to tag the HW blocks reserved. Signed-off-by: Jeykumar Sankaran --- drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 284 + drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h | 4 - 2 files changed, 43 insertions(+), 245 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c index bdb1177..36a929b 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c @@ -21,8 +21,8 @@ #include "dpu_encoder.h" #include "dpu_trace.h" -#define RESERVED_BY_OTHER(h, r) \ - ((h)->rsvp && ((h)->rsvp->enc_id != (r)->enc_id)) +#define RESERVED_BY_OTHER(h, r) \ + ((h)->enc_id && (h)->enc_id != r) /** * struct dpu_rm_requirements - Reservation requirements parameter bundle @@ -34,85 +34,23 @@ struct dpu_rm_requirements { struct dpu_encoder_hw_resources hw_res; }; -/** - * struct dpu_rm_rsvp - Use Case Reservation tagging structure - * Used to tag HW blocks as reserved by a CRTC->Encoder->Connector chain - * By using as a tag, rather than lists of pointers to HW blocks used - * we can avoid some list management since we don't know how many blocks - * of each type a given use case may require. - * @list: List head for list of all reservations - * @seq: Global RSVP sequence number for debugging, especially for - * differentiating differenct allocations for same encoder. - * @enc_id:Reservations are tracked by Encoder DRM object ID. - * CRTCs may be connected to multiple Encoders. - * An encoder or connector id identifies the display path. - */ -struct dpu_rm_rsvp { - struct list_head list; - uint32_t seq; - uint32_t enc_id; -}; /** * struct dpu_rm_hw_blk - hardware block tracking list member * @list: List head for list of all hardware blocks tracking items - * @rsvp: Pointer to use case reservation if reserved by a client - * @rsvp_nxt: Temporary pointer used during reservation to the incoming - * request. Will be swapped into rsvp if proposal is accepted * @type: Type of hardware block this structure tracks * @id:Hardware ID number, within it's own space, ie. LM_X - * @catalog: Pointer to the hardware catalog entry for this block + * @enc_id:Encoder id to which this blk is binded * @hw:Pointer to the hardware register access object for this block */ struct dpu_rm_hw_blk { struct list_head list; - struct dpu_rm_rsvp *rsvp; - struct dpu_rm_rsvp *rsvp_nxt; enum dpu_hw_blk_type type; uint32_t id; + uint32_t enc_id; struct dpu_hw_blk *hw; }; -/** - * dpu_rm_dbg_rsvp_stage - enum of steps in making reservation for event logging - */ -enum dpu_rm_dbg_rsvp_stage { - DPU_RM_STAGE_BEGIN, - DPU_RM_STAGE_AFTER_CLEAR, - DPU_RM_STAGE_AFTER_RSVPNEXT, - DPU_RM_STAGE_FINAL -}; - -static void _dpu_rm_print_rsvps( - struct dpu_rm *rm, - enum dpu_rm_dbg_rsvp_stage stage) -{ - struct dpu_rm_rsvp *rsvp; - struct dpu_rm_hw_blk *blk; - enum dpu_hw_blk_type type; - - DPU_DEBUG("%d\n", stage); - - list_for_each_entry(rsvp, >rsvps, list) { - DRM_DEBUG_KMS("%d rsvp[s%ue%u]\n", stage, rsvp->seq, - rsvp->enc_id); - } - - for (type = 0; type < DPU_HW_BLK_MAX; type++) { - list_for_each_entry(blk, >hw_blks[type], list) { - if (!blk->rsvp && !blk->rsvp_nxt) - continue; - - DRM_DEBUG_KMS("%d rsvp[s%ue%u->s%ue%u] %d %d\n", stage, - (blk->rsvp) ? blk->rsvp->seq : 0, - (blk->rsvp) ? blk->rsvp->enc_id : 0, - (blk->rsvp_nxt) ? blk->rsvp_nxt->seq : 0, - (blk->rsvp_nxt) ? blk->rsvp_nxt->enc_id : 0, - blk->type, blk->id); - } - } -} - struct dpu_hw_mdp *dpu_rm_get_mdp(struct dpu_rm *rm) { return rm->hw_mdp; @@ -148,15 +86,13 @@ static bool _dpu_rm_get_hw_locked(struct dpu_rm *rm, struct dpu_rm_hw_iter *i) i->blk = list_prepare_entry(i->blk, blk_list, list); list_for_each_entry_continue(i->blk, blk_list, list) { - struct dpu_rm_rsvp *rsvp = i->blk->
[Freedreno] [PATCH 06/25] drm/msm/dpu: clean up redundant hw type
struct dpu_hw_blk has hw block type info. Remove duplicate type tracking in struct dpu_rm_hw_blk. Signed-off-by: Jeykumar Sankaran --- drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 17 - 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c index 5ce89b9..377def7 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c @@ -38,14 +38,12 @@ struct dpu_rm_requirements { /** * struct dpu_rm_hw_blk - hardware block tracking list member * @list: List head for list of all hardware blocks tracking items - * @type: Type of hardware block this structure tracks * @id:Hardware ID number, within it's own space, ie. LM_X * @enc_id:Encoder id to which this blk is binded * @hw:Pointer to the hardware register access object for this block */ struct dpu_rm_hw_blk { struct list_head list; - enum dpu_hw_blk_type type; uint32_t id; uint32_t enc_id; struct dpu_hw_blk *hw; @@ -86,12 +84,6 @@ static bool _dpu_rm_get_hw_locked(struct dpu_rm *rm, struct dpu_rm_hw_iter *i) i->blk = list_prepare_entry(i->blk, blk_list, list); list_for_each_entry_continue(i->blk, blk_list, list) { - if (i->blk->type != i->type) { - DPU_ERROR("found incorrect block type %d on %d list\n", - i->blk->type, i->type); - return false; - } - if (i->enc_id == i->blk->enc_id) { i->hw = i->blk->hw; DPU_DEBUG("found type %d id %d for enc %d\n", @@ -151,7 +143,7 @@ int dpu_rm_destroy(struct dpu_rm *rm) list_for_each_entry_safe(hw_cur, hw_nxt, >hw_blks[type], list) { list_del(_cur->list); - _dpu_rm_hw_destroy(hw_cur->type, hw_cur->hw); + _dpu_rm_hw_destroy(type, hw_cur->hw); kfree(hw_cur); } } @@ -213,7 +205,6 @@ static int _dpu_rm_hw_blk_create( return -ENOMEM; } - blk->type = type; blk->id = id; blk->hw = hw; blk->enc_id = 0; @@ -458,7 +449,7 @@ static int _dpu_rm_reserve_lms(struct dpu_rm *rm, uint32_t enc_id, lm[i]->enc_id = enc_id; pp[i]->enc_id = enc_id; - trace_dpu_rm_reserve_lms(lm[i]->id, lm[i]->type, enc_id, + trace_dpu_rm_reserve_lms(lm[i]->id, DPU_HW_BLK_LM, enc_id, pp[i]->id); } @@ -510,7 +501,7 @@ static int _dpu_rm_reserve_ctls( for (i = 0; i < ARRAY_SIZE(ctls) && i < num_ctls; i++) { ctls[i]->enc_id = enc_id; - trace_dpu_rm_reserve_ctls(ctls[i]->id, ctls[i]->type, + trace_dpu_rm_reserve_ctls(ctls[i]->id, DPU_HW_BLK_CTL, enc_id); } @@ -538,7 +529,7 @@ static int _dpu_rm_reserve_intf( } iter.blk->enc_id = enc_id; - trace_dpu_rm_reserve_intf(iter.blk->id, iter.blk->type, + trace_dpu_rm_reserve_intf(iter.blk->id, DPU_HW_BLK_INTF, enc_id); break; } -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
[Freedreno] [PATCH 01/25] drm/msm/dpu: fix hw ctl retrieval for mixer muxing
Layer mixer/pingpong block counts and hw ctl block counts will not be same for all the topologies (e.g. layer mixer muxing to single interface) Use the encoder's split_role info to retrieve the respective control path for programming. Signed-off-by: Jeykumar Sankaran --- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 9 ++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index 96cdf06..d12f896 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -1060,6 +1060,7 @@ static void dpu_encoder_virt_mode_set(struct drm_encoder *drm_enc, for (i = 0; i < dpu_enc->num_phys_encs; i++) { struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; + int ctl_index; if (phys) { if (!dpu_enc->hw_pp[i]) { @@ -1068,14 +1069,16 @@ static void dpu_encoder_virt_mode_set(struct drm_encoder *drm_enc, return; } - if (!hw_ctl[i]) { + ctl_index = phys->split_role == ENC_ROLE_SLAVE ? 1 : 0; + + if (!hw_ctl[ctl_index]) { DPU_ERROR_ENC(dpu_enc, "no ctl block assigned" -"at idx: %d\n", i); +"at idx: %d\n", ctl_index); return; } phys->hw_pp = dpu_enc->hw_pp[i]; - phys->hw_ctl = hw_ctl[i]; + phys->hw_ctl = hw_ctl[ctl_index]; phys->connector = conn->state->connector; if (phys->ops.mode_set) -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
[Freedreno] [PATCH 05/25] drm/msm/dpu: remove encoder from crtc mixer struct
Not actively used. Clean up the crtc mixer struct. Signed-off-by: Jeykumar Sankaran --- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 2 -- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h | 2 -- 2 files changed, 4 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index d4530d6..4960641 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -461,8 +461,6 @@ static void _dpu_crtc_setup_mixer_for_encoder( return; } - mixer->encoder = enc; - cstate->num_mixers++; DPU_DEBUG("setup mixer %d: lm %d\n", i, mixer->hw_lm->idx - LM_0); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h index 3723b48..75fdd3c 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h @@ -84,14 +84,12 @@ struct dpu_crtc_smmu_state_data { * struct dpu_crtc_mixer: stores the map for each virtual pipeline in the CRTC * @hw_lm: LM HW Driver context * @lm_ctl:CTL Path HW driver context - * @encoder: Encoder attached to this lm & ctl * @mixer_op_mode: mixer blending operation mode * @flush_mask:mixer flush mask for ctl, mixer and pipe */ struct dpu_crtc_mixer { struct dpu_hw_mixer *hw_lm; struct dpu_hw_ctl *lm_ctl; - struct drm_encoder *encoder; u32 mixer_op_mode; u32 flush_mask; }; -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
[Freedreno] [PATCH 13/25] drm/msm/dpu: make RM iterator hw type specific
Usage of hw block iterators are only RM internal. Instead of using generic void pointers for HW blocks, use dpu specific structure. It helps us to get rid of duplicate hw block id's maintained in RM wrapper. Signed-off-by: Jeykumar Sankaran --- drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 27 --- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c index 561120d..303f1b3 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c @@ -38,13 +38,11 @@ struct dpu_rm_requirements { /** * struct dpu_rm_hw_blk - hardware block tracking list member * @list: List head for list of all hardware blocks tracking items - * @id:Hardware ID number, within it's own space, ie. LM_X * @enc_id:Encoder id to which this blk is binded * @hw:Pointer to the hardware register access object for this block */ struct dpu_rm_hw_blk { struct list_head list; - uint32_t id; uint32_t enc_id; struct dpu_hw_blk *hw; }; @@ -57,7 +55,7 @@ struct dpu_rm_hw_blk { * @type: Hardware Block Type client wishes to search for. */ struct dpu_rm_hw_iter { - void *hw; + struct dpu_hw_blk *hw; struct dpu_rm_hw_blk *blk; uint32_t enc_id; enum dpu_hw_blk_type type; @@ -96,7 +94,7 @@ static bool _dpu_rm_get_hw_locked(struct dpu_rm *rm, struct dpu_rm_hw_iter *i) if (i->enc_id == i->blk->enc_id) { i->hw = i->blk->hw; DPU_DEBUG("found type %d id %d for enc %d\n", - i->type, i->blk->id, i->enc_id); + i->type, i->blk->hw->id, i->enc_id); return true; } } @@ -197,7 +195,6 @@ static int _dpu_rm_hw_blk_create( return -ENOMEM; } - blk->id = id; blk->hw = hw; blk->enc_id = 0; list_add_tail(>list, >hw_blks[type]); @@ -350,7 +347,7 @@ static bool _dpu_rm_check_lm_and_get_connected_blks( _dpu_rm_init_hw_iter(, 0, DPU_HW_BLK_PINGPONG); while (_dpu_rm_get_hw_locked(rm, )) { - if (iter.blk->id == lm_cfg->pingpong) { + if (iter.blk->hw->id == lm_cfg->pingpong) { *pp = iter.blk; break; } @@ -362,8 +359,8 @@ static bool _dpu_rm_check_lm_and_get_connected_blks( } if (RESERVED_BY_OTHER(*pp, enc_id)) { - DPU_DEBUG("lm %d pp %d already reserved\n", lm->id, - (*pp)->id); + DPU_DEBUG("lm %d pp %d already reserved\n", lm->hw->id, + (*pp)->hw->id); return false; } @@ -436,8 +433,8 @@ static int _dpu_rm_reserve_lms(struct dpu_rm *rm, uint32_t enc_id, dpu_cstate->mixers[i].hw_lm = to_dpu_hw_mixer(lm[i]->hw); dpu_cstate->mixers[i].hw_pp = to_dpu_hw_pingpong(pp[i]->hw); - trace_dpu_rm_reserve_lms(lm[i]->id, DPU_HW_BLK_LM, enc_id, -pp[i]->id); + trace_dpu_rm_reserve_lms(lm[i]->hw->id, DPU_HW_BLK_LM, enc_id, +pp[i]->hw->id); } dpu_cstate->num_mixers = lm_count; @@ -474,13 +471,13 @@ static int _dpu_rm_reserve_ctls( has_split_display = BIT(DPU_CTL_SPLIT_DISPLAY) & features; - DPU_DEBUG("ctl %d caps 0x%lX\n", iter.blk->id, features); + DPU_DEBUG("ctl %d caps 0x%lX\n", iter.blk->hw->id, features); if (needs_split_display != has_split_display) continue; ctls[i] = iter.blk; - DPU_DEBUG("ctl %d match\n", iter.blk->id); + DPU_DEBUG("ctl %d match\n", iter.blk->hw->id); if (++i == num_ctls) break; @@ -493,7 +490,7 @@ static int _dpu_rm_reserve_ctls( ctls[i]->enc_id = enc_id; dpu_cstate->hw_ctls[i] = to_dpu_hw_ctl(ctls[i]->hw); - trace_dpu_rm_reserve_ctls(ctls[i]->id, DPU_HW_BLK_CTL, + trace_dpu_rm_reserve_ctls(ctls[i]->hw->id, DPU_HW_BLK_CTL, enc_id); } @@ -513,7 +510,7 @@ static struct dpu_rm_hw_blk *_dpu_rm_reserve_intf( /* Find the block entry in the rm, and note the reservation */ _dpu_rm_init_hw_iter(, 0, type); while (_dpu_rm_get_hw_locked(rm, )) { - if (iter.blk->id != id) + if (iter.blk->
[Freedreno] [PATCH 09/25] drm/msm/dpu: make RM iterator static
HW blocks reserved for a display are stored in crtc state. No one outside RM is interested in using these API's for HW block list iterations. Signed-off-by: Jeykumar Sankaran --- drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 37 ++- drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h | 46 -- 2 files changed, 20 insertions(+), 63 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c index 619b596..24fc1c7 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c @@ -49,12 +49,26 @@ struct dpu_rm_hw_blk { struct dpu_hw_blk *hw; }; +/** + * struct dpu_rm_hw_iter - iterator for use with dpu_rm + * @hw: dpu_hw object requested, or NULL on failure + * @blk: dpu_rm internal block representation. Clients ignore. Used as iterator. + * @enc_id: DRM ID of Encoder client wishes to search for, or 0 for Any Encoder + * @type: Hardware Block Type client wishes to search for. + */ +struct dpu_rm_hw_iter { + void *hw; + struct dpu_rm_hw_blk *blk; + uint32_t enc_id; + enum dpu_hw_blk_type type; +}; + struct dpu_hw_mdp *dpu_rm_get_mdp(struct dpu_rm *rm) { return rm->hw_mdp; } -void dpu_rm_init_hw_iter( +static void _dpu_rm_init_hw_iter( struct dpu_rm_hw_iter *iter, uint32_t enc_id, enum dpu_hw_blk_type type) @@ -97,17 +111,6 @@ static bool _dpu_rm_get_hw_locked(struct dpu_rm *rm, struct dpu_rm_hw_iter *i) return false; } -bool dpu_rm_get_hw(struct dpu_rm *rm, struct dpu_rm_hw_iter *i) -{ - bool ret; - - mutex_lock(>rm_lock); - ret = _dpu_rm_get_hw_locked(rm, i); - mutex_unlock(>rm_lock); - - return ret; -} - static void _dpu_rm_hw_destroy(enum dpu_hw_blk_type type, void *hw) { switch (type) { @@ -365,7 +368,7 @@ static bool _dpu_rm_check_lm_and_get_connected_blks( return false; } - dpu_rm_init_hw_iter(, 0, DPU_HW_BLK_PINGPONG); + _dpu_rm_init_hw_iter(, 0, DPU_HW_BLK_PINGPONG); while (_dpu_rm_get_hw_locked(rm, )) { if (iter.blk->id == lm_cfg->pingpong) { *pp = iter.blk; @@ -404,7 +407,7 @@ static int _dpu_rm_reserve_lms(struct dpu_rm *rm, uint32_t enc_id, } /* Find a primary mixer */ - dpu_rm_init_hw_iter(_i, 0, DPU_HW_BLK_LM); + _dpu_rm_init_hw_iter(_i, 0, DPU_HW_BLK_LM); while (lm_count != reqs->topology.num_lm && _dpu_rm_get_hw_locked(rm, _i)) { memset(, 0, sizeof(lm)); @@ -421,7 +424,7 @@ static int _dpu_rm_reserve_lms(struct dpu_rm *rm, uint32_t enc_id, ++lm_count; /* Valid primary mixer found, find matching peers */ - dpu_rm_init_hw_iter(_j, 0, DPU_HW_BLK_LM); + _dpu_rm_init_hw_iter(_j, 0, DPU_HW_BLK_LM); while (lm_count != reqs->topology.num_lm && _dpu_rm_get_hw_locked(rm, _j)) { @@ -480,7 +483,7 @@ static int _dpu_rm_reserve_ctls( needs_split_display = _dpu_rm_needs_split_display(top); - dpu_rm_init_hw_iter(, 0, DPU_HW_BLK_CTL); + _dpu_rm_init_hw_iter(, 0, DPU_HW_BLK_CTL); while (_dpu_rm_get_hw_locked(rm, )) { const struct dpu_hw_ctl *ctl = to_dpu_hw_ctl(iter.blk->hw); unsigned long features = ctl->caps->features; @@ -528,7 +531,7 @@ static struct dpu_rm_hw_blk *_dpu_rm_reserve_intf( struct dpu_rm_hw_iter iter; /* Find the block entry in the rm, and note the reservation */ - dpu_rm_init_hw_iter(, 0, type); + _dpu_rm_init_hw_iter(, 0, type); while (_dpu_rm_get_hw_locked(rm, )) { if (iter.blk->id != id) continue; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h index e48e8f2..c7e3b2b 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h @@ -36,26 +36,6 @@ struct dpu_rm { }; /** - * struct dpu_rm_hw_blk - resource manager internal structure - * forward declaration for single iterator definition without void pointer - */ -struct dpu_rm_hw_blk; - -/** - * struct dpu_rm_hw_iter - iterator for use with dpu_rm - * @hw: dpu_hw object requested, or NULL on failure - * @blk: dpu_rm internal block representation. Clients ignore. Used as iterator. - * @enc_id: DRM ID of Encoder client wishes to search for, or 0 for Any Encoder - * @type: Hardware Block Type client wishes to search for. - */ -struct dpu_rm_hw_iter { - void *hw; - struct dpu_rm_hw_blk *blk; - uint32_t enc_id; - enum dpu_hw_blk_type type; -}; - -/** * dpu_rm_init - Read hardware catalog and create reservation tracking objects * for all HW blocks. * @rm: DPU Resource Manager handle @@ -110