xref: /netbsd-src/sys/arch/hpcmips/hpcmips/bus_space.c (revision 48491f9819751125d121614a85f27fc971ad5fe6)
1 /*	$NetBSD: bus_space.c,v 1.35 2024/02/11 10:36:40 andvar Exp $	*/
2 
3 /*-
4  * Copyright (c) 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.35 2024/02/11 10:36:40 andvar Exp $");
35 
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/extent.h>
39 #include <sys/bus.h>
40 
41 #include <uvm/uvm_extern.h>
42 
43 #include <mips/cache.h>
44 #include <mips/locore.h>
45 #include <mips/pte.h>
46 
47 #include <machine/bus_space_hpcmips.h>
48 
49 #ifdef BUS_SPACE_DEBUG
50 #define	DPRINTF(arg) printf arg
51 #else
52 #define	DPRINTF(arg)
53 #endif
54 
55 #define MAX_BUSSPACE_TAG 10
56 
57 /* proto types */
58 bus_space_handle_t __hpcmips_cacheable(struct bus_space_tag_hpcmips*,
59     bus_addr_t, bus_size_t, int);
60 bus_space_protos(_);
61 bus_space_protos(bs_notimpl);
62 
63 /* variables */
64 static  struct bus_space_tag_hpcmips __bus_space[MAX_BUSSPACE_TAG];
65 static int __bus_space_index;
66 static struct bus_space_tag_hpcmips __sys_bus_space = {
67 	{
68 		NULL,
69 		{
70 			/* mapping/unmapping */
71 			__bs_map,
72 			__bs_unmap,
73 			__bs_subregion,
74 
75 			/* allocation/deallocation */
76 			__bs_alloc,
77 			__bs_free,
78 
79 			/* get kernel virtual address */
80 			bs_notimpl_bs_vaddr, /* there is no linear mapping */
81 
82 			/* Mmap bus space for user */
83 			bs_notimpl_bs_mmap,
84 
85 			/* barrier */
86 			__bs_barrier,
87 
88 			/* probe */
89 			__bs_peek,
90 			__bs_poke,
91 
92 			/* read (single) */
93 			__bs_r_1,
94 			__bs_r_2,
95 			__bs_r_4,
96 			bs_notimpl_bs_r_8,
97 
98 			/* read multiple */
99 			__bs_rm_1,
100 			__bs_rm_2,
101 			__bs_rm_4,
102 			bs_notimpl_bs_rm_8,
103 
104 			/* read region */
105 			__bs_rr_1,
106 			__bs_rr_2,
107 			__bs_rr_4,
108 			bs_notimpl_bs_rr_8,
109 
110 			/* write (single) */
111 			__bs_w_1,
112 			__bs_w_2,
113 			__bs_w_4,
114 			bs_notimpl_bs_w_8,
115 
116 			/* write multiple */
117 			__bs_wm_1,
118 			__bs_wm_2,
119 			__bs_wm_4,
120 			bs_notimpl_bs_wm_8,
121 
122 			/* write region */
123 			__bs_wr_1,
124 			__bs_wr_2,
125 			__bs_wr_4,
126 			bs_notimpl_bs_wr_8,
127 
128 			/* set multi */
129 			__bs_sm_1,
130 			__bs_sm_2,
131 			__bs_sm_4,
132 			bs_notimpl_bs_sm_8,
133 
134 			/* set region */
135 			__bs_sr_1,
136 			__bs_sr_2,
137 			__bs_sr_4,
138 			bs_notimpl_bs_sr_8,
139 
140 			/* copy */
141 			__bs_c_1,
142 			__bs_c_2,
143 			__bs_c_4,
144 			bs_notimpl_bs_c_8,
145 		},
146 	},
147 
148 	"whole bus space",	/* bus name */
149 	0,			/* extent base */
150 	0xffffffff,		/* extent size */
151 	NULL,			/* pointer for extent structure */
152 };
153 static bus_space_tag_t __sys_bus_space_tag = &__sys_bus_space.bst;
154 
155 bus_space_tag_t
hpcmips_system_bus_space(void)156 hpcmips_system_bus_space(void)
157 {
158 
159 	return (__sys_bus_space_tag);
160 }
161 
162 struct bus_space_tag_hpcmips *
hpcmips_system_bus_space_hpcmips(void)163 hpcmips_system_bus_space_hpcmips(void)
164 {
165 
166 	return (&__sys_bus_space);
167 }
168 
169 struct bus_space_tag_hpcmips *
hpcmips_alloc_bus_space_tag(void)170 hpcmips_alloc_bus_space_tag(void)
171 {
172 
173 	if (__bus_space_index >= MAX_BUSSPACE_TAG) {
174 		panic("hpcmips_internal_alloc_bus_space_tag: tag full.");
175 	}
176 
177 	return (&__bus_space[__bus_space_index++]);
178 }
179 
180 void
hpcmips_init_bus_space(struct bus_space_tag_hpcmips * t,struct bus_space_tag_hpcmips * basetag,const char * name,u_int32_t base,u_int32_t size)181 hpcmips_init_bus_space(struct bus_space_tag_hpcmips *t,
182     struct bus_space_tag_hpcmips *basetag,
183     const char *name, u_int32_t base, u_int32_t size)
184 {
185 	u_int32_t pa, endpa;
186 	vaddr_t va;
187 
188 	if (basetag != NULL)
189 		memcpy(t, basetag, sizeof(struct bus_space_tag_hpcmips));
190 	strncpy(t->name, name, sizeof(t->name));
191 	t->name[sizeof(t->name) - 1] = '\0';
192 	t->base = base;
193 	t->size = size;
194 
195 	/*
196 	 * If request physical address is greater than 512MByte,
197 	 * mapping it to kseg2.
198 	 */
199 	if (t->base >= 0x20000000) {
200 		pa = mips_trunc_page(t->base);
201 		endpa = mips_round_page(t->base + t->size);
202 
203 		if (!(va = uvm_km_alloc(kernel_map, endpa - pa, 0,
204 		    UVM_KMF_VAONLY))) {
205 			panic("hpcmips_init_bus_space_extent:"
206 			    "can't allocate kernel virtual");
207 		}
208 		DPRINTF(("pa:0x%08x -> kv:0x%08x+0x%08x",
209 		    (unsigned int)t->base, (unsigned int)va, t->size));
210 		t->base = va; /* kseg2 addr */
211 
212 		for (; pa < endpa; pa += PAGE_SIZE, va += PAGE_SIZE) {
213 			pmap_kenter_pa(va, pa, VM_PROT_READ | VM_PROT_WRITE, 0);
214 		}
215 		pmap_update(pmap_kernel());
216 	}
217 
218 	t->extent = (void*)extent_create(t->name, t->base,
219 	    t->base + t->size,
220 	    0, 0, EX_NOWAIT);
221 	if (!t->extent) {
222 		panic("hpcmips_init_bus_space_extent:"
223 		    "unable to allocate %s map", t->name);
224 	}
225 }
226 
227 static bool
mips_pte_cachechange(struct pmap * pmap,vaddr_t sva,vaddr_t eva,pt_entry_t * ptep,uintptr_t flags)228 mips_pte_cachechange(struct pmap *pmap, vaddr_t sva, vaddr_t eva,
229     pt_entry_t *ptep, uintptr_t flags)
230 {
231 	mips_dcache_wbinv_range(sva, eva - sva);
232 
233 	for (; sva < eva; sva += PAGE_SIZE) {
234 		pt_entry_t pte = pte_cached_change(*ptep, flags);
235 		/*
236 		 * Update the same virtual address entry.
237 		 */
238 		*ptep = pte;
239 		tlb_update_addr(sva, KERNEL_PID, pte, 0);
240 	}
241 
242 	return false;
243 }
244 
245 bus_space_handle_t
__hpcmips_cacheable(struct bus_space_tag_hpcmips * t,bus_addr_t bpa,bus_size_t size,int cacheable)246 __hpcmips_cacheable(struct bus_space_tag_hpcmips *t, bus_addr_t bpa,
247     bus_size_t size, int cacheable)
248 {
249 	if (t->base >= MIPS_KSEG2_START) {
250 		const vaddr_t sva = mips_trunc_page(bpa);
251 		const vaddr_t eva = mips_round_page(bpa + size);
252 		pmap_pte_process(pmap_kernel(), sva, eva,
253 		    mips_pte_cachechange, cacheable);
254 		return bpa;
255 	}
256 
257 	return cacheable ? MIPS_PHYS_TO_KSEG0(bpa) : MIPS_PHYS_TO_KSEG1(bpa);
258 }
259 
260 /* ARGSUSED */
261 int
__bs_map(bus_space_tag_t tx,bus_addr_t bpa,bus_size_t size,int flags,bus_space_handle_t * bshp)262 __bs_map(bus_space_tag_t tx, bus_addr_t bpa, bus_size_t size, int flags,
263     bus_space_handle_t *bshp)
264 {
265 	struct bus_space_tag_hpcmips *t = (struct bus_space_tag_hpcmips *)tx;
266 	int err;
267 	int cacheable = flags & BUS_SPACE_MAP_CACHEABLE;
268 
269 	DPRINTF(("\tbus_space_map:%#lx(%#lx)+%#lx\n",
270 	    bpa, bpa + t->base, size));
271 
272 	if (!t->extent) { /* Before autoconfiguration, can't use extent */
273 		DPRINTF(("bus_space_map: map temporary region:"
274 		    "0x%08lx-0x%08lx\n", bpa, bpa+size));
275 		bpa += t->base;
276 	} else {
277 		bpa += t->base;
278 		if ((err = extent_alloc_region(t->extent, bpa, size,
279 		    EX_NOWAIT|EX_MALLOCOK))) {
280 			DPRINTF(("\tbus_space_map: "
281 			    "extent_alloc_region() failed\n"));
282 			return (err);
283 		}
284 	}
285 	*bshp = __hpcmips_cacheable(t, bpa, size, cacheable);
286 
287 	return (0);
288 }
289 
290 /* ARGSUSED */
291 void
__bs_unmap(bus_space_tag_t tx,bus_space_handle_t bsh,bus_size_t size)292 __bs_unmap(bus_space_tag_t tx, bus_space_handle_t bsh, bus_size_t size)
293 {
294 	struct bus_space_tag_hpcmips *t = (struct bus_space_tag_hpcmips *)tx;
295 	int err;
296 	u_int32_t addr;
297 
298 	if (!t->extent) {
299 		return; /* Before autoconfiguration, can't use extent */
300 	}
301 
302 	if (t->base < MIPS_KSEG2_START) {
303 		addr = MIPS_KSEG1_TO_PHYS(bsh);
304 	} else {
305 		addr = bsh;
306 	}
307 
308 	if ((err = extent_free(t->extent, addr, size, EX_NOWAIT))) {
309 		DPRINTF(("warning: %#lx-%#lx of %s space lost\n",
310 		    bsh, bsh+size, t->name));
311 	}
312 }
313 
314 /* ARGSUSED */
315 int
__bs_subregion(bus_space_tag_t t,bus_space_handle_t bsh,bus_size_t offset,bus_size_t size,bus_space_handle_t * nbshp)316 __bs_subregion(bus_space_tag_t t, bus_space_handle_t bsh,
317     bus_size_t offset, bus_size_t size, bus_space_handle_t *nbshp)
318 {
319 
320 	*nbshp = bsh + offset;
321 
322 	return (0);
323 }
324 
325 /* ARGSUSED */
326 int
__bs_alloc(bus_space_tag_t tx,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)327 __bs_alloc(bus_space_tag_t tx, bus_addr_t rstart, bus_addr_t rend,
328     bus_size_t size, bus_size_t alignment, bus_size_t boundary, int flags,
329     bus_addr_t *bpap, bus_space_handle_t *bshp)
330 {
331 	struct bus_space_tag_hpcmips *t = (struct bus_space_tag_hpcmips *)tx;
332 	int cacheable = flags & BUS_SPACE_MAP_CACHEABLE;
333 	u_long bpa;
334 	int err;
335 
336 	if (!t->extent)
337 		panic("bus_space_alloc: no extent");
338 
339 	rstart += t->base;
340 	rend += t->base;
341 	if ((err = extent_alloc_subregion(t->extent, rstart, rend, size,
342 	    alignment, boundary, EX_FAST|EX_NOWAIT|EX_MALLOCOK, &bpa))) {
343 		return (err);
344 	}
345 
346 	DPRINTF(("\tbus_space_alloc:%#lx(%#lx)+%#lx\n", bpa,
347 	    bpa - t->base, size));
348 
349 	*bshp = __hpcmips_cacheable(t, bpa, size, cacheable);
350 
351 	if (bpap) {
352 		*bpap = bpa;
353 	}
354 
355 	return (0);
356 }
357 
358 /* ARGSUSED */
359 void
__bs_free(bus_space_tag_t t,bus_space_handle_t bsh,bus_size_t size)360 __bs_free(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t size)
361 {
362 	/* bus_space_unmap() does all that we need to do. */
363 	bus_space_unmap(t, bsh, size);
364 }
365 
366 void
__bs_barrier(bus_space_tag_t t,bus_space_handle_t bsh,bus_size_t offset,bus_size_t len,int flags)367 __bs_barrier(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset,
368     bus_size_t len, int flags)
369 {
370 	wbflush();
371 }
372 
373 int
__bs_peek(bus_space_tag_t t,bus_space_handle_t bsh,bus_size_t offset,size_t size,void * ptr)374 __bs_peek(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset,
375     size_t size, void *ptr)
376 {
377 	u_int32_t tmp;
378 
379 	if (badaddr((void *)(bsh + offset), size))
380 		return (-1);
381 
382 	if (ptr == NULL)
383 		ptr = &tmp;
384 
385 	switch(size) {
386 	case 1:
387 		*((u_int8_t *)ptr) = bus_space_read_1(t, bsh, offset);
388 		break;
389 	case 2:
390 		*((u_int16_t *)ptr) = bus_space_read_2(t, bsh, offset);
391 		break;
392 	case 4:
393 		*((u_int32_t *)ptr) = bus_space_read_4(t, bsh, offset);
394 		break;
395 	default:
396 		panic("bus_space_peek: bad size, %d", size);
397 	}
398 
399 	return (0);
400 }
401 
402 int
__bs_poke(bus_space_tag_t t,bus_space_handle_t bsh,bus_size_t offset,size_t size,u_int32_t val)403 __bs_poke(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset,
404     size_t size, u_int32_t val)
405 {
406 
407 	if (badaddr((void *)(bsh + offset), size))
408 		return (-1);
409 
410 	switch(size) {
411 	case 1:
412 		bus_space_write_1(t, bsh, offset, val);
413 		break;
414 	case 2:
415 		bus_space_write_2(t, bsh, offset, val);
416 		break;
417 	case 4:
418 		bus_space_write_4(t, bsh, offset, val);
419 		break;
420 	default:
421 		panic("bus_space_poke: bad size, %d", size);
422 	}
423 
424 	return (0);
425 }
426 
427 u_int8_t
__bs_r_1(bus_space_tag_t t,bus_space_handle_t bsh,bus_size_t offset)428 __bs_r_1(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset)
429 {
430 	wbflush();
431 	return (*(volatile u_int8_t *)(bsh + offset));
432 }
433 
434 u_int16_t
__bs_r_2(bus_space_tag_t t,bus_space_handle_t bsh,bus_size_t offset)435 __bs_r_2(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset)
436 {
437 	wbflush();
438 	return (*(volatile u_int16_t *)(bsh + offset));
439 }
440 
441 u_int32_t
__bs_r_4(bus_space_tag_t t,bus_space_handle_t bsh,bus_size_t offset)442 __bs_r_4(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset)
443 {
444 	wbflush();
445 	return (*(volatile u_int32_t *)(bsh + offset));
446 }
447 
448 void
__bs_rm_1(bus_space_tag_t t,bus_space_handle_t bsh,bus_size_t offset,u_int8_t * addr,bus_size_t count)449 __bs_rm_1(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset,
450     u_int8_t *addr, bus_size_t count) {
451 	while (count--)
452 		*addr++ = bus_space_read_1(t, bsh, offset);
453 }
454 
455 void
__bs_rm_2(bus_space_tag_t t,bus_space_handle_t bsh,bus_size_t offset,u_int16_t * addr,bus_size_t count)456 __bs_rm_2(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset,
457     u_int16_t *addr, bus_size_t count)
458 {
459 	while (count--)
460 		*addr++ = bus_space_read_2(t, bsh, offset);
461 }
462 
463 void
__bs_rm_4(bus_space_tag_t t,bus_space_handle_t bsh,bus_size_t offset,u_int32_t * addr,bus_size_t count)464 __bs_rm_4(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset,
465     u_int32_t *addr, bus_size_t count)
466 {
467 	while (count--)
468 		*addr++ = bus_space_read_4(t, bsh, offset);
469 }
470 
471 void
__bs_rr_1(bus_space_tag_t t,bus_space_handle_t bsh,bus_size_t offset,u_int8_t * addr,bus_size_t count)472 __bs_rr_1(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset,
473     u_int8_t *addr, bus_size_t count)
474 {
475 	while (count--) {
476 		*addr++ = bus_space_read_1(t, bsh, offset);
477 		offset += sizeof(*addr);
478 	}
479 }
480 
481 void
__bs_rr_2(bus_space_tag_t t,bus_space_handle_t bsh,bus_size_t offset,u_int16_t * addr,bus_size_t count)482 __bs_rr_2(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset,
483     u_int16_t *addr, bus_size_t count)
484 {
485 	while (count--) {
486 		*addr++ = bus_space_read_2(t, bsh, offset);
487 		offset += sizeof(*addr);
488 	}
489 }
490 
491 void
__bs_rr_4(bus_space_tag_t t,bus_space_handle_t bsh,bus_size_t offset,u_int32_t * addr,bus_size_t count)492 __bs_rr_4(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset,
493     u_int32_t *addr, bus_size_t count)
494 {
495 	while (count--) {
496 		*addr++ = bus_space_read_4(t, bsh, offset);
497 		offset += sizeof(*addr);
498 	}
499 }
500 
501 void
__bs_w_1(bus_space_tag_t t,bus_space_handle_t bsh,bus_size_t offset,u_int8_t value)502 __bs_w_1(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset,
503     u_int8_t value)
504 {
505 	*(volatile u_int8_t *)(bsh + offset) = value;
506 	wbflush();
507 }
508 
509 void
__bs_w_2(bus_space_tag_t t,bus_space_handle_t bsh,bus_size_t offset,u_int16_t value)510 __bs_w_2(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset,
511     u_int16_t value)
512 {
513 	*(volatile u_int16_t *)(bsh + offset) = value;
514 	wbflush();
515 }
516 
517 void
__bs_w_4(bus_space_tag_t t,bus_space_handle_t bsh,bus_size_t offset,u_int32_t value)518 __bs_w_4(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset,
519     u_int32_t value)
520 {
521 	*(volatile u_int32_t *)(bsh + offset) = value;
522 	wbflush();
523 }
524 
525 void
__bs_wm_1(bus_space_tag_t t,bus_space_handle_t bsh,bus_size_t offset,const u_int8_t * addr,bus_size_t count)526 __bs_wm_1(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset,
527     const u_int8_t *addr, bus_size_t count)
528 {
529 	while (count--)
530 		bus_space_write_1(t, bsh, offset, *addr++);
531 }
532 
533 void
__bs_wm_2(bus_space_tag_t t,bus_space_handle_t bsh,bus_size_t offset,const u_int16_t * addr,bus_size_t count)534 __bs_wm_2(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset,
535     const u_int16_t *addr, bus_size_t count)
536 {
537 	while (count--)
538 		bus_space_write_2(t, bsh, offset, *addr++);
539 }
540 
541 void
__bs_wm_4(bus_space_tag_t t,bus_space_handle_t bsh,bus_size_t offset,const u_int32_t * addr,bus_size_t count)542 __bs_wm_4(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset,
543     const u_int32_t *addr, bus_size_t count)
544 {
545 	while (count--)
546 		bus_space_write_4(t, bsh, offset, *addr++);
547 }
548 
549 void
__bs_wr_1(bus_space_tag_t t,bus_space_handle_t bsh,bus_size_t offset,const u_int8_t * addr,bus_size_t count)550 __bs_wr_1(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset,
551     const u_int8_t *addr, bus_size_t count)
552 {
553 	while (count--) {
554 		bus_space_write_1(t, bsh, offset, *addr++);
555 		offset += sizeof(*addr);
556 	}
557 }
558 
559 void
__bs_wr_2(bus_space_tag_t t,bus_space_handle_t bsh,bus_size_t offset,const u_int16_t * addr,bus_size_t count)560 __bs_wr_2(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset,
561     const u_int16_t *addr, bus_size_t count)
562 {
563 	while (count--) {
564 		bus_space_write_2(t, bsh, offset, *addr++);
565 		offset += sizeof(*addr);
566 	}
567 }
568 
569 void
__bs_wr_4(bus_space_tag_t t,bus_space_handle_t bsh,bus_size_t offset,const u_int32_t * addr,bus_size_t count)570 __bs_wr_4(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset,
571     const u_int32_t *addr, bus_size_t count)
572 {
573 	while (count--) {
574 		bus_space_write_4(t, bsh, offset, *addr++);
575 		offset += sizeof(*addr);
576 	}
577 }
578 
579 void
__bs_sm_1(bus_space_tag_t t,bus_space_handle_t bsh,bus_size_t offset,u_int8_t value,bus_size_t count)580 __bs_sm_1(bus_space_tag_t t, bus_space_handle_t bsh,
581     bus_size_t offset, u_int8_t value, bus_size_t count)
582 {
583 	while (count--)
584 		bus_space_write_1(t, bsh, offset, value);
585 }
586 
587 void
__bs_sm_2(bus_space_tag_t t,bus_space_handle_t bsh,bus_size_t offset,u_int16_t value,bus_size_t count)588 __bs_sm_2(bus_space_tag_t t, bus_space_handle_t bsh,
589     bus_size_t offset, u_int16_t value, bus_size_t count)
590 {
591 	while (count--)
592 		bus_space_write_2(t, bsh, offset, value);
593 }
594 
595 void
__bs_sm_4(bus_space_tag_t t,bus_space_handle_t bsh,bus_size_t offset,u_int32_t value,bus_size_t count)596 __bs_sm_4(bus_space_tag_t t, bus_space_handle_t bsh,
597     bus_size_t offset, u_int32_t value, bus_size_t count)
598 {
599 	while (count--)
600 		bus_space_write_4(t, bsh, offset, value);
601 }
602 
603 
604 void
__bs_sr_1(bus_space_tag_t t,bus_space_handle_t bsh,bus_size_t offset,u_int8_t value,bus_size_t count)605 __bs_sr_1(bus_space_tag_t t, bus_space_handle_t bsh,
606     bus_size_t offset, u_int8_t value, bus_size_t count)
607 {
608 	while (count--) {
609 		bus_space_write_1(t, bsh, offset, value);
610 		offset += (value);
611 	}
612 }
613 
614 void
__bs_sr_2(bus_space_tag_t t,bus_space_handle_t bsh,bus_size_t offset,u_int16_t value,bus_size_t count)615 __bs_sr_2(bus_space_tag_t t, bus_space_handle_t bsh,
616     bus_size_t offset, u_int16_t value, bus_size_t count)
617 {
618 	while (count--) {
619 		bus_space_write_2(t, bsh, offset, value);
620 		offset += (value);
621 	}
622 }
623 
624 void
__bs_sr_4(bus_space_tag_t t,bus_space_handle_t bsh,bus_size_t offset,u_int32_t value,bus_size_t count)625 __bs_sr_4(bus_space_tag_t t, bus_space_handle_t bsh,
626     bus_size_t offset, u_int32_t value, bus_size_t count)
627 {
628 	while (count--) {
629 		bus_space_write_4(t, bsh, offset, value);
630 		offset += (value);
631 	}
632 }
633 
634 #define __bs_c_n(n)							\
635 void __CONCAT(__bs_c_,n)(bus_space_tag_t t, bus_space_handle_t h1,	\
636     bus_size_t o1, bus_space_handle_t h2, bus_size_t o2, bus_size_t c)	\
637 {									\
638 	bus_size_t o;							\
639 									\
640 	if ((h1 + o1) >= (h2 + o2)) {					\
641 		/* src after dest: copy forward */			\
642 		for (o = 0; c != 0; c--, o += n)			\
643 			__CONCAT(bus_space_write_,n)(t, h2, o2 + o,	\
644 			    __CONCAT(bus_space_read_,n)(t, h1, o1 + o));\
645 	} else {							\
646 		/* dest after src: copy backwards */			\
647 		for (o = (c - 1) * n; c != 0; c--, o -= n)		\
648 			__CONCAT(bus_space_write_,n)(t, h2, o2 + o,	\
649 			    __CONCAT(bus_space_read_,n)(t, h1, o1 + o));\
650 	}								\
651 }
652 
653 __bs_c_n(1)
654 __bs_c_n(2)
655 __bs_c_n(4)
656