xref: /freebsd/sys/x86/include/bus.h (revision 839f11a4fe18e4ae2dd930766b551fa67e354735)
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_UNRESTRICTED	(~0)
134 
135 /*
136  * Map a region of device bus space into CPU virtual address space.
137  */
138 
139 static __inline int bus_space_map(bus_space_tag_t t, bus_addr_t addr,
140 				  bus_size_t size, int flags,
141 				  bus_space_handle_t *bshp);
142 
143 static __inline int
144 bus_space_map(bus_space_tag_t t __unused, bus_addr_t addr,
145 	      bus_size_t size __unused, int flags __unused,
146 	      bus_space_handle_t *bshp)
147 {
148 
149 	*bshp = addr;
150 	return (0);
151 }
152 
153 /*
154  * Unmap a region of device bus space.
155  */
156 
157 static __inline void bus_space_unmap(bus_space_tag_t t, bus_space_handle_t bsh,
158 				     bus_size_t size);
159 
160 static __inline void
161 bus_space_unmap(bus_space_tag_t t __unused, bus_space_handle_t bsh __unused,
162 		bus_size_t size __unused)
163 {
164 }
165 
166 /*
167  * Get a new handle for a subregion of an already-mapped area of bus space.
168  */
169 
170 static __inline int bus_space_subregion(bus_space_tag_t t,
171 					bus_space_handle_t bsh,
172 					bus_size_t offset, bus_size_t size,
173 					bus_space_handle_t *nbshp);
174 
175 static __inline int
176 bus_space_subregion(bus_space_tag_t t __unused, bus_space_handle_t bsh,
177 		    bus_size_t offset, bus_size_t size __unused,
178 		    bus_space_handle_t *nbshp)
179 {
180 
181 	*nbshp = bsh + offset;
182 	return (0);
183 }
184 
185 /*
186  * Allocate a region of memory that is accessible to devices in bus space.
187  */
188 
189 int	bus_space_alloc(bus_space_tag_t t, bus_addr_t rstart,
190 			bus_addr_t rend, bus_size_t size, bus_size_t align,
191 			bus_size_t boundary, int flags, bus_addr_t *addrp,
192 			bus_space_handle_t *bshp);
193 
194 /*
195  * Free a region of bus space accessible memory.
196  */
197 
198 static __inline void bus_space_free(bus_space_tag_t t, bus_space_handle_t bsh,
199 				    bus_size_t size);
200 
201 static __inline void
202 bus_space_free(bus_space_tag_t t __unused, bus_space_handle_t bsh __unused,
203 	       bus_size_t size __unused)
204 {
205 }
206 
207 
208 /*
209  * Read a 1, 2, 4, or 8 byte quantity from bus space
210  * described by tag/handle/offset.
211  */
212 static __inline u_int8_t bus_space_read_1(bus_space_tag_t tag,
213 					  bus_space_handle_t handle,
214 					  bus_size_t offset);
215 
216 static __inline u_int16_t bus_space_read_2(bus_space_tag_t tag,
217 					   bus_space_handle_t handle,
218 					   bus_size_t offset);
219 
220 static __inline u_int32_t bus_space_read_4(bus_space_tag_t tag,
221 					   bus_space_handle_t handle,
222 					   bus_size_t offset);
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 /*
255  * Read `count' 1, 2, 4, or 8 byte quantities from bus space
256  * described by tag/handle/offset and copy into buffer provided.
257  */
258 static __inline void bus_space_read_multi_1(bus_space_tag_t tag,
259 					    bus_space_handle_t bsh,
260 					    bus_size_t offset, u_int8_t *addr,
261 					    size_t count);
262 
263 static __inline void bus_space_read_multi_2(bus_space_tag_t tag,
264 					    bus_space_handle_t bsh,
265 					    bus_size_t offset, u_int16_t *addr,
266 					    size_t count);
267 
268 static __inline void bus_space_read_multi_4(bus_space_tag_t tag,
269 					    bus_space_handle_t bsh,
270 					    bus_size_t offset, u_int32_t *addr,
271 					    size_t count);
272 
273 static __inline void
274 bus_space_read_multi_1(bus_space_tag_t tag, bus_space_handle_t bsh,
275 		       bus_size_t offset, u_int8_t *addr, size_t count)
276 {
277 
278 	if (tag == X86_BUS_SPACE_IO)
279 		insb(bsh + offset, addr, count);
280 	else {
281 #ifdef __GNUCLIKE_ASM
282 		__asm __volatile("				\n\
283 			cld					\n\
284 		1:	movb (%2),%%al				\n\
285 			stosb					\n\
286 			loop 1b"				:
287 		    "=D" (addr), "=c" (count)			:
288 		    "r" (bsh + offset), "0" (addr), "1" (count)	:
289 		    "%eax", "memory");
290 #endif
291 	}
292 }
293 
294 static __inline void
295 bus_space_read_multi_2(bus_space_tag_t tag, bus_space_handle_t bsh,
296 		       bus_size_t offset, u_int16_t *addr, size_t count)
297 {
298 
299 	if (tag == X86_BUS_SPACE_IO)
300 		insw(bsh + offset, addr, count);
301 	else {
302 #ifdef __GNUCLIKE_ASM
303 		__asm __volatile("				\n\
304 			cld					\n\
305 		1:	movw (%2),%%ax				\n\
306 			stosw					\n\
307 			loop 1b"				:
308 		    "=D" (addr), "=c" (count)			:
309 		    "r" (bsh + offset), "0" (addr), "1" (count)	:
310 		    "%eax", "memory");
311 #endif
312 	}
313 }
314 
315 static __inline void
316 bus_space_read_multi_4(bus_space_tag_t tag, bus_space_handle_t bsh,
317 		       bus_size_t offset, u_int32_t *addr, size_t count)
318 {
319 
320 	if (tag == X86_BUS_SPACE_IO)
321 		insl(bsh + offset, addr, count);
322 	else {
323 #ifdef __GNUCLIKE_ASM
324 		__asm __volatile("				\n\
325 			cld					\n\
326 		1:	movl (%2),%%eax				\n\
327 			stosl					\n\
328 			loop 1b"				:
329 		    "=D" (addr), "=c" (count)			:
330 		    "r" (bsh + offset), "0" (addr), "1" (count)	:
331 		    "%eax", "memory");
332 #endif
333 	}
334 }
335 
336 /*
337  * Read `count' 1, 2, 4, or 8 byte quantities from bus space
338  * described by tag/handle and starting at `offset' and copy into
339  * buffer provided.
340  */
341 static __inline void bus_space_read_region_1(bus_space_tag_t tag,
342 					     bus_space_handle_t bsh,
343 					     bus_size_t offset, u_int8_t *addr,
344 					     size_t count);
345 
346 static __inline void bus_space_read_region_2(bus_space_tag_t tag,
347 					     bus_space_handle_t bsh,
348 					     bus_size_t offset, u_int16_t *addr,
349 					     size_t count);
350 
351 static __inline void bus_space_read_region_4(bus_space_tag_t tag,
352 					     bus_space_handle_t bsh,
353 					     bus_size_t offset, u_int32_t *addr,
354 					     size_t count);
355 
356 
357 static __inline void
358 bus_space_read_region_1(bus_space_tag_t tag, bus_space_handle_t bsh,
359 			bus_size_t offset, u_int8_t *addr, size_t count)
360 {
361 
362 	if (tag == X86_BUS_SPACE_IO) {
363 		int _port_ = bsh + offset;
364 #ifdef __GNUCLIKE_ASM
365 		__asm __volatile("				\n\
366 			cld					\n\
367 		1:	inb %w2,%%al				\n\
368 			stosb					\n\
369 			incl %2					\n\
370 			loop 1b"				:
371 		    "=D" (addr), "=c" (count), "=d" (_port_)	:
372 		    "0" (addr), "1" (count), "2" (_port_)	:
373 		    "%eax", "memory", "cc");
374 #endif
375 	} else {
376 		bus_space_handle_t _port_ = bsh + offset;
377 #ifdef __GNUCLIKE_ASM
378 		__asm __volatile("				\n\
379 			cld					\n\
380 			repne					\n\
381 			movsb"					:
382 		    "=D" (addr), "=c" (count), "=S" (_port_)	:
383 		    "0" (addr), "1" (count), "2" (_port_)	:
384 		    "memory", "cc");
385 #endif
386 	}
387 }
388 
389 static __inline void
390 bus_space_read_region_2(bus_space_tag_t tag, bus_space_handle_t bsh,
391 			bus_size_t offset, u_int16_t *addr, size_t count)
392 {
393 
394 	if (tag == X86_BUS_SPACE_IO) {
395 		int _port_ = bsh + offset;
396 #ifdef __GNUCLIKE_ASM
397 		__asm __volatile("				\n\
398 			cld					\n\
399 		1:	inw %w2,%%ax				\n\
400 			stosw					\n\
401 			addl $2,%2				\n\
402 			loop 1b"				:
403 		    "=D" (addr), "=c" (count), "=d" (_port_)	:
404 		    "0" (addr), "1" (count), "2" (_port_)	:
405 		    "%eax", "memory", "cc");
406 #endif
407 	} else {
408 		bus_space_handle_t _port_ = bsh + offset;
409 #ifdef __GNUCLIKE_ASM
410 		__asm __volatile("				\n\
411 			cld					\n\
412 			repne					\n\
413 			movsw"					:
414 		    "=D" (addr), "=c" (count), "=S" (_port_)	:
415 		    "0" (addr), "1" (count), "2" (_port_)	:
416 		    "memory", "cc");
417 #endif
418 	}
419 }
420 
421 static __inline void
422 bus_space_read_region_4(bus_space_tag_t tag, bus_space_handle_t bsh,
423 			bus_size_t offset, u_int32_t *addr, size_t count)
424 {
425 
426 	if (tag == X86_BUS_SPACE_IO) {
427 		int _port_ = bsh + offset;
428 #ifdef __GNUCLIKE_ASM
429 		__asm __volatile("				\n\
430 			cld					\n\
431 		1:	inl %w2,%%eax				\n\
432 			stosl					\n\
433 			addl $4,%2				\n\
434 			loop 1b"				:
435 		    "=D" (addr), "=c" (count), "=d" (_port_)	:
436 		    "0" (addr), "1" (count), "2" (_port_)	:
437 		    "%eax", "memory", "cc");
438 #endif
439 	} else {
440 		bus_space_handle_t _port_ = bsh + offset;
441 #ifdef __GNUCLIKE_ASM
442 		__asm __volatile("				\n\
443 			cld					\n\
444 			repne					\n\
445 			movsl"					:
446 		    "=D" (addr), "=c" (count), "=S" (_port_)	:
447 		    "0" (addr), "1" (count), "2" (_port_)	:
448 		    "memory", "cc");
449 #endif
450 	}
451 }
452 
453 /*
454  * Write the 1, 2, 4, or 8 byte value `value' to bus space
455  * described by tag/handle/offset.
456  */
457 
458 static __inline void bus_space_write_1(bus_space_tag_t tag,
459 				       bus_space_handle_t bsh,
460 				       bus_size_t offset, u_int8_t value);
461 
462 static __inline void bus_space_write_2(bus_space_tag_t tag,
463 				       bus_space_handle_t bsh,
464 				       bus_size_t offset, u_int16_t value);
465 
466 static __inline void bus_space_write_4(bus_space_tag_t tag,
467 				       bus_space_handle_t bsh,
468 				       bus_size_t offset, u_int32_t value);
469 
470 static __inline void
471 bus_space_write_1(bus_space_tag_t tag, bus_space_handle_t bsh,
472 		       bus_size_t offset, u_int8_t value)
473 {
474 
475 	if (tag == X86_BUS_SPACE_IO)
476 		outb(bsh + offset, value);
477 	else
478 		*(volatile u_int8_t *)(bsh + offset) = value;
479 }
480 
481 static __inline void
482 bus_space_write_2(bus_space_tag_t tag, bus_space_handle_t bsh,
483 		       bus_size_t offset, u_int16_t value)
484 {
485 
486 	if (tag == X86_BUS_SPACE_IO)
487 		outw(bsh + offset, value);
488 	else
489 		*(volatile u_int16_t *)(bsh + offset) = value;
490 }
491 
492 static __inline void
493 bus_space_write_4(bus_space_tag_t tag, bus_space_handle_t bsh,
494 		       bus_size_t offset, u_int32_t value)
495 {
496 
497 	if (tag == X86_BUS_SPACE_IO)
498 		outl(bsh + offset, value);
499 	else
500 		*(volatile u_int32_t *)(bsh + offset) = value;
501 }
502 
503 /*
504  * Write `count' 1, 2, 4, or 8 byte quantities from the buffer
505  * provided to bus space described by tag/handle/offset.
506  */
507 
508 static __inline void bus_space_write_multi_1(bus_space_tag_t tag,
509 					     bus_space_handle_t bsh,
510 					     bus_size_t offset,
511 					     const u_int8_t *addr,
512 					     size_t count);
513 static __inline void bus_space_write_multi_2(bus_space_tag_t tag,
514 					     bus_space_handle_t bsh,
515 					     bus_size_t offset,
516 					     const u_int16_t *addr,
517 					     size_t count);
518 
519 static __inline void bus_space_write_multi_4(bus_space_tag_t tag,
520 					     bus_space_handle_t bsh,
521 					     bus_size_t offset,
522 					     const u_int32_t *addr,
523 					     size_t count);
524 
525 static __inline void
526 bus_space_write_multi_1(bus_space_tag_t tag, bus_space_handle_t bsh,
527 			bus_size_t offset, const u_int8_t *addr, size_t count)
528 {
529 
530 	if (tag == X86_BUS_SPACE_IO)
531 		outsb(bsh + offset, addr, count);
532 	else {
533 #ifdef __GNUCLIKE_ASM
534 		__asm __volatile("				\n\
535 			cld					\n\
536 		1:	lodsb					\n\
537 			movb %%al,(%2)				\n\
538 			loop 1b"				:
539 		    "=S" (addr), "=c" (count)			:
540 		    "r" (bsh + offset), "0" (addr), "1" (count)	:
541 		    "%eax", "memory", "cc");
542 #endif
543 	}
544 }
545 
546 static __inline void
547 bus_space_write_multi_2(bus_space_tag_t tag, bus_space_handle_t bsh,
548 			bus_size_t offset, const u_int16_t *addr, size_t count)
549 {
550 
551 	if (tag == X86_BUS_SPACE_IO)
552 		outsw(bsh + offset, addr, count);
553 	else {
554 #ifdef __GNUCLIKE_ASM
555 		__asm __volatile("				\n\
556 			cld					\n\
557 		1:	lodsw					\n\
558 			movw %%ax,(%2)				\n\
559 			loop 1b"				:
560 		    "=S" (addr), "=c" (count)			:
561 		    "r" (bsh + offset), "0" (addr), "1" (count)	:
562 		    "%eax", "memory", "cc");
563 #endif
564 	}
565 }
566 
567 static __inline void
568 bus_space_write_multi_4(bus_space_tag_t tag, bus_space_handle_t bsh,
569 			bus_size_t offset, const u_int32_t *addr, size_t count)
570 {
571 
572 	if (tag == X86_BUS_SPACE_IO)
573 		outsl(bsh + offset, addr, count);
574 	else {
575 #ifdef __GNUCLIKE_ASM
576 		__asm __volatile("				\n\
577 			cld					\n\
578 		1:	lodsl					\n\
579 			movl %%eax,(%2)				\n\
580 			loop 1b"				:
581 		    "=S" (addr), "=c" (count)			:
582 		    "r" (bsh + offset), "0" (addr), "1" (count)	:
583 		    "%eax", "memory", "cc");
584 #endif
585 	}
586 }
587 
588 /*
589  * Write `count' 1, 2, 4, or 8 byte quantities from the buffer provided
590  * to bus space described by tag/handle starting at `offset'.
591  */
592 
593 static __inline void bus_space_write_region_1(bus_space_tag_t tag,
594 					      bus_space_handle_t bsh,
595 					      bus_size_t offset,
596 					      const u_int8_t *addr,
597 					      size_t count);
598 static __inline void bus_space_write_region_2(bus_space_tag_t tag,
599 					      bus_space_handle_t bsh,
600 					      bus_size_t offset,
601 					      const u_int16_t *addr,
602 					      size_t count);
603 static __inline void bus_space_write_region_4(bus_space_tag_t tag,
604 					      bus_space_handle_t bsh,
605 					      bus_size_t offset,
606 					      const u_int32_t *addr,
607 					      size_t count);
608 
609 static __inline void
610 bus_space_write_region_1(bus_space_tag_t tag, bus_space_handle_t bsh,
611 			 bus_size_t offset, const u_int8_t *addr, size_t count)
612 {
613 
614 	if (tag == X86_BUS_SPACE_IO) {
615 		int _port_ = bsh + offset;
616 #ifdef __GNUCLIKE_ASM
617 		__asm __volatile("				\n\
618 			cld					\n\
619 		1:	lodsb					\n\
620 			outb %%al,%w0				\n\
621 			incl %0					\n\
622 			loop 1b"				:
623 		    "=d" (_port_), "=S" (addr), "=c" (count)	:
624 		    "0" (_port_), "1" (addr), "2" (count)	:
625 		    "%eax", "memory", "cc");
626 #endif
627 	} else {
628 		bus_space_handle_t _port_ = bsh + offset;
629 #ifdef __GNUCLIKE_ASM
630 		__asm __volatile("				\n\
631 			cld					\n\
632 			repne					\n\
633 			movsb"					:
634 		    "=D" (_port_), "=S" (addr), "=c" (count)	:
635 		    "0" (_port_), "1" (addr), "2" (count)	:
636 		    "memory", "cc");
637 #endif
638 	}
639 }
640 
641 static __inline void
642 bus_space_write_region_2(bus_space_tag_t tag, bus_space_handle_t bsh,
643 			 bus_size_t offset, const u_int16_t *addr, size_t count)
644 {
645 
646 	if (tag == X86_BUS_SPACE_IO) {
647 		int _port_ = bsh + offset;
648 #ifdef __GNUCLIKE_ASM
649 		__asm __volatile("				\n\
650 			cld					\n\
651 		1:	lodsw					\n\
652 			outw %%ax,%w0				\n\
653 			addl $2,%0				\n\
654 			loop 1b"				:
655 		    "=d" (_port_), "=S" (addr), "=c" (count)	:
656 		    "0" (_port_), "1" (addr), "2" (count)	:
657 		    "%eax", "memory", "cc");
658 #endif
659 	} else {
660 		bus_space_handle_t _port_ = bsh + offset;
661 #ifdef __GNUCLIKE_ASM
662 		__asm __volatile("				\n\
663 			cld					\n\
664 			repne					\n\
665 			movsw"					:
666 		    "=D" (_port_), "=S" (addr), "=c" (count)	:
667 		    "0" (_port_), "1" (addr), "2" (count)	:
668 		    "memory", "cc");
669 #endif
670 	}
671 }
672 
673 static __inline void
674 bus_space_write_region_4(bus_space_tag_t tag, bus_space_handle_t bsh,
675 			 bus_size_t offset, const u_int32_t *addr, size_t count)
676 {
677 
678 	if (tag == X86_BUS_SPACE_IO) {
679 		int _port_ = bsh + offset;
680 #ifdef __GNUCLIKE_ASM
681 		__asm __volatile("				\n\
682 			cld					\n\
683 		1:	lodsl					\n\
684 			outl %%eax,%w0				\n\
685 			addl $4,%0				\n\
686 			loop 1b"				:
687 		    "=d" (_port_), "=S" (addr), "=c" (count)	:
688 		    "0" (_port_), "1" (addr), "2" (count)	:
689 		    "%eax", "memory", "cc");
690 #endif
691 	} else {
692 		bus_space_handle_t _port_ = bsh + offset;
693 #ifdef __GNUCLIKE_ASM
694 		__asm __volatile("				\n\
695 			cld					\n\
696 			repne					\n\
697 			movsl"					:
698 		    "=D" (_port_), "=S" (addr), "=c" (count)	:
699 		    "0" (_port_), "1" (addr), "2" (count)	:
700 		    "memory", "cc");
701 #endif
702 	}
703 }
704 
705 /*
706  * Write the 1, 2, 4, or 8 byte value `val' to bus space described
707  * by tag/handle/offset `count' times.
708  */
709 
710 static __inline void bus_space_set_multi_1(bus_space_tag_t tag,
711 					   bus_space_handle_t bsh,
712 					   bus_size_t offset,
713 					   u_int8_t value, size_t count);
714 static __inline void bus_space_set_multi_2(bus_space_tag_t tag,
715 					   bus_space_handle_t bsh,
716 					   bus_size_t offset,
717 					   u_int16_t value, size_t count);
718 static __inline void bus_space_set_multi_4(bus_space_tag_t tag,
719 					   bus_space_handle_t bsh,
720 					   bus_size_t offset,
721 					   u_int32_t value, size_t count);
722 
723 static __inline void
724 bus_space_set_multi_1(bus_space_tag_t tag, bus_space_handle_t bsh,
725 		      bus_size_t offset, u_int8_t value, size_t count)
726 {
727 	bus_space_handle_t addr = bsh + offset;
728 
729 	if (tag == X86_BUS_SPACE_IO)
730 		while (count--)
731 			outb(addr, value);
732 	else
733 		while (count--)
734 			*(volatile u_int8_t *)(addr) = value;
735 }
736 
737 static __inline void
738 bus_space_set_multi_2(bus_space_tag_t tag, bus_space_handle_t bsh,
739 		     bus_size_t offset, u_int16_t value, size_t count)
740 {
741 	bus_space_handle_t addr = bsh + offset;
742 
743 	if (tag == X86_BUS_SPACE_IO)
744 		while (count--)
745 			outw(addr, value);
746 	else
747 		while (count--)
748 			*(volatile u_int16_t *)(addr) = value;
749 }
750 
751 static __inline void
752 bus_space_set_multi_4(bus_space_tag_t tag, bus_space_handle_t bsh,
753 		      bus_size_t offset, u_int32_t value, size_t count)
754 {
755 	bus_space_handle_t addr = bsh + offset;
756 
757 	if (tag == X86_BUS_SPACE_IO)
758 		while (count--)
759 			outl(addr, value);
760 	else
761 		while (count--)
762 			*(volatile u_int32_t *)(addr) = value;
763 }
764 
765 /*
766  * Write `count' 1, 2, 4, or 8 byte value `val' to bus space described
767  * by tag/handle starting at `offset'.
768  */
769 
770 static __inline void bus_space_set_region_1(bus_space_tag_t tag,
771 					    bus_space_handle_t bsh,
772 					    bus_size_t offset, u_int8_t value,
773 					    size_t count);
774 static __inline void bus_space_set_region_2(bus_space_tag_t tag,
775 					    bus_space_handle_t bsh,
776 					    bus_size_t offset, u_int16_t value,
777 					    size_t count);
778 static __inline void bus_space_set_region_4(bus_space_tag_t tag,
779 					    bus_space_handle_t bsh,
780 					    bus_size_t offset, u_int32_t value,
781 					    size_t count);
782 
783 static __inline void
784 bus_space_set_region_1(bus_space_tag_t tag, bus_space_handle_t bsh,
785 		       bus_size_t offset, u_int8_t value, size_t count)
786 {
787 	bus_space_handle_t addr = bsh + offset;
788 
789 	if (tag == X86_BUS_SPACE_IO)
790 		for (; count != 0; count--, addr++)
791 			outb(addr, value);
792 	else
793 		for (; count != 0; count--, addr++)
794 			*(volatile u_int8_t *)(addr) = value;
795 }
796 
797 static __inline void
798 bus_space_set_region_2(bus_space_tag_t tag, bus_space_handle_t bsh,
799 		       bus_size_t offset, u_int16_t value, size_t count)
800 {
801 	bus_space_handle_t addr = bsh + offset;
802 
803 	if (tag == X86_BUS_SPACE_IO)
804 		for (; count != 0; count--, addr += 2)
805 			outw(addr, value);
806 	else
807 		for (; count != 0; count--, addr += 2)
808 			*(volatile u_int16_t *)(addr) = value;
809 }
810 
811 static __inline void
812 bus_space_set_region_4(bus_space_tag_t tag, bus_space_handle_t bsh,
813 		       bus_size_t offset, u_int32_t value, size_t count)
814 {
815 	bus_space_handle_t addr = bsh + offset;
816 
817 	if (tag == X86_BUS_SPACE_IO)
818 		for (; count != 0; count--, addr += 4)
819 			outl(addr, value);
820 	else
821 		for (; count != 0; count--, addr += 4)
822 			*(volatile u_int32_t *)(addr) = value;
823 }
824 
825 /*
826  * Copy `count' 1, 2, 4, or 8 byte values from bus space starting
827  * at tag/bsh1/off1 to bus space starting at tag/bsh2/off2.
828  */
829 
830 static __inline void bus_space_copy_region_1(bus_space_tag_t tag,
831 					     bus_space_handle_t bsh1,
832 					     bus_size_t off1,
833 					     bus_space_handle_t bsh2,
834 					     bus_size_t off2, size_t count);
835 
836 static __inline void bus_space_copy_region_2(bus_space_tag_t tag,
837 					     bus_space_handle_t bsh1,
838 					     bus_size_t off1,
839 					     bus_space_handle_t bsh2,
840 					     bus_size_t off2, size_t count);
841 
842 static __inline void bus_space_copy_region_4(bus_space_tag_t tag,
843 					     bus_space_handle_t bsh1,
844 					     bus_size_t off1,
845 					     bus_space_handle_t bsh2,
846 					     bus_size_t off2, size_t count);
847 
848 static __inline void
849 bus_space_copy_region_1(bus_space_tag_t tag, bus_space_handle_t bsh1,
850 			bus_size_t off1, bus_space_handle_t bsh2,
851 			bus_size_t off2, size_t count)
852 {
853 	bus_space_handle_t addr1 = bsh1 + off1;
854 	bus_space_handle_t addr2 = bsh2 + off2;
855 
856 	if (tag == X86_BUS_SPACE_IO) {
857 		if (addr1 >= addr2) {
858 			/* src after dest: copy forward */
859 			for (; count != 0; count--, addr1++, addr2++)
860 				outb(addr2, inb(addr1));
861 		} else {
862 			/* dest after src: copy backwards */
863 			for (addr1 += (count - 1), addr2 += (count - 1);
864 			    count != 0; count--, addr1--, addr2--)
865 				outb(addr2, inb(addr1));
866 		}
867 	} else {
868 		if (addr1 >= addr2) {
869 			/* src after dest: copy forward */
870 			for (; count != 0; count--, addr1++, addr2++)
871 				*(volatile u_int8_t *)(addr2) =
872 				    *(volatile u_int8_t *)(addr1);
873 		} else {
874 			/* dest after src: copy backwards */
875 			for (addr1 += (count - 1), addr2 += (count - 1);
876 			    count != 0; count--, addr1--, addr2--)
877 				*(volatile u_int8_t *)(addr2) =
878 				    *(volatile u_int8_t *)(addr1);
879 		}
880 	}
881 }
882 
883 static __inline void
884 bus_space_copy_region_2(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 += 2, addr2 += 2)
895 				outw(addr2, inw(addr1));
896 		} else {
897 			/* dest after src: copy backwards */
898 			for (addr1 += 2 * (count - 1), addr2 += 2 * (count - 1);
899 			    count != 0; count--, addr1 -= 2, addr2 -= 2)
900 				outw(addr2, inw(addr1));
901 		}
902 	} else {
903 		if (addr1 >= addr2) {
904 			/* src after dest: copy forward */
905 			for (; count != 0; count--, addr1 += 2, addr2 += 2)
906 				*(volatile u_int16_t *)(addr2) =
907 				    *(volatile u_int16_t *)(addr1);
908 		} else {
909 			/* dest after src: copy backwards */
910 			for (addr1 += 2 * (count - 1), addr2 += 2 * (count - 1);
911 			    count != 0; count--, addr1 -= 2, addr2 -= 2)
912 				*(volatile u_int16_t *)(addr2) =
913 				    *(volatile u_int16_t *)(addr1);
914 		}
915 	}
916 }
917 
918 static __inline void
919 bus_space_copy_region_4(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 += 4, addr2 += 4)
930 				outl(addr2, inl(addr1));
931 		} else {
932 			/* dest after src: copy backwards */
933 			for (addr1 += 4 * (count - 1), addr2 += 4 * (count - 1);
934 			    count != 0; count--, addr1 -= 4, addr2 -= 4)
935 				outl(addr2, inl(addr1));
936 		}
937 	} else {
938 		if (addr1 >= addr2) {
939 			/* src after dest: copy forward */
940 			for (; count != 0; count--, addr1 += 4, addr2 += 4)
941 				*(volatile u_int32_t *)(addr2) =
942 				    *(volatile u_int32_t *)(addr1);
943 		} else {
944 			/* dest after src: copy backwards */
945 			for (addr1 += 4 * (count - 1), addr2 += 4 * (count - 1);
946 			    count != 0; count--, addr1 -= 4, addr2 -= 4)
947 				*(volatile u_int32_t *)(addr2) =
948 				    *(volatile u_int32_t *)(addr1);
949 		}
950 	}
951 }
952 
953 /*
954  * Bus read/write barrier methods.
955  *
956  *	void bus_space_barrier(bus_space_tag_t tag, bus_space_handle_t bsh,
957  *			       bus_size_t offset, bus_size_t len, int flags);
958  *
959  *
960  * Note that BUS_SPACE_BARRIER_WRITE doesn't do anything other than
961  * prevent reordering by the compiler; all Intel x86 processors currently
962  * retire operations outside the CPU in program order.
963  */
964 #define	BUS_SPACE_BARRIER_READ	0x01		/* force read barrier */
965 #define	BUS_SPACE_BARRIER_WRITE	0x02		/* force write barrier */
966 
967 static __inline void
968 bus_space_barrier(bus_space_tag_t tag __unused, bus_space_handle_t bsh __unused,
969 		  bus_size_t offset __unused, bus_size_t len __unused, int flags)
970 {
971 #ifdef __GNUCLIKE_ASM
972 	if (flags & BUS_SPACE_BARRIER_READ)
973 #ifdef __amd64__
974 		__asm __volatile("lock; addl $0,0(%%rsp)" : : : "memory");
975 #else
976 		__asm __volatile("lock; addl $0,0(%%esp)" : : : "memory");
977 #endif
978 	else
979 		__compiler_membar();
980 #endif
981 }
982 
983 #ifdef BUS_SPACE_NO_LEGACY
984 #undef inb
985 #undef outb
986 #define inb(a) compiler_error
987 #define inw(a) compiler_error
988 #define inl(a) compiler_error
989 #define outb(a, b) compiler_error
990 #define outw(a, b) compiler_error
991 #define outl(a, b) compiler_error
992 #endif
993 
994 #include <machine/bus_dma.h>
995 
996 /*
997  * Stream accesses are the same as normal accesses on x86; there are no
998  * supported bus systems with an endianess different from the host one.
999  */
1000 #define	bus_space_read_stream_1(t, h, o)	bus_space_read_1((t), (h), (o))
1001 #define	bus_space_read_stream_2(t, h, o)	bus_space_read_2((t), (h), (o))
1002 #define	bus_space_read_stream_4(t, h, o)	bus_space_read_4((t), (h), (o))
1003 
1004 #define	bus_space_read_multi_stream_1(t, h, o, a, c) \
1005 	bus_space_read_multi_1((t), (h), (o), (a), (c))
1006 #define	bus_space_read_multi_stream_2(t, h, o, a, c) \
1007 	bus_space_read_multi_2((t), (h), (o), (a), (c))
1008 #define	bus_space_read_multi_stream_4(t, h, o, a, c) \
1009 	bus_space_read_multi_4((t), (h), (o), (a), (c))
1010 
1011 #define	bus_space_write_stream_1(t, h, o, v) \
1012 	bus_space_write_1((t), (h), (o), (v))
1013 #define	bus_space_write_stream_2(t, h, o, v) \
1014 	bus_space_write_2((t), (h), (o), (v))
1015 #define	bus_space_write_stream_4(t, h, o, v) \
1016 	bus_space_write_4((t), (h), (o), (v))
1017 
1018 #define	bus_space_write_multi_stream_1(t, h, o, a, c) \
1019 	bus_space_write_multi_1((t), (h), (o), (a), (c))
1020 #define	bus_space_write_multi_stream_2(t, h, o, a, c) \
1021 	bus_space_write_multi_2((t), (h), (o), (a), (c))
1022 #define	bus_space_write_multi_stream_4(t, h, o, a, c) \
1023 	bus_space_write_multi_4((t), (h), (o), (a), (c))
1024 
1025 #define	bus_space_set_multi_stream_1(t, h, o, v, c) \
1026 	bus_space_set_multi_1((t), (h), (o), (v), (c))
1027 #define	bus_space_set_multi_stream_2(t, h, o, v, c) \
1028 	bus_space_set_multi_2((t), (h), (o), (v), (c))
1029 #define	bus_space_set_multi_stream_4(t, h, o, v, c) \
1030 	bus_space_set_multi_4((t), (h), (o), (v), (c))
1031 
1032 #define	bus_space_read_region_stream_1(t, h, o, a, c) \
1033 	bus_space_read_region_1((t), (h), (o), (a), (c))
1034 #define	bus_space_read_region_stream_2(t, h, o, a, c) \
1035 	bus_space_read_region_2((t), (h), (o), (a), (c))
1036 #define	bus_space_read_region_stream_4(t, h, o, a, c) \
1037 	bus_space_read_region_4((t), (h), (o), (a), (c))
1038 
1039 #define	bus_space_write_region_stream_1(t, h, o, a, c) \
1040 	bus_space_write_region_1((t), (h), (o), (a), (c))
1041 #define	bus_space_write_region_stream_2(t, h, o, a, c) \
1042 	bus_space_write_region_2((t), (h), (o), (a), (c))
1043 #define	bus_space_write_region_stream_4(t, h, o, a, c) \
1044 	bus_space_write_region_4((t), (h), (o), (a), (c))
1045 
1046 #define	bus_space_set_region_stream_1(t, h, o, v, c) \
1047 	bus_space_set_region_1((t), (h), (o), (v), (c))
1048 #define	bus_space_set_region_stream_2(t, h, o, v, c) \
1049 	bus_space_set_region_2((t), (h), (o), (v), (c))
1050 #define	bus_space_set_region_stream_4(t, h, o, v, c) \
1051 	bus_space_set_region_4((t), (h), (o), (v), (c))
1052 
1053 #define	bus_space_copy_region_stream_1(t, h1, o1, h2, o2, c) \
1054 	bus_space_copy_region_1((t), (h1), (o1), (h2), (o2), (c))
1055 #define	bus_space_copy_region_stream_2(t, h1, o1, h2, o2, c) \
1056 	bus_space_copy_region_2((t), (h1), (o1), (h2), (o2), (c))
1057 #define	bus_space_copy_region_stream_4(t, h1, o1, h2, o2, c) \
1058 	bus_space_copy_region_4((t), (h1), (o1), (h2), (o2), (c))
1059 
1060 #endif /* _X86_BUS_H_ */
1061