xref: /netbsd/sys/arch/powerpc/powerpc/bus_space.c (revision 6550d01e)
1 /*	$NetBSD: bus_space.c,v 1.24 2011/01/18 01:02:55 matt Exp $	*/
2 
3 /*-
4  * Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9  * NASA Ames Research Center.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: bus_space.c,v 1.24 2011/01/18 01:02:55 matt Exp $");
35 
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/kernel.h>
39 #include <sys/device.h>
40 #include <sys/endian.h>
41 #include <sys/extent.h>
42 #include <sys/malloc.h>
43 
44 #include <uvm/uvm.h>
45 
46 #define _POWERPC_BUS_SPACE_PRIVATE
47 #include <machine/bus.h>
48 
49 #if defined (PPC_OEA) || defined(PPC_OEA64) || defined (PPC_OEA64_BRIDGE)
50 #include <powerpc/spr.h>
51 #include <powerpc/oea/bat.h>
52 #include <powerpc/oea/cpufeat.h>
53 #include <powerpc/oea/pte.h>
54 #include <powerpc/oea/spr.h>
55 #include <powerpc/oea/sr_601.h>
56 
57 extern unsigned long oeacpufeat;
58 #endif
59 
60 /* read_N */
61 u_int8_t bsr1(bus_space_tag_t, bus_space_handle_t, bus_size_t);
62 u_int16_t bsr2(bus_space_tag_t, bus_space_handle_t, bus_size_t);
63 u_int32_t bsr4(bus_space_tag_t, bus_space_handle_t, bus_size_t);
64 u_int64_t bsr8(bus_space_tag_t, bus_space_handle_t, bus_size_t);
65 
66 /* write_N */
67 void bsw1(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int8_t);
68 void bsw2(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int16_t);
69 void bsw4(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int32_t);
70 void bsw8(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int64_t);
71 
72 static const struct powerpc_bus_space_scalar scalar_ops = {
73 	bsr1, bsr2, bsr4, bsr8,
74 	bsw1, bsw2, bsw4, bsw8
75 };
76 
77 /* read_N byte reverse */
78 u_int16_t bsr2rb(bus_space_tag_t, bus_space_handle_t, bus_size_t);
79 u_int32_t bsr4rb(bus_space_tag_t, bus_space_handle_t, bus_size_t);
80 u_int64_t bsr8rb(bus_space_tag_t, bus_space_handle_t, bus_size_t);
81 
82 /* write_N byte reverse */
83 void bsw2rb(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int16_t);
84 void bsw4rb(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int32_t);
85 void bsw8rb(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int64_t);
86 
87 static const struct powerpc_bus_space_scalar scalar_rb_ops = {
88 	bsr1, bsr2rb, bsr4rb, bsr8rb,
89 	bsw1, bsw2rb, bsw4rb, bsw8rb
90 };
91 
92 /* read_multi_N */
93 void bsrm1(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int8_t *,
94 	size_t);
95 void bsrm2(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int16_t *,
96 	size_t);
97 void bsrm4(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int32_t *,
98 	size_t);
99 void bsrm8(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int64_t *,
100 	size_t);
101 
102 /* write_multi_N */
103 void bswm1(bus_space_tag_t, bus_space_handle_t, bus_size_t,
104 	const u_int8_t *, size_t);
105 void bswm2(bus_space_tag_t, bus_space_handle_t, bus_size_t,
106 	const u_int16_t *, size_t);
107 void bswm4(bus_space_tag_t, bus_space_handle_t, bus_size_t,
108 	const u_int32_t *, size_t);
109 void bswm8(bus_space_tag_t, bus_space_handle_t, bus_size_t,
110 	const u_int64_t *, size_t);
111 
112 static const struct powerpc_bus_space_group multi_ops = {
113 	bsrm1, bsrm2, bsrm4, bsrm8,
114 	bswm1, bswm2, bswm4, bswm8
115 };
116 
117 /* read_multi_N byte reversed */
118 void bsrm2rb(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int16_t *,
119 	size_t);
120 void bsrm4rb(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int32_t *,
121 	size_t);
122 void bsrm8rb(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int64_t *,
123 	size_t);
124 
125 /* write_multi_N byte reversed */
126 void bswm2rb(bus_space_tag_t, bus_space_handle_t, bus_size_t,
127 	const u_int16_t *, size_t);
128 void bswm4rb(bus_space_tag_t, bus_space_handle_t, bus_size_t,
129 	const u_int32_t *, size_t);
130 void bswm8rb(bus_space_tag_t, bus_space_handle_t, bus_size_t,
131 	const u_int64_t *, size_t);
132 
133 static const struct powerpc_bus_space_group multi_rb_ops = {
134 	bsrm1, bsrm2rb, bsrm4rb, bsrm8rb,
135 	bswm1, bswm2rb, bswm4rb, bswm8rb
136 };
137 
138 /* read_region_N */
139 void bsrr1(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int8_t *,
140 	size_t);
141 void bsrr2(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int16_t *,
142 	size_t);
143 void bsrr4(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int32_t *,
144 	size_t);
145 void bsrr8(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int64_t *,
146 	size_t);
147 
148 /* write_region_N */
149 void bswr1(bus_space_tag_t, bus_space_handle_t, bus_size_t,
150 	const u_int8_t *, size_t);
151 void bswr2(bus_space_tag_t, bus_space_handle_t, bus_size_t,
152 	const u_int16_t *, size_t);
153 void bswr4(bus_space_tag_t, bus_space_handle_t, bus_size_t,
154 	const u_int32_t *, size_t);
155 void bswr8(bus_space_tag_t, bus_space_handle_t, bus_size_t,
156 	const u_int64_t *, size_t);
157 
158 static const struct powerpc_bus_space_group region_ops = {
159 	bsrr1, bsrr2, bsrr4, bsrr8,
160 	bswr1, bswr2, bswr4, bswr8
161 };
162 
163 void bsrr2rb(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int16_t *,
164 	size_t);
165 void bsrr4rb(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int32_t *,
166 	size_t);
167 void bsrr8rb(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int64_t *,
168 	size_t);
169 
170 void bswr2rb(bus_space_tag_t, bus_space_handle_t, bus_size_t,
171 	const u_int16_t *, size_t);
172 void bswr4rb(bus_space_tag_t, bus_space_handle_t, bus_size_t,
173 	const u_int32_t *, size_t);
174 void bswr8rb(bus_space_tag_t, bus_space_handle_t, bus_size_t,
175 	const u_int64_t *, size_t);
176 
177 static const struct powerpc_bus_space_group region_rb_ops = {
178 	bsrr1, bsrr2rb, bsrr4rb, bsrr8rb,
179 	bswr1, bswr2rb, bswr4rb, bswr8rb
180 };
181 
182 /* set_region_n */
183 void bssr1(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int8_t,
184 	size_t);
185 void bssr2(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int16_t,
186 	size_t);
187 void bssr4(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int32_t,
188 	size_t);
189 void bssr8(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int64_t,
190 	size_t);
191 
192 static const struct powerpc_bus_space_set set_ops = {
193 	bssr1, bssr2, bssr4, bssr8,
194 };
195 
196 void bssr2rb(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int16_t,
197 	size_t);
198 void bssr4rb(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int32_t,
199 	size_t);
200 void bssr8rb(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int64_t,
201 	size_t);
202 
203 static const struct powerpc_bus_space_set set_rb_ops = {
204 	bssr1, bssr2rb, bssr4rb, bssr8rb,
205 };
206 
207 /* copy_region_N */
208 void bscr1(bus_space_tag_t, bus_space_handle_t,
209     bus_size_t, bus_space_handle_t, bus_size_t, size_t);
210 void bscr2(bus_space_tag_t, bus_space_handle_t,
211     bus_size_t, bus_space_handle_t, bus_size_t, size_t);
212 void bscr4(bus_space_tag_t, bus_space_handle_t,
213     bus_size_t, bus_space_handle_t, bus_size_t, size_t);
214 void bscr8(bus_space_tag_t, bus_space_handle_t,
215     bus_size_t, bus_space_handle_t, bus_size_t, size_t);
216 
217 static const struct powerpc_bus_space_copy copy_ops = {
218 	bscr1, bscr2, bscr4, bscr8
219 };
220 
221 /*
222  * Strided versions
223  */
224 /* read_N */
225 u_int8_t bsr1_s(bus_space_tag_t, bus_space_handle_t, bus_size_t);
226 u_int16_t bsr2_s(bus_space_tag_t, bus_space_handle_t, bus_size_t);
227 u_int32_t bsr4_s(bus_space_tag_t, bus_space_handle_t, bus_size_t);
228 u_int64_t bsr8_s(bus_space_tag_t, bus_space_handle_t, bus_size_t);
229 
230 /* write_N */
231 void bsw1_s(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int8_t);
232 void bsw2_s(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int16_t);
233 void bsw4_s(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int32_t);
234 void bsw8_s(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int64_t);
235 
236 static const struct powerpc_bus_space_scalar scalar_strided_ops = {
237 	bsr1_s, bsr2_s, bsr4_s, bsr8_s,
238 	bsw1_s, bsw2_s, bsw4_s, bsw8_s
239 };
240 
241 /* read_N */
242 u_int16_t bsr2rb_s(bus_space_tag_t, bus_space_handle_t, bus_size_t);
243 u_int32_t bsr4rb_s(bus_space_tag_t, bus_space_handle_t, bus_size_t);
244 u_int64_t bsr8rb_s(bus_space_tag_t, bus_space_handle_t, bus_size_t);
245 
246 /* write_N */
247 void bsw2rb_s(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int16_t);
248 void bsw4rb_s(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int32_t);
249 void bsw8rb_s(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int64_t);
250 
251 static const struct powerpc_bus_space_scalar scalar_rb_strided_ops = {
252 	bsr1_s, bsr2rb_s, bsr4rb_s, bsr8rb_s,
253 	bsw1_s, bsw2rb_s, bsw4rb_s, bsw8rb_s
254 };
255 
256 /* read_multi_N */
257 void bsrm1_s(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int8_t *,
258 	size_t);
259 void bsrm2_s(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int16_t *,
260 	size_t);
261 void bsrm4_s(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int32_t *,
262 	size_t);
263 void bsrm8_s(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int64_t *,
264 	size_t);
265 
266 /* write_multi_N */
267 void bswm1_s(bus_space_tag_t, bus_space_handle_t, bus_size_t,
268 	const u_int8_t *, size_t);
269 void bswm2_s(bus_space_tag_t, bus_space_handle_t, bus_size_t,
270 	const u_int16_t *, size_t);
271 void bswm4_s(bus_space_tag_t, bus_space_handle_t, bus_size_t,
272 	const u_int32_t *, size_t);
273 void bswm8_s(bus_space_tag_t, bus_space_handle_t, bus_size_t,
274 	const u_int64_t *, size_t);
275 
276 static const struct powerpc_bus_space_group multi_strided_ops = {
277 	bsrm1_s, bsrm2_s, bsrm4_s, bsrm8_s,
278 	bswm1_s, bswm2_s, bswm4_s, bswm8_s
279 };
280 
281 /* read_multi_N */
282 void bsrm2rb_s(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int16_t *,
283 	size_t);
284 void bsrm4rb_s(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int32_t *,
285 	size_t);
286 void bsrm8rb_s(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int64_t *,
287 	size_t);
288 
289 /* write_multi_N */
290 void bswm2rb_s(bus_space_tag_t, bus_space_handle_t, bus_size_t,
291 	const u_int16_t *, size_t);
292 void bswm4rb_s(bus_space_tag_t, bus_space_handle_t, bus_size_t,
293 	const u_int32_t *, size_t);
294 void bswm8rb_s(bus_space_tag_t, bus_space_handle_t, bus_size_t,
295 	const u_int64_t *, size_t);
296 
297 static const struct powerpc_bus_space_group multi_rb_strided_ops = {
298 	bsrm1_s, bsrm2rb_s, bsrm4rb_s, bsrm8rb_s,
299 	bswm1_s, bswm2rb_s, bswm4rb_s, bswm8rb_s
300 };
301 
302 /* read_region_N */
303 void bsrr1_s(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int8_t *,
304 	size_t);
305 void bsrr2_s(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int16_t *,
306 	size_t);
307 void bsrr4_s(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int32_t *,
308 	size_t);
309 void bsrr8_s(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int64_t *,
310 	size_t);
311 
312 /* write_region_N */
313 void bswr1_s(bus_space_tag_t, bus_space_handle_t, bus_size_t,
314 	const u_int8_t *, size_t);
315 void bswr2_s(bus_space_tag_t, bus_space_handle_t, bus_size_t,
316 	const u_int16_t *, size_t);
317 void bswr4_s(bus_space_tag_t, bus_space_handle_t, bus_size_t,
318 	const u_int32_t *, size_t);
319 void bswr8_s(bus_space_tag_t, bus_space_handle_t, bus_size_t,
320 	const u_int64_t *, size_t);
321 
322 static const struct powerpc_bus_space_group region_strided_ops = {
323 	bsrr1_s, bsrr2_s, bsrr4_s, bsrr8_s,
324 	bswr1_s, bswr2_s, bswr4_s, bswr8_s
325 };
326 
327 /* read_region_N */
328 void bsrr2rb_s(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int16_t *,
329 	size_t);
330 void bsrr4rb_s(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int32_t *,
331 	size_t);
332 void bsrr8rb_s(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int64_t *,
333 	size_t);
334 
335 /* write_region_N */
336 void bswr2rb_s(bus_space_tag_t, bus_space_handle_t, bus_size_t,
337 	const u_int16_t *, size_t);
338 void bswr4rb_s(bus_space_tag_t, bus_space_handle_t, bus_size_t,
339 	const u_int32_t *, size_t);
340 void bswr8rb_s(bus_space_tag_t, bus_space_handle_t, bus_size_t,
341 	const u_int64_t *, size_t);
342 
343 static const struct powerpc_bus_space_group region_rb_strided_ops = {
344 	bsrr1_s, bsrr2rb_s, bsrr4rb_s, bsrr8rb_s,
345 	bswr1_s, bswr2rb_s, bswr4rb_s, bswr8rb_s
346 };
347 
348 /* set_region_N */
349 void bssr1_s(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int8_t,
350 	size_t);
351 void bssr2_s(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int16_t,
352 	size_t);
353 void bssr4_s(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int32_t,
354 	size_t);
355 void bssr8_s(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int64_t,
356 	size_t);
357 
358 static const struct powerpc_bus_space_set set_strided_ops = {
359 	bssr1_s, bssr2_s, bssr4_s, bssr8_s,
360 };
361 
362 /* set_region_N */
363 void bssr2rb_s(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int16_t,
364 	size_t);
365 void bssr4rb_s(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int32_t,
366 	size_t);
367 void bssr8rb_s(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int64_t,
368 	size_t);
369 
370 static const struct powerpc_bus_space_set set_rb_strided_ops = {
371 	bssr1_s, bssr2rb_s, bssr4rb_s, bssr8rb_s,
372 };
373 
374 /* copy_region_N */
375 void bscr1_s(bus_space_tag_t, bus_space_handle_t, bus_size_t,
376 	bus_space_handle_t, bus_size_t, size_t);
377 void bscr2_s(bus_space_tag_t, bus_space_handle_t, bus_size_t,
378 	bus_space_handle_t, bus_size_t, size_t);
379 void bscr4_s(bus_space_tag_t, bus_space_handle_t, bus_size_t,
380 	bus_space_handle_t, bus_size_t, size_t);
381 void bscr8_s(bus_space_tag_t, bus_space_handle_t, bus_size_t,
382 	bus_space_handle_t, bus_size_t, size_t);
383 
384 static const struct powerpc_bus_space_copy copy_strided_ops = {
385 	bscr1_s, bscr2_s, bscr4_s, bscr8_s
386 };
387 
388 static paddr_t memio_mmap(bus_space_tag_t, bus_addr_t, off_t, int, int);
389 static int memio_map(bus_space_tag_t, bus_addr_t, bus_size_t, int,
390 	bus_space_handle_t *);
391 static int memio_subregion(bus_space_tag_t, bus_space_handle_t, bus_size_t,
392 	bus_size_t, bus_space_handle_t *);
393 static void memio_unmap(bus_space_tag_t, bus_space_handle_t, bus_size_t);
394 static int memio_alloc(bus_space_tag_t, bus_addr_t, bus_addr_t, bus_size_t,
395 	bus_size_t, bus_size_t, int, bus_addr_t *, bus_space_handle_t *);
396 static void memio_free(bus_space_tag_t, bus_space_handle_t, bus_size_t);
397 
398 static int extent_flags;
399 
400 int
401 bus_space_init(struct powerpc_bus_space *t, const char *extent_name,
402 	void *storage, size_t storage_size)
403 {
404 	if (t->pbs_extent == NULL && extent_name != NULL) {
405 		t->pbs_extent = extent_create(extent_name, t->pbs_base,
406 		    t->pbs_limit-1, M_DEVBUF, storage, storage_size,
407 		    EX_NOCOALESCE|EX_NOWAIT);
408 		if (t->pbs_extent == NULL)
409 			return ENOMEM;
410 	}
411 
412 	t->pbs_mmap = memio_mmap;
413 	t->pbs_map = memio_map;
414 	t->pbs_subregion = memio_subregion;
415 	t->pbs_unmap = memio_unmap;
416 	t->pbs_alloc = memio_alloc;
417 	t->pbs_free = memio_free;
418 
419 	if (t->pbs_flags & _BUS_SPACE_STRIDE_MASK) {
420 		t->pbs_scalar_stream = scalar_strided_ops;
421 		t->pbs_multi_stream = &multi_strided_ops;
422 		t->pbs_region_stream = &region_strided_ops;
423 		t->pbs_set_stream = &set_strided_ops;
424 		t->pbs_copy = &copy_strided_ops;
425 	} else {
426 		t->pbs_scalar_stream = scalar_ops;
427 		t->pbs_multi_stream = &multi_ops;
428 		t->pbs_region_stream = &region_ops;
429 		t->pbs_set_stream = &set_ops;
430 		t->pbs_copy = &copy_ops;
431 	}
432 
433 #if BYTE_ORDER == BIG_ENDIAN
434 	if (t->pbs_flags & _BUS_SPACE_BIG_ENDIAN) {
435 		if (t->pbs_flags & _BUS_SPACE_STRIDE_MASK) {
436 			t->pbs_scalar = scalar_strided_ops;
437 			t->pbs_multi = &multi_strided_ops;
438 			t->pbs_region = &region_strided_ops;
439 			t->pbs_set = &set_strided_ops;
440 		} else {
441 			t->pbs_scalar = scalar_ops;
442 			t->pbs_multi = &multi_ops;
443 			t->pbs_region = &region_ops;
444 			t->pbs_set = &set_ops;
445 		}
446 	} else {
447 		if (t->pbs_flags & _BUS_SPACE_STRIDE_MASK) {
448 			t->pbs_scalar = scalar_rb_strided_ops;
449 			t->pbs_multi = &multi_rb_strided_ops;
450 			t->pbs_region = &region_rb_strided_ops;
451 			t->pbs_set = &set_rb_strided_ops;
452 		} else {
453 			t->pbs_scalar = scalar_rb_ops;
454 			t->pbs_multi = &multi_rb_ops;
455 			t->pbs_region = &region_rb_ops;
456 			t->pbs_set = &set_rb_ops;
457 		}
458 	}
459 #else
460 	if (t->pbs_flags & _BUS_SPACE_LITTLE_ENDIAN) {
461 		if (t->pbs_flags & _BUS_SPACE_STRIDE_MASK) {
462 			t->pbs_scalar = scalar_strided_ops;
463 			t->pbs_multi = &multi_strided_ops;
464 			t->pbs_region = &region_strided_ops;
465 			t->pbs_set = &set_strided_ops;
466 		} else {
467 			t->pbs_scalar = scalar_ops;
468 			t->pbs_multi = &multi_ops;
469 			t->pbs_region = &region_ops;
470 			t->pbs_set = &set_ops;
471 		}
472 	} else {
473 		if (t->pbs_flags & _BUS_SPACE_STRIDE_MASK) {
474 			t->pbs_scalar = scalar_rb_strided_ops;
475 			t->pbs_multi = &multi_rb_strided_ops;
476 			t->pbs_region = &region_rb_strided_ops;
477 			t->pbs_set = &set_rb_strided_ops;
478 		} else {
479 			t->pbs_scalar = scalar_rb_ops;
480 			t->pbs_multi = &multi_rb_ops;
481 			t->pbs_region = &region_rb_ops;
482 			t->pbs_set = &set_rb_ops;
483 		}
484 	}
485 #endif
486 	return 0;
487 }
488 
489 void
490 bus_space_mallocok(void)
491 {
492 	extent_flags = EX_MALLOCOK;
493 }
494 
495 /* ARGSUSED */
496 paddr_t
497 memio_mmap(bus_space_tag_t t, bus_addr_t bpa, off_t offset, int prot, int flags)
498 {
499 	paddr_t ret;
500 	/* XXX what about stride? */
501 	ret = trunc_page(t->pbs_offset + bpa + offset);
502 #ifdef DEBUG
503 	if (ret == 0) {
504 		printf("%s: [%08x, %08x %08x] mmaps to 0?!\n", __func__,
505 		    (uint32_t)t->pbs_offset, (uint32_t)bpa, (uint32_t)offset);
506 		return -1;
507 	}
508 #endif
509 	return ret;
510 }
511 
512 int
513 memio_map(bus_space_tag_t t, bus_addr_t bpa, bus_size_t size, int flags,
514 	bus_space_handle_t *bshp)
515 {
516 	int error;
517 	paddr_t pa;
518 
519 	size = _BUS_SPACE_STRIDE(t, size);
520 	bpa = _BUS_SPACE_STRIDE(t, bpa);
521 
522 	if (bpa + size > t->pbs_limit) {
523 #ifdef DEBUG
524 		printf("bus_space_map(%p[%x:%x], %#x, %#x) failed: EINVAL\n",
525 		    t, t->pbs_base, t->pbs_limit, bpa, size);
526 #endif
527 		return (EINVAL);
528 	}
529 
530 	/*
531 	 * Can't map I/O space as linear.
532 	 */
533 	if ((flags & BUS_SPACE_MAP_LINEAR) &&
534 	    (t->pbs_flags & _BUS_SPACE_IO_TYPE)) {
535 		return (EOPNOTSUPP);
536 	}
537 
538 	if (t->pbs_extent != NULL) {
539 #ifdef PPC_IBM4XX
540 		/*
541 		 * XXX: Temporary kludge.
542 		 * Don't bother checking the extent during very early bootstrap.
543 		 */
544 		if (extent_flags) {
545 #endif
546 		/*
547 		 * Before we go any further, let's make sure that this
548 		 * region is available.
549 		 */
550 		error = extent_alloc_region(t->pbs_extent, bpa, size,
551 		    EX_NOWAIT | extent_flags);
552 		if (error) {
553 #ifdef DEBUG
554 			printf("bus_space_map(%p[%x:%x], %#x, %#x) failed"
555 			    ": %d\n",
556 			    t, t->pbs_base, t->pbs_limit, bpa, size, error);
557 #endif
558 			return (error);
559 		}
560 #ifdef PPC_IBM4XX
561 		}
562 #endif
563 	}
564 
565 	pa = t->pbs_offset + bpa;
566 #if defined (PPC_OEA) || defined(PPC_OEA601)
567 #ifdef PPC_OEA601
568 	if ((mfpvr() >> 16) == MPC601) {
569 		/*
570 		 * Map via the MPC601's I/O segments
571 		 */
572 		register_t sr = iosrtable[pa >> ADDR_SR_SHFT];
573 		if (SR601_VALID_P(sr) && ((pa >> ADDR_SR_SHFT) ==
574 		    ((pa + size - 1) >> ADDR_SR_SHFT))) {
575 			*bshp = pa;
576 			return (0);
577 		}
578 	} else
579 #endif /* PPC_OEA601 */
580 	if ((oeacpufeat & OEACPU_NOBAT) == 0) {
581 		/*
582 		 * Let's try to BAT map this address if possible
583 		 * (note this assumes 1:1 VA:PA)
584 		 */
585 		register_t batu = battable[BAT_VA2IDX(pa)].batu;
586 		if (BAT_VALID_P(batu, 0) && BAT_VA_MATCH_P(batu, pa) &&
587 		    BAT_VA_MATCH_P(batu, pa + size - 1)) {
588 			*bshp = pa;
589 			return (0);
590 		}
591 	}
592 #endif /* defined (PPC_OEA) || defined(PPC_OEA601) */
593 
594 	if (t->pbs_extent != NULL) {
595 #if !defined(PPC_IBM4XX)
596 	if (extent_flags == 0) {
597 		extent_free(t->pbs_extent, bpa, size, EX_NOWAIT);
598 #ifdef DEBUG
599 		printf("bus_space_map(%p[%x:%x], %#x, %#x) failed: ENOMEM\n",
600 		    t, t->pbs_base, t->pbs_limit, bpa, size);
601 #endif
602 		return (ENOMEM);
603 	}
604 #endif
605 	}
606 
607 	/*
608 	 * Map this into the kernel pmap.
609 	 */
610 	*bshp = (bus_space_handle_t) mapiodev(pa, size);
611 	if (*bshp == 0) {
612 		extent_free(t->pbs_extent, bpa, size, EX_NOWAIT | extent_flags);
613 #ifdef DEBUG
614 		printf("bus_space_map(%p[%x:%x], %#x, %#x) failed: ENOMEM\n",
615 		    t, t->pbs_base, t->pbs_limit, bpa, size);
616 #endif
617 		return (ENOMEM);
618 	}
619 
620 	return (0);
621 }
622 
623 int
624 memio_subregion(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset,
625 	bus_size_t size, bus_space_handle_t *bshp)
626 {
627 	*bshp = bsh + _BUS_SPACE_STRIDE(t, offset);
628 	return (0);
629 }
630 
631 void
632 memio_unmap(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t size)
633 {
634 	bus_addr_t bpa;
635 	vaddr_t va = bsh;
636 	paddr_t pa;
637 
638 	size = _BUS_SPACE_STRIDE(t, size);
639 
640 #if defined (PPC_OEA) || defined(PPC_OEA601)
641 #ifdef PPC_OEA601
642 	if ((mfpvr() >> 16) == MPC601) {
643 		register_t sr = iosrtable[va >> ADDR_SR_SHFT];
644 		if (SR601_VALID_P(sr) && ((pa >> ADDR_SR_SHFT) ==
645 		    ((pa + size - 1) >> ADDR_SR_SHFT))) {
646 			pa = va;
647 			va = 0;
648 		} else {
649 			pmap_extract(pmap_kernel(), va, &pa);
650 		}
651 	} else
652 #endif /* PPC_OEA601 */
653 	if ((oeacpufeat & OEACPU_NOBAT) == 0) {
654 		register_t batu = battable[BAT_VA2IDX(va)].batu;
655 		if (BAT_VALID_P(batu, 0) && BAT_VA_MATCH_P(batu, va) &&
656 		    BAT_VA_MATCH_P(batu, va + size - 1)) {
657 			pa = va;
658 			va = 0;
659 		} else {
660 			pmap_extract(pmap_kernel(), va, &pa);
661 		}
662 	} else
663 		pmap_extract(pmap_kernel(), va, &pa);
664 #else
665 	pmap_extract(pmap_kernel(), va, &pa);
666 #endif /* defined (PPC_OEA) || defined(PPC_OEA601) */
667 	bpa = pa - t->pbs_offset;
668 
669 	if (t->pbs_extent != NULL
670 	    && extent_free(t->pbs_extent, bpa, size,
671 			   EX_NOWAIT | extent_flags)) {
672 		printf("memio_unmap: %s 0x%lx, size 0x%lx\n",
673 		    (t->pbs_flags & _BUS_SPACE_IO_TYPE) ? "port" : "mem",
674 		    (unsigned long)bpa, (unsigned long)size);
675 		printf("memio_unmap: can't free region\n");
676 	}
677 
678 	unmapiodev(va, size);
679 }
680 
681 int
682 memio_alloc(bus_space_tag_t t, bus_addr_t rstart, bus_addr_t rend,
683 	bus_size_t size, bus_size_t alignment, bus_size_t boundary,
684 	int flags, bus_addr_t *bpap, bus_space_handle_t *bshp)
685 {
686 	u_long bpa;
687 	paddr_t pa;
688 	int error;
689 
690 	size = _BUS_SPACE_STRIDE(t, size);
691 	rstart = _BUS_SPACE_STRIDE(t, rstart);
692 
693 	if (t->pbs_extent == NULL)
694 		return ENOMEM;
695 
696 	if (rstart + size > t->pbs_limit) {
697 #ifdef DEBUG
698 		printf("%s(%p[%x:%x], %#x, %#x) failed: EINVAL\n",
699 		   __func__, t, t->pbs_base, t->pbs_limit, rstart, size);
700 #endif
701 		return (EINVAL);
702 	}
703 
704 	/*
705 	 * Can't map I/O space as linear.
706 	 */
707 	if ((flags & BUS_SPACE_MAP_LINEAR) &&
708 	    (t->pbs_flags & _BUS_SPACE_IO_TYPE))
709 		return (EOPNOTSUPP);
710 
711 	if (rstart < t->pbs_extent->ex_start || rend > t->pbs_extent->ex_end)
712 		panic("memio_alloc: bad region start/end");
713 
714 	error = extent_alloc_subregion(t->pbs_extent, rstart, rend, size,
715 	    alignment, boundary, EX_FAST | EX_NOWAIT | extent_flags, &bpa);
716 
717 	if (error)
718 		return (error);
719 
720 	*bpap = bpa;
721 	pa = t->pbs_offset + bpa;
722 #if defined (PPC_OEA) || defined(PPC_OEA601)
723 #ifdef PPC_OEA601
724 	if ((mfpvr() >> 16) == MPC601) {
725 		register_t sr = iosrtable[pa >> ADDR_SR_SHFT];
726 		if (SR601_VALID_P(sr) && SR601_PA_MATCH_P(sr, pa) &&
727 		    SR601_PA_MATCH_P(sr, pa + size - 1)) {
728 			*bshp = pa;
729 			return (0);
730 		}
731 	} else
732 #endif /* PPC_OEA601 */
733 	if ((oeacpufeat & OEACPU_NOBAT) == 0) {
734 		register_t batu = battable[BAT_VA2IDX(pa)].batu;
735 		if (BAT_VALID_P(batu, 0) && BAT_VA_MATCH_P(batu, pa) &&
736 		    BAT_VA_MATCH_P(batu, pa + size - 1)) {
737 			*bshp = pa;
738 			return (0);
739 		}
740 	}
741 #endif /* defined (PPC_OEA) || defined(PPC_OEA601) */
742 	*bshp = (bus_space_handle_t) mapiodev(pa, size);
743 	if (*bshp == 0) {
744 		extent_free(t->pbs_extent, bpa, size, EX_NOWAIT | extent_flags);
745 		return (ENOMEM);
746 	}
747 
748 	return (0);
749 }
750 
751 void
752 memio_free(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t size)
753 {
754 	if (t->pbs_extent == NULL)
755 		return;
756 
757 	/* memio_unmap() does all that we need to do. */
758 	memio_unmap(t, bsh, size);
759 }
760