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