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