Sun Microsystems, Inc.
spacerspacer
spacer www.sun.com docs.sun.com |
spacer
black dot
 
 
13.  Device Context Management Context Management Operation Device Context Management Entry Points  Previous   Contents   Next 
   
 

devmap() Entry Point

The syntax for devmap(9E) is:

int xxdevmap_map(devmap_cookie_t handle, dev_t dev, uint_t flags,
    offset_t offset, size_t len, void **new_devprivate);

This entry point is called after the driver returns from its devmap() entry point and the system has established the user mapping to the device memory. The devmap() entry point enables a driver to perform additional processing or to allocate mapping specific private data. For example, in order to support context switching, the driver has to allocate a context structure and associate it with the mapping.

The system expects the driver to return a pointer to the allocated private data in *new_devprivate. The driver must store offset and len, which define the range of the mapping, in its private data. Later, when the system calls devmap_unmap(9E), the driver will use offset and len stored in new_devprivate to check if the entire mapping, or just a part of it, is being unmapped.

flags indicates whether the driver should allocate a private context for the mapping. For example, a driver can allocate a memory region to store the device context if flags is set to MAP_PRIVATE, or it might return a pointer to a shared region if MAP_SHARED is set.

Example 13-1 shows an example of a devmap() entry point. The driver allocates a new context structure and saves relevant parameters passed in by the entry point. Then the mapping is assigned a new context by either allocating a new one or attaching it to an already existing shared context. The minimum time interval that the mapping should have access to the device is set to one millisecond.


Example 13-1 devmap(9E) Routine

static int
int xxdevmap_map(devmap_cookie_t handle, dev_t dev, uint_t flags,
    offset_t offset, size_t len, void **new_devprivate)
{
        struct xxstate *xsp = ddi_get_soft_state(statep,
                              getminor(dev));
        struct xxctx *newctx;

        /* create a new context structure */
        newctx = kmem_alloc(sizeof (struct xxctx), KM_SLEEP);
        newctx->xsp = xsp;
        newctx->handle = handle;
        newctx->offset = offset;
        newctx->flags = flags;
        newctx->len = len;
        mutex_enter(&xsp->ctx_lock);
        if (flags & MAP_PRIVATE) {
                /* allocate a private context and initialize it */
                newctx->context = kmem_alloc(XXCTX_SIZE, KM_SLEEP);
                xxctxinit(newctx);
        } else {
                /* set a pointer to the shared context */
                newctx->context = xsp->ctx_shared;
        }
        mutex_exit(&xsp->ctx_lock);
        /* give at least 1 ms access before context switching */
        devmap_set_ctx_timeout(handle, drv_usectohz(1000));
        /* return the context strcuture */
        *new_devprivate = newctx;
        return(0);
}

devmap_access() Entry Point

The syntax for devmap_access(9E) is:

int xxdevmap_access(devmap_cookie_t handle, void *devprivate,
    offset_t offset, size_t len, uint_t type, uint_t rw);

This entry point is called when an access is made to a mapping whose translations are invalid. Mapping translations are invalidated when the mapping is created with devmap_devmem_setup(9F) in response to mmap(2), duplicated by fork(2), or explicitly invalidated by a call to devmap_unload(9F).

handle

Mapping handle of the mapping that was accessed by a user process.

devprivate

Pointer to the driver private data associated with the mapping.

offset

Offset within the mapping that was accessed.

len

Length in bytes of the memory being accessed.

type

Type of access operation.

rw

Specifies the direction of access.

The system expects devmap_access(9E) to call either devmap_do_ctxmgt(9F) or devmap_default_access(9F) to load the memory address translations before it returns. For mappings that support context switching, the device driver should call devmap_do_ctxmgt(9F). This routine is passed all parameters from devmap_access(9E), as well as a pointer to the driver entry point devmap_contextmgt(9E), which handles the context switching. For mappings that do not support context switching, the driver should call devmap_default_access(9F), whose only purpose is to call devmap_load(9F) to load the user translation.

Example 13-2 shows an example of a devmap_access(9E) entry point. The mapping is divided into two regions. The region starting at offset OFF_CTXMG with a length of CTXMGT_SIZE bytes supports context management. The rest of the mapping supports default access.


Example 13-2 devmap_access(9E) Routine

#define OFF_CTXMG          0
#define CTXMGT_SIZE        0x20000        
static int
xxdevmap_access(devmap_cookie_t handle, void *devprivate,
    offset_t off, size_t len, uint_t type, uint_t rw)
{
        offset_t diff;
        int    error;

        if ((diff = off - OFF_CTXMG) >= 0 && diff < CTXMGT_SIZE) {
                error = devmap_do_ctxmgt(handle, devprivate, off,
                        len, type, rw, xxdevmap_contextmgt);
        } else {
                error = devmap_default_access(handle, devprivate,
                        off, len, type, rw);
        }
        return (error);
}

devmap_contextmgt() Entry Point

The syntax for devmap_contextmgt(9E) is:

int xxdevmap_contextmgt(devmap_cookie_t handle, void *devprivate,
    offset_t offset, size_t len, uint_t type, uint_t rw);

In general, devmap_contextmgt() should call devmap_unload(9F), with the handle of the mapping that currently has access to the device, to invalidate the translations for that mapping. This ensures that a call to devmap_access(9E) occurs for the current mapping the next time it is accessed. To validate the mapping translations for the mapping that caused the access event to occur, the driver must restore the device context for the process requesting access and call devmap_load(9F) on the handle of the mapping that generated the call to this entry point.

Accesses to portions of mappings that have had their mapping translations validated by a call to devmap_load() do not generate a call to devmap_access(). A subsequent call to devmap_unload() invalidates the mapping translations and allows devmap_access() to be called again.

If either devmap_load() or devmap_unload() returns an error, devmap_contextmgt() should immediately return that error. If the device driver encounters a hardware failure while restoring a device context, a -1 should be returned. Otherwise, after successfully handling the access request, devmap_contextmgt() should return zero. A return of other than zero from devmap_contextmgt() will cause a SIGBUS or SIGSEGV to be sent to the process.

Example 13-3 shows how to manage a one-page device context.


Note - xxctxsave() and xxctxrestore() are device-dependent context save and restore functions. xxctxsave() reads data from the registers using the Solaris 9 DDI/DKI data access routines and saves it in the soft state structure. xxctxrestore() takes data saved in the soft state structure and writes it to device registers using the Solaris 9 DDI/DKI data access routines.



Example 13-3 devmap_contextmgt(9E) Routine

static int
xxdevmap_contextmgt(devmap_cookie_t handle, void *devprivate,
    offset_t off, size_t len, uint_t type, uint_t rw)
{
        int    error;
        struct xxctx *ctxp = devprivate;
        struct xxstate *xsp = ctxp->xsp;
        mutex_enter(&xsp->ctx_lock);
        /* unload mapping for current context */
        if (xsp->current_ctx != NULL) {
                if ((error = devmap_unload(xsp->current_ctx->handle,
                    off, len)) != 0) {
                        xsp->current_ctx = NULL;
                        mutex_exit(&xsp->ctx_lock);
                        return (error);
                }
        }
        /* Switch device context - device dependent */
        if (xxctxsave(xsp->current_ctx, off, len) < 0) {
                xsp->current_ctx = NULL;
                mutex_exit(&xsp->ctx_lock);
                return (-1);
        }
        if (xxctxrestore(ctxp, off, len) < 0){
                xsp->current_ctx = NULL;
                mutex_exit(&xsp->ctx_lock);
                return (-1);
        }
        xsp->current_ctx = ctxp;
        /* establish mapping for new context and return */
        error = devmap_load(handle, off, len, type, rw);
        if (error)
                xsp->current_ctx = NULL;
        mutex_exit(&xsp->ctx_lock);
        return (error);
}

 
 
 
  Previous   Contents   Next