Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (c) 2020 Linaro Limited, All rights reserved.
0004  * Author: Mike Leach <mike.leach@linaro.org>
0005  */
0006 
0007 #include <linux/platform_device.h>
0008 #include <linux/slab.h>
0009 
0010 #include "coresight-config.h"
0011 #include "coresight-etm-perf.h"
0012 #include "coresight-syscfg.h"
0013 #include "coresight-syscfg-configfs.h"
0014 
0015 /*
0016  * cscfg_ API manages configurations and features for the entire coresight
0017  * infrastructure.
0018  *
0019  * It allows the loading of configurations and features, and loads these into
0020  * coresight devices as appropriate.
0021  */
0022 
0023 /* protect the cscsg_data and device */
0024 static DEFINE_MUTEX(cscfg_mutex);
0025 
0026 /* only one of these */
0027 static struct cscfg_manager *cscfg_mgr;
0028 
0029 /* load features and configuations into the lists */
0030 
0031 /* get name feature instance from a coresight device list of features */
0032 static struct cscfg_feature_csdev *
0033 cscfg_get_feat_csdev(struct coresight_device *csdev, const char *name)
0034 {
0035     struct cscfg_feature_csdev *feat_csdev = NULL;
0036 
0037     list_for_each_entry(feat_csdev, &csdev->feature_csdev_list, node) {
0038         if (strcmp(feat_csdev->feat_desc->name, name) == 0)
0039             return feat_csdev;
0040     }
0041     return NULL;
0042 }
0043 
0044 /* allocate the device config instance - with max number of used features */
0045 static struct cscfg_config_csdev *
0046 cscfg_alloc_csdev_cfg(struct coresight_device *csdev, int nr_feats)
0047 {
0048     struct cscfg_config_csdev *config_csdev = NULL;
0049     struct device *dev = csdev->dev.parent;
0050 
0051     /* this is being allocated using the devm for the coresight device */
0052     config_csdev = devm_kzalloc(dev,
0053                     offsetof(struct cscfg_config_csdev, feats_csdev[nr_feats]),
0054                     GFP_KERNEL);
0055     if (!config_csdev)
0056         return NULL;
0057 
0058     config_csdev->csdev = csdev;
0059     return config_csdev;
0060 }
0061 
0062 /* Load a config into a device if there are any feature matches between config and device */
0063 static int cscfg_add_csdev_cfg(struct coresight_device *csdev,
0064                    struct cscfg_config_desc *config_desc)
0065 {
0066     struct cscfg_config_csdev *config_csdev = NULL;
0067     struct cscfg_feature_csdev *feat_csdev;
0068     unsigned long flags;
0069     int i;
0070 
0071     /* look at each required feature and see if it matches any feature on the device */
0072     for (i = 0; i < config_desc->nr_feat_refs; i++) {
0073         /* look for a matching name */
0074         feat_csdev = cscfg_get_feat_csdev(csdev, config_desc->feat_ref_names[i]);
0075         if (feat_csdev) {
0076             /*
0077              * At least one feature on this device matches the config
0078              * add a config instance to the device and a reference to the feature.
0079              */
0080             if (!config_csdev) {
0081                 config_csdev = cscfg_alloc_csdev_cfg(csdev,
0082                                      config_desc->nr_feat_refs);
0083                 if (!config_csdev)
0084                     return -ENOMEM;
0085                 config_csdev->config_desc = config_desc;
0086             }
0087             config_csdev->feats_csdev[config_csdev->nr_feat++] = feat_csdev;
0088         }
0089     }
0090     /* if matched features, add config to device.*/
0091     if (config_csdev) {
0092         spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
0093         list_add(&config_csdev->node, &csdev->config_csdev_list);
0094         spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
0095     }
0096 
0097     return 0;
0098 }
0099 
0100 /*
0101  * Add the config to the set of registered devices - call with mutex locked.
0102  * Iterates through devices - any device that matches one or more of the
0103  * configuration features will load it, the others will ignore it.
0104  */
0105 static int cscfg_add_cfg_to_csdevs(struct cscfg_config_desc *config_desc)
0106 {
0107     struct cscfg_registered_csdev *csdev_item;
0108     int err;
0109 
0110     list_for_each_entry(csdev_item, &cscfg_mgr->csdev_desc_list, item) {
0111         err = cscfg_add_csdev_cfg(csdev_item->csdev, config_desc);
0112         if (err)
0113             return err;
0114     }
0115     return 0;
0116 }
0117 
0118 /*
0119  * Allocate a feature object for load into a csdev.
0120  * memory allocated using the csdev->dev object using devm managed allocator.
0121  */
0122 static struct cscfg_feature_csdev *
0123 cscfg_alloc_csdev_feat(struct coresight_device *csdev, struct cscfg_feature_desc *feat_desc)
0124 {
0125     struct cscfg_feature_csdev *feat_csdev = NULL;
0126     struct device *dev = csdev->dev.parent;
0127     int i;
0128 
0129     feat_csdev = devm_kzalloc(dev, sizeof(struct cscfg_feature_csdev), GFP_KERNEL);
0130     if (!feat_csdev)
0131         return NULL;
0132 
0133     /* parameters are optional - could be 0 */
0134     feat_csdev->nr_params = feat_desc->nr_params;
0135 
0136     /*
0137      * if we need parameters, zero alloc the space here, the load routine in
0138      * the csdev device driver will fill out some information according to
0139      * feature descriptor.
0140      */
0141     if (feat_csdev->nr_params) {
0142         feat_csdev->params_csdev = devm_kcalloc(dev, feat_csdev->nr_params,
0143                             sizeof(struct cscfg_parameter_csdev),
0144                             GFP_KERNEL);
0145         if (!feat_csdev->params_csdev)
0146             return NULL;
0147 
0148         /*
0149          * fill in the feature reference in the param - other fields
0150          * handled by loader in csdev.
0151          */
0152         for (i = 0; i < feat_csdev->nr_params; i++)
0153             feat_csdev->params_csdev[i].feat_csdev = feat_csdev;
0154     }
0155 
0156     /*
0157      * Always have registers to program - again the load routine in csdev device
0158      * will fill out according to feature descriptor and device requirements.
0159      */
0160     feat_csdev->nr_regs = feat_desc->nr_regs;
0161     feat_csdev->regs_csdev = devm_kcalloc(dev, feat_csdev->nr_regs,
0162                           sizeof(struct cscfg_regval_csdev),
0163                           GFP_KERNEL);
0164     if (!feat_csdev->regs_csdev)
0165         return NULL;
0166 
0167     /* load the feature default values */
0168     feat_csdev->feat_desc = feat_desc;
0169     feat_csdev->csdev = csdev;
0170 
0171     return feat_csdev;
0172 }
0173 
0174 /* load one feature into one coresight device */
0175 static int cscfg_load_feat_csdev(struct coresight_device *csdev,
0176                  struct cscfg_feature_desc *feat_desc,
0177                  struct cscfg_csdev_feat_ops *ops)
0178 {
0179     struct cscfg_feature_csdev *feat_csdev;
0180     unsigned long flags;
0181     int err;
0182 
0183     if (!ops->load_feat)
0184         return -EINVAL;
0185 
0186     feat_csdev = cscfg_alloc_csdev_feat(csdev, feat_desc);
0187     if (!feat_csdev)
0188         return -ENOMEM;
0189 
0190     /* load the feature into the device */
0191     err = ops->load_feat(csdev, feat_csdev);
0192     if (err)
0193         return err;
0194 
0195     /* add to internal csdev feature list & initialise using reset call */
0196     cscfg_reset_feat(feat_csdev);
0197     spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
0198     list_add(&feat_csdev->node, &csdev->feature_csdev_list);
0199     spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
0200 
0201     return 0;
0202 }
0203 
0204 /*
0205  * Add feature to any matching devices - call with mutex locked.
0206  * Iterates through devices - any device that matches the feature will be
0207  * called to load it.
0208  */
0209 static int cscfg_add_feat_to_csdevs(struct cscfg_feature_desc *feat_desc)
0210 {
0211     struct cscfg_registered_csdev *csdev_item;
0212     int err;
0213 
0214     list_for_each_entry(csdev_item, &cscfg_mgr->csdev_desc_list, item) {
0215         if (csdev_item->match_flags & feat_desc->match_flags) {
0216             err = cscfg_load_feat_csdev(csdev_item->csdev, feat_desc, &csdev_item->ops);
0217             if (err)
0218                 return err;
0219         }
0220     }
0221     return 0;
0222 }
0223 
0224 /* check feature list for a named feature - call with mutex locked. */
0225 static bool cscfg_match_list_feat(const char *name)
0226 {
0227     struct cscfg_feature_desc *feat_desc;
0228 
0229     list_for_each_entry(feat_desc, &cscfg_mgr->feat_desc_list, item) {
0230         if (strcmp(feat_desc->name, name) == 0)
0231             return true;
0232     }
0233     return false;
0234 }
0235 
0236 /* check all feat needed for cfg are in the list - call with mutex locked. */
0237 static int cscfg_check_feat_for_cfg(struct cscfg_config_desc *config_desc)
0238 {
0239     int i;
0240 
0241     for (i = 0; i < config_desc->nr_feat_refs; i++)
0242         if (!cscfg_match_list_feat(config_desc->feat_ref_names[i]))
0243             return -EINVAL;
0244     return 0;
0245 }
0246 
0247 /*
0248  * load feature - add to feature list.
0249  */
0250 static int cscfg_load_feat(struct cscfg_feature_desc *feat_desc)
0251 {
0252     int err;
0253     struct cscfg_feature_desc *feat_desc_exist;
0254 
0255     /* new feature must have unique name */
0256     list_for_each_entry(feat_desc_exist, &cscfg_mgr->feat_desc_list, item) {
0257         if (!strcmp(feat_desc_exist->name, feat_desc->name))
0258             return -EEXIST;
0259     }
0260 
0261     /* add feature to any matching registered devices */
0262     err = cscfg_add_feat_to_csdevs(feat_desc);
0263     if (err)
0264         return err;
0265 
0266     list_add(&feat_desc->item, &cscfg_mgr->feat_desc_list);
0267     return 0;
0268 }
0269 
0270 /*
0271  * load config into the system - validate used features exist then add to
0272  * config list.
0273  */
0274 static int cscfg_load_config(struct cscfg_config_desc *config_desc)
0275 {
0276     int err;
0277     struct cscfg_config_desc *config_desc_exist;
0278 
0279     /* new configuration must have a unique name */
0280     list_for_each_entry(config_desc_exist, &cscfg_mgr->config_desc_list, item) {
0281         if (!strcmp(config_desc_exist->name, config_desc->name))
0282             return -EEXIST;
0283     }
0284 
0285     /* validate features are present */
0286     err = cscfg_check_feat_for_cfg(config_desc);
0287     if (err)
0288         return err;
0289 
0290     /* add config to any matching registered device */
0291     err = cscfg_add_cfg_to_csdevs(config_desc);
0292     if (err)
0293         return err;
0294 
0295     /* add config to perf fs to allow selection */
0296     err = etm_perf_add_symlink_cscfg(cscfg_device(), config_desc);
0297     if (err)
0298         return err;
0299 
0300     list_add(&config_desc->item, &cscfg_mgr->config_desc_list);
0301     atomic_set(&config_desc->active_cnt, 0);
0302     return 0;
0303 }
0304 
0305 /* get a feature descriptor by name */
0306 const struct cscfg_feature_desc *cscfg_get_named_feat_desc(const char *name)
0307 {
0308     const struct cscfg_feature_desc *feat_desc = NULL, *feat_desc_item;
0309 
0310     mutex_lock(&cscfg_mutex);
0311 
0312     list_for_each_entry(feat_desc_item, &cscfg_mgr->feat_desc_list, item) {
0313         if (strcmp(feat_desc_item->name, name) == 0) {
0314             feat_desc = feat_desc_item;
0315             break;
0316         }
0317     }
0318 
0319     mutex_unlock(&cscfg_mutex);
0320     return feat_desc;
0321 }
0322 
0323 /* called with cscfg_mutex held */
0324 static struct cscfg_feature_csdev *
0325 cscfg_csdev_get_feat_from_desc(struct coresight_device *csdev,
0326                    struct cscfg_feature_desc *feat_desc)
0327 {
0328     struct cscfg_feature_csdev *feat_csdev;
0329 
0330     list_for_each_entry(feat_csdev, &csdev->feature_csdev_list, node) {
0331         if (feat_csdev->feat_desc == feat_desc)
0332             return feat_csdev;
0333     }
0334     return NULL;
0335 }
0336 
0337 int cscfg_update_feat_param_val(struct cscfg_feature_desc *feat_desc,
0338                 int param_idx, u64 value)
0339 {
0340     int err = 0;
0341     struct cscfg_feature_csdev *feat_csdev;
0342     struct cscfg_registered_csdev *csdev_item;
0343 
0344     mutex_lock(&cscfg_mutex);
0345 
0346     /* check if any config active & return busy */
0347     if (atomic_read(&cscfg_mgr->sys_active_cnt)) {
0348         err = -EBUSY;
0349         goto unlock_exit;
0350     }
0351 
0352     /* set the value */
0353     if ((param_idx < 0) || (param_idx >= feat_desc->nr_params)) {
0354         err = -EINVAL;
0355         goto unlock_exit;
0356     }
0357     feat_desc->params_desc[param_idx].value = value;
0358 
0359     /* update loaded instances.*/
0360     list_for_each_entry(csdev_item, &cscfg_mgr->csdev_desc_list, item) {
0361         feat_csdev = cscfg_csdev_get_feat_from_desc(csdev_item->csdev, feat_desc);
0362         if (feat_csdev)
0363             feat_csdev->params_csdev[param_idx].current_value = value;
0364     }
0365 
0366 unlock_exit:
0367     mutex_unlock(&cscfg_mutex);
0368     return err;
0369 }
0370 
0371 /*
0372  * Conditionally up reference count on owner to prevent unload.
0373  *
0374  * module loaded configs need to be locked in to prevent premature unload.
0375  */
0376 static int cscfg_owner_get(struct cscfg_load_owner_info *owner_info)
0377 {
0378     if ((owner_info->type == CSCFG_OWNER_MODULE) &&
0379         (!try_module_get(owner_info->owner_handle)))
0380         return -EINVAL;
0381     return 0;
0382 }
0383 
0384 /* conditionally lower ref count on an owner */
0385 static void cscfg_owner_put(struct cscfg_load_owner_info *owner_info)
0386 {
0387     if (owner_info->type == CSCFG_OWNER_MODULE)
0388         module_put(owner_info->owner_handle);
0389 }
0390 
0391 static void cscfg_remove_owned_csdev_configs(struct coresight_device *csdev, void *load_owner)
0392 {
0393     struct cscfg_config_csdev *config_csdev, *tmp;
0394 
0395     if (list_empty(&csdev->config_csdev_list))
0396         return;
0397 
0398     list_for_each_entry_safe(config_csdev, tmp, &csdev->config_csdev_list, node) {
0399         if (config_csdev->config_desc->load_owner == load_owner)
0400             list_del(&config_csdev->node);
0401     }
0402 }
0403 
0404 static void cscfg_remove_owned_csdev_features(struct coresight_device *csdev, void *load_owner)
0405 {
0406     struct cscfg_feature_csdev *feat_csdev, *tmp;
0407 
0408     if (list_empty(&csdev->feature_csdev_list))
0409         return;
0410 
0411     list_for_each_entry_safe(feat_csdev, tmp, &csdev->feature_csdev_list, node) {
0412         if (feat_csdev->feat_desc->load_owner == load_owner)
0413             list_del(&feat_csdev->node);
0414     }
0415 }
0416 
0417 /*
0418  * Unregister all configuration and features from configfs owned by load_owner.
0419  * Although this is called without the list mutex being held, it is in the
0420  * context of an unload operation which are strictly serialised,
0421  * so the lists cannot change during this call.
0422  */
0423 static void cscfg_fs_unregister_cfgs_feats(void *load_owner)
0424 {
0425     struct cscfg_config_desc *config_desc;
0426     struct cscfg_feature_desc *feat_desc;
0427 
0428     list_for_each_entry(config_desc, &cscfg_mgr->config_desc_list, item) {
0429         if (config_desc->load_owner == load_owner)
0430             cscfg_configfs_del_config(config_desc);
0431     }
0432     list_for_each_entry(feat_desc, &cscfg_mgr->feat_desc_list, item) {
0433         if (feat_desc->load_owner == load_owner)
0434             cscfg_configfs_del_feature(feat_desc);
0435     }
0436 }
0437 
0438 /*
0439  * removal is relatively easy - just remove from all lists, anything that
0440  * matches the owner. Memory for the descriptors will be managed by the owner,
0441  * memory for the csdev items is devm_ allocated with the individual csdev
0442  * devices.
0443  */
0444 static void cscfg_unload_owned_cfgs_feats(void *load_owner)
0445 {
0446     struct cscfg_config_desc *config_desc, *cfg_tmp;
0447     struct cscfg_feature_desc *feat_desc, *feat_tmp;
0448     struct cscfg_registered_csdev *csdev_item;
0449 
0450     lockdep_assert_held(&cscfg_mutex);
0451 
0452     /* remove from each csdev instance feature and config lists */
0453     list_for_each_entry(csdev_item, &cscfg_mgr->csdev_desc_list, item) {
0454         /*
0455          * for each csdev, check the loaded lists and remove if
0456          * referenced descriptor is owned
0457          */
0458         cscfg_remove_owned_csdev_configs(csdev_item->csdev, load_owner);
0459         cscfg_remove_owned_csdev_features(csdev_item->csdev, load_owner);
0460     }
0461 
0462     /* remove from the config descriptor lists */
0463     list_for_each_entry_safe(config_desc, cfg_tmp, &cscfg_mgr->config_desc_list, item) {
0464         if (config_desc->load_owner == load_owner) {
0465             etm_perf_del_symlink_cscfg(config_desc);
0466             list_del(&config_desc->item);
0467         }
0468     }
0469 
0470     /* remove from the feature descriptor lists */
0471     list_for_each_entry_safe(feat_desc, feat_tmp, &cscfg_mgr->feat_desc_list, item) {
0472         if (feat_desc->load_owner == load_owner) {
0473             list_del(&feat_desc->item);
0474         }
0475     }
0476 }
0477 
0478 /*
0479  * load the features and configs to the lists - called with list mutex held
0480  */
0481 static int cscfg_load_owned_cfgs_feats(struct cscfg_config_desc **config_descs,
0482                        struct cscfg_feature_desc **feat_descs,
0483                        struct cscfg_load_owner_info *owner_info)
0484 {
0485     int i, err;
0486 
0487     lockdep_assert_held(&cscfg_mutex);
0488 
0489     /* load features first */
0490     if (feat_descs) {
0491         for (i = 0; feat_descs[i]; i++) {
0492             err = cscfg_load_feat(feat_descs[i]);
0493             if (err) {
0494                 pr_err("coresight-syscfg: Failed to load feature %s\n",
0495                        feat_descs[i]->name);
0496                 return err;
0497             }
0498             feat_descs[i]->load_owner = owner_info;
0499         }
0500     }
0501 
0502     /* next any configurations to check feature dependencies */
0503     if (config_descs) {
0504         for (i = 0; config_descs[i]; i++) {
0505             err = cscfg_load_config(config_descs[i]);
0506             if (err) {
0507                 pr_err("coresight-syscfg: Failed to load configuration %s\n",
0508                        config_descs[i]->name);
0509                 return err;
0510             }
0511             config_descs[i]->load_owner = owner_info;
0512             config_descs[i]->available = false;
0513         }
0514     }
0515     return 0;
0516 }
0517 
0518 /* set configurations as available to activate at the end of the load process */
0519 static void cscfg_set_configs_available(struct cscfg_config_desc **config_descs)
0520 {
0521     int i;
0522 
0523     lockdep_assert_held(&cscfg_mutex);
0524 
0525     if (config_descs) {
0526         for (i = 0; config_descs[i]; i++)
0527             config_descs[i]->available = true;
0528     }
0529 }
0530 
0531 /*
0532  * Create and register each of the configurations and features with configfs.
0533  * Called without mutex being held.
0534  */
0535 static int cscfg_fs_register_cfgs_feats(struct cscfg_config_desc **config_descs,
0536                     struct cscfg_feature_desc **feat_descs)
0537 {
0538     int i, err;
0539 
0540     if (feat_descs) {
0541         for (i = 0; feat_descs[i]; i++) {
0542             err = cscfg_configfs_add_feature(feat_descs[i]);
0543             if (err)
0544                 return err;
0545         }
0546     }
0547     if (config_descs) {
0548         for (i = 0; config_descs[i]; i++) {
0549             err = cscfg_configfs_add_config(config_descs[i]);
0550             if (err)
0551                 return err;
0552         }
0553     }
0554     return 0;
0555 }
0556 
0557 /**
0558  * cscfg_load_config_sets - API function to load feature and config sets.
0559  *
0560  * Take a 0 terminated array of feature descriptors and/or configuration
0561  * descriptors and load into the system.
0562  * Features are loaded first to ensure configuration dependencies can be met.
0563  *
0564  * To facilitate dynamic loading and unloading, features and configurations
0565  * have a "load_owner", to allow later unload by the same owner. An owner may
0566  * be a loadable module or configuration dynamically created via configfs.
0567  * As later loaded configurations can use earlier loaded features, creating load
0568  * dependencies, a load order list is maintained. Unload is strictly in the
0569  * reverse order to load.
0570  *
0571  * @config_descs: 0 terminated array of configuration descriptors.
0572  * @feat_descs:   0 terminated array of feature descriptors.
0573  * @owner_info:   Information on the owner of this set.
0574  */
0575 int cscfg_load_config_sets(struct cscfg_config_desc **config_descs,
0576                struct cscfg_feature_desc **feat_descs,
0577                struct cscfg_load_owner_info *owner_info)
0578 {
0579     int err = 0;
0580 
0581     mutex_lock(&cscfg_mutex);
0582     if (cscfg_mgr->load_state != CSCFG_NONE) {
0583         mutex_unlock(&cscfg_mutex);
0584         return -EBUSY;
0585     }
0586     cscfg_mgr->load_state = CSCFG_LOAD;
0587 
0588     /* first load and add to the lists */
0589     err = cscfg_load_owned_cfgs_feats(config_descs, feat_descs, owner_info);
0590     if (err)
0591         goto err_clean_load;
0592 
0593     /* add the load owner to the load order list */
0594     list_add_tail(&owner_info->item, &cscfg_mgr->load_order_list);
0595     if (!list_is_singular(&cscfg_mgr->load_order_list)) {
0596         /* lock previous item in load order list */
0597         err = cscfg_owner_get(list_prev_entry(owner_info, item));
0598         if (err)
0599             goto err_clean_owner_list;
0600     }
0601 
0602     /*
0603      * make visible to configfs - configfs manipulation must occur outside
0604      * the list mutex lock to avoid circular lockdep issues with configfs
0605      * built in mutexes and semaphores. This is safe as it is not possible
0606      * to start a new load/unload operation till the current one is done.
0607      */
0608     mutex_unlock(&cscfg_mutex);
0609 
0610     /* create the configfs elements */
0611     err = cscfg_fs_register_cfgs_feats(config_descs, feat_descs);
0612     mutex_lock(&cscfg_mutex);
0613 
0614     if (err)
0615         goto err_clean_cfs;
0616 
0617     /* mark any new configs as available for activation */
0618     cscfg_set_configs_available(config_descs);
0619     goto exit_unlock;
0620 
0621 err_clean_cfs:
0622     /* cleanup after error registering with configfs */
0623     cscfg_fs_unregister_cfgs_feats(owner_info);
0624 
0625     if (!list_is_singular(&cscfg_mgr->load_order_list))
0626         cscfg_owner_put(list_prev_entry(owner_info, item));
0627 
0628 err_clean_owner_list:
0629     list_del(&owner_info->item);
0630 
0631 err_clean_load:
0632     cscfg_unload_owned_cfgs_feats(owner_info);
0633 
0634 exit_unlock:
0635     cscfg_mgr->load_state = CSCFG_NONE;
0636     mutex_unlock(&cscfg_mutex);
0637     return err;
0638 }
0639 EXPORT_SYMBOL_GPL(cscfg_load_config_sets);
0640 
0641 /**
0642  * cscfg_unload_config_sets - unload a set of configurations by owner.
0643  *
0644  * Dynamic unload of configuration and feature sets is done on the basis of
0645  * the load owner of that set. Later loaded configurations can depend on
0646  * features loaded earlier.
0647  *
0648  * Therefore, unload is only possible if:-
0649  * 1) no configurations are active.
0650  * 2) the set being unloaded was the last to be loaded to maintain dependencies.
0651  *
0652  * Once the unload operation commences, we disallow any configuration being
0653  * made active until it is complete.
0654  *
0655  * @owner_info: Information on owner for set being unloaded.
0656  */
0657 int cscfg_unload_config_sets(struct cscfg_load_owner_info *owner_info)
0658 {
0659     int err = 0;
0660     struct cscfg_load_owner_info *load_list_item = NULL;
0661 
0662     mutex_lock(&cscfg_mutex);
0663     if (cscfg_mgr->load_state != CSCFG_NONE) {
0664         mutex_unlock(&cscfg_mutex);
0665         return -EBUSY;
0666     }
0667 
0668     /* unload op in progress also prevents activation of any config */
0669     cscfg_mgr->load_state = CSCFG_UNLOAD;
0670 
0671     /* cannot unload if anything is active */
0672     if (atomic_read(&cscfg_mgr->sys_active_cnt)) {
0673         err = -EBUSY;
0674         goto exit_unlock;
0675     }
0676 
0677     /* cannot unload if not last loaded in load order */
0678     if (!list_empty(&cscfg_mgr->load_order_list)) {
0679         load_list_item = list_last_entry(&cscfg_mgr->load_order_list,
0680                          struct cscfg_load_owner_info, item);
0681         if (load_list_item != owner_info)
0682             load_list_item = NULL;
0683     }
0684 
0685     if (!load_list_item) {
0686         err = -EINVAL;
0687         goto exit_unlock;
0688     }
0689 
0690     /* remove from configfs - again outside the scope of the list mutex */
0691     mutex_unlock(&cscfg_mutex);
0692     cscfg_fs_unregister_cfgs_feats(owner_info);
0693     mutex_lock(&cscfg_mutex);
0694 
0695     /* unload everything from lists belonging to load_owner */
0696     cscfg_unload_owned_cfgs_feats(owner_info);
0697 
0698     /* remove from load order list */
0699     if (!list_is_singular(&cscfg_mgr->load_order_list)) {
0700         /* unlock previous item in load order list */
0701         cscfg_owner_put(list_prev_entry(owner_info, item));
0702     }
0703     list_del(&owner_info->item);
0704 
0705 exit_unlock:
0706     cscfg_mgr->load_state = CSCFG_NONE;
0707     mutex_unlock(&cscfg_mutex);
0708     return err;
0709 }
0710 EXPORT_SYMBOL_GPL(cscfg_unload_config_sets);
0711 
0712 /* Handle coresight device registration and add configs and features to devices */
0713 
0714 /* iterate through config lists and load matching configs to device */
0715 static int cscfg_add_cfgs_csdev(struct coresight_device *csdev)
0716 {
0717     struct cscfg_config_desc *config_desc;
0718     int err = 0;
0719 
0720     list_for_each_entry(config_desc, &cscfg_mgr->config_desc_list, item) {
0721         err = cscfg_add_csdev_cfg(csdev, config_desc);
0722         if (err)
0723             break;
0724     }
0725     return err;
0726 }
0727 
0728 /* iterate through feature lists and load matching features to device */
0729 static int cscfg_add_feats_csdev(struct coresight_device *csdev,
0730                  u32 match_flags,
0731                  struct cscfg_csdev_feat_ops *ops)
0732 {
0733     struct cscfg_feature_desc *feat_desc;
0734     int err = 0;
0735 
0736     if (!ops->load_feat)
0737         return -EINVAL;
0738 
0739     list_for_each_entry(feat_desc, &cscfg_mgr->feat_desc_list, item) {
0740         if (feat_desc->match_flags & match_flags) {
0741             err = cscfg_load_feat_csdev(csdev, feat_desc, ops);
0742             if (err)
0743                 break;
0744         }
0745     }
0746     return err;
0747 }
0748 
0749 /* Add coresight device to list and copy its matching info */
0750 static int cscfg_list_add_csdev(struct coresight_device *csdev,
0751                 u32 match_flags,
0752                 struct cscfg_csdev_feat_ops *ops)
0753 {
0754     struct cscfg_registered_csdev *csdev_item;
0755 
0756     /* allocate the list entry structure */
0757     csdev_item = kzalloc(sizeof(struct cscfg_registered_csdev), GFP_KERNEL);
0758     if (!csdev_item)
0759         return -ENOMEM;
0760 
0761     csdev_item->csdev = csdev;
0762     csdev_item->match_flags = match_flags;
0763     csdev_item->ops.load_feat = ops->load_feat;
0764     list_add(&csdev_item->item, &cscfg_mgr->csdev_desc_list);
0765 
0766     INIT_LIST_HEAD(&csdev->feature_csdev_list);
0767     INIT_LIST_HEAD(&csdev->config_csdev_list);
0768     spin_lock_init(&csdev->cscfg_csdev_lock);
0769 
0770     return 0;
0771 }
0772 
0773 /* remove a coresight device from the list and free data */
0774 static void cscfg_list_remove_csdev(struct coresight_device *csdev)
0775 {
0776     struct cscfg_registered_csdev *csdev_item, *tmp;
0777 
0778     list_for_each_entry_safe(csdev_item, tmp, &cscfg_mgr->csdev_desc_list, item) {
0779         if (csdev_item->csdev == csdev) {
0780             list_del(&csdev_item->item);
0781             kfree(csdev_item);
0782             break;
0783         }
0784     }
0785 }
0786 
0787 /**
0788  * cscfg_register_csdev - register a coresight device with the syscfg manager.
0789  *
0790  * Registers the coresight device with the system. @match_flags used to check
0791  * if the device is a match for registered features. Any currently registered
0792  * configurations and features that match the device will be loaded onto it.
0793  *
0794  * @csdev:      The coresight device to register.
0795  * @match_flags:    Matching information to load features.
0796  * @ops:        Standard operations supported by the device.
0797  */
0798 int cscfg_register_csdev(struct coresight_device *csdev,
0799              u32 match_flags,
0800              struct cscfg_csdev_feat_ops *ops)
0801 {
0802     int ret = 0;
0803 
0804     mutex_lock(&cscfg_mutex);
0805 
0806     /* add device to list of registered devices  */
0807     ret = cscfg_list_add_csdev(csdev, match_flags, ops);
0808     if (ret)
0809         goto reg_csdev_unlock;
0810 
0811     /* now load any registered features and configs matching the device. */
0812     ret = cscfg_add_feats_csdev(csdev, match_flags, ops);
0813     if (ret) {
0814         cscfg_list_remove_csdev(csdev);
0815         goto reg_csdev_unlock;
0816     }
0817 
0818     ret = cscfg_add_cfgs_csdev(csdev);
0819     if (ret) {
0820         cscfg_list_remove_csdev(csdev);
0821         goto reg_csdev_unlock;
0822     }
0823 
0824     pr_info("CSCFG registered %s", dev_name(&csdev->dev));
0825 
0826 reg_csdev_unlock:
0827     mutex_unlock(&cscfg_mutex);
0828     return ret;
0829 }
0830 EXPORT_SYMBOL_GPL(cscfg_register_csdev);
0831 
0832 /**
0833  * cscfg_unregister_csdev - remove coresight device from syscfg manager.
0834  *
0835  * @csdev: Device to remove.
0836  */
0837 void cscfg_unregister_csdev(struct coresight_device *csdev)
0838 {
0839     mutex_lock(&cscfg_mutex);
0840     cscfg_list_remove_csdev(csdev);
0841     mutex_unlock(&cscfg_mutex);
0842 }
0843 EXPORT_SYMBOL_GPL(cscfg_unregister_csdev);
0844 
0845 /**
0846  * cscfg_csdev_reset_feats - reset features for a CoreSight device.
0847  *
0848  * Resets all parameters and register values for any features loaded
0849  * into @csdev to their default values.
0850  *
0851  * @csdev: The CoreSight device.
0852  */
0853 void cscfg_csdev_reset_feats(struct coresight_device *csdev)
0854 {
0855     struct cscfg_feature_csdev *feat_csdev;
0856     unsigned long flags;
0857 
0858     spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
0859     if (list_empty(&csdev->feature_csdev_list))
0860         goto unlock_exit;
0861 
0862     list_for_each_entry(feat_csdev, &csdev->feature_csdev_list, node)
0863         cscfg_reset_feat(feat_csdev);
0864 
0865 unlock_exit:
0866     spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
0867 }
0868 EXPORT_SYMBOL_GPL(cscfg_csdev_reset_feats);
0869 
0870 /*
0871  * This activate configuration for either perf or sysfs. Perf can have multiple
0872  * active configs, selected per event, sysfs is limited to one.
0873  *
0874  * Increments the configuration descriptor active count and the global active
0875  * count.
0876  *
0877  * @cfg_hash: Hash value of the selected configuration name.
0878  */
0879 static int _cscfg_activate_config(unsigned long cfg_hash)
0880 {
0881     struct cscfg_config_desc *config_desc;
0882     int err = -EINVAL;
0883 
0884     if (cscfg_mgr->load_state == CSCFG_UNLOAD)
0885         return -EBUSY;
0886 
0887     list_for_each_entry(config_desc, &cscfg_mgr->config_desc_list, item) {
0888         if ((unsigned long)config_desc->event_ea->var == cfg_hash) {
0889             /* if we happen upon a partly loaded config, can't use it */
0890             if (config_desc->available == false)
0891                 return -EBUSY;
0892 
0893             /* must ensure that config cannot be unloaded in use */
0894             err = cscfg_owner_get(config_desc->load_owner);
0895             if (err)
0896                 break;
0897             /*
0898              * increment the global active count - control changes to
0899              * active configurations
0900              */
0901             atomic_inc(&cscfg_mgr->sys_active_cnt);
0902 
0903             /*
0904              * mark the descriptor as active so enable config on a
0905              * device instance will use it
0906              */
0907             atomic_inc(&config_desc->active_cnt);
0908 
0909             err = 0;
0910             dev_dbg(cscfg_device(), "Activate config %s.\n", config_desc->name);
0911             break;
0912         }
0913     }
0914     return err;
0915 }
0916 
0917 static void _cscfg_deactivate_config(unsigned long cfg_hash)
0918 {
0919     struct cscfg_config_desc *config_desc;
0920 
0921     list_for_each_entry(config_desc, &cscfg_mgr->config_desc_list, item) {
0922         if ((unsigned long)config_desc->event_ea->var == cfg_hash) {
0923             atomic_dec(&config_desc->active_cnt);
0924             atomic_dec(&cscfg_mgr->sys_active_cnt);
0925             cscfg_owner_put(config_desc->load_owner);
0926             dev_dbg(cscfg_device(), "Deactivate config %s.\n", config_desc->name);
0927             break;
0928         }
0929     }
0930 }
0931 
0932 /*
0933  * called from configfs to set/clear the active configuration for use when
0934  * using sysfs to control trace.
0935  */
0936 int cscfg_config_sysfs_activate(struct cscfg_config_desc *config_desc, bool activate)
0937 {
0938     unsigned long cfg_hash;
0939     int err = 0;
0940 
0941     mutex_lock(&cscfg_mutex);
0942 
0943     cfg_hash = (unsigned long)config_desc->event_ea->var;
0944 
0945     if (activate) {
0946         /* cannot be a current active value to activate this */
0947         if (cscfg_mgr->sysfs_active_config) {
0948             err = -EBUSY;
0949             goto exit_unlock;
0950         }
0951         err = _cscfg_activate_config(cfg_hash);
0952         if (!err)
0953             cscfg_mgr->sysfs_active_config = cfg_hash;
0954     } else {
0955         /* disable if matching current value */
0956         if (cscfg_mgr->sysfs_active_config == cfg_hash) {
0957             _cscfg_deactivate_config(cfg_hash);
0958             cscfg_mgr->sysfs_active_config = 0;
0959         } else
0960             err = -EINVAL;
0961     }
0962 
0963 exit_unlock:
0964     mutex_unlock(&cscfg_mutex);
0965     return err;
0966 }
0967 
0968 /* set the sysfs preset value */
0969 void cscfg_config_sysfs_set_preset(int preset)
0970 {
0971     mutex_lock(&cscfg_mutex);
0972     cscfg_mgr->sysfs_active_preset = preset;
0973     mutex_unlock(&cscfg_mutex);
0974 }
0975 
0976 /*
0977  * Used by a device to get the config and preset selected as active in configfs,
0978  * when using sysfs to control trace.
0979  */
0980 void cscfg_config_sysfs_get_active_cfg(unsigned long *cfg_hash, int *preset)
0981 {
0982     mutex_lock(&cscfg_mutex);
0983     *preset = cscfg_mgr->sysfs_active_preset;
0984     *cfg_hash = cscfg_mgr->sysfs_active_config;
0985     mutex_unlock(&cscfg_mutex);
0986 }
0987 EXPORT_SYMBOL_GPL(cscfg_config_sysfs_get_active_cfg);
0988 
0989 /**
0990  * cscfg_activate_config -  Mark a configuration descriptor as active.
0991  *
0992  * This will be seen when csdev devices are enabled in the system.
0993  * Only activated configurations can be enabled on individual devices.
0994  * Activation protects the configuration from alteration or removal while
0995  * active.
0996  *
0997  * Selection by hash value - generated from the configuration name when it
0998  * was loaded and added to the cs_etm/configurations file system for selection
0999  * by perf.
1000  *
1001  * @cfg_hash: Hash value of the selected configuration name.
1002  */
1003 int cscfg_activate_config(unsigned long cfg_hash)
1004 {
1005     int err = 0;
1006 
1007     mutex_lock(&cscfg_mutex);
1008     err = _cscfg_activate_config(cfg_hash);
1009     mutex_unlock(&cscfg_mutex);
1010 
1011     return err;
1012 }
1013 EXPORT_SYMBOL_GPL(cscfg_activate_config);
1014 
1015 /**
1016  * cscfg_deactivate_config -  Mark a config descriptor as inactive.
1017  *
1018  * Decrement the configuration and global active counts.
1019  *
1020  * @cfg_hash: Hash value of the selected configuration name.
1021  */
1022 void cscfg_deactivate_config(unsigned long cfg_hash)
1023 {
1024     mutex_lock(&cscfg_mutex);
1025     _cscfg_deactivate_config(cfg_hash);
1026     mutex_unlock(&cscfg_mutex);
1027 }
1028 EXPORT_SYMBOL_GPL(cscfg_deactivate_config);
1029 
1030 /**
1031  * cscfg_csdev_enable_active_config - Enable matching active configuration for device.
1032  *
1033  * Enables the configuration selected by @cfg_hash if the configuration is supported
1034  * on the device and has been activated.
1035  *
1036  * If active and supported the CoreSight device @csdev will be programmed with the
1037  * configuration, using @preset parameters.
1038  *
1039  * Should be called before driver hardware enable for the requested device, prior to
1040  * programming and enabling the physical hardware.
1041  *
1042  * @csdev:  CoreSight device to program.
1043  * @cfg_hash:   Selector for the configuration.
1044  * @preset: Preset parameter values to use, 0 for current / default values.
1045  */
1046 int cscfg_csdev_enable_active_config(struct coresight_device *csdev,
1047                      unsigned long cfg_hash, int preset)
1048 {
1049     struct cscfg_config_csdev *config_csdev_active = NULL, *config_csdev_item;
1050     const struct cscfg_config_desc *config_desc;
1051     unsigned long flags;
1052     int err = 0;
1053 
1054     /* quickly check global count */
1055     if (!atomic_read(&cscfg_mgr->sys_active_cnt))
1056         return 0;
1057 
1058     /*
1059      * Look for matching configuration - set the active configuration
1060      * context if found.
1061      */
1062     spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
1063     list_for_each_entry(config_csdev_item, &csdev->config_csdev_list, node) {
1064         config_desc = config_csdev_item->config_desc;
1065         if ((atomic_read(&config_desc->active_cnt)) &&
1066             ((unsigned long)config_desc->event_ea->var == cfg_hash)) {
1067             config_csdev_active = config_csdev_item;
1068             csdev->active_cscfg_ctxt = (void *)config_csdev_active;
1069             break;
1070         }
1071     }
1072     spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
1073 
1074     /*
1075      * If found, attempt to enable
1076      */
1077     if (config_csdev_active) {
1078         /*
1079          * Call the generic routine that will program up the internal
1080          * driver structures prior to programming up the hardware.
1081          * This routine takes the driver spinlock saved in the configs.
1082          */
1083         err = cscfg_csdev_enable_config(config_csdev_active, preset);
1084         if (!err) {
1085             /*
1086              * Successful programming. Check the active_cscfg_ctxt
1087              * pointer to ensure no pre-emption disabled it via
1088              * cscfg_csdev_disable_active_config() before
1089              * we could start.
1090              *
1091              * Set enabled if OK, err if not.
1092              */
1093             spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
1094             if (csdev->active_cscfg_ctxt)
1095                 config_csdev_active->enabled = true;
1096             else
1097                 err = -EBUSY;
1098             spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
1099         }
1100     }
1101     return err;
1102 }
1103 EXPORT_SYMBOL_GPL(cscfg_csdev_enable_active_config);
1104 
1105 /**
1106  * cscfg_csdev_disable_active_config - disable an active config on the device.
1107  *
1108  * Disables the active configuration on the CoreSight device @csdev.
1109  * Disable will save the values of any registers marked in the configurations
1110  * as save on disable.
1111  *
1112  * Should be called after driver hardware disable for the requested device,
1113  * after disabling the physical hardware and reading back registers.
1114  *
1115  * @csdev: The CoreSight device.
1116  */
1117 void cscfg_csdev_disable_active_config(struct coresight_device *csdev)
1118 {
1119     struct cscfg_config_csdev *config_csdev;
1120     unsigned long flags;
1121 
1122     /*
1123      * Check if we have an active config, and that it was successfully enabled.
1124      * If it was not enabled, we have no work to do, otherwise mark as disabled.
1125      * Clear the active config pointer.
1126      */
1127     spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
1128     config_csdev = (struct cscfg_config_csdev *)csdev->active_cscfg_ctxt;
1129     if (config_csdev) {
1130         if (!config_csdev->enabled)
1131             config_csdev = NULL;
1132         else
1133             config_csdev->enabled = false;
1134     }
1135     csdev->active_cscfg_ctxt = NULL;
1136     spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
1137 
1138     /* true if there was an enabled active config */
1139     if (config_csdev)
1140         cscfg_csdev_disable_config(config_csdev);
1141 }
1142 EXPORT_SYMBOL_GPL(cscfg_csdev_disable_active_config);
1143 
1144 /* Initialise system configuration management device. */
1145 
1146 struct device *cscfg_device(void)
1147 {
1148     return cscfg_mgr ? &cscfg_mgr->dev : NULL;
1149 }
1150 
1151 /* Must have a release function or the kernel will complain on module unload */
1152 static void cscfg_dev_release(struct device *dev)
1153 {
1154     mutex_lock(&cscfg_mutex);
1155     kfree(cscfg_mgr);
1156     cscfg_mgr = NULL;
1157     mutex_unlock(&cscfg_mutex);
1158 }
1159 
1160 /* a device is needed to "own" some kernel elements such as sysfs entries.  */
1161 static int cscfg_create_device(void)
1162 {
1163     struct device *dev;
1164     int err = -ENOMEM;
1165 
1166     mutex_lock(&cscfg_mutex);
1167     if (cscfg_mgr) {
1168         err = -EINVAL;
1169         goto create_dev_exit_unlock;
1170     }
1171 
1172     cscfg_mgr = kzalloc(sizeof(struct cscfg_manager), GFP_KERNEL);
1173     if (!cscfg_mgr)
1174         goto create_dev_exit_unlock;
1175 
1176     /* initialise the cscfg_mgr structure */
1177     INIT_LIST_HEAD(&cscfg_mgr->csdev_desc_list);
1178     INIT_LIST_HEAD(&cscfg_mgr->feat_desc_list);
1179     INIT_LIST_HEAD(&cscfg_mgr->config_desc_list);
1180     INIT_LIST_HEAD(&cscfg_mgr->load_order_list);
1181     atomic_set(&cscfg_mgr->sys_active_cnt, 0);
1182     cscfg_mgr->load_state = CSCFG_NONE;
1183 
1184     /* setup the device */
1185     dev = cscfg_device();
1186     dev->release = cscfg_dev_release;
1187     dev->init_name = "cs_system_cfg";
1188 
1189     err = device_register(dev);
1190     if (err)
1191         put_device(dev);
1192 
1193 create_dev_exit_unlock:
1194     mutex_unlock(&cscfg_mutex);
1195     return err;
1196 }
1197 
1198 /*
1199  * Loading and unloading is generally on user discretion.
1200  * If exiting due to coresight module unload, we need to unload any configurations that remain,
1201  * before we unregister the configfs intrastructure.
1202  *
1203  * Do this by walking the load_owner list and taking appropriate action, depending on the load
1204  * owner type.
1205  */
1206 static void cscfg_unload_cfgs_on_exit(void)
1207 {
1208     struct cscfg_load_owner_info *owner_info = NULL;
1209 
1210     /*
1211      * grab the mutex - even though we are exiting, some configfs files
1212      * may still be live till we dump them, so ensure list data is
1213      * protected from a race condition.
1214      */
1215     mutex_lock(&cscfg_mutex);
1216     while (!list_empty(&cscfg_mgr->load_order_list)) {
1217 
1218         /* remove in reverse order of loading */
1219         owner_info = list_last_entry(&cscfg_mgr->load_order_list,
1220                          struct cscfg_load_owner_info, item);
1221 
1222         /* action according to type */
1223         switch (owner_info->type) {
1224         case CSCFG_OWNER_PRELOAD:
1225             /*
1226              * preloaded  descriptors are statically allocated in
1227              * this module - just need to unload dynamic items from
1228              * csdev lists, and remove from configfs directories.
1229              */
1230             pr_info("cscfg: unloading preloaded configurations\n");
1231             break;
1232 
1233         case  CSCFG_OWNER_MODULE:
1234             /*
1235              * this is an error - the loadable module must have been unloaded prior
1236              * to the coresight module unload. Therefore that module has not
1237              * correctly unloaded configs in its own exit code.
1238              * Nothing to do other than emit an error string as the static descriptor
1239              * references we need to unload will have disappeared with the module.
1240              */
1241             pr_err("cscfg: ERROR: prior module failed to unload configuration\n");
1242             goto list_remove;
1243         }
1244 
1245         /* remove from configfs - outside the scope of the list mutex */
1246         mutex_unlock(&cscfg_mutex);
1247         cscfg_fs_unregister_cfgs_feats(owner_info);
1248         mutex_lock(&cscfg_mutex);
1249 
1250         /* Next unload from csdev lists. */
1251         cscfg_unload_owned_cfgs_feats(owner_info);
1252 
1253 list_remove:
1254         /* remove from load order list */
1255         list_del(&owner_info->item);
1256     }
1257     mutex_unlock(&cscfg_mutex);
1258 }
1259 
1260 static void cscfg_clear_device(void)
1261 {
1262     cscfg_unload_cfgs_on_exit();
1263     cscfg_configfs_release(cscfg_mgr);
1264     device_unregister(cscfg_device());
1265 }
1266 
1267 /* Initialise system config management API device  */
1268 int __init cscfg_init(void)
1269 {
1270     int err = 0;
1271 
1272     /* create the device and init cscfg_mgr */
1273     err = cscfg_create_device();
1274     if (err)
1275         return err;
1276 
1277     /* initialise configfs subsystem */
1278     err = cscfg_configfs_init(cscfg_mgr);
1279     if (err)
1280         goto exit_err;
1281 
1282     /* preload built-in configurations */
1283     err = cscfg_preload(THIS_MODULE);
1284     if (err)
1285         goto exit_err;
1286 
1287     dev_info(cscfg_device(), "CoreSight Configuration manager initialised");
1288     return 0;
1289 
1290 exit_err:
1291     cscfg_clear_device();
1292     return err;
1293 }
1294 
1295 void cscfg_exit(void)
1296 {
1297     cscfg_clear_device();
1298 }