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