Home | History | Annotate | Line # | Download | only in tc
tc_bus_mem.c revision 1.15
      1 /* $NetBSD: tc_bus_mem.c,v 1.15 1997/04/07 23:40:59 cgd 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 (at) 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 <machine/options.h>		/* Config options headers */
     35 #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
     36 
     37 __KERNEL_RCSID(0, "$NetBSD: tc_bus_mem.c,v 1.15 1997/04/07 23:40:59 cgd Exp $");
     38 
     39 #include <sys/param.h>
     40 #include <sys/systm.h>
     41 #include <sys/malloc.h>
     42 #include <sys/syslog.h>
     43 #include <sys/device.h>
     44 #include <vm/vm.h>
     45 
     46 #include <machine/bus.h>
     47 #include <dev/tc/tcvar.h>
     48 
     49 /* mapping/unmapping */
     50 int		tc_mem_map __P((void *, bus_addr_t, bus_size_t, int,
     51 		    bus_space_handle_t *));
     52 void		tc_mem_unmap __P((void *, bus_space_handle_t, bus_size_t));
     53 int		tc_mem_subregion __P((void *, bus_space_handle_t, bus_size_t,
     54 		    bus_size_t, bus_space_handle_t *));
     55 
     56 /* allocation/deallocation */
     57 int		tc_mem_alloc __P((void *, bus_addr_t, bus_addr_t, bus_size_t,
     58 		    bus_size_t, bus_addr_t, int, bus_addr_t *,
     59 		    bus_space_handle_t *));
     60 void		tc_mem_free __P((void *, bus_space_handle_t, bus_size_t));
     61 
     62 /* barrier */
     63 inline void	tc_mem_barrier __P((void *, bus_space_handle_t,
     64 		    bus_size_t, bus_size_t, int));
     65 
     66 /* read (single) */
     67 inline u_int8_t	tc_mem_read_1 __P((void *, bus_space_handle_t, bus_size_t));
     68 inline u_int16_t tc_mem_read_2 __P((void *, bus_space_handle_t, bus_size_t));
     69 inline u_int32_t tc_mem_read_4 __P((void *, bus_space_handle_t, bus_size_t));
     70 inline u_int64_t tc_mem_read_8 __P((void *, bus_space_handle_t, bus_size_t));
     71 
     72 /* read multiple */
     73 void		tc_mem_read_multi_1 __P((void *, bus_space_handle_t,
     74 		    bus_size_t, u_int8_t *, bus_size_t));
     75 void		tc_mem_read_multi_2 __P((void *, bus_space_handle_t,
     76 		    bus_size_t, u_int16_t *, bus_size_t));
     77 void		tc_mem_read_multi_4 __P((void *, bus_space_handle_t,
     78 		    bus_size_t, u_int32_t *, bus_size_t));
     79 void		tc_mem_read_multi_8 __P((void *, bus_space_handle_t,
     80 		    bus_size_t, u_int64_t *, bus_size_t));
     81 
     82 /* read region */
     83 void		tc_mem_read_region_1 __P((void *, bus_space_handle_t,
     84 		    bus_size_t, u_int8_t *, bus_size_t));
     85 void		tc_mem_read_region_2 __P((void *, bus_space_handle_t,
     86 		    bus_size_t, u_int16_t *, bus_size_t));
     87 void		tc_mem_read_region_4 __P((void *, bus_space_handle_t,
     88 		    bus_size_t, u_int32_t *, bus_size_t));
     89 void		tc_mem_read_region_8 __P((void *, bus_space_handle_t,
     90 		    bus_size_t, u_int64_t *, bus_size_t));
     91 
     92 /* write (single) */
     93 inline void	tc_mem_write_1 __P((void *, bus_space_handle_t, bus_size_t,
     94 		    u_int8_t));
     95 inline void	tc_mem_write_2 __P((void *, bus_space_handle_t, bus_size_t,
     96 		    u_int16_t));
     97 inline void	tc_mem_write_4 __P((void *, bus_space_handle_t, bus_size_t,
     98 		    u_int32_t));
     99 inline void	tc_mem_write_8 __P((void *, bus_space_handle_t, bus_size_t,
    100 		    u_int64_t));
    101 
    102 /* write multiple */
    103 void		tc_mem_write_multi_1 __P((void *, bus_space_handle_t,
    104 		    bus_size_t, const u_int8_t *, bus_size_t));
    105 void		tc_mem_write_multi_2 __P((void *, bus_space_handle_t,
    106 		    bus_size_t, const u_int16_t *, bus_size_t));
    107 void		tc_mem_write_multi_4 __P((void *, bus_space_handle_t,
    108 		    bus_size_t, const u_int32_t *, bus_size_t));
    109 void		tc_mem_write_multi_8 __P((void *, bus_space_handle_t,
    110 		    bus_size_t, const u_int64_t *, bus_size_t));
    111 
    112 /* write region */
    113 void		tc_mem_write_region_1 __P((void *, bus_space_handle_t,
    114 		    bus_size_t, const u_int8_t *, bus_size_t));
    115 void		tc_mem_write_region_2 __P((void *, bus_space_handle_t,
    116 		    bus_size_t, const u_int16_t *, bus_size_t));
    117 void		tc_mem_write_region_4 __P((void *, bus_space_handle_t,
    118 		    bus_size_t, const u_int32_t *, bus_size_t));
    119 void		tc_mem_write_region_8 __P((void *, bus_space_handle_t,
    120 		    bus_size_t, const u_int64_t *, bus_size_t));
    121 
    122 /* set multiple */
    123 void		tc_mem_set_multi_1 __P((void *, bus_space_handle_t,
    124 		    bus_size_t, u_int8_t, bus_size_t));
    125 void		tc_mem_set_multi_2 __P((void *, bus_space_handle_t,
    126 		    bus_size_t, u_int16_t, bus_size_t));
    127 void		tc_mem_set_multi_4 __P((void *, bus_space_handle_t,
    128 		    bus_size_t, u_int32_t, bus_size_t));
    129 void		tc_mem_set_multi_8 __P((void *, bus_space_handle_t,
    130 		    bus_size_t, u_int64_t, bus_size_t));
    131 
    132 /* set region */
    133 void		tc_mem_set_region_1 __P((void *, bus_space_handle_t,
    134 		    bus_size_t, u_int8_t, bus_size_t));
    135 void		tc_mem_set_region_2 __P((void *, bus_space_handle_t,
    136 		    bus_size_t, u_int16_t, bus_size_t));
    137 void		tc_mem_set_region_4 __P((void *, bus_space_handle_t,
    138 		    bus_size_t, u_int32_t, bus_size_t));
    139 void		tc_mem_set_region_8 __P((void *, bus_space_handle_t,
    140 		    bus_size_t, u_int64_t, bus_size_t));
    141 
    142 /* copy */
    143 void		tc_mem_copy_1 __P((void *, bus_space_handle_t,
    144 		    bus_size_t, bus_space_handle_t, bus_size_t, bus_size_t));
    145 void		tc_mem_copy_2 __P((void *, bus_space_handle_t,
    146 		    bus_size_t, bus_space_handle_t, bus_size_t, bus_size_t));
    147 void		tc_mem_copy_4 __P((void *, bus_space_handle_t,
    148 		    bus_size_t, bus_space_handle_t, bus_size_t, bus_size_t));
    149 void		tc_mem_copy_8 __P((void *, bus_space_handle_t,
    150 		    bus_size_t, bus_space_handle_t, bus_size_t, bus_size_t));
    151 
    152 static struct alpha_bus_space tc_mem_space = {
    153 	/* cookie */
    154 	NULL,
    155 
    156 	/* mapping/unmapping */
    157 	tc_mem_map,
    158 	tc_mem_unmap,
    159 	tc_mem_subregion,
    160 
    161 	/* allocation/deallocation */
    162 	tc_mem_alloc,
    163 	tc_mem_free,
    164 
    165 	/* barrier */
    166 	tc_mem_barrier,
    167 
    168 	/* read (single) */
    169 	tc_mem_read_1,
    170 	tc_mem_read_2,
    171 	tc_mem_read_4,
    172 	tc_mem_read_8,
    173 
    174 	/* read multiple */
    175 	tc_mem_read_multi_1,
    176 	tc_mem_read_multi_2,
    177 	tc_mem_read_multi_4,
    178 	tc_mem_read_multi_8,
    179 
    180 	/* read region */
    181 	tc_mem_read_region_1,
    182 	tc_mem_read_region_2,
    183 	tc_mem_read_region_4,
    184 	tc_mem_read_region_8,
    185 
    186 	/* write (single) */
    187 	tc_mem_write_1,
    188 	tc_mem_write_2,
    189 	tc_mem_write_4,
    190 	tc_mem_write_8,
    191 
    192 	/* write multiple */
    193 	tc_mem_write_multi_1,
    194 	tc_mem_write_multi_2,
    195 	tc_mem_write_multi_4,
    196 	tc_mem_write_multi_8,
    197 
    198 	/* write region */
    199 	tc_mem_write_region_1,
    200 	tc_mem_write_region_2,
    201 	tc_mem_write_region_4,
    202 	tc_mem_write_region_8,
    203 
    204 	/* set multiple */
    205 	tc_mem_set_multi_1,
    206 	tc_mem_set_multi_2,
    207 	tc_mem_set_multi_4,
    208 	tc_mem_set_multi_8,
    209 
    210 	/* set region */
    211 	tc_mem_set_region_1,
    212 	tc_mem_set_region_2,
    213 	tc_mem_set_region_4,
    214 	tc_mem_set_region_8,
    215 
    216 	/* copy */
    217 	tc_mem_copy_1,
    218 	tc_mem_copy_2,
    219 	tc_mem_copy_4,
    220 	tc_mem_copy_8,
    221 };
    222 
    223 bus_space_tag_t
    224 tc_bus_mem_init(memv)
    225 	void *memv;
    226 {
    227 	bus_space_tag_t h = &tc_mem_space;
    228 
    229 	h->abs_cookie = memv;
    230 	return (h);
    231 }
    232 
    233 int
    234 tc_mem_map(v, memaddr, memsize, cacheable, memhp)
    235 	void *v;
    236 	bus_addr_t memaddr;
    237 	bus_size_t memsize;
    238 	int cacheable;
    239 	bus_space_handle_t *memhp;
    240 {
    241 
    242 	if (memaddr & 0x7)
    243 		panic("tc_mem_map needs 8 byte alignment");
    244 	if (cacheable)
    245 		*memhp = ALPHA_PHYS_TO_K0SEG(memaddr);
    246 	else
    247 		*memhp = ALPHA_PHYS_TO_K0SEG(TC_DENSE_TO_SPARSE(memaddr));
    248 	return (0);
    249 }
    250 
    251 void
    252 tc_mem_unmap(v, memh, memsize)
    253 	void *v;
    254 	bus_space_handle_t memh;
    255 	bus_size_t memsize;
    256 {
    257 
    258 	/* XXX XX XXX nothing to do. */
    259 }
    260 
    261 int
    262 tc_mem_subregion(v, memh, offset, size, nmemh)
    263 	void *v;
    264 	bus_space_handle_t memh, *nmemh;
    265 	bus_size_t offset, size;
    266 {
    267 
    268 	/* Disallow subregioning that would make the handle unaligned. */
    269 	if ((offset & 0x7) != 0)
    270 		return (1);
    271 
    272 	if ((memh & TC_SPACE_SPARSE) != 0)
    273 		*nmemh = memh + (offset << 1);
    274 	else
    275 		*nmemh = memh + offset;
    276 
    277 	return (0);
    278 }
    279 
    280 int
    281 tc_mem_alloc(v, rstart, rend, size, align, boundary, cacheable, addrp, bshp)
    282 	void *v;
    283 	bus_addr_t rstart, rend, *addrp;
    284 	bus_size_t size, align, boundary;
    285 	int cacheable;
    286 	bus_space_handle_t *bshp;
    287 {
    288 
    289 	/* XXX XXX XXX XXX XXX XXX */
    290 	panic("tc_mem_alloc unimplemented");
    291 }
    292 
    293 void
    294 tc_mem_free(v, bsh, size)
    295 	void *v;
    296 	bus_space_handle_t bsh;
    297 	bus_size_t size;
    298 {
    299 
    300 	/* XXX XXX XXX XXX XXX XXX */
    301 	panic("tc_mem_free unimplemented");
    302 }
    303 
    304 inline void
    305 tc_mem_barrier(v, h, o, l, f)
    306 	void *v;
    307 	bus_space_handle_t h;
    308 	bus_size_t o, l;
    309 	int f;
    310 {
    311 
    312 	if ((f & BUS_BARRIER_READ) != 0)
    313 		alpha_mb();
    314 	else if ((f & BUS_BARRIER_WRITE) != 0)
    315 		alpha_wmb();
    316 }
    317 
    318 inline u_int8_t
    319 tc_mem_read_1(v, memh, off)
    320 	void *v;
    321 	bus_space_handle_t memh;
    322 	bus_size_t off;
    323 {
    324 	volatile u_int8_t *p;
    325 
    326 	alpha_mb();		/* XXX XXX XXX */
    327 
    328 	if ((memh & TC_SPACE_SPARSE) != 0)
    329 		panic("tc_mem_read_1 not implemented for sparse space");
    330 
    331 	p = (u_int8_t *)(memh + off);
    332 	return (*p);
    333 }
    334 
    335 inline u_int16_t
    336 tc_mem_read_2(v, memh, off)
    337 	void *v;
    338 	bus_space_handle_t memh;
    339 	bus_size_t off;
    340 {
    341 	volatile u_int16_t *p;
    342 
    343 	alpha_mb();		/* XXX XXX XXX */
    344 
    345 	if ((memh & TC_SPACE_SPARSE) != 0)
    346 		panic("tc_mem_read_2 not implemented for sparse space");
    347 
    348 	p = (u_int16_t *)(memh + off);
    349 	return (*p);
    350 }
    351 
    352 inline u_int32_t
    353 tc_mem_read_4(v, memh, off)
    354 	void *v;
    355 	bus_space_handle_t memh;
    356 	bus_size_t off;
    357 {
    358 	volatile u_int32_t *p;
    359 
    360 	alpha_mb();		/* XXX XXX XXX */
    361 
    362 	if ((memh & TC_SPACE_SPARSE) != 0)
    363 		/* Nothing special to do for 4-byte sparse space accesses */
    364 		p = (u_int32_t *)(memh + (off << 1));
    365 	else
    366 		p = (u_int32_t *)(memh + off);
    367 	return (*p);
    368 }
    369 
    370 inline u_int64_t
    371 tc_mem_read_8(v, memh, off)
    372 	void *v;
    373 	bus_space_handle_t memh;
    374 	bus_size_t off;
    375 {
    376 	volatile u_int64_t *p;
    377 
    378 	alpha_mb();		/* XXX XXX XXX */
    379 
    380 	if ((memh & TC_SPACE_SPARSE) != 0)
    381 		panic("tc_mem_read_8 not implemented for sparse space");
    382 
    383 	p = (u_int64_t *)(memh + off);
    384 	return (*p);
    385 }
    386 
    387 #define	tc_mem_read_multi_N(BYTES,TYPE)					\
    388 void									\
    389 __abs_c(tc_mem_read_multi_,BYTES)(v, h, o, a, c)			\
    390 	void *v;							\
    391 	bus_space_handle_t h;						\
    392 	bus_size_t o, c;						\
    393 	TYPE *a;							\
    394 {									\
    395 									\
    396 	while (c-- > 0) {						\
    397 		tc_mem_barrier(v, h, o, sizeof *a, BUS_BARRIER_READ);	\
    398 		*a++ = __abs_c(tc_mem_read_,BYTES)(v, h, o);		\
    399 	}								\
    400 }
    401 tc_mem_read_multi_N(1,u_int8_t)
    402 tc_mem_read_multi_N(2,u_int16_t)
    403 tc_mem_read_multi_N(4,u_int32_t)
    404 tc_mem_read_multi_N(8,u_int64_t)
    405 
    406 #define	tc_mem_read_region_N(BYTES,TYPE)				\
    407 void									\
    408 __abs_c(tc_mem_read_region_,BYTES)(v, h, o, a, c)			\
    409 	void *v;							\
    410 	bus_space_handle_t h;						\
    411 	bus_size_t o, c;						\
    412 	TYPE *a;							\
    413 {									\
    414 									\
    415 	while (c-- > 0) {						\
    416 		*a++ = __abs_c(tc_mem_read_,BYTES)(v, h, o);		\
    417 		o += sizeof *a;						\
    418 	}								\
    419 }
    420 tc_mem_read_region_N(1,u_int8_t)
    421 tc_mem_read_region_N(2,u_int16_t)
    422 tc_mem_read_region_N(4,u_int32_t)
    423 tc_mem_read_region_N(8,u_int64_t)
    424 
    425 inline void
    426 tc_mem_write_1(v, memh, off, val)
    427 	void *v;
    428 	bus_space_handle_t memh;
    429 	bus_size_t off;
    430 	u_int8_t val;
    431 {
    432 
    433 	if ((memh & TC_SPACE_SPARSE) != 0) {
    434 		volatile u_int64_t *p, v;
    435 		u_int64_t shift, msk;
    436 
    437 		shift = off & 0x3;
    438 		off &= 0x3;
    439 
    440 		p = (u_int64_t *)(memh + (off << 1));
    441 
    442 		msk = ~(0x1 << shift) & 0xf;
    443 		v = (msk << 32) | (((u_int64_t)val) << (shift * 8));
    444 
    445 		*p = val;
    446 	} else {
    447 		volatile u_int8_t *p;
    448 
    449 		p = (u_int8_t *)(memh + off);
    450 		*p = val;
    451 	}
    452         alpha_mb();		/* XXX XXX XXX */
    453 }
    454 
    455 inline void
    456 tc_mem_write_2(v, memh, off, val)
    457 	void *v;
    458 	bus_space_handle_t memh;
    459 	bus_size_t off;
    460 	u_int16_t val;
    461 {
    462 
    463 	if ((memh & TC_SPACE_SPARSE) != 0) {
    464 		volatile u_int64_t *p, v;
    465 		u_int64_t shift, msk;
    466 
    467 		shift = off & 0x2;
    468 		off &= 0x3;
    469 
    470 		p = (u_int64_t *)(memh + (off << 1));
    471 
    472 		msk = ~(0x3 << shift) & 0xf;
    473 		v = (msk << 32) | (((u_int64_t)val) << (shift * 8));
    474 
    475 		*p = val;
    476 	} else {
    477 		volatile u_int16_t *p;
    478 
    479 		p = (u_int16_t *)(memh + off);
    480 		*p = val;
    481 	}
    482         alpha_mb();		/* XXX XXX XXX */
    483 }
    484 
    485 inline void
    486 tc_mem_write_4(v, memh, off, val)
    487 	void *v;
    488 	bus_space_handle_t memh;
    489 	bus_size_t off;
    490 	u_int32_t val;
    491 {
    492 	volatile u_int32_t *p;
    493 
    494 	if ((memh & TC_SPACE_SPARSE) != 0)
    495 		/* Nothing special to do for 4-byte sparse space accesses */
    496 		p = (u_int32_t *)(memh + (off << 1));
    497 	else
    498 		p = (u_int32_t *)(memh + off);
    499 	*p = val;
    500         alpha_mb();		/* XXX XXX XXX */
    501 }
    502 
    503 inline void
    504 tc_mem_write_8(v, memh, off, val)
    505 	void *v;
    506 	bus_space_handle_t memh;
    507 	bus_size_t off;
    508 	u_int64_t val;
    509 {
    510 	volatile u_int64_t *p;
    511 
    512 	if ((memh & TC_SPACE_SPARSE) != 0)
    513 		panic("tc_mem_read_8 not implemented for sparse space");
    514 
    515 	p = (u_int64_t *)(memh + off);
    516 	*p = val;
    517         alpha_mb();		/* XXX XXX XXX */
    518 }
    519 
    520 #define	tc_mem_write_multi_N(BYTES,TYPE)				\
    521 void									\
    522 __abs_c(tc_mem_write_multi_,BYTES)(v, h, o, a, c)			\
    523 	void *v;							\
    524 	bus_space_handle_t h;						\
    525 	bus_size_t o, c;						\
    526 	const TYPE *a;							\
    527 {									\
    528 									\
    529 	while (c-- > 0) {						\
    530 		__abs_c(tc_mem_write_,BYTES)(v, h, o, *a++);		\
    531 		tc_mem_barrier(v, h, o, sizeof *a, BUS_BARRIER_WRITE);	\
    532 	}								\
    533 }
    534 tc_mem_write_multi_N(1,u_int8_t)
    535 tc_mem_write_multi_N(2,u_int16_t)
    536 tc_mem_write_multi_N(4,u_int32_t)
    537 tc_mem_write_multi_N(8,u_int64_t)
    538 
    539 #define	tc_mem_write_region_N(BYTES,TYPE)				\
    540 void									\
    541 __abs_c(tc_mem_write_region_,BYTES)(v, h, o, a, c)			\
    542 	void *v;							\
    543 	bus_space_handle_t h;						\
    544 	bus_size_t o, c;						\
    545 	const TYPE *a;							\
    546 {									\
    547 									\
    548 	while (c-- > 0) {						\
    549 		__abs_c(tc_mem_write_,BYTES)(v, h, o, *a++);		\
    550 		o += sizeof *a;						\
    551 	}								\
    552 }
    553 tc_mem_write_region_N(1,u_int8_t)
    554 tc_mem_write_region_N(2,u_int16_t)
    555 tc_mem_write_region_N(4,u_int32_t)
    556 tc_mem_write_region_N(8,u_int64_t)
    557 
    558 #define	tc_mem_set_multi_N(BYTES,TYPE)					\
    559 void									\
    560 __abs_c(tc_mem_set_multi_,BYTES)(v, h, o, val, c)			\
    561 	void *v;							\
    562 	bus_space_handle_t h;						\
    563 	bus_size_t o, c;						\
    564 	TYPE val;							\
    565 {									\
    566 									\
    567 	while (c-- > 0) {						\
    568 		__abs_c(tc_mem_write_,BYTES)(v, h, o, val);		\
    569 		tc_mem_barrier(v, h, o, sizeof val, BUS_BARRIER_WRITE);	\
    570 	}								\
    571 }
    572 tc_mem_set_multi_N(1,u_int8_t)
    573 tc_mem_set_multi_N(2,u_int16_t)
    574 tc_mem_set_multi_N(4,u_int32_t)
    575 tc_mem_set_multi_N(8,u_int64_t)
    576 
    577 #define	tc_mem_set_region_N(BYTES,TYPE)					\
    578 void									\
    579 __abs_c(tc_mem_set_region_,BYTES)(v, h, o, val, c)			\
    580 	void *v;							\
    581 	bus_space_handle_t h;						\
    582 	bus_size_t o, c;						\
    583 	TYPE val;							\
    584 {									\
    585 									\
    586 	while (c-- > 0) {						\
    587 		__abs_c(tc_mem_write_,BYTES)(v, h, o, val);		\
    588 		o += sizeof val;					\
    589 	}								\
    590 }
    591 tc_mem_set_region_N(1,u_int8_t)
    592 tc_mem_set_region_N(2,u_int16_t)
    593 tc_mem_set_region_N(4,u_int32_t)
    594 tc_mem_set_region_N(8,u_int64_t)
    595 
    596 #define	tc_mem_copy_N(BYTES)						\
    597 void									\
    598 __abs_c(tc_mem_copy_,BYTES)(v, h1, o1, h2, o2, c)			\
    599 	void *v;							\
    600 	bus_space_handle_t h1, h2;					\
    601 	bus_size_t o1, o2, c;						\
    602 {									\
    603 	bus_size_t i, o;						\
    604 									\
    605 	if ((h1 & TC_SPACE_SPARSE) != 0 &&				\
    606 	    (h2 & TC_SPACE_SPARSE) != 0) {				\
    607 		bcopy((void *)(h1 + o1), (void *)(h2 + o2), c * BYTES);	\
    608 		return;							\
    609 	}								\
    610 									\
    611 	for (i = 0, o = 0; i < c; i++, o += BYTES)			\
    612 		__abs_c(tc_mem_write_,BYTES)(v, h2, o2 + o,		\
    613 		    __abs_c(tc_mem_read_,BYTES)(v, h1, o1 + o));	\
    614 }
    615 tc_mem_copy_N(1)
    616 tc_mem_copy_N(2)
    617 tc_mem_copy_N(4)
    618 tc_mem_copy_N(8)
    619