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 *
)
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.
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_assignment
structure which describes the back-end to which the request is
currently assigned.
The back-end is assigned when the request is scheduled with
dmover_process(
).
NULL
if
DMOVER_REQ_WAIT
is set in
dreq_flags.
)
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.
, const char *function
, struct dmover_session **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:
dmover_request
structure.
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:
, struct dmover_session *session
)
The
dmover_session_destroy()
function tears down a data mover session and releases all resources
associated with it.
, struct dmover_session *session
, dmover_buffer *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.
, struct dmover_request *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.
, struct dmover_request *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_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:
dmover_algdesc
structures which describe the functions the data mover can perform.
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:
, struct dmover_backend *backend
)
The
dmover_backend_register()
function registers the back-end
backend
with the
dmover
facility.
, struct dmover_backend *backend
)
The
dmover_backend_unregister()
function removes the back-end
backend
from the
dmover
facility.
The back-end must already be registered.
, struct dmover_request *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.
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);
}