0001
0002
0003
0004
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
0017
0018
0019
0020
0021
0022
0023
0024 static DEFINE_MUTEX(cscfg_mutex);
0025
0026
0027 static struct cscfg_manager *cscfg_mgr;
0028
0029
0030
0031
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
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
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
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
0072 for (i = 0; i < config_desc->nr_feat_refs; i++) {
0073
0074 feat_csdev = cscfg_get_feat_csdev(csdev, config_desc->feat_ref_names[i]);
0075 if (feat_csdev) {
0076
0077
0078
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
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
0102
0103
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
0120
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
0134 feat_csdev->nr_params = feat_desc->nr_params;
0135
0136
0137
0138
0139
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
0150
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
0158
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
0168 feat_csdev->feat_desc = feat_desc;
0169 feat_csdev->csdev = csdev;
0170
0171 return feat_csdev;
0172 }
0173
0174
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
0191 err = ops->load_feat(csdev, feat_csdev);
0192 if (err)
0193 return err;
0194
0195
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
0206
0207
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
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
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
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
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
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
0272
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
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
0286 err = cscfg_check_feat_for_cfg(config_desc);
0287 if (err)
0288 return err;
0289
0290
0291 err = cscfg_add_cfg_to_csdevs(config_desc);
0292 if (err)
0293 return err;
0294
0295
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
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
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
0347 if (atomic_read(&cscfg_mgr->sys_active_cnt)) {
0348 err = -EBUSY;
0349 goto unlock_exit;
0350 }
0351
0352
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
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
0373
0374
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
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
0419
0420
0421
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
0440
0441
0442
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
0453 list_for_each_entry(csdev_item, &cscfg_mgr->csdev_desc_list, item) {
0454
0455
0456
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
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
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
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
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
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
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
0533
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
0559
0560
0561
0562
0563
0564
0565
0566
0567
0568
0569
0570
0571
0572
0573
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
0589 err = cscfg_load_owned_cfgs_feats(config_descs, feat_descs, owner_info);
0590 if (err)
0591 goto err_clean_load;
0592
0593
0594 list_add_tail(&owner_info->item, &cscfg_mgr->load_order_list);
0595 if (!list_is_singular(&cscfg_mgr->load_order_list)) {
0596
0597 err = cscfg_owner_get(list_prev_entry(owner_info, item));
0598 if (err)
0599 goto err_clean_owner_list;
0600 }
0601
0602
0603
0604
0605
0606
0607
0608 mutex_unlock(&cscfg_mutex);
0609
0610
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
0618 cscfg_set_configs_available(config_descs);
0619 goto exit_unlock;
0620
0621 err_clean_cfs:
0622
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
0643
0644
0645
0646
0647
0648
0649
0650
0651
0652
0653
0654
0655
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
0669 cscfg_mgr->load_state = CSCFG_UNLOAD;
0670
0671
0672 if (atomic_read(&cscfg_mgr->sys_active_cnt)) {
0673 err = -EBUSY;
0674 goto exit_unlock;
0675 }
0676
0677
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
0691 mutex_unlock(&cscfg_mutex);
0692 cscfg_fs_unregister_cfgs_feats(owner_info);
0693 mutex_lock(&cscfg_mutex);
0694
0695
0696 cscfg_unload_owned_cfgs_feats(owner_info);
0697
0698
0699 if (!list_is_singular(&cscfg_mgr->load_order_list)) {
0700
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
0713
0714
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
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
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
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
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
0789
0790
0791
0792
0793
0794
0795
0796
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
0807 ret = cscfg_list_add_csdev(csdev, match_flags, ops);
0808 if (ret)
0809 goto reg_csdev_unlock;
0810
0811
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
0834
0835
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
0847
0848
0849
0850
0851
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
0872
0873
0874
0875
0876
0877
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
0890 if (config_desc->available == false)
0891 return -EBUSY;
0892
0893
0894 err = cscfg_owner_get(config_desc->load_owner);
0895 if (err)
0896 break;
0897
0898
0899
0900
0901 atomic_inc(&cscfg_mgr->sys_active_cnt);
0902
0903
0904
0905
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
0934
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
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
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
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
0978
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
0991
0992
0993
0994
0995
0996
0997
0998
0999
1000
1001
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
1017
1018
1019
1020
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
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
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
1055 if (!atomic_read(&cscfg_mgr->sys_active_cnt))
1056 return 0;
1057
1058
1059
1060
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
1076
1077 if (config_csdev_active) {
1078
1079
1080
1081
1082
1083 err = cscfg_csdev_enable_config(config_csdev_active, preset);
1084 if (!err) {
1085
1086
1087
1088
1089
1090
1091
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
1107
1108
1109
1110
1111
1112
1113
1114
1115
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
1124
1125
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
1139 if (config_csdev)
1140 cscfg_csdev_disable_config(config_csdev);
1141 }
1142 EXPORT_SYMBOL_GPL(cscfg_csdev_disable_active_config);
1143
1144
1145
1146 struct device *cscfg_device(void)
1147 {
1148 return cscfg_mgr ? &cscfg_mgr->dev : NULL;
1149 }
1150
1151
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
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
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
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
1200
1201
1202
1203
1204
1205
1206 static void cscfg_unload_cfgs_on_exit(void)
1207 {
1208 struct cscfg_load_owner_info *owner_info = NULL;
1209
1210
1211
1212
1213
1214
1215 mutex_lock(&cscfg_mutex);
1216 while (!list_empty(&cscfg_mgr->load_order_list)) {
1217
1218
1219 owner_info = list_last_entry(&cscfg_mgr->load_order_list,
1220 struct cscfg_load_owner_info, item);
1221
1222
1223 switch (owner_info->type) {
1224 case CSCFG_OWNER_PRELOAD:
1225
1226
1227
1228
1229
1230 pr_info("cscfg: unloading preloaded configurations\n");
1231 break;
1232
1233 case CSCFG_OWNER_MODULE:
1234
1235
1236
1237
1238
1239
1240
1241 pr_err("cscfg: ERROR: prior module failed to unload configuration\n");
1242 goto list_remove;
1243 }
1244
1245
1246 mutex_unlock(&cscfg_mutex);
1247 cscfg_fs_unregister_cfgs_feats(owner_info);
1248 mutex_lock(&cscfg_mutex);
1249
1250
1251 cscfg_unload_owned_cfgs_feats(owner_info);
1252
1253 list_remove:
1254
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
1268 int __init cscfg_init(void)
1269 {
1270 int err = 0;
1271
1272
1273 err = cscfg_create_device();
1274 if (err)
1275 return err;
1276
1277
1278 err = cscfg_configfs_init(cscfg_mgr);
1279 if (err)
1280 goto exit_err;
1281
1282
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 }