xref: /netbsd/sys/arch/alpha/tc/tc_bus_mem.c (revision 7189b781)
1 /* $NetBSD: tc_bus_mem.c,v 1.40 2021/07/04 22:42:36 thorpej Exp $ */
2 
3 /*
4  * Copyright (c) 1996 Carnegie-Mellon University.
5  * All rights reserved.
6  *
7  * Author: Chris G. Demetriou
8  *
9  * Permission to use, copy, modify and distribute this software and
10  * its documentation is hereby granted, provided that both the copyright
11  * notice and this permission notice appear in all copies of the
12  * software, derivative works or modified versions, and any portions
13  * thereof, and that both notices appear in supporting documentation.
14  *
15  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
16  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
17  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
18  *
19  * Carnegie Mellon requests users of this software to return to
20  *
21  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
22  *  School of Computer Science
23  *  Carnegie Mellon University
24  *  Pittsburgh PA 15213-3890
25  *
26  * any improvements or extensions that they make and grant Carnegie the
27  * rights to redistribute these changes.
28  */
29 
30 /*
31  * Common TURBOchannel Chipset "bus memory" functions.
32  */
33 
34 #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
35 
36 __KERNEL_RCSID(0, "$NetBSD: tc_bus_mem.c,v 1.40 2021/07/04 22:42:36 thorpej Exp $");
37 
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/syslog.h>
41 #include <sys/device.h>
42 
43 #include <sys/bus.h>
44 #include <dev/tc/tcvar.h>
45 
46 #define	__C(A,B)	__CONCAT(A,B)
47 
48 /* mapping/unmapping */
49 static int	tc_mem_map(void *, bus_addr_t, bus_size_t, int,
50 		    bus_space_handle_t *, int);
51 static void	tc_mem_unmap(void *, bus_space_handle_t, bus_size_t, int);
52 static int	tc_mem_subregion(void *, bus_space_handle_t, bus_size_t,
53 		    bus_size_t, bus_space_handle_t *);
54 
55 static int	tc_mem_translate(void *, bus_addr_t, bus_size_t,
56 		    int, struct alpha_bus_space_translation *);
57 static int	tc_mem_get_window(void *, int,
58 		    struct alpha_bus_space_translation *);
59 
60 /* allocation/deallocation */
61 static int	tc_mem_alloc(void *, bus_addr_t, bus_addr_t, bus_size_t,
62 		    bus_size_t, bus_addr_t, int, bus_addr_t *,
63 		    bus_space_handle_t *);
64 static void	tc_mem_free(void *, bus_space_handle_t, bus_size_t);
65 
66 /* get kernel virtual address */
67 static void *	tc_mem_vaddr(void *, bus_space_handle_t);
68 
69 /* mmap for user */
70 static paddr_t	tc_mem_mmap(void *, bus_addr_t, off_t, int, int);
71 
72 /* barrier */
73 static inline void tc_mem_barrier(void *, bus_space_handle_t,
74 		    bus_size_t, bus_size_t, int);
75 
76 /* read (single) */
77 static inline uint8_t  tc_mem_read_1(void *, bus_space_handle_t, bus_size_t);
78 static inline uint16_t tc_mem_read_2(void *, bus_space_handle_t, bus_size_t);
79 static inline uint32_t tc_mem_read_4(void *, bus_space_handle_t, bus_size_t);
80 static inline uint64_t tc_mem_read_8(void *, bus_space_handle_t, bus_size_t);
81 
82 /* read multiple */
83 static void	tc_mem_read_multi_1(void *, bus_space_handle_t,
84 		    bus_size_t, uint8_t *, bus_size_t);
85 static void	tc_mem_read_multi_2(void *, bus_space_handle_t,
86 		    bus_size_t, uint16_t *, bus_size_t);
87 static void	tc_mem_read_multi_4(void *, bus_space_handle_t,
88 		    bus_size_t, uint32_t *, bus_size_t);
89 static void	tc_mem_read_multi_8(void *, bus_space_handle_t,
90 		    bus_size_t, uint64_t *, bus_size_t);
91 
92 /* read region */
93 static void	tc_mem_read_region_1(void *, bus_space_handle_t,
94 		    bus_size_t, uint8_t *, bus_size_t);
95 static void	tc_mem_read_region_2(void *, bus_space_handle_t,
96 		    bus_size_t, uint16_t *, bus_size_t);
97 static void	tc_mem_read_region_4(void *, bus_space_handle_t,
98 		    bus_size_t, uint32_t *, bus_size_t);
99 static void	tc_mem_read_region_8(void *, bus_space_handle_t,
100 		    bus_size_t, uint64_t *, bus_size_t);
101 
102 /* write (single) */
103 static inline void tc_mem_write_1(void *, bus_space_handle_t, bus_size_t,
104 		    uint8_t);
105 static inline void tc_mem_write_2(void *, bus_space_handle_t, bus_size_t,
106 		    uint16_t);
107 static inline void tc_mem_write_4(void *, bus_space_handle_t, bus_size_t,
108 		    uint32_t);
109 static inline void tc_mem_write_8(void *, bus_space_handle_t, bus_size_t,
110 		    uint64_t);
111 
112 /* write multiple */
113 static void	tc_mem_write_multi_1(void *, bus_space_handle_t,
114 		    bus_size_t, const uint8_t *, bus_size_t);
115 static void	tc_mem_write_multi_2(void *, bus_space_handle_t,
116 		    bus_size_t, const uint16_t *, bus_size_t);
117 static void	tc_mem_write_multi_4(void *, bus_space_handle_t,
118 		    bus_size_t, const uint32_t *, bus_size_t);
119 static void	tc_mem_write_multi_8(void *, bus_space_handle_t,
120 		    bus_size_t, const uint64_t *, bus_size_t);
121 
122 /* write region */
123 static void	tc_mem_write_region_1(void *, bus_space_handle_t,
124 		    bus_size_t, const uint8_t *, bus_size_t);
125 static void	tc_mem_write_region_2(void *, bus_space_handle_t,
126 		    bus_size_t, const uint16_t *, bus_size_t);
127 static void	tc_mem_write_region_4(void *, bus_space_handle_t,
128 		    bus_size_t, const uint32_t *, bus_size_t);
129 static void	tc_mem_write_region_8(void *, bus_space_handle_t,
130 		    bus_size_t, const uint64_t *, bus_size_t);
131 
132 /* set multiple */
133 static void	tc_mem_set_multi_1(void *, bus_space_handle_t,
134 		    bus_size_t, uint8_t, bus_size_t);
135 static void	tc_mem_set_multi_2(void *, bus_space_handle_t,
136 		    bus_size_t, uint16_t, bus_size_t);
137 static void	tc_mem_set_multi_4(void *, bus_space_handle_t,
138 		    bus_size_t, uint32_t, bus_size_t);
139 static void	tc_mem_set_multi_8(void *, bus_space_handle_t,
140 		    bus_size_t, uint64_t, bus_size_t);
141 
142 /* set region */
143 static void	tc_mem_set_region_1(void *, bus_space_handle_t,
144 		    bus_size_t, uint8_t, bus_size_t);
145 static void	tc_mem_set_region_2(void *, bus_space_handle_t,
146 		    bus_size_t, uint16_t, bus_size_t);
147 static void	tc_mem_set_region_4(void *, bus_space_handle_t,
148 		    bus_size_t, uint32_t, bus_size_t);
149 static void	tc_mem_set_region_8(void *, bus_space_handle_t,
150 		    bus_size_t, uint64_t, bus_size_t);
151 
152 /* copy */
153 static void	tc_mem_copy_region_1(void *, bus_space_handle_t,
154 		    bus_size_t, bus_space_handle_t, bus_size_t, bus_size_t);
155 static void	tc_mem_copy_region_2(void *, bus_space_handle_t,
156 		    bus_size_t, bus_space_handle_t, bus_size_t, bus_size_t);
157 static void	tc_mem_copy_region_4(void *, bus_space_handle_t,
158 		    bus_size_t, bus_space_handle_t, bus_size_t, bus_size_t);
159 static void	tc_mem_copy_region_8(void *, bus_space_handle_t,
160 		    bus_size_t, bus_space_handle_t, bus_size_t, bus_size_t);
161 
162 static struct alpha_bus_space tc_mem_space = {
163 	/* cookie */
164 	NULL,
165 
166 	/* mapping/unmapping */
167 	tc_mem_map,
168 	tc_mem_unmap,
169 	tc_mem_subregion,
170 
171 	tc_mem_translate,
172 	tc_mem_get_window,
173 
174 	/* allocation/deallocation */
175 	tc_mem_alloc,
176 	tc_mem_free,
177 
178 	/* get kernel virtual address */
179 	tc_mem_vaddr,
180 
181 	/* mmap for user */
182 	tc_mem_mmap,
183 
184 	/* barrier */
185 	tc_mem_barrier,
186 
187 	/* read (single) */
188 	tc_mem_read_1,
189 	tc_mem_read_2,
190 	tc_mem_read_4,
191 	tc_mem_read_8,
192 
193 	/* read multiple */
194 	tc_mem_read_multi_1,
195 	tc_mem_read_multi_2,
196 	tc_mem_read_multi_4,
197 	tc_mem_read_multi_8,
198 
199 	/* read region */
200 	tc_mem_read_region_1,
201 	tc_mem_read_region_2,
202 	tc_mem_read_region_4,
203 	tc_mem_read_region_8,
204 
205 	/* write (single) */
206 	tc_mem_write_1,
207 	tc_mem_write_2,
208 	tc_mem_write_4,
209 	tc_mem_write_8,
210 
211 	/* write multiple */
212 	tc_mem_write_multi_1,
213 	tc_mem_write_multi_2,
214 	tc_mem_write_multi_4,
215 	tc_mem_write_multi_8,
216 
217 	/* write region */
218 	tc_mem_write_region_1,
219 	tc_mem_write_region_2,
220 	tc_mem_write_region_4,
221 	tc_mem_write_region_8,
222 
223 	/* set multiple */
224 	tc_mem_set_multi_1,
225 	tc_mem_set_multi_2,
226 	tc_mem_set_multi_4,
227 	tc_mem_set_multi_8,
228 
229 	/* set region */
230 	tc_mem_set_region_1,
231 	tc_mem_set_region_2,
232 	tc_mem_set_region_4,
233 	tc_mem_set_region_8,
234 
235 	/* copy */
236 	tc_mem_copy_region_1,
237 	tc_mem_copy_region_2,
238 	tc_mem_copy_region_4,
239 	tc_mem_copy_region_8,
240 };
241 
242 bus_space_tag_t
tc_bus_mem_init(void * memv)243 tc_bus_mem_init(void *memv)
244 {
245 	bus_space_tag_t h = &tc_mem_space;
246 
247 	h->abs_cookie = memv;
248 	return (h);
249 }
250 
251 /* ARGSUSED */
252 static int
tc_mem_translate(void * v,bus_addr_t memaddr,bus_size_t memlen,int flags,struct alpha_bus_space_translation * abst)253 tc_mem_translate(void *v, bus_addr_t memaddr, bus_size_t memlen, int flags, struct alpha_bus_space_translation *abst)
254 {
255 
256 	return (EOPNOTSUPP);
257 }
258 
259 /* ARGSUSED */
260 static int
tc_mem_get_window(void * v,int window,struct alpha_bus_space_translation * abst)261 tc_mem_get_window(void *v, int window, struct alpha_bus_space_translation *abst)
262 {
263 
264 	return (EOPNOTSUPP);
265 }
266 
267 /* ARGSUSED */
268 static int
tc_mem_map(void * v,bus_addr_t memaddr,bus_size_t memsize,int flags,bus_space_handle_t * memhp,int acct)269 tc_mem_map(void *v, bus_addr_t memaddr, bus_size_t memsize, int flags, bus_space_handle_t *memhp, int acct)
270 {
271 	int cacheable = flags & BUS_SPACE_MAP_CACHEABLE;
272 	int linear = flags & BUS_SPACE_MAP_LINEAR;
273 
274 	/* Requests for linear uncacheable space can't be satisfied. */
275 	if (linear && !cacheable)
276 		return (EOPNOTSUPP);
277 
278 	if (memaddr & 0x7)
279 		panic("%s: need 8 byte alignment", __func__);
280 	if (cacheable)
281 		*memhp = ALPHA_PHYS_TO_K0SEG(memaddr);
282 	else
283 		*memhp = ALPHA_PHYS_TO_K0SEG(TC_DENSE_TO_SPARSE(memaddr));
284 	return (0);
285 }
286 
287 /* ARGSUSED */
288 static void
tc_mem_unmap(void * v,bus_space_handle_t memh,bus_size_t memsize,int acct)289 tc_mem_unmap(void *v, bus_space_handle_t memh, bus_size_t memsize, int acct)
290 {
291 
292 	/* XXX XX XXX nothing to do. */
293 }
294 
295 static int
tc_mem_subregion(void * v,bus_space_handle_t memh,bus_size_t offset,bus_size_t size,bus_space_handle_t * nmemh)296 tc_mem_subregion(void *v, bus_space_handle_t memh, bus_size_t offset, bus_size_t size, bus_space_handle_t *nmemh)
297 {
298 
299 	/* Disallow subregioning that would make the handle unaligned. */
300 	if ((offset & 0x7) != 0)
301 		return (1);
302 
303 	if ((memh & TC_SPACE_SPARSE) != 0)
304 		*nmemh = memh + (offset << 1);
305 	else
306 		*nmemh = memh + offset;
307 
308 	return (0);
309 }
310 
311 static int
tc_mem_alloc(void * v,bus_addr_t rstart,bus_addr_t rend,bus_size_t size,bus_size_t align,bus_size_t boundary,int flags,bus_addr_t * addrp,bus_space_handle_t * bshp)312 tc_mem_alloc(void *v, bus_addr_t rstart, bus_addr_t rend, bus_size_t size, bus_size_t align, bus_size_t boundary, int flags, bus_addr_t *addrp, bus_space_handle_t *bshp)
313 {
314 
315 	/* XXX XXX XXX XXX XXX XXX */
316 	panic("%s: unimplemented", __func__);
317 }
318 
319 static void
tc_mem_free(void * v,bus_space_handle_t bsh,bus_size_t size)320 tc_mem_free(void *v, bus_space_handle_t bsh, bus_size_t size)
321 {
322 
323 	/* XXX XXX XXX XXX XXX XXX */
324 	panic("%s: unimplemented", __func__);
325 }
326 
327 static void *
tc_mem_vaddr(void * v,bus_space_handle_t bsh)328 tc_mem_vaddr(void *v, bus_space_handle_t bsh)
329 {
330 #ifdef DIAGNOSTIC
331 	if ((bsh & TC_SPACE_SPARSE) != 0) {
332 		/*
333 		 * tc_mem_map() catches linear && !cacheable,
334 		 * so we shouldn't come here
335 		 */
336 		panic("%s: can't do sparse", __func__);
337 	}
338 #endif
339 	return ((void *)bsh);
340 }
341 
342 static paddr_t
tc_mem_mmap(void * v,bus_addr_t addr,off_t off,int prot,int flags)343 tc_mem_mmap(void *v, bus_addr_t addr, off_t off, int prot, int flags)
344 {
345 	int linear = flags & BUS_SPACE_MAP_LINEAR;
346 	bus_addr_t rv;
347 
348 	if (linear)
349 		rv = addr + off;
350 	else
351 		rv = TC_DENSE_TO_SPARSE(addr + off);
352 
353 	return (alpha_btop(rv));
354 }
355 
356 static inline void
tc_mem_barrier(void * v,bus_space_handle_t h,bus_size_t o,bus_size_t l,int f)357 tc_mem_barrier(void *v, bus_space_handle_t h, bus_size_t o, bus_size_t l, int f)
358 {
359 
360 	if ((f & BUS_SPACE_BARRIER_READ) != 0)
361 		alpha_mb();
362 	else if ((f & BUS_SPACE_BARRIER_WRITE) != 0)
363 		alpha_wmb();
364 }
365 
366 /*
367  * https://web-docs.gsi.de/~kraemer/COLLECTION/DEC/d3syspmb.pdf
368  * http://h20565.www2.hpe.com/hpsc/doc/public/display?docId=emr_na-c04623255
369  */
370 #define TC_SPARSE_PTR(memh, off) \
371     ((void *)((memh) + ((off & ((bus_size_t)-1 << 2)) << 1)))
372 
373 static inline uint8_t
tc_mem_read_1(void * v,bus_space_handle_t memh,bus_size_t off)374 tc_mem_read_1(void *v, bus_space_handle_t memh, bus_size_t off)
375 {
376 
377 	alpha_mb();		/* XXX XXX XXX */
378 
379 	if ((memh & TC_SPACE_SPARSE) != 0) {
380 		volatile uint32_t *p;
381 
382 		p = TC_SPARSE_PTR(memh, off);
383 		return ((*p >> ((off & 3) << 3)) & 0xff);
384 	} else {
385 		volatile uint8_t *p;
386 
387 		p = (uint8_t *)(memh + off);
388 		return (*p);
389 	}
390 }
391 
392 static inline uint16_t
tc_mem_read_2(void * v,bus_space_handle_t memh,bus_size_t off)393 tc_mem_read_2(void *v, bus_space_handle_t memh, bus_size_t off)
394 {
395 
396 	alpha_mb();		/* XXX XXX XXX */
397 
398 	if ((memh & TC_SPACE_SPARSE) != 0) {
399 		volatile uint32_t *p;
400 
401 		p = TC_SPARSE_PTR(memh, off);
402 		return ((*p >> ((off & 2) << 3)) & 0xffff);
403 	} else {
404 		volatile uint16_t *p;
405 
406 		p = (uint16_t *)(memh + off);
407 		return (*p);
408 	}
409 }
410 
411 static inline uint32_t
tc_mem_read_4(void * v,bus_space_handle_t memh,bus_size_t off)412 tc_mem_read_4(void *v, bus_space_handle_t memh, bus_size_t off)
413 {
414 	volatile uint32_t *p;
415 
416 	alpha_mb();		/* XXX XXX XXX */
417 
418 	if ((memh & TC_SPACE_SPARSE) != 0)
419 		/* Nothing special to do for 4-byte sparse space accesses */
420 		p = (uint32_t *)(memh + (off << 1));
421 	else
422 		/*
423 		 * LDL to a dense space address always results in two
424 		 * TURBOchannel I/O read transactions to consecutive longword
425 		 * addresses. Use caution in dense space if the option has
426 		 * registers with read side effects.
427 		 */
428 		p = (uint32_t *)(memh + off);
429 	return (*p);
430 }
431 
432 static inline uint64_t
tc_mem_read_8(void * v,bus_space_handle_t memh,bus_size_t off)433 tc_mem_read_8(void *v, bus_space_handle_t memh, bus_size_t off)
434 {
435 	volatile uint64_t *p;
436 
437 	alpha_mb();		/* XXX XXX XXX */
438 
439 	if ((memh & TC_SPACE_SPARSE) != 0)
440 		panic("%s: not implemented for sparse space", __func__);
441 
442 	p = (uint64_t *)(memh + off);
443 	return (*p);
444 }
445 
446 #define	tc_mem_read_multi_N(BYTES,TYPE)					\
447 static void								\
448 __C(tc_mem_read_multi_,BYTES)(						\
449 	void *v,							\
450 	bus_space_handle_t h,						\
451 	bus_size_t o,							\
452 	TYPE *a,							\
453 	bus_size_t c)							\
454 {									\
455 									\
456 	while (c-- > 0) {						\
457 		tc_mem_barrier(v, h, o, sizeof *a, BUS_SPACE_BARRIER_READ); \
458 		*a++ = __C(tc_mem_read_,BYTES)(v, h, o);		\
459 	}								\
460 }
461 tc_mem_read_multi_N(1,uint8_t)
462 tc_mem_read_multi_N(2,uint16_t)
463 tc_mem_read_multi_N(4,uint32_t)
464 tc_mem_read_multi_N(8,uint64_t)
465 
466 #define	tc_mem_read_region_N(BYTES,TYPE)				\
467 static void								\
468 __C(tc_mem_read_region_,BYTES)(						\
469 	void *v,							\
470 	bus_space_handle_t h,						\
471 	bus_size_t o,							\
472 	TYPE *a,							\
473 	bus_size_t c)							\
474 {									\
475 									\
476 	while (c-- > 0) {						\
477 		*a++ = __C(tc_mem_read_,BYTES)(v, h, o);		\
478 		o += sizeof *a;						\
479 	}								\
480 }
481 tc_mem_read_region_N(1,uint8_t)
482 tc_mem_read_region_N(2,uint16_t)
483 tc_mem_read_region_N(4,uint32_t)
484 tc_mem_read_region_N(8,uint64_t)
485 
486 #define TC_SPARSE_WR_PVAL(msk, b, v) \
487     ((UINT64_C(msk) << (32 + (b))) | ((uint64_t)(v) << ((b) << 3)))
488 
489 static inline void
tc_mem_write_1(void * v,bus_space_handle_t memh,bus_size_t off,uint8_t val)490 tc_mem_write_1(void *v, bus_space_handle_t memh, bus_size_t off, uint8_t val)
491 {
492 
493 	if ((memh & TC_SPACE_SPARSE) != 0) {
494 		volatile uint64_t *p;
495 
496 		p = TC_SPARSE_PTR(memh, off);
497 		*p = TC_SPARSE_WR_PVAL(0x1, off & 3, val);
498 	} else
499 		panic("%s: not implemented for dense space", __func__);
500 
501 	alpha_mb();		/* XXX XXX XXX */
502 }
503 
504 static inline void
tc_mem_write_2(void * v,bus_space_handle_t memh,bus_size_t off,uint16_t val)505 tc_mem_write_2(void *v, bus_space_handle_t memh, bus_size_t off, uint16_t val)
506 {
507 
508 	if ((memh & TC_SPACE_SPARSE) != 0) {
509 		volatile uint64_t *p;
510 
511 		p = TC_SPARSE_PTR(memh, off);
512 		*p = TC_SPARSE_WR_PVAL(0x3, off & 2, val);
513 	} else
514 		panic("%s: not implemented for dense space", __func__);
515 
516 	alpha_mb();		/* XXX XXX XXX */
517 }
518 
519 static inline void
tc_mem_write_4(void * v,bus_space_handle_t memh,bus_size_t off,uint32_t val)520 tc_mem_write_4(void *v, bus_space_handle_t memh, bus_size_t off, uint32_t val)
521 {
522 	volatile uint32_t *p;
523 
524 	if ((memh & TC_SPACE_SPARSE) != 0)
525 		/* Nothing special to do for 4-byte sparse space accesses */
526 		p = (uint32_t *)(memh + (off << 1));
527 	else
528 		p = (uint32_t *)(memh + off);
529 	*p = val;
530 
531 	alpha_mb();		/* XXX XXX XXX */
532 }
533 
534 static inline void
tc_mem_write_8(void * v,bus_space_handle_t memh,bus_size_t off,uint64_t val)535 tc_mem_write_8(void *v, bus_space_handle_t memh, bus_size_t off, uint64_t val)
536 {
537 	volatile uint64_t *p;
538 
539 	if ((memh & TC_SPACE_SPARSE) != 0)
540 		panic("%s: not implemented for sparse space", __func__);
541 
542 	p = (uint64_t *)(memh + off);
543 	*p = val;
544 
545 	alpha_mb();		/* XXX XXX XXX */
546 }
547 
548 #define	tc_mem_write_multi_N(BYTES,TYPE)				\
549 static void								\
550 __C(tc_mem_write_multi_,BYTES)(						\
551 	void *v,							\
552 	bus_space_handle_t h,						\
553 	bus_size_t o,							\
554 	const TYPE *a,							\
555 	bus_size_t c)							\
556 {									\
557 									\
558 	while (c-- > 0) {						\
559 		__C(tc_mem_write_,BYTES)(v, h, o, *a++);		\
560 		tc_mem_barrier(v, h, o, sizeof *a, BUS_SPACE_BARRIER_WRITE); \
561 	}								\
562 }
563 tc_mem_write_multi_N(1,uint8_t)
564 tc_mem_write_multi_N(2,uint16_t)
565 tc_mem_write_multi_N(4,uint32_t)
566 tc_mem_write_multi_N(8,uint64_t)
567 
568 #define	tc_mem_write_region_N(BYTES,TYPE)				\
569 static void								\
570 __C(tc_mem_write_region_,BYTES)(					\
571 	void *v,							\
572 	bus_space_handle_t h,						\
573 	bus_size_t o,							\
574 	const TYPE *a,							\
575 	bus_size_t c)							\
576 {									\
577 									\
578 	while (c-- > 0) {						\
579 		__C(tc_mem_write_,BYTES)(v, h, o, *a++);		\
580 		o += sizeof *a;						\
581 	}								\
582 }
583 tc_mem_write_region_N(1,uint8_t)
584 tc_mem_write_region_N(2,uint16_t)
585 tc_mem_write_region_N(4,uint32_t)
586 tc_mem_write_region_N(8,uint64_t)
587 
588 #define	tc_mem_set_multi_N(BYTES,TYPE)					\
589 static void								\
590 __C(tc_mem_set_multi_,BYTES)(						\
591 	void *v,							\
592 	bus_space_handle_t h,						\
593 	bus_size_t o,							\
594 	TYPE val,							\
595 	bus_size_t c)							\
596 {									\
597 									\
598 	while (c-- > 0) {						\
599 		__C(tc_mem_write_,BYTES)(v, h, o, val);			\
600 		tc_mem_barrier(v, h, o, sizeof val, BUS_SPACE_BARRIER_WRITE); \
601 	}								\
602 }
603 tc_mem_set_multi_N(1,uint8_t)
604 tc_mem_set_multi_N(2,uint16_t)
605 tc_mem_set_multi_N(4,uint32_t)
606 tc_mem_set_multi_N(8,uint64_t)
607 
608 #define	tc_mem_set_region_N(BYTES,TYPE)					\
609 static void								\
610 __C(tc_mem_set_region_,BYTES)(						\
611 	void *v,							\
612 	bus_space_handle_t h,						\
613 	bus_size_t o,							\
614 	TYPE val,							\
615 	bus_size_t c)							\
616 {									\
617 									\
618 	while (c-- > 0) {						\
619 		__C(tc_mem_write_,BYTES)(v, h, o, val);			\
620 		o += sizeof val;					\
621 	}								\
622 }
623 tc_mem_set_region_N(1,uint8_t)
624 tc_mem_set_region_N(2,uint16_t)
625 tc_mem_set_region_N(4,uint32_t)
626 tc_mem_set_region_N(8,uint64_t)
627 
628 #define	tc_mem_copy_region_N(BYTES)					\
629 static void								\
630 __C(tc_mem_copy_region_,BYTES)(						\
631 	void *v,							\
632 	bus_space_handle_t h1,						\
633 	bus_size_t o1,							\
634 	bus_space_handle_t h2,						\
635 	bus_size_t o2,							\
636 	bus_size_t c)							\
637 {									\
638 	bus_size_t o;							\
639 									\
640 	if ((h1 & TC_SPACE_SPARSE) != 0 &&				\
641 	    (h2 & TC_SPACE_SPARSE) != 0) {				\
642 		memmove((void *)(h2 + o2), (void *)(h1 + o1), c * BYTES); \
643 		return;							\
644 	}								\
645 									\
646 	if (h1 + o1 >= h2 + o2)						\
647 		/* src after dest: copy forward */			\
648 		for (o = 0; c > 0; c--, o += BYTES)			\
649 			__C(tc_mem_write_,BYTES)(v, h2, o2 + o,		\
650 			    __C(tc_mem_read_,BYTES)(v, h1, o1 + o));	\
651 	else								\
652 		/* dest after src: copy backwards */			\
653 		for (o = (c - 1) * BYTES; c > 0; c--, o -= BYTES)	\
654 			__C(tc_mem_write_,BYTES)(v, h2, o2 + o,		\
655 			    __C(tc_mem_read_,BYTES)(v, h1, o1 + o));	\
656 }
657 tc_mem_copy_region_N(1)
658 tc_mem_copy_region_N(2)
659 tc_mem_copy_region_N(4)
660 tc_mem_copy_region_N(8)
661