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