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