linux/tools/perf/arch/arm/util/cs-etm.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright(C) 2015 Linaro Limited. All rights reserved.
   4 * Author: Mathieu Poirier <mathieu.poirier@linaro.org>
   5 */
   6
   7#include <api/fs/fs.h>
   8#include <linux/bitops.h>
   9#include <linux/compiler.h>
  10#include <linux/coresight-pmu.h>
  11#include <linux/kernel.h>
  12#include <linux/log2.h>
  13#include <linux/types.h>
  14
  15#include "cs-etm.h"
  16#include "../../perf.h"
  17#include "../../util/auxtrace.h"
  18#include "../../util/cpumap.h"
  19#include "../../util/evlist.h"
  20#include "../../util/evsel.h"
  21#include "../../util/pmu.h"
  22#include "../../util/thread_map.h"
  23#include "../../util/cs-etm.h"
  24
  25#include <stdlib.h>
  26#include <sys/stat.h>
  27
  28#define ENABLE_SINK_MAX 128
  29#define CS_BUS_DEVICE_PATH "/bus/coresight/devices/"
  30
  31struct cs_etm_recording {
  32        struct auxtrace_record  itr;
  33        struct perf_pmu         *cs_etm_pmu;
  34        struct perf_evlist      *evlist;
  35        bool                    snapshot_mode;
  36        size_t                  snapshot_size;
  37};
  38
  39static bool cs_etm_is_etmv4(struct auxtrace_record *itr, int cpu);
  40
  41static int cs_etm_parse_snapshot_options(struct auxtrace_record *itr,
  42                                         struct record_opts *opts,
  43                                         const char *str)
  44{
  45        struct cs_etm_recording *ptr =
  46                                container_of(itr, struct cs_etm_recording, itr);
  47        unsigned long long snapshot_size = 0;
  48        char *endptr;
  49
  50        if (str) {
  51                snapshot_size = strtoull(str, &endptr, 0);
  52                if (*endptr || snapshot_size > SIZE_MAX)
  53                        return -1;
  54        }
  55
  56        opts->auxtrace_snapshot_mode = true;
  57        opts->auxtrace_snapshot_size = snapshot_size;
  58        ptr->snapshot_size = snapshot_size;
  59
  60        return 0;
  61}
  62
  63static int cs_etm_recording_options(struct auxtrace_record *itr,
  64                                    struct perf_evlist *evlist,
  65                                    struct record_opts *opts)
  66{
  67        struct cs_etm_recording *ptr =
  68                                container_of(itr, struct cs_etm_recording, itr);
  69        struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;
  70        struct perf_evsel *evsel, *cs_etm_evsel = NULL;
  71        const struct cpu_map *cpus = evlist->cpus;
  72        bool privileged = (geteuid() == 0 || perf_event_paranoid() < 0);
  73
  74        ptr->evlist = evlist;
  75        ptr->snapshot_mode = opts->auxtrace_snapshot_mode;
  76
  77        evlist__for_each_entry(evlist, evsel) {
  78                if (evsel->attr.type == cs_etm_pmu->type) {
  79                        if (cs_etm_evsel) {
  80                                pr_err("There may be only one %s event\n",
  81                                       CORESIGHT_ETM_PMU_NAME);
  82                                return -EINVAL;
  83                        }
  84                        evsel->attr.freq = 0;
  85                        evsel->attr.sample_period = 1;
  86                        cs_etm_evsel = evsel;
  87                        opts->full_auxtrace = true;
  88                }
  89        }
  90
  91        /* no need to continue if at least one event of interest was found */
  92        if (!cs_etm_evsel)
  93                return 0;
  94
  95        if (opts->use_clockid) {
  96                pr_err("Cannot use clockid (-k option) with %s\n",
  97                       CORESIGHT_ETM_PMU_NAME);
  98                return -EINVAL;
  99        }
 100
 101        /* we are in snapshot mode */
 102        if (opts->auxtrace_snapshot_mode) {
 103                /*
 104                 * No size were given to '-S' or '-m,', so go with
 105                 * the default
 106                 */
 107                if (!opts->auxtrace_snapshot_size &&
 108                    !opts->auxtrace_mmap_pages) {
 109                        if (privileged) {
 110                                opts->auxtrace_mmap_pages = MiB(4) / page_size;
 111                        } else {
 112                                opts->auxtrace_mmap_pages =
 113                                                        KiB(128) / page_size;
 114                                if (opts->mmap_pages == UINT_MAX)
 115                                        opts->mmap_pages = KiB(256) / page_size;
 116                        }
 117                } else if (!opts->auxtrace_mmap_pages && !privileged &&
 118                                                opts->mmap_pages == UINT_MAX) {
 119                        opts->mmap_pages = KiB(256) / page_size;
 120                }
 121
 122                /*
 123                 * '-m,xyz' was specified but no snapshot size, so make the
 124                 * snapshot size as big as the auxtrace mmap area.
 125                 */
 126                if (!opts->auxtrace_snapshot_size) {
 127                        opts->auxtrace_snapshot_size =
 128                                opts->auxtrace_mmap_pages * (size_t)page_size;
 129                }
 130
 131                /*
 132                 * -Sxyz was specified but no auxtrace mmap area, so make the
 133                 * auxtrace mmap area big enough to fit the requested snapshot
 134                 * size.
 135                 */
 136                if (!opts->auxtrace_mmap_pages) {
 137                        size_t sz = opts->auxtrace_snapshot_size;
 138
 139                        sz = round_up(sz, page_size) / page_size;
 140                        opts->auxtrace_mmap_pages = roundup_pow_of_two(sz);
 141                }
 142
 143                /* Snapshost size can't be bigger than the auxtrace area */
 144                if (opts->auxtrace_snapshot_size >
 145                                opts->auxtrace_mmap_pages * (size_t)page_size) {
 146                        pr_err("Snapshot size %zu must not be greater than AUX area tracing mmap size %zu\n",
 147                               opts->auxtrace_snapshot_size,
 148                               opts->auxtrace_mmap_pages * (size_t)page_size);
 149                        return -EINVAL;
 150                }
 151
 152                /* Something went wrong somewhere - this shouldn't happen */
 153                if (!opts->auxtrace_snapshot_size ||
 154                    !opts->auxtrace_mmap_pages) {
 155                        pr_err("Failed to calculate default snapshot size and/or AUX area tracing mmap pages\n");
 156                        return -EINVAL;
 157                }
 158        }
 159
 160        /* We are in full trace mode but '-m,xyz' wasn't specified */
 161        if (opts->full_auxtrace && !opts->auxtrace_mmap_pages) {
 162                if (privileged) {
 163                        opts->auxtrace_mmap_pages = MiB(4) / page_size;
 164                } else {
 165                        opts->auxtrace_mmap_pages = KiB(128) / page_size;
 166                        if (opts->mmap_pages == UINT_MAX)
 167                                opts->mmap_pages = KiB(256) / page_size;
 168                }
 169
 170        }
 171
 172        /* Validate auxtrace_mmap_pages provided by user */
 173        if (opts->auxtrace_mmap_pages) {
 174                unsigned int max_page = (KiB(128) / page_size);
 175                size_t sz = opts->auxtrace_mmap_pages * (size_t)page_size;
 176
 177                if (!privileged &&
 178                    opts->auxtrace_mmap_pages > max_page) {
 179                        opts->auxtrace_mmap_pages = max_page;
 180                        pr_err("auxtrace too big, truncating to %d\n",
 181                               max_page);
 182                }
 183
 184                if (!is_power_of_2(sz)) {
 185                        pr_err("Invalid mmap size for %s: must be a power of 2\n",
 186                               CORESIGHT_ETM_PMU_NAME);
 187                        return -EINVAL;
 188                }
 189        }
 190
 191        if (opts->auxtrace_snapshot_mode)
 192                pr_debug2("%s snapshot size: %zu\n", CORESIGHT_ETM_PMU_NAME,
 193                          opts->auxtrace_snapshot_size);
 194
 195        /*
 196         * To obtain the auxtrace buffer file descriptor, the auxtrace
 197         * event must come first.
 198         */
 199        perf_evlist__to_front(evlist, cs_etm_evsel);
 200
 201        /*
 202         * In the case of per-cpu mmaps, we need the CPU on the
 203         * AUX event.
 204         */
 205        if (!cpu_map__empty(cpus))
 206                perf_evsel__set_sample_bit(cs_etm_evsel, CPU);
 207
 208        /* Add dummy event to keep tracking */
 209        if (opts->full_auxtrace) {
 210                struct perf_evsel *tracking_evsel;
 211                int err;
 212
 213                err = parse_events(evlist, "dummy:u", NULL);
 214                if (err)
 215                        return err;
 216
 217                tracking_evsel = perf_evlist__last(evlist);
 218                perf_evlist__set_tracking_event(evlist, tracking_evsel);
 219
 220                tracking_evsel->attr.freq = 0;
 221                tracking_evsel->attr.sample_period = 1;
 222
 223                /* In per-cpu case, always need the time of mmap events etc */
 224                if (!cpu_map__empty(cpus))
 225                        perf_evsel__set_sample_bit(tracking_evsel, TIME);
 226        }
 227
 228        return 0;
 229}
 230
 231static u64 cs_etm_get_config(struct auxtrace_record *itr)
 232{
 233        u64 config = 0;
 234        struct cs_etm_recording *ptr =
 235                        container_of(itr, struct cs_etm_recording, itr);
 236        struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;
 237        struct perf_evlist *evlist = ptr->evlist;
 238        struct perf_evsel *evsel;
 239
 240        evlist__for_each_entry(evlist, evsel) {
 241                if (evsel->attr.type == cs_etm_pmu->type) {
 242                        /*
 243                         * Variable perf_event_attr::config is assigned to
 244                         * ETMv3/PTM.  The bit fields have been made to match
 245                         * the ETMv3.5 ETRMCR register specification.  See the
 246                         * PMU_FORMAT_ATTR() declarations in
 247                         * drivers/hwtracing/coresight/coresight-perf.c for
 248                         * details.
 249                         */
 250                        config = evsel->attr.config;
 251                        break;
 252                }
 253        }
 254
 255        return config;
 256}
 257
 258#ifndef BIT
 259#define BIT(N) (1UL << (N))
 260#endif
 261
 262static u64 cs_etmv4_get_config(struct auxtrace_record *itr)
 263{
 264        u64 config = 0;
 265        u64 config_opts = 0;
 266
 267        /*
 268         * The perf event variable config bits represent both
 269         * the command line options and register programming
 270         * bits in ETMv3/PTM. For ETMv4 we must remap options
 271         * to real bits
 272         */
 273        config_opts = cs_etm_get_config(itr);
 274        if (config_opts & BIT(ETM_OPT_CYCACC))
 275                config |= BIT(ETM4_CFG_BIT_CYCACC);
 276        if (config_opts & BIT(ETM_OPT_TS))
 277                config |= BIT(ETM4_CFG_BIT_TS);
 278        if (config_opts & BIT(ETM_OPT_RETSTK))
 279                config |= BIT(ETM4_CFG_BIT_RETSTK);
 280
 281        return config;
 282}
 283
 284static size_t
 285cs_etm_info_priv_size(struct auxtrace_record *itr __maybe_unused,
 286                      struct perf_evlist *evlist __maybe_unused)
 287{
 288        int i;
 289        int etmv3 = 0, etmv4 = 0;
 290        struct cpu_map *event_cpus = evlist->cpus;
 291        struct cpu_map *online_cpus = cpu_map__new(NULL);
 292
 293        /* cpu map is not empty, we have specific CPUs to work with */
 294        if (!cpu_map__empty(event_cpus)) {
 295                for (i = 0; i < cpu__max_cpu(); i++) {
 296                        if (!cpu_map__has(event_cpus, i) ||
 297                            !cpu_map__has(online_cpus, i))
 298                                continue;
 299
 300                        if (cs_etm_is_etmv4(itr, i))
 301                                etmv4++;
 302                        else
 303                                etmv3++;
 304                }
 305        } else {
 306                /* get configuration for all CPUs in the system */
 307                for (i = 0; i < cpu__max_cpu(); i++) {
 308                        if (!cpu_map__has(online_cpus, i))
 309                                continue;
 310
 311                        if (cs_etm_is_etmv4(itr, i))
 312                                etmv4++;
 313                        else
 314                                etmv3++;
 315                }
 316        }
 317
 318        cpu_map__put(online_cpus);
 319
 320        return (CS_ETM_HEADER_SIZE +
 321               (etmv4 * CS_ETMV4_PRIV_SIZE) +
 322               (etmv3 * CS_ETMV3_PRIV_SIZE));
 323}
 324
 325static const char *metadata_etmv3_ro[CS_ETM_PRIV_MAX] = {
 326        [CS_ETM_ETMCCER]        = "mgmt/etmccer",
 327        [CS_ETM_ETMIDR]         = "mgmt/etmidr",
 328};
 329
 330static const char *metadata_etmv4_ro[CS_ETMV4_PRIV_MAX] = {
 331        [CS_ETMV4_TRCIDR0]              = "trcidr/trcidr0",
 332        [CS_ETMV4_TRCIDR1]              = "trcidr/trcidr1",
 333        [CS_ETMV4_TRCIDR2]              = "trcidr/trcidr2",
 334        [CS_ETMV4_TRCIDR8]              = "trcidr/trcidr8",
 335        [CS_ETMV4_TRCAUTHSTATUS]        = "mgmt/trcauthstatus",
 336};
 337
 338static bool cs_etm_is_etmv4(struct auxtrace_record *itr, int cpu)
 339{
 340        bool ret = false;
 341        char path[PATH_MAX];
 342        int scan;
 343        unsigned int val;
 344        struct cs_etm_recording *ptr =
 345                        container_of(itr, struct cs_etm_recording, itr);
 346        struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;
 347
 348        /* Take any of the RO files for ETMv4 and see if it present */
 349        snprintf(path, PATH_MAX, "cpu%d/%s",
 350                 cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR0]);
 351        scan = perf_pmu__scan_file(cs_etm_pmu, path, "%x", &val);
 352
 353        /* The file was read successfully, we have a winner */
 354        if (scan == 1)
 355                ret = true;
 356
 357        return ret;
 358}
 359
 360static int cs_etm_get_ro(struct perf_pmu *pmu, int cpu, const char *path)
 361{
 362        char pmu_path[PATH_MAX];
 363        int scan;
 364        unsigned int val = 0;
 365
 366        /* Get RO metadata from sysfs */
 367        snprintf(pmu_path, PATH_MAX, "cpu%d/%s", cpu, path);
 368
 369        scan = perf_pmu__scan_file(pmu, pmu_path, "%x", &val);
 370        if (scan != 1)
 371                pr_err("%s: error reading: %s\n", __func__, pmu_path);
 372
 373        return val;
 374}
 375
 376static void cs_etm_get_metadata(int cpu, u32 *offset,
 377                                struct auxtrace_record *itr,
 378                                struct auxtrace_info_event *info)
 379{
 380        u32 increment;
 381        u64 magic;
 382        struct cs_etm_recording *ptr =
 383                        container_of(itr, struct cs_etm_recording, itr);
 384        struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;
 385
 386        /* first see what kind of tracer this cpu is affined to */
 387        if (cs_etm_is_etmv4(itr, cpu)) {
 388                magic = __perf_cs_etmv4_magic;
 389                /* Get trace configuration register */
 390                info->priv[*offset + CS_ETMV4_TRCCONFIGR] =
 391                                                cs_etmv4_get_config(itr);
 392                /* Get traceID from the framework */
 393                info->priv[*offset + CS_ETMV4_TRCTRACEIDR] =
 394                                                coresight_get_trace_id(cpu);
 395                /* Get read-only information from sysFS */
 396                info->priv[*offset + CS_ETMV4_TRCIDR0] =
 397                        cs_etm_get_ro(cs_etm_pmu, cpu,
 398                                      metadata_etmv4_ro[CS_ETMV4_TRCIDR0]);
 399                info->priv[*offset + CS_ETMV4_TRCIDR1] =
 400                        cs_etm_get_ro(cs_etm_pmu, cpu,
 401                                      metadata_etmv4_ro[CS_ETMV4_TRCIDR1]);
 402                info->priv[*offset + CS_ETMV4_TRCIDR2] =
 403                        cs_etm_get_ro(cs_etm_pmu, cpu,
 404                                      metadata_etmv4_ro[CS_ETMV4_TRCIDR2]);
 405                info->priv[*offset + CS_ETMV4_TRCIDR8] =
 406                        cs_etm_get_ro(cs_etm_pmu, cpu,
 407                                      metadata_etmv4_ro[CS_ETMV4_TRCIDR8]);
 408                info->priv[*offset + CS_ETMV4_TRCAUTHSTATUS] =
 409                        cs_etm_get_ro(cs_etm_pmu, cpu,
 410                                      metadata_etmv4_ro
 411                                      [CS_ETMV4_TRCAUTHSTATUS]);
 412
 413                /* How much space was used */
 414                increment = CS_ETMV4_PRIV_MAX;
 415        } else {
 416                magic = __perf_cs_etmv3_magic;
 417                /* Get configuration register */
 418                info->priv[*offset + CS_ETM_ETMCR] = cs_etm_get_config(itr);
 419                /* Get traceID from the framework */
 420                info->priv[*offset + CS_ETM_ETMTRACEIDR] =
 421                                                coresight_get_trace_id(cpu);
 422                /* Get read-only information from sysFS */
 423                info->priv[*offset + CS_ETM_ETMCCER] =
 424                        cs_etm_get_ro(cs_etm_pmu, cpu,
 425                                      metadata_etmv3_ro[CS_ETM_ETMCCER]);
 426                info->priv[*offset + CS_ETM_ETMIDR] =
 427                        cs_etm_get_ro(cs_etm_pmu, cpu,
 428                                      metadata_etmv3_ro[CS_ETM_ETMIDR]);
 429
 430                /* How much space was used */
 431                increment = CS_ETM_PRIV_MAX;
 432        }
 433
 434        /* Build generic header portion */
 435        info->priv[*offset + CS_ETM_MAGIC] = magic;
 436        info->priv[*offset + CS_ETM_CPU] = cpu;
 437        /* Where the next CPU entry should start from */
 438        *offset += increment;
 439}
 440
 441static int cs_etm_info_fill(struct auxtrace_record *itr,
 442                            struct perf_session *session,
 443                            struct auxtrace_info_event *info,
 444                            size_t priv_size)
 445{
 446        int i;
 447        u32 offset;
 448        u64 nr_cpu, type;
 449        struct cpu_map *cpu_map;
 450        struct cpu_map *event_cpus = session->evlist->cpus;
 451        struct cpu_map *online_cpus = cpu_map__new(NULL);
 452        struct cs_etm_recording *ptr =
 453                        container_of(itr, struct cs_etm_recording, itr);
 454        struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;
 455
 456        if (priv_size != cs_etm_info_priv_size(itr, session->evlist))
 457                return -EINVAL;
 458
 459        if (!session->evlist->nr_mmaps)
 460                return -EINVAL;
 461
 462        /* If the cpu_map is empty all online CPUs are involved */
 463        if (cpu_map__empty(event_cpus)) {
 464                cpu_map = online_cpus;
 465        } else {
 466                /* Make sure all specified CPUs are online */
 467                for (i = 0; i < cpu_map__nr(event_cpus); i++) {
 468                        if (cpu_map__has(event_cpus, i) &&
 469                            !cpu_map__has(online_cpus, i))
 470                                return -EINVAL;
 471                }
 472
 473                cpu_map = event_cpus;
 474        }
 475
 476        nr_cpu = cpu_map__nr(cpu_map);
 477        /* Get PMU type as dynamically assigned by the core */
 478        type = cs_etm_pmu->type;
 479
 480        /* First fill out the session header */
 481        info->type = PERF_AUXTRACE_CS_ETM;
 482        info->priv[CS_HEADER_VERSION_0] = 0;
 483        info->priv[CS_PMU_TYPE_CPUS] = type << 32;
 484        info->priv[CS_PMU_TYPE_CPUS] |= nr_cpu;
 485        info->priv[CS_ETM_SNAPSHOT] = ptr->snapshot_mode;
 486
 487        offset = CS_ETM_SNAPSHOT + 1;
 488
 489        for (i = 0; i < cpu__max_cpu() && offset < priv_size; i++)
 490                if (cpu_map__has(cpu_map, i))
 491                        cs_etm_get_metadata(i, &offset, itr, info);
 492
 493        cpu_map__put(online_cpus);
 494
 495        return 0;
 496}
 497
 498static int cs_etm_find_snapshot(struct auxtrace_record *itr __maybe_unused,
 499                                int idx, struct auxtrace_mmap *mm,
 500                                unsigned char *data __maybe_unused,
 501                                u64 *head, u64 *old)
 502{
 503        pr_debug3("%s: mmap index %d old head %zu new head %zu size %zu\n",
 504                  __func__, idx, (size_t)*old, (size_t)*head, mm->len);
 505
 506        *old = *head;
 507        *head += mm->len;
 508
 509        return 0;
 510}
 511
 512static int cs_etm_snapshot_start(struct auxtrace_record *itr)
 513{
 514        struct cs_etm_recording *ptr =
 515                        container_of(itr, struct cs_etm_recording, itr);
 516        struct perf_evsel *evsel;
 517
 518        evlist__for_each_entry(ptr->evlist, evsel) {
 519                if (evsel->attr.type == ptr->cs_etm_pmu->type)
 520                        return perf_evsel__disable(evsel);
 521        }
 522        return -EINVAL;
 523}
 524
 525static int cs_etm_snapshot_finish(struct auxtrace_record *itr)
 526{
 527        struct cs_etm_recording *ptr =
 528                        container_of(itr, struct cs_etm_recording, itr);
 529        struct perf_evsel *evsel;
 530
 531        evlist__for_each_entry(ptr->evlist, evsel) {
 532                if (evsel->attr.type == ptr->cs_etm_pmu->type)
 533                        return perf_evsel__enable(evsel);
 534        }
 535        return -EINVAL;
 536}
 537
 538static u64 cs_etm_reference(struct auxtrace_record *itr __maybe_unused)
 539{
 540        return (((u64) rand() <<  0) & 0x00000000FFFFFFFFull) |
 541                (((u64) rand() << 32) & 0xFFFFFFFF00000000ull);
 542}
 543
 544static void cs_etm_recording_free(struct auxtrace_record *itr)
 545{
 546        struct cs_etm_recording *ptr =
 547                        container_of(itr, struct cs_etm_recording, itr);
 548        free(ptr);
 549}
 550
 551static int cs_etm_read_finish(struct auxtrace_record *itr, int idx)
 552{
 553        struct cs_etm_recording *ptr =
 554                        container_of(itr, struct cs_etm_recording, itr);
 555        struct perf_evsel *evsel;
 556
 557        evlist__for_each_entry(ptr->evlist, evsel) {
 558                if (evsel->attr.type == ptr->cs_etm_pmu->type)
 559                        return perf_evlist__enable_event_idx(ptr->evlist,
 560                                                             evsel, idx);
 561        }
 562
 563        return -EINVAL;
 564}
 565
 566struct auxtrace_record *cs_etm_record_init(int *err)
 567{
 568        struct perf_pmu *cs_etm_pmu;
 569        struct cs_etm_recording *ptr;
 570
 571        cs_etm_pmu = perf_pmu__find(CORESIGHT_ETM_PMU_NAME);
 572
 573        if (!cs_etm_pmu) {
 574                *err = -EINVAL;
 575                goto out;
 576        }
 577
 578        ptr = zalloc(sizeof(struct cs_etm_recording));
 579        if (!ptr) {
 580                *err = -ENOMEM;
 581                goto out;
 582        }
 583
 584        ptr->cs_etm_pmu                 = cs_etm_pmu;
 585        ptr->itr.parse_snapshot_options = cs_etm_parse_snapshot_options;
 586        ptr->itr.recording_options      = cs_etm_recording_options;
 587        ptr->itr.info_priv_size         = cs_etm_info_priv_size;
 588        ptr->itr.info_fill              = cs_etm_info_fill;
 589        ptr->itr.find_snapshot          = cs_etm_find_snapshot;
 590        ptr->itr.snapshot_start         = cs_etm_snapshot_start;
 591        ptr->itr.snapshot_finish        = cs_etm_snapshot_finish;
 592        ptr->itr.reference              = cs_etm_reference;
 593        ptr->itr.free                   = cs_etm_recording_free;
 594        ptr->itr.read_finish            = cs_etm_read_finish;
 595
 596        *err = 0;
 597        return &ptr->itr;
 598out:
 599        return NULL;
 600}
 601
 602static FILE *cs_device__open_file(const char *name)
 603{
 604        struct stat st;
 605        char path[PATH_MAX];
 606        const char *sysfs;
 607
 608        sysfs = sysfs__mountpoint();
 609        if (!sysfs)
 610                return NULL;
 611
 612        snprintf(path, PATH_MAX,
 613                 "%s" CS_BUS_DEVICE_PATH "%s", sysfs, name);
 614
 615        if (stat(path, &st) < 0)
 616                return NULL;
 617
 618        return fopen(path, "w");
 619
 620}
 621
 622static int __printf(2, 3) cs_device__print_file(const char *name, const char *fmt, ...)
 623{
 624        va_list args;
 625        FILE *file;
 626        int ret = -EINVAL;
 627
 628        va_start(args, fmt);
 629        file = cs_device__open_file(name);
 630        if (file) {
 631                ret = vfprintf(file, fmt, args);
 632                fclose(file);
 633        }
 634        va_end(args);
 635        return ret;
 636}
 637
 638int cs_etm_set_drv_config(struct perf_evsel_config_term *term)
 639{
 640        int ret;
 641        char enable_sink[ENABLE_SINK_MAX];
 642
 643        snprintf(enable_sink, ENABLE_SINK_MAX, "%s/%s",
 644                 term->val.drv_cfg, "enable_sink");
 645
 646        ret = cs_device__print_file(enable_sink, "%d", 1);
 647        if (ret < 0)
 648                return ret;
 649
 650        return 0;
 651}
 652