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