xref: /openbmc/linux/drivers/hwtracing/stm/policy.c (revision 23c2b932)
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 }
485