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 *
cscfg_get_feat_csdev(struct coresight_device * csdev,const char * name)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 *
cscfg_alloc_csdev_cfg(struct coresight_device * csdev,int nr_feats)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 */
cscfg_add_csdev_cfg(struct coresight_device * csdev,struct cscfg_config_desc * config_desc)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 */
cscfg_add_cfg_to_csdevs(struct cscfg_config_desc * config_desc)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 *
cscfg_alloc_csdev_feat(struct coresight_device * csdev,struct cscfg_feature_desc * feat_desc)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 */
cscfg_load_feat_csdev(struct coresight_device * csdev,struct cscfg_feature_desc * feat_desc,struct cscfg_csdev_feat_ops * ops)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 */
cscfg_add_feat_to_csdevs(struct cscfg_feature_desc * feat_desc)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. */
cscfg_match_list_feat(const char * name)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. */
cscfg_check_feat_for_cfg(struct cscfg_config_desc * config_desc)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 */
cscfg_load_feat(struct cscfg_feature_desc * feat_desc)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 */
cscfg_load_config(struct cscfg_config_desc * config_desc)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 */
cscfg_get_named_feat_desc(const char * 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 *
cscfg_csdev_get_feat_from_desc(struct coresight_device * csdev,struct cscfg_feature_desc * feat_desc)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
cscfg_update_feat_param_val(struct cscfg_feature_desc * feat_desc,int param_idx,u64 value)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 */
cscfg_owner_get(struct cscfg_load_owner_info * owner_info)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 */
cscfg_owner_put(struct cscfg_load_owner_info * owner_info)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
cscfg_remove_owned_csdev_configs(struct coresight_device * csdev,void * load_owner)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
cscfg_remove_owned_csdev_features(struct coresight_device * csdev,void * load_owner)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 */
cscfg_fs_unregister_cfgs_feats(void * load_owner)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 */
cscfg_unload_owned_cfgs_feats(void * load_owner)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 */
cscfg_load_owned_cfgs_feats(struct cscfg_config_desc ** config_descs,struct cscfg_feature_desc ** feat_descs,struct cscfg_load_owner_info * owner_info)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 */
cscfg_set_configs_available(struct cscfg_config_desc ** config_descs)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 */
cscfg_fs_register_cfgs_feats(struct cscfg_config_desc ** config_descs,struct cscfg_feature_desc ** feat_descs)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 */
cscfg_load_config_sets(struct cscfg_config_desc ** config_descs,struct cscfg_feature_desc ** feat_descs,struct cscfg_load_owner_info * owner_info)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 */
cscfg_unload_config_sets(struct cscfg_load_owner_info * owner_info)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 */
cscfg_add_cfgs_csdev(struct coresight_device * csdev)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 */
cscfg_add_feats_csdev(struct coresight_device * csdev,u32 match_flags,struct cscfg_csdev_feat_ops * ops)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 */
cscfg_list_add_csdev(struct coresight_device * csdev,u32 match_flags,struct cscfg_csdev_feat_ops * ops)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(sizeof(struct cscfg_registered_csdev), GFP_KERNEL);
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 */
cscfg_list_remove_csdev(struct coresight_device * csdev)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 */
cscfg_register_csdev(struct coresight_device * csdev,u32 match_flags,struct cscfg_csdev_feat_ops * ops)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 */
cscfg_unregister_csdev(struct coresight_device * csdev)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 */
cscfg_csdev_reset_feats(struct coresight_device * csdev)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
cscfg_config_desc_get(struct cscfg_config_desc * config_desc)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
cscfg_config_desc_put(struct cscfg_config_desc * config_desc)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 */
_cscfg_activate_config(unsigned long cfg_hash)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
_cscfg_deactivate_config(unsigned long cfg_hash)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 */
cscfg_config_sysfs_activate(struct cscfg_config_desc * config_desc,bool activate)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 mutex_lock(&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 err = -EBUSY;
964 goto exit_unlock;
965 }
966 err = _cscfg_activate_config(cfg_hash);
967 if (!err)
968 cscfg_mgr->sysfs_active_config = cfg_hash;
969 } else {
970 /* disable if matching current value */
971 if (cscfg_mgr->sysfs_active_config == cfg_hash) {
972 _cscfg_deactivate_config(cfg_hash);
973 cscfg_mgr->sysfs_active_config = 0;
974 } else
975 err = -EINVAL;
976 }
977
978 exit_unlock:
979 mutex_unlock(&cscfg_mutex);
980 return err;
981 }
982
983 /* set the sysfs preset value */
cscfg_config_sysfs_set_preset(int preset)984 void cscfg_config_sysfs_set_preset(int preset)
985 {
986 mutex_lock(&cscfg_mutex);
987 cscfg_mgr->sysfs_active_preset = preset;
988 mutex_unlock(&cscfg_mutex);
989 }
990
991 /*
992 * Used by a device to get the config and preset selected as active in configfs,
993 * when using sysfs to control trace.
994 */
cscfg_config_sysfs_get_active_cfg(unsigned long * cfg_hash,int * preset)995 void cscfg_config_sysfs_get_active_cfg(unsigned long *cfg_hash, int *preset)
996 {
997 mutex_lock(&cscfg_mutex);
998 *preset = cscfg_mgr->sysfs_active_preset;
999 *cfg_hash = cscfg_mgr->sysfs_active_config;
1000 mutex_unlock(&cscfg_mutex);
1001 }
1002 EXPORT_SYMBOL_GPL(cscfg_config_sysfs_get_active_cfg);
1003
1004 /**
1005 * cscfg_activate_config - Mark a configuration descriptor as active.
1006 *
1007 * This will be seen when csdev devices are enabled in the system.
1008 * Only activated configurations can be enabled on individual devices.
1009 * Activation protects the configuration from alteration or removal while
1010 * active.
1011 *
1012 * Selection by hash value - generated from the configuration name when it
1013 * was loaded and added to the cs_etm/configurations file system for selection
1014 * by perf.
1015 *
1016 * @cfg_hash: Hash value of the selected configuration name.
1017 */
cscfg_activate_config(unsigned long cfg_hash)1018 int cscfg_activate_config(unsigned long cfg_hash)
1019 {
1020 int err = 0;
1021
1022 mutex_lock(&cscfg_mutex);
1023 err = _cscfg_activate_config(cfg_hash);
1024 mutex_unlock(&cscfg_mutex);
1025
1026 return err;
1027 }
1028 EXPORT_SYMBOL_GPL(cscfg_activate_config);
1029
1030 /**
1031 * cscfg_deactivate_config - Mark a config descriptor as inactive.
1032 *
1033 * Decrement the configuration and global active counts.
1034 *
1035 * @cfg_hash: Hash value of the selected configuration name.
1036 */
cscfg_deactivate_config(unsigned long cfg_hash)1037 void cscfg_deactivate_config(unsigned long cfg_hash)
1038 {
1039 mutex_lock(&cscfg_mutex);
1040 _cscfg_deactivate_config(cfg_hash);
1041 mutex_unlock(&cscfg_mutex);
1042 }
1043 EXPORT_SYMBOL_GPL(cscfg_deactivate_config);
1044
1045 /**
1046 * cscfg_csdev_enable_active_config - Enable matching active configuration for device.
1047 *
1048 * Enables the configuration selected by @cfg_hash if the configuration is supported
1049 * on the device and has been activated.
1050 *
1051 * If active and supported the CoreSight device @csdev will be programmed with the
1052 * configuration, using @preset parameters.
1053 *
1054 * Should be called before driver hardware enable for the requested device, prior to
1055 * programming and enabling the physical hardware.
1056 *
1057 * @csdev: CoreSight device to program.
1058 * @cfg_hash: Selector for the configuration.
1059 * @preset: Preset parameter values to use, 0 for current / default values.
1060 */
cscfg_csdev_enable_active_config(struct coresight_device * csdev,unsigned long cfg_hash,int preset)1061 int cscfg_csdev_enable_active_config(struct coresight_device *csdev,
1062 unsigned long cfg_hash, int preset)
1063 {
1064 struct cscfg_config_csdev *config_csdev_active = NULL, *config_csdev_item;
1065 struct cscfg_config_desc *config_desc;
1066 unsigned long flags;
1067 int err = 0;
1068
1069 /* quickly check global count */
1070 if (!atomic_read(&cscfg_mgr->sys_active_cnt))
1071 return 0;
1072
1073 /*
1074 * Look for matching configuration - set the active configuration
1075 * context if found.
1076 */
1077 raw_spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
1078 list_for_each_entry(config_csdev_item, &csdev->config_csdev_list, node) {
1079 config_desc = config_csdev_item->config_desc;
1080 if (((unsigned long)config_desc->event_ea->var == cfg_hash) &&
1081 cscfg_config_desc_get(config_desc)) {
1082 config_csdev_active = config_csdev_item;
1083 csdev->active_cscfg_ctxt = (void *)config_csdev_active;
1084 break;
1085 }
1086 }
1087 raw_spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
1088
1089 /*
1090 * If found, attempt to enable
1091 */
1092 if (config_csdev_active) {
1093 /*
1094 * Call the generic routine that will program up the internal
1095 * driver structures prior to programming up the hardware.
1096 * This routine takes the driver spinlock saved in the configs.
1097 */
1098 err = cscfg_csdev_enable_config(config_csdev_active, preset);
1099 if (!err) {
1100 /*
1101 * Successful programming. Check the active_cscfg_ctxt
1102 * pointer to ensure no pre-emption disabled it via
1103 * cscfg_csdev_disable_active_config() before
1104 * we could start.
1105 *
1106 * Set enabled if OK, err if not.
1107 */
1108 raw_spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
1109 if (csdev->active_cscfg_ctxt)
1110 config_csdev_active->enabled = true;
1111 else
1112 err = -EBUSY;
1113 raw_spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
1114 }
1115
1116 if (err)
1117 cscfg_config_desc_put(config_desc);
1118 }
1119
1120 return err;
1121 }
1122 EXPORT_SYMBOL_GPL(cscfg_csdev_enable_active_config);
1123
1124 /**
1125 * cscfg_csdev_disable_active_config - disable an active config on the device.
1126 *
1127 * Disables the active configuration on the CoreSight device @csdev.
1128 * Disable will save the values of any registers marked in the configurations
1129 * as save on disable.
1130 *
1131 * Should be called after driver hardware disable for the requested device,
1132 * after disabling the physical hardware and reading back registers.
1133 *
1134 * @csdev: The CoreSight device.
1135 */
cscfg_csdev_disable_active_config(struct coresight_device * csdev)1136 void cscfg_csdev_disable_active_config(struct coresight_device *csdev)
1137 {
1138 struct cscfg_config_csdev *config_csdev;
1139 unsigned long flags;
1140
1141 /*
1142 * Check if we have an active config, and that it was successfully enabled.
1143 * If it was not enabled, we have no work to do, otherwise mark as disabled.
1144 * Clear the active config pointer.
1145 */
1146 raw_spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
1147 config_csdev = (struct cscfg_config_csdev *)csdev->active_cscfg_ctxt;
1148 if (config_csdev) {
1149 if (!config_csdev->enabled)
1150 config_csdev = NULL;
1151 else
1152 config_csdev->enabled = false;
1153 }
1154 csdev->active_cscfg_ctxt = NULL;
1155 raw_spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
1156
1157 /* true if there was an enabled active config */
1158 if (config_csdev) {
1159 cscfg_csdev_disable_config(config_csdev);
1160 cscfg_config_desc_put(config_csdev->config_desc);
1161 }
1162 }
1163 EXPORT_SYMBOL_GPL(cscfg_csdev_disable_active_config);
1164
1165 /* Initialise system configuration management device. */
1166
cscfg_device(void)1167 struct device *cscfg_device(void)
1168 {
1169 return cscfg_mgr ? &cscfg_mgr->dev : NULL;
1170 }
1171
1172 /* Must have a release function or the kernel will complain on module unload */
cscfg_dev_release(struct device * dev)1173 static void cscfg_dev_release(struct device *dev)
1174 {
1175 mutex_lock(&cscfg_mutex);
1176 kfree(cscfg_mgr);
1177 cscfg_mgr = NULL;
1178 mutex_unlock(&cscfg_mutex);
1179 }
1180
1181 /* a device is needed to "own" some kernel elements such as sysfs entries. */
cscfg_create_device(void)1182 static int cscfg_create_device(void)
1183 {
1184 struct device *dev;
1185 int err = -ENOMEM;
1186
1187 mutex_lock(&cscfg_mutex);
1188 if (cscfg_mgr) {
1189 err = -EINVAL;
1190 goto create_dev_exit_unlock;
1191 }
1192
1193 cscfg_mgr = kzalloc(sizeof(struct cscfg_manager), GFP_KERNEL);
1194 if (!cscfg_mgr)
1195 goto create_dev_exit_unlock;
1196
1197 /* initialise the cscfg_mgr structure */
1198 INIT_LIST_HEAD(&cscfg_mgr->csdev_desc_list);
1199 INIT_LIST_HEAD(&cscfg_mgr->feat_desc_list);
1200 INIT_LIST_HEAD(&cscfg_mgr->config_desc_list);
1201 INIT_LIST_HEAD(&cscfg_mgr->load_order_list);
1202 atomic_set(&cscfg_mgr->sys_active_cnt, 0);
1203 cscfg_mgr->load_state = CSCFG_NONE;
1204
1205 /* setup the device */
1206 dev = cscfg_device();
1207 dev->release = cscfg_dev_release;
1208 dev->init_name = "cs_system_cfg";
1209
1210 err = device_register(dev);
1211 if (err)
1212 put_device(dev);
1213
1214 create_dev_exit_unlock:
1215 mutex_unlock(&cscfg_mutex);
1216 return err;
1217 }
1218
1219 /*
1220 * Loading and unloading is generally on user discretion.
1221 * If exiting due to coresight module unload, we need to unload any configurations that remain,
1222 * before we unregister the configfs intrastructure.
1223 *
1224 * Do this by walking the load_owner list and taking appropriate action, depending on the load
1225 * owner type.
1226 */
cscfg_unload_cfgs_on_exit(void)1227 static void cscfg_unload_cfgs_on_exit(void)
1228 {
1229 struct cscfg_load_owner_info *owner_info = NULL;
1230
1231 /*
1232 * grab the mutex - even though we are exiting, some configfs files
1233 * may still be live till we dump them, so ensure list data is
1234 * protected from a race condition.
1235 */
1236 mutex_lock(&cscfg_mutex);
1237 while (!list_empty(&cscfg_mgr->load_order_list)) {
1238
1239 /* remove in reverse order of loading */
1240 owner_info = list_last_entry(&cscfg_mgr->load_order_list,
1241 struct cscfg_load_owner_info, item);
1242
1243 /* action according to type */
1244 switch (owner_info->type) {
1245 case CSCFG_OWNER_PRELOAD:
1246 /*
1247 * preloaded descriptors are statically allocated in
1248 * this module - just need to unload dynamic items from
1249 * csdev lists, and remove from configfs directories.
1250 */
1251 pr_info("cscfg: unloading preloaded configurations\n");
1252 break;
1253
1254 case CSCFG_OWNER_MODULE:
1255 /*
1256 * this is an error - the loadable module must have been unloaded prior
1257 * to the coresight module unload. Therefore that module has not
1258 * correctly unloaded configs in its own exit code.
1259 * Nothing to do other than emit an error string as the static descriptor
1260 * references we need to unload will have disappeared with the module.
1261 */
1262 pr_err("cscfg: ERROR: prior module failed to unload configuration\n");
1263 goto list_remove;
1264 }
1265
1266 /* remove from configfs - outside the scope of the list mutex */
1267 mutex_unlock(&cscfg_mutex);
1268 cscfg_fs_unregister_cfgs_feats(owner_info);
1269 mutex_lock(&cscfg_mutex);
1270
1271 /* Next unload from csdev lists. */
1272 cscfg_unload_owned_cfgs_feats(owner_info);
1273
1274 list_remove:
1275 /* remove from load order list */
1276 list_del(&owner_info->item);
1277 }
1278 mutex_unlock(&cscfg_mutex);
1279 }
1280
cscfg_clear_device(void)1281 static void cscfg_clear_device(void)
1282 {
1283 cscfg_unload_cfgs_on_exit();
1284 cscfg_configfs_release(cscfg_mgr);
1285 device_unregister(cscfg_device());
1286 }
1287
1288 /* Initialise system config management API device */
cscfg_init(void)1289 int __init cscfg_init(void)
1290 {
1291 int err = 0;
1292
1293 /* create the device and init cscfg_mgr */
1294 err = cscfg_create_device();
1295 if (err)
1296 return err;
1297
1298 /* initialise configfs subsystem */
1299 err = cscfg_configfs_init(cscfg_mgr);
1300 if (err)
1301 goto exit_err;
1302
1303 /* preload built-in configurations */
1304 err = cscfg_preload(THIS_MODULE);
1305 if (err)
1306 goto exit_err;
1307
1308 dev_info(cscfg_device(), "CoreSight Configuration manager initialised");
1309 return 0;
1310
1311 exit_err:
1312 cscfg_clear_device();
1313 return err;
1314 }
1315
cscfg_exit(void)1316 void cscfg_exit(void)
1317 {
1318 cscfg_clear_device();
1319 }
1320