185e2414cSMike Leach // SPDX-License-Identifier: GPL-2.0
285e2414cSMike Leach /*
385e2414cSMike Leach * Copyright (c) 2020 Linaro Limited, All rights reserved.
485e2414cSMike Leach * Author: Mike Leach <mike.leach@linaro.org>
585e2414cSMike Leach */
685e2414cSMike Leach
785e2414cSMike Leach #include <linux/platform_device.h>
8212b5d2dSJian Cai #include <linux/slab.h>
985e2414cSMike Leach
1085e2414cSMike Leach #include "coresight-config.h"
1194d2bac5SMike Leach #include "coresight-etm-perf.h"
1285e2414cSMike Leach #include "coresight-syscfg.h"
13a13d5a24SMike Leach #include "coresight-syscfg-configfs.h"
1485e2414cSMike Leach
1585e2414cSMike Leach /*
1685e2414cSMike Leach * cscfg_ API manages configurations and features for the entire coresight
1785e2414cSMike Leach * infrastructure.
1885e2414cSMike Leach *
1985e2414cSMike Leach * It allows the loading of configurations and features, and loads these into
2085e2414cSMike Leach * coresight devices as appropriate.
2185e2414cSMike Leach */
2285e2414cSMike Leach
2385e2414cSMike Leach /* protect the cscsg_data and device */
2485e2414cSMike Leach static DEFINE_MUTEX(cscfg_mutex);
2585e2414cSMike Leach
2685e2414cSMike Leach /* only one of these */
2785e2414cSMike Leach static struct cscfg_manager *cscfg_mgr;
2885e2414cSMike Leach
2985e2414cSMike Leach /* load features and configuations into the lists */
3085e2414cSMike Leach
3142ff700fSMike Leach /* get name feature instance from a coresight device list of features */
3242ff700fSMike Leach static struct cscfg_feature_csdev *
cscfg_get_feat_csdev(struct coresight_device * csdev,const char * name)3342ff700fSMike Leach cscfg_get_feat_csdev(struct coresight_device *csdev, const char *name)
3442ff700fSMike Leach {
3542ff700fSMike Leach struct cscfg_feature_csdev *feat_csdev = NULL;
3642ff700fSMike Leach
3742ff700fSMike Leach list_for_each_entry(feat_csdev, &csdev->feature_csdev_list, node) {
3842ff700fSMike Leach if (strcmp(feat_csdev->feat_desc->name, name) == 0)
3942ff700fSMike Leach return feat_csdev;
4042ff700fSMike Leach }
4142ff700fSMike Leach return NULL;
4242ff700fSMike Leach }
4342ff700fSMike Leach
4442ff700fSMike Leach /* allocate the device config instance - with max number of used features */
4542ff700fSMike Leach static struct cscfg_config_csdev *
cscfg_alloc_csdev_cfg(struct coresight_device * csdev,int nr_feats)4642ff700fSMike Leach cscfg_alloc_csdev_cfg(struct coresight_device *csdev, int nr_feats)
4742ff700fSMike Leach {
4842ff700fSMike Leach struct cscfg_config_csdev *config_csdev = NULL;
4942ff700fSMike Leach struct device *dev = csdev->dev.parent;
5042ff700fSMike Leach
5142ff700fSMike Leach /* this is being allocated using the devm for the coresight device */
5242ff700fSMike Leach config_csdev = devm_kzalloc(dev,
5342ff700fSMike Leach offsetof(struct cscfg_config_csdev, feats_csdev[nr_feats]),
5442ff700fSMike Leach GFP_KERNEL);
5542ff700fSMike Leach if (!config_csdev)
5642ff700fSMike Leach return NULL;
5742ff700fSMike Leach
5842ff700fSMike Leach config_csdev->csdev = csdev;
5942ff700fSMike Leach return config_csdev;
6042ff700fSMike Leach }
6142ff700fSMike Leach
6242ff700fSMike Leach /* Load a config into a device if there are any feature matches between config and device */
cscfg_add_csdev_cfg(struct coresight_device * csdev,struct cscfg_config_desc * config_desc)6342ff700fSMike Leach static int cscfg_add_csdev_cfg(struct coresight_device *csdev,
6442ff700fSMike Leach struct cscfg_config_desc *config_desc)
6542ff700fSMike Leach {
6642ff700fSMike Leach struct cscfg_config_csdev *config_csdev = NULL;
6742ff700fSMike Leach struct cscfg_feature_csdev *feat_csdev;
6842ff700fSMike Leach unsigned long flags;
6942ff700fSMike Leach int i;
7042ff700fSMike Leach
7142ff700fSMike Leach /* look at each required feature and see if it matches any feature on the device */
7242ff700fSMike Leach for (i = 0; i < config_desc->nr_feat_refs; i++) {
7342ff700fSMike Leach /* look for a matching name */
7442ff700fSMike Leach feat_csdev = cscfg_get_feat_csdev(csdev, config_desc->feat_ref_names[i]);
7542ff700fSMike Leach if (feat_csdev) {
7642ff700fSMike Leach /*
7742ff700fSMike Leach * At least one feature on this device matches the config
7842ff700fSMike Leach * add a config instance to the device and a reference to the feature.
7942ff700fSMike Leach */
8042ff700fSMike Leach if (!config_csdev) {
8142ff700fSMike Leach config_csdev = cscfg_alloc_csdev_cfg(csdev,
8242ff700fSMike Leach config_desc->nr_feat_refs);
8342ff700fSMike Leach if (!config_csdev)
8442ff700fSMike Leach return -ENOMEM;
8542ff700fSMike Leach config_csdev->config_desc = config_desc;
8642ff700fSMike Leach }
8742ff700fSMike Leach config_csdev->feats_csdev[config_csdev->nr_feat++] = feat_csdev;
8842ff700fSMike Leach }
8942ff700fSMike Leach }
9042ff700fSMike Leach /* if matched features, add config to device.*/
9142ff700fSMike Leach if (config_csdev) {
9242ff700fSMike Leach spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
9342ff700fSMike Leach list_add(&config_csdev->node, &csdev->config_csdev_list);
9442ff700fSMike Leach spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
9542ff700fSMike Leach }
9642ff700fSMike Leach
9742ff700fSMike Leach return 0;
9842ff700fSMike Leach }
9942ff700fSMike Leach
10042ff700fSMike Leach /*
10142ff700fSMike Leach * Add the config to the set of registered devices - call with mutex locked.
10242ff700fSMike Leach * Iterates through devices - any device that matches one or more of the
10342ff700fSMike Leach * configuration features will load it, the others will ignore it.
10442ff700fSMike Leach */
cscfg_add_cfg_to_csdevs(struct cscfg_config_desc * config_desc)10542ff700fSMike Leach static int cscfg_add_cfg_to_csdevs(struct cscfg_config_desc *config_desc)
10642ff700fSMike Leach {
10742ff700fSMike Leach struct cscfg_registered_csdev *csdev_item;
10842ff700fSMike Leach int err;
10942ff700fSMike Leach
11042ff700fSMike Leach list_for_each_entry(csdev_item, &cscfg_mgr->csdev_desc_list, item) {
11142ff700fSMike Leach err = cscfg_add_csdev_cfg(csdev_item->csdev, config_desc);
11242ff700fSMike Leach if (err)
11342ff700fSMike Leach return err;
11442ff700fSMike Leach }
11542ff700fSMike Leach return 0;
11642ff700fSMike Leach }
11742ff700fSMike Leach
11842ff700fSMike Leach /*
11942ff700fSMike Leach * Allocate a feature object for load into a csdev.
12042ff700fSMike Leach * memory allocated using the csdev->dev object using devm managed allocator.
12142ff700fSMike Leach */
12242ff700fSMike Leach static struct cscfg_feature_csdev *
cscfg_alloc_csdev_feat(struct coresight_device * csdev,struct cscfg_feature_desc * feat_desc)12342ff700fSMike Leach cscfg_alloc_csdev_feat(struct coresight_device *csdev, struct cscfg_feature_desc *feat_desc)
12442ff700fSMike Leach {
12542ff700fSMike Leach struct cscfg_feature_csdev *feat_csdev = NULL;
12642ff700fSMike Leach struct device *dev = csdev->dev.parent;
12742ff700fSMike Leach int i;
12842ff700fSMike Leach
12942ff700fSMike Leach feat_csdev = devm_kzalloc(dev, sizeof(struct cscfg_feature_csdev), GFP_KERNEL);
13042ff700fSMike Leach if (!feat_csdev)
13142ff700fSMike Leach return NULL;
13242ff700fSMike Leach
13342ff700fSMike Leach /* parameters are optional - could be 0 */
13442ff700fSMike Leach feat_csdev->nr_params = feat_desc->nr_params;
13542ff700fSMike Leach
13642ff700fSMike Leach /*
13742ff700fSMike Leach * if we need parameters, zero alloc the space here, the load routine in
13842ff700fSMike Leach * the csdev device driver will fill out some information according to
13942ff700fSMike Leach * feature descriptor.
14042ff700fSMike Leach */
14142ff700fSMike Leach if (feat_csdev->nr_params) {
14242ff700fSMike Leach feat_csdev->params_csdev = devm_kcalloc(dev, feat_csdev->nr_params,
14342ff700fSMike Leach sizeof(struct cscfg_parameter_csdev),
14442ff700fSMike Leach GFP_KERNEL);
14542ff700fSMike Leach if (!feat_csdev->params_csdev)
14642ff700fSMike Leach return NULL;
14742ff700fSMike Leach
14842ff700fSMike Leach /*
14942ff700fSMike Leach * fill in the feature reference in the param - other fields
15042ff700fSMike Leach * handled by loader in csdev.
15142ff700fSMike Leach */
15242ff700fSMike Leach for (i = 0; i < feat_csdev->nr_params; i++)
15342ff700fSMike Leach feat_csdev->params_csdev[i].feat_csdev = feat_csdev;
15442ff700fSMike Leach }
15542ff700fSMike Leach
15642ff700fSMike Leach /*
15742ff700fSMike Leach * Always have registers to program - again the load routine in csdev device
15842ff700fSMike Leach * will fill out according to feature descriptor and device requirements.
15942ff700fSMike Leach */
16042ff700fSMike Leach feat_csdev->nr_regs = feat_desc->nr_regs;
16142ff700fSMike Leach feat_csdev->regs_csdev = devm_kcalloc(dev, feat_csdev->nr_regs,
16242ff700fSMike Leach sizeof(struct cscfg_regval_csdev),
16342ff700fSMike Leach GFP_KERNEL);
16442ff700fSMike Leach if (!feat_csdev->regs_csdev)
16542ff700fSMike Leach return NULL;
16642ff700fSMike Leach
16742ff700fSMike Leach /* load the feature default values */
16842ff700fSMike Leach feat_csdev->feat_desc = feat_desc;
16942ff700fSMike Leach feat_csdev->csdev = csdev;
17042ff700fSMike Leach
17142ff700fSMike Leach return feat_csdev;
17242ff700fSMike Leach }
17342ff700fSMike Leach
17442ff700fSMike Leach /* load one feature into one coresight device */
cscfg_load_feat_csdev(struct coresight_device * csdev,struct cscfg_feature_desc * feat_desc,struct cscfg_csdev_feat_ops * ops)17542ff700fSMike Leach static int cscfg_load_feat_csdev(struct coresight_device *csdev,
17642ff700fSMike Leach struct cscfg_feature_desc *feat_desc,
17742ff700fSMike Leach struct cscfg_csdev_feat_ops *ops)
17842ff700fSMike Leach {
17942ff700fSMike Leach struct cscfg_feature_csdev *feat_csdev;
18042ff700fSMike Leach unsigned long flags;
18142ff700fSMike Leach int err;
18242ff700fSMike Leach
18342ff700fSMike Leach if (!ops->load_feat)
18442ff700fSMike Leach return -EINVAL;
18542ff700fSMike Leach
18642ff700fSMike Leach feat_csdev = cscfg_alloc_csdev_feat(csdev, feat_desc);
18742ff700fSMike Leach if (!feat_csdev)
18842ff700fSMike Leach return -ENOMEM;
18942ff700fSMike Leach
19042ff700fSMike Leach /* load the feature into the device */
19142ff700fSMike Leach err = ops->load_feat(csdev, feat_csdev);
19242ff700fSMike Leach if (err)
19342ff700fSMike Leach return err;
19442ff700fSMike Leach
195f53e93acSMike Leach /* add to internal csdev feature list & initialise using reset call */
196f53e93acSMike Leach cscfg_reset_feat(feat_csdev);
19742ff700fSMike Leach spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
19842ff700fSMike Leach list_add(&feat_csdev->node, &csdev->feature_csdev_list);
19942ff700fSMike Leach spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
20042ff700fSMike Leach
20142ff700fSMike Leach return 0;
20242ff700fSMike Leach }
20342ff700fSMike Leach
20442ff700fSMike Leach /*
20542ff700fSMike Leach * Add feature to any matching devices - call with mutex locked.
20642ff700fSMike Leach * Iterates through devices - any device that matches the feature will be
20742ff700fSMike Leach * called to load it.
20842ff700fSMike Leach */
cscfg_add_feat_to_csdevs(struct cscfg_feature_desc * feat_desc)20942ff700fSMike Leach static int cscfg_add_feat_to_csdevs(struct cscfg_feature_desc *feat_desc)
21042ff700fSMike Leach {
21142ff700fSMike Leach struct cscfg_registered_csdev *csdev_item;
21242ff700fSMike Leach int err;
21342ff700fSMike Leach
21442ff700fSMike Leach list_for_each_entry(csdev_item, &cscfg_mgr->csdev_desc_list, item) {
21542ff700fSMike Leach if (csdev_item->match_flags & feat_desc->match_flags) {
21642ff700fSMike Leach err = cscfg_load_feat_csdev(csdev_item->csdev, feat_desc, &csdev_item->ops);
21742ff700fSMike Leach if (err)
21842ff700fSMike Leach return err;
21942ff700fSMike Leach }
22042ff700fSMike Leach }
22142ff700fSMike Leach return 0;
22242ff700fSMike Leach }
22342ff700fSMike Leach
22485e2414cSMike Leach /* check feature list for a named feature - call with mutex locked. */
cscfg_match_list_feat(const char * name)22585e2414cSMike Leach static bool cscfg_match_list_feat(const char *name)
22685e2414cSMike Leach {
22785e2414cSMike Leach struct cscfg_feature_desc *feat_desc;
22885e2414cSMike Leach
22985e2414cSMike Leach list_for_each_entry(feat_desc, &cscfg_mgr->feat_desc_list, item) {
23085e2414cSMike Leach if (strcmp(feat_desc->name, name) == 0)
23185e2414cSMike Leach return true;
23285e2414cSMike Leach }
23385e2414cSMike Leach return false;
23485e2414cSMike Leach }
23585e2414cSMike Leach
23685e2414cSMike Leach /* check all feat needed for cfg are in the list - call with mutex locked. */
cscfg_check_feat_for_cfg(struct cscfg_config_desc * config_desc)23785e2414cSMike Leach static int cscfg_check_feat_for_cfg(struct cscfg_config_desc *config_desc)
23885e2414cSMike Leach {
23985e2414cSMike Leach int i;
24085e2414cSMike Leach
24185e2414cSMike Leach for (i = 0; i < config_desc->nr_feat_refs; i++)
24285e2414cSMike Leach if (!cscfg_match_list_feat(config_desc->feat_ref_names[i]))
24385e2414cSMike Leach return -EINVAL;
24485e2414cSMike Leach return 0;
24585e2414cSMike Leach }
24685e2414cSMike Leach
24785e2414cSMike Leach /*
24885e2414cSMike Leach * load feature - add to feature list.
24985e2414cSMike Leach */
cscfg_load_feat(struct cscfg_feature_desc * feat_desc)25085e2414cSMike Leach static int cscfg_load_feat(struct cscfg_feature_desc *feat_desc)
25185e2414cSMike Leach {
25242ff700fSMike Leach int err;
25302bd588eSMike Leach struct cscfg_feature_desc *feat_desc_exist;
25402bd588eSMike Leach
25502bd588eSMike Leach /* new feature must have unique name */
25602bd588eSMike Leach list_for_each_entry(feat_desc_exist, &cscfg_mgr->feat_desc_list, item) {
25702bd588eSMike Leach if (!strcmp(feat_desc_exist->name, feat_desc->name))
25802bd588eSMike Leach return -EEXIST;
25902bd588eSMike Leach }
26085e2414cSMike Leach
26142ff700fSMike Leach /* add feature to any matching registered devices */
26242ff700fSMike Leach err = cscfg_add_feat_to_csdevs(feat_desc);
26342ff700fSMike Leach if (err)
26442ff700fSMike Leach return err;
26542ff700fSMike Leach
26642ff700fSMike Leach list_add(&feat_desc->item, &cscfg_mgr->feat_desc_list);
26785e2414cSMike Leach return 0;
26885e2414cSMike Leach }
26985e2414cSMike Leach
27085e2414cSMike Leach /*
27185e2414cSMike Leach * load config into the system - validate used features exist then add to
27285e2414cSMike Leach * config list.
27385e2414cSMike Leach */
cscfg_load_config(struct cscfg_config_desc * config_desc)27485e2414cSMike Leach static int cscfg_load_config(struct cscfg_config_desc *config_desc)
27585e2414cSMike Leach {
27685e2414cSMike Leach int err;
27702bd588eSMike Leach struct cscfg_config_desc *config_desc_exist;
27802bd588eSMike Leach
27902bd588eSMike Leach /* new configuration must have a unique name */
28002bd588eSMike Leach list_for_each_entry(config_desc_exist, &cscfg_mgr->config_desc_list, item) {
28102bd588eSMike Leach if (!strcmp(config_desc_exist->name, config_desc->name))
28202bd588eSMike Leach return -EEXIST;
28302bd588eSMike Leach }
28485e2414cSMike Leach
28585e2414cSMike Leach /* validate features are present */
28685e2414cSMike Leach err = cscfg_check_feat_for_cfg(config_desc);
28785e2414cSMike Leach if (err)
28885e2414cSMike Leach return err;
28985e2414cSMike Leach
29042ff700fSMike Leach /* add config to any matching registered device */
29142ff700fSMike Leach err = cscfg_add_cfg_to_csdevs(config_desc);
29242ff700fSMike Leach if (err)
29342ff700fSMike Leach return err;
29442ff700fSMike Leach
29594d2bac5SMike Leach /* add config to perf fs to allow selection */
29694d2bac5SMike Leach err = etm_perf_add_symlink_cscfg(cscfg_device(), config_desc);
29794d2bac5SMike Leach if (err)
29894d2bac5SMike Leach return err;
29994d2bac5SMike Leach
30085e2414cSMike Leach list_add(&config_desc->item, &cscfg_mgr->config_desc_list);
301f8cce2ffSMike Leach atomic_set(&config_desc->active_cnt, 0);
30285e2414cSMike Leach return 0;
30385e2414cSMike Leach }
30485e2414cSMike Leach
305a13d5a24SMike Leach /* get a feature descriptor by name */
cscfg_get_named_feat_desc(const char * name)306a13d5a24SMike Leach const struct cscfg_feature_desc *cscfg_get_named_feat_desc(const char *name)
307a13d5a24SMike Leach {
308a13d5a24SMike Leach const struct cscfg_feature_desc *feat_desc = NULL, *feat_desc_item;
309a13d5a24SMike Leach
310a13d5a24SMike Leach mutex_lock(&cscfg_mutex);
311a13d5a24SMike Leach
312a13d5a24SMike Leach list_for_each_entry(feat_desc_item, &cscfg_mgr->feat_desc_list, item) {
313a13d5a24SMike Leach if (strcmp(feat_desc_item->name, name) == 0) {
314a13d5a24SMike Leach feat_desc = feat_desc_item;
315a13d5a24SMike Leach break;
316a13d5a24SMike Leach }
317a13d5a24SMike Leach }
318a13d5a24SMike Leach
319a13d5a24SMike Leach mutex_unlock(&cscfg_mutex);
320a13d5a24SMike Leach return feat_desc;
321a13d5a24SMike Leach }
322a13d5a24SMike Leach
323a13d5a24SMike Leach /* called with cscfg_mutex held */
324a13d5a24SMike Leach static struct cscfg_feature_csdev *
cscfg_csdev_get_feat_from_desc(struct coresight_device * csdev,struct cscfg_feature_desc * feat_desc)325a13d5a24SMike Leach cscfg_csdev_get_feat_from_desc(struct coresight_device *csdev,
326a13d5a24SMike Leach struct cscfg_feature_desc *feat_desc)
327a13d5a24SMike Leach {
328a13d5a24SMike Leach struct cscfg_feature_csdev *feat_csdev;
329a13d5a24SMike Leach
330a13d5a24SMike Leach list_for_each_entry(feat_csdev, &csdev->feature_csdev_list, node) {
331a13d5a24SMike Leach if (feat_csdev->feat_desc == feat_desc)
332a13d5a24SMike Leach return feat_csdev;
333a13d5a24SMike Leach }
334a13d5a24SMike Leach return NULL;
335a13d5a24SMike Leach }
336a13d5a24SMike Leach
cscfg_update_feat_param_val(struct cscfg_feature_desc * feat_desc,int param_idx,u64 value)337a13d5a24SMike Leach int cscfg_update_feat_param_val(struct cscfg_feature_desc *feat_desc,
338a13d5a24SMike Leach int param_idx, u64 value)
339a13d5a24SMike Leach {
340a13d5a24SMike Leach int err = 0;
341a13d5a24SMike Leach struct cscfg_feature_csdev *feat_csdev;
342a13d5a24SMike Leach struct cscfg_registered_csdev *csdev_item;
343a13d5a24SMike Leach
344a13d5a24SMike Leach mutex_lock(&cscfg_mutex);
345a13d5a24SMike Leach
346a13d5a24SMike Leach /* check if any config active & return busy */
347a13d5a24SMike Leach if (atomic_read(&cscfg_mgr->sys_active_cnt)) {
348a13d5a24SMike Leach err = -EBUSY;
349a13d5a24SMike Leach goto unlock_exit;
350a13d5a24SMike Leach }
351a13d5a24SMike Leach
352a13d5a24SMike Leach /* set the value */
353a13d5a24SMike Leach if ((param_idx < 0) || (param_idx >= feat_desc->nr_params)) {
354a13d5a24SMike Leach err = -EINVAL;
355a13d5a24SMike Leach goto unlock_exit;
356a13d5a24SMike Leach }
357a13d5a24SMike Leach feat_desc->params_desc[param_idx].value = value;
358a13d5a24SMike Leach
359a13d5a24SMike Leach /* update loaded instances.*/
360a13d5a24SMike Leach list_for_each_entry(csdev_item, &cscfg_mgr->csdev_desc_list, item) {
361a13d5a24SMike Leach feat_csdev = cscfg_csdev_get_feat_from_desc(csdev_item->csdev, feat_desc);
362a13d5a24SMike Leach if (feat_csdev)
363a13d5a24SMike Leach feat_csdev->params_csdev[param_idx].current_value = value;
364a13d5a24SMike Leach }
365a13d5a24SMike Leach
366a13d5a24SMike Leach unlock_exit:
367a13d5a24SMike Leach mutex_unlock(&cscfg_mutex);
368a13d5a24SMike Leach return err;
369a13d5a24SMike Leach }
370a13d5a24SMike Leach
371eb2ec496SMike Leach /*
372eb2ec496SMike Leach * Conditionally up reference count on owner to prevent unload.
373eb2ec496SMike Leach *
374eb2ec496SMike Leach * module loaded configs need to be locked in to prevent premature unload.
375eb2ec496SMike Leach */
cscfg_owner_get(struct cscfg_load_owner_info * owner_info)376eb2ec496SMike Leach static int cscfg_owner_get(struct cscfg_load_owner_info *owner_info)
377eb2ec496SMike Leach {
378eb2ec496SMike Leach if ((owner_info->type == CSCFG_OWNER_MODULE) &&
379eb2ec496SMike Leach (!try_module_get(owner_info->owner_handle)))
380eb2ec496SMike Leach return -EINVAL;
381eb2ec496SMike Leach return 0;
382eb2ec496SMike Leach }
383eb2ec496SMike Leach
384eb2ec496SMike Leach /* conditionally lower ref count on an owner */
cscfg_owner_put(struct cscfg_load_owner_info * owner_info)385eb2ec496SMike Leach static void cscfg_owner_put(struct cscfg_load_owner_info *owner_info)
386eb2ec496SMike Leach {
387eb2ec496SMike Leach if (owner_info->type == CSCFG_OWNER_MODULE)
388eb2ec496SMike Leach module_put(owner_info->owner_handle);
389eb2ec496SMike Leach }
390eb2ec496SMike Leach
cscfg_remove_owned_csdev_configs(struct coresight_device * csdev,void * load_owner)39102bd588eSMike Leach static void cscfg_remove_owned_csdev_configs(struct coresight_device *csdev, void *load_owner)
39202bd588eSMike Leach {
39302bd588eSMike Leach struct cscfg_config_csdev *config_csdev, *tmp;
39402bd588eSMike Leach
39502bd588eSMike Leach if (list_empty(&csdev->config_csdev_list))
39602bd588eSMike Leach return;
39702bd588eSMike Leach
39802bd588eSMike Leach list_for_each_entry_safe(config_csdev, tmp, &csdev->config_csdev_list, node) {
39902bd588eSMike Leach if (config_csdev->config_desc->load_owner == load_owner)
40002bd588eSMike Leach list_del(&config_csdev->node);
40102bd588eSMike Leach }
40202bd588eSMike Leach }
40302bd588eSMike Leach
cscfg_remove_owned_csdev_features(struct coresight_device * csdev,void * load_owner)40402bd588eSMike Leach static void cscfg_remove_owned_csdev_features(struct coresight_device *csdev, void *load_owner)
40502bd588eSMike Leach {
40602bd588eSMike Leach struct cscfg_feature_csdev *feat_csdev, *tmp;
40702bd588eSMike Leach
40802bd588eSMike Leach if (list_empty(&csdev->feature_csdev_list))
40902bd588eSMike Leach return;
41002bd588eSMike Leach
41102bd588eSMike Leach list_for_each_entry_safe(feat_csdev, tmp, &csdev->feature_csdev_list, node) {
41202bd588eSMike Leach if (feat_csdev->feat_desc->load_owner == load_owner)
41302bd588eSMike Leach list_del(&feat_csdev->node);
41402bd588eSMike Leach }
41502bd588eSMike Leach }
41602bd588eSMike Leach
41702bd588eSMike Leach /*
418199380deSMike Leach * Unregister all configuration and features from configfs owned by load_owner.
419199380deSMike Leach * Although this is called without the list mutex being held, it is in the
420199380deSMike Leach * context of an unload operation which are strictly serialised,
421199380deSMike Leach * so the lists cannot change during this call.
422199380deSMike Leach */
cscfg_fs_unregister_cfgs_feats(void * load_owner)423199380deSMike Leach static void cscfg_fs_unregister_cfgs_feats(void *load_owner)
424199380deSMike Leach {
425199380deSMike Leach struct cscfg_config_desc *config_desc;
426199380deSMike Leach struct cscfg_feature_desc *feat_desc;
427199380deSMike Leach
428199380deSMike Leach list_for_each_entry(config_desc, &cscfg_mgr->config_desc_list, item) {
429199380deSMike Leach if (config_desc->load_owner == load_owner)
430199380deSMike Leach cscfg_configfs_del_config(config_desc);
431199380deSMike Leach }
432199380deSMike Leach list_for_each_entry(feat_desc, &cscfg_mgr->feat_desc_list, item) {
433199380deSMike Leach if (feat_desc->load_owner == load_owner)
434199380deSMike Leach cscfg_configfs_del_feature(feat_desc);
435199380deSMike Leach }
436199380deSMike Leach }
437199380deSMike Leach
438199380deSMike Leach /*
43902bd588eSMike Leach * removal is relatively easy - just remove from all lists, anything that
44002bd588eSMike Leach * matches the owner. Memory for the descriptors will be managed by the owner,
44102bd588eSMike Leach * memory for the csdev items is devm_ allocated with the individual csdev
44202bd588eSMike Leach * devices.
44302bd588eSMike Leach */
cscfg_unload_owned_cfgs_feats(void * load_owner)44402bd588eSMike Leach static void cscfg_unload_owned_cfgs_feats(void *load_owner)
44502bd588eSMike Leach {
44602bd588eSMike Leach struct cscfg_config_desc *config_desc, *cfg_tmp;
44702bd588eSMike Leach struct cscfg_feature_desc *feat_desc, *feat_tmp;
44802bd588eSMike Leach struct cscfg_registered_csdev *csdev_item;
44902bd588eSMike Leach
450*8add26f7SMike Leach lockdep_assert_held(&cscfg_mutex);
451*8add26f7SMike Leach
45202bd588eSMike Leach /* remove from each csdev instance feature and config lists */
45302bd588eSMike Leach list_for_each_entry(csdev_item, &cscfg_mgr->csdev_desc_list, item) {
45402bd588eSMike Leach /*
45502bd588eSMike Leach * for each csdev, check the loaded lists and remove if
45602bd588eSMike Leach * referenced descriptor is owned
45702bd588eSMike Leach */
45802bd588eSMike Leach cscfg_remove_owned_csdev_configs(csdev_item->csdev, load_owner);
45902bd588eSMike Leach cscfg_remove_owned_csdev_features(csdev_item->csdev, load_owner);
46002bd588eSMike Leach }
46102bd588eSMike Leach
46202bd588eSMike Leach /* remove from the config descriptor lists */
46302bd588eSMike Leach list_for_each_entry_safe(config_desc, cfg_tmp, &cscfg_mgr->config_desc_list, item) {
46402bd588eSMike Leach if (config_desc->load_owner == load_owner) {
46502bd588eSMike Leach etm_perf_del_symlink_cscfg(config_desc);
46602bd588eSMike Leach list_del(&config_desc->item);
46702bd588eSMike Leach }
46802bd588eSMike Leach }
46902bd588eSMike Leach
47002bd588eSMike Leach /* remove from the feature descriptor lists */
47102bd588eSMike Leach list_for_each_entry_safe(feat_desc, feat_tmp, &cscfg_mgr->feat_desc_list, item) {
47202bd588eSMike Leach if (feat_desc->load_owner == load_owner) {
47302bd588eSMike Leach list_del(&feat_desc->item);
47402bd588eSMike Leach }
47502bd588eSMike Leach }
47602bd588eSMike Leach }
47702bd588eSMike Leach
478*8add26f7SMike Leach /*
479*8add26f7SMike Leach * load the features and configs to the lists - called with list mutex held
480*8add26f7SMike Leach */
cscfg_load_owned_cfgs_feats(struct cscfg_config_desc ** config_descs,struct cscfg_feature_desc ** feat_descs,struct cscfg_load_owner_info * owner_info)481*8add26f7SMike Leach static int cscfg_load_owned_cfgs_feats(struct cscfg_config_desc **config_descs,
482*8add26f7SMike Leach struct cscfg_feature_desc **feat_descs,
483*8add26f7SMike Leach struct cscfg_load_owner_info *owner_info)
484*8add26f7SMike Leach {
485*8add26f7SMike Leach int i, err;
486*8add26f7SMike Leach
487*8add26f7SMike Leach lockdep_assert_held(&cscfg_mutex);
488*8add26f7SMike Leach
489*8add26f7SMike Leach /* load features first */
490*8add26f7SMike Leach if (feat_descs) {
491*8add26f7SMike Leach for (i = 0; feat_descs[i]; i++) {
492*8add26f7SMike Leach err = cscfg_load_feat(feat_descs[i]);
493*8add26f7SMike Leach if (err) {
494*8add26f7SMike Leach pr_err("coresight-syscfg: Failed to load feature %s\n",
495*8add26f7SMike Leach feat_descs[i]->name);
496*8add26f7SMike Leach return err;
497*8add26f7SMike Leach }
498*8add26f7SMike Leach feat_descs[i]->load_owner = owner_info;
499*8add26f7SMike Leach }
500*8add26f7SMike Leach }
501*8add26f7SMike Leach
502*8add26f7SMike Leach /* next any configurations to check feature dependencies */
503*8add26f7SMike Leach if (config_descs) {
504*8add26f7SMike Leach for (i = 0; config_descs[i]; i++) {
505*8add26f7SMike Leach err = cscfg_load_config(config_descs[i]);
506*8add26f7SMike Leach if (err) {
507*8add26f7SMike Leach pr_err("coresight-syscfg: Failed to load configuration %s\n",
508*8add26f7SMike Leach config_descs[i]->name);
509*8add26f7SMike Leach return err;
510*8add26f7SMike Leach }
511*8add26f7SMike Leach config_descs[i]->load_owner = owner_info;
512*8add26f7SMike Leach config_descs[i]->available = false;
513*8add26f7SMike Leach }
514*8add26f7SMike Leach }
515*8add26f7SMike Leach return 0;
516*8add26f7SMike Leach }
517*8add26f7SMike Leach
518*8add26f7SMike Leach /* set configurations as available to activate at the end of the load process */
cscfg_set_configs_available(struct cscfg_config_desc ** config_descs)519*8add26f7SMike Leach static void cscfg_set_configs_available(struct cscfg_config_desc **config_descs)
520*8add26f7SMike Leach {
521*8add26f7SMike Leach int i;
522*8add26f7SMike Leach
523*8add26f7SMike Leach lockdep_assert_held(&cscfg_mutex);
524*8add26f7SMike Leach
525*8add26f7SMike Leach if (config_descs) {
526*8add26f7SMike Leach for (i = 0; config_descs[i]; i++)
527*8add26f7SMike Leach config_descs[i]->available = true;
528*8add26f7SMike Leach }
529*8add26f7SMike Leach }
530*8add26f7SMike Leach
531*8add26f7SMike Leach /*
532*8add26f7SMike Leach * Create and register each of the configurations and features with configfs.
533*8add26f7SMike Leach * Called without mutex being held.
534*8add26f7SMike Leach */
cscfg_fs_register_cfgs_feats(struct cscfg_config_desc ** config_descs,struct cscfg_feature_desc ** feat_descs)535*8add26f7SMike Leach static int cscfg_fs_register_cfgs_feats(struct cscfg_config_desc **config_descs,
536*8add26f7SMike Leach struct cscfg_feature_desc **feat_descs)
537*8add26f7SMike Leach {
538*8add26f7SMike Leach int i, err;
539*8add26f7SMike Leach
540*8add26f7SMike Leach if (feat_descs) {
541*8add26f7SMike Leach for (i = 0; feat_descs[i]; i++) {
542*8add26f7SMike Leach err = cscfg_configfs_add_feature(feat_descs[i]);
543*8add26f7SMike Leach if (err)
544*8add26f7SMike Leach return err;
545*8add26f7SMike Leach }
546*8add26f7SMike Leach }
547*8add26f7SMike Leach if (config_descs) {
548*8add26f7SMike Leach for (i = 0; config_descs[i]; i++) {
549*8add26f7SMike Leach err = cscfg_configfs_add_config(config_descs[i]);
550*8add26f7SMike Leach if (err)
551*8add26f7SMike Leach return err;
552*8add26f7SMike Leach }
553*8add26f7SMike Leach }
554*8add26f7SMike Leach return 0;
555*8add26f7SMike Leach }
556*8add26f7SMike Leach
55785e2414cSMike Leach /**
55885e2414cSMike Leach * cscfg_load_config_sets - API function to load feature and config sets.
55985e2414cSMike Leach *
56085e2414cSMike Leach * Take a 0 terminated array of feature descriptors and/or configuration
56185e2414cSMike Leach * descriptors and load into the system.
56285e2414cSMike Leach * Features are loaded first to ensure configuration dependencies can be met.
56385e2414cSMike Leach *
564da7000e8SMike Leach * To facilitate dynamic loading and unloading, features and configurations
565da7000e8SMike Leach * have a "load_owner", to allow later unload by the same owner. An owner may
566da7000e8SMike Leach * be a loadable module or configuration dynamically created via configfs.
567da7000e8SMike Leach * As later loaded configurations can use earlier loaded features, creating load
568da7000e8SMike Leach * dependencies, a load order list is maintained. Unload is strictly in the
569da7000e8SMike Leach * reverse order to load.
570da7000e8SMike Leach *
57185e2414cSMike Leach * @config_descs: 0 terminated array of configuration descriptors.
57285e2414cSMike Leach * @feat_descs: 0 terminated array of feature descriptors.
573da7000e8SMike Leach * @owner_info: Information on the owner of this set.
57485e2414cSMike Leach */
cscfg_load_config_sets(struct cscfg_config_desc ** config_descs,struct cscfg_feature_desc ** feat_descs,struct cscfg_load_owner_info * owner_info)57585e2414cSMike Leach int cscfg_load_config_sets(struct cscfg_config_desc **config_descs,
576da7000e8SMike Leach struct cscfg_feature_desc **feat_descs,
577da7000e8SMike Leach struct cscfg_load_owner_info *owner_info)
57885e2414cSMike Leach {
579*8add26f7SMike Leach int err = 0;
58085e2414cSMike Leach
58185e2414cSMike Leach mutex_lock(&cscfg_mutex);
582*8add26f7SMike Leach if (cscfg_mgr->load_state != CSCFG_NONE) {
583*8add26f7SMike Leach mutex_unlock(&cscfg_mutex);
584*8add26f7SMike Leach return -EBUSY;
585*8add26f7SMike Leach }
586*8add26f7SMike Leach cscfg_mgr->load_state = CSCFG_LOAD;
58785e2414cSMike Leach
588*8add26f7SMike Leach /* first load and add to the lists */
589*8add26f7SMike Leach err = cscfg_load_owned_cfgs_feats(config_descs, feat_descs, owner_info);
590*8add26f7SMike Leach if (err)
591*8add26f7SMike Leach goto err_clean_load;
59285e2414cSMike Leach
593da7000e8SMike Leach /* add the load owner to the load order list */
594da7000e8SMike Leach list_add_tail(&owner_info->item, &cscfg_mgr->load_order_list);
595eb2ec496SMike Leach if (!list_is_singular(&cscfg_mgr->load_order_list)) {
596eb2ec496SMike Leach /* lock previous item in load order list */
597eb2ec496SMike Leach err = cscfg_owner_get(list_prev_entry(owner_info, item));
598*8add26f7SMike Leach if (err)
599*8add26f7SMike Leach goto err_clean_owner_list;
600eb2ec496SMike Leach }
601da7000e8SMike Leach
602*8add26f7SMike Leach /*
603*8add26f7SMike Leach * make visible to configfs - configfs manipulation must occur outside
604*8add26f7SMike Leach * the list mutex lock to avoid circular lockdep issues with configfs
605*8add26f7SMike Leach * built in mutexes and semaphores. This is safe as it is not possible
606*8add26f7SMike Leach * to start a new load/unload operation till the current one is done.
607*8add26f7SMike Leach */
608*8add26f7SMike Leach mutex_unlock(&cscfg_mutex);
609*8add26f7SMike Leach
610*8add26f7SMike Leach /* create the configfs elements */
611*8add26f7SMike Leach err = cscfg_fs_register_cfgs_feats(config_descs, feat_descs);
612*8add26f7SMike Leach mutex_lock(&cscfg_mutex);
613*8add26f7SMike Leach
614*8add26f7SMike Leach if (err)
615*8add26f7SMike Leach goto err_clean_cfs;
616*8add26f7SMike Leach
617*8add26f7SMike Leach /* mark any new configs as available for activation */
618*8add26f7SMike Leach cscfg_set_configs_available(config_descs);
619*8add26f7SMike Leach goto exit_unlock;
620*8add26f7SMike Leach
621*8add26f7SMike Leach err_clean_cfs:
622*8add26f7SMike Leach /* cleanup after error registering with configfs */
623*8add26f7SMike Leach cscfg_fs_unregister_cfgs_feats(owner_info);
624*8add26f7SMike Leach
625*8add26f7SMike Leach if (!list_is_singular(&cscfg_mgr->load_order_list))
626*8add26f7SMike Leach cscfg_owner_put(list_prev_entry(owner_info, item));
627*8add26f7SMike Leach
628*8add26f7SMike Leach err_clean_owner_list:
629*8add26f7SMike Leach list_del(&owner_info->item);
630*8add26f7SMike Leach
631*8add26f7SMike Leach err_clean_load:
632*8add26f7SMike Leach cscfg_unload_owned_cfgs_feats(owner_info);
633*8add26f7SMike Leach
63485e2414cSMike Leach exit_unlock:
635*8add26f7SMike Leach cscfg_mgr->load_state = CSCFG_NONE;
63685e2414cSMike Leach mutex_unlock(&cscfg_mutex);
63785e2414cSMike Leach return err;
63885e2414cSMike Leach }
63985e2414cSMike Leach EXPORT_SYMBOL_GPL(cscfg_load_config_sets);
64085e2414cSMike Leach
64102bd588eSMike Leach /**
64202bd588eSMike Leach * cscfg_unload_config_sets - unload a set of configurations by owner.
64302bd588eSMike Leach *
64402bd588eSMike Leach * Dynamic unload of configuration and feature sets is done on the basis of
64502bd588eSMike Leach * the load owner of that set. Later loaded configurations can depend on
64602bd588eSMike Leach * features loaded earlier.
64702bd588eSMike Leach *
64802bd588eSMike Leach * Therefore, unload is only possible if:-
64902bd588eSMike Leach * 1) no configurations are active.
65002bd588eSMike Leach * 2) the set being unloaded was the last to be loaded to maintain dependencies.
65102bd588eSMike Leach *
652*8add26f7SMike Leach * Once the unload operation commences, we disallow any configuration being
653*8add26f7SMike Leach * made active until it is complete.
654*8add26f7SMike Leach *
65502bd588eSMike Leach * @owner_info: Information on owner for set being unloaded.
65602bd588eSMike Leach */
cscfg_unload_config_sets(struct cscfg_load_owner_info * owner_info)65702bd588eSMike Leach int cscfg_unload_config_sets(struct cscfg_load_owner_info *owner_info)
65802bd588eSMike Leach {
65902bd588eSMike Leach int err = 0;
66002bd588eSMike Leach struct cscfg_load_owner_info *load_list_item = NULL;
66102bd588eSMike Leach
66202bd588eSMike Leach mutex_lock(&cscfg_mutex);
663*8add26f7SMike Leach if (cscfg_mgr->load_state != CSCFG_NONE) {
664*8add26f7SMike Leach mutex_unlock(&cscfg_mutex);
665*8add26f7SMike Leach return -EBUSY;
666*8add26f7SMike Leach }
667*8add26f7SMike Leach
668*8add26f7SMike Leach /* unload op in progress also prevents activation of any config */
669*8add26f7SMike Leach cscfg_mgr->load_state = CSCFG_UNLOAD;
67002bd588eSMike Leach
67102bd588eSMike Leach /* cannot unload if anything is active */
67202bd588eSMike Leach if (atomic_read(&cscfg_mgr->sys_active_cnt)) {
67302bd588eSMike Leach err = -EBUSY;
67402bd588eSMike Leach goto exit_unlock;
67502bd588eSMike Leach }
67602bd588eSMike Leach
67702bd588eSMike Leach /* cannot unload if not last loaded in load order */
67802bd588eSMike Leach if (!list_empty(&cscfg_mgr->load_order_list)) {
67902bd588eSMike Leach load_list_item = list_last_entry(&cscfg_mgr->load_order_list,
68002bd588eSMike Leach struct cscfg_load_owner_info, item);
68102bd588eSMike Leach if (load_list_item != owner_info)
68202bd588eSMike Leach load_list_item = NULL;
68302bd588eSMike Leach }
68402bd588eSMike Leach
68502bd588eSMike Leach if (!load_list_item) {
68602bd588eSMike Leach err = -EINVAL;
68702bd588eSMike Leach goto exit_unlock;
68802bd588eSMike Leach }
68902bd588eSMike Leach
690*8add26f7SMike Leach /* remove from configfs - again outside the scope of the list mutex */
691*8add26f7SMike Leach mutex_unlock(&cscfg_mutex);
692*8add26f7SMike Leach cscfg_fs_unregister_cfgs_feats(owner_info);
693*8add26f7SMike Leach mutex_lock(&cscfg_mutex);
694*8add26f7SMike Leach
695*8add26f7SMike Leach /* unload everything from lists belonging to load_owner */
69602bd588eSMike Leach cscfg_unload_owned_cfgs_feats(owner_info);
69702bd588eSMike Leach
69802bd588eSMike Leach /* remove from load order list */
699eb2ec496SMike Leach if (!list_is_singular(&cscfg_mgr->load_order_list)) {
700eb2ec496SMike Leach /* unlock previous item in load order list */
701eb2ec496SMike Leach cscfg_owner_put(list_prev_entry(owner_info, item));
702eb2ec496SMike Leach }
703eb2ec496SMike Leach list_del(&owner_info->item);
70402bd588eSMike Leach
70502bd588eSMike Leach exit_unlock:
706*8add26f7SMike Leach cscfg_mgr->load_state = CSCFG_NONE;
70702bd588eSMike Leach mutex_unlock(&cscfg_mutex);
70802bd588eSMike Leach return err;
70902bd588eSMike Leach }
71002bd588eSMike Leach EXPORT_SYMBOL_GPL(cscfg_unload_config_sets);
71102bd588eSMike Leach
71242ff700fSMike Leach /* Handle coresight device registration and add configs and features to devices */
71342ff700fSMike Leach
71442ff700fSMike Leach /* iterate through config lists and load matching configs to device */
cscfg_add_cfgs_csdev(struct coresight_device * csdev)71542ff700fSMike Leach static int cscfg_add_cfgs_csdev(struct coresight_device *csdev)
71642ff700fSMike Leach {
71742ff700fSMike Leach struct cscfg_config_desc *config_desc;
71842ff700fSMike Leach int err = 0;
71942ff700fSMike Leach
72042ff700fSMike Leach list_for_each_entry(config_desc, &cscfg_mgr->config_desc_list, item) {
72142ff700fSMike Leach err = cscfg_add_csdev_cfg(csdev, config_desc);
72242ff700fSMike Leach if (err)
72342ff700fSMike Leach break;
72442ff700fSMike Leach }
72542ff700fSMike Leach return err;
72642ff700fSMike Leach }
72742ff700fSMike Leach
72842ff700fSMike Leach /* iterate through feature lists and load matching features to device */
cscfg_add_feats_csdev(struct coresight_device * csdev,u32 match_flags,struct cscfg_csdev_feat_ops * ops)72942ff700fSMike Leach static int cscfg_add_feats_csdev(struct coresight_device *csdev,
73042ff700fSMike Leach u32 match_flags,
73142ff700fSMike Leach struct cscfg_csdev_feat_ops *ops)
73242ff700fSMike Leach {
73342ff700fSMike Leach struct cscfg_feature_desc *feat_desc;
73442ff700fSMike Leach int err = 0;
73542ff700fSMike Leach
73642ff700fSMike Leach if (!ops->load_feat)
73742ff700fSMike Leach return -EINVAL;
73842ff700fSMike Leach
73942ff700fSMike Leach list_for_each_entry(feat_desc, &cscfg_mgr->feat_desc_list, item) {
74042ff700fSMike Leach if (feat_desc->match_flags & match_flags) {
74142ff700fSMike Leach err = cscfg_load_feat_csdev(csdev, feat_desc, ops);
74242ff700fSMike Leach if (err)
74342ff700fSMike Leach break;
74442ff700fSMike Leach }
74542ff700fSMike Leach }
74642ff700fSMike Leach return err;
74742ff700fSMike Leach }
74842ff700fSMike Leach
74942ff700fSMike Leach /* Add coresight device to list and copy its matching info */
cscfg_list_add_csdev(struct coresight_device * csdev,u32 match_flags,struct cscfg_csdev_feat_ops * ops)75042ff700fSMike Leach static int cscfg_list_add_csdev(struct coresight_device *csdev,
75142ff700fSMike Leach u32 match_flags,
75242ff700fSMike Leach struct cscfg_csdev_feat_ops *ops)
75342ff700fSMike Leach {
75442ff700fSMike Leach struct cscfg_registered_csdev *csdev_item;
75542ff700fSMike Leach
75642ff700fSMike Leach /* allocate the list entry structure */
75742ff700fSMike Leach csdev_item = kzalloc(sizeof(struct cscfg_registered_csdev), GFP_KERNEL);
75842ff700fSMike Leach if (!csdev_item)
75942ff700fSMike Leach return -ENOMEM;
76042ff700fSMike Leach
76142ff700fSMike Leach csdev_item->csdev = csdev;
76242ff700fSMike Leach csdev_item->match_flags = match_flags;
76342ff700fSMike Leach csdev_item->ops.load_feat = ops->load_feat;
76442ff700fSMike Leach list_add(&csdev_item->item, &cscfg_mgr->csdev_desc_list);
76542ff700fSMike Leach
76642ff700fSMike Leach INIT_LIST_HEAD(&csdev->feature_csdev_list);
76742ff700fSMike Leach INIT_LIST_HEAD(&csdev->config_csdev_list);
76842ff700fSMike Leach spin_lock_init(&csdev->cscfg_csdev_lock);
76942ff700fSMike Leach
77042ff700fSMike Leach return 0;
77142ff700fSMike Leach }
77242ff700fSMike Leach
77342ff700fSMike Leach /* remove a coresight device from the list and free data */
cscfg_list_remove_csdev(struct coresight_device * csdev)77442ff700fSMike Leach static void cscfg_list_remove_csdev(struct coresight_device *csdev)
77542ff700fSMike Leach {
77642ff700fSMike Leach struct cscfg_registered_csdev *csdev_item, *tmp;
77742ff700fSMike Leach
77842ff700fSMike Leach list_for_each_entry_safe(csdev_item, tmp, &cscfg_mgr->csdev_desc_list, item) {
77942ff700fSMike Leach if (csdev_item->csdev == csdev) {
78042ff700fSMike Leach list_del(&csdev_item->item);
78142ff700fSMike Leach kfree(csdev_item);
78242ff700fSMike Leach break;
78342ff700fSMike Leach }
78442ff700fSMike Leach }
78542ff700fSMike Leach }
78642ff700fSMike Leach
78742ff700fSMike Leach /**
78842ff700fSMike Leach * cscfg_register_csdev - register a coresight device with the syscfg manager.
78942ff700fSMike Leach *
79042ff700fSMike Leach * Registers the coresight device with the system. @match_flags used to check
79142ff700fSMike Leach * if the device is a match for registered features. Any currently registered
79242ff700fSMike Leach * configurations and features that match the device will be loaded onto it.
79342ff700fSMike Leach *
79442ff700fSMike Leach * @csdev: The coresight device to register.
79542ff700fSMike Leach * @match_flags: Matching information to load features.
79642ff700fSMike Leach * @ops: Standard operations supported by the device.
79742ff700fSMike Leach */
cscfg_register_csdev(struct coresight_device * csdev,u32 match_flags,struct cscfg_csdev_feat_ops * ops)79842ff700fSMike Leach int cscfg_register_csdev(struct coresight_device *csdev,
79942ff700fSMike Leach u32 match_flags,
80042ff700fSMike Leach struct cscfg_csdev_feat_ops *ops)
80142ff700fSMike Leach {
80242ff700fSMike Leach int ret = 0;
80342ff700fSMike Leach
80442ff700fSMike Leach mutex_lock(&cscfg_mutex);
80542ff700fSMike Leach
80642ff700fSMike Leach /* add device to list of registered devices */
80742ff700fSMike Leach ret = cscfg_list_add_csdev(csdev, match_flags, ops);
80842ff700fSMike Leach if (ret)
80942ff700fSMike Leach goto reg_csdev_unlock;
81042ff700fSMike Leach
81142ff700fSMike Leach /* now load any registered features and configs matching the device. */
81242ff700fSMike Leach ret = cscfg_add_feats_csdev(csdev, match_flags, ops);
81342ff700fSMike Leach if (ret) {
81442ff700fSMike Leach cscfg_list_remove_csdev(csdev);
81542ff700fSMike Leach goto reg_csdev_unlock;
81642ff700fSMike Leach }
81742ff700fSMike Leach
81842ff700fSMike Leach ret = cscfg_add_cfgs_csdev(csdev);
81942ff700fSMike Leach if (ret) {
82042ff700fSMike Leach cscfg_list_remove_csdev(csdev);
82142ff700fSMike Leach goto reg_csdev_unlock;
82242ff700fSMike Leach }
82342ff700fSMike Leach
82442ff700fSMike Leach pr_info("CSCFG registered %s", dev_name(&csdev->dev));
82542ff700fSMike Leach
82642ff700fSMike Leach reg_csdev_unlock:
82742ff700fSMike Leach mutex_unlock(&cscfg_mutex);
82842ff700fSMike Leach return ret;
82942ff700fSMike Leach }
83042ff700fSMike Leach EXPORT_SYMBOL_GPL(cscfg_register_csdev);
83142ff700fSMike Leach
83242ff700fSMike Leach /**
83342ff700fSMike Leach * cscfg_unregister_csdev - remove coresight device from syscfg manager.
83442ff700fSMike Leach *
83542ff700fSMike Leach * @csdev: Device to remove.
83642ff700fSMike Leach */
cscfg_unregister_csdev(struct coresight_device * csdev)83742ff700fSMike Leach void cscfg_unregister_csdev(struct coresight_device *csdev)
83842ff700fSMike Leach {
83942ff700fSMike Leach mutex_lock(&cscfg_mutex);
84042ff700fSMike Leach cscfg_list_remove_csdev(csdev);
84142ff700fSMike Leach mutex_unlock(&cscfg_mutex);
84242ff700fSMike Leach }
84342ff700fSMike Leach EXPORT_SYMBOL_GPL(cscfg_unregister_csdev);
84442ff700fSMike Leach
845f8cce2ffSMike Leach /**
846f8cce2ffSMike Leach * cscfg_csdev_reset_feats - reset features for a CoreSight device.
847f8cce2ffSMike Leach *
848f8cce2ffSMike Leach * Resets all parameters and register values for any features loaded
849f8cce2ffSMike Leach * into @csdev to their default values.
850f8cce2ffSMike Leach *
851f8cce2ffSMike Leach * @csdev: The CoreSight device.
852f8cce2ffSMike Leach */
cscfg_csdev_reset_feats(struct coresight_device * csdev)853f8cce2ffSMike Leach void cscfg_csdev_reset_feats(struct coresight_device *csdev)
854f8cce2ffSMike Leach {
855f8cce2ffSMike Leach struct cscfg_feature_csdev *feat_csdev;
856f8cce2ffSMike Leach unsigned long flags;
857f8cce2ffSMike Leach
858f8cce2ffSMike Leach spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
859f8cce2ffSMike Leach if (list_empty(&csdev->feature_csdev_list))
860f8cce2ffSMike Leach goto unlock_exit;
861f8cce2ffSMike Leach
862f8cce2ffSMike Leach list_for_each_entry(feat_csdev, &csdev->feature_csdev_list, node)
863f8cce2ffSMike Leach cscfg_reset_feat(feat_csdev);
864f8cce2ffSMike Leach
865f8cce2ffSMike Leach unlock_exit:
866f8cce2ffSMike Leach spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
867f8cce2ffSMike Leach }
868f8cce2ffSMike Leach EXPORT_SYMBOL_GPL(cscfg_csdev_reset_feats);
869f8cce2ffSMike Leach
8707ebd0ec6SMike Leach /*
8717ebd0ec6SMike Leach * This activate configuration for either perf or sysfs. Perf can have multiple
8727ebd0ec6SMike Leach * active configs, selected per event, sysfs is limited to one.
873f8cce2ffSMike Leach *
874f8cce2ffSMike Leach * Increments the configuration descriptor active count and the global active
875f8cce2ffSMike Leach * count.
876f8cce2ffSMike Leach *
877f8cce2ffSMike Leach * @cfg_hash: Hash value of the selected configuration name.
878f8cce2ffSMike Leach */
_cscfg_activate_config(unsigned long cfg_hash)8797ebd0ec6SMike Leach static int _cscfg_activate_config(unsigned long cfg_hash)
880f8cce2ffSMike Leach {
881f8cce2ffSMike Leach struct cscfg_config_desc *config_desc;
882f8cce2ffSMike Leach int err = -EINVAL;
883f8cce2ffSMike Leach
884*8add26f7SMike Leach if (cscfg_mgr->load_state == CSCFG_UNLOAD)
885*8add26f7SMike Leach return -EBUSY;
886*8add26f7SMike Leach
887f8cce2ffSMike Leach list_for_each_entry(config_desc, &cscfg_mgr->config_desc_list, item) {
888f8cce2ffSMike Leach if ((unsigned long)config_desc->event_ea->var == cfg_hash) {
889*8add26f7SMike Leach /* if we happen upon a partly loaded config, can't use it */
890*8add26f7SMike Leach if (config_desc->available == false)
891*8add26f7SMike Leach return -EBUSY;
892*8add26f7SMike Leach
893eb2ec496SMike Leach /* must ensure that config cannot be unloaded in use */
894eb2ec496SMike Leach err = cscfg_owner_get(config_desc->load_owner);
895eb2ec496SMike Leach if (err)
896eb2ec496SMike Leach break;
897f8cce2ffSMike Leach /*
898f8cce2ffSMike Leach * increment the global active count - control changes to
899f8cce2ffSMike Leach * active configurations
900f8cce2ffSMike Leach */
901f8cce2ffSMike Leach atomic_inc(&cscfg_mgr->sys_active_cnt);
902f8cce2ffSMike Leach
903f8cce2ffSMike Leach /*
904f8cce2ffSMike Leach * mark the descriptor as active so enable config on a
905f8cce2ffSMike Leach * device instance will use it
906f8cce2ffSMike Leach */
907f8cce2ffSMike Leach atomic_inc(&config_desc->active_cnt);
908f8cce2ffSMike Leach
909f8cce2ffSMike Leach err = 0;
910f8cce2ffSMike Leach dev_dbg(cscfg_device(), "Activate config %s.\n", config_desc->name);
911f8cce2ffSMike Leach break;
912f8cce2ffSMike Leach }
913f8cce2ffSMike Leach }
9147ebd0ec6SMike Leach return err;
9157ebd0ec6SMike Leach }
9167ebd0ec6SMike Leach
_cscfg_deactivate_config(unsigned long cfg_hash)9177ebd0ec6SMike Leach static void _cscfg_deactivate_config(unsigned long cfg_hash)
9187ebd0ec6SMike Leach {
9197ebd0ec6SMike Leach struct cscfg_config_desc *config_desc;
9207ebd0ec6SMike Leach
9217ebd0ec6SMike Leach list_for_each_entry(config_desc, &cscfg_mgr->config_desc_list, item) {
9227ebd0ec6SMike Leach if ((unsigned long)config_desc->event_ea->var == cfg_hash) {
9237ebd0ec6SMike Leach atomic_dec(&config_desc->active_cnt);
9247ebd0ec6SMike Leach atomic_dec(&cscfg_mgr->sys_active_cnt);
9257ebd0ec6SMike Leach cscfg_owner_put(config_desc->load_owner);
9267ebd0ec6SMike Leach dev_dbg(cscfg_device(), "Deactivate config %s.\n", config_desc->name);
9277ebd0ec6SMike Leach break;
9287ebd0ec6SMike Leach }
9297ebd0ec6SMike Leach }
9307ebd0ec6SMike Leach }
9317ebd0ec6SMike Leach
9327ebd0ec6SMike Leach /*
9337ebd0ec6SMike Leach * called from configfs to set/clear the active configuration for use when
9347ebd0ec6SMike Leach * using sysfs to control trace.
9357ebd0ec6SMike Leach */
cscfg_config_sysfs_activate(struct cscfg_config_desc * config_desc,bool activate)9367ebd0ec6SMike Leach int cscfg_config_sysfs_activate(struct cscfg_config_desc *config_desc, bool activate)
9377ebd0ec6SMike Leach {
9387ebd0ec6SMike Leach unsigned long cfg_hash;
9397ebd0ec6SMike Leach int err = 0;
9407ebd0ec6SMike Leach
9417ebd0ec6SMike Leach mutex_lock(&cscfg_mutex);
9427ebd0ec6SMike Leach
9437ebd0ec6SMike Leach cfg_hash = (unsigned long)config_desc->event_ea->var;
9447ebd0ec6SMike Leach
9457ebd0ec6SMike Leach if (activate) {
9467ebd0ec6SMike Leach /* cannot be a current active value to activate this */
9477ebd0ec6SMike Leach if (cscfg_mgr->sysfs_active_config) {
9487ebd0ec6SMike Leach err = -EBUSY;
9497ebd0ec6SMike Leach goto exit_unlock;
9507ebd0ec6SMike Leach }
9517ebd0ec6SMike Leach err = _cscfg_activate_config(cfg_hash);
9527ebd0ec6SMike Leach if (!err)
9537ebd0ec6SMike Leach cscfg_mgr->sysfs_active_config = cfg_hash;
9547ebd0ec6SMike Leach } else {
9557ebd0ec6SMike Leach /* disable if matching current value */
9567ebd0ec6SMike Leach if (cscfg_mgr->sysfs_active_config == cfg_hash) {
9577ebd0ec6SMike Leach _cscfg_deactivate_config(cfg_hash);
9587ebd0ec6SMike Leach cscfg_mgr->sysfs_active_config = 0;
9597ebd0ec6SMike Leach } else
9607ebd0ec6SMike Leach err = -EINVAL;
9617ebd0ec6SMike Leach }
9627ebd0ec6SMike Leach
9637ebd0ec6SMike Leach exit_unlock:
9647ebd0ec6SMike Leach mutex_unlock(&cscfg_mutex);
9657ebd0ec6SMike Leach return err;
9667ebd0ec6SMike Leach }
9677ebd0ec6SMike Leach
9687ebd0ec6SMike Leach /* set the sysfs preset value */
cscfg_config_sysfs_set_preset(int preset)9697ebd0ec6SMike Leach void cscfg_config_sysfs_set_preset(int preset)
9707ebd0ec6SMike Leach {
9717ebd0ec6SMike Leach mutex_lock(&cscfg_mutex);
9727ebd0ec6SMike Leach cscfg_mgr->sysfs_active_preset = preset;
9737ebd0ec6SMike Leach mutex_unlock(&cscfg_mutex);
9747ebd0ec6SMike Leach }
9757ebd0ec6SMike Leach
9767ebd0ec6SMike Leach /*
9777ebd0ec6SMike Leach * Used by a device to get the config and preset selected as active in configfs,
9787ebd0ec6SMike Leach * when using sysfs to control trace.
9797ebd0ec6SMike Leach */
cscfg_config_sysfs_get_active_cfg(unsigned long * cfg_hash,int * preset)9807ebd0ec6SMike Leach void cscfg_config_sysfs_get_active_cfg(unsigned long *cfg_hash, int *preset)
9817ebd0ec6SMike Leach {
9827ebd0ec6SMike Leach mutex_lock(&cscfg_mutex);
9837ebd0ec6SMike Leach *preset = cscfg_mgr->sysfs_active_preset;
9847ebd0ec6SMike Leach *cfg_hash = cscfg_mgr->sysfs_active_config;
9857ebd0ec6SMike Leach mutex_unlock(&cscfg_mutex);
9867ebd0ec6SMike Leach }
9877ebd0ec6SMike Leach EXPORT_SYMBOL_GPL(cscfg_config_sysfs_get_active_cfg);
9887ebd0ec6SMike Leach
9897ebd0ec6SMike Leach /**
9907ebd0ec6SMike Leach * cscfg_activate_config - Mark a configuration descriptor as active.
9917ebd0ec6SMike Leach *
9927ebd0ec6SMike Leach * This will be seen when csdev devices are enabled in the system.
9937ebd0ec6SMike Leach * Only activated configurations can be enabled on individual devices.
9947ebd0ec6SMike Leach * Activation protects the configuration from alteration or removal while
9957ebd0ec6SMike Leach * active.
9967ebd0ec6SMike Leach *
9977ebd0ec6SMike Leach * Selection by hash value - generated from the configuration name when it
9987ebd0ec6SMike Leach * was loaded and added to the cs_etm/configurations file system for selection
9997ebd0ec6SMike Leach * by perf.
10007ebd0ec6SMike Leach *
10017ebd0ec6SMike Leach * @cfg_hash: Hash value of the selected configuration name.
10027ebd0ec6SMike Leach */
cscfg_activate_config(unsigned long cfg_hash)10037ebd0ec6SMike Leach int cscfg_activate_config(unsigned long cfg_hash)
10047ebd0ec6SMike Leach {
10057ebd0ec6SMike Leach int err = 0;
10067ebd0ec6SMike Leach
10077ebd0ec6SMike Leach mutex_lock(&cscfg_mutex);
10087ebd0ec6SMike Leach err = _cscfg_activate_config(cfg_hash);
1009f8cce2ffSMike Leach mutex_unlock(&cscfg_mutex);
1010f8cce2ffSMike Leach
1011f8cce2ffSMike Leach return err;
1012f8cce2ffSMike Leach }
1013f8cce2ffSMike Leach EXPORT_SYMBOL_GPL(cscfg_activate_config);
1014f8cce2ffSMike Leach
1015f8cce2ffSMike Leach /**
1016f8cce2ffSMike Leach * cscfg_deactivate_config - Mark a config descriptor as inactive.
1017f8cce2ffSMike Leach *
1018f8cce2ffSMike Leach * Decrement the configuration and global active counts.
1019f8cce2ffSMike Leach *
1020f8cce2ffSMike Leach * @cfg_hash: Hash value of the selected configuration name.
1021f8cce2ffSMike Leach */
cscfg_deactivate_config(unsigned long cfg_hash)1022f8cce2ffSMike Leach void cscfg_deactivate_config(unsigned long cfg_hash)
1023f8cce2ffSMike Leach {
1024f8cce2ffSMike Leach mutex_lock(&cscfg_mutex);
10257ebd0ec6SMike Leach _cscfg_deactivate_config(cfg_hash);
1026f8cce2ffSMike Leach mutex_unlock(&cscfg_mutex);
1027f8cce2ffSMike Leach }
1028f8cce2ffSMike Leach EXPORT_SYMBOL_GPL(cscfg_deactivate_config);
1029f8cce2ffSMike Leach
1030f8cce2ffSMike Leach /**
1031f8cce2ffSMike Leach * cscfg_csdev_enable_active_config - Enable matching active configuration for device.
1032f8cce2ffSMike Leach *
1033f8cce2ffSMike Leach * Enables the configuration selected by @cfg_hash if the configuration is supported
1034f8cce2ffSMike Leach * on the device and has been activated.
1035f8cce2ffSMike Leach *
1036f8cce2ffSMike Leach * If active and supported the CoreSight device @csdev will be programmed with the
1037f8cce2ffSMike Leach * configuration, using @preset parameters.
1038f8cce2ffSMike Leach *
1039f8cce2ffSMike Leach * Should be called before driver hardware enable for the requested device, prior to
1040f8cce2ffSMike Leach * programming and enabling the physical hardware.
1041f8cce2ffSMike Leach *
1042f8cce2ffSMike Leach * @csdev: CoreSight device to program.
1043f8cce2ffSMike Leach * @cfg_hash: Selector for the configuration.
1044f8cce2ffSMike Leach * @preset: Preset parameter values to use, 0 for current / default values.
1045f8cce2ffSMike Leach */
cscfg_csdev_enable_active_config(struct coresight_device * csdev,unsigned long cfg_hash,int preset)1046f8cce2ffSMike Leach int cscfg_csdev_enable_active_config(struct coresight_device *csdev,
1047f8cce2ffSMike Leach unsigned long cfg_hash, int preset)
1048f8cce2ffSMike Leach {
1049f8cce2ffSMike Leach struct cscfg_config_csdev *config_csdev_active = NULL, *config_csdev_item;
1050f8cce2ffSMike Leach const struct cscfg_config_desc *config_desc;
1051f8cce2ffSMike Leach unsigned long flags;
1052f8cce2ffSMike Leach int err = 0;
1053f8cce2ffSMike Leach
1054f8cce2ffSMike Leach /* quickly check global count */
1055f8cce2ffSMike Leach if (!atomic_read(&cscfg_mgr->sys_active_cnt))
1056f8cce2ffSMike Leach return 0;
1057f8cce2ffSMike Leach
1058f8cce2ffSMike Leach /*
1059f8cce2ffSMike Leach * Look for matching configuration - set the active configuration
1060f8cce2ffSMike Leach * context if found.
1061f8cce2ffSMike Leach */
1062f8cce2ffSMike Leach spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
1063f8cce2ffSMike Leach list_for_each_entry(config_csdev_item, &csdev->config_csdev_list, node) {
1064f8cce2ffSMike Leach config_desc = config_csdev_item->config_desc;
1065f8cce2ffSMike Leach if ((atomic_read(&config_desc->active_cnt)) &&
1066f8cce2ffSMike Leach ((unsigned long)config_desc->event_ea->var == cfg_hash)) {
1067f8cce2ffSMike Leach config_csdev_active = config_csdev_item;
1068f8cce2ffSMike Leach csdev->active_cscfg_ctxt = (void *)config_csdev_active;
1069f8cce2ffSMike Leach break;
1070f8cce2ffSMike Leach }
1071f8cce2ffSMike Leach }
1072f8cce2ffSMike Leach spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
1073f8cce2ffSMike Leach
1074f8cce2ffSMike Leach /*
1075f8cce2ffSMike Leach * If found, attempt to enable
1076f8cce2ffSMike Leach */
1077f8cce2ffSMike Leach if (config_csdev_active) {
1078f8cce2ffSMike Leach /*
1079f8cce2ffSMike Leach * Call the generic routine that will program up the internal
1080f8cce2ffSMike Leach * driver structures prior to programming up the hardware.
1081f8cce2ffSMike Leach * This routine takes the driver spinlock saved in the configs.
1082f8cce2ffSMike Leach */
1083f8cce2ffSMike Leach err = cscfg_csdev_enable_config(config_csdev_active, preset);
1084f8cce2ffSMike Leach if (!err) {
1085f8cce2ffSMike Leach /*
1086f8cce2ffSMike Leach * Successful programming. Check the active_cscfg_ctxt
1087f8cce2ffSMike Leach * pointer to ensure no pre-emption disabled it via
1088f8cce2ffSMike Leach * cscfg_csdev_disable_active_config() before
1089f8cce2ffSMike Leach * we could start.
1090f8cce2ffSMike Leach *
1091f8cce2ffSMike Leach * Set enabled if OK, err if not.
1092f8cce2ffSMike Leach */
1093f8cce2ffSMike Leach spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
1094f8cce2ffSMike Leach if (csdev->active_cscfg_ctxt)
1095f8cce2ffSMike Leach config_csdev_active->enabled = true;
1096f8cce2ffSMike Leach else
1097f8cce2ffSMike Leach err = -EBUSY;
1098f8cce2ffSMike Leach spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
1099f8cce2ffSMike Leach }
1100f8cce2ffSMike Leach }
1101f8cce2ffSMike Leach return err;
1102f8cce2ffSMike Leach }
1103f8cce2ffSMike Leach EXPORT_SYMBOL_GPL(cscfg_csdev_enable_active_config);
1104f8cce2ffSMike Leach
1105f8cce2ffSMike Leach /**
1106f8cce2ffSMike Leach * cscfg_csdev_disable_active_config - disable an active config on the device.
1107f8cce2ffSMike Leach *
1108f8cce2ffSMike Leach * Disables the active configuration on the CoreSight device @csdev.
1109f8cce2ffSMike Leach * Disable will save the values of any registers marked in the configurations
1110f8cce2ffSMike Leach * as save on disable.
1111f8cce2ffSMike Leach *
1112f8cce2ffSMike Leach * Should be called after driver hardware disable for the requested device,
1113f8cce2ffSMike Leach * after disabling the physical hardware and reading back registers.
1114f8cce2ffSMike Leach *
1115f8cce2ffSMike Leach * @csdev: The CoreSight device.
1116f8cce2ffSMike Leach */
cscfg_csdev_disable_active_config(struct coresight_device * csdev)1117f8cce2ffSMike Leach void cscfg_csdev_disable_active_config(struct coresight_device *csdev)
1118f8cce2ffSMike Leach {
1119f8cce2ffSMike Leach struct cscfg_config_csdev *config_csdev;
1120f8cce2ffSMike Leach unsigned long flags;
1121f8cce2ffSMike Leach
1122f8cce2ffSMike Leach /*
1123f8cce2ffSMike Leach * Check if we have an active config, and that it was successfully enabled.
1124f8cce2ffSMike Leach * If it was not enabled, we have no work to do, otherwise mark as disabled.
1125f8cce2ffSMike Leach * Clear the active config pointer.
1126f8cce2ffSMike Leach */
1127f8cce2ffSMike Leach spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
1128f8cce2ffSMike Leach config_csdev = (struct cscfg_config_csdev *)csdev->active_cscfg_ctxt;
1129f8cce2ffSMike Leach if (config_csdev) {
1130f8cce2ffSMike Leach if (!config_csdev->enabled)
1131f8cce2ffSMike Leach config_csdev = NULL;
1132f8cce2ffSMike Leach else
1133f8cce2ffSMike Leach config_csdev->enabled = false;
1134f8cce2ffSMike Leach }
1135f8cce2ffSMike Leach csdev->active_cscfg_ctxt = NULL;
1136f8cce2ffSMike Leach spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
1137f8cce2ffSMike Leach
1138f8cce2ffSMike Leach /* true if there was an enabled active config */
1139f8cce2ffSMike Leach if (config_csdev)
1140f8cce2ffSMike Leach cscfg_csdev_disable_config(config_csdev);
1141f8cce2ffSMike Leach }
1142f8cce2ffSMike Leach EXPORT_SYMBOL_GPL(cscfg_csdev_disable_active_config);
1143f8cce2ffSMike Leach
114485e2414cSMike Leach /* Initialise system configuration management device. */
114585e2414cSMike Leach
cscfg_device(void)114685e2414cSMike Leach struct device *cscfg_device(void)
114785e2414cSMike Leach {
114885e2414cSMike Leach return cscfg_mgr ? &cscfg_mgr->dev : NULL;
114985e2414cSMike Leach }
115085e2414cSMike Leach
115185e2414cSMike Leach /* Must have a release function or the kernel will complain on module unload */
cscfg_dev_release(struct device * dev)115285e2414cSMike Leach static void cscfg_dev_release(struct device *dev)
115385e2414cSMike Leach {
1154199380deSMike Leach mutex_lock(&cscfg_mutex);
115585e2414cSMike Leach kfree(cscfg_mgr);
115685e2414cSMike Leach cscfg_mgr = NULL;
1157199380deSMike Leach mutex_unlock(&cscfg_mutex);
115885e2414cSMike Leach }
115985e2414cSMike Leach
116085e2414cSMike Leach /* a device is needed to "own" some kernel elements such as sysfs entries. */
cscfg_create_device(void)116185e2414cSMike Leach static int cscfg_create_device(void)
116285e2414cSMike Leach {
116385e2414cSMike Leach struct device *dev;
116485e2414cSMike Leach int err = -ENOMEM;
116585e2414cSMike Leach
116685e2414cSMike Leach mutex_lock(&cscfg_mutex);
116785e2414cSMike Leach if (cscfg_mgr) {
116885e2414cSMike Leach err = -EINVAL;
116985e2414cSMike Leach goto create_dev_exit_unlock;
117085e2414cSMike Leach }
117185e2414cSMike Leach
117285e2414cSMike Leach cscfg_mgr = kzalloc(sizeof(struct cscfg_manager), GFP_KERNEL);
117385e2414cSMike Leach if (!cscfg_mgr)
117485e2414cSMike Leach goto create_dev_exit_unlock;
117585e2414cSMike Leach
1176199380deSMike Leach /* initialise the cscfg_mgr structure */
1177199380deSMike Leach INIT_LIST_HEAD(&cscfg_mgr->csdev_desc_list);
1178199380deSMike Leach INIT_LIST_HEAD(&cscfg_mgr->feat_desc_list);
1179199380deSMike Leach INIT_LIST_HEAD(&cscfg_mgr->config_desc_list);
1180199380deSMike Leach INIT_LIST_HEAD(&cscfg_mgr->load_order_list);
1181199380deSMike Leach atomic_set(&cscfg_mgr->sys_active_cnt, 0);
1182*8add26f7SMike Leach cscfg_mgr->load_state = CSCFG_NONE;
1183199380deSMike Leach
118485e2414cSMike Leach /* setup the device */
118585e2414cSMike Leach dev = cscfg_device();
118685e2414cSMike Leach dev->release = cscfg_dev_release;
118785e2414cSMike Leach dev->init_name = "cs_system_cfg";
118885e2414cSMike Leach
118985e2414cSMike Leach err = device_register(dev);
119085e2414cSMike Leach if (err)
1191cfa5dbcdSMiaoqian Lin put_device(dev);
119285e2414cSMike Leach
119385e2414cSMike Leach create_dev_exit_unlock:
119485e2414cSMike Leach mutex_unlock(&cscfg_mutex);
119585e2414cSMike Leach return err;
119685e2414cSMike Leach }
119785e2414cSMike Leach
1198199380deSMike Leach /*
1199199380deSMike Leach * Loading and unloading is generally on user discretion.
1200199380deSMike Leach * If exiting due to coresight module unload, we need to unload any configurations that remain,
1201199380deSMike Leach * before we unregister the configfs intrastructure.
1202199380deSMike Leach *
1203199380deSMike Leach * Do this by walking the load_owner list and taking appropriate action, depending on the load
1204199380deSMike Leach * owner type.
1205199380deSMike Leach */
cscfg_unload_cfgs_on_exit(void)1206199380deSMike Leach static void cscfg_unload_cfgs_on_exit(void)
1207199380deSMike Leach {
1208199380deSMike Leach struct cscfg_load_owner_info *owner_info = NULL;
1209199380deSMike Leach
1210199380deSMike Leach /*
1211199380deSMike Leach * grab the mutex - even though we are exiting, some configfs files
1212199380deSMike Leach * may still be live till we dump them, so ensure list data is
1213199380deSMike Leach * protected from a race condition.
1214199380deSMike Leach */
1215199380deSMike Leach mutex_lock(&cscfg_mutex);
1216199380deSMike Leach while (!list_empty(&cscfg_mgr->load_order_list)) {
1217199380deSMike Leach
1218199380deSMike Leach /* remove in reverse order of loading */
1219199380deSMike Leach owner_info = list_last_entry(&cscfg_mgr->load_order_list,
1220199380deSMike Leach struct cscfg_load_owner_info, item);
1221199380deSMike Leach
1222199380deSMike Leach /* action according to type */
1223199380deSMike Leach switch (owner_info->type) {
1224199380deSMike Leach case CSCFG_OWNER_PRELOAD:
1225199380deSMike Leach /*
1226199380deSMike Leach * preloaded descriptors are statically allocated in
1227199380deSMike Leach * this module - just need to unload dynamic items from
1228199380deSMike Leach * csdev lists, and remove from configfs directories.
1229199380deSMike Leach */
1230199380deSMike Leach pr_info("cscfg: unloading preloaded configurations\n");
1231199380deSMike Leach break;
1232199380deSMike Leach
1233199380deSMike Leach case CSCFG_OWNER_MODULE:
1234199380deSMike Leach /*
1235199380deSMike Leach * this is an error - the loadable module must have been unloaded prior
1236199380deSMike Leach * to the coresight module unload. Therefore that module has not
1237199380deSMike Leach * correctly unloaded configs in its own exit code.
1238199380deSMike Leach * Nothing to do other than emit an error string as the static descriptor
1239199380deSMike Leach * references we need to unload will have disappeared with the module.
1240199380deSMike Leach */
1241199380deSMike Leach pr_err("cscfg: ERROR: prior module failed to unload configuration\n");
1242199380deSMike Leach goto list_remove;
1243199380deSMike Leach }
1244199380deSMike Leach
1245199380deSMike Leach /* remove from configfs - outside the scope of the list mutex */
1246199380deSMike Leach mutex_unlock(&cscfg_mutex);
1247199380deSMike Leach cscfg_fs_unregister_cfgs_feats(owner_info);
1248199380deSMike Leach mutex_lock(&cscfg_mutex);
1249199380deSMike Leach
1250199380deSMike Leach /* Next unload from csdev lists. */
1251199380deSMike Leach cscfg_unload_owned_cfgs_feats(owner_info);
1252199380deSMike Leach
1253199380deSMike Leach list_remove:
1254199380deSMike Leach /* remove from load order list */
1255199380deSMike Leach list_del(&owner_info->item);
1256199380deSMike Leach }
1257199380deSMike Leach mutex_unlock(&cscfg_mutex);
1258199380deSMike Leach }
1259199380deSMike Leach
cscfg_clear_device(void)126085e2414cSMike Leach static void cscfg_clear_device(void)
126185e2414cSMike Leach {
1262199380deSMike Leach cscfg_unload_cfgs_on_exit();
1263a13d5a24SMike Leach cscfg_configfs_release(cscfg_mgr);
126485e2414cSMike Leach device_unregister(cscfg_device());
126585e2414cSMike Leach }
126685e2414cSMike Leach
126785e2414cSMike Leach /* Initialise system config management API device */
cscfg_init(void)126885e2414cSMike Leach int __init cscfg_init(void)
126985e2414cSMike Leach {
127085e2414cSMike Leach int err = 0;
127185e2414cSMike Leach
1272199380deSMike Leach /* create the device and init cscfg_mgr */
127385e2414cSMike Leach err = cscfg_create_device();
127485e2414cSMike Leach if (err)
127585e2414cSMike Leach return err;
127685e2414cSMike Leach
1277199380deSMike Leach /* initialise configfs subsystem */
1278a13d5a24SMike Leach err = cscfg_configfs_init(cscfg_mgr);
1279a13d5a24SMike Leach if (err)
1280a13d5a24SMike Leach goto exit_err;
1281a13d5a24SMike Leach
12827fdc9bb2SMike Leach /* preload built-in configurations */
1283da7000e8SMike Leach err = cscfg_preload(THIS_MODULE);
12847fdc9bb2SMike Leach if (err)
12857fdc9bb2SMike Leach goto exit_err;
12867fdc9bb2SMike Leach
128785e2414cSMike Leach dev_info(cscfg_device(), "CoreSight Configuration manager initialised");
128885e2414cSMike Leach return 0;
12897fdc9bb2SMike Leach
12907fdc9bb2SMike Leach exit_err:
12917fdc9bb2SMike Leach cscfg_clear_device();
12927fdc9bb2SMike Leach return err;
129385e2414cSMike Leach }
129485e2414cSMike Leach
cscfg_exit(void)129585e2414cSMike Leach void cscfg_exit(void)
129685e2414cSMike Leach {
129785e2414cSMike Leach cscfg_clear_device();
129885e2414cSMike Leach }
1299