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