aboutsummaryrefslogtreecommitdiffstats
path: root/arch/alpha/mm/remap.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/alpha/mm/remap.c')
-rw-r--r--arch/alpha/mm/remap.c90
1 files changed, 90 insertions, 0 deletions
diff --git a/arch/alpha/mm/remap.c b/arch/alpha/mm/remap.c
new file mode 100644
index 00000000000..19817ad3d89
--- /dev/null
+++ b/arch/alpha/mm/remap.c
@@ -0,0 +1,90 @@
1#include <linux/vmalloc.h>
2#include <asm/pgalloc.h>
3#include <asm/cacheflush.h>
4
5/* called with the page_table_lock held */
6static inline void
7remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
8 unsigned long phys_addr, unsigned long flags)
9{
10 unsigned long end;
11 unsigned long pfn;
12
13 address &= ~PMD_MASK;
14 end = address + size;
15 if (end > PMD_SIZE)
16 end = PMD_SIZE;
17 if (address >= end)
18 BUG();
19 pfn = phys_addr >> PAGE_SHIFT;
20 do {
21 if (!pte_none(*pte)) {
22 printk("remap_area_pte: page already exists\n");
23 BUG();
24 }
25 set_pte(pte, pfn_pte(pfn,
26 __pgprot(_PAGE_VALID | _PAGE_ASM |
27 _PAGE_KRE | _PAGE_KWE | flags)));
28 address += PAGE_SIZE;
29 pfn++;
30 pte++;
31 } while (address && (address < end));
32}
33
34/* called with the page_table_lock held */
35static inline int
36remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size,
37 unsigned long phys_addr, unsigned long flags)
38{
39 unsigned long end;
40
41 address &= ~PGDIR_MASK;
42 end = address + size;
43 if (end > PGDIR_SIZE)
44 end = PGDIR_SIZE;
45 phys_addr -= address;
46 if (address >= end)
47 BUG();
48 do {
49 pte_t * pte = pte_alloc_kernel(&init_mm, pmd, address);
50 if (!pte)
51 return -ENOMEM;
52 remap_area_pte(pte, address, end - address,
53 address + phys_addr, flags);
54 address = (address + PMD_SIZE) & PMD_MASK;
55 pmd++;
56 } while (address && (address < end));
57 return 0;
58}
59
60int
61__alpha_remap_area_pages(unsigned long address, unsigned long phys_addr,
62 unsigned long size, unsigned long flags)
63{
64 pgd_t * dir;
65 int error = 0;
66 unsigned long end = address + size;
67
68 phys_addr -= address;
69 dir = pgd_offset(&init_mm, address);
70 flush_cache_all();
71 if (address >= end)
72 BUG();
73 spin_lock(&init_mm.page_table_lock);
74 do {
75 pmd_t *pmd;
76 pmd = pmd_alloc(&init_mm, dir, address);
77 error = -ENOMEM;
78 if (!pmd)
79 break;
80 if (remap_area_pmd(pmd, address, end - address,
81 phys_addr + address, flags))
82 break;
83 error = 0;
84 address = (address + PGDIR_SIZE) & PGDIR_MASK;
85 dir++;
86 } while (address && (address < end));
87 spin_unlock(&init_mm.page_table_lock);
88 return error;
89}
90