cregit-Linux how code gets into the kernel

Release 4.14 drivers/hwtracing/coresight/coresight-etm3x-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-etm.h"
#include "coresight-priv.h"


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

Contributors

PersonTokensPropCommitsCommitProp
Mathieu J. Poirier52100.00%1100.00%
Total52100.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 etm_drvdata *drvdata = dev_get_drvdata(dev->parent); val = drvdata->nr_cntr; return sprintf(buf, "%#lx\n", val); }

Contributors

PersonTokensPropCommitsCommitProp
Mathieu J. Poirier52100.00%1100.00%
Total52100.00%1100.00%

static DEVICE_ATTR_RO(nr_cntr);
static ssize_t nr_ctxid_cmp_show(struct device *dev, struct device_attribute *attr, char *buf) { unsigned long val; struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); val = drvdata->nr_ctxid_cmp; return sprintf(buf, "%#lx\n", val); }

Contributors

PersonTokensPropCommitsCommitProp
Mathieu J. Poirier52100.00%1100.00%
Total52100.00%1100.00%

static DEVICE_ATTR_RO(nr_ctxid_cmp);
static ssize_t etmsr_show(struct device *dev, struct device_attribute *attr, char *buf) { unsigned long flags, val; struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); pm_runtime_get_sync(drvdata->dev); spin_lock_irqsave(&drvdata->spinlock, flags); CS_UNLOCK(drvdata->base); val = etm_readl(drvdata, ETMSR); CS_LOCK(drvdata->base); spin_unlock_irqrestore(&drvdata->spinlock, flags); pm_runtime_put(drvdata->dev); return sprintf(buf, "%#lx\n", val); }

Contributors

PersonTokensPropCommitsCommitProp
Mathieu J. Poirier105100.00%1100.00%
Total105100.00%1100.00%

static DEVICE_ATTR_RO(etmsr);
static ssize_t reset_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { int i, ret; unsigned long val; struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); struct etm_config *config = &drvdata->config; ret = kstrtoul(buf, 16, &val); if (ret) return ret; if (val) { spin_lock(&drvdata->spinlock); memset(config, 0, sizeof(struct etm_config)); config->mode = ETM_MODE_EXCLUDE; config->trigger_event = ETM_DEFAULT_EVENT_VAL; for (i = 0; i < drvdata->nr_addr_cmp; i++) { config->addr_type[i] = ETM_ADDR_TYPE_NONE; } etm_set_default(config); spin_unlock(&drvdata->spinlock); } return size; }

Contributors

PersonTokensPropCommitsCommitProp
Mathieu J. Poirier155100.00%2100.00%
Total155100.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 etm_drvdata *drvdata = dev_get_drvdata(dev->parent); struct etm_config *config = &drvdata->config; val = config->mode; return sprintf(buf, "%#lx\n", val); }

Contributors

PersonTokensPropCommitsCommitProp
Mathieu J. Poirier62100.00%2100.00%
Total62100.00%2100.00%


static ssize_t mode_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { int ret; unsigned long val; struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); struct etm_config *config = &drvdata->config; ret = kstrtoul(buf, 16, &val); if (ret) return ret; spin_lock(&drvdata->spinlock); config->mode = val & ETM_MODE_ALL; if (config->mode & ETM_MODE_EXCLUDE) config->enable_ctrl1 |= ETMTECR1_INC_EXC; else config->enable_ctrl1 &= ~ETMTECR1_INC_EXC; if (config->mode & ETM_MODE_CYCACC) config->ctrl |= ETMCR_CYC_ACC; else config->ctrl &= ~ETMCR_CYC_ACC; if (config->mode & ETM_MODE_STALL) { if (!(drvdata->etmccr & ETMCCR_FIFOFULL)) { dev_warn(drvdata->dev, "stall mode not supported\n"); ret = -EINVAL; goto err_unlock; } config->ctrl |= ETMCR_STALL_MODE; } else config->ctrl &= ~ETMCR_STALL_MODE; if (config->mode & ETM_MODE_TIMESTAMP) { if (!(drvdata->etmccer & ETMCCER_TIMESTAMP)) { dev_warn(drvdata->dev, "timestamp not supported\n"); ret = -EINVAL; goto err_unlock; } config->ctrl |= ETMCR_TIMESTAMP_EN; } else config->ctrl &= ~ETMCR_TIMESTAMP_EN; if (config->mode & ETM_MODE_CTXID) config->ctrl |= ETMCR_CTXID_SIZE; else config->ctrl &= ~ETMCR_CTXID_SIZE; if (config->mode & ETM_MODE_BBROAD) config->ctrl |= ETMCR_BRANCH_BROADCAST; else config->ctrl &= ~ETMCR_BRANCH_BROADCAST; if (config->mode & ETM_MODE_RET_STACK) config->ctrl |= ETMCR_RETURN_STACK; else config->ctrl &= ~ETMCR_RETURN_STACK; if (config->mode & (ETM_MODE_EXCL_KERN | ETM_MODE_EXCL_USER)) etm_config_trace_mode(config); spin_unlock(&drvdata->spinlock); return size; err_unlock: spin_unlock(&drvdata->spinlock); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Mathieu J. Poirier30387.32%375.00%
Muhammad Abdul WAHAB4412.68%125.00%
Total347100.00%4100.00%

static DEVICE_ATTR_RW(mode);
static ssize_t trigger_event_show(struct device *dev, struct device_attribute *attr, char *buf) { unsigned long val; struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); struct etm_config *config = &drvdata->config; val = config->trigger_event; return sprintf(buf, "%#lx\n", val); }

Contributors

PersonTokensPropCommitsCommitProp
Mathieu J. Poirier62100.00%2100.00%
Total62100.00%2100.00%


static ssize_t trigger_event_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { int ret; unsigned long val; struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); struct etm_config *config = &drvdata->config; ret = kstrtoul(buf, 16, &val); if (ret) return ret; config->trigger_event = val & ETM_EVENT_MASK; return size; }

Contributors

PersonTokensPropCommitsCommitProp
Mathieu J. Poirier83100.00%2100.00%
Total83100.00%2100.00%

static DEVICE_ATTR_RW(trigger_event);
static ssize_t enable_event_show(struct device *dev, struct device_attribute *attr, char *buf) { unsigned long val; struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); struct etm_config *config = &drvdata->config; val = config->enable_event; return sprintf(buf, "%#lx\n", val); }

Contributors

PersonTokensPropCommitsCommitProp
Mathieu J. Poirier62100.00%2100.00%
Total62100.00%2100.00%


static ssize_t enable_event_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { int ret; unsigned long val; struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); struct etm_config *config = &drvdata->config; ret = kstrtoul(buf, 16, &val); if (ret) return ret; config->enable_event = val & ETM_EVENT_MASK; return size; }

Contributors

PersonTokensPropCommitsCommitProp
Mathieu J. Poirier83100.00%2100.00%
Total83100.00%2100.00%

static DEVICE_ATTR_RW(enable_event);
static ssize_t fifofull_level_show(struct device *dev, struct device_attribute *attr, char *buf) { unsigned long val; struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); struct etm_config *config = &drvdata->config; val = config->fifofull_level; return sprintf(buf, "%#lx\n", val); }

Contributors

PersonTokensPropCommitsCommitProp
Mathieu J. Poirier62100.00%2100.00%
Total62100.00%2100.00%


static ssize_t fifofull_level_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { int ret; unsigned long val; struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); struct etm_config *config = &drvdata->config; ret = kstrtoul(buf, 16, &val); if (ret) return ret; config->fifofull_level = val; return size; }

Contributors

PersonTokensPropCommitsCommitProp
Mathieu J. Poirier81100.00%2100.00%
Total81100.00%2100.00%

static DEVICE_ATTR_RW(fifofull_level);
static ssize_t addr_idx_show(struct device *dev, struct device_attribute *attr, char *buf) { unsigned long val; struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); struct etm_config *config = &drvdata->config; val = config->addr_idx; return sprintf(buf, "%#lx\n", val); }

Contributors

PersonTokensPropCommitsCommitProp
Mathieu J. Poirier62100.00%2100.00%
Total62100.00%2100.00%


static ssize_t addr_idx_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { int ret; unsigned long val; struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); struct etm_config *config = &drvdata->config; ret = kstrtoul(buf, 16, &val); if (ret) return ret; if (val >= drvdata->nr_addr_cmp) return -EINVAL; /* * Use spinlock to ensure index doesn't change while it gets * dereferenced multiple times within a spinlock block elsewhere. */ spin_lock(&drvdata->spinlock); config->addr_idx = val; spin_unlock(&drvdata->spinlock); return size; }

Contributors

PersonTokensPropCommitsCommitProp
Mathieu J. Poirier110100.00%2100.00%
Total110100.00%2100.00%

static DEVICE_ATTR_RW(addr_idx);
static ssize_t addr_single_show(struct device *dev, struct device_attribute *attr, char *buf) { u8 idx; unsigned long val; struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); struct etm_config *config = &drvdata->config; spin_lock(&drvdata->spinlock); idx = config->addr_idx; if (!(config->addr_type[idx] == ETM_ADDR_TYPE_NONE || config->addr_type[idx] == ETM_ADDR_TYPE_SINGLE)) { spin_unlock(&drvdata->spinlock); return -EINVAL; } val = config->addr_val[idx]; spin_unlock(&drvdata->spinlock); return sprintf(buf, "%#lx\n", val); }

Contributors

PersonTokensPropCommitsCommitProp
Mathieu J. Poirier127100.00%2100.00%
Total127100.00%2100.00%


static ssize_t addr_single_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { u8 idx; int ret; unsigned long val; struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); struct etm_config *config = &drvdata->config; ret = kstrtoul(buf, 16, &val); if (ret) return ret; spin_lock(&drvdata->spinlock); idx = config->addr_idx; if (!(config->addr_type[idx] == ETM_ADDR_TYPE_NONE || config->addr_type[idx] == ETM_ADDR_TYPE_SINGLE)) { spin_unlock(&drvdata->spinlock); return -EINVAL; } config->addr_val[idx] = val; config->addr_type[idx] = ETM_ADDR_TYPE_SINGLE; spin_unlock(&drvdata->spinlock); return size; }

Contributors

PersonTokensPropCommitsCommitProp
Mathieu J. Poirier155100.00%2100.00%
Total155100.00%2100.00%

static DEVICE_ATTR_RW(addr_single);
static ssize_t addr_range_show(struct device *dev, struct device_attribute *attr, char *buf) { u8 idx; unsigned long val1, val2; struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); struct etm_config *config = &drvdata->config; spin_lock(&drvdata->spinlock); idx = config->addr_idx; if (idx % 2 != 0) { spin_unlock(&drvdata->spinlock); return -EPERM; } if (!((config->addr_type[idx] == ETM_ADDR_TYPE_NONE && config->addr_type[idx + 1] == ETM_ADDR_TYPE_NONE) || (config->addr_type[idx] == ETM_ADDR_TYPE_RANGE && config->addr_type[idx + 1] == ETM_ADDR_TYPE_RANGE))) { spin_unlock(&drvdata->spinlock); return -EPERM; } val1 = config->addr_val[idx]; val2 = config->addr_val[idx + 1]; spin_unlock(&drvdata->spinlock); return sprintf(buf, "%#lx %#lx\n", val1, val2); }

Contributors

PersonTokensPropCommitsCommitProp
Mathieu J. Poirier190100.00%2100.00%
Total190100.00%2100.00%


static ssize_t addr_range_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { u8 idx; unsigned long val1, val2; struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); struct etm_config *config = &drvdata->config; if (sscanf(buf, "%lx %lx", &val1, &val2) != 2) return -EINVAL; /* Lower address comparator cannot have a higher address value */ if (val1 > val2) return -EINVAL; spin_lock(&drvdata->spinlock); idx = config->addr_idx; if (idx % 2 != 0) { spin_unlock(&drvdata->spinlock); return -EPERM; } if (!((config->addr_type[idx] == ETM_ADDR_TYPE_NONE && config->addr_type[idx + 1] == ETM_ADDR_TYPE_NONE) || (config->addr_type[idx] == ETM_ADDR_TYPE_RANGE && config->addr_type[idx + 1] == ETM_ADDR_TYPE_RANGE))) { spin_unlock(&drvdata->spinlock); return -EPERM; } config->addr_val[idx] = val1; config->addr_type[idx] = ETM_ADDR_TYPE_RANGE; config->addr_val[idx + 1] = val2; config->addr_type[idx + 1] = ETM_ADDR_TYPE_RANGE; config->enable_ctrl1 |= (1 << (idx/2)); spin_unlock(&drvdata->spinlock); return size; }

Contributors

PersonTokensPropCommitsCommitProp
Mathieu J. Poirier251100.00%2100.00%
Total251100.00%2100.00%

static DEVICE_ATTR_RW(addr_range);
static ssize_t addr_start_show(struct device *dev, struct device_attribute *attr, char *buf) { u8 idx; unsigned long val; struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); struct etm_config *config = &drvdata->config; spin_lock(&drvdata->spinlock); idx = config->addr_idx; if (!(config->addr_type[idx] == ETM_ADDR_TYPE_NONE || config->addr_type[idx] == ETM_ADDR_TYPE_START)) { spin_unlock(&drvdata->spinlock); return -EPERM; } val = config->addr_val[idx]; spin_unlock(&drvdata->spinlock); return sprintf(buf, "%#lx\n", val); }

Contributors

PersonTokensPropCommitsCommitProp
Mathieu J. Poirier127100.00%2100.00%
Total127100.00%2100.00%


static ssize_t addr_start_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { u8 idx; int ret; unsigned long val; struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); struct etm_config *config = &drvdata->config; ret = kstrtoul(buf, 16, &val); if (ret) return ret; spin_lock(&drvdata->spinlock); idx = config->addr_idx; if (!(config->addr_type[idx] == ETM_ADDR_TYPE_NONE || config->addr_type[idx] == ETM_ADDR_TYPE_START)) { spin_unlock(&drvdata->spinlock); return -EPERM; } config->addr_val[idx] = val; config->addr_type[idx] = ETM_ADDR_TYPE_START; config->startstop_ctrl |= (1 << idx); config->enable_ctrl1 |= BIT(25); spin_unlock(&drvdata->spinlock); return size; }

Contributors

PersonTokensPropCommitsCommitProp
Mathieu J. Poirier174100.00%2100.00%
Total174100.00%2100.00%

static DEVICE_ATTR_RW(addr_start);
static ssize_t addr_stop_show(struct device *dev, struct device_attribute *attr, char *buf) { u8 idx; unsigned long val; struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); struct etm_config *config = &drvdata->config; spin_lock(&drvdata->spinlock); idx = config->addr_idx; if (!(config->addr_type[idx] == ETM_ADDR_TYPE_NONE || config->addr_type[idx] == ETM_ADDR_TYPE_STOP)) { spin_unlock(&drvdata->spinlock); return -EPERM; } val = config->addr_val[idx]; spin_unlock(&drvdata->spinlock); return sprintf(buf, "%#lx\n", val); }

Contributors

PersonTokensPropCommitsCommitProp
Mathieu J. Poirier127100.00%2100.00%
Total127100.00%2100.00%


static ssize_t addr_stop_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { u8 idx; int ret; unsigned long val; struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); struct etm_config *config = &drvdata->config; ret = kstrtoul(buf, 16, &val); if (ret) return ret; spin_lock(&drvdata->spinlock); idx = config->addr_idx; if (!(config->addr_type[idx] == ETM_ADDR_TYPE_NONE || config->addr_type[idx] == ETM_ADDR_TYPE_STOP)) { spin_unlock(&drvdata->spinlock); return -EPERM; } config->addr_val[idx] = val; config->addr_type[idx] = ETM_ADDR_TYPE_STOP; config->startstop_ctrl |= (1 << (idx + 16)); config->enable_ctrl1 |= ETMTECR1_START_STOP; spin_unlock(&drvdata->spinlock); return size; }

Contributors

PersonTokensPropCommitsCommitProp
Mathieu J. Poirier175100.00%2100.00%
Total175100.00%2100.00%

static DEVICE_ATTR_RW(addr_stop);
static ssize_t addr_acctype_show(struct device *dev, struct device_attribute *attr, char *buf) { unsigned long val; struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); struct etm_config *config = &drvdata->config; spin_lock(&drvdata->spinlock); val = config->addr_acctype[config->addr_idx]; spin_unlock