1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause AND BSD-2-Clause-NetBSDE 3 * 4 * Copyright (c) KATO Takenori, 1999. 5 * 6 * All rights reserved. Unpublished rights reserved under the copyright 7 * laws of Japan. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer as 15 * the first lines of this file unmodified. 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 * 3. The name of the author may not be used to endorse or promote products 20 * derived from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 * 33 * $FreeBSD$ 34 */ 35 36 /* $NetBSD: bus.h,v 1.12 1997/10/01 08:25:15 fvdl Exp $ */ 37 38 /*- 39 * Copyright (c) 1996, 1997 The NetBSD Foundation, Inc. 40 * All rights reserved. 41 * 42 * This code is derived from software contributed to The NetBSD Foundation 43 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 44 * NASA Ames Research Center. 45 * 46 * Redistribution and use in source and binary forms, with or without 47 * modification, are permitted provided that the following conditions 48 * are met: 49 * 1. Redistributions of source code must retain the above copyright 50 * notice, this list of conditions and the following disclaimer. 51 * 2. Redistributions in binary form must reproduce the above copyright 52 * notice, this list of conditions and the following disclaimer in the 53 * documentation and/or other materials provided with the distribution. 54 * 55 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 56 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 57 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 58 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 59 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 60 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 61 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 62 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 63 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 64 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 65 * POSSIBILITY OF SUCH DAMAGE. 66 */ 67 68 /*- 69 * Copyright (c) 1996 Charles M. Hannum. All rights reserved. 70 * Copyright (c) 1996 Christopher G. Demetriou. All rights reserved. 71 * 72 * Redistribution and use in source and binary forms, with or without 73 * modification, are permitted provided that the following conditions 74 * are met: 75 * 1. Redistributions of source code must retain the above copyright 76 * notice, this list of conditions and the following disclaimer. 77 * 2. Redistributions in binary form must reproduce the above copyright 78 * notice, this list of conditions and the following disclaimer in the 79 * documentation and/or other materials provided with the distribution. 80 * 3. All advertising materials mentioning features or use of this software 81 * must display the following acknowledgement: 82 * This product includes software developed by Christopher G. Demetriou 83 * for the NetBSD Project. 84 * 4. The name of the author may not be used to endorse or promote products 85 * derived from this software without specific prior written permission 86 * 87 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 88 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 89 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 90 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 91 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 92 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 93 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 94 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 95 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 96 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 97 */ 98 99 #ifndef _MACHINE_BUS_H_ 100 #define _MACHINE_BUS_H_ 101 102 #include <machine/_bus.h> 103 #include <machine/cpufunc.h> 104 #include <machine/bus_dma.h> 105 106 #ifndef __GNUCLIKE_ASM 107 #error "no assembler code for your compiler" 108 #endif 109 110 /* 111 * Values for the x86 bus space tag, not to be used directly by MI code. 112 */ 113 #define X86_BUS_SPACE_IO 0 /* space is i/o space */ 114 #define X86_BUS_SPACE_MEM 1 /* space is mem space */ 115 116 #define BUS_SPACE_MAXSIZE_24BIT 0xFFFFFF 117 #define BUS_SPACE_MAXSIZE_32BIT 0xFFFFFFFF 118 #if defined(__amd64__) 119 #define BUS_SPACE_MAXSIZE 0xFFFFFFFFFFFFFFFFULL 120 #else 121 #define BUS_SPACE_MAXSIZE 0xFFFFFFFF 122 #endif 123 #define BUS_SPACE_MAXADDR_24BIT 0xFFFFFF 124 #define BUS_SPACE_MAXADDR_32BIT 0xFFFFFFFF 125 #if defined(__amd64__) || defined(PAE) 126 #define BUS_SPACE_MAXADDR_48BIT 0xFFFFFFFFFFFFULL 127 #define BUS_SPACE_MAXADDR 0xFFFFFFFFFFFFFFFFULL 128 #else 129 #define BUS_SPACE_MAXADDR 0xFFFFFFFF 130 #endif 131 132 #define BUS_SPACE_INVALID_DATA (~0) 133 #define BUS_SPACE_UNRESTRICTED (~0) 134 135 #define BUS_SPACE_BARRIER_READ 0x01 /* force read barrier */ 136 #define BUS_SPACE_BARRIER_WRITE 0x02 /* force write barrier */ 137 138 #ifndef SAN_RUNTIME 139 #if defined(KASAN) 140 #define BUS_SAN_PREFIX kasan 141 #elif defined(KCSAN) 142 #define BUS_SAN_PREFIX kcsan 143 #endif 144 #endif 145 146 #ifdef BUS_SAN_PREFIX 147 #include <sys/bus_san.h> 148 #else 149 150 /* 151 * Map a region of device bus space into CPU virtual address space. 152 */ 153 154 int bus_space_map(bus_space_tag_t tag, bus_addr_t addr, bus_size_t size, 155 int flags, bus_space_handle_t *bshp); 156 157 /* 158 * Unmap a region of device bus space. 159 */ 160 161 void bus_space_unmap(bus_space_tag_t tag, bus_space_handle_t bsh, 162 bus_size_t size); 163 164 /* 165 * Get a new handle for a subregion of an already-mapped area of bus space. 166 */ 167 168 static __inline int bus_space_subregion(bus_space_tag_t t, 169 bus_space_handle_t bsh, 170 bus_size_t offset, bus_size_t size, 171 bus_space_handle_t *nbshp); 172 173 static __inline int 174 bus_space_subregion(bus_space_tag_t t __unused, bus_space_handle_t bsh, 175 bus_size_t offset, bus_size_t size __unused, 176 bus_space_handle_t *nbshp) 177 { 178 179 *nbshp = bsh + offset; 180 return (0); 181 } 182 183 /* 184 * Allocate a region of memory that is accessible to devices in bus space. 185 */ 186 187 int bus_space_alloc(bus_space_tag_t t, bus_addr_t rstart, 188 bus_addr_t rend, bus_size_t size, bus_size_t align, 189 bus_size_t boundary, int flags, bus_addr_t *addrp, 190 bus_space_handle_t *bshp); 191 192 /* 193 * Free a region of bus space accessible memory. 194 */ 195 196 static __inline void bus_space_free(bus_space_tag_t t, bus_space_handle_t bsh, 197 bus_size_t size); 198 199 static __inline void 200 bus_space_free(bus_space_tag_t t __unused, bus_space_handle_t bsh __unused, 201 bus_size_t size __unused) 202 { 203 } 204 205 /* 206 * Read a 1, 2, 4, or 8 byte quantity from bus space 207 * described by tag/handle/offset. 208 */ 209 static __inline u_int8_t bus_space_read_1(bus_space_tag_t tag, 210 bus_space_handle_t handle, 211 bus_size_t offset); 212 213 static __inline u_int16_t bus_space_read_2(bus_space_tag_t tag, 214 bus_space_handle_t handle, 215 bus_size_t offset); 216 217 static __inline u_int32_t bus_space_read_4(bus_space_tag_t tag, 218 bus_space_handle_t handle, 219 bus_size_t offset); 220 221 #ifdef __amd64__ 222 static __inline uint64_t bus_space_read_8(bus_space_tag_t tag, 223 bus_space_handle_t handle, 224 bus_size_t offset); 225 #endif 226 227 static __inline u_int8_t 228 bus_space_read_1(bus_space_tag_t tag, bus_space_handle_t handle, 229 bus_size_t offset) 230 { 231 232 if (tag == X86_BUS_SPACE_IO) 233 return (inb(handle + offset)); 234 return (*(volatile u_int8_t *)(handle + offset)); 235 } 236 237 static __inline u_int16_t 238 bus_space_read_2(bus_space_tag_t tag, bus_space_handle_t handle, 239 bus_size_t offset) 240 { 241 242 if (tag == X86_BUS_SPACE_IO) 243 return (inw(handle + offset)); 244 return (*(volatile u_int16_t *)(handle + offset)); 245 } 246 247 static __inline u_int32_t 248 bus_space_read_4(bus_space_tag_t tag, bus_space_handle_t handle, 249 bus_size_t offset) 250 { 251 252 if (tag == X86_BUS_SPACE_IO) 253 return (inl(handle + offset)); 254 return (*(volatile u_int32_t *)(handle + offset)); 255 } 256 257 #ifdef __amd64__ 258 static __inline uint64_t 259 bus_space_read_8(bus_space_tag_t tag, bus_space_handle_t handle, 260 bus_size_t offset) 261 { 262 263 if (tag == X86_BUS_SPACE_IO) /* No 8 byte IO space access on x86 */ 264 return (BUS_SPACE_INVALID_DATA); 265 return (*(volatile uint64_t *)(handle + offset)); 266 } 267 #endif 268 269 /* 270 * Read `count' 1, 2, 4, or 8 byte quantities from bus space 271 * described by tag/handle/offset and copy into buffer provided. 272 */ 273 static __inline void bus_space_read_multi_1(bus_space_tag_t tag, 274 bus_space_handle_t bsh, 275 bus_size_t offset, u_int8_t *addr, 276 size_t count); 277 278 static __inline void bus_space_read_multi_2(bus_space_tag_t tag, 279 bus_space_handle_t bsh, 280 bus_size_t offset, u_int16_t *addr, 281 size_t count); 282 283 static __inline void bus_space_read_multi_4(bus_space_tag_t tag, 284 bus_space_handle_t bsh, 285 bus_size_t offset, u_int32_t *addr, 286 size_t count); 287 288 static __inline void 289 bus_space_read_multi_1(bus_space_tag_t tag, bus_space_handle_t bsh, 290 bus_size_t offset, u_int8_t *addr, size_t count) 291 { 292 293 if (tag == X86_BUS_SPACE_IO) 294 insb(bsh + offset, addr, count); 295 else { 296 #ifdef __GNUCLIKE_ASM 297 __asm __volatile(" \n\ 298 1: movb (%2),%%al \n\ 299 stosb \n\ 300 loop 1b" : 301 "=D" (addr), "=c" (count) : 302 "r" (bsh + offset), "0" (addr), "1" (count) : 303 "%eax", "memory"); 304 #endif 305 } 306 } 307 308 static __inline void 309 bus_space_read_multi_2(bus_space_tag_t tag, bus_space_handle_t bsh, 310 bus_size_t offset, u_int16_t *addr, size_t count) 311 { 312 313 if (tag == X86_BUS_SPACE_IO) 314 insw(bsh + offset, addr, count); 315 else { 316 #ifdef __GNUCLIKE_ASM 317 __asm __volatile(" \n\ 318 1: movw (%2),%%ax \n\ 319 stosw \n\ 320 loop 1b" : 321 "=D" (addr), "=c" (count) : 322 "r" (bsh + offset), "0" (addr), "1" (count) : 323 "%eax", "memory"); 324 #endif 325 } 326 } 327 328 static __inline void 329 bus_space_read_multi_4(bus_space_tag_t tag, bus_space_handle_t bsh, 330 bus_size_t offset, u_int32_t *addr, size_t count) 331 { 332 333 if (tag == X86_BUS_SPACE_IO) 334 insl(bsh + offset, addr, count); 335 else { 336 #ifdef __GNUCLIKE_ASM 337 __asm __volatile(" \n\ 338 1: movl (%2),%%eax \n\ 339 stosl \n\ 340 loop 1b" : 341 "=D" (addr), "=c" (count) : 342 "r" (bsh + offset), "0" (addr), "1" (count) : 343 "%eax", "memory"); 344 #endif 345 } 346 } 347 348 #if 0 /* Cause a link error for bus_space_read_multi_8 */ 349 #define bus_space_read_multi_8 !!! bus_space_read_multi_8 unimplemented !!! 350 #endif 351 352 /* 353 * Read `count' 1, 2, 4, or 8 byte quantities from bus space 354 * described by tag/handle and starting at `offset' and copy into 355 * buffer provided. 356 */ 357 static __inline void bus_space_read_region_1(bus_space_tag_t tag, 358 bus_space_handle_t bsh, 359 bus_size_t offset, u_int8_t *addr, 360 size_t count); 361 362 static __inline void bus_space_read_region_2(bus_space_tag_t tag, 363 bus_space_handle_t bsh, 364 bus_size_t offset, u_int16_t *addr, 365 size_t count); 366 367 static __inline void bus_space_read_region_4(bus_space_tag_t tag, 368 bus_space_handle_t bsh, 369 bus_size_t offset, u_int32_t *addr, 370 size_t count); 371 372 static __inline void 373 bus_space_read_region_1(bus_space_tag_t tag, bus_space_handle_t bsh, 374 bus_size_t offset, u_int8_t *addr, size_t count) 375 { 376 377 if (tag == X86_BUS_SPACE_IO) { 378 int _port_ = bsh + offset; 379 #ifdef __GNUCLIKE_ASM 380 __asm __volatile(" \n\ 381 1: inb %w2,%%al \n\ 382 stosb \n\ 383 incl %2 \n\ 384 loop 1b" : 385 "=D" (addr), "=c" (count), "=d" (_port_) : 386 "0" (addr), "1" (count), "2" (_port_) : 387 "%eax", "memory", "cc"); 388 #endif 389 } else { 390 bus_space_handle_t _port_ = bsh + offset; 391 #ifdef __GNUCLIKE_ASM 392 __asm __volatile(" \n\ 393 repne \n\ 394 movsb" : 395 "=D" (addr), "=c" (count), "=S" (_port_) : 396 "0" (addr), "1" (count), "2" (_port_) : 397 "memory", "cc"); 398 #endif 399 } 400 } 401 402 static __inline void 403 bus_space_read_region_2(bus_space_tag_t tag, bus_space_handle_t bsh, 404 bus_size_t offset, u_int16_t *addr, size_t count) 405 { 406 407 if (tag == X86_BUS_SPACE_IO) { 408 int _port_ = bsh + offset; 409 #ifdef __GNUCLIKE_ASM 410 __asm __volatile(" \n\ 411 1: inw %w2,%%ax \n\ 412 stosw \n\ 413 addl $2,%2 \n\ 414 loop 1b" : 415 "=D" (addr), "=c" (count), "=d" (_port_) : 416 "0" (addr), "1" (count), "2" (_port_) : 417 "%eax", "memory", "cc"); 418 #endif 419 } else { 420 bus_space_handle_t _port_ = bsh + offset; 421 #ifdef __GNUCLIKE_ASM 422 __asm __volatile(" \n\ 423 repne \n\ 424 movsw" : 425 "=D" (addr), "=c" (count), "=S" (_port_) : 426 "0" (addr), "1" (count), "2" (_port_) : 427 "memory", "cc"); 428 #endif 429 } 430 } 431 432 static __inline void 433 bus_space_read_region_4(bus_space_tag_t tag, bus_space_handle_t bsh, 434 bus_size_t offset, u_int32_t *addr, size_t count) 435 { 436 437 if (tag == X86_BUS_SPACE_IO) { 438 int _port_ = bsh + offset; 439 #ifdef __GNUCLIKE_ASM 440 __asm __volatile(" \n\ 441 1: inl %w2,%%eax \n\ 442 stosl \n\ 443 addl $4,%2 \n\ 444 loop 1b" : 445 "=D" (addr), "=c" (count), "=d" (_port_) : 446 "0" (addr), "1" (count), "2" (_port_) : 447 "%eax", "memory", "cc"); 448 #endif 449 } else { 450 bus_space_handle_t _port_ = bsh + offset; 451 #ifdef __GNUCLIKE_ASM 452 __asm __volatile(" \n\ 453 repne \n\ 454 movsl" : 455 "=D" (addr), "=c" (count), "=S" (_port_) : 456 "0" (addr), "1" (count), "2" (_port_) : 457 "memory", "cc"); 458 #endif 459 } 460 } 461 462 #if 0 /* Cause a link error for bus_space_read_region_8 */ 463 #define bus_space_read_region_8 !!! bus_space_read_region_8 unimplemented !!! 464 #endif 465 466 /* 467 * Write the 1, 2, 4, or 8 byte value `value' to bus space 468 * described by tag/handle/offset. 469 */ 470 471 static __inline void bus_space_write_1(bus_space_tag_t tag, 472 bus_space_handle_t bsh, 473 bus_size_t offset, u_int8_t value); 474 475 static __inline void bus_space_write_2(bus_space_tag_t tag, 476 bus_space_handle_t bsh, 477 bus_size_t offset, u_int16_t value); 478 479 static __inline void bus_space_write_4(bus_space_tag_t tag, 480 bus_space_handle_t bsh, 481 bus_size_t offset, u_int32_t value); 482 483 #ifdef __amd64__ 484 static __inline void bus_space_write_8(bus_space_tag_t tag, 485 bus_space_handle_t bsh, 486 bus_size_t offset, uint64_t value); 487 #endif 488 489 static __inline void 490 bus_space_write_1(bus_space_tag_t tag, bus_space_handle_t bsh, 491 bus_size_t offset, u_int8_t value) 492 { 493 494 if (tag == X86_BUS_SPACE_IO) 495 outb(bsh + offset, value); 496 else 497 *(volatile u_int8_t *)(bsh + offset) = value; 498 } 499 500 static __inline void 501 bus_space_write_2(bus_space_tag_t tag, bus_space_handle_t bsh, 502 bus_size_t offset, u_int16_t value) 503 { 504 505 if (tag == X86_BUS_SPACE_IO) 506 outw(bsh + offset, value); 507 else 508 *(volatile u_int16_t *)(bsh + offset) = value; 509 } 510 511 static __inline void 512 bus_space_write_4(bus_space_tag_t tag, bus_space_handle_t bsh, 513 bus_size_t offset, u_int32_t value) 514 { 515 516 if (tag == X86_BUS_SPACE_IO) 517 outl(bsh + offset, value); 518 else 519 *(volatile u_int32_t *)(bsh + offset) = value; 520 } 521 522 #ifdef __amd64__ 523 static __inline void 524 bus_space_write_8(bus_space_tag_t tag, bus_space_handle_t bsh, 525 bus_size_t offset, uint64_t value) 526 { 527 528 if (tag == X86_BUS_SPACE_IO) /* No 8 byte IO space access on x86 */ 529 return; 530 else 531 *(volatile uint64_t *)(bsh + offset) = value; 532 } 533 #endif 534 535 /* 536 * Write `count' 1, 2, 4, or 8 byte quantities from the buffer 537 * provided to bus space described by tag/handle/offset. 538 */ 539 540 static __inline void bus_space_write_multi_1(bus_space_tag_t tag, 541 bus_space_handle_t bsh, 542 bus_size_t offset, 543 const u_int8_t *addr, 544 size_t count); 545 static __inline void bus_space_write_multi_2(bus_space_tag_t tag, 546 bus_space_handle_t bsh, 547 bus_size_t offset, 548 const u_int16_t *addr, 549 size_t count); 550 551 static __inline void bus_space_write_multi_4(bus_space_tag_t tag, 552 bus_space_handle_t bsh, 553 bus_size_t offset, 554 const u_int32_t *addr, 555 size_t count); 556 557 static __inline void 558 bus_space_write_multi_1(bus_space_tag_t tag, bus_space_handle_t bsh, 559 bus_size_t offset, const u_int8_t *addr, size_t count) 560 { 561 562 if (tag == X86_BUS_SPACE_IO) 563 outsb(bsh + offset, addr, count); 564 else { 565 #ifdef __GNUCLIKE_ASM 566 __asm __volatile(" \n\ 567 1: lodsb \n\ 568 movb %%al,(%2) \n\ 569 loop 1b" : 570 "=S" (addr), "=c" (count) : 571 "r" (bsh + offset), "0" (addr), "1" (count) : 572 "%eax", "memory", "cc"); 573 #endif 574 } 575 } 576 577 static __inline void 578 bus_space_write_multi_2(bus_space_tag_t tag, bus_space_handle_t bsh, 579 bus_size_t offset, const u_int16_t *addr, size_t count) 580 { 581 582 if (tag == X86_BUS_SPACE_IO) 583 outsw(bsh + offset, addr, count); 584 else { 585 #ifdef __GNUCLIKE_ASM 586 __asm __volatile(" \n\ 587 1: lodsw \n\ 588 movw %%ax,(%2) \n\ 589 loop 1b" : 590 "=S" (addr), "=c" (count) : 591 "r" (bsh + offset), "0" (addr), "1" (count) : 592 "%eax", "memory", "cc"); 593 #endif 594 } 595 } 596 597 static __inline void 598 bus_space_write_multi_4(bus_space_tag_t tag, bus_space_handle_t bsh, 599 bus_size_t offset, const u_int32_t *addr, size_t count) 600 { 601 602 if (tag == X86_BUS_SPACE_IO) 603 outsl(bsh + offset, addr, count); 604 else { 605 #ifdef __GNUCLIKE_ASM 606 __asm __volatile(" \n\ 607 1: lodsl \n\ 608 movl %%eax,(%2) \n\ 609 loop 1b" : 610 "=S" (addr), "=c" (count) : 611 "r" (bsh + offset), "0" (addr), "1" (count) : 612 "%eax", "memory", "cc"); 613 #endif 614 } 615 } 616 617 #if 0 /* Cause a link error for bus_space_write_multi_8 */ 618 #define bus_space_write_multi_8(t, h, o, a, c) \ 619 !!! bus_space_write_multi_8 unimplemented !!! 620 #endif 621 622 /* 623 * Write `count' 1, 2, 4, or 8 byte quantities from the buffer provided 624 * to bus space described by tag/handle starting at `offset'. 625 */ 626 627 static __inline void bus_space_write_region_1(bus_space_tag_t tag, 628 bus_space_handle_t bsh, 629 bus_size_t offset, 630 const u_int8_t *addr, 631 size_t count); 632 static __inline void bus_space_write_region_2(bus_space_tag_t tag, 633 bus_space_handle_t bsh, 634 bus_size_t offset, 635 const u_int16_t *addr, 636 size_t count); 637 static __inline void bus_space_write_region_4(bus_space_tag_t tag, 638 bus_space_handle_t bsh, 639 bus_size_t offset, 640 const u_int32_t *addr, 641 size_t count); 642 643 static __inline void 644 bus_space_write_region_1(bus_space_tag_t tag, bus_space_handle_t bsh, 645 bus_size_t offset, const u_int8_t *addr, size_t count) 646 { 647 648 if (tag == X86_BUS_SPACE_IO) { 649 int _port_ = bsh + offset; 650 #ifdef __GNUCLIKE_ASM 651 __asm __volatile(" \n\ 652 1: lodsb \n\ 653 outb %%al,%w0 \n\ 654 incl %0 \n\ 655 loop 1b" : 656 "=d" (_port_), "=S" (addr), "=c" (count) : 657 "0" (_port_), "1" (addr), "2" (count) : 658 "%eax", "memory", "cc"); 659 #endif 660 } else { 661 bus_space_handle_t _port_ = bsh + offset; 662 #ifdef __GNUCLIKE_ASM 663 __asm __volatile(" \n\ 664 repne \n\ 665 movsb" : 666 "=D" (_port_), "=S" (addr), "=c" (count) : 667 "0" (_port_), "1" (addr), "2" (count) : 668 "memory", "cc"); 669 #endif 670 } 671 } 672 673 static __inline void 674 bus_space_write_region_2(bus_space_tag_t tag, bus_space_handle_t bsh, 675 bus_size_t offset, const u_int16_t *addr, size_t count) 676 { 677 678 if (tag == X86_BUS_SPACE_IO) { 679 int _port_ = bsh + offset; 680 #ifdef __GNUCLIKE_ASM 681 __asm __volatile(" \n\ 682 1: lodsw \n\ 683 outw %%ax,%w0 \n\ 684 addl $2,%0 \n\ 685 loop 1b" : 686 "=d" (_port_), "=S" (addr), "=c" (count) : 687 "0" (_port_), "1" (addr), "2" (count) : 688 "%eax", "memory", "cc"); 689 #endif 690 } else { 691 bus_space_handle_t _port_ = bsh + offset; 692 #ifdef __GNUCLIKE_ASM 693 __asm __volatile(" \n\ 694 repne \n\ 695 movsw" : 696 "=D" (_port_), "=S" (addr), "=c" (count) : 697 "0" (_port_), "1" (addr), "2" (count) : 698 "memory", "cc"); 699 #endif 700 } 701 } 702 703 static __inline void 704 bus_space_write_region_4(bus_space_tag_t tag, bus_space_handle_t bsh, 705 bus_size_t offset, const u_int32_t *addr, size_t count) 706 { 707 708 if (tag == X86_BUS_SPACE_IO) { 709 int _port_ = bsh + offset; 710 #ifdef __GNUCLIKE_ASM 711 __asm __volatile(" \n\ 712 1: lodsl \n\ 713 outl %%eax,%w0 \n\ 714 addl $4,%0 \n\ 715 loop 1b" : 716 "=d" (_port_), "=S" (addr), "=c" (count) : 717 "0" (_port_), "1" (addr), "2" (count) : 718 "%eax", "memory", "cc"); 719 #endif 720 } else { 721 bus_space_handle_t _port_ = bsh + offset; 722 #ifdef __GNUCLIKE_ASM 723 __asm __volatile(" \n\ 724 repne \n\ 725 movsl" : 726 "=D" (_port_), "=S" (addr), "=c" (count) : 727 "0" (_port_), "1" (addr), "2" (count) : 728 "memory", "cc"); 729 #endif 730 } 731 } 732 733 #if 0 /* Cause a link error for bus_space_write_region_8 */ 734 #define bus_space_write_region_8 \ 735 !!! bus_space_write_region_8 unimplemented !!! 736 #endif 737 738 /* 739 * Write the 1, 2, 4, or 8 byte value `val' to bus space described 740 * by tag/handle/offset `count' times. 741 */ 742 743 static __inline void bus_space_set_multi_1(bus_space_tag_t tag, 744 bus_space_handle_t bsh, 745 bus_size_t offset, 746 u_int8_t value, size_t count); 747 static __inline void bus_space_set_multi_2(bus_space_tag_t tag, 748 bus_space_handle_t bsh, 749 bus_size_t offset, 750 u_int16_t value, size_t count); 751 static __inline void bus_space_set_multi_4(bus_space_tag_t tag, 752 bus_space_handle_t bsh, 753 bus_size_t offset, 754 u_int32_t value, size_t count); 755 756 static __inline void 757 bus_space_set_multi_1(bus_space_tag_t tag, bus_space_handle_t bsh, 758 bus_size_t offset, u_int8_t value, size_t count) 759 { 760 bus_space_handle_t addr = bsh + offset; 761 762 if (tag == X86_BUS_SPACE_IO) 763 while (count--) 764 outb(addr, value); 765 else 766 while (count--) 767 *(volatile u_int8_t *)(addr) = value; 768 } 769 770 static __inline void 771 bus_space_set_multi_2(bus_space_tag_t tag, bus_space_handle_t bsh, 772 bus_size_t offset, u_int16_t value, size_t count) 773 { 774 bus_space_handle_t addr = bsh + offset; 775 776 if (tag == X86_BUS_SPACE_IO) 777 while (count--) 778 outw(addr, value); 779 else 780 while (count--) 781 *(volatile u_int16_t *)(addr) = value; 782 } 783 784 static __inline void 785 bus_space_set_multi_4(bus_space_tag_t tag, bus_space_handle_t bsh, 786 bus_size_t offset, u_int32_t value, size_t count) 787 { 788 bus_space_handle_t addr = bsh + offset; 789 790 if (tag == X86_BUS_SPACE_IO) 791 while (count--) 792 outl(addr, value); 793 else 794 while (count--) 795 *(volatile u_int32_t *)(addr) = value; 796 } 797 798 #if 0 /* Cause a link error for bus_space_set_multi_8 */ 799 #define bus_space_set_multi_8 !!! bus_space_set_multi_8 unimplemented !!! 800 #endif 801 802 /* 803 * Write `count' 1, 2, 4, or 8 byte value `val' to bus space described 804 * by tag/handle starting at `offset'. 805 */ 806 807 static __inline void bus_space_set_region_1(bus_space_tag_t tag, 808 bus_space_handle_t bsh, 809 bus_size_t offset, u_int8_t value, 810 size_t count); 811 static __inline void bus_space_set_region_2(bus_space_tag_t tag, 812 bus_space_handle_t bsh, 813 bus_size_t offset, u_int16_t value, 814 size_t count); 815 static __inline void bus_space_set_region_4(bus_space_tag_t tag, 816 bus_space_handle_t bsh, 817 bus_size_t offset, u_int32_t value, 818 size_t count); 819 820 static __inline void 821 bus_space_set_region_1(bus_space_tag_t tag, bus_space_handle_t bsh, 822 bus_size_t offset, u_int8_t value, size_t count) 823 { 824 bus_space_handle_t addr = bsh + offset; 825 826 if (tag == X86_BUS_SPACE_IO) 827 for (; count != 0; count--, addr++) 828 outb(addr, value); 829 else 830 for (; count != 0; count--, addr++) 831 *(volatile u_int8_t *)(addr) = value; 832 } 833 834 static __inline void 835 bus_space_set_region_2(bus_space_tag_t tag, bus_space_handle_t bsh, 836 bus_size_t offset, u_int16_t value, size_t count) 837 { 838 bus_space_handle_t addr = bsh + offset; 839 840 if (tag == X86_BUS_SPACE_IO) 841 for (; count != 0; count--, addr += 2) 842 outw(addr, value); 843 else 844 for (; count != 0; count--, addr += 2) 845 *(volatile u_int16_t *)(addr) = value; 846 } 847 848 static __inline void 849 bus_space_set_region_4(bus_space_tag_t tag, bus_space_handle_t bsh, 850 bus_size_t offset, u_int32_t value, size_t count) 851 { 852 bus_space_handle_t addr = bsh + offset; 853 854 if (tag == X86_BUS_SPACE_IO) 855 for (; count != 0; count--, addr += 4) 856 outl(addr, value); 857 else 858 for (; count != 0; count--, addr += 4) 859 *(volatile u_int32_t *)(addr) = value; 860 } 861 862 #if 0 /* Cause a link error for bus_space_set_region_8 */ 863 #define bus_space_set_region_8 !!! bus_space_set_region_8 unimplemented !!! 864 #endif 865 866 /* 867 * Copy `count' 1, 2, 4, or 8 byte values from bus space starting 868 * at tag/bsh1/off1 to bus space starting at tag/bsh2/off2. 869 */ 870 871 static __inline void bus_space_copy_region_1(bus_space_tag_t tag, 872 bus_space_handle_t bsh1, 873 bus_size_t off1, 874 bus_space_handle_t bsh2, 875 bus_size_t off2, size_t count); 876 877 static __inline void bus_space_copy_region_2(bus_space_tag_t tag, 878 bus_space_handle_t bsh1, 879 bus_size_t off1, 880 bus_space_handle_t bsh2, 881 bus_size_t off2, size_t count); 882 883 static __inline void bus_space_copy_region_4(bus_space_tag_t tag, 884 bus_space_handle_t bsh1, 885 bus_size_t off1, 886 bus_space_handle_t bsh2, 887 bus_size_t off2, size_t count); 888 889 static __inline void 890 bus_space_copy_region_1(bus_space_tag_t tag, bus_space_handle_t bsh1, 891 bus_size_t off1, bus_space_handle_t bsh2, 892 bus_size_t off2, size_t count) 893 { 894 bus_space_handle_t addr1 = bsh1 + off1; 895 bus_space_handle_t addr2 = bsh2 + off2; 896 897 if (tag == X86_BUS_SPACE_IO) { 898 if (addr1 >= addr2) { 899 /* src after dest: copy forward */ 900 for (; count != 0; count--, addr1++, addr2++) 901 outb(addr2, inb(addr1)); 902 } else { 903 /* dest after src: copy backwards */ 904 for (addr1 += (count - 1), addr2 += (count - 1); 905 count != 0; count--, addr1--, addr2--) 906 outb(addr2, inb(addr1)); 907 } 908 } else { 909 if (addr1 >= addr2) { 910 /* src after dest: copy forward */ 911 for (; count != 0; count--, addr1++, addr2++) 912 *(volatile u_int8_t *)(addr2) = 913 *(volatile u_int8_t *)(addr1); 914 } else { 915 /* dest after src: copy backwards */ 916 for (addr1 += (count - 1), addr2 += (count - 1); 917 count != 0; count--, addr1--, addr2--) 918 *(volatile u_int8_t *)(addr2) = 919 *(volatile u_int8_t *)(addr1); 920 } 921 } 922 } 923 924 static __inline void 925 bus_space_copy_region_2(bus_space_tag_t tag, bus_space_handle_t bsh1, 926 bus_size_t off1, bus_space_handle_t bsh2, 927 bus_size_t off2, size_t count) 928 { 929 bus_space_handle_t addr1 = bsh1 + off1; 930 bus_space_handle_t addr2 = bsh2 + off2; 931 932 if (tag == X86_BUS_SPACE_IO) { 933 if (addr1 >= addr2) { 934 /* src after dest: copy forward */ 935 for (; count != 0; count--, addr1 += 2, addr2 += 2) 936 outw(addr2, inw(addr1)); 937 } else { 938 /* dest after src: copy backwards */ 939 for (addr1 += 2 * (count - 1), addr2 += 2 * (count - 1); 940 count != 0; count--, addr1 -= 2, addr2 -= 2) 941 outw(addr2, inw(addr1)); 942 } 943 } else { 944 if (addr1 >= addr2) { 945 /* src after dest: copy forward */ 946 for (; count != 0; count--, addr1 += 2, addr2 += 2) 947 *(volatile u_int16_t *)(addr2) = 948 *(volatile u_int16_t *)(addr1); 949 } else { 950 /* dest after src: copy backwards */ 951 for (addr1 += 2 * (count - 1), addr2 += 2 * (count - 1); 952 count != 0; count--, addr1 -= 2, addr2 -= 2) 953 *(volatile u_int16_t *)(addr2) = 954 *(volatile u_int16_t *)(addr1); 955 } 956 } 957 } 958 959 static __inline void 960 bus_space_copy_region_4(bus_space_tag_t tag, bus_space_handle_t bsh1, 961 bus_size_t off1, bus_space_handle_t bsh2, 962 bus_size_t off2, size_t count) 963 { 964 bus_space_handle_t addr1 = bsh1 + off1; 965 bus_space_handle_t addr2 = bsh2 + off2; 966 967 if (tag == X86_BUS_SPACE_IO) { 968 if (addr1 >= addr2) { 969 /* src after dest: copy forward */ 970 for (; count != 0; count--, addr1 += 4, addr2 += 4) 971 outl(addr2, inl(addr1)); 972 } else { 973 /* dest after src: copy backwards */ 974 for (addr1 += 4 * (count - 1), addr2 += 4 * (count - 1); 975 count != 0; count--, addr1 -= 4, addr2 -= 4) 976 outl(addr2, inl(addr1)); 977 } 978 } else { 979 if (addr1 >= addr2) { 980 /* src after dest: copy forward */ 981 for (; count != 0; count--, addr1 += 4, addr2 += 4) 982 *(volatile u_int32_t *)(addr2) = 983 *(volatile u_int32_t *)(addr1); 984 } else { 985 /* dest after src: copy backwards */ 986 for (addr1 += 4 * (count - 1), addr2 += 4 * (count - 1); 987 count != 0; count--, addr1 -= 4, addr2 -= 4) 988 *(volatile u_int32_t *)(addr2) = 989 *(volatile u_int32_t *)(addr1); 990 } 991 } 992 } 993 994 #if 0 /* Cause a link error for bus_space_copy_8 */ 995 #define bus_space_copy_region_8 !!! bus_space_copy_region_8 unimplemented !!! 996 #endif 997 998 /* 999 * Bus read/write barrier methods. 1000 * 1001 * void bus_space_barrier(bus_space_tag_t tag, bus_space_handle_t bsh, 1002 * bus_size_t offset, bus_size_t len, int flags); 1003 * 1004 * 1005 * Note that BUS_SPACE_BARRIER_WRITE doesn't do anything other than 1006 * prevent reordering by the compiler; all Intel x86 processors currently 1007 * retire operations outside the CPU in program order. 1008 */ 1009 static __inline void 1010 bus_space_barrier(bus_space_tag_t tag __unused, bus_space_handle_t bsh __unused, 1011 bus_size_t offset __unused, bus_size_t len __unused, int flags) 1012 { 1013 #ifdef __GNUCLIKE_ASM 1014 if (flags & BUS_SPACE_BARRIER_READ) 1015 #ifdef __amd64__ 1016 __asm __volatile("lock; addl $0,0(%%rsp)" : : : "memory"); 1017 #else 1018 __asm __volatile("lock; addl $0,0(%%esp)" : : : "memory"); 1019 #endif 1020 else 1021 __compiler_membar(); 1022 #endif 1023 } 1024 1025 #ifdef BUS_SPACE_NO_LEGACY 1026 #undef inb 1027 #undef outb 1028 #define inb(a) compiler_error 1029 #define inw(a) compiler_error 1030 #define inl(a) compiler_error 1031 #define outb(a, b) compiler_error 1032 #define outw(a, b) compiler_error 1033 #define outl(a, b) compiler_error 1034 #endif 1035 1036 /* 1037 * Stream accesses are the same as normal accesses on x86; there are no 1038 * supported bus systems with an endianess different from the host one. 1039 */ 1040 #define bus_space_read_stream_1(t, h, o) bus_space_read_1((t), (h), (o)) 1041 #define bus_space_read_stream_2(t, h, o) bus_space_read_2((t), (h), (o)) 1042 #define bus_space_read_stream_4(t, h, o) bus_space_read_4((t), (h), (o)) 1043 1044 #define bus_space_read_multi_stream_1(t, h, o, a, c) \ 1045 bus_space_read_multi_1((t), (h), (o), (a), (c)) 1046 #define bus_space_read_multi_stream_2(t, h, o, a, c) \ 1047 bus_space_read_multi_2((t), (h), (o), (a), (c)) 1048 #define bus_space_read_multi_stream_4(t, h, o, a, c) \ 1049 bus_space_read_multi_4((t), (h), (o), (a), (c)) 1050 1051 #define bus_space_write_stream_1(t, h, o, v) \ 1052 bus_space_write_1((t), (h), (o), (v)) 1053 #define bus_space_write_stream_2(t, h, o, v) \ 1054 bus_space_write_2((t), (h), (o), (v)) 1055 #define bus_space_write_stream_4(t, h, o, v) \ 1056 bus_space_write_4((t), (h), (o), (v)) 1057 1058 #define bus_space_write_multi_stream_1(t, h, o, a, c) \ 1059 bus_space_write_multi_1((t), (h), (o), (a), (c)) 1060 #define bus_space_write_multi_stream_2(t, h, o, a, c) \ 1061 bus_space_write_multi_2((t), (h), (o), (a), (c)) 1062 #define bus_space_write_multi_stream_4(t, h, o, a, c) \ 1063 bus_space_write_multi_4((t), (h), (o), (a), (c)) 1064 1065 #define bus_space_set_multi_stream_1(t, h, o, v, c) \ 1066 bus_space_set_multi_1((t), (h), (o), (v), (c)) 1067 #define bus_space_set_multi_stream_2(t, h, o, v, c) \ 1068 bus_space_set_multi_2((t), (h), (o), (v), (c)) 1069 #define bus_space_set_multi_stream_4(t, h, o, v, c) \ 1070 bus_space_set_multi_4((t), (h), (o), (v), (c)) 1071 1072 #define bus_space_read_region_stream_1(t, h, o, a, c) \ 1073 bus_space_read_region_1((t), (h), (o), (a), (c)) 1074 #define bus_space_read_region_stream_2(t, h, o, a, c) \ 1075 bus_space_read_region_2((t), (h), (o), (a), (c)) 1076 #define bus_space_read_region_stream_4(t, h, o, a, c) \ 1077 bus_space_read_region_4((t), (h), (o), (a), (c)) 1078 1079 #define bus_space_write_region_stream_1(t, h, o, a, c) \ 1080 bus_space_write_region_1((t), (h), (o), (a), (c)) 1081 #define bus_space_write_region_stream_2(t, h, o, a, c) \ 1082 bus_space_write_region_2((t), (h), (o), (a), (c)) 1083 #define bus_space_write_region_stream_4(t, h, o, a, c) \ 1084 bus_space_write_region_4((t), (h), (o), (a), (c)) 1085 1086 #define bus_space_set_region_stream_1(t, h, o, v, c) \ 1087 bus_space_set_region_1((t), (h), (o), (v), (c)) 1088 #define bus_space_set_region_stream_2(t, h, o, v, c) \ 1089 bus_space_set_region_2((t), (h), (o), (v), (c)) 1090 #define bus_space_set_region_stream_4(t, h, o, v, c) \ 1091 bus_space_set_region_4((t), (h), (o), (v), (c)) 1092 1093 #define bus_space_copy_region_stream_1(t, h1, o1, h2, o2, c) \ 1094 bus_space_copy_region_1((t), (h1), (o1), (h2), (o2), (c)) 1095 #define bus_space_copy_region_stream_2(t, h1, o1, h2, o2, c) \ 1096 bus_space_copy_region_2((t), (h1), (o1), (h2), (o2), (c)) 1097 #define bus_space_copy_region_stream_4(t, h1, o1, h2, o2, c) \ 1098 bus_space_copy_region_4((t), (h1), (o1), (h2), (o2), (c)) 1099 1100 #define BUS_PEEK_FUNC(width, type) \ 1101 static inline int \ 1102 bus_space_peek_##width(bus_space_tag_t tag, \ 1103 bus_space_handle_t hnd, bus_size_t offset, type *value) \ 1104 { \ 1105 type tmp; \ 1106 tmp = bus_space_read_##width(tag, hnd, offset); \ 1107 *value = (type)tmp; \ 1108 return (0); \ 1109 } 1110 BUS_PEEK_FUNC(1, uint8_t) 1111 BUS_PEEK_FUNC(2, uint16_t) 1112 BUS_PEEK_FUNC(4, uint32_t) 1113 #ifdef __amd64__ 1114 BUS_PEEK_FUNC(8, uint64_t) 1115 #endif 1116 1117 #define BUS_POKE_FUNC(width, type) \ 1118 static inline int \ 1119 bus_space_poke_##width(bus_space_tag_t tag, \ 1120 bus_space_handle_t hnd, bus_size_t offset, type value) \ 1121 { \ 1122 bus_space_write_##width(tag, hnd, offset, value); \ 1123 return (0); \ 1124 } 1125 BUS_POKE_FUNC(1, uint8_t) 1126 BUS_POKE_FUNC(2, uint16_t) 1127 BUS_POKE_FUNC(4, uint32_t) 1128 #ifdef __amd64__ 1129 BUS_POKE_FUNC(8, uint64_t) 1130 #endif 1131 1132 #endif /* !BUS_SAN_PREFIX */ 1133 1134 #endif /* !_MACHINE_BUS_H_ */ 1135