xref: /openbmc/linux/drivers/hwtracing/stm/policy.c (revision 9ea393d8)
19ea393d8SAlexander Shishkin // SPDX-License-Identifier: GPL-2.0
27bd1d409SAlexander Shishkin /*
37bd1d409SAlexander Shishkin  * System Trace Module (STM) master/channel allocation policy management
47bd1d409SAlexander Shishkin  * Copyright (c) 2014, Intel Corporation.
57bd1d409SAlexander Shishkin  *
67bd1d409SAlexander Shishkin  * A master/channel allocation policy allows mapping string identifiers to
77bd1d409SAlexander Shishkin  * master and channel ranges, where allocation can be done.
87bd1d409SAlexander Shishkin  */
97bd1d409SAlexander Shishkin 
107bd1d409SAlexander Shishkin #define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
117bd1d409SAlexander Shishkin 
127bd1d409SAlexander Shishkin #include <linux/types.h>
137bd1d409SAlexander Shishkin #include <linux/module.h>
147bd1d409SAlexander Shishkin #include <linux/device.h>
157bd1d409SAlexander Shishkin #include <linux/configfs.h>
167bd1d409SAlexander Shishkin #include <linux/slab.h>
177bd1d409SAlexander Shishkin #include <linux/stm.h>
187bd1d409SAlexander Shishkin #include "stm.h"
197bd1d409SAlexander Shishkin 
207bd1d409SAlexander Shishkin /*
217bd1d409SAlexander Shishkin  * STP Master/Channel allocation policy configfs layout.
227bd1d409SAlexander Shishkin  */
237bd1d409SAlexander Shishkin 
247bd1d409SAlexander Shishkin struct stp_policy {
257bd1d409SAlexander Shishkin 	struct config_group	group;
267bd1d409SAlexander Shishkin 	struct stm_device	*stm;
277bd1d409SAlexander Shishkin };
287bd1d409SAlexander Shishkin 
297bd1d409SAlexander Shishkin struct stp_policy_node {
307bd1d409SAlexander Shishkin 	struct config_group	group;
317bd1d409SAlexander Shishkin 	struct stp_policy	*policy;
327bd1d409SAlexander Shishkin 	unsigned int		first_master;
337bd1d409SAlexander Shishkin 	unsigned int		last_master;
347bd1d409SAlexander Shishkin 	unsigned int		first_channel;
357bd1d409SAlexander Shishkin 	unsigned int		last_channel;
367bd1d409SAlexander Shishkin };
377bd1d409SAlexander Shishkin 
387bd1d409SAlexander Shishkin static struct configfs_subsystem stp_policy_subsys;
397bd1d409SAlexander Shishkin 
407bd1d409SAlexander Shishkin void stp_policy_node_get_ranges(struct stp_policy_node *policy_node,
417bd1d409SAlexander Shishkin 				unsigned int *mstart, unsigned int *mend,
427bd1d409SAlexander Shishkin 				unsigned int *cstart, unsigned int *cend)
437bd1d409SAlexander Shishkin {
447bd1d409SAlexander Shishkin 	*mstart	= policy_node->first_master;
457bd1d409SAlexander Shishkin 	*mend	= policy_node->last_master;
467bd1d409SAlexander Shishkin 	*cstart	= policy_node->first_channel;
477bd1d409SAlexander Shishkin 	*cend	= policy_node->last_channel;
487bd1d409SAlexander Shishkin }
497bd1d409SAlexander Shishkin 
507bd1d409SAlexander Shishkin static inline char *stp_policy_node_name(struct stp_policy_node *policy_node)
517bd1d409SAlexander Shishkin {
527bd1d409SAlexander Shishkin 	return policy_node->group.cg_item.ci_name ? : "<none>";
537bd1d409SAlexander Shishkin }
547bd1d409SAlexander Shishkin 
557bd1d409SAlexander Shishkin static inline struct stp_policy *to_stp_policy(struct config_item *item)
567bd1d409SAlexander Shishkin {
577bd1d409SAlexander Shishkin 	return item ?
587bd1d409SAlexander Shishkin 		container_of(to_config_group(item), struct stp_policy, group) :
597bd1d409SAlexander Shishkin 		NULL;
607bd1d409SAlexander Shishkin }
617bd1d409SAlexander Shishkin 
627bd1d409SAlexander Shishkin static inline struct stp_policy_node *
637bd1d409SAlexander Shishkin to_stp_policy_node(struct config_item *item)
647bd1d409SAlexander Shishkin {
657bd1d409SAlexander Shishkin 	return item ?
667bd1d409SAlexander Shishkin 		container_of(to_config_group(item), struct stp_policy_node,
677bd1d409SAlexander Shishkin 			     group) :
687bd1d409SAlexander Shishkin 		NULL;
697bd1d409SAlexander Shishkin }
707bd1d409SAlexander Shishkin 
719aa3d651SLinus Torvalds static ssize_t
729aa3d651SLinus Torvalds stp_policy_node_masters_show(struct config_item *item, char *page)
737bd1d409SAlexander Shishkin {
749aa3d651SLinus Torvalds 	struct stp_policy_node *policy_node = to_stp_policy_node(item);
757bd1d409SAlexander Shishkin 	ssize_t count;
767bd1d409SAlexander Shishkin 
777bd1d409SAlexander Shishkin 	count = sprintf(page, "%u %u\n", policy_node->first_master,
787bd1d409SAlexander Shishkin 			policy_node->last_master);
797bd1d409SAlexander Shishkin 
807bd1d409SAlexander Shishkin 	return count;
817bd1d409SAlexander Shishkin }
827bd1d409SAlexander Shishkin 
837bd1d409SAlexander Shishkin static ssize_t
849aa3d651SLinus Torvalds stp_policy_node_masters_store(struct config_item *item, const char *page,
859aa3d651SLinus Torvalds 			      size_t count)
867bd1d409SAlexander Shishkin {
879aa3d651SLinus Torvalds 	struct stp_policy_node *policy_node = to_stp_policy_node(item);
887bd1d409SAlexander Shishkin 	unsigned int first, last;
897bd1d409SAlexander Shishkin 	struct stm_device *stm;
907bd1d409SAlexander Shishkin 	char *p = (char *)page;
917bd1d409SAlexander Shishkin 	ssize_t ret = -ENODEV;
927bd1d409SAlexander Shishkin 
937bd1d409SAlexander Shishkin 	if (sscanf(p, "%u %u", &first, &last) != 2)
947bd1d409SAlexander Shishkin 		return -EINVAL;
957bd1d409SAlexander Shishkin 
967bd1d409SAlexander Shishkin 	mutex_lock(&stp_policy_subsys.su_mutex);
977bd1d409SAlexander Shishkin 	stm = policy_node->policy->stm;
987bd1d409SAlexander Shishkin 	if (!stm)
997bd1d409SAlexander Shishkin 		goto unlock;
1007bd1d409SAlexander Shishkin 
1017bd1d409SAlexander Shishkin 	/* must be within [sw_start..sw_end], which is an inclusive range */
102f57af6dfSChunyan Zhang 	if (first > last || first < stm->data->sw_start ||
1037bd1d409SAlexander Shishkin 	    last > stm->data->sw_end) {
1047bd1d409SAlexander Shishkin 		ret = -ERANGE;
1057bd1d409SAlexander Shishkin 		goto unlock;
1067bd1d409SAlexander Shishkin 	}
1077bd1d409SAlexander Shishkin 
1087bd1d409SAlexander Shishkin 	ret = count;
1097bd1d409SAlexander Shishkin 	policy_node->first_master = first;
1107bd1d409SAlexander Shishkin 	policy_node->last_master = last;
1117bd1d409SAlexander Shishkin 
1127bd1d409SAlexander Shishkin unlock:
1137bd1d409SAlexander Shishkin 	mutex_unlock(&stp_policy_subsys.su_mutex);
1147bd1d409SAlexander Shishkin 
1157bd1d409SAlexander Shishkin 	return ret;
1167bd1d409SAlexander Shishkin }
1177bd1d409SAlexander Shishkin 
1187bd1d409SAlexander Shishkin static ssize_t
1199aa3d651SLinus Torvalds stp_policy_node_channels_show(struct config_item *item, char *page)
1207bd1d409SAlexander Shishkin {
1219aa3d651SLinus Torvalds 	struct stp_policy_node *policy_node = to_stp_policy_node(item);
1227bd1d409SAlexander Shishkin 	ssize_t count;
1237bd1d409SAlexander Shishkin 
1247bd1d409SAlexander Shishkin 	count = sprintf(page, "%u %u\n", policy_node->first_channel,
1257bd1d409SAlexander Shishkin 			policy_node->last_channel);
1267bd1d409SAlexander Shishkin 
1277bd1d409SAlexander Shishkin 	return count;
1287bd1d409SAlexander Shishkin }
1297bd1d409SAlexander Shishkin 
1307bd1d409SAlexander Shishkin static ssize_t
1319aa3d651SLinus Torvalds stp_policy_node_channels_store(struct config_item *item, const char *page,
1329aa3d651SLinus Torvalds 			       size_t count)
1337bd1d409SAlexander Shishkin {
1349aa3d651SLinus Torvalds 	struct stp_policy_node *policy_node = to_stp_policy_node(item);
1357bd1d409SAlexander Shishkin 	unsigned int first, last;
1367bd1d409SAlexander Shishkin 	struct stm_device *stm;
1377bd1d409SAlexander Shishkin 	char *p = (char *)page;
1387bd1d409SAlexander Shishkin 	ssize_t ret = -ENODEV;
1397bd1d409SAlexander Shishkin 
1407bd1d409SAlexander Shishkin 	if (sscanf(p, "%u %u", &first, &last) != 2)
1417bd1d409SAlexander Shishkin 		return -EINVAL;
1427bd1d409SAlexander Shishkin 
1437bd1d409SAlexander Shishkin 	mutex_lock(&stp_policy_subsys.su_mutex);
1447bd1d409SAlexander Shishkin 	stm = policy_node->policy->stm;
1457bd1d409SAlexander Shishkin 	if (!stm)
1467bd1d409SAlexander Shishkin 		goto unlock;
1477bd1d409SAlexander Shishkin 
1487bd1d409SAlexander Shishkin 	if (first > INT_MAX || last > INT_MAX || first > last ||
1497bd1d409SAlexander Shishkin 	    last >= stm->data->sw_nchannels) {
1507bd1d409SAlexander Shishkin 		ret = -ERANGE;
1517bd1d409SAlexander Shishkin 		goto unlock;
1527bd1d409SAlexander Shishkin 	}
1537bd1d409SAlexander Shishkin 
1547bd1d409SAlexander Shishkin 	ret = count;
1557bd1d409SAlexander Shishkin 	policy_node->first_channel = first;
1567bd1d409SAlexander Shishkin 	policy_node->last_channel = last;
1577bd1d409SAlexander Shishkin 
1587bd1d409SAlexander Shishkin unlock:
1597bd1d409SAlexander Shishkin 	mutex_unlock(&stp_policy_subsys.su_mutex);
1607bd1d409SAlexander Shishkin 
1617bd1d409SAlexander Shishkin 	return ret;
1627bd1d409SAlexander Shishkin }
1637bd1d409SAlexander Shishkin 
1647bd1d409SAlexander Shishkin static void stp_policy_node_release(struct config_item *item)
1657bd1d409SAlexander Shishkin {
1667bd1d409SAlexander Shishkin 	kfree(to_stp_policy_node(item));
1677bd1d409SAlexander Shishkin }
1687bd1d409SAlexander Shishkin 
1697bd1d409SAlexander Shishkin static struct configfs_item_operations stp_policy_node_item_ops = {
1707bd1d409SAlexander Shishkin 	.release		= stp_policy_node_release,
1717bd1d409SAlexander Shishkin };
1727bd1d409SAlexander Shishkin 
1739aa3d651SLinus Torvalds CONFIGFS_ATTR(stp_policy_node_, masters);
1749aa3d651SLinus Torvalds CONFIGFS_ATTR(stp_policy_node_, channels);
1757bd1d409SAlexander Shishkin 
1767bd1d409SAlexander Shishkin static struct configfs_attribute *stp_policy_node_attrs[] = {
1779aa3d651SLinus Torvalds 	&stp_policy_node_attr_masters,
1789aa3d651SLinus Torvalds 	&stp_policy_node_attr_channels,
1797bd1d409SAlexander Shishkin 	NULL,
1807bd1d409SAlexander Shishkin };
1817bd1d409SAlexander Shishkin 
182085006e8SBhumika Goyal static const struct config_item_type stp_policy_type;
183085006e8SBhumika Goyal static const struct config_item_type stp_policy_node_type;
1847bd1d409SAlexander Shishkin 
1857bd1d409SAlexander Shishkin static struct config_group *
1867bd1d409SAlexander Shishkin stp_policy_node_make(struct config_group *group, const char *name)
1877bd1d409SAlexander Shishkin {
1887bd1d409SAlexander Shishkin 	struct stp_policy_node *policy_node, *parent_node;
1897bd1d409SAlexander Shishkin 	struct stp_policy *policy;
1907bd1d409SAlexander Shishkin 
1917bd1d409SAlexander Shishkin 	if (group->cg_item.ci_type == &stp_policy_type) {
1927bd1d409SAlexander Shishkin 		policy = container_of(group, struct stp_policy, group);
1937bd1d409SAlexander Shishkin 	} else {
1947bd1d409SAlexander Shishkin 		parent_node = container_of(group, struct stp_policy_node,
1957bd1d409SAlexander Shishkin 					   group);
1967bd1d409SAlexander Shishkin 		policy = parent_node->policy;
1977bd1d409SAlexander Shishkin 	}
1987bd1d409SAlexander Shishkin 
1997bd1d409SAlexander Shishkin 	if (!policy->stm)
2007bd1d409SAlexander Shishkin 		return ERR_PTR(-ENODEV);
2017bd1d409SAlexander Shishkin 
2027bd1d409SAlexander Shishkin 	policy_node = kzalloc(sizeof(struct stp_policy_node), GFP_KERNEL);
2037bd1d409SAlexander Shishkin 	if (!policy_node)
2047bd1d409SAlexander Shishkin 		return ERR_PTR(-ENOMEM);
2057bd1d409SAlexander Shishkin 
2067bd1d409SAlexander Shishkin 	config_group_init_type_name(&policy_node->group, name,
2077bd1d409SAlexander Shishkin 				    &stp_policy_node_type);
2087bd1d409SAlexander Shishkin 
2097bd1d409SAlexander Shishkin 	policy_node->policy = policy;
2107bd1d409SAlexander Shishkin 
2117bd1d409SAlexander Shishkin 	/* default values for the attributes */
2127bd1d409SAlexander Shishkin 	policy_node->first_master = policy->stm->data->sw_start;
2137bd1d409SAlexander Shishkin 	policy_node->last_master = policy->stm->data->sw_end;
2147bd1d409SAlexander Shishkin 	policy_node->first_channel = 0;
2157bd1d409SAlexander Shishkin 	policy_node->last_channel = policy->stm->data->sw_nchannels - 1;
2167bd1d409SAlexander Shishkin 
2177bd1d409SAlexander Shishkin 	return &policy_node->group;
2187bd1d409SAlexander Shishkin }
2197bd1d409SAlexander Shishkin 
2207bd1d409SAlexander Shishkin static void
2217bd1d409SAlexander Shishkin stp_policy_node_drop(struct config_group *group, struct config_item *item)
2227bd1d409SAlexander Shishkin {
2237bd1d409SAlexander Shishkin 	config_item_put(item);
2247bd1d409SAlexander Shishkin }
2257bd1d409SAlexander Shishkin 
2267bd1d409SAlexander Shishkin static struct configfs_group_operations stp_policy_node_group_ops = {
2277bd1d409SAlexander Shishkin 	.make_group	= stp_policy_node_make,
2287bd1d409SAlexander Shishkin 	.drop_item	= stp_policy_node_drop,
2297bd1d409SAlexander Shishkin };
2307bd1d409SAlexander Shishkin 
231085006e8SBhumika Goyal static const struct config_item_type stp_policy_node_type = {
2327bd1d409SAlexander Shishkin 	.ct_item_ops	= &stp_policy_node_item_ops,
2337bd1d409SAlexander Shishkin 	.ct_group_ops	= &stp_policy_node_group_ops,
2347bd1d409SAlexander Shishkin 	.ct_attrs	= stp_policy_node_attrs,
2357bd1d409SAlexander Shishkin 	.ct_owner	= THIS_MODULE,
2367bd1d409SAlexander Shishkin };
2377bd1d409SAlexander Shishkin 
2387bd1d409SAlexander Shishkin /*
2397bd1d409SAlexander Shishkin  * Root group: policies.
2407bd1d409SAlexander Shishkin  */
2419aa3d651SLinus Torvalds static ssize_t stp_policy_device_show(struct config_item *item,
2427bd1d409SAlexander Shishkin 				      char *page)
2437bd1d409SAlexander Shishkin {
2447bd1d409SAlexander Shishkin 	struct stp_policy *policy = to_stp_policy(item);
2457bd1d409SAlexander Shishkin 	ssize_t count;
2467bd1d409SAlexander Shishkin 
2477bd1d409SAlexander Shishkin 	count = sprintf(page, "%s\n",
2487bd1d409SAlexander Shishkin 			(policy && policy->stm) ?
2497bd1d409SAlexander Shishkin 			policy->stm->data->name :
2507bd1d409SAlexander Shishkin 			"<none>");
2517bd1d409SAlexander Shishkin 
2527bd1d409SAlexander Shishkin 	return count;
2537bd1d409SAlexander Shishkin }
2547bd1d409SAlexander Shishkin 
2559aa3d651SLinus Torvalds CONFIGFS_ATTR_RO(stp_policy_, device);
2569aa3d651SLinus Torvalds 
2579aa3d651SLinus Torvalds static struct configfs_attribute *stp_policy_attrs[] = {
2589aa3d651SLinus Torvalds 	&stp_policy_attr_device,
2599aa3d651SLinus Torvalds 	NULL,
2609aa3d651SLinus Torvalds };
2619aa3d651SLinus Torvalds 
2627bd1d409SAlexander Shishkin void stp_policy_unbind(struct stp_policy *policy)
2637bd1d409SAlexander Shishkin {
2647bd1d409SAlexander Shishkin 	struct stm_device *stm = policy->stm;
2657bd1d409SAlexander Shishkin 
2664c127fd1SAlexander Shishkin 	/*
2674c127fd1SAlexander Shishkin 	 * stp_policy_release() will not call here if the policy is already
2684c127fd1SAlexander Shishkin 	 * unbound; other users should not either, as no link exists between
2694c127fd1SAlexander Shishkin 	 * this policy and anything else in that case
2704c127fd1SAlexander Shishkin 	 */
2717bd1d409SAlexander Shishkin 	if (WARN_ON_ONCE(!policy->stm))
2727bd1d409SAlexander Shishkin 		return;
2737bd1d409SAlexander Shishkin 
2744c127fd1SAlexander Shishkin 	lockdep_assert_held(&stm->policy_mutex);
2757bd1d409SAlexander Shishkin 
2764c127fd1SAlexander Shishkin 	stm->policy = NULL;
2777bd1d409SAlexander Shishkin 	policy->stm = NULL;
2787bd1d409SAlexander Shishkin 
2797bd1d409SAlexander Shishkin 	stm_put_device(stm);
2807bd1d409SAlexander Shishkin }
2817bd1d409SAlexander Shishkin 
2827bd1d409SAlexander Shishkin static void stp_policy_release(struct config_item *item)
2837bd1d409SAlexander Shishkin {
2847bd1d409SAlexander Shishkin 	struct stp_policy *policy = to_stp_policy(item);
2854c127fd1SAlexander Shishkin 	struct stm_device *stm = policy->stm;
2867bd1d409SAlexander Shishkin 
2874c127fd1SAlexander Shishkin 	/* a policy *can* be unbound and still exist in configfs tree */
2884c127fd1SAlexander Shishkin 	if (!stm)
2894c127fd1SAlexander Shishkin 		return;
2904c127fd1SAlexander Shishkin 
2914c127fd1SAlexander Shishkin 	mutex_lock(&stm->policy_mutex);
2927bd1d409SAlexander Shishkin 	stp_policy_unbind(policy);
2934c127fd1SAlexander Shishkin 	mutex_unlock(&stm->policy_mutex);
2944c127fd1SAlexander Shishkin 
2957bd1d409SAlexander Shishkin 	kfree(policy);
2967bd1d409SAlexander Shishkin }
2977bd1d409SAlexander Shishkin 
2987bd1d409SAlexander Shishkin static struct configfs_item_operations stp_policy_item_ops = {
2997bd1d409SAlexander Shishkin 	.release		= stp_policy_release,
3007bd1d409SAlexander Shishkin };
3017bd1d409SAlexander Shishkin 
3027bd1d409SAlexander Shishkin static struct configfs_group_operations stp_policy_group_ops = {
3037bd1d409SAlexander Shishkin 	.make_group	= stp_policy_node_make,
3047bd1d409SAlexander Shishkin };
3057bd1d409SAlexander Shishkin 
306085006e8SBhumika Goyal static const struct config_item_type stp_policy_type = {
3077bd1d409SAlexander Shishkin 	.ct_item_ops	= &stp_policy_item_ops,
3087bd1d409SAlexander Shishkin 	.ct_group_ops	= &stp_policy_group_ops,
3097bd1d409SAlexander Shishkin 	.ct_attrs	= stp_policy_attrs,
3107bd1d409SAlexander Shishkin 	.ct_owner	= THIS_MODULE,
3117bd1d409SAlexander Shishkin };
3127bd1d409SAlexander Shishkin 
3137bd1d409SAlexander Shishkin static struct config_group *
3147bd1d409SAlexander Shishkin stp_policies_make(struct config_group *group, const char *name)
3157bd1d409SAlexander Shishkin {
3167bd1d409SAlexander Shishkin 	struct config_group *ret;
3177bd1d409SAlexander Shishkin 	struct stm_device *stm;
3187bd1d409SAlexander Shishkin 	char *devname, *p;
3197bd1d409SAlexander Shishkin 
3207bd1d409SAlexander Shishkin 	devname = kasprintf(GFP_KERNEL, "%s", name);
3217bd1d409SAlexander Shishkin 	if (!devname)
3227bd1d409SAlexander Shishkin 		return ERR_PTR(-ENOMEM);
3237bd1d409SAlexander Shishkin 
3247bd1d409SAlexander Shishkin 	/*
3257bd1d409SAlexander Shishkin 	 * node must look like <device_name>.<policy_name>, where
32659be422eSAlexander Shishkin 	 * <device_name> is the name of an existing stm device; may
32759be422eSAlexander Shishkin 	 *               contain dots;
32859be422eSAlexander Shishkin 	 * <policy_name> is an arbitrary string; may not contain dots
3297bd1d409SAlexander Shishkin 	 */
33059be422eSAlexander Shishkin 	p = strrchr(devname, '.');
3317bd1d409SAlexander Shishkin 	if (!p) {
3327bd1d409SAlexander Shishkin 		kfree(devname);
3337bd1d409SAlexander Shishkin 		return ERR_PTR(-EINVAL);
3347bd1d409SAlexander Shishkin 	}
3357bd1d409SAlexander Shishkin 
336fb080190SAlexander Shishkin 	*p = '\0';
3377bd1d409SAlexander Shishkin 
3387bd1d409SAlexander Shishkin 	stm = stm_find_device(devname);
3397bd1d409SAlexander Shishkin 	kfree(devname);
3407bd1d409SAlexander Shishkin 
3417bd1d409SAlexander Shishkin 	if (!stm)
3427bd1d409SAlexander Shishkin 		return ERR_PTR(-ENODEV);
3437bd1d409SAlexander Shishkin 
3447bd1d409SAlexander Shishkin 	mutex_lock(&stm->policy_mutex);
3457bd1d409SAlexander Shishkin 	if (stm->policy) {
3467bd1d409SAlexander Shishkin 		ret = ERR_PTR(-EBUSY);
3477bd1d409SAlexander Shishkin 		goto unlock_policy;
3487bd1d409SAlexander Shishkin 	}
3497bd1d409SAlexander Shishkin 
3507bd1d409SAlexander Shishkin 	stm->policy = kzalloc(sizeof(*stm->policy), GFP_KERNEL);
3517bd1d409SAlexander Shishkin 	if (!stm->policy) {
3527bd1d409SAlexander Shishkin 		ret = ERR_PTR(-ENOMEM);
3537bd1d409SAlexander Shishkin 		goto unlock_policy;
3547bd1d409SAlexander Shishkin 	}
3557bd1d409SAlexander Shishkin 
3567bd1d409SAlexander Shishkin 	config_group_init_type_name(&stm->policy->group, name,
3577bd1d409SAlexander Shishkin 				    &stp_policy_type);
3587bd1d409SAlexander Shishkin 	stm->policy->stm = stm;
3597bd1d409SAlexander Shishkin 
3607bd1d409SAlexander Shishkin 	ret = &stm->policy->group;
3617bd1d409SAlexander Shishkin 
3627bd1d409SAlexander Shishkin unlock_policy:
3637bd1d409SAlexander Shishkin 	mutex_unlock(&stm->policy_mutex);
3647bd1d409SAlexander Shishkin 
3657bd1d409SAlexander Shishkin 	if (IS_ERR(ret))
3667bd1d409SAlexander Shishkin 		stm_put_device(stm);
3677bd1d409SAlexander Shishkin 
3687bd1d409SAlexander Shishkin 	return ret;
3697bd1d409SAlexander Shishkin }
3707bd1d409SAlexander Shishkin 
3717bd1d409SAlexander Shishkin static struct configfs_group_operations stp_policies_group_ops = {
3727bd1d409SAlexander Shishkin 	.make_group	= stp_policies_make,
3737bd1d409SAlexander Shishkin };
3747bd1d409SAlexander Shishkin 
375085006e8SBhumika Goyal static const struct config_item_type stp_policies_type = {
3767bd1d409SAlexander Shishkin 	.ct_group_ops	= &stp_policies_group_ops,
3777bd1d409SAlexander Shishkin 	.ct_owner	= THIS_MODULE,
3787bd1d409SAlexander Shishkin };
3797bd1d409SAlexander Shishkin 
3807bd1d409SAlexander Shishkin static struct configfs_subsystem stp_policy_subsys = {
3817bd1d409SAlexander Shishkin 	.su_group = {
3827bd1d409SAlexander Shishkin 		.cg_item = {
3837bd1d409SAlexander Shishkin 			.ci_namebuf	= "stp-policy",
3847bd1d409SAlexander Shishkin 			.ci_type	= &stp_policies_type,
3857bd1d409SAlexander Shishkin 		},
3867bd1d409SAlexander Shishkin 	},
3877bd1d409SAlexander Shishkin };
3887bd1d409SAlexander Shishkin 
3897bd1d409SAlexander Shishkin /*
3907bd1d409SAlexander Shishkin  * Lock the policy mutex from the outside
3917bd1d409SAlexander Shishkin  */
3927bd1d409SAlexander Shishkin static struct stp_policy_node *
3937bd1d409SAlexander Shishkin __stp_policy_node_lookup(struct stp_policy *policy, char *s)
3947bd1d409SAlexander Shishkin {
3957bd1d409SAlexander Shishkin 	struct stp_policy_node *policy_node, *ret;
3967bd1d409SAlexander Shishkin 	struct list_head *head = &policy->group.cg_children;
3977bd1d409SAlexander Shishkin 	struct config_item *item;
3987bd1d409SAlexander Shishkin 	char *start, *end = s;
3997bd1d409SAlexander Shishkin 
4007bd1d409SAlexander Shishkin 	if (list_empty(head))
4017bd1d409SAlexander Shishkin 		return NULL;
4027bd1d409SAlexander Shishkin 
4037bd1d409SAlexander Shishkin 	/* return the first entry if everything else fails */
4047bd1d409SAlexander Shishkin 	item = list_entry(head->next, struct config_item, ci_entry);
4057bd1d409SAlexander Shishkin 	ret = to_stp_policy_node(item);
4067bd1d409SAlexander Shishkin 
4077bd1d409SAlexander Shishkin next:
4087bd1d409SAlexander Shishkin 	for (;;) {
4097bd1d409SAlexander Shishkin 		start = strsep(&end, "/");
4107bd1d409SAlexander Shishkin 		if (!start)
4117bd1d409SAlexander Shishkin 			break;
4127bd1d409SAlexander Shishkin 
4137bd1d409SAlexander Shishkin 		if (!*start)
4147bd1d409SAlexander Shishkin 			continue;
4157bd1d409SAlexander Shishkin 
4167bd1d409SAlexander Shishkin 		list_for_each_entry(item, head, ci_entry) {
4177bd1d409SAlexander Shishkin 			policy_node = to_stp_policy_node(item);
4187bd1d409SAlexander Shishkin 
4197bd1d409SAlexander Shishkin 			if (!strcmp(start,
4207bd1d409SAlexander Shishkin 				    policy_node->group.cg_item.ci_name)) {
4217bd1d409SAlexander Shishkin 				ret = policy_node;
4227bd1d409SAlexander Shishkin 
4237bd1d409SAlexander Shishkin 				if (!end)
4247bd1d409SAlexander Shishkin 					goto out;
4257bd1d409SAlexander Shishkin 
4267bd1d409SAlexander Shishkin 				head = &policy_node->group.cg_children;
4277bd1d409SAlexander Shishkin 				goto next;
4287bd1d409SAlexander Shishkin 			}
4297bd1d409SAlexander Shishkin 		}
4307bd1d409SAlexander Shishkin 		break;
4317bd1d409SAlexander Shishkin 	}
4327bd1d409SAlexander Shishkin 
4337bd1d409SAlexander Shishkin out:
4347bd1d409SAlexander Shishkin 	return ret;
4357bd1d409SAlexander Shishkin }
4367bd1d409SAlexander Shishkin 
4377bd1d409SAlexander Shishkin 
4387bd1d409SAlexander Shishkin struct stp_policy_node *
4397bd1d409SAlexander Shishkin stp_policy_node_lookup(struct stm_device *stm, char *s)
4407bd1d409SAlexander Shishkin {
4417bd1d409SAlexander Shishkin 	struct stp_policy_node *policy_node = NULL;
4427bd1d409SAlexander Shishkin 
4437bd1d409SAlexander Shishkin 	mutex_lock(&stp_policy_subsys.su_mutex);
4447bd1d409SAlexander Shishkin 
4457bd1d409SAlexander Shishkin 	mutex_lock(&stm->policy_mutex);
4467bd1d409SAlexander Shishkin 	if (stm->policy)
4477bd1d409SAlexander Shishkin 		policy_node = __stp_policy_node_lookup(stm->policy, s);
4487bd1d409SAlexander Shishkin 	mutex_unlock(&stm->policy_mutex);
4497bd1d409SAlexander Shishkin 
4507bd1d409SAlexander Shishkin 	if (policy_node)
4517bd1d409SAlexander Shishkin 		config_item_get(&policy_node->group.cg_item);
4527bd1d409SAlexander Shishkin 	mutex_unlock(&stp_policy_subsys.su_mutex);
4537bd1d409SAlexander Shishkin 
4547bd1d409SAlexander Shishkin 	return policy_node;
4557bd1d409SAlexander Shishkin }
4567bd1d409SAlexander Shishkin 
4577bd1d409SAlexander Shishkin void stp_policy_node_put(struct stp_policy_node *policy_node)
4587bd1d409SAlexander Shishkin {
4597bd1d409SAlexander Shishkin 	config_item_put(&policy_node->group.cg_item);
4607bd1d409SAlexander Shishkin }
4617bd1d409SAlexander Shishkin 
4627bd1d409SAlexander Shishkin int __init stp_configfs_init(void)
4637bd1d409SAlexander Shishkin {
4647bd1d409SAlexander Shishkin 	int err;
4657bd1d409SAlexander Shishkin 
4667bd1d409SAlexander Shishkin 	config_group_init(&stp_policy_subsys.su_group);
4677bd1d409SAlexander Shishkin 	mutex_init(&stp_policy_subsys.su_mutex);
4687bd1d409SAlexander Shishkin 	err = configfs_register_subsystem(&stp_policy_subsys);
4697bd1d409SAlexander Shishkin 
4707bd1d409SAlexander Shishkin 	return err;
4717bd1d409SAlexander Shishkin }
4727bd1d409SAlexander Shishkin 
4737bd1d409SAlexander Shishkin void __exit stp_configfs_exit(void)
4747bd1d409SAlexander Shishkin {
4757bd1d409SAlexander Shishkin 	configfs_unregister_subsystem(&stp_policy_subsys);
4767bd1d409SAlexander Shishkin }
477