Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 172397
b: refs/heads/master
c: 695ae0a
h: refs/heads/master
i:
  172395: 5b0a732
v: v3
  • Loading branch information
Russell King committed Nov 24, 2009
1 parent 4bdddfc commit 2bd0832
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 74 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 04da56943b416dd9fe7058abf8d5b9153164b3e9
refs/heads/master: 695ae0af5a52df09dffcc2ce2d625d56ef36ce14
141 changes: 68 additions & 73 deletions trunk/arch/arm/mm/dma-mapping.c
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,70 @@ __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp,
*handle = ~0;
return NULL;
}

static void __dma_free_remap(void *cpu_addr, size_t size)
{
struct arm_vmregion *c;
unsigned long addr;
pte_t *ptep;
int idx;
u32 off;

c = arm_vmregion_find_remove(&consistent_head, (unsigned long)cpu_addr);
if (!c) {
printk(KERN_ERR "%s: trying to free invalid coherent area: %p\n",
__func__, cpu_addr);
dump_stack();
return;
}

if ((c->vm_end - c->vm_start) != size) {
printk(KERN_ERR "%s: freeing wrong coherent size (%ld != %d)\n",
__func__, c->vm_end - c->vm_start, size);
dump_stack();
size = c->vm_end - c->vm_start;
}

idx = CONSISTENT_PTE_INDEX(c->vm_start);
off = CONSISTENT_OFFSET(c->vm_start) & (PTRS_PER_PTE-1);
ptep = consistent_pte[idx] + off;
addr = c->vm_start;
do {
pte_t pte = ptep_get_and_clear(&init_mm, addr, ptep);
unsigned long pfn;

ptep++;
addr += PAGE_SIZE;
off++;
if (off >= PTRS_PER_PTE) {
off = 0;
ptep = consistent_pte[++idx];
}

if (!pte_none(pte) && pte_present(pte)) {
pfn = pte_pfn(pte);

if (pfn_valid(pfn)) {
struct page *page = pfn_to_page(pfn);

/*
* x86 does not mark the pages reserved...
*/
ClearPageReserved(page);
continue;
}
}
printk(KERN_CRIT "%s: bad page in kernel page table\n",
__func__);
} while (size -= PAGE_SIZE);

flush_tlb_kernel_range(c->vm_start, c->vm_end);

arm_vmregion_free(&consistent_head, c);
}

#else /* !CONFIG_MMU */

static void *
__dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp,
pgprot_t prot)
Expand All @@ -224,6 +287,9 @@ __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp,
*handle = page_to_dma(dev, page);
return page_address(page);
}

#define __dma_free_remap(addr, size) do { } while (0)

#endif /* CONFIG_MMU */

/*
Expand Down Expand Up @@ -317,91 +383,20 @@ EXPORT_SYMBOL(dma_mmap_writecombine);
* free a page as defined by the above mapping.
* Must not be called with IRQs disabled.
*/
#ifdef CONFIG_MMU
void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, dma_addr_t handle)
{
struct arm_vmregion *c;
unsigned long addr;
pte_t *ptep;
int idx;
u32 off;

WARN_ON(irqs_disabled());

if (dma_release_from_coherent(dev, get_order(size), cpu_addr))
return;

size = PAGE_ALIGN(size);

if (arch_is_coherent()) {
__dma_free_buffer(dma_to_page(dev, handle), size);
return;
}

c = arm_vmregion_find_remove(&consistent_head, (unsigned long)cpu_addr);
if (!c)
goto no_area;

if ((c->vm_end - c->vm_start) != size) {
printk(KERN_ERR "%s: freeing wrong coherent size (%ld != %d)\n",
__func__, c->vm_end - c->vm_start, size);
dump_stack();
size = c->vm_end - c->vm_start;
}

idx = CONSISTENT_PTE_INDEX(c->vm_start);
off = CONSISTENT_OFFSET(c->vm_start) & (PTRS_PER_PTE-1);
ptep = consistent_pte[idx] + off;
addr = c->vm_start;
do {
pte_t pte = ptep_get_and_clear(&init_mm, addr, ptep);
unsigned long pfn;

ptep++;
addr += PAGE_SIZE;
off++;
if (off >= PTRS_PER_PTE) {
off = 0;
ptep = consistent_pte[++idx];
}

if (!pte_none(pte) && pte_present(pte)) {
pfn = pte_pfn(pte);

if (pfn_valid(pfn)) {
struct page *page = pfn_to_page(pfn);

/*
* x86 does not mark the pages reserved...
*/
ClearPageReserved(page);
continue;
}
}
printk(KERN_CRIT "%s: bad page in kernel page table\n",
__func__);
} while (size -= PAGE_SIZE);

flush_tlb_kernel_range(c->vm_start, c->vm_end);

arm_vmregion_free(&consistent_head, c);
if (!arch_is_coherent())
__dma_free_remap(cpu_addr, size);

__dma_free_buffer(dma_to_page(dev, handle), size);
return;

no_area:
printk(KERN_ERR "%s: trying to free invalid coherent area: %p\n",
__func__, cpu_addr);
dump_stack();
}
#else /* !CONFIG_MMU */
void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, dma_addr_t handle)
{
if (dma_release_from_coherent(dev, get_order(size), cpu_addr))
return;
__dma_free_buffer(dma_to_page(dev, handle), PAGE_ALIGN(size));
}
#endif /* CONFIG_MMU */
EXPORT_SYMBOL(dma_free_coherent);

/*
Expand Down

0 comments on commit 2bd0832

Please sign in to comment.