svn commit: r237932 - projects/altix2/sys/kern
Marcel Moolenaar
marcel at FreeBSD.org
Sun Jul 1 17:06:22 UTC 2012
Author: marcel
Date: Sun Jul 1 17:06:21 2012
New Revision: 237932
URL: http://svn.freebsd.org/changeset/base/237932
Log:
Dump a milestone: we see disks on the SCSI bus with isp(4) using
the new busdma/mi implementation:
1. Implement load_linear using a common support function. The support
function takes a pmap_t, virtual address and length and extends the
last segment or appends new segments to the memory descriptor.
2. Implement unload as well now that we're getting too functional not
to have it implemented.
3. Comment-out dump routines and other debugging printfs. It's time now
to use KTR or other means to have the ability present without it
interfering with normal operation.
4. Add a first-line of pretection: check arguments and return EINVAL
when we're displeased with what;s given to us. Note that for the
load_* functions we need a good definition of which errors are
being returned directly and which errors are being relayed via the
callback.
Modified:
projects/altix2/sys/kern/subr_busdma.c
Modified: projects/altix2/sys/kern/subr_busdma.c
==============================================================================
--- projects/altix2/sys/kern/subr_busdma.c Sun Jul 1 16:26:07 2012 (r237931)
+++ projects/altix2/sys/kern/subr_busdma.c Sun Jul 1 17:06:21 2012 (r237932)
@@ -73,7 +73,7 @@ struct busdma_md {
struct busdma_tag *md_tag;
u_int md_flags;
u_int md_nsegs;
- TAILQ_HEAD(, busdma_md_seg) md_seg;
+ TAILQ_HEAD(busdma_md_head, busdma_md_seg) md_seg;
};
#define BUSDMA_MD_FLAG_ALLOCATED 0x1 /* busdma_mem_alloc() created
@@ -156,6 +156,7 @@ SYSINIT(busdma_kmem, SI_SUB_KMEM, SI_ORD
/* Section 3.2: Debugging & tracing. */
+#if 0
static void
_busdma_mtag_dump(const char *func, device_t dev, struct busdma_mtag *mtag)
{
@@ -167,7 +168,9 @@ _busdma_mtag_dump(const char *func, devi
(uintmax_t)mtag->dmt_maxsz, (uintmax_t)mtag->dmt_align,
(uintmax_t)mtag->dmt_bndry);
}
+#endif
+#if 0
static void
_busdma_tag_dump(const char *func, device_t dev, struct busdma_tag *tag)
{
@@ -180,7 +183,9 @@ _busdma_tag_dump(const char *func, devic
(uintmax_t)tag->dt_maxsz,
tag->dt_nsegs, (uintmax_t)tag->dt_maxsegsz);
}
+#endif
+#if 0
static void
_busdma_md_dump(const char *func, device_t dev, struct busdma_md *md)
{
@@ -205,6 +210,7 @@ _busdma_md_dump(const char *func, device
}
printf("]\n");
}
+#endif
/* Section 3.3: API support functions. */
@@ -213,10 +219,14 @@ _busdma_md_get_seg(struct busdma_md *md,
{
struct busdma_md_seg *seg;
+ if (md == NULL || idx >= md->md_nsegs)
+ return (NULL);
+
TAILQ_FOREACH(seg, &md->md_seg, mds_chain) {
if (seg->mds_idx == idx)
return (seg);
}
+ /* XXX getting here means we probably have a bug... */
return (NULL);
}
@@ -247,7 +257,7 @@ _busdma_tag_get_base(device_t dev)
base = busdma_root_tag;
parent = NULL;
}
- _busdma_tag_dump(__func__, parent, base);
+ // _busdma_tag_dump(__func__, parent, base);
return (base);
}
@@ -281,7 +291,7 @@ _busdma_tag_make(device_t dev, struct bu
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);
+ // _busdma_tag_dump(__func__, dev, tag);
*tag_p = tag;
return (0);
}
@@ -313,12 +323,12 @@ _busdma_iommu_xlate(device_t leaf, struc
error = 0;
dev = device_get_parent(leaf);
while (!error && dev != root_bus) {
- _busdma_mtag_dump(__func__, dev, mtag);
+ // _busdma_mtag_dump(__func__, dev, mtag);
error = BUSDMA_IOMMU_XLATE(dev, mtag);
if (!error)
dev = device_get_parent(dev);
}
- _busdma_mtag_dump(__func__, dev, mtag);
+ // _busdma_mtag_dump(__func__, dev, mtag);
return (error);
}
@@ -351,7 +361,7 @@ _busdma_iommu_map(device_t leaf, struct
device_t dev;
int error;
- _busdma_md_dump(__func__, root_bus, md);
+ // _busdma_md_dump(__func__, root_bus, md);
dev = device_get_parent(leaf);
error = 0;
TAILQ_FOREACH(seg, &md->md_seg, mds_chain) {
@@ -359,11 +369,62 @@ _busdma_iommu_map(device_t leaf, struct
if (error)
break;
}
- if (!error)
- _busdma_md_dump(__func__, leaf, md);
+ if (!error) {
+ // _busdma_md_dump(__func__, leaf, md);
+ }
return (error);
}
+static int
+_busdma_md_load(struct busdma_md *md, pmap_t pm, vm_offset_t va, vm_size_t len)
+{
+ struct busdma_md_seg *seg;
+ vm_paddr_t pa;
+ vm_size_t catsz, maxsegsz, pgsz, sz;
+ u_int idx;
+
+ maxsegsz = md->md_tag->dt_maxsegsz;
+ seg = TAILQ_LAST(&md->md_seg, busdma_md_head);
+ idx = (seg != NULL) ? seg->mds_idx + 1 : 0;
+ while (len != 0) {
+ pa = (pm != NULL) ? pmap_extract(pm, va) : pmap_kextract(va);
+ pgsz = PAGE_SIZE - (va & PAGE_MASK);
+ sz = MIN(len, maxsegsz);
+ sz = MIN(pgsz, sz);
+ if (seg != NULL && seg->mds_size < maxsegsz &&
+ seg->mds_paddr + seg->mds_size == pa) {
+ catsz = maxsegsz - seg->mds_size;
+ catsz = MIN(sz, catsz);
+ seg->mds_size += catsz;
+ pa += catsz;
+ sz -= catsz;
+ va += catsz;
+ }
+
+ if (sz == 0)
+ continue;
+
+ /*
+ * The remaining sz bytes go in a new segment.
+ */
+ seg = uma_zalloc(busdma_md_seg_zone, M_NOWAIT);
+ if (seg == NULL)
+ return (ENOMEM);
+ seg->mds_idx = idx++;
+ TAILQ_INSERT_TAIL(&md->md_seg, seg, mds_chain);
+ md->md_nsegs++;
+ seg->mds_busaddr = ~0U;
+ seg->mds_paddr = pa;
+ seg->mds_vaddr = 0;
+ seg->mds_size = sz;
+ len -= sz;
+ va += sz;
+ }
+
+ // _busdma_md_dump(__func__, NULL, md);
+ return (0);
+}
+
/*
* Section 4: Public interface.
*/
@@ -376,6 +437,9 @@ busdma_tag_create(device_t dev, bus_addr
struct busdma_tag *base, *first, *tag;
int error;
+ if (dev == NULL || tag_p == NULL)
+ return (EINVAL);
+
base = _busdma_tag_get_base(dev);
error = _busdma_tag_make(dev, base, align, bndry, maxaddr, maxsz,
nsegs, maxsegsz, flags, &tag);
@@ -399,6 +463,9 @@ busdma_tag_derive(struct busdma_tag *bas
struct busdma_tag *tag;
int error;
+ if (base == NULL || tag_p == NULL)
+ return (EINVAL);
+
error = _busdma_tag_make(base->dt_device, base, align, bndry, maxaddr,
maxsz, nsegs, maxsegsz, flags, &tag);
if (error != 0)
@@ -418,6 +485,10 @@ int
busdma_tag_destroy(struct busdma_tag *tag)
{
+ if (tag == NULL)
+ return (EINVAL);
+
+ /* TODO */
return (0);
}
@@ -426,11 +497,14 @@ busdma_md_create(struct busdma_tag *tag,
{
struct busdma_md *md;
+ if (tag == NULL || md_p == NULL)
+ return (EINVAL);
+
md = _busdma_md_create(tag, 0);
if (md == NULL)
return (ENOMEM);
- _busdma_md_dump(__func__, NULL, md);
+ // _busdma_md_dump(__func__, NULL, md);
*md_p = md;
return (0);
}
@@ -439,6 +513,8 @@ int
busdma_md_destroy(struct busdma_md *md)
{
+ if (md == NULL)
+ return (EINVAL);
if ((md->md_flags & BUSDMA_MD_FLAG_ALLOCATED) != 0)
return (EINVAL);
if (md->md_nsegs > 0)
@@ -462,7 +538,7 @@ u_int
busdma_md_get_nsegs(struct busdma_md *md)
{
- return (md->md_nsegs);
+ return ((md != NULL) ? md->md_nsegs : 0);
}
vm_paddr_t
@@ -496,10 +572,21 @@ int
busdma_md_load_linear(struct busdma_md *md, void *buf, size_t len,
busdma_callback_f cb, void *arg, u_int flags)
{
+ int error;
- printf("XXX: %s: md=%p, buf=%p, len=%lx\n", __func__, md,
- buf, (u_long)len);
- (*cb)(arg, md, ENOSYS);
+ // printf("XXX: %s: md=%p, buf=%p, len=%lx\n", __func__, md,
+ // buf, (u_long)len);
+
+ if (md == NULL || buf == NULL || len == 0)
+ return (EINVAL);
+
+ error = _busdma_md_load(md, NULL, (uintptr_t)buf, len);
+ if (!error) {
+ error = _busdma_iommu_map(md->md_tag->dt_device, md);
+ if (error)
+ printf("_busdma_iommu_map: error=%d\n", error);
+ }
+ (*cb)(arg, md, error);
return (0);
}
@@ -508,8 +595,8 @@ busdma_md_load_phys(struct busdma_md *md
busdma_callback_f cb, void *arg, u_int flags)
{
- printf("XXX: %s: md=%p, buf=%#jx, len=%lx\n", __func__, md,
- (uintmax_t)buf, (u_long)len);
+ // printf("XXX: %s: md=%p, buf=%#jx, len=%lx\n", __func__, md,
+ // (uintmax_t)buf, (u_long)len);
(*cb)(arg, md, ENOSYS);
return (0);
}
@@ -519,7 +606,7 @@ busdma_md_load_uio(struct busdma_md *md,
busdma_callback_f cb, void *arg, u_int flags)
{
- printf("XXX: %s: md=%p, uio=%p\n", __func__, md, uio);
+ // printf("XXX: %s: md=%p, uio=%p\n", __func__, md, uio);
(*cb)(arg, md, ENOSYS);
return (0);
}
@@ -527,8 +614,32 @@ busdma_md_load_uio(struct busdma_md *md,
int
busdma_md_unload(struct busdma_md *md)
{
+ struct busdma_md_seg *seg;
+ device_t bus;
+ int error;
+
+ // printf("XXX: %s: md=%p\n", __func__, md);
+
+ if (md == NULL)
+ return (EINVAL);
+ if ((md->md_flags & BUSDMA_MD_FLAG_ALLOCATED) != 0)
+ return (EINVAL);
+
+ if (md->md_nsegs == 0)
+ return (0);
+
+ bus = device_get_parent(md->md_tag->dt_device);
+ error = BUSDMA_IOMMU_UNMAP(bus, md);
+ if (error)
+ printf("BUSDMA_IOMMU_UNMAP: error=%d\n", error);
+
+ while ((seg = TAILQ_FIRST(&md->md_seg)) != NULL) {
+ TAILQ_REMOVE(&md->md_seg, seg, mds_chain);
+ uma_zfree(busdma_md_seg_zone, seg);
+ }
- return (ENOSYS);
+ md->md_nsegs = 0;
+ return (0);
}
int
@@ -541,12 +652,13 @@ busdma_mem_alloc(struct busdma_tag *tag,
u_int idx;
int error;
+ if (tag == NULL || md_p == NULL)
+ return (EINVAL);
+
md = _busdma_md_create(tag, BUSDMA_MD_FLAG_ALLOCATED);
if (md == NULL)
return (ENOMEM);
- idx = 0;
-
mtag.dmt_minaddr = tag->dt_minaddr;
mtag.dmt_maxaddr = tag->dt_maxaddr;
mtag.dmt_maxsz = tag->dt_maxsegsz;
@@ -559,6 +671,7 @@ busdma_mem_alloc(struct busdma_tag *tag,
goto fail;
}
+ idx = 0;
maxsz = tag->dt_maxsz;
while (maxsz > 0 && idx < tag->dt_nsegs) {
seg = uma_zalloc(busdma_md_seg_zone, M_NOWAIT);
@@ -566,6 +679,7 @@ busdma_mem_alloc(struct busdma_tag *tag,
goto fail;
seg->mds_idx = idx;
TAILQ_INSERT_TAIL(&md->md_seg, seg, mds_chain);
+ md->md_nsegs++;
seg->mds_busaddr = ~0UL;
seg->mds_paddr = ~0UL;
seg->mds_size = MIN(maxsz, mtag.dmt_maxsz);
@@ -581,7 +695,6 @@ busdma_mem_alloc(struct busdma_tag *tag,
idx++;
}
if (maxsz == 0) {
- md->md_nsegs = idx;
error = _busdma_iommu_map(tag->dt_device, md);
if (error)
printf("_busdma_iommu_map: error=%d\n", error);
@@ -607,6 +720,8 @@ busdma_mem_free(struct busdma_md *md)
device_t bus;
int error;
+ if (md == NULL)
+ return (EINVAL);
if ((md->md_flags & BUSDMA_MD_FLAG_ALLOCATED) == 0)
return (EINVAL);
More information about the svn-src-projects
mailing list