xref: /netbsd-src/sys/arch/arc/arc/bus_space.c (revision 8ff6f65dafc58186614d149001c905dec4c934a2)
1 /*	$NetBSD: bus_space.c,v 1.14 2023/12/20 06:36:02 thorpej Exp $	*/
2 /*	NetBSD: bus_machdep.c,v 1.1 2000/01/26 18:48:00 drochner Exp 	*/
3 
4 /*-
5  * Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to The NetBSD Foundation
9  * by Charles M. Hannum and by Jason R. Thorpe of the Numerical Aerospace
10  * Simulation Facility, NASA Ames Research Center.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
25  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: bus_space.c,v 1.14 2023/12/20 06:36:02 thorpej Exp $");
36 
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/vmem_impl.h>
40 
41 #include <uvm/uvm_extern.h>
42 
43 #include <sys/bus.h>
44 
45 /*
46  *	uintN_t bus_space_read_N(bus_space_tag_t tag,
47  *	    bus_space_handle_t bsh, bus_size_t offset);
48  *
49  * Read a 1, 2, 4, or 8 byte quantity from bus space
50  * described by tag/handle/offset.
51  */
52 
53 #define bus_space_read(BYTES,BITS)					\
54 __CONCAT3(uint,BITS,_t)					\
55 __CONCAT(bus_space_read_,BYTES)(bus_space_tag_t bst,			\
56     bus_space_handle_t bsh, bus_size_t offset)				\
57 {									\
58 	return (*(volatile __CONCAT3(uint,BITS,_t) *)			\
59 	    (bsh + (offset << __CONCAT(bst->bs_stride_,BYTES))));	\
60 }
61 
62 bus_space_read(1,8)
63 bus_space_read(2,16)
64 bus_space_read(4,32)
65 bus_space_read(8,64)
66 
67 /*
68  *	void bus_space_read_multi_N(bus_space_tag_t tag,
69  *	    bus_space_handle_t bsh, bus_size_t offset,
70  *	    uintN_t *addr, size_t count);
71  *
72  * Read `count' 1, 2, 4, or 8 byte quantities from bus space
73  * described by tag/handle/offset and copy into buffer provided.
74  */
75 
76 #define bus_space_read_multi(BYTES,BITS)				\
77 void							\
78 __CONCAT(bus_space_read_multi_,BYTES)(bus_space_tag_t bst,		\
79     bus_space_handle_t bsh, bus_size_t offset,				\
80     __CONCAT3(uint,BITS,_t) *datap, bus_size_t count)			\
81 {									\
82 	volatile __CONCAT3(uint,BITS,_t) *p =				\
83 	    (volatile __CONCAT3(uint,BITS,_t) *)			\
84 	    (bsh + (offset << __CONCAT(bst->bs_stride_,BYTES)));	\
85 									\
86 	for (; count > 0; --count)					\
87 		*datap++ = *p;						\
88 }
89 
90 bus_space_read_multi(1,8)
91 bus_space_read_multi(2,16)
92 bus_space_read_multi(4,32)
93 bus_space_read_multi(8,64)
94 
95 /*
96  *	void bus_space_read_region_N(bus_space_tag_t tag,
97  *	    bus_space_handle_t bsh, bus_size_t offset,
98  *	    uintN_t *addr, size_t count);
99  *
100  * Read `count' 1, 2, 4, or 8 byte quantities from bus space
101  * described by tag/handle and starting at `offset' and copy into
102  * buffer provided.
103  */
104 
105 #define bus_space_read_region(BYTES,BITS)				\
106 void							\
107 __CONCAT(bus_space_read_region_,BYTES)(bus_space_tag_t bst,		\
108     bus_space_handle_t bsh, bus_size_t offset,				\
109     __CONCAT3(uint,BITS,_t) *datap, bus_size_t count)			\
110 {									\
111 	int stride = 1 << __CONCAT(bst->bs_stride_,BYTES);		\
112 	volatile __CONCAT3(uint,BITS,_t) *p =				\
113 	    (volatile __CONCAT3(uint,BITS,_t) *)			\
114 	    (bsh + (offset << __CONCAT(bst->bs_stride_,BYTES)));	\
115 									\
116 	for (; count > 0; --count) {					\
117 		*datap++ = *p;						\
118 		p += stride;						\
119 	}								\
120 }
121 
122 bus_space_read_region(1,8)
123 bus_space_read_region(2,16)
124 bus_space_read_region(4,32)
125 bus_space_read_region(8,64)
126 
127 /*
128  *	void bus_space_write_N(bus_space_tag_t tag,
129  *	    bus_space_handle_t bsh, bus_size_t offset,
130  *	    uintN_t value);
131  *
132  * Write the 1, 2, 4, or 8 byte value `value' to bus space
133  * described by tag/handle/offset.
134  */
135 
136 #define bus_space_write(BYTES,BITS)					\
137 void							\
138 __CONCAT(bus_space_write_,BYTES)(bus_space_tag_t bst,			\
139     bus_space_handle_t bsh,						\
140     bus_size_t offset, __CONCAT3(uint,BITS,_t) data)			\
141 {									\
142 	*(volatile __CONCAT3(uint,BITS,_t) *)				\
143 	    (bsh + (offset << __CONCAT(bst->bs_stride_,BYTES))) = data; \
144 }
145 
146 bus_space_write(1,8)
147 bus_space_write(2,16)
148 bus_space_write(4,32)
149 bus_space_write(8,64)
150 
151 /*
152  *	void bus_space_write_multi_N(bus_space_tag_t tag,
153  *	    bus_space_handle_t bsh, bus_size_t offset,
154  *	    const uintN_t *addr, size_t count);
155  *
156  * Write `count' 1, 2, 4, or 8 byte quantities from the buffer
157  * provided to bus space described by tag/handle/offset.
158  */
159 
160 #define bus_space_write_multi(BYTES,BITS)				\
161 void							\
162 __CONCAT(bus_space_write_multi_,BYTES)(bus_space_tag_t bst,		\
163     bus_space_handle_t bsh, bus_size_t offset,				\
164     const __CONCAT3(uint,BITS,_t) *datap, bus_size_t count)		\
165 {									\
166 	volatile __CONCAT3(uint,BITS,_t) *p =				\
167 	    (volatile __CONCAT3(uint,BITS,_t) *)			\
168 	    (bsh + (offset << __CONCAT(bst->bs_stride_,BYTES)));	\
169 									\
170 	for (; count > 0; --count)					\
171 		*p = *datap++;						\
172 }
173 
174 bus_space_write_multi(1,8)
175 bus_space_write_multi(2,16)
176 bus_space_write_multi(4,32)
177 bus_space_write_multi(8,64)
178 
179 /*
180  *	void bus_space_write_region_N(bus_space_tag_t tag,
181  *	    bus_space_handle_t bsh, bus_size_t offset,
182  *	    const uintN_t *addr, size_t count);
183  *
184  * Write `count' 1, 2, 4, or 8 byte quantities from the buffer provided
185  * to bus space described by tag/handle starting at `offset'.
186  */
187 
188 #define bus_space_write_region(BYTES,BITS)				\
189 void							\
190 __CONCAT(bus_space_write_region_,BYTES)(bus_space_tag_t bst,		\
191     bus_space_handle_t bsh, bus_size_t offset,				\
192     const __CONCAT3(uint,BITS,_t) *datap, bus_size_t count)		\
193 {									\
194 	int stride = 1 << __CONCAT(bst->bs_stride_,BYTES);		\
195 	volatile __CONCAT3(uint,BITS,_t) *p =				\
196 	    (volatile __CONCAT3(uint,BITS,_t) *)			\
197 	    (bsh + (offset << __CONCAT(bst->bs_stride_,BYTES)));	\
198 									\
199 	for (; count > 0; --count) {					\
200 		*p = *datap++;						\
201 		p += stride;						\
202 	}								\
203 }
204 
205 bus_space_write_region(1,8)
206 bus_space_write_region(2,16)
207 bus_space_write_region(4,32)
208 bus_space_write_region(8,64)
209 
210 /*
211  *	void bus_space_set_multi_N(bus_space_tag_t tag,
212  *	    bus_space_handle_t bsh, bus_size_t offset, uintN_t val,
213  *	    size_t count);
214  *
215  * Write the 1, 2, 4, or 8 byte value `val' to bus space described
216  * by tag/handle/offset `count' times.
217  */
218 
219 #define bus_space_set_multi(BYTES,BITS)					\
220 void							\
221 __CONCAT(bus_space_set_multi_,BYTES)(bus_space_tag_t bst,		\
222     bus_space_handle_t bsh, bus_size_t offset,				\
223     const __CONCAT3(uint,BITS,_t) data, bus_size_t count)		\
224 {									\
225 	volatile __CONCAT3(uint,BITS,_t) *p =				\
226 	    (volatile __CONCAT3(uint,BITS,_t) *)			\
227 	    (bsh + (offset << __CONCAT(bst->bs_stride_,BYTES)));	\
228 									\
229 	for (; count > 0; --count)					\
230 		*p = data;						\
231 }
232 
233 bus_space_set_multi(1,8)
234 bus_space_set_multi(2,16)
235 bus_space_set_multi(4,32)
236 bus_space_set_multi(8,64)
237 
238 /*
239  *	void bus_space_set_region_N(bus_space_tag_t tag,
240  *	    bus_space_handle_t bsh, bus_size_t offset, uintN_t val,
241  *	    size_t count);
242  *
243  * Write `count' 1, 2, 4, or 8 byte value `val' to bus space described
244  * by tag/handle starting at `offset'.
245  */
246 
247 #define bus_space_set_region(BYTES,BITS)				\
248 void							\
249 __CONCAT(bus_space_set_region_,BYTES)(bus_space_tag_t bst,		\
250     bus_space_handle_t bsh, bus_size_t offset,				\
251     __CONCAT3(uint,BITS,_t) data, bus_size_t count)			\
252 {									\
253 	int stride = 1 << __CONCAT(bst->bs_stride_,BYTES);		\
254 	volatile __CONCAT3(uint,BITS,_t) *p =				\
255 	    (volatile __CONCAT3(uint,BITS,_t) *)			\
256 	    (bsh + (offset << __CONCAT(bst->bs_stride_,BYTES)));	\
257 									\
258 	for (; count > 0; --count) {					\
259 		*p = data;						\
260 		p += stride;						\
261 	}								\
262 }
263 
264 bus_space_set_region(1,8)
265 bus_space_set_region(2,16)
266 bus_space_set_region(4,32)
267 bus_space_set_region(8,64)
268 
269 /*
270  *	void bus_space_copy_region_N(bus_space_tag_t tag,
271  *	    bus_space_handle_t bsh1, bus_size_t off1,
272  *	    bus_space_handle_t bsh2, bus_size_t off2,
273  *	    size_t count);
274  *
275  * Copy `count' 1, 2, 4, or 8 byte values from bus space starting
276  * at tag/bsh1/off1 to bus space starting at tag/bsh2/off2.
277  */
278 
279 #define bus_space_copy_region(BYTES,BITS)				\
280 void							\
281 __CONCAT(bus_space_copy_region_,BYTES)(bus_space_tag_t bst,		\
282     bus_space_handle_t srcbsh, bus_size_t srcoffset,			\
283     bus_space_handle_t dstbsh, bus_size_t dstoffset, bus_size_t count)	\
284 {									\
285 	int stride = 1 << __CONCAT(bst->bs_stride_,BYTES);		\
286 	volatile __CONCAT3(uint,BITS,_t) *srcp =			\
287 	    (volatile __CONCAT3(uint,BITS,_t) *)			\
288 	    (srcbsh + (srcoffset << __CONCAT(bst->bs_stride_,BYTES)));	\
289 	volatile __CONCAT3(uint,BITS,_t) *dstp =			\
290 	    (volatile __CONCAT3(uint,BITS,_t) *)			\
291 	    (dstbsh + (dstoffset << __CONCAT(bst->bs_stride_,BYTES)));	\
292 	bus_size_t offset;						\
293 									\
294 	if (srcp >= dstp) {						\
295 		/* src after dest: copy forward */			\
296 		for (offset = 0; count > 0; --count, offset += stride)	\
297 			dstp[offset] = srcp[offset];			\
298 	} else {							\
299 		/* dest after src: copy backward */			\
300 		offset = (count << __CONCAT(bst->bs_stride_,BYTES))	\
301 		    - stride;						\
302 		for (; count > 0; --count, offset -= stride)		\
303 			dstp[offset] = srcp[offset];			\
304 	}								\
305 }
306 
307 bus_space_copy_region(1,8)
308 bus_space_copy_region(2,16)
309 bus_space_copy_region(4,32)
310 bus_space_copy_region(8,64)
311 
312 void
arc_bus_space_init(bus_space_tag_t bst,const char * name,paddr_t paddr,vaddr_t vaddr,bus_addr_t start,bus_size_t size)313 arc_bus_space_init(bus_space_tag_t bst, const char *name, paddr_t paddr,
314     vaddr_t vaddr, bus_addr_t start, bus_size_t size)
315 {
316 
317 	bst->bs_name = name;
318 	bst->bs_arena = NULL;
319 	bst->bs_start = start;
320 	bst->bs_size = size;
321 	bst->bs_pbase = paddr;
322 	bst->bs_vbase = vaddr;
323 	bst->bs_compose_handle = arc_bus_space_compose_handle;
324 	bst->bs_dispose_handle = arc_bus_space_dispose_handle;
325 	bst->bs_paddr = arc_bus_space_paddr;
326 	bst->bs_map = arc_bus_space_map;
327 	bst->bs_unmap = arc_bus_space_unmap;
328 	bst->bs_subregion = arc_bus_space_subregion;
329 	bst->bs_mmap = arc_bus_space_mmap;
330 	bst->bs_alloc = arc_bus_space_alloc;
331 	bst->bs_free = arc_bus_space_free;
332 	bst->bs_aux = NULL;
333 	bst->bs_stride_1 = 0;
334 	bst->bs_stride_2 = 0;
335 	bst->bs_stride_4 = 0;
336 	bst->bs_stride_8 = 0;
337 }
338 
339 void
arc_bus_space_init_arena(bus_space_tag_t bst,struct vmem * arena_store,struct vmem_btag * btag_store,unsigned int btag_count)340 arc_bus_space_init_arena(bus_space_tag_t bst, struct vmem *arena_store,
341     struct vmem_btag *btag_store, unsigned int btag_count)
342 {
343 	int error __diagused;
344 
345 	bst->bs_arena = vmem_init(arena_store,
346 				  bst->bs_name,		/* name */
347 				  0,			/* addr */
348 				  0,			/* size */
349 				  1,			/* quantum */
350 				  NULL,			/* importfn */
351 				  NULL,			/* releasefn */
352 				  NULL,			/* source */
353 				  0,			/* qcache_max */
354 				  VM_NOSLEEP | VM_PRIVTAGS,
355 				  IPL_NONE);
356 	KASSERT(bst->bs_arena != NULL);
357 
358 	vmem_add_bts(bst->bs_arena, btag_store, btag_count);
359 	error = vmem_add(bst->bs_arena, bst->bs_start, bst->bs_size,
360 	    VM_NOSLEEP);
361 	KASSERT(error == 0);
362 }
363 
364 void
arc_bus_space_set_aligned_stride(bus_space_tag_t bst,unsigned int alignment_shift)365 arc_bus_space_set_aligned_stride(bus_space_tag_t bst,
366     unsigned int alignment_shift)
367 {
368 
369 	bst->bs_stride_1 = alignment_shift;
370 	if (alignment_shift > 0)
371 		--alignment_shift;
372 	bst->bs_stride_2 = alignment_shift;
373 	if (alignment_shift > 0)
374 		--alignment_shift;
375 	bst->bs_stride_4 = alignment_shift;
376 	if (alignment_shift > 0)
377 		--alignment_shift;
378 	bst->bs_stride_8 = alignment_shift;
379 }
380 
381 int
arc_bus_space_compose_handle(bus_space_tag_t bst,bus_addr_t addr,bus_size_t size,int flags,bus_space_handle_t * bshp)382 arc_bus_space_compose_handle(bus_space_tag_t bst, bus_addr_t addr,
383     bus_size_t size, int flags, bus_space_handle_t *bshp)
384 {
385 	bus_space_handle_t bsh = bst->bs_vbase + (addr - bst->bs_start);
386 
387 	/*
388 	 * Since all buses can be linearly mappable, we don't have to check
389 	 * BUS_SPACE_MAP_LINEAR and BUS_SPACE_MAP_PREFETCHABLE.
390 	 */
391 	if ((flags & BUS_SPACE_MAP_CACHEABLE) == 0) {
392 		*bshp = bsh;
393 		return 0;
394 	}
395 	if (bsh < MIPS_KSEG1_START) /* KUSEG or KSEG0 */
396 		panic("arc_bus_space_compose_handle: bad address 0x%x", bsh);
397 	if (bsh < MIPS_KSEG2_START) { /* KSEG1 */
398 		*bshp = MIPS_PHYS_TO_KSEG0(MIPS_KSEG1_TO_PHYS(bsh));
399 		return 0;
400 	}
401 	/*
402 	 * KSEG2:
403 	 * Do not make the page cacheable in this case, since:
404 	 * - the page which this bus_space belongs might include
405 	 *   other bus_spaces.
406 	 * or
407 	 * - this bus might be mapped by wired TLB, in that case,
408 	 *   we cannot manupulate cacheable attribute with page granularity.
409 	 */
410 #ifdef DIAGNOSTIC
411 	printf("arc_bus_space_compose_handle: ignore cacheable 0x%x\n", bsh);
412 #endif
413 	*bshp = bsh;
414 	return 0;
415 }
416 
417 int
arc_bus_space_dispose_handle(bus_space_tag_t bst,bus_space_handle_t bsh,bus_size_t size)418 arc_bus_space_dispose_handle(bus_space_tag_t bst, bus_space_handle_t bsh,
419     bus_size_t size)
420 {
421 
422 	return 0;
423 }
424 
425 int
arc_bus_space_paddr(bus_space_tag_t bst,bus_space_handle_t bsh,paddr_t * pap)426 arc_bus_space_paddr(bus_space_tag_t bst, bus_space_handle_t bsh, paddr_t *pap)
427 {
428 
429 	if (bsh < MIPS_KSEG0_START) /* KUSEG */
430 		panic("arc_bus_space_paddr(0x%qx): bad address",
431 		    (unsigned long long) bsh);
432 	else if (bsh < MIPS_KSEG1_START) /* KSEG0 */
433 		*pap = MIPS_KSEG0_TO_PHYS(bsh);
434 	else if (bsh < MIPS_KSEG2_START) /* KSEG1 */
435 		*pap = MIPS_KSEG1_TO_PHYS(bsh);
436 	else { /* KSEG2 */
437 		/*
438 		 * Since this region may be mapped by wired TLB,
439 		 * kvtophys() is not always available.
440 		 */
441 		*pap = bst->bs_pbase + (bsh - bst->bs_vbase);
442 	}
443 	return 0;
444 }
445 
446 int
arc_bus_space_map(bus_space_tag_t bst,bus_addr_t addr,bus_size_t size,int flags,bus_space_handle_t * bshp)447 arc_bus_space_map(bus_space_tag_t bst, bus_addr_t addr, bus_size_t size,
448     int flags, bus_space_handle_t *bshp)
449 {
450 	int err;
451 
452 	if (addr < bst->bs_start || addr + size > bst->bs_start + bst->bs_size)
453 		return EINVAL;
454 
455 	if (bst->bs_arena != NULL) {
456 		err = vmem_xalloc_addr(bst->bs_arena, addr, size, VM_NOSLEEP);
457 		if (err)
458 			return err;
459 	}
460 
461 	return bus_space_compose_handle(bst, addr, size, flags, bshp);
462 }
463 
464 void
arc_bus_space_unmap(bus_space_tag_t bst,bus_space_handle_t bsh,bus_size_t size)465 arc_bus_space_unmap(bus_space_tag_t bst, bus_space_handle_t bsh,
466     bus_size_t size)
467 {
468 
469 	if (bst->bs_arena != NULL) {
470 		paddr_t pa;
471 		bus_addr_t addr;
472 		int err;
473 
474 		/* bus_space_paddr() becomes unavailable after unmapping */
475 		err = bus_space_paddr(bst, bsh, &pa);
476 		if (err)
477 			panic("arc_bus_space_unmap: %s va 0x%qx: error %d",
478 			    bst->bs_name, (unsigned long long) bsh, err);
479 		addr = (bus_size_t)(pa - bst->bs_pbase) + bst->bs_start;
480 		vmem_xfree(bst->bs_arena, addr, size);
481 	}
482 	bus_space_dispose_handle(bst, bsh, size);
483 }
484 
485 int
arc_bus_space_subregion(bus_space_tag_t bst,bus_space_handle_t bsh,bus_size_t offset,bus_size_t size,bus_space_handle_t * nbshp)486 arc_bus_space_subregion(bus_space_tag_t bst, bus_space_handle_t bsh,
487     bus_size_t offset, bus_size_t size, bus_space_handle_t *nbshp)
488 {
489 
490 	*nbshp = bsh + offset;
491 	return 0;
492 }
493 
494 paddr_t
arc_bus_space_mmap(bus_space_tag_t bst,bus_addr_t addr,off_t off,int prot,int flags)495 arc_bus_space_mmap(bus_space_tag_t bst, bus_addr_t addr, off_t off, int prot,
496     int flags)
497 {
498 
499 	/*
500 	 * XXX We do not disallow mmap'ing of EISA/PCI I/O space here,
501 	 * XXX which we should be doing.
502 	 */
503 
504 	if (addr < bst->bs_start ||
505 	    (addr + off) >= (bst->bs_start + bst->bs_size))
506 		return -1;
507 
508 	return mips_btop(bst->bs_pbase + (addr - bst->bs_start) + off);
509 }
510 
511 int
arc_bus_space_alloc(bus_space_tag_t bst,bus_addr_t start,bus_addr_t end,bus_size_t size,bus_size_t align,bus_size_t boundary,int flags,bus_addr_t * addrp,bus_space_handle_t * bshp)512 arc_bus_space_alloc(bus_space_tag_t bst, bus_addr_t start, bus_addr_t end,
513     bus_size_t size, bus_size_t align, bus_size_t boundary, int flags,
514     bus_addr_t *addrp, bus_space_handle_t *bshp)
515 {
516 	vmem_addr_t addr;
517 	int err;
518 
519 	if (bst->bs_arena == NULL)
520 		panic("arc_bus_space_alloc: vmem arena %s not available",
521 		    bst->bs_name);
522 
523 	if (start < bst->bs_start ||
524 	    start + size > bst->bs_start + bst->bs_size)
525 		return EINVAL;
526 
527 	err = vmem_xalloc(bst->bs_arena, size,
528 			  align,		/* align */
529 			  0,			/* phase */
530 			  boundary,		/* nocross */
531 			  start,		/* minaddr */
532 			  end,			/* maxaddr */
533 			  VM_BESTFIT | VM_NOSLEEP,
534 			  &addr);
535 	if (err)
536 		return err;
537 
538 	*addrp = addr;
539 	return bus_space_compose_handle(bst, addr, size, flags, bshp);
540 }
541