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 | return ret; | 617 | return ret; |
| 618 | } | 618 | } |
| 619 | EXPORT_SYMBOL_GPL(dtpm_create_hierarchy); | 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 | struct dtpm_subsys_ops { | 37 | struct dtpm_subsys_ops { |
| 38 | const char *name; | 38 | const char *name; |
| 39 | int (*init)(void); | 39 | int (*init)(void); |
| 40 | void (*exit)(void); | ||
| 40 | int (*setup)(struct dtpm *, struct device_node *); | 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 | int dtpm_register(const char *name, struct dtpm *dtpm, struct dtpm *parent); | 68 | int dtpm_register(const char *name, struct dtpm *dtpm, struct dtpm *parent); |
| 68 | 69 | ||
| 69 | int dtpm_create_hierarchy(struct of_device_id *dtpm_match_table); | 70 | int dtpm_create_hierarchy(struct of_device_id *dtpm_match_table); |
| 71 | |||
| 72 | void dtpm_destroy_hierarchy(void); | ||
| 70 | #endif | 73 | #endif |