1 /**	$MirOS: src/sys/arch/i386/include/bus.h,v 1.2 2005/03/06 21:26:59 tg Exp $ */
2 /*	$OpenBSD: bus.h,v 1.36 2004/05/04 17:06:33 grange Exp $	*/
3 /*	$NetBSD: bus.h,v 1.6 1996/11/10 03:19:25 thorpej Exp $	*/
4 
5 /*
6  * Copyright (c) 2003, Miodrag Vallat.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
21  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
25  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
29 /*-
30  * Copyright (c) 1996, 1997 The NetBSD Foundation, Inc.
31  * All rights reserved.
32  *
33  * This code is derived from software contributed to The NetBSD Foundation
34  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
35  * NASA Ames Research Center.
36  *
37  * Redistribution and use in source and binary forms, with or without
38  * modification, are permitted provided that the following conditions
39  * are met:
40  * 1. Redistributions of source code must retain the above copyright
41  *    notice, this list of conditions and the following disclaimer.
42  * 2. Redistributions in binary form must reproduce the above copyright
43  *    notice, this list of conditions and the following disclaimer in the
44  *    documentation and/or other materials provided with the distribution.
45  * 3. All advertising materials mentioning features or use of this software
46  *    must display the following acknowledgement:
47  *	This product includes software developed by the NetBSD
48  *	Foundation, Inc. and its contributors.
49  * 4. Neither the name of The NetBSD Foundation nor the names of its
50  *    contributors may be used to endorse or promote products derived
51  *    from this software without specific prior written permission.
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 Jason R. Thorpe.  All rights reserved.
69  * Copyright (c) 1996 Christopher G. Demetriou.  All rights reserved.
70  *
71  * Redistribution and use in source and binary forms, with or without
72  * modification, are permitted provided that the following conditions
73  * are met:
74  * 1. Redistributions of source code must retain the above copyright
75  *    notice, this list of conditions and the following disclaimer.
76  * 2. Redistributions in binary form must reproduce the above copyright
77  *    notice, this list of conditions and the following disclaimer in the
78  *    documentation and/or other materials provided with the distribution.
79  * 3. All advertising materials mentioning features or use of this software
80  *    must display the following acknowledgement:
81  *	This product includes software developed by Christopher G. Demetriou
82  *	for the NetBSD Project.
83  * 4. The name of the author may not be used to endorse or promote products
84  *    derived from this software without specific prior written permission
85  *
86  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
87  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
88  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
89  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
90  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
91  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
92  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
93  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
94  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
95  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
96  */
97 
98 #ifndef _I386_BUS_H_
99 #define _I386_BUS_H_
100 
101 #include <machine/pio.h>
102 
103 /*
104  * Values for the i386 bus space tag, not to be used directly by MI code.
105  */
106 #define	I386_BUS_SPACE_IO	0	/* space is i/o space */
107 #define I386_BUS_SPACE_MEM	1	/* space is mem space */
108 
109 /*
110  * Bus address and size types
111  */
112 typedef u_long bus_addr_t;
113 typedef u_long bus_size_t;
114 
115 /*
116  * Access methods for bus resources and address space.
117  */
118 typedef	int bus_space_tag_t;
119 typedef	u_long bus_space_handle_t;
120 
121 int	bus_space_map(bus_space_tag_t t, bus_addr_t addr,
122 	    bus_size_t size, int cacheable, bus_space_handle_t *bshp);
123 /* like bus_space_map(), but without extent map checking/allocation */
124 int	_bus_space_map(bus_space_tag_t t, bus_addr_t addr,
125 	    bus_size_t size, int cacheable, bus_space_handle_t *bshp);
126 void	bus_space_unmap(bus_space_tag_t t, bus_space_handle_t bsh,
127 	    bus_size_t size);
128 /* like bus_space_unmap(), but without extent map deallocation */
129 void	_bus_space_unmap(bus_space_tag_t, bus_space_handle_t,
130 	    bus_size_t, bus_addr_t *);
131 int	bus_space_subregion(bus_space_tag_t t, bus_space_handle_t bsh,
132 	    bus_size_t offset, bus_size_t size, bus_space_handle_t *nbshp);
133 
134 int	bus_space_alloc(bus_space_tag_t t, bus_addr_t rstart,
135 	    bus_addr_t rend, bus_size_t size, bus_size_t align,
136 	    bus_size_t boundary, int cacheable, bus_addr_t *addrp,
137 	    bus_space_handle_t *bshp);
138 void	bus_space_free(bus_space_tag_t t, bus_space_handle_t bsh,
139 	    bus_size_t size);
140 
141 static void bus_space_barrier(bus_space_tag_t, bus_space_handle_t,
142     bus_addr_t, bus_size_t, int);
143 
144 /*
145  *	u_intN_t bus_space_read_N(bus_space_tag_t tag,
146  *	    bus_space_handle_t bsh, bus_size_t offset);
147  *
148  * Read a 1, 2, 4, or 8 byte quantity from bus space
149  * described by tag/handle/offset.
150  */
151 
152 #define	bus_space_read_1(t, h, o)					\
153 	((t) == I386_BUS_SPACE_IO ? (inb((h) + (o))) :			\
154 	    (*(volatile u_int8_t *)((h) + (o))))
155 
156 #define	bus_space_read_2(t, h, o)					\
157 	((t) == I386_BUS_SPACE_IO ? (inw((h) + (o))) :			\
158 	    (*(volatile u_int16_t *)((h) + (o))))
159 
160 #define	bus_space_read_4(t, h, o)					\
161 	((t) == I386_BUS_SPACE_IO ? (inl((h) + (o))) :			\
162 	    (*(volatile u_int32_t *)((h) + (o))))
163 
164 #if 0	/* Cause a link error for bus_space_read_8 */
165 #define	bus_space_read_8(t, h, o)	!!! bus_space_read_8 unimplemented !!!
166 #endif
167 
168 /*
169  *	void bus_space_read_multi_N(bus_space_tag_t tag,
170  *	    bus_space_handle_t bsh, bus_size_t offset,
171  *	    u_intN_t *addr, size_t count);
172  *
173  * Read `count' 1, 2, 4, or 8 byte quantities from bus space
174  * described by tag/handle/offset and copy into buffer provided.
175  */
176 
177 #define	bus_space_read_multi_1(t, h, o, a, cnt) do {			\
178 	if ((t) == I386_BUS_SPACE_IO) {					\
179 		insb((h) + (o), (a), (cnt));				\
180 	} else {void *_addr=(a); int _cnt=(cnt);			\
181 		__asm __volatile("					\
182 			cld					;	\
183 		1:	movb (%2),%%al				;	\
184 			stosb					;	\
185 			loop 1b"				:	\
186 		    "+D" (_addr), "+c" (_cnt) : "r" ((h) + (o))	:	\
187 		    "%eax", "memory", "cc");				\
188 	}								\
189 } while (0)
190 
191 #define	bus_space_read_multi_2(t, h, o, a, cnt) do {			\
192 	if ((t) == I386_BUS_SPACE_IO) {					\
193 		insw((h) + (o), (a), (cnt));				\
194 	} else {void *_addr=(a); int _cnt=(cnt);			\
195 		__asm __volatile("					\
196 			cld					;	\
197 		1:	movw (%2),%%ax				;	\
198 			stosw					;	\
199 			loop 1b"				:	\
200 		    "+D" (_addr), "+c" (_cnt) : "r" ((h) + (o))	:	\
201 		    "%eax", "memory", "cc");				\
202 	}								\
203 } while (0)
204 
205 #define	bus_space_read_multi_4(t, h, o, a, cnt) do {			\
206 	if ((t) == I386_BUS_SPACE_IO) {					\
207 		insl((h) + (o), (a), (cnt));				\
208 	} else {void *_addr=(a); int _cnt=(cnt);			\
209 		__asm __volatile("					\
210 			cld					;	\
211 		1:	movl (%2),%%eax				;	\
212 			stosl					;	\
213 			loop 1b"				:	\
214 		    "+D" (_addr), "+c" (_cnt) : "r" ((h) + (o))	:	\
215 		    "%eax", "memory", "cc");				\
216 	}								\
217 } while (0)
218 
219 #if 0	/* Cause a link error for bus_space_read_multi_8 */
220 #define	bus_space_read_multi_8	!!! bus_space_read_multi_8 unimplemented !!!
221 #endif
222 
223 /*
224  *	void bus_space_read_raw_multi_N(bus_space_tag_t tag,
225  *	    bus_space_handle_t bsh, bus_size_t offset,
226  *	    u_int8_t *addr, size_t count);
227  *
228  * Read `count' bytes in 2, 4 or 8 byte wide quantities from bus space
229  * described by tag/handle/offset and copy into buffer provided.  The buffer
230  * must have proper alignment for the N byte wide entities.  Furthermore
231  * possible byte-swapping should be done by these functions.
232  */
233 
234 #define	bus_space_read_raw_multi_2(t, h, o, a, c) \
235     bus_space_read_multi_2((t), (h), (o), (u_int16_t *)(a), (c) >> 1)
236 #define	bus_space_read_raw_multi_4(t, h, o, a, c) \
237     bus_space_read_multi_4((t), (h), (o), (u_int32_t *)(a), (c) >> 2)
238 
239 #if 0	/* Cause a link error for bus_space_read_raw_multi_8 */
240 #define	bus_space_read_raw_multi_8 \
241     !!! bus_space_read_raw_multi_8 unimplemented !!!
242 #endif
243 
244 /*
245  *	void bus_space_read_region_N(bus_space_tag_t tag,
246  *	    bus_space_handle_t bsh, bus_size_t offset,
247  *	    u_intN_t *addr, size_t count);
248  *
249  * Read `count' 1, 2, 4, or 8 byte quantities from bus space
250  * described by tag/handle and starting at `offset' and copy into
251  * buffer provided.
252  */
253 
254 #define	bus_space_read_region_1(t, h, o, a, cnt) do {			\
255 	int _cnt = (cnt);	void *_addr = (a); int _port = (h)+(o);	\
256 	if ((t) == I386_BUS_SPACE_IO) {					\
257 		__asm __volatile("					\
258 			cld					;	\
259 		1:	inb %w2,%%al				;	\
260 			stosb					;	\
261 			incl %2					;	\
262 			loop 1b"				:	\
263 		    "+D" (_addr), "+c" (_cnt), "+d" (_port)	::	\
264 		    "%eax", "memory", "cc");				\
265 	} else								\
266 		i386_space_copy(_port, _addr, 1, _cnt);			\
267 } while (0)
268 
269 #define	bus_space_read_region_2(t, h, o, a, cnt) do {			\
270 	int _cnt = (cnt);	void *_addr = (a); int _port = (h)+(o);	\
271 	if ((t) == I386_BUS_SPACE_IO) {					\
272 		__asm __volatile("					\
273 			cld					;	\
274 		1:	inw %w2,%%ax				;	\
275 			stosw					;	\
276 			addl $2,%2				;	\
277 			loop 1b"				:	\
278 		    "+D" (_addr), "+c" (_cnt), "+d" (_port)	::	\
279 		    "%eax", "memory", "cc");				\
280 	} else								\
281 		i386_space_copy(_port, _addr, 2, _cnt);			\
282 } while (0)
283 
284 #define	bus_space_read_region_4(t, h, o, a, cnt) do {			\
285 	int _cnt = (cnt);	void *_addr = (a); int _port = (h)+(o);	\
286 	if ((t) == I386_BUS_SPACE_IO) {					\
287 		__asm __volatile("					\
288 			cld					;	\
289 		1:	inl %w2,%%eax				;	\
290 			stosl					;	\
291 			addl $4,%2				;	\
292 			loop 1b"				:	\
293 		    "+D" (_addr), "+c" (_cnt), "+d" (_port)	::	\
294 		    "%eax", "memory", "cc");				\
295 	} else								\
296 		i386_space_copy(_port, _addr, 4, _cnt);			\
297 } while (0)
298 
299 #if 0	/* Cause a link error for bus_space_read_region_8 */
300 #define	bus_space_read_region_8	!!! bus_space_read_region_8 unimplemented !!!
301 #endif
302 
303 /*
304  *	void bus_space_read_raw_region_N(bus_space_tag_t tag,
305  *	    bus_space_handle_t bsh, bus_size_t offset,
306  *	    u_int8_t *addr, size_t count);
307  *
308  * Read `count' bytes in 2, 4 or 8 byte wide quantities from bus space
309  * described by tag/handle and starting at `offset' and copy into
310  * buffer provided.  The buffer must have proper alignment for the N byte
311  * wide entities.  Furthermore possible byte-swapping should be done by
312  * these functions.
313  */
314 
315 #define	bus_space_read_raw_region_2(t, h, o, a, c) \
316     bus_space_read_region_2((t), (h), (o), (u_int16_t *)(a), (c) >> 1)
317 #define	bus_space_read_raw_region_4(t, h, o, a, c) \
318     bus_space_read_region_4((t), (h), (o), (u_int32_t *)(a), (c) >> 2)
319 
320 #if 0	/* Cause a link error for bus_space_read_raw_region_8 */
321 #define	bus_space_read_raw_region_8 \
322     !!! bus_space_read_raw_region_8 unimplemented !!!
323 #endif
324 
325 /*
326  *	void bus_space_write_N(bus_space_tag_t tag,
327  *	    bus_space_handle_t bsh, bus_size_t offset,
328  *	    u_intN_t value);
329  *
330  * Write the 1, 2, 4, or 8 byte value `value' to bus space
331  * described by tag/handle/offset.
332  */
333 
334 #define	bus_space_write_1(t, h, o, v)	do {				\
335 	if ((t) == I386_BUS_SPACE_IO)					\
336 		outb((h) + (o), (v));					\
337 	else								\
338 		((void)(*(volatile u_int8_t *)((h) + (o)) = (v)));	\
339 } while (0)
340 
341 #define	bus_space_write_2(t, h, o, v)	do {				\
342 	if ((t) == I386_BUS_SPACE_IO)					\
343 		outw((h) + (o), (v));					\
344 	else								\
345 		((void)(*(volatile u_int16_t *)((h) + (o)) = (v)));	\
346 } while (0)
347 
348 #define	bus_space_write_4(t, h, o, v)	do {				\
349 	if ((t) == I386_BUS_SPACE_IO)					\
350 		outl((h) + (o), (v));					\
351 	else								\
352 		((void)(*(volatile u_int32_t *)((h) + (o)) = (v)));	\
353 } while (0)
354 
355 #if 0	/* Cause a link error for bus_space_write_8 */
356 #define	bus_space_write_8	!!! bus_space_write_8 not implemented !!!
357 #endif
358 
359 /*
360  *	void bus_space_write_multi_N(bus_space_tag_t tag,
361  *	    bus_space_handle_t bsh, bus_size_t offset,
362  *	    const u_intN_t *addr, size_t count);
363  *
364  * Write `count' 1, 2, 4, or 8 byte quantities from the buffer
365  * provided to bus space described by tag/handle/offset.
366  */
367 
368 #define	bus_space_write_multi_1(t, h, o, a, cnt) do {			\
369 	if ((t) == I386_BUS_SPACE_IO) {					\
370 		outsb((h) + (o), (a), (cnt));				\
371 	} else {const void *_addr=(a); int _cnt=(cnt);			\
372 		__asm __volatile("					\
373 			cld					;	\
374 		1:	lodsb					;	\
375 			movb %%al,(%2)				;	\
376 			loop 1b"				:	\
377 		    "+S" (_addr), "+c" (_cnt) : "r" ((h) + (o))	:	\
378 		    "%eax", "memory", "cc");				\
379 	}								\
380 } while (0)
381 
382 #define bus_space_write_multi_2(t, h, o, a, cnt) do {			\
383 	if ((t) == I386_BUS_SPACE_IO) {					\
384 		outsw((h) + (o), (a), (cnt));				\
385 	} else {const void *_addr=(a); int _cnt=(cnt);			\
386 		__asm __volatile("					\
387 			cld					;	\
388 		1:	lodsw					;	\
389 			movw %%ax,(%2)				;	\
390 			loop 1b"				:	\
391 		    "+S" (_addr), "+c" (_cnt) : "r" ((h) + (o))	:	\
392 		    "%eax", "memory", "cc");				\
393 	}								\
394 } while (0)
395 
396 #define bus_space_write_multi_4(t, h, o, a, cnt) do {			\
397 	if ((t) == I386_BUS_SPACE_IO) {					\
398 		outsl((h) + (o), (a), (cnt));				\
399 	} else {const void *_addr=(a); int _cnt=(cnt);			\
400 		__asm __volatile("					\
401 			cld					;	\
402 		1:	lodsl					;	\
403 			movl %%eax,(%2)				;	\
404 			loop 1b"				:	\
405 		    "+S" (_addr), "+c" (_cnt) : "r" ((h) + (o))	:	\
406 		    "%eax", "memory", "cc");				\
407 	}								\
408 } while (0)
409 
410 #if 0	/* Cause a link error for bus_space_write_multi_8 */
411 #define	bus_space_write_multi_8(t, h, o, a, c)				\
412 			!!! bus_space_write_multi_8 unimplemented !!!
413 #endif
414 
415 /*
416  *	void bus_space_write_raw_multi_N(bus_space_tag_t tag,
417  *	    bus_space_handle_t bsh, bus_size_t offset,
418  *	    const u_int8_t *addr, size_t count);
419  *
420  * Write `count' bytes in 2, 4 or 8 byte wide quantities from the buffer
421  * provided to bus space described by tag/handle/offset.  The buffer
422  * must have proper alignment for the N byte wide entities.  Furthermore
423  * possible byte-swapping should be done by these functions.
424  */
425 
426 #define	bus_space_write_raw_multi_2(t, h, o, a, c) \
427     bus_space_write_multi_2((t), (h), (o), (const u_int16_t *)(a), (c) >> 1)
428 #define	bus_space_write_raw_multi_4(t, h, o, a, c) \
429     bus_space_write_multi_4((t), (h), (o), (const u_int32_t *)(a), (c) >> 2)
430 
431 #if 0	/* Cause a link error for bus_space_write_raw_multi_8 */
432 #define	bus_space_write_raw_multi_8 \
433     !!! bus_space_write_raw_multi_8 unimplemented !!!
434 #endif
435 
436 /*
437  *	void bus_space_write_region_N(bus_space_tag_t tag,
438  *	    bus_space_handle_t bsh, bus_size_t offset,
439  *	    const u_intN_t *addr, size_t count);
440  *
441  * Write `count' 1, 2, 4, or 8 byte quantities from the buffer provided
442  * to bus space described by tag/handle starting at `offset'.
443  */
444 
445 #define	bus_space_write_region_1(t, h, o, a, cnt) do {			\
446 	int _port = (h)+(o); const void *_addr=(a); int _cnt=(cnt);	\
447 	if ((t) == I386_BUS_SPACE_IO) {					\
448 		__asm __volatile("					\
449 			cld					;	\
450 		1:	lodsb					;	\
451 			outb %%al,%w0				;	\
452 			incl %0					;	\
453 			loop 1b"				:	\
454 		    "+d" (_port), "+S" (_addr), "+c" (_cnt)	::	\
455 		    "%eax", "memory", "cc");				\
456 	} else								\
457 		i386_space_copy(_addr, _port, 1, _cnt);			\
458 } while (0)
459 
460 #define	bus_space_write_region_2(t, h, o, a, cnt) do {			\
461 	int _port = (h)+(o); const void *_addr=(a); int _cnt=(cnt);	\
462 	if ((t) == I386_BUS_SPACE_IO) {					\
463 		__asm __volatile("					\
464 			cld					;	\
465 		1:	lodsw					;	\
466 			outw %%ax,%w0				;	\
467 			addl $2,%0				;	\
468 			loop 1b"				:	\
469 		    "+d" (_port), "+S" (_addr), "+c" (_cnt)	::	\
470 		    "%eax", "memory", "cc");				\
471 	} else								\
472 		i386_space_copy(_addr, _port, 2, _cnt);			\
473 } while (0)
474 
475 #define	bus_space_write_region_4(t, h, o, a, cnt) do {			\
476 	int _port = (h)+(o); const void *_addr=(a); int _cnt=(cnt);	\
477 	if ((t) == I386_BUS_SPACE_IO) {					\
478 		__asm __volatile("					\
479 			cld					;	\
480 		1:	lodsl					;	\
481 			outl %%eax,%w0				;	\
482 			addl $4,%0				;	\
483 			loop 1b"				:	\
484 		    "+d" (_port), "+S" (_addr), "+c" (_cnt)	::	\
485 		    "%eax", "memory", "cc");				\
486 	} else								\
487 		i386_space_copy(_addr, _port, 4, _cnt);			\
488 } while (0)
489 
490 #if 0	/* Cause a link error for bus_space_write_region_8 */
491 #define	bus_space_write_region_8					\
492 			!!! bus_space_write_region_8 unimplemented !!!
493 #endif
494 
495 /*
496  *	void bus_space_write_raw_region_N(bus_space_tag_t tag,
497  *	    bus_space_handle_t bsh, bus_size_t offset,
498  *	    const u_int8_t *addr, size_t count);
499  *
500  * Write `count' bytes in 2, 4 or 8 byte wide quantities to bus space
501  * described by tag/handle and starting at `offset' from the
502  * buffer provided.  The buffer must have proper alignment for the N byte
503  * wide entities.  Furthermore possible byte-swapping should be done by
504  * these functions.
505  */
506 
507 #define	bus_space_write_raw_region_2(t, h, o, a, c) \
508     bus_space_write_region_2((t), (h), (o), (const u_int16_t *)(a), (c) >> 1)
509 #define	bus_space_write_raw_region_4(t, h, o, a, c) \
510     bus_space_write_region_4((t), (h), (o), (const u_int32_t *)(a), (c) >> 2)
511 
512 #if 0	/* Cause a link error for bus_space_write_raw_region_8 */
513 #define	bus_space_write_raw_region_8 \
514     !!! bus_space_write_raw_region_8 unimplemented !!!
515 #endif
516 
517 /*
518  *	void bus_space_set_multi_N(bus_space_tag_t tag,
519  *	    bus_space_handle_t bsh, bus_size_t offset,
520  *	    u_intN_t val, size_t count);
521  *
522  * Write the 1, 2, 4, or 8 byte value `val' to bus space described
523  * by tag/handle/offset `count' times.
524  */
525 
526 #define	bus_space_set_multi_1(t, h, o, v, cnt) do {			\
527 	int _cnt=(cnt);							\
528 	if ((t) == I386_BUS_SPACE_IO) {					\
529 		__asm __volatile("					\
530 			cld					;	\
531 		1:	outb %b2, %w1				;	\
532 			loop 1b"				:	\
533 		    "+c" (_cnt) : "d" ((h) + (o)), "a" ((v))	:	\
534 		    "cc");						\
535 	} else {							\
536 		__asm __volatile("					\
537 			cld					;	\
538 		1:	movb %b2, (%1)				;	\
539 			loop 1b"				:	\
540 		    "+c" (_cnt) : "D" ((h) + (o)), "a" ((v))	:	\
541 		    "cc", "memory");					\
542 	}								\
543 } while (0)
544 
545 #define	bus_space_set_multi_2(t, h, o, v, cnt) do {			\
546 	int _cnt=(cnt);							\
547 	if ((t) == I386_BUS_SPACE_IO) {					\
548 		__asm __volatile("					\
549 			cld					;	\
550 		1:	outw %w2, %w1				;	\
551 			loop 1b"				:	\
552 		    "+c" (_cnt) : "d" ((h) + (o)), "a" ((v))	:	\
553 		    "cc");						\
554 	} else {							\
555 		__asm __volatile("					\
556 			cld					;	\
557 		1:	movw %w2, (%1)				;	\
558 			loop 1b"				:	\
559 		    "+c" (_cnt) : "D" ((h) + (o)), "a" ((v))	:	\
560 		    "cc", "memory");					\
561 	}								\
562 } while (0)
563 
564 #define	bus_space_set_multi_4(t, h, o, v, cnt) do {			\
565 	int _cnt=(cnt);							\
566 	if ((t) == I386_BUS_SPACE_IO) {					\
567 		__asm __volatile("					\
568 			cld					;	\
569 		1:	outl %2,%w1				;	\
570 			loop 1b"				:	\
571 		    "+c" (_cnt) : "d" ((h) + (o)), "a" ((v))	:	\
572 		    "cc");						\
573 	} else {							\
574 		__asm __volatile("					\
575 			cld					;	\
576 		1:	movl %2,(%1)				;	\
577 			loop 1b"				:	\
578 		    "+c" (_cnt) : "D" ((h) + (o)), "a" ((v))	:	\
579 		    "cc", "memory");					\
580 	}								\
581 } while (0)
582 
583 #if 0	/* Cause a link error for bus_space_set_multi_8 */
584 #define	bus_space_set_multi_8					\
585 			!!! bus_space_set_multi_8 unimplemented !!!
586 #endif
587 
588 /*
589  *	void bus_space_set_region_N(bus_space_tag_t tag,
590  *	    bus_space_handle_t bsh, bus_size_t offset,
591  *	    u_intN_t val, size_t count);
592  *
593  * Write `count' 1, 2, 4, or 8 byte value `val' to bus space described
594  * by tag/handle starting at `offset'.
595  */
596 
597 #define	bus_space_set_region_1(t, h, o, v, cnt) do {			\
598 	int _port = (h)+(o); int _cnt = (cnt);				\
599 	if ((t) == I386_BUS_SPACE_IO) {					\
600 		__asm __volatile("					\
601 		1:	outb %%al,%w0				;	\
602 			incl %0					;	\
603 			loop 1b"				:	\
604 		    "+d" (_port), "+c" (_cnt) : "a" ((v))	:	\
605 		    "cc");						\
606 	} else {							\
607 		__asm __volatile("					\
608 			cld					;	\
609 			repne					;	\
610 			stosb"					:	\
611 		    "+D" (_port), "+c" (_cnt) : "a" ((v))	:	\
612 		    "memory", "cc");					\
613 	}								\
614 } while (0)
615 
616 #define	bus_space_set_region_2(t, h, o, v, cnt) do {			\
617 	int _port = (h)+(o); int _cnt = (cnt);				\
618 	if ((t) == I386_BUS_SPACE_IO) {					\
619 		__asm __volatile("					\
620 		1:	outw %%ax,%w0				;	\
621 			addl $2, %0				;	\
622 			loop 1b"				:	\
623 		    "+d" (_port), "+c" (_cnt) : "a" ((v))	:	\
624 		    "cc");						\
625 	} else {							\
626 		__asm __volatile("					\
627 			cld					;	\
628 			repne					;	\
629 			stosw"					:	\
630 		    "+D" (_port), "+c" (_cnt) : "a" ((v))	:	\
631 		    "memory", "cc");					\
632 	}								\
633 } while (0)
634 
635 #define	bus_space_set_region_4(t, h, o, v, cnt) do {			\
636 	int _port = (h)+(o); int _cnt = (cnt);				\
637 	if ((t) == I386_BUS_SPACE_IO) {					\
638 		__asm __volatile("					\
639 		1:	outl %%eax,%w0				;	\
640 			addl $4, %0				;	\
641 			loop 1b"				:	\
642 		    "+d" (_port), "+c" (_cnt) : "a" ((v))	:	\
643 		    "cc");						\
644 	} else {							\
645 		__asm __volatile("					\
646 			cld					;	\
647 			repne					;	\
648 			stosl"					:	\
649 		    "+D" (_port), "+c" (_cnt) : "a" ((v))	:	\
650 		    "memory", "cc");					\
651 	}								\
652 } while (0)
653 
654 #if 0	/* Cause a link error for bus_space_set_region_8 */
655 #define	bus_space_set_region_8					\
656 			!!! bus_space_set_region_8 unimplemented !!!
657 #endif
658 
659 /*
660  *	void bus_space_copy_N(bus_space_tag_t tag,
661  *	    bus_space_handle_t bsh1, bus_size_t off1,
662  *	    bus_space_handle_t bsh2, bus_size_t off2,
663  *	    size_t count);
664  *
665  * Copy `count' 1, 2, 4, or 8 byte values from bus space starting
666  * at tag/bsh1/off1 to bus space starting at tag/bsh2/off2.
667  */
668 
669 #define	bus_space_copy_1(t, h1, o1, h2, o2, cnt) do {			\
670 	int _port1 = (h1)+(o1); int _port2 = (h2)+(o2); int _cnt=(cnt);	\
671 	if ((t) == I386_BUS_SPACE_IO) {					\
672 		__asm __volatile("					\
673 		1:	movl %k1,%%edx				;	\
674 			inb  %%dx,%%al				;	\
675 			movl %k0,%%edx				;	\
676 			outb %%al,%%dx				;	\
677 			incl %0					;	\
678 			incl %1					;	\
679 			loop 1b"				:	\
680 		    "+D" (_port2), "+S" (_port1), "+c" ((_cnt))	::	\
681 		    "%edx", "%eax", "cc");				\
682 	} else								\
683 		i386_space_copy(_port1, _port2, 1, _cnt);		\
684 } while (0)
685 
686 #define	bus_space_copy_2(t, h1, o1, h2, o2, cnt) do {			\
687 	int _port1 = (h1)+(o1); int _port2 = (h2)+(o2); int _cnt=(cnt);	\
688 	if ((t) == I386_BUS_SPACE_IO) {					\
689 		__asm __volatile("					\
690 		1:	movl %k1,%%edx				;	\
691 			inw  %%dx,%%ax				;	\
692 			movl %k0,%%edx				;	\
693 			outw %%ax,%%dx				;	\
694 			addl $2, %0				;	\
695 			addl $2, %1				;	\
696 			loop 1b"				:	\
697 		    "+D" (_port2), "+ES" (_port1), "+c" ((_cnt))	::	\
698 		    "%edx", "%eax", "cc");				\
699 	} else								\
700 		i386_space_copy(_port1, _port2, 2, _cnt);		\
701 } while (0)
702 
703 #define	bus_space_copy_4(t, h1, o1, h2, o2, cnt) do {			\
704 	int _port1 = (h1)+(o1); int _port2 = (h2)+(o2); int _cnt=(cnt);	\
705 	if ((t) == I386_BUS_SPACE_IO) {					\
706 		__asm __volatile("					\
707 		1:	movl %k1,%%edx				;	\
708 			inl  %%dx,%%eax				;	\
709 			movl %k0,%%edx				;	\
710 			outl %%eax,%%dx				;	\
711 			addl $4, %0				;	\
712 			addl $4, %1				;	\
713 			loop 1b"				:	\
714 		    "+D" (_port2), "+ES" (_port1), "+c" ((_cnt))	::	\
715 		    "%edx", "%eax", "cc");				\
716 	} else								\
717 		i386_space_copy(_port1, _port2, 4, _cnt);		\
718 } while (0)
719 
720 #if 0	/* Cause a link error for bus_space_copy_8 */
721 #define	bus_space_copy_8					\
722 			!!! bus_space_copy_8 unimplemented !!!
723 #endif
724 
725 #define	i386_space_copy1(a1, a2, cnt, movs, df)		\
726 	__asm __volatile(df "\n\trep\n\t" movs :	\
727 	    "+S" (a1), "+D" (a2), "+c" (cnt)	:: "memory", "cc");
728 
729 #define	i386_space_copy(a1, a2, sz, cnt) do {				\
730 	if ((void *)(a1) < (void *)(a2)) {				\
731 		a1 += ((cnt) - 1) * (sz); a2 += ((cnt) - 1) * (sz);	\
732 		switch (sz) {						\
733 		case 1:	i386_space_copy1(a1,a2,cnt,"movsb","std");break;\
734 		case 2:	i386_space_copy1(a1,a2,cnt,"movsw","std");break;\
735 		case 4:	i386_space_copy1(a1,a2,cnt,"movsl","std");break;\
736 		}							\
737 	} else								\
738 		switch (sz) {						\
739 		case 1:	i386_space_copy1(a1,a2,cnt,"movsb","cld");break;\
740 		case 2:	i386_space_copy1(a1,a2,cnt,"movsw","cld");break;\
741 		case 4:	i386_space_copy1(a1,a2,cnt,"movsl","cld");break;\
742 		}							\
743 } while (0)
744 
745 /*
746  * Bus read/write barrier methods.
747  *
748  *	void bus_space_barrier(bus_space_tag_t tag,
749  *	    bus_space_handle_t bsh, bus_size_t offset,
750  *	    bus_size_t len, int flags);
751  *
752  * Note: the i386 does not currently require barriers, but we must
753  * provide the flags to MI code.
754  */
755 #define	BUS_SPACE_BARRIER_READ	0x01		/* force read barrier */
756 #define	BUS_SPACE_BARRIER_WRITE	0x02		/* force write barrier */
757 /* Compatibility defines */
758 #define	BUS_BARRIER_READ	BUS_SPACE_BARRIER_READ
759 #define	BUS_BARRIER_WRITE	BUS_SPACE_BARRIER_WRITE
760 
761 static __inline__ void
bus_space_barrier(bus_space_tag_t tag,bus_space_handle_t handle,bus_addr_t offset,bus_size_t size,int flags)762 bus_space_barrier(bus_space_tag_t tag, bus_space_handle_t handle,
763     bus_addr_t offset, bus_size_t size, int flags)
764 {
765 	/* nothing, but can't be a void macro, thanks GCC */
766 }
767 
768 /*
769  * Flags used in various bus DMA methods.
770  */
771 #define	BUS_DMA_WAITOK		0x000	/* safe to sleep (pseudo-flag) */
772 #define	BUS_DMA_NOWAIT		0x001	/* not safe to sleep */
773 #define	BUS_DMA_ALLOCNOW	0x002	/* perform resource allocation now */
774 #define	BUS_DMA_COHERENT	0x004	/* hint: map memory DMA coherent */
775 #define	BUS_DMA_BUS1		0x010	/* placeholders for bus functions... */
776 #define	BUS_DMA_BUS2		0x020
777 #define	BUS_DMA_BUS3		0x040
778 #define	BUS_DMA_BUS4		0x080
779 #define	BUS_DMA_STREAMING	0x100	/* hint: sequential, unidirectional */
780 #define	BUS_DMA_READ		0x200	/* mapping is device -> memory only */
781 #define	BUS_DMA_WRITE		0x400	/* mapping is memory -> device only */
782 
783 /* Forwards needed by prototypes below. */
784 struct mbuf;
785 struct proc;
786 struct uio;
787 
788 /*
789  * Operations performed by bus_dmamap_sync().
790  */
791 #define BUS_DMASYNC_PREREAD	0x01
792 #define BUS_DMASYNC_POSTREAD	0x02
793 #define BUS_DMASYNC_PREWRITE	0x04
794 #define BUS_DMASYNC_POSTWRITE	0x08
795 
796 typedef struct i386_bus_dma_tag		*bus_dma_tag_t;
797 typedef struct i386_bus_dmamap		*bus_dmamap_t;
798 
799 /*
800  *	bus_dma_segment_t
801  *
802  *	Describes a single contiguous DMA transaction.  Values
803  *	are suitable for programming into DMA registers.
804  */
805 struct i386_bus_dma_segment {
806 	bus_addr_t	ds_addr;	/* DMA address */
807 	bus_size_t	ds_len;		/* length of transfer */
808 };
809 typedef struct i386_bus_dma_segment	bus_dma_segment_t;
810 
811 /*
812  *	bus_dma_tag_t
813  *
814  *	A machine-dependent opaque type describing the implementation of
815  *	DMA for a given bus.
816  */
817 
818 struct i386_bus_dma_tag {
819 	void	*_cookie;		/* cookie used in the guts */
820 
821 	/*
822 	 * DMA mapping methods.
823 	 */
824 	int	(*_dmamap_create)(bus_dma_tag_t, bus_size_t, int,
825 		    bus_size_t, bus_size_t, int, bus_dmamap_t *);
826 	void	(*_dmamap_destroy)(bus_dma_tag_t, bus_dmamap_t);
827 	int	(*_dmamap_load)(bus_dma_tag_t, bus_dmamap_t, void *,
828 		    bus_size_t, struct proc *, int);
829 	int	(*_dmamap_load_mbuf)(bus_dma_tag_t, bus_dmamap_t,
830 		    struct mbuf *, int);
831 	int	(*_dmamap_load_uio)(bus_dma_tag_t, bus_dmamap_t,
832 		    struct uio *, int);
833 	int	(*_dmamap_load_raw)(bus_dma_tag_t, bus_dmamap_t,
834 		    bus_dma_segment_t *, int, bus_size_t, int);
835 	void	(*_dmamap_unload)(bus_dma_tag_t, bus_dmamap_t);
836 	void	(*_dmamap_sync)(bus_dma_tag_t, bus_dmamap_t,
837 		    bus_addr_t, bus_size_t, int);
838 
839 	/*
840 	 * DMA memory utility functions.
841 	 */
842 	int	(*_dmamem_alloc)(bus_dma_tag_t, bus_size_t, bus_size_t,
843 		    bus_size_t, bus_dma_segment_t *, int, int *, int);
844 	void	(*_dmamem_free)(bus_dma_tag_t,
845 		    bus_dma_segment_t *, int);
846 	int	(*_dmamem_map)(bus_dma_tag_t, bus_dma_segment_t *,
847 		    int, size_t, caddr_t *, int);
848 	void	(*_dmamem_unmap)(bus_dma_tag_t, caddr_t, size_t);
849 	paddr_t	(*_dmamem_mmap)(bus_dma_tag_t, bus_dma_segment_t *,
850 		    int, off_t, int, int);
851 };
852 
853 #define	bus_dmamap_create(t, s, n, m, b, f, p)			\
854 	(*(t)->_dmamap_create)((t), (s), (n), (m), (b), (f), (p))
855 #define	bus_dmamap_destroy(t, p)				\
856 	(*(t)->_dmamap_destroy)((t), (p))
857 #define	bus_dmamap_load(t, m, b, s, p, f)			\
858 	(*(t)->_dmamap_load)((t), (m), (b), (s), (p), (f))
859 #define	bus_dmamap_load_mbuf(t, m, b, f)			\
860 	(*(t)->_dmamap_load_mbuf)((t), (m), (b), (f))
861 #define	bus_dmamap_load_uio(t, m, u, f)				\
862 	(*(t)->_dmamap_load_uio)((t), (m), (u), (f))
863 #define	bus_dmamap_load_raw(t, m, sg, n, s, f)			\
864 	(*(t)->_dmamap_load_raw)((t), (m), (sg), (n), (s), (f))
865 #define	bus_dmamap_unload(t, p)					\
866 	(*(t)->_dmamap_unload)((t), (p))
867 #define	bus_dmamap_sync(t, p, o, l, ops)			\
868 	(void)((t)->_dmamap_sync ?				\
869 	    (*(t)->_dmamap_sync)((t), (p), (o), (l), (ops)) : (void)0)
870 
871 #define	bus_dmamem_alloc(t, s, a, b, sg, n, r, f)		\
872 	(*(t)->_dmamem_alloc)((t), (s), (a), (b), (sg), (n), (r), (f))
873 #define	bus_dmamem_free(t, sg, n)				\
874 	(*(t)->_dmamem_free)((t), (sg), (n))
875 #define	bus_dmamem_map(t, sg, n, s, k, f)			\
876 	(*(t)->_dmamem_map)((t), (sg), (n), (s), (k), (f))
877 #define	bus_dmamem_unmap(t, k, s)				\
878 	(*(t)->_dmamem_unmap)((t), (k), (s))
879 #define	bus_dmamem_mmap(t, sg, n, o, p, f)			\
880 	(*(t)->_dmamem_mmap)((t), (sg), (n), (o), (p), (f))
881 
882 /*
883  *	bus_dmamap_t
884  *
885  *	Describes a DMA mapping.
886  */
887 struct i386_bus_dmamap {
888 	/*
889 	 * PRIVATE MEMBERS: not for use my machine-independent code.
890 	 */
891 	bus_size_t	_dm_size;	/* largest DMA transfer mappable */
892 	int		_dm_segcnt;	/* number of segs this map can map */
893 	bus_size_t	_dm_maxsegsz;	/* largest possible segment */
894 	bus_size_t	_dm_boundary;	/* don't cross this */
895 	int		_dm_flags;	/* misc. flags */
896 
897 	void		*_dm_cookie;	/* cookie for bus-specific functions */
898 
899 	/*
900 	 * PUBLIC MEMBERS: these are used by machine-independent code.
901 	 */
902 	bus_size_t	dm_mapsize;	/* size of the mapping */
903 	int		dm_nsegs;	/* # valid segments in mapping */
904 	bus_dma_segment_t dm_segs[1];	/* segments; variable length */
905 };
906 
907 #ifdef _I386_BUS_DMA_PRIVATE
908 int	_bus_dmamap_create(bus_dma_tag_t, bus_size_t, int, bus_size_t,
909 	    bus_size_t, int, bus_dmamap_t *);
910 void	_bus_dmamap_destroy(bus_dma_tag_t, bus_dmamap_t);
911 int	_bus_dmamap_load(bus_dma_tag_t, bus_dmamap_t, void *,
912 	    bus_size_t, struct proc *, int);
913 int	_bus_dmamap_load_mbuf(bus_dma_tag_t, bus_dmamap_t,
914 	    struct mbuf *, int);
915 int	_bus_dmamap_load_uio(bus_dma_tag_t, bus_dmamap_t,
916 	    struct uio *, int);
917 int	_bus_dmamap_load_raw(bus_dma_tag_t, bus_dmamap_t,
918 	    bus_dma_segment_t *, int, bus_size_t, int);
919 void	_bus_dmamap_unload(bus_dma_tag_t, bus_dmamap_t);
920 void	_bus_dmamap_sync(bus_dma_tag_t, bus_dmamap_t, bus_addr_t,
921 	    bus_size_t, int);
922 
923 int	_bus_dmamem_alloc(bus_dma_tag_t tag, bus_size_t size,
924 	    bus_size_t alignment, bus_size_t boundary,
925 	    bus_dma_segment_t *segs, int nsegs, int *rsegs, int flags);
926 void	_bus_dmamem_free(bus_dma_tag_t tag, bus_dma_segment_t *segs,
927 	    int nsegs);
928 int	_bus_dmamem_map(bus_dma_tag_t tag, bus_dma_segment_t *segs,
929 	    int nsegs, size_t size, caddr_t *kvap, int flags);
930 void	_bus_dmamem_unmap(bus_dma_tag_t tag, caddr_t kva,
931 	    size_t size);
932 paddr_t	_bus_dmamem_mmap(bus_dma_tag_t tag, bus_dma_segment_t *segs,
933 	    int nsegs, off_t off, int prot, int flags);
934 
935 int	_bus_dmamem_alloc_range(bus_dma_tag_t tag, bus_size_t size,
936 	    bus_size_t alignment, bus_size_t boundary,
937 	    bus_dma_segment_t *segs, int nsegs, int *rsegs, int flags,
938 	    paddr_t low, paddr_t high);
939 #endif /* _I386_BUS_DMA_PRIVATE */
940 
941 #endif /* _I386_BUS_H_ */
942