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