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