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