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

Commit 2aa23d3a authored by Rama Aparna Mallavarapu's avatar Rama Aparna Mallavarapu Committed by Tingwei Zhang
Browse files

coresight: ost: Add snapshot of Coresight OST driver



This is a snapshot of the coresight-cti driver as of msm-4.14
commit '7d42028b99d32ad6ec82aa429378fba0280a1c4a'.byte-cntr: Read 64bit rwp
TMC RWP has two 32bit registers which combine to one 64bit register.
Read correct RWP register in byte counter driver.
Make necessary change to adopt coresight framework change.

Change-Id: I4a89b9b041c354093b96e01ee0436a7372ff37fd
Signed-off-by: default avatarRama Aparna Mallavarapu <aparnam@codeaurora.org>
Signed-off-by: default avatarMulu He <muluhe@codeaurora.org>
Signed-off-by: default avatarTingwei Zhang <tingwei@codeaurora.org>
parent a3ccff97
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -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
@@ -183,4 +184,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
+1 −0
Original line number Diff line number Diff line
@@ -24,3 +24,4 @@ obj-$(CONFIG_CORESIGHT_HWEVENT) += coresight-hwevent.o
obj-$(CONFIG_CORESIGHT_DUMMY) += coresight-dummy.o
obj-$(CONFIG_CORESIGHT_CSR) += coresight-csr.o
obj-$(CONFIG_CORESIGHT_TGU) += coresight-tgu.o
obj-$(CONFIG_CORESIGHT_OST) += coresight-ost.o
+290 −0
Original line number Diff line number Diff line
// 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 −0
Original line number Diff line number Diff line
/* 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
+76 −69
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
 *
@@ -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
	 * 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);
@@ -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)
Loading