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