]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/hwtracing/stm/policy.c
Merge remote-tracking branch 'char-misc/char-misc-next'
[karo-tx-linux.git] / drivers / hwtracing / stm / policy.c
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
32 struct stp_policy {
33         struct config_group     group;
34         struct stm_device       *stm;
35 };
36
37 struct 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
46 static struct configfs_subsystem stp_policy_subsys;
47
48 void 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
58 static 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
63 static 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
70 static inline struct stp_policy_node *
71 to_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
79 static 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
90 static ssize_t
91 stp_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
119 unlock:
120         mutex_unlock(&stp_policy_subsys.su_mutex);
121
122         return ret;
123 }
124
125 static ssize_t
126 stp_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
136 static ssize_t
137 stp_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
163 unlock:
164         mutex_unlock(&stp_policy_subsys.su_mutex);
165
166         return ret;
167 }
168
169 static void stp_policy_node_release(struct config_item *item)
170 {
171         kfree(to_stp_policy_node(item));
172 }
173
174 struct 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
180 static 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
195 static 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
210 static 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
216 static 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
226 static 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
236 static 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
242 static struct config_item_type stp_policy_type;
243 static struct config_item_type stp_policy_node_type;
244
245 static struct config_group *
246 stp_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
280 static void
281 stp_policy_node_drop(struct config_group *group, struct config_item *item)
282 {
283         config_item_put(item);
284 }
285
286 static 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
291 static 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  */
301 static struct configfs_attribute stp_policy_attr_device = {
302         .ca_owner = THIS_MODULE,
303         .ca_name = "device",
304         .ca_mode = S_IRUGO,
305 };
306
307 static struct configfs_attribute *stp_policy_attrs[] = {
308         &stp_policy_attr_device,
309         NULL,
310 };
311
312 static 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
327 void 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
343 static 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
351 static struct configfs_item_operations stp_policy_item_ops = {
352         .release                = stp_policy_release,
353         .show_attribute         = stp_policy_attr_show,
354 };
355
356 static struct configfs_group_operations stp_policy_group_ops = {
357         .make_group     = stp_policy_node_make,
358 };
359
360 static 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
367 static struct config_group *
368 stp_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
415 unlock_policy:
416         mutex_unlock(&stm->policy_mutex);
417
418         if (IS_ERR(ret))
419                 stm_put_device(stm);
420
421         return ret;
422 }
423
424 static struct configfs_group_operations stp_policies_group_ops = {
425         .make_group     = stp_policies_make,
426 };
427
428 static struct config_item_type stp_policies_type = {
429         .ct_group_ops   = &stp_policies_group_ops,
430         .ct_owner       = THIS_MODULE,
431 };
432
433 static 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  */
445 static 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
460 next:
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
486 out:
487         return ret;
488 }
489
490
491 struct stp_policy_node *
492 stp_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
510 void stp_policy_node_put(struct stp_policy_node *policy_node)
511 {
512         config_item_put(&policy_node->group.cg_item);
513 }
514
515 int __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
526 void __exit stp_configfs_exit(void)
527 {
528         configfs_unregister_subsystem(&stp_policy_subsys);
529 }