Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 6 May 2012 18:23:19 +0000 (UTC)
From:      Marcel Moolenaar <marcel@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r235098 - in projects/altix2/sys: kern sys
Message-ID:  <201205061823.q46INJ8k025896@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: marcel
Date: Sun May  6 18:23:19 2012
New Revision: 235098
URL: http://svn.freebsd.org/changeset/base/235098

Log:
  Implement busdma_tag_create(). This uses device_get_busdma_tag() and
  device_set_busdma_tag() to obtain newbus inherited constraints and
  to link the tag to the device.
  
  Bus inheritance should be a newbus KOBJ method so that devices/busses
  can control which of their tags is to be used as a base for inheritance.
  For now, this suffices. I don't want to have busdma/mi reach too deep
  or extend too wide.

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	Sun May  6 17:31:29 2012	(r235097)
+++ projects/altix2/sys/kern/subr_busdma.c	Sun May  6 18:23:19 2012	(r235098)
@@ -32,16 +32,113 @@ __FBSDID("$FreeBSD$");
 #include <sys/kernel.h>
 #include <sys/bus.h>
 #include <sys/busdma.h>
+#include <sys/malloc.h>
+#include <machine/stdarg.h>
 
 struct busdma_tag {
+	struct busdma_tag *dt_chain;
 	device_t	dt_device;
+	bus_addr_t	dt_minaddr;
+	bus_addr_t	dt_maxaddr;
+	bus_addr_t	dt_align;
+	bus_addr_t	dt_bndry;
+	bus_size_t	dt_maxsz;
+	u_int		dt_nsegs;
+	bus_size_t	dt_maxsegsz;
 };
 
+static struct busdma_tag busdma_root_tag = {
+	.dt_maxaddr = ~0UL,
+	.dt_align = 1,
+	.dt_maxsz = ~0UL,
+	.dt_nsegs = ~0U,
+	.dt_maxsegsz = ~0UL,
+};
+
+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)
+{
+
+	printf("[%s: %s: tag=%p (minaddr=%jx, maxaddr=%jx, align=%jx, "
+	    "bndry=%jx, maxsz=%jx, nsegs=%u, maxsegsz=%jx)]\n",
+	    func, (dev != NULL) ? device_get_nameunit(dev) : "*", tag,
+	    (uintmax_t)tag->dt_minaddr, (uintmax_t)tag->dt_maxaddr,
+	    (uintmax_t)tag->dt_align, (uintmax_t)tag->dt_bndry,
+	    (uintmax_t)tag->dt_maxsz,
+	    tag->dt_nsegs, (uintmax_t)tag->dt_maxsegsz);
+}
+
+static busdma_tag_t
+_busdma_tag_get_base(device_t dev)
+{
+	device_t parent;
+	void *base;
+
+	base = NULL;
+	parent = device_get_parent(dev);
+	while (base == NULL && parent != NULL) {
+		base = device_get_busdma_tag(parent);
+		if (base == NULL)
+			parent = device_get_parent(parent);
+	}
+	if (base == NULL) {
+		base = &busdma_root_tag;
+		parent = NULL;
+	}
+	_busdma_tag_dump(__func__, parent, base);
+	return (base);
+}
+
+static int
+_busdma_tag_make(device_t dev, busdma_tag_t base, bus_addr_t maxaddr,
+    bus_addr_t align, bus_addr_t bndry, bus_addr_t maxsz, u_int nsegs,
+    bus_size_t maxsegsz, u_int flags, busdma_tag_t *tag_p)
+{
+	busdma_tag_t tag;
+
+	/*
+	 * If nsegs is 1, ignore maxsegsz. What this means is that if we have
+	 * just 1 segment, then maxsz should be equal to maxsegsz. Make it so.
+	 */
+	if (nsegs == 1)
+		maxsegsz = maxsz;
+
+	tag = (busdma_tag_t)malloc(sizeof(*tag), M_BUSDMA_TAG,
+	    M_WAITOK | M_ZERO);
+	tag->dt_device = dev;
+	tag->dt_minaddr = MAX(0, base->dt_minaddr);
+	tag->dt_maxaddr = MIN(maxaddr, base->dt_maxaddr);
+	tag->dt_align = MAX(align, base->dt_align);
+	tag->dt_bndry = MIN(bndry, base->dt_bndry);
+	tag->dt_maxsz = MIN(maxsz, base->dt_maxsz);
+	tag->dt_nsegs = MIN(nsegs, base->dt_nsegs);
+	tag->dt_maxsegsz = MIN(maxsegsz, base->dt_maxsegsz);
+	_busdma_tag_dump(__func__, dev, tag);
+	*tag_p = tag;
+	return (0);
+}
+
 int
-busdma_tag_create(device_t device, struct resource *res, bus_addr_t maxaddr,
-    bus_addr_t align, bus_addr_t bndry, u_int nsegs, bus_size_t maxsegsz,
+busdma_tag_create(device_t dev, bus_addr_t maxaddr, bus_addr_t align,
+    bus_addr_t bndry, bus_addr_t maxsz, u_int nsegs, bus_size_t maxsegsz,
     u_int flags, busdma_tag_t *tag_p)
 {
+	busdma_tag_t base, first, tag;
+	int error;
+
+	base = _busdma_tag_get_base(dev);
+	error = _busdma_tag_make(dev, base, maxaddr, align, bndry, maxsz,
+	    nsegs, maxsegsz, flags, &tag);
+	if (error != 0)
+		return (error);
 
-	return (ENOSYS);
+	/*
+	 * This is a root tag. Link it with the device.
+	 */
+	first = device_set_busdma_tag(dev, tag);
+	tag->dt_chain = first;
+	*tag_p = tag;
+	return (0);
 }

Modified: projects/altix2/sys/sys/busdma.h
==============================================================================
--- projects/altix2/sys/sys/busdma.h	Sun May  6 17:31:29 2012	(r235097)
+++ projects/altix2/sys/sys/busdma.h	Sun May  6 18:23:19 2012	(r235098)
@@ -34,7 +34,22 @@
 struct busdma_tag;
 typedef struct busdma_tag *busdma_tag_t;
 
-int busdma_tag_create(device_t, struct resource *, bus_addr_t, bus_addr_t,
-    bus_addr_t, u_int, bus_size_t, u_int, busdma_tag_t *);
+/*
+ * busdma_tag_create
+ * returns:		errno value
+ * arguments:
+ *	dev		device for which the created tag is a root tag.
+ *	maxaddr		largest address that can be handled by the device.
+ *	align		alignment requirements of the DMA segments.
+ *	bndry		address boundary constraints for DMA.
+ *	maxsz		maximum total DMA size allowed.
+ *	nsegs		maximum number of DMA segments allowed.
+ *	maxsegsz	maximum size of a single DMA segment.
+ *	flags		flags that control the behaviour of the operation.
+ *	tag_p		address in which to return the newly created tag.
+ */
+int busdma_tag_create(device_t dev, bus_addr_t maxaddr, bus_addr_t align,
+    bus_addr_t bndry, bus_addr_t maxsz, u_int nsegs, bus_size_t maxsegsz,
+    u_int flags, busdma_tag_t *tag_p);
 
 #endif /* _SYS_BUSDMA_H_ */



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