diff mbox

[19/38] drm/hisilicon: Implement some semblance of vblank event handling

Message ID 1464818821-5736-20-git-send-email-daniel.vetter@ffwll.ch (mailing list archive)
State New, archived
Headers show

Commit Message

Daniel Vetter June 1, 2016, 10:06 p.m. UTC
atomic_flush seems to be the right place, but I'm not entirely sure
whether this will catch them all. It could be that when disabling the
crtc we'll miss the vblank.

While at it nuke the dummy functions.

v2: Be more robust and either arm, when the CRTC is on, or just send
the event out right away.

Cc: Xinliang Liu <xinliang.liu@linaro.org>
Cc: Xinwei Kong <kong.kongxinwei@hisilicon.com>
Cc: Archit Taneja <architt@codeaurora.org>
Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
---
 drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c | 20 ++++++++++++--------
 1 file changed, 12 insertions(+), 8 deletions(-)

Comments

Xinliang Liu June 17, 2016, 2:09 a.m. UTC | #1
Hi Daniel,

I have tested your David's drm-next branch[1] which including this patch.
In most time it is ok. But when switching modes or disable/re-enable
mode, it will encounter bellow error msg:
--
[  357.940728] [drm:drm_atomic_helper_commit_cleanup_done] *ERROR*
[CRTC:24:crtc-0] flip_done timed out
[  368.004962] [drm:drm_atomic_helper_commit_cleanup_done] *ERROR*
[CRTC:24:crtc-0] flip_done timed out
[  396.064871] INFO: rcu_preempt detected stalls on CPUs/tasks:
[  396.070548]  0-...: (3 GPs behind) idle=f4f/1/0 softirq=4253/4253 fqs=19
[  396.077335]  7-...: (1 GPs behind) idle=71f/140000000000000/0
softirq=2444/2451 fqs=19
[  396.085332]  (detected by 1, t=6028 jiffies, g=3924, c=3923, q=246)
[  396.091600] Task dump for CPU 0:
[  396.094821] swapper/0       R  running task        0     0      0 0x00000002
[  396.101872] Call trace:
[  396.104323] [<ffff000008085bec>] __switch_to+0xa4/0xd4
[  396.109460] [<ffff000008c85000>] __boot_cpu_mode+0x0/0x80
[  396.114852] Task dump for CPU 7:
[  396.118072] Xorg            R  running task        0  1658   1646 0x00000002
[  396.125121] Call trace:
[  396.127562] [<ffff000008085c10>] __switch_to+0xc8/0xd4
[  396.132695] [<ffff800035567110>] 0xffff800035567110
[  396.137569] rcu_preempt kthread starved for 1000 jiffies! g3924
c3923 f0x0 RCU_GP_WAIT_FQS(3) ->state=0x1
[  396.147130] rcu_preempt     S ffff000008085c10     0     7      2 0x00000000
[  396.154180] Call trace:
[  396.156620] [<ffff000008085c10>] __switch_to+0xc8/0xd4
[  396.161758] [<ffff000008810490>] __schedule+0x188/0x590
[  396.166978] [<ffff0000088108d4>] schedule+0x3c/0xa0
[  396.171851] [<ffff00000881368c>] schedule_timeout+0x104/0x1a4
[  396.177595] [<ffff00000810549c>] rcu_gp_kthread+0x54c/0x814
[  396.183164] [<ffff0000080d3e5c>] kthread+0xd4/0xe8
[  396.187951] [<ffff000008084e10>] ret_from_fork+0x10/0x40
--

Then the console stuck. Any tips for addressing this issue?
I am running a debian system.

[1] git://people.freedesktop.org/~airlied/linux drm-next

Thanks,
-xinliang

On 2 June 2016 at 06:06, Daniel Vetter <daniel.vetter@ffwll.ch> wrote:
> atomic_flush seems to be the right place, but I'm not entirely sure
> whether this will catch them all. It could be that when disabling the
> crtc we'll miss the vblank.
>
> While at it nuke the dummy functions.
>
> v2: Be more robust and either arm, when the CRTC is on, or just send
> the event out right away.
>
> Cc: Xinliang Liu <xinliang.liu@linaro.org>
> Cc: Xinwei Kong <kong.kongxinwei@hisilicon.com>
> Cc: Archit Taneja <architt@codeaurora.org>
> Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>

Acked-by: Xinliang Liu <xinliang.liu@linaro.org>

> ---
>  drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c | 20 ++++++++++++--------
>  1 file changed, 12 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c
> index fba6372d060e..ed76baad525f 100644
> --- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c
> +++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c
> @@ -502,13 +502,6 @@ static void ade_crtc_disable(struct drm_crtc *crtc)
>         acrtc->enable = false;
>  }
>
> -static int ade_crtc_atomic_check(struct drm_crtc *crtc,
> -                                struct drm_crtc_state *state)
> -{
> -       /* do nothing */
> -       return 0;
> -}
> -
>  static void ade_crtc_mode_set_nofb(struct drm_crtc *crtc)
>  {
>         struct ade_crtc *acrtc = to_ade_crtc(crtc);
> @@ -537,6 +530,7 @@ static void ade_crtc_atomic_flush(struct drm_crtc *crtc,
>  {
>         struct ade_crtc *acrtc = to_ade_crtc(crtc);
>         struct ade_hw_ctx *ctx = acrtc->ctx;
> +       struct drm_pending_vblank_event *event = crtc->state->event;
>         void __iomem *base = ctx->base;
>
>         /* only crtc is enabled regs take effect */
> @@ -545,12 +539,22 @@ static void ade_crtc_atomic_flush(struct drm_crtc *crtc,
>                 /* flush ade registers */
>                 writel(ADE_ENABLE, base + ADE_EN);
>         }
> +
> +       if (event) {
> +               crtc->state->event = NULL;
> +
> +               spin_lock_irq(&crtc->dev->event_lock);
> +               if (drm_crtc_vblank_get(crtc) == 0)
> +                       drm_crtc_arm_vblank_event(crtc, event);
> +               else
> +                       drm_crtc_send_vblank_event(crtc, event);
> +               spin_unlock_irq(&crtc->dev->event_lock);
> +       }
>  }
>
>  static const struct drm_crtc_helper_funcs ade_crtc_helper_funcs = {
>         .enable         = ade_crtc_enable,
>         .disable        = ade_crtc_disable,
> -       .atomic_check   = ade_crtc_atomic_check,
>         .mode_set_nofb  = ade_crtc_mode_set_nofb,
>         .atomic_begin   = ade_crtc_atomic_begin,
>         .atomic_flush   = ade_crtc_atomic_flush,
> --
> 2.8.1
>
Daniel Vetter June 17, 2016, 7:23 a.m. UTC | #2
On Fri, Jun 17, 2016 at 10:09:50AM +0800, Xinliang Liu wrote:
> Hi Daniel,
> 
> I have tested your David's drm-next branch[1] which including this patch.
> In most time it is ok. But when switching modes or disable/re-enable
> mode, it will encounter bellow error msg:
> --
> [  357.940728] [drm:drm_atomic_helper_commit_cleanup_done] *ERROR*
> [CRTC:24:crtc-0] flip_done timed out
> [  368.004962] [drm:drm_atomic_helper_commit_cleanup_done] *ERROR*
> [CRTC:24:crtc-0] flip_done timed out
> [  396.064871] INFO: rcu_preempt detected stalls on CPUs/tasks:
> [  396.070548]  0-...: (3 GPs behind) idle=f4f/1/0 softirq=4253/4253 fqs=19
> [  396.077335]  7-...: (1 GPs behind) idle=71f/140000000000000/0
> softirq=2444/2451 fqs=19
> [  396.085332]  (detected by 1, t=6028 jiffies, g=3924, c=3923, q=246)
> [  396.091600] Task dump for CPU 0:
> [  396.094821] swapper/0       R  running task        0     0      0 0x00000002
> [  396.101872] Call trace:
> [  396.104323] [<ffff000008085bec>] __switch_to+0xa4/0xd4
> [  396.109460] [<ffff000008c85000>] __boot_cpu_mode+0x0/0x80
> [  396.114852] Task dump for CPU 7:
> [  396.118072] Xorg            R  running task        0  1658   1646 0x00000002
> [  396.125121] Call trace:
> [  396.127562] [<ffff000008085c10>] __switch_to+0xc8/0xd4
> [  396.132695] [<ffff800035567110>] 0xffff800035567110
> [  396.137569] rcu_preempt kthread starved for 1000 jiffies! g3924
> c3923 f0x0 RCU_GP_WAIT_FQS(3) ->state=0x1
> [  396.147130] rcu_preempt     S ffff000008085c10     0     7      2 0x00000000
> [  396.154180] Call trace:
> [  396.156620] [<ffff000008085c10>] __switch_to+0xc8/0xd4
> [  396.161758] [<ffff000008810490>] __schedule+0x188/0x590
> [  396.166978] [<ffff0000088108d4>] schedule+0x3c/0xa0
> [  396.171851] [<ffff00000881368c>] schedule_timeout+0x104/0x1a4
> [  396.177595] [<ffff00000810549c>] rcu_gp_kthread+0x54c/0x814
> [  396.183164] [<ffff0000080d3e5c>] kthread+0xd4/0xe8
> [  396.187951] [<ffff000008084e10>] ret_from_fork+0x10/0x40
> --
> 
> Then the console stuck. Any tips for addressing this issue?
> I am running a debian system.
> 
> [1] git://people.freedesktop.org/~airlied/linux drm-next

hisilicon doesn't handle crtc_state->event correctly. Most likely when
shutting down a CRTC if fails to send out that flip event, which means the
waiting for flip_done times out. My patch tried to fix that (it's not
correct, but it did work on other drivers).

From a quick look what's wrong with hisilicon vblank handling:
- You don't call drm_crtc_vblank_on/off, which means the core thinks
  vblanks will keep working even when the CRTC is off. That throws off the
  hack in my patch. You need to put a call to drm_crtc_vblank_off into
  crtc->disable hook, and drm_crtc_vblank_on into crtc->enable.

- While at it please review that the event sending is placed correctly and
  can't race with the new buffers showing up on the screen. The event
  should be signalled at exactly the time the buffers start to get scanned
  out. The important bit is to make sure that even if something races or
  gets delayed that it still happens together.

Cheers, Daniel
> 
> Thanks,
> -xinliang
> 
> On 2 June 2016 at 06:06, Daniel Vetter <daniel.vetter@ffwll.ch> wrote:
> > atomic_flush seems to be the right place, but I'm not entirely sure
> > whether this will catch them all. It could be that when disabling the
> > crtc we'll miss the vblank.
> >
> > While at it nuke the dummy functions.
> >
> > v2: Be more robust and either arm, when the CRTC is on, or just send
> > the event out right away.
> >
> > Cc: Xinliang Liu <xinliang.liu@linaro.org>
> > Cc: Xinwei Kong <kong.kongxinwei@hisilicon.com>
> > Cc: Archit Taneja <architt@codeaurora.org>
> > Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
> 
> Acked-by: Xinliang Liu <xinliang.liu@linaro.org>
> 
> > ---
> >  drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c | 20 ++++++++++++--------
> >  1 file changed, 12 insertions(+), 8 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c
> > index fba6372d060e..ed76baad525f 100644
> > --- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c
> > +++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c
> > @@ -502,13 +502,6 @@ static void ade_crtc_disable(struct drm_crtc *crtc)
> >         acrtc->enable = false;
> >  }
> >
> > -static int ade_crtc_atomic_check(struct drm_crtc *crtc,
> > -                                struct drm_crtc_state *state)
> > -{
> > -       /* do nothing */
> > -       return 0;
> > -}
> > -
> >  static void ade_crtc_mode_set_nofb(struct drm_crtc *crtc)
> >  {
> >         struct ade_crtc *acrtc = to_ade_crtc(crtc);
> > @@ -537,6 +530,7 @@ static void ade_crtc_atomic_flush(struct drm_crtc *crtc,
> >  {
> >         struct ade_crtc *acrtc = to_ade_crtc(crtc);
> >         struct ade_hw_ctx *ctx = acrtc->ctx;
> > +       struct drm_pending_vblank_event *event = crtc->state->event;
> >         void __iomem *base = ctx->base;
> >
> >         /* only crtc is enabled regs take effect */
> > @@ -545,12 +539,22 @@ static void ade_crtc_atomic_flush(struct drm_crtc *crtc,
> >                 /* flush ade registers */
> >                 writel(ADE_ENABLE, base + ADE_EN);
> >         }
> > +
> > +       if (event) {
> > +               crtc->state->event = NULL;
> > +
> > +               spin_lock_irq(&crtc->dev->event_lock);
> > +               if (drm_crtc_vblank_get(crtc) == 0)
> > +                       drm_crtc_arm_vblank_event(crtc, event);
> > +               else
> > +                       drm_crtc_send_vblank_event(crtc, event);
> > +               spin_unlock_irq(&crtc->dev->event_lock);
> > +       }
> >  }
> >
> >  static const struct drm_crtc_helper_funcs ade_crtc_helper_funcs = {
> >         .enable         = ade_crtc_enable,
> >         .disable        = ade_crtc_disable,
> > -       .atomic_check   = ade_crtc_atomic_check,
> >         .mode_set_nofb  = ade_crtc_mode_set_nofb,
> >         .atomic_begin   = ade_crtc_atomic_begin,
> >         .atomic_flush   = ade_crtc_atomic_flush,
> > --
> > 2.8.1
> >
Xinliang Liu June 17, 2016, 8:38 a.m. UTC | #3
Hi,

On 17 June 2016 at 15:23, Daniel Vetter <daniel@ffwll.ch> wrote:
> On Fri, Jun 17, 2016 at 10:09:50AM +0800, Xinliang Liu wrote:
>> Hi Daniel,
>>
>> I have tested your David's drm-next branch[1] which including this patch.
>> In most time it is ok. But when switching modes or disable/re-enable
>> mode, it will encounter bellow error msg:
>> --
>> [  357.940728] [drm:drm_atomic_helper_commit_cleanup_done] *ERROR*
>> [CRTC:24:crtc-0] flip_done timed out
>> [  368.004962] [drm:drm_atomic_helper_commit_cleanup_done] *ERROR*
>> [CRTC:24:crtc-0] flip_done timed out
>> [  396.064871] INFO: rcu_preempt detected stalls on CPUs/tasks:
>> [  396.070548]  0-...: (3 GPs behind) idle=f4f/1/0 softirq=4253/4253 fqs=19
>> [  396.077335]  7-...: (1 GPs behind) idle=71f/140000000000000/0
>> softirq=2444/2451 fqs=19
>> [  396.085332]  (detected by 1, t=6028 jiffies, g=3924, c=3923, q=246)
>> [  396.091600] Task dump for CPU 0:
>> [  396.094821] swapper/0       R  running task        0     0      0 0x00000002
>> [  396.101872] Call trace:
>> [  396.104323] [<ffff000008085bec>] __switch_to+0xa4/0xd4
>> [  396.109460] [<ffff000008c85000>] __boot_cpu_mode+0x0/0x80
>> [  396.114852] Task dump for CPU 7:
>> [  396.118072] Xorg            R  running task        0  1658   1646 0x00000002
>> [  396.125121] Call trace:
>> [  396.127562] [<ffff000008085c10>] __switch_to+0xc8/0xd4
>> [  396.132695] [<ffff800035567110>] 0xffff800035567110
>> [  396.137569] rcu_preempt kthread starved for 1000 jiffies! g3924
>> c3923 f0x0 RCU_GP_WAIT_FQS(3) ->state=0x1
>> [  396.147130] rcu_preempt     S ffff000008085c10     0     7      2 0x00000000
>> [  396.154180] Call trace:
>> [  396.156620] [<ffff000008085c10>] __switch_to+0xc8/0xd4
>> [  396.161758] [<ffff000008810490>] __schedule+0x188/0x590
>> [  396.166978] [<ffff0000088108d4>] schedule+0x3c/0xa0
>> [  396.171851] [<ffff00000881368c>] schedule_timeout+0x104/0x1a4
>> [  396.177595] [<ffff00000810549c>] rcu_gp_kthread+0x54c/0x814
>> [  396.183164] [<ffff0000080d3e5c>] kthread+0xd4/0xe8
>> [  396.187951] [<ffff000008084e10>] ret_from_fork+0x10/0x40
>> --
>>
>> Then the console stuck. Any tips for addressing this issue?
>> I am running a debian system.
>>
>> [1] git://people.freedesktop.org/~airlied/linux drm-next
>
> hisilicon doesn't handle crtc_state->event correctly. Most likely when
> shutting down a CRTC if fails to send out that flip event, which means the
> waiting for flip_done times out. My patch tried to fix that (it's not
> correct, but it did work on other drivers).
>
> From a quick look what's wrong with hisilicon vblank handling:
> - You don't call drm_crtc_vblank_on/off, which means the core thinks
>   vblanks will keep working even when the CRTC is off. That throws off the
>   hack in my patch. You need to put a call to drm_crtc_vblank_off into
>   crtc->disable hook, and drm_crtc_vblank_on into crtc->enable.

Yes, this is really a problem. I will add drm_crtc_vblank_on/off into
 crtc->disable/enable hook.
And try.

>
> - While at it please review that the event sending is placed correctly and
>   can't race with the new buffers showing up on the screen. The event
>   should be signalled at exactly the time the buffers start to get scanned
>   out. The important bit is to make sure that even if something races or
>   gets delayed that it still happens together.

Our display controller has a interrupt to indicate that  one
commit/flip is taken effect in hardware.
Should I put the sending event in this interrupt handler?

Thanks,
-xinliang

>
> Cheers, Daniel
>>
>> Thanks,
>> -xinliang
>>
>> On 2 June 2016 at 06:06, Daniel Vetter <daniel.vetter@ffwll.ch> wrote:
>> > atomic_flush seems to be the right place, but I'm not entirely sure
>> > whether this will catch them all. It could be that when disabling the
>> > crtc we'll miss the vblank.
>> >
>> > While at it nuke the dummy functions.
>> >
>> > v2: Be more robust and either arm, when the CRTC is on, or just send
>> > the event out right away.
>> >
>> > Cc: Xinliang Liu <xinliang.liu@linaro.org>
>> > Cc: Xinwei Kong <kong.kongxinwei@hisilicon.com>
>> > Cc: Archit Taneja <architt@codeaurora.org>
>> > Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
>>
>> Acked-by: Xinliang Liu <xinliang.liu@linaro.org>
>>
>> > ---
>> >  drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c | 20 ++++++++++++--------
>> >  1 file changed, 12 insertions(+), 8 deletions(-)
>> >
>> > diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c
>> > index fba6372d060e..ed76baad525f 100644
>> > --- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c
>> > +++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c
>> > @@ -502,13 +502,6 @@ static void ade_crtc_disable(struct drm_crtc *crtc)
>> >         acrtc->enable = false;
>> >  }
>> >
>> > -static int ade_crtc_atomic_check(struct drm_crtc *crtc,
>> > -                                struct drm_crtc_state *state)
>> > -{
>> > -       /* do nothing */
>> > -       return 0;
>> > -}
>> > -
>> >  static void ade_crtc_mode_set_nofb(struct drm_crtc *crtc)
>> >  {
>> >         struct ade_crtc *acrtc = to_ade_crtc(crtc);
>> > @@ -537,6 +530,7 @@ static void ade_crtc_atomic_flush(struct drm_crtc *crtc,
>> >  {
>> >         struct ade_crtc *acrtc = to_ade_crtc(crtc);
>> >         struct ade_hw_ctx *ctx = acrtc->ctx;
>> > +       struct drm_pending_vblank_event *event = crtc->state->event;
>> >         void __iomem *base = ctx->base;
>> >
>> >         /* only crtc is enabled regs take effect */
>> > @@ -545,12 +539,22 @@ static void ade_crtc_atomic_flush(struct drm_crtc *crtc,
>> >                 /* flush ade registers */
>> >                 writel(ADE_ENABLE, base + ADE_EN);
>> >         }
>> > +
>> > +       if (event) {
>> > +               crtc->state->event = NULL;
>> > +
>> > +               spin_lock_irq(&crtc->dev->event_lock);
>> > +               if (drm_crtc_vblank_get(crtc) == 0)
>> > +                       drm_crtc_arm_vblank_event(crtc, event);
>> > +               else
>> > +                       drm_crtc_send_vblank_event(crtc, event);
>> > +               spin_unlock_irq(&crtc->dev->event_lock);
>> > +       }
>> >  }
>> >
>> >  static const struct drm_crtc_helper_funcs ade_crtc_helper_funcs = {
>> >         .enable         = ade_crtc_enable,
>> >         .disable        = ade_crtc_disable,
>> > -       .atomic_check   = ade_crtc_atomic_check,
>> >         .mode_set_nofb  = ade_crtc_mode_set_nofb,
>> >         .atomic_begin   = ade_crtc_atomic_begin,
>> >         .atomic_flush   = ade_crtc_atomic_flush,
>> > --
>> > 2.8.1
>> >
>
> --
> Daniel Vetter
> Software Engineer, Intel Corporation
> http://blog.ffwll.ch
Daniel Vetter June 17, 2016, 12:24 p.m. UTC | #4
On Fri, Jun 17, 2016 at 04:38:06PM +0800, Xinliang Liu wrote:
> Hi,
> 
> On 17 June 2016 at 15:23, Daniel Vetter <daniel@ffwll.ch> wrote:
> > On Fri, Jun 17, 2016 at 10:09:50AM +0800, Xinliang Liu wrote:
> >> Hi Daniel,
> >>
> >> I have tested your David's drm-next branch[1] which including this patch.
> >> In most time it is ok. But when switching modes or disable/re-enable
> >> mode, it will encounter bellow error msg:
> >> --
> >> [  357.940728] [drm:drm_atomic_helper_commit_cleanup_done] *ERROR*
> >> [CRTC:24:crtc-0] flip_done timed out
> >> [  368.004962] [drm:drm_atomic_helper_commit_cleanup_done] *ERROR*
> >> [CRTC:24:crtc-0] flip_done timed out
> >> [  396.064871] INFO: rcu_preempt detected stalls on CPUs/tasks:
> >> [  396.070548]  0-...: (3 GPs behind) idle=f4f/1/0 softirq=4253/4253 fqs=19
> >> [  396.077335]  7-...: (1 GPs behind) idle=71f/140000000000000/0
> >> softirq=2444/2451 fqs=19
> >> [  396.085332]  (detected by 1, t=6028 jiffies, g=3924, c=3923, q=246)
> >> [  396.091600] Task dump for CPU 0:
> >> [  396.094821] swapper/0       R  running task        0     0      0 0x00000002
> >> [  396.101872] Call trace:
> >> [  396.104323] [<ffff000008085bec>] __switch_to+0xa4/0xd4
> >> [  396.109460] [<ffff000008c85000>] __boot_cpu_mode+0x0/0x80
> >> [  396.114852] Task dump for CPU 7:
> >> [  396.118072] Xorg            R  running task        0  1658   1646 0x00000002
> >> [  396.125121] Call trace:
> >> [  396.127562] [<ffff000008085c10>] __switch_to+0xc8/0xd4
> >> [  396.132695] [<ffff800035567110>] 0xffff800035567110
> >> [  396.137569] rcu_preempt kthread starved for 1000 jiffies! g3924
> >> c3923 f0x0 RCU_GP_WAIT_FQS(3) ->state=0x1
> >> [  396.147130] rcu_preempt     S ffff000008085c10     0     7      2 0x00000000
> >> [  396.154180] Call trace:
> >> [  396.156620] [<ffff000008085c10>] __switch_to+0xc8/0xd4
> >> [  396.161758] [<ffff000008810490>] __schedule+0x188/0x590
> >> [  396.166978] [<ffff0000088108d4>] schedule+0x3c/0xa0
> >> [  396.171851] [<ffff00000881368c>] schedule_timeout+0x104/0x1a4
> >> [  396.177595] [<ffff00000810549c>] rcu_gp_kthread+0x54c/0x814
> >> [  396.183164] [<ffff0000080d3e5c>] kthread+0xd4/0xe8
> >> [  396.187951] [<ffff000008084e10>] ret_from_fork+0x10/0x40
> >> --
> >>
> >> Then the console stuck. Any tips for addressing this issue?
> >> I am running a debian system.
> >>
> >> [1] git://people.freedesktop.org/~airlied/linux drm-next
> >
> > hisilicon doesn't handle crtc_state->event correctly. Most likely when
> > shutting down a CRTC if fails to send out that flip event, which means the
> > waiting for flip_done times out. My patch tried to fix that (it's not
> > correct, but it did work on other drivers).
> >
> > From a quick look what's wrong with hisilicon vblank handling:
> > - You don't call drm_crtc_vblank_on/off, which means the core thinks
> >   vblanks will keep working even when the CRTC is off. That throws off the
> >   hack in my patch. You need to put a call to drm_crtc_vblank_off into
> >   crtc->disable hook, and drm_crtc_vblank_on into crtc->enable.
> 
> Yes, this is really a problem. I will add drm_crtc_vblank_on/off into
>  crtc->disable/enable hook.
> And try.
> 
> >
> > - While at it please review that the event sending is placed correctly and
> >   can't race with the new buffers showing up on the screen. The event
> >   should be signalled at exactly the time the buffers start to get scanned
> >   out. The important bit is to make sure that even if something races or
> >   gets delayed that it still happens together.
> 
> Our display controller has a interrupt to indicate that  one
> commit/flip is taken effect in hardware.
> Should I put the sending event in this interrupt handler?

Yes, that would be perfect. So instead of the drm_crtc_arm_vblank_event
you put the event into a driver-private slot where the irq handler can
pick it up and send it out using drm_crtc_send_vblank_event.

Two important details:
- You need to arm the event this way before the hw can fire this special
  interrupt, so probably somewhere in atomic_begin.
- the drm_crtc_send_vblank_event must be called after
  drm_crtc_handle_vblank, because otherwise the vblank timestamp isn't
  properly updated.

Cheers, Daniel

> 
> Thanks,
> -xinliang
> 
> >
> > Cheers, Daniel
> >>
> >> Thanks,
> >> -xinliang
> >>
> >> On 2 June 2016 at 06:06, Daniel Vetter <daniel.vetter@ffwll.ch> wrote:
> >> > atomic_flush seems to be the right place, but I'm not entirely sure
> >> > whether this will catch them all. It could be that when disabling the
> >> > crtc we'll miss the vblank.
> >> >
> >> > While at it nuke the dummy functions.
> >> >
> >> > v2: Be more robust and either arm, when the CRTC is on, or just send
> >> > the event out right away.
> >> >
> >> > Cc: Xinliang Liu <xinliang.liu@linaro.org>
> >> > Cc: Xinwei Kong <kong.kongxinwei@hisilicon.com>
> >> > Cc: Archit Taneja <architt@codeaurora.org>
> >> > Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
> >>
> >> Acked-by: Xinliang Liu <xinliang.liu@linaro.org>
> >>
> >> > ---
> >> >  drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c | 20 ++++++++++++--------
> >> >  1 file changed, 12 insertions(+), 8 deletions(-)
> >> >
> >> > diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c
> >> > index fba6372d060e..ed76baad525f 100644
> >> > --- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c
> >> > +++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c
> >> > @@ -502,13 +502,6 @@ static void ade_crtc_disable(struct drm_crtc *crtc)
> >> >         acrtc->enable = false;
> >> >  }
> >> >
> >> > -static int ade_crtc_atomic_check(struct drm_crtc *crtc,
> >> > -                                struct drm_crtc_state *state)
> >> > -{
> >> > -       /* do nothing */
> >> > -       return 0;
> >> > -}
> >> > -
> >> >  static void ade_crtc_mode_set_nofb(struct drm_crtc *crtc)
> >> >  {
> >> >         struct ade_crtc *acrtc = to_ade_crtc(crtc);
> >> > @@ -537,6 +530,7 @@ static void ade_crtc_atomic_flush(struct drm_crtc *crtc,
> >> >  {
> >> >         struct ade_crtc *acrtc = to_ade_crtc(crtc);
> >> >         struct ade_hw_ctx *ctx = acrtc->ctx;
> >> > +       struct drm_pending_vblank_event *event = crtc->state->event;
> >> >         void __iomem *base = ctx->base;
> >> >
> >> >         /* only crtc is enabled regs take effect */
> >> > @@ -545,12 +539,22 @@ static void ade_crtc_atomic_flush(struct drm_crtc *crtc,
> >> >                 /* flush ade registers */
> >> >                 writel(ADE_ENABLE, base + ADE_EN);
> >> >         }
> >> > +
> >> > +       if (event) {
> >> > +               crtc->state->event = NULL;
> >> > +
> >> > +               spin_lock_irq(&crtc->dev->event_lock);
> >> > +               if (drm_crtc_vblank_get(crtc) == 0)
> >> > +                       drm_crtc_arm_vblank_event(crtc, event);
> >> > +               else
> >> > +                       drm_crtc_send_vblank_event(crtc, event);
> >> > +               spin_unlock_irq(&crtc->dev->event_lock);
> >> > +       }
> >> >  }
> >> >
> >> >  static const struct drm_crtc_helper_funcs ade_crtc_helper_funcs = {
> >> >         .enable         = ade_crtc_enable,
> >> >         .disable        = ade_crtc_disable,
> >> > -       .atomic_check   = ade_crtc_atomic_check,
> >> >         .mode_set_nofb  = ade_crtc_mode_set_nofb,
> >> >         .atomic_begin   = ade_crtc_atomic_begin,
> >> >         .atomic_flush   = ade_crtc_atomic_flush,
> >> > --
> >> > 2.8.1
> >> >
> >
> > --
> > Daniel Vetter
> > Software Engineer, Intel Corporation
> > http://blog.ffwll.ch
Xinliang Liu June 21, 2016, 1:32 a.m. UTC | #5
On 17 June 2016 at 20:24, Daniel Vetter <daniel@ffwll.ch> wrote:
> On Fri, Jun 17, 2016 at 04:38:06PM +0800, Xinliang Liu wrote:
>> Hi,
>>
>> On 17 June 2016 at 15:23, Daniel Vetter <daniel@ffwll.ch> wrote:
>> > On Fri, Jun 17, 2016 at 10:09:50AM +0800, Xinliang Liu wrote:
>> >> Hi Daniel,
>> >>
>> >> I have tested your David's drm-next branch[1] which including this patch.
>> >> In most time it is ok. But when switching modes or disable/re-enable
>> >> mode, it will encounter bellow error msg:
>> >> --
>> >> [  357.940728] [drm:drm_atomic_helper_commit_cleanup_done] *ERROR*
>> >> [CRTC:24:crtc-0] flip_done timed out
>> >> [  368.004962] [drm:drm_atomic_helper_commit_cleanup_done] *ERROR*
>> >> [CRTC:24:crtc-0] flip_done timed out
>> >> [  396.064871] INFO: rcu_preempt detected stalls on CPUs/tasks:
>> >> [  396.070548]  0-...: (3 GPs behind) idle=f4f/1/0 softirq=4253/4253 fqs=19
>> >> [  396.077335]  7-...: (1 GPs behind) idle=71f/140000000000000/0
>> >> softirq=2444/2451 fqs=19
>> >> [  396.085332]  (detected by 1, t=6028 jiffies, g=3924, c=3923, q=246)
>> >> [  396.091600] Task dump for CPU 0:
>> >> [  396.094821] swapper/0       R  running task        0     0      0 0x00000002
>> >> [  396.101872] Call trace:
>> >> [  396.104323] [<ffff000008085bec>] __switch_to+0xa4/0xd4
>> >> [  396.109460] [<ffff000008c85000>] __boot_cpu_mode+0x0/0x80
>> >> [  396.114852] Task dump for CPU 7:
>> >> [  396.118072] Xorg            R  running task        0  1658   1646 0x00000002
>> >> [  396.125121] Call trace:
>> >> [  396.127562] [<ffff000008085c10>] __switch_to+0xc8/0xd4
>> >> [  396.132695] [<ffff800035567110>] 0xffff800035567110
>> >> [  396.137569] rcu_preempt kthread starved for 1000 jiffies! g3924
>> >> c3923 f0x0 RCU_GP_WAIT_FQS(3) ->state=0x1
>> >> [  396.147130] rcu_preempt     S ffff000008085c10     0     7      2 0x00000000
>> >> [  396.154180] Call trace:
>> >> [  396.156620] [<ffff000008085c10>] __switch_to+0xc8/0xd4
>> >> [  396.161758] [<ffff000008810490>] __schedule+0x188/0x590
>> >> [  396.166978] [<ffff0000088108d4>] schedule+0x3c/0xa0
>> >> [  396.171851] [<ffff00000881368c>] schedule_timeout+0x104/0x1a4
>> >> [  396.177595] [<ffff00000810549c>] rcu_gp_kthread+0x54c/0x814
>> >> [  396.183164] [<ffff0000080d3e5c>] kthread+0xd4/0xe8
>> >> [  396.187951] [<ffff000008084e10>] ret_from_fork+0x10/0x40
>> >> --
>> >>
>> >> Then the console stuck. Any tips for addressing this issue?
>> >> I am running a debian system.
>> >>
>> >> [1] git://people.freedesktop.org/~airlied/linux drm-next
>> >
>> > hisilicon doesn't handle crtc_state->event correctly. Most likely when
>> > shutting down a CRTC if fails to send out that flip event, which means the
>> > waiting for flip_done times out. My patch tried to fix that (it's not
>> > correct, but it did work on other drivers).
>> >
>> > From a quick look what's wrong with hisilicon vblank handling:
>> > - You don't call drm_crtc_vblank_on/off, which means the core thinks
>> >   vblanks will keep working even when the CRTC is off. That throws off the
>> >   hack in my patch. You need to put a call to drm_crtc_vblank_off into
>> >   crtc->disable hook, and drm_crtc_vblank_on into crtc->enable.
>>
>> Yes, this is really a problem. I will add drm_crtc_vblank_on/off into
>>  crtc->disable/enable hook.
>> And try.
>>
>> >
>> > - While at it please review that the event sending is placed correctly and
>> >   can't race with the new buffers showing up on the screen. The event
>> >   should be signalled at exactly the time the buffers start to get scanned
>> >   out. The important bit is to make sure that even if something races or
>> >   gets delayed that it still happens together.
>>
>> Our display controller has a interrupt to indicate that  one
>> commit/flip is taken effect in hardware.
>> Should I put the sending event in this interrupt handler?
>
> Yes, that would be perfect. So instead of the drm_crtc_arm_vblank_event
> you put the event into a driver-private slot where the irq handler can
> pick it up and send it out using drm_crtc_send_vblank_event.
>
> Two important details:
> - You need to arm the event this way before the hw can fire this special
>   interrupt, so probably somewhere in atomic_begin.
> - the drm_crtc_send_vblank_event must be called after
>   drm_crtc_handle_vblank, because otherwise the vblank timestamp isn't
>   properly updated.

When adding drm_crtc_vblank_on/off into crtc->disable/enable hook,
The "flip_done timed out" error msg has gone. It seems that
drm_crtc_vblank_off will send out all the pending event.
I will send out this patch for review soon.

My understanding is that drm_crtc_arm_vblank_event work together with
drm_crtc_handle_vblank (called in vblank interrupt).
Arm the event first in somewhere(like atomic_begin/flush) and then
send it out throuth drm_crtc_handle_vblank in vblank interrupt.
In the other way, drm_crtc_send_vblank_event work together with flip
interrupt. That's means event will be sent in flip interrupt
immediately.
Is this right?

Best,
-xinliang

>
> Cheers, Daniel
>
>>
>> Thanks,
>> -xinliang
>>
>> >
>> > Cheers, Daniel
>> >>
>> >> Thanks,
>> >> -xinliang
>> >>
>> >> On 2 June 2016 at 06:06, Daniel Vetter <daniel.vetter@ffwll.ch> wrote:
>> >> > atomic_flush seems to be the right place, but I'm not entirely sure
>> >> > whether this will catch them all. It could be that when disabling the
>> >> > crtc we'll miss the vblank.
>> >> >
>> >> > While at it nuke the dummy functions.
>> >> >
>> >> > v2: Be more robust and either arm, when the CRTC is on, or just send
>> >> > the event out right away.
>> >> >
>> >> > Cc: Xinliang Liu <xinliang.liu@linaro.org>
>> >> > Cc: Xinwei Kong <kong.kongxinwei@hisilicon.com>
>> >> > Cc: Archit Taneja <architt@codeaurora.org>
>> >> > Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
>> >>
>> >> Acked-by: Xinliang Liu <xinliang.liu@linaro.org>
>> >>
>> >> > ---
>> >> >  drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c | 20 ++++++++++++--------
>> >> >  1 file changed, 12 insertions(+), 8 deletions(-)
>> >> >
>> >> > diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c
>> >> > index fba6372d060e..ed76baad525f 100644
>> >> > --- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c
>> >> > +++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c
>> >> > @@ -502,13 +502,6 @@ static void ade_crtc_disable(struct drm_crtc *crtc)
>> >> >         acrtc->enable = false;
>> >> >  }
>> >> >
>> >> > -static int ade_crtc_atomic_check(struct drm_crtc *crtc,
>> >> > -                                struct drm_crtc_state *state)
>> >> > -{
>> >> > -       /* do nothing */
>> >> > -       return 0;
>> >> > -}
>> >> > -
>> >> >  static void ade_crtc_mode_set_nofb(struct drm_crtc *crtc)
>> >> >  {
>> >> >         struct ade_crtc *acrtc = to_ade_crtc(crtc);
>> >> > @@ -537,6 +530,7 @@ static void ade_crtc_atomic_flush(struct drm_crtc *crtc,
>> >> >  {
>> >> >         struct ade_crtc *acrtc = to_ade_crtc(crtc);
>> >> >         struct ade_hw_ctx *ctx = acrtc->ctx;
>> >> > +       struct drm_pending_vblank_event *event = crtc->state->event;
>> >> >         void __iomem *base = ctx->base;
>> >> >
>> >> >         /* only crtc is enabled regs take effect */
>> >> > @@ -545,12 +539,22 @@ static void ade_crtc_atomic_flush(struct drm_crtc *crtc,
>> >> >                 /* flush ade registers */
>> >> >                 writel(ADE_ENABLE, base + ADE_EN);
>> >> >         }
>> >> > +
>> >> > +       if (event) {
>> >> > +               crtc->state->event = NULL;
>> >> > +
>> >> > +               spin_lock_irq(&crtc->dev->event_lock);
>> >> > +               if (drm_crtc_vblank_get(crtc) == 0)
>> >> > +                       drm_crtc_arm_vblank_event(crtc, event);
>> >> > +               else
>> >> > +                       drm_crtc_send_vblank_event(crtc, event);
>> >> > +               spin_unlock_irq(&crtc->dev->event_lock);
>> >> > +       }
>> >> >  }
>> >> >
>> >> >  static const struct drm_crtc_helper_funcs ade_crtc_helper_funcs = {
>> >> >         .enable         = ade_crtc_enable,
>> >> >         .disable        = ade_crtc_disable,
>> >> > -       .atomic_check   = ade_crtc_atomic_check,
>> >> >         .mode_set_nofb  = ade_crtc_mode_set_nofb,
>> >> >         .atomic_begin   = ade_crtc_atomic_begin,
>> >> >         .atomic_flush   = ade_crtc_atomic_flush,
>> >> > --
>> >> > 2.8.1
>> >> >
>> >
>> > --
>> > Daniel Vetter
>> > Software Engineer, Intel Corporation
>> > http://blog.ffwll.ch
>
> --
> Daniel Vetter
> Software Engineer, Intel Corporation
> http://blog.ffwll.ch
Daniel Vetter June 21, 2016, 7:19 a.m. UTC | #6
On Tue, Jun 21, 2016 at 3:32 AM, Xinliang Liu <xinliang.liu@linaro.org> wrote:
> My understanding is that drm_crtc_arm_vblank_event work together with
> drm_crtc_handle_vblank (called in vblank interrupt).
> Arm the event first in somewhere(like atomic_begin/flush) and then
> send it out throuth drm_crtc_handle_vblank in vblank interrupt.
> In the other way, drm_crtc_send_vblank_event work together with flip
> interrupt. That's means event will be sent in flip interrupt
> immediately.
> Is this right?

First part is right. Second part about drm_crtc_send_vblank event just
sends out the vblank directly (using the last recorded vblank). The
vblank subsystem doesn't itself interact with any interrupt.

Note that there's kerneldoc for all of this. Please make sure it does
describe things sufficiently well, and if not please send in patches
to improve them.
-Daniel
Xinliang Liu June 22, 2016, 2:50 a.m. UTC | #7
On 21 June 2016 at 15:19, Daniel Vetter <daniel@ffwll.ch> wrote:
> On Tue, Jun 21, 2016 at 3:32 AM, Xinliang Liu <xinliang.liu@linaro.org> wrote:
>> My understanding is that drm_crtc_arm_vblank_event work together with
>> drm_crtc_handle_vblank (called in vblank interrupt).
>> Arm the event first in somewhere(like atomic_begin/flush) and then
>> send it out throuth drm_crtc_handle_vblank in vblank interrupt.
>> In the other way, drm_crtc_send_vblank_event work together with flip
>> interrupt. That's means event will be sent in flip interrupt
>> immediately.
>> Is this right?
>
> First part is right. Second part about drm_crtc_send_vblank event just
> sends out the vblank directly (using the last recorded vblank). The
> vblank subsystem doesn't itself interact with any interrupt.
>
> Note that there's kerneldoc for all of this. Please make sure it does
> describe things sufficiently well, and if not please send in patches
> to improve them.

Ok, I will take a look at the doc.

Thanks,
-xinliang

> -Daniel
> --
> Daniel Vetter
> Software Engineer, Intel Corporation
> +41 (0) 79 365 57 48 - http://blog.ffwll.ch
diff mbox

Patch

diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c
index fba6372d060e..ed76baad525f 100644
--- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c
+++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c
@@ -502,13 +502,6 @@  static void ade_crtc_disable(struct drm_crtc *crtc)
 	acrtc->enable = false;
 }
 
-static int ade_crtc_atomic_check(struct drm_crtc *crtc,
-				 struct drm_crtc_state *state)
-{
-	/* do nothing */
-	return 0;
-}
-
 static void ade_crtc_mode_set_nofb(struct drm_crtc *crtc)
 {
 	struct ade_crtc *acrtc = to_ade_crtc(crtc);
@@ -537,6 +530,7 @@  static void ade_crtc_atomic_flush(struct drm_crtc *crtc,
 {
 	struct ade_crtc *acrtc = to_ade_crtc(crtc);
 	struct ade_hw_ctx *ctx = acrtc->ctx;
+	struct drm_pending_vblank_event *event = crtc->state->event;
 	void __iomem *base = ctx->base;
 
 	/* only crtc is enabled regs take effect */
@@ -545,12 +539,22 @@  static void ade_crtc_atomic_flush(struct drm_crtc *crtc,
 		/* flush ade registers */
 		writel(ADE_ENABLE, base + ADE_EN);
 	}
+
+	if (event) {
+		crtc->state->event = NULL;
+
+		spin_lock_irq(&crtc->dev->event_lock);
+		if (drm_crtc_vblank_get(crtc) == 0)
+			drm_crtc_arm_vblank_event(crtc, event);
+		else
+			drm_crtc_send_vblank_event(crtc, event);
+		spin_unlock_irq(&crtc->dev->event_lock);
+	}
 }
 
 static const struct drm_crtc_helper_funcs ade_crtc_helper_funcs = {
 	.enable		= ade_crtc_enable,
 	.disable	= ade_crtc_disable,
-	.atomic_check	= ade_crtc_atomic_check,
 	.mode_set_nofb	= ade_crtc_mode_set_nofb,
 	.atomic_begin	= ade_crtc_atomic_begin,
 	.atomic_flush	= ade_crtc_atomic_flush,