xref: /freebsd/sys/x86/include/bus.h (revision ce6a89e27cd190313be39bb479880aeda4778436)
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_ */
1097