diff options
Diffstat (limited to 'arch/m68k/mm/sun3kmap.c')
-rw-r--r-- | arch/m68k/mm/sun3kmap.c | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/arch/m68k/mm/sun3kmap.c b/arch/m68k/mm/sun3kmap.c new file mode 100644 index 000000000000..7f0d86f3fe73 --- /dev/null +++ b/arch/m68k/mm/sun3kmap.c | |||
@@ -0,0 +1,156 @@ | |||
1 | /* | ||
2 | * linux/arch/m68k/mm/sun3kmap.c | ||
3 | * | ||
4 | * Copyright (C) 2002 Sam Creasey <sammy@sammy.net> | ||
5 | * | ||
6 | * This file is subject to the terms and conditions of the GNU General Public | ||
7 | * License. See the file COPYING in the main directory of this archive | ||
8 | * for more details. | ||
9 | */ | ||
10 | |||
11 | #include <linux/types.h> | ||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/mm.h> | ||
14 | #include <linux/vmalloc.h> | ||
15 | |||
16 | #include <asm/page.h> | ||
17 | #include <asm/pgtable.h> | ||
18 | #include <asm/io.h> | ||
19 | #include <asm/sun3mmu.h> | ||
20 | |||
21 | #undef SUN3_KMAP_DEBUG | ||
22 | |||
23 | #ifdef SUN3_KMAP_DEBUG | ||
24 | extern void print_pte_vaddr(unsigned long vaddr); | ||
25 | #endif | ||
26 | |||
27 | extern void mmu_emu_map_pmeg (int context, int vaddr); | ||
28 | |||
29 | static inline void do_page_mapin(unsigned long phys, unsigned long virt, | ||
30 | unsigned long type) | ||
31 | { | ||
32 | unsigned long pte; | ||
33 | pte_t ptep; | ||
34 | |||
35 | ptep = pfn_pte(phys >> PAGE_SHIFT, PAGE_KERNEL); | ||
36 | pte = pte_val(ptep); | ||
37 | pte |= type; | ||
38 | |||
39 | sun3_put_pte(virt, pte); | ||
40 | |||
41 | #ifdef SUN3_KMAP_DEBUG | ||
42 | print_pte_vaddr(virt); | ||
43 | #endif | ||
44 | |||
45 | } | ||
46 | |||
47 | static inline void do_pmeg_mapin(unsigned long phys, unsigned long virt, | ||
48 | unsigned long type, int pages) | ||
49 | { | ||
50 | |||
51 | if(sun3_get_segmap(virt & ~SUN3_PMEG_MASK) == SUN3_INVALID_PMEG) | ||
52 | mmu_emu_map_pmeg(sun3_get_context(), virt); | ||
53 | |||
54 | while(pages) { | ||
55 | do_page_mapin(phys, virt, type); | ||
56 | phys += PAGE_SIZE; | ||
57 | virt += PAGE_SIZE; | ||
58 | pages--; | ||
59 | } | ||
60 | } | ||
61 | |||
62 | void *sun3_ioremap(unsigned long phys, unsigned long size, | ||
63 | unsigned long type) | ||
64 | { | ||
65 | struct vm_struct *area; | ||
66 | unsigned long offset, virt, ret; | ||
67 | int pages; | ||
68 | |||
69 | if(!size) | ||
70 | return NULL; | ||
71 | |||
72 | /* page align */ | ||
73 | offset = phys & (PAGE_SIZE-1); | ||
74 | phys &= ~(PAGE_SIZE-1); | ||
75 | |||
76 | size += offset; | ||
77 | size = PAGE_ALIGN(size); | ||
78 | if((area = get_vm_area(size, VM_IOREMAP)) == NULL) | ||
79 | return NULL; | ||
80 | |||
81 | #ifdef SUN3_KMAP_DEBUG | ||
82 | printk("ioremap: got virt %p size %lx(%lx)\n", | ||
83 | area->addr, size, area->size); | ||
84 | #endif | ||
85 | |||
86 | pages = size / PAGE_SIZE; | ||
87 | virt = (unsigned long)area->addr; | ||
88 | ret = virt + offset; | ||
89 | |||
90 | while(pages) { | ||
91 | int seg_pages; | ||
92 | |||
93 | seg_pages = (SUN3_PMEG_SIZE - (virt & SUN3_PMEG_MASK)) / PAGE_SIZE; | ||
94 | if(seg_pages > pages) | ||
95 | seg_pages = pages; | ||
96 | |||
97 | do_pmeg_mapin(phys, virt, type, seg_pages); | ||
98 | |||
99 | pages -= seg_pages; | ||
100 | phys += seg_pages * PAGE_SIZE; | ||
101 | virt += seg_pages * PAGE_SIZE; | ||
102 | } | ||
103 | |||
104 | return (void *)ret; | ||
105 | |||
106 | } | ||
107 | |||
108 | |||
109 | void *__ioremap(unsigned long phys, unsigned long size, int cache) | ||
110 | { | ||
111 | |||
112 | return sun3_ioremap(phys, size, SUN3_PAGE_TYPE_IO); | ||
113 | |||
114 | } | ||
115 | |||
116 | void iounmap(void *addr) | ||
117 | { | ||
118 | vfree((void *)(PAGE_MASK & (unsigned long)addr)); | ||
119 | } | ||
120 | |||
121 | /* sun3_map_test(addr, val) -- Reads a byte from addr, storing to val, | ||
122 | * trapping the potential read fault. Returns 0 if the access faulted, | ||
123 | * 1 on success. | ||
124 | * | ||
125 | * This function is primarily used to check addresses on the VME bus. | ||
126 | * | ||
127 | * Mucking with the page fault handler seems a little hackish to me, but | ||
128 | * SunOS, NetBSD, and Mach all implemented this check in such a manner, | ||
129 | * so I figure we're allowed. | ||
130 | */ | ||
131 | int sun3_map_test(unsigned long addr, char *val) | ||
132 | { | ||
133 | int ret = 0; | ||
134 | |||
135 | __asm__ __volatile__ | ||
136 | (".globl _sun3_map_test_start\n" | ||
137 | "_sun3_map_test_start:\n" | ||
138 | "1: moveb (%2), (%0)\n" | ||
139 | " moveq #1, %1\n" | ||
140 | "2:\n" | ||
141 | ".section .fixup,\"ax\"\n" | ||
142 | ".even\n" | ||
143 | "3: moveq #0, %1\n" | ||
144 | " jmp 2b\n" | ||
145 | ".previous\n" | ||
146 | ".section __ex_table,\"a\"\n" | ||
147 | ".align 4\n" | ||
148 | ".long 1b,3b\n" | ||
149 | ".previous\n" | ||
150 | ".globl _sun3_map_test_end\n" | ||
151 | "_sun3_map_test_end:\n" | ||
152 | : "=a"(val), "=r"(ret) | ||
153 | : "a"(addr)); | ||
154 | |||
155 | return ret; | ||
156 | } | ||