diff options
Diffstat (limited to 'arch/arm/mm/ioremap.c')
-rw-r--r-- | arch/arm/mm/ioremap.c | 98 |
1 files changed, 40 insertions, 58 deletions
diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c index a43d2800a9cd..3bb3951920bc 100644 --- a/arch/arm/mm/ioremap.c +++ b/arch/arm/mm/ioremap.c | |||
@@ -38,89 +38,71 @@ | |||
38 | */ | 38 | */ |
39 | #define VM_ARM_SECTION_MAPPING 0x80000000 | 39 | #define VM_ARM_SECTION_MAPPING 0x80000000 |
40 | 40 | ||
41 | static inline void | 41 | static int remap_area_pte(pmd_t *pmd, unsigned long addr, unsigned long end, |
42 | remap_area_pte(pte_t * pte, unsigned long address, unsigned long size, | 42 | unsigned long phys_addr, pgprot_t prot) |
43 | unsigned long phys_addr, pgprot_t prot) | ||
44 | { | 43 | { |
45 | unsigned long end; | 44 | pte_t *pte; |
45 | |||
46 | pte = pte_alloc_kernel(pmd, addr); | ||
47 | if (!pte) | ||
48 | return -ENOMEM; | ||
46 | 49 | ||
47 | address &= ~PMD_MASK; | ||
48 | end = address + size; | ||
49 | if (end > PMD_SIZE) | ||
50 | end = PMD_SIZE; | ||
51 | BUG_ON(address >= end); | ||
52 | do { | 50 | do { |
53 | if (!pte_none(*pte)) | 51 | if (!pte_none(*pte)) |
54 | goto bad; | 52 | goto bad; |
55 | 53 | ||
56 | set_pte_ext(pte, pfn_pte(phys_addr >> PAGE_SHIFT, prot), 0); | 54 | set_pte_ext(pte, pfn_pte(phys_addr >> PAGE_SHIFT, prot), 0); |
57 | address += PAGE_SIZE; | ||
58 | phys_addr += PAGE_SIZE; | 55 | phys_addr += PAGE_SIZE; |
59 | pte++; | 56 | } while (pte++, addr += PAGE_SIZE, addr != end); |
60 | } while (address && (address < end)); | 57 | return 0; |
61 | return; | ||
62 | 58 | ||
63 | bad: | 59 | bad: |
64 | printk("remap_area_pte: page already exists\n"); | 60 | printk(KERN_CRIT "remap_area_pte: page already exists\n"); |
65 | BUG(); | 61 | BUG(); |
66 | } | 62 | } |
67 | 63 | ||
68 | static inline int | 64 | static inline int remap_area_pmd(pgd_t *pgd, unsigned long addr, |
69 | remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size, | 65 | unsigned long end, unsigned long phys_addr, |
70 | unsigned long phys_addr, unsigned long flags) | 66 | pgprot_t prot) |
71 | { | 67 | { |
72 | unsigned long end; | 68 | unsigned long next; |
73 | pgprot_t pgprot; | 69 | pmd_t *pmd; |
74 | 70 | int ret = 0; | |
75 | address &= ~PGDIR_MASK; | ||
76 | end = address + size; | ||
77 | 71 | ||
78 | if (end > PGDIR_SIZE) | 72 | pmd = pmd_alloc(&init_mm, pgd, addr); |
79 | end = PGDIR_SIZE; | 73 | if (!pmd) |
74 | return -ENOMEM; | ||
80 | 75 | ||
81 | phys_addr -= address; | ||
82 | BUG_ON(address >= end); | ||
83 | |||
84 | pgprot = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | L_PTE_WRITE | flags); | ||
85 | do { | 76 | do { |
86 | pte_t * pte = pte_alloc_kernel(pmd, address); | 77 | next = pmd_addr_end(addr, end); |
87 | if (!pte) | 78 | ret = remap_area_pte(pmd, addr, next, phys_addr, prot); |
88 | return -ENOMEM; | 79 | if (ret) |
89 | remap_area_pte(pte, address, end - address, address + phys_addr, pgprot); | 80 | return ret; |
90 | address = (address + PMD_SIZE) & PMD_MASK; | 81 | phys_addr += next - addr; |
91 | pmd++; | 82 | } while (pmd++, addr = next, addr != end); |
92 | } while (address && (address < end)); | 83 | return ret; |
93 | return 0; | ||
94 | } | 84 | } |
95 | 85 | ||
96 | static int | 86 | static int remap_area_pages(unsigned long start, unsigned long pfn, |
97 | remap_area_pages(unsigned long start, unsigned long pfn, | 87 | unsigned long size, unsigned long flags) |
98 | unsigned long size, unsigned long flags) | ||
99 | { | 88 | { |
100 | unsigned long address = start; | 89 | unsigned long addr = start; |
101 | unsigned long end = start + size; | 90 | unsigned long next, end = start + size; |
102 | unsigned long phys_addr = __pfn_to_phys(pfn); | 91 | unsigned long phys_addr = __pfn_to_phys(pfn); |
92 | pgprot_t prot = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | | ||
93 | L_PTE_DIRTY | L_PTE_WRITE | flags); | ||
94 | pgd_t *pgd; | ||
103 | int err = 0; | 95 | int err = 0; |
104 | pgd_t * dir; | ||
105 | 96 | ||
106 | phys_addr -= address; | 97 | BUG_ON(addr >= end); |
107 | dir = pgd_offset(&init_mm, address); | 98 | pgd = pgd_offset_k(addr); |
108 | BUG_ON(address >= end); | ||
109 | do { | 99 | do { |
110 | pmd_t *pmd = pmd_alloc(&init_mm, dir, address); | 100 | next = pgd_addr_end(addr, end); |
111 | if (!pmd) { | 101 | err = remap_area_pmd(pgd, addr, next, phys_addr, prot); |
112 | err = -ENOMEM; | 102 | if (err) |
113 | break; | ||
114 | } | ||
115 | if (remap_area_pmd(pmd, address, end - address, | ||
116 | phys_addr + address, flags)) { | ||
117 | err = -ENOMEM; | ||
118 | break; | 103 | break; |
119 | } | 104 | phys_addr += next - addr; |
120 | 105 | } while (pgd++, addr = next, addr != end); | |
121 | address = (address + PGDIR_SIZE) & PGDIR_MASK; | ||
122 | dir++; | ||
123 | } while (address && (address < end)); | ||
124 | 106 | ||
125 | return err; | 107 | return err; |
126 | } | 108 | } |