1 /** $MirOS: src/sys/arch/i386/include/bus.h,v 1.2 2005/03/06 21:26:59 tg Exp $ */
2 /* $OpenBSD: bus.h,v 1.36 2004/05/04 17:06:33 grange Exp $ */
3 /* $NetBSD: bus.h,v 1.6 1996/11/10 03:19:25 thorpej Exp $ */
4
5 /*
6 * Copyright (c) 2003, Miodrag Vallat.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
21 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
25 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 */
29 /*-
30 * Copyright (c) 1996, 1997 The NetBSD Foundation, Inc.
31 * All rights reserved.
32 *
33 * This code is derived from software contributed to The NetBSD Foundation
34 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
35 * NASA Ames Research Center.
36 *
37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions
39 * are met:
40 * 1. Redistributions of source code must retain the above copyright
41 * notice, this list of conditions and the following disclaimer.
42 * 2. Redistributions in binary form must reproduce the above copyright
43 * notice, this list of conditions and the following disclaimer in the
44 * documentation and/or other materials provided with the distribution.
45 * 3. All advertising materials mentioning features or use of this software
46 * must display the following acknowledgement:
47 * This product includes software developed by the NetBSD
48 * Foundation, Inc. and its contributors.
49 * 4. Neither the name of The NetBSD Foundation nor the names of its
50 * contributors may be used to endorse or promote products derived
51 * from this software without specific prior written permission.
52 *
53 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
54 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
55 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
56 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
57 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
58 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
59 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
60 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
61 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
62 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
63 * POSSIBILITY OF SUCH DAMAGE.
64 */
65
66 /*
67 * Copyright (c) 1996 Charles M. Hannum. All rights reserved.
68 * Copyright (c) 1996 Jason R. Thorpe. All rights reserved.
69 * Copyright (c) 1996 Christopher G. Demetriou. All rights reserved.
70 *
71 * Redistribution and use in source and binary forms, with or without
72 * modification, are permitted provided that the following conditions
73 * are met:
74 * 1. Redistributions of source code must retain the above copyright
75 * notice, this list of conditions and the following disclaimer.
76 * 2. Redistributions in binary form must reproduce the above copyright
77 * notice, this list of conditions and the following disclaimer in the
78 * documentation and/or other materials provided with the distribution.
79 * 3. All advertising materials mentioning features or use of this software
80 * must display the following acknowledgement:
81 * This product includes software developed by Christopher G. Demetriou
82 * for the NetBSD Project.
83 * 4. The name of the author may not be used to endorse or promote products
84 * derived from this software without specific prior written permission
85 *
86 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
87 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
88 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
89 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
90 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
91 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
92 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
93 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
94 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
95 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
96 */
97
98 #ifndef _I386_BUS_H_
99 #define _I386_BUS_H_
100
101 #include <machine/pio.h>
102
103 /*
104 * Values for the i386 bus space tag, not to be used directly by MI code.
105 */
106 #define I386_BUS_SPACE_IO 0 /* space is i/o space */
107 #define I386_BUS_SPACE_MEM 1 /* space is mem space */
108
109 /*
110 * Bus address and size types
111 */
112 typedef u_long bus_addr_t;
113 typedef u_long bus_size_t;
114
115 /*
116 * Access methods for bus resources and address space.
117 */
118 typedef int bus_space_tag_t;
119 typedef u_long bus_space_handle_t;
120
121 int bus_space_map(bus_space_tag_t t, bus_addr_t addr,
122 bus_size_t size, int cacheable, bus_space_handle_t *bshp);
123 /* like bus_space_map(), but without extent map checking/allocation */
124 int _bus_space_map(bus_space_tag_t t, bus_addr_t addr,
125 bus_size_t size, int cacheable, bus_space_handle_t *bshp);
126 void bus_space_unmap(bus_space_tag_t t, bus_space_handle_t bsh,
127 bus_size_t size);
128 /* like bus_space_unmap(), but without extent map deallocation */
129 void _bus_space_unmap(bus_space_tag_t, bus_space_handle_t,
130 bus_size_t, bus_addr_t *);
131 int bus_space_subregion(bus_space_tag_t t, bus_space_handle_t bsh,
132 bus_size_t offset, bus_size_t size, bus_space_handle_t *nbshp);
133
134 int bus_space_alloc(bus_space_tag_t t, bus_addr_t rstart,
135 bus_addr_t rend, bus_size_t size, bus_size_t align,
136 bus_size_t boundary, int cacheable, bus_addr_t *addrp,
137 bus_space_handle_t *bshp);
138 void bus_space_free(bus_space_tag_t t, bus_space_handle_t bsh,
139 bus_size_t size);
140
141 static void bus_space_barrier(bus_space_tag_t, bus_space_handle_t,
142 bus_addr_t, bus_size_t, int);
143
144 /*
145 * u_intN_t bus_space_read_N(bus_space_tag_t tag,
146 * bus_space_handle_t bsh, bus_size_t offset);
147 *
148 * Read a 1, 2, 4, or 8 byte quantity from bus space
149 * described by tag/handle/offset.
150 */
151
152 #define bus_space_read_1(t, h, o) \
153 ((t) == I386_BUS_SPACE_IO ? (inb((h) + (o))) : \
154 (*(volatile u_int8_t *)((h) + (o))))
155
156 #define bus_space_read_2(t, h, o) \
157 ((t) == I386_BUS_SPACE_IO ? (inw((h) + (o))) : \
158 (*(volatile u_int16_t *)((h) + (o))))
159
160 #define bus_space_read_4(t, h, o) \
161 ((t) == I386_BUS_SPACE_IO ? (inl((h) + (o))) : \
162 (*(volatile u_int32_t *)((h) + (o))))
163
164 #if 0 /* Cause a link error for bus_space_read_8 */
165 #define bus_space_read_8(t, h, o) !!! bus_space_read_8 unimplemented !!!
166 #endif
167
168 /*
169 * void bus_space_read_multi_N(bus_space_tag_t tag,
170 * bus_space_handle_t bsh, bus_size_t offset,
171 * u_intN_t *addr, size_t count);
172 *
173 * Read `count' 1, 2, 4, or 8 byte quantities from bus space
174 * described by tag/handle/offset and copy into buffer provided.
175 */
176
177 #define bus_space_read_multi_1(t, h, o, a, cnt) do { \
178 if ((t) == I386_BUS_SPACE_IO) { \
179 insb((h) + (o), (a), (cnt)); \
180 } else {void *_addr=(a); int _cnt=(cnt); \
181 __asm __volatile(" \
182 cld ; \
183 1: movb (%2),%%al ; \
184 stosb ; \
185 loop 1b" : \
186 "+D" (_addr), "+c" (_cnt) : "r" ((h) + (o)) : \
187 "%eax", "memory", "cc"); \
188 } \
189 } while (0)
190
191 #define bus_space_read_multi_2(t, h, o, a, cnt) do { \
192 if ((t) == I386_BUS_SPACE_IO) { \
193 insw((h) + (o), (a), (cnt)); \
194 } else {void *_addr=(a); int _cnt=(cnt); \
195 __asm __volatile(" \
196 cld ; \
197 1: movw (%2),%%ax ; \
198 stosw ; \
199 loop 1b" : \
200 "+D" (_addr), "+c" (_cnt) : "r" ((h) + (o)) : \
201 "%eax", "memory", "cc"); \
202 } \
203 } while (0)
204
205 #define bus_space_read_multi_4(t, h, o, a, cnt) do { \
206 if ((t) == I386_BUS_SPACE_IO) { \
207 insl((h) + (o), (a), (cnt)); \
208 } else {void *_addr=(a); int _cnt=(cnt); \
209 __asm __volatile(" \
210 cld ; \
211 1: movl (%2),%%eax ; \
212 stosl ; \
213 loop 1b" : \
214 "+D" (_addr), "+c" (_cnt) : "r" ((h) + (o)) : \
215 "%eax", "memory", "cc"); \
216 } \
217 } while (0)
218
219 #if 0 /* Cause a link error for bus_space_read_multi_8 */
220 #define bus_space_read_multi_8 !!! bus_space_read_multi_8 unimplemented !!!
221 #endif
222
223 /*
224 * void bus_space_read_raw_multi_N(bus_space_tag_t tag,
225 * bus_space_handle_t bsh, bus_size_t offset,
226 * u_int8_t *addr, size_t count);
227 *
228 * Read `count' bytes in 2, 4 or 8 byte wide quantities from bus space
229 * described by tag/handle/offset and copy into buffer provided. The buffer
230 * must have proper alignment for the N byte wide entities. Furthermore
231 * possible byte-swapping should be done by these functions.
232 */
233
234 #define bus_space_read_raw_multi_2(t, h, o, a, c) \
235 bus_space_read_multi_2((t), (h), (o), (u_int16_t *)(a), (c) >> 1)
236 #define bus_space_read_raw_multi_4(t, h, o, a, c) \
237 bus_space_read_multi_4((t), (h), (o), (u_int32_t *)(a), (c) >> 2)
238
239 #if 0 /* Cause a link error for bus_space_read_raw_multi_8 */
240 #define bus_space_read_raw_multi_8 \
241 !!! bus_space_read_raw_multi_8 unimplemented !!!
242 #endif
243
244 /*
245 * void bus_space_read_region_N(bus_space_tag_t tag,
246 * bus_space_handle_t bsh, bus_size_t offset,
247 * u_intN_t *addr, size_t count);
248 *
249 * Read `count' 1, 2, 4, or 8 byte quantities from bus space
250 * described by tag/handle and starting at `offset' and copy into
251 * buffer provided.
252 */
253
254 #define bus_space_read_region_1(t, h, o, a, cnt) do { \
255 int _cnt = (cnt); void *_addr = (a); int _port = (h)+(o); \
256 if ((t) == I386_BUS_SPACE_IO) { \
257 __asm __volatile(" \
258 cld ; \
259 1: inb %w2,%%al ; \
260 stosb ; \
261 incl %2 ; \
262 loop 1b" : \
263 "+D" (_addr), "+c" (_cnt), "+d" (_port) :: \
264 "%eax", "memory", "cc"); \
265 } else \
266 i386_space_copy(_port, _addr, 1, _cnt); \
267 } while (0)
268
269 #define bus_space_read_region_2(t, h, o, a, cnt) do { \
270 int _cnt = (cnt); void *_addr = (a); int _port = (h)+(o); \
271 if ((t) == I386_BUS_SPACE_IO) { \
272 __asm __volatile(" \
273 cld ; \
274 1: inw %w2,%%ax ; \
275 stosw ; \
276 addl $2,%2 ; \
277 loop 1b" : \
278 "+D" (_addr), "+c" (_cnt), "+d" (_port) :: \
279 "%eax", "memory", "cc"); \
280 } else \
281 i386_space_copy(_port, _addr, 2, _cnt); \
282 } while (0)
283
284 #define bus_space_read_region_4(t, h, o, a, cnt) do { \
285 int _cnt = (cnt); void *_addr = (a); int _port = (h)+(o); \
286 if ((t) == I386_BUS_SPACE_IO) { \
287 __asm __volatile(" \
288 cld ; \
289 1: inl %w2,%%eax ; \
290 stosl ; \
291 addl $4,%2 ; \
292 loop 1b" : \
293 "+D" (_addr), "+c" (_cnt), "+d" (_port) :: \
294 "%eax", "memory", "cc"); \
295 } else \
296 i386_space_copy(_port, _addr, 4, _cnt); \
297 } while (0)
298
299 #if 0 /* Cause a link error for bus_space_read_region_8 */
300 #define bus_space_read_region_8 !!! bus_space_read_region_8 unimplemented !!!
301 #endif
302
303 /*
304 * void bus_space_read_raw_region_N(bus_space_tag_t tag,
305 * bus_space_handle_t bsh, bus_size_t offset,
306 * u_int8_t *addr, size_t count);
307 *
308 * Read `count' bytes in 2, 4 or 8 byte wide quantities from bus space
309 * described by tag/handle and starting at `offset' and copy into
310 * buffer provided. The buffer must have proper alignment for the N byte
311 * wide entities. Furthermore possible byte-swapping should be done by
312 * these functions.
313 */
314
315 #define bus_space_read_raw_region_2(t, h, o, a, c) \
316 bus_space_read_region_2((t), (h), (o), (u_int16_t *)(a), (c) >> 1)
317 #define bus_space_read_raw_region_4(t, h, o, a, c) \
318 bus_space_read_region_4((t), (h), (o), (u_int32_t *)(a), (c) >> 2)
319
320 #if 0 /* Cause a link error for bus_space_read_raw_region_8 */
321 #define bus_space_read_raw_region_8 \
322 !!! bus_space_read_raw_region_8 unimplemented !!!
323 #endif
324
325 /*
326 * void bus_space_write_N(bus_space_tag_t tag,
327 * bus_space_handle_t bsh, bus_size_t offset,
328 * u_intN_t value);
329 *
330 * Write the 1, 2, 4, or 8 byte value `value' to bus space
331 * described by tag/handle/offset.
332 */
333
334 #define bus_space_write_1(t, h, o, v) do { \
335 if ((t) == I386_BUS_SPACE_IO) \
336 outb((h) + (o), (v)); \
337 else \
338 ((void)(*(volatile u_int8_t *)((h) + (o)) = (v))); \
339 } while (0)
340
341 #define bus_space_write_2(t, h, o, v) do { \
342 if ((t) == I386_BUS_SPACE_IO) \
343 outw((h) + (o), (v)); \
344 else \
345 ((void)(*(volatile u_int16_t *)((h) + (o)) = (v))); \
346 } while (0)
347
348 #define bus_space_write_4(t, h, o, v) do { \
349 if ((t) == I386_BUS_SPACE_IO) \
350 outl((h) + (o), (v)); \
351 else \
352 ((void)(*(volatile u_int32_t *)((h) + (o)) = (v))); \
353 } while (0)
354
355 #if 0 /* Cause a link error for bus_space_write_8 */
356 #define bus_space_write_8 !!! bus_space_write_8 not implemented !!!
357 #endif
358
359 /*
360 * void bus_space_write_multi_N(bus_space_tag_t tag,
361 * bus_space_handle_t bsh, bus_size_t offset,
362 * const u_intN_t *addr, size_t count);
363 *
364 * Write `count' 1, 2, 4, or 8 byte quantities from the buffer
365 * provided to bus space described by tag/handle/offset.
366 */
367
368 #define bus_space_write_multi_1(t, h, o, a, cnt) do { \
369 if ((t) == I386_BUS_SPACE_IO) { \
370 outsb((h) + (o), (a), (cnt)); \
371 } else {const void *_addr=(a); int _cnt=(cnt); \
372 __asm __volatile(" \
373 cld ; \
374 1: lodsb ; \
375 movb %%al,(%2) ; \
376 loop 1b" : \
377 "+S" (_addr), "+c" (_cnt) : "r" ((h) + (o)) : \
378 "%eax", "memory", "cc"); \
379 } \
380 } while (0)
381
382 #define bus_space_write_multi_2(t, h, o, a, cnt) do { \
383 if ((t) == I386_BUS_SPACE_IO) { \
384 outsw((h) + (o), (a), (cnt)); \
385 } else {const void *_addr=(a); int _cnt=(cnt); \
386 __asm __volatile(" \
387 cld ; \
388 1: lodsw ; \
389 movw %%ax,(%2) ; \
390 loop 1b" : \
391 "+S" (_addr), "+c" (_cnt) : "r" ((h) + (o)) : \
392 "%eax", "memory", "cc"); \
393 } \
394 } while (0)
395
396 #define bus_space_write_multi_4(t, h, o, a, cnt) do { \
397 if ((t) == I386_BUS_SPACE_IO) { \
398 outsl((h) + (o), (a), (cnt)); \
399 } else {const void *_addr=(a); int _cnt=(cnt); \
400 __asm __volatile(" \
401 cld ; \
402 1: lodsl ; \
403 movl %%eax,(%2) ; \
404 loop 1b" : \
405 "+S" (_addr), "+c" (_cnt) : "r" ((h) + (o)) : \
406 "%eax", "memory", "cc"); \
407 } \
408 } while (0)
409
410 #if 0 /* Cause a link error for bus_space_write_multi_8 */
411 #define bus_space_write_multi_8(t, h, o, a, c) \
412 !!! bus_space_write_multi_8 unimplemented !!!
413 #endif
414
415 /*
416 * void bus_space_write_raw_multi_N(bus_space_tag_t tag,
417 * bus_space_handle_t bsh, bus_size_t offset,
418 * const u_int8_t *addr, size_t count);
419 *
420 * Write `count' bytes in 2, 4 or 8 byte wide quantities from the buffer
421 * provided to bus space described by tag/handle/offset. The buffer
422 * must have proper alignment for the N byte wide entities. Furthermore
423 * possible byte-swapping should be done by these functions.
424 */
425
426 #define bus_space_write_raw_multi_2(t, h, o, a, c) \
427 bus_space_write_multi_2((t), (h), (o), (const u_int16_t *)(a), (c) >> 1)
428 #define bus_space_write_raw_multi_4(t, h, o, a, c) \
429 bus_space_write_multi_4((t), (h), (o), (const u_int32_t *)(a), (c) >> 2)
430
431 #if 0 /* Cause a link error for bus_space_write_raw_multi_8 */
432 #define bus_space_write_raw_multi_8 \
433 !!! bus_space_write_raw_multi_8 unimplemented !!!
434 #endif
435
436 /*
437 * void bus_space_write_region_N(bus_space_tag_t tag,
438 * bus_space_handle_t bsh, bus_size_t offset,
439 * const u_intN_t *addr, size_t count);
440 *
441 * Write `count' 1, 2, 4, or 8 byte quantities from the buffer provided
442 * to bus space described by tag/handle starting at `offset'.
443 */
444
445 #define bus_space_write_region_1(t, h, o, a, cnt) do { \
446 int _port = (h)+(o); const void *_addr=(a); int _cnt=(cnt); \
447 if ((t) == I386_BUS_SPACE_IO) { \
448 __asm __volatile(" \
449 cld ; \
450 1: lodsb ; \
451 outb %%al,%w0 ; \
452 incl %0 ; \
453 loop 1b" : \
454 "+d" (_port), "+S" (_addr), "+c" (_cnt) :: \
455 "%eax", "memory", "cc"); \
456 } else \
457 i386_space_copy(_addr, _port, 1, _cnt); \
458 } while (0)
459
460 #define bus_space_write_region_2(t, h, o, a, cnt) do { \
461 int _port = (h)+(o); const void *_addr=(a); int _cnt=(cnt); \
462 if ((t) == I386_BUS_SPACE_IO) { \
463 __asm __volatile(" \
464 cld ; \
465 1: lodsw ; \
466 outw %%ax,%w0 ; \
467 addl $2,%0 ; \
468 loop 1b" : \
469 "+d" (_port), "+S" (_addr), "+c" (_cnt) :: \
470 "%eax", "memory", "cc"); \
471 } else \
472 i386_space_copy(_addr, _port, 2, _cnt); \
473 } while (0)
474
475 #define bus_space_write_region_4(t, h, o, a, cnt) do { \
476 int _port = (h)+(o); const void *_addr=(a); int _cnt=(cnt); \
477 if ((t) == I386_BUS_SPACE_IO) { \
478 __asm __volatile(" \
479 cld ; \
480 1: lodsl ; \
481 outl %%eax,%w0 ; \
482 addl $4,%0 ; \
483 loop 1b" : \
484 "+d" (_port), "+S" (_addr), "+c" (_cnt) :: \
485 "%eax", "memory", "cc"); \
486 } else \
487 i386_space_copy(_addr, _port, 4, _cnt); \
488 } while (0)
489
490 #if 0 /* Cause a link error for bus_space_write_region_8 */
491 #define bus_space_write_region_8 \
492 !!! bus_space_write_region_8 unimplemented !!!
493 #endif
494
495 /*
496 * void bus_space_write_raw_region_N(bus_space_tag_t tag,
497 * bus_space_handle_t bsh, bus_size_t offset,
498 * const u_int8_t *addr, size_t count);
499 *
500 * Write `count' bytes in 2, 4 or 8 byte wide quantities to bus space
501 * described by tag/handle and starting at `offset' from the
502 * buffer provided. The buffer must have proper alignment for the N byte
503 * wide entities. Furthermore possible byte-swapping should be done by
504 * these functions.
505 */
506
507 #define bus_space_write_raw_region_2(t, h, o, a, c) \
508 bus_space_write_region_2((t), (h), (o), (const u_int16_t *)(a), (c) >> 1)
509 #define bus_space_write_raw_region_4(t, h, o, a, c) \
510 bus_space_write_region_4((t), (h), (o), (const u_int32_t *)(a), (c) >> 2)
511
512 #if 0 /* Cause a link error for bus_space_write_raw_region_8 */
513 #define bus_space_write_raw_region_8 \
514 !!! bus_space_write_raw_region_8 unimplemented !!!
515 #endif
516
517 /*
518 * void bus_space_set_multi_N(bus_space_tag_t tag,
519 * bus_space_handle_t bsh, bus_size_t offset,
520 * u_intN_t val, size_t count);
521 *
522 * Write the 1, 2, 4, or 8 byte value `val' to bus space described
523 * by tag/handle/offset `count' times.
524 */
525
526 #define bus_space_set_multi_1(t, h, o, v, cnt) do { \
527 int _cnt=(cnt); \
528 if ((t) == I386_BUS_SPACE_IO) { \
529 __asm __volatile(" \
530 cld ; \
531 1: outb %b2, %w1 ; \
532 loop 1b" : \
533 "+c" (_cnt) : "d" ((h) + (o)), "a" ((v)) : \
534 "cc"); \
535 } else { \
536 __asm __volatile(" \
537 cld ; \
538 1: movb %b2, (%1) ; \
539 loop 1b" : \
540 "+c" (_cnt) : "D" ((h) + (o)), "a" ((v)) : \
541 "cc", "memory"); \
542 } \
543 } while (0)
544
545 #define bus_space_set_multi_2(t, h, o, v, cnt) do { \
546 int _cnt=(cnt); \
547 if ((t) == I386_BUS_SPACE_IO) { \
548 __asm __volatile(" \
549 cld ; \
550 1: outw %w2, %w1 ; \
551 loop 1b" : \
552 "+c" (_cnt) : "d" ((h) + (o)), "a" ((v)) : \
553 "cc"); \
554 } else { \
555 __asm __volatile(" \
556 cld ; \
557 1: movw %w2, (%1) ; \
558 loop 1b" : \
559 "+c" (_cnt) : "D" ((h) + (o)), "a" ((v)) : \
560 "cc", "memory"); \
561 } \
562 } while (0)
563
564 #define bus_space_set_multi_4(t, h, o, v, cnt) do { \
565 int _cnt=(cnt); \
566 if ((t) == I386_BUS_SPACE_IO) { \
567 __asm __volatile(" \
568 cld ; \
569 1: outl %2,%w1 ; \
570 loop 1b" : \
571 "+c" (_cnt) : "d" ((h) + (o)), "a" ((v)) : \
572 "cc"); \
573 } else { \
574 __asm __volatile(" \
575 cld ; \
576 1: movl %2,(%1) ; \
577 loop 1b" : \
578 "+c" (_cnt) : "D" ((h) + (o)), "a" ((v)) : \
579 "cc", "memory"); \
580 } \
581 } while (0)
582
583 #if 0 /* Cause a link error for bus_space_set_multi_8 */
584 #define bus_space_set_multi_8 \
585 !!! bus_space_set_multi_8 unimplemented !!!
586 #endif
587
588 /*
589 * void bus_space_set_region_N(bus_space_tag_t tag,
590 * bus_space_handle_t bsh, bus_size_t offset,
591 * u_intN_t val, size_t count);
592 *
593 * Write `count' 1, 2, 4, or 8 byte value `val' to bus space described
594 * by tag/handle starting at `offset'.
595 */
596
597 #define bus_space_set_region_1(t, h, o, v, cnt) do { \
598 int _port = (h)+(o); int _cnt = (cnt); \
599 if ((t) == I386_BUS_SPACE_IO) { \
600 __asm __volatile(" \
601 1: outb %%al,%w0 ; \
602 incl %0 ; \
603 loop 1b" : \
604 "+d" (_port), "+c" (_cnt) : "a" ((v)) : \
605 "cc"); \
606 } else { \
607 __asm __volatile(" \
608 cld ; \
609 repne ; \
610 stosb" : \
611 "+D" (_port), "+c" (_cnt) : "a" ((v)) : \
612 "memory", "cc"); \
613 } \
614 } while (0)
615
616 #define bus_space_set_region_2(t, h, o, v, cnt) do { \
617 int _port = (h)+(o); int _cnt = (cnt); \
618 if ((t) == I386_BUS_SPACE_IO) { \
619 __asm __volatile(" \
620 1: outw %%ax,%w0 ; \
621 addl $2, %0 ; \
622 loop 1b" : \
623 "+d" (_port), "+c" (_cnt) : "a" ((v)) : \
624 "cc"); \
625 } else { \
626 __asm __volatile(" \
627 cld ; \
628 repne ; \
629 stosw" : \
630 "+D" (_port), "+c" (_cnt) : "a" ((v)) : \
631 "memory", "cc"); \
632 } \
633 } while (0)
634
635 #define bus_space_set_region_4(t, h, o, v, cnt) do { \
636 int _port = (h)+(o); int _cnt = (cnt); \
637 if ((t) == I386_BUS_SPACE_IO) { \
638 __asm __volatile(" \
639 1: outl %%eax,%w0 ; \
640 addl $4, %0 ; \
641 loop 1b" : \
642 "+d" (_port), "+c" (_cnt) : "a" ((v)) : \
643 "cc"); \
644 } else { \
645 __asm __volatile(" \
646 cld ; \
647 repne ; \
648 stosl" : \
649 "+D" (_port), "+c" (_cnt) : "a" ((v)) : \
650 "memory", "cc"); \
651 } \
652 } while (0)
653
654 #if 0 /* Cause a link error for bus_space_set_region_8 */
655 #define bus_space_set_region_8 \
656 !!! bus_space_set_region_8 unimplemented !!!
657 #endif
658
659 /*
660 * void bus_space_copy_N(bus_space_tag_t tag,
661 * bus_space_handle_t bsh1, bus_size_t off1,
662 * bus_space_handle_t bsh2, bus_size_t off2,
663 * size_t count);
664 *
665 * Copy `count' 1, 2, 4, or 8 byte values from bus space starting
666 * at tag/bsh1/off1 to bus space starting at tag/bsh2/off2.
667 */
668
669 #define bus_space_copy_1(t, h1, o1, h2, o2, cnt) do { \
670 int _port1 = (h1)+(o1); int _port2 = (h2)+(o2); int _cnt=(cnt); \
671 if ((t) == I386_BUS_SPACE_IO) { \
672 __asm __volatile(" \
673 1: movl %k1,%%edx ; \
674 inb %%dx,%%al ; \
675 movl %k0,%%edx ; \
676 outb %%al,%%dx ; \
677 incl %0 ; \
678 incl %1 ; \
679 loop 1b" : \
680 "+D" (_port2), "+S" (_port1), "+c" ((_cnt)) :: \
681 "%edx", "%eax", "cc"); \
682 } else \
683 i386_space_copy(_port1, _port2, 1, _cnt); \
684 } while (0)
685
686 #define bus_space_copy_2(t, h1, o1, h2, o2, cnt) do { \
687 int _port1 = (h1)+(o1); int _port2 = (h2)+(o2); int _cnt=(cnt); \
688 if ((t) == I386_BUS_SPACE_IO) { \
689 __asm __volatile(" \
690 1: movl %k1,%%edx ; \
691 inw %%dx,%%ax ; \
692 movl %k0,%%edx ; \
693 outw %%ax,%%dx ; \
694 addl $2, %0 ; \
695 addl $2, %1 ; \
696 loop 1b" : \
697 "+D" (_port2), "+ES" (_port1), "+c" ((_cnt)) :: \
698 "%edx", "%eax", "cc"); \
699 } else \
700 i386_space_copy(_port1, _port2, 2, _cnt); \
701 } while (0)
702
703 #define bus_space_copy_4(t, h1, o1, h2, o2, cnt) do { \
704 int _port1 = (h1)+(o1); int _port2 = (h2)+(o2); int _cnt=(cnt); \
705 if ((t) == I386_BUS_SPACE_IO) { \
706 __asm __volatile(" \
707 1: movl %k1,%%edx ; \
708 inl %%dx,%%eax ; \
709 movl %k0,%%edx ; \
710 outl %%eax,%%dx ; \
711 addl $4, %0 ; \
712 addl $4, %1 ; \
713 loop 1b" : \
714 "+D" (_port2), "+ES" (_port1), "+c" ((_cnt)) :: \
715 "%edx", "%eax", "cc"); \
716 } else \
717 i386_space_copy(_port1, _port2, 4, _cnt); \
718 } while (0)
719
720 #if 0 /* Cause a link error for bus_space_copy_8 */
721 #define bus_space_copy_8 \
722 !!! bus_space_copy_8 unimplemented !!!
723 #endif
724
725 #define i386_space_copy1(a1, a2, cnt, movs, df) \
726 __asm __volatile(df "\n\trep\n\t" movs : \
727 "+S" (a1), "+D" (a2), "+c" (cnt) :: "memory", "cc");
728
729 #define i386_space_copy(a1, a2, sz, cnt) do { \
730 if ((void *)(a1) < (void *)(a2)) { \
731 a1 += ((cnt) - 1) * (sz); a2 += ((cnt) - 1) * (sz); \
732 switch (sz) { \
733 case 1: i386_space_copy1(a1,a2,cnt,"movsb","std");break;\
734 case 2: i386_space_copy1(a1,a2,cnt,"movsw","std");break;\
735 case 4: i386_space_copy1(a1,a2,cnt,"movsl","std");break;\
736 } \
737 } else \
738 switch (sz) { \
739 case 1: i386_space_copy1(a1,a2,cnt,"movsb","cld");break;\
740 case 2: i386_space_copy1(a1,a2,cnt,"movsw","cld");break;\
741 case 4: i386_space_copy1(a1,a2,cnt,"movsl","cld");break;\
742 } \
743 } while (0)
744
745 /*
746 * Bus read/write barrier methods.
747 *
748 * void bus_space_barrier(bus_space_tag_t tag,
749 * bus_space_handle_t bsh, bus_size_t offset,
750 * bus_size_t len, int flags);
751 *
752 * Note: the i386 does not currently require barriers, but we must
753 * provide the flags to MI code.
754 */
755 #define BUS_SPACE_BARRIER_READ 0x01 /* force read barrier */
756 #define BUS_SPACE_BARRIER_WRITE 0x02 /* force write barrier */
757 /* Compatibility defines */
758 #define BUS_BARRIER_READ BUS_SPACE_BARRIER_READ
759 #define BUS_BARRIER_WRITE BUS_SPACE_BARRIER_WRITE
760
761 static __inline__ void
bus_space_barrier(bus_space_tag_t tag,bus_space_handle_t handle,bus_addr_t offset,bus_size_t size,int flags)762 bus_space_barrier(bus_space_tag_t tag, bus_space_handle_t handle,
763 bus_addr_t offset, bus_size_t size, int flags)
764 {
765 /* nothing, but can't be a void macro, thanks GCC */
766 }
767
768 /*
769 * Flags used in various bus DMA methods.
770 */
771 #define BUS_DMA_WAITOK 0x000 /* safe to sleep (pseudo-flag) */
772 #define BUS_DMA_NOWAIT 0x001 /* not safe to sleep */
773 #define BUS_DMA_ALLOCNOW 0x002 /* perform resource allocation now */
774 #define BUS_DMA_COHERENT 0x004 /* hint: map memory DMA coherent */
775 #define BUS_DMA_BUS1 0x010 /* placeholders for bus functions... */
776 #define BUS_DMA_BUS2 0x020
777 #define BUS_DMA_BUS3 0x040
778 #define BUS_DMA_BUS4 0x080
779 #define BUS_DMA_STREAMING 0x100 /* hint: sequential, unidirectional */
780 #define BUS_DMA_READ 0x200 /* mapping is device -> memory only */
781 #define BUS_DMA_WRITE 0x400 /* mapping is memory -> device only */
782
783 /* Forwards needed by prototypes below. */
784 struct mbuf;
785 struct proc;
786 struct uio;
787
788 /*
789 * Operations performed by bus_dmamap_sync().
790 */
791 #define BUS_DMASYNC_PREREAD 0x01
792 #define BUS_DMASYNC_POSTREAD 0x02
793 #define BUS_DMASYNC_PREWRITE 0x04
794 #define BUS_DMASYNC_POSTWRITE 0x08
795
796 typedef struct i386_bus_dma_tag *bus_dma_tag_t;
797 typedef struct i386_bus_dmamap *bus_dmamap_t;
798
799 /*
800 * bus_dma_segment_t
801 *
802 * Describes a single contiguous DMA transaction. Values
803 * are suitable for programming into DMA registers.
804 */
805 struct i386_bus_dma_segment {
806 bus_addr_t ds_addr; /* DMA address */
807 bus_size_t ds_len; /* length of transfer */
808 };
809 typedef struct i386_bus_dma_segment bus_dma_segment_t;
810
811 /*
812 * bus_dma_tag_t
813 *
814 * A machine-dependent opaque type describing the implementation of
815 * DMA for a given bus.
816 */
817
818 struct i386_bus_dma_tag {
819 void *_cookie; /* cookie used in the guts */
820
821 /*
822 * DMA mapping methods.
823 */
824 int (*_dmamap_create)(bus_dma_tag_t, bus_size_t, int,
825 bus_size_t, bus_size_t, int, bus_dmamap_t *);
826 void (*_dmamap_destroy)(bus_dma_tag_t, bus_dmamap_t);
827 int (*_dmamap_load)(bus_dma_tag_t, bus_dmamap_t, void *,
828 bus_size_t, struct proc *, int);
829 int (*_dmamap_load_mbuf)(bus_dma_tag_t, bus_dmamap_t,
830 struct mbuf *, int);
831 int (*_dmamap_load_uio)(bus_dma_tag_t, bus_dmamap_t,
832 struct uio *, int);
833 int (*_dmamap_load_raw)(bus_dma_tag_t, bus_dmamap_t,
834 bus_dma_segment_t *, int, bus_size_t, int);
835 void (*_dmamap_unload)(bus_dma_tag_t, bus_dmamap_t);
836 void (*_dmamap_sync)(bus_dma_tag_t, bus_dmamap_t,
837 bus_addr_t, bus_size_t, int);
838
839 /*
840 * DMA memory utility functions.
841 */
842 int (*_dmamem_alloc)(bus_dma_tag_t, bus_size_t, bus_size_t,
843 bus_size_t, bus_dma_segment_t *, int, int *, int);
844 void (*_dmamem_free)(bus_dma_tag_t,
845 bus_dma_segment_t *, int);
846 int (*_dmamem_map)(bus_dma_tag_t, bus_dma_segment_t *,
847 int, size_t, caddr_t *, int);
848 void (*_dmamem_unmap)(bus_dma_tag_t, caddr_t, size_t);
849 paddr_t (*_dmamem_mmap)(bus_dma_tag_t, bus_dma_segment_t *,
850 int, off_t, int, int);
851 };
852
853 #define bus_dmamap_create(t, s, n, m, b, f, p) \
854 (*(t)->_dmamap_create)((t), (s), (n), (m), (b), (f), (p))
855 #define bus_dmamap_destroy(t, p) \
856 (*(t)->_dmamap_destroy)((t), (p))
857 #define bus_dmamap_load(t, m, b, s, p, f) \
858 (*(t)->_dmamap_load)((t), (m), (b), (s), (p), (f))
859 #define bus_dmamap_load_mbuf(t, m, b, f) \
860 (*(t)->_dmamap_load_mbuf)((t), (m), (b), (f))
861 #define bus_dmamap_load_uio(t, m, u, f) \
862 (*(t)->_dmamap_load_uio)((t), (m), (u), (f))
863 #define bus_dmamap_load_raw(t, m, sg, n, s, f) \
864 (*(t)->_dmamap_load_raw)((t), (m), (sg), (n), (s), (f))
865 #define bus_dmamap_unload(t, p) \
866 (*(t)->_dmamap_unload)((t), (p))
867 #define bus_dmamap_sync(t, p, o, l, ops) \
868 (void)((t)->_dmamap_sync ? \
869 (*(t)->_dmamap_sync)((t), (p), (o), (l), (ops)) : (void)0)
870
871 #define bus_dmamem_alloc(t, s, a, b, sg, n, r, f) \
872 (*(t)->_dmamem_alloc)((t), (s), (a), (b), (sg), (n), (r), (f))
873 #define bus_dmamem_free(t, sg, n) \
874 (*(t)->_dmamem_free)((t), (sg), (n))
875 #define bus_dmamem_map(t, sg, n, s, k, f) \
876 (*(t)->_dmamem_map)((t), (sg), (n), (s), (k), (f))
877 #define bus_dmamem_unmap(t, k, s) \
878 (*(t)->_dmamem_unmap)((t), (k), (s))
879 #define bus_dmamem_mmap(t, sg, n, o, p, f) \
880 (*(t)->_dmamem_mmap)((t), (sg), (n), (o), (p), (f))
881
882 /*
883 * bus_dmamap_t
884 *
885 * Describes a DMA mapping.
886 */
887 struct i386_bus_dmamap {
888 /*
889 * PRIVATE MEMBERS: not for use my machine-independent code.
890 */
891 bus_size_t _dm_size; /* largest DMA transfer mappable */
892 int _dm_segcnt; /* number of segs this map can map */
893 bus_size_t _dm_maxsegsz; /* largest possible segment */
894 bus_size_t _dm_boundary; /* don't cross this */
895 int _dm_flags; /* misc. flags */
896
897 void *_dm_cookie; /* cookie for bus-specific functions */
898
899 /*
900 * PUBLIC MEMBERS: these are used by machine-independent code.
901 */
902 bus_size_t dm_mapsize; /* size of the mapping */
903 int dm_nsegs; /* # valid segments in mapping */
904 bus_dma_segment_t dm_segs[1]; /* segments; variable length */
905 };
906
907 #ifdef _I386_BUS_DMA_PRIVATE
908 int _bus_dmamap_create(bus_dma_tag_t, bus_size_t, int, bus_size_t,
909 bus_size_t, int, bus_dmamap_t *);
910 void _bus_dmamap_destroy(bus_dma_tag_t, bus_dmamap_t);
911 int _bus_dmamap_load(bus_dma_tag_t, bus_dmamap_t, void *,
912 bus_size_t, struct proc *, int);
913 int _bus_dmamap_load_mbuf(bus_dma_tag_t, bus_dmamap_t,
914 struct mbuf *, int);
915 int _bus_dmamap_load_uio(bus_dma_tag_t, bus_dmamap_t,
916 struct uio *, int);
917 int _bus_dmamap_load_raw(bus_dma_tag_t, bus_dmamap_t,
918 bus_dma_segment_t *, int, bus_size_t, int);
919 void _bus_dmamap_unload(bus_dma_tag_t, bus_dmamap_t);
920 void _bus_dmamap_sync(bus_dma_tag_t, bus_dmamap_t, bus_addr_t,
921 bus_size_t, int);
922
923 int _bus_dmamem_alloc(bus_dma_tag_t tag, bus_size_t size,
924 bus_size_t alignment, bus_size_t boundary,
925 bus_dma_segment_t *segs, int nsegs, int *rsegs, int flags);
926 void _bus_dmamem_free(bus_dma_tag_t tag, bus_dma_segment_t *segs,
927 int nsegs);
928 int _bus_dmamem_map(bus_dma_tag_t tag, bus_dma_segment_t *segs,
929 int nsegs, size_t size, caddr_t *kvap, int flags);
930 void _bus_dmamem_unmap(bus_dma_tag_t tag, caddr_t kva,
931 size_t size);
932 paddr_t _bus_dmamem_mmap(bus_dma_tag_t tag, bus_dma_segment_t *segs,
933 int nsegs, off_t off, int prot, int flags);
934
935 int _bus_dmamem_alloc_range(bus_dma_tag_t tag, bus_size_t size,
936 bus_size_t alignment, bus_size_t boundary,
937 bus_dma_segment_t *segs, int nsegs, int *rsegs, int flags,
938 paddr_t low, paddr_t high);
939 #endif /* _I386_BUS_DMA_PRIVATE */
940
941 #endif /* _I386_BUS_H_ */
942