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