bus_machdep.c revision 178859
11120Schegar/*- 22476Sgtriantafill * Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc. 31120Schegar * All rights reserved. 41120Schegar * 51120Schegar * This code is derived from software contributed to The NetBSD Foundation 61120Schegar * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 71120Schegar * NASA Ames Research Center. 81120Schegar * 91120Schegar * Redistribution and use in source and binary forms, with or without 101120Schegar * modification, are permitted provided that the following conditions 111120Schegar * are met: 121120Schegar * 1. Redistributions of source code must retain the above copyright 131120Schegar * notice, this list of conditions and the following disclaimer. 141120Schegar * 2. Redistributions in binary form must reproduce the above copyright 151120Schegar * notice, this list of conditions and the following disclaimer in the 161120Schegar * documentation and/or other materials provided with the distribution. 171120Schegar * 3. All advertising materials mentioning features or use of this software 181120Schegar * must display the following acknowledgement: 191120Schegar * This product includes software developed by the NetBSD 201120Schegar * Foundation, Inc. and its contributors. 211120Schegar * 4. Neither the name of The NetBSD Foundation nor the names of its 221120Schegar * contributors may be used to endorse or promote products derived 231120Schegar * from this software without specific prior written permission. 241120Schegar * 251120Schegar * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 261120Schegar * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 271120Schegar * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 281120Schegar * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 291120Schegar * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 301120Schegar * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 312404Sprappo * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 322404Sprappo * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 332404Sprappo * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 342404Sprappo * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 352404Sprappo * POSSIBILITY OF SUCH DAMAGE. 361120Schegar */ 371120Schegar/*- 381120Schegar * Copyright (c) 1992, 1993 391120Schegar * The Regents of the University of California. All rights reserved. 401120Schegar * 411120Schegar * This software was developed by the Computer Systems Engineering group 421120Schegar * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 431120Schegar * contributed to Berkeley. 441120Schegar * 451120Schegar * Redistribution and use in source and binary forms, with or without 461120Schegar * modification, are permitted provided that the following conditions 471120Schegar * are met: 481120Schegar * 1. Redistributions of source code must retain the above copyright 491120Schegar * notice, this list of conditions and the following disclaimer. 501120Schegar * 2. Redistributions in binary form must reproduce the above copyright 511120Schegar * notice, this list of conditions and the following disclaimer in the 521120Schegar * documentation and/or other materials provided with the distribution. 531120Schegar * 4. Neither the name of the University nor the names of its contributors 541120Schegar * may be used to endorse or promote products derived from this software 551120Schegar * without specific prior written permission. 561120Schegar * 571120Schegar * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 581120Schegar * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 591120Schegar * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 601120Schegar * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 611120Schegar * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 621120Schegar * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 632479Slancea * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 641120Schegar * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 651120Schegar * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 661120Schegar * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 671120Schegar * SUCH DAMAGE. 681120Schegar */ 691120Schegar/*- 701120Schegar * Copyright (c) 1997, 1998 Justin T. Gibbs. 711120Schegar * All rights reserved. 721273Salanb * Copyright 2001 by Thomas Moestl <tmm@FreeBSD.org>. All rights reserved. 731273Salanb * 741120Schegar * Redistribution and use in source and binary forms, with or without 751120Schegar * modification, are permitted provided that the following conditions 761120Schegar * are met: 771120Schegar * 1. Redistributions of source code must retain the above copyright 781120Schegar * notice, this list of conditions, and the following disclaimer, 791120Schegar * without modification, immediately at the beginning of the file. 801120Schegar * 2. The name of the author may not be used to endorse or promote products 811120Schegar * derived from this software without specific prior written permission. 821120Schegar * 831120Schegar * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 841120Schegar * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 851120Schegar * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 861120Schegar * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 871120Schegar * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 881120Schegar * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 891120Schegar * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 901120Schegar * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 911120Schegar * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 921120Schegar * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 931120Schegar * SUCH DAMAGE. 941120Schegar * 951120Schegar * from: @(#)machdep.c 8.6 (Berkeley) 1/14/94 961120Schegar * from: NetBSD: machdep.c,v 1.111 2001/09/15 07:13:40 eeh Exp 971120Schegar * and 981120Schegar * from: FreeBSD: src/sys/i386/i386/busdma_machdep.c,v 1.24 2001/08/15 991120Schegar */ 1001120Schegar 1011120Schegar#include <sys/cdefs.h> 1021120Schegar__FBSDID("$FreeBSD: head/sys/sparc64/sparc64/bus_machdep.c 178859 2008-05-08 21:02:07Z marius $"); 1031120Schegar 1041120Schegar#include <sys/param.h> 1051120Schegar#include <sys/bus.h> 1061120Schegar#include <sys/lock.h> 1071120Schegar#include <sys/malloc.h> 1081120Schegar#include <sys/mbuf.h> 1091120Schegar#include <sys/mutex.h> 1101120Schegar#include <sys/proc.h> 1111120Schegar#include <sys/smp.h> 1121120Schegar#include <sys/systm.h> 1131120Schegar#include <sys/uio.h> 1141120Schegar 1151120Schegar#include <vm/vm.h> 1161120Schegar#include <vm/vm_extern.h> 1171120Schegar#include <vm/vm_kern.h> 1181120Schegar#include <vm/vm_page.h> 1191120Schegar#include <vm/vm_param.h> 1201120Schegar#include <vm/vm_map.h> 1211120Schegar 1221120Schegar#include <machine/asi.h> 1231120Schegar#include <machine/atomic.h> 1241120Schegar#include <machine/bus.h> 1251120Schegar#include <machine/bus_private.h> 1261120Schegar#include <machine/cache.h> 1271120Schegar#include <machine/smp.h> 1281120Schegar#include <machine/tlb.h> 1291120Schegar 1301120Schegarstatic void nexus_bus_barrier(bus_space_tag_t, bus_space_handle_t, 1311312Smchung bus_size_t, bus_size_t, int); 1321120Schegar 1331120Schegar/* ASIs for bus access */ 1341120Schegarconst int bus_type_asi[] = { 1351120Schegar ASI_PHYS_BYPASS_EC_WITH_EBIT, /* nexus */ 1361120Schegar ASI_PHYS_BYPASS_EC_WITH_EBIT, /* SBus */ 1371120Schegar ASI_PHYS_BYPASS_EC_WITH_EBIT_L, /* PCI configuration space */ 1381120Schegar ASI_PHYS_BYPASS_EC_WITH_EBIT_L, /* PCI memory space */ 1391120Schegar ASI_PHYS_BYPASS_EC_WITH_EBIT_L, /* PCI I/O space */ 1401120Schegar 0 1411120Schegar}; 1421120Schegar 1431120Schegarconst int bus_stream_asi[] = { 1441120Schegar ASI_PHYS_BYPASS_EC_WITH_EBIT, /* nexus */ 1451120Schegar ASI_PHYS_BYPASS_EC_WITH_EBIT, /* SBus */ 1461120Schegar ASI_PHYS_BYPASS_EC_WITH_EBIT, /* PCI configuration space */ 1471120Schegar ASI_PHYS_BYPASS_EC_WITH_EBIT, /* PCI memory space */ 1481120Schegar ASI_PHYS_BYPASS_EC_WITH_EBIT, /* PCI I/O space */ 1491120Schegar 0 1501120Schegar}; 1511120Schegar 1521120Schegar/* 1531120Schegar * Convenience function for manipulating driver locks from busdma (during 1541120Schegar * busdma_swi, for example). Drivers that don't provide their own locks 1551120Schegar * should specify &Giant to dmat->lockfuncarg. Drivers that use their own 1561120Schegar * non-mutex locking scheme don't have to use this at all. 1571120Schegar */ 1581120Schegarvoid 1591120Schegarbusdma_lock_mutex(void *arg, bus_dma_lock_op_t op) 1601120Schegar{ 1611120Schegar struct mtx *dmtx; 1621120Schegar 1631120Schegar dmtx = (struct mtx *)arg; 1641120Schegar switch (op) { 1651120Schegar case BUS_DMA_LOCK: 1661120Schegar mtx_lock(dmtx); 1671120Schegar break; 1681120Schegar case BUS_DMA_UNLOCK: 1691120Schegar mtx_unlock(dmtx); 1701120Schegar break; 1711120Schegar default: 1721120Schegar panic("Unknown operation 0x%x for busdma_lock_mutex!", op); 1731120Schegar } 1741120Schegar} 1751120Schegar 1761120Schegar/* 1771120Schegar * dflt_lock should never get called. It gets put into the dma tag when 1781120Schegar * lockfunc == NULL, which is only valid if the maps that are associated 1791120Schegar * with the tag are meant to never be defered. 1801120Schegar * XXX Should have a way to identify which driver is responsible here. 1811120Schegar */ 1821120Schegarstatic void 1831120Schegardflt_lock(void *arg, bus_dma_lock_op_t op) 1841120Schegar{ 1851120Schegar#ifdef INVARIANTS 1861120Schegar panic("driver error: busdma dflt_lock called"); 1871120Schegar#else 1881120Schegar printf("DRIVER_ERROR: busdma dflt_lock called\n"); 1891120Schegar#endif 1901120Schegar} 1911120Schegar 1921120Schegar/* 1931120Schegar * Allocate a device specific dma_tag. 1941120Schegar */ 1951120Schegarint 1961120Schegarbus_dma_tag_create(bus_dma_tag_t parent, bus_size_t alignment, 1971120Schegar bus_size_t boundary, bus_addr_t lowaddr, bus_addr_t highaddr, 1981120Schegar bus_dma_filter_t *filter, void *filterarg, bus_size_t maxsize, 1991120Schegar int nsegments, bus_size_t maxsegsz, int flags, bus_dma_lock_t *lockfunc, 2001120Schegar void *lockfuncarg, bus_dma_tag_t *dmat) 2011120Schegar{ 2021120Schegar bus_dma_tag_t newtag; 2031120Schegar 2041120Schegar /* Return a NULL tag on failure */ 2051120Schegar *dmat = NULL; 2061120Schegar 2071120Schegar /* Enforce the usage of BUS_GET_DMA_TAG(). */ 2081120Schegar if (parent == NULL) 2091120Schegar panic("%s: parent DMA tag NULL", __func__); 2101120Schegar 2111120Schegar newtag = (bus_dma_tag_t)malloc(sizeof(*newtag), M_DEVBUF, M_NOWAIT); 2121120Schegar if (newtag == NULL) 2131120Schegar return (ENOMEM); 2141120Schegar 2151120Schegar /* 2161120Schegar * The method table pointer and the cookie need to be taken over from 2171120Schegar * the parent. 2181120Schegar */ 2191120Schegar newtag->dt_cookie = parent->dt_cookie; 2201120Schegar newtag->dt_mt = parent->dt_mt; 2211120Schegar 2221120Schegar newtag->dt_parent = parent; 2231120Schegar newtag->dt_alignment = alignment; 2241120Schegar newtag->dt_boundary = boundary; 2251120Schegar newtag->dt_lowaddr = trunc_page((vm_offset_t)lowaddr) + (PAGE_SIZE - 1); 2261120Schegar newtag->dt_highaddr = trunc_page((vm_offset_t)highaddr) + 2271120Schegar (PAGE_SIZE - 1); 2281120Schegar newtag->dt_filter = filter; 2291120Schegar newtag->dt_filterarg = filterarg; 2301120Schegar newtag->dt_maxsize = maxsize; 2311120Schegar newtag->dt_nsegments = nsegments; 2321120Schegar newtag->dt_maxsegsz = maxsegsz; 2331120Schegar newtag->dt_flags = flags; 2341120Schegar newtag->dt_ref_count = 1; /* Count ourselves */ 2351120Schegar newtag->dt_map_count = 0; 2361120Schegar 2371120Schegar if (lockfunc != NULL) { 2381120Schegar newtag->dt_lockfunc = lockfunc; 2391120Schegar newtag->dt_lockfuncarg = lockfuncarg; 2401120Schegar } else { 2411120Schegar newtag->dt_lockfunc = dflt_lock; 2421120Schegar newtag->dt_lockfuncarg = NULL; 2431120Schegar } 2441120Schegar 2451120Schegar newtag->dt_segments = NULL; 2461120Schegar 2471120Schegar /* Take into account any restrictions imposed by our parent tag. */ 2481120Schegar newtag->dt_lowaddr = ulmin(parent->dt_lowaddr, newtag->dt_lowaddr); 2491120Schegar newtag->dt_highaddr = ulmax(parent->dt_highaddr, newtag->dt_highaddr); 2501120Schegar if (newtag->dt_boundary == 0) 2511120Schegar newtag->dt_boundary = parent->dt_boundary; 2521120Schegar else if (parent->dt_boundary != 0) 2531120Schegar newtag->dt_boundary = ulmin(parent->dt_boundary, 2541120Schegar newtag->dt_boundary); 2551120Schegar atomic_add_int(&parent->dt_ref_count, 1); 2561120Schegar 2571120Schegar if (newtag->dt_boundary > 0) 2581120Schegar newtag->dt_maxsegsz = ulmin(newtag->dt_maxsegsz, 2591120Schegar newtag->dt_boundary); 2601120Schegar 2611120Schegar *dmat = newtag; 2621120Schegar return (0); 2631120Schegar} 2641120Schegar 2651120Schegarint 2661120Schegarbus_dma_tag_destroy(bus_dma_tag_t dmat) 2671120Schegar{ 2681120Schegar bus_dma_tag_t parent; 2691120Schegar 2701120Schegar if (dmat != NULL) { 2711120Schegar if (dmat->dt_map_count != 0) 2721120Schegar return (EBUSY); 2731120Schegar while (dmat != NULL) { 2741120Schegar parent = dmat->dt_parent; 2751120Schegar atomic_subtract_int(&dmat->dt_ref_count, 1); 2761120Schegar if (dmat->dt_ref_count == 0) { 2771120Schegar if (dmat->dt_segments != NULL) 2781120Schegar free(dmat->dt_segments, M_DEVBUF); 2791120Schegar free(dmat, M_DEVBUF); 2801120Schegar /* 2811120Schegar * Last reference count, so 2821120Schegar * release our reference 2831120Schegar * count on our parent. 2841120Schegar */ 2851120Schegar dmat = parent; 2861120Schegar } else 2871120Schegar dmat = NULL; 2881120Schegar } 2891120Schegar } 2901120Schegar return (0); 2911120Schegar} 2921120Schegar 2931120Schegar/* Allocate/free a tag, and do the necessary management work. */ 2941120Schegarint 2951120Schegarsparc64_dma_alloc_map(bus_dma_tag_t dmat, bus_dmamap_t *mapp) 2961120Schegar{ 2971120Schegar 2981120Schegar if (dmat->dt_segments == NULL) { 2991120Schegar dmat->dt_segments = (bus_dma_segment_t *)malloc( 3001120Schegar sizeof(bus_dma_segment_t) * dmat->dt_nsegments, M_DEVBUF, 3011120Schegar M_NOWAIT); 3021120Schegar if (dmat->dt_segments == NULL) 3031120Schegar return (ENOMEM); 3041120Schegar } 3051120Schegar *mapp = malloc(sizeof(**mapp), M_DEVBUF, M_NOWAIT | M_ZERO); 3061120Schegar if (*mapp == NULL) 3071120Schegar return (ENOMEM); 3081120Schegar 3091120Schegar SLIST_INIT(&(*mapp)->dm_reslist); 3101120Schegar dmat->dt_map_count++; 3111120Schegar return (0); 3121120Schegar} 3131120Schegar 3141120Schegarvoid 3151120Schegarsparc64_dma_free_map(bus_dma_tag_t dmat, bus_dmamap_t map) 3161120Schegar{ 3171120Schegar 3181120Schegar free(map, M_DEVBUF); 3191120Schegar dmat->dt_map_count--; 3201120Schegar} 3211120Schegar 3221120Schegarstatic int 3231120Schegarnexus_dmamap_create(bus_dma_tag_t dmat, int flags, bus_dmamap_t *mapp) 3241120Schegar{ 3251120Schegar 3261120Schegar return (sparc64_dma_alloc_map(dmat, mapp)); 3271120Schegar} 3281120Schegar 3291120Schegarstatic int 3301120Schegarnexus_dmamap_destroy(bus_dma_tag_t dmat, bus_dmamap_t map) 3311120Schegar{ 3321120Schegar 3331120Schegar sparc64_dma_free_map(dmat, map); 3341120Schegar return (0); 3351120Schegar} 3361120Schegar 3371120Schegar/* 3381120Schegar * Utility function to load a linear buffer. lastaddrp holds state 3391120Schegar * between invocations (for multiple-buffer loads). segp contains 3401120Schegar * the starting segment on entrace, and the ending segment on exit. 3411120Schegar * first indicates if this is the first invocation of this function. 3421120Schegar */ 3431120Schegarstatic int 3441120Schegar_nexus_dmamap_load_buffer(bus_dma_tag_t dmat, void *buf, bus_size_t buflen, 3451120Schegar struct thread *td, int flags, bus_addr_t *lastaddrp, 3461120Schegar bus_dma_segment_t *segs, int *segp, int first) 3471120Schegar{ 3481120Schegar bus_size_t sgsize; 3491120Schegar bus_addr_t curaddr, lastaddr, baddr, bmask; 3501120Schegar vm_offset_t vaddr = (vm_offset_t)buf; 3511120Schegar int seg; 3521120Schegar pmap_t pmap; 3531120Schegar 3541120Schegar if (td != NULL) 3551120Schegar pmap = vmspace_pmap(td->td_proc->p_vmspace); 3561120Schegar else 3571120Schegar pmap = NULL; 3581120Schegar 3591120Schegar lastaddr = *lastaddrp; 3601120Schegar bmask = ~(dmat->dt_boundary - 1); 3611120Schegar 3621120Schegar for (seg = *segp; buflen > 0 ; ) { 3631120Schegar /* 3642495Ssherman * Get the physical address for this segment. 3652495Ssherman */ 3661120Schegar if (pmap) 3671120Schegar curaddr = pmap_extract(pmap, vaddr); 3681120Schegar else 3691120Schegar curaddr = pmap_kextract(vaddr); 3701120Schegar 3711120Schegar /* 3721120Schegar * Compute the segment size, and adjust counts. 3731120Schegar */ 3741120Schegar sgsize = PAGE_SIZE - ((u_long)curaddr & PAGE_MASK); 3751120Schegar if (sgsize > dmat->dt_maxsegsz) 3761120Schegar sgsize = dmat->dt_maxsegsz; 3771120Schegar if (buflen < sgsize) 3781120Schegar sgsize = buflen; 3791120Schegar 3801120Schegar /* 3811120Schegar * Make sure we don't cross any boundaries. 3821120Schegar */ 3831120Schegar if (dmat->dt_boundary > 0) { 3841120Schegar baddr = (curaddr + dmat->dt_boundary) & bmask; 3851120Schegar if (sgsize > (baddr - curaddr)) 3861865Sasmundak sgsize = (baddr - curaddr); 3871120Schegar } 3881120Schegar 3891120Schegar /* 3901120Schegar * Insert chunk into a segment, coalescing with 3911120Schegar * previous segment if possible. 3921120Schegar */ 3931120Schegar if (first) { 3941120Schegar segs[seg].ds_addr = curaddr; 3951120Schegar segs[seg].ds_len = sgsize; 3961120Schegar first = 0; 3971120Schegar } else { 3981120Schegar if (curaddr == lastaddr && 3991120Schegar (segs[seg].ds_len + sgsize) <= dmat->dt_maxsegsz && 4001120Schegar (dmat->dt_boundary == 0 || 4011120Schegar (segs[seg].ds_addr & bmask) == (curaddr & bmask))) 4021120Schegar segs[seg].ds_len += sgsize; 4031120Schegar else { 4041120Schegar if (++seg >= dmat->dt_nsegments) 4051120Schegar break; 4061120Schegar segs[seg].ds_addr = curaddr; 4071120Schegar segs[seg].ds_len = sgsize; 4081120Schegar } 4091120Schegar } 4101120Schegar 4111120Schegar lastaddr = curaddr + sgsize; 4121120Schegar vaddr += sgsize; 4131120Schegar buflen -= sgsize; 4141120Schegar } 4151120Schegar 4161120Schegar *segp = seg; 4171120Schegar *lastaddrp = lastaddr; 4181120Schegar 4191120Schegar /* 4201120Schegar * Did we fit? 4211120Schegar */ 4221120Schegar return (buflen != 0 ? EFBIG : 0); /* XXX better return value here? */ 4231120Schegar} 4241120Schegar 4251120Schegar/* 4261120Schegar * Common function for loading a DMA map with a linear buffer. May 4271120Schegar * be called by bus-specific DMA map load functions. 4281120Schegar * 4291120Schegar * Most SPARCs have IOMMUs in the bus controllers. In those cases 4301120Schegar * they only need one segment and will use virtual addresses for DVMA. 4311120Schegar * Those bus controllers should intercept these vectors and should 4321120Schegar * *NEVER* call nexus_dmamap_load() which is used only by devices that 4331120Schegar * bypass DVMA. 4341120Schegar */ 4351120Schegarstatic int 4361120Schegarnexus_dmamap_load(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf, 4371120Schegar bus_size_t buflen, bus_dmamap_callback_t *callback, void *callback_arg, 4381120Schegar int flags) 4391120Schegar{ 4401120Schegar bus_addr_t lastaddr; 4411120Schegar int error, nsegs; 4421120Schegar 4431120Schegar error = _nexus_dmamap_load_buffer(dmat, buf, buflen, NULL, flags, 4441120Schegar &lastaddr, dmat->dt_segments, &nsegs, 1); 4451120Schegar 4461120Schegar if (error == 0) { 4471120Schegar (*callback)(callback_arg, dmat->dt_segments, nsegs + 1, 0); 4481120Schegar map->dm_flags |= DMF_LOADED; 4491120Schegar } else 4501120Schegar (*callback)(callback_arg, NULL, 0, error); 4511120Schegar 4521120Schegar return (0); 4531120Schegar} 4541120Schegar 4551120Schegar/* 4561120Schegar * Like nexus_dmamap_load(), but for mbufs. 4571120Schegar */ 4581120Schegarstatic int 4591120Schegarnexus_dmamap_load_mbuf(bus_dma_tag_t dmat, bus_dmamap_t map, struct mbuf *m0, 4601120Schegar bus_dmamap_callback2_t *callback, void *callback_arg, int flags) 4611120Schegar{ 4621120Schegar int nsegs, error; 4631120Schegar 4641120Schegar M_ASSERTPKTHDR(m0); 4651120Schegar 4661120Schegar nsegs = 0; 4671120Schegar error = 0; 4681120Schegar if (m0->m_pkthdr.len <= dmat->dt_maxsize) { 4691120Schegar int first = 1; 4701120Schegar bus_addr_t lastaddr = 0; 4711120Schegar struct mbuf *m; 4721120Schegar 4731120Schegar for (m = m0; m != NULL && error == 0; m = m->m_next) { 4741120Schegar if (m->m_len > 0) { 4751120Schegar error = _nexus_dmamap_load_buffer(dmat, 4761120Schegar m->m_data, m->m_len,NULL, flags, &lastaddr, 4771120Schegar dmat->dt_segments, &nsegs, first); 4781120Schegar first = 0; 4791120Schegar } 4801120Schegar } 4811120Schegar } else { 4821120Schegar error = EINVAL; 4831120Schegar } 4841120Schegar 4851120Schegar if (error) { 4861120Schegar /* force "no valid mappings" in callback */ 4871120Schegar (*callback)(callback_arg, dmat->dt_segments, 0, 0, error); 4881120Schegar } else { 4891120Schegar map->dm_flags |= DMF_LOADED; 4901120Schegar (*callback)(callback_arg, dmat->dt_segments, nsegs + 1, 4911120Schegar m0->m_pkthdr.len, error); 4921120Schegar } 4931120Schegar return (error); 4941120Schegar} 4951120Schegar 4961120Schegarstatic int 4971120Schegarnexus_dmamap_load_mbuf_sg(bus_dma_tag_t dmat, bus_dmamap_t map, struct mbuf *m0, 4981120Schegar bus_dma_segment_t *segs, int *nsegs, int flags) 4991120Schegar{ 5001120Schegar int error; 5011120Schegar 5021120Schegar M_ASSERTPKTHDR(m0); 5031120Schegar 5041120Schegar *nsegs = 0; 5051120Schegar error = 0; 5061120Schegar if (m0->m_pkthdr.len <= dmat->dt_maxsize) { 5071120Schegar int first = 1; 5081120Schegar bus_addr_t lastaddr = 0; 5091120Schegar struct mbuf *m; 5101120Schegar 5111120Schegar for (m = m0; m != NULL && error == 0; m = m->m_next) { 5121120Schegar if (m->m_len > 0) { 5131120Schegar error = _nexus_dmamap_load_buffer(dmat, 5141120Schegar m->m_data, m->m_len,NULL, flags, &lastaddr, 5151120Schegar segs, nsegs, first); 5161120Schegar first = 0; 5171120Schegar } 5181120Schegar } 5191120Schegar } else { 5201120Schegar error = EINVAL; 5211120Schegar } 5221120Schegar 5231120Schegar ++*nsegs; 5241120Schegar return (error); 5251120Schegar} 5261120Schegar 5271120Schegar/* 5281120Schegar * Like nexus_dmamap_load(), but for uios. 5291120Schegar */ 5301120Schegarstatic int 5311120Schegarnexus_dmamap_load_uio(bus_dma_tag_t dmat, bus_dmamap_t map, struct uio *uio, 5321120Schegar bus_dmamap_callback2_t *callback, void *callback_arg, int flags) 5331120Schegar{ 5341181Sprr bus_addr_t lastaddr; 5351181Sprr int nsegs, error, first, i; 5361181Sprr bus_size_t resid; 5371181Sprr struct iovec *iov; 5381181Sprr struct thread *td = NULL; 5391181Sprr 5401181Sprr resid = uio->uio_resid; 5411181Sprr iov = uio->uio_iov; 5421181Sprr 5431181Sprr if (uio->uio_segflg == UIO_USERSPACE) { 5441181Sprr td = uio->uio_td; 5451181Sprr KASSERT(td != NULL, ("%s: USERSPACE but no proc", __func__)); 5461181Sprr } 5471181Sprr 5481181Sprr nsegs = 0; 5491181Sprr error = 0; 5501181Sprr first = 1; 5511181Sprr for (i = 0; i < uio->uio_iovcnt && resid != 0 && !error; i++) { 5521181Sprr /* 5531181Sprr * Now at the first iovec to load. Load each iovec 5541181Sprr * until we have exhausted the residual count. 5551181Sprr */ 5561181Sprr bus_size_t minlen = 5571181Sprr resid < iov[i].iov_len ? resid : iov[i].iov_len; 5581181Sprr caddr_t addr = (caddr_t) iov[i].iov_base; 5591181Sprr 5601181Sprr if (minlen > 0) { 5611181Sprr error = _nexus_dmamap_load_buffer(dmat, addr, minlen, 5621181Sprr td, flags, &lastaddr, dmat->dt_segments, &nsegs, 5631181Sprr first); 5641181Sprr first = 0; 5651181Sprr 5661181Sprr resid -= minlen; 5671181Sprr } 5681181Sprr } 5691181Sprr 5701181Sprr if (error) { 5711181Sprr /* force "no valid mappings" in callback */ 5721181Sprr (*callback)(callback_arg, dmat->dt_segments, 0, 0, error); 5731181Sprr } else { 5741181Sprr map->dm_flags |= DMF_LOADED; 5751181Sprr (*callback)(callback_arg, dmat->dt_segments, nsegs + 1, 5761181Sprr uio->uio_resid, error); 5771181Sprr } 5781181Sprr return (error); 5791181Sprr} 5801181Sprr 5811181Sprr/* 5821181Sprr * Common function for unloading a DMA map. May be called by 5831181Sprr * bus-specific DMA map unload functions. 5841181Sprr */ 5851181Sprrstatic void 5861181Sprrnexus_dmamap_unload(bus_dma_tag_t dmat, bus_dmamap_t map) 5871181Sprr{ 5881181Sprr 5891181Sprr map->dm_flags &= ~DMF_LOADED; 5901181Sprr} 5911181Sprr 5921181Sprr/* 5931181Sprr * Common function for DMA map synchronization. May be called 5941181Sprr * by bus-specific DMA map synchronization functions. 5951181Sprr */ 5961181Sprrstatic void 5971181Sprrnexus_dmamap_sync(bus_dma_tag_t dmat, bus_dmamap_t map, bus_dmasync_op_t op) 5981181Sprr{ 5991181Sprr 6001181Sprr /* 6011181Sprr * We sync out our caches, but the bus must do the same. 6021181Sprr * 6031181Sprr * Actually a #Sync is expensive. We should optimize. 6041181Sprr */ 6051181Sprr if ((op & BUS_DMASYNC_PREREAD) || (op & BUS_DMASYNC_PREWRITE)) { 6061181Sprr /* 6071181Sprr * Don't really need to do anything, but flush any pending 6081181Sprr * writes anyway. 6091181Sprr */ 6101181Sprr membar(Sync); 6111181Sprr } 6121181Sprr if (op & BUS_DMASYNC_POSTWRITE) { 6131181Sprr /* Nothing to do. Handled by the bus controller. */ 6141181Sprr } 6151120Schegar} 6161120Schegar 6171120Schegar/* 6181120Schegar * Common function for DMA-safe memory allocation. May be called 6191120Schegar * by bus-specific DMA memory allocation functions. 6201120Schegar */ 6211120Schegarstatic int 6221120Schegarnexus_dmamem_alloc(bus_dma_tag_t dmat, void **vaddr, int flags, 6231120Schegar bus_dmamap_t *mapp) 6241120Schegar{ 6251120Schegar int mflags; 6261120Schegar 6271120Schegar if (flags & BUS_DMA_NOWAIT) 6281120Schegar mflags = M_NOWAIT; 6291120Schegar else 6301120Schegar mflags = M_WAITOK; 6311120Schegar if (flags & BUS_DMA_ZERO) 6321120Schegar mflags |= M_ZERO; 6331120Schegar 6341120Schegar if ((dmat->dt_maxsize <= PAGE_SIZE)) { 6351120Schegar *vaddr = malloc(dmat->dt_maxsize, M_DEVBUF, mflags); 6361120Schegar } else { 6371120Schegar /* 6381120Schegar * XXX use contigmalloc until it is merged into this 6391120Schegar * facility and handles multi-seg allocations. Nobody 6401120Schegar * is doing multi-seg allocations yet though. 6411120Schegar */ 6421120Schegar *vaddr = contigmalloc(dmat->dt_maxsize, M_DEVBUF, mflags, 6431120Schegar 0ul, dmat->dt_lowaddr, 6441120Schegar dmat->dt_alignment ? dmat->dt_alignment : 1UL, 6451120Schegar dmat->dt_boundary); 6461120Schegar } 6471120Schegar if (*vaddr == NULL) 6481120Schegar return (ENOMEM); 6491120Schegar return (0); 6501120Schegar} 6511120Schegar 6521120Schegar/* 6531120Schegar * Common function for freeing DMA-safe memory. May be called by 6541120Schegar * bus-specific DMA memory free functions. 6551120Schegar */ 6561120Schegarstatic void 6571120Schegarnexus_dmamem_free(bus_dma_tag_t dmat, void *vaddr, bus_dmamap_t map) 6581120Schegar{ 6591120Schegar 6601120Schegar if ((dmat->dt_maxsize <= PAGE_SIZE)) 6611120Schegar free(vaddr, M_DEVBUF); 6621120Schegar else { 6631120Schegar contigfree(vaddr, dmat->dt_maxsize, M_DEVBUF); 6641120Schegar } 6651120Schegar} 6661120Schegar 6671120Schegarstruct bus_dma_methods nexus_dma_methods = { 6681120Schegar nexus_dmamap_create, 6691120Schegar nexus_dmamap_destroy, 6701120Schegar nexus_dmamap_load, 6711120Schegar nexus_dmamap_load_mbuf, 6721120Schegar nexus_dmamap_load_mbuf_sg, 6731120Schegar nexus_dmamap_load_uio, 6741120Schegar nexus_dmamap_unload, 6751120Schegar nexus_dmamap_sync, 6761120Schegar nexus_dmamem_alloc, 6771120Schegar nexus_dmamem_free, 6781120Schegar}; 6791120Schegar 6801120Schegarstruct bus_dma_tag nexus_dmatag = { 6811120Schegar NULL, 6821120Schegar NULL, 6831120Schegar 1, 6841120Schegar 0, 6851120Schegar ~0, 6861120Schegar ~0, 6871120Schegar NULL, /* XXX */ 6881120Schegar NULL, 6891181Sprr ~0, 6901181Sprr ~0, 6911181Sprr ~0, 6921181Sprr 0, 6931181Sprr 0, 6941181Sprr 0, 6951181Sprr NULL, 6961181Sprr NULL, 6971181Sprr NULL, 6981181Sprr &nexus_dma_methods, 6991181Sprr}; 7001120Schegar 7011181Sprr/* 7021181Sprr * Helpers to map/unmap bus memory 7031181Sprr */ 7041181Sprrint 7051181Sprrsparc64_bus_mem_map(bus_space_tag_t tag, bus_space_handle_t handle, 7061181Sprr bus_size_t size, int flags, vm_offset_t vaddr, void **hp) 7071181Sprr{ 7081181Sprr vm_offset_t addr; 7091120Schegar vm_offset_t sva; 7101120Schegar vm_offset_t va; 7111120Schegar vm_paddr_t pa; 7121120Schegar vm_size_t vsz; 7131120Schegar u_long pm_flags; 7141120Schegar 7151120Schegar addr = (vm_offset_t)handle; 7161120Schegar size = round_page(size); 7171120Schegar if (size == 0) { 7181120Schegar printf("%s: zero size\n", __func__); 7191120Schegar return (EINVAL); 7201120Schegar } 7211120Schegar switch (tag->bst_type) { 7221120Schegar case PCI_CONFIG_BUS_SPACE: 7231120Schegar case PCI_IO_BUS_SPACE: 7241120Schegar case PCI_MEMORY_BUS_SPACE: 7251120Schegar pm_flags = TD_IE; 7261120Schegar break; 7271120Schegar default: 7281120Schegar pm_flags = 0; 7291120Schegar break; 7301120Schegar } 7311120Schegar 7321120Schegar if (!(flags & BUS_SPACE_MAP_CACHEABLE)) 7331120Schegar pm_flags |= TD_E; 7341120Schegar 7351120Schegar if (vaddr != 0L) 7361120Schegar sva = trunc_page(vaddr); 7371120Schegar else { 7381120Schegar if ((sva = kmem_alloc_nofault(kernel_map, size)) == 0) 7391120Schegar panic("%s: cannot allocate virtual memory", __func__); 7401120Schegar } 7411120Schegar 7421120Schegar /* Preserve page offset. */ 7431120Schegar *hp = (void *)(sva | ((u_long)addr & PAGE_MASK)); 7441120Schegar 7451120Schegar pa = trunc_page(addr); 7461120Schegar if ((flags & BUS_SPACE_MAP_READONLY) == 0) 7471120Schegar pm_flags |= TD_W; 7481120Schegar 7491120Schegar va = sva; 7501120Schegar vsz = size; 7511120Schegar do { 7521120Schegar pmap_kenter_flags(va, pa, pm_flags); 7531120Schegar va += PAGE_SIZE; 7541120Schegar pa += PAGE_SIZE; 7551120Schegar } while ((vsz -= PAGE_SIZE) > 0); 7561120Schegar tlb_range_demap(kernel_pmap, sva, sva + size - 1); 7571120Schegar return (0); 7581120Schegar} 7591120Schegar 7601120Schegarint 7611120Schegarsparc64_bus_mem_unmap(void *bh, bus_size_t size) 7621120Schegar{ 7631120Schegar vm_offset_t sva; 7641120Schegar vm_offset_t va; 7651120Schegar vm_offset_t endva; 7661120Schegar 7671120Schegar sva = trunc_page((vm_offset_t)bh); 7681120Schegar endva = sva + round_page(size); 7691120Schegar for (va = sva; va < endva; va += PAGE_SIZE) 7701120Schegar pmap_kremove_flags(va); 7711120Schegar tlb_range_demap(kernel_pmap, sva, sva + size - 1); 7721120Schegar kmem_free(kernel_map, sva, size); 7731120Schegar return (0); 7741120Schegar} 7751120Schegar 7761120Schegar/* 7771120Schegar * Fake up a bus tag, for use by console drivers in early boot when the 7781120Schegar * regular means to allocate resources are not yet available. 7791120Schegar * Addr is the physical address of the desired start of the handle. 7801120Schegar */ 7811120Schegarbus_space_handle_t 7821120Schegarsparc64_fake_bustag(int space, bus_addr_t addr, struct bus_space_tag *ptag) 7831120Schegar{ 7841120Schegar 7851120Schegar ptag->bst_cookie = NULL; 7861120Schegar ptag->bst_parent = NULL; 7871120Schegar ptag->bst_type = space; 7881120Schegar ptag->bst_bus_barrier = nexus_bus_barrier; 7891120Schegar return (addr); 7901120Schegar} 7911120Schegar 7921120Schegar/* 7931120Schegar * Base bus space handlers. 7941120Schegar */ 7951120Schegar 7961120Schegarstatic void 7971120Schegarnexus_bus_barrier(bus_space_tag_t t, bus_space_handle_t h, bus_size_t offset, 7981120Schegar bus_size_t size, int flags) 7991120Schegar{ 8001120Schegar 8011120Schegar /* 8021120Schegar * We have lots of alternatives depending on whether we're 8031120Schegar * synchronizing loads with loads, loads with stores, stores 8041120Schegar * with loads, or stores with stores. The only ones that seem 8051120Schegar * generic are #Sync and #MemIssue. I'll use #Sync for safety. 8061120Schegar */ 8071120Schegar switch(flags) { 8081120Schegar case BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE: 8091120Schegar case BUS_SPACE_BARRIER_READ: 8101120Schegar case BUS_SPACE_BARRIER_WRITE: 8111120Schegar membar(Sync); 8121120Schegar break; 8131120Schegar default: 8141120Schegar panic("%s: unknown flags", __func__); 8151120Schegar } 8161120Schegar return; 8171120Schegar} 8181120Schegar 8191120Schegarstruct bus_space_tag nexus_bustag = { 8201120Schegar NULL, /* cookie */ 8211120Schegar NULL, /* parent bus tag */ 8221120Schegar NEXUS_BUS_SPACE, /* type */ 8231120Schegar nexus_bus_barrier, /* bus_space_barrier */ 8241120Schegar}; 8251120Schegar