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