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