• Stephen Boyd's avatar
    soc: qcom: rpmh-rsc: Sleep waiting for tcs slots to be free · 2bc20f3c
    Stephen Boyd authored
    The busy loop in rpmh_rsc_send_data() is written with the assumption
    that the udelay will be preempted by the tcs_tx_done() irq handler when
    the TCS slots are all full. This doesn't hold true when the calling
    thread is an irqthread and the tcs_tx_done() irq is also an irqthread.
    That's because kernel irqthreads are SCHED_FIFO and thus need to
    voluntarily give up priority by calling into the scheduler so that other
    threads can run.
    
    I see RCU stalls when I boot with irqthreads on the kernel commandline
    because the modem remoteproc driver is trying to send an rpmh async
    message from an irqthread that needs to give up the CPU for the rpmh
    irqthread to run and clear out tcs slots.
    
     rcu: INFO: rcu_preempt self-detected stall on CPU
     rcu:     0-....: (1 GPs behind) idle=402/1/0x4000000000000002 softirq=2108/2109 fqs=4920
      (t=21016 jiffies g=2933 q=590)
     Task dump for CPU 0:
     irq/11-smp2p    R  running task        0   148      2 0x00000028
     Call trace:
      dump_backtrace+0x0/0x154
      show_stack+0x20/0x2c
      sched_show_task+0xfc/0x108
      dump_cpu_task+0x44/0x50
      rcu_dump_cpu_stacks+0xa4/0xf8
      rcu_sched_clock_irq+0x7dc/0xaa8
      update_process_times+0x30/0x54
      tick_sched_handle+0x50/0x64
      tick_sched_timer+0x4c/0x8c
      __hrtimer_run_queues+0x21c/0x36c
      hrtimer_interrupt+0xf0/0x22c
      arch_timer_handler_phys+0x40/0x50
      handle_percpu_devid_irq+0x114/0x25c
      __handle_domain_irq+0x84/0xc4
      gic_handle_irq+0xd0/0x178
      el1_irq+0xbc/0x180
      save_return_addr+0x18/0x28
      return_address+0x54/0x88
      preempt_count_sub+0x40/0x88
      _raw_spin_unlock_irqrestore+0x4c/0x6c
      ___ratelimit+0xd0/0x128
      rpmh_rsc_send_data+0x24c/0x378
      __rpmh_write+0x1b0/0x208
      rpmh_write_async+0x90/0xbc
      rpmhpd_send_corner+0x60/0x8c
      rpmhpd_aggregate_corner+0x8c/0x124
      rpmhpd_set_performance_state+0x8c/0xbc
      _genpd_set_performance_state+0xdc/0x1b8
      dev_pm_genpd_set_performance_state+0xb8/0xf8
      q6v5_pds_disable+0x34/0x60 [qcom_q6v5_mss]
      qcom_msa_handover+0x38/0x44 [qcom_q6v5_mss]
      q6v5_handover_interrupt+0x24/0x3c [qcom_q6v5]
      handle_nested_irq+0xd0/0x138
      qcom_smp2p_intr+0x188/0x200
      irq_thread_fn+0x2c/0x70
      irq_thread+0xfc/0x14c
      kthread+0x11c/0x12c
      ret_from_fork+0x10/0x18
    
    This busy loop naturally lends itself to using a wait queue so that each
    thread that tries to send a message will sleep waiting on the waitqueue
    and only be woken up when a free slot is available. This should make
    things more predictable too because the scheduler will be able to sleep
    tasks that are waiting on a free tcs instead of the busy loop we
    currently have today.
    Reviewed-by: default avatarMaulik Shah <mkshah@codeaurora.org>
    Reviewed-by: default avatarDouglas Anderson <dianders@chromium.org>
    Tested-by: default avatarStanimir Varbanov <stanimir.varbanov@linaro.org>
    Cc: Douglas Anderson <dianders@chromium.org>
    Cc: Maulik Shah <mkshah@codeaurora.org>
    Cc: Lina Iyer <ilina@codeaurora.org>
    Signed-off-by: default avatarStephen Boyd <swboyd@chromium.org>
    Link: https://lore.kernel.org/r/20200724211711.810009-1-sboyd@kernel.orgSigned-off-by: default avatarBjorn Andersson <bjorn.andersson@linaro.org>
    2bc20f3c
rpmh-internal.h 4.59 KB