1/* 2 * drivers/base/dma-mapping.c - arch-independent dma-mapping routines 3 * 4 * Copyright (c) 2006 SUSE Linux Products GmbH 5 * Copyright (c) 2006 Tejun Heo <teheo@suse.de> 6 * 7 * This file is released under the GPLv2. 8 */ 9 10#include <linux/dma-mapping.h> 11#include <linux/export.h> 12#include <linux/gfp.h> 13 14/* 15 * Managed DMA API 16 */ 17struct dma_devres { 18 size_t size; 19 void *vaddr; 20 dma_addr_t dma_handle; 21}; 22 23static void dmam_coherent_release(struct device *dev, void *res) 24{ 25 struct dma_devres *this = res; 26 27 dma_free_coherent(dev, this->size, this->vaddr, this->dma_handle); 28} 29 30static void dmam_noncoherent_release(struct device *dev, void *res) 31{ 32 struct dma_devres *this = res; 33 34 dma_free_noncoherent(dev, this->size, this->vaddr, this->dma_handle); 35} 36 37static int dmam_match(struct device *dev, void *res, void *match_data) 38{ 39 struct dma_devres *this = res, *match = match_data; 40 41 if (this->vaddr == match->vaddr) { 42 WARN_ON(this->size != match->size || 43 this->dma_handle != match->dma_handle); 44 return 1; 45 } 46 return 0; 47} 48 49/** 50 * dmam_alloc_coherent - Managed dma_alloc_coherent() 51 * @dev: Device to allocate coherent memory for 52 * @size: Size of allocation 53 * @dma_handle: Out argument for allocated DMA handle 54 * @gfp: Allocation flags 55 * 56 * Managed dma_alloc_coherent(). Memory allocated using this function 57 * will be automatically released on driver detach. 58 * 59 * RETURNS: 60 * Pointer to allocated memory on success, NULL on failure. 61 */ 62void * dmam_alloc_coherent(struct device *dev, size_t size, 63 dma_addr_t *dma_handle, gfp_t gfp) 64{ 65 struct dma_devres *dr; 66 void *vaddr; 67 68 dr = devres_alloc(dmam_coherent_release, sizeof(*dr), gfp); 69 if (!dr) 70 return NULL; 71 72 vaddr = dma_alloc_coherent(dev, size, dma_handle, gfp); 73 if (!vaddr) { 74 devres_free(dr); 75 return NULL; 76 } 77 78 dr->vaddr = vaddr; 79 dr->dma_handle = *dma_handle; 80 dr->size = size; 81 82 devres_add(dev, dr); 83 84 return vaddr; 85} 86EXPORT_SYMBOL(dmam_alloc_coherent); 87 88/** 89 * dmam_free_coherent - Managed dma_free_coherent() 90 * @dev: Device to free coherent memory for 91 * @size: Size of allocation 92 * @vaddr: Virtual address of the memory to free 93 * @dma_handle: DMA handle of the memory to free 94 * 95 * Managed dma_free_coherent(). 96 */ 97void dmam_free_coherent(struct device *dev, size_t size, void *vaddr, 98 dma_addr_t dma_handle) 99{ 100 struct dma_devres match_data = { size, vaddr, dma_handle }; 101 102 dma_free_coherent(dev, size, vaddr, dma_handle); 103 WARN_ON(devres_destroy(dev, dmam_coherent_release, dmam_match, 104 &match_data)); 105} 106EXPORT_SYMBOL(dmam_free_coherent); 107 108/** 109 * dmam_alloc_non_coherent - Managed dma_alloc_non_coherent() 110 * @dev: Device to allocate non_coherent memory for 111 * @size: Size of allocation 112 * @dma_handle: Out argument for allocated DMA handle 113 * @gfp: Allocation flags 114 * 115 * Managed dma_alloc_non_coherent(). Memory allocated using this 116 * function will be automatically released on driver detach. 117 * 118 * RETURNS: 119 * Pointer to allocated memory on success, NULL on failure. 120 */ 121void *dmam_alloc_noncoherent(struct device *dev, size_t size, 122 dma_addr_t *dma_handle, gfp_t gfp) 123{ 124 struct dma_devres *dr; 125 void *vaddr; 126 127 dr = devres_alloc(dmam_noncoherent_release, sizeof(*dr), gfp); 128 if (!dr) 129 return NULL; 130 131 vaddr = dma_alloc_noncoherent(dev, size, dma_handle, gfp); 132 if (!vaddr) { 133 devres_free(dr); 134 return NULL; 135 } 136 137 dr->vaddr = vaddr; 138 dr->dma_handle = *dma_handle; 139 dr->size = size; 140 141 devres_add(dev, dr); 142 143 return vaddr; 144} 145EXPORT_SYMBOL(dmam_alloc_noncoherent); 146 147/** 148 * dmam_free_coherent - Managed dma_free_noncoherent() 149 * @dev: Device to free noncoherent memory for 150 * @size: Size of allocation 151 * @vaddr: Virtual address of the memory to free 152 * @dma_handle: DMA handle of the memory to free 153 * 154 * Managed dma_free_noncoherent(). 155 */ 156void dmam_free_noncoherent(struct device *dev, size_t size, void *vaddr, 157 dma_addr_t dma_handle) 158{ 159 struct dma_devres match_data = { size, vaddr, dma_handle }; 160 161 dma_free_noncoherent(dev, size, vaddr, dma_handle); 162 WARN_ON(!devres_destroy(dev, dmam_noncoherent_release, dmam_match, 163 &match_data)); 164} 165EXPORT_SYMBOL(dmam_free_noncoherent); 166 167#ifdef ARCH_HAS_DMA_DECLARE_COHERENT_MEMORY 168 169static void dmam_coherent_decl_release(struct device *dev, void *res) 170{ 171 dma_release_declared_memory(dev); 172} 173 174/** 175 * dmam_declare_coherent_memory - Managed dma_declare_coherent_memory() 176 * @dev: Device to declare coherent memory for 177 * @bus_addr: Bus address of coherent memory to be declared 178 * @device_addr: Device address of coherent memory to be declared 179 * @size: Size of coherent memory to be declared 180 * @flags: Flags 181 * 182 * Managed dma_declare_coherent_memory(). 183 * 184 * RETURNS: 185 * 0 on success, -errno on failure. 186 */ 187int dmam_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr, 188 dma_addr_t device_addr, size_t size, int flags) 189{ 190 void *res; 191 int rc; 192 193 res = devres_alloc(dmam_coherent_decl_release, 0, GFP_KERNEL); 194 if (!res) 195 return -ENOMEM; 196 197 rc = dma_declare_coherent_memory(dev, bus_addr, device_addr, size, 198 flags); 199 if (rc == 0) 200 devres_add(dev, res); 201 else 202 devres_free(res); 203 204 return rc; 205} 206EXPORT_SYMBOL(dmam_declare_coherent_memory); 207 208/** 209 * dmam_release_declared_memory - Managed dma_release_declared_memory(). 210 * @dev: Device to release declared coherent memory for 211 * 212 * Managed dmam_release_declared_memory(). 213 */ 214void dmam_release_declared_memory(struct device *dev) 215{ 216 WARN_ON(devres_destroy(dev, dmam_coherent_decl_release, NULL, NULL)); 217} 218EXPORT_SYMBOL(dmam_release_declared_memory); 219 220#endif 221