1 /*
   2  * drm_dma.c -- DMA IOCTL and function support -*- linux-c -*-
   3  * Created: Fri Mar 19 14:30:16 1999 by faith@valinux.com
   4  */
   5 /*
   6  * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
   7  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
   8  * All Rights Reserved.
   9  *
  10  * Permission is hereby granted, free of charge, to any person obtaining a
  11  * copy of this software and associated documentation files (the "Software"),
  12  * to deal in the Software without restriction, including without limitation
  13  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  14  * and/or sell copies of the Software, and to permit persons to whom the
  15  * Software is furnished to do so, subject to the following conditions:
  16  *
  17  * The above copyright notice and this permission notice (including the next
  18  * paragraph) shall be included in all copies or substantial portions of the
  19  * Software.
  20  *
  21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  22  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  24  * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
  25  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  26  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  27  * OTHER DEALINGS IN THE SOFTWARE.
  28  *
  29  * Authors:
  30  *    Rickard E. (Rik) Faith <faith@valinux.com>
  31  *    Gareth Hughes <gareth@valinux.com>
  32  *
  33  */
  34 
  35 /*
  36  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  37  * Use is subject to license terms.
  38  */
  39 
  40 #pragma ident   "%Z%%M% %I%     %E% SMI"
  41 
  42 #include "drmP.h"
  43 
  44 int
  45 drm_dma_setup(drm_device_t *dev)
  46 {
  47         int i;
  48         drm_buf_entry_t *pbuf;
  49 
  50         dev->dma = drm_calloc(1, sizeof (*dev->dma), DRM_MEM_DMA);
  51         if (dev->dma == NULL)
  52                 return (ENOMEM);
  53 
  54         mutex_init(&dev->dma_lock, NULL, MUTEX_DRIVER, NULL);
  55         pbuf = &(dev->dma->bufs[0]);
  56         for (i = 0; i <= DRM_MAX_ORDER; i++, pbuf++)
  57                 bzero(pbuf, sizeof (drm_buf_entry_t));
  58 
  59         return (0);
  60 }
  61 
  62 void
  63 drm_dma_takedown(drm_device_t *dev)
  64 {
  65         drm_device_dma_t  *dma = dev->dma;
  66         int i, j;
  67 
  68         if (dma == NULL)
  69                 return;
  70 
  71         /* Clear dma buffers */
  72         for (i = 0; i <= DRM_MAX_ORDER; i++) {
  73                 if (dma->bufs[i].seg_count) {
  74                         drm_free(dma->bufs[i].seglist,
  75                             dma->bufs[i].seg_count *
  76                             sizeof (*dma->bufs[0].seglist), DRM_MEM_SEGS);
  77                 }
  78 
  79                 for (j = 0; j < dma->bufs[i].buf_count; j++) {
  80                         if (dma->bufs[i].buflist[j].dev_private) {
  81                                 drm_free(dma->bufs[i].buflist[j].dev_private,
  82                                     dma->bufs[i].buflist[j].dev_priv_size,
  83                                     DRM_MEM_BUFS);
  84                         }
  85                 }
  86                 if (dma->bufs[i].buf_count)
  87                         drm_free(dma->bufs[i].buflist,
  88                             dma->bufs[i].buf_count *
  89                             sizeof (*dma->bufs[0].buflist), DRM_MEM_BUFS);
  90         }
  91         if (dma->buflist) {
  92                 drm_free(dma->buflist,
  93                     dma->buf_count *sizeof (*dma->buflist),
  94                     DRM_MEM_BUFS);
  95         }
  96 
  97         if (dma->pagelist) {
  98                 drm_free(dma->pagelist,
  99                     dma->page_count *sizeof (*dma->pagelist),
 100                     DRM_MEM_PAGES);
 101         }
 102 
 103         drm_free(dev->dma, sizeof (*dev->dma), DRM_MEM_DRIVER);
 104         dev->dma = NULL;
 105         mutex_destroy(&dev->dma_lock);
 106 }
 107 
 108 
 109 /*ARGSUSED*/
 110 void
 111 drm_free_buffer(drm_device_t *dev, drm_buf_t *buf)
 112 {
 113         if (!buf)
 114                 return;
 115 
 116         buf->pending = 0;
 117         buf->filp    = NULL;
 118         buf->used    = 0;
 119 }
 120 
 121 void
 122 drm_reclaim_buffers(drm_device_t *dev, drm_file_t *fpriv)
 123 {
 124         drm_device_dma_t *dma = dev->dma;
 125         int i;
 126 
 127         if (!dma)
 128                 return;
 129         for (i = 0; i < dma->buf_count; i++) {
 130                 if (dma->buflist[i]->filp == fpriv) {
 131                         switch (dma->buflist[i]->list) {
 132                         case DRM_LIST_NONE:
 133                                 drm_free_buffer(dev, dma->buflist[i]);
 134                                 break;
 135                         case DRM_LIST_WAIT:
 136                                 dma->buflist[i]->list = DRM_LIST_RECLAIM;
 137                                 break;
 138                         default:
 139                                 /* Buffer already on hardware. */
 140                                 break;
 141                         }
 142                 }
 143         }
 144 }
 145 
 146 /* Call into the driver-specific DMA handler */
 147 int
 148 drm_dma(DRM_IOCTL_ARGS)
 149 {
 150         DRM_DEVICE;
 151 
 152         if (dev->driver->dma_ioctl) {
 153                 return (dev->driver->dma_ioctl(dev, data, fpriv, mode));
 154         } else {
 155                 return (EINVAL);
 156         }
 157 }