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