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