Sun Microsystems, Inc.
spacerspacer
spacer www.sun.com docs.sun.com |
spacer
black dot
 
 
8.  Direct Memory Access (DMA) Managing DMA Resources Programming the DMA Engine   Previous   Contents   Next 
   
 

Freeing the DMA Resources

After a DMA transfer is completed (usually in the interrupt routine), the driver can release DMA resources by calling ddi_dma_unbind_handle(9F).

As described in "Synchronizing Memory Objects", ddi_dma_unbind_handle(9F) calls ddi_dma_sync(9F), eliminating the need for any explicit synchronization. After calling ddi_dma_unbind_handle(9F), the DMA resources become invalid, and further references to them have undefined results. Example 8-5 shows how to use ddi_dma_unbind_handle(9F).


Example 8-5 Freeing DMA Resources

static uint_t
xxintr(caddr_t arg)
{
     struct xxstate *xsp = (struct xxstate *)arg;
     uint8_t    status;
        volatile   uint8_t   temp;
     mutex_enter(&xsp->mu);
     /* read status */
     status = ddi_get8(xsp->access_hdl, &xsp->regp->csr);
     if (!(status & INTERRUPTING)) {
            mutex_exit(&xsp->mu);
            return (DDI_INTR_UNCLAIMED);
     }
     ddi_put8(xsp->access_hdl, &xsp->regp->csr, CLEAR_INTERRUPT);
      /* for store buffers */
     temp = ddi_get8(xsp->access_hdl, &xsp->regp->csr);
     ddi_dma_unbind_handle(xsp->handle);
     ...
         /* check for errors */
     ...
     xsp->busy = 0;
     mutex_exit(&xsp->mu);
     if (pending transfers) {
            (void) xxstart((caddr_t)xsp);
     }
     return (DDI_INTR_CLAIMED);
}

The DMA resources should be released and reallocated if a different object will be used in the next transfer. However, if the same object is always used, the resources can be allocated once and continually reused as long as there are intervening calls to ddi_dma_sync(9F).

Freeing the DMA Handle

When the driver is detached, the DMA handle must be freed. ddi_dma_free_handle(9F) destroys the DMA handle and any residual resources the system is caching on the handle. Any further references of the DMA handle will have undefined results.

Canceling DMA Callbacks

DMA callbacks cannot be canceled. This requires some additional code in the drivers detach(9E) routine, as it must not return DDI_SUCCESS if there are any outstanding callbacks. (See Example 8-6.) When DMA callbacks occur, the detach(9E) routine must wait for the callback to run and must prevent it from rescheduling itself. This can be done using additional fields in the state structure, as shown below.


Example 8-6 Canceling DMA Callbacks

static int
xxdetach(dev_info_t *dip, ddi_detach_cmd_t cmd)
{
     ...
     mutex_enter(&xsp->callback_mutex);
     xsp->cancel_callbacks = 1;
     while (xsp->callback_count > 0) {
            cv_wait(&xsp->callback_cv, &xsp->callback_mutex);
     }
     mutex_exit(&xsp->callback_mutex);
     ...
 }

static int
xxstrategy(struct buf *bp)
{
     ...
     mutex_enter(&xsp->callback_mutex);
       xsp->bp = bp;
     error = ddi_dma_buf_bind_handle(xsp->handle, xsp->bp, flags,
                 xxdmacallback, (caddr_t)xsp, &cookie, &ccount);
     if (error == DDI_DMA_NORESOURCES)
           xsp->callback_count++;
     mutex_exit(&xsp->callback_mutex);
     ...
}

static int
xxdmacallback(caddr_t callbackarg)
{
     struct xxstate *xsp = (struct xxstate *)callbackarg;
     ...
     mutex_enter(&xsp->callback_mutex);
     if (xsp->cancel_callbacks) {
            /* do not reschedule, in process of detaching */
            xsp->callback_count--;
            if (xsp->callback_count == 0)
               cv_signal(&xsp->callback_cv);
            mutex_exit(&xsp->callback_mutex);
            return (DDI_DMA_CALLBACK_DONE);        /* don't reschedule it */
     }
     /*
        * Presumably at this point the device is still active
        * and will not be detached until the DMA has completed.
        * A return of 0 means try again later
        */
     error = ddi_dma_buf_bind_handle(xsp->handle, xsp->bp, flags,
                 DDI_DMA_DONTWAIT, NULL, &cookie, &ccount);
     if (error == DDI_DMA_MAPPED) {
            ...
            /* program the DMA engine */
             ...
            xsp->callback_count--;
            mutex_exit(&xsp->callback_mutex);
            return (DDI_DMA_CALLBACK_DONE);
     }
     if (error != DDI_DMA_NORESOURCES) {
            xsp->callback_count--;
            mutex_exit(&xsp->callback_mutex);
            return (DDI_DMA_CALLBACK_DONE);
     }
     mutex_exit(&xsp->callback_mutex);
     return (DDI_DMA_CALLBACK_RUNOUT);
}

 
 
 
  Previous   Contents   Next