cregit-Linux how code gets into the kernel

Release 4.14 drivers/hwtracing/coresight/coresight-etm4x-sysfs.c

/*
 * Copyright(C) 2015 Linaro Limited. All rights reserved.
 * Author: Mathieu Poirier <mathieu.poirier@linaro.org>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 as published by
 * the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <linux/pm_runtime.h>
#include <linux/sysfs.h>
#include "coresight-etm4x.h"
#include "coresight-priv.h"


static int etm4_set_mode_exclude(struct etmv4_drvdata *drvdata, bool exclude) { u8 idx; struct etmv4_config *config = &drvdata->config; idx = config->addr_idx; /* * TRCACATRn.TYPE bit[1:0]: type of comparison * the trace unit performs */ if (BMVAL(config->addr_acc[idx], 0, 1) == ETM_INSTR_ADDR) { if (idx % 2 != 0) return -EINVAL; /* * We are performing instruction address comparison. Set the * relevant bit of ViewInst Include/Exclude Control register * for corresponding address comparator pair. */ if (config->addr_type[idx] != ETM_ADDR_TYPE_RANGE || config->addr_type[idx + 1] != ETM_ADDR_TYPE_RANGE) return -EINVAL; if (exclude == true) { /* * Set exclude bit and unset the include bit * corresponding to comparator pair */ config->viiectlr |= BIT(idx / 2 + 16); config->viiectlr &= ~BIT(idx / 2); } else { /* * Set include bit and unset exclude bit * corresponding to comparator pair */ config->viiectlr |= BIT(idx / 2); config->viiectlr &= ~BIT(idx / 2 + 16); } } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Mathieu J. Poirier159100.00%2100.00%
Total159100.00%2100.00%


static ssize_t nr_pe_cmp_show(struct device *dev, struct device_attribute *attr, char *buf) { unsigned long val; struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent); val = drvdata->nr_pe_cmp; return scnprintf(buf, PAGE_SIZE, "%#lx\n", val); }

Contributors

PersonTokensPropCommitsCommitProp
Mathieu J. Poirier54100.00%1100.00%
Total54100.00%1100.00%

static DEVICE_ATTR_RO(nr_pe_cmp);
static ssize_t nr_addr_cmp_show(struct device *dev, struct device_attribute *attr, char *buf) { unsigned long val; struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent); val = drvdata->nr_addr_cmp; return scnprintf(buf, PAGE_SIZE, "%#lx\n", val); }

Contributors

PersonTokensPropCommitsCommitProp
Mathieu J. Poirier54100.00%1100.00%
Total54100.00%1100.00%

static DEVICE_ATTR_RO(nr_addr_cmp);
static ssize_t nr_cntr_show(struct device *dev, struct device_attribute *attr, char *buf) { unsigned long val; struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent); val = drvdata->nr_cntr; return scnprintf(buf, PAGE_SIZE, "%#lx\n", val); }

Contributors

PersonTokensPropCommitsCommitProp
Mathieu J. Poirier54100.00%1100.00%
Total54100.00%1100.00%

static DEVICE_ATTR_RO(nr_cntr);
static ssize_t nr_ext_inp_show(struct device *dev, struct device_attribute *attr, char *buf) { unsigned long val; struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent); val = drvdata->nr_ext_inp; return scnprintf(buf, PAGE_SIZE, "%#lx\n", val); }

Contributors

PersonTokensPropCommitsCommitProp
Mathieu J. Poirier54100.00%1100.00%
Total54100.00%1100.00%

static DEVICE_ATTR_RO(nr_ext_inp);
static ssize_t numcidc_show(struct device *dev, struct device_attribute *attr, char *buf) { unsigned long val; struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent); val = drvdata->numcidc; return scnprintf(buf, PAGE_SIZE, "%#lx\n", val); }

Contributors

PersonTokensPropCommitsCommitProp
Mathieu J. Poirier54100.00%1100.00%
Total54100.00%1100.00%

static DEVICE_ATTR_RO(numcidc);
static ssize_t numvmidc_show(struct device *dev, struct device_attribute *attr, char *buf) { unsigned long val; struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent); val = drvdata->numvmidc; return scnprintf(buf, PAGE_SIZE, "%#lx\n", val); }

Contributors

PersonTokensPropCommitsCommitProp
Mathieu J. Poirier54100.00%1100.00%
Total54100.00%1100.00%

static DEVICE_ATTR_RO(numvmidc);
static ssize_t nrseqstate_show(struct device *dev, struct device_attribute *attr, char *buf) { unsigned long val; struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent); val = drvdata->nrseqstate; return scnprintf(buf, PAGE_SIZE, "%#lx\n", val); }

Contributors

PersonTokensPropCommitsCommitProp
Mathieu J. Poirier54100.00%1100.00%
Total54100.00%1100.00%

static DEVICE_ATTR_RO(nrseqstate);
static ssize_t nr_resource_show(struct device *dev, struct device_attribute *attr, char *buf) { unsigned long val; struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent); val = drvdata->nr_resource; return scnprintf(buf, PAGE_SIZE, "%#lx\n", val); }

Contributors

PersonTokensPropCommitsCommitProp
Mathieu J. Poirier54100.00%1100.00%
Total54100.00%1100.00%

static DEVICE_ATTR_RO(nr_resource);
static ssize_t nr_ss_cmp_show(struct device *dev, struct device_attribute *attr, char *buf) { unsigned long val; struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent); val = drvdata->nr_ss_cmp; return scnprintf(buf, PAGE_SIZE, "%#lx\n", val); }

Contributors

PersonTokensPropCommitsCommitProp
Mathieu J. Poirier54100.00%1100.00%
Total54100.00%1100.00%

static DEVICE_ATTR_RO(nr_ss_cmp);
static ssize_t reset_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { int i; unsigned long val; struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent); struct etmv4_config *config = &drvdata->config; if (kstrtoul(buf, 16, &val)) return -EINVAL; spin_lock(&drvdata->spinlock); if (val) config->mode = 0x0; /* Disable data tracing: do not trace load and store data transfers */ config->mode &= ~(ETM_MODE_LOAD | ETM_MODE_STORE); config->cfg &= ~(BIT(1) | BIT(2)); /* Disable data value and data address tracing */ config->mode &= ~(ETM_MODE_DATA_TRACE_ADDR | ETM_MODE_DATA_TRACE_VAL); config->cfg &= ~(BIT(16) | BIT(17)); /* Disable all events tracing */ config->eventctrl0 = 0x0; config->eventctrl1 = 0x0; /* Disable timestamp event */ config->ts_ctrl = 0x0; /* Disable stalling */ config->stall_ctrl = 0x0; /* Reset trace synchronization period to 2^8 = 256 bytes*/ if (drvdata->syncpr == false) config->syncfreq = 0x8; /* * Enable ViewInst to trace everything with start-stop logic in * started state. ARM recommends start-stop logic is set before * each trace run. */ config->vinst_ctrl |= BIT(0); if (drvdata->nr_addr_cmp == true) { config->mode |= ETM_MODE_VIEWINST_STARTSTOP; /* SSSTATUS, bit[9] */ config->vinst_ctrl |= BIT(9); } /* No address range filtering for ViewInst */ config->viiectlr = 0x0; /* No start-stop filtering for ViewInst */ config->vissctlr = 0x0; /* Disable seq events */ for (i = 0; i < drvdata->nrseqstate-1; i++) config->seq_ctrl[i] = 0x0; config->seq_rst = 0x0; config->seq_state = 0x0; /* Disable external input events */ config->ext_inp = 0x0; config->cntr_idx = 0x0; for (i = 0; i < drvdata->nr_cntr; i++) { config->cntrldvr[i] = 0x0; config->cntr_ctrl[i] = 0x0; config->cntr_val[i] = 0x0; } config->res_idx = 0x0; for (i = 0; i < drvdata->nr_resource; i++) config->res_ctrl[i] = 0x0; for (i = 0; i < drvdata->nr_ss_cmp; i++) { config->ss_ctrl[i] = 0x0; config->ss_pe_cmp[i] = 0x0; } config->addr_idx = 0x0; for (i = 0; i < drvdata->nr_addr_cmp * 2; i++) { config->addr_val[i] = 0x0; config->addr_acc[i] = 0x0; config->addr_type[i] = ETM_ADDR_TYPE_NONE; } config->ctxid_idx = 0x0; for (i = 0; i < drvdata->numcidc; i++) { config->ctxid_pid[i] = 0x0; config->ctxid_vpid[i] = 0x0; } config->ctxid_mask0 = 0x0; config->ctxid_mask1 = 0x0; config->vmid_idx = 0x0; for (i = 0; i < drvdata->numvmidc; i++) config->vmid_val[i] = 0x0; config->vmid_mask0 = 0x0; config->vmid_mask1 = 0x0; drvdata->trcid = drvdata->cpu + 1; spin_unlock(&drvdata->spinlock); return size; }

Contributors

PersonTokensPropCommitsCommitProp
Mathieu J. Poirier566100.00%2100.00%
Total566100.00%2100.00%

static DEVICE_ATTR_WO(reset);
static ssize_t mode_show(struct device *dev, struct device_attribute *attr, char *buf) { unsigned long val; struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent); struct etmv4_config *config = &drvdata->config; val = config->mode; return scnprintf(buf, PAGE_SIZE, "%#lx\n", val); }

Contributors

PersonTokensPropCommitsCommitProp
Mathieu J. Poirier64100.00%2100.00%
Total64100.00%2100.00%


static ssize_t mode_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { unsigned long val, mode; struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent); struct etmv4_config *config = &drvdata->config; if (kstrtoul(buf, 16, &val)) return -EINVAL; spin_lock(&drvdata->spinlock); config->mode = val & ETMv4_MODE_ALL; if (config->mode & ETM_MODE_EXCLUDE) etm4_set_mode_exclude(drvdata, true); else etm4_set_mode_exclude(drvdata, false); if (drvdata->instrp0 == true) { /* start by clearing instruction P0 field */ config->cfg &= ~(BIT(1) | BIT(2)); if (config->mode & ETM_MODE_LOAD) /* 0b01 Trace load instructions as P0 instructions */ config->cfg |= BIT(1); if (config->mode & ETM_MODE_STORE) /* 0b10 Trace store instructions as P0 instructions */ config->cfg |= BIT(2); if (config->mode & ETM_MODE_LOAD_STORE) /* * 0b11 Trace load and store instructions * as P0 instructions */ config->cfg |= BIT(1) | BIT(2); } /* bit[3], Branch broadcast mode */ if ((config->mode & ETM_MODE_BB) && (drvdata->trcbb == true)) config->cfg |= BIT(3); else config->cfg &= ~BIT(3); /* bit[4], Cycle counting instruction trace bit */ if ((config->mode & ETMv4_MODE_CYCACC) && (drvdata->trccci == true)) config->cfg |= BIT(4); else config->cfg &= ~BIT(4); /* bit[6], Context ID tracing bit */ if ((config->mode & ETMv4_MODE_CTXID) && (drvdata->ctxid_size)) config->cfg |= BIT(6); else config->cfg &= ~BIT(6); if ((config->mode & ETM_MODE_VMID) && (drvdata->vmid_size)) config->cfg |= BIT(7); else config->cfg &= ~BIT(7); /* bits[10:8], Conditional instruction tracing bit */ mode = ETM_MODE_COND(config->mode); if (drvdata->trccond == true) { config->cfg &= ~(BIT(8) | BIT(9) | BIT(10)); config->cfg |= mode << 8; } /* bit[11], Global timestamp tracing bit */ if ((config->mode & ETMv4_MODE_TIMESTAMP) && (drvdata->ts_size)) config->cfg |= BIT(11); else config->cfg &= ~BIT(11); /* bit[12], Return stack enable bit */ if ((config->mode & ETM_MODE_RETURNSTACK) && (drvdata->retstack == true)) config->cfg |= BIT(12); else config->cfg &= ~BIT(12); /* bits[14:13], Q element enable field */ mode = ETM_MODE_QELEM(config->mode); /* start by clearing QE bits */ config->cfg &= ~(BIT(13) | BIT(14)); /* if supported, Q elements with instruction counts are enabled */ if ((mode & BIT(0)) && (drvdata->q_support & BIT(0))) config->cfg |= BIT(13); /* * if supported, Q elements with and without instruction * counts are enabled */ if ((mode & BIT(1)) && (drvdata->q_support & BIT(1))) config->cfg |= BIT(14); /* bit[11], AMBA Trace Bus (ATB) trigger enable bit */ if ((config->mode & ETM_MODE_ATB_TRIGGER) && (drvdata->atbtrig == true)) config->eventctrl1 |= BIT(11); else config->eventctrl1 &= ~BIT(11); /* bit[12], Low-power state behavior override bit */ if ((config->mode & ETM_MODE_LPOVERRIDE) && (drvdata->lpoverride == true)) config->eventctrl1 |= BIT(12); else config->eventctrl1 &= ~BIT(12); /* bit[8], Instruction stall bit */ if (config->mode & ETM_MODE_ISTALL_EN) config->stall_ctrl |= BIT(8); else config->stall_ctrl &= ~BIT(8); /* bit[10], Prioritize instruction trace bit */ if (config->mode & ETM_MODE_INSTPRIO) config->stall_ctrl |= BIT(10); else config->stall_ctrl &= ~BIT(10); /* bit[13], Trace overflow prevention bit */ if ((config->mode & ETM_MODE_NOOVERFLOW) && (drvdata->nooverflow == true)) config->stall_ctrl |= BIT(13); else config->stall_ctrl &= ~BIT(13); /* bit[9] Start/stop logic control bit */ if (config->mode & ETM_MODE_VIEWINST_STARTSTOP) config->vinst_ctrl |= BIT(9); else config->vinst_ctrl &= ~BIT(9); /* bit[10], Whether a trace unit must trace a Reset exception */ if (config->mode & ETM_MODE_TRACE_RESET) config->vinst_ctrl |= BIT(10); else config->vinst_ctrl &= ~BIT(10); /* bit[11], Whether a trace unit must trace a system error exception */ if ((config->mode & ETM_MODE_TRACE_ERR) && (drvdata->trc_error == true)) config->vinst_ctrl |= BIT(11); else config->vinst_ctrl &= ~BIT(11); if (config->mode & (ETM_MODE_EXCL_KERN | ETM_MODE_EXCL_USER)) etm4_config_trace_mode(config); spin_unlock(&drvdata->spinlock); return size; }

Contributors

PersonTokensPropCommitsCommitProp
Mathieu J. Poirier863100.00%3100.00%
Total863100.00%3100.00%

static DEVICE_ATTR_RW(mode);
static ssize_t pe_show(struct device *dev, struct device_attribute *attr, char *buf) { unsigned long val; struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent); struct etmv4_config *config = &drvdata->config; val = config->pe_sel; return scnprintf(buf, PAGE_SIZE, "%#lx\n", val); }

Contributors

PersonTokensPropCommitsCommitProp
Mathieu J. Poirier64100.00%2100.00%
Total64100.00%2100.00%


static ssize_t pe_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { unsigned long val; struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent); struct etmv4_config *config = &drvdata->config; if (kstrtoul(buf, 16, &val)) return -EINVAL; spin_lock(&drvdata->spinlock); if (val > drvdata->nr_pe) { spin_unlock(&drvdata->spinlock); return -EINVAL; } config->pe_sel = val; spin_unlock(&drvdata->spinlock); return size; }

Contributors

PersonTokensPropCommitsCommitProp
Mathieu J. Poirier113100.00%2100.00%
Total113100.00%2100.00%

static DEVICE_ATTR_RW(pe);
static ssize_t event_show(struct device *dev, struct device_attribute *attr, char *buf) { unsigned long val; struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent); struct etmv4_config *config = &drvdata->config; val = config->eventctrl0; return scnprintf(buf, PAGE_SIZE, "%#lx\n", val); }

Contributors

PersonTokensPropCommitsCommitProp
Mathieu J. Poirier64100.00%2100.00%
Total64100.00%2100.00%


static ssize_t event_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { unsigned long val; struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent); struct etmv4_config *config = &drvdata->config; if (kstrtoul(buf, 16, &val)) return -EINVAL; spin_lock(&drvdata->spinlock); switch (drvdata->nr_event) { case 0x0: /* EVENT0, bits[7:0] */ config->eventctrl0 = val & 0xFF; break; case 0x1: /* EVENT1, bits[15:8] */ config->eventctrl0 = val & 0xFFFF; break; case 0x2: /* EVENT2, bits[23:16] */ config->eventctrl0 = val & 0xFFFFFF; break; case 0x3: /* EVENT3, bits[31:24] */ config->eventctrl0 = val; break; default: break; } spin_unlock(&drvdata->spinlock); return size; }

Contributors

PersonTokensPropCommitsCommitProp
Mathieu J. Poirier145100.00%2100.00%
Total145100.00%2100.00%

static DEVICE_ATTR_RW(event);
static ssize_t event_instren_show(struct device *dev, struct device_attribute *attr, char *buf) { unsigned long val; struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent); struct etmv4_config *config = &drvdata->config; val = BMVAL(config->eventctrl1, 0, 3); return scnprintf(buf, PAGE_SIZE, "%#lx\n", val); }

Contributors

PersonTokensPropCommitsCommitProp
Mathieu J. Poirier71100.00%2100.00%
Total71100.00%2100.00%


static ssize_t event_instren_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { unsigned long val; struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent); struct etmv4_config *config = &drvdata->config; if (kstrtoul(buf, 16, &val)) return -EINVAL; spin_lock(&drvdata->spinlock); /* start by clearing all instruction event enable bits */ config->eventctrl1 &= ~(BIT(0) | BIT(1) | BIT(2) | BIT(3)); switch (drvdata->nr_event) { case 0x0: /* generate Event element for event 1 */ config->eventctrl1 |= val & BIT(1); break; case 0x1: /* generate Event element for event 1 and 2 */ config->eventctrl1 |= val & (BIT(0) | BIT(1)); break; case 0x2: /* generate Event element for event 1, 2 and 3 */ config->eventctrl1 |= val & (BIT(0) | BIT(1) | BIT(2)); break; case 0x3: /* generate Event element for all 4 events */ config->eventctrl1 |= val & 0xF; break; default: break; } spin_unlock(&drvdata->spinlock); return size; }

Contributors

PersonTokensPropCommitsCommitProp
Mathieu J. Poirier203100.00%2100.00%
Total203100.00%2100.00%

static DEVICE_ATTR_RW(event_instren);
static ssize_t event_ts_show(struct device *dev, struct device_attribute *attr