Merge from vendor branch LESS:
[dragonfly.git] / sys / cpu / amd64 / include / bus_dma.h
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  * $DragonFly: src/sys/cpu/amd64/include/bus_dma.h,v 1.1 2007/09/23 04:29:30 yanyh Exp $
27  */
28
29 #ifndef _CPU_BUS_DMA_H_
30 #define _CPU_BUS_DMA_H_
31
32 #include <machine/cpufunc.h>
33
34 /*
35  * Bus address and size types
36  */
37
38 typedef uint64_t bus_addr_t;
39 typedef uint64_t bus_size_t;
40
41 typedef uint64_t bus_space_tag_t;
42 typedef uint64_t bus_space_handle_t;
43
44 #define BUS_SPACE_MAXSIZE_24BIT 0xFFFFFF
45 #define BUS_SPACE_MAXSIZE_32BIT 0xFFFFFFFF
46 #define BUS_SPACE_MAXSIZE       (64 * 1024) /* Maximum supported size */
47 #define BUS_SPACE_MAXADDR_24BIT 0xFFFFFF
48 #define BUS_SPACE_MAXADDR_32BIT 0xFFFFFFFF
49 #define BUS_SPACE_MAXADDR       BUS_SPACE_MAXADDR_32BIT
50
51 #define BUS_SPACE_UNRESTRICTED  (~0)
52
53 /*
54  * Values for the amd64 bus space tag, not to be used directly by MI code.
55  */
56 #define AMD64_BUS_SPACE_IO      0       /* space is i/o space */
57 #define AMD64_BUS_SPACE_MEM     1       /* space is mem space */
58
59 /*
60  * Map a region of device bus space into CPU virtual address space.
61  */
62
63 static __inline int bus_space_map(bus_space_tag_t t, bus_addr_t addr,
64                                   bus_size_t size, int flags,
65                                   bus_space_handle_t *bshp);
66
67 static __inline int
68 bus_space_map(bus_space_tag_t t __unused, bus_addr_t addr,
69               bus_size_t size __unused, int flags __unused,
70               bus_space_handle_t *bshp)
71 {
72
73         *bshp = addr;
74         return (0);
75 }
76
77 /*
78  * Unmap a region of device bus space.
79  */
80
81 static __inline void bus_space_unmap(bus_space_tag_t t, bus_space_handle_t bsh,
82                                      bus_size_t size);
83
84 static __inline void
85 bus_space_unmap(bus_space_tag_t t __unused, bus_space_handle_t bsh __unused,
86                 bus_size_t size __unused)
87 {
88 }
89
90 /*
91  * Get a new handle for a subregion of an already-mapped area of bus space.
92  */
93
94 static __inline int bus_space_subregion(bus_space_tag_t t,
95                                         bus_space_handle_t bsh,
96                                         bus_size_t offset, bus_size_t size,
97                                         bus_space_handle_t *nbshp);
98
99 static __inline int
100 bus_space_subregion(bus_space_tag_t t __unused, bus_space_handle_t bsh,
101                     bus_size_t offset, bus_size_t size __unused,
102                     bus_space_handle_t *nbshp)
103 {
104
105         *nbshp = bsh + offset;
106         return (0);
107 }
108
109 /*
110  * Allocate a region of memory that is accessible to devices in bus space.
111  */
112
113 int     bus_space_alloc(bus_space_tag_t t, bus_addr_t rstart,
114                         bus_addr_t rend, bus_size_t size, bus_size_t align,
115                         bus_size_t boundary, int flags, bus_addr_t *addrp,
116                         bus_space_handle_t *bshp);
117
118 /*
119  * Free a region of bus space accessible memory.
120  */
121
122 static __inline void bus_space_free(bus_space_tag_t t, bus_space_handle_t bsh,
123                                     bus_size_t size);
124
125 static __inline void
126 bus_space_free(bus_space_tag_t t __unused, bus_space_handle_t bsh __unused,
127                bus_size_t size __unused)
128 {
129 }
130
131
132 /*
133  * Read a 1, 2, 4, or 8 byte quantity from bus space
134  * described by tag/handle/offset.
135  */
136 static __inline u_int8_t bus_space_read_1(bus_space_tag_t tag,
137                                           bus_space_handle_t handle,
138                                           bus_size_t offset);
139
140 static __inline u_int16_t bus_space_read_2(bus_space_tag_t tag,
141                                            bus_space_handle_t handle,
142                                            bus_size_t offset);
143
144 static __inline u_int32_t bus_space_read_4(bus_space_tag_t tag,
145                                            bus_space_handle_t handle,
146                                            bus_size_t offset);
147
148 static __inline u_int8_t
149 bus_space_read_1(bus_space_tag_t tag, bus_space_handle_t handle,
150                  bus_size_t offset)
151 {
152
153         if (tag == AMD64_BUS_SPACE_IO)
154                 return (inb(handle + offset));
155         return (*(volatile u_int8_t *)(handle + offset));
156 }
157
158 static __inline u_int16_t
159 bus_space_read_2(bus_space_tag_t tag, bus_space_handle_t handle,
160                  bus_size_t offset)
161 {
162
163         if (tag == AMD64_BUS_SPACE_IO)
164                 return (inw(handle + offset));
165         return (*(volatile u_int16_t *)(handle + offset));
166 }
167
168 static __inline u_int32_t
169 bus_space_read_4(bus_space_tag_t tag, bus_space_handle_t handle,
170                  bus_size_t offset)
171 {
172
173         if (tag == AMD64_BUS_SPACE_IO)
174                 return (inl(handle + offset));
175         return (*(volatile u_int32_t *)(handle + offset));
176 }
177
178 #if 0   /* Cause a link error for bus_space_read_8 */
179 #define bus_space_read_8(t, h, o)       !!! bus_space_read_8 unimplemented !!!
180 #endif
181
182 /*
183  * Read `count' 1, 2, 4, or 8 byte quantities from bus space
184  * described by tag/handle/offset and copy into buffer provided.
185  */
186 static __inline void bus_space_read_multi_1(bus_space_tag_t tag,
187                                             bus_space_handle_t bsh,
188                                             bus_size_t offset, u_int8_t *addr,
189                                             size_t count);
190
191 static __inline void bus_space_read_multi_2(bus_space_tag_t tag,
192                                             bus_space_handle_t bsh,
193                                             bus_size_t offset, u_int16_t *addr,
194                                             size_t count);
195
196 static __inline void bus_space_read_multi_4(bus_space_tag_t tag,
197                                             bus_space_handle_t bsh,
198                                             bus_size_t offset, u_int32_t *addr,
199                                             size_t count);
200
201 static __inline void
202 bus_space_read_multi_1(bus_space_tag_t tag, bus_space_handle_t bsh,
203                        bus_size_t offset, u_int8_t *addr, size_t count)
204 {
205
206         if (tag == AMD64_BUS_SPACE_IO)
207                 insb(bsh + offset, addr, count);
208         else {
209                 __asm __volatile("                              \n\
210                         cld                                     \n\
211                 1:      movb (%2),%%al                          \n\
212                         stosb                                   \n\
213                         loop 1b"                                :
214                     "=D" (addr), "=c" (count)                   :
215                     "r" (bsh + offset), "0" (addr), "1" (count) :
216                     "%eax", "memory");
217         }
218 }
219
220 static __inline void
221 bus_space_read_multi_2(bus_space_tag_t tag, bus_space_handle_t bsh,
222                        bus_size_t offset, u_int16_t *addr, size_t count)
223 {
224
225         if (tag == AMD64_BUS_SPACE_IO)
226                 insw(bsh + offset, addr, count);
227         else {
228                 __asm __volatile("                              \n\
229                         cld                                     \n\
230                 1:      movw (%2),%%ax                          \n\
231                         stosw                                   \n\
232                         loop 1b"                                :
233                     "=D" (addr), "=c" (count)                   :
234                     "r" (bsh + offset), "0" (addr), "1" (count) :
235                     "%eax", "memory");
236         }
237 }
238
239 static __inline void
240 bus_space_read_multi_4(bus_space_tag_t tag, bus_space_handle_t bsh,
241                        bus_size_t offset, u_int32_t *addr, size_t count)
242 {
243
244         if (tag == AMD64_BUS_SPACE_IO)
245                 insl(bsh + offset, addr, count);
246         else {
247                 __asm __volatile("                              \n\
248                         cld                                     \n\
249                 1:      movl (%2),%%eax                         \n\
250                         stosl                                   \n\
251                         loop 1b"                                :
252                     "=D" (addr), "=c" (count)                   :
253                     "r" (bsh + offset), "0" (addr), "1" (count) :
254                     "%eax", "memory");
255         }
256 }
257
258 #if 0   /* Cause a link error for bus_space_read_multi_8 */
259 #define bus_space_read_multi_8  !!! bus_space_read_multi_8 unimplemented !!!
260 #endif
261
262 /*
263  * Read `count' 1, 2, 4, or 8 byte quantities from bus space
264  * described by tag/handle and starting at `offset' and copy into
265  * buffer provided.
266  */
267 static __inline void bus_space_read_region_1(bus_space_tag_t tag,
268                                              bus_space_handle_t bsh,
269                                              bus_size_t offset, u_int8_t *addr,
270                                              size_t count);
271
272 static __inline void bus_space_read_region_2(bus_space_tag_t tag,
273                                              bus_space_handle_t bsh,
274                                              bus_size_t offset, u_int16_t *addr,
275                                              size_t count);
276
277 static __inline void bus_space_read_region_4(bus_space_tag_t tag,
278                                              bus_space_handle_t bsh,
279                                              bus_size_t offset, u_int32_t *addr,
280                                              size_t count);
281
282
283 static __inline void
284 bus_space_read_region_1(bus_space_tag_t tag, bus_space_handle_t bsh,
285                         bus_size_t offset, u_int8_t *addr, size_t count)
286 {
287
288         if (tag == AMD64_BUS_SPACE_IO) {
289                 int _port_ = bsh + offset;
290                 __asm __volatile("                              \n\
291                         cld                                     \n\
292                 1:      inb %w2,%%al                            \n\
293                         stosb                                   \n\
294                         incl %2                                 \n\
295                         loop 1b"                                :
296                     "=D" (addr), "=c" (count), "=d" (_port_)    :
297                     "0" (addr), "1" (count), "2" (_port_)       :
298                     "%eax", "memory", "cc");
299         } else {
300                 bus_space_handle_t _port_ = bsh + offset;
301                 __asm __volatile("                              \n\
302                         cld                                     \n\
303                         repne                                   \n\
304                         movsb"                                  :
305                     "=D" (addr), "=c" (count), "=S" (_port_)    :
306                     "0" (addr), "1" (count), "2" (_port_)       :
307                     "memory", "cc");
308         }
309 }
310
311 static __inline void
312 bus_space_read_region_2(bus_space_tag_t tag, bus_space_handle_t bsh,
313                         bus_size_t offset, u_int16_t *addr, size_t count)
314 {
315
316         if (tag == AMD64_BUS_SPACE_IO) {
317                 int _port_ = bsh + offset;
318                 __asm __volatile("                              \n\
319                         cld                                     \n\
320                 1:      inw %w2,%%ax                            \n\
321                         stosw                                   \n\
322                         addl $2,%2                              \n\
323                         loop 1b"                                :
324                     "=D" (addr), "=c" (count), "=d" (_port_)    :
325                     "0" (addr), "1" (count), "2" (_port_)       :
326                     "%eax", "memory", "cc");
327         } else {
328                 bus_space_handle_t _port_ = bsh + offset;
329                 __asm __volatile("                              \n\
330                         cld                                     \n\
331                         repne                                   \n\
332                         movsw"                                  :
333                     "=D" (addr), "=c" (count), "=S" (_port_)    :
334                     "0" (addr), "1" (count), "2" (_port_)       :
335                     "memory", "cc");
336         }
337 }
338
339 static __inline void
340 bus_space_read_region_4(bus_space_tag_t tag, bus_space_handle_t bsh,
341                         bus_size_t offset, u_int32_t *addr, size_t count)
342 {
343
344         if (tag == AMD64_BUS_SPACE_IO) {
345                 int _port_ = bsh + offset;
346                 __asm __volatile("                              \n\
347                         cld                                     \n\
348                 1:      inl %w2,%%eax                           \n\
349                         stosl                                   \n\
350                         addl $4,%2                              \n\
351                         loop 1b"                                :
352                     "=D" (addr), "=c" (count), "=d" (_port_)    :
353                     "0" (addr), "1" (count), "2" (_port_)       :
354                     "%eax", "memory", "cc");
355         } else {
356                 bus_space_handle_t _port_ = bsh + offset;
357                 __asm __volatile("                              \n\
358                         cld                                     \n\
359                         repne                                   \n\
360                         movsl"                                  :
361                     "=D" (addr), "=c" (count), "=S" (_port_)    :
362                     "0" (addr), "1" (count), "2" (_port_)       :
363                     "memory", "cc");
364         }
365 }
366
367 #if 0   /* Cause a link error for bus_space_read_region_8 */
368 #define bus_space_read_region_8 !!! bus_space_read_region_8 unimplemented !!!
369 #endif
370
371 /*
372  * Write the 1, 2, 4, or 8 byte value `value' to bus space
373  * described by tag/handle/offset.
374  */
375
376 static __inline void bus_space_write_1(bus_space_tag_t tag,
377                                        bus_space_handle_t bsh,
378                                        bus_size_t offset, u_int8_t value);
379
380 static __inline void bus_space_write_2(bus_space_tag_t tag,
381                                        bus_space_handle_t bsh,
382                                        bus_size_t offset, u_int16_t value);
383
384 static __inline void bus_space_write_4(bus_space_tag_t tag,
385                                        bus_space_handle_t bsh,
386                                        bus_size_t offset, u_int32_t value);
387
388 static __inline void
389 bus_space_write_1(bus_space_tag_t tag, bus_space_handle_t bsh,
390                        bus_size_t offset, u_int8_t value)
391 {
392
393         if (tag == AMD64_BUS_SPACE_IO)
394                 outb(bsh + offset, value);
395         else
396                 *(volatile u_int8_t *)(bsh + offset) = value;
397 }
398
399 static __inline void
400 bus_space_write_2(bus_space_tag_t tag, bus_space_handle_t bsh,
401                        bus_size_t offset, u_int16_t value)
402 {
403
404         if (tag == AMD64_BUS_SPACE_IO)
405                 outw(bsh + offset, value);
406         else
407                 *(volatile u_int16_t *)(bsh + offset) = value;
408 }
409
410 static __inline void
411 bus_space_write_4(bus_space_tag_t tag, bus_space_handle_t bsh,
412                        bus_size_t offset, u_int32_t value)
413 {
414
415         if (tag == AMD64_BUS_SPACE_IO)
416                 outl(bsh + offset, value);
417         else
418                 *(volatile u_int32_t *)(bsh + offset) = value;
419 }
420
421 #if 0   /* Cause a link error for bus_space_write_8 */
422 #define bus_space_write_8       !!! bus_space_write_8 not implemented !!!
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 == AMD64_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 == AMD64_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 == AMD64_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 == AMD64_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 == AMD64_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 == AMD64_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 == AMD64_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 == AMD64_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 == AMD64_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 == AMD64_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 == AMD64_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 == AMD64_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 == AMD64_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 == AMD64_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 == AMD64_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_ */