svn commit: r235098 - in projects/altix2/sys: kern sys
Marcel Moolenaar
marcel at FreeBSD.org
Sun May 6 18:23:20 UTC 2012
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_ */
More information about the svn-src-projects
mailing list