571 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * System Trace Module (STM) master/channel allocation policy management4 * Copyright (c) 2014, Intel Corporation.5 *6 * A master/channel allocation policy allows mapping string identifiers to7 * master and channel ranges, where allocation can be done.8 */9 10#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt11 12#include <linux/types.h>13#include <linux/module.h>14#include <linux/device.h>15#include <linux/configfs.h>16#include <linux/slab.h>17#include <linux/stm.h>18#include "stm.h"19 20/*21 * STP Master/Channel allocation policy configfs layout.22 */23 24struct stp_policy {25 struct config_group group;26 struct stm_device *stm;27};28 29struct stp_policy_node {30 struct config_group group;31 struct stp_policy *policy;32 unsigned int first_master;33 unsigned int last_master;34 unsigned int first_channel;35 unsigned int last_channel;36 /* this is the one that's exposed to the attributes */37 unsigned char priv[];38};39 40void *stp_policy_node_priv(struct stp_policy_node *pn)41{42 if (!pn)43 return NULL;44 45 return pn->priv;46}47 48static struct configfs_subsystem stp_policy_subsys;49 50void stp_policy_node_get_ranges(struct stp_policy_node *policy_node,51 unsigned int *mstart, unsigned int *mend,52 unsigned int *cstart, unsigned int *cend)53{54 *mstart = policy_node->first_master;55 *mend = policy_node->last_master;56 *cstart = policy_node->first_channel;57 *cend = policy_node->last_channel;58}59 60static inline struct stp_policy *to_stp_policy(struct config_item *item)61{62 return item ?63 container_of(to_config_group(item), struct stp_policy, group) :64 NULL;65}66 67static inline struct stp_policy_node *68to_stp_policy_node(struct config_item *item)69{70 return item ?71 container_of(to_config_group(item), struct stp_policy_node,72 group) :73 NULL;74}75 76void *to_pdrv_policy_node(struct config_item *item)77{78 struct stp_policy_node *node = to_stp_policy_node(item);79 80 return stp_policy_node_priv(node);81}82EXPORT_SYMBOL_GPL(to_pdrv_policy_node);83 84static ssize_t85stp_policy_node_masters_show(struct config_item *item, char *page)86{87 struct stp_policy_node *policy_node = to_stp_policy_node(item);88 ssize_t count;89 90 count = sprintf(page, "%u %u\n", policy_node->first_master,91 policy_node->last_master);92 93 return count;94}95 96static ssize_t97stp_policy_node_masters_store(struct config_item *item, const char *page,98 size_t count)99{100 struct stp_policy_node *policy_node = to_stp_policy_node(item);101 unsigned int first, last;102 struct stm_device *stm;103 char *p = (char *)page;104 ssize_t ret = -ENODEV;105 106 if (sscanf(p, "%u %u", &first, &last) != 2)107 return -EINVAL;108 109 mutex_lock(&stp_policy_subsys.su_mutex);110 stm = policy_node->policy->stm;111 if (!stm)112 goto unlock;113 114 /* must be within [sw_start..sw_end], which is an inclusive range */115 if (first > last || first < stm->data->sw_start ||116 last > stm->data->sw_end) {117 ret = -ERANGE;118 goto unlock;119 }120 121 ret = count;122 policy_node->first_master = first;123 policy_node->last_master = last;124 125unlock:126 mutex_unlock(&stp_policy_subsys.su_mutex);127 128 return ret;129}130 131static ssize_t132stp_policy_node_channels_show(struct config_item *item, char *page)133{134 struct stp_policy_node *policy_node = to_stp_policy_node(item);135 ssize_t count;136 137 count = sprintf(page, "%u %u\n", policy_node->first_channel,138 policy_node->last_channel);139 140 return count;141}142 143static ssize_t144stp_policy_node_channels_store(struct config_item *item, const char *page,145 size_t count)146{147 struct stp_policy_node *policy_node = to_stp_policy_node(item);148 unsigned int first, last;149 struct stm_device *stm;150 char *p = (char *)page;151 ssize_t ret = -ENODEV;152 153 if (sscanf(p, "%u %u", &first, &last) != 2)154 return -EINVAL;155 156 mutex_lock(&stp_policy_subsys.su_mutex);157 stm = policy_node->policy->stm;158 if (!stm)159 goto unlock;160 161 if (first > INT_MAX || last > INT_MAX || first > last ||162 last >= stm->data->sw_nchannels) {163 ret = -ERANGE;164 goto unlock;165 }166 167 ret = count;168 policy_node->first_channel = first;169 policy_node->last_channel = last;170 171unlock:172 mutex_unlock(&stp_policy_subsys.su_mutex);173 174 return ret;175}176 177static void stp_policy_node_release(struct config_item *item)178{179 struct stp_policy_node *node = to_stp_policy_node(item);180 181 kfree(node);182}183 184static struct configfs_item_operations stp_policy_node_item_ops = {185 .release = stp_policy_node_release,186};187 188CONFIGFS_ATTR(stp_policy_node_, masters);189CONFIGFS_ATTR(stp_policy_node_, channels);190 191static struct configfs_attribute *stp_policy_node_attrs[] = {192 &stp_policy_node_attr_masters,193 &stp_policy_node_attr_channels,194 NULL,195};196 197static const struct config_item_type stp_policy_type;198static const struct config_item_type stp_policy_node_type;199 200const struct config_item_type *201get_policy_node_type(struct configfs_attribute **attrs)202{203 struct config_item_type *type;204 struct configfs_attribute **merged;205 206 type = kmemdup(&stp_policy_node_type, sizeof(stp_policy_node_type),207 GFP_KERNEL);208 if (!type)209 return NULL;210 211 merged = memcat_p(stp_policy_node_attrs, attrs);212 if (!merged) {213 kfree(type);214 return NULL;215 }216 217 type->ct_attrs = merged;218 219 return type;220}221 222static struct config_group *223stp_policy_node_make(struct config_group *group, const char *name)224{225 const struct config_item_type *type = &stp_policy_node_type;226 struct stp_policy_node *policy_node, *parent_node;227 const struct stm_protocol_driver *pdrv;228 struct stp_policy *policy;229 230 if (group->cg_item.ci_type == &stp_policy_type) {231 policy = container_of(group, struct stp_policy, group);232 } else {233 parent_node = container_of(group, struct stp_policy_node,234 group);235 policy = parent_node->policy;236 }237 238 if (!policy->stm)239 return ERR_PTR(-ENODEV);240 241 pdrv = policy->stm->pdrv;242 policy_node =243 kzalloc(offsetof(struct stp_policy_node, priv[pdrv->priv_sz]),244 GFP_KERNEL);245 if (!policy_node)246 return ERR_PTR(-ENOMEM);247 248 if (pdrv->policy_node_init)249 pdrv->policy_node_init((void *)policy_node->priv);250 251 if (policy->stm->pdrv_node_type)252 type = policy->stm->pdrv_node_type;253 254 config_group_init_type_name(&policy_node->group, name, type);255 256 policy_node->policy = policy;257 258 /* default values for the attributes */259 policy_node->first_master = policy->stm->data->sw_start;260 policy_node->last_master = policy->stm->data->sw_end;261 policy_node->first_channel = 0;262 policy_node->last_channel = policy->stm->data->sw_nchannels - 1;263 264 return &policy_node->group;265}266 267static void268stp_policy_node_drop(struct config_group *group, struct config_item *item)269{270 config_item_put(item);271}272 273static struct configfs_group_operations stp_policy_node_group_ops = {274 .make_group = stp_policy_node_make,275 .drop_item = stp_policy_node_drop,276};277 278static const struct config_item_type stp_policy_node_type = {279 .ct_item_ops = &stp_policy_node_item_ops,280 .ct_group_ops = &stp_policy_node_group_ops,281 .ct_attrs = stp_policy_node_attrs,282 .ct_owner = THIS_MODULE,283};284 285/*286 * Root group: policies.287 */288static ssize_t stp_policy_device_show(struct config_item *item,289 char *page)290{291 struct stp_policy *policy = to_stp_policy(item);292 ssize_t count;293 294 count = sprintf(page, "%s\n",295 (policy && policy->stm) ?296 policy->stm->data->name :297 "<none>");298 299 return count;300}301 302CONFIGFS_ATTR_RO(stp_policy_, device);303 304static ssize_t stp_policy_protocol_show(struct config_item *item,305 char *page)306{307 struct stp_policy *policy = to_stp_policy(item);308 ssize_t count;309 310 count = sprintf(page, "%s\n",311 (policy && policy->stm) ?312 policy->stm->pdrv->name :313 "<none>");314 315 return count;316}317 318CONFIGFS_ATTR_RO(stp_policy_, protocol);319 320static struct configfs_attribute *stp_policy_attrs[] = {321 &stp_policy_attr_device,322 &stp_policy_attr_protocol,323 NULL,324};325 326void stp_policy_unbind(struct stp_policy *policy)327{328 struct stm_device *stm = policy->stm;329 330 /*331 * stp_policy_release() will not call here if the policy is already332 * unbound; other users should not either, as no link exists between333 * this policy and anything else in that case334 */335 if (WARN_ON_ONCE(!policy->stm))336 return;337 338 lockdep_assert_held(&stm->policy_mutex);339 340 stm->policy = NULL;341 policy->stm = NULL;342 343 /*344 * Drop the reference on the protocol driver and lose the link.345 */346 stm_put_protocol(stm->pdrv);347 stm->pdrv = NULL;348 stm_put_device(stm);349}350 351static void stp_policy_release(struct config_item *item)352{353 struct stp_policy *policy = to_stp_policy(item);354 struct stm_device *stm = policy->stm;355 356 /* a policy *can* be unbound and still exist in configfs tree */357 if (!stm)358 return;359 360 mutex_lock(&stm->policy_mutex);361 stp_policy_unbind(policy);362 mutex_unlock(&stm->policy_mutex);363 364 kfree(policy);365}366 367static struct configfs_item_operations stp_policy_item_ops = {368 .release = stp_policy_release,369};370 371static struct configfs_group_operations stp_policy_group_ops = {372 .make_group = stp_policy_node_make,373};374 375static const struct config_item_type stp_policy_type = {376 .ct_item_ops = &stp_policy_item_ops,377 .ct_group_ops = &stp_policy_group_ops,378 .ct_attrs = stp_policy_attrs,379 .ct_owner = THIS_MODULE,380};381 382static struct config_group *383stp_policy_make(struct config_group *group, const char *name)384{385 const struct config_item_type *pdrv_node_type;386 const struct stm_protocol_driver *pdrv;387 char *devname, *proto, *p;388 struct config_group *ret;389 struct stm_device *stm;390 int err;391 392 devname = kasprintf(GFP_KERNEL, "%s", name);393 if (!devname)394 return ERR_PTR(-ENOMEM);395 396 /*397 * node must look like <device_name>.<policy_name>, where398 * <device_name> is the name of an existing stm device; may399 * contain dots;400 * <policy_name> is an arbitrary string; may not contain dots401 * <device_name>:<protocol_name>.<policy_name>402 */403 p = strrchr(devname, '.');404 if (!p) {405 kfree(devname);406 return ERR_PTR(-EINVAL);407 }408 409 *p = '\0';410 411 /*412 * look for ":<protocol_name>":413 * + no protocol suffix: fall back to whatever is available;414 * + unknown protocol: fail the whole thing415 */416 proto = strrchr(devname, ':');417 if (proto)418 *proto++ = '\0';419 420 stm = stm_find_device(devname);421 if (!stm) {422 kfree(devname);423 return ERR_PTR(-ENODEV);424 }425 426 err = stm_lookup_protocol(proto, &pdrv, &pdrv_node_type);427 kfree(devname);428 429 if (err) {430 stm_put_device(stm);431 return ERR_PTR(-ENODEV);432 }433 434 mutex_lock(&stm->policy_mutex);435 if (stm->policy) {436 ret = ERR_PTR(-EBUSY);437 goto unlock_policy;438 }439 440 stm->policy = kzalloc(sizeof(*stm->policy), GFP_KERNEL);441 if (!stm->policy) {442 ret = ERR_PTR(-ENOMEM);443 goto unlock_policy;444 }445 446 config_group_init_type_name(&stm->policy->group, name,447 &stp_policy_type);448 449 stm->pdrv = pdrv;450 stm->pdrv_node_type = pdrv_node_type;451 stm->policy->stm = stm;452 ret = &stm->policy->group;453 454unlock_policy:455 mutex_unlock(&stm->policy_mutex);456 457 if (IS_ERR(ret)) {458 /*459 * pdrv and stm->pdrv at this point can be quite different,460 * and only one of them needs to be 'put'461 */462 stm_put_protocol(pdrv);463 stm_put_device(stm);464 }465 466 return ret;467}468 469static struct configfs_group_operations stp_policy_root_group_ops = {470 .make_group = stp_policy_make,471};472 473static const struct config_item_type stp_policy_root_type = {474 .ct_group_ops = &stp_policy_root_group_ops,475 .ct_owner = THIS_MODULE,476};477 478static struct configfs_subsystem stp_policy_subsys = {479 .su_group = {480 .cg_item = {481 .ci_namebuf = "stp-policy",482 .ci_type = &stp_policy_root_type,483 },484 },485};486 487/*488 * Lock the policy mutex from the outside489 */490static struct stp_policy_node *491__stp_policy_node_lookup(struct stp_policy *policy, char *s)492{493 struct stp_policy_node *policy_node, *ret = NULL;494 struct list_head *head = &policy->group.cg_children;495 struct config_item *item;496 char *start, *end = s;497 498 if (list_empty(head))499 return NULL;500 501next:502 for (;;) {503 start = strsep(&end, "/");504 if (!start)505 break;506 507 if (!*start)508 continue;509 510 list_for_each_entry(item, head, ci_entry) {511 policy_node = to_stp_policy_node(item);512 513 if (!strcmp(start,514 policy_node->group.cg_item.ci_name)) {515 ret = policy_node;516 517 if (!end)518 goto out;519 520 head = &policy_node->group.cg_children;521 goto next;522 }523 }524 break;525 }526 527out:528 return ret;529}530 531 532struct stp_policy_node *533stp_policy_node_lookup(struct stm_device *stm, char *s)534{535 struct stp_policy_node *policy_node = NULL;536 537 mutex_lock(&stp_policy_subsys.su_mutex);538 539 mutex_lock(&stm->policy_mutex);540 if (stm->policy)541 policy_node = __stp_policy_node_lookup(stm->policy, s);542 mutex_unlock(&stm->policy_mutex);543 544 if (policy_node)545 config_item_get(&policy_node->group.cg_item);546 else547 mutex_unlock(&stp_policy_subsys.su_mutex);548 549 return policy_node;550}551 552void stp_policy_node_put(struct stp_policy_node *policy_node)553{554 lockdep_assert_held(&stp_policy_subsys.su_mutex);555 556 mutex_unlock(&stp_policy_subsys.su_mutex);557 config_item_put(&policy_node->group.cg_item);558}559 560int __init stp_configfs_init(void)561{562 config_group_init(&stp_policy_subsys.su_group);563 mutex_init(&stp_policy_subsys.su_mutex);564 return configfs_register_subsystem(&stp_policy_subsys);565}566 567void __exit stp_configfs_exit(void)568{569 configfs_unregister_subsystem(&stp_policy_subsys);570}571