History

stm class: Introduce an abstraction for System Trace Module devices

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(R) 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.

Alexander Shishkin committed 11 years ago

Commit 7bd1d401 parent 9b7696814 files · +1991 −0Browse files

Unified · Split

14 files
  1. Documentation/ABI/testing/configfs-stp-policy +48 −0
  2. Documentation/ABI/testing/sysfs-class-stm +14 −0
  3. Documentation/ABI/testing/sysfs-class-stm_source +11 −0
  4. Documentation/ioctl/ioctl-number.txt +3 −0
  5. Documentation/trace/stm.txt +80 −0
  6. drivers/Kconfig +2 −0
  7. drivers/Makefile +1 −0
  8. drivers/hwtracing/stm/Kconfig +8 −0
  9. drivers/hwtracing/stm/Makefile +3 −0
  10. drivers/hwtracing/stm/core.c +1029 −0
  11. drivers/hwtracing/stm/policy.c +529 −0
  12. drivers/hwtracing/stm/stm.h +87 −0
  13. include/linux/stm.h +126 −0
  14. include/uapi/linux/stm.h +50 −0
Documentation/ABI/testing/configfs-stp-policy+48−0
@@ -0,0 +1,48 @@
1What: /config/stp-policy
2Date: June 2015
3KernelVersion: 4.3
4Description:
5 This group contains policies mandating Master/Channel allocation
6 for software sources wishing to send trace data over an STM
7 device.
8
9What: /config/stp-policy/<device>.<policy>
10Date: June 2015
11KernelVersion: 4.3
12Description:
13 This group is the root of a policy; its name is a concatenation
14 of an stm device name to which this policy applies and an
15 arbitrary string. If <device> part doesn't match an existing
16 stm device, mkdir will fail with ENODEV; if that device already
17 has a policy assigned to it, mkdir will fail with EBUSY.
18
19What: /config/stp-policy/<device>.<policy>/device
20Date: June 2015
21KernelVersion: 4.3
22Description:
23 STM device to which this policy applies, read only. Same as the
24 <device> component of its parent directory.
25
26What: /config/stp-policy/<device>.<policy>/<node>
27Date: June 2015
28KernelVersion: 4.3
29Description:
30 Policy node is a string identifier that software clients will
31 use to request a master/channel to be allocated and assigned to
32 them.
33
34What: /config/stp-policy/<device>.<policy>/<node>/masters
35Date: June 2015
36KernelVersion: 4.3
37Description:
38 Range of masters from which to allocate for users of this node.
39 Write two numbers: the first master and the last master number.
40
41What: /config/stp-policy/<device>.<policy>/<node>/channels
42Date: June 2015
43KernelVersion: 4.3
44Description:
45 Range of channels from which to allocate for users of this node.
46 Write two numbers: the first channel and the last channel
47 number.
48
Documentation/ABI/testing/sysfs-class-stm+14−0
@@ -0,0 +1,14 @@
1What: /sys/class/stm/<stm>/masters
2Date: June 2015
3KernelVersion: 4.3
4Contact: Alexander Shishkin <alexander.shishkin@linux.intel.com>
5Description:
6 Shows first and last available to software master numbers on
7 this STM device.
8
9What: /sys/class/stm/<stm>/channels
10Date: June 2015
11KernelVersion: 4.3
12Contact: Alexander Shishkin <alexander.shishkin@linux.intel.com>
13Description:
14 Shows the number of channels per master on this STM device.
Documentation/ABI/testing/sysfs-class-stm_source+11−0
@@ -0,0 +1,11 @@
1What: /sys/class/stm_source/<stm_source>/stm_source_link
2Date: June 2015
3KernelVersion: 4.3
4Contact: Alexander Shishkin <alexander.shishkin@linux.intel.com>
5Description:
6 stm_source device linkage to stm device, where its tracing data
7 is directed. Reads return an existing connection or "<none>" if
8 this stm_source is not connected to any stm device yet.
9 Write an existing (registered) stm device's name here to
10 connect that device. If a device is already connected to this
11 stm_source, it will first be disconnected.
Documentation/ioctl/ioctl-number.txt+3−0
@@ -81,6 +81,9 @@ Code Seq#(hex) Include File Comments · 80 unmodified lines
810x22 all scsi/sg.h810x22 all scsi/sg.h
82'#' 00-3F IEEE 1394 Subsystem Block for the entire subsystem82'#' 00-3F IEEE 1394 Subsystem Block for the entire subsystem
83'$' 00-0F linux/perf_counter.h, linux/perf_event.h83'$' 00-0F linux/perf_counter.h, linux/perf_event.h
84'%' 00-0F include/uapi/linux/stm.h
85 System Trace Module subsystem
86 <mailto:alexander.shishkin@linux.intel.com>
84'&' 00-07 drivers/firewire/nosy-user.h87'&' 00-07 drivers/firewire/nosy-user.h
85'1' 00-1F <linux/timepps.h> PPS kit from Ulrich Windl88'1' 00-1F <linux/timepps.h> PPS kit from Ulrich Windl
86 <ftp://ftp.de.kernel.org/pub/linux/daemons/ntp/PPS/>89 <ftp://ftp.de.kernel.org/pub/linux/daemons/ntp/PPS/>
Documentation/trace/stm.txt+80−0
@@ -0,0 +1,80 @@
1System Trace Module
2===================
3
4System Trace Module (STM) is a device described in MIPI STP specs as
5STP trace stream generator. STP (System Trace Protocol) is a trace
6protocol multiplexing data from multiple trace sources, each one of
7which is assigned a unique pair of master and channel. While some of
8these masters and channels are statically allocated to certain
9hardware trace sources, others are available to software. Software
10trace sources are usually free to pick for themselves any
11master/channel combination from this pool.
12
13On the receiving end of this STP stream (the decoder side), trace
14sources can only be identified by master/channel combination, so in
15order for the decoder to be able to make sense of the trace that
16involves multiple trace sources, it needs to be able to map those
17master/channel pairs to the trace sources that it understands.
18
19For instance, it is helpful to know that syslog messages come on
20master 7 channel 15, while arbitrary user applications can use masters
2148 to 63 and channels 0 to 127.
22
23To solve this mapping problem, stm class provides a policy management
24mechanism via configfs, that allows defining rules that map string
25identifiers to ranges of masters and channels. If these rules (policy)
26are consistent with what decoder expects, it will be able to properly
27process the trace data.
28
29This policy is a tree structure containing rules (policy_node) that
30have a name (string identifier) and a range of masters and channels
31associated with it, located in "stp-policy" subsystem directory in
32configfs. The topmost directory's name (the policy) is formatted as
33the STM device name to which this policy applies and and arbitrary
34string identifier separated by a stop. From the examle above, a rule
35may look like this:
36
37$ ls /config/stp-policy/dummy_stm.my-policy/user
38channels masters
39$ cat /config/stp-policy/dummy_stm.my-policy/user/masters
4048 63
41$ cat /config/stp-policy/dummy_stm.my-policy/user/channels
420 127
43
44which means that the master allocation pool for this rule consists of
45masters 48 through 63 and channel allocation pool has channels 0
46through 127 in it. Now, any producer (trace source) identifying itself
47with "user" identification string will be allocated a master and
48channel from within these ranges.
49
50These rules can be nested, for example, one can define a rule "dummy"
51under "user" directory from the example above and this new rule will
52be used for trace sources with the id string of "user/dummy".
53
54Trace sources have to open the stm class device's node and write their
55trace data into its file descriptor. In order to identify themselves
56to the policy, they need to do a STP_POLICY_ID_SET ioctl on this file
57descriptor providing their id string. Otherwise, they will be
58automatically allocated a master/channel pair upon first write to this
59file descriptor according to the "default" rule of the policy, if such
60exists.
61
62Some STM devices may allow direct mapping of the channel mmio regions
63to userspace for zero-copy writing. One mappable page (in terms of
64mmu) will usually contain multiple channels' mmios, so the user will
65need to allocate that many channels to themselves (via the
66aforementioned ioctl() call) to be able to do this. That is, if your
67stm device's channel mmio region is 64 bytes and hardware page size is
684096 bytes, after a successful STP_POLICY_ID_SET ioctl() call with
69width==64, you should be able to mmap() one page on this file
70descriptor and obtain direct access to an mmio region for 64 channels.
71
72For kernel-based trace sources, there is "stm_source" device
73class. Devices of this class can be connected and disconnected to/from
74stm devices at runtime via a sysfs attribute.
75
76Examples of STM devices are Intel(R) Trace Hub [1] and Coresight STM
77[2].
78
79[1] https://software.intel.com/sites/default/files/managed/d3/3c/intel-th-developer-manual.pdf
80[2] http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0444b/index.html
drivers/Kconfig+2−0
@@ -188,4 +188,6 @@ source "drivers/nvdimm/Kconfig" · 187 unmodified lines
188 188
189source "drivers/nvmem/Kconfig"189source "drivers/nvmem/Kconfig"
190 190
191source "drivers/hwtracing/stm/Kconfig"
192
191endmenu193endmenu
drivers/Makefile+1−0
@@ -165,5 +165,6 @@ obj-$(CONFIG_PERF_EVENTS) += perf/ · 164 unmodified lines
165obj-$(CONFIG_RAS) += ras/165obj-$(CONFIG_RAS) += ras/
166obj-$(CONFIG_THUNDERBOLT) += thunderbolt/166obj-$(CONFIG_THUNDERBOLT) += thunderbolt/
167obj-$(CONFIG_CORESIGHT) += hwtracing/coresight/167obj-$(CONFIG_CORESIGHT) += hwtracing/coresight/
168obj-$(CONFIG_STM) += hwtracing/stm/
168obj-$(CONFIG_ANDROID) += android/169obj-$(CONFIG_ANDROID) += android/
169obj-$(CONFIG_NVMEM) += nvmem/170obj-$(CONFIG_NVMEM) += nvmem/
drivers/hwtracing/stm/Kconfig+8−0
@@ -0,0 +1,8 @@
1config STM
2 tristate "System Trace Module devices"
3 help
4 A System Trace Module (STM) is a device exporting data in System
5 Trace Protocol (STP) format as defined by MIPI STP standards.
6 Examples of such devices are Intel(R) Trace Hub and Coresight STM.
7
8 Say Y here to enable System Trace Module device support.
drivers/hwtracing/stm/Makefile+3−0
@@ -0,0 +1,3 @@
1obj-$(CONFIG_STM) += stm_core.o
2
3stm_core-y := core.o policy.o
drivers/hwtracing/stm/core.c+1029−0
@@ -0,0 +1,1029 @@
1/*
2 * System Trace Module (STM) infrastructure
3 * Copyright (c) 2014, Intel Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * STM class implements generic infrastructure for System Trace Module devices
15 * as defined in MIPI STPv2 specification.
16 */
17
18#include <linux/uaccess.h>
19#include <linux/kernel.h>
20#include <linux/module.h>
21#include <linux/device.h>
22#include <linux/compat.h>
23#include <linux/kdev_t.h>
24#include <linux/srcu.h>
25#include <linux/slab.h>
26#include <linux/stm.h>
27#include <linux/fs.h>
28#include <linux/mm.h>
29#include "stm.h"
30
31#include <uapi/linux/stm.h>
32
33static unsigned int stm_core_up;
34
35/*
36 * The SRCU here makes sure that STM device doesn't disappear from under a
37 * stm_source_write() caller, which may want to have as little overhead as
38 * possible.
39 */
40static struct srcu_struct stm_source_srcu;
41
42static ssize_t masters_show(struct device *dev,
43 struct device_attribute *attr,
44 char *buf)
45{
46 struct stm_device *stm = to_stm_device(dev);
47 int ret;
48
49 ret = sprintf(buf, "%u %u\n", stm->data->sw_start, stm->data->sw_end);
50
51 return ret;
52}
53
54static DEVICE_ATTR_RO(masters);
55
56static ssize_t channels_show(struct device *dev,
57 struct device_attribute *attr,
58 char *buf)
59{
60 struct stm_device *stm = to_stm_device(dev);
61 int ret;
62
63 ret = sprintf(buf, "%u\n", stm->data->sw_nchannels);
64
65 return ret;
66}
67
68static DEVICE_ATTR_RO(channels);
69
70static struct attribute *stm_attrs[] = {
71 &dev_attr_masters.attr,
72 &dev_attr_channels.attr,
73 NULL,
74};
75
76ATTRIBUTE_GROUPS(stm);
77
78static struct class stm_class = {
79 .name = "stm",
80 .dev_groups = stm_groups,
81};
82
83static int stm_dev_match(struct device *dev, const void *data)
84{
85 const char *name = data;
86
87 return sysfs_streq(name, dev_name(dev));
88}
89
90/**
91 * stm_find_device() - find stm device by name
92 * @buf: character buffer containing the name
93 *
94 * This is called when either policy gets assigned to an stm device or an
95 * stm_source device gets linked to an stm device.
96 *
97 * This grabs device's reference (get_device()) and module reference, both
98 * of which the calling path needs to make sure to drop with stm_put_device().
99 *
100 * Return: stm device pointer or null if lookup failed.
101 */
102struct stm_device *stm_find_device(const char *buf)
103{
104 struct stm_device *stm;
105 struct device *dev;
106
107 if (!stm_core_up)
108 return NULL;
109
110 dev = class_find_device(&stm_class, NULL, buf, stm_dev_match);
111 if (!dev)
112 return NULL;
113
114 stm = to_stm_device(dev);
115 if (!try_module_get(stm->owner)) {
116 put_device(dev);
117 return NULL;
118 }
119
120 return stm;
121}
122
123/**
124 * stm_put_device() - drop references on the stm device
125 * @stm: stm device, previously acquired by stm_find_device()
126 *
127 * This drops the module reference and device reference taken by
128 * stm_find_device().
129 */
130void stm_put_device(struct stm_device *stm)
131{
132 module_put(stm->owner);
133 put_device(&stm->dev);
134}
135
136/*
137 * Internally we only care about software-writable masters here, that is the
138 * ones in the range [stm_data->sw_start..stm_data..sw_end], however we need
139 * original master numbers to be visible externally, since they are the ones
140 * that will appear in the STP stream. Thus, the internal bookkeeping uses
141 * $master - stm_data->sw_start to reference master descriptors and such.
142 */
143
144#define __stm_master(_s, _m) \
145 ((_s)->masters[(_m) - (_s)->data->sw_start])
146
147static inline struct stp_master *
148stm_master(struct stm_device *stm, unsigned int idx)
149{
150 if (idx < stm->data->sw_start || idx > stm->data->sw_end)
151 return NULL;
152
153 return __stm_master(stm, idx);
154}
155
156static int stp_master_alloc(struct stm_device *stm, unsigned int idx)
157{
158 struct stp_master *master;
159 size_t size;
160
161 size = ALIGN(stm->data->sw_nchannels, 8) / 8;
162 size += sizeof(struct stp_master);
163 master = kzalloc(size, GFP_ATOMIC);
164 if (!master)
165 return -ENOMEM;
166
167 master->nr_free = stm->data->sw_nchannels;
168 __stm_master(stm, idx) = master;
169
170 return 0;
171}
172
173static void stp_master_free(struct stm_device *stm, unsigned int idx)
174{
175 struct stp_master *master = stm_master(stm, idx);
176
177 if (!master)
178 return;
179
180 __stm_master(stm, idx) = NULL;
181 kfree(master);
182}
183
184static void stm_output_claim(struct stm_device *stm, struct stm_output *output)
185{
186 struct stp_master *master = stm_master(stm, output->master);
187
188 if (WARN_ON_ONCE(master->nr_free < output->nr_chans))
189 return;
190
191 bitmap_allocate_region(&master->chan_map[0], output->channel,
192 ilog2(output->nr_chans));
193
194 master->nr_free -= output->nr_chans;
195}
196
197static void
198stm_output_disclaim(struct stm_device *stm, struct stm_output *output)
199{
200 struct stp_master *master = stm_master(stm, output->master);
201
202 bitmap_release_region(&master->chan_map[0], output->channel,
203 ilog2(output->nr_chans));
204
205 output->nr_chans = 0;
206 master->nr_free += output->nr_chans;
207}
208
209/*
210 * This is like bitmap_find_free_region(), except it can ignore @start bits
211 * at the beginning.
212 */
213static int find_free_channels(unsigned long *bitmap, unsigned int start,
214 unsigned int end, unsigned int width)
215{
216 unsigned int pos;
217 int i;
218
219 for (pos = start; pos < end + 1; pos = ALIGN(pos, width)) {
220 pos = find_next_zero_bit(bitmap, end + 1, pos);
221 if (pos + width > end + 1)
222 break;
223
224 if (pos & (width - 1))
225 continue;
226
227 for (i = 1; i < width && !test_bit(pos + i, bitmap); i++)
228 ;
229 if (i == width)
230 return pos;
231 }
232
233 return -1;
234}
235
236static unsigned int
237stm_find_master_chan(struct stm_device *stm, unsigned int width,
238 unsigned int *mstart, unsigned int mend,
239 unsigned int *cstart, unsigned int cend)
240{
241 struct stp_master *master;
242 unsigned int midx;
243 int pos, err;
244
245 for (midx = *mstart; midx <= mend; midx++) {
246 if (!stm_master(stm, midx)) {
247 err = stp_master_alloc(stm, midx);
248 if (err)
249 return err;
250 }
251
252 master = stm_master(stm, midx);
253
254 if (!master->nr_free)
255 continue;
256
257 pos = find_free_channels(master->chan_map, *cstart, cend,
258 width);
259 if (pos < 0)
260 continue;
261
262 *mstart = midx;
263 *cstart = pos;
264 return 0;
265 }
266
267 return -ENOSPC;
268}
269
270static int stm_output_assign(struct stm_device *stm, unsigned int width,
271 struct stp_policy_node *policy_node,
272 struct stm_output *output)
273{
274 unsigned int midx, cidx, mend, cend;
275 int ret = -EINVAL;
276
277 if (width > stm->data->sw_nchannels)
278 return -EINVAL;
279
280 if (policy_node) {
281 stp_policy_node_get_ranges(policy_node,
282 &midx, &mend, &cidx, &cend);
283 } else {
284 midx = stm->data->sw_start;
285 cidx = 0;
286 mend = stm->data->sw_end;
287 cend = stm->data->sw_nchannels - 1;
288 }
289
290 spin_lock(&stm->mc_lock);
291 /* output is already assigned -- shouldn't happen */
292 if (WARN_ON_ONCE(output->nr_chans))
293 goto unlock;
294
295 ret = stm_find_master_chan(stm, width, &midx, mend, &cidx, cend);
296 if (ret)
297 goto unlock;
298
299 output->master = midx;
300 output->channel = cidx;
301 output->nr_chans = width;
302 stm_output_claim(stm, output);
303 dev_dbg(&stm->dev, "assigned %u:%u (+%u)\n", midx, cidx, width);
304
305 ret = 0;
306unlock:
307 spin_unlock(&stm->mc_lock);
308
309 return ret;
310}
311
312static void stm_output_free(struct stm_device *stm, struct stm_output *output)
313{
314 spin_lock(&stm->mc_lock);
315 if (output->nr_chans)
316 stm_output_disclaim(stm, output);
317 spin_unlock(&stm->mc_lock);
318}
319
320static int major_match(struct device *dev, const void *data)
321{
322 unsigned int major = *(unsigned int *)data;
323
324 return MAJOR(dev->devt) == major;
325}
326
327static int stm_char_open(struct inode *inode, struct file *file)
328{
329 struct stm_file *stmf;
330 struct device *dev;
331 unsigned int major = imajor(inode);
332 int err = -ENODEV;
333
334 dev = class_find_device(&stm_class, NULL, &major, major_match);
335 if (!dev)
336 return -ENODEV;
337
338 stmf = kzalloc(sizeof(*stmf), GFP_KERNEL);
339 if (!stmf)
340 return -ENOMEM;
341
342 stmf->stm = to_stm_device(dev);
343
344 if (!try_module_get(stmf->stm->owner))
345 goto err_free;
346
347 file->private_data = stmf;
348
349 return nonseekable_open(inode, file);
350
351err_free:
352 kfree(stmf);
353
354 return err;
355}
356
357static int stm_char_release(struct inode *inode, struct file *file)
358{
359 struct stm_file *stmf = file->private_data;
360
361 stm_output_free(stmf->stm, &stmf->output);
362 stm_put_device(stmf->stm);
363 kfree(stmf);
364
365 return 0;
366}
367
368static int stm_file_assign(struct stm_file *stmf, char *id, unsigned int width)
369{
370 struct stm_device *stm = stmf->stm;
371 int ret;
372
373 stmf->policy_node = stp_policy_node_lookup(stm, id);
374
375 ret = stm_output_assign(stm, width, stmf->policy_node, &stmf->output);
376
377 if (stmf->policy_node)
378 stp_policy_node_put(stmf->policy_node);
379
380 return ret;
381}
382
383static void stm_write(struct stm_data *data, unsigned int master,
384 unsigned int channel, const char *buf, size_t count)
385{
386 unsigned int flags = STP_PACKET_TIMESTAMPED;
387 const unsigned char *p = buf, nil = 0;
388 size_t pos;
389 ssize_t sz;
390
391 for (pos = 0, p = buf; count > pos; pos += sz, p += sz) {
392 sz = min_t(unsigned int, count - pos, 8);
393 sz = data->packet(data, master, channel, STP_PACKET_DATA, flags,
394 sz, p);
395 flags = 0;
396 }
397
398 data->packet(data, master, channel, STP_PACKET_FLAG, 0, 0, &nil);
399}
400
401static ssize_t stm_char_write(struct file *file, const char __user *buf,
402 size_t count, loff_t *ppos)
403{
404 struct stm_file *stmf = file->private_data;
405 struct stm_device *stm = stmf->stm;
406 char *kbuf;
407 int err;
408
409 /*
410 * if no m/c have been assigned to this writer up to this
411 * point, use "default" policy entry
412 */
413 if (!stmf->output.nr_chans) {
414 err = stm_file_assign(stmf, "default", 1);
415 /*
416 * EBUSY means that somebody else just assigned this
417 * output, which is just fine for write()
418 */
419 if (err && err != -EBUSY)
420 return err;
421 }
422
423 kbuf = kmalloc(count + 1, GFP_KERNEL);
424 if (!kbuf)
425 return -ENOMEM;
426
427 err = copy_from_user(kbuf, buf, count);
428 if (err) {
429 kfree(kbuf);
430 return -EFAULT;
431 }
432
433 stm_write(stm->data, stmf->output.master, stmf->output.channel, kbuf,
434 count);
435
436 kfree(kbuf);
437
438 return count;
439}
440
441static int stm_char_mmap(struct file *file, struct vm_area_struct *vma)
442{
443 struct stm_file *stmf = file->private_data;
444 struct stm_device *stm = stmf->stm;
445 unsigned long size, phys;
446
447 if (!stm->data->mmio_addr)
448 return -EOPNOTSUPP;
449
450 if (vma->vm_pgoff)
451 return -EINVAL;
452
453 size = vma->vm_end - vma->vm_start;
454
455 if (stmf->output.nr_chans * stm->data->sw_mmiosz != size)
456 return -EINVAL;
457
458 phys = stm->data->mmio_addr(stm->data, stmf->output.master,
459 stmf->output.channel,
460 stmf->output.nr_chans);
461
462 if (!phys)
463 return -EINVAL;
464
465 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
466 vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP;
467 vm_iomap_memory(vma, phys, size);
468
469 return 0;
470}
471
472static int stm_char_policy_set_ioctl(struct stm_file *stmf, void __user *arg)
473{
474 struct stm_device *stm = stmf->stm;
475 struct stp_policy_id *id;
476 int ret = -EINVAL;
477 u32 size;
478
479 if (stmf->output.nr_chans)
480 return -EBUSY;
481
482 if (copy_from_user(&size, arg, sizeof(size)))
483 return -EFAULT;
484
485 if (size >= PATH_MAX + sizeof(*id))
486 return -EINVAL;
487
488 /*
489 * size + 1 to make sure the .id string at the bottom is terminated,
490 * which is also why memdup_user() is not useful here
491 */
492 id = kzalloc(size + 1, GFP_KERNEL);
493 if (!id)
494 return -ENOMEM;
495
496 if (copy_from_user(id, arg, size)) {
497 ret = -EFAULT;
498 goto err_free;
499 }
500
501 if (id->__reserved_0 || id->__reserved_1)
502 goto err_free;
503
504 if (id->width < 1 ||
505 id->width > PAGE_SIZE / stm->data->sw_mmiosz)
506 goto err_free;
507
508 ret = stm_file_assign(stmf, id->id, id->width);
509 if (ret)
510 goto err_free;
511
512 ret = 0;
513
514 if (stm->data->link)
515 ret = stm->data->link(stm->data, stmf->output.master,
516 stmf->output.channel);
517
518 if (ret) {
519 stm_output_free(stmf->stm, &stmf->output);
520 stm_put_device(stmf->stm);
521 }
522
523err_free:
524 kfree(id);
525
526 return ret;
527}
528
529static int stm_char_policy_get_ioctl(struct stm_file *stmf, void __user *arg)
530{
531 struct stp_policy_id id = {
532 .size = sizeof(id),
533 .master = stmf->output.master,
534 .channel = stmf->output.channel,
535 .width = stmf->output.nr_chans,
536 .__reserved_0 = 0,
537 .__reserved_1 = 0,
538 };
539
540 return copy_to_user(arg, &id, id.size) ? -EFAULT : 0;
541}
542
543static long
544stm_char_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
545{
546 struct stm_file *stmf = file->private_data;
547 struct stm_data *stm_data = stmf->stm->data;
548 int err = -ENOTTY;
549 u64 options;
550
551 switch (cmd) {
552 case STP_POLICY_ID_SET:
553 err = stm_char_policy_set_ioctl(stmf, (void __user *)arg);
554 if (err)
555 return err;
556
557 return stm_char_policy_get_ioctl(stmf, (void __user *)arg);
558
559 case STP_POLICY_ID_GET:
560 return stm_char_policy_get_ioctl(stmf, (void __user *)arg);
561
562 case STP_SET_OPTIONS:
563 if (copy_from_user(&options, (u64 __user *)arg, sizeof(u64)))
564 return -EFAULT;
565
566 if (stm_data->set_options)
567 err = stm_data->set_options(stm_data,
568 stmf->output.master,
569 stmf->output.channel,
570 stmf->output.nr_chans,
571 options);
572
573 break;
574 default:
575 break;
576 }
577
578 return err;
579}
580
581#ifdef CONFIG_COMPAT
582static long
583stm_char_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
584{
585 return stm_char_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
586}
587#else
588#define stm_char_compat_ioctl NULL
589#endif
590
591static const struct file_operations stm_fops = {
592 .open = stm_char_open,
593 .release = stm_char_release,
594 .write = stm_char_write,
595 .mmap = stm_char_mmap,
596 .unlocked_ioctl = stm_char_ioctl,
597 .compat_ioctl = stm_char_compat_ioctl,
598 .llseek = no_llseek,
599};
600
601static void stm_device_release(struct device *dev)
602{
603 struct stm_device *stm = to_stm_device(dev);
604
605 kfree(stm);
606}
607
608int stm_register_device(struct device *parent, struct stm_data *stm_data,
609 struct module *owner)
610{
611 struct stm_device *stm;
612 unsigned int nmasters;
613 int err = -ENOMEM;
614
615 if (!stm_core_up)
616 return -EPROBE_DEFER;
617
618 if (!stm_data->packet || !stm_data->sw_nchannels)
619 return -EINVAL;
620
621 nmasters = stm_data->sw_end - stm_data->sw_start;
622 stm = kzalloc(sizeof(*stm) + nmasters * sizeof(void *), GFP_KERNEL);
623 if (!stm)
624 return -ENOMEM;
625
626 stm->major = register_chrdev(0, stm_data->name, &stm_fops);
627 if (stm->major < 0)
628 goto err_free;
629
630 device_initialize(&stm->dev);
631 stm->dev.devt = MKDEV(stm->major, 0);
632 stm->dev.class = &stm_class;
633 stm->dev.parent = parent;
634 stm->dev.release = stm_device_release;
635
636 err = kobject_set_name(&stm->dev.kobj, "%s", stm_data->name);
637 if (err)
638 goto err_device;
639
640 err = device_add(&stm->dev);
641 if (err)
642 goto err_device;
643
644 spin_lock_init(&stm->link_lock);
645 INIT_LIST_HEAD(&stm->link_list);
646
647 spin_lock_init(&stm->mc_lock);
648 mutex_init(&stm->policy_mutex);
649 stm->sw_nmasters = nmasters;
650 stm->owner = owner;
651 stm->data = stm_data;
652 stm_data->stm = stm;
653
654 return 0;
655
656err_device:
657 put_device(&stm->dev);
658err_free:
659 kfree(stm);
660
661 return err;
662}
663EXPORT_SYMBOL_GPL(stm_register_device);
664
665static void __stm_source_link_drop(struct stm_source_device *src,
666 struct stm_device *stm);
667
668void stm_unregister_device(struct stm_data *stm_data)
669{
670 struct stm_device *stm = stm_data->stm;
671 struct stm_source_device *src, *iter;
672 int i;
673
674 spin_lock(&stm->link_lock);
675 list_for_each_entry_safe(src, iter, &stm->link_list, link_entry) {
676 __stm_source_link_drop(src, stm);
677 }
678 spin_unlock(&stm->link_lock);
679
680 synchronize_srcu(&stm_source_srcu);
681
682 unregister_chrdev(stm->major, stm_data->name);
683
684 mutex_lock(&stm->policy_mutex);
685 if (stm->policy)
686 stp_policy_unbind(stm->policy);
687 mutex_unlock(&stm->policy_mutex);
688
689 for (i = 0; i < stm->sw_nmasters; i++)
690 stp_master_free(stm, i);
691
692 device_unregister(&stm->dev);
693 stm_data->stm = NULL;
694}
695EXPORT_SYMBOL_GPL(stm_unregister_device);
696
697/**
698 * stm_source_link_add() - connect an stm_source device to an stm device
699 * @src: stm_source device
700 * @stm: stm device
701 *
702 * This function establishes a link from stm_source to an stm device so that
703 * the former can send out trace data to the latter.
704 *
705 * Return: 0 on success, -errno otherwise.
706 */
707static int stm_source_link_add(struct stm_source_device *src,
708 struct stm_device *stm)
709{
710 char *id;
711 int err;
712
713 spin_lock(&stm->link_lock);
714 spin_lock(&src->link_lock);
715
716 /* src->link is dereferenced under stm_source_srcu but not the list */
717 rcu_assign_pointer(src->link, stm);
718 list_add_tail(&src->link_entry, &stm->link_list);
719
720 spin_unlock(&src->link_lock);
721 spin_unlock(&stm->link_lock);
722
723 id = kstrdup(src->data->name, GFP_KERNEL);
724 if (id) {
725 src->policy_node =
726 stp_policy_node_lookup(stm, id);
727
728 kfree(id);
729 }
730
731 err = stm_output_assign(stm, src->data->nr_chans,
732 src->policy_node, &src->output);
733
734 if (src->policy_node)
735 stp_policy_node_put(src->policy_node);
736
737 if (err)
738 goto fail_detach;
739
740 /* this is to notify the STM device that a new link has been made */
741 if (stm->data->link)
742 err = stm->data->link(stm->data, src->output.master,
743 src->output.channel);
744
745 if (err)
746 goto fail_free_output;
747
748 /* this is to let the source carry out all necessary preparations */
749 if (src->data->link)
750 src->data->link(src->data);
751
752 return 0;
753
754fail_free_output:
755 stm_output_free(stm, &src->output);
756 stm_put_device(stm);
757
758fail_detach:
759 spin_lock(&stm->link_lock);
760 spin_lock(&src->link_lock);
761
762 rcu_assign_pointer(src->link, NULL);
763 list_del_init(&src->link_entry);
764
765 spin_unlock(&src->link_lock);
766 spin_unlock(&stm->link_lock);
767
768 return err;
769}
770
771/**
772 * __stm_source_link_drop() - detach stm_source from an stm device
773 * @src: stm_source device
774 * @stm: stm device
775 *
776 * If @stm is @src::link, disconnect them from one another and put the
777 * reference on the @stm device.
778 *
779 * Caller must hold stm::link_lock.
780 */
781static void __stm_source_link_drop(struct stm_source_device *src,
782 struct stm_device *stm)
783{
784 spin_lock(&src->link_lock);
785 if (WARN_ON_ONCE(src->link != stm)) {
786 spin_unlock(&src->link_lock);
787 return;
788 }
789
790 stm_output_free(src->link, &src->output);
791 /* caller must hold stm::link_lock */
792 list_del_init(&src->link_entry);
793 /* matches stm_find_device() from stm_source_link_store() */
794 stm_put_device(src->link);
795 rcu_assign_pointer(src->link, NULL);
796
797 spin_unlock(&src->link_lock);
798}
799
800/**
801 * stm_source_link_drop() - detach stm_source from its stm device
802 * @src: stm_source device
803 *
804 * Unlinking means disconnecting from source's STM device; after this
805 * writes will be unsuccessful until it is linked to a new STM device.
806 *
807 * This will happen on "stm_source_link" sysfs attribute write to undo
808 * the existing link (if any), or on linked STM device's de-registration.
809 */
810static void stm_source_link_drop(struct stm_source_device *src)
811{
812 struct stm_device *stm;
813 int idx;
814
815 idx = srcu_read_lock(&stm_source_srcu);
816 stm = srcu_dereference(src->link, &stm_source_srcu);
817
818 if (stm) {
819 if (src->data->unlink)
820 src->data->unlink(src->data);
821
822 spin_lock(&stm->link_lock);
823 __stm_source_link_drop(src, stm);
824 spin_unlock(&stm->link_lock);
825 }
826
827 srcu_read_unlock(&stm_source_srcu, idx);
828}
829
830static ssize_t stm_source_link_show(struct device *dev,
831 struct device_attribute *attr,
832 char *buf)
833{
834 struct stm_source_device *src = to_stm_source_device(dev);
835 struct stm_device *stm;
836 int idx, ret;
837
838 idx = srcu_read_lock(&stm_source_srcu);
839 stm = srcu_dereference(src->link, &stm_source_srcu);
840 ret = sprintf(buf, "%s\n",
841 stm ? dev_name(&stm->dev) : "<none>");
842 srcu_read_unlock(&stm_source_srcu, idx);
843
844 return ret;
845}
846
847static ssize_t stm_source_link_store(struct device *dev,
848 struct device_attribute *attr,
849 const char *buf, size_t count)
850{
851 struct stm_source_device *src = to_stm_source_device(dev);
852 struct stm_device *link;
853 int err;
854
855 stm_source_link_drop(src);
856
857 link = stm_find_device(buf);
858 if (!link)
859 return -EINVAL;
860
861 err = stm_source_link_add(src, link);
862 if (err)
863 stm_put_device(link);
864
865 return err ? : count;
866}
867
868static DEVICE_ATTR_RW(stm_source_link);
869
870static struct attribute *stm_source_attrs[] = {
871 &dev_attr_stm_source_link.attr,
872 NULL,
873};
874
875ATTRIBUTE_GROUPS(stm_source);
876
877static struct class stm_source_class = {
878 .name = "stm_source",
879 .dev_groups = stm_source_groups,
880};
881
882static void stm_source_device_release(struct device *dev)
883{
884 struct stm_source_device *src = to_stm_source_device(dev);
885
886 kfree(src);
887}
888
889/**
890 * stm_source_register_device() - register an stm_source device
891 * @parent: parent device
892 * @data: device description structure
893 *
894 * This will create a device of stm_source class that can write
895 * data to an stm device once linked.
896 *
897 * Return: 0 on success, -errno otherwise.
898 */
899int stm_source_register_device(struct device *parent,
900 struct stm_source_data *data)
901{
902 struct stm_source_device *src;
903 int err;
904
905 if (!stm_core_up)
906 return -EPROBE_DEFER;
907
908 src = kzalloc(sizeof(*src), GFP_KERNEL);
909 if (!src)
910 return -ENOMEM;
911
912 device_initialize(&src->dev);
913 src->dev.class = &stm_source_class;
914 src->dev.parent = parent;
915 src->dev.release = stm_source_device_release;
916
917 err = kobject_set_name(&src->dev.kobj, "%s", data->name);
918 if (err)
919 goto err;
920
921 err = device_add(&src->dev);
922 if (err)
923 goto err;
924
925 spin_lock_init(&src->link_lock);
926 INIT_LIST_HEAD(&src->link_entry);
927 src->data = data;
928 data->src = src;
929
930 return 0;
931
932err:
933 put_device(&src->dev);
934 kfree(src);
935
936 return err;
937}
938EXPORT_SYMBOL_GPL(stm_source_register_device);
939
940/**
941 * stm_source_unregister_device() - unregister an stm_source device
942 * @data: device description that was used to register the device
943 *
944 * This will remove a previously created stm_source device from the system.
945 */
946void stm_source_unregister_device(struct stm_source_data *data)
947{
948 struct stm_source_device *src = data->src;
949
950 stm_source_link_drop(src);
951
952 device_destroy(&stm_source_class, src->dev.devt);
953}
954EXPORT_SYMBOL_GPL(stm_source_unregister_device);
955
956int stm_source_write(struct stm_source_data *data, unsigned int chan,
957 const char *buf, size_t count)
958{
959 struct stm_source_device *src = data->src;
960 struct stm_device *stm;
961 int idx;
962
963 if (!src->output.nr_chans)
964 return -ENODEV;
965
966 if (chan >= src->output.nr_chans)
967 return -EINVAL;
968
969 idx = srcu_read_lock(&stm_source_srcu);
970
971 stm = srcu_dereference(src->link, &stm_source_srcu);
972 if (stm)
973 stm_write(stm->data, src->output.master,
974 src->output.channel + chan,
975 buf, count);
976 else
977 count = -ENODEV;
978
979 srcu_read_unlock(&stm_source_srcu, idx);
980
981 return count;
982}
983EXPORT_SYMBOL_GPL(stm_source_write);
984
985static int __init stm_core_init(void)
986{
987 int err;
988
989 err = class_register(&stm_class);
990 if (err)
991 return err;
992
993 err = class_register(&stm_source_class);
994 if (err)
995 goto err_stm;
996
997 err = stp_configfs_init();
998 if (err)
999 goto err_src;
1000
1001 init_srcu_struct(&stm_source_srcu);
1002
1003 stm_core_up++;
1004
1005 return 0;
1006
1007err_src:
1008 class_unregister(&stm_source_class);
1009err_stm:
1010 class_unregister(&stm_class);
1011
1012 return err;
1013}
1014
1015module_init(stm_core_init);
1016
1017static void __exit stm_core_exit(void)
1018{
1019 cleanup_srcu_struct(&stm_source_srcu);
1020 class_unregister(&stm_source_class);
1021 class_unregister(&stm_class);
1022 stp_configfs_exit();
1023}
1024
1025module_exit(stm_core_exit);
1026
1027MODULE_LICENSE("GPL v2");
1028MODULE_DESCRIPTION("System Trace Module device class");
1029MODULE_AUTHOR("Alexander Shishkin <alexander.shishkin@linux.intel.com>");
drivers/hwtracing/stm/policy.c+529−0
@@ -0,0 +1,529 @@
1/*
2 * System Trace Module (STM) master/channel allocation policy management
3 * Copyright (c) 2014, Intel Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * A master/channel allocation policy allows mapping string identifiers to
15 * master and channel ranges, where allocation can be done.
16 */
17
18#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
19
20#include <linux/types.h>
21#include <linux/module.h>
22#include <linux/device.h>
23#include <linux/configfs.h>
24#include <linux/slab.h>
25#include <linux/stm.h>
26#include "stm.h"
27
28/*
29 * STP Master/Channel allocation policy configfs layout.
30 */
31
32struct stp_policy {
33 struct config_group group;
34 struct stm_device *stm;
35};
36
37struct stp_policy_node {
38 struct config_group group;
39 struct stp_policy *policy;
40 unsigned int first_master;
41 unsigned int last_master;
42 unsigned int first_channel;
43 unsigned int last_channel;
44};
45
46static struct configfs_subsystem stp_policy_subsys;
47
48void stp_policy_node_get_ranges(struct stp_policy_node *policy_node,
49 unsigned int *mstart, unsigned int *mend,
50 unsigned int *cstart, unsigned int *cend)
51{
52 *mstart = policy_node->first_master;
53 *mend = policy_node->last_master;
54 *cstart = policy_node->first_channel;
55 *cend = policy_node->last_channel;
56}
57
58static inline char *stp_policy_node_name(struct stp_policy_node *policy_node)
59{
60 return policy_node->group.cg_item.ci_name ? : "<none>";
61}
62
63static inline struct stp_policy *to_stp_policy(struct config_item *item)
64{
65 return item ?
66 container_of(to_config_group(item), struct stp_policy, group) :
67 NULL;
68}
69
70static inline struct stp_policy_node *
71to_stp_policy_node(struct config_item *item)
72{
73 return item ?
74 container_of(to_config_group(item), struct stp_policy_node,
75 group) :
76 NULL;
77}
78
79static ssize_t stp_policy_node_masters_show(struct stp_policy_node *policy_node,
80 char *page)
81{
82 ssize_t count;
83
84 count = sprintf(page, "%u %u\n", policy_node->first_master,
85 policy_node->last_master);
86
87 return count;
88}
89
90static ssize_t
91stp_policy_node_masters_store(struct stp_policy_node *policy_node,
92 const char *page, size_t count)
93{
94 unsigned int first, last;
95 struct stm_device *stm;
96 char *p = (char *)page;
97 ssize_t ret = -ENODEV;
98
99 if (sscanf(p, "%u %u", &first, &last) != 2)
100 return -EINVAL;
101
102 mutex_lock(&stp_policy_subsys.su_mutex);
103 stm = policy_node->policy->stm;
104 if (!stm)
105 goto unlock;
106
107 /* must be within [sw_start..sw_end], which is an inclusive range */
108 if (first > INT_MAX || last > INT_MAX || first > last ||
109 first < stm->data->sw_start ||
110 last > stm->data->sw_end) {
111 ret = -ERANGE;
112 goto unlock;
113 }
114
115 ret = count;
116 policy_node->first_master = first;
117 policy_node->last_master = last;
118
119unlock:
120 mutex_unlock(&stp_policy_subsys.su_mutex);
121
122 return ret;
123}
124
125static ssize_t
126stp_policy_node_channels_show(struct stp_policy_node *policy_node, char *page)
127{
128 ssize_t count;
129
130 count = sprintf(page, "%u %u\n", policy_node->first_channel,
131 policy_node->last_channel);
132
133 return count;
134}
135
136static ssize_t
137stp_policy_node_channels_store(struct stp_policy_node *policy_node,
138 const char *page, size_t count)
139{
140 unsigned int first, last;
141 struct stm_device *stm;
142 char *p = (char *)page;
143 ssize_t ret = -ENODEV;
144
145 if (sscanf(p, "%u %u", &first, &last) != 2)
146 return -EINVAL;
147
148 mutex_lock(&stp_policy_subsys.su_mutex);
149 stm = policy_node->policy->stm;
150 if (!stm)
151 goto unlock;
152
153 if (first > INT_MAX || last > INT_MAX || first > last ||
154 last >= stm->data->sw_nchannels) {
155 ret = -ERANGE;
156 goto unlock;
157 }
158
159 ret = count;
160 policy_node->first_channel = first;
161 policy_node->last_channel = last;
162
163unlock:
164 mutex_unlock(&stp_policy_subsys.su_mutex);
165
166 return ret;
167}
168
169static void stp_policy_node_release(struct config_item *item)
170{
171 kfree(to_stp_policy_node(item));
172}
173
174struct stp_policy_node_attribute {
175 struct configfs_attribute attr;
176 ssize_t (*show)(struct stp_policy_node *, char *);
177 ssize_t (*store)(struct stp_policy_node *, const char *, size_t);
178};
179
180static ssize_t stp_policy_node_attr_show(struct config_item *item,
181 struct configfs_attribute *attr,
182 char *page)
183{
184 struct stp_policy_node *policy_node = to_stp_policy_node(item);
185 struct stp_policy_node_attribute *pn_attr =
186 container_of(attr, struct stp_policy_node_attribute, attr);
187 ssize_t count = 0;
188
189 if (pn_attr->show)
190 count = pn_attr->show(policy_node, page);
191
192 return count;
193}
194
195static ssize_t stp_policy_node_attr_store(struct config_item *item,
196 struct configfs_attribute *attr,
197 const char *page, size_t len)
198{
199 struct stp_policy_node *policy_node = to_stp_policy_node(item);
200 struct stp_policy_node_attribute *pn_attr =
201 container_of(attr, struct stp_policy_node_attribute, attr);
202 ssize_t count = -EINVAL;
203
204 if (pn_attr->store)
205 count = pn_attr->store(policy_node, page, len);
206
207 return count;
208}
209
210static struct configfs_item_operations stp_policy_node_item_ops = {
211 .release = stp_policy_node_release,
212 .show_attribute = stp_policy_node_attr_show,
213 .store_attribute = stp_policy_node_attr_store,
214};
215
216static struct stp_policy_node_attribute stp_policy_node_attr_range = {
217 .attr = {
218 .ca_owner = THIS_MODULE,
219 .ca_name = "masters",
220 .ca_mode = S_IRUGO | S_IWUSR,
221 },
222 .show = stp_policy_node_masters_show,
223 .store = stp_policy_node_masters_store,
224};
225
226static struct stp_policy_node_attribute stp_policy_node_attr_channels = {
227 .attr = {
228 .ca_owner = THIS_MODULE,
229 .ca_name = "channels",
230 .ca_mode = S_IRUGO | S_IWUSR,
231 },
232 .show = stp_policy_node_channels_show,
233 .store = stp_policy_node_channels_store,
234};
235
236static struct configfs_attribute *stp_policy_node_attrs[] = {
237 &stp_policy_node_attr_range.attr,
238 &stp_policy_node_attr_channels.attr,
239 NULL,
240};
241
242static struct config_item_type stp_policy_type;
243static struct config_item_type stp_policy_node_type;
244
245static struct config_group *
246stp_policy_node_make(struct config_group *group, const char *name)
247{
248 struct stp_policy_node *policy_node, *parent_node;
249 struct stp_policy *policy;
250
251 if (group->cg_item.ci_type == &stp_policy_type) {
252 policy = container_of(group, struct stp_policy, group);
253 } else {
254 parent_node = container_of(group, struct stp_policy_node,
255 group);
256 policy = parent_node->policy;
257 }
258
259 if (!policy->stm)
260 return ERR_PTR(-ENODEV);
261
262 policy_node = kzalloc(sizeof(struct stp_policy_node), GFP_KERNEL);
263 if (!policy_node)
264 return ERR_PTR(-ENOMEM);
265
266 config_group_init_type_name(&policy_node->group, name,
267 &stp_policy_node_type);
268
269 policy_node->policy = policy;
270
271 /* default values for the attributes */
272 policy_node->first_master = policy->stm->data->sw_start;
273 policy_node->last_master = policy->stm->data->sw_end;
274 policy_node->first_channel = 0;
275 policy_node->last_channel = policy->stm->data->sw_nchannels - 1;
276
277 return &policy_node->group;
278}
279
280static void
281stp_policy_node_drop(struct config_group *group, struct config_item *item)
282{
283 config_item_put(item);
284}
285
286static struct configfs_group_operations stp_policy_node_group_ops = {
287 .make_group = stp_policy_node_make,
288 .drop_item = stp_policy_node_drop,
289};
290
291static struct config_item_type stp_policy_node_type = {
292 .ct_item_ops = &stp_policy_node_item_ops,
293 .ct_group_ops = &stp_policy_node_group_ops,
294 .ct_attrs = stp_policy_node_attrs,
295 .ct_owner = THIS_MODULE,
296};
297
298/*
299 * Root group: policies.
300 */
301static struct configfs_attribute stp_policy_attr_device = {
302 .ca_owner = THIS_MODULE,
303 .ca_name = "device",
304 .ca_mode = S_IRUGO,
305};
306
307static struct configfs_attribute *stp_policy_attrs[] = {
308 &stp_policy_attr_device,
309 NULL,
310};
311
312static ssize_t stp_policy_attr_show(struct config_item *item,
313 struct configfs_attribute *attr,
314 char *page)
315{
316 struct stp_policy *policy = to_stp_policy(item);
317 ssize_t count;
318
319 count = sprintf(page, "%s\n",
320 (policy && policy->stm) ?
321 policy->stm->data->name :
322 "<none>");
323
324 return count;
325}
326
327void stp_policy_unbind(struct stp_policy *policy)
328{
329 struct stm_device *stm = policy->stm;
330
331 if (WARN_ON_ONCE(!policy->stm))
332 return;
333
334 mutex_lock(&stm->policy_mutex);
335 stm->policy = NULL;
336 mutex_unlock(&stm->policy_mutex);
337
338 policy->stm = NULL;
339
340 stm_put_device(stm);
341}
342
343static void stp_policy_release(struct config_item *item)
344{
345 struct stp_policy *policy = to_stp_policy(item);
346
347 stp_policy_unbind(policy);
348 kfree(policy);
349}
350
351static struct configfs_item_operations stp_policy_item_ops = {
352 .release = stp_policy_release,
353 .show_attribute = stp_policy_attr_show,
354};
355
356static struct configfs_group_operations stp_policy_group_ops = {
357 .make_group = stp_policy_node_make,
358};
359
360static struct config_item_type stp_policy_type = {
361 .ct_item_ops = &stp_policy_item_ops,
362 .ct_group_ops = &stp_policy_group_ops,
363 .ct_attrs = stp_policy_attrs,
364 .ct_owner = THIS_MODULE,
365};
366
367static struct config_group *
368stp_policies_make(struct config_group *group, const char *name)
369{
370 struct config_group *ret;
371 struct stm_device *stm;
372 char *devname, *p;
373
374 devname = kasprintf(GFP_KERNEL, "%s", name);
375 if (!devname)
376 return ERR_PTR(-ENOMEM);
377
378 /*
379 * node must look like <device_name>.<policy_name>, where
380 * <device_name> is the name of an existing stm device and
381 * <policy_name> is an arbitrary string
382 */
383 p = strchr(devname, '.');
384 if (!p) {
385 kfree(devname);
386 return ERR_PTR(-EINVAL);
387 }
388
389 *p++ = '\0';
390
391 stm = stm_find_device(devname);
392 kfree(devname);
393
394 if (!stm)
395 return ERR_PTR(-ENODEV);
396
397 mutex_lock(&stm->policy_mutex);
398 if (stm->policy) {
399 ret = ERR_PTR(-EBUSY);
400 goto unlock_policy;
401 }
402
403 stm->policy = kzalloc(sizeof(*stm->policy), GFP_KERNEL);
404 if (!stm->policy) {
405 ret = ERR_PTR(-ENOMEM);
406 goto unlock_policy;
407 }
408
409 config_group_init_type_name(&stm->policy->group, name,
410 &stp_policy_type);
411 stm->policy->stm = stm;
412
413 ret = &stm->policy->group;
414
415unlock_policy:
416 mutex_unlock(&stm->policy_mutex);
417
418 if (IS_ERR(ret))
419 stm_put_device(stm);
420
421 return ret;
422}
423
424static struct configfs_group_operations stp_policies_group_ops = {
425 .make_group = stp_policies_make,
426};
427
428static struct config_item_type stp_policies_type = {
429 .ct_group_ops = &stp_policies_group_ops,
430 .ct_owner = THIS_MODULE,
431};
432
433static struct configfs_subsystem stp_policy_subsys = {
434 .su_group = {
435 .cg_item = {
436 .ci_namebuf = "stp-policy",
437 .ci_type = &stp_policies_type,
438 },
439 },
440};
441
442/*
443 * Lock the policy mutex from the outside
444 */
445static struct stp_policy_node *
446__stp_policy_node_lookup(struct stp_policy *policy, char *s)
447{
448 struct stp_policy_node *policy_node, *ret;
449 struct list_head *head = &policy->group.cg_children;
450 struct config_item *item;
451 char *start, *end = s;
452
453 if (list_empty(head))
454 return NULL;
455
456 /* return the first entry if everything else fails */
457 item = list_entry(head->next, struct config_item, ci_entry);
458 ret = to_stp_policy_node(item);
459
460next:
461 for (;;) {
462 start = strsep(&end, "/");
463 if (!start)
464 break;
465
466 if (!*start)
467 continue;
468
469 list_for_each_entry(item, head, ci_entry) {
470 policy_node = to_stp_policy_node(item);
471
472 if (!strcmp(start,
473 policy_node->group.cg_item.ci_name)) {
474 ret = policy_node;
475
476 if (!end)
477 goto out;
478
479 head = &policy_node->group.cg_children;
480 goto next;
481 }
482 }
483 break;
484 }
485
486out:
487 return ret;
488}
489
490
491struct stp_policy_node *
492stp_policy_node_lookup(struct stm_device *stm, char *s)
493{
494 struct stp_policy_node *policy_node = NULL;
495
496 mutex_lock(&stp_policy_subsys.su_mutex);
497
498 mutex_lock(&stm->policy_mutex);
499 if (stm->policy)
500 policy_node = __stp_policy_node_lookup(stm->policy, s);
501 mutex_unlock(&stm->policy_mutex);
502
503 if (policy_node)
504 config_item_get(&policy_node->group.cg_item);
505 mutex_unlock(&stp_policy_subsys.su_mutex);
506
507 return policy_node;
508}
509
510void stp_policy_node_put(struct stp_policy_node *policy_node)
511{
512 config_item_put(&policy_node->group.cg_item);
513}
514
515int __init stp_configfs_init(void)
516{
517 int err;
518
519 config_group_init(&stp_policy_subsys.su_group);
520 mutex_init(&stp_policy_subsys.su_mutex);
521 err = configfs_register_subsystem(&stp_policy_subsys);
522
523 return err;
524}
525
526void __exit stp_configfs_exit(void)
527{
528 configfs_unregister_subsystem(&stp_policy_subsys);
529}
drivers/hwtracing/stm/stm.h+87−0
@@ -0,0 +1,87 @@
1/*
2 * System Trace Module (STM) infrastructure
3 * Copyright (c) 2014, Intel Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * STM class implements generic infrastructure for System Trace Module devices
15 * as defined in MIPI STPv2 specification.
16 */
17
18#ifndef _STM_STM_H_
19#define _STM_STM_H_
20
21struct stp_policy;
22struct stp_policy_node;
23
24struct stp_policy_node *
25stp_policy_node_lookup(struct stm_device *stm, char *s);
26void stp_policy_node_put(struct stp_policy_node *policy_node);
27void stp_policy_unbind(struct stp_policy *policy);
28
29void stp_policy_node_get_ranges(struct stp_policy_node *policy_node,
30 unsigned int *mstart, unsigned int *mend,
31 unsigned int *cstart, unsigned int *cend);
32int stp_configfs_init(void);
33void stp_configfs_exit(void);
34
35struct stp_master {
36 unsigned int nr_free;
37 unsigned long chan_map[0];
38};
39
40struct stm_device {
41 struct device dev;
42 struct module *owner;
43 struct stp_policy *policy;
44 struct mutex policy_mutex;
45 int major;
46 unsigned int sw_nmasters;
47 struct stm_data *data;
48 spinlock_t link_lock;
49 struct list_head link_list;
50 /* master allocation */
51 spinlock_t mc_lock;
52 struct stp_master *masters[0];
53};
54
55#define to_stm_device(_d) \
56 container_of((_d), struct stm_device, dev)
57
58struct stm_output {
59 unsigned int master;
60 unsigned int channel;
61 unsigned int nr_chans;
62};
63
64struct stm_file {
65 struct stm_device *stm;
66 struct stp_policy_node *policy_node;
67 struct stm_output output;
68};
69
70struct stm_device *stm_find_device(const char *name);
71void stm_put_device(struct stm_device *stm);
72
73struct stm_source_device {
74 struct device dev;
75 struct stm_source_data *data;
76 spinlock_t link_lock;
77 struct stm_device *link;
78 struct list_head link_entry;
79 /* one output per stm_source device */
80 struct stp_policy_node *policy_node;
81 struct stm_output output;
82};
83
84#define to_stm_source_device(_d) \
85 container_of((_d), struct stm_source_device, dev)
86
87#endif /* _STM_STM_H_ */
include/linux/stm.h+126−0
@@ -0,0 +1,126 @@
1/*
2 * System Trace Module (STM) infrastructure apis
3 * Copyright (C) 2014 Intel Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 */
14
15#ifndef _STM_H_
16#define _STM_H_
17
18#include <linux/device.h>
19
20/**
21 * enum stp_packet_type - STP packets that an STM driver sends
22 */
23enum stp_packet_type {
24 STP_PACKET_DATA = 0,
25 STP_PACKET_FLAG,
26 STP_PACKET_USER,
27 STP_PACKET_MERR,
28 STP_PACKET_GERR,
29 STP_PACKET_TRIG,
30 STP_PACKET_XSYNC,
31};
32
33/**
34 * enum stp_packet_flags - STP packet modifiers
35 */
36enum stp_packet_flags {
37 STP_PACKET_MARKED = 0x1,
38 STP_PACKET_TIMESTAMPED = 0x2,
39};
40
41struct stp_policy;
42
43struct stm_device;
44
45/**
46 * struct stm_data - STM device description and callbacks
47 * @name: device name
48 * @stm: internal structure, only used by stm class code
49 * @sw_start: first STP master available to software
50 * @sw_end: last STP master available to software
51 * @sw_nchannels: number of STP channels per master
52 * @sw_mmiosz: size of one channel's IO space, for mmap, optional
53 * @packet: callback that sends an STP packet
54 * @mmio_addr: mmap callback, optional
55 * @link: called when a new stm_source gets linked to us, optional
56 * @unlink: likewise for unlinking, again optional
57 * @set_options: set device-specific options on a channel
58 *
59 * Fill out this structure before calling stm_register_device() to create
60 * an STM device and stm_unregister_device() to destroy it. It will also be
61 * passed back to @packet(), @mmio_addr(), @link(), @unlink() and @set_options()
62 * callbacks.
63 *
64 * Normally, an STM device will have a range of masters available to software
65 * and the rest being statically assigned to various hardware trace sources.
66 * The former is defined by the the range [@sw_start..@sw_end] of the device
67 * description. That is, the lowest master that can be allocated to software
68 * writers is @sw_start and data from this writer will appear is @sw_start
69 * master in the STP stream.
70 */
71struct stm_data {
72 const char *name;
73 struct stm_device *stm;
74 unsigned int sw_start;
75 unsigned int sw_end;
76 unsigned int sw_nchannels;
77 unsigned int sw_mmiosz;
78 ssize_t (*packet)(struct stm_data *, unsigned int,
79 unsigned int, unsigned int,
80 unsigned int, unsigned int,
81 const unsigned char *);
82 phys_addr_t (*mmio_addr)(struct stm_data *, unsigned int,
83 unsigned int, unsigned int);
84 int (*link)(struct stm_data *, unsigned int,
85 unsigned int);
86 void (*unlink)(struct stm_data *, unsigned int,
87 unsigned int);
88 long (*set_options)(struct stm_data *, unsigned int,
89 unsigned int, unsigned int,
90 unsigned long);
91};
92
93int stm_register_device(struct device *parent, struct stm_data *stm_data,
94 struct module *owner);
95void stm_unregister_device(struct stm_data *stm_data);
96
97struct stm_source_device;
98
99/**
100 * struct stm_source_data - STM source device description and callbacks
101 * @name: device name, will be used for policy lookup
102 * @src: internal structure, only used by stm class code
103 * @nr_chans: number of channels to allocate
104 * @link: called when this source gets linked to an STM device
105 * @unlink: called when this source is about to get unlinked from its STM
106 *
107 * Fill in this structure before calling stm_source_register_device() to
108 * register a source device. Also pass it to unregister and write calls.
109 */
110struct stm_source_data {
111 const char *name;
112 struct stm_source_device *src;
113 unsigned int percpu;
114 unsigned int nr_chans;
115 int (*link)(struct stm_source_data *data);
116 void (*unlink)(struct stm_source_data *data);
117};
118
119int stm_source_register_device(struct device *parent,
120 struct stm_source_data *data);
121void stm_source_unregister_device(struct stm_source_data *data);
122
123int stm_source_write(struct stm_source_data *data, unsigned int chan,
124 const char *buf, size_t count);
125
126#endif /* _STM_H_ */
include/uapi/linux/stm.h+50−0
@@ -0,0 +1,50 @@
1/*
2 * System Trace Module (STM) userspace interfaces
3 * Copyright (c) 2014, Intel Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * STM class implements generic infrastructure for System Trace Module devices
15 * as defined in MIPI STPv2 specification.
16 */
17
18#ifndef _UAPI_LINUX_STM_H
19#define _UAPI_LINUX_STM_H
20
21#include <linux/types.h>
22
23/**
24 * struct stp_policy_id - identification for the STP policy
25 * @size: size of the structure including real id[] length
26 * @master: assigned master
27 * @channel: first assigned channel
28 * @width: number of requested channels
29 * @id: identification string
30 *
31 * User must calculate the total size of the structure and put it into
32 * @size field, fill out the @id and desired @width. In return, kernel
33 * fills out @master, @channel and @width.
34 */
35struct stp_policy_id {
36 __u32 size;
37 __u16 master;
38 __u16 channel;
39 __u16 width;
40 /* padding */
41 __u16 __reserved_0;
42 __u32 __reserved_1;
43 char id[0];
44};
45
46#define STP_POLICY_ID_SET _IOWR('%', 0, struct stp_policy_id)
47#define STP_POLICY_ID_GET _IOR('%', 1, struct stp_policy_id)
48#define STP_SET_OPTIONS _IOW('%', 2, __u64)
49
50#endif /* _UAPI_LINUX_STM_H */

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t