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