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