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 | |
| 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>
| -rw-r--r-- | Documentation/driver-model/devres.txt | 2 | ||||
| -rw-r--r-- | drivers/base/devres.c | 76 | ||||
| -rw-r--r-- | include/linux/device.h | 4 |
3 files changed, 82 insertions, 0 deletions
diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt index 499951873997..e1a27074caae 100644 --- a/Documentation/driver-model/devres.txt +++ b/Documentation/driver-model/devres.txt | |||
| @@ -237,6 +237,8 @@ MEM | |||
| 237 | devm_kzalloc() | 237 | devm_kzalloc() |
| 238 | devm_kfree() | 238 | devm_kfree() |
| 239 | devm_kmemdup() | 239 | devm_kmemdup() |
| 240 | devm_get_free_pages() | ||
| 241 | devm_free_pages() | ||
| 240 | 242 | ||
| 241 | IIO | 243 | IIO |
| 242 | devm_iio_device_alloc() | 244 | devm_iio_device_alloc() |
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); | ||
diff --git a/include/linux/device.h b/include/linux/device.h index ab871588da89..3dc69a2faa51 100644 --- a/include/linux/device.h +++ b/include/linux/device.h | |||
| @@ -626,6 +626,10 @@ extern char *devm_kstrdup(struct device *dev, const char *s, gfp_t gfp); | |||
| 626 | extern void *devm_kmemdup(struct device *dev, const void *src, size_t len, | 626 | extern void *devm_kmemdup(struct device *dev, const void *src, size_t len, |
| 627 | gfp_t gfp); | 627 | gfp_t gfp); |
| 628 | 628 | ||
| 629 | extern unsigned long devm_get_free_pages(struct device *dev, | ||
| 630 | gfp_t gfp_mask, unsigned int order); | ||
| 631 | extern void devm_free_pages(struct device *dev, unsigned long addr); | ||
| 632 | |||
| 629 | void __iomem *devm_ioremap_resource(struct device *dev, struct resource *res); | 633 | void __iomem *devm_ioremap_resource(struct device *dev, struct resource *res); |
| 630 | void __iomem *devm_request_and_ioremap(struct device *dev, | 634 | void __iomem *devm_request_and_ioremap(struct device *dev, |
| 631 | struct resource *res); | 635 | struct resource *res); |
