On 6/24/2026 4:08 PM, Mukesh Ojha wrote:
> On Tue, Jun 23, 2026 at 03:05:21AM -0700, Jingyi Wang wrote:
>> Subsystems can be brought out of reset by entities such as bootloaders.
>> As the irq enablement could be later than subsystem bring up, the state
>> of subsystem should be checked by reading SMP2P bits.
>>
>> A new qcom_pas_attach() function is introduced. if crash state is detected
>> for the subsystem, rproc_report_crash() is called. If the ready state is
>> detected meanwhile stop state is not detected, it will be marked as
>> "attached", otherwise it could be the early boot feature is not supported
>> by other entities or it has already been stopped. In above cases, the
>> state will be marked as RPROC_OFFLINE so that the PAS driver can load the
>> firmware and start the remoteproc.
>>
>> Co-developed-by: Gokul Krishna Krishnakumar 
>> <[email protected]>
>> Signed-off-by: Gokul Krishna Krishnakumar 
>> <[email protected]>
>> Tested-by: Shawn Guo <[email protected]>
>> Signed-off-by: Jingyi Wang <[email protected]>
>> ---
>>  drivers/remoteproc/qcom_common.h   |  6 ++++
>>  drivers/remoteproc/qcom_q6v5.c     |  3 +-
>>  drivers/remoteproc/qcom_q6v5_pas.c | 68 
>> ++++++++++++++++++++++++++++++++++++++
>>  drivers/remoteproc/qcom_sysmon.c   | 19 +++++++++++
>>  4 files changed, 95 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/remoteproc/qcom_common.h 
>> b/drivers/remoteproc/qcom_common.h
>> index b07fbaa091a0..b0e7e336d363 100644
>> --- a/drivers/remoteproc/qcom_common.h
>> +++ b/drivers/remoteproc/qcom_common.h
>> @@ -68,6 +68,7 @@ struct qcom_sysmon *qcom_add_sysmon_subdev(struct rproc 
>> *rproc,
>>                                         int ssctl_instance);
>>  void qcom_remove_sysmon_subdev(struct qcom_sysmon *sysmon);
>>  bool qcom_sysmon_shutdown_acked(struct qcom_sysmon *sysmon);
>> +bool qcom_sysmon_shutdown_irq_state(struct qcom_sysmon *sysmon);
>>  #else
>>  static inline struct qcom_sysmon *qcom_add_sysmon_subdev(struct rproc 
>> *rproc,
>>                                                       const char *name,
>> @@ -84,6 +85,11 @@ static inline bool qcom_sysmon_shutdown_acked(struct 
>> qcom_sysmon *sysmon)
>>  {
>>      return false;
>>  }
>> +
>> +static inline bool qcom_sysmon_shutdown_irq_state(struct qcom_sysmon 
>> *sysmon)
>> +{
>> +    return false;
>> +}
>>  #endif
>>  
>>  #endif
>> diff --git a/drivers/remoteproc/qcom_q6v5.c b/drivers/remoteproc/qcom_q6v5.c
>> index 58d5b85e58cd..a11d8ace554b 100644
>> --- a/drivers/remoteproc/qcom_q6v5.c
>> +++ b/drivers/remoteproc/qcom_q6v5.c
>> @@ -202,7 +202,8 @@ int qcom_q6v5_request_stop(struct qcom_q6v5 *q6v5, 
>> struct qcom_sysmon *sysmon)
>>      q6v5->running = false;
>>  
>>      /* Don't perform SMP2P dance if remote isn't running */
>> -    if (q6v5->rproc->state != RPROC_RUNNING || 
>> qcom_sysmon_shutdown_acked(sysmon))
>> +    if ((q6v5->rproc->state != RPROC_RUNNING && q6v5->rproc->state != 
>> RPROC_ATTACHED) ||
>> +        qcom_sysmon_shutdown_acked(sysmon))
>>              return 0;
>>  
>>      qcom_smem_state_update_bits(q6v5->state,
>> diff --git a/drivers/remoteproc/qcom_q6v5_pas.c 
>> b/drivers/remoteproc/qcom_q6v5_pas.c
>> index 808e9609988d..8a0bb4b2e71c 100644
>> --- a/drivers/remoteproc/qcom_q6v5_pas.c
>> +++ b/drivers/remoteproc/qcom_q6v5_pas.c
>> @@ -60,6 +60,7 @@ struct qcom_pas_data {
>>      int region_assign_count;
>>      bool region_assign_shared;
>>      int region_assign_vmid;
>> +    bool early_boot;
>>  };
>>  
>>  struct qcom_pas {
>> @@ -507,6 +508,67 @@ static unsigned long qcom_pas_panic(struct rproc *rproc)
>>      return qcom_q6v5_panic(&pas->q6v5);
>>  }
>>  
>> +static int qcom_pas_attach(struct rproc *rproc)
>> +{
>> +    struct qcom_pas *pas = rproc->priv;
>> +    bool ready_state;
>> +    bool crash_state;
>> +    bool stop_state;
>> +    int ret;
>> +
>> +    pas->q6v5.handover_issued = true;
>> +    enable_irq(pas->q6v5.handover_irq);
>> +
>> +    pas->q6v5.running = true;
>> +    ret = irq_get_irqchip_state(pas->q6v5.fatal_irq,
>> +                                IRQCHIP_STATE_LINE_LEVEL, &crash_state);
>> +    if (ret)
>> +            goto disable_running;
>> +
>> +    if (crash_state) {
>> +            dev_err(pas->dev, "Subsystem has crashed before driver 
>> probe\n");
>> +            rproc_report_crash(rproc, RPROC_FATAL_ERROR);
>> +            ret = -EINVAL;
>> +            goto disable_running;
>> +    }
>> +
>> +    ret = irq_get_irqchip_state(pas->q6v5.stop_irq,
>> +                                IRQCHIP_STATE_LINE_LEVEL, &stop_state);
>> +    if (ret)
>> +            goto disable_running;
>> +
>> +    if (stop_state || qcom_sysmon_shutdown_irq_state(pas->sysmon)) {
>> +            dev_info(pas->dev, "Subsystem found stop state set. Falling 
>> back to start.\n");
>> +            goto unroll_attach;
>> +    }
>> +
>> +    ret = irq_get_irqchip_state(pas->q6v5.ready_irq,
>> +                                IRQCHIP_STATE_LINE_LEVEL, &ready_state);
>> +    if (ret)
>> +            goto disable_running;
>> +
>> +    if (unlikely(!ready_state)) {
>> +            /*
>> +             * The bootloader may not support early boot, mark the state as
>> +             * RPROC_OFFLINE so that the PAS driver can load the firmware 
>> and
>> +             * start the remoteproc.
>> +             */
>> +            dev_err(pas->dev, "Failed to get subsystem ready interrupt\n");
>> +            goto unroll_attach;
>> +    }
>> +
>> +    return 0;
>> +
>> +unroll_attach:
>> +    pas->rproc->state = RPROC_OFFLINE;
>> +    ret = -EINVAL;
>> +disable_running:
>> +    disable_irq(pas->q6v5.handover_irq);
>> +    pas->q6v5.running = false;
>> +
>> +    return ret;
>> +}
>> +
>>  static const struct rproc_ops qcom_pas_ops = {
>>      .unprepare = qcom_pas_unprepare,
>>      .start = qcom_pas_start,
>> @@ -515,6 +577,7 @@ static const struct rproc_ops qcom_pas_ops = {
>>      .parse_fw = qcom_pas_parse_firmware,
>>      .load = qcom_pas_load,
>>      .panic = qcom_pas_panic,
>> +    .attach = qcom_pas_attach,
>>  };
>>  
>>  static const struct rproc_ops qcom_pas_minidump_ops = {
>> @@ -526,6 +589,7 @@ static const struct rproc_ops qcom_pas_minidump_ops = {
>>      .load = qcom_pas_load,
>>      .panic = qcom_pas_panic,
>>      .coredump = qcom_pas_minidump,
>> +    .attach = qcom_pas_attach,
>>  };
>>  
>>  static int qcom_pas_init_clock(struct qcom_pas *pas)
>> @@ -852,6 +916,10 @@ static int qcom_pas_probe(struct platform_device *pdev)
>>  
>>      pas->pas_ctx->use_tzmem = rproc->has_iommu;
>>      pas->dtb_pas_ctx->use_tzmem = rproc->has_iommu;
>> +
>> +    if (desc->early_boot)
>> +            pas->rproc->state = RPROC_DETACHED;
>> +
>>      ret = rproc_add(rproc);
>>      if (ret)
>>              goto remove_ssr_sysmon;
>> diff --git a/drivers/remoteproc/qcom_sysmon.c 
>> b/drivers/remoteproc/qcom_sysmon.c
>> index 913e3b750a86..a0830a48b1f4 100644
>> --- a/drivers/remoteproc/qcom_sysmon.c
>> +++ b/drivers/remoteproc/qcom_sysmon.c
>> @@ -736,6 +736,25 @@ bool qcom_sysmon_shutdown_acked(struct qcom_sysmon 
>> *sysmon)
>>  }
>>  EXPORT_SYMBOL_GPL(qcom_sysmon_shutdown_acked);
>>  
>> +bool qcom_sysmon_shutdown_irq_state(struct qcom_sysmon *sysmon)
>> +{
>> +    bool shutdown_state;
>> +    int ret;
>> +
>> +    if (!sysmon)
>> +            return false;
>> +
>> +    ret = irq_get_irqchip_state(sysmon->shutdown_irq,
>> +                                IRQCHIP_STATE_LINE_LEVEL, &shutdown_state);
>> +    if (ret) {
>> +            dev_warn(sysmon->dev, "failed to get shutdown_state: %d\n", 
>> ret);
>> +            return false;
>> +    }
>> +
>> +    return shutdown_state;
>> +}
>> +EXPORT_SYMBOL_GPL(qcom_sysmon_shutdown_irq_state);
>> +
>>  /**
>>   * sysmon_probe() - probe sys_mon channel
>>   * @rpdev:  rpmsg device handle
>>
>> -- 
>> 2.34.1
>>
> 
> I tested the series on Hawi., it works but unsure about newly introduced
> stop and shutdown status checking why is it required ? I think, you are
> checking this for sanity if it is left some random state by the boot
> loader..

The stop and shutdown status checking is to address a valid scenario
which Stephan brought out in previous comments [1]. The more improved
robustness for rproc_attach fail cases including Ping-pong is at [2].

[1] https://lore.kernel.org/all/[email protected]/
[2]
https://lore.kernel.org/all/[email protected]/

> 
> Tested-by: Mukesh Ojha <[email protected]>
> 


-- 
Thx and BRs,
Aiqun(Maria) Yu

Reply via email to