Subject: [RFC] Interface to hardware-assisted data movers
To: None <tech-kern@netbsd.org>
From: Jason R Thorpe <thorpej@wasabisystems.com>
List: tech-kern
Date: 06/19/2002 16:32:14
--+xNpyl7Qekk2NvDX
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

The following outlines an API for using hardware-assisted data movers.
Included in this category are hardware devices which can do:

	- block clear
	- block fill
	- block copy
	- multi-stream XOR

The eventual goal is to use this to accelerate the XOR operation for
RAID.  Userland access to the devices will also be provided by a
/dev/dmover device.

Comments are appreciated.

-- 
        -- Jason R. Thorpe <thorpej@wasabisystems.com>

--+xNpyl7Qekk2NvDX
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="dmover.9"

.\"	$NetBSD$
.\"
.\" 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.
.\"
.Dd June 18, 2002
.Dt DMOVER 9
.Os
.Sh NAME
.Nm dmover_backend_register ,
.Nm dmover_backend_unregister ,
.Nm dmover_session_create ,
.Nm dmover_session_destroy ,
.Nm dmover_request_alloc ,
.Nm dmover_request_free ,
.Nm dmover_process ,
.Nm dmover_done
.Nd hardware-assisted data mover interface
.Sh SYNOPSIS
.Fd #include \*[Lt]dev/dmover/dmovervar.h\*[Gt]
.Ft void
.Fn "dmover_backend_register" "struct dmover_backend *"
.Ft void
.Fn "dmover_backend_unregister" "struct dmover_backend *"
.Ft int
.Fn "dmover_session_create" "const char *, struct dmover_session **"
.Ft void
.Fn "dmover_session_destroy" "struct dmover_session *"
.Ft "struct dmover_request *"
.Fn "dmover_request_alloc" "struct dmover_session *"
.Ft void
.Fn "dmover_request_free" "struct dmover_request *"
.Ft void
.Fn "dmover_process" "struct dmover_request *"
.Ft void
.Fn "dmover_done" "struct dmover_request *"
.Sh DESCRIPTION
The
.Nm dmover
facility provides an interface to hardware-assisted data movers.  This
can be used to copy data from one location in memory to another, clear
a region of memory, fill a region of memory with a pattern, and perform
simple operations on multiple regions of memory, such as an XOR, without
intervention by the CPU.
.Pp
The drivers for hardware-assisted data movers present themselves to
.Nm dmover
by registering their capabilities.  When a client wishes to use a
.Nm dmover
function, it creates a session for that function, which automatically
selects the appropriate back-end.  The client then enqueues requests
on that session, which are processed asynchronously.  A call-back to
the client is made once the request has been completed.
.Pp
When a client creates a session, the
.Nm dmover
facility attempts to find the best back-end to handle that session by
scanning all of the registered back-ends and selecting the the back-end
with the lowest number of sessions, in an effort to balance load across
multiple hardware-assisted data movers.  If a hardware-assisted back-end
is not present, and the kernel is configured to provide a software
back-end for the specified function,
.Nm dmover
will fall back onto the software back-end.  The back-end selection
process will always favor a hardware-assisted back-end over a software
back-end, even if the software back-end has fewer sessions.
.Ss DATA STRUCTURES
The
.Nm dmover
facility shares several data structures between the client and
back-end in order to describe sessions and requests.
.Bd -literal -offset indent
typedef enum {
	DMOVER_BUF_LINEAR,
	DMOVER_BUF_UIO
} dmover_buf_t;

typedef union {
	void *dmover_bufptr_linear;
	struct uio *dmover_bufptr_uio;
} dmover_bufptr_t;
.Ed
.Pp
Together, these two data types are used to describe buffer data structures
which the
.Nm dmover
facility understands.
.Pp
The
.Em dmover_session
structure contains the following public members:
.Bl -tag -width "XXXX"
.It void *dses_cookie
This is a pointer to client private data.
.It const struct dmover_algdesc *dses_algdesc
This is a pointer to the back-end's algorithm description corresponding
to the session's selected
.Nm dmover
function.
.El
.Pp
The
.Em dmover_request
structure contains the following public members:
.Bl -tag -width "XXXX"
.It TAILQ_ENTRY(dmover_request) dreq_dmbq
Linkage on the back-end's queue of pending requests.
.It struct dmover_session *dreq_session
Pointer to the session with which this request is associated.  This
is intended for use by the back-end.
.It void (*dreq_callback)(struct dmover_request *)
This is a pointer to an optional call-back function provided by the
client.  If provided, the call-back is invoked when the request is
complete.
.It void *dreq_cookie
This is a pointer to client private data specific to the request.
.It __volatile int dreq_flags
The following flags are defined:
.Bl -tag -width "DMOVER_REQ_ERROR"
.It DMOVER_REQ_DONE
The request has been completed.  If not using a call-back, the client
may poll this bit to determine if a request has been processed.
.It DMOVER_REQ_ERROR
An error has occurred while processing the request.
.El
.It int dreq_error
If the
.Em DMOVER_REQ_ERROR
bit is set, this contains the
.Xr errno 2
value indicating the error that occurred during processing.
.It dreq_outbuf
This member is a structure describing the output buffer:
.Bd -literal
struct {
	dmover_bufptr_t dreq_outbuf_ptr;
	dmover_buf_t dreq_outbuf_type;
	size_t dreq_outbuf_len;
} dreq_outbuf;
#define dreq_outbuf_linear dreq_outbuf_ptr.dreq_bufptr_linear
#define dreq_outbuf_uio    dreq_outbuf_ptr.dreq_bufptr_uio
.Ed
.It uint8_t dreq_imm8
This is the input for algorithms which use an 8-bit immediate value.
.It uint16_t dreq_imm16
This is the input for algorithms which use a 16-bit immediate value.
.It uint32_t dreq_imm32
This is the input for algorithms which use a 32-bit immediate value.
.It uint64_t dreq_imm64
This is the input for algorithms which use a 64-bit immediate value.
.It dreq_inbuf
This member is an array of structures describing the input buffer(s):
.Bd -literal
struct {
	dmover_bufptr_t dreq_inbuf_ptr;
	dmover_buf_t dreq_inbuf_type;
	size_t dreq_inbuf_len;
} dreq_inbuf[];
#define dreq_inbuf_linear dreq_inbuf_ptr.dreq_bufptr_linear
#define dreq_inbuf_uio    dreq_inbuf_ptr.dreq_bufptr_uio
.Ed
.Pp
The number of inputs, and thus the number of valid elements in the array,
is specified by the algorithm description for the session.
.El
.Ss CLIENT INTERFACE
The following functions are provided to the client:
.Bl -tag -width "XXXX"
.It int Fn dmover_session_create "const char *function" \
    "struct dmover_session **sessionp"
.Pp
The
.Fn dmover_session_create
function creates a data mover session for the specied data movement
function
.Fa function .
A handle to the new session is returned in
.Fa *sessionp .
.Pp
The following are valid data movement function names:
.Bl -tag -width "fill32-block"
.It zero-block
Fill a memory region with zeros.  This algorithm has an input count of 0.
.It fill32-block
Fill a memory region with a 32-bit pattern.  This algorithm has an input
count of 0.  The pattern is provided in the
.Em dreq_imm32
member of the
.Em dreq_request
structure.
.It copy-block
Copy a memory region from one location to another.  This algorithm has an
input count of 1.
.El
.It void Fn dmover_session_destroy "struct dmover_session *session"
.Pp
The
.Fn dmover_session_destroy
function tears down a data mover session and releases all resources
associated with it.
.It struct dmover_request * Fn dmover_request_alloc \
    "struct dmover_session *session"
.Pp
The
.Fn dmover_request_alloc
function allocates a
.Nm dmover
request structure and associates it with the specified session.
.It void Fn dmover_request_free "struct dmover_request *req"
.Pp
The
.Fn dmover_request_free
function frees a
.Nm dmover
request structure.
.It void Fn dmover_process "struct dmover_request *req"
.Pp
The
.Fn dmover_process
function submits the
.Nm dmover
request
.Fa req
for processing.  The call-back specified by the request is
invoked when processing is complete.
.El
.Pp
The
.Fn dmover_session_create ,
.Fn dmover_session_destroy ,
.Fn dmover_request_alloc ,
and
.Fn dmover_request_free
functions must not be called from interrupt context.
.Pp
The
.Fn dmover_process
function may be called at
.Em IPL_BIO ,
.Em IPL_SOFTCLOCK ,
.Em IPL_SOFTNET ,
or in non-interrupt context.
.Pp
The request completion call-back is called at
.Em IPL_SOFTCLOCK .
.Ss BACK-END INTERFACE
A back-end describes the
.Nm dmover
functions it can perform using an array of
.Em dmover_algdesc
structures:
.Bd -literal -offset indent
struct dmover_algdesc {
	const char *dad_name;	/* algorithm name */
	void *dad_data;		/* opaque algorithm description */
	int dad_ninputs;	/* number of inputs */
};
.Ed
.Pp
The
.Em dad_name
member points to a valid
.Nm dmover
function name which the client may specify.  The
.Em dad_data
member points to a back-end-specific description of the algorithm.
.Pp
A back-end presents itself to the
.Nm dmover
facility using the
.Em dmover_backend
structure.  The back-end must initialize the following members
of the structure:
.Bl -tag -width "XXXX"
.It const char *dmb_name
This is the name of the back-end.
.It dmb_hwassist
This is an enumerated type indicating whether or not the back-end
is hardware assisted.  If the back-end is hardware assisted, this
also indicates the relative performance of the back-end:
.Bl -tag -width "DMOVER_HWASSIST_CACHEBUS"
.It DMOVER_HWASSIST_NONE
The back-end is not hardware assisted.
.It DMOVER_HWASSIST_IOBUS
The back-end is hardware assisted and the coprocessor is attached to
an I/O bus.
.It DMOVER_HWASSIST_MEMBUS
The back-end is hardware assisted and the coprocessor is attached to
the system memory bus.
.El
.It void *dmb_cookie
This is a pointer to back-end private data.
.It const struct dmover_algdesc *dmb_algdescs
This points to an array of
.Em dmover_algdesc
structures which describe the functions the data mover can perform.
.It int dmb_nalgdescs
This is the number of elements in the
.Em dmb_algdescs
array.
.It void (*dmb_process)(struct dmover_backend *)
This is the entry point to the back-end used to process requests.
.El
.Pp
When invoked by the
.Nm dmover
facility, the back-end's
.Fn (*dmb_process)
function should examine the pending request queue in it's
.Em dmover_backend
structure:
.Bl -tag -width "XXXX"
.It TAILQ_HEAD(, dmover_request) dmb_pendreqs
This is the queue of pending requests.
.It int dmb_npendreqs
This is the number of requests in the
.Em dmb_pendreqs
queue.
.El
.Pp
If an error occurs when processing the request, the
.Em DMOVER_REQ_ERROR
bit must be set in the
.Em dreq_flags
member of the request, and the
.Em dreq_error
member set to an
.Xr errno 2
value to indicate the error.
.Pp
When the back-end has finished processing the request, it must call
the
.Fn dmover_done
function.  This function eventually invokes the client's call-back
routine.
.Pp
The following functions are provided to the back-ends:
.Bl -tag -width "XXXX"
.It void Fn dmover_backend_register "struct dmover_backend *backend"
.Pp
The
.Fn dmover_backend_register
function registers the back-end
.Fa backend
with the
.Nm dmover
facility.
.It void Fn dmover_backend_unregister "struct dmover_backend *backend"
.Pp
The
.Fn dmover_backend_unregister
function removes the back-end
.Fa backend
from the
.Nm dmover
facility.  The back-end must already be registered.
.It void Fn dmover_done "struct dmover_request *req"
.Pp
The
.Fn dmover_done
function is called by the back-end when it has finished processing
a request, whether the request completed successfully or not.
.El
.Pp
The
.Fn dmover_backend_register
and
.Fn dmover_backend_unregister
functions must not be called from interrupt context.
.Pp
The
.Fn dmover_done
function may be called at
.Em IPL_BIO ,
.Em IPL_SOFTCLOCK ,
.Em IPL_SOFTNET ,
or in non-interrupt context.
.Ss EXAMPLE USAGE
The following is an example of a client using
.Nm dmover
to zero-fill a region of memory:
.Bd -literal
int
hw_bzero(void *buf, size_t len)
{
	struct dmover_session *dses;
	struct dmover_request *dreq;
	int error;

	error = dmover_session_create("zero-block", &dses);
	if (error)
		return (error);

	dreq = dmover_request_alloc(dses);
	if (dreq == NULL) {
		dmover_session_destroy(dses);
		return (ENOMEM);
	}

	dreq->dreq_callback = NULL;
	dreq->dreq_outbuf.dreq_outbuf_type = DMOVER_BUF_LINEAR;
	dreq->dreq_outbuf.dreq_outbuf_linear = buf;
	dreq->dreq_outbuf.dreq_outbuf_len = len;

	dmover_process(dreq);

	while ((dreq->dreq_flags & DMOVER_REQ_DONE) == 0)
		/* wait for completion */ ;

	error = (dreq->dreq_flags & DMOVER_REQ_ERROR) ?
	    dreq->dreq_error : 0;

	dmover_request_free(dreq);
	dmover_session_destroy(dses);

	return (error);
}
.Ed
.Sh SEE ALSO
.Xr queue 3
.Sh HISTORY
The
.Nm dmover
facility first appeared in
.Nx 2.0 .
.Sh AUTHOR
The
.Nm dmover
facility was designed and implemented by
.An Jason R. Thorpe
.Aq thorpej@wasabisystems.com
and contributed by Wasabi Systems, Inc.

--+xNpyl7Qekk2NvDX--