linux/drivers/hwtracing/coresight/coresight-syscfg.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (c) 2020 Linaro Limited, All rights reserved.
   4 * Author: Mike Leach <mike.leach@linaro.org>
   5 */
   6
   7#include <linux/platform_device.h>
   8#include <linux/slab.h>
   9
  10#include "coresight-config.h"
  11#include "coresight-etm-perf.h"
  12#include "coresight-syscfg.h"
  13#include "coresight-syscfg-configfs.h"
  14
  15/*
  16 * cscfg_ API manages configurations and features for the entire coresight
  17 * infrastructure.
  18 *
  19 * It allows the loading of configurations and features, and loads these into
  20 * coresight devices as appropriate.
  21 */
  22
  23/* protect the cscsg_data and device */
  24static DEFINE_MUTEX(cscfg_mutex);
  25
  26/* only one of these */
  27static struct cscfg_manager *cscfg_mgr;
  28
  29/* load features and configuations into the lists */
  30
  31/* get name feature instance from a coresight device list of features */
  32static struct cscfg_feature_csdev *
  33cscfg_get_feat_csdev(struct coresight_device *csdev, const char *name)
  34{
  35        struct cscfg_feature_csdev *feat_csdev = NULL;
  36
  37        list_for_each_entry(feat_csdev, &csdev->feature_csdev_list, node) {
  38                if (strcmp(feat_csdev->feat_desc->name, name) == 0)
  39                        return feat_csdev;
  40        }
  41        return NULL;
  42}
  43
  44/* allocate the device config instance - with max number of used features */
  45static struct cscfg_config_csdev *
  46cscfg_alloc_csdev_cfg(struct coresight_device *csdev, int nr_feats)
  47{
  48        struct cscfg_config_csdev *config_csdev = NULL;
  49        struct device *dev = csdev->dev.parent;
  50
  51        /* this is being allocated using the devm for the coresight device */
  52        config_csdev = devm_kzalloc(dev,
  53                                    offsetof(struct cscfg_config_csdev, feats_csdev[nr_feats]),
  54                                    GFP_KERNEL);
  55        if (!config_csdev)
  56                return NULL;
  57
  58        config_csdev->csdev = csdev;
  59        return config_csdev;
  60}
  61
  62/* Load a config into a device if there are any feature matches between config and device */
  63static int cscfg_add_csdev_cfg(struct coresight_device *csdev,
  64                               struct cscfg_config_desc *config_desc)
  65{
  66        struct cscfg_config_csdev *config_csdev = NULL;
  67        struct cscfg_feature_csdev *feat_csdev;
  68        unsigned long flags;
  69        int i;
  70
  71        /* look at each required feature and see if it matches any feature on the device */
  72        for (i = 0; i < config_desc->nr_feat_refs; i++) {
  73                /* look for a matching name */
  74                feat_csdev = cscfg_get_feat_csdev(csdev, config_desc->feat_ref_names[i]);
  75                if (feat_csdev) {
  76                        /*
  77                         * At least one feature on this device matches the config
  78                         * add a config instance to the device and a reference to the feature.
  79                         */
  80                        if (!config_csdev) {
  81                                config_csdev = cscfg_alloc_csdev_cfg(csdev,
  82                                                                     config_desc->nr_feat_refs);
  83                                if (!config_csdev)
  84                                        return -ENOMEM;
  85                                config_csdev->config_desc = config_desc;
  86                        }
  87                        config_csdev->feats_csdev[config_csdev->nr_feat++] = feat_csdev;
  88                }
  89        }
  90        /* if matched features, add config to device.*/
  91        if (config_csdev) {
  92                spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
  93                list_add(&config_csdev->node, &csdev->config_csdev_list);
  94                spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
  95        }
  96
  97        return 0;
  98}
  99
 100/*
 101 * Add the config to the set of registered devices - call with mutex locked.
 102 * Iterates through devices - any device that matches one or more of the
 103 * configuration features will load it, the others will ignore it.
 104 */
 105static int cscfg_add_cfg_to_csdevs(struct cscfg_config_desc *config_desc)
 106{
 107        struct cscfg_registered_csdev *csdev_item;
 108        int err;
 109
 110        list_for_each_entry(csdev_item, &cscfg_mgr->csdev_desc_list, item) {
 111                err = cscfg_add_csdev_cfg(csdev_item->csdev, config_desc);
 112                if (err)
 113                        return err;
 114        }
 115        return 0;
 116}
 117
 118/*
 119 * Allocate a feature object for load into a csdev.
 120 * memory allocated using the csdev->dev object using devm managed allocator.
 121 */
 122static struct cscfg_feature_csdev *
 123cscfg_alloc_csdev_feat(struct coresight_device *csdev, struct cscfg_feature_desc *feat_desc)
 124{
 125        struct cscfg_feature_csdev *feat_csdev = NULL;
 126        struct device *dev = csdev->dev.parent;
 127        int i;
 128
 129        feat_csdev = devm_kzalloc(dev, sizeof(struct cscfg_feature_csdev), GFP_KERNEL);
 130        if (!feat_csdev)
 131                return NULL;
 132
 133        /* parameters are optional - could be 0 */
 134        feat_csdev->nr_params = feat_desc->nr_params;
 135
 136        /*
 137         * if we need parameters, zero alloc the space here, the load routine in
 138         * the csdev device driver will fill out some information according to
 139         * feature descriptor.
 140         */
 141        if (feat_csdev->nr_params) {
 142                feat_csdev->params_csdev = devm_kcalloc(dev, feat_csdev->nr_params,
 143                                                        sizeof(struct cscfg_parameter_csdev),
 144                                                        GFP_KERNEL);
 145                if (!feat_csdev->params_csdev)
 146                        return NULL;
 147
 148                /*
 149                 * fill in the feature reference in the param - other fields
 150                 * handled by loader in csdev.
 151                 */
 152                for (i = 0; i < feat_csdev->nr_params; i++)
 153                        feat_csdev->params_csdev[i].feat_csdev = feat_csdev;
 154        }
 155
 156        /*
 157         * Always have registers to program - again the load routine in csdev device
 158         * will fill out according to feature descriptor and device requirements.
 159         */
 160        feat_csdev->nr_regs = feat_desc->nr_regs;
 161        feat_csdev->regs_csdev = devm_kcalloc(dev, feat_csdev->nr_regs,
 162                                              sizeof(struct cscfg_regval_csdev),
 163                                              GFP_KERNEL);
 164        if (!feat_csdev->regs_csdev)
 165                return NULL;
 166
 167        /* load the feature default values */
 168        feat_csdev->feat_desc = feat_desc;
 169        feat_csdev->csdev = csdev;
 170
 171        return feat_csdev;
 172}
 173
 174/* load one feature into one coresight device */
 175static int cscfg_load_feat_csdev(struct coresight_device *csdev,
 176                                 struct cscfg_feature_desc *feat_desc,
 177                                 struct cscfg_csdev_feat_ops *ops)
 178{
 179        struct cscfg_feature_csdev *feat_csdev;
 180        unsigned long flags;
 181        int err;
 182
 183        if (!ops->load_feat)
 184                return -EINVAL;
 185
 186        feat_csdev = cscfg_alloc_csdev_feat(csdev, feat_desc);
 187        if (!feat_csdev)
 188                return -ENOMEM;
 189
 190        /* load the feature into the device */
 191        err = ops->load_feat(csdev, feat_csdev);
 192        if (err)
 193                return err;
 194
 195        /* add to internal csdev feature list & initialise using reset call */
 196        cscfg_reset_feat(feat_csdev);
 197        spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
 198        list_add(&feat_csdev->node, &csdev->feature_csdev_list);
 199        spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
 200
 201        return 0;
 202}
 203
 204/*
 205 * Add feature to any matching devices - call with mutex locked.
 206 * Iterates through devices - any device that matches the feature will be
 207 * called to load it.
 208 */
 209static int cscfg_add_feat_to_csdevs(struct cscfg_feature_desc *feat_desc)
 210{
 211        struct cscfg_registered_csdev *csdev_item;
 212        int err;
 213
 214        list_for_each_entry(csdev_item, &cscfg_mgr->csdev_desc_list, item) {
 215                if (csdev_item->match_flags & feat_desc->match_flags) {
 216                        err = cscfg_load_feat_csdev(csdev_item->csdev, feat_desc, &csdev_item->ops);
 217                        if (err)
 218                                return err;
 219                }
 220        }
 221        return 0;
 222}
 223
 224/* check feature list for a named feature - call with mutex locked. */
 225static bool cscfg_match_list_feat(const char *name)
 226{
 227        struct cscfg_feature_desc *feat_desc;
 228
 229        list_for_each_entry(feat_desc, &cscfg_mgr->feat_desc_list, item) {
 230                if (strcmp(feat_desc->name, name) == 0)
 231                        return true;
 232        }
 233        return false;
 234}
 235
 236/* check all feat needed for cfg are in the list - call with mutex locked. */
 237static int cscfg_check_feat_for_cfg(struct cscfg_config_desc *config_desc)
 238{
 239        int i;
 240
 241        for (i = 0; i < config_desc->nr_feat_refs; i++)
 242                if (!cscfg_match_list_feat(config_desc->feat_ref_names[i]))
 243                        return -EINVAL;
 244        return 0;
 245}
 246
 247/*
 248 * load feature - add to feature list.
 249 */
 250static int cscfg_load_feat(struct cscfg_feature_desc *feat_desc)
 251{
 252        int err;
 253
 254        /* add feature to any matching registered devices */
 255        err = cscfg_add_feat_to_csdevs(feat_desc);
 256        if (err)
 257                return err;
 258
 259        list_add(&feat_desc->item, &cscfg_mgr->feat_desc_list);
 260        return 0;
 261}
 262
 263/*
 264 * load config into the system - validate used features exist then add to
 265 * config list.
 266 */
 267static int cscfg_load_config(struct cscfg_config_desc *config_desc)
 268{
 269        int err;
 270
 271        /* validate features are present */
 272        err = cscfg_check_feat_for_cfg(config_desc);
 273        if (err)
 274                return err;
 275
 276        /* add config to any matching registered device */
 277        err = cscfg_add_cfg_to_csdevs(config_desc);
 278        if (err)
 279                return err;
 280
 281        /* add config to perf fs to allow selection */
 282        err = etm_perf_add_symlink_cscfg(cscfg_device(), config_desc);
 283        if (err)
 284                return err;
 285
 286        list_add(&config_desc->item, &cscfg_mgr->config_desc_list);
 287        atomic_set(&config_desc->active_cnt, 0);
 288        return 0;
 289}
 290
 291/* get a feature descriptor by name */
 292const struct cscfg_feature_desc *cscfg_get_named_feat_desc(const char *name)
 293{
 294        const struct cscfg_feature_desc *feat_desc = NULL, *feat_desc_item;
 295
 296        mutex_lock(&cscfg_mutex);
 297
 298        list_for_each_entry(feat_desc_item, &cscfg_mgr->feat_desc_list, item) {
 299                if (strcmp(feat_desc_item->name, name) == 0) {
 300                        feat_desc = feat_desc_item;
 301                        break;
 302                }
 303        }
 304
 305        mutex_unlock(&cscfg_mutex);
 306        return feat_desc;
 307}
 308
 309/* called with cscfg_mutex held */
 310static struct cscfg_feature_csdev *
 311cscfg_csdev_get_feat_from_desc(struct coresight_device *csdev,
 312                               struct cscfg_feature_desc *feat_desc)
 313{
 314        struct cscfg_feature_csdev *feat_csdev;
 315
 316        list_for_each_entry(feat_csdev, &csdev->feature_csdev_list, node) {
 317                if (feat_csdev->feat_desc == feat_desc)
 318                        return feat_csdev;
 319        }
 320        return NULL;
 321}
 322
 323int cscfg_update_feat_param_val(struct cscfg_feature_desc *feat_desc,
 324                                int param_idx, u64 value)
 325{
 326        int err = 0;
 327        struct cscfg_feature_csdev *feat_csdev;
 328        struct cscfg_registered_csdev *csdev_item;
 329
 330        mutex_lock(&cscfg_mutex);
 331
 332        /* check if any config active & return busy */
 333        if (atomic_read(&cscfg_mgr->sys_active_cnt)) {
 334                err = -EBUSY;
 335                goto unlock_exit;
 336        }
 337
 338        /* set the value */
 339        if ((param_idx < 0) || (param_idx >= feat_desc->nr_params)) {
 340                err = -EINVAL;
 341                goto unlock_exit;
 342        }
 343        feat_desc->params_desc[param_idx].value = value;
 344
 345        /* update loaded instances.*/
 346        list_for_each_entry(csdev_item, &cscfg_mgr->csdev_desc_list, item) {
 347                feat_csdev = cscfg_csdev_get_feat_from_desc(csdev_item->csdev, feat_desc);
 348                if (feat_csdev)
 349                        feat_csdev->params_csdev[param_idx].current_value = value;
 350        }
 351
 352unlock_exit:
 353        mutex_unlock(&cscfg_mutex);
 354        return err;
 355}
 356
 357/**
 358 * cscfg_load_config_sets - API function to load feature and config sets.
 359 *
 360 * Take a 0 terminated array of feature descriptors and/or configuration
 361 * descriptors and load into the system.
 362 * Features are loaded first to ensure configuration dependencies can be met.
 363 *
 364 * @config_descs: 0 terminated array of configuration descriptors.
 365 * @feat_descs:   0 terminated array of feature descriptors.
 366 */
 367int cscfg_load_config_sets(struct cscfg_config_desc **config_descs,
 368                           struct cscfg_feature_desc **feat_descs)
 369{
 370        int err, i = 0;
 371
 372        mutex_lock(&cscfg_mutex);
 373
 374        /* load features first */
 375        if (feat_descs) {
 376                while (feat_descs[i]) {
 377                        err = cscfg_load_feat(feat_descs[i]);
 378                        if (!err)
 379                                err = cscfg_configfs_add_feature(feat_descs[i]);
 380                        if (err) {
 381                                pr_err("coresight-syscfg: Failed to load feature %s\n",
 382                                       feat_descs[i]->name);
 383                                goto exit_unlock;
 384                        }
 385                        i++;
 386                }
 387        }
 388
 389        /* next any configurations to check feature dependencies */
 390        i = 0;
 391        if (config_descs) {
 392                while (config_descs[i]) {
 393                        err = cscfg_load_config(config_descs[i]);
 394                        if (!err)
 395                                err = cscfg_configfs_add_config(config_descs[i]);
 396                        if (err) {
 397                                pr_err("coresight-syscfg: Failed to load configuration %s\n",
 398                                       config_descs[i]->name);
 399                                goto exit_unlock;
 400                        }
 401                        i++;
 402                }
 403        }
 404
 405exit_unlock:
 406        mutex_unlock(&cscfg_mutex);
 407        return err;
 408}
 409EXPORT_SYMBOL_GPL(cscfg_load_config_sets);
 410
 411/* Handle coresight device registration and add configs and features to devices */
 412
 413/* iterate through config lists and load matching configs to device */
 414static int cscfg_add_cfgs_csdev(struct coresight_device *csdev)
 415{
 416        struct cscfg_config_desc *config_desc;
 417        int err = 0;
 418
 419        list_for_each_entry(config_desc, &cscfg_mgr->config_desc_list, item) {
 420                err = cscfg_add_csdev_cfg(csdev, config_desc);
 421                if (err)
 422                        break;
 423        }
 424        return err;
 425}
 426
 427/* iterate through feature lists and load matching features to device */
 428static int cscfg_add_feats_csdev(struct coresight_device *csdev,
 429                                 u32 match_flags,
 430                                 struct cscfg_csdev_feat_ops *ops)
 431{
 432        struct cscfg_feature_desc *feat_desc;
 433        int err = 0;
 434
 435        if (!ops->load_feat)
 436                return -EINVAL;
 437
 438        list_for_each_entry(feat_desc, &cscfg_mgr->feat_desc_list, item) {
 439                if (feat_desc->match_flags & match_flags) {
 440                        err = cscfg_load_feat_csdev(csdev, feat_desc, ops);
 441                        if (err)
 442                                break;
 443                }
 444        }
 445        return err;
 446}
 447
 448/* Add coresight device to list and copy its matching info */
 449static int cscfg_list_add_csdev(struct coresight_device *csdev,
 450                                u32 match_flags,
 451                                struct cscfg_csdev_feat_ops *ops)
 452{
 453        struct cscfg_registered_csdev *csdev_item;
 454
 455        /* allocate the list entry structure */
 456        csdev_item = kzalloc(sizeof(struct cscfg_registered_csdev), GFP_KERNEL);
 457        if (!csdev_item)
 458                return -ENOMEM;
 459
 460        csdev_item->csdev = csdev;
 461        csdev_item->match_flags = match_flags;
 462        csdev_item->ops.load_feat = ops->load_feat;
 463        list_add(&csdev_item->item, &cscfg_mgr->csdev_desc_list);
 464
 465        INIT_LIST_HEAD(&csdev->feature_csdev_list);
 466        INIT_LIST_HEAD(&csdev->config_csdev_list);
 467        spin_lock_init(&csdev->cscfg_csdev_lock);
 468
 469        return 0;
 470}
 471
 472/* remove a coresight device from the list and free data */
 473static void cscfg_list_remove_csdev(struct coresight_device *csdev)
 474{
 475        struct cscfg_registered_csdev *csdev_item, *tmp;
 476
 477        list_for_each_entry_safe(csdev_item, tmp, &cscfg_mgr->csdev_desc_list, item) {
 478                if (csdev_item->csdev == csdev) {
 479                        list_del(&csdev_item->item);
 480                        kfree(csdev_item);
 481                        break;
 482                }
 483        }
 484}
 485
 486/**
 487 * cscfg_register_csdev - register a coresight device with the syscfg manager.
 488 *
 489 * Registers the coresight device with the system. @match_flags used to check
 490 * if the device is a match for registered features. Any currently registered
 491 * configurations and features that match the device will be loaded onto it.
 492 *
 493 * @csdev:              The coresight device to register.
 494 * @match_flags:        Matching information to load features.
 495 * @ops:                Standard operations supported by the device.
 496 */
 497int cscfg_register_csdev(struct coresight_device *csdev,
 498                         u32 match_flags,
 499                         struct cscfg_csdev_feat_ops *ops)
 500{
 501        int ret = 0;
 502
 503        mutex_lock(&cscfg_mutex);
 504
 505        /* add device to list of registered devices  */
 506        ret = cscfg_list_add_csdev(csdev, match_flags, ops);
 507        if (ret)
 508                goto reg_csdev_unlock;
 509
 510        /* now load any registered features and configs matching the device. */
 511        ret = cscfg_add_feats_csdev(csdev, match_flags, ops);
 512        if (ret) {
 513                cscfg_list_remove_csdev(csdev);
 514                goto reg_csdev_unlock;
 515        }
 516
 517        ret = cscfg_add_cfgs_csdev(csdev);
 518        if (ret) {
 519                cscfg_list_remove_csdev(csdev);
 520                goto reg_csdev_unlock;
 521        }
 522
 523        pr_info("CSCFG registered %s", dev_name(&csdev->dev));
 524
 525reg_csdev_unlock:
 526        mutex_unlock(&cscfg_mutex);
 527        return ret;
 528}
 529EXPORT_SYMBOL_GPL(cscfg_register_csdev);
 530
 531/**
 532 * cscfg_unregister_csdev - remove coresight device from syscfg manager.
 533 *
 534 * @csdev: Device to remove.
 535 */
 536void cscfg_unregister_csdev(struct coresight_device *csdev)
 537{
 538        mutex_lock(&cscfg_mutex);
 539        cscfg_list_remove_csdev(csdev);
 540        mutex_unlock(&cscfg_mutex);
 541}
 542EXPORT_SYMBOL_GPL(cscfg_unregister_csdev);
 543
 544/**
 545 * cscfg_csdev_reset_feats - reset features for a CoreSight device.
 546 *
 547 * Resets all parameters and register values for any features loaded
 548 * into @csdev to their default values.
 549 *
 550 * @csdev: The CoreSight device.
 551 */
 552void cscfg_csdev_reset_feats(struct coresight_device *csdev)
 553{
 554        struct cscfg_feature_csdev *feat_csdev;
 555        unsigned long flags;
 556
 557        spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
 558        if (list_empty(&csdev->feature_csdev_list))
 559                goto unlock_exit;
 560
 561        list_for_each_entry(feat_csdev, &csdev->feature_csdev_list, node)
 562                cscfg_reset_feat(feat_csdev);
 563
 564unlock_exit:
 565        spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
 566}
 567EXPORT_SYMBOL_GPL(cscfg_csdev_reset_feats);
 568
 569/**
 570 * cscfg_activate_config -  Mark a configuration descriptor as active.
 571 *
 572 * This will be seen when csdev devices are enabled in the system.
 573 * Only activated configurations can be enabled on individual devices.
 574 * Activation protects the configuration from alteration or removal while
 575 * active.
 576 *
 577 * Selection by hash value - generated from the configuration name when it
 578 * was loaded and added to the cs_etm/configurations file system for selection
 579 * by perf.
 580 *
 581 * Increments the configuration descriptor active count and the global active
 582 * count.
 583 *
 584 * @cfg_hash: Hash value of the selected configuration name.
 585 */
 586int cscfg_activate_config(unsigned long cfg_hash)
 587{
 588        struct cscfg_config_desc *config_desc;
 589        int err = -EINVAL;
 590
 591        mutex_lock(&cscfg_mutex);
 592
 593        list_for_each_entry(config_desc, &cscfg_mgr->config_desc_list, item) {
 594                if ((unsigned long)config_desc->event_ea->var == cfg_hash) {
 595                        /*
 596                         * increment the global active count - control changes to
 597                         * active configurations
 598                         */
 599                        atomic_inc(&cscfg_mgr->sys_active_cnt);
 600
 601                        /*
 602                         * mark the descriptor as active so enable config on a
 603                         * device instance will use it
 604                         */
 605                        atomic_inc(&config_desc->active_cnt);
 606
 607                        err = 0;
 608                        dev_dbg(cscfg_device(), "Activate config %s.\n", config_desc->name);
 609                        break;
 610                }
 611        }
 612        mutex_unlock(&cscfg_mutex);
 613
 614        return err;
 615}
 616EXPORT_SYMBOL_GPL(cscfg_activate_config);
 617
 618/**
 619 * cscfg_deactivate_config -  Mark a config descriptor as inactive.
 620 *
 621 * Decrement the configuration and global active counts.
 622 *
 623 * @cfg_hash: Hash value of the selected configuration name.
 624 */
 625void cscfg_deactivate_config(unsigned long cfg_hash)
 626{
 627        struct cscfg_config_desc *config_desc;
 628
 629        mutex_lock(&cscfg_mutex);
 630
 631        list_for_each_entry(config_desc, &cscfg_mgr->config_desc_list, item) {
 632                if ((unsigned long)config_desc->event_ea->var == cfg_hash) {
 633                        atomic_dec(&config_desc->active_cnt);
 634                        atomic_dec(&cscfg_mgr->sys_active_cnt);
 635                        dev_dbg(cscfg_device(), "Deactivate config %s.\n", config_desc->name);
 636                        break;
 637                }
 638        }
 639        mutex_unlock(&cscfg_mutex);
 640}
 641EXPORT_SYMBOL_GPL(cscfg_deactivate_config);
 642
 643/**
 644 * cscfg_csdev_enable_active_config - Enable matching active configuration for device.
 645 *
 646 * Enables the configuration selected by @cfg_hash if the configuration is supported
 647 * on the device and has been activated.
 648 *
 649 * If active and supported the CoreSight device @csdev will be programmed with the
 650 * configuration, using @preset parameters.
 651 *
 652 * Should be called before driver hardware enable for the requested device, prior to
 653 * programming and enabling the physical hardware.
 654 *
 655 * @csdev:      CoreSight device to program.
 656 * @cfg_hash:   Selector for the configuration.
 657 * @preset:     Preset parameter values to use, 0 for current / default values.
 658 */
 659int cscfg_csdev_enable_active_config(struct coresight_device *csdev,
 660                                     unsigned long cfg_hash, int preset)
 661{
 662        struct cscfg_config_csdev *config_csdev_active = NULL, *config_csdev_item;
 663        const struct cscfg_config_desc *config_desc;
 664        unsigned long flags;
 665        int err = 0;
 666
 667        /* quickly check global count */
 668        if (!atomic_read(&cscfg_mgr->sys_active_cnt))
 669                return 0;
 670
 671        /*
 672         * Look for matching configuration - set the active configuration
 673         * context if found.
 674         */
 675        spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
 676        list_for_each_entry(config_csdev_item, &csdev->config_csdev_list, node) {
 677                config_desc = config_csdev_item->config_desc;
 678                if ((atomic_read(&config_desc->active_cnt)) &&
 679                    ((unsigned long)config_desc->event_ea->var == cfg_hash)) {
 680                        config_csdev_active = config_csdev_item;
 681                        csdev->active_cscfg_ctxt = (void *)config_csdev_active;
 682                        break;
 683                }
 684        }
 685        spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
 686
 687        /*
 688         * If found, attempt to enable
 689         */
 690        if (config_csdev_active) {
 691                /*
 692                 * Call the generic routine that will program up the internal
 693                 * driver structures prior to programming up the hardware.
 694                 * This routine takes the driver spinlock saved in the configs.
 695                 */
 696                err = cscfg_csdev_enable_config(config_csdev_active, preset);
 697                if (!err) {
 698                        /*
 699                         * Successful programming. Check the active_cscfg_ctxt
 700                         * pointer to ensure no pre-emption disabled it via
 701                         * cscfg_csdev_disable_active_config() before
 702                         * we could start.
 703                         *
 704                         * Set enabled if OK, err if not.
 705                         */
 706                        spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
 707                        if (csdev->active_cscfg_ctxt)
 708                                config_csdev_active->enabled = true;
 709                        else
 710                                err = -EBUSY;
 711                        spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
 712                }
 713        }
 714        return err;
 715}
 716EXPORT_SYMBOL_GPL(cscfg_csdev_enable_active_config);
 717
 718/**
 719 * cscfg_csdev_disable_active_config - disable an active config on the device.
 720 *
 721 * Disables the active configuration on the CoreSight device @csdev.
 722 * Disable will save the values of any registers marked in the configurations
 723 * as save on disable.
 724 *
 725 * Should be called after driver hardware disable for the requested device,
 726 * after disabling the physical hardware and reading back registers.
 727 *
 728 * @csdev: The CoreSight device.
 729 */
 730void cscfg_csdev_disable_active_config(struct coresight_device *csdev)
 731{
 732        struct cscfg_config_csdev *config_csdev;
 733        unsigned long flags;
 734
 735        /*
 736         * Check if we have an active config, and that it was successfully enabled.
 737         * If it was not enabled, we have no work to do, otherwise mark as disabled.
 738         * Clear the active config pointer.
 739         */
 740        spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
 741        config_csdev = (struct cscfg_config_csdev *)csdev->active_cscfg_ctxt;
 742        if (config_csdev) {
 743                if (!config_csdev->enabled)
 744                        config_csdev = NULL;
 745                else
 746                        config_csdev->enabled = false;
 747        }
 748        csdev->active_cscfg_ctxt = NULL;
 749        spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
 750
 751        /* true if there was an enabled active config */
 752        if (config_csdev)
 753                cscfg_csdev_disable_config(config_csdev);
 754}
 755EXPORT_SYMBOL_GPL(cscfg_csdev_disable_active_config);
 756
 757/* Initialise system configuration management device. */
 758
 759struct device *cscfg_device(void)
 760{
 761        return cscfg_mgr ? &cscfg_mgr->dev : NULL;
 762}
 763
 764/* Must have a release function or the kernel will complain on module unload */
 765static void cscfg_dev_release(struct device *dev)
 766{
 767        kfree(cscfg_mgr);
 768        cscfg_mgr = NULL;
 769}
 770
 771/* a device is needed to "own" some kernel elements such as sysfs entries.  */
 772static int cscfg_create_device(void)
 773{
 774        struct device *dev;
 775        int err = -ENOMEM;
 776
 777        mutex_lock(&cscfg_mutex);
 778        if (cscfg_mgr) {
 779                err = -EINVAL;
 780                goto create_dev_exit_unlock;
 781        }
 782
 783        cscfg_mgr = kzalloc(sizeof(struct cscfg_manager), GFP_KERNEL);
 784        if (!cscfg_mgr)
 785                goto create_dev_exit_unlock;
 786
 787        /* setup the device */
 788        dev = cscfg_device();
 789        dev->release = cscfg_dev_release;
 790        dev->init_name = "cs_system_cfg";
 791
 792        err = device_register(dev);
 793        if (err)
 794                cscfg_dev_release(dev);
 795
 796create_dev_exit_unlock:
 797        mutex_unlock(&cscfg_mutex);
 798        return err;
 799}
 800
 801static void cscfg_clear_device(void)
 802{
 803        struct cscfg_config_desc *cfg_desc;
 804
 805        mutex_lock(&cscfg_mutex);
 806        list_for_each_entry(cfg_desc, &cscfg_mgr->config_desc_list, item) {
 807                etm_perf_del_symlink_cscfg(cfg_desc);
 808        }
 809        cscfg_configfs_release(cscfg_mgr);
 810        device_unregister(cscfg_device());
 811        mutex_unlock(&cscfg_mutex);
 812}
 813
 814/* Initialise system config management API device  */
 815int __init cscfg_init(void)
 816{
 817        int err = 0;
 818
 819        err = cscfg_create_device();
 820        if (err)
 821                return err;
 822
 823        err = cscfg_configfs_init(cscfg_mgr);
 824        if (err)
 825                goto exit_err;
 826
 827        INIT_LIST_HEAD(&cscfg_mgr->csdev_desc_list);
 828        INIT_LIST_HEAD(&cscfg_mgr->feat_desc_list);
 829        INIT_LIST_HEAD(&cscfg_mgr->config_desc_list);
 830        atomic_set(&cscfg_mgr->sys_active_cnt, 0);
 831
 832        /* preload built-in configurations */
 833        err = cscfg_preload();
 834        if (err)
 835                goto exit_err;
 836
 837        dev_info(cscfg_device(), "CoreSight Configuration manager initialised");
 838        return 0;
 839
 840exit_err:
 841        cscfg_clear_device();
 842        return err;
 843}
 844
 845void cscfg_exit(void)
 846{
 847        cscfg_clear_device();
 848}
 849