GNU Linux-libre 4.14.332-gnu1
[releases.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
80 stp_policy_node_masters_show(struct config_item *item, char *page)
81 {
82         struct stp_policy_node *policy_node = to_stp_policy_node(item);
83         ssize_t count;
84
85         count = sprintf(page, "%u %u\n", policy_node->first_master,
86                         policy_node->last_master);
87
88         return count;
89 }
90
91 static ssize_t
92 stp_policy_node_masters_store(struct config_item *item, const char *page,
93                               size_t count)
94 {
95         struct stp_policy_node *policy_node = to_stp_policy_node(item);
96         unsigned int first, last;
97         struct stm_device *stm;
98         char *p = (char *)page;
99         ssize_t ret = -ENODEV;
100
101         if (sscanf(p, "%u %u", &first, &last) != 2)
102                 return -EINVAL;
103
104         mutex_lock(&stp_policy_subsys.su_mutex);
105         stm = policy_node->policy->stm;
106         if (!stm)
107                 goto unlock;
108
109         /* must be within [sw_start..sw_end], which is an inclusive range */
110         if (first > last || first < stm->data->sw_start ||
111             last > stm->data->sw_end) {
112                 ret = -ERANGE;
113                 goto unlock;
114         }
115
116         ret = count;
117         policy_node->first_master = first;
118         policy_node->last_master = last;
119
120 unlock:
121         mutex_unlock(&stp_policy_subsys.su_mutex);
122
123         return ret;
124 }
125
126 static ssize_t
127 stp_policy_node_channels_show(struct config_item *item, char *page)
128 {
129         struct stp_policy_node *policy_node = to_stp_policy_node(item);
130         ssize_t count;
131
132         count = sprintf(page, "%u %u\n", policy_node->first_channel,
133                         policy_node->last_channel);
134
135         return count;
136 }
137
138 static ssize_t
139 stp_policy_node_channels_store(struct config_item *item, const char *page,
140                                size_t count)
141 {
142         struct stp_policy_node *policy_node = to_stp_policy_node(item);
143         unsigned int first, last;
144         struct stm_device *stm;
145         char *p = (char *)page;
146         ssize_t ret = -ENODEV;
147
148         if (sscanf(p, "%u %u", &first, &last) != 2)
149                 return -EINVAL;
150
151         mutex_lock(&stp_policy_subsys.su_mutex);
152         stm = policy_node->policy->stm;
153         if (!stm)
154                 goto unlock;
155
156         if (first > INT_MAX || last > INT_MAX || first > last ||
157             last >= stm->data->sw_nchannels) {
158                 ret = -ERANGE;
159                 goto unlock;
160         }
161
162         ret = count;
163         policy_node->first_channel = first;
164         policy_node->last_channel = last;
165
166 unlock:
167         mutex_unlock(&stp_policy_subsys.su_mutex);
168
169         return ret;
170 }
171
172 static void stp_policy_node_release(struct config_item *item)
173 {
174         kfree(to_stp_policy_node(item));
175 }
176
177 static struct configfs_item_operations stp_policy_node_item_ops = {
178         .release                = stp_policy_node_release,
179 };
180
181 CONFIGFS_ATTR(stp_policy_node_, masters);
182 CONFIGFS_ATTR(stp_policy_node_, channels);
183
184 static struct configfs_attribute *stp_policy_node_attrs[] = {
185         &stp_policy_node_attr_masters,
186         &stp_policy_node_attr_channels,
187         NULL,
188 };
189
190 static struct config_item_type stp_policy_type;
191 static struct config_item_type stp_policy_node_type;
192
193 static struct config_group *
194 stp_policy_node_make(struct config_group *group, const char *name)
195 {
196         struct stp_policy_node *policy_node, *parent_node;
197         struct stp_policy *policy;
198
199         if (group->cg_item.ci_type == &stp_policy_type) {
200                 policy = container_of(group, struct stp_policy, group);
201         } else {
202                 parent_node = container_of(group, struct stp_policy_node,
203                                            group);
204                 policy = parent_node->policy;
205         }
206
207         if (!policy->stm)
208                 return ERR_PTR(-ENODEV);
209
210         policy_node = kzalloc(sizeof(struct stp_policy_node), GFP_KERNEL);
211         if (!policy_node)
212                 return ERR_PTR(-ENOMEM);
213
214         config_group_init_type_name(&policy_node->group, name,
215                                     &stp_policy_node_type);
216
217         policy_node->policy = policy;
218
219         /* default values for the attributes */
220         policy_node->first_master = policy->stm->data->sw_start;
221         policy_node->last_master = policy->stm->data->sw_end;
222         policy_node->first_channel = 0;
223         policy_node->last_channel = policy->stm->data->sw_nchannels - 1;
224
225         return &policy_node->group;
226 }
227
228 static void
229 stp_policy_node_drop(struct config_group *group, struct config_item *item)
230 {
231         config_item_put(item);
232 }
233
234 static struct configfs_group_operations stp_policy_node_group_ops = {
235         .make_group     = stp_policy_node_make,
236         .drop_item      = stp_policy_node_drop,
237 };
238
239 static struct config_item_type stp_policy_node_type = {
240         .ct_item_ops    = &stp_policy_node_item_ops,
241         .ct_group_ops   = &stp_policy_node_group_ops,
242         .ct_attrs       = stp_policy_node_attrs,
243         .ct_owner       = THIS_MODULE,
244 };
245
246 /*
247  * Root group: policies.
248  */
249 static ssize_t stp_policy_device_show(struct config_item *item,
250                                       char *page)
251 {
252         struct stp_policy *policy = to_stp_policy(item);
253         ssize_t count;
254
255         count = sprintf(page, "%s\n",
256                         (policy && policy->stm) ?
257                         policy->stm->data->name :
258                         "<none>");
259
260         return count;
261 }
262
263 CONFIGFS_ATTR_RO(stp_policy_, device);
264
265 static struct configfs_attribute *stp_policy_attrs[] = {
266         &stp_policy_attr_device,
267         NULL,
268 };
269
270 void stp_policy_unbind(struct stp_policy *policy)
271 {
272         struct stm_device *stm = policy->stm;
273
274         /*
275          * stp_policy_release() will not call here if the policy is already
276          * unbound; other users should not either, as no link exists between
277          * this policy and anything else in that case
278          */
279         if (WARN_ON_ONCE(!policy->stm))
280                 return;
281
282         lockdep_assert_held(&stm->policy_mutex);
283
284         stm->policy = NULL;
285         policy->stm = NULL;
286
287         stm_put_device(stm);
288 }
289
290 static void stp_policy_release(struct config_item *item)
291 {
292         struct stp_policy *policy = to_stp_policy(item);
293         struct stm_device *stm = policy->stm;
294
295         /* a policy *can* be unbound and still exist in configfs tree */
296         if (!stm)
297                 return;
298
299         mutex_lock(&stm->policy_mutex);
300         stp_policy_unbind(policy);
301         mutex_unlock(&stm->policy_mutex);
302
303         kfree(policy);
304 }
305
306 static struct configfs_item_operations stp_policy_item_ops = {
307         .release                = stp_policy_release,
308 };
309
310 static struct configfs_group_operations stp_policy_group_ops = {
311         .make_group     = stp_policy_node_make,
312 };
313
314 static struct config_item_type stp_policy_type = {
315         .ct_item_ops    = &stp_policy_item_ops,
316         .ct_group_ops   = &stp_policy_group_ops,
317         .ct_attrs       = stp_policy_attrs,
318         .ct_owner       = THIS_MODULE,
319 };
320
321 static struct config_group *
322 stp_policies_make(struct config_group *group, const char *name)
323 {
324         struct config_group *ret;
325         struct stm_device *stm;
326         char *devname, *p;
327
328         devname = kasprintf(GFP_KERNEL, "%s", name);
329         if (!devname)
330                 return ERR_PTR(-ENOMEM);
331
332         /*
333          * node must look like <device_name>.<policy_name>, where
334          * <device_name> is the name of an existing stm device; may
335          *               contain dots;
336          * <policy_name> is an arbitrary string; may not contain dots
337          */
338         p = strrchr(devname, '.');
339         if (!p) {
340                 kfree(devname);
341                 return ERR_PTR(-EINVAL);
342         }
343
344         *p = '\0';
345
346         stm = stm_find_device(devname);
347         kfree(devname);
348
349         if (!stm)
350                 return ERR_PTR(-ENODEV);
351
352         mutex_lock(&stm->policy_mutex);
353         if (stm->policy) {
354                 ret = ERR_PTR(-EBUSY);
355                 goto unlock_policy;
356         }
357
358         stm->policy = kzalloc(sizeof(*stm->policy), GFP_KERNEL);
359         if (!stm->policy) {
360                 ret = ERR_PTR(-ENOMEM);
361                 goto unlock_policy;
362         }
363
364         config_group_init_type_name(&stm->policy->group, name,
365                                     &stp_policy_type);
366         stm->policy->stm = stm;
367
368         ret = &stm->policy->group;
369
370 unlock_policy:
371         mutex_unlock(&stm->policy_mutex);
372
373         if (IS_ERR(ret))
374                 stm_put_device(stm);
375
376         return ret;
377 }
378
379 static struct configfs_group_operations stp_policies_group_ops = {
380         .make_group     = stp_policies_make,
381 };
382
383 static struct config_item_type stp_policies_type = {
384         .ct_group_ops   = &stp_policies_group_ops,
385         .ct_owner       = THIS_MODULE,
386 };
387
388 static struct configfs_subsystem stp_policy_subsys = {
389         .su_group = {
390                 .cg_item = {
391                         .ci_namebuf     = "stp-policy",
392                         .ci_type        = &stp_policies_type,
393                 },
394         },
395 };
396
397 /*
398  * Lock the policy mutex from the outside
399  */
400 static struct stp_policy_node *
401 __stp_policy_node_lookup(struct stp_policy *policy, char *s)
402 {
403         struct stp_policy_node *policy_node, *ret;
404         struct list_head *head = &policy->group.cg_children;
405         struct config_item *item;
406         char *start, *end = s;
407
408         if (list_empty(head))
409                 return NULL;
410
411         /* return the first entry if everything else fails */
412         item = list_entry(head->next, struct config_item, ci_entry);
413         ret = to_stp_policy_node(item);
414
415 next:
416         for (;;) {
417                 start = strsep(&end, "/");
418                 if (!start)
419                         break;
420
421                 if (!*start)
422                         continue;
423
424                 list_for_each_entry(item, head, ci_entry) {
425                         policy_node = to_stp_policy_node(item);
426
427                         if (!strcmp(start,
428                                     policy_node->group.cg_item.ci_name)) {
429                                 ret = policy_node;
430
431                                 if (!end)
432                                         goto out;
433
434                                 head = &policy_node->group.cg_children;
435                                 goto next;
436                         }
437                 }
438                 break;
439         }
440
441 out:
442         return ret;
443 }
444
445
446 struct stp_policy_node *
447 stp_policy_node_lookup(struct stm_device *stm, char *s)
448 {
449         struct stp_policy_node *policy_node = NULL;
450
451         mutex_lock(&stp_policy_subsys.su_mutex);
452
453         mutex_lock(&stm->policy_mutex);
454         if (stm->policy)
455                 policy_node = __stp_policy_node_lookup(stm->policy, s);
456         mutex_unlock(&stm->policy_mutex);
457
458         if (policy_node)
459                 config_item_get(&policy_node->group.cg_item);
460         mutex_unlock(&stp_policy_subsys.su_mutex);
461
462         return policy_node;
463 }
464
465 void stp_policy_node_put(struct stp_policy_node *policy_node)
466 {
467         config_item_put(&policy_node->group.cg_item);
468 }
469
470 int __init stp_configfs_init(void)
471 {
472         int err;
473
474         config_group_init(&stp_policy_subsys.su_group);
475         mutex_init(&stp_policy_subsys.su_mutex);
476         err = configfs_register_subsystem(&stp_policy_subsys);
477
478         return err;
479 }
480
481 void __exit stp_configfs_exit(void)
482 {
483         configfs_unregister_subsystem(&stp_policy_subsys);
484 }