On 17 March 2015 at 04:37, Alexander Shishkin <alexander.shishkin@xxxxxxxxxxxxxxx> wrote: > 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, I forgot to mention in my previous email... I think the hierarchy of our respective tracing module along with the generic-stm probably needs a review. Currently we have drivers/coresight, drivers/intel_th and drivers/stm. To me it doesn't scale - what happens when other architectures come out with their own hw tracing technologies? I suggest we move everything under drivers/hwtracing and as such have: drivers/hwtracing drivers/hwtracing/intel_ht drivers/hwtracing/coresight drivers/hwtracing/stm That way other architectures can add drivers for their own hw tracing technology without further polluting the drivers/ directory and concentrating everything in the same area. What's your view on that? > -- > 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