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>