diff options
Diffstat (limited to 'drivers/hwtracing/coresight/coresight-cpu-debug.c')
| -rw-r--r-- | drivers/hwtracing/coresight/coresight-cpu-debug.c | 187 |
1 files changed, 138 insertions, 49 deletions
diff --git a/drivers/hwtracing/coresight/coresight-cpu-debug.c b/drivers/hwtracing/coresight/coresight-cpu-debug.c index 45b2460f3166..5f21366406aa 100644 --- a/drivers/hwtracing/coresight/coresight-cpu-debug.c +++ b/drivers/hwtracing/coresight/coresight-cpu-debug.c @@ -4,6 +4,7 @@ * * Author: Leo Yan <leo.yan@linaro.org> */ +#include <linux/acpi.h> #include <linux/amba/bus.h> #include <linux/coresight.h> #include <linux/cpu.h> @@ -17,6 +18,8 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/moduleparam.h> +#include <linux/panic_notifier.h> +#include <linux/platform_device.h> #include <linux/pm_qos.h> #include <linux/slab.h> #include <linux/smp.h> @@ -83,6 +86,7 @@ #define DEBUG_WAIT_TIMEOUT 32000 struct debug_drvdata { + struct clk *pclk; void __iomem *base; struct device *dev; int cpu; @@ -104,7 +108,7 @@ static DEFINE_PER_CPU(struct debug_drvdata *, debug_drvdata); static int debug_count; static struct dentry *debug_debugfs_dir; -static bool debug_enable; +static bool debug_enable = IS_ENABLED(CONFIG_CORESIGHT_CPU_DEBUG_DEFAULT_ON); module_param_named(enable, debug_enable, bool, 0600); MODULE_PARM_DESC(enable, "Control to enable coresight CPU debug functionality"); @@ -346,10 +350,10 @@ static void debug_init_arch_data(void *info) switch (mode) { case EDDEVID_IMPL_FULL: drvdata->edvidsr_present = true; - /* Fall through */ + fallthrough; case EDDEVID_IMPL_EDPCSR_EDCIDSR: drvdata->edcidsr_present = true; - /* Fall through */ + fallthrough; case EDDEVID_IMPL_EDPCSR: /* * In ARM DDI 0487A.k, the EDDEVID1.PCSROffset is used to @@ -379,9 +383,10 @@ static int debug_notifier_call(struct notifier_block *self, int cpu; struct debug_drvdata *drvdata; - mutex_lock(&debug_lock); + /* Bail out if we can't acquire the mutex or the functionality is off */ + if (!mutex_trylock(&debug_lock)) + return NOTIFY_DONE; - /* Bail out if the functionality is disabled */ if (!debug_enable) goto skip_dump; @@ -400,7 +405,7 @@ static int debug_notifier_call(struct notifier_block *self, skip_dump: mutex_unlock(&debug_lock); - return 0; + return NOTIFY_DONE; } static struct notifier_block debug_notifier = { @@ -525,23 +530,12 @@ static const struct file_operations debug_func_knob_fops = { static int debug_func_init(void) { - struct dentry *file; int ret; /* Create debugfs node */ debug_debugfs_dir = debugfs_create_dir("coresight_cpu_debug", NULL); - if (!debug_debugfs_dir) { - pr_err("%s: unable to create debugfs directory\n", __func__); - return -ENOMEM; - } - - file = debugfs_create_file("enable", 0644, debug_debugfs_dir, NULL, - &debug_func_knob_fops); - if (!file) { - pr_err("%s: unable to create enable knob file\n", __func__); - ret = -ENOMEM; - goto err; - } + debugfs_create_file("enable", 0644, debug_debugfs_dir, NULL, + &debug_func_knob_fops); /* Register function to be called for panic */ ret = atomic_notifier_chain_register(&panic_notifier_list, @@ -566,41 +560,44 @@ static void debug_func_exit(void) debugfs_remove_recursive(debug_debugfs_dir); } -static int debug_probe(struct amba_device *adev, const struct amba_id *id) +static int __debug_probe(struct device *dev, struct resource *res) { - void __iomem *base; - struct device *dev = &adev->dev; struct debug_drvdata *drvdata; - struct resource *res = &adev->res; - struct device_node *np = adev->dev.of_node; + void __iomem *base; int ret; drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); if (!drvdata) return -ENOMEM; - drvdata->cpu = np ? of_coresight_get_cpu(np) : 0; + dev_set_drvdata(dev, drvdata); + + ret = coresight_get_enable_clocks(dev, &drvdata->pclk, NULL); + if (ret) + return ret; + + drvdata->cpu = coresight_get_cpu(dev); + if (drvdata->cpu < 0) + return drvdata->cpu; + if (per_cpu(debug_drvdata, drvdata->cpu)) { dev_err(dev, "CPU%d drvdata has already been initialized\n", drvdata->cpu); return -EBUSY; } - drvdata->dev = &adev->dev; - amba_set_drvdata(adev, drvdata); - - /* Validity for the resource is already checked by the AMBA core */ + drvdata->dev = dev; base = devm_ioremap_resource(dev, res); if (IS_ERR(base)) return PTR_ERR(base); drvdata->base = base; - get_online_cpus(); + cpus_read_lock(); per_cpu(debug_drvdata, drvdata->cpu) = drvdata; ret = smp_call_function_single(drvdata->cpu, debug_init_arch_data, drvdata, 1); - put_online_cpus(); + cpus_read_unlock(); if (ret) { dev_err(dev, "CPU%d debug arch init failed\n", drvdata->cpu); @@ -636,10 +633,14 @@ err: return ret; } -static int debug_remove(struct amba_device *adev) +static int debug_probe(struct amba_device *adev, const struct amba_id *id) +{ + return __debug_probe(&adev->dev, &adev->res); +} + +static void __debug_remove(struct device *dev) { - struct device *dev = &adev->dev; - struct debug_drvdata *drvdata = amba_get_drvdata(adev); + struct debug_drvdata *drvdata = dev_get_drvdata(dev); per_cpu(debug_drvdata, drvdata->cpu) = NULL; @@ -651,26 +652,34 @@ static int debug_remove(struct amba_device *adev) if (!--debug_count) debug_func_exit(); +} - return 0; +static void debug_remove(struct amba_device *adev) +{ + __debug_remove(&adev->dev); } +static const struct amba_cs_uci_id uci_id_debug[] = { + { + /* CPU Debug UCI data */ + .devarch = 0x47706a15, + .devarch_mask = 0xfff0ffff, + .devtype = 0x00000015, + } +}; + static const struct amba_id debug_ids[] = { - { /* Debug for Cortex-A53 */ - .id = 0x000bbd03, - .mask = 0x000fffff, - }, - { /* Debug for Cortex-A57 */ - .id = 0x000bbd07, - .mask = 0x000fffff, - }, - { /* Debug for Cortex-A72 */ - .id = 0x000bbd08, - .mask = 0x000fffff, - }, - { 0, 0 }, + CS_AMBA_ID(0x000bbd03), /* Cortex-A53 */ + CS_AMBA_ID(0x000bbd07), /* Cortex-A57 */ + CS_AMBA_ID(0x000bbd08), /* Cortex-A72 */ + CS_AMBA_ID(0x000bbd09), /* Cortex-A73 */ + CS_AMBA_UCI_ID(0x000f0205, uci_id_debug), /* Qualcomm Kryo */ + CS_AMBA_UCI_ID(0x000f0211, uci_id_debug), /* Qualcomm Kryo */ + {}, }; +MODULE_DEVICE_TABLE(amba, debug_ids); + static struct amba_driver debug_driver = { .drv = { .name = "coresight-cpu-debug", @@ -681,7 +690,87 @@ static struct amba_driver debug_driver = { .id_table = debug_ids, }; -module_amba_driver(debug_driver); +static int debug_platform_probe(struct platform_device *pdev) +{ + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + int ret = 0; + + pm_runtime_get_noresume(&pdev->dev); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + + ret = __debug_probe(&pdev->dev, res); + if (ret) { + pm_runtime_put_noidle(&pdev->dev); + pm_runtime_disable(&pdev->dev); + } + return ret; +} + +static void debug_platform_remove(struct platform_device *pdev) +{ + struct debug_drvdata *drvdata = dev_get_drvdata(&pdev->dev); + + if (WARN_ON(!drvdata)) + return; + + __debug_remove(&pdev->dev); + pm_runtime_disable(&pdev->dev); +} + +#ifdef CONFIG_ACPI +static const struct acpi_device_id debug_platform_ids[] = { + {"ARMHC503", 0, 0, 0}, /* ARM CoreSight Debug */ + {}, +}; +MODULE_DEVICE_TABLE(acpi, debug_platform_ids); +#endif + +#ifdef CONFIG_PM +static int debug_runtime_suspend(struct device *dev) +{ + struct debug_drvdata *drvdata = dev_get_drvdata(dev); + + clk_disable_unprepare(drvdata->pclk); + + return 0; +} + +static int debug_runtime_resume(struct device *dev) +{ + struct debug_drvdata *drvdata = dev_get_drvdata(dev); + + return clk_prepare_enable(drvdata->pclk); +} +#endif + +static const struct dev_pm_ops debug_dev_pm_ops = { + SET_RUNTIME_PM_OPS(debug_runtime_suspend, debug_runtime_resume, NULL) +}; + +static struct platform_driver debug_platform_driver = { + .probe = debug_platform_probe, + .remove = debug_platform_remove, + .driver = { + .name = "coresight-debug-platform", + .acpi_match_table = ACPI_PTR(debug_platform_ids), + .suppress_bind_attrs = true, + .pm = &debug_dev_pm_ops, + }, +}; + +static int __init debug_init(void) +{ + return coresight_init_driver("debug", &debug_driver, &debug_platform_driver, + THIS_MODULE); +} + +static void __exit debug_exit(void) +{ + coresight_remove_driver(&debug_driver, &debug_platform_driver); +} +module_init(debug_init); +module_exit(debug_exit); MODULE_AUTHOR("Leo Yan <leo.yan@linaro.org>"); MODULE_DESCRIPTION("ARM Coresight CPU Debug Driver"); |
