1
2
3
4
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
17
18
19
20
21
22
23
24static DEFINE_MUTEX(cscfg_mutex);
25
26
27static struct cscfg_manager *cscfg_mgr;
28
29
30
31
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
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
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
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
72 for (i = 0; i < config_desc->nr_feat_refs; i++) {
73
74 feat_csdev = cscfg_get_feat_csdev(csdev, config_desc->feat_ref_names[i]);
75 if (feat_csdev) {
76
77
78
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
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
102
103
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
120
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
134 feat_csdev->nr_params = feat_desc->nr_params;
135
136
137
138
139
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
150
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
158
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
168 feat_csdev->feat_desc = feat_desc;
169 feat_csdev->csdev = csdev;
170
171 return feat_csdev;
172}
173
174
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
191 err = ops->load_feat(csdev, feat_csdev);
192 if (err)
193 return err;
194
195
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
206
207
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
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
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
249
250static int cscfg_load_feat(struct cscfg_feature_desc *feat_desc)
251{
252 int err;
253
254
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
265
266
267static int cscfg_load_config(struct cscfg_config_desc *config_desc)
268{
269 int err;
270
271
272 err = cscfg_check_feat_for_cfg(config_desc);
273 if (err)
274 return err;
275
276
277 err = cscfg_add_cfg_to_csdevs(config_desc);
278 if (err)
279 return err;
280
281
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
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
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
333 if (atomic_read(&cscfg_mgr->sys_active_cnt)) {
334 err = -EBUSY;
335 goto unlock_exit;
336 }
337
338
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
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
359
360
361
362
363
364
365
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
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
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
412
413
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
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
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
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
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
488
489
490
491
492
493
494
495
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
506 ret = cscfg_list_add_csdev(csdev, match_flags, ops);
507 if (ret)
508 goto reg_csdev_unlock;
509
510
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
533
534
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
546
547
548
549
550
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
571
572
573
574
575
576
577
578
579
580
581
582
583
584
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
597
598
599 atomic_inc(&cscfg_mgr->sys_active_cnt);
600
601
602
603
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
620
621
622
623
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
645
646
647
648
649
650
651
652
653
654
655
656
657
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
668 if (!atomic_read(&cscfg_mgr->sys_active_cnt))
669 return 0;
670
671
672
673
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
689
690 if (config_csdev_active) {
691
692
693
694
695
696 err = cscfg_csdev_enable_config(config_csdev_active, preset);
697 if (!err) {
698
699
700
701
702
703
704
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
720
721
722
723
724
725
726
727
728
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
737
738
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
752 if (config_csdev)
753 cscfg_csdev_disable_config(config_csdev);
754}
755EXPORT_SYMBOL_GPL(cscfg_csdev_disable_active_config);
756
757
758
759struct device *cscfg_device(void)
760{
761 return cscfg_mgr ? &cscfg_mgr->dev : NULL;
762}
763
764
765static void cscfg_dev_release(struct device *dev)
766{
767 kfree(cscfg_mgr);
768 cscfg_mgr = NULL;
769}
770
771
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
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
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
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