Initial import from FreeBSD RELENG_4:
[games.git] / sys / dev / drm / drm_dma.h
1 /* drm_dma.c -- DMA IOCTL and function support -*- linux-c -*-
2  * Created: Fri Mar 19 14:30:16 1999 by faith@valinux.com
3  *
4  * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
5  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
6  * All Rights Reserved.
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a
9  * copy of this software and associated documentation files (the "Software"),
10  * to deal in the Software without restriction, including without limitation
11  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12  * and/or sell copies of the Software, and to permit persons to whom the
13  * Software is furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice (including the next
16  * paragraph) shall be included in all copies or substantial portions of the
17  * Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
22  * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
23  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25  * OTHER DEALINGS IN THE SOFTWARE.
26  *
27  * Authors:
28  *    Rickard E. (Rik) Faith <faith@valinux.com>
29  *    Gareth Hughes <gareth@valinux.com>
30  *
31  * $FreeBSD: src/sys/dev/drm/drm_dma.h,v 1.5.2.1 2003/04/26 07:05:28 anholt Exp $
32  */
33
34 #include "dev/drm/drmP.h"
35
36 #ifndef __HAVE_DMA_WAITQUEUE
37 #define __HAVE_DMA_WAITQUEUE    0
38 #endif
39 #ifndef __HAVE_DMA_RECLAIM
40 #define __HAVE_DMA_RECLAIM      0
41 #endif
42 #ifndef __HAVE_SHARED_IRQ
43 #define __HAVE_SHARED_IRQ       0
44 #endif
45
46 #if __HAVE_DMA
47
48 int DRM(dma_setup)( drm_device_t *dev )
49 {
50         int i;
51
52         dev->dma = DRM(alloc)( sizeof(*dev->dma), DRM_MEM_DRIVER );
53         if ( !dev->dma )
54                 return DRM_ERR(ENOMEM);
55
56         memset( dev->dma, 0, sizeof(*dev->dma) );
57
58         for ( i = 0 ; i <= DRM_MAX_ORDER ; i++ )
59                 memset(&dev->dma->bufs[i], 0, sizeof(dev->dma->bufs[0]));
60
61         return 0;
62 }
63
64 void DRM(dma_takedown)(drm_device_t *dev)
65 {
66         drm_device_dma_t  *dma = dev->dma;
67         int               i, j;
68
69         if (!dma) return;
70
71                                 /* Clear dma buffers */
72         for (i = 0; i <= DRM_MAX_ORDER; i++) {
73                 if (dma->bufs[i].seg_count) {
74                         DRM_DEBUG("order %d: buf_count = %d,"
75                                   " seg_count = %d\n",
76                                   i,
77                                   dma->bufs[i].buf_count,
78                                   dma->bufs[i].seg_count);
79                         for (j = 0; j < dma->bufs[i].seg_count; j++) {
80                                 DRM(free)((void *)dma->bufs[i].seglist[j],
81                                                 dma->bufs[i].buf_size,
82                                                 DRM_MEM_DMA);
83                         }
84                         DRM(free)(dma->bufs[i].seglist,
85                                   dma->bufs[i].seg_count
86                                   * sizeof(*dma->bufs[0].seglist),
87                                   DRM_MEM_SEGS);
88                 }
89                 if(dma->bufs[i].buf_count) {
90                         for(j = 0; j < dma->bufs[i].buf_count; j++) {
91                            if(dma->bufs[i].buflist[j].dev_private) {
92                               DRM(free)(dma->bufs[i].buflist[j].dev_private,
93                                         dma->bufs[i].buflist[j].dev_priv_size,
94                                         DRM_MEM_BUFS);
95                            }
96                         }
97                         DRM(free)(dma->bufs[i].buflist,
98                                   dma->bufs[i].buf_count *
99                                   sizeof(*dma->bufs[0].buflist),
100                                   DRM_MEM_BUFS);
101                 }
102         }
103
104         if (dma->buflist) {
105                 DRM(free)(dma->buflist,
106                           dma->buf_count * sizeof(*dma->buflist),
107                           DRM_MEM_BUFS);
108         }
109
110         if (dma->pagelist) {
111                 DRM(free)(dma->pagelist,
112                           dma->page_count * sizeof(*dma->pagelist),
113                           DRM_MEM_PAGES);
114         }
115         DRM(free)(dev->dma, sizeof(*dev->dma), DRM_MEM_DRIVER);
116         dev->dma = NULL;
117 }
118
119
120 void DRM(free_buffer)(drm_device_t *dev, drm_buf_t *buf)
121 {
122         if (!buf) return;
123
124         buf->pending  = 0;
125         buf->filp     = NULL;
126         buf->used     = 0;
127 }
128
129 #if !__HAVE_DMA_RECLAIM
130 void DRM(reclaim_buffers)(drm_device_t *dev, DRMFILE filp)
131 {
132         drm_device_dma_t *dma = dev->dma;
133         int              i;
134
135         if (!dma) return;
136         for (i = 0; i < dma->buf_count; i++) {
137                 if (dma->buflist[i]->filp == filp) {
138                         switch (dma->buflist[i]->list) {
139                         case DRM_LIST_NONE:
140                                 DRM(free_buffer)(dev, dma->buflist[i]);
141                                 break;
142                         case DRM_LIST_WAIT:
143                                 dma->buflist[i]->list = DRM_LIST_RECLAIM;
144                                 break;
145                         default:
146                                 /* Buffer already on hardware. */
147                                 break;
148                         }
149                 }
150         }
151 }
152 #endif
153
154
155 #if __HAVE_DMA_IRQ
156
157 int DRM(irq_install)( drm_device_t *dev, int irq )
158 {
159         int retcode;
160
161         if ( !irq )
162                 return DRM_ERR(EINVAL);
163
164         DRM_LOCK;
165         if ( dev->irq ) {
166                 DRM_UNLOCK;
167                 return DRM_ERR(EBUSY);
168         }
169         dev->irq = irq;
170         DRM_UNLOCK;
171
172         DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, irq );
173
174         dev->context_flag = 0;
175
176         dev->dma->next_buffer = NULL;
177         dev->dma->this_buffer = NULL;
178
179 #if __HAVE_DMA_IRQ_BH
180         TASK_INIT(&dev->task, 0, DRM(dma_immediate_bh), dev);
181 #endif
182
183 #if __HAVE_VBL_IRQ && 0 /* disabled */
184         DRM_SPININIT( dev->vbl_lock, "vblsig" );
185         TAILQ_INIT( &dev->vbl_sig_list );
186 #endif
187
188                                 /* Before installing handler */
189         DRM(driver_irq_preinstall)( dev );
190
191                                 /* Install handler */
192         dev->irqrid = 0;
193 #ifdef __FreeBSD__
194         dev->irqr = bus_alloc_resource(dev->device, SYS_RES_IRQ, &dev->irqrid,
195                                       0, ~0, 1, RF_SHAREABLE);
196         if (!dev->irqr) {
197 #elif defined(__NetBSD__)
198         if (pci_intr_map(&dev->pa, &dev->ih) != 0) {
199 #endif
200                 DRM_LOCK;
201                 dev->irq = 0;
202                 dev->irqrid = 0;
203                 DRM_UNLOCK;
204                 return ENOENT;
205         }
206         
207 #ifdef __FreeBSD__
208 #if __FreeBSD_version < 500000
209         retcode = bus_setup_intr(dev->device, dev->irqr, INTR_TYPE_TTY,
210                                  DRM(dma_service), dev, &dev->irqh);
211 #else
212         retcode = bus_setup_intr(dev->device, dev->irqr, INTR_TYPE_TTY | INTR_MPSAFE,
213                                  DRM(dma_service), dev, &dev->irqh);
214 #endif
215         if ( retcode ) {
216 #elif defined(__NetBSD__)
217         dev->irqh = pci_intr_establish(&dev->pa.pa_pc, dev->ih, IPL_TTY,
218                                       (int (*)(DRM_IRQ_ARGS))DRM(dma_service), dev);
219         if ( !dev->irqh ) {
220 #endif
221                 DRM_LOCK;
222 #ifdef __FreeBSD__
223                 bus_release_resource(dev->device, SYS_RES_IRQ, dev->irqrid, dev->irqr);
224 #endif
225                 dev->irq = 0;
226                 dev->irqrid = 0;
227                 DRM_UNLOCK;
228                 return retcode;
229         }
230
231                                 /* After installing handler */
232         DRM(driver_irq_postinstall)( dev );
233
234         return 0;
235 }
236
237 int DRM(irq_uninstall)( drm_device_t *dev )
238 {
239         int irq;
240         int irqrid;
241         
242         DRM_LOCK;
243         irq = dev->irq;
244         irqrid = dev->irqrid;
245         dev->irq = 0;
246         dev->irqrid = 0;
247         DRM_UNLOCK;
248
249         if ( !irq )
250                 return DRM_ERR(EINVAL);
251
252         DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, irq );
253
254         DRM(driver_irq_uninstall)( dev );
255
256 #ifdef __FreeBSD__
257         bus_teardown_intr(dev->device, dev->irqr, dev->irqh);
258         bus_release_resource(dev->device, SYS_RES_IRQ, irqrid, dev->irqr);
259 #elif defined(__NetBSD__)
260         pci_intr_disestablish(&dev->pa.pa_pc, dev->irqh);
261 #endif
262
263         return 0;
264 }
265
266 int DRM(control)( DRM_IOCTL_ARGS )
267 {
268         DRM_DEVICE;
269         drm_control_t ctl;
270
271         DRM_COPY_FROM_USER_IOCTL( ctl, (drm_control_t *) data, sizeof(ctl) );
272
273         switch ( ctl.func ) {
274         case DRM_INST_HANDLER:
275                 return DRM(irq_install)( dev, ctl.irq );
276         case DRM_UNINST_HANDLER:
277                 return DRM(irq_uninstall)( dev );
278         default:
279                 return DRM_ERR(EINVAL);
280         }
281 }
282
283 #if __HAVE_VBL_IRQ
284 int DRM(wait_vblank)( DRM_IOCTL_ARGS )
285 {
286         DRM_DEVICE;
287         drm_wait_vblank_t vblwait;
288         struct timeval now;
289         int ret;
290
291         if (!dev->irq)
292                 return DRM_ERR(EINVAL);
293
294         DRM_COPY_FROM_USER_IOCTL( vblwait, (drm_wait_vblank_t *)data,
295                                   sizeof(vblwait) );
296
297         if (vblwait.request.type & _DRM_VBLANK_RELATIVE) {
298                 vblwait.request.sequence += atomic_read(&dev->vbl_received);
299                 vblwait.request.type &= ~_DRM_VBLANK_RELATIVE;
300         }
301
302         flags = vblwait.request.type & _DRM_VBLANK_FLAGS_MASK;
303         if (flags & _DRM_VBLANK_SIGNAL) {
304 #if 0 /* disabled */
305                 drm_vbl_sig_t *vbl_sig = DRM_MALLOC(sizeof(drm_vbl_sig_t));
306                 if (vbl_sig == NULL)
307                         return ENOMEM;
308                 bzero(vbl_sig, sizeof(*vbl_sig));
309                 
310                 vbl_sig->sequence = vblwait.request.sequence;
311                 vbl_sig->signo = vblwait.request.signal;
312                 vbl_sig->pid = DRM_CURRENTPID;
313
314                 vblwait.reply.sequence = atomic_read(&dev->vbl_received);
315                 
316                 DRM_SPINLOCK(&dev->vbl_lock);
317                 TAILQ_INSERT_HEAD(&dev->vbl_sig_list, vbl_sig, link);
318                 DRM_SPINUNLOCK(&dev->vbl_lock);
319                 ret = 0;
320 #endif
321                 ret = EINVAL;
322         } else {
323                 ret = DRM(vblank_wait)(dev, &vblwait.request.sequence);
324                 
325                 microtime(&now);
326                 vblwait.reply.tval_sec = now.tv_sec;
327                 vblwait.reply.tval_usec = now.tv_usec;
328         }
329
330         DRM_COPY_TO_USER_IOCTL( (drm_wait_vblank_t *)data, vblwait,
331                                 sizeof(vblwait) );
332
333         return ret;
334 }
335
336 void DRM(vbl_send_signals)(drm_device_t *dev)
337 {
338 }
339
340 #if 0 /* disabled */
341 void DRM(vbl_send_signals)( drm_device_t *dev )
342 {
343         drm_vbl_sig_t *vbl_sig;
344         unsigned int vbl_seq = atomic_read( &dev->vbl_received );
345         struct proc *p;
346
347         DRM_SPINLOCK(&dev->vbl_lock);
348
349         vbl_sig = TAILQ_FIRST(&dev->vbl_sig_list);
350         while (vbl_sig != NULL) {
351                 drm_vbl_sig_t *next = TAILQ_NEXT(vbl_sig, link);
352
353                 if ( ( vbl_seq - vbl_sig->sequence ) <= (1<<23) ) {
354                         p = pfind(vbl_sig->pid);
355                         if (p != NULL)
356                                 psignal(p, vbl_sig->signo);
357
358                         TAILQ_REMOVE(&dev->vbl_sig_list, vbl_sig, link);
359                         DRM_FREE(vbl_sig,sizeof(*vbl_sig));
360                 }
361                 vbl_sig = next;
362         }
363
364         DRM_SPINUNLOCK(&dev->vbl_lock);
365 }
366 #endif
367
368 #endif /*  __HAVE_VBL_IRQ */
369
370 #else
371
372 int DRM(control)( DRM_IOCTL_ARGS )
373 {
374         drm_control_t ctl;
375
376         DRM_COPY_FROM_USER_IOCTL( ctl, (drm_control_t *) data, sizeof(ctl) );
377
378         switch ( ctl.func ) {
379         case DRM_INST_HANDLER:
380         case DRM_UNINST_HANDLER:
381                 return 0;
382         default:
383                 return DRM_ERR(EINVAL);
384         }
385 }
386
387 #endif /* __HAVE_DMA_IRQ */
388
389 #endif /* __HAVE_DMA */
390