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