bus.h revision 32517
1/* $NetBSD: bus.h,v 1.12 1997/10/01 08:25:15 fvdl Exp $ */ 2 3/*- 4 * Copyright (c) 1996, 1997 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 9 * NASA Ames Research Center. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the NetBSD 22 * Foundation, Inc. and its contributors. 23 * 4. Neither the name of The NetBSD Foundation nor the names of its 24 * contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 * POSSIBILITY OF SUCH DAMAGE. 38 */ 39 40/* 41 * Copyright (c) 1996 Charles M. Hannum. All rights reserved. 42 * Copyright (c) 1996 Christopher G. Demetriou. All rights reserved. 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 Christopher G. Demetriou 55 * for the NetBSD Project. 56 * 4. The name of the author may not be used to endorse or promote products 57 * derived from this software without specific prior written permission 58 * 59 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 60 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 61 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 62 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 63 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 64 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 65 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 66 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 67 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 68 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 69 */ 70/* $Id$ */ 71 72#ifndef _I386_BUS_H_ 73#define _I386_BUS_H_ 74 75#include <machine/cpufunc.h> 76 77/* 78 * Values for the i386 bus space tag, not to be used directly by MI code. 79 */ 80#define I386_BUS_SPACE_IO 0 /* space is i/o space */ 81#define I386_BUS_SPACE_MEM 1 /* space is mem space */ 82 83/* 84 * Bus address and size types 85 */ 86typedef u_long bus_addr_t; 87typedef u_long bus_size_t; 88 89#define BUS_SPACE_MAXSIZE_24BIT 0xFFFFFF 90#define BUS_SPACE_MAXSIZE_32BIT 0xFFFFFFFF 91#define BUS_SPACE_MAXSIZE (64 * 1024) /* Maximum supported size */ 92#define BUS_SPACE_MAXADDR_24BIT 0xFFFFFF 93#define BUS_SPACE_MAXADDR_32BIT 0xFFFFFFFF 94#define BUS_SPACE_MAXADDR 0xFFFFFFFF 95 96/* 97 * Access methods for bus resources and address space. 98 */ 99typedef int bus_space_tag_t; 100typedef u_long bus_space_handle_t; 101 102/* 103 * Map a region of device bus space into CPU virtual address space. 104 */ 105 106#define BUS_SPACE_MAP_CACHEABLE 0x01 107#define BUS_SPACE_MAP_LINEAR 0x02 108 109int bus_space_map(bus_space_tag_t t, bus_addr_t addr, bus_size_t size, 110 int flags, bus_space_handle_t *bshp); 111 112/* 113 * Unmap a region of device bus space. 114 */ 115 116void bus_space_unmap(bus_space_tag_t t, bus_space_handle_t bsh, 117 bus_size_t size); 118 119/* 120 * Get a new handle for a subregion of an already-mapped area of bus space. 121 */ 122 123int bus_space_subregion(bus_space_tag_t t, bus_space_handle_t bsh, 124 bus_size_t offset, bus_size_t size, 125 bus_space_handle_t *nbshp); 126 127/* 128 * Allocate a region of memory that is accessible to devices in bus space. 129 */ 130 131int bus_space_alloc(bus_space_tag_t t, bus_addr_t rstart, 132 bus_addr_t rend, bus_size_t size, bus_size_t align, 133 bus_size_t boundary, int flags, bus_addr_t *addrp, 134 bus_space_handle_t *bshp); 135 136/* 137 * Free a region of bus space accessible memory. 138 */ 139 140void bus_space_free(bus_space_tag_t t, bus_space_handle_t bsh, 141 bus_size_t size); 142 143#if defined(_I386_BUS_PIO_H_) || defined(_I386_BUS_MEMIO_H_) 144 145/* 146 * Read a 1, 2, 4, or 8 byte quantity from bus space 147 * described by tag/handle/offset. 148 */ 149static __inline u_int8_t bus_space_read_1(bus_space_tag_t tag, 150 bus_space_handle_t handle, 151 bus_size_t offset); 152 153static __inline u_int16_t bus_space_read_2(bus_space_tag_t tag, 154 bus_space_handle_t handle, 155 bus_size_t offset); 156 157static __inline u_int32_t bus_space_read_4(bus_space_tag_t tag, 158 bus_space_handle_t handle, 159 bus_size_t offset); 160 161static __inline u_int8_t 162bus_space_read_1(bus_space_tag_t tag, bus_space_handle_t handle, 163 bus_size_t offset) 164{ 165#if defined (_I386_BUS_PIO_H_) 166#if defined (_I386_BUS_MEMIO_H_) 167 if (tag == I386_BUS_SPACE_IO) 168#endif 169 return (inb(handle + offset)); 170#endif 171#if defined (_I386_BUS_MEMIO_H_) 172 return (*(volatile u_int8_t *)(handle + offset)); 173#endif 174} 175 176static __inline u_int16_t 177bus_space_read_2(bus_space_tag_t tag, bus_space_handle_t handle, 178 bus_size_t offset) 179{ 180#if defined(_I386_BUS_PIO_H_) 181#if defined(_I386_BUS_MEMIO_H_) 182 if (tag == I386_BUS_SPACE_IO) 183#endif 184 return (inw(handle + offset)); 185#endif 186#if defined(_I386_BUS_MEMIO_H_) 187 return (*(volatile u_int16_t *)(handle + offset)); 188#endif 189} 190 191static __inline u_int32_t 192bus_space_read_4(bus_space_tag_t tag, bus_space_handle_t handle, 193 bus_size_t offset) 194{ 195#if defined(_I386_BUS_PIO_H_) 196#if defined(_I386_BUS_MEMIO_H_) 197 if (tag == I386_BUS_SPACE_IO) 198#endif 199 return (inl(handle + offset)); 200#endif 201#if defined(_I386_BUS_MEMIO_H_) 202 return (*(volatile u_int32_t *)(handle + offset)); 203#endif 204} 205 206#if 0 /* Cause a link error for bus_space_read_8 */ 207#define bus_space_read_8(t, h, o) !!! bus_space_read_8 unimplemented !!! 208#endif 209 210/* 211 * Read `count' 1, 2, 4, or 8 byte quantities from bus space 212 * described by tag/handle/offset and copy into buffer provided. 213 */ 214static __inline void bus_space_read_multi_1(bus_space_tag_t tag, 215 bus_space_handle_t bsh, 216 bus_size_t offset, u_int8_t *addr, 217 size_t count); 218 219static __inline void bus_space_read_multi_2(bus_space_tag_t tag, 220 bus_space_handle_t bsh, 221 bus_size_t offset, u_int16_t *addr, 222 size_t count); 223 224static __inline void bus_space_read_multi_4(bus_space_tag_t tag, 225 bus_space_handle_t bsh, 226 bus_size_t offset, u_int32_t *addr, 227 size_t count); 228 229static __inline void 230bus_space_read_multi_1(bus_space_tag_t tag, bus_space_handle_t bsh, 231 bus_size_t offset, u_int8_t *addr, size_t count) 232{ 233#if defined(_I386_BUS_PIO_H_) 234#if defined(_I386_BUS_MEMIO_H_) 235 if (tag == I386_BUS_SPACE_IO) 236#endif 237 insb(bsh + offset, addr, count); 238#endif 239#if defined(_I386_BUS_MEMIO_H_) 240#if defined(_I386_BUS_PIO_H_) 241 else 242#endif 243 { 244 int __x __asm__("%eax"); 245 __asm __volatile(" 246 cld ; 247 1: movb (%1),%%al ; 248 stosb ; 249 loop 1b" : 250 "=&a" (__x) : 251 "r" (bsh + offset), "D" (addr), "c" (count) : 252 "%edi", "%ecx", "memory"); 253 } 254#endif 255} 256 257static __inline void 258bus_space_read_multi_2(bus_space_tag_t tag, bus_space_handle_t bsh, 259 bus_size_t offset, u_int16_t *addr, size_t count) 260{ 261#if defined(_I386_BUS_PIO_H_) 262#if defined(_I386_BUS_MEMIO_H_) 263 if (tag == I386_BUS_SPACE_IO) 264#endif 265 insw(bsh + offset, addr, count); 266#endif 267#if defined(_I386_BUS_MEMIO_H_) 268#if defined(_I386_BUS_PIO_H_) 269 else 270#endif 271 { 272 int __x __asm__("%eax"); 273 __asm __volatile(" 274 cld ; 275 1: movw (%1),%%ax ; 276 stosw ; 277 loop 1b" : 278 "=&a" (__x) : 279 "r" (bsh + offset), "D" (addr), "c" (count) : 280 "%edi", "%ecx", "memory"); 281 } 282#endif 283} 284 285static __inline void 286bus_space_read_multi_4(bus_space_tag_t tag, bus_space_handle_t bsh, 287 bus_size_t offset, u_int32_t *addr, size_t count) 288{ 289#if defined(_I386_BUS_PIO_H_) 290#if defined(_I386_BUS_MEMIO_H_) 291 if (tag == I386_BUS_SPACE_IO) 292#endif 293 insl(bsh + offset, addr, count); 294#endif 295#if defined(_I386_BUS_MEMIO_H_) 296#if defined(_I386_BUS_PIO_H_) 297 else 298#endif 299 { 300 int __x __asm__("%eax"); 301 __asm __volatile(" 302 cld ; 303 1: movl (%1),%%eax ; 304 stosl ; 305 loop 1b" : 306 "=&a" (__x) : 307 "r" (bsh + offset), "D" (addr), "c" (count) : 308 "%edi", "%ecx", "memory"); 309 } 310#endif 311} 312 313#if 0 /* Cause a link error for bus_space_read_multi_8 */ 314#define bus_space_read_multi_8 !!! bus_space_read_multi_8 unimplemented !!! 315#endif 316 317/* 318 * Read `count' 1, 2, 4, or 8 byte quantities from bus space 319 * described by tag/handle and starting at `offset' and copy into 320 * buffer provided. 321 */ 322static __inline void bus_space_read_region_1(bus_space_tag_t tag, 323 bus_space_handle_t bsh, 324 bus_size_t offset, u_int8_t *addr, 325 size_t count); 326 327static __inline void bus_space_read_region_2(bus_space_tag_t tag, 328 bus_space_handle_t bsh, 329 bus_size_t offset, u_int16_t *addr, 330 size_t count); 331 332static __inline void bus_space_read_region_4(bus_space_tag_t tag, 333 bus_space_handle_t bsh, 334 bus_size_t offset, u_int32_t *addr, 335 size_t count); 336 337 338static __inline void 339bus_space_read_region_1(bus_space_tag_t tag, bus_space_handle_t bsh, 340 bus_size_t offset, u_int8_t *addr, size_t count) 341{ 342#if defined(_I386_BUS_PIO_H_) 343#if defined(_I386_BUS_MEMIO_H_) 344 if (tag == I386_BUS_SPACE_IO) 345#endif 346 { 347 int __x __asm__("%eax"); 348 __asm __volatile(" 349 cld ; 350 1: inb %w1,%%al ; 351 stosb ; 352 incl %1 ; 353 loop 1b" : 354 "=&a" (__x) : 355 "d" (bsh + offset), "D" (addr), "c" (count) : 356 "%edx", "%edi", "%ecx", "memory"); 357 } 358#endif 359#if defined(_I386_BUS_MEMIO_H_) 360#if defined(_I386_BUS_PIO_H_) 361 else 362#endif 363 { 364 __asm __volatile(" 365 cld ; 366 repne ; 367 movsb" : 368 : 369 "S" (bsh + offset), "D" (addr), "c" (count) : 370 "%esi", "%edi", "%ecx", "memory"); 371 } 372#endif 373} 374 375static __inline void 376bus_space_read_region_2(bus_space_tag_t tag, bus_space_handle_t bsh, 377 bus_size_t offset, u_int16_t *addr, size_t count) 378{ 379#if defined(_I386_BUS_PIO_H_) 380#if defined(_I386_BUS_MEMIO_H_) 381 if (tag == I386_BUS_SPACE_IO) 382#endif 383 { 384 int __x __asm__("%eax"); 385 __asm __volatile(" 386 cld ; 387 1: inw %w1,%%ax ; 388 stosw ; 389 addl $2,%1 ; 390 loop 1b" : 391 "=&a" (__x) : 392 "d" (bsh + offset), "D" (addr), "c" (count) : 393 "%edx", "%edi", "%ecx", "memory"); 394 } 395#endif 396#if defined(_I386_BUS_MEMIO_H_) 397#if defined(_I386_BUS_PIO_H_) 398 else 399#endif 400 { 401 __asm __volatile(" 402 cld ; 403 repne ; 404 movsw" : 405 : 406 "S" (bsh + offset), "D" (addr), "c" (count) : 407 "%esi", "%edi", "%ecx", "memory"); 408 } 409#endif 410} 411 412static __inline void 413bus_space_read_region_4(bus_space_tag_t tag, bus_space_handle_t bsh, 414 bus_size_t offset, u_int32_t *addr, size_t count) 415{ 416#if defined(_I386_BUS_PIO_H_) 417#if defined(_I386_BUS_MEMIO_H_) 418 if (tag == I386_BUS_SPACE_IO) 419#endif 420 { 421 int __x __asm__("%eax"); 422 __asm __volatile(" 423 cld ; 424 1: inl %w1,%%eax ; 425 stosl ; 426 addl $4,%1 ; 427 loop 1b" : 428 "=&a" (__x) : 429 "d" (bsh + offset), "D" (addr), "c" (count) : 430 "%edx", "%edi", "%ecx", "memory"); 431 } 432#endif 433#if defined(_I386_BUS_MEMIO_H_) 434#if defined(_I386_BUS_PIO_H_) 435 else 436#endif 437 { 438 __asm __volatile(" 439 cld ; 440 repne ; 441 movsl" : 442 : 443 "S" (bsh + offset), "D" (addr), "c" (count) : 444 "%esi", "%edi", "%ecx", "memory"); 445 } 446#endif 447} 448 449#if 0 /* Cause a link error for bus_space_read_region_8 */ 450#define bus_space_read_region_8 !!! bus_space_read_region_8 unimplemented !!! 451#endif 452 453/* 454 * Write the 1, 2, 4, or 8 byte value `value' to bus space 455 * described by tag/handle/offset. 456 */ 457 458static __inline void bus_space_write_1(bus_space_tag_t tag, 459 bus_space_handle_t bsh, 460 bus_size_t offset, u_int8_t value); 461 462static __inline void bus_space_write_2(bus_space_tag_t tag, 463 bus_space_handle_t bsh, 464 bus_size_t offset, u_int16_t value); 465 466static __inline void bus_space_write_4(bus_space_tag_t tag, 467 bus_space_handle_t bsh, 468 bus_size_t offset, u_int32_t value); 469 470static __inline void 471bus_space_write_1(bus_space_tag_t tag, bus_space_handle_t bsh, 472 bus_size_t offset, u_int8_t value) 473{ 474#if defined(_I386_BUS_PIO_H_) 475#if defined(_I386_BUS_MEMIO_H_) 476 if (tag == I386_BUS_SPACE_IO) 477#endif 478 outb(bsh + offset, value); 479#endif 480#if defined(_I386_BUS_MEMIO_H_) 481#if defined(_I386_BUS_PIO_H_) 482 else 483#endif 484 *(volatile u_int8_t *)(bsh + offset) = value; 485#endif 486} 487 488static __inline void 489bus_space_write_2(bus_space_tag_t tag, bus_space_handle_t bsh, 490 bus_size_t offset, u_int16_t value) 491{ 492#if defined(_I386_BUS_PIO_H_) 493#if defined(_I386_BUS_MEMIO_H_) 494 if (tag == I386_BUS_SPACE_IO) 495#endif 496 outw(bsh + offset, value); 497#endif 498#if defined(_I386_BUS_MEMIO_H_) 499#if defined(_I386_BUS_PIO_H_) 500 else 501#endif 502 *(volatile u_int16_t *)(bsh + offset) = value; 503#endif 504} 505 506static __inline void 507bus_space_write_4(bus_space_tag_t tag, bus_space_handle_t bsh, 508 bus_size_t offset, u_int32_t value) 509{ 510#if defined(_I386_BUS_PIO_H_) 511#if defined(_I386_BUS_MEMIO_H_) 512 if (tag == I386_BUS_SPACE_IO) 513#endif 514 outl(bsh + offset, value); 515#endif 516#if defined(_I386_BUS_MEMIO_H_) 517#if defined(_I386_BUS_PIO_H_) 518 else 519#endif 520 *(volatile u_int32_t *)(bsh + offset) = value; 521#endif 522} 523 524#if 0 /* Cause a link error for bus_space_write_8 */ 525#define bus_space_write_8 !!! bus_space_write_8 not implemented !!! 526#endif 527 528/* 529 * Write `count' 1, 2, 4, or 8 byte quantities from the buffer 530 * provided to bus space described by tag/handle/offset. 531 */ 532 533static __inline void bus_space_write_multi_1(bus_space_tag_t tag, 534 bus_space_handle_t bsh, 535 bus_size_t offset, 536 const u_int8_t *addr, 537 size_t count); 538static __inline void bus_space_write_multi_2(bus_space_tag_t tag, 539 bus_space_handle_t bsh, 540 bus_size_t offset, 541 const u_int16_t *addr, 542 size_t count); 543 544static __inline void bus_space_write_multi_4(bus_space_tag_t tag, 545 bus_space_handle_t bsh, 546 bus_size_t offset, 547 const u_int32_t *addr, 548 size_t count); 549 550static __inline void 551bus_space_write_multi_1(bus_space_tag_t tag, bus_space_handle_t bsh, 552 bus_size_t offset, const u_int8_t *addr, size_t count) 553{ 554#if defined(_I386_BUS_PIO_H_) 555#if defined(_I386_BUS_MEMIO_H_) 556 if (tag == I386_BUS_SPACE_IO) 557#endif 558 outsb(bsh + offset, addr, count); 559#endif 560#if defined(_I386_BUS_MEMIO_H_) 561#if defined(_I386_BUS_PIO_H_) 562 else 563#endif 564 { 565 int __x __asm__("%eax"); 566 __asm __volatile(" 567 cld ; 568 1: lodsb ; 569 movb %%al,(%1) ; 570 loop 1b" : 571 "=&a" (__x) : 572 "r" (bsh + offset), "S" (addr), "c" (count) : 573 "%esi", "%ecx"); 574 } 575#endif 576} 577 578static __inline void 579bus_space_write_multi_2(bus_space_tag_t tag, bus_space_handle_t bsh, 580 bus_size_t offset, const u_int16_t *addr, size_t count) 581{ 582#if defined(_I386_BUS_PIO_H_) 583#if defined(_I386_BUS_MEMIO_H_) 584 if (tag == I386_BUS_SPACE_IO) 585#endif 586 outsw(bsh + offset, addr, count); 587#endif 588#if defined(_I386_BUS_MEMIO_H_) 589#if defined(_I386_BUS_PIO_H_) 590 else 591#endif 592 { 593 int __x __asm__("%eax"); 594 __asm __volatile(" 595 cld ; 596 1: lodsw ; 597 movw %%ax,(%1) ; 598 loop 1b" : 599 "=&a" (__x) : 600 "r" (bsh + offset), "S" (addr), "c" (count) : 601 "%esi", "%ecx"); 602 } 603#endif 604} 605 606static __inline void 607bus_space_write_multi_4(bus_space_tag_t tag, bus_space_handle_t bsh, 608 bus_size_t offset, const u_int32_t *addr, size_t count) 609{ 610#if defined(_I386_BUS_PIO_H_) 611#if defined(_I386_BUS_MEMIO_H_) 612 if (tag == I386_BUS_SPACE_IO) 613#endif 614 outsl(bsh + offset, addr, count); 615#endif 616#if defined(_I386_BUS_MEMIO_H_) 617#if defined(_I386_BUS_PIO_H_) 618 else 619#endif 620 { 621 int __x __asm__("%eax"); 622 __asm __volatile(" 623 cld ; 624 1: lodsl ; 625 movl %%eax,(%1) ; 626 loop 1b" : 627 "=&a" (__x) : 628 "r" (bsh + offset), "S" (addr), "c" (count) : 629 "%esi", "%ecx"); 630 } 631#endif 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 644static __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); 649static __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); 654static __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 660static __inline void 661bus_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#if defined(_I386_BUS_PIO_H_) 665#if defined(_I386_BUS_MEMIO_H_) 666 if (tag == I386_BUS_SPACE_IO) 667#endif 668 { 669 int __x __asm__("%eax"); 670 __asm __volatile(" 671 cld ; 672 1: lodsb ; 673 outb %%al,%w1 ; 674 incl %1 ; 675 loop 1b" : 676 "=&a" (__x) : 677 "d" (bsh + offset), "S" (addr), "c" (count) : 678 "%edx", "%esi", "%ecx", "memory"); 679 } 680#endif 681#if defined(_I386_BUS_MEMIO_H_) 682#if defined(_I386_BUS_PIO_H_) 683 else 684#endif 685 { 686 __asm __volatile(" 687 cld ; 688 repne ; 689 movsb" : 690 : 691 "D" (bsh + offset), "S" (addr), "c" (count) : 692 "%edi", "%esi", "%ecx", "memory"); 693 } 694#endif 695} 696 697static __inline void 698bus_space_write_region_2(bus_space_tag_t tag, bus_space_handle_t bsh, 699 bus_size_t offset, const u_int16_t *addr, size_t count) 700{ 701#if defined(_I386_BUS_PIO_H_) 702#if defined(_I386_BUS_MEMIO_H_) 703 if (tag == I386_BUS_SPACE_IO) 704#endif 705 { 706 int __x __asm__("%eax"); 707 __asm __volatile(" 708 cld ; 709 1: lodsw ; 710 outw %%ax,%w1 ; 711 addl $2,%1 ; 712 loop 1b" : 713 "=&a" (__x) : 714 "d" (bsh + offset), "S" (addr), "c" (count) : 715 "%edx", "%esi", "%ecx", "memory"); 716 } 717#endif 718#if defined(_I386_BUS_MEMIO_H_) 719#if defined(_I386_BUS_PIO_H_) 720 else 721#endif 722 { 723 __asm __volatile(" 724 cld ; 725 repne ; 726 movsw" : 727 : 728 "D" (bsh + offset), "S" (addr), "c" (count) : 729 "%edi", "%esi", "%ecx", "memory"); 730 } 731#endif 732} 733 734static __inline void 735bus_space_write_region_4(bus_space_tag_t tag, bus_space_handle_t bsh, 736 bus_size_t offset, const u_int32_t *addr, size_t count) 737{ 738#if defined(_I386_BUS_PIO_H_) 739#if defined(_I386_BUS_MEMIO_H_) 740 if (tag == I386_BUS_SPACE_IO) 741#endif 742 { 743 int __x __asm__("%eax"); 744 __asm __volatile(" 745 cld ; 746 1: lodsl ; 747 outl %%eax,%w1 ; 748 addl $4,%1 ; 749 loop 1b" : 750 "=&a" (__x) : 751 "d" (bsh + offset), "S" (addr), "c" (count) : 752 "%edx", "%esi", "%ecx", "memory"); 753 } 754#endif 755#if defined(_I386_BUS_MEMIO_H_) 756#if defined(_I386_BUS_PIO_H_) 757 else 758#endif 759 { 760 __asm __volatile(" 761 cld ; 762 repne ; 763 movsl" : 764 : 765 "D" (bsh + offset), "S" (addr), "c" (count) : 766 "%edi", "%esi", "%ecx", "memory"); 767 } 768#endif 769} 770 771#if 0 /* Cause a link error for bus_space_write_region_8 */ 772#define bus_space_write_region_8 \ 773 !!! bus_space_write_region_8 unimplemented !!! 774#endif 775 776/* 777 * Write the 1, 2, 4, or 8 byte value `val' to bus space described 778 * by tag/handle/offset `count' times. 779 */ 780 781static __inline void bus_space_set_multi_1(bus_space_tag_t tag, 782 bus_space_handle_t bsh, 783 bus_size_t offset, 784 u_int8_t value, size_t count); 785static __inline void bus_space_set_multi_2(bus_space_tag_t tag, 786 bus_space_handle_t bsh, 787 bus_size_t offset, 788 u_int16_t value, size_t count); 789static __inline void bus_space_set_multi_4(bus_space_tag_t tag, 790 bus_space_handle_t bsh, 791 bus_size_t offset, 792 u_int32_t value, size_t count); 793 794static __inline void 795bus_space_set_multi_1(bus_space_tag_t tag, bus_space_handle_t bsh, 796 bus_size_t offset, u_int8_t value, size_t count) 797{ 798 bus_addr_t addr = bsh + offset; 799 800#if defined(_I386_BUS_PIO_H_) 801#if defined(_I386_BUS_MEMIO_H_) 802 if (tag == I386_BUS_SPACE_IO) 803#endif 804 while (count--) 805 outb(addr, value); 806#endif 807#if defined(_I386_BUS_MEMIO_H_) 808#if defined(_I386_BUS_PIO_H_) 809 else 810#endif 811 while (count--) 812 *(volatile u_int8_t *)(addr) = value; 813#endif 814} 815 816static __inline void 817bus_space_set_multi_2(bus_space_tag_t tag, bus_space_handle_t bsh, 818 bus_size_t offset, u_int16_t value, size_t count) 819{ 820 bus_addr_t addr = bsh + offset; 821 822#if defined(_I386_BUS_PIO_H_) 823#if defined(_I386_BUS_MEMIO_H_) 824 if (tag == I386_BUS_SPACE_IO) 825#endif 826 while (count--) 827 outw(addr, value); 828#endif 829#if defined(_I386_BUS_MEMIO_H_) 830#if defined(_I386_BUS_PIO_H_) 831 else 832#endif 833 while (count--) 834 *(volatile u_int16_t *)(addr) = value; 835#endif 836} 837 838static __inline void 839bus_space_set_multi_4(bus_space_tag_t tag, bus_space_handle_t bsh, 840 bus_size_t offset, u_int32_t value, size_t count) 841{ 842 bus_addr_t addr = bsh + offset; 843 844#if defined(_I386_BUS_PIO_H_) 845#if defined(_I386_BUS_MEMIO_H_) 846 if (tag == I386_BUS_SPACE_IO) 847#endif 848 while (count--) 849 outl(addr, value); 850#endif 851#if defined(_I386_BUS_MEMIO_H_) 852#if defined(_I386_BUS_PIO_H_) 853 else 854#endif 855 while (count--) 856 *(volatile u_int32_t *)(addr) = value; 857#endif 858} 859 860#if 0 /* Cause a link error for bus_space_set_multi_8 */ 861#define bus_space_set_multi_8 !!! bus_space_set_multi_8 unimplemented !!! 862#endif 863 864/* 865 * Write `count' 1, 2, 4, or 8 byte value `val' to bus space described 866 * by tag/handle starting at `offset'. 867 */ 868 869static __inline void bus_space_set_region_1(bus_space_tag_t tag, 870 bus_space_handle_t bsh, 871 bus_size_t offset, u_int8_t value, 872 size_t count); 873static __inline void bus_space_set_region_2(bus_space_tag_t tag, 874 bus_space_handle_t bsh, 875 bus_size_t offset, u_int16_t value, 876 size_t count); 877static __inline void bus_space_set_region_4(bus_space_tag_t tag, 878 bus_space_handle_t bsh, 879 bus_size_t offset, u_int32_t value, 880 size_t count); 881 882static __inline void 883bus_space_set_region_1(bus_space_tag_t tag, bus_space_handle_t bsh, 884 bus_size_t offset, u_int8_t value, size_t count) 885{ 886 bus_addr_t addr = bsh + offset; 887 888#if defined(_I386_BUS_PIO_H_) 889#if defined(_I386_BUS_MEMIO_H_) 890 if (tag == I386_BUS_SPACE_IO) 891#endif 892 for (; count != 0; count--, addr++) 893 outb(addr, value); 894#endif 895#if defined(_I386_BUS_MEMIO_H_) 896#if defined(_I386_BUS_PIO_H_) 897 else 898#endif 899 for (; count != 0; count--, addr++) 900 *(volatile u_int8_t *)(addr) = value; 901#endif 902} 903 904static __inline void 905bus_space_set_region_2(bus_space_tag_t tag, bus_space_handle_t bsh, 906 bus_size_t offset, u_int16_t value, size_t count) 907{ 908 bus_addr_t addr = bsh + offset; 909 910#if defined(_I386_BUS_PIO_H_) 911#if defined(_I386_BUS_MEMIO_H_) 912 if (tag == I386_BUS_SPACE_IO) 913#endif 914 for (; count != 0; count--, addr += 2) 915 outw(addr, value); 916#endif 917#if defined(_I386_BUS_MEMIO_H_) 918#if defined(_I386_BUS_PIO_H_) 919 else 920#endif 921 for (; count != 0; count--, addr += 2) 922 *(volatile u_int16_t *)(addr) = value; 923#endif 924} 925 926static __inline void 927bus_space_set_region_4(bus_space_tag_t tag, bus_space_handle_t bsh, 928 bus_size_t offset, u_int32_t value, size_t count) 929{ 930 bus_addr_t addr = bsh + offset; 931 932#if defined(_I386_BUS_PIO_H_) 933#if defined(_I386_BUS_MEMIO_H_) 934 if (tag == I386_BUS_SPACE_IO) 935#endif 936 for (; count != 0; count--, addr += 4) 937 outl(addr, value); 938#endif 939#if defined(_I386_BUS_MEMIO_H_) 940#if defined(_I386_BUS_PIO_H_) 941 else 942#endif 943 for (; count != 0; count--, addr += 4) 944 *(volatile u_int32_t *)(addr) = value; 945#endif 946} 947 948#if 0 /* Cause a link error for bus_space_set_region_8 */ 949#define bus_space_set_region_8 !!! bus_space_set_region_8 unimplemented !!! 950#endif 951 952/* 953 * Copy `count' 1, 2, 4, or 8 byte values from bus space starting 954 * at tag/bsh1/off1 to bus space starting at tag/bsh2/off2. 955 */ 956 957static __inline void bus_space_copy_region_1(bus_space_tag_t tag, 958 bus_space_handle_t bsh1, 959 bus_size_t off1, 960 bus_space_handle_t bsh2, 961 bus_size_t off2, size_t count); 962 963static __inline void bus_space_copy_region_2(bus_space_tag_t tag, 964 bus_space_handle_t bsh1, 965 bus_size_t off1, 966 bus_space_handle_t bsh2, 967 bus_size_t off2, size_t count); 968 969static __inline void bus_space_copy_region_4(bus_space_tag_t tag, 970 bus_space_handle_t bsh1, 971 bus_size_t off1, 972 bus_space_handle_t bsh2, 973 bus_size_t off2, size_t count); 974 975static __inline void 976bus_space_copy_region_1(bus_space_tag_t tag, bus_space_handle_t bsh1, 977 bus_size_t off1, bus_space_handle_t bsh2, 978 bus_size_t off2, size_t count) 979{ 980 bus_addr_t addr1 = bsh1 + off1; 981 bus_addr_t addr2 = bsh2 + off2; 982 983#if defined(_I386_BUS_PIO_H_) 984#if defined(_I386_BUS_MEMIO_H_) 985 if (tag == I386_BUS_SPACE_IO) 986#endif 987 { 988 if (addr1 >= addr2) { 989 /* src after dest: copy forward */ 990 for (; count != 0; count--, addr1++, addr2++) 991 outb(addr2, inb(addr1)); 992 } else { 993 /* dest after src: copy backwards */ 994 for (addr1 += (count - 1), addr2 += (count - 1); 995 count != 0; count--, addr1--, addr2--) 996 outb(addr2, inb(addr1)); 997 } 998 } 999#endif 1000#if defined(_I386_BUS_MEMIO_H_) 1001#if defined(_I386_BUS_PIO_H_) 1002 else 1003#endif 1004 { 1005 if (addr1 >= addr2) { 1006 /* src after dest: copy forward */ 1007 for (; count != 0; count--, addr1++, addr2++) 1008 *(volatile u_int8_t *)(addr2) = 1009 *(volatile u_int8_t *)(addr1); 1010 } else { 1011 /* dest after src: copy backwards */ 1012 for (addr1 += (count - 1), addr2 += (count - 1); 1013 count != 0; count--, addr1--, addr2--) 1014 *(volatile u_int8_t *)(addr2) = 1015 *(volatile u_int8_t *)(addr1); 1016 } 1017 } 1018#endif 1019} 1020 1021static __inline void 1022bus_space_copy_region_2(bus_space_tag_t tag, bus_space_handle_t bsh1, 1023 bus_size_t off1, bus_space_handle_t bsh2, 1024 bus_size_t off2, size_t count) 1025{ 1026 bus_addr_t addr1 = bsh1 + off1; 1027 bus_addr_t addr2 = bsh2 + off2; 1028 1029#if defined(_I386_BUS_PIO_H_) 1030#if defined(_I386_BUS_MEMIO_H_) 1031 if (tag == I386_BUS_SPACE_IO) 1032#endif 1033 { 1034 if (addr1 >= addr2) { 1035 /* src after dest: copy forward */ 1036 for (; count != 0; count--, addr1 += 2, addr2 += 2) 1037 outw(addr2, inw(addr1)); 1038 } else { 1039 /* dest after src: copy backwards */ 1040 for (addr1 += 2 * (count - 1), addr2 += 2 * (count - 1); 1041 count != 0; count--, addr1 -= 2, addr2 -= 2) 1042 outw(addr2, inw(addr1)); 1043 } 1044 } 1045#endif 1046#if defined(_I386_BUS_MEMIO_H_) 1047#if defined(_I386_BUS_PIO_H_) 1048 else 1049#endif 1050 { 1051 if (addr1 >= addr2) { 1052 /* src after dest: copy forward */ 1053 for (; count != 0; count--, addr1 += 2, addr2 += 2) 1054 *(volatile u_int16_t *)(addr2) = 1055 *(volatile u_int16_t *)(addr1); 1056 } else { 1057 /* dest after src: copy backwards */ 1058 for (addr1 += 2 * (count - 1), addr2 += 2 * (count - 1); 1059 count != 0; count--, addr1 -= 2, addr2 -= 2) 1060 *(volatile u_int16_t *)(addr2) = 1061 *(volatile u_int16_t *)(addr1); 1062 } 1063 } 1064#endif 1065} 1066 1067static __inline void 1068bus_space_copy_region_4(bus_space_tag_t tag, bus_space_handle_t bsh1, 1069 bus_size_t off1, bus_space_handle_t bsh2, 1070 bus_size_t off2, size_t count) 1071{ 1072 bus_addr_t addr1 = bsh1 + off1; 1073 bus_addr_t addr2 = bsh2 + off2; 1074 1075#if defined(_I386_BUS_PIO_H_) 1076#if defined(_I386_BUS_MEMIO_H_) 1077 if (tag == I386_BUS_SPACE_IO) 1078#endif 1079 { 1080 if (addr1 >= addr2) { 1081 /* src after dest: copy forward */ 1082 for (; count != 0; count--, addr1 += 4, addr2 += 4) 1083 outl(addr2, inl(addr1)); 1084 } else { 1085 /* dest after src: copy backwards */ 1086 for (addr1 += 4 * (count - 1), addr2 += 4 * (count - 1); 1087 count != 0; count--, addr1 -= 4, addr2 -= 4) 1088 outl(addr2, inl(addr1)); 1089 } 1090 } 1091#endif 1092#if defined(_I386_BUS_MEMIO_H_) 1093#if defined(_I386_BUS_PIO_H_) 1094 else 1095#endif 1096 { 1097 if (addr1 >= addr2) { 1098 /* src after dest: copy forward */ 1099 for (; count != 0; count--, addr1 += 4, addr2 += 4) 1100 *(volatile u_int32_t *)(addr2) = 1101 *(volatile u_int32_t *)(addr1); 1102 } else { 1103 /* dest after src: copy backwards */ 1104 for (addr1 += 4 * (count - 1), addr2 += 4 * (count - 1); 1105 count != 0; count--, addr1 -= 4, addr2 -= 4) 1106 *(volatile u_int32_t *)(addr2) = 1107 *(volatile u_int32_t *)(addr1); 1108 } 1109 } 1110#endif 1111} 1112 1113#endif /* defined(_I386_BUS_PIO_H_) || defined(_I386_MEM_IO_H_) */ 1114 1115#if 0 /* Cause a link error for bus_space_copy_8 */ 1116#define bus_space_copy_region_8 !!! bus_space_copy_region_8 unimplemented !!! 1117#endif 1118 1119/* 1120 * Bus read/write barrier methods. 1121 * 1122 * void bus_space_barrier(bus_space_tag_t tag, bus_space_handle_t bsh, 1123 * bus_size_t offset, bus_size_t len, int flags); 1124 * 1125 * Note: the i386 does not currently require barriers, but we must 1126 * provide the flags to MI code. 1127 */ 1128#define bus_space_barrier(t, h, o, l, f) \ 1129 ((void)((void)(t), (void)(h), (void)(o), (void)(l), (void)(f))) 1130#define BUS_SPACE_BARRIER_READ 0x01 /* force read barrier */ 1131#define BUS_SPACE_BARRIER_WRITE 0x02 /* force write barrier */ 1132 1133/* 1134 * Flags used in various bus DMA methods. 1135 */ 1136#define BUS_DMA_WAITOK 0x00 /* safe to sleep (pseudo-flag) */ 1137#define BUS_DMA_NOWAIT 0x01 /* not safe to sleep */ 1138#define BUS_DMA_ALLOCNOW 0x02 /* perform resource allocation now */ 1139#define BUS_DMAMEM_NOSYNC 0x04 /* map memory to not require sync */ 1140#define BUS_DMA_BUS1 0x10 /* placeholders for bus functions... */ 1141#define BUS_DMA_BUS2 0x20 1142#define BUS_DMA_BUS3 0x40 1143#define BUS_DMA_BUS4 0x80 1144 1145/* Forwards needed by prototypes below. */ 1146struct mbuf; 1147struct uio; 1148 1149/* 1150 * bus_dmasync_op_t 1151 * 1152 * Operations performed by bus_dmamap_sync(). 1153 */ 1154typedef enum { 1155 BUS_DMASYNC_PREREAD, 1156 BUS_DMASYNC_POSTREAD, 1157 BUS_DMASYNC_PREWRITE, 1158 BUS_DMASYNC_POSTWRITE, 1159} bus_dmasync_op_t; 1160 1161/* 1162 * bus_dma_tag_t 1163 * 1164 * A machine-dependent opaque type describing the characteristics 1165 * of how to perform DMA mappings. This structure encapsultes 1166 * information concerning address and alignment restrictions, number 1167 * of S/G segments, amount of data per S/G segment, etc. 1168 */ 1169typedef struct bus_dma_tag *bus_dma_tag_t; 1170 1171/* 1172 * bus_dmamap_t 1173 * 1174 * DMA mapping instance information. 1175 */ 1176typedef struct bus_dmamap *bus_dmamap_t; 1177 1178/* 1179 * bus_dma_segment_t 1180 * 1181 * Describes a single contiguous DMA transaction. Values 1182 * are suitable for programming into DMA registers. 1183 */ 1184typedef struct bus_dma_segment { 1185 bus_addr_t ds_addr; /* DMA address */ 1186 bus_size_t ds_len; /* length of transfer */ 1187} bus_dma_segment_t; 1188 1189/* 1190 * A function that returns 1 if the address cannot be accessed by 1191 * a device and 0 if it can be. 1192 */ 1193typedef int bus_dma_filter_t(void *, bus_addr_t); 1194 1195/* 1196 * Allocate a device specific dma_tag encapsulating the constraints of 1197 * the parent tag in addition to other restrictions specified: 1198 * 1199 * boundary: Boundary that segments cannot cross. 1200 * lowaddr: Low restricted address that cannot appear in a mapping. 1201 * highaddr: High restricted address that cannot appear in a mapping. 1202 * filtfunc: An optional function to further test if an address 1203 * within the range of lowaddr and highaddr cannot appear 1204 * in a mapping. 1205 * filtfuncarg: An argument that will be passed to filtfunc in addition 1206 * to the address to test. 1207 * flags: Bus DMA flags. 1208 * dmat: A pointer to set to a valid dma tag should the return 1209 * value of this function indicate success. 1210 */ 1211int bus_dma_tag_create(bus_dma_tag_t parent, bus_size_t boundary, 1212 bus_addr_t lowaddr, bus_addr_t highaddr, 1213 bus_dma_filter_t *filtfunc, void *filtfuncarg, 1214 bus_size_t maxsize, int nsegments, bus_size_t maxsegsz, 1215 int flags, bus_dma_tag_t *dmat); 1216 1217int bus_dma_tag_destroy(bus_dma_tag_t dmat); 1218 1219/* 1220 * Allocate a handle for mapping from kva/uva/physical 1221 * address space into bus device space. 1222 * 1223 * maxsize: Maximum mapping size supported by this handle. 1224 * nsegments: Number of discontinuities allowed in the map. 1225 * maxsegsz: Maximum size of a segment in the map. 1226 */ 1227int bus_dmamap_create(bus_dma_tag_t dmat, int flags, bus_dmamap_t *mapp); 1228 1229/* 1230 * Destroy a handle for mapping from kva/uva/physical 1231 * address space into bus device space. 1232 */ 1233int bus_dmamap_destroy(bus_dma_tag_t dmat, bus_dmamap_t map); 1234 1235/* 1236 * A function that processes a successfully loaded dma map or an error 1237 * from a delayed load map. 1238 */ 1239typedef void bus_dmamap_callback_t(void *, bus_dma_segment_t *, int, int); 1240 1241/* 1242 * Map the buffer buf into bus space using the dmamap map. 1243 */ 1244int bus_dmamap_load(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf, 1245 bus_size_t buflen, bus_dmamap_callback_t *callback, 1246 void *callback_arg, int flags); 1247 1248/* 1249 * Perform a syncronization operation on the given map. 1250 */ 1251void _bus_dmamap_sync(bus_dma_tag_t, bus_dmamap_t, bus_dmasync_op_t); 1252#define bus_dmamap_sync(dmat, dmamap, op) \ 1253 if ((dmamap) != NULL) \ 1254 _bus_dmamap_sync(dmat, dmamap, op) 1255 1256/* 1257 * Release the mapping held by map. 1258 */ 1259void _bus_dmamap_unload(bus_dma_tag_t dmat, bus_dmamap_t map); 1260#define bus_dmamap_unload(dmat, dmamap) \ 1261 if ((dmamap) != NULL) \ 1262 _bus_dmamap_unload(dmat, dmamap) 1263 1264#endif /* _I386_BUS_H_ */ 1265