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