bus.h revision 241374
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/x86/include/bus.h 241374 2012-10-09 14:32:30Z attilio $
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 _X86_BUS_H_
105#define _X86_BUS_H_
106
107#include <machine/_bus.h>
108#include <machine/cpufunc.h>
109
110#ifndef __GNUCLIKE_ASM
111# ifndef lint
112#  error "no assembler code for your compiler"
113# endif
114#endif
115
116/*
117 * Values for the x86 bus space tag, not to be used directly by MI code.
118 */
119#define	X86_BUS_SPACE_IO	0	/* space is i/o space */
120#define	X86_BUS_SPACE_MEM	1	/* space is mem space */
121
122#define BUS_SPACE_MAXSIZE_24BIT	0xFFFFFF
123#define BUS_SPACE_MAXSIZE_32BIT 0xFFFFFFFF
124#define BUS_SPACE_MAXSIZE	0xFFFFFFFF
125#define BUS_SPACE_MAXADDR_24BIT	0xFFFFFF
126#define BUS_SPACE_MAXADDR_32BIT 0xFFFFFFFF
127#if defined(__amd64__) || defined(PAE)
128#define BUS_SPACE_MAXADDR	0xFFFFFFFFFFFFFFFFULL
129#else
130#define BUS_SPACE_MAXADDR	0xFFFFFFFF
131#endif
132
133#define BUS_SPACE_UNRESTRICTED	(~0)
134
135/*
136 * Map a region of device bus space into CPU virtual address space.
137 */
138
139static __inline int bus_space_map(bus_space_tag_t t, bus_addr_t addr,
140				  bus_size_t size, int flags,
141				  bus_space_handle_t *bshp);
142
143static __inline int
144bus_space_map(bus_space_tag_t t __unused, bus_addr_t addr,
145	      bus_size_t size __unused, int flags __unused,
146	      bus_space_handle_t *bshp)
147{
148
149	*bshp = addr;
150	return (0);
151}
152
153/*
154 * Unmap a region of device bus space.
155 */
156
157static __inline void bus_space_unmap(bus_space_tag_t t, bus_space_handle_t bsh,
158				     bus_size_t size);
159
160static __inline void
161bus_space_unmap(bus_space_tag_t t __unused, bus_space_handle_t bsh __unused,
162		bus_size_t size __unused)
163{
164}
165
166/*
167 * Get a new handle for a subregion of an already-mapped area of bus space.
168 */
169
170static __inline int bus_space_subregion(bus_space_tag_t t,
171					bus_space_handle_t bsh,
172					bus_size_t offset, bus_size_t size,
173					bus_space_handle_t *nbshp);
174
175static __inline int
176bus_space_subregion(bus_space_tag_t t __unused, bus_space_handle_t bsh,
177		    bus_size_t offset, bus_size_t size __unused,
178		    bus_space_handle_t *nbshp)
179{
180
181	*nbshp = bsh + offset;
182	return (0);
183}
184
185/*
186 * Allocate a region of memory that is accessible to devices in bus space.
187 */
188
189int	bus_space_alloc(bus_space_tag_t t, bus_addr_t rstart,
190			bus_addr_t rend, bus_size_t size, bus_size_t align,
191			bus_size_t boundary, int flags, bus_addr_t *addrp,
192			bus_space_handle_t *bshp);
193
194/*
195 * Free a region of bus space accessible memory.
196 */
197
198static __inline void bus_space_free(bus_space_tag_t t, bus_space_handle_t bsh,
199				    bus_size_t size);
200
201static __inline void
202bus_space_free(bus_space_tag_t t __unused, bus_space_handle_t bsh __unused,
203	       bus_size_t size __unused)
204{
205}
206
207
208/*
209 * Read a 1, 2, 4, or 8 byte quantity from bus space
210 * described by tag/handle/offset.
211 */
212static __inline u_int8_t bus_space_read_1(bus_space_tag_t tag,
213					  bus_space_handle_t handle,
214					  bus_size_t offset);
215
216static __inline u_int16_t bus_space_read_2(bus_space_tag_t tag,
217					   bus_space_handle_t handle,
218					   bus_size_t offset);
219
220static __inline u_int32_t bus_space_read_4(bus_space_tag_t tag,
221					   bus_space_handle_t handle,
222					   bus_size_t offset);
223
224static __inline u_int8_t
225bus_space_read_1(bus_space_tag_t tag, bus_space_handle_t handle,
226		 bus_size_t offset)
227{
228
229	if (tag == X86_BUS_SPACE_IO)
230		return (inb(handle + offset));
231	return (*(volatile u_int8_t *)(handle + offset));
232}
233
234static __inline u_int16_t
235bus_space_read_2(bus_space_tag_t tag, bus_space_handle_t handle,
236		 bus_size_t offset)
237{
238
239	if (tag == X86_BUS_SPACE_IO)
240		return (inw(handle + offset));
241	return (*(volatile u_int16_t *)(handle + offset));
242}
243
244static __inline u_int32_t
245bus_space_read_4(bus_space_tag_t tag, bus_space_handle_t handle,
246		 bus_size_t offset)
247{
248
249	if (tag == X86_BUS_SPACE_IO)
250		return (inl(handle + offset));
251	return (*(volatile u_int32_t *)(handle + offset));
252}
253
254#if 0	/* Cause a link error for bus_space_read_8 */
255#define	bus_space_read_8(t, h, o)	!!! bus_space_read_8 unimplemented !!!
256#endif
257
258/*
259 * Read `count' 1, 2, 4, or 8 byte quantities from bus space
260 * described by tag/handle/offset and copy into buffer provided.
261 */
262static __inline void bus_space_read_multi_1(bus_space_tag_t tag,
263					    bus_space_handle_t bsh,
264					    bus_size_t offset, u_int8_t *addr,
265					    size_t count);
266
267static __inline void bus_space_read_multi_2(bus_space_tag_t tag,
268					    bus_space_handle_t bsh,
269					    bus_size_t offset, u_int16_t *addr,
270					    size_t count);
271
272static __inline void bus_space_read_multi_4(bus_space_tag_t tag,
273					    bus_space_handle_t bsh,
274					    bus_size_t offset, u_int32_t *addr,
275					    size_t count);
276
277static __inline void
278bus_space_read_multi_1(bus_space_tag_t tag, bus_space_handle_t bsh,
279		       bus_size_t offset, u_int8_t *addr, size_t count)
280{
281
282	if (tag == X86_BUS_SPACE_IO)
283		insb(bsh + offset, addr, count);
284	else {
285#ifdef __GNUCLIKE_ASM
286		__asm __volatile("				\n\
287			cld					\n\
288		1:	movb (%2),%%al				\n\
289			stosb					\n\
290			loop 1b"				:
291		    "=D" (addr), "=c" (count)			:
292		    "r" (bsh + offset), "0" (addr), "1" (count)	:
293		    "%eax", "memory");
294#endif
295	}
296}
297
298static __inline void
299bus_space_read_multi_2(bus_space_tag_t tag, bus_space_handle_t bsh,
300		       bus_size_t offset, u_int16_t *addr, size_t count)
301{
302
303	if (tag == X86_BUS_SPACE_IO)
304		insw(bsh + offset, addr, count);
305	else {
306#ifdef __GNUCLIKE_ASM
307		__asm __volatile("				\n\
308			cld					\n\
309		1:	movw (%2),%%ax				\n\
310			stosw					\n\
311			loop 1b"				:
312		    "=D" (addr), "=c" (count)			:
313		    "r" (bsh + offset), "0" (addr), "1" (count)	:
314		    "%eax", "memory");
315#endif
316	}
317}
318
319static __inline void
320bus_space_read_multi_4(bus_space_tag_t tag, bus_space_handle_t bsh,
321		       bus_size_t offset, u_int32_t *addr, size_t count)
322{
323
324	if (tag == X86_BUS_SPACE_IO)
325		insl(bsh + offset, addr, count);
326	else {
327#ifdef __GNUCLIKE_ASM
328		__asm __volatile("				\n\
329			cld					\n\
330		1:	movl (%2),%%eax				\n\
331			stosl					\n\
332			loop 1b"				:
333		    "=D" (addr), "=c" (count)			:
334		    "r" (bsh + offset), "0" (addr), "1" (count)	:
335		    "%eax", "memory");
336#endif
337	}
338}
339
340#if 0	/* Cause a link error for bus_space_read_multi_8 */
341#define	bus_space_read_multi_8	!!! bus_space_read_multi_8 unimplemented !!!
342#endif
343
344/*
345 * Read `count' 1, 2, 4, or 8 byte quantities from bus space
346 * described by tag/handle and starting at `offset' and copy into
347 * buffer provided.
348 */
349static __inline void bus_space_read_region_1(bus_space_tag_t tag,
350					     bus_space_handle_t bsh,
351					     bus_size_t offset, u_int8_t *addr,
352					     size_t count);
353
354static __inline void bus_space_read_region_2(bus_space_tag_t tag,
355					     bus_space_handle_t bsh,
356					     bus_size_t offset, u_int16_t *addr,
357					     size_t count);
358
359static __inline void bus_space_read_region_4(bus_space_tag_t tag,
360					     bus_space_handle_t bsh,
361					     bus_size_t offset, u_int32_t *addr,
362					     size_t count);
363
364
365static __inline void
366bus_space_read_region_1(bus_space_tag_t tag, bus_space_handle_t bsh,
367			bus_size_t offset, u_int8_t *addr, size_t count)
368{
369
370	if (tag == X86_BUS_SPACE_IO) {
371		int _port_ = bsh + offset;
372#ifdef __GNUCLIKE_ASM
373		__asm __volatile("				\n\
374			cld					\n\
375		1:	inb %w2,%%al				\n\
376			stosb					\n\
377			incl %2					\n\
378			loop 1b"				:
379		    "=D" (addr), "=c" (count), "=d" (_port_)	:
380		    "0" (addr), "1" (count), "2" (_port_)	:
381		    "%eax", "memory", "cc");
382#endif
383	} else {
384		bus_space_handle_t _port_ = bsh + offset;
385#ifdef __GNUCLIKE_ASM
386		__asm __volatile("				\n\
387			cld					\n\
388			repne					\n\
389			movsb"					:
390		    "=D" (addr), "=c" (count), "=S" (_port_)	:
391		    "0" (addr), "1" (count), "2" (_port_)	:
392		    "memory", "cc");
393#endif
394	}
395}
396
397static __inline void
398bus_space_read_region_2(bus_space_tag_t tag, bus_space_handle_t bsh,
399			bus_size_t offset, u_int16_t *addr, size_t count)
400{
401
402	if (tag == X86_BUS_SPACE_IO) {
403		int _port_ = bsh + offset;
404#ifdef __GNUCLIKE_ASM
405		__asm __volatile("				\n\
406			cld					\n\
407		1:	inw %w2,%%ax				\n\
408			stosw					\n\
409			addl $2,%2				\n\
410			loop 1b"				:
411		    "=D" (addr), "=c" (count), "=d" (_port_)	:
412		    "0" (addr), "1" (count), "2" (_port_)	:
413		    "%eax", "memory", "cc");
414#endif
415	} else {
416		bus_space_handle_t _port_ = bsh + offset;
417#ifdef __GNUCLIKE_ASM
418		__asm __volatile("				\n\
419			cld					\n\
420			repne					\n\
421			movsw"					:
422		    "=D" (addr), "=c" (count), "=S" (_port_)	:
423		    "0" (addr), "1" (count), "2" (_port_)	:
424		    "memory", "cc");
425#endif
426	}
427}
428
429static __inline void
430bus_space_read_region_4(bus_space_tag_t tag, bus_space_handle_t bsh,
431			bus_size_t offset, u_int32_t *addr, size_t count)
432{
433
434	if (tag == X86_BUS_SPACE_IO) {
435		int _port_ = bsh + offset;
436#ifdef __GNUCLIKE_ASM
437		__asm __volatile("				\n\
438			cld					\n\
439		1:	inl %w2,%%eax				\n\
440			stosl					\n\
441			addl $4,%2				\n\
442			loop 1b"				:
443		    "=D" (addr), "=c" (count), "=d" (_port_)	:
444		    "0" (addr), "1" (count), "2" (_port_)	:
445		    "%eax", "memory", "cc");
446#endif
447	} else {
448		bus_space_handle_t _port_ = bsh + offset;
449#ifdef __GNUCLIKE_ASM
450		__asm __volatile("				\n\
451			cld					\n\
452			repne					\n\
453			movsl"					:
454		    "=D" (addr), "=c" (count), "=S" (_port_)	:
455		    "0" (addr), "1" (count), "2" (_port_)	:
456		    "memory", "cc");
457#endif
458	}
459}
460
461#if 0	/* Cause a link error for bus_space_read_region_8 */
462#define	bus_space_read_region_8	!!! bus_space_read_region_8 unimplemented !!!
463#endif
464
465/*
466 * Write the 1, 2, 4, or 8 byte value `value' to bus space
467 * described by tag/handle/offset.
468 */
469
470static __inline void bus_space_write_1(bus_space_tag_t tag,
471				       bus_space_handle_t bsh,
472				       bus_size_t offset, u_int8_t value);
473
474static __inline void bus_space_write_2(bus_space_tag_t tag,
475				       bus_space_handle_t bsh,
476				       bus_size_t offset, u_int16_t value);
477
478static __inline void bus_space_write_4(bus_space_tag_t tag,
479				       bus_space_handle_t bsh,
480				       bus_size_t offset, u_int32_t value);
481
482static __inline void
483bus_space_write_1(bus_space_tag_t tag, bus_space_handle_t bsh,
484		       bus_size_t offset, u_int8_t value)
485{
486
487	if (tag == X86_BUS_SPACE_IO)
488		outb(bsh + offset, value);
489	else
490		*(volatile u_int8_t *)(bsh + offset) = value;
491}
492
493static __inline void
494bus_space_write_2(bus_space_tag_t tag, bus_space_handle_t bsh,
495		       bus_size_t offset, u_int16_t value)
496{
497
498	if (tag == X86_BUS_SPACE_IO)
499		outw(bsh + offset, value);
500	else
501		*(volatile u_int16_t *)(bsh + offset) = value;
502}
503
504static __inline void
505bus_space_write_4(bus_space_tag_t tag, bus_space_handle_t bsh,
506		       bus_size_t offset, u_int32_t value)
507{
508
509	if (tag == X86_BUS_SPACE_IO)
510		outl(bsh + offset, value);
511	else
512		*(volatile u_int32_t *)(bsh + offset) = value;
513}
514
515#if 0	/* Cause a link error for bus_space_write_8 */
516#define	bus_space_write_8	!!! bus_space_write_8 not implemented !!!
517#endif
518
519/*
520 * Write `count' 1, 2, 4, or 8 byte quantities from the buffer
521 * provided to bus space described by tag/handle/offset.
522 */
523
524static __inline void bus_space_write_multi_1(bus_space_tag_t tag,
525					     bus_space_handle_t bsh,
526					     bus_size_t offset,
527					     const u_int8_t *addr,
528					     size_t count);
529static __inline void bus_space_write_multi_2(bus_space_tag_t tag,
530					     bus_space_handle_t bsh,
531					     bus_size_t offset,
532					     const u_int16_t *addr,
533					     size_t count);
534
535static __inline void bus_space_write_multi_4(bus_space_tag_t tag,
536					     bus_space_handle_t bsh,
537					     bus_size_t offset,
538					     const u_int32_t *addr,
539					     size_t count);
540
541static __inline void
542bus_space_write_multi_1(bus_space_tag_t tag, bus_space_handle_t bsh,
543			bus_size_t offset, const u_int8_t *addr, size_t count)
544{
545
546	if (tag == X86_BUS_SPACE_IO)
547		outsb(bsh + offset, addr, count);
548	else {
549#ifdef __GNUCLIKE_ASM
550		__asm __volatile("				\n\
551			cld					\n\
552		1:	lodsb					\n\
553			movb %%al,(%2)				\n\
554			loop 1b"				:
555		    "=S" (addr), "=c" (count)			:
556		    "r" (bsh + offset), "0" (addr), "1" (count)	:
557		    "%eax", "memory", "cc");
558#endif
559	}
560}
561
562static __inline void
563bus_space_write_multi_2(bus_space_tag_t tag, bus_space_handle_t bsh,
564			bus_size_t offset, const u_int16_t *addr, size_t count)
565{
566
567	if (tag == X86_BUS_SPACE_IO)
568		outsw(bsh + offset, addr, count);
569	else {
570#ifdef __GNUCLIKE_ASM
571		__asm __volatile("				\n\
572			cld					\n\
573		1:	lodsw					\n\
574			movw %%ax,(%2)				\n\
575			loop 1b"				:
576		    "=S" (addr), "=c" (count)			:
577		    "r" (bsh + offset), "0" (addr), "1" (count)	:
578		    "%eax", "memory", "cc");
579#endif
580	}
581}
582
583static __inline void
584bus_space_write_multi_4(bus_space_tag_t tag, bus_space_handle_t bsh,
585			bus_size_t offset, const u_int32_t *addr, size_t count)
586{
587
588	if (tag == X86_BUS_SPACE_IO)
589		outsl(bsh + offset, addr, count);
590	else {
591#ifdef __GNUCLIKE_ASM
592		__asm __volatile("				\n\
593			cld					\n\
594		1:	lodsl					\n\
595			movl %%eax,(%2)				\n\
596			loop 1b"				:
597		    "=S" (addr), "=c" (count)			:
598		    "r" (bsh + offset), "0" (addr), "1" (count)	:
599		    "%eax", "memory", "cc");
600#endif
601	}
602}
603
604#if 0	/* Cause a link error for bus_space_write_multi_8 */
605#define	bus_space_write_multi_8(t, h, o, a, c)				\
606			!!! bus_space_write_multi_8 unimplemented !!!
607#endif
608
609/*
610 * Write `count' 1, 2, 4, or 8 byte quantities from the buffer provided
611 * to bus space described by tag/handle starting at `offset'.
612 */
613
614static __inline void bus_space_write_region_1(bus_space_tag_t tag,
615					      bus_space_handle_t bsh,
616					      bus_size_t offset,
617					      const u_int8_t *addr,
618					      size_t count);
619static __inline void bus_space_write_region_2(bus_space_tag_t tag,
620					      bus_space_handle_t bsh,
621					      bus_size_t offset,
622					      const u_int16_t *addr,
623					      size_t count);
624static __inline void bus_space_write_region_4(bus_space_tag_t tag,
625					      bus_space_handle_t bsh,
626					      bus_size_t offset,
627					      const u_int32_t *addr,
628					      size_t count);
629
630static __inline void
631bus_space_write_region_1(bus_space_tag_t tag, bus_space_handle_t bsh,
632			 bus_size_t offset, const u_int8_t *addr, size_t count)
633{
634
635	if (tag == X86_BUS_SPACE_IO) {
636		int _port_ = bsh + offset;
637#ifdef __GNUCLIKE_ASM
638		__asm __volatile("				\n\
639			cld					\n\
640		1:	lodsb					\n\
641			outb %%al,%w0				\n\
642			incl %0					\n\
643			loop 1b"				:
644		    "=d" (_port_), "=S" (addr), "=c" (count)	:
645		    "0" (_port_), "1" (addr), "2" (count)	:
646		    "%eax", "memory", "cc");
647#endif
648	} else {
649		bus_space_handle_t _port_ = bsh + offset;
650#ifdef __GNUCLIKE_ASM
651		__asm __volatile("				\n\
652			cld					\n\
653			repne					\n\
654			movsb"					:
655		    "=D" (_port_), "=S" (addr), "=c" (count)	:
656		    "0" (_port_), "1" (addr), "2" (count)	:
657		    "memory", "cc");
658#endif
659	}
660}
661
662static __inline void
663bus_space_write_region_2(bus_space_tag_t tag, bus_space_handle_t bsh,
664			 bus_size_t offset, const u_int16_t *addr, size_t count)
665{
666
667	if (tag == X86_BUS_SPACE_IO) {
668		int _port_ = bsh + offset;
669#ifdef __GNUCLIKE_ASM
670		__asm __volatile("				\n\
671			cld					\n\
672		1:	lodsw					\n\
673			outw %%ax,%w0				\n\
674			addl $2,%0				\n\
675			loop 1b"				:
676		    "=d" (_port_), "=S" (addr), "=c" (count)	:
677		    "0" (_port_), "1" (addr), "2" (count)	:
678		    "%eax", "memory", "cc");
679#endif
680	} else {
681		bus_space_handle_t _port_ = bsh + offset;
682#ifdef __GNUCLIKE_ASM
683		__asm __volatile("				\n\
684			cld					\n\
685			repne					\n\
686			movsw"					:
687		    "=D" (_port_), "=S" (addr), "=c" (count)	:
688		    "0" (_port_), "1" (addr), "2" (count)	:
689		    "memory", "cc");
690#endif
691	}
692}
693
694static __inline void
695bus_space_write_region_4(bus_space_tag_t tag, bus_space_handle_t bsh,
696			 bus_size_t offset, const u_int32_t *addr, size_t count)
697{
698
699	if (tag == X86_BUS_SPACE_IO) {
700		int _port_ = bsh + offset;
701#ifdef __GNUCLIKE_ASM
702		__asm __volatile("				\n\
703			cld					\n\
704		1:	lodsl					\n\
705			outl %%eax,%w0				\n\
706			addl $4,%0				\n\
707			loop 1b"				:
708		    "=d" (_port_), "=S" (addr), "=c" (count)	:
709		    "0" (_port_), "1" (addr), "2" (count)	:
710		    "%eax", "memory", "cc");
711#endif
712	} else {
713		bus_space_handle_t _port_ = bsh + offset;
714#ifdef __GNUCLIKE_ASM
715		__asm __volatile("				\n\
716			cld					\n\
717			repne					\n\
718			movsl"					:
719		    "=D" (_port_), "=S" (addr), "=c" (count)	:
720		    "0" (_port_), "1" (addr), "2" (count)	:
721		    "memory", "cc");
722#endif
723	}
724}
725
726#if 0	/* Cause a link error for bus_space_write_region_8 */
727#define	bus_space_write_region_8					\
728			!!! bus_space_write_region_8 unimplemented !!!
729#endif
730
731/*
732 * Write the 1, 2, 4, or 8 byte value `val' to bus space described
733 * by tag/handle/offset `count' times.
734 */
735
736static __inline void bus_space_set_multi_1(bus_space_tag_t tag,
737					   bus_space_handle_t bsh,
738					   bus_size_t offset,
739					   u_int8_t value, size_t count);
740static __inline void bus_space_set_multi_2(bus_space_tag_t tag,
741					   bus_space_handle_t bsh,
742					   bus_size_t offset,
743					   u_int16_t value, size_t count);
744static __inline void bus_space_set_multi_4(bus_space_tag_t tag,
745					   bus_space_handle_t bsh,
746					   bus_size_t offset,
747					   u_int32_t value, size_t count);
748
749static __inline void
750bus_space_set_multi_1(bus_space_tag_t tag, bus_space_handle_t bsh,
751		      bus_size_t offset, u_int8_t value, size_t count)
752{
753	bus_space_handle_t addr = bsh + offset;
754
755	if (tag == X86_BUS_SPACE_IO)
756		while (count--)
757			outb(addr, value);
758	else
759		while (count--)
760			*(volatile u_int8_t *)(addr) = value;
761}
762
763static __inline void
764bus_space_set_multi_2(bus_space_tag_t tag, bus_space_handle_t bsh,
765		     bus_size_t offset, u_int16_t value, size_t count)
766{
767	bus_space_handle_t addr = bsh + offset;
768
769	if (tag == X86_BUS_SPACE_IO)
770		while (count--)
771			outw(addr, value);
772	else
773		while (count--)
774			*(volatile u_int16_t *)(addr) = value;
775}
776
777static __inline void
778bus_space_set_multi_4(bus_space_tag_t tag, bus_space_handle_t bsh,
779		      bus_size_t offset, u_int32_t value, size_t count)
780{
781	bus_space_handle_t addr = bsh + offset;
782
783	if (tag == X86_BUS_SPACE_IO)
784		while (count--)
785			outl(addr, value);
786	else
787		while (count--)
788			*(volatile u_int32_t *)(addr) = value;
789}
790
791#if 0	/* Cause a link error for bus_space_set_multi_8 */
792#define	bus_space_set_multi_8 !!! bus_space_set_multi_8 unimplemented !!!
793#endif
794
795/*
796 * Write `count' 1, 2, 4, or 8 byte value `val' to bus space described
797 * by tag/handle starting at `offset'.
798 */
799
800static __inline void bus_space_set_region_1(bus_space_tag_t tag,
801					    bus_space_handle_t bsh,
802					    bus_size_t offset, u_int8_t value,
803					    size_t count);
804static __inline void bus_space_set_region_2(bus_space_tag_t tag,
805					    bus_space_handle_t bsh,
806					    bus_size_t offset, u_int16_t value,
807					    size_t count);
808static __inline void bus_space_set_region_4(bus_space_tag_t tag,
809					    bus_space_handle_t bsh,
810					    bus_size_t offset, u_int32_t value,
811					    size_t count);
812
813static __inline void
814bus_space_set_region_1(bus_space_tag_t tag, bus_space_handle_t bsh,
815		       bus_size_t offset, u_int8_t value, size_t count)
816{
817	bus_space_handle_t addr = bsh + offset;
818
819	if (tag == X86_BUS_SPACE_IO)
820		for (; count != 0; count--, addr++)
821			outb(addr, value);
822	else
823		for (; count != 0; count--, addr++)
824			*(volatile u_int8_t *)(addr) = value;
825}
826
827static __inline void
828bus_space_set_region_2(bus_space_tag_t tag, bus_space_handle_t bsh,
829		       bus_size_t offset, u_int16_t value, size_t count)
830{
831	bus_space_handle_t addr = bsh + offset;
832
833	if (tag == X86_BUS_SPACE_IO)
834		for (; count != 0; count--, addr += 2)
835			outw(addr, value);
836	else
837		for (; count != 0; count--, addr += 2)
838			*(volatile u_int16_t *)(addr) = value;
839}
840
841static __inline void
842bus_space_set_region_4(bus_space_tag_t tag, bus_space_handle_t bsh,
843		       bus_size_t offset, u_int32_t value, size_t count)
844{
845	bus_space_handle_t addr = bsh + offset;
846
847	if (tag == X86_BUS_SPACE_IO)
848		for (; count != 0; count--, addr += 4)
849			outl(addr, value);
850	else
851		for (; count != 0; count--, addr += 4)
852			*(volatile u_int32_t *)(addr) = value;
853}
854
855#if 0	/* Cause a link error for bus_space_set_region_8 */
856#define	bus_space_set_region_8	!!! bus_space_set_region_8 unimplemented !!!
857#endif
858
859/*
860 * Copy `count' 1, 2, 4, or 8 byte values from bus space starting
861 * at tag/bsh1/off1 to bus space starting at tag/bsh2/off2.
862 */
863
864static __inline void bus_space_copy_region_1(bus_space_tag_t tag,
865					     bus_space_handle_t bsh1,
866					     bus_size_t off1,
867					     bus_space_handle_t bsh2,
868					     bus_size_t off2, size_t count);
869
870static __inline void bus_space_copy_region_2(bus_space_tag_t tag,
871					     bus_space_handle_t bsh1,
872					     bus_size_t off1,
873					     bus_space_handle_t bsh2,
874					     bus_size_t off2, size_t count);
875
876static __inline void bus_space_copy_region_4(bus_space_tag_t tag,
877					     bus_space_handle_t bsh1,
878					     bus_size_t off1,
879					     bus_space_handle_t bsh2,
880					     bus_size_t off2, size_t count);
881
882static __inline void
883bus_space_copy_region_1(bus_space_tag_t tag, bus_space_handle_t bsh1,
884			bus_size_t off1, bus_space_handle_t bsh2,
885			bus_size_t off2, size_t count)
886{
887	bus_space_handle_t addr1 = bsh1 + off1;
888	bus_space_handle_t addr2 = bsh2 + off2;
889
890	if (tag == X86_BUS_SPACE_IO) {
891		if (addr1 >= addr2) {
892			/* src after dest: copy forward */
893			for (; count != 0; count--, addr1++, addr2++)
894				outb(addr2, inb(addr1));
895		} else {
896			/* dest after src: copy backwards */
897			for (addr1 += (count - 1), addr2 += (count - 1);
898			    count != 0; count--, addr1--, addr2--)
899				outb(addr2, inb(addr1));
900		}
901	} else {
902		if (addr1 >= addr2) {
903			/* src after dest: copy forward */
904			for (; count != 0; count--, addr1++, addr2++)
905				*(volatile u_int8_t *)(addr2) =
906				    *(volatile u_int8_t *)(addr1);
907		} else {
908			/* dest after src: copy backwards */
909			for (addr1 += (count - 1), addr2 += (count - 1);
910			    count != 0; count--, addr1--, addr2--)
911				*(volatile u_int8_t *)(addr2) =
912				    *(volatile u_int8_t *)(addr1);
913		}
914	}
915}
916
917static __inline void
918bus_space_copy_region_2(bus_space_tag_t tag, bus_space_handle_t bsh1,
919			bus_size_t off1, bus_space_handle_t bsh2,
920			bus_size_t off2, size_t count)
921{
922	bus_space_handle_t addr1 = bsh1 + off1;
923	bus_space_handle_t addr2 = bsh2 + off2;
924
925	if (tag == X86_BUS_SPACE_IO) {
926		if (addr1 >= addr2) {
927			/* src after dest: copy forward */
928			for (; count != 0; count--, addr1 += 2, addr2 += 2)
929				outw(addr2, inw(addr1));
930		} else {
931			/* dest after src: copy backwards */
932			for (addr1 += 2 * (count - 1), addr2 += 2 * (count - 1);
933			    count != 0; count--, addr1 -= 2, addr2 -= 2)
934				outw(addr2, inw(addr1));
935		}
936	} else {
937		if (addr1 >= addr2) {
938			/* src after dest: copy forward */
939			for (; count != 0; count--, addr1 += 2, addr2 += 2)
940				*(volatile u_int16_t *)(addr2) =
941				    *(volatile u_int16_t *)(addr1);
942		} else {
943			/* dest after src: copy backwards */
944			for (addr1 += 2 * (count - 1), addr2 += 2 * (count - 1);
945			    count != 0; count--, addr1 -= 2, addr2 -= 2)
946				*(volatile u_int16_t *)(addr2) =
947				    *(volatile u_int16_t *)(addr1);
948		}
949	}
950}
951
952static __inline void
953bus_space_copy_region_4(bus_space_tag_t tag, bus_space_handle_t bsh1,
954			bus_size_t off1, bus_space_handle_t bsh2,
955			bus_size_t off2, size_t count)
956{
957	bus_space_handle_t addr1 = bsh1 + off1;
958	bus_space_handle_t addr2 = bsh2 + off2;
959
960	if (tag == X86_BUS_SPACE_IO) {
961		if (addr1 >= addr2) {
962			/* src after dest: copy forward */
963			for (; count != 0; count--, addr1 += 4, addr2 += 4)
964				outl(addr2, inl(addr1));
965		} else {
966			/* dest after src: copy backwards */
967			for (addr1 += 4 * (count - 1), addr2 += 4 * (count - 1);
968			    count != 0; count--, addr1 -= 4, addr2 -= 4)
969				outl(addr2, inl(addr1));
970		}
971	} else {
972		if (addr1 >= addr2) {
973			/* src after dest: copy forward */
974			for (; count != 0; count--, addr1 += 4, addr2 += 4)
975				*(volatile u_int32_t *)(addr2) =
976				    *(volatile u_int32_t *)(addr1);
977		} else {
978			/* dest after src: copy backwards */
979			for (addr1 += 4 * (count - 1), addr2 += 4 * (count - 1);
980			    count != 0; count--, addr1 -= 4, addr2 -= 4)
981				*(volatile u_int32_t *)(addr2) =
982				    *(volatile u_int32_t *)(addr1);
983		}
984	}
985}
986
987#if 0	/* Cause a link error for bus_space_copy_8 */
988#define	bus_space_copy_region_8	!!! bus_space_copy_region_8 unimplemented !!!
989#endif
990
991/*
992 * Bus read/write barrier methods.
993 *
994 *	void bus_space_barrier(bus_space_tag_t tag, bus_space_handle_t bsh,
995 *			       bus_size_t offset, bus_size_t len, int flags);
996 *
997 *
998 * Note that BUS_SPACE_BARRIER_WRITE doesn't do anything other than
999 * prevent reordering by the compiler; all Intel x86 processors currently
1000 * retire operations outside the CPU in program order.
1001 */
1002#define	BUS_SPACE_BARRIER_READ	0x01		/* force read barrier */
1003#define	BUS_SPACE_BARRIER_WRITE	0x02		/* force write barrier */
1004
1005static __inline void
1006bus_space_barrier(bus_space_tag_t tag __unused, bus_space_handle_t bsh __unused,
1007		  bus_size_t offset __unused, bus_size_t len __unused, int flags)
1008{
1009#ifdef __GNUCLIKE_ASM
1010	if (flags & BUS_SPACE_BARRIER_READ)
1011#ifdef __amd64__
1012		__asm __volatile("lock; addl $0,0(%%rsp)" : : : "memory");
1013#else
1014		__asm __volatile("lock; addl $0,0(%%esp)" : : : "memory");
1015#endif
1016	else
1017		__compiler_membar();
1018#endif
1019}
1020
1021#ifdef BUS_SPACE_NO_LEGACY
1022#undef inb
1023#undef outb
1024#define inb(a) compiler_error
1025#define inw(a) compiler_error
1026#define inl(a) compiler_error
1027#define outb(a, b) compiler_error
1028#define outw(a, b) compiler_error
1029#define outl(a, b) compiler_error
1030#endif
1031
1032#include <machine/bus_dma.h>
1033
1034/*
1035 * Stream accesses are the same as normal accesses on x86; there are no
1036 * supported bus systems with an endianess different from the host one.
1037 */
1038#define	bus_space_read_stream_1(t, h, o)	bus_space_read_1((t), (h), (o))
1039#define	bus_space_read_stream_2(t, h, o)	bus_space_read_2((t), (h), (o))
1040#define	bus_space_read_stream_4(t, h, o)	bus_space_read_4((t), (h), (o))
1041
1042#define	bus_space_read_multi_stream_1(t, h, o, a, c) \
1043	bus_space_read_multi_1((t), (h), (o), (a), (c))
1044#define	bus_space_read_multi_stream_2(t, h, o, a, c) \
1045	bus_space_read_multi_2((t), (h), (o), (a), (c))
1046#define	bus_space_read_multi_stream_4(t, h, o, a, c) \
1047	bus_space_read_multi_4((t), (h), (o), (a), (c))
1048
1049#define	bus_space_write_stream_1(t, h, o, v) \
1050	bus_space_write_1((t), (h), (o), (v))
1051#define	bus_space_write_stream_2(t, h, o, v) \
1052	bus_space_write_2((t), (h), (o), (v))
1053#define	bus_space_write_stream_4(t, h, o, v) \
1054	bus_space_write_4((t), (h), (o), (v))
1055
1056#define	bus_space_write_multi_stream_1(t, h, o, a, c) \
1057	bus_space_write_multi_1((t), (h), (o), (a), (c))
1058#define	bus_space_write_multi_stream_2(t, h, o, a, c) \
1059	bus_space_write_multi_2((t), (h), (o), (a), (c))
1060#define	bus_space_write_multi_stream_4(t, h, o, a, c) \
1061	bus_space_write_multi_4((t), (h), (o), (a), (c))
1062
1063#define	bus_space_set_multi_stream_1(t, h, o, v, c) \
1064	bus_space_set_multi_1((t), (h), (o), (v), (c))
1065#define	bus_space_set_multi_stream_2(t, h, o, v, c) \
1066	bus_space_set_multi_2((t), (h), (o), (v), (c))
1067#define	bus_space_set_multi_stream_4(t, h, o, v, c) \
1068	bus_space_set_multi_4((t), (h), (o), (v), (c))
1069
1070#define	bus_space_read_region_stream_1(t, h, o, a, c) \
1071	bus_space_read_region_1((t), (h), (o), (a), (c))
1072#define	bus_space_read_region_stream_2(t, h, o, a, c) \
1073	bus_space_read_region_2((t), (h), (o), (a), (c))
1074#define	bus_space_read_region_stream_4(t, h, o, a, c) \
1075	bus_space_read_region_4((t), (h), (o), (a), (c))
1076
1077#define	bus_space_write_region_stream_1(t, h, o, a, c) \
1078	bus_space_write_region_1((t), (h), (o), (a), (c))
1079#define	bus_space_write_region_stream_2(t, h, o, a, c) \
1080	bus_space_write_region_2((t), (h), (o), (a), (c))
1081#define	bus_space_write_region_stream_4(t, h, o, a, c) \
1082	bus_space_write_region_4((t), (h), (o), (a), (c))
1083
1084#define	bus_space_set_region_stream_1(t, h, o, v, c) \
1085	bus_space_set_region_1((t), (h), (o), (v), (c))
1086#define	bus_space_set_region_stream_2(t, h, o, v, c) \
1087	bus_space_set_region_2((t), (h), (o), (v), (c))
1088#define	bus_space_set_region_stream_4(t, h, o, v, c) \
1089	bus_space_set_region_4((t), (h), (o), (v), (c))
1090
1091#define	bus_space_copy_region_stream_1(t, h1, o1, h2, o2, c) \
1092	bus_space_copy_region_1((t), (h1), (o1), (h2), (o2), (c))
1093#define	bus_space_copy_region_stream_2(t, h1, o1, h2, o2, c) \
1094	bus_space_copy_region_2((t), (h1), (o1), (h2), (o2), (c))
1095#define	bus_space_copy_region_stream_4(t, h1, o1, h2, o2, c) \
1096	bus_space_copy_region_4((t), (h1), (o1), (h2), (o2), (c))
1097
1098#endif /* _X86_BUS_H_ */
1099