GNU Linux-libre 5.19-rc6-gnu
[releases.git] / drivers / hwtracing / coresight / coresight-syscfg.c
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 */
24 static DEFINE_MUTEX(cscfg_mutex);
25
26 /* only one of these */
27 static 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 */
32 static struct cscfg_feature_csdev *
33 cscfg_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 */
45 static struct cscfg_config_csdev *
46 cscfg_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 */
63 static 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  */
105 static 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  */
122 static struct cscfg_feature_csdev *
123 cscfg_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 */
175 static 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  */
209 static 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. */
225 static 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. */
237 static 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  */
250 static int cscfg_load_feat(struct cscfg_feature_desc *feat_desc)
251 {
252         int err;
253         struct cscfg_feature_desc *feat_desc_exist;
254
255         /* new feature must have unique name */
256         list_for_each_entry(feat_desc_exist, &cscfg_mgr->feat_desc_list, item) {
257                 if (!strcmp(feat_desc_exist->name, feat_desc->name))
258                         return -EEXIST;
259         }
260
261         /* add feature to any matching registered devices */
262         err = cscfg_add_feat_to_csdevs(feat_desc);
263         if (err)
264                 return err;
265
266         list_add(&feat_desc->item, &cscfg_mgr->feat_desc_list);
267         return 0;
268 }
269
270 /*
271  * load config into the system - validate used features exist then add to
272  * config list.
273  */
274 static int cscfg_load_config(struct cscfg_config_desc *config_desc)
275 {
276         int err;
277         struct cscfg_config_desc *config_desc_exist;
278
279         /* new configuration must have a unique name */
280         list_for_each_entry(config_desc_exist, &cscfg_mgr->config_desc_list, item) {
281                 if (!strcmp(config_desc_exist->name, config_desc->name))
282                         return -EEXIST;
283         }
284
285         /* validate features are present */
286         err = cscfg_check_feat_for_cfg(config_desc);
287         if (err)
288                 return err;
289
290         /* add config to any matching registered device */
291         err = cscfg_add_cfg_to_csdevs(config_desc);
292         if (err)
293                 return err;
294
295         /* add config to perf fs to allow selection */
296         err = etm_perf_add_symlink_cscfg(cscfg_device(), config_desc);
297         if (err)
298                 return err;
299
300         list_add(&config_desc->item, &cscfg_mgr->config_desc_list);
301         atomic_set(&config_desc->active_cnt, 0);
302         return 0;
303 }
304
305 /* get a feature descriptor by name */
306 const struct cscfg_feature_desc *cscfg_get_named_feat_desc(const char *name)
307 {
308         const struct cscfg_feature_desc *feat_desc = NULL, *feat_desc_item;
309
310         mutex_lock(&cscfg_mutex);
311
312         list_for_each_entry(feat_desc_item, &cscfg_mgr->feat_desc_list, item) {
313                 if (strcmp(feat_desc_item->name, name) == 0) {
314                         feat_desc = feat_desc_item;
315                         break;
316                 }
317         }
318
319         mutex_unlock(&cscfg_mutex);
320         return feat_desc;
321 }
322
323 /* called with cscfg_mutex held */
324 static struct cscfg_feature_csdev *
325 cscfg_csdev_get_feat_from_desc(struct coresight_device *csdev,
326                                struct cscfg_feature_desc *feat_desc)
327 {
328         struct cscfg_feature_csdev *feat_csdev;
329
330         list_for_each_entry(feat_csdev, &csdev->feature_csdev_list, node) {
331                 if (feat_csdev->feat_desc == feat_desc)
332                         return feat_csdev;
333         }
334         return NULL;
335 }
336
337 int cscfg_update_feat_param_val(struct cscfg_feature_desc *feat_desc,
338                                 int param_idx, u64 value)
339 {
340         int err = 0;
341         struct cscfg_feature_csdev *feat_csdev;
342         struct cscfg_registered_csdev *csdev_item;
343
344         mutex_lock(&cscfg_mutex);
345
346         /* check if any config active & return busy */
347         if (atomic_read(&cscfg_mgr->sys_active_cnt)) {
348                 err = -EBUSY;
349                 goto unlock_exit;
350         }
351
352         /* set the value */
353         if ((param_idx < 0) || (param_idx >= feat_desc->nr_params)) {
354                 err = -EINVAL;
355                 goto unlock_exit;
356         }
357         feat_desc->params_desc[param_idx].value = value;
358
359         /* update loaded instances.*/
360         list_for_each_entry(csdev_item, &cscfg_mgr->csdev_desc_list, item) {
361                 feat_csdev = cscfg_csdev_get_feat_from_desc(csdev_item->csdev, feat_desc);
362                 if (feat_csdev)
363                         feat_csdev->params_csdev[param_idx].current_value = value;
364         }
365
366 unlock_exit:
367         mutex_unlock(&cscfg_mutex);
368         return err;
369 }
370
371 /*
372  * Conditionally up reference count on owner to prevent unload.
373  *
374  * module loaded configs need to be locked in to prevent premature unload.
375  */
376 static int cscfg_owner_get(struct cscfg_load_owner_info *owner_info)
377 {
378         if ((owner_info->type == CSCFG_OWNER_MODULE) &&
379             (!try_module_get(owner_info->owner_handle)))
380                 return -EINVAL;
381         return 0;
382 }
383
384 /* conditionally lower ref count on an owner */
385 static void cscfg_owner_put(struct cscfg_load_owner_info *owner_info)
386 {
387         if (owner_info->type == CSCFG_OWNER_MODULE)
388                 module_put(owner_info->owner_handle);
389 }
390
391 static void cscfg_remove_owned_csdev_configs(struct coresight_device *csdev, void *load_owner)
392 {
393         struct cscfg_config_csdev *config_csdev, *tmp;
394
395         if (list_empty(&csdev->config_csdev_list))
396                 return;
397
398         list_for_each_entry_safe(config_csdev, tmp, &csdev->config_csdev_list, node) {
399                 if (config_csdev->config_desc->load_owner == load_owner)
400                         list_del(&config_csdev->node);
401         }
402 }
403
404 static void cscfg_remove_owned_csdev_features(struct coresight_device *csdev, void *load_owner)
405 {
406         struct cscfg_feature_csdev *feat_csdev, *tmp;
407
408         if (list_empty(&csdev->feature_csdev_list))
409                 return;
410
411         list_for_each_entry_safe(feat_csdev, tmp, &csdev->feature_csdev_list, node) {
412                 if (feat_csdev->feat_desc->load_owner == load_owner)
413                         list_del(&feat_csdev->node);
414         }
415 }
416
417 /*
418  * removal is relatively easy - just remove from all lists, anything that
419  * matches the owner. Memory for the descriptors will be managed by the owner,
420  * memory for the csdev items is devm_ allocated with the individual csdev
421  * devices.
422  */
423 static void cscfg_unload_owned_cfgs_feats(void *load_owner)
424 {
425         struct cscfg_config_desc *config_desc, *cfg_tmp;
426         struct cscfg_feature_desc *feat_desc, *feat_tmp;
427         struct cscfg_registered_csdev *csdev_item;
428
429         /* remove from each csdev instance feature and config lists */
430         list_for_each_entry(csdev_item, &cscfg_mgr->csdev_desc_list, item) {
431                 /*
432                  * for each csdev, check the loaded lists and remove if
433                  * referenced descriptor is owned
434                  */
435                 cscfg_remove_owned_csdev_configs(csdev_item->csdev, load_owner);
436                 cscfg_remove_owned_csdev_features(csdev_item->csdev, load_owner);
437         }
438
439         /* remove from the config descriptor lists */
440         list_for_each_entry_safe(config_desc, cfg_tmp, &cscfg_mgr->config_desc_list, item) {
441                 if (config_desc->load_owner == load_owner) {
442                         cscfg_configfs_del_config(config_desc);
443                         etm_perf_del_symlink_cscfg(config_desc);
444                         list_del(&config_desc->item);
445                 }
446         }
447
448         /* remove from the feature descriptor lists */
449         list_for_each_entry_safe(feat_desc, feat_tmp, &cscfg_mgr->feat_desc_list, item) {
450                 if (feat_desc->load_owner == load_owner) {
451                         cscfg_configfs_del_feature(feat_desc);
452                         list_del(&feat_desc->item);
453                 }
454         }
455 }
456
457 /**
458  * cscfg_load_config_sets - API function to load feature and config sets.
459  *
460  * Take a 0 terminated array of feature descriptors and/or configuration
461  * descriptors and load into the system.
462  * Features are loaded first to ensure configuration dependencies can be met.
463  *
464  * To facilitate dynamic loading and unloading, features and configurations
465  * have a "load_owner", to allow later unload by the same owner. An owner may
466  * be a loadable module or configuration dynamically created via configfs.
467  * As later loaded configurations can use earlier loaded features, creating load
468  * dependencies, a load order list is maintained. Unload is strictly in the
469  * reverse order to load.
470  *
471  * @config_descs: 0 terminated array of configuration descriptors.
472  * @feat_descs:   0 terminated array of feature descriptors.
473  * @owner_info:   Information on the owner of this set.
474  */
475 int cscfg_load_config_sets(struct cscfg_config_desc **config_descs,
476                            struct cscfg_feature_desc **feat_descs,
477                            struct cscfg_load_owner_info *owner_info)
478 {
479         int err = 0, i = 0;
480
481         mutex_lock(&cscfg_mutex);
482
483         /* load features first */
484         if (feat_descs) {
485                 while (feat_descs[i]) {
486                         err = cscfg_load_feat(feat_descs[i]);
487                         if (!err)
488                                 err = cscfg_configfs_add_feature(feat_descs[i]);
489                         if (err) {
490                                 pr_err("coresight-syscfg: Failed to load feature %s\n",
491                                        feat_descs[i]->name);
492                                 cscfg_unload_owned_cfgs_feats(owner_info);
493                                 goto exit_unlock;
494                         }
495                         feat_descs[i]->load_owner = owner_info;
496                         i++;
497                 }
498         }
499
500         /* next any configurations to check feature dependencies */
501         i = 0;
502         if (config_descs) {
503                 while (config_descs[i]) {
504                         err = cscfg_load_config(config_descs[i]);
505                         if (!err)
506                                 err = cscfg_configfs_add_config(config_descs[i]);
507                         if (err) {
508                                 pr_err("coresight-syscfg: Failed to load configuration %s\n",
509                                        config_descs[i]->name);
510                                 cscfg_unload_owned_cfgs_feats(owner_info);
511                                 goto exit_unlock;
512                         }
513                         config_descs[i]->load_owner = owner_info;
514                         i++;
515                 }
516         }
517
518         /* add the load owner to the load order list */
519         list_add_tail(&owner_info->item, &cscfg_mgr->load_order_list);
520         if (!list_is_singular(&cscfg_mgr->load_order_list)) {
521                 /* lock previous item in load order list */
522                 err = cscfg_owner_get(list_prev_entry(owner_info, item));
523                 if (err) {
524                         cscfg_unload_owned_cfgs_feats(owner_info);
525                         list_del(&owner_info->item);
526                 }
527         }
528
529 exit_unlock:
530         mutex_unlock(&cscfg_mutex);
531         return err;
532 }
533 EXPORT_SYMBOL_GPL(cscfg_load_config_sets);
534
535 /**
536  * cscfg_unload_config_sets - unload a set of configurations by owner.
537  *
538  * Dynamic unload of configuration and feature sets is done on the basis of
539  * the load owner of that set. Later loaded configurations can depend on
540  * features loaded earlier.
541  *
542  * Therefore, unload is only possible if:-
543  * 1) no configurations are active.
544  * 2) the set being unloaded was the last to be loaded to maintain dependencies.
545  *
546  * @owner_info: Information on owner for set being unloaded.
547  */
548 int cscfg_unload_config_sets(struct cscfg_load_owner_info *owner_info)
549 {
550         int err = 0;
551         struct cscfg_load_owner_info *load_list_item = NULL;
552
553         mutex_lock(&cscfg_mutex);
554
555         /* cannot unload if anything is active */
556         if (atomic_read(&cscfg_mgr->sys_active_cnt)) {
557                 err = -EBUSY;
558                 goto exit_unlock;
559         }
560
561         /* cannot unload if not last loaded in load order */
562         if (!list_empty(&cscfg_mgr->load_order_list)) {
563                 load_list_item = list_last_entry(&cscfg_mgr->load_order_list,
564                                                  struct cscfg_load_owner_info, item);
565                 if (load_list_item != owner_info)
566                         load_list_item = NULL;
567         }
568
569         if (!load_list_item) {
570                 err = -EINVAL;
571                 goto exit_unlock;
572         }
573
574         /* unload all belonging to load_owner */
575         cscfg_unload_owned_cfgs_feats(owner_info);
576
577         /* remove from load order list */
578         if (!list_is_singular(&cscfg_mgr->load_order_list)) {
579                 /* unlock previous item in load order list */
580                 cscfg_owner_put(list_prev_entry(owner_info, item));
581         }
582         list_del(&owner_info->item);
583
584 exit_unlock:
585         mutex_unlock(&cscfg_mutex);
586         return err;
587 }
588 EXPORT_SYMBOL_GPL(cscfg_unload_config_sets);
589
590 /* Handle coresight device registration and add configs and features to devices */
591
592 /* iterate through config lists and load matching configs to device */
593 static int cscfg_add_cfgs_csdev(struct coresight_device *csdev)
594 {
595         struct cscfg_config_desc *config_desc;
596         int err = 0;
597
598         list_for_each_entry(config_desc, &cscfg_mgr->config_desc_list, item) {
599                 err = cscfg_add_csdev_cfg(csdev, config_desc);
600                 if (err)
601                         break;
602         }
603         return err;
604 }
605
606 /* iterate through feature lists and load matching features to device */
607 static int cscfg_add_feats_csdev(struct coresight_device *csdev,
608                                  u32 match_flags,
609                                  struct cscfg_csdev_feat_ops *ops)
610 {
611         struct cscfg_feature_desc *feat_desc;
612         int err = 0;
613
614         if (!ops->load_feat)
615                 return -EINVAL;
616
617         list_for_each_entry(feat_desc, &cscfg_mgr->feat_desc_list, item) {
618                 if (feat_desc->match_flags & match_flags) {
619                         err = cscfg_load_feat_csdev(csdev, feat_desc, ops);
620                         if (err)
621                                 break;
622                 }
623         }
624         return err;
625 }
626
627 /* Add coresight device to list and copy its matching info */
628 static int cscfg_list_add_csdev(struct coresight_device *csdev,
629                                 u32 match_flags,
630                                 struct cscfg_csdev_feat_ops *ops)
631 {
632         struct cscfg_registered_csdev *csdev_item;
633
634         /* allocate the list entry structure */
635         csdev_item = kzalloc(sizeof(struct cscfg_registered_csdev), GFP_KERNEL);
636         if (!csdev_item)
637                 return -ENOMEM;
638
639         csdev_item->csdev = csdev;
640         csdev_item->match_flags = match_flags;
641         csdev_item->ops.load_feat = ops->load_feat;
642         list_add(&csdev_item->item, &cscfg_mgr->csdev_desc_list);
643
644         INIT_LIST_HEAD(&csdev->feature_csdev_list);
645         INIT_LIST_HEAD(&csdev->config_csdev_list);
646         spin_lock_init(&csdev->cscfg_csdev_lock);
647
648         return 0;
649 }
650
651 /* remove a coresight device from the list and free data */
652 static void cscfg_list_remove_csdev(struct coresight_device *csdev)
653 {
654         struct cscfg_registered_csdev *csdev_item, *tmp;
655
656         list_for_each_entry_safe(csdev_item, tmp, &cscfg_mgr->csdev_desc_list, item) {
657                 if (csdev_item->csdev == csdev) {
658                         list_del(&csdev_item->item);
659                         kfree(csdev_item);
660                         break;
661                 }
662         }
663 }
664
665 /**
666  * cscfg_register_csdev - register a coresight device with the syscfg manager.
667  *
668  * Registers the coresight device with the system. @match_flags used to check
669  * if the device is a match for registered features. Any currently registered
670  * configurations and features that match the device will be loaded onto it.
671  *
672  * @csdev:              The coresight device to register.
673  * @match_flags:        Matching information to load features.
674  * @ops:                Standard operations supported by the device.
675  */
676 int cscfg_register_csdev(struct coresight_device *csdev,
677                          u32 match_flags,
678                          struct cscfg_csdev_feat_ops *ops)
679 {
680         int ret = 0;
681
682         mutex_lock(&cscfg_mutex);
683
684         /* add device to list of registered devices  */
685         ret = cscfg_list_add_csdev(csdev, match_flags, ops);
686         if (ret)
687                 goto reg_csdev_unlock;
688
689         /* now load any registered features and configs matching the device. */
690         ret = cscfg_add_feats_csdev(csdev, match_flags, ops);
691         if (ret) {
692                 cscfg_list_remove_csdev(csdev);
693                 goto reg_csdev_unlock;
694         }
695
696         ret = cscfg_add_cfgs_csdev(csdev);
697         if (ret) {
698                 cscfg_list_remove_csdev(csdev);
699                 goto reg_csdev_unlock;
700         }
701
702         pr_info("CSCFG registered %s", dev_name(&csdev->dev));
703
704 reg_csdev_unlock:
705         mutex_unlock(&cscfg_mutex);
706         return ret;
707 }
708 EXPORT_SYMBOL_GPL(cscfg_register_csdev);
709
710 /**
711  * cscfg_unregister_csdev - remove coresight device from syscfg manager.
712  *
713  * @csdev: Device to remove.
714  */
715 void cscfg_unregister_csdev(struct coresight_device *csdev)
716 {
717         mutex_lock(&cscfg_mutex);
718         cscfg_list_remove_csdev(csdev);
719         mutex_unlock(&cscfg_mutex);
720 }
721 EXPORT_SYMBOL_GPL(cscfg_unregister_csdev);
722
723 /**
724  * cscfg_csdev_reset_feats - reset features for a CoreSight device.
725  *
726  * Resets all parameters and register values for any features loaded
727  * into @csdev to their default values.
728  *
729  * @csdev: The CoreSight device.
730  */
731 void cscfg_csdev_reset_feats(struct coresight_device *csdev)
732 {
733         struct cscfg_feature_csdev *feat_csdev;
734         unsigned long flags;
735
736         spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
737         if (list_empty(&csdev->feature_csdev_list))
738                 goto unlock_exit;
739
740         list_for_each_entry(feat_csdev, &csdev->feature_csdev_list, node)
741                 cscfg_reset_feat(feat_csdev);
742
743 unlock_exit:
744         spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
745 }
746 EXPORT_SYMBOL_GPL(cscfg_csdev_reset_feats);
747
748 /*
749  * This activate configuration for either perf or sysfs. Perf can have multiple
750  * active configs, selected per event, sysfs is limited to one.
751  *
752  * Increments the configuration descriptor active count and the global active
753  * count.
754  *
755  * @cfg_hash: Hash value of the selected configuration name.
756  */
757 static int _cscfg_activate_config(unsigned long cfg_hash)
758 {
759         struct cscfg_config_desc *config_desc;
760         int err = -EINVAL;
761
762         list_for_each_entry(config_desc, &cscfg_mgr->config_desc_list, item) {
763                 if ((unsigned long)config_desc->event_ea->var == cfg_hash) {
764                         /* must ensure that config cannot be unloaded in use */
765                         err = cscfg_owner_get(config_desc->load_owner);
766                         if (err)
767                                 break;
768                         /*
769                          * increment the global active count - control changes to
770                          * active configurations
771                          */
772                         atomic_inc(&cscfg_mgr->sys_active_cnt);
773
774                         /*
775                          * mark the descriptor as active so enable config on a
776                          * device instance will use it
777                          */
778                         atomic_inc(&config_desc->active_cnt);
779
780                         err = 0;
781                         dev_dbg(cscfg_device(), "Activate config %s.\n", config_desc->name);
782                         break;
783                 }
784         }
785         return err;
786 }
787
788 static void _cscfg_deactivate_config(unsigned long cfg_hash)
789 {
790         struct cscfg_config_desc *config_desc;
791
792         list_for_each_entry(config_desc, &cscfg_mgr->config_desc_list, item) {
793                 if ((unsigned long)config_desc->event_ea->var == cfg_hash) {
794                         atomic_dec(&config_desc->active_cnt);
795                         atomic_dec(&cscfg_mgr->sys_active_cnt);
796                         cscfg_owner_put(config_desc->load_owner);
797                         dev_dbg(cscfg_device(), "Deactivate config %s.\n", config_desc->name);
798                         break;
799                 }
800         }
801 }
802
803 /*
804  * called from configfs to set/clear the active configuration for use when
805  * using sysfs to control trace.
806  */
807 int cscfg_config_sysfs_activate(struct cscfg_config_desc *config_desc, bool activate)
808 {
809         unsigned long cfg_hash;
810         int err = 0;
811
812         mutex_lock(&cscfg_mutex);
813
814         cfg_hash = (unsigned long)config_desc->event_ea->var;
815
816         if (activate) {
817                 /* cannot be a current active value to activate this */
818                 if (cscfg_mgr->sysfs_active_config) {
819                         err = -EBUSY;
820                         goto exit_unlock;
821                 }
822                 err = _cscfg_activate_config(cfg_hash);
823                 if (!err)
824                         cscfg_mgr->sysfs_active_config = cfg_hash;
825         } else {
826                 /* disable if matching current value */
827                 if (cscfg_mgr->sysfs_active_config == cfg_hash) {
828                         _cscfg_deactivate_config(cfg_hash);
829                         cscfg_mgr->sysfs_active_config = 0;
830                 } else
831                         err = -EINVAL;
832         }
833
834 exit_unlock:
835         mutex_unlock(&cscfg_mutex);
836         return err;
837 }
838
839 /* set the sysfs preset value */
840 void cscfg_config_sysfs_set_preset(int preset)
841 {
842         mutex_lock(&cscfg_mutex);
843         cscfg_mgr->sysfs_active_preset = preset;
844         mutex_unlock(&cscfg_mutex);
845 }
846
847 /*
848  * Used by a device to get the config and preset selected as active in configfs,
849  * when using sysfs to control trace.
850  */
851 void cscfg_config_sysfs_get_active_cfg(unsigned long *cfg_hash, int *preset)
852 {
853         mutex_lock(&cscfg_mutex);
854         *preset = cscfg_mgr->sysfs_active_preset;
855         *cfg_hash = cscfg_mgr->sysfs_active_config;
856         mutex_unlock(&cscfg_mutex);
857 }
858 EXPORT_SYMBOL_GPL(cscfg_config_sysfs_get_active_cfg);
859
860 /**
861  * cscfg_activate_config -  Mark a configuration descriptor as active.
862  *
863  * This will be seen when csdev devices are enabled in the system.
864  * Only activated configurations can be enabled on individual devices.
865  * Activation protects the configuration from alteration or removal while
866  * active.
867  *
868  * Selection by hash value - generated from the configuration name when it
869  * was loaded and added to the cs_etm/configurations file system for selection
870  * by perf.
871  *
872  * @cfg_hash: Hash value of the selected configuration name.
873  */
874 int cscfg_activate_config(unsigned long cfg_hash)
875 {
876         int err = 0;
877
878         mutex_lock(&cscfg_mutex);
879         err = _cscfg_activate_config(cfg_hash);
880         mutex_unlock(&cscfg_mutex);
881
882         return err;
883 }
884 EXPORT_SYMBOL_GPL(cscfg_activate_config);
885
886 /**
887  * cscfg_deactivate_config -  Mark a config descriptor as inactive.
888  *
889  * Decrement the configuration and global active counts.
890  *
891  * @cfg_hash: Hash value of the selected configuration name.
892  */
893 void cscfg_deactivate_config(unsigned long cfg_hash)
894 {
895         mutex_lock(&cscfg_mutex);
896         _cscfg_deactivate_config(cfg_hash);
897         mutex_unlock(&cscfg_mutex);
898 }
899 EXPORT_SYMBOL_GPL(cscfg_deactivate_config);
900
901 /**
902  * cscfg_csdev_enable_active_config - Enable matching active configuration for device.
903  *
904  * Enables the configuration selected by @cfg_hash if the configuration is supported
905  * on the device and has been activated.
906  *
907  * If active and supported the CoreSight device @csdev will be programmed with the
908  * configuration, using @preset parameters.
909  *
910  * Should be called before driver hardware enable for the requested device, prior to
911  * programming and enabling the physical hardware.
912  *
913  * @csdev:      CoreSight device to program.
914  * @cfg_hash:   Selector for the configuration.
915  * @preset:     Preset parameter values to use, 0 for current / default values.
916  */
917 int cscfg_csdev_enable_active_config(struct coresight_device *csdev,
918                                      unsigned long cfg_hash, int preset)
919 {
920         struct cscfg_config_csdev *config_csdev_active = NULL, *config_csdev_item;
921         const struct cscfg_config_desc *config_desc;
922         unsigned long flags;
923         int err = 0;
924
925         /* quickly check global count */
926         if (!atomic_read(&cscfg_mgr->sys_active_cnt))
927                 return 0;
928
929         /*
930          * Look for matching configuration - set the active configuration
931          * context if found.
932          */
933         spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
934         list_for_each_entry(config_csdev_item, &csdev->config_csdev_list, node) {
935                 config_desc = config_csdev_item->config_desc;
936                 if ((atomic_read(&config_desc->active_cnt)) &&
937                     ((unsigned long)config_desc->event_ea->var == cfg_hash)) {
938                         config_csdev_active = config_csdev_item;
939                         csdev->active_cscfg_ctxt = (void *)config_csdev_active;
940                         break;
941                 }
942         }
943         spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
944
945         /*
946          * If found, attempt to enable
947          */
948         if (config_csdev_active) {
949                 /*
950                  * Call the generic routine that will program up the internal
951                  * driver structures prior to programming up the hardware.
952                  * This routine takes the driver spinlock saved in the configs.
953                  */
954                 err = cscfg_csdev_enable_config(config_csdev_active, preset);
955                 if (!err) {
956                         /*
957                          * Successful programming. Check the active_cscfg_ctxt
958                          * pointer to ensure no pre-emption disabled it via
959                          * cscfg_csdev_disable_active_config() before
960                          * we could start.
961                          *
962                          * Set enabled if OK, err if not.
963                          */
964                         spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
965                         if (csdev->active_cscfg_ctxt)
966                                 config_csdev_active->enabled = true;
967                         else
968                                 err = -EBUSY;
969                         spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
970                 }
971         }
972         return err;
973 }
974 EXPORT_SYMBOL_GPL(cscfg_csdev_enable_active_config);
975
976 /**
977  * cscfg_csdev_disable_active_config - disable an active config on the device.
978  *
979  * Disables the active configuration on the CoreSight device @csdev.
980  * Disable will save the values of any registers marked in the configurations
981  * as save on disable.
982  *
983  * Should be called after driver hardware disable for the requested device,
984  * after disabling the physical hardware and reading back registers.
985  *
986  * @csdev: The CoreSight device.
987  */
988 void cscfg_csdev_disable_active_config(struct coresight_device *csdev)
989 {
990         struct cscfg_config_csdev *config_csdev;
991         unsigned long flags;
992
993         /*
994          * Check if we have an active config, and that it was successfully enabled.
995          * If it was not enabled, we have no work to do, otherwise mark as disabled.
996          * Clear the active config pointer.
997          */
998         spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
999         config_csdev = (struct cscfg_config_csdev *)csdev->active_cscfg_ctxt;
1000         if (config_csdev) {
1001                 if (!config_csdev->enabled)
1002                         config_csdev = NULL;
1003                 else
1004                         config_csdev->enabled = false;
1005         }
1006         csdev->active_cscfg_ctxt = NULL;
1007         spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
1008
1009         /* true if there was an enabled active config */
1010         if (config_csdev)
1011                 cscfg_csdev_disable_config(config_csdev);
1012 }
1013 EXPORT_SYMBOL_GPL(cscfg_csdev_disable_active_config);
1014
1015 /* Initialise system configuration management device. */
1016
1017 struct device *cscfg_device(void)
1018 {
1019         return cscfg_mgr ? &cscfg_mgr->dev : NULL;
1020 }
1021
1022 /* Must have a release function or the kernel will complain on module unload */
1023 static void cscfg_dev_release(struct device *dev)
1024 {
1025         kfree(cscfg_mgr);
1026         cscfg_mgr = NULL;
1027 }
1028
1029 /* a device is needed to "own" some kernel elements such as sysfs entries.  */
1030 static int cscfg_create_device(void)
1031 {
1032         struct device *dev;
1033         int err = -ENOMEM;
1034
1035         mutex_lock(&cscfg_mutex);
1036         if (cscfg_mgr) {
1037                 err = -EINVAL;
1038                 goto create_dev_exit_unlock;
1039         }
1040
1041         cscfg_mgr = kzalloc(sizeof(struct cscfg_manager), GFP_KERNEL);
1042         if (!cscfg_mgr)
1043                 goto create_dev_exit_unlock;
1044
1045         /* setup the device */
1046         dev = cscfg_device();
1047         dev->release = cscfg_dev_release;
1048         dev->init_name = "cs_system_cfg";
1049
1050         err = device_register(dev);
1051         if (err)
1052                 put_device(dev);
1053
1054 create_dev_exit_unlock:
1055         mutex_unlock(&cscfg_mutex);
1056         return err;
1057 }
1058
1059 static void cscfg_clear_device(void)
1060 {
1061         struct cscfg_config_desc *cfg_desc;
1062
1063         mutex_lock(&cscfg_mutex);
1064         list_for_each_entry(cfg_desc, &cscfg_mgr->config_desc_list, item) {
1065                 etm_perf_del_symlink_cscfg(cfg_desc);
1066         }
1067         cscfg_configfs_release(cscfg_mgr);
1068         device_unregister(cscfg_device());
1069         mutex_unlock(&cscfg_mutex);
1070 }
1071
1072 /* Initialise system config management API device  */
1073 int __init cscfg_init(void)
1074 {
1075         int err = 0;
1076
1077         err = cscfg_create_device();
1078         if (err)
1079                 return err;
1080
1081         err = cscfg_configfs_init(cscfg_mgr);
1082         if (err)
1083                 goto exit_err;
1084
1085         INIT_LIST_HEAD(&cscfg_mgr->csdev_desc_list);
1086         INIT_LIST_HEAD(&cscfg_mgr->feat_desc_list);
1087         INIT_LIST_HEAD(&cscfg_mgr->config_desc_list);
1088         INIT_LIST_HEAD(&cscfg_mgr->load_order_list);
1089         atomic_set(&cscfg_mgr->sys_active_cnt, 0);
1090
1091         /* preload built-in configurations */
1092         err = cscfg_preload(THIS_MODULE);
1093         if (err)
1094                 goto exit_err;
1095
1096         dev_info(cscfg_device(), "CoreSight Configuration manager initialised");
1097         return 0;
1098
1099 exit_err:
1100         cscfg_clear_device();
1101         return err;
1102 }
1103
1104 void cscfg_exit(void)
1105 {
1106         cscfg_clear_device();
1107 }