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