diff options
author | Eli Billauer <eli.billauer@gmail.com> | 2014-05-16 04:26:35 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-05-23 13:19:25 -0400 |
commit | 43339bed7010da6e7cf797db3216a136a974a0cd (patch) | |
tree | 3ee6929132df08a32ff8887297181da78de7715b /drivers/base/devres.c | |
parent | 8ffca9eae662004016a6d60a2a79ce93f81f150e (diff) |
devres: Add devm_get_free_pages API
devm_get_free_pages() and devm_free_pages() are the managed counterparts
for __get_free_pages() and free_pages().
Signed-off-by: Eli Billauer <eli.billauer@gmail.com>
Acked-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/base/devres.c')
-rw-r--r-- | drivers/base/devres.c | 76 |
1 files changed, 76 insertions, 0 deletions
diff --git a/drivers/base/devres.c b/drivers/base/devres.c index d0914cba2413..52302946770f 100644 --- a/drivers/base/devres.c +++ b/drivers/base/devres.c | |||
@@ -852,3 +852,79 @@ void *devm_kmemdup(struct device *dev, const void *src, size_t len, gfp_t gfp) | |||
852 | return p; | 852 | return p; |
853 | } | 853 | } |
854 | EXPORT_SYMBOL_GPL(devm_kmemdup); | 854 | EXPORT_SYMBOL_GPL(devm_kmemdup); |
855 | |||
856 | struct pages_devres { | ||
857 | unsigned long addr; | ||
858 | unsigned int order; | ||
859 | }; | ||
860 | |||
861 | static int devm_pages_match(struct device *dev, void *res, void *p) | ||
862 | { | ||
863 | struct pages_devres *devres = res; | ||
864 | struct pages_devres *target = p; | ||
865 | |||
866 | return devres->addr == target->addr; | ||
867 | } | ||
868 | |||
869 | static void devm_pages_release(struct device *dev, void *res) | ||
870 | { | ||
871 | struct pages_devres *devres = res; | ||
872 | |||
873 | free_pages(devres->addr, devres->order); | ||
874 | } | ||
875 | |||
876 | /** | ||
877 | * devm_get_free_pages - Resource-managed __get_free_pages | ||
878 | * @dev: Device to allocate memory for | ||
879 | * @gfp_mask: Allocation gfp flags | ||
880 | * @order: Allocation size is (1 << order) pages | ||
881 | * | ||
882 | * Managed get_free_pages. Memory allocated with this function is | ||
883 | * automatically freed on driver detach. | ||
884 | * | ||
885 | * RETURNS: | ||
886 | * Address of allocated memory on success, 0 on failure. | ||
887 | */ | ||
888 | |||
889 | unsigned long devm_get_free_pages(struct device *dev, | ||
890 | gfp_t gfp_mask, unsigned int order) | ||
891 | { | ||
892 | struct pages_devres *devres; | ||
893 | unsigned long addr; | ||
894 | |||
895 | addr = __get_free_pages(gfp_mask, order); | ||
896 | |||
897 | if (unlikely(!addr)) | ||
898 | return 0; | ||
899 | |||
900 | devres = devres_alloc(devm_pages_release, | ||
901 | sizeof(struct pages_devres), GFP_KERNEL); | ||
902 | if (unlikely(!devres)) { | ||
903 | free_pages(addr, order); | ||
904 | return 0; | ||
905 | } | ||
906 | |||
907 | devres->addr = addr; | ||
908 | devres->order = order; | ||
909 | |||
910 | devres_add(dev, devres); | ||
911 | return addr; | ||
912 | } | ||
913 | EXPORT_SYMBOL_GPL(devm_get_free_pages); | ||
914 | |||
915 | /** | ||
916 | * devm_free_pages - Resource-managed free_pages | ||
917 | * @dev: Device this memory belongs to | ||
918 | * @addr: Memory to free | ||
919 | * | ||
920 | * Free memory allocated with devm_get_free_pages(). Unlike free_pages, | ||
921 | * there is no need to supply the @order. | ||
922 | */ | ||
923 | void devm_free_pages(struct device *dev, unsigned long addr) | ||
924 | { | ||
925 | struct pages_devres devres = { .addr = addr }; | ||
926 | |||
927 | WARN_ON(devres_release(dev, devm_pages_release, devm_pages_match, | ||
928 | &devres)); | ||
929 | } | ||
930 | EXPORT_SYMBOL_GPL(devm_free_pages); | ||