diff options
Diffstat (limited to 'drivers/hwtracing/stm')
| -rw-r--r-- | drivers/hwtracing/stm/Kconfig | 3 | ||||
| -rw-r--r-- | drivers/hwtracing/stm/console.c | 1 | ||||
| -rw-r--r-- | drivers/hwtracing/stm/core.c | 22 | ||||
| -rw-r--r-- | drivers/hwtracing/stm/ftrace.c | 8 | ||||
| -rw-r--r-- | drivers/hwtracing/stm/heartbeat.c | 13 | ||||
| -rw-r--r-- | drivers/hwtracing/stm/p_basic.c | 3 | ||||
| -rw-r--r-- | drivers/hwtracing/stm/p_sys-t.c | 99 | ||||
| -rw-r--r-- | drivers/hwtracing/stm/policy.c | 7 | ||||
| -rw-r--r-- | drivers/hwtracing/stm/stm.h | 6 |
9 files changed, 122 insertions, 40 deletions
diff --git a/drivers/hwtracing/stm/Kconfig b/drivers/hwtracing/stm/Kconfig index d0e92a8a045c..eda6b11d40a1 100644 --- a/drivers/hwtracing/stm/Kconfig +++ b/drivers/hwtracing/stm/Kconfig @@ -2,7 +2,6 @@ config STM tristate "System Trace Module devices" select CONFIGFS_FS - select SRCU help A System Trace Module (STM) is a device exporting data in System Trace Protocol (STP) format as defined by MIPI STP standards. @@ -71,7 +70,7 @@ config STM_SOURCE_HEARTBEAT config STM_SOURCE_FTRACE tristate "Copy the output from kernel Ftrace to STM engine" - depends on FUNCTION_TRACER + depends on TRACING help This option can be used to copy the output from kernel Ftrace to STM engine. Enabling this option will introduce a slight diff --git a/drivers/hwtracing/stm/console.c b/drivers/hwtracing/stm/console.c index a00f65e21747..097a00ac43a7 100644 --- a/drivers/hwtracing/stm/console.c +++ b/drivers/hwtracing/stm/console.c @@ -22,6 +22,7 @@ static struct stm_console { .data = { .name = "console", .nr_chans = 1, + .type = STM_USER, .link = stm_console_link, .unlink = stm_console_unlink, }, diff --git a/drivers/hwtracing/stm/core.c b/drivers/hwtracing/stm/core.c index 2712e699ba08..cdba4e875b28 100644 --- a/drivers/hwtracing/stm/core.c +++ b/drivers/hwtracing/stm/core.c @@ -600,7 +600,7 @@ EXPORT_SYMBOL_GPL(stm_data_write); static ssize_t notrace stm_write(struct stm_device *stm, struct stm_output *output, - unsigned int chan, const char *buf, size_t count) + unsigned int chan, const char *buf, size_t count, struct stm_source_data *source) { int err; @@ -608,7 +608,7 @@ stm_write(struct stm_device *stm, struct stm_output *output, if (!stm->pdrv) return -ENODEV; - err = stm->pdrv->write(stm->data, output, chan, buf, count); + err = stm->pdrv->write(stm->data, output, chan, buf, count, source); if (err < 0) return err; @@ -657,7 +657,7 @@ static ssize_t stm_char_write(struct file *file, const char __user *buf, pm_runtime_get_sync(&stm->dev); - count = stm_write(stm, &stmf->output, 0, kbuf, count); + count = stm_write(stm, &stmf->output, 0, kbuf, count, NULL); pm_runtime_mark_last_busy(&stm->dev); pm_runtime_put_autosuspend(&stm->dev); @@ -715,7 +715,7 @@ static int stm_char_mmap(struct file *file, struct vm_area_struct *vma) pm_runtime_get_sync(&stm->dev); vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); - vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP; + vm_flags_set(vma, VM_IO | VM_DONTEXPAND | VM_DONTDUMP); vma->vm_ops = &stm_mmap_vmops; vm_iomap_memory(vma, phys, size); @@ -839,7 +839,6 @@ static const struct file_operations stm_fops = { .mmap = stm_char_mmap, .unlocked_ioctl = stm_char_ioctl, .compat_ioctl = compat_ptr_ioctl, - .llseek = no_llseek, }; static void stm_device_release(struct device *dev) @@ -868,8 +867,11 @@ int stm_register_device(struct device *parent, struct stm_data *stm_data, return -ENOMEM; stm->major = register_chrdev(0, stm_data->name, &stm_fops); - if (stm->major < 0) - goto err_free; + if (stm->major < 0) { + err = stm->major; + vfree(stm); + return err; + } device_initialize(&stm->dev); stm->dev.devt = MKDEV(stm->major, 0); @@ -913,10 +915,8 @@ int stm_register_device(struct device *parent, struct stm_data *stm_data, err_device: unregister_chrdev(stm->major, stm_data->name); - /* matches device_initialize() above */ + /* calls stm_device_release() */ put_device(&stm->dev); -err_free: - vfree(stm); return err; } @@ -1298,7 +1298,7 @@ int notrace stm_source_write(struct stm_source_data *data, stm = srcu_dereference(src->link, &stm_source_srcu); if (stm) - count = stm_write(stm, &src->output, chan, buf, count); + count = stm_write(stm, &src->output, chan, buf, count, data); else count = -ENODEV; diff --git a/drivers/hwtracing/stm/ftrace.c b/drivers/hwtracing/stm/ftrace.c index ce868e095410..a7cea7ea0163 100644 --- a/drivers/hwtracing/stm/ftrace.c +++ b/drivers/hwtracing/stm/ftrace.c @@ -23,6 +23,7 @@ static struct stm_ftrace { .data = { .name = "ftrace", .nr_chans = STM_FTRACE_NR_CHANNELS, + .type = STM_FTRACE, .link = stm_ftrace_link, .unlink = stm_ftrace_unlink, }, @@ -37,8 +38,10 @@ static void notrace stm_ftrace_write(struct trace_export *export, const void *buf, unsigned int len) { struct stm_ftrace *stm = container_of(export, struct stm_ftrace, ftrace); + /* This is called from trace system with preemption disabled */ + unsigned int cpu = smp_processor_id(); - stm_source_write(&stm->data, STM_FTRACE_CHAN, buf, len); + stm_source_write(&stm->data, STM_FTRACE_CHAN + cpu, buf, len); } static int stm_ftrace_link(struct stm_source_data *data) @@ -46,6 +49,8 @@ static int stm_ftrace_link(struct stm_source_data *data) struct stm_ftrace *sf = container_of(data, struct stm_ftrace, data); sf->ftrace.write = stm_ftrace_write; + sf->ftrace.flags = TRACE_EXPORT_FUNCTION | TRACE_EXPORT_EVENT + | TRACE_EXPORT_MARKER; return register_ftrace_export(&sf->ftrace); } @@ -61,6 +66,7 @@ static int __init stm_ftrace_init(void) { int ret; + stm_ftrace.data.nr_chans = roundup_pow_of_two(num_possible_cpus()); ret = stm_source_register_device(NULL, &stm_ftrace.data); if (ret) pr_err("Failed to register stm_source - ftrace.\n"); diff --git a/drivers/hwtracing/stm/heartbeat.c b/drivers/hwtracing/stm/heartbeat.c index 3e7df1c0477f..495eb1dc8ac5 100644 --- a/drivers/hwtracing/stm/heartbeat.c +++ b/drivers/hwtracing/stm/heartbeat.c @@ -64,7 +64,7 @@ static void stm_heartbeat_unlink(struct stm_source_data *data) static int stm_heartbeat_init(void) { - int i, ret = -ENOMEM; + int i, ret; if (nr_devs < 0 || nr_devs > STM_HEARTBEAT_MAX) return -EINVAL; @@ -72,16 +72,17 @@ static int stm_heartbeat_init(void) for (i = 0; i < nr_devs; i++) { stm_heartbeat[i].data.name = kasprintf(GFP_KERNEL, "heartbeat.%d", i); - if (!stm_heartbeat[i].data.name) + if (!stm_heartbeat[i].data.name) { + ret = -ENOMEM; goto fail_unregister; + } stm_heartbeat[i].data.nr_chans = 1; + stm_heartbeat[i].data.type = STM_USER; stm_heartbeat[i].data.link = stm_heartbeat_link; stm_heartbeat[i].data.unlink = stm_heartbeat_unlink; - hrtimer_init(&stm_heartbeat[i].hrtimer, CLOCK_MONOTONIC, - HRTIMER_MODE_ABS); - stm_heartbeat[i].hrtimer.function = - stm_heartbeat_hrtimer_handler; + hrtimer_setup(&stm_heartbeat[i].hrtimer, stm_heartbeat_hrtimer_handler, + CLOCK_MONOTONIC, HRTIMER_MODE_ABS); ret = stm_source_register_device(NULL, &stm_heartbeat[i].data); if (ret) diff --git a/drivers/hwtracing/stm/p_basic.c b/drivers/hwtracing/stm/p_basic.c index 8980a6a5fd6c..5525c975cc6f 100644 --- a/drivers/hwtracing/stm/p_basic.c +++ b/drivers/hwtracing/stm/p_basic.c @@ -10,7 +10,8 @@ #include "stm.h" static ssize_t basic_write(struct stm_data *data, struct stm_output *output, - unsigned int chan, const char *buf, size_t count) + unsigned int chan, const char *buf, size_t count, + struct stm_source_data *source) { unsigned int c = output->channel + chan; unsigned int m = output->master; diff --git a/drivers/hwtracing/stm/p_sys-t.c b/drivers/hwtracing/stm/p_sys-t.c index 360b5c03df95..1e75aa0025a3 100644 --- a/drivers/hwtracing/stm/p_sys-t.c +++ b/drivers/hwtracing/stm/p_sys-t.c @@ -20,6 +20,7 @@ enum sys_t_message_type { MIPI_SYST_TYPE_RAW = 6, MIPI_SYST_TYPE_SHORT64, MIPI_SYST_TYPE_CLOCK, + MIPI_SYST_TYPE_SBD, }; enum sys_t_message_severity { @@ -53,6 +54,19 @@ enum sys_t_message_string_subtype { MIPI_SYST_STRING_PRINTF_64 = 12, }; +/** + * enum sys_t_message_sbd_subtype - SyS-T SBD message subtypes + * @MIPI_SYST_SBD_ID32: SBD message with 32-bit message ID + * @MIPI_SYST_SBD_ID64: SBD message with 64-bit message ID + * + * Structured Binary Data messages can send information of arbitrary length, + * together with ID's that describe BLOB's content and layout. + */ +enum sys_t_message_sbd_subtype { + MIPI_SYST_SBD_ID32 = 0, + MIPI_SYST_SBD_ID64 = 1, +}; + #define MIPI_SYST_TYPE(t) ((u32)(MIPI_SYST_TYPE_ ## t)) #define MIPI_SYST_SEVERITY(s) ((u32)(MIPI_SYST_SEVERITY_ ## s) << 4) #define MIPI_SYST_OPT_LOC BIT(8) @@ -75,6 +89,20 @@ enum sys_t_message_string_subtype { #define CLOCK_SYNC_HEADER (MIPI_SYST_TYPES(CLOCK, TRANSPORT_SYNC) | \ MIPI_SYST_SEVERITY(MAX)) +/* + * SyS-T and ftrace headers are compatible to an extent that ftrace event ID + * and args can be treated as SyS-T SBD message with 64-bit ID and arguments + * BLOB right behind the header without modification. Bits [16:63] coming + * together with message ID from ftrace aren't used by SBD and must be zeroed. + * + * 0 15 16 23 24 31 32 39 40 63 + * ftrace: <event_id> <flags> <preempt> <-pid-> <----> <args> + * SBD: <------- msg_id ------------------------------> <BLOB> + */ +#define SBD_HEADER (MIPI_SYST_TYPES(SBD, ID64) | \ + MIPI_SYST_SEVERITY(INFO) | \ + MIPI_SYST_OPT_GUID) + struct sys_t_policy_node { uuid_t uuid; bool do_len; @@ -92,7 +120,7 @@ static void sys_t_policy_node_init(void *priv) { struct sys_t_policy_node *pn = priv; - generate_random_uuid(pn->uuid.b); + uuid_gen(&pn->uuid); } static int sys_t_output_open(void *priv, struct stm_output *output) @@ -284,14 +312,68 @@ sys_t_clock_sync(struct stm_data *data, unsigned int m, unsigned int c) return sizeof(header) + sizeof(payload); } +static inline u32 sys_t_header(struct stm_source_data *source) +{ + if (source && source->type == STM_FTRACE) + return SBD_HEADER; + return DATA_HEADER; +} + +static ssize_t sys_t_write_data(struct stm_data *data, + struct stm_source_data *source, + unsigned int master, unsigned int channel, + bool ts_first, const void *buf, size_t count) +{ + ssize_t sz; + const unsigned char nil = 0; + + /* + * Ftrace is zero-copy compatible with SyS-T SBD, but requires + * special handling of first 64 bits. Trim and send them separately + * to avoid damage on original ftrace buffer. + */ + if (source && source->type == STM_FTRACE) { + u64 compat_ftrace_header; + ssize_t header_sz; + ssize_t buf_sz; + + if (count < sizeof(compat_ftrace_header)) + return -EINVAL; + + /* SBD only makes use of low 16 bits (event ID) from ftrace event */ + compat_ftrace_header = *(u64 *)buf & 0xffff; + header_sz = stm_data_write(data, master, channel, false, + &compat_ftrace_header, + sizeof(compat_ftrace_header)); + if (header_sz != sizeof(compat_ftrace_header)) + return header_sz; + + buf_sz = stm_data_write(data, master, channel, false, + buf + header_sz, count - header_sz); + if (buf_sz != count - header_sz) + return buf_sz; + sz = header_sz + buf_sz; + } else { + sz = stm_data_write(data, master, channel, false, buf, count); + } + + if (sz <= 0) + return sz; + + data->packet(data, master, channel, STP_PACKET_FLAG, 0, 0, &nil); + + return sz; +} + static ssize_t sys_t_write(struct stm_data *data, struct stm_output *output, - unsigned int chan, const char *buf, size_t count) + unsigned int chan, const char *buf, size_t count, + struct stm_source_data *source) { struct sys_t_output *op = output->pdrv_private; unsigned int c = output->channel + chan; unsigned int m = output->master; - const unsigned char nil = 0; - u32 header = DATA_HEADER; + u32 header = sys_t_header(source); + u8 uuid[UUID_SIZE]; ssize_t sz; /* We require an existing policy node to proceed */ @@ -322,7 +404,8 @@ static ssize_t sys_t_write(struct stm_data *data, struct stm_output *output, return sz; /* GUID */ - sz = stm_data_write(data, m, c, false, op->node.uuid.b, UUID_SIZE); + export_uuid(uuid, &op->node.uuid); + sz = stm_data_write(data, m, c, false, uuid, sizeof(op->node.uuid)); if (sz <= 0) return sz; @@ -346,11 +429,7 @@ static ssize_t sys_t_write(struct stm_data *data, struct stm_output *output, } /* DATA */ - sz = stm_data_write(data, m, c, false, buf, count); - if (sz > 0) - data->packet(data, m, c, STP_PACKET_FLAG, 0, 0, &nil); - - return sz; + return sys_t_write_data(data, source, m, c, false, buf, count); } static const struct stm_protocol_driver sys_t_pdrv = { diff --git a/drivers/hwtracing/stm/policy.c b/drivers/hwtracing/stm/policy.c index 4f932a419752..42103c3a177f 100644 --- a/drivers/hwtracing/stm/policy.c +++ b/drivers/hwtracing/stm/policy.c @@ -34,7 +34,7 @@ struct stp_policy_node { unsigned int first_channel; unsigned int last_channel; /* this is the one that's exposed to the attributes */ - unsigned char priv[0]; + unsigned char priv[]; }; void *stp_policy_node_priv(struct stp_policy_node *pn) @@ -57,11 +57,6 @@ void stp_policy_node_get_ranges(struct stp_policy_node *policy_node, *cend = policy_node->last_channel; } -static inline char *stp_policy_node_name(struct stp_policy_node *policy_node) -{ - return policy_node->group.cg_item.ci_name ? : "<none>"; -} - static inline struct stp_policy *to_stp_policy(struct config_item *item) { return item ? diff --git a/drivers/hwtracing/stm/stm.h b/drivers/hwtracing/stm/stm.h index 3569439d53bb..85dda6e0d10c 100644 --- a/drivers/hwtracing/stm/stm.h +++ b/drivers/hwtracing/stm/stm.h @@ -23,7 +23,7 @@ void *stp_policy_node_priv(struct stp_policy_node *pn); struct stp_master { unsigned int nr_free; - unsigned long chan_map[0]; + unsigned long chan_map[]; }; struct stm_device { @@ -42,7 +42,7 @@ struct stm_device { const struct config_item_type *pdrv_node_type; /* master allocation */ spinlock_t mc_lock; - struct stp_master *masters[0]; + struct stp_master *masters[]; }; #define to_stm_device(_d) \ @@ -96,7 +96,7 @@ struct stm_protocol_driver { const char *name; ssize_t (*write)(struct stm_data *data, struct stm_output *output, unsigned int chan, - const char *buf, size_t count); + const char *buf, size_t count, struct stm_source_data *source); void (*policy_node_init)(void *arg); int (*output_open)(void *priv, struct stm_output *output); void (*output_close)(struct stm_output *output); |
