Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/avr32/mm/ioremap.c
10817 views
1
/*
2
* Copyright (C) 2004-2006 Atmel Corporation
3
*
4
* This program is free software; you can redistribute it and/or modify
5
* it under the terms of the GNU General Public License version 2 as
6
* published by the Free Software Foundation.
7
*/
8
#include <linux/vmalloc.h>
9
#include <linux/mm.h>
10
#include <linux/module.h>
11
#include <linux/io.h>
12
#include <linux/slab.h>
13
14
#include <asm/pgtable.h>
15
#include <asm/addrspace.h>
16
17
/*
18
* Re-map an arbitrary physical address space into the kernel virtual
19
* address space. Needed when the kernel wants to access physical
20
* memory directly.
21
*/
22
void __iomem *__ioremap(unsigned long phys_addr, size_t size,
23
unsigned long flags)
24
{
25
unsigned long addr;
26
struct vm_struct *area;
27
unsigned long offset, last_addr;
28
pgprot_t prot;
29
30
/*
31
* Check if we can simply use the P4 segment. This area is
32
* uncacheable, so if caching/buffering is requested, we can't
33
* use it.
34
*/
35
if ((phys_addr >= P4SEG) && (flags == 0))
36
return (void __iomem *)phys_addr;
37
38
/* Don't allow wraparound or zero size */
39
last_addr = phys_addr + size - 1;
40
if (!size || last_addr < phys_addr)
41
return NULL;
42
43
/*
44
* XXX: When mapping regular RAM, we'd better make damn sure
45
* it's never used for anything else. But this is really the
46
* caller's responsibility...
47
*/
48
if (PHYSADDR(P2SEGADDR(phys_addr)) == phys_addr)
49
return (void __iomem *)P2SEGADDR(phys_addr);
50
51
/* Mappings have to be page-aligned */
52
offset = phys_addr & ~PAGE_MASK;
53
phys_addr &= PAGE_MASK;
54
size = PAGE_ALIGN(last_addr + 1) - phys_addr;
55
56
prot = __pgprot(_PAGE_PRESENT | _PAGE_GLOBAL | _PAGE_RW | _PAGE_DIRTY
57
| _PAGE_ACCESSED | _PAGE_TYPE_SMALL | flags);
58
59
/*
60
* Ok, go for it..
61
*/
62
area = get_vm_area(size, VM_IOREMAP);
63
if (!area)
64
return NULL;
65
area->phys_addr = phys_addr;
66
addr = (unsigned long )area->addr;
67
if (ioremap_page_range(addr, addr + size, phys_addr, prot)) {
68
vunmap((void *)addr);
69
return NULL;
70
}
71
72
return (void __iomem *)(offset + (char *)addr);
73
}
74
EXPORT_SYMBOL(__ioremap);
75
76
void __iounmap(void __iomem *addr)
77
{
78
struct vm_struct *p;
79
80
if ((unsigned long)addr >= P4SEG)
81
return;
82
if (PXSEG(addr) == P2SEG)
83
return;
84
85
p = remove_vm_area((void *)(PAGE_MASK & (unsigned long __force)addr));
86
if (unlikely(!p)) {
87
printk (KERN_ERR "iounmap: bad address %p\n", addr);
88
return;
89
}
90
91
kfree (p);
92
}
93
EXPORT_SYMBOL(__iounmap);
94
95