Mathieu Poirier <mathieu.poirier@xxxxxxxxxx> writes: > On 7 March 2015 at 04:35, Alexander Shishkin > <alexander.shishkin@xxxxxxxxxxxxxxx> wrote: >> A System Trace Module (STM) is a device exporting data in System Trace >> Protocol (STP) format as defined by MIPI STP standards. Examples of such >> devices are Intel Trace Hub and Coresight STM. >> >> This abstraction provides a unified interface for software trace sources >> to send their data over an STM device to a debug host. In order to do >> that, such a trace source needs to be assigned a pair of master/channel >> identifiers that all the data from this source will be tagged with. The >> STP decoder on the debug host side will use these master/channel tags to >> distinguish different trace streams from one another inside one STP >> stream. >> >> This abstraction provides a configfs-based policy management mechanism >> for dynamic allocation of these master/channel pairs based on trace >> source-supplied string identifier. It has the flexibility of being >> defined at runtime and at the same time (provided that the policy >> definition is aligned with the decoding end) consistency. >> >> For userspace trace sources, this abstraction provides write()-based and >> mmap()-based (if the underlying stm device allows this) output mechanism. >> >> For kernel-side trace sources, we provide "stm_source" device class that >> can be connected to an stm device at run time. >> >> Cc: linux-api@xxxxxxxxxxxxxxx >> Cc: Pratik Patel <pratikp@xxxxxxxxxxxxxx> >> Cc: Mathieu Poirier <mathieu.poirier@xxxxxxxxxx> >> Signed-off-by: Alexander Shishkin <alexander.shishkin@xxxxxxxxxxxxxxx> >> --- >> Documentation/ABI/testing/configfs-stp-policy | 44 ++ >> Documentation/ABI/testing/sysfs-class-stm | 14 + >> Documentation/ABI/testing/sysfs-class-stm_source | 11 + >> Documentation/trace/stm.txt | 77 +++ >> drivers/Kconfig | 2 + >> drivers/Makefile | 1 + >> drivers/stm/Kconfig | 8 + >> drivers/stm/Makefile | 3 + >> drivers/stm/core.c | 839 +++++++++++++++++++++++ >> drivers/stm/policy.c | 470 +++++++++++++ >> drivers/stm/stm.h | 77 +++ >> include/linux/stm.h | 87 +++ >> include/uapi/linux/stm.h | 47 ++ >> 13 files changed, 1680 insertions(+) >> create mode 100644 Documentation/ABI/testing/configfs-stp-policy >> create mode 100644 Documentation/ABI/testing/sysfs-class-stm >> create mode 100644 Documentation/ABI/testing/sysfs-class-stm_source >> create mode 100644 Documentation/trace/stm.txt >> create mode 100644 drivers/stm/Kconfig >> create mode 100644 drivers/stm/Makefile >> create mode 100644 drivers/stm/core.c >> create mode 100644 drivers/stm/policy.c >> create mode 100644 drivers/stm/stm.h >> create mode 100644 include/linux/stm.h >> create mode 100644 include/uapi/linux/stm.h >> > > [Snip...] > >> + >> +static int stm_output_assign(struct stm_device *stm, unsigned int width, >> + struct stp_policy_node *policy_node, >> + struct stm_output *output) >> +{ >> + unsigned int midx, cidx, mend, cend; >> + int ret = -EBUSY; >> + >> + if (width > stm->data->sw_nchannels) >> + return -EINVAL; >> + >> + if (policy_node) { > > Where does this get set? All I found is code that is switching on it. It comes from stp_policy_node_lookup() in stm_file_assign() or stm_source_link_add(). >> + stp_policy_node_get_ranges(policy_node, >> + &midx, &mend, &cidx, &cend); >> + } else { >> + midx = stm->data->sw_start; >> + cidx = 0; >> + mend = stm->data->sw_end; >> + cend = stm->data->sw_nchannels - 1; >> + } >> + >> + spin_lock(&stm->mc_lock); >> + if (output->nr_chans) >> + goto unlock; >> + >> + ret = stm_find_master_chan(stm, width, &midx, mend, &cidx, cend); >> + if (ret) >> + goto unlock; >> + >> + output->master = midx; >> + output->channel = cidx; >> + output->nr_chans = width; >> + stm_output_claim(stm, output); >> + dev_dbg(stm->dev, "assigned %u:%u (+%u)\n", midx, cidx, width); >> + >> + ret = 0; >> +unlock: >> + spin_unlock(&stm->mc_lock); >> + >> + return ret; >> +} >> + > > [Snip...] > >> + >> +/** >> + * stm_source_register_device() - register an stm_source device >> + * @parent: parent device >> + * @data: device description structure >> + * >> + * This will create a device of stm_source class that can write >> + * data to an stm device once linked. >> + * >> + * Return: 0 on success, -errno otherwise. >> + */ >> +int stm_source_register_device(struct device *parent, >> + struct stm_source_data *data) >> +{ >> + struct stm_source_device *src; >> + struct device *dev; >> + >> + if (!stm_core_up) >> + return -EPROBE_DEFER; >> + >> + src = kzalloc(sizeof(*src), GFP_KERNEL); >> + if (!src) >> + return -ENOMEM; >> + >> + dev = device_create(&stm_source_class, parent, MKDEV(0, 0), NULL, "%s", >> + data->name); >> + if (IS_ERR(dev)) { >> + kfree(src); >> + return PTR_ERR(dev); >> + } >> + >> + spin_lock_init(&src->link_lock); >> + INIT_LIST_HEAD(&src->link_entry); >> + src->dev = dev; >> + src->data = data; >> + data->src = src; >> + dev_set_drvdata(dev, src); >> + >> + return 0; >> +} >> +EXPORT_SYMBOL_GPL(stm_source_register_device); >> + > > [Snip...] > > It's really not clear (at least to me) how stm_source_device works. > They make a bridge between the kernel and the STM devices but the > "link" between them is not obvious. More documentation perhaps? Sure, I need to elaborate on this a bit. The idea the stm_source device gets "linked" to an stm device by way of writing that stm device name to its stm_source_link attribute and if everything's fine, stm_sounrce's .link callback is called, after which it can start sending data out with stm_sounce_write(). >> +/** >> + * struct stm_data - STM device description and callbacks >> + * @name: device name >> + * @stm: internal structure, only used by stm class code >> + * @sw_start: first STP master >> + * @sw_end: last STP master >> + * @sw_nchannels: number of STP channels per master >> + * @sw_mmiosz: size of one channel's IO space, for mmap, optional >> + * @write: write callback >> + * @mmio_addr: mmap callback, optional >> + * >> + * Fill out this structure before calling stm_register_device() to create >> + * an STM device and stm_unregister_device() to destroy it. It will also be >> + * passed back to write() and mmio_addr() callbacks. >> + */ >> +struct stm_data { >> + const char *name; >> + struct stm_device *stm; >> + unsigned int sw_start; >> + unsigned int sw_end; > > The above kernel doc is the only place where "sw_start" and "sw_end" > are described as first and last STP masters. Other than that it takes > a really long time to figure out what they really are. I think a > better naming convention can be chosen here. The idea is that only a certain subset of masters is available for software (others being statically assigned to different hw blocks or otherwise unavailable to software). These two mark start and end of this subset. > >> + unsigned int sw_nchannels; >> + unsigned int sw_mmiosz; >> + ssize_t (*write)(struct stm_data *, unsigned int, >> + unsigned int, const char *, size_t); >> + phys_addr_t (*mmio_addr)(struct stm_data *, unsigned int, >> + unsigned int, unsigned int); >> + void (*link)(struct stm_data *, unsigned int, >> + unsigned int); >> + void (*unlink)(struct stm_data *, unsigned int, >> + unsigned int); > > It is really not clear to me what the "link" and "unlink" functions do > - documenting what they're for and explain when to use them and (not > use them) would be appreciated. Will do. > I think we should also add two things to this structure: 1) a private > field and 2) a (*stm_drv_ioctl) stub. > The private field would be filled by the registrant and left alone by > the generic-stm core. When parsing the commands in > "stm_char_ioctl()", data->stm_drv_ioctl(private, cmd, arg) could be > called to let architecture specific drivers deal with it. That way > applications can deal with a single configuration file descriptor. Indeed, good idea. > >> +}; >> + >> +int stm_register_device(struct device *parent, struct stm_data *stm_data, >> + struct module *owner); >> +void stm_unregister_device(struct stm_data *stm_data); >> + >> +struct stm_source_device; >> + >> +/** >> + * struct stm_source_data - STM source device description and callbacks >> + * @name: device name, will be used for policy lookup >> + * @src: internal structure, only used by stm class code >> + * @nr_chans: number of channels to allocate >> + * @link: called when STM device gets linked to this source >> + * @unlink: called when STH device is about to be unlinked >> + * >> + * Fill in this structure before calling stm_source_register_device() to >> + * register a source device. Also pass it to unregister and write calls. >> + */ >> +struct stm_source_data { >> + const char *name; >> + struct stm_source_device *src; >> + unsigned int percpu; >> + unsigned int nr_chans; >> + int (*link)(struct stm_source_data *data); >> + void (*unlink)(struct stm_source_data *data); >> +}; >> + > > I didn't get the linking/unlinking process - it is also not clear as > to why we need struct stm_data and struct stm_source_data. More > explanation on this would be good. My idea is that connecting stm to stm_source device is done via sysfs attribute write like so: $ echo dummy_stm > /sys/class/stm_source/stm_console/stm_source_link This will result in stm_source's .link getting called, at which point stm_console, for example, will do a register_console(). stm_data is there for stm devices to pass their parameters and callbacks to stm_register_device(); stm_source data is that for stm_source devices. I'll try to be more elaborate about these in my followup. >> +int stm_source_register_device(struct device *parent, >> + struct stm_source_data *data); >> +void stm_source_unregister_device(struct stm_source_data *data); >> + >> +int stm_source_write(struct stm_source_data *data, unsigned int chan, >> + const char *buf, size_t count); >> + >> +#endif /* _STM_H_ */ >> diff --git a/include/uapi/linux/stm.h b/include/uapi/linux/stm.h >> new file mode 100644 >> index 0000000000..042b58b53b >> --- /dev/null >> +++ b/include/uapi/linux/stm.h >> @@ -0,0 +1,47 @@ >> +/* >> + * System Trace Module (STM) userspace interfaces >> + * Copyright (c) 2014, Intel Corporation. >> + * >> + * This program is free software; you can redistribute it and/or modify it >> + * under the terms and conditions of the GNU General Public License, >> + * version 2, as published by the Free Software Foundation. >> + * >> + * This program is distributed in the hope it will be useful, but WITHOUT >> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or >> + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for >> + * more details. >> + * >> + * STM class implements generic infrastructure for System Trace Module devices >> + * as defined in MIPI STPv2 specification. >> + */ >> + >> +#ifndef _UAPI_LINUX_STM_H >> +#define _UAPI_LINUX_STM_H >> + >> +/** >> + * struct stp_policy_id - identification for the STP policy >> + * @size: size of the structure including real id[] length >> + * @master: assigned master >> + * @channel: first assigned channel >> + * @width: number of requested channels >> + * @id: identification string >> + * >> + * User must calculate the total size of the structure and put it into >> + * @size field, fill out the @id and desired @width. In return, kernel >> + * fills out @master, @channel and @width. >> + */ >> +struct stp_policy_id { >> + __u32 size; >> + __u16 master; >> + __u16 channel; >> + __u16 width; >> + /* padding */ >> + __u16 __reserved_0; >> + __u32 __reserved_1; >> + char id[0]; >> +}; >> + >> +#define STP_POLICY_ID_SET _IOWR('%', 0, struct stp_policy_id) >> +#define STP_POLICY_ID_GET _IOR('%', 1, struct stp_policy_id) >> + >> +#endif /* _UAPI_LINUX_STM_H */ >> -- >> 2.1.4 >> > > Aside from the above points I think this is all very good work. The > patchset should likely be broken up in two sets, one for the generic > STM architecture wrapper and another for the Intel TH part. That way > things can be worked on independently. The Intel TH part is very much dependent on the STM part; I could split out the stm-dependant patch from Intel TH, but that just seems to make it more complex for me and reviewers. I'd prefer to keep them together unless there are strong objections. > On my side I will get a prototype going that folds the current > coresight-stm driver in this new mindset - I'll let you know how > things go. Thanks a lot! Regards, -- Alex -- To unsubscribe from this list: send the line "unsubscribe linux-api" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html