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