diff options
| author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2026-09-14 13:41:11 +0200 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2026-09-14 13:41:11 +0200 |
| commit | d396b05e7e39b0ed6f6d5553fbaf174228e18bdf (patch) | |
| tree | 23c11525e2514ec13b5ce9abd8e9a57b27ca7e54 /drivers/remoteproc | |
| parent | ffb45b46184f54bf84d95e82df46932294b2031a (diff) | |
| parent | 500df175a7f9e6bc1a9c328590ca5150f84f9ff0 (diff) | |
| download | linux-stable-linux-rolling-stable.tar.gz linux-stable-linux-rolling-stable.zip | |
Merge v7.2.6linux-rolling-stable
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/remoteproc')
| -rw-r--r-- | drivers/remoteproc/qcom_common.c | 4 | ||||
| -rw-r--r-- | drivers/remoteproc/qcom_common.h | 6 | ||||
| -rw-r--r-- | drivers/remoteproc/qcom_q6v5.c | 5 | ||||
| -rw-r--r-- | drivers/remoteproc/qcom_q6v5_adsp.c | 1 | ||||
| -rw-r--r-- | drivers/remoteproc/qcom_q6v5_mss.c | 19 | ||||
| -rw-r--r-- | drivers/remoteproc/qcom_q6v5_pas.c | 68 | ||||
| -rw-r--r-- | drivers/remoteproc/qcom_sysmon.c | 19 | ||||
| -rw-r--r-- | drivers/remoteproc/qcom_wcnss.c | 23 | ||||
| -rw-r--r-- | drivers/remoteproc/remoteproc_core.c | 67 | ||||
| -rw-r--r-- | drivers/remoteproc/remoteproc_sysfs.c | 1 |
10 files changed, 181 insertions, 32 deletions
diff --git a/drivers/remoteproc/qcom_common.c b/drivers/remoteproc/qcom_common.c index e1a955476c9b..5294e327f158 100644 --- a/drivers/remoteproc/qcom_common.c +++ b/drivers/remoteproc/qcom_common.c @@ -253,8 +253,10 @@ void qcom_add_glink_subdev(struct rproc *rproc, struct qcom_rproc_glink *glink, return; glink->ssr_name = kstrdup_const(ssr_name, GFP_KERNEL); - if (!glink->ssr_name) + if (!glink->ssr_name) { + of_node_put(glink->node); return; + } glink->dev = dev; glink->subdev.start = glink_subdev_start; 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..241478ea2978 100644 --- a/drivers/remoteproc/qcom_q6v5.c +++ b/drivers/remoteproc/qcom_q6v5.c @@ -197,12 +197,13 @@ static irqreturn_t q6v5_stop_interrupt(int irq, void *data) */ int qcom_q6v5_request_stop(struct qcom_q6v5 *q6v5, struct qcom_sysmon *sysmon) { + bool was_running = q6v5->running; int ret; q6v5->running = false; - /* Don't perform SMP2P dance if remote isn't running */ - if (q6v5->rproc->state != RPROC_RUNNING || qcom_sysmon_shutdown_acked(sysmon)) + /* A watchdog/fatal IRQ clears running; logical crashes still need a stop. */ + if (!was_running || qcom_sysmon_shutdown_acked(sysmon)) return 0; qcom_smem_state_update_bits(q6v5->state, diff --git a/drivers/remoteproc/qcom_q6v5_adsp.c b/drivers/remoteproc/qcom_q6v5_adsp.c index b5c8d6d38c9c..c81e6c33c747 100644 --- a/drivers/remoteproc/qcom_q6v5_adsp.c +++ b/drivers/remoteproc/qcom_q6v5_adsp.c @@ -355,6 +355,7 @@ static int adsp_map_carveout(struct rproc *rproc) return ret; sid = args.args[0] & SID_MASK_DEFAULT; + of_node_put(args.np); /* Add SID configuration for ADSP Firmware to SMMU */ iova = adsp->mem_phys | (sid << 32); diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c index ae78f5c7c1b6..eb14308e7aef 100644 --- a/drivers/remoteproc/qcom_q6v5_mss.c +++ b/drivers/remoteproc/qcom_q6v5_mss.c @@ -162,6 +162,7 @@ struct rproc_hexagon_res { char **active_clk_names; char **proxy_pd_names; int version; + int ssctl_id; bool need_mem_protection; bool need_pas_mem_setup; bool has_alt_reset; @@ -2191,7 +2192,7 @@ static int q6v5_probe(struct platform_device *pdev) qcom_add_smd_subdev(rproc, &qproc->smd_subdev); qcom_add_pdm_subdev(rproc, &qproc->pdm_subdev); qcom_add_ssr_subdev(rproc, &qproc->ssr_subdev, "mpss"); - qproc->sysmon = qcom_add_sysmon_subdev(rproc, "modem", 0x12); + qproc->sysmon = qcom_add_sysmon_subdev(rproc, "modem", desc->ssctl_id); if (IS_ERR(qproc->sysmon)) { ret = PTR_ERR(qproc->sysmon); goto remove_subdevs; @@ -2271,6 +2272,7 @@ static const struct rproc_hexagon_res sc7180_mss = { .has_ext_cntl_regs = false, .has_vq6 = false, .version = MSS_SC7180, + .ssctl_id = 0x12, }; static const struct rproc_hexagon_res sc7280_mss = { @@ -2301,6 +2303,7 @@ static const struct rproc_hexagon_res sc7280_mss = { .has_ext_cntl_regs = true, .has_vq6 = true, .version = MSS_SC7280, + .ssctl_id = 0x12, }; static const struct rproc_hexagon_res sdm660_mss = { @@ -2334,6 +2337,7 @@ static const struct rproc_hexagon_res sdm660_mss = { .has_ext_cntl_regs = false, .has_vq6 = false, .version = MSS_SDM660, + .ssctl_id = 0x12, }; static const struct rproc_hexagon_res sdm845_mss = { @@ -2371,6 +2375,7 @@ static const struct rproc_hexagon_res sdm845_mss = { .has_ext_cntl_regs = false, .has_vq6 = false, .version = MSS_SDM845, + .ssctl_id = 0x12, }; static const struct rproc_hexagon_res msm8998_mss = { @@ -2404,6 +2409,7 @@ static const struct rproc_hexagon_res msm8998_mss = { .has_ext_cntl_regs = false, .has_vq6 = false, .version = MSS_MSM8998, + .ssctl_id = 0x12, }; static const struct rproc_hexagon_res msm8996_mss = { @@ -2444,6 +2450,7 @@ static const struct rproc_hexagon_res msm8996_mss = { .has_ext_cntl_regs = false, .has_vq6 = false, .version = MSS_MSM8996, + .ssctl_id = 0x12, }; static const struct rproc_hexagon_res mdm9607_mss = { @@ -2479,6 +2486,7 @@ static const struct rproc_hexagon_res mdm9607_mss = { .has_ext_cntl_regs = false, .has_vq6 = false, .version = MSS_MDM9607, + .ssctl_id = 0x22, }; static const struct rproc_hexagon_res msm8909_mss = { @@ -2515,6 +2523,7 @@ static const struct rproc_hexagon_res msm8909_mss = { .has_ext_cntl_regs = false, .has_vq6 = false, .version = MSS_MSM8909, + .ssctl_id = 0x12, }; static const struct rproc_hexagon_res msm8916_mss = { @@ -2562,6 +2571,7 @@ static const struct rproc_hexagon_res msm8916_mss = { .has_ext_cntl_regs = false, .has_vq6 = false, .version = MSS_MSM8916, + .ssctl_id = 0x12, }; static const struct rproc_hexagon_res msm8917_mss = { @@ -2606,6 +2616,7 @@ static const struct rproc_hexagon_res msm8917_mss = { .has_ext_cntl_regs = false, .has_vq6 = false, .version = MSS_MSM8917, + .ssctl_id = 0x12, }; static const struct rproc_hexagon_res msm8937_mss = { @@ -2650,6 +2661,7 @@ static const struct rproc_hexagon_res msm8937_mss = { .has_ext_cntl_regs = false, .has_vq6 = false, .version = MSS_MSM8937, + .ssctl_id = 0x12, }; static const struct rproc_hexagon_res msm8940_mss = { @@ -2694,6 +2706,7 @@ static const struct rproc_hexagon_res msm8940_mss = { .has_ext_cntl_regs = false, .has_vq6 = false, .version = MSS_MSM8940, + .ssctl_id = 0x12, }; static const struct rproc_hexagon_res msm8953_mss = { @@ -2731,6 +2744,7 @@ static const struct rproc_hexagon_res msm8953_mss = { .has_ext_cntl_regs = false, .has_vq6 = false, .version = MSS_MSM8953, + .ssctl_id = 0x12, }; static const struct rproc_hexagon_res msm8974_mss = { @@ -2785,6 +2799,7 @@ static const struct rproc_hexagon_res msm8974_mss = { .has_ext_cntl_regs = false, .has_vq6 = false, .version = MSS_MSM8974, + .ssctl_id = 0x12, }; static const struct rproc_hexagon_res msm8226_mss = { @@ -2824,6 +2839,7 @@ static const struct rproc_hexagon_res msm8226_mss = { .has_ext_cntl_regs = false, .has_vq6 = false, .version = MSS_MSM8226, + .ssctl_id = 0x12, }; static const struct rproc_hexagon_res msm8926_mss = { @@ -2871,6 +2887,7 @@ static const struct rproc_hexagon_res msm8926_mss = { .has_ext_cntl_regs = false, .has_vq6 = false, .version = MSS_MSM8926, + .ssctl_id = 0x12, }; static const struct of_device_id q6v5_of_match[] = { diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c index 7ab896952822..cb3e51d6f7ce 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 { @@ -504,6 +505,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, @@ -512,6 +574,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 = { @@ -523,6 +586,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) @@ -849,6 +913,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 diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c index 4add9037dbd5..5e4a623b8925 100644 --- a/drivers/remoteproc/qcom_wcnss.c +++ b/drivers/remoteproc/qcom_wcnss.c @@ -441,25 +441,31 @@ static void wcnss_release_pds(struct qcom_wcnss *wcnss) } static int wcnss_init_regulators(struct qcom_wcnss *wcnss, - const struct wcnss_vreg_info *info, - int num_vregs, int num_pd_vregs) + const struct wcnss_data *data) { + const struct wcnss_vreg_info *info = data->vregs; struct regulator_bulk_data *bulk; + size_t i, possible_pds = 0, num_vregs = data->num_vregs; int ret; - int i; + + for (i = 0; i < WCNSS_MAX_PDS; i++) + if (data->pd_names[i]) + possible_pds++; /* * If attaching the power domains suceeded we can skip requesting * the regulators for the power domains. For old device trees we need to * reserve extra space to manage them through the regulator interface. */ - if (wcnss->num_pds) { + if (possible_pds >= num_vregs) { + /* Do nothing if vregs do not include PD regulators (pronto-v3) */ + } else if (wcnss->num_pds) { info += wcnss->num_pds; /* Handle single power domain case */ - if (wcnss->num_pds < num_pd_vregs) - num_vregs += num_pd_vregs - wcnss->num_pds; + if (wcnss->num_pds < data->num_pd_vregs) + num_vregs += data->num_pd_vregs - wcnss->num_pds; } else { - num_vregs += num_pd_vregs; + num_vregs += data->num_pd_vregs; } bulk = devm_kcalloc(wcnss->dev, @@ -607,8 +613,7 @@ static int wcnss_probe(struct platform_device *pdev) if (ret && (ret != -ENODATA || !data->num_pd_vregs)) return ret; - ret = wcnss_init_regulators(wcnss, data->vregs, data->num_vregs, - data->num_pd_vregs); + ret = wcnss_init_regulators(wcnss, data); if (ret) goto detach_pds; diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index f003be006b1b..527996e8ecda 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -1668,18 +1668,21 @@ static void rproc_auto_boot_callback(const struct firmware *fw, void *context) release_firmware(fw); } +static void rproc_attach_work(struct work_struct *work) +{ + struct rproc *rproc = container_of(work, struct rproc, attach_work); + + rproc_boot(rproc); +} + static int rproc_trigger_auto_boot(struct rproc *rproc) { int ret; - /* - * Since the remote processor is in a detached state, it has already - * been booted by another entity. As such there is no point in waiting - * for a firmware image to be loaded, we can simply initiate the process - * of attaching to it immediately. - */ - if (rproc->state == RPROC_DETACHED) - return rproc_boot(rproc); + if (rproc->state == RPROC_DETACHED) { + schedule_work(&rproc->attach_work); + return 0; + } /* * We're initiating an asynchronous firmware loading, so we can @@ -1828,6 +1831,11 @@ int rproc_trigger_recovery(struct rproc *rproc) if (ret) return ret; + if (READ_ONCE(rproc->deleting)) { + ret = -ENODEV; + goto unlock_mutex; + } + /* State could have changed before we got the mutex */ if (rproc->state != RPROC_CRASHED) goto unlock_mutex; @@ -1860,6 +1868,11 @@ static void rproc_crash_handler_work(struct work_struct *work) mutex_lock(&rproc->lock); + if (READ_ONCE(rproc->deleting)) { + mutex_unlock(&rproc->lock); + goto out; + } + if (rproc->state == RPROC_CRASHED) { /* handle only the first crash detected */ mutex_unlock(&rproc->lock); @@ -1915,9 +1928,9 @@ int rproc_boot(struct rproc *rproc) return ret; } - if (rproc->state == RPROC_DELETED) { + if (READ_ONCE(rproc->deleting)) { ret = -ENODEV; - dev_err(dev, "can't boot deleted rproc %s\n", rproc->name); + dev_err(dev, "can't boot deleting rproc %s\n", rproc->name); goto unlock_mutex; } @@ -1979,6 +1992,7 @@ EXPORT_SYMBOL(rproc_boot); int rproc_shutdown(struct rproc *rproc) { struct device *dev = &rproc->dev; + bool crashed; int ret; ret = mutex_lock_interruptible(&rproc->lock); @@ -1988,16 +2002,18 @@ int rproc_shutdown(struct rproc *rproc) } if (rproc->state != RPROC_RUNNING && - rproc->state != RPROC_ATTACHED) { + rproc->state != RPROC_ATTACHED && + rproc->state != RPROC_CRASHED) { ret = -EINVAL; goto out; } + crashed = rproc->state == RPROC_CRASHED; /* if the remote proc is still needed, bail out */ if (!atomic_dec_and_test(&rproc->power)) goto out; - ret = rproc_stop(rproc, false); + ret = rproc_stop(rproc, crashed); if (ret) { atomic_inc(&rproc->power); goto out; @@ -2506,7 +2522,9 @@ struct rproc *rproc_alloc(struct device *dev, const char *name, INIT_LIST_HEAD(&rproc->subdevs); INIT_LIST_HEAD(&rproc->dump_segments); + INIT_WORK(&rproc->attach_work, rproc_attach_work); INIT_WORK(&rproc->crash_handler, rproc_crash_handler_work); + spin_lock_init(&rproc->crash_handler_lock); rproc->state = RPROC_OFFLINE; @@ -2570,16 +2588,21 @@ EXPORT_SYMBOL(rproc_put); */ int rproc_del(struct rproc *rproc) { + unsigned long flags; + if (!rproc) return -EINVAL; + spin_lock_irqsave(&rproc->crash_handler_lock, flags); + WRITE_ONCE(rproc->deleting, true); + spin_unlock_irqrestore(&rproc->crash_handler_lock, flags); + + if (cancel_work_sync(&rproc->crash_handler)) + pm_relax(rproc->dev.parent); + /* TODO: make sure this works with rproc->power > 1 */ rproc_shutdown(rproc); - mutex_lock(&rproc->lock); - rproc->state = RPROC_DELETED; - mutex_unlock(&rproc->lock); - rproc_delete_debug_dir(rproc); /* the rproc is downref'ed as soon as it's removed from the klist */ @@ -2691,18 +2714,26 @@ EXPORT_SYMBOL(rproc_get_by_child); */ void rproc_report_crash(struct rproc *rproc, enum rproc_crash_type type) { + unsigned long flags; + if (!rproc) { pr_err("NULL rproc pointer\n"); return; } + spin_lock_irqsave(&rproc->crash_handler_lock, flags); + if (READ_ONCE(rproc->deleting)) { + spin_unlock_irqrestore(&rproc->crash_handler_lock, flags); + return; + } + /* Prevent suspend while the remoteproc is being recovered */ pm_stay_awake(rproc->dev.parent); + queue_work(rproc_recovery_wq, &rproc->crash_handler); + spin_unlock_irqrestore(&rproc->crash_handler_lock, flags); dev_err(&rproc->dev, "crash detected in %s: type %s\n", rproc->name, rproc_crash_to_string(type)); - - queue_work(rproc_recovery_wq, &rproc->crash_handler); } EXPORT_SYMBOL(rproc_report_crash); diff --git a/drivers/remoteproc/remoteproc_sysfs.c b/drivers/remoteproc/remoteproc_sysfs.c index 138e752c5e4e..925b0cdbe577 100644 --- a/drivers/remoteproc/remoteproc_sysfs.c +++ b/drivers/remoteproc/remoteproc_sysfs.c @@ -168,7 +168,6 @@ static const char * const rproc_state_string[] = { [RPROC_SUSPENDED] = "suspended", [RPROC_RUNNING] = "running", [RPROC_CRASHED] = "crashed", - [RPROC_DELETED] = "deleted", [RPROC_ATTACHED] = "attached", [RPROC_DETACHED] = "detached", [RPROC_LAST] = "invalid", |
