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 105 #ifndef __GNUCLIKE_ASM 106 #error "no assembler code for your compiler" 107 #endif 108 109 /* 110 * Values for the x86 bus space tag, not to be used directly by MI code. 111 */ 112 #define X86_BUS_SPACE_IO 0 /* space is i/o space */ 113 #define X86_BUS_SPACE_MEM 1 /* space is mem space */ 114 115 #define BUS_SPACE_MAXSIZE_24BIT 0xFFFFFF 116 #define BUS_SPACE_MAXSIZE_32BIT 0xFFFFFFFF 117 #define BUS_SPACE_MAXSIZE 0xFFFFFFFF 118 #define BUS_SPACE_MAXADDR_24BIT 0xFFFFFF 119 #define BUS_SPACE_MAXADDR_32BIT 0xFFFFFFFF 120 #if defined(__amd64__) || defined(PAE) 121 #define BUS_SPACE_MAXADDR_48BIT 0xFFFFFFFFFFFFULL 122 #define BUS_SPACE_MAXADDR 0xFFFFFFFFFFFFFFFFULL 123 #else 124 #define BUS_SPACE_MAXADDR 0xFFFFFFFF 125 #endif 126 127 #define BUS_SPACE_INVALID_DATA (~0) 128 #define BUS_SPACE_UNRESTRICTED (~0) 129 130 /* 131 * Map a region of device bus space into CPU virtual address space. 132 */ 133 134 int bus_space_map(bus_space_tag_t tag, bus_addr_t addr, bus_size_t size, 135 int flags, bus_space_handle_t *bshp); 136 137 /* 138 * Unmap a region of device bus space. 139 */ 140 141 void bus_space_unmap(bus_space_tag_t tag, bus_space_handle_t bsh, 142 bus_size_t size); 143 144 /* 145 * Get a new handle for a subregion of an already-mapped area of bus space. 146 */ 147 148 static __inline int bus_space_subregion(bus_space_tag_t t, 149 bus_space_handle_t bsh, 150 bus_size_t offset, bus_size_t size, 151 bus_space_handle_t *nbshp); 152 153 static __inline int 154 bus_space_subregion(bus_space_tag_t t __unused, bus_space_handle_t bsh, 155 bus_size_t offset, bus_size_t size __unused, 156 bus_space_handle_t *nbshp) 157 { 158 159 *nbshp = bsh + offset; 160 return (0); 161 } 162 163 /* 164 * Allocate a region of memory that is accessible to devices in bus space. 165 */ 166 167 int bus_space_alloc(bus_space_tag_t t, bus_addr_t rstart, 168 bus_addr_t rend, bus_size_t size, bus_size_t align, 169 bus_size_t boundary, int flags, bus_addr_t *addrp, 170 bus_space_handle_t *bshp); 171 172 /* 173 * Free a region of bus space accessible memory. 174 */ 175 176 static __inline void bus_space_free(bus_space_tag_t t, bus_space_handle_t bsh, 177 bus_size_t size); 178 179 static __inline void 180 bus_space_free(bus_space_tag_t t __unused, bus_space_handle_t bsh __unused, 181 bus_size_t size __unused) 182 { 183 } 184 185 186 /* 187 * Read a 1, 2, 4, or 8 byte quantity from bus space 188 * described by tag/handle/offset. 189 */ 190 static __inline u_int8_t bus_space_read_1(bus_space_tag_t tag, 191 bus_space_handle_t handle, 192 bus_size_t offset); 193 194 static __inline u_int16_t bus_space_read_2(bus_space_tag_t tag, 195 bus_space_handle_t handle, 196 bus_size_t offset); 197 198 static __inline u_int32_t bus_space_read_4(bus_space_tag_t tag, 199 bus_space_handle_t handle, 200 bus_size_t offset); 201 202 #ifdef __amd64__ 203 static __inline uint64_t bus_space_read_8(bus_space_tag_t tag, 204 bus_space_handle_t handle, 205 bus_size_t offset); 206 #endif 207 208 static __inline u_int8_t 209 bus_space_read_1(bus_space_tag_t tag, bus_space_handle_t handle, 210 bus_size_t offset) 211 { 212 213 if (tag == X86_BUS_SPACE_IO) 214 return (inb(handle + offset)); 215 return (*(volatile u_int8_t *)(handle + offset)); 216 } 217 218 static __inline u_int16_t 219 bus_space_read_2(bus_space_tag_t tag, bus_space_handle_t handle, 220 bus_size_t offset) 221 { 222 223 if (tag == X86_BUS_SPACE_IO) 224 return (inw(handle + offset)); 225 return (*(volatile u_int16_t *)(handle + offset)); 226 } 227 228 static __inline u_int32_t 229 bus_space_read_4(bus_space_tag_t tag, bus_space_handle_t handle, 230 bus_size_t offset) 231 { 232 233 if (tag == X86_BUS_SPACE_IO) 234 return (inl(handle + offset)); 235 return (*(volatile u_int32_t *)(handle + offset)); 236 } 237 238 #ifdef __amd64__ 239 static __inline uint64_t 240 bus_space_read_8(bus_space_tag_t tag, bus_space_handle_t handle, 241 bus_size_t offset) 242 { 243 244 if (tag == X86_BUS_SPACE_IO) /* No 8 byte IO space access on x86 */ 245 return (BUS_SPACE_INVALID_DATA); 246 return (*(volatile uint64_t *)(handle + offset)); 247 } 248 #endif 249 250 /* 251 * Read `count' 1, 2, 4, or 8 byte quantities from bus space 252 * described by tag/handle/offset and copy into buffer provided. 253 */ 254 static __inline void bus_space_read_multi_1(bus_space_tag_t tag, 255 bus_space_handle_t bsh, 256 bus_size_t offset, u_int8_t *addr, 257 size_t count); 258 259 static __inline void bus_space_read_multi_2(bus_space_tag_t tag, 260 bus_space_handle_t bsh, 261 bus_size_t offset, u_int16_t *addr, 262 size_t count); 263 264 static __inline void bus_space_read_multi_4(bus_space_tag_t tag, 265 bus_space_handle_t bsh, 266 bus_size_t offset, u_int32_t *addr, 267 size_t count); 268 269 static __inline void 270 bus_space_read_multi_1(bus_space_tag_t tag, bus_space_handle_t bsh, 271 bus_size_t offset, u_int8_t *addr, size_t count) 272 { 273 274 if (tag == X86_BUS_SPACE_IO) 275 insb(bsh + offset, addr, count); 276 else { 277 #ifdef __GNUCLIKE_ASM 278 __asm __volatile(" \n\ 279 cld \n\ 280 1: movb (%2),%%al \n\ 281 stosb \n\ 282 loop 1b" : 283 "=D" (addr), "=c" (count) : 284 "r" (bsh + offset), "0" (addr), "1" (count) : 285 "%eax", "memory"); 286 #endif 287 } 288 } 289 290 static __inline void 291 bus_space_read_multi_2(bus_space_tag_t tag, bus_space_handle_t bsh, 292 bus_size_t offset, u_int16_t *addr, size_t count) 293 { 294 295 if (tag == X86_BUS_SPACE_IO) 296 insw(bsh + offset, addr, count); 297 else { 298 #ifdef __GNUCLIKE_ASM 299 __asm __volatile(" \n\ 300 cld \n\ 301 1: movw (%2),%%ax \n\ 302 stosw \n\ 303 loop 1b" : 304 "=D" (addr), "=c" (count) : 305 "r" (bsh + offset), "0" (addr), "1" (count) : 306 "%eax", "memory"); 307 #endif 308 } 309 } 310 311 static __inline void 312 bus_space_read_multi_4(bus_space_tag_t tag, bus_space_handle_t bsh, 313 bus_size_t offset, u_int32_t *addr, size_t count) 314 { 315 316 if (tag == X86_BUS_SPACE_IO) 317 insl(bsh + offset, addr, count); 318 else { 319 #ifdef __GNUCLIKE_ASM 320 __asm __volatile(" \n\ 321 cld \n\ 322 1: movl (%2),%%eax \n\ 323 stosl \n\ 324 loop 1b" : 325 "=D" (addr), "=c" (count) : 326 "r" (bsh + offset), "0" (addr), "1" (count) : 327 "%eax", "memory"); 328 #endif 329 } 330 } 331 332 #if 0 /* Cause a link error for bus_space_read_multi_8 */ 333 #define bus_space_read_multi_8 !!! bus_space_read_multi_8 unimplemented !!! 334 #endif 335 336 /* 337 * Read `count' 1, 2, 4, or 8 byte quantities from bus space 338 * described by tag/handle and starting at `offset' and copy into 339 * buffer provided. 340 */ 341 static __inline void bus_space_read_region_1(bus_space_tag_t tag, 342 bus_space_handle_t bsh, 343 bus_size_t offset, u_int8_t *addr, 344 size_t count); 345 346 static __inline void bus_space_read_region_2(bus_space_tag_t tag, 347 bus_space_handle_t bsh, 348 bus_size_t offset, u_int16_t *addr, 349 size_t count); 350 351 static __inline void bus_space_read_region_4(bus_space_tag_t tag, 352 bus_space_handle_t bsh, 353 bus_size_t offset, u_int32_t *addr, 354 size_t count); 355 356 357 static __inline void 358 bus_space_read_region_1(bus_space_tag_t tag, bus_space_handle_t bsh, 359 bus_size_t offset, u_int8_t *addr, size_t count) 360 { 361 362 if (tag == X86_BUS_SPACE_IO) { 363 int _port_ = bsh + offset; 364 #ifdef __GNUCLIKE_ASM 365 __asm __volatile(" \n\ 366 cld \n\ 367 1: inb %w2,%%al \n\ 368 stosb \n\ 369 incl %2 \n\ 370 loop 1b" : 371 "=D" (addr), "=c" (count), "=d" (_port_) : 372 "0" (addr), "1" (count), "2" (_port_) : 373 "%eax", "memory", "cc"); 374 #endif 375 } else { 376 bus_space_handle_t _port_ = bsh + offset; 377 #ifdef __GNUCLIKE_ASM 378 __asm __volatile(" \n\ 379 cld \n\ 380 repne \n\ 381 movsb" : 382 "=D" (addr), "=c" (count), "=S" (_port_) : 383 "0" (addr), "1" (count), "2" (_port_) : 384 "memory", "cc"); 385 #endif 386 } 387 } 388 389 static __inline void 390 bus_space_read_region_2(bus_space_tag_t tag, bus_space_handle_t bsh, 391 bus_size_t offset, u_int16_t *addr, size_t count) 392 { 393 394 if (tag == X86_BUS_SPACE_IO) { 395 int _port_ = bsh + offset; 396 #ifdef __GNUCLIKE_ASM 397 __asm __volatile(" \n\ 398 cld \n\ 399 1: inw %w2,%%ax \n\ 400 stosw \n\ 401 addl $2,%2 \n\ 402 loop 1b" : 403 "=D" (addr), "=c" (count), "=d" (_port_) : 404 "0" (addr), "1" (count), "2" (_port_) : 405 "%eax", "memory", "cc"); 406 #endif 407 } else { 408 bus_space_handle_t _port_ = bsh + offset; 409 #ifdef __GNUCLIKE_ASM 410 __asm __volatile(" \n\ 411 cld \n\ 412 repne \n\ 413 movsw" : 414 "=D" (addr), "=c" (count), "=S" (_port_) : 415 "0" (addr), "1" (count), "2" (_port_) : 416 "memory", "cc"); 417 #endif 418 } 419 } 420 421 static __inline void 422 bus_space_read_region_4(bus_space_tag_t tag, bus_space_handle_t bsh, 423 bus_size_t offset, u_int32_t *addr, size_t count) 424 { 425 426 if (tag == X86_BUS_SPACE_IO) { 427 int _port_ = bsh + offset; 428 #ifdef __GNUCLIKE_ASM 429 __asm __volatile(" \n\ 430 cld \n\ 431 1: inl %w2,%%eax \n\ 432 stosl \n\ 433 addl $4,%2 \n\ 434 loop 1b" : 435 "=D" (addr), "=c" (count), "=d" (_port_) : 436 "0" (addr), "1" (count), "2" (_port_) : 437 "%eax", "memory", "cc"); 438 #endif 439 } else { 440 bus_space_handle_t _port_ = bsh + offset; 441 #ifdef __GNUCLIKE_ASM 442 __asm __volatile(" \n\ 443 cld \n\ 444 repne \n\ 445 movsl" : 446 "=D" (addr), "=c" (count), "=S" (_port_) : 447 "0" (addr), "1" (count), "2" (_port_) : 448 "memory", "cc"); 449 #endif 450 } 451 } 452 453 #if 0 /* Cause a link error for bus_space_read_region_8 */ 454 #define bus_space_read_region_8 !!! bus_space_read_region_8 unimplemented !!! 455 #endif 456 457 /* 458 * Write the 1, 2, 4, or 8 byte value `value' to bus space 459 * described by tag/handle/offset. 460 */ 461 462 static __inline void bus_space_write_1(bus_space_tag_t tag, 463 bus_space_handle_t bsh, 464 bus_size_t offset, u_int8_t value); 465 466 static __inline void bus_space_write_2(bus_space_tag_t tag, 467 bus_space_handle_t bsh, 468 bus_size_t offset, u_int16_t value); 469 470 static __inline void bus_space_write_4(bus_space_tag_t tag, 471 bus_space_handle_t bsh, 472 bus_size_t offset, u_int32_t value); 473 474 #ifdef __amd64__ 475 static __inline void bus_space_write_8(bus_space_tag_t tag, 476 bus_space_handle_t bsh, 477 bus_size_t offset, uint64_t value); 478 #endif 479 480 static __inline void 481 bus_space_write_1(bus_space_tag_t tag, bus_space_handle_t bsh, 482 bus_size_t offset, u_int8_t value) 483 { 484 485 if (tag == X86_BUS_SPACE_IO) 486 outb(bsh + offset, value); 487 else 488 *(volatile u_int8_t *)(bsh + offset) = value; 489 } 490 491 static __inline void 492 bus_space_write_2(bus_space_tag_t tag, bus_space_handle_t bsh, 493 bus_size_t offset, u_int16_t value) 494 { 495 496 if (tag == X86_BUS_SPACE_IO) 497 outw(bsh + offset, value); 498 else 499 *(volatile u_int16_t *)(bsh + offset) = value; 500 } 501 502 static __inline void 503 bus_space_write_4(bus_space_tag_t tag, bus_space_handle_t bsh, 504 bus_size_t offset, u_int32_t value) 505 { 506 507 if (tag == X86_BUS_SPACE_IO) 508 outl(bsh + offset, value); 509 else 510 *(volatile u_int32_t *)(bsh + offset) = value; 511 } 512 513 #ifdef __amd64__ 514 static __inline void 515 bus_space_write_8(bus_space_tag_t tag, bus_space_handle_t bsh, 516 bus_size_t offset, uint64_t value) 517 { 518 519 if (tag == X86_BUS_SPACE_IO) /* No 8 byte IO space access on x86 */ 520 return; 521 else 522 *(volatile uint64_t *)(bsh + offset) = value; 523 } 524 #endif 525 526 /* 527 * Write `count' 1, 2, 4, or 8 byte quantities from the buffer 528 * provided to bus space described by tag/handle/offset. 529 */ 530 531 static __inline void bus_space_write_multi_1(bus_space_tag_t tag, 532 bus_space_handle_t bsh, 533 bus_size_t offset, 534 const u_int8_t *addr, 535 size_t count); 536 static __inline void bus_space_write_multi_2(bus_space_tag_t tag, 537 bus_space_handle_t bsh, 538 bus_size_t offset, 539 const u_int16_t *addr, 540 size_t count); 541 542 static __inline void bus_space_write_multi_4(bus_space_tag_t tag, 543 bus_space_handle_t bsh, 544 bus_size_t offset, 545 const u_int32_t *addr, 546 size_t count); 547 548 static __inline void 549 bus_space_write_multi_1(bus_space_tag_t tag, bus_space_handle_t bsh, 550 bus_size_t offset, const u_int8_t *addr, size_t count) 551 { 552 553 if (tag == X86_BUS_SPACE_IO) 554 outsb(bsh + offset, addr, count); 555 else { 556 #ifdef __GNUCLIKE_ASM 557 __asm __volatile(" \n\ 558 cld \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 cld \n\ 580 1: lodsw \n\ 581 movw %%ax,(%2) \n\ 582 loop 1b" : 583 "=S" (addr), "=c" (count) : 584 "r" (bsh + offset), "0" (addr), "1" (count) : 585 "%eax", "memory", "cc"); 586 #endif 587 } 588 } 589 590 static __inline void 591 bus_space_write_multi_4(bus_space_tag_t tag, bus_space_handle_t bsh, 592 bus_size_t offset, const u_int32_t *addr, size_t count) 593 { 594 595 if (tag == X86_BUS_SPACE_IO) 596 outsl(bsh + offset, addr, count); 597 else { 598 #ifdef __GNUCLIKE_ASM 599 __asm __volatile(" \n\ 600 cld \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 cld \n\ 647 1: lodsb \n\ 648 outb %%al,%w0 \n\ 649 incl %0 \n\ 650 loop 1b" : 651 "=d" (_port_), "=S" (addr), "=c" (count) : 652 "0" (_port_), "1" (addr), "2" (count) : 653 "%eax", "memory", "cc"); 654 #endif 655 } else { 656 bus_space_handle_t _port_ = bsh + offset; 657 #ifdef __GNUCLIKE_ASM 658 __asm __volatile(" \n\ 659 cld \n\ 660 repne \n\ 661 movsb" : 662 "=D" (_port_), "=S" (addr), "=c" (count) : 663 "0" (_port_), "1" (addr), "2" (count) : 664 "memory", "cc"); 665 #endif 666 } 667 } 668 669 static __inline void 670 bus_space_write_region_2(bus_space_tag_t tag, bus_space_handle_t bsh, 671 bus_size_t offset, const u_int16_t *addr, size_t count) 672 { 673 674 if (tag == X86_BUS_SPACE_IO) { 675 int _port_ = bsh + offset; 676 #ifdef __GNUCLIKE_ASM 677 __asm __volatile(" \n\ 678 cld \n\ 679 1: lodsw \n\ 680 outw %%ax,%w0 \n\ 681 addl $2,%0 \n\ 682 loop 1b" : 683 "=d" (_port_), "=S" (addr), "=c" (count) : 684 "0" (_port_), "1" (addr), "2" (count) : 685 "%eax", "memory", "cc"); 686 #endif 687 } else { 688 bus_space_handle_t _port_ = bsh + offset; 689 #ifdef __GNUCLIKE_ASM 690 __asm __volatile(" \n\ 691 cld \n\ 692 repne \n\ 693 movsw" : 694 "=D" (_port_), "=S" (addr), "=c" (count) : 695 "0" (_port_), "1" (addr), "2" (count) : 696 "memory", "cc"); 697 #endif 698 } 699 } 700 701 static __inline void 702 bus_space_write_region_4(bus_space_tag_t tag, bus_space_handle_t bsh, 703 bus_size_t offset, const u_int32_t *addr, size_t count) 704 { 705 706 if (tag == X86_BUS_SPACE_IO) { 707 int _port_ = bsh + offset; 708 #ifdef __GNUCLIKE_ASM 709 __asm __volatile(" \n\ 710 cld \n\ 711 1: lodsl \n\ 712 outl %%eax,%w0 \n\ 713 addl $4,%0 \n\ 714 loop 1b" : 715 "=d" (_port_), "=S" (addr), "=c" (count) : 716 "0" (_port_), "1" (addr), "2" (count) : 717 "%eax", "memory", "cc"); 718 #endif 719 } else { 720 bus_space_handle_t _port_ = bsh + offset; 721 #ifdef __GNUCLIKE_ASM 722 __asm __volatile(" \n\ 723 cld \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 #define BUS_SPACE_BARRIER_READ 0x01 /* force read barrier */ 1010 #define BUS_SPACE_BARRIER_WRITE 0x02 /* force write barrier */ 1011 1012 static __inline void 1013 bus_space_barrier(bus_space_tag_t tag __unused, bus_space_handle_t bsh __unused, 1014 bus_size_t offset __unused, bus_size_t len __unused, int flags) 1015 { 1016 #ifdef __GNUCLIKE_ASM 1017 if (flags & BUS_SPACE_BARRIER_READ) 1018 #ifdef __amd64__ 1019 __asm __volatile("lock; addl $0,0(%%rsp)" : : : "memory"); 1020 #else 1021 __asm __volatile("lock; addl $0,0(%%esp)" : : : "memory"); 1022 #endif 1023 else 1024 __compiler_membar(); 1025 #endif 1026 } 1027 1028 #ifdef BUS_SPACE_NO_LEGACY 1029 #undef inb 1030 #undef outb 1031 #define inb(a) compiler_error 1032 #define inw(a) compiler_error 1033 #define inl(a) compiler_error 1034 #define outb(a, b) compiler_error 1035 #define outw(a, b) compiler_error 1036 #define outl(a, b) compiler_error 1037 #endif 1038 1039 #include <machine/bus_dma.h> 1040 1041 /* 1042 * Stream accesses are the same as normal accesses on x86; there are no 1043 * supported bus systems with an endianess different from the host one. 1044 */ 1045 #define bus_space_read_stream_1(t, h, o) bus_space_read_1((t), (h), (o)) 1046 #define bus_space_read_stream_2(t, h, o) bus_space_read_2((t), (h), (o)) 1047 #define bus_space_read_stream_4(t, h, o) bus_space_read_4((t), (h), (o)) 1048 1049 #define bus_space_read_multi_stream_1(t, h, o, a, c) \ 1050 bus_space_read_multi_1((t), (h), (o), (a), (c)) 1051 #define bus_space_read_multi_stream_2(t, h, o, a, c) \ 1052 bus_space_read_multi_2((t), (h), (o), (a), (c)) 1053 #define bus_space_read_multi_stream_4(t, h, o, a, c) \ 1054 bus_space_read_multi_4((t), (h), (o), (a), (c)) 1055 1056 #define bus_space_write_stream_1(t, h, o, v) \ 1057 bus_space_write_1((t), (h), (o), (v)) 1058 #define bus_space_write_stream_2(t, h, o, v) \ 1059 bus_space_write_2((t), (h), (o), (v)) 1060 #define bus_space_write_stream_4(t, h, o, v) \ 1061 bus_space_write_4((t), (h), (o), (v)) 1062 1063 #define bus_space_write_multi_stream_1(t, h, o, a, c) \ 1064 bus_space_write_multi_1((t), (h), (o), (a), (c)) 1065 #define bus_space_write_multi_stream_2(t, h, o, a, c) \ 1066 bus_space_write_multi_2((t), (h), (o), (a), (c)) 1067 #define bus_space_write_multi_stream_4(t, h, o, a, c) \ 1068 bus_space_write_multi_4((t), (h), (o), (a), (c)) 1069 1070 #define bus_space_set_multi_stream_1(t, h, o, v, c) \ 1071 bus_space_set_multi_1((t), (h), (o), (v), (c)) 1072 #define bus_space_set_multi_stream_2(t, h, o, v, c) \ 1073 bus_space_set_multi_2((t), (h), (o), (v), (c)) 1074 #define bus_space_set_multi_stream_4(t, h, o, v, c) \ 1075 bus_space_set_multi_4((t), (h), (o), (v), (c)) 1076 1077 #define bus_space_read_region_stream_1(t, h, o, a, c) \ 1078 bus_space_read_region_1((t), (h), (o), (a), (c)) 1079 #define bus_space_read_region_stream_2(t, h, o, a, c) \ 1080 bus_space_read_region_2((t), (h), (o), (a), (c)) 1081 #define bus_space_read_region_stream_4(t, h, o, a, c) \ 1082 bus_space_read_region_4((t), (h), (o), (a), (c)) 1083 1084 #define bus_space_write_region_stream_1(t, h, o, a, c) \ 1085 bus_space_write_region_1((t), (h), (o), (a), (c)) 1086 #define bus_space_write_region_stream_2(t, h, o, a, c) \ 1087 bus_space_write_region_2((t), (h), (o), (a), (c)) 1088 #define bus_space_write_region_stream_4(t, h, o, a, c) \ 1089 bus_space_write_region_4((t), (h), (o), (a), (c)) 1090 1091 #define bus_space_set_region_stream_1(t, h, o, v, c) \ 1092 bus_space_set_region_1((t), (h), (o), (v), (c)) 1093 #define bus_space_set_region_stream_2(t, h, o, v, c) \ 1094 bus_space_set_region_2((t), (h), (o), (v), (c)) 1095 #define bus_space_set_region_stream_4(t, h, o, v, c) \ 1096 bus_space_set_region_4((t), (h), (o), (v), (c)) 1097 1098 #define bus_space_copy_region_stream_1(t, h1, o1, h2, o2, c) \ 1099 bus_space_copy_region_1((t), (h1), (o1), (h2), (o2), (c)) 1100 #define bus_space_copy_region_stream_2(t, h1, o1, h2, o2, c) \ 1101 bus_space_copy_region_2((t), (h1), (o1), (h2), (o2), (c)) 1102 #define bus_space_copy_region_stream_4(t, h1, o1, h2, o2, c) \ 1103 bus_space_copy_region_4((t), (h1), (o1), (h2), (o2), (c)) 1104 1105 #endif /* _X86_BUS_H_ */ 1106