2005-04-17 00:20:36 +02:00
|
|
|
/*
|
|
|
|
* Dynamic DMA mapping support.
|
|
|
|
*
|
|
|
|
* On i386 there is no hardware dynamic DMA address translation,
|
|
|
|
* so consistent alloc/free are merely page allocation/freeing.
|
|
|
|
* The rest of the dynamic DMA mapping interface is implemented
|
|
|
|
* in asm/pci.h.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/types.h>
|
|
|
|
#include <linux/mm.h>
|
|
|
|
#include <linux/string.h>
|
|
|
|
#include <linux/pci.h>
|
2005-06-23 09:08:33 +02:00
|
|
|
#include <linux/module.h>
|
2005-04-17 00:20:36 +02:00
|
|
|
#include <asm/io.h>
|
|
|
|
|
2008-03-25 22:36:36 +01:00
|
|
|
/* For i386, we make it point to the NULL address */
|
|
|
|
dma_addr_t bad_dma_address __read_mostly = 0x0;
|
|
|
|
EXPORT_SYMBOL(bad_dma_address);
|
|
|
|
|
2005-04-17 00:20:36 +02:00
|
|
|
void *dma_alloc_coherent(struct device *dev, size_t size,
|
2005-10-07 08:46:04 +02:00
|
|
|
dma_addr_t *dma_handle, gfp_t gfp)
|
2005-04-17 00:20:36 +02:00
|
|
|
{
|
|
|
|
void *ret;
|
|
|
|
struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL;
|
|
|
|
int order = get_order(size);
|
|
|
|
/* ignore region specifiers */
|
|
|
|
gfp &= ~(__GFP_DMA | __GFP_HIGHMEM);
|
|
|
|
|
|
|
|
if (mem) {
|
|
|
|
int page = bitmap_find_free_region(mem->bitmap, mem->size,
|
|
|
|
order);
|
|
|
|
if (page >= 0) {
|
|
|
|
*dma_handle = mem->device_base + (page << PAGE_SHIFT);
|
|
|
|
ret = mem->virt_base + (page << PAGE_SHIFT);
|
|
|
|
memset(ret, 0, size);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
if (mem->flags & DMA_MEMORY_EXCLUSIVE)
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dev == NULL || (dev->coherent_dma_mask < 0xffffffff))
|
|
|
|
gfp |= GFP_DMA;
|
|
|
|
|
|
|
|
ret = (void *)__get_free_pages(gfp, order);
|
|
|
|
|
|
|
|
if (ret != NULL) {
|
|
|
|
memset(ret, 0, size);
|
|
|
|
*dma_handle = virt_to_phys(ret);
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
2005-06-23 09:08:33 +02:00
|
|
|
EXPORT_SYMBOL(dma_alloc_coherent);
|
2005-04-17 00:20:36 +02:00
|
|
|
|
|
|
|
void dma_free_coherent(struct device *dev, size_t size,
|
|
|
|
void *vaddr, dma_addr_t dma_handle)
|
|
|
|
{
|
|
|
|
struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL;
|
|
|
|
int order = get_order(size);
|
2007-08-10 22:10:27 +02:00
|
|
|
|
|
|
|
WARN_ON(irqs_disabled()); /* for portability */
|
2005-04-17 00:20:36 +02:00
|
|
|
if (mem && vaddr >= mem->virt_base && vaddr < (mem->virt_base + (mem->size << PAGE_SHIFT))) {
|
|
|
|
int page = (vaddr - mem->virt_base) >> PAGE_SHIFT;
|
|
|
|
|
|
|
|
bitmap_release_region(mem->bitmap, page, order);
|
|
|
|
} else
|
|
|
|
free_pages((unsigned long)vaddr, order);
|
|
|
|
}
|
2005-06-23 09:08:33 +02:00
|
|
|
EXPORT_SYMBOL(dma_free_coherent);
|