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