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