aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/mips/mm/ioremap.c96
1 files changed, 88 insertions, 8 deletions
diff --git a/arch/mips/mm/ioremap.c b/arch/mips/mm/ioremap.c
index fc2c96f0a1fd..cea7d0ea36e4 100644
--- a/arch/mips/mm/ioremap.c
+++ b/arch/mips/mm/ioremap.c
@@ -6,13 +6,98 @@
6 * (C) Copyright 1995 1996 Linus Torvalds 6 * (C) Copyright 1995 1996 Linus Torvalds
7 * (C) Copyright 2001, 2002 Ralf Baechle 7 * (C) Copyright 2001, 2002 Ralf Baechle
8 */ 8 */
9#include <linux/mm.h>
10#include <linux/module.h> 9#include <linux/module.h>
11#include <asm/addrspace.h> 10#include <asm/addrspace.h>
12#include <asm/byteorder.h> 11#include <asm/byteorder.h>
13 12
14#include <linux/vmalloc.h> 13#include <linux/vmalloc.h>
15#include <linux/io.h> 14#include <asm/cacheflush.h>
15#include <asm/io.h>
16#include <asm/tlbflush.h>
17
18static inline void remap_area_pte(pte_t * pte, unsigned long address,
19 phys_t size, phys_t phys_addr, unsigned long flags)
20{
21 phys_t end;
22 unsigned long pfn;
23 pgprot_t pgprot = __pgprot(_PAGE_GLOBAL | _PAGE_PRESENT | __READABLE
24 | __WRITEABLE | flags);
25
26 address &= ~PMD_MASK;
27 end = address + size;
28 if (end > PMD_SIZE)
29 end = PMD_SIZE;
30 if (address >= end)
31 BUG();
32 pfn = phys_addr >> PAGE_SHIFT;
33 do {
34 if (!pte_none(*pte)) {
35 printk("remap_area_pte: page already exists\n");
36 BUG();
37 }
38 set_pte(pte, pfn_pte(pfn, pgprot));
39 address += PAGE_SIZE;
40 pfn++;
41 pte++;
42 } while (address && (address < end));
43}
44
45static inline int remap_area_pmd(pmd_t * pmd, unsigned long address,
46 phys_t size, phys_t phys_addr, unsigned long flags)
47{
48 phys_t end;
49
50 address &= ~PGDIR_MASK;
51 end = address + size;
52 if (end > PGDIR_SIZE)
53 end = PGDIR_SIZE;
54 phys_addr -= address;
55 if (address >= end)
56 BUG();
57 do {
58 pte_t * pte = pte_alloc_kernel(pmd, address);
59 if (!pte)
60 return -ENOMEM;
61 remap_area_pte(pte, address, end - address, address + phys_addr, flags);
62 address = (address + PMD_SIZE) & PMD_MASK;
63 pmd++;
64 } while (address && (address < end));
65 return 0;
66}
67
68static int remap_area_pages(unsigned long address, phys_t phys_addr,
69 phys_t size, unsigned long flags)
70{
71 int error;
72 pgd_t * dir;
73 unsigned long end = address + size;
74
75 phys_addr -= address;
76 dir = pgd_offset(&init_mm, address);
77 flush_cache_all();
78 if (address >= end)
79 BUG();
80 do {
81 pud_t *pud;
82 pmd_t *pmd;
83
84 error = -ENOMEM;
85 pud = pud_alloc(&init_mm, dir, address);
86 if (!pud)
87 break;
88 pmd = pmd_alloc(&init_mm, pud, address);
89 if (!pmd)
90 break;
91 if (remap_area_pmd(pmd, address, end - address,
92 phys_addr + address, flags))
93 break;
94 error = 0;
95 address = (address + PGDIR_SIZE) & PGDIR_MASK;
96 dir++;
97 } while (address && (address < end));
98 flush_tlb_all();
99 return error;
100}
16 101
17/* 102/*
18 * Generic mapping function (not visible outside): 103 * Generic mapping function (not visible outside):
@@ -36,7 +121,6 @@ void __iomem * __ioremap(phys_t phys_addr, phys_t size, unsigned long flags)
36 unsigned long offset; 121 unsigned long offset;
37 phys_t last_addr; 122 phys_t last_addr;
38 void * addr; 123 void * addr;
39 pgprot_t pgprot;
40 124
41 phys_addr = fixup_bigphys_addr(phys_addr, size); 125 phys_addr = fixup_bigphys_addr(phys_addr, size);
42 126
@@ -68,9 +152,6 @@ void __iomem * __ioremap(phys_t phys_addr, phys_t size, unsigned long flags)
68 return NULL; 152 return NULL;
69 } 153 }
70 154
71 pgprot = __pgprot(_PAGE_GLOBAL | _PAGE_PRESENT | __READABLE
72 | __WRITEABLE | flags);
73
74 /* 155 /*
75 * Mappings have to be page-aligned 156 * Mappings have to be page-aligned
76 */ 157 */
@@ -85,8 +166,7 @@ void __iomem * __ioremap(phys_t phys_addr, phys_t size, unsigned long flags)
85 if (!area) 166 if (!area)
86 return NULL; 167 return NULL;
87 addr = area->addr; 168 addr = area->addr;
88 if (ioremap_page_range((unsigned long)addr, (unsigned long)addr + size, 169 if (remap_area_pages((unsigned long) addr, phys_addr, size, flags)) {
89 phys_addr, pgprot)) {
90 vunmap(addr); 170 vunmap(addr);
91 return NULL; 171 return NULL;
92 } 172 }