Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

coresight: etm4x: implementing the perf PMU API

Adding a set of API allowing the Perf core to treat ETMv4
tracers like other PMUs.

Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Mathieu Poirier and committed by
Greg Kroah-Hartman
37fbbdbd 4f6fce54

+82 -8
+2 -3
drivers/hwtracing/coresight/Makefile
··· 1 1 # 2 2 # Makefile for CoreSight drivers. 3 3 # 4 - obj-$(CONFIG_CORESIGHT) += coresight.o 4 + obj-$(CONFIG_CORESIGHT) += coresight.o coresight-etm-perf.o 5 5 obj-$(CONFIG_OF) += of_coresight.o 6 6 obj-$(CONFIG_CORESIGHT_LINK_AND_SINK_TMC) += coresight-tmc.o 7 7 obj-$(CONFIG_CORESIGHT_SINK_TPIU) += coresight-tpiu.o ··· 9 9 obj-$(CONFIG_CORESIGHT_LINKS_AND_SINKS) += coresight-funnel.o \ 10 10 coresight-replicator.o 11 11 obj-$(CONFIG_CORESIGHT_SOURCE_ETM3X) += coresight-etm3x.o coresight-etm-cp14.o \ 12 - coresight-etm3x-sysfs.o \ 13 - coresight-etm-perf.o 12 + coresight-etm3x-sysfs.o 14 13 obj-$(CONFIG_CORESIGHT_SOURCE_ETM4X) += coresight-etm4x.o \ 15 14 coresight-etm4x-sysfs.o 16 15 obj-$(CONFIG_CORESIGHT_QCOM_REPLICATOR) += coresight-replicator-qcom.o
+80 -5
drivers/hwtracing/coresight/coresight-etm4x.c
··· 31 31 #include <linux/amba/bus.h> 32 32 #include <linux/seq_file.h> 33 33 #include <linux/uaccess.h> 34 + #include <linux/perf_event.h> 34 35 #include <linux/pm_runtime.h> 35 36 #include <linux/perf_event.h> 36 37 #include <asm/sections.h> 37 38 #include <asm/local.h> 38 39 39 40 #include "coresight-etm4x.h" 41 + #include "coresight-etm-perf.h" 40 42 41 43 static int boot_enable; 42 44 module_param_named(boot_enable, boot_enable, int, S_IRUGO); ··· 46 44 /* The number of ETMv4 currently registered */ 47 45 static int etm4_count; 48 46 static struct etmv4_drvdata *etmdrvdata[NR_CPUS]; 47 + static void etm4_set_default(struct etmv4_config *config); 49 48 50 49 static void etm4_os_unlock(struct etmv4_drvdata *drvdata) 51 50 { ··· 192 189 dev_dbg(drvdata->dev, "cpu: %d enable smp call done\n", drvdata->cpu); 193 190 } 194 191 192 + static int etm4_parse_event_config(struct etmv4_drvdata *drvdata, 193 + struct perf_event_attr *attr) 194 + { 195 + struct etmv4_config *config = &drvdata->config; 196 + 197 + if (!attr) 198 + return -EINVAL; 199 + 200 + /* Clear configuration from previous run */ 201 + memset(config, 0, sizeof(struct etmv4_config)); 202 + 203 + if (attr->exclude_kernel) 204 + config->mode = ETM_MODE_EXCL_KERN; 205 + 206 + if (attr->exclude_user) 207 + config->mode = ETM_MODE_EXCL_USER; 208 + 209 + /* Always start from the default config */ 210 + etm4_set_default(config); 211 + 212 + /* 213 + * By default the tracers are configured to trace the whole address 214 + * range. Narrow the field only if requested by user space. 215 + */ 216 + if (config->mode) 217 + etm4_config_trace_mode(config); 218 + 219 + /* Go from generic option to ETMv4 specifics */ 220 + if (attr->config & BIT(ETM_OPT_CYCACC)) 221 + config->cfg |= ETMv4_MODE_CYCACC; 222 + if (attr->config & BIT(ETM_OPT_TS)) 223 + config->cfg |= ETMv4_MODE_TIMESTAMP; 224 + 225 + return 0; 226 + } 227 + 228 + static int etm4_enable_perf(struct coresight_device *csdev, 229 + struct perf_event_attr *attr) 230 + { 231 + struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); 232 + 233 + if (WARN_ON_ONCE(drvdata->cpu != smp_processor_id())) 234 + return -EINVAL; 235 + 236 + /* Configure the tracer based on the session's specifics */ 237 + etm4_parse_event_config(drvdata, attr); 238 + /* And enable it */ 239 + etm4_enable_hw(drvdata); 240 + 241 + return 0; 242 + } 243 + 195 244 static int etm4_enable_sysfs(struct coresight_device *csdev) 196 245 { 197 246 struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); ··· 288 233 case CS_MODE_SYSFS: 289 234 ret = etm4_enable_sysfs(csdev); 290 235 break; 236 + case CS_MODE_PERF: 237 + ret = etm4_enable_perf(csdev, attr); 238 + break; 291 239 default: 292 240 ret = -EINVAL; 293 241 } ··· 322 264 CS_LOCK(drvdata->base); 323 265 324 266 dev_dbg(drvdata->dev, "cpu: %d disable smp call done\n", drvdata->cpu); 267 + } 268 + 269 + static int etm4_disable_perf(struct coresight_device *csdev) 270 + { 271 + struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); 272 + 273 + if (WARN_ON_ONCE(drvdata->cpu != smp_processor_id())) 274 + return -EINVAL; 275 + 276 + etm4_disable_hw(drvdata); 277 + return 0; 325 278 } 326 279 327 280 static void etm4_disable_sysfs(struct coresight_device *csdev) ··· 377 308 break; 378 309 case CS_MODE_SYSFS: 379 310 etm4_disable_sysfs(csdev); 311 + break; 312 + case CS_MODE_PERF: 313 + etm4_disable_perf(csdev); 380 314 break; 381 315 } 382 316 ··· 780 708 etm4_init_trace_id(drvdata); 781 709 etm4_set_default(&drvdata->config); 782 710 783 - pm_runtime_put(&adev->dev); 784 - 785 711 desc->type = CORESIGHT_DEV_TYPE_SOURCE; 786 712 desc->subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_PROC; 787 713 desc->ops = &etm4_cs_ops; ··· 789 719 drvdata->csdev = coresight_register(desc); 790 720 if (IS_ERR(drvdata->csdev)) { 791 721 ret = PTR_ERR(drvdata->csdev); 792 - goto err_coresight_register; 722 + goto err_arch_supported; 793 723 } 794 724 725 + ret = etm_perf_symlink(drvdata->csdev, true); 726 + if (ret) { 727 + coresight_unregister(drvdata->csdev); 728 + goto err_arch_supported; 729 + } 730 + 731 + pm_runtime_put(&adev->dev); 795 732 dev_info(dev, "%s initialized\n", (char *)id->data); 796 733 797 734 if (boot_enable) { ··· 809 732 return 0; 810 733 811 734 err_arch_supported: 812 - pm_runtime_put(&adev->dev); 813 - err_coresight_register: 814 735 if (--etm4_count == 0) 815 736 unregister_hotcpu_notifier(&etm4_cpu_notifier); 816 737 return ret;