Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Mike Leach and committed by
Mathieu Poirier
02bd588e da7000e8

+160
+4
drivers/hwtracing/coresight/coresight-config.h
··· 98 98 * @nr_regs: number of registers used. 99 99 * @regs_desc: array of registers used. 100 100 * @load_owner: handle to load owner for dynamic load and unload of features. 101 + * @fs_group: reference to configfs group for dynamic unload. 101 102 */ 102 103 struct cscfg_feature_desc { 103 104 const char *name; ··· 110 109 int nr_regs; 111 110 struct cscfg_regval_desc *regs_desc; 112 111 void *load_owner; 112 + struct config_group *fs_group; 113 113 }; 114 114 115 115 /** ··· 133 131 * @event_ea: Extended attribute for perf event value 134 132 * @active_cnt: ref count for activate on this configuration. 135 133 * @load_owner: handle to load owner for dynamic load and unload of configs. 134 + * @fs_group: reference to configfs group for dynamic unload. 136 135 */ 137 136 struct cscfg_config_desc { 138 137 const char *name; ··· 147 144 struct dev_ext_attribute *event_ea; 148 145 atomic_t active_cnt; 149 146 void *load_owner; 147 + struct config_group *fs_group; 150 148 }; 151 149 152 150 /**
+20
drivers/hwtracing/coresight/coresight-syscfg-configfs.c
··· 334 334 if (IS_ERR(new_group)) 335 335 return PTR_ERR(new_group); 336 336 err = configfs_register_group(&cscfg_configs_grp, new_group); 337 + if (!err) 338 + config_desc->fs_group = new_group; 337 339 return err; 340 + } 341 + 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 + } 338 348 } 339 349 340 350 static struct config_item_type cscfg_features_type = { ··· 368 358 if (IS_ERR(new_group)) 369 359 return PTR_ERR(new_group); 370 360 err = configfs_register_group(&cscfg_features_grp, new_group); 361 + if (!err) 362 + feat_desc->fs_group = new_group; 371 363 return err; 364 + } 365 + 366 + void cscfg_configfs_del_feature(struct cscfg_feature_desc *feat_desc) 367 + { 368 + if (feat_desc->fs_group) { 369 + configfs_unregister_group(feat_desc->fs_group); 370 + feat_desc->fs_group = NULL; 371 + } 372 372 } 373 373 374 374 int cscfg_configfs_init(struct cscfg_manager *cscfg_mgr)
+2
drivers/hwtracing/coresight/coresight-syscfg-configfs.h
··· 41 41 void cscfg_configfs_release(struct cscfg_manager *cscfg_mgr); 42 42 int cscfg_configfs_add_config(struct cscfg_config_desc *config_desc); 43 43 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); 44 46 45 47 #endif /* CORESIGHT_SYSCFG_CONFIGFS_H */
+133
drivers/hwtracing/coresight/coresight-syscfg.c
··· 250 250 static int cscfg_load_feat(struct cscfg_feature_desc *feat_desc) 251 251 { 252 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 + } 253 260 254 261 /* add feature to any matching registered devices */ 255 262 err = cscfg_add_feat_to_csdevs(feat_desc); ··· 274 267 static int cscfg_load_config(struct cscfg_config_desc *config_desc) 275 268 { 276 269 int err; 270 + struct cscfg_config_desc *config_desc_exist; 271 + 272 + /* new configuration must have a unique name */ 273 + list_for_each_entry(config_desc_exist, &cscfg_mgr->config_desc_list, item) { 274 + if (!strcmp(config_desc_exist->name, config_desc->name)) 275 + return -EEXIST; 276 + } 277 277 278 278 /* validate features are present */ 279 279 err = cscfg_check_feat_for_cfg(config_desc); ··· 368 354 return err; 369 355 } 370 356 357 + static void cscfg_remove_owned_csdev_configs(struct coresight_device *csdev, void *load_owner) 358 + { 359 + struct cscfg_config_csdev *config_csdev, *tmp; 360 + 361 + if (list_empty(&csdev->config_csdev_list)) 362 + return; 363 + 364 + list_for_each_entry_safe(config_csdev, tmp, &csdev->config_csdev_list, node) { 365 + if (config_csdev->config_desc->load_owner == load_owner) 366 + list_del(&config_csdev->node); 367 + } 368 + } 369 + 370 + static void cscfg_remove_owned_csdev_features(struct coresight_device *csdev, void *load_owner) 371 + { 372 + struct cscfg_feature_csdev *feat_csdev, *tmp; 373 + 374 + if (list_empty(&csdev->feature_csdev_list)) 375 + return; 376 + 377 + list_for_each_entry_safe(feat_csdev, tmp, &csdev->feature_csdev_list, node) { 378 + if (feat_csdev->feat_desc->load_owner == load_owner) 379 + list_del(&feat_csdev->node); 380 + } 381 + } 382 + 383 + /* 384 + * removal is relatively easy - just remove from all lists, anything that 385 + * matches the owner. Memory for the descriptors will be managed by the owner, 386 + * memory for the csdev items is devm_ allocated with the individual csdev 387 + * devices. 388 + */ 389 + static void cscfg_unload_owned_cfgs_feats(void *load_owner) 390 + { 391 + struct cscfg_config_desc *config_desc, *cfg_tmp; 392 + struct cscfg_feature_desc *feat_desc, *feat_tmp; 393 + struct cscfg_registered_csdev *csdev_item; 394 + 395 + /* remove from each csdev instance feature and config lists */ 396 + list_for_each_entry(csdev_item, &cscfg_mgr->csdev_desc_list, item) { 397 + /* 398 + * for each csdev, check the loaded lists and remove if 399 + * referenced descriptor is owned 400 + */ 401 + cscfg_remove_owned_csdev_configs(csdev_item->csdev, load_owner); 402 + cscfg_remove_owned_csdev_features(csdev_item->csdev, load_owner); 403 + } 404 + 405 + /* remove from the config descriptor lists */ 406 + list_for_each_entry_safe(config_desc, cfg_tmp, &cscfg_mgr->config_desc_list, item) { 407 + if (config_desc->load_owner == load_owner) { 408 + cscfg_configfs_del_config(config_desc); 409 + etm_perf_del_symlink_cscfg(config_desc); 410 + list_del(&config_desc->item); 411 + } 412 + } 413 + 414 + /* remove from the feature descriptor lists */ 415 + list_for_each_entry_safe(feat_desc, feat_tmp, &cscfg_mgr->feat_desc_list, item) { 416 + if (feat_desc->load_owner == load_owner) { 417 + cscfg_configfs_del_feature(feat_desc); 418 + list_del(&feat_desc->item); 419 + } 420 + } 421 + } 422 + 371 423 /** 372 424 * cscfg_load_config_sets - API function to load feature and config sets. 373 425 * ··· 469 389 if (err) { 470 390 pr_err("coresight-syscfg: Failed to load feature %s\n", 471 391 feat_descs[i]->name); 392 + cscfg_unload_owned_cfgs_feats(owner_info); 472 393 goto exit_unlock; 473 394 } 474 395 feat_descs[i]->load_owner = owner_info; ··· 487 406 if (err) { 488 407 pr_err("coresight-syscfg: Failed to load configuration %s\n", 489 408 config_descs[i]->name); 409 + cscfg_unload_owned_cfgs_feats(owner_info); 490 410 goto exit_unlock; 491 411 } 492 412 config_descs[i]->load_owner = owner_info; ··· 503 421 return err; 504 422 } 505 423 EXPORT_SYMBOL_GPL(cscfg_load_config_sets); 424 + 425 + /** 426 + * cscfg_unload_config_sets - unload a set of configurations by owner. 427 + * 428 + * Dynamic unload of configuration and feature sets is done on the basis of 429 + * the load owner of that set. Later loaded configurations can depend on 430 + * features loaded earlier. 431 + * 432 + * Therefore, unload is only possible if:- 433 + * 1) no configurations are active. 434 + * 2) the set being unloaded was the last to be loaded to maintain dependencies. 435 + * 436 + * @owner_info: Information on owner for set being unloaded. 437 + */ 438 + int cscfg_unload_config_sets(struct cscfg_load_owner_info *owner_info) 439 + { 440 + int err = 0; 441 + struct cscfg_load_owner_info *load_list_item = NULL; 442 + 443 + mutex_lock(&cscfg_mutex); 444 + 445 + /* cannot unload if anything is active */ 446 + if (atomic_read(&cscfg_mgr->sys_active_cnt)) { 447 + err = -EBUSY; 448 + goto exit_unlock; 449 + } 450 + 451 + /* cannot unload if not last loaded in load order */ 452 + if (!list_empty(&cscfg_mgr->load_order_list)) { 453 + load_list_item = list_last_entry(&cscfg_mgr->load_order_list, 454 + struct cscfg_load_owner_info, item); 455 + if (load_list_item != owner_info) 456 + load_list_item = NULL; 457 + } 458 + 459 + if (!load_list_item) { 460 + err = -EINVAL; 461 + goto exit_unlock; 462 + } 463 + 464 + /* unload all belonging to load_owner */ 465 + cscfg_unload_owned_cfgs_feats(owner_info); 466 + 467 + /* remove from load order list */ 468 + list_del(&load_list_item->item); 469 + 470 + exit_unlock: 471 + mutex_unlock(&cscfg_mutex); 472 + return err; 473 + } 474 + EXPORT_SYMBOL_GPL(cscfg_unload_config_sets); 506 475 507 476 /* Handle coresight device registration and add configs and features to devices */ 508 477
+1
drivers/hwtracing/coresight/coresight-syscfg.h
··· 93 93 int cscfg_load_config_sets(struct cscfg_config_desc **cfg_descs, 94 94 struct cscfg_feature_desc **feat_descs, 95 95 struct cscfg_load_owner_info *owner_info); 96 + int cscfg_unload_config_sets(struct cscfg_load_owner_info *owner_info); 96 97 int cscfg_register_csdev(struct coresight_device *csdev, u32 match_flags, 97 98 struct cscfg_csdev_feat_ops *ops); 98 99 void cscfg_unregister_csdev(struct coresight_device *csdev);