Commit eb2ec496 authored by Mike Leach's avatar Mike Leach Committed by Mathieu Poirier

coresight: syscfg: Update load API for config loadable modules

CoreSight configurations and features can be added as kernel loadable
modules. This patch updates the load owner API to ensure that the module
cannot be unloaded either:
1) if the config it supplies is in use
2) if the module is not the last in the load order list.
Signed-off-by: default avatarMike Leach <mike.leach@linaro.org>
Link: https://lore.kernel.org/r/20211124200038.28662-4-mike.leach@linaro.orgSigned-off-by: default avatarMathieu Poirier <mathieu.poirier@linaro.org>
parent 02bd588e
...@@ -368,6 +368,26 @@ int cscfg_update_feat_param_val(struct cscfg_feature_desc *feat_desc, ...@@ -368,6 +368,26 @@ int cscfg_update_feat_param_val(struct cscfg_feature_desc *feat_desc,
return err; return err;
} }
/*
* Conditionally up reference count on owner to prevent unload.
*
* module loaded configs need to be locked in to prevent premature unload.
*/
static int cscfg_owner_get(struct cscfg_load_owner_info *owner_info)
{
if ((owner_info->type == CSCFG_OWNER_MODULE) &&
(!try_module_get(owner_info->owner_handle)))
return -EINVAL;
return 0;
}
/* conditionally lower ref count on an owner */
static void cscfg_owner_put(struct cscfg_load_owner_info *owner_info)
{
if (owner_info->type == CSCFG_OWNER_MODULE)
module_put(owner_info->owner_handle);
}
static void cscfg_remove_owned_csdev_configs(struct coresight_device *csdev, void *load_owner) static void cscfg_remove_owned_csdev_configs(struct coresight_device *csdev, void *load_owner)
{ {
struct cscfg_config_csdev *config_csdev, *tmp; struct cscfg_config_csdev *config_csdev, *tmp;
...@@ -497,6 +517,14 @@ int cscfg_load_config_sets(struct cscfg_config_desc **config_descs, ...@@ -497,6 +517,14 @@ int cscfg_load_config_sets(struct cscfg_config_desc **config_descs,
/* add the load owner to the load order list */ /* add the load owner to the load order list */
list_add_tail(&owner_info->item, &cscfg_mgr->load_order_list); list_add_tail(&owner_info->item, &cscfg_mgr->load_order_list);
if (!list_is_singular(&cscfg_mgr->load_order_list)) {
/* lock previous item in load order list */
err = cscfg_owner_get(list_prev_entry(owner_info, item));
if (err) {
cscfg_unload_owned_cfgs_feats(owner_info);
list_del(&owner_info->item);
}
}
exit_unlock: exit_unlock:
mutex_unlock(&cscfg_mutex); mutex_unlock(&cscfg_mutex);
...@@ -547,7 +575,11 @@ int cscfg_unload_config_sets(struct cscfg_load_owner_info *owner_info) ...@@ -547,7 +575,11 @@ int cscfg_unload_config_sets(struct cscfg_load_owner_info *owner_info)
cscfg_unload_owned_cfgs_feats(owner_info); cscfg_unload_owned_cfgs_feats(owner_info);
/* remove from load order list */ /* remove from load order list */
list_del(&load_list_item->item); if (!list_is_singular(&cscfg_mgr->load_order_list)) {
/* unlock previous item in load order list */
cscfg_owner_put(list_prev_entry(owner_info, item));
}
list_del(&owner_info->item);
exit_unlock: exit_unlock:
mutex_unlock(&cscfg_mutex); mutex_unlock(&cscfg_mutex);
...@@ -739,6 +771,10 @@ int cscfg_activate_config(unsigned long cfg_hash) ...@@ -739,6 +771,10 @@ int cscfg_activate_config(unsigned long cfg_hash)
list_for_each_entry(config_desc, &cscfg_mgr->config_desc_list, item) { list_for_each_entry(config_desc, &cscfg_mgr->config_desc_list, item) {
if ((unsigned long)config_desc->event_ea->var == cfg_hash) { if ((unsigned long)config_desc->event_ea->var == cfg_hash) {
/* must ensure that config cannot be unloaded in use */
err = cscfg_owner_get(config_desc->load_owner);
if (err)
break;
/* /*
* increment the global active count - control changes to * increment the global active count - control changes to
* active configurations * active configurations
...@@ -779,6 +815,7 @@ void cscfg_deactivate_config(unsigned long cfg_hash) ...@@ -779,6 +815,7 @@ void cscfg_deactivate_config(unsigned long cfg_hash)
if ((unsigned long)config_desc->event_ea->var == cfg_hash) { if ((unsigned long)config_desc->event_ea->var == cfg_hash) {
atomic_dec(&config_desc->active_cnt); atomic_dec(&config_desc->active_cnt);
atomic_dec(&cscfg_mgr->sys_active_cnt); atomic_dec(&cscfg_mgr->sys_active_cnt);
cscfg_owner_put(config_desc->load_owner);
dev_dbg(cscfg_device(), "Deactivate config %s.\n", config_desc->name); dev_dbg(cscfg_device(), "Deactivate config %s.\n", config_desc->name);
break; break;
} }
......
...@@ -61,6 +61,7 @@ struct cscfg_registered_csdev { ...@@ -61,6 +61,7 @@ struct cscfg_registered_csdev {
/* owner types for loading and unloading of config and feature sets */ /* owner types for loading and unloading of config and feature sets */
enum cscfg_load_owner_type { enum cscfg_load_owner_type {
CSCFG_OWNER_PRELOAD, CSCFG_OWNER_PRELOAD,
CSCFG_OWNER_MODULE,
}; };
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment