xref: /openbmc/linux/drivers/hwtracing/stm/policy.c (revision 59be422e)
17bd1d409SAlexander Shishkin /*
27bd1d409SAlexander Shishkin  * System Trace Module (STM) master/channel allocation policy management
37bd1d409SAlexander Shishkin  * Copyright (c) 2014, Intel Corporation.
47bd1d409SAlexander Shishkin  *
57bd1d409SAlexander Shishkin  * This program is free software; you can redistribute it and/or modify it
67bd1d409SAlexander Shishkin  * under the terms and conditions of the GNU General Public License,
77bd1d409SAlexander Shishkin  * version 2, as published by the Free Software Foundation.
87bd1d409SAlexander Shishkin  *
97bd1d409SAlexander Shishkin  * This program is distributed in the hope it will be useful, but WITHOUT
107bd1d409SAlexander Shishkin  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
117bd1d409SAlexander Shishkin  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
127bd1d409SAlexander Shishkin  * more details.
137bd1d409SAlexander Shishkin  *
147bd1d409SAlexander Shishkin  * A master/channel allocation policy allows mapping string identifiers to
157bd1d409SAlexander Shishkin  * master and channel ranges, where allocation can be done.
167bd1d409SAlexander Shishkin  */
177bd1d409SAlexander Shishkin 
187bd1d409SAlexander Shishkin #define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
197bd1d409SAlexander Shishkin 
207bd1d409SAlexander Shishkin #include <linux/types.h>
217bd1d409SAlexander Shishkin #include <linux/module.h>
227bd1d409SAlexander Shishkin #include <linux/device.h>
237bd1d409SAlexander Shishkin #include <linux/configfs.h>
247bd1d409SAlexander Shishkin #include <linux/slab.h>
257bd1d409SAlexander Shishkin #include <linux/stm.h>
267bd1d409SAlexander Shishkin #include "stm.h"
277bd1d409SAlexander Shishkin 
287bd1d409SAlexander Shishkin /*
297bd1d409SAlexander Shishkin  * STP Master/Channel allocation policy configfs layout.
307bd1d409SAlexander Shishkin  */
317bd1d409SAlexander Shishkin 
327bd1d409SAlexander Shishkin struct stp_policy {
337bd1d409SAlexander Shishkin 	struct config_group	group;
347bd1d409SAlexander Shishkin 	struct stm_device	*stm;
357bd1d409SAlexander Shishkin };
367bd1d409SAlexander Shishkin 
377bd1d409SAlexander Shishkin struct stp_policy_node {
387bd1d409SAlexander Shishkin 	struct config_group	group;
397bd1d409SAlexander Shishkin 	struct stp_policy	*policy;
407bd1d409SAlexander Shishkin 	unsigned int		first_master;
417bd1d409SAlexander Shishkin 	unsigned int		last_master;
427bd1d409SAlexander Shishkin 	unsigned int		first_channel;
437bd1d409SAlexander Shishkin 	unsigned int		last_channel;
447bd1d409SAlexander Shishkin };
457bd1d409SAlexander Shishkin 
467bd1d409SAlexander Shishkin static struct configfs_subsystem stp_policy_subsys;
477bd1d409SAlexander Shishkin 
487bd1d409SAlexander Shishkin void stp_policy_node_get_ranges(struct stp_policy_node *policy_node,
497bd1d409SAlexander Shishkin 				unsigned int *mstart, unsigned int *mend,
507bd1d409SAlexander Shishkin 				unsigned int *cstart, unsigned int *cend)
517bd1d409SAlexander Shishkin {
527bd1d409SAlexander Shishkin 	*mstart	= policy_node->first_master;
537bd1d409SAlexander Shishkin 	*mend	= policy_node->last_master;
547bd1d409SAlexander Shishkin 	*cstart	= policy_node->first_channel;
557bd1d409SAlexander Shishkin 	*cend	= policy_node->last_channel;
567bd1d409SAlexander Shishkin }
577bd1d409SAlexander Shishkin 
587bd1d409SAlexander Shishkin static inline char *stp_policy_node_name(struct stp_policy_node *policy_node)
597bd1d409SAlexander Shishkin {
607bd1d409SAlexander Shishkin 	return policy_node->group.cg_item.ci_name ? : "<none>";
617bd1d409SAlexander Shishkin }
627bd1d409SAlexander Shishkin 
637bd1d409SAlexander Shishkin static inline struct stp_policy *to_stp_policy(struct config_item *item)
647bd1d409SAlexander Shishkin {
657bd1d409SAlexander Shishkin 	return item ?
667bd1d409SAlexander Shishkin 		container_of(to_config_group(item), struct stp_policy, group) :
677bd1d409SAlexander Shishkin 		NULL;
687bd1d409SAlexander Shishkin }
697bd1d409SAlexander Shishkin 
707bd1d409SAlexander Shishkin static inline struct stp_policy_node *
717bd1d409SAlexander Shishkin to_stp_policy_node(struct config_item *item)
727bd1d409SAlexander Shishkin {
737bd1d409SAlexander Shishkin 	return item ?
747bd1d409SAlexander Shishkin 		container_of(to_config_group(item), struct stp_policy_node,
757bd1d409SAlexander Shishkin 			     group) :
767bd1d409SAlexander Shishkin 		NULL;
777bd1d409SAlexander Shishkin }
787bd1d409SAlexander Shishkin 
799aa3d651SLinus Torvalds static ssize_t
809aa3d651SLinus Torvalds stp_policy_node_masters_show(struct config_item *item, char *page)
817bd1d409SAlexander Shishkin {
829aa3d651SLinus Torvalds 	struct stp_policy_node *policy_node = to_stp_policy_node(item);
837bd1d409SAlexander Shishkin 	ssize_t count;
847bd1d409SAlexander Shishkin 
857bd1d409SAlexander Shishkin 	count = sprintf(page, "%u %u\n", policy_node->first_master,
867bd1d409SAlexander Shishkin 			policy_node->last_master);
877bd1d409SAlexander Shishkin 
887bd1d409SAlexander Shishkin 	return count;
897bd1d409SAlexander Shishkin }
907bd1d409SAlexander Shishkin 
917bd1d409SAlexander Shishkin static ssize_t
929aa3d651SLinus Torvalds stp_policy_node_masters_store(struct config_item *item, const char *page,
939aa3d651SLinus Torvalds 			      size_t count)
947bd1d409SAlexander Shishkin {
959aa3d651SLinus Torvalds 	struct stp_policy_node *policy_node = to_stp_policy_node(item);
967bd1d409SAlexander Shishkin 	unsigned int first, last;
977bd1d409SAlexander Shishkin 	struct stm_device *stm;
987bd1d409SAlexander Shishkin 	char *p = (char *)page;
997bd1d409SAlexander Shishkin 	ssize_t ret = -ENODEV;
1007bd1d409SAlexander Shishkin 
1017bd1d409SAlexander Shishkin 	if (sscanf(p, "%u %u", &first, &last) != 2)
1027bd1d409SAlexander Shishkin 		return -EINVAL;
1037bd1d409SAlexander Shishkin 
1047bd1d409SAlexander Shishkin 	mutex_lock(&stp_policy_subsys.su_mutex);
1057bd1d409SAlexander Shishkin 	stm = policy_node->policy->stm;
1067bd1d409SAlexander Shishkin 	if (!stm)
1077bd1d409SAlexander Shishkin 		goto unlock;
1087bd1d409SAlexander Shishkin 
1097bd1d409SAlexander Shishkin 	/* must be within [sw_start..sw_end], which is an inclusive range */
1107bd1d409SAlexander Shishkin 	if (first > INT_MAX || last > INT_MAX || first > last ||
1117bd1d409SAlexander Shishkin 	    first < stm->data->sw_start ||
1127bd1d409SAlexander Shishkin 	    last > stm->data->sw_end) {
1137bd1d409SAlexander Shishkin 		ret = -ERANGE;
1147bd1d409SAlexander Shishkin 		goto unlock;
1157bd1d409SAlexander Shishkin 	}
1167bd1d409SAlexander Shishkin 
1177bd1d409SAlexander Shishkin 	ret = count;
1187bd1d409SAlexander Shishkin 	policy_node->first_master = first;
1197bd1d409SAlexander Shishkin 	policy_node->last_master = last;
1207bd1d409SAlexander Shishkin 
1217bd1d409SAlexander Shishkin unlock:
1227bd1d409SAlexander Shishkin 	mutex_unlock(&stp_policy_subsys.su_mutex);
1237bd1d409SAlexander Shishkin 
1247bd1d409SAlexander Shishkin 	return ret;
1257bd1d409SAlexander Shishkin }
1267bd1d409SAlexander Shishkin 
1277bd1d409SAlexander Shishkin static ssize_t
1289aa3d651SLinus Torvalds stp_policy_node_channels_show(struct config_item *item, char *page)
1297bd1d409SAlexander Shishkin {
1309aa3d651SLinus Torvalds 	struct stp_policy_node *policy_node = to_stp_policy_node(item);
1317bd1d409SAlexander Shishkin 	ssize_t count;
1327bd1d409SAlexander Shishkin 
1337bd1d409SAlexander Shishkin 	count = sprintf(page, "%u %u\n", policy_node->first_channel,
1347bd1d409SAlexander Shishkin 			policy_node->last_channel);
1357bd1d409SAlexander Shishkin 
1367bd1d409SAlexander Shishkin 	return count;
1377bd1d409SAlexander Shishkin }
1387bd1d409SAlexander Shishkin 
1397bd1d409SAlexander Shishkin static ssize_t
1409aa3d651SLinus Torvalds stp_policy_node_channels_store(struct config_item *item, const char *page,
1419aa3d651SLinus Torvalds 			       size_t count)
1427bd1d409SAlexander Shishkin {
1439aa3d651SLinus Torvalds 	struct stp_policy_node *policy_node = to_stp_policy_node(item);
1447bd1d409SAlexander Shishkin 	unsigned int first, last;
1457bd1d409SAlexander Shishkin 	struct stm_device *stm;
1467bd1d409SAlexander Shishkin 	char *p = (char *)page;
1477bd1d409SAlexander Shishkin 	ssize_t ret = -ENODEV;
1487bd1d409SAlexander Shishkin 
1497bd1d409SAlexander Shishkin 	if (sscanf(p, "%u %u", &first, &last) != 2)
1507bd1d409SAlexander Shishkin 		return -EINVAL;
1517bd1d409SAlexander Shishkin 
1527bd1d409SAlexander Shishkin 	mutex_lock(&stp_policy_subsys.su_mutex);
1537bd1d409SAlexander Shishkin 	stm = policy_node->policy->stm;
1547bd1d409SAlexander Shishkin 	if (!stm)
1557bd1d409SAlexander Shishkin 		goto unlock;
1567bd1d409SAlexander Shishkin 
1577bd1d409SAlexander Shishkin 	if (first > INT_MAX || last > INT_MAX || first > last ||
1587bd1d409SAlexander Shishkin 	    last >= stm->data->sw_nchannels) {
1597bd1d409SAlexander Shishkin 		ret = -ERANGE;
1607bd1d409SAlexander Shishkin 		goto unlock;
1617bd1d409SAlexander Shishkin 	}
1627bd1d409SAlexander Shishkin 
1637bd1d409SAlexander Shishkin 	ret = count;
1647bd1d409SAlexander Shishkin 	policy_node->first_channel = first;
1657bd1d409SAlexander Shishkin 	policy_node->last_channel = last;
1667bd1d409SAlexander Shishkin 
1677bd1d409SAlexander Shishkin unlock:
1687bd1d409SAlexander Shishkin 	mutex_unlock(&stp_policy_subsys.su_mutex);
1697bd1d409SAlexander Shishkin 
1707bd1d409SAlexander Shishkin 	return ret;
1717bd1d409SAlexander Shishkin }
1727bd1d409SAlexander Shishkin 
1737bd1d409SAlexander Shishkin static void stp_policy_node_release(struct config_item *item)
1747bd1d409SAlexander Shishkin {
1757bd1d409SAlexander Shishkin 	kfree(to_stp_policy_node(item));
1767bd1d409SAlexander Shishkin }
1777bd1d409SAlexander Shishkin 
1787bd1d409SAlexander Shishkin static struct configfs_item_operations stp_policy_node_item_ops = {
1797bd1d409SAlexander Shishkin 	.release		= stp_policy_node_release,
1807bd1d409SAlexander Shishkin };
1817bd1d409SAlexander Shishkin 
1829aa3d651SLinus Torvalds CONFIGFS_ATTR(stp_policy_node_, masters);
1839aa3d651SLinus Torvalds CONFIGFS_ATTR(stp_policy_node_, channels);
1847bd1d409SAlexander Shishkin 
1857bd1d409SAlexander Shishkin static struct configfs_attribute *stp_policy_node_attrs[] = {
1869aa3d651SLinus Torvalds 	&stp_policy_node_attr_masters,
1879aa3d651SLinus Torvalds 	&stp_policy_node_attr_channels,
1887bd1d409SAlexander Shishkin 	NULL,
1897bd1d409SAlexander Shishkin };
1907bd1d409SAlexander Shishkin 
1917bd1d409SAlexander Shishkin static struct config_item_type stp_policy_type;
1927bd1d409SAlexander Shishkin static struct config_item_type stp_policy_node_type;
1937bd1d409SAlexander Shishkin 
1947bd1d409SAlexander Shishkin static struct config_group *
1957bd1d409SAlexander Shishkin stp_policy_node_make(struct config_group *group, const char *name)
1967bd1d409SAlexander Shishkin {
1977bd1d409SAlexander Shishkin 	struct stp_policy_node *policy_node, *parent_node;
1987bd1d409SAlexander Shishkin 	struct stp_policy *policy;
1997bd1d409SAlexander Shishkin 
2007bd1d409SAlexander Shishkin 	if (group->cg_item.ci_type == &stp_policy_type) {
2017bd1d409SAlexander Shishkin 		policy = container_of(group, struct stp_policy, group);
2027bd1d409SAlexander Shishkin 	} else {
2037bd1d409SAlexander Shishkin 		parent_node = container_of(group, struct stp_policy_node,
2047bd1d409SAlexander Shishkin 					   group);
2057bd1d409SAlexander Shishkin 		policy = parent_node->policy;
2067bd1d409SAlexander Shishkin 	}
2077bd1d409SAlexander Shishkin 
2087bd1d409SAlexander Shishkin 	if (!policy->stm)
2097bd1d409SAlexander Shishkin 		return ERR_PTR(-ENODEV);
2107bd1d409SAlexander Shishkin 
2117bd1d409SAlexander Shishkin 	policy_node = kzalloc(sizeof(struct stp_policy_node), GFP_KERNEL);
2127bd1d409SAlexander Shishkin 	if (!policy_node)
2137bd1d409SAlexander Shishkin 		return ERR_PTR(-ENOMEM);
2147bd1d409SAlexander Shishkin 
2157bd1d409SAlexander Shishkin 	config_group_init_type_name(&policy_node->group, name,
2167bd1d409SAlexander Shishkin 				    &stp_policy_node_type);
2177bd1d409SAlexander Shishkin 
2187bd1d409SAlexander Shishkin 	policy_node->policy = policy;
2197bd1d409SAlexander Shishkin 
2207bd1d409SAlexander Shishkin 	/* default values for the attributes */
2217bd1d409SAlexander Shishkin 	policy_node->first_master = policy->stm->data->sw_start;
2227bd1d409SAlexander Shishkin 	policy_node->last_master = policy->stm->data->sw_end;
2237bd1d409SAlexander Shishkin 	policy_node->first_channel = 0;
2247bd1d409SAlexander Shishkin 	policy_node->last_channel = policy->stm->data->sw_nchannels - 1;
2257bd1d409SAlexander Shishkin 
2267bd1d409SAlexander Shishkin 	return &policy_node->group;
2277bd1d409SAlexander Shishkin }
2287bd1d409SAlexander Shishkin 
2297bd1d409SAlexander Shishkin static void
2307bd1d409SAlexander Shishkin stp_policy_node_drop(struct config_group *group, struct config_item *item)
2317bd1d409SAlexander Shishkin {
2327bd1d409SAlexander Shishkin 	config_item_put(item);
2337bd1d409SAlexander Shishkin }
2347bd1d409SAlexander Shishkin 
2357bd1d409SAlexander Shishkin static struct configfs_group_operations stp_policy_node_group_ops = {
2367bd1d409SAlexander Shishkin 	.make_group	= stp_policy_node_make,
2377bd1d409SAlexander Shishkin 	.drop_item	= stp_policy_node_drop,
2387bd1d409SAlexander Shishkin };
2397bd1d409SAlexander Shishkin 
2407bd1d409SAlexander Shishkin static struct config_item_type stp_policy_node_type = {
2417bd1d409SAlexander Shishkin 	.ct_item_ops	= &stp_policy_node_item_ops,
2427bd1d409SAlexander Shishkin 	.ct_group_ops	= &stp_policy_node_group_ops,
2437bd1d409SAlexander Shishkin 	.ct_attrs	= stp_policy_node_attrs,
2447bd1d409SAlexander Shishkin 	.ct_owner	= THIS_MODULE,
2457bd1d409SAlexander Shishkin };
2467bd1d409SAlexander Shishkin 
2477bd1d409SAlexander Shishkin /*
2487bd1d409SAlexander Shishkin  * Root group: policies.
2497bd1d409SAlexander Shishkin  */
2509aa3d651SLinus Torvalds static ssize_t stp_policy_device_show(struct config_item *item,
2517bd1d409SAlexander Shishkin 				      char *page)
2527bd1d409SAlexander Shishkin {
2537bd1d409SAlexander Shishkin 	struct stp_policy *policy = to_stp_policy(item);
2547bd1d409SAlexander Shishkin 	ssize_t count;
2557bd1d409SAlexander Shishkin 
2567bd1d409SAlexander Shishkin 	count = sprintf(page, "%s\n",
2577bd1d409SAlexander Shishkin 			(policy && policy->stm) ?
2587bd1d409SAlexander Shishkin 			policy->stm->data->name :
2597bd1d409SAlexander Shishkin 			"<none>");
2607bd1d409SAlexander Shishkin 
2617bd1d409SAlexander Shishkin 	return count;
2627bd1d409SAlexander Shishkin }
2637bd1d409SAlexander Shishkin 
2649aa3d651SLinus Torvalds CONFIGFS_ATTR_RO(stp_policy_, device);
2659aa3d651SLinus Torvalds 
2669aa3d651SLinus Torvalds static struct configfs_attribute *stp_policy_attrs[] = {
2679aa3d651SLinus Torvalds 	&stp_policy_attr_device,
2689aa3d651SLinus Torvalds 	NULL,
2699aa3d651SLinus Torvalds };
2709aa3d651SLinus Torvalds 
2717bd1d409SAlexander Shishkin void stp_policy_unbind(struct stp_policy *policy)
2727bd1d409SAlexander Shishkin {
2737bd1d409SAlexander Shishkin 	struct stm_device *stm = policy->stm;
2747bd1d409SAlexander Shishkin 
2754c127fd1SAlexander Shishkin 	/*
2764c127fd1SAlexander Shishkin 	 * stp_policy_release() will not call here if the policy is already
2774c127fd1SAlexander Shishkin 	 * unbound; other users should not either, as no link exists between
2784c127fd1SAlexander Shishkin 	 * this policy and anything else in that case
2794c127fd1SAlexander Shishkin 	 */
2807bd1d409SAlexander Shishkin 	if (WARN_ON_ONCE(!policy->stm))
2817bd1d409SAlexander Shishkin 		return;
2827bd1d409SAlexander Shishkin 
2834c127fd1SAlexander Shishkin 	lockdep_assert_held(&stm->policy_mutex);
2847bd1d409SAlexander Shishkin 
2854c127fd1SAlexander Shishkin 	stm->policy = NULL;
2867bd1d409SAlexander Shishkin 	policy->stm = NULL;
2877bd1d409SAlexander Shishkin 
2887bd1d409SAlexander Shishkin 	stm_put_device(stm);
2897bd1d409SAlexander Shishkin }
2907bd1d409SAlexander Shishkin 
2917bd1d409SAlexander Shishkin static void stp_policy_release(struct config_item *item)
2927bd1d409SAlexander Shishkin {
2937bd1d409SAlexander Shishkin 	struct stp_policy *policy = to_stp_policy(item);
2944c127fd1SAlexander Shishkin 	struct stm_device *stm = policy->stm;
2957bd1d409SAlexander Shishkin 
2964c127fd1SAlexander Shishkin 	/* a policy *can* be unbound and still exist in configfs tree */
2974c127fd1SAlexander Shishkin 	if (!stm)
2984c127fd1SAlexander Shishkin 		return;
2994c127fd1SAlexander Shishkin 
3004c127fd1SAlexander Shishkin 	mutex_lock(&stm->policy_mutex);
3017bd1d409SAlexander Shishkin 	stp_policy_unbind(policy);
3024c127fd1SAlexander Shishkin 	mutex_unlock(&stm->policy_mutex);
3034c127fd1SAlexander Shishkin 
3047bd1d409SAlexander Shishkin 	kfree(policy);
3057bd1d409SAlexander Shishkin }
3067bd1d409SAlexander Shishkin 
3077bd1d409SAlexander Shishkin static struct configfs_item_operations stp_policy_item_ops = {
3087bd1d409SAlexander Shishkin 	.release		= stp_policy_release,
3097bd1d409SAlexander Shishkin };
3107bd1d409SAlexander Shishkin 
3117bd1d409SAlexander Shishkin static struct configfs_group_operations stp_policy_group_ops = {
3127bd1d409SAlexander Shishkin 	.make_group	= stp_policy_node_make,
3137bd1d409SAlexander Shishkin };
3147bd1d409SAlexander Shishkin 
3157bd1d409SAlexander Shishkin static struct config_item_type stp_policy_type = {
3167bd1d409SAlexander Shishkin 	.ct_item_ops	= &stp_policy_item_ops,
3177bd1d409SAlexander Shishkin 	.ct_group_ops	= &stp_policy_group_ops,
3187bd1d409SAlexander Shishkin 	.ct_attrs	= stp_policy_attrs,
3197bd1d409SAlexander Shishkin 	.ct_owner	= THIS_MODULE,
3207bd1d409SAlexander Shishkin };
3217bd1d409SAlexander Shishkin 
3227bd1d409SAlexander Shishkin static struct config_group *
3237bd1d409SAlexander Shishkin stp_policies_make(struct config_group *group, const char *name)
3247bd1d409SAlexander Shishkin {
3257bd1d409SAlexander Shishkin 	struct config_group *ret;
3267bd1d409SAlexander Shishkin 	struct stm_device *stm;
3277bd1d409SAlexander Shishkin 	char *devname, *p;
3287bd1d409SAlexander Shishkin 
3297bd1d409SAlexander Shishkin 	devname = kasprintf(GFP_KERNEL, "%s", name);
3307bd1d409SAlexander Shishkin 	if (!devname)
3317bd1d409SAlexander Shishkin 		return ERR_PTR(-ENOMEM);
3327bd1d409SAlexander Shishkin 
3337bd1d409SAlexander Shishkin 	/*
3347bd1d409SAlexander Shishkin 	 * node must look like <device_name>.<policy_name>, where
33559be422eSAlexander Shishkin 	 * <device_name> is the name of an existing stm device; may
33659be422eSAlexander Shishkin 	 *               contain dots;
33759be422eSAlexander Shishkin 	 * <policy_name> is an arbitrary string; may not contain dots
3387bd1d409SAlexander Shishkin 	 */
33959be422eSAlexander Shishkin 	p = strrchr(devname, '.');
3407bd1d409SAlexander Shishkin 	if (!p) {
3417bd1d409SAlexander Shishkin 		kfree(devname);
3427bd1d409SAlexander Shishkin 		return ERR_PTR(-EINVAL);
3437bd1d409SAlexander Shishkin 	}
3447bd1d409SAlexander Shishkin 
3457bd1d409SAlexander Shishkin 	*p++ = '\0';
3467bd1d409SAlexander Shishkin 
3477bd1d409SAlexander Shishkin 	stm = stm_find_device(devname);
3487bd1d409SAlexander Shishkin 	kfree(devname);
3497bd1d409SAlexander Shishkin 
3507bd1d409SAlexander Shishkin 	if (!stm)
3517bd1d409SAlexander Shishkin 		return ERR_PTR(-ENODEV);
3527bd1d409SAlexander Shishkin 
3537bd1d409SAlexander Shishkin 	mutex_lock(&stm->policy_mutex);
3547bd1d409SAlexander Shishkin 	if (stm->policy) {
3557bd1d409SAlexander Shishkin 		ret = ERR_PTR(-EBUSY);
3567bd1d409SAlexander Shishkin 		goto unlock_policy;
3577bd1d409SAlexander Shishkin 	}
3587bd1d409SAlexander Shishkin 
3597bd1d409SAlexander Shishkin 	stm->policy = kzalloc(sizeof(*stm->policy), GFP_KERNEL);
3607bd1d409SAlexander Shishkin 	if (!stm->policy) {
3617bd1d409SAlexander Shishkin 		ret = ERR_PTR(-ENOMEM);
3627bd1d409SAlexander Shishkin 		goto unlock_policy;
3637bd1d409SAlexander Shishkin 	}
3647bd1d409SAlexander Shishkin 
3657bd1d409SAlexander Shishkin 	config_group_init_type_name(&stm->policy->group, name,
3667bd1d409SAlexander Shishkin 				    &stp_policy_type);
3677bd1d409SAlexander Shishkin 	stm->policy->stm = stm;
3687bd1d409SAlexander Shishkin 
3697bd1d409SAlexander Shishkin 	ret = &stm->policy->group;
3707bd1d409SAlexander Shishkin 
3717bd1d409SAlexander Shishkin unlock_policy:
3727bd1d409SAlexander Shishkin 	mutex_unlock(&stm->policy_mutex);
3737bd1d409SAlexander Shishkin 
3747bd1d409SAlexander Shishkin 	if (IS_ERR(ret))
3757bd1d409SAlexander Shishkin 		stm_put_device(stm);
3767bd1d409SAlexander Shishkin 
3777bd1d409SAlexander Shishkin 	return ret;
3787bd1d409SAlexander Shishkin }
3797bd1d409SAlexander Shishkin 
3807bd1d409SAlexander Shishkin static struct configfs_group_operations stp_policies_group_ops = {
3817bd1d409SAlexander Shishkin 	.make_group	= stp_policies_make,
3827bd1d409SAlexander Shishkin };
3837bd1d409SAlexander Shishkin 
3847bd1d409SAlexander Shishkin static struct config_item_type stp_policies_type = {
3857bd1d409SAlexander Shishkin 	.ct_group_ops	= &stp_policies_group_ops,
3867bd1d409SAlexander Shishkin 	.ct_owner	= THIS_MODULE,
3877bd1d409SAlexander Shishkin };
3887bd1d409SAlexander Shishkin 
3897bd1d409SAlexander Shishkin static struct configfs_subsystem stp_policy_subsys = {
3907bd1d409SAlexander Shishkin 	.su_group = {
3917bd1d409SAlexander Shishkin 		.cg_item = {
3927bd1d409SAlexander Shishkin 			.ci_namebuf	= "stp-policy",
3937bd1d409SAlexander Shishkin 			.ci_type	= &stp_policies_type,
3947bd1d409SAlexander Shishkin 		},
3957bd1d409SAlexander Shishkin 	},
3967bd1d409SAlexander Shishkin };
3977bd1d409SAlexander Shishkin 
3987bd1d409SAlexander Shishkin /*
3997bd1d409SAlexander Shishkin  * Lock the policy mutex from the outside
4007bd1d409SAlexander Shishkin  */
4017bd1d409SAlexander Shishkin static struct stp_policy_node *
4027bd1d409SAlexander Shishkin __stp_policy_node_lookup(struct stp_policy *policy, char *s)
4037bd1d409SAlexander Shishkin {
4047bd1d409SAlexander Shishkin 	struct stp_policy_node *policy_node, *ret;
4057bd1d409SAlexander Shishkin 	struct list_head *head = &policy->group.cg_children;
4067bd1d409SAlexander Shishkin 	struct config_item *item;
4077bd1d409SAlexander Shishkin 	char *start, *end = s;
4087bd1d409SAlexander Shishkin 
4097bd1d409SAlexander Shishkin 	if (list_empty(head))
4107bd1d409SAlexander Shishkin 		return NULL;
4117bd1d409SAlexander Shishkin 
4127bd1d409SAlexander Shishkin 	/* return the first entry if everything else fails */
4137bd1d409SAlexander Shishkin 	item = list_entry(head->next, struct config_item, ci_entry);
4147bd1d409SAlexander Shishkin 	ret = to_stp_policy_node(item);
4157bd1d409SAlexander Shishkin 
4167bd1d409SAlexander Shishkin next:
4177bd1d409SAlexander Shishkin 	for (;;) {
4187bd1d409SAlexander Shishkin 		start = strsep(&end, "/");
4197bd1d409SAlexander Shishkin 		if (!start)
4207bd1d409SAlexander Shishkin 			break;
4217bd1d409SAlexander Shishkin 
4227bd1d409SAlexander Shishkin 		if (!*start)
4237bd1d409SAlexander Shishkin 			continue;
4247bd1d409SAlexander Shishkin 
4257bd1d409SAlexander Shishkin 		list_for_each_entry(item, head, ci_entry) {
4267bd1d409SAlexander Shishkin 			policy_node = to_stp_policy_node(item);
4277bd1d409SAlexander Shishkin 
4287bd1d409SAlexander Shishkin 			if (!strcmp(start,
4297bd1d409SAlexander Shishkin 				    policy_node->group.cg_item.ci_name)) {
4307bd1d409SAlexander Shishkin 				ret = policy_node;
4317bd1d409SAlexander Shishkin 
4327bd1d409SAlexander Shishkin 				if (!end)
4337bd1d409SAlexander Shishkin 					goto out;
4347bd1d409SAlexander Shishkin 
4357bd1d409SAlexander Shishkin 				head = &policy_node->group.cg_children;
4367bd1d409SAlexander Shishkin 				goto next;
4377bd1d409SAlexander Shishkin 			}
4387bd1d409SAlexander Shishkin 		}
4397bd1d409SAlexander Shishkin 		break;
4407bd1d409SAlexander Shishkin 	}
4417bd1d409SAlexander Shishkin 
4427bd1d409SAlexander Shishkin out:
4437bd1d409SAlexander Shishkin 	return ret;
4447bd1d409SAlexander Shishkin }
4457bd1d409SAlexander Shishkin 
4467bd1d409SAlexander Shishkin 
4477bd1d409SAlexander Shishkin struct stp_policy_node *
4487bd1d409SAlexander Shishkin stp_policy_node_lookup(struct stm_device *stm, char *s)
4497bd1d409SAlexander Shishkin {
4507bd1d409SAlexander Shishkin 	struct stp_policy_node *policy_node = NULL;
4517bd1d409SAlexander Shishkin 
4527bd1d409SAlexander Shishkin 	mutex_lock(&stp_policy_subsys.su_mutex);
4537bd1d409SAlexander Shishkin 
4547bd1d409SAlexander Shishkin 	mutex_lock(&stm->policy_mutex);
4557bd1d409SAlexander Shishkin 	if (stm->policy)
4567bd1d409SAlexander Shishkin 		policy_node = __stp_policy_node_lookup(stm->policy, s);
4577bd1d409SAlexander Shishkin 	mutex_unlock(&stm->policy_mutex);
4587bd1d409SAlexander Shishkin 
4597bd1d409SAlexander Shishkin 	if (policy_node)
4607bd1d409SAlexander Shishkin 		config_item_get(&policy_node->group.cg_item);
4617bd1d409SAlexander Shishkin 	mutex_unlock(&stp_policy_subsys.su_mutex);
4627bd1d409SAlexander Shishkin 
4637bd1d409SAlexander Shishkin 	return policy_node;
4647bd1d409SAlexander Shishkin }
4657bd1d409SAlexander Shishkin 
4667bd1d409SAlexander Shishkin void stp_policy_node_put(struct stp_policy_node *policy_node)
4677bd1d409SAlexander Shishkin {
4687bd1d409SAlexander Shishkin 	config_item_put(&policy_node->group.cg_item);
4697bd1d409SAlexander Shishkin }
4707bd1d409SAlexander Shishkin 
4717bd1d409SAlexander Shishkin int __init stp_configfs_init(void)
4727bd1d409SAlexander Shishkin {
4737bd1d409SAlexander Shishkin 	int err;
4747bd1d409SAlexander Shishkin 
4757bd1d409SAlexander Shishkin 	config_group_init(&stp_policy_subsys.su_group);
4767bd1d409SAlexander Shishkin 	mutex_init(&stp_policy_subsys.su_mutex);
4777bd1d409SAlexander Shishkin 	err = configfs_register_subsystem(&stp_policy_subsys);
4787bd1d409SAlexander Shishkin 
4797bd1d409SAlexander Shishkin 	return err;
4807bd1d409SAlexander Shishkin }
4817bd1d409SAlexander Shishkin 
4827bd1d409SAlexander Shishkin void __exit stp_configfs_exit(void)
4837bd1d409SAlexander Shishkin {
4847bd1d409SAlexander Shishkin 	configfs_unregister_subsystem(&stp_policy_subsys);
4857bd1d409SAlexander Shishkin }
486