Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 20e5cd9d authored by qctecmdr Service's avatar qctecmdr Service Committed by Gerrit - the friendly Code Review server
Browse files

Merge "coresight: ost: Add snapshot of Coresight OST driver"

parents ea43b83e 969c0120
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -94,6 +94,7 @@ config CORESIGHT_STM
	depends on (ARM && !(CPU_32v3 || CPU_32v4 || CPU_32v4T)) || ARM64
	select CORESIGHT_LINKS_AND_SINKS
	select STM
	select CORESIGHT_OST
	help
	  This driver provides support for hardware assisted software
	  instrumentation based tracing. This is primarily used for
@@ -121,4 +122,14 @@ config CORESIGHT_CTI
	  used to input or output i.e. pass cross trigger events from one
	  hardware component to another. It can also be used to pass
	  software generated events.

config CORESIGHT_OST
	bool "CoreSight OST framework"
	depends on CORESIGHT_STM
	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
+1 −0
Original line number Diff line number Diff line
@@ -20,3 +20,4 @@ obj-$(CONFIG_CORESIGHT_STM) += coresight-stm.o
obj-$(CONFIG_CORESIGHT_CPU_DEBUG) += coresight-cpu-debug.o
obj-$(CONFIG_CORESIGHT_CATU) += coresight-catu.o
obj-$(CONFIG_CORESIGHT_CTI) += coresight-cti.o
obj-$(CONFIG_CORESIGHT_OST) += coresight-ost.o
+288 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
 */

#include <linux/device.h>
#include <linux/bitmap.h>
#include <linux/io.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->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 stm_drvdata *drvdata, size_t bitmap_size)
{
	drvdata->chs.bitmap = devm_kzalloc(drvdata->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 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * 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>

#if 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 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
+66 −73
Original line number Diff line number Diff line
// 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
 *
@@ -15,9 +15,7 @@
 * generic STM API by Chunyan Zhang
 * (C) 2015-2016 Chunyan Zhang <zhang.chunyan@linaro.org>
 */
#include <asm/local.h>
#include <linux/amba/bus.h>
#include <linux/bitmap.h>
#include <linux/clk.h>
#include <linux/coresight.h>
#include <linux/coresight-stm.h>
@@ -29,6 +27,7 @@
#include <linux/pm_runtime.h>
#include <linux/stm.h>

#include "coresight-ost.h"
#include "coresight-priv.h"

#define STMDMASTARTR			0xc04
@@ -66,8 +65,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 */
@@ -75,16 +72,6 @@
/* 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)

static int boot_nr_channel;

/*
@@ -95,56 +82,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;
};

/**
 * 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.
 * @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 device		*dev;
	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);
@@ -209,6 +146,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_info(drvdata->dev, "STM tracing enabled\n");
@@ -300,7 +238,7 @@ static inline bool stm_addr_unaligned(const void *addr, u8 write_bytes)
	return ((unsigned long)addr & (write_bytes - 1));
}

static void stm_send(void __iomem *addr, const void *data,
void stm_send(void __iomem *addr, const void *data,
		     u32 size, u8 write_bytes)
{
	u8 paload[8];
@@ -330,6 +268,7 @@ static void stm_send(void __iomem *addr, const void *data,
		break;
	}
}
EXPORT_SYMBOL(stm_send);

static int stm_generic_link(struct stm_data *stm_data,
			    unsigned int master,  unsigned int channel)
@@ -349,7 +288,9 @@ static void stm_generic_unlink(struct stm_data *stm_data,
						   struct stm_drvdata, stm);
	if (!drvdata || !drvdata->csdev)
		return;

	/* If any OST entity is enabled do not disable the device */
	if (drvdata->entities == NULL)
		return;
	coresight_disable(drvdata->csdev);
}

@@ -629,6 +570,50 @@ static ssize_t traceid_store(struct device *dev,
}
static DEVICE_ATTR_RW(traceid);

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

#define coresight_stm_reg(name, offset)	\
	coresight_simple_reg32(struct stm_drvdata, name, offset)

@@ -651,6 +636,7 @@ static struct attribute *coresight_stm_attrs[] = {
	&dev_attr_port_enable.attr,
	&dev_attr_port_select.attr,
	&dev_attr_traceid.attr,
	&dev_attr_entities.attr,
	NULL,
};

@@ -737,7 +723,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)
@@ -752,12 +738,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
	 * 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 0x00 and
	 * lowner than 0x10.
	 * 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);
@@ -775,6 +761,8 @@ 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;
	drvdata->stm.ost_configured = stm_ost_configured;
	drvdata->stm.ost_packet = stm_ost_packet;
	drvdata->stm.sw_mmiosz = BYTES_PER_CHANNEL;
	drvdata->stm.packet = stm_generic_packet;
	drvdata->stm.mmio_addr = stm_mmio_addr;
@@ -843,6 +831,11 @@ static int stm_probe(struct amba_device *adev, const struct amba_id *id)
				 BYTES_PER_CHANNEL), resource_size(res));
	}
	bitmap_size = BITS_TO_LONGS(drvdata->numsp) * sizeof(long);
	/* Store the driver data pointer for use in exported functions */
	ret = stm_set_ost_params(drvdata, bitmap_size);
	if (ret)
		return ret;


	guaranteed = devm_kzalloc(dev, bitmap_size, GFP_KERNEL);
	if (!guaranteed)
Loading