diff options
-rw-r--r-- | Documentation/driver-model/devres.txt | 4 | ||||
-rw-r--r-- | drivers/base/devres.c | 66 | ||||
-rw-r--r-- | include/linux/device.h | 19 |
3 files changed, 89 insertions, 0 deletions
diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt index 167070895498..ca9d1eb46bc0 100644 --- a/Documentation/driver-model/devres.txt +++ b/Documentation/driver-model/devres.txt | |||
@@ -332,6 +332,10 @@ MEM | |||
332 | MFD | 332 | MFD |
333 | devm_mfd_add_devices() | 333 | devm_mfd_add_devices() |
334 | 334 | ||
335 | PER-CPU MEM | ||
336 | devm_alloc_percpu() | ||
337 | devm_free_percpu() | ||
338 | |||
335 | PCI | 339 | PCI |
336 | pcim_enable_device() : after success, all PCI ops become managed | 340 | pcim_enable_device() : after success, all PCI ops become managed |
337 | pcim_pin_device() : keep PCI device enabled after release | 341 | pcim_pin_device() : keep PCI device enabled after release |
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); | ||
diff --git a/include/linux/device.h b/include/linux/device.h index bc41e87a969b..a00105cf795e 100644 --- a/include/linux/device.h +++ b/include/linux/device.h | |||
@@ -698,6 +698,25 @@ static inline int devm_add_action_or_reset(struct device *dev, | |||
698 | return ret; | 698 | return ret; |
699 | } | 699 | } |
700 | 700 | ||
701 | /** | ||
702 | * devm_alloc_percpu - Resource-managed alloc_percpu | ||
703 | * @dev: Device to allocate per-cpu memory for | ||
704 | * @type: Type to allocate per-cpu memory for | ||
705 | * | ||
706 | * Managed alloc_percpu. Per-cpu memory allocated with this function is | ||
707 | * automatically freed on driver detach. | ||
708 | * | ||
709 | * RETURNS: | ||
710 | * Pointer to allocated memory on success, NULL on failure. | ||
711 | */ | ||
712 | #define devm_alloc_percpu(dev, type) \ | ||
713 | ((typeof(type) __percpu *)__devm_alloc_percpu((dev), sizeof(type), \ | ||
714 | __alignof__(type))) | ||
715 | |||
716 | void __percpu *__devm_alloc_percpu(struct device *dev, size_t size, | ||
717 | size_t align); | ||
718 | void devm_free_percpu(struct device *dev, void __percpu *pdata); | ||
719 | |||
701 | struct device_dma_parameters { | 720 | struct device_dma_parameters { |
702 | /* | 721 | /* |
703 | * a low level driver may set these to teach IOMMU code about | 722 | * a low level driver may set these to teach IOMMU code about |