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