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
This commit is contained in:
Scott Long 2019-12-24 14:48:46 +00:00
parent e30f025ff9
commit 757d4fbaa7
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=356050
10 changed files with 500 additions and 0 deletions

View File

@ -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:

View File

@ -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)
{

View File

@ -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)
{

View File

@ -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)
{

View File

@ -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)
{

View File

@ -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)
{

View File

@ -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)
{

View File

@ -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)
{

View File

@ -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.
*

View File

@ -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)
{