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