diff options
Diffstat (limited to 'drivers/base/devres.c')
-rw-r--r-- | drivers/base/devres.c | 66 |
1 files changed, 66 insertions, 0 deletions
diff --git a/drivers/base/devres.c b/drivers/base/devres.c index 8fc654f0807b..71d577025285 100644 --- a/drivers/base/devres.c +++ b/drivers/base/devres.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include <linux/device.h> | 10 | #include <linux/device.h> |
11 | #include <linux/module.h> | 11 | #include <linux/module.h> |
12 | #include <linux/slab.h> | 12 | #include <linux/slab.h> |
13 | #include <linux/percpu.h> | ||
13 | 14 | ||
14 | #include "base.h" | 15 | #include "base.h" |
15 | 16 | ||
@@ -985,3 +986,68 @@ void devm_free_pages(struct device *dev, unsigned long addr) | |||
985 | &devres)); | 986 | &devres)); |
986 | } | 987 | } |
987 | EXPORT_SYMBOL_GPL(devm_free_pages); | 988 | EXPORT_SYMBOL_GPL(devm_free_pages); |
989 | |||
990 | static void devm_percpu_release(struct device *dev, void *pdata) | ||
991 | { | ||
992 | void __percpu *p; | ||
993 | |||
994 | p = *(void __percpu **)pdata; | ||
995 | free_percpu(p); | ||
996 | } | ||
997 | |||
998 | static int devm_percpu_match(struct device *dev, void *data, void *p) | ||
999 | { | ||
1000 | struct devres *devr = container_of(data, struct devres, data); | ||
1001 | |||
1002 | return *(void **)devr->data == p; | ||
1003 | } | ||
1004 | |||
1005 | /** | ||
1006 | * __devm_alloc_percpu - Resource-managed alloc_percpu | ||
1007 | * @dev: Device to allocate per-cpu memory for | ||
1008 | * @size: Size of per-cpu memory to allocate | ||
1009 | * @align: Alignment of per-cpu memory to allocate | ||
1010 | * | ||
1011 | * Managed alloc_percpu. Per-cpu memory allocated with this function is | ||
1012 | * automatically freed on driver detach. | ||
1013 | * | ||
1014 | * RETURNS: | ||
1015 | * Pointer to allocated memory on success, NULL on failure. | ||
1016 | */ | ||
1017 | void __percpu *__devm_alloc_percpu(struct device *dev, size_t size, | ||
1018 | size_t align) | ||
1019 | { | ||
1020 | void *p; | ||
1021 | void __percpu *pcpu; | ||
1022 | |||
1023 | pcpu = __alloc_percpu(size, align); | ||
1024 | if (!pcpu) | ||
1025 | return NULL; | ||
1026 | |||
1027 | p = devres_alloc(devm_percpu_release, sizeof(void *), GFP_KERNEL); | ||
1028 | if (!p) { | ||
1029 | free_percpu(pcpu); | ||
1030 | return NULL; | ||
1031 | } | ||
1032 | |||
1033 | *(void __percpu **)p = pcpu; | ||
1034 | |||
1035 | devres_add(dev, p); | ||
1036 | |||
1037 | return pcpu; | ||
1038 | } | ||
1039 | EXPORT_SYMBOL_GPL(__devm_alloc_percpu); | ||
1040 | |||
1041 | /** | ||
1042 | * devm_free_percpu - Resource-managed free_percpu | ||
1043 | * @dev: Device this memory belongs to | ||
1044 | * @pdata: Per-cpu memory to free | ||
1045 | * | ||
1046 | * Free memory allocated with devm_alloc_percpu(). | ||
1047 | */ | ||
1048 | void devm_free_percpu(struct device *dev, void __percpu *pdata) | ||
1049 | { | ||
1050 | WARN_ON(devres_destroy(dev, devm_percpu_release, devm_percpu_match, | ||
1051 | (void *)pdata)); | ||
1052 | } | ||
1053 | EXPORT_SYMBOL_GPL(devm_free_percpu); | ||