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