DMOVER(9) | Kernel Developer's Manual | DMOVER(9) |
dmover_backend_register
,
dmover_backend_unregister
,
dmover_session_create
,
dmover_session_destroy
,
dmover_request_alloc
,
dmover_request_free
,
dmover_process
, dmover_done
—
#include
<dev/dmover/dmovervar.h>
Client interface routines:
int
dmover_session_create
(const
char *, struct
dmover_session **);
void
dmover_session_destroy
(struct
dmover_session *);
struct dmover_request *
dmover_request_alloc
(struct
dmover_session *,
dmover_buffer *);
void
dmover_request_free
(struct
dmover_request *);
void
dmover_process
(struct
dmover_request *);
Back-end interface routines:
void
dmover_backend_register
(struct
dmover_backend *);
void
dmover_backend_unregister
(struct
dmover_backend *);
void
dmover_done
(struct
dmover_request *);
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.
The drivers for hardware-assisted data movers present themselves
to dmover
by registering their capabilities. When a
client wishes to use a dmover
function, it creates a
session for that function, which identifies back-ends capable of performing
that function. The client then enqueues requests on that session, which the
back-ends process asynchronously. The client may choose to block until the
request is completed, or may have a call-back invoked once the request has
been completed.
When a client creates a session, the
dmover
facility identifies back-ends which are
capable of handling the requested function. When a request is scheduled for
processing, the dmover
scheduler will identify the
best back-end to process the request from the list of candidate back-ends,
in an effort to provide load balancing, while considering the relative
performance of each back-end.
A dmover
function always has one output
region. A function may have zero or more input regions, or may use an
immediate value as an input. For functions which use input regions, the
lengths of each input region and the output region must be the same. All
dmover
functions with the same name will have the
same number of and type inputs. If a back-end attempts to register a
function which violates this invariant, behavior is undefined.
The dmover
facility supports several types
of buffer descriptors. For functions which use input regions, each input
buffer descriptor and the output buffer descriptor must be of the same type.
This restriction may be removed in a future revision of the interface.
The dmover
facility may need to interrupt
request processing and restart it. Clients of the
dmover
facility should take care to avoid unwanted
side-effects should this occur. In particular, for functions which use input
regions, no input region may overlap with the output region.
dmover
facility shares several data structures
between the client and back-end in order to describe sessions and requests.
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;
Together, these data types are used to describe buffer data
structures which the dmover
facility understands.
Additional buffer types may be added in future revisions of the
dmover
interface.
The dmover_assignment structure contains the information about the back-end to which a request is currently assigned. It contains the following public members:
The dmover_session structure contains the following public members:
The dmover_request structure contains the following public members:
dmover_process
().NULL
if
DMOVER_REQ_WAIT is set in
dreq_flags.dmover_process
() will
wait for the request to complete using
cv_wait(9). This flag
may only be used if the caller has a valid thread context. If this
flag is set, a callback may not be used.dmover
function has one or more inputs.dmover
function has one or more inputs. The number
of inputs, and thus the number of valid elements in the array, is
specified by the algorithm description for the session.dmover_session_create
(function,
sessionp)The dmover_session_create
() function
creates a data mover session for the specified data movement function
function. A handle to the new session is returned
in sessionp.
The following are valid data movement function names:
Users of the dmover
facility are
encouraged to use the following aliases for the well-known function
names, as doing so saves space and reduces the chance of programming
errors:
dmover_session_destroy
(session)The dmover_session_destroy
() function
tears down a data mover session and releases all resources associated
with it.
dmover_request_alloc
(session,
inbuf)The dmover_request_alloc
() function
allocates a dmover
request structure and
associates it with the specified session. If the
inbuf argument is not
NULL
, inbuf is used as the
array of input buffer descriptors in the request. Otherwise, if
inbuf is NULL
and the
dmover
function requires input buffers, the
input buffer descriptors will be allocated automatically using
malloc(9).
If the request structure or input buffer descriptors cannot be
allocated, dmover_request_alloc
() return
NULL
to indicate failure.
dmover_request_free
(req)The dmover_request_free
() function
frees a dmover
request structure. If the
dmover
function requires input buffers, and the
input buffer descriptors associated with req were
allocated by dmover_request_alloc
(), then the
input buffer descriptors will also be freed.
dmover_process
(req)The dmover_process
() function submits
the dmover
request req for
processing. The call-back specified by the request is invoked when
processing is complete.
The dmover_session_create
() and
dmover_session_destroy
() functions must not be
called from interrupt context.
The dmover_request_alloc
(),
dmover_request_free
(), and
dmover_process
() functions may be called from
interrupt handlers at levels IPL_VM,
IPL_SOFTCLOCK, and IPL_SOFTNET, or in
non-interrupt context.
The request completion call-back is called from a software interrupt handler at IPL_SOFTCLOCK.
dmover
functions it can perform
using an array of dmover_algdesc structures:
struct dmover_algdesc { const char *dad_name; /* algorithm name */ void *dad_data; /* opaque algorithm description */ int dad_ninputs; /* number of inputs */ };
The dad_name member points to a valid
dmover
function name which the client may specify.
The dad_data member points to a back-end-specific
description of the algorithm.
A back-end presents itself to the dmover
facility using the dmover_backend structure. The
back-end must initialize the following members of the structure:
When invoked by the dmover
facility, the
back-end's (*dmb_process)
() function should examine
the pending request queue in its dmover_backend
structure:
If an error occurs when processing the request, the DMOVER_REQ_ERROR bit must be set in the dreq_flags member of the request, and the dreq_error member set to an errno(2) value to indicate the error.
When the back-end has finished processing the request, it must
call the dmover_done
() function. This function
eventually invokes the client's call-back routine.
If a hardware-assisted data mover uses interrupts, the interrupt handlers should be registered at IPL_VM.
The following functions are provided to the back-ends:
dmover_backend_register
(backend)The dmover_backend_register
() function
registers the back-end backend with the
dmover
facility.
dmover_backend_unregister
(backend)The dmover_backend_unregister
()
function removes the back-end backend from the
dmover
facility. The back-end must already be
registered.
dmover_done
(req)The dmover_done
() function is called
by the back-end when it has finished processing a request, whether the
request completed successfully or not.
The dmover_backend_register
() and
dmover_backend_unregister
() functions must not be
called from interrupt context.
The dmover_done
() function may be called
at IPL_VM, IPL_SOFTCLOCK,
IPL_SOFTNET, or in non-interrupt context.
dmover
to
zero-fill a region of memory. In this example, the CPU will be able to context
switch to another thread and perform work while the hardware-assisted data
mover clears the specified block of memory.
int hw_bzero(void *buf, size_t len) { struct dmover_session *dses; struct dmover_request *dreq; int error; error = dmover_session_create(DMOVER_FUNC_ZERO, &dses); if (error) return (error); dreq = dmover_request_alloc(dses, NULL); if (dreq == NULL) { dmover_session_destroy(dses); return (ENOMEM); } dreq->dreq_flags = DMOVER_REQ_WAIT; dreq->dreq_callback = NULL; dreq->dreq_outbuf.dreq_outbuf_type = DMOVER_BUF_LINEAR; dreq->dreq_outbuf.dmbuf_linear.l_addr = buf; dreq->dreq_outbuf.dmbuf_linear.l_len = len; dmover_process(dreq); error = (dreq->dreq_flags & DMOVER_REQ_ERROR) ? dreq->dreq_error : 0; dmover_request_free(dreq); dmover_session_destroy(dses); return (error); }
dmover
facility first appeared in
NetBSD 2.0.
dmover
facility was designed and implemented by
Jason R. Thorpe
⟨thorpej@wasabisystems.com⟩ and contributed by Wasabi Systems,
Inc.
December 4, 2007 | NetBSD 9.0 |