mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-13 08:07:32 -04:00
Merge "coresight: enable stm logging for trace events, marker and printk"
This commit is contained in:
commit
4f5296141c
17 changed files with 657 additions and 80 deletions
|
|
@ -99,6 +99,7 @@ config CORESIGHT_STM
|
|||
depends on (ARM && !(CPU_32v3 || CPU_32v4 || CPU_32v4T)) || ARM64
|
||||
select CORESIGHT_LINKS_AND_SINKS
|
||||
select STM
|
||||
select CORESIGHT_OST if CORESIGHT_QGKI
|
||||
help
|
||||
This driver provides support for hardware assisted software
|
||||
instrumentation based tracing. This is primarily used for
|
||||
|
|
@ -263,4 +264,12 @@ config CORESIGHT_TGU
|
|||
provide a trigger point for centering data around a specific event
|
||||
within the trace data buffer.
|
||||
|
||||
config CORESIGHT_OST
|
||||
bool "CoreSight OST framework"
|
||||
depends on CORESIGHT_STM && COREISGHT_QGKI
|
||||
help
|
||||
This driver enables the support for Open System Trace packets in STM.
|
||||
This is primarily intended to be used as a layer on top of underlying
|
||||
physical byte transport mechanisms.The additional header can be used
|
||||
to provide more information.
|
||||
endif
|
||||
|
|
|
|||
|
|
@ -26,3 +26,4 @@ obj-$(CONFIG_CORESIGHT_DUMMY) += coresight-dummy.o
|
|||
obj-$(CONFIG_CORESIGHT_REMOTE_ETM) += coresight-remote-etm.o
|
||||
obj-$(CONFIG_CORESIGHT_CSR) += coresight-csr.o
|
||||
obj-$(CONFIG_CORESIGHT_TGU) += coresight-tgu.o
|
||||
obj-$(CONFIG_CORESIGHT_OST) += coresight-ost.o
|
||||
|
|
|
|||
290
drivers/hwtracing/coresight/coresight-ost.c
Normal file
290
drivers/hwtracing/coresight/coresight-ost.c
Normal file
|
|
@ -0,0 +1,290 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/bitmap.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/coresight.h>
|
||||
#include "coresight-ost.h"
|
||||
#include <linux/sched/clock.h>
|
||||
|
||||
#define STM_USERSPACE_HEADER_SIZE (8)
|
||||
#define STM_USERSPACE_MAGIC1_VAL (0xf0)
|
||||
#define STM_USERSPACE_MAGIC2_VAL (0xf1)
|
||||
|
||||
#define OST_TOKEN_STARTSIMPLE (0x10)
|
||||
#define OST_VERSION_MIPI1 (16)
|
||||
|
||||
#define STM_MAKE_VERSION(ma, mi) ((ma << 8) | mi)
|
||||
#define STM_HEADER_MAGIC (0x5953)
|
||||
|
||||
#define STM_FLAG_MARKED BIT(4)
|
||||
|
||||
#define STM_TRACE_BUF_SIZE 4096
|
||||
|
||||
static struct stm_drvdata *stmdrvdata;
|
||||
|
||||
static uint32_t stm_channel_alloc(void)
|
||||
{
|
||||
struct stm_drvdata *drvdata = stmdrvdata;
|
||||
uint32_t ch, off, num_ch_per_cpu;
|
||||
int cpu;
|
||||
|
||||
num_ch_per_cpu = drvdata->numsp/num_present_cpus();
|
||||
|
||||
cpu = get_cpu();
|
||||
|
||||
off = num_ch_per_cpu * cpu;
|
||||
ch = find_next_zero_bit(drvdata->chs.bitmap,
|
||||
drvdata->numsp, off);
|
||||
if (unlikely(ch >= (off + num_ch_per_cpu))) {
|
||||
put_cpu();
|
||||
return drvdata->numsp;
|
||||
}
|
||||
|
||||
set_bit(ch, drvdata->chs.bitmap);
|
||||
put_cpu();
|
||||
|
||||
return ch;
|
||||
}
|
||||
|
||||
static int stm_ost_send(void __iomem *addr, const void *data, uint32_t size)
|
||||
{
|
||||
uint32_t len = size;
|
||||
|
||||
if (((unsigned long)data & 0x1) && (size >= 1)) {
|
||||
writeb_relaxed_no_log(*(uint8_t *)data, addr);
|
||||
data++;
|
||||
size--;
|
||||
}
|
||||
if (((unsigned long)data & 0x2) && (size >= 2)) {
|
||||
writew_relaxed_no_log(*(uint16_t *)data, addr);
|
||||
data += 2;
|
||||
size -= 2;
|
||||
}
|
||||
|
||||
/* now we are 32bit aligned */
|
||||
while (size >= 4) {
|
||||
writel_relaxed_no_log(*(uint32_t *)data, addr);
|
||||
data += 4;
|
||||
size -= 4;
|
||||
}
|
||||
|
||||
if (size >= 2) {
|
||||
writew_relaxed_no_log(*(uint16_t *)data, addr);
|
||||
data += 2;
|
||||
size -= 2;
|
||||
}
|
||||
if (size >= 1) {
|
||||
writeb_relaxed_no_log(*(uint8_t *)data, addr);
|
||||
data++;
|
||||
size--;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static void stm_channel_free(uint32_t ch)
|
||||
{
|
||||
struct stm_drvdata *drvdata = stmdrvdata;
|
||||
|
||||
clear_bit(ch, drvdata->chs.bitmap);
|
||||
}
|
||||
|
||||
static int stm_trace_ost_header(void __iomem *ch_addr, uint32_t flags,
|
||||
uint8_t entity_id, uint8_t proto_id)
|
||||
{
|
||||
void __iomem *addr;
|
||||
uint32_t header;
|
||||
char *hdr;
|
||||
|
||||
hdr = (char *)&header;
|
||||
|
||||
hdr[0] = OST_TOKEN_STARTSIMPLE;
|
||||
hdr[1] = OST_VERSION_MIPI1;
|
||||
hdr[2] = entity_id;
|
||||
hdr[3] = proto_id;
|
||||
|
||||
/* header is expected to be D32M type */
|
||||
flags |= STM_FLAG_MARKED;
|
||||
flags &= ~STM_FLAG_TIMESTAMPED;
|
||||
addr = (void __iomem *)(ch_addr +
|
||||
stm_channel_off(STM_PKT_TYPE_DATA, flags));
|
||||
|
||||
return stm_ost_send(addr, &header, sizeof(header));
|
||||
}
|
||||
|
||||
static int stm_trace_data_header(void __iomem *addr)
|
||||
{
|
||||
char hdr[24];
|
||||
int len = 0;
|
||||
|
||||
*(uint16_t *)(hdr) = STM_MAKE_VERSION(0, 2);
|
||||
*(uint16_t *)(hdr + 2) = STM_HEADER_MAGIC;
|
||||
*(uint32_t *)(hdr + 4) = raw_smp_processor_id();
|
||||
*(uint64_t *)(hdr + 8) = sched_clock();
|
||||
*(uint64_t *)(hdr + 16) = task_tgid_nr(get_current());
|
||||
|
||||
len += stm_ost_send(addr, hdr, sizeof(hdr));
|
||||
len += stm_ost_send(addr, current->comm, TASK_COMM_LEN);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int stm_trace_data(void __iomem *ch_addr, uint32_t flags,
|
||||
const void *data, uint32_t size)
|
||||
{
|
||||
void __iomem *addr;
|
||||
int len = 0;
|
||||
|
||||
flags &= ~STM_FLAG_TIMESTAMPED;
|
||||
addr = (void __iomem *)(ch_addr +
|
||||
stm_channel_off(STM_PKT_TYPE_DATA, flags));
|
||||
|
||||
/* send the data header */
|
||||
len += stm_trace_data_header(addr);
|
||||
/* send the actual data */
|
||||
len += stm_ost_send(addr, data, size);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int stm_trace_ost_tail(void __iomem *ch_addr, uint32_t flags)
|
||||
{
|
||||
void __iomem *addr;
|
||||
uint32_t tail = 0x0;
|
||||
|
||||
addr = (void __iomem *)(ch_addr +
|
||||
stm_channel_off(STM_PKT_TYPE_FLAG, flags));
|
||||
|
||||
return stm_ost_send(addr, &tail, sizeof(tail));
|
||||
}
|
||||
|
||||
static inline int __stm_trace(uint32_t flags, uint8_t entity_id,
|
||||
uint8_t proto_id, const void *data, uint32_t size)
|
||||
{
|
||||
struct stm_drvdata *drvdata = stmdrvdata;
|
||||
int len = 0;
|
||||
uint32_t ch;
|
||||
void __iomem *ch_addr;
|
||||
|
||||
/* allocate channel and get the channel address */
|
||||
ch = stm_channel_alloc();
|
||||
if (unlikely(ch >= drvdata->numsp)) {
|
||||
drvdata->ch_alloc_fail_count++;
|
||||
dev_err_ratelimited(&drvdata->csdev->dev,
|
||||
"Channel allocation failed %d",
|
||||
drvdata->ch_alloc_fail_count);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ch_addr = (void __iomem *)stm_channel_addr(drvdata, ch);
|
||||
|
||||
/* send the ost header */
|
||||
len += stm_trace_ost_header(ch_addr, flags, entity_id,
|
||||
proto_id);
|
||||
|
||||
/* send the payload data */
|
||||
len += stm_trace_data(ch_addr, flags, data, size);
|
||||
|
||||
/* send the ost tail */
|
||||
len += stm_trace_ost_tail(ch_addr, flags);
|
||||
|
||||
/* we are done, free the channel */
|
||||
stm_channel_free(ch);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/*
|
||||
* stm_trace - trace the binary or string data through STM
|
||||
* @flags: tracing options - guaranteed, timestamped, etc
|
||||
* @entity_id: entity representing the trace data
|
||||
* @proto_id: protocol id to distinguish between different binary formats
|
||||
* @data: pointer to binary or string data buffer
|
||||
* @size: size of data to send
|
||||
*
|
||||
* Packetizes the data as the payload to an OST packet and sends it over STM
|
||||
*
|
||||
* CONTEXT:
|
||||
* Can be called from any context.
|
||||
*
|
||||
* RETURNS:
|
||||
* number of bytes transferred over STM
|
||||
*/
|
||||
int stm_trace(uint32_t flags, uint8_t entity_id, uint8_t proto_id,
|
||||
const void *data, uint32_t size)
|
||||
{
|
||||
struct stm_drvdata *drvdata = stmdrvdata;
|
||||
|
||||
/* we don't support sizes more than 24bits (0 to 23) */
|
||||
if (!(drvdata && drvdata->enable &&
|
||||
test_bit(entity_id, drvdata->entities) && size &&
|
||||
(size < 0x1000000)))
|
||||
return 0;
|
||||
|
||||
return __stm_trace(flags, entity_id, proto_id, data, size);
|
||||
}
|
||||
EXPORT_SYMBOL(stm_trace);
|
||||
|
||||
ssize_t stm_ost_packet(struct stm_data *stm_data,
|
||||
unsigned int size,
|
||||
const unsigned char *buf)
|
||||
{
|
||||
struct stm_drvdata *drvdata = container_of(stm_data,
|
||||
struct stm_drvdata, stm);
|
||||
|
||||
uint8_t entity_id, proto_id;
|
||||
uint32_t flags;
|
||||
|
||||
if (!drvdata->enable || !size)
|
||||
return -EINVAL;
|
||||
|
||||
if (size > STM_TRACE_BUF_SIZE)
|
||||
size = STM_TRACE_BUF_SIZE;
|
||||
|
||||
if (size >= STM_USERSPACE_HEADER_SIZE &&
|
||||
buf[0] == STM_USERSPACE_MAGIC1_VAL &&
|
||||
buf[1] == STM_USERSPACE_MAGIC2_VAL) {
|
||||
|
||||
entity_id = buf[2];
|
||||
proto_id = buf[3];
|
||||
flags = *(uint32_t *)(buf + 4);
|
||||
|
||||
if (!test_bit(entity_id, drvdata->entities) ||
|
||||
!(size - STM_USERSPACE_HEADER_SIZE)) {
|
||||
return size;
|
||||
}
|
||||
|
||||
__stm_trace(flags, entity_id, proto_id,
|
||||
buf + STM_USERSPACE_HEADER_SIZE,
|
||||
size - STM_USERSPACE_HEADER_SIZE);
|
||||
} else {
|
||||
if (!test_bit(OST_ENTITY_DEV_NODE, drvdata->entities))
|
||||
return size;
|
||||
|
||||
__stm_trace(STM_FLAG_TIMESTAMPED, OST_ENTITY_DEV_NODE, 0,
|
||||
buf, size);
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
EXPORT_SYMBOL(stm_ost_packet);
|
||||
|
||||
int stm_set_ost_params(struct device *dev, struct stm_drvdata *drvdata,
|
||||
size_t bitmap_size)
|
||||
{
|
||||
drvdata->chs.bitmap = devm_kzalloc(dev, bitmap_size,
|
||||
GFP_KERNEL);
|
||||
if (!drvdata->chs.bitmap)
|
||||
return -ENOMEM;
|
||||
|
||||
bitmap_fill(drvdata->entities, OST_ENTITY_MAX);
|
||||
stmdrvdata = drvdata;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(stm_set_ost_params);
|
||||
|
||||
37
drivers/hwtracing/coresight/coresight-ost.h
Normal file
37
drivers/hwtracing/coresight/coresight-ost.h
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _CORESIGHT_CORESIGHT_OST_H
|
||||
#define _CORESIGHT_CORESIGHT_OST_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/coresight-stm.h>
|
||||
|
||||
#ifdef CONFIG_CORESIGHT_OST
|
||||
static inline bool stm_ost_configured(void) { return true; }
|
||||
|
||||
extern ssize_t stm_ost_packet(struct stm_data *stm_data,
|
||||
unsigned int size,
|
||||
const unsigned char *buf);
|
||||
|
||||
extern int stm_set_ost_params(struct device *dev, struct stm_drvdata *drvdata,
|
||||
size_t bitmap_size);
|
||||
#else
|
||||
static inline bool stm_ost_configured(void) { return false; }
|
||||
|
||||
static inline ssize_t stm_ost_packet(struct stm_data *stm_data,
|
||||
unsigned int size,
|
||||
const unsigned char *buf)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int stm_set_ost_params(struct stm_drvdata *drvdata,
|
||||
size_t bitmap_size)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* Description: CoreSight System Trace Macrocell driver
|
||||
*
|
||||
|
|
@ -30,6 +30,7 @@
|
|||
#include <linux/pm_runtime.h>
|
||||
#include <linux/stm.h>
|
||||
|
||||
#include "coresight-ost.h"
|
||||
#include "coresight-priv.h"
|
||||
|
||||
#define STMDMASTARTR 0xc04
|
||||
|
|
@ -67,8 +68,6 @@
|
|||
#define STMITATBCTR0 0xef8
|
||||
|
||||
#define STM_32_CHANNEL 32
|
||||
#define BYTES_PER_CHANNEL 256
|
||||
#define STM_TRACE_BUF_SIZE 4096
|
||||
#define STM_SW_MASTER_END 127
|
||||
|
||||
/* Register bit definition */
|
||||
|
|
@ -76,15 +75,7 @@
|
|||
/* Reserve the first 10 channels for kernel usage */
|
||||
#define STM_CHANNEL_OFFSET 0
|
||||
|
||||
enum stm_pkt_type {
|
||||
STM_PKT_TYPE_DATA = 0x98,
|
||||
STM_PKT_TYPE_FLAG = 0xE8,
|
||||
STM_PKT_TYPE_TRIG = 0xF8,
|
||||
};
|
||||
|
||||
#define stm_channel_addr(drvdata, ch) (drvdata->chs.base + \
|
||||
(ch * BYTES_PER_CHANNEL))
|
||||
#define stm_channel_off(type, opts) (type & ~opts)
|
||||
DEFINE_CORESIGHT_DEVLIST(stm_devs, "stm");
|
||||
|
||||
static int boot_nr_channel;
|
||||
|
||||
|
|
@ -96,56 +87,6 @@ module_param_named(
|
|||
boot_nr_channel, boot_nr_channel, int, S_IRUGO
|
||||
);
|
||||
|
||||
/**
|
||||
* struct channel_space - central management entity for extended ports
|
||||
* @base: memory mapped base address where channels start.
|
||||
* @phys: physical base address of channel region.
|
||||
* @guaraneed: is the channel delivery guaranteed.
|
||||
*/
|
||||
struct channel_space {
|
||||
void __iomem *base;
|
||||
phys_addr_t phys;
|
||||
unsigned long *guaranteed;
|
||||
};
|
||||
|
||||
DEFINE_CORESIGHT_DEVLIST(stm_devs, "stm");
|
||||
|
||||
/**
|
||||
* struct stm_drvdata - specifics associated to an STM component
|
||||
* @base: memory mapped base address for this component.
|
||||
* @atclk: optional clock for the core parts of the STM.
|
||||
* @csdev: component vitals needed by the framework.
|
||||
* @spinlock: only one at a time pls.
|
||||
* @chs: the channels accociated to this STM.
|
||||
* @stm: structure associated to the generic STM interface.
|
||||
* @mode: this tracer's mode, i.e sysFS, or disabled.
|
||||
* @traceid: value of the current ID for this component.
|
||||
* @write_bytes: Maximus bytes this STM can write at a time.
|
||||
* @stmsper: settings for register STMSPER.
|
||||
* @stmspscr: settings for register STMSPSCR.
|
||||
* @numsp: the total number of stimulus port support by this STM.
|
||||
* @stmheer: settings for register STMHEER.
|
||||
* @stmheter: settings for register STMHETER.
|
||||
* @stmhebsr: settings for register STMHEBSR.
|
||||
*/
|
||||
struct stm_drvdata {
|
||||
void __iomem *base;
|
||||
struct clk *atclk;
|
||||
struct coresight_device *csdev;
|
||||
spinlock_t spinlock;
|
||||
struct channel_space chs;
|
||||
struct stm_data stm;
|
||||
local_t mode;
|
||||
u8 traceid;
|
||||
u32 write_bytes;
|
||||
u32 stmsper;
|
||||
u32 stmspscr;
|
||||
u32 numsp;
|
||||
u32 stmheer;
|
||||
u32 stmheter;
|
||||
u32 stmhebsr;
|
||||
};
|
||||
|
||||
static void stm_hwevent_enable_hw(struct stm_drvdata *drvdata)
|
||||
{
|
||||
CS_UNLOCK(drvdata->base);
|
||||
|
|
@ -210,6 +151,7 @@ static int stm_enable(struct coresight_device *csdev,
|
|||
|
||||
spin_lock(&drvdata->spinlock);
|
||||
stm_enable_hw(drvdata);
|
||||
drvdata->enable = true;
|
||||
spin_unlock(&drvdata->spinlock);
|
||||
|
||||
dev_dbg(&csdev->dev, "STM tracing enabled\n");
|
||||
|
|
@ -267,6 +209,7 @@ static void stm_disable(struct coresight_device *csdev,
|
|||
if (local_read(&drvdata->mode) == CS_MODE_SYSFS) {
|
||||
spin_lock(&drvdata->spinlock);
|
||||
stm_disable_hw(drvdata);
|
||||
drvdata->enable = false;
|
||||
spin_unlock(&drvdata->spinlock);
|
||||
|
||||
/* Wait until the engine has completely stopped */
|
||||
|
|
@ -350,7 +293,11 @@ static void stm_generic_unlink(struct stm_data *stm_data,
|
|||
struct stm_drvdata, stm);
|
||||
if (!drvdata || !drvdata->csdev)
|
||||
return;
|
||||
|
||||
#ifdef CONFIG_CORESIGHT_QGKI
|
||||
/* If any OST entity is enabled do not disable the device */
|
||||
if (!bitmap_empty(drvdata->entities, OST_ENTITY_MAX))
|
||||
return;
|
||||
#endif
|
||||
coresight_disable(drvdata->csdev);
|
||||
}
|
||||
|
||||
|
|
@ -630,6 +577,53 @@ static ssize_t traceid_store(struct device *dev,
|
|||
}
|
||||
static DEVICE_ATTR_RW(traceid);
|
||||
|
||||
#ifdef CONFIG_CORESIGHT_QGKI
|
||||
static ssize_t entities_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct stm_drvdata *drvdata = dev_get_drvdata(dev->parent);
|
||||
ssize_t len;
|
||||
|
||||
len = scnprintf(buf, PAGE_SIZE, "%*pb\n",
|
||||
OST_ENTITY_MAX, drvdata->entities);
|
||||
|
||||
if (PAGE_SIZE - len < 2)
|
||||
len = -EINVAL;
|
||||
else
|
||||
len += scnprintf(buf + len, 2, "\n");
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static ssize_t entities_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
struct stm_drvdata *drvdata = dev_get_drvdata(dev->parent);
|
||||
unsigned long val1, val2;
|
||||
|
||||
if (sscanf(buf, "%lx %lx", &val1, &val2) != 2)
|
||||
return -EINVAL;
|
||||
|
||||
if (val1 >= OST_ENTITY_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
if (!stm_ost_configured())
|
||||
return -EPERM;
|
||||
|
||||
if (val2)
|
||||
__set_bit(val1, drvdata->entities);
|
||||
else
|
||||
__clear_bit(val1, drvdata->entities);
|
||||
|
||||
return size;
|
||||
}
|
||||
static DEVICE_ATTR_RW(entities);
|
||||
|
||||
#define coresight_stm_simple_func(name, offset) \
|
||||
|
||||
#endif
|
||||
|
||||
#define coresight_stm_reg(name, offset) \
|
||||
coresight_simple_reg32(struct stm_drvdata, name, offset)
|
||||
|
||||
|
|
@ -652,6 +646,9 @@ static struct attribute *coresight_stm_attrs[] = {
|
|||
&dev_attr_port_enable.attr,
|
||||
&dev_attr_port_select.attr,
|
||||
&dev_attr_traceid.attr,
|
||||
#ifdef CONFIG_CORESIGHT_QGKI
|
||||
&dev_attr_entities.attr,
|
||||
#endif
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
|
@ -803,7 +800,7 @@ static u32 stm_num_stimulus_port(struct stm_drvdata *drvdata)
|
|||
numsp &= 0x1ffff;
|
||||
if (!numsp)
|
||||
numsp = STM_32_CHANNEL;
|
||||
return numsp;
|
||||
return STM_32_CHANNEL;
|
||||
}
|
||||
|
||||
static void stm_init_default_data(struct stm_drvdata *drvdata)
|
||||
|
|
@ -818,12 +815,12 @@ static void stm_init_default_data(struct stm_drvdata *drvdata)
|
|||
drvdata->stmsper = ~0x0;
|
||||
|
||||
/*
|
||||
* The trace ID value for *ETM* tracers start at CPU_ID * 2 + 0x10 and
|
||||
* anything equal to or higher than 0x70 is reserved. Since 0x00 is
|
||||
* also reserved the STM trace ID needs to be higher than 0x00 and
|
||||
* lowner than 0x10.
|
||||
* The trace ID value for *ETM* tracers start at CPU_ID + 0x1 and
|
||||
* anything equal to or higher than 0x70 is reserved. Since 0x00 is
|
||||
* also reserved the STM trace ID needs to be higher than number
|
||||
* of cpu i.e 0x8 in our case and lower than 0x70.
|
||||
*/
|
||||
drvdata->traceid = 0x1;
|
||||
drvdata->traceid = 0x10;
|
||||
|
||||
/* Set invariant transaction timing on all channels */
|
||||
bitmap_clear(drvdata->chs.guaranteed, 0, drvdata->numsp);
|
||||
|
|
@ -842,6 +839,10 @@ static void stm_init_generic_data(struct stm_drvdata *drvdata,
|
|||
drvdata->stm.sw_end = 1;
|
||||
drvdata->stm.hw_override = true;
|
||||
drvdata->stm.sw_nchannels = drvdata->numsp;
|
||||
#ifdef CONFIG_CORESIGHT_QGKI
|
||||
drvdata->stm.ost_configured = stm_ost_configured;
|
||||
drvdata->stm.ost_packet = stm_ost_packet;
|
||||
#endif
|
||||
drvdata->stm.sw_mmiosz = BYTES_PER_CHANNEL;
|
||||
drvdata->stm.packet = stm_generic_packet;
|
||||
drvdata->stm.mmio_addr = stm_mmio_addr;
|
||||
|
|
@ -902,6 +903,12 @@ static int stm_probe(struct amba_device *adev, const struct amba_id *id)
|
|||
drvdata->numsp = stm_num_stimulus_port(drvdata);
|
||||
|
||||
bitmap_size = BITS_TO_LONGS(drvdata->numsp) * sizeof(long);
|
||||
#ifdef CONFIG_CORESIGHT_QGKI
|
||||
/* Store the driver data pointer for use in exported functions */
|
||||
ret = stm_set_ost_params(dev, drvdata, bitmap_size);
|
||||
if (ret)
|
||||
return ret;
|
||||
#endif
|
||||
|
||||
guaranteed = devm_kzalloc(dev, bitmap_size, GFP_KERNEL);
|
||||
if (!guaranteed)
|
||||
|
|
|
|||
|
|
@ -580,7 +580,25 @@ ssize_t notrace stm_data_write(struct stm_data *data, unsigned int m,
|
|||
unsigned int flags = ts_first ? STP_PACKET_TIMESTAMPED : 0;
|
||||
ssize_t sz;
|
||||
size_t pos;
|
||||
#ifdef CONFIG_CORESIGHT_QGKI
|
||||
if (data->ost_configured()) {
|
||||
pos = data->ost_packet(data, count, buf);
|
||||
sz = 0;
|
||||
} else {
|
||||
for (pos = 0, sz = 0; pos < count; pos += sz) {
|
||||
sz = min_t(unsigned int, count - pos, 8);
|
||||
sz = data->packet(data, m, c, STP_PACKET_DATA, flags,
|
||||
sz, &((u8 *)buf)[pos]);
|
||||
if (sz <= 0)
|
||||
break;
|
||||
|
||||
if (ts_first) {
|
||||
flags = 0;
|
||||
ts_first = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
for (pos = 0, sz = 0; pos < count; pos += sz) {
|
||||
sz = min_t(unsigned int, count - pos, 8);
|
||||
sz = data->packet(data, m, c, STP_PACKET_DATA, flags, sz,
|
||||
|
|
@ -593,7 +611,7 @@ ssize_t notrace stm_data_write(struct stm_data *data, unsigned int m,
|
|||
ts_first = false;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
return sz < 0 ? sz : pos;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(stm_data_write);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,111 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2011-2012, 2017, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
#ifndef __LINUX_CORESIGHT_STM_H_
|
||||
#define __LINUX_CORESIGHT_STM_H_
|
||||
|
||||
#include <asm/local.h>
|
||||
#include <linux/stm.h>
|
||||
#include <linux/bitmap.h>
|
||||
#include <uapi/linux/coresight-stm.h>
|
||||
|
||||
#define BYTES_PER_CHANNEL 256
|
||||
|
||||
enum stm_pkt_type {
|
||||
STM_PKT_TYPE_DATA = 0x98,
|
||||
STM_PKT_TYPE_FLAG = 0xE8,
|
||||
STM_PKT_TYPE_TRIG = 0xF8,
|
||||
};
|
||||
|
||||
#define stm_channel_off(type, opts) (type & ~opts)
|
||||
|
||||
#define stm_channel_addr(drvdata, ch) (drvdata->chs.base + \
|
||||
(ch * BYTES_PER_CHANNEL))
|
||||
|
||||
#define stm_log_inv(entity_id, proto_id, data, size) \
|
||||
stm_trace(STM_FLAG_NONE, entity_id, proto_id, data, size)
|
||||
|
||||
#define stm_log_inv_ts(entity_id, proto_id, data, size) \
|
||||
stm_trace(STM_FLAG_TIMESTAMPED, entity_id, proto_id, \
|
||||
data, size)
|
||||
|
||||
#define stm_log_gtd(entity_id, proto_id, data, size) \
|
||||
stm_trace(STM_FLAG_GUARANTEED, entity_id, proto_id, \
|
||||
data, size)
|
||||
|
||||
#define stm_log_gtd_ts(entity_id, proto_id, data, size) \
|
||||
stm_trace(STM_FLAG_GUARANTEED | STM_OPTION_TIMESTAMPED, \
|
||||
entity_id, proto_id, data, size)
|
||||
|
||||
#define stm_log(entity_id, data, size) \
|
||||
stm_log_inv_ts(entity_id, 0, data, size)
|
||||
|
||||
/**
|
||||
* struct channel_space - central management entity for extended ports
|
||||
* @base: memory mapped base address where channels start.
|
||||
* @phys: physical base address of channel region.
|
||||
* @guaraneed: is the channel delivery guaranteed.
|
||||
* @bitmap: channel info for OST packet
|
||||
*/
|
||||
struct channel_space {
|
||||
void __iomem *base;
|
||||
phys_addr_t phys;
|
||||
unsigned long *guaranteed;
|
||||
unsigned long *bitmap;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct stm_drvdata - specifics associated to an STM component
|
||||
* @base: memory mapped base address for this component.
|
||||
* @dev: the device entity associated to this component.
|
||||
* @atclk: optional clock for the core parts of the STM.
|
||||
* @csdev: component vitals needed by the framework.
|
||||
* @spinlock: only one at a time pls.
|
||||
* @chs: the channels accociated to this STM.
|
||||
* @entities currently configured OST entities.
|
||||
* @stm: structure associated to the generic STM interface.
|
||||
* @mode: this tracer's mode, i.e sysFS, or disabled.
|
||||
* @traceid: value of the current ID for this component.
|
||||
* @write_bytes: Maximus bytes this STM can write at a time.
|
||||
* @stmsper: settings for register STMSPER.
|
||||
* @stmspscr: settings for register STMSPSCR.
|
||||
* @numsp: the total number of stimulus port support by this STM.
|
||||
* @stmheer: settings for register STMHEER.
|
||||
* @stmheter: settings for register STMHETER.
|
||||
* @stmhebsr: settings for register STMHEBSR.
|
||||
* @ch_alloc_fail_count: Number of ch allocation failures over time.
|
||||
*/
|
||||
struct stm_drvdata {
|
||||
void __iomem *base;
|
||||
struct clk *atclk;
|
||||
struct coresight_device *csdev;
|
||||
spinlock_t spinlock;
|
||||
struct channel_space chs;
|
||||
bool enable;
|
||||
DECLARE_BITMAP(entities, OST_ENTITY_MAX);
|
||||
struct stm_data stm;
|
||||
local_t mode;
|
||||
u8 traceid;
|
||||
u32 write_bytes;
|
||||
u32 stmsper;
|
||||
u32 stmspscr;
|
||||
u32 numsp;
|
||||
u32 stmheer;
|
||||
u32 stmheter;
|
||||
u32 stmhebsr;
|
||||
u32 ch_alloc_fail_count;
|
||||
};
|
||||
|
||||
#if defined(CONFIG_CORESIGHT_STM) && defined(CONFIG_CORESIGHT_QGKI)
|
||||
extern int stm_trace(uint32_t flags, uint8_t entity_id, uint8_t proto_id,
|
||||
const void *data, uint32_t size);
|
||||
|
||||
#else
|
||||
static inline int stm_trace(uint32_t flags, uint8_t entity_id,
|
||||
uint8_t proto_id, const void *data, uint32_t size)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -80,6 +80,12 @@ struct stm_data {
|
|||
unsigned int sw_nchannels;
|
||||
unsigned int sw_mmiosz;
|
||||
unsigned int hw_override;
|
||||
#ifdef CONFIG_CORESIGHT_QGKI
|
||||
bool (*ost_configured)(void);
|
||||
ssize_t (*ost_packet)(struct stm_data *stm_data,
|
||||
unsigned int size,
|
||||
const unsigned char *buf);
|
||||
#endif
|
||||
ssize_t (*packet)(struct stm_data *, unsigned int,
|
||||
unsigned int, unsigned int,
|
||||
unsigned int, unsigned int,
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#include <linux/hardirq.h>
|
||||
#include <linux/perf_event.h>
|
||||
#include <linux/tracepoint.h>
|
||||
#include <linux/coresight-stm.h>
|
||||
|
||||
struct trace_array;
|
||||
struct trace_buffer;
|
||||
|
|
@ -216,8 +217,12 @@ struct trace_event_buffer {
|
|||
void *trace_event_buffer_reserve(struct trace_event_buffer *fbuffer,
|
||||
struct trace_event_file *trace_file,
|
||||
unsigned long len);
|
||||
|
||||
#ifdef CONFIG_CORESIGHT_QGKI
|
||||
void trace_event_buffer_commit(struct trace_event_buffer *fbuffer,
|
||||
unsigned long len);
|
||||
#else
|
||||
void trace_event_buffer_commit(struct trace_event_buffer *fbuffer);
|
||||
#endif
|
||||
|
||||
enum {
|
||||
TRACE_EVENT_FL_FILTERED_BIT,
|
||||
|
|
|
|||
|
|
@ -693,6 +693,37 @@ static inline notrace int trace_event_get_offsets_##call( \
|
|||
#define __perf_task(t) (t)
|
||||
|
||||
#undef DECLARE_EVENT_CLASS
|
||||
#ifdef CONFIG_CORESIGHT_QGKI
|
||||
#define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \
|
||||
\
|
||||
static notrace void \
|
||||
trace_event_raw_event_##call(void *__data, proto) \
|
||||
{ \
|
||||
struct trace_event_file *trace_file = __data; \
|
||||
struct trace_event_data_offsets_##call __maybe_unused __data_offsets;\
|
||||
struct trace_event_buffer fbuffer; \
|
||||
struct trace_event_raw_##call *entry; \
|
||||
int __data_size; \
|
||||
\
|
||||
if (trace_trigger_soft_disabled(trace_file)) \
|
||||
return; \
|
||||
\
|
||||
__data_size = trace_event_get_offsets_##call(&__data_offsets, args); \
|
||||
\
|
||||
entry = trace_event_buffer_reserve(&fbuffer, trace_file, \
|
||||
sizeof(*entry) + __data_size); \
|
||||
\
|
||||
if (!entry) \
|
||||
return; \
|
||||
\
|
||||
tstruct \
|
||||
\
|
||||
{ assign; } \
|
||||
\
|
||||
trace_event_buffer_commit(&fbuffer, \
|
||||
sizeof(*entry) + __data_size); \
|
||||
}
|
||||
#else
|
||||
#define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \
|
||||
\
|
||||
static notrace void \
|
||||
|
|
@ -721,6 +752,7 @@ trace_event_raw_event_##call(void *__data, proto) \
|
|||
\
|
||||
trace_event_buffer_commit(&fbuffer); \
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* The ftrace_test_probe is compiled out, it is only here as a build time check
|
||||
* to make sure that if the tracepoint handling changes, the ftrace probe will
|
||||
|
|
|
|||
|
|
@ -2,9 +2,18 @@
|
|||
#ifndef __UAPI_CORESIGHT_STM_H_
|
||||
#define __UAPI_CORESIGHT_STM_H_
|
||||
|
||||
#define STM_FLAG_TIMESTAMPED BIT(3)
|
||||
#define STM_FLAG_GUARANTEED BIT(7)
|
||||
#define STM_FLAG_NONE 0x00
|
||||
#define STM_FLAG_TIMESTAMPED 0x08
|
||||
#define STM_FLAG_GUARANTEED 0x80
|
||||
|
||||
#define OST_ENTITY_NONE 0x00
|
||||
#define OST_ENTITY_FTRACE_EVENTS 0x01
|
||||
#define OST_ENTITY_TRACE_PRINTK 0x02
|
||||
#define OST_ENTITY_TRACE_MARKER 0x04
|
||||
#define OST_ENTITY_DEV_NODE 0x08
|
||||
#define OST_ENTITY_DIAG 0xEE
|
||||
#define OST_ENTITY_QVIEW 0xFE
|
||||
#define OST_ENTITY_MAX 0xFF
|
||||
/*
|
||||
* The CoreSight STM supports guaranteed and invariant timing
|
||||
* transactions. Guaranteed transactions are guaranteed to be
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@
|
|||
#include <linux/trace.h>
|
||||
#include <linux/sched/clock.h>
|
||||
#include <linux/sched/rt.h>
|
||||
#include <linux/coresight-stm.h>
|
||||
|
||||
#include "trace.h"
|
||||
#include "trace_output.h"
|
||||
|
|
@ -2578,15 +2579,26 @@ int tracepoint_printk_sysctl(struct ctl_table *table, int write,
|
|||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CORESIGHT_QGKI
|
||||
void trace_event_buffer_commit(struct trace_event_buffer *fbuffer,
|
||||
unsigned long len)
|
||||
{
|
||||
if (static_key_false(&tracepoint_printk_key.key))
|
||||
output_printk(fbuffer);
|
||||
event_trigger_unlock_commit(fbuffer->trace_file, fbuffer->buffer,
|
||||
fbuffer->event, fbuffer->entry,
|
||||
fbuffer->flags, fbuffer->pc, len);
|
||||
}
|
||||
#else
|
||||
void trace_event_buffer_commit(struct trace_event_buffer *fbuffer)
|
||||
{
|
||||
if (static_key_false(&tracepoint_printk_key.key))
|
||||
output_printk(fbuffer);
|
||||
|
||||
event_trigger_unlock_commit(fbuffer->trace_file, fbuffer->buffer,
|
||||
fbuffer->event, fbuffer->entry,
|
||||
fbuffer->flags, fbuffer->pc);
|
||||
}
|
||||
#endif
|
||||
EXPORT_SYMBOL_GPL(trace_event_buffer_commit);
|
||||
|
||||
/*
|
||||
|
|
@ -3194,6 +3206,7 @@ __trace_array_vprintk(struct ring_buffer *buffer,
|
|||
|
||||
memcpy(&entry->buf, tbuffer, len + 1);
|
||||
if (!call_filter_check_discard(call, entry, buffer, event)) {
|
||||
stm_log(OST_ENTITY_TRACE_PRINTK, entry->buf, len + 1);
|
||||
__buffer_unlock_commit(buffer, event);
|
||||
ftrace_trace_stack(&global_trace, buffer, flags, 6, pc, NULL);
|
||||
}
|
||||
|
|
@ -6426,8 +6439,11 @@ tracing_mark_write(struct file *filp, const char __user *ubuf,
|
|||
if (entry->buf[cnt - 1] != '\n') {
|
||||
entry->buf[cnt] = '\n';
|
||||
entry->buf[cnt + 1] = '\0';
|
||||
} else
|
||||
stm_log(OST_ENTITY_TRACE_MARKER, entry->buf, cnt + 2);
|
||||
} else {
|
||||
entry->buf[cnt] = '\0';
|
||||
stm_log(OST_ENTITY_TRACE_MARKER, entry->buf, cnt + 1);
|
||||
}
|
||||
|
||||
__buffer_unlock_commit(buffer, event);
|
||||
|
||||
|
|
|
|||
|
|
@ -1426,11 +1426,34 @@ __event_trigger_test_discard(struct trace_event_file *file,
|
|||
* @entry: The event itself
|
||||
* @irq_flags: The state of the interrupts at the start of the event
|
||||
* @pc: The state of the preempt count at the start of the event.
|
||||
* @len: The length of the payload data required for stm logging.
|
||||
*
|
||||
* This is a helper function to handle triggers that require data
|
||||
* from the event itself. It also tests the event against filters and
|
||||
* if the event is soft disabled and should be discarded.
|
||||
*/
|
||||
#ifdef CONFIG_CORESIGHT_QGKI
|
||||
static inline void
|
||||
event_trigger_unlock_commit(struct trace_event_file *file,
|
||||
struct ring_buffer *buffer,
|
||||
struct ring_buffer_event *event,
|
||||
void *entry, unsigned long irq_flags, int pc,
|
||||
unsigned long len)
|
||||
{
|
||||
enum event_trigger_type tt = ETT_NONE;
|
||||
|
||||
if (!__event_trigger_test_discard(file, buffer, event, entry, &tt)) {
|
||||
if (len)
|
||||
stm_log(OST_ENTITY_FTRACE_EVENTS, entry, len);
|
||||
|
||||
trace_buffer_unlock_commit(file->tr, buffer, event,
|
||||
irq_flags, pc);
|
||||
}
|
||||
|
||||
if (tt)
|
||||
event_triggers_post_call(file, tt);
|
||||
}
|
||||
#else
|
||||
static inline void
|
||||
event_trigger_unlock_commit(struct trace_event_file *file,
|
||||
struct ring_buffer *buffer,
|
||||
|
|
@ -1445,7 +1468,7 @@ event_trigger_unlock_commit(struct trace_event_file *file,
|
|||
if (tt)
|
||||
event_triggers_post_call(file, tt);
|
||||
}
|
||||
|
||||
#endif
|
||||
/**
|
||||
* event_trigger_unlock_commit_regs - handle triggers and finish event commit
|
||||
* @file: The file pointer assoctiated to the event
|
||||
|
|
|
|||
|
|
@ -3384,9 +3384,13 @@ function_test_events_call(unsigned long ip, unsigned long parent_ip,
|
|||
entry = ring_buffer_event_data(event);
|
||||
entry->ip = ip;
|
||||
entry->parent_ip = parent_ip;
|
||||
|
||||
#ifdef CONFIG_CORESIGHT_QGKI
|
||||
event_trigger_unlock_commit(&event_trace_file, buffer, event,
|
||||
entry, flags, pc, 0);
|
||||
#else
|
||||
event_trigger_unlock_commit(&event_trace_file, buffer, event,
|
||||
entry, flags, pc);
|
||||
#endif
|
||||
out:
|
||||
atomic_dec(&per_cpu(ftrace_test_event_disable, cpu));
|
||||
preempt_enable_notrace();
|
||||
|
|
|
|||
|
|
@ -915,8 +915,11 @@ static notrace void trace_event_raw_event_synth(void *__data,
|
|||
n_u64++;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CORESIGHT_QGKI
|
||||
trace_event_buffer_commit(&fbuffer, sizeof(*entry) + fields_size);
|
||||
#else
|
||||
trace_event_buffer_commit(&fbuffer);
|
||||
#endif
|
||||
out:
|
||||
ring_buffer_nest_end(buffer);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -350,9 +350,13 @@ static void ftrace_syscall_enter(void *data, struct pt_regs *regs, long id)
|
|||
entry->nr = syscall_nr;
|
||||
syscall_get_arguments(current, regs, args);
|
||||
memcpy(entry->args, args, sizeof(unsigned long) * sys_data->nb_args);
|
||||
|
||||
#ifdef CONFIG_CORESIGHT_QGKI
|
||||
event_trigger_unlock_commit(trace_file, buffer, event, entry,
|
||||
irq_flags, pc, 0);
|
||||
#else
|
||||
event_trigger_unlock_commit(trace_file, buffer, event, entry,
|
||||
irq_flags, pc);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void ftrace_syscall_exit(void *data, struct pt_regs *regs, long ret)
|
||||
|
|
@ -397,8 +401,13 @@ static void ftrace_syscall_exit(void *data, struct pt_regs *regs, long ret)
|
|||
entry->nr = syscall_nr;
|
||||
entry->ret = syscall_get_return_value(current, regs);
|
||||
|
||||
#ifdef CONFIG_CORESIGHT_QGKI
|
||||
event_trigger_unlock_commit(trace_file, buffer, event, entry,
|
||||
irq_flags, pc, 0);
|
||||
#else
|
||||
event_trigger_unlock_commit(trace_file, buffer, event, entry,
|
||||
irq_flags, pc);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int reg_event_syscall_enter(struct trace_event_file *file,
|
||||
|
|
|
|||
|
|
@ -971,7 +971,11 @@ static void __uprobe_trace_func(struct trace_uprobe *tu,
|
|||
|
||||
memcpy(data, ucb->buf, tu->tp.size + dsize);
|
||||
|
||||
#ifdef CONFIG_CORESIGHT_QGKI
|
||||
event_trigger_unlock_commit(trace_file, buffer, event, entry, 0, 0, 0);
|
||||
#else
|
||||
event_trigger_unlock_commit(trace_file, buffer, event, entry, 0, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* uprobe handler */
|
||||
|
|
|
|||
Loading…
Reference in a new issue