Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 7 May 2012 05:28:49 +0000 (UTC)
From:      Marcel Moolenaar <marcel@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r235120 - in projects/altix2/sys: kern sys
Message-ID:  <201205070528.q475SnFE048222@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: marcel
Date: Mon May  7 05:28:49 2012
New Revision: 235120
URL: http://svn.freebsd.org/changeset/base/235120

Log:
  o   Implement busdma_mem_alloc().
  o   Use M_NOWAIT to allocate tags.

Modified:
  projects/altix2/sys/kern/subr_busdma.c
  projects/altix2/sys/sys/busdma.h

Modified: projects/altix2/sys/kern/subr_busdma.c
==============================================================================
--- projects/altix2/sys/kern/subr_busdma.c	Mon May  7 04:56:26 2012	(r235119)
+++ projects/altix2/sys/kern/subr_busdma.c	Mon May  7 05:28:49 2012	(r235120)
@@ -34,6 +34,10 @@ __FBSDID("$FreeBSD$");
 #include <sys/busdma.h>
 #include <sys/malloc.h>
 #include <machine/stdarg.h>
+#include <vm/vm.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_kern.h>
+#include <vm/pmap.h>
 
 struct busdma_tag {
 	struct busdma_tag *dt_chain;
@@ -49,6 +53,20 @@ struct busdma_tag {
 	bus_size_t	dt_maxsegsz;
 };
 
+struct busdma_seg {
+	TAILQ_ENTRY(busdma_seg) ds_chain;
+	vm_offset_t	ds_vaddr;
+	vm_size_t	ds_size;
+	vm_paddr_t	ds_paddr;
+	bus_addr_t	ds_baddr;
+};
+
+struct busdma_mem {
+	struct busdma_tag *dm_tag;
+	TAILQ_HEAD(,busdma_seg) dm_seg;
+	u_int		dm_nsegs;
+};
+
 static struct busdma_tag busdma_root_tag = {
 	.dt_maxaddr = ~0UL,
 	.dt_align = 1,
@@ -57,10 +75,12 @@ static struct busdma_tag busdma_root_tag
 	.dt_maxsegsz = ~0UL,
 };
 
+static MALLOC_DEFINE(M_BUSDMA_MEM, "busdma_mem", "busdma mem structures");
+static MALLOC_DEFINE(M_BUSDMA_SEG, "busdma_seg", "busdma seg structures");
 static MALLOC_DEFINE(M_BUSDMA_TAG, "busdma_tag", "busdma tag structures");
 
 static void
-_busdma_tag_dump(const char *func, device_t dev, busdma_tag_t tag)
+_busdma_tag_dump(const char *func, device_t dev, struct busdma_tag *tag)
 {
 
 	printf("[%s: %s: tag=%p (minaddr=%jx, maxaddr=%jx, align=%jx, "
@@ -72,7 +92,21 @@ _busdma_tag_dump(const char *func, devic
 	    tag->dt_nsegs, (uintmax_t)tag->dt_maxsegsz);
 }
 
-static busdma_tag_t
+static void
+_busdma_mem_dump(const char *func, struct busdma_mem *mem) 
+{
+	struct busdma_seg *seg;
+
+	printf("[%s: %s: mem=%p (tag=%p, nsegs=%u)", func,
+	    device_get_nameunit(mem->dm_tag->dt_device), mem,
+	    mem->dm_tag, mem->dm_nsegs);
+	TAILQ_FOREACH(seg, &mem->dm_seg, ds_chain)
+		printf(", {size=%jx, paddr=%jx, vaddr=%jx}", seg->ds_size,
+		    seg->ds_paddr, seg->ds_vaddr);
+	printf("]\n");
+}
+
+static struct busdma_tag *
 _busdma_tag_get_base(device_t dev)
 {
 	device_t parent;
@@ -94,11 +128,11 @@ _busdma_tag_get_base(device_t dev)
 }
 
 static int
-_busdma_tag_make(device_t dev, busdma_tag_t base, bus_addr_t maxaddr,
+_busdma_tag_make(device_t dev, struct busdma_tag *base, bus_addr_t maxaddr,
     bus_addr_t align, bus_addr_t bndry, bus_size_t maxsz, u_int nsegs,
-    bus_size_t maxsegsz, u_int flags, busdma_tag_t *tag_p)
+    bus_size_t maxsegsz, u_int flags, struct busdma_tag **tag_p)
 {
-	busdma_tag_t tag;
+	struct busdma_tag *tag;
 
 	/*
 	 * If nsegs is 1, ignore maxsegsz. What this means is that if we have
@@ -108,8 +142,7 @@ _busdma_tag_make(device_t dev, busdma_ta
 	if (maxsegsz > maxsz || nsegs == 1)
 		maxsegsz = maxsz;
 
-	tag = (busdma_tag_t)malloc(sizeof(*tag), M_BUSDMA_TAG,
-	    M_WAITOK | M_ZERO);
+	tag = malloc(sizeof(*tag), M_BUSDMA_TAG, M_NOWAIT | M_ZERO);
 	tag->dt_device = dev;
 	tag->dt_minaddr = MAX(0, base->dt_minaddr);
 	tag->dt_maxaddr = MIN(maxaddr, base->dt_maxaddr);
@@ -126,9 +159,9 @@ _busdma_tag_make(device_t dev, busdma_ta
 int
 busdma_tag_create(device_t dev, bus_addr_t maxaddr, bus_addr_t align,
     bus_addr_t bndry, bus_size_t maxsz, u_int nsegs, bus_size_t maxsegsz,
-    u_int flags, busdma_tag_t *tag_p)
+    u_int flags, struct busdma_tag **tag_p)
 {
-	busdma_tag_t base, first, tag;
+	struct busdma_tag *base, *first, *tag;
 	int error;
 
 	base = _busdma_tag_get_base(dev);
@@ -147,11 +180,11 @@ busdma_tag_create(device_t dev, bus_addr
 }
 
 int
-busdma_tag_derive(busdma_tag_t base, bus_addr_t maxaddr, bus_addr_t align,
+busdma_tag_derive(struct busdma_tag *base, bus_addr_t maxaddr, bus_addr_t align,
     bus_addr_t bndry, bus_size_t maxsz, u_int nsegs, bus_size_t maxsegsz,
-    u_int flags, busdma_tag_t *tag_p)
+    u_int flags, struct busdma_tag **tag_p)
 {
-	busdma_tag_t tag;
+	struct busdma_tag *tag;
 	int error;
 
 	error = _busdma_tag_make(base->dt_device, base, maxaddr, align, bndry,
@@ -168,3 +201,48 @@ busdma_tag_derive(busdma_tag_t base, bus
 	*tag_p = tag;
 	return (0);
 }
+
+int
+busdma_mem_alloc(struct busdma_tag *tag, u_int flags, struct busdma_mem **mem_p)
+{
+	struct busdma_mem *mem;
+	struct busdma_seg *seg;
+	vm_size_t maxsz;
+
+	mem = malloc(sizeof(*mem), M_BUSDMA_MEM, M_WAITOK | M_ZERO);
+	mem->dm_tag = tag;
+	TAILQ_INIT(&mem->dm_seg);
+
+	maxsz = tag->dt_maxsz;
+	while (maxsz > 0 && mem->dm_nsegs < tag->dt_nsegs) {
+		seg = malloc(sizeof(*seg), M_BUSDMA_SEG, M_WAITOK | M_ZERO);
+		TAILQ_INSERT_TAIL(&mem->dm_seg, seg, ds_chain);
+		seg->ds_size = MIN(maxsz, tag->dt_maxsegsz);
+		seg->ds_vaddr = kmem_alloc_contig(kernel_map, seg->ds_size, 0,
+		    tag->dt_minaddr, tag->dt_maxaddr, tag->dt_align,
+		    tag->dt_bndry, VM_MEMATTR_DEFAULT);
+		if (seg->ds_vaddr == 0) {
+			/* TODO: try a smaller segment size */
+			goto fail;
+		}
+		seg->ds_paddr = pmap_kextract(seg->ds_vaddr);
+		maxsz -= seg->ds_size;
+		mem->dm_nsegs++;
+	}
+	if (maxsz == 0) {
+		_busdma_mem_dump(__func__, mem);
+		*mem_p = mem;
+		return (0);
+	}
+
+ fail:
+	while (!TAILQ_EMPTY(&mem->dm_seg)) {
+		seg = TAILQ_FIRST(&mem->dm_seg);
+		if (seg->ds_vaddr != 0)
+			kmem_free(kernel_map, seg->ds_vaddr, seg->ds_size);
+		TAILQ_REMOVE(&mem->dm_seg, seg, ds_chain);
+		free(seg, M_BUSDMA_SEG);
+	}
+	free(mem, M_BUSDMA_MEM);
+	return (ENOMEM);
+}

Modified: projects/altix2/sys/sys/busdma.h
==============================================================================
--- projects/altix2/sys/sys/busdma.h	Mon May  7 04:56:26 2012	(r235119)
+++ projects/altix2/sys/sys/busdma.h	Mon May  7 05:28:49 2012	(r235120)
@@ -34,6 +34,9 @@
 struct busdma_tag;
 typedef struct busdma_tag *busdma_tag_t;
 
+struct busdma_mem;
+typedef struct busdma_mem *busdma_mem_t;
+
 /*
  * busdma_tag_create
  * returns:		errno value
@@ -56,7 +59,7 @@ int busdma_tag_create(device_t dev, bus_
  * busdma_tag_derive
  * returns:		errno value
  * arguments:
- *	tag		The root tag that is to be derived from.
+ *	tag		the root tag that is to be derived from.
  *	maxaddr		largest address that can be handled by the device.
  *	align		alignment requirements of the DMA segments.
  *	bndry		address boundary constraints for DMA.
@@ -70,4 +73,14 @@ int busdma_tag_derive(busdma_tag_t tag, 
     bus_addr_t bndry, bus_size_t maxsz, u_int nsegs, bus_size_t maxsegsz,
     u_int flags, busdma_tag_t *tag_p);
 
+/*
+ * busdma_mem_alloc
+ * returns:		errno value
+ * arguments:
+ *	tag		the tag providing the constraints.
+ *	flags		flags that control the behaviour of the operation.
+ *	mem_p		address in which to return the memory descriptor.
+ */
+int busdma_mem_alloc(busdma_tag_t tag, u_int flags, busdma_mem_t *mem_p);
+
 #endif /* _SYS_BUSDMA_H_ */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201205070528.q475SnFE048222>