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