From 757d4fbaa75df6193ccd19e475f7b581081d5291 Mon Sep 17 00:00:00 2001 From: Scott Long Date: Tue, 24 Dec 2019 14:48:46 +0000 Subject: [PATCH] Introduce the concept of busdma tag templates. A template can be allocated off the stack, initialized to default values, and then filled in with driver-specific values, all without having to worry about the numerous other fields in the tag. The resulting template is then passed into busdma and the normal opaque tag object created. See the man page for details on how to initialize a template. Templates do not support tag filters. Filters have been broken for many years, and only existed for an ancient make/model of hardware that had a quirky DMA engine. Instead of breaking the ABI/API and changing the arugment signature of bus_dma_tag_create() to remove the filter arguments, templates allow us to ignore them, and also significantly reduce the complexity of creating and managing tags. Reviewed by: imp, kib Differential Revision: https://reviews.freebsd.org/D22906 --- share/man/man9/bus_dma.9 | 65 ++++++++++++++++++++++++++++ sys/arm/arm/busdma_machdep-v4.c | 51 ++++++++++++++++++++++ sys/arm/arm/busdma_machdep-v6.c | 51 ++++++++++++++++++++++ sys/arm64/arm64/busdma_machdep.c | 54 +++++++++++++++++++++++ sys/mips/mips/busdma_machdep.c | 51 ++++++++++++++++++++++ sys/powerpc/powerpc/busdma_machdep.c | 51 ++++++++++++++++++++++ sys/riscv/riscv/busdma_machdep.c | 54 +++++++++++++++++++++++ sys/sparc64/sparc64/bus_machdep.c | 51 ++++++++++++++++++++++ sys/sys/bus_dma.h | 18 ++++++++ sys/x86/x86/busdma_machdep.c | 54 +++++++++++++++++++++++ 10 files changed, 500 insertions(+) diff --git a/share/man/man9/bus_dma.9 b/share/man/man9/bus_dma.9 index dd6fd2233a5..e72c57dc735 100644 --- a/share/man/man9/bus_dma.9 +++ b/share/man/man9/bus_dma.9 @@ -60,6 +60,9 @@ .Nm bus_dma , .Nm bus_dma_tag_create , .Nm bus_dma_tag_destroy , +.Nm bus_dma_template_init , +.Nm bus_dma_template_tag , +.Nm bus_dma_template_clone , .Nm bus_dmamap_create , .Nm bus_dmamap_destroy , .Nm bus_dmamap_load , @@ -83,6 +86,21 @@ "void *lockfuncarg" "bus_dma_tag_t *dmat" .Ft int .Fn bus_dma_tag_destroy "bus_dma_tag_t dmat" +.Ft void +.Fo bus_dma_template_init +.Fa "bus_dma_template_t template" +.Fa "bus_dma_tag_t parent" +.Fc +.Ft int +.Fo bus_dma_template_tag +.Fa "bus_dma_template_t template" +.Fa "bus_dma_tag_t *dmat" +.Fc +.Ft void +.Fo bus_dma_template_clone +.Fa "bus_dma_template_t template" +.Fa "bus_dma_tag_t dmat" +.Fc .Ft int .Fn bus_dmamap_create "bus_dma_tag_t dmat" "int flags" "bus_dmamap_t *mapp" .Ft int @@ -282,6 +300,34 @@ DMA tags are organized into a hierarchy, with each child tag inheriting the restrictions of its parent. This allows all devices along the path of DMA transactions to contribute to the constraints of those transactions. +.It Vt bus_dma_template_t +A template structure for creating a +.Fa bus_dma_tag_t +from a set of defaults. +Once initialized with +.Fn bus_dma_template_init , +a driver can over-ride individual fields to suit its needs. +The following fields have the indicated values: +.Bd -literal + alignment 1 + boundary 0 + lowaddr BUS_SPACE_MAXADDR + highaddr BUS_SPACE_MAXADDR + maxsize BUS_SPACE_MAXSIZE + nsegments BUS_SPACE_UNRESTRICTED + maxsegsize BUS_SPACE_MAXSIZE + flags 0 + lockfunc NULL + lockfuncarg NULL +.Ed +.Pp +Descriptions of each field are documented with +.Fn bus_dma_tag_create . +Note that the +.Fa filtfunc +and +.Fa filtfuncarg +attributes of the DMA tag are not supported with templates. .It Vt bus_dma_filter_t Client specified address filter having the format: .Bl -tag -width indent @@ -633,6 +679,25 @@ if any DMA maps remain associated with or .Ql 0 on success. +.It Fn bus_dma_template_init "*template" "parent" +Initializes a +.Fa bus_dma_template_t +structure and associates it with an optional +.Fa parent . +The +.Fa parent +argument may be NULL. +.It Fn bus_dma_template_tag "*template" "*dmat" +Unpacks a template into a tag, and returns the tag via the +.Fa dmat . +All return values are identical to +.Fn bus_dma_tag_create . +.It Fn bus_dma_template_clone "*template" "dmat" +Clones the fields from a tag to a template. +This is useful for cloning tags when paired with +.Fn bus_dma_template_tag . +A template that is filled in as a clone does not need to be initialized +first. .It Fn bus_dmamap_create "dmat" "flags" "*mapp" Allocates and initializes a DMA map. Arguments are as follows: diff --git a/sys/arm/arm/busdma_machdep-v4.c b/sys/arm/arm/busdma_machdep-v4.c index 649ce05fdb3..6c1fd6a9e99 100644 --- a/sys/arm/arm/busdma_machdep-v4.c +++ b/sys/arm/arm/busdma_machdep-v4.c @@ -501,6 +501,57 @@ bus_dma_tag_create(bus_dma_tag_t parent, bus_size_t alignment, return (error); } +void +bus_dma_template_init(bus_dma_tag_template_t *t, bus_dma_tag_t parent) +{ + + if (t == NULL) + return; + + t->parent = parent; + t->alignment = 1; + t->boundary = 0; + t->lowaddr = t->highaddr = BUS_SPACE_MAXADDR; + t->maxsize = t->maxsegsize = BUS_SPACE_MAXSIZE; + t->nsegments = BUS_SPACE_UNRESTRICTED; + t->lockfunc = NULL; + t->lockfuncarg = NULL; + t->flags = 0; +} + +int +bus_dma_template_tag(bus_dma_tag_template_t *t, bus_dma_tag_t *dmat) +{ + + if (t == NULL || dmat == NULL) + return (EINVAL); + + return (bus_dma_tag_create(t->parent, t->alignment, t->boundary, + t->lowaddr, t->highaddr, NULL, NULL, t->maxsize, + t->nsegments, t->maxsegsize, t->flags, t->lockfunc, t->lockfuncarg, + dmat)); +} + +void +bus_dma_template_clone(bus_dma_tag_template_t *t, bus_dma_tag_t dmat) +{ + + if (t == NULL || dmat == NULL) + return; + + t->parent = dmat->parent; + t->alignment = dmat->alignment; + t->boundary = dmat->boundary; + t->lowaddr = dmat->lowaddr; + t->highaddr = dmat->highaddr; + t->maxsize = dmat->maxsize; + t->nsegments = dmat->nsegments; + t->maxsegsize = dmat->maxsegsz; + t->flags = dmat->flags; + t->lockfunc = dmat->lockfunc; + t->lockfuncarg = dmat->lockfuncarg; +} + int bus_dma_tag_set_domain(bus_dma_tag_t dmat, int domain) { diff --git a/sys/arm/arm/busdma_machdep-v6.c b/sys/arm/arm/busdma_machdep-v6.c index fa79b1d913d..6e2fb4a0d8f 100644 --- a/sys/arm/arm/busdma_machdep-v6.c +++ b/sys/arm/arm/busdma_machdep-v6.c @@ -575,6 +575,57 @@ bus_dma_tag_create(bus_dma_tag_t parent, bus_size_t alignment, return (error); } +void +bus_dma_template_init(bus_dma_tag_template_t *t, bus_dma_tag_t parent) +{ + + if (t == NULL) + return; + + t->parent = parent; + t->alignment = 1; + t->boundary = 0; + t->lowaddr = t->highaddr = BUS_SPACE_MAXADDR; + t->maxsize = t->maxsegsize = BUS_SPACE_MAXSIZE; + t->nsegments = BUS_SPACE_UNRESTRICTED; + t->lockfunc = NULL; + t->lockfuncarg = NULL; + t->flags = 0; +} + +int +bus_dma_template_tag(bus_dma_tag_template_t *t, bus_dma_tag_t *dmat) +{ + + if (t == NULL || dmat == NULL) + return (EINVAL); + + return (bus_dma_tag_create(t->parent, t->alignment, t->boundary, + t->lowaddr, t->highaddr, NULL, NULL, t->maxsize, + t->nsegments, t->maxsegsize, t->flags, t->lockfunc, t->lockfuncarg, + dmat)); +} + +void +bus_dma_template_clone(bus_dma_tag_template_t *t, bus_dma_tag_t dmat) +{ + + if (t == NULL || dmat == NULL) + return; + + t->parent = dmat->parent; + t->alignment = dmat->alignment; + t->boundary = dmat->boundary; + t->lowaddr = dmat->lowaddr; + t->highaddr = dmat->highaddr; + t->maxsize = dmat->maxsize; + t->nsegments = dmat->nsegments; + t->maxsegsize = dmat->maxsegsz; + t->flags = dmat->flags; + t->lockfunc = dmat->lockfunc; + t->lockfuncarg = dmat->lockfuncarg; +} + int bus_dma_tag_set_domain(bus_dma_tag_t dmat, int domain) { diff --git a/sys/arm64/arm64/busdma_machdep.c b/sys/arm64/arm64/busdma_machdep.c index 6abd213ccc9..1a5ac67a2a4 100644 --- a/sys/arm64/arm64/busdma_machdep.c +++ b/sys/arm64/arm64/busdma_machdep.c @@ -214,6 +214,60 @@ bus_dma_tag_create(bus_dma_tag_t parent, bus_size_t alignment, return (error); } +void +bus_dma_template_init(bus_dma_tag_template_t *t, bus_dma_tag_t parent) +{ + + if (t == NULL) + return; + + t->parent = parent; + t->alignment = 1; + t->boundary = 0; + t->lowaddr = t->highaddr = BUS_SPACE_MAXADDR; + t->maxsize = t->maxsegsize = BUS_SPACE_MAXSIZE; + t->nsegments = BUS_SPACE_UNRESTRICTED; + t->lockfunc = NULL; + t->lockfuncarg = NULL; + t->flags = 0; +} + +int +bus_dma_template_tag(bus_dma_tag_template_t *t, bus_dma_tag_t *dmat) +{ + + if (t == NULL || dmat == NULL) + return (EINVAL); + + return (bus_dma_tag_create(t->parent, t->alignment, t->boundary, + t->lowaddr, t->highaddr, NULL, NULL, t->maxsize, + t->nsegments, t->maxsegsize, t->flags, t->lockfunc, t->lockfuncarg, + dmat)); +} + +void +bus_dma_template_clone(bus_dma_tag_template_t *t, bus_dma_tag_t dmat) +{ + struct bus_dma_tag_common *common; + + if (t == NULL || dmat == NULL) + return; + + common = (struct bus_dma_tag_common *)dmat; + + t->parent = (bus_dma_tag_t)common->parent; + t->alignment = common->alignment; + t->boundary = common->boundary; + t->lowaddr = common->lowaddr; + t->highaddr = common->highaddr; + t->maxsize = common->maxsize; + t->nsegments = common->nsegments; + t->maxsegsize = common->maxsegsz; + t->flags = common->flags; + t->lockfunc = common->lockfunc; + t->lockfuncarg = common->lockfuncarg; +} + int bus_dma_tag_destroy(bus_dma_tag_t dmat) { diff --git a/sys/mips/mips/busdma_machdep.c b/sys/mips/mips/busdma_machdep.c index 94c3eb8f5d3..ca7816d1295 100644 --- a/sys/mips/mips/busdma_machdep.c +++ b/sys/mips/mips/busdma_machdep.c @@ -476,6 +476,57 @@ bus_dma_tag_create(bus_dma_tag_t parent, bus_size_t alignment, return (error); } +void +bus_dma_template_init(bus_dma_tag_template_t *t, bus_dma_tag_t parent) +{ + + if (t == NULL) + return; + + t->parent = parent; + t->alignment = 1; + t->boundary = 0; + t->lowaddr = t->highaddr = BUS_SPACE_MAXADDR; + t->maxsize = t->maxsegsize = BUS_SPACE_MAXSIZE; + t->nsegments = BUS_SPACE_UNRESTRICTED; + t->lockfunc = NULL; + t->lockfuncarg = NULL; + t->flags = 0; +} + +int +bus_dma_template_tag(bus_dma_tag_template_t *t, bus_dma_tag_t *dmat) +{ + + if (t == NULL || dmat == NULL) + return (EINVAL); + + return (bus_dma_tag_create(t->parent, t->alignment, t->boundary, + t->lowaddr, t->highaddr, NULL, NULL, t->maxsize, + t->nsegments, t->maxsegsize, t->flags, t->lockfunc, t->lockfuncarg, + dmat)); +} + +void +bus_dma_template_clone(bus_dma_tag_template_t *t, bus_dma_tag_t dmat) +{ + + if (t == NULL || dmat == NULL) + return; + + t->parent = dmat->parent; + t->alignment = dmat->alignment; + t->boundary = dmat->boundary; + t->lowaddr = dmat->lowaddr; + t->highaddr = dmat->highaddr; + t->maxsize = dmat->maxsize; + t->nsegments = dmat->nsegments; + t->maxsegsize = dmat->maxsegsz; + t->flags = dmat->flags; + t->lockfunc = dmat->lockfunc; + t->lockfuncarg = dmat->lockfuncarg; +} + int bus_dma_tag_set_domain(bus_dma_tag_t dmat, int domain) { diff --git a/sys/powerpc/powerpc/busdma_machdep.c b/sys/powerpc/powerpc/busdma_machdep.c index 46fffad5712..43196bc2eb2 100644 --- a/sys/powerpc/powerpc/busdma_machdep.c +++ b/sys/powerpc/powerpc/busdma_machdep.c @@ -340,6 +340,57 @@ bus_dma_tag_create(bus_dma_tag_t parent, bus_size_t alignment, return (error); } +void +bus_dma_template_init(bus_dma_tag_template_t *t, bus_dma_tag_t parent) +{ + + if (t == NULL) + return; + + t->parent = parent; + t->alignment = 1; + t->boundary = 0; + t->lowaddr = t->highaddr = BUS_SPACE_MAXADDR; + t->maxsize = t->maxsegsize = BUS_SPACE_MAXSIZE; + t->nsegments = BUS_SPACE_UNRESTRICTED; + t->lockfunc = NULL; + t->lockfuncarg = NULL; + t->flags = 0; +} + +int +bus_dma_template_tag(bus_dma_tag_template_t *t, bus_dma_tag_t *dmat) +{ + + if (t == NULL || dmat == NULL) + return (EINVAL); + + return (bus_dma_tag_create(t->parent, t->alignment, t->boundary, + t->lowaddr, t->highaddr, NULL, NULL, t->maxsize, + t->nsegments, t->maxsegsize, t->flags, t->lockfunc, t->lockfuncarg, + dmat)); +} + +void +bus_dma_template_clone(bus_dma_tag_template_t *t, bus_dma_tag_t dmat) +{ + + if (t == NULL || dmat == NULL) + return; + + t->parent = dmat->parent; + t->alignment = dmat->alignment; + t->boundary = dmat->boundary; + t->lowaddr = dmat->lowaddr; + t->highaddr = dmat->highaddr; + t->maxsize = dmat->maxsize; + t->nsegments = dmat->nsegments; + t->maxsegsize = dmat->maxsegsz; + t->flags = dmat->flags; + t->lockfunc = dmat->lockfunc; + t->lockfuncarg = dmat->lockfuncarg; +} + int bus_dma_tag_set_domain(bus_dma_tag_t dmat, int domain) { diff --git a/sys/riscv/riscv/busdma_machdep.c b/sys/riscv/riscv/busdma_machdep.c index 531371f5dda..dc678bc166d 100644 --- a/sys/riscv/riscv/busdma_machdep.c +++ b/sys/riscv/riscv/busdma_machdep.c @@ -214,6 +214,60 @@ bus_dma_tag_create(bus_dma_tag_t parent, bus_size_t alignment, return (error); } +void +bus_dma_template_init(bus_dma_tag_template_t *t, bus_dma_tag_t parent) +{ + + if (t == NULL) + return; + + t->parent = parent; + t->alignment = 1; + t->boundary = 0; + t->lowaddr = t->highaddr = BUS_SPACE_MAXADDR; + t->maxsize = t->maxsegsize = BUS_SPACE_MAXSIZE; + t->nsegments = BUS_SPACE_UNRESTRICTED; + t->lockfunc = NULL; + t->lockfuncarg = NULL; + t->flags = 0; +} + +int +bus_dma_template_tag(bus_dma_tag_template_t *t, bus_dma_tag_t *dmat) +{ + + if (t == NULL || dmat == NULL) + return (EINVAL); + + return (bus_dma_tag_create(t->parent, t->alignment, t->boundary, + t->lowaddr, t->highaddr, NULL, NULL, t->maxsize, + t->nsegments, t->maxsegsize, t->flags, t->lockfunc, t->lockfuncarg, + dmat)); +} + +void +bus_dma_template_clone(bus_dma_tag_template_t *t, bus_dma_tag_t dmat) +{ + struct bus_dma_tag_common *common; + + if (t == NULL || dmat == NULL) + return; + + common = (struct bus_dma_tag_common *)dmat; + + t->parent = (bus_dma_tag_t)common->parent; + t->alignment = common->alignment; + t->boundary = common->boundary; + t->lowaddr = common->lowaddr; + t->highaddr = common->highaddr; + t->maxsize = common->maxsize; + t->nsegments = common->nsegments; + t->maxsegsize = common->maxsegsz; + t->flags = common->flags; + t->lockfunc = common->lockfunc; + t->lockfuncarg = common->lockfuncarg; +} + int bus_dma_tag_destroy(bus_dma_tag_t dmat) { diff --git a/sys/sparc64/sparc64/bus_machdep.c b/sys/sparc64/sparc64/bus_machdep.c index bdc965f0acb..c887e264e2a 100644 --- a/sys/sparc64/sparc64/bus_machdep.c +++ b/sys/sparc64/sparc64/bus_machdep.c @@ -250,6 +250,57 @@ bus_dma_tag_create(bus_dma_tag_t parent, bus_size_t alignment, return (0); } +void +bus_dma_template_init(bus_dma_tag_template_t *t, bus_dma_tag_t parent) +{ + + if (t == NULL) + return; + + t->parent = parent; + t->alignment = 1; + t->boundary = 0; + t->lowaddr = t->highaddr = BUS_SPACE_MAXADDR; + t->maxsize = t->maxsegsize = BUS_SPACE_MAXSIZE; + t->nsegments = BUS_SPACE_UNRESTRICTED; + t->lockfunc = NULL; + t->lockfuncarg = NULL; + t->flags = 0; +} + +int +bus_dma_template_tag(bus_dma_tag_template_t *t, bus_dma_tag_t *dmat) +{ + + if (t == NULL || dmat == NULL) + return (EINVAL); + + return (bus_dma_tag_create(t->parent, t->alignment, t->boundary, + t->lowaddr, t->highaddr, NULL, NULL, t->maxsize, + t->nsegments, t->maxsegsize, t->flags, t->lockfunc, t->lockfuncarg, + dmat)); +} + +void +bus_dma_template_clone(bus_dma_tag_template_t *t, bus_dma_tag_t dmat) +{ + + if (t == NULL || dmat == NULL) + return; + + t->parent = dmat->dt_parent; + t->alignment = dmat->dt_alignment; + t->boundary = dmat->dt_boundary; + t->lowaddr = dmat->dt_lowaddr; + t->highaddr = dmat->dt_highaddr; + t->maxsize = dmat->dt_maxsize; + t->nsegments = dmat->dt_nsegments; + t->maxsegsize = dmat->dt_maxsegsz; + t->flags = dmat->dt_flags; + t->lockfunc = dmat->dt_lockfunc; + t->lockfuncarg = dmat->dt_lockfuncarg; +} + int bus_dma_tag_destroy(bus_dma_tag_t dmat) { diff --git a/sys/sys/bus_dma.h b/sys/sys/bus_dma.h index e99d8ecebe1..f70a8bb2b9a 100644 --- a/sys/sys/bus_dma.h +++ b/sys/sys/bus_dma.h @@ -179,6 +179,24 @@ int bus_dma_tag_create(bus_dma_tag_t parent, bus_size_t alignment, bus_size_t maxsegsz, int flags, bus_dma_lock_t *lockfunc, void *lockfuncarg, bus_dma_tag_t *dmat); +/* Functions for creating and cloning tags via a template */ +typedef struct { + bus_dma_tag_t parent; + bus_size_t alignment; + bus_addr_t boundary; + bus_addr_t lowaddr; + bus_addr_t highaddr; + bus_size_t maxsize; + int nsegments; + bus_size_t maxsegsize; + int flags; + bus_dma_lock_t *lockfunc; + void *lockfuncarg; +} bus_dma_tag_template_t; +void bus_dma_template_init(bus_dma_tag_template_t *t, bus_dma_tag_t parent); +int bus_dma_template_tag(bus_dma_tag_template_t *t, bus_dma_tag_t *dmat); +void bus_dma_template_clone(bus_dma_tag_template_t *t, bus_dma_tag_t dmat); + /* * Set the memory domain to be used for allocations. * diff --git a/sys/x86/x86/busdma_machdep.c b/sys/x86/x86/busdma_machdep.c index 152fec59141..36c8d1f7831 100644 --- a/sys/x86/x86/busdma_machdep.c +++ b/sys/x86/x86/busdma_machdep.c @@ -238,6 +238,60 @@ bus_dma_tag_create(bus_dma_tag_t parent, bus_size_t alignment, return (error); } +void +bus_dma_template_init(bus_dma_tag_template_t *t, bus_dma_tag_t parent) +{ + + if (t == NULL) + return; + + t->parent = parent; + t->alignment = 1; + t->boundary = 0; + t->lowaddr = t->highaddr = BUS_SPACE_MAXADDR; + t->maxsize = t->maxsegsize = BUS_SPACE_MAXSIZE; + t->nsegments = BUS_SPACE_UNRESTRICTED; + t->lockfunc = NULL; + t->lockfuncarg = NULL; + t->flags = 0; +} + +int +bus_dma_template_tag(bus_dma_tag_template_t *t, bus_dma_tag_t *dmat) +{ + + if (t == NULL || dmat == NULL) + return (EINVAL); + + return (bus_dma_tag_create(t->parent, t->alignment, t->boundary, + t->lowaddr, t->highaddr, NULL, NULL, t->maxsize, + t->nsegments, t->maxsegsize, t->flags, t->lockfunc, t->lockfuncarg, + dmat)); +} + +void +bus_dma_template_clone(bus_dma_tag_template_t *t, bus_dma_tag_t dmat) +{ + struct bus_dma_tag_common *common; + + if (t == NULL || dmat == NULL) + return; + + common = (struct bus_dma_tag_common *)dmat; + + t->parent = (bus_dma_tag_t)common->parent; + t->alignment = common->alignment; + t->boundary = common->boundary; + t->lowaddr = common->lowaddr; + t->highaddr = common->highaddr; + t->maxsize = common->maxsize; + t->nsegments = common->nsegments; + t->maxsegsize = common->maxsegsz; + t->flags = common->flags; + t->lockfunc = common->lockfunc; + t->lockfuncarg = common->lockfuncarg; +} + int bus_dma_tag_destroy(bus_dma_tag_t dmat) {