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