bus_machdep.c revision 86228
1/*- 2 * Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to The NetBSD Foundation 6 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 7 * NASA Ames Research Center. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by the NetBSD 20 * Foundation, Inc. and its contributors. 21 * 4. Neither the name of The NetBSD Foundation nor the names of its 22 * contributors may be used to endorse or promote products derived 23 * from this software without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 26 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGE. 36 */ 37/* 38 * Copyright (c) 1992, 1993 39 * The Regents of the University of California. All rights reserved. 40 * 41 * This software was developed by the Computer Systems Engineering group 42 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 43 * contributed to Berkeley. 44 * 45 * All advertising materials mentioning features or use of this software 46 * must display the following acknowledgement: 47 * This product includes software developed by the University of 48 * California, Lawrence Berkeley Laboratory. 49 * 50 * Redistribution and use in source and binary forms, with or without 51 * modification, are permitted provided that the following conditions 52 * are met: 53 * 1. Redistributions of source code must retain the above copyright 54 * notice, this list of conditions and the following disclaimer. 55 * 2. Redistributions in binary form must reproduce the above copyright 56 * notice, this list of conditions and the following disclaimer in the 57 * documentation and/or other materials provided with the distribution. 58 * 3. All advertising materials mentioning features or use of this software 59 * must display the following acknowledgement: 60 * This product includes software developed by the University of 61 * California, Berkeley and its contributors. 62 * 4. Neither the name of the University nor the names of its contributors 63 * may be used to endorse or promote products derived from this software 64 * without specific prior written permission. 65 * 66 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 67 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 68 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 69 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 70 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 71 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 72 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 73 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 74 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 75 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 76 * SUCH DAMAGE. 77 */ 78/* 79 * Copyright (c) 1997, 1998 Justin T. Gibbs. 80 * All rights reserved. 81 * Copyright 2001 by Thomas Moestl <tmm@FreeBSD.org>. All rights reserved. 82 * 83 * Redistribution and use in source and binary forms, with or without 84 * modification, are permitted provided that the following conditions 85 * are met: 86 * 1. Redistributions of source code must retain the above copyright 87 * notice, this list of conditions, and the following disclaimer, 88 * without modification, immediately at the beginning of the file. 89 * 2. The name of the author may not be used to endorse or promote products 90 * derived from this software without specific prior written permission. 91 * 92 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 93 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 94 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 95 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 96 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 97 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 98 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 99 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 100 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 101 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 102 * SUCH DAMAGE. 103 * 104 * from: @(#)machdep.c 8.6 (Berkeley) 1/14/94 105 * from: NetBSD: machdep.c,v 1.111 2001/09/15 07:13:40 eeh Exp 106 * and 107 * from: FreeBSD: src/sys/i386/i386/busdma_machdep.c,v 1.24 2001/08/15 108 * 109 * $FreeBSD: head/sys/sparc64/sparc64/bus_machdep.c 86228 2001-11-09 20:05:53Z tmm $ 110 */ 111 112#include <sys/param.h> 113#include <sys/bus.h> 114#include <sys/malloc.h> 115#include <sys/proc.h> 116#include <sys/systm.h> 117 118#include <vm/vm.h> 119#include <vm/vm_extern.h> 120#include <vm/vm_kern.h> 121#include <vm/vm_page.h> 122#include <vm/vm_param.h> 123 124#include <machine/asi.h> 125#include <machine/bus.h> 126#include <machine/cache.h> 127#include <machine/pmap.h> 128 129/* ASI's for bus access. */ 130int bus_type_asi[] = { 131 ASI_PHYS_BYPASS_EC_WITH_EBIT, /* UPA */ 132 ASI_PHYS_BYPASS_EC_WITH_EBIT, /* SBUS */ 133 ASI_PHYS_BYPASS_EC_WITH_EBIT_L, /* PCI configuration space */ 134 ASI_PHYS_BYPASS_EC_WITH_EBIT_L, /* PCI memory space */ 135 ASI_PHYS_BYPASS_EC_WITH_EBIT_L, /* PCI I/O space */ 136 0 137}; 138 139int bus_stream_asi[] = { 140 ASI_PHYS_BYPASS_EC_WITH_EBIT, /* UPA */ 141 ASI_PHYS_BYPASS_EC_WITH_EBIT, /* SBUS */ 142 ASI_PHYS_BYPASS_EC_WITH_EBIT, /* PCI configuration space */ 143 ASI_PHYS_BYPASS_EC_WITH_EBIT, /* PCI memory space */ 144 ASI_PHYS_BYPASS_EC_WITH_EBIT, /* PCI I/O space */ 145 0 146}; 147 148/* 149 * busdma support code. 150 * Note: there is no support for bounce buffers yet. 151 */ 152 153static int nexus_dmamap_create(bus_dma_tag_t, int, bus_dmamap_t *); 154static int nexus_dmamap_destroy(bus_dma_tag_t, bus_dmamap_t); 155static int nexus_dmamap_load(bus_dma_tag_t, bus_dmamap_t, void *, bus_size_t, 156 bus_dmamap_callback_t *, void *, int); 157static void nexus_dmamap_unload(bus_dma_tag_t, bus_dmamap_t); 158static void nexus_dmamap_sync(bus_dma_tag_t, bus_dmamap_t, bus_dmasync_op_t); 159static int nexus_dmamem_alloc(bus_dma_tag_t, void **, int, bus_dmamap_t *); 160static void nexus_dmamem_free(bus_dma_tag_t, void *, bus_dmamap_t); 161 162 163bus_dma_tag_t sparc64_root_dma_tag; 164 165/* 166 * Allocate a device specific dma_tag. 167 */ 168int 169bus_dma_tag_create(bus_dma_tag_t parent, bus_size_t alignment, 170 bus_size_t boundary, bus_addr_t lowaddr, bus_addr_t highaddr, 171 bus_dma_filter_t *filter, void *filterarg, bus_size_t maxsize, 172 int nsegments, bus_size_t maxsegsz, int flags, bus_dma_tag_t *dmat) 173{ 174 175 bus_dma_tag_t newtag, eparent; 176 177 /* Return a NULL tag on failure */ 178 *dmat = NULL; 179 180 newtag = (bus_dma_tag_t)malloc(sizeof(*newtag), M_DEVBUF, M_NOWAIT); 181 if (newtag == NULL) 182 return (ENOMEM); 183 184 /* Ugh... */ 185 eparent = parent != NULL ? parent : sparc64_root_dma_tag; 186 memcpy(newtag, eparent, sizeof(*newtag)); 187 if (parent != NULL) 188 newtag->parent = parent; 189 newtag->alignment = alignment; 190 newtag->boundary = boundary; 191 newtag->lowaddr = trunc_page((vm_offset_t)lowaddr) + (PAGE_SIZE - 1); 192 newtag->highaddr = trunc_page((vm_offset_t)highaddr) + (PAGE_SIZE - 1); 193 newtag->filter = filter; 194 newtag->filterarg = filterarg; 195 newtag->maxsize = maxsize; 196 newtag->nsegments = nsegments; 197 newtag->maxsegsz = maxsegsz; 198 newtag->flags = flags; 199 newtag->ref_count = 1; /* Count ourself */ 200 newtag->map_count = 0; 201 202 /* Take into account any restrictions imposed by our parent tag */ 203 if (parent != NULL) { 204 newtag->lowaddr = ulmin(parent->lowaddr, newtag->lowaddr); 205 newtag->highaddr = ulmax(parent->highaddr, newtag->highaddr); 206 /* 207 * XXX Not really correct??? Probably need to honor boundary 208 * all the way up the inheritence chain. 209 */ 210 newtag->boundary = ulmax(parent->boundary, newtag->boundary); 211 if (parent != NULL) 212 parent->ref_count++; 213 } 214 215 *dmat = newtag; 216 return (0); 217} 218 219int 220bus_dma_tag_destroy(bus_dma_tag_t dmat) 221{ 222 223 if (dmat != NULL) { 224 if (dmat->map_count != 0) 225 return (EBUSY); 226 227 while (dmat != NULL) { 228 bus_dma_tag_t parent; 229 230 parent = dmat->parent; 231 dmat->ref_count--; 232 if (dmat->ref_count == 0) { 233 free(dmat, M_DEVBUF); 234 /* 235 * Last reference count, so 236 * release our reference 237 * count on our parent. 238 */ 239 dmat = parent; 240 } else 241 dmat = NULL; 242 } 243 } 244 return (0); 245} 246 247/* 248 * Common function for DMA map creation. May be called by bus-specific 249 * DMA map creation functions. 250 */ 251static int 252nexus_dmamap_create(bus_dma_tag_t dmat, int flags, bus_dmamap_t *mapp) 253{ 254 255 /* Not much to do...? */ 256 *mapp = malloc(sizeof(**mapp), M_DEVBUF, M_WAITOK | M_ZERO); 257 dmat->map_count++; 258 return (0); 259} 260 261/* 262 * Common function for DMA map destruction. May be called by bus-specific 263 * DMA map destruction functions. 264 */ 265static int 266nexus_dmamap_destroy(bus_dma_tag_t dmat, bus_dmamap_t map) 267{ 268 269 free(map, M_DEVBUF); 270 dmat->map_count--; 271 return (0); 272} 273 274#define BUS_DMAMAP_NSEGS ((BUS_SPACE_MAXSIZE / PAGE_SIZE) + 1) 275 276/* 277 * Common function for loading a DMA map with a linear buffer. May 278 * be called by bus-specific DMA map load functions. 279 * 280 * Most SPARCs have IOMMUs in the bus controllers. In those cases 281 * they only need one segment and will use virtual addresses for DVMA. 282 * Those bus controllers should intercept these vectors and should 283 * *NEVER* call nexus_dmamap_load() which is used only by devices that 284 * bypass DVMA. 285 */ 286static int 287nexus_dmamap_load(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf, 288 bus_size_t buflen, bus_dmamap_callback_t *callback, void *callback_arg, 289 int flags) 290{ 291 vm_offset_t vaddr; 292 vm_offset_t paddr; 293#ifdef __GNUC__ 294 bus_dma_segment_t dm_segments[dmat->nsegments]; 295#else 296 bus_dma_segment_t dm_segments[BUS_DMAMAP_NSEGS]; 297#endif 298 bus_dma_segment_t *sg; 299 int seg; 300 int error; 301 vm_offset_t nextpaddr; 302 bus_size_t size; 303 304 error = 0; 305 306 vaddr = (vm_offset_t)buf; 307 sg = &dm_segments[0]; 308 seg = 1; 309 sg->ds_len = 0; 310 311 map->buf = buf; 312 map->buflen = buflen; 313 map->start = (bus_addr_t)buf; 314 315 nextpaddr = 0; 316 do { 317 paddr = pmap_kextract(vaddr); 318 size = PAGE_SIZE - (paddr & PAGE_MASK); 319 if (size > buflen) 320 size = buflen; 321 322 if (sg->ds_len == 0) { 323 sg->ds_addr = paddr; 324 sg->ds_len = size; 325 } else if (paddr == nextpaddr) { 326 sg->ds_len += size; 327 } else { 328 /* Go to the next segment */ 329 sg++; 330 seg++; 331 if (seg > dmat->nsegments) 332 break; 333 sg->ds_addr = paddr; 334 sg->ds_len = size; 335 } 336 vaddr += size; 337 nextpaddr = paddr + size; 338 buflen -= size; 339 } while (buflen > 0); 340 341 if (buflen != 0) { 342 printf("bus_dmamap_load: Too many segs! buf_len = 0x%lx\n", 343 (u_long)buflen); 344 error = EFBIG; 345 } 346 347 (*callback)(callback_arg, dm_segments, seg, error); 348 349 return (0); 350} 351 352/* 353 * Common function for unloading a DMA map. May be called by 354 * bus-specific DMA map unload functions. 355 */ 356static void 357nexus_dmamap_unload(bus_dma_tag_t dmat, bus_dmamap_t map) 358{ 359 360 /* Nothing to do...? */ 361} 362 363/* 364 * Common function for DMA map synchronization. May be called 365 * by bus-specific DMA map synchronization functions. 366 */ 367static void 368nexus_dmamap_sync(bus_dma_tag_t dmat, bus_dmamap_t map, bus_dmasync_op_t op) 369{ 370 371 /* 372 * We sync out our caches, but the bus must do the same. 373 * 374 * Actually a #Sync is expensive. We should optimize. 375 */ 376 if ((op == BUS_DMASYNC_PREREAD) || (op == BUS_DMASYNC_PREWRITE)) { 377 /* 378 * Don't really need to do anything, but flush any pending 379 * writes anyway. 380 */ 381 membar(Sync); 382 } 383 if (op == BUS_DMASYNC_POSTREAD) { 384 /* 385 * Invalidate the caches (it is unclear whether that is really 386 * needed. The manual only mentions that PCI transactions are 387 * cache coherent). 388 */ 389 ecache_flush((vm_offset_t)map->buf, 390 (vm_offset_t)map->buf + map->buflen - 1); 391 } 392 if (op == BUS_DMASYNC_POSTWRITE) { 393 /* Nothing to do. Handled by the bus controller. */ 394 } 395} 396 397/* 398 * Helper functions for buses that use their private dmamem_alloc/dmamem_free 399 * versions. 400 * These differ from the dmamap_alloc() functions in that they create a tag 401 * that is specifically for use with dmamem_alloc'ed memory. 402 * These are primitive now, but I expect that some fields of the map will need 403 * to be filled soon. 404 */ 405int 406sparc64_dmamem_alloc_map(bus_dma_tag_t dmat, bus_dmamap_t *mapp) 407{ 408 409 *mapp = malloc(sizeof(**mapp), M_DEVBUF, M_WAITOK | M_ZERO); 410 if (*mapp == NULL) 411 return (ENOMEM); 412 413 dmat->map_count++; 414 return (0); 415} 416 417void 418sparc64_dmamem_free_map(bus_dma_tag_t dmat, bus_dmamap_t map) 419{ 420 421 free(map, M_DEVBUF); 422 dmat->map_count--; 423} 424 425/* 426 * Common function for DMA-safe memory allocation. May be called 427 * by bus-specific DMA memory allocation functions. 428 */ 429static int 430nexus_dmamem_alloc(bus_dma_tag_t dmat, void **vaddr, int flags, 431 bus_dmamap_t *mapp) 432{ 433 434 if ((dmat->maxsize <= PAGE_SIZE)) { 435 *vaddr = malloc(dmat->maxsize, M_DEVBUF, 436 (flags & BUS_DMA_NOWAIT) ? M_NOWAIT : M_WAITOK); 437 } else { 438 /* 439 * XXX: Use contigmalloc until it is merged into this facility 440 * and handles multi-seg allocations. Nobody is doing multi-seg 441 * allocations yet though. 442 */ 443 *vaddr = contigmalloc(dmat->maxsize, M_DEVBUF, 444 (flags & BUS_DMA_NOWAIT) ? M_NOWAIT : M_WAITOK, 445 0ul, dmat->lowaddr, dmat->alignment ? dmat->alignment : 1UL, 446 dmat->boundary); 447 } 448 if (*vaddr == NULL) { 449 free(*mapp, M_DEVBUF); 450 return (ENOMEM); 451 } 452 return (0); 453} 454 455/* 456 * Common function for freeing DMA-safe memory. May be called by 457 * bus-specific DMA memory free functions. 458 */ 459static void 460nexus_dmamem_free(bus_dma_tag_t dmat, void *vaddr, bus_dmamap_t map) 461{ 462 463 sparc64_dmamem_free_map(dmat, map); 464 if ((dmat->maxsize <= PAGE_SIZE)) 465 free(vaddr, M_DEVBUF); 466 else 467 contigfree(vaddr, dmat->maxsize, M_DEVBUF); 468} 469 470struct bus_dma_tag nexus_dmatag = { 471 NULL, 472 NULL, 473 8, 474 0, 475 0, 476 0x3ffffffff, 477 NULL, /* XXX */ 478 NULL, 479 0x3ffffffff, /* XXX */ 480 0xff, /* XXX */ 481 0xffffffff, /* XXX */ 482 0, 483 0, 484 0, 485 nexus_dmamap_create, 486 nexus_dmamap_destroy, 487 nexus_dmamap_load, 488 nexus_dmamap_unload, 489 nexus_dmamap_sync, 490 491 nexus_dmamem_alloc, 492 nexus_dmamem_free, 493}; 494 495/* 496 * Helpers to map/unmap bus memory 497 */ 498int 499sparc64_bus_mem_map(bus_type_t iospace, bus_addr_t addr, 500 bus_size_t size, int flags, vm_offset_t vaddr, void **hp) 501{ 502 vm_offset_t v; 503 vm_offset_t pa; 504 u_long pm_flags; 505 506 size = round_page(size); 507 if (size == 0) { 508 printf("sparc64_bus_map: zero size\n"); 509 return (EINVAL); 510 } 511 switch (iospace) { 512 case PCI_CONFIG_BUS_SPACE: 513 case PCI_IO_BUS_SPACE: 514 case PCI_MEMORY_BUS_SPACE: 515 pm_flags = TD_IE; 516 break; 517 default: 518 pm_flags = 0; 519 break; 520 } 521 522 if (!(flags & BUS_SPACE_MAP_CACHEABLE)) 523 pm_flags |= TD_E; 524 525 if (vaddr != NULL) 526 v = trunc_page(vaddr); 527 else { 528 if ((v = kmem_alloc_nofault(kernel_map, size)) == NULL) 529 panic("sparc64_bus_map: cannot allocate virtual " 530 "memory"); 531 } 532 533 /* note: preserve page offset */ 534 *hp = (void *)(v | ((u_long)addr & PAGE_MASK)); 535 536 pa = trunc_page(addr); 537 if ((flags & BUS_SPACE_MAP_READONLY) == 0) 538 pm_flags |= TD_W; 539 540 do { 541 pmap_kenter_flags(v, pa, pm_flags); 542 v += PAGE_SIZE; 543 pa += PAGE_SIZE; 544 } while ((size -= PAGE_SIZE) > 0); 545 return (0); 546} 547 548int 549sparc64_bus_mem_unmap(void *bh, bus_size_t size) 550{ 551 vm_offset_t va ; 552 vm_offset_t endva; 553 554 va = trunc_page((vm_offset_t)bh); 555 endva = va + round_page(size); 556 for (; va < endva; va += PAGE_SIZE) 557 pmap_kremove(va); 558 kmem_free(kernel_map, va, size); 559 return (0); 560} 561 562/* 563 * Fake up a bus tag, for use by console drivers in early boot when the regular 564 * means to allocate resources are not yet available. 565 * Note that these tags are not eligible for bus_space_barrier operations. 566 * Addr is the physical address of the desired start of the handle. 567 */ 568bus_space_handle_t 569sparc64_fake_bustag(int space, bus_addr_t addr, struct bus_space_tag *ptag) 570{ 571 572 ptag->cookie = NULL; 573 ptag->parent = NULL; 574 ptag->type = space; 575 ptag->bus_barrier = NULL; 576 return (addr); 577} 578 579/* 580 * Base bus space handlers. 581 */ 582static void nexus_bus_barrier(bus_space_tag_t, bus_space_handle_t, 583 bus_size_t, bus_size_t, int); 584 585static void 586nexus_bus_barrier(bus_space_tag_t t, bus_space_handle_t h, bus_size_t offset, 587 bus_size_t size, int flags) 588{ 589 590 /* 591 * We have lots of alternatives depending on whether we're 592 * synchronizing loads with loads, loads with stores, stores 593 * with loads, or stores with stores. The only ones that seem 594 * generic are #Sync and #MemIssue. I'll use #Sync for safety. 595 */ 596 switch(flags) { 597 case BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE: 598 case BUS_SPACE_BARRIER_READ: 599 case BUS_SPACE_BARRIER_WRITE: 600 membar(Sync); 601 break; 602 default: 603 panic("sparc64_bus_barrier: unknown flags"); 604 } 605 return; 606} 607 608struct bus_space_tag nexus_bustag = { 609 NULL, /* cookie */ 610 NULL, /* parent bus tag */ 611 UPA_BUS_SPACE, /* type */ 612 nexus_bus_barrier, /* bus_space_barrier */ 613}; 614