The work queue is never flushed on module unload, so pending work items can run after coresight-config is cleaned up or the .text section is unloaded. The global workqueue also can't be flushed manually, so change it to a local workqueue and flush it on exit.
The init function needs to be rearranged to fix a similar problem. The Perf PMU can be used as soon as registration succeeds, so move it as late as possible so that the only failure that can follow is coresight- config. Failing to register coresight-config means no flush dependency between coresight-config and the Perf PMU will exist, so it doesn't need to be done.
Assisted-by: Codex:GPT-5.6-Sol Reported-by: sashiko-bot sashiko-bot@kernel.org Fixes: 0bcbf2e30ff2 ("coresight: etm-perf: new PMU driver for ETM tracers") Signed-off-by: James Clark james.clark@linaro.org --- drivers/hwtracing/coresight/coresight-core.c | 28 ++++++++++++++---------- drivers/hwtracing/coresight/coresight-etm-perf.c | 22 +++++++++++++++---- drivers/hwtracing/coresight/coresight-etm-perf.h | 1 + 3 files changed, 36 insertions(+), 15 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c index f7b1308a759c..5e653b08a83d 100644 --- a/drivers/hwtracing/coresight/coresight-core.c +++ b/drivers/hwtracing/coresight/coresight-core.c @@ -2094,31 +2094,31 @@ static int __init coresight_init(void) if (ret) return ret;
- ret = etm_perf_init(); - if (ret) - goto exit_bus_unregister; - /* Register function to be called for panic */ ret = atomic_notifier_chain_register(&panic_notifier_list, &coresight_notifier); if (ret) - goto exit_perf; + goto exit_bus_unregister;
- /* initialise the coresight syscfg API */ - ret = cscfg_init(); + ret = coresight_pm_setup(); if (ret) goto exit_notifier;
- ret = coresight_pm_setup(); + ret = etm_perf_init(); + if (ret) + goto exit_pm; + + /* initialise the coresight syscfg API */ + ret = cscfg_init(); if (!ret) return 0;
- cscfg_exit(); + etm_perf_exit(); +exit_pm: + coresight_pm_cleanup(); exit_notifier: atomic_notifier_chain_unregister(&panic_notifier_list, &coresight_notifier); -exit_perf: - etm_perf_exit(); exit_bus_unregister: bus_unregister(&coresight_bustype); return ret; @@ -2127,6 +2127,12 @@ static int __init coresight_init(void) static void __exit coresight_exit(void) { coresight_pm_cleanup(); + /* + * Flush Perf workqueue before the rest of Coresight is torn down + * because work items touch coresight-config and also require the .text + * to remain loaded. + */ + etm_perf_flush_workqueue(); cscfg_exit(); atomic_notifier_chain_unregister(&panic_notifier_list, &coresight_notifier); diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c index 09b21a711a87..7fb5c3d18bd5 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.c +++ b/drivers/hwtracing/coresight/coresight-etm-perf.c @@ -27,6 +27,7 @@ #include "coresight-trace-id.h"
static struct pmu etm_pmu; +static struct workqueue_struct *etm_free_wq; static bool etm_perf_up;
/* @@ -292,7 +293,7 @@ static void etm_free_aux(void *data) { struct etm_event_data *event_data = data;
- schedule_work(&event_data->work); + queue_work(etm_free_wq, &event_data->work); }
/* @@ -1034,6 +1035,10 @@ int __init etm_perf_init(void) { int ret;
+ etm_free_wq = alloc_workqueue("coresight_etm_free", WQ_UNBOUND, 0); + if (!etm_free_wq) + return -ENOMEM; + etm_pmu.capabilities = (PERF_PMU_CAP_EXCLUSIVE | PERF_PMU_CAP_ITRACE | PERF_PMU_CAP_AUX_PAUSE); @@ -1054,13 +1059,22 @@ int __init etm_perf_init(void) etm_pmu.module = THIS_MODULE;
ret = perf_pmu_register(&etm_pmu, CORESIGHT_ETM_PMU_NAME, -1); - if (ret == 0) - etm_perf_up = true; + if (ret) { + destroy_workqueue(etm_free_wq); + return ret; + }
- return ret; + etm_perf_up = true; + return 0; }
void etm_perf_exit(void) { perf_pmu_unregister(&etm_pmu); + destroy_workqueue(etm_free_wq); +} + +void etm_perf_flush_workqueue(void) +{ + flush_workqueue(etm_free_wq); } diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.h b/drivers/hwtracing/coresight/coresight-etm-perf.h index 24d929428633..86e259cc1adf 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.h +++ b/drivers/hwtracing/coresight/coresight-etm-perf.h @@ -116,5 +116,6 @@ int etm_perf_add_symlink_cscfg(struct device *dev, void etm_perf_del_symlink_cscfg(struct cscfg_config_desc *config_desc); int __init etm_perf_init(void); void etm_perf_exit(void); +void etm_perf_flush_workqueue(void);
#endif