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