xref: /netbsd-src/sys/arch/vax/include/bus.h (revision 274254cdae52594c1aa480a736aef78313d15c9c)
1 /*	$NetBSD: bus.h,v 1.31 2008/04/28 20:23:39 martin Exp $	*/
2 
3 /*-
4  * Copyright (c) 1996, 1997, 1998, 2001 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9  * NASA Ames Research Center.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 /*
34  * Copyright (c) 1996 Charles M. Hannum.  All rights reserved.
35  * Copyright (c) 1996 Christopher G. Demetriou.  All rights reserved.
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 Christopher G. Demetriou
48  *	for the NetBSD Project.
49  * 4. The name of the author may not be used to endorse or promote products
50  *    derived from this software without specific prior written permission
51  *
52  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
53  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
54  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
55  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
56  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
57  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
58  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
59  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
60  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
61  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
62  */
63 
64 #ifndef _VAX_BUS_H_
65 #define _VAX_BUS_H_
66 
67 #ifdef BUS_SPACE_DEBUG
68 #include <sys/systm.h> /* for printf() prototype */
69 /*
70  * Macros for sanity-checking the aligned-ness of pointers passed to
71  * bus space ops.  These are not strictly necessary on the VAX, but
72  * could lead to performance improvements, and help catch problems
73  * with drivers that would creep up on other architectures.
74  */
75 #define	__BUS_SPACE_ALIGNED_ADDRESS(p, t)				\
76 	((((u_long)(p)) & (sizeof(t)-1)) == 0)
77 
78 #define	__BUS_SPACE_ADDRESS_SANITY(p, t, d)				\
79 ({									\
80 	if (__BUS_SPACE_ALIGNED_ADDRESS((p), t) == 0) {			\
81 		printf("%s 0x%lx not aligned to %d bytes %s:%d\n",	\
82 		    d, (u_long)(p), sizeof(t), __FILE__, __LINE__);	\
83 	}								\
84 	(void) 0;							\
85 })
86 
87 #define BUS_SPACE_ALIGNED_POINTER(p, t) __BUS_SPACE_ALIGNED_ADDRESS(p, t)
88 #else
89 #define	__BUS_SPACE_ADDRESS_SANITY(p,t,d)	(void) 0
90 #define BUS_SPACE_ALIGNED_POINTER(p, t) ALIGNED_POINTER(p, t)
91 #endif /* BUS_SPACE_DEBUG */
92 
93 /*
94  * Bus address and size types
95  */
96 typedef paddr_t bus_addr_t;
97 typedef psize_t bus_size_t;
98 
99 /*
100  * Access methods for bus resources and address space.
101  */
102 typedef	struct vax_bus_space *bus_space_tag_t;
103 typedef	vaddr_t bus_space_handle_t;
104 
105 struct vax_bus_space {
106 	/* cookie */
107 	void		*vbs_cookie;
108 
109 	/* mapping/unmapping */
110 	int		(*vbs_map)(void *, bus_addr_t, bus_size_t, int,
111 			    bus_space_handle_t *, int);
112 	void		(*vbs_unmap)(void *, bus_space_handle_t, bus_size_t,
113 			    int);
114 	int		(*vbs_subregion)(void *, bus_space_handle_t, bus_size_t,
115 			    bus_size_t, bus_space_handle_t *);
116 
117 	/* allocation/deallocation */
118 	int		(*vbs_alloc)(void *, bus_addr_t, bus_addr_t, bus_size_t,
119 			    bus_size_t, bus_size_t, int, bus_addr_t *,
120 			    bus_space_handle_t *);
121 	void		(*vbs_free)(void *, bus_space_handle_t, bus_size_t);
122 	/* mmap bus space for user */
123 	paddr_t		(*vbs_mmap)(void *, bus_addr_t, off_t, int, int);
124 };
125 
126 /*
127  *	int bus_space_map(bus_space_tag_t t, bus_addr_t addr,
128  *	    bus_size_t size, int flags, bus_space_handle_t *bshp);
129  *
130  * Map a region of bus space.
131  */
132 
133 #define	BUS_SPACE_MAP_CACHEABLE		0x01
134 #define	BUS_SPACE_MAP_LINEAR		0x02
135 #define	BUS_SPACE_MAP_PREFETCHABLE	0x04
136 
137 #define	bus_space_map(t, a, s, f, hp)					\
138 	(*(t)->vbs_map)((t)->vbs_cookie, (a), (s), (f), (hp), 1)
139 #define	vax_bus_space_map_noacct(t, a, s, f, hp)			\
140 	(*(t)->vbs_map)((t)->vbs_cookie, (a), (s), (f), (hp), 0)
141 
142 /*
143  *	int bus_space_unmap(bus_space_tag_t t,
144  *	    bus_space_handle_t bsh, bus_size_t size);
145  *
146  * Unmap a region of bus space.
147  */
148 
149 #define bus_space_unmap(t, h, s)					\
150 	(*(t)->vbs_unmap)((t)->vbs_cookie, (h), (s), 1)
151 #define vax_bus_space_unmap_noacct(t, h, s)				\
152 	(*(t)->vbs_unmap)((t)->vbs_cookie, (h), (s), 0)
153 
154 /*
155  *	int bus_space_subregion(bus_space_tag_t t,
156  *	    bus_space_handle_t bsh, bus_size_t offset, bus_size_t size,
157  *	    bus_space_handle_t *nbshp);
158  *
159  * Get a new handle for a subregion of an already-mapped area of bus space.
160  */
161 
162 #define bus_space_subregion(t, h, o, s, nhp)				\
163 	(*(t)->vbs_subregion)((t)->vbs_cookie, (h), (o), (s), (nhp))
164 
165 /*
166  *	int bus_space_alloc(bus_space_tag_t t, bus_addr_t rstart,
167  *	    bus_addr_t rend, bus_size_t size, bus_size_t align,
168  *	    bus_size_t boundary, int flags, bus_addr_t *addrp,
169  *	    bus_space_handle_t *bshp);
170  *
171  * Allocate a region of bus space.
172  */
173 
174 #define bus_space_alloc(t, rs, re, s, a, b, f, ap, hp)			\
175 	(*(t)->vbs_alloc)((t)->vbs_cookie, (rs), (re), (s), (a), (b),   \
176 	    (f), (ap), (hp))
177 
178 /*
179  *	int bus_space_free(bus_space_tag_t t,
180  *	    bus_space_handle_t bsh, bus_size_t size);
181  *
182  * Free a region of bus space.
183  */
184 
185 #define bus_space_free(t, h, s)						\
186 	(*(t)->vbs_free)((t)->vbs_cookie, (h), (s))
187 
188 /*
189  * Mmap bus space for a user application.
190  */
191 #define bus_space_mmap(t, a, o, p, f)					\
192 	(*(t)->vbs_mmap)((t)->vbs_cookie, (a), (o), (p), (f))
193 
194 
195 /*
196  *	u_intN_t bus_space_read_N(bus_space_tag_t tag,
197  *	    bus_space_handle_t bsh, bus_size_t offset);
198  *
199  * Read a 1, 2, 4, or 8 byte quantity from bus space
200  * described by tag/handle/offset.
201  */
202 
203 #define	bus_space_read_1(t, h, o)					\
204 	    (*(volatile uint8_t *)((h) + (o)))
205 
206 #define	bus_space_read_2(t, h, o)					\
207 	 (__BUS_SPACE_ADDRESS_SANITY((h) + (o), uint16_t, "bus addr"),	\
208 	    (*(volatile uint16_t *)((h) + (o))))
209 
210 #define	bus_space_read_4(t, h, o)					\
211 	 (__BUS_SPACE_ADDRESS_SANITY((h) + (o), uint32_t, "bus addr"),	\
212 	    (*(volatile uint32_t *)((h) + (o))))
213 
214 #if 0	/* Cause a link error for bus_space_read_8 */
215 #define	bus_space_read_8(t, h, o)	!!! bus_space_read_8 unimplemented !!!
216 #endif
217 
218 /*
219  *	void bus_space_read_multi_N(bus_space_tag_t tag,
220  *	    bus_space_handle_t bsh, bus_size_t offset,
221  *	    u_intN_t *addr, size_t count);
222  *
223  * Read `count' 1, 2, 4, or 8 byte quantities from bus space
224  * described by tag/handle/offset and copy into buffer provided.
225  */
226 static __inline void
227 	vax_mem_read_multi_1(bus_space_tag_t, bus_space_handle_t, bus_size_t,
228 	    uint8_t *, size_t),
229 	vax_mem_read_multi_2(bus_space_tag_t, bus_space_handle_t, bus_size_t,
230 	    uint16_t *, size_t),
231 	vax_mem_read_multi_4(bus_space_tag_t, bus_space_handle_t, bus_size_t,
232 	    uint32_t *, size_t);
233 
234 #define	bus_space_read_multi_1(t, h, o, a, c)				\
235 	vax_mem_read_multi_1((t), (h), (o), (a), (c))
236 
237 #define bus_space_read_multi_2(t, h, o, a, c)				\
238 do {									\
239 	__BUS_SPACE_ADDRESS_SANITY((a), uint16_t, "buffer");		\
240 	__BUS_SPACE_ADDRESS_SANITY((h) + (o), uint16_t, "bus addr");	\
241 	vax_mem_read_multi_2((t), (h), (o), (a), (c));		\
242 } while (0)
243 
244 #define bus_space_read_multi_4(t, h, o, a, c)				\
245 do {									\
246 	__BUS_SPACE_ADDRESS_SANITY((a), uint32_t, "buffer");		\
247 	__BUS_SPACE_ADDRESS_SANITY((h) + (o), uint32_t, "bus addr");	\
248 	vax_mem_read_multi_4((t), (h), (o), (a), (c));		\
249 } while (0)
250 
251 #if 0	/* Cause a link error for bus_space_read_multi_8 */
252 #define	bus_space_read_multi_8	!!! bus_space_read_multi_8 unimplemented !!!
253 #endif
254 
255 static __inline void
256 vax_mem_read_multi_1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o,
257 	uint8_t *a, size_t c)
258 {
259 	const bus_addr_t addr = h + o;
260 
261 	for (; c != 0; c--, a++)
262 		*a = *(volatile uint8_t *)(addr);
263 }
264 
265 static __inline void
266 vax_mem_read_multi_2(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o,
267 	uint16_t *a, size_t c)
268 {
269 	const bus_addr_t addr = h + o;
270 
271 	for (; c != 0; c--, a++)
272 		*a = *(volatile uint16_t *)(addr);
273 }
274 
275 static __inline void
276 vax_mem_read_multi_4(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o,
277 	uint32_t *a, size_t c)
278 {
279 	const bus_addr_t addr = h + o;
280 
281 	for (; c != 0; c--, a++)
282 		*a = *(volatile uint32_t *)(addr);
283 }
284 
285 /*
286  *	void bus_space_read_region_N(bus_space_tag_t tag,
287  *	    bus_space_handle_t bsh, bus_size_t offset,
288  *	    u_intN_t *addr, size_t count);
289  *
290  * Read `count' 1, 2, 4, or 8 byte quantities from bus space
291  * described by tag/handle and starting at `offset' and copy into
292  * buffer provided.
293  */
294 
295 static __inline void vax_mem_read_region_1(bus_space_tag_t,
296 	bus_space_handle_t, bus_size_t, uint8_t *, size_t);
297 static __inline void vax_mem_read_region_2(bus_space_tag_t,
298 	bus_space_handle_t, bus_size_t, uint16_t *, size_t);
299 static __inline void vax_mem_read_region_4(bus_space_tag_t,
300 	bus_space_handle_t, bus_size_t, uint32_t *, size_t);
301 
302 #define	bus_space_read_region_1(t, h, o, a, c)				\
303 do {									\
304 	vax_mem_read_region_1((t), (h), (o), (a), (c));		\
305 } while (0)
306 
307 #define bus_space_read_region_2(t, h, o, a, c)				\
308 do {									\
309 	__BUS_SPACE_ADDRESS_SANITY((a), uint16_t, "buffer");		\
310 	__BUS_SPACE_ADDRESS_SANITY((h) + (o), uint16_t, "bus addr");	\
311 	vax_mem_read_region_2((t), (h), (o), (a), (c));		\
312 } while (0)
313 
314 #define bus_space_read_region_4(t, h, o, a, c)				\
315 do {									\
316 	__BUS_SPACE_ADDRESS_SANITY((a), uint32_t, "buffer");		\
317 	__BUS_SPACE_ADDRESS_SANITY((h) + (o), uint32_t, "bus addr");	\
318 	vax_mem_read_region_4((t), (h), (o), (a), (c));		\
319 } while (0)
320 
321 #if 0	/* Cause a link error for bus_space_read_region_8 */
322 #define	bus_space_read_region_8					\
323 			!!! bus_space_read_region_8 unimplemented !!!
324 #endif
325 
326 static __inline void
327 vax_mem_read_region_1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o,
328 	uint8_t *a, size_t c)
329 {
330 	bus_addr_t addr = h + o;
331 
332 	for (; c != 0; c--, addr++, a++)
333 		*a = *(volatile uint8_t *)(addr);
334 }
335 
336 static __inline void
337 vax_mem_read_region_2(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o,
338 	uint16_t *a, size_t c)
339 {
340 	bus_addr_t addr = h + o;
341 
342 	for (; c != 0; c--, addr += 2, a++)
343 		*a = *(volatile uint16_t *)(addr);
344 }
345 
346 static __inline void
347 vax_mem_read_region_4(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o,
348 	uint32_t *a, size_t c)
349 {
350 	bus_addr_t addr = h + o;
351 
352 	for (; c != 0; c--, addr += 4, a++)
353 		*a = *(volatile uint32_t *)(addr);
354 }
355 
356 /*
357  *	void bus_space_write_N(bus_space_tag_t tag,
358  *	    bus_space_handle_t bsh, bus_size_t offset,
359  *	    u_intN_t value);
360  *
361  * Write the 1, 2, 4, or 8 byte value `value' to bus space
362  * described by tag/handle/offset.
363  */
364 
365 #define	bus_space_write_1(t, h, o, v)					\
366 do {									\
367 	((void)(*(volatile uint8_t *)((h) + (o)) = (v)));		\
368 } while (0)
369 
370 #define	bus_space_write_2(t, h, o, v)					\
371 do {									\
372 	__BUS_SPACE_ADDRESS_SANITY((h) + (o), uint16_t, "bus addr");	\
373 	((void)(*(volatile uint16_t *)((h) + (o)) = (v)));		\
374 } while (0)
375 
376 #define	bus_space_write_4(t, h, o, v)					\
377 do {									\
378 	__BUS_SPACE_ADDRESS_SANITY((h) + (o), uint32_t, "bus addr");	\
379 	((void)(*(volatile uint32_t *)((h) + (o)) = (v)));		\
380 } while (0)
381 
382 #if 0	/* Cause a link error for bus_space_write_8 */
383 #define	bus_space_write_8	!!! bus_space_write_8 not implemented !!!
384 #endif
385 
386 /*
387  *	void bus_space_write_multi_N(bus_space_tag_t tag,
388  *	    bus_space_handle_t bsh, bus_size_t offset,
389  *	    const u_intN_t *addr, size_t count);
390  *
391  * Write `count' 1, 2, 4, or 8 byte quantities from the buffer
392  * provided to bus space described by tag/handle/offset.
393  */
394 static __inline void
395 	vax_mem_write_multi_1(bus_space_tag_t, bus_space_handle_t, bus_size_t,
396 	    const uint8_t *, size_t),
397 	vax_mem_write_multi_2(bus_space_tag_t, bus_space_handle_t, bus_size_t,
398 	    const uint16_t *, size_t),
399 	vax_mem_write_multi_4(bus_space_tag_t, bus_space_handle_t, bus_size_t,
400 	    const uint32_t *, size_t);
401 
402 #define	bus_space_write_multi_1(t, h, o, a, c)				\
403 do {									\
404 	vax_mem_write_multi_1((t), (h), (o), (a), (c));		\
405 } while (0)
406 
407 #define bus_space_write_multi_2(t, h, o, a, c)				\
408 do {									\
409 	__BUS_SPACE_ADDRESS_SANITY((a), uint16_t, "buffer");		\
410 	__BUS_SPACE_ADDRESS_SANITY((h) + (o), uint16_t, "bus addr");	\
411 	vax_mem_write_multi_2((t), (h), (o), (a), (c));		\
412 } while (0)
413 
414 #define bus_space_write_multi_4(t, h, o, a, c)				\
415 do {									\
416 	__BUS_SPACE_ADDRESS_SANITY((a), uint32_t, "buffer");		\
417 	__BUS_SPACE_ADDRESS_SANITY((h) + (o), uint32_t, "bus addr");	\
418 	vax_mem_write_multi_4((t), (h), (o), (a), (c));		\
419 } while (0)
420 
421 #if 0	/* Cause a link error for bus_space_write_multi_8 */
422 #define	bus_space_write_multi_8(t, h, o, a, c)				\
423 			!!! bus_space_write_multi_8 unimplemented !!!
424 #endif
425 
426 static __inline void
427 vax_mem_write_multi_1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o,
428 	const uint8_t *a, size_t c)
429 {
430 	const bus_addr_t addr = h + o;
431 
432 	for (; c != 0; c--, a++)
433 		*(volatile uint8_t *)(addr) = *a;
434 }
435 
436 static __inline void
437 vax_mem_write_multi_2(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o,
438 	const uint16_t *a, size_t c)
439 {
440 	const bus_addr_t addr = h + o;
441 
442 	for (; c != 0; c--, a++)
443 		*(volatile uint16_t *)(addr) = *a;
444 }
445 
446 static __inline void
447 vax_mem_write_multi_4(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o,
448 	const uint32_t *a, size_t c)
449 {
450 	const bus_addr_t addr = h + o;
451 
452 	for (; c != 0; c--, a++)
453 		*(volatile uint32_t *)(addr) = *a;
454 }
455 
456 /*
457  *	void bus_space_write_region_N(bus_space_tag_t tag,
458  *	    bus_space_handle_t bsh, bus_size_t offset,
459  *	    const u_intN_t *addr, size_t count);
460  *
461  * Write `count' 1, 2, 4, or 8 byte quantities from the buffer provided
462  * to bus space described by tag/handle starting at `offset'.
463  */
464 static __inline void
465 	vax_mem_write_region_1(bus_space_tag_t, bus_space_handle_t, bus_size_t,
466 	    const uint8_t *, size_t),
467 	vax_mem_write_region_2(bus_space_tag_t, bus_space_handle_t, bus_size_t,
468 	    const uint16_t *, size_t),
469 	vax_mem_write_region_4(bus_space_tag_t, bus_space_handle_t, bus_size_t,
470 	    const uint32_t *, size_t);
471 
472 #define	bus_space_write_region_1(t, h, o, a, c)				\
473 	vax_mem_write_region_1((t), (h), (o), (a), (c))
474 
475 #define bus_space_write_region_2(t, h, o, a, c)				\
476 do {									\
477 	__BUS_SPACE_ADDRESS_SANITY((a), uint16_t, "buffer");		\
478 	__BUS_SPACE_ADDRESS_SANITY((h) + (o), uint16_t, "bus addr");	\
479 	vax_mem_write_region_2((t), (h), (o), (a), (c));		\
480 } while (0)
481 
482 #define bus_space_write_region_4(t, h, o, a, c)				\
483 do {									\
484 	__BUS_SPACE_ADDRESS_SANITY((a), uint32_t, "buffer");		\
485 	__BUS_SPACE_ADDRESS_SANITY((h) + (o), uint32_t, "bus addr");	\
486 	vax_mem_write_region_4((t), (h), (o), (a), (c));		\
487 } while (0)
488 
489 #if 0	/* Cause a link error for bus_space_write_region_8 */
490 #define	bus_space_write_region_8					\
491 			!!! bus_space_write_region_8 unimplemented !!!
492 #endif
493 
494 static __inline void
495 vax_mem_write_region_1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o,
496 	const uint8_t *a, size_t c)
497 {
498 	bus_addr_t addr = h + o;
499 
500 	for (; c != 0; c--, addr++, a++)
501 		*(volatile uint8_t *)(addr) = *a;
502 }
503 
504 static __inline void
505 vax_mem_write_region_2(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o,
506 	const uint16_t *a, size_t c)
507 {
508 	bus_addr_t addr = h + o;
509 
510 	for (; c != 0; c--, addr++, a++)
511 		*(volatile uint16_t *)(addr) = *a;
512 }
513 
514 static __inline void
515 vax_mem_write_region_4(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o,
516 	const uint32_t *a, size_t c)
517 {
518 	bus_addr_t addr = h + o;
519 
520 	for (; c != 0; c--, addr++, a++)
521 		*(volatile uint32_t *)(addr) = *a;
522 }
523 
524 /*
525  *	void bus_space_set_multi_N(bus_space_tag_t tag,
526  *	    bus_space_handle_t bsh, bus_size_t offset, u_intN_t val,
527  *	    size_t count);
528  *
529  * Write the 1, 2, 4, or 8 byte value `val' to bus space described
530  * by tag/handle/offset `count' times.
531  */
532 
533 static __inline void
534 	vax_mem_set_multi_1(bus_space_tag_t, bus_space_handle_t, bus_size_t,
535 	    uint8_t, size_t),
536 	vax_mem_set_multi_2(bus_space_tag_t, bus_space_handle_t, bus_size_t,
537 	    uint16_t, size_t),
538 	vax_mem_set_multi_4(bus_space_tag_t, bus_space_handle_t, bus_size_t,
539 	    uint32_t, size_t);
540 
541 #define	bus_space_set_multi_1(t, h, o, v, c)				\
542 	vax_mem_set_multi_1((t), (h), (o), (v), (c))
543 
544 #define	bus_space_set_multi_2(t, h, o, v, c)				\
545 do {									\
546 	__BUS_SPACE_ADDRESS_SANITY((h) + (o), uint16_t, "bus addr");	\
547 	vax_mem_set_multi_2((t), (h), (o), (v), (c));		\
548 } while (0)
549 
550 #define	bus_space_set_multi_4(t, h, o, v, c)				\
551 do {									\
552 	__BUS_SPACE_ADDRESS_SANITY((h) + (o), uint32_t, "bus addr");	\
553 	vax_mem_set_multi_4((t), (h), (o), (v), (c));		\
554 } while (0)
555 
556 static __inline void
557 vax_mem_set_multi_1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o,
558 	uint8_t v, size_t c)
559 {
560 	bus_addr_t addr = h + o;
561 
562 	while (c--)
563 		*(volatile uint8_t *)(addr) = v;
564 }
565 
566 static __inline void
567 vax_mem_set_multi_2(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o,
568 	uint16_t v, size_t c)
569 {
570 	bus_addr_t addr = h + o;
571 
572 	while (c--)
573 		*(volatile uint16_t *)(addr) = v;
574 }
575 
576 static __inline void
577 vax_mem_set_multi_4(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o,
578 	uint32_t v, size_t c)
579 {
580 	bus_addr_t addr = h + o;
581 
582 	while (c--)
583 		*(volatile uint32_t *)(addr) = v;
584 }
585 
586 #if 0	/* Cause a link error for bus_space_set_multi_8 */
587 #define	bus_space_set_multi_8 !!! bus_space_set_multi_8 unimplemented !!!
588 #endif
589 
590 /*
591  *	void bus_space_set_region_N(bus_space_tag_t tag,
592  *	    bus_space_handle_t bsh, bus_size_t offset, u_intN_t val,
593  *	    size_t count);
594  *
595  * Write `count' 1, 2, 4, or 8 byte value `val' to bus space described
596  * by tag/handle starting at `offset'.
597  */
598 
599 static __inline void
600 	vax_mem_set_region_1(bus_space_tag_t, bus_space_handle_t, bus_size_t,
601 	    uint8_t, size_t),
602 	vax_mem_set_region_2(bus_space_tag_t, bus_space_handle_t, bus_size_t,
603 	    uint16_t, size_t),
604 	vax_mem_set_region_4(bus_space_tag_t, bus_space_handle_t, bus_size_t,
605 	    uint32_t, size_t);
606 
607 #define	bus_space_set_region_1(t, h, o, v, c)				\
608 	vax_mem_set_region_1((t), (h), (o), (v), (c))
609 
610 #define	bus_space_set_region_2(t, h, o, v, c)				\
611 do {									\
612 	__BUS_SPACE_ADDRESS_SANITY((h) + (o), uint16_t, "bus addr");	\
613 	vax_mem_set_region_2((t), (h), (o), (v), (c));		\
614 } while (0)
615 
616 #define	bus_space_set_region_4(t, h, o, v, c)				\
617 do {									\
618 	__BUS_SPACE_ADDRESS_SANITY((h) + (o), uint32_t, "bus addr");	\
619 	vax_mem_set_region_4((t), (h), (o), (v), (c));		\
620 } while (0)
621 
622 static __inline void
623 vax_mem_set_region_1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o,
624 	uint8_t v, size_t c)
625 {
626 	bus_addr_t addr = h + o;
627 
628 	for (; c != 0; c--, addr++)
629 		*(volatile uint8_t *)(addr) = v;
630 }
631 
632 static __inline void
633 vax_mem_set_region_2(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o,
634 	uint16_t v, size_t c)
635 {
636 	bus_addr_t addr = h + o;
637 
638 	for (; c != 0; c--, addr += 2)
639 		*(volatile uint16_t *)(addr) = v;
640 }
641 
642 static __inline void
643 vax_mem_set_region_4(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o,
644 	uint32_t v, size_t c)
645 {
646 	bus_addr_t addr = h + o;
647 
648 	for (; c != 0; c--, addr += 4)
649 		*(volatile uint32_t *)(addr) = v;
650 }
651 
652 #if 0	/* Cause a link error for bus_space_set_region_8 */
653 #define	bus_space_set_region_8	!!! bus_space_set_region_8 unimplemented !!!
654 #endif
655 
656 /*
657  *	void bus_space_copy_region_N(bus_space_tag_t tag,
658  *	    bus_space_handle_t bsh1, bus_size_t off1,
659  *	    bus_space_handle_t bsh2, bus_size_t off2,
660  *	    size_t count);
661  *
662  * Copy `count' 1, 2, 4, or 8 byte values from bus space starting
663  * at tag/bsh1/off1 to bus space starting at tag/bsh2/off2.
664  */
665 
666 static __inline void
667 	vax_mem_copy_region_1(bus_space_tag_t, bus_space_handle_t, bus_size_t,
668 	    bus_space_handle_t, bus_size_t, size_t),
669 	vax_mem_copy_region_2(bus_space_tag_t, bus_space_handle_t, bus_size_t,
670 	    bus_space_handle_t, bus_size_t, size_t),
671 	vax_mem_copy_region_4(bus_space_tag_t, bus_space_handle_t, bus_size_t,
672 	    bus_space_handle_t, bus_size_t, size_t);
673 
674 #define	bus_space_copy_region_1(t, h1, o1, h2, o2, c)			\
675 	vax_mem_copy_region_1((t), (h1), (o1), (h2), (o2), (c))
676 
677 #define	bus_space_copy_region_2(t, h1, o1, h2, o2, c)			\
678 do {									\
679 	__BUS_SPACE_ADDRESS_SANITY((h1) + (o1), uint16_t, "bus addr 1"); \
680 	__BUS_SPACE_ADDRESS_SANITY((h2) + (o2), uint16_t, "bus addr 2"); \
681 	vax_mem_copy_region_2((t), (h1), (o1), (h2), (o2), (c));	\
682 } while (0)
683 
684 #define	bus_space_copy_region_4(t, h1, o1, h2, o2, c)			\
685 do {									\
686 	__BUS_SPACE_ADDRESS_SANITY((h1) + (o1), uint32_t, "bus addr 1"); \
687 	__BUS_SPACE_ADDRESS_SANITY((h2) + (o2), uint32_t, "bus addr 2"); \
688 	vax_mem_copy_region_4((t), (h1), (o1), (h2), (o2), (c));	\
689 } while (0)
690 
691 static __inline void
692 vax_mem_copy_region_1(bus_space_tag_t t, bus_space_handle_t h1, bus_size_t o1,
693 	bus_space_handle_t h2, bus_size_t o2, size_t c)
694 {
695 	bus_addr_t addr1 = h1 + o1;
696 	bus_addr_t addr2 = h2 + o2;
697 
698 	if (addr1 >= addr2) {
699 		/* src after dest: copy forward */
700 		for (; c != 0; c--, addr1++, addr2++)
701 			*(volatile uint8_t *)(addr2) =
702 			    *(volatile uint8_t *)(addr1);
703 	} else {
704 		/* dest after src: copy backwards */
705 		for (addr1 += (c - 1), addr2 += (c - 1);
706 		    c != 0; c--, addr1--, addr2--)
707 			*(volatile uint8_t *)(addr2) =
708 			    *(volatile uint8_t *)(addr1);
709 	}
710 }
711 
712 static __inline void
713 vax_mem_copy_region_2(bus_space_tag_t t, bus_space_handle_t h1, bus_size_t o1,
714 	bus_space_handle_t h2, bus_size_t o2, size_t c)
715 {
716 	bus_addr_t addr1 = h1 + o1;
717 	bus_addr_t addr2 = h2 + o2;
718 
719 	if (addr1 >= addr2) {
720 		/* src after dest: copy forward */
721 		for (; c != 0; c--, addr1 += 2, addr2 += 2)
722 			*(volatile uint16_t *)(addr2) =
723 			    *(volatile uint16_t *)(addr1);
724 	} else {
725 		/* dest after src: copy backwards */
726 		for (addr1 += 2 * (c - 1), addr2 += 2 * (c - 1);
727 		    c != 0; c--, addr1 -= 2, addr2 -= 2)
728 			*(volatile uint16_t *)(addr2) =
729 			    *(volatile uint16_t *)(addr1);
730 	}
731 }
732 
733 static __inline void
734 vax_mem_copy_region_4(bus_space_tag_t t, bus_space_handle_t h1, bus_size_t o1,
735 	bus_space_handle_t h2, bus_size_t o2, size_t c)
736 {
737 	bus_addr_t addr1 = h1 + o1;
738 	bus_addr_t addr2 = h2 + o2;
739 
740 	if (addr1 >= addr2) {
741 		/* src after dest: copy forward */
742 		for (; c != 0; c--, addr1 += 4, addr2 += 4)
743 			*(volatile uint32_t *)(addr2) =
744 			    *(volatile uint32_t *)(addr1);
745 	} else {
746 		/* dest after src: copy backwards */
747 		for (addr1 += 4 * (c - 1), addr2 += 4 * (c - 1);
748 		    c != 0; c--, addr1 -= 4, addr2 -= 4)
749 			*(volatile uint32_t *)(addr2) =
750 			    *(volatile uint32_t *)(addr1);
751 	}
752 }
753 
754 #if 0	/* Cause a link error for bus_space_copy_8 */
755 #define	bus_space_copy_region_8	!!! bus_space_copy_region_8 unimplemented !!!
756 #endif
757 
758 
759 /*
760  * Bus read/write barrier methods.
761  *
762  *	void bus_space_barrier(bus_space_tag_t tag,
763  *	    bus_space_handle_t bsh, bus_size_t offset,
764  *	    bus_size_t len, int flags);
765  *
766  * Note: the vax does not currently require barriers, but we must
767  * provide the flags to MI code.
768  */
769 #define	bus_space_barrier(t, h, o, l, f)	\
770 	((void)((void)(t), (void)(h), (void)(o), (void)(l), (void)(f)))
771 #define	BUS_SPACE_BARRIER_READ	0x01		/* force read barrier */
772 #define	BUS_SPACE_BARRIER_WRITE	0x02		/* force write barrier */
773 
774 
775 /*
776  * Flags used in various bus DMA methods.
777  */
778 #define	BUS_DMA_WAITOK		0x000	/* safe to sleep (pseudo-flag) */
779 #define	BUS_DMA_NOWAIT		0x001	/* not safe to sleep */
780 #define	BUS_DMA_ALLOCNOW	0x002	/* perform resource allocation now */
781 #define	BUS_DMA_COHERENT	0x004	/* hint: map memory DMA coherent */
782 #define	BUS_DMA_STREAMING	0x008	/* hint: sequential, unidirectional */
783 #define	BUS_DMA_BUS1		0x010	/* placeholders for bus functions... */
784 #define	BUS_DMA_BUS2		0x020
785 #define	BUS_DMA_BUS3		0x040
786 #define	BUS_DMA_BUS4		0x080
787 #define	BUS_DMA_READ		0x100	/* mapping is device -> memory only */
788 #define	BUS_DMA_WRITE		0x200	/* mapping is memory -> device only */
789 #define	BUS_DMA_NOCACHE		0x400	/* hint: map non-cached memory */
790 
791 #define	VAX_BUS_DMA_SPILLPAGE	BUS_DMA_BUS1	/* VS4000 kludge */
792 /*
793  * Private flags stored in the DMA map.
794  */
795 #define DMAMAP_HAS_SGMAP	0x80000000	/* sgva/len are valid */
796 
797 /* Forwards needed by prototypes below. */
798 struct mbuf;
799 struct uio;
800 struct vax_sgmap;
801 
802 /*
803  * Operations performed by bus_dmamap_sync().
804  */
805 #define	BUS_DMASYNC_PREREAD	0x01	/* pre-read synchronization */
806 #define	BUS_DMASYNC_POSTREAD	0x02	/* post-read synchronization */
807 #define	BUS_DMASYNC_PREWRITE	0x04	/* pre-write synchronization */
808 #define	BUS_DMASYNC_POSTWRITE	0x08	/* post-write synchronization */
809 
810 /*
811  *	vax_bus_t
812  *
813  *	Busses supported by NetBSD/vax, used by internal
814  *	utility functions.  NOT TO BE USED BY MACHINE-INDEPENDENT
815  *	CODE!
816  */
817 typedef enum {
818 	VAX_BUS_MAINBUS,
819 	VAX_BUS_SBI,
820 	VAX_BUS_MASSBUS,
821 	VAX_BUS_UNIBUS,		/* Also handles QBUS */
822 	VAX_BUS_BI,
823 	VAX_BUS_XMI,
824 	VAX_BUS_TURBOCHANNEL
825 } vax_bus_t;
826 
827 typedef struct vax_bus_dma_tag	*bus_dma_tag_t;
828 typedef struct vax_bus_dmamap	*bus_dmamap_t;
829 
830 #define BUS_DMA_TAG_VALID(t)    ((t) != (bus_dma_tag_t)0)
831 
832 /*
833  *	bus_dma_segment_t
834  *
835  *	Describes a single contiguous DMA transaction.  Values
836  *	are suitable for programming into DMA registers.
837  */
838 struct vax_bus_dma_segment {
839 	bus_addr_t	ds_addr;	/* DMA address */
840 	bus_size_t	ds_len;		/* length of transfer */
841 };
842 typedef struct vax_bus_dma_segment	bus_dma_segment_t;
843 
844 struct proc;
845 
846 /*
847  *	bus_dma_tag_t
848  *
849  *	A machine-dependent opaque type describing the implementation of
850  *	DMA for a given bus.
851  */
852 struct vax_bus_dma_tag {
853 	void	*_cookie;		/* cookie used in the guts */
854 	bus_addr_t _wbase;		/* DMA window base */
855 	bus_size_t _wsize;		/* DMA window size */
856 
857 	/*
858 	 * Some chipsets have a built-in boundary constraint, independent
859 	 * of what the device requests.  This allows that boundary to
860 	 * be specified.  If the device has a more restrictive constraint,
861 	 * the map will use that, otherwise this boundary will be used.
862 	 * This value is ignored if 0.
863 	 */
864 	bus_size_t _boundary;
865 
866 	/*
867 	 * A bus may have more than one SGMAP window, so SGMAP
868 	 * windows also get a pointer to their SGMAP state.
869 	 */
870 	struct vax_sgmap *_sgmap;
871 
872 	/*
873 	 * Internal-use only utility methods.  NOT TO BE USED BY
874 	 * MACHINE-INDEPENDENT CODE!
875 	 */
876 	bus_dma_tag_t (*_get_tag)(bus_dma_tag_t, vax_bus_t);
877 
878 	/*
879 	 * DMA mapping methods.
880 	 */
881 	int	(*_dmamap_create)(bus_dma_tag_t, bus_size_t, int,
882 		    bus_size_t, bus_size_t, int, bus_dmamap_t *);
883 	void	(*_dmamap_destroy)(bus_dma_tag_t, bus_dmamap_t);
884 	int	(*_dmamap_load)(bus_dma_tag_t, bus_dmamap_t, void *,
885 		    bus_size_t, struct proc *, int);
886 	int	(*_dmamap_load_mbuf)(bus_dma_tag_t, bus_dmamap_t,
887 		    struct mbuf *, int);
888 	int	(*_dmamap_load_uio)(bus_dma_tag_t, bus_dmamap_t,
889 		    struct uio *, int);
890 	int	(*_dmamap_load_raw)(bus_dma_tag_t, bus_dmamap_t,
891 		    bus_dma_segment_t *, int, bus_size_t, int);
892 	void	(*_dmamap_unload)(bus_dma_tag_t, bus_dmamap_t);
893 	void	(*_dmamap_sync)(bus_dma_tag_t, bus_dmamap_t,
894 		    bus_addr_t, bus_size_t, int);
895 
896 	/*
897 	 * DMA memory utility functions.
898 	 */
899 	int	(*_dmamem_alloc)(bus_dma_tag_t, bus_size_t, bus_size_t,
900 		    bus_size_t, bus_dma_segment_t *, int, int *, int);
901 	void	(*_dmamem_free)(bus_dma_tag_t, bus_dma_segment_t *, int);
902 	int	(*_dmamem_map)(bus_dma_tag_t, bus_dma_segment_t *,
903 		    int, size_t, void **, int);
904 	void	(*_dmamem_unmap)(bus_dma_tag_t, void *, size_t);
905 	paddr_t	(*_dmamem_mmap)(bus_dma_tag_t, bus_dma_segment_t *,
906 		    int, off_t, int, int);
907 };
908 
909 #define	vaxbus_dma_get_tag(t, b)				\
910 	(*(t)->_get_tag)(t, b)
911 
912 #define	bus_dmamap_create(t, s, n, m, b, f, p)			\
913 	(*(t)->_dmamap_create)((t), (s), (n), (m), (b), (f), (p))
914 #define	bus_dmamap_destroy(t, p)				\
915 	(*(t)->_dmamap_destroy)((t), (p))
916 #define	bus_dmamap_load(t, m, b, s, p, f)			\
917 	(*(t)->_dmamap_load)((t), (m), (b), (s), (p), (f))
918 #define	bus_dmamap_load_mbuf(t, m, b, f)			\
919 	(*(t)->_dmamap_load_mbuf)((t), (m), (b), (f))
920 #define	bus_dmamap_load_uio(t, m, u, f)				\
921 	(*(t)->_dmamap_load_uio)((t), (m), (u), (f))
922 #define	bus_dmamap_load_raw(t, m, sg, n, s, f)			\
923 	(*(t)->_dmamap_load_raw)((t), (m), (sg), (n), (s), (f))
924 #define	bus_dmamap_unload(t, p)					\
925 	(*(t)->_dmamap_unload)((t), (p))
926 #define	bus_dmamap_sync(t, p, o, l, ops)			\
927 	(*(t)->_dmamap_sync)((t), (p), (o), (l), (ops))
928 #define	bus_dmamem_alloc(t, s, a, b, sg, n, r, f)		\
929 	(*(t)->_dmamem_alloc)((t), (s), (a), (b), (sg), (n), (r), (f))
930 #define	bus_dmamem_free(t, sg, n)				\
931 	(*(t)->_dmamem_free)((t), (sg), (n))
932 #define	bus_dmamem_map(t, sg, n, s, k, f)			\
933 	(*(t)->_dmamem_map)((t), (sg), (n), (s), (k), (f))
934 #define	bus_dmamem_unmap(t, k, s)				\
935 	(*(t)->_dmamem_unmap)((t), (k), (s))
936 #define	bus_dmamem_mmap(t, sg, n, o, p, f)			\
937 	(*(t)->_dmamem_mmap)((t), (sg), (n), (o), (p), (f))
938 
939 #define bus_dmatag_subregion(t, mna, mxa, nt, f) EOPNOTSUPP
940 #define bus_dmatag_destroy(t)
941 
942 /*
943  *	bus_dmamap_t
944  *
945  *	Describes a DMA mapping.
946  */
947 struct vax_bus_dmamap {
948 	/*
949 	 * PRIVATE MEMBERS: not for use my machine-independent code.
950 	 */
951 	bus_size_t	_dm_size;	/* largest DMA transfer mappable */
952 	int		_dm_segcnt;	/* number of segs this map can map */
953 	bus_size_t	_dm_maxmaxsegsz; /* fixed largest possible segment */
954 	bus_size_t	_dm_boundary;	/* don't cross this */
955 	int		_dm_flags;	/* misc. flags */
956 
957 	/*
958 	 * This is used only for SGMAP-mapped DMA, but we keep it
959 	 * here to avoid pointless indirection.
960 	 */
961 	int		_dm_pteidx;	/* PTE index */
962 	int		_dm_ptecnt;	/* PTE count */
963 	u_long		_dm_sgva;	/* allocated sgva */
964 	bus_size_t	_dm_sgvalen;	/* svga length */
965 
966 	/*
967 	 * PUBLIC MEMBERS: these are used by machine-independent code.
968 	 */
969 	bus_size_t	dm_maxsegsz;	/* largest possible segment */
970 	bus_size_t	dm_mapsize;	/* size of the mapping */
971 	int		dm_nsegs;	/* # valid segments in mapping */
972 	bus_dma_segment_t dm_segs[1];	/* segments; variable length */
973 };
974 
975 /*#ifdef _VAX_BUS_DMA_PRIVATE */
976 int	_bus_dmamap_create(bus_dma_tag_t, bus_size_t, int, bus_size_t,
977 	    bus_size_t, int, bus_dmamap_t *);
978 void	_bus_dmamap_destroy(bus_dma_tag_t, bus_dmamap_t);
979 
980 int	_bus_dmamap_load(bus_dma_tag_t, bus_dmamap_t,
981 	    void *, bus_size_t, struct proc *, int);
982 int	_bus_dmamap_load_mbuf(bus_dma_tag_t, bus_dmamap_t, struct mbuf *, int);
983 int	_bus_dmamap_load_uio(bus_dma_tag_t, bus_dmamap_t, struct uio *, int);
984 int	_bus_dmamap_load_raw(bus_dma_tag_t,
985 	    bus_dmamap_t, bus_dma_segment_t *, int, bus_size_t, int);
986 
987 void	_bus_dmamap_unload(bus_dma_tag_t, bus_dmamap_t);
988 void	_bus_dmamap_sync(bus_dma_tag_t, bus_dmamap_t, bus_addr_t,
989 	    bus_size_t, int);
990 
991 int	_bus_dmamem_alloc(bus_dma_tag_t tag, bus_size_t size,
992 	    bus_size_t alignment, bus_size_t boundary,
993 	    bus_dma_segment_t *segs, int nsegs, int *rsegs, int flags);
994 void	_bus_dmamem_free(bus_dma_tag_t tag, bus_dma_segment_t *segs, int nsegs);
995 int	_bus_dmamem_map(bus_dma_tag_t tag, bus_dma_segment_t *segs,
996 	    int nsegs, size_t size, void **kvap, int flags);
997 void	_bus_dmamem_unmap(bus_dma_tag_t tag, void *kva, size_t size);
998 paddr_t	_bus_dmamem_mmap(bus_dma_tag_t tag, bus_dma_segment_t *segs,
999 	    int nsegs, off_t off, int prot, int flags);
1000 /*#endif*/ /* _VAX_BUS_DMA_PRIVATE */
1001 
1002 #endif /* _VAX_BUS_H_ */
1003