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 * 31425e3c006SAlexander Shishkin stp_policy_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 37125e3c006SAlexander Shishkin static struct configfs_group_operations stp_policy_root_group_ops = { 37225e3c006SAlexander Shishkin .make_group = stp_policy_make, 3737bd1d409SAlexander Shishkin }; 3747bd1d409SAlexander Shishkin 37525e3c006SAlexander Shishkin static const struct config_item_type stp_policy_root_type = { 37625e3c006SAlexander Shishkin .ct_group_ops = &stp_policy_root_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", 38425e3c006SAlexander Shishkin .ci_type = &stp_policy_root_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 { 395cb6102bdSAlexander Shishkin struct stp_policy_node *policy_node, *ret = NULL; 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 next: 4047bd1d409SAlexander Shishkin for (;;) { 4057bd1d409SAlexander Shishkin start = strsep(&end, "/"); 4067bd1d409SAlexander Shishkin if (!start) 4077bd1d409SAlexander Shishkin break; 4087bd1d409SAlexander Shishkin 4097bd1d409SAlexander Shishkin if (!*start) 4107bd1d409SAlexander Shishkin continue; 4117bd1d409SAlexander Shishkin 4127bd1d409SAlexander Shishkin list_for_each_entry(item, head, ci_entry) { 4137bd1d409SAlexander Shishkin policy_node = to_stp_policy_node(item); 4147bd1d409SAlexander Shishkin 4157bd1d409SAlexander Shishkin if (!strcmp(start, 4167bd1d409SAlexander Shishkin policy_node->group.cg_item.ci_name)) { 4177bd1d409SAlexander Shishkin ret = policy_node; 4187bd1d409SAlexander Shishkin 4197bd1d409SAlexander Shishkin if (!end) 4207bd1d409SAlexander Shishkin goto out; 4217bd1d409SAlexander Shishkin 4227bd1d409SAlexander Shishkin head = &policy_node->group.cg_children; 4237bd1d409SAlexander Shishkin goto next; 4247bd1d409SAlexander Shishkin } 4257bd1d409SAlexander Shishkin } 4267bd1d409SAlexander Shishkin break; 4277bd1d409SAlexander Shishkin } 4287bd1d409SAlexander Shishkin 4297bd1d409SAlexander Shishkin out: 4307bd1d409SAlexander Shishkin return ret; 4317bd1d409SAlexander Shishkin } 4327bd1d409SAlexander Shishkin 4337bd1d409SAlexander Shishkin 4347bd1d409SAlexander Shishkin struct stp_policy_node * 4357bd1d409SAlexander Shishkin stp_policy_node_lookup(struct stm_device *stm, char *s) 4367bd1d409SAlexander Shishkin { 4377bd1d409SAlexander Shishkin struct stp_policy_node *policy_node = NULL; 4387bd1d409SAlexander Shishkin 4397bd1d409SAlexander Shishkin mutex_lock(&stp_policy_subsys.su_mutex); 4407bd1d409SAlexander Shishkin 4417bd1d409SAlexander Shishkin mutex_lock(&stm->policy_mutex); 4427bd1d409SAlexander Shishkin if (stm->policy) 4437bd1d409SAlexander Shishkin policy_node = __stp_policy_node_lookup(stm->policy, s); 4447bd1d409SAlexander Shishkin mutex_unlock(&stm->policy_mutex); 4457bd1d409SAlexander Shishkin 4467bd1d409SAlexander Shishkin if (policy_node) 4477bd1d409SAlexander Shishkin config_item_get(&policy_node->group.cg_item); 448cb6102bdSAlexander Shishkin else 4497bd1d409SAlexander Shishkin mutex_unlock(&stp_policy_subsys.su_mutex); 4507bd1d409SAlexander Shishkin 4517bd1d409SAlexander Shishkin return policy_node; 4527bd1d409SAlexander Shishkin } 4537bd1d409SAlexander Shishkin 4547bd1d409SAlexander Shishkin void stp_policy_node_put(struct stp_policy_node *policy_node) 4557bd1d409SAlexander Shishkin { 456cb6102bdSAlexander Shishkin lockdep_assert_held(&stp_policy_subsys.su_mutex); 457cb6102bdSAlexander Shishkin 458cb6102bdSAlexander Shishkin mutex_unlock(&stp_policy_subsys.su_mutex); 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