bus.h revision 48527
1/*	$NetBSD: bus.h,v 1.12 1997/10/01 08:25:15 fvdl Exp $	*/
2
3/*-
4 * Copyright (c) 1996, 1997 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9 * NASA Ames Research Center.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 *    must display the following acknowledgement:
21 *	This product includes software developed by the NetBSD
22 *	Foundation, Inc. and its contributors.
23 * 4. Neither the name of The NetBSD Foundation nor the names of its
24 *    contributors may be used to endorse or promote products derived
25 *    from this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39
40/*
41 * Copyright (c) 1996 Charles M. Hannum.  All rights reserved.
42 * Copyright (c) 1996 Christopher G. Demetriou.  All rights reserved.
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 Christopher G. Demetriou
55 *	for the NetBSD Project.
56 * 4. The name of the author may not be used to endorse or promote products
57 *    derived from this software without specific prior written permission
58 *
59 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
60 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
61 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
62 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
63 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
64 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
65 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
66 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
67 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
68 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
69 */
70/* $Id: bus.h,v 1.4 1998/09/29 09:06:00 bde Exp $ */
71
72#ifndef _I386_BUS_H_
73#define _I386_BUS_H_
74
75#include <machine/cpufunc.h>
76
77/*
78 * To remain compatible with NetBSD's interface, default to both memio and
79 * pio when neither of them is defined.
80 */
81#if !defined(_I386_BUS_PIO_H_) && !defined(_I386_BUS_MEMIO_H_)
82#define _I386_BUS_PIO_H_
83#define _I386_BUS_MEMIO_H_
84#endif
85
86/*
87 * Values for the i386 bus space tag, not to be used directly by MI code.
88 */
89#define	I386_BUS_SPACE_IO	0	/* space is i/o space */
90#define I386_BUS_SPACE_MEM	1	/* space is mem space */
91
92/*
93 * Bus address and size types
94 */
95typedef u_int bus_addr_t;
96typedef u_int bus_size_t;
97
98#define BUS_SPACE_MAXSIZE_24BIT	0xFFFFFF
99#define BUS_SPACE_MAXSIZE_32BIT 0xFFFFFFFF
100#define BUS_SPACE_MAXSIZE	(64 * 1024) /* Maximum supported size */
101#define BUS_SPACE_MAXADDR_24BIT	0xFFFFFF
102#define BUS_SPACE_MAXADDR_32BIT 0xFFFFFFFF
103#define BUS_SPACE_MAXADDR	0xFFFFFFFF
104
105#define BUS_SPACE_UNRESTRICTED	(~0)
106
107/*
108 * Access methods for bus resources and address space.
109 */
110typedef	int bus_space_tag_t;
111typedef	u_int bus_space_handle_t;
112
113/*
114 * Map a region of device bus space into CPU virtual address space.
115 */
116
117#define	BUS_SPACE_MAP_CACHEABLE		0x01
118#define	BUS_SPACE_MAP_LINEAR		0x02
119
120int	bus_space_map(bus_space_tag_t t, bus_addr_t addr, bus_size_t size,
121		      int flags, bus_space_handle_t *bshp);
122
123/*
124 * Unmap a region of device bus space.
125 */
126
127void	bus_space_unmap(bus_space_tag_t t, bus_space_handle_t bsh,
128			bus_size_t size);
129
130/*
131 * Get a new handle for a subregion of an already-mapped area of bus space.
132 */
133
134int	bus_space_subregion(bus_space_tag_t t, bus_space_handle_t bsh,
135			    bus_size_t offset, bus_size_t size,
136			    bus_space_handle_t *nbshp);
137
138/*
139 * Allocate a region of memory that is accessible to devices in bus space.
140 */
141
142int	bus_space_alloc(bus_space_tag_t t, bus_addr_t rstart,
143			bus_addr_t rend, bus_size_t size, bus_size_t align,
144			bus_size_t boundary, int flags, bus_addr_t *addrp,
145			bus_space_handle_t *bshp);
146
147/*
148 * Free a region of bus space accessible memory.
149 */
150
151void	bus_space_free(bus_space_tag_t t, bus_space_handle_t bsh,
152		       bus_size_t size);
153
154#if defined(_I386_BUS_PIO_H_) || defined(_I386_BUS_MEMIO_H_)
155
156/*
157 * Read a 1, 2, 4, or 8 byte quantity from bus space
158 * described by tag/handle/offset.
159 */
160static __inline u_int8_t bus_space_read_1(bus_space_tag_t tag,
161					  bus_space_handle_t handle,
162					  bus_size_t offset);
163
164static __inline u_int16_t bus_space_read_2(bus_space_tag_t tag,
165					   bus_space_handle_t handle,
166					   bus_size_t offset);
167
168static __inline u_int32_t bus_space_read_4(bus_space_tag_t tag,
169					   bus_space_handle_t handle,
170					   bus_size_t offset);
171
172static __inline u_int8_t
173bus_space_read_1(bus_space_tag_t tag, bus_space_handle_t handle,
174		 bus_size_t offset)
175{
176#if defined (_I386_BUS_PIO_H_)
177#if defined (_I386_BUS_MEMIO_H_)
178	if (tag == I386_BUS_SPACE_IO)
179#endif
180		return (inb(handle + offset));
181#endif
182#if defined (_I386_BUS_MEMIO_H_)
183	return (*(volatile u_int8_t *)(handle + offset));
184#endif
185}
186
187static __inline u_int16_t
188bus_space_read_2(bus_space_tag_t tag, bus_space_handle_t handle,
189		 bus_size_t offset)
190{
191#if defined(_I386_BUS_PIO_H_)
192#if defined(_I386_BUS_MEMIO_H_)
193	if (tag == I386_BUS_SPACE_IO)
194#endif
195		return (inw(handle + offset));
196#endif
197#if defined(_I386_BUS_MEMIO_H_)
198	return (*(volatile u_int16_t *)(handle + offset));
199#endif
200}
201
202static __inline u_int32_t
203bus_space_read_4(bus_space_tag_t tag, bus_space_handle_t handle,
204		 bus_size_t offset)
205{
206#if defined(_I386_BUS_PIO_H_)
207#if defined(_I386_BUS_MEMIO_H_)
208	if (tag == I386_BUS_SPACE_IO)
209#endif
210		return (inl(handle + offset));
211#endif
212#if defined(_I386_BUS_MEMIO_H_)
213	return (*(volatile u_int32_t *)(handle + offset));
214#endif
215}
216
217#if 0	/* Cause a link error for bus_space_read_8 */
218#define	bus_space_read_8(t, h, o)	!!! bus_space_read_8 unimplemented !!!
219#endif
220
221/*
222 * Read `count' 1, 2, 4, or 8 byte quantities from bus space
223 * described by tag/handle/offset and copy into buffer provided.
224 */
225static __inline void bus_space_read_multi_1(bus_space_tag_t tag,
226					    bus_space_handle_t bsh,
227					    bus_size_t offset, u_int8_t *addr,
228					    size_t count);
229
230static __inline void bus_space_read_multi_2(bus_space_tag_t tag,
231					    bus_space_handle_t bsh,
232					    bus_size_t offset, u_int16_t *addr,
233					    size_t count);
234
235static __inline void bus_space_read_multi_4(bus_space_tag_t tag,
236					    bus_space_handle_t bsh,
237					    bus_size_t offset, u_int32_t *addr,
238					    size_t count);
239
240static __inline void
241bus_space_read_multi_1(bus_space_tag_t tag, bus_space_handle_t bsh,
242		       bus_size_t offset, u_int8_t *addr, size_t count)
243{
244#if defined(_I386_BUS_PIO_H_)
245#if defined(_I386_BUS_MEMIO_H_)
246	if (tag == I386_BUS_SPACE_IO)
247#endif
248		insb(bsh + offset, addr, count);
249#endif
250#if defined(_I386_BUS_MEMIO_H_)
251#if defined(_I386_BUS_PIO_H_)
252	else
253#endif
254	{
255		int __x __asm__("%eax");
256		__asm __volatile("				\n\
257			cld					\n\
258		1:	movb (%1),%%al				\n\
259			stosb					\n\
260			loop 1b"				:
261		    "=&a" (__x)					:
262		    "r" (bsh + offset), "D" (addr), "c" (count)	:
263		    "%edi", "%ecx", "memory");
264	}
265#endif
266}
267
268static __inline void
269bus_space_read_multi_2(bus_space_tag_t tag, bus_space_handle_t bsh,
270		       bus_size_t offset, u_int16_t *addr, size_t count)
271{
272#if defined(_I386_BUS_PIO_H_)
273#if defined(_I386_BUS_MEMIO_H_)
274	if (tag == I386_BUS_SPACE_IO)
275#endif
276		insw(bsh + offset, addr, count);
277#endif
278#if defined(_I386_BUS_MEMIO_H_)
279#if defined(_I386_BUS_PIO_H_)
280	else
281#endif
282	{
283		int __x __asm__("%eax");
284		__asm __volatile("				\n\
285			cld					\n\
286		1:	movw (%1),%%ax				\n\
287			stosw					\n\
288			loop 1b"				:
289		    "=&a" (__x)					:
290		    "r" (bsh + offset), "D" (addr), "c" (count)	:
291		    "%edi", "%ecx", "memory");
292	}
293#endif
294}
295
296static __inline void
297bus_space_read_multi_4(bus_space_tag_t tag, bus_space_handle_t bsh,
298		       bus_size_t offset, u_int32_t *addr, size_t count)
299{
300#if defined(_I386_BUS_PIO_H_)
301#if defined(_I386_BUS_MEMIO_H_)
302	if (tag == I386_BUS_SPACE_IO)
303#endif
304		insl(bsh + offset, addr, count);
305#endif
306#if defined(_I386_BUS_MEMIO_H_)
307#if defined(_I386_BUS_PIO_H_)
308	else
309#endif
310	{
311		int __x __asm__("%eax");
312		__asm __volatile("				\n\
313			cld					\n\
314		1:	movl (%1),%%eax				\n\
315			stosl					\n\
316			loop 1b"				:
317		    "=&a" (__x)					:
318		    "r" (bsh + offset), "D" (addr), "c" (count)	:
319		    "%edi", "%ecx", "memory");
320	}
321#endif
322}
323
324#if 0	/* Cause a link error for bus_space_read_multi_8 */
325#define	bus_space_read_multi_8	!!! bus_space_read_multi_8 unimplemented !!!
326#endif
327
328/*
329 * Read `count' 1, 2, 4, or 8 byte quantities from bus space
330 * described by tag/handle and starting at `offset' and copy into
331 * buffer provided.
332 */
333static __inline void bus_space_read_region_1(bus_space_tag_t tag,
334					     bus_space_handle_t bsh,
335					     bus_size_t offset, u_int8_t *addr,
336					     size_t count);
337
338static __inline void bus_space_read_region_2(bus_space_tag_t tag,
339					     bus_space_handle_t bsh,
340					     bus_size_t offset, u_int16_t *addr,
341					     size_t count);
342
343static __inline void bus_space_read_region_4(bus_space_tag_t tag,
344					     bus_space_handle_t bsh,
345					     bus_size_t offset, u_int32_t *addr,
346					     size_t count);
347
348
349static __inline void
350bus_space_read_region_1(bus_space_tag_t tag, bus_space_handle_t bsh,
351			bus_size_t offset, u_int8_t *addr, size_t count)
352{
353#if defined(_I386_BUS_PIO_H_)
354#if defined(_I386_BUS_MEMIO_H_)
355	if (tag == I386_BUS_SPACE_IO)
356#endif
357	{
358		int __x __asm__("%eax");
359		__asm __volatile("				\n\
360			cld					\n\
361		1:	inb %w1,%%al				\n\
362			stosb					\n\
363			incl %1					\n\
364			loop 1b"				:
365		    "=&a" (__x)					:
366		    "d" (bsh + offset), "D" (addr), "c" (count)	:
367		    "%edx", "%edi", "%ecx", "memory");
368	}
369#endif
370#if defined(_I386_BUS_MEMIO_H_)
371#if defined(_I386_BUS_PIO_H_)
372	else
373#endif
374	{
375		__asm __volatile("				\n\
376			cld					\n\
377			repne					\n\
378			movsb"					:
379								:
380		    "S" (bsh + offset), "D" (addr), "c" (count)	:
381		    "%esi", "%edi", "%ecx", "memory");
382	}
383#endif
384}
385
386static __inline void
387bus_space_read_region_2(bus_space_tag_t tag, bus_space_handle_t bsh,
388			bus_size_t offset, u_int16_t *addr, size_t count)
389{
390#if defined(_I386_BUS_PIO_H_)
391#if defined(_I386_BUS_MEMIO_H_)
392	if (tag == I386_BUS_SPACE_IO)
393#endif
394	{
395		int __x __asm__("%eax");
396		__asm __volatile("				\n\
397			cld					\n\
398		1:	inw %w1,%%ax				\n\
399			stosw					\n\
400			addl $2,%1				\n\
401			loop 1b"				:
402		    "=&a" (__x)					:
403		    "d" (bsh + offset), "D" (addr), "c" (count)	:
404		    "%edx", "%edi", "%ecx", "memory");
405	}
406#endif
407#if defined(_I386_BUS_MEMIO_H_)
408#if defined(_I386_BUS_PIO_H_)
409	else
410#endif
411	{
412		__asm __volatile("				\n\
413			cld					\n\
414			repne					\n\
415			movsw"					:
416								:
417		    "S" (bsh + offset), "D" (addr), "c" (count)	:
418		    "%esi", "%edi", "%ecx", "memory");
419	}
420#endif
421}
422
423static __inline void
424bus_space_read_region_4(bus_space_tag_t tag, bus_space_handle_t bsh,
425			bus_size_t offset, u_int32_t *addr, size_t count)
426{
427#if defined(_I386_BUS_PIO_H_)
428#if defined(_I386_BUS_MEMIO_H_)
429	if (tag == I386_BUS_SPACE_IO)
430#endif
431	{
432		int __x __asm__("%eax");
433		__asm __volatile("				\n\
434			cld					\n\
435		1:	inl %w1,%%eax				\n\
436			stosl					\n\
437			addl $4,%1				\n\
438			loop 1b"				:
439		    "=&a" (__x)					:
440		    "d" (bsh + offset), "D" (addr), "c" (count)	:
441		    "%edx", "%edi", "%ecx", "memory");
442	}
443#endif
444#if defined(_I386_BUS_MEMIO_H_)
445#if defined(_I386_BUS_PIO_H_)
446	else
447#endif
448	{
449		__asm __volatile("				\n\
450			cld					\n\
451			repne					\n\
452			movsl"					:
453								:
454		    "S" (bsh + offset), "D" (addr), "c" (count)	:
455		    "%esi", "%edi", "%ecx", "memory");
456	}
457#endif
458}
459
460#if 0	/* Cause a link error for bus_space_read_region_8 */
461#define	bus_space_read_region_8	!!! bus_space_read_region_8 unimplemented !!!
462#endif
463
464/*
465 * Write the 1, 2, 4, or 8 byte value `value' to bus space
466 * described by tag/handle/offset.
467 */
468
469static __inline void bus_space_write_1(bus_space_tag_t tag,
470				       bus_space_handle_t bsh,
471				       bus_size_t offset, u_int8_t value);
472
473static __inline void bus_space_write_2(bus_space_tag_t tag,
474				       bus_space_handle_t bsh,
475				       bus_size_t offset, u_int16_t value);
476
477static __inline void bus_space_write_4(bus_space_tag_t tag,
478				       bus_space_handle_t bsh,
479				       bus_size_t offset, u_int32_t value);
480
481static __inline void
482bus_space_write_1(bus_space_tag_t tag, bus_space_handle_t bsh,
483		       bus_size_t offset, u_int8_t value)
484{
485#if defined(_I386_BUS_PIO_H_)
486#if defined(_I386_BUS_MEMIO_H_)
487	if (tag == I386_BUS_SPACE_IO)
488#endif
489		outb(bsh + offset, value);
490#endif
491#if defined(_I386_BUS_MEMIO_H_)
492#if defined(_I386_BUS_PIO_H_)
493	else
494#endif
495		*(volatile u_int8_t *)(bsh + offset) = value;
496#endif
497}
498
499static __inline void
500bus_space_write_2(bus_space_tag_t tag, bus_space_handle_t bsh,
501		       bus_size_t offset, u_int16_t value)
502{
503#if defined(_I386_BUS_PIO_H_)
504#if defined(_I386_BUS_MEMIO_H_)
505	if (tag == I386_BUS_SPACE_IO)
506#endif
507		outw(bsh + offset, value);
508#endif
509#if defined(_I386_BUS_MEMIO_H_)
510#if defined(_I386_BUS_PIO_H_)
511	else
512#endif
513		*(volatile u_int16_t *)(bsh + offset) = value;
514#endif
515}
516
517static __inline void
518bus_space_write_4(bus_space_tag_t tag, bus_space_handle_t bsh,
519		       bus_size_t offset, u_int32_t value)
520{
521#if defined(_I386_BUS_PIO_H_)
522#if defined(_I386_BUS_MEMIO_H_)
523	if (tag == I386_BUS_SPACE_IO)
524#endif
525		outl(bsh + offset, value);
526#endif
527#if defined(_I386_BUS_MEMIO_H_)
528#if defined(_I386_BUS_PIO_H_)
529	else
530#endif
531		*(volatile u_int32_t *)(bsh + offset) = value;
532#endif
533}
534
535#if 0	/* Cause a link error for bus_space_write_8 */
536#define	bus_space_write_8	!!! bus_space_write_8 not implemented !!!
537#endif
538
539/*
540 * Write `count' 1, 2, 4, or 8 byte quantities from the buffer
541 * provided to bus space described by tag/handle/offset.
542 */
543
544static __inline void bus_space_write_multi_1(bus_space_tag_t tag,
545					     bus_space_handle_t bsh,
546					     bus_size_t offset,
547					     const u_int8_t *addr,
548					     size_t count);
549static __inline void bus_space_write_multi_2(bus_space_tag_t tag,
550					     bus_space_handle_t bsh,
551					     bus_size_t offset,
552					     const u_int16_t *addr,
553					     size_t count);
554
555static __inline void bus_space_write_multi_4(bus_space_tag_t tag,
556					     bus_space_handle_t bsh,
557					     bus_size_t offset,
558					     const u_int32_t *addr,
559					     size_t count);
560
561static __inline void
562bus_space_write_multi_1(bus_space_tag_t tag, bus_space_handle_t bsh,
563			bus_size_t offset, const u_int8_t *addr, size_t count)
564{
565#if defined(_I386_BUS_PIO_H_)
566#if defined(_I386_BUS_MEMIO_H_)
567	if (tag == I386_BUS_SPACE_IO)
568#endif
569		outsb(bsh + offset, addr, count);
570#endif
571#if defined(_I386_BUS_MEMIO_H_)
572#if defined(_I386_BUS_PIO_H_)
573	else
574#endif
575	{
576		int __x __asm__("%eax");
577		__asm __volatile("				\n\
578			cld					\n\
579		1:	lodsb					\n\
580			movb %%al,(%1)				\n\
581			loop 1b"				:
582		    "=&a" (__x)					:
583		    "r" (bsh + offset), "S" (addr), "c" (count)	:
584		    "%esi", "%ecx");
585	}
586#endif
587}
588
589static __inline void
590bus_space_write_multi_2(bus_space_tag_t tag, bus_space_handle_t bsh,
591			bus_size_t offset, const u_int16_t *addr, size_t count)
592{
593#if defined(_I386_BUS_PIO_H_)
594#if defined(_I386_BUS_MEMIO_H_)
595	if (tag == I386_BUS_SPACE_IO)
596#endif
597		outsw(bsh + offset, addr, count);
598#endif
599#if defined(_I386_BUS_MEMIO_H_)
600#if defined(_I386_BUS_PIO_H_)
601	else
602#endif
603	{
604		int __x __asm__("%eax");
605		__asm __volatile("				\n\
606			cld					\n\
607		1:	lodsw					\n\
608			movw %%ax,(%1)				\n\
609			loop 1b"				:
610		    "=&a" (__x)					:
611		    "r" (bsh + offset), "S" (addr), "c" (count)	:
612		    "%esi", "%ecx");
613	}
614#endif
615}
616
617static __inline void
618bus_space_write_multi_4(bus_space_tag_t tag, bus_space_handle_t bsh,
619			bus_size_t offset, const u_int32_t *addr, size_t count)
620{
621#if defined(_I386_BUS_PIO_H_)
622#if defined(_I386_BUS_MEMIO_H_)
623	if (tag == I386_BUS_SPACE_IO)
624#endif
625		outsl(bsh + offset, addr, count);
626#endif
627#if defined(_I386_BUS_MEMIO_H_)
628#if defined(_I386_BUS_PIO_H_)
629	else
630#endif
631	{
632		int __x __asm__("%eax");
633		__asm __volatile("				\n\
634			cld					\n\
635		1:	lodsl					\n\
636			movl %%eax,(%1)				\n\
637			loop 1b"				:
638		    "=&a" (__x)					:
639		    "r" (bsh + offset), "S" (addr), "c" (count)	:
640		    "%esi", "%ecx");
641	}
642#endif
643}
644
645#if 0	/* Cause a link error for bus_space_write_multi_8 */
646#define	bus_space_write_multi_8(t, h, o, a, c)				\
647			!!! bus_space_write_multi_8 unimplemented !!!
648#endif
649
650/*
651 * Write `count' 1, 2, 4, or 8 byte quantities from the buffer provided
652 * to bus space described by tag/handle starting at `offset'.
653 */
654
655static __inline void bus_space_write_region_1(bus_space_tag_t tag,
656					      bus_space_handle_t bsh,
657					      bus_size_t offset,
658					      const u_int8_t *addr,
659					      size_t count);
660static __inline void bus_space_write_region_2(bus_space_tag_t tag,
661					      bus_space_handle_t bsh,
662					      bus_size_t offset,
663					      const u_int16_t *addr,
664					      size_t count);
665static __inline void bus_space_write_region_4(bus_space_tag_t tag,
666					      bus_space_handle_t bsh,
667					      bus_size_t offset,
668					      const u_int32_t *addr,
669					      size_t count);
670
671static __inline void
672bus_space_write_region_1(bus_space_tag_t tag, bus_space_handle_t bsh,
673			 bus_size_t offset, const u_int8_t *addr, size_t count)
674{
675#if defined(_I386_BUS_PIO_H_)
676#if defined(_I386_BUS_MEMIO_H_)
677	if (tag == I386_BUS_SPACE_IO)
678#endif
679	{
680		int __x __asm__("%eax");
681		__asm __volatile("				\n\
682			cld					\n\
683		1:	lodsb					\n\
684			outb %%al,%w1				\n\
685			incl %1					\n\
686			loop 1b"				:
687		    "=&a" (__x)					:
688		    "d" (bsh + offset), "S" (addr), "c" (count)	:
689		    "%edx", "%esi", "%ecx", "memory");
690	}
691#endif
692#if defined(_I386_BUS_MEMIO_H_)
693#if defined(_I386_BUS_PIO_H_)
694	else
695#endif
696	{
697		__asm __volatile("				\n\
698			cld					\n\
699			repne					\n\
700			movsb"					:
701								:
702		    "D" (bsh + offset), "S" (addr), "c" (count)	:
703		    "%edi", "%esi", "%ecx", "memory");
704	}
705#endif
706}
707
708static __inline void
709bus_space_write_region_2(bus_space_tag_t tag, bus_space_handle_t bsh,
710			 bus_size_t offset, const u_int16_t *addr, size_t count)
711{
712#if defined(_I386_BUS_PIO_H_)
713#if defined(_I386_BUS_MEMIO_H_)
714	if (tag == I386_BUS_SPACE_IO)
715#endif
716	{
717		int __x __asm__("%eax");
718		__asm __volatile("				\n\
719			cld					\n\
720		1:	lodsw					\n\
721			outw %%ax,%w1				\n\
722			addl $2,%1				\n\
723			loop 1b"				:
724		    "=&a" (__x)					:
725		    "d" (bsh + offset), "S" (addr), "c" (count)	:
726		    "%edx", "%esi", "%ecx", "memory");
727	}
728#endif
729#if defined(_I386_BUS_MEMIO_H_)
730#if defined(_I386_BUS_PIO_H_)
731	else
732#endif
733	{
734		__asm __volatile("				\n\
735			cld					\n\
736			repne					\n\
737			movsw"					:
738								:
739		    "D" (bsh + offset), "S" (addr), "c" (count)	:
740		    "%edi", "%esi", "%ecx", "memory");
741	}
742#endif
743}
744
745static __inline void
746bus_space_write_region_4(bus_space_tag_t tag, bus_space_handle_t bsh,
747			 bus_size_t offset, const u_int32_t *addr, size_t count)
748{
749#if defined(_I386_BUS_PIO_H_)
750#if defined(_I386_BUS_MEMIO_H_)
751	if (tag == I386_BUS_SPACE_IO)
752#endif
753	{
754		int __x __asm__("%eax");
755		__asm __volatile("				\n\
756			cld					\n\
757		1:	lodsl					\n\
758			outl %%eax,%w1				\n\
759			addl $4,%1				\n\
760			loop 1b"				:
761		    "=&a" (__x)					:
762		    "d" (bsh + offset), "S" (addr), "c" (count)	:
763		    "%edx", "%esi", "%ecx", "memory");
764	}
765#endif
766#if defined(_I386_BUS_MEMIO_H_)
767#if defined(_I386_BUS_PIO_H_)
768	else
769#endif
770	{
771		__asm __volatile("				\n\
772			cld					\n\
773			repne					\n\
774			movsl"					:
775								:
776		    "D" (bsh + offset), "S" (addr), "c" (count)	:
777		    "%edi", "%esi", "%ecx", "memory");
778	}
779#endif
780}
781
782#if 0	/* Cause a link error for bus_space_write_region_8 */
783#define	bus_space_write_region_8					\
784			!!! bus_space_write_region_8 unimplemented !!!
785#endif
786
787/*
788 * Write the 1, 2, 4, or 8 byte value `val' to bus space described
789 * by tag/handle/offset `count' times.
790 */
791
792static __inline void bus_space_set_multi_1(bus_space_tag_t tag,
793					   bus_space_handle_t bsh,
794					   bus_size_t offset,
795					   u_int8_t value, size_t count);
796static __inline void bus_space_set_multi_2(bus_space_tag_t tag,
797					   bus_space_handle_t bsh,
798					   bus_size_t offset,
799					   u_int16_t value, size_t count);
800static __inline void bus_space_set_multi_4(bus_space_tag_t tag,
801					   bus_space_handle_t bsh,
802					   bus_size_t offset,
803					   u_int32_t value, size_t count);
804
805static __inline void
806bus_space_set_multi_1(bus_space_tag_t tag, bus_space_handle_t bsh,
807		      bus_size_t offset, u_int8_t value, size_t count)
808{
809	bus_addr_t addr = bsh + offset;
810
811#if defined(_I386_BUS_PIO_H_)
812#if defined(_I386_BUS_MEMIO_H_)
813	if (tag == I386_BUS_SPACE_IO)
814#endif
815		while (count--)
816			outb(addr, value);
817#endif
818#if defined(_I386_BUS_MEMIO_H_)
819#if defined(_I386_BUS_PIO_H_)
820	else
821#endif
822		while (count--)
823			*(volatile u_int8_t *)(addr) = value;
824#endif
825}
826
827static __inline void
828bus_space_set_multi_2(bus_space_tag_t tag, bus_space_handle_t bsh,
829		     bus_size_t offset, u_int16_t value, size_t count)
830{
831	bus_addr_t addr = bsh + offset;
832
833#if defined(_I386_BUS_PIO_H_)
834#if defined(_I386_BUS_MEMIO_H_)
835	if (tag == I386_BUS_SPACE_IO)
836#endif
837		while (count--)
838			outw(addr, value);
839#endif
840#if defined(_I386_BUS_MEMIO_H_)
841#if defined(_I386_BUS_PIO_H_)
842	else
843#endif
844		while (count--)
845			*(volatile u_int16_t *)(addr) = value;
846#endif
847}
848
849static __inline void
850bus_space_set_multi_4(bus_space_tag_t tag, bus_space_handle_t bsh,
851		      bus_size_t offset, u_int32_t value, size_t count)
852{
853	bus_addr_t addr = bsh + offset;
854
855#if defined(_I386_BUS_PIO_H_)
856#if defined(_I386_BUS_MEMIO_H_)
857	if (tag == I386_BUS_SPACE_IO)
858#endif
859		while (count--)
860			outl(addr, value);
861#endif
862#if defined(_I386_BUS_MEMIO_H_)
863#if defined(_I386_BUS_PIO_H_)
864	else
865#endif
866		while (count--)
867			*(volatile u_int32_t *)(addr) = value;
868#endif
869}
870
871#if 0	/* Cause a link error for bus_space_set_multi_8 */
872#define	bus_space_set_multi_8 !!! bus_space_set_multi_8 unimplemented !!!
873#endif
874
875/*
876 * Write `count' 1, 2, 4, or 8 byte value `val' to bus space described
877 * by tag/handle starting at `offset'.
878 */
879
880static __inline void bus_space_set_region_1(bus_space_tag_t tag,
881					    bus_space_handle_t bsh,
882					    bus_size_t offset, u_int8_t value,
883					    size_t count);
884static __inline void bus_space_set_region_2(bus_space_tag_t tag,
885					    bus_space_handle_t bsh,
886					    bus_size_t offset, u_int16_t value,
887					    size_t count);
888static __inline void bus_space_set_region_4(bus_space_tag_t tag,
889					    bus_space_handle_t bsh,
890					    bus_size_t offset, u_int32_t value,
891					    size_t count);
892
893static __inline void
894bus_space_set_region_1(bus_space_tag_t tag, bus_space_handle_t bsh,
895		       bus_size_t offset, u_int8_t value, size_t count)
896{
897	bus_addr_t addr = bsh + offset;
898
899#if defined(_I386_BUS_PIO_H_)
900#if defined(_I386_BUS_MEMIO_H_)
901	if (tag == I386_BUS_SPACE_IO)
902#endif
903		for (; count != 0; count--, addr++)
904			outb(addr, value);
905#endif
906#if defined(_I386_BUS_MEMIO_H_)
907#if defined(_I386_BUS_PIO_H_)
908	else
909#endif
910		for (; count != 0; count--, addr++)
911			*(volatile u_int8_t *)(addr) = value;
912#endif
913}
914
915static __inline void
916bus_space_set_region_2(bus_space_tag_t tag, bus_space_handle_t bsh,
917		       bus_size_t offset, u_int16_t value, size_t count)
918{
919	bus_addr_t addr = bsh + offset;
920
921#if defined(_I386_BUS_PIO_H_)
922#if defined(_I386_BUS_MEMIO_H_)
923	if (tag == I386_BUS_SPACE_IO)
924#endif
925		for (; count != 0; count--, addr += 2)
926			outw(addr, value);
927#endif
928#if defined(_I386_BUS_MEMIO_H_)
929#if defined(_I386_BUS_PIO_H_)
930	else
931#endif
932		for (; count != 0; count--, addr += 2)
933			*(volatile u_int16_t *)(addr) = value;
934#endif
935}
936
937static __inline void
938bus_space_set_region_4(bus_space_tag_t tag, bus_space_handle_t bsh,
939		       bus_size_t offset, u_int32_t value, size_t count)
940{
941	bus_addr_t addr = bsh + offset;
942
943#if defined(_I386_BUS_PIO_H_)
944#if defined(_I386_BUS_MEMIO_H_)
945	if (tag == I386_BUS_SPACE_IO)
946#endif
947		for (; count != 0; count--, addr += 4)
948			outl(addr, value);
949#endif
950#if defined(_I386_BUS_MEMIO_H_)
951#if defined(_I386_BUS_PIO_H_)
952	else
953#endif
954		for (; count != 0; count--, addr += 4)
955			*(volatile u_int32_t *)(addr) = value;
956#endif
957}
958
959#if 0	/* Cause a link error for bus_space_set_region_8 */
960#define	bus_space_set_region_8	!!! bus_space_set_region_8 unimplemented !!!
961#endif
962
963/*
964 * Copy `count' 1, 2, 4, or 8 byte values from bus space starting
965 * at tag/bsh1/off1 to bus space starting at tag/bsh2/off2.
966 */
967
968static __inline void bus_space_copy_region_1(bus_space_tag_t tag,
969					     bus_space_handle_t bsh1,
970					     bus_size_t off1,
971					     bus_space_handle_t bsh2,
972					     bus_size_t off2, size_t count);
973
974static __inline void bus_space_copy_region_2(bus_space_tag_t tag,
975					     bus_space_handle_t bsh1,
976					     bus_size_t off1,
977					     bus_space_handle_t bsh2,
978					     bus_size_t off2, size_t count);
979
980static __inline void bus_space_copy_region_4(bus_space_tag_t tag,
981					     bus_space_handle_t bsh1,
982					     bus_size_t off1,
983					     bus_space_handle_t bsh2,
984					     bus_size_t off2, size_t count);
985
986static __inline void
987bus_space_copy_region_1(bus_space_tag_t tag, bus_space_handle_t bsh1,
988			bus_size_t off1, bus_space_handle_t bsh2,
989			bus_size_t off2, size_t count)
990{
991	bus_addr_t addr1 = bsh1 + off1;
992	bus_addr_t addr2 = bsh2 + off2;
993
994#if defined(_I386_BUS_PIO_H_)
995#if defined(_I386_BUS_MEMIO_H_)
996	if (tag == I386_BUS_SPACE_IO)
997#endif
998	{
999		if (addr1 >= addr2) {
1000			/* src after dest: copy forward */
1001			for (; count != 0; count--, addr1++, addr2++)
1002				outb(addr2, inb(addr1));
1003		} else {
1004			/* dest after src: copy backwards */
1005			for (addr1 += (count - 1), addr2 += (count - 1);
1006			    count != 0; count--, addr1--, addr2--)
1007				outb(addr2, inb(addr1));
1008		}
1009	}
1010#endif
1011#if defined(_I386_BUS_MEMIO_H_)
1012#if defined(_I386_BUS_PIO_H_)
1013	else
1014#endif
1015	{
1016		if (addr1 >= addr2) {
1017			/* src after dest: copy forward */
1018			for (; count != 0; count--, addr1++, addr2++)
1019				*(volatile u_int8_t *)(addr2) =
1020				    *(volatile u_int8_t *)(addr1);
1021		} else {
1022			/* dest after src: copy backwards */
1023			for (addr1 += (count - 1), addr2 += (count - 1);
1024			    count != 0; count--, addr1--, addr2--)
1025				*(volatile u_int8_t *)(addr2) =
1026				    *(volatile u_int8_t *)(addr1);
1027		}
1028	}
1029#endif
1030}
1031
1032static __inline void
1033bus_space_copy_region_2(bus_space_tag_t tag, bus_space_handle_t bsh1,
1034			bus_size_t off1, bus_space_handle_t bsh2,
1035			bus_size_t off2, size_t count)
1036{
1037	bus_addr_t addr1 = bsh1 + off1;
1038	bus_addr_t addr2 = bsh2 + off2;
1039
1040#if defined(_I386_BUS_PIO_H_)
1041#if defined(_I386_BUS_MEMIO_H_)
1042	if (tag == I386_BUS_SPACE_IO)
1043#endif
1044	{
1045		if (addr1 >= addr2) {
1046			/* src after dest: copy forward */
1047			for (; count != 0; count--, addr1 += 2, addr2 += 2)
1048				outw(addr2, inw(addr1));
1049		} else {
1050			/* dest after src: copy backwards */
1051			for (addr1 += 2 * (count - 1), addr2 += 2 * (count - 1);
1052			    count != 0; count--, addr1 -= 2, addr2 -= 2)
1053				outw(addr2, inw(addr1));
1054		}
1055	}
1056#endif
1057#if defined(_I386_BUS_MEMIO_H_)
1058#if defined(_I386_BUS_PIO_H_)
1059	else
1060#endif
1061	{
1062		if (addr1 >= addr2) {
1063			/* src after dest: copy forward */
1064			for (; count != 0; count--, addr1 += 2, addr2 += 2)
1065				*(volatile u_int16_t *)(addr2) =
1066				    *(volatile u_int16_t *)(addr1);
1067		} else {
1068			/* dest after src: copy backwards */
1069			for (addr1 += 2 * (count - 1), addr2 += 2 * (count - 1);
1070			    count != 0; count--, addr1 -= 2, addr2 -= 2)
1071				*(volatile u_int16_t *)(addr2) =
1072				    *(volatile u_int16_t *)(addr1);
1073		}
1074	}
1075#endif
1076}
1077
1078static __inline void
1079bus_space_copy_region_4(bus_space_tag_t tag, bus_space_handle_t bsh1,
1080			bus_size_t off1, bus_space_handle_t bsh2,
1081			bus_size_t off2, size_t count)
1082{
1083	bus_addr_t addr1 = bsh1 + off1;
1084	bus_addr_t addr2 = bsh2 + off2;
1085
1086#if defined(_I386_BUS_PIO_H_)
1087#if defined(_I386_BUS_MEMIO_H_)
1088	if (tag == I386_BUS_SPACE_IO)
1089#endif
1090	{
1091		if (addr1 >= addr2) {
1092			/* src after dest: copy forward */
1093			for (; count != 0; count--, addr1 += 4, addr2 += 4)
1094				outl(addr2, inl(addr1));
1095		} else {
1096			/* dest after src: copy backwards */
1097			for (addr1 += 4 * (count - 1), addr2 += 4 * (count - 1);
1098			    count != 0; count--, addr1 -= 4, addr2 -= 4)
1099				outl(addr2, inl(addr1));
1100		}
1101	}
1102#endif
1103#if defined(_I386_BUS_MEMIO_H_)
1104#if defined(_I386_BUS_PIO_H_)
1105	else
1106#endif
1107	{
1108		if (addr1 >= addr2) {
1109			/* src after dest: copy forward */
1110			for (; count != 0; count--, addr1 += 4, addr2 += 4)
1111				*(volatile u_int32_t *)(addr2) =
1112				    *(volatile u_int32_t *)(addr1);
1113		} else {
1114			/* dest after src: copy backwards */
1115			for (addr1 += 4 * (count - 1), addr2 += 4 * (count - 1);
1116			    count != 0; count--, addr1 -= 4, addr2 -= 4)
1117				*(volatile u_int32_t *)(addr2) =
1118				    *(volatile u_int32_t *)(addr1);
1119		}
1120	}
1121#endif
1122}
1123
1124#endif /* defined(_I386_BUS_PIO_H_) || defined(_I386_MEM_IO_H_) */
1125
1126#if 0	/* Cause a link error for bus_space_copy_8 */
1127#define	bus_space_copy_region_8	!!! bus_space_copy_region_8 unimplemented !!!
1128#endif
1129
1130/*
1131 * Bus read/write barrier methods.
1132 *
1133 *	void bus_space_barrier(bus_space_tag_t tag, bus_space_handle_t bsh,
1134 *			       bus_size_t offset, bus_size_t len, int flags);
1135 *
1136 * Note: the i386 does not currently require barriers, but we must
1137 * provide the flags to MI code.
1138 */
1139#define	bus_space_barrier(t, h, o, l, f)	\
1140	((void)((void)(t), (void)(h), (void)(o), (void)(l), (void)(f)))
1141#define	BUS_SPACE_BARRIER_READ	0x01		/* force read barrier */
1142#define	BUS_SPACE_BARRIER_WRITE	0x02		/* force write barrier */
1143
1144/*
1145 * Flags used in various bus DMA methods.
1146 */
1147#define	BUS_DMA_WAITOK		0x00	/* safe to sleep (pseudo-flag) */
1148#define	BUS_DMA_NOWAIT		0x01	/* not safe to sleep */
1149#define	BUS_DMA_ALLOCNOW	0x02	/* perform resource allocation now */
1150#define	BUS_DMAMEM_NOSYNC	0x04	/* map memory to not require sync */
1151#define	BUS_DMA_BUS1		0x10	/* placeholders for bus functions... */
1152#define	BUS_DMA_BUS2		0x20
1153#define	BUS_DMA_BUS3		0x40
1154#define	BUS_DMA_BUS4		0x80
1155
1156/* Forwards needed by prototypes below. */
1157struct mbuf;
1158struct uio;
1159
1160/*
1161 *	bus_dmasync_op_t
1162 *
1163 *	Operations performed by bus_dmamap_sync().
1164 */
1165typedef enum {
1166	BUS_DMASYNC_PREREAD,
1167	BUS_DMASYNC_POSTREAD,
1168	BUS_DMASYNC_PREWRITE,
1169	BUS_DMASYNC_POSTWRITE
1170} bus_dmasync_op_t;
1171
1172/*
1173 *	bus_dma_tag_t
1174 *
1175 *	A machine-dependent opaque type describing the characteristics
1176 *	of how to perform DMA mappings.  This structure encapsultes
1177 *	information concerning address and alignment restrictions, number
1178 *	of S/G	segments, amount of data per S/G segment, etc.
1179 */
1180typedef struct bus_dma_tag	*bus_dma_tag_t;
1181
1182/*
1183 *	bus_dmamap_t
1184 *
1185 *	DMA mapping instance information.
1186 */
1187typedef struct bus_dmamap	*bus_dmamap_t;
1188
1189/*
1190 *	bus_dma_segment_t
1191 *
1192 *	Describes a single contiguous DMA transaction.  Values
1193 *	are suitable for programming into DMA registers.
1194 */
1195typedef struct bus_dma_segment {
1196	bus_addr_t	ds_addr;	/* DMA address */
1197	bus_size_t	ds_len;		/* length of transfer */
1198} bus_dma_segment_t;
1199
1200/*
1201 * A function that returns 1 if the address cannot be accessed by
1202 * a device and 0 if it can be.
1203 */
1204typedef int bus_dma_filter_t(void *, bus_addr_t);
1205
1206/*
1207 * Allocate a device specific dma_tag encapsulating the constraints of
1208 * the parent tag in addition to other restrictions specified:
1209 *
1210 *	alignment:	alignment for segments.
1211 *	boundary:	Boundary that segments cannot cross.
1212 *	lowaddr:	Low restricted address that cannot appear in a mapping.
1213 *	highaddr:	High restricted address that cannot appear in a mapping.
1214 *	filtfunc:	An optional function to further test if an address
1215 *			within the range of lowaddr and highaddr cannot appear
1216 *			in a mapping.
1217 *	filtfuncarg:	An argument that will be passed to filtfunc in addition
1218 *			to the address to test.
1219 *	maxsize:	Maximum mapping size supported by this tag.
1220 *	nsegments:	Number of discontinuities allowed in maps.
1221 *	maxsegsz:	Maximum size of a segment in the map.
1222 *	flags:		Bus DMA flags.
1223 *	dmat:		A pointer to set to a valid dma tag should the return
1224 *			value of this function indicate success.
1225 */
1226/* XXX Should probably allow specification of alignment */
1227int bus_dma_tag_create(bus_dma_tag_t parent, bus_size_t alignemnt,
1228		       bus_size_t boundary, bus_addr_t lowaddr,
1229		       bus_addr_t highaddr, bus_dma_filter_t *filtfunc,
1230		       void *filtfuncarg, bus_size_t maxsize, int nsegments,
1231		       bus_size_t maxsegsz, int flags, bus_dma_tag_t *dmat);
1232
1233int bus_dma_tag_destroy(bus_dma_tag_t dmat);
1234
1235/*
1236 * Allocate a handle for mapping from kva/uva/physical
1237 * address space into bus device space.
1238 */
1239int bus_dmamap_create(bus_dma_tag_t dmat, int flags, bus_dmamap_t *mapp);
1240
1241/*
1242 * Destroy  a handle for mapping from kva/uva/physical
1243 * address space into bus device space.
1244 */
1245int bus_dmamap_destroy(bus_dma_tag_t dmat, bus_dmamap_t map);
1246
1247/*
1248 * Allocate a piece of memory that can be efficiently mapped into
1249 * bus device space based on the constraints lited in the dma tag.
1250 * A dmamap to for use with dmamap_load is also allocated.
1251 */
1252int bus_dmamem_alloc(bus_dma_tag_t dmat, void** vaddr, int flags,
1253		     bus_dmamap_t *mapp);
1254
1255/*
1256 * Free a piece of memory and it's allociated dmamap, that was allocated
1257 * via bus_dmamem_alloc.
1258 */
1259void bus_dmamem_free(bus_dma_tag_t dmat, void *vaddr, bus_dmamap_t map);
1260
1261/*
1262 * A function that processes a successfully loaded dma map or an error
1263 * from a delayed load map.
1264 */
1265typedef void bus_dmamap_callback_t(void *, bus_dma_segment_t *, int, int);
1266
1267/*
1268 * Map the buffer buf into bus space using the dmamap map.
1269 */
1270int bus_dmamap_load(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf,
1271		    bus_size_t buflen, bus_dmamap_callback_t *callback,
1272		    void *callback_arg, int flags);
1273
1274/*
1275 * Perform a syncronization operation on the given map.
1276 */
1277void _bus_dmamap_sync(bus_dma_tag_t, bus_dmamap_t, bus_dmasync_op_t);
1278#define bus_dmamap_sync(dmat, dmamap, op) 		\
1279	if ((dmamap) != NULL)				\
1280		_bus_dmamap_sync(dmat, dmamap, op)
1281
1282/*
1283 * Release the mapping held by map.
1284 */
1285void _bus_dmamap_unload(bus_dma_tag_t dmat, bus_dmamap_t map);
1286#define bus_dmamap_unload(dmat, dmamap) 		\
1287	if ((dmamap) != NULL)				\
1288		_bus_dmamap_unload(dmat, dmamap)
1289
1290#endif /* _I386_BUS_H_ */
1291