This source file includes following definitions.
- forget_pte
- io_remap_pte_range
- io_remap_pmd_range
- io_remap_page_range
1
2
3
4
5
6
7
8 #include <linux/kernel.h>
9 #include <linux/mm.h>
10 #include <linux/swap.h>
11
12 #include <asm/pgtable.h>
13 #include <asm/page.h>
14
15 static inline void forget_pte(pte_t page)
16 {
17 if (pte_none(page))
18 return;
19 if (pte_present(page)) {
20 unsigned long addr = pte_page(page);
21 if (addr >= high_memory || PageReserved(mem_map+MAP_NR(addr)))
22 return;
23 free_page(addr);
24 if (current->mm->rss <= 0)
25 return;
26 current->mm->rss--;
27 return;
28 }
29 swap_free(pte_val(page));
30 }
31
32
33
34
35
36
37
38 static inline void io_remap_pte_range(pte_t * pte, unsigned long address, unsigned long size,
39 unsigned long offset, pgprot_t prot, int space)
40 {
41 unsigned long end;
42
43 address &= ~PMD_MASK;
44 end = address + size;
45 if (end > PMD_SIZE)
46 end = PMD_SIZE;
47 do {
48 pte_t oldpage = *pte;
49 pte_clear(pte);
50 set_pte(pte, mk_pte_io(offset, prot, space));
51 forget_pte(oldpage);
52 address += PAGE_SIZE;
53 offset += PAGE_SIZE;
54 pte++;
55 } while (address < end);
56 }
57
58 static inline int io_remap_pmd_range(pmd_t * pmd, unsigned long address, unsigned long size,
59 unsigned long offset, pgprot_t prot, int space)
60 {
61 unsigned long end;
62
63 address &= ~PGDIR_MASK;
64 end = address + size;
65 if (end > PGDIR_SIZE)
66 end = PGDIR_SIZE;
67 offset -= address;
68 do {
69 pte_t * pte = pte_alloc(pmd, address);
70 if (!pte)
71 return -ENOMEM;
72 io_remap_pte_range(pte, address, end - address, address + offset, prot, space);
73 address = (address + PMD_SIZE) & PMD_MASK;
74 pmd++;
75 } while (address < end);
76 return 0;
77 }
78
79 int io_remap_page_range(unsigned long from, unsigned long offset, unsigned long size, pgprot_t prot, int space)
80 {
81 int error = 0;
82 pgd_t * dir;
83 unsigned long beg = from;
84 unsigned long end = from + size;
85
86 pgprot_val(prot) = pg_iobits;
87 offset -= from;
88 dir = pgd_offset(current->mm, from);
89 flush_cache_range(current->mm, beg, end);
90 while (from < end) {
91 pmd_t *pmd = pmd_alloc(dir, from);
92 error = -ENOMEM;
93 if (!pmd)
94 break;
95 error = io_remap_pmd_range(pmd, from, end - from, offset + from, prot, space);
96 if (error)
97 break;
98 from = (from + PGDIR_SIZE) & PGDIR_MASK;
99 dir++;
100 }
101 flush_tlb_range(current->mm, beg, end);
102 return error;
103 }