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