Merge "coresight: enable stm logging for trace events, marker and printk"

This commit is contained in:
qctecmdr 2019-12-17 12:30:58 -08:00 • committed by Gerrit - the friendly Code Review server
commit 4f5296141c
17 changed files with 657 additions and 80 deletions

View file

@ -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

View file

@ -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

View 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);

View 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

View file

@ -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)

View file

@ -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);

View file

@ -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

View file

@ -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,

View file

@ -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,

View file

@ -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

View file

@ -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

View file

@ -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);

View file

@ -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

View file

@ -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();

View file

@ -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);
}

View file

@ -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,

View 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 */