| @@ -1,860 +1,860 @@ | | | @@ -1,860 +1,860 @@ |
1 | /* $NetBSD: ofwoea_machdep.c,v 1.48 2020/07/06 09:34:17 rin Exp $ */ | | 1 | /* $NetBSD: ofwoea_machdep.c,v 1.49 2020/07/06 10:59:37 rin Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 2007 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 2007 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation | | 7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Tim Rightnour | | 8 | * by Tim Rightnour |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright | | 15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the | | 16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. | | 17 | * documentation and/or other materials provided with the distribution. |
18 | * | | 18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | | 19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. | | 29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ | | 30 | */ |
31 | | | 31 | |
32 | #include <sys/cdefs.h> | | 32 | #include <sys/cdefs.h> |
33 | __KERNEL_RCSID(0, "$NetBSD: ofwoea_machdep.c,v 1.48 2020/07/06 09:34:17 rin Exp $"); | | 33 | __KERNEL_RCSID(0, "$NetBSD: ofwoea_machdep.c,v 1.49 2020/07/06 10:59:37 rin Exp $"); |
34 | | | 34 | |
35 | #include "ksyms.h" | | 35 | #include "ksyms.h" |
36 | #include "wsdisplay.h" | | 36 | #include "wsdisplay.h" |
37 | | | 37 | |
38 | #ifdef _KERNEL_OPT | | 38 | #ifdef _KERNEL_OPT |
39 | #include "opt_ddb.h" | | 39 | #include "opt_ddb.h" |
40 | #include "opt_compat_netbsd.h" | | | |
41 | #include "opt_kgdb.h" | | 40 | #include "opt_kgdb.h" |
42 | #include "opt_modular.h" | | 41 | #include "opt_modular.h" |
| | | 42 | #include "opt_multiprocessor.h" |
43 | #include "opt_oea.h" | | 43 | #include "opt_oea.h" |
44 | #include "opt_ofwoea.h" | | 44 | #include "opt_ofwoea.h" |
45 | #include "opt_ppcarch.h" | | 45 | #include "opt_ppcarch.h" |
46 | #endif | | 46 | #endif |
47 | | | 47 | |
48 | #include <sys/param.h> | | 48 | #include <sys/param.h> |
49 | #include <sys/buf.h> | | 49 | #include <sys/buf.h> |
50 | #include <sys/boot_flag.h> | | 50 | #include <sys/boot_flag.h> |
51 | #include <sys/extent.h> | | 51 | #include <sys/extent.h> |
52 | #include <sys/kernel.h> | | 52 | #include <sys/kernel.h> |
53 | #include <sys/ksyms.h> | | 53 | #include <sys/ksyms.h> |
54 | #include <uvm/uvm_extern.h> | | 54 | #include <uvm/uvm_extern.h> |
55 | | | 55 | |
56 | #include <dev/ofw/openfirm.h> | | 56 | #include <dev/ofw/openfirm.h> |
57 | #include <dev/wscons/wsconsio.h> | | 57 | #include <dev/wscons/wsconsio.h> |
58 | #include <dev/wscons/wsdisplayvar.h> | | 58 | #include <dev/wscons/wsdisplayvar.h> |
59 | #include <dev/rasops/rasops.h> | | 59 | #include <dev/rasops/rasops.h> |
60 | #include <dev/wscons/wsdisplay_vconsvar.h> | | 60 | #include <dev/wscons/wsdisplay_vconsvar.h> |
61 | #include <machine/pmap.h> | | 61 | #include <machine/pmap.h> |
62 | #include <machine/powerpc.h> | | 62 | #include <machine/powerpc.h> |
63 | #include <machine/trap.h> | | 63 | #include <machine/trap.h> |
64 | #include <machine/vmparam.h> | | 64 | #include <machine/vmparam.h> |
65 | #include <machine/autoconf.h> | | 65 | #include <machine/autoconf.h> |
66 | #include <sys/bus.h> | | 66 | #include <sys/bus.h> |
67 | #include <powerpc/oea/bat.h> | | 67 | #include <powerpc/oea/bat.h> |
68 | #include <powerpc/oea/ofw_rasconsvar.h> | | 68 | #include <powerpc/oea/ofw_rasconsvar.h> |
69 | #include <powerpc/oea/cpufeat.h> | | 69 | #include <powerpc/oea/cpufeat.h> |
70 | #include <powerpc/include/oea/spr.h> | | 70 | #include <powerpc/include/oea/spr.h> |
71 | #include <powerpc/ofw_cons.h> | | 71 | #include <powerpc/ofw_cons.h> |
72 | #include <powerpc/spr.h> | | 72 | #include <powerpc/spr.h> |
73 | #include <powerpc/pic/picvar.h> | | 73 | #include <powerpc/pic/picvar.h> |
74 | | | 74 | |
75 | #ifdef DDB | | 75 | #ifdef DDB |
76 | #include <machine/db_machdep.h> | | 76 | #include <machine/db_machdep.h> |
77 | #include <ddb/db_extern.h> | | 77 | #include <ddb/db_extern.h> |
78 | #endif | | 78 | #endif |
79 | | | 79 | |
80 | #ifdef KGDB | | 80 | #ifdef KGDB |
81 | #include <sys/kgdb.h> | | 81 | #include <sys/kgdb.h> |
82 | #endif | | 82 | #endif |
83 | | | 83 | |
84 | #ifdef ofppc | | 84 | #ifdef ofppc |
85 | extern struct model_data modeldata; | | 85 | extern struct model_data modeldata; |
86 | #endif | | 86 | #endif |
87 | | | 87 | |
88 | #ifdef OFWOEA_DEBUG | | 88 | #ifdef OFWOEA_DEBUG |
89 | #define DPRINTF printf | | 89 | #define DPRINTF printf |
90 | #else | | 90 | #else |
91 | #define DPRINTF while (0) printf | | 91 | #define DPRINTF while (0) printf |
92 | #endif | | 92 | #endif |
93 | | | 93 | |
94 | typedef struct _rangemap { | | 94 | typedef struct _rangemap { |
95 | u_int32_t addr; | | 95 | u_int32_t addr; |
96 | u_int32_t size; | | 96 | u_int32_t size; |
97 | int type; | | 97 | int type; |
98 | } rangemap_t; | | 98 | } rangemap_t; |
99 | | | 99 | |
100 | struct ofw_translations { | | 100 | struct ofw_translations { |
101 | vaddr_t va; | | 101 | vaddr_t va; |
102 | int len; | | 102 | int len; |
103 | #if defined (PMAC_G5) | | 103 | #if defined (PMAC_G5) |
104 | register64_t pa; | | 104 | register64_t pa; |
105 | #else | | 105 | #else |
106 | register_t pa; | | 106 | register_t pa; |
107 | #endif | | 107 | #endif |
108 | int mode; | | 108 | int mode; |
109 | }__attribute__((packed)); | | 109 | }__attribute__((packed)); |
110 | | | 110 | |
111 | struct pmap ofw_pmap; | | 111 | struct pmap ofw_pmap; |
112 | struct ofw_translations ofmap[32]; | | 112 | struct ofw_translations ofmap[32]; |
113 | char bootpath[256]; | | 113 | char bootpath[256]; |
114 | char model_name[64]; | | 114 | char model_name[64]; |
115 | #if NKSYMS || defined(DDB) || defined(MODULAR) | | 115 | #if NKSYMS || defined(DDB) || defined(MODULAR) |
116 | void *startsym, *endsym; | | 116 | void *startsym, *endsym; |
117 | #endif | | 117 | #endif |
118 | | | 118 | |
119 | #if PPC_OEA601 | | 119 | #if PPC_OEA601 |
120 | #define TIMEBASE_FREQ (1000000000) /* RTC register */ | | 120 | #define TIMEBASE_FREQ (1000000000) /* RTC register */ |
121 | #endif | | 121 | #endif |
122 | | | 122 | |
123 | #ifdef TIMEBASE_FREQ | | 123 | #ifdef TIMEBASE_FREQ |
124 | u_int timebase_freq = TIMEBASE_FREQ; | | 124 | u_int timebase_freq = TIMEBASE_FREQ; |
125 | #else | | 125 | #else |
126 | u_int timebase_freq = 0; | | 126 | u_int timebase_freq = 0; |
127 | #endif | | 127 | #endif |
128 | | | 128 | |
129 | extern int ofwmsr; | | 129 | extern int ofwmsr; |
130 | extern int chosen; | | 130 | extern int chosen; |
131 | extern uint32_t ticks_per_sec; | | 131 | extern uint32_t ticks_per_sec; |
132 | extern uint32_t ns_per_tick; | | 132 | extern uint32_t ns_per_tick; |
133 | extern uint32_t ticks_per_intr; | | 133 | extern uint32_t ticks_per_intr; |
134 | | | 134 | |
135 | static int save_ofmap(struct ofw_translations *, int); | | 135 | static int save_ofmap(struct ofw_translations *, int); |
136 | static void restore_ofmap(struct ofw_translations *, int); | | 136 | static void restore_ofmap(struct ofw_translations *, int); |
137 | static void set_timebase(void); | | 137 | static void set_timebase(void); |
138 | | | 138 | |
139 | extern void cpu_spinstart(u_int); | | 139 | extern void cpu_spinstart(u_int); |
140 | extern volatile u_int cpu_spinstart_ack; | | 140 | extern volatile u_int cpu_spinstart_ack; |
141 | | | 141 | |
142 | void | | 142 | void |
143 | ofwoea_initppc(u_int startkernel, u_int endkernel, char *args) | | 143 | ofwoea_initppc(u_int startkernel, u_int endkernel, char *args) |
144 | { | | 144 | { |
145 | int ofmaplen, node, l; | | 145 | int ofmaplen, node, l; |
146 | register_t scratch; | | 146 | register_t scratch; |
147 | | | 147 | |
148 | #if defined(MULTIPROCESSOR) && defined(ofppc) | | 148 | #if defined(MULTIPROCESSOR) && defined(ofppc) |
149 | char cpupath[32]; | | 149 | char cpupath[32]; |
150 | int i; | | 150 | int i; |
151 | #endif | | 151 | #endif |
152 | | | 152 | |
153 | /* initialze bats */ | | 153 | /* initialze bats */ |
154 | if ((oeacpufeat & OEACPU_NOBAT) == 0) | | 154 | if ((oeacpufeat & OEACPU_NOBAT) == 0) |
155 | ofwoea_batinit(); | | 155 | ofwoea_batinit(); |
156 | | | 156 | |
157 | #if NKSYMS || defined(DDB) || defined(MODULAR) | | 157 | #if NKSYMS || defined(DDB) || defined(MODULAR) |
158 | /* get info of kernel symbol table from bootloader */ | | 158 | /* get info of kernel symbol table from bootloader */ |
159 | memcpy(&startsym, args + strlen(args) + 1, sizeof(startsym)); | | 159 | memcpy(&startsym, args + strlen(args) + 1, sizeof(startsym)); |
160 | memcpy(&endsym, args + strlen(args) + 1 + sizeof(startsym), | | 160 | memcpy(&endsym, args + strlen(args) + 1 + sizeof(startsym), |
161 | sizeof(endsym)); | | 161 | sizeof(endsym)); |
162 | if (startsym == NULL || endsym == NULL) | | 162 | if (startsym == NULL || endsym == NULL) |
163 | startsym = endsym = NULL; | | 163 | startsym = endsym = NULL; |
164 | #endif | | 164 | #endif |
165 | | | 165 | |
166 | /* get model name and perform model-specific actions */ | | 166 | /* get model name and perform model-specific actions */ |
167 | memset(model_name, 0, sizeof(model_name)); | | 167 | memset(model_name, 0, sizeof(model_name)); |
168 | node = OF_finddevice("/"); | | 168 | node = OF_finddevice("/"); |
169 | if (node != -1) { | | 169 | if (node != -1) { |
170 | l = OF_getprop(node, "model", model_name, sizeof(model_name)); | | 170 | l = OF_getprop(node, "model", model_name, sizeof(model_name)); |
171 | if (l == -1) | | 171 | if (l == -1) |
172 | OF_getprop(node, "name", model_name, | | 172 | OF_getprop(node, "name", model_name, |
173 | sizeof(model_name)); | | 173 | sizeof(model_name)); |
174 | model_init(); | | 174 | model_init(); |
175 | } | | 175 | } |
176 | | | 176 | |
177 | if (strncmp(model_name, "PowerMac11,2", 12) == 0 || | | 177 | if (strncmp(model_name, "PowerMac11,2", 12) == 0 || |
178 | strncmp(model_name, "PowerMac12,1", 12) == 0) | | 178 | strncmp(model_name, "PowerMac12,1", 12) == 0) |
179 | OF_quiesce(); | | 179 | OF_quiesce(); |
180 | | | 180 | |
181 | /* switch CPUs to full speed */ | | 181 | /* switch CPUs to full speed */ |
182 | if (strncmp(model_name, "PowerMac7,", 10) == 0) { | | 182 | if (strncmp(model_name, "PowerMac7,", 10) == 0) { |
183 | int clock_ih = OF_open("/u3/i2c/i2c-hwclock"); | | 183 | int clock_ih = OF_open("/u3/i2c/i2c-hwclock"); |
184 | if (clock_ih != 0) { | | 184 | if (clock_ih != 0) { |
185 | OF_call_method_1("slew-high", clock_ih, 0); | | 185 | OF_call_method_1("slew-high", clock_ih, 0); |
186 | } | | 186 | } |
187 | } | | 187 | } |
188 | | | 188 | |
189 | /* Initialize bus_space */ | | 189 | /* Initialize bus_space */ |
190 | ofwoea_bus_space_init(); | | 190 | ofwoea_bus_space_init(); |
191 | | | 191 | |
192 | ofwoea_consinit(); | | 192 | ofwoea_consinit(); |
193 | | | 193 | |
194 | #if defined(MULTIPROCESSOR) && defined(ofppc) | | 194 | #if defined(MULTIPROCESSOR) && defined(ofppc) |
195 | for (i=1; i < CPU_MAXNUM; i++) { | | 195 | for (i=1; i < CPU_MAXNUM; i++) { |
196 | snprintf(cpupath, sizeof(cpupath), "/cpus/@%x", i); | | 196 | snprintf(cpupath, sizeof(cpupath), "/cpus/@%x", i); |
197 | node = OF_finddevice(cpupath); | | 197 | node = OF_finddevice(cpupath); |
198 | if (node <= 0) | | 198 | if (node <= 0) |
199 | continue; | | 199 | continue; |
200 | aprint_verbose("Starting up CPU %d %s\n", i, cpupath); | | 200 | aprint_verbose("Starting up CPU %d %s\n", i, cpupath); |
201 | OF_start_cpu(node, (u_int)cpu_spinstart, i); | | 201 | OF_start_cpu(node, (u_int)cpu_spinstart, i); |
202 | for (l=0; l < 100000000; l++) { | | 202 | for (l=0; l < 100000000; l++) { |
203 | if (cpu_spinstart_ack == i) { | | 203 | if (cpu_spinstart_ack == i) { |
204 | aprint_verbose("CPU %d spun up.\n", i); | | 204 | aprint_verbose("CPU %d spun up.\n", i); |
205 | break; | | 205 | break; |
206 | } | | 206 | } |
207 | __asm volatile ("sync"); | | 207 | __asm volatile ("sync"); |
208 | } | | 208 | } |
209 | } | | 209 | } |
210 | #endif | | 210 | #endif |
211 | | | 211 | |
212 | oea_init(pic_ext_intr); | | 212 | oea_init(pic_ext_intr); |
213 | | | 213 | |
214 | ofmaplen = save_ofmap(NULL, 0); | | 214 | ofmaplen = save_ofmap(NULL, 0); |
215 | if (ofmaplen > 0) | | 215 | if (ofmaplen > 0) |
216 | save_ofmap(ofmap, ofmaplen); | | 216 | save_ofmap(ofmap, ofmaplen); |
217 | | | 217 | |
218 | /* | | 218 | /* |
219 | * XXX | | 219 | * XXX |
220 | * we need to do this here instead of earlier on in ofwinit() for some reason | | 220 | * we need to do this here instead of earlier on in ofwinit() for some reason |
221 | * At least some versions of Apple OF 2.0.1 hang if we do this earlier | | 221 | * At least some versions of Apple OF 2.0.1 hang if we do this earlier |
222 | */ | | 222 | */ |
223 | ofwmsr &= ~PSL_IP; | | 223 | ofwmsr &= ~PSL_IP; |
224 | | | 224 | |
225 | /* Parse the args string */ | | 225 | /* Parse the args string */ |
226 | if (args) { | | 226 | if (args) { |
227 | strcpy(bootpath, args); | | 227 | strcpy(bootpath, args); |
228 | args = bootpath; | | 228 | args = bootpath; |
229 | while (*++args && *args != ' '); | | 229 | while (*++args && *args != ' '); |
230 | if (*args) { | | 230 | if (*args) { |
231 | *args++ = 0; | | 231 | *args++ = 0; |
232 | while (*args) | | 232 | while (*args) |
233 | BOOT_FLAG(*args++, boothowto); | | 233 | BOOT_FLAG(*args++, boothowto); |
234 | } | | 234 | } |
235 | } else { | | 235 | } else { |
236 | int chs = OF_finddevice("/chosen"); | | 236 | int chs = OF_finddevice("/chosen"); |
237 | int len; | | 237 | int len; |
238 | | | 238 | |
239 | len = OF_getprop(chs, "bootpath", bootpath, sizeof(bootpath) - 1); | | 239 | len = OF_getprop(chs, "bootpath", bootpath, sizeof(bootpath) - 1); |
240 | if (len > -1) | | 240 | if (len > -1) |
241 | bootpath[len] = 0; | | 241 | bootpath[len] = 0; |
242 | } | | 242 | } |
243 | | | 243 | |
244 | uvm_md_init(); | | 244 | uvm_md_init(); |
245 | | | 245 | |
246 | pmap_bootstrap(startkernel, endkernel); | | 246 | pmap_bootstrap(startkernel, endkernel); |
247 | | | 247 | |
248 | /* as far as I can tell, the pmap_setup_seg0 stuff is horribly broken */ | | 248 | /* as far as I can tell, the pmap_setup_seg0 stuff is horribly broken */ |
249 | #if defined(PPC_OEA64) || defined (PPC_OEA64_BRIDGE) | | 249 | #if defined(PPC_OEA64) || defined (PPC_OEA64_BRIDGE) |
250 | #if defined (PMAC_G5) | | 250 | #if defined (PMAC_G5) |
251 | /* Mapin 1st 256MB segment 1:1, also map in mem needed to access OFW*/ | | 251 | /* Mapin 1st 256MB segment 1:1, also map in mem needed to access OFW*/ |
252 | if (oeacpufeat & OEACPU_64_BRIDGE) { | | 252 | if (oeacpufeat & OEACPU_64_BRIDGE) { |
253 | vaddr_t va; | | 253 | vaddr_t va; |
254 | paddr_t pa; | | 254 | paddr_t pa; |
255 | int i; | | 255 | int i; |
256 | | | 256 | |
257 | pmap_setup_segment0_map(0, msgbuf_paddr, msgbuf_paddr, | | 257 | pmap_setup_segment0_map(0, msgbuf_paddr, msgbuf_paddr, |
258 | round_page(MSGBUFSIZE), 0x0); | | 258 | round_page(MSGBUFSIZE), 0x0); |
259 | | | 259 | |
260 | /* Map OFW code+data */ | | 260 | /* Map OFW code+data */ |
261 | | | 261 | |
262 | for (i = 0; i < ofmaplen / sizeof(struct ofw_translations); i++) { | | 262 | for (i = 0; i < ofmaplen / sizeof(struct ofw_translations); i++) { |
263 | if (ofmap[i].va < 0xff800000) | | 263 | if (ofmap[i].va < 0xff800000) |
264 | continue; | | 264 | continue; |
265 | | | 265 | |
266 | for (va = ofmap[i].va, pa = ofmap[i].pa; | | 266 | for (va = ofmap[i].va, pa = ofmap[i].pa; |
267 | va < ofmap[i].va + ofmap[i].len; | | 267 | va < ofmap[i].va + ofmap[i].len; |
268 | va += PAGE_SIZE, pa += PAGE_SIZE) { | | 268 | va += PAGE_SIZE, pa += PAGE_SIZE) { |
269 | pmap_enter(pmap_kernel(), va, pa, VM_PROT_ALL, | | 269 | pmap_enter(pmap_kernel(), va, pa, VM_PROT_ALL, |
270 | VM_PROT_ALL | PMAP_WIRED); | | 270 | VM_PROT_ALL | PMAP_WIRED); |
271 | } | | 271 | } |
272 | } | | 272 | } |
273 | | | 273 | |
274 | #if NWSDISPLAY > 0 | | 274 | #if NWSDISPLAY > 0 |
275 | /* Map video frame buffer */ | | 275 | /* Map video frame buffer */ |
276 | | | 276 | |
277 | struct rasops_info *ri = &rascons_console_screen.scr_ri; | | 277 | struct rasops_info *ri = &rascons_console_screen.scr_ri; |
278 | | | 278 | |
279 | if (ri->ri_bits != NULL) { | | 279 | if (ri->ri_bits != NULL) { |
280 | for (va = (vaddr_t) ri->ri_bits; | | 280 | for (va = (vaddr_t) ri->ri_bits; |
281 | va < round_page((vaddr_t) ri->ri_bits + | | 281 | va < round_page((vaddr_t) ri->ri_bits + |
282 | ri->ri_height * ri->ri_stride); | | 282 | ri->ri_height * ri->ri_stride); |
283 | va += PAGE_SIZE) { | | 283 | va += PAGE_SIZE) { |
284 | pmap_enter(pmap_kernel(), va, va, | | 284 | pmap_enter(pmap_kernel(), va, va, |
285 | VM_PROT_READ | VM_PROT_WRITE, | | 285 | VM_PROT_READ | VM_PROT_WRITE, |
286 | PMAP_NOCACHE | PMAP_WIRED); | | 286 | PMAP_NOCACHE | PMAP_WIRED); |
287 | } | | 287 | } |
288 | } | | 288 | } |
289 | #endif | | 289 | #endif |
290 | } | | 290 | } |
291 | #elif defined (MAMBO) | | 291 | #elif defined (MAMBO) |
292 | /* Mapin 1st 256MB segment 1:1, also map in mem needed to access OFW*/ | | 292 | /* Mapin 1st 256MB segment 1:1, also map in mem needed to access OFW*/ |
293 | if (oeacpufeat & OEACPU_64_BRIDGE) | | 293 | if (oeacpufeat & OEACPU_64_BRIDGE) |
294 | pmap_setup_segment0_map(0, 0xf4000000, 0xf4000000, 0x1000, 0x0); | | 294 | pmap_setup_segment0_map(0, 0xf4000000, 0xf4000000, 0x1000, 0x0); |
295 | #endif /* PMAC_G5 */ | | 295 | #endif /* PMAC_G5 */ |
296 | #endif /* PPC_OEA64 || PPC_OEA64_BRIDGE */ | | 296 | #endif /* PPC_OEA64 || PPC_OEA64_BRIDGE */ |
297 | | | 297 | |
298 | /* Now enable translation (and machine checks/recoverable interrupts) */ | | 298 | /* Now enable translation (and machine checks/recoverable interrupts) */ |
299 | __asm __volatile ("sync; mfmsr %0; ori %0,%0,%1; mtmsr %0; isync" | | 299 | __asm __volatile ("sync; mfmsr %0; ori %0,%0,%1; mtmsr %0; isync" |
300 | : "=r"(scratch) | | 300 | : "=r"(scratch) |
301 | : "K"(PSL_IR|PSL_DR|PSL_ME|PSL_RI)); | | 301 | : "K"(PSL_IR|PSL_DR|PSL_ME|PSL_RI)); |
302 | | | 302 | |
303 | restore_ofmap(ofmap, ofmaplen); | | 303 | restore_ofmap(ofmap, ofmaplen); |
304 | | | 304 | |
305 | rascons_finalize(); | | 305 | rascons_finalize(); |
306 | | | 306 | |
307 | #if NKSYMS || defined(DDB) || defined(MODULAR) | | 307 | #if NKSYMS || defined(DDB) || defined(MODULAR) |
308 | ksyms_addsyms_elf((int)((uintptr_t)endsym - (uintptr_t)startsym), startsym, endsym); | | 308 | ksyms_addsyms_elf((int)((uintptr_t)endsym - (uintptr_t)startsym), startsym, endsym); |
309 | #endif | | 309 | #endif |
310 | | | 310 | |
311 | /* CPU clock stuff */ | | 311 | /* CPU clock stuff */ |
312 | set_timebase(); | | 312 | set_timebase(); |
313 | | | 313 | |
314 | #ifdef DDB | | 314 | #ifdef DDB |
315 | if (boothowto & RB_KDB) | | 315 | if (boothowto & RB_KDB) |
316 | Debugger(); | | 316 | Debugger(); |
317 | #endif | | 317 | #endif |
318 | } | | 318 | } |
319 | | | 319 | |
320 | void | | 320 | void |
321 | set_timebase(void) | | 321 | set_timebase(void) |
322 | { | | 322 | { |
323 | int qhandle, phandle, msr, scratch, node; | | 323 | int qhandle, phandle, msr, scratch, node; |
324 | char type[32]; | | 324 | char type[32]; |
325 | | | 325 | |
326 | if (timebase_freq != 0) { | | 326 | if (timebase_freq != 0) { |
327 | ticks_per_sec = timebase_freq; | | 327 | ticks_per_sec = timebase_freq; |
328 | goto found; | | 328 | goto found; |
329 | } | | 329 | } |
330 | | | 330 | |
331 | node = OF_finddevice("/cpus/@0"); | | 331 | node = OF_finddevice("/cpus/@0"); |
332 | if (node != -1 && | | 332 | if (node != -1 && |
333 | OF_getprop(node, "timebase-frequency", &ticks_per_sec, | | 333 | OF_getprop(node, "timebase-frequency", &ticks_per_sec, |
334 | sizeof ticks_per_sec) > 0) { | | 334 | sizeof ticks_per_sec) > 0) { |
335 | goto found; | | 335 | goto found; |
336 | } | | 336 | } |
337 | | | 337 | |
338 | node = OF_finddevice("/"); | | 338 | node = OF_finddevice("/"); |
339 | for (qhandle = node; qhandle; qhandle = phandle) { | | 339 | for (qhandle = node; qhandle; qhandle = phandle) { |
340 | if (OF_getprop(qhandle, "device_type", type, sizeof type) > 0 | | 340 | if (OF_getprop(qhandle, "device_type", type, sizeof type) > 0 |
341 | && strcmp(type, "cpu") == 0 | | 341 | && strcmp(type, "cpu") == 0 |
342 | && OF_getprop(qhandle, "timebase-frequency", | | 342 | && OF_getprop(qhandle, "timebase-frequency", |
343 | &ticks_per_sec, sizeof ticks_per_sec) > 0) { | | 343 | &ticks_per_sec, sizeof ticks_per_sec) > 0) { |
344 | goto found; | | 344 | goto found; |
345 | } | | 345 | } |
346 | if ((phandle = OF_child(qhandle))) | | 346 | if ((phandle = OF_child(qhandle))) |
347 | continue; | | 347 | continue; |
348 | while (qhandle) { | | 348 | while (qhandle) { |
349 | if ((phandle = OF_peer(qhandle))) | | 349 | if ((phandle = OF_peer(qhandle))) |
350 | break; | | 350 | break; |
351 | qhandle = OF_parent(qhandle); | | 351 | qhandle = OF_parent(qhandle); |
352 | } | | 352 | } |
353 | } | | 353 | } |
354 | panic("no cpu node"); | | 354 | panic("no cpu node"); |
355 | | | 355 | |
356 | found: | | 356 | found: |
357 | __asm volatile ("mfmsr %0; andi. %1,%0,%2; mtmsr %1" | | 357 | __asm volatile ("mfmsr %0; andi. %1,%0,%2; mtmsr %1" |
358 | : "=r"(msr), "=r"(scratch) : "K"((u_short)~PSL_EE)); | | 358 | : "=r"(msr), "=r"(scratch) : "K"((u_short)~PSL_EE)); |
359 | ns_per_tick = 1000000000 / ticks_per_sec; | | 359 | ns_per_tick = 1000000000 / ticks_per_sec; |
360 | ticks_per_intr = ticks_per_sec / hz; | | 360 | ticks_per_intr = ticks_per_sec / hz; |
361 | cpu_timebase = ticks_per_sec; | | 361 | cpu_timebase = ticks_per_sec; |
362 | | | 362 | |
363 | #ifdef PPC_OEA601 | | 363 | #ifdef PPC_OEA601 |
364 | if ((mfpvr() >> 16) == MPC601) | | 364 | if ((mfpvr() >> 16) == MPC601) |
365 | curcpu()->ci_lasttb = rtc_nanosecs(); | | 365 | curcpu()->ci_lasttb = rtc_nanosecs(); |
366 | else | | 366 | else |
367 | #endif | | 367 | #endif |
368 | curcpu()->ci_lasttb = mftbl(); | | 368 | curcpu()->ci_lasttb = mftbl(); |
369 | | | 369 | |
370 | mtspr(SPR_DEC, ticks_per_intr); | | 370 | mtspr(SPR_DEC, ticks_per_intr); |
371 | mtmsr(msr); | | 371 | mtmsr(msr); |
372 | } | | 372 | } |
373 | | | 373 | |
374 | static int | | 374 | static int |
375 | save_ofmap(struct ofw_translations *map, int maxlen) | | 375 | save_ofmap(struct ofw_translations *map, int maxlen) |
376 | { | | 376 | { |
377 | int mmui, mmu, len; | | 377 | int mmui, mmu, len; |
378 | | | 378 | |
379 | OF_getprop(chosen, "mmu", &mmui, sizeof mmui); | | 379 | OF_getprop(chosen, "mmu", &mmui, sizeof mmui); |
380 | mmu = OF_instance_to_package(mmui); | | 380 | mmu = OF_instance_to_package(mmui); |
381 | | | 381 | |
382 | if (map) { | | 382 | if (map) { |
383 | memset(map, 0, maxlen); /* to be safe */ | | 383 | memset(map, 0, maxlen); /* to be safe */ |
384 | len = OF_getprop(mmu, "translations", map, maxlen); | | 384 | len = OF_getprop(mmu, "translations", map, maxlen); |
385 | } else | | 385 | } else |
386 | len = OF_getproplen(mmu, "translations"); | | 386 | len = OF_getproplen(mmu, "translations"); |
387 | | | 387 | |
388 | if (len < 0) | | 388 | if (len < 0) |
389 | len = 0; | | 389 | len = 0; |
390 | return len; | | 390 | return len; |
391 | } | | 391 | } |
392 | | | 392 | |
393 | | | 393 | |
394 | /* The PMAC_G5 code here needs to be replaced by code that looks for the | | 394 | /* The PMAC_G5 code here needs to be replaced by code that looks for the |
395 | size_cells and does the right thing automatically. | | 395 | size_cells and does the right thing automatically. |
396 | */ | | 396 | */ |
397 | void | | 397 | void |
398 | restore_ofmap(struct ofw_translations *map, int len) | | 398 | restore_ofmap(struct ofw_translations *map, int len) |
399 | { | | 399 | { |
400 | int n = len / sizeof(struct ofw_translations); | | 400 | int n = len / sizeof(struct ofw_translations); |
401 | int i; | | 401 | int i; |
402 | | | 402 | |
403 | pmap_pinit(&ofw_pmap); | | 403 | pmap_pinit(&ofw_pmap); |
404 | | | 404 | |
405 | #ifndef _LP64 | | 405 | #ifndef _LP64 |
406 | ofw_pmap.pm_sr[0] = KERNELN_SEGMENT(0)|SR_PRKEY; | | 406 | ofw_pmap.pm_sr[0] = KERNELN_SEGMENT(0)|SR_PRKEY; |
407 | ofw_pmap.pm_sr[KERNEL_SR] = KERNEL_SEGMENT|SR_SUKEY|SR_PRKEY; | | 407 | ofw_pmap.pm_sr[KERNEL_SR] = KERNEL_SEGMENT|SR_SUKEY|SR_PRKEY; |
408 | | | 408 | |
409 | #ifdef KERNEL2_SR | | 409 | #ifdef KERNEL2_SR |
410 | ofw_pmap.pm_sr[KERNEL2_SR] = KERNEL2_SEGMENT|SR_SUKEY|SR_PRKEY; | | 410 | ofw_pmap.pm_sr[KERNEL2_SR] = KERNEL2_SEGMENT|SR_SUKEY|SR_PRKEY; |
411 | #endif | | 411 | #endif |
412 | #endif | | 412 | #endif |
413 | | | 413 | |
414 | for (i = 0; i < n; i++) { | | 414 | for (i = 0; i < n; i++) { |
415 | #if defined (PMAC_G5) | | 415 | #if defined (PMAC_G5) |
416 | register64_t pa = map[i].pa; | | 416 | register64_t pa = map[i].pa; |
417 | #else | | 417 | #else |
418 | register_t pa = map[i].pa; | | 418 | register_t pa = map[i].pa; |
419 | #endif | | 419 | #endif |
420 | vaddr_t va = map[i].va; | | 420 | vaddr_t va = map[i].va; |
421 | size_t length = map[i].len; | | 421 | size_t length = map[i].len; |
422 | | | 422 | |
423 | if (va < 0xf0000000) /* XXX */ | | 423 | if (va < 0xf0000000) /* XXX */ |
424 | continue; | | 424 | continue; |
425 | | | 425 | |
426 | while (length > 0) { | | 426 | while (length > 0) { |
427 | pmap_enter(&ofw_pmap, va, (paddr_t)pa, VM_PROT_ALL, | | 427 | pmap_enter(&ofw_pmap, va, (paddr_t)pa, VM_PROT_ALL, |
428 | VM_PROT_ALL|PMAP_WIRED); | | 428 | VM_PROT_ALL|PMAP_WIRED); |
429 | pa += PAGE_SIZE; | | 429 | pa += PAGE_SIZE; |
430 | va += PAGE_SIZE; | | 430 | va += PAGE_SIZE; |
431 | length -= PAGE_SIZE; | | 431 | length -= PAGE_SIZE; |
432 | } | | 432 | } |
433 | } | | 433 | } |
434 | pmap_update(&ofw_pmap); | | 434 | pmap_update(&ofw_pmap); |
435 | } | | 435 | } |
436 | | | 436 | |
437 | | | 437 | |
438 | | | 438 | |
439 | /* | | 439 | /* |
440 | * Scan the device tree for ranges, and return them as bitmap 0..15 | | 440 | * Scan the device tree for ranges, and return them as bitmap 0..15 |
441 | */ | | 441 | */ |
442 | #if !defined(macppc) && defined(PPC_OEA) | | 442 | #if !defined(macppc) && defined(PPC_OEA) |
443 | static u_int16_t | | 443 | static u_int16_t |
444 | ranges_bitmap(int node, u_int16_t bitmap) | | 444 | ranges_bitmap(int node, u_int16_t bitmap) |
445 | { | | 445 | { |
446 | int child, mlen, acells, scells, reclen, i, j; | | 446 | int child, mlen, acells, scells, reclen, i, j; |
447 | u_int32_t addr, len, map[160]; | | 447 | u_int32_t addr, len, map[160]; |
448 | | | 448 | |
449 | for (child = OF_child(node); child; child = OF_peer(child)) { | | 449 | for (child = OF_child(node); child; child = OF_peer(child)) { |
450 | mlen = OF_getprop(child, "ranges", map, sizeof(map)); | | 450 | mlen = OF_getprop(child, "ranges", map, sizeof(map)); |
451 | if (mlen == -1) | | 451 | if (mlen == -1) |
452 | goto noranges; | | 452 | goto noranges; |
453 | | | 453 | |
454 | j = OF_getprop(child, "#address-cells", &acells, | | 454 | j = OF_getprop(child, "#address-cells", &acells, |
455 | sizeof(acells)); | | 455 | sizeof(acells)); |
456 | if (j == -1) | | 456 | if (j == -1) |
457 | goto noranges; | | 457 | goto noranges; |
458 | | | 458 | |
459 | j = OF_getprop(child, "#size-cells", &scells, | | 459 | j = OF_getprop(child, "#size-cells", &scells, |
460 | sizeof(scells)); | | 460 | sizeof(scells)); |
461 | if (j == -1) | | 461 | if (j == -1) |
462 | goto noranges; | | 462 | goto noranges; |
463 | | | 463 | |
464 | #ifdef ofppc | | 464 | #ifdef ofppc |
465 | reclen = acells + modeldata.ranges_offset + scells; | | 465 | reclen = acells + modeldata.ranges_offset + scells; |
466 | #else | | 466 | #else |
467 | reclen = acells + 1 + scells; | | 467 | reclen = acells + 1 + scells; |
468 | #endif | | 468 | #endif |
469 | | | 469 | |
470 | for (i=0; i < (mlen/4)/reclen; i++) { | | 470 | for (i=0; i < (mlen/4)/reclen; i++) { |
471 | addr = map[reclen * i + acells]; | | 471 | addr = map[reclen * i + acells]; |
472 | len = map[reclen * i + reclen - 1]; | | 472 | len = map[reclen * i + reclen - 1]; |
473 | for (j = 0; j < len / 0x10000000; j++) | | 473 | for (j = 0; j < len / 0x10000000; j++) |
474 | bitmap |= 1 << ((addr+j*0x10000000) >>28); | | 474 | bitmap |= 1 << ((addr+j*0x10000000) >>28); |
475 | bitmap |= 1 << (addr >> 28); | | 475 | bitmap |= 1 << (addr >> 28); |
476 | } | | 476 | } |
477 | noranges: | | 477 | noranges: |
478 | bitmap |= ranges_bitmap(child, bitmap); | | 478 | bitmap |= ranges_bitmap(child, bitmap); |
479 | continue; | | 479 | continue; |
480 | } | | 480 | } |
481 | return bitmap; | | 481 | return bitmap; |
482 | } | | 482 | } |
483 | #endif /* !macppc && PPC_OEA */ | | 483 | #endif /* !macppc && PPC_OEA */ |
484 | | | 484 | |
485 | void | | 485 | void |
486 | ofwoea_batinit(void) | | 486 | ofwoea_batinit(void) |
487 | { | | 487 | { |
488 | #if defined (PPC_OEA) | | 488 | #if defined (PPC_OEA) |
489 | | | 489 | |
490 | #ifdef macppc | | 490 | #ifdef macppc |
491 | /* | | 491 | /* |
492 | * cover PCI and register space but not the firmware ROM | | 492 | * cover PCI and register space but not the firmware ROM |
493 | */ | | 493 | */ |
494 | #ifdef PPC_OEA601 | | 494 | #ifdef PPC_OEA601 |
495 | | | 495 | |
496 | /* | | 496 | /* |
497 | * use segment registers for the 601 | | 497 | * use segment registers for the 601 |
498 | */ | | 498 | */ |
499 | if ((mfpvr() >> 16 ) == MPC601) | | 499 | if ((mfpvr() >> 16 ) == MPC601) |
500 | oea_batinit( | | 500 | oea_batinit( |
501 | 0x80000000, BAT_BL_256M, | | 501 | 0x80000000, BAT_BL_256M, |
502 | 0x90000000, BAT_BL_256M, | | 502 | 0x90000000, BAT_BL_256M, |
503 | 0xa0000000, BAT_BL_256M, | | 503 | 0xa0000000, BAT_BL_256M, |
504 | 0xb0000000, BAT_BL_256M, | | 504 | 0xb0000000, BAT_BL_256M, |
505 | 0xf0000000, BAT_BL_256M, | | 505 | 0xf0000000, BAT_BL_256M, |
506 | 0); | | 506 | 0); |
507 | else | | 507 | else |
508 | #endif | | 508 | #endif |
509 | /* | | 509 | /* |
510 | * map to bats | | 510 | * map to bats |
511 | */ | | 511 | */ |
512 | oea_batinit(0x80000000, BAT_BL_1G, | | 512 | oea_batinit(0x80000000, BAT_BL_1G, |
513 | 0xf0000000, BAT_BL_128M, | | 513 | 0xf0000000, BAT_BL_128M, |
514 | 0xf8000000, BAT_BL_64M, | | 514 | 0xf8000000, BAT_BL_64M, |
515 | 0xfe000000, BAT_BL_8M, /* Grackle IO */ | | 515 | 0xfe000000, BAT_BL_8M, /* Grackle IO */ |
516 | 0); | | 516 | 0); |
517 | #else | | 517 | #else |
518 | uint16_t bitmap; | | 518 | uint16_t bitmap; |
519 | int node, i; | | 519 | int node, i; |
520 | | | 520 | |
521 | node = OF_finddevice("/"); | | 521 | node = OF_finddevice("/"); |
522 | | | 522 | |
523 | bitmap = ranges_bitmap(node, 0); | | 523 | bitmap = ranges_bitmap(node, 0); |
524 | oea_batinit(0); | | 524 | oea_batinit(0); |
525 | | | 525 | |
526 | for (i=1; i < 0x10; i++) { | | 526 | for (i=1; i < 0x10; i++) { |
527 | /* skip the three vital SR regions */ | | 527 | /* skip the three vital SR regions */ |
528 | if (i == USER_SR || i == KERNEL_SR || i == KERNEL2_SR) | | 528 | if (i == USER_SR || i == KERNEL_SR || i == KERNEL2_SR) |
529 | continue; | | 529 | continue; |
530 | if (bitmap & (1 << i)) { | | 530 | if (bitmap & (1 << i)) { |
531 | oea_iobat_add(0x10000000 * i, BAT_BL_256M); | | 531 | oea_iobat_add(0x10000000 * i, BAT_BL_256M); |
532 | DPRINTF("Batmapped 256M at 0x%x\n", 0x10000000 * i); | | 532 | DPRINTF("Batmapped 256M at 0x%x\n", 0x10000000 * i); |
533 | } | | 533 | } |
534 | } | | 534 | } |
535 | #endif | | 535 | #endif |
536 | #endif /* OEA */ | | 536 | #endif /* OEA */ |
537 | } | | 537 | } |
538 | | | 538 | |
539 | | | 539 | |
540 | /* we define these partially, as we will fill the rest in later */ | | 540 | /* we define these partially, as we will fill the rest in later */ |
541 | struct powerpc_bus_space genppc_isa_io_space_tag = { | | 541 | struct powerpc_bus_space genppc_isa_io_space_tag = { |
542 | .pbs_flags = _BUS_SPACE_LITTLE_ENDIAN|_BUS_SPACE_IO_TYPE, | | 542 | .pbs_flags = _BUS_SPACE_LITTLE_ENDIAN|_BUS_SPACE_IO_TYPE, |
543 | .pbs_base = 0x00000000, | | 543 | .pbs_base = 0x00000000, |
544 | }; | | 544 | }; |
545 | | | 545 | |
546 | struct powerpc_bus_space genppc_isa_mem_space_tag = { | | 546 | struct powerpc_bus_space genppc_isa_mem_space_tag = { |
547 | .pbs_flags = _BUS_SPACE_LITTLE_ENDIAN|_BUS_SPACE_MEM_TYPE, | | 547 | .pbs_flags = _BUS_SPACE_LITTLE_ENDIAN|_BUS_SPACE_MEM_TYPE, |
548 | .pbs_base = 0x00000000, | | 548 | .pbs_base = 0x00000000, |
549 | }; | | 549 | }; |
550 | | | 550 | |
551 | /* This gives us a maximum of 6 PCI busses, assuming both io/mem on each. | | 551 | /* This gives us a maximum of 6 PCI busses, assuming both io/mem on each. |
552 | * Increase if necc. | | 552 | * Increase if necc. |
553 | */ | | 553 | */ |
554 | static char ex_storage[EXSTORAGE_MAX][EXTENT_FIXED_STORAGE_SIZE(EXTMAP_RANGES)] | | 554 | static char ex_storage[EXSTORAGE_MAX][EXTENT_FIXED_STORAGE_SIZE(EXTMAP_RANGES)] |
555 | __attribute__((aligned(8))); | | 555 | __attribute__((aligned(8))); |
556 | | | 556 | |
557 | | | 557 | |
558 | static void | | 558 | static void |
559 | find_ranges(int base, rangemap_t *regions, int *cur, int type) | | 559 | find_ranges(int base, rangemap_t *regions, int *cur, int type) |
560 | { | | 560 | { |
561 | int node, i, len, reclen; | | 561 | int node, i, len, reclen; |
562 | u_int32_t parent_acells, acells, scells, map[160]; | | 562 | u_int32_t parent_acells, acells, scells, map[160]; |
563 | char tmp[32]; | | 563 | char tmp[32]; |
564 | | | 564 | |
565 | node = base; | | 565 | node = base; |
566 | if (OF_getprop(node, "device_type", tmp, sizeof(tmp)) == -1) | | 566 | if (OF_getprop(node, "device_type", tmp, sizeof(tmp)) == -1) |
567 | goto rec; | | 567 | goto rec; |
568 | if ((type == RANGE_TYPE_PCI || type == RANGE_TYPE_FIRSTPCI) && | | 568 | if ((type == RANGE_TYPE_PCI || type == RANGE_TYPE_FIRSTPCI) && |
569 | strcmp("pci", tmp) != 0) | | 569 | strcmp("pci", tmp) != 0) |
570 | goto rec; | | 570 | goto rec; |
571 | if (type == RANGE_TYPE_ISA && strcmp("isa", tmp) != 0) | | 571 | if (type == RANGE_TYPE_ISA && strcmp("isa", tmp) != 0) |
572 | goto rec; | | 572 | goto rec; |
573 | if (type == RANGE_TYPE_MACIO && strcmp("memory-controller", tmp) == 0) { | | 573 | if (type == RANGE_TYPE_MACIO && strcmp("memory-controller", tmp) == 0) { |
574 | len = OF_getprop(node, "reg", map, sizeof(map)); | | 574 | len = OF_getprop(node, "reg", map, sizeof(map)); |
575 | acells = 1; | | 575 | acells = 1; |
576 | scells = 1; | | 576 | scells = 1; |
577 | } else { | | 577 | } else { |
578 | len = OF_getprop(node, "ranges", map, sizeof(map)); | | 578 | len = OF_getprop(node, "ranges", map, sizeof(map)); |
579 | } | | 579 | } |
580 | if (len == -1) | | 580 | if (len == -1) |
581 | goto rec; | | 581 | goto rec; |
582 | if (OF_getprop(OF_parent(node), "#address-cells", &parent_acells, | | 582 | if (OF_getprop(OF_parent(node), "#address-cells", &parent_acells, |
583 | sizeof(parent_acells)) != sizeof(parent_acells)) | | 583 | sizeof(parent_acells)) != sizeof(parent_acells)) |
584 | parent_acells = 1; | | 584 | parent_acells = 1; |
585 | if (OF_getprop(node, "#address-cells", &acells, | | 585 | if (OF_getprop(node, "#address-cells", &acells, |
586 | sizeof(acells)) != sizeof(acells)) | | 586 | sizeof(acells)) != sizeof(acells)) |
587 | acells = 3; | | 587 | acells = 3; |
588 | if (OF_getprop(node, "#size-cells", &scells, | | 588 | if (OF_getprop(node, "#size-cells", &scells, |
589 | sizeof(scells)) != sizeof(scells)) | | 589 | sizeof(scells)) != sizeof(scells)) |
590 | scells = 2; | | 590 | scells = 2; |
591 | #ifdef ofppc | | 591 | #ifdef ofppc |
592 | if (modeldata.ranges_offset == 0) | | 592 | if (modeldata.ranges_offset == 0) |
593 | scells -= 1; | | 593 | scells -= 1; |
594 | #endif | | 594 | #endif |
595 | if (type == RANGE_TYPE_ISA) | | 595 | if (type == RANGE_TYPE_ISA) |
596 | reclen = 6; | | 596 | reclen = 6; |
597 | else | | 597 | else |
598 | reclen = parent_acells + acells + scells; | | 598 | reclen = parent_acells + acells + scells; |
599 | /* | | 599 | /* |
600 | * There exist ISA buses with empty ranges properties. This is | | 600 | * There exist ISA buses with empty ranges properties. This is |
601 | * known to occur on the Pegasos II machine, and likely others. | | 601 | * known to occur on the Pegasos II machine, and likely others. |
602 | * According to them, that means that the isa bus is a fake bus, and | | 602 | * According to them, that means that the isa bus is a fake bus, and |
603 | * the real maps are the PCI maps of the preceeding bus. To deal | | 603 | * the real maps are the PCI maps of the preceeding bus. To deal |
604 | * with this, we will set cur to -1 and return. | | 604 | * with this, we will set cur to -1 and return. |
605 | */ | | 605 | */ |
606 | if (type == RANGE_TYPE_ISA && strcmp("isa", tmp) == 0 && len == 0) { | | 606 | if (type == RANGE_TYPE_ISA && strcmp("isa", tmp) == 0 && len == 0) { |
607 | *cur = -1; | | 607 | *cur = -1; |
608 | DPRINTF("Found empty range in isa bus\n"); | | 608 | DPRINTF("Found empty range in isa bus\n"); |
609 | return; | | 609 | return; |
610 | } | | 610 | } |
611 | | | 611 | |
612 | DPRINTF("found a map reclen=%d cur=%d len=%d\n", reclen, *cur, len); | | 612 | DPRINTF("found a map reclen=%d cur=%d len=%d\n", reclen, *cur, len); |
613 | switch (type) { | | 613 | switch (type) { |
614 | case RANGE_TYPE_PCI: | | 614 | case RANGE_TYPE_PCI: |
615 | case RANGE_TYPE_FIRSTPCI: | | 615 | case RANGE_TYPE_FIRSTPCI: |
616 | for (i=0; i < len/(4*reclen); i++) { | | 616 | for (i=0; i < len/(4*reclen); i++) { |
617 | DPRINTF("FOUND PCI RANGE\n"); | | 617 | DPRINTF("FOUND PCI RANGE\n"); |
618 | regions[*cur].size = | | 618 | regions[*cur].size = |
619 | map[i*reclen + parent_acells + acells + scells - 1]; | | 619 | map[i*reclen + parent_acells + acells + scells - 1]; |
620 | /* skip ranges of size==0 */ | | 620 | /* skip ranges of size==0 */ |
621 | if (regions[*cur].size == 0) | | 621 | if (regions[*cur].size == 0) |
622 | continue; | | 622 | continue; |
623 | regions[*cur].type = (map[i*reclen] >> 24) & 0x3; | | 623 | regions[*cur].type = (map[i*reclen] >> 24) & 0x3; |
624 | regions[*cur].addr = map[i*reclen + parent_acells + acells - 1]; | | 624 | regions[*cur].addr = map[i*reclen + parent_acells + acells - 1]; |
625 | (*cur)++; | | 625 | (*cur)++; |
626 | } | | 626 | } |
627 | break; | | 627 | break; |
628 | case RANGE_TYPE_ISA: | | 628 | case RANGE_TYPE_ISA: |
629 | for (i=0; i < len/(4*reclen); i++) { | | 629 | for (i=0; i < len/(4*reclen); i++) { |
630 | if (map[i*reclen] == 1) | | 630 | if (map[i*reclen] == 1) |
631 | regions[*cur].type = RANGE_IO; | | 631 | regions[*cur].type = RANGE_IO; |
632 | else | | 632 | else |
633 | regions[*cur].type = RANGE_MEM; | | 633 | regions[*cur].type = RANGE_MEM; |
634 | DPRINTF("FOUND ISA RANGE TYPE=%d\n", | | 634 | DPRINTF("FOUND ISA RANGE TYPE=%d\n", |
635 | regions[*cur].type); | | 635 | regions[*cur].type); |
636 | regions[*cur].size = | | 636 | regions[*cur].size = |
637 | map[i*reclen + acells + scells]; | | 637 | map[i*reclen + acells + scells]; |
638 | (*cur)++; | | 638 | (*cur)++; |
639 | } | | 639 | } |
640 | break; | | 640 | break; |
641 | case RANGE_TYPE_MACIO: | | 641 | case RANGE_TYPE_MACIO: |
642 | regions[*cur].type = RANGE_MEM; | | 642 | regions[*cur].type = RANGE_MEM; |
643 | if (len == 8) { | | 643 | if (len == 8) { |
644 | regions[*cur].size = map[1]; | | 644 | regions[*cur].size = map[1]; |
645 | regions[*cur].addr = map[0]; | | 645 | regions[*cur].addr = map[0]; |
646 | } else { | | 646 | } else { |
647 | regions[*cur].size = map[2]; | | 647 | regions[*cur].size = map[2]; |
648 | regions[*cur].addr = map[1]; | | 648 | regions[*cur].addr = map[1]; |
649 | } | | 649 | } |
650 | (*cur)++; | | 650 | (*cur)++; |
651 | break; | | 651 | break; |
652 | } | | 652 | } |
653 | DPRINTF("returning with CUR=%d\n", *cur); | | 653 | DPRINTF("returning with CUR=%d\n", *cur); |
654 | return; | | 654 | return; |
655 | rec: | | 655 | rec: |
656 | for (node = OF_child(base); node; node = OF_peer(node)) { | | 656 | for (node = OF_child(base); node; node = OF_peer(node)) { |
657 | DPRINTF("RECURSE 1 STEP\n"); | | 657 | DPRINTF("RECURSE 1 STEP\n"); |
658 | find_ranges(node, regions, cur, type); | | 658 | find_ranges(node, regions, cur, type); |
659 | if (*cur == -1) | | 659 | if (*cur == -1) |
660 | return; | | 660 | return; |
661 | } | | 661 | } |
662 | } | | 662 | } |
663 | | | 663 | |
664 | static int | | 664 | static int |
665 | find_lowest_range(rangemap_t *ranges, int nrof, int type) | | 665 | find_lowest_range(rangemap_t *ranges, int nrof, int type) |
666 | { | | 666 | { |
667 | int i, low = 0; | | 667 | int i, low = 0; |
668 | u_int32_t addr = 0xffffffff; | | 668 | u_int32_t addr = 0xffffffff; |
669 | | | 669 | |
670 | for (i=0; i < nrof; i++) { | | 670 | for (i=0; i < nrof; i++) { |
671 | if (ranges[i].type == type && ranges[i].addr != 0 && | | 671 | if (ranges[i].type == type && ranges[i].addr != 0 && |
672 | ranges[i].addr < addr) { | | 672 | ranges[i].addr < addr) { |
673 | low = i; | | 673 | low = i; |
674 | addr = ranges[i].addr; | | 674 | addr = ranges[i].addr; |
675 | } | | 675 | } |
676 | } | | 676 | } |
677 | if (addr == 0xffffffff) | | 677 | if (addr == 0xffffffff) |
678 | return -1; | | 678 | return -1; |
679 | return low; | | 679 | return low; |
680 | } | | 680 | } |
681 | | | 681 | |
682 | /* | | 682 | /* |
683 | * Find a region of memory, and create a bus_space_tag for it. | | 683 | * Find a region of memory, and create a bus_space_tag for it. |
684 | * Notes: | | 684 | * Notes: |
685 | * For ISA node is ignored. | | 685 | * For ISA node is ignored. |
686 | * node is the starting node. if -1, we start at / and map everything. | | 686 | * node is the starting node. if -1, we start at / and map everything. |
687 | */ | | 687 | */ |
688 | | | 688 | |
689 | int | | 689 | int |
690 | ofwoea_map_space(int rangetype, int iomem, int node, | | 690 | ofwoea_map_space(int rangetype, int iomem, int node, |
691 | struct powerpc_bus_space *tag, const char *name) | | 691 | struct powerpc_bus_space *tag, const char *name) |
692 | { | | 692 | { |
693 | int i, cur, range, nrofholes, error; | | 693 | int i, cur, range, nrofholes, error; |
694 | static int exmap=0; | | 694 | static int exmap=0; |
695 | rangemap_t region, holes[32], list[32]; | | 695 | rangemap_t region, holes[32], list[32]; |
696 | | | 696 | |
697 | memset(list, 0, sizeof(list)); | | 697 | memset(list, 0, sizeof(list)); |
698 | memset(®ion, 0, sizeof(region)); | | 698 | memset(®ion, 0, sizeof(region)); |
699 | cur = 0; | | 699 | cur = 0; |
700 | if (rangetype == RANGE_TYPE_ISA || node == -1) | | 700 | if (rangetype == RANGE_TYPE_ISA || node == -1) |
701 | node = OF_finddevice("/"); | | 701 | node = OF_finddevice("/"); |
702 | if (rangetype == RANGE_TYPE_ISA) { | | 702 | if (rangetype == RANGE_TYPE_ISA) { |
703 | u_int32_t size = 0; | | 703 | u_int32_t size = 0; |
704 | rangemap_t regions[32]; | | 704 | rangemap_t regions[32]; |
705 | | | 705 | |
706 | DPRINTF("LOOKING FOR FIRSTPCI\n"); | | 706 | DPRINTF("LOOKING FOR FIRSTPCI\n"); |
707 | find_ranges(node, list, &cur, RANGE_TYPE_FIRSTPCI); | | 707 | find_ranges(node, list, &cur, RANGE_TYPE_FIRSTPCI); |
708 | range = 0; | | 708 | range = 0; |
709 | DPRINTF("LOOKING FOR ISA\n"); | | 709 | DPRINTF("LOOKING FOR ISA\n"); |
710 | find_ranges(node, regions, &range, RANGE_TYPE_ISA); | | 710 | find_ranges(node, regions, &range, RANGE_TYPE_ISA); |
711 | if (range == 0 || cur == 0) | | 711 | if (range == 0 || cur == 0) |
712 | return -1; /* no isa stuff found */ | | 712 | return -1; /* no isa stuff found */ |
713 | /* | | 713 | /* |
714 | * This may be confusing to some. The ISA ranges property | | 714 | * This may be confusing to some. The ISA ranges property |
715 | * is supposed to be a set of IO ranges for the ISA bus, but | | 715 | * is supposed to be a set of IO ranges for the ISA bus, but |
716 | * generally, it's just a set of pci devfunc lists that tell | | 716 | * generally, it's just a set of pci devfunc lists that tell |
717 | * you to go look at the parent PCI device for the actual | | 717 | * you to go look at the parent PCI device for the actual |
718 | * ranges. | | 718 | * ranges. |
719 | */ | | 719 | */ |
720 | if (range == -1) { | | 720 | if (range == -1) { |
721 | /* we found a rangeless isa bus */ | | 721 | /* we found a rangeless isa bus */ |
722 | if (iomem == RANGE_IO) | | 722 | if (iomem == RANGE_IO) |
723 | size = 0x10000; | | 723 | size = 0x10000; |
724 | else | | 724 | else |
725 | size = 0x1000000; | | 725 | size = 0x1000000; |
726 | } | | 726 | } |
727 | DPRINTF("found isa stuff\n"); | | 727 | DPRINTF("found isa stuff\n"); |
728 | for (i=0; i < range; i++) | | 728 | for (i=0; i < range; i++) |
729 | if (regions[i].type == iomem) | | 729 | if (regions[i].type == iomem) |
730 | size = regions[i].size; | | 730 | size = regions[i].size; |
731 | if (iomem == RANGE_IO) { | | 731 | if (iomem == RANGE_IO) { |
732 | /* the first io range is the one */ | | 732 | /* the first io range is the one */ |
733 | for (i=0; i < cur; i++) | | 733 | for (i=0; i < cur; i++) |
734 | if (list[i].type == RANGE_IO && size) { | | 734 | if (list[i].type == RANGE_IO && size) { |
735 | DPRINTF("found IO\n"); | | 735 | DPRINTF("found IO\n"); |
736 | tag->pbs_offset = list[i].addr; | | 736 | tag->pbs_offset = list[i].addr; |
737 | tag->pbs_limit = size; | | 737 | tag->pbs_limit = size; |
738 | error = bus_space_init(tag, name, | | 738 | error = bus_space_init(tag, name, |
739 | ex_storage[exmap], | | 739 | ex_storage[exmap], |
740 | sizeof(ex_storage[exmap])); | | 740 | sizeof(ex_storage[exmap])); |
741 | exmap++; | | 741 | exmap++; |
742 | return error; | | 742 | return error; |
743 | } | | 743 | } |
744 | } else { | | 744 | } else { |
745 | for (i=0; i < cur; i++) | | 745 | for (i=0; i < cur; i++) |
746 | if (list[i].type == RANGE_MEM && | | 746 | if (list[i].type == RANGE_MEM && |
747 | list[i].size == size) { | | 747 | list[i].size == size) { |
748 | DPRINTF("found mem\n"); | | 748 | DPRINTF("found mem\n"); |
749 | tag->pbs_offset = list[i].addr; | | 749 | tag->pbs_offset = list[i].addr; |
750 | tag->pbs_limit = size; | | 750 | tag->pbs_limit = size; |
751 | error = bus_space_init(tag, name, | | 751 | error = bus_space_init(tag, name, |
752 | ex_storage[exmap], | | 752 | ex_storage[exmap], |
753 | sizeof(ex_storage[exmap])); | | 753 | sizeof(ex_storage[exmap])); |
754 | exmap++; | | 754 | exmap++; |
755 | return error; | | 755 | return error; |
756 | } | | 756 | } |
757 | } | | 757 | } |
758 | return -1; /* NO ISA FOUND */ | | 758 | return -1; /* NO ISA FOUND */ |
759 | } | | 759 | } |
760 | find_ranges(node, list, &cur, rangetype); | | 760 | find_ranges(node, list, &cur, rangetype); |
761 | | | 761 | |
762 | DPRINTF("cur == %d\n", cur); | | 762 | DPRINTF("cur == %d\n", cur); |
763 | /* now list should contain a list of memory regions */ | | 763 | /* now list should contain a list of memory regions */ |
764 | for (i=0; i < cur; i++) | | 764 | for (i=0; i < cur; i++) |
765 | DPRINTF("addr=0x%x size=0x%x type=%d\n", list[i].addr, | | 765 | DPRINTF("addr=0x%x size=0x%x type=%d\n", list[i].addr, |
766 | list[i].size, list[i].type); | | 766 | list[i].size, list[i].type); |
767 | | | 767 | |
768 | range = find_lowest_range(list, cur, iomem); | | 768 | range = find_lowest_range(list, cur, iomem); |
769 | i = 0; | | 769 | i = 0; |
770 | nrofholes = 0; | | 770 | nrofholes = 0; |
771 | while (range != -1) { | | 771 | while (range != -1) { |
772 | DPRINTF("range==%d\n", range); | | 772 | DPRINTF("range==%d\n", range); |
773 | DPRINTF("i==%d\n", i); | | 773 | DPRINTF("i==%d\n", i); |
774 | if (i == 0) { | | 774 | if (i == 0) { |
775 | memcpy(®ion, &list[range], sizeof(rangemap_t)); | | 775 | memcpy(®ion, &list[range], sizeof(rangemap_t)); |
776 | list[range].addr = 0; | | 776 | list[range].addr = 0; |
777 | i++; | | 777 | i++; |
778 | range = find_lowest_range(list, cur, iomem); | | 778 | range = find_lowest_range(list, cur, iomem); |
779 | continue; | | 779 | continue; |
780 | } | | 780 | } |
781 | if (region.addr + region.size < list[range].addr) { | | 781 | if (region.addr + region.size < list[range].addr) { |
782 | /* allocate a hole */ | | 782 | /* allocate a hole */ |
783 | holes[nrofholes].type = iomem; | | 783 | holes[nrofholes].type = iomem; |
784 | holes[nrofholes].addr = region.size + region.addr; | | 784 | holes[nrofholes].addr = region.size + region.addr; |
785 | holes[nrofholes].size = list[range].addr - | | 785 | holes[nrofholes].size = list[range].addr - |
786 | holes[nrofholes].addr - 1; | | 786 | holes[nrofholes].addr - 1; |
787 | nrofholes++; | | 787 | nrofholes++; |
788 | } | | 788 | } |
789 | region.size = list[range].size + list[range].addr - | | 789 | region.size = list[range].size + list[range].addr - |
790 | region.addr; | | 790 | region.addr; |
791 | list[range].addr = 0; | | 791 | list[range].addr = 0; |
792 | range = find_lowest_range(list, cur, iomem); | | 792 | range = find_lowest_range(list, cur, iomem); |
793 | } | | 793 | } |
794 | DPRINTF("RANGE iomem=%d FOUND\n", iomem); | | 794 | DPRINTF("RANGE iomem=%d FOUND\n", iomem); |
795 | DPRINTF("addr=0x%x size=0x%x type=%d\n", region.addr, | | 795 | DPRINTF("addr=0x%x size=0x%x type=%d\n", region.addr, |
796 | region.size, region.type); | | 796 | region.size, region.type); |
797 | DPRINTF("HOLES FOUND\n"); | | 797 | DPRINTF("HOLES FOUND\n"); |
798 | for (i=0; i < nrofholes; i++) | | 798 | for (i=0; i < nrofholes; i++) |
799 | DPRINTF("addr=0x%x size=0x%x type=%d\n", holes[i].addr, | | 799 | DPRINTF("addr=0x%x size=0x%x type=%d\n", holes[i].addr, |
800 | holes[i].size, holes[i].type); | | 800 | holes[i].size, holes[i].type); |
801 | /* AT THIS POINT WE MAP IT */ | | 801 | /* AT THIS POINT WE MAP IT */ |
802 | | | 802 | |
803 | if ((rangetype == RANGE_TYPE_PCI) || (rangetype == RANGE_TYPE_MACIO)) { | | 803 | if ((rangetype == RANGE_TYPE_PCI) || (rangetype == RANGE_TYPE_MACIO)) { |
804 | if (exmap == EXSTORAGE_MAX) | | 804 | if (exmap == EXSTORAGE_MAX) |
805 | panic("Not enough ex_storage space. " | | 805 | panic("Not enough ex_storage space. " |
806 | "Increase EXSTORAGE_MAX"); | | 806 | "Increase EXSTORAGE_MAX"); |
807 | | | 807 | |
808 | /* XXX doing this in here might be wrong */ | | 808 | /* XXX doing this in here might be wrong */ |
809 | if (iomem == 1) { | | 809 | if (iomem == 1) { |
810 | /* we map an IO region */ | | 810 | /* we map an IO region */ |
811 | tag->pbs_offset = region.addr; | | 811 | tag->pbs_offset = region.addr; |
812 | tag->pbs_base = 0; | | 812 | tag->pbs_base = 0; |
813 | tag->pbs_limit = region.size; | | 813 | tag->pbs_limit = region.size; |
814 | } else { | | 814 | } else { |
815 | /* ... or a memory region */ | | 815 | /* ... or a memory region */ |
816 | tag->pbs_offset = 0; | | 816 | tag->pbs_offset = 0; |
817 | tag->pbs_base = region.addr; | | 817 | tag->pbs_base = region.addr; |
818 | tag->pbs_limit = region.size + region.addr; | | 818 | tag->pbs_limit = region.size + region.addr; |
819 | } | | 819 | } |
820 | | | 820 | |
821 | error = bus_space_init(tag, name, ex_storage[exmap], | | 821 | error = bus_space_init(tag, name, ex_storage[exmap], |
822 | sizeof(ex_storage[exmap])); | | 822 | sizeof(ex_storage[exmap])); |
823 | exmap++; | | 823 | exmap++; |
824 | if (error) | | 824 | if (error) |
825 | panic("ofwoea_bus_space_init: can't init tag %s", name); | | 825 | panic("ofwoea_bus_space_init: can't init tag %s", name); |
826 | for (i=0; i < nrofholes; i++) { | | 826 | for (i=0; i < nrofholes; i++) { |
827 | if (holes[i].type == RANGE_IO) { | | 827 | if (holes[i].type == RANGE_IO) { |
828 | error = extent_alloc_region(tag->pbs_extent, | | 828 | error = extent_alloc_region(tag->pbs_extent, |
829 | holes[i].addr - tag->pbs_offset, | | 829 | holes[i].addr - tag->pbs_offset, |
830 | holes[i].size, EX_NOWAIT); | | 830 | holes[i].size, EX_NOWAIT); |
831 | } else { | | 831 | } else { |
832 | error = extent_alloc_region(tag->pbs_extent, | | 832 | error = extent_alloc_region(tag->pbs_extent, |
833 | holes[i].addr, holes[i].size, EX_NOWAIT); | | 833 | holes[i].addr, holes[i].size, EX_NOWAIT); |
834 | } | | 834 | } |
835 | if (error) | | 835 | if (error) |
836 | panic("ofwoea_bus_space_init: can't block out" | | 836 | panic("ofwoea_bus_space_init: can't block out" |
837 | " reserved space 0x%x-0x%x: error=%d", | | 837 | " reserved space 0x%x-0x%x: error=%d", |
838 | holes[i].addr, holes[i].addr+holes[i].size, | | 838 | holes[i].addr, holes[i].addr+holes[i].size, |
839 | error); | | 839 | error); |
840 | } | | 840 | } |
841 | return error; | | 841 | return error; |
842 | } | | 842 | } |
843 | return -1; | | 843 | return -1; |
844 | } | | 844 | } |
845 | | | 845 | |
846 | void | | 846 | void |
847 | ofwoea_bus_space_init(void) | | 847 | ofwoea_bus_space_init(void) |
848 | { | | 848 | { |
849 | int error; | | 849 | int error; |
850 | | | 850 | |
851 | error = ofwoea_map_space(RANGE_TYPE_ISA, RANGE_IO, -1, | | 851 | error = ofwoea_map_space(RANGE_TYPE_ISA, RANGE_IO, -1, |
852 | &genppc_isa_io_space_tag, "isa-ioport"); | | 852 | &genppc_isa_io_space_tag, "isa-ioport"); |
853 | if (error > 0) | | 853 | if (error > 0) |
854 | panic("Could not map ISA IO"); | | 854 | panic("Could not map ISA IO"); |
855 | | | 855 | |
856 | error = ofwoea_map_space(RANGE_TYPE_ISA, RANGE_MEM, -1, | | 856 | error = ofwoea_map_space(RANGE_TYPE_ISA, RANGE_MEM, -1, |
857 | &genppc_isa_mem_space_tag, "isa-iomem"); | | 857 | &genppc_isa_mem_space_tag, "isa-iomem"); |
858 | if (error > 0) | | 858 | if (error > 0) |
859 | panic("Could not map ISA MEM"); | | 859 | panic("Could not map ISA MEM"); |
860 | } | | 860 | } |