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