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