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