1 /* $NetBSD: bus_space.c,v 1.19 2002/05/04 05:13:28 takemura Exp $ */ 2 3 /*- 4 * Copyright (c) 1998 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 #include <sys/param.h> 41 #include <sys/systm.h> 42 #include <sys/malloc.h> 43 #include <sys/extent.h> 44 45 #include <uvm/uvm_extern.h> 46 47 #include <mips/cache.h> 48 #include <mips/pte.h> 49 #include <machine/bus.h> 50 #include <machine/bus_space_hpcmips.h> 51 52 #ifdef BUS_SPACE_DEBUG 53 #define DPRINTF(arg) printf arg 54 #else 55 #define DPRINTF(arg) 56 #endif 57 58 #define MAX_BUSSPACE_TAG 10 59 60 /* proto types */ 61 bus_space_handle_t __hpcmips_cacheable(struct bus_space_tag_hpcmips*, 62 bus_addr_t, bus_size_t, int); 63 bus_space_protos(_); 64 bus_space_protos(bs_notimpl); 65 66 /* variables */ 67 static struct bus_space_tag_hpcmips __bus_space[MAX_BUSSPACE_TAG]; 68 static int __bus_space_index; 69 static struct bus_space_tag_hpcmips __sys_bus_space = { 70 { 71 NULL, 72 { 73 /* mapping/unmapping */ 74 __bs_map, 75 __bs_unmap, 76 __bs_subregion, 77 78 /* allocation/deallocation */ 79 __bs_alloc, 80 __bs_free, 81 82 /* get kernel virtual address */ 83 bs_notimpl_bs_vaddr, /* there is no linear mapping */ 84 85 /* Mmap bus space for user */ 86 bs_notimpl_bs_mmap, 87 88 /* barrier */ 89 __bs_barrier, 90 91 /* probe */ 92 __bs_peek, 93 __bs_poke, 94 95 /* read (single) */ 96 __bs_r_1, 97 __bs_r_2, 98 __bs_r_4, 99 bs_notimpl_bs_r_8, 100 101 /* read multiple */ 102 __bs_rm_1, 103 __bs_rm_2, 104 __bs_rm_4, 105 bs_notimpl_bs_rm_8, 106 107 /* read region */ 108 __bs_rr_1, 109 __bs_rr_2, 110 __bs_rr_4, 111 bs_notimpl_bs_rr_8, 112 113 /* write (single) */ 114 __bs_w_1, 115 __bs_w_2, 116 __bs_w_4, 117 bs_notimpl_bs_w_8, 118 119 /* write multiple */ 120 __bs_wm_1, 121 __bs_wm_2, 122 __bs_wm_4, 123 bs_notimpl_bs_wm_8, 124 125 /* write region */ 126 __bs_wr_1, 127 __bs_wr_2, 128 __bs_wr_4, 129 bs_notimpl_bs_wr_8, 130 131 /* set multi */ 132 __bs_sm_1, 133 __bs_sm_2, 134 __bs_sm_4, 135 bs_notimpl_bs_sm_8, 136 137 /* set region */ 138 __bs_sr_1, 139 __bs_sr_2, 140 __bs_sr_4, 141 bs_notimpl_bs_sr_8, 142 143 /* copy */ 144 __bs_c_1, 145 __bs_c_2, 146 __bs_c_4, 147 bs_notimpl_bs_c_8, 148 }, 149 }, 150 151 "whole bus space", /* bus name */ 152 0, /* extent base */ 153 0xffffffff, /* extent size */ 154 NULL, /* pointer for extent structure */ 155 }; 156 static bus_space_tag_t __sys_bus_space_tag = &__sys_bus_space.bst; 157 158 bus_space_tag_t 159 hpcmips_system_bus_space() 160 { 161 162 return (__sys_bus_space_tag); 163 } 164 165 struct bus_space_tag_hpcmips * 166 hpcmips_system_bus_space_hpcmips() 167 { 168 169 return (&__sys_bus_space); 170 } 171 172 struct bus_space_tag_hpcmips * 173 hpcmips_alloc_bus_space_tag() 174 { 175 176 if (__bus_space_index >= MAX_BUSSPACE_TAG) { 177 panic("hpcmips_internal_alloc_bus_space_tag: tag full."); 178 } 179 180 return (&__bus_space[__bus_space_index++]); 181 } 182 183 void 184 hpcmips_init_bus_space(struct bus_space_tag_hpcmips *t, 185 struct bus_space_tag_hpcmips *basetag, 186 char *name, u_int32_t base, u_int32_t size) 187 { 188 u_int32_t pa, endpa; 189 vaddr_t va; 190 191 if (basetag != NULL) 192 memcpy(t, basetag, sizeof(struct bus_space_tag_hpcmips)); 193 strncpy(t->name, name, sizeof(t->name)); 194 t->name[sizeof(t->name) - 1] = '\0'; 195 t->base = base; 196 t->size = size; 197 198 /* 199 * If request physical address is greater than 512MByte, 200 * mapping it to kseg2. 201 */ 202 if (t->base >= 0x20000000) { 203 pa = mips_trunc_page(t->base); 204 endpa = mips_round_page(t->base + t->size); 205 206 if (!(va = uvm_km_valloc(kernel_map, endpa - pa))) { 207 panic("hpcmips_init_bus_space_extent:" 208 "can't allocate kernel virtual"); 209 } 210 DPRINTF(("pa:0x%08x -> kv:0x%08x+0x%08x", 211 (unsigned int)t->base, (unsigned int)va, t->size)); 212 t->base = va; /* kseg2 addr */ 213 214 for (; pa < endpa; pa += NBPG, va += NBPG) { 215 pmap_kenter_pa(va, pa, VM_PROT_READ | VM_PROT_WRITE); 216 } 217 pmap_update(pmap_kernel()); 218 } 219 220 t->extent = (void*)extent_create(t->name, t->base, 221 t->base + t->size, M_DEVBUF, 222 0, 0, EX_NOWAIT); 223 if (!t->extent) { 224 panic("hpcmips_init_bus_space_extent:" 225 "unable to allocate %s map", t->name); 226 } 227 } 228 229 bus_space_handle_t 230 __hpcmips_cacheable(struct bus_space_tag_hpcmips *t, bus_addr_t bpa, 231 bus_size_t size, int cacheable) 232 { 233 vaddr_t va, endva; 234 pt_entry_t *pte; 235 u_int32_t opte, npte; 236 237 if (t->base >= MIPS_KSEG2_START) { 238 va = mips_trunc_page(bpa); 239 endva = mips_round_page(bpa + size); 240 npte = CPUISMIPS3 ? MIPS3_PG_UNCACHED : MIPS1_PG_N; 241 242 mips_dcache_wbinv_range(va, endva - va); 243 244 for (; va < endva; va += NBPG) { 245 pte = kvtopte(va); 246 opte = pte->pt_entry; 247 if (cacheable) { 248 opte &= ~npte; 249 } else { 250 opte |= npte; 251 } 252 pte->pt_entry = opte; 253 /* 254 * Update the same virtual address entry. 255 */ 256 MachTLBUpdate(va, opte); 257 } 258 return (bpa); 259 } 260 261 return (cacheable ? MIPS_PHYS_TO_KSEG0(bpa) : MIPS_PHYS_TO_KSEG1(bpa)); 262 } 263 264 /* ARGSUSED */ 265 int 266 __bs_map(bus_space_tag_t tx, bus_addr_t bpa, bus_size_t size, int flags, 267 bus_space_handle_t *bshp) 268 { 269 struct bus_space_tag_hpcmips *t = (struct bus_space_tag_hpcmips *)tx; 270 int err; 271 int cacheable = flags & BUS_SPACE_MAP_CACHEABLE; 272 273 DPRINTF(("\tbus_space_map:%#lx(%#lx)+%#lx\n", 274 bpa, bpa + t->base, size)); 275 276 if (!t->extent) { /* Before autoconfiguration, can't use extent */ 277 DPRINTF(("bus_space_map: map temporary region:" 278 "0x%08lx-0x%08lx\n", bpa, bpa+size)); 279 bpa += t->base; 280 } else { 281 bpa += t->base; 282 if ((err = extent_alloc_region(t->extent, bpa, size, 283 EX_NOWAIT|EX_MALLOCOK))) { 284 DPRINTF(("\tbus_space_map: " 285 "extent_alloc_regiion() failed\n")); 286 return (err); 287 } 288 } 289 *bshp = __hpcmips_cacheable(t, bpa, size, cacheable); 290 291 return (0); 292 } 293 294 /* ARGSUSED */ 295 void 296 __bs_unmap(bus_space_tag_t tx, bus_space_handle_t bsh, bus_size_t size) 297 { 298 struct bus_space_tag_hpcmips *t = (struct bus_space_tag_hpcmips *)tx; 299 int err; 300 u_int32_t addr; 301 302 if (!t->extent) { 303 return; /* Before autoconfiguration, can't use extent */ 304 } 305 306 if (t->base < MIPS_KSEG2_START) { 307 addr = MIPS_KSEG1_TO_PHYS(bsh); 308 } else { 309 addr = bsh; 310 } 311 312 if ((err = extent_free(t->extent, addr, size, EX_NOWAIT))) { 313 DPRINTF(("warning: %#lx-%#lx of %s space lost\n", 314 bsh, bsh+size, t->name)); 315 } 316 } 317 318 /* ARGSUSED */ 319 int 320 __bs_subregion(bus_space_tag_t t, bus_space_handle_t bsh, 321 bus_size_t offset, bus_size_t size, bus_space_handle_t *nbshp) 322 { 323 324 *nbshp = bsh + offset; 325 326 return (0); 327 } 328 329 /* ARGSUSED */ 330 int 331 __bs_alloc(bus_space_tag_t tx, bus_addr_t rstart, bus_addr_t rend, 332 bus_size_t size, bus_size_t alignment, bus_size_t boundary, int flags, 333 bus_addr_t *bpap, bus_space_handle_t *bshp) 334 { 335 struct bus_space_tag_hpcmips *t = (struct bus_space_tag_hpcmips *)tx; 336 int cacheable = flags & BUS_SPACE_MAP_CACHEABLE; 337 u_long bpa; 338 int err; 339 340 if (!t->extent) 341 panic("bus_space_alloc: no extent"); 342 343 DPRINTF(("\tbus_space_alloc:%#lx(%#lx)+%#lx\n", bpa, 344 bpa - t->base, size)); 345 346 rstart += t->base; 347 rend += t->base; 348 if ((err = extent_alloc_subregion(t->extent, rstart, rend, size, 349 alignment, boundary, EX_FAST|EX_NOWAIT|EX_MALLOCOK, &bpa))) { 350 return (err); 351 } 352 353 *bshp = __hpcmips_cacheable(t, bpa, size, cacheable); 354 355 if (bpap) { 356 *bpap = bpa; 357 } 358 359 return (0); 360 } 361 362 /* ARGSUSED */ 363 void 364 __bs_free(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t size) 365 { 366 /* bus_space_unmap() does all that we need to do. */ 367 bus_space_unmap(t, bsh, size); 368 } 369 370 void 371 __bs_barrier(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset, 372 bus_size_t len, int flags) 373 { 374 wbflush(); 375 } 376 377 int 378 __bs_peek(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset, 379 size_t size, void *ptr) 380 { 381 u_int32_t tmp; 382 383 if (badaddr((void *)(bsh + offset), size)) 384 return (-1); 385 386 if (ptr == NULL) 387 ptr = &tmp; 388 389 switch(size) { 390 case 1: 391 *((u_int8_t *)ptr) = bus_space_read_1(t, bsh, offset); 392 break; 393 case 2: 394 *((u_int16_t *)ptr) = bus_space_read_2(t, bsh, offset); 395 break; 396 case 4: 397 *((u_int32_t *)ptr) = bus_space_read_4(t, bsh, offset); 398 break; 399 default: 400 panic("bus_space_peek: bad size, %d\n", size); 401 } 402 403 return (0); 404 } 405 406 int 407 __bs_poke(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset, 408 size_t size, u_int32_t val) 409 { 410 411 if (badaddr((void *)(bsh + offset), size)) 412 return (-1); 413 414 switch(size) { 415 case 1: 416 bus_space_write_1(t, bsh, offset, val); 417 break; 418 case 2: 419 bus_space_write_2(t, bsh, offset, val); 420 break; 421 case 4: 422 bus_space_write_4(t, bsh, offset, val); 423 break; 424 default: 425 panic("bus_space_poke: bad size, %d\n", size); 426 } 427 428 return (0); 429 } 430 431 u_int8_t 432 __bs_r_1(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset) 433 { 434 wbflush(); 435 return (*(volatile u_int8_t *)(bsh + offset)); 436 } 437 438 u_int16_t 439 __bs_r_2(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset) 440 { 441 wbflush(); 442 return (*(volatile u_int16_t *)(bsh + offset)); 443 } 444 445 u_int32_t 446 __bs_r_4(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset) 447 { 448 wbflush(); 449 return (*(volatile u_int32_t *)(bsh + offset)); 450 } 451 452 void 453 __bs_rm_1(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset, 454 u_int8_t *addr, bus_size_t count) { 455 while (count--) 456 *addr++ = bus_space_read_1(t, bsh, offset); 457 } 458 459 void 460 __bs_rm_2(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset, 461 u_int16_t *addr, bus_size_t count) 462 { 463 while (count--) 464 *addr++ = bus_space_read_2(t, bsh, offset); 465 } 466 467 void 468 __bs_rm_4(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset, 469 u_int32_t *addr, bus_size_t count) 470 { 471 while (count--) 472 *addr++ = bus_space_read_4(t, bsh, offset); 473 } 474 475 void 476 __bs_rr_1(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset, 477 u_int8_t *addr, bus_size_t count) 478 { 479 while (count--) { 480 *addr++ = bus_space_read_1(t, bsh, offset); 481 offset += sizeof(*addr); 482 } 483 } 484 485 void 486 __bs_rr_2(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset, 487 u_int16_t *addr, bus_size_t count) 488 { 489 while (count--) { 490 *addr++ = bus_space_read_2(t, bsh, offset); 491 offset += sizeof(*addr); 492 } 493 } 494 495 void 496 __bs_rr_4(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset, 497 u_int32_t *addr, bus_size_t count) 498 { 499 while (count--) { 500 *addr++ = bus_space_read_4(t, bsh, offset); 501 offset += sizeof(*addr); 502 } 503 } 504 505 void 506 __bs_w_1(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset, 507 u_int8_t value) 508 { 509 *(volatile u_int8_t *)(bsh + offset) = value; 510 wbflush(); 511 } 512 513 void 514 __bs_w_2(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset, 515 u_int16_t value) 516 { 517 *(volatile u_int16_t *)(bsh + offset) = value; 518 wbflush(); 519 } 520 521 void 522 __bs_w_4(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset, 523 u_int32_t value) 524 { 525 *(volatile u_int32_t *)(bsh + offset) = value; 526 wbflush(); 527 } 528 529 void 530 __bs_wm_1(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset, 531 const u_int8_t *addr, bus_size_t count) 532 { 533 while (count--) 534 bus_space_write_1(t, bsh, offset, *addr++); 535 } 536 537 void 538 __bs_wm_2(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset, 539 const u_int16_t *addr, bus_size_t count) 540 { 541 while (count--) 542 bus_space_write_2(t, bsh, offset, *addr++); 543 } 544 545 void 546 __bs_wm_4(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset, 547 const u_int32_t *addr, bus_size_t count) 548 { 549 while (count--) 550 bus_space_write_4(t, bsh, offset, *addr++); 551 } 552 553 void 554 __bs_wr_1(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset, 555 const u_int8_t *addr, bus_size_t count) 556 { 557 while (count--) { 558 bus_space_write_1(t, bsh, offset, *addr++); 559 offset += sizeof(*addr); 560 } 561 } 562 563 void 564 __bs_wr_2(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset, 565 const u_int16_t *addr, bus_size_t count) 566 { 567 while (count--) { 568 bus_space_write_2(t, bsh, offset, *addr++); 569 offset += sizeof(*addr); 570 } 571 } 572 573 void 574 __bs_wr_4(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset, 575 const u_int32_t *addr, bus_size_t count) 576 { 577 while (count--) { 578 bus_space_write_4(t, bsh, offset, *addr++); 579 offset += sizeof(*addr); 580 } 581 } 582 583 void 584 __bs_sm_1(bus_space_tag_t t, bus_space_handle_t bsh, 585 bus_size_t offset, u_int8_t value, bus_size_t count) 586 { 587 while (count--) 588 bus_space_write_1(t, bsh, offset, value); 589 } 590 591 void 592 __bs_sm_2(bus_space_tag_t t, bus_space_handle_t bsh, 593 bus_size_t offset, u_int16_t value, bus_size_t count) 594 { 595 while (count--) 596 bus_space_write_2(t, bsh, offset, value); 597 } 598 599 void 600 __bs_sm_4(bus_space_tag_t t, bus_space_handle_t bsh, 601 bus_size_t offset, u_int32_t value, bus_size_t count) 602 { 603 while (count--) 604 bus_space_write_4(t, bsh, offset, value); 605 } 606 607 608 void 609 __bs_sr_1(bus_space_tag_t t, bus_space_handle_t bsh, 610 bus_size_t offset, u_int8_t value, bus_size_t count) 611 { 612 while (count--) { 613 bus_space_write_1(t, bsh, offset, value); 614 offset += (value); 615 } 616 } 617 618 void 619 __bs_sr_2(bus_space_tag_t t, bus_space_handle_t bsh, 620 bus_size_t offset, u_int16_t value, bus_size_t count) 621 { 622 while (count--) { 623 bus_space_write_2(t, bsh, offset, value); 624 offset += (value); 625 } 626 } 627 628 void 629 __bs_sr_4(bus_space_tag_t t, bus_space_handle_t bsh, 630 bus_size_t offset, u_int32_t value, bus_size_t count) 631 { 632 while (count--) { 633 bus_space_write_4(t, bsh, offset, value); 634 offset += (value); 635 } 636 } 637 638 #define __bs_c_n(n) \ 639 void __CONCAT(__bs_c_,n)(bus_space_tag_t t, bus_space_handle_t h1, \ 640 bus_size_t o1, bus_space_handle_t h2, bus_size_t o2, bus_size_t c) \ 641 { \ 642 bus_size_t o; \ 643 \ 644 if ((h1 + o1) >= (h2 + o2)) { \ 645 /* src after dest: copy forward */ \ 646 for (o = 0; c != 0; c--, o += n) \ 647 __CONCAT(bus_space_write_,n)(t, h2, o2 + o, \ 648 __CONCAT(bus_space_read_,n)(t, h1, o1 + o));\ 649 } else { \ 650 /* dest after src: copy backwards */ \ 651 for (o = (c - 1) * n; c != 0; c--, o -= n) \ 652 __CONCAT(bus_space_write_,n)(t, h2, o2 + o, \ 653 __CONCAT(bus_space_read_,n)(t, h1, o1 + o));\ 654 } \ 655 } 656 657 __bs_c_n(1) 658 __bs_c_n(2) 659 __bs_c_n(4) 660