The hierarchy creation function exits but without a destroy hierarchy function. Due to that, the modules creating the hierarchy can not be unloaded properly because they don't have an exit callback. Provide the dtpm_destroy_hierarchy() function to remove the previously created hierarchy. The function relies on all the release mechanisms implemented by the underlying powercap framework.
Unified · Split
| @@ -617,3 +617,46 @@ out_unlock: · 616 unmodified lines | ||
| 617 | 617 | return ret; |
| 618 | 618 | } |
| 619 | 619 | EXPORT_SYMBOL_GPL(dtpm_create_hierarchy); |
| 620 | + | |
| 621 | +static void __dtpm_destroy_hierarchy(struct dtpm *dtpm) | |
| 622 | +{ | |
| 623 | + struct dtpm *child, *aux; | |
| 624 | + | |
| 625 | + list_for_each_entry_safe(child, aux, &dtpm->children, sibling) | |
| 626 | + __dtpm_destroy_hierarchy(child); | |
| 627 | + | |
| 628 | + /* | |
| 629 | + * At this point, we know all children were removed from the | |
| 630 | + * recursive call before | |
| 631 | + */ | |
| 632 | + dtpm_unregister(dtpm); | |
| 633 | +} | |
| 634 | + | |
| 635 | +void dtpm_destroy_hierarchy(void) | |
| 636 | +{ | |
| 637 | + int i; | |
| 638 | + | |
| 639 | + mutex_lock(&dtpm_lock); | |
| 640 | + | |
| 641 | + if (!pct) | |
| 642 | + goto out_unlock; | |
| 643 | + | |
| 644 | + __dtpm_destroy_hierarchy(root); | |
| 645 | + | |
| 646 | + | |
| 647 | + for (i = 0; i < ARRAY_SIZE(dtpm_subsys); i++) { | |
| 648 | + | |
| 649 | + if (!dtpm_subsys[i]->exit) | |
| 650 | + continue; | |
| 651 | + | |
| 652 | + dtpm_subsys[i]->exit(); | |
| 653 | + } | |
| 654 | + | |
| 655 | + powercap_unregister_control_type(pct); | |
| 656 | + | |
| 657 | + pct = NULL; | |
| 658 | + | |
| 659 | +out_unlock: | |
| 660 | + mutex_unlock(&dtpm_lock); | |
| 661 | +} | |
| 662 | +EXPORT_SYMBOL_GPL(dtpm_destroy_hierarchy); | |
| @@ -37,6 +37,7 @@ struct device_node; · 36 unmodified lines | ||
| 37 | 37 | struct dtpm_subsys_ops { |
| 38 | 38 | const char *name; |
| 39 | 39 | int (*init)(void); |
| 40 | + void (*exit)(void); | |
| 40 | 41 | int (*setup)(struct dtpm *, struct device_node *); |
| 41 | 42 | }; |
| 42 | 43 | |
| @@ -67,4 +68,6 @@ void dtpm_unregister(struct dtpm *dtpm); · 24 unmodified lines | ||
| 67 | 68 | int dtpm_register(const char *name, struct dtpm *dtpm, struct dtpm *parent); |
| 68 | 69 | |
| 69 | 70 | int dtpm_create_hierarchy(struct of_device_id *dtpm_match_table); |
| 71 | + | |
| 72 | +void dtpm_destroy_hierarchy(void); | |
| 70 | 73 | #endif |