Loading drivers/hwtracing/coresight/Kconfig +11 −0 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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 drivers/hwtracing/coresight/Makefile +1 −0 Original line number Diff line number Diff line Loading @@ -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 drivers/hwtracing/coresight/coresight-ost.c 0 → 100644 +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); drivers/hwtracing/coresight/coresight-ost.h 0 → 100644 +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 drivers/hwtracing/coresight/coresight-stm.c +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 * Loading @@ -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> Loading @@ -29,6 +27,7 @@ #include <linux/pm_runtime.h> #include <linux/stm.h> #include "coresight-ost.h" #include "coresight-priv.h" #define STMDMASTARTR 0xc04 Loading Loading @@ -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 */ Loading @@ -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; /* Loading @@ -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); Loading Loading @@ -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"); Loading Loading @@ -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]; Loading Loading @@ -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) Loading @@ -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); } Loading Loading @@ -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) Loading @@ -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, }; Loading Loading @@ -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) Loading @@ -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); Loading @@ -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; Loading Loading @@ -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 Loading
drivers/hwtracing/coresight/Kconfig +11 −0 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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
drivers/hwtracing/coresight/Makefile +1 −0 Original line number Diff line number Diff line Loading @@ -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
drivers/hwtracing/coresight/coresight-ost.c 0 → 100644 +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);
drivers/hwtracing/coresight/coresight-ost.h 0 → 100644 +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
drivers/hwtracing/coresight/coresight-stm.c +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 * Loading @@ -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> Loading @@ -29,6 +27,7 @@ #include <linux/pm_runtime.h> #include <linux/stm.h> #include "coresight-ost.h" #include "coresight-priv.h" #define STMDMASTARTR 0xc04 Loading Loading @@ -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 */ Loading @@ -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; /* Loading @@ -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); Loading Loading @@ -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"); Loading Loading @@ -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]; Loading Loading @@ -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) Loading @@ -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); } Loading Loading @@ -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) Loading @@ -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, }; Loading Loading @@ -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) Loading @@ -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); Loading @@ -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; Loading Loading @@ -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