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