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 (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 <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 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 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 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 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 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 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 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 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 * 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 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 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 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 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 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 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 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 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 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 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