From 3c728e079d83f581a1f8b7755f6e26087b15c4fb Mon Sep 17 00:00:00 2001 From: Tamas Zsoldos Date: Tue, 5 Jul 2022 16:59:35 +0200 Subject: [PATCH 1/4] coresight: etm4x: add CPU hotplug support for probing etm4x devices cannot be successfully probed when their CPU is offline. For example, when booting with maxcpus=n, ETM probing will fail on CPUs >n, and the probing won't be reattempted once the CPUs come online. This will leave those CPUs unable to make use of ETM. This change adds a mechanism to delay the probing if the corresponding CPU is offline, and to try it again when the CPU comes online. Signed-off-by: Tamas Zsoldos Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20220705145935.24679-1-tamas.zsoldos@arm.com --- .../coresight/coresight-etm4x-core.c | 153 +++++++++++++----- 1 file changed, 113 insertions(+), 40 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c index 80fefaba58ee..9dc0d7f57565 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c @@ -66,10 +66,13 @@ static enum cpuhp_state hp_online; struct etm4_init_arg { unsigned int pid; - struct etmv4_drvdata *drvdata; + struct device *dev; struct csdev_access *csa; }; +static DEFINE_PER_CPU(struct etm4_init_arg *, delayed_probe); +static int etm4_probe_cpu(unsigned int cpu); + /* * Check if TRCSSPCICRn(i) is implemented for a given instance. * @@ -1085,7 +1088,7 @@ static void etm4_init_arch_data(void *info) struct csdev_access *csa; int i; - drvdata = init_arg->drvdata; + drvdata = dev_get_drvdata(init_arg->dev); csa = init_arg->csa; /* @@ -1528,7 +1531,7 @@ void etm4_config_trace_mode(struct etmv4_config *config) static int etm4_online_cpu(unsigned int cpu) { if (!etmdrvdata[cpu]) - return 0; + return etm4_probe_cpu(cpu); if (etmdrvdata[cpu]->boot_enable && !etmdrvdata[cpu]->sticky_enable) coresight_enable(etmdrvdata[cpu]->csdev); @@ -1904,48 +1907,20 @@ static void etm4_pm_clear(void) } } -static int etm4_probe(struct device *dev, void __iomem *base, u32 etm_pid) +static int etm4_add_coresight_dev(struct etm4_init_arg *init_arg) { int ret; struct coresight_platform_data *pdata = NULL; - struct etmv4_drvdata *drvdata; + struct device *dev = init_arg->dev; + struct etmv4_drvdata *drvdata = dev_get_drvdata(dev); struct coresight_desc desc = { 0 }; - struct etm4_init_arg init_arg = { 0 }; u8 major, minor; char *type_name; - drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); if (!drvdata) - return -ENOMEM; + return -EINVAL; - dev_set_drvdata(dev, drvdata); - - if (pm_save_enable == PARAM_PM_SAVE_FIRMWARE) - pm_save_enable = coresight_loses_context_with_cpu(dev) ? - PARAM_PM_SAVE_SELF_HOSTED : PARAM_PM_SAVE_NEVER; - - if (pm_save_enable != PARAM_PM_SAVE_NEVER) { - drvdata->save_state = devm_kmalloc(dev, - sizeof(struct etmv4_save_state), GFP_KERNEL); - if (!drvdata->save_state) - return -ENOMEM; - } - - drvdata->base = base; - - spin_lock_init(&drvdata->spinlock); - - drvdata->cpu = coresight_get_cpu(dev); - if (drvdata->cpu < 0) - return drvdata->cpu; - - init_arg.drvdata = drvdata; - init_arg.csa = &desc.access; - init_arg.pid = etm_pid; - - if (smp_call_function_single(drvdata->cpu, - etm4_init_arch_data, &init_arg, 1)) - dev_err(dev, "ETM arch init failed\n"); + desc.access = *init_arg->csa; if (!drvdata->arch) return -EINVAL; @@ -2016,6 +1991,68 @@ static int etm4_probe(struct device *dev, void __iomem *base, u32 etm_pid) return 0; } +static int etm4_probe(struct device *dev, void __iomem *base, u32 etm_pid) +{ + struct etmv4_drvdata *drvdata; + struct csdev_access access = { 0 }; + struct etm4_init_arg init_arg = { 0 }; + struct etm4_init_arg *delayed; + + drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); + if (!drvdata) + return -ENOMEM; + + dev_set_drvdata(dev, drvdata); + + if (pm_save_enable == PARAM_PM_SAVE_FIRMWARE) + pm_save_enable = coresight_loses_context_with_cpu(dev) ? + PARAM_PM_SAVE_SELF_HOSTED : PARAM_PM_SAVE_NEVER; + + if (pm_save_enable != PARAM_PM_SAVE_NEVER) { + drvdata->save_state = devm_kmalloc(dev, + sizeof(struct etmv4_save_state), GFP_KERNEL); + if (!drvdata->save_state) + return -ENOMEM; + } + + drvdata->base = base; + + spin_lock_init(&drvdata->spinlock); + + drvdata->cpu = coresight_get_cpu(dev); + if (drvdata->cpu < 0) + return drvdata->cpu; + + init_arg.dev = dev; + init_arg.csa = &access; + init_arg.pid = etm_pid; + + /* + * Serialize against CPUHP callbacks to avoid race condition + * between the smp call and saving the delayed probe. + */ + cpus_read_lock(); + if (smp_call_function_single(drvdata->cpu, + etm4_init_arch_data, &init_arg, 1)) { + /* The CPU was offline, try again once it comes online. */ + delayed = devm_kmalloc(dev, sizeof(*delayed), GFP_KERNEL); + if (!delayed) { + cpus_read_unlock(); + return -ENOMEM; + } + + *delayed = init_arg; + + per_cpu(delayed_probe, drvdata->cpu) = delayed; + + cpus_read_unlock(); + return 0; + } + cpus_read_unlock(); + + return etm4_add_coresight_dev(&init_arg); +} + static int etm4_probe_amba(struct amba_device *adev, const struct amba_id *id) { void __iomem *base; @@ -2054,6 +2091,35 @@ static int etm4_probe_platform_dev(struct platform_device *pdev) return ret; } +static int etm4_probe_cpu(unsigned int cpu) +{ + int ret; + struct etm4_init_arg init_arg; + struct csdev_access access = { 0 }; + struct etm4_init_arg *iap = *this_cpu_ptr(&delayed_probe); + + if (!iap) + return 0; + + init_arg = *iap; + devm_kfree(init_arg.dev, iap); + *this_cpu_ptr(&delayed_probe) = NULL; + + ret = pm_runtime_resume_and_get(init_arg.dev); + if (ret < 0) { + dev_err(init_arg.dev, "Failed to get PM runtime!\n"); + return 0; + } + + init_arg.csa = &access; + etm4_init_arch_data(&init_arg); + + etm4_add_coresight_dev(&init_arg); + + pm_runtime_put(init_arg.dev); + return 0; +} + static struct amba_cs_uci_id uci_id_etm4[] = { { /* ETMv4 UCI data */ @@ -2068,16 +2134,20 @@ static void clear_etmdrvdata(void *info) int cpu = *(int *)info; etmdrvdata[cpu] = NULL; + per_cpu(delayed_probe, cpu) = NULL; } static int __exit etm4_remove_dev(struct etmv4_drvdata *drvdata) { - etm_perf_symlink(drvdata->csdev, false); + bool had_delayed_probe; /* * Taking hotplug lock here to avoid racing between etm4_remove_dev() * and CPU hotplug call backs. */ cpus_read_lock(); + + had_delayed_probe = per_cpu(delayed_probe, drvdata->cpu); + /* * The readers for etmdrvdata[] are CPU hotplug call backs * and PM notification call backs. Change etmdrvdata[i] on @@ -2085,12 +2155,15 @@ static int __exit etm4_remove_dev(struct etmv4_drvdata *drvdata) * inside one call back function. */ if (smp_call_function_single(drvdata->cpu, clear_etmdrvdata, &drvdata->cpu, 1)) - etmdrvdata[drvdata->cpu] = NULL; + clear_etmdrvdata(&drvdata->cpu); cpus_read_unlock(); - cscfg_unregister_csdev(drvdata->csdev); - coresight_unregister(drvdata->csdev); + if (!had_delayed_probe) { + etm_perf_symlink(drvdata->csdev, false); + cscfg_unregister_csdev(drvdata->csdev); + coresight_unregister(drvdata->csdev); + } return 0; } From 20ee8c223f792947378196307d8e707c9cdc2d61 Mon Sep 17 00:00:00 2001 From: Yang Shen Date: Tue, 22 Nov 2022 17:03:55 +0800 Subject: [PATCH 2/4] coresight: trbe: remove cpuhp instance node before remove cpuhp state cpuhp_state_add_instance() and cpuhp_state_remove_instance() should be used in pairs. Or there will lead to the warn on cpuhp_remove_multi_state() since the cpuhp_step list is not empty. The following is the error log with 'rmmod coresight-trbe': Error: Removing state 215 which has instances left. Call trace: __cpuhp_remove_state_cpuslocked+0x144/0x160 __cpuhp_remove_state+0xac/0x100 arm_trbe_device_remove+0x2c/0x60 [coresight_trbe] platform_remove+0x34/0x70 device_remove+0x54/0x90 device_release_driver_internal+0x1e4/0x250 driver_detach+0x5c/0xb0 bus_remove_driver+0x64/0xc0 driver_unregister+0x3c/0x70 platform_driver_unregister+0x20/0x30 arm_trbe_exit+0x1c/0x658 [coresight_trbe] __arm64_sys_delete_module+0x1ac/0x24c invoke_syscall+0x50/0x120 el0_svc_common.constprop.0+0x58/0x1a0 do_el0_svc+0x38/0xd0 el0_svc+0x2c/0xc0 el0t_64_sync_handler+0x1ac/0x1b0 el0t_64_sync+0x19c/0x1a0 ---[ end trace 0000000000000000 ]--- Fixes: 3fbf7f011f24 ("coresight: sink: Add TRBE driver") Reviewed-by: Anshuman Khandual Signed-off-by: Yang Shen Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20221122090355.23533-1-shenyang39@huawei.com --- drivers/hwtracing/coresight/coresight-trbe.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c index 2b386bb848f8..1fc4fd79a1c6 100644 --- a/drivers/hwtracing/coresight/coresight-trbe.c +++ b/drivers/hwtracing/coresight/coresight-trbe.c @@ -1434,6 +1434,7 @@ static int arm_trbe_probe_cpuhp(struct trbe_drvdata *drvdata) static void arm_trbe_remove_cpuhp(struct trbe_drvdata *drvdata) { + cpuhp_state_remove_instance(drvdata->trbe_online, &drvdata->hotplug_node); cpuhp_remove_multi_state(drvdata->trbe_online); } From 3dc228b35387803d9c43ed1b098aabb1d3ae9c7d Mon Sep 17 00:00:00 2001 From: Mike Leach Date: Wed, 23 Nov 2022 19:38:18 +0000 Subject: [PATCH 3/4] coresight: cti: Fix null pointer error on CTI init before ETM When CTI is discovered first then the function coresight_set_assoc_ectdev_mutex() is called to set the association between CTI and ETM device. Recent lockdep fix passes a null pointer. This patch passes the correct pointer. Before patch: log of boot oops sequence with CTI discovered first: [ 12.424091] cs_system_cfg: CoreSight Configuration manager initialised [ 12.483474] coresight cti_sys0: CTI initialized [ 12.488109] coresight cti_sys1: CTI initialized [ 12.503594] coresight cti_cpu0: CTI initialized [ 12.517877] coresight-cpu-debug 850000.debug: Coresight debug-CPU0 initialized [ 12.523479] coresight-cpu-debug 852000.debug: Coresight debug-CPU1 initialized [ 12.529926] coresight-cpu-debug 854000.debug: Coresight debug-CPU2 initialized [ 12.541808] coresight stm0: STM32 initialized [ 12.544421] coresight-cpu-debug 856000.debug: Coresight debug-CPU3 initialized [ 12.585639] coresight cti_cpu1: CTI initialized [ 12.614028] coresight cti_cpu2: CTI initialized [ 12.631679] CSCFG registered etm0 [ 12.633920] coresight etm0: CPU0: etm v4.0 initialized [ 12.656392] coresight cti_cpu3: CTI initialized ... [ 12.708383] Unable to handle kernel NULL pointer dereference at virtual address 0000000000000348 ... [ 12.755094] Internal error: Oops: 0000000096000044 [#1] SMP [ 12.761817] Modules linked in: coresight_etm4x(+) coresight_tmc coresight_cpu_debug coresight_replicator coresight_funnel coresight_cti coresight_tpiu coresight_stm coresight [ 12.767210] CPU: 3 PID: 1346 Comm: systemd-udevd Not tainted 6.1.0-rc3tid-v6tid-v6-235166-gf7f7d7a2204a-dirty #498 [ 12.782827] Hardware name: Qualcomm Technologies, Inc. APQ 8016 SBC (DT) [ 12.793154] pstate: 60000005 (nZCv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 12.800010] pc : coresight_set_assoc_ectdev_mutex+0x30/0x50 [coresight] [ 12.806694] lr : coresight_set_assoc_ectdev_mutex+0x30/0x50 [coresight] ... [ 12.885064] Call trace: [ 12.892352] coresight_set_assoc_ectdev_mutex+0x30/0x50 [coresight] [ 12.894693] cti_add_assoc_to_csdev+0x144/0x1b0 [coresight_cti] [ 12.900943] coresight_register+0x2c8/0x320 [coresight] [ 12.906844] etm4_add_coresight_dev.isra.27+0x148/0x280 [coresight_etm4x] [ 12.912056] etm4_probe+0x144/0x1c0 [coresight_etm4x] [ 12.918998] etm4_probe_amba+0x40/0x78 [coresight_etm4x] [ 12.924032] amba_probe+0x11c/0x1f0 After patch: similar log [ 12.444467] cs_system_cfg: CoreSight Configuration manager initialised [ 12.456329] coresight-cpu-debug 850000.debug: Coresight debug-CPU0 initialized [ 12.456754] coresight-cpu-debug 852000.debug: Coresight debug-CPU1 initialized [ 12.469672] coresight-cpu-debug 854000.debug: Coresight debug-CPU2 initialized [ 12.476098] coresight-cpu-debug 856000.debug: Coresight debug-CPU3 initialized [ 12.532409] coresight stm0: STM32 initialized [ 12.533708] coresight cti_sys0: CTI initialized [ 12.539478] coresight cti_sys1: CTI initialized [ 12.550106] coresight cti_cpu0: CTI initialized [ 12.633931] coresight cti_cpu1: CTI initialized [ 12.634664] coresight cti_cpu2: CTI initialized [ 12.638090] coresight cti_cpu3: CTI initialized [ 12.721136] CSCFG registered etm0 ... [ 12.762643] CSCFG registered etm1 [ 12.762666] coresight etm1: CPU1: etm v4.0 initialized [ 12.776258] CSCFG registered etm2 [ 12.776282] coresight etm2: CPU2: etm v4.0 initialized [ 12.784357] CSCFG registered etm3 [ 12.785455] coresight etm3: CPU3: etm v4.0 initialized Error can also be triggered by manually starting the modules using modprobe in the following order: root@linaro-developer:/home/linaro/cs-mods# modprobe coresight root@linaro-developer:/home/linaro/cs-mods# modprobe coresight-cti root@linaro-developer:/home/linaro/cs-mods# modprobe coresight-etm4x Tested on Dragonboard DB410c Applies to coresight/next Fixes: 23722fb46725 ("coresight: Fix possible deadlock with lock dependency") Signed-off-by: Mike Leach Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20221123193818.6253-1-mike.leach@linaro.org --- drivers/hwtracing/coresight/coresight-cti-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hwtracing/coresight/coresight-cti-core.c b/drivers/hwtracing/coresight/coresight-cti-core.c index c6e8c6542f24..d2cf4f4848e1 100644 --- a/drivers/hwtracing/coresight/coresight-cti-core.c +++ b/drivers/hwtracing/coresight/coresight-cti-core.c @@ -564,7 +564,7 @@ static void cti_add_assoc_to_csdev(struct coresight_device *csdev) * if we found a matching csdev then update the ECT * association pointer for the device with this CTI. */ - coresight_set_assoc_ectdev_mutex(csdev->ect_dev, + coresight_set_assoc_ectdev_mutex(csdev, ect_item->csdev); break; } From c767c34740132ffc478226864a7461493cdc2413 Mon Sep 17 00:00:00 2001 From: Jilin Yuan Date: Wed, 19 Oct 2022 20:49:53 +0800 Subject: [PATCH 4/4] coresight: etm4x: fix repeated words in comments Delete the redundant word 'the'. Signed-off-by: Jilin Yuan Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20221019124953.45885-1-yuanjilin@cdjrlc.com --- drivers/hwtracing/coresight/coresight-etm4x-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c index 9dc0d7f57565..1cc052979e01 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c @@ -1481,7 +1481,7 @@ static int etm4_set_event_filters(struct etmv4_drvdata *drvdata, /* * If filters::ssstatus == 1, trace acquisition was * started but the process was yanked away before the - * the stop address was hit. As such the start/stop + * stop address was hit. As such the start/stop * logic needs to be re-started so that tracing can * resume where it left. *