bus_machdep.c revision 112227
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 112227 2003-03-14 07:19:29Z jake $ 110 */ 111 112#include <sys/param.h> 113#include <sys/bus.h> 114#include <sys/lock.h> 115#include <sys/malloc.h> 116#include <sys/mbuf.h> 117#include <sys/mutex.h> 118#include <sys/proc.h> 119#include <sys/smp.h> 120#include <sys/systm.h> 121#include <sys/uio.h> 122 123#include <vm/vm.h> 124#include <vm/vm_extern.h> 125#include <vm/vm_kern.h> 126#include <vm/vm_page.h> 127#include <vm/vm_param.h> 128#include <vm/vm_map.h> 129 130#include <machine/asi.h> 131#include <machine/bus.h> 132#include <machine/bus_private.h> 133#include <machine/cache.h> 134#include <machine/smp.h> 135#include <machine/tlb.h> 136 137/* ASI's for bus access. */ 138int bus_type_asi[] = { 139 ASI_PHYS_BYPASS_EC_WITH_EBIT, /* UPA */ 140 ASI_PHYS_BYPASS_EC_WITH_EBIT, /* SBUS */ 141 ASI_PHYS_BYPASS_EC_WITH_EBIT_L, /* PCI configuration space */ 142 ASI_PHYS_BYPASS_EC_WITH_EBIT_L, /* PCI memory space */ 143 ASI_PHYS_BYPASS_EC_WITH_EBIT_L, /* PCI I/O space */ 144 0 145}; 146 147int bus_stream_asi[] = { 148 ASI_PHYS_BYPASS_EC_WITH_EBIT, /* UPA */ 149 ASI_PHYS_BYPASS_EC_WITH_EBIT, /* SBUS */ 150 ASI_PHYS_BYPASS_EC_WITH_EBIT, /* PCI configuration space */ 151 ASI_PHYS_BYPASS_EC_WITH_EBIT, /* PCI memory space */ 152 ASI_PHYS_BYPASS_EC_WITH_EBIT, /* PCI I/O space */ 153 0 154}; 155 156/* 157 * busdma support code. 158 * Note: there is no support for bounce buffers yet. 159 */ 160 161static int nexus_dmamap_create(bus_dma_tag_t, bus_dma_tag_t, int, 162 bus_dmamap_t *); 163static int nexus_dmamap_destroy(bus_dma_tag_t, bus_dma_tag_t, bus_dmamap_t); 164static int nexus_dmamap_load(bus_dma_tag_t, bus_dma_tag_t, bus_dmamap_t, 165 void *, bus_size_t, bus_dmamap_callback_t *, void *, int); 166static int nexus_dmamap_load_mbuf(bus_dma_tag_t, bus_dma_tag_t, bus_dmamap_t, 167 struct mbuf *, bus_dmamap_callback2_t *, void *, int); 168static int nexus_dmamap_load_uio(bus_dma_tag_t, bus_dma_tag_t, bus_dmamap_t, 169 struct uio *, bus_dmamap_callback2_t *, void *, int); 170static void nexus_dmamap_unload(bus_dma_tag_t, bus_dma_tag_t, bus_dmamap_t); 171static void nexus_dmamap_sync(bus_dma_tag_t, bus_dma_tag_t, bus_dmamap_t, 172 bus_dmasync_op_t); 173static int nexus_dmamem_alloc_size(bus_dma_tag_t, bus_dma_tag_t, void **, int, 174 bus_dmamap_t *, u_long size); 175static int nexus_dmamem_alloc(bus_dma_tag_t, bus_dma_tag_t, void **, int, 176 bus_dmamap_t *); 177static void nexus_dmamem_free_size(bus_dma_tag_t, bus_dma_tag_t, void *, 178 bus_dmamap_t, u_long size); 179static void nexus_dmamem_free(bus_dma_tag_t, bus_dma_tag_t, void *, 180 bus_dmamap_t); 181 182/* 183 * Since there is now way for a device to obtain a dma tag from its parent 184 * we use this kluge to handle different the different supported bus systems. 185 * The sparc64_root_dma_tag is used as parent for tags that have none, so that 186 * the correct methods will be used. 187 */ 188bus_dma_tag_t sparc64_root_dma_tag; 189 190/* 191 * Allocate a device specific dma_tag. 192 */ 193int 194bus_dma_tag_create(bus_dma_tag_t parent, bus_size_t alignment, 195 bus_size_t boundary, bus_addr_t lowaddr, bus_addr_t highaddr, 196 bus_dma_filter_t *filter, void *filterarg, bus_size_t maxsize, 197 int nsegments, bus_size_t maxsegsz, int flags, bus_dma_tag_t *dmat) 198{ 199 200 bus_dma_tag_t newtag; 201 202 /* Return a NULL tag on failure */ 203 *dmat = NULL; 204 205 newtag = (bus_dma_tag_t)malloc(sizeof(*newtag), M_DEVBUF, M_NOWAIT); 206 if (newtag == NULL) 207 return (ENOMEM); 208 209 newtag->dt_parent = parent != NULL ? parent : sparc64_root_dma_tag; 210 newtag->dt_alignment = alignment; 211 newtag->dt_boundary = boundary; 212 newtag->dt_lowaddr = trunc_page((vm_offset_t)lowaddr) + (PAGE_SIZE - 1); 213 newtag->dt_highaddr = trunc_page((vm_offset_t)highaddr) + 214 (PAGE_SIZE - 1); 215 newtag->dt_filter = filter; 216 newtag->dt_filterarg = filterarg; 217 newtag->dt_maxsize = maxsize; 218 newtag->dt_nsegments = nsegments; 219 newtag->dt_maxsegsz = maxsegsz; 220 newtag->dt_flags = flags; 221 newtag->dt_ref_count = 1; /* Count ourselves */ 222 newtag->dt_map_count = 0; 223 224 newtag->dt_dmamap_create = NULL; 225 newtag->dt_dmamap_destroy = NULL; 226 newtag->dt_dmamap_load = NULL; 227 newtag->dt_dmamap_load_mbuf = NULL; 228 newtag->dt_dmamap_load_uio = NULL; 229 newtag->dt_dmamap_unload = NULL; 230 newtag->dt_dmamap_sync = NULL; 231 newtag->dt_dmamem_alloc_size = NULL; 232 newtag->dt_dmamem_alloc = NULL; 233 newtag->dt_dmamem_free_size = NULL; 234 newtag->dt_dmamem_free = NULL; 235 236 /* Take into account any restrictions imposed by our parent tag */ 237 if (parent != NULL) { 238 newtag->dt_lowaddr = ulmin(parent->dt_lowaddr, 239 newtag->dt_lowaddr); 240 newtag->dt_highaddr = ulmax(parent->dt_highaddr, 241 newtag->dt_highaddr); 242 /* 243 * XXX Not really correct??? Probably need to honor boundary 244 * all the way up the inheritence chain. 245 */ 246 newtag->dt_boundary = ulmin(parent->dt_boundary, 247 newtag->dt_boundary); 248 } 249 newtag->dt_parent->dt_ref_count++; 250 251 *dmat = newtag; 252 return (0); 253} 254 255int 256bus_dma_tag_destroy(bus_dma_tag_t dmat) 257{ 258 bus_dma_tag_t parent; 259 260 if (dmat != NULL) { 261 if (dmat->dt_map_count != 0) 262 return (EBUSY); 263 while (dmat != NULL) { 264 parent = dmat->dt_parent; 265 dmat->dt_ref_count--; 266 if (dmat->dt_ref_count == 0) { 267 free(dmat, M_DEVBUF); 268 /* 269 * Last reference count, so 270 * release our reference 271 * count on our parent. 272 */ 273 dmat = parent; 274 } else 275 dmat = NULL; 276 } 277 } 278 return (0); 279} 280 281/* 282 * Common function for DMA map creation. May be called by bus-specific 283 * DMA map creation functions. 284 */ 285static int 286nexus_dmamap_create(bus_dma_tag_t pdmat, bus_dma_tag_t ddmat, int flags, 287 bus_dmamap_t *mapp) 288{ 289 290 *mapp = malloc(sizeof(**mapp), M_DEVBUF, M_NOWAIT | M_ZERO); 291 if (*mapp != NULL) { 292 ddmat->dt_map_count++; 293 sparc64_dmamap_init(*mapp); 294 return (0); 295 } else 296 return (ENOMEM); 297} 298 299/* 300 * Common function for DMA map destruction. May be called by bus-specific 301 * DMA map destruction functions. 302 */ 303static int 304nexus_dmamap_destroy(bus_dma_tag_t pdmat, bus_dma_tag_t ddmat, bus_dmamap_t map) 305{ 306 307 free(map, M_DEVBUF); 308 ddmat->dt_map_count--; 309 return (0); 310} 311 312/* 313 * Utility function to load a linear buffer. lastaddrp holds state 314 * between invocations (for multiple-buffer loads). segp contains 315 * the starting segment on entrace, and the ending segment on exit. 316 * first indicates if this is the first invocation of this function. 317 */ 318static int 319_nexus_dmamap_load_buffer(bus_dma_tag_t ddmat, bus_dma_segment_t segs[], 320 void *buf, bus_size_t buflen, struct thread *td, int flags, 321 vm_offset_t *lastaddrp, int *segp, int first) 322{ 323 bus_size_t sgsize; 324 bus_addr_t curaddr, lastaddr, baddr, bmask; 325 vm_offset_t vaddr = (vm_offset_t)buf; 326 int seg; 327 pmap_t pmap; 328 329 if (td != NULL) 330 pmap = vmspace_pmap(td->td_proc->p_vmspace); 331 else 332 pmap = NULL; 333 334 lastaddr = *lastaddrp; 335 bmask = ~(ddmat->dt_boundary - 1); 336 337 for (seg = *segp; buflen > 0 ; ) { 338 /* 339 * Get the physical address for this segment. 340 */ 341 if (pmap) 342 curaddr = pmap_extract(pmap, vaddr); 343 else 344 curaddr = pmap_kextract(vaddr); 345 346 /* 347 * Compute the segment size, and adjust counts. 348 */ 349 sgsize = PAGE_SIZE - ((u_long)curaddr & PAGE_MASK); 350 if (buflen < sgsize) 351 sgsize = buflen; 352 353 /* 354 * Make sure we don't cross any boundaries. 355 */ 356 if (ddmat->dt_boundary > 0) { 357 baddr = (curaddr + ddmat->dt_boundary) & bmask; 358 if (sgsize > (baddr - curaddr)) 359 sgsize = (baddr - curaddr); 360 } 361 362 /* 363 * Insert chunk into a segment, coalescing with 364 * previous segment if possible. 365 */ 366 if (first) { 367 segs[seg].ds_addr = curaddr; 368 segs[seg].ds_len = sgsize; 369 first = 0; 370 } else { 371 if (curaddr == lastaddr && 372 (segs[seg].ds_len + sgsize) <= ddmat->dt_maxsegsz && 373 (ddmat->dt_boundary == 0 || 374 (segs[seg].ds_addr & bmask) == (curaddr & bmask))) 375 segs[seg].ds_len += sgsize; 376 else { 377 if (++seg >= ddmat->dt_nsegments) 378 break; 379 segs[seg].ds_addr = curaddr; 380 segs[seg].ds_len = sgsize; 381 } 382 } 383 384 lastaddr = curaddr + sgsize; 385 vaddr += sgsize; 386 buflen -= sgsize; 387 } 388 389 *segp = seg; 390 *lastaddrp = lastaddr; 391 392 /* 393 * Did we fit? 394 */ 395 return (buflen != 0 ? EFBIG : 0); /* XXX better return value here? */ 396} 397 398/* 399 * Common function for loading a DMA map with a linear buffer. May 400 * be called by bus-specific DMA map load functions. 401 * 402 * Most SPARCs have IOMMUs in the bus controllers. In those cases 403 * they only need one segment and will use virtual addresses for DVMA. 404 * Those bus controllers should intercept these vectors and should 405 * *NEVER* call nexus_dmamap_load() which is used only by devices that 406 * bypass DVMA. 407 */ 408static int 409nexus_dmamap_load(bus_dma_tag_t pdmat, bus_dma_tag_t ddmat, bus_dmamap_t map, 410 void *buf, bus_size_t buflen, bus_dmamap_callback_t *callback, 411 void *callback_arg, int flags) 412{ 413#ifdef __GNUC__ 414 bus_dma_segment_t dm_segments[ddmat->dt_nsegments]; 415#else 416 bus_dma_segment_t dm_segments[BUS_DMAMAP_NSEGS]; 417#endif 418 vm_offset_t lastaddr; 419 int error, nsegs; 420 421 error = _nexus_dmamap_load_buffer(ddmat, dm_segments, buf, buflen, 422 NULL, flags, &lastaddr, &nsegs, 1); 423 424 if (error == 0) { 425 (*callback)(callback_arg, dm_segments, nsegs + 1, 0); 426 map->dm_loaded = 1; 427 } else 428 (*callback)(callback_arg, NULL, 0, error); 429 430 return (0); 431} 432 433/* 434 * Like nexus_dmamap_load(), but for mbufs. 435 */ 436static int 437nexus_dmamap_load_mbuf(bus_dma_tag_t pdmat, bus_dma_tag_t ddmat, 438 bus_dmamap_t map, struct mbuf *m0, bus_dmamap_callback2_t *callback, 439 void *callback_arg, int flags) 440{ 441#ifdef __GNUC__ 442 bus_dma_segment_t dm_segments[ddmat->dt_nsegments]; 443#else 444 bus_dma_segment_t dm_segments[BUS_DMAMAP_NSEGS]; 445#endif 446 int nsegs, error; 447 448 KASSERT(m0->m_flags & M_PKTHDR, 449 ("nexus_dmamap_load_mbuf: no packet header")); 450 451 nsegs = 0; 452 error = 0; 453 if (m0->m_pkthdr.len <= ddmat->dt_maxsize) { 454 int first = 1; 455 vm_offset_t lastaddr = 0; 456 struct mbuf *m; 457 458 for (m = m0; m != NULL && error == 0; m = m->m_next) { 459 if (m->m_len > 0) { 460 error = _nexus_dmamap_load_buffer(ddmat, 461 dm_segments, m->m_data, m->m_len, NULL, 462 flags, &lastaddr, &nsegs, first); 463 first = 0; 464 } 465 } 466 } else { 467 error = EINVAL; 468 } 469 470 if (error) { 471 /* force "no valid mappings" in callback */ 472 (*callback)(callback_arg, dm_segments, 0, 0, error); 473 } else { 474 map->dm_loaded = 1; 475 (*callback)(callback_arg, dm_segments, nsegs + 1, 476 m0->m_pkthdr.len, error); 477 } 478 return (error); 479} 480 481/* 482 * Like nexus_dmamap_load(), but for uios. 483 */ 484static int 485nexus_dmamap_load_uio(bus_dma_tag_t pdmat, bus_dma_tag_t ddmat, 486 bus_dmamap_t map, struct uio *uio, bus_dmamap_callback2_t *callback, 487 void *callback_arg, int flags) 488{ 489 vm_offset_t lastaddr; 490#ifdef __GNUC__ 491 bus_dma_segment_t dm_segments[ddmat->dt_nsegments]; 492#else 493 bus_dma_segment_t dm_segments[BUS_DMAMAP_NSEGS]; 494#endif 495 int nsegs, error, first, i; 496 bus_size_t resid; 497 struct iovec *iov; 498 struct thread *td = NULL; 499 500 resid = uio->uio_resid; 501 iov = uio->uio_iov; 502 503 if (uio->uio_segflg == UIO_USERSPACE) { 504 td = uio->uio_td; 505 KASSERT(td != NULL, 506 ("nexus_dmamap_load_uio: USERSPACE but no proc")); 507 } 508 509 nsegs = 0; 510 error = 0; 511 first = 1; 512 for (i = 0; i < uio->uio_iovcnt && resid != 0 && !error; i++) { 513 /* 514 * Now at the first iovec to load. Load each iovec 515 * until we have exhausted the residual count. 516 */ 517 bus_size_t minlen = 518 resid < iov[i].iov_len ? resid : iov[i].iov_len; 519 caddr_t addr = (caddr_t) iov[i].iov_base; 520 521 if (minlen > 0) { 522 error = _nexus_dmamap_load_buffer(ddmat, dm_segments, 523 addr, minlen, td, flags, &lastaddr, &nsegs, first); 524 first = 0; 525 526 resid -= minlen; 527 } 528 } 529 530 if (error) { 531 /* force "no valid mappings" in callback */ 532 (*callback)(callback_arg, dm_segments, 0, 0, error); 533 } else { 534 map->dm_loaded = 1; 535 (*callback)(callback_arg, dm_segments, nsegs + 1, 536 uio->uio_resid, error); 537 } 538 return (error); 539} 540 541/* 542 * Common function for unloading a DMA map. May be called by 543 * bus-specific DMA map unload functions. 544 */ 545static void 546nexus_dmamap_unload(bus_dma_tag_t pdmat, bus_dma_tag_t ddmat, bus_dmamap_t map) 547{ 548 549 map->dm_loaded = 0; 550} 551 552/* 553 * Common function for DMA map synchronization. May be called 554 * by bus-specific DMA map synchronization functions. 555 */ 556static void 557nexus_dmamap_sync(bus_dma_tag_t pdmat, bus_dma_tag_t ddmat, bus_dmamap_t map, 558 bus_dmasync_op_t op) 559{ 560 561 /* 562 * We sync out our caches, but the bus must do the same. 563 * 564 * Actually a #Sync is expensive. We should optimize. 565 */ 566 if ((op == BUS_DMASYNC_PREREAD) || (op == BUS_DMASYNC_PREWRITE)) { 567 /* 568 * Don't really need to do anything, but flush any pending 569 * writes anyway. 570 */ 571 membar(Sync); 572 } 573#if 0 574 /* Should not be needed. */ 575 if (op == BUS_DMASYNC_POSTREAD) { 576 ecache_flush((vm_offset_t)map->buf, 577 (vm_offset_t)map->buf + map->buflen - 1); 578 } 579#endif 580 if (op == BUS_DMASYNC_POSTWRITE) { 581 /* Nothing to do. Handled by the bus controller. */ 582 } 583} 584 585/* 586 * Helper functions for buses that use their private dmamem_alloc/dmamem_free 587 * versions. 588 * These differ from the dmamap_alloc() functions in that they create a tag 589 * that is specifically for use with dmamem_alloc'ed memory. 590 * These are primitive now, but I expect that some fields of the map will need 591 * to be filled soon. 592 */ 593int 594sparc64_dmamem_alloc_map(bus_dma_tag_t dmat, bus_dmamap_t *mapp) 595{ 596 597 *mapp = malloc(sizeof(**mapp), M_DEVBUF, M_NOWAIT | M_ZERO); 598 if (*mapp == NULL) 599 return (ENOMEM); 600 601 dmat->dt_map_count++; 602 sparc64_dmamap_init(*mapp); 603 return (0); 604} 605 606void 607sparc64_dmamem_free_map(bus_dma_tag_t dmat, bus_dmamap_t map) 608{ 609 610 free(map, M_DEVBUF); 611 dmat->dt_map_count--; 612} 613 614/* 615 * Common function for DMA-safe memory allocation. May be called 616 * by bus-specific DMA memory allocation functions. 617 */ 618static int 619nexus_dmamem_alloc_size(bus_dma_tag_t pdmat, bus_dma_tag_t ddmat, void **vaddr, 620 int flags, bus_dmamap_t *mapp, bus_size_t size) 621{ 622 623 if (size > ddmat->dt_maxsize) 624 return (ENOMEM); 625 626 if ((size <= PAGE_SIZE)) { 627 *vaddr = malloc(size, M_DEVBUF, 628 (flags & BUS_DMA_NOWAIT) ? M_NOWAIT : M_WAITOK); 629 } else { 630 /* 631 * XXX: Use contigmalloc until it is merged into this facility 632 * and handles multi-seg allocations. Nobody is doing multi-seg 633 * allocations yet though. 634 */ 635 mtx_lock(&Giant); 636 *vaddr = contigmalloc(size, M_DEVBUF, 637 (flags & BUS_DMA_NOWAIT) ? M_NOWAIT : M_WAITOK, 638 0ul, ddmat->dt_lowaddr, 639 ddmat->dt_alignment ? ddmat->dt_alignment : 1UL, 640 ddmat->dt_boundary); 641 mtx_unlock(&Giant); 642 } 643 if (*vaddr == NULL) { 644 free(*mapp, M_DEVBUF); 645 return (ENOMEM); 646 } 647 return (0); 648} 649 650static int 651nexus_dmamem_alloc(bus_dma_tag_t pdmat, bus_dma_tag_t ddmat, void **vaddr, 652 int flags, bus_dmamap_t *mapp) 653{ 654 return (sparc64_dmamem_alloc_size(pdmat, ddmat, vaddr, flags, mapp, 655 ddmat->dt_maxsize)); 656} 657 658/* 659 * Common function for freeing DMA-safe memory. May be called by 660 * bus-specific DMA memory free functions. 661 */ 662static void 663nexus_dmamem_free_size(bus_dma_tag_t pdmat, bus_dma_tag_t ddmat, void *vaddr, 664 bus_dmamap_t map, bus_size_t size) 665{ 666 667 sparc64_dmamem_free_map(ddmat, map); 668 if ((size <= PAGE_SIZE)) 669 free(vaddr, M_DEVBUF); 670 else { 671 mtx_lock(&Giant); 672 contigfree(vaddr, size, M_DEVBUF); 673 mtx_unlock(&Giant); 674 } 675} 676 677static void 678nexus_dmamem_free(bus_dma_tag_t pdmat, bus_dma_tag_t ddmat, void *vaddr, 679 bus_dmamap_t map) 680{ 681 sparc64_dmamem_free_size(pdmat, ddmat, vaddr, map, ddmat->dt_maxsize); 682} 683 684struct bus_dma_tag nexus_dmatag = { 685 NULL, 686 NULL, 687 8, 688 0, 689 0, 690 0x3ffffffff, 691 NULL, /* XXX */ 692 NULL, 693 0x3ffffffff, /* XXX */ 694 0xff, /* XXX */ 695 0xffffffff, /* XXX */ 696 0, 697 0, 698 0, 699 nexus_dmamap_create, 700 nexus_dmamap_destroy, 701 nexus_dmamap_load, 702 nexus_dmamap_load_mbuf, 703 nexus_dmamap_load_uio, 704 nexus_dmamap_unload, 705 nexus_dmamap_sync, 706 707 nexus_dmamem_alloc_size, 708 nexus_dmamem_alloc, 709 nexus_dmamem_free_size, 710 nexus_dmamem_free, 711}; 712 713/* 714 * Helpers to map/unmap bus memory 715 */ 716int 717sparc64_bus_mem_map(bus_space_tag_t tag, bus_space_handle_t handle, 718 bus_size_t size, int flags, vm_offset_t vaddr, void **hp) 719{ 720 vm_offset_t addr; 721 vm_offset_t sva; 722 vm_offset_t va; 723 vm_offset_t pa; 724 vm_size_t vsz; 725 u_long pm_flags; 726 727 addr = (vm_offset_t)handle; 728 size = round_page(size); 729 if (size == 0) { 730 printf("sparc64_bus_map: zero size\n"); 731 return (EINVAL); 732 } 733 switch (tag->bst_type) { 734 case PCI_CONFIG_BUS_SPACE: 735 case PCI_IO_BUS_SPACE: 736 case PCI_MEMORY_BUS_SPACE: 737 pm_flags = TD_IE; 738 break; 739 default: 740 pm_flags = 0; 741 break; 742 } 743 744 if (!(flags & BUS_SPACE_MAP_CACHEABLE)) 745 pm_flags |= TD_E; 746 747 if (vaddr != NULL) 748 sva = trunc_page(vaddr); 749 else { 750 if ((sva = kmem_alloc_nofault(kernel_map, size)) == NULL) 751 panic("sparc64_bus_map: cannot allocate virtual " 752 "memory"); 753 } 754 755 /* Preserve page offset. */ 756 *hp = (void *)(sva | ((u_long)addr & PAGE_MASK)); 757 758 pa = trunc_page(addr); 759 if ((flags & BUS_SPACE_MAP_READONLY) == 0) 760 pm_flags |= TD_W; 761 762 va = sva; 763 vsz = size; 764 do { 765 pmap_kenter_flags(va, pa, pm_flags); 766 va += PAGE_SIZE; 767 pa += PAGE_SIZE; 768 } while ((vsz -= PAGE_SIZE) > 0); 769 tlb_range_demap(kernel_pmap, sva, sva + size - 1); 770 return (0); 771} 772 773int 774sparc64_bus_mem_unmap(void *bh, bus_size_t size) 775{ 776 vm_offset_t sva; 777 vm_offset_t va; 778 vm_offset_t endva; 779 780 sva = trunc_page((vm_offset_t)bh); 781 endva = sva + round_page(size); 782 for (va = sva; va < endva; va += PAGE_SIZE) 783 pmap_kremove_flags(va); 784 tlb_range_demap(kernel_pmap, sva, sva + size - 1); 785 kmem_free(kernel_map, sva, size); 786 return (0); 787} 788 789/* 790 * Fake up a bus tag, for use by console drivers in early boot when the regular 791 * means to allocate resources are not yet available. 792 * Note that these tags are not eligible for bus_space_barrier operations. 793 * Addr is the physical address of the desired start of the handle. 794 */ 795bus_space_handle_t 796sparc64_fake_bustag(int space, bus_addr_t addr, struct bus_space_tag *ptag) 797{ 798 799 ptag->bst_cookie = NULL; 800 ptag->bst_parent = NULL; 801 ptag->bst_type = space; 802 ptag->bst_bus_barrier = NULL; 803 return (addr); 804} 805 806/* 807 * Base bus space handlers. 808 */ 809static void nexus_bus_barrier(bus_space_tag_t, bus_space_handle_t, 810 bus_size_t, bus_size_t, int); 811 812static void 813nexus_bus_barrier(bus_space_tag_t t, bus_space_handle_t h, bus_size_t offset, 814 bus_size_t size, int flags) 815{ 816 817 /* 818 * We have lots of alternatives depending on whether we're 819 * synchronizing loads with loads, loads with stores, stores 820 * with loads, or stores with stores. The only ones that seem 821 * generic are #Sync and #MemIssue. I'll use #Sync for safety. 822 */ 823 switch(flags) { 824 case BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE: 825 case BUS_SPACE_BARRIER_READ: 826 case BUS_SPACE_BARRIER_WRITE: 827 membar(Sync); 828 break; 829 default: 830 panic("sparc64_bus_barrier: unknown flags"); 831 } 832 return; 833} 834 835struct bus_space_tag nexus_bustag = { 836 NULL, /* cookie */ 837 NULL, /* parent bus tag */ 838 UPA_BUS_SPACE, /* type */ 839 nexus_bus_barrier, /* bus_space_barrier */ 840}; 841