xref: /linux/drivers/hwtracing/coresight/coresight-syscfg.c (revision 3b6e3e04659a7e32cfbf71d6958eb6318bae50c0)
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 		raw_spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
93 		list_add(&config_csdev->node, &csdev->config_csdev_list);
94 		raw_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 	raw_spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
198 	list_add(&feat_csdev->node, &csdev->feature_csdev_list);
199 	raw_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 	guard(raw_spinlock_irqsave)(&csdev->cscfg_csdev_lock);
399 
400 	list_for_each_entry_safe(config_csdev, tmp, &csdev->config_csdev_list, node) {
401 		if (config_csdev->config_desc->load_owner == load_owner)
402 			list_del(&config_csdev->node);
403 	}
404 }
405 
406 static void cscfg_remove_owned_csdev_features(struct coresight_device *csdev, void *load_owner)
407 {
408 	struct cscfg_feature_csdev *feat_csdev, *tmp;
409 
410 	if (list_empty(&csdev->feature_csdev_list))
411 		return;
412 
413 	list_for_each_entry_safe(feat_csdev, tmp, &csdev->feature_csdev_list, node) {
414 		if (feat_csdev->feat_desc->load_owner == load_owner)
415 			list_del(&feat_csdev->node);
416 	}
417 }
418 
419 /*
420  * Unregister all configuration and features from configfs owned by load_owner.
421  * Although this is called without the list mutex being held, it is in the
422  * context of an unload operation which are strictly serialised,
423  * so the lists cannot change during this call.
424  */
425 static void cscfg_fs_unregister_cfgs_feats(void *load_owner)
426 {
427 	struct cscfg_config_desc *config_desc;
428 	struct cscfg_feature_desc *feat_desc;
429 
430 	list_for_each_entry(config_desc, &cscfg_mgr->config_desc_list, item) {
431 		if (config_desc->load_owner == load_owner)
432 			cscfg_configfs_del_config(config_desc);
433 	}
434 	list_for_each_entry(feat_desc, &cscfg_mgr->feat_desc_list, item) {
435 		if (feat_desc->load_owner == load_owner)
436 			cscfg_configfs_del_feature(feat_desc);
437 	}
438 }
439 
440 /*
441  * removal is relatively easy - just remove from all lists, anything that
442  * matches the owner. Memory for the descriptors will be managed by the owner,
443  * memory for the csdev items is devm_ allocated with the individual csdev
444  * devices.
445  */
446 static void cscfg_unload_owned_cfgs_feats(void *load_owner)
447 {
448 	struct cscfg_config_desc *config_desc, *cfg_tmp;
449 	struct cscfg_feature_desc *feat_desc, *feat_tmp;
450 	struct cscfg_registered_csdev *csdev_item;
451 
452 	lockdep_assert_held(&cscfg_mutex);
453 
454 	/* remove from each csdev instance feature and config lists */
455 	list_for_each_entry(csdev_item, &cscfg_mgr->csdev_desc_list, item) {
456 		/*
457 		 * for each csdev, check the loaded lists and remove if
458 		 * referenced descriptor is owned
459 		 */
460 		cscfg_remove_owned_csdev_configs(csdev_item->csdev, load_owner);
461 		cscfg_remove_owned_csdev_features(csdev_item->csdev, load_owner);
462 	}
463 
464 	/* remove from the config descriptor lists */
465 	list_for_each_entry_safe(config_desc, cfg_tmp, &cscfg_mgr->config_desc_list, item) {
466 		if (config_desc->load_owner == load_owner) {
467 			etm_perf_del_symlink_cscfg(config_desc);
468 			list_del(&config_desc->item);
469 		}
470 	}
471 
472 	/* remove from the feature descriptor lists */
473 	list_for_each_entry_safe(feat_desc, feat_tmp, &cscfg_mgr->feat_desc_list, item) {
474 		if (feat_desc->load_owner == load_owner) {
475 			list_del(&feat_desc->item);
476 		}
477 	}
478 }
479 
480 /*
481  * load the features and configs to the lists - called with list mutex held
482  */
483 static int cscfg_load_owned_cfgs_feats(struct cscfg_config_desc **config_descs,
484 				       struct cscfg_feature_desc **feat_descs,
485 				       struct cscfg_load_owner_info *owner_info)
486 {
487 	int i, err;
488 
489 	lockdep_assert_held(&cscfg_mutex);
490 
491 	/* load features first */
492 	if (feat_descs) {
493 		for (i = 0; feat_descs[i]; i++) {
494 			err = cscfg_load_feat(feat_descs[i]);
495 			if (err) {
496 				pr_err("coresight-syscfg: Failed to load feature %s\n",
497 				       feat_descs[i]->name);
498 				return err;
499 			}
500 			feat_descs[i]->load_owner = owner_info;
501 		}
502 	}
503 
504 	/* next any configurations to check feature dependencies */
505 	if (config_descs) {
506 		for (i = 0; config_descs[i]; i++) {
507 			err = cscfg_load_config(config_descs[i]);
508 			if (err) {
509 				pr_err("coresight-syscfg: Failed to load configuration %s\n",
510 				       config_descs[i]->name);
511 				return err;
512 			}
513 			config_descs[i]->load_owner = owner_info;
514 			config_descs[i]->available = false;
515 		}
516 	}
517 	return 0;
518 }
519 
520 /* set configurations as available to activate at the end of the load process */
521 static void cscfg_set_configs_available(struct cscfg_config_desc **config_descs)
522 {
523 	int i;
524 
525 	lockdep_assert_held(&cscfg_mutex);
526 
527 	if (config_descs) {
528 		for (i = 0; config_descs[i]; i++)
529 			config_descs[i]->available = true;
530 	}
531 }
532 
533 /*
534  * Create and register each of the configurations and features with configfs.
535  * Called without mutex being held.
536  */
537 static int cscfg_fs_register_cfgs_feats(struct cscfg_config_desc **config_descs,
538 					struct cscfg_feature_desc **feat_descs)
539 {
540 	int i, err;
541 
542 	if (feat_descs) {
543 		for (i = 0; feat_descs[i]; i++) {
544 			err = cscfg_configfs_add_feature(feat_descs[i]);
545 			if (err)
546 				return err;
547 		}
548 	}
549 	if (config_descs) {
550 		for (i = 0; config_descs[i]; i++) {
551 			err = cscfg_configfs_add_config(config_descs[i]);
552 			if (err)
553 				return err;
554 		}
555 	}
556 	return 0;
557 }
558 
559 /**
560  * cscfg_load_config_sets - API function to load feature and config sets.
561  *
562  * Take a 0 terminated array of feature descriptors and/or configuration
563  * descriptors and load into the system.
564  * Features are loaded first to ensure configuration dependencies can be met.
565  *
566  * To facilitate dynamic loading and unloading, features and configurations
567  * have a "load_owner", to allow later unload by the same owner. An owner may
568  * be a loadable module or configuration dynamically created via configfs.
569  * As later loaded configurations can use earlier loaded features, creating load
570  * dependencies, a load order list is maintained. Unload is strictly in the
571  * reverse order to load.
572  *
573  * @config_descs: 0 terminated array of configuration descriptors.
574  * @feat_descs:   0 terminated array of feature descriptors.
575  * @owner_info:	  Information on the owner of this set.
576  */
577 int cscfg_load_config_sets(struct cscfg_config_desc **config_descs,
578 			   struct cscfg_feature_desc **feat_descs,
579 			   struct cscfg_load_owner_info *owner_info)
580 {
581 	int err = 0;
582 
583 	mutex_lock(&cscfg_mutex);
584 	if (cscfg_mgr->load_state != CSCFG_NONE) {
585 		mutex_unlock(&cscfg_mutex);
586 		return -EBUSY;
587 	}
588 	cscfg_mgr->load_state = CSCFG_LOAD;
589 
590 	/* first load and add to the lists */
591 	err = cscfg_load_owned_cfgs_feats(config_descs, feat_descs, owner_info);
592 	if (err)
593 		goto err_clean_load;
594 
595 	/* add the load owner to the load order list */
596 	list_add_tail(&owner_info->item, &cscfg_mgr->load_order_list);
597 	if (!list_is_singular(&cscfg_mgr->load_order_list)) {
598 		/* lock previous item in load order list */
599 		err = cscfg_owner_get(list_prev_entry(owner_info, item));
600 		if (err)
601 			goto err_clean_owner_list;
602 	}
603 
604 	/*
605 	 * make visible to configfs - configfs manipulation must occur outside
606 	 * the list mutex lock to avoid circular lockdep issues with configfs
607 	 * built in mutexes and semaphores. This is safe as it is not possible
608 	 * to start a new load/unload operation till the current one is done.
609 	 */
610 	mutex_unlock(&cscfg_mutex);
611 
612 	/* create the configfs elements */
613 	err = cscfg_fs_register_cfgs_feats(config_descs, feat_descs);
614 	mutex_lock(&cscfg_mutex);
615 
616 	if (err)
617 		goto err_clean_cfs;
618 
619 	/* mark any new configs as available for activation */
620 	cscfg_set_configs_available(config_descs);
621 	goto exit_unlock;
622 
623 err_clean_cfs:
624 	/* cleanup after error registering with configfs */
625 	cscfg_fs_unregister_cfgs_feats(owner_info);
626 
627 	if (!list_is_singular(&cscfg_mgr->load_order_list))
628 		cscfg_owner_put(list_prev_entry(owner_info, item));
629 
630 err_clean_owner_list:
631 	list_del(&owner_info->item);
632 
633 err_clean_load:
634 	cscfg_unload_owned_cfgs_feats(owner_info);
635 
636 exit_unlock:
637 	cscfg_mgr->load_state = CSCFG_NONE;
638 	mutex_unlock(&cscfg_mutex);
639 	return err;
640 }
641 EXPORT_SYMBOL_GPL(cscfg_load_config_sets);
642 
643 /**
644  * cscfg_unload_config_sets - unload a set of configurations by owner.
645  *
646  * Dynamic unload of configuration and feature sets is done on the basis of
647  * the load owner of that set. Later loaded configurations can depend on
648  * features loaded earlier.
649  *
650  * Therefore, unload is only possible if:-
651  * 1) no configurations are active.
652  * 2) the set being unloaded was the last to be loaded to maintain dependencies.
653  *
654  * Once the unload operation commences, we disallow any configuration being
655  * made active until it is complete.
656  *
657  * @owner_info:	Information on owner for set being unloaded.
658  */
659 int cscfg_unload_config_sets(struct cscfg_load_owner_info *owner_info)
660 {
661 	int err = 0;
662 	struct cscfg_load_owner_info *load_list_item = NULL;
663 
664 	mutex_lock(&cscfg_mutex);
665 	if (cscfg_mgr->load_state != CSCFG_NONE) {
666 		mutex_unlock(&cscfg_mutex);
667 		return -EBUSY;
668 	}
669 
670 	/* unload op in progress also prevents activation of any config */
671 	cscfg_mgr->load_state = CSCFG_UNLOAD;
672 
673 	/* cannot unload if anything is active */
674 	if (atomic_read(&cscfg_mgr->sys_active_cnt)) {
675 		err = -EBUSY;
676 		goto exit_unlock;
677 	}
678 
679 	/* cannot unload if not last loaded in load order */
680 	if (!list_empty(&cscfg_mgr->load_order_list)) {
681 		load_list_item = list_last_entry(&cscfg_mgr->load_order_list,
682 						 struct cscfg_load_owner_info, item);
683 		if (load_list_item != owner_info)
684 			load_list_item = NULL;
685 	}
686 
687 	if (!load_list_item) {
688 		err = -EINVAL;
689 		goto exit_unlock;
690 	}
691 
692 	/* remove from configfs - again outside the scope of the list mutex */
693 	mutex_unlock(&cscfg_mutex);
694 	cscfg_fs_unregister_cfgs_feats(owner_info);
695 	mutex_lock(&cscfg_mutex);
696 
697 	/* unload everything from lists belonging to load_owner */
698 	cscfg_unload_owned_cfgs_feats(owner_info);
699 
700 	/* remove from load order list */
701 	if (!list_is_singular(&cscfg_mgr->load_order_list)) {
702 		/* unlock previous item in load order list */
703 		cscfg_owner_put(list_prev_entry(owner_info, item));
704 	}
705 	list_del(&owner_info->item);
706 
707 exit_unlock:
708 	cscfg_mgr->load_state = CSCFG_NONE;
709 	mutex_unlock(&cscfg_mutex);
710 	return err;
711 }
712 EXPORT_SYMBOL_GPL(cscfg_unload_config_sets);
713 
714 /* Handle coresight device registration and add configs and features to devices */
715 
716 /* iterate through config lists and load matching configs to device */
717 static int cscfg_add_cfgs_csdev(struct coresight_device *csdev)
718 {
719 	struct cscfg_config_desc *config_desc;
720 	int err = 0;
721 
722 	list_for_each_entry(config_desc, &cscfg_mgr->config_desc_list, item) {
723 		err = cscfg_add_csdev_cfg(csdev, config_desc);
724 		if (err)
725 			break;
726 	}
727 	return err;
728 }
729 
730 /* iterate through feature lists and load matching features to device */
731 static int cscfg_add_feats_csdev(struct coresight_device *csdev,
732 				 u32 match_flags,
733 				 struct cscfg_csdev_feat_ops *ops)
734 {
735 	struct cscfg_feature_desc *feat_desc;
736 	int err = 0;
737 
738 	if (!ops->load_feat)
739 		return -EINVAL;
740 
741 	list_for_each_entry(feat_desc, &cscfg_mgr->feat_desc_list, item) {
742 		if (feat_desc->match_flags & match_flags) {
743 			err = cscfg_load_feat_csdev(csdev, feat_desc, ops);
744 			if (err)
745 				break;
746 		}
747 	}
748 	return err;
749 }
750 
751 /* Add coresight device to list and copy its matching info */
752 static int cscfg_list_add_csdev(struct coresight_device *csdev,
753 				u32 match_flags,
754 				struct cscfg_csdev_feat_ops *ops)
755 {
756 	struct cscfg_registered_csdev *csdev_item;
757 
758 	/* allocate the list entry structure */
759 	csdev_item = kzalloc_obj(struct cscfg_registered_csdev);
760 	if (!csdev_item)
761 		return -ENOMEM;
762 
763 	csdev_item->csdev = csdev;
764 	csdev_item->match_flags = match_flags;
765 	csdev_item->ops.load_feat = ops->load_feat;
766 	list_add(&csdev_item->item, &cscfg_mgr->csdev_desc_list);
767 
768 	INIT_LIST_HEAD(&csdev->feature_csdev_list);
769 	INIT_LIST_HEAD(&csdev->config_csdev_list);
770 	raw_spin_lock_init(&csdev->cscfg_csdev_lock);
771 
772 	return 0;
773 }
774 
775 /* remove a coresight device from the list and free data */
776 static void cscfg_list_remove_csdev(struct coresight_device *csdev)
777 {
778 	struct cscfg_registered_csdev *csdev_item, *tmp;
779 
780 	list_for_each_entry_safe(csdev_item, tmp, &cscfg_mgr->csdev_desc_list, item) {
781 		if (csdev_item->csdev == csdev) {
782 			list_del(&csdev_item->item);
783 			kfree(csdev_item);
784 			break;
785 		}
786 	}
787 }
788 
789 /**
790  * cscfg_register_csdev - register a coresight device with the syscfg manager.
791  *
792  * Registers the coresight device with the system. @match_flags used to check
793  * if the device is a match for registered features. Any currently registered
794  * configurations and features that match the device will be loaded onto it.
795  *
796  * @csdev:		The coresight device to register.
797  * @match_flags:	Matching information to load features.
798  * @ops:		Standard operations supported by the device.
799  */
800 int cscfg_register_csdev(struct coresight_device *csdev,
801 			 u32 match_flags,
802 			 struct cscfg_csdev_feat_ops *ops)
803 {
804 	int ret = 0;
805 
806 	mutex_lock(&cscfg_mutex);
807 
808 	/* add device to list of registered devices  */
809 	ret = cscfg_list_add_csdev(csdev, match_flags, ops);
810 	if (ret)
811 		goto reg_csdev_unlock;
812 
813 	/* now load any registered features and configs matching the device. */
814 	ret = cscfg_add_feats_csdev(csdev, match_flags, ops);
815 	if (ret) {
816 		cscfg_list_remove_csdev(csdev);
817 		goto reg_csdev_unlock;
818 	}
819 
820 	ret = cscfg_add_cfgs_csdev(csdev);
821 	if (ret) {
822 		cscfg_list_remove_csdev(csdev);
823 		goto reg_csdev_unlock;
824 	}
825 
826 	pr_info("CSCFG registered %s", dev_name(&csdev->dev));
827 
828 reg_csdev_unlock:
829 	mutex_unlock(&cscfg_mutex);
830 	return ret;
831 }
832 EXPORT_SYMBOL_GPL(cscfg_register_csdev);
833 
834 /**
835  * cscfg_unregister_csdev - remove coresight device from syscfg manager.
836  *
837  * @csdev: Device to remove.
838  */
839 void cscfg_unregister_csdev(struct coresight_device *csdev)
840 {
841 	mutex_lock(&cscfg_mutex);
842 	cscfg_list_remove_csdev(csdev);
843 	mutex_unlock(&cscfg_mutex);
844 }
845 EXPORT_SYMBOL_GPL(cscfg_unregister_csdev);
846 
847 /**
848  * cscfg_csdev_reset_feats - reset features for a CoreSight device.
849  *
850  * Resets all parameters and register values for any features loaded
851  * into @csdev to their default values.
852  *
853  * @csdev: The CoreSight device.
854  */
855 void cscfg_csdev_reset_feats(struct coresight_device *csdev)
856 {
857 	struct cscfg_feature_csdev *feat_csdev;
858 	unsigned long flags;
859 
860 	raw_spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
861 	if (list_empty(&csdev->feature_csdev_list))
862 		goto unlock_exit;
863 
864 	list_for_each_entry(feat_csdev, &csdev->feature_csdev_list, node)
865 		cscfg_reset_feat(feat_csdev);
866 
867 unlock_exit:
868 	raw_spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
869 }
870 EXPORT_SYMBOL_GPL(cscfg_csdev_reset_feats);
871 
872 static bool cscfg_config_desc_get(struct cscfg_config_desc *config_desc)
873 {
874 	if (!atomic_fetch_inc(&config_desc->active_cnt)) {
875 		/* must ensure that config cannot be unloaded in use */
876 		if (unlikely(cscfg_owner_get(config_desc->load_owner))) {
877 			atomic_dec(&config_desc->active_cnt);
878 			return false;
879 		}
880 	}
881 
882 	return true;
883 }
884 
885 static void cscfg_config_desc_put(struct cscfg_config_desc *config_desc)
886 {
887 	if (!atomic_dec_return(&config_desc->active_cnt))
888 		cscfg_owner_put(config_desc->load_owner);
889 }
890 
891 /*
892  * This activate configuration for either perf or sysfs. Perf can have multiple
893  * active configs, selected per event, sysfs is limited to one.
894  *
895  * Increments the configuration descriptor active count and the global active
896  * count.
897  *
898  * @cfg_hash: Hash value of the selected configuration name.
899  */
900 static int _cscfg_activate_config(unsigned long cfg_hash)
901 {
902 	struct cscfg_config_desc *config_desc;
903 	int err = -EINVAL;
904 
905 	if (cscfg_mgr->load_state == CSCFG_UNLOAD)
906 		return -EBUSY;
907 
908 	list_for_each_entry(config_desc, &cscfg_mgr->config_desc_list, item) {
909 		if ((unsigned long)config_desc->event_ea->var == cfg_hash) {
910 			/* if we happen upon a partly loaded config, can't use it */
911 			if (config_desc->available == false)
912 				return -EBUSY;
913 
914 			if (!cscfg_config_desc_get(config_desc)) {
915 				err = -EINVAL;
916 				break;
917 			}
918 
919 			/*
920 			 * increment the global active count - control changes to
921 			 * active configurations
922 			 */
923 			atomic_inc(&cscfg_mgr->sys_active_cnt);
924 
925 			err = 0;
926 			dev_dbg(cscfg_device(), "Activate config %s.\n", config_desc->name);
927 			break;
928 		}
929 	}
930 	return err;
931 }
932 
933 static void _cscfg_deactivate_config(unsigned long cfg_hash)
934 {
935 	struct cscfg_config_desc *config_desc;
936 
937 	list_for_each_entry(config_desc, &cscfg_mgr->config_desc_list, item) {
938 		if ((unsigned long)config_desc->event_ea->var == cfg_hash) {
939 			atomic_dec(&cscfg_mgr->sys_active_cnt);
940 			cscfg_config_desc_put(config_desc);
941 			dev_dbg(cscfg_device(), "Deactivate config %s.\n", config_desc->name);
942 			break;
943 		}
944 	}
945 }
946 
947 /*
948  * called from configfs to set/clear the active configuration for use when
949  * using sysfs to control trace.
950  */
951 int cscfg_config_sysfs_activate(struct cscfg_config_desc *config_desc, bool activate)
952 {
953 	unsigned long cfg_hash;
954 	int err = 0;
955 
956 	guard(mutex)(&cscfg_mutex);
957 
958 	cfg_hash = (unsigned long)config_desc->event_ea->var;
959 
960 	if (activate) {
961 		/* cannot be a current active value to activate this */
962 		if (cscfg_mgr->sysfs_active_config)
963 			return -EBUSY;
964 
965 		scoped_guard(raw_spinlock_irqsave, &cscfg_mgr->sysfs_store_lock) {
966 			err = _cscfg_activate_config(cfg_hash);
967 			if (err)
968 				return err;
969 
970 			cscfg_mgr->sysfs_active_config = cfg_hash;
971 		}
972 	} else {
973 		if (cscfg_mgr->sysfs_active_config != cfg_hash)
974 			return -EINVAL;
975 
976 		scoped_guard(raw_spinlock_irqsave, &cscfg_mgr->sysfs_store_lock) {
977 			/* disable if matching current value */
978 			_cscfg_deactivate_config(cfg_hash);
979 			cscfg_mgr->sysfs_active_config = 0;
980 		}
981 	}
982 
983 	return 0;
984 }
985 
986 /* set the sysfs preset value */
987 void cscfg_config_sysfs_set_preset(int preset)
988 {
989 	guard(raw_spinlock_irqsave)(&cscfg_mgr->sysfs_store_lock);
990 	cscfg_mgr->sysfs_active_preset = preset;
991 }
992 
993 /*
994  * Used by a device to get the config and preset selected as active in configfs,
995  * when using sysfs to control trace.
996  */
997 void cscfg_config_sysfs_get_active_cfg(unsigned long *cfg_hash, int *preset)
998 {
999 	guard(raw_spinlock_irqsave)(&cscfg_mgr->sysfs_store_lock);
1000 	*preset = cscfg_mgr->sysfs_active_preset;
1001 	*cfg_hash = cscfg_mgr->sysfs_active_config;
1002 }
1003 EXPORT_SYMBOL_GPL(cscfg_config_sysfs_get_active_cfg);
1004 
1005 /**
1006  * cscfg_activate_config -  Mark a configuration descriptor as active.
1007  *
1008  * This will be seen when csdev devices are enabled in the system.
1009  * Only activated configurations can be enabled on individual devices.
1010  * Activation protects the configuration from alteration or removal while
1011  * active.
1012  *
1013  * Selection by hash value - generated from the configuration name when it
1014  * was loaded and added to the cs_etm/configurations file system for selection
1015  * by perf.
1016  *
1017  * @cfg_hash: Hash value of the selected configuration name.
1018  */
1019 int cscfg_activate_config(unsigned long cfg_hash)
1020 {
1021 	int err = 0;
1022 
1023 	mutex_lock(&cscfg_mutex);
1024 	err = _cscfg_activate_config(cfg_hash);
1025 	mutex_unlock(&cscfg_mutex);
1026 
1027 	return err;
1028 }
1029 EXPORT_SYMBOL_GPL(cscfg_activate_config);
1030 
1031 /**
1032  * cscfg_deactivate_config -  Mark a config descriptor as inactive.
1033  *
1034  * Decrement the configuration and global active counts.
1035  *
1036  * @cfg_hash: Hash value of the selected configuration name.
1037  */
1038 void cscfg_deactivate_config(unsigned long cfg_hash)
1039 {
1040 	mutex_lock(&cscfg_mutex);
1041 	_cscfg_deactivate_config(cfg_hash);
1042 	mutex_unlock(&cscfg_mutex);
1043 }
1044 EXPORT_SYMBOL_GPL(cscfg_deactivate_config);
1045 
1046 /**
1047  * cscfg_csdev_enable_active_config - Enable matching active configuration for device.
1048  *
1049  * Enables the configuration selected by @cfg_hash if the configuration is supported
1050  * on the device and has been activated.
1051  *
1052  * If active and supported the CoreSight device @csdev will be programmed with the
1053  * configuration, using @preset parameters.
1054  *
1055  * Should be called before driver hardware enable for the requested device, prior to
1056  * programming and enabling the physical hardware.
1057  *
1058  * @csdev:	CoreSight device to program.
1059  * @cfg_hash:	Selector for the configuration.
1060  * @preset:	Preset parameter values to use, 0 for current / default values.
1061  */
1062 int cscfg_csdev_enable_active_config(struct coresight_device *csdev,
1063 				     unsigned long cfg_hash, int preset)
1064 {
1065 	struct cscfg_config_csdev *config_csdev_active = NULL, *config_csdev_item;
1066 	struct cscfg_config_desc *config_desc;
1067 	unsigned long flags;
1068 	int err = 0;
1069 
1070 	/* quickly check global count */
1071 	if (!atomic_read(&cscfg_mgr->sys_active_cnt))
1072 		return 0;
1073 
1074 	/*
1075 	 * Look for matching configuration - set the active configuration
1076 	 * context if found.
1077 	 */
1078 	raw_spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
1079 	list_for_each_entry(config_csdev_item, &csdev->config_csdev_list, node) {
1080 		config_desc = config_csdev_item->config_desc;
1081 		if (((unsigned long)config_desc->event_ea->var == cfg_hash) &&
1082 				cscfg_config_desc_get(config_desc)) {
1083 			config_csdev_active = config_csdev_item;
1084 			csdev->active_cscfg_ctxt = (void *)config_csdev_active;
1085 			break;
1086 		}
1087 	}
1088 	raw_spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
1089 
1090 	/*
1091 	 * If found, attempt to enable
1092 	 */
1093 	if (config_csdev_active) {
1094 		/*
1095 		 * Call the generic routine that will program up the internal
1096 		 * driver structures prior to programming up the hardware.
1097 		 * This routine takes the driver spinlock saved in the configs.
1098 		 */
1099 		err = cscfg_csdev_enable_config(config_csdev_active, preset);
1100 		if (!err) {
1101 			/*
1102 			 * Successful programming. Check the active_cscfg_ctxt
1103 			 * pointer to ensure no pre-emption disabled it via
1104 			 * cscfg_csdev_disable_active_config() before
1105 			 * we could start.
1106 			 *
1107 			 * Set enabled if OK, err if not.
1108 			 */
1109 			raw_spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
1110 			if (csdev->active_cscfg_ctxt)
1111 				config_csdev_active->enabled = true;
1112 			else
1113 				err = -EBUSY;
1114 			raw_spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
1115 		}
1116 
1117 		if (err)
1118 			cscfg_config_desc_put(config_desc);
1119 	}
1120 
1121 	return err;
1122 }
1123 EXPORT_SYMBOL_GPL(cscfg_csdev_enable_active_config);
1124 
1125 /**
1126  * cscfg_csdev_disable_active_config - disable an active config on the device.
1127  *
1128  * Disables the active configuration on the CoreSight device @csdev.
1129  * Disable will save the values of any registers marked in the configurations
1130  * as save on disable.
1131  *
1132  * Should be called after driver hardware disable for the requested device,
1133  * after disabling the physical hardware and reading back registers.
1134  *
1135  * @csdev: The CoreSight device.
1136  */
1137 void cscfg_csdev_disable_active_config(struct coresight_device *csdev)
1138 {
1139 	struct cscfg_config_csdev *config_csdev;
1140 	unsigned long flags;
1141 
1142 	/*
1143 	 * Check if we have an active config, and that it was successfully enabled.
1144 	 * If it was not enabled, we have no work to do, otherwise mark as disabled.
1145 	 * Clear the active config pointer.
1146 	 */
1147 	raw_spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
1148 	config_csdev = (struct cscfg_config_csdev *)csdev->active_cscfg_ctxt;
1149 	if (config_csdev) {
1150 		if (!config_csdev->enabled)
1151 			config_csdev = NULL;
1152 		else
1153 			config_csdev->enabled = false;
1154 	}
1155 	csdev->active_cscfg_ctxt = NULL;
1156 	raw_spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
1157 
1158 	/* true if there was an enabled active config */
1159 	if (config_csdev) {
1160 		cscfg_csdev_disable_config(config_csdev);
1161 		cscfg_config_desc_put(config_csdev->config_desc);
1162 	}
1163 }
1164 EXPORT_SYMBOL_GPL(cscfg_csdev_disable_active_config);
1165 
1166 /* Initialise system configuration management device. */
1167 
1168 struct device *cscfg_device(void)
1169 {
1170 	return cscfg_mgr ? &cscfg_mgr->dev : NULL;
1171 }
1172 
1173 /* Must have a release function or the kernel will complain on module unload */
1174 static void cscfg_dev_release(struct device *dev)
1175 {
1176 	mutex_lock(&cscfg_mutex);
1177 	kfree(cscfg_mgr);
1178 	cscfg_mgr = NULL;
1179 	mutex_unlock(&cscfg_mutex);
1180 }
1181 
1182 /* a device is needed to "own" some kernel elements such as sysfs entries.  */
1183 static int cscfg_create_device(void)
1184 {
1185 	struct device *dev;
1186 	int err = -ENOMEM;
1187 
1188 	mutex_lock(&cscfg_mutex);
1189 	if (cscfg_mgr) {
1190 		err = -EINVAL;
1191 		goto create_dev_exit_unlock;
1192 	}
1193 
1194 	cscfg_mgr = kzalloc_obj(struct cscfg_manager);
1195 	if (!cscfg_mgr)
1196 		goto create_dev_exit_unlock;
1197 
1198 	/* initialise the cscfg_mgr structure */
1199 	INIT_LIST_HEAD(&cscfg_mgr->csdev_desc_list);
1200 	INIT_LIST_HEAD(&cscfg_mgr->feat_desc_list);
1201 	INIT_LIST_HEAD(&cscfg_mgr->config_desc_list);
1202 	INIT_LIST_HEAD(&cscfg_mgr->load_order_list);
1203 	atomic_set(&cscfg_mgr->sys_active_cnt, 0);
1204 	cscfg_mgr->load_state = CSCFG_NONE;
1205 	raw_spin_lock_init(&cscfg_mgr->sysfs_store_lock);
1206 
1207 	/* setup the device */
1208 	dev = cscfg_device();
1209 	dev->release = cscfg_dev_release;
1210 	dev->init_name = "cs_system_cfg";
1211 
1212 	err = device_register(dev);
1213 	if (err)
1214 		put_device(dev);
1215 
1216 create_dev_exit_unlock:
1217 	mutex_unlock(&cscfg_mutex);
1218 	return err;
1219 }
1220 
1221 /*
1222  * Loading and unloading is generally on user discretion.
1223  * If exiting due to coresight module unload, we need to unload any configurations that remain,
1224  * before we unregister the configfs intrastructure.
1225  *
1226  * Do this by walking the load_owner list and taking appropriate action, depending on the load
1227  * owner type.
1228  */
1229 static void cscfg_unload_cfgs_on_exit(void)
1230 {
1231 	struct cscfg_load_owner_info *owner_info = NULL;
1232 
1233 	/*
1234 	 * grab the mutex - even though we are exiting, some configfs files
1235 	 * may still be live till we dump them, so ensure list data is
1236 	 * protected from a race condition.
1237 	 */
1238 	mutex_lock(&cscfg_mutex);
1239 	while (!list_empty(&cscfg_mgr->load_order_list)) {
1240 
1241 		/* remove in reverse order of loading */
1242 		owner_info = list_last_entry(&cscfg_mgr->load_order_list,
1243 					     struct cscfg_load_owner_info, item);
1244 
1245 		/* action according to type */
1246 		switch (owner_info->type) {
1247 		case CSCFG_OWNER_PRELOAD:
1248 			/*
1249 			 * preloaded  descriptors are statically allocated in
1250 			 * this module - just need to unload dynamic items from
1251 			 * csdev lists, and remove from configfs directories.
1252 			 */
1253 			pr_info("cscfg: unloading preloaded configurations\n");
1254 			break;
1255 
1256 		case  CSCFG_OWNER_MODULE:
1257 			/*
1258 			 * this is an error - the loadable module must have been unloaded prior
1259 			 * to the coresight module unload. Therefore that module has not
1260 			 * correctly unloaded configs in its own exit code.
1261 			 * Nothing to do other than emit an error string as the static descriptor
1262 			 * references we need to unload will have disappeared with the module.
1263 			 */
1264 			pr_err("cscfg: ERROR: prior module failed to unload configuration\n");
1265 			goto list_remove;
1266 		}
1267 
1268 		/* remove from configfs - outside the scope of the list mutex */
1269 		mutex_unlock(&cscfg_mutex);
1270 		cscfg_fs_unregister_cfgs_feats(owner_info);
1271 		mutex_lock(&cscfg_mutex);
1272 
1273 		/* Next unload from csdev lists. */
1274 		cscfg_unload_owned_cfgs_feats(owner_info);
1275 
1276 list_remove:
1277 		/* remove from load order list */
1278 		list_del(&owner_info->item);
1279 	}
1280 	mutex_unlock(&cscfg_mutex);
1281 }
1282 
1283 static void cscfg_clear_device(void)
1284 {
1285 	cscfg_unload_cfgs_on_exit();
1286 	cscfg_configfs_release(cscfg_mgr);
1287 	device_unregister(cscfg_device());
1288 }
1289 
1290 /* Initialise system config management API device  */
1291 int __init cscfg_init(void)
1292 {
1293 	int err = 0;
1294 
1295 	/* create the device and init cscfg_mgr */
1296 	err = cscfg_create_device();
1297 	if (err)
1298 		return err;
1299 
1300 	/* initialise configfs subsystem */
1301 	err = cscfg_configfs_init(cscfg_mgr);
1302 	if (err)
1303 		goto exit_err;
1304 
1305 	/* preload built-in configurations */
1306 	err = cscfg_preload(THIS_MODULE);
1307 	if (err)
1308 		goto exit_err;
1309 
1310 	dev_info(cscfg_device(), "CoreSight Configuration manager initialised");
1311 	return 0;
1312 
1313 exit_err:
1314 	cscfg_clear_device();
1315 	return err;
1316 }
1317 
1318 void cscfg_exit(void)
1319 {
1320 	cscfg_clear_device();
1321 }
1322