Home | History | Annotate | Line # | Download | only in hpcmips
      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
    156 hpcmips_system_bus_space(void)
    157 {
    158 
    159 	return (__sys_bus_space_tag);
    160 }
    161 
    162 struct bus_space_tag_hpcmips *
    163 hpcmips_system_bus_space_hpcmips(void)
    164 {
    165 
    166 	return (&__sys_bus_space);
    167 }
    168 
    169 struct bus_space_tag_hpcmips *
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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