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