| @@ -1,724 +1,732 @@ | | | @@ -1,724 +1,732 @@ |
1 | /* $NetBSD: ofwoea_machdep.c,v 1.24 2011/07/17 23:23:54 dyoung Exp $ */ | | 1 | /* $NetBSD: ofwoea_machdep.c,v 1.25 2011/07/27 22:04:23 macallan 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.24 2011/07/17 23:23:54 dyoung Exp $"); | | 33 | __KERNEL_RCSID(0, "$NetBSD: ofwoea_machdep.c,v 1.25 2011/07/27 22:04:23 macallan Exp $"); |
34 | | | 34 | |
35 | #include "opt_ppcarch.h" | | 35 | #include "opt_ppcarch.h" |
36 | #include "opt_compat_netbsd.h" | | 36 | #include "opt_compat_netbsd.h" |
37 | #include "opt_ddb.h" | | 37 | #include "opt_ddb.h" |
38 | #include "opt_kgdb.h" | | 38 | #include "opt_kgdb.h" |
39 | #include "opt_ipkdb.h" | | 39 | #include "opt_ipkdb.h" |
40 | #include "opt_modular.h" | | 40 | #include "opt_modular.h" |
41 | | | 41 | |
42 | #include <sys/param.h> | | 42 | #include <sys/param.h> |
43 | #include <sys/buf.h> | | 43 | #include <sys/buf.h> |
44 | #include <sys/boot_flag.h> | | 44 | #include <sys/boot_flag.h> |
45 | #include <sys/extent.h> | | 45 | #include <sys/extent.h> |
46 | #include <sys/kernel.h> | | 46 | #include <sys/kernel.h> |
47 | #include <sys/ksyms.h> | | 47 | #include <sys/ksyms.h> |
48 | #include <uvm/uvm_extern.h> | | 48 | #include <uvm/uvm_extern.h> |
49 | | | 49 | |
50 | #include <dev/ofw/openfirm.h> | | 50 | #include <dev/ofw/openfirm.h> |
51 | #include <machine/pmap.h> | | 51 | #include <machine/pmap.h> |
52 | #include <machine/powerpc.h> | | 52 | #include <machine/powerpc.h> |
53 | #include <machine/trap.h> | | 53 | #include <machine/trap.h> |
54 | #include <machine/vmparam.h> | | 54 | #include <machine/vmparam.h> |
55 | #include <machine/autoconf.h> | | 55 | #include <machine/autoconf.h> |
56 | #include <sys/bus.h> | | 56 | #include <sys/bus.h> |
57 | #include <powerpc/oea/bat.h> | | 57 | #include <powerpc/oea/bat.h> |
58 | #include <powerpc/oea/cpufeat.h> | | 58 | #include <powerpc/oea/cpufeat.h> |
59 | #include <powerpc/ofw_cons.h> | | 59 | #include <powerpc/ofw_cons.h> |
60 | #include <powerpc/spr.h> | | 60 | #include <powerpc/spr.h> |
61 | #include <powerpc/pic/picvar.h> | | 61 | #include <powerpc/pic/picvar.h> |
62 | | | 62 | |
63 | #include "opt_oea.h" | | 63 | #include "opt_oea.h" |
64 | | | 64 | |
65 | #include "ksyms.h" | | 65 | #include "ksyms.h" |
66 | | | 66 | |
67 | #ifdef DDB | | 67 | #ifdef DDB |
68 | #include <machine/db_machdep.h> | | 68 | #include <machine/db_machdep.h> |
69 | #include <ddb/db_extern.h> | | 69 | #include <ddb/db_extern.h> |
70 | #endif | | 70 | #endif |
71 | | | 71 | |
72 | #ifdef KGDB | | 72 | #ifdef KGDB |
73 | #include <sys/kgdb.h> | | 73 | #include <sys/kgdb.h> |
74 | #endif | | 74 | #endif |
75 | | | 75 | |
76 | #ifdef IPKDB | | 76 | #ifdef IPKDB |
77 | #include <ipkdb/ipkdb.h> | | 77 | #include <ipkdb/ipkdb.h> |
78 | #endif | | 78 | #endif |
79 | | | 79 | |
80 | #include "opt_ofwoea.h" | | 80 | #include "opt_ofwoea.h" |
81 | | | 81 | |
82 | #ifdef ofppc | | 82 | #ifdef ofppc |
83 | extern struct model_data modeldata; | | 83 | extern struct model_data modeldata; |
84 | #endif | | 84 | #endif |
85 | | | 85 | |
86 | #ifdef OFWOEA_DEBUG | | 86 | #ifdef OFWOEA_DEBUG |
87 | #define DPRINTF printf | | 87 | #define DPRINTF printf |
88 | #else | | 88 | #else |
89 | #define DPRINTF while (0) printf | | 89 | #define DPRINTF while (0) printf |
90 | #endif | | 90 | #endif |
91 | | | 91 | |
92 | typedef struct _rangemap { | | 92 | typedef struct _rangemap { |
93 | u_int32_t addr; | | 93 | u_int32_t addr; |
94 | u_int32_t size; | | 94 | u_int32_t size; |
95 | int type; | | 95 | int type; |
96 | } rangemap_t; | | 96 | } rangemap_t; |
97 | | | 97 | |
98 | struct ofw_translations { | | 98 | struct ofw_translations { |
99 | vaddr_t va; | | 99 | vaddr_t va; |
100 | int len; | | 100 | int len; |
101 | #if defined (PMAC_G5) | | 101 | #if defined (PMAC_G5) |
102 | register64_t pa; | | 102 | register64_t pa; |
103 | #else | | 103 | #else |
104 | register_t pa; | | 104 | register_t pa; |
105 | #endif | | 105 | #endif |
106 | int mode; | | 106 | int mode; |
107 | }__attribute__((packed)); | | 107 | }__attribute__((packed)); |
108 | | | 108 | |
109 | struct pmap ofw_pmap; | | 109 | struct pmap ofw_pmap; |
110 | struct ofw_translations ofmap[32]; | | 110 | struct ofw_translations ofmap[32]; |
111 | char bootpath[256]; | | 111 | char bootpath[256]; |
112 | char model_name[64]; | | 112 | char model_name[64]; |
113 | #if NKSYMS || defined(DDB) || defined(MODULAR) | | 113 | #if NKSYMS || defined(DDB) || defined(MODULAR) |
114 | void *startsym, *endsym; | | 114 | void *startsym, *endsym; |
115 | #endif | | 115 | #endif |
116 | #ifdef TIMEBASE_FREQ | | 116 | #ifdef TIMEBASE_FREQ |
117 | u_int timebase_freq = TIMEBASE_FREQ; | | 117 | u_int timebase_freq = TIMEBASE_FREQ; |
118 | #else | | 118 | #else |
119 | u_int timebase_freq = 0; | | 119 | u_int timebase_freq = 0; |
120 | #endif | | 120 | #endif |
121 | | | 121 | |
| | | 122 | extern int ofwmsr; |
122 | extern int chosen; | | 123 | extern int chosen; |
123 | extern uint32_t ticks_per_sec; | | 124 | extern uint32_t ticks_per_sec; |
124 | extern uint32_t ns_per_tick; | | 125 | extern uint32_t ns_per_tick; |
125 | extern uint32_t ticks_per_intr; | | 126 | extern uint32_t ticks_per_intr; |
126 | | | 127 | |
127 | static int save_ofmap(struct ofw_translations *, int); | | 128 | static int save_ofmap(struct ofw_translations *, int); |
128 | static void restore_ofmap(struct ofw_translations *, int); | | 129 | static void restore_ofmap(struct ofw_translations *, int); |
129 | static void set_timebase(void); | | 130 | static void set_timebase(void); |
130 | | | 131 | |
131 | extern void cpu_spinstart(u_int); | | 132 | extern void cpu_spinstart(u_int); |
132 | volatile u_int cpu_spinstart_ack, cpu_spinstart_cpunum; | | 133 | volatile u_int cpu_spinstart_ack, cpu_spinstart_cpunum; |
133 | | | 134 | |
134 | void | | 135 | void |
135 | ofwoea_initppc(u_int startkernel, u_int endkernel, char *args) | | 136 | ofwoea_initppc(u_int startkernel, u_int endkernel, char *args) |
136 | { | | 137 | { |
137 | int ofmaplen, node, l; | | 138 | int ofmaplen, node, l; |
138 | register_t scratch; | | 139 | register_t scratch; |
139 | | | 140 | |
140 | #if defined(MULTIPROCESSOR) && defined(ofppc) | | 141 | #if defined(MULTIPROCESSOR) && defined(ofppc) |
141 | char cpupath[32]; | | 142 | char cpupath[32]; |
142 | int i; | | 143 | int i; |
143 | #endif | | 144 | #endif |
144 | | | 145 | |
145 | /* initialze bats */ | | 146 | /* initialze bats */ |
146 | if ((oeacpufeat & OEACPU_NOBAT) == 0) | | 147 | if ((oeacpufeat & OEACPU_NOBAT) == 0) |
147 | ofwoea_batinit(); | | 148 | ofwoea_batinit(); |
148 | | | 149 | |
149 | #if NKSYMS || defined(DDB) || defined(MODULAR) | | 150 | #if NKSYMS || defined(DDB) || defined(MODULAR) |
150 | /* get info of kernel symbol table from bootloader */ | | 151 | /* get info of kernel symbol table from bootloader */ |
151 | memcpy(&startsym, args + strlen(args) + 1, sizeof(startsym)); | | 152 | memcpy(&startsym, args + strlen(args) + 1, sizeof(startsym)); |
152 | memcpy(&endsym, args + strlen(args) + 1 + sizeof(startsym), | | 153 | memcpy(&endsym, args + strlen(args) + 1 + sizeof(startsym), |
153 | sizeof(endsym)); | | 154 | sizeof(endsym)); |
154 | if (startsym == NULL || endsym == NULL) | | 155 | if (startsym == NULL || endsym == NULL) |
155 | startsym = endsym = NULL; | | 156 | startsym = endsym = NULL; |
156 | #endif | | 157 | #endif |
157 | | | 158 | |
158 | /* get model name and perform model-specific actions */ | | 159 | /* get model name and perform model-specific actions */ |
159 | memset(model_name, 0, sizeof(model_name)); | | 160 | memset(model_name, 0, sizeof(model_name)); |
160 | node = OF_finddevice("/"); | | 161 | node = OF_finddevice("/"); |
161 | if (node >= 0) { | | 162 | if (node >= 0) { |
162 | l = OF_getprop(node, "model", model_name, sizeof(model_name)); | | 163 | l = OF_getprop(node, "model", model_name, sizeof(model_name)); |
163 | if (l == -1) | | 164 | if (l == -1) |
164 | OF_getprop(node, "name", model_name, | | 165 | OF_getprop(node, "name", model_name, |
165 | sizeof(model_name)); | | 166 | sizeof(model_name)); |
166 | model_init(); | | 167 | model_init(); |
167 | } | | 168 | } |
168 | /* Initialize bus_space */ | | 169 | /* Initialize bus_space */ |
169 | ofwoea_bus_space_init(); | | 170 | ofwoea_bus_space_init(); |
170 | | | 171 | |
171 | ofwoea_consinit(); | | 172 | ofwoea_consinit(); |
172 | | | 173 | |
173 | #if defined(MULTIPROCESSOR) && defined(ofppc) | | 174 | #if defined(MULTIPROCESSOR) && defined(ofppc) |
174 | for (i=1; i < CPU_MAXNUM; i++) { | | 175 | for (i=1; i < CPU_MAXNUM; i++) { |
175 | sprintf(cpupath, "/cpus/@%x", i); | | 176 | sprintf(cpupath, "/cpus/@%x", i); |
176 | node = OF_finddevice(cpupath); | | 177 | node = OF_finddevice(cpupath); |
177 | if (node <= 0) | | 178 | if (node <= 0) |
178 | continue; | | 179 | continue; |
179 | aprint_verbose("Starting up CPU %d %s\n", i, cpupath); | | 180 | aprint_verbose("Starting up CPU %d %s\n", i, cpupath); |
180 | OF_start_cpu(node, (u_int)cpu_spinstart, i); | | 181 | OF_start_cpu(node, (u_int)cpu_spinstart, i); |
181 | for (l=0; l < 100000000; l++) { | | 182 | for (l=0; l < 100000000; l++) { |
182 | if (cpu_spinstart_ack == i) { | | 183 | if (cpu_spinstart_ack == i) { |
183 | aprint_verbose("CPU %d spun up.\n", i); | | 184 | aprint_verbose("CPU %d spun up.\n", i); |
184 | break; | | 185 | break; |
185 | } | | 186 | } |
186 | __asm volatile ("sync"); | | 187 | __asm volatile ("sync"); |
187 | } | | 188 | } |
188 | } | | 189 | } |
189 | #endif | | 190 | #endif |
190 | | | 191 | |
191 | #if defined (PPC_OEA64_BRIDGE) && defined (PPC_OEA) | | 192 | #if defined (PPC_OEA64_BRIDGE) && defined (PPC_OEA) |
192 | if (oeacpufeat & OEACPU_64_BRIDGE) | | 193 | if (oeacpufeat & OEACPU_64_BRIDGE) |
193 | pmap_setup64bridge(); | | 194 | pmap_setup64bridge(); |
194 | else | | 195 | else |
195 | pmap_setup32(); | | 196 | pmap_setup32(); |
196 | #endif | | 197 | #endif |
197 | | | 198 | |
198 | oea_init(pic_ext_intr); | | 199 | oea_init(pic_ext_intr); |
199 | | | 200 | |
200 | ofmaplen = save_ofmap(NULL, 0); | | 201 | ofmaplen = save_ofmap(NULL, 0); |
201 | if (ofmaplen > 0) | | 202 | if (ofmaplen > 0) |
202 | save_ofmap(ofmap, ofmaplen); | | 203 | save_ofmap(ofmap, ofmaplen); |
203 | | | 204 | |
| | | 205 | /* |
| | | 206 | * XXX |
| | | 207 | * we need to do this here instead of earlier on in ofwinit() for some reason |
| | | 208 | * At least some versions of Apple OF 2.0.1 hang if we do this earlier |
| | | 209 | */ |
| | | 210 | ofwmsr &= ~PSL_IP; |
| | | 211 | |
204 | /* Parse the args string */ | | 212 | /* Parse the args string */ |
205 | if (args) { | | 213 | if (args) { |
206 | strcpy(bootpath, args); | | 214 | strcpy(bootpath, args); |
207 | args = bootpath; | | 215 | args = bootpath; |
208 | while (*++args && *args != ' '); | | 216 | while (*++args && *args != ' '); |
209 | if (*args) { | | 217 | if (*args) { |
210 | *args++ = 0; | | 218 | *args++ = 0; |
211 | while (*args) | | 219 | while (*args) |
212 | BOOT_FLAG(*args++, boothowto); | | 220 | BOOT_FLAG(*args++, boothowto); |
213 | } | | 221 | } |
214 | } | | 222 | } |
215 | | | 223 | |
216 | uvm_setpagesize(); | | 224 | uvm_setpagesize(); |
217 | | | 225 | |
218 | pmap_bootstrap(startkernel, endkernel); | | 226 | pmap_bootstrap(startkernel, endkernel); |
219 | | | 227 | |
220 | /* as far as I can tell, the pmap_setup_seg0 stuff is horribly broken */ | | 228 | /* as far as I can tell, the pmap_setup_seg0 stuff is horribly broken */ |
221 | #if defined(PPC_OEA64) || defined (PPC_OEA64_BRIDGE) | | 229 | #if defined(PPC_OEA64) || defined (PPC_OEA64_BRIDGE) |
222 | #if defined (PMAC_G5) | | 230 | #if defined (PMAC_G5) |
223 | /* Mapin 1st 256MB segment 1:1, also map in mem needed to access OFW*/ | | 231 | /* Mapin 1st 256MB segment 1:1, also map in mem needed to access OFW*/ |
224 | if (oeacpufeat & OEACPU_64_BRIDGE) | | 232 | if (oeacpufeat & OEACPU_64_BRIDGE) |
225 | pmap_setup_segment0_map(0, 0xff800000, 0x3fc00000, 0x400000, | | 233 | pmap_setup_segment0_map(0, 0xff800000, 0x3fc00000, 0x400000, |
226 | 0x0); | | 234 | 0x0); |
227 | #elif defined (MAMBO) | | 235 | #elif defined (MAMBO) |
228 | /* Mapin 1st 256MB segment 1:1, also map in mem needed to access OFW*/ | | 236 | /* Mapin 1st 256MB segment 1:1, also map in mem needed to access OFW*/ |
229 | if (oeacpufeat & OEACPU_64_BRIDGE) | | 237 | if (oeacpufeat & OEACPU_64_BRIDGE) |
230 | pmap_setup_segment0_map(0, 0xf4000000, 0xf4000000, 0x1000, 0x0); | | 238 | pmap_setup_segment0_map(0, 0xf4000000, 0xf4000000, 0x1000, 0x0); |
231 | #endif /* PMAC_G5 */ | | 239 | #endif /* PMAC_G5 */ |
232 | #endif /* PPC_OEA64 || PPC_OEA64_BRIDGE */ | | 240 | #endif /* PPC_OEA64 || PPC_OEA64_BRIDGE */ |
233 | | | 241 | |
234 | /* Now enable translation (and machine checks/recoverable interrupts) */ | | 242 | /* Now enable translation (and machine checks/recoverable interrupts) */ |
235 | __asm __volatile ("sync; mfmsr %0; ori %0,%0,%1; mtmsr %0; isync" | | 243 | __asm __volatile ("sync; mfmsr %0; ori %0,%0,%1; mtmsr %0; isync" |
236 | : "=r"(scratch) | | 244 | : "=r"(scratch) |
237 | : "K"(PSL_IR|PSL_DR|PSL_ME|PSL_RI)); | | 245 | : "K"(PSL_IR|PSL_DR|PSL_ME|PSL_RI)); |
238 | | | 246 | |
239 | restore_ofmap(ofmap, ofmaplen); | | 247 | restore_ofmap(ofmap, ofmaplen); |
240 | | | 248 | |
241 | #if NKSYMS || defined(DDB) || defined(MODULAR) | | 249 | #if NKSYMS || defined(DDB) || defined(MODULAR) |
242 | ksyms_addsyms_elf((int)((u_int)endsym - (u_int)startsym), startsym, endsym); | | 250 | ksyms_addsyms_elf((int)((u_int)endsym - (u_int)startsym), startsym, endsym); |
243 | #endif | | 251 | #endif |
244 | | | 252 | |
245 | /* CPU clock stuff */ | | 253 | /* CPU clock stuff */ |
246 | set_timebase(); | | 254 | set_timebase(); |
247 | } | | 255 | } |
248 | | | 256 | |
249 | void | | 257 | void |
250 | set_timebase(void) | | 258 | set_timebase(void) |
251 | { | | 259 | { |
252 | int qhandle, phandle, msr, scratch; | | 260 | int qhandle, phandle, msr, scratch; |
253 | char type[32]; | | 261 | char type[32]; |
254 | | | 262 | |
255 | if (timebase_freq != 0) { | | 263 | if (timebase_freq != 0) { |
256 | ticks_per_sec = timebase_freq; | | 264 | ticks_per_sec = timebase_freq; |
257 | goto found; | | 265 | goto found; |
258 | } | | 266 | } |
259 | | | 267 | |
260 | for (qhandle = OF_peer(0); qhandle; qhandle = phandle) { | | 268 | for (qhandle = OF_peer(0); qhandle; qhandle = phandle) { |
261 | if (OF_getprop(qhandle, "device_type", type, sizeof type) > 0 | | 269 | if (OF_getprop(qhandle, "device_type", type, sizeof type) > 0 |
262 | && strcmp(type, "cpu") == 0 | | 270 | && strcmp(type, "cpu") == 0 |
263 | && OF_getprop(qhandle, "timebase-frequency", | | 271 | && OF_getprop(qhandle, "timebase-frequency", |
264 | &ticks_per_sec, sizeof ticks_per_sec) > 0) { | | 272 | &ticks_per_sec, sizeof ticks_per_sec) > 0) { |
265 | goto found; | | 273 | goto found; |
266 | } | | 274 | } |
267 | if ((phandle = OF_child(qhandle))) | | 275 | if ((phandle = OF_child(qhandle))) |
268 | continue; | | 276 | continue; |
269 | while (qhandle) { | | 277 | while (qhandle) { |
270 | if ((phandle = OF_peer(qhandle))) | | 278 | if ((phandle = OF_peer(qhandle))) |
271 | break; | | 279 | break; |
272 | qhandle = OF_parent(qhandle); | | 280 | qhandle = OF_parent(qhandle); |
273 | } | | 281 | } |
274 | } | | 282 | } |
275 | panic("no cpu node"); | | 283 | panic("no cpu node"); |
276 | | | 284 | |
277 | found: | | 285 | found: |
278 | __asm volatile ("mfmsr %0; andi. %1,%0,%2; mtmsr %1" | | 286 | __asm volatile ("mfmsr %0; andi. %1,%0,%2; mtmsr %1" |
279 | : "=r"(msr), "=r"(scratch) : "K"((u_short)~PSL_EE)); | | 287 | : "=r"(msr), "=r"(scratch) : "K"((u_short)~PSL_EE)); |
280 | ns_per_tick = 1000000000 / ticks_per_sec; | | 288 | ns_per_tick = 1000000000 / ticks_per_sec; |
281 | ticks_per_intr = ticks_per_sec / hz; | | 289 | ticks_per_intr = ticks_per_sec / hz; |
282 | cpu_timebase = ticks_per_sec; | | 290 | cpu_timebase = ticks_per_sec; |
283 | curcpu()->ci_lasttb = mftbl(); | | 291 | curcpu()->ci_lasttb = mftbl(); |
284 | mtspr(SPR_DEC, ticks_per_intr); | | 292 | mtspr(SPR_DEC, ticks_per_intr); |
285 | mtmsr(msr); | | 293 | mtmsr(msr); |
286 | } | | 294 | } |
287 | | | 295 | |
288 | static int | | 296 | static int |
289 | save_ofmap(struct ofw_translations *map, int maxlen) | | 297 | save_ofmap(struct ofw_translations *map, int maxlen) |
290 | { | | 298 | { |
291 | int mmui, mmu, len; | | 299 | int mmui, mmu, len; |
292 | | | 300 | |
293 | OF_getprop(chosen, "mmu", &mmui, sizeof mmui); | | 301 | OF_getprop(chosen, "mmu", &mmui, sizeof mmui); |
294 | mmu = OF_instance_to_package(mmui); | | 302 | mmu = OF_instance_to_package(mmui); |
295 | | | 303 | |
296 | if (map) { | | 304 | if (map) { |
297 | memset(map, 0, maxlen); /* to be safe */ | | 305 | memset(map, 0, maxlen); /* to be safe */ |
298 | len = OF_getprop(mmu, "translations", map, maxlen); | | 306 | len = OF_getprop(mmu, "translations", map, maxlen); |
299 | } else | | 307 | } else |
300 | len = OF_getproplen(mmu, "translations"); | | 308 | len = OF_getproplen(mmu, "translations"); |
301 | | | 309 | |
302 | if (len < 0) | | 310 | if (len < 0) |
303 | len = 0; | | 311 | len = 0; |
304 | return len; | | 312 | return len; |
305 | } | | 313 | } |
306 | | | 314 | |
307 | | | 315 | |
308 | /* The PMAC_G5 code here needs to be replaced by code that looks for the | | 316 | /* The PMAC_G5 code here needs to be replaced by code that looks for the |
309 | size_cells and does the right thing automatically. | | 317 | size_cells and does the right thing automatically. |
310 | */ | | 318 | */ |
311 | void | | 319 | void |
312 | restore_ofmap(struct ofw_translations *map, int len) | | 320 | restore_ofmap(struct ofw_translations *map, int len) |
313 | { | | 321 | { |
314 | int n = len / sizeof(struct ofw_translations); | | 322 | int n = len / sizeof(struct ofw_translations); |
315 | int i; | | 323 | int i; |
316 | | | 324 | |
317 | pmap_pinit(&ofw_pmap); | | 325 | pmap_pinit(&ofw_pmap); |
318 | | | 326 | |
319 | ofw_pmap.pm_sr[KERNEL_SR] = KERNEL_SEGMENT; | | 327 | ofw_pmap.pm_sr[KERNEL_SR] = KERNEL_SEGMENT; |
320 | | | 328 | |
321 | #ifdef KERNEL2_SR | | 329 | #ifdef KERNEL2_SR |
322 | ofw_pmap.pm_sr[KERNEL2_SR] = KERNEL2_SEGMENT; | | 330 | ofw_pmap.pm_sr[KERNEL2_SR] = KERNEL2_SEGMENT; |
323 | #endif | | 331 | #endif |
324 | | | 332 | |
325 | for (i = 0; i < n; i++) { | | 333 | for (i = 0; i < n; i++) { |
326 | #if defined (PMAC_G5) | | 334 | #if defined (PMAC_G5) |
327 | register64_t pa = map[i].pa; | | 335 | register64_t pa = map[i].pa; |
328 | #else | | 336 | #else |
329 | register_t pa = map[i].pa; | | 337 | register_t pa = map[i].pa; |
330 | #endif | | 338 | #endif |
331 | vaddr_t va = map[i].va; | | 339 | vaddr_t va = map[i].va; |
332 | size_t length = map[i].len; | | 340 | size_t length = map[i].len; |
333 | | | 341 | |
334 | if (va < 0xf0000000) /* XXX */ | | 342 | if (va < 0xf0000000) /* XXX */ |
335 | continue; | | 343 | continue; |
336 | | | 344 | |
337 | while (length > 0) { | | 345 | while (length > 0) { |
338 | pmap_enter(&ofw_pmap, va, (paddr_t)pa, VM_PROT_ALL, | | 346 | pmap_enter(&ofw_pmap, va, (paddr_t)pa, VM_PROT_ALL, |
339 | VM_PROT_ALL|PMAP_WIRED); | | 347 | VM_PROT_ALL|PMAP_WIRED); |
340 | pa += PAGE_SIZE; | | 348 | pa += PAGE_SIZE; |
341 | va += PAGE_SIZE; | | 349 | va += PAGE_SIZE; |
342 | length -= PAGE_SIZE; | | 350 | length -= PAGE_SIZE; |
343 | } | | 351 | } |
344 | } | | 352 | } |
345 | pmap_update(&ofw_pmap); | | 353 | pmap_update(&ofw_pmap); |
346 | } | | 354 | } |
347 | | | 355 | |
348 | | | 356 | |
349 | | | 357 | |
350 | /* | | 358 | /* |
351 | * Scan the device tree for ranges, and return them as bitmap 0..15 | | 359 | * Scan the device tree for ranges, and return them as bitmap 0..15 |
352 | */ | | 360 | */ |
353 | | | 361 | |
354 | static u_int16_t | | 362 | static u_int16_t |
355 | ranges_bitmap(int node, u_int16_t bitmap) | | 363 | ranges_bitmap(int node, u_int16_t bitmap) |
356 | { | | 364 | { |
357 | int child, mlen, acells, scells, reclen, i, j; | | 365 | int child, mlen, acells, scells, reclen, i, j; |
358 | u_int32_t addr, len, map[160]; | | 366 | u_int32_t addr, len, map[160]; |
359 | | | 367 | |
360 | for (child = OF_child(node); child; child = OF_peer(child)) { | | 368 | for (child = OF_child(node); child; child = OF_peer(child)) { |
361 | mlen = OF_getprop(child, "ranges", map, sizeof(map)); | | 369 | mlen = OF_getprop(child, "ranges", map, sizeof(map)); |
362 | if (mlen == -1) | | 370 | if (mlen == -1) |
363 | goto noranges; | | 371 | goto noranges; |
364 | | | 372 | |
365 | j = OF_getprop(child, "#address-cells", &acells, | | 373 | j = OF_getprop(child, "#address-cells", &acells, |
366 | sizeof(acells)); | | 374 | sizeof(acells)); |
367 | if (j == -1) | | 375 | if (j == -1) |
368 | goto noranges; | | 376 | goto noranges; |
369 | | | 377 | |
370 | j = OF_getprop(child, "#size-cells", &scells, | | 378 | j = OF_getprop(child, "#size-cells", &scells, |
371 | sizeof(scells)); | | 379 | sizeof(scells)); |
372 | if (j == -1) | | 380 | if (j == -1) |
373 | goto noranges; | | 381 | goto noranges; |
374 | | | 382 | |
375 | #ifdef ofppc | | 383 | #ifdef ofppc |
376 | reclen = acells + modeldata.ranges_offset + scells; | | 384 | reclen = acells + modeldata.ranges_offset + scells; |
377 | #else | | 385 | #else |
378 | reclen = acells + 1 + scells; | | 386 | reclen = acells + 1 + scells; |
379 | #endif | | 387 | #endif |
380 | | | 388 | |
381 | for (i=0; i < (mlen/4)/reclen; i++) { | | 389 | for (i=0; i < (mlen/4)/reclen; i++) { |
382 | addr = map[reclen * i + acells]; | | 390 | addr = map[reclen * i + acells]; |
383 | len = map[reclen * i + reclen - 1]; | | 391 | len = map[reclen * i + reclen - 1]; |
384 | for (j = 0; j < len / 0x10000000; j++) | | 392 | for (j = 0; j < len / 0x10000000; j++) |
385 | bitmap |= 1 << ((addr+j*0x10000000) >>28); | | 393 | bitmap |= 1 << ((addr+j*0x10000000) >>28); |
386 | bitmap |= 1 << (addr >> 28); | | 394 | bitmap |= 1 << (addr >> 28); |
387 | } | | 395 | } |
388 | noranges: | | 396 | noranges: |
389 | bitmap |= ranges_bitmap(child, bitmap); | | 397 | bitmap |= ranges_bitmap(child, bitmap); |
390 | continue; | | 398 | continue; |
391 | } | | 399 | } |
392 | return bitmap; | | 400 | return bitmap; |
393 | } | | 401 | } |
394 | | | 402 | |
395 | void | | 403 | void |
396 | ofwoea_batinit(void) | | 404 | ofwoea_batinit(void) |
397 | { | | 405 | { |
398 | #if defined (PPC_OEA) | | 406 | #if defined (PPC_OEA) |
399 | u_int16_t bitmap; | | 407 | u_int16_t bitmap; |
400 | int node, i; | | 408 | int node, i; |
401 | | | 409 | |
402 | node = OF_finddevice("/"); | | 410 | node = OF_finddevice("/"); |
403 | bitmap = ranges_bitmap(node, 0); | | 411 | bitmap = ranges_bitmap(node, 0); |
404 | oea_batinit(0); | | 412 | oea_batinit(0); |
405 | | | 413 | |
406 | #ifdef macppc | | 414 | #ifdef macppc |
407 | /* XXX this is a macppc-specific hack */ | | 415 | /* XXX this is a macppc-specific hack */ |
408 | bitmap = 0x8f00; | | 416 | bitmap = 0x8f00; |
409 | #endif | | 417 | #endif |
410 | for (i=1; i < 0x10; i++) { | | 418 | for (i=1; i < 0x10; i++) { |
411 | /* skip the three vital SR regions */ | | 419 | /* skip the three vital SR regions */ |
412 | if (i == USER_SR || i == KERNEL_SR || i == KERNEL2_SR) | | 420 | if (i == USER_SR || i == KERNEL_SR || i == KERNEL2_SR) |
413 | continue; | | 421 | continue; |
414 | if (bitmap & (1 << i)) { | | 422 | if (bitmap & (1 << i)) { |
415 | oea_iobat_add(0x10000000 * i, BAT_BL_256M); | | 423 | oea_iobat_add(0x10000000 * i, BAT_BL_256M); |
416 | DPRINTF("Batmapped 256M at 0x%x\n", 0x10000000 * i); | | 424 | DPRINTF("Batmapped 256M at 0x%x\n", 0x10000000 * i); |
417 | } | | 425 | } |
418 | } | | 426 | } |
419 | #endif /* OEA */ | | 427 | #endif /* OEA */ |
420 | } | | 428 | } |
421 | | | 429 | |
422 | | | 430 | |
423 | /* we define these partially, as we will fill the rest in later */ | | 431 | /* we define these partially, as we will fill the rest in later */ |
424 | struct powerpc_bus_space genppc_isa_io_space_tag = { | | 432 | struct powerpc_bus_space genppc_isa_io_space_tag = { |
425 | .pbs_flags = _BUS_SPACE_LITTLE_ENDIAN|_BUS_SPACE_IO_TYPE, | | 433 | .pbs_flags = _BUS_SPACE_LITTLE_ENDIAN|_BUS_SPACE_IO_TYPE, |
426 | .pbs_base = 0x00000000, | | 434 | .pbs_base = 0x00000000, |
427 | }; | | 435 | }; |
428 | | | 436 | |
429 | struct powerpc_bus_space genppc_isa_mem_space_tag = { | | 437 | struct powerpc_bus_space genppc_isa_mem_space_tag = { |
430 | .pbs_flags = _BUS_SPACE_LITTLE_ENDIAN|_BUS_SPACE_MEM_TYPE, | | 438 | .pbs_flags = _BUS_SPACE_LITTLE_ENDIAN|_BUS_SPACE_MEM_TYPE, |
431 | .pbs_base = 0x00000000, | | 439 | .pbs_base = 0x00000000, |
432 | }; | | 440 | }; |
433 | | | 441 | |
434 | /* This gives us a maximum of 6 PCI busses, assuming both io/mem on each. | | 442 | /* This gives us a maximum of 6 PCI busses, assuming both io/mem on each. |
435 | * Increase if necc. | | 443 | * Increase if necc. |
436 | */ | | 444 | */ |
437 | static char ex_storage[EXSTORAGE_MAX][EXTENT_FIXED_STORAGE_SIZE(EXTMAP_RANGES)] | | 445 | static char ex_storage[EXSTORAGE_MAX][EXTENT_FIXED_STORAGE_SIZE(EXTMAP_RANGES)] |
438 | __attribute__((aligned(8))); | | 446 | __attribute__((aligned(8))); |
439 | | | 447 | |
440 | | | 448 | |
441 | static void | | 449 | static void |
442 | find_ranges(int base, rangemap_t *regions, int *cur, int type) | | 450 | find_ranges(int base, rangemap_t *regions, int *cur, int type) |
443 | { | | 451 | { |
444 | int node, i, len, reclen; | | 452 | int node, i, len, reclen; |
445 | u_int32_t acells, scells, map[160]; | | 453 | u_int32_t acells, scells, map[160]; |
446 | char tmp[32]; | | 454 | char tmp[32]; |
447 | | | 455 | |
448 | node = base; | | 456 | node = base; |
449 | if (OF_getprop(node, "device_type", tmp, sizeof(tmp)) == -1) | | 457 | if (OF_getprop(node, "device_type", tmp, sizeof(tmp)) == -1) |
450 | goto rec; | | 458 | goto rec; |
451 | if ((type == RANGE_TYPE_PCI || type == RANGE_TYPE_FIRSTPCI) && | | 459 | if ((type == RANGE_TYPE_PCI || type == RANGE_TYPE_FIRSTPCI) && |
452 | strcmp("pci", tmp) != 0) | | 460 | strcmp("pci", tmp) != 0) |
453 | goto rec; | | 461 | goto rec; |
454 | if (type == RANGE_TYPE_ISA && strcmp("isa", tmp) != 0) | | 462 | if (type == RANGE_TYPE_ISA && strcmp("isa", tmp) != 0) |
455 | goto rec; | | 463 | goto rec; |
456 | len = OF_getprop(node, "ranges", map, sizeof(map)); | | 464 | len = OF_getprop(node, "ranges", map, sizeof(map)); |
457 | if (len == -1) | | 465 | if (len == -1) |
458 | goto rec; | | 466 | goto rec; |
459 | if (OF_getprop(node, "#address-cells", &acells, | | 467 | if (OF_getprop(node, "#address-cells", &acells, |
460 | sizeof(acells)) != sizeof(acells)) | | 468 | sizeof(acells)) != sizeof(acells)) |
461 | acells = 1; | | 469 | acells = 1; |
462 | if (OF_getprop(node, "#size-cells", &scells, | | 470 | if (OF_getprop(node, "#size-cells", &scells, |
463 | sizeof(scells)) != sizeof(scells)) | | 471 | sizeof(scells)) != sizeof(scells)) |
464 | scells = 1; | | 472 | scells = 1; |
465 | #ifdef ofppc | | 473 | #ifdef ofppc |
466 | if (modeldata.ranges_offset == 0) | | 474 | if (modeldata.ranges_offset == 0) |
467 | scells -= 1; | | 475 | scells -= 1; |
468 | #endif | | 476 | #endif |
469 | if (type == RANGE_TYPE_ISA) | | 477 | if (type == RANGE_TYPE_ISA) |
470 | reclen = 6; | | 478 | reclen = 6; |
471 | else | | 479 | else |
472 | reclen = acells + scells + 1; | | 480 | reclen = acells + scells + 1; |
473 | /* | | 481 | /* |
474 | * There exist ISA buses with empty ranges properties. This is | | 482 | * There exist ISA buses with empty ranges properties. This is |
475 | * known to occur on the Pegasos II machine, and likely others. | | 483 | * known to occur on the Pegasos II machine, and likely others. |
476 | * According to them, that means that the isa bus is a fake bus, and | | 484 | * According to them, that means that the isa bus is a fake bus, and |
477 | * the real maps are the PCI maps of the preceeding bus. To deal | | 485 | * the real maps are the PCI maps of the preceeding bus. To deal |
478 | * with this, we will set cur to -1 and return. | | 486 | * with this, we will set cur to -1 and return. |
479 | */ | | 487 | */ |
480 | if (type == RANGE_TYPE_ISA && strcmp("isa", tmp) == 0 && len == 0) { | | 488 | if (type == RANGE_TYPE_ISA && strcmp("isa", tmp) == 0 && len == 0) { |
481 | *cur = -1; | | 489 | *cur = -1; |
482 | DPRINTF("Found empty range in isa bus\n"); | | 490 | DPRINTF("Found empty range in isa bus\n"); |
483 | return; | | 491 | return; |
484 | } | | 492 | } |
485 | | | 493 | |
486 | DPRINTF("found a map reclen=%d cur=%d len=%d\n", reclen, *cur, len); | | 494 | DPRINTF("found a map reclen=%d cur=%d len=%d\n", reclen, *cur, len); |
487 | switch (type) { | | 495 | switch (type) { |
488 | case RANGE_TYPE_PCI: | | 496 | case RANGE_TYPE_PCI: |
489 | case RANGE_TYPE_FIRSTPCI: | | 497 | case RANGE_TYPE_FIRSTPCI: |
490 | for (i=0; i < len/(4*reclen); i++) { | | 498 | for (i=0; i < len/(4*reclen); i++) { |
491 | DPRINTF("FOUND PCI RANGE\n"); | | 499 | DPRINTF("FOUND PCI RANGE\n"); |
492 | regions[*cur].size = | | 500 | regions[*cur].size = |
493 | map[i*reclen + acells + scells]; | | 501 | map[i*reclen + acells + scells]; |
494 | /* skip ranges of size==0 */ | | 502 | /* skip ranges of size==0 */ |
495 | if (regions[*cur].size == 0) | | 503 | if (regions[*cur].size == 0) |
496 | continue; | | 504 | continue; |
497 | regions[*cur].type = map[i*reclen] >> 24; | | 505 | regions[*cur].type = map[i*reclen] >> 24; |
498 | regions[*cur].addr = map[i*reclen + acells]; | | 506 | regions[*cur].addr = map[i*reclen + acells]; |
499 | (*cur)++; | | 507 | (*cur)++; |
500 | } | | 508 | } |
501 | break; | | 509 | break; |
502 | case RANGE_TYPE_ISA: | | 510 | case RANGE_TYPE_ISA: |
503 | for (i=0; i < len/(4*reclen); i++) { | | 511 | for (i=0; i < len/(4*reclen); i++) { |
504 | if (map[i*reclen] == 1) | | 512 | if (map[i*reclen] == 1) |
505 | regions[*cur].type = RANGE_IO; | | 513 | regions[*cur].type = RANGE_IO; |
506 | else | | 514 | else |
507 | regions[*cur].type = RANGE_MEM; | | 515 | regions[*cur].type = RANGE_MEM; |
508 | DPRINTF("FOUND ISA RANGE TYPE=%d\n", | | 516 | DPRINTF("FOUND ISA RANGE TYPE=%d\n", |
509 | regions[*cur].type); | | 517 | regions[*cur].type); |
510 | regions[*cur].size = | | 518 | regions[*cur].size = |
511 | map[i*reclen + acells + scells]; | | 519 | map[i*reclen + acells + scells]; |
512 | (*cur)++; | | 520 | (*cur)++; |
513 | } | | 521 | } |
514 | break; | | 522 | break; |
515 | } | | 523 | } |
516 | DPRINTF("returning with CUR=%d\n", *cur); | | 524 | DPRINTF("returning with CUR=%d\n", *cur); |
517 | return; | | 525 | return; |
518 | rec: | | 526 | rec: |
519 | for (node = OF_child(base); node; node = OF_peer(node)) { | | 527 | for (node = OF_child(base); node; node = OF_peer(node)) { |
520 | DPRINTF("RECURSE 1 STEP\n"); | | 528 | DPRINTF("RECURSE 1 STEP\n"); |
521 | find_ranges(node, regions, cur, type); | | 529 | find_ranges(node, regions, cur, type); |
522 | if (*cur == -1) | | 530 | if (*cur == -1) |
523 | return; | | 531 | return; |
524 | } | | 532 | } |
525 | } | | 533 | } |
526 | | | 534 | |
527 | static int | | 535 | static int |
528 | find_lowest_range(rangemap_t *ranges, int nrof, int type) | | 536 | find_lowest_range(rangemap_t *ranges, int nrof, int type) |
529 | { | | 537 | { |
530 | int i, low = 0; | | 538 | int i, low = 0; |
531 | u_int32_t addr = 0xffffffff; | | 539 | u_int32_t addr = 0xffffffff; |
532 | | | 540 | |
533 | for (i=0; i < nrof; i++) { | | 541 | for (i=0; i < nrof; i++) { |
534 | if (ranges[i].type == type && ranges[i].addr != 0 && | | 542 | if (ranges[i].type == type && ranges[i].addr != 0 && |
535 | ranges[i].addr < addr) { | | 543 | ranges[i].addr < addr) { |
536 | low = i; | | 544 | low = i; |
537 | addr = ranges[i].addr; | | 545 | addr = ranges[i].addr; |
538 | } | | 546 | } |
539 | } | | 547 | } |
540 | if (addr == 0xffffffff) | | 548 | if (addr == 0xffffffff) |
541 | return -1; | | 549 | return -1; |
542 | return low; | | 550 | return low; |
543 | } | | 551 | } |
544 | | | 552 | |
545 | /* | | 553 | /* |
546 | * Find a region of memory, and create a bus_space_tag for it. | | 554 | * Find a region of memory, and create a bus_space_tag for it. |
547 | * Notes: | | 555 | * Notes: |
548 | * For ISA node is ignored. | | 556 | * For ISA node is ignored. |
549 | * node is the starting node. if -1, we start at / and map everything. | | 557 | * node is the starting node. if -1, we start at / and map everything. |
550 | */ | | 558 | */ |
551 | | | 559 | |
552 | int | | 560 | int |
553 | ofwoea_map_space(int rangetype, int iomem, int node, | | 561 | ofwoea_map_space(int rangetype, int iomem, int node, |
554 | struct powerpc_bus_space *tag, const char *name) | | 562 | struct powerpc_bus_space *tag, const char *name) |
555 | { | | 563 | { |
556 | int i, cur, range, nrofholes, error; | | 564 | int i, cur, range, nrofholes, error; |
557 | static int exmap=0; | | 565 | static int exmap=0; |
558 | u_int32_t addr; | | 566 | u_int32_t addr; |
559 | rangemap_t region, holes[32], list[32]; | | 567 | rangemap_t region, holes[32], list[32]; |
560 | | | 568 | |
561 | memset(list, 0, sizeof(list)); | | 569 | memset(list, 0, sizeof(list)); |
562 | cur = 0; | | 570 | cur = 0; |
563 | if (rangetype == RANGE_TYPE_ISA || node == -1) | | 571 | if (rangetype == RANGE_TYPE_ISA || node == -1) |
564 | node = OF_finddevice("/"); | | 572 | node = OF_finddevice("/"); |
565 | if (rangetype == RANGE_TYPE_ISA) { | | 573 | if (rangetype == RANGE_TYPE_ISA) { |
566 | u_int32_t size = 0; | | 574 | u_int32_t size = 0; |
567 | rangemap_t regions[32]; | | 575 | rangemap_t regions[32]; |
568 | | | 576 | |
569 | DPRINTF("LOOKING FOR FIRSTPCI\n"); | | 577 | DPRINTF("LOOKING FOR FIRSTPCI\n"); |
570 | find_ranges(node, list, &cur, RANGE_TYPE_FIRSTPCI); | | 578 | find_ranges(node, list, &cur, RANGE_TYPE_FIRSTPCI); |
571 | range = 0; | | 579 | range = 0; |
572 | DPRINTF("LOOKING FOR ISA\n"); | | 580 | DPRINTF("LOOKING FOR ISA\n"); |
573 | find_ranges(node, regions, &range, RANGE_TYPE_ISA); | | 581 | find_ranges(node, regions, &range, RANGE_TYPE_ISA); |
574 | if (range == 0 || cur == 0) | | 582 | if (range == 0 || cur == 0) |
575 | return -1; /* no isa stuff found */ | | 583 | return -1; /* no isa stuff found */ |
576 | /* | | 584 | /* |
577 | * This may be confusing to some. The ISA ranges property | | 585 | * This may be confusing to some. The ISA ranges property |
578 | * is supposed to be a set of IO ranges for the ISA bus, but | | 586 | * is supposed to be a set of IO ranges for the ISA bus, but |
579 | * generally, it's just a set of pci devfunc lists that tell | | 587 | * generally, it's just a set of pci devfunc lists that tell |
580 | * you to go look at the parent PCI device for the actual | | 588 | * you to go look at the parent PCI device for the actual |
581 | * ranges. | | 589 | * ranges. |
582 | */ | | 590 | */ |
583 | if (range == -1) { | | 591 | if (range == -1) { |
584 | /* we found a rangeless isa bus */ | | 592 | /* we found a rangeless isa bus */ |
585 | if (iomem == RANGE_IO) | | 593 | if (iomem == RANGE_IO) |
586 | size = 0x10000; | | 594 | size = 0x10000; |
587 | else | | 595 | else |
588 | size = 0x1000000; | | 596 | size = 0x1000000; |
589 | } | | 597 | } |
590 | DPRINTF("found isa stuff\n"); | | 598 | DPRINTF("found isa stuff\n"); |
591 | for (i=0; i < range; i++) | | 599 | for (i=0; i < range; i++) |
592 | if (regions[i].type == iomem) | | 600 | if (regions[i].type == iomem) |
593 | size = regions[i].size; | | 601 | size = regions[i].size; |
594 | if (iomem == RANGE_IO) { | | 602 | if (iomem == RANGE_IO) { |
595 | /* the first io range is the one */ | | 603 | /* the first io range is the one */ |
596 | for (i=0; i < cur; i++) | | 604 | for (i=0; i < cur; i++) |
597 | if (list[i].type == RANGE_IO && size) { | | 605 | if (list[i].type == RANGE_IO && size) { |
598 | DPRINTF("found IO\n"); | | 606 | DPRINTF("found IO\n"); |
599 | tag->pbs_offset = list[i].addr; | | 607 | tag->pbs_offset = list[i].addr; |
600 | tag->pbs_limit = size; | | 608 | tag->pbs_limit = size; |
601 | error = bus_space_init(tag, name, | | 609 | error = bus_space_init(tag, name, |
602 | ex_storage[exmap], | | 610 | ex_storage[exmap], |
603 | sizeof(ex_storage[exmap])); | | 611 | sizeof(ex_storage[exmap])); |
604 | exmap++; | | 612 | exmap++; |
605 | return error; | | 613 | return error; |
606 | } | | 614 | } |
607 | } else { | | 615 | } else { |
608 | for (i=0; i < cur; i++) | | 616 | for (i=0; i < cur; i++) |
609 | if (list[i].type == RANGE_MEM && | | 617 | if (list[i].type == RANGE_MEM && |
610 | list[i].size == size) { | | 618 | list[i].size == size) { |
611 | DPRINTF("found mem\n"); | | 619 | DPRINTF("found mem\n"); |
612 | tag->pbs_offset = list[i].addr; | | 620 | tag->pbs_offset = list[i].addr; |
613 | tag->pbs_limit = size; | | 621 | tag->pbs_limit = size; |
614 | error = bus_space_init(tag, name, | | 622 | error = bus_space_init(tag, name, |
615 | ex_storage[exmap], | | 623 | ex_storage[exmap], |
616 | sizeof(ex_storage[exmap])); | | 624 | sizeof(ex_storage[exmap])); |
617 | exmap++; | | 625 | exmap++; |
618 | return error; | | 626 | return error; |
619 | } | | 627 | } |
620 | } | | 628 | } |
621 | return -1; /* NO ISA FOUND */ | | 629 | return -1; /* NO ISA FOUND */ |
622 | } | | 630 | } |
623 | find_ranges(node, list, &cur, rangetype); | | 631 | find_ranges(node, list, &cur, rangetype); |
624 | | | 632 | |
625 | DPRINTF("cur == %d\n", cur); | | 633 | DPRINTF("cur == %d\n", cur); |
626 | /* now list should contain a list of memory regions */ | | 634 | /* now list should contain a list of memory regions */ |
627 | for (i=0; i < cur; i++) | | 635 | for (i=0; i < cur; i++) |
628 | DPRINTF("addr=0x%x size=0x%x type=%d\n", list[i].addr, | | 636 | DPRINTF("addr=0x%x size=0x%x type=%d\n", list[i].addr, |
629 | list[i].size, list[i].type); | | 637 | list[i].size, list[i].type); |
630 | | | 638 | |
631 | addr=0; | | 639 | addr=0; |
632 | range = find_lowest_range(list, cur, iomem); | | 640 | range = find_lowest_range(list, cur, iomem); |
633 | i = 0; | | 641 | i = 0; |
634 | nrofholes = 0; | | 642 | nrofholes = 0; |
635 | while (range != -1) { | | 643 | while (range != -1) { |
636 | DPRINTF("range==%d\n", range); | | 644 | DPRINTF("range==%d\n", range); |
637 | DPRINTF("i==%d\n", i); | | 645 | DPRINTF("i==%d\n", i); |
638 | if (i == 0) { | | 646 | if (i == 0) { |
639 | memcpy(®ion, &list[range], sizeof(rangemap_t)); | | 647 | memcpy(®ion, &list[range], sizeof(rangemap_t)); |
640 | list[range].addr = 0; | | 648 | list[range].addr = 0; |
641 | i++; | | 649 | i++; |
642 | range = find_lowest_range(list, cur, iomem); | | 650 | range = find_lowest_range(list, cur, iomem); |
643 | continue; | | 651 | continue; |
644 | } | | 652 | } |
645 | if (region.addr + region.size < list[range].addr) { | | 653 | if (region.addr + region.size < list[range].addr) { |
646 | /* allocate a hole */ | | 654 | /* allocate a hole */ |
647 | holes[nrofholes].type = iomem; | | 655 | holes[nrofholes].type = iomem; |
648 | holes[nrofholes].addr = region.size + region.addr; | | 656 | holes[nrofholes].addr = region.size + region.addr; |
649 | holes[nrofholes].size = list[range].addr - | | 657 | holes[nrofholes].size = list[range].addr - |
650 | holes[nrofholes].addr - 1; | | 658 | holes[nrofholes].addr - 1; |
651 | nrofholes++; | | 659 | nrofholes++; |
652 | } | | 660 | } |
653 | region.size = list[range].size + list[range].addr - | | 661 | region.size = list[range].size + list[range].addr - |
654 | region.addr; | | 662 | region.addr; |
655 | list[range].addr = 0; | | 663 | list[range].addr = 0; |
656 | range = find_lowest_range(list, cur, iomem); | | 664 | range = find_lowest_range(list, cur, iomem); |
657 | } | | 665 | } |
658 | DPRINTF("RANGE iomem=%d FOUND\n", iomem); | | 666 | DPRINTF("RANGE iomem=%d FOUND\n", iomem); |
659 | DPRINTF("addr=0x%x size=0x%x type=%d\n", region.addr, | | 667 | DPRINTF("addr=0x%x size=0x%x type=%d\n", region.addr, |
660 | region.size, region.type); | | 668 | region.size, region.type); |
661 | DPRINTF("HOLES FOUND\n"); | | 669 | DPRINTF("HOLES FOUND\n"); |
662 | for (i=0; i < nrofholes; i++) | | 670 | for (i=0; i < nrofholes; i++) |
663 | DPRINTF("addr=0x%x size=0x%x type=%d\n", holes[i].addr, | | 671 | DPRINTF("addr=0x%x size=0x%x type=%d\n", holes[i].addr, |
664 | holes[i].size, holes[i].type); | | 672 | holes[i].size, holes[i].type); |
665 | /* AT THIS POINT WE MAP IT */ | | 673 | /* AT THIS POINT WE MAP IT */ |
666 | | | 674 | |
667 | if (rangetype == RANGE_TYPE_PCI) { | | 675 | if (rangetype == RANGE_TYPE_PCI) { |
668 | if (exmap == EXSTORAGE_MAX) | | 676 | if (exmap == EXSTORAGE_MAX) |
669 | panic("Not enough ex_storage space. " | | 677 | panic("Not enough ex_storage space. " |
670 | "Increase EXSTORAGE_MAX"); | | 678 | "Increase EXSTORAGE_MAX"); |
671 | | | 679 | |
672 | /* XXX doing this in here might be wrong */ | | 680 | /* XXX doing this in here might be wrong */ |
673 | if (iomem == 1) { | | 681 | if (iomem == 1) { |
674 | /* we map an IO region */ | | 682 | /* we map an IO region */ |
675 | tag->pbs_offset = region.addr; | | 683 | tag->pbs_offset = region.addr; |
676 | tag->pbs_base = 0; | | 684 | tag->pbs_base = 0; |
677 | tag->pbs_limit = region.size; | | 685 | tag->pbs_limit = region.size; |
678 | } else { | | 686 | } else { |
679 | /* ... or a memory region */ | | 687 | /* ... or a memory region */ |
680 | tag->pbs_offset = 0; | | 688 | tag->pbs_offset = 0; |
681 | tag->pbs_base = region.addr; | | 689 | tag->pbs_base = region.addr; |
682 | tag->pbs_limit = region.size + region.addr; | | 690 | tag->pbs_limit = region.size + region.addr; |
683 | } | | 691 | } |
684 | | | 692 | |
685 | error = bus_space_init(tag, name, ex_storage[exmap], | | 693 | error = bus_space_init(tag, name, ex_storage[exmap], |
686 | sizeof(ex_storage[exmap])); | | 694 | sizeof(ex_storage[exmap])); |
687 | exmap++; | | 695 | exmap++; |
688 | if (error) | | 696 | if (error) |
689 | panic("ofwoea_bus_space_init: can't init tag %s", name); | | 697 | panic("ofwoea_bus_space_init: can't init tag %s", name); |
690 | for (i=0; i < nrofholes; i++) { | | 698 | for (i=0; i < nrofholes; i++) { |
691 | if (holes[i].type == RANGE_IO) { | | 699 | if (holes[i].type == RANGE_IO) { |
692 | error = extent_alloc_region(tag->pbs_extent, | | 700 | error = extent_alloc_region(tag->pbs_extent, |
693 | holes[i].addr - tag->pbs_offset, | | 701 | holes[i].addr - tag->pbs_offset, |
694 | holes[i].size, EX_NOWAIT); | | 702 | holes[i].size, EX_NOWAIT); |
695 | } else { | | 703 | } else { |
696 | error = extent_alloc_region(tag->pbs_extent, | | 704 | error = extent_alloc_region(tag->pbs_extent, |
697 | holes[i].addr, holes[i].size, EX_NOWAIT); | | 705 | holes[i].addr, holes[i].size, EX_NOWAIT); |
698 | } | | 706 | } |
699 | if (error) | | 707 | if (error) |
700 | panic("ofwoea_bus_space_init: can't block out" | | 708 | panic("ofwoea_bus_space_init: can't block out" |
701 | " reserved space 0x%x-0x%x: error=%d", | | 709 | " reserved space 0x%x-0x%x: error=%d", |
702 | holes[i].addr, holes[i].addr+holes[i].size, | | 710 | holes[i].addr, holes[i].addr+holes[i].size, |
703 | error); | | 711 | error); |
704 | } | | 712 | } |
705 | return error; | | 713 | return error; |
706 | } | | 714 | } |
707 | return -1; | | 715 | return -1; |
708 | } | | 716 | } |
709 | | | 717 | |
710 | void | | 718 | void |
711 | ofwoea_bus_space_init(void) | | 719 | ofwoea_bus_space_init(void) |
712 | { | | 720 | { |
713 | int error; | | 721 | int error; |
714 | | | 722 | |
715 | error = ofwoea_map_space(RANGE_TYPE_ISA, RANGE_IO, -1, | | 723 | error = ofwoea_map_space(RANGE_TYPE_ISA, RANGE_IO, -1, |
716 | &genppc_isa_io_space_tag, "isa-ioport"); | | 724 | &genppc_isa_io_space_tag, "isa-ioport"); |
717 | if (error > 0) | | 725 | if (error > 0) |
718 | panic("Could not map ISA IO"); | | 726 | panic("Could not map ISA IO"); |
719 | | | 727 | |
720 | error = ofwoea_map_space(RANGE_TYPE_ISA, RANGE_MEM, -1, | | 728 | error = ofwoea_map_space(RANGE_TYPE_ISA, RANGE_MEM, -1, |
721 | &genppc_isa_mem_space_tag, "isa-iomem"); | | 729 | &genppc_isa_mem_space_tag, "isa-iomem"); |
722 | if (error > 0) | | 730 | if (error > 0) |
723 | panic("Could not map ISA MEM"); | | 731 | panic("Could not map ISA MEM"); |
724 | } | | 732 | } |