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:
parent
bf72c7334c
commit
5d06c0e812
|
@ -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>
|
|
@ -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();
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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_ */
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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_ */
|
|
@ -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
|
|
@ -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);
|
||||
}
|
Loading…
Reference in New Issue