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