diff options
-rw-r--r-- | drivers/acpi/nfit/core.c | 76 | ||||
-rw-r--r-- | drivers/acpi/nfit/nfit.h | 1 | ||||
-rw-r--r-- | tools/testing/nvdimm/test/nfit.c | 4 |
3 files changed, 51 insertions, 30 deletions
diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index 69c6cc77130c..261eea1d2906 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c | |||
@@ -2604,7 +2604,8 @@ static int acpi_nfit_register_regions(struct acpi_nfit_desc *acpi_desc) | |||
2604 | return rc; | 2604 | return rc; |
2605 | } | 2605 | } |
2606 | 2606 | ||
2607 | queue_work(nfit_wq, &acpi_desc->work); | 2607 | if (!acpi_desc->cancel) |
2608 | queue_work(nfit_wq, &acpi_desc->work); | ||
2608 | return 0; | 2609 | return 0; |
2609 | } | 2610 | } |
2610 | 2611 | ||
@@ -2650,32 +2651,11 @@ static int acpi_nfit_desc_init_scrub_attr(struct acpi_nfit_desc *acpi_desc) | |||
2650 | return 0; | 2651 | return 0; |
2651 | } | 2652 | } |
2652 | 2653 | ||
2653 | static void acpi_nfit_destruct(void *data) | 2654 | static void acpi_nfit_unregister(void *data) |
2654 | { | 2655 | { |
2655 | struct acpi_nfit_desc *acpi_desc = data; | 2656 | struct acpi_nfit_desc *acpi_desc = data; |
2656 | struct device *bus_dev = to_nvdimm_bus_dev(acpi_desc->nvdimm_bus); | ||
2657 | 2657 | ||
2658 | /* | ||
2659 | * Destruct under acpi_desc_lock so that nfit_handle_mce does not | ||
2660 | * race teardown | ||
2661 | */ | ||
2662 | mutex_lock(&acpi_desc_lock); | ||
2663 | acpi_desc->cancel = 1; | ||
2664 | /* | ||
2665 | * Bounce the nvdimm bus lock to make sure any in-flight | ||
2666 | * acpi_nfit_ars_rescan() submissions have had a chance to | ||
2667 | * either submit or see ->cancel set. | ||
2668 | */ | ||
2669 | device_lock(bus_dev); | ||
2670 | device_unlock(bus_dev); | ||
2671 | |||
2672 | flush_workqueue(nfit_wq); | ||
2673 | if (acpi_desc->scrub_count_state) | ||
2674 | sysfs_put(acpi_desc->scrub_count_state); | ||
2675 | nvdimm_bus_unregister(acpi_desc->nvdimm_bus); | 2658 | nvdimm_bus_unregister(acpi_desc->nvdimm_bus); |
2676 | acpi_desc->nvdimm_bus = NULL; | ||
2677 | list_del(&acpi_desc->list); | ||
2678 | mutex_unlock(&acpi_desc_lock); | ||
2679 | } | 2659 | } |
2680 | 2660 | ||
2681 | int acpi_nfit_init(struct acpi_nfit_desc *acpi_desc, void *data, acpi_size sz) | 2661 | int acpi_nfit_init(struct acpi_nfit_desc *acpi_desc, void *data, acpi_size sz) |
@@ -2693,7 +2673,7 @@ int acpi_nfit_init(struct acpi_nfit_desc *acpi_desc, void *data, acpi_size sz) | |||
2693 | if (!acpi_desc->nvdimm_bus) | 2673 | if (!acpi_desc->nvdimm_bus) |
2694 | return -ENOMEM; | 2674 | return -ENOMEM; |
2695 | 2675 | ||
2696 | rc = devm_add_action_or_reset(dev, acpi_nfit_destruct, | 2676 | rc = devm_add_action_or_reset(dev, acpi_nfit_unregister, |
2697 | acpi_desc); | 2677 | acpi_desc); |
2698 | if (rc) | 2678 | if (rc) |
2699 | return rc; | 2679 | return rc; |
@@ -2787,9 +2767,10 @@ static int acpi_nfit_flush_probe(struct nvdimm_bus_descriptor *nd_desc) | |||
2787 | 2767 | ||
2788 | /* bounce the init_mutex to make init_complete valid */ | 2768 | /* bounce the init_mutex to make init_complete valid */ |
2789 | mutex_lock(&acpi_desc->init_mutex); | 2769 | mutex_lock(&acpi_desc->init_mutex); |
2790 | mutex_unlock(&acpi_desc->init_mutex); | 2770 | if (acpi_desc->cancel || acpi_desc->init_complete) { |
2791 | if (acpi_desc->init_complete) | 2771 | mutex_unlock(&acpi_desc->init_mutex); |
2792 | return 0; | 2772 | return 0; |
2773 | } | ||
2793 | 2774 | ||
2794 | /* | 2775 | /* |
2795 | * Scrub work could take 10s of seconds, userspace may give up so we | 2776 | * Scrub work could take 10s of seconds, userspace may give up so we |
@@ -2798,6 +2779,7 @@ static int acpi_nfit_flush_probe(struct nvdimm_bus_descriptor *nd_desc) | |||
2798 | INIT_WORK_ONSTACK(&flush.work, flush_probe); | 2779 | INIT_WORK_ONSTACK(&flush.work, flush_probe); |
2799 | COMPLETION_INITIALIZER_ONSTACK(flush.cmp); | 2780 | COMPLETION_INITIALIZER_ONSTACK(flush.cmp); |
2800 | queue_work(nfit_wq, &flush.work); | 2781 | queue_work(nfit_wq, &flush.work); |
2782 | mutex_unlock(&acpi_desc->init_mutex); | ||
2801 | 2783 | ||
2802 | rc = wait_for_completion_interruptible(&flush.cmp); | 2784 | rc = wait_for_completion_interruptible(&flush.cmp); |
2803 | cancel_work_sync(&flush.work); | 2785 | cancel_work_sync(&flush.work); |
@@ -2834,10 +2816,12 @@ int acpi_nfit_ars_rescan(struct acpi_nfit_desc *acpi_desc) | |||
2834 | if (work_busy(&acpi_desc->work)) | 2816 | if (work_busy(&acpi_desc->work)) |
2835 | return -EBUSY; | 2817 | return -EBUSY; |
2836 | 2818 | ||
2837 | if (acpi_desc->cancel) | 2819 | mutex_lock(&acpi_desc->init_mutex); |
2820 | if (acpi_desc->cancel) { | ||
2821 | mutex_unlock(&acpi_desc->init_mutex); | ||
2838 | return 0; | 2822 | return 0; |
2823 | } | ||
2839 | 2824 | ||
2840 | mutex_lock(&acpi_desc->init_mutex); | ||
2841 | list_for_each_entry(nfit_spa, &acpi_desc->spas, list) { | 2825 | list_for_each_entry(nfit_spa, &acpi_desc->spas, list) { |
2842 | struct acpi_nfit_system_address *spa = nfit_spa->spa; | 2826 | struct acpi_nfit_system_address *spa = nfit_spa->spa; |
2843 | 2827 | ||
@@ -2886,6 +2870,35 @@ static void acpi_nfit_put_table(void *table) | |||
2886 | acpi_put_table(table); | 2870 | acpi_put_table(table); |
2887 | } | 2871 | } |
2888 | 2872 | ||
2873 | void acpi_nfit_shutdown(void *data) | ||
2874 | { | ||
2875 | struct acpi_nfit_desc *acpi_desc = data; | ||
2876 | struct device *bus_dev = to_nvdimm_bus_dev(acpi_desc->nvdimm_bus); | ||
2877 | |||
2878 | /* | ||
2879 | * Destruct under acpi_desc_lock so that nfit_handle_mce does not | ||
2880 | * race teardown | ||
2881 | */ | ||
2882 | mutex_lock(&acpi_desc_lock); | ||
2883 | list_del(&acpi_desc->list); | ||
2884 | mutex_unlock(&acpi_desc_lock); | ||
2885 | |||
2886 | mutex_lock(&acpi_desc->init_mutex); | ||
2887 | acpi_desc->cancel = 1; | ||
2888 | mutex_unlock(&acpi_desc->init_mutex); | ||
2889 | |||
2890 | /* | ||
2891 | * Bounce the nvdimm bus lock to make sure any in-flight | ||
2892 | * acpi_nfit_ars_rescan() submissions have had a chance to | ||
2893 | * either submit or see ->cancel set. | ||
2894 | */ | ||
2895 | device_lock(bus_dev); | ||
2896 | device_unlock(bus_dev); | ||
2897 | |||
2898 | flush_workqueue(nfit_wq); | ||
2899 | } | ||
2900 | EXPORT_SYMBOL_GPL(acpi_nfit_shutdown); | ||
2901 | |||
2889 | static int acpi_nfit_add(struct acpi_device *adev) | 2902 | static int acpi_nfit_add(struct acpi_device *adev) |
2890 | { | 2903 | { |
2891 | struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL }; | 2904 | struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL }; |
@@ -2933,12 +2946,15 @@ static int acpi_nfit_add(struct acpi_device *adev) | |||
2933 | rc = acpi_nfit_init(acpi_desc, (void *) tbl | 2946 | rc = acpi_nfit_init(acpi_desc, (void *) tbl |
2934 | + sizeof(struct acpi_table_nfit), | 2947 | + sizeof(struct acpi_table_nfit), |
2935 | sz - sizeof(struct acpi_table_nfit)); | 2948 | sz - sizeof(struct acpi_table_nfit)); |
2936 | return rc; | 2949 | |
2950 | if (rc) | ||
2951 | return rc; | ||
2952 | return devm_add_action_or_reset(dev, acpi_nfit_shutdown, acpi_desc); | ||
2937 | } | 2953 | } |
2938 | 2954 | ||
2939 | static int acpi_nfit_remove(struct acpi_device *adev) | 2955 | static int acpi_nfit_remove(struct acpi_device *adev) |
2940 | { | 2956 | { |
2941 | /* see acpi_nfit_destruct */ | 2957 | /* see acpi_nfit_unregister */ |
2942 | return 0; | 2958 | return 0; |
2943 | } | 2959 | } |
2944 | 2960 | ||
diff --git a/drivers/acpi/nfit/nfit.h b/drivers/acpi/nfit/nfit.h index fac098bfa585..58fb7d68e04a 100644 --- a/drivers/acpi/nfit/nfit.h +++ b/drivers/acpi/nfit/nfit.h | |||
@@ -239,6 +239,7 @@ static inline struct acpi_nfit_desc *to_acpi_desc( | |||
239 | 239 | ||
240 | const u8 *to_nfit_uuid(enum nfit_uuids id); | 240 | const u8 *to_nfit_uuid(enum nfit_uuids id); |
241 | int acpi_nfit_init(struct acpi_nfit_desc *acpi_desc, void *nfit, acpi_size sz); | 241 | int acpi_nfit_init(struct acpi_nfit_desc *acpi_desc, void *nfit, acpi_size sz); |
242 | void acpi_nfit_shutdown(void *data); | ||
242 | void __acpi_nfit_notify(struct device *dev, acpi_handle handle, u32 event); | 243 | void __acpi_nfit_notify(struct device *dev, acpi_handle handle, u32 event); |
243 | void __acpi_nvdimm_notify(struct device *dev, u32 event); | 244 | void __acpi_nvdimm_notify(struct device *dev, u32 event); |
244 | int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm, | 245 | int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm, |
diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c index d7fb1b894128..c2187178fb13 100644 --- a/tools/testing/nvdimm/test/nfit.c +++ b/tools/testing/nvdimm/test/nfit.c | |||
@@ -1851,6 +1851,10 @@ static int nfit_test_probe(struct platform_device *pdev) | |||
1851 | if (rc) | 1851 | if (rc) |
1852 | return rc; | 1852 | return rc; |
1853 | 1853 | ||
1854 | rc = devm_add_action_or_reset(&pdev->dev, acpi_nfit_shutdown, acpi_desc); | ||
1855 | if (rc) | ||
1856 | return rc; | ||
1857 | |||
1854 | if (nfit_test->setup != nfit_test0_setup) | 1858 | if (nfit_test->setup != nfit_test0_setup) |
1855 | return 0; | 1859 | return 0; |
1856 | 1860 | ||