Skip to content

Commit 27bb7fa

Browse files
committed
coresight: configuration: Update API to permit dynamic load/unload
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2055405 commit 02bd588 Author: Mike Leach <mike.leach@linaro.org> Date: Wed Nov 24 20:00:34 2021 +0000 coresight: configuration: Update API to permit dynamic load/unload Expand the configuration API to allow dynamic runtime load and unload of configurations and features. On load, configurations and features are tagged with a "load owner" that is used to determine sets that were loaded together in a given API call. To unload the API uses the load owner to unload all elements previously loaded by that owner. The API also records the order in which different owners loaded their elements into the system. Later loading configurations can use previously loaded features, creating load dependencies. Therefore unload is enforced strictly in the reverse order to load. A load owner will be an additional loadable module, or a configuration loaded via configfs. Signed-off-by: Mike Leach <mike.leach@linaro.org> Link: https://lore.kernel.org/r/20211124200038.28662-3-mike.leach@linaro.org Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org> Signed-off-by: Jeremy Linton <jlinton@redhat.com>
1 parent 2e96492 commit 27bb7fa

File tree

5 files changed

+160
-0
lines changed

5 files changed

+160
-0
lines changed

drivers/hwtracing/coresight/coresight-config.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ struct cscfg_regval_desc {
9898
* @nr_regs: number of registers used.
9999
* @regs_desc: array of registers used.
100100
* @load_owner: handle to load owner for dynamic load and unload of features.
101+
* @fs_group: reference to configfs group for dynamic unload.
101102
*/
102103
struct cscfg_feature_desc {
103104
const char *name;
@@ -109,6 +110,7 @@ struct cscfg_feature_desc {
109110
int nr_regs;
110111
struct cscfg_regval_desc *regs_desc;
111112
void *load_owner;
113+
struct config_group *fs_group;
112114
};
113115

114116
/**
@@ -131,6 +133,7 @@ struct cscfg_feature_desc {
131133
* @event_ea: Extended attribute for perf event value
132134
* @active_cnt: ref count for activate on this configuration.
133135
* @load_owner: handle to load owner for dynamic load and unload of configs.
136+
* @fs_group: reference to configfs group for dynamic unload.
134137
*/
135138
struct cscfg_config_desc {
136139
const char *name;
@@ -144,6 +147,7 @@ struct cscfg_config_desc {
144147
struct dev_ext_attribute *event_ea;
145148
atomic_t active_cnt;
146149
void *load_owner;
150+
struct config_group *fs_group;
147151
};
148152

149153
/**

drivers/hwtracing/coresight/coresight-syscfg-configfs.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,9 +334,19 @@ int cscfg_configfs_add_config(struct cscfg_config_desc *config_desc)
334334
if (IS_ERR(new_group))
335335
return PTR_ERR(new_group);
336336
err = configfs_register_group(&cscfg_configs_grp, new_group);
337+
if (!err)
338+
config_desc->fs_group = new_group;
337339
return err;
338340
}
339341

342+
void cscfg_configfs_del_config(struct cscfg_config_desc *config_desc)
343+
{
344+
if (config_desc->fs_group) {
345+
configfs_unregister_group(config_desc->fs_group);
346+
config_desc->fs_group = NULL;
347+
}
348+
}
349+
340350
static struct config_item_type cscfg_features_type = {
341351
.ct_owner = THIS_MODULE,
342352
};
@@ -358,9 +368,19 @@ int cscfg_configfs_add_feature(struct cscfg_feature_desc *feat_desc)
358368
if (IS_ERR(new_group))
359369
return PTR_ERR(new_group);
360370
err = configfs_register_group(&cscfg_features_grp, new_group);
371+
if (!err)
372+
feat_desc->fs_group = new_group;
361373
return err;
362374
}
363375

376+
void cscfg_configfs_del_feature(struct cscfg_feature_desc *feat_desc)
377+
{
378+
if (feat_desc->fs_group) {
379+
configfs_unregister_group(feat_desc->fs_group);
380+
feat_desc->fs_group = NULL;
381+
}
382+
}
383+
364384
int cscfg_configfs_init(struct cscfg_manager *cscfg_mgr)
365385
{
366386
struct configfs_subsystem *subsys;

drivers/hwtracing/coresight/coresight-syscfg-configfs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,5 +41,7 @@ int cscfg_configfs_init(struct cscfg_manager *cscfg_mgr);
4141
void cscfg_configfs_release(struct cscfg_manager *cscfg_mgr);
4242
int cscfg_configfs_add_config(struct cscfg_config_desc *config_desc);
4343
int cscfg_configfs_add_feature(struct cscfg_feature_desc *feat_desc);
44+
void cscfg_configfs_del_config(struct cscfg_config_desc *config_desc);
45+
void cscfg_configfs_del_feature(struct cscfg_feature_desc *feat_desc);
4446

4547
#endif /* CORESIGHT_SYSCFG_CONFIGFS_H */

drivers/hwtracing/coresight/coresight-syscfg.c

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,13 @@ static int cscfg_check_feat_for_cfg(struct cscfg_config_desc *config_desc)
250250
static int cscfg_load_feat(struct cscfg_feature_desc *feat_desc)
251251
{
252252
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+
}
253260

254261
/* add feature to any matching registered devices */
255262
err = cscfg_add_feat_to_csdevs(feat_desc);
@@ -267,6 +274,13 @@ static int cscfg_load_feat(struct cscfg_feature_desc *feat_desc)
267274
static int cscfg_load_config(struct cscfg_config_desc *config_desc)
268275
{
269276
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+
}
270284

271285
/* validate features are present */
272286
err = cscfg_check_feat_for_cfg(config_desc);
@@ -354,6 +368,72 @@ int cscfg_update_feat_param_val(struct cscfg_feature_desc *feat_desc,
354368
return err;
355369
}
356370

371+
static void cscfg_remove_owned_csdev_configs(struct coresight_device *csdev, void *load_owner)
372+
{
373+
struct cscfg_config_csdev *config_csdev, *tmp;
374+
375+
if (list_empty(&csdev->config_csdev_list))
376+
return;
377+
378+
list_for_each_entry_safe(config_csdev, tmp, &csdev->config_csdev_list, node) {
379+
if (config_csdev->config_desc->load_owner == load_owner)
380+
list_del(&config_csdev->node);
381+
}
382+
}
383+
384+
static void cscfg_remove_owned_csdev_features(struct coresight_device *csdev, void *load_owner)
385+
{
386+
struct cscfg_feature_csdev *feat_csdev, *tmp;
387+
388+
if (list_empty(&csdev->feature_csdev_list))
389+
return;
390+
391+
list_for_each_entry_safe(feat_csdev, tmp, &csdev->feature_csdev_list, node) {
392+
if (feat_csdev->feat_desc->load_owner == load_owner)
393+
list_del(&feat_csdev->node);
394+
}
395+
}
396+
397+
/*
398+
* removal is relatively easy - just remove from all lists, anything that
399+
* matches the owner. Memory for the descriptors will be managed by the owner,
400+
* memory for the csdev items is devm_ allocated with the individual csdev
401+
* devices.
402+
*/
403+
static void cscfg_unload_owned_cfgs_feats(void *load_owner)
404+
{
405+
struct cscfg_config_desc *config_desc, *cfg_tmp;
406+
struct cscfg_feature_desc *feat_desc, *feat_tmp;
407+
struct cscfg_registered_csdev *csdev_item;
408+
409+
/* remove from each csdev instance feature and config lists */
410+
list_for_each_entry(csdev_item, &cscfg_mgr->csdev_desc_list, item) {
411+
/*
412+
* for each csdev, check the loaded lists and remove if
413+
* referenced descriptor is owned
414+
*/
415+
cscfg_remove_owned_csdev_configs(csdev_item->csdev, load_owner);
416+
cscfg_remove_owned_csdev_features(csdev_item->csdev, load_owner);
417+
}
418+
419+
/* remove from the config descriptor lists */
420+
list_for_each_entry_safe(config_desc, cfg_tmp, &cscfg_mgr->config_desc_list, item) {
421+
if (config_desc->load_owner == load_owner) {
422+
cscfg_configfs_del_config(config_desc);
423+
etm_perf_del_symlink_cscfg(config_desc);
424+
list_del(&config_desc->item);
425+
}
426+
}
427+
428+
/* remove from the feature descriptor lists */
429+
list_for_each_entry_safe(feat_desc, feat_tmp, &cscfg_mgr->feat_desc_list, item) {
430+
if (feat_desc->load_owner == load_owner) {
431+
cscfg_configfs_del_feature(feat_desc);
432+
list_del(&feat_desc->item);
433+
}
434+
}
435+
}
436+
357437
/**
358438
* cscfg_load_config_sets - API function to load feature and config sets.
359439
*
@@ -389,6 +469,7 @@ int cscfg_load_config_sets(struct cscfg_config_desc **config_descs,
389469
if (err) {
390470
pr_err("coresight-syscfg: Failed to load feature %s\n",
391471
feat_descs[i]->name);
472+
cscfg_unload_owned_cfgs_feats(owner_info);
392473
goto exit_unlock;
393474
}
394475
feat_descs[i]->load_owner = owner_info;
@@ -406,6 +487,7 @@ int cscfg_load_config_sets(struct cscfg_config_desc **config_descs,
406487
if (err) {
407488
pr_err("coresight-syscfg: Failed to load configuration %s\n",
408489
config_descs[i]->name);
490+
cscfg_unload_owned_cfgs_feats(owner_info);
409491
goto exit_unlock;
410492
}
411493
config_descs[i]->load_owner = owner_info;
@@ -422,6 +504,57 @@ int cscfg_load_config_sets(struct cscfg_config_desc **config_descs,
422504
}
423505
EXPORT_SYMBOL_GPL(cscfg_load_config_sets);
424506

507+
/**
508+
* cscfg_unload_config_sets - unload a set of configurations by owner.
509+
*
510+
* Dynamic unload of configuration and feature sets is done on the basis of
511+
* the load owner of that set. Later loaded configurations can depend on
512+
* features loaded earlier.
513+
*
514+
* Therefore, unload is only possible if:-
515+
* 1) no configurations are active.
516+
* 2) the set being unloaded was the last to be loaded to maintain dependencies.
517+
*
518+
* @owner_info: Information on owner for set being unloaded.
519+
*/
520+
int cscfg_unload_config_sets(struct cscfg_load_owner_info *owner_info)
521+
{
522+
int err = 0;
523+
struct cscfg_load_owner_info *load_list_item = NULL;
524+
525+
mutex_lock(&cscfg_mutex);
526+
527+
/* cannot unload if anything is active */
528+
if (atomic_read(&cscfg_mgr->sys_active_cnt)) {
529+
err = -EBUSY;
530+
goto exit_unlock;
531+
}
532+
533+
/* cannot unload if not last loaded in load order */
534+
if (!list_empty(&cscfg_mgr->load_order_list)) {
535+
load_list_item = list_last_entry(&cscfg_mgr->load_order_list,
536+
struct cscfg_load_owner_info, item);
537+
if (load_list_item != owner_info)
538+
load_list_item = NULL;
539+
}
540+
541+
if (!load_list_item) {
542+
err = -EINVAL;
543+
goto exit_unlock;
544+
}
545+
546+
/* unload all belonging to load_owner */
547+
cscfg_unload_owned_cfgs_feats(owner_info);
548+
549+
/* remove from load order list */
550+
list_del(&load_list_item->item);
551+
552+
exit_unlock:
553+
mutex_unlock(&cscfg_mutex);
554+
return err;
555+
}
556+
EXPORT_SYMBOL_GPL(cscfg_unload_config_sets);
557+
425558
/* Handle coresight device registration and add configs and features to devices */
426559

427560
/* iterate through config lists and load matching configs to device */

drivers/hwtracing/coresight/coresight-syscfg.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ int cscfg_update_feat_param_val(struct cscfg_feature_desc *feat_desc,
9393
int cscfg_load_config_sets(struct cscfg_config_desc **cfg_descs,
9494
struct cscfg_feature_desc **feat_descs,
9595
struct cscfg_load_owner_info *owner_info);
96+
int cscfg_unload_config_sets(struct cscfg_load_owner_info *owner_info);
9697
int cscfg_register_csdev(struct coresight_device *csdev, u32 match_flags,
9798
struct cscfg_csdev_feat_ops *ops);
9899
void cscfg_unregister_csdev(struct coresight_device *csdev);

0 commit comments

Comments
 (0)