dmover(9) -- an interface to hardware-assisted data movers. This allows

clients to use a hardware-assisted data mover to clear a region of memory,
fill a region of memory with a specific value, copy a region of memory,
and perform simple boolean operations such as XOR on multiple regions
of memory.

Included here is a software back-end which can serve as an example of
how to write a back-end (and also provides a fall-back in case hardware
for a given function is not available), as well as a dmoverio(4) pseudo-
device which provides access to dmover(9) to userland via a message
passing interface.

dmover(9) is still a work-in-progress -- a few minor changes to the
interface are expected.
This commit is contained in:
thorpej 2002-08-02 00:30:37 +00:00
parent bf72c7334c
commit 5d06c0e812
11 changed files with 2331 additions and 0 deletions

9
sys/dev/dmover/Makefile Normal file
View File

@ -0,0 +1,9 @@
# $NetBSD: Makefile,v 1.1 2002/08/02 00:30:37 thorpej Exp $
KDIR= /sys/dev/dmover
INCSDIR= /usr/include/dev/dmover
# Only install includes which are used by userland
INCS= dmover_io.h
.include <bsd.kinc.mk>

View File

@ -0,0 +1,269 @@
/* $NetBSD: dmover_backend.c,v 1.1 2002/08/02 00:30:38 thorpej Exp $ */
/*
* Copyright (c) 2002 Wasabi Systems, Inc.
* All rights reserved.
*
* Written by Jason R. Thorpe for Wasabi Systems, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed for the NetBSD Project by
* Wasabi Systems, Inc.
* 4. The name of Wasabi Systems, Inc. may not be used to endorse
* or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* dmover_backend.c: Backend management functions for dmover-api.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD");
#include <sys/param.h>
#include <sys/lock.h>
#include <sys/systm.h>
#include <dev/dmover/dmovervar.h>
TAILQ_HEAD(, dmover_backend) dmover_backend_list;
struct lock dmover_backend_list_lock;
#define BACKEND_LIST_LOCK_READ() \
do { \
(void) spinlockmgr(&dmover_backend_list_lock, LK_SHRED, NULL); \
} while (/*CONSTCOND*/0)
#define BACKEND_LIST_UNLOCK_READ() \
do { \
(void) spinlockmgr(&dmover_backend_list_lock, LK_RELEASE, NULL);\
} while (/*CONSTCOND*/0)
#define BACKEND_LIST_LOCK_WRITE(s) \
do { \
(s) = splbio(); \
(void) spinlockmgr(&dmover_backend_list_lock, LK_EXCLUSIVE, NULL); \
} while (/*CONSTCOND*/0)
#define BACKEND_LIST_UNLOCK_WRITE(s) \
do { \
(void) spinlockmgr(&dmover_backend_list_lock, LK_RELEASE, NULL);\
splx((s)); \
} while (/*CONSTCOND*/0)
static int initialized;
static struct simplelock initialized_slock = SIMPLELOCK_INITIALIZER;
static void
initialize(void)
{
simple_lock(&initialized_slock);
if (__predict_true(initialized == 0)) {
TAILQ_INIT(&dmover_backend_list);
spinlockinit(&dmover_backend_list_lock, "dmbelk", 0);
/* Initialize the other bits of dmover. */
dmover_session_initialize();
dmover_request_initialize();
dmover_process_initialize();
initialized = 1;
}
simple_unlock(&initialized_slock);
}
/*
* dmover_backend_register: [back-end interface function]
*
* Register a back-end with dmover-api.
*/
void
dmover_backend_register(struct dmover_backend *dmb)
{
int s;
if (__predict_false(initialized == 0))
initialize();
LIST_INIT(&dmb->dmb_sessions);
dmb->dmb_nsessions = 0;
TAILQ_INIT(&dmb->dmb_pendreqs);
dmb->dmb_npendreqs = 0;
BACKEND_LIST_LOCK_WRITE(s);
TAILQ_INSERT_TAIL(&dmover_backend_list, dmb, dmb_list);
BACKEND_LIST_UNLOCK_WRITE(s);
}
/*
* dmover_backend_unregister: [back-end interface function]
*
* Un-register a back-end from dmover-api.
*/
void
dmover_backend_unregister(struct dmover_backend *dmb)
{
int s;
#ifdef DIAGNOSTIC
if (__predict_false(initialized == 0)) {
int croak;
simple_lock(&initialized_slock);
croak = (initialized == 0);
simple_unlock(&initialized_slock);
if (croak)
panic("dmover_backend_unregister: not initialized");
}
#endif
/* XXX */
if (dmb->dmb_nsessions)
panic("dmover_backend_unregister");
BACKEND_LIST_LOCK_WRITE(s);
TAILQ_REMOVE(&dmover_backend_list, dmb, dmb_list);
BACKEND_LIST_UNLOCK_WRITE(s);
}
/*
* dmover_backend_alloc:
*
* Allocate and return a back-end on behalf of a session.
*/
int
dmover_backend_alloc(struct dmover_session *dses, const char *type)
{
struct dmover_backend *dmb, *best_dmb = NULL;
const struct dmover_algdesc *algdesc, *best_algdesc = NULL;
if (__predict_false(initialized == 0)) {
int fail;
simple_lock(&initialized_slock);
fail = (initialized == 0);
simple_unlock(&initialized_slock);
if (fail)
return (ESRCH);
}
BACKEND_LIST_LOCK_READ();
/* First, find a back-end that can handle the session parts. */
for (dmb = TAILQ_FIRST(&dmover_backend_list); dmb != NULL;
dmb = TAILQ_NEXT(dmb, dmb_list)) {
/*
* First, check to see if the back-end supports the
* function we wish to perform.
*/
algdesc = dmover_algdesc_lookup(dmb->dmb_algdescs,
dmb->dmb_nalgdescs, type);
if (algdesc == NULL)
continue;
if (best_dmb == NULL) {
best_dmb = dmb;
best_algdesc = algdesc;
continue;
}
/*
* XXX All the stuff from here on should be shot in
* XXX the head. Instead, we should build a list
* XXX of candidates, and select the best back-end
* XXX when a request is scheduled for processing.
*/
if (dmb->dmb_speed >= best_dmb->dmb_speed) {
/*
* If the current best match is slower than
* this back-end, then this one is the new
* best match.
*/
if (dmb->dmb_speed > best_dmb->dmb_speed) {
best_dmb = dmb;
best_algdesc = algdesc;
continue;
}
/*
* If this back-end has fewer sessions allocated
* to it than the current best match, then this
* one is now the best match.
*/
if (best_dmb->dmb_nsessions > dmb->dmb_nsessions) {
best_dmb = dmb;
best_algdesc = algdesc;
continue;
}
}
}
if (best_dmb == NULL) {
BACKEND_LIST_UNLOCK_READ();
return (ESRCH);
}
KASSERT(best_algdesc != NULL);
/* Plug the back-end into the static (XXX) assignment. */
dses->__dses_assignment.das_backend = best_dmb;
dses->__dses_assignment.das_algdesc = best_algdesc;
dses->dses_ninputs = algdesc->dad_ninputs;
LIST_INSERT_HEAD(&best_dmb->dmb_sessions, dses, __dses_list);
best_dmb->dmb_nsessions++;
BACKEND_LIST_UNLOCK_READ();
return (0);
}
/*
* dmover_backend_release:
*
* Release the back-end from the specified session.
*/
void
dmover_backend_release(struct dmover_session *dses)
{
struct dmover_backend *dmb;
BACKEND_LIST_UNLOCK_READ();
/* XXX Clear out the static assignment. */
dmb = dses->__dses_assignment.das_backend;
dses->__dses_assignment.das_backend = NULL;
dses->__dses_assignment.das_algdesc = NULL;
LIST_REMOVE(dses, __dses_list);
dmb->dmb_nsessions--;
BACKEND_LIST_UNLOCK_READ();
}

733
sys/dev/dmover/dmover_io.c Normal file
View File

@ -0,0 +1,733 @@
/* $NetBSD: dmover_io.c,v 1.1 2002/08/02 00:30:38 thorpej Exp $ */
/*
* Copyright (c) 2002 Wasabi Systems, Inc.
* All rights reserved.
*
* Written by Jason R. Thorpe for Wasabi Systems, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed for the NetBSD Project by
* Wasabi Systems, Inc.
* 4. The name of Wasabi Systems, Inc. may not be used to endorse
* or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* dmover_io.c: Support for user-space access to dmover-api
*
* This interface is quite simple:
*
* 1. The user opens /dev/dmover, which is a cloning device. This
* allocates internal state for the session.
*
* 2. The user does a DMIO_SETFUNC to select the data movement
* function. This actually creates the dmover session.
*
* 3. The user writes request messages to its dmover handle.
*
* 4. The user reads request responses from its dmover handle.
*
* 5. The user closes the file descriptor and the session is
* torn down.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD");
#include <sys/param.h>
#include <sys/queue.h>
#include <sys/conf.h>
#include <sys/pool.h>
#include <sys/proc.h>
#include <sys/poll.h>
#include <sys/malloc.h>
#include <sys/lock.h>
#include <sys/file.h>
#include <sys/filedesc.h>
#include <sys/filio.h>
#include <sys/select.h>
#include <sys/systm.h>
#include <dev/dmover/dmovervar.h>
#include <dev/dmover/dmover_io.h>
struct dmio_usrreq_state {
TAILQ_ENTRY(dmio_usrreq_state) dus_q;
struct uio dus_uio_out;
struct uio *dus_uio_in;
struct dmover_request *dus_req;
uint32_t dus_id;
};
struct dmio_state {
struct dmover_session *ds_session;
TAILQ_HEAD(, dmio_usrreq_state) ds_pending;
TAILQ_HEAD(, dmio_usrreq_state) ds_complete;
struct selinfo ds_selq;
__volatile int ds_flags;
u_int ds_nreqs;
struct simplelock ds_slock;
};
#define DMIO_STATE_SEL 0x0001
#define DMIO_STATE_DEAD 0x0002
#define DMIO_STATE_LARVAL 0x0004
#define DMIO_STATE_READ_WAIT 0x0008
#define DMIO_STATE_WRITE_WAIT 0x0010
#define DMIO_NREQS_MAX 64 /* XXX pulled out of a hat */
struct pool dmio_state_pool;
struct pool dmio_usrreq_state_pool;
void dmoverioattach(int);
cdev_decl(dmoverio);
/*
* dmoverioattach:
*
* Pseudo-device attach routine.
*/
void
dmoverioattach(int count)
{
pool_init(&dmio_state_pool, sizeof(struct dmio_state),
0, 0, 0, "dmiostate", NULL);
pool_init(&dmio_usrreq_state_pool, sizeof(struct dmio_usrreq_state),
0, 0, 0, "dmiourstate", NULL);
}
/*
* dmio_usrreq_init:
*
* Build a request structure.
*/
static int
dmio_usrreq_init(struct file *fp, struct dmio_usrreq_state *dus,
struct dmio_usrreq *req, struct dmover_request *dreq)
{
struct dmio_state *ds = (struct dmio_state *) fp->f_data;
struct dmover_session *dses = ds->ds_session;
struct uio *uio_out = &dus->dus_uio_out;
struct uio *uio_in;
dmio_buffer inbuf;
size_t len;
u_int i, j;
int error;
/* XXX How should malloc interact w/ FNONBLOCK? */
if (req->req_outbuf.dmbuf_iovcnt > IOV_MAX)
return (EINVAL);
len = sizeof(struct iovec) * req->req_outbuf.dmbuf_iovcnt;
if (len == 0)
return (EINVAL);
uio_out->uio_iov = malloc(len, M_TEMP, M_WAITOK);
error = copyin(req->req_outbuf.dmbuf_iov, uio_out->uio_iov, len);
if (error) {
free(uio_out->uio_iov, M_TEMP);
return (error);
}
for (j = 0, len = 0; j < req->req_outbuf.dmbuf_iovcnt; j++) {
len += uio_out->uio_iov[j].iov_len;
if (len > SSIZE_MAX) {
free(uio_out->uio_iov, M_TEMP);
return (error);
}
}
uio_out->uio_iovcnt = req->req_outbuf.dmbuf_iovcnt;
uio_out->uio_resid = len;
uio_out->uio_rw = UIO_READ;
uio_out->uio_segflg = UIO_USERSPACE;
uio_out->uio_procp = curproc;
dreq->dreq_outbuf_type = DMOVER_BUF_UIO;
dreq->dreq_outbuf.dmbuf_uio = uio_out;
if (dses->dses_ninputs == 0) {
/* No inputs; copy the immediate. */
memcpy(dreq->dreq_immediate, req->req_immediate,
sizeof(dreq->dreq_immediate));
return (0);
}
dreq->dreq_inbuf_type = DMOVER_BUF_UIO;
dus->dus_uio_in = malloc(sizeof(struct uio) * dses->dses_ninputs,
M_TEMP, M_WAITOK);
memset(dus->dus_uio_in, 0, sizeof(struct uio) * dses->dses_ninputs);
for (i = 0; i < dses->dses_ninputs; i++) {
uio_in = &dus->dus_uio_in[i];
error = copyin(&req->req_inbuf[i], &inbuf, sizeof(inbuf));
if (error)
goto bad;
if (inbuf.dmbuf_iovcnt > IOV_MAX) {
error = EINVAL;
goto bad;
}
len = sizeof(struct iovec) * inbuf.dmbuf_iovcnt;
if (len == 0) {
error = EINVAL;
goto bad;
}
uio_in->uio_iov = malloc(len, M_TEMP, M_WAITOK);
error = copyin(inbuf.dmbuf_iov, uio_in->uio_iov, len);
if (error) {
free(uio_in->uio_iov, M_TEMP);
goto bad;
}
for (j = 0, len = 0; j < req->req_outbuf.dmbuf_iovcnt; j++) {
len += uio_in->uio_iov[j].iov_len;
if (len > SSIZE_MAX) {
free(uio_in->uio_iov, M_TEMP);
error = EINVAL;
goto bad;
}
}
if (len != uio_out->uio_resid) {
free(uio_in->uio_iov, M_TEMP);
error = EINVAL;
goto bad;
}
uio_in->uio_iovcnt = inbuf.dmbuf_iovcnt;
uio_in->uio_resid = len;
uio_in->uio_rw = UIO_WRITE;
uio_in->uio_segflg = UIO_USERSPACE;
uio_in->uio_procp = curproc;
dreq->dreq_inbuf[i].dmbuf_uio = uio_in;
}
return (0);
bad:
if (i > 0) {
for (--i; i >= 0; i--) {
uio_in = &dus->dus_uio_in[i];
free(uio_in->uio_iov, M_TEMP);
}
}
free(dus->dus_uio_in, M_TEMP);
free(uio_out->uio_iov, M_TEMP);
return (error);
}
/*
* dmio_usrreq_fini:
*
* Tear down a request. Must be called at splsoftclock().
*/
static void
dmio_usrreq_fini(struct dmio_state *ds, struct dmio_usrreq_state *dus)
{
struct dmover_session *dses = ds->ds_session;
struct uio *uio_out = &dus->dus_uio_out;
struct uio *uio_in;
int i;
free(uio_out->uio_iov, M_TEMP);
if (dses->dses_ninputs == 0) {
pool_put(&dmio_usrreq_state_pool, dus);
return;
}
for (i = 0; i < dses->dses_ninputs; i++) {
uio_in = &dus->dus_uio_in[i];
free(uio_in->uio_iov, M_TEMP);
}
free(dus->dus_uio_in, M_TEMP);
pool_put(&dmio_usrreq_state_pool, dus);
}
/*
* dmio_read:
*
* Read file op.
*/
static int
dmio_read(struct file *fp, off_t *offp, struct uio *uio,
struct ucred *cred, int flags)
{
struct dmio_state *ds = (struct dmio_state *) fp->f_data;
struct dmio_usrreq_state *dus;
struct dmover_request *dreq;
struct dmio_usrresp resp;
int s, error = 0, progress = 0;
if ((uio->uio_resid % sizeof(resp)) != 0)
return (EINVAL);
if (ds->ds_session == NULL)
return (ENXIO);
s = splsoftclock();
simple_lock(&ds->ds_slock);
while (uio->uio_resid != 0) {
for (;;) {
dus = TAILQ_FIRST(&ds->ds_complete);
if (dus == NULL) {
if (fp->f_flag & FNONBLOCK) {
error = progress ? 0 : EWOULDBLOCK;
goto out;
}
error = ltsleep(&ds->ds_complete,
PRIBIO | PCATCH, "dmvrrd", 0,
&ds->ds_slock);
if (error)
goto out;
continue;
}
/* Have a completed request. */
TAILQ_REMOVE(&ds->ds_complete, dus, dus_q);
ds->ds_nreqs--;
if (ds->ds_flags & DMIO_STATE_WRITE_WAIT) {
ds->ds_flags &= ~DMIO_STATE_WRITE_WAIT;
wakeup(&ds->ds_nreqs);
}
if (ds->ds_flags & DMIO_STATE_SEL) {
ds->ds_flags &= ~DMIO_STATE_SEL;
selwakeup(&ds->ds_selq);
}
break;
}
simple_unlock(&ds->ds_slock);
dreq = dus->dus_req;
resp.resp_id = dus->dus_id;
resp.resp_error = (dreq->dreq_flags & DMOVER_REQ_ERROR) ?
dreq->dreq_error : 0;
dmio_usrreq_fini(ds, dus);
splx(s);
progress = 1;
dmover_request_free(dreq);
error = uiomove(&resp, sizeof(resp), uio);
if (error)
return (error);
s = splsoftclock();
simple_lock(&ds->ds_slock);
}
out:
simple_unlock(&ds->ds_slock);
splx(s);
return (error);
}
/*
* dmio_usrreq_done:
*
* Dmover completion callback.
*/
static void
dmio_usrreq_done(struct dmover_request *dreq)
{
struct dmio_usrreq_state *dus = dreq->dreq_cookie;
struct dmio_state *ds = dreq->dreq_session->dses_cookie;
/* We're already at splsoftclock(). */
simple_lock(&ds->ds_slock);
TAILQ_REMOVE(&ds->ds_pending, dus, dus_q);
if (ds->ds_flags & DMIO_STATE_DEAD) {
ds->ds_nreqs--;
dmio_usrreq_fini(ds, dus);
dmover_request_free(dreq);
if (ds->ds_nreqs == 0) {
simple_unlock(&ds->ds_slock);
pool_put(&dmio_state_pool, ds);
return;
}
} else {
TAILQ_INSERT_TAIL(&ds->ds_complete, dus, dus_q);
if (ds->ds_flags & DMIO_STATE_READ_WAIT) {
ds->ds_flags &= ~DMIO_STATE_READ_WAIT;
wakeup(&ds->ds_complete);
}
if (ds->ds_flags & DMIO_STATE_SEL) {
ds->ds_flags &= ~DMIO_STATE_SEL;
selwakeup(&ds->ds_selq);
}
}
simple_unlock(&ds->ds_slock);
}
/*
* dmio_write:
*
* Write file op.
*/
static int
dmio_write(struct file *fp, off_t *offp, struct uio *uio,
struct ucred *cred, int flags)
{
struct dmio_state *ds = (struct dmio_state *) fp->f_data;
struct dmio_usrreq_state *dus;
struct dmover_request *dreq;
struct dmio_usrreq req;
int error = 0, s, progress = 0;
if ((uio->uio_resid % sizeof(req)) != 0)
return (EINVAL);
if (ds->ds_session == NULL)
return (ENXIO);
s = splsoftclock();
simple_lock(&ds->ds_slock);
while (uio->uio_resid != 0) {
if (ds->ds_nreqs == DMIO_NREQS_MAX) {
if (fp->f_flag & FNONBLOCK) {
error = progress ? 0 : EWOULDBLOCK;
break;
}
ds->ds_flags |= DMIO_STATE_WRITE_WAIT;
error = ltsleep(&ds->ds_nreqs, PRIBIO | PCATCH,
"dmiowr", 0, &ds->ds_slock);
if (error)
break;
continue;
}
ds->ds_nreqs++;
simple_unlock(&ds->ds_slock);
splx(s);
progress = 1;
error = uiomove(&req, sizeof(req), uio);
if (error) {
s = splsoftclock();
simple_lock(&ds->ds_slock);
ds->ds_nreqs--;
break;
}
/* XXX How should this interact with FNONBLOCK? */
dreq = dmover_request_alloc(ds->ds_session, NULL);
if (dreq == NULL) {
/* XXX */
s = splsoftclock();
simple_lock(&ds->ds_slock);
ds->ds_nreqs--;
error = ENOMEM;
break;
}
s = splsoftclock();
dus = pool_get(&dmio_usrreq_state_pool, PR_WAITOK);
splx(s);
error = dmio_usrreq_init(fp, dus, &req, dreq);
if (error) {
dmover_request_free(dreq);
s = splsoftclock();
pool_put(&dmio_usrreq_state_pool, dus);
simple_lock(&ds->ds_slock);
break;
}
dreq->dreq_callback = dmio_usrreq_done;
dreq->dreq_cookie = dus;
dus->dus_req = dreq;
dus->dus_id = req.req_id;
s = splsoftclock();
simple_lock(&ds->ds_slock);
TAILQ_INSERT_TAIL(&ds->ds_pending, dus, dus_q);
simple_unlock(&ds->ds_slock);
splx(s);
dmover_process(dreq);
s = splsoftclock();
simple_lock(&ds->ds_slock);
}
simple_unlock(&ds->ds_slock);
splx(s);
return (error);
}
/*
* dmio_ioctl:
*
* Ioctl file op.
*/
static int
dmio_ioctl(struct file *fp, u_long cmd, caddr_t data, struct proc *p)
{
struct dmio_state *ds = (struct dmio_state *) fp->f_data;
int error, s;
switch (cmd) {
case FIONBIO:
case FIOASYNC:
return (0);
case DMIO_SETFUNC:
{
struct dmio_setfunc *dsf = (void *) data;
struct dmover_session *dses;
s = splsoftclock();
simple_lock(&ds->ds_slock);
if (ds->ds_session != NULL ||
(ds->ds_flags & DMIO_STATE_LARVAL) != 0) {
simple_unlock(&ds->ds_slock);
splx(s);
return (EBUSY);
}
ds->ds_flags |= DMIO_STATE_LARVAL;
simple_unlock(&ds->ds_slock);
splx(s);
dsf->dsf_name[DMIO_MAX_FUNCNAME - 1] = '\0';
error = dmover_session_create(dsf->dsf_name, &dses);
s = splsoftclock();
simple_lock(&ds->ds_slock);
if (error == 0) {
dses->dses_cookie = ds;
ds->ds_session = dses;
}
ds->ds_flags &= ~DMIO_STATE_LARVAL;
simple_unlock(&ds->ds_slock);
splx(s);
break;
}
default:
error = ENOTTY;
}
return (error);
}
/*
* dmio_fcntl:
*
* Fcntl file op.
*/
static int
dmio_fcntl(struct file *fp, u_int cmd, caddr_t data, struct proc *p)
{
if (cmd == FNONBLOCK || cmd == FASYNC)
return (0);
return (EOPNOTSUPP);
}
/*
* dmio_poll:
*
* Poll file op.
*/
static int
dmio_poll(struct file *fp, int events, struct proc *p)
{
struct dmio_state *ds = (struct dmio_state *) fp->f_data;
int s, revents = 0;
if ((events & (POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM)) == 0)
return (revents);
s = splsoftclock();
simple_lock(&ds->ds_slock);
if (ds->ds_flags & DMIO_STATE_DEAD) {
/* EOF */
revents |= events & (POLLIN | POLLRDNORM |
POLLOUT | POLLWRNORM);
goto out;
}
/* We can read if there are completed requests. */
if (events & (POLLIN | POLLRDNORM))
if (TAILQ_EMPTY(&ds->ds_complete) == 0)
revents |= events & (POLLIN | POLLRDNORM);
/*
* We can write if there is there are fewer then DMIO_NREQS_MAX
* are already in the queue.
*/
if (events & (POLLOUT | POLLWRNORM))
if (ds->ds_nreqs < DMIO_NREQS_MAX)
revents |= events & (POLLOUT | POLLWRNORM);
if (revents == 0) {
selrecord(p, &ds->ds_selq);
ds->ds_flags |= DMIO_STATE_SEL;
}
out:
simple_unlock(&ds->ds_slock);
splx(s);
return (revents);
}
/*
* dmio_stat:
*
* Stat file op.
*/
static int
dmio_stat(struct file *fp, struct stat *sb, struct proc *p)
{
return (EOPNOTSUPP);
}
/*
* dmio_close:
*
* Close file op.
*/
static int
dmio_close(struct file *fp, struct proc *p)
{
struct dmio_state *ds = (struct dmio_state *) fp->f_data;
struct dmio_usrreq_state *dus;
struct dmover_session *dses;
int s;
s = splsoftclock();
simple_lock(&ds->ds_slock);
ds->ds_flags |= DMIO_STATE_DEAD;
/* Garbage-collect all the responses on the queue. */
while ((dus = TAILQ_FIRST(&ds->ds_complete)) != NULL) {
TAILQ_REMOVE(&ds->ds_complete, dus, dus_q);
ds->ds_nreqs--;
dmover_request_free(dus->dus_req);
dmio_usrreq_fini(ds, dus);
}
/*
* If there are any requests pending, we have to wait for
* them. Don't free the dmio_state in this case.
*/
if (ds->ds_nreqs == 0) {
dses = ds->ds_session;
simple_unlock(&ds->ds_slock);
pool_put(&dmio_state_pool, ds);
} else {
dses = NULL;
simple_unlock(&ds->ds_slock);
}
splx(s);
fp->f_data = NULL;
if (dses != NULL)
dmover_session_destroy(dses);
return (0);
}
static struct fileops dmio_fileops = {
dmio_read,
dmio_write,
dmio_ioctl,
dmio_fcntl,
dmio_poll,
dmio_stat,
dmio_close,
};
/*
* dmoverioopen:
*
* Device switch open routine.
*/
int
dmoverioopen(dev_t dev, int flag, int mode, struct proc *p)
{
struct dmio_state *ds;
struct file *fp;
int error, fd, s;
/* falloc() will use the descriptor for us. */
if ((error = falloc(p, &fp, &fd)) != 0)
return (error);
s = splsoftclock();
ds = pool_get(&dmio_state_pool, PR_WAITOK);
splx(s);
memset(ds, 0, sizeof(*ds));
TAILQ_INIT(&ds->ds_pending);
TAILQ_INIT(&ds->ds_complete);
fp->f_flag = FREAD | FWRITE;
fp->f_type = DTYPE_MISC;
fp->f_ops = &dmio_fileops;
fp->f_data = (caddr_t) ds;
p->p_dupfd = fd;
FILE_SET_MATURE(fp);
FILE_UNUSE(fp, p);
return (ENXIO);
}

View File

@ -0,0 +1,92 @@
/* $NetBSD: dmover_io.h,v 1.1 2002/08/02 00:30:38 thorpej Exp $ */
/*
* Copyright (c) 2002 Wasabi Systems, Inc.
* All rights reserved.
*
* Written by Jason R. Thorpe for Wasabi Systems, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed for the NetBSD Project by
* Wasabi Systems, Inc.
* 4. The name of Wasabi Systems, Inc. may not be used to endorse
* or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _DMOVER_DMOVER_IO_H_
#define _DMOVER_DMOVER_IO_H_
#include <sys/ioccom.h>
#include <sys/uio.h>
typedef struct {
struct iovec *dmbuf_iov;
u_int dmbuf_iovcnt;
} dmio_buffer;
/*
* dmio_usrreq:
*
* Request structure passed from user-space.
*/
struct dmio_usrreq {
/* Output buffer. */
dmio_buffer req_outbuf;
/* Input buffer. */
union {
uint8_t _immediate[8];
dmio_buffer *_inbuf;
} _req_inbuf_un;
#define req_immediate _req_inbuf_un._immediate
#define req_inbuf _req_inbuf_un._inbuf
uint32_t req_id; /* request ID; passed in response */
};
/*
* dmio_usrresp:
*
* Response structure passed to user-space.
*/
struct dmio_usrresp {
uint32_t resp_id; /* request ID */
int resp_error; /* error, 0 if success */
};
/*
* DMIO_SETFUNC:
*
* Ioctl to set the function type for the session.
*/
#define DMIO_SETFUNC _IOW('D', 0, struct dmio_setfunc)
#define DMIO_MAX_FUNCNAME 64
struct dmio_setfunc {
char dsf_name[DMIO_MAX_FUNCNAME];
};
#endif /* _DMOVER_DMOVER_IO_H_ */

View File

@ -0,0 +1,199 @@
/* $NetBSD: dmover_process.c,v 1.1 2002/08/02 00:30:38 thorpej Exp $ */
/*
* Copyright (c) 2002 Wasabi Systems, Inc.
* All rights reserved.
*
* Written by Jason R. Thorpe for Wasabi Systems, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed for the NetBSD Project by
* Wasabi Systems, Inc.
* 4. The name of Wasabi Systems, Inc. may not be used to endorse
* or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* dmover_process.c: Processing engine for dmover-api.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: dmover_process.c,v 1.1 2002/08/02 00:30:38 thorpej Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <machine/intr.h>
#include <dev/dmover/dmovervar.h>
TAILQ_HEAD(, dmover_request) dmover_completed_q;
struct simplelock dmover_completed_q_slock; /* must be held at splbio */
void *dmover_completed_si;
void dmover_complete(void *);
/*
* dmover_process_init:
*
* Initialize the processing engine.
*/
void
dmover_process_initialize(void)
{
TAILQ_INIT(&dmover_completed_q);
simple_lock_init(&dmover_completed_q_slock);
dmover_completed_si = softintr_establish(IPL_SOFTCLOCK,
dmover_complete, NULL);
}
/*
* dmover_process: [client interface function]
*
* Submit a tranform request for processing.
*/
void
dmover_process(struct dmover_request *dreq)
{
struct dmover_session *dses = dreq->dreq_session;
struct dmover_assignment *das;
struct dmover_backend *dmb;
int s;
#ifdef DIAGNOSTIC
if ((dreq->dreq_flags & DMOVER_REQ_WAIT) != 0 &&
dreq->dreq_callback != NULL)
panic("dmover_process: WAIT used with callback");
#endif
/* Clear unwanted flag bits. */
dreq->dreq_flags &= __DMOVER_REQ_FLAGS_PRESERVE;
s = splbio();
/* XXXLOCK */
/* XXX Right now, the back-end is statically assigned. */
das = &dses->__dses_assignment;
dmb = das->das_backend;
dreq->dreq_assignment = das;
dmover_session_insque(dses, dreq);
/* XXX Currently, both buffers must be of same type. */
if (das->das_algdesc->dad_ninputs != 0 &&
dreq->dreq_inbuf_type != dreq->dreq_outbuf_type) {
dreq->dreq_error = EINVAL;
dreq->dreq_flags |= DMOVER_REQ_ERROR;
/* XXXUNLOCK */
splx(s);
dmover_done(dreq);
return;
}
dmover_backend_insque(dmb, dreq);
/* XXXUNLOCK */
splx(s);
/* Kick the back-end into action. */
(*dmb->dmb_process)(das->das_backend);
if (dreq->dreq_flags & DMOVER_REQ_WAIT) {
s = splbio();
/* XXXLOCK */
while ((dreq->dreq_flags & DMOVER_REQ_DONE) == 0)
(void) tsleep(dreq, PRIBIO, "dmover", 0);
/* XXXUNLOCK */
splx(s);
}
}
/*
* dmover_done: [back-end interface function]
*
* Back-end notification that the dmover is done.
*/
void
dmover_done(struct dmover_request *dreq)
{
struct dmover_session *dses = dreq->dreq_session;
int s;
s = splbio();
/* XXXLOCK */
dmover_session_remque(dses, dreq);
/* backend has removed it from its queue */
/* XXXUNLOCK */
dreq->dreq_flags |= DMOVER_REQ_DONE;
dreq->dreq_flags &= ~DMOVER_REQ_RUNNING;
dreq->dreq_assignment = NULL;
if (dreq->dreq_callback != NULL) {
simple_lock(&dmover_completed_q_slock);
TAILQ_INSERT_TAIL(&dmover_completed_q, dreq, dreq_dmbq);
simple_unlock(&dmover_completed_q_slock);
softintr_schedule(dmover_completed_si);
} else if (dreq->dreq_flags & DMOVER_REQ_WAIT)
wakeup(dreq);
splx(s);
}
/*
* dmover_complete:
*
* Complete a request by invoking the callback.
*/
void
dmover_complete(void *arg)
{
struct dmover_request *dreq;
int s;
for (;;) {
s = splbio();
simple_lock(&dmover_completed_q_slock);
if ((dreq = TAILQ_FIRST(&dmover_completed_q)) != NULL)
TAILQ_REMOVE(&dmover_completed_q, dreq, dreq_dmbq);
simple_unlock(&dmover_completed_q_slock);
splx(s);
if (dreq == NULL)
return;
(*dreq->dreq_callback)(dreq);
}
}

View File

@ -0,0 +1,145 @@
/* $NetBSD: dmover_request.c,v 1.1 2002/08/02 00:30:39 thorpej Exp $ */
/*
* Copyright (c) 2002 Wasabi Systems, Inc.
* All rights reserved.
*
* Written by Jason R. Thorpe for Wasabi Systems, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed for the NetBSD Project by
* Wasabi Systems, Inc.
* 4. The name of Wasabi Systems, Inc. may not be used to endorse
* or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* dmover_request.c: Request management functions for dmover-api.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: dmover_request.c,v 1.1 2002/08/02 00:30:39 thorpej Exp $");
#include <sys/param.h>
#include <sys/lock.h>
#include <sys/pool.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <dev/dmover/dmovervar.h>
struct pool dmover_request_pool;
struct pool_cache dmover_request_cache;
static int initialized;
static struct simplelock initialized_slock = SIMPLELOCK_INITIALIZER;
void
dmover_request_initialize(void)
{
int s;
s = splbio();
simple_lock(&initialized_slock);
if (__predict_true(initialized == 0)) {
pool_init(&dmover_request_pool, sizeof(struct dmover_request),
0, 0, 0, "dmreq", NULL);
pool_cache_init(&dmover_request_cache, &dmover_request_pool,
NULL, NULL, NULL);
initialized = 1;
}
simple_unlock(&initialized_slock);
splx(s);
}
/*
* dmover_request_alloc: [client interface function]
*
* Allocate a tranform request for the specified session.
*/
struct dmover_request *
dmover_request_alloc(struct dmover_session *dses, dmover_buffer *inbuf)
{
struct dmover_request *dreq;
int s, inputs = dses->dses_ninputs;
if (__predict_false(initialized == 0)) {
int error;
s = splbio();
simple_lock(&initialized_slock);
error = (initialized == 0);
simple_unlock(&initialized_slock);
splx(s);
if (error)
return (NULL);
}
s = splbio();
dreq = pool_cache_get(&dmover_request_cache, PR_NOWAIT);
splx(s);
if (dreq == NULL)
return (NULL);
memset(dreq, 0, sizeof(*dreq));
if (inputs != 0) {
if (inbuf == NULL) {
inbuf = malloc(sizeof(dmover_buffer) * inputs,
M_DEVBUF, M_NOWAIT);
if (inbuf == NULL) {
s = splbio();
pool_cache_put(&dmover_request_cache, dreq);
splx(s);
return (NULL);
}
}
dreq->dreq_flags |= __DMOVER_REQ_INBUF_FREE;
dreq->dreq_inbuf = inbuf;
}
dreq->dreq_session = dses;
return (dreq);
}
/*
* dmover_request_free: [client interface function]
*
* Free a dmover request.
*/
void
dmover_request_free(struct dmover_request *dreq)
{
int s;
if (dreq->dreq_flags & __DMOVER_REQ_INBUF_FREE)
free(dreq->dreq_inbuf, M_DEVBUF);
s = splbio();
pool_cache_put(&dmover_request_cache, dreq);
splx(s);
}

View File

@ -0,0 +1,137 @@
/* $NetBSD: dmover_session.c,v 1.1 2002/08/02 00:30:39 thorpej Exp $ */
/*
* Copyright (c) 2002 Wasabi Systems, Inc.
* All rights reserved.
*
* Written by Jason R. Thorpe for Wasabi Systems, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed for the NetBSD Project by
* Wasabi Systems, Inc.
* 4. The name of Wasabi Systems, Inc. may not be used to endorse
* or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* dmover_session.c: Session management functions for dmover-api.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: dmover_session.c,v 1.1 2002/08/02 00:30:39 thorpej Exp $");
#include <sys/param.h>
#include <sys/lock.h>
#include <sys/pool.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <dev/dmover/dmovervar.h>
struct pool dmover_session_pool;
static int initialized;
static struct simplelock initialized_slock = SIMPLELOCK_INITIALIZER;
void
dmover_session_initialize(void)
{
simple_lock(&initialized_slock);
if (__predict_true(initialized == 0)) {
pool_init(&dmover_session_pool, sizeof(struct dmover_session),
0, 0, 0, "dmses", &pool_allocator_nointr);
initialized = 1;
}
simple_unlock(&initialized_slock);
}
/*
* dmover_session_create: [client interface function]
*
* Create a dmover session.
*/
int
dmover_session_create(const char *type, struct dmover_session **dsesp)
{
struct dmover_session *dses;
int error;
if (__predict_false(initialized == 0)) {
simple_lock(&initialized_slock);
error = initialized ? 0 : ENXIO;
simple_unlock(&initialized_slock);
if (error)
return (error);
}
dses = pool_get(&dmover_session_pool, PR_NOWAIT);
if (__predict_false(dses == NULL))
return (ENOMEM);
/* Allocate a back-end to the session. */
error = dmover_backend_alloc(dses, type);
if (__predict_false(error)) {
pool_put(&dmover_session_pool, dses);
return (error);
}
TAILQ_INIT(&dses->__dses_pendreqs);
dses->__dses_npendreqs = 0;
*dsesp = dses;
return (0);
}
/*
* dmover_session_destroy: [client interface function]
*
* Tear down a dmover session.
*/
void
dmover_session_destroy(struct dmover_session *dses)
{
#ifdef DIAGNOSTIC
if (__predict_false(initialized == 0)) {
int croak;
simple_lock(&initialized_slock);
croak = (initialized == 0);
simple_unlock(&initialized_slock);
if (croak)
panic("dmover_session_destroy: not initialized");
}
#endif
/* XXX */
if (dses->__dses_npendreqs)
panic("dmover_session_destroy");
dmover_backend_release(dses);
pool_put(&dmover_session_pool, dses);
}

View File

@ -0,0 +1,78 @@
/* $NetBSD: dmover_util.c,v 1.1 2002/08/02 00:30:39 thorpej Exp $ */
/*
* Copyright (c) 2002 Wasabi Systems, Inc.
* All rights reserved.
*
* Written by Jason R. Thorpe for Wasabi Systems, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed for the NetBSD Project by
* Wasabi Systems, Inc.
* 4. The name of Wasabi Systems, Inc. may not be used to endorse
* or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* dmover_util.c: Utility functions for dmover-api.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: dmover_util.c,v 1.1 2002/08/02 00:30:39 thorpej Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <dev/dmover/dmovervar.h>
/****************************************************************************
* Well-known data mover function names.
****************************************************************************/
const char dmover_funcname_zero[] = "zero";
const char dmover_funcname_fill8[] = "fill8";
const char dmover_funcname_copy[] = "copy";
/****************************************************************************
* Utility functions.
****************************************************************************/
/*
* dmover_algdesc_lookup:
*
* Look up the algdesc in the provided array by name.
*/
const struct dmover_algdesc *
dmover_algdesc_lookup(const struct dmover_algdesc *dad, int ndad,
const char *name)
{
for (; ndad != 0; ndad--, dad++) {
if (name[0] == dad->dad_name[0] &&
strcmp(name, dad->dad_name) == 0)
return (dad);
}
return (NULL);
}

265
sys/dev/dmover/dmovervar.h Normal file
View File

@ -0,0 +1,265 @@
/* $NetBSD: dmovervar.h,v 1.1 2002/08/02 00:30:40 thorpej Exp $ */
/*
* Copyright (c) 2002 Wasabi Systems, Inc.
* All rights reserved.
*
* Written by Jason R. Thorpe for Wasabi Systems, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed for the NetBSD Project by
* Wasabi Systems, Inc.
* 4. The name of Wasabi Systems, Inc. may not be used to endorse
* or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _DMOVER_DMOVERVAR_H_
#define _DMOVER_DMOVERVAR_H_
#include <sys/lock.h>
#include <sys/queue.h>
/*
* Types of buffers the dmover-api can handle.
*/
typedef enum {
DMOVER_BUF_LINEAR,
DMOVER_BUF_UIO
} dmover_buffer_type;
typedef struct {
void *l_addr;
size_t l_len;
} dmover_buf_linear;
typedef union {
dmover_buf_linear dmbuf_linear;
struct uio *dmbuf_uio;
} dmover_buffer;
/*
* dmover_algdesc:
*
* This structure describes an dmover algorithm.
*
* All members of this structure are public.
*/
struct dmover_algdesc {
const char *dad_name; /* algorithm name */
void *dad_data; /* opaque algorithm description */
int dad_ninputs; /* number of inputs */
};
/*
* dmover_assignment:
*
* This structure contains the information necessary to assign
* a request to a back-end.
*
* All members of this structure are public.
*/
struct dmover_assignment {
struct dmover_backend *das_backend;
const struct dmover_algdesc *das_algdesc;
};
/*
* dmover_session:
*
* State for a dmover session.
*/
struct dmover_session {
/*
* PUBLIC MEMBERS
*/
void *dses_cookie; /* for client */
int dses_ninputs; /* number of inputs for function */
/*
* PRIVATE MEMBERS
*/
LIST_ENTRY(dmover_session) __dses_list;
/*
* XXX Assignment is static when a session is
* XXX created, for now.
*/
struct dmover_assignment __dses_assignment;
/* List of active requests on this session. */
TAILQ_HEAD(, dmover_request) __dses_pendreqs;
int __dses_npendreqs;
};
#define dmover_session_insque(dses, dreq) \
do { \
TAILQ_INSERT_TAIL(&(dses)->__dses_pendreqs, (dreq), dreq_sesq); \
(dses)->__dses_npendreqs++; \
} while (/*CONSTCOND*/0)
#define dmover_session_remque(dses, dreq) \
do { \
TAILQ_REMOVE(&(dses)->__dses_pendreqs, (dreq), dreq_sesq); \
(dses)->__dses_npendreqs--; \
} while (/*CONSTCOND*/0)
/*
* dmover_request:
*
* A data dmover request.
*/
struct dmover_request {
/*
* PUBLIC MEMBERS
*/
/* Links on session and back-end queues. */
TAILQ_ENTRY(dmover_request) dreq_sesq;
TAILQ_ENTRY(dmover_request) dreq_dmbq;
/* Pointer to our session. */
struct dmover_session *dreq_session;
/* Our current back-end assignment. */
struct dmover_assignment *dreq_assignment;
/* Function to call when processing is complete. */
void (*dreq_callback)(struct dmover_request *);
void *dreq_cookie; /* for client */
__volatile int dreq_flags; /* flags; see below */
int dreq_error; /* valid if DMOVER_REQ_ERROR is set */
/* Output buffer. */
dmover_buffer_type dreq_outbuf_type;
dmover_buffer dreq_outbuf;
/* Input buffer. */
dmover_buffer_type dreq_inbuf_type;
union {
uint8_t _immediate[8];
dmover_buffer *_inbuf;
} _dreq_inbuf_un;
#define dreq_immediate _dreq_inbuf_un._immediate
#define dreq_inbuf _dreq_inbuf_un._inbuf
};
/* dreq_flags */
#define DMOVER_REQ_DONE 0x0001 /* request is completed */
#define DMOVER_REQ_ERROR 0x0002 /* error occurred */
#define DMOVER_REQ_RUNNING 0x0004 /* request is being executed */
#define DMOVER_REQ_WAIT 0x0008 /* wait for completion */
#define __DMOVER_REQ_INBUF_FREE 0x01000000 /* need to free input buffer */
#define __DMOVER_REQ_FLAGS_PRESERVE \
(DMOVER_REQ_WAIT | __DMOVER_REQ_INBUF_FREE)
/*
* dmover_backend:
*
* Glue between the dmover-api middle layer and the dmover
* backends.
*
* All members of this structure are public.
*/
struct dmover_backend {
TAILQ_ENTRY(dmover_backend) dmb_list;
const char *dmb_name; /* name of back-end */
u_int dmb_speed; /* est. KB/s throughput */
void *dmb_cookie; /* for back-end */
/* List of algorithms this back-ends supports. */
const struct dmover_algdesc *dmb_algdescs;
int dmb_nalgdescs;
/* Back-end functions. */
void (*dmb_process)(struct dmover_backend *);
/* List of sessions currently on this back-end. */
LIST_HEAD(, dmover_session) dmb_sessions;
int dmb_nsessions; /* current number of sessions */
/* List of active requests on this back-end. */
TAILQ_HEAD(, dmover_request) dmb_pendreqs;
int dmb_npendreqs;
};
#define dmover_backend_insque(dmb, dreq) \
do { \
TAILQ_INSERT_TAIL(&(dmb)->dmb_pendreqs, (dreq), dreq_dmbq); \
(dmb)->dmb_npendreqs++; \
} while (/*CONSTCOND*/0)
#define dmover_backend_remque(dmb, dreq) \
do { \
TAILQ_REMOVE(&(dmb)->dmb_pendreqs, (dreq), dreq_dmbq); \
(dmb)->dmb_npendreqs--; \
} while (/*CONSTCOND*/0)
/*
* Well-known data mover functions. Using these for the function name
* saves space.
*/
extern const char dmover_funcname_zero[];
#define DMOVER_FUNC_ZERO dmover_funcname_zero
extern const char dmover_funcname_fill8[];
#define DMOVER_FUNC_FILL8 dmover_funcname_fill8
extern const char dmover_funcname_copy[];
#define DMOVER_FUNC_COPY dmover_funcname_copy
/* Back-end management functions. */
void dmover_backend_register(struct dmover_backend *);
void dmover_backend_unregister(struct dmover_backend *);
int dmover_backend_alloc(struct dmover_session *, const char *);
void dmover_backend_release(struct dmover_session *);
/* Session management functions. */
void dmover_session_initialize(void);
int dmover_session_create(const char *, struct dmover_session **);
void dmover_session_destroy(struct dmover_session *);
/* Request management functions. */
void dmover_request_initialize(void);
struct dmover_request *dmover_request_alloc(struct dmover_session *,
dmover_buffer *);
void dmover_request_free(struct dmover_request *);
/* Processing engine functions. */
void dmover_process_initialize(void);
void dmover_process(struct dmover_request *);
void dmover_done(struct dmover_request *);
/* Utility functions. */
const struct dmover_algdesc *
dmover_algdesc_lookup(const struct dmover_algdesc *, int,
const char *);
#endif /* _DMOVER_DMOVERVAR_H_ */

View File

@ -0,0 +1,19 @@
# $NetBSD: files.dmover,v 1.1 2002/08/02 00:30:40 thorpej Exp $
define dmover_service
file dev/dmover/dmover_backend.c dmover_service
file dev/dmover/dmover_process.c dmover_service
file dev/dmover/dmover_request.c dmover_service
file dev/dmover/dmover_session.c dmover_service
file dev/dmover/dmover_util.c dmover_service
# Software back-end which provides the dmover functions
# documented in dmover(9).
defpseudo swdmover: dmover_service
file dev/dmover/swdmover.c swdmover
# Userland interface to dmover(9) through a message-passing
# interface.
defpseudo dmoverio: dmover_service
file dev/dmover/dmover_io.c dmoverio needs-flag

385
sys/dev/dmover/swdmover.c Normal file
View File

@ -0,0 +1,385 @@
/* $NetBSD: swdmover.c,v 1.1 2002/08/02 00:30:40 thorpej Exp $ */
/*
* Copyright (c) 2002 Wasabi Systems, Inc.
* All rights reserved.
*
* Written by Jason R. Thorpe for Wasabi Systems, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed for the NetBSD Project by
* Wasabi Systems, Inc.
* 4. The name of Wasabi Systems, Inc. may not be used to endorse
* or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* swdmover.c: Software back-end providing the dmover functions
* mentioned in dmover(9).
*
* This module provides a fallback for cases where no hardware
* data movers are present in a system, and also serves an an
* example of how to write a dmover back-end.
*
* Note that even through the software dmover doesn't require
* interrupts to be blocked, we block them anyway to demonstrate
* the locking protocol.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD");
#include <sys/param.h>
#include <sys/lock.h>
#include <sys/kthread.h>
#include <sys/systm.h>
#include <sys/uio.h>
#include <dev/dmover/dmovervar.h>
struct swdmover_function {
void (*sdf_process)(struct dmover_request *);
};
static struct dmover_backend swdmover_backend;
static struct proc *swdmover_proc;
static int swdmover_cv;
void swdmoverattach(int);
/*
* swdmover_process:
*
* Dmover back-end entry point.
*/
static void
swdmover_process(struct dmover_backend *dmb)
{
int s;
/*
* Just wake up the processing thread. This will allow
* requests to linger on the middle-end's queue so that
* they can be cancelled, if need-be.
*/
s = splbio();
/* XXXLOCK */
if (TAILQ_EMPTY(&dmb->dmb_pendreqs) == 0)
wakeup(&swdmover_cv);
/* XXXUNLOCK */
splx(s);
}
/*
* swdmover_thread:
*
* Request processing thread.
*/
static void
swdmover_thread(void *arg)
{
struct dmover_backend *dmb = arg;
struct dmover_request *dreq;
struct swdmover_function *sdf;
int s;
s = splbio();
/* XXXLOCK */
for (;;) {
dreq = TAILQ_FIRST(&dmb->dmb_pendreqs);
if (dreq == NULL) {
/* XXXUNLOCK */
(void) tsleep(&swdmover_cv, PRIBIO, "swdmvr", 0);
continue;
}
dmover_backend_remque(dmb, dreq);
dreq->dreq_flags |= DMOVER_REQ_RUNNING;
/* XXXUNLOCK */
splx(s);
sdf = dreq->dreq_assignment->das_algdesc->dad_data;
(*sdf->sdf_process)(dreq);
s = splbio();
/* XXXLOCK */
}
}
/*
* swdmover_func_zero_process:
*
* Processing routine for the "zero" function.
*/
static void
swdmover_func_zero_process(struct dmover_request *dreq)
{
switch (dreq->dreq_outbuf_type) {
case DMOVER_BUF_LINEAR:
memset(dreq->dreq_outbuf.dmbuf_linear.l_addr, 0,
dreq->dreq_outbuf.dmbuf_linear.l_len);
break;
case DMOVER_BUF_UIO:
{
struct uio *uio = dreq->dreq_outbuf.dmbuf_uio;
char *cp;
size_t count, buflen;
int error;
if (uio->uio_rw != UIO_READ) {
/* XXXLOCK */
dreq->dreq_error = EINVAL;
dreq->dreq_flags |= DMOVER_REQ_ERROR;
/* XXXUNLOCK */
break;
}
buflen = uio->uio_resid;
if (buflen > 1024)
buflen = 1024;
cp = alloca(buflen);
memset(cp, 0, buflen);
while ((count = uio->uio_resid) != 0) {
if (count > buflen)
count = buflen;
error = uiomove(cp, count, uio);
if (error) {
/* XXXLOCK */
dreq->dreq_error = error;
dreq->dreq_flags |= DMOVER_REQ_ERROR;
/* XXXUNLOCK */
break;
}
}
break;
}
}
dmover_done(dreq);
}
/*
* swdmover_func_fill8_process:
*
* Processing routine for the "fill8" function.
*/
static void
swdmover_func_fill8_process(struct dmover_request *dreq)
{
switch (dreq->dreq_outbuf_type) {
case DMOVER_BUF_LINEAR:
memset(dreq->dreq_outbuf.dmbuf_linear.l_addr,
dreq->dreq_immediate[0],
dreq->dreq_outbuf.dmbuf_linear.l_len);
break;
case DMOVER_BUF_UIO:
{
struct uio *uio = dreq->dreq_outbuf.dmbuf_uio;
char *cp;
size_t count, buflen;
int error;
if (uio->uio_rw != UIO_READ) {
/* XXXLOCK */
dreq->dreq_error = EINVAL;
dreq->dreq_flags |= DMOVER_REQ_ERROR;
/* XXXUNLOCK */
break;
}
buflen = uio->uio_resid;
if (buflen > 1024)
buflen = 1024;
cp = alloca(buflen);
memset(cp, dreq->dreq_immediate[0], buflen);
while ((count = uio->uio_resid) != 0) {
if (count > buflen)
count = buflen;
error = uiomove(cp, count, uio);
if (error) {
/* XXXLOCK */
dreq->dreq_error = error;
dreq->dreq_flags |= DMOVER_REQ_ERROR;
/* XXXUNLOCK */
break;
}
}
break;
}
}
dmover_done(dreq);
}
/*
* swdmover_func_copy_process:
*
* Processing routine for the "copy" function.
*/
static void
swdmover_func_copy_process(struct dmover_request *dreq)
{
/*
* Middle-end makes sure input and output buffers are of
* the same type.
*/
switch (dreq->dreq_outbuf_type) {
case DMOVER_BUF_LINEAR:
if (dreq->dreq_outbuf.dmbuf_linear.l_len !=
dreq->dreq_inbuf[0].dmbuf_linear.l_len) {
/* XXXLOCK */
dreq->dreq_error = EINVAL;
dreq->dreq_flags |= DMOVER_REQ_ERROR;
/* XXXUNLOCK */
break;
}
memcpy(dreq->dreq_outbuf.dmbuf_linear.l_addr,
dreq->dreq_inbuf[0].dmbuf_linear.l_addr,
dreq->dreq_outbuf.dmbuf_linear.l_len);
break;
case DMOVER_BUF_UIO:
{
struct uio *uio_out = dreq->dreq_outbuf.dmbuf_uio;
struct uio *uio_in = dreq->dreq_inbuf[0].dmbuf_uio;
char *cp;
size_t count, buflen;
int error;
if (uio_in->uio_rw != UIO_WRITE ||
uio_out->uio_rw != UIO_READ ||
uio_in->uio_resid != uio_out->uio_resid) {
/* XXXLOCK */
dreq->dreq_error = EINVAL;
dreq->dreq_flags |= DMOVER_REQ_ERROR;
/* XXXUNLOCK */
break;
}
buflen = uio_in->uio_resid;
if (buflen > 1024)
buflen = 1024;
cp = alloca(buflen);
while ((count = uio_in->uio_resid) != 0) {
if (count > buflen)
count = buflen;
error = uiomove(cp, count, uio_in);
if (error == 0)
error = uiomove(cp, count, uio_out);
if (error) {
/* XXXLOCK */
dreq->dreq_error = error;
dreq->dreq_flags |= DMOVER_REQ_ERROR;
/* XXXUNLOCK */
break;
}
}
break;
}
}
dmover_done(dreq);
}
static struct swdmover_function swdmover_func_zero = {
swdmover_func_zero_process
};
static struct swdmover_function swdmover_func_fill8 = {
swdmover_func_fill8_process
};
struct swdmover_function swdmover_func_copy = {
swdmover_func_copy_process
};
const struct dmover_algdesc swdmover_algdescs[] = {
{
DMOVER_FUNC_ZERO,
&swdmover_func_zero,
0
},
{
DMOVER_FUNC_FILL8,
&swdmover_func_fill8,
0
},
{
DMOVER_FUNC_COPY,
&swdmover_func_copy,
1
},
};
#define SWDMOVER_ALGDESC_COUNT \
(sizeof(swdmover_algdescs) / sizeof(swdmover_algdescs[0]))
/*
* swdmover_create_thread:
*
* Actually create the swdmover processing thread.
*/
static void
swdmover_create_thread(void *arg)
{
int error;
error = kthread_create1(swdmover_thread, arg, &swdmover_proc,
"swdmover");
if (error)
printf("WARNING: unable to create swdmover thread, "
"error = %d\n", error);
}
/*
* swdmoverattach:
*
* Pesudo-device attach routine.
*/
void
swdmoverattach(int count)
{
swdmover_backend.dmb_name = "swdmover";
swdmover_backend.dmb_speed = 1; /* XXX */
swdmover_backend.dmb_cookie = NULL;
swdmover_backend.dmb_algdescs = swdmover_algdescs;
swdmover_backend.dmb_nalgdescs = SWDMOVER_ALGDESC_COUNT;
swdmover_backend.dmb_process = swdmover_process;
kthread_create(swdmover_create_thread, &swdmover_backend);
/* XXX Should only register this when kthread creation succeeds. */
dmover_backend_register(&swdmover_backend);
}