patch-2_6_7-vs1_9_1_12
[linux-2.6.git] / drivers / char / drm / drm_dma.h
1 /**
2  * \file drm_dma.h 
3  * DMA IOCTL and function support
4  *
5  * \author Rickard E. (Rik) Faith <faith@valinux.com>
6  * \author Gareth Hughes <gareth@valinux.com>
7  */
8
9 /*
10  * Created: Fri Mar 19 14:30:16 1999 by faith@valinux.com
11  *
12  * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
13  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
14  * All Rights Reserved.
15  *
16  * Permission is hereby granted, free of charge, to any person obtaining a
17  * copy of this software and associated documentation files (the "Software"),
18  * to deal in the Software without restriction, including without limitation
19  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
20  * and/or sell copies of the Software, and to permit persons to whom the
21  * Software is furnished to do so, subject to the following conditions:
22  *
23  * The above copyright notice and this permission notice (including the next
24  * paragraph) shall be included in all copies or substantial portions of the
25  * Software.
26  *
27  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
30  * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
31  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
32  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
33  * OTHER DEALINGS IN THE SOFTWARE.
34  */
35
36 #include "drmP.h"
37
38
39 #ifndef __HAVE_DMA_WAITQUEUE
40 #define __HAVE_DMA_WAITQUEUE    0
41 #endif
42 #ifndef __HAVE_DMA_RECLAIM
43 #define __HAVE_DMA_RECLAIM      0
44 #endif
45
46 #if __HAVE_DMA
47
48 /**
49  * Initialize the DMA data.
50  * 
51  * \param dev DRM device.
52  * \return zero on success or a negative value on failure.
53  *
54  * Allocate and initialize a drm_device_dma structure.
55  */
56 int DRM(dma_setup)( drm_device_t *dev )
57 {
58         int i;
59
60         dev->dma = DRM(alloc)( sizeof(*dev->dma), DRM_MEM_DRIVER );
61         if ( !dev->dma )
62                 return -ENOMEM;
63
64         memset( dev->dma, 0, sizeof(*dev->dma) );
65
66         for ( i = 0 ; i <= DRM_MAX_ORDER ; i++ )
67                 memset(&dev->dma->bufs[i], 0, sizeof(dev->dma->bufs[0]));
68
69         return 0;
70 }
71
72 /**
73  * Cleanup the DMA resources.
74  *
75  * \param dev DRM device.
76  *
77  * Free all pages associated with DMA buffers, the buffers and pages lists, and
78  * finally the the drm_device::dma structure itself.
79  */
80 void DRM(dma_takedown)(drm_device_t *dev)
81 {
82         drm_device_dma_t  *dma = dev->dma;
83         int               i, j;
84
85         if (!dma) return;
86
87                                 /* Clear dma buffers */
88         for (i = 0; i <= DRM_MAX_ORDER; i++) {
89                 if (dma->bufs[i].seg_count) {
90                         DRM_DEBUG("order %d: buf_count = %d,"
91                                   " seg_count = %d\n",
92                                   i,
93                                   dma->bufs[i].buf_count,
94                                   dma->bufs[i].seg_count);
95                         for (j = 0; j < dma->bufs[i].seg_count; j++) {
96                                 if (dma->bufs[i].seglist[j]) {
97                                         DRM(free_pages)(dma->bufs[i].seglist[j],
98                                                         dma->bufs[i].page_order,
99                                                         DRM_MEM_DMA);
100                                 }
101                         }
102                         DRM(free)(dma->bufs[i].seglist,
103                                   dma->bufs[i].seg_count
104                                   * sizeof(*dma->bufs[0].seglist),
105                                   DRM_MEM_SEGS);
106                 }
107                 if (dma->bufs[i].buf_count) {
108                         for (j = 0; j < dma->bufs[i].buf_count; j++) {
109                                 if (dma->bufs[i].buflist[j].dev_private) {
110                                         DRM(free)(dma->bufs[i].buflist[j].dev_private,
111                                                   dma->bufs[i].buflist[j].dev_priv_size,
112                                                   DRM_MEM_BUFS);
113                                 }
114                         }
115                         DRM(free)(dma->bufs[i].buflist,
116                                   dma->bufs[i].buf_count *
117                                   sizeof(*dma->bufs[0].buflist),
118                                   DRM_MEM_BUFS);
119 #if __HAVE_DMA_FREELIST
120                         DRM(freelist_destroy)(&dma->bufs[i].freelist);
121 #endif
122                 }
123         }
124
125         if (dma->buflist) {
126                 DRM(free)(dma->buflist,
127                           dma->buf_count * sizeof(*dma->buflist),
128                           DRM_MEM_BUFS);
129         }
130
131         if (dma->pagelist) {
132                 DRM(free)(dma->pagelist,
133                           dma->page_count * sizeof(*dma->pagelist),
134                           DRM_MEM_PAGES);
135         }
136         DRM(free)(dev->dma, sizeof(*dev->dma), DRM_MEM_DRIVER);
137         dev->dma = NULL;
138 }
139
140
141 /**
142  * Free a buffer.
143  *
144  * \param dev DRM device.
145  * \param buf buffer to free.
146  * 
147  * Resets the fields of \p buf.
148  */
149 void DRM(free_buffer)(drm_device_t *dev, drm_buf_t *buf)
150 {
151         if (!buf) return;
152
153         buf->waiting  = 0;
154         buf->pending  = 0;
155         buf->filp     = 0;
156         buf->used     = 0;
157
158         if ( __HAVE_DMA_WAITQUEUE && waitqueue_active(&buf->dma_wait)) {
159                 wake_up_interruptible(&buf->dma_wait);
160         }
161 #if __HAVE_DMA_FREELIST
162         else {
163                 drm_device_dma_t *dma = dev->dma;
164                                 /* If processes are waiting, the last one
165                                    to wake will put the buffer on the free
166                                    list.  If no processes are waiting, we
167                                    put the buffer on the freelist here. */
168                 DRM(freelist_put)(dev, &dma->bufs[buf->order].freelist, buf);
169         }
170 #endif
171 }
172
173 #if !__HAVE_DMA_RECLAIM
174 /**
175  * Reclaim the buffers.
176  *
177  * \param filp file pointer.
178  *
179  * Frees each buffer associated with \p filp not already on the hardware.
180  */
181 void DRM(reclaim_buffers)( struct file *filp )
182 {
183         drm_file_t    *priv   = filp->private_data;
184         drm_device_t  *dev    = priv->dev;
185         drm_device_dma_t *dma = dev->dma;
186         int              i;
187
188         if (!dma) return;
189         for (i = 0; i < dma->buf_count; i++) {
190                 if (dma->buflist[i]->filp == filp) {
191                         switch (dma->buflist[i]->list) {
192                         case DRM_LIST_NONE:
193                                 DRM(free_buffer)(dev, dma->buflist[i]);
194                                 break;
195                         case DRM_LIST_WAIT:
196                                 dma->buflist[i]->list = DRM_LIST_RECLAIM;
197                                 break;
198                         default:
199                                 /* Buffer already on hardware. */
200                                 break;
201                         }
202                 }
203         }
204 }
205 #endif
206
207 #if !__HAVE_IRQ
208 /* This stub DRM_IOCTL_CONTROL handler is for the drivers that used to require
209  * IRQs for DMA but no longer do.  It maintains compatibility with the X Servers
210  * that try to use the control ioctl by simply returning success.
211  */
212 int DRM(control)( struct inode *inode, struct file *filp,
213                   unsigned int cmd, unsigned long arg )
214 {
215         drm_control_t ctl;
216
217         if ( copy_from_user( &ctl, (drm_control_t *)arg, sizeof(ctl) ) )
218                 return -EFAULT;
219
220         switch ( ctl.func ) {
221         case DRM_INST_HANDLER:
222         case DRM_UNINST_HANDLER:
223                 return 0;
224         default:
225                 return -EINVAL;
226         }
227 }
228 #endif
229
230 #endif /* __HAVE_DMA */