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 _X86_BUS_H_ 100 #define _X86_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 #if defined(KCSAN) && !defined(KCSAN_RUNTIME) 139 #include <sys/_cscan_bus.h> 140 #else 141 142 /* 143 * Map a region of device bus space into CPU virtual address space. 144 */ 145 146 int bus_space_map(bus_space_tag_t tag, bus_addr_t addr, bus_size_t size, 147 int flags, bus_space_handle_t *bshp); 148 149 /* 150 * Unmap a region of device bus space. 151 */ 152 153 void bus_space_unmap(bus_space_tag_t tag, bus_space_handle_t bsh, 154 bus_size_t size); 155 156 /* 157 * Get a new handle for a subregion of an already-mapped area of bus space. 158 */ 159 160 static __inline int bus_space_subregion(bus_space_tag_t t, 161 bus_space_handle_t bsh, 162 bus_size_t offset, bus_size_t size, 163 bus_space_handle_t *nbshp); 164 165 static __inline int 166 bus_space_subregion(bus_space_tag_t t __unused, bus_space_handle_t bsh, 167 bus_size_t offset, bus_size_t size __unused, 168 bus_space_handle_t *nbshp) 169 { 170 171 *nbshp = bsh + offset; 172 return (0); 173 } 174 175 /* 176 * Allocate a region of memory that is accessible to devices in bus space. 177 */ 178 179 int bus_space_alloc(bus_space_tag_t t, bus_addr_t rstart, 180 bus_addr_t rend, bus_size_t size, bus_size_t align, 181 bus_size_t boundary, int flags, bus_addr_t *addrp, 182 bus_space_handle_t *bshp); 183 184 /* 185 * Free a region of bus space accessible memory. 186 */ 187 188 static __inline void bus_space_free(bus_space_tag_t t, bus_space_handle_t bsh, 189 bus_size_t size); 190 191 static __inline void 192 bus_space_free(bus_space_tag_t t __unused, bus_space_handle_t bsh __unused, 193 bus_size_t size __unused) 194 { 195 } 196 197 /* 198 * Read a 1, 2, 4, or 8 byte quantity from bus space 199 * described by tag/handle/offset. 200 */ 201 static __inline u_int8_t bus_space_read_1(bus_space_tag_t tag, 202 bus_space_handle_t handle, 203 bus_size_t offset); 204 205 static __inline u_int16_t bus_space_read_2(bus_space_tag_t tag, 206 bus_space_handle_t handle, 207 bus_size_t offset); 208 209 static __inline u_int32_t bus_space_read_4(bus_space_tag_t tag, 210 bus_space_handle_t handle, 211 bus_size_t offset); 212 213 #ifdef __amd64__ 214 static __inline uint64_t bus_space_read_8(bus_space_tag_t tag, 215 bus_space_handle_t handle, 216 bus_size_t offset); 217 #endif 218 219 static __inline u_int8_t 220 bus_space_read_1(bus_space_tag_t tag, bus_space_handle_t handle, 221 bus_size_t offset) 222 { 223 224 if (tag == X86_BUS_SPACE_IO) 225 return (inb(handle + offset)); 226 return (*(volatile u_int8_t *)(handle + offset)); 227 } 228 229 static __inline u_int16_t 230 bus_space_read_2(bus_space_tag_t tag, bus_space_handle_t handle, 231 bus_size_t offset) 232 { 233 234 if (tag == X86_BUS_SPACE_IO) 235 return (inw(handle + offset)); 236 return (*(volatile u_int16_t *)(handle + offset)); 237 } 238 239 static __inline u_int32_t 240 bus_space_read_4(bus_space_tag_t tag, bus_space_handle_t handle, 241 bus_size_t offset) 242 { 243 244 if (tag == X86_BUS_SPACE_IO) 245 return (inl(handle + offset)); 246 return (*(volatile u_int32_t *)(handle + offset)); 247 } 248 249 #ifdef __amd64__ 250 static __inline uint64_t 251 bus_space_read_8(bus_space_tag_t tag, bus_space_handle_t handle, 252 bus_size_t offset) 253 { 254 255 if (tag == X86_BUS_SPACE_IO) /* No 8 byte IO space access on x86 */ 256 return (BUS_SPACE_INVALID_DATA); 257 return (*(volatile uint64_t *)(handle + offset)); 258 } 259 #endif 260 261 /* 262 * Read `count' 1, 2, 4, or 8 byte quantities from bus space 263 * described by tag/handle/offset and copy into buffer provided. 264 */ 265 static __inline void bus_space_read_multi_1(bus_space_tag_t tag, 266 bus_space_handle_t bsh, 267 bus_size_t offset, u_int8_t *addr, 268 size_t count); 269 270 static __inline void bus_space_read_multi_2(bus_space_tag_t tag, 271 bus_space_handle_t bsh, 272 bus_size_t offset, u_int16_t *addr, 273 size_t count); 274 275 static __inline void bus_space_read_multi_4(bus_space_tag_t tag, 276 bus_space_handle_t bsh, 277 bus_size_t offset, u_int32_t *addr, 278 size_t count); 279 280 static __inline void 281 bus_space_read_multi_1(bus_space_tag_t tag, bus_space_handle_t bsh, 282 bus_size_t offset, u_int8_t *addr, size_t count) 283 { 284 285 if (tag == X86_BUS_SPACE_IO) 286 insb(bsh + offset, addr, count); 287 else { 288 #ifdef __GNUCLIKE_ASM 289 __asm __volatile(" \n\ 290 1: movb (%2),%%al \n\ 291 stosb \n\ 292 loop 1b" : 293 "=D" (addr), "=c" (count) : 294 "r" (bsh + offset), "0" (addr), "1" (count) : 295 "%eax", "memory"); 296 #endif 297 } 298 } 299 300 static __inline void 301 bus_space_read_multi_2(bus_space_tag_t tag, bus_space_handle_t bsh, 302 bus_size_t offset, u_int16_t *addr, size_t count) 303 { 304 305 if (tag == X86_BUS_SPACE_IO) 306 insw(bsh + offset, addr, count); 307 else { 308 #ifdef __GNUCLIKE_ASM 309 __asm __volatile(" \n\ 310 1: movw (%2),%%ax \n\ 311 stosw \n\ 312 loop 1b" : 313 "=D" (addr), "=c" (count) : 314 "r" (bsh + offset), "0" (addr), "1" (count) : 315 "%eax", "memory"); 316 #endif 317 } 318 } 319 320 static __inline void 321 bus_space_read_multi_4(bus_space_tag_t tag, bus_space_handle_t bsh, 322 bus_size_t offset, u_int32_t *addr, size_t count) 323 { 324 325 if (tag == X86_BUS_SPACE_IO) 326 insl(bsh + offset, addr, count); 327 else { 328 #ifdef __GNUCLIKE_ASM 329 __asm __volatile(" \n\ 330 1: movl (%2),%%eax \n\ 331 stosl \n\ 332 loop 1b" : 333 "=D" (addr), "=c" (count) : 334 "r" (bsh + offset), "0" (addr), "1" (count) : 335 "%eax", "memory"); 336 #endif 337 } 338 } 339 340 #if 0 /* Cause a link error for bus_space_read_multi_8 */ 341 #define bus_space_read_multi_8 !!! bus_space_read_multi_8 unimplemented !!! 342 #endif 343 344 /* 345 * Read `count' 1, 2, 4, or 8 byte quantities from bus space 346 * described by tag/handle and starting at `offset' and copy into 347 * buffer provided. 348 */ 349 static __inline void bus_space_read_region_1(bus_space_tag_t tag, 350 bus_space_handle_t bsh, 351 bus_size_t offset, u_int8_t *addr, 352 size_t count); 353 354 static __inline void bus_space_read_region_2(bus_space_tag_t tag, 355 bus_space_handle_t bsh, 356 bus_size_t offset, u_int16_t *addr, 357 size_t count); 358 359 static __inline void bus_space_read_region_4(bus_space_tag_t tag, 360 bus_space_handle_t bsh, 361 bus_size_t offset, u_int32_t *addr, 362 size_t count); 363 364 static __inline void 365 bus_space_read_region_1(bus_space_tag_t tag, bus_space_handle_t bsh, 366 bus_size_t offset, u_int8_t *addr, size_t count) 367 { 368 369 if (tag == X86_BUS_SPACE_IO) { 370 int _port_ = bsh + offset; 371 #ifdef __GNUCLIKE_ASM 372 __asm __volatile(" \n\ 373 1: inb %w2,%%al \n\ 374 stosb \n\ 375 incl %2 \n\ 376 loop 1b" : 377 "=D" (addr), "=c" (count), "=d" (_port_) : 378 "0" (addr), "1" (count), "2" (_port_) : 379 "%eax", "memory", "cc"); 380 #endif 381 } else { 382 bus_space_handle_t _port_ = bsh + offset; 383 #ifdef __GNUCLIKE_ASM 384 __asm __volatile(" \n\ 385 repne \n\ 386 movsb" : 387 "=D" (addr), "=c" (count), "=S" (_port_) : 388 "0" (addr), "1" (count), "2" (_port_) : 389 "memory", "cc"); 390 #endif 391 } 392 } 393 394 static __inline void 395 bus_space_read_region_2(bus_space_tag_t tag, bus_space_handle_t bsh, 396 bus_size_t offset, u_int16_t *addr, size_t count) 397 { 398 399 if (tag == X86_BUS_SPACE_IO) { 400 int _port_ = bsh + offset; 401 #ifdef __GNUCLIKE_ASM 402 __asm __volatile(" \n\ 403 1: inw %w2,%%ax \n\ 404 stosw \n\ 405 addl $2,%2 \n\ 406 loop 1b" : 407 "=D" (addr), "=c" (count), "=d" (_port_) : 408 "0" (addr), "1" (count), "2" (_port_) : 409 "%eax", "memory", "cc"); 410 #endif 411 } else { 412 bus_space_handle_t _port_ = bsh + offset; 413 #ifdef __GNUCLIKE_ASM 414 __asm __volatile(" \n\ 415 repne \n\ 416 movsw" : 417 "=D" (addr), "=c" (count), "=S" (_port_) : 418 "0" (addr), "1" (count), "2" (_port_) : 419 "memory", "cc"); 420 #endif 421 } 422 } 423 424 static __inline void 425 bus_space_read_region_4(bus_space_tag_t tag, bus_space_handle_t bsh, 426 bus_size_t offset, u_int32_t *addr, size_t count) 427 { 428 429 if (tag == X86_BUS_SPACE_IO) { 430 int _port_ = bsh + offset; 431 #ifdef __GNUCLIKE_ASM 432 __asm __volatile(" \n\ 433 1: inl %w2,%%eax \n\ 434 stosl \n\ 435 addl $4,%2 \n\ 436 loop 1b" : 437 "=D" (addr), "=c" (count), "=d" (_port_) : 438 "0" (addr), "1" (count), "2" (_port_) : 439 "%eax", "memory", "cc"); 440 #endif 441 } else { 442 bus_space_handle_t _port_ = bsh + offset; 443 #ifdef __GNUCLIKE_ASM 444 __asm __volatile(" \n\ 445 repne \n\ 446 movsl" : 447 "=D" (addr), "=c" (count), "=S" (_port_) : 448 "0" (addr), "1" (count), "2" (_port_) : 449 "memory", "cc"); 450 #endif 451 } 452 } 453 454 #if 0 /* Cause a link error for bus_space_read_region_8 */ 455 #define bus_space_read_region_8 !!! bus_space_read_region_8 unimplemented !!! 456 #endif 457 458 /* 459 * Write the 1, 2, 4, or 8 byte value `value' to bus space 460 * described by tag/handle/offset. 461 */ 462 463 static __inline void bus_space_write_1(bus_space_tag_t tag, 464 bus_space_handle_t bsh, 465 bus_size_t offset, u_int8_t value); 466 467 static __inline void bus_space_write_2(bus_space_tag_t tag, 468 bus_space_handle_t bsh, 469 bus_size_t offset, u_int16_t value); 470 471 static __inline void bus_space_write_4(bus_space_tag_t tag, 472 bus_space_handle_t bsh, 473 bus_size_t offset, u_int32_t value); 474 475 #ifdef __amd64__ 476 static __inline void bus_space_write_8(bus_space_tag_t tag, 477 bus_space_handle_t bsh, 478 bus_size_t offset, uint64_t value); 479 #endif 480 481 static __inline void 482 bus_space_write_1(bus_space_tag_t tag, bus_space_handle_t bsh, 483 bus_size_t offset, u_int8_t value) 484 { 485 486 if (tag == X86_BUS_SPACE_IO) 487 outb(bsh + offset, value); 488 else 489 *(volatile u_int8_t *)(bsh + offset) = value; 490 } 491 492 static __inline void 493 bus_space_write_2(bus_space_tag_t tag, bus_space_handle_t bsh, 494 bus_size_t offset, u_int16_t value) 495 { 496 497 if (tag == X86_BUS_SPACE_IO) 498 outw(bsh + offset, value); 499 else 500 *(volatile u_int16_t *)(bsh + offset) = value; 501 } 502 503 static __inline void 504 bus_space_write_4(bus_space_tag_t tag, bus_space_handle_t bsh, 505 bus_size_t offset, u_int32_t value) 506 { 507 508 if (tag == X86_BUS_SPACE_IO) 509 outl(bsh + offset, value); 510 else 511 *(volatile u_int32_t *)(bsh + offset) = value; 512 } 513 514 #ifdef __amd64__ 515 static __inline void 516 bus_space_write_8(bus_space_tag_t tag, bus_space_handle_t bsh, 517 bus_size_t offset, uint64_t value) 518 { 519 520 if (tag == X86_BUS_SPACE_IO) /* No 8 byte IO space access on x86 */ 521 return; 522 else 523 *(volatile uint64_t *)(bsh + offset) = value; 524 } 525 #endif 526 527 /* 528 * Write `count' 1, 2, 4, or 8 byte quantities from the buffer 529 * provided to bus space described by tag/handle/offset. 530 */ 531 532 static __inline void bus_space_write_multi_1(bus_space_tag_t tag, 533 bus_space_handle_t bsh, 534 bus_size_t offset, 535 const u_int8_t *addr, 536 size_t count); 537 static __inline void bus_space_write_multi_2(bus_space_tag_t tag, 538 bus_space_handle_t bsh, 539 bus_size_t offset, 540 const u_int16_t *addr, 541 size_t count); 542 543 static __inline void bus_space_write_multi_4(bus_space_tag_t tag, 544 bus_space_handle_t bsh, 545 bus_size_t offset, 546 const u_int32_t *addr, 547 size_t count); 548 549 static __inline void 550 bus_space_write_multi_1(bus_space_tag_t tag, bus_space_handle_t bsh, 551 bus_size_t offset, const u_int8_t *addr, size_t count) 552 { 553 554 if (tag == X86_BUS_SPACE_IO) 555 outsb(bsh + offset, addr, count); 556 else { 557 #ifdef __GNUCLIKE_ASM 558 __asm __volatile(" \n\ 559 1: lodsb \n\ 560 movb %%al,(%2) \n\ 561 loop 1b" : 562 "=S" (addr), "=c" (count) : 563 "r" (bsh + offset), "0" (addr), "1" (count) : 564 "%eax", "memory", "cc"); 565 #endif 566 } 567 } 568 569 static __inline void 570 bus_space_write_multi_2(bus_space_tag_t tag, bus_space_handle_t bsh, 571 bus_size_t offset, const u_int16_t *addr, size_t count) 572 { 573 574 if (tag == X86_BUS_SPACE_IO) 575 outsw(bsh + offset, addr, count); 576 else { 577 #ifdef __GNUCLIKE_ASM 578 __asm __volatile(" \n\ 579 1: lodsw \n\ 580 movw %%ax,(%2) \n\ 581 loop 1b" : 582 "=S" (addr), "=c" (count) : 583 "r" (bsh + offset), "0" (addr), "1" (count) : 584 "%eax", "memory", "cc"); 585 #endif 586 } 587 } 588 589 static __inline void 590 bus_space_write_multi_4(bus_space_tag_t tag, bus_space_handle_t bsh, 591 bus_size_t offset, const u_int32_t *addr, size_t count) 592 { 593 594 if (tag == X86_BUS_SPACE_IO) 595 outsl(bsh + offset, addr, count); 596 else { 597 #ifdef __GNUCLIKE_ASM 598 __asm __volatile(" \n\ 599 1: lodsl \n\ 600 movl %%eax,(%2) \n\ 601 loop 1b" : 602 "=S" (addr), "=c" (count) : 603 "r" (bsh + offset), "0" (addr), "1" (count) : 604 "%eax", "memory", "cc"); 605 #endif 606 } 607 } 608 609 #if 0 /* Cause a link error for bus_space_write_multi_8 */ 610 #define bus_space_write_multi_8(t, h, o, a, c) \ 611 !!! bus_space_write_multi_8 unimplemented !!! 612 #endif 613 614 /* 615 * Write `count' 1, 2, 4, or 8 byte quantities from the buffer provided 616 * to bus space described by tag/handle starting at `offset'. 617 */ 618 619 static __inline void bus_space_write_region_1(bus_space_tag_t tag, 620 bus_space_handle_t bsh, 621 bus_size_t offset, 622 const u_int8_t *addr, 623 size_t count); 624 static __inline void bus_space_write_region_2(bus_space_tag_t tag, 625 bus_space_handle_t bsh, 626 bus_size_t offset, 627 const u_int16_t *addr, 628 size_t count); 629 static __inline void bus_space_write_region_4(bus_space_tag_t tag, 630 bus_space_handle_t bsh, 631 bus_size_t offset, 632 const u_int32_t *addr, 633 size_t count); 634 635 static __inline void 636 bus_space_write_region_1(bus_space_tag_t tag, bus_space_handle_t bsh, 637 bus_size_t offset, const u_int8_t *addr, size_t count) 638 { 639 640 if (tag == X86_BUS_SPACE_IO) { 641 int _port_ = bsh + offset; 642 #ifdef __GNUCLIKE_ASM 643 __asm __volatile(" \n\ 644 1: lodsb \n\ 645 outb %%al,%w0 \n\ 646 incl %0 \n\ 647 loop 1b" : 648 "=d" (_port_), "=S" (addr), "=c" (count) : 649 "0" (_port_), "1" (addr), "2" (count) : 650 "%eax", "memory", "cc"); 651 #endif 652 } else { 653 bus_space_handle_t _port_ = bsh + offset; 654 #ifdef __GNUCLIKE_ASM 655 __asm __volatile(" \n\ 656 repne \n\ 657 movsb" : 658 "=D" (_port_), "=S" (addr), "=c" (count) : 659 "0" (_port_), "1" (addr), "2" (count) : 660 "memory", "cc"); 661 #endif 662 } 663 } 664 665 static __inline void 666 bus_space_write_region_2(bus_space_tag_t tag, bus_space_handle_t bsh, 667 bus_size_t offset, const u_int16_t *addr, size_t count) 668 { 669 670 if (tag == X86_BUS_SPACE_IO) { 671 int _port_ = bsh + offset; 672 #ifdef __GNUCLIKE_ASM 673 __asm __volatile(" \n\ 674 1: lodsw \n\ 675 outw %%ax,%w0 \n\ 676 addl $2,%0 \n\ 677 loop 1b" : 678 "=d" (_port_), "=S" (addr), "=c" (count) : 679 "0" (_port_), "1" (addr), "2" (count) : 680 "%eax", "memory", "cc"); 681 #endif 682 } else { 683 bus_space_handle_t _port_ = bsh + offset; 684 #ifdef __GNUCLIKE_ASM 685 __asm __volatile(" \n\ 686 repne \n\ 687 movsw" : 688 "=D" (_port_), "=S" (addr), "=c" (count) : 689 "0" (_port_), "1" (addr), "2" (count) : 690 "memory", "cc"); 691 #endif 692 } 693 } 694 695 static __inline void 696 bus_space_write_region_4(bus_space_tag_t tag, bus_space_handle_t bsh, 697 bus_size_t offset, const u_int32_t *addr, size_t count) 698 { 699 700 if (tag == X86_BUS_SPACE_IO) { 701 int _port_ = bsh + offset; 702 #ifdef __GNUCLIKE_ASM 703 __asm __volatile(" \n\ 704 1: lodsl \n\ 705 outl %%eax,%w0 \n\ 706 addl $4,%0 \n\ 707 loop 1b" : 708 "=d" (_port_), "=S" (addr), "=c" (count) : 709 "0" (_port_), "1" (addr), "2" (count) : 710 "%eax", "memory", "cc"); 711 #endif 712 } else { 713 bus_space_handle_t _port_ = bsh + offset; 714 #ifdef __GNUCLIKE_ASM 715 __asm __volatile(" \n\ 716 repne \n\ 717 movsl" : 718 "=D" (_port_), "=S" (addr), "=c" (count) : 719 "0" (_port_), "1" (addr), "2" (count) : 720 "memory", "cc"); 721 #endif 722 } 723 } 724 725 #if 0 /* Cause a link error for bus_space_write_region_8 */ 726 #define bus_space_write_region_8 \ 727 !!! bus_space_write_region_8 unimplemented !!! 728 #endif 729 730 /* 731 * Write the 1, 2, 4, or 8 byte value `val' to bus space described 732 * by tag/handle/offset `count' times. 733 */ 734 735 static __inline void bus_space_set_multi_1(bus_space_tag_t tag, 736 bus_space_handle_t bsh, 737 bus_size_t offset, 738 u_int8_t value, size_t count); 739 static __inline void bus_space_set_multi_2(bus_space_tag_t tag, 740 bus_space_handle_t bsh, 741 bus_size_t offset, 742 u_int16_t value, size_t count); 743 static __inline void bus_space_set_multi_4(bus_space_tag_t tag, 744 bus_space_handle_t bsh, 745 bus_size_t offset, 746 u_int32_t value, size_t count); 747 748 static __inline void 749 bus_space_set_multi_1(bus_space_tag_t tag, bus_space_handle_t bsh, 750 bus_size_t offset, u_int8_t value, size_t count) 751 { 752 bus_space_handle_t addr = bsh + offset; 753 754 if (tag == X86_BUS_SPACE_IO) 755 while (count--) 756 outb(addr, value); 757 else 758 while (count--) 759 *(volatile u_int8_t *)(addr) = value; 760 } 761 762 static __inline void 763 bus_space_set_multi_2(bus_space_tag_t tag, bus_space_handle_t bsh, 764 bus_size_t offset, u_int16_t value, size_t count) 765 { 766 bus_space_handle_t addr = bsh + offset; 767 768 if (tag == X86_BUS_SPACE_IO) 769 while (count--) 770 outw(addr, value); 771 else 772 while (count--) 773 *(volatile u_int16_t *)(addr) = value; 774 } 775 776 static __inline void 777 bus_space_set_multi_4(bus_space_tag_t tag, bus_space_handle_t bsh, 778 bus_size_t offset, u_int32_t value, size_t count) 779 { 780 bus_space_handle_t addr = bsh + offset; 781 782 if (tag == X86_BUS_SPACE_IO) 783 while (count--) 784 outl(addr, value); 785 else 786 while (count--) 787 *(volatile u_int32_t *)(addr) = value; 788 } 789 790 #if 0 /* Cause a link error for bus_space_set_multi_8 */ 791 #define bus_space_set_multi_8 !!! bus_space_set_multi_8 unimplemented !!! 792 #endif 793 794 /* 795 * Write `count' 1, 2, 4, or 8 byte value `val' to bus space described 796 * by tag/handle starting at `offset'. 797 */ 798 799 static __inline void bus_space_set_region_1(bus_space_tag_t tag, 800 bus_space_handle_t bsh, 801 bus_size_t offset, u_int8_t value, 802 size_t count); 803 static __inline void bus_space_set_region_2(bus_space_tag_t tag, 804 bus_space_handle_t bsh, 805 bus_size_t offset, u_int16_t value, 806 size_t count); 807 static __inline void bus_space_set_region_4(bus_space_tag_t tag, 808 bus_space_handle_t bsh, 809 bus_size_t offset, u_int32_t value, 810 size_t count); 811 812 static __inline void 813 bus_space_set_region_1(bus_space_tag_t tag, bus_space_handle_t bsh, 814 bus_size_t offset, u_int8_t value, size_t count) 815 { 816 bus_space_handle_t addr = bsh + offset; 817 818 if (tag == X86_BUS_SPACE_IO) 819 for (; count != 0; count--, addr++) 820 outb(addr, value); 821 else 822 for (; count != 0; count--, addr++) 823 *(volatile u_int8_t *)(addr) = value; 824 } 825 826 static __inline void 827 bus_space_set_region_2(bus_space_tag_t tag, bus_space_handle_t bsh, 828 bus_size_t offset, u_int16_t value, size_t count) 829 { 830 bus_space_handle_t addr = bsh + offset; 831 832 if (tag == X86_BUS_SPACE_IO) 833 for (; count != 0; count--, addr += 2) 834 outw(addr, value); 835 else 836 for (; count != 0; count--, addr += 2) 837 *(volatile u_int16_t *)(addr) = value; 838 } 839 840 static __inline void 841 bus_space_set_region_4(bus_space_tag_t tag, bus_space_handle_t bsh, 842 bus_size_t offset, u_int32_t value, size_t count) 843 { 844 bus_space_handle_t addr = bsh + offset; 845 846 if (tag == X86_BUS_SPACE_IO) 847 for (; count != 0; count--, addr += 4) 848 outl(addr, value); 849 else 850 for (; count != 0; count--, addr += 4) 851 *(volatile u_int32_t *)(addr) = value; 852 } 853 854 #if 0 /* Cause a link error for bus_space_set_region_8 */ 855 #define bus_space_set_region_8 !!! bus_space_set_region_8 unimplemented !!! 856 #endif 857 858 /* 859 * Copy `count' 1, 2, 4, or 8 byte values from bus space starting 860 * at tag/bsh1/off1 to bus space starting at tag/bsh2/off2. 861 */ 862 863 static __inline void bus_space_copy_region_1(bus_space_tag_t tag, 864 bus_space_handle_t bsh1, 865 bus_size_t off1, 866 bus_space_handle_t bsh2, 867 bus_size_t off2, size_t count); 868 869 static __inline void bus_space_copy_region_2(bus_space_tag_t tag, 870 bus_space_handle_t bsh1, 871 bus_size_t off1, 872 bus_space_handle_t bsh2, 873 bus_size_t off2, size_t count); 874 875 static __inline void bus_space_copy_region_4(bus_space_tag_t tag, 876 bus_space_handle_t bsh1, 877 bus_size_t off1, 878 bus_space_handle_t bsh2, 879 bus_size_t off2, size_t count); 880 881 static __inline void 882 bus_space_copy_region_1(bus_space_tag_t tag, bus_space_handle_t bsh1, 883 bus_size_t off1, bus_space_handle_t bsh2, 884 bus_size_t off2, size_t count) 885 { 886 bus_space_handle_t addr1 = bsh1 + off1; 887 bus_space_handle_t addr2 = bsh2 + off2; 888 889 if (tag == X86_BUS_SPACE_IO) { 890 if (addr1 >= addr2) { 891 /* src after dest: copy forward */ 892 for (; count != 0; count--, addr1++, addr2++) 893 outb(addr2, inb(addr1)); 894 } else { 895 /* dest after src: copy backwards */ 896 for (addr1 += (count - 1), addr2 += (count - 1); 897 count != 0; count--, addr1--, addr2--) 898 outb(addr2, inb(addr1)); 899 } 900 } else { 901 if (addr1 >= addr2) { 902 /* src after dest: copy forward */ 903 for (; count != 0; count--, addr1++, addr2++) 904 *(volatile u_int8_t *)(addr2) = 905 *(volatile u_int8_t *)(addr1); 906 } else { 907 /* dest after src: copy backwards */ 908 for (addr1 += (count - 1), addr2 += (count - 1); 909 count != 0; count--, addr1--, addr2--) 910 *(volatile u_int8_t *)(addr2) = 911 *(volatile u_int8_t *)(addr1); 912 } 913 } 914 } 915 916 static __inline void 917 bus_space_copy_region_2(bus_space_tag_t tag, bus_space_handle_t bsh1, 918 bus_size_t off1, bus_space_handle_t bsh2, 919 bus_size_t off2, size_t count) 920 { 921 bus_space_handle_t addr1 = bsh1 + off1; 922 bus_space_handle_t addr2 = bsh2 + off2; 923 924 if (tag == X86_BUS_SPACE_IO) { 925 if (addr1 >= addr2) { 926 /* src after dest: copy forward */ 927 for (; count != 0; count--, addr1 += 2, addr2 += 2) 928 outw(addr2, inw(addr1)); 929 } else { 930 /* dest after src: copy backwards */ 931 for (addr1 += 2 * (count - 1), addr2 += 2 * (count - 1); 932 count != 0; count--, addr1 -= 2, addr2 -= 2) 933 outw(addr2, inw(addr1)); 934 } 935 } else { 936 if (addr1 >= addr2) { 937 /* src after dest: copy forward */ 938 for (; count != 0; count--, addr1 += 2, addr2 += 2) 939 *(volatile u_int16_t *)(addr2) = 940 *(volatile u_int16_t *)(addr1); 941 } else { 942 /* dest after src: copy backwards */ 943 for (addr1 += 2 * (count - 1), addr2 += 2 * (count - 1); 944 count != 0; count--, addr1 -= 2, addr2 -= 2) 945 *(volatile u_int16_t *)(addr2) = 946 *(volatile u_int16_t *)(addr1); 947 } 948 } 949 } 950 951 static __inline void 952 bus_space_copy_region_4(bus_space_tag_t tag, bus_space_handle_t bsh1, 953 bus_size_t off1, bus_space_handle_t bsh2, 954 bus_size_t off2, size_t count) 955 { 956 bus_space_handle_t addr1 = bsh1 + off1; 957 bus_space_handle_t addr2 = bsh2 + off2; 958 959 if (tag == X86_BUS_SPACE_IO) { 960 if (addr1 >= addr2) { 961 /* src after dest: copy forward */ 962 for (; count != 0; count--, addr1 += 4, addr2 += 4) 963 outl(addr2, inl(addr1)); 964 } else { 965 /* dest after src: copy backwards */ 966 for (addr1 += 4 * (count - 1), addr2 += 4 * (count - 1); 967 count != 0; count--, addr1 -= 4, addr2 -= 4) 968 outl(addr2, inl(addr1)); 969 } 970 } else { 971 if (addr1 >= addr2) { 972 /* src after dest: copy forward */ 973 for (; count != 0; count--, addr1 += 4, addr2 += 4) 974 *(volatile u_int32_t *)(addr2) = 975 *(volatile u_int32_t *)(addr1); 976 } else { 977 /* dest after src: copy backwards */ 978 for (addr1 += 4 * (count - 1), addr2 += 4 * (count - 1); 979 count != 0; count--, addr1 -= 4, addr2 -= 4) 980 *(volatile u_int32_t *)(addr2) = 981 *(volatile u_int32_t *)(addr1); 982 } 983 } 984 } 985 986 #if 0 /* Cause a link error for bus_space_copy_8 */ 987 #define bus_space_copy_region_8 !!! bus_space_copy_region_8 unimplemented !!! 988 #endif 989 990 /* 991 * Bus read/write barrier methods. 992 * 993 * void bus_space_barrier(bus_space_tag_t tag, bus_space_handle_t bsh, 994 * bus_size_t offset, bus_size_t len, int flags); 995 * 996 * 997 * Note that BUS_SPACE_BARRIER_WRITE doesn't do anything other than 998 * prevent reordering by the compiler; all Intel x86 processors currently 999 * retire operations outside the CPU in program order. 1000 */ 1001 static __inline void 1002 bus_space_barrier(bus_space_tag_t tag __unused, bus_space_handle_t bsh __unused, 1003 bus_size_t offset __unused, bus_size_t len __unused, int flags) 1004 { 1005 #ifdef __GNUCLIKE_ASM 1006 if (flags & BUS_SPACE_BARRIER_READ) 1007 #ifdef __amd64__ 1008 __asm __volatile("lock; addl $0,0(%%rsp)" : : : "memory"); 1009 #else 1010 __asm __volatile("lock; addl $0,0(%%esp)" : : : "memory"); 1011 #endif 1012 else 1013 __compiler_membar(); 1014 #endif 1015 } 1016 1017 #ifdef BUS_SPACE_NO_LEGACY 1018 #undef inb 1019 #undef outb 1020 #define inb(a) compiler_error 1021 #define inw(a) compiler_error 1022 #define inl(a) compiler_error 1023 #define outb(a, b) compiler_error 1024 #define outw(a, b) compiler_error 1025 #define outl(a, b) compiler_error 1026 #endif 1027 1028 /* 1029 * Stream accesses are the same as normal accesses on x86; there are no 1030 * supported bus systems with an endianess different from the host one. 1031 */ 1032 #define bus_space_read_stream_1(t, h, o) bus_space_read_1((t), (h), (o)) 1033 #define bus_space_read_stream_2(t, h, o) bus_space_read_2((t), (h), (o)) 1034 #define bus_space_read_stream_4(t, h, o) bus_space_read_4((t), (h), (o)) 1035 1036 #define bus_space_read_multi_stream_1(t, h, o, a, c) \ 1037 bus_space_read_multi_1((t), (h), (o), (a), (c)) 1038 #define bus_space_read_multi_stream_2(t, h, o, a, c) \ 1039 bus_space_read_multi_2((t), (h), (o), (a), (c)) 1040 #define bus_space_read_multi_stream_4(t, h, o, a, c) \ 1041 bus_space_read_multi_4((t), (h), (o), (a), (c)) 1042 1043 #define bus_space_write_stream_1(t, h, o, v) \ 1044 bus_space_write_1((t), (h), (o), (v)) 1045 #define bus_space_write_stream_2(t, h, o, v) \ 1046 bus_space_write_2((t), (h), (o), (v)) 1047 #define bus_space_write_stream_4(t, h, o, v) \ 1048 bus_space_write_4((t), (h), (o), (v)) 1049 1050 #define bus_space_write_multi_stream_1(t, h, o, a, c) \ 1051 bus_space_write_multi_1((t), (h), (o), (a), (c)) 1052 #define bus_space_write_multi_stream_2(t, h, o, a, c) \ 1053 bus_space_write_multi_2((t), (h), (o), (a), (c)) 1054 #define bus_space_write_multi_stream_4(t, h, o, a, c) \ 1055 bus_space_write_multi_4((t), (h), (o), (a), (c)) 1056 1057 #define bus_space_set_multi_stream_1(t, h, o, v, c) \ 1058 bus_space_set_multi_1((t), (h), (o), (v), (c)) 1059 #define bus_space_set_multi_stream_2(t, h, o, v, c) \ 1060 bus_space_set_multi_2((t), (h), (o), (v), (c)) 1061 #define bus_space_set_multi_stream_4(t, h, o, v, c) \ 1062 bus_space_set_multi_4((t), (h), (o), (v), (c)) 1063 1064 #define bus_space_read_region_stream_1(t, h, o, a, c) \ 1065 bus_space_read_region_1((t), (h), (o), (a), (c)) 1066 #define bus_space_read_region_stream_2(t, h, o, a, c) \ 1067 bus_space_read_region_2((t), (h), (o), (a), (c)) 1068 #define bus_space_read_region_stream_4(t, h, o, a, c) \ 1069 bus_space_read_region_4((t), (h), (o), (a), (c)) 1070 1071 #define bus_space_write_region_stream_1(t, h, o, a, c) \ 1072 bus_space_write_region_1((t), (h), (o), (a), (c)) 1073 #define bus_space_write_region_stream_2(t, h, o, a, c) \ 1074 bus_space_write_region_2((t), (h), (o), (a), (c)) 1075 #define bus_space_write_region_stream_4(t, h, o, a, c) \ 1076 bus_space_write_region_4((t), (h), (o), (a), (c)) 1077 1078 #define bus_space_set_region_stream_1(t, h, o, v, c) \ 1079 bus_space_set_region_1((t), (h), (o), (v), (c)) 1080 #define bus_space_set_region_stream_2(t, h, o, v, c) \ 1081 bus_space_set_region_2((t), (h), (o), (v), (c)) 1082 #define bus_space_set_region_stream_4(t, h, o, v, c) \ 1083 bus_space_set_region_4((t), (h), (o), (v), (c)) 1084 1085 #define bus_space_copy_region_stream_1(t, h1, o1, h2, o2, c) \ 1086 bus_space_copy_region_1((t), (h1), (o1), (h2), (o2), (c)) 1087 #define bus_space_copy_region_stream_2(t, h1, o1, h2, o2, c) \ 1088 bus_space_copy_region_2((t), (h1), (o1), (h2), (o2), (c)) 1089 #define bus_space_copy_region_stream_4(t, h1, o1, h2, o2, c) \ 1090 bus_space_copy_region_4((t), (h1), (o1), (h2), (o2), (c)) 1091 1092 #define BUS_PEEK_FUNC(width, type) \ 1093 static inline int \ 1094 bus_space_peek_##width(bus_space_tag_t tag, \ 1095 bus_space_handle_t hnd, bus_size_t offset, type *value) \ 1096 { \ 1097 type tmp; \ 1098 tmp = bus_space_read_##width(tag, hnd, offset); \ 1099 *value = (type)tmp; \ 1100 return (0); \ 1101 } 1102 BUS_PEEK_FUNC(1, uint8_t) 1103 BUS_PEEK_FUNC(2, uint16_t) 1104 BUS_PEEK_FUNC(4, uint32_t) 1105 #ifdef __amd64__ 1106 BUS_PEEK_FUNC(8, uint64_t) 1107 #endif 1108 1109 #define BUS_POKE_FUNC(width, type) \ 1110 static inline int \ 1111 bus_space_poke_##width(bus_space_tag_t tag, \ 1112 bus_space_handle_t hnd, bus_size_t offset, type value) \ 1113 { \ 1114 bus_space_write_##width(tag, hnd, offset, value); \ 1115 return (0); \ 1116 } 1117 BUS_POKE_FUNC(1, uint8_t) 1118 BUS_POKE_FUNC(2, uint16_t) 1119 BUS_POKE_FUNC(4, uint32_t) 1120 #ifdef __amd64__ 1121 BUS_POKE_FUNC(8, uint64_t) 1122 #endif 1123 1124 #endif /* KCSAN && !KCSAN_RUNTIME */ 1125 1126 #endif /* _X86_BUS_H_ */ 1127